@tldraw/editor 4.3.0-canary.c7096a59bf3b → 4.3.0-canary.cb6779b4f066

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 (176) hide show
  1. package/README.md +1 -1
  2. package/dist-cjs/index.d.ts +446 -120
  3. package/dist-cjs/index.js +8 -1
  4. package/dist-cjs/index.js.map +2 -2
  5. package/dist-cjs/lib/components/ErrorBoundary.js.map +1 -1
  6. package/dist-cjs/lib/components/GeometryDebuggingView.js +1 -17
  7. package/dist-cjs/lib/components/GeometryDebuggingView.js.map +2 -2
  8. package/dist-cjs/lib/components/default-components/DefaultCanvas.js +4 -5
  9. package/dist-cjs/lib/components/default-components/DefaultCanvas.js.map +2 -2
  10. package/dist-cjs/lib/constants.js +1 -3
  11. package/dist-cjs/lib/constants.js.map +2 -2
  12. package/dist-cjs/lib/editor/Editor.js +342 -280
  13. package/dist-cjs/lib/editor/Editor.js.map +2 -2
  14. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js +16 -23
  15. package/dist-cjs/lib/editor/derivations/notVisibleShapes.js.map +3 -3
  16. package/dist-cjs/lib/editor/derivations/parentsToChildren.js +12 -3
  17. package/dist-cjs/lib/editor/derivations/parentsToChildren.js.map +2 -2
  18. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js +1 -1
  19. package/dist-cjs/lib/editor/managers/ClickManager/ClickManager.js.map +2 -2
  20. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js +5 -6
  21. package/dist-cjs/lib/editor/managers/EdgeScrollManager/EdgeScrollManager.js.map +2 -2
  22. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js +591 -0
  23. package/dist-cjs/lib/editor/managers/InputsManager/InputsManager.js.map +7 -0
  24. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js +1 -1
  25. package/dist-cjs/lib/editor/managers/SnapManager/SnapManager.js.map +2 -2
  26. package/dist-cjs/lib/editor/managers/SpatialIndexManager/RBushIndex.js +144 -0
  27. package/dist-cjs/lib/editor/managers/SpatialIndexManager/RBushIndex.js.map +7 -0
  28. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js +181 -0
  29. package/dist-cjs/lib/editor/managers/SpatialIndexManager/SpatialIndexManager.js.map +7 -0
  30. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js +1 -22
  31. package/dist-cjs/lib/editor/managers/TickManager/TickManager.js.map +2 -2
  32. package/dist-cjs/lib/editor/shapes/ShapeUtil.js +31 -23
  33. package/dist-cjs/lib/editor/shapes/ShapeUtil.js.map +2 -2
  34. package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js +1 -1
  35. package/dist-cjs/lib/editor/shapes/group/DashedOutlineBox.js.map +2 -2
  36. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js +3 -3
  37. package/dist-cjs/lib/editor/tools/BaseBoxShapeTool/children/Pointing.js.map +2 -2
  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 +446 -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 +343 -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 +448 -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/exports/parseCss.test.ts +1 -0
  160. package/src/lib/exports/parseCss.ts +1 -1
  161. package/src/lib/globals/environment.ts +65 -10
  162. package/src/lib/hooks/useCoarsePointer.ts +16 -59
  163. package/src/lib/hooks/useEvent.tsx +1 -1
  164. package/src/lib/hooks/useFixSafariDoubleTapZoomPencilEvents.ts +1 -1
  165. package/src/lib/hooks/useGestureEvents.ts +2 -2
  166. package/src/lib/hooks/usePassThroughMouseOverEvents.ts +1 -1
  167. package/src/lib/hooks/usePassThroughWheelEvents.ts +1 -1
  168. package/src/lib/hooks/useScreenBounds.ts +1 -1
  169. package/src/lib/hooks/useStateAttribute.ts +4 -1
  170. package/src/lib/hooks/useTransform.ts +1 -1
  171. package/src/lib/hooks/useZoomCss.ts +3 -8
  172. package/src/lib/options.ts +32 -0
  173. package/src/lib/primitives/Box.ts +9 -0
  174. package/src/lib/primitives/geometry/Geometry2d.ts +1 -0
  175. package/src/lib/utils/rotation.ts +1 -1
  176. 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,24 @@ 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
+ __publicField(this, "_spatialIndex");
216
225
  /**
217
226
  * A manager for the any asynchronous events and making sure they're
218
227
  * cleaned up upon disposal.
@@ -290,7 +299,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
290
299
  __publicField(this, "bindingUtils");
291
300
  /* --------------------- History -------------------- */
292
301
  /**
293
- * A manager for the app's history.
302
+ * A manager for the editor's history.
294
303
  *
295
304
  * @readonly
296
305
  */
@@ -305,6 +314,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
305
314
  // Rich text editor
306
315
  __publicField(this, "_currentRichTextEditor", atom("rich text editor", null));
307
316
  __publicField(this, "_textOptions");
317
+ __publicField(this, "_debouncedZoomLevel", atom("debounced zoom level", 1));
308
318
  __publicField(this, "_cameraOptions", atom("camera options", DEFAULT_CAMERA_OPTIONS));
309
319
  /** @internal */
310
320
  __publicField(this, "_viewportAnimation", null);
@@ -328,6 +338,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
328
338
  /* --------------------- Shapes --------------------- */
329
339
  __publicField(this, "_shapeGeometryCaches", {});
330
340
  __publicField(this, "_notVisibleShapes", notVisibleShapes(this));
341
+ __publicField(this, "_culledShapesCache", null);
331
342
  // Parents and children
332
343
  /**
333
344
  * A cache of parents to children.
@@ -355,54 +366,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
355
366
  tldraw: null,
356
367
  excalidraw: null
357
368
  });
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
369
  /**
407
370
  * A manager for recording multiple click events.
408
371
  *
@@ -426,8 +389,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
426
389
  /** @internal */
427
390
  __publicField(this, "_restoreToolId", "select");
428
391
  /** @internal */
429
- __publicField(this, "_pinchStart", 1);
430
- /** @internal */
431
392
  __publicField(this, "_didPinch", false);
432
393
  /** @internal */
433
394
  __publicField(this, "_selectedShapeIdsAtPointerDown", []);
@@ -453,6 +414,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
453
414
  }
454
415
  });
455
416
  this.snaps = new SnapManager(this);
417
+ this._spatialIndex = new SpatialIndexManager(this);
418
+ this.disposables.add(() => this._spatialIndex.dispose());
456
419
  this.disposables.add(this.timers.dispose);
457
420
  this._cameraOptions.set({ ...DEFAULT_CAMERA_OPTIONS, ...cameraOptions });
458
421
  this._textOptions = atom("text options", textOptions ?? null);
@@ -463,6 +426,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
463
426
  this.disposables.add(() => this.textMeasure.dispose());
464
427
  this.fonts = new FontManager(this, fontAssetUrls);
465
428
  this._tickManager = new TickManager(this);
429
+ this.inputs = new InputsManager(this);
466
430
  class NewRoot extends RootState {
467
431
  static initial = initialState ?? "";
468
432
  }
@@ -929,9 +893,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
929
893
  this.history.undo();
930
894
  return this;
931
895
  }
932
- getCanUndo() {
896
+ canUndo() {
933
897
  return this.history.getNumUndos() > 0;
934
898
  }
899
+ getCanUndo() {
900
+ return this.canUndo();
901
+ }
935
902
  /**
936
903
  * Redo to the next mark.
937
904
  *
@@ -948,13 +915,16 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
948
915
  this.history.redo();
949
916
  return this;
950
917
  }
918
+ canRedo() {
919
+ return this.history.getNumRedos() > 0;
920
+ }
921
+ getCanRedo() {
922
+ return this.canRedo();
923
+ }
951
924
  clearHistory() {
952
925
  this.history.clear();
953
926
  return this;
954
927
  }
955
- getCanRedo() {
956
- return this.history.getNumRedos() > 0;
957
- }
958
928
  /**
959
929
  * Create a new "mark", or stopping point, in the undo redo history. Creating a mark will clear
960
930
  * any redos. You typically want to do this just before a user interaction begins or is handled.
@@ -1109,7 +1079,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1109
1079
  }),
1110
1080
  selectionCount: this.getSelectedShapes().length,
1111
1081
  editingShape: editingShapeId ? this.getShape(editingShapeId) : void 0,
1112
- inputs: this.inputs,
1082
+ inputs: this.inputs.toJson(),
1113
1083
  pageState: this.getCurrentPageState(),
1114
1084
  instanceState: this.getInstanceState(),
1115
1085
  collaboratorCount: this.getCollaboratorsOnCurrentPage().length
@@ -1130,7 +1100,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1130
1100
  * we're in a transaction that's about to be rolled back due to the same error we're currently
1131
1101
  * reporting.
1132
1102
  *
1133
- * Instead, to listen to changes to this value, you need to listen to app's `crash` event.
1103
+ * Instead, to listen to changes to this value, you need to listen to editor's `crash` event.
1134
1104
  *
1135
1105
  * @internal
1136
1106
  */
@@ -1781,6 +1751,28 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1781
1751
  const editingShapeId = this.getEditingShapeId();
1782
1752
  return editingShapeId ? this.getShape(editingShapeId) : void 0;
1783
1753
  }
1754
+ /**
1755
+ * Whether the shape can be edited.
1756
+ *
1757
+ * @param shape - The shape (or shape id) to check if it can be edited.
1758
+ * @param info - The info about the edit start.
1759
+ *
1760
+ * @public
1761
+ * @returns true if the shape can be edited, false otherwise.
1762
+ */
1763
+ canEditShape(shape, info) {
1764
+ const id = typeof shape === "string" ? shape : shape?.id ?? null;
1765
+ if (!id) return false;
1766
+ if (id === this.getEditingShapeId()) return false;
1767
+ const _shape = this.getShape(id);
1768
+ if (!_shape) return false;
1769
+ const util = this.getShapeUtil(_shape);
1770
+ const _info = info ?? { type: "unknown" };
1771
+ if (!util.canEdit(_shape, _info)) return false;
1772
+ if (this.getIsReadonly() && !util.canEditInReadonly(_shape)) return false;
1773
+ if (this.isShapeOrAncestorLocked(_shape) && !util.canEditWhileLocked(_shape)) return false;
1774
+ return true;
1775
+ }
1784
1776
  /**
1785
1777
  * Set the current editing shape.
1786
1778
  *
@@ -1796,42 +1788,42 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1796
1788
  */
1797
1789
  setEditingShape(shape) {
1798
1790
  const id = typeof shape === "string" ? shape : shape?.id ?? null;
1799
- this.setRichTextEditor(null);
1800
- const prevEditingShapeId = this.getEditingShapeId();
1801
- if (id !== prevEditingShapeId) {
1802
- if (id) {
1803
- const shape2 = this.getShape(id);
1804
- if (shape2 && this.getShapeUtil(shape2).canEdit(shape2)) {
1805
- this.run(
1806
- () => {
1807
- this._updateCurrentPageState({ editingShapeId: id });
1808
- if (prevEditingShapeId) {
1809
- const prevEditingShape = this.getShape(prevEditingShapeId);
1810
- if (prevEditingShape) {
1811
- this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1812
- }
1813
- }
1814
- this.getShapeUtil(shape2).onEditStart?.(shape2);
1815
- },
1816
- { history: "ignore" }
1817
- );
1818
- return this;
1819
- }
1820
- }
1791
+ if (!id) {
1821
1792
  this.run(
1822
1793
  () => {
1823
- this._updateCurrentPageState({ editingShapeId: null });
1824
- this._currentRichTextEditor.set(null);
1794
+ const prevEditingShapeId = this.getEditingShapeId();
1825
1795
  if (prevEditingShapeId) {
1826
1796
  const prevEditingShape = this.getShape(prevEditingShapeId);
1827
1797
  if (prevEditingShape) {
1828
1798
  this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1829
1799
  }
1830
1800
  }
1801
+ this._updateCurrentPageState({ editingShapeId: null });
1802
+ this._currentRichTextEditor.set(null);
1831
1803
  },
1832
1804
  { history: "ignore" }
1833
1805
  );
1806
+ return this;
1834
1807
  }
1808
+ if (!this.canEditShape(id)) return this;
1809
+ this.run(
1810
+ () => {
1811
+ const prevEditingShapeId = this.getEditingShapeId();
1812
+ if (prevEditingShapeId) {
1813
+ const prevEditingShape = this.getShape(prevEditingShapeId);
1814
+ if (prevEditingShape) {
1815
+ this.getShapeUtil(prevEditingShape).onEditEnd?.(prevEditingShape);
1816
+ }
1817
+ }
1818
+ this._updateCurrentPageState({ editingShapeId: null });
1819
+ this._currentRichTextEditor.set(null);
1820
+ this.select(id);
1821
+ this._updateCurrentPageState({ editingShapeId: id });
1822
+ const nextEditingShape = this.getShape(id);
1823
+ this.getShapeUtil(nextEditingShape).onEditStart?.(nextEditingShape);
1824
+ },
1825
+ { history: "ignore" }
1826
+ );
1835
1827
  return this;
1836
1828
  }
1837
1829
  getRichTextEditor() {
@@ -1964,6 +1956,25 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1964
1956
  getCroppingShapeId() {
1965
1957
  return this.getCurrentPageState().croppingShapeId;
1966
1958
  }
1959
+ /**
1960
+ * Whether the shape can be cropped.
1961
+ *
1962
+ * @param shape - The shape (or shape id) to check if it can be cropped.
1963
+ *
1964
+ * @public
1965
+ * @returns true if the shape can be cropped, false otherwise.
1966
+ */
1967
+ canCropShape(shape) {
1968
+ if (!shape) return false;
1969
+ const id = typeof shape === "string" ? shape : shape?.id ?? null;
1970
+ if (!id) return false;
1971
+ const _shape = this.getShape(id);
1972
+ if (!_shape) return false;
1973
+ const util = this.getShapeUtil(_shape);
1974
+ if (!util.canCrop(_shape)) return false;
1975
+ if (this.isShapeOrAncestorLocked(_shape)) return false;
1976
+ return true;
1977
+ }
1967
1978
  /**
1968
1979
  * Set the current cropping shape.
1969
1980
  *
@@ -1985,12 +1996,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
1985
1996
  () => {
1986
1997
  if (!id) {
1987
1998
  this.updateCurrentPageState({ croppingShapeId: null });
1988
- } else {
1989
- const shape2 = this.getShape(id);
1990
- const util = this.getShapeUtil(shape2);
1991
- if (shape2 && util.canCrop(shape2)) {
1992
- this.updateCurrentPageState({ croppingShapeId: id });
1993
- }
1999
+ } else if (this.canCropShape(id)) {
2000
+ this.updateCurrentPageState({ croppingShapeId: id });
1994
2001
  }
1995
2002
  },
1996
2003
  { history: "ignore" }
@@ -2065,6 +2072,22 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2065
2072
  getZoomLevel() {
2066
2073
  return this.getCamera().z;
2067
2074
  }
2075
+ getDebouncedZoomLevel() {
2076
+ if (this.options.debouncedZoom) {
2077
+ if (this.getCameraState() === "idle") {
2078
+ return this.getZoomLevel();
2079
+ } else {
2080
+ return this._debouncedZoomLevel.get();
2081
+ }
2082
+ }
2083
+ return this.getZoomLevel();
2084
+ }
2085
+ _getAboveDebouncedZoomThreshold() {
2086
+ return this.getCurrentPageShapeIds().size > this.options.debouncedZoomThreshold;
2087
+ }
2088
+ getEfficientZoomLevel() {
2089
+ return this._getAboveDebouncedZoomThreshold() ? this.getDebouncedZoomLevel() : this.getZoomLevel();
2090
+ }
2068
2091
  /**
2069
2092
  * Get the camera's initial or reset zoom level.
2070
2093
  *
@@ -2310,7 +2333,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2310
2333
  },
2311
2334
  { history: "ignore" }
2312
2335
  );
2313
- const { currentScreenPoint, currentPagePoint } = this.inputs;
2336
+ const currentScreenPoint = this.inputs.getCurrentScreenPoint();
2337
+ const currentPagePoint = this.inputs.getCurrentPagePoint();
2314
2338
  if (currentScreenPoint.x / z - x !== currentPagePoint.x || currentScreenPoint.y / z - y !== currentPagePoint.y) {
2315
2339
  this.updatePointer({
2316
2340
  immediate: opts?.immediate,
@@ -2445,7 +2469,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2445
2469
  * ```ts
2446
2470
  * editor.zoomIn()
2447
2471
  * editor.zoomIn(editor.getViewportScreenCenter(), { animation: { duration: 200 } })
2448
- * editor.zoomIn(editor.inputs.currentScreenPoint, { animation: { duration: 200 } })
2472
+ * editor.zoomIn(editor.inputs.getCurrentScreenPoint(), { animation: { duration: 200 } })
2449
2473
  * ```
2450
2474
  *
2451
2475
  * @param point - The screen point to zoom in on. Defaults to the screen center
@@ -2486,7 +2510,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2486
2510
  * ```ts
2487
2511
  * editor.zoomOut()
2488
2512
  * editor.zoomOut(editor.getViewportScreenCenter(), { animation: { duration: 120 } })
2489
- * editor.zoomOut(editor.inputs.currentScreenPoint, { animation: { duration: 120 } })
2513
+ * editor.zoomOut(editor.inputs.getCurrentScreenPoint(), { animation: { duration: 120 } })
2490
2514
  * ```
2491
2515
  *
2492
2516
  * @param point - The point to zoom out on. Defaults to the viewport screen center.
@@ -2538,10 +2562,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2538
2562
  if (isLocked && !opts?.force) return this;
2539
2563
  const selectionPageBounds = this.getSelectionPageBounds();
2540
2564
  if (selectionPageBounds) {
2541
- this.zoomToBounds(selectionPageBounds, {
2542
- targetZoom: Math.max(1, this.getZoomLevel()),
2543
- ...opts
2544
- });
2565
+ const currentZoom = this.getZoomLevel();
2566
+ if (Math.abs(currentZoom - 1) < 0.01) {
2567
+ this.zoomToBounds(selectionPageBounds, opts);
2568
+ } else {
2569
+ this.zoomToBounds(selectionPageBounds, {
2570
+ targetZoom: 1,
2571
+ ...opts
2572
+ });
2573
+ }
2545
2574
  }
2546
2575
  return this;
2547
2576
  }
@@ -2581,7 +2610,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2581
2610
  const cameraOptions = this._cameraOptions.__unsafe__getWithoutCapture();
2582
2611
  if (cameraOptions.isLocked && !opts?.force) return this;
2583
2612
  const viewportScreenBounds = this.getViewportScreenBounds();
2584
- const inset = opts?.inset ?? Math.min(ZOOM_TO_FIT_PADDING, viewportScreenBounds.width * 0.28);
2613
+ const inset = opts?.inset ?? Math.min(this.options.zoomToFitPadding, viewportScreenBounds.width * 0.28);
2585
2614
  const baseZoom = this.getBaseZoom();
2586
2615
  const zoomMin = cameraOptions.zoomSteps[0];
2587
2616
  const zoomMax = last(cameraOptions.zoomSteps);
@@ -2819,7 +2848,6 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
2819
2848
  this._setCamera(Vec.From({ ...this.getCamera() }));
2820
2849
  }
2821
2850
  }
2822
- this._tickCameraState();
2823
2851
  return this;
2824
2852
  }
2825
2853
  getViewportScreenBounds() {
@@ -3099,6 +3127,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3099
3127
  this._cameraStateTimeoutRemaining = this.options.cameraMovingTimeoutMs;
3100
3128
  if (this._cameraState.__unsafe__getWithoutCapture() !== "idle") return;
3101
3129
  this._cameraState.set("moving");
3130
+ this._debouncedZoomLevel.set(unsafe__withoutCapture(() => this.getCamera().z));
3102
3131
  this.on("tick", this._decayCameraStateTimeout);
3103
3132
  }
3104
3133
  /**
@@ -3851,14 +3880,29 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3851
3880
  const notVisibleShapes2 = this.getNotVisibleShapes();
3852
3881
  const selectedShapeIds = this.getSelectedShapeIds();
3853
3882
  const editingId = this.getEditingShapeId();
3854
- const culledShapes = new Set(notVisibleShapes2);
3883
+ const nextValue = new Set(notVisibleShapes2);
3855
3884
  if (editingId) {
3856
- culledShapes.delete(editingId);
3885
+ nextValue.delete(editingId);
3857
3886
  }
3858
3887
  selectedShapeIds.forEach((id) => {
3859
- culledShapes.delete(id);
3888
+ nextValue.delete(id);
3860
3889
  });
3861
- return culledShapes;
3890
+ const prevValue = this._culledShapesCache;
3891
+ if (prevValue) {
3892
+ if (prevValue.size !== nextValue.size) {
3893
+ this._culledShapesCache = nextValue;
3894
+ return nextValue;
3895
+ }
3896
+ for (const id of prevValue) {
3897
+ if (!nextValue.has(id)) {
3898
+ this._culledShapesCache = nextValue;
3899
+ return nextValue;
3900
+ }
3901
+ }
3902
+ return prevValue;
3903
+ }
3904
+ this._culledShapesCache = nextValue;
3905
+ return nextValue;
3862
3906
  }
3863
3907
  getCurrentPageBounds() {
3864
3908
  let commonBounds;
@@ -3908,7 +3952,10 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
3908
3952
  let inHollowSmallestAreaHit = null;
3909
3953
  let inMarginClosestToEdgeDistance = Infinity;
3910
3954
  let inMarginClosestToEdgeHit = null;
3955
+ const searchMargin = Math.max(innerMargin, outerMargin, this.options.hitTestMargin / zoomLevel);
3956
+ const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, searchMargin);
3911
3957
  const shapesToCheck = (opts.renderingOnly ? this.getCurrentPageRenderingShapesSorted() : this.getCurrentPageShapesSorted()).filter((shape) => {
3958
+ if (!candidateIds.has(shape.id) && !this.isShapeOfType(shape, "frame")) return false;
3912
3959
  if (shape.isLocked && !hitLocked || this.isShapeHidden(shape) || this.isShapeOfType(shape, "group"))
3913
3960
  return false;
3914
3961
  const pageMask = this.getShapeMask(shape);
@@ -4015,7 +4062,33 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
4015
4062
  * @public
4016
4063
  */
4017
4064
  getShapesAtPoint(point, opts = {}) {
4018
- return this.getCurrentPageShapesSorted().filter((shape) => !this.isShapeHidden(shape) && this.isPointInShape(shape, point, opts)).reverse();
4065
+ const margin = opts.margin ?? 0;
4066
+ const candidateIds = this._spatialIndex.getShapeIdsAtPoint(point, margin);
4067
+ return this.getCurrentPageShapesSorted().filter((shape) => {
4068
+ if (this.isShapeHidden(shape)) return false;
4069
+ if (!candidateIds.has(shape.id) && !this.isShapeOfType(shape, "frame")) return false;
4070
+ return this.isPointInShape(shape, point, opts);
4071
+ }).reverse();
4072
+ }
4073
+ /**
4074
+ * Get shape IDs within the given bounds.
4075
+ *
4076
+ * Note: Uses shape page bounds only. Frames with labels outside their bounds
4077
+ * may not be included even if the label is within the search bounds.
4078
+ *
4079
+ * Note: Results are unordered. If you need z-order, combine with sorted shapes:
4080
+ * ```ts
4081
+ * const candidates = editor.getShapeIdsInsideBounds(bounds)
4082
+ * const sorted = editor.getCurrentPageShapesSorted().filter(s => candidates.has(s.id))
4083
+ * ```
4084
+ *
4085
+ * @param bounds - The bounds to search within.
4086
+ * @returns Unordered set of shape IDs within the given bounds.
4087
+ *
4088
+ * @internal
4089
+ */
4090
+ getShapeIdsInsideBounds(bounds) {
4091
+ return this._spatialIndex.getShapeIdsInsideBounds(bounds);
4019
4092
  }
4020
4093
  /**
4021
4094
  * Test whether a point (in the current page space) will will a shape. This method takes into account masks,
@@ -5698,8 +5771,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
5698
5771
  isAspectRatioLocked: options.isAspectRatioLocked
5699
5772
  });
5700
5773
  if (Math.sign(scale.x) * Math.sign(scale.y) < 0) {
5701
- let { rotation } = Mat.Decompose(options.initialPageTransform);
5702
- rotation -= 2 * rotation;
5774
+ const parentRotation = this.getShapeParentTransform(id).rotation();
5775
+ const rotation = -options.initialShape.rotation - 2 * parentRotation;
5703
5776
  this.updateShapes([{ id, type, rotation }]);
5704
5777
  }
5705
5778
  const preScaleShapePageCenter = Mat.applyToPoint(
@@ -5712,9 +5785,9 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
5712
5785
  scale,
5713
5786
  options.scaleAxisRotation
5714
5787
  );
5715
- const pageBounds = this.getShapePageBounds(id);
5716
5788
  const pageTransform = this.getShapePageTransform(id);
5717
- const currentPageCenter = pageBounds.center;
5789
+ const currentLocalBounds = this.getShapeGeometry(id).bounds;
5790
+ const currentPageCenter = Mat.applyToPoint(pageTransform, currentLocalBounds.center);
5718
5791
  const shapePageTransformOrigin = pageTransform.point();
5719
5792
  if (!currentPageCenter || !shapePageTransformOrigin) return this;
5720
5793
  const pageDelta = Vec.Sub(postScaleShapePageCenter, currentPageCenter);
@@ -6000,7 +6073,11 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
6000
6073
  )
6001
6074
  );
6002
6075
  const sortedShapeIds = shapesToGroup.sort(sortByIndex).map((s) => s.id);
6003
- const pageBounds = Box.Common(compact(shapesToGroup.map((id) => this.getShapePageBounds(id))));
6076
+ const childBounds = compact(shapesToGroup.map((shape) => this.getShapePageBounds(shape)));
6077
+ const pageBounds = Box.Common(childBounds);
6078
+ if (!pageBounds.isValid()) {
6079
+ throw Error(`Editor.groupShapes: group bounds are invalid (NaN).`);
6080
+ }
6004
6081
  const { x, y } = pageBounds.point;
6005
6082
  const parentId = this.findCommonAncestor(shapesToGroup) ?? this.getCurrentPageId();
6006
6083
  if (this.getCurrentToolId() !== "select") return this;
@@ -6690,6 +6767,25 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
6690
6767
  }
6691
6768
  }
6692
6769
  }
6770
+ if (point) {
6771
+ const shapesById = new Map(shapes.map((shape) => [shape.id, shape]));
6772
+ const rootShapesFromContent = compact(rootShapeIds.map((id) => shapesById.get(id)));
6773
+ if (rootShapesFromContent.length > 0) {
6774
+ const targetParent = this.getShapeAtPoint(point, {
6775
+ hitInside: true,
6776
+ hitFrameInside: true,
6777
+ hitLocked: true,
6778
+ filter: (shape) => {
6779
+ const util = this.getShapeUtil(shape);
6780
+ if (!util.canReceiveNewChildrenOfType) return false;
6781
+ return rootShapesFromContent.every(
6782
+ (rootShape) => util.canReceiveNewChildrenOfType(shape, rootShape.type)
6783
+ );
6784
+ }
6785
+ });
6786
+ pasteParentId = targetParent ? targetParent.id : currentPageId;
6787
+ }
6788
+ }
6693
6789
  let isDuplicating = false;
6694
6790
  if (!isPageId(pasteParentId)) {
6695
6791
  const parent = this.getShape(pasteParentId);
@@ -6934,60 +7030,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
6934
7030
  height
6935
7031
  };
6936
7032
  }
6937
- /**
6938
- * Update the input points from a pointer, pinch, or wheel event.
6939
- *
6940
- * @param info - The event info.
6941
- */
6942
- _updateInputsFromEvent(info) {
6943
- const {
6944
- pointerVelocity,
6945
- previousScreenPoint,
6946
- previousPagePoint,
6947
- currentScreenPoint,
6948
- currentPagePoint,
6949
- originScreenPoint,
6950
- originPagePoint
6951
- } = this.inputs;
6952
- const { screenBounds } = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID);
6953
- const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
6954
- const sx = info.point.x - screenBounds.x;
6955
- const sy = info.point.y - screenBounds.y;
6956
- const sz = info.point.z ?? 0.5;
6957
- previousScreenPoint.setTo(currentScreenPoint);
6958
- previousPagePoint.setTo(currentPagePoint);
6959
- currentScreenPoint.set(sx, sy);
6960
- const nx = sx / cz - cx;
6961
- const ny = sy / cz - cy;
6962
- if (isFinite(nx) && isFinite(ny)) {
6963
- currentPagePoint.set(nx, ny, sz);
6964
- }
6965
- this.inputs.isPen = info.type === "pointer" && info.isPen;
6966
- if (info.name === "pointer_down" || this.inputs.isPinching) {
6967
- pointerVelocity.set(0, 0);
6968
- originScreenPoint.setTo(currentScreenPoint);
6969
- originPagePoint.setTo(currentPagePoint);
6970
- }
6971
- this.run(
6972
- () => {
6973
- this.store.put([
6974
- {
6975
- id: TLPOINTER_ID,
6976
- typeName: "pointer",
6977
- x: currentPagePoint.x,
6978
- y: currentPagePoint.y,
6979
- lastActivityTimestamp: (
6980
- // If our pointer moved only because we're following some other user, then don't
6981
- // update our last activity timestamp; otherwise, update it to the current timestamp.
6982
- (info.type === "pointer" && info.pointerId === INTERNAL_POINTER_IDS.CAMERA_MOVE ? this.store.unsafeGetWithoutCapture(TLPOINTER_ID)?.lastActivityTimestamp ?? this._tickManager.now : this._tickManager.now)
6983
- ),
6984
- meta: {}
6985
- }
6986
- ]);
6987
- },
6988
- { history: "ignore" }
6989
- );
6990
- }
7033
+ /* --------------------- Events --------------------- */
6991
7034
  /**
6992
7035
  * Dispatch a cancel event.
6993
7036
  *
@@ -7052,18 +7095,19 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7052
7095
  point: options?.point ?? // weird but true: what `inputs` calls screen-space is actually viewport space. so
7053
7096
  // we need to convert back into true screen space first. we should fix this...
7054
7097
  Vec.Add(
7055
- this.inputs.currentScreenPoint,
7098
+ this.inputs.getCurrentScreenPoint(),
7056
7099
  this.store.unsafeGetWithoutCapture(TLINSTANCE_ID).screenBounds
7057
7100
  ),
7058
7101
  pointerId: options?.pointerId ?? 0,
7059
7102
  button: options?.button ?? 0,
7060
- isPen: options?.isPen ?? this.inputs.isPen,
7061
- shiftKey: options?.shiftKey ?? this.inputs.shiftKey,
7062
- altKey: options?.altKey ?? this.inputs.altKey,
7063
- ctrlKey: options?.ctrlKey ?? this.inputs.ctrlKey,
7064
- metaKey: options?.metaKey ?? this.inputs.metaKey,
7065
- accelKey: options?.accelKey ?? isAccelKey(this.inputs)
7103
+ isPen: options?.isPen ?? this.inputs.getIsPen(),
7104
+ shiftKey: options?.shiftKey ?? this.inputs.getShiftKey(),
7105
+ altKey: options?.altKey ?? this.inputs.getAltKey(),
7106
+ ctrlKey: options?.ctrlKey ?? this.inputs.getCtrlKey(),
7107
+ metaKey: options?.metaKey ?? this.inputs.getMetaKey(),
7108
+ accelKey: false
7066
7109
  };
7110
+ event.accelKey = options?.accelKey ?? this.inputs.getAccelKey();
7067
7111
  if (options?.immediate) {
7068
7112
  this._flushEventForTick(event);
7069
7113
  } else {
@@ -7379,58 +7423,58 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7379
7423
  this._clickManager.cancelDoubleClickTimeout();
7380
7424
  }
7381
7425
  _setShiftKeyTimeout() {
7382
- this.inputs.shiftKey = false;
7426
+ this.inputs.setShiftKey(false);
7383
7427
  this.dispatch({
7384
7428
  type: "keyboard",
7385
7429
  name: "key_up",
7386
7430
  key: "Shift",
7387
- shiftKey: this.inputs.shiftKey,
7388
- ctrlKey: this.inputs.ctrlKey,
7389
- altKey: this.inputs.altKey,
7390
- metaKey: this.inputs.metaKey,
7391
- accelKey: isAccelKey(this.inputs),
7431
+ shiftKey: this.inputs.getShiftKey(),
7432
+ ctrlKey: this.inputs.getCtrlKey(),
7433
+ altKey: this.inputs.getAltKey(),
7434
+ metaKey: this.inputs.getMetaKey(),
7435
+ accelKey: this.inputs.getAccelKey(),
7392
7436
  code: "ShiftLeft"
7393
7437
  });
7394
7438
  }
7395
7439
  _setAltKeyTimeout() {
7396
- this.inputs.altKey = false;
7440
+ this.inputs.setAltKey(false);
7397
7441
  this.dispatch({
7398
7442
  type: "keyboard",
7399
7443
  name: "key_up",
7400
7444
  key: "Alt",
7401
- shiftKey: this.inputs.shiftKey,
7402
- ctrlKey: this.inputs.ctrlKey,
7403
- altKey: this.inputs.altKey,
7404
- metaKey: this.inputs.metaKey,
7405
- accelKey: isAccelKey(this.inputs),
7445
+ shiftKey: this.inputs.getShiftKey(),
7446
+ ctrlKey: this.inputs.getCtrlKey(),
7447
+ altKey: this.inputs.getAltKey(),
7448
+ metaKey: this.inputs.getMetaKey(),
7449
+ accelKey: this.inputs.getAccelKey(),
7406
7450
  code: "AltLeft"
7407
7451
  });
7408
7452
  }
7409
7453
  _setCtrlKeyTimeout() {
7410
- this.inputs.ctrlKey = false;
7454
+ this.inputs.setCtrlKey(false);
7411
7455
  this.dispatch({
7412
7456
  type: "keyboard",
7413
7457
  name: "key_up",
7414
7458
  key: "Ctrl",
7415
- shiftKey: this.inputs.shiftKey,
7416
- ctrlKey: this.inputs.ctrlKey,
7417
- altKey: this.inputs.altKey,
7418
- metaKey: this.inputs.metaKey,
7419
- accelKey: isAccelKey(this.inputs),
7459
+ shiftKey: this.inputs.getShiftKey(),
7460
+ ctrlKey: this.inputs.getCtrlKey(),
7461
+ altKey: this.inputs.getAltKey(),
7462
+ metaKey: this.inputs.getMetaKey(),
7463
+ accelKey: this.inputs.getAccelKey(),
7420
7464
  code: "ControlLeft"
7421
7465
  });
7422
7466
  }
7423
7467
  _setMetaKeyTimeout() {
7424
- this.inputs.metaKey = false;
7468
+ this.inputs.setMetaKey(false);
7425
7469
  this.dispatch({
7426
7470
  type: "keyboard",
7427
7471
  name: "key_up",
7428
7472
  key: "Meta",
7429
- shiftKey: this.inputs.shiftKey,
7430
- ctrlKey: this.inputs.ctrlKey,
7431
- altKey: this.inputs.altKey,
7432
- metaKey: this.inputs.metaKey,
7433
- accelKey: isAccelKey(this.inputs),
7473
+ shiftKey: this.inputs.getShiftKey(),
7474
+ ctrlKey: this.inputs.getCtrlKey(),
7475
+ altKey: this.inputs.getAltKey(),
7476
+ metaKey: this.inputs.getMetaKey(),
7477
+ accelKey: this.inputs.getAccelKey(),
7434
7478
  code: "MetaLeft"
7435
7479
  });
7436
7480
  }
@@ -7501,48 +7545,47 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7501
7545
  const { type } = info;
7502
7546
  if (info.type === "misc") {
7503
7547
  if (info.name === "cancel" || info.name === "complete") {
7504
- this.inputs.isDragging = false;
7505
- if (this.inputs.isPanning) {
7506
- this.inputs.isPanning = false;
7507
- this.inputs.isSpacebarPanning = false;
7548
+ this.inputs.setIsDragging(false);
7549
+ if (this.inputs.getIsPanning()) {
7550
+ this.inputs.setIsPanning(false);
7551
+ this.inputs.setIsSpacebarPanning(false);
7508
7552
  this.setCursor({ type: this._prevCursor, rotation: 0 });
7509
7553
  }
7510
7554
  }
7511
- this.emit("event", info);
7512
7555
  this.root.handleEvent(info);
7556
+ this.emit("event", info);
7513
7557
  return;
7514
7558
  }
7515
7559
  if (info.shiftKey) {
7516
7560
  clearTimeout(this._shiftKeyTimeout);
7517
7561
  this._shiftKeyTimeout = -1;
7518
- inputs.shiftKey = true;
7519
- } else if (!info.shiftKey && inputs.shiftKey && this._shiftKeyTimeout === -1) {
7562
+ inputs.setShiftKey(true);
7563
+ } else if (!info.shiftKey && inputs.getShiftKey() && this._shiftKeyTimeout === -1) {
7520
7564
  this._shiftKeyTimeout = this.timers.setTimeout(this._setShiftKeyTimeout, 150);
7521
7565
  }
7522
7566
  if (info.altKey) {
7523
7567
  clearTimeout(this._altKeyTimeout);
7524
7568
  this._altKeyTimeout = -1;
7525
- inputs.altKey = true;
7526
- } else if (!info.altKey && inputs.altKey && this._altKeyTimeout === -1) {
7569
+ inputs.setAltKey(true);
7570
+ } else if (!info.altKey && inputs.getAltKey() && this._altKeyTimeout === -1) {
7527
7571
  this._altKeyTimeout = this.timers.setTimeout(this._setAltKeyTimeout, 150);
7528
7572
  }
7529
7573
  if (info.ctrlKey) {
7530
7574
  clearTimeout(this._ctrlKeyTimeout);
7531
7575
  this._ctrlKeyTimeout = -1;
7532
- inputs.ctrlKey = true;
7533
- } else if (!info.ctrlKey && inputs.ctrlKey && this._ctrlKeyTimeout === -1) {
7576
+ inputs.setCtrlKey(true);
7577
+ } else if (!info.ctrlKey && inputs.getCtrlKey() && this._ctrlKeyTimeout === -1) {
7534
7578
  this._ctrlKeyTimeout = this.timers.setTimeout(this._setCtrlKeyTimeout, 150);
7535
7579
  }
7536
7580
  if (info.metaKey) {
7537
7581
  clearTimeout(this._metaKeyTimeout);
7538
7582
  this._metaKeyTimeout = -1;
7539
- inputs.metaKey = true;
7540
- } else if (!info.metaKey && inputs.metaKey && this._metaKeyTimeout === -1) {
7583
+ inputs.setMetaKey(true);
7584
+ } else if (!info.metaKey && inputs.getMetaKey() && this._metaKeyTimeout === -1) {
7541
7585
  this._metaKeyTimeout = this.timers.setTimeout(this._setMetaKeyTimeout, 150);
7542
7586
  }
7543
- const { originPagePoint, currentPagePoint } = inputs;
7544
- if (!inputs.isPointing) {
7545
- inputs.isDragging = false;
7587
+ if (!inputs.getIsPointing()) {
7588
+ inputs.setIsDragging(false);
7546
7589
  }
7547
7590
  const instanceState = this.store.unsafeGetWithoutCapture(TLINSTANCE_ID);
7548
7591
  const pageState = this.store.get(this._getCurrentPageStateId());
@@ -7551,23 +7594,23 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7551
7594
  case "pinch": {
7552
7595
  if (cameraOptions.isLocked) return;
7553
7596
  clearTimeout(this._longPressTimeout);
7554
- this._updateInputsFromEvent(info);
7597
+ this.inputs.updateFromEvent(info);
7555
7598
  switch (info.name) {
7556
7599
  case "pinch_start": {
7557
- if (inputs.isPinching) return;
7558
- if (!inputs.isEditing) {
7559
- this._pinchStart = this.getCamera().z;
7600
+ if (inputs.getIsPinching()) return;
7601
+ if (!inputs.getIsEditing()) {
7560
7602
  if (!this._selectedShapeIdsAtPointerDown.length) {
7561
7603
  this._selectedShapeIdsAtPointerDown = [...pageState.selectedShapeIds];
7562
7604
  }
7563
7605
  this._didPinch = true;
7564
- inputs.isPinching = true;
7606
+ inputs.setIsPinching(true);
7565
7607
  this.interrupt();
7566
7608
  }
7609
+ this.emit("event", info);
7567
7610
  return;
7568
7611
  }
7569
7612
  case "pinch": {
7570
- if (!inputs.isPinching) return;
7613
+ if (!inputs.getIsPinching()) return;
7571
7614
  const {
7572
7615
  point: { z = 1 },
7573
7616
  delta: { x: dx, y: dy }
@@ -7591,11 +7634,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7591
7634
  ),
7592
7635
  { immediate: true }
7593
7636
  );
7637
+ this.emit("event", info);
7594
7638
  return;
7595
7639
  }
7596
7640
  case "pinch_end": {
7597
- if (!inputs.isPinching) return this;
7598
- inputs.isPinching = false;
7641
+ if (!inputs.getIsPinching()) return this;
7642
+ inputs.setIsPinching(false);
7599
7643
  const { _selectedShapeIdsAtPointerDown: shapesToReselect } = this;
7600
7644
  this.setSelectedShapes(this._selectedShapeIdsAtPointerDown);
7601
7645
  this._selectedShapeIdsAtPointerDown = [];
@@ -7609,13 +7653,14 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7609
7653
  });
7610
7654
  }
7611
7655
  }
7656
+ this.emit("event", info);
7612
7657
  return;
7613
7658
  }
7614
7659
  }
7615
7660
  }
7616
7661
  case "wheel": {
7617
7662
  if (cameraOptions.isLocked) return;
7618
- this._updateInputsFromEvent(info);
7663
+ this.inputs.updateFromEvent(info);
7619
7664
  const { panSpeed, zoomSpeed } = cameraOptions;
7620
7665
  let wheelBehavior = cameraOptions.wheelBehavior;
7621
7666
  const inputMode = this.user.getUserPreferences().inputMode;
@@ -7633,7 +7678,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7633
7678
  if (info.ctrlKey) behavior = wheelBehavior === "pan" ? "zoom" : "pan";
7634
7679
  switch (behavior) {
7635
7680
  case "zoom": {
7636
- const { x, y } = this.inputs.currentScreenPoint;
7681
+ const { x, y } = this.inputs.getCurrentScreenPoint();
7637
7682
  let delta = dz;
7638
7683
  if (wheelBehavior === "zoom") {
7639
7684
  if (Math.abs(dy) > 10) {
@@ -7647,6 +7692,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7647
7692
  immediate: true
7648
7693
  });
7649
7694
  this.maybeTrackPerformance("Zooming");
7695
+ this.root.handleEvent(info);
7696
+ this.emit("event", info);
7650
7697
  return;
7651
7698
  }
7652
7699
  case "pan": {
@@ -7654,6 +7701,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7654
7701
  immediate: true
7655
7702
  });
7656
7703
  this.maybeTrackPerformance("Panning");
7704
+ this.root.handleEvent(info);
7705
+ this.emit("event", info);
7657
7706
  return;
7658
7707
  }
7659
7708
  }
@@ -7661,14 +7710,14 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7661
7710
  break;
7662
7711
  }
7663
7712
  case "pointer": {
7664
- if (inputs.isPinching) return;
7665
- this._updateInputsFromEvent(info);
7713
+ if (inputs.getIsPinching()) return;
7714
+ this.inputs.updateFromEvent(info);
7666
7715
  const { isPen } = info;
7667
7716
  const { isPenMode } = instanceState;
7668
7717
  switch (info.name) {
7669
7718
  case "pointer_down": {
7670
7719
  if (isPenMode && !isPen) return;
7671
- if (!this.inputs.isPanning) {
7720
+ if (!this.inputs.getIsPanning()) {
7672
7721
  this._longPressTimeout = this.timers.setTimeout(() => {
7673
7722
  const vsb = this.getViewportScreenBounds();
7674
7723
  this.dispatch({
@@ -7677,7 +7726,7 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7677
7726
  // viewport bounds, and will be again when this event is handled...
7678
7727
  // so we need to counter-adjust from the stored value so that the
7679
7728
  // new value is set correctly.
7680
- point: this.inputs.originScreenPoint.clone().addXY(vsb.x, vsb.y),
7729
+ point: this.inputs.getOriginScreenPoint().clone().addXY(vsb.x, vsb.y),
7681
7730
  name: "long_press"
7682
7731
  });
7683
7732
  }, this.options.longPressDurationMs);
@@ -7685,21 +7734,21 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7685
7734
  this._selectedShapeIdsAtPointerDown = this.getSelectedShapeIds();
7686
7735
  if (info.button === LEFT_MOUSE_BUTTON) this.capturedPointerId = info.pointerId;
7687
7736
  inputs.buttons.add(info.button);
7688
- inputs.isPointing = true;
7689
- inputs.isDragging = false;
7737
+ inputs.setIsPointing(true);
7738
+ inputs.setIsDragging(false);
7690
7739
  if (!isPenMode && isPen) this.updateInstanceState({ isPenMode: true });
7691
7740
  if (info.button === STYLUS_ERASER_BUTTON) {
7692
7741
  this._restoreToolId = this.getCurrentToolId();
7693
7742
  this.complete();
7694
7743
  this.setCurrentTool("eraser");
7695
7744
  } else if (info.button === MIDDLE_MOUSE_BUTTON) {
7696
- if (!this.inputs.isPanning) {
7745
+ if (!this.inputs.getIsPanning()) {
7697
7746
  this._prevCursor = this.getInstanceState().cursor.type;
7698
7747
  }
7699
- this.inputs.isPanning = true;
7748
+ this.inputs.setIsPanning(true);
7700
7749
  clearTimeout(this._longPressTimeout);
7701
7750
  }
7702
- if (this.inputs.isPanning) {
7751
+ if (this.inputs.getIsPanning()) {
7703
7752
  this.stopCameraAnimation();
7704
7753
  this.setCursor({ type: "grabbing", rotation: 0 });
7705
7754
  return this;
@@ -7709,8 +7758,9 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7709
7758
  case "pointer_move": {
7710
7759
  if (!isPen && isPenMode) return;
7711
7760
  const { x: cx, y: cy, z: cz } = unsafe__withoutCapture(() => this.getCamera());
7712
- if (this.inputs.isPanning && this.inputs.isPointing) {
7713
- const { currentScreenPoint, previousScreenPoint } = this.inputs;
7761
+ if (this.inputs.getIsPanning() && this.inputs.getIsPointing()) {
7762
+ const currentScreenPoint = this.inputs.getCurrentScreenPoint();
7763
+ const previousScreenPoint = this.inputs.getPreviousScreenPoint();
7714
7764
  const offset = Vec.Sub(currentScreenPoint, previousScreenPoint);
7715
7765
  this.setCamera(new Vec(cx + offset.x / cz, cy + offset.y / cz, cz), {
7716
7766
  immediate: true
@@ -7718,15 +7768,15 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7718
7768
  this.maybeTrackPerformance("Panning");
7719
7769
  return;
7720
7770
  }
7721
- if (inputs.isPointing && !inputs.isDragging && Vec.Dist2(originPagePoint, currentPagePoint) * this.getZoomLevel() > (instanceState.isCoarsePointer ? this.options.coarseDragDistanceSquared : this.options.dragDistanceSquared) / cz) {
7722
- inputs.isDragging = true;
7771
+ if (inputs.getIsPointing() && !inputs.getIsDragging() && Vec.Dist2(inputs.getOriginPagePoint(), inputs.getCurrentPagePoint()) * this.getZoomLevel() > (instanceState.isCoarsePointer ? this.options.coarseDragDistanceSquared : this.options.dragDistanceSquared) / cz) {
7772
+ inputs.setIsDragging(true);
7723
7773
  clearTimeout(this._longPressTimeout);
7724
7774
  }
7725
7775
  break;
7726
7776
  }
7727
7777
  case "pointer_up": {
7728
- inputs.isDragging = false;
7729
- inputs.isPointing = false;
7778
+ inputs.setIsDragging(false);
7779
+ inputs.setIsPointing(false);
7730
7780
  clearTimeout(this._longPressTimeout);
7731
7781
  inputs.buttons.delete(info.button);
7732
7782
  if (instanceState.isPenMode && !isPen) return;
@@ -7734,12 +7784,12 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7734
7784
  this.capturedPointerId = null;
7735
7785
  info.button = 0;
7736
7786
  }
7737
- if (inputs.isPanning) {
7787
+ if (inputs.getIsPanning()) {
7738
7788
  if (!inputs.keys.has("Space")) {
7739
- inputs.isPanning = false;
7740
- inputs.isSpacebarPanning = false;
7789
+ inputs.setIsPanning(false);
7790
+ inputs.setIsSpacebarPanning(false);
7741
7791
  }
7742
- const slideDirection = this.inputs.pointerVelocity;
7792
+ const slideDirection = this.inputs.getPointerVelocity();
7743
7793
  const slideSpeed = Math.min(2, slideDirection.len());
7744
7794
  switch (info.button) {
7745
7795
  case LEFT_MOUSE_BUTTON: {
@@ -7776,51 +7826,58 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7776
7826
  switch (info.name) {
7777
7827
  case "key_down": {
7778
7828
  inputs.keys.add(info.code);
7779
- if (info.code === "Space" && !info.ctrlKey) {
7780
- if (!this.inputs.isPanning) {
7781
- this._prevCursor = instanceState.cursor.type;
7782
- }
7783
- this.inputs.isPanning = true;
7784
- this.inputs.isSpacebarPanning = true;
7785
- clearTimeout(this._longPressTimeout);
7786
- this.setCursor({ type: this.inputs.isPointing ? "grabbing" : "grab", rotation: 0 });
7787
- }
7788
- if (this.inputs.isSpacebarPanning) {
7789
- let offset;
7790
- switch (info.code) {
7791
- case "ArrowUp": {
7792
- offset = new Vec(0, -1);
7793
- break;
7794
- }
7795
- case "ArrowRight": {
7796
- offset = new Vec(1, 0);
7797
- break;
7829
+ if (this.options.spacebarPanning) {
7830
+ if (info.code === "Space" && !info.ctrlKey) {
7831
+ if (!this.inputs.getIsPanning()) {
7832
+ this._prevCursor = instanceState.cursor.type;
7798
7833
  }
7799
- case "ArrowDown": {
7800
- offset = new Vec(0, 1);
7801
- break;
7834
+ this.inputs.setIsPanning(true);
7835
+ this.inputs.setIsSpacebarPanning(true);
7836
+ clearTimeout(this._longPressTimeout);
7837
+ this.setCursor({
7838
+ type: this.inputs.getIsPointing() ? "grabbing" : "grab",
7839
+ rotation: 0
7840
+ });
7841
+ }
7842
+ if (this.inputs.getIsSpacebarPanning()) {
7843
+ let offset;
7844
+ switch (info.code) {
7845
+ case "ArrowUp": {
7846
+ offset = new Vec(0, -1);
7847
+ break;
7848
+ }
7849
+ case "ArrowRight": {
7850
+ offset = new Vec(1, 0);
7851
+ break;
7852
+ }
7853
+ case "ArrowDown": {
7854
+ offset = new Vec(0, 1);
7855
+ break;
7856
+ }
7857
+ case "ArrowLeft": {
7858
+ offset = new Vec(-1, 0);
7859
+ break;
7860
+ }
7802
7861
  }
7803
- case "ArrowLeft": {
7804
- offset = new Vec(-1, 0);
7805
- break;
7862
+ if (offset) {
7863
+ const bounds = this.getViewportPageBounds();
7864
+ const next = bounds.clone().translate(offset.mulV({ x: bounds.w, y: bounds.h }));
7865
+ this._animateToViewport(next, { animation: { duration: 320 } });
7806
7866
  }
7807
7867
  }
7808
- if (offset) {
7809
- const bounds = this.getViewportPageBounds();
7810
- const next = bounds.clone().translate(offset.mulV({ x: bounds.w, y: bounds.h }));
7811
- this._animateToViewport(next, { animation: { duration: 320 } });
7812
- }
7813
7868
  }
7814
7869
  break;
7815
7870
  }
7816
7871
  case "key_up": {
7817
7872
  inputs.keys.delete(info.code);
7818
- if (info.code === "Space") {
7819
- if (this.inputs.buttons.has(MIDDLE_MOUSE_BUTTON)) {
7820
- } else {
7821
- this.inputs.isPanning = false;
7822
- this.inputs.isSpacebarPanning = false;
7823
- this.setCursor({ type: this._prevCursor, rotation: 0 });
7873
+ if (this.options.spacebarPanning) {
7874
+ if (info.code === "Space") {
7875
+ if (this.inputs.buttons.has(MIDDLE_MOUSE_BUTTON)) {
7876
+ } else {
7877
+ this.inputs.setIsPanning(false);
7878
+ this.inputs.setIsSpacebarPanning(false);
7879
+ this.setCursor({ type: this._prevCursor, rotation: 0 });
7880
+ }
7824
7881
  }
7825
7882
  }
7826
7883
  break;
@@ -7873,8 +7930,8 @@ class Editor extends (_a = EventEmitter, _getIsShapeHiddenCache_dec = [computed]
7873
7930
  }
7874
7931
  _init = __decoratorStart(_a);
7875
7932
  __decorateElement(_init, 1, "getIsShapeHiddenCache", _getIsShapeHiddenCache_dec, Editor);
7876
- __decorateElement(_init, 1, "getCanUndo", _getCanUndo_dec, Editor);
7877
- __decorateElement(_init, 1, "getCanRedo", _getCanRedo_dec, Editor);
7933
+ __decorateElement(_init, 1, "canUndo", _canUndo_dec, Editor);
7934
+ __decorateElement(_init, 1, "canRedo", _canRedo_dec, Editor);
7878
7935
  __decorateElement(_init, 1, "getPath", _getPath_dec, Editor);
7879
7936
  __decorateElement(_init, 1, "getCurrentTool", _getCurrentTool_dec, Editor);
7880
7937
  __decorateElement(_init, 1, "getCurrentToolId", _getCurrentToolId_dec, Editor);
@@ -7909,6 +7966,9 @@ __decorateElement(_init, 1, "getCamera", _getCamera_dec, Editor);
7909
7966
  __decorateElement(_init, 1, "getViewportPageBoundsForFollowing", _getViewportPageBoundsForFollowing_dec, Editor);
7910
7967
  __decorateElement(_init, 1, "getCameraForFollowing", _getCameraForFollowing_dec, Editor);
7911
7968
  __decorateElement(_init, 1, "getZoomLevel", _getZoomLevel_dec, Editor);
7969
+ __decorateElement(_init, 1, "getDebouncedZoomLevel", _getDebouncedZoomLevel_dec, Editor);
7970
+ __decorateElement(_init, 1, "_getAboveDebouncedZoomThreshold", __getAboveDebouncedZoomThreshold_dec, Editor);
7971
+ __decorateElement(_init, 1, "getEfficientZoomLevel", _getEfficientZoomLevel_dec, Editor);
7912
7972
  __decorateElement(_init, 1, "getViewportScreenBounds", _getViewportScreenBounds_dec, Editor);
7913
7973
  __decorateElement(_init, 1, "getViewportScreenCenter", _getViewportScreenCenter_dec, Editor);
7914
7974
  __decorateElement(_init, 1, "getViewportPageBounds", _getViewportPageBounds_dec, Editor);