@pixerate/editor 0.25.0 → 0.26.1

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 (113) hide show
  1. package/README.md +30 -0
  2. package/THIRD_PARTY_NOTICES.md +11 -0
  3. package/dist/agent/index.cjs +174 -11
  4. package/dist/agent/index.cjs.map +1 -1
  5. package/dist/agent/index.d.cts +18 -4
  6. package/dist/agent/index.d.ts +18 -4
  7. package/dist/agent/index.js +167 -4
  8. package/dist/agent/index.js.map +1 -1
  9. package/dist/{arrangeShortcuts-B8O3f8-P.d.cts → arrange-BICutYPk.d.cts} +243 -29
  10. package/dist/{arrangeShortcuts-sLlD2rSX.d.ts → arrange-BICutYPk.d.ts} +243 -29
  11. package/dist/builtins-CdPcLwwF.d.cts +176 -0
  12. package/dist/builtins-Chj6zv_O.d.ts +176 -0
  13. package/dist/canvas/index.cjs +3917 -19
  14. package/dist/canvas/index.cjs.map +1 -1
  15. package/dist/canvas/index.d.cts +1232 -7
  16. package/dist/canvas/index.d.ts +1232 -7
  17. package/dist/canvas/index.js +3916 -18
  18. package/dist/canvas/index.js.map +1 -1
  19. package/dist/chunk-3CC7OPUQ.cjs +831 -0
  20. package/dist/chunk-3CC7OPUQ.cjs.map +1 -0
  21. package/dist/{chunk-7WISYZFO.cjs → chunk-66IMF6OD.cjs} +174 -67
  22. package/dist/chunk-66IMF6OD.cjs.map +1 -0
  23. package/dist/{chunk-AL6JMGWW.cjs → chunk-CS6NZWWA.cjs} +24 -24
  24. package/dist/{chunk-AL6JMGWW.cjs.map → chunk-CS6NZWWA.cjs.map} +1 -1
  25. package/dist/{chunk-C7P22VIP.cjs → chunk-EWCOFSCQ.cjs} +17 -6
  26. package/dist/chunk-EWCOFSCQ.cjs.map +1 -0
  27. package/dist/chunk-HDYMLS3X.cjs +409 -0
  28. package/dist/chunk-HDYMLS3X.cjs.map +1 -0
  29. package/dist/{chunk-V3CHHWOE.cjs → chunk-HNDSPZ5T.cjs} +4 -4
  30. package/dist/{chunk-V3CHHWOE.cjs.map → chunk-HNDSPZ5T.cjs.map} +1 -1
  31. package/dist/{chunk-X4N4WUKB.cjs → chunk-IFHKKVXH.cjs} +150 -38
  32. package/dist/chunk-IFHKKVXH.cjs.map +1 -0
  33. package/dist/chunk-KRGXUQ2Y.js +1696 -0
  34. package/dist/chunk-KRGXUQ2Y.js.map +1 -0
  35. package/dist/{chunk-PO6A6QQH.cjs → chunk-LN2POBHT.cjs} +742 -970
  36. package/dist/chunk-LN2POBHT.cjs.map +1 -0
  37. package/dist/chunk-MR2764X2.js +831 -0
  38. package/dist/chunk-MR2764X2.js.map +1 -0
  39. package/dist/{chunk-WSQKHXW7.cjs → chunk-NQF32I6Z.cjs} +1209 -457
  40. package/dist/chunk-NQF32I6Z.cjs.map +1 -0
  41. package/dist/{chunk-NAXVVS5I.js → chunk-QJSOZFCZ.js} +2 -2
  42. package/dist/{chunk-UAKDG62Z.js → chunk-SWE3NPOU.js} +116 -4
  43. package/dist/chunk-SWE3NPOU.js.map +1 -0
  44. package/dist/chunk-TXXNBDQX.cjs +1696 -0
  45. package/dist/chunk-TXXNBDQX.cjs.map +1 -0
  46. package/dist/chunk-UBCFIABU.js +409 -0
  47. package/dist/chunk-UBCFIABU.js.map +1 -0
  48. package/dist/{chunk-ECCCYKGL.js → chunk-UKI64KUD.js} +147 -40
  49. package/dist/chunk-UKI64KUD.js.map +1 -0
  50. package/dist/{chunk-QGYDWPRM.js → chunk-WON34HKM.js} +2 -2
  51. package/dist/{chunk-RR7F5GUM.js → chunk-X7HXL2SB.js} +941 -189
  52. package/dist/chunk-X7HXL2SB.js.map +1 -0
  53. package/dist/{chunk-IXHSYOVY.js → chunk-XQFHLT53.js} +638 -866
  54. package/dist/chunk-XQFHLT53.js.map +1 -0
  55. package/dist/{chunk-FH6F67DN.js → chunk-ZRNHGAQT.js} +17 -6
  56. package/dist/{chunk-FH6F67DN.js.map → chunk-ZRNHGAQT.js.map} +1 -1
  57. package/dist/commands/index.cjs +352 -4
  58. package/dist/commands/index.cjs.map +1 -1
  59. package/dist/commands/index.d.cts +37 -108
  60. package/dist/commands/index.d.ts +37 -108
  61. package/dist/commands/index.js +351 -3
  62. package/dist/commands/index.js.map +1 -1
  63. package/dist/compare/index.cjs +3 -3
  64. package/dist/compare/index.js +2 -2
  65. package/dist/{controller-BIJiNoVs.d.cts → controller-CxXGOEmy.d.cts} +209 -13
  66. package/dist/{controller-BIJiNoVs.d.ts → controller-CxXGOEmy.d.ts} +209 -13
  67. package/dist/export/index.cjs +36 -0
  68. package/dist/export/index.cjs.map +1 -0
  69. package/dist/export/index.d.cts +243 -0
  70. package/dist/export/index.d.ts +243 -0
  71. package/dist/export/index.js +36 -0
  72. package/dist/export/index.js.map +1 -0
  73. package/dist/extensions/index.cjs +54 -6
  74. package/dist/extensions/index.cjs.map +1 -1
  75. package/dist/extensions/index.d.cts +7 -2
  76. package/dist/extensions/index.d.ts +7 -2
  77. package/dist/extensions/index.js +59 -11
  78. package/dist/{index-7a6bHTLy.d.ts → index-B273Zllk.d.ts} +211 -207
  79. package/dist/{index-Csd5qI8u.d.cts → index-jcJwmBYt.d.cts} +211 -207
  80. package/dist/index.cjs +146 -32
  81. package/dist/index.cjs.map +1 -1
  82. package/dist/index.d.cts +50 -14
  83. package/dist/index.d.ts +50 -14
  84. package/dist/index.js +138 -24
  85. package/dist/index.js.map +1 -1
  86. package/dist/registry-CED5C0lA.d.cts +204 -0
  87. package/dist/registry-CED5C0lA.d.ts +204 -0
  88. package/dist/{registry-D32LpIc4.d.cts → registry-D0GADKc7.d.cts} +1 -1
  89. package/dist/{registry-evKTP4ls.d.ts → registry-DhVUZioj.d.ts} +1 -1
  90. package/dist/serializers/index.cjs +6 -4
  91. package/dist/serializers/index.cjs.map +1 -1
  92. package/dist/serializers/index.d.cts +15 -4
  93. package/dist/serializers/index.d.ts +15 -4
  94. package/dist/serializers/index.js +5 -3
  95. package/dist/spreadsheet/index.cjs +33 -3
  96. package/dist/spreadsheet/index.cjs.map +1 -1
  97. package/dist/spreadsheet/index.d.cts +106 -3
  98. package/dist/spreadsheet/index.d.ts +106 -3
  99. package/dist/spreadsheet/index.js +32 -2
  100. package/package.json +10 -1
  101. package/dist/chunk-7WISYZFO.cjs.map +0 -1
  102. package/dist/chunk-C7P22VIP.cjs.map +0 -1
  103. package/dist/chunk-ECCCYKGL.js.map +0 -1
  104. package/dist/chunk-IXHSYOVY.js.map +0 -1
  105. package/dist/chunk-PO6A6QQH.cjs.map +0 -1
  106. package/dist/chunk-RR7F5GUM.js.map +0 -1
  107. package/dist/chunk-UAKDG62Z.js.map +0 -1
  108. package/dist/chunk-WSQKHXW7.cjs.map +0 -1
  109. package/dist/chunk-X4N4WUKB.cjs.map +0 -1
  110. package/dist/types-DX4Mh4SL.d.cts +0 -217
  111. package/dist/types-DX4Mh4SL.d.ts +0 -217
  112. /package/dist/{chunk-NAXVVS5I.js.map → chunk-QJSOZFCZ.js.map} +0 -0
  113. /package/dist/{chunk-QGYDWPRM.js.map → chunk-WON34HKM.js.map} +0 -0
@@ -1,4 +1,4 @@
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; var _class7;
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; var _class7; var _class8; var _class9; var _class10;
2
2
 
3
3
 
4
4
  var _chunk26BVFKHUcjs = require('../chunk-26BVFKHU.cjs');
@@ -8,6 +8,9 @@ var _chunk26BVFKHUcjs = require('../chunk-26BVFKHU.cjs');
8
8
 
9
9
 
10
10
 
11
+
12
+
13
+
11
14
  var _chunk4BVP64JJcjs = require('../chunk-4BVP64JJ.cjs');
12
15
 
13
16
 
@@ -2264,17 +2267,17 @@ function newton(c, p, t) {
2264
2267
  6 * (s * (c.p2[1] - 2 * c.p1[1] + c.p0[1]) + t * (c.p3[1] - 2 * c.p2[1] + c.p1[1]))
2265
2268
  ];
2266
2269
  const diff = [q[0] - p[0], q[1] - p[1]];
2267
- const num = dot(diff, d1);
2270
+ const num2 = dot(diff, d1);
2268
2271
  const den = dot(d1, d1) + dot(diff, d2);
2269
2272
  if (Math.abs(den) < 1e-12) return t;
2270
- const nt = t - num / den;
2273
+ const nt = t - num2 / den;
2271
2274
  return Number.isFinite(nt) ? Math.min(1, Math.max(0, nt)) : t;
2272
2275
  }
2273
2276
  function fitSingleFrom(pts, u, t0, t1) {
2274
2277
  let best = generate(pts, u, t0, t1);
2275
2278
  let [bestErr, bestSplit] = maxError(pts, best, u);
2276
2279
  const params = u.slice();
2277
- for (let round = 0; round < MAX_REPARAM; round++) {
2280
+ for (let round3 = 0; round3 < MAX_REPARAM; round3++) {
2278
2281
  for (let i = 0; i < params.length; i++) params[i] = newton(best, pts[i], params[i]);
2279
2282
  const c = generate(pts, params, t0, t1);
2280
2283
  const [e, s] = maxError(pts, c, params);
@@ -2729,9 +2732,9 @@ function flattenArc(out, p0, cmd, tolerance, max) {
2729
2732
  rx *= s;
2730
2733
  ry *= s;
2731
2734
  }
2732
- const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
2735
+ const num2 = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
2733
2736
  const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
2734
- let coef = den === 0 ? 0 : Math.sqrt(Math.max(0, num / den));
2737
+ let coef = den === 0 ? 0 : Math.sqrt(Math.max(0, num2 / den));
2735
2738
  if (cmd.largeArc === cmd.sweep) coef = -coef;
2736
2739
  const cxp = coef * rx * y1p / ry;
2737
2740
  const cyp = -coef * ry * x1p / rx;
@@ -3382,9 +3385,9 @@ function arcToCubics(from, cmd) {
3382
3385
  rx *= s;
3383
3386
  ry *= s;
3384
3387
  }
3385
- const num = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
3388
+ const num2 = rx * rx * ry * ry - rx * rx * y1p * y1p - ry * ry * x1p * x1p;
3386
3389
  const den = rx * rx * y1p * y1p + ry * ry * x1p * x1p;
3387
- let coef = den === 0 ? 0 : Math.sqrt(Math.max(0, num / den));
3390
+ let coef = den === 0 ? 0 : Math.sqrt(Math.max(0, num2 / den));
3388
3391
  if (cmd.largeArc === cmd.sweep) coef = -coef;
3389
3392
  const cxp = coef * rx * y1p / ry;
3390
3393
  const cyp = -coef * ry * x1p / rx;
@@ -5262,15 +5265,15 @@ function combineShapeNodes(nodes, ids, operation, options = {}) {
5262
5265
  }
5263
5266
  }
5264
5267
  if (created.length === 0) return { ok: false, operation, reason: "empty" };
5265
- const done = {
5268
+ const done2 = {
5266
5269
  ok: true,
5267
5270
  operation,
5268
5271
  removeIds: ordered.map((n) => n.id),
5269
5272
  nodes: created,
5270
5273
  engine: report.engine
5271
5274
  };
5272
- if (report.fallbackReason) done.fallbackReason = report.fallbackReason;
5273
- return done;
5275
+ if (report.fallbackReason) done2.fallbackReason = report.fallbackReason;
5276
+ return done2;
5274
5277
  }
5275
5278
  function buildPathNode(path, source, id, options) {
5276
5279
  const bounds = bezierPathBounds(path);
@@ -5956,7 +5959,7 @@ function layoutFrameInner(s, frame) {
5956
5959
  const alignMain = _nullishCoalesce(al.alignMain, () => ( "start"));
5957
5960
  const autoGap = alignMain === "space-between" || alignMain === "space-around" || alignMain === "space-evenly";
5958
5961
  const wraps = !!al.wrap && !hugMain;
5959
- const sizeOf = (id) => {
5962
+ const sizeOf2 = (id) => {
5960
5963
  const b = s.boxes.get(id);
5961
5964
  return horizontal ? [b.w, b.h] : [b.h, b.w];
5962
5965
  };
@@ -5965,7 +5968,7 @@ function layoutFrameInner(s, frame) {
5965
5968
  for (const it of items) {
5966
5969
  if (!it.fillCross || it.fillMain) continue;
5967
5970
  resize(it, it.main, clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross));
5968
- it.main = sizeOf(it.id)[0];
5971
+ it.main = sizeOf2(it.id)[0];
5969
5972
  }
5970
5973
  }
5971
5974
  const lines = [];
@@ -5998,7 +6001,7 @@ function layoutFrameInner(s, frame) {
5998
6001
  if (!it.fillMain) continue;
5999
6002
  const cross2 = it.fillCross && !wraps ? clampLayoutSize(innerCrossFixed, it.minCross, it.maxCross) : it.cross;
6000
6003
  resize(it, it.main, cross2);
6001
- it.cross = sizeOf(it.id)[1];
6004
+ it.cross = sizeOf2(it.id)[1];
6002
6005
  }
6003
6006
  if (baseline) {
6004
6007
  for (const it of items) if (!it.fillCross) it.baseline = itemBaseline(s, it.id, 0);
@@ -6542,11 +6545,11 @@ function moveLayoutChild(nodes, childId, index) {
6542
6545
  function parentsFirst(nodes) {
6543
6546
  const ids = new Set(nodes.map((n) => n.id));
6544
6547
  const pending = /* @__PURE__ */ new Map();
6545
- const done = /* @__PURE__ */ new Set();
6548
+ const done2 = /* @__PURE__ */ new Set();
6546
6549
  const out = [];
6547
6550
  const emit = (n) => {
6548
6551
  out.push(n);
6549
- done.add(n.id);
6552
+ done2.add(n.id);
6550
6553
  const waiting = pending.get(n.id);
6551
6554
  if (waiting) {
6552
6555
  pending.delete(n.id);
@@ -6554,12 +6557,12 @@ function parentsFirst(nodes) {
6554
6557
  }
6555
6558
  };
6556
6559
  for (const n of nodes) {
6557
- if (n.parentId && ids.has(n.parentId) && !done.has(n.parentId) && n.parentId !== n.id) {
6560
+ if (n.parentId && ids.has(n.parentId) && !done2.has(n.parentId) && n.parentId !== n.id) {
6558
6561
  if (!pending.has(n.parentId)) pending.set(n.parentId, []);
6559
6562
  pending.get(n.parentId).push(n);
6560
6563
  } else emit(n);
6561
6564
  }
6562
- for (const waiting of pending.values()) for (const n of waiting) if (!done.has(n.id)) emit(n);
6565
+ for (const waiting of pending.values()) for (const n of waiting) if (!done2.has(n.id)) emit(n);
6563
6566
  return out;
6564
6567
  }
6565
6568
 
@@ -7431,6 +7434,9 @@ function parseDeclarations(style) {
7431
7434
  }
7432
7435
  return out;
7433
7436
  }
7437
+ function parseNodeStyleDeclarations(style) {
7438
+ return parseDeclarations(style);
7439
+ }
7434
7440
  function readNodeStyleProperty(style, prop) {
7435
7441
  if (!style) return void 0;
7436
7442
  if (typeof style === "object") return style[prop];
@@ -7837,6 +7843,3898 @@ function pruneCanvasTokenModes(nodes, state) {
7837
7843
  return changed ? out : nodes;
7838
7844
  }
7839
7845
 
7846
+ // src/canvas/animation/easing.ts
7847
+ var ANIMATION_EASING_PRESETS = [
7848
+ "linear",
7849
+ "ease",
7850
+ "ease-in",
7851
+ "ease-out",
7852
+ "ease-in-out",
7853
+ "ease-in-back",
7854
+ "ease-out-back",
7855
+ "spring",
7856
+ "hold"
7857
+ ];
7858
+ var ANIMATION_EASING_LABELS = {
7859
+ linear: "Linear",
7860
+ hold: "Hold",
7861
+ ease: "Ease",
7862
+ "ease-in": "Ease in",
7863
+ "ease-out": "Ease out",
7864
+ "ease-in-out": "Ease in-out",
7865
+ "ease-in-back": "Back in",
7866
+ "ease-out-back": "Back out",
7867
+ spring: "Spring"
7868
+ };
7869
+ var CUBIC_BEZIER_PRESETS = {
7870
+ linear: [0, 0, 1, 1],
7871
+ ease: [0.25, 0.1, 0.25, 1],
7872
+ "ease-in": [0.42, 0, 1, 1],
7873
+ "ease-out": [0, 0, 0.58, 1],
7874
+ "ease-in-out": [0.42, 0, 0.58, 1],
7875
+ "ease-in-back": [0.36, 0, 0.66, -0.56],
7876
+ "ease-out-back": [0.34, 1.56, 0.64, 1]
7877
+ };
7878
+ var DEFAULT_SPRING = { stiffness: 170, damping: 26, mass: 1, velocity: 0 };
7879
+ var clamp = (v, lo, hi) => Math.min(hi, Math.max(lo, v));
7880
+ var finite2 = (v, fallback) => typeof v === "number" && Number.isFinite(v) ? v : fallback;
7881
+ function cubicBezierAt(x1, y1, x2, y2, x) {
7882
+ if (x <= 0) return 0;
7883
+ if (x >= 1) return 1;
7884
+ x1 = clamp(x1, 0, 1);
7885
+ x2 = clamp(x2, 0, 1);
7886
+ const bx = (s2) => 3 * (1 - s2) * (1 - s2) * s2 * x1 + 3 * (1 - s2) * s2 * s2 * x2 + s2 * s2 * s2;
7887
+ const by = (s2) => 3 * (1 - s2) * (1 - s2) * s2 * y1 + 3 * (1 - s2) * s2 * s2 * y2 + s2 * s2 * s2;
7888
+ const dbx = (s2) => 3 * (1 - s2) * (1 - s2) * x1 + 6 * (1 - s2) * s2 * (x2 - x1) + 3 * s2 * s2 * (1 - x2);
7889
+ let s = x;
7890
+ for (let i = 0; i < 8; i++) {
7891
+ const d = dbx(s);
7892
+ if (Math.abs(d) < 1e-9) break;
7893
+ const next = s - (bx(s) - x) / d;
7894
+ if (!(next >= 0 && next <= 1)) break;
7895
+ s = next;
7896
+ }
7897
+ if (Math.abs(bx(s) - x) > 1e-7) {
7898
+ let lo = 0;
7899
+ let hi = 1;
7900
+ for (let i = 0; i < 60; i++) {
7901
+ s = (lo + hi) / 2;
7902
+ if (bx(s) < x) lo = s;
7903
+ else hi = s;
7904
+ }
7905
+ }
7906
+ return by(s);
7907
+ }
7908
+ function springAt(spring, seconds) {
7909
+ const stiffness = Math.max(1e-6, finite2(spring.stiffness, DEFAULT_SPRING.stiffness));
7910
+ const damping = Math.max(0, finite2(spring.damping, DEFAULT_SPRING.damping));
7911
+ const mass = Math.max(1e-6, finite2(spring.mass, DEFAULT_SPRING.mass));
7912
+ const v0 = -finite2(spring.velocity, DEFAULT_SPRING.velocity);
7913
+ const t = Math.max(0, seconds);
7914
+ const w0 = Math.sqrt(stiffness / mass);
7915
+ const zeta = damping / (2 * Math.sqrt(stiffness * mass));
7916
+ let x;
7917
+ if (zeta < 1 - 1e-6) {
7918
+ const wd = w0 * Math.sqrt(1 - zeta * zeta);
7919
+ x = Math.exp(-zeta * w0 * t) * (Math.cos(wd * t) + (zeta * w0 + v0) / wd * Math.sin(wd * t));
7920
+ } else if (zeta <= 1 + 1e-6) {
7921
+ x = Math.exp(-w0 * t) * (1 + (w0 + v0) * t);
7922
+ } else {
7923
+ const r = Math.sqrt(zeta * zeta - 1);
7924
+ const s1 = -w0 * (zeta - r);
7925
+ const s2 = -w0 * (zeta + r);
7926
+ const c2 = (v0 - s1) / (s2 - s1);
7927
+ const c1 = 1 - c2;
7928
+ x = c1 * Math.exp(s1 * t) + c2 * Math.exp(s2 * t);
7929
+ }
7930
+ return 1 - x;
7931
+ }
7932
+ function resolveEasing(easing) {
7933
+ if (easing === "hold") return "hold";
7934
+ if (easing === "spring") return { type: "spring", ...DEFAULT_SPRING };
7935
+ if (typeof easing === "string") {
7936
+ const preset = CUBIC_BEZIER_PRESETS[easing];
7937
+ if (preset) return { type: "cubic-bezier", x1: preset[0], y1: preset[1], x2: preset[2], y2: preset[3] };
7938
+ const parsed = parseCssEasing(easing);
7939
+ return parsed ? resolveEasing(parsed) : { type: "cubic-bezier", x1: 0, y1: 0, x2: 1, y2: 1 };
7940
+ }
7941
+ if (easing && typeof easing === "object") {
7942
+ if (easing.type === "spring") {
7943
+ return {
7944
+ type: "spring",
7945
+ stiffness: finite2(easing.stiffness, DEFAULT_SPRING.stiffness),
7946
+ damping: finite2(easing.damping, DEFAULT_SPRING.damping),
7947
+ mass: finite2(easing.mass, DEFAULT_SPRING.mass),
7948
+ velocity: finite2(easing.velocity, DEFAULT_SPRING.velocity)
7949
+ };
7950
+ }
7951
+ if (easing.type === "cubic-bezier") {
7952
+ return {
7953
+ type: "cubic-bezier",
7954
+ x1: clamp(finite2(easing.x1, 0), 0, 1),
7955
+ y1: finite2(easing.y1, 0),
7956
+ x2: clamp(finite2(easing.x2, 1), 0, 1),
7957
+ y2: finite2(easing.y2, 1)
7958
+ };
7959
+ }
7960
+ }
7961
+ return { type: "cubic-bezier", x1: 0, y1: 0, x2: 1, y2: 1 };
7962
+ }
7963
+ function evaluateEasing(easing, u, durationMs = 1e3) {
7964
+ if (!(u > 0)) return 0;
7965
+ if (u >= 1) return 1;
7966
+ const resolved = resolveEasing(easing);
7967
+ if (resolved === "hold") return 0;
7968
+ if (resolved.type === "spring") return springAt(resolved, u * Math.max(0, durationMs) / 1e3);
7969
+ const { x1, y1, x2, y2 } = resolved;
7970
+ if (x1 === y1 && x2 === y2) return u;
7971
+ return cubicBezierAt(x1, y1, x2, y2, u);
7972
+ }
7973
+ function easingFromInfluence(outInfluence = 1 / 3, inInfluence = 1 / 3) {
7974
+ return {
7975
+ type: "cubic-bezier",
7976
+ x1: clamp(outInfluence, 0.01, 1),
7977
+ y1: 0,
7978
+ x2: 1 - clamp(inInfluence, 0.01, 1),
7979
+ y2: 1
7980
+ };
7981
+ }
7982
+ var NUMBER = String.raw`\s*(-?(?:\d+\.?\d*|\.\d+)(?:e[-+]?\d+)?)\s*`;
7983
+ var CUBIC_RE = new RegExp(`^cubic-bezier\\(${NUMBER},${NUMBER},${NUMBER},${NUMBER}\\)$`, "i");
7984
+ function parseCssEasing(text) {
7985
+ const value = text.trim().toLowerCase();
7986
+ if (value.length > 200) return null;
7987
+ if (ANIMATION_EASING_PRESETS.includes(value)) return value;
7988
+ if (value === "step-end" || /^steps\(\s*1\s*(,\s*(end|jump-end)\s*)?\)$/.test(value)) return "hold";
7989
+ const m = CUBIC_RE.exec(value);
7990
+ if (!m) return null;
7991
+ const [x1, y1, x2, y2] = m.slice(1).map(Number);
7992
+ if (![x1, y1, x2, y2].every(Number.isFinite) || x1 < 0 || x1 > 1 || x2 < 0 || x2 > 1) return null;
7993
+ return { type: "cubic-bezier", x1, y1, x2, y2 };
7994
+ }
7995
+ function isAnimationEasing(value) {
7996
+ if (typeof value === "string") return parseCssEasing(value) !== null;
7997
+ if (typeof value !== "object" || value === null) return false;
7998
+ const e = value;
7999
+ if (e.type === "spring") return true;
8000
+ return e.type === "cubic-bezier" && [e.x1, e.y1, e.x2, e.y2].every((v) => typeof v === "number" && Number.isFinite(v));
8001
+ }
8002
+ var round = (v, digits = 4) => {
8003
+ const p = 10 ** digits;
8004
+ return Math.round(v * p) / p;
8005
+ };
8006
+ function easingToCss(easing, durationMs = 1e3, samples = 24) {
8007
+ const resolved = resolveEasing(easing);
8008
+ if (resolved === "hold") return "steps(1, end)";
8009
+ if (resolved.type === "spring") {
8010
+ const n = Math.max(2, Math.floor(samples));
8011
+ const points = [];
8012
+ for (let i = 0; i <= n; i++) points.push(String(round(i === n ? 1 : springAt(resolved, i / n * durationMs / 1e3))));
8013
+ return `linear(${points.join(", ")})`;
8014
+ }
8015
+ const { x1, y1, x2, y2 } = resolved;
8016
+ for (const [name, p] of Object.entries(CUBIC_BEZIER_PRESETS)) {
8017
+ if (["linear", "ease", "ease-in", "ease-out", "ease-in-out"].includes(name) && p[0] === x1 && p[1] === y1 && p[2] === x2 && p[3] === y2) {
8018
+ return name;
8019
+ }
8020
+ }
8021
+ return `cubic-bezier(${round(x1)}, ${round(y1)}, ${round(x2)}, ${round(y2)})`;
8022
+ }
8023
+ function easingLabel(easing) {
8024
+ if (easing === void 0 || easing === null) return ANIMATION_EASING_LABELS.linear;
8025
+ if (typeof easing === "string") return _nullishCoalesce(ANIMATION_EASING_LABELS[easing], () => ( easing));
8026
+ return easing.type === "spring" ? "Spring" : "Custom";
8027
+ }
8028
+
8029
+ // src/canvas/animation/color.ts
8030
+ var toLinear = (c) => c <= 0.04045 ? c / 12.92 : ((c + 0.055) / 1.055) ** 2.4;
8031
+ var toGamma = (c) => c <= 31308e-7 ? 12.92 * c : 1.055 * Math.sign(c) * Math.abs(c) ** (1 / 2.4) - 0.055;
8032
+ function rgbToOklab(r, g, b, alpha = 1) {
8033
+ const lr = toLinear(r);
8034
+ const lg = toLinear(g);
8035
+ const lb = toLinear(b);
8036
+ const l = Math.cbrt(0.4122214708 * lr + 0.5363325363 * lg + 0.0514459929 * lb);
8037
+ const m = Math.cbrt(0.2119034982 * lr + 0.6806995451 * lg + 0.1073969566 * lb);
8038
+ const s = Math.cbrt(0.0883024619 * lr + 0.2817188376 * lg + 0.6299787005 * lb);
8039
+ return {
8040
+ l: 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s,
8041
+ a: 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s,
8042
+ b: 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s,
8043
+ alpha
8044
+ };
8045
+ }
8046
+ function oklabToRgb(color) {
8047
+ const l_ = color.l + 0.3963377774 * color.a + 0.2158037573 * color.b;
8048
+ const m_ = color.l - 0.1055613458 * color.a - 0.0638541728 * color.b;
8049
+ const s_ = color.l - 0.0894841775 * color.a - 1.291485548 * color.b;
8050
+ const l = l_ ** 3;
8051
+ const m = m_ ** 3;
8052
+ const s = s_ ** 3;
8053
+ const clamp01 = (v) => Math.min(1, Math.max(0, v));
8054
+ return {
8055
+ r: clamp01(toGamma(4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s)),
8056
+ g: clamp01(toGamma(-1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s)),
8057
+ b: clamp01(toGamma(-0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s)),
8058
+ a: clamp01(color.alpha)
8059
+ };
8060
+ }
8061
+ function parseOklab(input) {
8062
+ const hex = _chunk4BVP64JJcjs.normalizeTokenColor.call(void 0, input);
8063
+ if (hex === null) return null;
8064
+ const c = _chunk4BVP64JJcjs.hexToRgba.call(void 0, hex);
8065
+ return rgbToOklab(c.r, c.g, c.b, c.a);
8066
+ }
8067
+ function formatOklab(color) {
8068
+ const { r, g, b, a } = oklabToRgb(color);
8069
+ return _chunk4BVP64JJcjs.rgbaToHex.call(void 0, r, g, b, a);
8070
+ }
8071
+ function mixColorsOklab(from, to, t) {
8072
+ const a = parseOklab(from);
8073
+ const b = parseOklab(to);
8074
+ if (!a || !b) return null;
8075
+ const alpha = a.alpha + (b.alpha - a.alpha) * t;
8076
+ const premul = (k) => a[k] * a.alpha + (b[k] * b.alpha - a[k] * a.alpha) * t;
8077
+ if (alpha <= 1e-9) return formatOklab({ l: a.l + (b.l - a.l) * t, a: 0, b: 0, alpha: 0 });
8078
+ return formatOklab({ l: premul("l") / alpha, a: premul("a") / alpha, b: premul("b") / alpha, alpha });
8079
+ }
8080
+
8081
+ // src/canvas/animation/model.ts
8082
+ var ANIMATION_DATA_KEY = "animation";
8083
+ var ANIMATION_TIME_EPSILON = 1e-6;
8084
+ var num = (value) => {
8085
+ if (typeof value === "number") return Number.isFinite(value) ? value : void 0;
8086
+ if (typeof value === "string") {
8087
+ const n = parseFloat(value);
8088
+ return Number.isFinite(n) ? n : void 0;
8089
+ }
8090
+ return void 0;
8091
+ };
8092
+ var tidy = (v) => Math.round(v * 1e4) / 1e4;
8093
+ function tokenBacked(key, label, type, extra = {}) {
8094
+ return {
8095
+ key,
8096
+ label,
8097
+ type,
8098
+ ...extra,
8099
+ read: (node) => {
8100
+ const p = getCanvasTokenProperty(key);
8101
+ const v = _optionalChain([p, 'optionalAccess', _200 => _200.appliesTo, 'call', _201 => _201(node)]) ? p.read(node) : void 0;
8102
+ return typeof v === "number" || typeof v === "string" ? v : void 0;
8103
+ },
8104
+ write: (node, value) => {
8105
+ const p = getCanvasTokenProperty(key);
8106
+ return _optionalChain([p, 'optionalAccess', _202 => _202.appliesTo, 'call', _203 => _203(node)]) ? p.write(node, value) : node;
8107
+ }
8108
+ };
8109
+ }
8110
+ function sizeProperty(key, label) {
8111
+ return {
8112
+ key,
8113
+ label,
8114
+ type: "number",
8115
+ min: 0,
8116
+ unit: "px",
8117
+ read: (node) => _nullishCoalesce(_nullishCoalesce(num(node[key]), () => ( readStyleSize(node.style)[key])), () => ( num(_optionalChain([node, 'access', _204 => _204.measured, 'optionalAccess', _205 => _205[key]])))),
8118
+ write: (node, value) => {
8119
+ const v = tidy(Math.max(0, value));
8120
+ return { ...node, [key]: v, style: withStyleSize(node.style, { [key]: v }) };
8121
+ }
8122
+ };
8123
+ }
8124
+ function motionPathPoint(node, progress) {
8125
+ const path = _optionalChain([getNodeAnimation, 'call', _206 => _206(node), 'optionalAccess', _207 => _207.motionPath]);
8126
+ if (!path || typeof path.d !== "string") return null;
8127
+ try {
8128
+ const length = bezierPathLength(path.d);
8129
+ return bezierPathPointAtLength(path.d, Math.min(1, Math.max(0, progress)) * length);
8130
+ } catch (e9) {
8131
+ return null;
8132
+ }
8133
+ }
8134
+ var ANIMATABLE_PROPERTIES = [
8135
+ {
8136
+ key: "x",
8137
+ label: "X",
8138
+ type: "number",
8139
+ unit: "px",
8140
+ read: (node) => num(_optionalChain([node, 'access', _208 => _208.position, 'optionalAccess', _209 => _209.x])),
8141
+ write: (node, value) => ({ ...node, position: { ...node.position, x: tidy(value) } })
8142
+ },
8143
+ {
8144
+ key: "y",
8145
+ label: "Y",
8146
+ type: "number",
8147
+ unit: "px",
8148
+ read: (node) => num(_optionalChain([node, 'access', _210 => _210.position, 'optionalAccess', _211 => _211.y])),
8149
+ write: (node, value) => ({ ...node, position: { ...node.position, y: tidy(value) } })
8150
+ },
8151
+ sizeProperty("width", "Width"),
8152
+ sizeProperty("height", "Height"),
8153
+ {
8154
+ key: "rotation",
8155
+ label: "Rotation",
8156
+ type: "number",
8157
+ unit: "\xB0",
8158
+ read: (node) => _nullishCoalesce(num(readNodeStyleProperty(node.style, "rotate")), () => ( 0)),
8159
+ write: (node, value) => ({
8160
+ ...node,
8161
+ style: writeNodeStyleProperty(node.style, "rotate", `${tidy(value)}deg`)
8162
+ })
8163
+ },
8164
+ {
8165
+ key: "scale",
8166
+ label: "Scale",
8167
+ type: "number",
8168
+ min: 0,
8169
+ read: (node) => _nullishCoalesce(num(readNodeStyleProperty(node.style, "scale")), () => ( 1)),
8170
+ write: (node, value) => ({
8171
+ ...node,
8172
+ style: writeNodeStyleProperty(_nullishCoalesce(node.style, () => ( {})), "scale", tidy(Math.max(0, value)), true)
8173
+ })
8174
+ },
8175
+ {
8176
+ key: "opacity",
8177
+ label: "Opacity",
8178
+ type: "number",
8179
+ min: 0,
8180
+ max: 1,
8181
+ read: (node) => _nullishCoalesce(num(readNodeStyleProperty(node.style, "opacity")), () => ( 1)),
8182
+ write: (node, value) => ({
8183
+ ...node,
8184
+ style: withStyleOpacity(node.style, tidy(Math.min(1, Math.max(0, value))), typeof node.style === "string" ? "string" : "object")
8185
+ })
8186
+ },
8187
+ tokenBacked("fill", "Fill", "color"),
8188
+ tokenBacked("stroke", "Stroke", "color"),
8189
+ tokenBacked("strokeWidth", "Stroke width", "number", { min: 0, unit: "px" }),
8190
+ tokenBacked("cornerRadius", "Corner radius", "number", { min: 0, unit: "px" }),
8191
+ {
8192
+ key: "motionPath",
8193
+ label: "Motion path",
8194
+ type: "number",
8195
+ min: 0,
8196
+ max: 1,
8197
+ read: () => void 0,
8198
+ write: (node, value) => {
8199
+ const at = motionPathPoint(node, value);
8200
+ if (!at) return node;
8201
+ const { width, height } = getNodeSize(node);
8202
+ let next = {
8203
+ ...node,
8204
+ position: { x: tidy(at.point[0] - width / 2), y: tidy(at.point[1] - height / 2) }
8205
+ };
8206
+ if (_optionalChain([getNodeAnimation, 'call', _212 => _212(node), 'optionalAccess', _213 => _213.motionPath, 'optionalAccess', _214 => _214.autoRotate])) {
8207
+ const base = _nullishCoalesce(num(readNodeStyleProperty(node.style, "rotate")), () => ( 0));
8208
+ next = { ...next, style: writeNodeStyleProperty(next.style, "rotate", `${tidy(base + at.angle * 180 / Math.PI)}deg`) };
8209
+ }
8210
+ return next;
8211
+ }
8212
+ }
8213
+ ];
8214
+ function getAnimatableProperty(key, options = {}) {
8215
+ return (_nullishCoalesce(options.properties, () => ( ANIMATABLE_PROPERTIES))).find((p) => p.key === key);
8216
+ }
8217
+ function clampAnimationValue(property, value) {
8218
+ if (!property || typeof value !== "number") return value;
8219
+ let v = value;
8220
+ if (property.min !== void 0) v = Math.max(property.min, v);
8221
+ if (property.max !== void 0) v = Math.min(property.max, v);
8222
+ return v;
8223
+ }
8224
+ function isValue(value) {
8225
+ return typeof value === "number" && Number.isFinite(value) || typeof value === "string";
8226
+ }
8227
+ function isAnimationKeyframe(value) {
8228
+ if (typeof value !== "object" || value === null) return false;
8229
+ const k = value;
8230
+ return typeof k.time === "number" && Number.isFinite(k.time) && isValue(k.value) && (k.easing === void 0 || isAnimationEasing(k.easing));
8231
+ }
8232
+ var sortedCache = /* @__PURE__ */ new WeakMap();
8233
+ function normalizeKeyframes(keyframes) {
8234
+ if (!Array.isArray(keyframes)) return [];
8235
+ const cached = sortedCache.get(keyframes);
8236
+ if (cached && cached.items.length === keyframes.length && cached.items.every((k, i) => k === keyframes[i])) return cached.out;
8237
+ const indexed = keyframes.map((k, i) => ({ k, i })).filter(({ k }) => isAnimationKeyframe(k)).sort((a, b) => a.k.time - b.k.time || a.i - b.i);
8238
+ const out = [];
8239
+ let lastIndex = -1;
8240
+ for (const { k, i } of indexed) {
8241
+ const prev = out[out.length - 1];
8242
+ if (prev && Math.abs(k.time - prev.time) <= ANIMATION_TIME_EPSILON) {
8243
+ if (i > lastIndex) {
8244
+ out[out.length - 1] = k;
8245
+ lastIndex = i;
8246
+ }
8247
+ continue;
8248
+ }
8249
+ out.push(k);
8250
+ lastIndex = i;
8251
+ }
8252
+ sortedCache.set(keyframes, { items: [...keyframes], out });
8253
+ return out;
8254
+ }
8255
+ function getNodeAnimation(node) {
8256
+ const raw = _optionalChain([node, 'optionalAccess', _215 => _215.data, 'optionalAccess', _216 => _216[ANIMATION_DATA_KEY]]);
8257
+ if (typeof raw !== "object" || raw === null || typeof raw.tracks !== "object" || raw.tracks === null) return null;
8258
+ return raw;
8259
+ }
8260
+ function getAnimationTrack(node, property) {
8261
+ const track = _optionalChain([getNodeAnimation, 'call', _217 => _217(node), 'optionalAccess', _218 => _218.tracks, 'access', _219 => _219[property]]);
8262
+ return track && Array.isArray(track.keyframes) && normalizeKeyframes(track.keyframes).length > 0 ? track : void 0;
8263
+ }
8264
+ function isNodeAnimated(node) {
8265
+ const animation = getNodeAnimation(node);
8266
+ if (!animation) return false;
8267
+ return Object.keys(animation.tracks).some((key) => getAnimationTrack(node, key) !== void 0);
8268
+ }
8269
+ function getAnimatedProperties(node, options = {}) {
8270
+ const animation = getNodeAnimation(node);
8271
+ if (!animation) return [];
8272
+ const keys = Object.keys(animation.tracks).filter((k) => getAnimationTrack(node, k));
8273
+ const order = (_nullishCoalesce(options.properties, () => ( ANIMATABLE_PROPERTIES))).map((p) => p.key);
8274
+ const rank = (k) => order.includes(k) ? order.indexOf(k) : order.length;
8275
+ return keys.sort((a, b) => rank(a) - rank(b) || a.localeCompare(b));
8276
+ }
8277
+ function withNodeAnimation(node, animation) {
8278
+ const tracks = {};
8279
+ if (animation) {
8280
+ for (const [key, track] of Object.entries(animation.tracks)) {
8281
+ if (track && Array.isArray(track.keyframes) && track.keyframes.length > 0) tracks[key] = track;
8282
+ }
8283
+ }
8284
+ const data = { ..._nullishCoalesce(node.data, () => ( {})) };
8285
+ if (Object.keys(tracks).length === 0 && !_optionalChain([animation, 'optionalAccess', _220 => _220.motionPath])) delete data[ANIMATION_DATA_KEY];
8286
+ else data[ANIMATION_DATA_KEY] = { ...animation, tracks };
8287
+ return { ...node, data };
8288
+ }
8289
+
8290
+ // src/canvas/animation/evaluate.ts
8291
+ var nodesOf = (doc) => Array.isArray(doc) ? doc : doc.nodes;
8292
+ function interpolateAnimationValue(from, to, t, type = "number") {
8293
+ if (typeof from === "number" && typeof to === "number") return from + (to - from) * t;
8294
+ if (t <= 0) return from;
8295
+ if (t >= 1) return to;
8296
+ if (type === "color" || typeof from === "string" && typeof to === "string") {
8297
+ const mixed = mixColorsOklab(from, to, t);
8298
+ if (mixed !== null) return mixed;
8299
+ }
8300
+ return from;
8301
+ }
8302
+ function segmentIndex(keys, time) {
8303
+ let lo = 0;
8304
+ let hi = keys.length - 1;
8305
+ let found = -1;
8306
+ while (lo <= hi) {
8307
+ const mid = lo + hi >> 1;
8308
+ if (keys[mid].time <= time) {
8309
+ found = mid;
8310
+ lo = mid + 1;
8311
+ } else hi = mid - 1;
8312
+ }
8313
+ return found;
8314
+ }
8315
+ function evaluateTrack(track, time, type = "number") {
8316
+ const keyframes = Array.isArray(track) ? track : _optionalChain([track, 'optionalAccess', _221 => _221.keyframes]);
8317
+ const keys = normalizeKeyframes(keyframes);
8318
+ if (keys.length === 0) return void 0;
8319
+ if (!(time > keys[0].time)) return keys[0].value;
8320
+ const last = keys[keys.length - 1];
8321
+ if (time >= last.time) return last.value;
8322
+ const i = segmentIndex(keys, time);
8323
+ const a = keys[i];
8324
+ const b = keys[i + 1];
8325
+ if (time === a.time) return a.value;
8326
+ const span = b.time - a.time;
8327
+ const u = (time - a.time) / span;
8328
+ if (a.easing === "hold") return a.value;
8329
+ return interpolateAnimationValue(a.value, b.value, evaluateEasing(a.easing, u, span), type);
8330
+ }
8331
+ function getAnimationDuration(doc) {
8332
+ let end = 0;
8333
+ for (const node of nodesOf(doc)) {
8334
+ const animation = getNodeAnimation(node);
8335
+ if (!animation) continue;
8336
+ for (const track of Object.values(animation.tracks)) {
8337
+ if (!track || track.enabled === false) continue;
8338
+ const keys = normalizeKeyframes(track.keyframes);
8339
+ if (keys.length > 0) end = Math.max(end, keys[keys.length - 1].time);
8340
+ }
8341
+ }
8342
+ return end;
8343
+ }
8344
+ function wrapAnimationTime(time, duration, loop = "none") {
8345
+ if (!Number.isFinite(time)) return 0;
8346
+ if (!(duration > 0)) return 0;
8347
+ if (loop === "loop") return (time % duration + duration) % duration;
8348
+ if (loop === "ping-pong") {
8349
+ const period = duration * 2;
8350
+ const m = (time % period + period) % period;
8351
+ return m <= duration ? m : period - m;
8352
+ }
8353
+ return Math.min(duration, Math.max(0, time));
8354
+ }
8355
+ function evaluateAnimation(doc, time, options = {}) {
8356
+ const only = options.ids ? new Set(options.ids) : null;
8357
+ const out = {};
8358
+ for (const node of nodesOf(doc)) {
8359
+ if (only && !only.has(node.id)) continue;
8360
+ const animation = getNodeAnimation(node);
8361
+ if (!animation) continue;
8362
+ let values;
8363
+ for (const [key, track] of Object.entries(animation.tracks)) {
8364
+ if (!track || track.enabled === false) continue;
8365
+ const property = (_nullishCoalesce(options.properties, () => ( ANIMATABLE_PROPERTIES))).find((p) => p.key === key);
8366
+ const value = evaluateTrack(track, time, _nullishCoalesce(_optionalChain([property, 'optionalAccess', _222 => _222.type]), () => ( "number")));
8367
+ if (value === void 0) continue;
8368
+ (values ??= {})[key] = clampAnimationValue(property, value);
8369
+ }
8370
+ if (values) out[node.id] = values;
8371
+ }
8372
+ return out;
8373
+ }
8374
+ function applyAnimationOverrides(nodes, overrides, options = {}) {
8375
+ const properties = _nullishCoalesce(options.properties, () => ( ANIMATABLE_PROPERTIES));
8376
+ let changed = false;
8377
+ const out = nodes.map((node) => {
8378
+ const values = overrides[node.id];
8379
+ if (!values) return node;
8380
+ let next = node;
8381
+ for (const property of properties) {
8382
+ if (!(property.key in values)) continue;
8383
+ next = property.write(next, values[property.key]);
8384
+ }
8385
+ if (next !== node) changed = true;
8386
+ return next;
8387
+ });
8388
+ return changed ? out : nodes;
8389
+ }
8390
+ function applyAnimation(nodes, time, options = {}) {
8391
+ return applyAnimationOverrides(nodes, evaluateAnimation(nodes, time, options), options);
8392
+ }
8393
+
8394
+ // src/canvas/animation/edit.ts
8395
+ var AnimationEditError = class extends Error {
8396
+
8397
+ constructor(code, message) {
8398
+ super(message);
8399
+ this.name = "AnimationEditError";
8400
+ this.code = code;
8401
+ }
8402
+ };
8403
+ var MAX_KEYFRAME_REFS = 4096;
8404
+ var sameTime = (a, b) => Math.abs(a - b) <= ANIMATION_TIME_EPSILON;
8405
+ var refKey = (r) => `${r.nodeId}\0${r.property}`;
8406
+ function snapTimeToFrame(time, fps) {
8407
+ if (!(fps > 0)) return time;
8408
+ const frame = 1e3 / fps;
8409
+ return Math.round(Math.round(time / frame) * frame * 1e3) / 1e3;
8410
+ }
8411
+ function coerceValue(property, value) {
8412
+ const type = _nullishCoalesce(_optionalChain([property, 'optionalAccess', _223 => _223.type]), () => ( (typeof value === "string" && _chunk4BVP64JJcjs.normalizeTokenColor.call(void 0, value) !== null ? "color" : "number")));
8413
+ if (type === "color") {
8414
+ const color = _chunk4BVP64JJcjs.normalizeTokenColor.call(void 0, value);
8415
+ if (color === null) throw new AnimationEditError("invalid_value", `"${String(value)}" is not a colour.`);
8416
+ return color;
8417
+ }
8418
+ const n = typeof value === "string" && value.trim() !== "" ? Number(value) : value;
8419
+ if (typeof n !== "number" || !Number.isFinite(n)) throw new AnimationEditError("invalid_value", `"${String(value)}" is not a number.`);
8420
+ return clampAnimationValue(property, n);
8421
+ }
8422
+ function coerceEasing(easing) {
8423
+ if (typeof easing === "string") {
8424
+ const parsed = parseCssEasing(easing);
8425
+ if (parsed) return parsed;
8426
+ } else if (isAnimationEasing(easing)) return easing;
8427
+ throw new AnimationEditError("invalid_easing", `Unknown easing ${JSON.stringify(easing)}.`);
8428
+ }
8429
+ function coerceTime(time) {
8430
+ if (typeof time !== "number" || !Number.isFinite(time)) throw new AnimationEditError("invalid_time", `Invalid time ${String(time)}.`);
8431
+ return Math.max(0, time);
8432
+ }
8433
+ var Draft = (_class8 = class {
8434
+ constructor(nodes, options = {}) {;_class8.prototype.__init20.call(this);_class8.prototype.__init21.call(this);
8435
+ this.nodes = nodes;
8436
+ this.options = options;
8437
+ this.byId = new Map(nodes.map((n) => [n.id, n]));
8438
+ }
8439
+
8440
+
8441
+
8442
+ __init20() {this.animations = /* @__PURE__ */ new Map()}
8443
+ __init21() {this.nodeWrites = /* @__PURE__ */ new Map()}
8444
+ node(id) {
8445
+ const node = _nullishCoalesce(this.nodeWrites.get(id), () => ( this.byId.get(id)));
8446
+ if (!node) throw new AnimationEditError("unknown_node", `Node "${id}" does not exist.`);
8447
+ return node;
8448
+ }
8449
+ has(id) {
8450
+ return this.byId.has(id);
8451
+ }
8452
+ animation(id) {
8453
+ let animation = this.animations.get(id);
8454
+ if (!animation) {
8455
+ const current = getNodeAnimation(this.node(id));
8456
+ const tracks = {};
8457
+ for (const [key, track] of Object.entries(_nullishCoalesce(_optionalChain([current, 'optionalAccess', _224 => _224.tracks]), () => ( {})))) {
8458
+ if (track) tracks[key] = { ...track, keyframes: normalizeKeyframes(track.keyframes) };
8459
+ }
8460
+ animation = { ..._nullishCoalesce(current, () => ( {})), tracks };
8461
+ this.animations.set(id, animation);
8462
+ }
8463
+ return animation;
8464
+ }
8465
+ keys(id, property) {
8466
+ return _nullishCoalesce(_optionalChain([this, 'access', _225 => _225.animation, 'call', _226 => _226(id), 'access', _227 => _227.tracks, 'access', _228 => _228[property], 'optionalAccess', _229 => _229.keyframes]), () => ( []));
8467
+ }
8468
+ track(id, property) {
8469
+ return this.animation(id).tracks[property];
8470
+ }
8471
+ setKeys(id, property, keyframes) {
8472
+ const animation = this.animation(id);
8473
+ const sorted = [...keyframes].sort((a, b) => a.time - b.time);
8474
+ if (sorted.length === 0) delete animation.tracks[property];
8475
+ else animation.tracks[property] = { ..._nullishCoalesce(animation.tracks[property], () => ( {})), keyframes: sorted };
8476
+ }
8477
+ setMotionPath(id, motionPath) {
8478
+ const animation = this.animation(id);
8479
+ if (motionPath) animation.motionPath = { ...motionPath };
8480
+ else delete animation.motionPath;
8481
+ }
8482
+ writeNode(id, fn) {
8483
+ this.nodeWrites.set(id, fn(this.node(id)));
8484
+ }
8485
+ find(ref) {
8486
+ const keys = this.keys(ref.nodeId, ref.property);
8487
+ return keys.findIndex((k) => sameTime(k.time, ref.time));
8488
+ }
8489
+ property(key) {
8490
+ return getAnimatableProperty(key, this.options);
8491
+ }
8492
+ commit() {
8493
+ if (this.animations.size === 0 && this.nodeWrites.size === 0) return this.nodes;
8494
+ return this.nodes.map((node) => {
8495
+ const written = this.nodeWrites.get(node.id);
8496
+ const animation = this.animations.get(node.id);
8497
+ if (!written && !animation) return node;
8498
+ const base = _nullishCoalesce(written, () => ( node));
8499
+ return animation ? withNodeAnimation(base, animation) : base;
8500
+ });
8501
+ }
8502
+ }, _class8);
8503
+ function validateRefs(draft, refs, allowEmpty = false) {
8504
+ if (!Array.isArray(refs) || !allowEmpty && refs.length === 0) throw new AnimationEditError("unknown_keyframe", "Name at least one keyframe.");
8505
+ if (refs.length > MAX_KEYFRAME_REFS) throw new AnimationEditError("too_many_keyframes", `At most ${MAX_KEYFRAME_REFS} keyframes per edit.`);
8506
+ const seen = /* @__PURE__ */ new Map();
8507
+ for (const ref of refs) {
8508
+ if (!ref || typeof ref.nodeId !== "string" || typeof ref.property !== "string" || typeof ref.time !== "number" || !Number.isFinite(ref.time)) {
8509
+ throw new AnimationEditError("unknown_keyframe", "Invalid keyframe reference.");
8510
+ }
8511
+ draft.node(ref.nodeId);
8512
+ if (draft.find(ref) === -1) throw new AnimationEditError("unknown_keyframe", `No ${ref.property} keyframe at ${ref.time}ms on "${ref.nodeId}".`);
8513
+ const times = _nullishCoalesce(seen.get(refKey(ref)), () => ( []));
8514
+ if (times.some((t) => sameTime(t, ref.time))) throw new AnimationEditError("duplicate_keyframe", "A keyframe is named twice.");
8515
+ times.push(ref.time);
8516
+ seen.set(refKey(ref), times);
8517
+ }
8518
+ }
8519
+ function readAnimatableValue(node, property) {
8520
+ const value = property.read(node);
8521
+ if (value !== void 0) return value;
8522
+ if (property.key === "width" || property.key === "height") return getNodeSize(node)[property.key];
8523
+ return void 0;
8524
+ }
8525
+ function getAnimatedValue(node, propertyKey, time, options = {}) {
8526
+ const property = getAnimatableProperty(propertyKey, options);
8527
+ const track = getAnimationTrack(node, propertyKey);
8528
+ if (track && track.enabled !== false) return evaluateTrack(track, time, _nullishCoalesce(_optionalChain([property, 'optionalAccess', _230 => _230.type]), () => ( "number")));
8529
+ return property ? readAnimatableValue(node, property) : void 0;
8530
+ }
8531
+ function putKey(draft, nodeId, property, time, value, easing, inherit = true) {
8532
+ const keys = [...draft.keys(nodeId, property)];
8533
+ const at = keys.findIndex((k) => sameTime(k.time, time));
8534
+ if (at >= 0) {
8535
+ keys[at] = { ...keys[at], value, ...easing !== void 0 ? { easing } : {} };
8536
+ } else {
8537
+ const before = [...keys].reverse().find((k) => k.time < time);
8538
+ const inherited = _nullishCoalesce(easing, () => ( (inherit ? _optionalChain([before, 'optionalAccess', _231 => _231.easing]) : void 0)));
8539
+ keys.push({ time, value, ...inherited !== void 0 ? { easing: inherited } : {} });
8540
+ }
8541
+ draft.setKeys(nodeId, property, keys);
8542
+ }
8543
+ function setKeyframe(nodes, nodeId, property, time, value, options = {}) {
8544
+ const draft = new Draft(nodes, options);
8545
+ draft.node(nodeId);
8546
+ const p = draft.property(property);
8547
+ if (!p) throw new AnimationEditError("unknown_property", `"${property}" cannot be animated.`);
8548
+ putKey(draft, nodeId, property, coerceTime(time), coerceValue(p, value), options.easing === void 0 ? void 0 : coerceEasing(options.easing));
8549
+ return draft.commit();
8550
+ }
8551
+ function addKeyframesAtTime(nodes, ids, time, options = {}) {
8552
+ const draft = new Draft(nodes, options);
8553
+ const t = coerceTime(time);
8554
+ const refs = [];
8555
+ for (const id of ids) {
8556
+ const node = draft.node(id);
8557
+ const animated = Object.keys(draft.animation(id).tracks);
8558
+ const keys = _nullishCoalesce(options.keys, () => ( (animated.length > 0 ? animated : ["x", "y"])));
8559
+ for (const key of keys) {
8560
+ const p = draft.property(key);
8561
+ if (!p) throw new AnimationEditError("unknown_property", `"${key}" cannot be animated.`);
8562
+ const value = getAnimatedValue(node, key, t, options);
8563
+ if (value === void 0) continue;
8564
+ putKey(draft, id, key, t, value);
8565
+ refs.push({ nodeId: id, property: key, time: t });
8566
+ }
8567
+ }
8568
+ return { nodes: draft.commit(), refs };
8569
+ }
8570
+ function updateKeyframe(nodes, ref, patch, options = {}) {
8571
+ const draft = new Draft(nodes, options);
8572
+ validateRefs(draft, [ref]);
8573
+ const keys = [...draft.keys(ref.nodeId, ref.property)];
8574
+ const i = keys.findIndex((k) => sameTime(k.time, ref.time));
8575
+ const next = { ...keys[i] };
8576
+ if (patch.value !== void 0) next.value = coerceValue(draft.property(ref.property), patch.value);
8577
+ if (patch.easing === null) delete next.easing;
8578
+ else if (patch.easing !== void 0) next.easing = coerceEasing(patch.easing);
8579
+ if (patch.time !== void 0) next.time = coerceTime(patch.time);
8580
+ keys.splice(i, 1);
8581
+ const rest = keys.filter((k) => !sameTime(k.time, next.time));
8582
+ draft.setKeys(ref.nodeId, ref.property, [...rest, next]);
8583
+ return draft.commit();
8584
+ }
8585
+ function setKeyframeEasing(nodes, refs, easing, options = {}) {
8586
+ const draft = new Draft(nodes, options);
8587
+ validateRefs(draft, refs);
8588
+ const value = easing === null ? null : coerceEasing(easing);
8589
+ for (const ref of refs) {
8590
+ const keys = draft.keys(ref.nodeId, ref.property).map((k) => {
8591
+ if (!sameTime(k.time, ref.time)) return k;
8592
+ const { easing: _old, ...rest } = k;
8593
+ return value === null ? rest : { ...rest, easing: value };
8594
+ });
8595
+ draft.setKeys(ref.nodeId, ref.property, keys);
8596
+ }
8597
+ return draft.commit();
8598
+ }
8599
+ function deleteKeyframes(nodes, refs, options = {}) {
8600
+ const draft = new Draft(nodes, options);
8601
+ validateRefs(draft, refs);
8602
+ const lanes = /* @__PURE__ */ new Map();
8603
+ for (const ref of refs) lanes.set(refKey(ref), [..._nullishCoalesce(lanes.get(refKey(ref)), () => ( [])), ref]);
8604
+ for (const lane of lanes.values()) {
8605
+ const { nodeId, property } = lane[0];
8606
+ const keys = draft.keys(nodeId, property);
8607
+ const left = keys.filter((k) => !lane.some((r) => sameTime(r.time, k.time)));
8608
+ if (left.length === 0) {
8609
+ const p = draft.property(property);
8610
+ const last = _nullishCoalesce(keys.find((k) => sameTime(k.time, lane[lane.length - 1].time)), () => ( keys[keys.length - 1]));
8611
+ if (p && property !== "motionPath") draft.writeNode(nodeId, (n) => p.write(n, last.value));
8612
+ }
8613
+ draft.setKeys(nodeId, property, left);
8614
+ }
8615
+ return draft.commit();
8616
+ }
8617
+ function setTrackEnabled(nodes, nodeId, property, enabled) {
8618
+ const draft = new Draft(nodes);
8619
+ if (!draft.track(nodeId, property)) throw new AnimationEditError("unknown_property", `"${nodeId}" has no ${property} track.`);
8620
+ const { enabled: _was, ...track } = draft.track(nodeId, property);
8621
+ draft.animation(nodeId).tracks[property] = enabled ? track : { ...track, enabled: false };
8622
+ return draft.commit();
8623
+ }
8624
+ function removeTrack(nodes, nodeId, property, options = {}) {
8625
+ const draft = new Draft(nodes, options);
8626
+ const track = draft.track(nodeId, property);
8627
+ if (!track) return nodes;
8628
+ const p = draft.property(property);
8629
+ if (options.keepValueAt !== void 0 && p && property !== "motionPath") {
8630
+ const value = evaluateTrack(track, options.keepValueAt, p.type);
8631
+ if (value !== void 0) draft.writeNode(nodeId, (n) => p.write(n, value));
8632
+ }
8633
+ draft.setKeys(nodeId, property, []);
8634
+ if (property === "motionPath") draft.setMotionPath(nodeId, void 0);
8635
+ return draft.commit();
8636
+ }
8637
+ function setMotionPath(nodes, nodeId, motionPath) {
8638
+ const draft = new Draft(nodes);
8639
+ draft.node(nodeId);
8640
+ if (motionPath && (typeof motionPath.d !== "string" || motionPath.d.trim() === "")) {
8641
+ throw new AnimationEditError("invalid_value", "A motion path needs SVG path data.");
8642
+ }
8643
+ draft.setMotionPath(nodeId, _nullishCoalesce(motionPath, () => ( void 0)));
8644
+ return draft.commit();
8645
+ }
8646
+ function moveKeyframes(nodes, refs, delta, options = {}) {
8647
+ if (typeof delta !== "number" || Number.isNaN(delta)) throw new AnimationEditError("invalid_time", "The delta must be a number.");
8648
+ const draft = new Draft(nodes);
8649
+ validateRefs(draft, refs);
8650
+ const min = _nullishCoalesce(options.min, () => ( 0));
8651
+ const max = _nullishCoalesce(options.max, () => ( Infinity));
8652
+ let low = -Infinity;
8653
+ let high = Infinity;
8654
+ for (const ref of refs) {
8655
+ const time = draft.keys(ref.nodeId, ref.property)[draft.find(ref)].time;
8656
+ low = Math.max(low, min - time);
8657
+ high = Math.min(high, max - time);
8658
+ }
8659
+ if (low > high + ANIMATION_TIME_EPSILON) throw new AnimationEditError("no_movement_range", "The keyframes have no common movement range.");
8660
+ const applied = Math.min(high, Math.max(low, delta));
8661
+ const moved = refs.map((ref) => ({ ...ref, time: draft.keys(ref.nodeId, ref.property)[draft.find(ref)].time + applied }));
8662
+ if (Math.abs(applied) <= ANIMATION_TIME_EPSILON) return { nodes, delta: 0, refs: refs.map((r) => ({ ...r })) };
8663
+ retime(draft, refs, (time) => time + applied);
8664
+ return { nodes: draft.commit(), delta: applied, refs: moved };
8665
+ }
8666
+ function retime(draft, refs, map) {
8667
+ const lanes = /* @__PURE__ */ new Map();
8668
+ for (const ref of refs) lanes.set(refKey(ref), [..._nullishCoalesce(lanes.get(refKey(ref)), () => ( [])), ref]);
8669
+ for (const lane of lanes.values()) {
8670
+ const { nodeId, property } = lane[0];
8671
+ const keys = draft.keys(nodeId, property);
8672
+ const picked = keys.filter((k) => lane.some((r) => sameTime(r.time, k.time)));
8673
+ const movedKeys = picked.map((k) => ({ ...k, time: map(k.time) }));
8674
+ const rest = keys.filter((k) => !picked.includes(k) && !movedKeys.some((m) => sameTime(m.time, k.time)));
8675
+ draft.setKeys(nodeId, property, [...rest, ...movedKeys]);
8676
+ }
8677
+ }
8678
+ function scaleKeyframes(nodes, refs, factor, options = {}) {
8679
+ if (typeof factor !== "number" || !Number.isFinite(factor) || factor <= 0) throw new AnimationEditError("invalid_factor", "The scale factor must be a positive number.");
8680
+ const draft = new Draft(nodes);
8681
+ validateRefs(draft, refs);
8682
+ const times = refs.map((ref) => draft.keys(ref.nodeId, ref.property)[draft.find(ref)].time);
8683
+ const pivot = _nullishCoalesce(options.pivot, () => ( Math.min(...times)));
8684
+ const min = _nullishCoalesce(options.min, () => ( 0));
8685
+ const max = _nullishCoalesce(options.max, () => ( Infinity));
8686
+ let applied = factor;
8687
+ for (const t of times) {
8688
+ if (t > pivot && Number.isFinite(max)) applied = Math.min(applied, (max - pivot) / (t - pivot));
8689
+ if (t < pivot) applied = Math.min(applied, (pivot - min) / (pivot - t));
8690
+ }
8691
+ applied = Math.max(applied, Number.EPSILON);
8692
+ const map = (t) => pivot + (t - pivot) * applied;
8693
+ if (Math.abs(applied - 1) <= 1e-12) return { nodes, factor: 1, refs: refs.map((r) => ({ ...r })) };
8694
+ retime(draft, refs, map);
8695
+ return { nodes: draft.commit(), factor: applied, refs: refs.map((r, i) => ({ ...r, time: map(times[i]) })) };
8696
+ }
8697
+ function getKeyframeTimes(nodes, options = {}) {
8698
+ const only = options.ids ? new Set(options.ids) : null;
8699
+ const excluded = /* @__PURE__ */ new Map();
8700
+ for (const ref of _nullishCoalesce(options.exclude, () => ( []))) excluded.set(refKey(ref), [..._nullishCoalesce(excluded.get(refKey(ref)), () => ( [])), ref.time]);
8701
+ const times = [];
8702
+ for (const node of nodes) {
8703
+ if (only && !only.has(node.id)) continue;
8704
+ const animation = getNodeAnimation(node);
8705
+ if (!animation) continue;
8706
+ for (const [property, track] of Object.entries(animation.tracks)) {
8707
+ const skip = _nullishCoalesce(excluded.get(refKey({ nodeId: node.id, property })), () => ( []));
8708
+ for (const k of normalizeKeyframes(_optionalChain([track, 'optionalAccess', _232 => _232.keyframes]))) if (!skip.some((t) => sameTime(t, k.time))) times.push(k.time);
8709
+ }
8710
+ }
8711
+ times.sort((a, b) => a - b);
8712
+ return times.filter((t, i) => i === 0 || !sameTime(t, times[i - 1]));
8713
+ }
8714
+ function snapKeyframeDelta(times, delta, targets, threshold) {
8715
+ const sorted = [...targets].filter(Number.isFinite).sort((a, b) => a - b);
8716
+ let best = null;
8717
+ for (const time of times) {
8718
+ const at = time + delta;
8719
+ let lo = 0;
8720
+ let hi = sorted.length;
8721
+ while (lo < hi) {
8722
+ const mid = lo + hi >> 1;
8723
+ if (sorted[mid] < at) lo = mid + 1;
8724
+ else hi = mid;
8725
+ }
8726
+ for (const i of [lo - 1, lo]) {
8727
+ const target = sorted[i];
8728
+ if (target === void 0) continue;
8729
+ const distance = Math.abs(target - at);
8730
+ if (distance <= threshold && (!best || distance < best.distance)) best = { distance, target, delta: delta + (target - at) };
8731
+ }
8732
+ }
8733
+ return best ? { delta: best.delta, target: best.target } : { delta, target: null };
8734
+ }
8735
+ function copyKeyframes(nodes, refs) {
8736
+ const draft = new Draft(nodes);
8737
+ validateRefs(draft, refs);
8738
+ const found = refs.map((ref) => ({ ref, key: draft.keys(ref.nodeId, ref.property)[draft.find(ref)] }));
8739
+ const start = Math.min(...found.map((f) => f.key.time));
8740
+ return {
8741
+ type: "pixerate/keyframes",
8742
+ version: 1,
8743
+ keyframes: found.map(({ ref, key }) => ({
8744
+ nodeId: ref.nodeId,
8745
+ property: ref.property,
8746
+ offset: key.time - start,
8747
+ value: key.value,
8748
+ ...key.easing !== void 0 ? { easing: key.easing } : {}
8749
+ }))
8750
+ };
8751
+ }
8752
+ function parseKeyframeClipboard(input) {
8753
+ let value = input;
8754
+ if (typeof input === "string") {
8755
+ if (input.length > 5e6) return null;
8756
+ try {
8757
+ value = JSON.parse(input);
8758
+ } catch (e10) {
8759
+ return null;
8760
+ }
8761
+ }
8762
+ if (typeof value !== "object" || value === null) return null;
8763
+ const clip = value;
8764
+ if (clip.type !== "pixerate/keyframes" || clip.version !== 1 || !Array.isArray(clip.keyframes)) return null;
8765
+ const keyframes = clip.keyframes.filter(
8766
+ (k) => k && typeof k.nodeId === "string" && typeof k.property === "string" && typeof k.offset === "number" && Number.isFinite(k.offset) && (typeof k.value === "number" && Number.isFinite(k.value) || typeof k.value === "string") && (k.easing === void 0 || isAnimationEasing(k.easing))
8767
+ );
8768
+ return keyframes.length > 0 ? { type: "pixerate/keyframes", version: 1, keyframes } : null;
8769
+ }
8770
+ function pasteKeyframes(nodes, clipboard, time, options = {}) {
8771
+ const draft = new Draft(nodes, options);
8772
+ const t = coerceTime(time);
8773
+ const sources = [...new Set(clipboard.keyframes.map((k) => k.nodeId))];
8774
+ const targetsOf = (source) => {
8775
+ if (!options.nodeIds || options.nodeIds.length === 0) return [source];
8776
+ if (sources.length === 1) return [...options.nodeIds];
8777
+ const i = sources.indexOf(source);
8778
+ return i < options.nodeIds.length ? [options.nodeIds[i]] : [];
8779
+ };
8780
+ const refs = [];
8781
+ for (const k of clipboard.keyframes) {
8782
+ const p = draft.property(k.property);
8783
+ if (!p) continue;
8784
+ for (const target of targetsOf(k.nodeId)) {
8785
+ if (!draft.has(target)) continue;
8786
+ let value;
8787
+ try {
8788
+ value = coerceValue(p, k.value);
8789
+ } catch (e11) {
8790
+ continue;
8791
+ }
8792
+ const at = t + Math.max(0, k.offset);
8793
+ putKey(draft, target, k.property, at, value, k.easing, false);
8794
+ refs.push({ nodeId: target, property: k.property, time: at });
8795
+ }
8796
+ }
8797
+ return { nodes: draft.commit(), refs };
8798
+ }
8799
+ var sameValue = (a, b) => typeof a === "number" && typeof b === "number" ? Math.abs(a - b) <= 1e-9 : a === b;
8800
+ function recordAnimationChanges(base, before, after, time, options = {}) {
8801
+ const properties = (_nullishCoalesce(options.properties, () => ( ANIMATABLE_PROPERTIES))).filter((p) => p.key !== "motionPath");
8802
+ const baseById = new Map(base.map((n) => [n.id, n]));
8803
+ const beforeById = new Map(before.map((n) => [n.id, n]));
8804
+ const t = coerceTime(time);
8805
+ const keyed = [];
8806
+ const out = after.map((next) => {
8807
+ const stored = baseById.get(next.id);
8808
+ const shown = beforeById.get(next.id);
8809
+ if (!stored) return next;
8810
+ if (shown === next) return stored;
8811
+ const animation = getNodeAnimation(stored);
8812
+ let result = next;
8813
+ let tracks = null;
8814
+ const tracksOf = () => tracks ??= { ..._nullishCoalesce(_optionalChain([animation, 'optionalAccess', _233 => _233.tracks]), () => ( {})) };
8815
+ for (const p of properties) {
8816
+ const track = getAnimationTrack(stored, p.key);
8817
+ const animated = !!track && track.enabled !== false;
8818
+ const now = p.read(next);
8819
+ const was = shown ? p.read(shown) : void 0;
8820
+ const changed = !!shown && now !== void 0 && !sameValue(now, was);
8821
+ const restore = () => {
8822
+ const value = p.read(stored);
8823
+ if (value !== void 0) result = p.write(result, value);
8824
+ };
8825
+ if (animated) {
8826
+ if (changed) {
8827
+ const keys = normalizeKeyframes(track.keyframes).filter((k) => !sameTime(k.time, t));
8828
+ const before2 = [...keys].reverse().find((k) => k.time < t);
8829
+ keys.push({ time: t, value: now, ..._optionalChain([before2, 'optionalAccess', _234 => _234.easing]) !== void 0 ? { easing: before2.easing } : {} });
8830
+ tracksOf()[p.key] = { ...track, keyframes: keys.sort((a, b) => a.time - b.time) };
8831
+ keyed.push({ nodeId: next.id, property: p.key, time: t });
8832
+ }
8833
+ restore();
8834
+ } else if (changed && options.recording && !track) {
8835
+ const keys = [];
8836
+ if (t > ANIMATION_TIME_EPSILON && was !== void 0) keys.push({ time: 0, value: was });
8837
+ keys.push({ time: t, value: now });
8838
+ tracksOf()[p.key] = { keyframes: keys };
8839
+ keyed.push({ nodeId: next.id, property: p.key, time: t });
8840
+ restore();
8841
+ }
8842
+ }
8843
+ if (tracks) result = withNodeAnimation(result, { ..._nullishCoalesce(animation, () => ( {})), tracks });
8844
+ return result;
8845
+ });
8846
+ return { nodes: out, keyed };
8847
+ }
8848
+ function animateNode(nodes, nodeId, options) {
8849
+ const draft = new Draft(nodes, options);
8850
+ const node = draft.node(nodeId);
8851
+ const start = coerceTime(_nullishCoalesce(options.delay, () => ( 0)));
8852
+ const duration = _nullishCoalesce(options.duration, () => ( 1e3));
8853
+ if (typeof duration !== "number" || !Number.isFinite(duration) || duration <= 0) throw new AnimationEditError("invalid_time", "The duration must be positive.");
8854
+ const easing = options.easing === void 0 ? void 0 : coerceEasing(options.easing);
8855
+ const entries = Object.entries(_nullishCoalesce(options.to, () => ( {})));
8856
+ if (entries.length === 0) throw new AnimationEditError("invalid_value", "Name at least one property to animate.");
8857
+ const refs = [];
8858
+ const writes = [];
8859
+ for (const [key, target] of entries) {
8860
+ const p = draft.property(key);
8861
+ if (!p || key === "motionPath" && !_optionalChain([getNodeAnimation, 'call', _235 => _235(node), 'optionalAccess', _236 => _236.motionPath])) {
8862
+ throw new AnimationEditError("unknown_property", `"${key}" cannot be animated${p ? " without a motion path" : ""}.`);
8863
+ }
8864
+ const from = _nullishCoalesce(_optionalChain([options, 'access', _237 => _237.from, 'optionalAccess', _238 => _238[key]]), () => ( (key === "motionPath" ? 0 : getAnimatedValue(node, key, start, options))));
8865
+ if (from === void 0) throw new AnimationEditError("invalid_value", `"${nodeId}" has no ${key} to animate from; pass "from".`);
8866
+ writes.push([key, coerceValue(p, from), coerceValue(p, target)]);
8867
+ }
8868
+ for (const [key, from, to] of writes) {
8869
+ putKey(draft, nodeId, key, start, from, easing);
8870
+ putKey(draft, nodeId, key, start + duration, to, void 0, false);
8871
+ refs.push({ nodeId, property: key, time: start }, { nodeId, property: key, time: start + duration });
8872
+ }
8873
+ return { nodes: draft.commit(), refs };
8874
+ }
8875
+
8876
+ // src/canvas/animation/player.ts
8877
+ var AnimationPlayer = (_class9 = class {
8878
+
8879
+
8880
+
8881
+
8882
+
8883
+ __init22() {this.playing = false}
8884
+ __init23() {this.scrubbing = false}
8885
+ __init24() {this.resumeAfterScrub = false}
8886
+
8887
+
8888
+ /** Unwrapped time at `anchorAt` (keeps the ping-pong direction across frames). */
8889
+ __init25() {this.anchorRaw = 0}
8890
+ __init26() {this.anchorAt = 0}
8891
+ __init27() {this.generation = 0}
8892
+
8893
+ __init28() {this.listeners = /* @__PURE__ */ new Set()}
8894
+ constructor(options = {}) {;_class9.prototype.__init22.call(this);_class9.prototype.__init23.call(this);_class9.prototype.__init24.call(this);_class9.prototype.__init25.call(this);_class9.prototype.__init26.call(this);_class9.prototype.__init27.call(this);_class9.prototype.__init28.call(this);
8895
+ this.clock = _nullishCoalesce(options.clock, () => ( realClock));
8896
+ this.durationSource = _nullishCoalesce(options.duration, () => ( 1e3));
8897
+ this.loop = _nullishCoalesce(options.loop, () => ( "none"));
8898
+ this.rate = Number.isFinite(options.playbackRate) && options.playbackRate !== 0 ? options.playbackRate : 1;
8899
+ this.onTime = options.onTime;
8900
+ this.onEnd = options.onEnd;
8901
+ this.time = this.clamp(_nullishCoalesce(options.time, () => ( 0)));
8902
+ this.cached = this.snapshot();
8903
+ }
8904
+ /** Current timeline length (ms). */
8905
+ get duration() {
8906
+ const d = typeof this.durationSource === "function" ? this.durationSource() : this.durationSource;
8907
+ return Number.isFinite(d) && d > 0 ? d : 0;
8908
+ }
8909
+ get currentTime() {
8910
+ return this.time;
8911
+ }
8912
+ get isPlaying() {
8913
+ return this.playing;
8914
+ }
8915
+ getState() {
8916
+ return this.cached;
8917
+ }
8918
+ subscribe(listener) {
8919
+ this.listeners.add(listener);
8920
+ return () => {
8921
+ this.listeners.delete(listener);
8922
+ };
8923
+ }
8924
+ /** Replaces the callbacks (hooks keep them current without recreating the player). */
8925
+ setCallbacks(callbacks) {
8926
+ this.onTime = callbacks.onTime;
8927
+ this.onEnd = callbacks.onEnd;
8928
+ }
8929
+ setDuration(duration) {
8930
+ this.durationSource = duration;
8931
+ this.time = this.clamp(this.time);
8932
+ this.emit(false);
8933
+ }
8934
+ setLoop(loop) {
8935
+ if (loop === this.loop) return;
8936
+ this.reanchor();
8937
+ this.loop = loop;
8938
+ this.emit(false);
8939
+ }
8940
+ setPlaybackRate(rate) {
8941
+ if (!Number.isFinite(rate) || rate === 0 || rate === this.rate) return;
8942
+ this.reanchor();
8943
+ this.rate = rate;
8944
+ this.emit(false);
8945
+ }
8946
+ /** Starts playing from the playhead (from the start again when a one-shot play had ended). */
8947
+ play() {
8948
+ if (this.playing) return;
8949
+ const d = this.duration;
8950
+ if (this.loop === "none" && d > 0) {
8951
+ if (this.rate > 0 && this.time >= d) this.time = 0;
8952
+ if (this.rate < 0 && this.time <= 0) this.time = d;
8953
+ }
8954
+ this.playing = true;
8955
+ this.scrubbing = false;
8956
+ this.anchorRaw = this.time;
8957
+ this.anchorAt = this.clock.now();
8958
+ this.emit(false);
8959
+ this.schedule();
8960
+ }
8961
+ pause() {
8962
+ if (!this.playing) return;
8963
+ this.tick(false);
8964
+ this.playing = false;
8965
+ this.generation++;
8966
+ this.emit(true);
8967
+ }
8968
+ toggle() {
8969
+ if (this.playing) this.pause();
8970
+ else this.play();
8971
+ }
8972
+ /** Pauses and returns to the start. */
8973
+ stop() {
8974
+ this.playing = false;
8975
+ this.generation++;
8976
+ this.seek(0);
8977
+ }
8978
+ /** Moves the playhead (clamped to the timeline); playback continues from there. */
8979
+ seek(time) {
8980
+ if (!Number.isFinite(time)) return;
8981
+ this.time = this.clamp(time);
8982
+ this.anchorRaw = this.time;
8983
+ this.anchorAt = this.clock.now();
8984
+ this.emit(true);
8985
+ }
8986
+ /** Seeks while dragging the playhead: playback pauses until `endScrub`. */
8987
+ scrub(time) {
8988
+ if (!this.scrubbing) {
8989
+ this.resumeAfterScrub = this.playing;
8990
+ if (this.playing) {
8991
+ this.playing = false;
8992
+ this.generation++;
8993
+ }
8994
+ this.scrubbing = true;
8995
+ }
8996
+ this.seek(time);
8997
+ }
8998
+ /** Ends a scrub, resuming playback if it was playing when the scrub began. */
8999
+ endScrub() {
9000
+ if (!this.scrubbing) return;
9001
+ this.scrubbing = false;
9002
+ const resume = this.resumeAfterScrub;
9003
+ this.resumeAfterScrub = false;
9004
+ if (resume) this.play();
9005
+ else this.emit(false);
9006
+ }
9007
+ /** Stops scheduling frames and drops listeners. */
9008
+ destroy() {
9009
+ this.playing = false;
9010
+ this.generation++;
9011
+ this.listeners.clear();
9012
+ }
9013
+ clamp(time) {
9014
+ return Math.min(this.duration, Math.max(0, Number.isFinite(time) ? time : 0));
9015
+ }
9016
+ reanchor() {
9017
+ if (!this.playing) return;
9018
+ this.tick(false);
9019
+ this.anchorRaw = this.rawNow();
9020
+ this.anchorAt = this.clock.now();
9021
+ }
9022
+ rawNow() {
9023
+ return this.anchorRaw + (this.clock.now() - this.anchorAt) * this.rate;
9024
+ }
9025
+ schedule() {
9026
+ const generation = this.generation;
9027
+ this.clock.frame().then(() => {
9028
+ if (generation !== this.generation || !this.playing) return;
9029
+ this.tick(true);
9030
+ if (this.playing) this.schedule();
9031
+ });
9032
+ }
9033
+ /** Advances the playhead to the clock's time; `notify` emits the change. */
9034
+ tick(notify) {
9035
+ if (!this.playing) return;
9036
+ const d = this.duration;
9037
+ const raw = this.rawNow();
9038
+ let ended = false;
9039
+ if (this.loop === "none" || d <= 0) {
9040
+ if (this.rate > 0 && raw >= d) {
9041
+ this.time = d;
9042
+ ended = true;
9043
+ } else if (this.rate < 0 && raw <= 0) {
9044
+ this.time = 0;
9045
+ ended = true;
9046
+ } else this.time = this.clamp(raw);
9047
+ } else {
9048
+ this.time = wrapAnimationTime(raw, d, this.loop);
9049
+ }
9050
+ if (ended) {
9051
+ this.playing = false;
9052
+ this.generation++;
9053
+ }
9054
+ if (notify || ended) this.emit(true);
9055
+ if (ended) _optionalChain([this, 'access', _239 => _239.onEnd, 'optionalCall', _240 => _240()]);
9056
+ }
9057
+ snapshot() {
9058
+ return {
9059
+ time: this.time,
9060
+ playing: this.playing,
9061
+ scrubbing: this.scrubbing,
9062
+ loop: this.loop,
9063
+ playbackRate: this.rate,
9064
+ duration: this.duration
9065
+ };
9066
+ }
9067
+ emit(timeChanged) {
9068
+ const next = this.snapshot();
9069
+ const prev = this.cached;
9070
+ if (prev.time === next.time && prev.playing === next.playing && prev.scrubbing === next.scrubbing && prev.loop === next.loop && prev.playbackRate === next.playbackRate && prev.duration === next.duration) {
9071
+ return;
9072
+ }
9073
+ this.cached = next;
9074
+ if (timeChanged && prev.time !== next.time) _optionalChain([this, 'access', _241 => _241.onTime, 'optionalCall', _242 => _242(next.time)]);
9075
+ for (const listener of this.listeners) listener(next);
9076
+ }
9077
+ }, _class9);
9078
+ function createAnimationPlayer(options) {
9079
+ return new AnimationPlayer(options);
9080
+ }
9081
+
9082
+ // src/canvas/animation/export.ts
9083
+ function sampleAnimationFrames(doc, options = {}) {
9084
+ const fps = _nullishCoalesce(options.fps, () => ( 30));
9085
+ if (!(fps > 0) || !Number.isFinite(fps)) throw new RangeError("fps must be a positive number.");
9086
+ const start = _nullishCoalesce(options.start, () => ( 0));
9087
+ const duration = Math.max(0, _nullishCoalesce(options.duration, () => ( getAnimationDuration(doc) - start)));
9088
+ const step = 1e3 / fps;
9089
+ const count = Math.floor(duration / step + 1e-9) + 1;
9090
+ if (count > (_nullishCoalesce(options.maxFrames, () => ( 1e5)))) throw new RangeError(`Sampling would produce ${count} frames.`);
9091
+ const frames = [];
9092
+ for (let i = 0; i < count; i++) {
9093
+ const time = start + i * step;
9094
+ frames.push({ index: i, time, overrides: evaluateAnimation(doc, time, options) });
9095
+ }
9096
+ return frames;
9097
+ }
9098
+ var CSS_ANIMATION_PROPERTIES = {
9099
+ x: { css: "translate", camel: "translate" },
9100
+ y: { css: "translate", camel: "translate" },
9101
+ motionPath: { css: "translate", camel: "translate" },
9102
+ rotation: { css: "rotate", camel: "rotate" },
9103
+ scale: { css: "scale", camel: "scale" },
9104
+ opacity: { css: "opacity", camel: "opacity" },
9105
+ fill: { css: "background-color", camel: "backgroundColor" },
9106
+ stroke: { css: "border-color", camel: "borderColor" },
9107
+ strokeWidth: { css: "border-width", camel: "borderWidth" },
9108
+ cornerRadius: { css: "border-radius", camel: "borderRadius" },
9109
+ width: { css: "width", camel: "width" },
9110
+ height: { css: "height", camel: "height" }
9111
+ };
9112
+ var round2 = (v) => Math.round(v * 1e3) / 1e3;
9113
+ function cssValue(source, value, node, partner, partnerSource) {
9114
+ if (source === "x" || source === "y") {
9115
+ const dx = source === "x" ? value - node.position.x : partner !== void 0 ? partner - node.position.x : 0;
9116
+ const dy = source === "y" ? value - node.position.y : partner !== void 0 && partnerSource === "y" ? partner - node.position.y : 0;
9117
+ return `${round2(dx)}px ${round2(dy)}px`;
9118
+ }
9119
+ if (typeof value === "string") return value;
9120
+ switch (source) {
9121
+ case "rotation":
9122
+ return `${round2(value)}deg`;
9123
+ case "scale":
9124
+ case "opacity":
9125
+ return String(round2(value));
9126
+ default:
9127
+ return `${round2(value)}px`;
9128
+ }
9129
+ }
9130
+ var sameTimes = (a, b) => a.length === b.length && a.every((k, i) => Math.abs(k.time - b[i].time) < 1e-6 && JSON.stringify(_nullishCoalesce(k.easing, () => ( "linear"))) === JSON.stringify(_nullishCoalesce(b[i].easing, () => ( "linear"))));
9131
+ function needsOklab(keys) {
9132
+ for (let i = 0; i + 1 < keys.length; i++) {
9133
+ if (keys[i].easing !== "hold" && keys[i].value !== keys[i + 1].value) return true;
9134
+ }
9135
+ return false;
9136
+ }
9137
+ function exactStops(keys, duration, format) {
9138
+ const stops = [];
9139
+ if (keys[0].time > 0) stops.push({ offset: 0, value: format(keys[0], 0), easing: "linear" });
9140
+ keys.forEach((k, i) => {
9141
+ const next = keys[i + 1];
9142
+ stops.push({
9143
+ offset: Math.min(1, Math.max(0, k.time / duration)),
9144
+ value: format(k, i),
9145
+ ...next ? { easing: easingToCss(k.easing, next.time - k.time) } : {}
9146
+ });
9147
+ });
9148
+ const last = keys[keys.length - 1];
9149
+ if (last.time < duration) stops.push({ offset: 1, value: format(last, keys.length - 1) });
9150
+ return stops;
9151
+ }
9152
+ function sampledStops(duration, fps, keyTimes, valueAt) {
9153
+ const times = /* @__PURE__ */ new Set([0, duration, ...keyTimes.filter((t) => t >= 0 && t <= duration)]);
9154
+ const step = 1e3 / Math.max(1, fps);
9155
+ for (let t = step; t < duration; t += step) times.add(t);
9156
+ return [...times].sort((a, b) => a - b).map((t) => ({ offset: Math.min(1, t / duration), value: valueAt(t), easing: "linear" }));
9157
+ }
9158
+ function getCssPropertyAnimations(nodes, nodeId, options = {}) {
9159
+ const node = nodes.find((n) => n.id === nodeId);
9160
+ const animation = getNodeAnimation(node);
9161
+ if (!node || !animation) return [];
9162
+ const duration = _nullishCoalesce(options.duration, () => ( getAnimationDuration([node])));
9163
+ if (!(duration > 0)) return [];
9164
+ const fps = _nullishCoalesce(options.sampleFps, () => ( 30));
9165
+ const map = { ...CSS_ANIMATION_PROPERTIES, ..._nullishCoalesce(options.cssProperties, () => ( {})) };
9166
+ const tracks = /* @__PURE__ */ new Map();
9167
+ for (const [key, track] of Object.entries(animation.tracks)) {
9168
+ if (!track || track.enabled === false || !map[key]) continue;
9169
+ const keys = normalizeKeyframes(track.keyframes);
9170
+ if (keys.length > 0) tracks.set(key, keys);
9171
+ }
9172
+ const typeOf = (key) => _nullishCoalesce(_optionalChain([ANIMATABLE_PROPERTIES, 'access', _243 => _243.find, 'call', _244 => _244((p) => p.key === key), 'optionalAccess', _245 => _245.type]), () => ( "number"));
9173
+ const groups = /* @__PURE__ */ new Map();
9174
+ for (const key of tracks.keys()) {
9175
+ const css = map[key].css;
9176
+ groups.set(css, [..._nullishCoalesce(groups.get(css), () => ( [])), key]);
9177
+ }
9178
+ const out = [];
9179
+ for (const [css, sources] of groups) {
9180
+ const camel2 = map[sources[0]].camel;
9181
+ const keysOf = (k) => tracks.get(k);
9182
+ const evalAt = (k, t) => evaluateTrack(keysOf(k), t, typeOf(k));
9183
+ const allTimes = sources.flatMap((k) => keysOf(k).map((x) => x.time));
9184
+ if (sources.includes("motionPath")) {
9185
+ const position = (t) => {
9186
+ const moved = ANIMATABLE_PROPERTIES.find((p) => p.key === "motionPath").write(node, evalAt("motionPath", t));
9187
+ return `${round2(moved.position.x - node.position.x)}px ${round2(moved.position.y - node.position.y)}px`;
9188
+ };
9189
+ out.push({ property: css, camel: camel2, sources, stops: sampledStops(duration, fps, allTimes, position), exact: false });
9190
+ continue;
9191
+ }
9192
+ if (sources.length === 2 && css === "translate") {
9193
+ const [a, b] = sources[0] === "x" ? sources : [sources[1], sources[0]];
9194
+ if (sameTimes(keysOf(a), keysOf(b))) {
9195
+ const bKeys = keysOf(b);
9196
+ out.push({ property: css, camel: camel2, sources, stops: exactStops(keysOf(a), duration, (k, i) => cssValue(a, k.value, node, bKeys[i].value, b)), exact: true });
9197
+ } else {
9198
+ out.push({
9199
+ property: css,
9200
+ camel: camel2,
9201
+ sources,
9202
+ stops: sampledStops(duration, fps, allTimes, (t) => cssValue(a, evalAt(a, t), node, evalAt(b, t), b)),
9203
+ exact: false
9204
+ });
9205
+ }
9206
+ continue;
9207
+ }
9208
+ const key = sources[sources.length - 1];
9209
+ const keys = keysOf(key);
9210
+ if (typeOf(key) === "color" && needsOklab(keys)) {
9211
+ out.push({ property: css, camel: camel2, sources: [key], stops: sampledStops(duration, fps, allTimes, (t) => cssValue(key, evalAt(key, t), node)), exact: false });
9212
+ } else {
9213
+ out.push({ property: css, camel: camel2, sources: [key], stops: exactStops(keys, duration, (k) => cssValue(key, k.value, node)), exact: true });
9214
+ }
9215
+ }
9216
+ return out;
9217
+ }
9218
+ function timing(options, duration) {
9219
+ const rate = options.playbackRate && Number.isFinite(options.playbackRate) && options.playbackRate !== 0 ? options.playbackRate : 1;
9220
+ const loop = _nullishCoalesce(options.loop, () => ( "none"));
9221
+ return {
9222
+ duration: round2(duration / Math.abs(rate)),
9223
+ iterations: loop === "none" ? 1 : Infinity,
9224
+ direction: loop === "ping-pong" ? rate < 0 ? "alternate-reverse" : "alternate" : rate < 0 ? "reverse" : "normal"
9225
+ };
9226
+ }
9227
+ var cssIdent = (text) => text.replace(/[^A-Za-z0-9_-]/g, "-").replace(/^(\d)/, "_$1");
9228
+ function exportCssAnimation(nodes, nodeId, options = {}) {
9229
+ const duration = _nullishCoalesce(options.duration, () => ( getAnimationDuration(nodes.filter((n) => n.id === nodeId))));
9230
+ const props = getCssPropertyAnimations(nodes, nodeId, { ...options, duration });
9231
+ const base = cssIdent(_nullishCoalesce(options.name, () => ( `anim-${nodeId}`)));
9232
+ const t = timing(options, duration);
9233
+ const blocks = [];
9234
+ const parts = [];
9235
+ const animations = [];
9236
+ for (const prop of props) {
9237
+ const name = `${base}-${cssIdent(prop.property)}`;
9238
+ const lines = prop.stops.map((s) => {
9239
+ const pct = `${round2(s.offset * 100)}%`;
9240
+ const easing = s.easing ? ` animation-timing-function: ${s.easing};` : "";
9241
+ return ` ${pct} { ${prop.property}: ${s.value};${easing} }`;
9242
+ });
9243
+ blocks.push(`@keyframes ${name} {
9244
+ ${lines.join("\n")}
9245
+ }`);
9246
+ parts.push(`${name} ${t.duration}ms linear 0ms ${t.iterations === Infinity ? "infinite" : 1} ${t.direction} both`);
9247
+ animations.push({ name, property: prop.property, exact: prop.exact });
9248
+ }
9249
+ const animation = parts.join(", ");
9250
+ const selector = _nullishCoalesce(options.selector, () => ( `[data-id="${nodeId.replace(/["\\]/g, "\\$&")}"]`));
9251
+ const css = blocks.length ? `${blocks.join("\n\n")}
9252
+
9253
+ ${selector} {
9254
+ animation: ${animation};
9255
+ }
9256
+ ` : "";
9257
+ return { css, animation, animations, exact: props.every((p) => p.exact) };
9258
+ }
9259
+ function toWebAnimations(nodes, nodeId, options = {}) {
9260
+ const duration = _nullishCoalesce(options.duration, () => ( getAnimationDuration(nodes.filter((n) => n.id === nodeId))));
9261
+ const t = timing(options, duration);
9262
+ return getCssPropertyAnimations(nodes, nodeId, { ...options, duration }).map((prop) => ({
9263
+ property: prop.property,
9264
+ keyframes: prop.stops.map((s) => ({ offset: s.offset, [prop.camel]: s.value, ...s.easing ? { easing: s.easing } : {} })),
9265
+ options: { duration: t.duration, iterations: t.iterations, direction: t.direction, fill: "both", easing: "linear" },
9266
+ exact: prop.exact
9267
+ }));
9268
+ }
9269
+ function playWebAnimations(element, specs) {
9270
+ return specs.map((spec) => element.animate(spec.keyframes, spec.options));
9271
+ }
9272
+ function isCssExportExact(nodes, nodeId) {
9273
+ return getCssPropertyAnimations(nodes, nodeId).every((p) => p.exact);
9274
+ }
9275
+
9276
+ // src/canvas/animation/timeline.ts
9277
+ function isKeyframeSelected(selection, ref) {
9278
+ return selection.some((s) => s.nodeId === ref.nodeId && s.property === ref.property && Math.abs(s.time - ref.time) <= ANIMATION_TIME_EPSILON);
9279
+ }
9280
+ var defaultLabel = (node) => typeof _optionalChain([node, 'access', _246 => _246.data, 'optionalAccess', _247 => _247.label]) === "string" && node.data.label.trim() ? node.data.label : node.id;
9281
+ function getTimelineRows(nodes, ids, options = {}) {
9282
+ const byId = new Map(nodes.map((n) => [n.id, n]));
9283
+ const selection = _nullishCoalesce(options.selection, () => ( []));
9284
+ const labelOf = _nullishCoalesce(options.labelOf, () => ( defaultLabel));
9285
+ const rows = [];
9286
+ for (const id of new Set(ids)) {
9287
+ const node = byId.get(id);
9288
+ if (!node) continue;
9289
+ for (const property of getAnimatedProperties(node, options)) {
9290
+ const track = getAnimationTrack(node, property);
9291
+ const label = _nullishCoalesce(_optionalChain([(_nullishCoalesce(options.properties, () => ( ANIMATABLE_PROPERTIES))), 'access', _248 => _248.find, 'call', _249 => _249((p) => p.key === property), 'optionalAccess', _250 => _250.label]), () => ( property));
9292
+ rows.push({
9293
+ id: `${id}:${property}`,
9294
+ nodeId: id,
9295
+ nodeLabel: labelOf(node),
9296
+ property,
9297
+ label,
9298
+ enabled: track.enabled !== false,
9299
+ keyframes: normalizeKeyframes(track.keyframes).map((k) => {
9300
+ const ref = { nodeId: id, property, time: k.time };
9301
+ const selected = isKeyframeSelected(selection, ref);
9302
+ return {
9303
+ ref,
9304
+ time: selected && options.dragDelta ? k.time + options.dragDelta : k.time,
9305
+ value: k.value,
9306
+ ...k.easing !== void 0 ? { easing: k.easing } : {},
9307
+ selected
9308
+ };
9309
+ })
9310
+ });
9311
+ }
9312
+ }
9313
+ return rows;
9314
+ }
9315
+ function timeToX(time, duration, width) {
9316
+ return duration > 0 ? time / duration * width : 0;
9317
+ }
9318
+ function xToTime(x, duration, width) {
9319
+ if (!(width > 0) || !(duration > 0)) return 0;
9320
+ return Math.min(duration, Math.max(0, x / width * duration));
9321
+ }
9322
+ function formatAnimationTime(ms) {
9323
+ const s = Math.max(0, ms) / 1e3;
9324
+ return `${s.toFixed(s < 10 ? 2 : 1)}s`;
9325
+ }
9326
+ var STEPS = [10, 20, 50, 100, 200, 250, 500, 1e3, 2e3, 5e3, 1e4, 15e3, 3e4, 6e4, 12e4, 3e5, 6e5];
9327
+ function getTimelineTicks(duration, width, minSpacing = 60) {
9328
+ if (!(duration > 0) || !(width > 0)) return [];
9329
+ const step = _nullishCoalesce(STEPS.find((s) => timeToX(s, duration, width) >= minSpacing), () => ( STEPS[STEPS.length - 1]));
9330
+ const ticks = [];
9331
+ for (let t = 0; t <= duration + 1e-6 && ticks.length < 1e3; t += step) {
9332
+ ticks.push({ time: t, x: timeToX(t, duration, width), label: formatAnimationTime(t) });
9333
+ }
9334
+ return ticks;
9335
+ }
9336
+
9337
+ // src/canvas/animation/controller.ts
9338
+ var uniq = (items) => [...new Set(items)];
9339
+ function createCanvasAnimationController(options) {
9340
+ let fixedDuration = options.duration !== void 0 && options.duration > 0 ? options.duration : null;
9341
+ let recording = _nullishCoalesce(options.recording, () => ( false));
9342
+ let fps = options.fps && options.fps > 0 ? options.fps : 30;
9343
+ let selection = [];
9344
+ let drag = null;
9345
+ let clipboard = null;
9346
+ const listeners = /* @__PURE__ */ new Set();
9347
+ const propertyOptions = () => options.properties ? { properties: options.properties } : {};
9348
+ const durationOf = (nodes) => _nullishCoalesce(fixedDuration, () => ( Math.max(_nullishCoalesce(options.minDuration, () => ( 1e3)), getAnimationDuration(nodes))));
9349
+ let durationNodes = null;
9350
+ let durationValue = 0;
9351
+ const duration = () => {
9352
+ const nodes = options.getNodes();
9353
+ if (nodes !== durationNodes) {
9354
+ durationNodes = nodes;
9355
+ durationValue = durationOf(nodes);
9356
+ }
9357
+ return _nullishCoalesce(fixedDuration, () => ( durationValue));
9358
+ };
9359
+ const player = new AnimationPlayer({
9360
+ clock: options.clock,
9361
+ duration,
9362
+ loop: options.loop,
9363
+ playbackRate: options.playbackRate,
9364
+ onTime: (time) => _optionalChain([options, 'access', _251 => _251.onTime, 'optionalCall', _252 => _252(time)])
9365
+ });
9366
+ let cached = null;
9367
+ const snapshot = () => ({
9368
+ ...player.getState(),
9369
+ duration: duration(),
9370
+ recording,
9371
+ fps,
9372
+ selection,
9373
+ drag,
9374
+ autoDuration: fixedDuration === null
9375
+ });
9376
+ const getState = () => {
9377
+ const next = snapshot();
9378
+ if (cached && cached.time === next.time && cached.playing === next.playing && cached.scrubbing === next.scrubbing && cached.loop === next.loop && cached.playbackRate === next.playbackRate && cached.duration === next.duration && cached.recording === next.recording && cached.fps === next.fps && cached.selection === next.selection && cached.drag === next.drag && cached.autoDuration === next.autoDuration) {
9379
+ return cached;
9380
+ }
9381
+ cached = next;
9382
+ return cached;
9383
+ };
9384
+ const notify = () => {
9385
+ const state = getState();
9386
+ _optionalChain([options, 'access', _253 => _253.onChange, 'optionalCall', _254 => _254(state)]);
9387
+ for (const listener of listeners) listener(state);
9388
+ };
9389
+ player.subscribe(notify);
9390
+ const selectedIds = () => _nullishCoalesce(_optionalChain([options, 'access', _255 => _255.getSelectedIds, 'optionalCall', _256 => _256()]), () => ( options.getNodes().filter((n) => n.selected).map((n) => n.id)));
9391
+ const KEEP_FIELDS = ["selected", "dragging", "measured"];
9392
+ const replaceNodes = (nodes, replacements, animationOnly = false) => nodes.map((node) => {
9393
+ const replacement = replacements.get(node.id);
9394
+ if (!replacement) return node;
9395
+ if (animationOnly) {
9396
+ const data = { ..._nullishCoalesce(node.data, () => ( {})) };
9397
+ const value = _optionalChain([replacement, 'access', _257 => _257.data, 'optionalAccess', _258 => _258[ANIMATION_DATA_KEY]]);
9398
+ if (value === void 0) delete data[ANIMATION_DATA_KEY];
9399
+ else data[ANIMATION_DATA_KEY] = value;
9400
+ return { ...node, data };
9401
+ }
9402
+ const next = { ...replacement };
9403
+ for (const field of KEEP_FIELDS) {
9404
+ if (field in node) next[field] = node[field];
9405
+ else delete next[field];
9406
+ }
9407
+ return next;
9408
+ });
9409
+ function commit(name, edit, merge) {
9410
+ const before = options.getNodes();
9411
+ const after = edit(before);
9412
+ if (after === before) return false;
9413
+ const beforeById = new Map(before.map((n) => [n.id, n]));
9414
+ const undoMap = /* @__PURE__ */ new Map();
9415
+ const redoMap = /* @__PURE__ */ new Map();
9416
+ for (const node of after) {
9417
+ const old = beforeById.get(node.id);
9418
+ if (old && old !== node) {
9419
+ undoMap.set(node.id, old);
9420
+ redoMap.set(node.id, node);
9421
+ }
9422
+ }
9423
+ if (redoMap.size === 0) return false;
9424
+ const scope = _nullishCoalesce(_optionalChain([merge, 'optionalAccess', _259 => _259.animationOnly]), () => ( false));
9425
+ const execute = () => options.setNodes(replaceNodes(options.getNodes(), redoMap, scope));
9426
+ const undo = () => options.setNodes(replaceNodes(options.getNodes(), undoMap, scope));
9427
+ const command = { name, execute, undo, ...merge ? { tag: merge.tag } : {} };
9428
+ if (!options.history) execute();
9429
+ else if (merge && options.history.executeMerged) options.history.executeMerged(command, { windowMs: _nullishCoalesce(merge.windowMs, () => ( 1e3)) });
9430
+ else options.history.execute(command);
9431
+ return true;
9432
+ }
9433
+ function pruneSelection() {
9434
+ if (selection.length === 0) return;
9435
+ const byId = new Map(options.getNodes().map((n) => [n.id, n]));
9436
+ const kept = selection.filter((ref) => {
9437
+ const track = _optionalChain([getNodeAnimation, 'call', _260 => _260(byId.get(ref.nodeId)), 'optionalAccess', _261 => _261.tracks, 'access', _262 => _262[ref.property]]);
9438
+ return !!track && normalizeKeyframes(track.keyframes).some((k) => Math.abs(k.time - ref.time) <= ANIMATION_TIME_EPSILON);
9439
+ });
9440
+ if (kept.length !== selection.length) selection = kept;
9441
+ }
9442
+ const setSelection = (refs) => {
9443
+ selection = refs.map((r) => ({ nodeId: r.nodeId, property: r.property, time: r.time }));
9444
+ };
9445
+ let displayCache = null;
9446
+ function display(nodes = options.getNodes()) {
9447
+ const time = player.currentTime;
9448
+ if (displayCache && displayCache.nodes === nodes && displayCache.time === time) return displayCache.out;
9449
+ const out = applyAnimation(nodes, time, propertyOptions());
9450
+ displayCache = { nodes, time, out };
9451
+ return out;
9452
+ }
9453
+ const controller = {
9454
+ player,
9455
+ getState,
9456
+ subscribe(listener) {
9457
+ listeners.add(listener);
9458
+ return () => {
9459
+ listeners.delete(listener);
9460
+ };
9461
+ },
9462
+ /** Re-reads node-derived state (the automatic duration) and notifies when it changed. */
9463
+ refresh() {
9464
+ const prev = cached;
9465
+ if (getState() !== prev) notify();
9466
+ },
9467
+ // ----- playback ---------------------------------------------------------------------
9468
+ get time() {
9469
+ return player.currentTime;
9470
+ },
9471
+ get playing() {
9472
+ return player.isPlaying;
9473
+ },
9474
+ get duration() {
9475
+ return duration();
9476
+ },
9477
+ play: () => player.play(),
9478
+ pause: () => player.pause(),
9479
+ toggle: () => player.toggle(),
9480
+ stop: () => player.stop(),
9481
+ seek: (time) => player.seek(time),
9482
+ scrub: (time) => player.scrub(time),
9483
+ endScrub: () => player.endScrub(),
9484
+ setLoop: (loop) => player.setLoop(loop),
9485
+ setPlaybackRate: (rate) => player.setPlaybackRate(rate),
9486
+ /** Fixed duration in ms, or `null` to follow the last keyframe. */
9487
+ setDuration(ms) {
9488
+ fixedDuration = ms !== null && Number.isFinite(ms) && ms > 0 ? ms : null;
9489
+ durationNodes = null;
9490
+ player.setDuration(duration);
9491
+ notify();
9492
+ },
9493
+ setFps(value) {
9494
+ if (!(value > 0) || value === fps) return;
9495
+ fps = value;
9496
+ notify();
9497
+ },
9498
+ setRecording(on) {
9499
+ if (recording === on) return;
9500
+ recording = on;
9501
+ notify();
9502
+ },
9503
+ toggleRecording() {
9504
+ controller.setRecording(!recording);
9505
+ },
9506
+ /** Seeks to the next keyframe (of the selected nodes, or all) after the playhead. */
9507
+ nextKeyframe(ids = selectedIds()) {
9508
+ const list = [...ids];
9509
+ const times = getKeyframeTimes(options.getNodes(), list.length ? { ids: list } : {});
9510
+ const next = times.find((t) => t > player.currentTime + ANIMATION_TIME_EPSILON);
9511
+ if (next === void 0) return null;
9512
+ player.seek(next);
9513
+ return next;
9514
+ },
9515
+ previousKeyframe(ids = selectedIds()) {
9516
+ const list = [...ids];
9517
+ const times = getKeyframeTimes(options.getNodes(), list.length ? { ids: list } : {});
9518
+ const prev = [...times].reverse().find((t) => t < player.currentTime - ANIMATION_TIME_EPSILON);
9519
+ if (prev === void 0) return null;
9520
+ player.seek(prev);
9521
+ return prev;
9522
+ },
9523
+ // ----- display ----------------------------------------------------------------------
9524
+ /** The nodes evaluated at the playhead (same array when nothing is animated). */
9525
+ display,
9526
+ /**
9527
+ * Applies edits made on the displayed nodes: animated properties (and, in record mode,
9528
+ * any property) are keyed at the playhead; other changes go to the stored nodes.
9529
+ * Keying is one undo step per node set, merged while a drag continues.
9530
+ */
9531
+ applyDisplayChanges(next) {
9532
+ const base = options.getNodes();
9533
+ const shown = display(base);
9534
+ const time = player.currentTime;
9535
+ const { nodes, keyed } = recordAnimationChanges(base, shown, next, time, { recording, ...propertyOptions() });
9536
+ if (keyed.length === 0) {
9537
+ if (nodes !== base) options.setNodes(nodes);
9538
+ return [];
9539
+ }
9540
+ const ids = new Set(keyed.map((k) => k.nodeId));
9541
+ const baseById = new Map(base.map((n) => [n.id, n]));
9542
+ const staticNodes = nodes.map((n) => {
9543
+ if (!ids.has(n.id)) return n;
9544
+ const old = _optionalChain([baseById, 'access', _263 => _263.get, 'call', _264 => _264(n.id), 'optionalAccess', _265 => _265.data, 'optionalAccess', _266 => _266[ANIMATION_DATA_KEY]]);
9545
+ const data = { ..._nullishCoalesce(n.data, () => ( {})) };
9546
+ if (old === void 0) delete data[ANIMATION_DATA_KEY];
9547
+ else data[ANIMATION_DATA_KEY] = old;
9548
+ return { ...n, data };
9549
+ });
9550
+ const animationOf = new Map(nodes.filter((n) => ids.has(n.id)).map((n) => [n.id, _optionalChain([n, 'access', _267 => _267.data, 'optionalAccess', _268 => _268[ANIMATION_DATA_KEY]])]));
9551
+ options.setNodes(staticNodes);
9552
+ const tag = `animation.record:${[...ids].sort().join(",")}`;
9553
+ commit(
9554
+ "Record Keyframe",
9555
+ (current) => current.map((n) => {
9556
+ if (!animationOf.has(n.id)) return n;
9557
+ const data = { ..._nullishCoalesce(n.data, () => ( {})) };
9558
+ const value = animationOf.get(n.id);
9559
+ if (value === void 0) delete data[ANIMATION_DATA_KEY];
9560
+ else data[ANIMATION_DATA_KEY] = value;
9561
+ return { ...n, data };
9562
+ }),
9563
+ { tag, animationOnly: true }
9564
+ );
9565
+ return keyed;
9566
+ },
9567
+ // ----- editing ----------------------------------------------------------------------
9568
+ /** Keys the nodes (default: selected) at the playhead; see `addKeyframesAtTime`. */
9569
+ addKeyframe(ids, keys, time = player.currentTime) {
9570
+ let refs = [];
9571
+ commit("Add Keyframe", (nodes) => {
9572
+ const result = addKeyframesAtTime(nodes, _nullishCoalesce(ids, () => ( selectedIds())), time, { ...propertyOptions(), ...keys ? { keys } : {} });
9573
+ refs = result.refs;
9574
+ return result.nodes;
9575
+ });
9576
+ if (refs.length) setSelection(refs);
9577
+ notify();
9578
+ return refs;
9579
+ },
9580
+ setKeyframe(nodeId, property, value, time = player.currentTime, easing) {
9581
+ commit("Set Keyframe", (nodes) => setKeyframe(nodes, nodeId, property, time, value, { ...propertyOptions(), ...easing !== void 0 ? { easing } : {} }));
9582
+ },
9583
+ updateKeyframe(ref, patch) {
9584
+ commit("Edit Keyframe", (nodes) => updateKeyframe(nodes, ref, patch, propertyOptions()));
9585
+ if (patch.time !== void 0 && isKeyframeSelected(selection, ref)) {
9586
+ setSelection(selection.map((s) => isKeyframeSelected([ref], s) ? { ...s, time: Math.max(0, patch.time) } : s));
9587
+ }
9588
+ pruneSelection();
9589
+ notify();
9590
+ },
9591
+ deleteKeyframes(refs = selection) {
9592
+ if (refs.length === 0) return false;
9593
+ const changed = commit(refs.length === 1 ? "Delete Keyframe" : "Delete Keyframes", (nodes) => deleteKeyframes(nodes, refs, propertyOptions()));
9594
+ pruneSelection();
9595
+ notify();
9596
+ return changed;
9597
+ },
9598
+ setEasing(easing, refs = selection) {
9599
+ if (refs.length === 0) return false;
9600
+ return commit("Set Easing", (nodes) => setKeyframeEasing(nodes, refs, easing, propertyOptions()));
9601
+ },
9602
+ setTrackEnabled(nodeId, property, enabled) {
9603
+ commit(enabled ? "Enable Track" : "Disable Track", (nodes) => setTrackEnabled(nodes, nodeId, property, enabled));
9604
+ },
9605
+ removeTrack(nodeId, property) {
9606
+ commit("Remove Track", (nodes) => removeTrack(nodes, nodeId, property, { ...propertyOptions(), keepValueAt: player.currentTime }));
9607
+ pruneSelection();
9608
+ notify();
9609
+ },
9610
+ setMotionPath(nodeId, motionPath) {
9611
+ commit("Set Motion Path", (nodes) => setMotionPath(nodes, nodeId, motionPath));
9612
+ },
9613
+ /** Animates a node to `to` (from its current values) over `duration`; see `animateNode`. */
9614
+ animateNode(nodeId, opts) {
9615
+ let refs = [];
9616
+ commit("Animate", (nodes) => {
9617
+ const result = animateNode(nodes, nodeId, { ...opts, ...propertyOptions() });
9618
+ refs = result.refs;
9619
+ return result.nodes;
9620
+ });
9621
+ return refs;
9622
+ },
9623
+ /** Moves keyframes (default: selected) by `delta` ms as one step; returns the delta applied. */
9624
+ moveKeyframes(delta, refs = selection) {
9625
+ if (refs.length === 0) return 0;
9626
+ let applied = 0;
9627
+ let moved = [];
9628
+ commit(refs.length === 1 ? "Move Keyframe" : "Move Keyframes", (nodes) => {
9629
+ const result = moveKeyframes(nodes, refs, delta);
9630
+ applied = result.delta;
9631
+ moved = result.refs;
9632
+ return result.nodes;
9633
+ });
9634
+ if (applied !== 0 && refs === selection) setSelection(moved);
9635
+ notify();
9636
+ return applied;
9637
+ },
9638
+ /** Scales keyframe spacing (default: selected) around `pivot`; returns the factor applied. */
9639
+ scaleKeyframes(factor, refs = selection, pivot) {
9640
+ if (refs.length === 0) return 1;
9641
+ let applied = 1;
9642
+ let scaled = [];
9643
+ commit("Scale Keyframes", (nodes) => {
9644
+ const result = scaleKeyframes(nodes, refs, factor, pivot === void 0 ? {} : { pivot });
9645
+ applied = result.factor;
9646
+ scaled = result.refs;
9647
+ return result.nodes;
9648
+ });
9649
+ if (applied !== 1 && refs === selection) setSelection(scaled);
9650
+ notify();
9651
+ return applied;
9652
+ },
9653
+ copyKeyframes(refs = selection) {
9654
+ if (refs.length === 0) return null;
9655
+ clipboard = copyKeyframes(options.getNodes(), refs);
9656
+ return clipboard;
9657
+ },
9658
+ /** Pastes at the playhead onto the selected nodes (or the copied ones). */
9659
+ pasteKeyframes(data = clipboard, nodeIds = selectedIds(), time = player.currentTime) {
9660
+ if (!data) return [];
9661
+ let refs = [];
9662
+ commit("Paste Keyframes", (nodes) => {
9663
+ const result = pasteKeyframes(nodes, data, time, { ...propertyOptions(), nodeIds });
9664
+ refs = result.refs;
9665
+ return result.nodes;
9666
+ });
9667
+ if (refs.length) setSelection(refs);
9668
+ notify();
9669
+ return refs;
9670
+ },
9671
+ get clipboard() {
9672
+ return clipboard;
9673
+ },
9674
+ // ----- selection & drag -------------------------------------------------------------
9675
+ get selection() {
9676
+ return selection;
9677
+ },
9678
+ selectKeyframes(refs, mode = "replace") {
9679
+ if (mode === "replace") setSelection([...refs]);
9680
+ else if (mode === "add") setSelection([...selection, ...refs.filter((r) => !isKeyframeSelected(selection, r))]);
9681
+ else {
9682
+ const removed = selection.filter((s) => !isKeyframeSelected(refs, s));
9683
+ setSelection([...removed, ...refs.filter((r) => !isKeyframeSelected(selection, r))]);
9684
+ }
9685
+ notify();
9686
+ },
9687
+ clearSelection() {
9688
+ if (selection.length === 0) return;
9689
+ selection = [];
9690
+ notify();
9691
+ },
9692
+ /** Starts dragging keyframes (default: the selection; refs not selected become the selection). */
9693
+ beginKeyframeDrag(refs) {
9694
+ if (refs && !refs.every((r) => isKeyframeSelected(selection, r))) setSelection([...refs]);
9695
+ if (selection.length === 0) return;
9696
+ drag = { refs: selection.map((r) => ({ ...r })), delta: 0, target: null };
9697
+ notify();
9698
+ },
9699
+ /**
9700
+ * Previews the drag at `delta` ms. With `snap` (default on) the group snaps to other
9701
+ * keyframes, the playhead, 0 and the end within `thresholdMs`, else to whole frames.
9702
+ */
9703
+ updateKeyframeDrag(delta, opts = {}) {
9704
+ if (!drag) return null;
9705
+ const nodes = options.getNodes();
9706
+ const times = drag.refs.map((r) => r.time);
9707
+ const minTime = Math.min(...times);
9708
+ let d = Math.max(-minTime, Number.isFinite(delta) ? delta : 0);
9709
+ let target = null;
9710
+ if (opts.snap !== false) {
9711
+ const targets = uniq([...getKeyframeTimes(nodes, { exclude: drag.refs }), player.currentTime, 0, duration()]);
9712
+ const snapped = snapKeyframeDelta(times, d, targets, _nullishCoalesce(opts.thresholdMs, () => ( 1e3 / fps / 2)));
9713
+ target = snapped.target;
9714
+ d = snapped.delta;
9715
+ if (target === null) d = snapTimeToFrame(minTime + d, fps) - minTime;
9716
+ }
9717
+ d = Math.max(-minTime, d);
9718
+ if (d !== drag.delta || target !== drag.target) {
9719
+ drag = { ...drag, delta: d, target };
9720
+ notify();
9721
+ }
9722
+ return drag;
9723
+ },
9724
+ /** Commits the drag as one undo step. */
9725
+ endKeyframeDrag() {
9726
+ if (!drag) return 0;
9727
+ const { refs, delta } = drag;
9728
+ drag = null;
9729
+ let applied = 0;
9730
+ if (delta !== 0) {
9731
+ let moved = [];
9732
+ commit(refs.length === 1 ? "Move Keyframe" : "Move Keyframes", (nodes) => {
9733
+ const result = moveKeyframes(nodes, refs, delta);
9734
+ applied = result.delta;
9735
+ moved = result.refs;
9736
+ return result.nodes;
9737
+ });
9738
+ if (applied !== 0) setSelection(moved);
9739
+ }
9740
+ notify();
9741
+ return applied;
9742
+ },
9743
+ /** Cancels the drag preview (Escape); nothing is edited. */
9744
+ cancelKeyframeDrag() {
9745
+ if (!drag) return;
9746
+ drag = null;
9747
+ notify();
9748
+ },
9749
+ // ----- views & export ---------------------------------------------------------------
9750
+ /** Timeline rows for `ids` (default: selected nodes), including the drag preview. */
9751
+ timelineRows(ids = selectedIds(), opts = {}) {
9752
+ return getTimelineRows(options.getNodes(), ids, { ...propertyOptions(), ...opts, selection, dragDelta: _nullishCoalesce(_optionalChain([drag, 'optionalAccess', _269 => _269.delta]), () => ( 0)) });
9753
+ },
9754
+ sampleFrames(opts = {}) {
9755
+ return sampleAnimationFrames(options.getNodes(), { fps, duration: duration(), ...propertyOptions(), ...opts });
9756
+ },
9757
+ exportCss(nodeId, opts = {}) {
9758
+ const state = player.getState();
9759
+ return exportCssAnimation(options.getNodes(), nodeId, { duration: duration(), loop: state.loop, playbackRate: state.playbackRate, ...opts });
9760
+ },
9761
+ toWebAnimations(nodeId, opts = {}) {
9762
+ const state = player.getState();
9763
+ return toWebAnimations(options.getNodes(), nodeId, { duration: duration(), loop: state.loop, playbackRate: state.playbackRate, ...opts });
9764
+ },
9765
+ destroy() {
9766
+ player.destroy();
9767
+ listeners.clear();
9768
+ }
9769
+ };
9770
+ return controller;
9771
+ }
9772
+
9773
+ // src/canvas/components.ts
9774
+ var COMPONENT_DATA_KEY = "component";
9775
+ var COMPONENT_SET_DATA_KEY = "componentSet";
9776
+ var INSTANCE_DATA_KEY = "instance";
9777
+ var COMPONENT_SOURCE_DATA_KEY = "componentSource";
9778
+ var COMPONENT_OVERRIDES_DATA_KEY = "componentOverrides";
9779
+ var COMPONENT_PROPERTY_REFS_DATA_KEY = "componentPropertyRefs";
9780
+ var MAX_DEPTH = 16;
9781
+ var isRecord = (v) => typeof v === "object" && v !== null && !Array.isArray(v);
9782
+ var dataOf = (node) => isRecord(_optionalChain([node, 'optionalAccess', _270 => _270.data])) ? node.data : {};
9783
+ function same(a, b) {
9784
+ if (a === b) return true;
9785
+ if (typeof a !== "object" || typeof b !== "object" || a === null || b === null) {
9786
+ return typeof a === "number" && typeof b === "number" && Number.isNaN(a) && Number.isNaN(b);
9787
+ }
9788
+ if (Array.isArray(a) !== Array.isArray(b)) return false;
9789
+ if (Array.isArray(a)) {
9790
+ const other = b;
9791
+ return a.length === other.length && a.every((x, i) => same(x, other[i]));
9792
+ }
9793
+ const ra = a;
9794
+ const rb = b;
9795
+ const ka = Object.keys(ra).filter((k) => ra[k] !== void 0);
9796
+ const kb = Object.keys(rb).filter((k) => rb[k] !== void 0);
9797
+ return ka.length === kb.length && ka.every((k) => same(ra[k], rb[k]));
9798
+ }
9799
+ function stringRecord2(value) {
9800
+ const out = {};
9801
+ if (isRecord(value)) {
9802
+ for (const [k, v] of Object.entries(value)) if (typeof v === "string") out[k] = v;
9803
+ }
9804
+ return out;
9805
+ }
9806
+ function isCanvasComponent(node) {
9807
+ return isRecord(dataOf(node)[COMPONENT_DATA_KEY]);
9808
+ }
9809
+ function isCanvasComponentSet(node) {
9810
+ return isRecord(dataOf(node)[COMPONENT_SET_DATA_KEY]);
9811
+ }
9812
+ function isCanvasInstance(node) {
9813
+ const inst = dataOf(node)[INSTANCE_DATA_KEY];
9814
+ return isRecord(inst) && typeof inst.componentId === "string";
9815
+ }
9816
+ function getInstanceData(node) {
9817
+ return isCanvasInstance(node) ? dataOf(node)[INSTANCE_DATA_KEY] : void 0;
9818
+ }
9819
+ function getComponentData(node) {
9820
+ return isCanvasComponent(node) ? dataOf(node)[COMPONENT_DATA_KEY] : void 0;
9821
+ }
9822
+ function getComponentSourceId(node) {
9823
+ const s = dataOf(node)[COMPONENT_SOURCE_DATA_KEY];
9824
+ return typeof s === "string" ? s : void 0;
9825
+ }
9826
+ function getNodeOverrides(node) {
9827
+ const o = dataOf(node)[COMPONENT_OVERRIDES_DATA_KEY];
9828
+ return Array.isArray(o) ? o.filter((g) => typeof g === "string") : [];
9829
+ }
9830
+ function getComponentPropertyRefs(node) {
9831
+ return stringRecord2(dataOf(node)[COMPONENT_PROPERTY_REFS_DATA_KEY]);
9832
+ }
9833
+ function getLayerName(node) {
9834
+ const d = dataOf(node);
9835
+ for (const key of ["name", "label", "text"]) if (typeof d[key] === "string" && d[key]) return d[key];
9836
+ return typeof _optionalChain([node, 'optionalAccess', _271 => _271.type]) === "string" ? node.type : "";
9837
+ }
9838
+ function withData(node, data) {
9839
+ return { ...node, data };
9840
+ }
9841
+ function setOverrides(node, groups) {
9842
+ const list = [...new Set(groups)].sort();
9843
+ const data = { ...dataOf(node) };
9844
+ if (list.length) data[COMPONENT_OVERRIDES_DATA_KEY] = list;
9845
+ else delete data[COMPONENT_OVERRIDES_DATA_KEY];
9846
+ return same(getNodeOverrides(node), list) ? node : withData(node, data);
9847
+ }
9848
+ function unlinked(node, keepRefs = false) {
9849
+ const d = dataOf(node);
9850
+ if (!(COMPONENT_SOURCE_DATA_KEY in d) && !(COMPONENT_OVERRIDES_DATA_KEY in d) && (keepRefs || !(COMPONENT_PROPERTY_REFS_DATA_KEY in d))) return node;
9851
+ const data = { ...d };
9852
+ delete data[COMPONENT_SOURCE_DATA_KEY];
9853
+ delete data[COMPONENT_OVERRIDES_DATA_KEY];
9854
+ if (!keepRefs) delete data[COMPONENT_PROPERTY_REFS_DATA_KEY];
9855
+ return withData(node, data);
9856
+ }
9857
+ var LINK_KEYS = /* @__PURE__ */ new Set([
9858
+ COMPONENT_DATA_KEY,
9859
+ COMPONENT_SET_DATA_KEY,
9860
+ INSTANCE_DATA_KEY,
9861
+ COMPONENT_SOURCE_DATA_KEY,
9862
+ COMPONENT_OVERRIDES_DATA_KEY,
9863
+ COMPONENT_PROPERTY_REFS_DATA_KEY
9864
+ ]);
9865
+ var NESTED_KEYS = { shape: "shape", layout: "layout", tokenBindings: "token", tokenModes: "tokenMode" };
9866
+ var NESTED_PREFIX = { shape: "shape", layout: "layout", token: "tokenBindings", tokenMode: "tokenModes" };
9867
+ var SKIPPED_NODE_KEYS = /* @__PURE__ */ new Set([
9868
+ "id",
9869
+ "parentId",
9870
+ "parentNode",
9871
+ "position",
9872
+ "positionAbsolute",
9873
+ "selected",
9874
+ "dragging",
9875
+ "resizing",
9876
+ "measured",
9877
+ "width",
9878
+ "height",
9879
+ "style",
9880
+ "data",
9881
+ "hidden",
9882
+ "internals",
9883
+ "computed",
9884
+ "handleBounds"
9885
+ ]);
9886
+ var RUNTIME_KEYS = ["selected", "dragging", "resizing"];
9887
+ var UNITLESS = /* @__PURE__ */ new Set(["opacity", "zIndex", "fontWeight", "lineHeight", "flex", "flexGrow", "flexShrink", "order", "zoom"]);
9888
+ var OWN_ROOT_GROUPS = /* @__PURE__ */ new Set([
9889
+ "position",
9890
+ "hidden",
9891
+ "component",
9892
+ "props",
9893
+ "data.locked",
9894
+ "data.lockedPrevious",
9895
+ "data.childLayout",
9896
+ "node.draggable",
9897
+ "node.selectable",
9898
+ "node.deletable",
9899
+ "node.connectable",
9900
+ "node.zIndex",
9901
+ "node.extent",
9902
+ "node.expandParent"
9903
+ ]);
9904
+ var isOwnRootGroup = (g) => OWN_ROOT_GROUPS.has(g) || g.startsWith("tokenMode.");
9905
+ var camel = (name) => name.startsWith("--") ? name : name.trim().toLowerCase().replace(/-([a-z])/g, (_, c) => c.toUpperCase());
9906
+ function styleKeys(style) {
9907
+ if (!style) return [];
9908
+ if (typeof style === "object") return Object.keys(style).filter((k) => style[k] !== void 0);
9909
+ return parseNodeStyleDeclarations(style).map(([k]) => camel(k));
9910
+ }
9911
+ function sizeOf(node) {
9912
+ const s = readStyleSize(node.style);
9913
+ return { width: node.width, height: node.height, styleWidth: s.width, styleHeight: s.height };
9914
+ }
9915
+ var splitGroup = (group) => {
9916
+ const dot3 = group.indexOf(".");
9917
+ return dot3 < 0 ? [group, ""] : [group.slice(0, dot3), group.slice(dot3 + 1)];
9918
+ };
9919
+ function readOverrideGroup(node, group) {
9920
+ const data = dataOf(node);
9921
+ switch (group) {
9922
+ case "hidden":
9923
+ return node.hidden === true;
9924
+ case "position":
9925
+ return node.position;
9926
+ case "size":
9927
+ return sizeOf(node);
9928
+ case "component":
9929
+ return _optionalChain([getInstanceData, 'call', _272 => _272(node), 'optionalAccess', _273 => _273.componentId]);
9930
+ case "props":
9931
+ return _nullishCoalesce(_optionalChain([getInstanceData, 'call', _274 => _274(node), 'optionalAccess', _275 => _275.properties]), () => ( {}));
9932
+ }
9933
+ const [kind, key] = splitGroup(group);
9934
+ switch (kind) {
9935
+ case "style":
9936
+ return readNodeStyleProperty(node.style, key);
9937
+ case "data":
9938
+ return data[key];
9939
+ case "node":
9940
+ return node[key];
9941
+ }
9942
+ const holder = NESTED_PREFIX[kind];
9943
+ if (holder) return isRecord(data[holder]) ? data[holder][key] : void 0;
9944
+ return void 0;
9945
+ }
9946
+ function withSize(node, value) {
9947
+ const v = isRecord(value) ? value : {};
9948
+ const next = { ...node };
9949
+ if (v.width === void 0) delete next.width;
9950
+ else next.width = v.width;
9951
+ if (v.height === void 0) delete next.height;
9952
+ else next.height = v.height;
9953
+ const current = readStyleSize(node.style);
9954
+ let style = node.style;
9955
+ if (v.styleWidth !== current.width) style = writeNodeStyleProperty(style, "width", v.styleWidth);
9956
+ if (v.styleHeight !== current.height) style = writeNodeStyleProperty(style, "height", v.styleHeight);
9957
+ if (style !== node.style) next.style = style;
9958
+ const w = _nullishCoalesce(v.width, () => ( v.styleWidth));
9959
+ const h = _nullishCoalesce(v.height, () => ( v.styleHeight));
9960
+ if (node.measured && (w !== void 0 || h !== void 0)) {
9961
+ next.measured = { ...node.measured, ...w !== void 0 ? { width: w } : {}, ...h !== void 0 ? { height: h } : {} };
9962
+ }
9963
+ return next;
9964
+ }
9965
+ function writeOverrideGroup(node, group, value) {
9966
+ if (same(readOverrideGroup(node, group), value)) return node;
9967
+ const next = { ...node };
9968
+ const data = { ...dataOf(node) };
9969
+ switch (group) {
9970
+ case "hidden":
9971
+ if (value) next.hidden = true;
9972
+ else delete next.hidden;
9973
+ return next;
9974
+ case "position":
9975
+ if (isRecord(value)) next.position = { x: value.x, y: value.y };
9976
+ return next;
9977
+ case "size":
9978
+ return withSize(node, value);
9979
+ case "component": {
9980
+ const inst = getInstanceData(node);
9981
+ if (!inst || typeof value !== "string") return node;
9982
+ data[INSTANCE_DATA_KEY] = { ...inst, componentId: value };
9983
+ return withData(node, data);
9984
+ }
9985
+ case "props": {
9986
+ const inst = getInstanceData(node);
9987
+ if (!inst) return node;
9988
+ data[INSTANCE_DATA_KEY] = { ...inst, properties: isRecord(value) ? { ...value } : {} };
9989
+ return withData(node, data);
9990
+ }
9991
+ }
9992
+ const [kind, key] = splitGroup(group);
9993
+ if (!key) return node;
9994
+ switch (kind) {
9995
+ case "style": {
9996
+ const unitless = typeof value === "number" && UNITLESS.has(key);
9997
+ next.style = writeNodeStyleProperty(node.style, key, value, unitless);
9998
+ return next;
9999
+ }
10000
+ case "data":
10001
+ if (LINK_KEYS.has(key) || key in NESTED_KEYS) return node;
10002
+ if (value === void 0) delete data[key];
10003
+ else data[key] = value;
10004
+ return withData(node, data);
10005
+ case "node":
10006
+ if (SKIPPED_NODE_KEYS.has(key)) return node;
10007
+ if (value === void 0) delete next[key];
10008
+ else next[key] = value;
10009
+ return next;
10010
+ }
10011
+ const holder = NESTED_PREFIX[kind];
10012
+ if (!holder) return node;
10013
+ const record = isRecord(data[holder]) ? { ...data[holder] } : {};
10014
+ if (value === void 0) delete record[key];
10015
+ else record[key] = value;
10016
+ if (Object.keys(record).length === 0 && (holder === "tokenBindings" || holder === "tokenModes")) delete data[holder];
10017
+ else data[holder] = record;
10018
+ return withData(node, data);
10019
+ }
10020
+ function listGroups(node, out) {
10021
+ out.add("hidden");
10022
+ out.add("size");
10023
+ out.add("position");
10024
+ for (const k of styleKeys(node.style)) if (k !== "width" && k !== "height") out.add(`style.${k}`);
10025
+ const data = dataOf(node);
10026
+ for (const [k, v] of Object.entries(data)) {
10027
+ if (LINK_KEYS.has(k)) continue;
10028
+ const prefix = NESTED_KEYS[k];
10029
+ if (prefix) {
10030
+ if (isRecord(v)) for (const sub3 of Object.keys(v)) out.add(`${prefix}.${sub3}`);
10031
+ continue;
10032
+ }
10033
+ out.add(`data.${k}`);
10034
+ }
10035
+ if (isCanvasInstance(node)) {
10036
+ out.add("component");
10037
+ out.add("props");
10038
+ }
10039
+ for (const k of Object.keys(node)) if (!SKIPPED_NODE_KEYS.has(k)) out.add(`node.${k}`);
10040
+ }
10041
+ function diffOverrideGroups(a, b) {
10042
+ const groups = /* @__PURE__ */ new Set();
10043
+ listGroups(a, groups);
10044
+ listGroups(b, groups);
10045
+ return [...groups].filter((g) => !same(readOverrideGroup(a, g), readOverrideGroup(b, g)));
10046
+ }
10047
+ function copyGroups(from, to, groups) {
10048
+ let next = to;
10049
+ for (const g of groups) next = writeOverrideGroup(next, g, readOverrideGroup(from, g));
10050
+ return next;
10051
+ }
10052
+ function fieldGroup(field) {
10053
+ return field === "visible" ? "hidden" : field;
10054
+ }
10055
+ var Graph = (_class10 = class {
10056
+ constructor(nodes) {;_class10.prototype.__init29.call(this);
10057
+ this.nodes = nodes;
10058
+ this.byId = new Map(nodes.map((n) => [n.id, n]));
10059
+ for (const n of nodes) {
10060
+ if (!n.parentId || !this.byId.has(n.parentId)) continue;
10061
+ let list = this.kids.get(n.parentId);
10062
+ if (!list) this.kids.set(n.parentId, list = []);
10063
+ list.push(n.id);
10064
+ }
10065
+ }
10066
+
10067
+
10068
+ __init29() {this.kids = /* @__PURE__ */ new Map()}
10069
+ get(id) {
10070
+ return id === void 0 ? void 0 : this.byId.get(id);
10071
+ }
10072
+ children(id) {
10073
+ return _nullishCoalesce(this.kids.get(id), () => ( []));
10074
+ }
10075
+ /** `id` (optionally) and its ancestors, nearest first. */
10076
+ chain(id, self = true) {
10077
+ const out = [];
10078
+ const seen = /* @__PURE__ */ new Set();
10079
+ let at = this.get(id);
10080
+ if (at && !self) {
10081
+ seen.add(at.id);
10082
+ at = this.get(at.parentId);
10083
+ }
10084
+ while (at && !seen.has(at.id)) {
10085
+ seen.add(at.id);
10086
+ out.push(at);
10087
+ at = this.get(at.parentId);
10088
+ }
10089
+ return out;
10090
+ }
10091
+ /** Whether `a` is a strict ancestor of `b`. */
10092
+ isAncestor(a, b) {
10093
+ return this.chain(b, false).some((n) => n.id === a);
10094
+ }
10095
+ /** `id` and its descendants, pre-order. */
10096
+ subtree(id) {
10097
+ const out = [];
10098
+ const seen = /* @__PURE__ */ new Set();
10099
+ const stack = [id];
10100
+ while (stack.length) {
10101
+ const at = stack.pop();
10102
+ if (seen.has(at) || !this.byId.has(at)) continue;
10103
+ seen.add(at);
10104
+ out.push(at);
10105
+ const kids = this.children(at);
10106
+ for (let i = kids.length - 1; i >= 0; i--) stack.push(kids[i]);
10107
+ }
10108
+ return out;
10109
+ }
10110
+ }, _class10);
10111
+ var owningComponentIn = (g, id) => _optionalChain([g, 'access', _276 => _276.chain, 'call', _277 => _277(id), 'access', _278 => _278.find, 'call', _279 => _279(isCanvasComponent), 'optionalAccess', _280 => _280.id]);
10112
+ var owningInstanceIn = (g, id) => _optionalChain([g, 'access', _281 => _281.chain, 'call', _282 => _282(id), 'access', _283 => _283.find, 'call', _284 => _284(isCanvasInstance), 'optionalAccess', _285 => _285.id]);
10113
+ var enclosingInstanceIn = (g, id) => _optionalChain([g, 'access', _286 => _286.chain, 'call', _287 => _287(id, false), 'access', _288 => _288.find, 'call', _289 => _289(isCanvasInstance), 'optionalAccess', _290 => _290.id]);
10114
+ function rootInstanceIn(g, id) {
10115
+ const list = g.chain(id).filter(isCanvasInstance);
10116
+ return _optionalChain([list, 'access', _291 => _291[list.length - 1], 'optionalAccess', _292 => _292.id]);
10117
+ }
10118
+ function variantSetIn(g, componentId) {
10119
+ const comp = g.get(componentId);
10120
+ if (!isCanvasComponent(comp)) return void 0;
10121
+ const parent = g.get(comp.parentId);
10122
+ return isCanvasComponentSet(parent) ? parent : void 0;
10123
+ }
10124
+ function getVariantValues(node) {
10125
+ const explicit = _optionalChain([getComponentData, 'call', _293 => _293(node), 'optionalAccess', _294 => _294.variant]);
10126
+ if (isRecord(explicit) && Object.keys(explicit).length) return stringRecord2(explicit);
10127
+ const name = getLayerName(node);
10128
+ return name.includes("=") ? parseVariantName(name) : {};
10129
+ }
10130
+ function parseVariantName(name) {
10131
+ const out = {};
10132
+ for (const part of name.split(",")) {
10133
+ const eq = part.indexOf("=");
10134
+ if (eq < 0) continue;
10135
+ const k = part.slice(0, eq).trim();
10136
+ if (k) out[k] = part.slice(eq + 1).trim();
10137
+ }
10138
+ return out;
10139
+ }
10140
+ function formatVariantName(pairs, order = []) {
10141
+ const keys = order.filter((k) => k in pairs);
10142
+ keys.push(...Object.keys(pairs).filter((k) => !order.includes(k)).sort());
10143
+ return keys.map((k) => `${k}=${pairs[k]}`).join(", ");
10144
+ }
10145
+ function variantsIn(g, setId) {
10146
+ return g.children(setId).map((id) => g.get(id)).filter(isCanvasComponent);
10147
+ }
10148
+ function variantOptionsIn(g, setId) {
10149
+ const out = [];
10150
+ for (const v of variantsIn(g, setId)) {
10151
+ for (const [k, value] of Object.entries(getVariantValues(v))) {
10152
+ let entry = out.find((o) => o.name === k);
10153
+ if (!entry) out.push(entry = { name: k, values: [] });
10154
+ if (!entry.values.includes(value)) entry.values.push(value);
10155
+ }
10156
+ }
10157
+ return out;
10158
+ }
10159
+ function defaultVariantIn(g, setId) {
10160
+ let best;
10161
+ for (const v of variantsIn(g, setId)) {
10162
+ const { x, y } = v.position;
10163
+ const key = [x + y, y, x];
10164
+ if (!best || key[0] < best.key[0] || key[0] === best.key[0] && (key[1] < best.key[1] || key[1] === best.key[1] && key[2] < best.key[2])) {
10165
+ best = { key, id: v.id };
10166
+ }
10167
+ }
10168
+ return _optionalChain([best, 'optionalAccess', _295 => _295.id]);
10169
+ }
10170
+ function findVariantIn(g, setId, wanted) {
10171
+ const entries = Object.entries(wanted);
10172
+ let best;
10173
+ for (const v of variantsIn(g, setId)) {
10174
+ const values = getVariantValues(v);
10175
+ const score = entries.filter(([k, val]) => values[k] === val).length;
10176
+ if (score === entries.length) return v.id;
10177
+ if (!best || score > best.score) best = { score, id: v.id };
10178
+ }
10179
+ return _optionalChain([best, 'optionalAccess', _296 => _296.id]);
10180
+ }
10181
+ function mainOfIn(g, id) {
10182
+ const node = g.get(id);
10183
+ if (isCanvasComponent(node)) return id;
10184
+ if (isCanvasComponentSet(node)) return defaultVariantIn(g, id);
10185
+ return void 0;
10186
+ }
10187
+ var siblingVariants = (g, a, b) => !!a && !!b && a !== b && !!variantSetIn(g, a) && variantSetIn(g, a) === variantSetIn(g, b);
10188
+ function propertyDefsIn(g, componentId) {
10189
+ const comp = g.get(componentId);
10190
+ if (!isCanvasComponent(comp)) return {};
10191
+ const set = variantSetIn(g, componentId);
10192
+ const owner = set ? dataOf(set)[COMPONENT_SET_DATA_KEY] : dataOf(comp)[COMPONENT_DATA_KEY];
10193
+ return isRecord(_optionalChain([owner, 'optionalAccess', _297 => _297.properties])) ? owner.properties : {};
10194
+ }
10195
+ function validValue(def, v) {
10196
+ return def.type === "boolean" ? typeof v === "boolean" : typeof v === "string";
10197
+ }
10198
+ function effectivePropsIn(g, componentId, values) {
10199
+ const out = {};
10200
+ for (const [k, def] of Object.entries(propertyDefsIn(g, componentId))) {
10201
+ const v = _optionalChain([values, 'optionalAccess', _298 => _298[k]]);
10202
+ out[k] = v !== void 0 && validValue(def, v) ? v : def.default;
10203
+ }
10204
+ return out;
10205
+ }
10206
+ function componentDepsIn(g, componentId) {
10207
+ const deps = /* @__PURE__ */ new Set();
10208
+ const queue = [componentId];
10209
+ while (queue.length) {
10210
+ const c = queue.pop();
10211
+ for (const id of g.subtree(c)) {
10212
+ const target = _optionalChain([getInstanceData, 'call', _299 => _299(g.get(id)), 'optionalAccess', _300 => _300.componentId]);
10213
+ if (target && !deps.has(target)) {
10214
+ deps.add(target);
10215
+ queue.push(target);
10216
+ }
10217
+ }
10218
+ }
10219
+ return deps;
10220
+ }
10221
+ function createsCycleIn(g, componentId, parentId) {
10222
+ if (!parentId) return false;
10223
+ const hosts = g.chain(parentId).filter(isCanvasComponent).map((n) => n.id);
10224
+ if (hosts.length === 0) return false;
10225
+ const deps = componentDepsIn(g, componentId);
10226
+ deps.add(componentId);
10227
+ return hosts.some((h) => deps.has(h));
10228
+ }
10229
+ function wouldCreateComponentCycle(nodes, componentId, parentId) {
10230
+ const g = new Graph(nodes);
10231
+ return createsCycleIn(g, _nullishCoalesce(mainOfIn(g, componentId), () => ( componentId)), parentId);
10232
+ }
10233
+ function getOwningComponent(nodes, id) {
10234
+ return owningComponentIn(new Graph(nodes), id);
10235
+ }
10236
+ function getOwningInstance(nodes, id) {
10237
+ return owningInstanceIn(new Graph(nodes), id);
10238
+ }
10239
+ function getRootInstance(nodes, id) {
10240
+ return rootInstanceIn(new Graph(nodes), id);
10241
+ }
10242
+ function isInsideInstance(nodes, id) {
10243
+ return enclosingInstanceIn(new Graph(nodes), id) !== void 0;
10244
+ }
10245
+ function getComponentInstances(nodes, componentId) {
10246
+ return nodes.filter((n) => _optionalChain([getInstanceData, 'call', _301 => _301(n), 'optionalAccess', _302 => _302.componentId]) === componentId).map((n) => n.id);
10247
+ }
10248
+ function getInstanceStatus(nodes, id) {
10249
+ const g = new Graph(nodes);
10250
+ const inst = getInstanceData(g.get(id));
10251
+ if (!inst) return void 0;
10252
+ return isCanvasComponent(g.get(inst.componentId)) ? "linked" : "missing-main";
10253
+ }
10254
+ function getVariantSet(nodes, componentId) {
10255
+ return _optionalChain([variantSetIn, 'call', _303 => _303(new Graph(nodes), componentId), 'optionalAccess', _304 => _304.id]);
10256
+ }
10257
+ function getVariantOptions(nodes, setId) {
10258
+ return variantOptionsIn(new Graph(nodes), setId);
10259
+ }
10260
+ function findVariant(nodes, setId, wanted) {
10261
+ return findVariantIn(new Graph(nodes), setId, wanted);
10262
+ }
10263
+ function getDefaultVariant(nodes, setId) {
10264
+ return defaultVariantIn(new Graph(nodes), setId);
10265
+ }
10266
+ function getVariantConflicts(nodes, setId) {
10267
+ const by = /* @__PURE__ */ new Map();
10268
+ for (const v of variantsIn(new Graph(nodes), setId)) {
10269
+ const key = formatVariantName(getVariantValues(v));
10270
+ by.set(key, [..._nullishCoalesce(by.get(key), () => ( [])), v.id]);
10271
+ }
10272
+ return [...by.values()].filter((ids) => ids.length > 1);
10273
+ }
10274
+ function getComponentPropertyDefs(nodes, componentId) {
10275
+ return { ...propertyDefsIn(new Graph(nodes), componentId) };
10276
+ }
10277
+ function getInstanceProperties(nodes, id) {
10278
+ const g = new Graph(nodes);
10279
+ const inst = getInstanceData(g.get(id));
10280
+ return inst ? effectivePropsIn(g, inst.componentId, inst.properties) : {};
10281
+ }
10282
+ function listCanvasComponents(nodes) {
10283
+ const g = new Graph(nodes);
10284
+ const counts = /* @__PURE__ */ new Map();
10285
+ for (const n of nodes) {
10286
+ const c = _optionalChain([getInstanceData, 'call', _305 => _305(n), 'optionalAccess', _306 => _306.componentId]);
10287
+ if (c) counts.set(c, (_nullishCoalesce(counts.get(c), () => ( 0))) + 1);
10288
+ }
10289
+ const components = [];
10290
+ for (const n of nodes) {
10291
+ if (!isCanvasComponent(n)) continue;
10292
+ const set = variantSetIn(g, n.id);
10293
+ components.push({
10294
+ id: n.id,
10295
+ name: getLayerName(n) || n.id,
10296
+ ...set ? { setId: set.id, variant: getVariantValues(n) } : {},
10297
+ instanceCount: _nullishCoalesce(counts.get(n.id), () => ( 0))
10298
+ });
10299
+ }
10300
+ const sets = nodes.filter(isCanvasComponentSet).map((s) => ({
10301
+ id: s.id,
10302
+ name: getLayerName(s) || s.id,
10303
+ variants: components.filter((c) => c.setId === s.id),
10304
+ options: variantOptionsIn(g, s.id),
10305
+ defaultVariantId: defaultVariantIn(g, s.id)
10306
+ }));
10307
+ return { components, sets };
10308
+ }
10309
+ function inspectCanvasInstance(nodes, id) {
10310
+ const g = new Graph(nodes);
10311
+ const instId = owningInstanceIn(g, id);
10312
+ if (!instId) return void 0;
10313
+ const inst = g.get(instId);
10314
+ const data = getInstanceData(inst);
10315
+ const comp = g.get(data.componentId);
10316
+ const linked = isCanvasComponent(comp);
10317
+ const set = linked ? variantSetIn(g, data.componentId) : void 0;
10318
+ const defs = propertyDefsIn(g, data.componentId);
10319
+ const values = effectivePropsIn(g, data.componentId, data.properties);
10320
+ const overrides = [];
10321
+ for (const d of g.subtree(instId)) {
10322
+ const groups = getNodeOverrides(g.get(d));
10323
+ if (groups.length) overrides.push({ id: d, name: getLayerName(g.get(d)) || d, groups: [...groups] });
10324
+ }
10325
+ return {
10326
+ id: instId,
10327
+ rootId: _nullishCoalesce(rootInstanceIn(g, instId), () => ( instId)),
10328
+ nested: enclosingInstanceIn(g, instId) !== void 0,
10329
+ componentId: data.componentId,
10330
+ ...linked ? { componentName: getLayerName(comp) || comp.id } : {},
10331
+ status: linked ? "linked" : "missing-main",
10332
+ ...set ? { setId: set.id } : {},
10333
+ variant: linked && set ? getVariantValues(comp) : {},
10334
+ variantOptions: set ? variantOptionsIn(g, set.id) : [],
10335
+ properties: Object.entries(defs).map(([name, def]) => ({
10336
+ name,
10337
+ type: def.type,
10338
+ value: values[name],
10339
+ default: def.default,
10340
+ ...def.type === "instanceSwap" ? { preferred: [..._nullishCoalesce(def.preferred, () => ( []))] } : {}
10341
+ })),
10342
+ overrides
10343
+ };
10344
+ }
10345
+ function resolveSync(options = {}) {
10346
+ return {
10347
+ idGenerator: _nullishCoalesce(options.idGenerator, () => ( ((inst, src) => `${inst}:${src}`))),
10348
+ textTypes: _nullishCoalesce(options.textTypes, () => ( ["text"])),
10349
+ layout: options.layout === false ? false : options.layout === true || options.layout === void 0 ? {} : options.layout,
10350
+ tokens: options.tokens
10351
+ };
10352
+ }
10353
+ var stripLook = (data) => {
10354
+ const out = { ...data };
10355
+ for (const k of LINK_KEYS) delete out[k];
10356
+ return out;
10357
+ };
10358
+ function clearRuntime(node, old) {
10359
+ for (const k of RUNTIME_KEYS) {
10360
+ if (old && old[k] !== void 0) node[k] = old[k];
10361
+ else delete node[k];
10362
+ }
10363
+ }
10364
+ function tokenDrivenGroups(n, options) {
10365
+ const mine = stringRecord2(dataOf(n).tokenBindings);
10366
+ const out = [];
10367
+ for (const key of Object.keys(mine)) {
10368
+ const property = getCanvasTokenProperty(key, options);
10369
+ if (!property || !property.appliesTo(n)) continue;
10370
+ const current = property.read(n);
10371
+ const probe = typeof current === "number" ? current + 1 : typeof current === "boolean" ? !current : `${_nullishCoalesce(current, () => ( ""))}`;
10372
+ for (const g of diffOverrideGroups(n, property.write(n, probe))) if (!out.includes(g)) out.push(g);
10373
+ }
10374
+ return out;
10375
+ }
10376
+ function propertyDrivenGroups(g, src) {
10377
+ const out = [];
10378
+ let at = src;
10379
+ for (let i = 0; at && i <= MAX_DEPTH; i++) {
10380
+ for (const field of Object.keys(getComponentPropertyRefs(at))) out.push(fieldGroup(field));
10381
+ at = g.get(getComponentSourceId(at));
10382
+ }
10383
+ return out;
10384
+ }
10385
+ function rootReference(g, comp) {
10386
+ const set = variantSetIn(g, comp.id);
10387
+ if (!set) return comp;
10388
+ const label = dataOf(set).label;
10389
+ return "label" in dataOf(comp) && typeof label === "string" ? withData(comp, { ...dataOf(comp), label }) : comp;
10390
+ }
10391
+ function fixMeasured(node, old) {
10392
+ const measured2 = _nullishCoalesce(_optionalChain([old, 'optionalAccess', _307 => _307.measured]), () => ( node.measured));
10393
+ const size = sizeOf(node);
10394
+ const w = _nullishCoalesce(size.width, () => ( size.styleWidth));
10395
+ const h = _nullishCoalesce(size.height, () => ( size.styleHeight));
10396
+ if (!measured2) {
10397
+ if (node.measured === void 0) return node;
10398
+ const next = { ...node };
10399
+ delete next.measured;
10400
+ return next;
10401
+ }
10402
+ const fixed = { ...measured2, ...w !== void 0 ? { width: w } : {}, ...h !== void 0 ? { height: h } : {} };
10403
+ return same(fixed, node.measured) ? node : { ...node, measured: fixed };
10404
+ }
10405
+ function applyProp(g, node, field, value) {
10406
+ if (field === "visible") return typeof value === "boolean" ? writeOverrideGroup(node, "hidden", !value) : node;
10407
+ if (field === "component") {
10408
+ if (typeof value !== "string" || !isCanvasInstance(node)) return node;
10409
+ const main = mainOfIn(g, value);
10410
+ return main ? writeOverrideGroup(node, "component", main) : node;
10411
+ }
10412
+ if (field.startsWith("data.")) return writeOverrideGroup(node, field, typeof value === "string" ? value : String(value));
10413
+ return node;
10414
+ }
10415
+ function buildInstance(g, instId, opts, taken) {
10416
+ const inst = g.get(instId);
10417
+ const instData = getInstanceData(inst);
10418
+ if (!inst || !instData) return void 0;
10419
+ const compId = instData.componentId;
10420
+ const comp = g.get(compId);
10421
+ if (!comp || !isCanvasComponent(comp) || compId === instId || g.isAncestor(instId, compId) || g.isAncestor(compId, instId)) return void 0;
10422
+ const oldIds = [];
10423
+ const foreign = [];
10424
+ const stack = [...g.children(instId)];
10425
+ while (stack.length) {
10426
+ const id = stack.pop();
10427
+ if (getComponentSourceId(g.get(id)) !== void 0) {
10428
+ oldIds.push(id);
10429
+ stack.push(...g.children(id));
10430
+ } else foreign.push(...g.subtree(id));
10431
+ }
10432
+ const old = new Map(oldIds.map((id) => [id, g.get(id)]));
10433
+ const byParentSource = /* @__PURE__ */ new Map();
10434
+ const bySource = /* @__PURE__ */ new Map();
10435
+ for (const id of oldIds) {
10436
+ const n = old.get(id);
10437
+ const s = getComponentSourceId(n);
10438
+ const key = `${n.parentId}\0${s}`;
10439
+ if (!byParentSource.has(key)) byParentSource.set(key, id);
10440
+ bySource.set(s, bySource.has(s) ? null : id);
10441
+ }
10442
+ let byPath;
10443
+ const oldPaths = () => {
10444
+ const out2 = /* @__PURE__ */ new Map();
10445
+ const walk = (parent, prefix) => {
10446
+ const counts = /* @__PURE__ */ new Map();
10447
+ for (const c of g.children(parent)) {
10448
+ const n = g.get(c);
10449
+ const src = getComponentSourceId(n);
10450
+ if (src === void 0) continue;
10451
+ const name = getLayerName(_nullishCoalesce(g.get(src), () => ( n)));
10452
+ const k = _nullishCoalesce(counts.get(name), () => ( 0));
10453
+ counts.set(name, k + 1);
10454
+ const path = `${prefix}/${k === 0 ? name : `${name}#${k}`}`;
10455
+ if (!out2.has(path)) out2.set(path, c);
10456
+ walk(c, path);
10457
+ }
10458
+ };
10459
+ walk(instId, "");
10460
+ return out2;
10461
+ };
10462
+ const used = /* @__PURE__ */ new Set();
10463
+ const fresh = (sourceId) => {
10464
+ const base = opts.idGenerator(instId, sourceId);
10465
+ let id = base;
10466
+ for (let k = 2; taken.has(id); k++) id = `${base}~${k}`;
10467
+ taken.add(id);
10468
+ return id;
10469
+ };
10470
+ const instProps = /* @__PURE__ */ new Map();
10471
+ const out = [];
10472
+ const isText2 = (n) => typeof n.type === "string" && opts.textTypes.includes(n.type);
10473
+ const copyLayer = (s, o, id, parentId) => {
10474
+ const next = { ...s, id, parentId };
10475
+ const data = stripLook(dataOf(s));
10476
+ if (isCanvasInstance(s)) data[INSTANCE_DATA_KEY] = { ...dataOf(s)[INSTANCE_DATA_KEY] };
10477
+ data[COMPONENT_SOURCE_DATA_KEY] = s.id;
10478
+ next.data = data;
10479
+ clearRuntime(next, o);
10480
+ let n = next;
10481
+ if (o) {
10482
+ let groups = [...getNodeOverrides(o)];
10483
+ const from = g.get(getComponentSourceId(o));
10484
+ if (from && from.id !== s.id && groups.length && !isText2(o) && siblingVariants(g, owningComponentIn(g, from.id), owningComponentIn(g, s.id))) {
10485
+ const differs = new Set(diffOverrideGroups(from, s));
10486
+ groups = groups.filter((gr) => !differs.has(gr));
10487
+ }
10488
+ n = copyGroups(o, n, groups);
10489
+ n = keepLaidOut(s, o, n, groups);
10490
+ n = setOverrides(n, groups);
10491
+ }
10492
+ return fixMeasured(n, o);
10493
+ };
10494
+ const keepLaidOut = (s, o, n, groups) => {
10495
+ if (o.parentId !== n.parentId || groups.includes("size") || groups.includes("position")) return n;
10496
+ const flows = !getChildLayout(n).absolute && !!getAutoLayout(g.get(s.parentId));
10497
+ let next = n;
10498
+ if (flows) next = writeOverrideGroup(next, "position", o.position);
10499
+ const derived = (axis) => {
10500
+ const sizing = getLayoutSizing(next, axis);
10501
+ return sizing === "hug" && !!getAutoLayout(next) || sizing === "fill" && flows;
10502
+ };
10503
+ const size = { ...sizeOf(next) };
10504
+ const oldSize = sizeOf(o);
10505
+ if (derived("width")) {
10506
+ size.width = oldSize.width;
10507
+ size.styleWidth = oldSize.styleWidth;
10508
+ }
10509
+ if (derived("height")) {
10510
+ size.height = oldSize.height;
10511
+ size.styleHeight = oldSize.styleHeight;
10512
+ }
10513
+ return writeOverrideGroup(next, "size", size);
10514
+ };
10515
+ const instanceRoot = (look, place2, old2, id, parentId, sourceId, instance, previousComponent, topLevel) => {
10516
+ const reference = rootReference(g, look);
10517
+ const next = { ...reference, id, position: { ...place2.position } };
10518
+ if (parentId === void 0) delete next.parentId;
10519
+ else next.parentId = parentId;
10520
+ const data = stripLook(dataOf(reference));
10521
+ delete data.tokenModes;
10522
+ data[INSTANCE_DATA_KEY] = { ...instance };
10523
+ data[COMPONENT_SOURCE_DATA_KEY] = sourceId;
10524
+ next.data = data;
10525
+ clearRuntime(next, old2);
10526
+ let n = next;
10527
+ const own = /* @__PURE__ */ new Set();
10528
+ listGroups(place2, own);
10529
+ listGroups(n, own);
10530
+ n = copyGroups(place2, n, [...own].filter((gr) => isOwnRootGroup(gr) && gr !== "component" && gr !== "props"));
10531
+ let groups = old2 ? getNodeOverrides(old2).filter((gr) => !topLevel || !isOwnRootGroup(gr)) : [];
10532
+ if (old2 && previousComponent && siblingVariants(g, previousComponent, look.id)) {
10533
+ const differs = new Set(diffOverrideGroups(g.get(previousComponent), look));
10534
+ groups = groups.filter((gr) => gr === "data.label" || gr === "data.name" || !differs.has(gr));
10535
+ }
10536
+ if (old2) n = copyGroups(old2, n, groups.filter((gr) => gr !== "component" && gr !== "props"));
10537
+ return fixMeasured(setOverrides(n, groups), old2);
10538
+ };
10539
+ const applyChainProps = (n, s, enc) => {
10540
+ const chain = [s];
10541
+ while (chain.length < enc.length) {
10542
+ const next2 = g.get(getComponentSourceId(chain[chain.length - 1]));
10543
+ if (!next2) break;
10544
+ chain.push(next2);
10545
+ }
10546
+ let next = n;
10547
+ for (let j = chain.length - 1; j >= 0; j--) {
10548
+ const props = instProps.get(enc[j]);
10549
+ if (!props) continue;
10550
+ for (const [field, prop] of Object.entries(getComponentPropertyRefs(chain[j]))) {
10551
+ const group = fieldGroup(field);
10552
+ if (getNodeOverrides(next).includes(group) || j > 0 && getNodeOverrides(s).includes(group)) continue;
10553
+ if (prop in props) next = applyProp(g, next, field, props[prop]);
10554
+ }
10555
+ }
10556
+ return next;
10557
+ };
10558
+ const copyChildren = (srcParent, newParent, prefix, enc, expanding, depth) => {
10559
+ const counts = /* @__PURE__ */ new Map();
10560
+ for (const sid of g.children(srcParent)) {
10561
+ const s = g.get(sid);
10562
+ const name = getLayerName(s);
10563
+ const k = _nullishCoalesce(counts.get(name), () => ( 0));
10564
+ counts.set(name, k + 1);
10565
+ const path = `${prefix}/${k === 0 ? name : `${name}#${k}`}`;
10566
+ let oid = byParentSource.get(`${newParent}\0${sid}`);
10567
+ if (oid !== void 0 && used.has(oid)) oid = void 0;
10568
+ if (oid === void 0) {
10569
+ const u = bySource.get(sid);
10570
+ if (u && !used.has(u)) oid = u;
10571
+ }
10572
+ if (oid === void 0) {
10573
+ byPath ??= oldPaths();
10574
+ const p = byPath.get(path);
10575
+ if (p && !used.has(p)) oid = p;
10576
+ }
10577
+ if (oid !== void 0) used.add(oid);
10578
+ const o = oid !== void 0 ? old.get(oid) : void 0;
10579
+ const id = _nullishCoalesce(oid, () => ( fresh(sid)));
10580
+ let n = applyChainProps(copyLayer(s, o, id, newParent), s, enc);
10581
+ const nested = getInstanceData(n);
10582
+ if (nested && depth < MAX_DEPTH) {
10583
+ const target = nested.componentId;
10584
+ instProps.set(id, effectivePropsIn(g, target, nested.properties));
10585
+ if (_optionalChain([getInstanceData, 'call', _308 => _308(s), 'optionalAccess', _309 => _309.componentId]) !== target) {
10586
+ const main = g.get(target);
10587
+ if (isCanvasComponent(main) && !expanding.includes(target) && !g.isAncestor(target, instId)) {
10588
+ const previousComponent = o ? _optionalChain([getInstanceData, 'call', _310 => _310(o), 'optionalAccess', _311 => _311.componentId]) : void 0;
10589
+ n = applyChainProps(instanceRoot(main, s, o, id, newParent, sid, nested, previousComponent, false), s, enc);
10590
+ out.push(n);
10591
+ copyChildren(target, id, path, [id], [...expanding, target], depth + 1);
10592
+ continue;
10593
+ }
10594
+ }
10595
+ out.push(n);
10596
+ copyChildren(sid, id, path, [...enc, id], expanding, depth);
10597
+ continue;
10598
+ }
10599
+ out.push(n);
10600
+ copyChildren(sid, id, path, enc, expanding, depth);
10601
+ }
10602
+ };
10603
+ const root = instanceRoot(comp, inst, inst, instId, inst.parentId, compId, instData, getComponentSourceId(inst), true);
10604
+ instProps.set(instId, effectivePropsIn(g, compId, instData.properties));
10605
+ copyChildren(compId, instId, "", [instId], [compId], 0);
10606
+ const placed = /* @__PURE__ */ new Set([instId, ...out.map((n) => n.id)]);
10607
+ const keptForeign = [];
10608
+ for (const id of foreign) {
10609
+ const n = g.get(id);
10610
+ if (n.parentId && placed.has(n.parentId)) {
10611
+ placed.add(id);
10612
+ keptForeign.push(n);
10613
+ }
10614
+ }
10615
+ const removed = /* @__PURE__ */ new Set([instId, ...oldIds, ...foreign]);
10616
+ let block = [root, ...out, ...keptForeign];
10617
+ const compSize = getNodeSize(comp);
10618
+ const rootSize = getNodeSize(root);
10619
+ if (!getAutoLayout(root) && (Math.abs(compSize.width - rootSize.width) > 1e-9 || Math.abs(compSize.height - rootSize.height) > 1e-9)) {
10620
+ const fixed = new Set(out.filter((n) => getNodeOverrides(n).some((gr) => gr === "size" || gr === "position")).map((n) => n.id));
10621
+ const updates = applyConstraints(block, instId, compSize, opts.layout || {}).filter((u) => !fixed.has(u.id));
10622
+ block = applyNodeUpdates(block, updates);
10623
+ }
10624
+ if (opts.layout) {
10625
+ const frames = block.filter((n) => getAutoLayout(n)).map((n) => n.id);
10626
+ if (frames.length) block = applyNodeUpdates(block, layoutUpMany(block, frames, opts.layout));
10627
+ }
10628
+ block = block.map((n) => {
10629
+ const prev = g.get(n.id);
10630
+ return prev && prev !== n && same(prev, n) ? prev : n;
10631
+ });
10632
+ return { block, removed };
10633
+ }
10634
+ function rebuildBatch(nodes, ids, opts) {
10635
+ const g = new Graph(nodes);
10636
+ const taken = new Set(g.byId.keys());
10637
+ const built = /* @__PURE__ */ new Map();
10638
+ for (const id of ids) {
10639
+ const root = g.get(id) ? _nullishCoalesce(rootInstanceIn(g, id), () => ( id)) : void 0;
10640
+ if (!root || built.has(root)) continue;
10641
+ const b = buildInstance(g, root, opts, taken);
10642
+ if (b) built.set(root, b);
10643
+ }
10644
+ if (built.size === 0) return nodes;
10645
+ const removed = /* @__PURE__ */ new Set();
10646
+ for (const b of built.values()) for (const id of b.removed) removed.add(id);
10647
+ let result = [];
10648
+ for (const n of nodes) {
10649
+ const b = built.get(n.id);
10650
+ if (b) result.push(...b.block);
10651
+ else if (!removed.has(n.id)) result.push(n);
10652
+ }
10653
+ if (opts.layout) {
10654
+ const lookup = new Map(result.map((n) => [n.id, n]));
10655
+ const inFrames = [...built.keys()].filter((r) => {
10656
+ const parent = lookup.get(_nullishCoalesce(_optionalChain([lookup, 'access', _312 => _312.get, 'call', _313 => _313(r), 'optionalAccess', _314 => _314.parentId]), () => ( "")));
10657
+ return !!getAutoLayout(parent);
10658
+ });
10659
+ if (inFrames.length) result = applyNodeUpdates(result, layoutUpMany(result, inFrames, opts.layout));
10660
+ }
10661
+ return result.length === nodes.length && result.every((n, i) => n === nodes[i]) ? nodes : result;
10662
+ }
10663
+ function rebuildInstances(nodes, comps, resync, opts) {
10664
+ let current = nodes;
10665
+ if (resync.size) {
10666
+ current = rebuildBatch(current, resync, opts);
10667
+ const after = new Graph(current);
10668
+ for (const r of resync) {
10669
+ const c = after.get(r) ? owningComponentIn(after, r) : void 0;
10670
+ if (c) comps.add(c);
10671
+ }
10672
+ }
10673
+ if (comps.size === 0) return current;
10674
+ const g = new Graph(current);
10675
+ const rootsOf = /* @__PURE__ */ new Map();
10676
+ for (const n of current) {
10677
+ const inst = getInstanceData(n);
10678
+ if (!inst) continue;
10679
+ const root = _nullishCoalesce(rootInstanceIn(g, n.id), () => ( n.id));
10680
+ let set = rootsOf.get(inst.componentId);
10681
+ if (!set) rootsOf.set(inst.componentId, set = /* @__PURE__ */ new Set());
10682
+ set.add(root);
10683
+ }
10684
+ const level = new Map([...comps].map((c) => [c, 0]));
10685
+ const outer = /* @__PURE__ */ new Map();
10686
+ let frontier = [...comps];
10687
+ for (let rounds = 0; frontier.length && rounds < 64; rounds++) {
10688
+ const next = [];
10689
+ for (const c of frontier) {
10690
+ const lc = _nullishCoalesce(level.get(c), () => ( 0));
10691
+ for (const r of _nullishCoalesce(rootsOf.get(c), () => ( []))) {
10692
+ if (!outer.has(r)) outer.set(r, owningComponentIn(g, r));
10693
+ const x = outer.get(r);
10694
+ if (x && x !== c && (_nullishCoalesce(level.get(x), () => ( -1))) < lc + 1) {
10695
+ level.set(x, lc + 1);
10696
+ next.push(x);
10697
+ }
10698
+ }
10699
+ }
10700
+ frontier = next;
10701
+ }
10702
+ const batches = /* @__PURE__ */ new Map();
10703
+ for (const [r, o] of outer) {
10704
+ const l = o !== void 0 ? _nullishCoalesce(level.get(o), () => ( Number.MAX_SAFE_INTEGER)) : Number.MAX_SAFE_INTEGER;
10705
+ batches.set(l, [..._nullishCoalesce(batches.get(l), () => ( [])), r]);
10706
+ }
10707
+ for (const l of [...batches.keys()].sort((a, b) => a - b)) current = rebuildBatch(current, batches.get(l), opts);
10708
+ return current;
10709
+ }
10710
+ function finish(original, result, opts) {
10711
+ let out = result;
10712
+ if (_optionalChain([opts, 'access', _315 => _315.tokens, 'optionalAccess', _316 => _316.state])) out = resolveCanvasTokens(out, opts.tokens.state, opts.tokens);
10713
+ if (out.length === original.length && out.every((n, i) => n === original[i])) return original;
10714
+ return out;
10715
+ }
10716
+ function syncCanvasInstance(nodes, instanceId, options = {}) {
10717
+ const opts = resolveSync(options);
10718
+ return finish(nodes, rebuildInstances([...nodes], /* @__PURE__ */ new Set(), /* @__PURE__ */ new Set([instanceId]), opts), opts);
10719
+ }
10720
+ function syncAllCanvasInstances(nodes, options = {}) {
10721
+ const opts = resolveSync(options);
10722
+ const comps = new Set(nodes.filter(isCanvasComponent).map((n) => n.id));
10723
+ return finish(nodes, rebuildInstances([...nodes], comps, /* @__PURE__ */ new Set(), opts), opts);
10724
+ }
10725
+ function rebaseInstance(nodes, instId, tokens) {
10726
+ const g = new Graph(nodes);
10727
+ const inst = getInstanceData(g.get(instId));
10728
+ if (!inst) return nodes;
10729
+ const compId = inst.componentId;
10730
+ const comp = g.get(compId);
10731
+ const theirs = /* @__PURE__ */ new Map();
10732
+ const mine = /* @__PURE__ */ new Map();
10733
+ const paths = (root2, viaSource, into, flip) => {
10734
+ const walk = (parent, prefix) => {
10735
+ const counts = /* @__PURE__ */ new Map();
10736
+ for (const c of g.children(parent)) {
10737
+ const n = g.get(c);
10738
+ const name = getLayerName(viaSource && g.get(getComponentSourceId(n)) || n);
10739
+ const k = _nullishCoalesce(counts.get(name), () => ( 0));
10740
+ counts.set(name, k + 1);
10741
+ const path = `${prefix}/${k === 0 ? name : `${name}#${k}`}`;
10742
+ if (flip) {
10743
+ if (!into.has(path)) into.set(path, c);
10744
+ } else into.set(c, path);
10745
+ walk(c, path);
10746
+ }
10747
+ };
10748
+ walk(root2, "");
10749
+ };
10750
+ if (comp) paths(compId, false, theirs, true);
10751
+ paths(instId, true, mine, false);
10752
+ const updates = /* @__PURE__ */ new Map();
10753
+ for (const [id, path] of mine) {
10754
+ const n = g.get(id);
10755
+ let main;
10756
+ let cur = getComponentSourceId(n);
10757
+ for (let i = 0; cur && i < MAX_DEPTH; i++) {
10758
+ if (cur !== compId && g.get(cur) && g.isAncestor(compId, cur)) {
10759
+ main = cur;
10760
+ break;
10761
+ }
10762
+ cur = getComponentSourceId(g.get(cur));
10763
+ }
10764
+ main ??= comp ? theirs.get(path) : void 0;
10765
+ const m = g.get(main);
10766
+ let next = n;
10767
+ if (m) {
10768
+ const bound = /* @__PURE__ */ new Set([...propertyDrivenGroups(g, m), ...tokenDrivenGroups(n, tokens)]);
10769
+ const groups = new Set(getNodeOverrides(n).filter((gr) => gr !== "component" && gr !== "props"));
10770
+ for (const gr of diffOverrideGroups(m, n)) if (gr !== "size" && gr !== "position" && !bound.has(gr)) groups.add(gr);
10771
+ if (isCanvasInstance(m) && isCanvasInstance(n) && getInstanceData(m).componentId !== getInstanceData(n).componentId) groups.add("component");
10772
+ next = setOverrides(withData(n, { ...dataOf(n), [COMPONENT_SOURCE_DATA_KEY]: m.id }), groups);
10773
+ } else next = unlinked(n);
10774
+ if (next !== n) updates.set(id, next);
10775
+ }
10776
+ const root = g.get(instId);
10777
+ let nextRoot = withData(root, { ...dataOf(root), [COMPONENT_SOURCE_DATA_KEY]: compId });
10778
+ if (comp) {
10779
+ const ref = rootReference(g, comp);
10780
+ const driven = new Set(tokenDrivenGroups(root, tokens));
10781
+ const groups = new Set(getNodeOverrides(root).filter((gr) => !isOwnRootGroup(gr)));
10782
+ for (const gr of diffOverrideGroups(ref, root)) if (!isOwnRootGroup(gr) && !driven.has(gr)) groups.add(gr);
10783
+ nextRoot = setOverrides(nextRoot, groups);
10784
+ }
10785
+ updates.set(instId, nextRoot);
10786
+ return nodes.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
10787
+ }
10788
+ function sizeFromLayout(g, node) {
10789
+ const parentFlows = !!getAutoLayout(g.get(node.parentId)) && !getChildLayout(node).absolute;
10790
+ return ["width", "height"].some((axis) => {
10791
+ const sizing = getLayoutSizing(node, axis);
10792
+ return sizing === "hug" && !!getAutoLayout(node) || sizing === "fill" && parentFlows;
10793
+ });
10794
+ }
10795
+ function syncCanvasComponents(before, after, options = {}) {
10796
+ if (before === after) return after;
10797
+ const opts = resolveSync(options);
10798
+ const prev = new Graph(before);
10799
+ let nodes = [...after];
10800
+ const resync = /* @__PURE__ */ new Set();
10801
+ const afterIds = new Set(after.map((n) => n.id));
10802
+ const restore = [];
10803
+ for (const b of before) {
10804
+ if (afterIds.has(b.id) || getComponentSourceId(b) === void 0 || isCanvasInstance(b) && !enclosingInstanceIn(prev, b.id)) continue;
10805
+ const root = rootInstanceIn(prev, b.id);
10806
+ if (!root || root === b.id || !afterIds.has(root)) continue;
10807
+ restore.push(b);
10808
+ }
10809
+ if (restore.length) {
10810
+ const restoring = new Set(restore.map((n) => n.id));
10811
+ for (const b of restore) nodes.push(b.parentId && restoring.has(b.parentId) ? b : writeOverrideGroup(b, "hidden", true));
10812
+ for (const b of restore) {
10813
+ const r = rootInstanceIn(prev, b.id);
10814
+ if (r) resync.add(r);
10815
+ }
10816
+ }
10817
+ let g = new Graph(nodes);
10818
+ const added = nodes.filter((n) => !prev.byId.has(n.id));
10819
+ if (added.length) {
10820
+ const addedIds = new Set(added.map((n) => n.id));
10821
+ const moves = /* @__PURE__ */ new Map();
10822
+ for (const n of added) {
10823
+ if (!n.parentId || addedIds.has(n.parentId)) continue;
10824
+ const r = rootInstanceIn(g, n.parentId);
10825
+ if (!r || addedIds.has(r)) continue;
10826
+ const rootNode = g.get(r);
10827
+ const abs = getAbsolutePosition(n, g.byId);
10828
+ const parent = g.get(rootNode.parentId);
10829
+ const base = parent ? getAbsolutePosition(parent, g.byId) : { x: 0, y: 0 };
10830
+ const moved = { ...n, position: { x: abs.x - base.x, y: abs.y - base.y } };
10831
+ if (rootNode.parentId) moved.parentId = rootNode.parentId;
10832
+ else delete moved.parentId;
10833
+ moves.set(n.id, moved);
10834
+ }
10835
+ if (moves.size) {
10836
+ nodes = nodes.map((n) => _nullishCoalesce(moves.get(n.id), () => ( n)));
10837
+ g = new Graph(nodes);
10838
+ }
10839
+ const rebase = [];
10840
+ const strips = /* @__PURE__ */ new Map();
10841
+ for (const n of added) {
10842
+ const cur = g.get(n.id);
10843
+ if (isCanvasInstance(cur)) {
10844
+ if (enclosingInstanceIn(g, n.id) === void 0 && getComponentSourceId(cur) !== getInstanceData(cur).componentId) rebase.push(n.id);
10845
+ continue;
10846
+ }
10847
+ if (getComponentSourceId(cur) === void 0 && getNodeOverrides(cur).length === 0) continue;
10848
+ const r = rootInstanceIn(g, n.id);
10849
+ if (!r || !addedIds.has(r) || moves.has(n.id)) strips.set(n.id, unlinked(cur, true));
10850
+ }
10851
+ if (strips.size) nodes = nodes.map((n) => _nullishCoalesce(strips.get(n.id), () => ( n)));
10852
+ for (const id of rebase) nodes = rebaseInstance(nodes, id, opts.tokens);
10853
+ g = new Graph(nodes);
10854
+ }
10855
+ const overrideUpdates = /* @__PURE__ */ new Map();
10856
+ for (const n of nodes) {
10857
+ const b = prev.get(n.id);
10858
+ if (!b || b === n) continue;
10859
+ const inst = owningInstanceIn(g, n.id);
10860
+ if (!inst || getComponentSourceId(n) === void 0 && inst !== n.id) continue;
10861
+ const topRoot = inst === n.id && enclosingInstanceIn(g, n.id) === void 0;
10862
+ const bi = getInstanceData(b);
10863
+ const ni = getInstanceData(n);
10864
+ const raw = diffOverrideGroups(b, n);
10865
+ if (topRoot) {
10866
+ if (bi && ni && (bi.componentId !== ni.componentId || !same(_nullishCoalesce(bi.properties, () => ( {})), _nullishCoalesce(ni.properties, () => ( {}))))) resync.add(n.id);
10867
+ if (raw.includes("size")) resync.add(n.id);
10868
+ }
10869
+ let groups = raw.filter((gr) => gr !== "position" && (gr !== "size" || topRoot && !sizeFromLayout(g, n)));
10870
+ if (topRoot) groups = groups.filter((gr) => !isOwnRootGroup(gr));
10871
+ let cleared = [];
10872
+ const srcId = topRoot ? _optionalChain([ni, 'optionalAccess', _317 => _317.componentId]) : getComponentSourceId(n);
10873
+ const src = g.get(srcId);
10874
+ if (src) {
10875
+ const reference = topRoot ? rootReference(g, src) : src;
10876
+ const differs = new Set(diffOverrideGroups(reference, n));
10877
+ const driven = new Set(tokenDrivenGroups(n, opts.tokens));
10878
+ groups = groups.filter((gr) => differs.has(gr) && !driven.has(gr));
10879
+ cleared = raw.filter((gr) => gr !== "size" && gr !== "position" && !differs.has(gr) && getNodeOverrides(n).includes(gr));
10880
+ if (topRoot) cleared = cleared.filter((gr) => !isOwnRootGroup(gr));
10881
+ }
10882
+ const lost = getNodeOverrides(b).some((gr) => !getNodeOverrides(n).includes(gr));
10883
+ const nestedSwitch = !topRoot && raw.some((gr) => gr === "component" || gr === "props");
10884
+ if (groups.length || cleared.length) {
10885
+ const set = new Set(getNodeOverrides(n));
10886
+ for (const gr of groups) set.add(gr);
10887
+ for (const gr of cleared) set.delete(gr);
10888
+ const updated = setOverrides(n, set);
10889
+ if (updated !== n) overrideUpdates.set(n.id, updated);
10890
+ }
10891
+ if (lost || nestedSwitch) {
10892
+ const r = rootInstanceIn(g, n.id);
10893
+ if (r) resync.add(r);
10894
+ }
10895
+ }
10896
+ if (overrideUpdates.size) {
10897
+ nodes = nodes.map((n) => _nullishCoalesce(overrideUpdates.get(n.id), () => ( n)));
10898
+ g = new Graph(nodes);
10899
+ }
10900
+ const comps = /* @__PURE__ */ new Set();
10901
+ for (const n of nodes) {
10902
+ const b = prev.get(n.id);
10903
+ if (b === n) continue;
10904
+ const c = owningComponentIn(g, n.id);
10905
+ if (isCanvasComponentSet(n) && (!b || !same(dataOf(b)[COMPONENT_SET_DATA_KEY], dataOf(n)[COMPONENT_SET_DATA_KEY]))) {
10906
+ for (const v of variantsIn(g, n.id)) comps.add(v.id);
10907
+ }
10908
+ if (!c) continue;
10909
+ if (!b) {
10910
+ comps.add(c);
10911
+ continue;
10912
+ }
10913
+ const structural = b.parentId !== n.parentId || !same(dataOf(b)[COMPONENT_DATA_KEY], dataOf(n)[COMPONENT_DATA_KEY]) || !same(getComponentPropertyRefs(b), getComponentPropertyRefs(n)) || getComponentSourceId(b) !== getComponentSourceId(n) || !same(getNodeOverrides(b), getNodeOverrides(n));
10914
+ const diff = diffOverrideGroups(b, n);
10915
+ if (!structural && (diff.length === 0 || n.id === c && diff.every(isOwnRootGroup))) continue;
10916
+ comps.add(c);
10917
+ }
10918
+ for (const b of before) {
10919
+ if (afterIds.has(b.id)) continue;
10920
+ const c = owningComponentIn(prev, b.id);
10921
+ if (c && c !== b.id && g.get(c)) comps.add(c);
10922
+ }
10923
+ {
10924
+ const order = (list) => {
10925
+ const m = /* @__PURE__ */ new Map();
10926
+ for (const n of list) if (n.parentId) m.set(n.parentId, [..._nullishCoalesce(m.get(n.parentId), () => ( [])), n.id]);
10927
+ return m;
10928
+ };
10929
+ const ob = order(before);
10930
+ const oa = order(nodes);
10931
+ for (const [parent, kids] of oa) {
10932
+ if (same(ob.get(parent), kids)) continue;
10933
+ const c = owningComponentIn(g, parent);
10934
+ if (c && !owningInstanceIn(g, parent)) comps.add(c);
10935
+ }
10936
+ }
10937
+ nodes = rebuildInstances(nodes, comps, resync, opts);
10938
+ return finish(after, nodes, opts);
10939
+ }
10940
+ function fail(nodes, code, reason) {
10941
+ return { ok: false, nodes, code, reason };
10942
+ }
10943
+ function done(before, after, ids, options) {
10944
+ return { ok: true, nodes: syncCanvasComponents(before, after, options), ids };
10945
+ }
10946
+ function uniqueId(base, taken) {
10947
+ let id = base;
10948
+ for (let k = 2; taken.has(id); k++) id = `${base}-${k}`;
10949
+ return id;
10950
+ }
10951
+ function sizedStyle(like, width, height) {
10952
+ return typeof like === "string" ? `width: ${width}px; height: ${height}px` : { width, height };
10953
+ }
10954
+ function wrapInFrame(nodes, ids, frame) {
10955
+ const g = new Graph(nodes);
10956
+ const roots = ids.map((id) => g.get(id));
10957
+ let minX = Infinity;
10958
+ let minY = Infinity;
10959
+ let maxX = -Infinity;
10960
+ let maxY = -Infinity;
10961
+ for (const n of roots) {
10962
+ const { width: width2, height: height2 } = getNodeSize(n);
10963
+ minX = Math.min(minX, n.position.x);
10964
+ minY = Math.min(minY, n.position.y);
10965
+ maxX = Math.max(maxX, n.position.x + width2);
10966
+ maxY = Math.max(maxY, n.position.y + height2);
10967
+ }
10968
+ minX -= frame.padding;
10969
+ minY -= frame.padding;
10970
+ maxX += frame.padding;
10971
+ maxY += frame.padding;
10972
+ const width = maxX - minX;
10973
+ const height = maxY - minY;
10974
+ const parentId = roots[0].parentId;
10975
+ const wrapper = {
10976
+ id: frame.id,
10977
+ type: frame.type,
10978
+ position: { x: minX, y: minY },
10979
+ width,
10980
+ height,
10981
+ style: sizedStyle(roots[0].style, width, height),
10982
+ data: frame.data,
10983
+ ...parentId ? { parentId } : {}
10984
+ };
10985
+ const selected = new Set(ids);
10986
+ const firstIndex = nodes.findIndex((n) => selected.has(n.id));
10987
+ const out = [];
10988
+ nodes.forEach((n, i) => {
10989
+ if (i === firstIndex) out.push(wrapper);
10990
+ out.push(selected.has(n.id) ? { ...n, parentId: frame.id, position: { x: n.position.x - minX, y: n.position.y - minY } } : n);
10991
+ });
10992
+ return out;
10993
+ }
10994
+ function createCanvasComponent(nodes, ids, options = {}) {
10995
+ const g = new Graph(nodes);
10996
+ const picked = [...new Set(ids)].filter((id2) => g.get(id2));
10997
+ const roots = picked.filter((id2) => !picked.some((o) => o !== id2 && g.isAncestor(o, id2)));
10998
+ if (roots.length === 0) return fail(nodes, "not-found", "Select the layers to make a component.");
10999
+ if (roots.some((id2) => enclosingInstanceIn(g, id2) !== void 0)) {
11000
+ return fail(nodes, "inside-instance", "Layers inside an instance can't become components: detach the instance first.");
11001
+ }
11002
+ if (roots.some((id2) => isCanvasComponent(g.get(id2)) || isCanvasComponentSet(g.get(id2)))) {
11003
+ return fail(nodes, "invalid", "The selection is already a component.");
11004
+ }
11005
+ if (new Set(roots.map((id2) => _nullishCoalesce(g.get(id2).parentId, () => ( "")))).size > 1) return fail(nodes, "invalid", "Select layers that share a parent.");
11006
+ const frameTypes = _nullishCoalesce(options.frameTypes, () => ( ["group", "frame"]));
11007
+ if (roots.length === 1) {
11008
+ const node = g.get(roots[0]);
11009
+ const frameLike = !isCanvasInstance(node) && (g.children(node.id).length > 0 || typeof node.type === "string" && frameTypes.includes(node.type) || !!getAutoLayout(node));
11010
+ if (frameLike) {
11011
+ const after2 = nodes.map((n) => n.id === node.id ? withData(n, { ...dataOf(n), [COMPONENT_DATA_KEY]: {} }) : n);
11012
+ return done(nodes, after2, [node.id], options);
11013
+ }
11014
+ }
11015
+ const id = _nullishCoalesce(options.id, () => ( uniqueId("component", g.byId)));
11016
+ const name = _nullishCoalesce(options.name, () => ( (roots.length === 1 ? getLayerName(g.get(roots[0])) || "Component" : "Component")));
11017
+ const after = wrapInFrame([...nodes], roots, { id, type: _nullishCoalesce(options.frameType, () => ( "group")), data: { label: name, [COMPONENT_DATA_KEY]: {} }, padding: 0 });
11018
+ return done(nodes, after, [id], options);
11019
+ }
11020
+ function combineCanvasComponentsAsVariants(nodes, ids, options = {}) {
11021
+ const g = new Graph(nodes);
11022
+ const picked = [...new Set(ids)].filter((id2) => g.get(id2));
11023
+ if (picked.length === 0) return fail(nodes, "not-found", "Select components to combine.");
11024
+ if (!picked.every((id2) => isCanvasComponent(g.get(id2)))) return fail(nodes, "invalid", "Select components only.");
11025
+ if (picked.some((id2) => variantSetIn(g, id2))) return fail(nodes, "invalid", "A component is already a variant of a set.");
11026
+ if (picked.some((id2) => owningInstanceIn(g, id2))) return fail(nodes, "inside-instance", "Components inside an instance can't be combined.");
11027
+ if (new Set(picked.map((id2) => _nullishCoalesce(g.get(id2).parentId, () => ( "")))).size > 1) return fail(nodes, "invalid", "Select components that share a parent.");
11028
+ const ordered = nodes.filter((n) => picked.includes(n.id)).map((n) => n.id);
11029
+ const first = g.get(ordered[0]);
11030
+ const firstName = getLayerName(first);
11031
+ const name = _nullishCoalesce(options.name, () => ( (firstName && !firstName.includes("=") ? firstName.split("/")[0].trim() : "Component")));
11032
+ const id = _nullishCoalesce(options.id, () => ( uniqueId("component-set", g.byId)));
11033
+ let after = wrapInFrame([...nodes], ordered, {
11034
+ id,
11035
+ type: _nullishCoalesce(options.frameType, () => ( "group")),
11036
+ data: { label: name, [COMPONENT_SET_DATA_KEY]: {} },
11037
+ padding: _nullishCoalesce(options.padding, () => ( 20))
11038
+ });
11039
+ const order = [];
11040
+ for (const vid of ordered) for (const k of Object.keys(getVariantValues(g.get(vid)))) if (!order.includes(k)) order.push(k);
11041
+ after = after.map((n) => {
11042
+ const k = ordered.indexOf(n.id);
11043
+ if (k < 0) return n;
11044
+ let variant = getVariantValues(n);
11045
+ if (Object.keys(variant).length === 0) variant = { "Property 1": k === 0 ? "Default" : `Variant${k + 1}` };
11046
+ const comp = { ..._nullishCoalesce(getComponentData(n), () => ( {})), variant };
11047
+ return withData(n, { ...dataOf(n), [COMPONENT_DATA_KEY]: comp, label: formatVariantName(variant, order) });
11048
+ });
11049
+ return done(nodes, after, [id], options);
11050
+ }
11051
+ function createCanvasInstance(nodes, componentId, options = {}) {
11052
+ const g = new Graph(nodes);
11053
+ const main = mainOfIn(g, componentId);
11054
+ if (!main) return fail(nodes, "not-found", "Choose a component or component set.");
11055
+ const parentId = options.parentId;
11056
+ if (parentId !== void 0 && !g.get(parentId)) return fail(nodes, "not-found", `Unknown parent "${parentId}".`);
11057
+ if (createsCycleIn(g, main, parentId)) return fail(nodes, "cycle", "An instance can't be placed inside its own main component.");
11058
+ if (parentId !== void 0 && owningInstanceIn(g, parentId)) return fail(nodes, "inside-instance", "Instances can't gain layers: place it outside the instance.");
11059
+ const comp = g.get(main);
11060
+ const id = _nullishCoalesce(options.id, () => ( uniqueId(`${main}-instance`, g.byId)));
11061
+ if (g.get(id)) return fail(nodes, "invalid", `Id "${id}" is taken.`);
11062
+ let position = options.position;
11063
+ if (!position) {
11064
+ if (parentId !== void 0) position = { x: 0, y: 0 };
11065
+ else {
11066
+ const top = g.chain(main).pop();
11067
+ position = { x: getAbsolutePosition(top, g.byId).x + getNodeSize(top).width + 40, y: getAbsolutePosition(comp, g.byId).y };
11068
+ }
11069
+ }
11070
+ const root = {
11071
+ id,
11072
+ type: comp.type,
11073
+ position: { ...position },
11074
+ data: { [INSTANCE_DATA_KEY]: { componentId: main, properties: effectivePropsIn(g, main, void 0) }, [COMPONENT_SOURCE_DATA_KEY]: main },
11075
+ ...parentId !== void 0 ? { parentId } : {}
11076
+ };
11077
+ const opts = resolveSync(options);
11078
+ let after = rebuildBatch([...nodes, root], [id], opts);
11079
+ if (options.properties && Object.keys(options.properties).length) {
11080
+ const set = setCanvasInstanceProperties(after, [id], options.properties, { ...options, tokens: void 0 });
11081
+ if (!set.ok) return fail(nodes, set.code, set.reason);
11082
+ after = set.nodes;
11083
+ }
11084
+ return { ok: true, nodes: finish(nodes, after, opts), ids: [id] };
11085
+ }
11086
+ function detachCanvasInstance(nodes, ids, options = {}) {
11087
+ let current = [...nodes];
11088
+ const doneIds = [];
11089
+ for (const id of new Set(ids)) {
11090
+ const g = new Graph(current);
11091
+ if (!isCanvasInstance(g.get(id))) continue;
11092
+ if (enclosingInstanceIn(g, id) !== void 0) {
11093
+ return fail(nodes, "nested-instance", "A nested instance can't be detached on its own: detach the outer instance first.");
11094
+ }
11095
+ const nested = [];
11096
+ const updates = /* @__PURE__ */ new Map();
11097
+ for (const d of g.subtree(id)) {
11098
+ if (d === id || enclosingInstanceIn(g, d) !== id) continue;
11099
+ if (isCanvasInstance(g.get(d))) nested.push(d);
11100
+ else updates.set(d, unlinked(g.get(d)));
11101
+ }
11102
+ const root = g.get(id);
11103
+ const data = { ...dataOf(root) };
11104
+ delete data[INSTANCE_DATA_KEY];
11105
+ delete data[COMPONENT_SOURCE_DATA_KEY];
11106
+ delete data[COMPONENT_OVERRIDES_DATA_KEY];
11107
+ updates.set(id, withData(root, data));
11108
+ current = current.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
11109
+ for (const nn of nested) current = rebaseInstance(current, nn, options.tokens);
11110
+ doneIds.push(id);
11111
+ }
11112
+ if (doneIds.length === 0) return fail(nodes, "invalid", "Select an instance.");
11113
+ return done(nodes, current, doneIds, options);
11114
+ }
11115
+ function resetCanvasInstanceOverrides(nodes, id, group, options = {}) {
11116
+ const g = new Graph(nodes);
11117
+ const node = g.get(id);
11118
+ const inst = node ? owningInstanceIn(g, id) : void 0;
11119
+ if (!node || !inst) return fail(nodes, "not-found", "Select an instance or a layer inside one.");
11120
+ const top = inst === id && enclosingInstanceIn(g, id) === void 0;
11121
+ const updates = /* @__PURE__ */ new Map();
11122
+ const resetProps = (n) => {
11123
+ const data = getInstanceData(n);
11124
+ const defaults = effectivePropsIn(g, data.componentId, void 0);
11125
+ return same(_nullishCoalesce(data.properties, () => ( {})), defaults) ? n : withData(n, { ...dataOf(n), [INSTANCE_DATA_KEY]: { ...data, properties: defaults } });
11126
+ };
11127
+ if (group !== void 0) {
11128
+ let next = setOverrides(node, getNodeOverrides(node).filter((gr) => gr !== group));
11129
+ if (top && group === "props") next = resetProps(next);
11130
+ updates.set(id, next);
11131
+ } else if (inst === id) {
11132
+ for (const d of g.subtree(id)) {
11133
+ const n = g.get(d);
11134
+ const keep = d === id && top ? getNodeOverrides(n).filter((gr) => gr === "size") : [];
11135
+ updates.set(d, setOverrides(n, keep));
11136
+ }
11137
+ if (top) updates.set(id, resetProps(updates.get(id)));
11138
+ } else updates.set(id, setOverrides(node, []));
11139
+ const after = nodes.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
11140
+ const changed = after.some((n, i) => n !== nodes[i]);
11141
+ if (!changed) return { ok: true, nodes, ids: [] };
11142
+ const synced = syncCanvasComponents(nodes, after, options);
11143
+ return { ok: true, nodes: synced, ids: [inst] };
11144
+ }
11145
+ function pushCanvasInstanceOverrides(nodes, id, options = {}) {
11146
+ const g = new Graph(nodes);
11147
+ const inst = g.get(id) ? rootInstanceIn(g, id) : void 0;
11148
+ if (!inst) return fail(nodes, "not-found", "Select an instance.");
11149
+ const compId = getInstanceData(g.get(inst)).componentId;
11150
+ if (!isCanvasComponent(g.get(compId))) return fail(nodes, "missing-main", "The main component was deleted: restore it first.");
11151
+ const updates = /* @__PURE__ */ new Map();
11152
+ let pushed = 0;
11153
+ for (const d of g.subtree(inst)) {
11154
+ const n = g.get(d);
11155
+ const overrides = getNodeOverrides(n);
11156
+ if (overrides.length === 0) continue;
11157
+ const src = d === inst ? compId : getComponentSourceId(n);
11158
+ if (!src || !g.get(src) || src !== compId && !g.isAncestor(compId, src)) continue;
11159
+ const groups = overrides.filter(
11160
+ (gr) => gr !== "size" && gr !== "position" && gr !== "component" && gr !== "props" && !(d === inst && (gr === "data.label" || gr === "data.name" || isOwnRootGroup(gr)))
11161
+ );
11162
+ if (groups.length === 0) continue;
11163
+ pushed++;
11164
+ updates.set(src, copyGroups(n, _nullishCoalesce(updates.get(src), () => ( g.get(src))), groups));
11165
+ updates.set(d, setOverrides(n, overrides.filter((gr) => !groups.includes(gr))));
11166
+ }
11167
+ if (pushed === 0) return fail(nodes, "no-overrides", "The instance has no changes to push.");
11168
+ const after = nodes.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
11169
+ return done(nodes, after, [inst], options);
11170
+ }
11171
+ function swapCanvasInstance(nodes, ids, componentId, options = {}) {
11172
+ const g = new Graph(nodes);
11173
+ const main = mainOfIn(g, componentId);
11174
+ if (!main) return fail(nodes, "not-found", "Choose a component or component set.");
11175
+ const updates = /* @__PURE__ */ new Map();
11176
+ const list = [...new Set(ids)];
11177
+ for (const id of list) {
11178
+ const n = g.get(id);
11179
+ const inst = getInstanceData(n);
11180
+ if (!n || !inst) return fail(nodes, "invalid", `"${id}" is not an instance.`);
11181
+ if (g.isAncestor(main, id) || createsCycleIn(g, main, n.parentId)) return fail(nodes, "cycle", "An instance can't show the component it is inside.");
11182
+ const defaults = effectivePropsIn(g, main, void 0);
11183
+ const properties = {};
11184
+ for (const [k, d] of Object.entries(defaults)) properties[k] = _optionalChain([inst, 'access', _318 => _318.properties, 'optionalAccess', _319 => _319[k]]) !== void 0 && typeof inst.properties[k] === typeof d ? inst.properties[k] : d;
11185
+ updates.set(id, withData(n, { ...dataOf(n), [INSTANCE_DATA_KEY]: { ...inst, componentId: main, properties } }));
11186
+ if (options.keepTextOverridesOnly) {
11187
+ for (const d of g.subtree(id)) {
11188
+ const layer = _nullishCoalesce(updates.get(d), () => ( g.get(d)));
11189
+ const text = typeof layer.type === "string" && (_nullishCoalesce(options.textTypes, () => ( ["text"]))).includes(layer.type);
11190
+ const keep = getNodeOverrides(layer).filter((gr) => text || d === id && gr === "size");
11191
+ updates.set(d, setOverrides(layer, keep));
11192
+ }
11193
+ }
11194
+ }
11195
+ if (list.length === 0) return fail(nodes, "invalid", "Select an instance.");
11196
+ const after = nodes.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
11197
+ return done(nodes, after, list, options);
11198
+ }
11199
+ function setCanvasInstanceProperties(nodes, ids, properties, options = {}) {
11200
+ const g = new Graph(nodes);
11201
+ const updates = /* @__PURE__ */ new Map();
11202
+ const list = [...new Set(ids)];
11203
+ if (list.length === 0) return fail(nodes, "invalid", "Select an instance.");
11204
+ for (const id of list) {
11205
+ const n = g.get(id);
11206
+ const inst = getInstanceData(n);
11207
+ if (!n || !inst) return fail(nodes, "invalid", `"${id}" is not an instance.`);
11208
+ const set = variantSetIn(g, inst.componentId);
11209
+ const options_ = set ? variantOptionsIn(g, set.id) : [];
11210
+ const wanted = { ...getVariantValues(g.get(inst.componentId)) };
11211
+ const rest = [];
11212
+ for (const [k, v] of Object.entries(properties)) {
11213
+ const option = options_.find((o) => o.name === k);
11214
+ if (option) {
11215
+ const value = typeof v === "string" ? v : String(v);
11216
+ if (!option.values.includes(value)) return fail(nodes, "invalid", `"${k}" must be one of ${option.values.join(", ")}.`);
11217
+ wanted[k] = value;
11218
+ } else rest.push([k, v]);
11219
+ }
11220
+ let target = inst.componentId;
11221
+ if (set && !same(wanted, getVariantValues(g.get(inst.componentId)))) target = _nullishCoalesce(findVariantIn(g, set.id, wanted), () => ( target));
11222
+ const defs = propertyDefsIn(g, target);
11223
+ const values = { ..._nullishCoalesce(inst.properties, () => ( {})) };
11224
+ for (const [k, v] of rest) {
11225
+ const def = defs[k];
11226
+ if (!def) {
11227
+ const known = [...Object.keys(defs), ...options_.map((o) => o.name)];
11228
+ return fail(nodes, "unknown-property", `Unknown property "${k}"${known.length ? ` (known: ${known.join(", ")})` : ""}.`);
11229
+ }
11230
+ if (def.type === "boolean") {
11231
+ const b = typeof v === "boolean" ? v : v === "true" ? true : v === "false" ? false : void 0;
11232
+ if (b === void 0) return fail(nodes, "type-mismatch", `"${k}" takes true or false.`);
11233
+ values[k] = b;
11234
+ } else if (def.type === "text") {
11235
+ if (typeof v !== "string" && typeof v !== "number") return fail(nodes, "type-mismatch", `"${k}" takes text.`);
11236
+ values[k] = String(v);
11237
+ } else {
11238
+ const main = typeof v === "string" ? mainOfIn(g, v) : void 0;
11239
+ if (!main) return fail(nodes, "type-mismatch", `"${k}" takes a component id.`);
11240
+ if (main === target || componentDepsIn(g, main).has(target) || createsCycleIn(g, main, n.parentId)) {
11241
+ return fail(nodes, "cycle", `"${k}" can't show a component that contains this one.`);
11242
+ }
11243
+ values[k] = main;
11244
+ }
11245
+ }
11246
+ const properties2 = effectivePropsIn(g, target, values);
11247
+ updates.set(id, withData(n, { ...dataOf(n), [INSTANCE_DATA_KEY]: { ...inst, componentId: target, properties: properties2 } }));
11248
+ }
11249
+ const after = nodes.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
11250
+ return done(nodes, after, list, options);
11251
+ }
11252
+ function setCanvasComponentProperty(nodes, componentId, name, def, options = {}) {
11253
+ const g = new Graph(nodes);
11254
+ const target = g.get(componentId);
11255
+ const compId = isCanvasComponentSet(target) ? void 0 : owningComponentIn(g, componentId);
11256
+ const owner = isCanvasComponentSet(target) ? target : compId ? _nullishCoalesce(variantSetIn(g, compId), () => ( g.get(compId))) : void 0;
11257
+ if (!owner) return fail(nodes, "not-found", "Select a component or component set.");
11258
+ const key = isCanvasComponentSet(owner) ? COMPONENT_SET_DATA_KEY : COMPONENT_DATA_KEY;
11259
+ const ownerData = { ..._nullishCoalesce(dataOf(owner)[key], () => ( {})) };
11260
+ const defs = { ..._nullishCoalesce(ownerData.properties, () => ( {})) };
11261
+ const finalName = (_nullishCoalesce(options.newName, () => ( name))).trim();
11262
+ if (!finalName) return fail(nodes, "invalid", "Property names must not be empty.");
11263
+ if (isCanvasComponentSet(owner) && variantOptionsIn(g, owner.id).some((o) => o.name === finalName)) {
11264
+ return fail(nodes, "invalid", `"${finalName}" is a variant property.`);
11265
+ }
11266
+ if (finalName !== name && defs[finalName]) return fail(nodes, "invalid", `"${finalName}" exists already.`);
11267
+ if (def === null) {
11268
+ if (!defs[name]) return fail(nodes, "unknown-property", `Unknown property "${name}".`);
11269
+ delete defs[name];
11270
+ } else {
11271
+ if (def.type === "boolean" && typeof def.default !== "boolean") return fail(nodes, "type-mismatch", "A boolean property needs a boolean default.");
11272
+ if (def.type === "text" && typeof def.default !== "string") return fail(nodes, "type-mismatch", "A text property needs a text default.");
11273
+ if (def.type === "instanceSwap" && !mainOfIn(g, def.default)) return fail(nodes, "type-mismatch", "An instance swap property needs a component as default.");
11274
+ if (finalName !== name) delete defs[name];
11275
+ defs[finalName] = def;
11276
+ }
11277
+ ownerData.properties = defs;
11278
+ const comps = isCanvasComponentSet(owner) ? variantsIn(g, owner.id).map((v) => v.id) : [owner.id];
11279
+ const updates = /* @__PURE__ */ new Map();
11280
+ updates.set(owner.id, withData(owner, { ...dataOf(owner), [key]: ownerData }));
11281
+ const renamed = def === null ? null : finalName;
11282
+ if (renamed !== name) {
11283
+ for (const c of comps) {
11284
+ for (const d of g.subtree(c)) {
11285
+ const n = _nullishCoalesce(updates.get(d), () => ( g.get(d)));
11286
+ const refs = { ...getComponentPropertyRefs(n) };
11287
+ let touched = false;
11288
+ for (const [field, prop] of Object.entries(refs)) {
11289
+ if (prop !== name) continue;
11290
+ touched = true;
11291
+ if (renamed === null) delete refs[field];
11292
+ else refs[field] = renamed;
11293
+ }
11294
+ if (!touched) continue;
11295
+ const data = { ...dataOf(n), [COMPONENT_PROPERTY_REFS_DATA_KEY]: refs };
11296
+ if (Object.keys(refs).length === 0) delete data[COMPONENT_PROPERTY_REFS_DATA_KEY];
11297
+ updates.set(d, withData(n, data));
11298
+ }
11299
+ }
11300
+ for (const n of nodes) {
11301
+ const inst = getInstanceData(n);
11302
+ if (!inst || !comps.includes(inst.componentId) || !inst.properties || !(name in inst.properties)) continue;
11303
+ const props = { ...inst.properties };
11304
+ const v = props[name];
11305
+ delete props[name];
11306
+ if (renamed !== null) props[renamed] = v;
11307
+ const cur = _nullishCoalesce(updates.get(n.id), () => ( n));
11308
+ updates.set(n.id, withData(cur, { ...dataOf(cur), [INSTANCE_DATA_KEY]: { ...inst, properties: props } }));
11309
+ }
11310
+ }
11311
+ const after = nodes.map((n) => _nullishCoalesce(updates.get(n.id), () => ( n)));
11312
+ return done(nodes, after, [owner.id], options);
11313
+ }
11314
+ function bindCanvasComponentProperty(nodes, layerId, field, name, options = {}) {
11315
+ const g = new Graph(nodes);
11316
+ const layer = g.get(layerId);
11317
+ const compId = layer ? owningComponentIn(g, layerId) : void 0;
11318
+ if (!layer || !compId || compId === layerId) return fail(nodes, "not-found", "Select a layer of a main component.");
11319
+ const inst = enclosingInstanceIn(g, layerId);
11320
+ if (inst && g.isAncestor(compId, inst)) return fail(nodes, "inside-instance", "Layers of a nested instance can't be bound: bind the nested instance's own main.");
11321
+ const refs = { ...getComponentPropertyRefs(layer) };
11322
+ if (name === null) delete refs[field];
11323
+ else {
11324
+ const def = propertyDefsIn(g, compId)[name];
11325
+ if (!def) return fail(nodes, "unknown-property", `Unknown property "${name}".`);
11326
+ const ok = def.type === "boolean" && field === "visible" || def.type === "text" && field.startsWith("data.") || def.type === "instanceSwap" && field === "component" && isCanvasInstance(layer);
11327
+ if (!ok) return fail(nodes, "type-mismatch", `A ${def.type} property can't drive "${field}".`);
11328
+ refs[field] = name;
11329
+ }
11330
+ const data = { ...dataOf(layer) };
11331
+ if (Object.keys(refs).length) data[COMPONENT_PROPERTY_REFS_DATA_KEY] = refs;
11332
+ else delete data[COMPONENT_PROPERTY_REFS_DATA_KEY];
11333
+ const after = nodes.map((n) => n.id === layerId ? withData(n, data) : n);
11334
+ return done(nodes, after, [layerId], options);
11335
+ }
11336
+ function restoreCanvasMainComponent(nodes, id, options = {}) {
11337
+ const g = new Graph(nodes);
11338
+ const inst = getInstanceData(g.get(id));
11339
+ if (!inst) return fail(nodes, "invalid", "Select an instance.");
11340
+ if (g.get(inst.componentId)) return fail(nodes, "invalid", "The main component still exists.");
11341
+ if (enclosingInstanceIn(g, id) !== void 0) return fail(nodes, "nested-instance", "Select the outer instance.");
11342
+ const compId = inst.componentId;
11343
+ const sub3 = g.subtree(id);
11344
+ const map = /* @__PURE__ */ new Map([[id, compId]]);
11345
+ const taken = new Set(nodes.map((n) => n.id));
11346
+ taken.add(compId);
11347
+ for (const d of sub3) {
11348
+ if (d === id) continue;
11349
+ const src = enclosingInstanceIn(g, d) === id ? getComponentSourceId(g.get(d)) : void 0;
11350
+ if (src && !taken.has(src)) {
11351
+ map.set(d, src);
11352
+ taken.add(src);
11353
+ }
11354
+ }
11355
+ const nested = [];
11356
+ const replaced = /* @__PURE__ */ new Map();
11357
+ for (const d of sub3) {
11358
+ let n = g.get(d);
11359
+ const nid = _nullishCoalesce(map.get(d), () => ( d));
11360
+ const parentId = n.parentId !== void 0 ? _nullishCoalesce(map.get(n.parentId), () => ( n.parentId)) : void 0;
11361
+ n = { ...n, id: nid, ...parentId !== void 0 ? { parentId } : {} };
11362
+ if (d === id) {
11363
+ const defs = {};
11364
+ for (const [k, v] of Object.entries(_nullishCoalesce(inst.properties, () => ( {})))) {
11365
+ if (typeof v === "boolean") defs[k] = { type: "boolean", default: v };
11366
+ else if (typeof v === "string" && isCanvasComponent(g.get(v))) defs[k] = { type: "instanceSwap", default: v };
11367
+ else if (typeof v === "string") defs[k] = { type: "text", default: v };
11368
+ }
11369
+ const data = { ...dataOf(n) };
11370
+ delete data[INSTANCE_DATA_KEY];
11371
+ delete data[COMPONENT_SOURCE_DATA_KEY];
11372
+ delete data[COMPONENT_OVERRIDES_DATA_KEY];
11373
+ data[COMPONENT_DATA_KEY] = Object.keys(defs).length ? { properties: defs } : {};
11374
+ n = withData(n, data);
11375
+ } else if (enclosingInstanceIn(g, d) === id) {
11376
+ if (isCanvasInstance(n)) nested.push(nid);
11377
+ else n = unlinked(n);
11378
+ }
11379
+ replaced.set(d, n);
11380
+ }
11381
+ let after = nodes.map((n) => _nullishCoalesce(replaced.get(n.id), () => ( n)));
11382
+ for (const nn of nested) after = rebaseInstance(after, nn, options.tokens);
11383
+ return done(nodes, after, [compId], options);
11384
+ }
11385
+
11386
+ // src/canvas/componentsController.ts
11387
+ function makePatch(from, to) {
11388
+ const fromIds = new Map(from.map((n) => [n.id, n]));
11389
+ const toIds = new Set(to.map((n) => n.id));
11390
+ const changes = /* @__PURE__ */ new Map();
11391
+ for (const n of to) if (fromIds.get(n.id) !== n) changes.set(n.id, n);
11392
+ for (const n of from) if (!toIds.has(n.id)) changes.set(n.id, null);
11393
+ return { changes, order: to.map((n) => n.id) };
11394
+ }
11395
+ function applyPatch(current, patch) {
11396
+ const byId = new Map(current.map((n) => [n.id, n]));
11397
+ for (const [id, n] of patch.changes) {
11398
+ if (n) byId.set(id, n);
11399
+ else byId.delete(id);
11400
+ }
11401
+ const out = [];
11402
+ const placed = /* @__PURE__ */ new Set();
11403
+ for (const id of patch.order) {
11404
+ const n = byId.get(id);
11405
+ if (n && !placed.has(id)) {
11406
+ out.push(n);
11407
+ placed.add(id);
11408
+ }
11409
+ }
11410
+ for (const n of current) if (!placed.has(n.id) && byId.has(n.id)) out.push(byId.get(n.id));
11411
+ return out;
11412
+ }
11413
+ function createCanvasComponentsController(options) {
11414
+ let synced;
11415
+ const syncOptions = () => ({
11416
+ idGenerator: options.idGenerator,
11417
+ textTypes: options.textTypes,
11418
+ layout: options.layout,
11419
+ tokens: options.tokens
11420
+ });
11421
+ const selection = (ids) => ids ? [...ids] : _nullishCoalesce(_optionalChain([options, 'access', _320 => _320.getSelectedIds, 'optionalCall', _321 => _321()]), () => ( options.getNodes().filter((n) => n.selected).map((n) => n.id)));
11422
+ const target = (id) => _nullishCoalesce(id, () => ( selection()[0]));
11423
+ function set(next) {
11424
+ synced = next;
11425
+ options.setNodes(next);
11426
+ }
11427
+ function sync() {
11428
+ const nodes2 = options.getNodes();
11429
+ if (synced === void 0 || nodes2 === synced) {
11430
+ synced = nodes2;
11431
+ return nodes2;
11432
+ }
11433
+ const next = syncCanvasComponents(synced, nodes2, syncOptions());
11434
+ synced = next;
11435
+ if (next !== nodes2) options.setNodes(next);
11436
+ return next;
11437
+ }
11438
+ function run(name, op) {
11439
+ const before = sync();
11440
+ const result = op(before);
11441
+ if (!result.ok || result.nodes === before) return result;
11442
+ const forward = makePatch(before, result.nodes);
11443
+ const backward = makePatch(result.nodes, before);
11444
+ const execute = () => set(applyPatch(options.getNodes(), forward));
11445
+ const undo = () => set(applyPatch(options.getNodes(), backward));
11446
+ if (options.history) options.history.execute({ name, execute, undo });
11447
+ else execute();
11448
+ return result;
11449
+ }
11450
+ const reason = (result) => result.ok ? true : result.reason;
11451
+ const nodes = () => options.getNodes();
11452
+ const controller = {
11453
+ sync,
11454
+ /** Rebuilds every instance from its main (e.g. after loading), not recorded in history. */
11455
+ syncAll() {
11456
+ const next = syncAllCanvasInstances(nodes(), syncOptions());
11457
+ if (next !== nodes()) set(next);
11458
+ else synced = next;
11459
+ return next;
11460
+ },
11461
+ /** Create Component from `ids` (default: the selection). */
11462
+ createComponent(ids, createOptions = {}) {
11463
+ const list = selection(ids);
11464
+ return run("Create Component", (n) => createCanvasComponent(n, list, { ...syncOptions(), ...createOptions }));
11465
+ },
11466
+ canCreateComponent: (ids) => reason(createCanvasComponent(nodes(), selection(ids), { layout: false })),
11467
+ /** Combine as Variants: wraps the selected components in a component set. */
11468
+ combineAsVariants(ids, combineOptions = {}) {
11469
+ const list = selection(ids);
11470
+ return run("Combine as Variants", (n) => combineCanvasComponentsAsVariants(n, list, { ...syncOptions(), ...combineOptions }));
11471
+ },
11472
+ canCombineAsVariants: (ids) => reason(combineCanvasComponentsAsVariants(nodes(), selection(ids), { layout: false })),
11473
+ /** Create Instance of a component or component set. */
11474
+ createInstance(componentId, createOptions = {}) {
11475
+ return run("Create Instance", (n) => createCanvasInstance(n, componentId, { ...syncOptions(), ...createOptions }));
11476
+ },
11477
+ canCreateInstance(componentId, parentId) {
11478
+ const list = nodes();
11479
+ const target2 = componentId ? list.find((n) => n.id === componentId) : void 0;
11480
+ if (!target2 || !isCanvasComponent(target2) && !isCanvasComponentSet(target2)) return "Choose a component or component set.";
11481
+ if (wouldCreateComponentCycle(list, componentId, parentId)) return "An instance can't be placed inside its own main component.";
11482
+ if (parentId && getOwningInstance(list, parentId)) return "Instances can't gain layers: place it outside the instance.";
11483
+ return true;
11484
+ },
11485
+ /** Detach Instance (default: the selected instances). */
11486
+ detachInstance(ids) {
11487
+ const list = selection(ids);
11488
+ return run("Detach Instance", (n) => detachCanvasInstance(n, list, syncOptions()));
11489
+ },
11490
+ canDetachInstance(ids) {
11491
+ const list = nodes();
11492
+ const instances = selection(ids).filter((id) => getInstanceData(list.find((n) => n.id === id)));
11493
+ if (instances.length === 0) return "Select an instance.";
11494
+ if (instances.some((id) => isInsideInstance(list, id))) return "A nested instance can't be detached on its own: detach the outer instance first.";
11495
+ return true;
11496
+ },
11497
+ /** Reset overrides of an instance or layer (default: the first selected); `group` resets one. */
11498
+ resetOverrides(id, group) {
11499
+ const at = target(id);
11500
+ if (!at) return { ok: false, nodes: nodes(), code: "not-found", reason: "Select an instance or a layer inside one." };
11501
+ return run(group ? "Reset Override" : "Reset All Changes", (n) => resetCanvasInstanceOverrides(n, at, group, syncOptions()));
11502
+ },
11503
+ canResetOverrides(id) {
11504
+ const at = target(id);
11505
+ const info = at ? inspectCanvasInstance(nodes(), at) : void 0;
11506
+ if (!info) return "Select an instance or a layer inside one.";
11507
+ const changedProps = !info.nested && info.properties.some((p) => p.value !== p.default);
11508
+ const own = info.id === at ? info.overrides.length > 0 : getNodeOverrides(nodes().find((n) => n.id === at)).length > 0;
11509
+ return own || info.id === at && changedProps ? true : "No overrides to reset.";
11510
+ },
11511
+ /** Push the (outermost) instance's overrides to its main component. */
11512
+ pushOverrides(id) {
11513
+ const at = target(id);
11514
+ if (!at) return { ok: false, nodes: nodes(), code: "not-found", reason: "Select an instance." };
11515
+ return run("Push Changes to Main Component", (n) => pushCanvasInstanceOverrides(n, at, syncOptions()));
11516
+ },
11517
+ canPushOverrides(id) {
11518
+ const at = target(id);
11519
+ return at ? reason(pushCanvasInstanceOverrides(nodes(), at, { layout: false })) : "Select an instance.";
11520
+ },
11521
+ /** Swap the selected instances to another component (or a set's default variant). */
11522
+ swapInstance(componentId, ids, swapOptions = {}) {
11523
+ const list = selection(ids);
11524
+ return run("Swap Instance", (n) => swapCanvasInstance(n, list, componentId, { ...syncOptions(), ...swapOptions }));
11525
+ },
11526
+ canSwapInstance(componentId, ids) {
11527
+ const list = nodes();
11528
+ const instances = selection(ids).filter((id) => getInstanceData(list.find((n) => n.id === id)));
11529
+ if (instances.length === 0) return "Select an instance.";
11530
+ if (componentId === void 0) return true;
11531
+ const main = list.find((n) => n.id === componentId);
11532
+ if (!main || !isCanvasComponent(main) && !isCanvasComponentSet(main)) return "Choose a component or component set.";
11533
+ for (const id of instances) {
11534
+ const node = list.find((n) => n.id === id);
11535
+ if (wouldCreateComponentCycle(list, componentId, node.parentId)) return "An instance can't show the component it is inside.";
11536
+ }
11537
+ return true;
11538
+ },
11539
+ /** Set variant / component property values on the selected instances (one step). */
11540
+ setInstanceProperties(properties, ids) {
11541
+ const list = selection(ids);
11542
+ return run("Set Instance Properties", (n) => setCanvasInstanceProperties(n, list, properties, syncOptions()));
11543
+ },
11544
+ canSetInstanceProperties(ids) {
11545
+ const list = nodes();
11546
+ const sel = selection(ids);
11547
+ return sel.length > 0 && sel.every((id) => getInstanceData(list.find((n) => n.id === id))) ? true : "Select instances.";
11548
+ },
11549
+ /** Restore Main Component from an instance whose main was deleted. */
11550
+ restoreMainComponent(id) {
11551
+ const at = target(id);
11552
+ if (!at) return { ok: false, nodes: nodes(), code: "not-found", reason: "Select an instance." };
11553
+ return run("Restore Main Component", (n) => restoreCanvasMainComponent(n, at, syncOptions()));
11554
+ },
11555
+ canRestoreMainComponent(id) {
11556
+ const at = target(id);
11557
+ return at ? reason(restoreCanvasMainComponent(nodes(), at, { layout: false })) : "Select an instance.";
11558
+ },
11559
+ /** Adds, edits or (with `null`) deletes a component property. */
11560
+ setComponentProperty(componentId, name, def, propertyOptions = {}) {
11561
+ return run(
11562
+ def ? "Edit Component Property" : "Delete Component Property",
11563
+ (n) => setCanvasComponentProperty(n, componentId, name, def, { ...syncOptions(), ...propertyOptions })
11564
+ );
11565
+ },
11566
+ /** Binds (or with `null` unbinds) a main layer's field to a component property. */
11567
+ bindComponentProperty(layerId, field, name) {
11568
+ return run("Bind Component Property", (n) => bindCanvasComponentProperty(n, layerId, field, name, syncOptions()));
11569
+ },
11570
+ /** Selects the main component of an instance (or of the instance a layer is in). */
11571
+ goToMainComponent(id) {
11572
+ const at = target(id);
11573
+ const list = sync();
11574
+ const inst = at ? getOwningInstance(list, at) : void 0;
11575
+ const main = inst ? _optionalChain([getInstanceData, 'call', _322 => _322(list.find((n) => n.id === inst)), 'optionalAccess', _323 => _323.componentId]) : void 0;
11576
+ const node = main ? list.find((n) => n.id === main) : void 0;
11577
+ if (!node) return void 0;
11578
+ const next = list.map((n) => !!n.selected === (n.id === main) ? n : { ...n, selected: n.id === main });
11579
+ set(next);
11580
+ _optionalChain([options, 'access', _324 => _324.onReveal, 'optionalCall', _325 => _325(next.find((n) => n.id === main))]);
11581
+ return main;
11582
+ },
11583
+ canGoToMainComponent(id) {
11584
+ const at = target(id);
11585
+ const list = nodes();
11586
+ const inst = at ? getOwningInstance(list, at) : void 0;
11587
+ if (!inst) return "Select an instance.";
11588
+ const main = getInstanceData(list.find((n) => n.id === inst)).componentId;
11589
+ return list.some((n) => n.id === main) ? true : "The main component was deleted.";
11590
+ },
11591
+ /** Components and component sets, for a components panel. */
11592
+ list: () => listCanvasComponents(nodes()),
11593
+ /** The instance inspector's view of an instance or a layer inside one (default: the selection). */
11594
+ inspect: (id) => {
11595
+ const at = target(id);
11596
+ return at ? inspectCanvasInstance(nodes(), at) : void 0;
11597
+ },
11598
+ /** The outermost instance containing `id`. */
11599
+ rootInstanceOf: (id) => getRootInstance(nodes(), id)
11600
+ };
11601
+ return controller;
11602
+ }
11603
+ var CANVAS_COMPONENT_DRAG_TYPE = "application/x-pixerate-component";
11604
+ function getCanvasComponentDragId(dataTransfer) {
11605
+ const id = _optionalChain([dataTransfer, 'optionalAccess', _326 => _326.getData, 'call', _327 => _327(CANVAS_COMPONENT_DRAG_TYPE)]);
11606
+ return id ? id : void 0;
11607
+ }
11608
+
11609
+
11610
+
11611
+
11612
+
11613
+
11614
+
11615
+
11616
+
11617
+
11618
+
11619
+
11620
+
11621
+
11622
+
11623
+
11624
+
11625
+
11626
+
11627
+
11628
+
11629
+
11630
+
11631
+
11632
+
11633
+
11634
+
11635
+
11636
+
11637
+
11638
+
11639
+
11640
+
11641
+
11642
+
11643
+
11644
+
11645
+
11646
+
11647
+
11648
+
11649
+
11650
+
11651
+
11652
+
11653
+
11654
+
11655
+
11656
+
11657
+
11658
+
11659
+
11660
+
11661
+
11662
+
11663
+
11664
+
11665
+
11666
+
11667
+
11668
+
11669
+
11670
+
11671
+
11672
+
11673
+
11674
+
11675
+
11676
+
11677
+
11678
+
11679
+
11680
+
11681
+
11682
+
11683
+
11684
+
11685
+
11686
+
11687
+
11688
+
11689
+
11690
+
11691
+
11692
+
11693
+
11694
+
11695
+
11696
+
11697
+
11698
+
11699
+
11700
+
11701
+
11702
+
11703
+
11704
+
11705
+
11706
+
11707
+
11708
+
11709
+
11710
+
11711
+
11712
+
11713
+
11714
+
11715
+
11716
+
11717
+
11718
+
11719
+
11720
+
11721
+
11722
+
11723
+
11724
+
11725
+
11726
+
11727
+
11728
+
11729
+
11730
+
11731
+
11732
+
11733
+
11734
+
11735
+
11736
+
11737
+
7840
11738
 
7841
11739
 
7842
11740
 
@@ -8056,5 +11954,5 @@ function pruneCanvasTokenModes(nodes, state) {
8056
11954
 
8057
11955
 
8058
11956
 
8059
- exports.AUTO_LAYOUT_DATA_KEY = AUTO_LAYOUT_DATA_KEY; exports.CANVAS_TOKEN_PROPERTIES = CANVAS_TOKEN_PROPERTIES; 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.PathOpsError = PathOpsError; 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.TOKEN_BINDINGS_DATA_KEY = TOKEN_BINDINGS_DATA_KEY; exports.TOKEN_MODES_DATA_KEY = TOKEN_MODES_DATA_KEY; exports.alignNodes = alignNodes; exports.applyConstraints = applyConstraints; exports.applyNodeUpdates = applyNodeUpdates; exports.applyShapeCombination = applyShapeCombination; exports.applyShapeReplacement = applyShapeReplacement; exports.arcToCubics = arcToCubics; exports.bezierPathArea = bezierPathArea; exports.bezierPathBounds = bezierPathBounds; exports.bezierPathLength = bezierPathLength; exports.bezierPathPointAtLength = bezierPathPointAtLength; exports.bezierPathSignedArea = bezierPathSignedArea; exports.bezierPathToSvg = bezierPathToSvg; exports.bindCanvasToken = bindCanvasToken; exports.blendLayout = blendLayout; exports.boundsOf = _chunkWADCJ7A7cjs.boundsOf; exports.calculateDagreReflowDisplacement = calculateDagreReflowDisplacement; exports.calculateDirectionalDisplacement = calculateDirectionalDisplacement; exports.canCombineShapeNodes = canCombineShapeNodes; exports.canOffsetShapeNodes = canOffsetShapeNodes; exports.canOutlineShapeNodeStrokes = canOutlineShapeNodeStrokes; exports.canvasHeight = canvasHeight; exports.centerNodes = _chunkWADCJ7A7cjs.centerNodes; exports.centre = _chunkWADCJ7A7cjs.centre; exports.clampLayoutSize = clampLayoutSize; exports.closeContour = closeContour; exports.collectDescendantIds = collectDescendantIds; exports.combineShapeNodes = combineShapeNodes; exports.computeNodesBoundingBox = computeNodesBoundingBox; exports.computeSnapGuides = computeSnapGuides; exports.connectedOnly = connectedOnly; exports.contourSignedArea = contourSignedArea; exports.contoursToPath = contoursToPath; exports.countPathSegments = countPathSegments; 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.dashContours = dashContours; exports.defaultEasing = defaultEasing; exports.detachTokenBindings = detachTokenBindings; exports.distanceToBezierPath = distanceToBezierPath; exports.distributeNodes = distributeNodes; exports.dividePaths = dividePaths; exports.dividePolygons = dividePolygons; exports.ensureLayout = _chunkWADCJ7A7cjs.ensureLayout; exports.estimateCanvasHeight = estimateCanvasHeight; exports.estimateNodeSize = _chunkWADCJ7A7cjs.estimateNodeSize; exports.excludePaths = excludePaths; 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.getBindableTokenProperties = getBindableTokenProperties; exports.getCanvasTokenProperty = getCanvasTokenProperty; exports.getCenteredNodePosition = _chunkWADCJ7A7cjs.getCenteredNodePosition; exports.getChildLayout = getChildLayout; exports.getEffectiveTokenModes = getEffectiveTokenModes; exports.getFlowChildren = getFlowChildren; exports.getLayoutParent = getLayoutParent; exports.getLayoutSizing = getLayoutSizing; exports.getLayoutedNodes = _chunkWADCJ7A7cjs.getLayoutedNodes; exports.getNodeRect = getNodeRect; exports.getNodeShape = getNodeShape; exports.getNodeSize = getNodeSize; exports.getNodeTokenBindings = getNodeTokenBindings; exports.getNodeTokenModes = getNodeTokenModes; exports.getResizingNodeRect = getResizingNodeRect; exports.getShapeRenderData = getShapeRenderData; exports.getShapeSvg = getShapeSvg; exports.getTokenPropertyScope = getTokenPropertyScope; exports.getTokensForProperty = getTokensForProperty; exports.handlePoint = handlePoint; exports.hasVisibleStroke = hasVisibleStroke; exports.inferResizeHandle = inferResizeHandle; exports.inspectNodeTokens = inspectNodeTokens; exports.intersectPaths = intersectPaths; 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.normalizeBezierPath = normalizeBezierPath; exports.offsetPath = offsetPath; exports.offsetShapeNodes = offsetShapeNodes; exports.oppositePosition = oppositePosition; exports.outlineShapeNodeStrokes = outlineShapeNodeStrokes; exports.outlineStroke = outlineStroke; exports.overlaps = _chunkWADCJ7A7cjs.overlaps; exports.pageHidden = pageHidden; exports.parseCanvasClipboardData = parseCanvasClipboardData; exports.parseCanvasScenes = parseCanvasScenes; exports.parseSvgPath = parseSvgPath; exports.pathBoolean = pathBoolean; exports.pathToContours = pathToContours; exports.placeBeside = _chunkWADCJ7A7cjs.placeBeside; exports.pointInBezierPath = pointInBezierPath; exports.pointInMultiPolygon = pointInMultiPolygon; exports.pointInRings = pointInRings; exports.polygonArea = polygonArea; exports.polygonBoolean = polygonBoolean; exports.polygonToSvgPath = polygonToSvgPath; exports.positionToSide = positionToSide; exports.pruneCanvasTokenModes = pruneCanvasTokenModes; exports.readNodeStyleProperty = readNodeStyleProperty; exports.readStyleSize = readStyleSize; exports.realClock = realClock; exports.relayoutUpdates = relayoutUpdates; exports.remapPastedNodes = remapPastedNodes; exports.reorderNodes = reorderNodes; exports.repositionNodesTo = repositionNodesTo; exports.resizeHandleAxes = resizeHandleAxes; exports.resolveCanvasTokens = resolveCanvasTokens; exports.resolvePadding = resolvePadding; exports.revertShapeCombination = revertShapeCombination; exports.ringSignedArea = ringSignedArea; exports.runMultiNodeTransition = runMultiNodeTransition; exports.segmentBounds = segmentBounds; exports.segmentCurvature = segmentCurvature; exports.segmentDerivative = segmentDerivative; exports.segmentExtrema = segmentExtrema; exports.segmentLength = segmentLength; exports.segmentNearest = segmentNearest; exports.segmentParamAtLength = segmentParamAtLength; exports.segmentPoint = segmentPoint; exports.segmentTangent = segmentTangent; exports.serializeCanvasNodes = serializeCanvasNodes; exports.setCanvasTokenMode = setCanvasTokenMode; exports.shapeNodeToBezierPath = shapeNodeToBezierPath; exports.shapeNodeToPolygon = shapeNodeToPolygon; exports.shapeToBezierPath = shapeToBezierPath; exports.shapeToPolygon = shapeToPolygon; exports.sideToPosition = sideToPosition; exports.simplifyRing = simplifyRing; exports.snapNodeDrag = snapNodeDrag; exports.snapNodeResize = snapNodeResize; exports.snapResize = snapResize; exports.snapToGrid = snapToGrid; exports.splitSegment = splitSegment; exports.strokeOutlineRings = strokeOutlineRings; exports.subSegment = subSegment; exports.subtractPaths = subtractPaths; exports.subtractPolygons = subtractPolygons; exports.toBezierPath = toBezierPath; exports.toggleLockNodes = toggleLockNodes; exports.transformBezierPath = transformBezierPath; exports.trimSegments = trimSegments; exports.unionPolygons = unionPolygons; exports.unitePaths = unitePaths; exports.unlockNodes = unlockNodes; exports.windingNumber = windingNumber; exports.withStyleOpacity = withStyleOpacity; exports.withStyleSize = withStyleSize; exports.writeNodeStyleProperty = writeNodeStyleProperty; exports.xorPolygons = xorPolygons;
11957
+ exports.ANIMATABLE_PROPERTIES = ANIMATABLE_PROPERTIES; exports.ANIMATION_DATA_KEY = ANIMATION_DATA_KEY; exports.ANIMATION_EASING_LABELS = ANIMATION_EASING_LABELS; exports.ANIMATION_EASING_PRESETS = ANIMATION_EASING_PRESETS; exports.ANIMATION_TIME_EPSILON = ANIMATION_TIME_EPSILON; exports.AUTO_LAYOUT_DATA_KEY = AUTO_LAYOUT_DATA_KEY; exports.AnimationEditError = AnimationEditError; exports.AnimationPlayer = AnimationPlayer; exports.CANVAS_COMPONENT_DRAG_TYPE = CANVAS_COMPONENT_DRAG_TYPE; exports.CANVAS_TOKEN_PROPERTIES = CANVAS_TOKEN_PROPERTIES; exports.CHILD_LAYOUT_DATA_KEY = CHILD_LAYOUT_DATA_KEY; exports.COMPONENT_DATA_KEY = COMPONENT_DATA_KEY; exports.COMPONENT_OVERRIDES_DATA_KEY = COMPONENT_OVERRIDES_DATA_KEY; exports.COMPONENT_PROPERTY_REFS_DATA_KEY = COMPONENT_PROPERTY_REFS_DATA_KEY; exports.COMPONENT_SET_DATA_KEY = COMPONENT_SET_DATA_KEY; exports.COMPONENT_SOURCE_DATA_KEY = COMPONENT_SOURCE_DATA_KEY; exports.CONNECTION_LINE_TYPES = CONNECTION_LINE_TYPES; exports.CSS_ANIMATION_PROPERTIES = CSS_ANIMATION_PROPERTIES; exports.CUBIC_BEZIER_PRESETS = CUBIC_BEZIER_PRESETS; 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.INSTANCE_DATA_KEY = INSTANCE_DATA_KEY; exports.LOCKED_DATA_KEY = LOCKED_DATA_KEY; exports.LOCKED_PREVIOUS_FLAGS_KEY = LOCKED_PREVIOUS_FLAGS_KEY; exports.MAX_KEYFRAME_REFS = MAX_KEYFRAME_REFS; exports.ManualClock = ManualClock; exports.PathOpsError = PathOpsError; 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.TOKEN_BINDINGS_DATA_KEY = TOKEN_BINDINGS_DATA_KEY; exports.TOKEN_MODES_DATA_KEY = TOKEN_MODES_DATA_KEY; exports.addKeyframesAtTime = addKeyframesAtTime; exports.alignNodes = alignNodes; exports.animateNode = animateNode; exports.applyAnimation = applyAnimation; exports.applyAnimationOverrides = applyAnimationOverrides; exports.applyConstraints = applyConstraints; exports.applyNodeUpdates = applyNodeUpdates; exports.applyShapeCombination = applyShapeCombination; exports.applyShapeReplacement = applyShapeReplacement; exports.arcToCubics = arcToCubics; exports.bezierPathArea = bezierPathArea; exports.bezierPathBounds = bezierPathBounds; exports.bezierPathLength = bezierPathLength; exports.bezierPathPointAtLength = bezierPathPointAtLength; exports.bezierPathSignedArea = bezierPathSignedArea; exports.bezierPathToSvg = bezierPathToSvg; exports.bindCanvasComponentProperty = bindCanvasComponentProperty; exports.bindCanvasToken = bindCanvasToken; exports.blendLayout = blendLayout; exports.boundsOf = _chunkWADCJ7A7cjs.boundsOf; exports.calculateDagreReflowDisplacement = calculateDagreReflowDisplacement; exports.calculateDirectionalDisplacement = calculateDirectionalDisplacement; exports.canCombineShapeNodes = canCombineShapeNodes; exports.canOffsetShapeNodes = canOffsetShapeNodes; exports.canOutlineShapeNodeStrokes = canOutlineShapeNodeStrokes; exports.canvasHeight = canvasHeight; exports.centerNodes = _chunkWADCJ7A7cjs.centerNodes; exports.centre = _chunkWADCJ7A7cjs.centre; exports.clampAnimationValue = clampAnimationValue; exports.clampLayoutSize = clampLayoutSize; exports.closeContour = closeContour; exports.collectDescendantIds = collectDescendantIds; exports.combineCanvasComponentsAsVariants = combineCanvasComponentsAsVariants; exports.combineShapeNodes = combineShapeNodes; exports.computeNodesBoundingBox = computeNodesBoundingBox; exports.computeSnapGuides = computeSnapGuides; exports.connectedOnly = connectedOnly; exports.contourSignedArea = contourSignedArea; exports.contoursToPath = contoursToPath; exports.copyKeyframes = copyKeyframes; exports.countPathSegments = countPathSegments; exports.createAnimationPlayer = createAnimationPlayer; exports.createBezierTrajectory = createBezierTrajectory; exports.createCanvasAnimationController = createCanvasAnimationController; exports.createCanvasArrangeController = createCanvasArrangeController; exports.createCanvasAutoLayoutController = createCanvasAutoLayoutController; exports.createCanvasComponent = createCanvasComponent; exports.createCanvasComponentsController = createCanvasComponentsController; exports.createCanvasInstance = createCanvasInstance; exports.createCanvasScenesStore = createCanvasScenesStore; exports.createFanOutTrajectory = createFanOutTrajectory; exports.createGuideIndex = createGuideIndex; exports.createNodeGuideIndex = createNodeGuideIndex; exports.createNodeLookup = createNodeLookup; exports.cubicBezierAt = cubicBezierAt; exports.cubicPointAt = cubicPointAt; exports.cubicsToPathData = cubicsToPathData; exports.dashContours = dashContours; exports.defaultEasing = defaultEasing; exports.deleteKeyframes = deleteKeyframes; exports.detachCanvasInstance = detachCanvasInstance; exports.detachTokenBindings = detachTokenBindings; exports.diffOverrideGroups = diffOverrideGroups; exports.distanceToBezierPath = distanceToBezierPath; exports.distributeNodes = distributeNodes; exports.dividePaths = dividePaths; exports.dividePolygons = dividePolygons; exports.easingFromInfluence = easingFromInfluence; exports.easingLabel = easingLabel; exports.easingToCss = easingToCss; exports.ensureLayout = _chunkWADCJ7A7cjs.ensureLayout; exports.estimateCanvasHeight = estimateCanvasHeight; exports.estimateNodeSize = _chunkWADCJ7A7cjs.estimateNodeSize; exports.evaluateAnimation = evaluateAnimation; exports.evaluateEasing = evaluateEasing; exports.evaluateTrack = evaluateTrack; exports.excludePaths = excludePaths; exports.exportCssAnimation = exportCssAnimation; exports.findConnectorSnap = findConnectorSnap; exports.findVariant = findVariant; 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.formatAnimationTime = formatAnimationTime; exports.formatNumber = formatNumber2; exports.formatOklab = formatOklab; exports.formatVariantName = formatVariantName; exports.getAbsolutePosition = getAbsolutePosition; exports.getAnimatableProperty = getAnimatableProperty; exports.getAnimatedProperties = getAnimatedProperties; exports.getAnimatedValue = getAnimatedValue; exports.getAnimationDuration = getAnimationDuration; exports.getAnimationTrack = getAnimationTrack; exports.getAutoLayout = getAutoLayout; exports.getAutoLayoutGrid = getAutoLayoutGrid; exports.getAutoLayoutInsertTarget = getAutoLayoutInsertTarget; exports.getBindableTokenProperties = getBindableTokenProperties; exports.getCanvasComponentDragId = getCanvasComponentDragId; exports.getCanvasTokenProperty = getCanvasTokenProperty; exports.getCenteredNodePosition = _chunkWADCJ7A7cjs.getCenteredNodePosition; exports.getChildLayout = getChildLayout; exports.getComponentData = getComponentData; exports.getComponentInstances = getComponentInstances; exports.getComponentPropertyDefs = getComponentPropertyDefs; exports.getComponentPropertyRefs = getComponentPropertyRefs; exports.getComponentSourceId = getComponentSourceId; exports.getCssPropertyAnimations = getCssPropertyAnimations; exports.getDefaultVariant = getDefaultVariant; exports.getEffectiveTokenModes = getEffectiveTokenModes; exports.getFlowChildren = getFlowChildren; exports.getInstanceData = getInstanceData; exports.getInstanceProperties = getInstanceProperties; exports.getInstanceStatus = getInstanceStatus; exports.getKeyframeTimes = getKeyframeTimes; exports.getLayerName = getLayerName; exports.getLayoutParent = getLayoutParent; exports.getLayoutSizing = getLayoutSizing; exports.getLayoutedNodes = _chunkWADCJ7A7cjs.getLayoutedNodes; exports.getNodeAnimation = getNodeAnimation; exports.getNodeOverrides = getNodeOverrides; exports.getNodeRect = getNodeRect; exports.getNodeShape = getNodeShape; exports.getNodeSize = getNodeSize; exports.getNodeTokenBindings = getNodeTokenBindings; exports.getNodeTokenModes = getNodeTokenModes; exports.getOwningComponent = getOwningComponent; exports.getOwningInstance = getOwningInstance; exports.getResizingNodeRect = getResizingNodeRect; exports.getRootInstance = getRootInstance; exports.getShapeRenderData = getShapeRenderData; exports.getShapeSvg = getShapeSvg; exports.getTimelineRows = getTimelineRows; exports.getTimelineTicks = getTimelineTicks; exports.getTokenPropertyScope = getTokenPropertyScope; exports.getTokensForProperty = getTokensForProperty; exports.getVariantConflicts = getVariantConflicts; exports.getVariantOptions = getVariantOptions; exports.getVariantSet = getVariantSet; exports.getVariantValues = getVariantValues; exports.handlePoint = handlePoint; exports.hasVisibleStroke = hasVisibleStroke; exports.inferResizeHandle = inferResizeHandle; exports.inspectCanvasInstance = inspectCanvasInstance; exports.inspectNodeTokens = inspectNodeTokens; exports.interpolateAnimationValue = interpolateAnimationValue; exports.intersectPaths = intersectPaths; exports.intersectPolygons = intersectPolygons; exports.invertNodeUpdates = invertNodeUpdates; exports.isAnimationEasing = isAnimationEasing; exports.isAnimationKeyframe = isAnimationKeyframe; exports.isAutoLayoutFrame = isAutoLayoutFrame; exports.isCanvasComponent = isCanvasComponent; exports.isCanvasComponentSet = isCanvasComponentSet; exports.isCanvasInstance = isCanvasInstance; exports.isCssExportExact = isCssExportExact; exports.isEventFromTextInput = isEventFromTextInput; exports.isInsideInstance = isInsideInstance; exports.isKeyframeSelected = isKeyframeSelected; exports.isLocked = isLocked; exports.isMeasureModifierHeld = isMeasureModifierHeld; exports.isNodeAnimated = isNodeAnimated; 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.listCanvasComponents = listCanvasComponents; 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.mixColorsOklab = mixColorsOklab; exports.moveKeyframes = moveKeyframes; exports.moveLayoutChild = moveLayoutChild; exports.multiPolygonArea = multiPolygonArea; exports.multiPolygonBounds = multiPolygonBounds; exports.nearestHandlePositions = nearestHandlePositions; exports.normalizeBezierPath = normalizeBezierPath; exports.normalizeKeyframes = normalizeKeyframes; exports.offsetPath = offsetPath; exports.offsetShapeNodes = offsetShapeNodes; exports.oklabToRgb = oklabToRgb; exports.oppositePosition = oppositePosition; exports.outlineShapeNodeStrokes = outlineShapeNodeStrokes; exports.outlineStroke = outlineStroke; exports.overlaps = _chunkWADCJ7A7cjs.overlaps; exports.pageHidden = pageHidden; exports.parseCanvasClipboardData = parseCanvasClipboardData; exports.parseCanvasScenes = parseCanvasScenes; exports.parseCssEasing = parseCssEasing; exports.parseKeyframeClipboard = parseKeyframeClipboard; exports.parseNodeStyleDeclarations = parseNodeStyleDeclarations; exports.parseOklab = parseOklab; exports.parseSvgPath = parseSvgPath; exports.parseVariantName = parseVariantName; exports.pasteKeyframes = pasteKeyframes; exports.pathBoolean = pathBoolean; exports.pathToContours = pathToContours; exports.placeBeside = _chunkWADCJ7A7cjs.placeBeside; exports.playWebAnimations = playWebAnimations; exports.pointInBezierPath = pointInBezierPath; exports.pointInMultiPolygon = pointInMultiPolygon; exports.pointInRings = pointInRings; exports.polygonArea = polygonArea; exports.polygonBoolean = polygonBoolean; exports.polygonToSvgPath = polygonToSvgPath; exports.positionToSide = positionToSide; exports.pruneCanvasTokenModes = pruneCanvasTokenModes; exports.pushCanvasInstanceOverrides = pushCanvasInstanceOverrides; exports.readAnimatableValue = readAnimatableValue; exports.readNodeStyleProperty = readNodeStyleProperty; exports.readOverrideGroup = readOverrideGroup; exports.readStyleSize = readStyleSize; exports.realClock = realClock; exports.recordAnimationChanges = recordAnimationChanges; exports.relayoutUpdates = relayoutUpdates; exports.remapPastedNodes = remapPastedNodes; exports.removeTrack = removeTrack; exports.reorderNodes = reorderNodes; exports.repositionNodesTo = repositionNodesTo; exports.resetCanvasInstanceOverrides = resetCanvasInstanceOverrides; exports.resizeHandleAxes = resizeHandleAxes; exports.resolveCanvasTokens = resolveCanvasTokens; exports.resolveEasing = resolveEasing; exports.resolvePadding = resolvePadding; exports.restoreCanvasMainComponent = restoreCanvasMainComponent; exports.revertShapeCombination = revertShapeCombination; exports.rgbToOklab = rgbToOklab; exports.ringSignedArea = ringSignedArea; exports.runMultiNodeTransition = runMultiNodeTransition; exports.sampleAnimationFrames = sampleAnimationFrames; exports.scaleKeyframes = scaleKeyframes; exports.segmentBounds = segmentBounds; exports.segmentCurvature = segmentCurvature; exports.segmentDerivative = segmentDerivative; exports.segmentExtrema = segmentExtrema; exports.segmentLength = segmentLength; exports.segmentNearest = segmentNearest; exports.segmentParamAtLength = segmentParamAtLength; exports.segmentPoint = segmentPoint; exports.segmentTangent = segmentTangent; exports.serializeCanvasNodes = serializeCanvasNodes; exports.setCanvasComponentProperty = setCanvasComponentProperty; exports.setCanvasInstanceProperties = setCanvasInstanceProperties; exports.setCanvasTokenMode = setCanvasTokenMode; exports.setKeyframe = setKeyframe; exports.setKeyframeEasing = setKeyframeEasing; exports.setMotionPath = setMotionPath; exports.setTrackEnabled = setTrackEnabled; exports.shapeNodeToBezierPath = shapeNodeToBezierPath; exports.shapeNodeToPolygon = shapeNodeToPolygon; exports.shapeToBezierPath = shapeToBezierPath; exports.shapeToPolygon = shapeToPolygon; exports.sideToPosition = sideToPosition; exports.simplifyRing = simplifyRing; exports.snapKeyframeDelta = snapKeyframeDelta; exports.snapNodeDrag = snapNodeDrag; exports.snapNodeResize = snapNodeResize; exports.snapResize = snapResize; exports.snapTimeToFrame = snapTimeToFrame; exports.snapToGrid = snapToGrid; exports.splitSegment = splitSegment; exports.springAt = springAt; exports.strokeOutlineRings = strokeOutlineRings; exports.subSegment = subSegment; exports.subtractPaths = subtractPaths; exports.subtractPolygons = subtractPolygons; exports.swapCanvasInstance = swapCanvasInstance; exports.syncAllCanvasInstances = syncAllCanvasInstances; exports.syncCanvasComponents = syncCanvasComponents; exports.syncCanvasInstance = syncCanvasInstance; exports.timeToX = timeToX; exports.toBezierPath = toBezierPath; exports.toWebAnimations = toWebAnimations; exports.toggleLockNodes = toggleLockNodes; exports.transformBezierPath = transformBezierPath; exports.trimSegments = trimSegments; exports.unionPolygons = unionPolygons; exports.unitePaths = unitePaths; exports.unlockNodes = unlockNodes; exports.updateKeyframe = updateKeyframe; exports.windingNumber = windingNumber; exports.withNodeAnimation = withNodeAnimation; exports.withStyleOpacity = withStyleOpacity; exports.withStyleSize = withStyleSize; exports.wouldCreateComponentCycle = wouldCreateComponentCycle; exports.wrapAnimationTime = wrapAnimationTime; exports.writeNodeStyleProperty = writeNodeStyleProperty; exports.writeOverrideGroup = writeOverrideGroup; exports.xToTime = xToTime; exports.xorPolygons = xorPolygons;
8060
11958
  //# sourceMappingURL=index.cjs.map