@oh-just-another/scene 0.57.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 (129) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/LICENSE +21 -0
  3. package/README.md +72 -0
  4. package/dist/.tsbuildinfo +1 -0
  5. package/dist/a11y.d.ts +23 -0
  6. package/dist/a11y.d.ts.map +1 -0
  7. package/dist/a11y.js +37 -0
  8. package/dist/a11y.js.map +1 -0
  9. package/dist/anchors.d.ts +120 -0
  10. package/dist/anchors.d.ts.map +1 -0
  11. package/dist/anchors.js +322 -0
  12. package/dist/anchors.js.map +1 -0
  13. package/dist/annotation-geometry.d.ts +11 -0
  14. package/dist/annotation-geometry.d.ts.map +1 -0
  15. package/dist/annotation-geometry.js +19 -0
  16. package/dist/annotation-geometry.js.map +1 -0
  17. package/dist/annotation.d.ts +32 -0
  18. package/dist/annotation.d.ts.map +1 -0
  19. package/dist/annotation.js +2 -0
  20. package/dist/annotation.js.map +1 -0
  21. package/dist/constants.d.ts +186 -0
  22. package/dist/constants.d.ts.map +1 -0
  23. package/dist/constants.js +186 -0
  24. package/dist/constants.js.map +1 -0
  25. package/dist/container.d.ts +112 -0
  26. package/dist/container.d.ts.map +1 -0
  27. package/dist/container.js +227 -0
  28. package/dist/container.js.map +1 -0
  29. package/dist/diff.d.ts +22 -0
  30. package/dist/diff.d.ts.map +1 -0
  31. package/dist/diff.js +18 -0
  32. package/dist/diff.js.map +1 -0
  33. package/dist/edge-curve.d.ts +37 -0
  34. package/dist/edge-curve.d.ts.map +1 -0
  35. package/dist/edge-curve.js +72 -0
  36. package/dist/edge-curve.js.map +1 -0
  37. package/dist/edge-geometry.d.ts +96 -0
  38. package/dist/edge-geometry.d.ts.map +1 -0
  39. package/dist/edge-geometry.js +467 -0
  40. package/dist/edge-geometry.js.map +1 -0
  41. package/dist/edge.d.ts +206 -0
  42. package/dist/edge.d.ts.map +1 -0
  43. package/dist/edge.js +2 -0
  44. package/dist/edge.js.map +1 -0
  45. package/dist/elbow-link.d.ts +23 -0
  46. package/dist/elbow-link.d.ts.map +1 -0
  47. package/dist/elbow-link.js +419 -0
  48. package/dist/elbow-link.js.map +1 -0
  49. package/dist/elbow-router.d.ts +20 -0
  50. package/dist/elbow-router.d.ts.map +1 -0
  51. package/dist/elbow-router.js +218 -0
  52. package/dist/elbow-router.js.map +1 -0
  53. package/dist/file.d.ts +41 -0
  54. package/dist/file.d.ts.map +1 -0
  55. package/dist/file.js +13 -0
  56. package/dist/file.js.map +1 -0
  57. package/dist/heading.d.ts +42 -0
  58. package/dist/heading.d.ts.map +1 -0
  59. package/dist/heading.js +77 -0
  60. package/dist/heading.js.map +1 -0
  61. package/dist/index.d.ts +47 -0
  62. package/dist/index.d.ts.map +1 -0
  63. package/dist/index.js +40 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/layer.d.ts +18 -0
  66. package/dist/layer.d.ts.map +1 -0
  67. package/dist/layer.js +2 -0
  68. package/dist/layer.js.map +1 -0
  69. package/dist/layout-registry.d.ts +35 -0
  70. package/dist/layout-registry.d.ts.map +1 -0
  71. package/dist/layout-registry.js +13 -0
  72. package/dist/layout-registry.js.map +1 -0
  73. package/dist/layout.d.ts +128 -0
  74. package/dist/layout.d.ts.map +1 -0
  75. package/dist/layout.js +453 -0
  76. package/dist/layout.js.map +1 -0
  77. package/dist/operations.d.ts +32 -0
  78. package/dist/operations.d.ts.map +1 -0
  79. package/dist/operations.js +105 -0
  80. package/dist/operations.js.map +1 -0
  81. package/dist/outline.d.ts +36 -0
  82. package/dist/outline.d.ts.map +1 -0
  83. package/dist/outline.js +129 -0
  84. package/dist/outline.js.map +1 -0
  85. package/dist/patch.d.ts +57 -0
  86. package/dist/patch.d.ts.map +1 -0
  87. package/dist/patch.js +47 -0
  88. package/dist/patch.js.map +1 -0
  89. package/dist/queries.d.ts +115 -0
  90. package/dist/queries.d.ts.map +1 -0
  91. package/dist/queries.js +403 -0
  92. package/dist/queries.js.map +1 -0
  93. package/dist/render-bounds.d.ts +36 -0
  94. package/dist/render-bounds.d.ts.map +1 -0
  95. package/dist/render-bounds.js +36 -0
  96. package/dist/render-bounds.js.map +1 -0
  97. package/dist/scene.d.ts +80 -0
  98. package/dist/scene.d.ts.map +1 -0
  99. package/dist/scene.js +129 -0
  100. package/dist/scene.js.map +1 -0
  101. package/dist/shape.d.ts +306 -0
  102. package/dist/shape.d.ts.map +1 -0
  103. package/dist/shape.js +192 -0
  104. package/dist/shape.js.map +1 -0
  105. package/dist/snap.d.ts +88 -0
  106. package/dist/snap.d.ts.map +1 -0
  107. package/dist/snap.js +128 -0
  108. package/dist/snap.js.map +1 -0
  109. package/dist/spatial.d.ts +38 -0
  110. package/dist/spatial.d.ts.map +1 -0
  111. package/dist/spatial.js +95 -0
  112. package/dist/spatial.js.map +1 -0
  113. package/dist/style.d.ts +87 -0
  114. package/dist/style.d.ts.map +1 -0
  115. package/dist/style.js +43 -0
  116. package/dist/style.js.map +1 -0
  117. package/dist/text-measure.d.ts +29 -0
  118. package/dist/text-measure.d.ts.map +1 -0
  119. package/dist/text-measure.js +8 -0
  120. package/dist/text-measure.js.map +1 -0
  121. package/dist/three-way-merge.d.ts +59 -0
  122. package/dist/three-way-merge.d.ts.map +1 -0
  123. package/dist/three-way-merge.js +108 -0
  124. package/dist/three-way-merge.js.map +1 -0
  125. package/dist/viewport.d.ts +78 -0
  126. package/dist/viewport.d.ts.map +1 -0
  127. package/dist/viewport.js +62 -0
  128. package/dist/viewport.js.map +1 -0
  129. package/package.json +54 -0
@@ -0,0 +1,218 @@
1
+ /**
2
+ * A*-based elbow router (Manhattan / 90° segments that detour
3
+ * around obstacle bboxes).
4
+ *
5
+ * Self-contained and pure: takes `from`, `to`, an `obstacles[]` list of world-
6
+ * space bboxes (the source / target shapes typically), and returns
7
+ * the polyline of axis-aligned bends — or `null` when no path
8
+ * exists (degenerate: same point).
9
+ *
10
+ * Algorithm:
11
+ * 1. Build a candidate-point set: from, to, and the four
12
+ * corners of each obstacle bbox inflated by `MARGIN` so
13
+ * the path runs *around* the box, not on its edge. Links
14
+ * whose two endpoints lie on the same axis (same x or same
15
+ * y) and don't cross any obstacle's interior become graph
16
+ * edges with cost = Manhattan distance.
17
+ * 2. A* with Manhattan-distance heuristic from `from` to `to`.
18
+ * 3. Post-process: collapse colinear waypoints so the returned
19
+ * path is the minimal bend list.
20
+ *
21
+ * The router is not a global optimum — A* on this sparse graph
22
+ * gives a "good enough" detour without the O(N²) cost of a full
23
+ * visibility graph.
24
+ */
25
+ import { ELBOW_OBSTACLE_MARGIN, ELBOW_OBSTACLE_INTERIOR_EPSILON, ELBOW_BEND_PENALTY, } from "./constants.js";
26
+ const req = (v) => {
27
+ if (v === undefined)
28
+ throw new Error("packages/scene: index out of range");
29
+ return v;
30
+ };
31
+ const MARGIN = ELBOW_OBSTACLE_MARGIN;
32
+ const INTERIOR_EPS = ELBOW_OBSTACLE_INTERIOR_EPSILON;
33
+ const BEND_PENALTY = ELBOW_BEND_PENALTY;
34
+ export const elbowRoute = (from, to, obstacles, options = {}) => {
35
+ if (eq(from, to))
36
+ return [from];
37
+ const margin = options.margin ?? MARGIN;
38
+ const inflated = obstacles.map((b) => inflate(b, margin));
39
+ const startHeading = options.startHeading;
40
+ const endHeading = options.endHeading;
41
+ // Candidate axes — every unique x and y value from endpoints + bbox
42
+ // corners. The router walks the implicit grid those axes form.
43
+ const xs = new Set([from.x, to.x]);
44
+ const ys = new Set([from.y, to.y]);
45
+ for (const b of inflated) {
46
+ xs.add(b.x);
47
+ xs.add(b.x + b.width);
48
+ ys.add(b.y);
49
+ ys.add(b.y + b.height);
50
+ }
51
+ const xList = [...xs].sort((a, b) => a - b);
52
+ const yList = [...ys].sort((a, b) => a - b);
53
+ // Each node is "(xIndex,yIndex)" packed into one string for Map keys.
54
+ const nodeKey = (xi, yi) => `${xi},${yi}`;
55
+ const xOfIdx = (xi) => req(xList[xi]);
56
+ const yOfIdx = (yi) => req(yList[yi]);
57
+ const startXi = xList.indexOf(from.x);
58
+ const startYi = yList.indexOf(from.y);
59
+ const endXi = xList.indexOf(to.x);
60
+ const endYi = yList.indexOf(to.y);
61
+ // Manhattan heuristic — admissible on a grid with 90° edges.
62
+ const h = (xi, yi) => Math.abs(xOfIdx(xi) - xOfIdx(endXi)) + Math.abs(yOfIdx(yi) - yOfIdx(endYi));
63
+ const startNode = nodeKey(startXi, startYi);
64
+ const open = [
65
+ { key: startNode, skey: `${startNode},0`, xi: startXi, yi: startYi, axis: 0, g: 0, f: h(startXi, startYi) },
66
+ ];
67
+ // cameFrom / gScore keyed by *state* (node + arrival axis) so a node can be
68
+ // reached from both axes with different bend costs.
69
+ const cameFrom = new Map();
70
+ const gScore = new Map([[`${startNode},0`, 0]]);
71
+ while (open.length > 0) {
72
+ // Extract-min with a deterministic tie-break (f, then g, then key).
73
+ open.sort((a, b) => a.f - b.f || a.g - b.g || (a.skey < b.skey ? -1 : 1));
74
+ const cur = req(open.shift());
75
+ if (cur.xi === endXi && cur.yi === endYi) {
76
+ return reconstructPath(cameFrom, cur.skey, xOfIdx, yOfIdx);
77
+ }
78
+ for (const next of neighbours(cur.xi, cur.yi, xList.length, yList.length)) {
79
+ const fromPt = { x: xOfIdx(cur.xi), y: yOfIdx(cur.yi) };
80
+ const toPt = { x: xOfIdx(next.xi), y: yOfIdx(next.yi) };
81
+ if (segmentCrossesObstacle(fromPt, toPt, inflated))
82
+ continue;
83
+ const stepX = Math.sign(toPt.x - fromPt.x);
84
+ const stepY = Math.sign(toPt.y - fromPt.y);
85
+ // Don't let the very first move reverse the start buffer (would retrace
86
+ // the terminal stub) …
87
+ if (cur.axis === 0 &&
88
+ startHeading &&
89
+ stepX === -Math.sign(startHeading.x) &&
90
+ stepY === -Math.sign(startHeading.y)) {
91
+ continue;
92
+ }
93
+ // … and don't arrive at the goal travelling along the end-buffer heading
94
+ // (would make bufB→to double back).
95
+ if (next.xi === endXi &&
96
+ next.yi === endYi &&
97
+ endHeading &&
98
+ stepX === Math.sign(endHeading.x) &&
99
+ stepY === Math.sign(endHeading.y)) {
100
+ continue;
101
+ }
102
+ const stepAxis = next.xi !== cur.xi ? 1 : 2;
103
+ const stepCost = Math.abs(fromPt.x - toPt.x) + Math.abs(fromPt.y - toPt.y);
104
+ const turn = cur.axis !== 0 && cur.axis !== stepAxis ? BEND_PENALTY : 0;
105
+ const tentative = cur.g + stepCost + turn;
106
+ const nodeK = nodeKey(next.xi, next.yi);
107
+ const stateK = `${nodeK},${stepAxis}`;
108
+ const prev = gScore.get(stateK);
109
+ if (prev !== undefined && tentative >= prev)
110
+ continue;
111
+ gScore.set(stateK, tentative);
112
+ cameFrom.set(stateK, cur.skey);
113
+ open.push({
114
+ key: nodeK,
115
+ skey: stateK,
116
+ xi: next.xi,
117
+ yi: next.yi,
118
+ axis: stepAxis,
119
+ g: tentative,
120
+ f: tentative + h(next.xi, next.yi),
121
+ });
122
+ }
123
+ }
124
+ // No path — caller falls back to a direct elbow.
125
+ return null;
126
+ };
127
+ const eq = (a, b) => a.x === b.x && a.y === b.y;
128
+ const inflate = (b, m) => ({
129
+ x: b.x - m,
130
+ y: b.y - m,
131
+ width: b.width + 2 * m,
132
+ height: b.height + 2 * m,
133
+ });
134
+ /**
135
+ * Neighbours: the four orthogonal grid steps. We don't enumerate
136
+ * every possible (xi, yi) target — only ±1 on one axis. That
137
+ * yields a path that walks the axis-aligned grid one cell at a
138
+ * time, and the colinear-collapse pass at the end strips the
139
+ * intermediate waypoints.
140
+ */
141
+ const neighbours = (xi, yi, xLen, yLen) => {
142
+ const out = [];
143
+ if (xi > 0)
144
+ out.push({ xi: xi - 1, yi });
145
+ if (xi < xLen - 1)
146
+ out.push({ xi: xi + 1, yi });
147
+ if (yi > 0)
148
+ out.push({ xi, yi: yi - 1 });
149
+ if (yi < yLen - 1)
150
+ out.push({ xi, yi: yi + 1 });
151
+ return out;
152
+ };
153
+ /**
154
+ * Returns `true` when the axis-aligned segment `from → to` passes
155
+ * through the *interior* of any obstacle. Link-on contact (the
156
+ * segment runs along the bbox boundary) is allowed — that's the
157
+ * whole point of the margin inflate.
158
+ */
159
+ const segmentCrossesObstacle = (from, to, obstacles) => {
160
+ const minX = Math.min(from.x, to.x);
161
+ const maxX = Math.max(from.x, to.x);
162
+ const minY = Math.min(from.y, to.y);
163
+ const maxY = Math.max(from.y, to.y);
164
+ for (const o of obstacles) {
165
+ const oMaxX = o.x + o.width;
166
+ const oMaxY = o.y + o.height;
167
+ // Bounding-box check first.
168
+ if (maxX <= o.x || minX >= oMaxX || maxY <= o.y || minY >= oMaxY)
169
+ continue;
170
+ // Touching along an edge — allowed.
171
+ if (maxX - o.x <= INTERIOR_EPS ||
172
+ oMaxX - minX <= INTERIOR_EPS ||
173
+ maxY - o.y <= INTERIOR_EPS ||
174
+ oMaxY - minY <= INTERIOR_EPS) {
175
+ continue;
176
+ }
177
+ return true;
178
+ }
179
+ return false;
180
+ };
181
+ const reconstructPath = (cameFrom, endKey, xOfIdx, yOfIdx) => {
182
+ const path = [];
183
+ const seen = new Set();
184
+ let cursor = endKey;
185
+ // Guard against a malformed cameFrom (a predecessor cycle) — follow each
186
+ // state at most once. With positive edge weights the chain is always a tree,
187
+ // but this makes a hang structurally impossible regardless.
188
+ while (cursor && !seen.has(cursor)) {
189
+ seen.add(cursor);
190
+ const parts = cursor.split(",").map(Number);
191
+ path.unshift({ x: xOfIdx(req(parts[0])), y: yOfIdx(req(parts[1])) });
192
+ cursor = cameFrom.get(cursor);
193
+ }
194
+ return collapseColinear(path);
195
+ };
196
+ /**
197
+ * Drop intermediate points on an axis-aligned polyline that lie
198
+ * between their neighbours on the same axis. Three colinear points
199
+ * → keep first and third.
200
+ */
201
+ const collapseColinear = (points) => {
202
+ if (points.length <= 2)
203
+ return points;
204
+ const out = [req(points[0])];
205
+ for (let i = 1; i < points.length - 1; i++) {
206
+ const prev = req(points[i - 1]);
207
+ const cur = req(points[i]);
208
+ const next = req(points[i + 1]);
209
+ const horizontal = prev.y === cur.y && cur.y === next.y;
210
+ const vertical = prev.x === cur.x && cur.x === next.x;
211
+ if (horizontal || vertical)
212
+ continue;
213
+ out.push(cur);
214
+ }
215
+ out.push(req(points[points.length - 1]));
216
+ return out;
217
+ };
218
+ //# sourceMappingURL=elbow-router.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"elbow-router.js","sourceRoot":"","sources":["../src/elbow-router.ts"],"names":[],"mappings":"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"}
package/dist/file.d.ts ADDED
@@ -0,0 +1,41 @@
1
+ import type { FileId } from "@oh-just-another/types";
2
+ /**
3
+ * Binary file entry stored in `Scene.files`. An `ImageElement` (or
4
+ * other binary-bearing shape type) carries just a `fileId` and
5
+ * resolves through this registry at render time. The actual bytes
6
+ * live here once, regardless of how many shapes reference them.
7
+ *
8
+ * Storage shape is intentionally minimal:
9
+ *
10
+ * • `mime` — content type ("image/png", "image/jpeg", "image/svg+xml", …)
11
+ * • `data` — the bytes themselves (`ArrayBuffer` so it serialises
12
+ * cleanly through `structuredClone`, IndexedDB, postMessage; SVG
13
+ * files can also use a UTF-8 encoded string round-tripped through
14
+ * `TextEncoder.encode().buffer`).
15
+ * • `name` — original filename when known, useful for downloads /
16
+ * export menus / accessible labels.
17
+ * • `createdAt` — millisecond timestamp; lets hosts age out caches
18
+ * and surface "added today" in file pickers.
19
+ *
20
+ * The serializer pipeline writes `files` to a separate sidecar so a
21
+ * pure-text scene.json stays small; on import the host re-attaches
22
+ * the sidecar and the shapes resolve their `fileId` lookups again.
23
+ */
24
+ export interface BinaryFile {
25
+ readonly id: FileId;
26
+ readonly mime: string;
27
+ readonly data: ArrayBuffer;
28
+ readonly name?: string;
29
+ readonly createdAt: number;
30
+ }
31
+ /**
32
+ * Convenience constructor — assigns the current timestamp + a
33
+ * sensible default `mime` of `application/octet-stream`. Hosts
34
+ * normally pass an explicit `mime` from the source `Blob.type`.
35
+ */
36
+ export declare const createBinaryFile: (id: FileId, data: ArrayBuffer, options?: {
37
+ readonly mime?: string;
38
+ readonly name?: string;
39
+ readonly createdAt?: number;
40
+ }) => BinaryFile;
41
+ //# sourceMappingURL=file.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.d.ts","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,wBAAwB,CAAC;AAErD;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,UAAU;IACzB,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,IAAI,EAAE,WAAW,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAC;CAC5B;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,GAC3B,IAAI,MAAM,EACV,MAAM,WAAW,EACjB,UAAS;IAAE,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAA;CAAO,KAC5F,UAMD,CAAC"}
package/dist/file.js ADDED
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Convenience constructor — assigns the current timestamp + a
3
+ * sensible default `mime` of `application/octet-stream`. Hosts
4
+ * normally pass an explicit `mime` from the source `Blob.type`.
5
+ */
6
+ export const createBinaryFile = (id, data, options = {}) => ({
7
+ id,
8
+ data,
9
+ mime: options.mime ?? "application/octet-stream",
10
+ createdAt: options.createdAt ?? Date.now(),
11
+ ...(options.name !== undefined ? { name: options.name } : {}),
12
+ });
13
+ //# sourceMappingURL=file.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"file.js","sourceRoot":"","sources":["../src/file.ts"],"names":[],"mappings":"AAgCA;;;;GAIG;AACH,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,EAAU,EACV,IAAiB,EACjB,UAA2F,EAAE,EACjF,EAAE,CAAC,CAAC;IAChB,EAAE;IACF,IAAI;IACJ,IAAI,EAAE,OAAO,CAAC,IAAI,IAAI,0BAA0B;IAChD,SAAS,EAAE,OAAO,CAAC,SAAS,IAAI,IAAI,CAAC,GAAG,EAAE;IAC1C,GAAG,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;CAC9D,CAAC,CAAC"}
@@ -0,0 +1,42 @@
1
+ import type { Vec2 } from "@oh-just-another/types";
2
+ import { type ElementBase } from "./shape.js";
3
+ /**
4
+ * Heading — the cardinal direction an elbow connector exits a shape on
5
+ * (standard model). One of four unit vectors. Used by the orthogonal
6
+ * router to push the endpoint out perpendicular to the shape's edge (the
7
+ * "dongle") before routing, so connectors always leave a box straight.
8
+ */
9
+ export type Heading = Readonly<Vec2>;
10
+ export declare const HEADING_RIGHT: Heading;
11
+ export declare const HEADING_DOWN: Heading;
12
+ export declare const HEADING_LEFT: Heading;
13
+ export declare const HEADING_UP: Heading;
14
+ /** True for left/right headings (horizontal exit). */
15
+ export declare const headingIsHorizontal: (h: Heading) => boolean;
16
+ export declare const headingsEqual: (a: Heading, b: Heading) => boolean;
17
+ /** Opposite heading (reverse direction). */
18
+ export declare const flipHeading: (h: Heading) => Heading;
19
+ /**
20
+ * Quantise an arbitrary vector to the nearest cardinal heading. Ties on
21
+ * the dominant axis resolve to vertical (matches standard's
22
+ * `vectorToHeading`: `x > |y|` → right, `x <= -|y|` → left, else by y).
23
+ */
24
+ export declare const vectorToHeading: (v: Vec2) => Heading;
25
+ /** Heading from `origin` toward `p`. */
26
+ export declare const headingForPoint: (p: Vec2, origin: Vec2) => Heading;
27
+ /**
28
+ * Outward normal of the AABB edge nearest to `p` — the correct exit heading
29
+ * for a point that sits ON the shape outline (floating / outline / ratio
30
+ * anchors). More accurate near corners than {@link headingForPointFromElement}
31
+ * (the cone test there can pick an adjacent side). For a point on the right
32
+ * edge → RIGHT, etc.
33
+ */
34
+ export declare const headingForEdgePoint: (shape: ElementBase, p: Vec2) => Heading;
35
+ /**
36
+ * Which side of `shape` the world point `p` exits on. Splits the shape's
37
+ * (world-AABB) into four triangular cones from the centre to each corner;
38
+ * the cone `p` falls in decides the heading. A point dead-centre resolves
39
+ * via the centre→p vector. Diamonds/rotated shapes use the AABB.
40
+ */
41
+ export declare const headingForPointFromElement: (shape: ElementBase, p: Vec2) => Heading;
42
+ //# sourceMappingURL=heading.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../src/heading.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAyB,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AAErE;;;;;GAKG;AACH,MAAM,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;AAErC,eAAO,MAAM,aAAa,EAAE,OAAwB,CAAC;AACrD,eAAO,MAAM,YAAY,EAAE,OAAwB,CAAC;AACpD,eAAO,MAAM,YAAY,EAAE,OAAyB,CAAC;AACrD,eAAO,MAAM,UAAU,EAAE,OAAyB,CAAC;AAEnD,sDAAsD;AACtD,eAAO,MAAM,mBAAmB,GAAI,GAAG,OAAO,KAAG,OAAoB,CAAC;AAEtE,eAAO,MAAM,aAAa,GAAI,GAAG,OAAO,EAAE,GAAG,OAAO,KAAG,OAAqC,CAAC;AAE7F,4CAA4C;AAC5C,eAAO,MAAM,WAAW,GAAI,GAAG,OAAO,KAAG,OAA2C,CAAC;AAErF;;;;GAIG;AACH,eAAO,MAAM,eAAe,GAAI,GAAG,IAAI,KAAG,OAOzC,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,eAAe,GAAI,GAAG,IAAI,EAAE,QAAQ,IAAI,KAAG,OACG,CAAC;AAE5D;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,GAAI,OAAO,WAAW,EAAE,GAAG,IAAI,KAAG,OAWjE,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B,GAAI,OAAO,WAAW,EAAE,GAAG,IAAI,KAAG,OAkBxE,CAAC"}
@@ -0,0 +1,77 @@
1
+ import { getElementWorldBounds } from "./shape.js";
2
+ export const HEADING_RIGHT = { x: 1, y: 0 };
3
+ export const HEADING_DOWN = { x: 0, y: 1 };
4
+ export const HEADING_LEFT = { x: -1, y: 0 };
5
+ export const HEADING_UP = { x: 0, y: -1 };
6
+ /** True for left/right headings (horizontal exit). */
7
+ export const headingIsHorizontal = (h) => h.y === 0;
8
+ export const headingsEqual = (a, b) => a.x === b.x && a.y === b.y;
9
+ /** Opposite heading (reverse direction). */
10
+ export const flipHeading = (h) => ({ x: -h.x || 0, y: -h.y || 0 });
11
+ /**
12
+ * Quantise an arbitrary vector to the nearest cardinal heading. Ties on
13
+ * the dominant axis resolve to vertical (matches standard's
14
+ * `vectorToHeading`: `x > |y|` → right, `x <= -|y|` → left, else by y).
15
+ */
16
+ export const vectorToHeading = (v) => {
17
+ const ax = Math.abs(v.x);
18
+ const ay = Math.abs(v.y);
19
+ if (v.x > ay)
20
+ return HEADING_RIGHT;
21
+ if (v.x <= -ay)
22
+ return HEADING_LEFT;
23
+ if (v.y > ax)
24
+ return HEADING_DOWN;
25
+ return HEADING_UP;
26
+ };
27
+ /** Heading from `origin` toward `p`. */
28
+ export const headingForPoint = (p, origin) => vectorToHeading({ x: p.x - origin.x, y: p.y - origin.y });
29
+ /**
30
+ * Outward normal of the AABB edge nearest to `p` — the correct exit heading
31
+ * for a point that sits ON the shape outline (floating / outline / ratio
32
+ * anchors). More accurate near corners than {@link headingForPointFromElement}
33
+ * (the cone test there can pick an adjacent side). For a point on the right
34
+ * edge → RIGHT, etc.
35
+ */
36
+ export const headingForEdgePoint = (shape, p) => {
37
+ const b = getElementWorldBounds(shape);
38
+ const dl = Math.abs(p.x - b.x); // distance to left edge
39
+ const dr = Math.abs(b.x + b.width - p.x); // right
40
+ const dt = Math.abs(p.y - b.y); // top
41
+ const db = Math.abs(b.y + b.height - p.y); // bottom
42
+ const min = Math.min(dl, dr, dt, db);
43
+ if (min === dl)
44
+ return HEADING_LEFT;
45
+ if (min === dr)
46
+ return HEADING_RIGHT;
47
+ if (min === dt)
48
+ return HEADING_UP;
49
+ return HEADING_DOWN;
50
+ };
51
+ /**
52
+ * Which side of `shape` the world point `p` exits on. Splits the shape's
53
+ * (world-AABB) into four triangular cones from the centre to each corner;
54
+ * the cone `p` falls in decides the heading. A point dead-centre resolves
55
+ * via the centre→p vector. Diamonds/rotated shapes use the AABB.
56
+ */
57
+ export const headingForPointFromElement = (shape, p) => {
58
+ const b = getElementWorldBounds(shape);
59
+ const cx = b.x + b.width / 2;
60
+ const cy = b.y + b.height / 2;
61
+ const dx = p.x - cx;
62
+ const dy = p.y - cy;
63
+ if (dx === 0 && dy === 0)
64
+ return HEADING_RIGHT;
65
+ // Compare the point's offset against the box aspect: the diagonals of the
66
+ // AABB split it into top/right/bottom/left cones. `dy/dx` vs `h/w`.
67
+ const w = b.width || 1;
68
+ const h = b.height || 1;
69
+ // Normalise offsets by half-extent so the cone test is a unit-square test.
70
+ const nx = dx / (w / 2);
71
+ const ny = dy / (h / 2);
72
+ if (Math.abs(nx) >= Math.abs(ny)) {
73
+ return nx >= 0 ? HEADING_RIGHT : HEADING_LEFT;
74
+ }
75
+ return ny >= 0 ? HEADING_DOWN : HEADING_UP;
76
+ };
77
+ //# sourceMappingURL=heading.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"heading.js","sourceRoot":"","sources":["../src/heading.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,47 @@
1
+ export type { Style, TextStyle, LineCap, LineJoin, TextAlign, TextBaseline, FontWeight, FontStyle, TextDecoration, StrokeAlign, Roundness, } from "./style.js";
2
+ export { getCornerRadius, strokeOutsideExtent } from "./style.js";
3
+ export { ADAPTIVE_CORNER_RADIUS, PROPORTIONAL_CORNER_RADIUS } from "./constants.js";
4
+ export type { Element, ElementBase, BuiltinElement, RectangleElement, EllipseElement, PolygonElement, PathElement, PathCommand, TextElement, ImageElement, TemplateElement, GroupElement, FrameElement, BlockArrowElement, BrushElement, BrushPoint, ElementBounder, } from "./shape.js";
5
+ export type { Link, LinkEndpoint, LinkRouting, LinkArrowheads, LinkLabel, ArrowheadStyle, AnchorRef, NamedAnchor, StandardAnchor, } from "./edge.js";
6
+ export { getLinkEndpointWorld, getLinkPath, findLinkAt, getLinkCurvePoints, getLinkCurveSegments, getLinkWaypointMidpoints, getSelfLoopSpec, } from "./edge-geometry.js";
7
+ export { catmullRomBeziers, cubicWithEndTangents, flattenSegments, type BezierSegment, } from "./edge-curve.js";
8
+ export type { Layer } from "./layer.js";
9
+ export type { Viewport, GridStyle } from "./viewport.js";
10
+ export type { Scene } from "./scene.js";
11
+ export type { Patch } from "./patch.js";
12
+ export type { OperationResult } from "./operations.js";
13
+ export { isRectangle, isEllipse, isPolygon, isPath, isText, isImage, isTemplate, isGroup, isFrame, isBlockArrow, isBrush, registerBounder, getBounder, getElementLocalBounds, getElementWorldBounds, } from "./shape.js";
14
+ export { registerRenderOverflow, getElementRenderBounds, type RenderOverflow, } from "./render-bounds.js";
15
+ export { setTextMeasurer, getTextMeasurer, type TextMeasurer, type TextMeasureOpts, } from "./text-measure.js";
16
+ export { STANDARD_ANCHORS, STANDARD_ANCHOR_RATIOS, CARDINAL_ANCHORS, getNamedAnchorLocal, getAnchorLocal, getAnchorWorld, getAnchorOutwardNormal, listAnchorsLocal, geometryDefaultAnchorsLocal, findNearestAnchor, snapExcludedAnchors, } from "./anchors.js";
17
+ export type { SnapCandidate, SnapContext, SnapContributor } from "./snap.js";
18
+ export { SnapEngine, gridSnapper, anchorSnapper, outlineSnapper } from "./snap.js";
19
+ export type { OutlineSampler } from "./outline.js";
20
+ export { registerOutlineSampler, getOutlineSampler, getOutlinePoint, findNearestOutlinePoint, } from "./outline.js";
21
+ export { DEFAULT_VIEWPORT, getWorldToScreen, getScreenToWorld, panBy, zoomAt, resize, resolveSnapSpacing, isSnapToGridEnabled, } from "./viewport.js";
22
+ export { DEFAULT_LAYER_ID, emptyScene, apply, orderForTop, orderForBottom, orderBetween, orderBetweenMany, addBinaryFile, removeBinaryFile, getBinaryFile, } from "./scene.js";
23
+ export type { FractionalIndex } from "fractional-keys";
24
+ export type { BinaryFile } from "./file.js";
25
+ export { createBinaryFile } from "./file.js";
26
+ export { invert, batch, isNoop } from "./patch.js";
27
+ export { addElement, removeElement, updateElement, moveElement, addLink, removeLink, updateLink, addLayer, removeLayer, updateLayer, setViewport, addAnnotation, removeAnnotation, updateAnnotation, } from "./operations.js";
28
+ export type { Annotation, Comment } from "./annotation.js";
29
+ export { getAnnotationWorldPosition } from "./annotation-geometry.js";
30
+ export { getElement, getLink, getLayer, getLayersInOrder, getElementsInLayer, getLinksInLayer, getElementsInBounds, getElementsCoveredByBounds, getElementAt, buildSpatialIndex, queryByIndex, getElementAtIndexed, getChildrenOf, getElementOutline, registerElementOutline, type ElementOutlineProvider, getRootSelf, getDescendantsOf, isElementLocked, isElementHidden, } from "./queries.js";
31
+ export { SpatialGrid } from "./spatial.js";
32
+ export type { AccessibleNameResolver } from "./a11y.js";
33
+ export { getElementAccessibleName, registerAccessibleName } from "./a11y.js";
34
+ export type { LayoutFn, LayoutSpec, GridLayoutSpec, StackLayoutSpec, WrapLayoutSpec, TreeLayoutSpec, AutoLayoutSpec, } from "./layout.js";
35
+ export { gridLayout, stackLayout, wrapLayout, measureWrap, treeLayout, allElementsInLayer, getAutoLayoutSpec, runAutoLayout, } from "./layout.js";
36
+ export type { LayoutKindEntry } from "./layout-registry.js";
37
+ export { registerLayoutKind, unregisterLayoutKind, getLayoutKind, listLayoutKinds, } from "./layout-registry.js";
38
+ export { SNAP_PROBE_CULL_RADIUS, DEFAULT_GRID_SPACING, ELBOW_OBSTACLE_MARGIN, ELBOW_OBSTACLE_INTERIOR_EPSILON, FRAME_HEADER_HEIGHT, FRAME_HEADER_PADDING_X, FRAME_HEADER_FONT_SIZE, } from "./constants.js";
39
+ export { elbowRoute, type ElbowRouteOptions } from "./elbow-router.js";
40
+ export { routeElbowLink, routeElbowPreview } from "./elbow-link.js";
41
+ export { type Heading, HEADING_RIGHT, HEADING_DOWN, HEADING_LEFT, HEADING_UP, headingIsHorizontal, headingsEqual, flipHeading, vectorToHeading, headingForPoint, headingForPointFromElement, headingForEdgePoint, } from "./heading.js";
42
+ export type { SceneElementDiff } from "./diff.js";
43
+ export { diffSceneElements } from "./diff.js";
44
+ export type { ConflictResolutionInput, ThreeWayMergeConflict, ThreeWayMergeOptions, ThreeWayMergeReport, } from "./three-way-merge.js";
45
+ export { mergeScenesThreeWay, applyConflictResolutions } from "./three-way-merge.js";
46
+ export { isContainer, getContainerSpec, getDropZoneWorld, findContainerAt, expandDropZoneToFit, containerSizeForZone, registerContainerResolver, getDropZonesWorld, registerContainerZonesResolver, type ContainerSpec, type ContainerResolver, type ContainerZonesResolver, } from "./container.js";
47
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js ADDED
@@ -0,0 +1,40 @@
1
+ export { getCornerRadius, strokeOutsideExtent } from "./style.js";
2
+ export { ADAPTIVE_CORNER_RADIUS, PROPORTIONAL_CORNER_RADIUS } from "./constants.js";
3
+ export { getLinkEndpointWorld, getLinkPath, findLinkAt, getLinkCurvePoints, getLinkCurveSegments, getLinkWaypointMidpoints, getSelfLoopSpec, } from "./edge-geometry.js";
4
+ export { catmullRomBeziers, cubicWithEndTangents, flattenSegments, } from "./edge-curve.js";
5
+ // Element helpers + bounder registry
6
+ export { isRectangle, isEllipse, isPolygon, isPath, isText, isImage, isTemplate, isGroup, isFrame, isBlockArrow, isBrush, registerBounder, getBounder, getElementLocalBounds, getElementWorldBounds, } from "./shape.js";
7
+ export { registerRenderOverflow, getElementRenderBounds, } from "./render-bounds.js";
8
+ export { setTextMeasurer, getTextMeasurer, } from "./text-measure.js";
9
+ // Anchor helpers
10
+ export { STANDARD_ANCHORS, STANDARD_ANCHOR_RATIOS, CARDINAL_ANCHORS, getNamedAnchorLocal, getAnchorLocal, getAnchorWorld, getAnchorOutwardNormal, listAnchorsLocal, geometryDefaultAnchorsLocal, findNearestAnchor, snapExcludedAnchors, } from "./anchors.js";
11
+ export { SnapEngine, gridSnapper, anchorSnapper, outlineSnapper } from "./snap.js";
12
+ export { registerOutlineSampler, getOutlineSampler, getOutlinePoint, findNearestOutlinePoint, } from "./outline.js";
13
+ // Viewport helpers
14
+ export { DEFAULT_VIEWPORT, getWorldToScreen, getScreenToWorld, panBy, zoomAt, resize, resolveSnapSpacing, isSnapToGridEnabled, } from "./viewport.js";
15
+ // Scene constructor + apply + ordering helpers
16
+ export { DEFAULT_LAYER_ID, emptyScene, apply, orderForTop, orderForBottom, orderBetween, orderBetweenMany, addBinaryFile, removeBinaryFile, getBinaryFile, } from "./scene.js";
17
+ export { createBinaryFile } from "./file.js";
18
+ // Patch utilities
19
+ export { invert, batch, isNoop } from "./patch.js";
20
+ // Operations (return { scene, patch })
21
+ export { addElement, removeElement, updateElement, moveElement, addLink, removeLink, updateLink, addLayer, removeLayer, updateLayer, setViewport, addAnnotation, removeAnnotation, updateAnnotation, } from "./operations.js";
22
+ export { getAnnotationWorldPosition } from "./annotation-geometry.js";
23
+ // Queries
24
+ export { getElement, getLink, getLayer, getLayersInOrder, getElementsInLayer, getLinksInLayer, getElementsInBounds, getElementsCoveredByBounds, getElementAt, buildSpatialIndex, queryByIndex, getElementAtIndexed, getChildrenOf, getElementOutline, registerElementOutline, getRootSelf, getDescendantsOf, isElementLocked, isElementHidden, } from "./queries.js";
25
+ // Spatial index (the class itself, for advanced uses)
26
+ export { SpatialGrid } from "./spatial.js";
27
+ export { getElementAccessibleName, registerAccessibleName } from "./a11y.js";
28
+ export { gridLayout, stackLayout, wrapLayout, measureWrap, treeLayout, allElementsInLayer, getAutoLayoutSpec, runAutoLayout, } from "./layout.js";
29
+ export { registerLayoutKind, unregisterLayoutKind, getLayoutKind, listLayoutKinds, } from "./layout-registry.js";
30
+ // Tunable thresholds.
31
+ export { SNAP_PROBE_CULL_RADIUS, DEFAULT_GRID_SPACING, ELBOW_OBSTACLE_MARGIN, ELBOW_OBSTACLE_INTERIOR_EPSILON, FRAME_HEADER_HEIGHT, FRAME_HEADER_PADDING_X, FRAME_HEADER_FONT_SIZE, } from "./constants.js";
32
+ // Elbow router — A*-based obstacle-avoiding 90° routing.
33
+ export { elbowRoute } from "./elbow-router.js";
34
+ export { routeElbowLink, routeElbowPreview } from "./elbow-link.js";
35
+ export { HEADING_RIGHT, HEADING_DOWN, HEADING_LEFT, HEADING_UP, headingIsHorizontal, headingsEqual, flipHeading, vectorToHeading, headingForPoint, headingForPointFromElement, headingForEdgePoint, } from "./heading.js";
36
+ export { diffSceneElements } from "./diff.js";
37
+ export { mergeScenesThreeWay, applyConflictResolutions } from "./three-way-merge.js";
38
+ // Container / drop-zone protocol.
39
+ export { isContainer, getContainerSpec, getDropZoneWorld, findContainerAt, expandDropZoneToFit, containerSizeForZone, registerContainerResolver, getDropZonesWorld, registerContainerZonesResolver, } from "./container.js";
40
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,18 @@
1
+ import type { LayerId } from "@oh-just-another/types";
2
+ import type { FractionalIndex } from "fractional-keys";
3
+ /**
4
+ * Layer is a named, ordered container for shapes and edges. Membership is
5
+ * stored on the children (via `shape.layerId` / `edge.layerId`), not on the
6
+ * layer itself, so cross-layer moves are O(1) updates of a single field.
7
+ *
8
+ * Layer z-order is governed by `order` (fractional index). Within a layer,
9
+ * child z-order is governed by each child's `order`.
10
+ */
11
+ export interface Layer {
12
+ readonly id: LayerId;
13
+ readonly name: string;
14
+ readonly visible: boolean;
15
+ readonly locked: boolean;
16
+ readonly order: FractionalIndex;
17
+ }
18
+ //# sourceMappingURL=layer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer.d.ts","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wBAAwB,CAAC;AACtD,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAEvD;;;;;;;GAOG;AACH,MAAM,WAAW,KAAK;IACpB,QAAQ,CAAC,EAAE,EAAE,OAAO,CAAC;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,KAAK,EAAE,eAAe,CAAC;CACjC"}
package/dist/layer.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=layer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layer.js","sourceRoot":"","sources":["../src/layer.ts"],"names":[],"mappings":""}
@@ -0,0 +1,35 @@
1
+ import type { ElementId, Vec2 } from "@oh-just-another/types";
2
+ import type { Patch } from "./patch.js";
3
+ import type { Scene } from "./scene.js";
4
+ /**
5
+ * Pluggable layout registry.
6
+ *
7
+ * The built-in `AutoLayoutSpec` union is closed (grid / stack /
8
+ * tree); the registry lets hosts add their own kinds without
9
+ * widening the union. Each entry pairs a string `kind` with two
10
+ * functions:
11
+ *
12
+ * • `parse(metadata)` reads a shape's `metadata.autoLayout`
13
+ * payload and returns a validated spec (or `null` if the
14
+ * payload doesn't apply). This is what `getAutoLayoutSpec`
15
+ * consults after exhausting built-ins.
16
+ * • `run(scene, parentId, children, origin, spec)` produces the
17
+ * batched `Patch` (or `null` when nothing changed). The
18
+ * registry passes a pre-computed `children` list + dropzone-
19
+ * aware `origin` so plugins don't reimplement those.
20
+ *
21
+ * Registration is process-global — same model as the renderer
22
+ * registry. Hosts opt in via `registerLayoutKind("radial", ...)`;
23
+ * unregister returns the previous entry (mostly useful in tests).
24
+ */
25
+ export interface LayoutKindEntry<Spec = unknown> {
26
+ readonly kind: string;
27
+ parse(metadata: unknown): Spec | null;
28
+ run(scene: Scene, parentId: ElementId, children: readonly ElementId[], origin: Vec2, spec: Spec): Patch | null;
29
+ }
30
+ export declare const registerLayoutKind: <S>(entry: LayoutKindEntry<S>) => void;
31
+ export declare const unregisterLayoutKind: (kind: string) => LayoutKindEntry | undefined;
32
+ export declare const getLayoutKind: (kind: string) => LayoutKindEntry | undefined;
33
+ /** Iterate every registered kind — useful for diagnostics / lints. */
34
+ export declare const listLayoutKinds: () => readonly string[];
35
+ //# sourceMappingURL=layout-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"layout-registry.d.ts","sourceRoot":"","sources":["../src/layout-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AACxC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAC;AAExC;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,MAAM,WAAW,eAAe,CAAC,IAAI,GAAG,OAAO;IAC7C,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,KAAK,CAAC,QAAQ,EAAE,OAAO,GAAG,IAAI,GAAG,IAAI,CAAC;IACtC,GAAG,CACD,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,SAAS,EACnB,QAAQ,EAAE,SAAS,SAAS,EAAE,EAC9B,MAAM,EAAE,IAAI,EACZ,IAAI,EAAE,IAAI,GACT,KAAK,GAAG,IAAI,CAAC;CACjB;AAID,eAAO,MAAM,kBAAkB,GAAI,CAAC,EAAE,OAAO,eAAe,CAAC,CAAC,CAAC,KAAG,IAEjE,CAAC;AAEF,eAAO,MAAM,oBAAoB,GAAI,MAAM,MAAM,KAAG,eAAe,GAAG,SAIrE,CAAC;AAEF,eAAO,MAAM,aAAa,GAAI,MAAM,MAAM,KAAG,eAAe,GAAG,SAC3C,CAAC;AAErB,sEAAsE;AACtE,eAAO,MAAM,eAAe,QAAO,SAAS,MAAM,EAA0B,CAAC"}
@@ -0,0 +1,13 @@
1
+ const registry = new Map();
2
+ export const registerLayoutKind = (entry) => {
3
+ registry.set(entry.kind, entry);
4
+ };
5
+ export const unregisterLayoutKind = (kind) => {
6
+ const prev = registry.get(kind);
7
+ registry.delete(kind);
8
+ return prev;
9
+ };
10
+ export const getLayoutKind = (kind) => registry.get(kind);
11
+ /** Iterate every registered kind — useful for diagnostics / lints. */
12
+ export const listLayoutKinds = () => [...registry.keys()];
13
+ //# sourceMappingURL=layout-registry.js.map