chain line: the logic is the connective — LaTeX ∧ and ⟹ via KaTeX (owner ruling)
'A → B → C' misread as chained implication when A and B are CO-premises. The honest shape (owner, 2026-09-30): premises join with the LaTeX LAND (∧), the conclusion separates by the LaTeX IMPLICATION (⟹) — A ∧ B ⟹ C. The glyphs are REAL KaTeX renders — components/latex-glyph.tsx wraps katex.renderToString (cached per command; the app's math engine, the stylesheet already rides app-wide from app/layout.tsx). No SVGs, no font-dependent unicode. PROMINENT in the theme foreground (white in the dark theme) per the owner's same-round ruling — the logic is the payload, not the old dim gray. A lonely chip carries no glyph (it reads as a standalone proposition); the plain-text '→' survives only in the row's aria-label (formatChainLine, the screen-reader form).
This commit is contained in:
@@ -0,0 +1,53 @@
|
||||
import katex from "katex";
|
||||
|
||||
/**
|
||||
* THE LaTeX glyph seam (owner ruling, 2026-09-30): UI connectors that
|
||||
* want math symbols render the REAL LaTeX glyphs through KaTeX — the
|
||||
* app's math engine, already shipped (app/layout.tsx carries the
|
||||
* katex stylesheet) — never hand-rolled SVGs or font-dependent
|
||||
* unicode. Born for the chain table's logical connectives: premises
|
||||
* join with \land (∧), the conclusion separates with \implies (⟹) —
|
||||
* `A ∧ B ⟹ C`, not the misleading `A → B → C`.
|
||||
*
|
||||
* Prominent by the same ruling: the connectives render in the
|
||||
* theme's FOREGROUND (white in the dark theme) — the chain line's
|
||||
* logic is the payload, not decoration. Callers pass the class.
|
||||
*/
|
||||
|
||||
/** Cached katex HTML per command — the glyph set is tiny and
|
||||
* renderToString is pure; one render per command per process. */
|
||||
const cache = new Map<string, string>();
|
||||
|
||||
/** The raw katex HTML for a LaTeX command (pure, sync — SSR-safe). */
|
||||
export function latexGlyphHtml(cmd: string): string {
|
||||
let html = cache.get(cmd);
|
||||
if (html === undefined) {
|
||||
html = katex.renderToString(cmd, { throwOnError: false, output: "html" });
|
||||
cache.set(cmd, html);
|
||||
}
|
||||
return html;
|
||||
}
|
||||
|
||||
/** One rendered LaTeX glyph. `cmd` is the LaTeX command ("\land",
|
||||
* "\implies"); the output is aria-hidden — callers carry the textual
|
||||
* aria-label (formatChainLine keeps the plain-text form). */
|
||||
export function LatexGlyph({
|
||||
cmd,
|
||||
testid,
|
||||
className,
|
||||
}: {
|
||||
cmd: string;
|
||||
testid?: string;
|
||||
className?: string;
|
||||
}) {
|
||||
return (
|
||||
<span
|
||||
data-testid={testid}
|
||||
aria-hidden="true"
|
||||
className={className}
|
||||
// katex.renderToString is the library's own trusted output
|
||||
// (the same thing rehype-katex injects for markdown math).
|
||||
dangerouslySetInnerHTML={{ __html: latexGlyphHtml(cmd) }}
|
||||
/>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user