63 lines
1.4 KiB
TypeScript
63 lines
1.4 KiB
TypeScript
import katex, { type KatexOptions, ParseError } from 'katex'
|
|
import { type ComponentProps, type ReactElement } from 'react'
|
|
|
|
export type Props<T extends keyof JSX.IntrinsicElements = 'div'> =
|
|
ComponentProps<T> &
|
|
Partial<{
|
|
as: T
|
|
block: boolean
|
|
errorColor: string
|
|
renderError: (error: ParseError | TypeError) => ReactElement
|
|
settings: KatexOptions
|
|
}> & {
|
|
math: string
|
|
}
|
|
|
|
/**
|
|
* This is only used for the RSS feed
|
|
*/
|
|
export function SyncTeX({
|
|
children,
|
|
math,
|
|
block,
|
|
errorColor,
|
|
renderError,
|
|
settings,
|
|
as: asComponent,
|
|
...props
|
|
}: Props) {
|
|
const Component = asComponent || (block ? 'div' : 'span')
|
|
const content = (children ?? math) as string
|
|
|
|
let innerHtml: string
|
|
try {
|
|
innerHtml = katex.renderToString(content, {
|
|
displayMode: !!block,
|
|
errorColor,
|
|
throwOnError: !!renderError,
|
|
...settings,
|
|
})
|
|
} catch (error) {
|
|
if (error instanceof ParseError || error instanceof TypeError) {
|
|
if (renderError) {
|
|
return renderError(error)
|
|
} else {
|
|
innerHtml = error.message
|
|
}
|
|
} else {
|
|
throw error
|
|
}
|
|
}
|
|
|
|
return (
|
|
<Component {...props} dangerouslySetInnerHTML={{ __html: innerHtml }} />
|
|
)
|
|
}
|
|
|
|
export default async function TeX(props: Props) {
|
|
// @ts-expect-error CSS not JS
|
|
await import('katex/dist/katex.min.css')
|
|
|
|
return <SyncTeX {...props} />
|
|
}
|