/* eslint-disable @typescript-eslint/no-unnecessary-condition */ "use client"; import { useCallback, useEffect, useRef, useState } from "react"; import mermaid from "mermaid"; interface MermaidViewerProps { diagram: string; className?: string; onNodeClick?: (nodeId: string) => void; } export function MermaidViewer({ diagram, className = "", onNodeClick, }: MermaidViewerProps): React.JSX.Element { const containerRef = useRef(null); const [error, setError] = useState(null); const [isLoading, setIsLoading] = useState(true); const renderDiagram = useCallback(async () => { if (!containerRef.current || !diagram) { setIsLoading(false); return; } setIsLoading(true); setError(null); try { // Initialize mermaid with theme based on document const isDark = document.documentElement.classList.contains("dark"); mermaid.initialize({ startOnLoad: false, theme: isDark ? "dark" : "default", flowchart: { useMaxWidth: true, htmlLabels: true, curve: "basis", }, securityLevel: "loose", }); // Generate unique ID for this render const id = `mermaid-${String(Date.now())}`; // Render the diagram const { svg } = await mermaid.render(id, diagram); const container = containerRef.current; if (container) { container.innerHTML = svg; // Add click handlers to nodes if callback provided if (onNodeClick) { const nodes = container.querySelectorAll(".node"); nodes.forEach((node) => { node.addEventListener("click", () => { const nodeId = node.id.replace(/^flowchart-/, "").replace(/-\d+$/, ""); if (nodeId) { onNodeClick(nodeId); } }); (node as HTMLElement).style.cursor = "pointer"; }); } } } catch (err) { setError(err instanceof Error ? err.message : "Failed to render diagram"); } finally { setIsLoading(false); } }, [diagram, onNodeClick]); useEffect(() => { void renderDiagram(); }, [renderDiagram]); // Re-render on theme change useEffect(() => { const observer = new MutationObserver((mutations) => { mutations.forEach((mutation) => { if (mutation.attributeName === "class") { void renderDiagram(); } }); }); observer.observe(document.documentElement, { attributes: true }); return (): void => { observer.disconnect(); }; }, [renderDiagram]); if (!diagram) { return (
No diagram data available
); } if (error) { return (
Failed to render diagram
{error}
          {diagram}
        
); } return (
{isLoading && (
)}
); }