@tldraw/editor 4.3.0-canary.244925359412 → 4.3.0-canary.2643056dfc8d

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 (177) hide show
  1. package/dist-cjs/index.d.ts +536 -120
  2. package/dist-cjs/index.js +8 -1
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/components/ErrorBoundary.js.map +1 -1
  5. package/dist-cjs/lib/components/GeometryDebuggingView.js +1 -17
  6. package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
  7. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -5
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  9. package/dist-cjs/lib/constants.js +1 -3
  10. package/dist-cjs/lib/constants.js.map +2 -2
  11. package/dist-cjs/lib/editor/Editor.js +346 -280
  12. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  13. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +16 -23
  14. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +3 -3
  15. package/dist-cjs/lib/editor/derivations/parentsToChildren.js +12 -3
  16. package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
  17. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -1
  18. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  19. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +5 -6
  20. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  21. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +591 -0
  22. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +7 -0
  23. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +1 -1
  24. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  25. package/dist-cjs/lib/editor/managers/SpatialIndexManager/RBushIndex.js +144 -0
  26. package/dist-cjs/lib/editor/managers/SpatialIndexManager/RBushIndex.js.map +7 -0
  27. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +181 -0
  28. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +7 -0
  29. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -22
  30. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  31. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +31 -23
  32. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  33. package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js +1 -1
  34. package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js.map +2 -2
  35. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +3 -3
  36. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  37. package/dist-cjs/lib/editor/types/emit-types.js.map +1 -1
  38. package/dist-cjs/lib/exports/parseCss.js +1 -1
  39. package/dist-cjs/lib/exports/parseCss.js.map +2 -2
  40. package/dist-cjs/lib/globals/environment.js +45 -9
  41. package/dist-cjs/lib/globals/environment.js.map +2 -2
  42. package/dist-cjs/lib/hooks/useCoarsePointer.js +14 -29
  43. package/dist-cjs/lib/hooks/useCoarsePointer.js.map +2 -2
  44. package/dist-cjs/lib/hooks/useEvent.js +1 -1
  45. package/dist-cjs/lib/hooks/useEvent.js.map +2 -2
  46. package/dist-cjs/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.js.map +2 -2
  47. package/dist-cjs/lib/hooks/useGestureEvents.js +1 -1
  48. package/dist-cjs/lib/hooks/useGestureEvents.js.map +2 -2
  49. package/dist-cjs/lib/hooks/usePassThroughMouseOverEvents.js.map +2 -2
  50. package/dist-cjs/lib/hooks/usePassThroughWheelEvents.js.map +2 -2
  51. package/dist-cjs/lib/hooks/useScreenBounds.js.map +2 -2
  52. package/dist-cjs/lib/hooks/useStateAttribute.js +4 -1
  53. package/dist-cjs/lib/hooks/useStateAttribute.js.map +2 -2
  54. package/dist-cjs/lib/hooks/useTransform.js.map +1 -1
  55. package/dist-cjs/lib/hooks/useZoomCss.js +4 -8
  56. package/dist-cjs/lib/hooks/useZoomCss.js.map +2 -2
  57. package/dist-cjs/lib/options.js +6 -1
  58. package/dist-cjs/lib/options.js.map +2 -2
  59. package/dist-cjs/lib/primitives/Box.js +3 -0
  60. package/dist-cjs/lib/primitives/Box.js.map +2 -2
  61. package/dist-cjs/lib/primitives/geometry/Geometry2d.js +1 -0
  62. package/dist-cjs/lib/primitives/geometry/Geometry2d.js.map +2 -2
  63. package/dist-cjs/lib/utils/rotation.js +1 -1
  64. package/dist-cjs/lib/utils/rotation.js.map +2 -2
  65. package/dist-cjs/version.js +3 -3
  66. package/dist-cjs/version.js.map +1 -1
  67. package/dist-esm/index.d.mts +536 -120
  68. package/dist-esm/index.mjs +9 -2
  69. package/dist-esm/index.mjs.map +2 -2
  70. package/dist-esm/lib/components/ErrorBoundary.mjs.map +1 -1
  71. package/dist-esm/lib/components/GeometryDebuggingView.mjs +1 -17
  72. package/dist-esm/lib/components/GeometryDebuggingView.mjs.map +2 -2
  73. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs +4 -5
  74. package/dist-esm/lib/components/default-components/DefaultCanvas.mjs.map +2 -2
  75. package/dist-esm/lib/constants.mjs +1 -3
  76. package/dist-esm/lib/constants.mjs.map +2 -2
  77. package/dist-esm/lib/editor/Editor.mjs +347 -283
  78. package/dist-esm/lib/editor/Editor.mjs.map +2 -2
  79. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs +16 -23
  80. package/dist-esm/lib/editor/derivations/notVisibleShapes.mjs.map +3 -3
  81. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs +13 -4
  82. package/dist-esm/lib/editor/derivations/parentsToChildren.mjs.map +2 -2
  83. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs +1 -1
  84. package/dist-esm/lib/editor/managers/ClickManager/ClickManager.mjs.map +2 -2
  85. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs +5 -6
  86. package/dist-esm/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.mjs.map +2 -2
  87. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs +573 -0
  88. package/dist-esm/lib/editor/managers/InputsManager/InputsManager.mjs.map +7 -0
  89. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs +1 -1
  90. package/dist-esm/lib/editor/managers/SnapManager/SnapManager.mjs.map +2 -2
  91. package/dist-esm/lib/editor/managers/SpatialIndexManager/RBushIndex.mjs +114 -0
  92. package/dist-esm/lib/editor/managers/SpatialIndexManager/RBushIndex.mjs.map +7 -0
  93. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs +161 -0
  94. package/dist-esm/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.mjs.map +7 -0
  95. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs +1 -22
  96. package/dist-esm/lib/editor/managers/TickManager/TickManager.mjs.map +2 -2
  97. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs +31 -23
  98. package/dist-esm/lib/editor/shapes/ShapeUtil.mjs.map +2 -2
  99. package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs +1 -1
  100. package/dist-esm/lib/editor/shapes/group/DashedOutlineBox.mjs.map +2 -2
  101. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs +3 -3
  102. package/dist-esm/lib/editor/tools/BaseBoxShapeTool/children/Pointing.mjs.map +2 -2
  103. package/dist-esm/lib/exports/parseCss.mjs +1 -1
  104. package/dist-esm/lib/exports/parseCss.mjs.map +2 -2
  105. package/dist-esm/lib/globals/environment.mjs +45 -9
  106. package/dist-esm/lib/globals/environment.mjs.map +2 -2
  107. package/dist-esm/lib/hooks/useCoarsePointer.mjs +15 -30
  108. package/dist-esm/lib/hooks/useCoarsePointer.mjs.map +2 -2
  109. package/dist-esm/lib/hooks/useEvent.mjs +1 -1
  110. package/dist-esm/lib/hooks/useEvent.mjs.map +2 -2
  111. package/dist-esm/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.mjs.map +2 -2
  112. package/dist-esm/lib/hooks/useGestureEvents.mjs +1 -1
  113. package/dist-esm/lib/hooks/useGestureEvents.mjs.map +2 -2
  114. package/dist-esm/lib/hooks/usePassThroughMouseOverEvents.mjs.map +2 -2
  115. package/dist-esm/lib/hooks/usePassThroughWheelEvents.mjs.map +2 -2
  116. package/dist-esm/lib/hooks/useScreenBounds.mjs.map +2 -2
  117. package/dist-esm/lib/hooks/useStateAttribute.mjs +4 -1
  118. package/dist-esm/lib/hooks/useStateAttribute.mjs.map +2 -2
  119. package/dist-esm/lib/hooks/useTransform.mjs.map +1 -1
  120. package/dist-esm/lib/hooks/useZoomCss.mjs +4 -8
  121. package/dist-esm/lib/hooks/useZoomCss.mjs.map +2 -2
  122. package/dist-esm/lib/options.mjs +6 -1
  123. package/dist-esm/lib/options.mjs.map +2 -2
  124. package/dist-esm/lib/primitives/Box.mjs +3 -0
  125. package/dist-esm/lib/primitives/Box.mjs.map +2 -2
  126. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs +1 -0
  127. package/dist-esm/lib/primitives/geometry/Geometry2d.mjs.map +2 -2
  128. package/dist-esm/lib/utils/rotation.mjs +1 -1
  129. package/dist-esm/lib/utils/rotation.mjs.map +2 -2
  130. package/dist-esm/version.mjs +3 -3
  131. package/dist-esm/version.mjs.map +1 -1
  132. package/editor.css +14 -12
  133. package/package.json +21 -17
  134. package/src/index.ts +5 -1
  135. package/src/lib/components/ErrorBoundary.tsx +1 -1
  136. package/src/lib/components/GeometryDebuggingView.tsx +1 -19
  137. package/src/lib/components/default-components/DefaultCanvas.tsx +4 -8
  138. package/src/lib/config/TLUserPreferences.test.ts +40 -0
  139. package/src/lib/constants.ts +0 -2
  140. package/src/lib/editor/Editor.test.ts +140 -0
  141. package/src/lib/editor/Editor.ts +452 -326
  142. package/src/lib/editor/derivations/notVisibleShapes.ts +21 -33
  143. package/src/lib/editor/derivations/parentsToChildren.ts +18 -7
  144. package/src/lib/editor/managers/ClickManager/ClickManager.test.ts +17 -31
  145. package/src/lib/editor/managers/ClickManager/ClickManager.ts +1 -1
  146. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.test.ts +129 -79
  147. package/src/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.ts +10 -6
  148. package/src/lib/editor/managers/InputsManager/InputsManager.ts +566 -0
  149. package/src/lib/editor/managers/ScribbleManager/ScribbleManager.test.ts +0 -4
  150. package/src/lib/editor/managers/SnapManager/SnapManager.test.ts +12 -0
  151. package/src/lib/editor/managers/SnapManager/SnapManager.ts +1 -1
  152. package/src/lib/editor/managers/SpatialIndexManager/RBushIndex.ts +144 -0
  153. package/src/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.ts +215 -0
  154. package/src/lib/editor/managers/TickManager/TickManager.test.ts +40 -107
  155. package/src/lib/editor/managers/TickManager/TickManager.ts +2 -32
  156. package/src/lib/editor/shapes/ShapeUtil.ts +67 -24
  157. package/src/lib/editor/shapes/group/DashedOutlineBox.tsx +1 -1
  158. package/src/lib/editor/tools/BaseBoxShapeTool/children/Pointing.ts +3 -3
  159. package/src/lib/editor/types/emit-types.ts +1 -0
  160. package/src/lib/exports/parseCss.test.ts +1 -0
  161. package/src/lib/exports/parseCss.ts +1 -1
  162. package/src/lib/globals/environment.ts +65 -10
  163. package/src/lib/hooks/useCoarsePointer.ts +16 -59
  164. package/src/lib/hooks/useEvent.tsx +1 -1
  165. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
  166. package/src/lib/hooks/useGestureEvents.ts +2 -2
  167. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +1 -1
  168. package/src/lib/hooks/usePassThroughWheelEvents.ts +1 -1
  169. package/src/lib/hooks/useScreenBounds.ts +1 -1
  170. package/src/lib/hooks/useStateAttribute.ts +4 -1
  171. package/src/lib/hooks/useTransform.ts +1 -1
  172. package/src/lib/hooks/useZoomCss.ts +3 -8
  173. package/src/lib/options.ts +32 -0
  174. package/src/lib/primitives/Box.ts +9 -0
  175. package/src/lib/primitives/geometry/Geometry2d.ts +1 -0
  176. package/src/lib/utils/rotation.ts +1 -1
  177. 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, _getNotVisibleShapes_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, _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, _getNotVisibleShapes_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, _getEfficientZoomLevel_dec, __getAboveDebouncedZoomThreshold_dec, _getDebouncedZoomLevel_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, _getInstanceState_dec, _getDocumentSettings_dec, _getCurrentToolId_dec, _getCurrentTool_dec, _getPath_dec, _canRedo_dec, _canUndo_dec, _getIsShapeHiddenCache_dec, _a, _init;
50
50
  import {
51
51
  EMPTY_ARRAY,
52
52
  atom,
@@ -64,7 +64,6 @@ import {
64
64
  PageRecordType,
65
65
  TLDOCUMENT_ID,
66
66
  TLINSTANCE_ID,
67
- TLPOINTER_ID,
68
67
  createBindingId,
69
68
  createShapeId,
70
69
  getShapePropKeysByStyle,
@@ -116,8 +115,7 @@ import {
116
115
  LEFT_MOUSE_BUTTON,
117
116
  MIDDLE_MOUSE_BUTTON,
118
117
  RIGHT_MOUSE_BUTTON,
119
- STYLUS_ERASER_BUTTON,
120
- ZOOM_TO_FIT_PADDING
118
+ STYLUS_ERASER_BUTTON
121
119
  } from "../constants.mjs";
122
120
  import { exportToSvg } from "../exports/exportToSvg.mjs";
123
121
  import { getSvgAsImage } from "../exports/getSvgAsImage.mjs";
@@ -140,7 +138,6 @@ import {
140
138
  parseDeepLinkString
141
139
  } from "../utils/deepLinks.mjs";
142
140
  import { getIncrementedName } from "../utils/getIncrementedName.mjs";
143
- import { isAccelKey } from "../utils/keyboard.mjs";
144
141
  import { getReorderingShapesChanges } from "../utils/reorderShapes.mjs";
145
142
  import { applyRotationToSnapshotShapes, getRotationSnapshot } from "../utils/rotation.mjs";
146
143
  import { bindingsIndex } from "./derivations/bindingsIndex.mjs";
@@ -152,13 +149,15 @@ import { EdgeScrollManager } from "./managers/EdgeScrollManager/EdgeScrollManage
152
149
  import { FocusManager } from "./managers/FocusManager/FocusManager.mjs";
153
150
  import { FontManager } from "./managers/FontManager/FontManager.mjs";
154
151
  import { HistoryManager } from "./managers/HistoryManager/HistoryManager.mjs";
152
+ import { InputsManager } from "./managers/InputsManager/InputsManager.mjs";
155
153
  import { ScribbleManager } from "./managers/ScribbleManager/ScribbleManager.mjs";
156
154
  import { SnapManager } from "./managers/SnapManager/SnapManager.mjs";
155
+ import { SpatialIndexManager } from "./managers/SpatialIndexManager/SpatialIndexManager.mjs";
157
156
  import { TextManager } from "./managers/TextManager/TextManager.mjs";
158
157
  import { TickManager } from "./managers/TickManager/TickManager.mjs";
159
158
  import { UserPreferencesManager } from "./managers/UserPreferencesManager/UserPreferencesManager.mjs";
160
159
  import { RootState } from "./tools/RootState.mjs";
161
- 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], _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], _getNotVisibleShapes_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], _canUndo_dec = [computed], _canRedo_dec = [computed], _getPath_dec = [computed], _getCurrentTool_dec = [computed], _getCurrentToolId_dec = [computed], _getDocumentSettings_dec = [computed], _getInstanceState_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], _getDebouncedZoomLevel_dec = [computed], __getAboveDebouncedZoomThreshold_dec = [computed], _getEfficientZoomLevel_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], _getNotVisibleShapes_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) {
162
161
  constructor({
163
162
  store,
164
163
  user,
@@ -194,7 +193,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
194
193
  */
195
194
  __publicField(this, "root");
196
195
  /**
197
- * A set of functions to call when the app is disposed.
196
+ * A set of functions to call when the editor is disposed.
198
197
  *
199
198
  * @public
200
199
  */
@@ -205,14 +204,29 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
205
204
  * @public
206
205
  */
207
206
  __publicField(this, "isDisposed", false);
208
- /** @internal */
207
+ /**
208
+ * A manager for the editor's tick events.
209
+ *
210
+ * @internal */
209
211
  __publicField(this, "_tickManager");
210
212
  /**
211
- * A manager for the app's snapping feature.
213
+ * A manager for the editor's input state.
214
+ *
215
+ * @public
216
+ */
217
+ __publicField(this, "inputs");
218
+ /**
219
+ * A manager for the editor's snapping feature.
212
220
  *
213
221
  * @public
214
222
  */
215
223
  __publicField(this, "snaps");
224
+ /**
225
+ * A manager for spatial indexing, enabling efficient shape location queries.
226
+ *
227
+ * @public
228
+ */
229
+ __publicField(this, "spatialIndex");
216
230
  /**
217
231
  * A manager for the any asynchronous events and making sure they're
218
232
  * cleaned up upon disposal.
@@ -290,7 +304,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
290
304
  __publicField(this, "bindingUtils");
291
305
  /* --------------------- History -------------------- */
292
306
  /**
293
- * A manager for the app's history.
307
+ * A manager for the editor's history.
294
308
  *
295
309
  * @readonly
296
310
  */
@@ -305,6 +319,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
305
319
  // Rich text editor
306
320
  __publicField(this, "_currentRichTextEditor", atom("rich text editor", null));
307
321
  __publicField(this, "_textOptions");
322
+ __publicField(this, "_debouncedZoomLevel", atom("debounced zoom level", 1));
308
323
  __publicField(this, "_cameraOptions", atom("camera options", DEFAULT_CAMERA_OPTIONS));
309
324
  /** @internal */
310
325
  __publicField(this, "_viewportAnimation", null);
@@ -328,6 +343,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
328
343
  /* --------------------- Shapes --------------------- */
329
344
  __publicField(this, "_shapeGeometryCaches", {});
330
345
  __publicField(this, "_notVisibleShapes", notVisibleShapes(this));
346
+ __publicField(this, "_culledShapesCache", null);
331
347
  // Parents and children
332
348
  /**
333
349
  * A cache of parents to children.
@@ -355,54 +371,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
355
371
  tldraw: null,
356
372
  excalidraw: null
357
373
  });
358
- /* --------------------- Events --------------------- */
359
- /**
360
- * The app's current input state.
361
- *
362
- * @public
363
- */
364
- __publicField(this, "inputs", {
365
- /** The most recent pointer down's position in the current page space. */
366
- originPagePoint: new Vec(),
367
- /** The most recent pointer down's position in screen space. */
368
- originScreenPoint: new Vec(),
369
- /** The previous pointer position in the current page space. */
370
- previousPagePoint: new Vec(),
371
- /** The previous pointer position in screen space. */
372
- previousScreenPoint: new Vec(),
373
- /** The most recent pointer position in the current page space. */
374
- currentPagePoint: new Vec(),
375
- /** The most recent pointer position in screen space. */
376
- currentScreenPoint: new Vec(),
377
- /** A set containing the currently pressed keys. */
378
- keys: /* @__PURE__ */ new Set(),
379
- /** A set containing the currently pressed buttons. */
380
- buttons: /* @__PURE__ */ new Set(),
381
- /** Whether the input is from a pe. */
382
- isPen: false,
383
- /** Whether the shift key is currently pressed. */
384
- shiftKey: false,
385
- /** Whether the meta key is currently pressed. */
386
- metaKey: false,
387
- /** Whether the control or command key is currently pressed. */
388
- ctrlKey: false,
389
- /** Whether the alt or option key is currently pressed. */
390
- altKey: false,
391
- /** Whether the user is dragging. */
392
- isDragging: false,
393
- /** Whether the user is pointing. */
394
- isPointing: false,
395
- /** Whether the user is pinching. */
396
- isPinching: false,
397
- /** Whether the user is editing. */
398
- isEditing: false,
399
- /** Whether the user is panning. */
400
- isPanning: false,
401
- /** Whether the user is spacebar panning. */
402
- isSpacebarPanning: false,
403
- /** Velocity of mouse pointer, in pixels per millisecond */
404
- pointerVelocity: new Vec()
405
- });
406
374
  /**
407
375
  * A manager for recording multiple click events.
408
376
  *
@@ -426,8 +394,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
426
394
  /** @internal */
427
395
  __publicField(this, "_restoreToolId", "select");
428
396
  /** @internal */
429
- __publicField(this, "_pinchStart", 1);
430
- /** @internal */
431
397
  __publicField(this, "_didPinch", false);
432
398
  /** @internal */
433
399
  __publicField(this, "_selectedShapeIdsAtPointerDown", []);
@@ -453,6 +419,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
453
419
  }
454
420
  });
455
421
  this.snaps = new SnapManager(this);
422
+ this.spatialIndex = new SpatialIndexManager(this);
423
+ this.disposables.add(() => this.spatialIndex.dispose());
456
424
  this.disposables.add(this.timers.dispose);
457
425
  this._cameraOptions.set({ ...DEFAULT_CAMERA_OPTIONS, ...cameraOptions });
458
426
  this._textOptions = atom("text options", textOptions ?? null);
@@ -463,6 +431,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
463
431
  this.disposables.add(() => this.textMeasure.dispose());
464
432
  this.fonts = new FontManager(this, fontAssetUrls);
465
433
  this._tickManager = new TickManager(this);
434
+ this.inputs = new InputsManager(this);
466
435
  class NewRoot extends RootState {
467
436
  static initial = initialState ?? "";
468
437
  }
@@ -895,6 +864,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
895
864
  this.disposables.clear();
896
865
  this.store.dispose();
897
866
  this.isDisposed = true;
867
+ this.emit("dispose");
898
868
  }
899
869
  getShapeUtil(arg) {
900
870
  const type = typeof arg === "string" ? arg : arg.type;
@@ -928,9 +898,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
928
898
  this.history.undo();
929
899
  return this;
930
900
  }
931
- getCanUndo() {
901
+ canUndo() {
932
902
  return this.history.getNumUndos() > 0;
933
903
  }
904
+ getCanUndo() {
905
+ return this.canUndo();
906
+ }
934
907
  /**
935
908
  * Redo to the next mark.
936
909
  *
@@ -947,13 +920,16 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
947
920
  this.history.redo();
948
921
  return this;
949
922
  }
923
+ canRedo() {
924
+ return this.history.getNumRedos() > 0;
925
+ }
926
+ getCanRedo() {
927
+ return this.canRedo();
928
+ }
950
929
  clearHistory() {
951
930
  this.history.clear();
952
931
  return this;
953
932
  }
954
- getCanRedo() {
955
- return this.history.getNumRedos() > 0;
956
- }
957
933
  /**
958
934
  * Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
959
935
  * any redos. You typically want to do this just before a user interaction begins or is handled.
@@ -1108,7 +1084,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1108
1084
  }),
1109
1085
  selectionCount: this.getSelectedShapes().length,
1110
1086
  editingShape: editingShapeId ? this.getShape(editingShapeId) : void 0,
1111
- inputs: this.inputs,
1087
+ inputs: this.inputs.toJson(),
1112
1088
  pageState: this.getCurrentPageState(),
1113
1089
  instanceState: this.getInstanceState(),
1114
1090
  collaboratorCount: this.getCollaboratorsOnCurrentPage().length
@@ -1129,7 +1105,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1129
1105
  * we're in a transaction that's about to be rolled back due to the same error we're currently
1130
1106
  * reporting.
1131
1107
  *
1132
- * Instead, to listen to changes to this value, you need to listen to app's `crash` event.
1108
+ * Instead, to listen to changes to this value, you need to listen to editor's `crash` event.
1133
1109
  *
1134
1110
  * @internal
1135
1111
  */
@@ -1780,6 +1756,28 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1780
1756
  const editingShapeId = this.getEditingShapeId();
1781
1757
  return editingShapeId ? this.getShape(editingShapeId) : void 0;
1782
1758
  }
1759
+ /**
1760
+ * Whether the shape can be edited.
1761
+ *
1762
+ * @param shape - The shape (or shape id) to check if it can be edited.
1763
+ * @param info - The info about the edit start.
1764
+ *
1765
+ * @public
1766
+ * @returns true if the shape can be edited, false otherwise.
1767
+ */
1768
+ canEditShape(shape, info) {
1769
+ const id = typeof shape === "string" ? shape : shape?.id ?? null;
1770
+ if (!id) return false;
1771
+ if (id === this.getEditingShapeId()) return false;
1772
+ const _shape = this.getShape(id);
1773
+ if (!_shape) return false;
1774
+ const util = this.getShapeUtil(_shape);
1775
+ const _info = info ?? { type: "unknown" };
1776
+ if (!util.canEdit(_shape, _info)) return false;
1777
+ if (this.getIsReadonly() && !util.canEditInReadonly(_shape)) return false;
1778
+ if (this.isShapeOrAncestorLocked(_shape) && !util.canEditWhileLocked(_shape)) return false;
1779
+ return true;
1780
+ }
1783
1781
  /**
1784
1782
  * Set the current editing shape.
1785
1783
  *
@@ -1795,42 +1793,42 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1795
1793
  */
1796
1794
  setEditingShape(shape) {
1797
1795
  const id = typeof shape === "string" ? shape : shape?.id ?? null;
1798
- this.setRichTextEditor(null);
1799
- const prevEditingShapeId = this.getEditingShapeId();
1800
- if (id !== prevEditingShapeId) {
1801
- if (id) {
1802
- const shape2 = this.getShape(id);
1803
- if (shape2 && this.getShapeUtil(shape2).canEdit(shape2)) {
1804
- this.run(
1805
- () => {
1806
- this._updateCurrentPageState({ editingShapeId: id });
1807
- if (prevEditingShapeId) {
1808
- const prevEditingShape = this.getShape(prevEditingShapeId);
1809
- if (prevEditingShape) {
1810
- this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1811
- }
1812
- }
1813
- this.getShapeUtil(shape2).onEditStart?.(shape2);
1814
- },
1815
- { history: "ignore" }
1816
- );
1817
- return this;
1818
- }
1819
- }
1796
+ if (!id) {
1820
1797
  this.run(
1821
1798
  () => {
1822
- this._updateCurrentPageState({ editingShapeId: null });
1823
- this._currentRichTextEditor.set(null);
1799
+ const prevEditingShapeId = this.getEditingShapeId();
1824
1800
  if (prevEditingShapeId) {
1825
1801
  const prevEditingShape = this.getShape(prevEditingShapeId);
1826
1802
  if (prevEditingShape) {
1827
1803
  this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1828
1804
  }
1829
1805
  }
1806
+ this._updateCurrentPageState({ editingShapeId: null });
1807
+ this._currentRichTextEditor.set(null);
1830
1808
  },
1831
1809
  { history: "ignore" }
1832
1810
  );
1811
+ return this;
1833
1812
  }
1813
+ if (!this.canEditShape(id)) return this;
1814
+ this.run(
1815
+ () => {
1816
+ const prevEditingShapeId = this.getEditingShapeId();
1817
+ if (prevEditingShapeId) {
1818
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1819
+ if (prevEditingShape) {
1820
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1821
+ }
1822
+ }
1823
+ this._updateCurrentPageState({ editingShapeId: null });
1824
+ this._currentRichTextEditor.set(null);
1825
+ this.select(id);
1826
+ this._updateCurrentPageState({ editingShapeId: id });
1827
+ const nextEditingShape = this.getShape(id);
1828
+ this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
1829
+ },
1830
+ { history: "ignore" }
1831
+ );
1834
1832
  return this;
1835
1833
  }
1836
1834
  getRichTextEditor() {
@@ -1963,6 +1961,25 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1963
1961
  getCroppingShapeId() {
1964
1962
  return this.getCurrentPageState().croppingShapeId;
1965
1963
  }
1964
+ /**
1965
+ * Whether the shape can be cropped.
1966
+ *
1967
+ * @param shape - The shape (or shape id) to check if it can be cropped.
1968
+ *
1969
+ * @public
1970
+ * @returns true if the shape can be cropped, false otherwise.
1971
+ */
1972
+ canCropShape(shape) {
1973
+ if (!shape) return false;
1974
+ const id = typeof shape === "string" ? shape : shape?.id ?? null;
1975
+ if (!id) return false;
1976
+ const _shape = this.getShape(id);
1977
+ if (!_shape) return false;
1978
+ const util = this.getShapeUtil(_shape);
1979
+ if (!util.canCrop(_shape)) return false;
1980
+ if (this.isShapeOrAncestorLocked(_shape)) return false;
1981
+ return true;
1982
+ }
1966
1983
  /**
1967
1984
  * Set the current cropping shape.
1968
1985
  *
@@ -1984,12 +2001,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1984
2001
  () => {
1985
2002
  if (!id) {
1986
2003
  this.updateCurrentPageState({ croppingShapeId: null });
1987
- } else {
1988
- const shape2 = this.getShape(id);
1989
- const util = this.getShapeUtil(shape2);
1990
- if (shape2 && util.canCrop(shape2)) {
1991
- this.updateCurrentPageState({ croppingShapeId: id });
1992
- }
2004
+ } else if (this.canCropShape(id)) {
2005
+ this.updateCurrentPageState({ croppingShapeId: id });
1993
2006
  }
1994
2007
  },
1995
2008
  { history: "ignore" }
@@ -2064,6 +2077,22 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2064
2077
  getZoomLevel() {
2065
2078
  return this.getCamera().z;
2066
2079
  }
2080
+ getDebouncedZoomLevel() {
2081
+ if (this.options.debouncedZoom) {
2082
+ if (this.getCameraState() === "idle") {
2083
+ return this.getZoomLevel();
2084
+ } else {
2085
+ return this._debouncedZoomLevel.get();
2086
+ }
2087
+ }
2088
+ return this.getZoomLevel();
2089
+ }
2090
+ _getAboveDebouncedZoomThreshold() {
2091
+ return this.getCurrentPageShapeIds().size > this.options.debouncedZoomThreshold;
2092
+ }
2093
+ getEfficientZoomLevel() {
2094
+ return this._getAboveDebouncedZoomThreshold() ? this.getDebouncedZoomLevel() : this.getZoomLevel();
2095
+ }
2067
2096
  /**
2068
2097
  * Get the camera's initial or reset zoom level.
2069
2098
  *
@@ -2309,7 +2338,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2309
2338
  },
2310
2339
  { history: "ignore" }
2311
2340
  );
2312
- const { currentScreenPoint, currentPagePoint } = this.inputs;
2341
+ const currentScreenPoint = this.inputs.getCurrentScreenPoint();
2342
+ const currentPagePoint = this.inputs.getCurrentPagePoint();
2313
2343
  if (currentScreenPoint.x / z - x !== currentPagePoint.x || currentScreenPoint.y / z - y !== currentPagePoint.y) {
2314
2344
  this.updatePointer({
2315
2345
  immediate: opts?.immediate,
@@ -2444,7 +2474,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2444
2474
  * ```ts
2445
2475
  * editor.zoomIn()
2446
2476
  * editor.zoomIn(editor.getViewportScreenCenter(), { animation: { duration: 200 } })
2447
- * editor.zoomIn(editor.inputs.currentScreenPoint, { animation: { duration: 200 } })
2477
+ * editor.zoomIn(editor.inputs.getCurrentScreenPoint(), { animation: { duration: 200 } })
2448
2478
  * ```
2449
2479
  *
2450
2480
  * @param point - The screen point to zoom in on. Defaults to the screen center
@@ -2485,7 +2515,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2485
2515
  * ```ts
2486
2516
  * editor.zoomOut()
2487
2517
  * editor.zoomOut(editor.getViewportScreenCenter(), { animation: { duration: 120 } })
2488
- * editor.zoomOut(editor.inputs.currentScreenPoint, { animation: { duration: 120 } })
2518
+ * editor.zoomOut(editor.inputs.getCurrentScreenPoint(), { animation: { duration: 120 } })
2489
2519
  * ```
2490
2520
  *
2491
2521
  * @param point - The point to zoom out on. Defaults to the viewport screen center.
@@ -2537,10 +2567,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2537
2567
  if (isLocked && !opts?.force) return this;
2538
2568
  const selectionPageBounds = this.getSelectionPageBounds();
2539
2569
  if (selectionPageBounds) {
2540
- this.zoomToBounds(selectionPageBounds, {
2541
- targetZoom: Math.max(1, this.getZoomLevel()),
2542
- ...opts
2543
- });
2570
+ const currentZoom = this.getZoomLevel();
2571
+ if (Math.abs(currentZoom - 1) < 0.01) {
2572
+ this.zoomToBounds(selectionPageBounds, opts);
2573
+ } else {
2574
+ this.zoomToBounds(selectionPageBounds, {
2575
+ targetZoom: 1,
2576
+ ...opts
2577
+ });
2578
+ }
2544
2579
  }
2545
2580
  return this;
2546
2581
  }
@@ -2580,7 +2615,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2580
2615
  const cameraOptions = this._cameraOptions.__unsafe__getWithoutCapture();
2581
2616
  if (cameraOptions.isLocked && !opts?.force) return this;
2582
2617
  const viewportScreenBounds = this.getViewportScreenBounds();
2583
- const inset = opts?.inset ?? Math.min(ZOOM_TO_FIT_PADDING, viewportScreenBounds.width * 0.28);
2618
+ const inset = opts?.inset ?? Math.min(this.options.zoomToFitPadding, viewportScreenBounds.width * 0.28);
2584
2619
  const baseZoom = this.getBaseZoom();
2585
2620
  const zoomMin = cameraOptions.zoomSteps[0];
2586
2621
  const zoomMax = last(cameraOptions.zoomSteps);
@@ -2818,7 +2853,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2818
2853
  this._setCamera(Vec.From({ ...this.getCamera() }));
2819
2854
  }
2820
2855
  }
2821
- this._tickCameraState();
2822
2856
  return this;
2823
2857
  }
2824
2858
  getViewportScreenBounds() {
@@ -3098,6 +3132,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3098
3132
  this._cameraStateTimeoutRemaining = this.options.cameraMovingTimeoutMs;
3099
3133
  if (this._cameraState.__unsafe__getWithoutCapture() !== "idle") return;
3100
3134
  this._cameraState.set("moving");
3135
+ this._debouncedZoomLevel.set(unsafe__withoutCapture(() => this.getCamera().z));
3101
3136
  this.on("tick", this._decayCameraStateTimeout);
3102
3137
  }
3103
3138
  /**
@@ -3850,14 +3885,29 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3850
3885
  const notVisibleShapes2 = this.getNotVisibleShapes();
3851
3886
  const selectedShapeIds = this.getSelectedShapeIds();
3852
3887
  const editingId = this.getEditingShapeId();
3853
- const culledShapes = new Set(notVisibleShapes2);
3888
+ const nextValue = new Set(notVisibleShapes2);
3854
3889
  if (editingId) {
3855
- culledShapes.delete(editingId);
3890
+ nextValue.delete(editingId);
3856
3891
  }
3857
3892
  selectedShapeIds.forEach((id) => {
3858
- culledShapes.delete(id);
3893
+ nextValue.delete(id);
3859
3894
  });
3860
- return culledShapes;
3895
+ const prevValue = this._culledShapesCache;
3896
+ if (prevValue) {
3897
+ if (prevValue.size !== nextValue.size) {
3898
+ this._culledShapesCache = nextValue;
3899
+ return nextValue;
3900
+ }
3901
+ for (const id of prevValue) {
3902
+ if (!nextValue.has(id)) {
3903
+ this._culledShapesCache = nextValue;
3904
+ return nextValue;
3905
+ }
3906
+ }
3907
+ return prevValue;
3908
+ }
3909
+ this._culledShapesCache = nextValue;
3910
+ return nextValue;
3861
3911
  }
3862
3912
  getCurrentPageBounds() {
3863
3913
  let commonBounds;
@@ -3907,7 +3957,10 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3907
3957
  let inHollowSmallestAreaHit = null;
3908
3958
  let inMarginClosestToEdgeDistance = Infinity;
3909
3959
  let inMarginClosestToEdgeHit = null;
3960
+ const searchMargin = Math.max(innerMargin, outerMargin, this.options.hitTestMargin / zoomLevel);
3961
+ const candidateIds = this.spatialIndex.getShapeIdsAtPoint(point, searchMargin);
3910
3962
  const shapesToCheck = (opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted()).filter((shape) => {
3963
+ if (!candidateIds.has(shape.id) && !this.isShapeOfType(shape, "frame")) return false;
3911
3964
  if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
3912
3965
  return false;
3913
3966
  const pageMask = this.getShapeMask(shape);
@@ -4014,7 +4067,31 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
4014
4067
  * @public
4015
4068
  */
4016
4069
  getShapesAtPoint(point, opts = {}) {
4017
- return this.getCurrentPageShapesSorted().filter((shape) => !this.isShapeHidden(shape) && this.isPointInShape(shape, point, opts)).reverse();
4070
+ const margin = opts.margin ?? 0;
4071
+ const candidateIds = this.spatialIndex.getShapeIdsAtPoint(point, margin);
4072
+ return this.getCurrentPageShapesSorted().filter((shape) => {
4073
+ if (this.isShapeHidden(shape)) return false;
4074
+ if (!candidateIds.has(shape.id) && !this.isShapeOfType(shape, "frame")) return false;
4075
+ return this.isPointInShape(shape, point, opts);
4076
+ }).reverse();
4077
+ }
4078
+ /**
4079
+ * Get shape IDs within the given bounds.
4080
+ *
4081
+ * Note: Results are unordered. If you need z-order, combine with sorted shapes:
4082
+ * ```ts
4083
+ * const candidates = editor.getShapeIdsInsideBounds(bounds)
4084
+ * const sorted = editor.getCurrentPageShapesSorted().filter(s => candidates.has(s.id))
4085
+ * ```
4086
+ *
4087
+ * @param bounds - The bounds to search within.
4088
+ *
4089
+ * @returns Unordered set of shape IDs within the given bounds.
4090
+ *
4091
+ * @public
4092
+ */
4093
+ getShapeIdsInsideBounds(bounds) {
4094
+ return this.spatialIndex.getShapeIdsInsideBounds(bounds);
4018
4095
  }
4019
4096
  /**
4020
4097
  * Test whether a point (in the current page space) will will a shape. This method takes into account masks,
@@ -5697,8 +5774,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
5697
5774
  isAspectRatioLocked: options.isAspectRatioLocked
5698
5775
  });
5699
5776
  if (Math.sign(scale.x) * Math.sign(scale.y) < 0) {
5700
- let { rotation } = Mat.Decompose(options.initialPageTransform);
5701
- rotation -= 2 * rotation;
5777
+ const parentRotation = this.getShapeParentTransform(id).rotation();
5778
+ const rotation = -options.initialShape.rotation - 2 * parentRotation;
5702
5779
  this.updateShapes([{ id, type, rotation }]);
5703
5780
  }
5704
5781
  const preScaleShapePageCenter = Mat.applyToPoint(
@@ -5711,9 +5788,9 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
5711
5788
  scale,
5712
5789
  options.scaleAxisRotation
5713
5790
  );
5714
- const pageBounds = this.getShapePageBounds(id);
5715
5791
  const pageTransform = this.getShapePageTransform(id);
5716
- const currentPageCenter = pageBounds.center;
5792
+ const currentLocalBounds = this.getShapeGeometry(id).bounds;
5793
+ const currentPageCenter = Mat.applyToPoint(pageTransform, currentLocalBounds.center);
5717
5794
  const shapePageTransformOrigin = pageTransform.point();
5718
5795
  if (!currentPageCenter || !shapePageTransformOrigin) return this;
5719
5796
  const pageDelta = Vec.Sub(postScaleShapePageCenter, currentPageCenter);
@@ -5999,7 +6076,11 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
5999
6076
  )
6000
6077
  );
6001
6078
  const sortedShapeIds = shapesToGroup.sort(sortByIndex).map((s) => s.id);
6002
- const pageBounds = Box.Common(compact(shapesToGroup.map((id) => this.getShapePageBounds(id))));
6079
+ const childBounds = compact(shapesToGroup.map((shape) => this.getShapePageBounds(shape)));
6080
+ const pageBounds = Box.Common(childBounds);
6081
+ if (!pageBounds.isValid()) {
6082
+ throw Error(`Editor.groupShapes: group bounds are invalid (NaN).`);
6083
+ }
6003
6084
  const { x, y } = pageBounds.point;
6004
6085
  const parentId = this.findCommonAncestor(shapesToGroup) ?? this.getCurrentPageId();
6005
6086
  if (this.getCurrentToolId() !== "select") return this;
@@ -6689,6 +6770,25 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
6689
6770
  }
6690
6771
  }
6691
6772
  }
6773
+ if (point) {
6774
+ const shapesById = new Map(shapes.map((shape) => [shape.id, shape]));
6775
+ const rootShapesFromContent = compact(rootShapeIds.map((id) => shapesById.get(id)));
6776
+ if (rootShapesFromContent.length > 0) {
6777
+ const targetParent = this.getShapeAtPoint(point, {
6778
+ hitInside: true,
6779
+ hitFrameInside: true,
6780
+ hitLocked: true,
6781
+ filter: (shape) => {
6782
+ const util = this.getShapeUtil(shape);
6783
+ if (!util.canReceiveNewChildrenOfType) return false;
6784
+ return rootShapesFromContent.every(
6785
+ (rootShape) => util.canReceiveNewChildrenOfType(shape, rootShape.type)
6786
+ );
6787
+ }
6788
+ });
6789
+ pasteParentId = targetParent ? targetParent.id : currentPageId;
6790
+ }
6791
+ }
6692
6792
  let isDuplicating = false;
6693
6793
  if (!isPageId(pasteParentId)) {
6694
6794
  const parent = this.getShape(pasteParentId);
@@ -6933,60 +7033,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
6933
7033
  height
6934
7034
  };
6935
7035
  }
6936
- /**
6937
- * Update the input points from a pointer, pinch, or wheel event.
6938
- *
6939
- * @param info - The event info.
6940
- */
6941
- _updateInputsFromEvent(info) {
6942
- const {
6943
- pointerVelocity,
6944
- previousScreenPoint,
6945
- previousPagePoint,
6946
- currentScreenPoint,
6947
- currentPagePoint,
6948
- originScreenPoint,
6949
- originPagePoint
6950
- } = this.inputs;
6951
- const { screenBounds } = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID);
6952
- const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
6953
- const sx = info.point.x - screenBounds.x;
6954
- const sy = info.point.y - screenBounds.y;
6955
- const sz = info.point.z ?? 0.5;
6956
- previousScreenPoint.setTo(currentScreenPoint);
6957
- previousPagePoint.setTo(currentPagePoint);
6958
- currentScreenPoint.set(sx, sy);
6959
- const nx = sx / cz - cx;
6960
- const ny = sy / cz - cy;
6961
- if (isFinite(nx) && isFinite(ny)) {
6962
- currentPagePoint.set(nx, ny, sz);
6963
- }
6964
- this.inputs.isPen = info.type === "pointer" && info.isPen;
6965
- if (info.name === "pointer_down" || this.inputs.isPinching) {
6966
- pointerVelocity.set(0, 0);
6967
- originScreenPoint.setTo(currentScreenPoint);
6968
- originPagePoint.setTo(currentPagePoint);
6969
- }
6970
- this.run(
6971
- () => {
6972
- this.store.put([
6973
- {
6974
- id: TLPOINTER_ID,
6975
- typeName: "pointer",
6976
- x: currentPagePoint.x,
6977
- y: currentPagePoint.y,
6978
- lastActivityTimestamp: (
6979
- // If our pointer moved only because we're following some other user, then don't
6980
- // update our last activity timestamp; otherwise, update it to the current timestamp.
6981
- (info.type === "pointer" && info.pointerId === INTERNAL_POINTER_IDS.CAMERA_MOVE ? this.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ?? this._tickManager.now : this._tickManager.now)
6982
- ),
6983
- meta: {}
6984
- }
6985
- ]);
6986
- },
6987
- { history: "ignore" }
6988
- );
6989
- }
7036
+ /* --------------------- Events --------------------- */
6990
7037
  /**
6991
7038
  * Dispatch a cancel event.
6992
7039
  *
@@ -7051,18 +7098,19 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7051
7098
  point: options?.point ?? // weird but true: what `inputs` calls screen-space is actually viewport space. so
7052
7099
  // we need to convert back into true screen space first. we should fix this...
7053
7100
  Vec.Add(
7054
- this.inputs.currentScreenPoint,
7101
+ this.inputs.getCurrentScreenPoint(),
7055
7102
  this.store.unsafeGetWithoutCapture(TLINSTANCE_ID).screenBounds
7056
7103
  ),
7057
7104
  pointerId: options?.pointerId ?? 0,
7058
7105
  button: options?.button ?? 0,
7059
- isPen: options?.isPen ?? this.inputs.isPen,
7060
- shiftKey: options?.shiftKey ?? this.inputs.shiftKey,
7061
- altKey: options?.altKey ?? this.inputs.altKey,
7062
- ctrlKey: options?.ctrlKey ?? this.inputs.ctrlKey,
7063
- metaKey: options?.metaKey ?? this.inputs.metaKey,
7064
- accelKey: options?.accelKey ?? isAccelKey(this.inputs)
7106
+ isPen: options?.isPen ?? this.inputs.getIsPen(),
7107
+ shiftKey: options?.shiftKey ?? this.inputs.getShiftKey(),
7108
+ altKey: options?.altKey ?? this.inputs.getAltKey(),
7109
+ ctrlKey: options?.ctrlKey ?? this.inputs.getCtrlKey(),
7110
+ metaKey: options?.metaKey ?? this.inputs.getMetaKey(),
7111
+ accelKey: false
7065
7112
  };
7113
+ event.accelKey = options?.accelKey ?? this.inputs.getAccelKey();
7066
7114
  if (options?.immediate) {
7067
7115
  this._flushEventForTick(event);
7068
7116
  } else {
@@ -7378,58 +7426,58 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7378
7426
  this._clickManager.cancelDoubleClickTimeout();
7379
7427
  }
7380
7428
  _setShiftKeyTimeout() {
7381
- this.inputs.shiftKey = false;
7429
+ this.inputs.setShiftKey(false);
7382
7430
  this.dispatch({
7383
7431
  type: "keyboard",
7384
7432
  name: "key_up",
7385
7433
  key: "Shift",
7386
- shiftKey: this.inputs.shiftKey,
7387
- ctrlKey: this.inputs.ctrlKey,
7388
- altKey: this.inputs.altKey,
7389
- metaKey: this.inputs.metaKey,
7390
- accelKey: isAccelKey(this.inputs),
7434
+ shiftKey: this.inputs.getShiftKey(),
7435
+ ctrlKey: this.inputs.getCtrlKey(),
7436
+ altKey: this.inputs.getAltKey(),
7437
+ metaKey: this.inputs.getMetaKey(),
7438
+ accelKey: this.inputs.getAccelKey(),
7391
7439
  code: "ShiftLeft"
7392
7440
  });
7393
7441
  }
7394
7442
  _setAltKeyTimeout() {
7395
- this.inputs.altKey = false;
7443
+ this.inputs.setAltKey(false);
7396
7444
  this.dispatch({
7397
7445
  type: "keyboard",
7398
7446
  name: "key_up",
7399
7447
  key: "Alt",
7400
- shiftKey: this.inputs.shiftKey,
7401
- ctrlKey: this.inputs.ctrlKey,
7402
- altKey: this.inputs.altKey,
7403
- metaKey: this.inputs.metaKey,
7404
- accelKey: isAccelKey(this.inputs),
7448
+ shiftKey: this.inputs.getShiftKey(),
7449
+ ctrlKey: this.inputs.getCtrlKey(),
7450
+ altKey: this.inputs.getAltKey(),
7451
+ metaKey: this.inputs.getMetaKey(),
7452
+ accelKey: this.inputs.getAccelKey(),
7405
7453
  code: "AltLeft"
7406
7454
  });
7407
7455
  }
7408
7456
  _setCtrlKeyTimeout() {
7409
- this.inputs.ctrlKey = false;
7457
+ this.inputs.setCtrlKey(false);
7410
7458
  this.dispatch({
7411
7459
  type: "keyboard",
7412
7460
  name: "key_up",
7413
7461
  key: "Ctrl",
7414
- shiftKey: this.inputs.shiftKey,
7415
- ctrlKey: this.inputs.ctrlKey,
7416
- altKey: this.inputs.altKey,
7417
- metaKey: this.inputs.metaKey,
7418
- accelKey: isAccelKey(this.inputs),
7462
+ shiftKey: this.inputs.getShiftKey(),
7463
+ ctrlKey: this.inputs.getCtrlKey(),
7464
+ altKey: this.inputs.getAltKey(),
7465
+ metaKey: this.inputs.getMetaKey(),
7466
+ accelKey: this.inputs.getAccelKey(),
7419
7467
  code: "ControlLeft"
7420
7468
  });
7421
7469
  }
7422
7470
  _setMetaKeyTimeout() {
7423
- this.inputs.metaKey = false;
7471
+ this.inputs.setMetaKey(false);
7424
7472
  this.dispatch({
7425
7473
  type: "keyboard",
7426
7474
  name: "key_up",
7427
7475
  key: "Meta",
7428
- shiftKey: this.inputs.shiftKey,
7429
- ctrlKey: this.inputs.ctrlKey,
7430
- altKey: this.inputs.altKey,
7431
- metaKey: this.inputs.metaKey,
7432
- accelKey: isAccelKey(this.inputs),
7476
+ shiftKey: this.inputs.getShiftKey(),
7477
+ ctrlKey: this.inputs.getCtrlKey(),
7478
+ altKey: this.inputs.getAltKey(),
7479
+ metaKey: this.inputs.getMetaKey(),
7480
+ accelKey: this.inputs.getAccelKey(),
7433
7481
  code: "MetaLeft"
7434
7482
  });
7435
7483
  }
@@ -7500,48 +7548,47 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7500
7548
  const { type } = info;
7501
7549
  if (info.type === "misc") {
7502
7550
  if (info.name === "cancel" || info.name === "complete") {
7503
- this.inputs.isDragging = false;
7504
- if (this.inputs.isPanning) {
7505
- this.inputs.isPanning = false;
7506
- this.inputs.isSpacebarPanning = false;
7551
+ this.inputs.setIsDragging(false);
7552
+ if (this.inputs.getIsPanning()) {
7553
+ this.inputs.setIsPanning(false);
7554
+ this.inputs.setIsSpacebarPanning(false);
7507
7555
  this.setCursor({ type: this._prevCursor, rotation: 0 });
7508
7556
  }
7509
7557
  }
7510
- this.emit("event", info);
7511
7558
  this.root.handleEvent(info);
7559
+ this.emit("event", info);
7512
7560
  return;
7513
7561
  }
7514
7562
  if (info.shiftKey) {
7515
7563
  clearTimeout(this._shiftKeyTimeout);
7516
7564
  this._shiftKeyTimeout = -1;
7517
- inputs.shiftKey = true;
7518
- } else if (!info.shiftKey && inputs.shiftKey && this._shiftKeyTimeout === -1) {
7565
+ inputs.setShiftKey(true);
7566
+ } else if (!info.shiftKey && inputs.getShiftKey() && this._shiftKeyTimeout === -1) {
7519
7567
  this._shiftKeyTimeout = this.timers.setTimeout(this._setShiftKeyTimeout, 150);
7520
7568
  }
7521
7569
  if (info.altKey) {
7522
7570
  clearTimeout(this._altKeyTimeout);
7523
7571
  this._altKeyTimeout = -1;
7524
- inputs.altKey = true;
7525
- } else if (!info.altKey && inputs.altKey && this._altKeyTimeout === -1) {
7572
+ inputs.setAltKey(true);
7573
+ } else if (!info.altKey && inputs.getAltKey() && this._altKeyTimeout === -1) {
7526
7574
  this._altKeyTimeout = this.timers.setTimeout(this._setAltKeyTimeout, 150);
7527
7575
  }
7528
7576
  if (info.ctrlKey) {
7529
7577
  clearTimeout(this._ctrlKeyTimeout);
7530
7578
  this._ctrlKeyTimeout = -1;
7531
- inputs.ctrlKey = true;
7532
- } else if (!info.ctrlKey && inputs.ctrlKey && this._ctrlKeyTimeout === -1) {
7579
+ inputs.setCtrlKey(true);
7580
+ } else if (!info.ctrlKey && inputs.getCtrlKey() && this._ctrlKeyTimeout === -1) {
7533
7581
  this._ctrlKeyTimeout = this.timers.setTimeout(this._setCtrlKeyTimeout, 150);
7534
7582
  }
7535
7583
  if (info.metaKey) {
7536
7584
  clearTimeout(this._metaKeyTimeout);
7537
7585
  this._metaKeyTimeout = -1;
7538
- inputs.metaKey = true;
7539
- } else if (!info.metaKey && inputs.metaKey && this._metaKeyTimeout === -1) {
7586
+ inputs.setMetaKey(true);
7587
+ } else if (!info.metaKey && inputs.getMetaKey() && this._metaKeyTimeout === -1) {
7540
7588
  this._metaKeyTimeout = this.timers.setTimeout(this._setMetaKeyTimeout, 150);
7541
7589
  }
7542
- const { originPagePoint, currentPagePoint } = inputs;
7543
- if (!inputs.isPointing) {
7544
- inputs.isDragging = false;
7590
+ if (!inputs.getIsPointing()) {
7591
+ inputs.setIsDragging(false);
7545
7592
  }
7546
7593
  const instanceState = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID);
7547
7594
  const pageState = this.store.get(this._getCurrentPageStateId());
@@ -7550,23 +7597,23 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7550
7597
  case "pinch": {
7551
7598
  if (cameraOptions.isLocked) return;
7552
7599
  clearTimeout(this._longPressTimeout);
7553
- this._updateInputsFromEvent(info);
7600
+ this.inputs.updateFromEvent(info);
7554
7601
  switch (info.name) {
7555
7602
  case "pinch_start": {
7556
- if (inputs.isPinching) return;
7557
- if (!inputs.isEditing) {
7558
- this._pinchStart = this.getCamera().z;
7603
+ if (inputs.getIsPinching()) return;
7604
+ if (!inputs.getIsEditing()) {
7559
7605
  if (!this._selectedShapeIdsAtPointerDown.length) {
7560
7606
  this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds];
7561
7607
  }
7562
7608
  this._didPinch = true;
7563
- inputs.isPinching = true;
7609
+ inputs.setIsPinching(true);
7564
7610
  this.interrupt();
7565
7611
  }
7612
+ this.emit("event", info);
7566
7613
  return;
7567
7614
  }
7568
7615
  case "pinch": {
7569
- if (!inputs.isPinching) return;
7616
+ if (!inputs.getIsPinching()) return;
7570
7617
  const {
7571
7618
  point: { z = 1 },
7572
7619
  delta: { x: dx, y: dy }
@@ -7590,11 +7637,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7590
7637
  ),
7591
7638
  { immediate: true }
7592
7639
  );
7640
+ this.emit("event", info);
7593
7641
  return;
7594
7642
  }
7595
7643
  case "pinch_end": {
7596
- if (!inputs.isPinching) return this;
7597
- inputs.isPinching = false;
7644
+ if (!inputs.getIsPinching()) return this;
7645
+ inputs.setIsPinching(false);
7598
7646
  const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this;
7599
7647
  this.setSelectedShapes(this._selectedShapeIdsAtPointerDown);
7600
7648
  this._selectedShapeIdsAtPointerDown = [];
@@ -7608,13 +7656,14 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7608
7656
  });
7609
7657
  }
7610
7658
  }
7659
+ this.emit("event", info);
7611
7660
  return;
7612
7661
  }
7613
7662
  }
7614
7663
  }
7615
7664
  case "wheel": {
7616
7665
  if (cameraOptions.isLocked) return;
7617
- this._updateInputsFromEvent(info);
7666
+ this.inputs.updateFromEvent(info);
7618
7667
  const { panSpeed, zoomSpeed } = cameraOptions;
7619
7668
  let wheelBehavior = cameraOptions.wheelBehavior;
7620
7669
  const inputMode = this.user.getUserPreferences().inputMode;
@@ -7632,7 +7681,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7632
7681
  if (info.ctrlKey) behavior = wheelBehavior === "pan" ? "zoom" : "pan";
7633
7682
  switch (behavior) {
7634
7683
  case "zoom": {
7635
- const { x, y } = this.inputs.currentScreenPoint;
7684
+ const { x, y } = this.inputs.getCurrentScreenPoint();
7636
7685
  let delta = dz;
7637
7686
  if (wheelBehavior === "zoom") {
7638
7687
  if (Math.abs(dy) > 10) {
@@ -7646,6 +7695,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7646
7695
  immediate: true
7647
7696
  });
7648
7697
  this.maybeTrackPerformance("Zooming");
7698
+ this.root.handleEvent(info);
7699
+ this.emit("event", info);
7649
7700
  return;
7650
7701
  }
7651
7702
  case "pan": {
@@ -7653,6 +7704,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7653
7704
  immediate: true
7654
7705
  });
7655
7706
  this.maybeTrackPerformance("Panning");
7707
+ this.root.handleEvent(info);
7708
+ this.emit("event", info);
7656
7709
  return;
7657
7710
  }
7658
7711
  }
@@ -7660,14 +7713,14 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7660
7713
  break;
7661
7714
  }
7662
7715
  case "pointer": {
7663
- if (inputs.isPinching) return;
7664
- this._updateInputsFromEvent(info);
7716
+ if (inputs.getIsPinching()) return;
7717
+ this.inputs.updateFromEvent(info);
7665
7718
  const { isPen } = info;
7666
7719
  const { isPenMode } = instanceState;
7667
7720
  switch (info.name) {
7668
7721
  case "pointer_down": {
7669
7722
  if (isPenMode && !isPen) return;
7670
- if (!this.inputs.isPanning) {
7723
+ if (!this.inputs.getIsPanning()) {
7671
7724
  this._longPressTimeout = this.timers.setTimeout(() => {
7672
7725
  const vsb = this.getViewportScreenBounds();
7673
7726
  this.dispatch({
@@ -7676,7 +7729,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7676
7729
  // viewport bounds, and will be again when this event is handled...
7677
7730
  // so we need to counter-adjust from the stored value so that the
7678
7731
  // new value is set correctly.
7679
- point: this.inputs.originScreenPoint.clone().addXY(vsb.x, vsb.y),
7732
+ point: this.inputs.getOriginScreenPoint().clone().addXY(vsb.x, vsb.y),
7680
7733
  name: "long_press"
7681
7734
  });
7682
7735
  }, this.options.longPressDurationMs);
@@ -7684,21 +7737,21 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7684
7737
  this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds();
7685
7738
  if (info.button === LEFT_MOUSE_BUTTON) this.capturedPointerId = info.pointerId;
7686
7739
  inputs.buttons.add(info.button);
7687
- inputs.isPointing = true;
7688
- inputs.isDragging = false;
7740
+ inputs.setIsPointing(true);
7741
+ inputs.setIsDragging(false);
7689
7742
  if (!isPenMode && isPen) this.updateInstanceState({ isPenMode: true });
7690
7743
  if (info.button === STYLUS_ERASER_BUTTON) {
7691
7744
  this._restoreToolId = this.getCurrentToolId();
7692
7745
  this.complete();
7693
7746
  this.setCurrentTool("eraser");
7694
7747
  } else if (info.button === MIDDLE_MOUSE_BUTTON) {
7695
- if (!this.inputs.isPanning) {
7748
+ if (!this.inputs.getIsPanning()) {
7696
7749
  this._prevCursor = this.getInstanceState().cursor.type;
7697
7750
  }
7698
- this.inputs.isPanning = true;
7751
+ this.inputs.setIsPanning(true);
7699
7752
  clearTimeout(this._longPressTimeout);
7700
7753
  }
7701
- if (this.inputs.isPanning) {
7754
+ if (this.inputs.getIsPanning()) {
7702
7755
  this.stopCameraAnimation();
7703
7756
  this.setCursor({ type: "grabbing", rotation: 0 });
7704
7757
  return this;
@@ -7708,8 +7761,9 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7708
7761
  case "pointer_move": {
7709
7762
  if (!isPen && isPenMode) return;
7710
7763
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7711
- if (this.inputs.isPanning && this.inputs.isPointing) {
7712
- const { currentScreenPoint, previousScreenPoint } = this.inputs;
7764
+ if (this.inputs.getIsPanning() && this.inputs.getIsPointing()) {
7765
+ const currentScreenPoint = this.inputs.getCurrentScreenPoint();
7766
+ const previousScreenPoint = this.inputs.getPreviousScreenPoint();
7713
7767
  const offset = Vec.Sub(currentScreenPoint, previousScreenPoint);
7714
7768
  this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
7715
7769
  immediate: true
@@ -7717,15 +7771,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7717
7771
  this.maybeTrackPerformance("Panning");
7718
7772
  return;
7719
7773
  }
7720
- if (inputs.isPointing && !inputs.isDragging && Vec.Dist2(originPagePoint, currentPagePoint) * this.getZoomLevel() > (instanceState.isCoarsePointer ? this.options.coarseDragDistanceSquared : this.options.dragDistanceSquared) / cz) {
7721
- inputs.isDragging = true;
7774
+ if (inputs.getIsPointing() && !inputs.getIsDragging() && Vec.Dist2(inputs.getOriginPagePoint(), inputs.getCurrentPagePoint()) * this.getZoomLevel() > (instanceState.isCoarsePointer ? this.options.coarseDragDistanceSquared : this.options.dragDistanceSquared) / cz) {
7775
+ inputs.setIsDragging(true);
7722
7776
  clearTimeout(this._longPressTimeout);
7723
7777
  }
7724
7778
  break;
7725
7779
  }
7726
7780
  case "pointer_up": {
7727
- inputs.isDragging = false;
7728
- inputs.isPointing = false;
7781
+ inputs.setIsDragging(false);
7782
+ inputs.setIsPointing(false);
7729
7783
  clearTimeout(this._longPressTimeout);
7730
7784
  inputs.buttons.delete(info.button);
7731
7785
  if (instanceState.isPenMode && !isPen) return;
@@ -7733,12 +7787,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7733
7787
  this.capturedPointerId = null;
7734
7788
  info.button = 0;
7735
7789
  }
7736
- if (inputs.isPanning) {
7790
+ if (inputs.getIsPanning()) {
7737
7791
  if (!inputs.keys.has("Space")) {
7738
- inputs.isPanning = false;
7739
- inputs.isSpacebarPanning = false;
7792
+ inputs.setIsPanning(false);
7793
+ inputs.setIsSpacebarPanning(false);
7740
7794
  }
7741
- const slideDirection = this.inputs.pointerVelocity;
7795
+ const slideDirection = this.inputs.getPointerVelocity();
7742
7796
  const slideSpeed = Math.min(2, slideDirection.len());
7743
7797
  switch (info.button) {
7744
7798
  case LEFT_MOUSE_BUTTON: {
@@ -7775,51 +7829,58 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7775
7829
  switch (info.name) {
7776
7830
  case "key_down": {
7777
7831
  inputs.keys.add(info.code);
7778
- if (info.code === "Space" && !info.ctrlKey) {
7779
- if (!this.inputs.isPanning) {
7780
- this._prevCursor = instanceState.cursor.type;
7781
- }
7782
- this.inputs.isPanning = true;
7783
- this.inputs.isSpacebarPanning = true;
7784
- clearTimeout(this._longPressTimeout);
7785
- this.setCursor({ type: this.inputs.isPointing ? "grabbing" : "grab", rotation: 0 });
7786
- }
7787
- if (this.inputs.isSpacebarPanning) {
7788
- let offset;
7789
- switch (info.code) {
7790
- case "ArrowUp": {
7791
- offset = new Vec(0, -1);
7792
- break;
7793
- }
7794
- case "ArrowRight": {
7795
- offset = new Vec(1, 0);
7796
- break;
7832
+ if (this.options.spacebarPanning) {
7833
+ if (info.code === "Space" && !info.ctrlKey) {
7834
+ if (!this.inputs.getIsPanning()) {
7835
+ this._prevCursor = instanceState.cursor.type;
7797
7836
  }
7798
- case "ArrowDown": {
7799
- offset = new Vec(0, 1);
7800
- break;
7837
+ this.inputs.setIsPanning(true);
7838
+ this.inputs.setIsSpacebarPanning(true);
7839
+ clearTimeout(this._longPressTimeout);
7840
+ this.setCursor({
7841
+ type: this.inputs.getIsPointing() ? "grabbing" : "grab",
7842
+ rotation: 0
7843
+ });
7844
+ }
7845
+ if (this.inputs.getIsSpacebarPanning()) {
7846
+ let offset;
7847
+ switch (info.code) {
7848
+ case "ArrowUp": {
7849
+ offset = new Vec(0, -1);
7850
+ break;
7851
+ }
7852
+ case "ArrowRight": {
7853
+ offset = new Vec(1, 0);
7854
+ break;
7855
+ }
7856
+ case "ArrowDown": {
7857
+ offset = new Vec(0, 1);
7858
+ break;
7859
+ }
7860
+ case "ArrowLeft": {
7861
+ offset = new Vec(-1, 0);
7862
+ break;
7863
+ }
7801
7864
  }
7802
- case "ArrowLeft": {
7803
- offset = new Vec(-1, 0);
7804
- break;
7865
+ if (offset) {
7866
+ const bounds = this.getViewportPageBounds();
7867
+ const next = bounds.clone().translate(offset.mulV({ x: bounds.w, y: bounds.h }));
7868
+ this._animateToViewport(next, { animation: { duration: 320 } });
7805
7869
  }
7806
7870
  }
7807
- if (offset) {
7808
- const bounds = this.getViewportPageBounds();
7809
- const next = bounds.clone().translate(offset.mulV({ x: bounds.w, y: bounds.h }));
7810
- this._animateToViewport(next, { animation: { duration: 320 } });
7811
- }
7812
7871
  }
7813
7872
  break;
7814
7873
  }
7815
7874
  case "key_up": {
7816
7875
  inputs.keys.delete(info.code);
7817
- if (info.code === "Space") {
7818
- if (this.inputs.buttons.has(MIDDLE_MOUSE_BUTTON)) {
7819
- } else {
7820
- this.inputs.isPanning = false;
7821
- this.inputs.isSpacebarPanning = false;
7822
- this.setCursor({ type: this._prevCursor, rotation: 0 });
7876
+ if (this.options.spacebarPanning) {
7877
+ if (info.code === "Space") {
7878
+ if (this.inputs.buttons.has(MIDDLE_MOUSE_BUTTON)) {
7879
+ } else {
7880
+ this.inputs.setIsPanning(false);
7881
+ this.inputs.setIsSpacebarPanning(false);
7882
+ this.setCursor({ type: this._prevCursor, rotation: 0 });
7883
+ }
7823
7884
  }
7824
7885
  }
7825
7886
  break;
@@ -7872,8 +7933,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7872
7933
  }
7873
7934
  _init = __decoratorStart(_a);
7874
7935
  __decorateElement(_init, 1, "getIsShapeHiddenCache", _getIsShapeHiddenCache_dec, Editor);
7875
- __decorateElement(_init, 1, "getCanUndo", _getCanUndo_dec, Editor);
7876
- __decorateElement(_init, 1, "getCanRedo", _getCanRedo_dec, Editor);
7936
+ __decorateElement(_init, 1, "canUndo", _canUndo_dec, Editor);
7937
+ __decorateElement(_init, 1, "canRedo", _canRedo_dec, Editor);
7877
7938
  __decorateElement(_init, 1, "getPath", _getPath_dec, Editor);
7878
7939
  __decorateElement(_init, 1, "getCurrentTool", _getCurrentTool_dec, Editor);
7879
7940
  __decorateElement(_init, 1, "getCurrentToolId", _getCurrentToolId_dec, Editor);
@@ -7908,6 +7969,9 @@ __decorateElement(_init, 1, "getCamera", _getCamera_dec, Editor);
7908
7969
  __decorateElement(_init, 1, "getViewportPageBoundsForFollowing", _getViewportPageBoundsForFollowing_dec, Editor);
7909
7970
  __decorateElement(_init, 1, "getCameraForFollowing", _getCameraForFollowing_dec, Editor);
7910
7971
  __decorateElement(_init, 1, "getZoomLevel", _getZoomLevel_dec, Editor);
7972
+ __decorateElement(_init, 1, "getDebouncedZoomLevel", _getDebouncedZoomLevel_dec, Editor);
7973
+ __decorateElement(_init, 1, "_getAboveDebouncedZoomThreshold", __getAboveDebouncedZoomThreshold_dec, Editor);
7974
+ __decorateElement(_init, 1, "getEfficientZoomLevel", _getEfficientZoomLevel_dec, Editor);
7911
7975
  __decorateElement(_init, 1, "getViewportScreenBounds", _getViewportScreenBounds_dec, Editor);
7912
7976
  __decorateElement(_init, 1, "getViewportScreenCenter", _getViewportScreenCenter_dec, Editor);
7913
7977
  __decorateElement(_init, 1, "getViewportPageBounds", _getViewportPageBounds_dec, Editor);