2025-05-28 13:36:35 -07:00

62 lines
1.8 KiB
TypeScript

import React, { useEffect, useRef, useState, useCallback } from 'react';
import mermaid, { MermaidConfig } from 'mermaid';
import { SxProps } from '@mui/material/styles';
import { Box } from '@mui/material';
import { useResizeObserverAndMutationObserver } from '../hooks/useAutoScrollToBottom';
const defaultMermaidConfig : MermaidConfig = {
startOnLoad: true,
securityLevel: 'loose',
fontFamily: 'Fira Code',
};
interface MermaidProps {
chart: string;
sx?: SxProps;
className?: string;
mermaidConfig?: MermaidConfig;
}
const Mermaid: React.FC<MermaidProps> = (props: MermaidProps) => {
const { chart, sx, className, mermaidConfig } = props;
const [ visible, setVisible] = useState<boolean>(false);
const containerRef = useRef<HTMLDivElement>(null);
const checkVisible = useCallback(() => {
if (containerRef.current) {
const { width, height } = containerRef.current.getBoundingClientRect();
if (width > 0 && height > 0) {
setVisible(true);
}
}
}, [containerRef, setVisible]);
useEffect(() => {
const renderMermaid = async () => {
if (containerRef.current && visible && chart) {
try {
await mermaid.initialize(mermaidConfig || defaultMermaidConfig);
await mermaid.run({ nodes: [containerRef.current] });
} catch (e) {
console.error("Mermaid render error:", e, containerRef.current);
}
}
}
renderMermaid();
}, [containerRef, mermaidConfig, visible, chart]);
// Observe container and TextField size, plus DOM changes
useResizeObserverAndMutationObserver(containerRef, null, checkVisible);
return <Box className={className || "Mermaid"} ref={containerRef} sx={{
display: "flex",
flexGrow: 1,
...sx
}}>
{chart}
</Box>;
};
export {
Mermaid
};