@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
package/dist/scene.js ADDED
@@ -0,0 +1,129 @@
1
+ import { layerId as castLayerId, } from "@oh-just-another/types";
2
+ import { generateKeyBetween, generateNKeysBetween } from "fractional-keys";
3
+ import {} from "./layer.js";
4
+ import { DEFAULT_VIEWPORT } from "./viewport.js";
5
+ export const DEFAULT_LAYER_ID = castLayerId("default");
6
+ const defaultLayer = () => ({
7
+ id: DEFAULT_LAYER_ID,
8
+ name: "Default",
9
+ visible: true,
10
+ locked: false,
11
+ order: generateKeyBetween(null, null),
12
+ });
13
+ /** Empty scene with a single default layer and a zero-size viewport. */
14
+ export const emptyScene = () => ({
15
+ elements: new Map(),
16
+ links: new Map(),
17
+ layers: new Map([[DEFAULT_LAYER_ID, defaultLayer()]]),
18
+ annotations: new Map(),
19
+ files: new Map(),
20
+ viewport: DEFAULT_VIEWPORT,
21
+ });
22
+ /**
23
+ * Idempotent add: writes the file under its id, replacing any
24
+ * previous entry with the same id. Returns a fresh Scene with
25
+ * the new `files` map. Pure.
26
+ */
27
+ export const addBinaryFile = (scene, file) => {
28
+ const files = new Map(scene.files);
29
+ files.set(file.id, file);
30
+ return { ...scene, files };
31
+ };
32
+ /**
33
+ * Remove a binary file by id. No-op when the id isn't present.
34
+ * Doesn't garbage-collect references — callers that delete shapes
35
+ * pointing at the file should remove the file separately when
36
+ * they're certain no other shape still references it.
37
+ */
38
+ export const removeBinaryFile = (scene, id) => {
39
+ if (!scene.files.has(id))
40
+ return scene;
41
+ const files = new Map(scene.files);
42
+ files.delete(id);
43
+ return { ...scene, files };
44
+ };
45
+ /** Lookup helper — mirrors `getElement` / `getLink` style. */
46
+ export const getBinaryFile = (scene, id) => scene.files.get(id);
47
+ /** Apply a patch to a scene, returning a new scene. Pure. */
48
+ export const apply = (scene, patch) => {
49
+ switch (patch.kind) {
50
+ case "element": {
51
+ const elements = new Map(scene.elements);
52
+ if (patch.after === null)
53
+ elements.delete(patch.id);
54
+ else
55
+ elements.set(patch.id, patch.after);
56
+ return { ...scene, elements };
57
+ }
58
+ case "link": {
59
+ const links = new Map(scene.links);
60
+ if (patch.after === null)
61
+ links.delete(patch.id);
62
+ else
63
+ links.set(patch.id, patch.after);
64
+ return { ...scene, links };
65
+ }
66
+ case "layer": {
67
+ const layers = new Map(scene.layers);
68
+ if (patch.after === null)
69
+ layers.delete(patch.id);
70
+ else
71
+ layers.set(patch.id, patch.after);
72
+ return { ...scene, layers };
73
+ }
74
+ case "annotation": {
75
+ const annotations = new Map(scene.annotations);
76
+ if (patch.after === null)
77
+ annotations.delete(patch.id);
78
+ else
79
+ annotations.set(patch.id, patch.after);
80
+ return { ...scene, annotations };
81
+ }
82
+ case "viewport":
83
+ return { ...scene, viewport: patch.after };
84
+ case "file": {
85
+ const files = new Map(scene.files);
86
+ if (patch.after === null)
87
+ files.delete(patch.id);
88
+ else
89
+ files.set(patch.id, patch.after);
90
+ return { ...scene, files };
91
+ }
92
+ case "batch":
93
+ return patch.patches.reduce(apply, scene);
94
+ }
95
+ };
96
+ // --- Fractional-index helpers ---
97
+ /**
98
+ * Pick an `order` key that places the new entity above every existing one in
99
+ * `layerId`. O(n) in the number of entities in that layer. For bulk inserts,
100
+ * compute once and chain manually.
101
+ */
102
+ export const orderForTop = (existing) => {
103
+ let highest = null;
104
+ for (const order of existing) {
105
+ if (highest === null || order > highest)
106
+ highest = order;
107
+ }
108
+ return generateKeyBetween(highest, null);
109
+ };
110
+ /** Mirror of `orderForTop` for placing below everything. */
111
+ export const orderForBottom = (existing) => {
112
+ let lowest = null;
113
+ for (const order of existing) {
114
+ if (lowest === null || order < lowest)
115
+ lowest = order;
116
+ }
117
+ return generateKeyBetween(null, lowest);
118
+ };
119
+ /** Pick an `order` that places strictly between two neighbors. */
120
+ export const orderBetween = (a, b) => generateKeyBetween(a, b);
121
+ /**
122
+ * Generate `n` evenly-spaced fractional indices strictly between `a` and
123
+ * `b`. Useful for compaction passes that rewrite a whole layer's
124
+ * z-order back to short balanced strings (`"a0"`, `"a1"`, `"a2"`, …)
125
+ * after a burst of insert-in-the-middle operations has lengthened the
126
+ * existing keys.
127
+ */
128
+ export const orderBetweenMany = (a, b, n) => generateNKeysBetween(a, b, n);
129
+ //# sourceMappingURL=scene.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scene.js","sourceRoot":"","sources":["../src/scene.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,306 @@
1
+ import type { Bounds, FileId, LayerId, ElementId, Vec2 } from "@oh-just-another/types";
2
+ import type { FractionalIndex } from "fractional-keys";
3
+ import type { AnchorRef } from "./edge.js";
4
+ import type { Style, TextStyle } from "./style.js";
5
+ /**
6
+ * Fields shared by every shape variant. `order` is a fractional-index string
7
+ * used for z-ordering within the parent layer — insertions are O(1) and never
8
+ * require renumbering neighbors, which keeps history small and is conflict-free
9
+ * under concurrent edits.
10
+ */
11
+ export interface ElementBase {
12
+ readonly id: ElementId;
13
+ readonly layerId: LayerId;
14
+ /** Discriminator. Built-in shapes use the literal types declared below. */
15
+ readonly type: string;
16
+ /** Local-space origin. The shape is rotated/scaled around this point. */
17
+ readonly position: Vec2;
18
+ /** Rotation in radians, counter-clockwise. */
19
+ readonly rotation: number;
20
+ readonly scale: Vec2;
21
+ /** Z-order key within `layerId`. */
22
+ readonly order: FractionalIndex;
23
+ readonly style: Style;
24
+ /** Free-form metadata for plugins; the kernel never reads from here. */
25
+ readonly metadata?: Readonly<Record<string, unknown>>;
26
+ /**
27
+ * Interactive-resize size constraints in local pixels. The editor clamps
28
+ * the shape's width/height into [min, max] after every resize gesture.
29
+ * Omitted = no constraint on that axis.
30
+ */
31
+ readonly minWidth?: number;
32
+ readonly minHeight?: number;
33
+ readonly maxWidth?: number;
34
+ readonly maxHeight?: number;
35
+ /**
36
+ * If true, interactive resize is prevented from dragging through the
37
+ * opposite edge — the shape cannot be mirrored by overshooting a handle.
38
+ * `width` / `height` are clamped to a non-negative range (or `minWidth` /
39
+ * `minHeight` if set). Defaults to `false` for backward compatibility.
40
+ */
41
+ readonly noFlip?: boolean;
42
+ /**
43
+ * Custom named connection points on this shape, on top of the 9 standard
44
+ * anchors (`top-left` / `top` / `top-right` / `right` / `bottom-right` /
45
+ * `bottom` / `bottom-left` / `left` / `center`). Entries with a standard
46
+ * name override the standard placement; new names add fresh ports.
47
+ *
48
+ * Values are `AnchorRef`s — `ratio` keeps the point proportional to the
49
+ * shape's bounds, `absolute` pins it at a fixed pixel offset. Resolving
50
+ * an anchor is `getAnchorLocal` / `getAnchorWorld` in `./anchors.ts`.
51
+ */
52
+ readonly anchors?: Readonly<Record<string, AnchorRef>>;
53
+ /**
54
+ * Optional parent shape id. When set, the shape is considered part of
55
+ * the parent's group: hit-test and drag operations promote selection
56
+ * to the parent (grouped), and `moveSelectionBy` translates every
57
+ * descendant in lockstep. The kernel does not enforce a particular
58
+ * shape type for parents — `GroupElement` (type `"group"`) is just the
59
+ * default zero-render container; custom shape types can also act as
60
+ * parents.
61
+ */
62
+ readonly parentId?: ElementId;
63
+ /**
64
+ * Frame membership — modern-style. Distinct from `parentId`
65
+ * (which is for groups and containers). Children of a frame are
66
+ * NOT nested in its `children` list; they're flat in the scene
67
+ * but share `frameId === frame.id`. Move-by-drag of the frame
68
+ * translates every shape with the matching frameId; export-by-
69
+ * frame uses the frame's bounds as the crop region.
70
+ */
71
+ readonly frameId?: ElementId;
72
+ /**
73
+ * Per-shape lock flag. Locked shapes ignore all interactive gestures
74
+ * (hit-test pretends they're not there for clicks / drags / resize),
75
+ * but still render and remain serialisable. Propagates to
76
+ * descendants: if any ancestor in the `parentId` chain is locked,
77
+ * the shape is effectively locked. Use `isElementLocked(scene, shape)`
78
+ * to consult the propagated state.
79
+ *
80
+ * Independent from `Layer.locked` — both gate interactions; either
81
+ * one being true is enough to lock.
82
+ */
83
+ readonly locked?: boolean;
84
+ /**
85
+ * Per-shape visibility flag. Hidden shapes do not render and do not
86
+ * receive interactions. Propagates to descendants like `locked`.
87
+ * Use `isElementHidden(scene, shape)` to consult the propagated state.
88
+ *
89
+ * Independent from `Layer.visible` — either being false hides the
90
+ * shape.
91
+ */
92
+ readonly hidden?: boolean;
93
+ /**
94
+ * Element-level hyperlink (standard model). Any shape — text, image,
95
+ * rectangle — can carry one. The host opens it on Cmd/Ctrl-click or via
96
+ * the hover link-popup. Stored verbatim; the host MUST validate the
97
+ * scheme before navigating (only `http`/`https`/`mailto` — never
98
+ * `javascript:`). Per-fragment links inside text are a separate
99
+ * rich-text feature.
100
+ */
101
+ readonly href?: string;
102
+ }
103
+ export interface RectangleElement extends ElementBase {
104
+ readonly type: "rectangle";
105
+ readonly width: number;
106
+ readonly height: number;
107
+ }
108
+ export interface EllipseElement extends ElementBase {
109
+ readonly type: "ellipse";
110
+ readonly width: number;
111
+ readonly height: number;
112
+ }
113
+ export interface PolygonElement extends ElementBase {
114
+ readonly type: "polygon";
115
+ /** Closed polygon in local coordinates (origin = `position`). */
116
+ readonly points: readonly Vec2[];
117
+ }
118
+ export type PathCommand = {
119
+ readonly kind: "M";
120
+ readonly to: Vec2;
121
+ } | {
122
+ readonly kind: "L";
123
+ readonly to: Vec2;
124
+ } | {
125
+ readonly kind: "Q";
126
+ readonly control: Vec2;
127
+ readonly to: Vec2;
128
+ } | {
129
+ readonly kind: "C";
130
+ readonly control1: Vec2;
131
+ readonly control2: Vec2;
132
+ readonly to: Vec2;
133
+ } | {
134
+ readonly kind: "Z";
135
+ };
136
+ export interface PathElement extends ElementBase {
137
+ readonly type: "path";
138
+ /** Commands in local coordinates. */
139
+ readonly commands: readonly PathCommand[];
140
+ }
141
+ export interface TextElement extends ElementBase {
142
+ readonly type: "text";
143
+ readonly text: string;
144
+ readonly fontFamily: string;
145
+ readonly fontSize: number;
146
+ /** Width budget for wrapping; `undefined` = single line. */
147
+ readonly maxWidth?: number;
148
+ readonly style: TextStyle;
149
+ }
150
+ export interface ImageElement extends ElementBase {
151
+ readonly type: "image";
152
+ /**
153
+ * URL or data-URI. Kept as a fallback for legacy scenes and for
154
+ * remote-host / SVG images that don't need binary registration.
155
+ * Newer shapes set `fileId` to point at a `Scene.files` entry
156
+ * instead — keeps scene.json small for large bitmaps.
157
+ */
158
+ readonly src: string;
159
+ /**
160
+ * Id of the `BinaryFile` in `Scene.files` that backs this image.
161
+ * When present, hosts should resolve through the file registry
162
+ * (creates an object-URL or ImageBitmap on demand); `src` stays
163
+ * around as a fallback for the static renderer path.
164
+ */
165
+ readonly fileId?: FileId;
166
+ readonly width: number;
167
+ readonly height: number;
168
+ /**
169
+ * Animated-content hint (opt-in). When set, the
170
+ * renderer's image path consults `getAnimationAdapter(kind)`
171
+ * to fetch the current frame's image source instead of using
172
+ * `src` directly. Hosts that don't register an adapter for the
173
+ * kind get a static fallback (src as-is). The actual frame data
174
+ * lives in `animationData` — opaque to the kernel, decoded by
175
+ * the adapter.
176
+ *
177
+ * Built-in kinds: "gif" (host plugs `gifuct-js`), "lottie"
178
+ * (host plugs `lottie-web`), "video" (host plugs an
179
+ * `HTMLVideoElement`). No adapters ship in the kernel —
180
+ * registration is per-host.
181
+ */
182
+ readonly animationKind?: string;
183
+ readonly animationData?: unknown;
184
+ }
185
+ /**
186
+ * Composite shape backed by a rich template (`@oh-just-another/templates`). The
187
+ * scene stores only the binding (`templateId` + `data`) plus a fixed box
188
+ * size — layout, hit-test and rendering live in the templates package.
189
+ *
190
+ * The kernel ships a basic bounder (uses `width` × `height`); the templates
191
+ * package can re-register a tighter bounder that respects the layout engine.
192
+ */
193
+ export interface TemplateElement extends ElementBase {
194
+ readonly type: "template";
195
+ readonly templateId: string;
196
+ readonly data: Readonly<Record<string, unknown>>;
197
+ readonly width: number;
198
+ readonly height: number;
199
+ }
200
+ /**
201
+ * Variable-width brush stroke. Each `BrushPoint` carries its own width
202
+ * (typically derived from `PointerEvent.pressure × MAX_BRUSH_WIDTH`).
203
+ * The renderer interpolates between consecutive widths along the path.
204
+ *
205
+ * Coordinates are local; the shape's `position` / `rotation` / `scale`
206
+ * apply on top, same as any other shape variant.
207
+ */
208
+ export interface BrushPoint {
209
+ readonly x: number;
210
+ readonly y: number;
211
+ /** Stroke half-width in local pixels at this vertex. */
212
+ readonly width: number;
213
+ }
214
+ export interface BrushElement extends ElementBase {
215
+ readonly type: "brush";
216
+ readonly points: readonly BrushPoint[];
217
+ }
218
+ /**
219
+ * Container shape that holds children via the shared `parentId` link.
220
+ * Rendered as a no-op (the group itself has no visual); the editor's
221
+ * overlay highlights the union AABB of the children when selected.
222
+ */
223
+ export interface GroupElement extends ElementBase {
224
+ readonly type: "group";
225
+ }
226
+ /**
227
+ * Frame element — modern-style visual container that groups
228
+ * shapes via a separate `frameId` link (NOT `parentId`). Drawn as
229
+ * a dashed rectangle with a header title; clicks pass through to
230
+ * children. Move-by-drag translates every shape whose `frameId`
231
+ * matches; the export pipeline can crop to the frame's bounds.
232
+ *
233
+ * Auto-numbering: the editor picks the next free "Frame N" on
234
+ * create. Custom `name` overrides.
235
+ */
236
+ export interface FrameElement extends ElementBase {
237
+ readonly type: "frame";
238
+ readonly width: number;
239
+ readonly height: number;
240
+ /** Visible header label. */
241
+ readonly name?: string;
242
+ }
243
+ /**
244
+ * Filled arrow drawn as a single shape (body rectangle + triangular
245
+ * head, optionally with a triangular tail). Distinct from an Link:
246
+ * edges connect anchors and re-route on shape move; a BlockArrowElement
247
+ * is a free-standing element with a fixed silhouette like a block-arrow icon.
248
+ */
249
+ export interface BlockArrowElement extends ElementBase {
250
+ readonly type: "block-arrow";
251
+ readonly width: number;
252
+ readonly height: number;
253
+ /**
254
+ * Where the arrow points. Default `"right"`. Rotation is still
255
+ * applied on top via `ElementBase.rotation` — this enum just picks
256
+ * the head side in local coords so the user can quickly toggle
257
+ * direction without typing a 90/180/270 deg angle.
258
+ */
259
+ readonly direction?: "right" | "left" | "up" | "down";
260
+ /** Ratio of the head length over the total length (0..0.9). Default 0.4. */
261
+ readonly headRatio?: number;
262
+ /** Ratio of the body thickness over the perpendicular dimension. Default 0.5. */
263
+ readonly bodyThickness?: number;
264
+ }
265
+ export type BuiltinElement = RectangleElement | EllipseElement | PolygonElement | PathElement | TextElement | ImageElement | TemplateElement | GroupElement | FrameElement | BlockArrowElement | BrushElement;
266
+ /**
267
+ * Open shape type. `Element` accepts any `ElementBase` extension, which lets plugins
268
+ * register their own types without amending this union. The kernel treats
269
+ * unknown shape types via the bounder registry — see `registerBounder`.
270
+ */
271
+ export type Element = BuiltinElement | ElementBase;
272
+ export declare const isRectangle: (s: ElementBase) => s is RectangleElement;
273
+ export declare const isEllipse: (s: ElementBase) => s is EllipseElement;
274
+ export declare const isPolygon: (s: ElementBase) => s is PolygonElement;
275
+ export declare const isPath: (s: ElementBase) => s is PathElement;
276
+ export declare const isText: (s: ElementBase) => s is TextElement;
277
+ export declare const isImage: (s: ElementBase) => s is ImageElement;
278
+ export declare const isTemplate: (s: ElementBase) => s is TemplateElement;
279
+ export declare const isGroup: (s: ElementBase) => s is GroupElement;
280
+ export declare const isFrame: (s: ElementBase) => s is FrameElement;
281
+ export declare const isBlockArrow: (s: ElementBase) => s is BlockArrowElement;
282
+ export declare const isBrush: (s: ElementBase) => s is BrushElement;
283
+ /**
284
+ * Computes the *local* bounds of a shape — its AABB in local coordinates,
285
+ * before `position`/`rotation`/`scale` are applied. The world AABB lives in
286
+ * `getElementWorldBounds`.
287
+ */
288
+ export type ElementBounder<S extends ElementBase = ElementBase> = (shape: S) => Bounds;
289
+ /**
290
+ * Register a bounder for a custom shape type. Plugins call this once at module
291
+ * load. The kernel ships bounders for every `BuiltinElement`.
292
+ */
293
+ export declare const registerBounder: <S extends ElementBase>(type: S["type"], bounder: ElementBounder<S>) => void;
294
+ /** Look up a registered bounder. Returns `undefined` for unknown shape types. */
295
+ export declare const getBounder: (type: string) => ElementBounder | undefined;
296
+ /**
297
+ * Local AABB for any shape with a registered bounder. Throws on unknown types
298
+ * — callers should either register a bounder or filter unknown shapes out.
299
+ */
300
+ export declare const getElementLocalBounds: (shape: ElementBase) => Bounds;
301
+ /**
302
+ * World-space AABB after `position`/`rotation`/`scale`. This is the conservative
303
+ * AABB of the rotated/scaled local box, suitable for spatial-index keys.
304
+ */
305
+ export declare const getElementWorldBounds: (shape: ElementBase) => Bounds;
306
+ //# sourceMappingURL=shape.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.d.ts","sourceRoot":"","sources":["../src/shape.ts"],"names":[],"mappings":"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"}
package/dist/shape.js ADDED
@@ -0,0 +1,192 @@
1
+ import { bounds as B } from "@oh-just-another/math";
2
+ import { TEXT_APPROX_CHAR_WIDTH_FACTOR, TEXT_LINE_HEIGHT_FACTOR } from "./constants.js";
3
+ import { getTextMeasurer } from "./text-measure.js";
4
+ // --- type guards ---
5
+ export const isRectangle = (s) => s.type === "rectangle";
6
+ export const isEllipse = (s) => s.type === "ellipse";
7
+ export const isPolygon = (s) => s.type === "polygon";
8
+ export const isPath = (s) => s.type === "path";
9
+ export const isText = (s) => s.type === "text";
10
+ export const isImage = (s) => s.type === "image";
11
+ export const isTemplate = (s) => s.type === "template";
12
+ export const isGroup = (s) => s.type === "group";
13
+ export const isFrame = (s) => s.type === "frame";
14
+ export const isBlockArrow = (s) => s.type === "block-arrow";
15
+ export const isBrush = (s) => s.type === "brush";
16
+ const bounderRegistry = new Map();
17
+ /**
18
+ * Register a bounder for a custom shape type. Plugins call this once at module
19
+ * load. The kernel ships bounders for every `BuiltinElement`.
20
+ */
21
+ export const registerBounder = (type, bounder) => {
22
+ bounderRegistry.set(type, bounder);
23
+ };
24
+ /** Look up a registered bounder. Returns `undefined` for unknown shape types. */
25
+ export const getBounder = (type) => bounderRegistry.get(type);
26
+ /**
27
+ * Local AABB for any shape with a registered bounder. Throws on unknown types
28
+ * — callers should either register a bounder or filter unknown shapes out.
29
+ */
30
+ export const getElementLocalBounds = (shape) => {
31
+ const bounder = bounderRegistry.get(shape.type);
32
+ if (!bounder) {
33
+ throw new Error(`No bounder registered for shape type: ${shape.type}`);
34
+ }
35
+ return bounder(shape);
36
+ };
37
+ /**
38
+ * World-space AABB after `position`/`rotation`/`scale`. This is the conservative
39
+ * AABB of the rotated/scaled local box, suitable for spatial-index keys.
40
+ */
41
+ export const getElementWorldBounds = (shape) => {
42
+ const local = getElementLocalBounds(shape);
43
+ // Transform 4 corners then re-AABB.
44
+ const corners = [
45
+ { x: local.x, y: local.y },
46
+ { x: local.x + local.width, y: local.y },
47
+ { x: local.x, y: local.y + local.height },
48
+ { x: local.x + local.width, y: local.y + local.height },
49
+ ];
50
+ const sin = Math.sin(shape.rotation);
51
+ const cos = Math.cos(shape.rotation);
52
+ const transformed = corners.map((p) => {
53
+ const sx = p.x * shape.scale.x;
54
+ const sy = p.y * shape.scale.y;
55
+ return {
56
+ x: shape.position.x + (sx * cos - sy * sin),
57
+ y: shape.position.y + (sx * sin + sy * cos),
58
+ };
59
+ });
60
+ return B.fromPoints(transformed);
61
+ };
62
+ // --- built-in bounders ---
63
+ registerBounder("rectangle", (s) => ({
64
+ x: 0,
65
+ y: 0,
66
+ width: s.width,
67
+ height: s.height,
68
+ }));
69
+ registerBounder("ellipse", (s) => ({
70
+ x: 0,
71
+ y: 0,
72
+ width: s.width,
73
+ height: s.height,
74
+ }));
75
+ registerBounder("polygon", (s) => B.fromPoints(s.points));
76
+ registerBounder("path", (s) => {
77
+ const points = [];
78
+ let cursor = { x: 0, y: 0 };
79
+ for (const cmd of s.commands) {
80
+ switch (cmd.kind) {
81
+ case "M":
82
+ case "L":
83
+ points.push(cmd.to);
84
+ cursor = cmd.to;
85
+ break;
86
+ case "Q":
87
+ points.push(cmd.control, cmd.to);
88
+ cursor = cmd.to;
89
+ break;
90
+ case "C":
91
+ points.push(cmd.control1, cmd.control2, cmd.to);
92
+ cursor = cmd.to;
93
+ break;
94
+ case "Z":
95
+ // closes the subpath, no new points
96
+ break;
97
+ }
98
+ }
99
+ // suppress unused-var warning
100
+ void cursor;
101
+ return B.fromPoints(points);
102
+ });
103
+ registerBounder("text", (s) => {
104
+ // Width comes from the host measurer when installed (matches the
105
+ // actually-rendered glyph advances), falling back to a geometric
106
+ // estimate (`chars × fontSize × factor`) headless / in tests. Height
107
+ // is line count × line-height; hard newlines honoured in both modes.
108
+ const lineHeight = s.fontSize * TEXT_LINE_HEIGHT_FACTOR;
109
+ const paragraphs = s.text.split("\n");
110
+ const measurer = getTextMeasurer();
111
+ // Pass weight/style so the measured width matches the rendered (bold /
112
+ // italic) glyphs — otherwise the box wouldn't grow when text is bolded.
113
+ const opts = {
114
+ bold: s.style.fontWeight === "bold",
115
+ italic: s.style.fontStyle === "italic",
116
+ };
117
+ const measureLine = (line) => {
118
+ if (measurer) {
119
+ const w = measurer(line, s.fontFamily, s.fontSize, opts);
120
+ if (w !== null)
121
+ return w;
122
+ }
123
+ return line.length * s.fontSize * TEXT_APPROX_CHAR_WIDTH_FACTOR;
124
+ };
125
+ if (s.maxWidth === undefined) {
126
+ // Auto-width: widest paragraph drives width, one visual line per
127
+ // paragraph. Empty text keeps a caret-sized box so it stays
128
+ // selectable / editable.
129
+ let width = 0;
130
+ for (const p of paragraphs)
131
+ width = Math.max(width, measureLine(p));
132
+ width = Math.max(width, s.fontSize * 0.5);
133
+ return { x: 0, y: 0, width, height: Math.max(1, paragraphs.length) * lineHeight };
134
+ }
135
+ // Fixed-width: width is the budget; height ≈ wrapped line count.
136
+ let lines = 0;
137
+ for (const p of paragraphs) {
138
+ lines += Math.max(1, Math.ceil(measureLine(p) / s.maxWidth));
139
+ }
140
+ return { x: 0, y: 0, width: s.maxWidth, height: Math.max(1, lines) * lineHeight };
141
+ });
142
+ registerBounder("image", (s) => ({
143
+ x: 0,
144
+ y: 0,
145
+ width: s.width,
146
+ height: s.height,
147
+ }));
148
+ // Built-in template bounder: uses the explicit `width` × `height` box. The
149
+ // templates package can re-register a tighter bounder driven by the layout
150
+ // engine when an instance is auto-sized.
151
+ registerBounder("template", (s) => ({
152
+ x: 0,
153
+ y: 0,
154
+ width: s.width,
155
+ height: s.height,
156
+ }));
157
+ registerBounder("brush", (s) => {
158
+ if (s.points.length === 0)
159
+ return { x: 0, y: 0, width: 0, height: 0 };
160
+ let minX = Infinity;
161
+ let minY = Infinity;
162
+ let maxX = -Infinity;
163
+ let maxY = -Infinity;
164
+ for (const p of s.points) {
165
+ if (p.x - p.width < minX)
166
+ minX = p.x - p.width;
167
+ if (p.y - p.width < minY)
168
+ minY = p.y - p.width;
169
+ if (p.x + p.width > maxX)
170
+ maxX = p.x + p.width;
171
+ if (p.y + p.width > maxY)
172
+ maxY = p.y + p.width;
173
+ }
174
+ return { x: minX, y: minY, width: maxX - minX, height: maxY - minY };
175
+ });
176
+ // Group shapes have no intrinsic geometry — their world AABB is empty.
177
+ // Callers that need the union of descendants must walk `parentId` via
178
+ // `getChildrenOf` and union the children's world bounds instead.
179
+ registerBounder("group", () => ({ x: 0, y: 0, width: 0, height: 0 }));
180
+ registerBounder("frame", (s) => ({
181
+ x: 0,
182
+ y: 0,
183
+ width: s.width,
184
+ height: s.height,
185
+ }));
186
+ registerBounder("block-arrow", (s) => ({
187
+ x: 0,
188
+ y: 0,
189
+ width: s.width,
190
+ height: s.height,
191
+ }));
192
+ //# sourceMappingURL=shape.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"shape.js","sourceRoot":"","sources":["../src/shape.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,IAAI,CAAC,EAAE,MAAM,uBAAuB,CAAC;AAGpD,OAAO,EAAE,6BAA6B,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AACxF,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAoSpD,sBAAsB;AAEtB,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAc,EAAyB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,WAAW,CAAC;AAC7F,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAc,EAAuB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;AACvF,MAAM,CAAC,MAAM,SAAS,GAAG,CAAC,CAAc,EAAuB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,CAAC;AACvF,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAc,EAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9E,MAAM,CAAC,MAAM,MAAM,GAAG,CAAC,CAAc,EAAoB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,MAAM,CAAC;AAC9E,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAc,EAAqB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;AACjF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,CAAc,EAAwB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,UAAU,CAAC;AAC1F,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAc,EAAqB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;AACjF,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAc,EAAqB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;AACjF,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,CAAc,EAA0B,EAAE,CACrE,CAAC,CAAC,IAAI,KAAK,aAAa,CAAC;AAC3B,MAAM,CAAC,MAAM,OAAO,GAAG,CAAC,CAAc,EAAqB,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC;AAWjF,MAAM,eAAe,GAAG,IAAI,GAAG,EAA0B,CAAC;AAE1D;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAC7B,IAAe,EACf,OAA0B,EACpB,EAAE;IACR,eAAe,CAAC,GAAG,CAAC,IAAI,EAAE,OAAyB,CAAC,CAAC;AACvD,CAAC,CAAC;AAEF,iFAAiF;AACjF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAY,EAA8B,EAAE,CAAC,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;AAElG;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAkB,EAAU,EAAE;IAClE,MAAM,OAAO,GAAG,eAAe,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAChD,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,yCAAyC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,OAAO,CAAC,KAAK,CAAC,CAAC;AACxB,CAAC,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,MAAM,qBAAqB,GAAG,CAAC,KAAkB,EAAU,EAAE;IAClE,MAAM,KAAK,GAAG,qBAAqB,CAAC,KAAK,CAAC,CAAC;IAC3C,oCAAoC;IACpC,MAAM,OAAO,GAAoB;QAC/B,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;QAC1B,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE;QACxC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE;QACzC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE;KACxD,CAAC;IACF,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;IACrC,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;QACpC,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,MAAM,EAAE,GAAG,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,CAAC;QAC/B,OAAO;YACL,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;YAC3C,CAAC,EAAE,KAAK,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,EAAE,GAAG,GAAG,GAAG,EAAE,GAAG,GAAG,CAAC;SAC5C,CAAC;IACJ,CAAC,CAAC,CAAC;IACH,OAAO,CAAC,CAAC,UAAU,CAAC,WAAW,CAAC,CAAC;AACnC,CAAC,CAAC;AAEF,4BAA4B;AAE5B,eAAe,CAAmB,WAAW,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACrD,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,MAAM,EAAE,CAAC,CAAC,MAAM;CACjB,CAAC,CAAC,CAAC;AAEJ,eAAe,CAAiB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,MAAM,EAAE,CAAC,CAAC,MAAM;CACjB,CAAC,CAAC,CAAC;AAEJ,eAAe,CAAiB,SAAS,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;AAE1E,eAAe,CAAc,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;IACzC,MAAM,MAAM,GAAW,EAAE,CAAC;IAC1B,IAAI,MAAM,GAAS,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC;IAClC,KAAK,MAAM,GAAG,IAAI,CAAC,CAAC,QAAQ,EAAE,CAAC;QAC7B,QAAQ,GAAG,CAAC,IAAI,EAAE,CAAC;YACjB,KAAK,GAAG,CAAC;YACT,KAAK,GAAG;gBACN,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;gBACpB,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;gBAChB,MAAM;YACR,KAAK,GAAG;gBACN,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBACjC,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;gBAChB,MAAM;YACR,KAAK,GAAG;gBACN,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC,CAAC;gBAChD,MAAM,GAAG,GAAG,CAAC,EAAE,CAAC;gBAChB,MAAM;YACR,KAAK,GAAG;gBACN,oCAAoC;gBACpC,MAAM;QACV,CAAC;IACH,CAAC;IACD,8BAA8B;IAC9B,KAAK,MAAM,CAAC;IACZ,OAAO,CAAC,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;AAC9B,CAAC,CAAC,CAAC;AAEH,eAAe,CAAc,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE;IACzC,iEAAiE;IACjE,iEAAiE;IACjE,qEAAqE;IACrE,qEAAqE;IACrE,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,GAAG,uBAAuB,CAAC;IACxD,MAAM,UAAU,GAAG,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,eAAe,EAAE,CAAC;IACnC,uEAAuE;IACvE,wEAAwE;IACxE,MAAM,IAAI,GAAG;QACX,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,UAAU,KAAK,MAAM;QACnC,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,SAAS,KAAK,QAAQ;KACvC,CAAC;IACF,MAAM,WAAW,GAAG,CAAC,IAAY,EAAU,EAAE;QAC3C,IAAI,QAAQ,EAAE,CAAC;YACb,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC,CAAC;YACzD,IAAI,CAAC,KAAK,IAAI;gBAAE,OAAO,CAAC,CAAC;QAC3B,CAAC;QACD,OAAO,IAAI,CAAC,MAAM,GAAG,CAAC,CAAC,QAAQ,GAAG,6BAA6B,CAAC;IAClE,CAAC,CAAC;IACF,IAAI,CAAC,CAAC,QAAQ,KAAK,SAAS,EAAE,CAAC;QAC7B,iEAAiE;QACjE,4DAA4D;QAC5D,yBAAyB;QACzB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,MAAM,CAAC,IAAI,UAAU;YAAE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC;QACpE,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,CAAC,QAAQ,GAAG,GAAG,CAAC,CAAC;QAC1C,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,UAAU,CAAC,MAAM,CAAC,GAAG,UAAU,EAAE,CAAC;IACpF,CAAC;IACD,iEAAiE;IACjE,IAAI,KAAK,GAAG,CAAC,CAAC;IACd,KAAK,MAAM,CAAC,IAAI,UAAU,EAAE,CAAC;QAC3B,KAAK,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,CAAC,GAAG,UAAU,EAAE,CAAC;AACpF,CAAC,CAAC,CAAC;AAEH,eAAe,CAAe,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,MAAM,EAAE,CAAC,CAAC,MAAM;CACjB,CAAC,CAAC,CAAC;AAEJ,2EAA2E;AAC3E,2EAA2E;AAC3E,yCAAyC;AACzC,eAAe,CAAkB,UAAU,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACnD,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,MAAM,EAAE,CAAC,CAAC,MAAM;CACjB,CAAC,CAAC,CAAC;AAEJ,eAAe,CAAe,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE;IAC3C,IAAI,CAAC,CAAC,MAAM,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IACtE,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,IAAI,IAAI,GAAG,QAAQ,CAAC;IACpB,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC;IACrB,IAAI,IAAI,GAAG,CAAC,QAAQ,CAAC;IACrB,KAAK,MAAM,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,CAAC;QACzB,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI;YAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI;YAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI;YAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;QAC/C,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,GAAG,IAAI;YAAE,IAAI,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,KAAK,CAAC;IACjD,CAAC;IACD,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,GAAG,IAAI,EAAE,MAAM,EAAE,IAAI,GAAG,IAAI,EAAE,CAAC;AACvE,CAAC,CAAC,CAAC;AAEH,uEAAuE;AACvE,sEAAsE;AACtE,iEAAiE;AACjE,eAAe,CAAe,OAAO,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC;AAEpF,eAAe,CAAe,OAAO,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAC7C,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,MAAM,EAAE,CAAC,CAAC,MAAM;CACjB,CAAC,CAAC,CAAC;AAEJ,eAAe,CAAoB,aAAa,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IACxD,CAAC,EAAE,CAAC;IACJ,CAAC,EAAE,CAAC;IACJ,KAAK,EAAE,CAAC,CAAC,KAAK;IACd,MAAM,EAAE,CAAC,CAAC,MAAM;CACjB,CAAC,CAAC,CAAC"}