tldraw 5.4.0-next.ef99ab47e5ce → 5.4.0

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 (316) hide show
  1. package/DOCS.md +2826 -3226
  2. package/RELEASE_NOTES.md +190 -2
  3. package/dist-cjs/index.d.ts +264 -275
  4. package/dist-cjs/index.js +1 -1
  5. package/dist-cjs/lib/defaultExternalContentHandlers.js +32 -16
  6. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  7. package/dist-cjs/lib/shapes/arrow/curved-arrow.js +2 -2
  8. package/dist-cjs/lib/shapes/arrow/curved-arrow.js.map +2 -2
  9. package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js +2 -2
  10. package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js.map +2 -2
  11. package/dist-cjs/lib/shapes/arrow/getArrowInfo.js +1 -1
  12. package/dist-cjs/lib/shapes/arrow/getArrowInfo.js.map +2 -2
  13. package/dist-cjs/lib/shapes/arrow/straight-arrow.js +2 -2
  14. package/dist-cjs/lib/shapes/arrow/straight-arrow.js.map +2 -2
  15. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js +2 -3
  16. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js.map +2 -2
  17. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +7 -5
  18. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  19. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +8 -6
  20. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
  21. package/dist-cjs/lib/shapes/geo/getGeoShapePath.js +3 -1
  22. package/dist-cjs/lib/shapes/geo/getGeoShapePath.js.map +2 -2
  23. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js +2 -3
  24. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js.map +2 -2
  25. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +1 -1
  26. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
  27. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +2 -6
  28. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
  29. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
  30. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  31. package/dist-cjs/lib/shapes/note/noteHelpers.js +6 -5
  32. package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
  33. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +1 -1
  34. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
  35. package/dist-cjs/lib/shapes/shared/crop.js +1 -1
  36. package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
  37. package/dist-cjs/lib/shapes/text/toolStates/Idle.js +1 -1
  38. package/dist-cjs/lib/shapes/text/toolStates/Idle.js.map +2 -2
  39. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +1 -0
  40. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
  41. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -2
  42. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +2 -2
  43. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +2 -0
  44. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  45. package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +6 -0
  46. package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +2 -2
  47. package/dist-cjs/lib/tools/SelectTool/SelectTool.js +3 -0
  48. package/dist-cjs/lib/tools/SelectTool/SelectTool.js.map +2 -2
  49. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js +1 -0
  50. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +2 -2
  51. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js +1 -0
  52. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js.map +2 -2
  53. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +1 -3
  54. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  55. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +6 -3
  56. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  57. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js +1 -1
  58. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
  59. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js +3 -0
  60. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js.map +2 -2
  61. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js +1 -0
  62. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +2 -2
  63. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +1 -1
  64. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
  65. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +22 -30
  66. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  67. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js +1 -3
  68. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +2 -2
  69. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +4 -1
  70. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  71. package/dist-cjs/lib/tools/SelectTool/selectHelpers.js +10 -0
  72. package/dist-cjs/lib/tools/SelectTool/selectHelpers.js.map +2 -2
  73. package/dist-cjs/lib/ui/TldrawUi.js +2 -3
  74. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +1 -11
  76. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +6 -1
  78. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js +1 -1
  80. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/Dialogs.js +8 -0
  82. package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/EditLinkDialog.js +5 -5
  84. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +4 -20
  86. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js +1 -2
  88. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js +2 -0
  90. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +2 -2
  91. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +1 -0
  92. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  93. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +10 -8
  94. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  95. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +20 -1
  96. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  97. package/dist-cjs/lib/ui/context/actions.js +8 -8
  98. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  99. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +2 -0
  100. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  101. package/dist-cjs/lib/ui/hooks/useCommentingEnabled.js +1 -1
  102. package/dist-cjs/lib/ui/hooks/useCommentingEnabled.js.map +2 -2
  103. package/dist-cjs/lib/ui/hooks/useFlatten.js +42 -23
  104. package/dist-cjs/lib/ui/hooks/useFlatten.js.map +2 -2
  105. package/dist-cjs/lib/ui/version.js +3 -3
  106. package/dist-cjs/lib/ui/version.js.map +1 -1
  107. package/dist-esm/index.d.mts +264 -275
  108. package/dist-esm/index.mjs +1 -1
  109. package/dist-esm/lib/defaultExternalContentHandlers.mjs +32 -16
  110. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  111. package/dist-esm/lib/shapes/arrow/curved-arrow.mjs +2 -2
  112. package/dist-esm/lib/shapes/arrow/curved-arrow.mjs.map +2 -2
  113. package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs +2 -2
  114. package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs.map +2 -2
  115. package/dist-esm/lib/shapes/arrow/getArrowInfo.mjs +1 -1
  116. package/dist-esm/lib/shapes/arrow/getArrowInfo.mjs.map +2 -2
  117. package/dist-esm/lib/shapes/arrow/straight-arrow.mjs +2 -2
  118. package/dist-esm/lib/shapes/arrow/straight-arrow.mjs.map +2 -2
  119. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs +3 -4
  120. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs.map +2 -2
  121. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +7 -5
  122. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  123. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +8 -6
  124. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
  125. package/dist-esm/lib/shapes/geo/getGeoShapePath.mjs +3 -1
  126. package/dist-esm/lib/shapes/geo/getGeoShapePath.mjs.map +2 -2
  127. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs +3 -4
  128. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs.map +2 -2
  129. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +1 -1
  130. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
  131. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +2 -7
  132. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
  133. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +4 -4
  134. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  135. package/dist-esm/lib/shapes/note/noteHelpers.mjs +6 -5
  136. package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
  137. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +1 -1
  138. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
  139. package/dist-esm/lib/shapes/shared/crop.mjs +1 -1
  140. package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
  141. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs +2 -2
  142. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs.map +2 -2
  143. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +1 -0
  144. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
  145. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -2
  146. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +2 -2
  147. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +2 -0
  148. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  149. package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +6 -0
  150. package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +2 -2
  151. package/dist-esm/lib/tools/SelectTool/SelectTool.mjs +3 -0
  152. package/dist-esm/lib/tools/SelectTool/SelectTool.mjs.map +2 -2
  153. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs +1 -0
  154. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +2 -2
  155. package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs +1 -0
  156. package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs.map +2 -2
  157. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +1 -3
  158. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  159. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +6 -3
  160. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  161. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs +1 -1
  162. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
  163. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs +3 -0
  164. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs.map +2 -2
  165. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +5 -1
  166. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +2 -2
  167. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +1 -1
  168. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
  169. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +22 -31
  170. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  171. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs +1 -3
  172. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +2 -2
  173. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +4 -1
  174. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  175. package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs +10 -0
  176. package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs.map +2 -2
  177. package/dist-esm/lib/ui/TldrawUi.mjs +2 -3
  178. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  179. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +2 -12
  180. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  181. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +7 -2
  182. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
  183. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs +1 -1
  184. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs.map +2 -2
  185. package/dist-esm/lib/ui/components/Dialogs.mjs +9 -1
  186. package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
  187. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +5 -5
  188. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
  189. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +5 -22
  190. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  191. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs +1 -2
  192. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs.map +2 -2
  193. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs +2 -0
  194. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +2 -2
  195. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +1 -0
  196. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  197. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +10 -8
  198. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  199. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +20 -1
  200. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  201. package/dist-esm/lib/ui/context/actions.mjs +8 -8
  202. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  203. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +2 -0
  204. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  205. package/dist-esm/lib/ui/hooks/useCommentingEnabled.mjs +2 -2
  206. package/dist-esm/lib/ui/hooks/useCommentingEnabled.mjs.map +2 -2
  207. package/dist-esm/lib/ui/hooks/useFlatten.mjs +42 -23
  208. package/dist-esm/lib/ui/hooks/useFlatten.mjs.map +2 -2
  209. package/dist-esm/lib/ui/version.mjs +3 -3
  210. package/dist-esm/lib/ui/version.mjs.map +1 -1
  211. package/package.json +12 -6
  212. package/src/lib/defaultExternalContentHandlers.test.ts +43 -0
  213. package/src/lib/defaultExternalContentHandlers.ts +40 -18
  214. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +17 -0
  215. package/src/lib/shapes/arrow/curved-arrow.ts +2 -2
  216. package/src/lib/shapes/arrow/elbow/getElbowArrowInfo.tsx +5 -3
  217. package/src/lib/shapes/arrow/getArrowInfo.ts +2 -1
  218. package/src/lib/shapes/arrow/straight-arrow.ts +2 -2
  219. package/src/lib/shapes/arrow/toolStates/Idle.tsx +3 -4
  220. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +10 -6
  221. package/src/lib/shapes/draw/DrawShapeTool.test.ts +19 -0
  222. package/src/lib/shapes/draw/toolStates/Drawing.ts +12 -6
  223. package/src/lib/shapes/frame/FrameShapeTool.test.ts +17 -0
  224. package/src/lib/shapes/geo/GeoShapeTool.test.ts +28 -0
  225. package/src/lib/shapes/geo/getGeoShapePath.ts +3 -1
  226. package/src/lib/shapes/geo/toolStates/Idle.ts +3 -4
  227. package/src/lib/shapes/geo/toolStates/Pointing.ts +2 -1
  228. package/src/lib/shapes/line/LineShapeTool.test.ts +30 -1
  229. package/src/lib/shapes/line/toolStates/Pointing.ts +6 -7
  230. package/src/lib/shapes/note/NoteShapeTool.test.ts +45 -0
  231. package/src/lib/shapes/note/NoteShapeUtil.tsx +7 -4
  232. package/src/lib/shapes/note/noteHelpers.ts +18 -8
  233. package/src/lib/shapes/note/toolStates/Pointing.ts +2 -1
  234. package/src/lib/shapes/shared/crop.ts +7 -1
  235. package/src/lib/shapes/text/TextShapeTool.test.ts +33 -0
  236. package/src/lib/shapes/text/toolStates/Idle.ts +2 -2
  237. package/src/lib/shapes/text/toolStates/Pointing.ts +3 -0
  238. package/src/lib/shapes/video/VideoShapeUtil.tsx +4 -2
  239. package/src/lib/tools/EraserTool/childStates/Erasing.ts +5 -0
  240. package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +10 -0
  241. package/src/lib/tools/SelectTool/SelectTool.ts +4 -0
  242. package/src/lib/tools/SelectTool/childStates/Brushing.ts +4 -0
  243. package/src/lib/tools/SelectTool/childStates/Crop/Crop.ts +4 -0
  244. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +3 -4
  245. package/src/lib/tools/SelectTool/childStates/Idle.ts +10 -3
  246. package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +1 -1
  247. package/src/lib/tools/SelectTool/childStates/PointingCanvas.ts +4 -0
  248. package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +6 -1
  249. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +4 -1
  250. package/src/lib/tools/SelectTool/childStates/Resizing.ts +30 -33
  251. package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +3 -3
  252. package/src/lib/tools/SelectTool/childStates/Translating.ts +6 -0
  253. package/src/lib/tools/SelectTool/selectHelpers.ts +21 -0
  254. package/src/lib/ui/TldrawUi.tsx +1 -2
  255. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +4 -14
  256. package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +8 -2
  257. package/src/lib/ui/components/ContextMenu/DefaultContextMenuContent.tsx +5 -1
  258. package/src/lib/ui/components/Dialogs.tsx +17 -1
  259. package/src/lib/ui/components/EditLinkDialog.tsx +8 -7
  260. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +5 -23
  261. package/src/lib/ui/components/SharePanel/DefaultPeopleMenuItem.tsx +2 -3
  262. package/src/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.tsx +2 -0
  263. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +1 -0
  264. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +13 -8
  265. package/src/lib/ui/components/primitives/TldrawUiSlider.test.tsx +92 -0
  266. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +25 -1
  267. package/src/lib/ui/context/actions.tsx +25 -8
  268. package/src/lib/ui/hooks/useClipboardEvents.ts +2 -0
  269. package/src/lib/ui/hooks/useCommentingEnabled.ts +5 -3
  270. package/src/lib/ui/hooks/useFlatten.ts +56 -23
  271. package/src/lib/ui/version.ts +3 -3
  272. package/src/lib/ui.css +7 -16
  273. package/src/test/ClickManager.test.ts +18 -0
  274. package/src/test/Editor.test.tsx +3 -0
  275. package/src/test/EraserTool.test.ts +18 -2
  276. package/src/test/HandTool.test.ts +21 -0
  277. package/src/test/LaserTool.test.ts +46 -0
  278. package/src/test/ScribbleManager.test.ts +19 -0
  279. package/src/test/SelectTool.test.ts +110 -0
  280. package/src/test/TldrawEditor.test.tsx +18 -0
  281. package/src/test/VideoShapeUtil.test.tsx +126 -0
  282. package/src/test/actions-menu-readonly.test.tsx +37 -0
  283. package/src/test/bookmark-shapes.test.ts +110 -0
  284. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +6 -6
  285. package/src/test/commands/clipboard.test.ts +36 -1
  286. package/src/test/commands/lockShapes.test.ts +11 -0
  287. package/src/test/commands/packShapes.test.ts +20 -0
  288. package/src/test/commands/putContent.test.ts +35 -1
  289. package/src/test/commands/setCamera.test.ts +69 -0
  290. package/src/test/commands/stackShapes.test.ts +12 -0
  291. package/src/test/commands/updateViewportPageBounds.test.ts +8 -0
  292. package/src/test/cropping.test.ts +162 -0
  293. package/src/test/customSnapping.test.tsx +32 -0
  294. package/src/test/defaultHandleExternalFileContent.test.ts +86 -0
  295. package/src/test/drawing.test.ts +60 -1
  296. package/src/test/duplicate.test.ts +22 -0
  297. package/src/test/flatten.test.ts +135 -0
  298. package/src/test/frames.test.ts +51 -0
  299. package/src/test/getShapeAtPoint.test.ts +44 -1
  300. package/src/test/handleDeepLink.test.tsx +15 -0
  301. package/src/test/minimap-wheel.test.tsx +48 -0
  302. package/src/test/resizing.test.ts +46 -0
  303. package/src/test/selection-omnibus.test.ts +50 -0
  304. package/src/test/spacebarPanning.test.ts +58 -0
  305. package/src/test/translating.test.ts +42 -0
  306. package/src/test/ui/AltTextEditor.test.tsx +51 -0
  307. package/src/test/ui/ContextMenu.test.tsx +61 -2
  308. package/src/test/ui/EditLinkDialog.test.tsx +77 -0
  309. package/src/test/ui/ImageToolbar.test.tsx +58 -0
  310. package/src/test/ui/StylePanel.test.tsx +33 -2
  311. package/src/test/ui/keyboardShortcuts.test.tsx +27 -0
  312. package/src/test/ui/presenceActivity.test.tsx +44 -0
  313. package/src/test/ui/unlockAll.test.tsx +55 -0
  314. package/src/test/ui-outside-editor.test.tsx +74 -0
  315. package/src/test/viewport-following.test.ts +29 -1
  316. package/tldraw.css +7 -16
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/shapes/text/toolStates/Pointing.ts"],
4
- "sourcesContent": ["import {\n\tStateNode,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tTLTextShape,\n\tVec,\n\tcreateShapeId,\n\tisShapeId,\n\tmaybeSnapToGrid,\n\ttoRichText,\n} from '@tldraw/editor'\nimport { startEditingShapeWithRichText } from '../../../tools/SelectTool/selectHelpers'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\tshape?: TLTextShape\n\n\tmarkId = ''\n\n\tenterTime = 0\n\toverride onEnter(): void {\n\t\tthis.enterTime = Date.now()\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setHintingShapes([])\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\t// Create a fixed width shape if the user wants to do that.\n\n\t\t// Don't create a fixed width shape unless the the drag is a little larger,\n\t\t// otherwise you get a vertical column of single characters if you accidentally\n\t\t// drag a bit unintentionally.\n\n\t\t// If the user hasn't been pointing for more than 150ms, don't create a fixed width shape\n\t\tif (Date.now() - this.enterTime < 150) return\n\n\t\tconst { editor } = this\n\t\tconst isPointing = editor.inputs.getIsPointing()\n\n\t\tif (!isPointing) return\n\n\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\n\t\tconst currentDragDist = Math.abs(originPagePoint.x - currentPagePoint.x)\n\n\t\tconst baseMinDragDistForFixedWidth = Math.sqrt(\n\t\t\teditor.getInstanceState().isCoarsePointer\n\t\t\t\t? editor.options.coarseDragDistanceSquared\n\t\t\t\t: editor.options.dragDistanceSquared\n\t\t)\n\n\t\t// Ten times the base drag distance for fixed width\n\t\tconst minSquaredDragDist = (baseMinDragDistForFixedWidth * 6) / editor.getZoomLevel()\n\n\t\tif (currentDragDist > minSquaredDragDist) {\n\t\t\tconst id = createShapeId()\n\t\t\tthis.markId = editor.markHistoryStoppingPoint(`creating_text:${id}`)\n\n\t\t\t// create the initial shape with the width that we've dragged\n\t\t\tconst shape = this.createTextShape(id, originPagePoint, false, currentDragDist)\n\n\t\t\tif (!shape) {\n\t\t\t\tthis.cancel()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Now save the fresh reference\n\t\t\tthis.shape = editor.getShape(shape)\n\n\t\t\teditor.select(id)\n\n\t\t\tconst scale = this.editor.getResizeScaleFactor()\n\n\t\t\teditor.setCurrentTool('select.resizing', {\n\t\t\t\t...info,\n\t\t\t\ttarget: 'selection',\n\t\t\t\thandle: 'right',\n\t\t\t\tisCreating: true,\n\t\t\t\tcreatingMarkId: this.markId,\n\t\t\t\t// Make sure the cursor offset takes into account how far we've already dragged\n\t\t\t\tcreationCursorOffset: { x: currentDragDist * scale, y: 1 },\n\t\t\t\tonInteractionEnd: 'text',\n\t\t\t\tonCreate: () => {\n\t\t\t\t\tstartEditingShapeWithRichText(editor, shape.id)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\t// On a touch (coarse pointer) long-press, cancel the pending shape so it leaves nothing behind.\n\t\tif (this.editor.getInstanceState().isCoarsePointer) this.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.cancel()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate complete() {\n\t\tthis.editor.markHistoryStoppingPoint('creating text shape')\n\t\tconst id = createShapeId()\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tconst shape = this.createTextShape(id, originPagePoint, true, 20)\n\t\tif (!shape) return\n\n\t\tthis.editor.select(id)\n\t\tstartEditingShapeWithRichText(this.editor, id)\n\t}\n\n\tprivate cancel() {\n\t\tthis.parent.transition('idle')\n\t\tthis.editor.bailToMark(this.markId)\n\t}\n\n\tprivate createTextShape(id: TLShapeId, point: Vec, autoSize: boolean, width: number) {\n\t\tthis.editor.createShape({\n\t\t\tid,\n\t\t\ttype: 'text',\n\t\t\tx: point.x,\n\t\t\ty: point.y,\n\t\t\tprops: {\n\t\t\t\trichText: toRichText(''),\n\t\t\t\tautoSize,\n\t\t\t\tw: width,\n\t\t\t\tscale: this.editor.getResizeScaleFactor(),\n\t\t\t},\n\t\t})\n\n\t\tconst shape = this.editor.getShape<TLTextShape>(id)\n\t\tif (!shape) {\n\t\t\tthis.cancel()\n\t\t\treturn\n\t\t}\n\n\t\tconst bounds = this.editor.getShapePageBounds(shape)!\n\n\t\tconst delta = new Vec()\n\n\t\tif (autoSize) {\n\t\t\tswitch (shape.props.textAlign) {\n\t\t\t\tcase 'start': {\n\t\t\t\t\tdelta.x = 0\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'middle': {\n\t\t\t\t\tdelta.x = -bounds.width / 2\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'end': {\n\t\t\t\t\tdelta.x = -bounds.width\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tdelta.x = 0\n\t\t}\n\n\t\tdelta.y = -bounds.height / 2\n\n\t\tif (isShapeId(shape.parentId)) {\n\t\t\tconst transform = this.editor.getShapeParentTransform(shape)\n\t\t\tdelta.rot(-transform.rotation())\n\t\t}\n\n\t\tconst shapeX = shape.x + delta.x\n\t\tconst shapeY = shape.y + delta.y\n\t\tif (this.editor.getInstanceState().isGridMode) {\n\t\t\tconst topLeft = new Vec(shapeX, shapeY)\n\t\t\tconst gridSnappedPoint = maybeSnapToGrid(topLeft, this.editor)\n\t\t\tconst gridDelta = Vec.Sub(topLeft, gridSnappedPoint)\n\t\t\tthis.editor.updateShape({\n\t\t\t\t...shape,\n\t\t\t\tx: shapeX - gridDelta.x,\n\t\t\t\ty: shapeY - gridDelta.y,\n\t\t\t})\n\t\t} else {\n\t\t\tthis.editor.updateShape({\n\t\t\t\t...shape,\n\t\t\t\tx: shapeX,\n\t\t\t\ty: shapeY,\n\t\t\t})\n\t\t}\n\n\t\treturn shape\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tStateNode,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tTLTextShape,\n\tVec,\n\tcreateShapeId,\n\tisShapeId,\n\tmaybeSnapToGrid,\n\ttoRichText,\n} from '@tldraw/editor'\nimport { startEditingShapeWithRichText } from '../../../tools/SelectTool/selectHelpers'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\tshape?: TLTextShape\n\n\tmarkId = ''\n\n\tenterTime = 0\n\toverride onEnter(): void {\n\t\tthis.enterTime = Date.now()\n\t\t// Only the drag-to-create path sets a mark. Without this reset, a later cancel\n\t\t// would bail to a mark left over from a previous text shape and undo unrelated work.\n\t\tthis.markId = ''\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setHintingShapes([])\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\t// Create a fixed width shape if the user wants to do that.\n\n\t\t// Don't create a fixed width shape unless the the drag is a little larger,\n\t\t// otherwise you get a vertical column of single characters if you accidentally\n\t\t// drag a bit unintentionally.\n\n\t\t// If the user hasn't been pointing for more than 150ms, don't create a fixed width shape\n\t\tif (Date.now() - this.enterTime < 150) return\n\n\t\tconst { editor } = this\n\t\tconst isPointing = editor.inputs.getIsPointing()\n\n\t\tif (!isPointing) return\n\n\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\n\t\tconst currentDragDist = Math.abs(originPagePoint.x - currentPagePoint.x)\n\n\t\tconst baseMinDragDistForFixedWidth = Math.sqrt(\n\t\t\teditor.getInstanceState().isCoarsePointer\n\t\t\t\t? editor.options.coarseDragDistanceSquared\n\t\t\t\t: editor.options.dragDistanceSquared\n\t\t)\n\n\t\t// Ten times the base drag distance for fixed width\n\t\tconst minSquaredDragDist = (baseMinDragDistForFixedWidth * 6) / editor.getZoomLevel()\n\n\t\tif (currentDragDist > minSquaredDragDist) {\n\t\t\tconst id = createShapeId()\n\t\t\tthis.markId = editor.markHistoryStoppingPoint(`creating_text:${id}`)\n\n\t\t\t// create the initial shape with the width that we've dragged\n\t\t\tconst shape = this.createTextShape(id, originPagePoint, false, currentDragDist)\n\n\t\t\tif (!shape) {\n\t\t\t\tthis.cancel()\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Now save the fresh reference\n\t\t\tthis.shape = editor.getShape(shape)\n\n\t\t\teditor.select(id)\n\n\t\t\tconst scale = this.editor.getResizeScaleFactor()\n\n\t\t\teditor.setCurrentTool('select.resizing', {\n\t\t\t\t...info,\n\t\t\t\ttarget: 'selection',\n\t\t\t\thandle: 'right',\n\t\t\t\tisCreating: true,\n\t\t\t\tcreatingMarkId: this.markId,\n\t\t\t\t// Make sure the cursor offset takes into account how far we've already dragged\n\t\t\t\tcreationCursorOffset: { x: currentDragDist * scale, y: 1 },\n\t\t\t\tonInteractionEnd: 'text',\n\t\t\t\tonCreate: () => {\n\t\t\t\t\tstartEditingShapeWithRichText(editor, shape.id)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onLongPress() {\n\t\t// On a touch (coarse pointer) long-press, cancel the pending shape so it leaves nothing behind.\n\t\tif (this.editor.getInstanceState().isCoarsePointer) this.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.cancel()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate complete() {\n\t\tthis.editor.markHistoryStoppingPoint('creating text shape')\n\t\tconst id = createShapeId()\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tconst shape = this.createTextShape(id, originPagePoint, true, 20)\n\t\tif (!shape) return\n\n\t\tthis.editor.select(id)\n\t\tstartEditingShapeWithRichText(this.editor, id)\n\t}\n\n\tprivate cancel() {\n\t\tthis.parent.transition('idle')\n\t\tthis.editor.bailToMark(this.markId)\n\t}\n\n\tprivate createTextShape(id: TLShapeId, point: Vec, autoSize: boolean, width: number) {\n\t\tthis.editor.createShape({\n\t\t\tid,\n\t\t\ttype: 'text',\n\t\t\tx: point.x,\n\t\t\ty: point.y,\n\t\t\tprops: {\n\t\t\t\trichText: toRichText(''),\n\t\t\t\tautoSize,\n\t\t\t\tw: width,\n\t\t\t\tscale: this.editor.getResizeScaleFactor(),\n\t\t\t},\n\t\t})\n\n\t\tconst shape = this.editor.getShape<TLTextShape>(id)\n\t\tif (!shape) {\n\t\t\tthis.cancel()\n\t\t\treturn\n\t\t}\n\n\t\tconst bounds = this.editor.getShapePageBounds(shape)!\n\n\t\tconst delta = new Vec()\n\n\t\tif (autoSize) {\n\t\t\tswitch (shape.props.textAlign) {\n\t\t\t\tcase 'start': {\n\t\t\t\t\tdelta.x = 0\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'middle': {\n\t\t\t\t\tdelta.x = -bounds.width / 2\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t\tcase 'end': {\n\t\t\t\t\tdelta.x = -bounds.width\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tdelta.x = 0\n\t\t}\n\n\t\tdelta.y = -bounds.height / 2\n\n\t\tif (isShapeId(shape.parentId)) {\n\t\t\tconst transform = this.editor.getShapeParentTransform(shape)\n\t\t\tdelta.rot(-transform.rotation())\n\t\t}\n\n\t\tconst shapeX = shape.x + delta.x\n\t\tconst shapeY = shape.y + delta.y\n\t\tif (this.editor.getInstanceState().isGridMode) {\n\t\t\tconst topLeft = new Vec(shapeX, shapeY)\n\t\t\tconst gridSnappedPoint = maybeSnapToGrid(topLeft, this.editor)\n\t\t\tconst gridDelta = Vec.Sub(topLeft, gridSnappedPoint)\n\t\t\tthis.editor.updateShape({\n\t\t\t\t...shape,\n\t\t\t\tx: shapeX - gridDelta.x,\n\t\t\t\ty: shapeY - gridDelta.y,\n\t\t\t})\n\t\t} else {\n\t\t\tthis.editor.updateShape({\n\t\t\t\t...shape,\n\t\t\t\tx: shapeX,\n\t\t\t\ty: shapeY,\n\t\t\t})\n\t\t}\n\n\t\treturn shape\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -148,6 +148,7 @@ const VideoShape = (0, import_react.memo)(function VideoShape2({ shape }) {
148
148
  }
149
149
  }
150
150
  }, [isEditing, isLoaded]);
151
+ const hasVideo = !!asset?.props.src && !!url && isLoaded;
151
152
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
152
153
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
153
154
  import_editor.HTMLContainer,
@@ -155,8 +156,8 @@ const VideoShape = (0, import_react.memo)(function VideoShape2({ shape }) {
155
156
  id: shape.id,
156
157
  style: {
157
158
  color: "var(--tl-color-text-3)",
158
- backgroundColor: asset ? "transparent" : "var(--tl-color-low)",
159
- border: asset ? "none" : "1px solid var(--tl-color-low-border)"
159
+ backgroundColor: hasVideo ? "transparent" : "var(--tl-color-low)",
160
+ border: hasVideo ? "none" : "1px solid var(--tl-color-low-border)"
160
161
  },
161
162
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tl-counter-scaled", children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tl-video-container", children: !asset ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(import_BrokenAssetIcon.BrokenAssetIcon, {}) : Spinner && !asset.props.src ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(Spinner, {}) : url ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
162
163
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/video/VideoShapeUtil.tsx"],
4
- "sourcesContent": ["import {\n\tBaseBoxShapeUtil,\n\tHTMLContainer,\n\tMediaHelpers,\n\tSvgExportContext,\n\tTLAsset,\n\tTLShapePartial,\n\tTLVideoAsset,\n\tTLVideoShape,\n\tVecModel,\n\tWeakCache,\n\tcreateShapeId,\n\tuseEditor,\n\tuseEditorComponents,\n\tuseIsEditing,\n\tvideoShapeMigrations,\n\tvideoShapeProps,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { ReactEventHandler, memo, useCallback, useEffect, useRef, useState } from 'react'\nimport { BrokenAssetIcon } from '../shared/BrokenAssetIcon'\nimport type { ShapeOptionsWithDisplayValues } from '../shared/getDisplayValues'\nimport { HyperlinkButton } from '../shared/HyperlinkButton'\nimport { useImageOrVideoAsset } from '../shared/useImageOrVideoAsset'\nimport { usePrefersReducedMotion } from '../shared/usePrefersReducedMotion'\n\nconst videoSvgExportCache = new WeakCache<TLAsset, Promise<string | null>>()\n\n/** @public */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface VideoShapeUtilDisplayValues {}\n\n/** @public */\nexport interface VideoShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLVideoShape,\n\tVideoShapeUtilDisplayValues\n> {\n\t/**\n\t * Should videos play automatically?\n\t */\n\tautoplay: boolean\n}\n\n/** @public */\nexport class VideoShapeUtil extends BaseBoxShapeUtil<TLVideoShape> {\n\tstatic override type = 'video' as const\n\tstatic override props = videoShapeProps\n\tstatic override migrations = videoShapeMigrations\n\tstatic override handledAssetTypes = ['video'] as const\n\n\toverride options: VideoShapeOptions = {\n\t\tautoplay: true,\n\t\tgetDefaultDisplayValues(): VideoShapeUtilDisplayValues {\n\t\t\treturn {}\n\t\t},\n\t\tgetCustomDisplayValues(): Partial<VideoShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride canEdit(shape: TLVideoShape) {\n\t\treturn true\n\t}\n\toverride isAspectRatioLocked(shape: TLVideoShape) {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLVideoShape['props'] {\n\t\treturn {\n\t\t\tw: 100,\n\t\t\th: 100,\n\t\t\tassetId: null,\n\t\t\tautoplay: this.options.autoplay,\n\t\t\turl: '',\n\t\t\taltText: '',\n\t\t\t// Not used, but once upon a time were used to sync video state between users\n\t\t\ttime: 0,\n\t\t\tplaying: true,\n\t\t}\n\t}\n\n\toverride createShapeForAsset(asset: TLAsset, position: VecModel): TLShapePartial | null {\n\t\tconst videoAsset = asset as TLVideoAsset\n\t\treturn {\n\t\t\tid: createShapeId(),\n\t\t\ttype: 'video',\n\t\t\tx: position.x,\n\t\t\ty: position.y,\n\t\t\topacity: 1,\n\t\t\tprops: {\n\t\t\t\tassetId: videoAsset.id,\n\t\t\t\tw: videoAsset.props.w,\n\t\t\t\th: videoAsset.props.h,\n\t\t\t},\n\t\t}\n\t}\n\n\toverride getAriaDescriptor(shape: TLVideoShape) {\n\t\treturn shape.props.altText\n\t}\n\n\tcomponent(shape: TLVideoShape) {\n\t\treturn <VideoShape shape={shape} />\n\t}\n\n\toverride getIndicatorPath(shape: TLVideoShape): Path2D {\n\t\tconst path = new Path2D()\n\t\tpath.rect(0, 0, shape.props.w, shape.props.h)\n\t\treturn path\n\t}\n\n\toverride async toSvg(shape: TLVideoShape, ctx: SvgExportContext) {\n\t\tconst props = shape.props\n\t\tif (!props.assetId) return null\n\n\t\tconst asset = this.editor.getAsset<TLAsset>(props.assetId)\n\t\tif (!asset) return null\n\n\t\tconst src = await videoSvgExportCache.get(asset, async () => {\n\t\t\tconst assetUrl = await ctx.resolveAssetUrl(asset.id, props.w)\n\t\t\tif (!assetUrl) return null\n\t\t\tconst video = await MediaHelpers.loadVideo(assetUrl, this.editor.getContainerDocument())\n\t\t\treturn await MediaHelpers.getVideoFrameAsDataUrl(video, 0)\n\t\t})\n\n\t\tif (!src) return null\n\n\t\treturn <image href={src} width={props.w} height={props.h} aria-label={shape.props.altText} />\n\t}\n}\n\nconst VideoShape = memo(function VideoShape({ shape }: { shape: TLVideoShape }) {\n\tconst editor = useEditor()\n\tconst showControls =\n\t\teditor.getShapeGeometry(shape).bounds.w * editor.getEfficientZoomLevel() >= 110\n\tconst isEditing = useIsEditing(shape.id)\n\tconst prefersReducedMotion = usePrefersReducedMotion()\n\tconst { Spinner } = useEditorComponents()\n\n\tconst { asset, url } = useImageOrVideoAsset({\n\t\tshapeId: shape.id,\n\t\tassetId: shape.props.assetId,\n\t\twidth: shape.props.w,\n\t})\n\n\tconst rVideo = useRef<HTMLVideoElement>(null!)\n\n\tconst [isLoaded, setIsLoaded] = useState(false)\n\n\tconst handleLoadedData = useCallback<ReactEventHandler<HTMLVideoElement>>((e) => {\n\t\tconst video = e.currentTarget\n\t\tif (!video) return\n\t\tsetIsLoaded(true)\n\t}, [])\n\n\tconst [isFullscreen, setIsFullscreen] = useState(false)\n\n\tuseEffect(() => {\n\t\tconst doc = rVideo.current?.ownerDocument ?? editor.getContainerDocument()\n\t\tconst fullscreenChange = () => setIsFullscreen(doc.fullscreenElement === rVideo.current)\n\t\tdoc.addEventListener('fullscreenchange', fullscreenChange)\n\n\t\treturn () => doc.removeEventListener('fullscreenchange', fullscreenChange)\n\t})\n\n\t// Focus the video when editing\n\tuseEffect(() => {\n\t\tconst video = rVideo.current\n\t\tif (!video) return\n\n\t\tif (isEditing) {\n\t\t\tif (video.ownerDocument.activeElement !== video) {\n\t\t\t\tvideo.focus()\n\t\t\t}\n\t\t}\n\t}, [isEditing, isLoaded])\n\n\treturn (\n\t\t<>\n\t\t\t<HTMLContainer\n\t\t\t\tid={shape.id}\n\t\t\t\tstyle={{\n\t\t\t\t\tcolor: 'var(--tl-color-text-3)',\n\t\t\t\t\tbackgroundColor: asset ? 'transparent' : 'var(--tl-color-low)',\n\t\t\t\t\tborder: asset ? 'none' : '1px solid var(--tl-color-low-border)',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className=\"tl-counter-scaled\">\n\t\t\t\t\t<div className=\"tl-video-container\">\n\t\t\t\t\t\t{!asset ? (\n\t\t\t\t\t\t\t<BrokenAssetIcon />\n\t\t\t\t\t\t) : Spinner && !asset.props.src ? (\n\t\t\t\t\t\t\t<Spinner />\n\t\t\t\t\t\t) : url ? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<video\n\t\t\t\t\t\t\t\t\tkey={url}\n\t\t\t\t\t\t\t\t\tref={rVideo}\n\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\tisEditing\n\t\t\t\t\t\t\t\t\t\t\t? { pointerEvents: 'all' }\n\t\t\t\t\t\t\t\t\t\t\t: !isLoaded\n\t\t\t\t\t\t\t\t\t\t\t\t? { display: 'none' }\n\t\t\t\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tclassName={classNames('tl-video', `tl-video-shape-${shape.id.split(':')[1]}`, {\n\t\t\t\t\t\t\t\t\t\t'tl-video-is-fullscreen': isFullscreen,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\theight=\"100%\"\n\t\t\t\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t\t\t\tplaysInline\n\t\t\t\t\t\t\t\t\tautoPlay={shape.props.autoplay && !prefersReducedMotion}\n\t\t\t\t\t\t\t\t\tmuted\n\t\t\t\t\t\t\t\t\tloop\n\t\t\t\t\t\t\t\t\tdisableRemotePlayback\n\t\t\t\t\t\t\t\t\tdisablePictureInPicture\n\t\t\t\t\t\t\t\t\tcontrols={isEditing && showControls}\n\t\t\t\t\t\t\t\t\tonLoadedData={handleLoadedData}\n\t\t\t\t\t\t\t\t\thidden={!isLoaded}\n\t\t\t\t\t\t\t\t\taria-label={shape.props.altText}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<source src={url} />\n\t\t\t\t\t\t\t\t</video>\n\t\t\t\t\t\t\t\t{!isLoaded && Spinner && <Spinner />}\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</HTMLContainer>\n\t\t\t{'url' in shape.props && shape.props.url && <HyperlinkButton url={shape.props.url} />}\n\t\t</>\n\t)\n})\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tBaseBoxShapeUtil,\n\tHTMLContainer,\n\tMediaHelpers,\n\tSvgExportContext,\n\tTLAsset,\n\tTLShapePartial,\n\tTLVideoAsset,\n\tTLVideoShape,\n\tVecModel,\n\tWeakCache,\n\tcreateShapeId,\n\tuseEditor,\n\tuseEditorComponents,\n\tuseIsEditing,\n\tvideoShapeMigrations,\n\tvideoShapeProps,\n} from '@tldraw/editor'\nimport classNames from 'classnames'\nimport { ReactEventHandler, memo, useCallback, useEffect, useRef, useState } from 'react'\nimport { BrokenAssetIcon } from '../shared/BrokenAssetIcon'\nimport type { ShapeOptionsWithDisplayValues } from '../shared/getDisplayValues'\nimport { HyperlinkButton } from '../shared/HyperlinkButton'\nimport { useImageOrVideoAsset } from '../shared/useImageOrVideoAsset'\nimport { usePrefersReducedMotion } from '../shared/usePrefersReducedMotion'\n\nconst videoSvgExportCache = new WeakCache<TLAsset, Promise<string | null>>()\n\n/** @public */\n// eslint-disable-next-line @typescript-eslint/no-empty-object-type\nexport interface VideoShapeUtilDisplayValues {}\n\n/** @public */\nexport interface VideoShapeOptions extends ShapeOptionsWithDisplayValues<\n\tTLVideoShape,\n\tVideoShapeUtilDisplayValues\n> {\n\t/**\n\t * Should videos play automatically?\n\t */\n\tautoplay: boolean\n}\n\n/** @public */\nexport class VideoShapeUtil extends BaseBoxShapeUtil<TLVideoShape> {\n\tstatic override type = 'video' as const\n\tstatic override props = videoShapeProps\n\tstatic override migrations = videoShapeMigrations\n\tstatic override handledAssetTypes = ['video'] as const\n\n\toverride options: VideoShapeOptions = {\n\t\tautoplay: true,\n\t\tgetDefaultDisplayValues(): VideoShapeUtilDisplayValues {\n\t\t\treturn {}\n\t\t},\n\t\tgetCustomDisplayValues(): Partial<VideoShapeUtilDisplayValues> {\n\t\t\treturn {}\n\t\t},\n\t}\n\n\toverride canEdit(shape: TLVideoShape) {\n\t\treturn true\n\t}\n\toverride isAspectRatioLocked(shape: TLVideoShape) {\n\t\treturn true\n\t}\n\n\toverride getDefaultProps(): TLVideoShape['props'] {\n\t\treturn {\n\t\t\tw: 100,\n\t\t\th: 100,\n\t\t\tassetId: null,\n\t\t\tautoplay: this.options.autoplay,\n\t\t\turl: '',\n\t\t\taltText: '',\n\t\t\t// Not used, but once upon a time were used to sync video state between users\n\t\t\ttime: 0,\n\t\t\tplaying: true,\n\t\t}\n\t}\n\n\toverride createShapeForAsset(asset: TLAsset, position: VecModel): TLShapePartial | null {\n\t\tconst videoAsset = asset as TLVideoAsset\n\t\treturn {\n\t\t\tid: createShapeId(),\n\t\t\ttype: 'video',\n\t\t\tx: position.x,\n\t\t\ty: position.y,\n\t\t\topacity: 1,\n\t\t\tprops: {\n\t\t\t\tassetId: videoAsset.id,\n\t\t\t\tw: videoAsset.props.w,\n\t\t\t\th: videoAsset.props.h,\n\t\t\t},\n\t\t}\n\t}\n\n\toverride getAriaDescriptor(shape: TLVideoShape) {\n\t\treturn shape.props.altText\n\t}\n\n\tcomponent(shape: TLVideoShape) {\n\t\treturn <VideoShape shape={shape} />\n\t}\n\n\toverride getIndicatorPath(shape: TLVideoShape): Path2D {\n\t\tconst path = new Path2D()\n\t\tpath.rect(0, 0, shape.props.w, shape.props.h)\n\t\treturn path\n\t}\n\n\toverride async toSvg(shape: TLVideoShape, ctx: SvgExportContext) {\n\t\tconst props = shape.props\n\t\tif (!props.assetId) return null\n\n\t\tconst asset = this.editor.getAsset<TLAsset>(props.assetId)\n\t\tif (!asset) return null\n\n\t\tconst src = await videoSvgExportCache.get(asset, async () => {\n\t\t\tconst assetUrl = await ctx.resolveAssetUrl(asset.id, props.w)\n\t\t\tif (!assetUrl) return null\n\t\t\tconst video = await MediaHelpers.loadVideo(assetUrl, this.editor.getContainerDocument())\n\t\t\treturn await MediaHelpers.getVideoFrameAsDataUrl(video, 0)\n\t\t})\n\n\t\tif (!src) return null\n\n\t\treturn <image href={src} width={props.w} height={props.h} aria-label={shape.props.altText} />\n\t}\n}\n\nconst VideoShape = memo(function VideoShape({ shape }: { shape: TLVideoShape }) {\n\tconst editor = useEditor()\n\tconst showControls =\n\t\teditor.getShapeGeometry(shape).bounds.w * editor.getEfficientZoomLevel() >= 110\n\tconst isEditing = useIsEditing(shape.id)\n\tconst prefersReducedMotion = usePrefersReducedMotion()\n\tconst { Spinner } = useEditorComponents()\n\n\tconst { asset, url } = useImageOrVideoAsset({\n\t\tshapeId: shape.id,\n\t\tassetId: shape.props.assetId,\n\t\twidth: shape.props.w,\n\t})\n\n\tconst rVideo = useRef<HTMLVideoElement>(null!)\n\n\tconst [isLoaded, setIsLoaded] = useState(false)\n\n\tconst handleLoadedData = useCallback<ReactEventHandler<HTMLVideoElement>>((e) => {\n\t\tconst video = e.currentTarget\n\t\tif (!video) return\n\t\tsetIsLoaded(true)\n\t}, [])\n\n\tconst [isFullscreen, setIsFullscreen] = useState(false)\n\n\tuseEffect(() => {\n\t\tconst doc = rVideo.current?.ownerDocument ?? editor.getContainerDocument()\n\t\tconst fullscreenChange = () => setIsFullscreen(doc.fullscreenElement === rVideo.current)\n\t\tdoc.addEventListener('fullscreenchange', fullscreenChange)\n\n\t\treturn () => doc.removeEventListener('fullscreenchange', fullscreenChange)\n\t})\n\n\t// Focus the video when editing\n\tuseEffect(() => {\n\t\tconst video = rVideo.current\n\t\tif (!video) return\n\n\t\tif (isEditing) {\n\t\t\tif (video.ownerDocument.activeElement !== video) {\n\t\t\t\tvideo.focus()\n\t\t\t}\n\t\t}\n\t}, [isEditing, isLoaded])\n\n\tconst hasVideo = !!asset?.props.src && !!url && isLoaded\n\n\treturn (\n\t\t<>\n\t\t\t<HTMLContainer\n\t\t\t\tid={shape.id}\n\t\t\t\tstyle={{\n\t\t\t\t\tcolor: 'var(--tl-color-text-3)',\n\t\t\t\t\tbackgroundColor: hasVideo ? 'transparent' : 'var(--tl-color-low)',\n\t\t\t\t\tborder: hasVideo ? 'none' : '1px solid var(--tl-color-low-border)',\n\t\t\t\t}}\n\t\t\t>\n\t\t\t\t<div className=\"tl-counter-scaled\">\n\t\t\t\t\t<div className=\"tl-video-container\">\n\t\t\t\t\t\t{!asset ? (\n\t\t\t\t\t\t\t<BrokenAssetIcon />\n\t\t\t\t\t\t) : Spinner && !asset.props.src ? (\n\t\t\t\t\t\t\t<Spinner />\n\t\t\t\t\t\t) : url ? (\n\t\t\t\t\t\t\t<>\n\t\t\t\t\t\t\t\t<video\n\t\t\t\t\t\t\t\t\tkey={url}\n\t\t\t\t\t\t\t\t\tref={rVideo}\n\t\t\t\t\t\t\t\t\tstyle={\n\t\t\t\t\t\t\t\t\t\tisEditing\n\t\t\t\t\t\t\t\t\t\t\t? { pointerEvents: 'all' }\n\t\t\t\t\t\t\t\t\t\t\t: !isLoaded\n\t\t\t\t\t\t\t\t\t\t\t\t? { display: 'none' }\n\t\t\t\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tclassName={classNames('tl-video', `tl-video-shape-${shape.id.split(':')[1]}`, {\n\t\t\t\t\t\t\t\t\t\t'tl-video-is-fullscreen': isFullscreen,\n\t\t\t\t\t\t\t\t\t})}\n\t\t\t\t\t\t\t\t\twidth=\"100%\"\n\t\t\t\t\t\t\t\t\theight=\"100%\"\n\t\t\t\t\t\t\t\t\tdraggable={false}\n\t\t\t\t\t\t\t\t\tplaysInline\n\t\t\t\t\t\t\t\t\tautoPlay={shape.props.autoplay && !prefersReducedMotion}\n\t\t\t\t\t\t\t\t\tmuted\n\t\t\t\t\t\t\t\t\tloop\n\t\t\t\t\t\t\t\t\tdisableRemotePlayback\n\t\t\t\t\t\t\t\t\tdisablePictureInPicture\n\t\t\t\t\t\t\t\t\tcontrols={isEditing && showControls}\n\t\t\t\t\t\t\t\t\tonLoadedData={handleLoadedData}\n\t\t\t\t\t\t\t\t\thidden={!isLoaded}\n\t\t\t\t\t\t\t\t\taria-label={shape.props.altText}\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t<source src={url} />\n\t\t\t\t\t\t\t\t</video>\n\t\t\t\t\t\t\t\t{!isLoaded && Spinner && <Spinner />}\n\t\t\t\t\t\t\t</>\n\t\t\t\t\t\t) : null}\n\t\t\t\t\t</div>\n\t\t\t\t</div>\n\t\t\t</HTMLContainer>\n\t\t\t{'url' in shape.props && shape.props.url && <HyperlinkButton url={shape.props.url} />}\n\t\t</>\n\t)\n})\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAsGS;AAtGT,oBAiBO;AACP,wBAAuB;AACvB,mBAAkF;AAClF,6BAAgC;AAEhC,6BAAgC;AAChC,kCAAqC;AACrC,qCAAwC;AAExC,MAAM,sBAAsB,IAAI,wBAA2C;AAkBpE,MAAM,uBAAuB,+BAA+B;AAAA,EAClE,OAAgB,OAAO;AAAA,EACvB,OAAgB,QAAQ;AAAA,EACxB,OAAgB,aAAa;AAAA,EAC7B,OAAgB,oBAAoB,CAAC,OAAO;AAAA,EAEnC,UAA6B;AAAA,IACrC,UAAU;AAAA,IACV,0BAAuD;AACtD,aAAO,CAAC;AAAA,IACT;AAAA,IACA,yBAA+D;AAC9D,aAAO,CAAC;AAAA,IACT;AAAA,EACD;AAAA,EAES,QAAQ,OAAqB;AACrC,WAAO;AAAA,EACR;AAAA,EACS,oBAAoB,OAAqB;AACjD,WAAO;AAAA,EACR;AAAA,EAES,kBAAyC;AACjD,WAAO;AAAA,MACN,GAAG;AAAA,MACH,GAAG;AAAA,MACH,SAAS;AAAA,MACT,UAAU,KAAK,QAAQ;AAAA,MACvB,KAAK;AAAA,MACL,SAAS;AAAA;AAAA,MAET,MAAM;AAAA,MACN,SAAS;AAAA,IACV;AAAA,EACD;AAAA,EAES,oBAAoB,OAAgB,UAA2C;AACvF,UAAM,aAAa;AACnB,WAAO;AAAA,MACN,QAAI,6BAAc;AAAA,MAClB,MAAM;AAAA,MACN,GAAG,SAAS;AAAA,MACZ,GAAG,SAAS;AAAA,MACZ,SAAS;AAAA,MACT,OAAO;AAAA,QACN,SAAS,WAAW;AAAA,QACpB,GAAG,WAAW,MAAM;AAAA,QACpB,GAAG,WAAW,MAAM;AAAA,MACrB;AAAA,IACD;AAAA,EACD;AAAA,EAES,kBAAkB,OAAqB;AAC/C,WAAO,MAAM,MAAM;AAAA,EACpB;AAAA,EAEA,UAAU,OAAqB;AAC9B,WAAO,4CAAC,cAAW,OAAc;AAAA,EAClC;AAAA,EAES,iBAAiB,OAA6B;AACtD,UAAM,OAAO,IAAI,OAAO;AACxB,SAAK,KAAK,GAAG,GAAG,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC;AAC5C,WAAO;AAAA,EACR;AAAA,EAEA,MAAe,MAAM,OAAqB,KAAuB;AAChE,UAAM,QAAQ,MAAM;AACpB,QAAI,CAAC,MAAM,QAAS,QAAO;AAE3B,UAAM,QAAQ,KAAK,OAAO,SAAkB,MAAM,OAAO;AACzD,QAAI,CAAC,MAAO,QAAO;AAEnB,UAAM,MAAM,MAAM,oBAAoB,IAAI,OAAO,YAAY;AAC5D,YAAM,WAAW,MAAM,IAAI,gBAAgB,MAAM,IAAI,MAAM,CAAC;AAC5D,UAAI,CAAC,SAAU,QAAO;AACtB,YAAM,QAAQ,MAAM,2BAAa,UAAU,UAAU,KAAK,OAAO,qBAAqB,CAAC;AACvF,aAAO,MAAM,2BAAa,uBAAuB,OAAO,CAAC;AAAA,IAC1D,CAAC;AAED,QAAI,CAAC,IAAK,QAAO;AAEjB,WAAO,4CAAC,WAAM,MAAM,KAAK,OAAO,MAAM,GAAG,QAAQ,MAAM,GAAG,cAAY,MAAM,MAAM,SAAS;AAAA,EAC5F;AACD;AAEA,MAAM,iBAAa,mBAAK,SAASA,YAAW,EAAE,MAAM,GAA4B;AAC/E,QAAM,aAAS,yBAAU;AACzB,QAAM,eACL,OAAO,iBAAiB,KAAK,EAAE,OAAO,IAAI,OAAO,sBAAsB,KAAK;AAC7E,QAAM,gBAAY,4BAAa,MAAM,EAAE;AACvC,QAAM,2BAAuB,wDAAwB;AACrD,QAAM,EAAE,QAAQ,QAAI,mCAAoB;AAExC,QAAM,EAAE,OAAO,IAAI,QAAI,kDAAqB;AAAA,IAC3C,SAAS,MAAM;AAAA,IACf,SAAS,MAAM,MAAM;AAAA,IACrB,OAAO,MAAM,MAAM;AAAA,EACpB,CAAC;AAED,QAAM,aAAS,qBAAyB,IAAK;AAE7C,QAAM,CAAC,UAAU,WAAW,QAAI,uBAAS,KAAK;AAE9C,QAAM,uBAAmB,0BAAiD,CAAC,MAAM;AAChF,UAAM,QAAQ,EAAE;AAChB,QAAI,CAAC,MAAO;AACZ,gBAAY,IAAI;AAAA,EACjB,GAAG,CAAC,CAAC;AAEL,QAAM,CAAC,cAAc,eAAe,QAAI,uBAAS,KAAK;AAEtD,8BAAU,MAAM;AACf,UAAM,MAAM,OAAO,SAAS,iBAAiB,OAAO,qBAAqB;AACzE,UAAM,mBAAmB,MAAM,gBAAgB,IAAI,sBAAsB,OAAO,OAAO;AACvF,QAAI,iBAAiB,oBAAoB,gBAAgB;AAEzD,WAAO,MAAM,IAAI,oBAAoB,oBAAoB,gBAAgB;AAAA,EAC1E,CAAC;AAGD,8BAAU,MAAM;AACf,UAAM,QAAQ,OAAO;AACrB,QAAI,CAAC,MAAO;AAEZ,QAAI,WAAW;AACd,UAAI,MAAM,cAAc,kBAAkB,OAAO;AAChD,cAAM,MAAM;AAAA,MACb;AAAA,IACD;AAAA,EACD,GAAG,CAAC,WAAW,QAAQ,CAAC;AAExB,QAAM,WAAW,CAAC,CAAC,OAAO,MAAM,OAAO,CAAC,CAAC,OAAO;AAEhD,SACC,4EACC;AAAA;AAAA,MAAC;AAAA;AAAA,QACA,IAAI,MAAM;AAAA,QACV,OAAO;AAAA,UACN,OAAO;AAAA,UACP,iBAAiB,WAAW,gBAAgB;AAAA,UAC5C,QAAQ,WAAW,SAAS;AAAA,QAC7B;AAAA,QAEA,sDAAC,SAAI,WAAU,qBACd,sDAAC,SAAI,WAAU,sBACb,WAAC,QACD,4CAAC,0CAAgB,IACd,WAAW,CAAC,MAAM,MAAM,MAC3B,4CAAC,WAAQ,IACN,MACH,4EACC;AAAA;AAAA,YAAC;AAAA;AAAA,cAEA,KAAK;AAAA,cACL,OACC,YACG,EAAE,eAAe,MAAM,IACvB,CAAC,WACA,EAAE,SAAS,OAAO,IAClB;AAAA,cAEL,eAAW,kBAAAC,SAAW,YAAY,kBAAkB,MAAM,GAAG,MAAM,GAAG,EAAE,CAAC,CAAC,IAAI;AAAA,gBAC7E,0BAA0B;AAAA,cAC3B,CAAC;AAAA,cACD,OAAM;AAAA,cACN,QAAO;AAAA,cACP,WAAW;AAAA,cACX,aAAW;AAAA,cACX,UAAU,MAAM,MAAM,YAAY,CAAC;AAAA,cACnC,OAAK;AAAA,cACL,MAAI;AAAA,cACJ,uBAAqB;AAAA,cACrB,yBAAuB;AAAA,cACvB,UAAU,aAAa;AAAA,cACvB,cAAc;AAAA,cACd,QAAQ,CAAC;AAAA,cACT,cAAY,MAAM,MAAM;AAAA,cAExB,sDAAC,YAAO,KAAK,KAAK;AAAA;AAAA,YA1Bb;AAAA,UA2BN;AAAA,UACC,CAAC,YAAY,WAAW,4CAAC,WAAQ;AAAA,WACnC,IACG,MACL,GACD;AAAA;AAAA,IACD;AAAA,IACC,SAAS,MAAM,SAAS,MAAM,MAAM,OAAO,4CAAC,0CAAgB,KAAK,MAAM,MAAM,KAAK;AAAA,KACpF;AAEF,CAAC;",
6
6
  "names": ["VideoShape", "classNames"]
7
7
  }
@@ -34,9 +34,11 @@ class Erasing extends import_editor.StateNode {
34
34
  this.markId = this.editor.markHistoryStoppingPoint("erase scribble begin");
35
35
  this.info = info;
36
36
  const originPagePoint = this.editor.inputs.getOriginPagePoint();
37
+ const pressedShapeIds = new Set(this.editor.getErasingShapeIds());
37
38
  this.excludedShapeIds = new Set(
38
39
  this.editor.getCurrentPageShapes().filter((shape) => {
39
40
  if (this.editor.isShapeOrAncestorLocked(shape)) return true;
41
+ if (this.editor.isShapeFrameLike(shape) && pressedShapeIds.has(shape.id)) return false;
40
42
  if (this.editor.isShapeOfType(shape, "group") || this.editor.isShapeFrameLike(shape)) {
41
43
  const pointInShapeShape = this.editor.getPointInShapeSpace(shape, originPagePoint);
42
44
  const geometry = this.editor.getShapeGeometry(shape);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/EraserTool/childStates/Erasing.ts"],
4
- "sourcesContent": ["import { Box, StateNode, TLPointerEventInfo, TLShapeId, pointInPolygon } from '@tldraw/editor'\n\nexport class Erasing extends StateNode {\n\tstatic override id = 'erasing'\n\tstatic override trackPerformance = true\n\n\tprivate info = {} as TLPointerEventInfo\n\tprivate scribbleId = 'id'\n\tprivate markId = ''\n\tprivate excludedShapeIds = new Set<TLShapeId>()\n\n\t_erasingShapeIds: TLShapeId[] = []\n\n\toverride onEnter(info: TLPointerEventInfo) {\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('erase scribble begin')\n\t\tthis.info = info\n\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tthis.excludedShapeIds = new Set(\n\t\t\tthis.editor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter((shape) => {\n\t\t\t\t\t//If the shape is locked, we shouldn't erase it\n\t\t\t\t\tif (this.editor.isShapeOrAncestorLocked(shape)) return true\n\t\t\t\t\t//If the shape is a group or frame-like, check we're inside it when we start erasing\n\t\t\t\t\tif (this.editor.isShapeOfType(shape, 'group') || this.editor.isShapeFrameLike(shape)) {\n\t\t\t\t\t\tconst pointInShapeShape = this.editor.getPointInShapeSpace(shape, originPagePoint)\n\t\t\t\t\t\tconst geometry = this.editor.getShapeGeometry(shape)\n\t\t\t\t\t\treturn geometry.bounds.containsPoint(pointInShapeShape)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false\n\t\t\t\t})\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tthis._erasingShapeIds = this.editor\n\t\t\t.getShapesAtPoint(originPagePoint)\n\t\t\t.filter((s) => !this.excludedShapeIds.has(s.id))\n\t\t\t.map((s) => s.id)\n\n\t\tthis.editor.setErasingShapes([\n\t\t\t...new Set([...this.editor.getErasingShapeIds(), ...this._erasingShapeIds]),\n\t\t])\n\n\t\tconst scribble = this.editor.scribbles.addScribble({\n\t\t\tcolor: 'muted-1',\n\t\t\tsize: 12,\n\t\t})\n\t\tthis.scribbleId = scribble.id\n\n\t\tthis.update()\n\t}\n\n\tprivate pushPointToScribble() {\n\t\tconst { x, y } = this.editor.inputs.getCurrentPagePoint()\n\t\tthis.editor.scribbles.addPoint(this.scribbleId, x, y)\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setErasingShapes([])\n\t\tthis.editor.scribbles.stop(this.scribbleId)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp(info: TLPointerEventInfo) {\n\t\tthis.complete(info)\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\tupdate() {\n\t\tconst { editor, excludedShapeIds } = this\n\t\tconst erasingShapeIds = editor.getErasingShapeIds()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst previousPagePoint = editor.inputs.getPreviousPagePoint()\n\n\t\tthis.pushPointToScribble()\n\n\t\t// Otherwise, erasing shapes are all the shapes that were hit before plus any new shapes that are hit\n\t\tconst erasing = new Set<TLShapeId>(erasingShapeIds)\n\t\tconst minDist = this.editor.getHitTestMargin()\n\n\t\t// Create bounds around line segment with margin\n\t\tconst lineBounds = Box.FromPoints([previousPagePoint, currentPagePoint]).expandBy(minDist)\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(lineBounds)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageRenderingShapesSorted()\n\t\tif (candidateIds.size === 0) {\n\t\t\teditor.setErasingShapes(Array.from(erasing))\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes = editor.getCurrentPageRenderingShapesSorted()\n\t\tconst currentPageShapes = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\tfor (const shape of currentPageShapes) {\n\t\t\tif (editor.isShapeOfType(shape, 'group')) continue\n\n\t\t\t// Avoid testing masked shapes, unless the pointer is inside the mask\n\t\t\tconst pageMask = editor.getShapeMask(shape.id)\n\t\t\tif (pageMask && !pointInPolygon(currentPagePoint, pageMask)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Hit test the shape using a line segment\n\t\t\tconst geometry = editor.getShapeGeometry(shape)\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\t\tif (!geometry || !pageTransform) continue\n\t\t\tconst pt = pageTransform.clone().invert()\n\t\t\tconst A = pt.applyToPoint(previousPagePoint)\n\t\t\tconst B = pt.applyToPoint(currentPagePoint)\n\n\t\t\t// If the line segment is entirely above / below / left / right of the shape's bounding box, skip the hit test\n\t\t\tconst { bounds } = geometry\n\t\t\tif (\n\t\t\t\tbounds.minX - minDist > Math.max(A.x, B.x) ||\n\t\t\t\tbounds.minY - minDist > Math.max(A.y, B.y) ||\n\t\t\t\tbounds.maxX + minDist < Math.min(A.x, B.x) ||\n\t\t\t\tbounds.maxY + minDist < Math.min(A.y, B.y)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If a shape is hit and is part of a group, erase the group\n\t\t\t// If we started erasing inside a group's bounds, erase child shapes (or nested groups) inside it\n\t\t\tif (geometry.hitTestLineSegment(A, B, minDist)) {\n\t\t\t\tconst outermost = editor.getOutermostSelectableShape(shape)\n\t\t\t\tif (excludedShapeIds.has(outermost.id)) {\n\t\t\t\t\terasing.add(\n\t\t\t\t\t\teditor.getOutermostSelectableShape(shape, (s) => !excludedShapeIds.has(s.id)).id\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\terasing.add(outermost.id)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._erasingShapeIds = [...erasing]\n\t\t}\n\n\t\t// Remove the hit shapes, except if they're in the list of excluded shapes\n\t\t// (these excluded shapes will be any frames or groups the pointer was inside of\n\t\t// when the user started erasing)\n\t\tthis.editor.setErasingShapes(this._erasingShapeIds.filter((id) => !excludedShapeIds.has(id)))\n\t}\n\n\tcomplete(info?: TLPointerEventInfo) {\n\t\tconst { editor } = this\n\t\teditor.deleteShapes(editor.getCurrentPageState().erasingShapeIds)\n\t\tthis.parent.transition('idle', info)\n\t\tthis._erasingShapeIds = []\n\t}\n\n\tcancel() {\n\t\tconst { editor } = this\n\t\teditor.bailToMark(this.markId)\n\t\tthis.parent.transition('idle', this.info)\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { Box, StateNode, TLPointerEventInfo, TLShapeId, pointInPolygon } from '@tldraw/editor'\n\nexport class Erasing extends StateNode {\n\tstatic override id = 'erasing'\n\tstatic override trackPerformance = true\n\n\tprivate info = {} as TLPointerEventInfo\n\tprivate scribbleId = 'id'\n\tprivate markId = ''\n\tprivate excludedShapeIds = new Set<TLShapeId>()\n\n\t_erasingShapeIds: TLShapeId[] = []\n\n\toverride onEnter(info: TLPointerEventInfo) {\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('erase scribble begin')\n\t\tthis.info = info\n\n\t\tconst originPagePoint = this.editor.inputs.getOriginPagePoint()\n\t\tconst pressedShapeIds = new Set(this.editor.getErasingShapeIds())\n\t\tthis.excludedShapeIds = new Set(\n\t\t\tthis.editor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter((shape) => {\n\t\t\t\t\t//If the shape is locked, we shouldn't erase it\n\t\t\t\t\tif (this.editor.isShapeOrAncestorLocked(shape)) return true\n\t\t\t\t\t// A frame the press hit on its outline stays marked: a press just inside the outline\n\t\t\t\t\t// is within the frame's bounds, so the containment check below would otherwise\n\t\t\t\t\t// unmark it on the first move while a press just outside would erase it\n\t\t\t\t\tif (this.editor.isShapeFrameLike(shape) && pressedShapeIds.has(shape.id)) return false\n\t\t\t\t\t//If the shape is a group or frame-like, check we're inside it when we start erasing\n\t\t\t\t\tif (this.editor.isShapeOfType(shape, 'group') || this.editor.isShapeFrameLike(shape)) {\n\t\t\t\t\t\tconst pointInShapeShape = this.editor.getPointInShapeSpace(shape, originPagePoint)\n\t\t\t\t\t\tconst geometry = this.editor.getShapeGeometry(shape)\n\t\t\t\t\t\treturn geometry.bounds.containsPoint(pointInShapeShape)\n\t\t\t\t\t}\n\n\t\t\t\t\treturn false\n\t\t\t\t})\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tthis._erasingShapeIds = this.editor\n\t\t\t.getShapesAtPoint(originPagePoint)\n\t\t\t.filter((s) => !this.excludedShapeIds.has(s.id))\n\t\t\t.map((s) => s.id)\n\n\t\tthis.editor.setErasingShapes([\n\t\t\t...new Set([...this.editor.getErasingShapeIds(), ...this._erasingShapeIds]),\n\t\t])\n\n\t\tconst scribble = this.editor.scribbles.addScribble({\n\t\t\tcolor: 'muted-1',\n\t\t\tsize: 12,\n\t\t})\n\t\tthis.scribbleId = scribble.id\n\n\t\tthis.update()\n\t}\n\n\tprivate pushPointToScribble() {\n\t\tconst { x, y } = this.editor.inputs.getCurrentPagePoint()\n\t\tthis.editor.scribbles.addPoint(this.scribbleId, x, y)\n\t}\n\n\toverride onExit() {\n\t\tthis.editor.setErasingShapes([])\n\t\tthis.editor.scribbles.stop(this.scribbleId)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp(info: TLPointerEventInfo) {\n\t\tthis.complete(info)\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\tupdate() {\n\t\tconst { editor, excludedShapeIds } = this\n\t\tconst erasingShapeIds = editor.getErasingShapeIds()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst previousPagePoint = editor.inputs.getPreviousPagePoint()\n\n\t\tthis.pushPointToScribble()\n\n\t\t// Otherwise, erasing shapes are all the shapes that were hit before plus any new shapes that are hit\n\t\tconst erasing = new Set<TLShapeId>(erasingShapeIds)\n\t\tconst minDist = this.editor.getHitTestMargin()\n\n\t\t// Create bounds around line segment with margin\n\t\tconst lineBounds = Box.FromPoints([previousPagePoint, currentPagePoint]).expandBy(minDist)\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(lineBounds)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageRenderingShapesSorted()\n\t\tif (candidateIds.size === 0) {\n\t\t\teditor.setErasingShapes(Array.from(erasing))\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes = editor.getCurrentPageRenderingShapesSorted()\n\t\tconst currentPageShapes = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\tfor (const shape of currentPageShapes) {\n\t\t\tif (editor.isShapeOfType(shape, 'group')) continue\n\n\t\t\t// Avoid testing masked shapes, unless the pointer is inside the mask\n\t\t\tconst pageMask = editor.getShapeMask(shape.id)\n\t\t\tif (pageMask && !pointInPolygon(currentPagePoint, pageMask)) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// Hit test the shape using a line segment\n\t\t\tconst geometry = editor.getShapeGeometry(shape)\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape)\n\t\t\tif (!geometry || !pageTransform) continue\n\t\t\tconst pt = pageTransform.clone().invert()\n\t\t\tconst A = pt.applyToPoint(previousPagePoint)\n\t\t\tconst B = pt.applyToPoint(currentPagePoint)\n\n\t\t\t// If the line segment is entirely above / below / left / right of the shape's bounding box, skip the hit test\n\t\t\tconst { bounds } = geometry\n\t\t\tif (\n\t\t\t\tbounds.minX - minDist > Math.max(A.x, B.x) ||\n\t\t\t\tbounds.minY - minDist > Math.max(A.y, B.y) ||\n\t\t\t\tbounds.maxX + minDist < Math.min(A.x, B.x) ||\n\t\t\t\tbounds.maxY + minDist < Math.min(A.y, B.y)\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\t// If a shape is hit and is part of a group, erase the group\n\t\t\t// If we started erasing inside a group's bounds, erase child shapes (or nested groups) inside it\n\t\t\tif (geometry.hitTestLineSegment(A, B, minDist)) {\n\t\t\t\tconst outermost = editor.getOutermostSelectableShape(shape)\n\t\t\t\tif (excludedShapeIds.has(outermost.id)) {\n\t\t\t\t\terasing.add(\n\t\t\t\t\t\teditor.getOutermostSelectableShape(shape, (s) => !excludedShapeIds.has(s.id)).id\n\t\t\t\t\t)\n\t\t\t\t} else {\n\t\t\t\t\terasing.add(outermost.id)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tthis._erasingShapeIds = [...erasing]\n\t\t}\n\n\t\t// Remove the hit shapes, except if they're in the list of excluded shapes\n\t\t// (these excluded shapes will be any frames or groups the pointer was inside of\n\t\t// when the user started erasing)\n\t\tthis.editor.setErasingShapes(this._erasingShapeIds.filter((id) => !excludedShapeIds.has(id)))\n\t}\n\n\tcomplete(info?: TLPointerEventInfo) {\n\t\tconst { editor } = this\n\t\teditor.deleteShapes(editor.getCurrentPageState().erasingShapeIds)\n\t\tthis.parent.transition('idle', info)\n\t\tthis._erasingShapeIds = []\n\t}\n\n\tcancel() {\n\t\tconst { editor } = this\n\t\teditor.bailToMark(this.markId)\n\t\tthis.parent.transition('idle', this.info)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -56,6 +56,12 @@ class OneFingerZooming extends import_editor.StateNode {
56
56
  onPointerUp(_info) {
57
57
  this.complete();
58
58
  }
59
+ onPointerDown() {
60
+ this.parent.transition("idle");
61
+ }
62
+ onComplete() {
63
+ this.parent.transition("idle");
64
+ }
59
65
  onCancel() {
60
66
  this.parent.transition("idle");
61
67
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/HandTool/childStates/OneFingerZooming.ts"],
4
- "sourcesContent": ["import { StateNode, TLPointerEventInfo, Vec, clamp, last } from '@tldraw/editor'\n\nexport class OneFingerZooming extends StateNode {\n\tstatic override id = 'one_finger_zooming'\n\n\tprivate anchorScreenPoint = new Vec()\n\tprivate initialCamera = new Vec()\n\tprivate initialZoom = 1\n\tprivate originScreenY = 0\n\n\toverride onEnter(_info: TLPointerEventInfo) {\n\t\tconst camera = this.editor.getCamera()\n\t\tthis.initialCamera = Vec.From(camera)\n\t\tthis.initialZoom = camera.z\n\t\tthis.anchorScreenPoint = this.editor.inputs.getOriginScreenPoint().clone()\n\t\tthis.originScreenY = this.editor.inputs.getCurrentScreenPoint().y\n\t\tthis.editor.setCursor({ type: 'grab', rotation: 0 })\n\t}\n\n\toverride onPointerMove(_info: TLPointerEventInfo) {\n\t\tthis.editor.menus.clearOpenMenus()\n\n\t\tconst currentScreenY = this.editor.inputs.getCurrentScreenPoint().y\n\n\t\t// Dragging up = zoom out, dragging down = zoom in (same as google maps default)\n\t\t// we won't respect the user's zoom direction preference because it only applies\n\t\t// to mouse input\n\t\tconst dy = (this.originScreenY - currentScreenY) * -1\n\n\t\t// ~200px of drag \u2248 2x zoom change.\n\t\tconst zoomFactor = Math.pow(2, dy / 200)\n\t\tconst newZoom = this.clampZoom(this.initialZoom * zoomFactor)\n\n\t\tconst { x: cx, y: cy } = this.initialCamera\n\t\tconst { x: sx, y: sy } = this.anchorScreenPoint\n\t\tthis.editor.setCamera(\n\t\t\tnew Vec(\n\t\t\t\tcx + sx / newZoom - sx / this.initialZoom,\n\t\t\t\tcy + sy / newZoom - sy / this.initialZoom,\n\t\t\t\tnewZoom\n\t\t\t),\n\t\t\t{ immediate: true }\n\t\t)\n\t}\n\n\toverride onPointerUp(_info: TLPointerEventInfo) {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.parent.transition('idle')\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate complete() {\n\t\tconst pointerVelocity = this.editor.inputs.getPointerVelocity()\n\t\tconst velocityAtPointerUp = Math.min(pointerVelocity.len(), 2)\n\n\t\tif (velocityAtPointerUp > 0.1) {\n\t\t\t// Use velocity y-sign for momentum direction (positive y = moving down = zoom in)\n\t\t\tthis.editor.slideCamera({\n\t\t\t\tspeed: velocityAtPointerUp,\n\t\t\t\tdirection: { x: 0, y: 0, z: Math.sign(pointerVelocity.y) * 0.01 },\n\t\t\t})\n\t\t}\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate clampZoom(zoom: number): number {\n\t\tconst { zoomSteps } = this.editor.getCameraOptions()\n\t\tconst baseZoom = this.editor.getBaseZoom()\n\t\tconst zoomMin = zoomSteps[0] * baseZoom\n\t\tconst zoomMax = last(zoomSteps)! * baseZoom\n\t\treturn clamp(zoom, zoomMin, zoomMax)\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAgE;AAEzD,MAAM,yBAAyB,wBAAU;AAAA,EAC/C,OAAgB,KAAK;AAAA,EAEb,oBAAoB,IAAI,kBAAI;AAAA,EAC5B,gBAAgB,IAAI,kBAAI;AAAA,EACxB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAEf,QAAQ,OAA2B;AAC3C,UAAM,SAAS,KAAK,OAAO,UAAU;AACrC,SAAK,gBAAgB,kBAAI,KAAK,MAAM;AACpC,SAAK,cAAc,OAAO;AAC1B,SAAK,oBAAoB,KAAK,OAAO,OAAO,qBAAqB,EAAE,MAAM;AACzE,SAAK,gBAAgB,KAAK,OAAO,OAAO,sBAAsB,EAAE;AAChE,SAAK,OAAO,UAAU,EAAE,MAAM,QAAQ,UAAU,EAAE,CAAC;AAAA,EACpD;AAAA,EAES,cAAc,OAA2B;AACjD,SAAK,OAAO,MAAM,eAAe;AAEjC,UAAM,iBAAiB,KAAK,OAAO,OAAO,sBAAsB,EAAE;AAKlE,UAAM,MAAM,KAAK,gBAAgB,kBAAkB;AAGnD,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,GAAG;AACvC,UAAM,UAAU,KAAK,UAAU,KAAK,cAAc,UAAU;AAE5D,UAAM,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;AAC9B,UAAM,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;AAC9B,SAAK,OAAO;AAAA,MACX,IAAI;AAAA,QACH,KAAK,KAAK,UAAU,KAAK,KAAK;AAAA,QAC9B,KAAK,KAAK,UAAU,KAAK,KAAK;AAAA,QAC9B;AAAA,MACD;AAAA,MACA,EAAE,WAAW,KAAK;AAAA,IACnB;AAAA,EACD;AAAA,EAES,YAAY,OAA2B;AAC/C,SAAK,SAAS;AAAA,EACf;AAAA,EAES,WAAW;AACnB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAES,cAAc;AACtB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEQ,WAAW;AAClB,UAAM,kBAAkB,KAAK,OAAO,OAAO,mBAAmB;AAC9D,UAAM,sBAAsB,KAAK,IAAI,gBAAgB,IAAI,GAAG,CAAC;AAE7D,QAAI,sBAAsB,KAAK;AAE9B,WAAK,OAAO,YAAY;AAAA,QACvB,OAAO;AAAA,QACP,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,KAAK,gBAAgB,CAAC,IAAI,KAAK;AAAA,MACjE,CAAC;AAAA,IACF;AACA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEQ,UAAU,MAAsB;AACvC,UAAM,EAAE,UAAU,IAAI,KAAK,OAAO,iBAAiB;AACnD,UAAM,WAAW,KAAK,OAAO,YAAY;AACzC,UAAM,UAAU,UAAU,CAAC,IAAI;AAC/B,UAAM,cAAU,oBAAK,SAAS,IAAK;AACnC,eAAO,qBAAM,MAAM,SAAS,OAAO;AAAA,EACpC;AACD;",
4
+ "sourcesContent": ["import { StateNode, TLPointerEventInfo, Vec, clamp, last } from '@tldraw/editor'\n\nexport class OneFingerZooming extends StateNode {\n\tstatic override id = 'one_finger_zooming'\n\n\tprivate anchorScreenPoint = new Vec()\n\tprivate initialCamera = new Vec()\n\tprivate initialZoom = 1\n\tprivate originScreenY = 0\n\n\toverride onEnter(_info: TLPointerEventInfo) {\n\t\tconst camera = this.editor.getCamera()\n\t\tthis.initialCamera = Vec.From(camera)\n\t\tthis.initialZoom = camera.z\n\t\tthis.anchorScreenPoint = this.editor.inputs.getOriginScreenPoint().clone()\n\t\tthis.originScreenY = this.editor.inputs.getCurrentScreenPoint().y\n\t\tthis.editor.setCursor({ type: 'grab', rotation: 0 })\n\t}\n\n\toverride onPointerMove(_info: TLPointerEventInfo) {\n\t\tthis.editor.menus.clearOpenMenus()\n\n\t\tconst currentScreenY = this.editor.inputs.getCurrentScreenPoint().y\n\n\t\t// Dragging up = zoom out, dragging down = zoom in (same as google maps default)\n\t\t// we won't respect the user's zoom direction preference because it only applies\n\t\t// to mouse input\n\t\tconst dy = (this.originScreenY - currentScreenY) * -1\n\n\t\t// ~200px of drag \u2248 2x zoom change.\n\t\tconst zoomFactor = Math.pow(2, dy / 200)\n\t\tconst newZoom = this.clampZoom(this.initialZoom * zoomFactor)\n\n\t\tconst { x: cx, y: cy } = this.initialCamera\n\t\tconst { x: sx, y: sy } = this.anchorScreenPoint\n\t\tthis.editor.setCamera(\n\t\t\tnew Vec(\n\t\t\t\tcx + sx / newZoom - sx / this.initialZoom,\n\t\t\t\tcy + sy / newZoom - sy / this.initialZoom,\n\t\t\t\tnewZoom\n\t\t\t),\n\t\t\t{ immediate: true }\n\t\t)\n\t}\n\n\toverride onPointerUp(_info: TLPointerEventInfo) {\n\t\tthis.complete()\n\t}\n\n\toverride onPointerDown() {\n\t\t// A second touch resets the input origin to the new pointer, so continuing\n\t\t// the zoom would jump the camera. Yield before the pinch begins.\n\t\tthis.parent.transition('idle')\n\t}\n\n\toverride onComplete() {\n\t\tthis.parent.transition('idle')\n\t}\n\n\toverride onCancel() {\n\t\tthis.parent.transition('idle')\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate complete() {\n\t\tconst pointerVelocity = this.editor.inputs.getPointerVelocity()\n\t\tconst velocityAtPointerUp = Math.min(pointerVelocity.len(), 2)\n\n\t\tif (velocityAtPointerUp > 0.1) {\n\t\t\t// Use velocity y-sign for momentum direction (positive y = moving down = zoom in)\n\t\t\tthis.editor.slideCamera({\n\t\t\t\tspeed: velocityAtPointerUp,\n\t\t\t\tdirection: { x: 0, y: 0, z: Math.sign(pointerVelocity.y) * 0.01 },\n\t\t\t})\n\t\t}\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate clampZoom(zoom: number): number {\n\t\tconst { zoomSteps } = this.editor.getCameraOptions()\n\t\tconst baseZoom = this.editor.getBaseZoom()\n\t\tconst zoomMin = zoomSteps[0] * baseZoom\n\t\tconst zoomMax = last(zoomSteps)! * baseZoom\n\t\treturn clamp(zoom, zoomMin, zoomMax)\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAgE;AAEzD,MAAM,yBAAyB,wBAAU;AAAA,EAC/C,OAAgB,KAAK;AAAA,EAEb,oBAAoB,IAAI,kBAAI;AAAA,EAC5B,gBAAgB,IAAI,kBAAI;AAAA,EACxB,cAAc;AAAA,EACd,gBAAgB;AAAA,EAEf,QAAQ,OAA2B;AAC3C,UAAM,SAAS,KAAK,OAAO,UAAU;AACrC,SAAK,gBAAgB,kBAAI,KAAK,MAAM;AACpC,SAAK,cAAc,OAAO;AAC1B,SAAK,oBAAoB,KAAK,OAAO,OAAO,qBAAqB,EAAE,MAAM;AACzE,SAAK,gBAAgB,KAAK,OAAO,OAAO,sBAAsB,EAAE;AAChE,SAAK,OAAO,UAAU,EAAE,MAAM,QAAQ,UAAU,EAAE,CAAC;AAAA,EACpD;AAAA,EAES,cAAc,OAA2B;AACjD,SAAK,OAAO,MAAM,eAAe;AAEjC,UAAM,iBAAiB,KAAK,OAAO,OAAO,sBAAsB,EAAE;AAKlE,UAAM,MAAM,KAAK,gBAAgB,kBAAkB;AAGnD,UAAM,aAAa,KAAK,IAAI,GAAG,KAAK,GAAG;AACvC,UAAM,UAAU,KAAK,UAAU,KAAK,cAAc,UAAU;AAE5D,UAAM,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;AAC9B,UAAM,EAAE,GAAG,IAAI,GAAG,GAAG,IAAI,KAAK;AAC9B,SAAK,OAAO;AAAA,MACX,IAAI;AAAA,QACH,KAAK,KAAK,UAAU,KAAK,KAAK;AAAA,QAC9B,KAAK,KAAK,UAAU,KAAK,KAAK;AAAA,QAC9B;AAAA,MACD;AAAA,MACA,EAAE,WAAW,KAAK;AAAA,IACnB;AAAA,EACD;AAAA,EAES,YAAY,OAA2B;AAC/C,SAAK,SAAS;AAAA,EACf;AAAA,EAES,gBAAgB;AAGxB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAES,aAAa;AACrB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAES,WAAW;AACnB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAES,cAAc;AACtB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEQ,WAAW;AAClB,UAAM,kBAAkB,KAAK,OAAO,OAAO,mBAAmB;AAC9D,UAAM,sBAAsB,KAAK,IAAI,gBAAgB,IAAI,GAAG,CAAC;AAE7D,QAAI,sBAAsB,KAAK;AAE9B,WAAK,OAAO,YAAY;AAAA,QACvB,OAAO;AAAA,QACP,WAAW,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,KAAK,KAAK,gBAAgB,CAAC,IAAI,KAAK;AAAA,MACjE,CAAC;AAAA,IACF;AACA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEQ,UAAU,MAAsB;AACvC,UAAM,EAAE,UAAU,IAAI,KAAK,OAAO,iBAAiB;AACnD,UAAM,WAAW,KAAK,OAAO,YAAY;AACzC,UAAM,UAAU,UAAU,CAAC,IAAI;AAC/B,UAAM,cAAU,oBAAK,SAAS,IAAK;AACnC,eAAO,qBAAM,MAAM,SAAS,OAAO;AAAA,EACpC;AACD;",
6
6
  "names": []
7
7
  }
@@ -97,6 +97,9 @@ class SelectTool extends import_editor.StateNode {
97
97
  if (this.editor.getCurrentPageState().editingShapeId) {
98
98
  this.editor.setEditingShape(null);
99
99
  }
100
+ if (this.editor.getCroppingShapeId()) {
101
+ this.editor.setCroppingShape(null);
102
+ }
100
103
  }
101
104
  }
102
105
  //# sourceMappingURL=SelectTool.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/tools/SelectTool/SelectTool.ts"],
4
- "sourcesContent": ["import { StateNode, TLStateNodeConstructor, react } from '@tldraw/editor'\nimport { Brushing } from './childStates/Brushing'\nimport { Cropping } from './childStates/Crop/children/Cropping'\nimport { PointingCropHandle } from './childStates/Crop/children/PointingCropHandle'\nimport { Crop } from './childStates/Crop/Crop'\nimport { DraggingHandle } from './childStates/DraggingHandle'\nimport { EditingShape } from './childStates/EditingShape'\nimport { Idle } from './childStates/Idle'\nimport { PointingArrowLabel } from './childStates/PointingArrowLabel'\nimport { PointingCanvas } from './childStates/PointingCanvas'\nimport { PointingHandle } from './childStates/PointingHandle'\nimport { PointingResizeHandle } from './childStates/PointingResizeHandle'\nimport { PointingRotateHandle } from './childStates/PointingRotateHandle'\nimport { PointingSelection } from './childStates/PointingSelection'\nimport { PointingShape } from './childStates/PointingShape'\nimport { Resizing } from './childStates/Resizing'\nimport { Rotating } from './childStates/Rotating'\nimport { ScribbleBrushing } from './childStates/ScribbleBrushing'\nimport { Translating } from './childStates/Translating'\n\n/** @public */\nexport class SelectTool extends StateNode {\n\tstatic override id = 'select'\n\tstatic override initial = 'idle'\n\tstatic override isLockable = false\n\treactor: undefined | (() => void) = undefined\n\n\tstatic override children(): TLStateNodeConstructor[] {\n\t\treturn [\n\t\t\tCrop,\n\t\t\tCropping,\n\t\t\tIdle,\n\t\t\tPointingCanvas,\n\t\t\tPointingShape,\n\t\t\tTranslating,\n\t\t\tBrushing,\n\t\t\tScribbleBrushing,\n\t\t\tPointingCropHandle,\n\t\t\tPointingSelection,\n\t\t\tPointingResizeHandle,\n\t\t\tEditingShape,\n\t\t\tResizing,\n\t\t\tRotating,\n\t\t\tPointingRotateHandle,\n\t\t\tPointingArrowLabel,\n\t\t\tPointingHandle,\n\t\t\tDraggingHandle,\n\t\t]\n\t}\n\n\t// We want to clean up the duplicate props when the selection changes\n\tcleanUpDuplicateProps() {\n\t\tconst selectedShapeIds = this.editor.getSelectedShapeIds()\n\t\tconst instance = this.editor.getInstanceState()\n\t\tif (!instance.duplicateProps) return\n\t\tconst duplicatedShapes = new Set(instance.duplicateProps.shapeIds)\n\t\tif (\n\t\t\tselectedShapeIds.length === duplicatedShapes.size &&\n\t\t\tselectedShapeIds.every((shapeId) => duplicatedShapes.has(shapeId))\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tthis.editor.updateInstanceState({\n\t\t\tduplicateProps: null,\n\t\t})\n\t}\n\n\toverride onEnter() {\n\t\tthis.reactor = react('clean duplicate props', () => {\n\t\t\ttry {\n\t\t\t\tthis.cleanUpDuplicateProps()\n\t\t\t} catch (e) {\n\t\t\t\tif (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {\n\t\t\t\t\t// ignore errors at test time\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(e)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\toverride onExit() {\n\t\tthis.reactor?.()\n\t\tif (this.editor.getCurrentPageState().editingShapeId) {\n\t\t\tthis.editor.setEditingShape(null)\n\t\t}\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyD;AACzD,sBAAyB;AACzB,sBAAyB;AACzB,gCAAmC;AACnC,kBAAqB;AACrB,4BAA+B;AAC/B,0BAA6B;AAC7B,kBAAqB;AACrB,gCAAmC;AACnC,4BAA+B;AAC/B,4BAA+B;AAC/B,kCAAqC;AACrC,kCAAqC;AACrC,+BAAkC;AAClC,2BAA8B;AAC9B,sBAAyB;AACzB,sBAAyB;AACzB,8BAAiC;AACjC,yBAA4B;AAGrB,MAAM,mBAAmB,wBAAU;AAAA,EACzC,OAAgB,KAAK;AAAA,EACrB,OAAgB,UAAU;AAAA,EAC1B,OAAgB,aAAa;AAAA,EAC7B,UAAoC;AAAA,EAEpC,OAAgB,WAAqC;AACpD,WAAO;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAGA,wBAAwB;AACvB,UAAM,mBAAmB,KAAK,OAAO,oBAAoB;AACzD,UAAM,WAAW,KAAK,OAAO,iBAAiB;AAC9C,QAAI,CAAC,SAAS,eAAgB;AAC9B,UAAM,mBAAmB,IAAI,IAAI,SAAS,eAAe,QAAQ;AACjE,QACC,iBAAiB,WAAW,iBAAiB,QAC7C,iBAAiB,MAAM,CAAC,YAAY,iBAAiB,IAAI,OAAO,CAAC,GAChE;AACD;AAAA,IACD;AACA,SAAK,OAAO,oBAAoB;AAAA,MAC/B,gBAAgB;AAAA,IACjB,CAAC;AAAA,EACF;AAAA,EAES,UAAU;AAClB,SAAK,cAAU,qBAAM,yBAAyB,MAAM;AACnD,UAAI;AACH,aAAK,sBAAsB;AAAA,MAC5B,SAAS,GAAG;AACX,YAAI,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa,QAAQ;AAAA,QAEvE,OAAO;AACN,kBAAQ,MAAM,CAAC;AAAA,QAChB;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAES,SAAS;AACjB,SAAK,UAAU;AACf,QAAI,KAAK,OAAO,oBAAoB,EAAE,gBAAgB;AACrD,WAAK,OAAO,gBAAgB,IAAI;AAAA,IACjC;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["import { StateNode, TLStateNodeConstructor, react } from '@tldraw/editor'\nimport { Brushing } from './childStates/Brushing'\nimport { Cropping } from './childStates/Crop/children/Cropping'\nimport { PointingCropHandle } from './childStates/Crop/children/PointingCropHandle'\nimport { Crop } from './childStates/Crop/Crop'\nimport { DraggingHandle } from './childStates/DraggingHandle'\nimport { EditingShape } from './childStates/EditingShape'\nimport { Idle } from './childStates/Idle'\nimport { PointingArrowLabel } from './childStates/PointingArrowLabel'\nimport { PointingCanvas } from './childStates/PointingCanvas'\nimport { PointingHandle } from './childStates/PointingHandle'\nimport { PointingResizeHandle } from './childStates/PointingResizeHandle'\nimport { PointingRotateHandle } from './childStates/PointingRotateHandle'\nimport { PointingSelection } from './childStates/PointingSelection'\nimport { PointingShape } from './childStates/PointingShape'\nimport { Resizing } from './childStates/Resizing'\nimport { Rotating } from './childStates/Rotating'\nimport { ScribbleBrushing } from './childStates/ScribbleBrushing'\nimport { Translating } from './childStates/Translating'\n\n/** @public */\nexport class SelectTool extends StateNode {\n\tstatic override id = 'select'\n\tstatic override initial = 'idle'\n\tstatic override isLockable = false\n\treactor: undefined | (() => void) = undefined\n\n\tstatic override children(): TLStateNodeConstructor[] {\n\t\treturn [\n\t\t\tCrop,\n\t\t\tCropping,\n\t\t\tIdle,\n\t\t\tPointingCanvas,\n\t\t\tPointingShape,\n\t\t\tTranslating,\n\t\t\tBrushing,\n\t\t\tScribbleBrushing,\n\t\t\tPointingCropHandle,\n\t\t\tPointingSelection,\n\t\t\tPointingResizeHandle,\n\t\t\tEditingShape,\n\t\t\tResizing,\n\t\t\tRotating,\n\t\t\tPointingRotateHandle,\n\t\t\tPointingArrowLabel,\n\t\t\tPointingHandle,\n\t\t\tDraggingHandle,\n\t\t]\n\t}\n\n\t// We want to clean up the duplicate props when the selection changes\n\tcleanUpDuplicateProps() {\n\t\tconst selectedShapeIds = this.editor.getSelectedShapeIds()\n\t\tconst instance = this.editor.getInstanceState()\n\t\tif (!instance.duplicateProps) return\n\t\tconst duplicatedShapes = new Set(instance.duplicateProps.shapeIds)\n\t\tif (\n\t\t\tselectedShapeIds.length === duplicatedShapes.size &&\n\t\t\tselectedShapeIds.every((shapeId) => duplicatedShapes.has(shapeId))\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tthis.editor.updateInstanceState({\n\t\t\tduplicateProps: null,\n\t\t})\n\t}\n\n\toverride onEnter() {\n\t\tthis.reactor = react('clean duplicate props', () => {\n\t\t\ttry {\n\t\t\t\tthis.cleanUpDuplicateProps()\n\t\t\t} catch (e) {\n\t\t\t\tif (typeof process !== 'undefined' && process.env.NODE_ENV === 'test') {\n\t\t\t\t\t// ignore errors at test time\n\t\t\t\t} else {\n\t\t\t\t\tconsole.error(e)\n\t\t\t\t}\n\t\t\t}\n\t\t})\n\t}\n\n\toverride onExit() {\n\t\tthis.reactor?.()\n\t\tif (this.editor.getCurrentPageState().editingShapeId) {\n\t\t\tthis.editor.setEditingShape(null)\n\t\t}\n\t\t// Leaving crop mode for another tool would otherwise keep the image in its cropping state\n\t\tif (this.editor.getCroppingShapeId()) {\n\t\t\tthis.editor.setCroppingShape(null)\n\t\t}\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAyD;AACzD,sBAAyB;AACzB,sBAAyB;AACzB,gCAAmC;AACnC,kBAAqB;AACrB,4BAA+B;AAC/B,0BAA6B;AAC7B,kBAAqB;AACrB,gCAAmC;AACnC,4BAA+B;AAC/B,4BAA+B;AAC/B,kCAAqC;AACrC,kCAAqC;AACrC,+BAAkC;AAClC,2BAA8B;AAC9B,sBAAyB;AACzB,sBAAyB;AACzB,8BAAiC;AACjC,yBAA4B;AAGrB,MAAM,mBAAmB,wBAAU;AAAA,EACzC,OAAgB,KAAK;AAAA,EACrB,OAAgB,UAAU;AAAA,EAC1B,OAAgB,aAAa;AAAA,EAC7B,UAAoC;AAAA,EAEpC,OAAgB,WAAqC;AACpD,WAAO;AAAA,MACN;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAAA,EACD;AAAA;AAAA,EAGA,wBAAwB;AACvB,UAAM,mBAAmB,KAAK,OAAO,oBAAoB;AACzD,UAAM,WAAW,KAAK,OAAO,iBAAiB;AAC9C,QAAI,CAAC,SAAS,eAAgB;AAC9B,UAAM,mBAAmB,IAAI,IAAI,SAAS,eAAe,QAAQ;AACjE,QACC,iBAAiB,WAAW,iBAAiB,QAC7C,iBAAiB,MAAM,CAAC,YAAY,iBAAiB,IAAI,OAAO,CAAC,GAChE;AACD;AAAA,IACD;AACA,SAAK,OAAO,oBAAoB;AAAA,MAC/B,gBAAgB;AAAA,IACjB,CAAC;AAAA,EACF;AAAA,EAES,UAAU;AAClB,SAAK,cAAU,qBAAM,yBAAyB,MAAM;AACnD,UAAI;AACH,aAAK,sBAAsB;AAAA,MAC5B,SAAS,GAAG;AACX,YAAI,OAAO,YAAY,eAAe,QAAQ,IAAI,aAAa,QAAQ;AAAA,QAEvE,OAAO;AACN,kBAAQ,MAAM,CAAC;AAAA,QAChB;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAAA,EAES,SAAS;AACjB,SAAK,UAAU;AACf,QAAI,KAAK,OAAO,oBAAoB,EAAE,gBAAgB;AACrD,WAAK,OAAO,gBAAgB,IAAI;AAAA,IACjC;AAEA,QAAI,KAAK,OAAO,mBAAmB,GAAG;AACrC,WAAK,OAAO,iBAAiB,IAAI;AAAA,IAClC;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -37,6 +37,7 @@ class Brushing extends import_editor.StateNode {
37
37
  const { editor } = this;
38
38
  const altKey = editor.inputs.getAltKey();
39
39
  this.isWrapMode = editor.user.getIsWrapMode();
40
+ editor.setCursor({ type: "default", rotation: 0 });
40
41
  this.viewportDidChange = false;
41
42
  let isInitialCheck = true;
42
43
  this.cleanupViewportChangeReactor = (0, import_editor.react)("viewport change while brushing", () => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/SelectTool/childStates/Brushing.ts"],
4
- "sourcesContent": ["import {\n\tBox,\n\tMat,\n\tStateNode,\n\tTLCancelEventInfo,\n\tTLKeyboardEventInfo,\n\tTLPageId,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLTickEventInfo,\n\tVec,\n\tpointInPolygon,\n\tpolygonsIntersect,\n\treact,\n} from '@tldraw/editor'\n\nexport class Brushing extends StateNode {\n\tstatic override id = 'brushing'\n\tstatic override trackPerformance = true\n\n\tinfo = {} as TLPointerEventInfo & { target: 'canvas' }\n\n\tinitialSelectedShapeIds: TLShapeId[] = []\n\texcludedShapeIds = new Set<TLShapeId>()\n\tisWrapMode = false\n\n\tviewportDidChange = false\n\tcleanupViewportChangeReactor() {\n\t\tvoid null\n\t} // cleanup function for the viewport reactor\n\n\toverride onEnter(info: TLPointerEventInfo & { target: 'canvas' }) {\n\t\tconst { editor } = this\n\t\tconst altKey = editor.inputs.getAltKey()\n\n\t\tthis.isWrapMode = editor.user.getIsWrapMode()\n\n\t\tthis.viewportDidChange = false\n\n\t\tlet isInitialCheck = true\n\n\t\tthis.cleanupViewportChangeReactor = react('viewport change while brushing', () => {\n\t\t\teditor.getViewportPageBounds() // capture the viewport change\n\t\t\tif (!isInitialCheck && !this.viewportDidChange) {\n\t\t\t\tthis.viewportDidChange = true\n\t\t\t}\n\t\t})\n\n\t\tif (altKey) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t\treturn\n\t\t}\n\n\t\tconst selectLockedShapes = editor.options.selectLockedShapes\n\t\tthis.excludedShapeIds = new Set(\n\t\t\teditor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter(\n\t\t\t\t\t(shape) =>\n\t\t\t\t\t\teditor.isShapeOfType(shape, 'group') ||\n\t\t\t\t\t\t(!selectLockedShapes && editor.isShapeOrAncestorLocked(shape))\n\t\t\t\t)\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tthis.info = info\n\t\tthis.initialSelectedShapeIds = editor.getSelectedShapeIds().slice()\n\t\tthis.hitTestShapes()\n\t\tisInitialCheck = false\n\t}\n\n\toverride onExit() {\n\t\tthis.initialSelectedShapeIds = []\n\t\tthis.editor.updateInstanceState({ brush: null })\n\n\t\tthis.cleanupViewportChangeReactor()\n\t}\n\n\toverride onTick({ elapsed }: TLTickEventInfo) {\n\t\tconst { editor } = this\n\t\tif (!editor.inputs.getIsDragging() || editor.inputs.getIsPanning()) return\n\t\teditor.edgeScrollManager.updateEdgeScrolling(elapsed)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.hitTestShapes()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel(info: TLCancelEventInfo) {\n\t\tthis.editor.setSelectedShapes(this.initialSelectedShapeIds)\n\t\tthis.parent.transition('idle', info)\n\t}\n\n\toverride onKeyDown(info: TLKeyboardEventInfo) {\n\t\tif (this.editor.inputs.getAltKey()) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t} else {\n\t\t\tthis.hitTestShapes()\n\t\t}\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.hitTestShapes()\n\t}\n\n\tprivate complete() {\n\t\tthis.hitTestShapes()\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate hitTestShapes() {\n\t\tconst { editor, excludedShapeIds, isWrapMode } = this\n\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst shiftKey = editor.inputs.getShiftKey()\n\t\tconst ctrlKey = editor.inputs.getCtrlKey()\n\n\t\t// We'll be collecting shape ids of selected shapes; if we're holding shift key, we start from our initial shapes\n\t\tconst results = new Set(shiftKey ? this.initialSelectedShapeIds : [])\n\n\t\t// In wrap mode, we need to completely enclose a shape to select it\n\t\tconst isWrapping = isWrapMode ? !ctrlKey : ctrlKey\n\n\t\t// Set the brush to contain the current and origin points\n\t\tconst brush = Box.FromPoints([originPagePoint, currentPagePoint])\n\n\t\t// We'll be testing the corners of the brush against the shapes\n\t\tconst { corners } = brush\n\n\t\tlet A: Vec,\n\t\t\tB: Vec,\n\t\t\tshape: TLShape,\n\t\t\tpageBounds: Box | undefined,\n\t\t\tpageTransform: Mat | undefined,\n\t\t\tlocalCorners: Vec[]\n\n\t\t// Some notes on optimization. We could easily cache all of the shape positions at\n\t\t// the start of the interaction and then do very fast checks against them, but that\n\t\t// would mean changes introduced by other collaborators wouldn't be reflected\u2014a user\n\t\t// could select a shape by selecting where it _used_ to be.\n\n\t\t// We still want to avoid hit tests as much as possible, however, so we test only the\n\t\t// shapes that are on screen UNLESS: the user has scrolled their viewpor; or the user\n\t\t// is dragging outside of the screen (e.g. in a window). In those cases, we need to\n\t\t// test all shapes.\n\n\t\t// On a page with ~5000 shapes, on-screen hit tests are about 2x faster than\n\t\t// testing all shapes.\n\n\t\tconst brushBoxIsInsideViewport = editor.getViewportPageBounds().contains(brush)\n\t\tconst currentPageId = editor.getCurrentPageId()\n\n\t\t// Use spatial index to filter candidates\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(brush)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageShapesSorted()\n\t\t// But still update brush visual and selection\n\t\tif (candidateIds.size === 0) {\n\t\t\tconst currentBrush = editor.getInstanceState().brush\n\t\t\tif (!currentBrush || !brush.equals(currentBrush)) {\n\t\t\t\teditor.updateInstanceState({ brush: { ...brush.toJson() } })\n\t\t\t}\n\n\t\t\tconst current = editor.getSelectedShapeIds()\n\t\t\tif (current.length !== results.size || current.some((id) => !results.has(id))) {\n\t\t\t\teditor.setSelectedShapes(Array.from(results))\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes =\n\t\t\tbrushBoxIsInsideViewport && !this.viewportDidChange\n\t\t\t\t? editor.getCurrentPageRenderingShapesSorted()\n\t\t\t\t: editor.getCurrentPageShapesSorted()\n\t\tconst shapesToHitTest = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\ttestAllShapes: for (let i = 0, n = shapesToHitTest.length; i < n; i++) {\n\t\t\tshape = shapesToHitTest[i]\n\t\t\tif (excludedShapeIds.has(shape.id) || results.has(shape.id)) continue testAllShapes\n\n\t\t\tpageBounds = editor.getShapePageBounds(shape)\n\t\t\tif (!pageBounds) continue testAllShapes\n\n\t\t\t// If the brush fully wraps a shape, it's almost certainly a hit\n\t\t\tif (brush.contains(pageBounds)) {\n\t\t\t\tthis.handleHit(shape, currentPagePoint, currentPageId, results, corners)\n\t\t\t\tcontinue testAllShapes\n\t\t\t}\n\n\t\t\t// If we're in wrap mode and the brush did not fully encloses the shape, it's a miss\n\t\t\t// We also skip frame-like shapes unless we've completely selected them.\n\t\t\tif (isWrapping || editor.isShapeFrameLike(shape)) {\n\t\t\t\tcontinue testAllShapes\n\t\t\t}\n\n\t\t\t// If the brush collides the page bounds, then do hit tests against\n\t\t\t// each of the brush's four sides.\n\t\t\tif (brush.collides(pageBounds)) {\n\t\t\t\t// Shapes expect to hit test line segments in their own coordinate system,\n\t\t\t\t// so we first need to get the brush corners in the shape's local space.\n\t\t\t\tpageTransform = editor.getShapePageTransform(shape)\n\t\t\t\tif (!pageTransform) continue testAllShapes\n\t\t\t\tlocalCorners = pageTransform.clone().invert().applyToPoints(corners)\n\t\t\t\t// See if any of the edges intersect the shape's geometry\n\t\t\t\tconst geometry = editor.getShapeGeometry(shape)\n\t\t\t\thitTestBrushEdges: for (let i = 0; i < 4; i++) {\n\t\t\t\t\tA = localCorners[i]\n\t\t\t\t\tB = localCorners[(i + 1) % 4]\n\t\t\t\t\tif (geometry.hitTestLineSegment(A, B, 0)) {\n\t\t\t\t\t\tthis.handleHit(shape, currentPagePoint, currentPageId, results, corners)\n\t\t\t\t\t\tbreak hitTestBrushEdges\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst currentBrush = editor.getInstanceState().brush\n\t\tif (!currentBrush || !brush.equals(currentBrush)) {\n\t\t\teditor.updateInstanceState({ brush: { ...brush.toJson() } })\n\t\t}\n\n\t\tconst current = editor.getSelectedShapeIds()\n\t\tif (current.length !== results.size || current.some((id) => !results.has(id))) {\n\t\t\teditor.setSelectedShapes(Array.from(results))\n\t\t}\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.editor.updateInstanceState({ brush: null })\n\t}\n\n\tprivate handleHit(\n\t\tshape: TLShape,\n\t\tcurrentPagePoint: Vec,\n\t\tcurrentPageId: TLPageId,\n\t\tresults: Set<TLShapeId>,\n\t\tcorners: Vec[]\n\t) {\n\t\tif (shape.parentId === currentPageId) {\n\t\t\tresults.add(shape.id)\n\t\t\treturn\n\t\t}\n\n\t\t// Find the outermost selectable shape, check to see if it has a\n\t\t// page mask; and if so, check to see if the brush intersects it\n\t\tconst selectedShape = this.editor.getOutermostSelectableShape(shape)\n\t\tconst pageMask = this.editor.getShapeMask(selectedShape.id)\n\t\tif (\n\t\t\tpageMask &&\n\t\t\t!polygonsIntersect(pageMask, corners) &&\n\t\t\t!pointInPolygon(currentPagePoint, pageMask)\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tresults.add(selectedShape.id)\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAeO;AAEA,MAAM,iBAAiB,wBAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EACrB,OAAgB,mBAAmB;AAAA,EAEnC,OAAO,CAAC;AAAA,EAER,0BAAuC,CAAC;AAAA,EACxC,mBAAmB,oBAAI,IAAe;AAAA,EACtC,aAAa;AAAA,EAEb,oBAAoB;AAAA,EACpB,+BAA+B;AAAA,EAE/B;AAAA;AAAA,EAES,QAAQ,MAAiD;AACjE,UAAM,EAAE,OAAO,IAAI;AACnB,UAAM,SAAS,OAAO,OAAO,UAAU;AAEvC,SAAK,aAAa,OAAO,KAAK,cAAc;AAE5C,SAAK,oBAAoB;AAEzB,QAAI,iBAAiB;AAErB,SAAK,mCAA+B,qBAAM,kCAAkC,MAAM;AACjF,aAAO,sBAAsB;AAC7B,UAAI,CAAC,kBAAkB,CAAC,KAAK,mBAAmB;AAC/C,aAAK,oBAAoB;AAAA,MAC1B;AAAA,IACD,CAAC;AAED,QAAI,QAAQ;AACX,WAAK,OAAO,WAAW,qBAAqB,IAAI;AAChD;AAAA,IACD;AAEA,UAAM,qBAAqB,OAAO,QAAQ;AAC1C,SAAK,mBAAmB,IAAI;AAAA,MAC3B,OACE,qBAAqB,EACrB;AAAA,QACA,CAAC,UACA,OAAO,cAAc,OAAO,OAAO,KAClC,CAAC,sBAAsB,OAAO,wBAAwB,KAAK;AAAA,MAC9D,EACC,IAAI,CAAC,UAAU,MAAM,EAAE;AAAA,IAC1B;AAEA,SAAK,OAAO;AACZ,SAAK,0BAA0B,OAAO,oBAAoB,EAAE,MAAM;AAClE,SAAK,cAAc;AACnB,qBAAiB;AAAA,EAClB;AAAA,EAES,SAAS;AACjB,SAAK,0BAA0B,CAAC;AAChC,SAAK,OAAO,oBAAoB,EAAE,OAAO,KAAK,CAAC;AAE/C,SAAK,6BAA6B;AAAA,EACnC;AAAA,EAES,OAAO,EAAE,QAAQ,GAAoB;AAC7C,UAAM,EAAE,OAAO,IAAI;AACnB,QAAI,CAAC,OAAO,OAAO,cAAc,KAAK,OAAO,OAAO,aAAa,EAAG;AACpE,WAAO,kBAAkB,oBAAoB,OAAO;AAAA,EACrD;AAAA,EAES,gBAAgB;AACxB,SAAK,cAAc;AAAA,EACpB;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,SAAS,MAAyB;AAC1C,SAAK,OAAO,kBAAkB,KAAK,uBAAuB;AAC1D,SAAK,OAAO,WAAW,QAAQ,IAAI;AAAA,EACpC;AAAA,EAES,UAAU,MAA2B;AAC7C,QAAI,KAAK,OAAO,OAAO,UAAU,GAAG;AACnC,WAAK,OAAO,WAAW,qBAAqB,IAAI;AAAA,IACjD,OAAO;AACN,WAAK,cAAc;AAAA,IACpB;AAAA,EACD;AAAA,EAES,UAAU;AAClB,SAAK,cAAc;AAAA,EACpB;AAAA,EAEQ,WAAW;AAClB,SAAK,cAAc;AACnB,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEQ,gBAAgB;AACvB,UAAM,EAAE,QAAQ,kBAAkB,WAAW,IAAI;AACjD,UAAM,kBAAkB,OAAO,OAAO,mBAAmB;AACzD,UAAM,mBAAmB,OAAO,OAAO,oBAAoB;AAC3D,UAAM,WAAW,OAAO,OAAO,YAAY;AAC3C,UAAM,UAAU,OAAO,OAAO,WAAW;AAGzC,UAAM,UAAU,IAAI,IAAI,WAAW,KAAK,0BAA0B,CAAC,CAAC;AAGpE,UAAM,aAAa,aAAa,CAAC,UAAU;AAG3C,UAAM,QAAQ,kBAAI,WAAW,CAAC,iBAAiB,gBAAgB,CAAC;AAGhE,UAAM,EAAE,QAAQ,IAAI;AAEpB,QAAI,GACH,GACA,OACA,YACA,eACA;AAeD,UAAM,2BAA2B,OAAO,sBAAsB,EAAE,SAAS,KAAK;AAC9E,UAAM,gBAAgB,OAAO,iBAAiB;AAG9C,UAAM,eAAe,OAAO,wBAAwB,KAAK;AAIzD,QAAI,aAAa,SAAS,GAAG;AAC5B,YAAMA,gBAAe,OAAO,iBAAiB,EAAE;AAC/C,UAAI,CAACA,iBAAgB,CAAC,MAAM,OAAOA,aAAY,GAAG;AACjD,eAAO,oBAAoB,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,EAAE,EAAE,CAAC;AAAA,MAC5D;AAEA,YAAMC,WAAU,OAAO,oBAAoB;AAC3C,UAAIA,SAAQ,WAAW,QAAQ,QAAQA,SAAQ,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,GAAG;AAC9E,eAAO,kBAAkB,MAAM,KAAK,OAAO,CAAC;AAAA,MAC7C;AACA;AAAA,IACD;AAEA,UAAM,YACL,4BAA4B,CAAC,KAAK,oBAC/B,OAAO,oCAAoC,IAC3C,OAAO,2BAA2B;AACtC,UAAM,kBAAkB,UAAU,OAAO,CAACC,WAAU,aAAa,IAAIA,OAAM,EAAE,CAAC;AAE9E,kBAAe,UAAS,IAAI,GAAG,IAAI,gBAAgB,QAAQ,IAAI,GAAG,KAAK;AACtE,cAAQ,gBAAgB,CAAC;AACzB,UAAI,iBAAiB,IAAI,MAAM,EAAE,KAAK,QAAQ,IAAI,MAAM,EAAE,EAAG,UAAS;AAEtE,mBAAa,OAAO,mBAAmB,KAAK;AAC5C,UAAI,CAAC,WAAY,UAAS;AAG1B,UAAI,MAAM,SAAS,UAAU,GAAG;AAC/B,aAAK,UAAU,OAAO,kBAAkB,eAAe,SAAS,OAAO;AACvE,iBAAS;AAAA,MACV;AAIA,UAAI,cAAc,OAAO,iBAAiB,KAAK,GAAG;AACjD,iBAAS;AAAA,MACV;AAIA,UAAI,MAAM,SAAS,UAAU,GAAG;AAG/B,wBAAgB,OAAO,sBAAsB,KAAK;AAClD,YAAI,CAAC,cAAe,UAAS;AAC7B,uBAAe,cAAc,MAAM,EAAE,OAAO,EAAE,cAAc,OAAO;AAEnE,cAAM,WAAW,OAAO,iBAAiB,KAAK;AAC9C,0BAAmB,UAASC,KAAI,GAAGA,KAAI,GAAGA,MAAK;AAC9C,cAAI,aAAaA,EAAC;AAClB,cAAI,cAAcA,KAAI,KAAK,CAAC;AAC5B,cAAI,SAAS,mBAAmB,GAAG,GAAG,CAAC,GAAG;AACzC,iBAAK,UAAU,OAAO,kBAAkB,eAAe,SAAS,OAAO;AACvE,kBAAM;AAAA,UACP;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,UAAM,eAAe,OAAO,iBAAiB,EAAE;AAC/C,QAAI,CAAC,gBAAgB,CAAC,MAAM,OAAO,YAAY,GAAG;AACjD,aAAO,oBAAoB,EAAE,OAAO,EAAE,GAAG,MAAM,OAAO,EAAE,EAAE,CAAC;AAAA,IAC5D;AAEA,UAAM,UAAU,OAAO,oBAAoB;AAC3C,QAAI,QAAQ,WAAW,QAAQ,QAAQ,QAAQ,KAAK,CAAC,OAAO,CAAC,QAAQ,IAAI,EAAE,CAAC,GAAG;AAC9E,aAAO,kBAAkB,MAAM,KAAK,OAAO,CAAC;AAAA,IAC7C;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,OAAO,oBAAoB,EAAE,OAAO,KAAK,CAAC;AAAA,EAChD;AAAA,EAEQ,UACP,OACA,kBACA,eACA,SACA,SACC;AACD,QAAI,MAAM,aAAa,eAAe;AACrC,cAAQ,IAAI,MAAM,EAAE;AACpB;AAAA,IACD;AAIA,UAAM,gBAAgB,KAAK,OAAO,4BAA4B,KAAK;AACnE,UAAM,WAAW,KAAK,OAAO,aAAa,cAAc,EAAE;AAC1D,QACC,YACA,KAAC,iCAAkB,UAAU,OAAO,KACpC,KAAC,8BAAe,kBAAkB,QAAQ,GACzC;AACD;AAAA,IACD;AACA,YAAQ,IAAI,cAAc,EAAE;AAAA,EAC7B;AACD;",
4
+ "sourcesContent": ["import {\n\tBox,\n\tMat,\n\tStateNode,\n\tTLCancelEventInfo,\n\tTLKeyboardEventInfo,\n\tTLPageId,\n\tTLPointerEventInfo,\n\tTLShape,\n\tTLShapeId,\n\tTLTickEventInfo,\n\tVec,\n\tpointInPolygon,\n\tpolygonsIntersect,\n\treact,\n} from '@tldraw/editor'\n\nexport class Brushing extends StateNode {\n\tstatic override id = 'brushing'\n\tstatic override trackPerformance = true\n\n\tinfo = {} as TLPointerEventInfo & { target: 'canvas' }\n\n\tinitialSelectedShapeIds: TLShapeId[] = []\n\texcludedShapeIds = new Set<TLShapeId>()\n\tisWrapMode = false\n\n\tviewportDidChange = false\n\tcleanupViewportChangeReactor() {\n\t\tvoid null\n\t} // cleanup function for the viewport reactor\n\n\toverride onEnter(info: TLPointerEventInfo & { target: 'canvas' }) {\n\t\tconst { editor } = this\n\t\tconst altKey = editor.inputs.getAltKey()\n\n\t\tthis.isWrapMode = editor.user.getIsWrapMode()\n\n\t\t// Accel-pressing a resize or rotate handle brushes instead of resizing or rotating,\n\t\t// and the handle's hover cursor would otherwise stay up for the whole brush.\n\t\teditor.setCursor({ type: 'default', rotation: 0 })\n\n\t\tthis.viewportDidChange = false\n\n\t\tlet isInitialCheck = true\n\n\t\tthis.cleanupViewportChangeReactor = react('viewport change while brushing', () => {\n\t\t\teditor.getViewportPageBounds() // capture the viewport change\n\t\t\tif (!isInitialCheck && !this.viewportDidChange) {\n\t\t\t\tthis.viewportDidChange = true\n\t\t\t}\n\t\t})\n\n\t\tif (altKey) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t\treturn\n\t\t}\n\n\t\tconst selectLockedShapes = editor.options.selectLockedShapes\n\t\tthis.excludedShapeIds = new Set(\n\t\t\teditor\n\t\t\t\t.getCurrentPageShapes()\n\t\t\t\t.filter(\n\t\t\t\t\t(shape) =>\n\t\t\t\t\t\teditor.isShapeOfType(shape, 'group') ||\n\t\t\t\t\t\t(!selectLockedShapes && editor.isShapeOrAncestorLocked(shape))\n\t\t\t\t)\n\t\t\t\t.map((shape) => shape.id)\n\t\t)\n\n\t\tthis.info = info\n\t\tthis.initialSelectedShapeIds = editor.getSelectedShapeIds().slice()\n\t\tthis.hitTestShapes()\n\t\tisInitialCheck = false\n\t}\n\n\toverride onExit() {\n\t\tthis.initialSelectedShapeIds = []\n\t\tthis.editor.updateInstanceState({ brush: null })\n\n\t\tthis.cleanupViewportChangeReactor()\n\t}\n\n\toverride onTick({ elapsed }: TLTickEventInfo) {\n\t\tconst { editor } = this\n\t\tif (!editor.inputs.getIsDragging() || editor.inputs.getIsPanning()) return\n\t\teditor.edgeScrollManager.updateEdgeScrolling(elapsed)\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.hitTestShapes()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel(info: TLCancelEventInfo) {\n\t\tthis.editor.setSelectedShapes(this.initialSelectedShapeIds)\n\t\tthis.parent.transition('idle', info)\n\t}\n\n\toverride onKeyDown(info: TLKeyboardEventInfo) {\n\t\tif (this.editor.inputs.getAltKey()) {\n\t\t\tthis.parent.transition('scribble_brushing', info)\n\t\t} else {\n\t\t\tthis.hitTestShapes()\n\t\t}\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.hitTestShapes()\n\t}\n\n\tprivate complete() {\n\t\tthis.hitTestShapes()\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate hitTestShapes() {\n\t\tconst { editor, excludedShapeIds, isWrapMode } = this\n\t\tconst originPagePoint = editor.inputs.getOriginPagePoint()\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst shiftKey = editor.inputs.getShiftKey()\n\t\tconst ctrlKey = editor.inputs.getCtrlKey()\n\n\t\t// We'll be collecting shape ids of selected shapes; if we're holding shift key, we start from our initial shapes\n\t\tconst results = new Set(shiftKey ? this.initialSelectedShapeIds : [])\n\n\t\t// In wrap mode, we need to completely enclose a shape to select it\n\t\tconst isWrapping = isWrapMode ? !ctrlKey : ctrlKey\n\n\t\t// Set the brush to contain the current and origin points\n\t\tconst brush = Box.FromPoints([originPagePoint, currentPagePoint])\n\n\t\t// We'll be testing the corners of the brush against the shapes\n\t\tconst { corners } = brush\n\n\t\tlet A: Vec,\n\t\t\tB: Vec,\n\t\t\tshape: TLShape,\n\t\t\tpageBounds: Box | undefined,\n\t\t\tpageTransform: Mat | undefined,\n\t\t\tlocalCorners: Vec[]\n\n\t\t// Some notes on optimization. We could easily cache all of the shape positions at\n\t\t// the start of the interaction and then do very fast checks against them, but that\n\t\t// would mean changes introduced by other collaborators wouldn't be reflected\u2014a user\n\t\t// could select a shape by selecting where it _used_ to be.\n\n\t\t// We still want to avoid hit tests as much as possible, however, so we test only the\n\t\t// shapes that are on screen UNLESS: the user has scrolled their viewpor; or the user\n\t\t// is dragging outside of the screen (e.g. in a window). In those cases, we need to\n\t\t// test all shapes.\n\n\t\t// On a page with ~5000 shapes, on-screen hit tests are about 2x faster than\n\t\t// testing all shapes.\n\n\t\tconst brushBoxIsInsideViewport = editor.getViewportPageBounds().contains(brush)\n\t\tconst currentPageId = editor.getCurrentPageId()\n\n\t\t// Use spatial index to filter candidates\n\t\tconst candidateIds = editor.getShapeIdsInsideBounds(brush)\n\n\t\t// Early return if no candidates - avoid expensive getCurrentPageShapesSorted()\n\t\t// But still update brush visual and selection\n\t\tif (candidateIds.size === 0) {\n\t\t\tconst currentBrush = editor.getInstanceState().brush\n\t\t\tif (!currentBrush || !brush.equals(currentBrush)) {\n\t\t\t\teditor.updateInstanceState({ brush: { ...brush.toJson() } })\n\t\t\t}\n\n\t\t\tconst current = editor.getSelectedShapeIds()\n\t\t\tif (current.length !== results.size || current.some((id) => !results.has(id))) {\n\t\t\t\teditor.setSelectedShapes(Array.from(results))\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tconst allShapes =\n\t\t\tbrushBoxIsInsideViewport && !this.viewportDidChange\n\t\t\t\t? editor.getCurrentPageRenderingShapesSorted()\n\t\t\t\t: editor.getCurrentPageShapesSorted()\n\t\tconst shapesToHitTest = allShapes.filter((shape) => candidateIds.has(shape.id))\n\n\t\ttestAllShapes: for (let i = 0, n = shapesToHitTest.length; i < n; i++) {\n\t\t\tshape = shapesToHitTest[i]\n\t\t\tif (excludedShapeIds.has(shape.id) || results.has(shape.id)) continue testAllShapes\n\n\t\t\tpageBounds = editor.getShapePageBounds(shape)\n\t\t\tif (!pageBounds) continue testAllShapes\n\n\t\t\t// If the brush fully wraps a shape, it's almost certainly a hit\n\t\t\tif (brush.contains(pageBounds)) {\n\t\t\t\tthis.handleHit(shape, currentPagePoint, currentPageId, results, corners)\n\t\t\t\tcontinue testAllShapes\n\t\t\t}\n\n\t\t\t// If we're in wrap mode and the brush did not fully encloses the shape, it's a miss\n\t\t\t// We also skip frame-like shapes unless we've completely selected them.\n\t\t\tif (isWrapping || editor.isShapeFrameLike(shape)) {\n\t\t\t\tcontinue testAllShapes\n\t\t\t}\n\n\t\t\t// If the brush collides the page bounds, then do hit tests against\n\t\t\t// each of the brush's four sides.\n\t\t\tif (brush.collides(pageBounds)) {\n\t\t\t\t// Shapes expect to hit test line segments in their own coordinate system,\n\t\t\t\t// so we first need to get the brush corners in the shape's local space.\n\t\t\t\tpageTransform = editor.getShapePageTransform(shape)\n\t\t\t\tif (!pageTransform) continue testAllShapes\n\t\t\t\tlocalCorners = pageTransform.clone().invert().applyToPoints(corners)\n\t\t\t\t// See if any of the edges intersect the shape's geometry\n\t\t\t\tconst geometry = editor.getShapeGeometry(shape)\n\t\t\t\thitTestBrushEdges: for (let i = 0; i < 4; i++) {\n\t\t\t\t\tA = localCorners[i]\n\t\t\t\t\tB = localCorners[(i + 1) % 4]\n\t\t\t\t\tif (geometry.hitTestLineSegment(A, B, 0)) {\n\t\t\t\t\t\tthis.handleHit(shape, currentPagePoint, currentPageId, results, corners)\n\t\t\t\t\t\tbreak hitTestBrushEdges\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tconst currentBrush = editor.getInstanceState().brush\n\t\tif (!currentBrush || !brush.equals(currentBrush)) {\n\t\t\teditor.updateInstanceState({ brush: { ...brush.toJson() } })\n\t\t}\n\n\t\tconst current = editor.getSelectedShapeIds()\n\t\tif (current.length !== results.size || current.some((id) => !results.has(id))) {\n\t\t\teditor.setSelectedShapes(Array.from(results))\n\t\t}\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.editor.updateInstanceState({ brush: null })\n\t}\n\n\tprivate handleHit(\n\t\tshape: TLShape,\n\t\tcurrentPagePoint: Vec,\n\t\tcurrentPageId: TLPageId,\n\t\tresults: Set<TLShapeId>,\n\t\tcorners: Vec[]\n\t) {\n\t\tif (shape.parentId === currentPageId) {\n\t\t\tresults.add(shape.id)\n\t\t\treturn\n\t\t}\n\n\t\t// Find the outermost selectable shape, check to see if it has a\n\t\t// page mask; and if so, check to see if the brush intersects it\n\t\tconst selectedShape = this.editor.getOutermostSelectableShape(shape)\n\t\tconst pageMask = this.editor.getShapeMask(selectedShape.id)\n\t\tif (\n\t\t\tpageMask &&\n\t\t\t!polygonsIntersect(pageMask, corners) &&\n\t\t\t!pointInPolygon(currentPagePoint, pageMask)\n\t\t) {\n\t\t\treturn\n\t\t}\n\t\tresults.add(selectedShape.id)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["currentBrush", "current", "shape", "i"]
7
7
  }
@@ -48,6 +48,7 @@ class Crop extends import_editor.StateNode {
48
48
  }
49
49
  }
50
50
  onCancel() {
51
+ if (this.getCurrent()?.id !== "idle") return;
51
52
  if (!this.didExit) {
52
53
  this.didExit = true;
53
54
  this.editor.bailToMark(this.markId);
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../../src/lib/tools/SelectTool/childStates/Crop/Crop.ts"],
4
- "sourcesContent": ["import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'\nimport { Cropping } from './children/Cropping'\nimport { Idle } from './children/Idle'\nimport { PointingCrop } from './children/PointingCrop'\nimport { PointingCropHandle } from './children/PointingCropHandle'\nimport { TranslatingCrop } from './children/TranslatingCrop'\n\nexport class Crop extends StateNode {\n\tstatic override id = 'crop'\n\tstatic override initial = 'idle'\n\tstatic override children(): TLStateNodeConstructor[] {\n\t\treturn [Idle, TranslatingCrop, PointingCrop, PointingCropHandle, Cropping]\n\t}\n\n\tmarkId = ''\n\n\toverride onEnter() {\n\t\tthis.didExit = false\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('crop')\n\t}\n\tdidExit = false\n\toverride onExit() {\n\t\tif (!this.didExit) {\n\t\t\tthis.didExit = true\n\t\t\tif (this.editor.getMarkIdMatching(this.markId) === this.markId) {\n\t\t\t\tthis.editor.squashToMark(this.markId)\n\t\t\t}\n\t\t}\n\t}\n\toverride onCancel() {\n\t\tif (!this.didExit) {\n\t\t\tthis.didExit = true\n\t\t\tthis.editor.bailToMark(this.markId)\n\t\t}\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAkD;AAClD,sBAAyB;AACzB,kBAAqB;AACrB,0BAA6B;AAC7B,gCAAmC;AACnC,6BAAgC;AAEzB,MAAM,aAAa,wBAAU;AAAA,EACnC,OAAgB,KAAK;AAAA,EACrB,OAAgB,UAAU;AAAA,EAC1B,OAAgB,WAAqC;AACpD,WAAO,CAAC,kBAAM,wCAAiB,kCAAc,8CAAoB,wBAAQ;AAAA,EAC1E;AAAA,EAEA,SAAS;AAAA,EAEA,UAAU;AAClB,SAAK,UAAU;AACf,SAAK,SAAS,KAAK,OAAO,yBAAyB,MAAM;AAAA,EAC1D;AAAA,EACA,UAAU;AAAA,EACD,SAAS;AACjB,QAAI,CAAC,KAAK,SAAS;AAClB,WAAK,UAAU;AACf,UAAI,KAAK,OAAO,kBAAkB,KAAK,MAAM,MAAM,KAAK,QAAQ;AAC/D,aAAK,OAAO,aAAa,KAAK,MAAM;AAAA,MACrC;AAAA,IACD;AAAA,EACD;AAAA,EACS,WAAW;AACnB,QAAI,CAAC,KAAK,SAAS;AAClB,WAAK,UAAU;AACf,WAAK,OAAO,WAAW,KAAK,MAAM;AAAA,IACnC;AAAA,EACD;AACD;",
4
+ "sourcesContent": ["import { StateNode, TLStateNodeConstructor } from '@tldraw/editor'\nimport { Cropping } from './children/Cropping'\nimport { Idle } from './children/Idle'\nimport { PointingCrop } from './children/PointingCrop'\nimport { PointingCropHandle } from './children/PointingCropHandle'\nimport { TranslatingCrop } from './children/TranslatingCrop'\n\nexport class Crop extends StateNode {\n\tstatic override id = 'crop'\n\tstatic override initial = 'idle'\n\tstatic override children(): TLStateNodeConstructor[] {\n\t\treturn [Idle, TranslatingCrop, PointingCrop, PointingCropHandle, Cropping]\n\t}\n\n\tmarkId = ''\n\n\toverride onEnter() {\n\t\tthis.didExit = false\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('crop')\n\t}\n\tdidExit = false\n\toverride onExit() {\n\t\tif (!this.didExit) {\n\t\t\tthis.didExit = true\n\t\t\tif (this.editor.getMarkIdMatching(this.markId) === this.markId) {\n\t\t\t\tthis.editor.squashToMark(this.markId)\n\t\t\t}\n\t\t}\n\t}\n\toverride onCancel() {\n\t\t// Parents handle events before children, so a cancel during a child's drag would unwind\n\t\t// the whole session here before the child bails to its own mark. Only idle's escape ends\n\t\t// the session; mid-drag children revert just their own change and return to idle.\n\t\tif (this.getCurrent()?.id !== 'idle') return\n\t\tif (!this.didExit) {\n\t\t\tthis.didExit = true\n\t\t\tthis.editor.bailToMark(this.markId)\n\t\t}\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAkD;AAClD,sBAAyB;AACzB,kBAAqB;AACrB,0BAA6B;AAC7B,gCAAmC;AACnC,6BAAgC;AAEzB,MAAM,aAAa,wBAAU;AAAA,EACnC,OAAgB,KAAK;AAAA,EACrB,OAAgB,UAAU;AAAA,EAC1B,OAAgB,WAAqC;AACpD,WAAO,CAAC,kBAAM,wCAAiB,kCAAc,8CAAoB,wBAAQ;AAAA,EAC1E;AAAA,EAEA,SAAS;AAAA,EAEA,UAAU;AAClB,SAAK,UAAU;AACf,SAAK,SAAS,KAAK,OAAO,yBAAyB,MAAM;AAAA,EAC1D;AAAA,EACA,UAAU;AAAA,EACD,SAAS;AACjB,QAAI,CAAC,KAAK,SAAS;AAClB,WAAK,UAAU;AACf,UAAI,KAAK,OAAO,kBAAkB,KAAK,MAAM,MAAM,KAAK,QAAQ;AAC/D,aAAK,OAAO,aAAa,KAAK,MAAM;AAAA,MACrC;AAAA,IACD;AAAA,EACD;AAAA,EACS,WAAW;AAInB,QAAI,KAAK,WAAW,GAAG,OAAO,OAAQ;AACtC,QAAI,CAAC,KAAK,SAAS;AAClB,WAAK,UAAU;AACf,WAAK,OAAO,WAAW,KAAK,MAAM;AAAA,IACnC;AAAA,EACD;AACD;",
6
6
  "names": []
7
7
  }
@@ -257,11 +257,9 @@ class DraggingHandle extends import_editor.StateNode {
257
257
  canSnap = initialHandle.canSnap || initialHandle.snapType !== void 0;
258
258
  }
259
259
  if (canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) {
260
- const pageTransform = editor.getShapePageTransform(shape.id);
261
- if (!pageTransform) throw Error("Expected a page transform");
262
260
  const snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle });
263
261
  if (snap) {
264
- snap.nudge.rot(-editor.getShapeParentTransform(shape).rotation());
262
+ snap.nudge.rot(-editor.getShapePageTransform(shape.id).rotation());
265
263
  point.add(snap.nudge);
266
264
  nextHandle = { ...initialHandle, x: point.x, y: point.y };
267
265
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/SelectTool/childStates/DraggingHandle.tsx"],
4
- "sourcesContent": ["import {\n\tMat,\n\tStateNode,\n\tTLArrowShape,\n\tTLHandle,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tTLShapePartial,\n\tVec,\n\tkickoutOccludedShapes,\n\tsnapAngle,\n\tsortByIndex,\n\tstructuredClone,\n\twarnOnce,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../../../shapes/arrow/ArrowShapeUtil'\nimport { clearArrowTargetState } from '../../../shapes/arrow/arrowTargetState'\nimport { getArrowBindings } from '../../../shapes/arrow/shared'\n\nexport type DraggingHandleInfo = TLPointerEventInfo & {\n\tshape: TLArrowShape | TLLineShape\n\ttarget: 'handle'\n\tonInteractionEnd?: string | (() => void)\n\tisCreating?: boolean\n\tcreatingMarkId?: string\n}\n\nexport class DraggingHandle extends StateNode {\n\tstatic override id = 'dragging_handle'\n\tstatic override trackPerformance = true\n\n\tshapeId!: TLShapeId\n\tinitialHandle!: TLHandle\n\tinitialAdjacentHandle!: TLHandle | null\n\tinitialPagePoint!: Vec\n\n\tmarkId!: string\n\tinitialPageTransform!: Mat\n\tinitialPageRotation!: number\n\n\tinfo!: DraggingHandleInfo\n\n\tisPrecise = false\n\tisPreciseId: TLShapeId | null = null\n\tpointingId: TLShapeId | null = null\n\n\toverride onEnter(info: DraggingHandleInfo) {\n\t\tconst { shape, isCreating, creatingMarkId, handle } = info\n\t\tthis.info = info\n\t\tif (typeof info.onInteractionEnd === 'string') {\n\t\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\t}\n\t\tthis.shapeId = shape.id\n\t\tthis.markId = ''\n\n\t\tif (isCreating) {\n\t\t\tif (creatingMarkId) {\n\t\t\t\tthis.markId = creatingMarkId\n\t\t\t} else {\n\t\t\t\t// handle legacy implicit `creating:{shapeId}` marks\n\t\t\t\tconst markId = this.editor.getMarkIdMatching(\n\t\t\t\t\t`creating:${this.editor.getOnlySelectedShapeId()}`\n\t\t\t\t)\n\t\t\t\tif (markId) {\n\t\t\t\t\tthis.markId = markId\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.markId = this.editor.markHistoryStoppingPoint('dragging handle')\n\t\t}\n\n\t\tthis.initialHandle = structuredClone(handle)\n\n\t\tthis.initialPageTransform = this.editor.getShapePageTransform(shape)!\n\t\tthis.initialPageRotation = this.initialPageTransform.rotation()\n\t\tthis.initialPagePoint = this.editor.inputs.getOriginPagePoint().clone()\n\n\t\tthis.editor.setCursor({ type: isCreating ? 'cross' : 'grabbing', rotation: 0 })\n\n\t\tconst handles = this.editor.getShapeHandles(shape)!.sort(sortByIndex)\n\t\tconst index = handles.findIndex((h) => h.id === info.handle.id)\n\n\t\t// Find the adjacent handle\n\t\tthis.initialAdjacentHandle = null\n\n\t\t// First, check if the handle specifies a custom reference handle\n\t\tif (info.handle.snapReferenceHandleId) {\n\t\t\tconst customHandle = handles.find((h) => h.id === info.handle.snapReferenceHandleId)\n\t\t\tif (customHandle) {\n\t\t\t\tthis.initialAdjacentHandle = customHandle\n\t\t\t}\n\t\t}\n\n\t\t// If no custom reference handle, use default behavior\n\t\tif (!this.initialAdjacentHandle) {\n\t\t\t// Start from the handle and work forward\n\t\t\tfor (let i = index + 1; i < handles.length; i++) {\n\t\t\t\tconst handle = handles[i]\n\t\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If still no handle, start from the end and work backward\n\t\t\tif (!this.initialAdjacentHandle) {\n\t\t\t\tfor (let i = handles.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst handle = handles[i]\n\t\t\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// <!-- Only relevant to arrows\n\t\tif (this.editor.isShapeOfType(shape, 'arrow')) {\n\t\t\tconst initialBinding = getArrowBindings(this.editor, shape)[info.handle.id as 'start' | 'end']\n\n\t\t\tthis.isPrecise = false\n\n\t\t\tif (initialBinding) {\n\t\t\t\tthis.isPrecise = initialBinding.props.isPrecise\n\t\t\t\tif (this.isPrecise) {\n\t\t\t\t\tthis.isPreciseId = initialBinding.toId\n\t\t\t\t} else {\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// -->\n\n\t\t// Call onHandleDragStart callback\n\t\tconst handleDragInfo = {\n\t\t\thandle: this.initialHandle,\n\t\t\tisPrecise: this.isPrecise,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: shape,\n\t\t}\n\t\tconst util = this.editor.getShapeUtil(shape)\n\t\tconst startChanges = util.onHandleDragStart?.(shape, handleDragInfo)\n\t\tif (startChanges) {\n\t\t\tthis.editor.updateShapes([{ ...startChanges, id: shape.id, type: shape.type }])\n\t\t}\n\n\t\tthis.update()\n\n\t\tthis.editor.select(this.shapeId)\n\t}\n\n\t// Only relevant to arrows\n\tprivate exactTimeout = -1\n\n\t// Only relevant to arrows\n\tprivate resetExactTimeout() {\n\t\tconst arrowUtil = this.editor.getShapeUtil<ArrowShapeUtil>('arrow')\n\t\tconst timeoutValue = arrowUtil.options.pointingPreciseTimeout\n\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tthis.clearExactTimeout()\n\t\t}\n\n\t\tthis.exactTimeout = this.editor.timers.setTimeout(() => {\n\t\t\tif (this.getIsActive() && !this.isPrecise) {\n\t\t\t\tthis.isPrecise = true\n\t\t\t\tthis.isPreciseId = this.pointingId\n\t\t\t\tthis.update()\n\t\t\t}\n\t\t\tthis.exactTimeout = -1\n\t\t}, timeoutValue)\n\t}\n\n\t// Only relevant to arrows\n\tprivate clearExactTimeout() {\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tclearTimeout(this.exactTimeout)\n\t\t\tthis.exactTimeout = -1\n\t\t}\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.update()\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onExit() {\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\t\tclearArrowTargetState(this.editor)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t}\n\n\tprivate complete() {\n\t\tthis.editor.snaps.clearIndicators()\n\t\tkickoutOccludedShapes(this.editor, [this.shapeId])\n\n\t\t// Call onHandleDragEnd callback before state transitions\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tconst endChanges = util.onHandleDragEnd?.(shape, handleDragInfo)\n\t\t\tif (endChanges) {\n\t\t\t\tthis.editor.updateShapes([{ ...endChanges, id: shape.id }])\n\t\t\t}\n\t\t}\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\tif (typeof onInteractionEnd === 'string') {\n\t\t\t\tif (this.editor.getInstanceState().isToolLocked && onInteractionEnd) {\n\t\t\t\t\t// Return to the tool that was active before this one but only if tool lock is turned on!\n\t\t\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tonInteractionEnd?.()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate cancel() {\n\t\t// Call onHandleDragCancel callback before bailing to mark\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tutil.onHandleDragCancel?.(shape, handleDragInfo)\n\t\t}\n\n\t\tthis.editor.bailToMark(this.markId)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\tif (typeof onInteractionEnd === 'string') {\n\t\t\t\t// Return to the tool that was active before this one, whether tool lock is turned on or not!\n\t\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\t} else {\n\t\t\t\tonInteractionEnd?.()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate update() {\n\t\tconst { editor, shapeId, initialPagePoint } = this\n\t\tconst { initialHandle, initialPageRotation, initialAdjacentHandle } = this\n\t\tconst isSnapMode = this.editor.user.getIsSnapMode()\n\t\tconst { snaps } = editor\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst shiftKey = editor.inputs.getShiftKey()\n\t\tconst ctrlKey = editor.inputs.getCtrlKey()\n\t\tconst altKey = editor.inputs.getAltKey()\n\t\tconst pointerVelocity = editor.inputs.getPointerVelocity()\n\n\t\tconst initial = this.info.shape\n\n\t\tconst shape = editor.getShape(shapeId)\n\t\tif (!shape) return\n\t\tconst util = editor.getShapeUtil(shape)\n\n\t\tconst initialBinding = editor.isShapeOfType(shape, 'arrow')\n\t\t\t? getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\t\t\t: undefined\n\n\t\tlet point = currentPagePoint\n\t\t\t.clone()\n\t\t\t.sub(initialPagePoint)\n\t\t\t.rot(-initialPageRotation)\n\t\t\t.add(initialHandle)\n\n\t\tif (shiftKey && initialAdjacentHandle && initialHandle.id !== 'middle') {\n\t\t\tconst angle = Vec.Angle(initialAdjacentHandle, point)\n\t\t\tconst snappedAngle = snapAngle(angle, 24)\n\t\t\tconst angleDifference = snappedAngle - angle\n\t\t\tpoint = Vec.RotWith(point, initialAdjacentHandle, angleDifference)\n\t\t}\n\n\t\t// Clear any existing snaps\n\t\teditor.snaps.clearIndicators()\n\n\t\tlet nextHandle = { ...initialHandle, x: point.x, y: point.y }\n\n\t\tlet canSnap = false\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif (initialHandle.canSnap && initialHandle.snapType) {\n\t\t\twarnOnce(\n\t\t\t\t'canSnap is deprecated. Cannot use both canSnap and snapType together - snapping disabled. Please use only snapType.'\n\t\t\t)\n\t\t} else {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tcanSnap = initialHandle.canSnap || initialHandle.snapType !== undefined\n\t\t}\n\n\t\tif (canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) {\n\t\t\t// We're snapping\n\t\t\tconst pageTransform = editor.getShapePageTransform(shape.id)\n\t\t\tif (!pageTransform) throw Error('Expected a page transform')\n\n\t\t\tconst snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle })\n\n\t\t\tif (snap) {\n\t\t\t\tsnap.nudge.rot(-editor.getShapeParentTransform(shape)!.rotation())\n\t\t\t\tpoint.add(snap.nudge)\n\t\t\t\tnextHandle = { ...initialHandle, x: point.x, y: point.y }\n\t\t\t}\n\t\t}\n\n\t\tconst changes = util.onHandleDrag?.(shape, {\n\t\t\thandle: nextHandle,\n\t\t\tisPrecise: this.isPrecise || altKey,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: initial,\n\t\t})\n\n\t\tconst next: TLShapePartial<any> = { id: shape.id, type: shape.type, ...changes }\n\n\t\t// Arrows\n\t\tif (initialHandle.type === 'vertex' && this.editor.isShapeOfType(shape, 'arrow')) {\n\t\t\tconst bindingAfter = getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\n\t\t\tif (bindingAfter) {\n\t\t\t\tif (initialBinding?.toId !== bindingAfter.toId) {\n\t\t\t\t\tthis.pointingId = bindingAfter.toId\n\t\t\t\t\tthis.isPrecise = pointerVelocity.len() < 0.5 || altKey\n\t\t\t\t\tthis.isPreciseId = this.isPrecise ? bindingAfter.toId : null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (initialBinding) {\n\t\t\t\t\tthis.pointingId = null\n\t\t\t\t\tthis.isPrecise = false\n\t\t\t\t\tthis.isPreciseId = null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (changes) {\n\t\t\teditor.updateShapes([next])\n\t\t}\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tMat,\n\tStateNode,\n\tTLArrowShape,\n\tTLHandle,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tTLShapePartial,\n\tVec,\n\tkickoutOccludedShapes,\n\tsnapAngle,\n\tsortByIndex,\n\tstructuredClone,\n\twarnOnce,\n} from '@tldraw/editor'\nimport { ArrowShapeUtil } from '../../../shapes/arrow/ArrowShapeUtil'\nimport { clearArrowTargetState } from '../../../shapes/arrow/arrowTargetState'\nimport { getArrowBindings } from '../../../shapes/arrow/shared'\n\nexport type DraggingHandleInfo = TLPointerEventInfo & {\n\tshape: TLArrowShape | TLLineShape\n\ttarget: 'handle'\n\tonInteractionEnd?: string | (() => void)\n\tisCreating?: boolean\n\tcreatingMarkId?: string\n}\n\nexport class DraggingHandle extends StateNode {\n\tstatic override id = 'dragging_handle'\n\tstatic override trackPerformance = true\n\n\tshapeId!: TLShapeId\n\tinitialHandle!: TLHandle\n\tinitialAdjacentHandle!: TLHandle | null\n\tinitialPagePoint!: Vec\n\n\tmarkId!: string\n\tinitialPageTransform!: Mat\n\tinitialPageRotation!: number\n\n\tinfo!: DraggingHandleInfo\n\n\tisPrecise = false\n\tisPreciseId: TLShapeId | null = null\n\tpointingId: TLShapeId | null = null\n\n\toverride onEnter(info: DraggingHandleInfo) {\n\t\tconst { shape, isCreating, creatingMarkId, handle } = info\n\t\tthis.info = info\n\t\tif (typeof info.onInteractionEnd === 'string') {\n\t\t\tthis.parent.setCurrentToolIdMask(info.onInteractionEnd)\n\t\t}\n\t\tthis.shapeId = shape.id\n\t\tthis.markId = ''\n\n\t\tif (isCreating) {\n\t\t\tif (creatingMarkId) {\n\t\t\t\tthis.markId = creatingMarkId\n\t\t\t} else {\n\t\t\t\t// handle legacy implicit `creating:{shapeId}` marks\n\t\t\t\tconst markId = this.editor.getMarkIdMatching(\n\t\t\t\t\t`creating:${this.editor.getOnlySelectedShapeId()}`\n\t\t\t\t)\n\t\t\t\tif (markId) {\n\t\t\t\t\tthis.markId = markId\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tthis.markId = this.editor.markHistoryStoppingPoint('dragging handle')\n\t\t}\n\n\t\tthis.initialHandle = structuredClone(handle)\n\n\t\tthis.initialPageTransform = this.editor.getShapePageTransform(shape)!\n\t\tthis.initialPageRotation = this.initialPageTransform.rotation()\n\t\tthis.initialPagePoint = this.editor.inputs.getOriginPagePoint().clone()\n\n\t\tthis.editor.setCursor({ type: isCreating ? 'cross' : 'grabbing', rotation: 0 })\n\n\t\tconst handles = this.editor.getShapeHandles(shape)!.sort(sortByIndex)\n\t\tconst index = handles.findIndex((h) => h.id === info.handle.id)\n\n\t\t// Find the adjacent handle\n\t\tthis.initialAdjacentHandle = null\n\n\t\t// First, check if the handle specifies a custom reference handle\n\t\tif (info.handle.snapReferenceHandleId) {\n\t\t\tconst customHandle = handles.find((h) => h.id === info.handle.snapReferenceHandleId)\n\t\t\tif (customHandle) {\n\t\t\t\tthis.initialAdjacentHandle = customHandle\n\t\t\t}\n\t\t}\n\n\t\t// If no custom reference handle, use default behavior\n\t\tif (!this.initialAdjacentHandle) {\n\t\t\t// Start from the handle and work forward\n\t\t\tfor (let i = index + 1; i < handles.length; i++) {\n\t\t\t\tconst handle = handles[i]\n\t\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If still no handle, start from the end and work backward\n\t\t\tif (!this.initialAdjacentHandle) {\n\t\t\t\tfor (let i = handles.length - 1; i >= 0; i--) {\n\t\t\t\t\tconst handle = handles[i]\n\t\t\t\t\tif (handle.type === 'vertex' && handle.id !== 'middle' && handle.id !== info.handle.id) {\n\t\t\t\t\t\tthis.initialAdjacentHandle = handle\n\t\t\t\t\t\tbreak\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// <!-- Only relevant to arrows\n\t\tif (this.editor.isShapeOfType(shape, 'arrow')) {\n\t\t\tconst initialBinding = getArrowBindings(this.editor, shape)[info.handle.id as 'start' | 'end']\n\n\t\t\tthis.isPrecise = false\n\n\t\t\tif (initialBinding) {\n\t\t\t\tthis.isPrecise = initialBinding.props.isPrecise\n\t\t\t\tif (this.isPrecise) {\n\t\t\t\t\tthis.isPreciseId = initialBinding.toId\n\t\t\t\t} else {\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\t// -->\n\n\t\t// Call onHandleDragStart callback\n\t\tconst handleDragInfo = {\n\t\t\thandle: this.initialHandle,\n\t\t\tisPrecise: this.isPrecise,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: shape,\n\t\t}\n\t\tconst util = this.editor.getShapeUtil(shape)\n\t\tconst startChanges = util.onHandleDragStart?.(shape, handleDragInfo)\n\t\tif (startChanges) {\n\t\t\tthis.editor.updateShapes([{ ...startChanges, id: shape.id, type: shape.type }])\n\t\t}\n\n\t\tthis.update()\n\n\t\tthis.editor.select(this.shapeId)\n\t}\n\n\t// Only relevant to arrows\n\tprivate exactTimeout = -1\n\n\t// Only relevant to arrows\n\tprivate resetExactTimeout() {\n\t\tconst arrowUtil = this.editor.getShapeUtil<ArrowShapeUtil>('arrow')\n\t\tconst timeoutValue = arrowUtil.options.pointingPreciseTimeout\n\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tthis.clearExactTimeout()\n\t\t}\n\n\t\tthis.exactTimeout = this.editor.timers.setTimeout(() => {\n\t\t\tif (this.getIsActive() && !this.isPrecise) {\n\t\t\t\tthis.isPrecise = true\n\t\t\t\tthis.isPreciseId = this.pointingId\n\t\t\t\tthis.update()\n\t\t\t}\n\t\t\tthis.exactTimeout = -1\n\t\t}, timeoutValue)\n\t}\n\n\t// Only relevant to arrows\n\tprivate clearExactTimeout() {\n\t\tif (this.exactTimeout !== -1) {\n\t\t\tclearTimeout(this.exactTimeout)\n\t\t\tthis.exactTimeout = -1\n\t\t}\n\t}\n\n\toverride onPointerMove() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis.update()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis.update()\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onComplete() {\n\t\tthis.update()\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onExit() {\n\t\tthis.parent.setCurrentToolIdMask(undefined)\n\t\tclearArrowTargetState(this.editor)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tthis.editor.setCursor({ type: 'default', rotation: 0 })\n\t}\n\n\tprivate complete() {\n\t\tthis.editor.snaps.clearIndicators()\n\t\tkickoutOccludedShapes(this.editor, [this.shapeId])\n\n\t\t// Call onHandleDragEnd callback before state transitions\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tconst endChanges = util.onHandleDragEnd?.(shape, handleDragInfo)\n\t\t\tif (endChanges) {\n\t\t\t\tthis.editor.updateShapes([{ ...endChanges, id: shape.id }])\n\t\t\t}\n\t\t}\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\tif (typeof onInteractionEnd === 'string') {\n\t\t\t\tif (this.editor.getInstanceState().isToolLocked && onInteractionEnd) {\n\t\t\t\t\t// Return to the tool that was active before this one but only if tool lock is turned on!\n\t\t\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tonInteractionEnd?.()\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate cancel() {\n\t\t// Call onHandleDragCancel callback before bailing to mark\n\t\tconst shape = this.editor.getShape(this.shapeId)\n\t\tif (shape) {\n\t\t\tconst util = this.editor.getShapeUtil(shape)\n\t\t\tconst handleDragInfo = {\n\t\t\t\thandle: this.initialHandle,\n\t\t\t\tisPrecise: this.isPrecise,\n\t\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\t\tinitial: this.info.shape,\n\t\t\t}\n\t\t\tutil.onHandleDragCancel?.(shape, handleDragInfo)\n\t\t}\n\n\t\tthis.editor.bailToMark(this.markId)\n\t\tthis.editor.snaps.clearIndicators()\n\n\t\tconst { onInteractionEnd } = this.info\n\t\tif (onInteractionEnd) {\n\t\t\tif (typeof onInteractionEnd === 'string') {\n\t\t\t\t// Return to the tool that was active before this one, whether tool lock is turned on or not!\n\t\t\t\tthis.editor.setCurrentTool(onInteractionEnd, { shapeId: this.shapeId })\n\t\t\t} else {\n\t\t\t\tonInteractionEnd?.()\n\t\t\t}\n\t\t\treturn\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tprivate update() {\n\t\tconst { editor, shapeId, initialPagePoint } = this\n\t\tconst { initialHandle, initialPageRotation, initialAdjacentHandle } = this\n\t\tconst isSnapMode = this.editor.user.getIsSnapMode()\n\t\tconst { snaps } = editor\n\t\tconst currentPagePoint = editor.inputs.getCurrentPagePoint()\n\t\tconst shiftKey = editor.inputs.getShiftKey()\n\t\tconst ctrlKey = editor.inputs.getCtrlKey()\n\t\tconst altKey = editor.inputs.getAltKey()\n\t\tconst pointerVelocity = editor.inputs.getPointerVelocity()\n\n\t\tconst initial = this.info.shape\n\n\t\tconst shape = editor.getShape(shapeId)\n\t\tif (!shape) return\n\t\tconst util = editor.getShapeUtil(shape)\n\n\t\tconst initialBinding = editor.isShapeOfType(shape, 'arrow')\n\t\t\t? getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\t\t\t: undefined\n\n\t\tlet point = currentPagePoint\n\t\t\t.clone()\n\t\t\t.sub(initialPagePoint)\n\t\t\t.rot(-initialPageRotation)\n\t\t\t.add(initialHandle)\n\n\t\tif (shiftKey && initialAdjacentHandle && initialHandle.id !== 'middle') {\n\t\t\tconst angle = Vec.Angle(initialAdjacentHandle, point)\n\t\t\tconst snappedAngle = snapAngle(angle, 24)\n\t\t\tconst angleDifference = snappedAngle - angle\n\t\t\tpoint = Vec.RotWith(point, initialAdjacentHandle, angleDifference)\n\t\t}\n\n\t\t// Clear any existing snaps\n\t\teditor.snaps.clearIndicators()\n\n\t\tlet nextHandle = { ...initialHandle, x: point.x, y: point.y }\n\n\t\tlet canSnap = false\n\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\tif (initialHandle.canSnap && initialHandle.snapType) {\n\t\t\twarnOnce(\n\t\t\t\t'canSnap is deprecated. Cannot use both canSnap and snapType together - snapping disabled. Please use only snapType.'\n\t\t\t)\n\t\t} else {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-deprecated\n\t\t\tcanSnap = initialHandle.canSnap || initialHandle.snapType !== undefined\n\t\t}\n\n\t\tif (canSnap && (isSnapMode ? !ctrlKey : ctrlKey)) {\n\t\t\t// We're snapping\n\t\t\tconst snap = snaps.handles.snapHandle({ currentShapeId: shapeId, handle: nextHandle })\n\n\t\t\tif (snap) {\n\t\t\t\t// The nudge is in page space and `point` is in the shape's own space, so the shape's\n\t\t\t\t// full page rotation (not just its parent's) has to come off\n\t\t\t\tsnap.nudge.rot(-editor.getShapePageTransform(shape.id).rotation())\n\t\t\t\tpoint.add(snap.nudge)\n\t\t\t\tnextHandle = { ...initialHandle, x: point.x, y: point.y }\n\t\t\t}\n\t\t}\n\n\t\tconst changes = util.onHandleDrag?.(shape, {\n\t\t\thandle: nextHandle,\n\t\t\tisPrecise: this.isPrecise || altKey,\n\t\t\tisCreatingShape: !!this.info.isCreating,\n\t\t\tinitial: initial,\n\t\t})\n\n\t\tconst next: TLShapePartial<any> = { id: shape.id, type: shape.type, ...changes }\n\n\t\t// Arrows\n\t\tif (initialHandle.type === 'vertex' && this.editor.isShapeOfType(shape, 'arrow')) {\n\t\t\tconst bindingAfter = getArrowBindings(editor, shape)[initialHandle.id as 'start' | 'end']\n\n\t\t\tif (bindingAfter) {\n\t\t\t\tif (initialBinding?.toId !== bindingAfter.toId) {\n\t\t\t\t\tthis.pointingId = bindingAfter.toId\n\t\t\t\t\tthis.isPrecise = pointerVelocity.len() < 0.5 || altKey\n\t\t\t\t\tthis.isPreciseId = this.isPrecise ? bindingAfter.toId : null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tif (initialBinding) {\n\t\t\t\t\tthis.pointingId = null\n\t\t\t\t\tthis.isPrecise = false\n\t\t\t\t\tthis.isPreciseId = null\n\t\t\t\t\tthis.resetExactTimeout()\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tif (changes) {\n\t\t\teditor.updateShapes([next])\n\t\t}\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["handle"]
7
7
  }
@@ -348,6 +348,7 @@ class Idle extends import_editor.StateNode {
348
348
  if (util.onDoubleClick) {
349
349
  const change = util.onDoubleClick?.(shape);
350
350
  if (change) {
351
+ this.editor.markHistoryStoppingPoint("double click shape");
351
352
  this.editor.updateShapes([change]);
352
353
  return;
353
354
  }
@@ -376,6 +377,7 @@ class Idle extends import_editor.StateNode {
376
377
  const util = this.editor.getShapeUtil(shape);
377
378
  const changes = util.onDoubleClickHandle?.(shape, handle);
378
379
  if (changes) {
380
+ this.editor.markHistoryStoppingPoint("double click handle");
379
381
  this.editor.updateShapes([changes]);
380
382
  } else {
381
383
  if (this.editor.canEditShape(shape)) {
@@ -472,7 +474,7 @@ class Idle extends import_editor.StateNode {
472
474
  }
473
475
  return;
474
476
  }
475
- this.nudgeSelectedShapes(false);
477
+ this.nudgeSelectedShapes(info, false);
476
478
  return;
477
479
  }
478
480
  }
@@ -509,7 +511,7 @@ class Idle extends import_editor.StateNode {
509
511
  );
510
512
  return;
511
513
  }
512
- this.nudgeSelectedShapes(true);
514
+ this.nudgeSelectedShapes(info, true);
513
515
  break;
514
516
  }
515
517
  case "Tab": {
@@ -597,12 +599,13 @@ class Idle extends import_editor.StateNode {
597
599
  if (!this.editor.canEditShape(shape)) return;
598
600
  (0, import_selectHelpers.startEditingShapeWithRichText)(this.editor, id, { info });
599
601
  }
600
- nudgeSelectedShapes(ephemeral = false) {
602
+ nudgeSelectedShapes(info, ephemeral = false) {
601
603
  const {
602
604
  editor: {
603
605
  inputs: { keys }
604
606
  }
605
607
  } = this;
608
+ if (info.altKey || this.editor.inputs.getIsSpacebarPanning()) return;
606
609
  const shiftKey = keys.has("ShiftLeft");
607
610
  const delta = new import_editor.Vec(0, 0);
608
611
  if (keys.has("ArrowLeft")) delta.x -= 1;