import { useEffect, useMemo } from "react"; import ReactFlow, { Background, BackgroundVariant, Controls, MiniMap, useReactFlow, ReactFlowProvider, type Node, type NodeMouseHandler, } from "reactflow"; import "reactflow/dist/style.css"; import "./graph-overrides.css"; import { layoutGraph } from "../lib/layout"; import type { IRGraph, IRNode } from "../types"; import { nodeTypes } from "./CustomNodes"; interface Props { ir: IRGraph; onSelectNode: (node: IRNode | null) => void; } function GraphViewInner({ ir, onSelectNode }: Props) { const { nodes, edges } = useMemo(() => layoutGraph(ir), [ir]); const { fitView } = useReactFlow(); // Re-fit the camera every time the underlying graph topology changes // (e.g. a new model loaded, or the granularity slider collapsed clusters). // Without this, the viewport stays where the previous graph was and the // user can end up staring at an empty panel. useEffect(() => { const id = window.setTimeout(() => { fitView({ duration: 200, padding: 0.15 }); }, 50); return () => window.clearTimeout(id); }, [nodes.length, edges.length, fitView]); const handleNodeClick: NodeMouseHandler = (_e, node) => { const irNode = (node.data as { irNode?: IRNode }).irNode ?? null; onSelectNode(irNode); }; const handlePaneClick = () => onSelectNode(null); const nodeColor = (n: Node) => (n.data as { color?: string }).color ?? "#6477a8"; return ( ); } export function GraphView(props: Props) { return ( ); }