@tldraw/editor 5.2.0-next.355d68cf24e8 → 5.2.0-next.43d958280e72

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 (101) hide show
  1. package/README.md +7 -1
  2. package/dist-cjs/index.d.ts +44 -40
  3. package/dist-cjs/index.js +4 -4
  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/editor/Editor.js +91 -44
  8. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  9. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js +3 -3
  10. package/dist-cjs/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.js.map +2 -2
  11. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +24 -2
  12. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  13. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +14 -3
  14. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +2 -2
  15. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +4 -2
  16. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +2 -2
  17. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +7 -3
  18. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  19. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +0 -1
  20. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  21. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +15 -2
  22. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  23. package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js +79 -0
  24. package/dist-cjs/lib/editor/overlays/strokeShapeIndicators.js.map +7 -0
  25. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +3 -0
  26. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  27. package/dist-cjs/lib/hooks/useCanvasEvents.js +14 -7
  28. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  29. package/dist-cjs/lib/hooks/usePresence.js.map +2 -2
  30. package/dist-cjs/lib/utils/getPointerInfo.js +2 -1
  31. package/dist-cjs/lib/utils/getPointerInfo.js.map +2 -2
  32. package/dist-cjs/lib/utils/pointer.js +32 -0
  33. package/dist-cjs/lib/utils/pointer.js.map +7 -0
  34. package/dist-cjs/version.js +3 -3
  35. package/dist-cjs/version.js.map +1 -1
  36. package/dist-esm/index.d.mts +44 -40
  37. package/dist-esm/index.mjs +5 -7
  38. package/dist-esm/index.mjs.map +2 -2
  39. package/dist-esm/lib/components/MenuClickCapture.mjs +8 -5
  40. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  41. package/dist-esm/lib/editor/Editor.mjs +91 -44
  42. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  43. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs +3 -3
  44. package/dist-esm/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.mjs.map +2 -2
  45. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +24 -2
  46. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  47. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +14 -3
  48. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +2 -2
  49. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +4 -2
  50. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +2 -2
  51. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +7 -3
  52. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  53. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +0 -1
  54. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
  55. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +15 -2
  56. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  57. package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs +59 -0
  58. package/dist-esm/lib/editor/overlays/strokeShapeIndicators.mjs.map +7 -0
  59. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +3 -0
  60. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  61. package/dist-esm/lib/hooks/useCanvasEvents.mjs +14 -7
  62. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  63. package/dist-esm/lib/hooks/usePresence.mjs.map +2 -2
  64. package/dist-esm/lib/utils/getPointerInfo.mjs +2 -1
  65. package/dist-esm/lib/utils/getPointerInfo.mjs.map +2 -2
  66. package/dist-esm/lib/utils/pointer.mjs +12 -0
  67. package/dist-esm/lib/utils/pointer.mjs.map +7 -0
  68. package/dist-esm/version.mjs +3 -3
  69. package/dist-esm/version.mjs.map +1 -1
  70. package/editor.css +5 -3
  71. package/package.json +8 -8
  72. package/src/index.ts +2 -5
  73. package/src/lib/components/MenuClickCapture.tsx +8 -4
  74. package/src/lib/editor/Editor.ts +115 -53
  75. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.test.ts +43 -16
  76. package/src/lib/editor/managers/CollaboratorsManager/CollaboratorsManager.ts +8 -5
  77. package/src/lib/editor/managers/FontManager/FontManager.test.ts +13 -9
  78. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +32 -0
  79. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +34 -4
  80. package/src/lib/editor/managers/InputsManager/InputsManager.test.ts +61 -0
  81. package/src/lib/editor/managers/InputsManager/InputsManager.ts +16 -4
  82. package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +9 -2
  83. package/src/lib/editor/managers/TextManager/TextManager.test.ts +16 -14
  84. package/src/lib/editor/managers/TextManager/TextManager.ts +17 -2
  85. package/src/lib/editor/managers/TickManager/TickManager.test.ts +0 -40
  86. package/src/lib/editor/managers/TickManager/TickManager.ts +0 -1
  87. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +12 -2
  88. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +27 -2
  89. package/src/lib/editor/overlays/strokeShapeIndicators.ts +86 -0
  90. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +4 -0
  91. package/src/lib/hooks/useCanvasEvents.ts +19 -12
  92. package/src/lib/hooks/usePresence.ts +2 -2
  93. package/src/lib/utils/getPointerInfo.ts +2 -1
  94. package/src/lib/utils/pointer.test.ts +48 -0
  95. package/src/lib/utils/pointer.ts +18 -0
  96. package/src/version.ts +3 -3
  97. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js +0 -161
  98. package/dist-cjs/lib/editor/overlays/ShapeIndicatorOverlayUtil.js.map +0 -7
  99. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs +0 -141
  100. package/dist-esm/lib/editor/overlays/ShapeIndicatorOverlayUtil.mjs.map +0 -7
  101. package/src/lib/editor/overlays/ShapeIndicatorOverlayUtil.ts +0 -216
@@ -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)) {
@@ -2862,14 +2871,25 @@ class Editor extends import_eventemitter3.default {
2862
2871
  this.off("stop-camera-animation", cancel);
2863
2872
  };
2864
2873
  this.once("stop-camera-animation", cancel);
2874
+ const dirZ = direction.z ?? 0;
2865
2875
  const moveCamera = (elapsed) => {
2866
2876
  const { x: cx, y: cy, z: cz } = this.getCamera();
2867
- 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
+ }
2868
2888
  currentSpeed *= 1 - friction;
2869
2889
  if (currentSpeed < speedThreshold) {
2870
2890
  cancel();
2871
2891
  } else {
2872
- this._setCamera(new import_Vec.Vec(cx + movementVec.x, cy + movementVec.y, cz));
2892
+ this._setCamera(new import_Vec.Vec(newCx, newCy, newCz));
2873
2893
  }
2874
2894
  };
2875
2895
  this.on("tick", moveCamera);
@@ -3189,7 +3209,7 @@ class Editor extends import_eventemitter3.default {
3189
3209
  */
3190
3210
  startFollowingUser(userId) {
3191
3211
  this.stopFollowingUser();
3192
- const thisUserId = this.user.getId();
3212
+ const thisUserId = this.user.getExternalId();
3193
3213
  if (!thisUserId) {
3194
3214
  console.warn("You should set the userId for the current instance before following a user");
3195
3215
  }
@@ -5893,24 +5913,40 @@ class Editor extends import_eventemitter3.default {
5893
5913
  * @public
5894
5914
  */
5895
5915
  resizeShape(shape, scale, opts = {}) {
5916
+ const partial = this.getResizeShapePartial(shape, scale, opts);
5917
+ if (partial) this.updateShapes([partial]);
5918
+ return this;
5919
+ }
5920
+ /**
5921
+ * Get the update for a resized shape without committing it to the store. Interactions that
5922
+ * resize many shapes at once use this to collect all of the updates and commit them in a
5923
+ * single batch. Returns null when there is nothing to update.
5924
+ *
5925
+ * Shapes that are rotated out of alignment with the scale axis cannot be resized with a
5926
+ * single update; those shapes are resized immediately (as `resizeShape` would do) and null
5927
+ * is returned.
5928
+ *
5929
+ * @internal
5930
+ */
5931
+ getResizeShapePartial(shape, scale, opts = {}) {
5896
5932
  const id = typeof shape === "string" ? shape : shape.id;
5897
- if (this.getIsReadonly()) return this;
5933
+ if (this.getIsReadonly()) return null;
5898
5934
  if (!Number.isFinite(scale.x)) scale = new import_Vec.Vec(1, scale.y);
5899
5935
  if (!Number.isFinite(scale.y)) scale = new import_Vec.Vec(scale.x, 1);
5900
5936
  const initialShape = opts.initialShape ?? this.getShape(id);
5901
- if (!initialShape) return this;
5937
+ if (!initialShape) return null;
5902
5938
  const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
5903
- if (!scaleOrigin) return this;
5939
+ if (!scaleOrigin) return null;
5904
5940
  const pageTransform = opts.initialPageTransform ? import_Mat.Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
5905
- if (!pageTransform) return this;
5941
+ if (!pageTransform) return null;
5906
5942
  const pageRotation = pageTransform.rotation();
5907
- if (pageRotation == null) return this;
5943
+ if (pageRotation == null) return null;
5908
5944
  const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
5909
5945
  const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
5910
- if (!initialBounds) return this;
5946
+ if (!initialBounds) return null;
5911
5947
  const isAspectRatioLocked = opts.isAspectRatioLocked ?? this.getShapeUtil(initialShape).isAspectRatioLocked(initialShape);
5912
5948
  if (!(0, import_utils2.areAnglesCompatible)(pageRotation, scaleAxisRotation)) {
5913
- return this._resizeUnalignedShape(id, scale, {
5949
+ this._resizeUnalignedShape(id, scale, {
5914
5950
  ...opts,
5915
5951
  initialBounds,
5916
5952
  scaleOrigin,
@@ -5919,6 +5955,7 @@ class Editor extends import_eventemitter3.default {
5919
5955
  isAspectRatioLocked,
5920
5956
  initialShape
5921
5957
  });
5958
+ return null;
5922
5959
  }
5923
5960
  const util = this.getShapeUtil(initialShape);
5924
5961
  if (isAspectRatioLocked) {
@@ -5928,7 +5965,7 @@ class Editor extends import_eventemitter3.default {
5928
5965
  scale = new import_Vec.Vec(Math.sign(scale.x) * Math.abs(scale.y), scale.y);
5929
5966
  }
5930
5967
  }
5931
- let didResize = false;
5968
+ let workingShape = null;
5932
5969
  if (util.onResize && util.canResize(initialShape)) {
5933
5970
  const newPagePoint = this._scalePagePoint(
5934
5971
  import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec(0, 0)),
@@ -5946,7 +5983,7 @@ class Editor extends import_eventemitter3.default {
5946
5983
  myScale.y = areWidthAndHeightAlignedWithCorrectAxis ? scale.y : scale.x;
5947
5984
  const initialPagePoint = import_Mat.Mat.applyToPoint(pageTransform, new import_Vec.Vec());
5948
5985
  const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint);
5949
- let workingShape = initialShape;
5986
+ workingShape = initialShape;
5950
5987
  if (!opts.skipStartAndEndCallbacks) {
5951
5988
  workingShape = applyPartialToRecordWithProps(
5952
5989
  initialShape,
@@ -5966,9 +6003,6 @@ class Editor extends import_eventemitter3.default {
5966
6003
  initialShape
5967
6004
  }
5968
6005
  );
5969
- if (resizedShape) {
5970
- didResize = true;
5971
- }
5972
6006
  workingShape = applyPartialToRecordWithProps(workingShape, {
5973
6007
  id,
5974
6008
  type: initialShape.type,
@@ -5982,32 +6016,36 @@ class Editor extends import_eventemitter3.default {
5982
6016
  util.onResizeEnd?.(initialShape, workingShape) ?? void 0
5983
6017
  );
5984
6018
  }
5985
- this.updateShapes([workingShape]);
6019
+ if (resizedShape) {
6020
+ return workingShape;
6021
+ }
5986
6022
  }
5987
- if (!didResize) {
5988
- const initialPageCenter = import_Mat.Mat.applyToPoint(pageTransform, initialBounds.center);
5989
- const newPageCenter = this._scalePagePoint(
5990
- initialPageCenter,
5991
- scaleOrigin,
5992
- scale,
5993
- scaleAxisRotation
5994
- );
5995
- const initialPageCenterInParentSpace = this.getPointInParentSpace(
5996
- initialShape.id,
5997
- initialPageCenter
5998
- );
5999
- const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
6000
- const delta = import_Vec.Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
6001
- this.updateShapes([
6002
- {
6003
- id,
6004
- type: initialShape.type,
6005
- x: initialShape.x + delta.x,
6006
- y: initialShape.y + delta.y
6007
- }
6008
- ]);
6023
+ const initialPageCenter = import_Mat.Mat.applyToPoint(pageTransform, initialBounds.center);
6024
+ const newPageCenter = this._scalePagePoint(
6025
+ initialPageCenter,
6026
+ scaleOrigin,
6027
+ scale,
6028
+ scaleAxisRotation
6029
+ );
6030
+ const initialPageCenterInParentSpace = this.getPointInParentSpace(
6031
+ initialShape.id,
6032
+ initialPageCenter
6033
+ );
6034
+ const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
6035
+ const delta = import_Vec.Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
6036
+ if (workingShape) {
6037
+ return {
6038
+ ...workingShape,
6039
+ x: initialShape.x + delta.x,
6040
+ y: initialShape.y + delta.y
6041
+ };
6009
6042
  }
6010
- return this;
6043
+ return {
6044
+ id,
6045
+ type: initialShape.type,
6046
+ x: initialShape.x + delta.x,
6047
+ y: initialShape.y + delta.y
6048
+ };
6011
6049
  }
6012
6050
  /** @internal */
6013
6051
  _scalePagePoint(point, scaleOrigin, scale, scaleAxisRotation) {
@@ -8126,7 +8164,10 @@ class Editor extends import_eventemitter3.default {
8126
8164
  inputs.buttons.add(info.button);
8127
8165
  inputs.setIsPointing(true);
8128
8166
  inputs.setIsDragging(false);
8129
- if (!isPenMode && isPen) this.updateInstanceState({ isPenMode: true });
8167
+ if (!isPenMode && isPen) {
8168
+ this.updateInstanceState({ isPenMode: true });
8169
+ this.interrupt();
8170
+ }
8130
8171
  if (info.button === import_constants.STYLUS_ERASER_BUTTON) {
8131
8172
  this._restoreToolId = this.getCurrentToolId();
8132
8173
  this.complete();
@@ -8229,7 +8270,10 @@ class Editor extends import_eventemitter3.default {
8229
8270
  this.setCursor({ type: this._prevCursor, rotation: 0 });
8230
8271
  }
8231
8272
  if (slideSpeed > 0) {
8232
- this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8273
+ this.slideCamera({
8274
+ speed: slideSpeed,
8275
+ direction: { x: slideDirection.x, y: slideDirection.y, z: 0 }
8276
+ });
8233
8277
  }
8234
8278
  this._selectedShapeIdsAtPointerDown = [];
8235
8279
  this._didCaptureSelectionAtPointerDown = false;
@@ -8237,7 +8281,10 @@ class Editor extends import_eventemitter3.default {
8237
8281
  }
8238
8282
  }
8239
8283
  if (slideSpeed > 0) {
8240
- this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8284
+ this.slideCamera({
8285
+ speed: slideSpeed,
8286
+ direction: { x: slideDirection.x, y: slideDirection.y, z: 0 }
8287
+ });
8241
8288
  }
8242
8289
  } else {
8243
8290
  if (info.button === import_constants.STYLUS_ERASER_BUTTON) {