@weasel-js/core 0.5.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 (74) hide show
  1. package/CHANGELOG.md +381 -0
  2. package/LICENSE +21 -0
  3. package/README.md +144 -0
  4. package/dist/DrawCommand-Dl0bXNfS.d.ts +500 -0
  5. package/dist/chunk-775XXAHR.js +216 -0
  6. package/dist/chunk-775XXAHR.js.map +1 -0
  7. package/dist/chunk-7V6JEOXE.js +27754 -0
  8. package/dist/chunk-7V6JEOXE.js.map +1 -0
  9. package/dist/chunk-AM6ARSPN.js +517 -0
  10. package/dist/chunk-AM6ARSPN.js.map +1 -0
  11. package/dist/chunk-BGGZ4CVF.js +248 -0
  12. package/dist/chunk-BGGZ4CVF.js.map +1 -0
  13. package/dist/chunk-BHVYVFGV.js +29 -0
  14. package/dist/chunk-BHVYVFGV.js.map +1 -0
  15. package/dist/chunk-CQNKCG34.js +831 -0
  16. package/dist/chunk-CQNKCG34.js.map +1 -0
  17. package/dist/chunk-GVCNT7UH.js +47 -0
  18. package/dist/chunk-GVCNT7UH.js.map +1 -0
  19. package/dist/chunk-PZ5AY32C.js +9 -0
  20. package/dist/chunk-PZ5AY32C.js.map +1 -0
  21. package/dist/chunk-UGFFCMQP.js +28 -0
  22. package/dist/chunk-UGFFCMQP.js.map +1 -0
  23. package/dist/chunk-VOVKONXA.js +103 -0
  24. package/dist/chunk-VOVKONXA.js.map +1 -0
  25. package/dist/chunk-Y52N27PF.js +39 -0
  26. package/dist/chunk-Y52N27PF.js.map +1 -0
  27. package/dist/clipboard.d.ts +91 -0
  28. package/dist/clipboard.js +6 -0
  29. package/dist/clipboard.js.map +1 -0
  30. package/dist/clone.d.ts +8 -0
  31. package/dist/clone.js +6 -0
  32. package/dist/clone.js.map +1 -0
  33. package/dist/fitViewToBounds-evGsnR8Q.d.ts +62 -0
  34. package/dist/grid-Cf87knjU.d.ts +153 -0
  35. package/dist/index-DZBYMsHI.d.ts +1555 -0
  36. package/dist/index.css +121 -0
  37. package/dist/index.css.map +1 -0
  38. package/dist/index.d.ts +10200 -0
  39. package/dist/index.js +13 -0
  40. package/dist/index.js.map +1 -0
  41. package/dist/insert.d.ts +33 -0
  42. package/dist/insert.js +81 -0
  43. package/dist/insert.js.map +1 -0
  44. package/dist/move.d.ts +69 -0
  45. package/dist/move.js +145 -0
  46. package/dist/move.js.map +1 -0
  47. package/dist/options-BPPBWMa7.d.ts +64 -0
  48. package/dist/patterns-builtin.d.ts +55 -0
  49. package/dist/patterns-builtin.js +100 -0
  50. package/dist/patterns-builtin.js.map +1 -0
  51. package/dist/pointSnapToGrid-D7s7QmOF.d.ts +185 -0
  52. package/dist/registerFont-CP-wCsrz.d.ts +109 -0
  53. package/dist/registerTexture-BzHTLhD9.d.ts +25 -0
  54. package/dist/renderer.css +121 -0
  55. package/dist/renderer.css.map +1 -0
  56. package/dist/renderer.d.ts +376 -0
  57. package/dist/renderer.js +13 -0
  58. package/dist/renderer.js.map +1 -0
  59. package/dist/resize.d.ts +78 -0
  60. package/dist/resize.js +5 -0
  61. package/dist/resize.js.map +1 -0
  62. package/dist/routing.css +35 -0
  63. package/dist/routing.css.map +1 -0
  64. package/dist/routing.d.ts +14 -0
  65. package/dist/routing.js +4 -0
  66. package/dist/routing.js.map +1 -0
  67. package/dist/types-B6MMiodD.d.ts +59 -0
  68. package/dist/types-BJ8_cyT7.d.ts +130 -0
  69. package/dist/types-B_-khFM0.d.ts +331 -0
  70. package/dist/types-BjUi2vA-.d.ts +355 -0
  71. package/dist/types-Cpb4hii1.d.ts +445 -0
  72. package/dist/types-D2tTKEU0.d.ts +18 -0
  73. package/dist/view-DSQgxBJB.d.ts +63 -0
  74. package/package.json +96 -0
@@ -0,0 +1,130 @@
1
+ /** One bit per debug feature; absent keys are off. */
2
+ interface DebugConfig {
3
+ hitboxes?: boolean;
4
+ handles?: boolean;
5
+ bounds?: boolean;
6
+ origins?: boolean;
7
+ snap?: boolean;
8
+ layers?: boolean;
9
+ /** Render each tracked node's id as a label at the top-left of its
10
+ * bounds. Pulls from the same `recordBounds` stream `bounds` uses, so
11
+ * no extra sink calls are required to enable. */
12
+ ids?: boolean;
13
+ /** Rolling FPS counter rendered in the top-left corner of the canvas.
14
+ * Tracks the rate at which the debug overlay's draw callback runs;
15
+ * this matches the canvas's effective repaint rate. */
16
+ fps?: boolean;
17
+ /** Optional per-feature color overrides; falls back to the default theme. */
18
+ theme?: Partial<DebugTheme>;
19
+ }
20
+ type DebugFeature = 'hitboxes' | 'handles' | 'bounds' | 'origins' | 'snap' | 'layers' | 'ids' | 'fps';
21
+ interface DebugTheme {
22
+ hitboxFill: string;
23
+ hitboxStroke: string;
24
+ handle: string;
25
+ bounds: string;
26
+ origin: string;
27
+ snap: string;
28
+ layerText: string;
29
+ layerTextBg: string;
30
+ /** Color for the per-node id label rendered when `config.ids` is on. */
31
+ idText: string;
32
+ /** Foreground / background for the FPS panel. */
33
+ fpsText: string;
34
+ fpsTextBg: string;
35
+ }
36
+ type HandleKind = 'corner' | 'rotation' | 'anchor';
37
+ type HitShape = {
38
+ kind: 'rect';
39
+ x: number;
40
+ y: number;
41
+ width: number;
42
+ height: number;
43
+ rotation?: number;
44
+ } | {
45
+ kind: 'circle';
46
+ cx: number;
47
+ cy: number;
48
+ r: number;
49
+ } | {
50
+ kind: 'path';
51
+ d: Path2D;
52
+ };
53
+ interface RecordedHitbox {
54
+ id: string;
55
+ kind: 'body' | 'handle' | 'rotation' | 'anchor';
56
+ shape: HitShape;
57
+ }
58
+ interface RecordedHandle {
59
+ id: string;
60
+ position: {
61
+ x: number;
62
+ y: number;
63
+ };
64
+ kind: HandleKind;
65
+ }
66
+ interface RecordedBounds {
67
+ id: string;
68
+ bounds: {
69
+ x: number;
70
+ y: number;
71
+ width: number;
72
+ height: number;
73
+ };
74
+ }
75
+ interface RecordedOrigin {
76
+ id: string;
77
+ point: {
78
+ x: number;
79
+ y: number;
80
+ };
81
+ }
82
+ interface RecordedSnap {
83
+ point: {
84
+ x: number;
85
+ y: number;
86
+ };
87
+ accepted: boolean;
88
+ }
89
+ interface RecordedLayer {
90
+ id: string;
91
+ label: string;
92
+ space: 'world' | 'screen';
93
+ index: number;
94
+ }
95
+ interface DebugSnapshot {
96
+ hitboxes: RecordedHitbox[];
97
+ handles: RecordedHandle[];
98
+ bounds: RecordedBounds[];
99
+ origins: RecordedOrigin[];
100
+ snap: RecordedSnap[];
101
+ layers: RecordedLayer[];
102
+ }
103
+ interface DebugSink {
104
+ recordHitbox(id: string, kind: 'body' | 'handle' | 'rotation' | 'anchor', shape: HitShape): void;
105
+ recordHandle(id: string, position: {
106
+ x: number;
107
+ y: number;
108
+ }, kind: HandleKind): void;
109
+ recordBounds(id: string, bounds: {
110
+ x: number;
111
+ y: number;
112
+ width: number;
113
+ height: number;
114
+ }): void;
115
+ recordOrigin(id: string, point: {
116
+ x: number;
117
+ y: number;
118
+ }): void;
119
+ recordSnapCandidate(point: {
120
+ x: number;
121
+ y: number;
122
+ }, accepted: boolean): void;
123
+ recordLayer(id: string, label: string, space: 'world' | 'screen', index: number): void;
124
+ /** Clears every non-snap array. Called at the start of each Canvas render. */
125
+ beginFrame(): void;
126
+ /** Clears the snap array. Called at gesture end. */
127
+ clearSnap(): void;
128
+ }
129
+
130
+ export type { DebugSink as D, HandleKind as H, RecordedBounds as R, DebugConfig as a, DebugSnapshot as b, DebugTheme as c, DebugFeature as d, HitShape as e, RecordedHandle as f, RecordedHitbox as g, RecordedLayer as h, RecordedOrigin as i, RecordedSnap as j };
@@ -0,0 +1,331 @@
1
+ import { Op } from '@weasel-js/history';
2
+
3
+ type ContainerBounds = {
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ };
9
+ interface LayoutChild<TPose> {
10
+ id: string;
11
+ pose: TPose;
12
+ }
13
+ interface DropTarget<TPose> {
14
+ /** Where the dragged child lands if this target is picked. */
15
+ pose: TPose;
16
+ /** Reference point for distance metrics (snap algorithms). */
17
+ origin: {
18
+ x: number;
19
+ y: number;
20
+ };
21
+ /** Optional axis-aligned region (world units) used by region-aware snaps
22
+ * (e.g. `containedThenNearest`). When present, a pointer inside this rect
23
+ * is treated as a containment hit on this target. Strategies that emit
24
+ * region-shaped targets (gutters, drop-zones) should populate this.
25
+ * Strategies whose targets are point-like (free-form, snap-point) can omit
26
+ * it and rely on `origin`-distance snaps. */
27
+ hitBounds?: {
28
+ x: number;
29
+ y: number;
30
+ width: number;
31
+ height: number;
32
+ };
33
+ /** Strategy-private metadata (e.g. cell coords for tile-grid). */
34
+ meta?: unknown;
35
+ }
36
+ interface LayoutSnap<TPose> {
37
+ pickTarget(targets: DropTarget<TPose>[], pointer: {
38
+ x: number;
39
+ y: number;
40
+ }): DropTarget<TPose> | null;
41
+ }
42
+ interface LayoutContainer {
43
+ id: string;
44
+ bounds: ContainerBounds;
45
+ }
46
+ interface LayoutDragged<TPose> {
47
+ id: string;
48
+ /** The pose the dragged child currently has (pre-drop). */
49
+ originPose: TPose;
50
+ /** The pose the gesture proposes (pointer-driven, pre-snap). */
51
+ pose: TPose;
52
+ sourceContainerId: string | null;
53
+ }
54
+ interface LayoutStrategy<TPose> {
55
+ childPoses(container: LayoutContainer, children: ReadonlyArray<LayoutChild<TPose>>): Map<string, TPose>;
56
+ getDropTargets(container: LayoutContainer, children: ReadonlyArray<LayoutChild<TPose>>, dragged: LayoutDragged<TPose>): DropTarget<TPose>[];
57
+ reflowPoses(container: LayoutContainer, children: ReadonlyArray<LayoutChild<TPose>>, dragged: LayoutDragged<TPose>, target: DropTarget<TPose> | null): Map<string, TPose>;
58
+ commitDrop(container: LayoutContainer, children: ReadonlyArray<LayoutChild<TPose>>, dragged: LayoutDragged<TPose>, target: DropTarget<TPose> | null): Op[];
59
+ snap: LayoutSnap<TPose>;
60
+ /** Optional: predicate for whether a world-space point is inside this
61
+ * container. When absent, callers fall back to an axis-aligned bounding-box
62
+ * test on the container's pose. Strategies whose containers aren't
63
+ * rectangular (circles, irregular zones) implement this to override the
64
+ * AABB default. */
65
+ contains?(containerPose: TPose, point: {
66
+ x: number;
67
+ y: number;
68
+ }): boolean;
69
+ }
70
+
71
+ /**
72
+ * Opaque clipboard payload. `items` is `unknown[]` so each app's clipboard
73
+ * adapter stores whatever shape it wants; the kit never inspects entries.
74
+ *
75
+ * The adapter is responsible for both producing snapshots
76
+ * (`snapshotSelection`) and consuming them (`commitPaste`). Type safety lives
77
+ * at that boundary, not in the kit.
78
+ */
79
+ interface ClipboardSnapshot {
80
+ items: unknown[];
81
+ }
82
+ /**
83
+ * SnapTarget — where a dragged node would re-parent to if released.
84
+ *
85
+ * `slotPose` is the pose (in world coordinates) the node should snap to
86
+ * within the target. `metadata` is an opaque pass-through for app-specific
87
+ * snap details (slot index, visual hint, etc.).
88
+ */
89
+ interface SnapTarget<TPose = unknown> {
90
+ parentId: string;
91
+ slotPose: TPose;
92
+ metadata?: unknown;
93
+ }
94
+ /**
95
+ * Full scene adapter. Most consumers implement narrow per-hook subsets
96
+ * (MoveAdapter, ResizeAdapter, ClipboardAdapter, ...) — TypeScript's
97
+ * structural typing means a wider adapter satisfies any narrower interface.
98
+ *
99
+ * **Pose semantics:** `getPose` / `setPose` work in **local** coordinates —
100
+ * relative to the node's direct parent (or world, for root-parented nodes).
101
+ * The kit composes world poses via `composeWorldPose` when it needs to
102
+ * render, hit-test, or snap. For the common axis-aligned rect pose,
103
+ * `composeRectPose` / `decomposeRectPose` ship as the canonical compose pair.
104
+ */
105
+ interface SceneAdapter<TNode extends {
106
+ id: string;
107
+ }, TPose> {
108
+ getNodes(): TNode[];
109
+ getNode(id: string): TNode | undefined;
110
+ getSelection(): string[];
111
+ hitTest(worldX: number, worldY: number): string | null;
112
+ getPose(id: string): TPose;
113
+ getParent(id: string): string | null;
114
+ setPose(id: string, pose: TPose): void;
115
+ setParent(id: string, parentId: string | null): void;
116
+ insertNode(node: TNode): void;
117
+ removeNode(id: string): void;
118
+ setSelection(ids: string[]): void;
119
+ applyOps?(ops: Op[], label?: string): void;
120
+ }
121
+ /**
122
+ * Narrow adapter for `useMove`. Includes optional snap-target
123
+ * lookup; apps without container-snapping leave it out.
124
+ */
125
+ interface MoveAdapter<TNode extends {
126
+ id: string;
127
+ }, TPose> {
128
+ getNode(id: string): TNode | undefined;
129
+ /** Enumerate all nodes. `<Canvas>` derives a default rect-pose `pickEvery`
130
+ * and the scene-iteration loop from this. */
131
+ getNodes(): TNode[];
132
+ getPose(id: string): TPose;
133
+ /** Optional. Required only by hierarchy-aware paths: layout-pass drop
134
+ * targeting (`getLayout` present), nested-hit collapse
135
+ * (`pickTopMostHit`), and group-pose composition. Flat scenes may omit. */
136
+ getParent?(id: string): string | null;
137
+ setPose(id: string, pose: TPose): void;
138
+ /** Optional. Used only by reparent ops (e.g. drag-into-container drops via
139
+ * layout strategies). Flat scenes that never reparent may omit. */
140
+ setParent?(id: string, parentId: string | null): void;
141
+ /** Optional: see SceneAdapter.applyOps. */
142
+ applyOps?(ops: Op[], label: string): void;
143
+ findSnapTarget?(draggedId: string, worldX: number, worldY: number): SnapTarget<TPose> | null;
144
+ /** Optional: direct children of `id`. When present (alongside the
145
+ * `cascadeWorldPose` option on `useMove`), dragging a node
146
+ * auto-cascades its descendants in the live overlay so structurally-
147
+ * grouped children visually follow the parent during the drag. No
148
+ * additional ops are generated — children's local poses don't change
149
+ * when the parent's local pose moves. */
150
+ getChildren?(id: string): string[];
151
+ /** Optional: layout strategy attached to a container, or null if the
152
+ * container uses absolute positioning (default behavior). When present,
153
+ * `useMove` uses the strategy to compute drop targets, sibling reflow,
154
+ * and the commit op batch when a drag ends over the container. */
155
+ getLayout?(containerId: string): LayoutStrategy<TPose> | null;
156
+ }
157
+ /**
158
+ * Narrow adapter for `useResize`. Mirrors `MoveAdapter`'s shape
159
+ * minus reparenting and snap-target lookup.
160
+ * TPose is constrained to { x, y, width, height } inline to avoid a circular
161
+ * import with interactions/types.ts.
162
+ */
163
+ interface ResizeAdapter<TNode extends {
164
+ id: string;
165
+ }, TPose> {
166
+ getNode(id: string): TNode | undefined;
167
+ getPose(id: string): TPose;
168
+ setPose(id: string, pose: TPose): void;
169
+ /** Optional: see SceneAdapter.applyOps. */
170
+ applyOps?(ops: Op[], label: string): void;
171
+ }
172
+ /**
173
+ * Narrow adapter for `useRotate`. Mirrors `ResizeAdapter`'s shape — rotate
174
+ * mutates pose only and never reparents. TPose is left fully generic so
175
+ * non-rect rotated poses (e.g. a `RotatedPath`) compose without changes.
176
+ */
177
+ interface RotateAdapter<TNode extends {
178
+ id: string;
179
+ }, TPose> {
180
+ getNode(id: string): TNode | undefined;
181
+ getPose(id: string): TPose;
182
+ setPose(id: string, pose: TPose): void;
183
+ /** Optional: see SceneAdapter.applyOps. */
184
+ applyOps?(ops: Op[], label: string): void;
185
+ }
186
+ /**
187
+ * Narrow adapter for `useAreaSelect`. Transient: no checkpoint, no
188
+ * history. The hook calls `applyOps(ops)` instead of `applyOps(ops, label)`.
189
+ */
190
+ /**
191
+ * Narrow adapter for `useAreaSelect`. Transient: no checkpoint, no
192
+ * history. The hook calls `applyOps(ops)` instead of `applyOps(ops, label)`.
193
+ *
194
+ * All fields are **optional** — area-select is opt-in. `useSelectTool` only
195
+ * wires the default marquee behavior when `hitTestArea`, `getSelection`,
196
+ * `setSelection`, and `applyOps` are all present on the adapter; otherwise
197
+ * the gesture short-circuits (empty-space drags do nothing, sub-threshold
198
+ * empty clicks still clear selection via the tool's `onClick` path).
199
+ * Demos that don't need marquee selection can omit these methods entirely.
200
+ */
201
+ interface AreaSelectAdapter {
202
+ /** Returns ids of nodes intersecting the world-space rect. */
203
+ hitTestArea?(rect: {
204
+ x: number;
205
+ y: number;
206
+ width: number;
207
+ height: number;
208
+ }): string[];
209
+ /** Current selection — read by behaviors to compute additive merges. */
210
+ getSelection?(): string[];
211
+ /** Mutator wired by `setSelection` op. */
212
+ setSelection?(ids: string[]): void;
213
+ /** Apply ops without checkpointing or pushing a history entry. The optional
214
+ * `label` parameter is accepted (and ignored by transient implementations)
215
+ * so that this signature is compatible with `MoveAdapter.applyOps`. */
216
+ applyOps?(ops: Op[], label?: string): void;
217
+ }
218
+ /**
219
+ * Hit mode for `LassoSelectAdapter.hitTestLasso`:
220
+ * - 'centers' — bounds center inside polygon.
221
+ * - 'intersect' — bounds intersect polygon (any overlap).
222
+ * - 'enclosed' — bounds fully inside polygon.
223
+ */
224
+ type LassoHitMode = 'centers' | 'intersect' | 'enclosed';
225
+ /**
226
+ * Narrow adapter for `useLassoSelect`. Extends `AreaSelectAdapter` with a
227
+ * polygon hit-test method. Transient — uses `applyOps` like its rectangular
228
+ * sibling. `hitTestLasso` is optional; when omitted, `useLassoTool` skips
229
+ * wiring the default behavior (same opt-in pattern as `hitTestArea`).
230
+ */
231
+ interface LassoSelectAdapter extends AreaSelectAdapter {
232
+ /** Hit-test against a closed polygon. Vertex order may be CW or CCW; the
233
+ * closing edge from last → first is implicit. */
234
+ hitTestLasso?(polygon: ReadonlyArray<{
235
+ x: number;
236
+ y: number;
237
+ }>, mode: LassoHitMode): string[];
238
+ }
239
+ /**
240
+ * Narrow adapter for `useInsert` and `useClipboardOps`. The kit knows
241
+ * nothing about what tool is active or what shape to construct; it asks the
242
+ * adapter to produce node(s) given gesture or paste inputs.
243
+ *
244
+ * Drag-rectangle path: `commitInsert(bounds)` returns one new node or null.
245
+ * Clipboard paste path: `commitPaste(clipboard, offset)` returns the array of
246
+ * newly-materialized nodes (in order). Both empty array and array of
247
+ * length N are valid; the kit wraps each entry in an `InsertOp`.
248
+ *
249
+ * `snapshotSelection(ids)` builds the payload that paste later consumes.
250
+ * `getPasteOffset` is optional; the kit defaults to a fixed grid-cell offset
251
+ * supplied by the consumer (passed to `useClipboardOps` options if needed; see
252
+ * the hook for resolution order).
253
+ */
254
+ interface InsertAdapter<TNode extends {
255
+ id: string;
256
+ }> {
257
+ /** Materialize a new node from drag-rect bounds (drag-to-insert tools).
258
+ * Optional — hooks that don't drive insertion (e.g. `useClone`,
259
+ * read-only clipboard) won't call it, and `sceneToAdapter` only fills
260
+ * it in when `options.commitInsert` is supplied. Hooks that *do* call
261
+ * it (insert tools) document the requirement at their own surface. */
262
+ commitInsert?(bounds: {
263
+ x: number;
264
+ y: number;
265
+ width: number;
266
+ height: number;
267
+ }): TNode | null;
268
+ /** Materialize one or more new nodes from a clipboard snapshot. Optional
269
+ * — required by `useClipboard.paste`, ignored by other consumers. */
270
+ commitPaste?(clipboard: ClipboardSnapshot, offset: {
271
+ dx: number;
272
+ dy: number;
273
+ }, ctx?: {
274
+ dropPoint?: {
275
+ worldX: number;
276
+ worldY: number;
277
+ };
278
+ }): TNode[];
279
+ /** Snapshot the current selection into the clipboard payload shape.
280
+ * Optional — required by `useClipboard.copy` / `cut` and `useClone`'s
281
+ * ghost capture, ignored by other consumers. */
282
+ snapshotSelection?(ids: string[]): ClipboardSnapshot;
283
+ getPasteOffset?(clipboard: ClipboardSnapshot): {
284
+ dx: number;
285
+ dy: number;
286
+ };
287
+ /** Mutator wired by `insertNode`-using ops (kit-side InsertOp). */
288
+ insertNode(node: TNode): void;
289
+ /** Mutator wired by `setSelection` ops batched alongside paste. */
290
+ setSelection(ids: string[]): void;
291
+ /** Optional: see SceneAdapter.applyOps. */
292
+ applyOps?(ops: Op[], label: string): void;
293
+ /** Returns the current selection. Used by clone behaviors. */
294
+ getSelection(): string[];
295
+ }
296
+ /**
297
+ * Optional surface that lets `buildSceneTree` walk the adapter by layer.
298
+ * Adapters that don't implement this fall back to flat rendering in Canvas's
299
+ * scene layer.
300
+ */
301
+ interface LayerEnumerableAdapter<TLayer extends string = string> {
302
+ getLayers?(): readonly {
303
+ id: TLayer;
304
+ visible: boolean;
305
+ }[];
306
+ }
307
+ /**
308
+ * Optional adapter mixin for sibling z-order.
309
+ *
310
+ * Both methods are optional. Reorder ops and `useReorder` no-op when
311
+ * either is absent — adopt z-order incrementally without breaking existing
312
+ * adapters.
313
+ *
314
+ * **Convention:** array order IS z-order. Index 0 is the bottom of the
315
+ * stack, the last index is the top. Hit-testing should iterate the returned
316
+ * list in REVERSE (top to bottom). Render layers iterate FORWARD (bottom to
317
+ * top).
318
+ *
319
+ * For groups, `parentId` may be a group id; the group adapter routes
320
+ * `getChildren`/`setChildOrder` to the group's `members[]` array.
321
+ */
322
+ interface OrderedAdapter {
323
+ /** Ordered children of `parentId` (or root siblings if null), in z-order:
324
+ * index 0 is bottom, last index is top. */
325
+ getChildren?(parentId: string | null): string[];
326
+ /** Rewrite the order of `parentId`'s children. Length and contents must
327
+ * match the existing children — reorder only, no add/remove. */
328
+ setChildOrder?(parentId: string | null, ids: string[]): void;
329
+ }
330
+
331
+ export type { AreaSelectAdapter as A, ClipboardSnapshot as C, DropTarget as D, InsertAdapter as I, LayoutStrategy as L, MoveAdapter as M, OrderedAdapter as O, RotateAdapter as R, SnapTarget as S, LassoHitMode as a, LassoSelectAdapter as b, ResizeAdapter as c, SceneAdapter as d, LayerEnumerableAdapter as e, LayoutSnap as f, ContainerBounds as g, LayoutChild as h, LayoutContainer as i, LayoutDragged as j };