import type { FunctionComponent, ComponentChildren } from 'preact';
import { usePathname } from '@/src/hooks/use-pathname';
import { usePageLoadingState } from './page-loading-state-provider';
interface LinkProps {
children: ComponentChildren;
to: string;
activeClassName?: string;
partiallyActive?: boolean;
className?: string;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
onClick?: (event: any) => void;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
[key: string]: any;
}
// Link component with active-state detection and loading behavior
const Link: FunctionComponent<LinkProps> = ({
children,
to,
activeClassName,
partiallyActive,
className = '',
...other
}) => {
const pathname = usePathname();
const { isPageLoading, setIsPageLoading } = usePageLoadingState();
// Extract onClick handler from props to preserve it
const { onClick, ...rest } = other;
// Check if link is internal (starts with / but not //)
const internal = /^\/(?!\/)/.test(to);
// Check if link is active
const isActive = partiallyActive ? pathname.startsWith(to) : pathname === to;
const finalClassName =
isActive && activeClassName ? `${className} ${activeClassName}` : className;
if (internal) {
return (
<a
href={to}
className={finalClassName}
onClick={(event: MouseEvent) => {
// Call the original onClick handler first (if provided)
if (onClick && typeof onClick === 'function') {
onClick(event);
}
// If event was cancelled by the onClick handler, stop here
if (event.defaultPrevented) {
return;
}
// Allow default browser behavior for meta/ctrl + click (open in new tab)
if (event.metaKey || event.ctrlKey) {
return;
}
// Prevent click if page is already loading
if (isPageLoading) {
event.preventDefault();
return;
}
// Skip loading state for same-path navigation (already on this page)
if (pathname === to) {
return;
}
// Scroll to top BEFORE navigation (while overlay is shown)
// Use auto behavior to override CSS smooth scroll
// This ensures scroll happens instantly before new content is visible
window.scrollTo({ top: 0, left: 0, behavior: 'auto' });
setIsPageLoading(true);
}}
{...rest}
>
{children}
</a>
);
}
// External link
return (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
<a href={to} className={finalClassName} rel="nofollow noopener noreferrer" {...(rest as any)}>
{children}
</a>
);
};
export { Link };