@tldraw/editor 3.15.3 → 3.16.0-canary.016d4c2889b7

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 (147) hide show
  1. package/dist-cjs/index.d.ts +180 -9
  2. package/dist-cjs/index.js +5 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +8 -2
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/MenuClickCapture.js +0 -5
  7. package/dist-cjs/lib/components/MenuClickCapture.js.map +2 -2
  8. package/dist-cjs/lib/components/Shape.js +11 -36
  9. package/dist-cjs/lib/components/Shape.js.map +2 -2
  10. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -23
  11. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  12. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js +1 -1
  13. package/dist-cjs/lib/components/default-components/DefaultCollaboratorHint.js.map +1 -1
  14. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js +1 -1
  15. package/dist-cjs/lib/components/default-components/DefaultErrorFallback.js.map +2 -2
  16. package/dist-cjs/lib/components/default-components/DefaultScribble.js +1 -1
  17. package/dist-cjs/lib/components/default-components/DefaultScribble.js.map +2 -2
  18. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +9 -1
  19. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  20. package/dist-cjs/lib/components/default-components/DefaultShapeWrapper.js +53 -0
  21. package/dist-cjs/lib/components/default-components/DefaultShapeWrapper.js.map +7 -0
  22. package/dist-cjs/lib/config/TLUserPreferences.js +9 -3
  23. package/dist-cjs/lib/config/TLUserPreferences.js.map +2 -2
  24. package/dist-cjs/lib/editor/Editor.js +138 -69
  25. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  26. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js +9 -4
  27. package/dist-cjs/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.js.map +2 -2
  28. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +13 -0
  29. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  30. package/dist-cjs/lib/editor/types/misc-types.js.map +1 -1
  31. package/dist-cjs/lib/exports/getSvgJsx.js +35 -16
  32. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  33. package/dist-cjs/lib/hooks/useCanvasEvents.js +31 -25
  34. package/dist-cjs/lib/hooks/useCanvasEvents.js.map +2 -2
  35. package/dist-cjs/lib/hooks/useEditorComponents.js +2 -0
  36. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  37. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js +4 -1
  38. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  39. package/dist-cjs/lib/{utils/nearestMultiple.js → hooks/useStateAttribute.js} +15 -14
  40. package/dist-cjs/lib/hooks/useStateAttribute.js.map +7 -0
  41. package/dist-cjs/lib/license/Watermark.js +6 -6
  42. package/dist-cjs/lib/license/Watermark.js.map +1 -1
  43. package/dist-cjs/lib/options.js +7 -0
  44. package/dist-cjs/lib/options.js.map +2 -2
  45. package/dist-cjs/lib/primitives/Box.js +3 -0
  46. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  47. package/dist-cjs/lib/utils/EditorAtom.js +45 -0
  48. package/dist-cjs/lib/utils/EditorAtom.js.map +7 -0
  49. package/dist-cjs/version.js +3 -3
  50. package/dist-cjs/version.js.map +1 -1
  51. package/dist-esm/index.d.mts +180 -9
  52. package/dist-esm/index.mjs +7 -1
  53. package/dist-esm/index.mjs.map +2 -2
  54. package/dist-esm/lib/TldrawEditor.mjs +8 -2
  55. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  56. package/dist-esm/lib/components/MenuClickCapture.mjs +0 -5
  57. package/dist-esm/lib/components/MenuClickCapture.mjs.map +2 -2
  58. package/dist-esm/lib/components/Shape.mjs +11 -36
  59. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  60. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +4 -23
  61. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  62. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs +1 -1
  63. package/dist-esm/lib/components/default-components/DefaultCollaboratorHint.mjs.map +1 -1
  64. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs +1 -1
  65. package/dist-esm/lib/components/default-components/DefaultErrorFallback.mjs.map +2 -2
  66. package/dist-esm/lib/components/default-components/DefaultScribble.mjs +1 -1
  67. package/dist-esm/lib/components/default-components/DefaultScribble.mjs.map +2 -2
  68. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +9 -1
  69. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  70. package/dist-esm/lib/components/default-components/DefaultShapeWrapper.mjs +23 -0
  71. package/dist-esm/lib/components/default-components/DefaultShapeWrapper.mjs.map +7 -0
  72. package/dist-esm/lib/config/TLUserPreferences.mjs +9 -3
  73. package/dist-esm/lib/config/TLUserPreferences.mjs.map +2 -2
  74. package/dist-esm/lib/editor/Editor.mjs +138 -69
  75. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  76. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs +9 -4
  77. package/dist-esm/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.mjs.map +2 -2
  78. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +13 -0
  79. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  80. package/dist-esm/lib/exports/getSvgJsx.mjs +36 -16
  81. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  82. package/dist-esm/lib/hooks/useCanvasEvents.mjs +32 -26
  83. package/dist-esm/lib/hooks/useCanvasEvents.mjs.map +2 -2
  84. package/dist-esm/lib/hooks/useEditorComponents.mjs +4 -0
  85. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  86. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs +4 -1
  87. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  88. package/dist-esm/lib/hooks/useStateAttribute.mjs +15 -0
  89. package/dist-esm/lib/hooks/useStateAttribute.mjs.map +7 -0
  90. package/dist-esm/lib/license/Watermark.mjs +6 -6
  91. package/dist-esm/lib/license/Watermark.mjs.map +1 -1
  92. package/dist-esm/lib/options.mjs +7 -0
  93. package/dist-esm/lib/options.mjs.map +2 -2
  94. package/dist-esm/lib/primitives/Box.mjs +4 -1
  95. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  96. package/dist-esm/lib/utils/EditorAtom.mjs +25 -0
  97. package/dist-esm/lib/utils/EditorAtom.mjs.map +7 -0
  98. package/dist-esm/version.mjs +3 -3
  99. package/dist-esm/version.mjs.map +1 -1
  100. package/editor.css +305 -311
  101. package/package.json +14 -37
  102. package/src/index.ts +7 -0
  103. package/src/lib/TldrawEditor.tsx +13 -6
  104. package/src/lib/components/MenuClickCapture.tsx +0 -8
  105. package/src/lib/components/Shape.tsx +12 -33
  106. package/src/lib/components/default-components/DefaultCanvas.tsx +5 -22
  107. package/src/lib/components/default-components/DefaultCollaboratorHint.tsx +1 -1
  108. package/src/lib/components/default-components/DefaultErrorFallback.tsx +1 -1
  109. package/src/lib/components/default-components/DefaultScribble.tsx +1 -1
  110. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +5 -1
  111. package/src/lib/components/default-components/DefaultShapeWrapper.tsx +35 -0
  112. package/src/lib/config/TLUserPreferences.ts +8 -1
  113. package/src/lib/editor/Editor.test.ts +12 -11
  114. package/src/lib/editor/Editor.ts +178 -103
  115. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +15 -14
  116. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +16 -15
  117. package/src/lib/editor/managers/FocusManager/FocusManager.test.ts +49 -48
  118. package/src/lib/editor/managers/FontManager/FontManager.test.ts +24 -23
  119. package/src/lib/editor/managers/HistoryManager/HistoryManager.test.ts +7 -6
  120. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +12 -11
  121. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +57 -50
  122. package/src/lib/editor/managers/TextManager/TextManager.test.ts +51 -26
  123. package/src/lib/editor/managers/TickManager/TickManager.test.ts +14 -13
  124. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.test.ts +34 -26
  125. package/src/lib/editor/managers/UserPreferencesManager/UserPreferencesManager.ts +6 -1
  126. package/src/lib/editor/shapes/ShapeUtil.ts +36 -0
  127. package/src/lib/editor/types/misc-types.ts +73 -1
  128. package/src/lib/exports/getSvgJsx.test.ts +868 -0
  129. package/src/lib/exports/getSvgJsx.tsx +78 -21
  130. package/src/lib/hooks/useCanvasEvents.ts +45 -38
  131. package/src/lib/hooks/useEditorComponents.tsx +7 -1
  132. package/src/lib/hooks/usePassThroughWheelEvents.ts +6 -1
  133. package/src/lib/hooks/useStateAttribute.ts +15 -0
  134. package/src/lib/license/LicenseManager.test.ts +3 -1
  135. package/src/lib/license/Watermark.test.tsx +2 -1
  136. package/src/lib/license/Watermark.tsx +6 -6
  137. package/src/lib/options.ts +8 -0
  138. package/src/lib/primitives/Box.test.ts +126 -0
  139. package/src/lib/primitives/Box.ts +10 -1
  140. package/src/lib/utils/EditorAtom.ts +37 -0
  141. package/src/lib/utils/sync/LocalIndexedDb.test.ts +2 -1
  142. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +15 -15
  143. package/src/version.ts +3 -3
  144. package/dist-cjs/lib/utils/nearestMultiple.js.map +0 -7
  145. package/dist-esm/lib/utils/nearestMultiple.mjs +0 -14
  146. package/dist-esm/lib/utils/nearestMultiple.mjs.map +0 -7
  147. package/src/lib/utils/nearestMultiple.ts +0 -13
@@ -2323,28 +2323,11 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
2323
2323
  { history: "ignore" }
2324
2324
  );
2325
2325
  const { currentScreenPoint, currentPagePoint } = this.inputs;
2326
- const { screenBounds } = this.store.unsafeGetWithoutCapture(import_tlschema.TLINSTANCE_ID);
2327
2326
  if (currentScreenPoint.x / z - x !== currentPagePoint.x || currentScreenPoint.y / z - y !== currentPagePoint.y) {
2328
- const event = {
2329
- type: "pointer",
2330
- target: "canvas",
2331
- name: "pointer_move",
2332
- // weird but true: we need to put the screen point back into client space
2333
- point: import_Vec.Vec.AddXY(currentScreenPoint, screenBounds.x, screenBounds.y),
2334
- pointerId: import_constants.INTERNAL_POINTER_IDS.CAMERA_MOVE,
2335
- ctrlKey: this.inputs.ctrlKey,
2336
- altKey: this.inputs.altKey,
2337
- shiftKey: this.inputs.shiftKey,
2338
- metaKey: this.inputs.metaKey,
2339
- accelKey: (0, import_keyboard.isAccelKey)(this.inputs),
2340
- button: 0,
2341
- isPen: this.getInstanceState().isPenMode ?? false
2342
- };
2343
- if (opts?.immediate) {
2344
- this._flushEventForTick(event);
2345
- } else {
2346
- this.dispatch(event);
2347
- }
2327
+ this.updatePointer({
2328
+ immediate: opts?.immediate,
2329
+ pointerId: import_constants.INTERNAL_POINTER_IDS.CAMERA_MOVE
2330
+ });
2348
2331
  }
2349
2332
  this._tickCameraState();
2350
2333
  });
@@ -3313,19 +3296,24 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3313
3296
  */
3314
3297
  deletePage(page) {
3315
3298
  const id = typeof page === "string" ? page : page.id;
3316
- this.run(() => {
3317
- if (this.getIsReadonly()) return;
3318
- const pages = this.getPages();
3319
- if (pages.length === 1) return;
3320
- const deletedPage = this.getPage(id);
3321
- if (!deletedPage) return;
3322
- if (id === this.getCurrentPageId()) {
3323
- const index = pages.findIndex((page2) => page2.id === id);
3324
- const next = pages[index - 1] ?? pages[index + 1];
3325
- this.setCurrentPage(next.id);
3326
- }
3327
- this.store.remove([deletedPage.id]);
3328
- });
3299
+ this.run(
3300
+ () => {
3301
+ if (this.getIsReadonly()) return;
3302
+ const pages = this.getPages();
3303
+ if (pages.length === 1) return;
3304
+ const deletedPage = this.getPage(id);
3305
+ if (!deletedPage) return;
3306
+ if (id === this.getCurrentPageId()) {
3307
+ const index = pages.findIndex((page2) => page2.id === id);
3308
+ const next = pages[index - 1] ?? pages[index + 1];
3309
+ this.setCurrentPage(next.id);
3310
+ }
3311
+ const shapes = this.getSortedChildIdsForParent(deletedPage.id);
3312
+ this.deleteShapes(shapes);
3313
+ this.store.remove([deletedPage.id]);
3314
+ },
3315
+ { ignoreShapeLock: true }
3316
+ );
3329
3317
  return this;
3330
3318
  }
3331
3319
  /**
@@ -3678,16 +3666,17 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3678
3666
  _getShapeMaskCache() {
3679
3667
  return this.store.createComputedCache("pageMaskCache", (shape) => {
3680
3668
  if ((0, import_tlschema.isPageId)(shape.parentId)) return void 0;
3681
- const frameAncestors = this.getShapeAncestors(shape.id).filter(
3682
- (shape2) => this.isShapeOfType(shape2, "frame")
3683
- );
3684
- if (frameAncestors.length === 0) return void 0;
3685
- const pageMask = frameAncestors.map((s) => {
3686
- const geometry = this.getShapeGeometry(s.id);
3687
- const pageTransform = this.getShapePageTransform(s.id);
3688
- return pageTransform.applyToPoints(geometry.vertices);
3689
- }).reduce((acc, b) => {
3690
- if (!(b && acc)) return void 0;
3669
+ const clipPaths = [];
3670
+ for (const ancestor of this.getShapeAncestors(shape.id)) {
3671
+ const util = this.getShapeUtil(ancestor);
3672
+ const clipPath = util.getClipPath?.(ancestor);
3673
+ if (!clipPath) continue;
3674
+ if (util.shouldClipChild?.(shape) === false) continue;
3675
+ const pageTransform = this.getShapePageTransform(ancestor.id);
3676
+ clipPaths.push(pageTransform.applyToPoints(clipPath));
3677
+ }
3678
+ if (clipPaths.length === 0) return void 0;
3679
+ const pageMask = clipPaths.reduce((acc, b) => {
3691
3680
  const intersection = (0, import_intersect.intersectPolygonPolygon)(acc, b);
3692
3681
  if (intersection) {
3693
3682
  return intersection.map(import_Vec.Vec.Cast);
@@ -3922,6 +3911,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3922
3911
  hitInside = false,
3923
3912
  hitFrameInside = false
3924
3913
  } = opts;
3914
+ const [innerMargin, outerMargin] = Array.isArray(margin) ? margin : [margin, margin];
3925
3915
  let inHollowSmallestArea = Infinity;
3926
3916
  let inHollowSmallestAreaHit = null;
3927
3917
  let inMarginClosestToEdgeDistance = Infinity;
@@ -3931,7 +3921,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3931
3921
  return false;
3932
3922
  const pageMask = this.getShapeMask(shape);
3933
3923
  if (pageMask && !(0, import_utils2.pointInPolygon)(point, pageMask)) return false;
3934
- if (filter) return filter(shape);
3924
+ if (filter && !filter(shape)) return false;
3935
3925
  return true;
3936
3926
  });
3937
3927
  for (let i = shapesToCheck.length - 1; i >= 0; i--) {
@@ -3939,7 +3929,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3939
3929
  const geometry = this.getShapeGeometry(shape);
3940
3930
  const isGroup = geometry instanceof import_Group2d.Group2d;
3941
3931
  const pointInShapeSpace = this.getPointInShapeSpace(shape, point);
3942
- if (this.isShapeOfType(shape, "frame") || this.isShapeOfType(shape, "arrow") && shape.props.text.trim() || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && this.getShapeUtil(shape).getText(shape)?.trim()) {
3932
+ if (this.isShapeOfType(shape, "frame") || (this.isShapeOfType(shape, "note") || this.isShapeOfType(shape, "arrow") || this.isShapeOfType(shape, "geo") && shape.props.fill === "none") && this.getShapeUtil(shape).getText(shape)?.trim()) {
3943
3933
  for (const childGeometry of geometry.children) {
3944
3934
  if (childGeometry.isLabel && childGeometry.isPointInBounds(pointInShapeSpace)) {
3945
3935
  return shape;
@@ -3947,8 +3937,8 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3947
3937
  }
3948
3938
  }
3949
3939
  if (this.isShapeOfType(shape, "frame")) {
3950
- const distance2 = geometry.distanceToPoint(pointInShapeSpace, hitInside);
3951
- if (Math.abs(distance2) <= margin) {
3940
+ const distance2 = geometry.distanceToPoint(pointInShapeSpace, hitFrameInside);
3941
+ if (hitFrameInside ? distance2 > 0 && distance2 <= outerMargin || distance2 <= 0 && distance2 > -innerMargin : distance2 > 0 && distance2 <= outerMargin) {
3952
3942
  return inMarginClosestToEdgeHit || shape;
3953
3943
  }
3954
3944
  if (geometry.hitTestPoint(pointInShapeSpace, 0, true)) {
@@ -3968,10 +3958,10 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3968
3958
  }
3969
3959
  distance = minDistance;
3970
3960
  } else {
3971
- if (margin === 0 && (geometry.bounds.w < 1 || geometry.bounds.h < 1)) {
3961
+ if (outerMargin === 0 && (geometry.bounds.w < 1 || geometry.bounds.h < 1)) {
3972
3962
  distance = geometry.distanceToPoint(pointInShapeSpace, hitInside);
3973
3963
  } else {
3974
- if (geometry.bounds.containsPoint(pointInShapeSpace, margin)) {
3964
+ if (geometry.bounds.containsPoint(pointInShapeSpace, outerMargin)) {
3975
3965
  distance = geometry.distanceToPoint(pointInShapeSpace, hitInside);
3976
3966
  } else {
3977
3967
  distance = Infinity;
@@ -3979,12 +3969,22 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
3979
3969
  }
3980
3970
  }
3981
3971
  if (geometry.isClosed) {
3982
- if (distance <= margin) {
3972
+ if (distance <= outerMargin || hitInside && distance <= 0 && distance > -innerMargin) {
3983
3973
  if (geometry.isFilled || isGroup && geometry.children[0].isFilled) {
3984
3974
  return inMarginClosestToEdgeHit || shape;
3985
3975
  } else {
3986
3976
  if (this.getShapePageBounds(shape).contains(viewportPageBounds)) continue;
3987
- if (Math.abs(distance) < margin) {
3977
+ if (hitInside ? (
3978
+ // On hitInside, the distance will be negative for hits inside
3979
+ // If the distance is positive, check against the outer margin
3980
+ distance > 0 && distance <= outerMargin || // If the distance is negative, check against the inner margin
3981
+ distance <= 0 && distance > -innerMargin
3982
+ ) : (
3983
+ // If hitInside is false, then sadly _we do not know_ whether the
3984
+ // point is inside or outside of the shape, so we check against
3985
+ // the max of the two margins
3986
+ Math.abs(distance) <= Math.max(innerMargin, outerMargin)
3987
+ )) {
3988
3988
  if (Math.abs(distance) < inMarginClosestToEdgeDistance) {
3989
3989
  inMarginClosestToEdgeDistance = Math.abs(distance);
3990
3990
  inMarginClosestToEdgeHit = shape;
@@ -4749,7 +4749,16 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
4749
4749
  }
4750
4750
  this.createShapes(shapesToCreate);
4751
4751
  this.createBindings(bindingsToCreate);
4752
- this.setSelectedShapes((0, import_utils.compact)(ids.map((id) => shapeIds.get(id))));
4752
+ this.setSelectedShapes(
4753
+ (0, import_utils.compact)(
4754
+ ids.map((oldId) => {
4755
+ const newId = shapeIds.get(oldId);
4756
+ if (!newId) return null;
4757
+ if (!this.getShape(newId)) return null;
4758
+ return newId;
4759
+ })
4760
+ )
4761
+ );
4753
4762
  if (offset !== void 0) {
4754
4763
  const selectionPageBounds = this.getSelectionPageBounds();
4755
4764
  const viewportPageBounds = this.getViewportPageBounds();
@@ -5503,8 +5512,7 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5503
5512
  const shapesMovingTogether = [shape];
5504
5513
  const boundsOfShapesMovingTogether = [shapePageBounds];
5505
5514
  if (!this.getShapeUtil(shape).canBeLaidOut?.(shape, {
5506
- type: "stretch",
5507
- shapes: shapesToStretchFirstPass
5515
+ type: "stretch"
5508
5516
  })) {
5509
5517
  continue;
5510
5518
  }
@@ -5829,21 +5837,24 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
5829
5837
  }
5830
5838
  if (!partial.parentId || !(this.store.has(partial.parentId) || shapes.some((p) => p.id === partial.parentId))) {
5831
5839
  let parentId = this.getFocusedGroupId();
5832
- for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
5833
- const parent = currentPageShapesSorted[i];
5834
- const util = this.getShapeUtil(parent);
5835
- if (util.canReceiveNewChildrenOfType(parent, partial.type) && !this.isShapeHidden(parent) && this.isPointInShape(
5836
- parent,
5837
- // If no parent is provided, then we can treat the
5838
- // shape's provided x/y as being in the page's space.
5839
- { x: partial.x ?? 0, y: partial.y ?? 0 },
5840
- {
5841
- margin: 0,
5842
- hitInside: true
5840
+ const isPositioned = partial.x !== void 0 && partial.y !== void 0;
5841
+ if (isPositioned) {
5842
+ for (let i = currentPageShapesSorted.length - 1; i >= 0; i--) {
5843
+ const parent = currentPageShapesSorted[i];
5844
+ const util = this.getShapeUtil(parent);
5845
+ if (util.canReceiveNewChildrenOfType(parent, partial.type) && !this.isShapeHidden(parent) && this.isPointInShape(
5846
+ parent,
5847
+ // If no parent is provided, then we can treat the
5848
+ // shape's provided x/y as being in the page's space.
5849
+ { x: partial.x ?? 0, y: partial.y ?? 0 },
5850
+ {
5851
+ margin: 0,
5852
+ hitInside: true
5853
+ }
5854
+ )) {
5855
+ parentId = parent.id;
5856
+ break;
5843
5857
  }
5844
- )) {
5845
- parentId = parent.id;
5846
- break;
5847
5858
  }
5848
5859
  }
5849
5860
  const prevParentId = partial.parentId;
@@ -6932,6 +6943,23 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
6932
6943
  }
6933
6944
  }
6934
6945
  }
6946
+ /**
6947
+ * Get an exported image of the given shapes as a data URL.
6948
+ *
6949
+ * @param shapes - The shapes (or shape ids) to export.
6950
+ * @param opts - Options for the export.
6951
+ *
6952
+ * @returns A data URL of the image.
6953
+ * @public
6954
+ */
6955
+ async toImageDataUrl(shapes, opts = {}) {
6956
+ const { blob, width, height } = await this.toImage(shapes, opts);
6957
+ return {
6958
+ url: await import_utils.FileHelpers.blobToDataUrl(blob),
6959
+ width,
6960
+ height
6961
+ };
6962
+ }
6935
6963
  /**
6936
6964
  * Update the input points from a pointer, pinch, or wheel event.
6937
6965
  *
@@ -7028,6 +7056,47 @@ class Editor extends (_a = import_eventemitter3.default, _getIsShapeHiddenCache_
7028
7056
  this.dispatch({ type: "misc", name: "complete" });
7029
7057
  return this;
7030
7058
  }
7059
+ /**
7060
+ * Dispatch a pointer move event in the current position of the pointer. This is useful when
7061
+ * external circumstances have changed (e.g. the camera moved or a shape was moved) and you want
7062
+ * the current interaction to respond to that change.
7063
+ *
7064
+ * @example
7065
+ * ```ts
7066
+ * editor.updatePointer()
7067
+ * ```
7068
+ *
7069
+ * @param options - The options for updating the pointer.
7070
+ * @returns The editor instance.
7071
+ * @public
7072
+ */
7073
+ updatePointer(options) {
7074
+ const event = {
7075
+ type: "pointer",
7076
+ target: "canvas",
7077
+ name: "pointer_move",
7078
+ point: options?.point ?? // weird but true: what `inputs` calls screen-space is actually viewport space. so
7079
+ // we need to convert back into true screen space first. we should fix this...
7080
+ import_Vec.Vec.Add(
7081
+ this.inputs.currentScreenPoint,
7082
+ this.store.unsafeGetWithoutCapture(import_tlschema.TLINSTANCE_ID).screenBounds
7083
+ ),
7084
+ pointerId: options?.pointerId ?? 0,
7085
+ button: options?.button ?? 0,
7086
+ isPen: options?.isPen ?? this.inputs.isPen,
7087
+ shiftKey: options?.shiftKey ?? this.inputs.shiftKey,
7088
+ altKey: options?.altKey ?? this.inputs.altKey,
7089
+ ctrlKey: options?.ctrlKey ?? this.inputs.ctrlKey,
7090
+ metaKey: options?.metaKey ?? this.inputs.metaKey,
7091
+ accelKey: options?.accelKey ?? (0, import_keyboard.isAccelKey)(this.inputs)
7092
+ };
7093
+ if (options?.immediate) {
7094
+ this._flushEventForTick(event);
7095
+ } else {
7096
+ this.dispatch(event);
7097
+ }
7098
+ return this;
7099
+ }
7031
7100
  /**
7032
7101
  * Puts the editor into focused mode.
7033
7102
  *