(
blocks: Record<string, BlockState>,
edges: Edge[],
options: {
isContainer: boolean
layoutOptions?: LayoutOptions
subflowDepths?: Map<string, number>
}
)
| 391 | * @returns The laid-out nodes with updated positions, and bounding dimensions |
| 392 | */ |
| 393 | export function layoutBlocksCore( |
| 394 | blocks: Record<string, BlockState>, |
| 395 | edges: Edge[], |
| 396 | options: { |
| 397 | isContainer: boolean |
| 398 | layoutOptions?: LayoutOptions |
| 399 | subflowDepths?: Map<string, number> |
| 400 | } |
| 401 | ): { nodes: Map<string, GraphNode>; dimensions: { width: number; height: number } } { |
| 402 | if (Object.keys(blocks).length === 0) { |
| 403 | return { nodes: new Map(), dimensions: { width: 0, height: 0 } } |
| 404 | } |
| 405 | |
| 406 | const layoutOptions: LayoutOptions = |
| 407 | options.layoutOptions ?? |
| 408 | (options.isContainer ? CONTAINER_LAYOUT_OPTIONS : DEFAULT_LAYOUT_OPTIONS) |
| 409 | |
| 410 | // 1. Assign layers (with subflow depth adjustment for subflow end edges) |
| 411 | const nodes = assignLayers(blocks, edges, options.subflowDepths) |
| 412 | |
| 413 | // 2. Prepare metrics |
| 414 | prepareBlockMetrics(nodes) |
| 415 | |
| 416 | // 3. Group by layer |
| 417 | const layers = groupByLayer(nodes) |
| 418 | |
| 419 | // 4. Calculate positions (pass edges for handle offset calculations) |
| 420 | calculatePositions(layers, edges, layoutOptions) |
| 421 | |
| 422 | // 5. Normalize positions |
| 423 | let dimensions = normalizePositions(nodes, { isContainer: options.isContainer }) |
| 424 | |
| 425 | // 6. Snap to grid if gridSize is specified (recalculates dimensions) |
| 426 | const snappedDimensions = snapNodesToGrid(nodes, layoutOptions.gridSize) |
| 427 | if (snappedDimensions) { |
| 428 | dimensions = snappedDimensions |
| 429 | } |
| 430 | |
| 431 | return { nodes, dimensions } |
| 432 | } |
no test coverage detected