import dagre from '@dagrejs/dagre' import type { Node, Edge } from '@xyflow/react' const NODE_WIDTH = 280 const DEFAULT_NODE_HEIGHT = 100 interface LayoutOptions { direction?: 'TB' | 'LR' rankSep?: number nodeSep?: number } export function getLayoutedElements( nodes: Node[], edges: Edge[], options: LayoutOptions = {} ): Node[] { const { direction = 'TB', rankSep = 100, nodeSep = 40 } = options const g = new dagre.graphlib.Graph() g.setDefaultEdgeLabel(() => ({})) g.setGraph({ rankdir: direction, ranksep: rankSep, nodesep: nodeSep }) nodes.forEach((node) => { const height = node.measured?.height ?? node.data?.estimatedHeight ?? DEFAULT_NODE_HEIGHT g.setNode(node.id, { width: NODE_WIDTH, height }) }) edges.forEach((edge) => { g.setEdge(edge.source, edge.target) }) dagre.layout(g) return nodes.map((node) => { const dagreNode = g.node(node.id) // dagre gives center positions — convert to top-left for React Flow const x = dagreNode.x - NODE_WIDTH / 2 const y = dagreNode.y - (dagreNode.height ?? DEFAULT_NODE_HEIGHT) / 2 return { ...node, position: { x, y } } }) } export { NODE_WIDTH, DEFAULT_NODE_HEIGHT }