{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "flow-diagram",
  "type": "registry:component",
  "title": "Flow Diagram",
  "description": "Interactive flow diagram with nodes, edges, and controls.",
  "dependencies": [
    "@vllnt/ui@^0.2.1"
  ],
  "registryDependencies": [],
  "files": [
    {
      "path": "registry/default/flow-diagram/flow-diagram.tsx",
      "content": "\"use client\";\n\nimport \"@xyflow/react/dist/style.css\";\n\nimport { memo, useCallback, useEffect } from \"react\";\n\nimport {\n  type Node,\n  type NodeMouseHandler,\n  ReactFlowProvider,\n} from \"@xyflow/react\";\n\nimport { cn } from \"@vllnt/ui\";\n\nimport { FlowCanvas } from \"./flow-canvas\";\nimport { FlowErrorBoundary } from \"./flow-error-boundary\";\nimport { FlowFullscreen } from \"./flow-fullscreen\";\nimport type {\n  FlowDiagramEdge,\n  FlowDiagramNode,\n  FlowDiagramProps,\n} from \"./types\";\nimport { useFlowDiagram } from \"./use-flow-diagram\";\n\n/**\n * Validates nodes and edges, logging warnings for common issues.\n */\nfunction validateFlowData(\n  nodes: FlowDiagramNode[],\n  edges: FlowDiagramEdge[],\n): void {\n  if (nodes.length === 0 && edges.length > 0) {\n    console.warn(\n      \"[FlowDiagram] Edges provided without nodes - edges will not render\",\n    );\n  }\n\n  const nodeIds = new Set(nodes.map((n) => n.id));\n  const invalidEdges = edges.filter(\n    (e) => !nodeIds.has(e.source) || !nodeIds.has(e.target),\n  );\n\n  if (invalidEdges.length > 0) {\n    console.warn(\n      `[FlowDiagram] ${invalidEdges.length} edge(s) reference non-existent nodes:`,\n      invalidEdges.map((e) => `${e.id}: ${e.source} -> ${e.target}`),\n    );\n  }\n\n  const nodesWithoutPosition = nodes.filter((n) => n.position === undefined);\n  if (nodesWithoutPosition.length > 0) {\n    console.warn(\n      `[FlowDiagram] ${nodesWithoutPosition.length} node(s) missing position:`,\n      nodesWithoutPosition.map((n) => n.id),\n    );\n  }\n}\n\nconst FlowDiagramInner = memo(function FlowDiagramInner({\n  allowCopy = false,\n  allowFullscreen = true,\n  className,\n  edges,\n  fitView = true,\n  fitViewOptions,\n  height = 400,\n  nodes,\n  onNodeClick,\n  showControls = true,\n  title,\n}: FlowDiagramProps) {\n  // Check input on mount and when data changes\n  useEffect(() => {\n    validateFlowData(nodes, edges);\n  }, [nodes, edges]);\n\n  const {\n    closeFullscreen,\n    copyStatus,\n    copyToClipboard,\n    fitView: handleFitView,\n    isFullscreen,\n    toggleFullscreen,\n    zoomIn,\n    zoomOut,\n  } = useFlowDiagram({ allowCopy, allowFullscreen });\n\n  // Memoize node click handler to prevent unnecessary re-renders\n  const handleNodeClick: NodeMouseHandler | undefined = useCallback(\n    (_event: React.MouseEvent, node: Node) => {\n      onNodeClick?.(node as FlowDiagramNode);\n    },\n    [onNodeClick],\n  );\n\n  const handleCopy = useCallback(() => {\n    void copyToClipboard();\n  }, [copyToClipboard]);\n\n  const canvasProps = {\n    allowCopy,\n    allowFullscreen,\n    className,\n    copyStatus,\n    edges,\n    fitView,\n    fitViewOptions,\n    height,\n    isFullscreen,\n    nodes,\n    onCopy: allowCopy ? handleCopy : undefined,\n    onFitView: handleFitView,\n    onFullscreen: allowFullscreen ? toggleFullscreen : undefined,\n    onNodeClick: onNodeClick ? handleNodeClick : undefined,\n    onZoomIn: zoomIn,\n    onZoomOut: zoomOut,\n    showControls,\n    title,\n  };\n\n  if (isFullscreen) {\n    return (\n      <>\n        <div\n          className={cn(\n            \"rounded-lg border border-border bg-muted/50\",\n            className,\n          )}\n          style={{ height }}\n        />\n        <FlowFullscreen isOpen={isFullscreen} onClose={closeFullscreen}>\n          <FlowCanvas {...canvasProps} />\n        </FlowFullscreen>\n      </>\n    );\n  }\n\n  return <FlowCanvas {...canvasProps} />;\n});\n\n/**\n * FlowDiagram component for rendering interactive flow diagrams.\n * Uses @xyflow/react under the hood with error boundary protection.\n *\n * @example\n * ```tsx\n * <FlowDiagram\n *   nodes={[\n *     { id: '1', data: { label: 'Start' }, position: { x: 0, y: 0 } },\n *     { id: '2', data: { label: 'End' }, position: { x: 200, y: 100 } }\n *   ]}\n *   edges={[{ id: 'e1-2', source: '1', target: '2' }]}\n *   showControls\n *   allowFullscreen\n * />\n * ```\n */\nexport const FlowDiagram = memo(function FlowDiagram(props: FlowDiagramProps) {\n  return (\n    <FlowErrorBoundary height={props.height}>\n      <ReactFlowProvider>\n        <FlowDiagramInner {...props} />\n      </ReactFlowProvider>\n    </FlowErrorBoundary>\n  );\n});\n",
      "type": "registry:component"
    }
  ],
  "version": "0.2.1",
  "stability": "stable"
}
