Fix mermaid diagram arrowheads not rendering
The `@boneskull/typedoc-plugin-mermaid` creates both dark and light theme variants of each diagram, each with identical marker IDs (e.g., `#arrowhead`). When mermaid renders SVGs at runtime, lines reference `url(#arrowhead)`, but the browser resolves this to the first match in document order — the hidden dark-theme SVG — causing arrows to be invisible. The fix removes dark-theme `<div class="mermaid dark">` elements at build time, leaving only one SVG per diagram with unique marker IDs. A CSS filter (`filter: invert(1) hue-rotate(180deg)`) handles dark mode styling instead. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
0058ad85bc
commit
4546a686c3
1 changed files with 54 additions and 6 deletions
|
|
@ -1,12 +1,15 @@
|
|||
/**
|
||||
* TypeDoc plugin that properly decodes HTML entities in mermaid code blocks.
|
||||
* TypeDoc plugin that fixes mermaid diagram rendering issues.
|
||||
*
|
||||
* This runs BEFORE the mermaid plugin and converts HTML entities back to raw
|
||||
* characters, allowing mermaid to parse them correctly.
|
||||
* 1. Decodes HTML entities in mermaid code blocks before the mermaid plugin
|
||||
* processes them. The @boneskull/typedoc-plugin-mermaid converts < to #lt;
|
||||
* and > to #gt;, but those aren't valid mermaid entities.
|
||||
*
|
||||
* The @boneskull/typedoc-plugin-mermaid converts < to #lt; and > to #gt;,
|
||||
* but those aren't valid mermaid entities (mermaid uses numeric codes like #60;).
|
||||
* This plugin sidesteps the issue by decoding entities before mermaid sees them.
|
||||
* 2. Removes dark-theme mermaid divs to fix duplicate marker IDs. The mermaid
|
||||
* plugin creates both dark and light variants with identical marker IDs
|
||||
* (e.g., `#arrowhead`), causing the browser to resolve references to the
|
||||
* wrong SVG. By keeping only light-theme divs, we avoid duplicate IDs.
|
||||
* CSS filters handle dark mode styling.
|
||||
*/
|
||||
|
||||
import { Renderer } from "typedoc";
|
||||
|
|
@ -29,6 +32,18 @@ function decodeHtmlEntities(html) {
|
|||
.replace(/&/g, "&"); // Must be last
|
||||
}
|
||||
|
||||
/**
|
||||
* CSS to invert mermaid diagrams in dark mode.
|
||||
* Since we only render light-theme diagrams, we use CSS filters for dark mode.
|
||||
*/
|
||||
const darkModeStyles = `
|
||||
<style>
|
||||
:root[data-theme="dark"] .mermaid-block .mermaid svg {
|
||||
filter: invert(1) hue-rotate(180deg);
|
||||
}
|
||||
</style>
|
||||
`;
|
||||
|
||||
/**
|
||||
* TypeDoc plugin entry point.
|
||||
* @param {import('typedoc').Application} app
|
||||
|
|
@ -51,4 +66,37 @@ export function load(app) {
|
|||
},
|
||||
200,
|
||||
);
|
||||
|
||||
// Use low priority (-100) to run after the mermaid plugin injects its content
|
||||
app.renderer.on(
|
||||
Renderer.EVENT_END_PAGE,
|
||||
(page) => {
|
||||
if (!page.contents) return;
|
||||
if (!page.contents.includes('class="mermaid-block"')) return;
|
||||
|
||||
// Remove dark-theme mermaid divs to avoid duplicate marker IDs
|
||||
page.contents = page.contents.replace(
|
||||
/<div class="mermaid dark">[\s\S]*?<\/div>/g,
|
||||
"",
|
||||
);
|
||||
|
||||
// Also remove the CSS that hides light-theme divs by default
|
||||
// The mermaid plugin adds visibility:hidden until JS sets display:block
|
||||
// Since we only have light divs now, make them visible immediately
|
||||
page.contents = page.contents.replace(
|
||||
/<div class="mermaid light">/g,
|
||||
'<div class="mermaid" style="display: block">',
|
||||
);
|
||||
|
||||
// Add dark mode CSS filter before </head>
|
||||
const headEndIndex = page.contents.indexOf("</head>");
|
||||
if (headEndIndex !== -1) {
|
||||
page.contents =
|
||||
page.contents.slice(0, headEndIndex) +
|
||||
darkModeStyles +
|
||||
page.contents.slice(headEndIndex);
|
||||
}
|
||||
},
|
||||
-100,
|
||||
);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue