"use client"; import { motion } from "motion/react"; import { ChartFrame } from "@/components/charts/chart-frame"; export type FlowKind = "start" | "process" | "decision" | "end"; export type FlowNode = { id: string; label: string; kind?: FlowKind; col: number; row: number }; export type FlowEdge = { from: string; to: string; label?: string }; type FlowchartProps = { nodes: FlowNode[]; edges: FlowEdge[]; width?: number; height?: number; className?: string; }; const BOX_W = 132; const BOX_H = 50; /** Flowchart — grid-placed nodes (start/process/decision/end shapes) reveal by row; connectors draw with arrowheads. */ export function Flowchart({ nodes, edges, width = 680, height = 420, className }: FlowchartProps) { const maxCol = Math.max(...nodes.map((n) => n.col)); const maxRow = Math.max(...nodes.map((n) => n.row)); const px = (c: number) => (maxCol === 0 ? width / 2 : 90 + (c / maxCol) * (width - 180)); const py = (r: number) => (maxRow === 0 ? height / 2 : 50 + (r / maxRow) * (height - 100)); const byId = new Map(nodes.map((n) => [n, { x: px(n.col), y: py(n.row) }] as const)); const posOf = (id: string) => { const n = nodes.find((x) => x.id === id); return n ? byId.get(n)! : null; }; return ( {({ inView, reduce }) => ( <> {edges.map((e, i) => { const a = posOf(e.from); const b = posOf(e.to); if (!a || !b) return null; const vertical = Math.abs(b.y - a.y) >= Math.abs(b.x - a.x); const start = vertical ? { x: a.x, y: a.y + BOX_H / 2 } : { x: a.x + BOX_W / 2, y: a.y }; const end = vertical ? { x: b.x, y: b.y - BOX_H / 2 - 8 } : { x: b.x - BOX_W / 2 - 8, y: b.y }; const d = vertical ? `M${start.x},${start.y} V${(start.y + end.y) / 2} H${end.x} V${end.y}` : `M${start.x},${start.y} H${(start.x + end.x) / 2} V${end.y} H${end.x}`; return ( {e.label && ( {e.label} )} ); })} {nodes.map((n, i) => { const p = byId.get(n)!; const kind = n.kind ?? "process"; const pill = kind === "start" || kind === "end"; const decision = kind === "decision"; return ( {decision ? ( ) : ( )} {n.label} ); })} )} ); }