import React from 'react'; import katex from 'katex'; import 'katex/dist/katex.min.css'; type KaTeXProps = { /** Raw LaTeX source (without `$`/`$$` delimiters). */ latex: string; /** Render as block (display) math when true, inline otherwise. */ displayMode?: boolean; }; /** * Lazily-loaded KaTeX renderer. * * This module statically imports `katex` and its stylesheet, so both only enter * the bundle via the dynamic `import()` of this file (see the `lazy()` wrapper * in `react-custom-html-parser.tsx`). They are therefore NOT part of the eager * import graph. * * We render with `throwOnError: false`, so KaTeX itself renders a parse error * inline (in its error colour) rather than throwing. The HTML returned by * `renderToString` is produced by our own trusted call from a fixed options * object — it is safe to inject via `dangerouslySetInnerHTML`. * * `maxSize`/`maxExpand` cap how large a single glyph (`\\rule`, etc.) or macro * expansion remote LaTeX can request, and `trust: false` disables commands * that can embed arbitrary HTML/URLs (e.g. `\\includegraphics`, `\\href`) — * without these a hostile `$$...$$` from a remote message can DoS or (via * `trust`) inject unsafe links (Gitea #65). `strict: 'ignore'` keeps unknown- * but-harmless LaTeX from spamming the console as before. Extremely long * source is rendered as plain text rather than handed to KaTeX at all. */ const MAX_LATEX_LENGTH = 5000; export default function KaTeX({ latex, displayMode = false }: KaTeXProps) { if (latex.length > MAX_LATEX_LENGTH) { const Plain = displayMode ? 'div' : 'span'; return {latex}; } const html = katex.renderToString(latex, { displayMode, throwOnError: false, output: 'htmlAndMathml', maxSize: 10, maxExpand: 100, trust: false, strict: 'ignore', }); const Wrapper = displayMode ? 'div' : 'span'; return ( ); }