@tldraw/editor 3.13.0-canary.a2884bb1bab2 → 3.13.0-canary.ad6c4f5526a8

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 (185) hide show
  1. package/dist-cjs/index.d.ts +129 -113
  2. package/dist-cjs/index.js +7 -22
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +2 -1
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/Shape.js +12 -8
  7. package/dist-cjs/lib/components/Shape.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +37 -8
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +14 -12
  11. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  12. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +17 -11
  13. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  14. package/dist-cjs/lib/components/default-components/DefaultSpinner.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultSpinner.js.map +2 -2
  16. package/dist-cjs/lib/editor/Editor.js +110 -44
  17. package/dist-cjs/lib/editor/Editor.js.map +3 -3
  18. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
  19. package/dist-cjs/lib/editor/managers/TextManager.js +10 -0
  20. package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
  21. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +1 -1
  22. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  23. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +0 -3
  24. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  25. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
  26. package/dist-cjs/lib/exports/getSvgJsx.js +12 -3
  27. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  28. package/dist-cjs/lib/hooks/useDocumentEvents.js +3 -2
  29. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  30. package/dist-cjs/lib/hooks/useEditorComponents.js +16 -16
  31. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  32. package/dist-cjs/lib/license/LicenseManager.js +8 -1
  33. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  34. package/dist-cjs/lib/options.js.map +2 -2
  35. package/dist-cjs/lib/primitives/Box.js +16 -0
  36. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  37. package/dist-cjs/lib/primitives/Mat.js +1 -1
  38. package/dist-cjs/lib/primitives/Mat.js.map +2 -2
  39. package/dist-cjs/lib/primitives/Vec.js +20 -0
  40. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  41. package/dist-cjs/lib/primitives/geometry/Arc2d.js +2 -2
  42. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  43. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
  44. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  45. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
  46. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  47. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
  48. package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
  49. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  50. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  51. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +91 -20
  52. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  53. package/dist-cjs/lib/primitives/geometry/Group2d.js +55 -2
  54. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  55. package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
  56. package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
  57. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
  58. package/dist-cjs/lib/utils/areShapesContentEqual.js +25 -0
  59. package/dist-cjs/lib/utils/areShapesContentEqual.js.map +7 -0
  60. package/dist-cjs/lib/utils/debug-flags.js +5 -2
  61. package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
  62. package/dist-cjs/lib/utils/dom.js +3 -3
  63. package/dist-cjs/lib/utils/dom.js.map +2 -2
  64. package/dist-cjs/lib/utils/nearestMultiple.js +34 -0
  65. package/dist-cjs/lib/utils/nearestMultiple.js.map +7 -0
  66. package/dist-cjs/lib/utils/rotation.js +5 -5
  67. package/dist-cjs/lib/utils/rotation.js.map +2 -2
  68. package/dist-cjs/version.js +3 -3
  69. package/dist-cjs/version.js.map +1 -1
  70. package/dist-esm/index.d.mts +129 -113
  71. package/dist-esm/index.mjs +9 -41
  72. package/dist-esm/index.mjs.map +2 -2
  73. package/dist-esm/lib/TldrawEditor.mjs +2 -1
  74. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  75. package/dist-esm/lib/components/Shape.mjs +12 -8
  76. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  77. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +37 -8
  78. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  79. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +14 -12
  80. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  81. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +17 -11
  82. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  83. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs +1 -1
  84. package/dist-esm/lib/components/default-components/DefaultSpinner.mjs.map +2 -2
  85. package/dist-esm/lib/editor/Editor.mjs +110 -44
  86. package/dist-esm/lib/editor/Editor.mjs.map +3 -3
  87. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
  88. package/dist-esm/lib/editor/managers/TextManager.mjs +10 -0
  89. package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
  90. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +1 -1
  91. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  92. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +0 -3
  93. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  94. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
  95. package/dist-esm/lib/exports/getSvgJsx.mjs +12 -3
  96. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  97. package/dist-esm/lib/hooks/useDocumentEvents.mjs +3 -2
  98. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  99. package/dist-esm/lib/hooks/useEditorComponents.mjs +16 -18
  100. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  101. package/dist-esm/lib/license/LicenseManager.mjs +8 -1
  102. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  103. package/dist-esm/lib/options.mjs.map +2 -2
  104. package/dist-esm/lib/primitives/Box.mjs +16 -0
  105. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  106. package/dist-esm/lib/primitives/Mat.mjs +1 -1
  107. package/dist-esm/lib/primitives/Mat.mjs.map +2 -2
  108. package/dist-esm/lib/primitives/Vec.mjs +20 -0
  109. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  110. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
  111. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  112. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -1
  113. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  114. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
  115. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  116. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
  117. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
  118. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  119. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  120. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +92 -21
  121. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  122. package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -2
  123. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  124. package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
  125. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
  126. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
  127. package/dist-esm/lib/utils/areShapesContentEqual.mjs +5 -0
  128. package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +7 -0
  129. package/dist-esm/lib/utils/debug-flags.mjs +5 -2
  130. package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
  131. package/dist-esm/lib/utils/dom.mjs +3 -3
  132. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  133. package/dist-esm/lib/utils/nearestMultiple.mjs +14 -0
  134. package/dist-esm/lib/utils/nearestMultiple.mjs.map +7 -0
  135. package/dist-esm/lib/utils/rotation.mjs +5 -5
  136. package/dist-esm/lib/utils/rotation.mjs.map +2 -2
  137. package/dist-esm/version.mjs +3 -3
  138. package/dist-esm/version.mjs.map +1 -1
  139. package/editor.css +47 -4
  140. package/package.json +7 -7
  141. package/src/index.ts +16 -31
  142. package/src/lib/TldrawEditor.tsx +6 -1
  143. package/src/lib/components/Shape.tsx +14 -10
  144. package/src/lib/components/default-components/DefaultCanvas.tsx +43 -8
  145. package/src/lib/components/default-components/DefaultErrorFallback.tsx +25 -14
  146. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +17 -8
  147. package/src/lib/components/default-components/DefaultSpinner.tsx +1 -1
  148. package/src/lib/editor/Editor.test.ts +1 -1
  149. package/src/lib/editor/Editor.ts +118 -43
  150. package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +0 -1
  151. package/src/lib/editor/managers/TextManager.ts +12 -0
  152. package/src/lib/editor/shapes/ShapeUtil.ts +23 -3
  153. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +0 -4
  154. package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +9 -9
  155. package/src/lib/exports/getSvgJsx.tsx +16 -7
  156. package/src/lib/hooks/useDocumentEvents.ts +7 -2
  157. package/src/lib/hooks/useEditorComponents.tsx +33 -32
  158. package/src/lib/license/LicenseManager.test.ts +40 -0
  159. package/src/lib/license/LicenseManager.ts +13 -1
  160. package/src/lib/options.ts +4 -0
  161. package/src/lib/primitives/Box.ts +20 -0
  162. package/src/lib/primitives/Mat.ts +5 -4
  163. package/src/lib/primitives/Vec.ts +23 -0
  164. package/src/lib/primitives/geometry/Arc2d.ts +5 -5
  165. package/src/lib/primitives/geometry/Circle2d.ts +4 -4
  166. package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -4
  167. package/src/lib/primitives/geometry/CubicSpline2d.ts +3 -3
  168. package/src/lib/primitives/geometry/Edge2d.ts +3 -3
  169. package/src/lib/primitives/geometry/Ellipse2d.ts +3 -3
  170. package/src/lib/primitives/geometry/Geometry2d.test.ts +42 -0
  171. package/src/lib/primitives/geometry/Geometry2d.ts +123 -35
  172. package/src/lib/primitives/geometry/Group2d.ts +70 -7
  173. package/src/lib/primitives/geometry/Point2d.ts +2 -2
  174. package/src/lib/primitives/geometry/Polyline2d.ts +3 -3
  175. package/src/lib/primitives/geometry/Stadium2d.ts +3 -3
  176. package/src/lib/test/currentToolIdMask.test.ts +1 -1
  177. package/src/lib/test/user.test.ts +1 -1
  178. package/src/lib/utils/areShapesContentEqual.ts +4 -0
  179. package/src/lib/utils/debug-flags.ts +7 -2
  180. package/src/lib/utils/dom.ts +4 -4
  181. package/src/lib/utils/nearestMultiple.ts +13 -0
  182. package/src/lib/utils/rotation.ts +8 -6
  183. package/src/lib/utils/sync/LocalIndexedDb.test.ts +1 -1
  184. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +1 -1
  185. package/src/version.ts +3 -3
@@ -132,6 +132,7 @@ import { Group2d } from "../primitives/geometry/Group2d.mjs";
132
132
  import { intersectPolygonPolygon } from "../primitives/intersect.mjs";
133
133
  import { PI, approximately, areAnglesCompatible, clamp, pointInPolygon } from "../primitives/utils.mjs";
134
134
  import { SharedStyleMap } from "../utils/SharedStylesMap.mjs";
135
+ import { areShapesContentEqual } from "../utils/areShapesContentEqual.mjs";
135
136
  import { dataUrlToFile } from "../utils/assets.mjs";
136
137
  import { debugFlags } from "../utils/debug-flags.mjs";
137
138
  import {
@@ -457,7 +458,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
457
458
  ) : getShapeVisibility;
458
459
  this.options = { ...defaultTldrawOptions, ...options };
459
460
  this.store = store;
460
- this.disposables.add(this.store.dispose.bind(this.store));
461
461
  this.history = new HistoryManager({
462
462
  store,
463
463
  annotateError: (error) => {
@@ -869,6 +869,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
869
869
  dispose() {
870
870
  this.disposables.forEach((dispose) => dispose());
871
871
  this.disposables.clear();
872
+ this.store.dispose();
872
873
  this.isDisposed = true;
873
874
  }
874
875
  getShapeUtil(arg) {
@@ -1381,8 +1382,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1381
1382
  return this.getCurrentPageState().selectedShapeIds;
1382
1383
  }
1383
1384
  getSelectedShapes() {
1384
- const { selectedShapeIds } = this.getCurrentPageState();
1385
- return compact(selectedShapeIds.map((id) => this.store.get(id)));
1385
+ return compact(this.getSelectedShapeIds().map((id) => this.store.get(id)));
1386
1386
  }
1387
1387
  /**
1388
1388
  * Select one or more shapes.
@@ -1475,9 +1475,23 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1475
1475
  this.setSelectedShapes(this._getUnlockedShapeIds(ids));
1476
1476
  return this;
1477
1477
  }
1478
+ /**
1479
+ * Select the next shape in the reading order or in cardinal order.
1480
+ *
1481
+ * @example
1482
+ * ```ts
1483
+ * editor.selectAdjacentShape('next')
1484
+ * ```
1485
+ *
1486
+ * @public
1487
+ */
1478
1488
  selectAdjacentShape(direction) {
1479
- const readingOrderShapes = this.getCurrentPageShapesInReadingOrder();
1480
1489
  const selectedShapeIds = this.getSelectedShapeIds();
1490
+ const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null;
1491
+ const isSelectedWithinContainer = firstParentId && selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) && !isPageId(firstParentId);
1492
+ const readingOrderShapes = isSelectedWithinContainer ? this._getShapesInReadingOrder(
1493
+ this.getCurrentPageShapes().filter((shape2) => shape2.parentId === firstParentId)
1494
+ ) : this.getCurrentPageShapesInReadingOrder();
1481
1495
  const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
1482
1496
  let adjacentShapeId;
1483
1497
  if (direction === "next" || direction === "prev") {
@@ -1491,18 +1505,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1491
1505
  }
1492
1506
  const shape = this.getShape(adjacentShapeId);
1493
1507
  if (!shape) return;
1494
- this.setSelectedShapes([shape.id]);
1495
- this.zoomToSelectionIfOffscreen(256, {
1496
- animation: {
1497
- duration: this.options.animationMediumMs
1498
- },
1499
- inset: 0
1500
- });
1508
+ this._selectShapesAndZoom([shape.id]);
1501
1509
  }
1502
1510
  getCurrentPageShapesInReadingOrder() {
1511
+ const shapes = this.getCurrentPageShapes().filter((shape) => isPageId(shape.parentId));
1512
+ return this._getShapesInReadingOrder(shapes);
1513
+ }
1514
+ _getShapesInReadingOrder(shapes) {
1503
1515
  const SHALLOW_ANGLE = 20;
1504
1516
  const ROW_THRESHOLD = 100;
1505
- const shapes = this.getCurrentPageShapes();
1506
1517
  const tabbableShapes = shapes.filter((shape) => this.getShapeUtil(shape).canTabTo(shape));
1507
1518
  if (tabbableShapes.length <= 1) return tabbableShapes;
1508
1519
  const shapesWithCenters = tabbableShapes.map((shape) => ({
@@ -1600,6 +1611,31 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1600
1611
  });
1601
1612
  return lowestScoringShape.shape.id;
1602
1613
  }
1614
+ selectParentShape() {
1615
+ const selectedShape = this.getOnlySelectedShape();
1616
+ if (!selectedShape) return;
1617
+ const parentShape = this.getShape(selectedShape.parentId);
1618
+ if (!parentShape) return;
1619
+ this._selectShapesAndZoom([parentShape.id]);
1620
+ }
1621
+ selectFirstChildShape() {
1622
+ const selectedShapes = this.getSelectedShapes();
1623
+ if (!selectedShapes.length) return;
1624
+ const selectedShape = selectedShapes[0];
1625
+ const children = this.getSortedChildIdsForParent(selectedShape.id).map((id) => this.getShape(id)).filter((i) => i);
1626
+ const sortedChildren = this._getShapesInReadingOrder(children);
1627
+ if (sortedChildren.length === 0) return;
1628
+ this._selectShapesAndZoom([sortedChildren[0].id]);
1629
+ }
1630
+ _selectShapesAndZoom(ids) {
1631
+ this.setSelectedShapes(ids);
1632
+ this.zoomToSelectionIfOffscreen(256, {
1633
+ animation: {
1634
+ duration: this.options.animationMediumMs
1635
+ },
1636
+ inset: 0
1637
+ });
1638
+ }
1603
1639
  /**
1604
1640
  * Clear the selection.
1605
1641
  *
@@ -1772,13 +1808,21 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1772
1808
  setEditingShape(shape) {
1773
1809
  const id = typeof shape === "string" ? shape : shape?.id ?? null;
1774
1810
  this.setRichTextEditor(null);
1775
- if (id !== this.getEditingShapeId()) {
1811
+ const prevEditingShapeId = this.getEditingShapeId();
1812
+ if (id !== prevEditingShapeId) {
1776
1813
  if (id) {
1777
1814
  const shape2 = this.getShape(id);
1778
1815
  if (shape2 && this.getShapeUtil(shape2).canEdit(shape2)) {
1779
1816
  this.run(
1780
1817
  () => {
1781
1818
  this._updateCurrentPageState({ editingShapeId: id });
1819
+ if (prevEditingShapeId) {
1820
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1821
+ if (prevEditingShape) {
1822
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1823
+ }
1824
+ }
1825
+ this.getShapeUtil(shape2).onEditStart?.(shape2);
1782
1826
  },
1783
1827
  { history: "ignore" }
1784
1828
  );
@@ -1789,6 +1833,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1789
1833
  () => {
1790
1834
  this._updateCurrentPageState({ editingShapeId: null });
1791
1835
  this._currentRichTextEditor.set(null);
1836
+ if (prevEditingShapeId) {
1837
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1838
+ if (prevEditingShape) {
1839
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1840
+ }
1841
+ }
1792
1842
  },
1793
1843
  { history: "ignore" }
1794
1844
  );
@@ -1984,12 +2034,22 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1984
2034
  }
1985
2035
  return baseCamera;
1986
2036
  }
2037
+ _getFollowingPresence(targetUserId) {
2038
+ const visited = [this.user.getId()];
2039
+ const collaborators = this.getCollaborators();
2040
+ let leaderPresence = null;
2041
+ while (targetUserId && !visited.includes(targetUserId)) {
2042
+ leaderPresence = collaborators.find((c) => c.userId === targetUserId) ?? null;
2043
+ targetUserId = leaderPresence?.followingUserId ?? null;
2044
+ if (leaderPresence) {
2045
+ visited.push(leaderPresence.userId);
2046
+ }
2047
+ }
2048
+ return leaderPresence;
2049
+ }
1987
2050
  getViewportPageBoundsForFollowing() {
1988
- const followingUserId = this.getInstanceState().followingUserId;
1989
- if (!followingUserId) return null;
1990
- const leaderPresence = this.getCollaborators().find((c) => c.userId === followingUserId);
1991
- if (!leaderPresence) return null;
1992
- if (!leaderPresence.camera || !leaderPresence.screenBounds) return null;
2051
+ const leaderPresence = this._getFollowingPresence(this.getInstanceState().followingUserId);
2052
+ if (!leaderPresence?.camera || !leaderPresence?.screenBounds) return null;
1993
2053
  const { w: lw, h: lh } = leaderPresence.screenBounds;
1994
2054
  const { x: lx, y: ly, z: lz } = leaderPresence.camera;
1995
2055
  const theirViewport = new Box(-lx, -ly, lw / lz, lh / lz);
@@ -2896,34 +2956,30 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2896
2956
  */
2897
2957
  startFollowingUser(userId) {
2898
2958
  this.stopFollowingUser();
2899
- const leaderPresences = this._getCollaboratorsQuery().get().filter((p) => p.userId === userId);
2900
- if (!leaderPresences.length) {
2901
- console.warn("User not found");
2902
- return this;
2903
- }
2904
2959
  const thisUserId = this.user.getId();
2905
2960
  if (!thisUserId) {
2906
2961
  console.warn("You should set the userId for the current instance before following a user");
2907
2962
  }
2908
- if (leaderPresences.some((p) => p.followingUserId === thisUserId)) {
2963
+ const leaderPresence = this._getFollowingPresence(userId);
2964
+ if (!leaderPresence) {
2909
2965
  return this;
2910
2966
  }
2911
2967
  const latestLeaderPresence = computed("latestLeaderPresence", () => {
2912
- return this.getCollaborators().find((p) => p.userId === userId);
2968
+ return this._getFollowingPresence(userId);
2913
2969
  });
2914
2970
  transact(() => {
2915
2971
  this.updateInstanceState({ followingUserId: userId }, { history: "ignore" });
2916
2972
  const dispose = react("update current page", () => {
2917
- const leaderPresence = latestLeaderPresence.get();
2918
- if (!leaderPresence) {
2973
+ const leaderPresence2 = latestLeaderPresence.get();
2974
+ if (!leaderPresence2) {
2919
2975
  this.stopFollowingUser();
2920
2976
  return;
2921
2977
  }
2922
- if (leaderPresence.currentPageId !== this.getCurrentPageId() && this.getPage(leaderPresence.currentPageId)) {
2978
+ if (leaderPresence2.currentPageId !== this.getCurrentPageId() && this.getPage(leaderPresence2.currentPageId)) {
2923
2979
  this.run(
2924
2980
  () => {
2925
2981
  this.store.put([
2926
- { ...this.getInstanceState(), currentPageId: leaderPresence.currentPageId }
2982
+ { ...this.getInstanceState(), currentPageId: leaderPresence2.currentPageId }
2927
2983
  ]);
2928
2984
  this._isLockedOnFollowingUser.set(true);
2929
2985
  },
@@ -2938,8 +2994,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2938
2994
  this.off("stop-following", cancel);
2939
2995
  };
2940
2996
  const moveTowardsUser = () => {
2941
- const leaderPresence = latestLeaderPresence.get();
2942
- if (!leaderPresence) {
2997
+ const leaderPresence2 = latestLeaderPresence.get();
2998
+ if (!leaderPresence2) {
2943
2999
  this.stopFollowingUser();
2944
3000
  return;
2945
3001
  }
@@ -3468,7 +3524,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3468
3524
  this.fonts.trackFontsForShape(shape2);
3469
3525
  return this.getShapeUtil(shape2).getGeometry(shape2, opts);
3470
3526
  },
3471
- { areRecordsEqual: (a, b) => a.props === b.props }
3527
+ { areRecordsEqual: areShapesContentEqual }
3472
3528
  );
3473
3529
  }
3474
3530
  return this._shapeGeometryCaches[context].get(
@@ -3511,9 +3567,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3511
3567
  );
3512
3568
  }
3513
3569
  _getShapeHandlesCache() {
3514
- return this.store.createComputedCache("handles", (shape) => {
3515
- return this.getShapeUtil(shape).getHandles?.(shape);
3516
- });
3570
+ return this.store.createComputedCache(
3571
+ "handles",
3572
+ (shape) => {
3573
+ return this.getShapeUtil(shape).getHandles?.(shape);
3574
+ },
3575
+ {
3576
+ areRecordsEqual: areShapesContentEqual
3577
+ }
3578
+ );
3517
3579
  }
3518
3580
  /**
3519
3581
  * Get the handles (if any) for a shape.
@@ -4397,9 +4459,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
4397
4459
  }
4398
4460
  _getBindingsIndexCache() {
4399
4461
  const index = bindingsIndex(this);
4400
- return this.store.createComputedCache("bindingsIndex", (shape) => {
4401
- return index.get().get(shape.id);
4402
- });
4462
+ return this.store.createComputedCache(
4463
+ "bindingsIndex",
4464
+ (shape) => {
4465
+ return index.get().get(shape.id);
4466
+ },
4467
+ // we can ignore the shape equality check here because the index is
4468
+ // computed incrementally based on what bindings are in the store
4469
+ { areRecordsEqual: () => true }
4470
+ );
4403
4471
  }
4404
4472
  /**
4405
4473
  * Get a binding from the store by its ID if it exists.
@@ -7474,7 +7542,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7474
7542
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7475
7543
  const { x: dx, y: dy, z: dz = 0 } = info.delta;
7476
7544
  let behavior = wheelBehavior;
7477
- if (inputs.ctrlKey) behavior = wheelBehavior === "pan" ? "zoom" : "pan";
7545
+ if (info.ctrlKey) behavior = wheelBehavior === "pan" ? "zoom" : "pan";
7478
7546
  switch (behavior) {
7479
7547
  case "zoom": {
7480
7548
  const { x, y } = this.inputs.currentScreenPoint;
@@ -7555,12 +7623,10 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7555
7623
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7556
7624
  if (this.inputs.isPanning && this.inputs.isPointing) {
7557
7625
  const { currentScreenPoint, previousScreenPoint } = this.inputs;
7558
- const { panSpeed } = cameraOptions;
7559
7626
  const offset = Vec.Sub(currentScreenPoint, previousScreenPoint);
7560
- this.setCamera(
7561
- new Vec(cx + offset.x * panSpeed / cz, cy + offset.y * panSpeed / cz, cz),
7562
- { immediate: true }
7563
- );
7627
+ this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
7628
+ immediate: true
7629
+ });
7564
7630
  this.maybeTrackPerformance("Panning");
7565
7631
  return;
7566
7632
  }