feat(messages): KaTeX math rendering (P4-4)
Renders LaTeX via spec data-mx-maths spans/divs (KaTeX render of the attr, children as fallback) and conservative $…$ / $$…$$ text detection (escape-aware, currency-guarded, never inside code/pre). KaTeX + CSS load lazily on first math (ReactPrism pattern) — verified absent from the eager bundle. Sanitizer unchanged by design (we render post-sanitize from attr/text; no incoming MathML accepted). +14 unit tests. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,41 @@
|
||||
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`.
|
||||
*/
|
||||
export default function KaTeX({ latex, displayMode = false }: KaTeXProps) {
|
||||
const html = katex.renderToString(latex, {
|
||||
displayMode,
|
||||
throwOnError: false,
|
||||
output: 'htmlAndMathml',
|
||||
});
|
||||
|
||||
const Wrapper = displayMode ? 'div' : 'span';
|
||||
|
||||
return (
|
||||
<Wrapper
|
||||
// KaTeX output is generated by our own render call (trusted-safe).
|
||||
// eslint-disable-next-line react/no-danger
|
||||
dangerouslySetInnerHTML={{ __html: html }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user