2022-10-11 19:26:45 +02:00
'use client'
2022-09-17 00:12:59 +02:00
2021-07-14 20:12:04 +02:00
import React from 'react'
2020-07-13 18:08:12 +02:00
import { UrlObject } from 'url'
2020-08-05 20:12:17 +02:00
import {
isLocalURL ,
2020-08-18 18:36:40 +02:00
NextRouter ,
2022-11-01 04:13:27 +01:00
PrefetchOptions as RouterPrefetchOptions ,
2020-08-18 18:36:40 +02:00
resolveHref ,
2021-06-30 11:43:31 +02:00
} from '../shared/lib/router/router'
2022-11-01 04:13:27 +01:00
import { formatUrl } from '../shared/lib/router/utils/format-url'
2022-05-30 20:19:37 +02:00
import { addLocale } from './add-locale'
2022-05-29 20:53:12 +02:00
import { RouterContext } from '../shared/lib/router-context'
2022-07-14 18:51:57 +02:00
import {
AppRouterContext ,
AppRouterInstance ,
} from '../shared/lib/app-router-context'
2020-11-07 00:03:15 +01:00
import { useIntersection } from './use-intersection'
2022-05-30 20:19:37 +02:00
import { getDomainLocale } from './get-domain-locale'
import { addBasePath } from './add-base-path'
2020-07-13 18:08:12 +02:00
2019-05-30 03:19:32 +02:00
type Url = string | UrlObject
2020-08-18 18:36:40 +02:00
type RequiredKeys < T > = {
[ K in keyof T ] - ? : { } extends Pick < T , K > ? never : K
} [ keyof T ]
type OptionalKeys < T > = {
[ K in keyof T ] - ? : { } extends Pick < T , K > ? K : never
} [ keyof T ]
2018-08-07 07:44:18 +02:00
2022-04-26 00:01:30 +02:00
type InternalLinkProps = {
2022-09-27 21:33:01 +02:00
/ * *
* The path or URL to navigate to . It can also be an object .
*
* @example https : //nextjs.org/docs/api-reference/next/link#with-url-object
* /
2019-05-30 03:19:32 +02:00
href : Url
2022-09-27 21:33:01 +02:00
/ * *
* Optional decorator for the path that will be shown in the browser URL bar . Before Next . js 9.5 . 3 this was used for dynamic routes , check our [ previous docs ] ( https : //nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes) to see how it worked. Note: when this path differs from the one provided in `href` the previous `href`/`as` behavior is used as shown in the [previous docs](https://nextjs.org/docs/tag/v9.5.2/api-reference/next/link#dynamic-routes).
* /
2019-07-11 20:52:21 +02:00
as ? : Url
2022-09-27 21:33:01 +02:00
/ * *
* Replace the current ` history ` state instead of adding a new url into the stack .
*
* @defaultValue ` false `
* /
2019-05-30 03:19:32 +02:00
replace? : boolean
2022-09-27 21:33:01 +02:00
/ * *
* Whether to override the default scroll behavior
*
* @example https : //nextjs.org/docs/api-reference/next/link#disable-scrolling-to-the-top-of-the-page
*
* @defaultValue ` true `
* /
2019-05-30 03:19:32 +02:00
scroll? : boolean
2022-09-27 21:33:01 +02:00
/ * *
* Update the path of the current page without rerunning [ ` getStaticProps ` ] ( / d o c s / b a s i c - f e a t u r e s / d a t a - f e t c h i n g / g e t - s t a t i c - p r o p s . m d ) , [ ` g e t S e r v e r S i d e P r o p s ` ] ( / d o c s / b a s i c - f e a t u r e s / d a t a - f e t c h i n g / g e t - s e r v e r - s i d e - p r o p s . m d ) o r [ ` g e t I n i t i a l P r o p s ` ] ( / d o c s / a p i - r e f e r e n c e / d a t a - f e t c h i n g / g e t - i n i t i a l - p r o p s . m d ) .
*
* @defaultValue ` false `
* /
2019-05-30 03:19:32 +02:00
shallow? : boolean
2022-09-27 21:33:01 +02:00
/ * *
* Forces ` Link ` to send the ` href ` property to its child .
*
* @defaultValue ` false `
* /
2019-05-30 03:19:32 +02:00
passHref? : boolean
2022-09-27 21:33:01 +02:00
/ * *
* Prefetch the page in the background .
* Any ` <Link /> ` that is in the viewport ( initially or through scroll ) will be preloaded .
* Prefetch can be disabled by passing ` prefetch={false} ` . When ` prefetch ` is set to ` false ` , prefetching will still occur on hover . Pages using [ Static Generation ] ( / d o c s / b a s i c - f e a t u r e s / d a t a - f e t c h i n g / g e t - s t a t i c - p r o p s . m d ) w i l l p r e l o a d ` J S O N ` f i l e s w i t h t h e d a t a f o r f a s t e r p a g e t r a n s i t i o n s . P r e f e t c h i n g i s o n l y e n a b l e d i n p r o d u c t i o n .
*
* @defaultValue ` true `
* /
2019-05-30 03:19:32 +02:00
prefetch? : boolean
2022-09-27 21:33:01 +02:00
/ * *
* The active locale is automatically prepended . ` locale ` allows for providing a different locale .
* When ` false ` ` href ` has to include the locale as the default behavior is disabled .
* /
2020-10-22 17:08:01 +02:00
locale? : string | false
2022-09-27 21:33:01 +02:00
/ * *
2022-11-01 04:13:27 +01:00
* Enable legacy link behavior .
2022-10-27 08:32:03 +02:00
* @defaultValue ` false `
2022-09-27 21:33:01 +02:00
* @see https : //github.com/vercel/next.js/commit/489e65ed98544e69b0afd7e0cfc3f9f6c2b803b7
* /
2022-04-26 00:01:30 +02:00
legacyBehavior? : boolean
2022-04-26 13:46:09 +02:00
// e: any because as it would otherwise overlap with existing types
2022-04-26 00:01:30 +02:00
/ * *
2022-10-27 08:32:03 +02:00
* Optional event handler for when the mouse pointer is moved onto Link
2022-04-26 00:01:30 +02:00
* /
2022-04-26 13:46:09 +02:00
onMouseEnter ? : ( e : any ) = > void
// e: any because as it would otherwise overlap with existing types
2022-07-25 21:04:03 +02:00
/ * *
2022-10-27 08:32:03 +02:00
* Optional event handler for when Link is touched .
2022-07-25 21:04:03 +02:00
* /
onTouchStart ? : ( e : any ) = > void
// e: any because as it would otherwise overlap with existing types
2022-04-26 00:01:30 +02:00
/ * *
2022-10-27 08:32:03 +02:00
* Optional event handler for when Link is clicked .
2022-04-26 00:01:30 +02:00
* /
2022-04-26 13:46:09 +02:00
onClick ? : ( e : any ) = > void
2019-04-25 21:31:53 +02:00
}
2022-04-26 00:01:30 +02:00
2022-07-12 18:32:27 +02:00
// TODO-APP: Include the full set of Anchor props
2022-04-26 13:46:09 +02:00
// adding this to the publicly exported type currently breaks existing apps
export type LinkProps = InternalLinkProps
2020-08-18 18:36:40 +02:00
type LinkPropsRequired = RequiredKeys < LinkProps >
2022-04-26 00:01:30 +02:00
type LinkPropsOptional = OptionalKeys < InternalLinkProps >
2019-04-25 21:31:53 +02:00
2022-11-01 04:13:27 +01:00
const prefetched = new Set < string > ( )
type PrefetchOptions = RouterPrefetchOptions & {
/ * *
* bypassPrefetchedCheck will bypass the check to see if the ` href ` has
* already been fetched .
* /
bypassPrefetchedCheck? : boolean
}
2019-05-01 15:14:27 +02:00
2020-07-07 06:52:26 +02:00
function prefetch (
2022-11-01 04:13:27 +01:00
router : NextRouter | AppRouterInstance ,
2020-07-07 06:52:26 +02:00
href : string ,
as : string ,
2022-11-01 04:13:27 +01:00
options : PrefetchOptions
2020-07-07 06:52:26 +02:00
) : void {
2022-11-01 04:13:27 +01:00
if ( typeof window === 'undefined' ) {
return
}
if ( ! isLocalURL ( href ) ) {
return
}
// We should only dedupe requests when experimental.optimisticClientCache is
// disabled.
if ( ! options . bypassPrefetchedCheck ) {
const locale =
// Let the link's locale prop override the default router locale.
typeof options . locale !== 'undefined'
? options . locale
: // Otherwise fallback to the router's locale.
'locale' in router
? router . locale
: undefined
const prefetchedKey = href + '%' + as + '%' + locale
// If we've already fetched the key, then don't prefetch it again!
if ( prefetched . has ( prefetchedKey ) ) {
return
}
// Mark this URL as prefetched.
prefetched . add ( prefetchedKey )
}
2020-07-02 06:53:17 +02:00
// Prefetch the JSON page if asked (only in the client)
// We need to handle a prefetch error here since we may be
// loading with priority which can reject but we don't
// want to force navigation since this is only a prefetch
2022-09-06 19:29:09 +02:00
Promise . resolve ( router . prefetch ( href , as , options ) ) . catch ( ( err ) = > {
2019-08-12 06:26:25 +02:00
if ( process . env . NODE_ENV !== 'production' ) {
2020-07-02 06:53:17 +02:00
// rethrow to show invalid URL errors
throw err
2019-08-12 06:26:25 +02:00
}
2020-07-02 06:53:17 +02:00
} )
}
2019-05-01 15:14:27 +02:00
2021-01-05 16:11:37 +01:00
function isModifiedEvent ( event : React.MouseEvent ) : boolean {
2020-08-05 20:12:17 +02:00
const { target } = event . currentTarget as HTMLAnchorElement
return (
( target && target !== '_self' ) ||
event . metaKey ||
event . ctrlKey ||
event . shiftKey ||
2020-08-10 22:32:47 +02:00
event . altKey || // triggers resource download
2020-08-05 20:12:17 +02:00
( event . nativeEvent && event . nativeEvent . which === 2 )
)
}
2020-07-02 06:53:17 +02:00
function linkClicked (
e : React.MouseEvent ,
2022-07-14 18:51:57 +02:00
router : NextRouter | AppRouterInstance ,
2020-07-02 06:53:17 +02:00
href : string ,
2020-07-07 06:52:26 +02:00
as : string ,
2020-07-02 06:53:17 +02:00
replace? : boolean ,
shallow? : boolean ,
2020-10-15 10:58:26 +02:00
scroll? : boolean ,
2022-06-01 13:52:57 +02:00
locale? : string | false ,
2022-09-13 13:47:20 +02:00
isAppRouter? : boolean ,
2022-09-06 19:29:09 +02:00
prefetchEnabled? : boolean
2020-07-02 06:53:17 +02:00
) : void {
2020-08-05 20:12:17 +02:00
const { nodeName } = e . currentTarget
2018-08-07 05:53:06 +02:00
2022-02-06 21:53:03 +01:00
// anchors inside an svg have a lowercase nodeName
const isAnchorNodeName = nodeName . toUpperCase ( ) === 'A'
if ( isAnchorNodeName && ( isModifiedEvent ( e ) || ! isLocalURL ( href ) ) ) {
2020-08-10 22:32:47 +02:00
// ignore click for browser’ s default behavior
2020-07-02 06:53:17 +02:00
return
2019-12-20 22:30:58 +01:00
}
2020-07-02 06:53:17 +02:00
e . preventDefault ( )
2018-08-07 05:53:06 +02:00
2022-06-01 13:52:57 +02:00
const navigate = ( ) = > {
2022-09-06 19:29:09 +02:00
// If the router is an NextRouter instance it will have `beforePopState`
if ( 'beforePopState' in router ) {
2022-07-14 18:51:57 +02:00
router [ replace ? 'replace' : 'push' ] ( href , as , {
shallow ,
locale ,
scroll ,
} )
2022-09-06 19:29:09 +02:00
} else {
2022-11-01 04:13:27 +01:00
router [ replace ? 'replace' : 'push' ] ( as || href , {
2022-10-08 19:42:55 +02:00
forceOptimisticNavigation : ! prefetchEnabled ,
} )
2022-07-14 18:51:57 +02:00
}
2022-06-01 13:52:57 +02:00
}
2022-09-13 13:47:20 +02:00
if ( isAppRouter ) {
// @ts-expect-error startTransition exists.
React . startTransition ( navigate )
2022-06-01 13:52:57 +02:00
} else {
navigate ( )
}
2020-07-02 06:53:17 +02:00
}
2016-10-06 09:07:41 +02:00
2022-04-28 11:32:32 +02:00
type LinkPropsReal = React . PropsWithChildren <
Omit < React.AnchorHTMLAttributes < HTMLAnchorElement > , keyof LinkProps > &
LinkProps
>
2022-11-01 04:13:27 +01:00
function formatStringOrUrl ( urlObjOrString : UrlObject | string ) : string {
if ( typeof urlObjOrString === 'string' ) {
return urlObjOrString
}
return formatUrl ( urlObjOrString )
}
2022-09-27 21:33:01 +02:00
/ * *
* React Component that enables client - side transitions between routes .
* /
2022-04-28 11:32:32 +02:00
const Link = React . forwardRef < HTMLAnchorElement , LinkPropsReal > (
2022-05-24 18:00:22 +02:00
function LinkComponent ( props , forwardedRef ) {
2022-04-28 11:32:32 +02:00
if ( process . env . NODE_ENV !== 'production' ) {
function createPropError ( args : {
key : string
expected : string
actual : string
} ) {
return new Error (
` Failed prop type: The prop \` ${ args . key } \` expects a ${ args . expected } in \` <Link> \` , but got \` ${ args . actual } \` instead. ` +
( typeof window !== 'undefined'
? "\nOpen your browser's console to view the Component stack trace."
: '' )
)
2020-08-18 18:36:40 +02:00
}
2022-04-28 11:32:32 +02:00
// TypeScript trick for type-guarding:
const requiredPropsGuard : Record < LinkPropsRequired , true > = {
href : true ,
} as const
const requiredProps : LinkPropsRequired [ ] = Object . keys (
requiredPropsGuard
) as LinkPropsRequired [ ]
requiredProps . forEach ( ( key : LinkPropsRequired ) = > {
if ( key === 'href' ) {
if (
props [ key ] == null ||
( typeof props [ key ] !== 'string' && typeof props [ key ] !== 'object' )
) {
throw createPropError ( {
key ,
expected : '`string` or `object`' ,
actual : props [ key ] === null ? 'null' : typeof props [ key ] ,
} )
}
} else {
// TypeScript trick for type-guarding:
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ : never = key
2020-10-15 10:58:26 +02:00
}
2022-04-28 11:32:32 +02:00
} )
// TypeScript trick for type-guarding:
const optionalPropsGuard : Record < LinkPropsOptional , true > = {
as : true ,
replace : true ,
scroll : true ,
shallow : true ,
passHref : true ,
prefetch : true ,
locale : true ,
onClick : true ,
onMouseEnter : true ,
2022-07-25 21:04:03 +02:00
onTouchStart : true ,
2022-04-28 11:32:32 +02:00
legacyBehavior : true ,
} as const
const optionalProps : LinkPropsOptional [ ] = Object . keys (
optionalPropsGuard
) as LinkPropsOptional [ ]
optionalProps . forEach ( ( key : LinkPropsOptional ) = > {
const valType = typeof props [ key ]
if ( key === 'as' ) {
if ( props [ key ] && valType !== 'string' && valType !== 'object' ) {
throw createPropError ( {
key ,
expected : '`string` or `object`' ,
actual : valType ,
} )
}
} else if ( key === 'locale' ) {
if ( props [ key ] && valType !== 'string' ) {
throw createPropError ( {
key ,
expected : '`string`' ,
actual : valType ,
} )
}
2022-07-25 21:04:03 +02:00
} else if (
key === 'onClick' ||
key === 'onMouseEnter' ||
key === 'onTouchStart'
) {
2022-04-28 11:32:32 +02:00
if ( props [ key ] && valType !== 'function' ) {
throw createPropError ( {
key ,
expected : '`function`' ,
actual : valType ,
} )
}
} else if (
key === 'replace' ||
key === 'scroll' ||
key === 'shallow' ||
key === 'passHref' ||
key === 'prefetch' ||
key === 'legacyBehavior'
) {
if ( props [ key ] != null && valType !== 'boolean' ) {
throw createPropError ( {
key ,
expected : '`boolean`' ,
actual : valType ,
} )
}
} else {
// TypeScript trick for type-guarding:
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const _ : never = key
2020-08-18 18:36:40 +02:00
}
2022-04-28 11:32:32 +02:00
} )
2020-08-18 18:36:40 +02:00
2022-04-28 11:32:32 +02:00
// This hook is in a conditional but that is ok because `process.env.NODE_ENV` never changes
// eslint-disable-next-line react-hooks/rules-of-hooks
const hasWarned = React . useRef ( false )
if ( props . prefetch && ! hasWarned . current ) {
hasWarned . current = true
console . warn (
'Next.js auto-prefetches automatically based on viewport. The prefetch attribute is no longer needed. More: https://nextjs.org/docs/messages/prefetch-true-deprecated'
)
}
2016-10-06 09:07:41 +02:00
}
2022-04-26 00:01:30 +02:00
2022-04-28 11:32:32 +02:00
let children : React.ReactNode
const {
href : hrefProp ,
as : asProp ,
children : childrenProp ,
prefetch : prefetchProp ,
passHref ,
replace ,
shallow ,
scroll ,
locale ,
onClick ,
2022-11-01 04:13:27 +01:00
onMouseEnter : onMouseEnterProp ,
onTouchStart : onTouchStartProp ,
2022-05-30 16:09:14 +02:00
legacyBehavior = Boolean ( process . env . __NEXT_NEW_LINK_BEHAVIOR ) !== true ,
2022-04-28 11:32:32 +02:00
. . . restProps
} = props
children = childrenProp
2022-06-25 22:07:40 +02:00
if (
legacyBehavior &&
( typeof children === 'string' || typeof children === 'number' )
) {
2022-04-28 11:32:32 +02:00
children = < a > { children } < / a >
2020-07-07 06:52:26 +02:00
}
2016-10-06 09:07:41 +02:00
2022-11-01 04:13:27 +01:00
const prefetchEnabled = prefetchProp !== false
2022-05-29 20:53:12 +02:00
2022-11-01 04:13:27 +01:00
const pagesRouter = React . useContext ( RouterContext )
const appRouter = React . useContext ( AppRouterContext )
const router = pagesRouter ? ? appRouter
// We're in the app directory if there is no pages router.
const isAppRouter = ! pagesRouter
2022-04-04 20:18:49 +02:00
2022-04-28 11:32:32 +02:00
const { href , as } = React . useMemo ( ( ) = > {
2022-11-01 04:13:27 +01:00
if ( ! pagesRouter ) {
const resolvedHref = formatStringOrUrl ( hrefProp )
return {
href : resolvedHref ,
as : asProp ? formatStringOrUrl ( asProp ) : resolvedHref ,
}
}
const [ resolvedHref , resolvedAs ] = resolveHref (
pagesRouter ,
hrefProp ,
true
)
2022-04-28 11:32:32 +02:00
return {
href : resolvedHref ,
2022-11-01 04:13:27 +01:00
as : asProp
? resolveHref ( pagesRouter , asProp )
: resolvedAs || resolvedHref ,
2022-04-26 00:01:30 +02:00
}
2022-11-01 04:13:27 +01:00
} , [ pagesRouter , hrefProp , asProp ] )
2022-04-28 11:32:32 +02:00
const previousHref = React . useRef < string > ( href )
const previousAs = React . useRef < string > ( as )
// This will return the first child, if multiple are provided it will throw an error
let child : any
if ( legacyBehavior ) {
if ( process . env . NODE_ENV === 'development' ) {
if ( onClick ) {
console . warn (
` "onClick" was passed to <Link> with \` href \` of \` ${ hrefProp } \` but "legacyBehavior" was set. The legacy behavior requires onClick be set on the child of next/link `
)
}
2022-11-01 04:13:27 +01:00
if ( onMouseEnterProp ) {
2022-04-28 11:32:32 +02:00
console . warn (
` "onMouseEnter" was passed to <Link> with \` href \` of \` ${ hrefProp } \` but "legacyBehavior" was set. The legacy behavior requires onMouseEnter be set on the child of next/link `
)
}
try {
child = React . Children . only ( children )
} catch ( err ) {
if ( ! children ) {
throw new Error (
` No children were passed to <Link> with \` href \` of \` ${ hrefProp } \` but one child is required https://nextjs.org/docs/messages/link-no-children `
)
}
2022-04-26 00:01:30 +02:00
throw new Error (
2022-04-28 11:32:32 +02:00
` Multiple children were passed to <Link> with \` href \` of \` ${ hrefProp } \` but only one child is supported https://nextjs.org/docs/messages/link-multiple-children ` +
( typeof window !== 'undefined'
? " \nOpen your browser's console to view the Component stack trace."
: '' )
2022-04-26 00:01:30 +02:00
)
}
2022-04-28 11:32:32 +02:00
} else {
child = React . Children . only ( children )
2022-03-22 19:58:55 +01:00
}
2022-10-25 07:39:22 +02:00
} else {
if ( process . env . NODE_ENV === 'development' ) {
if ( ( children as any ) ? . type === 'a' ) {
throw new Error (
'Invalid <Link> with <a> child. Please remove <a> or use <Link legacyBehavior>.\nLearn more: https://nextjs.org/docs/messages/invalid-new-link-with-extra-anchor'
)
}
}
2021-05-31 21:41:57 +02:00
}
2022-04-26 00:01:30 +02:00
2022-04-28 11:32:32 +02:00
const childRef : any = legacyBehavior
? child && typeof child === 'object' && child . ref
: forwardedRef
2020-11-01 04:37:28 +01:00
2022-04-28 11:32:32 +02:00
const [ setIntersectionRef , isVisible , resetVisible ] = useIntersection ( {
rootMargin : '200px' ,
} )
2022-04-04 20:18:49 +02:00
2022-04-28 11:32:32 +02:00
const setRef = React . useCallback (
( el : Element ) = > {
// Before the link getting observed, check if visible state need to be reset
if ( previousAs . current !== as || previousHref . current !== href ) {
resetVisible ( )
previousAs . current = as
previousHref . current = href
}
2022-04-04 20:18:49 +02:00
2022-04-28 11:32:32 +02:00
setIntersectionRef ( el )
if ( childRef ) {
if ( typeof childRef === 'function' ) childRef ( el )
else if ( typeof childRef === 'object' ) {
childRef . current = el
}
2020-11-01 04:37:28 +01:00
}
2022-04-28 11:32:32 +02:00
} ,
[ as , childRef , href , resetVisible , setIntersectionRef ]
)
2022-11-01 04:13:27 +01:00
// Prefetch the URL if we haven't already and it's visible.
2022-04-28 11:32:32 +02:00
React . useEffect ( ( ) = > {
2022-11-01 04:13:27 +01:00
if ( ! router ) {
return
2020-11-01 04:37:28 +01:00
}
2022-11-01 04:13:27 +01:00
// If we don't need to prefetch the URL, don't do prefetch.
if ( ! isVisible || ! prefetchEnabled ) {
return
}
// Prefetch the URL.
prefetch ( router , href , as , { locale } )
} , [
as ,
href ,
isVisible ,
locale ,
prefetchEnabled ,
pagesRouter ? . locale ,
router ,
] )
2022-04-28 11:32:32 +02:00
const childProps : {
2022-07-25 21:04:03 +02:00
onTouchStart : React.TouchEventHandler
2022-04-28 11:32:32 +02:00
onMouseEnter : React.MouseEventHandler
onClick : React.MouseEventHandler
href? : string
ref? : any
} = {
ref : setRef ,
onClick : ( e : React.MouseEvent ) = > {
if ( process . env . NODE_ENV !== 'production' ) {
if ( ! e ) {
throw new Error (
` Component rendered inside next/link has to pass click event to "onClick" prop. `
)
}
2022-02-07 01:04:37 +01:00
}
2022-04-26 00:01:30 +02:00
2022-04-28 11:32:32 +02:00
if ( ! legacyBehavior && typeof onClick === 'function' ) {
onClick ( e )
}
2022-11-01 04:13:27 +01:00
2022-04-28 11:32:32 +02:00
if (
legacyBehavior &&
child . props &&
typeof child . props . onClick === 'function'
) {
child . props . onClick ( e )
}
2022-11-01 04:13:27 +01:00
if ( ! router ) {
return
2022-04-28 11:32:32 +02:00
}
2022-11-01 04:13:27 +01:00
if ( e . defaultPrevented ) {
return
}
linkClicked (
e ,
router ,
href ,
as ,
replace ,
shallow ,
scroll ,
locale ,
isAppRouter ,
prefetchEnabled
)
2022-04-28 11:32:32 +02:00
} ,
onMouseEnter : ( e : React.MouseEvent ) = > {
2022-11-01 04:13:27 +01:00
if ( ! legacyBehavior && typeof onMouseEnterProp === 'function' ) {
onMouseEnterProp ( e )
2022-04-28 11:32:32 +02:00
}
2022-11-01 04:13:27 +01:00
2022-04-28 11:32:32 +02:00
if (
legacyBehavior &&
child . props &&
typeof child . props . onMouseEnter === 'function'
) {
child . props . onMouseEnter ( e )
}
2022-09-06 19:29:09 +02:00
2022-11-01 04:13:27 +01:00
if ( ! router ) {
return
}
if ( ! prefetchEnabled && isAppRouter ) {
return
2022-04-28 11:32:32 +02:00
}
2022-11-01 04:13:27 +01:00
prefetch ( router , href , as , {
locale ,
priority : true ,
// @see {https://github.com/vercel/next.js/discussions/40268?sort=top#discussioncomment-3572642}
bypassPrefetchedCheck : true ,
} )
2022-04-28 11:32:32 +02:00
} ,
2022-07-25 21:04:03 +02:00
onTouchStart : ( e : React.TouchEvent < HTMLAnchorElement > ) = > {
2022-11-01 04:13:27 +01:00
if ( ! legacyBehavior && typeof onTouchStartProp === 'function' ) {
onTouchStartProp ( e )
2022-07-25 21:04:03 +02:00
}
if (
legacyBehavior &&
child . props &&
typeof child . props . onTouchStart === 'function'
) {
child . props . onTouchStart ( e )
}
2022-11-01 04:13:27 +01:00
if ( ! router ) {
return
}
if ( ! prefetchEnabled && isAppRouter ) {
return
2022-07-25 21:04:03 +02:00
}
2022-11-01 04:13:27 +01:00
prefetch ( router , href , as , {
locale ,
priority : true ,
// @see {https://github.com/vercel/next.js/discussions/40268?sort=top#discussioncomment-3572642}
bypassPrefetchedCheck : true ,
} )
2022-07-25 21:04:03 +02:00
} ,
2022-04-28 11:32:32 +02:00
}
2016-10-06 09:07:41 +02:00
2022-04-28 11:32:32 +02:00
// If child is an <a> tag and doesn't have a href attribute, or if the 'passHref' property is
// defined, we specify the current 'href', so that repetition is not needed by the user
if (
! legacyBehavior ||
passHref ||
( child . type === 'a' && ! ( 'href' in child . props ) )
) {
const curLocale =
2022-11-01 04:13:27 +01:00
typeof locale !== 'undefined' ? locale : pagesRouter?.locale
2022-04-28 11:32:32 +02:00
// we only render domain locales if we are currently on a domain locale
// so that locale links are still visitable in development/preview envs
const localeDomain =
2022-11-01 04:13:27 +01:00
pagesRouter ? . isLocaleDomain &&
getDomainLocale (
as ,
curLocale ,
pagesRouter ? . locales ,
pagesRouter ? . domainLocales
)
2016-10-06 09:07:41 +02:00
2022-04-28 11:32:32 +02:00
childProps . href =
localeDomain ||
2022-11-01 04:13:27 +01:00
addBasePath ( addLocale ( as , curLocale , pagesRouter ? . defaultLocale ) )
2022-04-28 11:32:32 +02:00
}
return legacyBehavior ? (
React . cloneElement ( child , childProps )
) : (
< a { ...restProps } { ...childProps } >
{ children }
< / a >
)
}
)
2016-10-06 09:07:41 +02:00
2018-08-07 05:23:28 +02:00
export default Link