|
| 1 | +import { ForwardedRef, forwardRef, ReactElement } from "react" |
| 2 | +import NextLink from "next/link" |
| 3 | +import type { LinkProps as NextLinkProps } from "next/link" |
| 4 | + |
| 5 | +// eslint-disable-next-line @typescript-eslint/no-namespace |
| 6 | +export declare namespace AnchorProps { |
| 7 | + interface IntrinsicAnchorProps |
| 8 | + extends React.DetailedHTMLProps< |
| 9 | + React.AnchorHTMLAttributes<HTMLAnchorElement>, |
| 10 | + HTMLAnchorElement |
| 11 | + > { |
| 12 | + href: `#${string}` | `http${string}` |
| 13 | + } |
| 14 | + |
| 15 | + interface InternalAnchorProps extends NextLinkProps {} |
| 16 | +} |
| 17 | + |
| 18 | +export type AnchorProps = |
| 19 | + | AnchorProps.IntrinsicAnchorProps |
| 20 | + | AnchorProps.InternalAnchorProps |
| 21 | + |
| 22 | +export const Anchor = forwardRef(function Anchor( |
| 23 | + props: AnchorProps, |
| 24 | + ref: ForwardedRef<HTMLAnchorElement>, |
| 25 | +) { |
| 26 | + return isInternal(props) ? ( |
| 27 | + <NextLink {...props} ref={ref} /> |
| 28 | + ) : ( |
| 29 | + <a ref={ref} rel="noopener noreferrer" target="_blank" {...props} /> |
| 30 | + ) |
| 31 | +}) as (props: AnchorProps) => ReactElement |
| 32 | + |
| 33 | +function isInternal( |
| 34 | + props: AnchorProps, |
| 35 | +): props is AnchorProps.InternalAnchorProps { |
| 36 | + return ( |
| 37 | + typeof props.href === "object" || |
| 38 | + (typeof props.href === "string" && |
| 39 | + !props.href.startsWith("http") && |
| 40 | + !props.href.startsWith("#")) |
| 41 | + ) |
| 42 | +} |
0 commit comments