@tldraw/editor 3.14.0-canary.f907ed7d9ee5 → 3.14.0-canary.fb0390b30559

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 (75) hide show
  1. package/dist-cjs/index.d.ts +149 -50
  2. package/dist-cjs/index.js +4 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/editor/Editor.js +82 -25
  5. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  6. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js +3 -1
  7. package/dist-cjs/lib/editor/managers/HistoryManager/HistoryManager.js.map +2 -2
  8. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js +73 -42
  9. package/dist-cjs/lib/editor/managers/TextManager/TextManager.js.map +2 -2
  10. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +0 -10
  11. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +13 -6
  13. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +3 -3
  14. package/dist-cjs/lib/editor/tools/StateNode.js +3 -3
  15. package/dist-cjs/lib/editor/tools/StateNode.js.map +2 -2
  16. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  17. package/dist-cjs/lib/editor/types/external-content.js.map +1 -1
  18. package/dist-cjs/lib/hooks/useCanvasEvents.js +1 -2
  19. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  20. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +6 -2
  21. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  22. package/dist-cjs/lib/primitives/geometry/Group2d.js +11 -6
  23. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  24. package/dist-cjs/lib/utils/dom.js +1 -1
  25. package/dist-cjs/lib/utils/dom.js.map +2 -2
  26. package/dist-cjs/lib/utils/reparenting.js +232 -0
  27. package/dist-cjs/lib/utils/reparenting.js.map +7 -0
  28. package/dist-cjs/version.js +3 -3
  29. package/dist-cjs/version.js.map +1 -1
  30. package/dist-esm/index.d.mts +149 -50
  31. package/dist-esm/index.mjs +4 -1
  32. package/dist-esm/index.mjs.map +2 -2
  33. package/dist-esm/lib/editor/Editor.mjs +82 -25
  34. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  35. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs +3 -1
  36. package/dist-esm/lib/editor/managers/HistoryManager/HistoryManager.mjs.map +2 -2
  37. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs +73 -42
  38. package/dist-esm/lib/editor/managers/TextManager/TextManager.mjs.map +2 -2
  39. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +0 -10
  40. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  41. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +13 -6
  42. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +3 -3
  43. package/dist-esm/lib/editor/tools/StateNode.mjs +3 -3
  44. package/dist-esm/lib/editor/tools/StateNode.mjs.map +2 -2
  45. package/dist-esm/lib/hooks/useCanvasEvents.mjs +1 -2
  46. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  47. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +6 -2
  48. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  49. package/dist-esm/lib/primitives/geometry/Group2d.mjs +11 -6
  50. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  51. package/dist-esm/lib/utils/dom.mjs +1 -1
  52. package/dist-esm/lib/utils/dom.mjs.map +2 -2
  53. package/dist-esm/lib/utils/reparenting.mjs +216 -0
  54. package/dist-esm/lib/utils/reparenting.mjs.map +7 -0
  55. package/dist-esm/version.mjs +3 -3
  56. package/dist-esm/version.mjs.map +1 -1
  57. package/editor.css +446 -489
  58. package/package.json +7 -7
  59. package/src/index.ts +7 -0
  60. package/src/lib/editor/Editor.ts +103 -36
  61. package/src/lib/editor/managers/HistoryManager/HistoryManager.ts +3 -1
  62. package/src/lib/editor/managers/TextManager/TextManager.test.ts +1 -5
  63. package/src/lib/editor/managers/TextManager/TextManager.ts +118 -86
  64. package/src/lib/editor/shapes/ShapeUtil.ts +47 -15
  65. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +25 -17
  66. package/src/lib/editor/tools/StateNode.ts +3 -3
  67. package/src/lib/editor/types/emit-types.ts +4 -0
  68. package/src/lib/editor/types/external-content.ts +11 -2
  69. package/src/lib/hooks/useCanvasEvents.ts +0 -1
  70. package/src/lib/primitives/geometry/Geometry2d.ts +7 -2
  71. package/src/lib/primitives/geometry/Group2d.ts +11 -5
  72. package/src/lib/utils/dom.ts +1 -1
  73. package/src/lib/utils/reparenting.ts +383 -0
  74. package/src/version.ts +3 -3
  75. package/CHANGELOG.md +0 -4327
@@ -323,6 +323,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
323
323
  __publicField(this, "externalContentHandlers", {
324
324
  text: null,
325
325
  files: null,
326
+ "file-replace": null,
326
327
  embed: null,
327
328
  "svg-text": null,
328
329
  url: null,
@@ -439,6 +440,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
439
440
  this.disposables.add(() => this.user.dispose());
440
441
  this.getContainer = getContainer;
441
442
  this.textMeasure = new import_TextManager.TextManager(this);
443
+ this.disposables.add(() => this.textMeasure.dispose());
442
444
  this.fonts = new import_FontManager.FontManager(this, fontAssetUrls);
443
445
  this._tickManager = new import_TickManager.TickManager(this);
444
446
  class NewRoot extends import_RootState.RootState {
@@ -1640,6 +1642,19 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
1640
1642
  getSelectionPageBounds() {
1641
1643
  return this.getShapesPageBounds(this.getSelectedShapeIds());
1642
1644
  }
1645
+ /**
1646
+ * The bounds of the selection bounding box in the current page space.
1647
+ *
1648
+ * @readonly
1649
+ * @public
1650
+ */
1651
+ getSelectionScreenBounds() {
1652
+ const bounds = this.getSelectionPageBounds();
1653
+ if (!bounds) return void 0;
1654
+ const { x, y } = this.pageToScreen(bounds.point);
1655
+ const zoom = this.getZoomLevel();
1656
+ return new import_Box.Box(x, y, bounds.width * zoom, bounds.height * zoom);
1657
+ }
1643
1658
  /**
1644
1659
  * @internal
1645
1660
  */
@@ -2773,7 +2788,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
2773
2788
  * @public
2774
2789
  */
2775
2790
  updateViewportScreenBounds(screenBounds, center = false) {
2776
- if (screenBounds instanceof HTMLElement) {
2791
+ if (!(screenBounds instanceof import_Box.Box)) {
2777
2792
  const rect = screenBounds.getBoundingClientRect();
2778
2793
  screenBounds = new import_Box.Box(
2779
2794
  rect.left || rect.x,
@@ -4116,7 +4131,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4116
4131
  if (!id) return void 0;
4117
4132
  const freshShape = this.getShape(id);
4118
4133
  if (freshShape === void 0 || !(0, import_tlschema.isShapeId)(freshShape.parentId)) return void 0;
4119
- return this.store.get(freshShape.parentId);
4134
+ return this.getShape(freshShape.parentId);
4120
4135
  }
4121
4136
  /**
4122
4137
  * If siblingShape and targetShape are siblings, this returns targetShape. If targetShape has an
@@ -4248,6 +4263,9 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4248
4263
  if (!pagePoint) continue;
4249
4264
  const newPoint = invertedParentTransform.applyToPoint(pagePoint);
4250
4265
  const newRotation = pageTransform.rotation() - parentPageRotation;
4266
+ if (shape.id === parentId) {
4267
+ throw Error("Attempted to reparent a shape to itself!");
4268
+ }
4251
4269
  changes.push({
4252
4270
  id: shape.id,
4253
4271
  type: shape.type,
@@ -4340,6 +4358,10 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4340
4358
  }
4341
4359
  return shapeIds;
4342
4360
  }
4361
+ /** @deprecated Use {@link Editor.getDraggingOverShape} instead */
4362
+ getDroppingOverShape(point, droppingShapes) {
4363
+ return this.getDraggingOverShape(point, droppingShapes);
4364
+ }
4343
4365
  /**
4344
4366
  * Get the shape that some shapes should be dropped on at a given point.
4345
4367
  *
@@ -4350,22 +4372,20 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4350
4372
  *
4351
4373
  * @public
4352
4374
  */
4353
- getDroppingOverShape(point, droppingShapes = []) {
4354
- const currentPageShapesSorted = this.getCurrentPageShapesSorted();
4355
- for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
4356
- const shape = currentPageShapesSorted[i];
4357
- if (
4358
- // ignore hidden shapes
4359
- this.isShapeHidden(shape) || // don't allow dropping on selected shapes
4360
- this.getSelectedShapeIds().includes(shape.id) || // only allow shapes that can receive children
4361
- !this.getShapeUtil(shape).canDropShapes(shape, droppingShapes) || // don't allow dropping a shape on itself or one of it's children
4362
- droppingShapes.find((s) => s.id === shape.id || this.hasAncestor(shape, s.id))
4363
- ) {
4364
- continue;
4365
- }
4366
- const maskedPageBounds = this.getShapeMaskedPageBounds(shape.id);
4367
- if (maskedPageBounds && maskedPageBounds.containsPoint(point) && this.getShapeGeometry(shape).hitTestPoint(this.getPointInShapeSpace(shape, point), 0, true)) {
4368
- return shape;
4375
+ getDraggingOverShape(point, droppingShapes) {
4376
+ const draggingShapes = (0, import_utils.compact)(droppingShapes.map((s) => this.getShape(s))).filter(
4377
+ (s) => !s.isLocked && !this.isShapeHidden(s)
4378
+ );
4379
+ const maybeDraggingOverShapes = this.getShapesAtPoint(point, {
4380
+ hitInside: true,
4381
+ margin: 0
4382
+ }).filter(
4383
+ (s) => !droppingShapes.includes(s) && !s.isLocked && !this.isShapeHidden(s) && !draggingShapes.includes(s)
4384
+ );
4385
+ for (const maybeDraggingOverShape of maybeDraggingOverShapes) {
4386
+ const shapeUtil = this.getShapeUtil(maybeDraggingOverShape);
4387
+ if (shapeUtil.onDragShapesOver || shapeUtil.onDragShapesIn || shapeUtil.onDragShapesOut || shapeUtil.onDropShapesOver) {
4388
+ return maybeDraggingOverShape;
4369
4389
  }
4370
4390
  }
4371
4391
  }
@@ -4642,7 +4662,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4642
4662
  */
4643
4663
  duplicateShapes(shapes, offset) {
4644
4664
  this.run(() => {
4645
- const ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4665
+ const _ids = typeof shapes[0] === "string" ? shapes : shapes.map((s) => s.id);
4666
+ const ids = this._shouldIgnoreShapeLock ? _ids : this._getUnlockedShapeIds(_ids);
4646
4667
  if (ids.length <= 0) return this;
4647
4668
  const initialIds = new Set(ids);
4648
4669
  const shapeIdSet = this.getShapeAndDescendantIds(ids);
@@ -4706,8 +4727,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4706
4727
  shape.index = index;
4707
4728
  });
4708
4729
  const shapesToCreate = shapesToCreateWithOriginals.map(({ shape }) => shape);
4709
- const maxShapesReached = shapesToCreate.length + this.getCurrentPageShapeIds().size > this.options.maxShapesPerPage;
4710
- if (maxShapesReached) {
4730
+ if (!this.canCreateShapes(shapesToCreate)) {
4711
4731
  alertMaxShapes(this);
4712
4732
  return;
4713
4733
  }
@@ -5722,6 +5742,26 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5722
5742
  getInitialMetaForShape(_shape) {
5723
5743
  return {};
5724
5744
  }
5745
+ /**
5746
+ * Get whether the provided shape can be created.
5747
+ *
5748
+ * @param shape - The shape or shape IDs to check.
5749
+ *
5750
+ * @public
5751
+ */
5752
+ canCreateShape(shape) {
5753
+ return this.canCreateShapes([shape]);
5754
+ }
5755
+ /**
5756
+ * Get whether the provided shapes can be created.
5757
+ *
5758
+ * @param shapes - The shapes or shape IDs to create.
5759
+ *
5760
+ * @public
5761
+ */
5762
+ canCreateShapes(shapes) {
5763
+ return shapes.length + this.getCurrentPageShapeIds().size <= this.options.maxShapesPerPage;
5764
+ }
5725
5765
  /**
5726
5766
  * Create a single shape.
5727
5767
  *
@@ -5775,7 +5815,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5775
5815
  let parentId = this.getFocusedGroupId();
5776
5816
  for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
5777
5817
  const parent = currentPageShapesSorted[i];
5778
- if (!this.isShapeHidden(parent) && this.getShapeUtil(parent).canReceiveNewChildrenOfType(parent, partial.type) && this.isPointInShape(
5818
+ const util = this.getShapeUtil(parent);
5819
+ if (util.canReceiveNewChildrenOfType(parent, partial.type) && !this.isShapeHidden(parent) && this.isPointInShape(
5779
5820
  parent,
5780
5821
  // If no parent is provided, then we can treat the
5781
5822
  // shape's provided x/y as being in the page's space.
@@ -5850,6 +5891,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5850
5891
  ...shape.meta
5851
5892
  };
5852
5893
  });
5894
+ this.emit("created-shapes", shapeRecordsToCreate);
5895
+ this.emit("edit");
5853
5896
  this.store.put(shapeRecordsToCreate);
5854
5897
  });
5855
5898
  return this;
@@ -6091,6 +6134,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6091
6134
  updated = this.getShapeUtil(shape).onBeforeUpdate?.(shape, updated) ?? updated;
6092
6135
  updates.push(updated);
6093
6136
  }
6137
+ this.emit("edited-shapes", updates);
6138
+ this.emit("edit");
6094
6139
  this.store.put(updates);
6095
6140
  });
6096
6141
  }
@@ -6112,6 +6157,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6112
6157
  allShapeIdsToDelete.add(childId);
6113
6158
  });
6114
6159
  }
6160
+ this.emit("deleted-shapes", [...allShapeIdsToDelete]);
6161
+ this.emit("edit");
6115
6162
  return this.run(() => this.store.remove([...allShapeIdsToDelete]));
6116
6163
  }
6117
6164
  deleteShape(_id) {
@@ -6455,6 +6502,14 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6455
6502
  async putExternalContent(info) {
6456
6503
  return this.externalContentHandlers[info.type]?.(info);
6457
6504
  }
6505
+ /**
6506
+ * Handle replacing external content.
6507
+ *
6508
+ * @param info - Info about the external content.
6509
+ */
6510
+ async replaceExternalContent(info) {
6511
+ return this.externalContentHandlers[info.type]?.(info);
6512
+ }
6458
6513
  /**
6459
6514
  * Get content that can be exported for the given shape ids.
6460
6515
  *
@@ -6872,7 +6927,9 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6872
6927
  previousScreenPoint,
6873
6928
  previousPagePoint,
6874
6929
  currentScreenPoint,
6875
- currentPagePoint
6930
+ currentPagePoint,
6931
+ originScreenPoint,
6932
+ originPagePoint
6876
6933
  } = this.inputs;
6877
6934
  const { screenBounds } = this.store.unsafeGetWithoutCapture(import_tlschema.TLINSTANCE_ID);
6878
6935
  const { x: cx, y: cy, z: cz } = (0, import_state.unsafe__withoutCapture)(() => this.getCamera());
@@ -6890,8 +6947,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6890
6947
  this.inputs.isPen = info.type === "pointer" && info.isPen;
6891
6948
  if (info.name === "pointer_down" || this.inputs.isPinching) {
6892
6949
  pointerVelocity.set(0, 0);
6893
- this.inputs.originScreenPoint.setTo(currentScreenPoint);
6894
- this.inputs.originPagePoint.setTo(currentPagePoint);
6950
+ originScreenPoint.setTo(currentScreenPoint);
6951
+ originPagePoint.setTo(currentPagePoint);
6895
6952
  }
6896
6953
  this.run(
6897
6954
  () => {