Repository navigation
preview: Fix mermaid labels clipped in preview - #529
junereycasuga wants to merge 1 commit into
Conversation
|
Merged into the For anyone reading later, the root cause in one line: Verified by driving the built app over CDP and measuring each label's content width against its
Three extra checks beyond the screenshots:
One follow-up commit on top ( Closing here because the merge landed on the release branch rather than through the GitHub button, so this cannot auto-close. Ships in 2.21.0. |
|
thanks @adibhanna |
ZenNotes drew ```mermaid fences with mermaid.js. It worked, but it was the heaviest stack in the renderer (mermaid.core alone is 140 kB gzipped before any diagram chunk, about 800 kB across all of its chunks), it laid diagrams out asynchronously through temporary DOM, and its labels were HTML inside foreignObject, the layer behind every clipped-label bug here (ZenNotes#529, and the getBoundingClientRect patch ZenNotes#911 needed). Theming was a 160-line themeVariables map, rebuilt and re-rendered on every theme change. Pele (pele.run, obsidianmd/pele, MIT) reads the same Mermaid syntax with its own parsers and lays diagrams out itself, returning one SVG string synchronously. Before switching, every example in Mermaid 11.17's docs that mermaid.js accepts (476, across all 32 doc pages) rendered in Pele, as did every fence in the repo and the demo tour; only ZenUML, which ZenNotes never registered, is unsupported. In Chromium those 476 diagrams take 83 ms instead of 4.2 s. What changes: - lib/mermaid-render.ts loads Pele through a new pele-runtime module, so the async chunk has a name the perf harness and the packaged-web browser test can hold off the boot path, and keeps the shared (fonts, source) cache. Once the runtime and a diagram type are loaded, peekMermaidSvg draws a new diagram on the spot, so typing one in live preview no longer shows a pending block. Fonts are the only theme input: labels are measured on a canvas in the note's text font, after any loading font settles. - The cache trims the source first. Preview keeps a fence's trailing newline and the editor trims its body, so split view used to draw every diagram twice under two keys, the double work the shared cache exists to remove. - Colour moved to CSS. A .pele rule in index.css maps --pele-* onto the --z-* tokens with the roles the themeVariables had (nodes on bg-2 with a bg-3 border, subgraphs on bg-softer, edges grey-1, series in the old pie and git order). One drawing is right in every theme, custom CSS themes included, and a theme switch repaints without a relayout. - The ZenNotes#911 getBoundingClientRect patch and its test are gone: labels are SVG text and wrap inside their box. - Images and links in diagrams stay off, as mermaid's strict mode had them, so drawing a diagram never fetches anything. - Preview shows a render error as text in .zen-diagram-error. The old branch wrote the message into innerHTML, and the message quotes the diagram source, so a crafted fence could inject markup. - pele 1.6.0 replaces mermaid in the five workspaces that declared it, pinned exactly while Pele moves fast. mermaid stays installed for Excalidraw's Mermaid-to-Excalidraw dialog, which still lazy-loads it; the chunk comments, preload deferral lists and perf patterns name both. What it deliberately does not do: no maxWidth is passed, so Pele never flips a wide left-to-right flowchart to top-down; the author's direction stands and the existing pan/zoom handles width. Pele's own zoom is not used. What users will notice: layouts are Pele's (node placement differs from mermaid.live, mindmaps draw as an outline tree), $$ math inside a label and raw HTML other than <br> and bold or italic show as written, and %%{init}%% theme settings give way to the app theme. The in-app manual, the website docs and the MCP instructions say so.
Summary
Fixes clipped mermaid diagram labels in the preview by ensuring text metrics are measured against the same loaded font that will paint the final SVG.
Mermaid measures text in a temporary element appended to
document.body. We were passingfontFamily: "inherit"in the theme, so the measurement font could resolve differently from the font actually used inside.prose-zen. Rendering also often ran before the active font finished loading, so labels were sized for a fallback font and then clipped once the real font painted.Changes
--z-text-fontas a concrete font-family stack and pass it to mermaid'sthemeVariables.fontFamily.document.fonts.readybefore callingmermaid.render()so text metrics are computed against the loaded font.Screenshots
Before
After