@pixerate/editor 0.22.0 → 0.24.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 (188) hide show
  1. package/README.md +175 -2
  2. package/THIRD_PARTY_NOTICES.md +139 -0
  3. package/dist/agent/index.cjs +87 -111
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +70 -211
  6. package/dist/agent/index.d.ts +70 -211
  7. package/dist/agent/index.js +78 -102
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/arrangeShortcuts-B8O3f8-P.d.cts +184 -0
  10. package/dist/arrangeShortcuts-sLlD2rSX.d.ts +184 -0
  11. package/dist/canvas/index.cjs +2075 -86
  12. package/dist/canvas/index.cjs.map +1 -1
  13. package/dist/canvas/index.d.cts +608 -186
  14. package/dist/canvas/index.d.ts +608 -186
  15. package/dist/canvas/index.js +2060 -71
  16. package/dist/canvas/index.js.map +1 -1
  17. package/dist/chunk-26BVFKHU.cjs +453 -0
  18. package/dist/chunk-26BVFKHU.cjs.map +1 -0
  19. package/dist/chunk-2H7ZHPEJ.js +762 -0
  20. package/dist/chunk-2H7ZHPEJ.js.map +1 -0
  21. package/dist/{chunk-DENSCKFC.js → chunk-3CN2WD3X.js} +1730 -189
  22. package/dist/chunk-3CN2WD3X.js.map +1 -0
  23. package/dist/{chunk-JJDLPEWL.js → chunk-3LV6RRPH.js} +2 -2
  24. package/dist/{chunk-MJZBNWG7.js → chunk-5S3Z4PPF.js} +78 -557
  25. package/dist/chunk-5S3Z4PPF.js.map +1 -0
  26. package/dist/chunk-664LQYFJ.js +115 -0
  27. package/dist/chunk-664LQYFJ.js.map +1 -0
  28. package/dist/chunk-7DWMJCAT.js +453 -0
  29. package/dist/chunk-7DWMJCAT.js.map +1 -0
  30. package/dist/chunk-ARRTP33I.js +101 -0
  31. package/dist/chunk-ARRTP33I.js.map +1 -0
  32. package/dist/chunk-CPOKFNBG.cjs +101 -0
  33. package/dist/chunk-CPOKFNBG.cjs.map +1 -0
  34. package/dist/{chunk-AA4ZEVCC.cjs → chunk-D27YFC46.cjs} +101 -580
  35. package/dist/chunk-D27YFC46.cjs.map +1 -0
  36. package/dist/chunk-D6FH2YAX.cjs +131 -0
  37. package/dist/chunk-D6FH2YAX.cjs.map +1 -0
  38. package/dist/{chunk-4SUNJZWB.cjs → chunk-FD4LPFAE.cjs} +48 -200
  39. package/dist/chunk-FD4LPFAE.cjs.map +1 -0
  40. package/dist/chunk-FODNLX5N.js +749 -0
  41. package/dist/chunk-FODNLX5N.js.map +1 -0
  42. package/dist/{chunk-OYXSKQFR.js → chunk-FPENXAEJ.js} +35 -187
  43. package/dist/chunk-FPENXAEJ.js.map +1 -0
  44. package/dist/chunk-G2I4QJOT.cjs +762 -0
  45. package/dist/chunk-G2I4QJOT.cjs.map +1 -0
  46. package/dist/chunk-HLIMTC6N.js +1 -0
  47. package/dist/chunk-HLIMTC6N.js.map +1 -0
  48. package/dist/{chunk-QGHGJ56O.js → chunk-ITBSKI26.js} +1483 -19
  49. package/dist/chunk-ITBSKI26.js.map +1 -0
  50. package/dist/{chunk-6M3BCTBD.cjs → chunk-MA2F5KHF.cjs} +470 -242
  51. package/dist/chunk-MA2F5KHF.cjs.map +1 -0
  52. package/dist/{chunk-SAZRENEZ.cjs → chunk-MCSJFWAO.cjs} +1733 -192
  53. package/dist/chunk-MCSJFWAO.cjs.map +1 -0
  54. package/dist/chunk-MKA3AHLV.cjs +256 -0
  55. package/dist/chunk-MKA3AHLV.cjs.map +1 -0
  56. package/dist/chunk-OLZJXL4R.cjs +749 -0
  57. package/dist/chunk-OLZJXL4R.cjs.map +1 -0
  58. package/dist/chunk-OXSV64JX.js +689 -0
  59. package/dist/chunk-OXSV64JX.js.map +1 -0
  60. package/dist/chunk-P3RQ5UJE.cjs +689 -0
  61. package/dist/chunk-P3RQ5UJE.cjs.map +1 -0
  62. package/dist/chunk-P6ODPZ4W.js +256 -0
  63. package/dist/chunk-P6ODPZ4W.js.map +1 -0
  64. package/dist/chunk-PGNZKFQS.js +685 -0
  65. package/dist/chunk-PGNZKFQS.js.map +1 -0
  66. package/dist/chunk-PL4JB3BF.cjs +1 -0
  67. package/dist/chunk-PL4JB3BF.cjs.map +1 -0
  68. package/dist/{chunk-GVSMRPHB.cjs → chunk-SBCZ6RN5.cjs} +1568 -104
  69. package/dist/chunk-SBCZ6RN5.cjs.map +1 -0
  70. package/dist/{chunk-CL37JGFW.cjs → chunk-SML64VJG.cjs} +4 -4
  71. package/dist/{chunk-CL37JGFW.cjs.map → chunk-SML64VJG.cjs.map} +1 -1
  72. package/dist/chunk-TNNJXF46.cjs +115 -0
  73. package/dist/chunk-TNNJXF46.cjs.map +1 -0
  74. package/dist/chunk-U5HZSFCS.js +131 -0
  75. package/dist/chunk-U5HZSFCS.js.map +1 -0
  76. package/dist/{chunk-RU52I7QO.js → chunk-U5KWZU4X.js} +388 -160
  77. package/dist/chunk-U5KWZU4X.js.map +1 -0
  78. package/dist/chunk-XNORY7M6.cjs +685 -0
  79. package/dist/chunk-XNORY7M6.cjs.map +1 -0
  80. package/dist/commands/index.cjs +860 -0
  81. package/dist/commands/index.cjs.map +1 -0
  82. package/dist/commands/index.d.cts +244 -0
  83. package/dist/commands/index.d.ts +244 -0
  84. package/dist/commands/index.js +860 -0
  85. package/dist/commands/index.js.map +1 -0
  86. package/dist/comment-store-BEMgVlAA.d.cts +135 -0
  87. package/dist/comment-store-BEMgVlAA.d.ts +135 -0
  88. package/dist/compare/index.cjs +15 -0
  89. package/dist/compare/index.cjs.map +1 -0
  90. package/dist/compare/index.d.cts +58 -0
  91. package/dist/compare/index.d.ts +58 -0
  92. package/dist/compare/index.js +15 -0
  93. package/dist/compare/index.js.map +1 -0
  94. package/dist/{controller-B7GIybc4.d.cts → controller-BhLLAoi8.d.cts} +119 -5
  95. package/dist/{controller-B7GIybc4.d.ts → controller-BhLLAoi8.d.ts} +119 -5
  96. package/dist/documents-BQjzJNe2.d.ts +76 -0
  97. package/dist/documents-KRTPhvst.d.cts +76 -0
  98. package/dist/extensions/index.cjs +53 -5
  99. package/dist/extensions/index.cjs.map +1 -1
  100. package/dist/extensions/index.d.cts +7 -3
  101. package/dist/extensions/index.d.ts +7 -3
  102. package/dist/extensions/index.js +52 -4
  103. package/dist/generation/index.cjs +1373 -0
  104. package/dist/generation/index.cjs.map +1 -0
  105. package/dist/generation/index.d.cts +554 -0
  106. package/dist/generation/index.d.ts +554 -0
  107. package/dist/generation/index.js +1373 -0
  108. package/dist/generation/index.js.map +1 -0
  109. package/dist/grammar/index.cjs +48 -3
  110. package/dist/grammar/index.cjs.map +1 -1
  111. package/dist/grammar/index.d.cts +322 -100
  112. package/dist/grammar/index.d.ts +322 -100
  113. package/dist/grammar/index.js +54 -9
  114. package/dist/history/index.cjs +12 -2
  115. package/dist/history/index.cjs.map +1 -1
  116. package/dist/history/index.d.cts +211 -7
  117. package/dist/history/index.d.ts +211 -7
  118. package/dist/history/index.js +13 -3
  119. package/dist/image-editor/index.cjs +2244 -38
  120. package/dist/image-editor/index.cjs.map +1 -1
  121. package/dist/image-editor/index.d.cts +742 -4
  122. package/dist/image-editor/index.d.ts +742 -4
  123. package/dist/image-editor/index.js +2222 -16
  124. package/dist/image-editor/index.js.map +1 -1
  125. package/dist/{index-CCr_z9kF.d.cts → index-BhJBSm2d.d.cts} +370 -4
  126. package/dist/{index-Ck6ajwXh.d.ts → index-fJrlkJCd.d.ts} +370 -4
  127. package/dist/index.cjs +193 -98
  128. package/dist/index.cjs.map +1 -1
  129. package/dist/index.d.cts +17 -48
  130. package/dist/index.d.ts +17 -48
  131. package/dist/index.js +198 -103
  132. package/dist/index.js.map +1 -1
  133. package/dist/migrate-iTlm3a8h.d.cts +112 -0
  134. package/dist/migrate-iTlm3a8h.d.ts +112 -0
  135. package/dist/persistence/index.cjs +676 -0
  136. package/dist/persistence/index.cjs.map +1 -0
  137. package/dist/persistence/index.d.cts +347 -0
  138. package/dist/persistence/index.d.ts +347 -0
  139. package/dist/persistence/index.js +676 -0
  140. package/dist/persistence/index.js.map +1 -0
  141. package/dist/registry-BDe-vlv3.d.ts +171 -0
  142. package/dist/registry-D32LpIc4.d.cts +354 -0
  143. package/dist/registry-DnzpgY27.d.cts +171 -0
  144. package/dist/registry-evKTP4ls.d.ts +354 -0
  145. package/dist/schema-DYDGdYL9.d.cts +41 -0
  146. package/dist/schema-DYDGdYL9.d.ts +41 -0
  147. package/dist/serializers/index.cjs +4 -3
  148. package/dist/serializers/index.cjs.map +1 -1
  149. package/dist/serializers/index.d.cts +2 -1
  150. package/dist/serializers/index.d.ts +2 -1
  151. package/dist/serializers/index.js +3 -2
  152. package/dist/sourcemap-C8AH3MBQ.d.cts +91 -0
  153. package/dist/sourcemap-DA1Evhrv.d.ts +91 -0
  154. package/dist/spreadsheet/index.cjs +53 -3
  155. package/dist/spreadsheet/index.cjs.map +1 -1
  156. package/dist/spreadsheet/index.d.cts +247 -18
  157. package/dist/spreadsheet/index.d.ts +247 -18
  158. package/dist/spreadsheet/index.js +58 -8
  159. package/dist/{tokens-CyLZmIei.d.cts → tokens-D7yXvUU6.d.cts} +15 -2
  160. package/dist/{tokens-CyLZmIei.d.ts → tokens-D7yXvUU6.d.ts} +15 -2
  161. package/dist/{track-changes-BSF58RK0.d.cts → track-changes-BK5sVf4_.d.cts} +18 -136
  162. package/dist/{track-changes-BSF58RK0.d.ts → track-changes-CDjCrwKe.d.ts} +18 -136
  163. package/dist/{types-CJ4U-HHI.d.ts → types-DX4Mh4SL.d.cts} +1 -1
  164. package/dist/{types-CJ4U-HHI.d.cts → types-DX4Mh4SL.d.ts} +1 -1
  165. package/dist/types-GT5a5YAX.d.cts +86 -0
  166. package/dist/types-GT5a5YAX.d.ts +86 -0
  167. package/package.json +23 -2
  168. package/dist/chunk-2TWGLC5K.cjs +0 -262
  169. package/dist/chunk-2TWGLC5K.cjs.map +0 -1
  170. package/dist/chunk-4SUNJZWB.cjs.map +0 -1
  171. package/dist/chunk-6M3BCTBD.cjs.map +0 -1
  172. package/dist/chunk-AA4ZEVCC.cjs.map +0 -1
  173. package/dist/chunk-AXV2ZW34.cjs +0 -118
  174. package/dist/chunk-AXV2ZW34.cjs.map +0 -1
  175. package/dist/chunk-B2ZRLN4S.js +0 -118
  176. package/dist/chunk-B2ZRLN4S.js.map +0 -1
  177. package/dist/chunk-DENSCKFC.js.map +0 -1
  178. package/dist/chunk-GVSMRPHB.cjs.map +0 -1
  179. package/dist/chunk-KAADNAPF.js +0 -262
  180. package/dist/chunk-KAADNAPF.js.map +0 -1
  181. package/dist/chunk-MJZBNWG7.js.map +0 -1
  182. package/dist/chunk-OYXSKQFR.js.map +0 -1
  183. package/dist/chunk-QGHGJ56O.js.map +0 -1
  184. package/dist/chunk-RU52I7QO.js.map +0 -1
  185. package/dist/chunk-SAZRENEZ.cjs.map +0 -1
  186. package/dist/types-BZgcDsC5.d.cts +0 -42
  187. package/dist/types-BZgcDsC5.d.ts +0 -42
  188. /package/dist/{chunk-JJDLPEWL.js.map → chunk-3LV6RRPH.js.map} +0 -0
@@ -1,4 +1,8 @@
1
- "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5;
1
+ "use strict";Object.defineProperty(exports, "__esModule", {value: true}); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _nullishCoalesce(lhs, rhsFn) { if (lhs != null) { return lhs; } else { return rhsFn(); } } function _optionalChain(ops) { let lastAccessLHS = undefined; let value = ops[0]; let i = 1; while (i < ops.length) { const op = ops[i]; const fn = ops[i + 1]; i += 2; if ((op === 'optionalAccess' || op === 'optionalCall') && value == null) { return undefined; } if (op === 'access' || op === 'optionalAccess') { lastAccessLHS = value; value = fn(value); } else if (op === 'call' || op === 'optionalCall') { value = fn((...args) => value.call(lastAccessLHS, ...args)); lastAccessLHS = undefined; } } return value; } var _class; var _class2; var _class3; var _class4; var _class5; var _class6;
2
+
3
+
4
+ var _chunk26BVFKHUcjs = require('../chunk-26BVFKHU.cjs');
5
+
2
6
 
3
7
 
4
8
 
@@ -1073,6 +1077,10 @@ function invertNodeUpdates(nodes, updates) {
1073
1077
  }
1074
1078
 
1075
1079
  // src/canvas/guides.ts
1080
+ function snapToGrid(value, spacing, origin = 0) {
1081
+ if (!(spacing > 0) || !Number.isFinite(spacing)) return value;
1082
+ return Math.round((value - origin) / spacing) * spacing + origin;
1083
+ }
1076
1084
  function buildAxis(entries) {
1077
1085
  entries.sort((a, b) => a.value - b.value);
1078
1086
  return {
@@ -1229,8 +1237,10 @@ function computeSnapGuides(moving, targets, options = {}) {
1229
1237
  };
1230
1238
  const sx = snapAxis(true);
1231
1239
  const sy = snapAxis(false);
1232
- const dx = _nullishCoalesce(sx.delta, () => ( 0));
1233
- const dy = _nullishCoalesce(sy.delta, () => ( 0));
1240
+ const grid = _nullishCoalesce(options.gridSize, () => ( 0));
1241
+ const gridDelta = (v, origin) => snapToGrid(v, grid, origin) - v;
1242
+ const dx = _nullishCoalesce(sx.delta, () => ( (grid > 0 ? gridDelta(moving.x, _nullishCoalesce(_optionalChain([options, 'access', _46 => _46.gridOrigin, 'optionalAccess', _47 => _47.x]), () => ( 0))) : 0)));
1243
+ const dy = _nullishCoalesce(sy.delta, () => ( (grid > 0 ? gridDelta(moving.y, _nullishCoalesce(_optionalChain([options, 'access', _48 => _48.gridOrigin, 'optionalAccess', _49 => _49.y]), () => ( 0))) : 0)));
1234
1244
  const snapped = { x: moving.x + dx, y: moving.y + dy, width: moving.width, height: moving.height };
1235
1245
  const guides = [];
1236
1246
  const alignmentGuides = (horizontal) => {
@@ -1244,12 +1254,12 @@ function computeSnapGuides(moving, targets, options = {}) {
1244
1254
  if (useCentres) {
1245
1255
  lines.push({ value: start + size / 2, kind: "centre", axis: horizontal ? index.centreX : index.centreY });
1246
1256
  }
1247
- for (const line of lines) {
1248
- const aligned = matches(line.axis, line.value, eps);
1257
+ for (const line2 of lines) {
1258
+ const aligned = matches(line2.axis, line2.value, eps);
1249
1259
  if (aligned.length === 0) continue;
1250
1260
  const span = _chunkWADCJ7A7cjs.boundsOf.call(void 0, [snapped, ...aligned]);
1251
1261
  guides.push(
1252
- horizontal ? { orientation: "vertical", kind: line.kind, x1: line.value, y1: span.y, x2: line.value, y2: span.y + span.height } : { orientation: "horizontal", kind: line.kind, x1: span.x, y1: line.value, x2: span.x + span.width, y2: line.value }
1262
+ horizontal ? { orientation: "vertical", kind: line2.kind, x1: line2.value, y1: span.y, x2: line2.value, y2: span.y + span.height } : { orientation: "horizontal", kind: line2.kind, x1: span.x, y1: line2.value, x2: span.x + span.width, y2: line2.value }
1253
1263
  );
1254
1264
  }
1255
1265
  };
@@ -1390,16 +1400,16 @@ function findConnectorSnap(pointer, targets, options = {}) {
1390
1400
  if (pointer.x < rect.x - radius || pointer.x > rect.x + rect.width + radius || pointer.y < rect.y - radius || pointer.y > rect.y + rect.height + radius) {
1391
1401
  continue;
1392
1402
  }
1393
- const inside = pointer.x >= rect.x && pointer.x <= rect.x + rect.width && pointer.y >= rect.y && pointer.y <= rect.y + rect.height;
1403
+ const inside2 = pointer.x >= rect.x && pointer.x <= rect.x + rect.width && pointer.y >= rect.y && pointer.y <= rect.y + rect.height;
1394
1404
  for (const position of _nullishCoalesce(target.positions, () => ( all))) {
1395
1405
  const point = options.mode === "edge" ? closestPointOnSide(rect, position, pointer) : handlePoint(rect, position);
1396
1406
  const sidePoint = closestPointOnSide(rect, position, pointer);
1397
1407
  const rank = Math.hypot(pointer.x - sidePoint.x, pointer.y - sidePoint.y);
1398
1408
  const distance = Math.hypot(pointer.x - point.x, pointer.y - point.y);
1399
- if (!inside && rank > radius) continue;
1400
- const better = !best || inside && !best.inside || inside === best.inside && rank < best.rank;
1409
+ if (!inside2 && rank > radius) continue;
1410
+ const better = !best || inside2 && !best.inside || inside2 === best.inside && rank < best.rank;
1401
1411
  if (better) {
1402
- best = { nodeId: target.id, position, side: positionToSide(position), point, distance, inside, rank };
1412
+ best = { nodeId: target.id, position, side: positionToSide(position), point, distance, inside: inside2, rank };
1403
1413
  }
1404
1414
  }
1405
1415
  }
@@ -1505,7 +1515,7 @@ var CanvasScenesStore = (_class3 = class {
1505
1515
  this.scenes = scenes;
1506
1516
  if (this.currentId && !scenes.some((s) => s.id === this.currentId)) this.currentId = null;
1507
1517
  this.cached = this.snapshot();
1508
- _optionalChain([this, 'access', _46 => _46.onChange, 'optionalCall', _47 => _47(this.cached)]);
1518
+ _optionalChain([this, 'access', _50 => _50.onChange, 'optionalCall', _51 => _51(this.cached)]);
1509
1519
  for (const listener of this.listeners) listener(this.cached);
1510
1520
  }
1511
1521
  getState() {
@@ -1533,7 +1543,7 @@ var CanvasScenesStore = (_class3 = class {
1533
1543
  add(input, index) {
1534
1544
  const scene = cloneScene({
1535
1545
  id: input.id && !this.getScene(input.id) ? input.id : this.createId(),
1536
- name: _optionalChain([input, 'access', _48 => _48.name, 'optionalAccess', _49 => _49.trim, 'call', _50 => _50()]) || this.nextDefaultName(),
1546
+ name: _optionalChain([input, 'access', _52 => _52.name, 'optionalAccess', _53 => _53.trim, 'call', _54 => _54()]) || this.nextDefaultName(),
1537
1547
  viewport: input.viewport,
1538
1548
  nodeIds: input.nodeIds
1539
1549
  });
@@ -1567,10 +1577,10 @@ var CanvasScenesStore = (_class3 = class {
1567
1577
  return this.update(id, { name });
1568
1578
  }
1569
1579
  /** Moves a scene to `toIndex` (clamped). */
1570
- move(id, toIndex) {
1580
+ move(id, toIndex2) {
1571
1581
  const from = this.scenes.findIndex((s) => s.id === id);
1572
1582
  if (from === -1) return;
1573
- const to = Math.max(0, Math.min(this.scenes.length - 1, Math.trunc(toIndex)));
1583
+ const to = Math.max(0, Math.min(this.scenes.length - 1, Math.trunc(toIndex2)));
1574
1584
  if (from === to) return;
1575
1585
  const scenes = [...this.scenes];
1576
1586
  const [scene] = scenes.splice(from, 1);
@@ -1662,49 +1672,6 @@ function fitViewportToNodes(nodes, size, ids, options = {}) {
1662
1672
  return bounds ? fitViewportToRect(bounds, size, options) : null;
1663
1673
  }
1664
1674
 
1665
- // src/canvas/arrangeShortcuts.ts
1666
- var DEFAULT_ARRANGE_SHORTCUTS = [
1667
- { action: "alignLeft", code: "KeyA", alt: true, label: "Alt+A" },
1668
- { action: "alignCenter", code: "KeyH", alt: true, label: "Alt+H" },
1669
- { action: "alignRight", code: "KeyD", alt: true, label: "Alt+D" },
1670
- { action: "alignTop", code: "KeyW", alt: true, label: "Alt+W" },
1671
- { action: "alignMiddle", code: "KeyV", alt: true, label: "Alt+V" },
1672
- { action: "alignBottom", code: "KeyS", alt: true, label: "Alt+S" },
1673
- { action: "distributeHorizontal", code: "KeyH", alt: true, shift: true, label: "Alt+Shift+H" },
1674
- { action: "distributeVertical", code: "KeyV", alt: true, shift: true, label: "Alt+Shift+V" },
1675
- { action: "lock", code: "KeyL", mod: true, label: "Mod+L" },
1676
- { action: "unlock", code: "KeyL", mod: true, alt: true, label: "Mod+Alt+L" },
1677
- { action: "bringForward", code: "BracketRight", mod: true, label: "Mod+]" },
1678
- { action: "sendBackward", code: "BracketLeft", mod: true, label: "Mod+[" },
1679
- { action: "bringToFront", code: "BracketRight", mod: true, alt: true, label: "Mod+Alt+]" },
1680
- { action: "sendToBack", code: "BracketLeft", mod: true, alt: true, label: "Mod+Alt+[" },
1681
- { action: "nextScene", code: "PageDown", label: "PageDown" },
1682
- { action: "previousScene", code: "PageUp", label: "PageUp" }
1683
- ];
1684
- var KEY_TO_CODE = {
1685
- "]": "BracketRight",
1686
- "[": "BracketLeft",
1687
- PageDown: "PageDown",
1688
- PageUp: "PageUp"
1689
- };
1690
- function eventCode(event) {
1691
- if (event.code) return event.code;
1692
- if (KEY_TO_CODE[event.key]) return KEY_TO_CODE[event.key];
1693
- if (/^[a-z]$/i.test(event.key)) return `Key${event.key.toUpperCase()}`;
1694
- return event.key;
1695
- }
1696
- function matchArrangeShortcut(event, bindings = DEFAULT_ARRANGE_SHORTCUTS) {
1697
- if (isEventFromTextInput(event)) return null;
1698
- const code = eventCode(event);
1699
- const mod = event.metaKey || event.ctrlKey;
1700
- for (const binding of bindings) {
1701
- if (binding.code === code && !!binding.mod === mod && !!binding.alt === event.altKey && !!binding.shift === event.shiftKey) {
1702
- return binding.action;
1703
- }
1704
- }
1705
- return null;
1706
- }
1707
-
1708
1675
  // src/canvas/polygonBoolean.ts
1709
1676
  function ringSignedArea(ring) {
1710
1677
  let sum = 0;
@@ -1885,9 +1852,9 @@ function splitPass(segments, pool, eps) {
1885
1852
  ]) {
1886
1853
  for (const p of [other.a, other.b]) {
1887
1854
  if (p.id === seg.a.id || p.id === seg.b.id) continue;
1888
- const { t: t2, dist } = project(seg.a, seg.b, p);
1855
+ const { t: t2, dist: dist2 } = project(seg.a, seg.b, p);
1889
1856
  const len = Math.hypot(seg.b.x - seg.a.x, seg.b.y - seg.a.y);
1890
- if (dist <= eps && t2 * len > eps && (1 - t2) * len > eps) {
1857
+ if (dist2 <= eps && t2 * len > eps && (1 - t2) * len > eps) {
1891
1858
  addSplit(split, t2, p);
1892
1859
  touched = true;
1893
1860
  }
@@ -2077,8 +2044,8 @@ function removeCollinear(ring, eps) {
2077
2044
  const dy = nxt[1] - prev[1];
2078
2045
  const len = Math.hypot(dx, dy);
2079
2046
  const cross = (cur[0] - prev[0]) * dy - (cur[1] - prev[1]) * dx;
2080
- const dot = (cur[0] - prev[0]) * dx + (cur[1] - prev[1]) * dy;
2081
- if (len > 0 && Math.abs(cross) / len <= eps && dot > 0 && dot < len * len) {
2047
+ const dot2 = (cur[0] - prev[0]) * dx + (cur[1] - prev[1]) * dy;
2048
+ if (len > 0 && Math.abs(cross) / len <= eps && dot2 > 0 && dot2 < len * len) {
2082
2049
  changed = true;
2083
2050
  continue;
2084
2051
  }
@@ -2174,6 +2141,347 @@ function dividePolygons(operands, options = {}) {
2174
2141
  return pieces;
2175
2142
  }
2176
2143
 
2144
+ // src/canvas/curveFit.ts
2145
+ function formatNumber(value, precision) {
2146
+ const factor = 10 ** precision;
2147
+ const rounded = Math.round(value * factor) / factor;
2148
+ return Object.is(rounded, -0) ? "0" : String(rounded);
2149
+ }
2150
+ var MAX_REPARAM = 6;
2151
+ var sub = (a, b) => [a[0] - b[0], a[1] - b[1]];
2152
+ var add = (a, v, s = 1) => [a[0] + v[0] * s, a[1] + v[1] * s];
2153
+ var dot = (a, b) => a[0] * b[0] + a[1] * b[1];
2154
+ var dist = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1]);
2155
+ function unit(v) {
2156
+ const l = Math.hypot(v[0], v[1]);
2157
+ return l > 1e-12 && Number.isFinite(l) ? [v[0] / l, v[1] / l] : null;
2158
+ }
2159
+ function evalCubic(c, t) {
2160
+ const s = 1 - t;
2161
+ const b0 = s * s * s;
2162
+ const b1 = 3 * s * s * t;
2163
+ const b2 = 3 * s * t * t;
2164
+ const b3 = t * t * t;
2165
+ return [
2166
+ b0 * c.p0[0] + b1 * c.p1[0] + b2 * c.p2[0] + b3 * c.p3[0],
2167
+ b0 * c.p0[1] + b1 * c.p1[1] + b2 * c.p2[1] + b3 * c.p3[1]
2168
+ ];
2169
+ }
2170
+ function cubicPointAt(c, t) {
2171
+ return evalCubic(c, t);
2172
+ }
2173
+ function dedup(points) {
2174
+ const out = [];
2175
+ for (const p of points) {
2176
+ if (!Number.isFinite(p[0]) || !Number.isFinite(p[1])) continue;
2177
+ if (out.length === 0 || dist(out[out.length - 1], p) > 1e-12) out.push(p);
2178
+ }
2179
+ return out;
2180
+ }
2181
+ function chordParams(pts) {
2182
+ const u = [0];
2183
+ let acc = 0;
2184
+ for (let i = 1; i < pts.length; i++) {
2185
+ acc += dist(pts[i - 1], pts[i]);
2186
+ u.push(acc);
2187
+ }
2188
+ return acc > 0 ? u.map((x) => x / acc) : u;
2189
+ }
2190
+ function generate(pts, u, t0, t1) {
2191
+ const p0 = pts[0];
2192
+ const p3 = pts[pts.length - 1];
2193
+ const dirIn = [-t1[0], -t1[1]];
2194
+ let c00 = 0;
2195
+ let c01 = 0;
2196
+ let c11 = 0;
2197
+ let x0 = 0;
2198
+ let x1 = 0;
2199
+ for (let i = 0; i < pts.length; i++) {
2200
+ const t = u[i];
2201
+ const s = 1 - t;
2202
+ const b0 = s * s * s;
2203
+ const b1 = 3 * s * s * t;
2204
+ const b2 = 3 * s * t * t;
2205
+ const b3 = t * t * t;
2206
+ const a0 = [t0[0] * b1, t0[1] * b1];
2207
+ const a1 = [dirIn[0] * b2, dirIn[1] * b2];
2208
+ c00 += dot(a0, a0);
2209
+ c01 += dot(a0, a1);
2210
+ c11 += dot(a1, a1);
2211
+ const tmp = [
2212
+ pts[i][0] - (p0[0] * (b0 + b1) + p3[0] * (b2 + b3)),
2213
+ pts[i][1] - (p0[1] * (b0 + b1) + p3[1] * (b2 + b3))
2214
+ ];
2215
+ x0 += dot(a0, tmp);
2216
+ x1 += dot(a1, tmp);
2217
+ }
2218
+ const det = c00 * c11 - c01 * c01;
2219
+ const seg = dist(p0, p3);
2220
+ const eps = 1e-6 * seg;
2221
+ let al = seg / 3;
2222
+ let ar = seg / 3;
2223
+ if (Math.abs(det) > 1e-12) {
2224
+ al = (x0 * c11 - x1 * c01) / det;
2225
+ ar = (c00 * x1 - c01 * x0) / det;
2226
+ }
2227
+ if (!Number.isFinite(al) || !Number.isFinite(ar) || al < eps || ar < eps) {
2228
+ al = seg / 3;
2229
+ ar = seg / 3;
2230
+ }
2231
+ const cap = seg * 4 + 1e-9;
2232
+ al = Math.min(al, cap);
2233
+ ar = Math.min(ar, cap);
2234
+ return { p0, p1: add(p0, t0, al), p2: add(p3, dirIn, ar), p3 };
2235
+ }
2236
+ function maxError(pts, c, u) {
2237
+ let e = 0;
2238
+ let idx = pts.length >> 1;
2239
+ for (let i = 0; i < pts.length; i++) {
2240
+ const d = dist(evalCubic(c, u[i]), pts[i]);
2241
+ if (d > e) {
2242
+ e = d;
2243
+ idx = i;
2244
+ }
2245
+ }
2246
+ return [e, idx];
2247
+ }
2248
+ function newton(c, p, t) {
2249
+ const s = 1 - t;
2250
+ const q = evalCubic(c, t);
2251
+ const d1 = [
2252
+ 3 * (s * s * (c.p1[0] - c.p0[0]) + 2 * s * t * (c.p2[0] - c.p1[0]) + t * t * (c.p3[0] - c.p2[0])),
2253
+ 3 * (s * s * (c.p1[1] - c.p0[1]) + 2 * s * t * (c.p2[1] - c.p1[1]) + t * t * (c.p3[1] - c.p2[1]))
2254
+ ];
2255
+ const d2 = [
2256
+ 6 * (s * (c.p2[0] - 2 * c.p1[0] + c.p0[0]) + t * (c.p3[0] - 2 * c.p2[0] + c.p1[0])),
2257
+ 6 * (s * (c.p2[1] - 2 * c.p1[1] + c.p0[1]) + t * (c.p3[1] - 2 * c.p2[1] + c.p1[1]))
2258
+ ];
2259
+ const diff = [q[0] - p[0], q[1] - p[1]];
2260
+ const num = dot(diff, d1);
2261
+ const den = dot(d1, d1) + dot(diff, d2);
2262
+ if (Math.abs(den) < 1e-12) return t;
2263
+ const nt = t - num / den;
2264
+ return Number.isFinite(nt) ? Math.min(1, Math.max(0, nt)) : t;
2265
+ }
2266
+ function fitSingleFrom(pts, u, t0, t1) {
2267
+ let best = generate(pts, u, t0, t1);
2268
+ let [bestErr, bestSplit] = maxError(pts, best, u);
2269
+ const params = u.slice();
2270
+ for (let round = 0; round < MAX_REPARAM; round++) {
2271
+ for (let i = 0; i < params.length; i++) params[i] = newton(best, pts[i], params[i]);
2272
+ const c = generate(pts, params, t0, t1);
2273
+ const [e, s] = maxError(pts, c, params);
2274
+ if (e < bestErr) {
2275
+ best = c;
2276
+ bestErr = e;
2277
+ bestSplit = s;
2278
+ } else break;
2279
+ }
2280
+ return [best, bestErr, bestSplit];
2281
+ }
2282
+ function fitRec(pts, t0, t1, tol, out, depth) {
2283
+ const n = pts.length;
2284
+ if (n === 2) {
2285
+ const d = dist(pts[0], pts[1]) / 3;
2286
+ out.push({ p0: pts[0], p1: add(pts[0], t0, d), p2: add(pts[1], t1, -d), p3: pts[1] });
2287
+ return;
2288
+ }
2289
+ const [c, err, splitAt] = fitSingleFrom(pts, chordParams(pts), t0, t1);
2290
+ if (err <= tol || depth > 40) {
2291
+ out.push(c);
2292
+ return;
2293
+ }
2294
+ const split = Math.min(n - 2, Math.max(1, splitAt));
2295
+ const tc = _nullishCoalesce(unit(sub(pts[split + 1], pts[split - 1])), () => ( t0));
2296
+ fitRec(pts.slice(0, split + 1), t0, tc, tol, out, depth + 1);
2297
+ fitRec(pts.slice(split), tc, t1, tol, out, depth + 1);
2298
+ }
2299
+ function tangentFrom(a, b, c) {
2300
+ const chord = unit(sub(b, a));
2301
+ if (!c) return chord;
2302
+ const d1 = dist(a, b);
2303
+ const d2 = dist(b, c);
2304
+ if (!(d1 > 0) || !(d2 > 0)) return chord;
2305
+ const ka = -(2 * d1 + d2) / (d1 * (d1 + d2));
2306
+ const kb = (d1 + d2) / (d1 * d2);
2307
+ const kc = -d1 / (d2 * (d1 + d2));
2308
+ const est = unit([ka * a[0] + kb * b[0] + kc * c[0], ka * a[1] + kb * b[1] + kc * c[1]]);
2309
+ return est && chord && dot(est, chord) > Math.cos(Math.PI / 4) ? est : chord;
2310
+ }
2311
+ function fitCubicRun(points, tolerance, t0, t1) {
2312
+ const pts = dedup(points);
2313
+ const out = [];
2314
+ if (pts.length < 2) return out;
2315
+ const n = pts.length;
2316
+ const start = _nullishCoalesce(_nullishCoalesce((t0 && unit([t0[0], t0[1]])), () => ( tangentFrom(pts[0], pts[1], pts[2]))), () => ( [1, 0]));
2317
+ const back = tangentFrom(pts[n - 1], pts[n - 2], pts[n - 3]);
2318
+ const end = _nullishCoalesce((t1 && unit([t1[0], t1[1]])), () => ( (back ? [-back[0], -back[1]] : [1, 0])));
2319
+ fitRec(pts, start, end, Math.max(tolerance, 1e-9), out, 0);
2320
+ return out;
2321
+ }
2322
+ function turnDeg(a, b, c) {
2323
+ const u = unit(sub(b, a));
2324
+ const v = unit(sub(c, b));
2325
+ if (!u || !v) return 0;
2326
+ return Math.acos(Math.min(1, Math.max(-1, dot(u, v)))) * 180 / Math.PI;
2327
+ }
2328
+ function findCorners(pts, closed, cornerAngle, span) {
2329
+ const n = pts.length;
2330
+ const at = (i) => pts[closed ? (i % n + n) % n : i];
2331
+ const reach = (i, step) => {
2332
+ for (let k = 1; k < (closed ? n : Infinity); k++) {
2333
+ const j = i + step * k;
2334
+ if (!closed && (j < 0 || j >= n)) return k > 1 ? j - step : null;
2335
+ if (dist(at(j), pts[i]) >= span) return j;
2336
+ }
2337
+ return null;
2338
+ };
2339
+ const turns = new Float64Array(n);
2340
+ const windows = [];
2341
+ for (let i = 0; i < n; i++) {
2342
+ windows.push([i, i]);
2343
+ if (!closed && (i === 0 || i === n - 1)) continue;
2344
+ const prev = reach(i, -1);
2345
+ const next = reach(i, 1);
2346
+ if (prev === null || next === null) continue;
2347
+ windows[i] = [prev, next];
2348
+ turns[i] = turnDeg(at(prev), pts[i], at(next));
2349
+ }
2350
+ const corners = [];
2351
+ for (let i = 0; i < n; i++) {
2352
+ if (!(turns[i] > cornerAngle)) continue;
2353
+ const [lo, hi] = windows[i];
2354
+ let sharpest = true;
2355
+ for (let j = lo; j <= hi && sharpest; j++) {
2356
+ const k = closed ? (j % n + n) % n : j;
2357
+ if (k === i || dist(pts[k], pts[i]) >= span) continue;
2358
+ if (turns[k] > turns[i] || turns[k] === turns[i] && k < i) sharpest = false;
2359
+ }
2360
+ if (sharpest) corners.push(i);
2361
+ }
2362
+ return corners;
2363
+ }
2364
+ function densify(run) {
2365
+ if (run.length < 3) return run;
2366
+ const lengths = [];
2367
+ for (let i = 1; i < run.length; i++) lengths.push(dist(run[i - 1], run[i]));
2368
+ const sorted = [...lengths].sort((a, b) => a - b);
2369
+ const median = sorted[sorted.length >> 1];
2370
+ if (!(median > 0)) return run;
2371
+ const out = [run[0]];
2372
+ for (let i = 1; i < run.length; i++) {
2373
+ const len = lengths[i - 1];
2374
+ if (len > 2 * median) {
2375
+ const steps = Math.min(64, Math.ceil(len / median));
2376
+ const a = run[i - 1];
2377
+ const b = run[i];
2378
+ for (let k = 1; k < steps; k++) {
2379
+ const t = k / steps;
2380
+ out.push([a[0] + (b[0] - a[0]) * t, a[1] + (b[1] - a[1]) * t]);
2381
+ }
2382
+ }
2383
+ out.push(run[i]);
2384
+ }
2385
+ return out;
2386
+ }
2387
+ function fitCubics(points, tolerance, options = {}) {
2388
+ let pts = dedup(points);
2389
+ const closed = options.closed === true;
2390
+ if (closed && pts.length > 1 && dist(pts[0], pts[pts.length - 1]) <= 1e-12) pts = pts.slice(0, -1);
2391
+ if (pts.length < 2) return [];
2392
+ const tol = Math.max(tolerance, 1e-6);
2393
+ const cornerAngle = _nullishCoalesce(options.cornerAngleDeg, () => ( 30));
2394
+ const n = pts.length;
2395
+ const span = 4 * tol;
2396
+ if (!closed || n < 3) {
2397
+ const corners2 = [0, ...n > 2 ? findCorners(pts, false, cornerAngle, span) : [], n - 1];
2398
+ const out2 = [];
2399
+ for (let k = 1; k < corners2.length; k++) {
2400
+ const run = pts.slice(corners2[k - 1], corners2[k] + 1);
2401
+ out2.push(...fitCubicRun(densify(run), tol));
2402
+ }
2403
+ if (closed && n === 2) out2.push(...fitCubicRun([pts[1], pts[0]], tol));
2404
+ return out2;
2405
+ }
2406
+ const corners = findCorners(pts, true, cornerAngle, span);
2407
+ if (corners.length === 0) {
2408
+ const ring = [...pts, pts[0]];
2409
+ const t = _nullishCoalesce(unit(sub(pts[1], pts[n - 1])), () => ( [1, 0]));
2410
+ return fitCubicRun(densify(ring), tol, t, t);
2411
+ }
2412
+ const out = [];
2413
+ for (let k = 0; k < corners.length; k++) {
2414
+ const from = corners[k];
2415
+ const to = corners[(k + 1) % corners.length];
2416
+ const run = [];
2417
+ for (let i = from; ; i = (i + 1) % n) {
2418
+ run.push(pts[i]);
2419
+ if (run.length > 1 && i === to) break;
2420
+ }
2421
+ out.push(...fitCubicRun(densify(run), tol));
2422
+ }
2423
+ return out;
2424
+ }
2425
+ function isStraightCubic(c, tol) {
2426
+ const chord = sub(c.p3, c.p0);
2427
+ const len = Math.hypot(chord[0], chord[1]);
2428
+ if (len < 1e-12) return dist(c.p1, c.p0) <= tol && dist(c.p2, c.p0) <= tol;
2429
+ const dir = [chord[0] / len, chord[1] / len];
2430
+ return [c.p1, c.p2].every((h) => {
2431
+ const v = sub(h, c.p0);
2432
+ const along = dot(v, dir);
2433
+ const across = Math.abs(v[0] * dir[1] - v[1] * dir[0]);
2434
+ return across <= tol && along >= -tol && along <= len + tol;
2435
+ });
2436
+ }
2437
+ function cubicsToPathData(segments, options = {}) {
2438
+ if (segments.length === 0) return "";
2439
+ const f = (n) => formatNumber(n, _nullishCoalesce(options.precision, () => ( 3)));
2440
+ const dx = _nullishCoalesce(_optionalChain([options, 'access', _55 => _55.offset, 'optionalAccess', _56 => _56.x]), () => ( 0));
2441
+ const dy = _nullishCoalesce(_optionalChain([options, 'access', _57 => _57.offset, 'optionalAccess', _58 => _58.y]), () => ( 0));
2442
+ const pt = (p) => `${f(p[0] + dx)} ${f(p[1] + dy)}`;
2443
+ const straight = _nullishCoalesce(options.straightTolerance, () => ( 1e-3));
2444
+ let d = `M${pt(segments[0].p0)}`;
2445
+ segments.forEach((c, i) => {
2446
+ const last = options.closed && i === segments.length - 1;
2447
+ if (isStraightCubic(c, straight)) {
2448
+ if (!last) d += `L${pt(c.p3)}`;
2449
+ } else d += `C${pt(c.p1)} ${pt(c.p2)} ${pt(c.p3)}`;
2450
+ });
2451
+ return options.closed ? `${d}Z` : d;
2452
+ }
2453
+ function polylineToPathData(points, closed, options) {
2454
+ if (points.length < 2) return "";
2455
+ const f = (n) => formatNumber(n, _nullishCoalesce(options.precision, () => ( 3)));
2456
+ const dx = _nullishCoalesce(_optionalChain([options, 'access', _59 => _59.offset, 'optionalAccess', _60 => _60.x]), () => ( 0));
2457
+ const dy = _nullishCoalesce(_optionalChain([options, 'access', _61 => _61.offset, 'optionalAccess', _62 => _62.y]), () => ( 0));
2458
+ let d = `M${f(points[0][0] + dx)} ${f(points[0][1] + dy)}`;
2459
+ for (let i = 1; i < points.length; i++) d += `L${f(points[i][0] + dx)} ${f(points[i][1] + dy)}`;
2460
+ return closed ? `${d}Z` : d;
2461
+ }
2462
+ function fitPathData(ring, options = {}) {
2463
+ const closed = _nullishCoalesce(options.closed, () => ( true));
2464
+ const tolerance = _nullishCoalesce(options.tolerance, () => ( 0.5));
2465
+ const pts = dedup(ring);
2466
+ const segments = fitCubics(pts, tolerance, { ...options, closed });
2467
+ if (segments.length === 0) return "";
2468
+ const edges = closed ? pts.length : pts.length - 1;
2469
+ if (options.noWorse !== false) {
2470
+ const straight = segments.filter((c) => isStraightCubic(c, tolerance * 0.02)).length;
2471
+ if (segments.length >= edges && straight === segments.length) return polylineToPathData(pts, closed, options);
2472
+ if (segments.length > edges) return polylineToPathData(pts, closed, options);
2473
+ }
2474
+ return cubicsToPathData(segments, {
2475
+ precision: options.precision,
2476
+ offset: options.offset,
2477
+ closed,
2478
+ straightTolerance: tolerance * 0.02
2479
+ });
2480
+ }
2481
+ function fitFreehandPath(points, options = {}) {
2482
+ return fitPathData(points, { tolerance: 1, ...options, closed: false });
2483
+ }
2484
+
2177
2485
  // src/canvas/shapeGeometry.ts
2178
2486
  var SHAPE_KINDS = ["rect", "ellipse", "polygon", "star", "path"];
2179
2487
  function isShapeDescription(value) {
@@ -2302,8 +2610,8 @@ function parseSvgPath(d) {
2302
2610
  break;
2303
2611
  }
2304
2612
  case "s": {
2305
- const x1 = _optionalChain([lastControl, 'optionalAccess', _51 => _51.type]) === "C" ? 2 * cx - lastControl.x : cx;
2306
- const y1 = _optionalChain([lastControl, 'optionalAccess', _52 => _52.type]) === "C" ? 2 * cy - lastControl.y : cy;
2613
+ const x1 = _optionalChain([lastControl, 'optionalAccess', _63 => _63.type]) === "C" ? 2 * cx - lastControl.x : cx;
2614
+ const y1 = _optionalChain([lastControl, 'optionalAccess', _64 => _64.type]) === "C" ? 2 * cy - lastControl.y : cy;
2307
2615
  const c = {
2308
2616
  type: "C",
2309
2617
  x1,
@@ -2328,8 +2636,8 @@ function parseSvgPath(d) {
2328
2636
  break;
2329
2637
  }
2330
2638
  case "t": {
2331
- const x1 = _optionalChain([lastControl, 'optionalAccess', _53 => _53.type]) === "Q" ? 2 * cx - lastControl.x : cx;
2332
- const y1 = _optionalChain([lastControl, 'optionalAccess', _54 => _54.type]) === "Q" ? 2 * cy - lastControl.y : cy;
2639
+ const x1 = _optionalChain([lastControl, 'optionalAccess', _65 => _65.type]) === "Q" ? 2 * cx - lastControl.x : cx;
2640
+ const y1 = _optionalChain([lastControl, 'optionalAccess', _66 => _66.type]) === "Q" ? 2 * cy - lastControl.y : cy;
2333
2641
  const c = { type: "Q", x1, y1, x: args[0] + ox, y: args[1] + oy };
2334
2642
  commands.push(c);
2335
2643
  lastControl = { x: x1, y: y1, type: "Q" };
@@ -2540,7 +2848,7 @@ function rotationTransform(shape, size) {
2540
2848
  }
2541
2849
  function getShapeSvg(shape, size) {
2542
2850
  const { width: w, height: h } = size;
2543
- const f = (n) => formatNumber(n, 3);
2851
+ const f = (n) => formatNumber2(n, 3);
2544
2852
  const transforms = [];
2545
2853
  if (shape.rotation) transforms.push(`rotate(${f(shape.rotation)} ${f(w / 2)} ${f(h / 2)})`);
2546
2854
  let d = "";
@@ -2589,7 +2897,7 @@ function getShapeRenderData(shape, size = {}) {
2589
2897
  const height = size.height && size.height > 0 ? size.height : vb ? vb[3] : 100;
2590
2898
  const svg = getShapeSvg(shape, { width, height });
2591
2899
  const data = {
2592
- viewBox: `0 0 ${formatNumber(width, 3)} ${formatNumber(height, 3)}`,
2900
+ viewBox: `0 0 ${formatNumber2(width, 3)} ${formatNumber2(height, 3)}`,
2593
2901
  width,
2594
2902
  height,
2595
2903
  d: svg.d,
@@ -2636,7 +2944,7 @@ function shapeToPolygon(shape, size, options = {}) {
2636
2944
  if (rotate) rings = rings.map((ring) => ring.map(rotate));
2637
2945
  return { rings, fillRule };
2638
2946
  }
2639
- function formatNumber(value, precision = 3) {
2947
+ function formatNumber2(value, precision = 3) {
2640
2948
  const factor = 10 ** precision;
2641
2949
  const rounded = Math.round(value * factor) / factor;
2642
2950
  return Object.is(rounded, -0) ? "0" : String(rounded);
@@ -2670,9 +2978,9 @@ function rdp(points, tolerance) {
2670
2978
  let maxDist = -1;
2671
2979
  let index = -1;
2672
2980
  for (let i = s + 1; i < e; i++) {
2673
- const dist = segmentDistance(points[i], points[s], points[e]);
2674
- if (dist > maxDist) {
2675
- maxDist = dist;
2981
+ const dist2 = segmentDistance(points[i], points[s], points[e]);
2982
+ if (dist2 > maxDist) {
2983
+ maxDist = dist2;
2676
2984
  index = i;
2677
2985
  }
2678
2986
  }
@@ -2688,9 +2996,9 @@ function simplifyRing(ring, tolerance) {
2688
2996
  let far = 0;
2689
2997
  let farDist = -1;
2690
2998
  for (let i = 1; i < ring.length; i++) {
2691
- const dist = Math.hypot(ring[i][0] - ring[0][0], ring[i][1] - ring[0][1]);
2692
- if (dist > farDist) {
2693
- farDist = dist;
2999
+ const dist2 = Math.hypot(ring[i][0] - ring[0][0], ring[i][1] - ring[0][1]);
3000
+ if (dist2 > farDist) {
3001
+ farDist = dist2;
2694
3002
  far = i;
2695
3003
  }
2696
3004
  }
@@ -2701,20 +3009,31 @@ function simplifyRing(ring, tolerance) {
2701
3009
  }
2702
3010
  function polygonToSvgPath(input, options = {}) {
2703
3011
  const precision = _nullishCoalesce(options.precision, () => ( 3));
2704
- const f = (n) => formatNumber(n, precision);
2705
- const dx = _nullishCoalesce(_optionalChain([options, 'access', _55 => _55.offset, 'optionalAccess', _56 => _56.x]), () => ( 0));
2706
- const dy = _nullishCoalesce(_optionalChain([options, 'access', _57 => _57.offset, 'optionalAccess', _58 => _58.y]), () => ( 0));
3012
+ const f = (n) => formatNumber2(n, precision);
3013
+ const dx = _nullishCoalesce(_optionalChain([options, 'access', _67 => _67.offset, 'optionalAccess', _68 => _68.x]), () => ( 0));
3014
+ const dy = _nullishCoalesce(_optionalChain([options, 'access', _69 => _69.offset, 'optionalAccess', _70 => _70.y]), () => ( 0));
2707
3015
  const rings = [];
3016
+ const fit = options.curves === "fit";
3017
+ let fitted = "";
2708
3018
  for (const item of input) {
2709
3019
  const list = item.length > 0 && Array.isArray(item[0]) && Array.isArray(item[0][0]) ? item : [item];
2710
3020
  for (const ring of list) {
2711
3021
  let r = ring;
2712
3022
  if (options.simplify && options.simplify > 0) r = simplifyRing(r, options.simplify);
2713
3023
  if (r.length < 3) continue;
3024
+ if (fit) {
3025
+ fitted += fitPathData(r, {
3026
+ tolerance: _nullishCoalesce(options.curveTolerance, () => ( 0.25)),
3027
+ cornerAngleDeg: options.cornerAngleDeg,
3028
+ precision,
3029
+ offset: { x: dx, y: dy }
3030
+ });
3031
+ continue;
3032
+ }
2714
3033
  rings.push(dx || dy ? r.map(([x, y]) => [x + dx, y + dy]) : r);
2715
3034
  }
2716
3035
  }
2717
- return ringsToPath(rings, f);
3036
+ return fit ? fitted : ringsToPath(rings, f);
2718
3037
  }
2719
3038
 
2720
3039
  // src/canvas/shapeNodes.ts
@@ -2728,10 +3047,10 @@ var BOOLEAN_FOR = {
2728
3047
  exclude: "xor"
2729
3048
  };
2730
3049
  function isShapeNode(node) {
2731
- return !!node && isShapeDescription(_optionalChain([node, 'access', _59 => _59.data, 'optionalAccess', _60 => _60[SHAPE_DATA_KEY]]));
3050
+ return !!node && isShapeDescription(_optionalChain([node, 'access', _71 => _71.data, 'optionalAccess', _72 => _72[SHAPE_DATA_KEY]]));
2732
3051
  }
2733
3052
  function getNodeShape(node) {
2734
- const shape = _optionalChain([node, 'optionalAccess', _61 => _61.data, 'optionalAccess', _62 => _62[SHAPE_DATA_KEY]]);
3053
+ const shape = _optionalChain([node, 'optionalAccess', _73 => _73.data, 'optionalAccess', _74 => _74[SHAPE_DATA_KEY]]);
2735
3054
  return isShapeDescription(shape) ? shape : null;
2736
3055
  }
2737
3056
  function shapeNodeToPolygon(node, lookup, options = {}) {
@@ -2792,7 +3111,10 @@ function combineShapeNodes(nodes, ids, operation, options = {}) {
2792
3111
  const d = polygonToSvgPath(polygon, {
2793
3112
  precision: options.precision,
2794
3113
  simplify: options.simplify,
2795
- offset: { x: -bounds.minX, y: -bounds.minY }
3114
+ offset: { x: -bounds.minX, y: -bounds.minY },
3115
+ curves: _nullishCoalesce(options.curves, () => ( "fit")),
3116
+ curveTolerance: _nullishCoalesce(_nullishCoalesce(options.curveTolerance, () => ( options.tolerance)), () => ( 0.25)),
3117
+ cornerAngleDeg: options.cornerAngleDeg
2796
3118
  });
2797
3119
  if (!d) return null;
2798
3120
  const sourceShape = getNodeShape(source);
@@ -2876,20 +3198,1106 @@ function revertShapeCombination(nodes, change, previous) {
2876
3198
  return out;
2877
3199
  }
2878
3200
 
3201
+ // src/canvas/resizeSnap.ts
3202
+ var RESIZE_HANDLES = [
3203
+ "top-left",
3204
+ "top",
3205
+ "top-right",
3206
+ "right",
3207
+ "bottom-right",
3208
+ "bottom",
3209
+ "bottom-left",
3210
+ "left"
3211
+ ];
3212
+ function resizeHandleAxes(handle) {
3213
+ const x = handle.includes("left") ? -1 : handle.includes("right") ? 1 : 0;
3214
+ const y = handle.includes("top") ? -1 : handle.includes("bottom") ? 1 : 0;
3215
+ return { x, y };
3216
+ }
3217
+ function inferResizeHandle(start, next, eps = 1e-6) {
3218
+ const moved = (a, b) => Math.abs(a - b) > eps;
3219
+ const left = moved(start.x, next.x);
3220
+ const right = moved(start.x + start.width, next.x + next.width);
3221
+ const top = moved(start.y, next.y);
3222
+ const bottom = moved(start.y + start.height, next.y + next.height);
3223
+ const h = left ? "left" : right ? "right" : "";
3224
+ const v = top ? "top" : bottom ? "bottom" : "";
3225
+ if (h && v) return `${v}-${h}`;
3226
+ return h || v || null;
3227
+ }
3228
+ function within(axis, v, tolerance) {
3229
+ const { values } = axis;
3230
+ let lo = 0;
3231
+ let hi = values.length;
3232
+ while (lo < hi) {
3233
+ const mid = lo + hi >>> 1;
3234
+ if (values[mid] < v - tolerance) lo = mid + 1;
3235
+ else hi = mid;
3236
+ }
3237
+ const out = [];
3238
+ for (let i = lo; i < values.length && values[i] <= v + tolerance; i++) out.push(values[i]);
3239
+ return out;
3240
+ }
3241
+ function matching(axis, v, eps) {
3242
+ const { values, rects } = axis;
3243
+ const out = [];
3244
+ for (let i = 0; i < values.length; i++) if (Math.abs(values[i] - v) <= eps) out.push(rects[i]);
3245
+ return out;
3246
+ }
3247
+ function snapResize(rect, handle, targets, options = {}) {
3248
+ const index = Array.isArray(targets) ? createGuideIndex(targets) : targets;
3249
+ const zoom = options.zoom && options.zoom > 0 ? options.zoom : 1;
3250
+ const tolerance = (_nullishCoalesce(options.threshold, () => ( 6))) / zoom;
3251
+ const eps = 0.5 / zoom;
3252
+ const useEdges = options.edges !== false;
3253
+ const useCentres = options.centres !== false;
3254
+ const grid = _nullishCoalesce(options.gridSize, () => ( 0));
3255
+ const axes = resizeHandleAxes(handle);
3256
+ const unchanged = { rect: { ...rect }, guides: [], snappedX: false, snappedY: false, changed: false };
3257
+ if (![rect.x, rect.y, rect.width, rect.height].every(Number.isFinite)) return unchanged;
3258
+ const x0 = rect.x;
3259
+ const x1 = rect.x + rect.width;
3260
+ const y0 = rect.y;
3261
+ const y1 = rect.y + rect.height;
3262
+ const bestHit = (horizontal) => {
3263
+ const dir = horizontal ? axes.x : axes.y;
3264
+ if (dir === 0) return null;
3265
+ const moving = horizontal ? dir < 0 ? x0 : x1 : dir < 0 ? y0 : y1;
3266
+ const fixed = horizontal ? dir < 0 ? x1 : x0 : dir < 0 ? y1 : y0;
3267
+ const min = _nullishCoalesce((horizontal ? options.minWidth : options.minHeight), () => ( 0));
3268
+ const valid = (t) => {
3269
+ const size = dir < 0 ? fixed - t : t - fixed;
3270
+ return Number.isFinite(size) && size > 1e-9 && size >= min;
3271
+ };
3272
+ let best = null;
3273
+ const consider = (values, kind) => {
3274
+ for (const t of values) {
3275
+ if (!valid(t)) continue;
3276
+ if (!best || Math.abs(t - moving) < Math.abs(best.value - moving)) best = { value: t, kind };
3277
+ }
3278
+ };
3279
+ if (useEdges) consider(within(horizontal ? index.edgeX : index.edgeY, moving, tolerance), "edge");
3280
+ if (useCentres) consider(within(horizontal ? index.centreX : index.centreY, moving, tolerance), "centre");
3281
+ if (!best && grid > 0) {
3282
+ const origin = horizontal ? _nullishCoalesce(_optionalChain([options, 'access', _75 => _75.gridOrigin, 'optionalAccess', _76 => _76.x]), () => ( 0)) : _nullishCoalesce(_optionalChain([options, 'access', _77 => _77.gridOrigin, 'optionalAccess', _78 => _78.y]), () => ( 0));
3283
+ consider([snapToGrid(moving, grid, origin)], "grid");
3284
+ }
3285
+ return best;
3286
+ };
3287
+ let nx0 = x0;
3288
+ let nx1 = x1;
3289
+ let ny0 = y0;
3290
+ let ny1 = y1;
3291
+ const setEdge = (horizontal, value) => {
3292
+ const dir = horizontal ? axes.x : axes.y;
3293
+ if (horizontal) {
3294
+ if (dir < 0) nx0 = value;
3295
+ else nx1 = value;
3296
+ } else if (dir < 0) ny0 = value;
3297
+ else ny1 = value;
3298
+ };
3299
+ let hitX = bestHit(true);
3300
+ let hitY = bestHit(false);
3301
+ const ratio = rect.height > 0 ? rect.width / rect.height : 0;
3302
+ if (options.keepAspectRatio && ratio > 0 && (hitX || hitY)) {
3303
+ if (axes.x !== 0 && axes.y !== 0) {
3304
+ const dist2 = (h, horizontal) => h ? Math.abs(h.value - (horizontal ? axes.x < 0 ? x0 : x1 : axes.y < 0 ? y0 : y1)) : Infinity;
3305
+ const useX = dist2(hitX, true) <= dist2(hitY, false);
3306
+ if (useX && hitX) {
3307
+ setEdge(true, hitX.value);
3308
+ const height = (nx1 - nx0) / ratio;
3309
+ if (axes.y < 0) ny0 = ny1 - height;
3310
+ else ny1 = ny0 + height;
3311
+ hitY = null;
3312
+ } else if (hitY) {
3313
+ setEdge(false, hitY.value);
3314
+ const width = (ny1 - ny0) * ratio;
3315
+ if (axes.x < 0) nx0 = nx1 - width;
3316
+ else nx1 = nx0 + width;
3317
+ hitX = null;
3318
+ }
3319
+ const min = (v) => _nullishCoalesce(v, () => ( 0));
3320
+ if (nx1 - nx0 < min(options.minWidth) || ny1 - ny0 < min(options.minHeight) || !(nx1 > nx0 && ny1 > ny0)) {
3321
+ return unchanged;
3322
+ }
3323
+ } else if (axes.x !== 0 && hitX) {
3324
+ setEdge(true, hitX.value);
3325
+ const height = (nx1 - nx0) / ratio;
3326
+ const cy = (y0 + y1) / 2;
3327
+ ny0 = cy - height / 2;
3328
+ ny1 = cy + height / 2;
3329
+ } else if (axes.y !== 0 && hitY) {
3330
+ setEdge(false, hitY.value);
3331
+ const width = (ny1 - ny0) * ratio;
3332
+ const cx = (x0 + x1) / 2;
3333
+ nx0 = cx - width / 2;
3334
+ nx1 = cx + width / 2;
3335
+ }
3336
+ } else {
3337
+ if (hitX) setEdge(true, hitX.value);
3338
+ if (hitY) setEdge(false, hitY.value);
3339
+ }
3340
+ const out = { x: nx0, y: ny0, width: nx1 - nx0, height: ny1 - ny0 };
3341
+ const guides = [];
3342
+ const guideFor = (horizontal, hit) => {
3343
+ if (!hit || hit.kind === "grid") return;
3344
+ const axis = hit.kind === "edge" ? horizontal ? index.edgeX : index.edgeY : horizontal ? index.centreX : index.centreY;
3345
+ const aligned = matching(axis, hit.value, eps);
3346
+ const span = _chunkWADCJ7A7cjs.boundsOf.call(void 0, [out, ...aligned]);
3347
+ guides.push(
3348
+ horizontal ? { orientation: "vertical", kind: hit.kind, x1: hit.value, y1: span.y, x2: hit.value, y2: span.y + span.height } : { orientation: "horizontal", kind: hit.kind, x1: span.x, y1: hit.value, x2: span.x + span.width, y2: hit.value }
3349
+ );
3350
+ };
3351
+ guideFor(true, hitX);
3352
+ guideFor(false, hitY);
3353
+ const changed = out.x !== rect.x || out.y !== rect.y || out.width !== rect.width || out.height !== rect.height;
3354
+ return {
3355
+ rect: out,
3356
+ guides,
3357
+ snappedX: !!hitX && hitX.kind !== "grid",
3358
+ snappedY: !!hitY && hitY.kind !== "grid",
3359
+ changed
3360
+ };
3361
+ }
3362
+ function snapNodeResize(nodes, id, rect, handle, options = {}) {
3363
+ const lookup = createNodeLookup(nodes);
3364
+ const node = lookup.get(id);
3365
+ if (!node || isLocked(node)) {
3366
+ return { rect: { ...rect }, guides: [], snappedX: false, snappedY: false, changed: false, updates: [] };
3367
+ }
3368
+ const index = _nullishCoalesce(options.index, () => ( createNodeGuideIndex(nodes, [id], options)));
3369
+ const result = snapResize(rect, handle, index, options);
3370
+ if (!result.changed) return { ...result, updates: [] };
3371
+ const parent = node.parentId ? lookup.get(node.parentId) : void 0;
3372
+ const origin = parent ? getAbsolutePosition(parent, lookup) : { x: 0, y: 0 };
3373
+ return {
3374
+ ...result,
3375
+ updates: [
3376
+ {
3377
+ id,
3378
+ position: { x: result.rect.x - origin.x, y: result.rect.y - origin.y },
3379
+ width: result.rect.width,
3380
+ height: result.rect.height
3381
+ }
3382
+ ]
3383
+ };
3384
+ }
3385
+ function getResizingNodeRect(node, lookup, options = {}) {
3386
+ const { x, y } = node.parentId ? getAbsolutePosition(node, lookup) : node.position;
3387
+ const size = getNodeSize(node, options);
3388
+ return { x, y, width: _nullishCoalesce(node.width, () => ( size.width)), height: _nullishCoalesce(node.height, () => ( size.height)) };
3389
+ }
3390
+
3391
+ // src/canvas/autoLayout.ts
3392
+ var AUTO_LAYOUT_DATA_KEY = "layout";
3393
+ var CHILD_LAYOUT_DATA_KEY = "childLayout";
3394
+ var MODES = /* @__PURE__ */ new Set(["horizontal", "vertical", "grid"]);
3395
+ var EPS = 1e-6;
3396
+ var MAX_TRACKS = 1e3;
3397
+ var MAX_GRID_CELLS = 1e6;
3398
+ function clampLayoutSize(value, min, max) {
3399
+ let v = Number.isFinite(value) ? Math.max(value, 0) : 0;
3400
+ if (typeof max === "number" && Number.isFinite(max)) v = Math.min(v, max);
3401
+ if (typeof min === "number" && Number.isFinite(min)) v = Math.max(v, min);
3402
+ return v;
3403
+ }
3404
+ var finite = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
3405
+ function getAutoLayout(node) {
3406
+ const layout2 = _optionalChain([node, 'optionalAccess', _79 => _79.data, 'optionalAccess', _80 => _80[AUTO_LAYOUT_DATA_KEY]]);
3407
+ return layout2 && typeof layout2 === "object" && MODES.has(layout2.mode) ? layout2 : void 0;
3408
+ }
3409
+ function isAutoLayoutFrame(node) {
3410
+ return getAutoLayout(node) !== void 0;
3411
+ }
3412
+ function getChildLayout(node) {
3413
+ const child = _optionalChain([node, 'optionalAccess', _81 => _81.data, 'optionalAccess', _82 => _82[CHILD_LAYOUT_DATA_KEY]]);
3414
+ return child && typeof child === "object" ? child : {};
3415
+ }
3416
+ function getLayoutSizing(node, axis) {
3417
+ const value = _nullishCoalesce(_optionalChain([getChildLayout, 'call', _83 => _83(node), 'access', _84 => _84.sizing, 'optionalAccess', _85 => _85[axis]]), () => ( _optionalChain([getAutoLayout, 'call', _86 => _86(node), 'optionalAccess', _87 => _87.sizing, 'optionalAccess', _88 => _88[axis]])));
3418
+ return value === "hug" || value === "fill" ? value : "fixed";
3419
+ }
3420
+ function limitsOf(node) {
3421
+ const child = getChildLayout(node);
3422
+ const layout2 = getAutoLayout(node);
3423
+ const min = _nullishCoalesce(_nullishCoalesce(child.min, () => ( _optionalChain([layout2, 'optionalAccess', _89 => _89.min]))), () => ( {}));
3424
+ const max = _nullishCoalesce(_nullishCoalesce(child.max, () => ( _optionalChain([layout2, 'optionalAccess', _90 => _90.max]))), () => ( {}));
3425
+ return { minW: min.width, maxW: max.width, minH: min.height, maxH: max.height };
3426
+ }
3427
+ function resolvePadding(padding) {
3428
+ let sides;
3429
+ if (typeof padding === "number") sides = [padding, padding, padding, padding];
3430
+ else if (Array.isArray(padding)) {
3431
+ sides = padding.length === 2 ? [padding[0], padding[1], padding[0], padding[1]] : [padding[0], padding[1], padding[2], padding[3]];
3432
+ } else if (padding && typeof padding === "object") sides = [padding.top, padding.right, padding.bottom, padding.left];
3433
+ else sides = [0, 0, 0, 0];
3434
+ return sides.map((p) => Math.max(finite(p), 0));
3435
+ }
3436
+ var LayoutState = (_class6 = class {
3437
+ __init15() {this.boxes = /* @__PURE__ */ new Map()}
3438
+
3439
+ __init16() {this.visiting = /* @__PURE__ */ new Set()}
3440
+ __init17() {this.original = /* @__PURE__ */ new Map()}
3441
+ constructor(nodes, options = {}) {;_class6.prototype.__init15.call(this);_class6.prototype.__init16.call(this);_class6.prototype.__init17.call(this);
3442
+ this.measure = _nullishCoalesce(options.measure, () => ( {}));
3443
+ for (const node of nodes) {
3444
+ const size = _nullishCoalesce(_optionalChain([this, 'access', _91 => _91.measure, 'access', _92 => _92.size, 'optionalCall', _93 => _93(node)]), () => ( getNodeSize(node, options.rectOptions)));
3445
+ const box = {
3446
+ id: node.id,
3447
+ node,
3448
+ parent: node.parentId,
3449
+ x: finite(_optionalChain([node, 'access', _94 => _94.position, 'optionalAccess', _95 => _95.x])),
3450
+ y: finite(_optionalChain([node, 'access', _96 => _96.position, 'optionalAccess', _97 => _97.y])),
3451
+ w: finite(size.width),
3452
+ h: finite(size.height),
3453
+ kids: []
3454
+ };
3455
+ this.boxes.set(node.id, box);
3456
+ this.original.set(node.id, { x: box.x, y: box.y, w: box.w, h: box.h });
3457
+ }
3458
+ for (const node of nodes) {
3459
+ if (node.parentId && node.parentId !== node.id) _optionalChain([this, 'access', _98 => _98.boxes, 'access', _99 => _99.get, 'call', _100 => _100(node.parentId), 'optionalAccess', _101 => _101.kids, 'access', _102 => _102.push, 'call', _103 => _103(node.id)]);
3460
+ }
3461
+ }
3462
+ updates() {
3463
+ const out = [];
3464
+ for (const [id, box] of this.boxes) {
3465
+ const o = this.original.get(id);
3466
+ const update = { id };
3467
+ if (Math.abs(box.x - o.x) > EPS || Math.abs(box.y - o.y) > EPS) update.position = { x: box.x, y: box.y };
3468
+ if (Math.abs(box.w - o.w) > EPS) update.width = box.w;
3469
+ if (Math.abs(box.h - o.h) > EPS) update.height = box.h;
3470
+ if (update.position || update.width !== void 0 || update.height !== void 0) out.push(update);
3471
+ }
3472
+ return out;
3473
+ }
3474
+ /** Runs `fn` for `id` unless it is already on the stack (guards `parentId` cycles). */
3475
+ guard(id, fn) {
3476
+ if (this.visiting.has(id)) return;
3477
+ this.visiting.add(id);
3478
+ try {
3479
+ fn();
3480
+ } finally {
3481
+ this.visiting.delete(id);
3482
+ }
3483
+ }
3484
+ ancestors(id) {
3485
+ const out = [];
3486
+ const seen = /* @__PURE__ */ new Set([id]);
3487
+ let parent = _optionalChain([this, 'access', _104 => _104.boxes, 'access', _105 => _105.get, 'call', _106 => _106(id), 'optionalAccess', _107 => _107.parent]);
3488
+ while (parent && !seen.has(parent) && this.boxes.has(parent)) {
3489
+ out.push(parent);
3490
+ seen.add(parent);
3491
+ parent = this.boxes.get(parent).parent;
3492
+ }
3493
+ return out;
3494
+ }
3495
+ }, _class6);
3496
+ function setSize(s, id, w, h) {
3497
+ const b = s.boxes.get(id);
3498
+ if (!b) return;
3499
+ b.w = Number.isFinite(w) ? Math.max(w, 0) : b.w;
3500
+ b.h = Number.isFinite(h) ? Math.max(h, 0) : b.h;
3501
+ }
3502
+ function place(s, id, x, y) {
3503
+ const b = s.boxes.get(id);
3504
+ if (!b) return;
3505
+ b.x = x;
3506
+ b.y = y;
3507
+ }
3508
+ var isText = (s, b) => !!s.measure.textSize && s.measure.textSize(b.node) !== void 0;
3509
+ function flowChildren(s, frame) {
3510
+ const f = s.boxes.get(frame);
3511
+ if (!f) return [];
3512
+ return f.kids.filter((k) => {
3513
+ const n = s.boxes.get(k).node;
3514
+ return n.hidden !== true && !getChildLayout(n).absolute;
3515
+ });
3516
+ }
3517
+ function fitHugText(s, id) {
3518
+ const b = s.boxes.get(id);
3519
+ if (!b || !isText(s, b)) return;
3520
+ const natural = s.measure.textSize(b.node);
3521
+ const { minW, maxW } = limitsOf(b.node);
3522
+ if (getLayoutSizing(b.node, "width") === "hug") {
3523
+ const w = clampLayoutSize(natural.width, minW, maxW);
3524
+ const limited = Math.abs(w - natural.width) > EPS;
3525
+ const h = limited ? _nullishCoalesce(_optionalChain([s, 'access', _108 => _108.measure, 'access', _109 => _109.textHeight, 'optionalCall', _110 => _110(b.node, w)]), () => ( natural.height)) : natural.height;
3526
+ setSize(s, id, w, h);
3527
+ } else if (getLayoutSizing(b.node, "height") === "hug") {
3528
+ setSize(s, id, b.w, _nullishCoalesce(_optionalChain([s, 'access', _111 => _111.measure, 'access', _112 => _112.textHeight, 'optionalCall', _113 => _113(b.node, b.w)]), () => ( b.h)));
3529
+ }
3530
+ }
3531
+ function enforceLimits(s, id) {
3532
+ const b = s.boxes.get(id);
3533
+ if (!b) return;
3534
+ const { minW, maxW, minH, maxH } = limitsOf(b.node);
3535
+ if (minW === void 0 && maxW === void 0 && minH === void 0 && maxH === void 0) return;
3536
+ const nw = clampLayoutSize(b.w, minW, maxW);
3537
+ const nh = clampLayoutSize(b.h, minH, maxH);
3538
+ if (Math.abs(nw - b.w) < 1e-9 && Math.abs(nh - b.h) < 1e-9) return;
3539
+ if (isText(s, b)) setSize(s, id, nw, nh);
3540
+ else resizeChild(s, id, nw, nh);
3541
+ }
3542
+ function itemBaseline(s, id, depth) {
3543
+ const b = s.boxes.get(id);
3544
+ if (!b) return void 0;
3545
+ if (isText(s, b)) {
3546
+ const v = _optionalChain([s, 'access', _114 => _114.measure, 'access', _115 => _115.textBaseline, 'optionalCall', _116 => _116(b.node)]);
3547
+ return typeof v === "number" && Number.isFinite(v) ? v : void 0;
3548
+ }
3549
+ const layout2 = getAutoLayout(b.node);
3550
+ if (!layout2 || layout2.mode === "grid" || depth >= 32) return void 0;
3551
+ for (const k of flowChildren(s, id)) {
3552
+ const base = itemBaseline(s, k, depth + 1);
3553
+ if (base !== void 0) return s.boxes.get(k).y + base;
3554
+ }
3555
+ return void 0;
3556
+ }
3557
+ function resizeChild(s, id, w, h) {
3558
+ const b = s.boxes.get(id);
3559
+ if (!b) return;
3560
+ if (isText(s, b) && getLayoutSizing(b.node, "height") === "hug") {
3561
+ setSize(s, id, w, _nullishCoalesce(_optionalChain([s, 'access', _117 => _117.measure, 'access', _118 => _118.textHeight, 'optionalCall', _119 => _119(b.node, w)]), () => ( h)));
3562
+ return;
3563
+ }
3564
+ const ow = b.w;
3565
+ const oh = b.h;
3566
+ setSize(s, id, w, h);
3567
+ if (b.kids.length > 0) constrain(s, id, ow, oh);
3568
+ if (getAutoLayout(b.node)) layout(s, id);
3569
+ }
3570
+ function mainOffsets(align, inner, total, n, gap) {
3571
+ const gaps = gap * Math.max(n - 1, 0);
3572
+ const free = inner - total;
3573
+ const k = Math.max(n, 1);
3574
+ switch (align) {
3575
+ case "center":
3576
+ return [(free - gaps) / 2, gap];
3577
+ case "end":
3578
+ return [free - gaps, gap];
3579
+ case "space-between":
3580
+ return [0, n > 1 ? Math.max(free / (n - 1), 0) : 0];
3581
+ case "space-around": {
3582
+ const g = Math.max(free / k, 0);
3583
+ return [g / 2, g];
3584
+ }
3585
+ case "space-evenly": {
3586
+ const g = Math.max(free / (k + 1), 0);
3587
+ return [g, g];
3588
+ }
3589
+ default:
3590
+ return [0, gap];
3591
+ }
3592
+ }
3593
+ function distribute(items, open, free) {
3594
+ free = Math.max(free, 0);
3595
+ while (open.length > 0) {
3596
+ const share = free / open.length;
3597
+ const sized = open.map((i) => [i, clampLayoutSize(share, items[i].minMain, items[i].maxMain)]);
3598
+ const violation = sized.reduce((sum, [, v]) => sum + (v - share), 0);
3599
+ const frozen = (v) => Math.abs(violation) < 1e-9 || violation > 0 && v > share + 1e-9 || violation < 0 && v < share - 1e-9;
3600
+ for (const [i, v] of sized) {
3601
+ if (frozen(v)) {
3602
+ items[i].main = v;
3603
+ free -= v;
3604
+ }
3605
+ }
3606
+ free = Math.max(free, 0);
3607
+ open = sized.filter(([, v]) => !frozen(v)).map(([i]) => i);
3608
+ }
3609
+ }
3610
+ function layout(s, frame) {
3611
+ s.guard(frame, () => layoutFrameInner(s, frame));
3612
+ }
3613
+ function layoutFrameInner(s, frame) {
3614
+ const f = s.boxes.get(frame);
3615
+ const al = f && getAutoLayout(f.node);
3616
+ if (!f || !al) return;
3617
+ const horizontal = al.mode !== "vertical";
3618
+ const hugW = getLayoutSizing(f.node, "width") === "hug";
3619
+ const hugH = getLayoutSizing(f.node, "height") === "hug";
3620
+ const ow = f.w;
3621
+ const oh = f.h;
3622
+ const fl = limitsOf(f.node);
3623
+ const [pt, pr, pb, pl] = resolvePadding(al.padding);
3624
+ const fw = Math.max(clampLayoutSize(ow, fl.minW, fl.maxW), pl + pr);
3625
+ const fh = Math.max(clampLayoutSize(oh, fl.minH, fl.maxH), pt + pb);
3626
+ const kids = flowChildren(s, frame);
3627
+ for (const c of kids) {
3628
+ fitHugText(s, c);
3629
+ enforceLimits(s, c);
3630
+ }
3631
+ if (al.mode === "grid") {
3632
+ layoutGrid(s, frame, al);
3633
+ return;
3634
+ }
3635
+ const innerMainFixed = horizontal ? fw - pl - pr : fh - pt - pb;
3636
+ const innerCrossFixed = horizontal ? fh - pt - pb : fw - pl - pr;
3637
+ const hugMain = horizontal ? hugW : hugH;
3638
+ const hugCross = horizontal ? hugH : hugW;
3639
+ const alignCross = _nullishCoalesce(al.alignCross, () => ( "start"));
3640
+ const baseline = horizontal && alignCross === "baseline";
3641
+ const stretch = alignCross === "stretch";
3642
+ const items = [];
3643
+ for (const c of kids) {
3644
+ const b = s.boxes.get(c);
3645
+ const lim = limitsOf(b.node);
3646
+ const sm = getLayoutSizing(b.node, horizontal ? "width" : "height");
3647
+ const sc = getLayoutSizing(b.node, horizontal ? "height" : "width");
3648
+ items.push({
3649
+ id: c,
3650
+ main: horizontal ? b.w : b.h,
3651
+ cross: horizontal ? b.h : b.w,
3652
+ // Fill needs room to fill: on an axis the frame hugs it reads as fixed.
3653
+ fillMain: sm === "fill" && !hugMain,
3654
+ fillCross: (sc === "fill" || stretch && sc !== "hug") && !hugCross,
3655
+ minMain: horizontal ? lim.minW : lim.minH,
3656
+ maxMain: horizontal ? lim.maxW : lim.maxH,
3657
+ minCross: horizontal ? lim.minH : lim.minW,
3658
+ maxCross: horizontal ? lim.maxH : lim.maxW,
3659
+ baseOff: 0
3660
+ });
3661
+ }
3662
+ const gap = finite(al.gap);
3663
+ const alignMain = _nullishCoalesce(al.alignMain, () => ( "start"));
3664
+ const autoGap = alignMain === "space-between" || alignMain === "space-around" || alignMain === "space-evenly";
3665
+ const wraps = !!al.wrap && !hugMain;
3666
+ const sizeOf = (id) => {
3667
+ const b = s.boxes.get(id);
3668
+ return horizontal ? [b.w, b.h] : [b.h, b.w];
3669
+ };
3670
+ const resize = (it, main, cross) => resizeChild(s, it.id, horizontal ? main : cross, horizontal ? cross : main);
3671
+ if (!wraps) {
3672
+ for (const it of items) {
3673
+ if (!it.fillCross || it.fillMain) continue;
3674
+ resize(it, it.main, clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross));
3675
+ it.main = sizeOf(it.id)[0];
3676
+ }
3677
+ }
3678
+ const lines = [];
3679
+ if (wraps) {
3680
+ let cur = [];
3681
+ let used = 0;
3682
+ items.forEach((it, i) => {
3683
+ const sz = it.fillMain ? _nullishCoalesce(it.minMain, () => ( 0)) : it.main;
3684
+ const add2 = cur.length === 0 ? sz : Math.max(gap, 0) + sz;
3685
+ if (cur.length > 0 && used + add2 > innerMainFixed + 1e-6) {
3686
+ lines.push(cur);
3687
+ cur = [];
3688
+ used = sz;
3689
+ } else {
3690
+ used += add2;
3691
+ }
3692
+ cur.push(i);
3693
+ });
3694
+ if (cur.length > 0) lines.push(cur);
3695
+ } else {
3696
+ lines.push(items.map((_, i) => i));
3697
+ }
3698
+ for (const line2 of lines) {
3699
+ const fixed = line2.filter((i) => !items[i].fillMain).reduce((sum, i) => sum + items[i].main, 0);
3700
+ const gaps = gap * Math.max(line2.length - 1, 0);
3701
+ const fills = line2.filter((i) => items[i].fillMain);
3702
+ if (fills.length > 0) distribute(items, fills, innerMainFixed - fixed - (autoGap ? 0 : gaps));
3703
+ }
3704
+ for (const it of items) {
3705
+ if (!it.fillMain) continue;
3706
+ const cross = it.fillCross && !wraps ? clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross) : it.cross;
3707
+ resize(it, it.main, cross);
3708
+ it.cross = sizeOf(it.id)[1];
3709
+ }
3710
+ if (baseline) {
3711
+ for (const it of items) if (!it.fillCross) it.baseline = itemBaseline(s, it.id, 0);
3712
+ }
3713
+ const extents = [];
3714
+ for (const line2 of lines) {
3715
+ const gaps = gap * Math.max(line2.length - 1, 0);
3716
+ const lineBase = line2.reduce((m, i) => Math.max(m, _nullishCoalesce(items[i].baseline, () => ( 0))), 0);
3717
+ for (const i of line2) items[i].baseOff = items[i].baseline !== void 0 ? lineBase - items[i].baseline : 0;
3718
+ const inLine = line2.map((i) => items[i]);
3719
+ const mainUsed = inLine.reduce((sum, it) => sum + it.main, 0) + gaps;
3720
+ const allFill = inLine.every((it) => it.fillCross);
3721
+ const cross = inLine.filter((it) => allFill || !it.fillCross).reduce((m, it) => Math.max(m, it.baseOff + it.cross), 0);
3722
+ extents.push([mainUsed, cross]);
3723
+ }
3724
+ const contentMain = extents.reduce((m, l) => Math.max(m, l[0]), 0);
3725
+ let crossGap = al.rowGap !== void 0 ? finite(al.rowGap) : gap;
3726
+ const contentCross = extents.reduce((sum, l) => sum + l[1], 0) + crossGap * Math.max(lines.length - 1, 0);
3727
+ let nw = fw;
3728
+ let nh = fh;
3729
+ if (hugMain) {
3730
+ const v = contentMain + (horizontal ? pl + pr : pt + pb);
3731
+ if (horizontal) nw = v;
3732
+ else nh = v;
3733
+ }
3734
+ if (hugCross) {
3735
+ const v = contentCross + (horizontal ? pt + pb : pl + pr);
3736
+ if (horizontal) nh = v;
3737
+ else nw = v;
3738
+ }
3739
+ nw = Math.max(clampLayoutSize(nw, fl.minW, fl.maxW), pl + pr);
3740
+ nh = Math.max(clampLayoutSize(nh, fl.minH, fl.maxH), pt + pb);
3741
+ setSize(s, frame, nw, nh);
3742
+ constrain(s, frame, ow, oh);
3743
+ const innerMain = horizontal ? nw - pl - pr : nh - pt - pb;
3744
+ const innerCross = horizontal ? nh - pt - pb : nw - pl - pr;
3745
+ let crossPos = horizontal ? pt : pl;
3746
+ const single = lines.length === 1;
3747
+ if (lines.length > 1) {
3748
+ const linesCross = extents.reduce((sum, l) => sum + l[1], 0);
3749
+ const between = lines.length - 1;
3750
+ const spread = (innerCross - linesCross) / between;
3751
+ const spaceBetween = al.alignContent === "space-between";
3752
+ if (spaceBetween && spread > 0) {
3753
+ crossGap = spread;
3754
+ } else {
3755
+ if (spaceBetween) crossGap = 0;
3756
+ const free = innerCross - linesCross - crossGap * between;
3757
+ if (free > 0 && items.every((it) => it.fillCross)) {
3758
+ const extra = free / lines.length;
3759
+ for (const l of extents) l[1] += extra;
3760
+ } else if (Number.isFinite(free)) {
3761
+ crossPos += alignCross === "center" ? free / 2 : alignCross === "end" ? free : 0;
3762
+ }
3763
+ }
3764
+ }
3765
+ lines.forEach((line2, li) => {
3766
+ const [used, ownCross] = extents[li];
3767
+ const lineCross = single ? innerCross : ownCross;
3768
+ const total = used - gap * Math.max(line2.length - 1, 0);
3769
+ let [pos, step] = mainOffsets(alignMain, innerMain, total, line2.length, gap);
3770
+ pos += horizontal ? pl : pt;
3771
+ for (const i of line2) {
3772
+ const it = items[i];
3773
+ const crossSize = it.fillCross ? clampLayoutSize(lineCross, it.minCross, it.maxCross) : it.cross;
3774
+ let off = 0;
3775
+ if (alignCross === "baseline") off = it.baseOff;
3776
+ else if (alignCross === "center") off = (lineCross - crossSize) / 2;
3777
+ else if (alignCross === "end") off = lineCross - crossSize;
3778
+ if (it.fillCross && wraps) resize(it, it.main, crossSize);
3779
+ const x = horizontal ? pos : crossPos + off;
3780
+ const y = horizontal ? crossPos + off : pos;
3781
+ place(s, it.id, finite(x), finite(y));
3782
+ pos += it.main + step;
3783
+ }
3784
+ crossPos += lineCross + crossGap;
3785
+ });
3786
+ }
3787
+ function parseTrack(track) {
3788
+ if (typeof track === "number") return { sizing: "fixed", value: track };
3789
+ if (track === "hug") return { sizing: "hug", value: 0 };
3790
+ if (typeof track === "string") {
3791
+ const match = /^\s*(-?\d*\.?\d+)\s*fr\s*$/i.exec(track);
3792
+ if (match) return { sizing: "fill", value: Number(match[1]) };
3793
+ }
3794
+ if (track && typeof track === "object" && "fr" in track) return { sizing: "fill", value: track.fr };
3795
+ return { sizing: "fill", value: 1 };
3796
+ }
3797
+ function trackList(spec, fallback) {
3798
+ if (Array.isArray(spec)) return { count: Math.min(Math.max(spec.length, 1), MAX_TRACKS), tracks: spec.map(parseTrack) };
3799
+ const n = typeof spec === "number" && Number.isFinite(spec) ? Math.floor(spec) : fallback;
3800
+ return { count: Math.min(Math.max(n, 1), MAX_TRACKS), tracks: [] };
3801
+ }
3802
+ function trackSpec(tracks, i) {
3803
+ const t = _nullishCoalesce(tracks[i], () => ( { sizing: "fill", value: 1 }));
3804
+ const value = Number.isFinite(t.value) ? Math.min(Math.max(t.value, 0), 1e6) : 0;
3805
+ return { sizing: t.sizing, value };
3806
+ }
3807
+ function cellRect(g, c) {
3808
+ const x0 = _nullishCoalesce(_optionalChain([g, 'access', _120 => _120.columns, 'access', _121 => _121[c.column], 'optionalAccess', _122 => _122[0]]), () => ( 0));
3809
+ const x1 = _nullishCoalesce(_optionalChain([g, 'access', _123 => _123.columns, 'access', _124 => _124[c.column + c.columnSpan - 1], 'optionalAccess', _125 => _125[1]]), () => ( x0));
3810
+ const y0 = _nullishCoalesce(_optionalChain([g, 'access', _126 => _126.rows, 'access', _127 => _127[c.row], 'optionalAccess', _128 => _128[0]]), () => ( 0));
3811
+ const y1 = _nullishCoalesce(_optionalChain([g, 'access', _129 => _129.rows, 'access', _130 => _130[c.row + c.rowSpan - 1], 'optionalAccess', _131 => _131[1]]), () => ( y0));
3812
+ return { x: x0, y: y0, width: Math.max(x1, x0) - x0, height: Math.max(y1, y0) - y0 };
3813
+ }
3814
+ var toIndex = (v) => typeof v === "number" && Number.isFinite(v) && v >= 0 ? Math.floor(v) : void 0;
3815
+ function gridPlace(s, al, kids) {
3816
+ const cols = trackList(_optionalChain([al, 'access', _132 => _132.grid, 'optionalAccess', _133 => _133.columns]), 2).count;
3817
+ const minRows = trackList(_optionalChain([al, 'access', _134 => _134.grid, 'optionalAccess', _135 => _135.rows]), 1).count;
3818
+ const maxRows = Math.min(Math.max(Math.floor(MAX_GRID_CELLS / cols), 1), MAX_TRACKS);
3819
+ const occ = [];
3820
+ const free = (c, r, cs, rs) => {
3821
+ for (let ri = r; ri < r + rs; ri++) {
3822
+ const row = occ[ri];
3823
+ if (!row) continue;
3824
+ for (let ci = c; ci < c + cs; ci++) if (row[ci]) return false;
3825
+ }
3826
+ return true;
3827
+ };
3828
+ const mark = (c, r, cs, rs) => {
3829
+ while (occ.length < r + rs) occ.push(new Array(cols).fill(false));
3830
+ for (let ri = r; ri < r + rs; ri++) for (let ci = c; ci < c + cs; ci++) occ[ri][ci] = true;
3831
+ };
3832
+ const spans = (id) => {
3833
+ const area = _nullishCoalesce(getChildLayout(s.boxes.get(id).node).gridArea, () => ( {}));
3834
+ const cs = Math.min(Math.max(_nullishCoalesce(toIndex(area.columnSpan), () => ( 1)), 1), cols);
3835
+ const rs = Math.min(Math.max(_nullishCoalesce(toIndex(area.rowSpan), () => ( 1)), 1), maxRows);
3836
+ const col = toIndex(area.column);
3837
+ const row = toIndex(area.row);
3838
+ return {
3839
+ col: col === void 0 ? void 0 : Math.min(col, cols - cs),
3840
+ row: row === void 0 ? void 0 : Math.min(row, maxRows - rs),
3841
+ cs,
3842
+ rs
3843
+ };
3844
+ };
3845
+ const placed = new Array(kids.length).fill(void 0);
3846
+ kids.forEach((id, i) => {
3847
+ const { col, row, cs, rs } = spans(id);
3848
+ if (col !== void 0 && row !== void 0) {
3849
+ mark(col, row, cs, rs);
3850
+ placed[i] = { id, column: col, row, columnSpan: cs, rowSpan: rs };
3851
+ }
3852
+ });
3853
+ let cursor = [0, 0];
3854
+ kids.forEach((id, i) => {
3855
+ if (placed[i]) return;
3856
+ const { col, row, cs, rs } = spans(id);
3857
+ const lastRow = maxRows - rs;
3858
+ let c = 0;
3859
+ let r = 0;
3860
+ if (col !== void 0) {
3861
+ r = lastRow;
3862
+ for (let ri = 0; ri <= lastRow; ri++) if (free(col, ri, cs, rs)) {
3863
+ r = ri;
3864
+ break;
3865
+ }
3866
+ c = col;
3867
+ } else if (row !== void 0) {
3868
+ r = row;
3869
+ for (let ci = 0; ci <= cols - cs; ci++) if (free(ci, row, cs, rs)) {
3870
+ c = ci;
3871
+ break;
3872
+ }
3873
+ } else {
3874
+ let [rr, cc] = cursor;
3875
+ let found;
3876
+ while (rr <= lastRow) {
3877
+ if (cc + cs <= cols && free(cc, rr, cs, rs)) {
3878
+ found = [cc, rr];
3879
+ break;
3880
+ }
3881
+ cc += 1;
3882
+ if (cc + cs > cols) {
3883
+ cc = 0;
3884
+ rr += 1;
3885
+ }
3886
+ }
3887
+ [c, r] = _nullishCoalesce(found, () => ( [0, lastRow]));
3888
+ cursor = [r, c + cs];
3889
+ }
3890
+ mark(c, r, cs, rs);
3891
+ placed[i] = { id, column: c, row: r, columnSpan: cs, rowSpan: rs };
3892
+ });
3893
+ const cells = placed.filter((c) => !!c);
3894
+ const rows = Math.max(cells.reduce((m, c) => Math.max(m, c.row + c.rowSpan), 0), minRows);
3895
+ return { cells, rows: Math.min(rows, MAX_TRACKS) };
3896
+ }
3897
+ function resolveTracks(tracks, content, avail) {
3898
+ const out = content.map((c, i) => {
3899
+ const t = trackSpec(tracks, i);
3900
+ return t.sizing === "fixed" ? t.value : c;
3901
+ });
3902
+ if (avail === void 0) return out;
3903
+ const fr = (i) => trackSpec(tracks, i).value;
3904
+ let flex = out.map((_, i) => i).filter((i) => trackSpec(tracks, i).sizing === "fill");
3905
+ let used = out.reduce((sum, v, i) => trackSpec(tracks, i).sizing === "fill" ? sum : sum + v, 0);
3906
+ while (flex.length > 0) {
3907
+ const total = flex.reduce((sum, i) => sum + fr(i), 0);
3908
+ const unit2 = total > 1e-12 ? Math.max(avail - used, 0) / total : 0;
3909
+ const open = flex.filter((i) => unit2 * fr(i) >= out[i]);
3910
+ const frozen = flex.filter((i) => unit2 * fr(i) < out[i]);
3911
+ if (frozen.length === 0) {
3912
+ for (const i of open) out[i] = unit2 * fr(i);
3913
+ break;
3914
+ }
3915
+ used += frozen.reduce((sum, i) => sum + out[i], 0);
3916
+ flex = open;
3917
+ }
3918
+ return out;
3919
+ }
3920
+ function trackContent(cells, sizes, tracks, n, gap, columns, hug) {
3921
+ const byContent = (i) => trackSpec(tracks, i).sizing !== "fixed";
3922
+ const content = Array.from({ length: n }, (_, i) => {
3923
+ const t = trackSpec(tracks, i);
3924
+ return t.sizing === "fixed" ? t.value : 0;
3925
+ });
3926
+ const span = (c) => columns ? [c.column, c.columnSpan] : [c.row, c.rowSpan];
3927
+ cells.forEach((c, k) => {
3928
+ const [start, len] = span(c);
3929
+ if (len === 1 && byContent(start) && start < n) content[start] = Math.max(content[start], sizes[k]);
3930
+ });
3931
+ cells.forEach((c, k) => {
3932
+ const [start, len] = span(c);
3933
+ if (len < 2) return;
3934
+ const range = Array.from({ length: len }, (_, j) => start + j).filter((i) => i < n);
3935
+ if (!hug && range.some((i) => trackSpec(tracks, i).sizing === "fill")) return;
3936
+ const have = range.reduce((sum, i) => sum + content[i], 0) + gap * (len - 1);
3937
+ const grow = range.filter(byContent);
3938
+ if (sizes[k] > have && grow.length > 0) {
3939
+ const extra = (sizes[k] - have) / grow.length;
3940
+ for (const i of grow) content[i] += extra;
3941
+ }
3942
+ });
3943
+ return content;
3944
+ }
3945
+ function trackRanges(start, sizes, gap) {
3946
+ let x = start;
3947
+ return sizes.map((size) => {
3948
+ const r = [x, x + size];
3949
+ x += size + gap;
3950
+ return r;
3951
+ });
3952
+ }
3953
+ function gridGeometryOf(s, frame) {
3954
+ const f = s.boxes.get(frame);
3955
+ const al = f && getAutoLayout(f.node);
3956
+ if (!f || !al || al.mode !== "grid") return void 0;
3957
+ const [pt, pr, pb, pl] = resolvePadding(al.padding);
3958
+ const kids = flowChildren(s, frame);
3959
+ const { cells, rows } = gridPlace(s, al, kids);
3960
+ const colSpec = trackList(_optionalChain([al, 'access', _136 => _136.grid, 'optionalAccess', _137 => _137.columns]), 2);
3961
+ const rowSpec = trackList(_optionalChain([al, 'access', _138 => _138.grid, 'optionalAccess', _139 => _139.rows]), 1);
3962
+ const cols = colSpec.count;
3963
+ const gx = Math.max(finite(al.gap), 0);
3964
+ const gy = Math.max(al.rowGap !== void 0 ? finite(al.rowGap) : gx, 0);
3965
+ const hugW = getLayoutSizing(f.node, "width") === "hug";
3966
+ const hugH = getLayoutSizing(f.node, "height") === "hug";
3967
+ const ws = [];
3968
+ const hs = [];
3969
+ for (const c of cells) {
3970
+ const b = s.boxes.get(c.id);
3971
+ const lim2 = limitsOf(b.node);
3972
+ ws.push(getLayoutSizing(b.node, "width") === "fill" && !hugW ? _nullishCoalesce(lim2.minW, () => ( 0)) : b.w);
3973
+ hs.push(getLayoutSizing(b.node, "height") === "fill" && !hugH ? _nullishCoalesce(lim2.minH, () => ( 0)) : b.h);
3974
+ }
3975
+ const colContent = trackContent(cells, ws, colSpec.tracks, cols, gx, true, hugW);
3976
+ const rowContent = trackContent(cells, hs, rowSpec.tracks, rows, gy, false, hugH);
3977
+ const gapsW = gx * Math.max(cols - 1, 0);
3978
+ const gapsH = gy * Math.max(rows - 1, 0);
3979
+ const colW = resolveTracks(colSpec.tracks, colContent, hugW ? void 0 : finite(f.w) - pl - pr - gapsW);
3980
+ const rowH = resolveTracks(rowSpec.tracks, rowContent, hugH ? void 0 : finite(f.h) - pt - pb - gapsH);
3981
+ const lim = limitsOf(f.node);
3982
+ const width = hugW ? colW.reduce((a, b) => a + b, 0) + gapsW + pl + pr : finite(f.w);
3983
+ const height = hugH ? rowH.reduce((a, b) => a + b, 0) + gapsH + pt + pb : finite(f.h);
3984
+ return {
3985
+ columns: trackRanges(pl, colW, gx),
3986
+ rows: trackRanges(pt, rowH, gy),
3987
+ cells,
3988
+ width: Math.max(clampLayoutSize(width, lim.minW, lim.maxW), pl + pr),
3989
+ height: Math.max(clampLayoutSize(height, lim.minH, lim.maxH), pt + pb)
3990
+ };
3991
+ }
3992
+ function layoutGrid(s, frame, al) {
3993
+ const f = s.boxes.get(frame);
3994
+ const fw = f.w;
3995
+ const fh = f.h;
3996
+ const hugW = getLayoutSizing(f.node, "width") === "hug";
3997
+ const hugH = getLayoutSizing(f.node, "height") === "hug";
3998
+ const lim = limitsOf(f.node);
3999
+ const [pt, pr, pb, pl] = resolvePadding(al.padding);
4000
+ setSize(
4001
+ s,
4002
+ frame,
4003
+ hugW ? fw : Math.max(clampLayoutSize(fw, lim.minW, lim.maxW), pl + pr),
4004
+ hugH ? fh : Math.max(clampLayoutSize(fh, lim.minH, lim.maxH), pt + pb)
4005
+ );
4006
+ let g = gridGeometryOf(s, frame);
4007
+ if (!g) return;
4008
+ let widened = false;
4009
+ for (const c of g.cells) {
4010
+ const b = s.boxes.get(c.id);
4011
+ if (getLayoutSizing(b.node, "width") === "fill" && !hugW) {
4012
+ const l = limitsOf(b.node);
4013
+ resizeChild(s, c.id, clampLayoutSize(cellRect(g, c).width, l.minW, l.maxW), b.h);
4014
+ widened = true;
4015
+ }
4016
+ }
4017
+ if (widened) g = _nullishCoalesce(gridGeometryOf(s, frame), () => ( g));
4018
+ setSize(s, frame, g.width, g.height);
4019
+ constrain(s, frame, fw, fh);
4020
+ const frameX = al.alignMain === "center" ? "center" : al.alignMain === "end" ? "end" : "start";
4021
+ const frameY = al.alignCross === "center" ? "center" : al.alignCross === "end" ? "end" : "start";
4022
+ const offset = (a, free) => a === "center" ? free / 2 : a === "end" ? free : 0;
4023
+ for (const c of g.cells) {
4024
+ const cell = cellRect(g, c);
4025
+ const b = s.boxes.get(c.id);
4026
+ const l = limitsOf(b.node);
4027
+ const area = _nullishCoalesce(getChildLayout(b.node).gridArea, () => ( {}));
4028
+ const fillW = getLayoutSizing(b.node, "width") === "fill" && !hugW;
4029
+ const fillH = getLayoutSizing(b.node, "height") === "fill" && !hugH;
4030
+ if (fillW || fillH) {
4031
+ resizeChild(
4032
+ s,
4033
+ c.id,
4034
+ fillW ? clampLayoutSize(cell.width, l.minW, l.maxW) : b.w,
4035
+ fillH ? clampLayoutSize(cell.height, l.minH, l.maxH) : b.h
4036
+ );
4037
+ }
4038
+ const ox = offset(_nullishCoalesce(area.alignX, () => ( frameX)), cell.width - b.w);
4039
+ const oy = offset(_nullishCoalesce(area.alignY, () => ( frameY)), cell.height - b.h);
4040
+ place(s, c.id, finite(cell.x + ox), finite(cell.y + oy));
4041
+ }
4042
+ }
4043
+ function constrain(s, id, ow, oh) {
4044
+ const f = s.boxes.get(id);
4045
+ if (!f) return;
4046
+ const nw = f.w;
4047
+ const nh = f.h;
4048
+ if (Math.abs(nw - ow) < 1e-9 && Math.abs(nh - oh) < 1e-9) return;
4049
+ const absoluteOnly = !!getAutoLayout(f.node);
4050
+ const sx = ow > 1e-9 ? nw / ow : 1;
4051
+ const sy = oh > 1e-9 ? nh / oh : 1;
4052
+ s.guard(`constrain:${id}`, () => {
4053
+ for (const k of f.kids) {
4054
+ const c = s.boxes.get(k);
4055
+ const child = getChildLayout(c.node);
4056
+ if (absoluteOnly && !child.absolute) continue;
4057
+ let x0 = c.x;
4058
+ let x1 = c.x + c.w;
4059
+ let y0 = c.y;
4060
+ let y1 = c.y + c.h;
4061
+ const dx = nw - ow;
4062
+ const dy = nh - oh;
4063
+ switch (_nullishCoalesce(_optionalChain([child, 'access', _140 => _140.constraints, 'optionalAccess', _141 => _141.horizontal]), () => ( "left"))) {
4064
+ case "right":
4065
+ x0 += dx;
4066
+ x1 += dx;
4067
+ break;
4068
+ case "leftRight":
4069
+ x1 += dx;
4070
+ break;
4071
+ case "center":
4072
+ x0 += dx / 2;
4073
+ x1 += dx / 2;
4074
+ break;
4075
+ case "scale":
4076
+ x0 *= sx;
4077
+ x1 *= sx;
4078
+ break;
4079
+ }
4080
+ switch (_nullishCoalesce(_optionalChain([child, 'access', _142 => _142.constraints, 'optionalAccess', _143 => _143.vertical]), () => ( "top"))) {
4081
+ case "bottom":
4082
+ y0 += dy;
4083
+ y1 += dy;
4084
+ break;
4085
+ case "topBottom":
4086
+ y1 += dy;
4087
+ break;
4088
+ case "center":
4089
+ y0 += dy / 2;
4090
+ y1 += dy / 2;
4091
+ break;
4092
+ case "scale":
4093
+ y0 *= sy;
4094
+ y1 *= sy;
4095
+ break;
4096
+ }
4097
+ const cw = c.w;
4098
+ const ch = c.h;
4099
+ const resized = Math.abs(x1 - x0 - cw) > 1e-9 || Math.abs(y1 - y0 - ch) > 1e-9;
4100
+ place(s, k, finite(x0), finite(y0));
4101
+ if (resized) {
4102
+ setSize(s, k, x1 - x0, y1 - y0);
4103
+ if (c.kids.length > 0) constrain(s, k, cw, ch);
4104
+ if (getAutoLayout(c.node)) layout(s, k);
4105
+ }
4106
+ }
4107
+ });
4108
+ }
4109
+ function layoutFrame(nodes, frameId, options = {}) {
4110
+ const s = new LayoutState(nodes, options);
4111
+ layout(s, frameId);
4112
+ return s.updates();
4113
+ }
4114
+ function postOrder(s, nodes) {
4115
+ const out = [];
4116
+ const seen = /* @__PURE__ */ new Set();
4117
+ const visit = (id) => {
4118
+ if (seen.has(id)) return;
4119
+ seen.add(id);
4120
+ for (const k of _nullishCoalesce(_optionalChain([s, 'access', _144 => _144.boxes, 'access', _145 => _145.get, 'call', _146 => _146(id), 'optionalAccess', _147 => _147.kids]), () => ( []))) visit(k);
4121
+ out.push(id);
4122
+ };
4123
+ const roots = nodes.filter((n) => !n.parentId || !s.boxes.has(n.parentId));
4124
+ for (const r of roots) visit(r.id);
4125
+ for (const n of nodes) visit(n.id);
4126
+ return out;
4127
+ }
4128
+ function layoutAll(nodes, options = {}) {
4129
+ const s = new LayoutState(nodes, options);
4130
+ for (const id of postOrder(s, nodes)) if (getAutoLayout(s.boxes.get(id).node)) layout(s, id);
4131
+ return s.updates();
4132
+ }
4133
+ function layoutUp(nodes, changedId, options = {}) {
4134
+ return layoutUpMany(nodes, [changedId], options);
4135
+ }
4136
+ function layoutUpMany(nodes, changedIds, options = {}) {
4137
+ const s = new LayoutState(nodes, options);
4138
+ const chains = [...new Set(changedIds)].filter((id) => s.boxes.has(id)).map((id) => [id, ...s.ancestors(id)]);
4139
+ const depth = /* @__PURE__ */ new Map();
4140
+ for (const chain of chains) chain.forEach((id, i) => depth.set(id, Math.max(_nullishCoalesce(depth.get(id), () => ( 0)), chain.length - 1 - i)));
4141
+ const order = [...depth.keys()].sort((a, b) => depth.get(b) - depth.get(a));
4142
+ for (const id of order) if (getAutoLayout(s.boxes.get(id).node)) layout(s, id);
4143
+ return s.updates();
4144
+ }
4145
+ function applyConstraints(nodes, parentId, previousSize, options = {}) {
4146
+ const s = new LayoutState(nodes, options);
4147
+ constrain(s, parentId, previousSize.width, previousSize.height);
4148
+ return s.updates();
4149
+ }
4150
+ function getAutoLayoutGrid(nodes, frameId, options = {}) {
4151
+ return gridGeometryOf(new LayoutState(nodes, options), frameId);
4152
+ }
4153
+ function getFlowChildren(nodes, frameId) {
4154
+ return nodes.filter((n) => n.parentId === frameId && n.id !== frameId && n.hidden !== true && !getChildLayout(n).absolute).map((n) => n.id);
4155
+ }
4156
+ function getLayoutParent(nodes, id) {
4157
+ const lookup = createNodeLookup(nodes);
4158
+ const node = lookup.get(id);
4159
+ if (!_optionalChain([node, 'optionalAccess', _148 => _148.parentId]) || getChildLayout(node).absolute) return void 0;
4160
+ const parent = lookup.get(node.parentId);
4161
+ return isAutoLayoutFrame(parent) ? parent : void 0;
4162
+ }
4163
+ function makeSizingCoherent(nodes, id, options = {}) {
4164
+ const lookup = createNodeLookup(nodes);
4165
+ const targets = /* @__PURE__ */ new Set([id, ...nodes.filter((n) => n.parentId === id).map((n) => n.id)]);
4166
+ if (!lookup.has(id)) return nodes;
4167
+ let changed = false;
4168
+ const next = nodes.map((node) => {
4169
+ if (!targets.has(node.id)) return node;
4170
+ const parent = node.parentId ? lookup.get(node.parentId) : void 0;
4171
+ const flowParent = parent && isAutoLayoutFrame(parent) && !getChildLayout(node).absolute ? parent : void 0;
4172
+ const canHug = isAutoLayoutFrame(node) || _optionalChain([options, 'access', _149 => _149.measure, 'optionalAccess', _150 => _150.textSize, 'optionalCall', _151 => _151(node)]) !== void 0;
4173
+ const coherent = (axis) => {
4174
+ const sizing = getLayoutSizing(node, axis);
4175
+ if (sizing === "fill" && (!flowParent || getLayoutSizing(flowParent, axis) === "hug")) return "fixed";
4176
+ if (sizing === "hug" && !canHug) return "fixed";
4177
+ return sizing;
4178
+ };
4179
+ const width = coherent("width");
4180
+ const height = coherent("height");
4181
+ if (width === getLayoutSizing(node, "width") && height === getLayoutSizing(node, "height")) return node;
4182
+ changed = true;
4183
+ const child = getChildLayout(node);
4184
+ return {
4185
+ ...node,
4186
+ data: { ...node.data, [CHILD_LAYOUT_DATA_KEY]: { ...child, sizing: { ...child.sizing, width, height } } }
4187
+ };
4188
+ });
4189
+ return changed ? next : nodes;
4190
+ }
4191
+ function getAutoLayoutInsertTarget(nodes, frameId, point, options = {}) {
4192
+ const lookup = createNodeLookup(nodes);
4193
+ const frame = lookup.get(frameId);
4194
+ const al = getAutoLayout(frame);
4195
+ if (!frame || !al) return void 0;
4196
+ const s = new LayoutState(nodes, options);
4197
+ const origin = getAbsolutePosition(frame, lookup);
4198
+ const px = point.x - origin.x;
4199
+ const py = point.y - origin.y;
4200
+ const siblings = flowChildren(s, frameId).filter((id) => id !== options.excludeId).map((id) => s.boxes.get(id));
4201
+ const horizontal = al.mode !== "vertical";
4202
+ const main = (b) => horizontal ? b.x : b.y;
4203
+ const mainSize = (b) => horizontal ? b.w : b.h;
4204
+ const cross = (b) => horizontal ? b.y : b.x;
4205
+ const crossSize = (b) => horizontal ? b.h : b.w;
4206
+ const p = { x: px, y: py };
4207
+ const multiLine = al.mode === "grid" || !!al.wrap;
4208
+ let index = 0;
4209
+ for (const b of siblings) {
4210
+ const before = multiLine ? cross(b) + crossSize(b) <= cross(p) || cross(b) <= cross(p) && main(b) + mainSize(b) / 2 < main(p) : main(b) + mainSize(b) / 2 < main(p);
4211
+ if (before) index += 1;
4212
+ }
4213
+ const [pt, pr, pb, pl] = resolvePadding(al.padding);
4214
+ const prev = siblings[index - 1];
4215
+ const next = siblings[index];
4216
+ const f = s.boxes.get(frameId);
4217
+ let guide;
4218
+ if (horizontal) {
4219
+ const x = prev && next && Math.abs(cross(prev) - cross(next)) < 1e-6 ? (prev.x + prev.w + next.x) / 2 : prev ? prev.x + prev.w : next ? next.x : pl;
4220
+ const ref = _nullishCoalesce(next, () => ( prev));
4221
+ const y1 = ref ? ref.y : pt;
4222
+ const y2 = ref ? ref.y + ref.h : f.h - pb;
4223
+ guide = { orientation: "vertical", kind: "edge", x1: origin.x + x, y1: origin.y + y1, x2: origin.x + x, y2: origin.y + y2 };
4224
+ } else {
4225
+ const y = prev && next && Math.abs(cross(prev) - cross(next)) < 1e-6 ? (prev.y + prev.h + next.y) / 2 : prev ? prev.y + prev.h : next ? next.y : pt;
4226
+ const ref = _nullishCoalesce(next, () => ( prev));
4227
+ const x1 = ref ? ref.x : pl;
4228
+ const x2 = ref ? ref.x + ref.w : f.w - pr;
4229
+ guide = { orientation: "horizontal", kind: "edge", x1: origin.x + x1, y1: origin.y + y, x2: origin.x + x2, y2: origin.y + y };
4230
+ }
4231
+ return { frameId, index, guide };
4232
+ }
4233
+ function moveLayoutChild(nodes, childId, index) {
4234
+ const child = nodes.find((n) => n.id === childId);
4235
+ if (!_optionalChain([child, 'optionalAccess', _152 => _152.parentId])) return nodes;
4236
+ const siblings = nodes.filter((n) => n.parentId === child.parentId && n.id !== child.parentId);
4237
+ const flow = siblings.filter((n) => n.hidden !== true && !getChildLayout(n).absolute && n.id !== childId);
4238
+ const clamped = Math.min(Math.max(Math.floor(Number.isFinite(index) ? index : 0), 0), flow.length);
4239
+ const order = siblings.filter((n) => n.id !== childId);
4240
+ const anchor = flow[clamped];
4241
+ const at = anchor ? order.indexOf(anchor) : flow.length > 0 ? order.indexOf(flow[flow.length - 1]) + 1 : order.length;
4242
+ order.splice(at, 0, child);
4243
+ if (order.every((n, i) => n === siblings[i])) return nodes;
4244
+ let k = 0;
4245
+ const parentId = child.parentId;
4246
+ const placed = nodes.map((n) => n.parentId === parentId && n.id !== parentId ? order[k++] : n);
4247
+ return parentsFirst(placed);
4248
+ }
4249
+ function parentsFirst(nodes) {
4250
+ const ids = new Set(nodes.map((n) => n.id));
4251
+ const pending = /* @__PURE__ */ new Map();
4252
+ const done = /* @__PURE__ */ new Set();
4253
+ const out = [];
4254
+ const emit = (n) => {
4255
+ out.push(n);
4256
+ done.add(n.id);
4257
+ const waiting = pending.get(n.id);
4258
+ if (waiting) {
4259
+ pending.delete(n.id);
4260
+ for (const w of waiting) emit(w);
4261
+ }
4262
+ };
4263
+ for (const n of nodes) {
4264
+ if (n.parentId && ids.has(n.parentId) && !done.has(n.parentId) && n.parentId !== n.id) {
4265
+ if (!pending.has(n.parentId)) pending.set(n.parentId, []);
4266
+ pending.get(n.parentId).push(n);
4267
+ } else emit(n);
4268
+ }
4269
+ for (const waiting of pending.values()) for (const n of waiting) if (!done.has(n.id)) emit(n);
4270
+ return out;
4271
+ }
4272
+
2879
4273
  // src/canvas/arrangeController.ts
2880
4274
  function createCanvasArrangeController(options) {
2881
4275
  let guides = [];
2882
4276
  let dragIndex = null;
2883
4277
  let dragKey = "";
2884
4278
  let lastSnapped = /* @__PURE__ */ new Map();
2885
- const selectedIds = (ids) => ids ? [...ids] : _nullishCoalesce(_optionalChain([options, 'access', _63 => _63.getSelectedIds, 'optionalCall', _64 => _64()]), () => ( options.getNodes().filter((n) => n.selected).map((n) => n.id)));
4279
+ let resizeId = null;
4280
+ let resizeStart = null;
4281
+ let resizeIndex = null;
4282
+ let lastResized = null;
4283
+ const selectedIds = (ids) => ids ? [...ids] : _nullishCoalesce(_optionalChain([options, 'access', _153 => _153.getSelectedIds, 'optionalCall', _154 => _154()]), () => ( options.getNodes().filter((n) => n.selected).map((n) => n.id)));
2886
4284
  const setGuides = (next) => {
2887
4285
  if (next.length === 0 && guides.length === 0) return;
2888
4286
  guides = next;
2889
- _optionalChain([options, 'access', _65 => _65.onGuidesChange, 'optionalCall', _66 => _66(guides)]);
4287
+ _optionalChain([options, 'access', _155 => _155.onGuidesChange, 'optionalCall', _156 => _156(guides)]);
2890
4288
  };
2891
4289
  function apply(name, updates) {
2892
4290
  if (updates.length === 0) return updates;
4291
+ if (options.autoLayout) {
4292
+ const layoutOptions = options.autoLayout === true ? { rectOptions: options.rectOptions } : options.autoLayout;
4293
+ const moved = applyNodeUpdates(options.getNodes(), updates);
4294
+ const layout2 = layoutUpMany(moved, updates.map((u) => u.id), layoutOptions);
4295
+ if (layout2.length > 0) {
4296
+ const byId = /* @__PURE__ */ new Map();
4297
+ for (const u of [...updates, ...layout2]) byId.set(u.id, { ...byId.get(u.id), ...u });
4298
+ updates = [...byId.values()];
4299
+ }
4300
+ }
2893
4301
  const inverse = invertNodeUpdates(options.getNodes(), updates);
2894
4302
  const run = (u) => options.setNodes(applyNodeUpdates(options.getNodes(), u));
2895
4303
  if (options.history) {
@@ -3044,7 +4452,7 @@ function createCanvasArrangeController(options) {
3044
4452
  const result = snapNodeDrag(options.getNodes(), list, {
3045
4453
  ...rect(),
3046
4454
  ...options.guides,
3047
- zoom: _nullishCoalesce(_optionalChain([options, 'access', _67 => _67.getZoom, 'optionalCall', _68 => _68()]), () => ( 1)),
4455
+ zoom: _nullishCoalesce(_optionalChain([options, 'access', _157 => _157.getZoom, 'optionalCall', _158 => _158()]), () => ( 1)),
3048
4456
  index: dragIndex
3049
4457
  });
3050
4458
  lastSnapped = /* @__PURE__ */ new Map();
@@ -3082,7 +4490,7 @@ function createCanvasArrangeController(options) {
3082
4490
  const result = snapNodeDrag(nodes, ids, {
3083
4491
  ...rect(),
3084
4492
  ...options.guides,
3085
- zoom: _nullishCoalesce(_optionalChain([options, 'access', _69 => _69.getZoom, 'optionalCall', _70 => _70()]), () => ( 1)),
4493
+ zoom: _nullishCoalesce(_optionalChain([options, 'access', _159 => _159.getZoom, 'optionalCall', _160 => _160()]), () => ( 1)),
3086
4494
  index: dragIndex
3087
4495
  });
3088
4496
  setGuides(result.guides);
@@ -3098,6 +4506,150 @@ function createCanvasArrangeController(options) {
3098
4506
  return { ...c, position };
3099
4507
  });
3100
4508
  },
4509
+ /**
4510
+ * Starts resize snapping for node `id`: records its box (to tell which handle is
4511
+ * dragged) and caches the snap targets. Optional: `resize` starts lazily.
4512
+ */
4513
+ beginResize(id) {
4514
+ const nodes = options.getNodes();
4515
+ const lookup = createNodeLookup(nodes);
4516
+ const node = lookup.get(id);
4517
+ resizeId = id;
4518
+ resizeStart = node ? getResizingNodeRect(node, lookup, rect()) : null;
4519
+ resizeIndex = createNodeGuideIndex(nodes, [id], rect());
4520
+ lastResized = null;
4521
+ },
4522
+ /**
4523
+ * Snaps node `id` as currently sized in `getNodes()` (call it after the flow wrote the
4524
+ * new size, e.g. SvelteFlow's `NodeResizer` `onResize`, deferred by a microtask) and
4525
+ * writes the snapped box back through `setNodes` (not recorded in history). `handle`
4526
+ * defaults to the one inferred from the edges that moved since `beginResize`. A locked
4527
+ * node is restored to its starting box.
4528
+ */
4529
+ resize(id, handle) {
4530
+ if (resizeId !== id) controller.beginResize(id);
4531
+ const nodes = options.getNodes();
4532
+ const lookup = createNodeLookup(nodes);
4533
+ const node = lookup.get(id);
4534
+ if (!node || !resizeStart) return null;
4535
+ const proposed = getResizingNodeRect(node, lookup, rect());
4536
+ if (isLocked(node)) {
4537
+ const start = resizeStart;
4538
+ const parent = node.parentId ? lookup.get(node.parentId) : void 0;
4539
+ const origin = parent ? getResizingNodeRect(parent, lookup, rect()) : { x: 0, y: 0 };
4540
+ if (proposed.x !== start.x || proposed.y !== start.y || proposed.width !== start.width || proposed.height !== start.height) {
4541
+ options.setNodes(
4542
+ applyNodeUpdates(nodes, [
4543
+ { id, position: { x: start.x - origin.x, y: start.y - origin.y }, width: start.width, height: start.height }
4544
+ ])
4545
+ );
4546
+ }
4547
+ return null;
4548
+ }
4549
+ if ((_nullishCoalesce(options.resizeSnapping, () => ( options.snapping))) === false) return null;
4550
+ const h = _nullishCoalesce(handle, () => ( inferResizeHandle(resizeStart, proposed)));
4551
+ if (!h) {
4552
+ setGuides([]);
4553
+ return null;
4554
+ }
4555
+ const result = snapNodeResize(nodes, id, proposed, h, {
4556
+ ...rect(),
4557
+ ...options.guides,
4558
+ ...options.resize,
4559
+ zoom: _nullishCoalesce(_optionalChain([options, 'access', _161 => _161.getZoom, 'optionalCall', _162 => _162()]), () => ( 1)),
4560
+ index: resizeIndex
4561
+ });
4562
+ lastResized = result.updates.length > 0 ? result : null;
4563
+ if (result.updates.length > 0) options.setNodes(applyNodeUpdates(nodes, result.updates));
4564
+ setGuides(result.guides);
4565
+ return result;
4566
+ },
4567
+ /**
4568
+ * Ends resize snapping: clears guides and re-applies the last snapped box if the flow
4569
+ * wrote the raw pointer size afterwards.
4570
+ */
4571
+ endResize() {
4572
+ const last = lastResized;
4573
+ resizeId = null;
4574
+ resizeStart = null;
4575
+ resizeIndex = null;
4576
+ lastResized = null;
4577
+ setGuides([]);
4578
+ const update = _optionalChain([last, 'optionalAccess', _163 => _163.updates, 'access', _164 => _164[0]]);
4579
+ if (!update) return;
4580
+ const node = options.getNodes().find((n) => n.id === update.id);
4581
+ if (!node) return;
4582
+ const drift = node.position.x !== update.position.x || node.position.y !== update.position.y || node.width !== update.width || node.height !== update.height;
4583
+ if (drift) options.setNodes(applyNodeUpdates(options.getNodes(), [update]));
4584
+ },
4585
+ /**
4586
+ * React Flow style: snaps the `dimensions` (and matching `position`) changes a
4587
+ * `NodeResizer` emits in an `onNodesChange` batch and updates `guides`. The resize-end
4588
+ * change (`resizing: false`) carries the raw pointer size, so the last snapped size is
4589
+ * kept. Resize changes of locked nodes are dropped. Returns the (possibly new) changes.
4590
+ */
4591
+ snapResizeChanges(changes) {
4592
+ const dims = changes.find(
4593
+ (c) => c.type === "dimensions" && typeof c.id === "string" && !!c.dimensions && typeof c.resizing === "boolean"
4594
+ );
4595
+ if (!dims) return changes;
4596
+ const id = dims.id;
4597
+ const nodes = options.getNodes();
4598
+ const lookup = createNodeLookup(nodes);
4599
+ const node = lookup.get(id);
4600
+ const isResizeChange = (c) => c.id === id && (c.type === "dimensions" || c.type === "position");
4601
+ if (node && isLocked(node)) {
4602
+ if (dims.resizing === false) controller.endResize();
4603
+ return changes.filter((c) => !isResizeChange(c));
4604
+ }
4605
+ if (dims.resizing === false) {
4606
+ const last = _optionalChain([lastResized, 'optionalAccess', _165 => _165.updates, 'access', _166 => _166[0]]);
4607
+ lastResized = null;
4608
+ controller.endResize();
4609
+ if (!last || last.id !== id) return changes;
4610
+ return changes.map(
4611
+ (c) => c === dims ? { ...c, dimensions: { width: last.width, height: last.height } } : c
4612
+ );
4613
+ }
4614
+ if (!node || (_nullishCoalesce(options.resizeSnapping, () => ( options.snapping))) === false) return changes;
4615
+ if (resizeId !== id) controller.beginResize(id);
4616
+ if (!resizeStart) return changes;
4617
+ const posChange = changes.find((c) => c.id === id && c.type === "position" && !!c.position);
4618
+ const parent = node.parentId ? lookup.get(node.parentId) : void 0;
4619
+ const origin = parent ? getResizingNodeRect(parent, lookup, rect()) : { x: 0, y: 0 };
4620
+ const position = _nullishCoalesce(_optionalChain([posChange, 'optionalAccess', _167 => _167.position]), () => ( node.position));
4621
+ const proposed = {
4622
+ x: position.x + origin.x,
4623
+ y: position.y + origin.y,
4624
+ width: dims.dimensions.width,
4625
+ height: dims.dimensions.height
4626
+ };
4627
+ const handle = inferResizeHandle(resizeStart, proposed);
4628
+ if (!handle) {
4629
+ setGuides([]);
4630
+ return changes;
4631
+ }
4632
+ const result = snapNodeResize(nodes, id, proposed, handle, {
4633
+ ...rect(),
4634
+ ...options.guides,
4635
+ ...options.resize,
4636
+ zoom: _nullishCoalesce(_optionalChain([options, 'access', _168 => _168.getZoom, 'optionalCall', _169 => _169()]), () => ( 1)),
4637
+ index: resizeIndex
4638
+ });
4639
+ setGuides(result.guides);
4640
+ const update = result.updates[0];
4641
+ lastResized = update ? result : null;
4642
+ if (!update) return changes;
4643
+ const next = changes.map((c) => {
4644
+ if (c === dims) return { ...c, dimensions: { width: update.width, height: update.height } };
4645
+ if (c === posChange) return { ...c, position: update.position };
4646
+ return c;
4647
+ });
4648
+ if (!posChange && (update.position.x !== node.position.x || update.position.y !== node.position.y)) {
4649
+ next.push({ id, type: "position", position: update.position });
4650
+ }
4651
+ return next;
4652
+ },
3101
4653
  /**
3102
4654
  * Clears guides and the cached snap targets. Call it from the flow's drag-stop
3103
4655
  * handler: flow libraries write the raw pointer position when a drag ends, so the
@@ -3123,6 +4675,443 @@ function createCanvasArrangeController(options) {
3123
4675
  return controller;
3124
4676
  }
3125
4677
 
4678
+ // src/canvas/measure.ts
4679
+ var EPS2 = 1e-6;
4680
+ function measureLabel(distance) {
4681
+ const v = Math.round(Math.abs(distance) * 100) / 100;
4682
+ return Object.is(v, -0) ? "0" : String(v);
4683
+ }
4684
+ var toBox = (r) => ({ x0: r.x, y0: r.y, x1: r.x + r.width, y1: r.y + r.height });
4685
+ var finiteBox = (b) => [b.x0, b.y0, b.x1, b.y1].every(Number.isFinite);
4686
+ function line(kind, x1, y1, x2, y2) {
4687
+ return { orientation: x1 === x2 ? "vertical" : "horizontal", kind, x1, y1, x2, y2 };
4688
+ }
4689
+ function measured(out, x1, y1, x2, y2) {
4690
+ const d = Math.hypot(x2 - x1, y2 - y1);
4691
+ if (d > EPS2 && Number.isFinite(d)) out.push({ ...line("measure", x1, y1, x2, y2), label: measureLabel(d) });
4692
+ }
4693
+ function extension(out, x1, y1, x2, y2) {
4694
+ if (Math.hypot(x2 - x1, y2 - y1) > EPS2) out.push(line("extension", x1, y1, x2, y2));
4695
+ }
4696
+ function contains(outer, inner) {
4697
+ return outer.x0 <= inner.x0 + EPS2 && outer.y0 <= inner.y0 + EPS2 && outer.x1 >= inner.x1 - EPS2 && outer.y1 >= inner.y1 - EPS2;
4698
+ }
4699
+ function overlapMid(a0, a1, b0, b1) {
4700
+ const lo = Math.max(a0, b0);
4701
+ const hi = Math.min(a1, b1);
4702
+ return lo <= hi ? (lo + hi) / 2 : null;
4703
+ }
4704
+ function inside(out, inner, outer) {
4705
+ const cx = (inner.x0 + inner.x1) / 2;
4706
+ const cy = (inner.y0 + inner.y1) / 2;
4707
+ measured(out, outer.x0, cy, inner.x0, cy);
4708
+ measured(out, inner.x1, cy, outer.x1, cy);
4709
+ measured(out, cx, outer.y0, cx, inner.y0);
4710
+ measured(out, cx, inner.y1, cx, outer.y1);
4711
+ }
4712
+ function measureBetween(a, b) {
4713
+ const out = [];
4714
+ const A = toBox(a);
4715
+ const B = toBox(b);
4716
+ if (!finiteBox(A) || !finiteBox(B)) return out;
4717
+ if (contains(B, A)) {
4718
+ inside(out, A, B);
4719
+ return out;
4720
+ }
4721
+ if (contains(A, B)) {
4722
+ inside(out, B, A);
4723
+ return out;
4724
+ }
4725
+ const ox = overlapMid(A.x0, A.x1, B.x0, B.x1);
4726
+ const oy = overlapMid(A.y0, A.y1, B.y0, B.y1);
4727
+ const overlapping = A.x0 < B.x1 && B.x0 < A.x1 && A.y0 < B.y1 && B.y0 < A.y1;
4728
+ if (overlapping && ox !== null && oy !== null) {
4729
+ measured(out, A.x0, oy, B.x0, oy);
4730
+ measured(out, A.x1, oy, B.x1, oy);
4731
+ measured(out, ox, A.y0, ox, B.y0);
4732
+ measured(out, ox, A.y1, ox, B.y1);
4733
+ return out;
4734
+ }
4735
+ const cx = (A.x0 + A.x1) / 2;
4736
+ const cy = (A.y0 + A.y1) / 2;
4737
+ const gapX = B.x0 >= A.x1 ? [A.x1, B.x0] : B.x1 <= A.x0 ? [A.x0, B.x1] : null;
4738
+ if (gapX) {
4739
+ const [from, to] = gapX;
4740
+ const y = _nullishCoalesce(oy, () => ( cy));
4741
+ measured(out, from, y, to, y);
4742
+ if (oy === null) extension(out, to, y, to, y < B.y0 ? B.y0 : B.y1);
4743
+ }
4744
+ const gapY = B.y0 >= A.y1 ? [A.y1, B.y0] : B.y1 <= A.y0 ? [A.y0, B.y1] : null;
4745
+ if (gapY) {
4746
+ const [from, to] = gapY;
4747
+ const x = _nullishCoalesce(ox, () => ( cx));
4748
+ measured(out, x, from, x, to);
4749
+ if (ox === null) extension(out, x, to, x < B.x0 ? B.x0 : B.x1, to);
4750
+ }
4751
+ return out;
4752
+ }
4753
+ function measureToLine(a, orientation, at) {
4754
+ const out = [];
4755
+ const A = toBox(a);
4756
+ if (!finiteBox(A) || !Number.isFinite(at)) return out;
4757
+ const vertical = orientation === "vertical";
4758
+ const cx = (A.x0 + A.x1) / 2;
4759
+ const cy = (A.y0 + A.y1) / 2;
4760
+ const [lo, hi] = vertical ? [A.x0, A.x1] : [A.y0, A.y1];
4761
+ const seg = (from, to) => vertical ? measured(out, from, cy, to, cy) : measured(out, cx, from, cx, to);
4762
+ if (at >= hi) seg(hi, at);
4763
+ else if (at <= lo) seg(at, lo);
4764
+ else {
4765
+ seg(lo, at);
4766
+ seg(at, hi);
4767
+ }
4768
+ return out;
4769
+ }
4770
+ function measureSelection(nodes, selectedIds, hoveredId, options = {}) {
4771
+ const none = (selection2 = null) => ({ guides: [], target: null, selection: selection2 });
4772
+ const lookup = createNodeLookup(nodes);
4773
+ const selected = [...new Set(selectedIds)].map((id) => lookup.get(id)).filter((n) => !!n && n.hidden !== true);
4774
+ if (selected.length === 0) return none();
4775
+ const selection = _chunkWADCJ7A7cjs.boundsOf.call(void 0, selected.map((n) => getNodeRect(n, lookup, options)));
4776
+ if (!selection) return none();
4777
+ const selectedSet = new Set(selected.map((n) => n.id));
4778
+ let targetId = _nullishCoalesce(hoveredId, () => ( null));
4779
+ if (targetId === null || selectedSet.has(targetId)) {
4780
+ const parentId = selected[0].parentId;
4781
+ const sameParent = selected.every((n) => n.parentId === parentId);
4782
+ targetId = parentId && sameParent && !selectedSet.has(parentId) ? parentId : null;
4783
+ }
4784
+ const target = targetId !== null ? lookup.get(targetId) : void 0;
4785
+ if (!target || target.hidden === true) return none(selection);
4786
+ const rect = getNodeRect(target, lookup, options);
4787
+ return { guides: measureBetween(selection, rect), target: rect, selection };
4788
+ }
4789
+ function isMeasureModifierHeld(event) {
4790
+ if (!event) return false;
4791
+ if (event.type === "keyup" && event.key === "Alt") return false;
4792
+ return event.altKey === true || event.type === "keydown" && event.key === "Alt";
4793
+ }
4794
+
4795
+ // src/canvas/autoLayoutController.ts
4796
+ function mergeNodeUpdates(...lists) {
4797
+ const byId = /* @__PURE__ */ new Map();
4798
+ for (const list of lists) for (const u of list) byId.set(u.id, { ...byId.get(u.id), ...u });
4799
+ return [...byId.values()];
4800
+ }
4801
+ function relayoutUpdates(nodes, ids, options = {}) {
4802
+ return layoutUpMany(nodes, ids, options);
4803
+ }
4804
+ function createCanvasAutoLayoutController(options) {
4805
+ const layoutOptions = () => ({ measure: options.measure, rectOptions: options.rectOptions });
4806
+ const enabled = () => options.enabled !== false;
4807
+ const pendingIds = /* @__PURE__ */ new Set();
4808
+ const pendingResizes = /* @__PURE__ */ new Map();
4809
+ const resizeStarts = /* @__PURE__ */ new Map();
4810
+ let pendingAll = false;
4811
+ const dragStarts = /* @__PURE__ */ new Map();
4812
+ const pendingDrops = /* @__PURE__ */ new Set();
4813
+ let guides = [];
4814
+ const setGuides = (next) => {
4815
+ if (next.length === 0 && guides.length === 0) return;
4816
+ guides = next;
4817
+ _optionalChain([options, 'access', _170 => _170.onGuidesChange, 'optionalCall', _171 => _171(guides)]);
4818
+ };
4819
+ function run(name, forward, backward, ids, extra = [], restore) {
4820
+ const before = options.getNodes();
4821
+ const structural = forward(before);
4822
+ const withExtra = applyNodeUpdates(structural, extra);
4823
+ const layout2 = enabled() || name === "Auto Layout" ? relayoutUpdates(withExtra, ids(withExtra), layoutOptions()) : [];
4824
+ const updates = mergeNodeUpdates(extra, layout2);
4825
+ if (structural === before && updates.length === 0) return updates;
4826
+ let inverse = invertNodeUpdates(structural, updates);
4827
+ if (restore) {
4828
+ inverse = mergeNodeUpdates(inverse, [{ id: restore.id, position: { ...restore.position } }]);
4829
+ }
4830
+ const execute = () => options.setNodes(applyNodeUpdates(forward(options.getNodes()), updates));
4831
+ const undo = () => options.setNodes(backward(applyNodeUpdates(options.getNodes(), inverse)));
4832
+ if (options.history) options.history.execute({ name, execute, undo });
4833
+ else execute();
4834
+ return updates;
4835
+ }
4836
+ const identity = (nodes) => nodes;
4837
+ const controller = {
4838
+ /** Drop marker of the active reorder drag (flow coordinates); empty otherwise. */
4839
+ get guides() {
4840
+ return guides;
4841
+ },
4842
+ /**
4843
+ * Lays out frame `frameId` and its auto layout ancestors (default: every frame) as one
4844
+ * (optionally undoable) step. Returns the updates.
4845
+ */
4846
+ applyAutoLayout(frameId) {
4847
+ if (frameId === void 0) {
4848
+ const updates = layoutAll(options.getNodes(), layoutOptions());
4849
+ return run("Auto Layout", identity, identity, () => [], updates);
4850
+ }
4851
+ return run("Auto Layout", identity, identity, () => [frameId]);
4852
+ },
4853
+ /** Updates that relayout around `ids` on the current nodes, without applying them. */
4854
+ layoutUpdates(ids) {
4855
+ return relayoutUpdates(options.getNodes(), ids, layoutOptions());
4856
+ },
4857
+ /**
4858
+ * Applies the relayout around `ids` (frames, or nodes inside frames) directly, not
4859
+ * recorded in history: auto layout is derived state, re-run after any change.
4860
+ */
4861
+ relayout(ids) {
4862
+ const updates = relayoutUpdates(options.getNodes(), ids, layoutOptions());
4863
+ if (updates.length > 0) options.setNodes(applyNodeUpdates(options.getNodes(), updates));
4864
+ return updates;
4865
+ },
4866
+ /**
4867
+ * Adds `node` (into the frame named by its `parentId`, at flow `index` when given) and
4868
+ * lays out its frame, as one step.
4869
+ */
4870
+ addNode(node, addOptions = {}) {
4871
+ const forward = (nodes) => {
4872
+ if (nodes.some((n) => n.id === node.id)) return nodes;
4873
+ let next = [...nodes, node];
4874
+ if (addOptions.index !== void 0 && node.parentId) next = moveLayoutChild(next, node.id, addOptions.index);
4875
+ return next;
4876
+ };
4877
+ const backward = (nodes) => nodes.filter((n) => n.id !== node.id);
4878
+ return run("Add Node", forward, backward, () => [node.id]);
4879
+ },
4880
+ /** Removes nodes (and their descendants) and lays out the frames they leave, as one step. */
4881
+ removeNodes(ids) {
4882
+ const before = options.getNodes();
4883
+ const remove = new Set(ids);
4884
+ let grew = true;
4885
+ while (grew) {
4886
+ grew = false;
4887
+ for (const n of before) {
4888
+ if (n.parentId && remove.has(n.parentId) && !remove.has(n.id)) {
4889
+ remove.add(n.id);
4890
+ grew = true;
4891
+ }
4892
+ }
4893
+ }
4894
+ const removed = before.map((n, i) => [i, n]).filter(([, n]) => remove.has(n.id));
4895
+ if (removed.length === 0) return [];
4896
+ const parents = [...new Set(removed.map(([, n]) => n.parentId).filter((p) => !!p && !remove.has(p)))];
4897
+ const forward = (nodes) => nodes.filter((n) => !remove.has(n.id));
4898
+ const backward = (nodes) => {
4899
+ const next = [...nodes];
4900
+ for (const [i, n] of removed) next.splice(Math.min(i, next.length), 0, n);
4901
+ return next;
4902
+ };
4903
+ return run("Delete", forward, backward, () => parents);
4904
+ },
4905
+ /**
4906
+ * Resizes node `id` (its children follow their constraints) and lays out around it,
4907
+ * as one step.
4908
+ */
4909
+ resizeNode(id, size) {
4910
+ const nodes = options.getNodes();
4911
+ const node = nodes.find((n) => n.id === id);
4912
+ if (!node) return [];
4913
+ const old = getNodeSize(node, options.rectOptions);
4914
+ const update = { id };
4915
+ if (size.width !== void 0) update.width = size.width;
4916
+ if (size.height !== void 0) update.height = size.height;
4917
+ const resized = applyNodeUpdates(nodes, [update]);
4918
+ const constrained = mergeNodeUpdates([update], applyConstraints(resized, id, old, layoutOptions()));
4919
+ return run("Resize", identity, identity, () => [id], constrained);
4920
+ },
4921
+ /** Moves flow child `childId` to flow index `index` in its frame and lays it out, as one step. */
4922
+ moveChild(childId, index) {
4923
+ const before = options.getNodes();
4924
+ const order = before.map((n) => n.id);
4925
+ const forward = (nodes) => moveLayoutChild(nodes, childId, index);
4926
+ const backward = (nodes) => restoreOrder(nodes, order);
4927
+ if (forward(before) === before) return [];
4928
+ return run("Reorder", forward, backward, () => [childId]);
4929
+ },
4930
+ /** Where flow child `id` would drop if released at `point` (default: its centre). */
4931
+ getInsertTarget(id, point) {
4932
+ const nodes = options.getNodes();
4933
+ const frame = getLayoutParent(nodes, id);
4934
+ if (!frame) return void 0;
4935
+ const lookup = createNodeLookup(nodes);
4936
+ const rect = getNodeRect(lookup.get(id), lookup, options.rectOptions);
4937
+ const at = _nullishCoalesce(point, () => ( { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 }));
4938
+ return getAutoLayoutInsertTarget(nodes, frame.id, at, { ...layoutOptions(), excludeId: id });
4939
+ },
4940
+ /** Records the start position of a reorder drag. Optional: `dragReorder` records it lazily. */
4941
+ beginReorderDrag(id) {
4942
+ const node = options.getNodes().find((n) => n.id === id);
4943
+ if (node && getLayoutParent(options.getNodes(), id)) dragStarts.set(id, { ...node.position });
4944
+ },
4945
+ /**
4946
+ * While flow child `id` is dragged (as currently positioned in `getNodes()`): updates the
4947
+ * drop marker. Returns the insert target.
4948
+ */
4949
+ dragReorder(id, point) {
4950
+ if (options.dragReorder === false) return void 0;
4951
+ if (!dragStarts.has(id)) controller.beginReorderDrag(id);
4952
+ const target = controller.getInsertTarget(id, point);
4953
+ setGuides(target ? [target.guide] : []);
4954
+ return target;
4955
+ },
4956
+ /**
4957
+ * Ends a reorder drag: moves `id` to the slot under `point` (default: its centre) and lays
4958
+ * the frame out, as one undoable step whose undo puts the node back where the drag began.
4959
+ */
4960
+ endReorderDrag(id, point) {
4961
+ setGuides([]);
4962
+ const start = dragStarts.get(id);
4963
+ dragStarts.delete(id);
4964
+ if (options.dragReorder === false || !getLayoutParent(options.getNodes(), id)) return [];
4965
+ const target = controller.getInsertTarget(id, point);
4966
+ if (!target) return [];
4967
+ const before = options.getNodes();
4968
+ const order = before.map((n) => n.id);
4969
+ const forward = (nodes) => moveLayoutChild(nodes, id, target.index);
4970
+ const backward = (nodes) => restoreOrder(nodes, order);
4971
+ return run("Reorder", forward, backward, () => [id], [], start && { id, position: start });
4972
+ },
4973
+ /**
4974
+ * Notes a batch of React Flow / SvelteFlow style node changes (before or after they are
4975
+ * applied) so `flush` can relayout: dimension changes (measured sizes, resize ends),
4976
+ * added and removed nodes, and position changes of flow children (reorder drags).
4977
+ * Returns the changes unchanged.
4978
+ */
4979
+ noteChanges(changes) {
4980
+ const nodes = options.getNodes();
4981
+ const lookup = createNodeLookup(nodes);
4982
+ for (const c of changes) {
4983
+ const id = _nullishCoalesce(c.id, () => ( _optionalChain([c, 'access', _172 => _172.item, 'optionalAccess', _173 => _173.id])));
4984
+ if (c.type === "add" && c.item) {
4985
+ pendingIds.add(c.item.id);
4986
+ } else if (c.type === "remove" && id) {
4987
+ const parent = _optionalChain([lookup, 'access', _174 => _174.get, 'call', _175 => _175(id), 'optionalAccess', _176 => _176.parentId]);
4988
+ if (parent) pendingIds.add(parent);
4989
+ else pendingAll = true;
4990
+ } else if (c.type === "replace" && id) {
4991
+ pendingIds.add(id);
4992
+ } else if (c.type === "dimensions" && id) {
4993
+ const node = lookup.get(id);
4994
+ if (c.resizing === true) {
4995
+ if (node && !resizeStarts.has(id)) resizeStarts.set(id, getNodeSize(node, options.rectOptions));
4996
+ continue;
4997
+ }
4998
+ const start = resizeStarts.get(id);
4999
+ resizeStarts.delete(id);
5000
+ if (start) pendingResizes.set(id, start);
5001
+ pendingIds.add(id);
5002
+ } else if (c.type === "position" && id && options.dragReorder !== false) {
5003
+ if (!getLayoutParent(nodes, id)) continue;
5004
+ if (c.dragging === true) {
5005
+ if (!dragStarts.has(id)) {
5006
+ const node = lookup.get(id);
5007
+ if (node) dragStarts.set(id, { ...node.position });
5008
+ }
5009
+ } else if (c.dragging === false || dragStarts.has(id)) {
5010
+ pendingDrops.add(id);
5011
+ }
5012
+ }
5013
+ }
5014
+ return changes;
5015
+ },
5016
+ /**
5017
+ * Notes nodes that were already removed (e.g. SvelteFlow's `ondelete`), so `flush`
5018
+ * relayouts the frames they left. The nodes must still carry their `parentId`.
5019
+ */
5020
+ noteRemoved(removed) {
5021
+ const gone = /* @__PURE__ */ new Set();
5022
+ const list = [...removed];
5023
+ for (const n of list) gone.add(n.id);
5024
+ for (const n of list) if (n.parentId && !gone.has(n.parentId)) pendingIds.add(n.parentId);
5025
+ },
5026
+ /** Whether `noteChanges` left work for `flush`. */
5027
+ get hasPending() {
5028
+ return pendingAll || pendingIds.size > 0 || pendingResizes.size > 0 || pendingDrops.size > 0 || dragStarts.size > 0;
5029
+ },
5030
+ /**
5031
+ * Applies the work noted by `noteChanges` to the current nodes: drop markers while
5032
+ * dragging, committed reorders on drop (undoable), and a relayout (not recorded) for
5033
+ * size, add and remove changes. Call it once the changes are applied.
5034
+ */
5035
+ flush() {
5036
+ let applied = [];
5037
+ for (const id of pendingDrops) applied = mergeNodeUpdates(applied, controller.endReorderDrag(id));
5038
+ pendingDrops.clear();
5039
+ for (const id of dragStarts.keys()) controller.dragReorder(id);
5040
+ if (!enabled()) {
5041
+ pendingIds.clear();
5042
+ pendingResizes.clear();
5043
+ pendingAll = false;
5044
+ return applied;
5045
+ }
5046
+ let nodes = options.getNodes();
5047
+ let updates = [];
5048
+ for (const [id, previous] of pendingResizes) {
5049
+ if (!nodes.some((n) => n.id === id)) continue;
5050
+ const constrained = applyConstraints(nodes, id, previous, layoutOptions());
5051
+ nodes = applyNodeUpdates(nodes, constrained);
5052
+ updates = mergeNodeUpdates(updates, constrained);
5053
+ }
5054
+ const layout2 = pendingAll ? layoutAll(nodes, layoutOptions()) : relayoutUpdates(nodes, [...pendingIds].filter((id) => nodes.some((n) => n.id === id)), layoutOptions());
5055
+ updates = mergeNodeUpdates(updates, layout2);
5056
+ pendingIds.clear();
5057
+ pendingResizes.clear();
5058
+ pendingAll = false;
5059
+ if (updates.length > 0) options.setNodes(applyNodeUpdates(options.getNodes(), updates));
5060
+ return mergeNodeUpdates(applied, updates);
5061
+ },
5062
+ /** Whether `id` is an auto layout frame. */
5063
+ isFrame: (id) => isAutoLayoutFrame(options.getNodes().find((n) => n.id === id))
5064
+ };
5065
+ return controller;
5066
+ }
5067
+ function restoreOrder(nodes, order) {
5068
+ const rank = new Map(order.map((id, i) => [id, i]));
5069
+ const indexed = nodes.map((n, i) => ({ n, r: _nullishCoalesce(rank.get(n.id), () => ( order.length + i)) }));
5070
+ indexed.sort((a, b) => a.r - b.r);
5071
+ return indexed.every((e, i) => e.n === nodes[i]) ? nodes : indexed.map((e) => e.n);
5072
+ }
5073
+
5074
+
5075
+
5076
+
5077
+
5078
+
5079
+
5080
+
5081
+
5082
+
5083
+
5084
+
5085
+
5086
+
5087
+
5088
+
5089
+
5090
+
5091
+
5092
+
5093
+
5094
+
5095
+
5096
+
5097
+
5098
+
5099
+
5100
+
5101
+
5102
+
5103
+
5104
+
5105
+
5106
+
5107
+
5108
+
5109
+
5110
+
5111
+
5112
+
5113
+
5114
+
3126
5115
 
3127
5116
 
3128
5117
 
@@ -3234,5 +5223,5 @@ function createCanvasArrangeController(options) {
3234
5223
 
3235
5224
 
3236
5225
 
3237
- exports.CONNECTION_LINE_TYPES = CONNECTION_LINE_TYPES; exports.CanvasScenesStore = CanvasScenesStore; exports.DEFAULT_ARRANGE_SHORTCUTS = DEFAULT_ARRANGE_SHORTCUTS; exports.DEFAULT_NODE_HEIGHT = _chunkWADCJ7A7cjs.DEFAULT_NODE_HEIGHT; exports.DEFAULT_NODE_WIDTH = _chunkWADCJ7A7cjs.DEFAULT_NODE_WIDTH; exports.DEFAULT_PLACEMENT_GAP = _chunkWADCJ7A7cjs.DEFAULT_PLACEMENT_GAP; exports.LOCKED_DATA_KEY = LOCKED_DATA_KEY; exports.LOCKED_PREVIOUS_FLAGS_KEY = LOCKED_PREVIOUS_FLAGS_KEY; exports.ManualClock = ManualClock; exports.SHAPE_DATA_KEY = SHAPE_DATA_KEY; exports.SHAPE_KINDS = SHAPE_KINDS; exports.SHAPE_NODE_TYPE = SHAPE_NODE_TYPE; exports.SHAPE_OPERATIONS = SHAPE_OPERATIONS; exports.StreamingLayoutManager = StreamingLayoutManager; exports.alignNodes = alignNodes; exports.applyNodeUpdates = applyNodeUpdates; exports.applyShapeCombination = applyShapeCombination; exports.blendLayout = blendLayout; exports.boundsOf = _chunkWADCJ7A7cjs.boundsOf; exports.calculateDagreReflowDisplacement = calculateDagreReflowDisplacement; exports.calculateDirectionalDisplacement = calculateDirectionalDisplacement; exports.canCombineShapeNodes = canCombineShapeNodes; exports.canvasHeight = canvasHeight; exports.centerNodes = _chunkWADCJ7A7cjs.centerNodes; exports.centre = _chunkWADCJ7A7cjs.centre; exports.collectDescendantIds = collectDescendantIds; exports.combineShapeNodes = combineShapeNodes; exports.computeNodesBoundingBox = computeNodesBoundingBox; exports.computeSnapGuides = computeSnapGuides; exports.connectedOnly = connectedOnly; exports.createBezierTrajectory = createBezierTrajectory; exports.createCanvasArrangeController = createCanvasArrangeController; exports.createCanvasScenesStore = createCanvasScenesStore; exports.createFanOutTrajectory = createFanOutTrajectory; exports.createGuideIndex = createGuideIndex; exports.createNodeGuideIndex = createNodeGuideIndex; exports.createNodeLookup = createNodeLookup; exports.defaultEasing = defaultEasing; exports.distributeNodes = distributeNodes; exports.dividePolygons = dividePolygons; exports.ensureLayout = _chunkWADCJ7A7cjs.ensureLayout; exports.estimateCanvasHeight = estimateCanvasHeight; exports.estimateNodeSize = _chunkWADCJ7A7cjs.estimateNodeSize; exports.findConnectorSnap = findConnectorSnap; exports.fitViewportToNodes = fitViewportToNodes; exports.fitViewportToRect = fitViewportToRect; exports.flattenSvgPath = flattenSvgPath; exports.flowSide = _chunkWADCJ7A7cjs.flowSide; exports.formatNumber = formatNumber; exports.getAbsolutePosition = getAbsolutePosition; exports.getCenteredNodePosition = _chunkWADCJ7A7cjs.getCenteredNodePosition; exports.getLayoutedNodes = _chunkWADCJ7A7cjs.getLayoutedNodes; exports.getNodeRect = getNodeRect; exports.getNodeShape = getNodeShape; exports.getNodeSize = getNodeSize; exports.getShapeRenderData = getShapeRenderData; exports.getShapeSvg = getShapeSvg; exports.handlePoint = handlePoint; exports.intersectPolygons = intersectPolygons; exports.invertNodeUpdates = invertNodeUpdates; exports.isEventFromTextInput = isEventFromTextInput; exports.isLocked = isLocked; exports.isShapeDescription = isShapeDescription; exports.isShapeNode = isShapeNode; exports.isValidCanvasEdge = isValidCanvasEdge; exports.isValidCanvasNode = isValidCanvasNode; exports.isValidCanvasScene = isValidCanvasScene; exports.isValidUrl = isValidUrl; exports.layoutBounds = layoutBounds; exports.linearPositionTrajectory = linearPositionTrajectory; exports.linearTrajectory = linearTrajectory; exports.lockNodes = lockNodes; exports.matchArrangeShortcut = matchArrangeShortcut; exports.matchSize = matchSize; exports.multiPolygonArea = multiPolygonArea; exports.multiPolygonBounds = multiPolygonBounds; exports.nearestHandlePositions = nearestHandlePositions; exports.oppositePosition = oppositePosition; exports.overlaps = _chunkWADCJ7A7cjs.overlaps; exports.pageHidden = pageHidden; exports.parseCanvasClipboardData = parseCanvasClipboardData; exports.parseCanvasScenes = parseCanvasScenes; exports.parseSvgPath = parseSvgPath; exports.placeBeside = _chunkWADCJ7A7cjs.placeBeside; exports.pointInMultiPolygon = pointInMultiPolygon; exports.pointInRings = pointInRings; exports.polygonArea = polygonArea; exports.polygonBoolean = polygonBoolean; exports.polygonToSvgPath = polygonToSvgPath; exports.positionToSide = positionToSide; exports.readStyleSize = readStyleSize; exports.realClock = realClock; exports.remapPastedNodes = remapPastedNodes; exports.reorderNodes = reorderNodes; exports.repositionNodesTo = repositionNodesTo; exports.revertShapeCombination = revertShapeCombination; exports.ringSignedArea = ringSignedArea; exports.runMultiNodeTransition = runMultiNodeTransition; exports.serializeCanvasNodes = serializeCanvasNodes; exports.shapeNodeToPolygon = shapeNodeToPolygon; exports.shapeToPolygon = shapeToPolygon; exports.sideToPosition = sideToPosition; exports.simplifyRing = simplifyRing; exports.snapNodeDrag = snapNodeDrag; exports.subtractPolygons = subtractPolygons; exports.toggleLockNodes = toggleLockNodes; exports.unionPolygons = unionPolygons; exports.unlockNodes = unlockNodes; exports.withStyleOpacity = withStyleOpacity; exports.withStyleSize = withStyleSize; exports.xorPolygons = xorPolygons;
5226
+ exports.AUTO_LAYOUT_DATA_KEY = AUTO_LAYOUT_DATA_KEY; exports.CHILD_LAYOUT_DATA_KEY = CHILD_LAYOUT_DATA_KEY; exports.CONNECTION_LINE_TYPES = CONNECTION_LINE_TYPES; exports.CanvasScenesStore = CanvasScenesStore; exports.DEFAULT_ARRANGE_SHORTCUTS = _chunk26BVFKHUcjs.DEFAULT_ARRANGE_SHORTCUTS; exports.DEFAULT_NODE_HEIGHT = _chunkWADCJ7A7cjs.DEFAULT_NODE_HEIGHT; exports.DEFAULT_NODE_WIDTH = _chunkWADCJ7A7cjs.DEFAULT_NODE_WIDTH; exports.DEFAULT_PLACEMENT_GAP = _chunkWADCJ7A7cjs.DEFAULT_PLACEMENT_GAP; exports.LOCKED_DATA_KEY = LOCKED_DATA_KEY; exports.LOCKED_PREVIOUS_FLAGS_KEY = LOCKED_PREVIOUS_FLAGS_KEY; exports.ManualClock = ManualClock; exports.RESIZE_HANDLES = RESIZE_HANDLES; exports.SHAPE_DATA_KEY = SHAPE_DATA_KEY; exports.SHAPE_KINDS = SHAPE_KINDS; exports.SHAPE_NODE_TYPE = SHAPE_NODE_TYPE; exports.SHAPE_OPERATIONS = SHAPE_OPERATIONS; exports.StreamingLayoutManager = StreamingLayoutManager; exports.alignNodes = alignNodes; exports.applyConstraints = applyConstraints; exports.applyNodeUpdates = applyNodeUpdates; exports.applyShapeCombination = applyShapeCombination; exports.blendLayout = blendLayout; exports.boundsOf = _chunkWADCJ7A7cjs.boundsOf; exports.calculateDagreReflowDisplacement = calculateDagreReflowDisplacement; exports.calculateDirectionalDisplacement = calculateDirectionalDisplacement; exports.canCombineShapeNodes = canCombineShapeNodes; exports.canvasHeight = canvasHeight; exports.centerNodes = _chunkWADCJ7A7cjs.centerNodes; exports.centre = _chunkWADCJ7A7cjs.centre; exports.clampLayoutSize = clampLayoutSize; exports.collectDescendantIds = collectDescendantIds; exports.combineShapeNodes = combineShapeNodes; exports.computeNodesBoundingBox = computeNodesBoundingBox; exports.computeSnapGuides = computeSnapGuides; exports.connectedOnly = connectedOnly; exports.createBezierTrajectory = createBezierTrajectory; exports.createCanvasArrangeController = createCanvasArrangeController; exports.createCanvasAutoLayoutController = createCanvasAutoLayoutController; exports.createCanvasScenesStore = createCanvasScenesStore; exports.createFanOutTrajectory = createFanOutTrajectory; exports.createGuideIndex = createGuideIndex; exports.createNodeGuideIndex = createNodeGuideIndex; exports.createNodeLookup = createNodeLookup; exports.cubicPointAt = cubicPointAt; exports.cubicsToPathData = cubicsToPathData; exports.defaultEasing = defaultEasing; exports.distributeNodes = distributeNodes; exports.dividePolygons = dividePolygons; exports.ensureLayout = _chunkWADCJ7A7cjs.ensureLayout; exports.estimateCanvasHeight = estimateCanvasHeight; exports.estimateNodeSize = _chunkWADCJ7A7cjs.estimateNodeSize; exports.findConnectorSnap = findConnectorSnap; exports.fitCubicRun = fitCubicRun; exports.fitCubics = fitCubics; exports.fitFreehandPath = fitFreehandPath; exports.fitPathData = fitPathData; exports.fitViewportToNodes = fitViewportToNodes; exports.fitViewportToRect = fitViewportToRect; exports.flattenSvgPath = flattenSvgPath; exports.flowSide = _chunkWADCJ7A7cjs.flowSide; exports.formatNumber = formatNumber2; exports.getAbsolutePosition = getAbsolutePosition; exports.getAutoLayout = getAutoLayout; exports.getAutoLayoutGrid = getAutoLayoutGrid; exports.getAutoLayoutInsertTarget = getAutoLayoutInsertTarget; exports.getCenteredNodePosition = _chunkWADCJ7A7cjs.getCenteredNodePosition; exports.getChildLayout = getChildLayout; exports.getFlowChildren = getFlowChildren; exports.getLayoutParent = getLayoutParent; exports.getLayoutSizing = getLayoutSizing; exports.getLayoutedNodes = _chunkWADCJ7A7cjs.getLayoutedNodes; exports.getNodeRect = getNodeRect; exports.getNodeShape = getNodeShape; exports.getNodeSize = getNodeSize; exports.getResizingNodeRect = getResizingNodeRect; exports.getShapeRenderData = getShapeRenderData; exports.getShapeSvg = getShapeSvg; exports.handlePoint = handlePoint; exports.inferResizeHandle = inferResizeHandle; exports.intersectPolygons = intersectPolygons; exports.invertNodeUpdates = invertNodeUpdates; exports.isAutoLayoutFrame = isAutoLayoutFrame; exports.isEventFromTextInput = isEventFromTextInput; exports.isLocked = isLocked; exports.isMeasureModifierHeld = isMeasureModifierHeld; exports.isShapeDescription = isShapeDescription; exports.isShapeNode = isShapeNode; exports.isStraightCubic = isStraightCubic; exports.isValidCanvasEdge = isValidCanvasEdge; exports.isValidCanvasNode = isValidCanvasNode; exports.isValidCanvasScene = isValidCanvasScene; exports.isValidUrl = isValidUrl; exports.layoutAll = layoutAll; exports.layoutBounds = layoutBounds; exports.layoutFrame = layoutFrame; exports.layoutUp = layoutUp; exports.layoutUpMany = layoutUpMany; exports.linearPositionTrajectory = linearPositionTrajectory; exports.linearTrajectory = linearTrajectory; exports.lockNodes = lockNodes; exports.makeSizingCoherent = makeSizingCoherent; exports.matchArrangeShortcut = _chunk26BVFKHUcjs.matchArrangeShortcut; exports.matchSize = matchSize; exports.measureBetween = measureBetween; exports.measureLabel = measureLabel; exports.measureSelection = measureSelection; exports.measureToLine = measureToLine; exports.mergeNodeUpdates = mergeNodeUpdates; exports.moveLayoutChild = moveLayoutChild; exports.multiPolygonArea = multiPolygonArea; exports.multiPolygonBounds = multiPolygonBounds; exports.nearestHandlePositions = nearestHandlePositions; exports.oppositePosition = oppositePosition; exports.overlaps = _chunkWADCJ7A7cjs.overlaps; exports.pageHidden = pageHidden; exports.parseCanvasClipboardData = parseCanvasClipboardData; exports.parseCanvasScenes = parseCanvasScenes; exports.parseSvgPath = parseSvgPath; exports.placeBeside = _chunkWADCJ7A7cjs.placeBeside; exports.pointInMultiPolygon = pointInMultiPolygon; exports.pointInRings = pointInRings; exports.polygonArea = polygonArea; exports.polygonBoolean = polygonBoolean; exports.polygonToSvgPath = polygonToSvgPath; exports.positionToSide = positionToSide; exports.readStyleSize = readStyleSize; exports.realClock = realClock; exports.relayoutUpdates = relayoutUpdates; exports.remapPastedNodes = remapPastedNodes; exports.reorderNodes = reorderNodes; exports.repositionNodesTo = repositionNodesTo; exports.resizeHandleAxes = resizeHandleAxes; exports.resolvePadding = resolvePadding; exports.revertShapeCombination = revertShapeCombination; exports.ringSignedArea = ringSignedArea; exports.runMultiNodeTransition = runMultiNodeTransition; exports.serializeCanvasNodes = serializeCanvasNodes; exports.shapeNodeToPolygon = shapeNodeToPolygon; exports.shapeToPolygon = shapeToPolygon; exports.sideToPosition = sideToPosition; exports.simplifyRing = simplifyRing; exports.snapNodeDrag = snapNodeDrag; exports.snapNodeResize = snapNodeResize; exports.snapResize = snapResize; exports.snapToGrid = snapToGrid; exports.subtractPolygons = subtractPolygons; exports.toggleLockNodes = toggleLockNodes; exports.unionPolygons = unionPolygons; exports.unlockNodes = unlockNodes; exports.withStyleOpacity = withStyleOpacity; exports.withStyleSize = withStyleSize; exports.xorPolygons = xorPolygons;
3238
5227
  //# sourceMappingURL=index.cjs.map