@tldraw/editor 5.5.0-next.f9308d324e1c → 5.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (192) hide show
  1. package/dist-cjs/index.d.ts +49 -23
  2. package/dist-cjs/index.js +1 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +16 -12
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/MenuClickCapture.js +42 -3
  7. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +5 -1
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +2 -5
  11. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +3 -3
  12. package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
  13. package/dist-cjs/lib/editor/Editor.js +168 -181
  14. package/dist-cjs/lib/editor/Editor.js.map +3 -3
  15. package/dist-cjs/lib/editor/derivations/bindingsIndex.js +2 -0
  16. package/dist-cjs/lib/editor/derivations/bindingsIndex.js.map +2 -2
  17. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +3 -2
  18. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  19. package/dist-cjs/lib/editor/managers/EditorManager.js +11 -2
  20. package/dist-cjs/lib/editor/managers/EditorManager.js.map +2 -2
  21. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js +49 -63
  22. package/dist-cjs/lib/editor/managers/PerformanceManager/PerformanceManager.js.map +2 -2
  23. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js +1 -1
  24. package/dist-cjs/lib/editor/managers/ScribbleManager/ScribbleManager.js.map +2 -2
  25. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js +24 -24
  26. package/dist-cjs/lib/editor/managers/SnapManager/BoundsSnaps.js.map +2 -2
  27. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js +7 -1
  28. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
  29. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +4 -3
  30. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  31. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +4 -4
  32. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  33. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +14 -6
  34. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +3 -3
  35. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  36. package/dist-cjs/lib/exports/ExportDelay.js +10 -2
  37. package/dist-cjs/lib/exports/ExportDelay.js.map +2 -2
  38. package/dist-cjs/lib/exports/FontEmbedder.js +25 -11
  39. package/dist-cjs/lib/exports/FontEmbedder.js.map +2 -2
  40. package/dist-cjs/lib/exports/StyleEmbedder.js +9 -4
  41. package/dist-cjs/lib/exports/StyleEmbedder.js.map +2 -2
  42. package/dist-cjs/lib/exports/fetchCache.js +3 -0
  43. package/dist-cjs/lib/exports/fetchCache.js.map +2 -2
  44. package/dist-cjs/lib/exports/getSvgAsImage.js +10 -4
  45. package/dist-cjs/lib/exports/getSvgAsImage.js.map +2 -2
  46. package/dist-cjs/lib/exports/getSvgJsx.js +18 -9
  47. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  48. package/dist-cjs/lib/exports/parseCss.js +1 -1
  49. package/dist-cjs/lib/exports/parseCss.js.map +1 -1
  50. package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
  51. package/dist-cjs/lib/hooks/useCanvasEvents.js +24 -0
  52. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  53. package/dist-cjs/lib/hooks/useIdentity.js +6 -2
  54. package/dist-cjs/lib/hooks/useIdentity.js.map +3 -3
  55. package/dist-cjs/lib/license/LicenseManager.js +9 -1
  56. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  57. package/dist-cjs/lib/license/LicenseProvider.js +12 -4
  58. package/dist-cjs/lib/license/LicenseProvider.js.map +2 -2
  59. package/dist-cjs/lib/utils/debug-flags.js +0 -6
  60. package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
  61. package/dist-cjs/lib/utils/deepLinks.js +2 -1
  62. package/dist-cjs/lib/utils/deepLinks.js.map +2 -2
  63. package/dist-cjs/lib/utils/sync/LocalIndexedDb.js +32 -25
  64. package/dist-cjs/lib/utils/sync/LocalIndexedDb.js.map +2 -2
  65. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js +81 -40
  66. package/dist-cjs/lib/utils/sync/TLLocalSyncClient.js.map +2 -2
  67. package/dist-cjs/version.js +3 -3
  68. package/dist-cjs/version.js.map +1 -1
  69. package/dist-esm/index.d.mts +49 -23
  70. package/dist-esm/index.mjs +4 -2
  71. package/dist-esm/index.mjs.map +2 -2
  72. package/dist-esm/lib/TldrawEditor.mjs +17 -13
  73. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  74. package/dist-esm/lib/components/MenuClickCapture.mjs +42 -3
  75. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  76. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +5 -1
  77. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  78. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +2 -5
  79. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +3 -3
  80. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
  81. package/dist-esm/lib/editor/Editor.mjs +168 -181
  82. package/dist-esm/lib/editor/Editor.mjs.map +3 -3
  83. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs +2 -0
  84. package/dist-esm/lib/editor/derivations/bindingsIndex.mjs.map +2 -2
  85. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +3 -2
  86. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  87. package/dist-esm/lib/editor/managers/EditorManager.mjs +11 -2
  88. package/dist-esm/lib/editor/managers/EditorManager.mjs.map +2 -2
  89. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs +49 -63
  90. package/dist-esm/lib/editor/managers/PerformanceManager/PerformanceManager.mjs.map +2 -2
  91. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs +1 -1
  92. package/dist-esm/lib/editor/managers/ScribbleManager/ScribbleManager.mjs.map +2 -2
  93. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs +24 -24
  94. package/dist-esm/lib/editor/managers/SnapManager/BoundsSnaps.mjs.map +2 -2
  95. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs +7 -1
  96. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
  97. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +4 -3
  98. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  99. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +4 -4
  100. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  101. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +14 -6
  102. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +3 -3
  103. package/dist-esm/lib/exports/ExportDelay.mjs +11 -3
  104. package/dist-esm/lib/exports/ExportDelay.mjs.map +2 -2
  105. package/dist-esm/lib/exports/FontEmbedder.mjs +25 -11
  106. package/dist-esm/lib/exports/FontEmbedder.mjs.map +2 -2
  107. package/dist-esm/lib/exports/StyleEmbedder.mjs +9 -4
  108. package/dist-esm/lib/exports/StyleEmbedder.mjs.map +2 -2
  109. package/dist-esm/lib/exports/fetchCache.mjs +3 -0
  110. package/dist-esm/lib/exports/fetchCache.mjs.map +2 -2
  111. package/dist-esm/lib/exports/getSvgAsImage.mjs +10 -4
  112. package/dist-esm/lib/exports/getSvgAsImage.mjs.map +2 -2
  113. package/dist-esm/lib/exports/getSvgJsx.mjs +18 -9
  114. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  115. package/dist-esm/lib/exports/parseCss.mjs +1 -1
  116. package/dist-esm/lib/exports/parseCss.mjs.map +1 -1
  117. package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
  118. package/dist-esm/lib/hooks/useCanvasEvents.mjs +24 -0
  119. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  120. package/dist-esm/lib/hooks/useIdentity.mjs +7 -3
  121. package/dist-esm/lib/hooks/useIdentity.mjs.map +3 -3
  122. package/dist-esm/lib/license/LicenseManager.mjs +9 -1
  123. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  124. package/dist-esm/lib/license/LicenseProvider.mjs +13 -5
  125. package/dist-esm/lib/license/LicenseProvider.mjs.map +2 -2
  126. package/dist-esm/lib/utils/debug-flags.mjs +0 -6
  127. package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
  128. package/dist-esm/lib/utils/deepLinks.mjs +2 -1
  129. package/dist-esm/lib/utils/deepLinks.mjs.map +2 -2
  130. package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs +32 -25
  131. package/dist-esm/lib/utils/sync/LocalIndexedDb.mjs.map +2 -2
  132. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs +81 -40
  133. package/dist-esm/lib/utils/sync/TLLocalSyncClient.mjs.map +2 -2
  134. package/dist-esm/version.mjs +3 -3
  135. package/dist-esm/version.mjs.map +1 -1
  136. package/editor.css +9 -1
  137. package/package.json +8 -11
  138. package/src/index.ts +5 -1
  139. package/src/lib/TldrawEditor.tsx +35 -21
  140. package/src/lib/components/MenuClickCapture.tsx +55 -4
  141. package/src/lib/components/default-components/DefaultCanvas.tsx +7 -1
  142. package/src/lib/components/default-components/DefaultErrorFallback.tsx +13 -5
  143. package/src/lib/components/default-components/DefaultSpinner.tsx +4 -1
  144. package/src/lib/editor/Editor.test.ts +65 -0
  145. package/src/lib/editor/Editor.ts +261 -294
  146. package/src/lib/editor/derivations/bindingsIndex.ts +3 -0
  147. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +1 -0
  148. package/src/lib/editor/managers/ClickManager/ClickManager.ts +3 -2
  149. package/src/lib/editor/managers/EditorManager.test.ts +32 -1
  150. package/src/lib/editor/managers/EditorManager.ts +15 -3
  151. package/src/lib/editor/managers/PerformanceManager/PerformanceManager.test.ts +80 -0
  152. package/src/lib/editor/managers/PerformanceManager/PerformanceManager.ts +54 -81
  153. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.ts +1 -1
  154. package/src/lib/editor/managers/SnapManager/BoundsSnaps.ts +32 -36
  155. package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +13 -2
  156. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +13 -0
  157. package/src/lib/editor/managers/SnapManager/SnapManager.ts +6 -4
  158. package/src/lib/editor/managers/TextManager/TextManager.test.ts +74 -0
  159. package/src/lib/editor/managers/TextManager/TextManager.ts +6 -5
  160. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +23 -8
  161. package/src/lib/editor/types/external-content.ts +5 -0
  162. package/src/lib/exports/ExportDelay.tsx +16 -4
  163. package/src/lib/exports/FontEmbedder.test.ts +99 -0
  164. package/src/lib/exports/FontEmbedder.ts +32 -11
  165. package/src/lib/exports/StyleEmbedder.ts +13 -4
  166. package/src/lib/exports/fetchCache.test.ts +22 -0
  167. package/src/lib/exports/fetchCache.ts +4 -0
  168. package/src/lib/exports/getSvgAsImage.ts +13 -5
  169. package/src/lib/exports/getSvgJsx.test.ts +43 -1
  170. package/src/lib/exports/getSvgJsx.tsx +28 -16
  171. package/src/lib/exports/parseCss.test.ts +4 -0
  172. package/src/lib/exports/parseCss.ts +2 -2
  173. package/src/lib/hooks/EditorComponentsContext.tsx +2 -1
  174. package/src/lib/hooks/useCanvasEvents.ts +42 -0
  175. package/src/lib/hooks/useIdentity.tsx +12 -1
  176. package/src/lib/license/LicenseManager.ts +13 -1
  177. package/src/lib/license/LicenseProvider.test.tsx +76 -0
  178. package/src/lib/license/LicenseProvider.tsx +19 -5
  179. package/src/lib/test/preserveFocus.test.tsx +81 -0
  180. package/src/lib/utils/debug-flags.ts +0 -6
  181. package/src/lib/utils/deepLinks.test.ts +15 -0
  182. package/src/lib/utils/deepLinks.ts +8 -3
  183. package/src/lib/utils/sync/LocalIndexedDb.test.ts +121 -1
  184. package/src/lib/utils/sync/LocalIndexedDb.ts +41 -28
  185. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +257 -1
  186. package/src/lib/utils/sync/TLLocalSyncClient.ts +112 -54
  187. package/src/version.ts +3 -3
  188. package/dist-cjs/lib/primitives/geometry/geometry.bench.js +0 -133
  189. package/dist-cjs/lib/primitives/geometry/geometry.bench.js.map +0 -7
  190. package/dist-esm/lib/primitives/geometry/geometry.bench.mjs +0 -132
  191. package/dist-esm/lib/primitives/geometry/geometry.bench.mjs.map +0 -7
  192. package/src/lib/primitives/geometry/geometry.bench.ts +0 -179
@@ -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 }]);
@@ -1403,7 +1408,7 @@ class Editor extends import_eventemitter3.default {
1403
1408
  updateInstanceState(partial, historyOptions) {
1404
1409
  this._updateInstanceState(partial, { history: "ignore", ...historyOptions });
1405
1410
  if (partial.isChangingStyle !== void 0) {
1406
- clearTimeout(this._isChangingStyleTimeout);
1411
+ this.timers.clearTimeout(this._isChangingStyleTimeout);
1407
1412
  if (partial.isChangingStyle === true) {
1408
1413
  this._isChangingStyleTimeout = this.timers.setTimeout(() => {
1409
1414
  this._updateInstanceState({ isChangingStyle: false }, { history: "ignore" });
@@ -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,12 +1615,15 @@ 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
1628
  const startIndex = currentIndex === -1 && direction === "prev" ? 0 : currentIndex;
1621
1629
  const adjacentIndex = (startIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
@@ -1717,13 +1725,14 @@ class Editor extends import_eventemitter3.default {
1717
1725
  });
1718
1726
  if (shapesInDirection.length === 0) return currentShapeId;
1719
1727
  const lowestScoringShape = (0, import_utils.minBy)(shapesInDirection, ({ center }) => {
1720
- const distance = import_Vec.Vec.Dist2(currentCenter, center);
1728
+ const distance = import_Vec.Vec.Dist(currentCenter, center);
1721
1729
  const dirProp = ["left", "right"].includes(direction) ? "x" : "y";
1722
1730
  const directionalDistance = Math.abs(center[dirProp] - currentCenter[dirProp]);
1723
1731
  const offProp = ["left", "right"].includes(direction) ? "y" : "x";
1724
1732
  const offAxisDeviation = Math.abs(center[offProp] - currentCenter[offProp]);
1725
- const angle = Math.abs(import_Vec.Vec.Angle(currentCenter, center) * (180 / Math.PI));
1726
- 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);
1727
1736
  return distance * 1 + // Base distance
1728
1737
  offAxisDeviation * 2 + // Heavy penalty for off-axis deviation
1729
1738
  (distance - directionalDistance) * 1.5 + // Penalty for diagonal distance
@@ -2061,7 +2070,7 @@ class Editor extends import_eventemitter3.default {
2061
2070
  * @public
2062
2071
  */
2063
2072
  setHintingShapes(shapes) {
2064
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
2073
+ const ids = toShapeIds(shapes);
2065
2074
  this.run(
2066
2075
  () => {
2067
2076
  this._updateCurrentPageState({ hintingShapeIds: (0, import_utils.dedupe)(ids) });
@@ -2091,7 +2100,7 @@ class Editor extends import_eventemitter3.default {
2091
2100
  * @public
2092
2101
  */
2093
2102
  setErasingShapes(shapes) {
2094
- const ids = typeof shapes[0] === "string" ? shapes.slice() : shapes.map((shape) => shape.id);
2103
+ const ids = toShapeIds(shapes).slice();
2095
2104
  ids.sort();
2096
2105
  const erasingShapeIds = this.getErasingShapeIds();
2097
2106
  this.run(
@@ -2498,14 +2507,16 @@ class Editor extends import_eventemitter3.default {
2498
2507
  setCamera(point, opts) {
2499
2508
  const { isLocked } = this._cameraOptions.__unsafe__getWithoutCapture();
2500
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
+ }
2501
2516
  this.stopCameraAnimation();
2502
2517
  if (this.getInstanceState().followingUserId) {
2503
2518
  this.stopFollowingUser();
2504
2519
  }
2505
- const _point = import_Vec.Vec.Cast(point);
2506
- if (!Number.isFinite(_point.x)) _point.x = 0;
2507
- if (!Number.isFinite(_point.y)) _point.y = 0;
2508
- if (_point.z === void 0 || !Number.isFinite(_point.z)) point.z = this.getZoomLevel();
2509
2520
  const camera = this.getConstrainedCamera(_point, opts);
2510
2521
  if (opts?.animation) {
2511
2522
  const { width, height } = this.getViewportScreenBounds();
@@ -2790,11 +2801,14 @@ class Editor extends import_eventemitter3.default {
2790
2801
  _animateViewport(ms) {
2791
2802
  if (!this._viewportAnimation) return;
2792
2803
  this._viewportAnimation.elapsed += ms;
2793
- const { elapsed, easing, duration, start, end } = this._viewportAnimation;
2804
+ const { elapsed, easing, duration, start, end, opts } = this._viewportAnimation;
2794
2805
  if (elapsed > duration) {
2795
2806
  this.off("tick", this._animateViewport);
2796
2807
  this._viewportAnimation = null;
2797
- this._setCamera(new import_Vec.Vec(-end.x, -end.y, this.getViewportScreenBounds().width / end.width));
2808
+ this._setCamera(
2809
+ new import_Vec.Vec(-end.x, -end.y, this.getViewportScreenBounds().width / end.width),
2810
+ opts
2811
+ );
2798
2812
  return;
2799
2813
  }
2800
2814
  const remaining = duration - elapsed;
@@ -2832,7 +2846,8 @@ class Editor extends import_eventemitter3.default {
2832
2846
  duration: duration / animationSpeed,
2833
2847
  easing,
2834
2848
  start: viewportPageBounds.clone(),
2835
- end: targetViewportPage.clone()
2849
+ end: targetViewportPage.clone(),
2850
+ opts: rest
2836
2851
  };
2837
2852
  this.once("stop-camera-animation", () => {
2838
2853
  this.off("tick", this._animateViewport);
@@ -2918,6 +2933,7 @@ class Editor extends import_eventemitter3.default {
2918
2933
  }
2919
2934
  const isOnSamePage = presence.currentPageId === this.getCurrentPageId();
2920
2935
  if (!isOnSamePage) {
2936
+ this.markHistoryStoppingPoint("change-page");
2921
2937
  this.setCurrentPage(presence.currentPageId);
2922
2938
  }
2923
2939
  if (opts && opts.animation && !isOnSamePage) {
@@ -3749,7 +3765,9 @@ class Editor extends import_eventemitter3.default {
3749
3765
  if (ids.length <= 0) return this;
3750
3766
  this.run(
3751
3767
  () => {
3752
- this.store.props.assets.remove?.(ids);
3768
+ Promise.resolve(this.store.props.assets.remove?.(ids)).catch(
3769
+ (err) => console.error("Error while removing assets from the asset store:", err)
3770
+ );
3753
3771
  this.store.remove(ids);
3754
3772
  },
3755
3773
  { history: "ignore" }
@@ -4131,7 +4149,7 @@ class Editor extends import_eventemitter3.default {
4131
4149
  if (shapes.length === 0) {
4132
4150
  return;
4133
4151
  }
4134
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4152
+ const ids = toShapeIds(shapes);
4135
4153
  const freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
4136
4154
  if (freshShapes.length === 1) {
4137
4155
  const parentId = freshShapes[0].parentId;
@@ -4228,12 +4246,14 @@ class Editor extends import_eventemitter3.default {
4228
4246
  */
4229
4247
  getSelectedShapeAtPoint(point) {
4230
4248
  const selectedShapeIds = this.getSelectedShapeIds();
4231
- const margin = this.options.hitTestMargin / this.getZoomLevel();
4249
+ if (selectedShapeIds.length === 0) return void 0;
4250
+ const selectedShapeIdSet = new Set(selectedShapeIds);
4251
+ const margin = this.getHitTestMargin();
4232
4252
  const sortedShapes = this.getCurrentPageShapesSorted();
4233
4253
  for (let i = sortedShapes.length - 1; i >= 0; i--) {
4234
4254
  const shape = sortedShapes[i];
4235
4255
  if (shape.type === "group") continue;
4236
- if (!selectedShapeIds.includes(shape.id)) continue;
4256
+ if (!selectedShapeIdSet.has(shape.id)) continue;
4237
4257
  if (this.getShapeGeometry(shape).hitTestPoint(
4238
4258
  this.getPointInShapeSpace(shape, point),
4239
4259
  margin,
@@ -4331,7 +4351,6 @@ class Editor extends import_eventemitter3.default {
4331
4351
  }
4332
4352
  return inMarginClosestToEdgeHit || shape;
4333
4353
  } else {
4334
- if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
4335
4354
  if (hitInside ? (
4336
4355
  // On hitInside, the distance will be negative for hits inside
4337
4356
  // If the distance is positive, check against the outer margin
@@ -4348,6 +4367,7 @@ class Editor extends import_eventemitter3.default {
4348
4367
  inMarginClosestToEdgeHit = shape;
4349
4368
  }
4350
4369
  } else if (!inMarginClosestToEdgeHit) {
4370
+ if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
4351
4371
  const { area } = geometry;
4352
4372
  if (area < inHollowSmallestArea) {
4353
4373
  inHollowSmallestArea = area;
@@ -4358,6 +4378,9 @@ class Editor extends import_eventemitter3.default {
4358
4378
  }
4359
4379
  } else {
4360
4380
  if (distance < this.getHitTestMargin()) {
4381
+ if (inMarginClosestToEdgeHit && inMarginClosestToEdgeDistance <= distance) {
4382
+ return inMarginClosestToEdgeHit;
4383
+ }
4361
4384
  return shape;
4362
4385
  }
4363
4386
  }
@@ -4634,7 +4657,7 @@ class Editor extends import_eventemitter3.default {
4634
4657
  * @public
4635
4658
  */
4636
4659
  reparentShapes(shapes, parentId, insertIndex) {
4637
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4660
+ const ids = toShapeIds(shapes);
4638
4661
  if (ids.length === 0) return this;
4639
4662
  const changes = [];
4640
4663
  const parentTransform = (0, import_tlschema.isPageId)(parentId) ? import_Mat.Mat.Identity() : this.getShapePageTransform(parentId);
@@ -4863,6 +4886,7 @@ class Editor extends import_eventemitter3.default {
4863
4886
  * binding, but the `type`, `toId`, and `fromId` must all be provided.
4864
4887
  */
4865
4888
  createBindings(partials) {
4889
+ if (this.getIsReadonly()) return this;
4866
4890
  const bindings = [];
4867
4891
  for (const partial of partials) {
4868
4892
  const fromShape = this.getShape(partial.fromId);
@@ -4897,6 +4921,7 @@ class Editor extends import_eventemitter3.default {
4897
4921
  * binding is skipped. The changes from the partial are merged into the existing record.
4898
4922
  */
4899
4923
  updateBindings(partials) {
4924
+ if (this.getIsReadonly()) return this;
4900
4925
  const updated = [];
4901
4926
  for (const partial of partials) {
4902
4927
  if (!partial) continue;
@@ -4925,6 +4950,16 @@ class Editor extends import_eventemitter3.default {
4925
4950
  * Delete several bindings by their IDs. If a binding ID doesn't exist, it's ignored.
4926
4951
  */
4927
4952
  deleteBindings(bindings, { isolateShapes = false } = {}) {
4953
+ if (this.getIsReadonly()) return this;
4954
+ return this._deleteBindings(bindings, { isolateShapes });
4955
+ }
4956
+ /**
4957
+ * Unguarded so that withIsolatedShapes can transiently isolate shapes for copy and export in
4958
+ * readonly mode; the public deleteBindings is what readonly blocks.
4959
+ *
4960
+ * @internal
4961
+ */
4962
+ _deleteBindings(bindings, { isolateShapes = false } = {}) {
4928
4963
  const ids = bindings.map((binding) => typeof binding === "string" ? binding : binding.id);
4929
4964
  if (isolateShapes) {
4930
4965
  this.store.atomic(() => {
@@ -4983,7 +5018,7 @@ class Editor extends import_eventemitter3.default {
4983
5018
  * @param opts - The options for the rotation.
4984
5019
  */
4985
5020
  rotateShapesBy(shapes, delta, opts) {
4986
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5021
+ const ids = toShapeIds(shapes);
4987
5022
  if (ids.length <= 0) return this;
4988
5023
  const snapshot = (0, import_rotation.getRotationSnapshot)({ editor: this, ids });
4989
5024
  if (!snapshot) return this;
@@ -5020,6 +5055,14 @@ class Editor extends import_eventemitter3.default {
5020
5055
  }
5021
5056
  return workingShape;
5022
5057
  }
5058
+ // Counter-rotates the page-space delta into the parent's space; without that a child of a rotated
5059
+ // frame or group would move along its parent's axes instead of the page's.
5060
+ // todo: a shape laid out together with its own parent moves twice, once with the parent and once
5061
+ // on its own; the layout commands should skip shapes whose ancestors are also being laid out
5062
+ getChangesToTranslateShapeByPageDelta(shape, pageDelta) {
5063
+ const localDelta = import_Vec.Vec.From(pageDelta).rot(-this.getShapeParentTransform(shape).rotation());
5064
+ return this.getChangesToTranslateShape(shape, localDelta.add(shape));
5065
+ }
5023
5066
  /**
5024
5067
  * Move shapes by a delta.
5025
5068
  *
@@ -5032,14 +5075,12 @@ class Editor extends import_eventemitter3.default {
5032
5075
  * @param offset - The offset to apply to the shapes.
5033
5076
  */
5034
5077
  nudgeShapes(shapes, offset) {
5035
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5078
+ const ids = toShapeIds(shapes);
5036
5079
  if (ids.length <= 0) return this;
5037
5080
  const changes = [];
5038
5081
  for (const id of ids) {
5039
5082
  const shape = this.getShape(id);
5040
- const localDelta = import_Vec.Vec.From(offset);
5041
- localDelta.rot(-this.getShapeParentTransform(shape).rotation());
5042
- changes.push(this.getChangesToTranslateShape(shape, localDelta.add(shape)));
5083
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, offset));
5043
5084
  }
5044
5085
  this.updateShapes(changes);
5045
5086
  return this;
@@ -5060,7 +5101,7 @@ class Editor extends import_eventemitter3.default {
5060
5101
  */
5061
5102
  duplicateShapes(shapes, offset) {
5062
5103
  this.run(() => {
5063
- const _ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5104
+ const _ids = toShapeIds(shapes);
5064
5105
  const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids);
5065
5106
  if (ids.length <= 0) return this;
5066
5107
  const initialIds = new Set(ids);
@@ -5169,7 +5210,7 @@ class Editor extends import_eventemitter3.default {
5169
5210
  * @public
5170
5211
  */
5171
5212
  moveShapesToPage(shapes, pageId) {
5172
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5213
+ const ids = toShapeIds(shapes);
5173
5214
  if (ids.length === 0) return this;
5174
5215
  if (this.getIsReadonly()) return this;
5175
5216
  const currentPageId = this.getCurrentPageId();
@@ -5205,7 +5246,7 @@ class Editor extends import_eventemitter3.default {
5205
5246
  * @public
5206
5247
  */
5207
5248
  toggleLock(shapes) {
5208
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5249
+ const ids = toShapeIds(shapes);
5209
5250
  if (this.getIsReadonly() || ids.length === 0) return this;
5210
5251
  let allLocked = true;
5211
5252
  const shapesToToggle = [];
@@ -5244,7 +5285,7 @@ class Editor extends import_eventemitter3.default {
5244
5285
  * @public
5245
5286
  */
5246
5287
  sendToBack(shapes) {
5247
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5288
+ const ids = toShapeIds(shapes);
5248
5289
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "toBack", ids, {
5249
5290
  considerAllShapes: true
5250
5291
  });
@@ -5274,7 +5315,7 @@ class Editor extends import_eventemitter3.default {
5274
5315
  * @public
5275
5316
  */
5276
5317
  sendBackward(shapes, opts = {}) {
5277
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5318
+ const ids = toShapeIds(shapes);
5278
5319
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "backward", ids, opts);
5279
5320
  if (changes) this.updateShapes(changes);
5280
5321
  return this;
@@ -5302,7 +5343,7 @@ class Editor extends import_eventemitter3.default {
5302
5343
  * @public
5303
5344
  */
5304
5345
  bringForward(shapes, opts = {}) {
5305
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5346
+ const ids = toShapeIds(shapes);
5306
5347
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "forward", ids, opts);
5307
5348
  if (changes) this.updateShapes(changes);
5308
5349
  return this;
@@ -5321,7 +5362,7 @@ class Editor extends import_eventemitter3.default {
5321
5362
  * @public
5322
5363
  */
5323
5364
  bringToFront(shapes) {
5324
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5365
+ const ids = toShapeIds(shapes);
5325
5366
  const changes = (0, import_reorderShapes.getReorderingShapesChanges)(this, "toFront", ids);
5326
5367
  if (changes) this.updateShapes(changes);
5327
5368
  return this;
@@ -5333,7 +5374,7 @@ class Editor extends import_eventemitter3.default {
5333
5374
  * @internal
5334
5375
  */
5335
5376
  getShapeClusters(shapes, type, opts) {
5336
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5377
+ const ids = toShapeIds(shapes);
5337
5378
  let freshShapes = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
5338
5379
  if (opts?.filterAxisAligned) {
5339
5380
  freshShapes = freshShapes.filter((s) => {
@@ -5358,7 +5399,7 @@ class Editor extends import_eventemitter3.default {
5358
5399
  const shapesMovingTogether = [shape];
5359
5400
  const boundsOfShapesMovingTogether = [shapePageBounds];
5360
5401
  this.collectShapesViaArrowBindings({
5361
- bindings: this.getBindingsToShape(shape.id, "arrow"),
5402
+ bindings: this.getBindingsInvolvingShape(shape.id, "arrow"),
5362
5403
  initialShapes: freshShapes,
5363
5404
  resultShapes: shapesMovingTogether,
5364
5405
  resultBounds: boundsOfShapesMovingTogether,
@@ -5414,7 +5455,7 @@ class Editor extends import_eventemitter3.default {
5414
5455
  */
5415
5456
  flipShapes(shapes, operation) {
5416
5457
  if (this.getIsReadonly()) return this;
5417
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5458
+ const ids = toShapeIds(shapes);
5418
5459
  const shapesToFlipFirstPass = (0, import_utils.compact)(ids.map((id) => this.getShape(id)));
5419
5460
  for (const shape of shapesToFlipFirstPass) {
5420
5461
  if (this.isShapeOfType(shape, "group")) {
@@ -5488,21 +5529,7 @@ class Editor extends import_eventemitter3.default {
5488
5529
  const { clusters: shapeClustersToStack } = this.getShapeClusters(shapes, "stack");
5489
5530
  const len = shapeClustersToStack.length;
5490
5531
  if (_gap === 0 && len < 3 || len < 2) return this;
5491
- let val;
5492
- let min;
5493
- let max;
5494
- let dim;
5495
- if (operation === "horizontal") {
5496
- val = "x";
5497
- min = "minX";
5498
- max = "maxX";
5499
- dim = "width";
5500
- } else {
5501
- val = "y";
5502
- min = "minY";
5503
- max = "maxY";
5504
- dim = "height";
5505
- }
5532
+ const { val, min, max, dim } = AXIS[operation];
5506
5533
  let shapeGap = 0;
5507
5534
  shapeClustersToStack.sort((a, b) => a.pageBounds[min] - b.pageBounds[min]);
5508
5535
  if (_gap === 0) {
@@ -5541,13 +5568,7 @@ class Editor extends import_eventemitter3.default {
5541
5568
  const delta = new import_Vec.Vec();
5542
5569
  delta[val] = v + shapeGap - pageBounds[val];
5543
5570
  for (const shape of shapes2) {
5544
- const shapeDelta = delta.clone();
5545
- const parent = this.getShapeParent(shape);
5546
- if (parent) {
5547
- shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5548
- }
5549
- shapeDelta.add(shape);
5550
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5571
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5551
5572
  }
5552
5573
  v += pageBounds[dim] + shapeGap;
5553
5574
  }
@@ -5627,13 +5648,7 @@ class Editor extends import_eventemitter3.default {
5627
5648
  for (const { shapes: shapes2, pageBounds, nextPageBounds } of shapeClustersToPack) {
5628
5649
  const delta = import_Vec.Vec.Sub(nextPageBounds.point, pageBounds.point).add(centerDelta);
5629
5650
  for (const shape of shapes2) {
5630
- const shapeDelta = delta.clone();
5631
- const parent = this.getShapeParent(shape);
5632
- if (parent) {
5633
- shapeDelta.rot(-this.getShapeParentTransform(shape).rotation());
5634
- }
5635
- shapeDelta.add(shape);
5636
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5651
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5637
5652
  }
5638
5653
  }
5639
5654
  if (changes.length) {
@@ -5693,13 +5708,7 @@ class Editor extends import_eventemitter3.default {
5693
5708
  }
5694
5709
  }
5695
5710
  for (const shape of shapes2) {
5696
- const shapeDelta = delta.clone();
5697
- const parent = this.getShapeParent(shape);
5698
- if (parent) {
5699
- shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5700
- }
5701
- shapeDelta.add(shape);
5702
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5711
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5703
5712
  }
5704
5713
  });
5705
5714
  this.updateShapes(changes);
@@ -5723,27 +5732,13 @@ class Editor extends import_eventemitter3.default {
5723
5732
  if (this.getIsReadonly()) return this;
5724
5733
  const { clusters: shapeClustersToDistribute } = this.getShapeClusters(shapes, "distribute");
5725
5734
  if (shapeClustersToDistribute.length < 3) return this;
5726
- let val;
5727
- let min;
5728
- let max;
5729
- let dim;
5730
- if (operation === "horizontal") {
5731
- val = "x";
5732
- min = "minX";
5733
- max = "maxX";
5734
- dim = "width";
5735
- } else {
5736
- val = "y";
5737
- min = "minY";
5738
- max = "maxY";
5739
- dim = "height";
5740
- }
5735
+ const { val, min, max, dim } = AXIS[operation];
5741
5736
  const changes = [];
5742
5737
  const first = shapeClustersToDistribute.sort((a, b) => a.pageBounds[min] - b.pageBounds[min])[0];
5743
5738
  const last2 = shapeClustersToDistribute.sort((a, b) => b.pageBounds[max] - a.pageBounds[max])[0];
5744
5739
  if (first === last2) {
5745
5740
  const excludedShapeIds = new Set(first.shapes.map((s) => s.id));
5746
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
5741
+ const ids = toShapeIds(shapes);
5747
5742
  return this.distributeShapes(
5748
5743
  ids.filter((id) => !excludedShapeIds.has(id)),
5749
5744
  operation
@@ -5767,13 +5762,7 @@ class Editor extends import_eventemitter3.default {
5767
5762
  delta[val] = last2.pageBounds[max] - pageBounds[max] - 1;
5768
5763
  }
5769
5764
  for (const shape of shapes2) {
5770
- const shapeDelta = delta.clone();
5771
- const parent = this.getShapeParent(shape);
5772
- if (parent) {
5773
- shapeDelta.rot(-this.getShapePageTransform(parent).rotation());
5774
- }
5775
- shapeDelta.add(shape);
5776
- changes.push(this.getChangesToTranslateShape(shape, shapeDelta));
5765
+ changes.push(this.getChangesToTranslateShapeByPageDelta(shape, delta));
5777
5766
  }
5778
5767
  v += pageBounds[dim] + gap;
5779
5768
  }
@@ -5803,32 +5792,17 @@ class Editor extends import_eventemitter3.default {
5803
5792
  );
5804
5793
  if (shapeClustersToStretch.length < 2) return this;
5805
5794
  const commonBounds = import_Box.Box.Common(allBounds);
5806
- let val;
5807
- let min;
5808
- let dim;
5809
- if (operation === "horizontal") {
5810
- val = "x";
5811
- min = "minX";
5812
- dim = "width";
5813
- } else {
5814
- val = "y";
5815
- min = "minY";
5816
- dim = "height";
5817
- }
5795
+ const { val, min, dim } = AXIS[operation];
5818
5796
  this.run(() => {
5819
5797
  shapeClustersToStretch.forEach(({ shapes: shapes2, pageBounds }) => {
5820
- const localOffset = new import_Vec.Vec();
5821
- localOffset[val] = commonBounds[min] - pageBounds[min];
5798
+ const pageOffset = new import_Vec.Vec();
5799
+ pageOffset[val] = commonBounds[min] - pageBounds[min];
5822
5800
  const scaleOrigin = pageBounds.center.clone();
5823
5801
  scaleOrigin[val] = commonBounds[min];
5824
5802
  const scale = new import_Vec.Vec(1, 1);
5825
5803
  scale[val] = commonBounds[dim] / pageBounds[dim];
5826
5804
  for (const shape of shapes2) {
5827
- const shapeLocalOffset = localOffset.clone();
5828
- shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5829
- shapeLocalOffset.add(shape);
5830
- const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5831
- this.updateShape(changes);
5805
+ this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
5832
5806
  this.resizeShape(shape.id, scale, {
5833
5807
  initialBounds: this.getShapeGeometry(shape).bounds,
5834
5808
  scaleOrigin,
@@ -5871,7 +5845,7 @@ class Editor extends import_eventemitter3.default {
5871
5845
  const scaleY = targetBounds.height / commonBounds.height;
5872
5846
  const scale = new import_Vec.Vec(scaleX, scaleY);
5873
5847
  shapeClusters.forEach(({ shapes: shapes2, pageBounds }) => {
5874
- const localOffset = new import_Vec.Vec(
5848
+ const pageOffset = new import_Vec.Vec(
5875
5849
  targetBounds.minX - commonBounds.minX + (pageBounds.minX - commonBounds.minX) * (scaleX - 1),
5876
5850
  targetBounds.minY - commonBounds.minY + (pageBounds.minY - commonBounds.minY) * (scaleY - 1)
5877
5851
  );
@@ -5880,11 +5854,7 @@ class Editor extends import_eventemitter3.default {
5880
5854
  targetBounds.minY + (pageBounds.minY - commonBounds.minY) * scaleY
5881
5855
  );
5882
5856
  for (const shape of shapes2) {
5883
- const shapeLocalOffset = localOffset.clone();
5884
- shapeLocalOffset.rot(-this.getShapeParentTransform(shape).rotation());
5885
- shapeLocalOffset.add(shape);
5886
- const changes = this.getChangesToTranslateShape(shape, shapeLocalOffset);
5887
- this.updateShape(changes);
5857
+ this.updateShape(this.getChangesToTranslateShapeByPageDelta(shape, pageOffset));
5888
5858
  this.resizeShape(shape.id, scale, {
5889
5859
  initialBounds: this.getShapeGeometry(shape).bounds,
5890
5860
  scaleOrigin,
@@ -6303,12 +6273,17 @@ class Editor extends import_eventemitter3.default {
6303
6273
  let remaining = duration;
6304
6274
  let t;
6305
6275
  const animations = [];
6276
+ const ignoreShapeLock = this._shouldIgnoreShapeLock;
6306
6277
  let partial, result;
6307
6278
  for (let i = 0, n = partials.length; i < n; i++) {
6308
6279
  partial = partials[i];
6309
6280
  if (!partial) continue;
6310
6281
  const shape = this.getShape(partial.id);
6311
6282
  if (!shape) continue;
6283
+ const unlocks = shape.isLocked && Object.hasOwn(partial, "isLocked") && !partial.isLocked;
6284
+ if (!ignoreShapeLock && !unlocks && this.isShapeOrAncestorLocked(shape)) {
6285
+ continue;
6286
+ }
6312
6287
  result = {
6313
6288
  start: (0, import_utils.structuredClone)(shape),
6314
6289
  end: applyPartialToRecordWithProps((0, import_utils.structuredClone)(shape), partial)
@@ -6324,7 +6299,7 @@ class Editor extends import_eventemitter3.default {
6324
6299
  (p) => p && animatingShapes2.get(p.id) === animationId
6325
6300
  );
6326
6301
  if (partialsToUpdate.length) {
6327
- this.updateShapes(partialsToUpdate);
6302
+ this.run(() => this.updateShapes(partialsToUpdate), { ignoreShapeLock });
6328
6303
  }
6329
6304
  this.off("tick", handleTick);
6330
6305
  return;
@@ -6357,13 +6332,13 @@ class Editor extends import_eventemitter3.default {
6357
6332
  throw Error("Editor.groupShapes: must provide an array of shapes or shape ids");
6358
6333
  }
6359
6334
  if (this.getIsReadonly()) return this;
6360
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
6361
- if (ids.length <= 1) return this;
6335
+ const ids = toShapeIds(shapes);
6362
6336
  const shapesToGroup = (0, import_utils.compact)(
6363
6337
  (this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
6364
6338
  (id) => this.getShape(id)
6365
6339
  )
6366
6340
  );
6341
+ if (shapesToGroup.length <= 1) return this;
6367
6342
  const sortedShapeIds = shapesToGroup.sort(import_utils.sortByIndex).map((s) => s.id);
6368
6343
  const childBounds = (0, import_utils.compact)(shapesToGroup.map((shape) => this.getShapePageBounds(shape)));
6369
6344
  const pageBounds = import_Box.Box.Common(childBounds);
@@ -6372,8 +6347,11 @@ class Editor extends import_eventemitter3.default {
6372
6347
  }
6373
6348
  const { x, y } = pageBounds.point;
6374
6349
  const parentId = this.findCommonAncestor(shapesToGroup) ?? this.getCurrentPageId();
6375
- if (this.getCurrentToolId() !== "select") return this;
6376
- if (!this.isIn("select.idle")) {
6350
+ if (!this.canCreateShapes([groupId])) {
6351
+ alertMaxShapes(this);
6352
+ return this;
6353
+ }
6354
+ if (this.isIn("select") && !this.isIn("select.idle")) {
6377
6355
  this.cancel();
6378
6356
  }
6379
6357
  const shapesWithRootParent = shapesToGroup.filter((shape) => shape.parentId === parentId).sort(import_utils.sortByIndex);
@@ -6401,15 +6379,14 @@ class Editor extends import_eventemitter3.default {
6401
6379
  ungroupShapes(shapes, opts = {}) {
6402
6380
  if (this.getIsReadonly()) return this;
6403
6381
  const { select = true } = opts;
6404
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
6382
+ const ids = toShapeIds(shapes);
6405
6383
  const shapesToUngroup = (0, import_utils.compact)(
6406
6384
  (this._shouldIgnoreShapeLock ? ids : this._getUnlockedShapeIds(ids)).map(
6407
6385
  (id) => this.getShape(id)
6408
6386
  )
6409
6387
  );
6410
6388
  if (shapesToUngroup.length === 0) return this;
6411
- if (this.getCurrentToolId() !== "select") return this;
6412
- if (!this.isIn("select.idle")) {
6389
+ if (this.isIn("select") && !this.isIn("select.idle")) {
6413
6390
  this.cancel();
6414
6391
  }
6415
6392
  const idsToSelect = /* @__PURE__ */ new Set();
@@ -6423,16 +6400,16 @@ class Editor extends import_eventemitter3.default {
6423
6400
  });
6424
6401
  if (groups.length === 0) return this;
6425
6402
  this.run(() => {
6426
- let group;
6427
6403
  for (let i = 0, n = groups.length; i < n; i++) {
6428
- group = groups[i];
6404
+ const group = this.getShape(groups[i].id);
6405
+ if (!group) continue;
6429
6406
  const childIds = this.getSortedChildIdsForParent(group.id);
6430
6407
  for (let j = 0, n2 = childIds.length; j < n2; j++) {
6431
6408
  idsToSelect.add(childIds[j]);
6432
6409
  }
6433
6410
  this.reparentShapes(childIds, group.parentId, group.index);
6434
6411
  }
6435
- this.deleteShapes(groups.map((group2) => group2.id));
6412
+ this.deleteShapes(groups.map((group) => group.id));
6436
6413
  if (select) {
6437
6414
  this.select(...idsToSelect);
6438
6415
  }
@@ -6513,14 +6490,14 @@ class Editor extends import_eventemitter3.default {
6513
6490
  }
6514
6491
  /** @internal */
6515
6492
  _getUnlockedShapeIds(ids) {
6516
- return ids.filter((id) => !this.getShape(id)?.isLocked);
6493
+ return ids.filter((id) => !this.isShapeOrAncestorLocked(id));
6517
6494
  }
6518
6495
  deleteShapes(_ids) {
6519
6496
  if (this.getIsReadonly()) return this;
6520
6497
  if (!Array.isArray(_ids)) {
6521
6498
  throw Error("Editor.deleteShapes: must provide an array of shapes or shapeIds");
6522
6499
  }
6523
- const shapeIds = typeof _ids[0] === "string" ? _ids : _ids.map((s) => s.id);
6500
+ const shapeIds = toShapeIds(_ids);
6524
6501
  const shapeIdsToDelete = this._shouldIgnoreShapeLock ? shapeIds : this._getUnlockedShapeIds(shapeIds);
6525
6502
  if (shapeIdsToDelete.length === 0) return this;
6526
6503
  const allShapeIdsToDelete = new Set(shapeIdsToDelete);
@@ -6865,7 +6842,7 @@ class Editor extends import_eventemitter3.default {
6865
6842
  * @public
6866
6843
  */
6867
6844
  getContentFromCurrentPage(shapes) {
6868
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
6845
+ const ids = toShapeIds(shapes);
6869
6846
  if (!ids) return;
6870
6847
  if (ids.length === 0) return;
6871
6848
  const shapeIds = this.getShapeAndDescendantIds(ids);
@@ -6933,21 +6910,29 @@ class Editor extends import_eventemitter3.default {
6933
6910
  await Promise.allSettled(
6934
6911
  content.assets.map(async (asset) => {
6935
6912
  if ((asset.type === "image" || asset.type === "video") && !asset.props.src?.startsWith("data:image") && !asset.props.src?.startsWith("data:video") && !asset.props.src?.startsWith("http")) {
6936
- const assetWithDataUrl = (0, import_utils.structuredClone)(asset);
6937
- const objectUrl = await this.store.props.assets.resolve(asset, {
6938
- screenScale: 1,
6939
- steppedScreenScale: 1,
6940
- dpr: 1,
6941
- networkEffectiveType: null,
6942
- shouldResolveToOriginal: true
6943
- });
6944
- assetWithDataUrl.props.src = await import_utils.FileHelpers.blobToDataUrl(
6945
- await (0, import_utils.fetch)(objectUrl).then((r) => r.blob())
6946
- );
6947
- assets.push(assetWithDataUrl);
6948
- } else {
6949
- assets.push(asset);
6913
+ try {
6914
+ const objectUrl = await this.store.props.assets.resolve(asset, {
6915
+ screenScale: 1,
6916
+ steppedScreenScale: 1,
6917
+ dpr: 1,
6918
+ networkEffectiveType: null,
6919
+ shouldResolveToOriginal: true
6920
+ });
6921
+ if (objectUrl) {
6922
+ const response = await (0, import_utils.fetch)(objectUrl);
6923
+ if (response.ok) {
6924
+ const assetWithDataUrl = (0, import_utils.structuredClone)(asset);
6925
+ assetWithDataUrl.props.src = await import_utils.FileHelpers.blobToDataUrl(await response.blob());
6926
+ assets.push(assetWithDataUrl);
6927
+ return;
6928
+ }
6929
+ console.warn(`Could not inline asset ${asset.id}: fetch returned ${response.status}`);
6930
+ }
6931
+ } catch (err) {
6932
+ console.warn(`Could not inline asset ${asset.id}`, err);
6933
+ }
6950
6934
  }
6935
+ assets.push(asset);
6951
6936
  })
6952
6937
  );
6953
6938
  content.assets = assets;
@@ -7241,7 +7226,7 @@ class Editor extends import_eventemitter3.default {
7241
7226
  * @public
7242
7227
  */
7243
7228
  async getSvgElement(shapes, opts = {}) {
7244
- const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
7229
+ const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : toShapeIds(shapes);
7245
7230
  if (ids.length === 0) return void 0;
7246
7231
  await this.fonts.loadRequiredFontsForCurrentPage(this.options.maxFontsToLoadBeforeRender);
7247
7232
  return (0, import_exportToSvg.exportToSvg)(this, ids, opts);
@@ -7837,22 +7822,22 @@ class Editor extends import_eventemitter3.default {
7837
7822
  const releaseCtrl = this._ctrlKeyTimeout !== -1;
7838
7823
  const releaseMeta = this._metaKeyTimeout !== -1;
7839
7824
  if (releaseShift) {
7840
- clearTimeout(this._shiftKeyTimeout);
7825
+ this.timers.clearTimeout(this._shiftKeyTimeout);
7841
7826
  this._shiftKeyTimeout = -1;
7842
7827
  this.inputs.setShiftKey(false);
7843
7828
  }
7844
7829
  if (releaseAlt) {
7845
- clearTimeout(this._altKeyTimeout);
7830
+ this.timers.clearTimeout(this._altKeyTimeout);
7846
7831
  this._altKeyTimeout = -1;
7847
7832
  this.inputs.setAltKey(false);
7848
7833
  }
7849
7834
  if (releaseCtrl) {
7850
- clearTimeout(this._ctrlKeyTimeout);
7835
+ this.timers.clearTimeout(this._ctrlKeyTimeout);
7851
7836
  this._ctrlKeyTimeout = -1;
7852
7837
  this.inputs.setCtrlKey(false);
7853
7838
  }
7854
7839
  if (releaseMeta) {
7855
- clearTimeout(this._metaKeyTimeout);
7840
+ this.timers.clearTimeout(this._metaKeyTimeout);
7856
7841
  this._metaKeyTimeout = -1;
7857
7842
  this.inputs.setMetaKey(false);
7858
7843
  }
@@ -7966,28 +7951,28 @@ class Editor extends import_eventemitter3.default {
7966
7951
  return;
7967
7952
  }
7968
7953
  if (info.shiftKey) {
7969
- clearTimeout(this._shiftKeyTimeout);
7954
+ this.timers.clearTimeout(this._shiftKeyTimeout);
7970
7955
  this._shiftKeyTimeout = -1;
7971
7956
  inputs.setShiftKey(true);
7972
7957
  } else if (!info.shiftKey && inputs.getShiftKey() && this._shiftKeyTimeout === -1) {
7973
7958
  this._shiftKeyTimeout = this.timers.setTimeout(this._releaseShiftKey, 150);
7974
7959
  }
7975
7960
  if (info.altKey) {
7976
- clearTimeout(this._altKeyTimeout);
7961
+ this.timers.clearTimeout(this._altKeyTimeout);
7977
7962
  this._altKeyTimeout = -1;
7978
7963
  inputs.setAltKey(true);
7979
7964
  } else if (!info.altKey && inputs.getAltKey() && this._altKeyTimeout === -1) {
7980
7965
  this._altKeyTimeout = this.timers.setTimeout(this._releaseAltKey, 150);
7981
7966
  }
7982
7967
  if (info.ctrlKey) {
7983
- clearTimeout(this._ctrlKeyTimeout);
7968
+ this.timers.clearTimeout(this._ctrlKeyTimeout);
7984
7969
  this._ctrlKeyTimeout = -1;
7985
7970
  inputs.setCtrlKey(true);
7986
7971
  } else if (!info.ctrlKey && inputs.getCtrlKey() && this._ctrlKeyTimeout === -1) {
7987
7972
  this._ctrlKeyTimeout = this.timers.setTimeout(this._releaseCtrlKey, 150);
7988
7973
  }
7989
7974
  if (info.metaKey && info.name !== "key_up") {
7990
- clearTimeout(this._metaKeyTimeout);
7975
+ this.timers.clearTimeout(this._metaKeyTimeout);
7991
7976
  this._metaKeyTimeout = -1;
7992
7977
  inputs.setMetaKey(true);
7993
7978
  } else if (!info.metaKey && inputs.getMetaKey() && this._metaKeyTimeout === -1) {
@@ -8001,8 +7986,7 @@ class Editor extends import_eventemitter3.default {
8001
7986
  const cameraOptions = this._cameraOptions.__unsafe__getWithoutCapture();
8002
7987
  switch (type) {
8003
7988
  case "pinch": {
8004
- if (cameraOptions.isLocked) return;
8005
- clearTimeout(this._longPressTimeout);
7989
+ this.timers.clearTimeout(this._longPressTimeout);
8006
7990
  this.inputs.updateFromEvent(info);
8007
7991
  switch (info.name) {
8008
7992
  case "pinch_start": {
@@ -8023,6 +8007,7 @@ class Editor extends import_eventemitter3.default {
8023
8007
  }
8024
8008
  case "pinch": {
8025
8009
  if (!inputs.getIsPinching()) return;
8010
+ if (cameraOptions.isLocked) return;
8026
8011
  const {
8027
8012
  point: { z = 1 },
8028
8013
  delta: { x: dx, y: dy }
@@ -8078,7 +8063,7 @@ class Editor extends import_eventemitter3.default {
8078
8063
  const { panSpeed, zoomSpeed } = cameraOptions;
8079
8064
  let wheelBehavior = cameraOptions.wheelBehavior;
8080
8065
  const inputMode = this.user.getUserPreferences().inputMode;
8081
- if (inputMode !== null) {
8066
+ if (inputMode !== null && wheelBehavior !== "none") {
8082
8067
  wheelBehavior = inputMode === "trackpad" ? "pan" : "zoom";
8083
8068
  }
8084
8069
  if (wheelBehavior !== "none") {
@@ -8130,12 +8115,12 @@ class Editor extends import_eventemitter3.default {
8130
8115
  }
8131
8116
  case "pointer": {
8132
8117
  if (inputs.getIsPinching()) return;
8133
- this.inputs.updateFromEvent(info);
8134
8118
  const { isPen } = info;
8135
8119
  const { isPenMode } = instanceState;
8120
+ if (isPenMode && !isPen) return;
8121
+ this.inputs.updateFromEvent(info);
8136
8122
  switch (info.name) {
8137
8123
  case "pointer_down": {
8138
- if (isPenMode && !isPen) return;
8139
8124
  this._releaseDebouncedModifiers();
8140
8125
  if (!this.inputs.getIsPanning()) {
8141
8126
  this._longPressTimeout = this.timers.setTimeout(() => {
@@ -8159,11 +8144,12 @@ class Editor extends import_eventemitter3.default {
8159
8144
  inputs.buttons.add(info.button);
8160
8145
  inputs.setIsPointing(true);
8161
8146
  inputs.setIsDragging(false);
8147
+ this.stopCameraAnimation();
8162
8148
  if (!isPenMode && info.isPenDirect) {
8163
8149
  this.updateInstanceState({ isPenMode: true });
8164
8150
  this.interrupt();
8165
8151
  }
8166
- if (info.button === import_constants.STYLUS_ERASER_BUTTON) {
8152
+ if (info.button === import_constants.STYLUS_ERASER_BUTTON && this.getStateDescendant("eraser")) {
8167
8153
  this._restoreToolId = this.getCurrentToolId();
8168
8154
  this.complete();
8169
8155
  this.setCurrentTool("eraser");
@@ -8172,10 +8158,10 @@ class Editor extends import_eventemitter3.default {
8172
8158
  this._prevCursor = this.getInstanceState().cursor.type;
8173
8159
  }
8174
8160
  this.inputs.setIsPanning(true);
8175
- clearTimeout(this._longPressTimeout);
8161
+ this.timers.clearTimeout(this._longPressTimeout);
8176
8162
  } else if (info.button === import_constants.RIGHT_MOUSE_BUTTON && this.options.rightClickPanning) {
8177
8163
  this.inputs.setIsRightPointing(true);
8178
- clearTimeout(this._longPressTimeout);
8164
+ this.timers.clearTimeout(this._longPressTimeout);
8179
8165
  return this;
8180
8166
  }
8181
8167
  if (this.inputs.getIsPanning()) {
@@ -8186,7 +8172,6 @@ class Editor extends import_eventemitter3.default {
8186
8172
  break;
8187
8173
  }
8188
8174
  case "pointer_move": {
8189
- if (!isPen && isPenMode) return;
8190
8175
  const { x: cx, y: cy, z: cz } = (0, import_state.unsafe__withoutCapture)(() => this.getCamera());
8191
8176
  if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
8192
8177
  const currentScreenPoint = this.inputs.getCurrentScreenPoint();
@@ -8217,16 +8202,15 @@ class Editor extends import_eventemitter3.default {
8217
8202
  }
8218
8203
  if (inputs.getIsPointing() && !inputs.getIsDragging() && import_Vec.Vec.Dist2(inputs.getOriginPagePoint(), inputs.getCurrentPagePoint()) * this.getZoomLevel() > (instanceState.isCoarsePointer ? this.options.coarseDragDistanceSquared : this.options.dragDistanceSquared) / cz) {
8219
8204
  inputs.setIsDragging(true);
8220
- clearTimeout(this._longPressTimeout);
8205
+ this.timers.clearTimeout(this._longPressTimeout);
8221
8206
  }
8222
8207
  break;
8223
8208
  }
8224
8209
  case "pointer_up": {
8225
8210
  inputs.setIsDragging(false);
8226
8211
  inputs.setIsPointing(false);
8227
- clearTimeout(this._longPressTimeout);
8212
+ this.timers.clearTimeout(this._longPressTimeout);
8228
8213
  inputs.buttons.delete(info.button);
8229
- if (instanceState.isPenMode && !isPen) return;
8230
8214
  if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
8231
8215
  this.inputs.setIsRightPointing(false);
8232
8216
  this._selectedShapeIdsAtPointerDown = [];
@@ -8282,7 +8266,7 @@ class Editor extends import_eventemitter3.default {
8282
8266
  });
8283
8267
  }
8284
8268
  } else {
8285
- if (info.button === import_constants.STYLUS_ERASER_BUTTON) {
8269
+ if (info.button === import_constants.STYLUS_ERASER_BUTTON && this.getStateDescendant("eraser")) {
8286
8270
  this.complete();
8287
8271
  this.setCurrentTool(this._restoreToolId);
8288
8272
  }
@@ -8295,8 +8279,8 @@ class Editor extends import_eventemitter3.default {
8295
8279
  break;
8296
8280
  }
8297
8281
  case "keyboard": {
8298
- if (info.key === "ShiftRight") info.key = "ShiftLeft";
8299
- if (info.key === "AltRight") info.key = "AltLeft";
8282
+ if (info.code === "ShiftRight") info.code = "ShiftLeft";
8283
+ if (info.code === "AltRight") info.code = "AltLeft";
8300
8284
  if (info.code === "ControlRight") info.code = "ControlLeft";
8301
8285
  if (info.code === "MetaRight") info.code = "MetaLeft";
8302
8286
  switch (info.name) {
@@ -8309,7 +8293,7 @@ class Editor extends import_eventemitter3.default {
8309
8293
  }
8310
8294
  this.inputs.setIsPanning(true);
8311
8295
  this.inputs.setIsSpacebarPanning(true);
8312
- clearTimeout(this._longPressTimeout);
8296
+ this.timers.clearTimeout(this._longPressTimeout);
8313
8297
  this.setCursor({
8314
8298
  type: this.inputs.getIsPointing() ? "grabbing" : "grab",
8315
8299
  rotation: 0
@@ -8335,7 +8319,7 @@ class Editor extends import_eventemitter3.default {
8335
8319
  break;
8336
8320
  }
8337
8321
  }
8338
- if (offset) {
8322
+ if (offset && !cameraOptions.isLocked) {
8339
8323
  const bounds = this.getViewportPageBounds();
8340
8324
  const next = bounds.clone().translate(offset.mulV({ x: bounds.w, y: bounds.h }));
8341
8325
  this._animateToViewport(next, { animation: { duration: 320 } });
@@ -8375,7 +8359,7 @@ class Editor extends import_eventemitter3.default {
8375
8359
  this.setCurrentTool("select");
8376
8360
  }
8377
8361
  const { isPenMode } = this.store.unsafeGetWithoutCapture(import_tlschema.TLINSTANCE_ID);
8378
- if (info.isPen === isPenMode) {
8362
+ if (!isPenMode || info.isPen) {
8379
8363
  const clickInfo = this._clickManager.handlePointerEvent(info);
8380
8364
  if (info.name !== clickInfo.name) {
8381
8365
  this.root.handleEvent(info);
@@ -8397,7 +8381,7 @@ class Editor extends import_eventemitter3.default {
8397
8381
  maybeTrackPerformance(name) {
8398
8382
  if (import_debug_flags.debugFlags.measurePerformance.get()) {
8399
8383
  if (this.performanceTracker.isStarted()) {
8400
- clearTimeout(this.performanceTrackerTimeout);
8384
+ this.timers.clearTimeout(this.performanceTrackerTimeout);
8401
8385
  } else {
8402
8386
  this.performanceTracker.start(name);
8403
8387
  }
@@ -8666,6 +8650,9 @@ function pushShapeWithDescendants(editor, id, result) {
8666
8650
  pushShapeWithDescendants(editor, childIds[i], result);
8667
8651
  }
8668
8652
  }
8653
+ function toShapeIds(shapes) {
8654
+ return typeof shapes[0] === "string" ? shapes : shapes.map((shape) => shape.id);
8655
+ }
8669
8656
  function withIsolatedShapes(editor, shapeIds, callback) {
8670
8657
  let result;
8671
8658
  editor.run(
@@ -8688,7 +8675,7 @@ function withIsolatedShapes(editor, shapeIds, callback) {
8688
8675
  }
8689
8676
  }
8690
8677
  }
8691
- editor.deleteBindings([...bindingsToRemove], { isolateShapes: true });
8678
+ editor._deleteBindings([...bindingsToRemove], { isolateShapes: true });
8692
8679
  try {
8693
8680
  result = import_utils.Result.ok(callback(bindingsWithBoth));
8694
8681
  } catch (error) {