tldraw 3.16.0-canary.6f3aedaa1c01 → 3.16.0-canary.76c0d51de595

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 (453) hide show
  1. package/dist-cjs/index.d.ts +359 -113
  2. package/dist-cjs/index.js +40 -14
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/Tldraw.js +12 -2
  5. package/dist-cjs/lib/Tldraw.js.map +2 -2
  6. package/dist-cjs/lib/canvas/TldrawScribble.js +1 -1
  7. package/dist-cjs/lib/canvas/TldrawScribble.js.map +2 -2
  8. package/dist-cjs/lib/defaultExternalContentHandlers.js +15 -4
  9. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/arrow-types.js.map +1 -1
  11. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  12. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  13. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +3 -2
  14. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  15. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js +3 -3
  16. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js.map +1 -1
  17. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +1 -1
  18. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  19. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  20. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  21. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +1 -1
  22. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
  23. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +12 -5
  24. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  25. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
  26. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
  27. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +8 -2
  28. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  29. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  30. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  31. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +6 -3
  32. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  33. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  34. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  35. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  36. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  37. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  38. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  39. package/dist-cjs/lib/shapes/shared/ShapeFill.js +1 -1
  40. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  41. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  42. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -5
  43. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  44. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  45. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  46. package/dist-cjs/lib/shapes/text/PlainTextArea.js +3 -2
  47. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  48. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  49. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  50. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  51. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  52. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  53. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  54. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  55. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  56. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +3 -1
  57. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  58. package/dist-cjs/lib/ui/TldrawUi.js +27 -12
  59. package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
  60. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  61. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  62. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  63. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  64. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +10 -2
  65. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  66. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  67. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  68. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  69. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  70. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  71. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  72. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +2 -1
  73. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  74. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  75. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  76. package/dist-cjs/lib/ui/components/MobileStylePanel.js +4 -2
  77. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  78. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  79. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  80. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  81. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  82. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  83. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  84. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  85. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  86. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  87. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  88. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  89. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  90. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +24 -21
  91. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  92. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  93. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  94. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +2 -0
  95. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  96. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +39 -10
  97. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  98. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -22
  99. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
  100. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  101. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  102. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
  103. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  104. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +188 -78
  105. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
  106. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +6 -2
  107. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  108. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  109. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  110. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +5 -3
  111. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  112. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  113. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  114. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +18 -3
  115. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  116. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +187 -165
  117. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  118. package/dist-cjs/lib/ui/components/primitives/layout.js +30 -5
  119. package/dist-cjs/lib/ui/components/primitives/layout.js.map +2 -2
  120. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  121. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  122. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  123. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
  124. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  125. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +11 -27
  126. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  127. package/dist-cjs/lib/ui/context/actions.js +29 -10
  128. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  129. package/dist-cjs/lib/ui/context/components.js +2 -0
  130. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  131. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  132. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  133. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  134. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  135. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  136. package/dist-cjs/lib/ui/hooks/useTools.js +22 -4
  137. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  138. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  139. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -2
  140. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  141. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  142. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  143. package/dist-cjs/lib/ui/version.js +3 -3
  144. package/dist-cjs/lib/ui/version.js.map +1 -1
  145. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  146. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  147. package/dist-cjs/lib/utils/export/export.js +0 -20
  148. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  149. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  150. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  151. package/dist-esm/index.d.mts +359 -113
  152. package/dist-esm/index.mjs +76 -30
  153. package/dist-esm/index.mjs.map +2 -2
  154. package/dist-esm/lib/Tldraw.mjs +14 -4
  155. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  156. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  157. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  158. package/dist-esm/lib/defaultExternalContentHandlers.mjs +15 -4
  159. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  160. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  161. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  162. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +3 -2
  163. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  164. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  165. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  166. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +1 -1
  167. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  168. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +4 -5
  169. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  170. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  171. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  172. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +12 -5
  173. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  174. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  175. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  176. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +9 -3
  177. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  178. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  179. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  180. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +6 -3
  181. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  182. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  183. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  184. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  185. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  186. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  187. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  188. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +1 -1
  189. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  190. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  191. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +3 -6
  192. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  193. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  194. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  195. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +4 -3
  196. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  197. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  198. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  199. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  200. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  201. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  202. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  203. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  204. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  205. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +3 -1
  206. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  207. package/dist-esm/lib/ui/TldrawUi.mjs +29 -14
  208. package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
  209. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  210. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  211. package/dist-esm/lib/ui/components/A11y.mjs +1 -2
  212. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  213. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +10 -2
  214. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  215. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  216. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  217. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  218. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  219. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  220. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  221. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +2 -1
  222. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  223. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  224. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  225. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +4 -2
  226. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  227. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +1 -2
  228. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  229. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  230. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  231. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  232. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  233. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
  234. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  235. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  236. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  237. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  238. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  239. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +21 -18
  240. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  241. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  242. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  243. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +2 -0
  244. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  245. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +39 -10
  246. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  247. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -22
  248. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
  249. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  250. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  251. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +2 -1
  252. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  253. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -80
  254. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
  255. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +6 -2
  256. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  257. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +11 -3
  258. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  259. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +6 -4
  260. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  261. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  262. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  263. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +19 -4
  264. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  265. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +197 -167
  266. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  267. package/dist-esm/lib/ui/components/primitives/layout.mjs +31 -6
  268. package/dist-esm/lib/ui/components/primitives/layout.mjs.map +2 -2
  269. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  270. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  271. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  272. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
  273. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  274. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +11 -27
  275. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  276. package/dist-esm/lib/ui/context/actions.mjs +29 -10
  277. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  278. package/dist-esm/lib/ui/context/components.mjs +2 -0
  279. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  280. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  281. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +1 -2
  282. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  283. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  284. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  285. package/dist-esm/lib/ui/hooks/useTools.mjs +23 -4
  286. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  287. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -2
  288. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  289. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  290. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  291. package/dist-esm/lib/ui/version.mjs +3 -3
  292. package/dist-esm/lib/ui/version.mjs.map +1 -1
  293. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  294. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  295. package/dist-esm/lib/utils/export/export.mjs +0 -20
  296. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  297. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  298. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  299. package/package.json +11 -34
  300. package/src/index.ts +56 -22
  301. package/src/lib/Tldraw.tsx +15 -2
  302. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  303. package/src/lib/defaultExternalContentHandlers.ts +26 -4
  304. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +85 -14
  305. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +103 -8
  306. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  307. package/src/lib/shapes/arrow/arrow-types.ts +3 -5
  308. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  309. package/src/lib/shapes/arrow/arrowTargetState.ts +34 -3
  310. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  311. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
  312. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +4 -5
  313. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  314. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  315. package/src/lib/shapes/frame/FrameShapeUtil.tsx +21 -4
  316. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  317. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
  318. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  319. package/src/lib/shapes/image/ImageShapeUtil.tsx +6 -3
  320. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  321. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  322. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  323. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  324. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  325. package/src/lib/shapes/shared/ShapeFill.tsx +1 -1
  326. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  327. package/src/lib/shapes/shared/useEditablePlainText.ts +3 -10
  328. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  329. package/src/lib/shapes/text/PlainTextArea.tsx +4 -3
  330. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  331. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  332. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  333. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  334. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  335. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +6 -2
  336. package/src/lib/ui/TldrawUi.tsx +33 -12
  337. package/src/lib/ui/assetUrls.ts +13 -10
  338. package/src/lib/ui/components/A11y.tsx +1 -2
  339. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +13 -2
  340. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  341. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  342. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  343. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +2 -1
  344. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  345. package/src/lib/ui/components/MobileStylePanel.tsx +4 -3
  346. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +1 -2
  347. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  348. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  349. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  350. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  351. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  352. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  353. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  354. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -0
  355. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +33 -16
  356. package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -24
  357. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  358. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
  359. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +208 -56
  360. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +9 -2
  361. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +7 -3
  362. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
  363. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  364. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +27 -6
  365. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +232 -185
  366. package/src/lib/ui/components/primitives/layout.tsx +79 -5
  367. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  368. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  369. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
  370. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +14 -27
  371. package/src/lib/ui/context/actions.tsx +36 -10
  372. package/src/lib/ui/context/components.tsx +3 -0
  373. package/src/lib/ui/context/events.tsx +1 -1
  374. package/src/lib/ui/hooks/useClipboardEvents.ts +1 -2
  375. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  376. package/src/lib/ui/hooks/useTools.tsx +26 -4
  377. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +4 -0
  378. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -2
  379. package/src/lib/ui/kbd-utils.ts +10 -3
  380. package/src/lib/ui/version.ts +3 -3
  381. package/src/lib/ui.css +389 -246
  382. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  383. package/src/lib/utils/export/copyAs.ts +1 -24
  384. package/src/lib/utils/export/export.ts +0 -36
  385. package/src/lib/utils/export/exportAs.ts +1 -32
  386. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  387. package/src/test/A11y.test.tsx +3 -2
  388. package/src/test/ClickManager.test.ts +7 -6
  389. package/src/test/Editor.test.tsx +20 -19
  390. package/src/test/EraserTool.test.ts +184 -13
  391. package/src/test/HandTool.test.ts +10 -9
  392. package/src/test/HighlightShape.test.ts +2 -1
  393. package/src/test/SelectTool.test.ts +3 -2
  394. package/src/test/TLUserPreferences.test.ts +4 -3
  395. package/src/test/TestEditor.ts +21 -17
  396. package/src/test/TldrawEditor.test.tsx +11 -10
  397. package/src/test/ZoomTool.test.ts +7 -6
  398. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  399. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  400. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  401. package/src/test/arrows-megabus.test.tsx +5 -4
  402. package/src/test/bindings.test.tsx +24 -37
  403. package/src/test/bookmark-shapes.test.ts +1 -8
  404. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  405. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  406. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  407. package/src/test/commands/alignShapes.test.tsx +25 -24
  408. package/src/test/commands/animationSpeed.test.ts +2 -1
  409. package/src/test/commands/centerOnPoint.test.ts +3 -2
  410. package/src/test/commands/clipboard.test.ts +3 -2
  411. package/src/test/commands/createShapes.test.ts +2 -1
  412. package/src/test/commands/deleteShapes.test.ts +2 -1
  413. package/src/test/commands/distributeShapes.test.tsx +11 -10
  414. package/src/test/commands/getSvgString.test.ts +2 -1
  415. package/src/test/commands/packShapes.test.ts +5 -4
  416. package/src/test/commands/resizeShape.test.ts +2 -1
  417. package/src/test/commands/rotateShapes.test.ts +7 -6
  418. package/src/test/commands/setCamera.test.ts +4 -3
  419. package/src/test/commands/setCurrentPage.test.ts +3 -2
  420. package/src/test/commands/stackShapes.test.ts +11 -10
  421. package/src/test/commands/stretch.test.tsx +13 -12
  422. package/src/test/createDeepLink.test.tsx +2 -1
  423. package/src/test/cropping.test.ts +3 -2
  424. package/src/test/custom-clipping.test.ts +436 -0
  425. package/src/test/drawing.test.ts +2 -1
  426. package/src/test/flipShapes.test.ts +4 -3
  427. package/src/test/frames.test.ts +25 -24
  428. package/src/test/getCulledShapes.test.tsx +74 -4
  429. package/src/test/groups.test.tsx +1 -1
  430. package/src/test/handleDeepLink.test.tsx +2 -1
  431. package/src/test/maxShapes.test.ts +3 -2
  432. package/src/test/modifiers.test.ts +5 -4
  433. package/src/test/navigation.test.ts +12 -11
  434. package/src/test/panning.test.ts +2 -1
  435. package/src/test/perf/perf.test.ts +2 -1
  436. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  437. package/src/test/resizing.test.ts +39 -38
  438. package/src/test/select.test.tsx +4 -3
  439. package/src/test/selection-omnibus.test.ts +11 -10
  440. package/src/test/shapeutils.test.ts +4 -3
  441. package/src/test/translating.test.ts +9 -8
  442. package/tldraw.css +697 -538
  443. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  444. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  445. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  446. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  447. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  448. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  449. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  450. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  451. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  452. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  453. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/shapes/shared/freehand/svg.ts"],
4
- "sourcesContent": ["import { average, precise } from '@tldraw/editor'\nimport { StrokePoint } from './types'\n\n/**\n * Turn an array of stroke points into a path of quadradic curves.\n *\n * @param points - The stroke points returned from perfect-freehand\n * @param closed - Whether the shape is closed\n */\nexport function getSvgPathFromStrokePoints(points: StrokePoint[], closed = false): string {\n\tconst len = points.length\n\n\tif (len < 2) {\n\t\treturn ''\n\t}\n\n\tlet a = points[0].point\n\tlet b = points[1].point\n\n\tif (len === 2) {\n\t\treturn `M${precise(a)}L${precise(b)}`\n\t}\n\n\tlet result = ''\n\n\tfor (let i = 2, max = len - 1; i < max; i++) {\n\t\ta = points[i].point\n\t\tb = points[i + 1].point\n\t\tresult += average(a, b)\n\t}\n\n\tif (closed) {\n\t\t// If closed, draw a curve from the last point to the first\n\t\treturn `M${average(points[0].point, points[1].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}T${result}${average(points[len - 1].point, points[0].point)}${average(\n\t\t\tpoints[0].point,\n\t\t\tpoints[1].point\n\t\t)}Z`\n\t} else {\n\t\t// If not closed, draw a curve starting at the first point and\n\t\t// ending at the midpoint of the last and second-last point, then\n\t\t// complete the curve with a line segment to the last point.\n\t\treturn `M${precise(points[0].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}${points.length > 3 ? 'T' : ''}${result}L${precise(points[len - 1].point)}`\n\t}\n}\n"],
5
- "mappings": "AAAA,SAAS,SAAS,eAAe;AAS1B,SAAS,2BAA2B,QAAuB,SAAS,OAAe;AACzF,QAAM,MAAM,OAAO;AAEnB,MAAI,MAAM,GAAG;AACZ,WAAO;AAAA,EACR;AAEA,MAAI,IAAI,OAAO,CAAC,EAAE;AAClB,MAAI,IAAI,OAAO,CAAC,EAAE;AAElB,MAAI,QAAQ,GAAG;AACd,WAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC;AAAA,EACpC;AAEA,MAAI,SAAS;AAEb,WAAS,IAAI,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,KAAK;AAC5C,QAAI,OAAO,CAAC,EAAE;AACd,QAAI,OAAO,IAAI,CAAC,EAAE;AAClB,cAAU,QAAQ,GAAG,CAAC;AAAA,EACvB;AAEA,MAAI,QAAQ;AAEX,WAAO,IAAI,QAAQ,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG;AAAA,MAClF,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,IAAI,MAAM,GAAG,QAAQ,OAAO,MAAM,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG;AAAA,MAC/D,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC;AAAA,EACF,OAAO;AAIN,WAAO,IAAI,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG;AAAA,MACjE,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,GAAG,OAAO,SAAS,IAAI,MAAM,EAAE,GAAG,MAAM,IAAI,QAAQ,OAAO,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,EAC5E;AACD;",
4
+ "sourcesContent": ["import { average, precise } from '@tldraw/editor'\nimport { StrokePoint } from './types'\n\n/**\n * Turn an array of stroke points into a path of quadradic curves.\n *\n * @param points - The stroke points returned from perfect-freehand\n * @param closed - Whether the shape is closed\n *\n * @public\n */\nexport function getSvgPathFromStrokePoints(points: StrokePoint[], closed = false): string {\n\tconst len = points.length\n\n\tif (len < 2) {\n\t\treturn ''\n\t}\n\n\tlet a = points[0].point\n\tlet b = points[1].point\n\n\tif (len === 2) {\n\t\treturn `M${precise(a)}L${precise(b)}`\n\t}\n\n\tlet result = ''\n\n\tfor (let i = 2, max = len - 1; i < max; i++) {\n\t\ta = points[i].point\n\t\tb = points[i + 1].point\n\t\tresult += average(a, b)\n\t}\n\n\tif (closed) {\n\t\t// If closed, draw a curve from the last point to the first\n\t\treturn `M${average(points[0].point, points[1].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}T${result}${average(points[len - 1].point, points[0].point)}${average(\n\t\t\tpoints[0].point,\n\t\t\tpoints[1].point\n\t\t)}Z`\n\t} else {\n\t\t// If not closed, draw a curve starting at the first point and\n\t\t// ending at the midpoint of the last and second-last point, then\n\t\t// complete the curve with a line segment to the last point.\n\t\treturn `M${precise(points[0].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}${points.length > 3 ? 'T' : ''}${result}L${precise(points[len - 1].point)}`\n\t}\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS,eAAe;AAW1B,SAAS,2BAA2B,QAAuB,SAAS,OAAe;AACzF,QAAM,MAAM,OAAO;AAEnB,MAAI,MAAM,GAAG;AACZ,WAAO;AAAA,EACR;AAEA,MAAI,IAAI,OAAO,CAAC,EAAE;AAClB,MAAI,IAAI,OAAO,CAAC,EAAE;AAElB,MAAI,QAAQ,GAAG;AACd,WAAO,IAAI,QAAQ,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC;AAAA,EACpC;AAEA,MAAI,SAAS;AAEb,WAAS,IAAI,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,KAAK;AAC5C,QAAI,OAAO,CAAC,EAAE;AACd,QAAI,OAAO,IAAI,CAAC,EAAE;AAClB,cAAU,QAAQ,GAAG,CAAC;AAAA,EACvB;AAEA,MAAI,QAAQ;AAEX,WAAO,IAAI,QAAQ,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG;AAAA,MAClF,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,IAAI,MAAM,GAAG,QAAQ,OAAO,MAAM,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG;AAAA,MAC/D,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC;AAAA,EACF,OAAO;AAIN,WAAO,IAAI,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,IAAI,QAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,GAAG;AAAA,MACjE,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,GAAG,OAAO,SAAS,IAAI,MAAM,EAAE,GAAG,MAAM,IAAI,QAAQ,OAAO,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,EAC5E;AACD;",
6
6
  "names": []
7
7
  }
@@ -2,7 +2,6 @@ import {
2
2
  getPointerInfo,
3
3
  noop,
4
4
  preventDefault,
5
- stopEventPropagation,
6
5
  tlenv,
7
6
  useEditor,
8
7
  useValue
@@ -93,13 +92,13 @@ function useEditableTextCommon(shapeId) {
93
92
  const handleInputPointerDown = useCallback(
94
93
  (e) => {
95
94
  editor.dispatch({
96
- ...getPointerInfo(e),
95
+ ...getPointerInfo(editor, e),
97
96
  type: "pointer",
98
97
  name: "pointer_down",
99
98
  target: "shape",
100
99
  shape: editor.getShape(shapeId)
101
100
  });
102
- stopEventPropagation(e);
101
+ e.stopPropagation();
103
102
  },
104
103
  [editor, shapeId]
105
104
  );
@@ -121,16 +120,14 @@ function useEditableTextCommon(shapeId) {
121
120
  handleFocus: noop,
122
121
  handleBlur: noop,
123
122
  handleInputPointerDown,
124
- handleDoubleClick: stopEventPropagation,
123
+ handleDoubleClick: editor.markEventAsHandled,
125
124
  handlePaste,
126
125
  isEditing,
127
126
  isReadyForEditing
128
127
  };
129
128
  }
130
- const useEditableText = useEditablePlainText;
131
129
  export {
132
130
  useEditablePlainText,
133
- useEditableText,
134
131
  useEditableTextCommon,
135
132
  useIsReadyForEditing
136
133
  };
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/useEditablePlainText.ts"],
4
- "sourcesContent": ["import {\n\tEditor,\n\tTLShapeId,\n\tTLUnknownShape,\n\tgetPointerInfo,\n\tnoop,\n\tpreventDefault,\n\tstopEventPropagation,\n\ttlenv,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport React, { useCallback, useEffect, useRef } from 'react'\nimport { TextHelpers } from './TextHelpers'\n\n/** @public */\nexport function useEditablePlainText(shapeId: TLShapeId, type: string, text?: string) {\n\tconst commonUseEditableTextHandlers = useEditableTextCommon(shapeId)\n\tconst isEditing = commonUseEditableTextHandlers.isEditing\n\tconst editor = useEditor()\n\tconst rInput = useRef<HTMLTextAreaElement>(null)\n\tconst isEmpty = (text || '').trim().length === 0\n\n\tuseEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === shapeId) {\n\t\t\t\trInput.current?.select?.()\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t}\n\t}, [editor, shapeId, isEditing])\n\n\tuseEffect(() => {\n\t\tif (!isEditing) return\n\n\t\tif (document.activeElement !== rInput.current) {\n\t\t\trInput.current?.focus()\n\t\t}\n\n\t\tif (editor.getInstanceState().isCoarsePointer) {\n\t\t\trInput.current?.select()\n\t\t}\n\n\t\t// XXX(mime): This fixes iOS not showing the caret sometimes.\n\t\t// This \"shakes\" the caret awake.\n\t\tif (tlenv.isSafari) {\n\t\t\trInput.current?.blur()\n\t\t\trInput.current?.focus()\n\t\t}\n\t}, [editor, isEditing])\n\n\t// When the user presses ctrl / meta enter, complete the editing state.\n\tconst handleKeyDown = useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase 'Enter': {\n\t\t\t\t\tif (e.ctrlKey || e.metaKey) {\n\t\t\t\t\t\teditor.complete()\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\t// When the text changes, update the text value.\n\tconst handleChange = useCallback(\n\t\t({ plaintext }: { plaintext: string }) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tconst normalizedPlaintext = TextHelpers.normalizeText(plaintext || '')\n\t\t\teditor.updateShape<TLUnknownShape & { props: { text: string } }>({\n\t\t\t\tid: shapeId,\n\t\t\t\ttype,\n\t\t\t\tprops: { text: normalizedPlaintext },\n\t\t\t})\n\t\t},\n\t\t[editor, shapeId, type]\n\t)\n\n\treturn {\n\t\trInput,\n\t\thandleKeyDown,\n\t\thandleChange,\n\t\tisEmpty,\n\t\t...commonUseEditableTextHandlers,\n\t}\n}\n\n/** @internal */\nexport function useIsReadyForEditing(editor: Editor, shapeId: TLShapeId) {\n\treturn useValue(\n\t\t'isReadyForEditing',\n\t\t() => {\n\t\t\tconst editingShapeId = editor.getEditingShapeId()\n\t\t\treturn (\n\t\t\t\t// something's being editing... and either it's this shape OR this shape is hovered\n\t\t\t\teditingShapeId !== null &&\n\t\t\t\t(editingShapeId === shapeId || editor.getHoveredShapeId() === shapeId)\n\t\t\t)\n\t\t},\n\t\t[editor, shapeId]\n\t)\n}\n\n/** @internal */\nexport function useEditableTextCommon(shapeId: TLShapeId) {\n\tconst editor = useEditor()\n\tconst isEditing = useValue('isEditing', () => editor.getEditingShapeId() === shapeId, [editor])\n\tconst isReadyForEditing = useIsReadyForEditing(editor, shapeId)\n\n\tconst handleInputPointerDown = useCallback(\n\t\t(e: React.PointerEvent) => {\n\t\t\t// N.B. We used to only do this only when isEditing to help\n\t\t\t// prevent an issue where you could drag a selected shape\n\t\t\t// behind another shape. That is addressed now by the CSS logic\n\t\t\t// looking at data-isselectinganything.\n\t\t\t//\n\t\t\t// We still need to follow this logic even if not isEditing\n\t\t\t// because otherwise there is some flakiness in selection.\n\t\t\t// When selecting text, it would sometimes select some text\n\t\t\t// partially if we didn't dispatch/stop below.\n\n\t\t\teditor.dispatch({\n\t\t\t\t...getPointerInfo(e),\n\t\t\t\ttype: 'pointer',\n\t\t\t\tname: 'pointer_down',\n\t\t\t\ttarget: 'shape',\n\t\t\t\tshape: editor.getShape(shapeId)!,\n\t\t\t})\n\n\t\t\tstopEventPropagation(e) // we need to prevent blurring the input\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\tconst handlePaste = useCallback(\n\t\t(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\t\t\tif (e.clipboardData) {\n\t\t\t\t// find html in the clipboard and look for the tldraw data\n\t\t\t\tconst html = e.clipboardData.getData('text/html')\n\t\t\t\tif (html) {\n\t\t\t\t\tif (html.includes('<div data-tldraw')) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\treturn {\n\t\thandleFocus: noop,\n\t\thandleBlur: noop,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick: stopEventPropagation,\n\t\thandlePaste,\n\t\tisEditing,\n\t\tisReadyForEditing,\n\t}\n}\n\n/**\n * @deprecated Use `useEditablePlainText` instead.\n * @public\n */\nexport const useEditableText = useEditablePlainText\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tEditor,\n\tTLShapeId,\n\tTLUnknownShape,\n\tgetPointerInfo,\n\tnoop,\n\tpreventDefault,\n\ttlenv,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport React, { useCallback, useEffect, useRef } from 'react'\nimport { TextHelpers } from './TextHelpers'\n\n/** @public */\nexport function useEditablePlainText(shapeId: TLShapeId, type: string, text?: string) {\n\tconst commonUseEditableTextHandlers = useEditableTextCommon(shapeId)\n\tconst isEditing = commonUseEditableTextHandlers.isEditing\n\tconst editor = useEditor()\n\tconst rInput = useRef<HTMLTextAreaElement>(null)\n\tconst isEmpty = (text || '').trim().length === 0\n\n\tuseEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === shapeId) {\n\t\t\t\trInput.current?.select?.()\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t}\n\t}, [editor, shapeId, isEditing])\n\n\tuseEffect(() => {\n\t\tif (!isEditing) return\n\n\t\tif (document.activeElement !== rInput.current) {\n\t\t\trInput.current?.focus()\n\t\t}\n\n\t\tif (editor.getInstanceState().isCoarsePointer) {\n\t\t\trInput.current?.select()\n\t\t}\n\n\t\t// XXX(mime): This fixes iOS not showing the caret sometimes.\n\t\t// This \"shakes\" the caret awake.\n\t\tif (tlenv.isSafari) {\n\t\t\trInput.current?.blur()\n\t\t\trInput.current?.focus()\n\t\t}\n\t}, [editor, isEditing])\n\n\t// When the user presses ctrl / meta enter, complete the editing state.\n\tconst handleKeyDown = useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase 'Enter': {\n\t\t\t\t\tif (e.ctrlKey || e.metaKey) {\n\t\t\t\t\t\teditor.complete()\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\t// When the text changes, update the text value.\n\tconst handleChange = useCallback(\n\t\t({ plaintext }: { plaintext: string }) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tconst normalizedPlaintext = TextHelpers.normalizeText(plaintext || '')\n\t\t\teditor.updateShape<TLUnknownShape & { props: { text: string } }>({\n\t\t\t\tid: shapeId,\n\t\t\t\ttype,\n\t\t\t\tprops: { text: normalizedPlaintext },\n\t\t\t})\n\t\t},\n\t\t[editor, shapeId, type]\n\t)\n\n\treturn {\n\t\trInput,\n\t\thandleKeyDown,\n\t\thandleChange,\n\t\tisEmpty,\n\t\t...commonUseEditableTextHandlers,\n\t}\n}\n\n/** @internal */\nexport function useIsReadyForEditing(editor: Editor, shapeId: TLShapeId) {\n\treturn useValue(\n\t\t'isReadyForEditing',\n\t\t() => {\n\t\t\tconst editingShapeId = editor.getEditingShapeId()\n\t\t\treturn (\n\t\t\t\t// something's being editing... and either it's this shape OR this shape is hovered\n\t\t\t\teditingShapeId !== null &&\n\t\t\t\t(editingShapeId === shapeId || editor.getHoveredShapeId() === shapeId)\n\t\t\t)\n\t\t},\n\t\t[editor, shapeId]\n\t)\n}\n\n/** @internal */\nexport function useEditableTextCommon(shapeId: TLShapeId) {\n\tconst editor = useEditor()\n\tconst isEditing = useValue('isEditing', () => editor.getEditingShapeId() === shapeId, [editor])\n\tconst isReadyForEditing = useIsReadyForEditing(editor, shapeId)\n\n\tconst handleInputPointerDown = useCallback(\n\t\t(e: React.PointerEvent) => {\n\t\t\t// N.B. We used to only do this only when isEditing to help\n\t\t\t// prevent an issue where you could drag a selected shape\n\t\t\t// behind another shape. That is addressed now by the CSS logic\n\t\t\t// looking at data-isselectinganything.\n\t\t\t//\n\t\t\t// We still need to follow this logic even if not isEditing\n\t\t\t// because otherwise there is some flakiness in selection.\n\t\t\t// When selecting text, it would sometimes select some text\n\t\t\t// partially if we didn't dispatch/stop below.\n\n\t\t\teditor.dispatch({\n\t\t\t\t...getPointerInfo(editor, e),\n\t\t\t\ttype: 'pointer',\n\t\t\t\tname: 'pointer_down',\n\t\t\t\ttarget: 'shape',\n\t\t\t\tshape: editor.getShape(shapeId)!,\n\t\t\t})\n\n\t\t\te.stopPropagation() // we need to prevent blurring the input\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\tconst handlePaste = useCallback(\n\t\t(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\t\t\tif (e.clipboardData) {\n\t\t\t\t// find html in the clipboard and look for the tldraw data\n\t\t\t\tconst html = e.clipboardData.getData('text/html')\n\t\t\t\tif (html) {\n\t\t\t\t\tif (html.includes('<div data-tldraw')) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\treturn {\n\t\thandleFocus: noop,\n\t\thandleBlur: noop,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick: editor.markEventAsHandled,\n\t\thandlePaste,\n\t\tisEditing,\n\t\tisReadyForEditing,\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -79,9 +79,7 @@ function resolveAssetUrl(editor, assetId, screenScale, exportInfo, callback) {
79
79
  callback(url);
80
80
  });
81
81
  }
82
- const useAsset = useImageOrVideoAsset;
83
82
  export {
84
- useAsset,
85
83
  useImageOrVideoAsset
86
84
  };
87
85
  //# sourceMappingURL=useImageOrVideoAsset.mjs.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/useImageOrVideoAsset.ts"],
4
- "sourcesContent": ["import {\n\tEditor,\n\tSvgExportContext,\n\tTLAssetId,\n\tTLImageAsset,\n\tTLShapeId,\n\tTLVideoAsset,\n\treact,\n\tuseDelaySvgExport,\n\tuseEditor,\n\tuseSvgExportContext,\n} from '@tldraw/editor'\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * Options for {@link useImageOrVideoAsset}.\n *\n * @public\n */\nexport interface UseImageOrVideoAssetOptions {\n\t/** The asset ID you want a URL for. */\n\tassetId: TLAssetId | null\n\t/**\n\t * The shape the asset is being used for. We won't update the resolved URL while the shape is\n\t * off-screen.\n\t */\n\tshapeId?: TLShapeId\n\t/**\n\t * The width at which the asset will be displayed, in shape-space pixels.\n\t */\n\twidth: number\n}\n\n/**\n * This is a handy helper hook that resolves an asset to an optimized URL for a given shape, or its\n * {@link @tldraw/editor#Editor.createTemporaryAssetPreview | placeholder} if the asset is still\n * uploading. This is used in particular for high-resolution images when you want lower and higher\n * resolution depending on the size of the image on the canvas and the zoom level.\n *\n * For image scaling to work, you need to implement scaled URLs in\n * {@link @tldraw/tlschema#TLAssetStore.resolve}.\n *\n * @public\n */\nexport function useImageOrVideoAsset({ shapeId, assetId, width }: UseImageOrVideoAssetOptions) {\n\tconst editor = useEditor()\n\tconst exportInfo = useSvgExportContext()\n\tconst exportIsReady = useDelaySvgExport()\n\n\t// We use a state to store the result of the asset resolution, and we're going to avoid updating this whenever we can\n\tconst [result, setResult] = useState<{\n\t\tasset: (TLImageAsset | TLVideoAsset) | null\n\t\turl: string | null\n\t}>(() => ({\n\t\tasset: assetId ? (editor.getAsset<TLImageAsset | TLVideoAsset>(assetId) ?? null) : null,\n\t\turl: null as string | null,\n\t}))\n\n\t// A flag for whether we've resolved the asset URL at least once, after which we can debounce\n\tconst didAlreadyResolve = useRef(false)\n\n\t// The last URL that we've seen for the shape\n\tconst previousUrl = useRef<string | null>(null)\n\n\tuseEffect(() => {\n\t\tif (!assetId) return\n\n\t\tlet isCancelled = false\n\t\tlet cancelDebounceFn: (() => void) | undefined\n\n\t\tconst cleanupEffectScheduler = react('update state', () => {\n\t\t\tif (!exportInfo && shapeId && editor.getCulledShapes().has(shapeId)) return\n\n\t\t\t// Get the fresh asset\n\t\t\tconst asset = editor.getAsset<TLImageAsset | TLVideoAsset>(assetId)\n\t\t\tif (!asset) {\n\t\t\t\t// If the asset is deleted, such as when an upload fails, set the URL to null\n\t\t\t\tsetResult((prev) => ({ ...prev, asset: null, url: null }))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Set initial preview for the shape if it has no source (if it was pasted into a local project as base64)\n\t\t\tif (!asset.props.src) {\n\t\t\t\tconst preview = editor.getTemporaryAssetPreview(asset.id)\n\t\t\t\tif (preview) {\n\t\t\t\t\tif (previousUrl.current !== preview) {\n\t\t\t\t\t\tpreviousUrl.current = preview // just for kicks, let's save the url as the previous URL\n\t\t\t\t\t\tsetResult((prev) => ({ ...prev, isPlaceholder: true, url: preview })) // set the preview as the URL\n\t\t\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// aside ...we could bail here if the only thing that has changed is the shape has changed from culled to not culled\n\n\t\t\tconst screenScale = exportInfo\n\t\t\t\t? exportInfo.scale * (width / asset.props.w)\n\t\t\t\t: editor.getZoomLevel() * (width / asset.props.w)\n\n\t\t\tfunction resolve(asset: TLImageAsset | TLVideoAsset, url: string | null) {\n\t\t\t\tif (isCancelled) return // don't update if the hook has remounted\n\t\t\t\tif (previousUrl.current === url) return // don't update the state if the url is the same\n\t\t\t\tdidAlreadyResolve.current = true // mark that we've resolved our first image\n\t\t\t\tpreviousUrl.current = url // keep the url around to compare with the next one\n\t\t\t\tsetResult({ asset, url })\n\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t}\n\n\t\t\t// If we already resolved the URL, debounce fetching potentially multiple image variations.\n\t\t\tif (didAlreadyResolve.current) {\n\t\t\t\tlet tick = 0\n\n\t\t\t\tconst resolveAssetAfterAWhile = () => {\n\t\t\t\t\ttick++\n\t\t\t\t\tif (tick > 500 / 16) {\n\t\t\t\t\t\t// debounce for 500ms\n\t\t\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t\t\t\tcancelDebounceFn?.()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcancelDebounceFn?.()\n\t\t\t\teditor.on('tick', resolveAssetAfterAWhile)\n\t\t\t\tcancelDebounceFn = () => editor.off('tick', resolveAssetAfterAWhile)\n\t\t\t} else {\n\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t}\n\t\t})\n\n\t\treturn () => {\n\t\t\tcleanupEffectScheduler()\n\t\t\tcancelDebounceFn?.()\n\t\t\tisCancelled = true\n\t\t}\n\t}, [editor, assetId, exportInfo, exportIsReady, shapeId, width])\n\n\treturn result\n}\n\nfunction resolveAssetUrl(\n\teditor: Editor,\n\tassetId: TLAssetId,\n\tscreenScale: number,\n\texportInfo: SvgExportContext | null,\n\tcallback: (url: string | null) => void\n) {\n\teditor\n\t\t.resolveAssetUrl(assetId, {\n\t\t\tscreenScale,\n\t\t\tshouldResolveToOriginal: exportInfo ? exportInfo.pixelRatio === null : false,\n\t\t\tdpr: exportInfo?.pixelRatio ?? undefined,\n\t\t})\n\t\t// There's a weird bug with out debounce function that doesn't\n\t\t// make it work right with async functions, so we use a callback\n\t\t// here instead of returning a promise.\n\t\t.then((url) => {\n\t\t\tcallback(url)\n\t\t})\n}\n\n/**\n * @deprecated Use {@link useImageOrVideoAsset} instead.\n *\n * @public\n */\nexport const useAsset = useImageOrVideoAsset\n"],
5
- "mappings": "AAAA;AAAA,EAOC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,WAAW,QAAQ,gBAAgB;AAgCrC,SAAS,qBAAqB,EAAE,SAAS,SAAS,MAAM,GAAgC;AAC9F,QAAM,SAAS,UAAU;AACzB,QAAM,aAAa,oBAAoB;AACvC,QAAM,gBAAgB,kBAAkB;AAGxC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAGzB,OAAO;AAAA,IACT,OAAO,UAAW,OAAO,SAAsC,OAAO,KAAK,OAAQ;AAAA,IACnF,KAAK;AAAA,EACN,EAAE;AAGF,QAAM,oBAAoB,OAAO,KAAK;AAGtC,QAAM,cAAc,OAAsB,IAAI;AAE9C,YAAU,MAAM;AACf,QAAI,CAAC,QAAS;AAEd,QAAI,cAAc;AAClB,QAAI;AAEJ,UAAM,yBAAyB,MAAM,gBAAgB,MAAM;AAC1D,UAAI,CAAC,cAAc,WAAW,OAAO,gBAAgB,EAAE,IAAI,OAAO,EAAG;AAGrE,YAAM,QAAQ,OAAO,SAAsC,OAAO;AAClE,UAAI,CAAC,OAAO;AAEX,kBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,MAAM,KAAK,KAAK,EAAE;AACzD;AAAA,MACD;AAGA,UAAI,CAAC,MAAM,MAAM,KAAK;AACrB,cAAM,UAAU,OAAO,yBAAyB,MAAM,EAAE;AACxD,YAAI,SAAS;AACZ,cAAI,YAAY,YAAY,SAAS;AACpC,wBAAY,UAAU;AACtB,sBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,eAAe,MAAM,KAAK,QAAQ,EAAE;AACpE,0BAAc;AAAA,UACf;AACA;AAAA,QACD;AAAA,MACD;AAIA,YAAM,cAAc,aACjB,WAAW,SAAS,QAAQ,MAAM,MAAM,KACxC,OAAO,aAAa,KAAK,QAAQ,MAAM,MAAM;AAEhD,eAAS,QAAQA,QAAoC,KAAoB;AACxE,YAAI,YAAa;AACjB,YAAI,YAAY,YAAY,IAAK;AACjC,0BAAkB,UAAU;AAC5B,oBAAY,UAAU;AACtB,kBAAU,EAAE,OAAAA,QAAO,IAAI,CAAC;AACxB,sBAAc;AAAA,MACf;AAGA,UAAI,kBAAkB,SAAS;AAC9B,YAAI,OAAO;AAEX,cAAM,0BAA0B,MAAM;AACrC;AACA,cAAI,OAAO,MAAM,IAAI;AAEpB,4BAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AACtF,+BAAmB;AAAA,UACpB;AAAA,QACD;AAEA,2BAAmB;AACnB,eAAO,GAAG,QAAQ,uBAAuB;AACzC,2BAAmB,MAAM,OAAO,IAAI,QAAQ,uBAAuB;AAAA,MACpE,OAAO;AACN,wBAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AAAA,MACvF;AAAA,IACD,CAAC;AAED,WAAO,MAAM;AACZ,6BAAuB;AACvB,yBAAmB;AACnB,oBAAc;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,YAAY,eAAe,SAAS,KAAK,CAAC;AAE/D,SAAO;AACR;AAEA,SAAS,gBACR,QACA,SACA,aACA,YACA,UACC;AACD,SACE,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,yBAAyB,aAAa,WAAW,eAAe,OAAO;AAAA,IACvE,KAAK,YAAY,cAAc;AAAA,EAChC,CAAC,EAIA,KAAK,CAAC,QAAQ;AACd,aAAS,GAAG;AAAA,EACb,CAAC;AACH;AAOO,MAAM,WAAW;",
4
+ "sourcesContent": ["import {\n\tEditor,\n\tSvgExportContext,\n\tTLAssetId,\n\tTLImageAsset,\n\tTLShapeId,\n\tTLVideoAsset,\n\treact,\n\tuseDelaySvgExport,\n\tuseEditor,\n\tuseSvgExportContext,\n} from '@tldraw/editor'\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * Options for {@link useImageOrVideoAsset}.\n *\n * @public\n */\nexport interface UseImageOrVideoAssetOptions {\n\t/** The asset ID you want a URL for. */\n\tassetId: TLAssetId | null\n\t/**\n\t * The shape the asset is being used for. We won't update the resolved URL while the shape is\n\t * off-screen.\n\t */\n\tshapeId?: TLShapeId\n\t/**\n\t * The width at which the asset will be displayed, in shape-space pixels.\n\t */\n\twidth: number\n}\n\n/**\n * This is a handy helper hook that resolves an asset to an optimized URL for a given shape, or its\n * {@link @tldraw/editor#Editor.createTemporaryAssetPreview | placeholder} if the asset is still\n * uploading. This is used in particular for high-resolution images when you want lower and higher\n * resolution depending on the size of the image on the canvas and the zoom level.\n *\n * For image scaling to work, you need to implement scaled URLs in\n * {@link @tldraw/tlschema#TLAssetStore.resolve}.\n *\n * @public\n */\nexport function useImageOrVideoAsset({ shapeId, assetId, width }: UseImageOrVideoAssetOptions) {\n\tconst editor = useEditor()\n\tconst exportInfo = useSvgExportContext()\n\tconst exportIsReady = useDelaySvgExport()\n\n\t// We use a state to store the result of the asset resolution, and we're going to avoid updating this whenever we can\n\tconst [result, setResult] = useState<{\n\t\tasset: (TLImageAsset | TLVideoAsset) | null\n\t\turl: string | null\n\t}>(() => ({\n\t\tasset: assetId ? (editor.getAsset<TLImageAsset | TLVideoAsset>(assetId) ?? null) : null,\n\t\turl: null as string | null,\n\t}))\n\n\t// A flag for whether we've resolved the asset URL at least once, after which we can debounce\n\tconst didAlreadyResolve = useRef(false)\n\n\t// The last URL that we've seen for the shape\n\tconst previousUrl = useRef<string | null>(null)\n\n\tuseEffect(() => {\n\t\tif (!assetId) return\n\n\t\tlet isCancelled = false\n\t\tlet cancelDebounceFn: (() => void) | undefined\n\n\t\tconst cleanupEffectScheduler = react('update state', () => {\n\t\t\tif (!exportInfo && shapeId && editor.getCulledShapes().has(shapeId)) return\n\n\t\t\t// Get the fresh asset\n\t\t\tconst asset = editor.getAsset<TLImageAsset | TLVideoAsset>(assetId)\n\t\t\tif (!asset) {\n\t\t\t\t// If the asset is deleted, such as when an upload fails, set the URL to null\n\t\t\t\tsetResult((prev) => ({ ...prev, asset: null, url: null }))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Set initial preview for the shape if it has no source (if it was pasted into a local project as base64)\n\t\t\tif (!asset.props.src) {\n\t\t\t\tconst preview = editor.getTemporaryAssetPreview(asset.id)\n\t\t\t\tif (preview) {\n\t\t\t\t\tif (previousUrl.current !== preview) {\n\t\t\t\t\t\tpreviousUrl.current = preview // just for kicks, let's save the url as the previous URL\n\t\t\t\t\t\tsetResult((prev) => ({ ...prev, isPlaceholder: true, url: preview })) // set the preview as the URL\n\t\t\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// aside ...we could bail here if the only thing that has changed is the shape has changed from culled to not culled\n\n\t\t\tconst screenScale = exportInfo\n\t\t\t\t? exportInfo.scale * (width / asset.props.w)\n\t\t\t\t: editor.getZoomLevel() * (width / asset.props.w)\n\n\t\t\tfunction resolve(asset: TLImageAsset | TLVideoAsset, url: string | null) {\n\t\t\t\tif (isCancelled) return // don't update if the hook has remounted\n\t\t\t\tif (previousUrl.current === url) return // don't update the state if the url is the same\n\t\t\t\tdidAlreadyResolve.current = true // mark that we've resolved our first image\n\t\t\t\tpreviousUrl.current = url // keep the url around to compare with the next one\n\t\t\t\tsetResult({ asset, url })\n\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t}\n\n\t\t\t// If we already resolved the URL, debounce fetching potentially multiple image variations.\n\t\t\tif (didAlreadyResolve.current) {\n\t\t\t\tlet tick = 0\n\n\t\t\t\tconst resolveAssetAfterAWhile = () => {\n\t\t\t\t\ttick++\n\t\t\t\t\tif (tick > 500 / 16) {\n\t\t\t\t\t\t// debounce for 500ms\n\t\t\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t\t\t\tcancelDebounceFn?.()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcancelDebounceFn?.()\n\t\t\t\teditor.on('tick', resolveAssetAfterAWhile)\n\t\t\t\tcancelDebounceFn = () => editor.off('tick', resolveAssetAfterAWhile)\n\t\t\t} else {\n\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t}\n\t\t})\n\n\t\treturn () => {\n\t\t\tcleanupEffectScheduler()\n\t\t\tcancelDebounceFn?.()\n\t\t\tisCancelled = true\n\t\t}\n\t}, [editor, assetId, exportInfo, exportIsReady, shapeId, width])\n\n\treturn result\n}\n\nfunction resolveAssetUrl(\n\teditor: Editor,\n\tassetId: TLAssetId,\n\tscreenScale: number,\n\texportInfo: SvgExportContext | null,\n\tcallback: (url: string | null) => void\n) {\n\teditor\n\t\t.resolveAssetUrl(assetId, {\n\t\t\tscreenScale,\n\t\t\tshouldResolveToOriginal: exportInfo ? exportInfo.pixelRatio === null : false,\n\t\t\tdpr: exportInfo?.pixelRatio ?? undefined,\n\t\t})\n\t\t// There's a weird bug with out debounce function that doesn't\n\t\t// make it work right with async functions, so we use a callback\n\t\t// here instead of returning a promise.\n\t\t.then((url) => {\n\t\t\tcallback(url)\n\t\t})\n}\n"],
5
+ "mappings": "AAAA;AAAA,EAOC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OACM;AACP,SAAS,WAAW,QAAQ,gBAAgB;AAgCrC,SAAS,qBAAqB,EAAE,SAAS,SAAS,MAAM,GAAgC;AAC9F,QAAM,SAAS,UAAU;AACzB,QAAM,aAAa,oBAAoB;AACvC,QAAM,gBAAgB,kBAAkB;AAGxC,QAAM,CAAC,QAAQ,SAAS,IAAI,SAGzB,OAAO;AAAA,IACT,OAAO,UAAW,OAAO,SAAsC,OAAO,KAAK,OAAQ;AAAA,IACnF,KAAK;AAAA,EACN,EAAE;AAGF,QAAM,oBAAoB,OAAO,KAAK;AAGtC,QAAM,cAAc,OAAsB,IAAI;AAE9C,YAAU,MAAM;AACf,QAAI,CAAC,QAAS;AAEd,QAAI,cAAc;AAClB,QAAI;AAEJ,UAAM,yBAAyB,MAAM,gBAAgB,MAAM;AAC1D,UAAI,CAAC,cAAc,WAAW,OAAO,gBAAgB,EAAE,IAAI,OAAO,EAAG;AAGrE,YAAM,QAAQ,OAAO,SAAsC,OAAO;AAClE,UAAI,CAAC,OAAO;AAEX,kBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,MAAM,KAAK,KAAK,EAAE;AACzD;AAAA,MACD;AAGA,UAAI,CAAC,MAAM,MAAM,KAAK;AACrB,cAAM,UAAU,OAAO,yBAAyB,MAAM,EAAE;AACxD,YAAI,SAAS;AACZ,cAAI,YAAY,YAAY,SAAS;AACpC,wBAAY,UAAU;AACtB,sBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,eAAe,MAAM,KAAK,QAAQ,EAAE;AACpE,0BAAc;AAAA,UACf;AACA;AAAA,QACD;AAAA,MACD;AAIA,YAAM,cAAc,aACjB,WAAW,SAAS,QAAQ,MAAM,MAAM,KACxC,OAAO,aAAa,KAAK,QAAQ,MAAM,MAAM;AAEhD,eAAS,QAAQA,QAAoC,KAAoB;AACxE,YAAI,YAAa;AACjB,YAAI,YAAY,YAAY,IAAK;AACjC,0BAAkB,UAAU;AAC5B,oBAAY,UAAU;AACtB,kBAAU,EAAE,OAAAA,QAAO,IAAI,CAAC;AACxB,sBAAc;AAAA,MACf;AAGA,UAAI,kBAAkB,SAAS;AAC9B,YAAI,OAAO;AAEX,cAAM,0BAA0B,MAAM;AACrC;AACA,cAAI,OAAO,MAAM,IAAI;AAEpB,4BAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AACtF,+BAAmB;AAAA,UACpB;AAAA,QACD;AAEA,2BAAmB;AACnB,eAAO,GAAG,QAAQ,uBAAuB;AACzC,2BAAmB,MAAM,OAAO,IAAI,QAAQ,uBAAuB;AAAA,MACpE,OAAO;AACN,wBAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AAAA,MACvF;AAAA,IACD,CAAC;AAED,WAAO,MAAM;AACZ,6BAAuB;AACvB,yBAAmB;AACnB,oBAAc;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,YAAY,eAAe,SAAS,KAAK,CAAC;AAE/D,SAAO;AACR;AAEA,SAAS,gBACR,QACA,SACA,aACA,YACA,UACC;AACD,SACE,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,yBAAyB,aAAa,WAAW,eAAe,OAAO;AAAA,IACvE,KAAK,YAAY,cAAc;AAAA,EAChC,CAAC,EAIA,KAAK,CAAC,QAAQ;AACd,aAAS,GAAG;AAAA,EACb,CAAC;AACH;",
6
6
  "names": ["asset"]
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import { jsx } from "react/jsx-runtime";
2
- import { preventDefault, stopEventPropagation } from "@tldraw/editor";
2
+ import { preventDefault, useEditor } from "@tldraw/editor";
3
3
  import React from "react";
4
4
  const PlainTextArea = React.forwardRef(function TextArea({
5
5
  isEditing,
@@ -12,6 +12,7 @@ const PlainTextArea = React.forwardRef(function TextArea({
12
12
  handleInputPointerDown,
13
13
  handleDoubleClick
14
14
  }, ref) {
15
+ const editor = useEditor();
15
16
  const onChange = (e) => {
16
17
  handleChange({ plaintext: e.target.value });
17
18
  };
@@ -37,8 +38,8 @@ const PlainTextArea = React.forwardRef(function TextArea({
37
38
  onChange,
38
39
  onKeyDown: (e) => handleKeyDown(e.nativeEvent),
39
40
  onBlur: handleBlur,
40
- onTouchEnd: stopEventPropagation,
41
- onContextMenu: isEditing ? stopEventPropagation : void 0,
41
+ onTouchEnd: editor.markEventAsHandled,
42
+ onContextMenu: isEditing ? (e) => e.stopPropagation() : void 0,
42
43
  onPointerDown: handleInputPointerDown,
43
44
  onPaste: handlePaste,
44
45
  onDoubleClick: handleDoubleClick,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/text/PlainTextArea.tsx"],
4
- "sourcesContent": ["import { preventDefault, stopEventPropagation } from '@tldraw/editor'\nimport React from 'react'\nimport { TextAreaProps } from './RichTextArea'\n\n/**\n * A plain text area that can be used for basic editing text.\n *\n * @public @react\n */\nexport const PlainTextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\n\t{\n\t\tisEditing,\n\t\ttext,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleKeyDown,\n\t\thandlePaste,\n\t\thandleBlur,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick,\n\t},\n\tref\n) {\n\tconst onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\thandleChange({ plaintext: e.target.value })\n\t}\n\n\treturn (\n\t\t<textarea\n\t\t\tref={ref}\n\t\t\tclassName=\"tl-text tl-text-input\"\n\t\t\tname=\"text\"\n\t\t\ttabIndex={-1}\n\t\t\tdisabled={!isEditing}\n\t\t\treadOnly={!isEditing}\n\t\t\tautoComplete=\"off\"\n\t\t\tautoCapitalize=\"off\"\n\t\t\tautoCorrect=\"off\"\n\t\t\tautoSave=\"off\"\n\t\t\tplaceholder=\"\"\n\t\t\tspellCheck=\"true\"\n\t\t\twrap=\"off\"\n\t\t\tdir=\"auto\"\n\t\t\tdefaultValue={text}\n\t\t\tonFocus={handleFocus}\n\t\t\tonChange={onChange}\n\t\t\tonKeyDown={(e) => handleKeyDown(e.nativeEvent)}\n\t\t\tonBlur={handleBlur}\n\t\t\tonTouchEnd={stopEventPropagation}\n\t\t\tonContextMenu={isEditing ? stopEventPropagation : undefined}\n\t\t\tonPointerDown={handleInputPointerDown}\n\t\t\tonPaste={handlePaste}\n\t\t\tonDoubleClick={handleDoubleClick}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t/>\n\t)\n})\n"],
5
- "mappings": "AA4BE;AA5BF,SAAS,gBAAgB,4BAA4B;AACrD,OAAO,WAAW;AAQX,MAAM,gBAAgB,MAAM,WAA+C,SAAS,SAC1F;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GACA,KACC;AACD,QAAM,WAAW,CAAC,MAA8C;AAC/D,iBAAa,EAAE,WAAW,EAAE,OAAO,MAAM,CAAC;AAAA,EAC3C;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,WAAU;AAAA,MACV,MAAK;AAAA,MACL,UAAU;AAAA,MACV,UAAU,CAAC;AAAA,MACX,UAAU,CAAC;AAAA,MACX,cAAa;AAAA,MACb,gBAAe;AAAA,MACf,aAAY;AAAA,MACZ,UAAS;AAAA,MACT,aAAY;AAAA,MACZ,YAAW;AAAA,MACX,MAAK;AAAA,MACL,KAAI;AAAA,MACJ,cAAc;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,WAAW,CAAC,MAAM,cAAc,EAAE,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,eAAe,YAAY,uBAAuB;AAAA,MAClD,eAAe;AAAA,MACf,SAAS;AAAA,MACT,eAAe;AAAA,MAKf,aAAa;AAAA;AAAA,EACd;AAEF,CAAC;",
4
+ "sourcesContent": ["import { preventDefault, useEditor } from '@tldraw/editor'\nimport React from 'react'\nimport { TextAreaProps } from './RichTextArea'\n\n/**\n * A plain text area that can be used for basic editing text.\n *\n * @public @react\n */\nexport const PlainTextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\n\t{\n\t\tisEditing,\n\t\ttext,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleKeyDown,\n\t\thandlePaste,\n\t\thandleBlur,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick,\n\t},\n\tref\n) {\n\tconst editor = useEditor()\n\tconst onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\thandleChange({ plaintext: e.target.value })\n\t}\n\n\treturn (\n\t\t<textarea\n\t\t\tref={ref}\n\t\t\tclassName=\"tl-text tl-text-input\"\n\t\t\tname=\"text\"\n\t\t\ttabIndex={-1}\n\t\t\tdisabled={!isEditing}\n\t\t\treadOnly={!isEditing}\n\t\t\tautoComplete=\"off\"\n\t\t\tautoCapitalize=\"off\"\n\t\t\tautoCorrect=\"off\"\n\t\t\tautoSave=\"off\"\n\t\t\tplaceholder=\"\"\n\t\t\tspellCheck=\"true\"\n\t\t\twrap=\"off\"\n\t\t\tdir=\"auto\"\n\t\t\tdefaultValue={text}\n\t\t\tonFocus={handleFocus}\n\t\t\tonChange={onChange}\n\t\t\tonKeyDown={(e) => handleKeyDown(e.nativeEvent)}\n\t\t\tonBlur={handleBlur}\n\t\t\tonTouchEnd={editor.markEventAsHandled}\n\t\t\tonContextMenu={isEditing ? (e) => e.stopPropagation() : undefined}\n\t\t\tonPointerDown={handleInputPointerDown}\n\t\t\tonPaste={handlePaste}\n\t\t\tonDoubleClick={handleDoubleClick}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t/>\n\t)\n})\n"],
5
+ "mappings": "AA6BE;AA7BF,SAAS,gBAAgB,iBAAiB;AAC1C,OAAO,WAAW;AAQX,MAAM,gBAAgB,MAAM,WAA+C,SAAS,SAC1F;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GACA,KACC;AACD,QAAM,SAAS,UAAU;AACzB,QAAM,WAAW,CAAC,MAA8C;AAC/D,iBAAa,EAAE,WAAW,EAAE,OAAO,MAAM,CAAC;AAAA,EAC3C;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,WAAU;AAAA,MACV,MAAK;AAAA,MACL,UAAU;AAAA,MACV,UAAU,CAAC;AAAA,MACX,UAAU,CAAC;AAAA,MACX,cAAa;AAAA,MACb,gBAAe;AAAA,MACf,aAAY;AAAA,MACZ,UAAS;AAAA,MACT,aAAY;AAAA,MACZ,YAAW;AAAA,MACX,MAAK;AAAA,MACL,KAAI;AAAA,MACJ,cAAc;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,WAAW,CAAC,MAAM,cAAc,EAAE,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,YAAY,OAAO;AAAA,MACnB,eAAe,YAAY,CAAC,MAAM,EAAE,gBAAgB,IAAI;AAAA,MACxD,eAAe;AAAA,MACf,SAAS;AAAA,MACT,eAAe;AAAA,MAKf,aAAa;AAAA;AAAA,EACd;AAEF,CAAC;",
6
6
  "names": []
7
7
  }
@@ -4,7 +4,6 @@ import {
4
4
  } from "@tiptap/react";
5
5
  import {
6
6
  preventDefault,
7
- stopEventPropagation,
8
7
  useEditor,
9
8
  useEvent,
10
9
  useUniqueSafeId
@@ -158,9 +157,9 @@ const RichTextArea = React.forwardRef(function RichTextArea2({
158
157
  tabIndex: -1,
159
158
  "data-testid": "rich-text-area",
160
159
  className: "tl-rich-text tl-text tl-text-input",
161
- onContextMenu: isEditing ? stopEventPropagation : void 0,
162
- onPointerDownCapture: stopEventPropagation,
163
- onTouchEnd: stopEventPropagation,
160
+ onContextMenu: isEditing ? (e) => e.stopPropagation() : void 0,
161
+ onPointerDownCapture: (e) => e.stopPropagation(),
162
+ onTouchEnd: (e) => e.stopPropagation(),
164
163
  onDragStart: preventDefault,
165
164
  children: /* @__PURE__ */ jsx("div", { className: "tl-rich-text", ref: rTextEditorEl })
166
165
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/text/RichTextArea.tsx"],
4
- "sourcesContent": ["import { EditorView } from '@tiptap/pm/view'\nimport {\n\tEditorEvents,\n\tJSONContent,\n\tEditor as TextEditor,\n\ttype Editor as TTEditor,\n} from '@tiptap/react'\nimport {\n\tEditor,\n\tTLRichText,\n\tTLShapeId,\n\tpreventDefault,\n\tstopEventPropagation,\n\tuseEditor,\n\tuseEvent,\n\tuseUniqueSafeId,\n} from '@tldraw/editor'\nimport React, { useLayoutEffect, useRef } from 'react'\n\n/** @public */\nexport interface TextAreaProps {\n\tisEditing: boolean\n\ttext?: string\n\tshapeId: TLShapeId\n\trichText?: TLRichText\n\thandleFocus(): void\n\thandleBlur(): void\n\thandleKeyDown(e: KeyboardEvent): void\n\thandleChange(changeInfo: { plaintext?: string; richText?: TLRichText }): void\n\thandleInputPointerDown(e: React.PointerEvent<HTMLElement>): void\n\thandleDoubleClick(e: any): any\n\thandlePaste(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>): void\n\thasCustomTabBehavior?: boolean\n}\n\n/**\n * N.B. In Development mode you need to ensure you're testing this without StrictMode on.\n * Otherwise it's not gonna work as expected on iOS.\n * Specifically, it means that the virtual keyboard won't pop open sometimes\n * (iOS starts flipping out when you render multiple times when trying to focus something) .\n */\n\n/**\n * A rich text area that can be used for editing text with rich text formatting.\n * This component uses the TipTap editor under the hood.\n *\n * @public @react\n */\nexport const RichTextArea = React.forwardRef<HTMLDivElement, TextAreaProps>(function RichTextArea(\n\t{\n\t\tshapeId,\n\t\tisEditing,\n\t\trichText,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleBlur,\n\t\thandleKeyDown,\n\t\thandleDoubleClick,\n\t\thasCustomTabBehavior,\n\t\thandlePaste,\n\t},\n\tref\n) {\n\tconst editor = useEditor()\n\tconst tipTapId = useUniqueSafeId('tip-tap-editor')\n\tconst tipTapConfig = editor.getTextOptions().tipTapConfig\n\n\tconst rInitialRichText = useRef(richText)\n\tconst rTextEditor = useRef<TTEditor | null>(null)\n\tconst rTextEditorEl = useRef<HTMLDivElement>(null)\n\n\tuseLayoutEffect(() => {\n\t\tif (!rTextEditor.current) {\n\t\t\trInitialRichText.current = richText\n\t\t} else if (rInitialRichText.current !== richText) {\n\t\t\trTextEditor.current.commands.setContent(richText as JSONContent)\n\t\t}\n\t}, [richText])\n\n\t// The order of events is:\n\t// - editor begins editing any shape\n\t// - we set listeners for select all / place caret events\n\t// - if the user is editing this shape, this component is rendered\n\t// - editor emits the select all event / place caret event\n\t// - the text editor is onCreate callback is called\n\tconst rCreateInfo = useRef({\n\t\tselectAll: false,\n\t\tcaretPosition: null as { x: number; y: number } | null,\n\t})\n\n\tuseLayoutEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.selectAll = true\n\t\t\t}\n\t\t}\n\n\t\tfunction placeCaret(event: { shapeId: TLShapeId; point: { x: number; y: number } }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.caretPosition = event.point\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\teditor.on('place-caret', placeCaret)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t\teditor.off('place-caret', placeCaret)\n\t\t}\n\t}, [editor, isEditing])\n\n\tconst onChange = useEvent(handleChange)\n\tconst onKeyDown = useEvent(handleKeyDown)\n\tconst onFocus = useEvent(handleFocus)\n\tconst onBlur = useEvent(handleBlur)\n\tconst onDoubleClick = useEvent(handleDoubleClick)\n\tconst onPaste = useEvent(handlePaste)\n\tuseLayoutEffect(() => {\n\t\tif (!isEditing || !tipTapConfig || !rTextEditorEl.current) return\n\n\t\tconst { editorProps, ...restOfTipTapConfig } = tipTapConfig\n\n\t\t// Because React can double-render in Strict Mode, we need to make sure we're not setting\n\t\t// the text editor twice. This became more much more prevalent in React 19, but also it\n\t\t// started manifesting in some cases in Next 14.2 (which maybe patches React 18.3 in weird\n\t\t// ways). So we used to use EditorProvider but we into weird rendering issues.\n\t\tconst textEditorInstance = new TextEditor({\n\t\t\telement: rTextEditorEl.current,\n\t\t\tautofocus: true,\n\t\t\teditable: isEditing,\n\t\t\tonUpdate: (props: EditorEvents['update']) => {\n\t\t\t\tconst content: TLRichText = props.editor.state.doc.toJSON()\n\t\t\t\trInitialRichText.current = content\n\t\t\t\tonChange({ richText: content })\n\t\t\t},\n\t\t\tonFocus,\n\t\t\tonBlur,\n\t\t\t// onCreate is called after a `setTimeout(0)`\n\t\t\tonCreate: (props) => {\n\t\t\t\t// If we're not still editing the original shape, then don't do anything.\n\t\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\t\tconst textEditor = props.editor\n\t\t\t\teditor.setRichTextEditor(textEditor)\n\n\t\t\t\tconst { selectAll, caretPosition } = rCreateInfo.current\n\n\t\t\t\tif (selectAll) {\n\t\t\t\t\t// Select all of the text\n\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t} else if (caretPosition) {\n\t\t\t\t\t// Set the initial caret screen position\n\t\t\t\t\tconst pos = textEditor.view.posAtCoords({\n\t\t\t\t\t\tleft: caretPosition.x,\n\t\t\t\t\t\ttop: caretPosition.y,\n\t\t\t\t\t})?.pos\n\n\t\t\t\t\tif (pos) {\n\t\t\t\t\t\t// Focus to that position.\n\t\t\t\t\t\ttextEditor.chain().focus().setTextSelection(pos).run()\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no position, default to select all.\n\t\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\teditorProps: {\n\t\t\t\thandleKeyDown: (view: EditorView, event: KeyboardEvent) => {\n\t\t\t\t\tif (!hasCustomTabBehavior && event.key === 'Tab') {\n\t\t\t\t\t\thandleTab(editor, view, event)\n\t\t\t\t\t}\n\n\t\t\t\t\tonKeyDown(event)\n\t\t\t\t},\n\t\t\t\thandlePaste: (view: EditorView, event: ClipboardEvent) => {\n\t\t\t\t\tonPaste(event)\n\t\t\t\t\tif (event.defaultPrevented) return true\n\t\t\t\t},\n\t\t\t\thandleDoubleClick: (_view, _pos, event) => onDoubleClick(event),\n\t\t\t\t...editorProps,\n\t\t\t},\n\t\t\tcoreExtensionOptions: {\n\t\t\t\tclipboardTextSerializer: {\n\t\t\t\t\tblockSeparator: '\\n',\n\t\t\t\t},\n\t\t\t},\n\t\t\t...restOfTipTapConfig,\n\t\t\tcontent: rInitialRichText.current as JSONContent,\n\t\t})\n\n\t\t// XXX: When creating a brand new shape and double-clicking into it quickly to edit it,\n\t\t// there's some kind of race condition happening where the editor doesn't focus properly.\n\t\tconst timeout = editor.timers.setTimeout(() => {\n\t\t\tif (rCreateInfo.current.caretPosition || rCreateInfo.current.selectAll) {\n\t\t\t\ttextEditorInstance.commands.focus()\n\t\t\t} else {\n\t\t\t\ttextEditorInstance.commands.focus('end')\n\t\t\t}\n\n\t\t\trCreateInfo.current.selectAll = false\n\t\t\trCreateInfo.current.caretPosition = null\n\t\t}, 100)\n\n\t\trTextEditor.current = textEditorInstance\n\n\t\treturn () => {\n\t\t\trTextEditor.current = null\n\t\t\tclearTimeout(timeout)\n\t\t\ttextEditorInstance.destroy()\n\t\t}\n\t}, [\n\t\tisEditing,\n\t\ttipTapConfig,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonDoubleClick,\n\t\tonChange,\n\t\tonPaste,\n\t\tonKeyDown,\n\t\teditor,\n\t\tshapeId,\n\t\thasCustomTabBehavior,\n\t])\n\n\tif (!isEditing || !tipTapConfig) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tid={tipTapId}\n\t\t\tref={ref}\n\t\t\ttabIndex={-1}\n\t\t\tdata-testid=\"rich-text-area\"\n\t\t\tclassName=\"tl-rich-text tl-text tl-text-input\"\n\t\t\tonContextMenu={isEditing ? stopEventPropagation : undefined}\n\t\t\t// N.B. When PointerStateExtension was introduced, this was moved there.\n\t\t\t// However, that caused selecting over list items to break.\n\t\t\t// The handleDOMEvents in TipTap don't seem to support the pointerDownCapture event.\n\t\t\tonPointerDownCapture={stopEventPropagation}\n\t\t\t// This onTouchEnd is important for Android to be able to change selection on text.\n\t\t\tonTouchEnd={stopEventPropagation}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t>\n\t\t\t<div className=\"tl-rich-text\" ref={rTextEditorEl} />\n\t\t</div>\n\t)\n})\n\n// Prevent exiting the editor when hitting Tab.\n// Also, insert a tab character at the front of the line if the shift key isn't pressed,\n// otherwise if shift is pressed, remove a tab character from the front of the line.\nfunction handleTab(editor: Editor, view: EditorView, event: KeyboardEvent) {\n\t// Don't exit the editor.\n\tevent.preventDefault()\n\n\tconst textEditor = editor.getRichTextEditor()\n\tif (textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList')) return\n\n\tconst { state, dispatch } = view\n\tconst { $from, $to } = state.selection\n\tconst isShift = event.shiftKey\n\n\t// Create a new transaction\n\tlet tr = state.tr\n\n\t// Iterate over each line in the selection in reverse so that the positions\n\t// are stable as we modify the document.\n\tlet pos = $to.end()\n\twhile (pos >= $from.start()) {\n\t\tconst line = state.doc.resolve(pos).blockRange()\n\t\tif (!line) break\n\n\t\tconst lineStart = line.start\n\t\tconst lineEnd = line.end\n\t\tconst lineText = state.doc.textBetween(lineStart, lineEnd, '\\n')\n\n\t\t// Check if the current line or any of its parent nodes are part of a list\n\t\tlet isInList = false\n\t\tstate.doc.nodesBetween(lineStart, lineEnd, (node) => {\n\t\t\tif (node.type.name === 'bulletList' || node.type.name === 'orderedList') {\n\t\t\t\tisInList = true\n\t\t\t\treturn false // Stop iteration\n\t\t\t}\n\t\t})\n\n\t\t// TODO: for now skip over lists. Later, we might consider handling them using\n\t\t// sinkListItem and liftListItem from @tiptap/pm/schema-list\n\t\tif (!isInList) {\n\t\t\tif (!isShift) {\n\t\t\t\t// Insert a tab character at the start of the line\n\t\t\t\ttr = tr.insertText('\\t', lineStart + 1)\n\t\t\t} else {\n\t\t\t\t// Remove a tab character from the start of the line\n\t\t\t\tif (lineText.startsWith('\\t')) {\n\t\t\t\t\ttr = tr.delete(lineStart + 1, lineStart + 2)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpos = lineStart - 1\n\t}\n\n\tconst mappedSelection = state.selection.map(tr.doc, tr.mapping)\n\ttr.setSelection(mappedSelection)\n\n\tif (tr.docChanged) {\n\t\tdispatch(tr)\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { EditorView } from '@tiptap/pm/view'\nimport {\n\tEditorEvents,\n\tJSONContent,\n\tEditor as TextEditor,\n\ttype Editor as TTEditor,\n} from '@tiptap/react'\nimport {\n\tEditor,\n\tTLRichText,\n\tTLShapeId,\n\tpreventDefault,\n\tuseEditor,\n\tuseEvent,\n\tuseUniqueSafeId,\n} from '@tldraw/editor'\nimport React, { useLayoutEffect, useRef } from 'react'\n\n/** @public */\nexport interface TextAreaProps {\n\tisEditing: boolean\n\ttext?: string\n\tshapeId: TLShapeId\n\trichText?: TLRichText\n\thandleFocus(): void\n\thandleBlur(): void\n\thandleKeyDown(e: KeyboardEvent): void\n\thandleChange(changeInfo: { plaintext?: string; richText?: TLRichText }): void\n\thandleInputPointerDown(e: React.PointerEvent<HTMLElement>): void\n\thandleDoubleClick(e: any): any\n\thandlePaste(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>): void\n\thasCustomTabBehavior?: boolean\n}\n\n/**\n * N.B. In Development mode you need to ensure you're testing this without StrictMode on.\n * Otherwise it's not gonna work as expected on iOS.\n * Specifically, it means that the virtual keyboard won't pop open sometimes\n * (iOS starts flipping out when you render multiple times when trying to focus something) .\n */\n\n/**\n * A rich text area that can be used for editing text with rich text formatting.\n * This component uses the TipTap editor under the hood.\n *\n * @public @react\n */\nexport const RichTextArea = React.forwardRef<HTMLDivElement, TextAreaProps>(function RichTextArea(\n\t{\n\t\tshapeId,\n\t\tisEditing,\n\t\trichText,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleBlur,\n\t\thandleKeyDown,\n\t\thandleDoubleClick,\n\t\thasCustomTabBehavior,\n\t\thandlePaste,\n\t},\n\tref\n) {\n\tconst editor = useEditor()\n\tconst tipTapId = useUniqueSafeId('tip-tap-editor')\n\tconst tipTapConfig = editor.getTextOptions().tipTapConfig\n\n\tconst rInitialRichText = useRef(richText)\n\tconst rTextEditor = useRef<TTEditor | null>(null)\n\tconst rTextEditorEl = useRef<HTMLDivElement>(null)\n\n\tuseLayoutEffect(() => {\n\t\tif (!rTextEditor.current) {\n\t\t\trInitialRichText.current = richText\n\t\t} else if (rInitialRichText.current !== richText) {\n\t\t\trTextEditor.current.commands.setContent(richText as JSONContent)\n\t\t}\n\t}, [richText])\n\n\t// The order of events is:\n\t// - editor begins editing any shape\n\t// - we set listeners for select all / place caret events\n\t// - if the user is editing this shape, this component is rendered\n\t// - editor emits the select all event / place caret event\n\t// - the text editor is onCreate callback is called\n\tconst rCreateInfo = useRef({\n\t\tselectAll: false,\n\t\tcaretPosition: null as { x: number; y: number } | null,\n\t})\n\n\tuseLayoutEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.selectAll = true\n\t\t\t}\n\t\t}\n\n\t\tfunction placeCaret(event: { shapeId: TLShapeId; point: { x: number; y: number } }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.caretPosition = event.point\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\teditor.on('place-caret', placeCaret)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t\teditor.off('place-caret', placeCaret)\n\t\t}\n\t}, [editor, isEditing])\n\n\tconst onChange = useEvent(handleChange)\n\tconst onKeyDown = useEvent(handleKeyDown)\n\tconst onFocus = useEvent(handleFocus)\n\tconst onBlur = useEvent(handleBlur)\n\tconst onDoubleClick = useEvent(handleDoubleClick)\n\tconst onPaste = useEvent(handlePaste)\n\tuseLayoutEffect(() => {\n\t\tif (!isEditing || !tipTapConfig || !rTextEditorEl.current) return\n\n\t\tconst { editorProps, ...restOfTipTapConfig } = tipTapConfig\n\n\t\t// Because React can double-render in Strict Mode, we need to make sure we're not setting\n\t\t// the text editor twice. This became more much more prevalent in React 19, but also it\n\t\t// started manifesting in some cases in Next 14.2 (which maybe patches React 18.3 in weird\n\t\t// ways). So we used to use EditorProvider but we into weird rendering issues.\n\t\tconst textEditorInstance = new TextEditor({\n\t\t\telement: rTextEditorEl.current,\n\t\t\tautofocus: true,\n\t\t\teditable: isEditing,\n\t\t\tonUpdate: (props: EditorEvents['update']) => {\n\t\t\t\tconst content: TLRichText = props.editor.state.doc.toJSON()\n\t\t\t\trInitialRichText.current = content\n\t\t\t\tonChange({ richText: content })\n\t\t\t},\n\t\t\tonFocus,\n\t\t\tonBlur,\n\t\t\t// onCreate is called after a `setTimeout(0)`\n\t\t\tonCreate: (props) => {\n\t\t\t\t// If we're not still editing the original shape, then don't do anything.\n\t\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\t\tconst textEditor = props.editor\n\t\t\t\teditor.setRichTextEditor(textEditor)\n\n\t\t\t\tconst { selectAll, caretPosition } = rCreateInfo.current\n\n\t\t\t\tif (selectAll) {\n\t\t\t\t\t// Select all of the text\n\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t} else if (caretPosition) {\n\t\t\t\t\t// Set the initial caret screen position\n\t\t\t\t\tconst pos = textEditor.view.posAtCoords({\n\t\t\t\t\t\tleft: caretPosition.x,\n\t\t\t\t\t\ttop: caretPosition.y,\n\t\t\t\t\t})?.pos\n\n\t\t\t\t\tif (pos) {\n\t\t\t\t\t\t// Focus to that position.\n\t\t\t\t\t\ttextEditor.chain().focus().setTextSelection(pos).run()\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no position, default to select all.\n\t\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\teditorProps: {\n\t\t\t\thandleKeyDown: (view: EditorView, event: KeyboardEvent) => {\n\t\t\t\t\tif (!hasCustomTabBehavior && event.key === 'Tab') {\n\t\t\t\t\t\thandleTab(editor, view, event)\n\t\t\t\t\t}\n\n\t\t\t\t\tonKeyDown(event)\n\t\t\t\t},\n\t\t\t\thandlePaste: (view: EditorView, event: ClipboardEvent) => {\n\t\t\t\t\tonPaste(event)\n\t\t\t\t\tif (event.defaultPrevented) return true\n\t\t\t\t},\n\t\t\t\thandleDoubleClick: (_view, _pos, event) => onDoubleClick(event),\n\t\t\t\t...editorProps,\n\t\t\t},\n\t\t\tcoreExtensionOptions: {\n\t\t\t\tclipboardTextSerializer: {\n\t\t\t\t\tblockSeparator: '\\n',\n\t\t\t\t},\n\t\t\t},\n\t\t\t...restOfTipTapConfig,\n\t\t\tcontent: rInitialRichText.current as JSONContent,\n\t\t})\n\n\t\t// XXX: When creating a brand new shape and double-clicking into it quickly to edit it,\n\t\t// there's some kind of race condition happening where the editor doesn't focus properly.\n\t\tconst timeout = editor.timers.setTimeout(() => {\n\t\t\tif (rCreateInfo.current.caretPosition || rCreateInfo.current.selectAll) {\n\t\t\t\ttextEditorInstance.commands.focus()\n\t\t\t} else {\n\t\t\t\ttextEditorInstance.commands.focus('end')\n\t\t\t}\n\n\t\t\trCreateInfo.current.selectAll = false\n\t\t\trCreateInfo.current.caretPosition = null\n\t\t}, 100)\n\n\t\trTextEditor.current = textEditorInstance\n\n\t\treturn () => {\n\t\t\trTextEditor.current = null\n\t\t\tclearTimeout(timeout)\n\t\t\ttextEditorInstance.destroy()\n\t\t}\n\t}, [\n\t\tisEditing,\n\t\ttipTapConfig,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonDoubleClick,\n\t\tonChange,\n\t\tonPaste,\n\t\tonKeyDown,\n\t\teditor,\n\t\tshapeId,\n\t\thasCustomTabBehavior,\n\t])\n\n\tif (!isEditing || !tipTapConfig) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tid={tipTapId}\n\t\t\tref={ref}\n\t\t\ttabIndex={-1}\n\t\t\tdata-testid=\"rich-text-area\"\n\t\t\tclassName=\"tl-rich-text tl-text tl-text-input\"\n\t\t\tonContextMenu={isEditing ? (e) => e.stopPropagation() : undefined}\n\t\t\t// N.B. When PointerStateExtension was introduced, this was moved there.\n\t\t\t// However, that caused selecting over list items to break.\n\t\t\t// The handleDOMEvents in TipTap don't seem to support the pointerDownCapture event.\n\t\t\tonPointerDownCapture={(e) => e.stopPropagation()}\n\t\t\t// This onTouchEnd is important for Android to be able to change selection on text.\n\t\t\tonTouchEnd={(e) => e.stopPropagation()}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t>\n\t\t\t<div className=\"tl-rich-text\" ref={rTextEditorEl} />\n\t\t</div>\n\t)\n})\n\n// Prevent exiting the editor when hitting Tab.\n// Also, insert a tab character at the front of the line if the shift key isn't pressed,\n// otherwise if shift is pressed, remove a tab character from the front of the line.\nfunction handleTab(editor: Editor, view: EditorView, event: KeyboardEvent) {\n\t// Don't exit the editor.\n\tevent.preventDefault()\n\n\tconst textEditor = editor.getRichTextEditor()\n\tif (textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList')) return\n\n\tconst { state, dispatch } = view\n\tconst { $from, $to } = state.selection\n\tconst isShift = event.shiftKey\n\n\t// Create a new transaction\n\tlet tr = state.tr\n\n\t// Iterate over each line in the selection in reverse so that the positions\n\t// are stable as we modify the document.\n\tlet pos = $to.end()\n\twhile (pos >= $from.start()) {\n\t\tconst line = state.doc.resolve(pos).blockRange()\n\t\tif (!line) break\n\n\t\tconst lineStart = line.start\n\t\tconst lineEnd = line.end\n\t\tconst lineText = state.doc.textBetween(lineStart, lineEnd, '\\n')\n\n\t\t// Check if the current line or any of its parent nodes are part of a list\n\t\tlet isInList = false\n\t\tstate.doc.nodesBetween(lineStart, lineEnd, (node) => {\n\t\t\tif (node.type.name === 'bulletList' || node.type.name === 'orderedList') {\n\t\t\t\tisInList = true\n\t\t\t\treturn false // Stop iteration\n\t\t\t}\n\t\t})\n\n\t\t// TODO: for now skip over lists. Later, we might consider handling them using\n\t\t// sinkListItem and liftListItem from @tiptap/pm/schema-list\n\t\tif (!isInList) {\n\t\t\tif (!isShift) {\n\t\t\t\t// Insert a tab character at the start of the line\n\t\t\t\ttr = tr.insertText('\\t', lineStart + 1)\n\t\t\t} else {\n\t\t\t\t// Remove a tab character from the start of the line\n\t\t\t\tif (lineText.startsWith('\\t')) {\n\t\t\t\t\ttr = tr.delete(lineStart + 1, lineStart + 2)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpos = lineStart - 1\n\t}\n\n\tconst mappedSelection = state.selection.map(tr.doc, tr.mapping)\n\ttr.setSelection(mappedSelection)\n\n\tif (tr.docChanged) {\n\t\tdispatch(tr)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["RichTextArea"]
7
7
  }
@@ -107,9 +107,9 @@ const VideoShape = memo(function VideoShape2({ shape }) {
107
107
  {
108
108
  id: shape.id,
109
109
  style: {
110
- color: "var(--color-text-3)",
111
- backgroundColor: asset ? "transparent" : "var(--color-low)",
112
- border: asset ? "none" : "1px solid var(--color-low-border)"
110
+ color: "var(--tl-color-text-3)",
111
+ backgroundColor: asset ? "transparent" : "var(--tl-color-low)",
112
+ border: asset ? "none" : "1px solid var(--tl-color-low-border)"
113
113
  },
114
114
  children: /* @__PURE__ */ jsx("div", { className: "tl-counter-scaled", children: /* @__PURE__ */ jsx("div", { className: "tl-video-container", children: !asset ? /* @__PURE__ */ jsx(BrokenAssetIcon, {}) : Spinner && !asset.props.src ? /* @__PURE__ */ jsx(Spinner, {}) : url ? /* @__PURE__ */ jsxs(Fragment, { children: [
115
115
  /* @__PURE__ */ 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\tTLVideoShape,\n\tWeakCache,\n\ttoDomPrecision,\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 { 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 */\nexport interface VideoShapeOptions {\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\n\toverride options: VideoShapeOptions = {\n\t\tautoplay: true,\n\t}\n\n\toverride canEdit() {\n\t\treturn true\n\t}\n\toverride isAspectRatioLocked() {\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 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\tindicator(shape: TLVideoShape) {\n\t\treturn <rect width={toDomPrecision(shape.props.w)} height={toDomPrecision(shape.props.h)} />\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)\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 = editor.getShapeGeometry(shape).bounds.w * editor.getZoomLevel() >= 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 fullscreenChange = () => setIsFullscreen(document.fullscreenElement === rVideo.current)\n\t\tdocument.addEventListener('fullscreenchange', fullscreenChange)\n\n\t\treturn () => document.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 (document.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(--color-text-3)',\n\t\t\t\t\tbackgroundColor: asset ? 'transparent' : 'var(--color-low)',\n\t\t\t\t\tborder: asset ? 'none' : '1px solid var(--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"],
4
+ "sourcesContent": ["import {\n\tBaseBoxShapeUtil,\n\tHTMLContainer,\n\tMediaHelpers,\n\tSvgExportContext,\n\tTLAsset,\n\tTLVideoShape,\n\tWeakCache,\n\ttoDomPrecision,\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 { 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 */\nexport interface VideoShapeOptions {\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\n\toverride options: VideoShapeOptions = {\n\t\tautoplay: true,\n\t}\n\n\toverride canEdit() {\n\t\treturn true\n\t}\n\toverride isAspectRatioLocked() {\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 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\tindicator(shape: TLVideoShape) {\n\t\treturn <rect width={toDomPrecision(shape.props.w)} height={toDomPrecision(shape.props.h)} />\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)\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 = editor.getShapeGeometry(shape).bounds.w * editor.getZoomLevel() >= 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 fullscreenChange = () => setIsFullscreen(document.fullscreenElement === rVideo.current)\n\t\tdocument.addEventListener('fullscreenchange', fullscreenChange)\n\n\t\treturn () => document.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 (document.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
5
  "mappings": "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",
6
6
  "names": ["VideoShape"]
7
7
  }
@@ -1,5 +1,6 @@
1
1
  import {
2
2
  StateNode,
3
+ isAccelKey,
3
4
  pointInPolygon
4
5
  } from "@tldraw/editor";
5
6
  class Erasing extends StateNode {
@@ -8,7 +9,13 @@ class Erasing extends StateNode {
8
9
  scribbleId = "id";
9
10
  markId = "";
10
11
  excludedShapeIds = /* @__PURE__ */ new Set();
12
+ _isHoldingAccelKey = false;
13
+ _firstErasingShapeId = null;
14
+ _erasingShapeIds = [];
11
15
  onEnter(info) {
16
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs);
17
+ this._firstErasingShapeId = this.editor.getErasingShapeIds()[0];
18
+ this._erasingShapeIds = this.editor.getErasingShapeIds();
12
19
  this.markId = this.editor.markHistoryStoppingPoint("erase scribble begin");
13
20
  this.info = info;
14
21
  const { originPagePoint } = this.editor.inputs;
@@ -50,6 +57,14 @@ class Erasing extends StateNode {
50
57
  onComplete() {
51
58
  this.complete();
52
59
  }
60
+ onKeyUp() {
61
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs);
62
+ this.update();
63
+ }
64
+ onKeyDown() {
65
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs);
66
+ this.update();
67
+ }
53
68
  update() {
54
69
  const { editor, excludedShapeIds } = this;
55
70
  const erasingShapeIds = editor.getErasingShapeIds();
@@ -80,13 +95,23 @@ class Erasing extends StateNode {
80
95
  if (geometry.hitTestLineSegment(A, B, minDist)) {
81
96
  erasing.add(editor.getOutermostSelectableShape(shape).id);
82
97
  }
98
+ this._erasingShapeIds = [...erasing];
99
+ }
100
+ if (this._isHoldingAccelKey && this._firstErasingShapeId) {
101
+ const erasingShapeId = this._firstErasingShapeId;
102
+ if (erasingShapeId && this.editor.getShape(erasingShapeId)) {
103
+ editor.setErasingShapes([erasingShapeId]);
104
+ }
105
+ return;
83
106
  }
84
- this.editor.setErasingShapes([...erasing].filter((id) => !excludedShapeIds.has(id)));
107
+ this.editor.setErasingShapes(this._erasingShapeIds.filter((id) => !excludedShapeIds.has(id)));
85
108
  }
86
109
  complete() {
87
110
  const { editor } = this;
88
111
  editor.deleteShapes(editor.getCurrentPageState().erasingShapeIds);
89
112
  this.parent.transition("idle");
113
+ this._erasingShapeIds = [];
114
+ this._firstErasingShapeId = null;
90
115
  }
91
116
  cancel() {
92
117
  const { editor } = this;
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/EraserTool/childStates/Erasing.ts"],
4
- "sourcesContent": ["import {\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tpointInPolygon,\n} from '@tldraw/editor'\n\nexport class Erasing extends StateNode {\n\tstatic override id = 'erasing'\n\n\tprivate info = {} as TLPointerEventInfo\n\tprivate scribbleId = 'id'\n\tprivate markId = ''\n\tprivate excludedShapeIds = new Set<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\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, check we're inside it when we start erasing\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group') ||\n\t\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(shape, 'frame')\n\t\t\t\t\t) {\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\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.currentPagePoint\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() {\n\t\tthis.complete()\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 zoomLevel = editor.getZoomLevel()\n\t\tconst currentPageShapes = editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint, previousPagePoint },\n\t\t} = editor\n\n\t\tthis.pushPointToScribble()\n\n\t\tconst erasing = new Set<TLShapeId>(erasingShapeIds)\n\t\tconst minDist = this.editor.options.hitTestMargin / zoomLevel\n\n\t\tfor (const shape of currentPageShapes) {\n\t\t\tif (editor.isShapeOfType<TLGroupShape>(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\tif (geometry.hitTestLineSegment(A, B, minDist)) {\n\t\t\t\terasing.add(editor.getOutermostSelectableShape(shape).id)\n\t\t\t}\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([...erasing].filter((id) => !excludedShapeIds.has(id)))\n\t}\n\n\tcomplete() {\n\t\tconst { editor } = this\n\t\teditor.deleteShapes(editor.getCurrentPageState().erasingShapeIds)\n\t\tthis.parent.transition('idle')\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 {\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\tisAccelKey,\n\tpointInPolygon,\n} from '@tldraw/editor'\n\nexport class Erasing extends StateNode {\n\tstatic override id = 'erasing'\n\n\tprivate info = {} as TLPointerEventInfo\n\tprivate scribbleId = 'id'\n\tprivate markId = ''\n\tprivate excludedShapeIds = new Set<TLShapeId>()\n\n\t_isHoldingAccelKey = false\n\t_firstErasingShapeId: TLShapeId | null = null\n\t_erasingShapeIds: TLShapeId[] = []\n\n\toverride onEnter(info: TLPointerEventInfo) {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis._firstErasingShapeId = this.editor.getErasingShapeIds()[0] // the first one should be the first one we hit... is it?\n\t\tthis._erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tthis.markId = this.editor.markHistoryStoppingPoint('erase scribble begin')\n\t\tthis.info = info\n\n\t\tconst { originPagePoint } = this.editor.inputs\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, check we're inside it when we start erasing\n\t\t\t\t\tif (\n\t\t\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group') ||\n\t\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(shape, 'frame')\n\t\t\t\t\t) {\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\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.currentPagePoint\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() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onKeyUp() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis.update()\n\t}\n\n\toverride onKeyDown() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t\tthis.update()\n\t}\n\n\tupdate() {\n\t\tconst { editor, excludedShapeIds } = this\n\t\tconst erasingShapeIds = editor.getErasingShapeIds()\n\t\tconst zoomLevel = editor.getZoomLevel()\n\t\tconst currentPageShapes = editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint, previousPagePoint },\n\t\t} = editor\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.options.hitTestMargin / zoomLevel\n\n\t\tfor (const shape of currentPageShapes) {\n\t\t\tif (editor.isShapeOfType<TLGroupShape>(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\tif (geometry.hitTestLineSegment(A, B, minDist)) {\n\t\t\t\terasing.add(editor.getOutermostSelectableShape(shape).id)\n\t\t\t}\n\n\t\t\tthis._erasingShapeIds = [...erasing]\n\t\t}\n\n\t\t// If the user is holding the meta / ctrl key, we should only erase the first shape we hit\n\t\tif (this._isHoldingAccelKey && this._firstErasingShapeId) {\n\t\t\tconst erasingShapeId = this._firstErasingShapeId\n\t\t\tif (erasingShapeId && this.editor.getShape(erasingShapeId)) {\n\t\t\t\teditor.setErasingShapes([erasingShapeId])\n\t\t\t}\n\t\t\treturn\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() {\n\t\tconst { editor } = this\n\t\teditor.deleteShapes(editor.getCurrentPageState().erasingShapeIds)\n\t\tthis.parent.transition('idle')\n\t\tthis._erasingShapeIds = []\n\t\tthis._firstErasingShapeId = null\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
  }
@@ -1,9 +1,12 @@
1
1
  import {
2
+ isAccelKey,
2
3
  StateNode
3
4
  } from "@tldraw/editor";
4
5
  class Pointing extends StateNode {
5
6
  static id = "pointing";
7
+ _isHoldingAccelKey = false;
6
8
  onEnter() {
9
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs);
7
10
  const zoomLevel = this.editor.getZoomLevel();
8
11
  const currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted();
9
12
  const {
@@ -25,10 +28,19 @@ class Pointing extends StateNode {
25
28
  break;
26
29
  }
27
30
  erasing.add(hitShape.id);
31
+ if (this._isHoldingAccelKey) {
32
+ break;
33
+ }
28
34
  }
29
35
  }
30
36
  this.editor.setErasingShapes([...erasing]);
31
37
  }
38
+ onKeyUp() {
39
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs);
40
+ }
41
+ onKeyDown() {
42
+ this._isHoldingAccelKey = isAccelKey(this.editor.inputs);
43
+ }
32
44
  onLongPress(info) {
33
45
  this.startErasing(info);
34
46
  }
@@ -38,6 +50,7 @@ class Pointing extends StateNode {
38
50
  }
39
51
  }
40
52
  onPointerMove(info) {
53
+ if (this._isHoldingAccelKey) return;
41
54
  if (this.editor.inputs.isDragging) {
42
55
  this.startErasing(info);
43
56
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/tools/EraserTool/childStates/Pointing.ts"],
4
- "sourcesContent": ["import {\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n} from '@tldraw/editor'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\toverride onEnter() {\n\t\tconst zoomLevel = this.editor.getZoomLevel()\n\t\tconst currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint },\n\t\t} = this.editor\n\n\t\tconst erasing = new Set<TLShapeId>()\n\n\t\tconst initialSize = erasing.size\n\n\t\tfor (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {\n\t\t\tconst shape = currentPageShapesSorted[i]\n\t\t\tif (\n\t\t\t\tthis.editor.isShapeOrAncestorLocked(shape) ||\n\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group')\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.editor.isPointInShape(shape, currentPagePoint, {\n\t\t\t\t\thitInside: false,\n\t\t\t\t\tmargin: this.editor.options.hitTestMargin / zoomLevel,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tconst hitShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\t// If we've hit a frame after hitting any other shape, stop here\n\t\t\t\tif (\n\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(hitShape, 'frame') &&\n\t\t\t\t\terasing.size > initialSize\n\t\t\t\t) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\terasing.add(hitShape.id)\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.setErasingShapes([...erasing])\n\t}\n\n\toverride onLongPress(info: TLPointerEventInfo) {\n\t\tthis.startErasing(info)\n\t}\n\n\toverride onExit(_info: any, to: string) {\n\t\tif (to !== 'erasing') {\n\t\t\tthis.editor.setErasingShapes([])\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tthis.startErasing(info)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate startErasing(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('erasing', info)\n\t}\n\n\tcomplete() {\n\t\tconst erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tif (erasingShapeIds.length) {\n\t\t\tthis.editor.markHistoryStoppingPoint('erase end')\n\t\t\tthis.editor.deleteShapes(erasingShapeIds)\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
5
- "mappings": "AAAA;AAAA,EACC;AAAA,OAKM;AAEA,MAAM,iBAAiB,UAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAEZ,UAAU;AAClB,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,0BAA0B,KAAK,OAAO,oCAAoC;AAChF,UAAM;AAAA,MACL,QAAQ,EAAE,iBAAiB;AAAA,IAC5B,IAAI,KAAK;AAET,UAAM,UAAU,oBAAI,IAAe;AAEnC,UAAM,cAAc,QAAQ;AAE5B,aAAS,IAAI,wBAAwB,QAAQ,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AACpE,YAAM,QAAQ,wBAAwB,CAAC;AACvC,UACC,KAAK,OAAO,wBAAwB,KAAK,KACzC,KAAK,OAAO,cAA4B,OAAO,OAAO,GACrD;AACD;AAAA,MACD;AAEA,UACC,KAAK,OAAO,eAAe,OAAO,kBAAkB;AAAA,QACnD,WAAW;AAAA,QACX,QAAQ,KAAK,OAAO,QAAQ,gBAAgB;AAAA,MAC7C,CAAC,GACA;AACD,cAAM,WAAW,KAAK,OAAO,4BAA4B,KAAK;AAE9D,YACC,KAAK,OAAO,cAA4B,UAAU,OAAO,KACzD,QAAQ,OAAO,aACd;AACD;AAAA,QACD;AAEA,gBAAQ,IAAI,SAAS,EAAE;AAAA,MACxB;AAAA,IACD;AAEA,SAAK,OAAO,iBAAiB,CAAC,GAAG,OAAO,CAAC;AAAA,EAC1C;AAAA,EAES,YAAY,MAA0B;AAC9C,SAAK,aAAa,IAAI;AAAA,EACvB;AAAA,EAES,OAAO,OAAY,IAAY;AACvC,QAAI,OAAO,WAAW;AACrB,WAAK,OAAO,iBAAiB,CAAC,CAAC;AAAA,IAChC;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,OAAO,OAAO,YAAY;AAClC,WAAK,aAAa,IAAI;AAAA,IACvB;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,WAAW;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAEQ,aAAa,MAA0B;AAC9C,SAAK,OAAO,WAAW,WAAW,IAAI;AAAA,EACvC;AAAA,EAEA,WAAW;AACV,UAAM,kBAAkB,KAAK,OAAO,mBAAmB;AAEvD,QAAI,gBAAgB,QAAQ;AAC3B,WAAK,OAAO,yBAAyB,WAAW;AAChD,WAAK,OAAO,aAAa,eAAe;AAAA,IACzC;AAEA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEA,SAAS;AACR,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AACD;",
4
+ "sourcesContent": ["import {\n\tisAccelKey,\n\tStateNode,\n\tTLFrameShape,\n\tTLGroupShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n} from '@tldraw/editor'\n\nexport class Pointing extends StateNode {\n\tstatic override id = 'pointing'\n\n\t_isHoldingAccelKey = false\n\n\toverride onEnter() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\n\t\tconst zoomLevel = this.editor.getZoomLevel()\n\t\tconst currentPageShapesSorted = this.editor.getCurrentPageRenderingShapesSorted()\n\t\tconst {\n\t\t\tinputs: { currentPagePoint },\n\t\t} = this.editor\n\n\t\tconst erasing = new Set<TLShapeId>()\n\n\t\tconst initialSize = erasing.size\n\n\t\tfor (let n = currentPageShapesSorted.length, i = n - 1; i >= 0; i--) {\n\t\t\tconst shape = currentPageShapesSorted[i]\n\t\t\tif (\n\t\t\t\tthis.editor.isShapeOrAncestorLocked(shape) ||\n\t\t\t\tthis.editor.isShapeOfType<TLGroupShape>(shape, 'group')\n\t\t\t) {\n\t\t\t\tcontinue\n\t\t\t}\n\n\t\t\tif (\n\t\t\t\tthis.editor.isPointInShape(shape, currentPagePoint, {\n\t\t\t\t\thitInside: false,\n\t\t\t\t\tmargin: this.editor.options.hitTestMargin / zoomLevel,\n\t\t\t\t})\n\t\t\t) {\n\t\t\t\tconst hitShape = this.editor.getOutermostSelectableShape(shape)\n\t\t\t\t// If we've hit a frame after hitting any other shape, stop here\n\t\t\t\tif (\n\t\t\t\t\tthis.editor.isShapeOfType<TLFrameShape>(hitShape, 'frame') &&\n\t\t\t\t\terasing.size > initialSize\n\t\t\t\t) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\n\t\t\t\terasing.add(hitShape.id)\n\n\t\t\t\t// If the user is holding the meta / ctrl key, stop after the first shape\n\t\t\t\tif (this._isHoldingAccelKey) {\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.editor.setErasingShapes([...erasing])\n\t}\n\n\toverride onKeyUp() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t}\n\n\toverride onKeyDown() {\n\t\tthis._isHoldingAccelKey = isAccelKey(this.editor.inputs)\n\t}\n\n\toverride onLongPress(info: TLPointerEventInfo) {\n\t\tthis.startErasing(info)\n\t}\n\n\toverride onExit(_info: any, to: string) {\n\t\tif (to !== 'erasing') {\n\t\t\tthis.editor.setErasingShapes([])\n\t\t}\n\t}\n\n\toverride onPointerMove(info: TLPointerEventInfo) {\n\t\tif (this._isHoldingAccelKey) return\n\n\t\tif (this.editor.inputs.isDragging) {\n\t\t\tthis.startErasing(info)\n\t\t}\n\t}\n\n\toverride onPointerUp() {\n\t\tthis.complete()\n\t}\n\n\toverride onCancel() {\n\t\tthis.cancel()\n\t}\n\n\toverride onComplete() {\n\t\tthis.complete()\n\t}\n\n\toverride onInterrupt() {\n\t\tthis.cancel()\n\t}\n\n\tprivate startErasing(info: TLPointerEventInfo) {\n\t\tthis.parent.transition('erasing', info)\n\t}\n\n\tcomplete() {\n\t\tconst erasingShapeIds = this.editor.getErasingShapeIds()\n\n\t\tif (erasingShapeIds.length) {\n\t\t\tthis.editor.markHistoryStoppingPoint('erase end')\n\t\t\tthis.editor.deleteShapes(erasingShapeIds)\n\t\t}\n\n\t\tthis.parent.transition('idle')\n\t}\n\n\tcancel() {\n\t\tthis.parent.transition('idle')\n\t}\n}\n"],
5
+ "mappings": "AAAA;AAAA,EACC;AAAA,EACA;AAAA,OAKM;AAEA,MAAM,iBAAiB,UAAU;AAAA,EACvC,OAAgB,KAAK;AAAA,EAErB,qBAAqB;AAAA,EAEZ,UAAU;AAClB,SAAK,qBAAqB,WAAW,KAAK,OAAO,MAAM;AAEvD,UAAM,YAAY,KAAK,OAAO,aAAa;AAC3C,UAAM,0BAA0B,KAAK,OAAO,oCAAoC;AAChF,UAAM;AAAA,MACL,QAAQ,EAAE,iBAAiB;AAAA,IAC5B,IAAI,KAAK;AAET,UAAM,UAAU,oBAAI,IAAe;AAEnC,UAAM,cAAc,QAAQ;AAE5B,aAAS,IAAI,wBAAwB,QAAQ,IAAI,IAAI,GAAG,KAAK,GAAG,KAAK;AACpE,YAAM,QAAQ,wBAAwB,CAAC;AACvC,UACC,KAAK,OAAO,wBAAwB,KAAK,KACzC,KAAK,OAAO,cAA4B,OAAO,OAAO,GACrD;AACD;AAAA,MACD;AAEA,UACC,KAAK,OAAO,eAAe,OAAO,kBAAkB;AAAA,QACnD,WAAW;AAAA,QACX,QAAQ,KAAK,OAAO,QAAQ,gBAAgB;AAAA,MAC7C,CAAC,GACA;AACD,cAAM,WAAW,KAAK,OAAO,4BAA4B,KAAK;AAE9D,YACC,KAAK,OAAO,cAA4B,UAAU,OAAO,KACzD,QAAQ,OAAO,aACd;AACD;AAAA,QACD;AAEA,gBAAQ,IAAI,SAAS,EAAE;AAGvB,YAAI,KAAK,oBAAoB;AAC5B;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAEA,SAAK,OAAO,iBAAiB,CAAC,GAAG,OAAO,CAAC;AAAA,EAC1C;AAAA,EAES,UAAU;AAClB,SAAK,qBAAqB,WAAW,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA,EAES,YAAY;AACpB,SAAK,qBAAqB,WAAW,KAAK,OAAO,MAAM;AAAA,EACxD;AAAA,EAES,YAAY,MAA0B;AAC9C,SAAK,aAAa,IAAI;AAAA,EACvB;AAAA,EAES,OAAO,OAAY,IAAY;AACvC,QAAI,OAAO,WAAW;AACrB,WAAK,OAAO,iBAAiB,CAAC,CAAC;AAAA,IAChC;AAAA,EACD;AAAA,EAES,cAAc,MAA0B;AAChD,QAAI,KAAK,mBAAoB;AAE7B,QAAI,KAAK,OAAO,OAAO,YAAY;AAClC,WAAK,aAAa,IAAI;AAAA,IACvB;AAAA,EACD;AAAA,EAES,cAAc;AACtB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,WAAW;AACnB,SAAK,OAAO;AAAA,EACb;AAAA,EAES,aAAa;AACrB,SAAK,SAAS;AAAA,EACf;AAAA,EAES,cAAc;AACtB,SAAK,OAAO;AAAA,EACb;AAAA,EAEQ,aAAa,MAA0B;AAC9C,SAAK,OAAO,WAAW,WAAW,IAAI;AAAA,EACvC;AAAA,EAEA,WAAW;AACV,UAAM,kBAAkB,KAAK,OAAO,mBAAmB;AAEvD,QAAI,gBAAgB,QAAQ;AAC3B,WAAK,OAAO,yBAAyB,WAAW;AAChD,WAAK,OAAO,aAAa,eAAe;AAAA,IACzC;AAEA,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AAAA,EAEA,SAAS;AACR,SAAK,OAAO,WAAW,MAAM;AAAA,EAC9B;AACD;",
6
6
  "names": []
7
7
  }
@@ -95,6 +95,8 @@ class DraggingHandle extends StateNode {
95
95
  exactTimeout = -1;
96
96
  // Only relevant to arrows
97
97
  resetExactTimeout() {
98
+ const arrowUtil = this.editor.getShapeUtil("arrow");
99
+ const timeoutValue = arrowUtil.options.pointingPreciseTimeout;
98
100
  if (this.exactTimeout !== -1) {
99
101
  this.clearExactTimeout();
100
102
  }
@@ -105,7 +107,7 @@ class DraggingHandle extends StateNode {
105
107
  this.update();
106
108
  }
107
109
  this.exactTimeout = -1;
108
- }, 750);
110
+ }, timeoutValue);
109
111
  }
110
112
  // Only relevant to arrows
111
113
  clearExactTimeout() {