Created
April 14, 2022 15:21
-
-
Save sdornan/ca308046d76b766758a157c1174bbe14 to your computer and use it in GitHub Desktop.
Custom Next.js MUI Link component
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Link as MuiLink, LinkProps as MuiLinkProps } from '@mui/material' | |
import NextLink, { LinkProps as NextLinkProps } from 'next/link' | |
import { useRouter } from 'next/router' | |
import * as React from 'react' | |
import { useStyles } from 'tss-react/mui' | |
import { colors } from 'lib/root' | |
/* eslint-disable jsx-a11y/anchor-has-content */ | |
interface NextLinkComposedProps | |
extends Omit<React.AnchorHTMLAttributes<HTMLAnchorElement>, 'href'>, | |
Omit<NextLinkProps, 'href' | 'as'> { | |
to: NextLinkProps['href'] | |
linkAs?: NextLinkProps['as'] | |
href?: NextLinkProps['href'] | |
} | |
export const NextLinkComposed = React.forwardRef< | |
HTMLAnchorElement, | |
NextLinkComposedProps | |
>(function NextLinkComposed(props, ref) { | |
const { | |
to, | |
linkAs, | |
href, | |
replace, | |
scroll, | |
passHref, | |
shallow, | |
prefetch, | |
locale, | |
...other | |
} = props | |
return ( | |
<NextLink | |
href={to} | |
prefetch={prefetch} | |
as={linkAs} | |
replace={replace} | |
scroll={scroll} | |
shallow={shallow} | |
passHref={passHref} | |
locale={locale} | |
> | |
<a ref={ref} {...other} /> | |
</NextLink> | |
) | |
}) | |
export type LinkProps = { | |
activeClassName?: string | |
as?: NextLinkProps['as'] | |
href: NextLinkProps['href'] | |
noLinkStyle?: boolean | |
} & Omit<NextLinkComposedProps, 'to' | 'linkAs' | 'href'> & | |
Omit<MuiLinkProps, 'href'> | |
// A styled version of the Next.js Link component: | |
// https://nextjs.org/docs/#with-link | |
const Link = React.forwardRef<HTMLAnchorElement, LinkProps>(function Link( | |
props, | |
ref | |
) { | |
const { | |
activeClassName = 'active', | |
as: linkAs, | |
className: classNameProps, | |
href, | |
noLinkStyle, | |
role, // Link don't have roles. | |
...other | |
} = props | |
const router = useRouter() | |
const { cx } = useStyles() | |
const pathname = typeof href === 'string' ? href : href.pathname | |
const className = cx(classNameProps, { | |
[activeClassName]: router.pathname === pathname && !!activeClassName, | |
}) | |
const isExternal = | |
typeof href === 'string' && | |
(href.indexOf('http') === 0 || | |
href.indexOf('mailto:') === 0 || | |
href.indexOf('sms:') === 0) | |
if (isExternal) { | |
if (noLinkStyle) { | |
return ( | |
<a | |
className={className} | |
href={href as string} | |
ref={ref as any} | |
{...other} | |
/> | |
) | |
} | |
return ( | |
<MuiLink | |
className={className} | |
href={href as string} | |
ref={ref} | |
{...other} | |
/> | |
) | |
} | |
if (noLinkStyle) { | |
return ( | |
<NextLinkComposed | |
className={className} | |
ref={ref as any} | |
to={href} | |
{...other} | |
/> | |
) | |
} | |
return ( | |
<MuiLink | |
component={NextLinkComposed} | |
linkAs={linkAs} | |
className={className} | |
ref={ref} | |
to={href} | |
sx={{ | |
...(!className && { | |
color: colors.tints.blue[4], | |
}), | |
}} | |
{...other} | |
/> | |
) | |
}) | |
export default Link |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment