@tldraw/editor 3.12.0-canary.e333011facbe → 3.12.0-canary.f5c40cbda19f

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 (80) hide show
  1. package/dist-cjs/index.d.ts +113 -12
  2. package/dist-cjs/index.js +3 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/TldrawEditor.js +1 -0
  5. package/dist-cjs/lib/TldrawEditor.js.map +2 -2
  6. package/dist-cjs/lib/components/GeometryDebuggingView.js +2 -2
  7. package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +10 -1
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/editor/Editor.js +184 -10
  11. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  12. package/dist-cjs/lib/editor/managers/FocusManager.js +1 -1
  13. package/dist-cjs/lib/editor/managers/FocusManager.js.map +2 -2
  14. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +12 -0
  15. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js +4 -13
  17. package/dist-cjs/lib/editor/shapes/group/GroupShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/editor/types/selection-types.js.map +1 -1
  19. package/dist-cjs/lib/hooks/useDocumentEvents.js +16 -0
  20. package/dist-cjs/lib/hooks/useDocumentEvents.js.map +2 -2
  21. package/dist-cjs/lib/license/Watermark.js +10 -20
  22. package/dist-cjs/lib/license/Watermark.js.map +2 -2
  23. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +133 -16
  24. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +3 -3
  25. package/dist-cjs/lib/primitives/geometry/Group2d.js +54 -11
  26. package/dist-cjs/lib/primitives/geometry/Group2d.js.map +2 -2
  27. package/dist-cjs/lib/primitives/intersect.js +20 -0
  28. package/dist-cjs/lib/primitives/intersect.js.map +2 -2
  29. package/dist-cjs/lib/utils/reorderShapes.js +2 -8
  30. package/dist-cjs/lib/utils/reorderShapes.js.map +2 -2
  31. package/dist-cjs/version.js +3 -3
  32. package/dist-cjs/version.js.map +1 -1
  33. package/dist-esm/index.d.mts +113 -12
  34. package/dist-esm/index.mjs +8 -2
  35. package/dist-esm/index.mjs.map +2 -2
  36. package/dist-esm/lib/TldrawEditor.mjs +1 -0
  37. package/dist-esm/lib/TldrawEditor.mjs.map +2 -2
  38. package/dist-esm/lib/components/GeometryDebuggingView.mjs +3 -3
  39. package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
  40. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +10 -1
  41. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  42. package/dist-esm/lib/editor/Editor.mjs +185 -10
  43. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  44. package/dist-esm/lib/editor/managers/FocusManager.mjs +1 -1
  45. package/dist-esm/lib/editor/managers/FocusManager.mjs.map +2 -2
  46. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +12 -0
  47. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  48. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs +4 -13
  49. package/dist-esm/lib/editor/shapes/group/GroupShapeUtil.mjs.map +2 -2
  50. package/dist-esm/lib/hooks/useDocumentEvents.mjs +16 -0
  51. package/dist-esm/lib/hooks/useDocumentEvents.mjs.map +2 -2
  52. package/dist-esm/lib/license/Watermark.mjs +10 -20
  53. package/dist-esm/lib/license/Watermark.mjs.map +2 -2
  54. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +137 -14
  55. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  56. package/dist-esm/lib/primitives/geometry/Group2d.mjs +55 -12
  57. package/dist-esm/lib/primitives/geometry/Group2d.mjs.map +2 -2
  58. package/dist-esm/lib/primitives/intersect.mjs +20 -0
  59. package/dist-esm/lib/primitives/intersect.mjs.map +2 -2
  60. package/dist-esm/lib/utils/reorderShapes.mjs +2 -8
  61. package/dist-esm/lib/utils/reorderShapes.mjs.map +2 -2
  62. package/dist-esm/version.mjs +3 -3
  63. package/dist-esm/version.mjs.map +1 -1
  64. package/package.json +7 -7
  65. package/src/index.ts +11 -2
  66. package/src/lib/TldrawEditor.tsx +1 -0
  67. package/src/lib/components/GeometryDebuggingView.tsx +3 -3
  68. package/src/lib/components/default-components/DefaultCanvas.tsx +6 -1
  69. package/src/lib/editor/Editor.ts +263 -16
  70. package/src/lib/editor/managers/FocusManager.ts +1 -1
  71. package/src/lib/editor/shapes/ShapeUtil.ts +14 -0
  72. package/src/lib/editor/shapes/group/GroupShapeUtil.tsx +7 -15
  73. package/src/lib/editor/types/selection-types.ts +3 -0
  74. package/src/lib/hooks/useDocumentEvents.ts +18 -0
  75. package/src/lib/license/Watermark.tsx +18 -29
  76. package/src/lib/primitives/geometry/Geometry2d.ts +196 -16
  77. package/src/lib/primitives/geometry/Group2d.ts +76 -13
  78. package/src/lib/primitives/intersect.ts +41 -0
  79. package/src/lib/utils/reorderShapes.ts +2 -9
  80. package/src/version.ts +3 -3
@@ -46,7 +46,7 @@ var __privateIn = (member, obj) => Object(obj) !== obj ? __typeError('Cannot use
46
46
  var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
47
47
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
48
48
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
49
- var __setMetaKeyTimeout_dec, __setCtrlKeyTimeout_dec, __setAltKeyTimeout_dec, __setShiftKeyTimeout_dec, _getIsReadonly_dec, _getIsFocused_dec, _getSharedOpacity_dec, _getSharedStyles_dec, __getSelectionSharedStyles_dec, __getBindingsIndexCache_dec, _getCurrentPageRenderingShapesSorted_dec, _getCurrentPageShapesSorted_dec, _getCurrentPageShapes_dec, _getCurrentPageBounds_dec, _getCulledShapes_dec, __notVisibleShapes_dec, __getShapeMaskedPageBoundsCache_dec, __getShapeMaskCache_dec, __getShapeClipPathCache_dec, __getShapePageBoundsCache_dec, __getShapePageTransformCache_dec, __getShapeHandlesCache_dec, __getAllAssetsQuery_dec, _getCurrentPageShapeIdsSorted_dec, _getCurrentPageId_dec, _getPages_dec, __getAllPagesQuery_dec, _getRenderingShapes_dec, _getCollaboratorsOnCurrentPage_dec, _getCollaborators_dec, __getCollaboratorsQuery_dec, _getViewportPageBounds_dec, _getViewportScreenCenter_dec, _getViewportScreenBounds_dec, _getZoomLevel_dec, _getCameraForFollowing_dec, _getViewportPageBoundsForFollowing_dec, _getCamera_dec, __unsafe_getCameraId_dec, _getErasingShapes_dec, _getErasingShapeIds_dec, _getHintingShape_dec, _getHintingShapeIds_dec, _getHoveredShape_dec, _getHoveredShapeId_dec, _getRichTextEditor_dec, _getEditingShape_dec, _getEditingShapeId_dec, _getFocusedGroup_dec, _getFocusedGroupId_dec, _getSelectionRotatedScreenBounds_dec, _getSelectionRotatedPageBounds_dec, _getSelectionRotation_dec, _getSelectionPageBounds_dec, _getOnlySelectedShape_dec, _getOnlySelectedShapeId_dec, _getSelectedShapes_dec, _getSelectedShapeIds_dec, __getCurrentPageStateId_dec, _getCurrentPageState_dec, __getPageStatesQuery_dec, _getPageStates_dec, _getIsMenuOpen_dec, _getOpenMenus_dec, _getInstanceState_dec, _getDocumentSettings_dec, _getCurrentToolId_dec, _getCurrentTool_dec, _getPath_dec, _getCanRedo_dec, _getCanUndo_dec, _getIsShapeHiddenCache_dec, _a, _init;
49
+ var __setMetaKeyTimeout_dec, __setCtrlKeyTimeout_dec, __setAltKeyTimeout_dec, __setShiftKeyTimeout_dec, _getIsReadonly_dec, _getIsFocused_dec, _getSharedOpacity_dec, _getSharedStyles_dec, __getSelectionSharedStyles_dec, __getBindingsIndexCache_dec, _getCurrentPageRenderingShapesSorted_dec, _getCurrentPageShapesSorted_dec, _getCurrentPageShapes_dec, _getCurrentPageBounds_dec, _getCulledShapes_dec, __notVisibleShapes_dec, __getShapeMaskedPageBoundsCache_dec, __getShapeMaskCache_dec, __getShapeClipPathCache_dec, __getShapePageBoundsCache_dec, __getShapePageTransformCache_dec, __getShapeHandlesCache_dec, __getAllAssetsQuery_dec, _getCurrentPageShapeIdsSorted_dec, _getCurrentPageId_dec, _getPages_dec, __getAllPagesQuery_dec, _getRenderingShapes_dec, _getCollaboratorsOnCurrentPage_dec, _getCollaborators_dec, __getCollaboratorsQuery_dec, _getViewportPageBounds_dec, _getViewportScreenCenter_dec, _getViewportScreenBounds_dec, _getZoomLevel_dec, _getCameraForFollowing_dec, _getViewportPageBoundsForFollowing_dec, _getCamera_dec, __unsafe_getCameraId_dec, _getErasingShapes_dec, _getErasingShapeIds_dec, _getHintingShape_dec, _getHintingShapeIds_dec, _getHoveredShape_dec, _getHoveredShapeId_dec, _getRichTextEditor_dec, _getEditingShape_dec, _getEditingShapeId_dec, _getFocusedGroup_dec, _getFocusedGroupId_dec, _getSelectionRotatedScreenBounds_dec, _getSelectionRotatedPageBounds_dec, _getSelectionRotation_dec, _getSelectionPageBounds_dec, _getOnlySelectedShape_dec, _getOnlySelectedShapeId_dec, _getCurrentPageShapesInReadingOrder_dec, _getSelectedShapes_dec, _getSelectedShapeIds_dec, __getCurrentPageStateId_dec, _getCurrentPageState_dec, __getPageStatesQuery_dec, _getPageStates_dec, _getIsMenuOpen_dec, _getOpenMenus_dec, _getInstanceState_dec, _getDocumentSettings_dec, _getCurrentToolId_dec, _getCurrentTool_dec, _getPath_dec, _getCanRedo_dec, _getCanUndo_dec, _getIsShapeHiddenCache_dec, _a, _init;
50
50
  import {
51
51
  EMPTY_ARRAY,
52
52
  atom,
@@ -94,6 +94,7 @@ import {
94
94
  last,
95
95
  lerp,
96
96
  maxBy,
97
+ minBy,
97
98
  sortById,
98
99
  sortByIndex,
99
100
  structuredClone,
@@ -156,7 +157,7 @@ import { TextManager } from "./managers/TextManager.mjs";
156
157
  import { TickManager } from "./managers/TickManager.mjs";
157
158
  import { UserPreferencesManager } from "./managers/UserPreferencesManager.mjs";
158
159
  import { RootState } from "./tools/RootState.mjs";
159
- class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed], _getCanUndo_dec = [computed], _getCanRedo_dec = [computed], _getPath_dec = [computed], _getCurrentTool_dec = [computed], _getCurrentToolId_dec = [computed], _getDocumentSettings_dec = [computed], _getInstanceState_dec = [computed], _getOpenMenus_dec = [computed], _getIsMenuOpen_dec = [computed], _getPageStates_dec = [computed], __getPageStatesQuery_dec = [computed], _getCurrentPageState_dec = [computed], __getCurrentPageStateId_dec = [computed], _getSelectedShapeIds_dec = [computed], _getSelectedShapes_dec = [computed], _getOnlySelectedShapeId_dec = [computed], _getOnlySelectedShape_dec = [computed], _getSelectionPageBounds_dec = [computed], _getSelectionRotation_dec = [computed], _getSelectionRotatedPageBounds_dec = [computed], _getSelectionRotatedScreenBounds_dec = [computed], _getFocusedGroupId_dec = [computed], _getFocusedGroup_dec = [computed], _getEditingShapeId_dec = [computed], _getEditingShape_dec = [computed], _getRichTextEditor_dec = [computed], _getHoveredShapeId_dec = [computed], _getHoveredShape_dec = [computed], _getHintingShapeIds_dec = [computed], _getHintingShape_dec = [computed], _getErasingShapeIds_dec = [computed], _getErasingShapes_dec = [computed], __unsafe_getCameraId_dec = [computed], _getCamera_dec = [computed], _getViewportPageBoundsForFollowing_dec = [computed], _getCameraForFollowing_dec = [computed], _getZoomLevel_dec = [computed], _getViewportScreenBounds_dec = [computed], _getViewportScreenCenter_dec = [computed], _getViewportPageBounds_dec = [computed], __getCollaboratorsQuery_dec = [computed], _getCollaborators_dec = [computed], _getCollaboratorsOnCurrentPage_dec = [computed], _getRenderingShapes_dec = [computed], __getAllPagesQuery_dec = [computed], _getPages_dec = [computed], _getCurrentPageId_dec = [computed], _getCurrentPageShapeIdsSorted_dec = [computed], __getAllAssetsQuery_dec = [computed], __getShapeHandlesCache_dec = [computed], __getShapePageTransformCache_dec = [computed], __getShapePageBoundsCache_dec = [computed], __getShapeClipPathCache_dec = [computed], __getShapeMaskCache_dec = [computed], __getShapeMaskedPageBoundsCache_dec = [computed], __notVisibleShapes_dec = [computed], _getCulledShapes_dec = [computed], _getCurrentPageBounds_dec = [computed], _getCurrentPageShapes_dec = [computed], _getCurrentPageShapesSorted_dec = [computed], _getCurrentPageRenderingShapesSorted_dec = [computed], __getBindingsIndexCache_dec = [computed], __getSelectionSharedStyles_dec = [computed], _getSharedStyles_dec = [computed({ isEqual: (a, b) => a.equals(b) })], _getSharedOpacity_dec = [computed], _getIsFocused_dec = [computed], _getIsReadonly_dec = [computed], __setShiftKeyTimeout_dec = [bind], __setAltKeyTimeout_dec = [bind], __setCtrlKeyTimeout_dec = [bind], __setMetaKeyTimeout_dec = [bind], _a) {
160
+ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed], _getCanUndo_dec = [computed], _getCanRedo_dec = [computed], _getPath_dec = [computed], _getCurrentTool_dec = [computed], _getCurrentToolId_dec = [computed], _getDocumentSettings_dec = [computed], _getInstanceState_dec = [computed], _getOpenMenus_dec = [computed], _getIsMenuOpen_dec = [computed], _getPageStates_dec = [computed], __getPageStatesQuery_dec = [computed], _getCurrentPageState_dec = [computed], __getCurrentPageStateId_dec = [computed], _getSelectedShapeIds_dec = [computed], _getSelectedShapes_dec = [computed], _getCurrentPageShapesInReadingOrder_dec = [computed], _getOnlySelectedShapeId_dec = [computed], _getOnlySelectedShape_dec = [computed], _getSelectionPageBounds_dec = [computed], _getSelectionRotation_dec = [computed], _getSelectionRotatedPageBounds_dec = [computed], _getSelectionRotatedScreenBounds_dec = [computed], _getFocusedGroupId_dec = [computed], _getFocusedGroup_dec = [computed], _getEditingShapeId_dec = [computed], _getEditingShape_dec = [computed], _getRichTextEditor_dec = [computed], _getHoveredShapeId_dec = [computed], _getHoveredShape_dec = [computed], _getHintingShapeIds_dec = [computed], _getHintingShape_dec = [computed], _getErasingShapeIds_dec = [computed], _getErasingShapes_dec = [computed], __unsafe_getCameraId_dec = [computed], _getCamera_dec = [computed], _getViewportPageBoundsForFollowing_dec = [computed], _getCameraForFollowing_dec = [computed], _getZoomLevel_dec = [computed], _getViewportScreenBounds_dec = [computed], _getViewportScreenCenter_dec = [computed], _getViewportPageBounds_dec = [computed], __getCollaboratorsQuery_dec = [computed], _getCollaborators_dec = [computed], _getCollaboratorsOnCurrentPage_dec = [computed], _getRenderingShapes_dec = [computed], __getAllPagesQuery_dec = [computed], _getPages_dec = [computed], _getCurrentPageId_dec = [computed], _getCurrentPageShapeIdsSorted_dec = [computed], __getAllAssetsQuery_dec = [computed], __getShapeHandlesCache_dec = [computed], __getShapePageTransformCache_dec = [computed], __getShapePageBoundsCache_dec = [computed], __getShapeClipPathCache_dec = [computed], __getShapeMaskCache_dec = [computed], __getShapeMaskedPageBoundsCache_dec = [computed], __notVisibleShapes_dec = [computed], _getCulledShapes_dec = [computed], _getCurrentPageBounds_dec = [computed], _getCurrentPageShapes_dec = [computed], _getCurrentPageShapesSorted_dec = [computed], _getCurrentPageRenderingShapesSorted_dec = [computed], __getBindingsIndexCache_dec = [computed], __getSelectionSharedStyles_dec = [computed], _getSharedStyles_dec = [computed({ isEqual: (a, b) => a.equals(b) })], _getSharedOpacity_dec = [computed], _getIsFocused_dec = [computed], _getIsReadonly_dec = [computed], __setShiftKeyTimeout_dec = [bind], __setAltKeyTimeout_dec = [bind], __setCtrlKeyTimeout_dec = [bind], __setMetaKeyTimeout_dec = [bind], _a) {
160
161
  constructor({
161
162
  store,
162
163
  user,
@@ -334,6 +335,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
334
335
  __publicField(this, "_currentPageShapeIds");
335
336
  /* --------------------- Shapes --------------------- */
336
337
  __publicField(this, "_shapeGeometryCaches", {});
338
+ __publicField(this, "_shapePageGeometryCaches", {});
337
339
  // Parents and children
338
340
  /**
339
341
  * A cache of parents to children.
@@ -1473,6 +1475,131 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1473
1475
  this.setSelectedShapes(this._getUnlockedShapeIds(ids));
1474
1476
  return this;
1475
1477
  }
1478
+ selectAdjacentShape(direction) {
1479
+ const readingOrderShapes = this.getCurrentPageShapesInReadingOrder();
1480
+ const selectedShapeIds = this.getSelectedShapeIds();
1481
+ const currentShapeId = selectedShapeIds.length === 1 ? selectedShapeIds[0] : readingOrderShapes.find((shape2) => selectedShapeIds.includes(shape2.id))?.id;
1482
+ let adjacentShapeId;
1483
+ if (direction === "next" || direction === "prev") {
1484
+ const shapeIds = readingOrderShapes.map((shape2) => shape2.id);
1485
+ const currentIndex = currentShapeId ? shapeIds.indexOf(currentShapeId) : -1;
1486
+ const adjacentIndex = (currentIndex + (direction === "next" ? 1 : -1) + shapeIds.length) % shapeIds.length;
1487
+ adjacentShapeId = shapeIds[adjacentIndex];
1488
+ } else {
1489
+ if (!currentShapeId) return;
1490
+ adjacentShapeId = this.getNearestAdjacentShape(currentShapeId, direction);
1491
+ }
1492
+ const shape = this.getShape(adjacentShapeId);
1493
+ if (!shape) return;
1494
+ this.setSelectedShapes([shape.id]);
1495
+ this.zoomToSelectionIfOffscreen(256, {
1496
+ animation: {
1497
+ duration: this.options.animationMediumMs
1498
+ },
1499
+ inset: 0
1500
+ });
1501
+ }
1502
+ getCurrentPageShapesInReadingOrder() {
1503
+ const SHALLOW_ANGLE = 20;
1504
+ const ROW_THRESHOLD = 100;
1505
+ const shapes = this.getCurrentPageShapes();
1506
+ const tabbableShapes = shapes.filter((shape) => this.getShapeUtil(shape).canTabTo(shape));
1507
+ if (tabbableShapes.length <= 1) return tabbableShapes;
1508
+ const shapesWithCenters = tabbableShapes.map((shape) => ({
1509
+ shape,
1510
+ center: this.getShapePageBounds(shape).center
1511
+ }));
1512
+ shapesWithCenters.sort((a, b) => a.center.y - b.center.y);
1513
+ const rows = [];
1514
+ for (const shapeWithCenter of shapesWithCenters) {
1515
+ let rowIndex = -1;
1516
+ for (let i = rows.length - 1; i >= 0; i--) {
1517
+ const row = rows[i];
1518
+ const lastShapeInRow = row[row.length - 1];
1519
+ if (Math.abs(shapeWithCenter.center.y - lastShapeInRow.center.y) < ROW_THRESHOLD) {
1520
+ rowIndex = i;
1521
+ break;
1522
+ }
1523
+ }
1524
+ if (rowIndex === -1) {
1525
+ rows.push([shapeWithCenter]);
1526
+ } else {
1527
+ rows[rowIndex].push(shapeWithCenter);
1528
+ }
1529
+ }
1530
+ for (const row of rows) {
1531
+ row.sort((a, b) => a.center.x - b.center.x);
1532
+ }
1533
+ for (const row of rows) {
1534
+ if (row.length <= 2) continue;
1535
+ for (let i = 0; i < row.length - 2; i++) {
1536
+ const currentShape = row[i];
1537
+ const nextShape = row[i + 1];
1538
+ const nextNextShape = row[i + 2];
1539
+ const dist1 = Vec.Dist2(currentShape.center, nextShape.center);
1540
+ const dist2 = Vec.Dist2(currentShape.center, nextNextShape.center);
1541
+ if (dist2 < dist1 * 0.9) {
1542
+ const angle = Math.abs(
1543
+ Vec.Angle(currentShape.center, nextNextShape.center) * (180 / Math.PI)
1544
+ );
1545
+ if (angle <= SHALLOW_ANGLE) {
1546
+ ;
1547
+ [row[i + 1], row[i + 2]] = [row[i + 2], row[i + 1]];
1548
+ }
1549
+ }
1550
+ }
1551
+ }
1552
+ return rows.flat().map((item) => item.shape);
1553
+ }
1554
+ /**
1555
+ * Find the nearest adjacent shape in a specific direction.
1556
+ *
1557
+ * @public
1558
+ */
1559
+ getNearestAdjacentShape(currentShapeId, direction) {
1560
+ const directionToAngle = { right: 0, left: 180, down: 90, up: 270 };
1561
+ const currentShape = this.getShape(currentShapeId);
1562
+ if (!currentShape) return currentShapeId;
1563
+ const shapes = this.getCurrentPageShapes();
1564
+ const tabbableShapes = shapes.filter(
1565
+ (shape) => this.getShapeUtil(shape).canTabTo(shape) && shape.id !== currentShapeId
1566
+ );
1567
+ if (!tabbableShapes.length) return currentShapeId;
1568
+ const currentCenter = this.getShapePageBounds(currentShape).center;
1569
+ const shapesWithCenters = tabbableShapes.map((shape) => ({
1570
+ shape,
1571
+ center: this.getShapePageBounds(shape).center
1572
+ }));
1573
+ const shapesInDirection = shapesWithCenters.filter(({ center }) => {
1574
+ const isRight = center.x > currentCenter.x;
1575
+ const isDown = center.y > currentCenter.y;
1576
+ const xDist = center.x - currentCenter.x;
1577
+ const yDist = center.y - currentCenter.y;
1578
+ const isInXDirection = Math.abs(yDist) < Math.abs(xDist) * 2;
1579
+ const isInYDirection = Math.abs(xDist) < Math.abs(yDist) * 2;
1580
+ if (direction === "left" || direction === "right") {
1581
+ return isInXDirection && (direction === "right" ? isRight : !isRight);
1582
+ }
1583
+ if (direction === "up" || direction === "down") {
1584
+ return isInYDirection && (direction === "down" ? isDown : !isDown);
1585
+ }
1586
+ });
1587
+ if (shapesInDirection.length === 0) return currentShapeId;
1588
+ const lowestScoringShape = minBy(shapesInDirection, ({ center }) => {
1589
+ const distance = Vec.Dist2(currentCenter, center);
1590
+ const dirProp = ["left", "right"].includes(direction) ? "x" : "y";
1591
+ const directionalDistance = Math.abs(center[dirProp] - currentCenter[dirProp]);
1592
+ const offProp = ["left", "right"].includes(direction) ? "y" : "x";
1593
+ const offAxisDeviation = Math.abs(center[offProp] - currentCenter[offProp]);
1594
+ const angle = Math.abs(Vec.Angle(currentCenter, center) * (180 / Math.PI));
1595
+ const angleDeviation = Math.abs(angle - directionToAngle[direction]);
1596
+ return distance * 1 + // Base distance
1597
+ offAxisDeviation * 2 + // Heavy penalty for off-axis deviation
1598
+ (distance - directionalDistance) * 1.5 + // Penalty for diagonal distance
1599
+ angleDeviation * 0.5;
1600
+ });
1601
+ return lowestScoringShape.shape.id;
1602
+ }
1476
1603
  /**
1477
1604
  * Clear the selection.
1478
1605
  *
@@ -2386,6 +2513,23 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2386
2513
  }
2387
2514
  return this;
2388
2515
  }
2516
+ /**
2517
+ * Zoom the camera to the current selection if offscreen.
2518
+ *
2519
+ * @public
2520
+ */
2521
+ zoomToSelectionIfOffscreen(padding = 16, opts) {
2522
+ const selectionPageBounds = this.getSelectionPageBounds();
2523
+ const viewportPageBounds = this.getViewportPageBounds();
2524
+ if (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {
2525
+ const eb = selectionPageBounds.clone().expandBy(padding / this.getZoomLevel()).expand(viewportPageBounds);
2526
+ const nextBounds = viewportPageBounds.clone().translate({
2527
+ x: (eb.center.x - viewportPageBounds.center.x) * 2,
2528
+ y: (eb.center.y - viewportPageBounds.center.y) * 2
2529
+ });
2530
+ this.zoomToBounds(nextBounds, opts);
2531
+ }
2532
+ }
2389
2533
  /**
2390
2534
  * Zoom the camera to fit a bounding box (in the current page space).
2391
2535
  *
@@ -3301,7 +3445,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3301
3445
  return await this.store.props.assets.upload(asset, file, abortSignal);
3302
3446
  }
3303
3447
  /**
3304
- * Get the geometry of a shape.
3448
+ * Get the geometry of a shape in shape-space.
3305
3449
  *
3306
3450
  * @example
3307
3451
  * ```ts
@@ -3331,6 +3475,41 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3331
3475
  typeof shape === "string" ? shape : shape.id
3332
3476
  );
3333
3477
  }
3478
+ /**
3479
+ * Get the geometry of a shape in page-space.
3480
+ *
3481
+ * @example
3482
+ * ```ts
3483
+ * editor.getShapePageGeometry(myShape)
3484
+ * editor.getShapePageGeometry(myShapeId)
3485
+ * editor.getShapePageGeometry(myShapeId, { context: "arrow" })
3486
+ * ```
3487
+ *
3488
+ * @param shape - The shape (or shape id) to get the geometry for.
3489
+ * @param opts - Additional options about the request for geometry. Passed to {@link ShapeUtil.getGeometry}.
3490
+ *
3491
+ * @public
3492
+ */
3493
+ getShapePageGeometry(shape, opts) {
3494
+ const context = opts?.context ?? "none";
3495
+ if (!this._shapePageGeometryCaches[context]) {
3496
+ this._shapePageGeometryCaches[context] = this.store.createComputedCache(
3497
+ "bounds",
3498
+ (shape2) => {
3499
+ const geometry = this.getShapeGeometry(shape2.id, opts);
3500
+ const pageTransform = this.getShapePageTransform(shape2.id);
3501
+ return geometry.transform(pageTransform);
3502
+ },
3503
+ {
3504
+ // we only depend directly on the shape id, and changing geometry/transform will update us anyway
3505
+ areRecordsEqual: () => true
3506
+ }
3507
+ );
3508
+ }
3509
+ return this._shapePageGeometryCaches[context].get(
3510
+ typeof shape === "string" ? shape : shape.id
3511
+ );
3512
+ }
3334
3513
  _getShapeHandlesCache() {
3335
3514
  return this.store.createComputedCache("handles", (shape) => {
3336
3515
  return this.getShapeUtil(shape).getHandles?.(shape);
@@ -3418,12 +3597,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3418
3597
  }
3419
3598
  _getShapePageBoundsCache() {
3420
3599
  return this.store.createComputedCache("pageBoundsCache", (shape) => {
3421
- const pageTransform = this._getShapePageTransformCache().get(shape.id);
3422
- if (!pageTransform) return new Box();
3423
- const result = Box.FromPoints(
3424
- Mat.applyToPoints(pageTransform, this.getShapeGeometry(shape).vertices)
3425
- );
3426
- return result;
3600
+ return this.getShapePageGeometry(shape).bounds;
3427
3601
  });
3428
3602
  }
3429
3603
  /**
@@ -3483,7 +3657,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3483
3657
  const pageMask = frameAncestors.map(
3484
3658
  (s) => (
3485
3659
  // Apply the frame transform to the frame outline to get the frame outline in the current page space
3486
- (this._getShapePageTransformCache().get(s.id).applyToPoints(this.getShapeGeometry(s).vertices))
3660
+ (this.getShapePageGeometry(s.id).vertices)
3487
3661
  )
3488
3662
  ).reduce((acc, b) => {
3489
3663
  if (!(b && acc)) return void 0;
@@ -7560,6 +7734,7 @@ __decorateElement(_init, 1, "getCurrentPageState", _getCurrentPageState_dec, Edi
7560
7734
  __decorateElement(_init, 1, "_getCurrentPageStateId", __getCurrentPageStateId_dec, Editor);
7561
7735
  __decorateElement(_init, 1, "getSelectedShapeIds", _getSelectedShapeIds_dec, Editor);
7562
7736
  __decorateElement(_init, 1, "getSelectedShapes", _getSelectedShapes_dec, Editor);
7737
+ __decorateElement(_init, 1, "getCurrentPageShapesInReadingOrder", _getCurrentPageShapesInReadingOrder_dec, Editor);
7563
7738
  __decorateElement(_init, 1, "getOnlySelectedShapeId", _getOnlySelectedShapeId_dec, Editor);
7564
7739
  __decorateElement(_init, 1, "getOnlySelectedShape", _getOnlySelectedShape_dec, Editor);
7565
7740
  __decorateElement(_init, 1, "getSelectionPageBounds", _getSelectionPageBounds_dec, Editor);