@tldraw/editor 5.2.0-next.ee0fa4d6244f → 5.2.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 (189) hide show
  1. package/README.md +7 -1
  2. package/dist-cjs/index.d.ts +117 -60
  3. package/dist-cjs/index.js +7 -8
  4. package/dist-cjs/index.js.map +2 -2
  5. package/dist-cjs/lib/components/MenuClickCapture.js +8 -5
  6. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  7. package/dist-cjs/lib/components/Shape.js +47 -1
  8. package/dist-cjs/lib/components/Shape.js.map +3 -3
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +1 -16
  10. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  11. package/dist-cjs/lib/editor/Editor.js +131 -57
  12. package/dist-cjs/lib/editor/Editor.js.map +3 -3
  13. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +8 -58
  14. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  15. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +3 -3
  16. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
  17. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js +1 -2
  18. package/dist-cjs/lib/editor/managers/FocusManager/FocusManager.js.map +2 -2
  19. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js +28 -4
  20. package/dist-cjs/lib/editor/managers/FontManager/FontManager.js.map +3 -3
  21. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +24 -2
  22. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  23. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +14 -3
  24. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  25. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +4 -2
  26. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
  27. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +7 -3
  28. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  29. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +0 -1
  30. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  31. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +15 -2
  32. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  33. package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +79 -0
  34. package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +7 -0
  35. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  36. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +4 -0
  37. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  38. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  39. package/dist-cjs/lib/{hooks/useTransform.js → editor/tools/cancelShapeCreationOnLongPress.js} +8 -23
  40. package/dist-cjs/lib/editor/tools/cancelShapeCreationOnLongPress.js.map +7 -0
  41. package/dist-cjs/lib/editor/types/event-types.js +0 -2
  42. package/dist-cjs/lib/editor/types/event-types.js.map +2 -2
  43. package/dist-cjs/lib/globals/environment.js +6 -1
  44. package/dist-cjs/lib/globals/environment.js.map +2 -2
  45. package/dist-cjs/lib/hooks/EditorComponentsContext.js.map +2 -2
  46. package/dist-cjs/lib/hooks/useCanvasEvents.js +17 -8
  47. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  48. package/dist-cjs/lib/hooks/useEditorComponents.js +0 -1
  49. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  50. package/dist-cjs/lib/hooks/usePresence.js.map +2 -2
  51. package/dist-cjs/lib/hooks/useScreenBounds.js +1 -0
  52. package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
  53. package/dist-cjs/lib/license/LicenseManager.js +5 -1
  54. package/dist-cjs/lib/license/LicenseManager.js.map +2 -2
  55. package/dist-cjs/lib/primitives/Vec.js +3 -2
  56. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  57. package/dist-cjs/lib/utils/dom.js +12 -0
  58. package/dist-cjs/lib/utils/dom.js.map +2 -2
  59. package/dist-cjs/lib/utils/getPointerInfo.js +2 -1
  60. package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
  61. package/dist-cjs/lib/utils/pointer.js +37 -0
  62. package/dist-cjs/lib/utils/pointer.js.map +7 -0
  63. package/dist-cjs/version.js +3 -3
  64. package/dist-cjs/version.js.map +1 -1
  65. package/dist-esm/index.d.mts +117 -60
  66. package/dist-esm/index.mjs +9 -13
  67. package/dist-esm/index.mjs.map +2 -2
  68. package/dist-esm/lib/components/MenuClickCapture.mjs +8 -5
  69. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  70. package/dist-esm/lib/components/Shape.mjs +48 -2
  71. package/dist-esm/lib/components/Shape.mjs.map +3 -3
  72. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +1 -16
  73. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  74. package/dist-esm/lib/editor/Editor.mjs +131 -57
  75. package/dist-esm/lib/editor/Editor.mjs.map +3 -3
  76. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +8 -58
  77. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  78. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +3 -3
  79. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
  80. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs +1 -2
  81. package/dist-esm/lib/editor/managers/FocusManager/FocusManager.mjs.map +2 -2
  82. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs +28 -4
  83. package/dist-esm/lib/editor/managers/FontManager/FontManager.mjs.map +3 -3
  84. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +24 -2
  85. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  86. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +14 -3
  87. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  88. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +4 -2
  89. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
  90. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +7 -3
  91. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  92. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +0 -1
  93. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
  94. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +15 -2
  95. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  96. package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +59 -0
  97. package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +7 -0
  98. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  99. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +4 -0
  100. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  101. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  102. package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs +8 -0
  103. package/dist-esm/lib/editor/tools/cancelShapeCreationOnLongPress.mjs.map +7 -0
  104. package/dist-esm/lib/editor/types/event-types.mjs +0 -2
  105. package/dist-esm/lib/editor/types/event-types.mjs.map +2 -2
  106. package/dist-esm/lib/globals/environment.mjs +6 -1
  107. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  108. package/dist-esm/lib/hooks/EditorComponentsContext.mjs.map +2 -2
  109. package/dist-esm/lib/hooks/useCanvasEvents.mjs +17 -8
  110. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  111. package/dist-esm/lib/hooks/useEditorComponents.mjs +0 -1
  112. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  113. package/dist-esm/lib/hooks/usePresence.mjs.map +2 -2
  114. package/dist-esm/lib/hooks/useScreenBounds.mjs +1 -0
  115. package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
  116. package/dist-esm/lib/license/LicenseManager.mjs +5 -1
  117. package/dist-esm/lib/license/LicenseManager.mjs.map +2 -2
  118. package/dist-esm/lib/primitives/Vec.mjs +3 -2
  119. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  120. package/dist-esm/lib/utils/dom.mjs +12 -0
  121. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  122. package/dist-esm/lib/utils/getPointerInfo.mjs +2 -1
  123. package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
  124. package/dist-esm/lib/utils/pointer.mjs +17 -0
  125. package/dist-esm/lib/utils/pointer.mjs.map +7 -0
  126. package/dist-esm/version.mjs +3 -3
  127. package/dist-esm/version.mjs.map +1 -1
  128. package/editor.css +15 -3
  129. package/package.json +11 -8
  130. package/src/index.ts +4 -10
  131. package/src/lib/components/MenuClickCapture.tsx +8 -4
  132. package/src/lib/components/Shape.tsx +88 -1
  133. package/src/lib/components/default-components/DefaultCanvas.tsx +1 -17
  134. package/src/lib/editor/Editor.test.ts +36 -0
  135. package/src/lib/editor/Editor.ts +204 -75
  136. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +54 -74
  137. package/src/lib/editor/managers/ClickManager/ClickManager.ts +15 -65
  138. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +43 -16
  139. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +8 -5
  140. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +4 -4
  141. package/src/lib/editor/managers/FocusManager/FocusManager.ts +1 -2
  142. package/src/lib/editor/managers/FontManager/FontManager.test.ts +37 -10
  143. package/src/lib/editor/managers/FontManager/FontManager.ts +46 -1
  144. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +32 -0
  145. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +34 -4
  146. package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +61 -0
  147. package/src/lib/editor/managers/InputsManager/InputsManager.ts +16 -4
  148. package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +9 -2
  149. package/src/lib/editor/managers/TextManager/TextManager.test.ts +16 -14
  150. package/src/lib/editor/managers/TextManager/TextManager.ts +17 -2
  151. package/src/lib/editor/managers/TickManager/TickManager.test.ts +0 -40
  152. package/src/lib/editor/managers/TickManager/TickManager.ts +0 -1
  153. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +12 -2
  154. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +27 -2
  155. package/src/lib/editor/overlays/strokeShapeIndicators.ts +86 -0
  156. package/src/lib/editor/shapes/ShapeUtil.ts +41 -0
  157. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +5 -0
  158. package/src/lib/editor/tools/StateNode.ts +0 -2
  159. package/src/lib/editor/tools/cancelShapeCreationOnLongPress.ts +31 -0
  160. package/src/lib/editor/types/event-types.ts +9 -6
  161. package/src/lib/globals/environment.ts +7 -0
  162. package/src/lib/hooks/EditorComponentsContext.tsx +0 -2
  163. package/src/lib/hooks/useCanvasEvents.ts +24 -12
  164. package/src/lib/hooks/useEditorComponents.tsx +0 -1
  165. package/src/lib/hooks/usePresence.ts +2 -2
  166. package/src/lib/hooks/useScreenBounds.ts +3 -0
  167. package/src/lib/license/LicenseManager.test.ts +24 -16
  168. package/src/lib/license/LicenseManager.ts +8 -2
  169. package/src/lib/primitives/Vec.ts +5 -2
  170. package/src/lib/test/ContentElementSlot.test.tsx +201 -0
  171. package/src/lib/utils/dom.ts +34 -0
  172. package/src/lib/utils/getPointerInfo.ts +2 -1
  173. package/src/lib/utils/pointer.test.ts +76 -0
  174. package/src/lib/utils/pointer.ts +42 -0
  175. package/src/version.ts +3 -3
  176. package/dist-cjs/lib/components/default-components/DefaultSelectionBackground.js +0 -49
  177. package/dist-cjs/lib/components/default-components/DefaultSelectionBackground.js.map +0 -7
  178. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
  179. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +0 -7
  180. package/dist-cjs/lib/hooks/useTransform.js.map +0 -7
  181. package/dist-esm/lib/components/default-components/DefaultSelectionBackground.mjs +0 -19
  182. package/dist-esm/lib/components/default-components/DefaultSelectionBackground.mjs.map +0 -7
  183. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +0 -141
  184. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +0 -7
  185. package/dist-esm/lib/hooks/useTransform.mjs +0 -23
  186. package/dist-esm/lib/hooks/useTransform.mjs.map +0 -7
  187. package/src/lib/components/default-components/DefaultSelectionBackground.tsx +0 -25
  188. package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
  189. package/src/lib/hooks/useTransform.ts +0 -30
@@ -155,12 +155,12 @@ class Editor extends import_eventemitter3.default {
155
155
  this._tickManager = new import_TickManager.TickManager(this);
156
156
  this.disposables.add(() => this._tickManager.dispose());
157
157
  this.disposables.add(() => {
158
- this.off("tick", this._decayCameraStateTimeout);
159
158
  this._setCameraState("idle");
160
159
  });
161
160
  this.fonts = new import_FontManager.FontManager(this, fontAssetUrls);
162
161
  this.disposables.add(() => this.fonts.dispose());
163
162
  this.inputs = new import_InputsManager.InputsManager(this);
163
+ this.disposables.add(() => this.inputs.dispose());
164
164
  this.performance = new import_PerformanceManager.PerformanceManager(this);
165
165
  this.disposables.add(() => this.performance.dispose());
166
166
  this.collaborators = new import_CollaboratorsManager.CollaboratorsManager(this);
@@ -789,6 +789,7 @@ class Editor extends import_eventemitter3.default {
789
789
  this.store.dispose();
790
790
  this.isDisposed = true;
791
791
  this.emit("dispose");
792
+ this.removeAllListeners();
792
793
  }
793
794
  /* ------------------ Themes (shadowing the theme manager) ------------------ */
794
795
  /**
@@ -1058,6 +1059,14 @@ class Editor extends import_eventemitter3.default {
1058
1059
  getMarkIdMatching(idSubstring) {
1059
1060
  return this.history.getMarkIdMatching(idSubstring);
1060
1061
  }
1062
+ /**
1063
+ * Whether the editor is currently replaying history (i.e. an undo or redo is being applied).
1064
+ *
1065
+ * @internal
1066
+ */
1067
+ isReplayingHistory() {
1068
+ return this.history.isReplaying();
1069
+ }
1061
1070
  /**
1062
1071
  * Coalesces all changes since the given mark into a single change, removing any intermediate marks.
1063
1072
  *
@@ -2152,7 +2161,7 @@ class Editor extends import_eventemitter3.default {
2152
2161
  return baseCamera;
2153
2162
  }
2154
2163
  _getFollowingPresence(targetUserId) {
2155
- const visited = [this.user.getId()];
2164
+ const visited = [this.user.getRecordId()];
2156
2165
  const collaborators = this.getCollaborators();
2157
2166
  let leaderPresence = null;
2158
2167
  while (targetUserId && !visited.includes(targetUserId)) {
@@ -2340,6 +2349,11 @@ class Editor extends import_eventemitter3.default {
2340
2349
  getConstrainedCamera(point, opts) {
2341
2350
  const currentCamera = this.getCamera();
2342
2351
  let { x, y, z = currentCamera.z } = point;
2352
+ const preserveFocalPoint = (current, requested, rz, z2) => {
2353
+ const cz = currentCamera.z;
2354
+ if (rz === cz) return current;
2355
+ return current + (requested - current) * (1 / z2 - 1 / cz) / (1 / rz - 1 / cz);
2356
+ };
2343
2357
  if (!opts?.force) {
2344
2358
  const cameraOptions = this.getCameraOptions();
2345
2359
  const zoomMin = cameraOptions.zoomSteps[0];
@@ -2359,14 +2373,10 @@ class Editor extends import_eventemitter3.default {
2359
2373
  z = this.getInitialZoom();
2360
2374
  }
2361
2375
  if (z < minZ || z > maxZ) {
2362
- const { x: cx, y: cy, z: cz } = currentCamera;
2363
- const cxA = -cx + vsb.w / cz / 2;
2364
- const cyA = -cy + vsb.h / cz / 2;
2376
+ const rz = z;
2365
2377
  z = (0, import_utils2.clamp)(z, minZ, maxZ);
2366
- const cxB = -cx + vsb.w / z / 2;
2367
- const cyB = -cy + vsb.h / z / 2;
2368
- x = cx + cxB - cxA;
2369
- y = cy + cyB - cyA;
2378
+ x = preserveFocalPoint(currentCamera.x, x, rz, z);
2379
+ y = preserveFocalPoint(currentCamera.y, y, rz, z);
2370
2380
  }
2371
2381
  const minX = px / z - bounds.x;
2372
2382
  const minY = py / z - bounds.y;
@@ -2435,10 +2445,10 @@ class Editor extends import_eventemitter3.default {
2435
2445
  }
2436
2446
  } else {
2437
2447
  if (z > zoomMax || z < zoomMin) {
2438
- const { x: cx, y: cy, z: cz } = currentCamera;
2448
+ const rz = z;
2439
2449
  z = (0, import_utils2.clamp)(z, zoomMin, zoomMax);
2440
- x = cx + (-cx + vsb.w / z / 2) - (-cx + vsb.w / cz / 2);
2441
- y = cy + (-cy + vsb.h / z / 2) - (-cy + vsb.h / cz / 2);
2450
+ x = preserveFocalPoint(currentCamera.x, x, rz, z);
2451
+ y = preserveFocalPoint(currentCamera.y, y, rz, z);
2442
2452
  }
2443
2453
  }
2444
2454
  }
@@ -2861,14 +2871,25 @@ class Editor extends import_eventemitter3.default {
2861
2871
  this.off("stop-camera-animation", cancel);
2862
2872
  };
2863
2873
  this.once("stop-camera-animation", cancel);
2874
+ const dirZ = direction.z ?? 0;
2864
2875
  const moveCamera = (elapsed) => {
2865
2876
  const { x: cx, y: cy, z: cz } = this.getCamera();
2866
- const movementVec = import_Vec.Vec.Mul(direction, currentSpeed * elapsed / cz);
2877
+ const dx = direction.x * (currentSpeed * elapsed) / cz;
2878
+ const dy = direction.y * (currentSpeed * elapsed) / cz;
2879
+ let newCx = cx + dx;
2880
+ let newCy = cy + dy;
2881
+ let newCz = cz;
2882
+ if (dirZ !== 0) {
2883
+ newCz = cz * (1 + dirZ * currentSpeed * elapsed);
2884
+ const center = this.getViewportScreenCenter();
2885
+ newCx += center.x / newCz - center.x / cz;
2886
+ newCy += center.y / newCz - center.y / cz;
2887
+ }
2867
2888
  currentSpeed *= 1 - friction;
2868
2889
  if (currentSpeed < speedThreshold) {
2869
2890
  cancel();
2870
2891
  } else {
2871
- this._setCamera(new import_Vec.Vec(cx + movementVec.x, cy + movementVec.y, cz));
2892
+ this._setCamera(new import_Vec.Vec(newCx, newCy, newCz));
2872
2893
  }
2873
2894
  };
2874
2895
  this.on("tick", moveCamera);
@@ -2948,6 +2969,7 @@ class Editor extends import_eventemitter3.default {
2948
2969
  screenBounds.height = Math.max(screenBounds.height, 1);
2949
2970
  }
2950
2971
  const doc = this.getContainerDocument();
2972
+ if (!doc.body) return this;
2951
2973
  const insets = [
2952
2974
  // top
2953
2975
  screenBounds.minY !== 0,
@@ -3157,7 +3179,7 @@ class Editor extends import_eventemitter3.default {
3157
3179
  }
3158
3180
  /**
3159
3181
  * Collect user IDs referenced by a set of shapes via shape-specific props
3160
- * (e.g. `textFirstEditedBy` on notes).
3182
+ * (e.g. `textLastEditedBy` on notes).
3161
3183
  *
3162
3184
  * @internal
3163
3185
  */
@@ -3188,7 +3210,7 @@ class Editor extends import_eventemitter3.default {
3188
3210
  */
3189
3211
  startFollowingUser(userId) {
3190
3212
  this.stopFollowingUser();
3191
- const thisUserId = this.user.getId();
3213
+ const thisUserId = this.user.getExternalId();
3192
3214
  if (!thisUserId) {
3193
3215
  console.warn("You should set the userId for the current instance before following a user");
3194
3216
  }
@@ -5892,24 +5914,40 @@ class Editor extends import_eventemitter3.default {
5892
5914
  * @public
5893
5915
  */
5894
5916
  resizeShape(shape, scale, opts = {}) {
5917
+ const partial = this.getResizeShapePartial(shape, scale, opts);
5918
+ if (partial) this.updateShapes([partial]);
5919
+ return this;
5920
+ }
5921
+ /**
5922
+ * Get the update for a resized shape without committing it to the store. Interactions that
5923
+ * resize many shapes at once use this to collect all of the updates and commit them in a
5924
+ * single batch. Returns null when there is nothing to update.
5925
+ *
5926
+ * Shapes that are rotated out of alignment with the scale axis cannot be resized with a
5927
+ * single update; those shapes are resized immediately (as `resizeShape` would do) and null
5928
+ * is returned.
5929
+ *
5930
+ * @internal
5931
+ */
5932
+ getResizeShapePartial(shape, scale, opts = {}) {
5895
5933
  const id = typeof shape === "string" ? shape : shape.id;
5896
- if (this.getIsReadonly()) return this;
5934
+ if (this.getIsReadonly()) return null;
5897
5935
  if (!Number.isFinite(scale.x)) scale = new import_Vec.Vec(1, scale.y);
5898
5936
  if (!Number.isFinite(scale.y)) scale = new import_Vec.Vec(scale.x, 1);
5899
5937
  const initialShape = opts.initialShape ?? this.getShape(id);
5900
- if (!initialShape) return this;
5938
+ if (!initialShape) return null;
5901
5939
  const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
5902
- if (!scaleOrigin) return this;
5940
+ if (!scaleOrigin) return null;
5903
5941
  const pageTransform = opts.initialPageTransform ? import_Mat.Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
5904
- if (!pageTransform) return this;
5942
+ if (!pageTransform) return null;
5905
5943
  const pageRotation = pageTransform.rotation();
5906
- if (pageRotation == null) return this;
5944
+ if (pageRotation == null) return null;
5907
5945
  const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
5908
5946
  const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
5909
- if (!initialBounds) return this;
5947
+ if (!initialBounds) return null;
5910
5948
  const isAspectRatioLocked = opts.isAspectRatioLocked ?? this.getShapeUtil(initialShape).isAspectRatioLocked(initialShape);
5911
5949
  if (!(0, import_utils2.areAnglesCompatible)(pageRotation, scaleAxisRotation)) {
5912
- return this._resizeUnalignedShape(id, scale, {
5950
+ this._resizeUnalignedShape(id, scale, {
5913
5951
  ...opts,
5914
5952
  initialBounds,
5915
5953
  scaleOrigin,
@@ -5918,6 +5956,7 @@ class Editor extends import_eventemitter3.default {
5918
5956
  isAspectRatioLocked,
5919
5957
  initialShape
5920
5958
  });
5959
+ return null;
5921
5960
  }
5922
5961
  const util = this.getShapeUtil(initialShape);
5923
5962
  if (isAspectRatioLocked) {
@@ -5927,7 +5966,7 @@ class Editor extends import_eventemitter3.default {
5927
5966
  scale = new import_Vec.Vec(Math.sign(scale.x) * Math.abs(scale.y), scale.y);
5928
5967
  }
5929
5968
  }
5930
- let didResize = false;
5969
+ let workingShape = null;
5931
5970
  if (util.onResize && util.canResize(initialShape)) {
5932
5971
  const newPagePoint = this._scalePagePoint(
5933
5972
  import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec(0, 0)),
@@ -5945,7 +5984,7 @@ class Editor extends import_eventemitter3.default {
5945
5984
  myScale.y = areWidthAndHeightAlignedWithCorrectAxis ? scale.y : scale.x;
5946
5985
  const initialPagePoint = import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec());
5947
5986
  const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint);
5948
- let workingShape = initialShape;
5987
+ workingShape = initialShape;
5949
5988
  if (!opts.skipStartAndEndCallbacks) {
5950
5989
  workingShape = applyPartialToRecordWithProps(
5951
5990
  initialShape,
@@ -5965,9 +6004,6 @@ class Editor extends import_eventemitter3.default {
5965
6004
  initialShape
5966
6005
  }
5967
6006
  );
5968
- if (resizedShape) {
5969
- didResize = true;
5970
- }
5971
6007
  workingShape = applyPartialToRecordWithProps(workingShape, {
5972
6008
  id,
5973
6009
  type: initialShape.type,
@@ -5981,32 +6017,36 @@ class Editor extends import_eventemitter3.default {
5981
6017
  util.onResizeEnd?.(initialShape, workingShape) ?? void 0
5982
6018
  );
5983
6019
  }
5984
- this.updateShapes([workingShape]);
6020
+ if (resizedShape) {
6021
+ return workingShape;
6022
+ }
5985
6023
  }
5986
- if (!didResize) {
5987
- const initialPageCenter = import_Mat.Mat.applyToPoint(pageTransform, initialBounds.center);
5988
- const newPageCenter = this._scalePagePoint(
5989
- initialPageCenter,
5990
- scaleOrigin,
5991
- scale,
5992
- scaleAxisRotation
5993
- );
5994
- const initialPageCenterInParentSpace = this.getPointInParentSpace(
5995
- initialShape.id,
5996
- initialPageCenter
5997
- );
5998
- const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
5999
- const delta = import_Vec.Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
6000
- this.updateShapes([
6001
- {
6002
- id,
6003
- type: initialShape.type,
6004
- x: initialShape.x + delta.x,
6005
- y: initialShape.y + delta.y
6006
- }
6007
- ]);
6024
+ const initialPageCenter = import_Mat.Mat.applyToPoint(pageTransform, initialBounds.center);
6025
+ const newPageCenter = this._scalePagePoint(
6026
+ initialPageCenter,
6027
+ scaleOrigin,
6028
+ scale,
6029
+ scaleAxisRotation
6030
+ );
6031
+ const initialPageCenterInParentSpace = this.getPointInParentSpace(
6032
+ initialShape.id,
6033
+ initialPageCenter
6034
+ );
6035
+ const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
6036
+ const delta = import_Vec.Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
6037
+ if (workingShape) {
6038
+ return {
6039
+ ...workingShape,
6040
+ x: initialShape.x + delta.x,
6041
+ y: initialShape.y + delta.y
6042
+ };
6008
6043
  }
6009
- return this;
6044
+ return {
6045
+ id,
6046
+ type: initialShape.type,
6047
+ x: initialShape.x + delta.x,
6048
+ y: initialShape.y + delta.y
6049
+ };
6010
6050
  }
6011
6051
  /** @internal */
6012
6052
  _scalePagePoint(point, scaleOrigin, scale, scaleAxisRotation) {
@@ -7260,6 +7300,7 @@ class Editor extends import_eventemitter3.default {
7260
7300
  async getSvgElement(shapes, opts = {}) {
7261
7301
  const ids = shapes.length === 0 ? this.getCurrentPageShapeIdsSorted() : typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
7262
7302
  if (ids.length === 0) return void 0;
7303
+ await this.fonts.loadRequiredFontsForCurrentPage(this.options.maxFontsToLoadBeforeRender);
7263
7304
  return (0, import_exportToSvg.exportToSvg)(this, ids, opts);
7264
7305
  }
7265
7306
  /**
@@ -7834,6 +7875,15 @@ class Editor extends import_eventemitter3.default {
7834
7875
  _didPinch = false;
7835
7876
  /** @internal */
7836
7877
  _selectedShapeIdsAtPointerDown = [];
7878
+ /**
7879
+ * Whether `_selectedShapeIdsAtPointerDown` holds a pre-gesture selection
7880
+ * captured by a `pointer_down` (the touch path) that a following pinch
7881
+ * should restore. False when no pointer_down preceded the pinch (the
7882
+ * Safari trackpad path uses gesture events), in which case `pinch_start`
7883
+ * captures the live selection instead.
7884
+ * @internal
7885
+ */
7886
+ _didCaptureSelectionAtPointerDown = false;
7837
7887
  /** @internal */
7838
7888
  _longPressTimeout = -1;
7839
7889
  /** @internal */
@@ -7966,10 +8016,15 @@ class Editor extends import_eventemitter3.default {
7966
8016
  case "pinch_start": {
7967
8017
  if (inputs.getIsPinching()) return;
7968
8018
  if (!inputs.getIsEditing()) {
7969
- this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds];
8019
+ if (!this._didCaptureSelectionAtPointerDown) {
8020
+ this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds];
8021
+ }
7970
8022
  this._didPinch = true;
7971
8023
  inputs.setIsPinching(true);
7972
8024
  this.interrupt();
8025
+ if (this._didCaptureSelectionAtPointerDown) {
8026
+ this.setSelectedShapes(this._selectedShapeIdsAtPointerDown);
8027
+ }
7973
8028
  }
7974
8029
  this.emit("event", info);
7975
8030
  return;
@@ -8009,6 +8064,7 @@ class Editor extends import_eventemitter3.default {
8009
8064
  const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this;
8010
8065
  this.setSelectedShapes(this._selectedShapeIdsAtPointerDown);
8011
8066
  this._selectedShapeIdsAtPointerDown = [];
8067
+ this._didCaptureSelectionAtPointerDown = false;
8012
8068
  if (this._didPinch) {
8013
8069
  this._didPinch = false;
8014
8070
  if (shapesToReselect.length > 0) {
@@ -8102,12 +8158,18 @@ class Editor extends import_eventemitter3.default {
8102
8158
  });
8103
8159
  }, this.options.longPressDurationMs);
8104
8160
  }
8105
- this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds();
8161
+ if (!this._didCaptureSelectionAtPointerDown) {
8162
+ this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds();
8163
+ this._didCaptureSelectionAtPointerDown = true;
8164
+ }
8106
8165
  if (info.button === import_constants.LEFT_MOUSE_BUTTON) this.capturedPointerId = info.pointerId;
8107
8166
  inputs.buttons.add(info.button);
8108
8167
  inputs.setIsPointing(true);
8109
8168
  inputs.setIsDragging(false);
8110
- if (!isPenMode && isPen) this.updateInstanceState({ isPenMode: true });
8169
+ if (!isPenMode && info.isPenDirect) {
8170
+ this.updateInstanceState({ isPenMode: true });
8171
+ this.interrupt();
8172
+ }
8111
8173
  if (info.button === import_constants.STYLUS_ERASER_BUTTON) {
8112
8174
  this._restoreToolId = this.getCurrentToolId();
8113
8175
  this.complete();
@@ -8175,6 +8237,7 @@ class Editor extends import_eventemitter3.default {
8175
8237
  if (this.inputs.getIsRightPointing() && !this.inputs.getIsPanning()) {
8176
8238
  this.inputs.setIsRightPointing(false);
8177
8239
  this._selectedShapeIdsAtPointerDown = [];
8240
+ this._didCaptureSelectionAtPointerDown = false;
8178
8241
  break;
8179
8242
  }
8180
8243
  this.inputs.setIsRightPointing(false);
@@ -8209,14 +8272,21 @@ class Editor extends import_eventemitter3.default {
8209
8272
  this.setCursor({ type: this._prevCursor, rotation: 0 });
8210
8273
  }
8211
8274
  if (slideSpeed > 0) {
8212
- this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8275
+ this.slideCamera({
8276
+ speed: slideSpeed,
8277
+ direction: { x: slideDirection.x, y: slideDirection.y, z: 0 }
8278
+ });
8213
8279
  }
8214
8280
  this._selectedShapeIdsAtPointerDown = [];
8281
+ this._didCaptureSelectionAtPointerDown = false;
8215
8282
  return this;
8216
8283
  }
8217
8284
  }
8218
8285
  if (slideSpeed > 0) {
8219
- this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8286
+ this.slideCamera({
8287
+ speed: slideSpeed,
8288
+ direction: { x: slideDirection.x, y: slideDirection.y, z: 0 }
8289
+ });
8220
8290
  }
8221
8291
  } else {
8222
8292
  if (info.button === import_constants.STYLUS_ERASER_BUTTON) {
@@ -8225,6 +8295,7 @@ class Editor extends import_eventemitter3.default {
8225
8295
  }
8226
8296
  }
8227
8297
  this._selectedShapeIdsAtPointerDown = [];
8298
+ this._didCaptureSelectionAtPointerDown = false;
8228
8299
  break;
8229
8300
  }
8230
8301
  }
@@ -8307,6 +8378,9 @@ class Editor extends import_eventemitter3.default {
8307
8378
  } else if (info.button === import_constants.RIGHT_MOUSE_BUTTON) {
8308
8379
  info.name = "right_click";
8309
8380
  }
8381
+ if (info.name === "right_click" && this.getCurrentToolId() !== "select" && this.getStateDescendant("select")) {
8382
+ this.setCurrentTool("select");
8383
+ }
8310
8384
  const { isPenMode } = this.store.unsafeGetWithoutCapture(import_tlschema.TLINSTANCE_ID);
8311
8385
  if (info.isPen === isPenMode) {
8312
8386
  const clickInfo = this._clickManager.handlePointerEvent(info);