@statelyai/layout 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/README.md +71 -2
  2. package/dist/elkjs/index.cjs +3 -2
  3. package/dist/elkjs/index.d.cts +11 -2
  4. package/dist/elkjs/index.d.mts +11 -2
  5. package/dist/elkjs/index.mjs +3 -3
  6. package/dist/elkjs/main.cjs +2 -2
  7. package/dist/elkjs/main.d.cts +2 -2
  8. package/dist/elkjs/main.d.mts +2 -2
  9. package/dist/elkjs/main.mjs +2 -2
  10. package/dist/elkjs/worker-api.cjs +1 -1
  11. package/dist/elkjs/worker-api.d.cts +2 -2
  12. package/dist/elkjs/worker-api.d.mts +2 -2
  13. package/dist/elkjs/worker-api.mjs +1 -1
  14. package/dist/elkjs/worker.cjs +2 -2
  15. package/dist/elkjs/worker.mjs +2 -2
  16. package/dist/{elkjs-CFlfkEBz.mjs → elkjs-DaHMISnQ.mjs} +152 -3
  17. package/dist/{elkjs-BVnDwnBQ.cjs → elkjs-dMghiiWW.cjs} +157 -2
  18. package/dist/index-BEA_pzeT.d.cts +72 -0
  19. package/dist/{index-BSH2bloA.d.mts → index-D9dhxrRl.d.cts} +35 -3
  20. package/dist/index-DNTLRsDl.d.mts +72 -0
  21. package/dist/{index-CG712jzV.d.cts → index-DNixtE3h.d.mts} +35 -3
  22. package/dist/index.cjs +36 -9
  23. package/dist/index.d.cts +4 -3
  24. package/dist/index.d.mts +4 -3
  25. package/dist/index.mjs +4 -3
  26. package/dist/layered/index.cjs +1 -1
  27. package/dist/layered/index.d.cts +3 -2
  28. package/dist/layered/index.d.mts +3 -2
  29. package/dist/layered/index.mjs +1 -1
  30. package/dist/{layered-Cf9Rn8l7.cjs → layered-B2buJqMf.cjs} +417 -469
  31. package/dist/{layered-Bz2nWmVp.mjs → layered-DGFTeQSl.mjs} +391 -431
  32. package/dist/{layout-engine-WbC0YjjT.mjs → layout-engine-Cs5tatA6.mjs} +1 -1
  33. package/dist/{layout-engine-BNex9jxg.cjs → layout-engine-Dn1PiFwP.cjs} +1 -1
  34. package/dist/routing/index.cjs +28 -0
  35. package/dist/routing/index.d.cts +3 -0
  36. package/dist/routing/index.d.mts +3 -0
  37. package/dist/routing/index.mjs +3 -0
  38. package/dist/routing-A2hrK9MP.mjs +2396 -0
  39. package/dist/routing-ujEP7Qh6.cjs +2606 -0
  40. package/dist/types-CT2akdK0.d.mts +133 -0
  41. package/dist/types-uxPlGRof.d.cts +133 -0
  42. package/dist/{worker-client-DAT_z2OR.d.mts → worker-client-BwGGRD5y.d.mts} +1 -1
  43. package/dist/{worker-client-DVhklF6A.d.cts → worker-client-D4zNyPEI.d.cts} +1 -1
  44. package/package.json +7 -2
  45. package/src/authoring/coordinates.ts +10 -2
  46. package/src/elkjs/index.ts +5 -3
  47. package/src/elkjs/routes.ts +147 -0
  48. package/src/index.ts +6 -0
  49. package/src/layered/compound.ts +417 -0
  50. package/src/layered/index.ts +27 -102
  51. package/src/layered/types.ts +21 -0
  52. package/src/routing/adapters.ts +111 -0
  53. package/src/routing/algorithms.ts +676 -0
  54. package/src/routing/coordination.ts +86 -0
  55. package/src/routing/engine.ts +473 -0
  56. package/src/routing/index.ts +68 -0
  57. package/src/routing/layout-cache.ts +65 -0
  58. package/src/routing/model.ts +218 -0
  59. package/src/routing/path.ts +324 -0
  60. package/src/routing/persistent.ts +117 -0
  61. package/src/routing/search.ts +276 -0
  62. package/src/routing/spatial.ts +78 -0
  63. package/src/routing/types.ts +146 -0
  64. /package/dist/{public-types-B8rAALJq.d.mts → public-types-9NCPoqbp.d.mts} +0 -0
  65. /package/dist/{public-types-CVB0hXGk.d.cts → public-types-BcRZoJE3.d.cts} +0 -0
  66. /package/dist/{worker-client-DkwS4sHx.mjs → worker-client-BNjwT1AJ.mjs} +0 -0
  67. /package/dist/{worker-client-D3HMK33r.cjs → worker-client-D4oEvhAl.cjs} +0 -0
package/README.md CHANGED
@@ -4,8 +4,9 @@ Native TypeScript graph layout algorithms built directly on
4
4
  [`@statelyai/graph`](https://github.com/statelyai/graph).
5
5
 
6
6
  This is not a new graph interchange format. Public APIs consume `Graph` and
7
- return `VisualGraph`; positions remain node fields and routes remain
8
- `GraphEdge.points`.
7
+ return `VisualGraph`; positions remain node fields. Standalone routing adds
8
+ immutable structured routes and incremental patches alongside the existing
9
+ `GraphEdge.points` layout output.
9
10
 
10
11
  ## Status
11
12
 
@@ -55,6 +56,74 @@ result.diagnostics;
55
56
  result.metrics;
56
57
  ```
57
58
 
59
+ ## Native compound geometry
60
+
61
+ <!-- compound geometry options and output from src/layered/types.ts and src/layered/compound.ts -->
62
+
63
+ ```ts
64
+ const result = getLayeredLayout(graph, {
65
+ direction: "down",
66
+ padding: { top: 24, right: 40, bottom: 24, left: 40 },
67
+ compound: (node) => ({
68
+ header: { width: 200, height: 60, side: "top" },
69
+ direction: "right",
70
+ }),
71
+ edgeAttachment: (edge) => ({
72
+ source: "content", // Use "outer" for an outward/reentering transition.
73
+ }),
74
+ });
75
+ result.compoundGeometry.get("parent"); // { bounds, header, content }
76
+ result.compoundRoutes; // World-space sections, label gaps, routing diagnostics.
77
+ ```
78
+
79
+ Each scope reserves children and measured labels before its ancestors are laid
80
+ out. Header measurements cannot replace finalized compound dimensions. Node
81
+ positions and compound bounds are parent-relative; edge label positions and
82
+ routes are world-relative, marked by `edgeCoordinateSpace: "world"`. Header and content rectangles are local to the
83
+ compound. For ancestor-to-descendant edges, content attachments leave inward;
84
+ outer attachments leave outward. Explicit ports retain their node-local geometry.
85
+ The native compound router emits orthogonal route sections for the original endpoints.
86
+ Use `compoundRoutes` or `getLayoutRoutes(result)` to retain label gaps and
87
+ fallback diagnostics; legacy `edge.points` flattens the sections. `getLayout`
88
+ also reports routing diagnostics in its result. Compound routing currently uses
89
+ orthogonal sections independently of the flat layout routing setting.
90
+
91
+ These options belong to the native contract; they do not change the pinned
92
+ ELK compatibility contract. The existing simplified advanced options still
93
+ map to ELK option IDs, but identical geometry is not guaranteed between contracts.
94
+
95
+ ## Standalone incremental routing
96
+
97
+ <!-- routing API and strategy catalog from src/routing/index.ts -->
98
+
99
+ ```ts
100
+ import { getDiff } from "@statelyai/graph";
101
+ import { orthogonalRouting, toSvgPath } from "@statelyai/layout/routing";
102
+
103
+ const previous = orthogonalRouting.route(graph);
104
+ const { snapshot, patches } = orthogonalRouting.update(
105
+ nextGraph,
106
+ previous,
107
+ getDiff(graph, nextGraph),
108
+ );
109
+ const route = snapshot.routes.get("ab");
110
+ const paths = route?.sections.map((section) => toSvgPath(section.path));
111
+ ```
112
+
113
+ Incremental results match fresh routing for the same graph and settings. Previous
114
+ paths are cached outputs, never constraints on new routes.
115
+
116
+ Every strategy supports incremental updates with immutable snapshots and shared
117
+ indexes. Nodes, ports, and labels stay fixed. Every edge receives a route;
118
+ fallbacks expose status and diagnostics. Deterministic soft crossing/overlap costs
119
+ coordinate unrelated groups; residual conflicts stay visible and reported. Native TypeScript strategies cover
120
+ straight, Bézier, orthogonal, polyline, octilinear, curved, organic, parallel,
121
+ self-loop, fan, bus, and bundled routes. Render curves directly or flatten them
122
+ for a lines-only renderer. ELK/native layout adapters preserve existing output.
123
+
124
+ For efficient dragging, supply the edit's diff directly: `getDiff` scans the
125
+ whole graph. See [routing contracts, algorithms, and examples](docs/routing.md).
126
+
58
127
  ## Layout while authoring
59
128
 
60
129
  <!-- partial scopes and geometry constraints from src/types.ts and src/constraints.ts -->
@@ -1,8 +1,9 @@
1
1
  Object.defineProperty(exports, '__esModule', { value: true });
2
- require('../layered-Cf9Rn8l7.cjs');
3
- const require_elkjs = require('../elkjs-BVnDwnBQ.cjs');
2
+ require('../layered-B2buJqMf.cjs');
3
+ const require_elkjs = require('../elkjs-dMghiiWW.cjs');
4
4
 
5
5
  exports.compileStatechartLayout = require_elkjs.compileStatechartLayout;
6
6
  exports.default = require_elkjs.ELK;
7
+ exports.getElkRoutes = require_elkjs.getElkRoutes;
7
8
  exports.layoutStatechart = require_elkjs.layoutStatechart;
8
9
  exports.scoreStatechartLayout = require_elkjs.scoreStatechartLayout;
@@ -1,4 +1,5 @@
1
- import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-CVB0hXGk.cjs";
1
+ import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-BcRZoJE3.cjs";
2
+ import { r as Route } from "../types-uxPlGRof.cjs";
2
3
 
3
4
  //#region src/elkjs/types.d.ts
4
5
  type ElkId = string | number;
@@ -131,6 +132,14 @@ declare function layoutStatechart<T extends ElkNode$1>(input: T, options: Statec
131
132
  attempt: number;
132
133
  }>;
133
134
  //#endregion
135
+ //#region src/elkjs/routes.d.ts
136
+ interface ElkRouteOptions {
137
+ /** ELK stores spline controls in bendPoints; the caller must identify that encoding. */
138
+ routing?: "ORTHOGONAL" | "POLYLINE" | "SPLINES";
139
+ }
140
+ /** Normalize any ELK layout's section geometry, preserving ports and hyperedge junctions. */
141
+ declare function getElkRoutes(graph: ElkNode, options?: ElkRouteOptions): ReadonlyMap<string, Route>;
142
+ //#endregion
134
143
  //#region src/elkjs/index.d.ts
135
144
  declare class ELK$1 {
136
145
  #private;
@@ -143,4 +152,4 @@ declare class ELK$1 {
143
152
  layout<T extends ElkNode$1>(graph: T, arguments_?: ElkLayoutArguments$1): Promise<LaidOutElkNode$1<T>>;
144
153
  }
145
154
  //#endregion
146
- export { type ELK, type ELKConstructorArguments, type ElkCommonDescription, type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkId, type ElkLabel, type ElkLayoutAlgorithmDescription, type ElkLayoutArguments, type ElkLayoutCategoryDescription, type ElkLayoutOptionDescription, type ElkLogging, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkShape, type LaidOutElkNode, type LayoutOptions, type StatechartLayoutOptions, type StatechartLayoutPlan, type StatechartLayoutScore, type StatechartScope, compileStatechartLayout, ELK$1 as default, layoutStatechart, scoreStatechartLayout };
155
+ export { type ELK, type ELKConstructorArguments, type ElkCommonDescription, type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkId, type ElkLabel, type ElkLayoutAlgorithmDescription, type ElkLayoutArguments, type ElkLayoutCategoryDescription, type ElkLayoutOptionDescription, type ElkLogging, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkRouteOptions, type ElkShape, type LaidOutElkNode, type LayoutOptions, type StatechartLayoutOptions, type StatechartLayoutPlan, type StatechartLayoutScore, type StatechartScope, compileStatechartLayout, ELK$1 as default, getElkRoutes, layoutStatechart, scoreStatechartLayout };
@@ -1,4 +1,5 @@
1
- import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-B8rAALJq.mjs";
1
+ import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-9NCPoqbp.mjs";
2
+ import { r as Route } from "../types-CT2akdK0.mjs";
2
3
 
3
4
  //#region src/elkjs/types.d.ts
4
5
  type ElkId = string | number;
@@ -131,6 +132,14 @@ declare function layoutStatechart<T extends ElkNode$1>(input: T, options: Statec
131
132
  attempt: number;
132
133
  }>;
133
134
  //#endregion
135
+ //#region src/elkjs/routes.d.ts
136
+ interface ElkRouteOptions {
137
+ /** ELK stores spline controls in bendPoints; the caller must identify that encoding. */
138
+ routing?: "ORTHOGONAL" | "POLYLINE" | "SPLINES";
139
+ }
140
+ /** Normalize any ELK layout's section geometry, preserving ports and hyperedge junctions. */
141
+ declare function getElkRoutes(graph: ElkNode, options?: ElkRouteOptions): ReadonlyMap<string, Route>;
142
+ //#endregion
134
143
  //#region src/elkjs/index.d.ts
135
144
  declare class ELK$1 {
136
145
  #private;
@@ -143,4 +152,4 @@ declare class ELK$1 {
143
152
  layout<T extends ElkNode$1>(graph: T, arguments_?: ElkLayoutArguments$1): Promise<LaidOutElkNode$1<T>>;
144
153
  }
145
154
  //#endregion
146
- export { type ELK, type ELKConstructorArguments, type ElkCommonDescription, type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkId, type ElkLabel, type ElkLayoutAlgorithmDescription, type ElkLayoutArguments, type ElkLayoutCategoryDescription, type ElkLayoutOptionDescription, type ElkLogging, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkShape, type LaidOutElkNode, type LayoutOptions, type StatechartLayoutOptions, type StatechartLayoutPlan, type StatechartLayoutScore, type StatechartScope, compileStatechartLayout, ELK$1 as default, layoutStatechart, scoreStatechartLayout };
155
+ export { type ELK, type ELKConstructorArguments, type ElkCommonDescription, type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkId, type ElkLabel, type ElkLayoutAlgorithmDescription, type ElkLayoutArguments, type ElkLayoutCategoryDescription, type ElkLayoutOptionDescription, type ElkLogging, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkRouteOptions, type ElkShape, type LaidOutElkNode, type LayoutOptions, type StatechartLayoutOptions, type StatechartLayoutPlan, type StatechartLayoutScore, type StatechartScope, compileStatechartLayout, ELK$1 as default, getElkRoutes, layoutStatechart, scoreStatechartLayout };
@@ -1,4 +1,4 @@
1
- import "../layered-Bz2nWmVp.mjs";
2
- import { i as scoreStatechartLayout, n as compileStatechartLayout, r as layoutStatechart, t as ELK } from "../elkjs-CFlfkEBz.mjs";
1
+ import "../layered-DGFTeQSl.mjs";
2
+ import { a as scoreStatechartLayout, i as layoutStatechart, n as getElkRoutes, r as compileStatechartLayout, t as ELK } from "../elkjs-DaHMISnQ.mjs";
3
3
 
4
- export { compileStatechartLayout, ELK as default, layoutStatechart, scoreStatechartLayout };
4
+ export { compileStatechartLayout, ELK as default, getElkRoutes, layoutStatechart, scoreStatechartLayout };
@@ -1,6 +1,6 @@
1
- require('../layered-Cf9Rn8l7.cjs');
1
+ require('../layered-B2buJqMf.cjs');
2
2
  const require_elkjs_worker = require('./worker.cjs');
3
- const require_worker_client = require('../worker-client-D3HMK33r.cjs');
3
+ const require_worker_client = require('../worker-client-D4oEvhAl.cjs');
4
4
 
5
5
  //#region src/elkjs/main.ts
6
6
  /** Node-compatible elkjs entry point with an in-process worker fallback. */
@@ -1,5 +1,5 @@
1
- import { n as ELKConstructorArguments } from "../public-types-CVB0hXGk.cjs";
2
- import { t as WorkerELK } from "../worker-client-DVhklF6A.cjs";
1
+ import { n as ELKConstructorArguments } from "../public-types-BcRZoJE3.cjs";
2
+ import { t as WorkerELK } from "../worker-client-D4zNyPEI.cjs";
3
3
 
4
4
  //#region src/elkjs/main.d.ts
5
5
 
@@ -1,5 +1,5 @@
1
- import { n as ELKConstructorArguments } from "../public-types-B8rAALJq.mjs";
2
- import { t as WorkerELK } from "../worker-client-DAT_z2OR.mjs";
1
+ import { n as ELKConstructorArguments } from "../public-types-9NCPoqbp.mjs";
2
+ import { t as WorkerELK } from "../worker-client-BwGGRD5y.mjs";
3
3
 
4
4
  //#region src/elkjs/main.d.ts
5
5
 
@@ -1,6 +1,6 @@
1
- import "../layered-Bz2nWmVp.mjs";
1
+ import "../layered-DGFTeQSl.mjs";
2
2
  import { Worker } from "./worker.mjs";
3
- import { t as WorkerELK } from "../worker-client-DkwS4sHx.mjs";
3
+ import { t as WorkerELK } from "../worker-client-BNjwT1AJ.mjs";
4
4
 
5
5
  //#region src/elkjs/main.ts
6
6
  /** Node-compatible elkjs entry point with an in-process worker fallback. */
@@ -1,3 +1,3 @@
1
- const require_worker_client = require('../worker-client-D3HMK33r.cjs');
1
+ const require_worker_client = require('../worker-client-D4oEvhAl.cjs');
2
2
 
3
3
  module.exports = require_worker_client.WorkerELK;
@@ -1,3 +1,3 @@
1
- import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-CVB0hXGk.cjs";
2
- import { t as WorkerELK } from "../worker-client-DVhklF6A.cjs";
1
+ import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-BcRZoJE3.cjs";
2
+ import { t as WorkerELK } from "../worker-client-D4zNyPEI.cjs";
3
3
  export { type ELK, type ELKConstructorArguments, type ElkCommonDescription, type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkLabel, type ElkLayoutAlgorithmDescription, type ElkLayoutArguments, type ElkLayoutCategoryDescription, type ElkLayoutOptionDescription, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkShape, type LaidOutElkNode, type LayoutOptions, WorkerELK as default };
@@ -1,3 +1,3 @@
1
- import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-B8rAALJq.mjs";
2
- import { t as WorkerELK } from "../worker-client-DAT_z2OR.mjs";
1
+ import { _ as ElkShape, a as ElkEdgeSection, c as ElkLabel, d as ElkLayoutCategoryDescription, f as ElkLayoutOptionDescription, g as ElkPrimitiveEdge, h as ElkPort, i as ElkEdge, l as ElkLayoutAlgorithmDescription, m as ElkPoint, n as ELKConstructorArguments, o as ElkExtendedEdge, p as ElkNode, r as ElkCommonDescription, s as ElkGraphElement, t as ELK, u as ElkLayoutArguments, v as LaidOutElkNode, y as LayoutOptions } from "../public-types-9NCPoqbp.mjs";
2
+ import { t as WorkerELK } from "../worker-client-BwGGRD5y.mjs";
3
3
  export { type ELK, type ELKConstructorArguments, type ElkCommonDescription, type ElkEdge, type ElkEdgeSection, type ElkExtendedEdge, type ElkGraphElement, type ElkLabel, type ElkLayoutAlgorithmDescription, type ElkLayoutArguments, type ElkLayoutCategoryDescription, type ElkLayoutOptionDescription, type ElkNode, type ElkPoint, type ElkPort, type ElkPrimitiveEdge, type ElkShape, type LaidOutElkNode, type LayoutOptions, WorkerELK as default };
@@ -1,3 +1,3 @@
1
- import { t as WorkerELK } from "../worker-client-DkwS4sHx.mjs";
1
+ import { t as WorkerELK } from "../worker-client-BNjwT1AJ.mjs";
2
2
 
3
3
  export { WorkerELK as default };
@@ -1,5 +1,5 @@
1
- require('../layered-Cf9Rn8l7.cjs');
2
- const require_elkjs = require('../elkjs-BVnDwnBQ.cjs');
1
+ require('../layered-B2buJqMf.cjs');
2
+ const require_elkjs = require('../elkjs-dMghiiWW.cjs');
3
3
 
4
4
  //#region src/elkjs/worker.ts
5
5
  /*******************************************************************************
@@ -1,5 +1,5 @@
1
- import "../layered-Bz2nWmVp.mjs";
2
- import { t as ELK } from "../elkjs-CFlfkEBz.mjs";
1
+ import "../layered-DGFTeQSl.mjs";
2
+ import { t as ELK } from "../elkjs-DaHMISnQ.mjs";
3
3
 
4
4
  //#region src/elkjs/worker.ts
5
5
  /*******************************************************************************
@@ -1,5 +1,6 @@
1
- import { o as elkLayeredOptionDefinitions } from "./layered-Bz2nWmVp.mjs";
2
- import { h as elkjs0111ResultPolicy, n as executeElkjs0111Layout } from "./layout-engine-WbC0YjjT.mjs";
1
+ import { O as pathFromPoints, S as freeze, h as pathFromSplinePoints } from "./routing-A2hrK9MP.mjs";
2
+ import { o as elkLayeredOptionDefinitions } from "./layered-DGFTeQSl.mjs";
3
+ import { h as elkjs0111ResultPolicy, n as executeElkjs0111Layout } from "./layout-engine-Cs5tatA6.mjs";
3
4
  import { createGraph } from "@statelyai/graph";
4
5
 
5
6
  //#region src/elkjs/statechart.ts
@@ -260,6 +261,154 @@ async function layoutStatechart(input, options) {
260
261
  };
261
262
  }
262
263
 
264
+ //#endregion
265
+ //#region src/elkjs/routes.ts
266
+ /** Normalize any ELK layout's section geometry, preserving ports and hyperedge junctions. */
267
+ function getElkRoutes(graph, options = {}) {
268
+ const shapes = /* @__PURE__ */ new Map(), frames = /* @__PURE__ */ new Map();
269
+ const edges = [];
270
+ function visit(node, offset, inherited) {
271
+ const position = {
272
+ x: offset.x + (node.x ?? 0),
273
+ y: offset.y + (node.y ?? 0)
274
+ };
275
+ const routing = node.layoutOptions?.["elk.edgeRouting"] ?? node.layoutOptions?.["org.eclipse.elk.edgeRouting"] ?? inherited;
276
+ frames.set(node.id, position);
277
+ shapes.set(node.id, {
278
+ ref: {
279
+ kind: "node",
280
+ nodeId: node.id
281
+ },
282
+ center: {
283
+ x: position.x + (node.width ?? 0) / 2,
284
+ y: position.y + (node.height ?? 0) / 2
285
+ }
286
+ });
287
+ for (const port of node.ports ?? []) shapes.set(port.id, {
288
+ ref: {
289
+ kind: "node",
290
+ nodeId: node.id,
291
+ port: port.id
292
+ },
293
+ center: {
294
+ x: position.x + (port.x ?? 0) + (port.width ?? 0) / 2,
295
+ y: position.y + (port.y ?? 0) + (port.height ?? 0) / 2
296
+ }
297
+ });
298
+ for (const edge of node.edges ?? []) edges.push({
299
+ edge,
300
+ offset: position,
301
+ routing: edge.layoutOptions?.["elk.edgeRouting"] ?? edge.layoutOptions?.["org.eclipse.elk.edgeRouting"] ?? routing
302
+ });
303
+ for (const child of node.children ?? []) visit(child, position, routing);
304
+ }
305
+ visit(graph, {
306
+ x: 0,
307
+ y: 0
308
+ }, options.routing ?? "POLYLINE");
309
+ const result = /* @__PURE__ */ new Map();
310
+ for (const { edge, offset: inheritedOffset, routing } of edges) {
311
+ const offset = edge.container ? frames.get(edge.container) ?? inheritedOffset : inheritedOffset;
312
+ const point = (p) => ({
313
+ x: p.x + offset.x,
314
+ y: p.y + offset.y
315
+ });
316
+ const parents = /* @__PURE__ */ new Map();
317
+ const root = (key) => {
318
+ let current = key;
319
+ while (parents.has(current)) current = parents.get(current);
320
+ return current;
321
+ };
322
+ const join = (a, b) => {
323
+ const x = root(a), y = root(b);
324
+ if (x !== y) parents.set(x < y ? y : x, x < y ? x : y);
325
+ };
326
+ for (const section of edge.sections ?? []) {
327
+ for (const id of section.outgoingSections ?? []) join(`${section.id}:end`, `${id}:start`);
328
+ for (const id of section.incomingSections ?? []) join(`${id}:end`, `${section.id}:start`);
329
+ }
330
+ const sections = [];
331
+ let malformed = false;
332
+ for (const section of edge.sections ?? []) {
333
+ const points = [
334
+ section.startPoint,
335
+ ...section.bendPoints ?? [],
336
+ section.endPoint
337
+ ].map(point);
338
+ let path;
339
+ if (points.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y))) {
340
+ malformed = true;
341
+ for (let i = 0; i < points.length; i++) if (!Number.isFinite(points[i].x) || !Number.isFinite(points[i].y)) points[i] = {
342
+ x: offset.x + i * 20,
343
+ y: offset.y
344
+ };
345
+ }
346
+ if (routing === "SPLINES") if ((points.length - 1) % 3 || points.length < 4) {
347
+ malformed = true;
348
+ path = pathFromPoints([points[0], points.at(-1)]);
349
+ } else path = pathFromSplinePoints(points);
350
+ else path = pathFromPoints(points);
351
+ const fromShape = section.incomingShape ?? (!section.incomingSections?.length && edge.sources.length === 1 ? edge.sources[0] : void 0);
352
+ const toShape = section.outgoingShape ?? (!section.outgoingSections?.length && edge.targets.length === 1 ? edge.targets[0] : void 0);
353
+ sections.push({
354
+ id: section.id,
355
+ from: fromShape ? shapes.get(fromShape)?.ref ?? {
356
+ kind: "node",
357
+ nodeId: fromShape
358
+ } : {
359
+ kind: "junction",
360
+ id: `${edge.id}:${root(`${section.id}:start`)}`
361
+ },
362
+ to: toShape ? shapes.get(toShape)?.ref ?? {
363
+ kind: "node",
364
+ nodeId: toShape
365
+ } : {
366
+ kind: "junction",
367
+ id: `${edge.id}:${root(`${section.id}:end`)}`
368
+ },
369
+ path
370
+ });
371
+ }
372
+ if (!sections.length) {
373
+ malformed = true;
374
+ const source = shapes.get(edge.sources[0] ?? ""), origin = source?.center ?? {
375
+ x: 0,
376
+ y: 0
377
+ };
378
+ const targets = [...edge.targets, ...edge.sources.slice(1)];
379
+ for (const [i, id] of (targets.length ? targets : [""]).entries()) {
380
+ const target = shapes.get(id);
381
+ sections.push({
382
+ id: `${edge.id}:fallback:${i}`,
383
+ from: source?.ref ?? {
384
+ kind: "node",
385
+ nodeId: edge.sources[0] ?? ""
386
+ },
387
+ to: target?.ref ?? {
388
+ kind: "node",
389
+ nodeId: id
390
+ },
391
+ path: pathFromPoints([origin, target?.center ?? {
392
+ x: origin.x + 40,
393
+ y: origin.y + 40
394
+ }])
395
+ });
396
+ }
397
+ }
398
+ result.set(edge.id, freeze({
399
+ edgeId: edge.id,
400
+ sections,
401
+ status: malformed ? "fallback" : "routed",
402
+ diagnostics: malformed ? [{
403
+ code: "MISSING_GEOMETRY",
404
+ edgeId: edge.id,
405
+ message: "ELK sections contain missing or invalid geometry; rendered fallback paths"
406
+ }] : []
407
+ }));
408
+ }
409
+ return result;
410
+ }
411
+
263
412
  //#endregion
264
413
  //#region src/elkjs/index.ts
265
414
  function isLayoutEdgeLabel(label) {
@@ -1525,4 +1674,4 @@ function placePortLabels(node, globalOptions) {
1525
1674
  }
1526
1675
 
1527
1676
  //#endregion
1528
- export { scoreStatechartLayout as i, compileStatechartLayout as n, layoutStatechart as r, ELK as t };
1677
+ export { scoreStatechartLayout as a, layoutStatechart as i, getElkRoutes as n, compileStatechartLayout as r, ELK as t };
@@ -1,5 +1,6 @@
1
- const require_layered = require('./layered-Cf9Rn8l7.cjs');
2
- const require_layout_engine = require('./layout-engine-BNex9jxg.cjs');
1
+ const require_routing = require('./routing-ujEP7Qh6.cjs');
2
+ const require_layered = require('./layered-B2buJqMf.cjs');
3
+ const require_layout_engine = require('./layout-engine-Dn1PiFwP.cjs');
3
4
  let _statelyai_graph = require("@statelyai/graph");
4
5
 
5
6
  //#region src/elkjs/statechart.ts
@@ -260,6 +261,154 @@ async function layoutStatechart(input, options) {
260
261
  };
261
262
  }
262
263
 
264
+ //#endregion
265
+ //#region src/elkjs/routes.ts
266
+ /** Normalize any ELK layout's section geometry, preserving ports and hyperedge junctions. */
267
+ function getElkRoutes(graph, options = {}) {
268
+ const shapes = /* @__PURE__ */ new Map(), frames = /* @__PURE__ */ new Map();
269
+ const edges = [];
270
+ function visit(node, offset, inherited) {
271
+ const position = {
272
+ x: offset.x + (node.x ?? 0),
273
+ y: offset.y + (node.y ?? 0)
274
+ };
275
+ const routing = node.layoutOptions?.["elk.edgeRouting"] ?? node.layoutOptions?.["org.eclipse.elk.edgeRouting"] ?? inherited;
276
+ frames.set(node.id, position);
277
+ shapes.set(node.id, {
278
+ ref: {
279
+ kind: "node",
280
+ nodeId: node.id
281
+ },
282
+ center: {
283
+ x: position.x + (node.width ?? 0) / 2,
284
+ y: position.y + (node.height ?? 0) / 2
285
+ }
286
+ });
287
+ for (const port of node.ports ?? []) shapes.set(port.id, {
288
+ ref: {
289
+ kind: "node",
290
+ nodeId: node.id,
291
+ port: port.id
292
+ },
293
+ center: {
294
+ x: position.x + (port.x ?? 0) + (port.width ?? 0) / 2,
295
+ y: position.y + (port.y ?? 0) + (port.height ?? 0) / 2
296
+ }
297
+ });
298
+ for (const edge of node.edges ?? []) edges.push({
299
+ edge,
300
+ offset: position,
301
+ routing: edge.layoutOptions?.["elk.edgeRouting"] ?? edge.layoutOptions?.["org.eclipse.elk.edgeRouting"] ?? routing
302
+ });
303
+ for (const child of node.children ?? []) visit(child, position, routing);
304
+ }
305
+ visit(graph, {
306
+ x: 0,
307
+ y: 0
308
+ }, options.routing ?? "POLYLINE");
309
+ const result = /* @__PURE__ */ new Map();
310
+ for (const { edge, offset: inheritedOffset, routing } of edges) {
311
+ const offset = edge.container ? frames.get(edge.container) ?? inheritedOffset : inheritedOffset;
312
+ const point = (p) => ({
313
+ x: p.x + offset.x,
314
+ y: p.y + offset.y
315
+ });
316
+ const parents = /* @__PURE__ */ new Map();
317
+ const root = (key) => {
318
+ let current = key;
319
+ while (parents.has(current)) current = parents.get(current);
320
+ return current;
321
+ };
322
+ const join = (a, b) => {
323
+ const x = root(a), y = root(b);
324
+ if (x !== y) parents.set(x < y ? y : x, x < y ? x : y);
325
+ };
326
+ for (const section of edge.sections ?? []) {
327
+ for (const id of section.outgoingSections ?? []) join(`${section.id}:end`, `${id}:start`);
328
+ for (const id of section.incomingSections ?? []) join(`${id}:end`, `${section.id}:start`);
329
+ }
330
+ const sections = [];
331
+ let malformed = false;
332
+ for (const section of edge.sections ?? []) {
333
+ const points = [
334
+ section.startPoint,
335
+ ...section.bendPoints ?? [],
336
+ section.endPoint
337
+ ].map(point);
338
+ let path;
339
+ if (points.some((p) => !Number.isFinite(p.x) || !Number.isFinite(p.y))) {
340
+ malformed = true;
341
+ for (let i = 0; i < points.length; i++) if (!Number.isFinite(points[i].x) || !Number.isFinite(points[i].y)) points[i] = {
342
+ x: offset.x + i * 20,
343
+ y: offset.y
344
+ };
345
+ }
346
+ if (routing === "SPLINES") if ((points.length - 1) % 3 || points.length < 4) {
347
+ malformed = true;
348
+ path = require_routing.pathFromPoints([points[0], points.at(-1)]);
349
+ } else path = require_routing.pathFromSplinePoints(points);
350
+ else path = require_routing.pathFromPoints(points);
351
+ const fromShape = section.incomingShape ?? (!section.incomingSections?.length && edge.sources.length === 1 ? edge.sources[0] : void 0);
352
+ const toShape = section.outgoingShape ?? (!section.outgoingSections?.length && edge.targets.length === 1 ? edge.targets[0] : void 0);
353
+ sections.push({
354
+ id: section.id,
355
+ from: fromShape ? shapes.get(fromShape)?.ref ?? {
356
+ kind: "node",
357
+ nodeId: fromShape
358
+ } : {
359
+ kind: "junction",
360
+ id: `${edge.id}:${root(`${section.id}:start`)}`
361
+ },
362
+ to: toShape ? shapes.get(toShape)?.ref ?? {
363
+ kind: "node",
364
+ nodeId: toShape
365
+ } : {
366
+ kind: "junction",
367
+ id: `${edge.id}:${root(`${section.id}:end`)}`
368
+ },
369
+ path
370
+ });
371
+ }
372
+ if (!sections.length) {
373
+ malformed = true;
374
+ const source = shapes.get(edge.sources[0] ?? ""), origin = source?.center ?? {
375
+ x: 0,
376
+ y: 0
377
+ };
378
+ const targets = [...edge.targets, ...edge.sources.slice(1)];
379
+ for (const [i, id] of (targets.length ? targets : [""]).entries()) {
380
+ const target = shapes.get(id);
381
+ sections.push({
382
+ id: `${edge.id}:fallback:${i}`,
383
+ from: source?.ref ?? {
384
+ kind: "node",
385
+ nodeId: edge.sources[0] ?? ""
386
+ },
387
+ to: target?.ref ?? {
388
+ kind: "node",
389
+ nodeId: id
390
+ },
391
+ path: require_routing.pathFromPoints([origin, target?.center ?? {
392
+ x: origin.x + 40,
393
+ y: origin.y + 40
394
+ }])
395
+ });
396
+ }
397
+ }
398
+ result.set(edge.id, require_routing.freeze({
399
+ edgeId: edge.id,
400
+ sections,
401
+ status: malformed ? "fallback" : "routed",
402
+ diagnostics: malformed ? [{
403
+ code: "MISSING_GEOMETRY",
404
+ edgeId: edge.id,
405
+ message: "ELK sections contain missing or invalid geometry; rendered fallback paths"
406
+ }] : []
407
+ }));
408
+ }
409
+ return result;
410
+ }
411
+
263
412
  //#endregion
264
413
  //#region src/elkjs/index.ts
265
414
  function isLayoutEdgeLabel(label) {
@@ -1537,6 +1686,12 @@ Object.defineProperty(exports, 'compileStatechartLayout', {
1537
1686
  return compileStatechartLayout;
1538
1687
  }
1539
1688
  });
1689
+ Object.defineProperty(exports, 'getElkRoutes', {
1690
+ enumerable: true,
1691
+ get: function () {
1692
+ return getElkRoutes;
1693
+ }
1694
+ });
1540
1695
  Object.defineProperty(exports, 'layoutStatechart', {
1541
1696
  enumerable: true,
1542
1697
  get: function () {