Merged in feat/sw-3230-move-link-to-design-system (pull request #2618)
feat(SW-3230): Move Link to design-system * Move Link to design-system * Remove comments Approved-by: Linus Flood
This commit is contained in:
119
packages/design-system/lib/components/Link/index.tsx
Normal file
119
packages/design-system/lib/components/Link/index.tsx
Normal file
@@ -0,0 +1,119 @@
|
||||
'use client'
|
||||
import NextLink from 'next/link'
|
||||
import { usePathname, useSearchParams } from 'next/navigation'
|
||||
import { useMemo } from 'react'
|
||||
|
||||
import { linkVariants } from './variants'
|
||||
|
||||
import type { LinkProps } from './link'
|
||||
|
||||
export { LinkProps }
|
||||
|
||||
export default function Link({
|
||||
active,
|
||||
className,
|
||||
color,
|
||||
href,
|
||||
partialMatch = false,
|
||||
textDecoration,
|
||||
size,
|
||||
scroll = true,
|
||||
prefetch,
|
||||
variant,
|
||||
weight,
|
||||
onClick,
|
||||
/**
|
||||
* Decides if the link should include the current search params in the URL.
|
||||
* If the given href also contains search params, they take precedence and
|
||||
* override any current search params. If you need to merge them, handle that
|
||||
* in your component that passes the href here.
|
||||
*/
|
||||
keepSearchParams,
|
||||
...props
|
||||
}: LinkProps) {
|
||||
const currentPageSlug = usePathname()
|
||||
const searchParams = useSearchParams()
|
||||
let isActive = active || currentPageSlug === href
|
||||
|
||||
if (partialMatch && !isActive) {
|
||||
isActive = currentPageSlug === href
|
||||
}
|
||||
|
||||
const classNames = linkVariants({
|
||||
active: isActive,
|
||||
className,
|
||||
textDecoration,
|
||||
color,
|
||||
size,
|
||||
weight,
|
||||
variant,
|
||||
})
|
||||
|
||||
const fullUrl = useMemo(() => {
|
||||
const newPath = href
|
||||
|
||||
if (keepSearchParams && searchParams.size) {
|
||||
if (newPath.includes('?')) {
|
||||
const newPathParts = newPath.split('?')
|
||||
const newSearchParams = new URLSearchParams(newPathParts[1])
|
||||
searchParams.forEach((v, k) => {
|
||||
if (!newSearchParams.has(k)) {
|
||||
newSearchParams.set(k, v)
|
||||
}
|
||||
})
|
||||
return `${newPathParts[0]}?${newSearchParams}`
|
||||
}
|
||||
return `${newPath}?${searchParams}`
|
||||
}
|
||||
|
||||
return newPath
|
||||
}, [href, searchParams, keepSearchParams])
|
||||
|
||||
// TODO: Remove this check (and hook) and only return <Link /> when current web is deleted
|
||||
const isExternal = useCheckIfExternalLink(href)
|
||||
|
||||
const linkProps = {
|
||||
href: fullUrl,
|
||||
className: classNames,
|
||||
}
|
||||
|
||||
return isExternal ? (
|
||||
<a
|
||||
{...linkProps}
|
||||
{...props}
|
||||
onClick={(e) => {
|
||||
if (onClick) {
|
||||
onClick(e)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
) : (
|
||||
<NextLink
|
||||
scroll={scroll}
|
||||
prefetch={prefetch}
|
||||
onClick={onClick}
|
||||
{...props}
|
||||
{...linkProps}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
const useCheckIfExternalLink = (url: string) => {
|
||||
return useMemo(() => {
|
||||
if (typeof window !== 'undefined' && url?.length) {
|
||||
try {
|
||||
const hostName = window.location.hostname
|
||||
const newURL = new URL(url)
|
||||
|
||||
const hostsMatch = hostName === newURL.hostname
|
||||
const langRouteRegex = /^\/[a-zA-Z]{2}\//
|
||||
|
||||
return !hostsMatch || !langRouteRegex.test(newURL.pathname)
|
||||
} catch {
|
||||
// Don't care. Expecting internal url (#, /my-pages/overview, etc)
|
||||
return false
|
||||
}
|
||||
}
|
||||
return false
|
||||
}, [url])
|
||||
}
|
||||
Reference in New Issue
Block a user