import { useEffect, useId, useRef, useState } from 'react'; import { DiagramLoader } from './DiagramLoader.js'; import { useInView } from './useInView.js'; /** * Mermaid runs in the browser. * * Rendering diagrams at build time would mean `rehype-mermaid`, which means Playwright and a * downloaded browser as an install dependency of a documentation CLI. The stated consequence * is that diagrams are absent from the prerendered HTML; page *text*, which is what the SEO * guarantee protects, is not. */ export function Mermaid({ chart }: { chart: string }) { const id = useId().replace(/[^a-zA-Z0-9]/g, ''); const container = useRef(null); const inView = useInView(container); const [svg, setSvg] = useState(); const [error, setError] = useState(); useEffect(() => { // Mermaid's layout pass is synchronous and can't be interrupted, so a large diagram // freezes the main thread — including any pending navigation — the moment it starts. // Waiting until the diagram is actually scrolled into view keeps that off the critical // path of landing on the page. if (!inView) return; let cancelled = false; void (async () => { try { const { default: mermaid } = await import('mermaid'); const dark = document.documentElement.classList.contains('dark'); mermaid.initialize({ startOnLoad: false, theme: dark ? 'dark' : 'default', securityLevel: 'strict' }); const { svg: rendered } = await mermaid.render(`seemore-mermaid-${id}`, chart); if (!cancelled) setSvg(rendered); } catch (cause) { if (!cancelled) setError(cause instanceof Error ? cause.message : String(cause)); } })(); return () => { cancelled = true; }; }, [inView, chart, id]); if (error !== undefined) { return (
        {`Could not render this diagram: ${error}`}
      
); } return (
{svg === undefined ? ( inView ? ( ) : (
{chart}
) ) : undefined}
); } export default Mermaid;