80 行
2.3 KiB
TypeScript
80 行
2.3 KiB
TypeScript
import { createElement, useMemo } from 'react'
|
|
import { useLocation } from 'react-router-dom'
|
|
|
|
import PrefetchLink from '@/components/PrefetchLink'
|
|
import { localiseUIChildren } from '@/components/LocalisedText'
|
|
import { cn } from '@/lib/utils'
|
|
|
|
import type { MDXComponents } from 'mdx/types'
|
|
import type { ComponentProps, HTMLAttributes } from 'react'
|
|
|
|
|
|
const MDXLink = (
|
|
{ href, children, ...props }: ComponentProps<'a'>,
|
|
) => {
|
|
const location = useLocation ()
|
|
const url = useMemo (() => {
|
|
try
|
|
{
|
|
const base = new URL (location.pathname + location.search, window.location.origin)
|
|
return href ? new URL (href, base) : null
|
|
}
|
|
catch
|
|
{
|
|
return null
|
|
}
|
|
}, [href, location.pathname, location.search])
|
|
const internal = url != null
|
|
&& url.origin === window.location.origin
|
|
&& (url.protocol === 'http:' || url.protocol === 'https:')
|
|
const anchor = href?.startsWith ('#')
|
|
|| (url?.pathname === location.pathname
|
|
&& url.search === location.search && Boolean (url.hash))
|
|
const external = url != null && !(internal)
|
|
&& (url.protocol === 'http:' || url.protocol === 'https:')
|
|
|
|
if (internal && !(anchor) && props.download == null)
|
|
{
|
|
return (
|
|
<PrefetchLink to={url.pathname + url.search + url.hash} {...props}>
|
|
{children}
|
|
</PrefetchLink>)
|
|
}
|
|
|
|
return (
|
|
<a href={href}
|
|
{...props}
|
|
target={external ? props.target ?? '_blank' : props.target}
|
|
rel={props.rel ?? 'noopener noreferrer'}>
|
|
{children}
|
|
</a>)
|
|
}
|
|
|
|
|
|
export const useMDXComponents = (): MDXComponents => ({ a: MDXLink })
|
|
|
|
|
|
const ainuElement = (element: string) => {
|
|
const AinuElement = ({ children, className, ...props }: HTMLAttributes<HTMLElement>) =>
|
|
createElement (element,
|
|
{ ...props, lang: 'ain-Kana', className: cn ('ainu-ui-text', className) },
|
|
localiseUIChildren (children, 'ain-Kana'))
|
|
return AinuElement
|
|
}
|
|
|
|
|
|
// Opt in only for authored Ainu UI documents, never user-supplied Markdown.
|
|
export const ainuMDXComponents: MDXComponents = {
|
|
p: ainuElement ('p'),
|
|
h1: ainuElement ('h1'),
|
|
h2: ainuElement ('h2'),
|
|
h3: ainuElement ('h3'),
|
|
h4: ainuElement ('h4'),
|
|
h5: ainuElement ('h5'),
|
|
h6: ainuElement ('h6'),
|
|
li: ainuElement ('li'),
|
|
dt: ainuElement ('dt'),
|
|
dd: ainuElement ('dd'),
|
|
th: ainuElement ('th'),
|
|
td: ainuElement ('td') }
|