@tldraw/editor 5.4.2 → 5.5.0-canary.0241f11f2e99

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 (135) hide show
  1. package/dist-cjs/index.d.ts +7 -2
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/lib/constants.js +2 -0
  4. package/dist-cjs/lib/constants.js.map +2 -2
  5. package/dist-cjs/lib/editor/Editor.js +131 -151
  6. package/dist-cjs/lib/editor/Editor.js.map +3 -3
  7. package/dist-cjs/lib/editor/derivations/bindingsIndex.js +2 -0
  8. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  9. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +10 -6
  10. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  11. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js +7 -3
  12. package/dist-cjs/lib/editor/managers/ThemeManager/ThemeManager.js.map +2 -2
  13. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +14 -6
  14. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +3 -3
  15. package/dist-cjs/lib/exports/ExportDelay.js +10 -2
  16. package/dist-cjs/lib/exports/ExportDelay.js.map +2 -2
  17. package/dist-cjs/lib/exports/FontEmbedder.js +25 -11
  18. package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
  19. package/dist-cjs/lib/exports/StyleEmbedder.js +9 -4
  20. package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
  21. package/dist-cjs/lib/exports/fetchCache.js +3 -0
  22. package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
  23. package/dist-cjs/lib/exports/getSvgAsImage.js +10 -4
  24. package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
  25. package/dist-cjs/lib/exports/getSvgJsx.js +18 -9
  26. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  27. package/dist-cjs/lib/exports/parseCss.js +1 -1
  28. package/dist-cjs/lib/exports/parseCss.js.map +1 -1
  29. package/dist-cjs/lib/license/LicenseManager.js +9 -1
  30. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  31. package/dist-cjs/lib/license/LicenseProvider.js +12 -4
  32. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  33. package/dist-cjs/lib/primitives/geometry/Arc2d.js +1 -1
  34. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  35. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
  36. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  37. package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
  38. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  39. package/dist-cjs/lib/primitives/geometry/Group2d.js +8 -5
  40. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  41. package/dist-cjs/lib/primitives/geometry/Point2d.js +1 -1
  42. package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
  43. package/dist-cjs/lib/utils/sync/LocalIndexedDb.js +13 -17
  44. package/dist-cjs/lib/utils/sync/LocalIndexedDb.js.map +2 -2
  45. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +78 -40
  46. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  47. package/dist-cjs/version.js +3 -3
  48. package/dist-cjs/version.js.map +1 -1
  49. package/dist-esm/index.d.mts +7 -2
  50. package/dist-esm/index.mjs +1 -1
  51. package/dist-esm/lib/constants.mjs +2 -0
  52. package/dist-esm/lib/constants.mjs.map +2 -2
  53. package/dist-esm/lib/editor/Editor.mjs +132 -151
  54. package/dist-esm/lib/editor/Editor.mjs.map +3 -3
  55. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +2 -0
  56. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  57. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +10 -6
  58. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  59. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs +7 -3
  60. package/dist-esm/lib/editor/managers/ThemeManager/ThemeManager.mjs.map +2 -2
  61. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +14 -6
  62. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +3 -3
  63. package/dist-esm/lib/exports/ExportDelay.mjs +11 -3
  64. package/dist-esm/lib/exports/ExportDelay.mjs.map +2 -2
  65. package/dist-esm/lib/exports/FontEmbedder.mjs +25 -11
  66. package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
  67. package/dist-esm/lib/exports/StyleEmbedder.mjs +9 -4
  68. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
  69. package/dist-esm/lib/exports/fetchCache.mjs +3 -0
  70. package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
  71. package/dist-esm/lib/exports/getSvgAsImage.mjs +10 -4
  72. package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
  73. package/dist-esm/lib/exports/getSvgJsx.mjs +18 -9
  74. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  75. package/dist-esm/lib/exports/parseCss.mjs +1 -1
  76. package/dist-esm/lib/exports/parseCss.mjs.map +1 -1
  77. package/dist-esm/lib/license/LicenseManager.mjs +9 -1
  78. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  79. package/dist-esm/lib/license/LicenseProvider.mjs +13 -5
  80. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  81. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +1 -1
  82. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  83. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
  84. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  85. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
  86. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  87. package/dist-esm/lib/primitives/geometry/Group2d.mjs +12 -6
  88. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  89. package/dist-esm/lib/primitives/geometry/Point2d.mjs +1 -1
  90. package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
  91. package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs +13 -17
  92. package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs.map +2 -2
  93. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +78 -40
  94. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  95. package/dist-esm/version.mjs +3 -3
  96. package/dist-esm/version.mjs.map +1 -1
  97. package/package.json +7 -7
  98. package/src/lib/constants.ts +8 -0
  99. package/src/lib/editor/Editor.test.ts +20 -0
  100. package/src/lib/editor/Editor.ts +202 -255
  101. package/src/lib/editor/derivations/bindingsIndex.ts +3 -0
  102. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +35 -4
  103. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +13 -7
  104. package/src/lib/editor/managers/ThemeManager/ThemeManager.test.ts +53 -0
  105. package/src/lib/editor/managers/ThemeManager/ThemeManager.ts +9 -3
  106. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +23 -8
  107. package/src/lib/exports/ExportDelay.tsx +16 -4
  108. package/src/lib/exports/FontEmbedder.test.ts +99 -0
  109. package/src/lib/exports/FontEmbedder.ts +32 -11
  110. package/src/lib/exports/StyleEmbedder.ts +13 -4
  111. package/src/lib/exports/fetchCache.test.ts +22 -0
  112. package/src/lib/exports/fetchCache.ts +4 -0
  113. package/src/lib/exports/getSvgAsImage.ts +13 -5
  114. package/src/lib/exports/getSvgJsx.test.ts +43 -1
  115. package/src/lib/exports/getSvgJsx.tsx +28 -16
  116. package/src/lib/exports/parseCss.test.ts +4 -0
  117. package/src/lib/exports/parseCss.ts +2 -2
  118. package/src/lib/license/LicenseManager.ts +13 -1
  119. package/src/lib/license/LicenseProvider.test.tsx +76 -0
  120. package/src/lib/license/LicenseProvider.tsx +19 -5
  121. package/src/lib/primitives/geometry/Arc2d.test.ts +9 -0
  122. package/src/lib/primitives/geometry/Arc2d.ts +1 -1
  123. package/src/lib/primitives/geometry/CubicBezier2d.test.ts +13 -0
  124. package/src/lib/primitives/geometry/CubicBezier2d.ts +1 -1
  125. package/src/lib/primitives/geometry/Edge2d.test.ts +21 -3
  126. package/src/lib/primitives/geometry/Edge2d.ts +1 -1
  127. package/src/lib/primitives/geometry/Group2d.test.ts +26 -5
  128. package/src/lib/primitives/geometry/Group2d.ts +18 -7
  129. package/src/lib/primitives/geometry/Point2d.test.ts +14 -3
  130. package/src/lib/primitives/geometry/Point2d.ts +1 -1
  131. package/src/lib/utils/sync/LocalIndexedDb.test.ts +28 -0
  132. package/src/lib/utils/sync/LocalIndexedDb.ts +18 -20
  133. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +236 -0
  134. package/src/lib/utils/sync/TLLocalSyncClient.ts +106 -54
  135. package/src/version.ts +3 -3
@@ -95,6 +95,10 @@ var import_UserPreferencesManager = require("./managers/UserPreferencesManager/U
95
95
  var import_OverlayManager = require("./overlays/OverlayManager");
96
96
  var import_RootState = require("./tools/RootState");
97
97
  const RENDERING_SHAPES_SORT_CACHE_THRESHOLD = 100;
98
+ const AXIS = {
99
+ horizontal: { val: "x", min: "minX", max: "maxX", dim: "width" },
100
+ vertical: { val: "y", min: "minY", max: "maxY", dim: "height" }
101
+ };
98
102
  class Editor extends import_eventemitter3.default {
99
103
  id = (0, import_utils.uniqueId)();
100
104
  constructor({
@@ -421,7 +425,7 @@ class Editor extends import_eventemitter3.default {
421
425
  }
422
426
  }
423
427
  if (deleteBindingIds.length) {
424
- this.deleteBindings(deleteBindingIds);
428
+ this.store.remove(deleteBindingIds);
425
429
  }
426
430
  }
427
431
  },
@@ -1381,6 +1385,7 @@ class Editor extends import_eventemitter3.default {
1381
1385
  * @public
1382
1386
  **/
1383
1387
  updateDocumentSettings(settings) {
1388
+ if (this.getIsReadonly()) return this;
1384
1389
  this.run(
1385
1390
  () => {
1386
1391
  this.store.put([{ ...this.getDocumentSettings(), ...settings }]);
@@ -1540,7 +1545,7 @@ class Editor extends import_eventemitter3.default {
1540
1545
  * @public
1541
1546
  */
1542
1547
  select(...shapes) {
1543
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
1548
+ const ids = toShapeIds(shapes);
1544
1549
  this.setSelectedShapes(ids);
1545
1550
  return this;
1546
1551
  }
@@ -1555,7 +1560,7 @@ class Editor extends import_eventemitter3.default {
1555
1560
  * @public
1556
1561
  */
1557
1562
  deselect(...shapes) {
1558
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
1563
+ const ids = toShapeIds(shapes);
1559
1564
  const selectedShapeIds = this.getSelectedShapeIds();
1560
1565
  if (selectedShapeIds.length > 0 && ids.length > 0) {
1561
1566
  this.setSelectedShapes(selectedShapeIds.filter((id) => !ids.includes(id)));
@@ -1593,7 +1598,7 @@ class Editor extends import_eventemitter3.default {
1593
1598
  }
1594
1599
  const ids = this.getSortedChildIdsForParent(parentToSelectWithinId);
1595
1600
  if (ids.length <= 0) return this;
1596
- this.setSelectedShapes(this._getUnlockedShapeIds(ids));
1601
+ this.setSelectedShapes(ids.filter((id) => !this.getShape(id)?.isLocked));
1597
1602
  return this;
1598
1603
  }
1599
1604
  /**
@@ -1610,14 +1615,18 @@ class Editor extends import_eventemitter3.default {
1610
1615
  const selectedShapeIds = this.getSelectedShapeIds();
1611
1616
  const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null;
1612
1617
  const isSelectedWithinContainer = firstParentId && selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) && !(0, import_tlschema.isPageId)(firstParentId);
1613
- const filteredShapes = isSelectedWithinContainer ? this.getCurrentPageShapes().filter((shape2) => shape2.parentId === firstParentId) : this.getCurrentPageShapes().filter((shape2) => (0, import_tlschema.isPageId)(shape2.parentId));
1614
- const readingOrderShapes = isSelectedWithinContainer ? this._getShapesInReadingOrder(filteredShapes) : this.getCurrentPageShapesInReadingOrder();
1618
+ const filteredShapes = this.getCurrentPageShapes().filter(
1619
+ (shape2) => !this.isShapeOrAncestorLocked(shape2) && (isSelectedWithinContainer ? shape2.parentId === firstParentId : (0, import_tlschema.isPageId)(shape2.parentId))
1620
+ );
1621
+ const readingOrderShapes = this._getShapesInReadingOrder(filteredShapes);
1615
1622
  const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
1616
1623
  let adjacentShapeId;
1617
1624
  if (direction === "next" || direction === "prev") {
1618
1625
  const shapeIds = readingOrderShapes.map((shape2) => shape2.id);
1626
+ if (shapeIds.length === 0) return;
1619
1627
  const currentIndex = currentShapeId ? shapeIds.indexOf(currentShapeId) : -1;
1620
- const adjacentIndex = (currentIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
1628
+ const startIndex = currentIndex === -1 && direction === "prev" ? 0 : currentIndex;
1629
+ const adjacentIndex = (startIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
1621
1630
  adjacentShapeId = shapeIds[adjacentIndex];
1622
1631
  } else {
1623
1632
  if (!currentShapeId) return;
@@ -1716,13 +1725,14 @@ class Editor extends import_eventemitter3.default {
1716
1725
  });
1717
1726
  if (shapesInDirection.length === 0) return currentShapeId;
1718
1727
  const lowestScoringShape = (0, import_utils.minBy)(shapesInDirection, ({ center }) => {
1719
- const distance = import_Vec.Vec.Dist2(currentCenter, center);
1728
+ const distance = import_Vec.Vec.Dist(currentCenter, center);
1720
1729
  const dirProp = ["left", "right"].includes(direction) ? "x" : "y";
1721
1730
  const directionalDistance = Math.abs(center[dirProp] - currentCenter[dirProp]);
1722
1731
  const offProp = ["left", "right"].includes(direction) ? "y" : "x";
1723
1732
  const offAxisDeviation = Math.abs(center[offProp] - currentCenter[offProp]);
1724
- const angle = Math.abs(import_Vec.Vec.Angle(currentCenter, center) * (180 / Math.PI));
1725
- const angleDeviation = Math.abs(angle - directionToAngle[direction]);
1733
+ const angle = (import_Vec.Vec.Angle(currentCenter, center) * (180 / Math.PI) + 360) % 360;
1734
+ const rawAngleDeviation = Math.abs(angle - directionToAngle[direction]);
1735
+ const angleDeviation = Math.min(rawAngleDeviation, 360 - rawAngleDeviation);
1726
1736
  return distance * 1 + // Base distance
1727
1737
  offAxisDeviation * 2 + // Heavy penalty for off-axis deviation
1728
1738
  (distance - directionalDistance) * 1.5 + // Penalty for diagonal distance
@@ -2060,7 +2070,7 @@ class Editor extends import_eventemitter3.default {
2060
2070
  * @public
2061
2071
  */
2062
2072
  setHintingShapes(shapes) {
2063
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
2073
+ const ids = toShapeIds(shapes);
2064
2074
  this.run(
2065
2075
  () => {
2066
2076
  this._updateCurrentPageState({ hintingShapeIds: (0, import_utils.dedupe)(ids) });
@@ -2090,7 +2100,7 @@ class Editor extends import_eventemitter3.default {
2090
2100
  * @public
2091
2101
  */
2092
2102
  setErasingShapes(shapes) {
2093
- const ids = typeof shapes[0] === "string" ? shapes.slice() : shapes.map((shape) => shape.id);
2103
+ const ids = toShapeIds(shapes).slice();
2094
2104
  ids.sort();
2095
2105
  const erasingShapeIds = this.getErasingShapeIds();
2096
2106
  this.run(
@@ -2497,14 +2507,16 @@ class Editor extends import_eventemitter3.default {
2497
2507
  setCamera(point, opts) {
2498
2508
  const { isLocked } = this._cameraOptions.__unsafe__getWithoutCapture();
2499
2509
  if (isLocked && !opts?.force) return this;
2510
+ const _point = new import_Vec.Vec(point.x, point.y, point.z ?? this.getZoomLevel());
2511
+ if (!Number.isFinite(_point.x) || !Number.isFinite(_point.y) || !Number.isFinite(_point.z)) {
2512
+ throw Error(
2513
+ `Editor.setCamera: expected finite values, got (${_point.x}, ${_point.y}, ${_point.z}).`
2514
+ );
2515
+ }
2500
2516
  this.stopCameraAnimation();
2501
2517
  if (this.getInstanceState().followingUserId) {
2502
2518
  this.stopFollowingUser();
2503
2519
  }
2504
- const _point = import_Vec.Vec.Cast(point);
2505
- if (!Number.isFinite(_point.x)) _point.x = 0;
2506
- if (!Number.isFinite(_point.y)) _point.y = 0;
2507
- if (_point.z === void 0 || !Number.isFinite(_point.z)) point.z = this.getZoomLevel();
2508
2520
  const camera = this.getConstrainedCamera(_point, opts);
2509
2521
  if (opts?.animation) {
2510
2522
  const { width, height } = this.getViewportScreenBounds();
@@ -2883,7 +2895,7 @@ class Editor extends import_eventemitter3.default {
2883
2895
  newCx += center.x / newCz - center.x / cz;
2884
2896
  newCy += center.y / newCz - center.y / cz;
2885
2897
  }
2886
- currentSpeed *= 1 - friction;
2898
+ currentSpeed *= (1 - friction) ** (elapsed / import_constants.FRAME_MS_60HZ);
2887
2899
  if (currentSpeed < speedThreshold) {
2888
2900
  cancel();
2889
2901
  } else {
@@ -2917,6 +2929,7 @@ class Editor extends import_eventemitter3.default {
2917
2929
  }
2918
2930
  const isOnSamePage = presence.currentPageId === this.getCurrentPageId();
2919
2931
  if (!isOnSamePage) {
2932
+ this.markHistoryStoppingPoint("change-page");
2920
2933
  this.setCurrentPage(presence.currentPageId);
2921
2934
  }
2922
2935
  if (opts && opts.animation && !isOnSamePage) {
@@ -3748,7 +3761,9 @@ class Editor extends import_eventemitter3.default {
3748
3761
  if (ids.length <= 0) return this;
3749
3762
  this.run(
3750
3763
  () => {
3751
- this.store.props.assets.remove?.(ids);
3764
+ Promise.resolve(this.store.props.assets.remove?.(ids)).catch(
3765
+ (err) => console.error("Error while removing assets from the asset store:", err)
3766
+ );
3752
3767
  this.store.remove(ids);
3753
3768
  },
3754
3769
  { history: "ignore" }
@@ -4130,7 +4145,7 @@ class Editor extends import_eventemitter3.default {
4130
4145
  if (shapes.length === 0) {
4131
4146
  return;
4132
4147
  }
4133
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4148
+ const ids = toShapeIds(shapes);
4134
4149
  const freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
4135
4150
  if (freshShapes.length === 1) {
4136
4151
  const parentId = freshShapes[0].parentId;
@@ -4633,7 +4648,7 @@ class Editor extends import_eventemitter3.default {
4633
4648
  * @public
4634
4649
  */
4635
4650
  reparentShapes(shapes, parentId, insertIndex) {
4636
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4651
+ const ids = toShapeIds(shapes);
4637
4652
  if (ids.length === 0) return this;
4638
4653
  const changes = [];
4639
4654
  const parentTransform = (0, import_tlschema.isPageId)(parentId) ? import_Mat.Mat.Identity() : this.getShapePageTransform(parentId);
@@ -4862,6 +4877,7 @@ class Editor extends import_eventemitter3.default {
4862
4877
  * binding, but the `type`, `toId`, and `fromId` must all be provided.
4863
4878
  */
4864
4879
  createBindings(partials) {
4880
+ if (this.getIsReadonly()) return this;
4865
4881
  const bindings = [];
4866
4882
  for (const partial of partials) {
4867
4883
  const fromShape = this.getShape(partial.fromId);
@@ -4896,6 +4912,7 @@ class Editor extends import_eventemitter3.default {
4896
4912
  * binding is skipped. The changes from the partial are merged into the existing record.
4897
4913
  */
4898
4914
  updateBindings(partials) {
4915
+ if (this.getIsReadonly()) return this;
4899
4916
  const updated = [];
4900
4917
  for (const partial of partials) {
4901
4918
  if (!partial) continue;
@@ -4924,6 +4941,16 @@ class Editor extends import_eventemitter3.default {
4924
4941
  * Delete several bindings by their IDs. If a binding ID doesn't exist, it's ignored.
4925
4942
  */
4926
4943
  deleteBindings(bindings, { isolateShapes = false } = {}) {
4944
+ if (this.getIsReadonly()) return this;
4945
+ return this._deleteBindings(bindings, { isolateShapes });
4946
+ }
4947
+ /**
4948
+ * Unguarded so that withIsolatedShapes can transiently isolate shapes for copy and export in
4949
+ * readonly mode; the public deleteBindings is what readonly blocks.
4950
+ *
4951
+ * @internal
4952
+ */
4953
+ _deleteBindings(bindings, { isolateShapes = false } = {}) {
4927
4954
  const ids = bindings.map((binding) => typeof binding === "string" ? binding : binding.id);
4928
4955
  if (isolateShapes) {
4929
4956
  this.store.atomic(() => {
@@ -4982,7 +5009,7 @@ class Editor extends import_eventemitter3.default {
4982
5009
  * @param opts - The options for the rotation.
4983
5010
  */
4984
5011
  rotateShapesBy(shapes, delta, opts) {
4985
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5012
+ const ids = toShapeIds(shapes);
4986
5013
  if (ids.length <= 0) return this;
4987
5014
  const snapshot = (0, import_rotation.getRotationSnapshot)({ editor: this, ids });
4988
5015
  if (!snapshot) return this;
@@ -5019,6 +5046,14 @@ class Editor extends import_eventemitter3.default {
5019
5046
  }
5020
5047
  return workingShape;
5021
5048
  }
5049
+ // Counter-rotates the page-space delta into the parent's space; without that a child of a rotated
5050
+ // frame or group would move along its parent's axes instead of the page's.
5051
+ // todo: a shape laid out together with its own parent moves twice, once with the parent and once
5052
+ // on its own; the layout commands should skip shapes whose ancestors are also being laid out
5053
+ getChangesToTranslateShapeByPageDelta(shape, pageDelta) {
5054
+ const localDelta = import_Vec.Vec.From(pageDelta).rot(-this.getShapeParentTransform(shape).rotation());
5055
+ return this.getChangesToTranslateShape(shape, localDelta.add(shape));
5056
+ }
5022
5057
  /**
5023
5058
  * Move shapes by a delta.
5024
5059
  *
@@ -5031,14 +5066,12 @@ class Editor extends import_eventemitter3.default {
5031
5066
  * @param offset - The offset to apply to the shapes.
5032
5067
  */
5033
5068
  nudgeShapes(shapes, offset) {
5034
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5069
+ const ids = toShapeIds(shapes);
5035
5070
  if (ids.length <= 0) return this;
5036
5071
  const changes = [];
5037
5072
  for (const id of ids) {
5038
5073
  const shape = this.getShape(id);
5039
- const localDelta = import_Vec.Vec.From(offset);
5040
- localDelta.rot(-this.getShapeParentTransform(shape).rotation());
5041
- changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
5074
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, offset));
5042
5075
  }
5043
5076
  this.updateShapes(changes);
5044
5077
  return this;
@@ -5059,7 +5092,7 @@ class Editor extends import_eventemitter3.default {
5059
5092
  */
5060
5093
  duplicateShapes(shapes, offset) {
5061
5094
  this.run(() => {
5062
- const _ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5095
+ const _ids = toShapeIds(shapes);
5063
5096
  const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids);
5064
5097
  if (ids.length <= 0) return this;
5065
5098
  const initialIds = new Set(ids);
@@ -5168,7 +5201,7 @@ class Editor extends import_eventemitter3.default {
5168
5201
  * @public
5169
5202
  */
5170
5203
  moveShapesToPage(shapes, pageId) {
5171
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5204
+ const ids = toShapeIds(shapes);
5172
5205
  if (ids.length === 0) return this;
5173
5206
  if (this.getIsReadonly()) return this;
5174
5207
  const currentPageId = this.getCurrentPageId();
@@ -5204,7 +5237,7 @@ class Editor extends import_eventemitter3.default {
5204
5237
  * @public
5205
5238
  */
5206
5239
  toggleLock(shapes) {
5207
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5240
+ const ids = toShapeIds(shapes);
5208
5241
  if (this.getIsReadonly() || ids.length === 0) return this;
5209
5242
  let allLocked = true;
5210
5243
  const shapesToToggle = [];
@@ -5243,7 +5276,7 @@ class Editor extends import_eventemitter3.default {
5243
5276
  * @public
5244
5277
  */
5245
5278
  sendToBack(shapes) {
5246
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5279
+ const ids = toShapeIds(shapes);
5247
5280
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "toBack", ids, {
5248
5281
  considerAllShapes: true
5249
5282
  });
@@ -5273,7 +5306,7 @@ class Editor extends import_eventemitter3.default {
5273
5306
  * @public
5274
5307
  */
5275
5308
  sendBackward(shapes, opts = {}) {
5276
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5309
+ const ids = toShapeIds(shapes);
5277
5310
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "backward", ids, opts);
5278
5311
  if (changes) this.updateShapes(changes);
5279
5312
  return this;
@@ -5301,7 +5334,7 @@ class Editor extends import_eventemitter3.default {
5301
5334
  * @public
5302
5335
  */
5303
5336
  bringForward(shapes, opts = {}) {
5304
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5337
+ const ids = toShapeIds(shapes);
5305
5338
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "forward", ids, opts);
5306
5339
  if (changes) this.updateShapes(changes);
5307
5340
  return this;
@@ -5320,7 +5353,7 @@ class Editor extends import_eventemitter3.default {
5320
5353
  * @public
5321
5354
  */
5322
5355
  bringToFront(shapes) {
5323
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5356
+ const ids = toShapeIds(shapes);
5324
5357
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "toFront", ids);
5325
5358
  if (changes) this.updateShapes(changes);
5326
5359
  return this;
@@ -5332,7 +5365,7 @@ class Editor extends import_eventemitter3.default {
5332
5365
  * @internal
5333
5366
  */
5334
5367
  getShapeClusters(shapes, type, opts) {
5335
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5368
+ const ids = toShapeIds(shapes);
5336
5369
  let freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
5337
5370
  if (opts?.filterAxisAligned) {
5338
5371
  freshShapes = freshShapes.filter((s) => {
@@ -5357,7 +5390,7 @@ class Editor extends import_eventemitter3.default {
5357
5390
  const shapesMovingTogether = [shape];
5358
5391
  const boundsOfShapesMovingTogether = [shapePageBounds];
5359
5392
  this.collectShapesViaArrowBindings({
5360
- bindings: this.getBindingsToShape(shape.id, "arrow"),
5393
+ bindings: this.getBindingsInvolvingShape(shape.id, "arrow"),
5361
5394
  initialShapes: freshShapes,
5362
5395
  resultShapes: shapesMovingTogether,
5363
5396
  resultBounds: boundsOfShapesMovingTogether,
@@ -5413,7 +5446,7 @@ class Editor extends import_eventemitter3.default {
5413
5446
  */
5414
5447
  flipShapes(shapes, operation) {
5415
5448
  if (this.getIsReadonly()) return this;
5416
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5449
+ const ids = toShapeIds(shapes);
5417
5450
  const shapesToFlipFirstPass = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
5418
5451
  for (const shape of shapesToFlipFirstPass) {
5419
5452
  if (this.isShapeOfType(shape, "group")) {
@@ -5487,21 +5520,7 @@ class Editor extends import_eventemitter3.default {
5487
5520
  const { clusters: shapeClustersToStack } = this.getShapeClusters(shapes, "stack");
5488
5521
  const len = shapeClustersToStack.length;
5489
5522
  if (_gap === 0 && len < 3 || len < 2) return this;
5490
- let val;
5491
- let min;
5492
- let max;
5493
- let dim;
5494
- if (operation === "horizontal") {
5495
- val = "x";
5496
- min = "minX";
5497
- max = "maxX";
5498
- dim = "width";
5499
- } else {
5500
- val = "y";
5501
- min = "minY";
5502
- max = "maxY";
5503
- dim = "height";
5504
- }
5523
+ const { val, min, max, dim } = AXIS[operation];
5505
5524
  let shapeGap = 0;
5506
5525
  shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
5507
5526
  if (_gap === 0) {
@@ -5540,13 +5559,7 @@ class Editor extends import_eventemitter3.default {
5540
5559
  const delta = new import_Vec.Vec();
5541
5560
  delta[val] = v + shapeGap - pageBounds[val];
5542
5561
  for (const shape of shapes2) {
5543
- const shapeDelta = delta.clone();
5544
- const parent = this.getShapeParent(shape);
5545
- if (parent) {
5546
- shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5547
- }
5548
- shapeDelta.add(shape);
5549
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5562
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5550
5563
  }
5551
5564
  v += pageBounds[dim] + shapeGap;
5552
5565
  }
@@ -5626,13 +5639,7 @@ class Editor extends import_eventemitter3.default {
5626
5639
  for (const { shapes: shapes2, pageBounds, nextPageBounds } of shapeClustersToPack) {
5627
5640
  const delta = import_Vec.Vec.Sub(nextPageBounds.point, pageBounds.point).add(centerDelta);
5628
5641
  for (const shape of shapes2) {
5629
- const shapeDelta = delta.clone();
5630
- const parent = this.getShapeParent(shape);
5631
- if (parent) {
5632
- shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
5633
- }
5634
- shapeDelta.add(shape);
5635
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5642
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5636
5643
  }
5637
5644
  }
5638
5645
  if (changes.length) {
@@ -5692,13 +5699,7 @@ class Editor extends import_eventemitter3.default {
5692
5699
  }
5693
5700
  }
5694
5701
  for (const shape of shapes2) {
5695
- const shapeDelta = delta.clone();
5696
- const parent = this.getShapeParent(shape);
5697
- if (parent) {
5698
- shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5699
- }
5700
- shapeDelta.add(shape);
5701
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5702
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5702
5703
  }
5703
5704
  });
5704
5705
  this.updateShapes(changes);
@@ -5722,27 +5723,13 @@ class Editor extends import_eventemitter3.default {
5722
5723
  if (this.getIsReadonly()) return this;
5723
5724
  const { clusters: shapeClustersToDistribute } = this.getShapeClusters(shapes, "distribute");
5724
5725
  if (shapeClustersToDistribute.length < 3) return this;
5725
- let val;
5726
- let min;
5727
- let max;
5728
- let dim;
5729
- if (operation === "horizontal") {
5730
- val = "x";
5731
- min = "minX";
5732
- max = "maxX";
5733
- dim = "width";
5734
- } else {
5735
- val = "y";
5736
- min = "minY";
5737
- max = "maxY";
5738
- dim = "height";
5739
- }
5726
+ const { val, min, max, dim } = AXIS[operation];
5740
5727
  const changes = [];
5741
5728
  const first = shapeClustersToDistribute.sort((a, b) => a.pageBounds[min] - b.pageBounds[min])[0];
5742
5729
  const last2 = shapeClustersToDistribute.sort((a, b) => b.pageBounds[max] - a.pageBounds[max])[0];
5743
5730
  if (first === last2) {
5744
5731
  const excludedShapeIds = new Set(first.shapes.map((s) => s.id));
5745
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5732
+ const ids = toShapeIds(shapes);
5746
5733
  return this.distributeShapes(
5747
5734
  ids.filter((id) => !excludedShapeIds.has(id)),
5748
5735
  operation
@@ -5766,13 +5753,7 @@ class Editor extends import_eventemitter3.default {
5766
5753
  delta[val] = last2.pageBounds[max] - pageBounds[max] - 1;
5767
5754
  }
5768
5755
  for (const shape of shapes2) {
5769
- const shapeDelta = delta.clone();
5770
- const parent = this.getShapeParent(shape);
5771
- if (parent) {
5772
- shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5773
- }
5774
- shapeDelta.add(shape);
5775
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5756
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5776
5757
  }
5777
5758
  v += pageBounds[dim] + gap;
5778
5759
  }
@@ -5802,32 +5783,17 @@ class Editor extends import_eventemitter3.default {
5802
5783
  );
5803
5784
  if (shapeClustersToStretch.length < 2) return this;
5804
5785
  const commonBounds = import_Box.Box.Common(allBounds);
5805
- let val;
5806
- let min;
5807
- let dim;
5808
- if (operation === "horizontal") {
5809
- val = "x";
5810
- min = "minX";
5811
- dim = "width";
5812
- } else {
5813
- val = "y";
5814
- min = "minY";
5815
- dim = "height";
5816
- }
5786
+ const { val, min, dim } = AXIS[operation];
5817
5787
  this.run(() => {
5818
5788
  shapeClustersToStretch.forEach(({ shapes: shapes2, pageBounds }) => {
5819
- const localOffset = new import_Vec.Vec();
5820
- localOffset[val] = commonBounds[min] - pageBounds[min];
5789
+ const pageOffset = new import_Vec.Vec();
5790
+ pageOffset[val] = commonBounds[min] - pageBounds[min];
5821
5791
  const scaleOrigin = pageBounds.center.clone();
5822
5792
  scaleOrigin[val] = commonBounds[min];
5823
5793
  const scale = new import_Vec.Vec(1, 1);
5824
5794
  scale[val] = commonBounds[dim] / pageBounds[dim];
5825
5795
  for (const shape of shapes2) {
5826
- const shapeLocalOffset = localOffset.clone();
5827
- shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5828
- shapeLocalOffset.add(shape);
5829
- const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5830
- this.updateShape(changes);
5796
+ this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
5831
5797
  this.resizeShape(shape.id, scale, {
5832
5798
  initialBounds: this.getShapeGeometry(shape).bounds,
5833
5799
  scaleOrigin,
@@ -5870,7 +5836,7 @@ class Editor extends import_eventemitter3.default {
5870
5836
  const scaleY = targetBounds.height / commonBounds.height;
5871
5837
  const scale = new import_Vec.Vec(scaleX, scaleY);
5872
5838
  shapeClusters.forEach(({ shapes: shapes2, pageBounds }) => {
5873
- const localOffset = new import_Vec.Vec(
5839
+ const pageOffset = new import_Vec.Vec(
5874
5840
  targetBounds.minX - commonBounds.minX + (pageBounds.minX - commonBounds.minX) * (scaleX - 1),
5875
5841
  targetBounds.minY - commonBounds.minY + (pageBounds.minY - commonBounds.minY) * (scaleY - 1)
5876
5842
  );
@@ -5879,11 +5845,7 @@ class Editor extends import_eventemitter3.default {
5879
5845
  targetBounds.minY + (pageBounds.minY - commonBounds.minY) * scaleY
5880
5846
  );
5881
5847
  for (const shape of shapes2) {
5882
- const shapeLocalOffset = localOffset.clone();
5883
- shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5884
- shapeLocalOffset.add(shape);
5885
- const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5886
- this.updateShape(changes);
5848
+ this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
5887
5849
  this.resizeShape(shape.id, scale, {
5888
5850
  initialBounds: this.getShapeGeometry(shape).bounds,
5889
5851
  scaleOrigin,
@@ -6302,12 +6264,17 @@ class Editor extends import_eventemitter3.default {
6302
6264
  let remaining = duration;
6303
6265
  let t;
6304
6266
  const animations = [];
6267
+ const ignoreShapeLock = this._shouldIgnoreShapeLock;
6305
6268
  let partial, result;
6306
6269
  for (let i = 0, n = partials.length; i < n; i++) {
6307
6270
  partial = partials[i];
6308
6271
  if (!partial) continue;
6309
6272
  const shape = this.getShape(partial.id);
6310
6273
  if (!shape) continue;
6274
+ const unlocks = shape.isLocked && Object.hasOwn(partial, "isLocked") && !partial.isLocked;
6275
+ if (!ignoreShapeLock && !unlocks && this.isShapeOrAncestorLocked(shape)) {
6276
+ continue;
6277
+ }
6311
6278
  result = {
6312
6279
  start: (0, import_utils.structuredClone)(shape),
6313
6280
  end: applyPartialToRecordWithProps((0, import_utils.structuredClone)(shape), partial)
@@ -6323,7 +6290,7 @@ class Editor extends import_eventemitter3.default {
6323
6290
  (p) => p && animatingShapes2.get(p.id) === animationId
6324
6291
  );
6325
6292
  if (partialsToUpdate.length) {
6326
- this.updateShapes(partialsToUpdate);
6293
+ this.run(() => this.updateShapes(partialsToUpdate), { ignoreShapeLock });
6327
6294
  }
6328
6295
  this.off("tick", handleTick);
6329
6296
  return;
@@ -6356,13 +6323,13 @@ class Editor extends import_eventemitter3.default {
6356
6323
  throw Error("Editor.groupShapes: must provide an array of shapes or shape ids");
6357
6324
  }
6358
6325
  if (this.getIsReadonly()) return this;
6359
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
6360
- if (ids.length <= 1) return this;
6326
+ const ids = toShapeIds(shapes);
6361
6327
  const shapesToGroup = (0, import_utils.compact)(
6362
6328
  (this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
6363
6329
  (id) => this.getShape(id)
6364
6330
  )
6365
6331
  );
6332
+ if (shapesToGroup.length <= 1) return this;
6366
6333
  const sortedShapeIds = shapesToGroup.sort(import_utils.sortByIndex).map((s) => s.id);
6367
6334
  const childBounds = (0, import_utils.compact)(shapesToGroup.map((shape) => this.getShapePageBounds(shape)));
6368
6335
  const pageBounds = import_Box.Box.Common(childBounds);
@@ -6371,8 +6338,11 @@ class Editor extends import_eventemitter3.default {
6371
6338
  }
6372
6339
  const { x, y } = pageBounds.point;
6373
6340
  const parentId = this.findCommonAncestor(shapesToGroup) ?? this.getCurrentPageId();
6374
- if (this.getCurrentToolId() !== "select") return this;
6375
- if (!this.isIn("select.idle")) {
6341
+ if (!this.canCreateShapes([groupId])) {
6342
+ alertMaxShapes(this);
6343
+ return this;
6344
+ }
6345
+ if (this.isIn("select") && !this.isIn("select.idle")) {
6376
6346
  this.cancel();
6377
6347
  }
6378
6348
  const shapesWithRootParent = shapesToGroup.filter((shape) => shape.parentId === parentId).sort(import_utils.sortByIndex);
@@ -6400,15 +6370,14 @@ class Editor extends import_eventemitter3.default {
6400
6370
  ungroupShapes(shapes, opts = {}) {
6401
6371
  if (this.getIsReadonly()) return this;
6402
6372
  const { select = true } = opts;
6403
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
6373
+ const ids = toShapeIds(shapes);
6404
6374
  const shapesToUngroup = (0, import_utils.compact)(
6405
6375
  (this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
6406
6376
  (id) => this.getShape(id)
6407
6377
  )
6408
6378
  );
6409
6379
  if (shapesToUngroup.length === 0) return this;
6410
- if (this.getCurrentToolId() !== "select") return this;
6411
- if (!this.isIn("select.idle")) {
6380
+ if (this.isIn("select") && !this.isIn("select.idle")) {
6412
6381
  this.cancel();
6413
6382
  }
6414
6383
  const idsToSelect = /* @__PURE__ */ new Set();
@@ -6422,16 +6391,16 @@ class Editor extends import_eventemitter3.default {
6422
6391
  });
6423
6392
  if (groups.length === 0) return this;
6424
6393
  this.run(() => {
6425
- let group;
6426
6394
  for (let i = 0, n = groups.length; i < n; i++) {
6427
- group = groups[i];
6395
+ const group = this.getShape(groups[i].id);
6396
+ if (!group) continue;
6428
6397
  const childIds = this.getSortedChildIdsForParent(group.id);
6429
6398
  for (let j = 0, n2 = childIds.length; j < n2; j++) {
6430
6399
  idsToSelect.add(childIds[j]);
6431
6400
  }
6432
6401
  this.reparentShapes(childIds, group.parentId, group.index);
6433
6402
  }
6434
- this.deleteShapes(groups.map((group2) => group2.id));
6403
+ this.deleteShapes(groups.map((group) => group.id));
6435
6404
  if (select) {
6436
6405
  this.select(...idsToSelect);
6437
6406
  }
@@ -6512,14 +6481,14 @@ class Editor extends import_eventemitter3.default {
6512
6481
  }
6513
6482
  /** @internal */
6514
6483
  _getUnlockedShapeIds(ids) {
6515
- return ids.filter((id) => !this.getShape(id)?.isLocked);
6484
+ return ids.filter((id) => !this.isShapeOrAncestorLocked(id));
6516
6485
  }
6517
6486
  deleteShapes(_ids) {
6518
6487
  if (this.getIsReadonly()) return this;
6519
6488
  if (!Array.isArray(_ids)) {
6520
6489
  throw Error("Editor.deleteShapes: must provide an array of shapes or shapeIds");
6521
6490
  }
6522
- const shapeIds = typeof _ids[0] === "string" ? _ids : _ids.map((s) => s.id);
6491
+ const shapeIds = toShapeIds(_ids);
6523
6492
  const shapeIdsToDelete = this._shouldIgnoreShapeLock ? shapeIds : this._getUnlockedShapeIds(shapeIds);
6524
6493
  if (shapeIdsToDelete.length === 0) return this;
6525
6494
  const allShapeIdsToDelete = new Set(shapeIdsToDelete);
@@ -6864,7 +6833,7 @@ class Editor extends import_eventemitter3.default {
6864
6833
  * @public
6865
6834
  */
6866
6835
  getContentFromCurrentPage(shapes) {
6867
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
6836
+ const ids = toShapeIds(shapes);
6868
6837
  if (!ids) return;
6869
6838
  if (ids.length === 0) return;
6870
6839
  const shapeIds = this.getShapeAndDescendantIds(ids);
@@ -6932,21 +6901,29 @@ class Editor extends import_eventemitter3.default {
6932
6901
  await Promise.allSettled(
6933
6902
  content.assets.map(async (asset) => {
6934
6903
  if ((asset.type === "image" || asset.type === "video") && !asset.props.src?.startsWith("data:image") && !asset.props.src?.startsWith("data:video") && !asset.props.src?.startsWith("http")) {
6935
- const assetWithDataUrl = (0, import_utils.structuredClone)(asset);
6936
- const objectUrl = await this.store.props.assets.resolve(asset, {
6937
- screenScale: 1,
6938
- steppedScreenScale: 1,
6939
- dpr: 1,
6940
- networkEffectiveType: null,
6941
- shouldResolveToOriginal: true
6942
- });
6943
- assetWithDataUrl.props.src = await import_utils.FileHelpers.blobToDataUrl(
6944
- await (0, import_utils.fetch)(objectUrl).then((r) => r.blob())
6945
- );
6946
- assets.push(assetWithDataUrl);
6947
- } else {
6948
- assets.push(asset);
6904
+ try {
6905
+ const objectUrl = await this.store.props.assets.resolve(asset, {
6906
+ screenScale: 1,
6907
+ steppedScreenScale: 1,
6908
+ dpr: 1,
6909
+ networkEffectiveType: null,
6910
+ shouldResolveToOriginal: true
6911
+ });
6912
+ if (objectUrl) {
6913
+ const response = await (0, import_utils.fetch)(objectUrl);
6914
+ if (response.ok) {
6915
+ const assetWithDataUrl = (0, import_utils.structuredClone)(asset);
6916
+ assetWithDataUrl.props.src = await import_utils.FileHelpers.blobToDataUrl(await response.blob());
6917
+ assets.push(assetWithDataUrl);
6918
+ return;
6919
+ }
6920
+ console.warn(`Could not inline asset ${asset.id}: fetch returned ${response.status}`);
6921
+ }
6922
+ } catch (err) {
6923
+ console.warn(`Could not inline asset ${asset.id}`, err);
6924
+ }
6949
6925
  }
6926
+ assets.push(asset);
6950
6927
  })
6951
6928
  );
6952
6929
  content.assets = assets;
@@ -7240,7 +7217,7 @@ class Editor extends import_eventemitter3.default {
7240
7217
  * @public
7241
7218
  */
7242
7219
  async getSvgElement(shapes, opts = {}) {
7243
- const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
7220
+ const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : toShapeIds(shapes);
7244
7221
  if (ids.length === 0) return void 0;
7245
7222
  await this.fonts.loadRequiredFontsForCurrentPage(this.options.maxFontsToLoadBeforeRender);
7246
7223
  return (0, import_exportToSvg.exportToSvg)(this, ids, opts);
@@ -8294,8 +8271,8 @@ class Editor extends import_eventemitter3.default {
8294
8271
  break;
8295
8272
  }
8296
8273
  case "keyboard": {
8297
- if (info.key === "ShiftRight") info.key = "ShiftLeft";
8298
- if (info.key === "AltRight") info.key = "AltLeft";
8274
+ if (info.code === "ShiftRight") info.code = "ShiftLeft";
8275
+ if (info.code === "AltRight") info.code = "AltLeft";
8299
8276
  if (info.code === "ControlRight") info.code = "ControlLeft";
8300
8277
  if (info.code === "MetaRight") info.code = "MetaLeft";
8301
8278
  switch (info.name) {
@@ -8665,6 +8642,9 @@ function pushShapeWithDescendants(editor, id, result) {
8665
8642
  pushShapeWithDescendants(editor, childIds[i], result);
8666
8643
  }
8667
8644
  }
8645
+ function toShapeIds(shapes) {
8646
+ return typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
8647
+ }
8668
8648
  function withIsolatedShapes(editor, shapeIds, callback) {
8669
8649
  let result;
8670
8650
  editor.run(
@@ -8687,7 +8667,7 @@ function withIsolatedShapes(editor, shapeIds, callback) {
8687
8667
  }
8688
8668
  }
8689
8669
  }
8690
- editor.deleteBindings([...bindingsToRemove], { isolateShapes: true });
8670
+ editor._deleteBindings([...bindingsToRemove], { isolateShapes: true });
8691
8671
  try {
8692
8672
  result = import_utils.Result.ok(callback(bindingsWithBoth));
8693
8673
  } catch (error) {