"use client"; import { useCallback, useState } from "react"; import { Background, BackgroundVariant, Controls, type Edge, type EdgeTypes, type FitViewOptions, type Node, type NodeTypes, type OnInit, ReactFlow, } from "@xyflow/react"; import "@xyflow/react/dist/style.css"; type FlowCanvasProps = { nodes: TNode[]; edges: TEdge[]; nodeTypes?: NodeTypes; edgeTypes?: EdgeTypes; /** Inline style for the canvas wrapper (height, minHeight, etc.). */ canvasStyle: React.CSSProperties; /** Extra class on the canvas wrapper (the `flow-canvas` class is always * applied). Use it to scope per-diagram styles. */ className?: string; fitViewOptions?: FitViewOptions; maxZoom?: number; translateExtent?: [[number, number], [number, number]]; ariaLabel?: string; }; const DEFAULT_FIT_VIEW = { padding: 0.05 } satisfies FitViewOptions; /** * Shared ReactFlow wrapper for docs diagrams. * * Behavior: * - Drag-to-pan, pinch-to-zoom, double-click-to-zoom. * - Scroll wheel passes through to the page (zoomOnScroll/panOnScroll off). * - On mount, the view is fitted and `minZoom` is locked to the fitted zoom * so the user can zoom in but not out beyond the initial framing. * - Nodes are non-draggable, non-selectable, non-focusable — the diagram is * a static read-only artifact. * - Common CSS lives in `global.css` under the `.flow-canvas` selector; the * per-diagram `className` adds anything else specific to that diagram. */ export function FlowCanvas({ nodes, edges, nodeTypes, edgeTypes, canvasStyle, className, fitViewOptions = DEFAULT_FIT_VIEW, maxZoom = 1.5, translateExtent, ariaLabel, }: FlowCanvasProps) { const [minZoom, setMinZoom] = useState(0.15); const handleInit = useCallback>( (instance) => { requestAnimationFrame(() => { void instance.fitView(fitViewOptions).then(() => { setMinZoom(instance.getZoom()); }); }); }, [fitViewOptions], ); return (
Drag to pan · ⌘/Ctrl + scroll to zoom
); }