| import type { Transformer } from "./types.js"; | |
| import katex from "katex"; | |
| /** | |
| * Renders math placeholders into static KaTeX HTML. | |
| * | |
| * `@tiptap/extension-mathematics` only produces empty placeholders in its | |
| * static `renderHTML` (the actual KaTeX rendering lives in a client-side | |
| * NodeView): | |
| * - inline: `<span data-type="inline-math" data-latex="...">` | |
| * - block: `<div data-type="block-math" data-latex="...">` | |
| * | |
| * `generateHTML()` (used by the publisher) never runs the NodeView, so without | |
| * this transformer the published page would contain empty, invisible math | |
| * nodes. We render the `data-latex` server-side with `katex.renderToString` | |
| * so the published article is fully static (the page already loads the KaTeX | |
| * stylesheet; no client-side JS is required). | |
| */ | |
| const SELECTOR = '[data-type="inline-math"], [data-type="block-math"]'; | |
| export const mathTransformer: Transformer = { | |
| name: "math", | |
| apply(document) { | |
| for (const el of [...document.querySelectorAll(SELECTOR)]) { | |
| const latex = el.getAttribute("data-latex") || ""; | |
| const displayMode = el.getAttribute("data-type") === "block-math"; | |
| if (!latex.trim()) { | |
| // Nothing to render: drop the empty placeholder so it leaves no | |
| // invisible gap in the published article. | |
| el.remove(); | |
| continue; | |
| } | |
| // `throwOnError: false` makes KaTeX emit a red error node instead of | |
| // throwing, mirroring the editor's behaviour and keeping publish | |
| // resilient to a single malformed expression. | |
| el.innerHTML = katex.renderToString(latex, { | |
| displayMode, | |
| throwOnError: false, | |
| output: "htmlAndMathml", | |
| }); | |
| } | |
| }, | |
| }; | |