@tldraw/editor 3.13.0-canary.eb5f191f61ac → 3.13.0-canary.ee08fd8a3063

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 (146) hide show
  1. package/dist-cjs/index.d.ts +110 -100
  2. package/dist-cjs/index.js +7 -22
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/Shape.js +12 -8
  5. package/dist-cjs/lib/components/Shape.js.map +2 -2
  6. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +31 -8
  7. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js +17 -11
  9. package/dist-cjs/lib/components/default-components/DefaultShapeIndicator.js.map +2 -2
  10. package/dist-cjs/lib/editor/Editor.js +85 -24
  11. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  12. package/dist-cjs/lib/editor/managers/SnapManager/HandleSnaps.js.map +2 -2
  13. package/dist-cjs/lib/editor/managers/TextManager.js +10 -0
  14. package/dist-cjs/lib/editor/managers/TextManager.js.map +2 -2
  15. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +1 -1
  16. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  17. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +0 -3
  18. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  19. package/dist-cjs/lib/editor/shapes/shared/getPerfectDashProps.js.map +2 -2
  20. package/dist-cjs/lib/exports/getSvgJsx.js +12 -3
  21. package/dist-cjs/lib/exports/getSvgJsx.js.map +2 -2
  22. package/dist-cjs/lib/hooks/useEditorComponents.js +1 -2
  23. package/dist-cjs/lib/hooks/useEditorComponents.js.map +2 -2
  24. package/dist-cjs/lib/primitives/Box.js +16 -0
  25. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  26. package/dist-cjs/lib/primitives/Mat.js +1 -1
  27. package/dist-cjs/lib/primitives/Mat.js.map +2 -2
  28. package/dist-cjs/lib/primitives/Vec.js +20 -0
  29. package/dist-cjs/lib/primitives/Vec.js.map +2 -2
  30. package/dist-cjs/lib/primitives/geometry/Arc2d.js +2 -2
  31. package/dist-cjs/lib/primitives/geometry/Arc2d.js.map +2 -2
  32. package/dist-cjs/lib/primitives/geometry/Circle2d.js +1 -1
  33. package/dist-cjs/lib/primitives/geometry/Circle2d.js.map +2 -2
  34. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js +1 -1
  35. package/dist-cjs/lib/primitives/geometry/CubicBezier2d.js.map +2 -2
  36. package/dist-cjs/lib/primitives/geometry/CubicSpline2d.js.map +2 -2
  37. package/dist-cjs/lib/primitives/geometry/Edge2d.js +1 -1
  38. package/dist-cjs/lib/primitives/geometry/Edge2d.js.map +2 -2
  39. package/dist-cjs/lib/primitives/geometry/Ellipse2d.js.map +2 -2
  40. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +91 -20
  41. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  42. package/dist-cjs/lib/primitives/geometry/Group2d.js +55 -2
  43. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  44. package/dist-cjs/lib/primitives/geometry/Point2d.js.map +2 -2
  45. package/dist-cjs/lib/primitives/geometry/Polyline2d.js.map +2 -2
  46. package/dist-cjs/lib/primitives/geometry/Stadium2d.js.map +2 -2
  47. package/dist-cjs/lib/utils/areShapesContentEqual.js +25 -0
  48. package/dist-cjs/lib/utils/areShapesContentEqual.js.map +7 -0
  49. package/dist-cjs/lib/utils/debug-flags.js +5 -2
  50. package/dist-cjs/lib/utils/debug-flags.js.map +2 -2
  51. package/dist-cjs/lib/utils/nearestMultiple.js +34 -0
  52. package/dist-cjs/lib/utils/nearestMultiple.js.map +7 -0
  53. package/dist-cjs/version.js +3 -3
  54. package/dist-cjs/version.js.map +1 -1
  55. package/dist-esm/index.d.mts +110 -100
  56. package/dist-esm/index.mjs +9 -41
  57. package/dist-esm/index.mjs.map +2 -2
  58. package/dist-esm/lib/components/Shape.mjs +12 -8
  59. package/dist-esm/lib/components/Shape.mjs.map +2 -2
  60. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +31 -8
  61. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  62. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs +17 -11
  63. package/dist-esm/lib/components/default-components/DefaultShapeIndicator.mjs.map +2 -2
  64. package/dist-esm/lib/editor/Editor.mjs +85 -24
  65. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  66. package/dist-esm/lib/editor/managers/SnapManager/HandleSnaps.mjs.map +2 -2
  67. package/dist-esm/lib/editor/managers/TextManager.mjs +10 -0
  68. package/dist-esm/lib/editor/managers/TextManager.mjs.map +2 -2
  69. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +1 -1
  70. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  71. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +0 -3
  72. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  73. package/dist-esm/lib/editor/shapes/shared/getPerfectDashProps.mjs.map +2 -2
  74. package/dist-esm/lib/exports/getSvgJsx.mjs +12 -3
  75. package/dist-esm/lib/exports/getSvgJsx.mjs.map +2 -2
  76. package/dist-esm/lib/hooks/useEditorComponents.mjs +1 -4
  77. package/dist-esm/lib/hooks/useEditorComponents.mjs.map +2 -2
  78. package/dist-esm/lib/primitives/Box.mjs +16 -0
  79. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  80. package/dist-esm/lib/primitives/Mat.mjs +1 -1
  81. package/dist-esm/lib/primitives/Mat.mjs.map +2 -2
  82. package/dist-esm/lib/primitives/Vec.mjs +20 -0
  83. package/dist-esm/lib/primitives/Vec.mjs.map +2 -2
  84. package/dist-esm/lib/primitives/geometry/Arc2d.mjs +2 -2
  85. package/dist-esm/lib/primitives/geometry/Arc2d.mjs.map +2 -2
  86. package/dist-esm/lib/primitives/geometry/Circle2d.mjs +1 -1
  87. package/dist-esm/lib/primitives/geometry/Circle2d.mjs.map +2 -2
  88. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs +1 -1
  89. package/dist-esm/lib/primitives/geometry/CubicBezier2d.mjs.map +2 -2
  90. package/dist-esm/lib/primitives/geometry/CubicSpline2d.mjs.map +2 -2
  91. package/dist-esm/lib/primitives/geometry/Edge2d.mjs +1 -1
  92. package/dist-esm/lib/primitives/geometry/Edge2d.mjs.map +2 -2
  93. package/dist-esm/lib/primitives/geometry/Ellipse2d.mjs.map +2 -2
  94. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +92 -21
  95. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  96. package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -2
  97. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  98. package/dist-esm/lib/primitives/geometry/Point2d.mjs.map +2 -2
  99. package/dist-esm/lib/primitives/geometry/Polyline2d.mjs.map +2 -2
  100. package/dist-esm/lib/primitives/geometry/Stadium2d.mjs.map +2 -2
  101. package/dist-esm/lib/utils/areShapesContentEqual.mjs +5 -0
  102. package/dist-esm/lib/utils/areShapesContentEqual.mjs.map +7 -0
  103. package/dist-esm/lib/utils/debug-flags.mjs +5 -2
  104. package/dist-esm/lib/utils/debug-flags.mjs.map +2 -2
  105. package/dist-esm/lib/utils/nearestMultiple.mjs +14 -0
  106. package/dist-esm/lib/utils/nearestMultiple.mjs.map +7 -0
  107. package/dist-esm/version.mjs +3 -3
  108. package/dist-esm/version.mjs.map +1 -1
  109. package/editor.css +36 -4
  110. package/package.json +7 -7
  111. package/src/index.ts +16 -31
  112. package/src/lib/components/Shape.tsx +14 -10
  113. package/src/lib/components/default-components/DefaultCanvas.tsx +32 -8
  114. package/src/lib/components/default-components/DefaultShapeIndicator.tsx +17 -8
  115. package/src/lib/editor/Editor.test.ts +1 -1
  116. package/src/lib/editor/Editor.ts +96 -24
  117. package/src/lib/editor/managers/SnapManager/HandleSnaps.ts +0 -1
  118. package/src/lib/editor/managers/TextManager.ts +12 -0
  119. package/src/lib/editor/shapes/ShapeUtil.ts +23 -3
  120. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +0 -4
  121. package/src/lib/editor/shapes/shared/getPerfectDashProps.ts +9 -9
  122. package/src/lib/exports/getSvgJsx.tsx +16 -7
  123. package/src/lib/hooks/useEditorComponents.tsx +2 -5
  124. package/src/lib/primitives/Box.ts +20 -0
  125. package/src/lib/primitives/Mat.ts +5 -4
  126. package/src/lib/primitives/Vec.ts +23 -0
  127. package/src/lib/primitives/geometry/Arc2d.ts +5 -5
  128. package/src/lib/primitives/geometry/Circle2d.ts +4 -4
  129. package/src/lib/primitives/geometry/CubicBezier2d.ts +4 -4
  130. package/src/lib/primitives/geometry/CubicSpline2d.ts +3 -3
  131. package/src/lib/primitives/geometry/Edge2d.ts +3 -3
  132. package/src/lib/primitives/geometry/Ellipse2d.ts +3 -3
  133. package/src/lib/primitives/geometry/Geometry2d.test.ts +42 -0
  134. package/src/lib/primitives/geometry/Geometry2d.ts +123 -35
  135. package/src/lib/primitives/geometry/Group2d.ts +70 -7
  136. package/src/lib/primitives/geometry/Point2d.ts +2 -2
  137. package/src/lib/primitives/geometry/Polyline2d.ts +3 -3
  138. package/src/lib/primitives/geometry/Stadium2d.ts +3 -3
  139. package/src/lib/test/currentToolIdMask.test.ts +1 -1
  140. package/src/lib/test/user.test.ts +1 -1
  141. package/src/lib/utils/areShapesContentEqual.ts +4 -0
  142. package/src/lib/utils/debug-flags.ts +7 -2
  143. package/src/lib/utils/nearestMultiple.ts +13 -0
  144. package/src/lib/utils/sync/LocalIndexedDb.test.ts +1 -1
  145. package/src/lib/utils/sync/TLLocalSyncClient.test.ts +1 -1
  146. package/src/version.ts +3 -3
@@ -132,6 +132,7 @@ import { Group2d } from "../primitives/geometry/Group2d.mjs";
132
132
  import { intersectPolygonPolygon } from "../primitives/intersect.mjs";
133
133
  import { PI, approximately, areAnglesCompatible, clamp, pointInPolygon } from "../primitives/utils.mjs";
134
134
  import { SharedStyleMap } from "../utils/SharedStylesMap.mjs";
135
+ import { areShapesContentEqual } from "../utils/areShapesContentEqual.mjs";
135
136
  import { dataUrlToFile } from "../utils/assets.mjs";
136
137
  import { debugFlags } from "../utils/debug-flags.mjs";
137
138
  import {
@@ -457,7 +458,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
457
458
  ) : getShapeVisibility;
458
459
  this.options = { ...defaultTldrawOptions, ...options };
459
460
  this.store = store;
460
- this.disposables.add(this.store.dispose.bind(this.store));
461
461
  this.history = new HistoryManager({
462
462
  store,
463
463
  annotateError: (error) => {
@@ -869,6 +869,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
869
869
  dispose() {
870
870
  this.disposables.forEach((dispose) => dispose());
871
871
  this.disposables.clear();
872
+ this.store.dispose();
872
873
  this.isDisposed = true;
873
874
  }
874
875
  getShapeUtil(arg) {
@@ -1474,9 +1475,23 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1474
1475
  this.setSelectedShapes(this._getUnlockedShapeIds(ids));
1475
1476
  return this;
1476
1477
  }
1478
+ /**
1479
+ * Select the next shape in the reading order or in cardinal order.
1480
+ *
1481
+ * @example
1482
+ * ```ts
1483
+ * editor.selectAdjacentShape('next')
1484
+ * ```
1485
+ *
1486
+ * @public
1487
+ */
1477
1488
  selectAdjacentShape(direction) {
1478
- const readingOrderShapes = this.getCurrentPageShapesInReadingOrder();
1479
1489
  const selectedShapeIds = this.getSelectedShapeIds();
1490
+ const firstParentId = selectedShapeIds[0] ? this.getShape(selectedShapeIds[0])?.parentId : null;
1491
+ const isSelectedWithinContainer = firstParentId && selectedShapeIds.every((shapeId) => this.getShape(shapeId)?.parentId === firstParentId) && !isPageId(firstParentId);
1492
+ const readingOrderShapes = isSelectedWithinContainer ? this._getShapesInReadingOrder(
1493
+ this.getCurrentPageShapes().filter((shape2) => shape2.parentId === firstParentId)
1494
+ ) : this.getCurrentPageShapesInReadingOrder();
1480
1495
  const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
1481
1496
  let adjacentShapeId;
1482
1497
  if (direction === "next" || direction === "prev") {
@@ -1490,18 +1505,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1490
1505
  }
1491
1506
  const shape = this.getShape(adjacentShapeId);
1492
1507
  if (!shape) return;
1493
- this.setSelectedShapes([shape.id]);
1494
- this.zoomToSelectionIfOffscreen(256, {
1495
- animation: {
1496
- duration: this.options.animationMediumMs
1497
- },
1498
- inset: 0
1499
- });
1508
+ this._selectShapesAndZoom([shape.id]);
1500
1509
  }
1501
1510
  getCurrentPageShapesInReadingOrder() {
1511
+ const shapes = this.getCurrentPageShapes().filter((shape) => isPageId(shape.parentId));
1512
+ return this._getShapesInReadingOrder(shapes);
1513
+ }
1514
+ _getShapesInReadingOrder(shapes) {
1502
1515
  const SHALLOW_ANGLE = 20;
1503
1516
  const ROW_THRESHOLD = 100;
1504
- const shapes = this.getCurrentPageShapes();
1505
1517
  const tabbableShapes = shapes.filter((shape) => this.getShapeUtil(shape).canTabTo(shape));
1506
1518
  if (tabbableShapes.length <= 1) return tabbableShapes;
1507
1519
  const shapesWithCenters = tabbableShapes.map((shape) => ({
@@ -1599,6 +1611,31 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1599
1611
  });
1600
1612
  return lowestScoringShape.shape.id;
1601
1613
  }
1614
+ selectParentShape() {
1615
+ const selectedShape = this.getOnlySelectedShape();
1616
+ if (!selectedShape) return;
1617
+ const parentShape = this.getShape(selectedShape.parentId);
1618
+ if (!parentShape) return;
1619
+ this._selectShapesAndZoom([parentShape.id]);
1620
+ }
1621
+ selectFirstChildShape() {
1622
+ const selectedShapes = this.getSelectedShapes();
1623
+ if (!selectedShapes.length) return;
1624
+ const selectedShape = selectedShapes[0];
1625
+ const children = this.getSortedChildIdsForParent(selectedShape.id).map((id) => this.getShape(id)).filter((i) => i);
1626
+ const sortedChildren = this._getShapesInReadingOrder(children);
1627
+ if (sortedChildren.length === 0) return;
1628
+ this._selectShapesAndZoom([sortedChildren[0].id]);
1629
+ }
1630
+ _selectShapesAndZoom(ids) {
1631
+ this.setSelectedShapes(ids);
1632
+ this.zoomToSelectionIfOffscreen(256, {
1633
+ animation: {
1634
+ duration: this.options.animationMediumMs
1635
+ },
1636
+ inset: 0
1637
+ });
1638
+ }
1602
1639
  /**
1603
1640
  * Clear the selection.
1604
1641
  *
@@ -1771,13 +1808,21 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1771
1808
  setEditingShape(shape) {
1772
1809
  const id = typeof shape === "string" ? shape : shape?.id ?? null;
1773
1810
  this.setRichTextEditor(null);
1774
- if (id !== this.getEditingShapeId()) {
1811
+ const prevEditingShapeId = this.getEditingShapeId();
1812
+ if (id !== prevEditingShapeId) {
1775
1813
  if (id) {
1776
1814
  const shape2 = this.getShape(id);
1777
1815
  if (shape2 && this.getShapeUtil(shape2).canEdit(shape2)) {
1778
1816
  this.run(
1779
1817
  () => {
1780
1818
  this._updateCurrentPageState({ editingShapeId: id });
1819
+ if (prevEditingShapeId) {
1820
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1821
+ if (prevEditingShape) {
1822
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1823
+ }
1824
+ }
1825
+ this.getShapeUtil(shape2).onEditStart?.(shape2);
1781
1826
  },
1782
1827
  { history: "ignore" }
1783
1828
  );
@@ -1788,6 +1833,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1788
1833
  () => {
1789
1834
  this._updateCurrentPageState({ editingShapeId: null });
1790
1835
  this._currentRichTextEditor.set(null);
1836
+ if (prevEditingShapeId) {
1837
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1838
+ if (prevEditingShape) {
1839
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1840
+ }
1841
+ }
1791
1842
  },
1792
1843
  { history: "ignore" }
1793
1844
  );
@@ -3473,7 +3524,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3473
3524
  this.fonts.trackFontsForShape(shape2);
3474
3525
  return this.getShapeUtil(shape2).getGeometry(shape2, opts);
3475
3526
  },
3476
- { areRecordsEqual: (a, b) => a.props === b.props }
3527
+ { areRecordsEqual: areShapesContentEqual }
3477
3528
  );
3478
3529
  }
3479
3530
  return this._shapeGeometryCaches[context].get(
@@ -3516,9 +3567,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3516
3567
  );
3517
3568
  }
3518
3569
  _getShapeHandlesCache() {
3519
- return this.store.createComputedCache("handles", (shape) => {
3520
- return this.getShapeUtil(shape).getHandles?.(shape);
3521
- });
3570
+ return this.store.createComputedCache(
3571
+ "handles",
3572
+ (shape) => {
3573
+ return this.getShapeUtil(shape).getHandles?.(shape);
3574
+ },
3575
+ {
3576
+ areRecordsEqual: areShapesContentEqual
3577
+ }
3578
+ );
3522
3579
  }
3523
3580
  /**
3524
3581
  * Get the handles (if any) for a shape.
@@ -4402,9 +4459,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
4402
4459
  }
4403
4460
  _getBindingsIndexCache() {
4404
4461
  const index = bindingsIndex(this);
4405
- return this.store.createComputedCache("bindingsIndex", (shape) => {
4406
- return index.get().get(shape.id);
4407
- });
4462
+ return this.store.createComputedCache(
4463
+ "bindingsIndex",
4464
+ (shape) => {
4465
+ return index.get().get(shape.id);
4466
+ },
4467
+ // we can ignore the shape equality check here because the index is
4468
+ // computed incrementally based on what bindings are in the store
4469
+ { areRecordsEqual: () => true }
4470
+ );
4408
4471
  }
4409
4472
  /**
4410
4473
  * Get a binding from the store by its ID if it exists.
@@ -7479,7 +7542,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7479
7542
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7480
7543
  const { x: dx, y: dy, z: dz = 0 } = info.delta;
7481
7544
  let behavior = wheelBehavior;
7482
- if (inputs.ctrlKey) behavior = wheelBehavior === "pan" ? "zoom" : "pan";
7545
+ if (info.ctrlKey) behavior = wheelBehavior === "pan" ? "zoom" : "pan";
7483
7546
  switch (behavior) {
7484
7547
  case "zoom": {
7485
7548
  const { x, y } = this.inputs.currentScreenPoint;
@@ -7560,12 +7623,10 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7560
7623
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7561
7624
  if (this.inputs.isPanning && this.inputs.isPointing) {
7562
7625
  const { currentScreenPoint, previousScreenPoint } = this.inputs;
7563
- const { panSpeed } = cameraOptions;
7564
7626
  const offset = Vec.Sub(currentScreenPoint, previousScreenPoint);
7565
- this.setCamera(
7566
- new Vec(cx + offset.x * panSpeed / cz, cy + offset.y * panSpeed / cz, cz),
7567
- { immediate: true }
7568
- );
7627
+ this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
7628
+ immediate: true
7629
+ });
7569
7630
  this.maybeTrackPerformance("Panning");
7570
7631
  return;
7571
7632
  }