tldraw 3.15.1 → 3.16.0-canary.03deb7f8fe34

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 (374) hide show
  1. package/dist-cjs/index.d.ts +271 -9
  2. package/dist-cjs/index.js +28 -2
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/canvas/TldrawCropHandles.js.map +2 -2
  5. package/dist-cjs/lib/canvas/TldrawScribble.js +1 -1
  6. package/dist-cjs/lib/canvas/TldrawScribble.js.map +2 -2
  7. package/dist-cjs/lib/defaultExternalContentHandlers.js +1 -0
  8. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  9. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +25 -39
  10. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  11. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +16 -4
  12. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +2 -2
  13. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +1 -1
  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 +3 -0
  18. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  19. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
  20. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.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 -12
  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/geo/GeoShapeUtil.js +2 -2
  28. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  29. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
  30. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
  31. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
  32. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  33. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -3
  34. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +1 -1
  35. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +20 -2
  36. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  37. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
  38. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  39. package/dist-cjs/lib/shapes/shared/ShapeFill.js +4 -4
  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/usePrefersReducedMotion.js +10 -1
  43. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +2 -2
  44. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
  45. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
  46. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  47. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  48. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  49. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  50. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  51. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  52. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +43 -22
  53. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  54. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +2 -15
  55. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  56. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +5 -0
  57. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
  58. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +8 -0
  59. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  60. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js +8 -0
  61. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js.map +2 -2
  62. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +8 -0
  63. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  64. package/dist-cjs/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.js.map +2 -2
  65. package/dist-cjs/lib/ui/TldrawUi.js +14 -0
  66. package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
  67. package/dist-cjs/lib/ui/components/AccessibilityMenu.js +35 -0
  68. package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +7 -0
  69. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +12 -3
  70. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  71. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
  72. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
  73. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +40 -0
  74. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +3 -3
  76. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  78. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/MobileStylePanel.js +5 -3
  80. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +1 -1
  82. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +2 -1
  84. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
  86. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
  88. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +2 -0
  90. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  91. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +171 -140
  92. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  93. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js +3 -3
  94. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +2 -2
  95. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js +26 -25
  96. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +3 -3
  97. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +1 -1
  98. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  99. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -21
  100. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
  101. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +189 -80
  102. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
  103. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +5 -4
  104. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  105. package/dist-cjs/lib/ui/components/menu-items.js +6 -0
  106. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  107. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +5 -16
  108. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +3 -3
  109. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +1 -1
  110. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  111. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
  112. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
  113. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -0
  114. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  115. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +30 -7
  116. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  117. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +268 -0
  118. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
  119. package/dist-cjs/lib/ui/components/primitives/layout.js +76 -0
  120. package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
  121. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  122. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
  123. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  124. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +153 -20
  125. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  126. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js +3 -2
  127. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js.map +2 -2
  128. package/dist-cjs/lib/ui/context/actions.js +29 -7
  129. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  130. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  131. package/dist-cjs/lib/ui/hooks/menu-hooks.js.map +2 -2
  132. package/dist-cjs/lib/ui/hooks/useTools.js +94 -9
  133. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  134. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  135. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +7 -0
  136. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  137. package/dist-cjs/lib/ui/kbd-utils.js +2 -1
  138. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  139. package/dist-cjs/lib/ui/version.js +3 -3
  140. package/dist-cjs/lib/ui/version.js.map +1 -1
  141. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js +1 -1
  142. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js.map +2 -2
  143. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js +3 -2
  144. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js.map +2 -2
  145. package/dist-esm/index.d.mts +271 -9
  146. package/dist-esm/index.mjs +44 -3
  147. package/dist-esm/index.mjs.map +2 -2
  148. package/dist-esm/lib/canvas/TldrawCropHandles.mjs.map +2 -2
  149. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  150. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  151. package/dist-esm/lib/defaultExternalContentHandlers.mjs +1 -0
  152. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  153. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +28 -39
  154. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  155. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +19 -5
  156. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +2 -2
  157. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +1 -1
  158. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  159. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  160. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  161. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +3 -0
  162. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  163. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
  164. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  165. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  166. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  167. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +13 -12
  168. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  169. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  170. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  171. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +3 -2
  172. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  173. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
  174. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
  175. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
  176. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  177. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -3
  178. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +1 -1
  179. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +21 -2
  180. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  181. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +5 -4
  182. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  183. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +5 -4
  184. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  185. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  186. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +10 -1
  187. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +2 -2
  188. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
  189. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
  190. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  191. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  192. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  193. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  194. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  195. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  196. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +43 -22
  197. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  198. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +2 -15
  199. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  200. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +5 -0
  201. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
  202. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +8 -0
  203. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  204. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs +8 -0
  205. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs.map +2 -2
  206. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +8 -0
  207. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  208. package/dist-esm/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.mjs.map +2 -2
  209. package/dist-esm/lib/ui/TldrawUi.mjs +16 -2
  210. package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
  211. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +19 -0
  212. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +7 -0
  213. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +12 -3
  214. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  215. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
  216. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
  217. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +40 -0
  218. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +2 -2
  219. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +3 -5
  220. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
  221. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  222. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  223. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +6 -3
  224. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  225. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
  226. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
  227. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -1
  228. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  229. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
  230. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
  231. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
  232. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs.map +2 -2
  233. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +3 -1
  234. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  235. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +171 -140
  236. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  237. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs +3 -3
  238. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +2 -2
  239. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs +26 -25
  240. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +2 -2
  241. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +1 -1
  242. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  243. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -21
  244. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
  245. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -81
  246. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
  247. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +5 -4
  248. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  249. package/dist-esm/lib/ui/components/menu-items.mjs +6 -0
  250. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  251. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +6 -6
  252. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +2 -2
  253. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +1 -1
  254. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  255. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
  256. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
  257. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +1 -0
  258. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  259. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +30 -7
  260. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  261. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +245 -0
  262. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
  263. package/dist-esm/lib/ui/components/primitives/layout.mjs +46 -0
  264. package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
  265. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  266. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
  267. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  268. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +161 -22
  269. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  270. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs +3 -2
  271. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs.map +2 -2
  272. package/dist-esm/lib/ui/context/actions.mjs +29 -7
  273. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  274. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  275. package/dist-esm/lib/ui/hooks/menu-hooks.mjs.map +2 -2
  276. package/dist-esm/lib/ui/hooks/useTools.mjs +102 -10
  277. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  278. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +7 -0
  279. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  280. package/dist-esm/lib/ui/kbd-utils.mjs +2 -1
  281. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  282. package/dist-esm/lib/ui/version.mjs +3 -3
  283. package/dist-esm/lib/ui/version.mjs.map +1 -1
  284. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs +1 -1
  285. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs.map +2 -2
  286. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs +3 -2
  287. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs.map +2 -2
  288. package/package.json +3 -3
  289. package/src/index.ts +32 -1
  290. package/src/lib/canvas/TldrawCropHandles.tsx +2 -0
  291. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  292. package/src/lib/defaultExternalContentHandlers.ts +2 -1
  293. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +5 -5
  294. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +29 -42
  295. package/src/lib/shapes/arrow/arrowLabel.ts +23 -3
  296. package/src/lib/shapes/arrow/arrowTargetState.ts +2 -1
  297. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  298. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +3 -0
  299. package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
  300. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  301. package/src/lib/shapes/frame/FrameShapeUtil.tsx +21 -14
  302. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  303. package/src/lib/shapes/geo/GeoShapeUtil.tsx +3 -2
  304. package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
  305. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
  306. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -3
  307. package/src/lib/shapes/line/LineShapeUtil.tsx +25 -3
  308. package/src/lib/shapes/note/NoteShapeUtil.tsx +9 -4
  309. package/src/lib/shapes/shared/ShapeFill.tsx +5 -4
  310. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  311. package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
  312. package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
  313. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  314. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  315. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  316. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +54 -30
  317. package/src/lib/tools/SelectTool/childStates/Idle.ts +2 -24
  318. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +7 -0
  319. package/src/lib/tools/SelectTool/childStates/Resizing.ts +12 -1
  320. package/src/lib/tools/SelectTool/childStates/Rotating.ts +11 -0
  321. package/src/lib/tools/SelectTool/childStates/Translating.ts +11 -1
  322. package/src/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.ts +1 -0
  323. package/src/lib/ui/TldrawUi.tsx +17 -2
  324. package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
  325. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +15 -3
  326. package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
  327. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +32 -0
  328. package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
  329. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  330. package/src/lib/ui/components/MobileStylePanel.tsx +9 -6
  331. package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
  332. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +3 -2
  333. package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
  334. package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
  335. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +3 -1
  336. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +146 -107
  337. package/src/lib/ui/components/StylePanel/DoubleDropdownPicker.tsx +3 -3
  338. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +7 -6
  339. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +1 -1
  340. package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -23
  341. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +212 -61
  342. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +17 -12
  343. package/src/lib/ui/components/menu-items.tsx +8 -0
  344. package/src/lib/ui/components/primitives/TldrawUiButtonPicker.tsx +40 -37
  345. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +1 -1
  346. package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
  347. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +1 -0
  348. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +51 -12
  349. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +327 -0
  350. package/src/lib/ui/components/primitives/layout.tsx +107 -0
  351. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  352. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
  353. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +220 -19
  354. package/src/lib/ui/context/TldrawUiContextProvider.tsx +23 -20
  355. package/src/lib/ui/context/actions.tsx +29 -7
  356. package/src/lib/ui/context/events.tsx +4 -2
  357. package/src/lib/ui/hooks/menu-hooks.ts +1 -0
  358. package/src/lib/ui/hooks/useTools.tsx +140 -10
  359. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +7 -0
  360. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +7 -0
  361. package/src/lib/ui/kbd-utils.ts +2 -1
  362. package/src/lib/ui/version.ts +3 -3
  363. package/src/lib/ui.css +406 -292
  364. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +16 -2
  365. package/src/lib/utils/excalidraw/putExcalidrawContent.ts +1 -1
  366. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +24 -3
  367. package/src/lib/utils/tldr/buildFromV1Document.ts +2 -1
  368. package/src/test/EraserTool.test.ts +176 -6
  369. package/src/test/SelectTool.test.ts +37 -11
  370. package/src/test/arrows-megabus.test.tsx +12 -6
  371. package/src/test/commands/deletePage.test.ts +84 -1
  372. package/src/test/inner-outer-margin.test.ts +315 -0
  373. package/src/test/shapeutils.test.ts +394 -45
  374. package/tldraw.css +703 -603
@@ -0,0 +1,107 @@
1
+ import classNames from 'classnames'
2
+ import { Slot } from 'radix-ui'
3
+ import { HTMLAttributes, ReactNode, createContext, forwardRef, useContext } from 'react'
4
+
5
+ /** @public */
6
+ export interface TldrawUiOrientationContext {
7
+ orientation: 'horizontal' | 'vertical'
8
+ tooltipSide: 'top' | 'right' | 'bottom' | 'left'
9
+ }
10
+
11
+ const TldrawUiOrientationContext = createContext<TldrawUiOrientationContext>({
12
+ orientation: 'horizontal',
13
+ tooltipSide: 'bottom',
14
+ })
15
+
16
+ /** @public */
17
+ export interface TldrawUiOrientationProviderProps {
18
+ children: ReactNode
19
+ orientation: 'horizontal' | 'vertical'
20
+ tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
21
+ }
22
+ /** @public @react */
23
+ export function TldrawUiOrientationProvider({
24
+ children,
25
+ orientation,
26
+ tooltipSide,
27
+ }: TldrawUiOrientationProviderProps) {
28
+ const prevContext = useTldrawUiOrientation()
29
+ // generally, we want tooltip side to cascade down through the layout - apart from when the
30
+ // orientation changes. If the tooltip side is "bottom", and then I include some vertical layout
31
+ // elements, keeping the tooltip side as bottom will cause the tooltip to overlap elements
32
+ // stacked on top of each other. In the absence of a tooltip side, we pick a default side based
33
+ // on the orientation whenever the orientation changes.
34
+ const tooltipSideToUse =
35
+ tooltipSide ??
36
+ (orientation === prevContext.orientation
37
+ ? prevContext.tooltipSide
38
+ : orientation === 'horizontal'
39
+ ? 'bottom'
40
+ : 'right')
41
+
42
+ return (
43
+ <TldrawUiOrientationContext.Provider value={{ orientation, tooltipSide: tooltipSideToUse }}>
44
+ {children}
45
+ </TldrawUiOrientationContext.Provider>
46
+ )
47
+ }
48
+
49
+ /** @public */
50
+ export function useTldrawUiOrientation() {
51
+ return useContext(TldrawUiOrientationContext)
52
+ }
53
+
54
+ /** @public */
55
+ export interface TLUiLayoutProps extends HTMLAttributes<HTMLDivElement> {
56
+ children: ReactNode
57
+ tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
58
+ asChild?: boolean
59
+ }
60
+
61
+ /**
62
+ * A row, usually of UI controls like buttons, select dropdown, checkboxes, etc.
63
+ *
64
+ * @public @react
65
+ */
66
+ export const TldrawUiRow = forwardRef<HTMLDivElement, TLUiLayoutProps>(
67
+ ({ asChild, className, tooltipSide, ...props }, ref) => {
68
+ const Component = asChild ? Slot.Root : 'div'
69
+ return (
70
+ <TldrawUiOrientationProvider orientation="horizontal" tooltipSide={tooltipSide}>
71
+ <Component ref={ref} className={classNames('tlui-row', className)} {...props} />
72
+ </TldrawUiOrientationProvider>
73
+ )
74
+ }
75
+ )
76
+
77
+ /**
78
+ * A column, usually of UI controls like buttons, select dropdown, checkboxes, etc.
79
+ *
80
+ * @public @react
81
+ */
82
+ export const TldrawUiColumn = forwardRef<HTMLDivElement, TLUiLayoutProps>(
83
+ ({ asChild, className, tooltipSide, ...props }, ref) => {
84
+ const Component = asChild ? Slot.Root : 'div'
85
+ return (
86
+ <TldrawUiOrientationProvider orientation="vertical" tooltipSide={tooltipSide}>
87
+ <Component ref={ref} className={classNames('tlui-column', className)} {...props} />
88
+ </TldrawUiOrientationProvider>
89
+ )
90
+ }
91
+ )
92
+
93
+ /**
94
+ * A tight grid 4 elements wide, usually of UI controls like buttons, select dropdown, checkboxes,
95
+ * etc.
96
+ *
97
+ * @public @react */
98
+ export const TldrawUiGrid = forwardRef<HTMLDivElement, TLUiLayoutProps>(
99
+ ({ asChild, className, tooltipSide, ...props }, ref) => {
100
+ const Component = asChild ? Slot.Root : 'div'
101
+ return (
102
+ <TldrawUiOrientationProvider orientation="horizontal" tooltipSide={tooltipSide}>
103
+ <Component ref={ref} className={classNames('tlui-grid', className)} {...props} />
104
+ </TldrawUiOrientationProvider>
105
+ )
106
+ }
107
+ )
@@ -3,7 +3,6 @@ import { TLUiEventSource } from '../../../context/events'
3
3
 
4
4
  /** @public */
5
5
  export type TLUiMenuContextType =
6
- | 'panel'
7
6
  | 'menu'
8
7
  | 'small-icons'
9
8
  | 'context-menu'
@@ -3,6 +3,7 @@ import { ReactNode } from 'react'
3
3
  import { unwrapLabel } from '../../../context/actions'
4
4
  import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
5
5
  import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
6
+ import { TldrawUiColumn, TldrawUiGrid, TldrawUiRow, useTldrawUiOrientation } from '../layout'
6
7
  import { TldrawUiDropdownMenuGroup } from '../TldrawUiDropdownMenu'
7
8
  import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
8
9
 
@@ -19,25 +20,19 @@ export interface TLUiMenuGroupProps<TranslationKey extends string = string> {
19
20
 
20
21
  /** @public @react */
21
22
  export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGroupProps) {
22
- const { type: menuType, sourceId } = useTldrawUiMenuContext()
23
+ const menu = useTldrawUiMenuContext()
24
+ const { orientation } = useTldrawUiOrientation()
23
25
  const msg = useTranslation()
24
- const labelToUse = unwrapLabel(label, menuType)
26
+ const labelToUse = unwrapLabel(label, menu.type)
25
27
  const labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined
26
28
 
27
- switch (menuType) {
28
- case 'panel': {
29
- return (
30
- <div
31
- className={classNames('tlui-menu__group', className)}
32
- data-testid={`${sourceId}-group.${id}`}
33
- >
34
- {children}
35
- </div>
36
- )
37
- }
29
+ switch (menu.type) {
38
30
  case 'menu': {
39
31
  return (
40
- <TldrawUiDropdownMenuGroup className={className} data-testid={`${sourceId}-group.${id}`}>
32
+ <TldrawUiDropdownMenuGroup
33
+ className={className}
34
+ data-testid={`${menu.sourceId}-group.${id}`}
35
+ >
41
36
  {children}
42
37
  </TldrawUiDropdownMenuGroup>
43
38
  )
@@ -47,7 +42,7 @@ export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGr
47
42
  <div
48
43
  dir="ltr"
49
44
  className={classNames('tlui-menu__group', className)}
50
- data-testid={`${sourceId}-group.${id}`}
45
+ data-testid={`${menu.sourceId}-group.${id}`}
51
46
  >
52
47
  {children}
53
48
  </div>
@@ -56,12 +51,30 @@ export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGr
56
51
  case 'keyboard-shortcuts': {
57
52
  // todo: if groups need a label, let's give em a label
58
53
  return (
59
- <div className="tlui-shortcuts-dialog__group" data-testid={`${sourceId}-group.${id}`}>
54
+ <div className="tlui-shortcuts-dialog__group" data-testid={`${menu.sourceId}-group.${id}`}>
60
55
  <h2 className="tlui-shortcuts-dialog__group__title">{labelStr}</h2>
61
56
  <div className="tlui-shortcuts-dialog__group__content">{children}</div>
62
57
  </div>
63
58
  )
64
59
  }
60
+ case 'toolbar': {
61
+ const Layout = orientation === 'horizontal' ? TldrawUiRow : TldrawUiColumn
62
+ return (
63
+ <Layout className="tlui-main-toolbar__group" data-testid={`${menu.sourceId}-group.${id}`}>
64
+ {children}
65
+ </Layout>
66
+ )
67
+ }
68
+ case 'toolbar-overflow': {
69
+ return (
70
+ <TldrawUiGrid
71
+ className="tlui-main-toolbar__group"
72
+ data-testid={`${menu.sourceId}-group.${id}`}
73
+ >
74
+ {children}
75
+ </TldrawUiGrid>
76
+ )
77
+ }
65
78
  default: {
66
79
  return children
67
80
  }
@@ -1,9 +1,18 @@
1
- import { exhaustiveSwitchError, preventDefault } from '@tldraw/editor'
1
+ import {
2
+ exhaustiveSwitchError,
3
+ getPointerInfo,
4
+ preventDefault,
5
+ TLPointerEventInfo,
6
+ useEditor,
7
+ Vec,
8
+ VecModel,
9
+ } from '@tldraw/editor'
2
10
  import { ContextMenu as _ContextMenu } from 'radix-ui'
3
- import { useState } from 'react'
11
+ import { useMemo, useState } from 'react'
4
12
  import { unwrapLabel } from '../../../context/actions'
5
13
  import { TLUiEventSource } from '../../../context/events'
6
14
  import { useReadonly } from '../../../hooks/useReadonly'
15
+ import { TLUiToolItem } from '../../../hooks/useTools'
7
16
  import { TLUiTranslationKey } from '../../../hooks/useTranslation/TLUiTranslationKey'
8
17
  import { useTranslation } from '../../../hooks/useTranslation/useTranslation'
9
18
  import { kbdStr } from '../../../kbd-utils'
@@ -15,6 +24,7 @@ import { TldrawUiDropdownMenuItem } from '../TldrawUiDropdownMenu'
15
24
  import { TLUiIconJsx } from '../TldrawUiIcon'
16
25
  import { TldrawUiKbd } from '../TldrawUiKbd'
17
26
  import { TldrawUiToolbarButton } from '../TldrawUiToolbar'
27
+ import { tooltipManager } from '../TldrawUiTooltip'
18
28
  import { useTldrawUiMenuContext } from './TldrawUiMenuContext'
19
29
 
20
30
  /** @public */
@@ -63,6 +73,10 @@ export interface TLUiMenuItemProps<
63
73
  * Whether the item is selected.
64
74
  */
65
75
  isSelected?: boolean
76
+ /**
77
+ * The function to call when the item is dragged. If this is provided, the item will be draggable.
78
+ */
79
+ onDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void
66
80
  }
67
81
 
68
82
  /** @public @react */
@@ -81,6 +95,7 @@ export function TldrawUiMenuItem<
81
95
  onSelect,
82
96
  noClose,
83
97
  isSelected,
98
+ onDragStart,
84
99
  }: TLUiMenuItemProps<TranslationKey, IconType>) {
85
100
  const { type: menuType, sourceId } = useTldrawUiMenuContext()
86
101
 
@@ -105,7 +120,6 @@ export function TldrawUiMenuItem<
105
120
  type="menu"
106
121
  data-testid={`${sourceId}.${id}`}
107
122
  disabled={disabled}
108
- title={titleStr}
109
123
  onClick={(e) => {
110
124
  if (noClose) {
111
125
  preventDefault(e)
@@ -131,7 +145,6 @@ export function TldrawUiMenuItem<
131
145
  return (
132
146
  <_ContextMenu.Item
133
147
  dir="ltr"
134
- title={titleStr}
135
148
  draggable={false}
136
149
  className="tlui-button tlui-button__menu"
137
150
  data-testid={`${sourceId}.${id}`}
@@ -153,20 +166,6 @@ export function TldrawUiMenuItem<
153
166
  </_ContextMenu.Item>
154
167
  )
155
168
  }
156
- case 'panel': {
157
- return (
158
- <TldrawUiButton
159
- data-testid={`${sourceId}.${id}`}
160
- type="menu"
161
- title={titleStr}
162
- disabled={disabled}
163
- onClick={() => onSelect(sourceId)}
164
- >
165
- <TldrawUiButtonLabel>{labelStr}</TldrawUiButtonLabel>
166
- {spinner ? <Spinner /> : icon && <TldrawUiButtonIcon icon={icon} />}
167
- </TldrawUiButton>
168
- )
169
- }
170
169
  case 'small-icons':
171
170
  case 'icons': {
172
171
  return (
@@ -207,6 +206,20 @@ export function TldrawUiMenuItem<
207
206
  )
208
207
  }
209
208
  case 'toolbar': {
209
+ if (onDragStart) {
210
+ return (
211
+ <DraggableToolbarButton
212
+ id={id}
213
+ icon={icon}
214
+ onSelect={onSelect}
215
+ onDragStart={onDragStart}
216
+ labelToUse={labelToUse}
217
+ titleStr={titleStr}
218
+ disabled={disabled}
219
+ isSelected={isSelected}
220
+ />
221
+ )
222
+ }
210
223
  return (
211
224
  <TldrawUiToolbarButton
212
225
  aria-label={labelStr}
@@ -227,12 +240,26 @@ export function TldrawUiMenuItem<
227
240
  )
228
241
  }
229
242
  case 'toolbar-overflow': {
243
+ if (onDragStart) {
244
+ return (
245
+ <DraggableToolbarButton
246
+ id={id}
247
+ icon={icon}
248
+ onSelect={onSelect}
249
+ onDragStart={onDragStart}
250
+ labelToUse={labelToUse}
251
+ titleStr={titleStr}
252
+ disabled={disabled}
253
+ isSelected={isSelected}
254
+ overflow
255
+ />
256
+ )
257
+ }
230
258
  return (
231
259
  <TldrawUiToolbarButton
232
260
  aria-label={labelStr}
233
261
  aria-pressed={isSelected ? 'true' : 'false'}
234
262
  isActive={isSelected}
235
- className="tlui-button-grid__button"
236
263
  data-testid={`tools.more.${id}`}
237
264
  data-value={id}
238
265
  disabled={disabled}
@@ -249,3 +276,177 @@ export function TldrawUiMenuItem<
249
276
  }
250
277
  }
251
278
  }
279
+
280
+ function useDraggableEvents(
281
+ onDragStart: TLUiToolItem['onDragStart'],
282
+ onSelect: TLUiToolItem['onSelect']
283
+ ) {
284
+ const editor = useEditor()
285
+ const events = useMemo(() => {
286
+ let state = { name: 'idle' } as
287
+ | {
288
+ name: 'idle'
289
+ }
290
+ | {
291
+ name: 'pointing'
292
+ screenSpaceStart: VecModel
293
+ }
294
+ | {
295
+ name: 'dragging'
296
+ screenSpaceStart: VecModel
297
+ }
298
+ | {
299
+ name: 'dragged'
300
+ }
301
+
302
+ function handlePointerDown(e: React.PointerEvent<HTMLButtonElement>) {
303
+ state = {
304
+ name: 'pointing',
305
+ screenSpaceStart: { x: e.clientX, y: e.clientY },
306
+ }
307
+
308
+ e.currentTarget.setPointerCapture(e.pointerId)
309
+ }
310
+
311
+ function handlePointerMove(e: React.PointerEvent<HTMLButtonElement>) {
312
+ if ((e as any).isSpecialRedispatchedEvent) return
313
+
314
+ if (state.name === 'pointing') {
315
+ const distanceSq = Vec.Dist2(state.screenSpaceStart, { x: e.clientX, y: e.clientY })
316
+ if (
317
+ distanceSq >
318
+ (editor.getInstanceState().isCoarsePointer
319
+ ? editor.options.coarseDragDistanceSquared
320
+ : editor.options.dragDistanceSquared)
321
+ ) {
322
+ const screenSpaceStart = state.screenSpaceStart
323
+ state = {
324
+ name: 'dragging',
325
+ screenSpaceStart,
326
+ }
327
+
328
+ editor.run(() => {
329
+ editor.setCurrentTool('select')
330
+
331
+ // Set origin point
332
+ editor.dispatch({
333
+ type: 'pointer',
334
+ target: 'canvas',
335
+ name: 'pointer_down',
336
+ ...getPointerInfo(e),
337
+ point: screenSpaceStart,
338
+ })
339
+
340
+ // Pointer down potentially selects shapes, so we need to deselect them.
341
+ editor.selectNone()
342
+
343
+ // start drag
344
+ onDragStart?.('toolbar', {
345
+ type: 'pointer',
346
+ target: 'canvas',
347
+ name: 'pointer_move',
348
+ ...getPointerInfo(e),
349
+ point: screenSpaceStart,
350
+ })
351
+
352
+ tooltipManager.hideAllTooltips()
353
+ })
354
+ }
355
+ }
356
+ }
357
+
358
+ function handlePointerUp(e: React.PointerEvent<HTMLButtonElement>) {
359
+ if ((e as any).isSpecialRedispatchedEvent) return
360
+
361
+ e.currentTarget.releasePointerCapture(e.pointerId)
362
+
363
+ editor.dispatch({
364
+ type: 'pointer',
365
+ target: 'canvas',
366
+ name: 'pointer_up',
367
+ ...getPointerInfo(e),
368
+ })
369
+ }
370
+
371
+ function handleClick() {
372
+ if (state.name === 'dragging' || state.name === 'dragged') {
373
+ state = { name: 'idle' }
374
+ return true
375
+ }
376
+
377
+ state = { name: 'idle' }
378
+ onSelect?.('toolbar')
379
+ }
380
+
381
+ return {
382
+ onPointerDown: handlePointerDown,
383
+ onPointerMove: handlePointerMove,
384
+ onPointerUp: handlePointerUp,
385
+ onClick: handleClick,
386
+ }
387
+ }, [onDragStart, editor, onSelect])
388
+
389
+ return events
390
+ }
391
+
392
+ function DraggableToolbarButton({
393
+ id,
394
+ labelToUse,
395
+ titleStr,
396
+ disabled,
397
+ isSelected,
398
+ icon,
399
+ onSelect,
400
+ onDragStart,
401
+ overflow,
402
+ }: {
403
+ id: string
404
+ disabled: boolean
405
+ labelToUse?: string
406
+ titleStr?: string
407
+ isSelected?: boolean
408
+ icon: TLUiMenuItemProps['icon']
409
+ onSelect: TLUiMenuItemProps['onSelect']
410
+ onDragStart: TLUiMenuItemProps['onDragStart']
411
+ overflow?: boolean
412
+ }) {
413
+ const events = useDraggableEvents(onDragStart, onSelect)
414
+
415
+ if (overflow) {
416
+ return (
417
+ <TldrawUiToolbarButton
418
+ aria-label={labelToUse}
419
+ aria-pressed={isSelected ? 'true' : 'false'}
420
+ isActive={isSelected}
421
+ className="tlui-button-grid__button"
422
+ data-testid={`tools.more.${id}`}
423
+ data-value={id}
424
+ disabled={disabled}
425
+ title={titleStr}
426
+ type="icon"
427
+ {...events}
428
+ >
429
+ <TldrawUiButtonIcon icon={icon!} />
430
+ </TldrawUiToolbarButton>
431
+ )
432
+ }
433
+
434
+ return (
435
+ <TldrawUiToolbarButton
436
+ aria-label={labelToUse}
437
+ aria-pressed={isSelected ? 'true' : 'false'}
438
+ data-testid={`tools.${id}`}
439
+ data-value={id}
440
+ disabled={disabled}
441
+ onTouchStart={(e) => {
442
+ preventDefault(e)
443
+ onSelect('toolbar')
444
+ }}
445
+ title={titleStr}
446
+ type="tool"
447
+ {...events}
448
+ >
449
+ <TldrawUiButtonIcon icon={icon!} />
450
+ </TldrawUiToolbarButton>
451
+ )
452
+ }
@@ -1,6 +1,7 @@
1
1
  import { RecursivePartial, defaultUserPreferences, track, useMaybeEditor } from '@tldraw/editor'
2
2
  import { ReactNode } from 'react'
3
3
  import { TLUiAssetUrls, useDefaultUiAssetUrlsWithOverrides } from '../assetUrls'
4
+ import { TldrawUiTooltipProvider } from '../components/primitives/TldrawUiTooltip'
4
5
  import { ToolsProvider } from '../hooks/useTools'
5
6
  import { TldrawUiTranslationProvider } from '../hooks/useTranslation/useTranslation'
6
7
  import {
@@ -72,26 +73,28 @@ export const TldrawUiContextProvider = track(function TldrawUiContextProvider({
72
73
  const editor = useMaybeEditor()
73
74
  return (
74
75
  <MimeTypeContext.Provider value={mediaMimeTypes}>
75
- <AssetUrlsProvider assetUrls={useDefaultUiAssetUrlsWithOverrides(assetUrls)}>
76
- <TldrawUiTranslationProvider
77
- overrides={useMergedTranslationOverrides(overrides)}
78
- locale={editor?.user.getLocale() ?? defaultUserPreferences.locale}
79
- >
80
- <TldrawUiEventsProvider onEvent={onUiEvent}>
81
- <TldrawUiToastsProvider>
82
- <TldrawUiDialogsProvider context={'tla'}>
83
- <TldrawUiA11yProvider>
84
- <BreakPointProvider forceMobile={forceMobile}>
85
- <TldrawUiComponentsProvider overrides={components}>
86
- <InternalProviders overrides={overrides}>{children}</InternalProviders>
87
- </TldrawUiComponentsProvider>
88
- </BreakPointProvider>
89
- </TldrawUiA11yProvider>
90
- </TldrawUiDialogsProvider>
91
- </TldrawUiToastsProvider>
92
- </TldrawUiEventsProvider>
93
- </TldrawUiTranslationProvider>
94
- </AssetUrlsProvider>
76
+ <TldrawUiTooltipProvider>
77
+ <AssetUrlsProvider assetUrls={useDefaultUiAssetUrlsWithOverrides(assetUrls)}>
78
+ <TldrawUiTranslationProvider
79
+ overrides={useMergedTranslationOverrides(overrides)}
80
+ locale={editor?.user.getLocale() ?? defaultUserPreferences.locale}
81
+ >
82
+ <TldrawUiEventsProvider onEvent={onUiEvent}>
83
+ <TldrawUiToastsProvider>
84
+ <TldrawUiDialogsProvider context={'tla'}>
85
+ <TldrawUiA11yProvider>
86
+ <BreakPointProvider forceMobile={forceMobile}>
87
+ <TldrawUiComponentsProvider overrides={components}>
88
+ <InternalProviders overrides={overrides}>{children}</InternalProviders>
89
+ </TldrawUiComponentsProvider>
90
+ </BreakPointProvider>
91
+ </TldrawUiA11yProvider>
92
+ </TldrawUiDialogsProvider>
93
+ </TldrawUiToastsProvider>
94
+ </TldrawUiEventsProvider>
95
+ </TldrawUiTranslationProvider>
96
+ </AssetUrlsProvider>
97
+ </TldrawUiTooltipProvider>
95
98
  </MimeTypeContext.Provider>
96
99
  )
97
100
  })
@@ -1037,17 +1037,20 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1037
1037
  id: 'rotate-cw',
1038
1038
  label: 'action.rotate-cw',
1039
1039
  icon: 'rotate-cw',
1040
+ kbd: 'shift+.,shift+alt+.',
1040
1041
  onSelect(source) {
1041
1042
  if (!canApplySelectionAction()) return
1042
1043
  if (mustGoBackToSelectToolFirst()) return
1043
1044
 
1044
- trackEvent('rotate-cw', { source })
1045
+ const isFine = editor.inputs.altKey
1046
+ trackEvent('rotate-cw', { source, fine: isFine })
1045
1047
  editor.markHistoryStoppingPoint('rotate-cw')
1046
1048
  editor.run(() => {
1047
- const offset = editor.getSelectionRotation() % (HALF_PI / 2)
1048
- const dontUseOffset = approximately(offset, 0) || approximately(offset, HALF_PI / 2)
1049
+ const rotation = HALF_PI / (isFine ? 96 : 6)
1050
+ const offset = editor.getSelectionRotation() % rotation
1051
+ const dontUseOffset = approximately(offset, 0) || approximately(offset, rotation)
1049
1052
  const selectedShapeIds = editor.getSelectedShapeIds()
1050
- editor.rotateShapesBy(selectedShapeIds, HALF_PI / 2 - (dontUseOffset ? 0 : offset))
1053
+ editor.rotateShapesBy(selectedShapeIds, rotation - (dontUseOffset ? 0 : offset))
1051
1054
  kickoutOccludedShapes(editor, selectedShapeIds)
1052
1055
  })
1053
1056
  },
@@ -1056,17 +1059,21 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1056
1059
  id: 'rotate-ccw',
1057
1060
  label: 'action.rotate-ccw',
1058
1061
  icon: 'rotate-ccw',
1062
+ // omg double comma
1063
+ kbd: 'shift+,,shift+alt+,',
1059
1064
  onSelect(source) {
1060
1065
  if (!canApplySelectionAction()) return
1061
1066
  if (mustGoBackToSelectToolFirst()) return
1062
1067
 
1063
- trackEvent('rotate-ccw', { source })
1068
+ const isFine = editor.inputs.altKey
1069
+ trackEvent('rotate-ccw', { source, fine: isFine })
1064
1070
  editor.markHistoryStoppingPoint('rotate-ccw')
1065
1071
  editor.run(() => {
1066
- const offset = editor.getSelectionRotation() % (HALF_PI / 2)
1072
+ const rotation = HALF_PI / (isFine ? 96 : 6)
1073
+ const offset = editor.getSelectionRotation() % rotation
1067
1074
  const offsetCloseToZero = approximately(offset, 0)
1068
1075
  const selectedShapeIds = editor.getSelectedShapeIds()
1069
- editor.rotateShapesBy(selectedShapeIds, offsetCloseToZero ? -(HALF_PI / 2) : -offset)
1076
+ editor.rotateShapesBy(selectedShapeIds, offsetCloseToZero ? -rotation : -offset)
1070
1077
  kickoutOccludedShapes(editor, selectedShapeIds)
1071
1078
  })
1072
1079
  },
@@ -1259,6 +1266,21 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1259
1266
  },
1260
1267
  checkbox: true,
1261
1268
  },
1269
+ {
1270
+ id: 'toggle-ui-labels',
1271
+ label: {
1272
+ default: 'action.toggle-ui-labels',
1273
+ menu: 'action.toggle-ui-labels.menu',
1274
+ },
1275
+ readonlyOk: true,
1276
+ onSelect(source) {
1277
+ trackEvent('toggle-ui-labels', { source })
1278
+ editor.user.updateUserPreferences({
1279
+ showUiLabels: !editor.user.getShowUiLabels(),
1280
+ })
1281
+ },
1282
+ checkbox: true,
1283
+ },
1262
1284
  {
1263
1285
  id: 'toggle-edge-scrolling',
1264
1286
  label: {
@@ -76,8 +76,8 @@ export interface TLUiEventMap {
76
76
  'delete-shapes': null
77
77
  'select-all-shapes': null
78
78
  'select-none-shapes': null
79
- 'rotate-ccw': null
80
- 'rotate-cw': null
79
+ 'rotate-ccw': { fine: boolean }
80
+ 'rotate-cw': { fine: boolean }
81
81
  'zoom-in': { towardsCursor: boolean }
82
82
  'zoom-out': { towardsCursor: boolean }
83
83
  'zoom-to-fit': null
@@ -108,6 +108,7 @@ export interface TLUiEventMap {
108
108
  'toggle-lock': null
109
109
  'toggle-reduce-motion': null
110
110
  'toggle-keyboard-shortcuts': null
111
+ 'toggle-ui-labels': null
111
112
  'toggle-edge-scrolling': null
112
113
  'color-scheme': { value: string }
113
114
  'exit-pen-mode': null
@@ -126,6 +127,7 @@ export interface TLUiEventMap {
126
127
  'open-context-menu': null
127
128
  'adjust-shape-styles': null
128
129
  'copy-link': null
130
+ 'drag-tool': { id: string }
129
131
  'image-replace': null
130
132
  'video-replace': null
131
133
  'open-kbd-shortcuts': null
@@ -123,6 +123,7 @@ export function useAnySelectedShapesCount(min?: number, max?: number) {
123
123
 
124
124
  /**
125
125
  * Returns true if the number of UNLOCKED selected shapes is at least min or at most max.
126
+ * @public
126
127
  */
127
128
  export function useUnlockedSelectedShapesCount(min?: number, max?: number) {
128
129
  const editor = useEditor()