@weasel-js/diagram 1.13.0 → 1.14.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 (35) hide show
  1. package/README.md +122 -17
  2. package/dist/{chunk-Y72FK3Y7.js → chunk-5VNPLOIX.js} +94 -6
  3. package/dist/chunk-5VNPLOIX.js.map +1 -0
  4. package/dist/{chunk-ESFIS7BB.js → chunk-62SMY45E.js} +918 -574
  5. package/dist/chunk-62SMY45E.js.map +1 -0
  6. package/dist/{chunk-FAQXYGMX.js → chunk-TBG6DFB2.js} +3 -3
  7. package/dist/{chunk-FAQXYGMX.js.map → chunk-TBG6DFB2.js.map} +1 -1
  8. package/dist/{chunk-L4H444QI.js → chunk-VB6HUKNG.js} +659 -185
  9. package/dist/chunk-VB6HUKNG.js.map +1 -0
  10. package/dist/{chunk-QU4QZUC6.js → chunk-ZWXM5F4I.js} +141 -39
  11. package/dist/chunk-ZWXM5F4I.js.map +1 -0
  12. package/dist/{dataTypes-DW-MljuN.d.ts → dataTypes-BIkhAOc4.d.ts} +13 -2
  13. package/dist/effect-audio.d.ts +2 -1
  14. package/dist/effect-audio.js +6 -5
  15. package/dist/effect-audio.js.map +1 -1
  16. package/dist/effect.d.ts +46 -16
  17. package/dist/effect.js +257 -102
  18. package/dist/effect.js.map +1 -1
  19. package/dist/icons.table.js +262 -0
  20. package/dist/icons.table.js.map +1 -1
  21. package/dist/icons.table.json +262 -0
  22. package/dist/index.d.ts +491 -167
  23. package/dist/index.js +586 -36
  24. package/dist/index.js.map +1 -1
  25. package/dist/labelTrait-BBjRgxbz.d.ts +44 -0
  26. package/dist/layout.d.ts +4 -3
  27. package/dist/{layout.entry-CQoPNfzA.d.ts → layout.entry-Ca6pVvqo.d.ts} +23 -2
  28. package/dist/layout.js +2 -2
  29. package/dist/{stageTypes-DvnR8cKQ.d.ts → stageTypes-UiO25hcn.d.ts} +7 -0
  30. package/dist/{types-vbW21fHm.d.ts → types-B0n2CNTW.d.ts} +108 -81
  31. package/package.json +11 -9
  32. package/dist/chunk-ESFIS7BB.js.map +0 -1
  33. package/dist/chunk-L4H444QI.js.map +0 -1
  34. package/dist/chunk-QU4QZUC6.js.map +0 -1
  35. package/dist/chunk-Y72FK3Y7.js.map +0 -1
@@ -1,11 +1,13 @@
1
- import { createAvoidRouter, placeLabels, edgeHops, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, simplifyStops } from './chunk-Y72FK3Y7.js';
2
- import { edgeRouter, registerMarkShape, withDiagramRegistry, diagramLabelOf, editEdgeLabelBinding, editEdgeLabelAction, diagramGroupOf, diagramContainerOf, headerBox, labelFollowsLayout, buildGraph, LABEL_DRAG_AFFORDANCE_KIND, EDIT_EDGE_LABEL_ACTION_ID, labelDragLayer, laneOutlineOf, routerOf, labelScratchOf, ROUTERS, avoid, LABEL_PLACEMENT, editableLabels, titleIdOf, orthogonal, diagramAnchorOf, MIN_LANE_SIZE, endAims, resolveEnd, EDGE_DERIVE_PATH, titlePose, regionSpecs, DIAGRAM_THEME_KEY, diagramThemeOf, boxCenter, themeLabelFamily, roleEdgeStyle, roleStyle, themeLabelFont, firstLanes, DEFAULT_LANE_SIZE, bodyBox } from './chunk-QU4QZUC6.js';
3
- import { diagramEdgeOf, isPromise, dataKeyReader, diagramNodeOf, portsOf, portSitesOf, outlinePath, samePoints, layoutWritesRoute, plannerPlan, planOf, layered, forceRelaxation, center, layoutOwnsPort, chain, force, tree, portOf, labelCenter, labelSpotAt, isPinned, layoutOwnsRoute } from './chunk-L4H444QI.js';
4
- import { bodyPredicate, dragPanContribution, WeaselProvider, useScene, useSelection, useLatest, SceneCanvas, useDepSource, registerNodeShape, reconcileSpecs, nodeGates, effectivePose, pagesBounds, pagesLayer, AUTO_POSE_DESCRIPTOR, usePoseRun, drawnBoundsScene, pointAlongPath, drawnAABBOf, RECT_POSE_DESCRIPTOR, resolveFill, resolveStroke, commandFill, commandStroke, fitViewToBounds, translatePoseViaDescriptor, composeAffordanceLayer, createResizeAction, createDeleteAction, polylineFromPoints, SNAP_ROLES, ActionDisabledReason, paintsLayer, viewToTransform, ellipsePath, snapMods, documentDepOf, carriedDescendants, sceneCarrySource, derivedDepOf, PathBuilder, createInsertOp, createSetDataOp, documentPose } from '@weasel-js/core';
1
+ import { createAvoidRouter, placeLabels, edgeHops, radial, DEFAULT_HOP_SIZE, HOPS_DOC_KEY, simplifyStops } from './chunk-5VNPLOIX.js';
2
+ import { edgeRouter, registerMarkShape, withDiagramRegistry, diagramLabelOf, editEdgeLabelBinding, editEdgeLabelAction, diagramGroupOf, diagramContainerOf, headerBox, labelFollowsLayout, buildGraph, LABEL_DRAG_AFFORDANCE_KIND, EDIT_EDGE_LABEL_ACTION_ID, labelDragLayer, laneOutlineOf, recordedRows, keyedIndex, boxIndex, boxesMeeting, routerOf, labelScratchOf, ROUTERS, avoid, LABEL_PLACEMENT, editableLabels, titleIdOf, orthogonal, diagramAnchorOf, MIN_LANE_SIZE, EDGE_DERIVE_PATH, titleInFrame, regionSpecs, DIAGRAM_THEME_KEY, diagramThemeOf, endAims, resolveEnd, themeLabelFamily, bodyBox, boxCenter, roleEdgeStyle, roleStyle, themeLabelFont, firstLanes, DEFAULT_LANE_SIZE } from './chunk-ZWXM5F4I.js';
3
+ import { diagramEdgeOf, isPromise, diagramNodeOf, portsOf, portSitesOf, outlinePath, outlineDetail, samePoints, layoutWritesRoute, plannerPlan, planOf, layered, dataKeyReader, layoutBody, forceRelaxation, center, layoutOwnsPort, chain, force, tree, portOf, labelCenter, labelSpotAt, isPinned, layoutOwnsRoute } from './chunk-VB6HUKNG.js';
4
+ import { bodyPredicate, dragPanContribution, WeaselProvider, useScene, useSelection, useLatest, SceneCanvas, useDepSource, RIGID_POSE_COMPOSITION, registerNodeShape, reconcileSpecs, pagesBounds, pagesLayer, AUTO_POSE_DESCRIPTOR, usePoseRun, drawnBoundsScene, pointAlongPath, scenePoseAdapter, drawnAABBOf, composeWorldPose, worldPosesOf, RECT_POSE_DESCRIPTOR, resolveFill, resolveStroke, commandFill, commandStroke, nodeGates, scenePoseFrame, fitViewToBounds, clampView, rebaseLocalPose, translatePoseViaDescriptor, carriedDescendants, sceneCarrySource, composeAffordanceLayer, createResizeAction, createDeleteAction, effectivePose, polylineFromPoints, SNAP_ROLES, ActionDisabledReason, refusalOf, snapMods, documentDepOf, definesFrame, paintsLayer, viewToTransform, ellipsePath, derivedDepOf, localizeWorldPoses, PathBuilder, startCarry, createInsertOp, createSetDataOp, documentPose } from '@weasel-js/core';
5
+ import { createSettledCache } from '@weasel-js/geom/nd';
5
6
  import { AUTO_POSE_DESCRIPTOR as AUTO_POSE_DESCRIPTOR$1, rotatePoint } from '@weasel-js/core/math';
6
7
  import { clampRectWithin, placeRect, pathContainsPoint } from '@weasel-js/geom';
7
- import { useLatest as useLatest$1, adoptCssOnce } from '@weasel-js/react';
8
+ import { nudgeGap, moveItems, nearestGap, isNoopDrop } from '@weasel-js/headless';
8
9
  import { forwardRef, useMemo, useEffect, useState, useRef, useCallback, useImperativeHandle, useLayoutEffect } from 'react';
10
+ import { useLatest as useLatest$1, adoptCssOnce } from '@weasel-js/react';
9
11
  import '@weasel-js/animator';
10
12
  import { jsx, jsxs } from 'react/jsx-runtime';
11
13
 
@@ -50,34 +52,69 @@ function createPortAffordance(participants, opts = {}) {
50
52
  }
51
53
  };
52
54
  };
55
+ const regionOf = (node, port) => ({
56
+ id: `${node.id}:${port.id}`,
57
+ targetId: null,
58
+ shape: { kind: "point", x: port.point.x, y: port.point.y, hitRadiusPx },
59
+ ...withPaint(paintOf2(port)),
60
+ ...opts.cursor !== void 0 ? { cursor: opts.cursor } : {},
61
+ strength,
62
+ claimedKinds: ["pointer"],
63
+ bind: () => ({
64
+ initialScratch: {
65
+ targetId: node.id,
66
+ nodeId: node.id,
67
+ portId: port.id,
68
+ port
69
+ }
70
+ })
71
+ });
72
+ const shown = (participant, state) => offersPorts(participant, state) && (opts.shows === void 0 || opts.shows(participant.node, state));
73
+ const showsPort = (port) => opts.showsPort === void 0 || opts.showsPort(port);
74
+ const generation = participants.generation;
75
+ const allPorts = () => {
76
+ const at = [];
77
+ for (const participant of participants()) {
78
+ for (const port of portsOf(participant.node, participant.pose, portOpts)) at.push({ participant, port });
79
+ }
80
+ return at;
81
+ };
82
+ const held = createSettledCache({ reads: 1 });
83
+ const portsAt = (key) => held.read(key, allPorts) ?? allPorts();
84
+ const regionAt = (entry) => entry.region ??= regionOf(entry.participant.node, entry.port);
85
+ const index = keyedIndex(generation ?? (() => void 0), () => {
86
+ const at = portsAt(generation());
87
+ return { at, boxes: boxIndex(at.map(({ port: { point: p } }) => [p.x, p.y, p.x, p.y])) };
88
+ });
89
+ const regions = (state) => {
90
+ const out = [];
91
+ if (generation !== void 0) {
92
+ for (const entry of portsAt(generation())) {
93
+ if (shown(entry.participant, state) && showsPort(entry.port)) out.push(regionAt(entry));
94
+ }
95
+ return out;
96
+ }
97
+ for (const participant of participants()) {
98
+ if (!shown(participant, state)) continue;
99
+ for (const port of portsOf(participant.node, participant.pose, portOpts)) {
100
+ if (showsPort(port)) out.push(regionOf(participant.node, port));
101
+ }
102
+ }
103
+ return out;
104
+ };
53
105
  return {
54
106
  id,
55
- regions(state) {
107
+ regions,
108
+ regionsAt(state, wx, wy, view) {
109
+ const built = index();
110
+ const rx = hitRadiusPx / Math.abs(view.scale.x);
111
+ const ry = hitRadiusPx / Math.abs(view.scale.y);
112
+ const near2 = built && boxesMeeting(built.boxes, wx - rx, wy - ry, wx + rx, wy + ry);
113
+ if (!built || !near2) return regions(state);
56
114
  const out = [];
57
- for (const participant of participants()) {
58
- if (!offersPorts(participant, state)) continue;
59
- const { node, pose } = participant;
60
- if (opts.shows !== void 0 && !opts.shows(node, state)) continue;
61
- for (const port of portsOf(node, pose, portOpts)) {
62
- if (opts.showsPort !== void 0 && !opts.showsPort(port)) continue;
63
- out.push({
64
- id: `${node.id}:${port.id}`,
65
- targetId: null,
66
- shape: { kind: "point", x: port.point.x, y: port.point.y, hitRadiusPx },
67
- ...withPaint(paintOf2(port)),
68
- ...opts.cursor !== void 0 ? { cursor: opts.cursor } : {},
69
- strength,
70
- claimedKinds: ["pointer"],
71
- bind: () => ({
72
- initialScratch: {
73
- targetId: node.id,
74
- nodeId: node.id,
75
- portId: port.id,
76
- port
77
- }
78
- })
79
- });
80
- }
115
+ for (const i of near2) {
116
+ const entry = built.at[i];
117
+ if (shown(entry.participant, state) && showsPort(entry.port)) out.push(regionAt(entry));
81
118
  }
82
119
  return out;
83
120
  }
@@ -104,7 +141,28 @@ function bodyAt(participants, at, opts = {}) {
104
141
  }
105
142
  return hit;
106
143
  }
144
+ function refusalMarks(box, at, reason) {
145
+ const out = [];
146
+ if (box !== null) {
147
+ const { x, y, width, height } = box;
148
+ out.push({ kind: "polyline", points: [{ x, y }, { x: x + width, y }, { x: x + width, y: y + height }, { x, y: y + height }, { x, y }], role: "refused" });
149
+ }
150
+ out.push({ kind: "reason", at: { x: at.x, y: at.y }, text: reason });
151
+ return out;
152
+ }
107
153
  function createTargets(opts) {
154
+ const resolver = createResolver(opts);
155
+ const { landing, preview, boxOf } = resolver;
156
+ function overlays(route, fixed, at, view, moving = "to", waypoints = []) {
157
+ const points = preview(route, fixed, at, view, moving, waypoints);
158
+ const hit = landing(fixed, at, view);
159
+ const run = points.length < 2 ? [] : [{ kind: "polyline", points, role: hit?.refuse != null ? "refused" : "connector" }];
160
+ if (hit === null || hit.refuse === null) return run;
161
+ return [...run, ...refusalMarks(boxOf(hit.end.nodeId), at, hit.refuse)];
162
+ }
163
+ return { ...resolver, overlays };
164
+ }
165
+ function createResolver(opts) {
108
166
  const portOpts = {
109
167
  ...opts.geometry ? { geometry: opts.geometry } : {},
110
168
  ...opts.read ? { read: opts.read } : {}
@@ -117,22 +175,27 @@ function createTargets(opts) {
117
175
  if (!offersPorts(participant, view)) continue;
118
176
  for (const port of portsOf(participant.node, participant.pose, portOpts)) {
119
177
  if (opts.showsPort !== void 0 && !opts.showsPort(port)) continue;
120
- if (!opts.canConnect(from, port)) continue;
121
178
  const d2 = (port.point.x - at.x) ** 2 + (port.point.y - at.y) ** 2;
122
- if (d2 <= bestD2) {
123
- bestD2 = d2;
124
- best = port;
125
- }
179
+ if (d2 > bestD2) continue;
180
+ const verdict = opts.canConnect(from, port);
181
+ if (verdict === false) continue;
182
+ bestD2 = d2;
183
+ best = { end: port, refuse: refusalOf(verdict) };
126
184
  }
127
185
  }
128
186
  return best;
129
187
  }
130
- function target(from, at, view) {
188
+ function landing(from, at, view) {
131
189
  const port = portTarget(from, at, view);
132
190
  if (port !== null || !opts.bodies) return port;
133
191
  const body = bodyAt(opts.participants, at, { ...portOpts, view });
134
192
  if (body === null || portsOf(body.participant.node, body.participant.pose, portOpts).length === 0) return null;
135
- return opts.canConnect(from, body.end) ? body.end : null;
193
+ const verdict = opts.canConnect(from, body.end);
194
+ return verdict === false ? null : { end: body.end, refuse: refusalOf(verdict) };
195
+ }
196
+ function target(from, at, view) {
197
+ const hit = landing(from, at, view);
198
+ return hit === null || hit.refuse !== null ? null : hit.end;
136
199
  }
137
200
  function participantOf(nodeId) {
138
201
  for (const participant of opts.participants()) {
@@ -153,7 +216,7 @@ function createTargets(opts) {
153
216
  return resolveEnd({}, dep, toward2, portOpts, all) ?? null;
154
217
  }
155
218
  function preview(route, fixed, at, view, moving = "to", waypoints = []) {
156
- const landed = target(fixed, at, view);
219
+ const landed = landing(fixed, at, view)?.end ?? null;
157
220
  const [fixedCenter, landedCenter] = [centerOf(fixed), landed === null ? at : centerOf(landed)];
158
221
  const aims = moving === "to" ? endAims(fixedCenter, landedCenter, waypoints) : endAims(landedCenter, fixedCenter, waypoints);
159
222
  const [fixedAim, landedAim] = moving === "to" ? [aims.from, aims.to] : [aims.to, aims.from];
@@ -162,7 +225,11 @@ function createTargets(opts) {
162
225
  if (free === null || anchored === null) return [];
163
226
  return moving === "to" ? route({ from: anchored, to: free, waypoints }) : route({ from: free, to: anchored, waypoints });
164
227
  }
165
- return { target, portFor, preview };
228
+ function boxOf(nodeId) {
229
+ const participant = participantOf(nodeId);
230
+ return participant === void 0 ? null : geometry.getBounds(participant.pose);
231
+ }
232
+ return { target, landing, portFor, preview, boxOf };
166
233
  }
167
234
  var CONNECT_ACTION_ID = "diagram.connect";
168
235
  var defaultCanConnect = (from, to) => {
@@ -266,66 +333,513 @@ function createConnectAction(opts) {
266
333
  scratch.current = { x: moveCtx.world.x, y: moveCtx.world.y };
267
334
  },
268
335
  overlay() {
269
- if (!scratch.open) return null;
270
- const points = targets.preview(route, scratch.from, scratch.current, scratch.deps.view);
271
- if (points.length < 2) return null;
272
- return { kind: "polyline", points, role: "connector" };
336
+ if (!scratch.open) return null;
337
+ return targets.overlays(route, scratch.from, scratch.current, scratch.deps.view);
338
+ },
339
+ onEnd(endCtx, reason) {
340
+ scratch.open = false;
341
+ if (reason === "cancel") return;
342
+ const to = targets.target(scratch.from, { x: endCtx.world.x, y: endCtx.world.y }, scratch.deps.view);
343
+ if (to === null) return;
344
+ commit(
345
+ { from: scratch.from, to, router: routerKey },
346
+ { ...endCtx, deps: scratch.deps }
347
+ );
348
+ }
349
+ };
350
+ }
351
+ },
352
+ enabled: () => true
353
+ };
354
+ }
355
+
356
+ // src/containers/canDropInto.ts
357
+ function diagramCanDropInto(scene, canReparent) {
358
+ const nodeOf = (id) => scene.get(id);
359
+ const roleOf = (id) => {
360
+ const node = nodeOf(id);
361
+ return node === void 0 ? null : diagramContainerOf(node)?.role ?? null;
362
+ };
363
+ const attached = (id) => {
364
+ const node = nodeOf(id);
365
+ return node !== void 0 && (diagramEdgeOf(node) !== null || diagramLabelOf(node) !== null);
366
+ };
367
+ const allowed = (parent, ids) => {
368
+ const node = nodeOf(parent);
369
+ if (node === void 0 || ids.some(attached)) return false;
370
+ const role = roleOf(parent);
371
+ if (role === "pool") return ids.every((id) => roleOf(id) === "lane");
372
+ if (ids.some((id) => roleOf(id) === "lane")) return false;
373
+ if (role !== null) return ids.every((id) => roleOf(id) !== "pool");
374
+ return !attached(parent) && dataKeyReader(node) === null;
375
+ };
376
+ return (parent, ids) => {
377
+ if (!allowed(parent, ids)) return false;
378
+ if (canReparent === void 0 || ids.every((id) => nodeOf(id)?.parent === parent)) return true;
379
+ return canReparent(ids, parent);
380
+ };
381
+ }
382
+ function diagramDropParentAt(scene, point, role) {
383
+ if (role === "pool" || role === "lane") return null;
384
+ let best = null;
385
+ const compose = scene.composition?.compose;
386
+ const walk = (ids, frame) => {
387
+ for (const id of ids) {
388
+ const node = scene.get(id);
389
+ if (node === void 0) continue;
390
+ const pose = node.pose;
391
+ const world = frame === null || compose === void 0 ? pose : compose(frame, pose);
392
+ const trait = diagramContainerOf(node);
393
+ const b = bodyBox(world, trait?.header);
394
+ const inside2 = point.x >= b.x && point.x < b.x + b.width && point.y >= b.y && point.y < b.y + b.height;
395
+ if (!inside2) continue;
396
+ if (trait?.role === "container" || trait?.role === "lane") best = id;
397
+ walk(scene.childrenOf(id), world);
398
+ }
399
+ };
400
+ walk(scene.roots, null);
401
+ return best;
402
+ }
403
+ function packed(items, spans, order) {
404
+ const gaps = items.slice(1).map((m, i) => spans.get(m).start - (spans.get(items[i]).start + spans.get(items[i]).size));
405
+ const out = /* @__PURE__ */ new Map();
406
+ let at = items.length > 0 ? spans.get(items[0]).start : 0;
407
+ order.forEach((m, i) => {
408
+ out.set(m, at);
409
+ at += spans.get(m).size + (gaps[i] ?? gaps[gaps.length - 1] ?? 0);
410
+ });
411
+ return out;
412
+ }
413
+ var carriedBy = (item) => item.carries ?? [item.id];
414
+ var RELEASE_MS = 500;
415
+ function slideOthers(scene, slots, carried) {
416
+ const { axis } = slots;
417
+ const size = axis === "x" ? "width" : "height";
418
+ const ids = slots.items.map((i) => i.id);
419
+ const spans = new Map(slots.items.map((i) => [i.id, { start: i.bounds[axis], size: i.bounds[size] }]));
420
+ const nodes = slots.items.map((item) => ({
421
+ id: item.id,
422
+ poses: carriedBy(item).flatMap((id) => {
423
+ const node = scene.get(id);
424
+ return node === void 0 || node.derivePose !== void 0 ? [] : [{ id, pose: effectivePose(scene, node) }];
425
+ })
426
+ }));
427
+ const hold = scene.overrides.hold();
428
+ return {
429
+ /** The items standing in `order`, or as they were for `null`, with the carried one `by` along. */
430
+ show(order, by) {
431
+ const starts = packed(ids, spans, order ?? ids);
432
+ hold.set(nodes.flatMap(({ id, poses }) => {
433
+ const d = id === carried ? by : starts.get(id) - spans.get(id).start;
434
+ return poses.map(({ id: node, pose }) => [node, { ...pose, [axis]: pose[axis] + d }]);
435
+ }));
436
+ },
437
+ drop: () => hold.drop(),
438
+ /** Held until the host's new specs land, so the items do not jump back for
439
+ * the frames in between; a host that keeps the old order gets it back shortly after. */
440
+ keep() {
441
+ const release = () => {
442
+ stop();
443
+ clearTimeout(timer);
444
+ hold.drop();
445
+ };
446
+ const stop = scene.subscribe(release);
447
+ const timer = setTimeout(release, RELEASE_MS);
448
+ }
449
+ };
450
+ }
451
+
452
+ // src/reorder.ts
453
+ var REORDER_ACTION_ID = "diagram.reorder";
454
+ var END_GAP = 24;
455
+ var inside = (p, b) => p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;
456
+ function sequenceSlots(axis, items) {
457
+ const [along2, across, size, depth] = axis === "x" ? ["x", "y", "width", "height"] : ["y", "x", "height", "width"];
458
+ const lo = (b) => b[along2];
459
+ const hi = (b) => b[along2] + b[size];
460
+ const bar = (at, boxes2) => {
461
+ const from = Math.min(...boxes2.map((b) => b[across]));
462
+ const to = Math.max(...boxes2.map((b) => b[across] + b[depth]));
463
+ const point = (c) => axis === "x" ? { x: at, y: c } : { x: c, y: at };
464
+ return { a: point(from), b: point(to) };
465
+ };
466
+ const boxes = items.map((i) => i.bounds);
467
+ const halves = boxes.slice(1).map((b, k) => (lo(b) - hi(boxes[k])) / 2);
468
+ const gaps = [];
469
+ if (boxes.length === 0) return { axis, items, gaps };
470
+ gaps.push({ index: 0, ...bar(lo(boxes[0]) - (halves[0] ?? END_GAP / 2), [boxes[0]]) });
471
+ for (let k = 1; k < boxes.length; k++) gaps.push({ index: k, ...bar(hi(boxes[k - 1]) + halves[k - 1], [boxes[k - 1], boxes[k]]) });
472
+ const last = boxes[boxes.length - 1];
473
+ gaps.push({ index: boxes.length, ...bar(hi(last) + (halves[halves.length - 1] ?? END_GAP / 2), [last]) });
474
+ return { axis, items, gaps };
475
+ }
476
+ function pickAt(slots, at) {
477
+ const from = slots?.items.findIndex((i) => i.grip !== null && inside(at, i.grip ?? i.bounds)) ?? -1;
478
+ return from < 0 ? null : { from, item: slots.items[from] };
479
+ }
480
+ function gapAt(held, by) {
481
+ const { axis, gaps } = held.slots;
482
+ const size = axis === "x" ? "width" : "height";
483
+ const mid = held.item.bounds[axis] + held.item.bounds[size] / 2 + by;
484
+ const best = gaps[nearestGap(gaps.map((g) => g.a[axis]), mid)];
485
+ return best === void 0 || isNoopDrop([held.from], best.index) ? null : best;
486
+ }
487
+ function moveOf(held, gap) {
488
+ const order = moveItems(held.slots.items.map((i) => i.id), [held.from], gap.index);
489
+ return { id: held.item.id, from: held.from, to: gap.index, order };
490
+ }
491
+ function createReorderAction(opts) {
492
+ const { canDrop = () => true, show = "bar" } = opts;
493
+ return {
494
+ id: opts.id ?? REORDER_ACTION_ID,
495
+ label: opts.label ?? "Reorder",
496
+ group: "diagram",
497
+ requires: ["scene", ...opts.requires ?? []],
498
+ cursor: "grab",
499
+ activeCursor: "grabbing",
500
+ enabled: (deps, at) => deps === void 0 || at === void 0 || pickAt(opts.slots(deps, at), at) !== null ? true : ActionDisabledReason.NotApplicable,
501
+ invoker: {
502
+ timing: "ongoing",
503
+ start(ctx) {
504
+ const start = { x: (ctx.drag?.start ?? ctx.world).x, y: (ctx.drag?.start ?? ctx.world).y };
505
+ const slots = opts.slots(ctx.deps, start);
506
+ const picked = pickAt(slots, start);
507
+ if (slots === null || picked === null) return {};
508
+ const held = { slots, ...picked };
509
+ const { axis } = slots;
510
+ const region = opts.region?.(ctx.deps, held.item) ?? null;
511
+ const leaves = (at) => region !== null && !inside(at, region);
512
+ let by = ctx.world[axis] - start[axis];
513
+ let open = true;
514
+ const verdicts = /* @__PURE__ */ new Map();
515
+ const landing = (gap) => {
516
+ if (gap === null) return null;
517
+ if (!verdicts.has(gap.index)) {
518
+ const move = moveOf(held, gap);
519
+ verdicts.set(gap.index, canDrop(move) ? move : null);
520
+ }
521
+ return verdicts.get(gap.index);
522
+ };
523
+ const finish = (endCtx, reason) => {
524
+ open = false;
525
+ by = endCtx.world[axis] - start[axis];
526
+ const move = reason === "commit" ? landing(gapAt(held, by)) : null;
527
+ if (move !== null) opts.commit(move, { ...endCtx, deps: ctx.deps });
528
+ return move;
529
+ };
530
+ if (show === "slide") {
531
+ const slide = ctx.deps.scene === void 0 ? null : slideOthers(ctx.deps.scene, held.slots, held.item.id);
532
+ return {
533
+ kind: "diagram-reorder",
534
+ onMove(moveCtx) {
535
+ if (leaves(moveCtx.world)) return "pass";
536
+ by = moveCtx.world[axis] - start[axis];
537
+ slide?.show(landing(gapAt(held, by))?.order ?? null, by);
538
+ },
539
+ onEnd(endCtx, reason) {
540
+ const move = finish(endCtx, reason);
541
+ if (move === null) slide?.drop();
542
+ else slide?.keep();
543
+ }
544
+ };
545
+ }
546
+ const carried = carriedBy(held.item);
547
+ const poses = /* @__PURE__ */ new Map();
548
+ for (const id of carried) {
549
+ const pose = ctx.deps.scene?.get(id)?.pose;
550
+ if (pose !== void 0) poses.set(id, pose);
551
+ }
552
+ return {
553
+ kind: "diagram-reorder",
554
+ onMove(moveCtx) {
555
+ if (leaves(moveCtx.world)) return "pass";
556
+ by = moveCtx.world[axis] - start[axis];
557
+ },
558
+ previewIds: () => open && poses.size > 0 ? [...poses.keys()] : null,
559
+ previewPose: (id) => {
560
+ const pose = poses.get(id);
561
+ return pose === void 0 ? null : { ...pose, [axis]: pose[axis] + by };
562
+ },
563
+ previewOpaqueIds: () => [...carried],
564
+ overlay() {
565
+ const gap = open ? gapAt(held, by) : null;
566
+ if (gap === null) return null;
567
+ return { kind: "polyline", points: [gap.a, gap.b], role: landing(gap) !== null ? "insert" : "refused" };
568
+ },
569
+ onEnd(endCtx, reason) {
570
+ finish(endCtx, reason);
571
+ }
572
+ };
573
+ }
574
+ }
575
+ };
576
+ }
577
+ var ANYWHERE = bodyPredicate(() => true);
578
+ function reorderBinding(actionId = REORDER_ACTION_ID, on = ANYWHERE) {
579
+ return { spec: { kind: "drag", target: { kindOf: on } }, actionId, opts: { id: on === ANYWHERE ? `${actionId}.drag` : `${actionId}.bodyDrag` } };
580
+ }
581
+ function reorderContribution(opts) {
582
+ const actionId = opts.id ?? REORDER_ACTION_ID;
583
+ return {
584
+ id: `weasel-diagram-reorder:${actionId}`,
585
+ eligibility: { always: true },
586
+ actions: [createReorderAction({ ...opts, id: actionId })],
587
+ bindings: [reorderBinding(actionId, opts.on)]
588
+ };
589
+ }
590
+ function worldRectOf(scene, id) {
591
+ const node = scene.get(id);
592
+ if (node === void 0) return null;
593
+ const drawn = drawnBoundsScene(scene);
594
+ const route = diagramEdgeOf(node) === null ? null : drawn.derivedPathOf?.(id) ?? null;
595
+ const mid = route === null ? null : pointAlongPath(route, 0.5);
596
+ if (mid != null) return { x: mid.point.x, y: mid.point.y, width: 0, height: 0 };
597
+ const live = { ...scenePoseAdapter(scene), getPose: (at) => effectivePose(scene, scene.get(at)) };
598
+ return drawnAABBOf(drawn, id, composeWorldPose(live, id, scene.composition.compose), { includeStroke: false });
599
+ }
600
+ function screenRectOf(rect, view) {
601
+ return {
602
+ x: (rect.x - view.x) * view.scale.x,
603
+ y: (rect.y - view.y) * view.scale.y,
604
+ width: rect.width * view.scale.x,
605
+ height: rect.height * view.scale.y
606
+ };
607
+ }
608
+ var CENTER = "center";
609
+ function place(el, overlay, anchor, view) {
610
+ const size = { width: el.offsetWidth, height: el.offsetHeight };
611
+ const placement = overlay.placement ?? CENTER;
612
+ const at = placement === CENTER ? { x: anchor.x + (anchor.width - size.width) / 2, y: anchor.y + (anchor.height - size.height) / 2 } : clampRectWithin(placeRect({ anchor, overlay: size, boundary: view, placement, offset: overlay.offset ?? 0 }).rect, view);
613
+ el.style.transform = `translate(${Math.round(at.x)}px, ${Math.round(at.y)}px)`;
614
+ }
615
+ function useOverlayPlacement(canvasRef, scene, overlays) {
616
+ const elements = useRef(/* @__PURE__ */ new Map());
617
+ const current = useLatest$1(overlays);
618
+ const placeAll = useCallback(() => {
619
+ const canvas = canvasRef.current;
620
+ const surface = canvas?.element;
621
+ if (canvas == null || surface == null) return;
622
+ const view = canvas.getView();
623
+ for (const overlay of current.current) {
624
+ const el = elements.current.get(overlay.key ?? overlay.target);
625
+ if (el === void 0) continue;
626
+ const world = worldRectOf(scene, overlay.target);
627
+ el.hidden = world === null;
628
+ if (world === null) continue;
629
+ const rect = screenRectOf(world, view);
630
+ const anchor = { ...rect, x: rect.x + surface.offsetLeft, y: rect.y + surface.offsetTop };
631
+ place(el, overlay, anchor, {
632
+ x: surface.offsetLeft,
633
+ y: surface.offsetTop,
634
+ width: surface.offsetWidth,
635
+ height: surface.offsetHeight
636
+ });
637
+ }
638
+ }, [canvasRef, scene, current]);
639
+ useLayoutEffect(() => {
640
+ placeAll();
641
+ const canvas = canvasRef.current;
642
+ if (canvas == null) return;
643
+ const stop = canvas.subscribeFrame(placeAll);
644
+ const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(placeAll);
645
+ for (const el of elements.current.values()) observer?.observe(el);
646
+ return () => {
647
+ stop();
648
+ observer?.disconnect();
649
+ };
650
+ }, [canvasRef, placeAll, overlays]);
651
+ const refs = useRef(/* @__PURE__ */ new Map());
652
+ return useCallback((key) => {
653
+ let ref = refs.current.get(key);
654
+ if (ref === void 0) {
655
+ ref = (el) => {
656
+ if (el !== null) {
657
+ elements.current.set(key, el);
658
+ return;
659
+ }
660
+ elements.current.delete(key);
661
+ refs.current.delete(key);
662
+ };
663
+ refs.current.set(key, ref);
664
+ }
665
+ return ref;
666
+ }, []);
667
+ }
668
+
669
+ // src/reorderModel.ts
670
+ var depsOf = (node) => Array.isArray(node?.dependsOn) ? node.dependsOn : [];
671
+ function holders(scene) {
672
+ const out = /* @__PURE__ */ new Map();
673
+ for (const node of scene.renderOrderNodes()) {
674
+ if (diagramGroupOf(node) === null) continue;
675
+ for (const dep of depsOf(node)) {
676
+ const member = scene.get(dep);
677
+ if (member !== void 0 && diagramLabelOf(member) === null) out.set(dep, node.id);
678
+ }
679
+ }
680
+ return out;
681
+ }
682
+ function membersOf(scene, holder) {
683
+ const node = scene.get(holder);
684
+ const ids = node !== void 0 && diagramGroupOf(node) !== null ? depsOf(node) : (scene.childrenOf?.(holder) ?? []).filter((id) => id !== titleIdOf(holder));
685
+ return ids.filter((id) => {
686
+ const member = scene.get(id);
687
+ return member !== void 0 && diagramLabelOf(member) === null && diagramEdgeOf(member) === null;
688
+ });
689
+ }
690
+ function holderOf(scene, held, id) {
691
+ const group = held.get(id);
692
+ if (group !== void 0) return group;
693
+ const parent = scene.get(id)?.parent;
694
+ const node = parent == null ? void 0 : scene.get(parent);
695
+ return node !== void 0 && diagramContainerOf(node)?.role === "container" ? node.id : void 0;
696
+ }
697
+ var axisOf = (node) => diagramGroupOf(node)?.reorder ?? diagramContainerOf(node)?.reorder;
698
+ function reorderTargetOf(scene, id, boxOf) {
699
+ const held = holders(scene);
700
+ for (let member = id, holder = holderOf(scene, held, id); holder !== void 0; member = holder, holder = holderOf(scene, held, holder)) {
701
+ const axis = axisOf(scene.get(holder));
702
+ if (axis === void 0) continue;
703
+ const start = (m) => {
704
+ const box = boxOf(m);
705
+ return box === null ? 0 : axis === "x" ? box.x : box.y;
706
+ };
707
+ const members2 = membersOf(scene, holder).sort((a, b) => start(a) - start(b));
708
+ return { parent: holder, axis, member, members: members2 };
709
+ }
710
+ return null;
711
+ }
712
+ function carriedWith(scene, member) {
713
+ const out = /* @__PURE__ */ new Set();
714
+ const visit = (id) => {
715
+ if (out.has(id)) return;
716
+ out.add(id);
717
+ const node = scene.get(id);
718
+ if (node !== void 0 && diagramGroupOf(node) !== null) depsOf(node).forEach(visit);
719
+ scene.childrenOf?.(id).forEach(visit);
720
+ };
721
+ visit(member);
722
+ for (const node of scene.renderOrderNodes()) {
723
+ const on = depsOf(node)[0];
724
+ if (on !== void 0 && out.has(on) && diagramAnchorOf(node) !== null) out.add(node.id);
725
+ }
726
+ return out;
727
+ }
728
+
729
+ // src/itemDropTarget.ts
730
+ function placeAmong(scene, container, at) {
731
+ const axis = diagramContainerOf(scene.get(container))?.reorder;
732
+ const boxed = membersOf(scene, container).flatMap((id) => {
733
+ const bounds = worldRectOf(scene, id);
734
+ return bounds === null ? [] : [{ id, bounds }];
735
+ });
736
+ if (axis === void 0) {
737
+ const before = (b) => at.y > b.y + b.height || at.y >= b.y && at.x > b.x + b.width / 2;
738
+ return { index: boxed.filter((m) => before(m.bounds)).length, gap: null };
739
+ }
740
+ const slots = sequenceSlots(axis, [...boxed].sort((p, q) => p.bounds[axis] - q.bounds[axis]));
741
+ const gap = slots.gaps[nearestGap(slots.gaps.map((g) => g.a[axis]), at[axis])] ?? null;
742
+ return { index: gap?.index ?? 0, gap };
743
+ }
744
+ function itemDropTargetAt(scene, participants, at) {
745
+ const point = { x: at.x, y: at.y };
746
+ const hit = bodyAt(participants, point);
747
+ const node = hit !== null && diagramContainerOf(hit.participant.node) === null ? hit.end.nodeId : null;
748
+ const container = diagramDropParentAt(scene, point, null);
749
+ const place2 = container === null ? null : placeAmong(scene, container, point);
750
+ return { target: node ?? container, container, index: place2?.index ?? null, at: point, gap: place2?.gap ?? null };
751
+ }
752
+ function outlineOf(scene, id, role) {
753
+ const b = worldRectOf(scene, id);
754
+ if (b === null) return null;
755
+ const points = [{ x: b.x, y: b.y }, { x: b.x + b.width, y: b.y }, { x: b.x + b.width, y: b.y + b.height }, { x: b.x, y: b.y + b.height }, { x: b.x, y: b.y }];
756
+ return { kind: "polyline", points, role };
757
+ }
758
+
759
+ // src/itemDrop.ts
760
+ var DIAGRAM_ITEM_CARRY = "weasel-diagram/item";
761
+ var ITEM_DROP_ACTION_ID = "diagram.dropItem";
762
+ function startItemDrag(down, item, cb) {
763
+ return startCarry(down.currentTarget, down, { type: DIAGRAM_ITEM_CARRY, value: item }, cb);
764
+ }
765
+ function dragItemProps(item, cb) {
766
+ return {
767
+ onPointerDown: (e) => {
768
+ if (e.button !== 0) return;
769
+ e.preventDefault();
770
+ startItemDrag(e, item, cb);
771
+ }
772
+ };
773
+ }
774
+ var ANY = "optional";
775
+ function createItemDropAction(opts) {
776
+ const { participants, report, canDrop = () => true, requires = [] } = opts;
777
+ return {
778
+ id: ITEM_DROP_ACTION_ID,
779
+ label: "Drop an item",
780
+ group: "diagram",
781
+ requires: [.../* @__PURE__ */ new Set(["scene", ...requires])],
782
+ defaultBinding: [{
783
+ spec: { kind: "carry", types: [DIAGRAM_ITEM_CARRY], mods: { alt: ANY, ctrl: ANY, meta: ANY, shift: ANY } },
784
+ opts: { id: `${ITEM_DROP_ACTION_ID}.carry` }
785
+ }],
786
+ invoker: {
787
+ timing: "ongoing",
788
+ start(ctx) {
789
+ const scene = ctx.deps.scene;
790
+ if (scene === void 0 || ctx.carry === void 0) return {};
791
+ const item = ctx.carry.value;
792
+ const { deps } = ctx;
793
+ const verdicts = /* @__PURE__ */ new Map();
794
+ const over = (c) => {
795
+ const { gap, ...drop } = itemDropTargetAt(scene, participants, c.world);
796
+ const key = `${drop.target}|${drop.container}|${drop.index}`;
797
+ if (!verdicts.has(key)) verdicts.set(key, canDrop(item, drop));
798
+ return { drop, gap, verdict: verdicts.get(key) };
799
+ };
800
+ let now = over(ctx);
801
+ let open = true;
802
+ return {
803
+ kind: "diagram-item-drop",
804
+ onMove(moveCtx) {
805
+ now = over(moveCtx);
806
+ },
807
+ overlay() {
808
+ const { drop, gap, verdict } = now;
809
+ if (!open || drop.target === null || verdict === false) return null;
810
+ const reason = refusalOf(verdict);
811
+ const box = outlineOf(scene, drop.target, reason === null ? "target" : "refused");
812
+ const out = box === null ? [] : [box];
813
+ if (reason !== null) out.push({ kind: "reason", at: drop.at, text: reason });
814
+ else if (gap !== null) out.push({ kind: "polyline", points: [gap.a, gap.b], role: "insert" });
815
+ return out;
273
816
  },
274
817
  onEnd(endCtx, reason) {
275
- scratch.open = false;
276
- if (reason === "cancel") return;
277
- const to = targets.target(scratch.from, { x: endCtx.world.x, y: endCtx.world.y }, scratch.deps.view);
278
- if (to === null) return;
279
- commit(
280
- { from: scratch.from, to, router: routerKey },
281
- { ...endCtx, deps: scratch.deps }
282
- );
818
+ open = false;
819
+ if (reason !== "commit") return;
820
+ now = over(endCtx);
821
+ if (now.verdict === true) report({ item, ...now.drop }, deps);
283
822
  }
284
823
  };
285
824
  }
286
- },
287
- enabled: () => true
825
+ }
288
826
  };
289
827
  }
290
-
291
- // src/containers/canDropInto.ts
292
- function diagramCanDropInto(scene) {
293
- const nodeOf = (id) => scene.get(id);
294
- const roleOf = (id) => {
295
- const node = nodeOf(id);
296
- return node === void 0 ? null : diagramContainerOf(node)?.role ?? null;
297
- };
298
- const attached = (id) => {
299
- const node = nodeOf(id);
300
- return node !== void 0 && (diagramEdgeOf(node) !== null || diagramLabelOf(node) !== null);
301
- };
302
- return (parent, ids) => {
303
- const node = nodeOf(parent);
304
- if (node === void 0 || ids.some(attached)) return false;
305
- const role = roleOf(parent);
306
- if (role === "pool") return ids.every((id) => roleOf(id) === "lane");
307
- if (ids.some((id) => roleOf(id) === "lane")) return false;
308
- if (role !== null) return ids.every((id) => roleOf(id) !== "pool");
309
- return !attached(parent) && dataKeyReader(node) === null;
828
+ function itemDropContribution(opts) {
829
+ return {
830
+ id: "weasel-diagram-item-drop",
831
+ eligibility: { always: true },
832
+ actions: [createItemDropAction(opts)]
310
833
  };
311
834
  }
312
- function diagramDropParentAt(scene, point, role) {
313
- if (role === "pool" || role === "lane") return null;
314
- let best = null;
315
- const walk = (ids) => {
316
- for (const id of ids) {
317
- const node = scene.get(id);
318
- if (node === void 0) continue;
319
- const trait = diagramContainerOf(node);
320
- const b = bodyBox(node.pose, trait?.header);
321
- const inside2 = point.x >= b.x && point.x < b.x + b.width && point.y >= b.y && point.y < b.y + b.height;
322
- if (!inside2) continue;
323
- if (trait?.role === "container" || trait?.role === "lane") best = id;
324
- walk(scene.childrenOf(id));
325
- }
326
- };
327
- walk(scene.roots);
328
- return best;
835
+ function useItemDrop(participants, props) {
836
+ const latest = useLatest(props);
837
+ const on = props.onDropItem !== void 0;
838
+ return useMemo(() => on ? itemDropContribution({
839
+ participants,
840
+ canDrop: (item, target) => latest.current.canDropItem?.(item, target) ?? true,
841
+ report: (drop) => latest.current.onDropItem?.(drop)
842
+ }) : null, [on, participants, latest]);
329
843
  }
330
844
 
331
845
  // src/theme/themeWrites.ts
@@ -439,6 +953,8 @@ function themeWrites(scene, theme, ids, from) {
439
953
  }
440
954
  return out;
441
955
  }
956
+
957
+ // src/stencils/containers.ts
442
958
  var CONTAINER_STENCILS = [
443
959
  { id: "container", label: "Container", role: "container", size: { width: 240, height: 160 }, icon: (
444
960
  /* @icon */
@@ -453,6 +969,7 @@ var CONTAINER_STENCILS = [
453
969
  "diagram:poolColumns"
454
970
  ) }
455
971
  ];
972
+ var CONTAINERS_GROUP = { id: "containers", label: "Containers", stencils: CONTAINER_STENCILS };
456
973
  var NEW_LANE_SIZE = 120;
457
974
  function placedBounds(stencil, b) {
458
975
  if (b.width > 0 && b.height > 0) return { ...b };
@@ -475,7 +992,8 @@ function containerBuild(stencil, bounds, opts) {
475
992
  ...stencil.role === "pool" ? firstLanes(id, axis, at, opts) : []
476
993
  ];
477
994
  const label = `Insert ${stencil.label}`;
478
- return { id, ops: specs.map((node) => createInsertOp({ node, label })) };
995
+ const stored = localizeWorldPoses(specs, RIGID_POSE_COMPOSITION);
996
+ return { id, ops: stored.map((node) => createInsertOp({ node, label })) };
479
997
  }
480
998
  var poolAxisOf = (pool) => pool.header?.side === "top" ? "x" : "y";
481
999
  function lanesOf(scene, poolId) {
@@ -495,19 +1013,20 @@ function addLane(scene, poolId, index, style) {
495
1013
  if (pool === void 0 || trait?.role !== "pool") return null;
496
1014
  const axis = poolAxisOf(trait);
497
1015
  const lanes = lanesOf(scene, poolId);
498
- const b = pool.pose;
1016
+ const { width, height } = pool.pose;
1017
+ const b = { x: 0, y: 0, width, height };
499
1018
  const at = index === void 0 || index >= lanes.length ? null : scene.get(lanes[index]).pose;
500
1019
  const boundary = at !== null ? axis === "y" ? at.y : at.x : axis === "y" ? b.y + b.height : b.x + b.width;
501
1020
  const start = boundary - NEW_LANE_SIZE / 2;
502
1021
  const offset = trait.header?.size ?? 0;
503
1022
  const pose = axis === "y" ? { x: b.x + offset, y: start, width: b.width - offset, height: NEW_LANE_SIZE } : { x: start, y: b.y + offset, width: NEW_LANE_SIZE, height: b.height - offset };
504
1023
  const id = scene.mintId();
505
- const specs = regionSpecs("lane", axis, pose, `Lane ${lanes.length + 1}`, {
1024
+ const specs = localizeWorldPoses(regionSpecs("lane", axis, pose, `Lane ${lanes.length + 1}`, {
506
1025
  id,
507
1026
  layer: pool.layer,
508
1027
  parent: poolId,
509
1028
  ...style ? { style } : {}
510
- });
1029
+ }), scene.composition);
511
1030
  scene.batch("Add lane", () => {
512
1031
  for (const spec of specs) scene.add(spec);
513
1032
  if (style === void 0 && scene.doc.get(DIAGRAM_THEME_KEY) !== void 0) {
@@ -531,11 +1050,27 @@ function releaseMembers(scene, id) {
531
1050
  const beside = releasedFrom(scene, node.id);
532
1051
  const parent = scene.get(beside).parent;
533
1052
  const index = (parent === null ? scene.roots : scene.childrenOf(parent)).indexOf(beside);
1053
+ const frame = scenePoseFrame(scene);
1054
+ const worlds = members2.map((m) => frame.world(m));
534
1055
  scene.batch("Release members", () => {
535
- members2.forEach((m, k) => scene.move(m, parent, index + k));
1056
+ members2.forEach((m, k) => {
1057
+ scene.move(m, parent, index + k);
1058
+ scene.setPose(m, frame.localUnder(parent, worlds[k]));
1059
+ });
536
1060
  scene.remove(node.id);
537
1061
  });
538
1062
  }
1063
+ function worldWith(sc, frame = /* @__PURE__ */ new Map()) {
1064
+ const poses = {
1065
+ getPose: (id) => frame.has(id) ? frame.get(id) : sc.get(id).pose,
1066
+ getParent: (id) => sc.get(id)?.parent ?? null,
1067
+ definesFrame: (id) => {
1068
+ const n = sc.get(id);
1069
+ return n === void 0 || definesFrame(n);
1070
+ }
1071
+ };
1072
+ return (id) => composeWorldPose(poses, id, sc.composition.compose);
1073
+ }
539
1074
  var LANE_LAYER_ID = "diagram-lanes";
540
1075
  var LANE_AFFORDANCE_KIND = `layer:${LANE_LAYER_ID}`;
541
1076
  function laneScratchOf(hit) {
@@ -544,6 +1079,7 @@ function laneScratchOf(hit) {
544
1079
  }
545
1080
  function poolsOf(scene) {
546
1081
  const out = [];
1082
+ const world = worldWith(scene);
547
1083
  for (const node of scene.renderOrderNodes()) {
548
1084
  const trait = diagramContainerOf(node);
549
1085
  if (trait?.role !== "pool" || scene.isHidden(node.id) || scene.isLocked(node.id)) continue;
@@ -551,7 +1087,8 @@ function poolsOf(scene) {
551
1087
  id: node.id,
552
1088
  axis: poolAxisOf(trait),
553
1089
  pose: node.pose,
554
- lanes: lanesOf(scene, node.id).map((id) => ({ id, pose: scene.get(id).pose }))
1090
+ at: world(node.id),
1091
+ lanes: lanesOf(scene, node.id).map((id) => ({ id, pose: scene.get(id).pose, at: world(id) }))
555
1092
  });
556
1093
  }
557
1094
  return out;
@@ -595,7 +1132,7 @@ function createLaneAffordance(scene, opts = {}) {
595
1132
  out.push({
596
1133
  id: `${lane.id}:boundary`,
597
1134
  targetId: null,
598
- shape: { kind: "outline", path: boundaryOf(pool.axis, lane.pose), hitRadiusPx },
1135
+ shape: { kind: "outline", path: boundaryOf(pool.axis, lane.at), hitRadiusPx },
599
1136
  cursor,
600
1137
  strength: "exclusive",
601
1138
  claimedKinds: ["pointer"],
@@ -603,7 +1140,7 @@ function createLaneAffordance(scene, opts = {}) {
603
1140
  });
604
1141
  }
605
1142
  if (addSizePx <= 0) continue;
606
- const p = pool.pose;
1143
+ const p = pool.at;
607
1144
  const end = pool.axis === "y" ? { x: p.x + p.width / 2, y: p.y + p.height, normal: { x: 0, y: 1 } } : { x: p.x + p.width, y: p.y + p.height / 2, normal: { x: 1, y: 0 } };
608
1145
  out.push({
609
1146
  id: `${pool.id}:add-lane`,
@@ -652,7 +1189,7 @@ function laneResizeFrame(scene, pool, index, size) {
652
1189
  const placeTitle = (id, at) => {
653
1190
  const node = scene.get(id);
654
1191
  if (node !== void 0 && scene.get(titleIdOf(id)) !== void 0) {
655
- out.set(titleIdOf(id), titlePose(at, diagramContainerOf(node)?.header));
1192
+ out.set(titleIdOf(id), titleInFrame(at, diagramContainerOf(node)?.header));
656
1193
  }
657
1194
  };
658
1195
  const laneAt = grow(lane.pose, d);
@@ -722,9 +1259,10 @@ function createAddLaneAction(opts) {
722
1259
  invoker: {
723
1260
  timing: "immediate",
724
1261
  run(deps, params) {
725
- const pressed = laneScratchOf(params?.affordance);
726
- if (pressed === null || pressed.laneId !== void 0) return;
727
- const world = { x: Number(params?.worldX), y: Number(params?.worldY) };
1262
+ const p = params;
1263
+ const pressed = laneScratchOf(p?.affordance);
1264
+ const world = p?.world;
1265
+ if (pressed === null || pressed.laneId !== void 0 || !world) return;
728
1266
  commit(pressed.poolId, { world, modifiers: NO_MODIFIERS, deps });
729
1267
  }
730
1268
  },
@@ -803,7 +1341,8 @@ function editContainerTitleAction(commit) {
803
1341
  invoker: {
804
1342
  timing: "immediate",
805
1343
  run(deps, params) {
806
- const id = regionHeaderAt(deps, { x: Number(params?.worldX), y: Number(params?.worldY) });
1344
+ const world = params?.world;
1345
+ const id = world ? regionHeaderAt(deps, world) : null;
807
1346
  if (id !== null) commit(id);
808
1347
  }
809
1348
  },
@@ -826,6 +1365,10 @@ function createSetHopsAction(opts = {}) {
826
1365
  return {
827
1366
  id: SET_HOPS_ACTION_ID,
828
1367
  label: "Line jumps",
1368
+ icon: (
1369
+ /* @icon */
1370
+ "diagram:lineJumps"
1371
+ ),
829
1372
  group: "diagram",
830
1373
  requires: ["scene"],
831
1374
  invoker: {
@@ -960,20 +1503,27 @@ function createResetLabelAction(opts) {
960
1503
  };
961
1504
  }
962
1505
  function sceneParticipants(scene) {
963
- return function* () {
1506
+ const each = function* () {
964
1507
  const gates = nodeGates(scene);
1508
+ const frame = scenePoseFrame(scene);
965
1509
  for (const node of scene.renderOrderNodes()) {
966
1510
  const hidden = gates.hidden(node.id);
967
1511
  const locked = gates.locked(node.id);
968
1512
  yield {
969
1513
  node,
970
- pose: effectivePose(scene, node),
1514
+ pose: frame.world(node.id),
971
1515
  ...node.layer !== void 0 ? { layer: node.layer } : {},
972
1516
  ...hidden ? { hidden } : {},
973
1517
  ...locked ? { locked } : {}
974
1518
  };
975
1519
  }
976
1520
  };
1521
+ const { getVersion } = scene;
1522
+ const getGeneration = scene.overrides.getGeneration;
1523
+ if (getVersion === void 0 || getGeneration === void 0) return each;
1524
+ return Object.assign(each, {
1525
+ generation: () => [getVersion.call(scene), getGeneration.call(scene.overrides)]
1526
+ });
977
1527
  }
978
1528
  function portLayer(participants, opts = {}) {
979
1529
  return composeAffordanceLayer(
@@ -1330,7 +1880,7 @@ function neighborsOf(handle, stops) {
1330
1880
  const at = handle.kind === "vertex" ? handle.index + 1 : handle.leg + 1;
1331
1881
  return [stops[at - 1], stops[handle.kind === "vertex" ? at + 1 : at]];
1332
1882
  }
1333
- function moveOf(p, session, ctx) {
1883
+ function moveOf2(p, session, ctx) {
1334
1884
  const d = { x: ctx.world.x - p.press.x, y: ctx.world.y - p.press.y };
1335
1885
  if (session === null) return d;
1336
1886
  const at = session.at({ x: p.handle.at.x + d.x, y: p.handle.at.y + d.y }, snapMods(ctx)).point;
@@ -1382,7 +1932,7 @@ function createRouteEditAction(opts) {
1382
1932
  return {
1383
1933
  kind: "diagram-edit-route",
1384
1934
  onMove(moveCtx) {
1385
- waypoints = waypointsAt(p, moveOf(p, session, moveCtx));
1935
+ waypoints = waypointsAt(p, moveOf2(p, session, moveCtx));
1386
1936
  },
1387
1937
  previewIds: () => proposed() === null ? null : [p.edgeId],
1388
1938
  previewPose: (id) => id === p.edgeId && proposed() !== null ? p.pose : null,
@@ -1392,7 +1942,7 @@ function createRouteEditAction(opts) {
1392
1942
  },
1393
1943
  onEnd(endCtx, reason) {
1394
1944
  open = false;
1395
- const final = reason === "commit" ? waypointsAt(p, moveOf(p, session, endCtx)) : null;
1945
+ const final = reason === "commit" ? waypointsAt(p, moveOf2(p, session, endCtx)) : null;
1396
1946
  session?.end();
1397
1947
  if (final !== null) commit({ edgeId: p.edgeId, waypoints: final }, { ...endCtx, deps: p.deps });
1398
1948
  }
@@ -1439,8 +1989,10 @@ function createRemoveWaypointAction(opts) {
1439
1989
  invoker: {
1440
1990
  timing: "immediate",
1441
1991
  run(deps, params) {
1442
- const world = { x: Number(params?.worldX), y: Number(params?.worldY) };
1443
- const pressed = waypointScratchOf(params?.affordance);
1992
+ const p = params;
1993
+ const world = p?.world;
1994
+ if (!world) return;
1995
+ const pressed = waypointScratchOf(p.affordance);
1444
1996
  const route = pressed === null ? null : routeOf3(pressed.edgeId);
1445
1997
  const waypoints = pressed === null || route === null ? null : removalOf(route, pressed.handle);
1446
1998
  const edit = pressed !== null && waypoints !== null ? { edgeId: pressed.edgeId, waypoints } : removalAt(deps, world);
@@ -1493,6 +2045,24 @@ var ROUTER_LABELS = {
1493
2045
  straight: "Straight",
1494
2046
  bezier: "Curved"
1495
2047
  };
2048
+ var ROUTER_ICONS = {
2049
+ avoid: (
2050
+ /* @icon */
2051
+ "diagram:routerAvoid"
2052
+ ),
2053
+ orthogonal: (
2054
+ /* @icon */
2055
+ "diagram:routerOrthogonal"
2056
+ ),
2057
+ straight: (
2058
+ /* @icon */
2059
+ "diagram:routerStraight"
2060
+ ),
2061
+ bezier: (
2062
+ /* @icon */
2063
+ "diagram:routerCurved"
2064
+ )
2065
+ };
1496
2066
  function withRouter(data, trait, router) {
1497
2067
  const { route: _r, ...rest } = trait;
1498
2068
  return { ...data, diagram: { ...rest, router } };
@@ -1520,6 +2090,7 @@ function createSetRouterAction(router, opts) {
1520
2090
  return {
1521
2091
  id: SET_ROUTER_ACTION_IDS[router],
1522
2092
  label: ROUTER_LABELS[router],
2093
+ icon: ROUTER_ICONS[router],
1523
2094
  group: "diagram",
1524
2095
  requires: ["scene"],
1525
2096
  invoker: {
@@ -1650,7 +2221,7 @@ function avoidSceneInput(scene, opts = {}, poseOf) {
1650
2221
  const pose = (node) => {
1651
2222
  let p = poses.get(node.id);
1652
2223
  if (p === void 0) {
1653
- p = poseOf?.(node.id) ?? documentPose(sc, node);
2224
+ p = poseOf?.(node.id) ?? composeWorldPose(scenePoseAdapter(sc), node.id, sc.composition.compose);
1654
2225
  poses.set(node.id, p);
1655
2226
  }
1656
2227
  return p;
@@ -1714,10 +2285,20 @@ function avoidSceneInput(scene, opts = {}, poseOf) {
1714
2285
  }
1715
2286
  return { obstacles, edges };
1716
2287
  }
2288
+ var specWorldPoses = (specs, composition = RIGID_POSE_COMPOSITION) => worldPosesOf(specs, composition);
2289
+ function specDeps(specs, world) {
2290
+ const byId = new Map(specs.map((s) => [s.id, s]));
2291
+ return (id) => {
2292
+ const s = byId.get(id);
2293
+ if (s === void 0) return void 0;
2294
+ const pose = world.get(s.id) ?? s.pose;
2295
+ return { node: { ...s, parent: null, pose }, pose, path: null };
2296
+ };
2297
+ }
1717
2298
 
1718
2299
  // src/avoid/specRoutes.ts
1719
2300
  var facing = (ports) => ports.flatMap((p) => p.normal === null ? [] : [{ point: p.point, normal: p.normal }]);
1720
- function obstaclesOf(specs) {
2301
+ function obstaclesOf(specs, world) {
1721
2302
  const children = /* @__PURE__ */ new Map();
1722
2303
  for (const s of specs) {
1723
2304
  if (s.parent == null) continue;
@@ -1736,10 +2317,11 @@ function obstaclesOf(specs) {
1736
2317
  if (spec.derivePose !== void 0 || diagramEdgeOf(spec) !== null) continue;
1737
2318
  const region = diagramContainerOf(spec);
1738
2319
  if (diagramNodeOf(node) === null && region?.role !== "lane") continue;
1739
- const header = region === null ? null : headerBox(spec.pose, region.header);
2320
+ const box = world.get(node.id) ?? spec.pose;
2321
+ const header = region === null ? null : headerBox(box, region.header);
1740
2322
  if (header !== null) out.push({ id: headerIdOf(node.id), kind: "shape", box: header });
1741
2323
  if (region?.role === "lane") continue;
1742
- out.push(region === null ? { id: node.id, kind: "shape", box: spec.pose } : { id: node.id, kind: "region", box: spec.pose, members: inside2(node.id, /* @__PURE__ */ new Set()) });
2324
+ out.push(region === null ? { id: node.id, kind: "shape", box } : { id: node.id, kind: "region", box, members: inside2(node.id, /* @__PURE__ */ new Set()) });
1743
2325
  }
1744
2326
  return out;
1745
2327
  }
@@ -1755,12 +2337,14 @@ function labelsOf(specs) {
1755
2337
  return out;
1756
2338
  }
1757
2339
  function createSpecRouter(options = {}) {
1758
- const router = createAvoidRouter(options);
2340
+ const { composition = RIGID_POSE_COMPOSITION, ...avoid2 } = options;
2341
+ const router = createAvoidRouter(avoid2);
1759
2342
  let held = /* @__PURE__ */ new Map();
1760
2343
  return (specs) => {
1761
2344
  const byId = new Map(specs.map((s) => [s.id, s]));
1762
2345
  const labels = labelsOf(specs);
1763
- const obstacles = obstaclesOf(specs);
2346
+ const world = specWorldPoses(specs, composition);
2347
+ const obstacles = obstaclesOf(specs, world);
1764
2348
  const edges = [];
1765
2349
  for (const spec of specs) {
1766
2350
  const edge = diagramEdgeOf(spec);
@@ -1770,7 +2354,8 @@ function createSpecRouter(options = {}) {
1770
2354
  if (a === void 0 || b === void 0 || a === b) continue;
1771
2355
  const portsAt = (s, port) => {
1772
2356
  const n = { id: s.id, kind: s.kind, data: s.data };
1773
- return facing(port === void 0 ? portsOf(n, s.pose) : portSitesOf(n, s.pose, port));
2357
+ const pose = world.get(n.id) ?? s.pose;
2358
+ return facing(port === void 0 ? portsOf(n, pose) : portSitesOf(n, pose, port));
1774
2359
  };
1775
2360
  const route = held.get(spec.id);
1776
2361
  edges.push({
@@ -1846,11 +2431,7 @@ function hopDataOps(scene, hops) {
1846
2431
  function createSpecHops(r) {
1847
2432
  const route = edgeRouter();
1848
2433
  return (specs) => {
1849
- const byId = new Map(specs.map((s) => [s.id, s]));
1850
- const dep = (id) => {
1851
- const s = byId.get(id);
1852
- return s === void 0 ? void 0 : { node: s, pose: s.pose, path: null };
1853
- };
2434
+ const dep = specDeps(specs, specWorldPoses(specs));
1854
2435
  const polylines = /* @__PURE__ */ new Map();
1855
2436
  const order = [];
1856
2437
  for (const spec of specs) {
@@ -1911,390 +2492,74 @@ function sameEnd(ends, moving, target) {
1911
2492
  function createReconnectAction(opts) {
1912
2493
  const { canConnect = defaultCanConnect, commit = commitReconnectToScene } = opts;
1913
2494
  const endsOf = createEdgeEnds(opts.participants, opts);
1914
- const shared = { ...opts, snapRadius: opts.snapRadius ?? DEFAULT_SNAP2, bodies: opts.bodies ?? true };
1915
- const targetsFor = (moving) => createTargets({
1916
- ...shared,
1917
- canConnect: moving.end === "to" ? (fixed, candidate) => canConnect(fixed, candidate, moving) : (fixed, candidate) => canConnect(candidate, fixed, moving)
1918
- });
1919
- return {
1920
- id: opts.id ?? RECONNECT_ACTION_ID,
1921
- label: "Reconnect",
1922
- group: "diagram",
1923
- requires: ["scene", "view"],
1924
- invoker: {
1925
- timing: "ongoing",
1926
- start(ctx) {
1927
- const pressed = edgeEndScratchOf(ctx.drag?.affordance);
1928
- const ends = pressed === null ? null : endsOf(pressed.edgeId);
1929
- if (pressed === null || ends === null) return {};
1930
- const scratch = {
1931
- edgeId: pressed.edgeId,
1932
- moving: pressed.end,
1933
- fixed: fixedEndOf(ends, pressed.end, opts),
1934
- ends,
1935
- route: routerOf(ends.trait, opts.routers),
1936
- current: { x: ctx.world.x, y: ctx.world.y },
1937
- open: true,
1938
- deps: ctx.deps
1939
- };
1940
- const resolver = targetsFor({ edge: scratch.edgeId, end: scratch.moving });
1941
- return {
1942
- kind: "diagram-reconnect",
1943
- onMove(moveCtx) {
1944
- scratch.current = { x: moveCtx.world.x, y: moveCtx.world.y };
1945
- },
1946
- overlay() {
1947
- if (!scratch.open) return null;
1948
- const points = resolver.preview(scratch.route, scratch.fixed, scratch.current, scratch.deps.view, scratch.moving, scratch.ends.trait.waypoints);
1949
- return points.length < 2 ? null : { kind: "polyline", points, role: "connector" };
1950
- },
1951
- onEnd(endCtx, reason) {
1952
- scratch.open = false;
1953
- if (reason === "cancel") return;
1954
- const target = resolver.target(scratch.fixed, { x: endCtx.world.x, y: endCtx.world.y }, scratch.deps.view);
1955
- if (target === null || sameEnd(scratch.ends, scratch.moving, target)) return;
1956
- commit({ edgeId: scratch.edgeId, end: scratch.moving, target }, { ...endCtx, deps: scratch.deps });
1957
- }
1958
- };
1959
- }
1960
- },
1961
- enabled: () => true
1962
- };
1963
- }
1964
- function reconnectBinding(actionId = RECONNECT_ACTION_ID) {
1965
- return { spec: { kind: "drag", target: `affordance:${EDGE_END_AFFORDANCE_KIND}` }, actionId, opts: { id: `${actionId}.drag` } };
1966
- }
1967
- function diagramEdgeEnds(opts) {
1968
- const actionId = opts.id ?? RECONNECT_ACTION_ID;
1969
- return {
1970
- // `opts.id` names the action; the layer keeps its own id.
1971
- layer: edgeEndLayer(opts.participants, opts.selected, { ...opts, id: EDGE_END_LAYER_ID }),
1972
- contribution: {
1973
- id: "weasel-diagram-edge-ends",
1974
- eligibility: { claimed: true },
1975
- actions: [createReconnectAction({ ...opts, id: actionId }), grabPortAction(GRAB_EDGE_END_ACTION_ID)],
1976
- bindings: [
1977
- reconnectBinding(actionId),
1978
- ...grabPortBindings(GRAB_EDGE_END_ACTION_ID, EDGE_END_AFFORDANCE_KIND)
1979
- ]
1980
- }
1981
- };
1982
- }
1983
- function packed(items, spans, order) {
1984
- const gaps = items.slice(1).map((m, i) => spans.get(m).start - (spans.get(items[i]).start + spans.get(items[i]).size));
1985
- const out = /* @__PURE__ */ new Map();
1986
- let at = items.length > 0 ? spans.get(items[0]).start : 0;
1987
- order.forEach((m, i) => {
1988
- out.set(m, at);
1989
- at += spans.get(m).size + (gaps[i] ?? gaps[gaps.length - 1] ?? 0);
1990
- });
1991
- return out;
1992
- }
1993
- var carriedBy = (item) => item.carries ?? [item.id];
1994
- var RELEASE_MS = 500;
1995
- function slideOthers(scene, slots, carried) {
1996
- const { axis } = slots;
1997
- const size = axis === "x" ? "width" : "height";
1998
- const ids = slots.items.map((i) => i.id);
1999
- const spans = new Map(slots.items.map((i) => [i.id, { start: i.bounds[axis], size: i.bounds[size] }]));
2000
- const nodes = slots.items.map((item) => ({
2001
- id: item.id,
2002
- poses: carriedBy(item).flatMap((id) => {
2003
- const node = scene.get(id);
2004
- return node === void 0 || node.derivePose !== void 0 ? [] : [{ id, pose: effectivePose(scene, node) }];
2005
- })
2006
- }));
2007
- const hold = scene.overrides.hold();
2008
- return {
2009
- /** The items standing in `order`, or as they were for `null`, with the carried one `by` along. */
2010
- show(order, by) {
2011
- const starts = packed(ids, spans, order ?? ids);
2012
- hold.set(nodes.flatMap(({ id, poses }) => {
2013
- const d = id === carried ? by : starts.get(id) - spans.get(id).start;
2014
- return poses.map(({ id: node, pose }) => [node, { ...pose, [axis]: pose[axis] + d }]);
2015
- }));
2016
- },
2017
- drop: () => hold.drop(),
2018
- /** Held until the host's new specs land, so the items do not jump back for
2019
- * the frames in between; a host that keeps the old order gets it back shortly after. */
2020
- keep() {
2021
- const release = () => {
2022
- stop();
2023
- clearTimeout(timer);
2024
- hold.drop();
2025
- };
2026
- const stop = scene.subscribe(release);
2027
- const timer = setTimeout(release, RELEASE_MS);
2028
- }
2029
- };
2030
- }
2031
-
2032
- // src/reorder.ts
2033
- var REORDER_ACTION_ID = "diagram.reorder";
2034
- var END_GAP = 24;
2035
- var inside = (p, b) => p.x >= b.x && p.x <= b.x + b.width && p.y >= b.y && p.y <= b.y + b.height;
2036
- function sequenceSlots(axis, items) {
2037
- const [along2, across, size, depth] = axis === "x" ? ["x", "y", "width", "height"] : ["y", "x", "height", "width"];
2038
- const lo = (b) => b[along2];
2039
- const hi = (b) => b[along2] + b[size];
2040
- const bar = (at, boxes2) => {
2041
- const from = Math.min(...boxes2.map((b) => b[across]));
2042
- const to = Math.max(...boxes2.map((b) => b[across] + b[depth]));
2043
- const point = (c) => axis === "x" ? { x: at, y: c } : { x: c, y: at };
2044
- return { a: point(from), b: point(to) };
2045
- };
2046
- const boxes = items.map((i) => i.bounds);
2047
- const halves = boxes.slice(1).map((b, k) => (lo(b) - hi(boxes[k])) / 2);
2048
- const gaps = [];
2049
- if (boxes.length === 0) return { axis, items, gaps };
2050
- gaps.push({ index: 0, ...bar(lo(boxes[0]) - (halves[0] ?? END_GAP / 2), [boxes[0]]) });
2051
- for (let k = 1; k < boxes.length; k++) gaps.push({ index: k, ...bar(hi(boxes[k - 1]) + halves[k - 1], [boxes[k - 1], boxes[k]]) });
2052
- const last = boxes[boxes.length - 1];
2053
- gaps.push({ index: boxes.length, ...bar(hi(last) + (halves[halves.length - 1] ?? END_GAP / 2), [last]) });
2054
- return { axis, items, gaps };
2055
- }
2056
- function pickAt(slots, at) {
2057
- const from = slots?.items.findIndex((i) => i.grip !== null && inside(at, i.grip ?? i.bounds)) ?? -1;
2058
- return from < 0 ? null : { from, item: slots.items[from] };
2059
- }
2060
- function gapAt(held, by) {
2061
- const { axis, gaps } = held.slots;
2062
- const size = axis === "x" ? "width" : "height";
2063
- const mid = held.item.bounds[axis] + held.item.bounds[size] / 2 + by;
2064
- let best = null;
2065
- for (const g of gaps) if (best === null || Math.abs(g.a[axis] - mid) < Math.abs(best.a[axis] - mid)) best = g;
2066
- return best === null || best.index === held.from || best.index === held.from + 1 ? null : best;
2067
- }
2068
- function moveOf2(held, gap) {
2069
- const order = held.slots.items.map((i) => i.id);
2070
- order.splice(held.from, 1);
2071
- order.splice(gap.index > held.from ? gap.index - 1 : gap.index, 0, held.item.id);
2072
- return { id: held.item.id, from: held.from, to: gap.index, order };
2073
- }
2074
- function createReorderAction(opts) {
2075
- const { canDrop = () => true, show = "bar" } = opts;
2076
- return {
2077
- id: opts.id ?? REORDER_ACTION_ID,
2078
- label: opts.label ?? "Reorder",
2079
- group: "diagram",
2080
- requires: ["scene", ...opts.requires ?? []],
2081
- cursor: "grab",
2082
- activeCursor: "grabbing",
2083
- enabled: (deps, at) => deps === void 0 || at === void 0 || pickAt(opts.slots(deps, at), at) !== null ? true : ActionDisabledReason.NotApplicable,
2084
- invoker: {
2085
- timing: "ongoing",
2086
- start(ctx) {
2087
- const start = { x: (ctx.drag?.start ?? ctx.world).x, y: (ctx.drag?.start ?? ctx.world).y };
2088
- const slots = opts.slots(ctx.deps, start);
2089
- const picked = pickAt(slots, start);
2090
- if (slots === null || picked === null) return {};
2091
- const held = { slots, ...picked };
2092
- const { axis } = slots;
2093
- let by = ctx.world[axis] - start[axis];
2094
- let open = true;
2095
- const verdicts = /* @__PURE__ */ new Map();
2096
- const landing = (gap) => {
2097
- if (gap === null) return null;
2098
- if (!verdicts.has(gap.index)) {
2099
- const move = moveOf2(held, gap);
2100
- verdicts.set(gap.index, canDrop(move) ? move : null);
2101
- }
2102
- return verdicts.get(gap.index);
2103
- };
2104
- const finish = (endCtx, reason) => {
2105
- open = false;
2106
- by = endCtx.world[axis] - start[axis];
2107
- const move = reason === "commit" ? landing(gapAt(held, by)) : null;
2108
- if (move !== null) opts.commit(move, { ...endCtx, deps: ctx.deps });
2109
- return move;
2495
+ const shared = { ...opts, snapRadius: opts.snapRadius ?? DEFAULT_SNAP2, bodies: opts.bodies ?? true };
2496
+ const targetsFor = (moving) => createTargets({
2497
+ ...shared,
2498
+ canConnect: moving.end === "to" ? (fixed, candidate) => canConnect(fixed, candidate, moving) : (fixed, candidate) => canConnect(candidate, fixed, moving)
2499
+ });
2500
+ return {
2501
+ id: opts.id ?? RECONNECT_ACTION_ID,
2502
+ label: "Reconnect",
2503
+ group: "diagram",
2504
+ requires: ["scene", "view"],
2505
+ invoker: {
2506
+ timing: "ongoing",
2507
+ start(ctx) {
2508
+ const pressed = edgeEndScratchOf(ctx.drag?.affordance);
2509
+ const ends = pressed === null ? null : endsOf(pressed.edgeId);
2510
+ if (pressed === null || ends === null) return {};
2511
+ const scratch = {
2512
+ edgeId: pressed.edgeId,
2513
+ moving: pressed.end,
2514
+ fixed: fixedEndOf(ends, pressed.end, opts),
2515
+ ends,
2516
+ route: routerOf(ends.trait, opts.routers),
2517
+ current: { x: ctx.world.x, y: ctx.world.y },
2518
+ open: true,
2519
+ deps: ctx.deps
2110
2520
  };
2111
- if (show === "slide") {
2112
- const slide = ctx.deps.scene === void 0 ? null : slideOthers(ctx.deps.scene, held.slots, held.item.id);
2113
- return {
2114
- kind: "diagram-reorder",
2115
- onMove(moveCtx) {
2116
- by = moveCtx.world[axis] - start[axis];
2117
- slide?.show(landing(gapAt(held, by))?.order ?? null, by);
2118
- },
2119
- onEnd(endCtx, reason) {
2120
- const move = finish(endCtx, reason);
2121
- if (move === null) slide?.drop();
2122
- else slide?.keep();
2123
- }
2124
- };
2125
- }
2126
- const carried = carriedBy(held.item);
2127
- const poses = /* @__PURE__ */ new Map();
2128
- for (const id of carried) {
2129
- const pose = ctx.deps.scene?.get(id)?.pose;
2130
- if (pose !== void 0) poses.set(id, pose);
2131
- }
2521
+ const resolver = targetsFor({ edge: scratch.edgeId, end: scratch.moving });
2132
2522
  return {
2133
- kind: "diagram-reorder",
2523
+ kind: "diagram-reconnect",
2134
2524
  onMove(moveCtx) {
2135
- by = moveCtx.world[axis] - start[axis];
2136
- },
2137
- previewIds: () => open && poses.size > 0 ? [...poses.keys()] : null,
2138
- previewPose: (id) => {
2139
- const pose = poses.get(id);
2140
- return pose === void 0 ? null : { ...pose, [axis]: pose[axis] + by };
2525
+ scratch.current = { x: moveCtx.world.x, y: moveCtx.world.y };
2141
2526
  },
2142
- previewOpaqueIds: () => [...carried],
2143
2527
  overlay() {
2144
- const gap = open ? gapAt(held, by) : null;
2145
- if (gap === null) return null;
2146
- return { kind: "polyline", points: [gap.a, gap.b], role: landing(gap) !== null ? "insert" : "refused" };
2528
+ if (!scratch.open) return null;
2529
+ return resolver.overlays(scratch.route, scratch.fixed, scratch.current, scratch.deps.view, scratch.moving, scratch.ends.trait.waypoints);
2147
2530
  },
2148
2531
  onEnd(endCtx, reason) {
2149
- finish(endCtx, reason);
2532
+ scratch.open = false;
2533
+ if (reason === "cancel") return;
2534
+ const target = resolver.target(scratch.fixed, { x: endCtx.world.x, y: endCtx.world.y }, scratch.deps.view);
2535
+ if (target === null || sameEnd(scratch.ends, scratch.moving, target)) return;
2536
+ commit({ edgeId: scratch.edgeId, end: scratch.moving, target }, { ...endCtx, deps: scratch.deps });
2150
2537
  }
2151
2538
  };
2152
2539
  }
2153
- }
2154
- };
2155
- }
2156
- var ANYWHERE = bodyPredicate(() => true);
2157
- function reorderBinding(actionId = REORDER_ACTION_ID, on = ANYWHERE) {
2158
- return { spec: { kind: "drag", target: { kindOf: on } }, actionId, opts: { id: on === ANYWHERE ? `${actionId}.drag` : `${actionId}.bodyDrag` } };
2159
- }
2160
- function reorderContribution(opts) {
2161
- const actionId = opts.id ?? REORDER_ACTION_ID;
2162
- return {
2163
- id: `weasel-diagram-reorder:${actionId}`,
2164
- eligibility: { always: true },
2165
- actions: [createReorderAction({ ...opts, id: actionId })],
2166
- bindings: [reorderBinding(actionId, opts.on)]
2540
+ },
2541
+ enabled: () => true
2167
2542
  };
2168
2543
  }
2169
- function worldRectOf(scene, id) {
2170
- const node = scene.get(id);
2171
- if (node === void 0) return null;
2172
- const drawn = drawnBoundsScene(scene);
2173
- const route = diagramEdgeOf(node) === null ? null : drawn.derivedPathOf?.(id) ?? null;
2174
- const mid = route === null ? null : pointAlongPath(route, 0.5);
2175
- if (mid != null) return { x: mid.point.x, y: mid.point.y, width: 0, height: 0 };
2176
- return drawnAABBOf(drawn, id, effectivePose(scene, node), { includeStroke: false });
2544
+ function reconnectBinding(actionId = RECONNECT_ACTION_ID) {
2545
+ return { spec: { kind: "drag", target: `affordance:${EDGE_END_AFFORDANCE_KIND}` }, actionId, opts: { id: `${actionId}.drag` } };
2177
2546
  }
2178
- function screenRectOf(rect, view) {
2547
+ function diagramEdgeEnds(opts) {
2548
+ const actionId = opts.id ?? RECONNECT_ACTION_ID;
2179
2549
  return {
2180
- x: (rect.x - view.x) * view.scale.x,
2181
- y: (rect.y - view.y) * view.scale.y,
2182
- width: rect.width * view.scale.x,
2183
- height: rect.height * view.scale.y
2184
- };
2185
- }
2186
- var CENTER = "center";
2187
- function place(el, overlay, anchor, view) {
2188
- const size = { width: el.offsetWidth, height: el.offsetHeight };
2189
- const placement = overlay.placement ?? CENTER;
2190
- const at = placement === CENTER ? { x: anchor.x + (anchor.width - size.width) / 2, y: anchor.y + (anchor.height - size.height) / 2 } : clampRectWithin(placeRect({ anchor, overlay: size, boundary: view, placement, offset: overlay.offset ?? 0 }).rect, view);
2191
- el.style.transform = `translate(${Math.round(at.x)}px, ${Math.round(at.y)}px)`;
2192
- }
2193
- function useOverlayPlacement(canvasRef, scene, overlays) {
2194
- const elements = useRef(/* @__PURE__ */ new Map());
2195
- const current = useLatest$1(overlays);
2196
- const placeAll = useCallback(() => {
2197
- const canvas = canvasRef.current;
2198
- const surface = canvas?.element;
2199
- if (canvas == null || surface == null) return;
2200
- const view = canvas.getView();
2201
- for (const overlay of current.current) {
2202
- const el = elements.current.get(overlay.key ?? overlay.target);
2203
- if (el === void 0) continue;
2204
- const world = worldRectOf(scene, overlay.target);
2205
- el.hidden = world === null;
2206
- if (world === null) continue;
2207
- const rect = screenRectOf(world, view);
2208
- const anchor = { ...rect, x: rect.x + surface.offsetLeft, y: rect.y + surface.offsetTop };
2209
- place(el, overlay, anchor, {
2210
- x: surface.offsetLeft,
2211
- y: surface.offsetTop,
2212
- width: surface.offsetWidth,
2213
- height: surface.offsetHeight
2214
- });
2215
- }
2216
- }, [canvasRef, scene, current]);
2217
- useLayoutEffect(() => {
2218
- placeAll();
2219
- const canvas = canvasRef.current;
2220
- if (canvas == null) return;
2221
- const stop = canvas.subscribeFrame(placeAll);
2222
- const observer = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(placeAll);
2223
- for (const el of elements.current.values()) observer?.observe(el);
2224
- return () => {
2225
- stop();
2226
- observer?.disconnect();
2227
- };
2228
- }, [canvasRef, placeAll, overlays]);
2229
- const refs = useRef(/* @__PURE__ */ new Map());
2230
- return useCallback((key) => {
2231
- let ref = refs.current.get(key);
2232
- if (ref === void 0) {
2233
- ref = (el) => {
2234
- if (el !== null) {
2235
- elements.current.set(key, el);
2236
- return;
2237
- }
2238
- elements.current.delete(key);
2239
- refs.current.delete(key);
2240
- };
2241
- refs.current.set(key, ref);
2242
- }
2243
- return ref;
2244
- }, []);
2245
- }
2246
-
2247
- // src/reorderModel.ts
2248
- var depsOf = (node) => Array.isArray(node?.dependsOn) ? node.dependsOn : [];
2249
- function holders(scene) {
2250
- const out = /* @__PURE__ */ new Map();
2251
- for (const node of scene.renderOrderNodes()) {
2252
- if (diagramGroupOf(node) === null) continue;
2253
- for (const dep of depsOf(node)) {
2254
- const member = scene.get(dep);
2255
- if (member !== void 0 && diagramLabelOf(member) === null) out.set(dep, node.id);
2550
+ // `opts.id` names the action; the layer keeps its own id.
2551
+ layer: edgeEndLayer(opts.participants, opts.selected, { ...opts, id: EDGE_END_LAYER_ID }),
2552
+ contribution: {
2553
+ id: "weasel-diagram-edge-ends",
2554
+ eligibility: { claimed: true },
2555
+ actions: [createReconnectAction({ ...opts, id: actionId }), grabPortAction(GRAB_EDGE_END_ACTION_ID)],
2556
+ bindings: [
2557
+ reconnectBinding(actionId),
2558
+ ...grabPortBindings(GRAB_EDGE_END_ACTION_ID, EDGE_END_AFFORDANCE_KIND)
2559
+ ]
2256
2560
  }
2257
- }
2258
- return out;
2259
- }
2260
- function membersOf(scene, group) {
2261
- return depsOf(scene.get(group)).filter((id) => {
2262
- const node = scene.get(id);
2263
- return node !== void 0 && diagramLabelOf(node) === null;
2264
- });
2265
- }
2266
- function reorderTargetOf(scene, id, boxOf) {
2267
- const held = holders(scene);
2268
- for (let member = id, group = held.get(id); group !== void 0; member = group, group = held.get(group)) {
2269
- const axis = diagramGroupOf(scene.get(group))?.reorder;
2270
- if (axis === void 0) continue;
2271
- const start = (m) => {
2272
- const box = boxOf(m);
2273
- return box === null ? 0 : axis === "x" ? box.x : box.y;
2274
- };
2275
- const members2 = membersOf(scene, group).sort((a, b) => start(a) - start(b));
2276
- return { group, axis, member, members: members2 };
2277
- }
2278
- return null;
2279
- }
2280
- function carriedWith(scene, member) {
2281
- const out = /* @__PURE__ */ new Set();
2282
- const visit = (id) => {
2283
- if (out.has(id)) return;
2284
- out.add(id);
2285
- const node = scene.get(id);
2286
- if (node !== void 0 && diagramGroupOf(node) !== null) depsOf(node).forEach(visit);
2287
- scene.childrenOf?.(id).forEach(visit);
2288
2561
  };
2289
- visit(member);
2290
- for (const node of scene.renderOrderNodes()) {
2291
- const on = depsOf(node)[0];
2292
- if (on !== void 0 && out.has(on) && diagramAnchorOf(node) !== null) out.add(node.id);
2293
- }
2294
- return out;
2295
2562
  }
2296
-
2297
- // src/groupReorder.ts
2298
2563
  var STEP_REORDER_ACTION_ID = "diagram.stepReorder";
2299
2564
  var sceneOf = (deps) => deps?.scene;
2300
2565
  function targetAt(deps, id) {
@@ -2336,17 +2601,21 @@ function createStepReorderAction(report) {
2336
2601
  if (target === null || params?.axis !== target.axis) return;
2337
2602
  const { members: members2, member } = target;
2338
2603
  const at = members2.indexOf(member);
2339
- const to = at + (params.step === -1 ? -1 : 1);
2340
- if (to < 0 || to >= members2.length) return;
2341
- const order = [...members2];
2342
- order.splice(at, 1);
2343
- order.splice(to, 0, member);
2344
- report({ group: target.group, order });
2604
+ const to = nudgeGap([at], params.step === -1 ? -1 : 1, members2.length);
2605
+ if (to === null) return;
2606
+ report({ parent: target.parent, order: moveItems(members2, [at], to) });
2345
2607
  }
2346
2608
  },
2347
2609
  enabled: (deps) => selectedTarget(deps) !== null ? true : ActionDisabledReason.NotApplicable
2348
2610
  };
2349
2611
  }
2612
+ function containerRegion(deps, member) {
2613
+ const scene = sceneOf(deps);
2614
+ const parent = targetAt(deps, member)?.parent;
2615
+ const node = parent === void 0 ? void 0 : scene?.get(parent);
2616
+ if (scene === void 0 || node === void 0 || diagramContainerOf(node)?.role !== "container") return null;
2617
+ return worldRectOf(scene, parent);
2618
+ }
2350
2619
  var onBody2 = bodyPredicate((target) => target === "selected-body" || target === "unselected-body");
2351
2620
  function groupReorderContribution(report) {
2352
2621
  const drag = reorderContribution({
@@ -2354,9 +2623,10 @@ function groupReorderContribution(report) {
2354
2623
  requires: ["nodeAtPoint"],
2355
2624
  show: "slide",
2356
2625
  on: onBody2,
2626
+ region: (deps, item) => containerRegion(deps, item.id),
2357
2627
  commit: (move, ctx) => {
2358
- const group = targetAt(ctx.deps, move.id)?.group;
2359
- if (group !== void 0) report({ group, order: move.order });
2628
+ const parent = targetAt(ctx.deps, move.id)?.parent;
2629
+ if (parent !== void 0) report({ parent, order: move.order });
2360
2630
  }
2361
2631
  });
2362
2632
  return { ...drag, id: "weasel-diagram-reorder", actions: [...drag.actions ?? [], createStepReorderAction(report)] };
@@ -2365,11 +2635,8 @@ function groupReorderContribution(report) {
2365
2635
  // src/labels/specLabels.ts
2366
2636
  var routeOf = edgeRouter();
2367
2637
  function inputOf(specs) {
2368
- const byId = new Map(specs.map((s) => [s.id, s]));
2369
- const dep = (id) => {
2370
- const s = byId.get(id);
2371
- return s === void 0 ? void 0 : { node: { ...s, parent: null }, pose: s.pose, path: null };
2372
- };
2638
+ const world = specWorldPoses(specs);
2639
+ const dep = specDeps(specs, world);
2373
2640
  const shapes = [];
2374
2641
  const routes = [];
2375
2642
  const labels = [];
@@ -2389,7 +2656,7 @@ function inputOf(specs) {
2389
2656
  }
2390
2657
  const node = { id, kind: spec.kind, data: spec.data };
2391
2658
  if (spec.derivePose !== void 0 || diagramContainerOf(node) !== null || diagramGroupOf(node) !== null || diagramNodeOf(node) === null) continue;
2392
- shapes.push({ id, box: spec.pose });
2659
+ shapes.push({ id, box: world.get(id) ?? spec.pose });
2393
2660
  }
2394
2661
  return { shapes, routes, labels };
2395
2662
  }
@@ -2500,7 +2767,8 @@ var LAYOUTS = Object.freeze({
2500
2767
  layered,
2501
2768
  tree,
2502
2769
  force,
2503
- chain
2770
+ chain,
2771
+ radial
2504
2772
  });
2505
2773
  function applyLayout(scene, result, opts = {}) {
2506
2774
  const poses = layoutPoses(scene, result, opts.geometry);
@@ -2518,39 +2786,52 @@ function applyLayout(scene, result, opts = {}) {
2518
2786
  return moved;
2519
2787
  }
2520
2788
  function layoutPoses(scene, result, geometry = AUTO_POSE_DESCRIPTOR) {
2789
+ const sc = scene;
2790
+ const { compose, decompose } = sc.composition;
2791
+ const stored = scenePoseAdapter(sc);
2521
2792
  const out = /* @__PURE__ */ new Map();
2522
- for (const [id, at] of result) {
2523
- const node = scene.get(id);
2524
- if (node === void 0) continue;
2525
- const bounds = geometry.getBounds(node.pose);
2793
+ const decided = { ...stored, getPose: (id) => out.has(id) ? out.get(id) : stored.getPose(id) };
2794
+ const depth = (id) => {
2795
+ let d = 0;
2796
+ for (let at = scene.get(id)?.parent; at != null; at = scene.get(at)?.parent) d++;
2797
+ return d;
2798
+ };
2799
+ const ids = [...result.keys()].filter((id) => scene.get(id) !== void 0).sort((a, b) => depth(a) - depth(b));
2800
+ for (const id of ids) {
2801
+ const at = result.get(id);
2802
+ const world = composeWorldPose(stored, id, compose);
2803
+ const bounds = geometry.getBounds(world);
2526
2804
  const dx = at.x - bounds.x;
2527
2805
  const dy = at.y - bounds.y;
2528
2806
  if (dx === 0 && dy === 0) continue;
2529
- out.set(id, translatePoseViaDescriptor(node.pose, dx, dy, geometry));
2530
- for (const descendant of subtreeOf(scene, id)) {
2531
- const child = scene.get(descendant);
2532
- if (child === void 0) continue;
2533
- out.set(descendant, translatePoseViaDescriptor(child.pose, dx, dy, geometry));
2534
- }
2535
- }
2536
- return out;
2537
- }
2538
- function subtreeOf(scene, id) {
2539
- const out = [];
2540
- const stack = [...scene.childrenOf(id)];
2541
- while (stack.length > 0) {
2542
- const next = stack.pop();
2543
- out.push(next);
2544
- stack.push(...scene.childrenOf(next));
2807
+ const parent = scene.get(id).parent;
2808
+ out.set(id, rebaseLocalPose(decided, translatePoseViaDescriptor(world, dx, dy, geometry), parent, compose, decompose));
2809
+ const carried = carriedDescendants(sceneCarrySource(sc), id, (w) => translatePoseViaDescriptor(w, dx, dy, geometry));
2810
+ for (const [d, pose] of carried) out.set(d, pose);
2545
2811
  }
2546
2812
  return out;
2547
2813
  }
2548
2814
  var LAYOUT_ACTION_ID = "diagram.layout";
2549
- function createLayoutAction(opts) {
2550
- const algorithm = typeof opts.algorithm === "function" ? opts.algorithm : LAYOUTS[opts.algorithm ?? "layered"] ?? layered;
2551
- const build = {
2815
+ function layoutDiagram(scene, source, algorithm, opts = {}) {
2816
+ const fn = typeof algorithm === "function" ? algorithm : LAYOUTS[algorithm] ?? layered;
2817
+ const graph = buildGraph(source, {
2552
2818
  ...opts.read ? { read: opts.read } : {},
2553
2819
  ...opts.geometry ? { geometry: opts.geometry } : {}
2820
+ });
2821
+ const plan = planOf(fn, graph, opts.layout);
2822
+ return applyLayout(scene, plan.moves, {
2823
+ ...opts.geometry ? { geometry: opts.geometry } : {},
2824
+ ...opts.label ? { label: opts.label } : {},
2825
+ routes: routesOf(graph, plan)
2826
+ });
2827
+ }
2828
+ function createLayoutAction(opts) {
2829
+ const { read, geometry, layout, label } = opts;
2830
+ const options = {
2831
+ ...read ? { read } : {},
2832
+ ...geometry ? { geometry } : {},
2833
+ ...layout ? { layout } : {},
2834
+ ...label ? { label } : {}
2554
2835
  };
2555
2836
  return {
2556
2837
  id: opts.id ?? LAYOUT_ACTION_ID,
@@ -2561,14 +2842,7 @@ function createLayoutAction(opts) {
2561
2842
  timing: "immediate",
2562
2843
  run: (deps) => {
2563
2844
  const scene = deps["scene"];
2564
- if (scene === void 0) return;
2565
- const graph = buildGraph(opts.source, build);
2566
- const plan = planOf(algorithm, graph, opts.layout);
2567
- applyLayout(scene, plan.moves, {
2568
- ...opts.geometry ? { geometry: opts.geometry } : {},
2569
- ...opts.label ? { label: opts.label } : {},
2570
- routes: routesOf(graph, plan)
2571
- });
2845
+ if (scene !== void 0) layoutDiagram(scene, opts.source, opts.algorithm ?? "layered", options);
2572
2846
  }
2573
2847
  },
2574
2848
  enabled: () => true
@@ -2965,14 +3239,27 @@ var EASED_LAYOUTS = Object.freeze({
2965
3239
  tree,
2966
3240
  chain
2967
3241
  });
3242
+ function bodyRules(trait, box) {
3243
+ const layout = trait.body;
3244
+ if (layout?.dividers === void 0 || trait.outline === void 0) return [];
3245
+ const rows = recordedRows(layout);
3246
+ if (rows === null) return [];
3247
+ const spec = { outline: trait.outline, rows, padding: layout.padding, gap: layout.gap, verticalAlign: layout.verticalAlign };
3248
+ return layoutBody(spec, box).filter((b) => b.row.kind === "divider").map((b) => {
3249
+ const y = b.y + b.height / 2;
3250
+ return polylineFromPoints([{ x: b.x, y }, { x: b.x + b.width, y }]);
3251
+ });
3252
+ }
3253
+
3254
+ // src/shape.ts
2968
3255
  function diagramShape(opts = {}) {
2969
3256
  const geometry = opts.geometry ?? RECT_POSE_DESCRIPTOR;
2970
- const outlineOf = (node) => diagramNodeOf(node, opts.read)?.outline ?? laneOutlineOf(node);
3257
+ const outlineOf2 = (node) => diagramNodeOf(node, opts.read)?.outline ?? laneOutlineOf(node);
2971
3258
  return {
2972
3259
  id: opts.id ?? "diagram:outline",
2973
- matches: (node) => outlineOf(node) !== void 0,
3260
+ matches: (node) => outlineOf2(node) !== void 0,
2974
3261
  paint: (node, pose, ctx) => {
2975
- const outline = outlineOf(node);
3262
+ const outline = outlineOf2(node);
2976
3263
  if (outline === void 0) return [];
2977
3264
  const d = node.data;
2978
3265
  const box = geometry.getBounds(pose);
@@ -2982,17 +3269,21 @@ function diagramShape(opts = {}) {
2982
3269
  const stroke = declaredStroke && commandStroke(declaredStroke, box);
2983
3270
  const header = headerBox(box, diagramContainerOf(node)?.header);
2984
3271
  const divider = header === null || !stroke ? [] : [{ kind: "path", path: dividerPath(box, header), stroke }];
3272
+ const detailPath = stroke ? outlineDetail(outline, box) : null;
3273
+ const detail = stroke && detailPath ? [{ kind: "path", path: detailPath, stroke }] : [];
3274
+ const trait = diagramNodeOf(node, opts.read);
3275
+ const rules = stroke && trait !== null ? bodyRules(trait, box).map((path) => ({ kind: "path", path, stroke })) : [];
2985
3276
  return [{
2986
3277
  kind: "path",
2987
3278
  path: outlinePath(outline, box),
2988
3279
  ...fill ? { fill } : {},
2989
3280
  ...stroke ? { stroke } : {}
2990
- }, ...divider];
3281
+ }, ...detail, ...rules, ...divider];
2991
3282
  },
2992
3283
  // The drawn boundary, so picking and clipping follow the diamond rather
2993
3284
  // than its bounding box.
2994
3285
  silhouette: (node, pose) => {
2995
- const outline = outlineOf(node);
3286
+ const outline = outlineOf2(node);
2996
3287
  return outline === void 0 ? null : outlinePath(outline, geometry.getBounds(pose));
2997
3288
  }
2998
3289
  };
@@ -3007,17 +3298,24 @@ function registerDiagramShape(opts = {}) {
3007
3298
  // src/bodyNode.ts
3008
3299
  var isDiagramBody = (node) => diagramContainerOf(node) === null && diagramGroupOf(node) === null && dataKeyReader(node) !== null;
3009
3300
  var isBodyOrRegion = (node) => diagramContainerOf(node) !== null || isDiagramBody(node);
3301
+ function agrees(selection, want) {
3302
+ if (typeof want === "string" || want === null) return (selection.at(-1) ?? null) === want;
3303
+ return selection.length === want.length && want.every((id) => selection.includes(id));
3304
+ }
3010
3305
  function useMirroredSelection(selection, selected, onSelect) {
3011
3306
  const want = selected ?? null;
3307
+ const key = typeof want === "string" || want === null ? want : `\0${want.join("\0")}`;
3012
3308
  const pushed = useRef(void 0);
3013
3309
  useEffect(() => {
3014
- if (pushed.current === want) return;
3015
- pushed.current = want;
3016
- if ((selection.get()[0] ?? null) !== want) selection.set(want === null ? [] : [want]);
3017
- }, [want]);
3310
+ if (pushed.current === key) return;
3311
+ pushed.current = key;
3312
+ if (agrees(selection.get(), want)) return;
3313
+ selection.set(want === null ? [] : typeof want === "string" ? [want] : [...want]);
3314
+ }, [key]);
3018
3315
  const onSelectRef = useLatest(onSelect);
3019
3316
  return useCallback(() => {
3020
- onSelectRef.current?.(selection.get()[0] ?? null);
3317
+ const ids = [...selection.get()];
3318
+ onSelectRef.current?.(ids.at(-1) ?? null, ids);
3021
3319
  }, [selection, onSelectRef]);
3022
3320
  }
3023
3321
 
@@ -3035,10 +3333,11 @@ function laneList(scene, poolId) {
3035
3333
  function readRegions(scene) {
3036
3334
  const regions = /* @__PURE__ */ new Map();
3037
3335
  const pools = /* @__PURE__ */ new Map();
3336
+ const at = worldWith(scene);
3038
3337
  for (const n of scene.renderOrderNodes()) {
3039
3338
  const trait = diagramContainerOf(n);
3040
3339
  if (trait === null) continue;
3041
- const { x, y, width, height } = n.pose;
3340
+ const { x, y, width, height } = at(n.id);
3042
3341
  regions.set(n.id, { box: { x, y, width, height }, parent: n.parent, fitted: trait.fitted === true });
3043
3342
  if (trait.role === "pool") pools.set(n.id, laneList(scene, n.id));
3044
3343
  }
@@ -3086,9 +3385,11 @@ var routeOf2 = (edge) => ({ waypoints: edge.waypoints ?? NONE, ports: portsOf2(e
3086
3385
  function readScene(scene) {
3087
3386
  const nodes = /* @__PURE__ */ new Map();
3088
3387
  const routes = /* @__PURE__ */ new Map();
3388
+ const at = worldWith(scene);
3089
3389
  for (const n of scene.renderOrderNodes()) {
3090
3390
  if (isDiagramBody(n)) {
3091
- nodes.set(n.id, { x: n.pose.x, y: n.pose.y, parent: n.parent });
3391
+ const { x, y } = at(n.id);
3392
+ nodes.set(n.id, { x, y, parent: n.parent });
3092
3393
  continue;
3093
3394
  }
3094
3395
  if (diagramContainerOf(n) !== null) continue;
@@ -3101,18 +3402,19 @@ function diagramLayoutOf(specs) {
3101
3402
  const moves = [];
3102
3403
  const routes = [];
3103
3404
  const containers = [];
3405
+ const world = worldPosesOf(specs, RIGID_POSE_COMPOSITION);
3104
3406
  for (const s of specs) {
3105
3407
  const id = s.id;
3106
3408
  if (id === void 0) continue;
3107
3409
  if (isBodyOrRegion(s)) {
3108
3410
  const region = diagramContainerOf(s);
3109
3411
  const pinned = isPinned({ id, kind: s.kind, data: s.data });
3412
+ const { x, y, width, height } = world.get(id);
3110
3413
  if (region !== null) {
3111
3414
  if (!pinned && region.role !== "lane" && region.fitted !== true) {
3112
- const { x, y, width, height } = s.pose;
3113
3415
  containers.push({ kind: "box", id, box: { x, y, width, height } });
3114
3416
  }
3115
- } else if (!pinned) moves.push({ id, x: s.pose.x, y: s.pose.y });
3417
+ } else if (!pinned) moves.push({ id, x, y });
3116
3418
  continue;
3117
3419
  }
3118
3420
  const edge = diagramEdgeOf(s);
@@ -3177,14 +3479,20 @@ function laneResizeReports(scene, resize) {
3177
3479
  const lanes = laneList(scene, pool.id).map((l) => l.id === resize.laneId ? { ...l, size: resize.size } : l);
3178
3480
  const moves = [];
3179
3481
  const boxes = [];
3180
- for (const [id, pose] of laneResizeFrame(scene, pool, index, resize.size)) {
3181
- const node = scene.get(id);
3182
- if (node === void 0) continue;
3183
- const region = diagramContainerOf(node);
3184
- const { x, y, width, height } = pose;
3185
- if (region !== null) {
3186
- if (region.role === "container" && region.fitted !== true) boxes.push({ kind: "box", id, box: { x, y, width, height } });
3187
- } else if (isDiagramBody(node)) moves.push({ id, x, y });
3482
+ const after = worldWith(scene, laneResizeFrame(scene, pool, index, resize.size));
3483
+ const before = worldWith(scene);
3484
+ for (const lane of pool.lanes.slice(index + 1)) {
3485
+ for (const id of descendantsOf(scene, lane.id)) {
3486
+ const node = scene.get(id);
3487
+ if (node === void 0) continue;
3488
+ const { x, y, width, height } = after(id);
3489
+ const was = before(id);
3490
+ if (x === was.x && y === was.y) continue;
3491
+ const region = diagramContainerOf(node);
3492
+ if (region !== null) {
3493
+ if (region.role === "container" && region.fitted !== true) boxes.push({ kind: "box", id, box: { x, y, width, height } });
3494
+ } else if (isDiagramBody(node)) moves.push({ id, x, y });
3495
+ }
3188
3496
  }
3189
3497
  return { lanes: { kind: "lanes", pool: pool.id, lanes }, moves, boxes };
3190
3498
  }
@@ -3214,6 +3522,11 @@ function regionEditing(scene, selected, reports) {
3214
3522
  };
3215
3523
  return { layer: containers.layer, contributions: [containers.contribution, title] };
3216
3524
  }
3525
+ function descendantsOf(scene, id) {
3526
+ const out = [];
3527
+ for (const c of scene.childrenOf(id)) out.push(c, ...descendantsOf(scene, c));
3528
+ return out;
3529
+ }
3217
3530
 
3218
3531
  // src/diagramEditing.ts
3219
3532
  var AMBIENT = [dragPanContribution()];
@@ -3366,8 +3679,14 @@ function usePagesView(pages) {
3366
3679
  };
3367
3680
  }, [placed, fill]);
3368
3681
  }
3682
+ var DEFAULT_FIT_PADDING = 16;
3369
3683
  function diagramBounds(specs, extra) {
3370
- const boxes = specs.filter((s) => isBodyOrRegion(s) || diagramGroupOf(s) !== null).map((s) => s.pose);
3684
+ const world = worldPosesOf(specs, RIGID_POSE_COMPOSITION);
3685
+ const boxes = specs.filter((s) => isBodyOrRegion(s) || diagramGroupOf(s) !== null).map((s) => world.get(s.id ?? "") ?? s.pose);
3686
+ for (const s of specs) {
3687
+ const edge = diagramEdgeOf(s);
3688
+ for (const p of [...edge?.waypoints ?? [], ...edge?.route ?? []]) boxes.push({ x: p.x, y: p.y, width: 0, height: 0 });
3689
+ }
3371
3690
  if (extra !== void 0) boxes.push(extra);
3372
3691
  if (boxes.length === 0) return null;
3373
3692
  const x = Math.min(...boxes.map((b) => b.x));
@@ -3382,12 +3701,17 @@ function diagramBounds(specs, extra) {
3382
3701
  function fitDiagram(specs, size, fit = {}, extra) {
3383
3702
  const bounds = diagramBounds(specs, extra);
3384
3703
  if (bounds === null) return void 0;
3385
- return fitViewToBounds(bounds, size, { x: 0, y: 0, scale: { x: 1, y: 1 } }, {
3704
+ const view = fitViewToBounds(bounds, size, { x: 0, y: 0, scale: { x: 1, y: 1 } }, {
3386
3705
  maxScale: fit.maxScale ?? 1,
3387
3706
  ...fit.minScale !== void 0 ? { minScale: fit.minScale } : {},
3388
3707
  ...fit.anchor !== void 0 ? { anchor: fit.anchor } : {},
3389
- ...fit.padding !== void 0 ? { padding: fit.padding } : {}
3708
+ padding: fit.padding ?? DEFAULT_FIT_PADDING
3390
3709
  });
3710
+ return fit.bounds === void 0 ? view : clampView(view, fit.bounds, size);
3711
+ }
3712
+ function diagramViewBounds(specs, padding, extra) {
3713
+ const b = diagramBounds(specs, extra);
3714
+ return b === null ? void 0 : { x: b.x - padding, y: b.y - padding, width: b.width + 2 * padding, height: b.height + 2 * padding };
3391
3715
  }
3392
3716
  var IDENTITY = { x: 0, y: 0, scale: { x: 1, y: 1 } };
3393
3717
  var sameView = (a, b) => a.x === b.x && a.y === b.y && a.scale.x === b.scale.x && a.scale.y === b.scale.y;
@@ -3401,14 +3725,14 @@ function useDiagramFit(args) {
3401
3725
  const unsized = size.width === 0 || size.height === 0;
3402
3726
  const defaultView = useMemo(
3403
3727
  () => controlled || unsized ? void 0 : fitDiagram(specs, size, fit, extra),
3404
- // A later `specs` is the overflow check's to answer.
3728
+ // A later `specs` is the refit check's to answer.
3405
3729
  // eslint-disable-next-line react-hooks/exhaustive-deps
3406
3730
  [controlled, unsized, size.width, size.height, fit.minScale, fit.maxScale, fit.anchor, fit.padding, extra]
3407
3731
  );
3408
3732
  const [later, setLater] = useState(null);
3409
3733
  const target = later !== null && later.over === defaultView ? later.view : defaultView;
3410
3734
  const fitted = useRef(target);
3411
- const opts = useLatest({ controlled, unsized, size, fit, extra, defaultView, current: args.current });
3735
+ const opts = useLatest({ controlled, unsized, size, fit, extra, defaultView, current: args.current, refit: args.refit ?? "overflow" });
3412
3736
  useEffect(() => {
3413
3737
  const canvas = canvasRef.current;
3414
3738
  const was = fitted.current;
@@ -3423,10 +3747,11 @@ function useDiagramFit(args) {
3423
3747
  first.current = false;
3424
3748
  return;
3425
3749
  }
3426
- const { controlled: c, unsized: u, size: box, fit: f, extra: more, defaultView: over } = opts.current;
3750
+ const { controlled: c, unsized: u, size: box, fit: f, extra: more, defaultView: over, refit } = opts.current;
3427
3751
  const canvas = canvasRef.current;
3428
3752
  const bounds = diagramBounds(specs, more);
3429
- if (c || u || canvas === null || bounds === null || inView(bounds, canvas.getView(), box)) return;
3753
+ if (c || u || canvas === null || bounds === null) return;
3754
+ if (refit === "overflow" && inView(bounds, canvas.getView(), box)) return;
3430
3755
  setLater({ view: fitDiagram(specs, box, f, more), over });
3431
3756
  }, [specs, canvasRef, opts]);
3432
3757
  return useMemo(() => {
@@ -3464,6 +3789,7 @@ function Inner({
3464
3789
  hops,
3465
3790
  width,
3466
3791
  height,
3792
+ selectionMode = "single",
3467
3793
  selected,
3468
3794
  onSelect,
3469
3795
  onHover,
@@ -3478,6 +3804,9 @@ function Inner({
3478
3804
  onReorder,
3479
3805
  onEditContainer,
3480
3806
  connectBodies,
3807
+ canReparent,
3808
+ onDropItem,
3809
+ canDropItem,
3481
3810
  pickEdges,
3482
3811
  overlays = NO_OVERLAYS,
3483
3812
  ambient: extraAmbient,
@@ -3490,6 +3819,8 @@ function Inner({
3490
3819
  maxScale,
3491
3820
  anchor,
3492
3821
  fitPadding,
3822
+ bounded,
3823
+ refit,
3493
3824
  background,
3494
3825
  pages,
3495
3826
  view,
@@ -3516,7 +3847,7 @@ function Inner({
3516
3847
  initial: specs,
3517
3848
  registry
3518
3849
  });
3519
- const selection = useSelection({ scene, mode: "single" });
3850
+ const selection = useSelection({ scene, mode: selectionMode === "multiple" ? "multi" : "single" });
3520
3851
  const onClick = useMirroredSelection(selection, selected, onSelect);
3521
3852
  useSceneSync(scene, specs, { onMove, onEditContainer });
3522
3853
  const source = useMemo(() => sceneParticipants(scene), [scene]);
@@ -3527,14 +3858,19 @@ function Inner({
3527
3858
  const { layers, box: pagesBox } = usePagesView(pages);
3528
3859
  const canvasRef = useRef(null);
3529
3860
  const current = useCallback(() => Array.from(source(), ({ node, pose }) => ({ ...node, pose })), [source]);
3861
+ const viewBounds = useMemo(
3862
+ () => bounded ? diagramViewBounds(specs, fitPadding ?? DEFAULT_FIT_PADDING, pagesBox) : void 0,
3863
+ [bounded, specs, fitPadding, pagesBox]
3864
+ );
3530
3865
  const fitting = useDiagramFit({
3531
3866
  canvasRef,
3532
3867
  specs,
3533
3868
  current,
3534
3869
  controlled,
3535
3870
  size: { width: width ?? measured?.width ?? 0, height: height ?? measured?.height ?? 0 },
3536
- fit: { minScale, maxScale, anchor, padding: fitPadding },
3537
- extra: pagesBox
3871
+ fit: { minScale, maxScale, anchor, padding: fitPadding, ...viewBounds ? { bounds: viewBounds } : {} },
3872
+ extra: pagesBox,
3873
+ ...refit ? { refit } : {}
3538
3874
  });
3539
3875
  const { defaultView } = fitting;
3540
3876
  const settled = useLatest((moved) => {
@@ -3573,6 +3909,8 @@ function Inner({
3573
3909
  portOptions,
3574
3910
  ambient: extraAmbient
3575
3911
  });
3912
+ const itemDrop = useItemDrop(source, { onDropItem, canDropItem });
3913
+ const ambient = useMemo(() => itemDrop === null ? editing.ambient : [...editing.ambient, itemDrop], [editing.ambient, itemDrop]);
3576
3914
  useEffect(() => {
3577
3915
  const canvas = canvasRef.current;
3578
3916
  if (canvas === null) return;
@@ -3596,7 +3934,7 @@ function Inner({
3596
3934
  features,
3597
3935
  ...resizes ? { selectTool } : {},
3598
3936
  enableKeybindings: enableKeybindings ?? edits,
3599
- ambient: editing.ambient,
3937
+ ambient,
3600
3938
  actions: editing.actions,
3601
3939
  onClick,
3602
3940
  ...onHover ? { onHover } : {},
@@ -3606,9 +3944,10 @@ function Inner({
3606
3944
  ...defaultView ? { defaultView } : {},
3607
3945
  ...view ? { view } : {},
3608
3946
  ...onViewChange ? { onViewChange } : {},
3947
+ ...viewBounds ? { viewBounds } : {},
3609
3948
  ...background ? { backgroundFill: background } : {},
3610
3949
  ...layers ? { layers } : {},
3611
- children: /* @__PURE__ */ jsx(DropRules, { scene })
3950
+ children: /* @__PURE__ */ jsx(DropRules, { scene, canReparent })
3612
3951
  }
3613
3952
  ),
3614
3953
  overlays.map((o) => {
@@ -3618,8 +3957,13 @@ function Inner({
3618
3957
  ] });
3619
3958
  }
3620
3959
  var NO_OVERLAYS = [];
3621
- function DropRules({ scene }) {
3622
- const canDropInto = useMemo(() => diagramCanDropInto(scene), [scene]);
3960
+ function DropRules({ scene, canReparent }) {
3961
+ const latest = useLatest(canReparent);
3962
+ const asks = canReparent !== void 0;
3963
+ const canDropInto = useMemo(
3964
+ () => diagramCanDropInto(scene, asks ? (ids, into) => latest.current?.(ids, into) ?? true : void 0),
3965
+ [scene, asks, latest]
3966
+ );
3623
3967
  useDepSource("canDropInto", () => canDropInto);
3624
3968
  return null;
3625
3969
  }
@@ -3653,6 +3997,6 @@ function useDiagramApi(apiRef, canvasRef, scene, live, setRun, fitNow) {
3653
3997
  }), [canvasRef, live, scene, setRun, fitNow]);
3654
3998
  }
3655
3999
 
3656
- export { ADD_LANE_ACTION_ID, ANYWHERE, CONNECT_ACTION_ID, CONTAINER_STENCILS, DEFAULT_EDGE_STROKE, DiagramView, EASED_LAYOUTS, EDGE_END_AFFORDANCE_KIND, EDGE_END_LAYER_ID, EDIT_CONTAINER_TITLE_ACTION_ID, GRAB_EDGE_END_ACTION_ID, GRAB_LABEL_ACTION_ID, GRAB_PORT_ACTION_ID, GRAB_WAYPOINT_ACTION_ID, LANE_AFFORDANCE_KIND, LANE_LAYER_ID, LANE_RESIZE_ACTION_ID, LAYOUTS, LAYOUT_ACTION_ID, MOVE_LABEL_ACTION_ID, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, RECONNECT_ACTION_ID, RELEASE_MEMBERS_ACTION_ID, REMOVE_WAYPOINT_ACTION_ID, REORDER_ACTION_ID, RESET_LABEL_ACTION_ID, RESET_ROUTE_ACTION_ID, ROUTER_LABELS, ROUTE_EDIT_ACTION_ID, SELECT_LABEL_EDGE_ACTION_ID, SET_HOPS_ACTION_ID, SET_ROUTER_ACTION_IDS, STEP_REORDER_ACTION_ID, WAYPOINT_AFFORDANCE_KIND, WAYPOINT_HIT_PX, WAYPOINT_LAYER_ID, addLane, applyLayout, avoidSceneInput, bodyAt, commitEdgeToScene, commitLabelToScene, commitLaneResizeToScene, commitReconnectToScene, commitRouteToScene, commitRouterToScene, connectBinding, containerBuild, createAddLaneAction, createConnectAction, createDiagramContribution, createEdgeEndAffordance, createLabelDragAction, createLaneAffordance, createLaneResizeAction, createLayoutAction, createPortAffordance, createReconnectAction, createReleaseMembersAction, createRemoveWaypointAction, createReorderAction, createResetLabelAction, createResetRouteAction, createRouteEditAction, createSetHopsAction, createSetRouterAction, createSpecHops, createSpecLabelPlacer, createSpecRouter, createStepReorderAction, createWaypointAffordance, defaultCanConnect, diagramCanDropInto, diagramContainers, diagramDropParentAt, diagramEdgeEnds, diagramLabelDrag, diagramLayoutOf, diagramPorts, diagramResizable, diagramShape, diagramWaypoints, dragSegment, dragVertex, easedProducer, edgeEndLayer, edgeEndScratchOf, edgePolylines, editContainerTitleAction, editContainerTitleBinding, forceProducer, grabPortAction, grabPortBindings, groupReorderContribution, groupReorderSlots, headerIdOf, hopDataOps, inOrUnder, insertWaypoint, isBodyEnd, isBodyOrRegion, isDiagramBody, laneLayer, laneResizeFrame, laneScratchOf, lanesOf, layoutPoses, movedLabelData, pinSegment, poolAxisOf, poolsOf, portLayer, portScratchOf, reconnectBinding, regionHeaderAt, registerDiagramShape, releaseMembers, removeSegment, removeWaypoint, reorderBinding, reorderContribution, routeHandles, routeStateOf, routeWrites, routedData, routerActions, routesOf, sceneEdges, sceneParticipants, segmentAxis, sequenceSlots, themeWrites, unpinSegment, useLiveLayout, useMirroredSelection, waypointLayer, waypointScratchOf, withHopsData, withRouter };
3657
- //# sourceMappingURL=chunk-ESFIS7BB.js.map
3658
- //# sourceMappingURL=chunk-ESFIS7BB.js.map
4000
+ export { ADD_LANE_ACTION_ID, ANYWHERE, CONNECT_ACTION_ID, CONTAINERS_GROUP, CONTAINER_STENCILS, DEFAULT_EDGE_STROKE, DIAGRAM_ITEM_CARRY, DiagramView, EASED_LAYOUTS, EDGE_END_AFFORDANCE_KIND, EDGE_END_LAYER_ID, EDIT_CONTAINER_TITLE_ACTION_ID, GRAB_EDGE_END_ACTION_ID, GRAB_LABEL_ACTION_ID, GRAB_PORT_ACTION_ID, GRAB_WAYPOINT_ACTION_ID, ITEM_DROP_ACTION_ID, LANE_AFFORDANCE_KIND, LANE_LAYER_ID, LANE_RESIZE_ACTION_ID, LAYOUTS, LAYOUT_ACTION_ID, MOVE_LABEL_ACTION_ID, PORT_AFFORDANCE_KIND, PORT_LAYER_ID, RECONNECT_ACTION_ID, RELEASE_MEMBERS_ACTION_ID, REMOVE_WAYPOINT_ACTION_ID, REORDER_ACTION_ID, RESET_LABEL_ACTION_ID, RESET_ROUTE_ACTION_ID, ROUTER_LABELS, ROUTE_EDIT_ACTION_ID, SELECT_LABEL_EDGE_ACTION_ID, SET_HOPS_ACTION_ID, SET_ROUTER_ACTION_IDS, STEP_REORDER_ACTION_ID, WAYPOINT_AFFORDANCE_KIND, WAYPOINT_HIT_PX, WAYPOINT_LAYER_ID, addLane, applyLayout, avoidSceneInput, bodyAt, commitEdgeToScene, commitLabelToScene, commitLaneResizeToScene, commitReconnectToScene, commitRouteToScene, commitRouterToScene, connectBinding, containerBuild, createAddLaneAction, createConnectAction, createDiagramContribution, createEdgeEndAffordance, createItemDropAction, createLabelDragAction, createLaneAffordance, createLaneResizeAction, createLayoutAction, createPortAffordance, createReconnectAction, createReleaseMembersAction, createRemoveWaypointAction, createReorderAction, createResetLabelAction, createResetRouteAction, createRouteEditAction, createSetHopsAction, createSetRouterAction, createSpecHops, createSpecLabelPlacer, createSpecRouter, createStepReorderAction, createWaypointAffordance, defaultCanConnect, diagramCanDropInto, diagramContainers, diagramDropParentAt, diagramEdgeEnds, diagramLabelDrag, diagramLayoutOf, diagramPorts, diagramResizable, diagramShape, diagramWaypoints, dragItemProps, dragSegment, dragVertex, easedProducer, edgeEndLayer, edgeEndScratchOf, edgePolylines, editContainerTitleAction, editContainerTitleBinding, forceProducer, grabPortAction, grabPortBindings, groupReorderContribution, groupReorderSlots, headerIdOf, hopDataOps, inOrUnder, insertWaypoint, isBodyEnd, isBodyOrRegion, isDiagramBody, itemDropContribution, laneLayer, laneResizeFrame, laneScratchOf, lanesOf, layoutDiagram, layoutPoses, movedLabelData, pinSegment, poolAxisOf, poolsOf, portLayer, portScratchOf, reconnectBinding, regionHeaderAt, registerDiagramShape, releaseMembers, removeSegment, removeWaypoint, reorderBinding, reorderContribution, routeHandles, routeStateOf, routeWrites, routedData, routerActions, routesOf, sceneEdges, sceneParticipants, segmentAxis, sequenceSlots, startItemDrag, themeWrites, unpinSegment, useLiveLayout, useMirroredSelection, waypointLayer, waypointScratchOf, withHopsData, withRouter, worldWith };
4001
+ //# sourceMappingURL=chunk-62SMY45E.js.map
4002
+ //# sourceMappingURL=chunk-62SMY45E.js.map