@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
@@ -188,12 +188,12 @@ class Editor extends EventEmitter {
188
188
  this._tickManager = new TickManager(this);
189
189
  this.disposables.add(() => this._tickManager.dispose());
190
190
  this.disposables.add(() => {
191
- this.off("tick", this._decayCameraStateTimeout);
192
191
  this._setCameraState("idle");
193
192
  });
194
193
  this.fonts = new FontManager(this, fontAssetUrls);
195
194
  this.disposables.add(() => this.fonts.dispose());
196
195
  this.inputs = new InputsManager(this);
196
+ this.disposables.add(() => this.inputs.dispose());
197
197
  this.performance = new PerformanceManager(this);
198
198
  this.disposables.add(() => this.performance.dispose());
199
199
  this.collaborators = new CollaboratorsManager(this);
@@ -822,6 +822,7 @@ class Editor extends EventEmitter {
822
822
  this.store.dispose();
823
823
  this.isDisposed = true;
824
824
  this.emit("dispose");
825
+ this.removeAllListeners();
825
826
  }
826
827
  /* ------------------ Themes (shadowing the theme manager) ------------------ */
827
828
  /**
@@ -1091,6 +1092,14 @@ class Editor extends EventEmitter {
1091
1092
  getMarkIdMatching(idSubstring) {
1092
1093
  return this.history.getMarkIdMatching(idSubstring);
1093
1094
  }
1095
+ /**
1096
+ * Whether the editor is currently replaying history (i.e. an undo or redo is being applied).
1097
+ *
1098
+ * @internal
1099
+ */
1100
+ isReplayingHistory() {
1101
+ return this.history.isReplaying();
1102
+ }
1094
1103
  /**
1095
1104
  * Coalesces all changes since the given mark into a single change, removing any intermediate marks.
1096
1105
  *
@@ -2185,7 +2194,7 @@ class Editor extends EventEmitter {
2185
2194
  return baseCamera;
2186
2195
  }
2187
2196
  _getFollowingPresence(targetUserId) {
2188
- const visited = [this.user.getId()];
2197
+ const visited = [this.user.getRecordId()];
2189
2198
  const collaborators = this.getCollaborators();
2190
2199
  let leaderPresence = null;
2191
2200
  while (targetUserId && !visited.includes(targetUserId)) {
@@ -2895,14 +2904,25 @@ class Editor extends EventEmitter {
2895
2904
  this.off("stop-camera-animation", cancel);
2896
2905
  };
2897
2906
  this.once("stop-camera-animation", cancel);
2907
+ const dirZ = direction.z ?? 0;
2898
2908
  const moveCamera = (elapsed) => {
2899
2909
  const { x: cx, y: cy, z: cz } = this.getCamera();
2900
- const movementVec = Vec.Mul(direction, currentSpeed * elapsed / cz);
2910
+ const dx = direction.x * (currentSpeed * elapsed) / cz;
2911
+ const dy = direction.y * (currentSpeed * elapsed) / cz;
2912
+ let newCx = cx + dx;
2913
+ let newCy = cy + dy;
2914
+ let newCz = cz;
2915
+ if (dirZ !== 0) {
2916
+ newCz = cz * (1 + dirZ * currentSpeed * elapsed);
2917
+ const center = this.getViewportScreenCenter();
2918
+ newCx += center.x / newCz - center.x / cz;
2919
+ newCy += center.y / newCz - center.y / cz;
2920
+ }
2901
2921
  currentSpeed *= 1 - friction;
2902
2922
  if (currentSpeed < speedThreshold) {
2903
2923
  cancel();
2904
2924
  } else {
2905
- this._setCamera(new Vec(cx + movementVec.x, cy + movementVec.y, cz));
2925
+ this._setCamera(new Vec(newCx, newCy, newCz));
2906
2926
  }
2907
2927
  };
2908
2928
  this.on("tick", moveCamera);
@@ -3222,7 +3242,7 @@ class Editor extends EventEmitter {
3222
3242
  */
3223
3243
  startFollowingUser(userId) {
3224
3244
  this.stopFollowingUser();
3225
- const thisUserId = this.user.getId();
3245
+ const thisUserId = this.user.getExternalId();
3226
3246
  if (!thisUserId) {
3227
3247
  console.warn("You should set the userId for the current instance before following a user");
3228
3248
  }
@@ -5926,24 +5946,40 @@ class Editor extends EventEmitter {
5926
5946
  * @public
5927
5947
  */
5928
5948
  resizeShape(shape, scale, opts = {}) {
5949
+ const partial = this.getResizeShapePartial(shape, scale, opts);
5950
+ if (partial) this.updateShapes([partial]);
5951
+ return this;
5952
+ }
5953
+ /**
5954
+ * Get the update for a resized shape without committing it to the store. Interactions that
5955
+ * resize many shapes at once use this to collect all of the updates and commit them in a
5956
+ * single batch. Returns null when there is nothing to update.
5957
+ *
5958
+ * Shapes that are rotated out of alignment with the scale axis cannot be resized with a
5959
+ * single update; those shapes are resized immediately (as `resizeShape` would do) and null
5960
+ * is returned.
5961
+ *
5962
+ * @internal
5963
+ */
5964
+ getResizeShapePartial(shape, scale, opts = {}) {
5929
5965
  const id = typeof shape === "string" ? shape : shape.id;
5930
- if (this.getIsReadonly()) return this;
5966
+ if (this.getIsReadonly()) return null;
5931
5967
  if (!Number.isFinite(scale.x)) scale = new Vec(1, scale.y);
5932
5968
  if (!Number.isFinite(scale.y)) scale = new Vec(scale.x, 1);
5933
5969
  const initialShape = opts.initialShape ?? this.getShape(id);
5934
- if (!initialShape) return this;
5970
+ if (!initialShape) return null;
5935
5971
  const scaleOrigin = opts.scaleOrigin ?? this.getShapePageBounds(id)?.center;
5936
- if (!scaleOrigin) return this;
5972
+ if (!scaleOrigin) return null;
5937
5973
  const pageTransform = opts.initialPageTransform ? Mat.Cast(opts.initialPageTransform) : this.getShapePageTransform(id);
5938
- if (!pageTransform) return this;
5974
+ if (!pageTransform) return null;
5939
5975
  const pageRotation = pageTransform.rotation();
5940
- if (pageRotation == null) return this;
5976
+ if (pageRotation == null) return null;
5941
5977
  const scaleAxisRotation = opts.scaleAxisRotation ?? pageRotation;
5942
5978
  const initialBounds = opts.initialBounds ?? this.getShapeGeometry(id).bounds;
5943
- if (!initialBounds) return this;
5979
+ if (!initialBounds) return null;
5944
5980
  const isAspectRatioLocked = opts.isAspectRatioLocked ?? this.getShapeUtil(initialShape).isAspectRatioLocked(initialShape);
5945
5981
  if (!areAnglesCompatible(pageRotation, scaleAxisRotation)) {
5946
- return this._resizeUnalignedShape(id, scale, {
5982
+ this._resizeUnalignedShape(id, scale, {
5947
5983
  ...opts,
5948
5984
  initialBounds,
5949
5985
  scaleOrigin,
@@ -5952,6 +5988,7 @@ class Editor extends EventEmitter {
5952
5988
  isAspectRatioLocked,
5953
5989
  initialShape
5954
5990
  });
5991
+ return null;
5955
5992
  }
5956
5993
  const util = this.getShapeUtil(initialShape);
5957
5994
  if (isAspectRatioLocked) {
@@ -5961,7 +5998,7 @@ class Editor extends EventEmitter {
5961
5998
  scale = new Vec(Math.sign(scale.x) * Math.abs(scale.y), scale.y);
5962
5999
  }
5963
6000
  }
5964
- let didResize = false;
6001
+ let workingShape = null;
5965
6002
  if (util.onResize && util.canResize(initialShape)) {
5966
6003
  const newPagePoint = this._scalePagePoint(
5967
6004
  Mat.applyToPoint(pageTransform, new Vec(0, 0)),
@@ -5979,7 +6016,7 @@ class Editor extends EventEmitter {
5979
6016
  myScale.y = areWidthAndHeightAlignedWithCorrectAxis ? scale.y : scale.x;
5980
6017
  const initialPagePoint = Mat.applyToPoint(pageTransform, new Vec());
5981
6018
  const { x, y } = this.getPointInParentSpace(initialShape.id, initialPagePoint);
5982
- let workingShape = initialShape;
6019
+ workingShape = initialShape;
5983
6020
  if (!opts.skipStartAndEndCallbacks) {
5984
6021
  workingShape = applyPartialToRecordWithProps(
5985
6022
  initialShape,
@@ -5999,9 +6036,6 @@ class Editor extends EventEmitter {
5999
6036
  initialShape
6000
6037
  }
6001
6038
  );
6002
- if (resizedShape) {
6003
- didResize = true;
6004
- }
6005
6039
  workingShape = applyPartialToRecordWithProps(workingShape, {
6006
6040
  id,
6007
6041
  type: initialShape.type,
@@ -6015,32 +6049,36 @@ class Editor extends EventEmitter {
6015
6049
  util.onResizeEnd?.(initialShape, workingShape) ?? void 0
6016
6050
  );
6017
6051
  }
6018
- this.updateShapes([workingShape]);
6052
+ if (resizedShape) {
6053
+ return workingShape;
6054
+ }
6019
6055
  }
6020
- if (!didResize) {
6021
- const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center);
6022
- const newPageCenter = this._scalePagePoint(
6023
- initialPageCenter,
6024
- scaleOrigin,
6025
- scale,
6026
- scaleAxisRotation
6027
- );
6028
- const initialPageCenterInParentSpace = this.getPointInParentSpace(
6029
- initialShape.id,
6030
- initialPageCenter
6031
- );
6032
- const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
6033
- const delta = Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
6034
- this.updateShapes([
6035
- {
6036
- id,
6037
- type: initialShape.type,
6038
- x: initialShape.x + delta.x,
6039
- y: initialShape.y + delta.y
6040
- }
6041
- ]);
6056
+ const initialPageCenter = Mat.applyToPoint(pageTransform, initialBounds.center);
6057
+ const newPageCenter = this._scalePagePoint(
6058
+ initialPageCenter,
6059
+ scaleOrigin,
6060
+ scale,
6061
+ scaleAxisRotation
6062
+ );
6063
+ const initialPageCenterInParentSpace = this.getPointInParentSpace(
6064
+ initialShape.id,
6065
+ initialPageCenter
6066
+ );
6067
+ const newPageCenterInParentSpace = this.getPointInParentSpace(initialShape.id, newPageCenter);
6068
+ const delta = Vec.Sub(newPageCenterInParentSpace, initialPageCenterInParentSpace);
6069
+ if (workingShape) {
6070
+ return {
6071
+ ...workingShape,
6072
+ x: initialShape.x + delta.x,
6073
+ y: initialShape.y + delta.y
6074
+ };
6042
6075
  }
6043
- return this;
6076
+ return {
6077
+ id,
6078
+ type: initialShape.type,
6079
+ x: initialShape.x + delta.x,
6080
+ y: initialShape.y + delta.y
6081
+ };
6044
6082
  }
6045
6083
  /** @internal */
6046
6084
  _scalePagePoint(point, scaleOrigin, scale, scaleAxisRotation) {
@@ -8159,7 +8197,10 @@ class Editor extends EventEmitter {
8159
8197
  inputs.buttons.add(info.button);
8160
8198
  inputs.setIsPointing(true);
8161
8199
  inputs.setIsDragging(false);
8162
- if (!isPenMode && isPen) this.updateInstanceState({ isPenMode: true });
8200
+ if (!isPenMode && isPen) {
8201
+ this.updateInstanceState({ isPenMode: true });
8202
+ this.interrupt();
8203
+ }
8163
8204
  if (info.button === STYLUS_ERASER_BUTTON) {
8164
8205
  this._restoreToolId = this.getCurrentToolId();
8165
8206
  this.complete();
@@ -8262,7 +8303,10 @@ class Editor extends EventEmitter {
8262
8303
  this.setCursor({ type: this._prevCursor, rotation: 0 });
8263
8304
  }
8264
8305
  if (slideSpeed > 0) {
8265
- this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8306
+ this.slideCamera({
8307
+ speed: slideSpeed,
8308
+ direction: { x: slideDirection.x, y: slideDirection.y, z: 0 }
8309
+ });
8266
8310
  }
8267
8311
  this._selectedShapeIdsAtPointerDown = [];
8268
8312
  this._didCaptureSelectionAtPointerDown = false;
@@ -8270,7 +8314,10 @@ class Editor extends EventEmitter {
8270
8314
  }
8271
8315
  }
8272
8316
  if (slideSpeed > 0) {
8273
- this.slideCamera({ speed: slideSpeed, direction: slideDirection });
8317
+ this.slideCamera({
8318
+ speed: slideSpeed,
8319
+ direction: { x: slideDirection.x, y: slideDirection.y, z: 0 }
8320
+ });
8274
8321
  }
8275
8322
  } else {
8276
8323
  if (info.button === STYLUS_ERASER_BUTTON) {