import type { MouseEvent, MouseEventHandler } from 'react'; import React, { forwardRef, useLayoutEffect, useTransition } from 'react'; import { Link as DumiLink, useLocation, useNavigate } from 'dumi'; import nprogress from 'nprogress'; export interface LinkProps { to: string | { pathname?: string; search?: string; hash?: string }; style?: React.CSSProperties; className?: string; onClick?: MouseEventHandler; component?: React.ComponentType; } nprogress.configure({ showSpinner: false }); const Link = forwardRef>((props, ref) => { const { to, children, component, ...rest } = props; const [isPending, startTransition] = useTransition(); const navigate = useNavigate(); const { pathname } = useLocation(); const href = React.useMemo(() => { if (typeof to === 'object') { return `${to.pathname || pathname}${to.search || ''}${to.hash || ''}`; } return to; }, [to]); const handleClick = (e: MouseEvent) => { props.onClick?.(e); if (!href?.startsWith('http')) { // Should support open in new tab if (!e.metaKey && !e.ctrlKey && !e.shiftKey) { e.preventDefault(); startTransition(() => { if (href) { navigate(href); } }); } } }; useLayoutEffect(() => { if (isPending) { nprogress.start(); } else { nprogress.done(); } }, [isPending]); if (component) { return React.createElement( component, { ...rest, ref, onClick: handleClick, href, }, children, ); } return ( {children} ); }); export default Link;