Files
documenso/apps/docs/src/components/mdx/mermaid.tsx
T
2026-05-08 16:04:22 +10:00

67 lines
1.5 KiB
TypeScript

'use client';
import { useTheme } from 'next-themes';
import { useEffect, useId, useRef, useState } from 'react';
export const Mermaid = ({ chart }: { chart: string }) => {
const [mounted, setMounted] = useState(false);
useEffect(() => {
setMounted(true);
}, []);
if (!mounted) {
return null;
}
return <MermaidContent chart={chart} />;
};
const MermaidContent = ({ chart }: { chart: string }) => {
const id = useId();
const containerRef = useRef<HTMLDivElement>(null);
const { resolvedTheme } = useTheme();
const [svg, setSvg] = useState<string | null>(null);
useEffect(() => {
let cancelled = false;
const render = async () => {
const mermaid = (await import('mermaid')).default;
mermaid.initialize({
startOnLoad: false,
securityLevel: 'loose',
fontFamily: 'inherit',
themeCSS: 'margin: 1.5rem auto 0;',
theme: resolvedTheme === 'dark' ? 'dark' : 'default',
});
const { svg: rendered, bindFunctions } = await mermaid.render(
id.replaceAll(':', ''),
chart.replaceAll('\\n', '\n'),
);
if (!cancelled) {
setSvg(rendered);
if (containerRef.current) {
bindFunctions?.(containerRef.current);
}
}
};
void render();
return () => {
cancelled = true;
};
}, [chart, id, resolvedTheme]);
if (!svg) {
return null;
}
return <div ref={containerRef} dangerouslySetInnerHTML={{ __html: svg }} />;
};