tldraw 3.16.0-canary.f60032f16651 → 3.16.0-canary.faec5de49906

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 (460) hide show
  1. package/dist-cjs/index.d.ts +323 -106
  2. package/dist-cjs/index.js +45 -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 +5 -4
  9. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +3 -3
  11. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  13. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  14. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js +3 -3
  15. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js.map +1 -1
  16. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
  17. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +1 -1
  19. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
  20. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +20 -13
  21. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  22. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
  23. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
  24. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +3 -2
  25. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  26. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
  27. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
  28. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
  29. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  30. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +6 -3
  31. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  32. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +5 -1
  33. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  34. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +6 -5
  35. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  36. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  37. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  38. package/dist-cjs/lib/shapes/shared/ShapeFill.js +4 -4
  39. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  40. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  41. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +0 -2
  42. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  43. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  44. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  45. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js +10 -1
  46. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +2 -2
  47. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
  48. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
  49. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  50. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  51. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  52. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  53. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  54. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  55. package/dist-cjs/lib/ui/TldrawUi.js +27 -12
  56. package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
  57. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  58. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  59. package/dist-cjs/lib/ui/components/AccessibilityMenu.js +35 -0
  60. package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +7 -0
  61. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +12 -3
  62. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  63. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  64. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  65. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
  66. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
  67. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  68. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  69. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +3 -3
  70. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
  71. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  72. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  73. package/dist-cjs/lib/ui/components/MobileStylePanel.js +5 -3
  74. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +1 -1
  76. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +2 -1
  78. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
  80. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
  82. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +11 -4
  84. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +249 -279
  86. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/{primitives/TldrawUiButtonPicker.js → StylePanel/StylePanelButtonPicker.js} +52 -56
  88. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  89. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  90. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  91. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +26 -25
  92. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  93. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +47 -43
  94. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  95. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  96. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  97. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +3 -2
  98. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  99. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +39 -10
  100. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  101. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -21
  102. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
  103. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  104. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  105. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +3 -3
  106. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  107. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +189 -80
  108. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
  109. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +5 -4
  110. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  111. package/dist-cjs/lib/ui/components/menu-items.js +6 -0
  112. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  113. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +10 -1
  114. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  115. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
  116. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
  117. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  118. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  119. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +32 -7
  120. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  121. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +294 -0
  122. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
  123. package/dist-cjs/lib/ui/components/primitives/layout.js +76 -0
  124. package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
  125. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  126. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
  127. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  128. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +17 -31
  129. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  130. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js +3 -2
  131. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js.map +2 -2
  132. package/dist-cjs/lib/ui/context/actions.js +38 -10
  133. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  134. package/dist-cjs/lib/ui/context/components.js +2 -0
  135. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  136. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  137. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  138. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  139. package/dist-cjs/lib/ui/hooks/useTools.js +22 -4
  140. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  141. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  142. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -1
  143. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  144. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  145. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  146. package/dist-cjs/lib/ui/version.js +3 -3
  147. package/dist-cjs/lib/ui/version.js.map +1 -1
  148. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  149. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  150. package/dist-cjs/lib/utils/export/export.js +0 -20
  151. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  152. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  153. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  154. package/dist-esm/index.d.mts +323 -106
  155. package/dist-esm/index.mjs +83 -29
  156. package/dist-esm/index.mjs.map +2 -2
  157. package/dist-esm/lib/Tldraw.mjs +14 -4
  158. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  159. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  160. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  161. package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -4
  162. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  163. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +4 -3
  164. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  165. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  166. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  167. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  168. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  169. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
  170. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  171. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  172. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  173. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +21 -13
  174. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  175. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  176. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  177. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +4 -2
  178. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  179. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
  180. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
  181. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
  182. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  183. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +6 -3
  184. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  185. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +6 -1
  186. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  187. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +7 -5
  188. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  189. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  190. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  191. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +5 -4
  192. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  193. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  194. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +0 -2
  195. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  196. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  197. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  198. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +10 -1
  199. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +2 -2
  200. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
  201. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
  202. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  203. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  204. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  205. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  206. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  207. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  208. package/dist-esm/lib/ui/TldrawUi.mjs +29 -14
  209. package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
  210. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  211. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  212. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +19 -0
  213. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +7 -0
  214. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +12 -3
  215. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  216. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  217. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  218. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
  219. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
  220. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  221. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  222. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +3 -5
  223. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
  224. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  225. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  226. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +6 -3
  227. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  228. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
  229. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
  230. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -1
  231. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  232. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
  233. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
  234. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
  235. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs.map +2 -2
  236. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +16 -5
  237. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  238. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +251 -283
  239. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  240. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +126 -0
  241. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  242. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  243. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  244. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +23 -22
  245. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  246. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +44 -40
  247. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  248. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  249. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  250. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +3 -2
  251. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  252. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +39 -10
  253. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  254. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -21
  255. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
  256. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  257. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  258. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +3 -3
  259. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  260. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -81
  261. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
  262. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +5 -4
  263. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  264. package/dist-esm/lib/ui/components/menu-items.mjs +6 -0
  265. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  266. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +10 -1
  267. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  268. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
  269. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
  270. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  271. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  272. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +32 -7
  273. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  274. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +272 -0
  275. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
  276. package/dist-esm/lib/ui/components/primitives/layout.mjs +46 -0
  277. package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
  278. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  279. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
  280. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  281. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +17 -31
  282. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  283. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs +3 -2
  284. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs.map +2 -2
  285. package/dist-esm/lib/ui/context/actions.mjs +38 -10
  286. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  287. package/dist-esm/lib/ui/context/components.mjs +2 -0
  288. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  289. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  290. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  291. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  292. package/dist-esm/lib/ui/hooks/useTools.mjs +23 -4
  293. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  294. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -1
  295. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  296. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  297. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  298. package/dist-esm/lib/ui/version.mjs +3 -3
  299. package/dist-esm/lib/ui/version.mjs.map +1 -1
  300. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  301. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  302. package/dist-esm/lib/utils/export/export.mjs +0 -20
  303. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  304. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  305. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  306. package/package.json +11 -34
  307. package/src/index.ts +62 -22
  308. package/src/lib/Tldraw.tsx +15 -2
  309. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  310. package/src/lib/defaultExternalContentHandlers.ts +12 -4
  311. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  312. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +4 -3
  313. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  314. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +4 -3
  315. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  316. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  317. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  318. package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
  319. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  320. package/src/lib/shapes/frame/FrameShapeUtil.tsx +30 -14
  321. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  322. package/src/lib/shapes/geo/GeoShapeUtil.tsx +4 -2
  323. package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
  324. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
  325. package/src/lib/shapes/image/ImageShapeUtil.tsx +6 -3
  326. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  327. package/src/lib/shapes/line/LineShapeUtil.tsx +6 -1
  328. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  329. package/src/lib/shapes/note/NoteShapeUtil.tsx +10 -4
  330. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  331. package/src/lib/shapes/shared/ShapeFill.tsx +5 -4
  332. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  333. package/src/lib/shapes/shared/useEditablePlainText.ts +0 -6
  334. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  335. package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
  336. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  337. package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
  338. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  339. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  340. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  341. package/src/lib/ui/TldrawUi.tsx +33 -12
  342. package/src/lib/ui/assetUrls.ts +13 -10
  343. package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
  344. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +15 -3
  345. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  346. package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
  347. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  348. package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
  349. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  350. package/src/lib/ui/components/MobileStylePanel.tsx +9 -6
  351. package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
  352. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +3 -2
  353. package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
  354. package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
  355. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +28 -12
  356. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +261 -343
  357. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +66 -50
  358. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  359. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +31 -22
  360. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  361. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  362. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +4 -3
  363. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +33 -16
  364. package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -23
  365. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  366. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +5 -5
  367. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +212 -61
  368. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +14 -11
  369. package/src/lib/ui/components/menu-items.tsx +8 -0
  370. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +6 -1
  371. package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
  372. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  373. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +54 -12
  374. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +365 -0
  375. package/src/lib/ui/components/primitives/layout.tsx +107 -0
  376. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  377. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
  378. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +24 -33
  379. package/src/lib/ui/context/TldrawUiContextProvider.tsx +23 -20
  380. package/src/lib/ui/context/actions.tsx +38 -10
  381. package/src/lib/ui/context/components.tsx +3 -0
  382. package/src/lib/ui/context/events.tsx +2 -1
  383. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  384. package/src/lib/ui/hooks/useTools.tsx +26 -4
  385. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +5 -0
  386. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -1
  387. package/src/lib/ui/kbd-utils.ts +10 -3
  388. package/src/lib/ui/version.ts +3 -3
  389. package/src/lib/ui.css +424 -293
  390. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  391. package/src/lib/utils/export/copyAs.ts +1 -24
  392. package/src/lib/utils/export/export.ts +0 -36
  393. package/src/lib/utils/export/exportAs.ts +1 -32
  394. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  395. package/src/test/A11y.test.tsx +3 -2
  396. package/src/test/ClickManager.test.ts +7 -6
  397. package/src/test/Editor.test.tsx +20 -19
  398. package/src/test/EraserTool.test.ts +184 -13
  399. package/src/test/HandTool.test.ts +10 -9
  400. package/src/test/HighlightShape.test.ts +2 -1
  401. package/src/test/SelectTool.test.ts +3 -2
  402. package/src/test/TLUserPreferences.test.ts +4 -3
  403. package/src/test/TestEditor.ts +13 -15
  404. package/src/test/TldrawEditor.test.tsx +11 -10
  405. package/src/test/ZoomTool.test.ts +7 -6
  406. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  407. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  408. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  409. package/src/test/arrows-megabus.test.tsx +5 -4
  410. package/src/test/bindings.test.tsx +24 -37
  411. package/src/test/bookmark-shapes.test.ts +1 -8
  412. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  413. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  414. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  415. package/src/test/commands/alignShapes.test.tsx +25 -24
  416. package/src/test/commands/animationSpeed.test.ts +2 -1
  417. package/src/test/commands/centerOnPoint.test.ts +3 -2
  418. package/src/test/commands/clipboard.test.ts +3 -2
  419. package/src/test/commands/createShapes.test.ts +2 -1
  420. package/src/test/commands/deleteShapes.test.ts +2 -1
  421. package/src/test/commands/distributeShapes.test.tsx +11 -10
  422. package/src/test/commands/getSvgString.test.ts +2 -1
  423. package/src/test/commands/packShapes.test.ts +5 -4
  424. package/src/test/commands/resizeShape.test.ts +2 -1
  425. package/src/test/commands/rotateShapes.test.ts +7 -6
  426. package/src/test/commands/setCamera.test.ts +4 -3
  427. package/src/test/commands/setCurrentPage.test.ts +3 -2
  428. package/src/test/commands/stackShapes.test.ts +11 -10
  429. package/src/test/commands/stretch.test.tsx +13 -12
  430. package/src/test/createDeepLink.test.tsx +2 -1
  431. package/src/test/cropping.test.ts +3 -2
  432. package/src/test/custom-clipping.test.ts +436 -0
  433. package/src/test/drawing.test.ts +2 -1
  434. package/src/test/flipShapes.test.ts +4 -3
  435. package/src/test/frames.test.ts +25 -24
  436. package/src/test/getCulledShapes.test.tsx +74 -4
  437. package/src/test/groups.test.tsx +1 -1
  438. package/src/test/handleDeepLink.test.tsx +2 -1
  439. package/src/test/maxShapes.test.ts +3 -2
  440. package/src/test/modifiers.test.ts +5 -4
  441. package/src/test/navigation.test.ts +12 -11
  442. package/src/test/panning.test.ts +2 -1
  443. package/src/test/perf/perf.test.ts +2 -1
  444. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  445. package/src/test/resizing.test.ts +39 -38
  446. package/src/test/select.test.tsx +4 -3
  447. package/src/test/selection-omnibus.test.ts +11 -10
  448. package/src/test/shapeutils.test.ts +4 -3
  449. package/src/test/translating.test.ts +9 -8
  450. package/tldraw.css +732 -583
  451. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  452. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  453. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  454. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  455. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  456. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  457. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  458. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  459. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  460. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -109
@@ -1,7 +1,9 @@
1
+ import { tltime } from '@tldraw/editor'
1
2
  import { Slider as _Slider } from 'radix-ui'
2
3
  import React, { useCallback, useEffect, useState } from 'react'
3
4
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
4
5
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
6
+ import { TldrawUiTooltip, tooltipManager } from './TldrawUiTooltip'
5
7
 
6
8
  /** @public */
7
9
  export interface TLUiSliderProps {
@@ -11,7 +13,7 @@ export interface TLUiSliderProps {
11
13
  label: string
12
14
  title: string
13
15
  onValueChange(value: number): void
14
- onHistoryMark(id: string): void
16
+ onHistoryMark?(id: string): void
15
17
  'data-testid'?: string
16
18
  ariaValueModifier?: number
17
19
  }
@@ -32,6 +34,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
32
34
  ref
33
35
  ) {
34
36
  const msg = useTranslation()
37
+ const [titleAndLabel, setTitleAndLabel] = useState('')
35
38
 
36
39
  // XXX: Radix starts out our slider with a tabIndex of 0
37
40
  // This causes some tab focusing issues, most prevelant in MobileStylePanel,
@@ -49,9 +52,25 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
49
52
  )
50
53
 
51
54
  const handlePointerDown = useCallback(() => {
52
- onHistoryMark('click slider')
55
+ tooltipManager.hideAllTooltips()
56
+ onHistoryMark?.('click slider')
53
57
  }, [onHistoryMark])
54
58
 
59
+ // N.B. This is a bit silly. The Radix slider auto-focuses which
60
+ // triggers TldrawUiTooltip handleFocus when we dbl-click to edit an image,
61
+ // which in turn makes the tooltip display prematurely.
62
+ // This makes it wait until we've focused to show the tooltip.
63
+ useEffect(() => {
64
+ const timeout = tltime.setTimeout(
65
+ 'set title and label',
66
+ () => {
67
+ setTitleAndLabel(title + ' — ' + msg(label as TLUiTranslationKey))
68
+ },
69
+ 0
70
+ )
71
+ return () => clearTimeout(timeout)
72
+ }, [label, msg, title])
73
+
55
74
  // N.B. Annoying. For a11y purposes, we need Tab to work.
56
75
  // For some reason, Radix has some custom behavior here
57
76
  // that interferes with tabbing past the slider and then
@@ -64,36 +83,37 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
64
83
 
65
84
  return (
66
85
  <div className="tlui-slider__container">
67
- <_Slider.Root
68
- data-testid={testId}
69
- className="tlui-slider"
70
- dir="ltr"
71
- min={min ?? 0}
72
- max={steps}
73
- step={1}
74
- value={value !== null ? [value] : undefined}
75
- onPointerDown={handlePointerDown}
76
- onValueChange={handleValueChange}
77
- onKeyDownCapture={handleKeyEvent}
78
- onKeyUpCapture={handleKeyEvent}
79
- title={title + ' — ' + msg(label as TLUiTranslationKey)}
80
- >
81
- <_Slider.Track className="tlui-slider__track" dir="ltr">
82
- {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
83
- </_Slider.Track>
84
- {value !== null && (
85
- <_Slider.Thumb
86
- aria-valuemin={(min ?? 0) * ariaValueModifier}
87
- aria-valuenow={value * ariaValueModifier}
88
- aria-valuemax={steps * ariaValueModifier}
89
- aria-label={title + ' — ' + msg(label as TLUiTranslationKey)}
90
- className="tlui-slider__thumb"
91
- dir="ltr"
92
- ref={ref}
93
- tabIndex={tabIndex}
94
- />
95
- )}
96
- </_Slider.Root>
86
+ <TldrawUiTooltip content={titleAndLabel}>
87
+ <_Slider.Root
88
+ data-testid={testId}
89
+ className="tlui-slider"
90
+ dir="ltr"
91
+ min={min ?? 0}
92
+ max={steps}
93
+ step={1}
94
+ value={value !== null ? [value] : undefined}
95
+ onPointerDown={handlePointerDown}
96
+ onValueChange={handleValueChange}
97
+ onKeyDownCapture={handleKeyEvent}
98
+ onKeyUpCapture={handleKeyEvent}
99
+ >
100
+ <_Slider.Track className="tlui-slider__track" dir="ltr">
101
+ {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
102
+ </_Slider.Track>
103
+ {value !== null && (
104
+ <_Slider.Thumb
105
+ aria-valuemin={(min ?? 0) * ariaValueModifier}
106
+ aria-valuenow={value * ariaValueModifier}
107
+ aria-valuemax={steps * ariaValueModifier}
108
+ aria-label={titleAndLabel}
109
+ className="tlui-slider__thumb"
110
+ dir="ltr"
111
+ ref={ref}
112
+ tabIndex={tabIndex}
113
+ />
114
+ )}
115
+ </_Slider.Root>
116
+ </TldrawUiTooltip>
97
117
  </div>
98
118
  )
99
119
  })
@@ -1,6 +1,8 @@
1
1
  import classnames from 'classnames'
2
2
  import { Toolbar as _Toolbar } from 'radix-ui'
3
3
  import React from 'react'
4
+ import { TldrawUiColumn, TldrawUiGrid, TldrawUiRow } from './layout'
5
+ import { TldrawUiTooltip } from './TldrawUiTooltip'
4
6
 
5
7
  /** @public */
6
8
  export interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
@@ -8,20 +10,42 @@ export interface TLUiToolbarProps extends React.HTMLAttributes<HTMLDivElement> {
8
10
  className?: string
9
11
  dir?: 'ltr' | 'rtl'
10
12
  label: string
13
+ orientation?: 'horizontal' | 'vertical' | 'grid'
14
+ tooltipSide?: 'top' | 'right' | 'bottom' | 'left'
15
+ }
16
+
17
+ const LayoutByOrientation = {
18
+ horizontal: TldrawUiRow,
19
+ vertical: TldrawUiColumn,
20
+ grid: TldrawUiGrid,
11
21
  }
12
22
 
13
23
  /** @public @react */
14
24
  export const TldrawUiToolbar = React.forwardRef<HTMLDivElement, TLUiToolbarProps>(
15
- ({ children, className, label, ...props }: TLUiToolbarProps, ref) => {
25
+ (
26
+ {
27
+ children,
28
+ className,
29
+ label,
30
+ orientation = 'horizontal',
31
+ tooltipSide,
32
+ ...props
33
+ }: TLUiToolbarProps,
34
+ ref
35
+ ) => {
36
+ const Layout = LayoutByOrientation[orientation]
16
37
  return (
17
- <_Toolbar.Root
18
- ref={ref}
19
- {...props}
20
- className={classnames('tlui-toolbar-container', className)}
21
- aria-label={label}
22
- >
23
- {children}
24
- </_Toolbar.Root>
38
+ <Layout asChild tooltipSide={tooltipSide}>
39
+ <_Toolbar.Root
40
+ ref={ref}
41
+ {...props}
42
+ className={classnames('tlui-toolbar', className)}
43
+ aria-label={label}
44
+ orientation={orientation === 'grid' ? 'horizontal' : orientation}
45
+ >
46
+ {children}
47
+ </_Toolbar.Root>
48
+ </Layout>
25
49
  )
26
50
  }
27
51
  )
@@ -34,23 +58,30 @@ export interface TLUiToolbarButtonProps extends React.HTMLAttributes<HTMLButtonE
34
58
  disabled?: boolean
35
59
  isActive?: boolean
36
60
  type: 'icon' | 'tool' | 'menu'
61
+ tooltip?: string
37
62
  }
38
63
 
39
64
  /** @public @react */
40
65
  export const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToolbarButtonProps>(
41
- ({ asChild, children, type, isActive, ...props }: TLUiToolbarButtonProps, ref) => {
42
- return (
66
+ ({ asChild, children, type, isActive, tooltip, ...props }: TLUiToolbarButtonProps, ref) => {
67
+ const button = (
43
68
  <_Toolbar.Button
44
69
  ref={ref}
45
70
  asChild={asChild}
46
71
  draggable={false}
47
72
  data-isactive={isActive}
48
73
  {...props}
74
+ // The tooltip takes care of this.
75
+ title={undefined}
49
76
  className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
50
77
  >
51
78
  {children}
52
79
  </_Toolbar.Button>
53
80
  )
81
+
82
+ const tooltipContent = tooltip || props.title
83
+
84
+ return <TldrawUiTooltip content={tooltipContent}>{button}</TldrawUiTooltip>
54
85
  }
55
86
  )
56
87
 
@@ -63,6 +94,7 @@ export interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDi
63
94
  // TODO: fix up this type later
64
95
  defaultValue?: any
65
96
  type: 'single' | 'multiple'
97
+ asChild?: boolean
66
98
  }
67
99
 
68
100
  /** @public @react */
@@ -70,10 +102,12 @@ export const TldrawUiToolbarToggleGroup = ({
70
102
  children,
71
103
  className,
72
104
  type,
105
+ asChild,
73
106
  ...props
74
107
  }: TLUiToolbarToggleGroupProps) => {
75
108
  return (
76
109
  <_Toolbar.ToggleGroup
110
+ asChild={asChild}
77
111
  type={type}
78
112
  {...props}
79
113
  // TODO: this fixes a bug in Radix until they fix it.
@@ -93,6 +127,7 @@ export interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLBut
93
127
  className?: string
94
128
  type: 'icon' | 'tool'
95
129
  value: string
130
+ tooltip?: string
96
131
  }
97
132
 
98
133
  /** @public @react */
@@ -101,11 +136,14 @@ export const TldrawUiToolbarToggleItem = ({
101
136
  className,
102
137
  type,
103
138
  value,
139
+ tooltip,
104
140
  ...props
105
141
  }: TLUiToolbarToggleItemProps) => {
106
- return (
142
+ const toggleItem = (
107
143
  <_Toolbar.ToggleItem
108
144
  {...props}
145
+ // The tooltip takes care of this.
146
+ title={undefined}
109
147
  className={classnames(
110
148
  'tlui-button',
111
149
  `tlui-button__${type}`,
@@ -117,4 +155,8 @@ export const TldrawUiToolbarToggleItem = ({
117
155
  {children}
118
156
  </_Toolbar.ToggleItem>
119
157
  )
158
+
159
+ const tooltipContent = tooltip || props.title
160
+
161
+ return <TldrawUiTooltip content={tooltipContent}>{toggleItem}</TldrawUiTooltip>
120
162
  }
@@ -0,0 +1,365 @@
1
+ import { assert, Atom, atom, Editor, uniqueId, useMaybeEditor, useValue } from '@tldraw/editor'
2
+ import { Tooltip as _Tooltip } from 'radix-ui'
3
+ import React, {
4
+ createContext,
5
+ forwardRef,
6
+ ReactNode,
7
+ useContext,
8
+ useEffect,
9
+ useLayoutEffect,
10
+ useRef,
11
+ useState,
12
+ } from 'react'
13
+ import { useTldrawUiOrientation } from './layout'
14
+
15
+ const DEFAULT_TOOLTIP_DELAY_MS = 700
16
+
17
+ /** @public */
18
+ export interface TldrawUiTooltipProps {
19
+ children: React.ReactNode
20
+ content?: string | React.ReactNode
21
+ side?: 'top' | 'right' | 'bottom' | 'left'
22
+ sideOffset?: number
23
+ disabled?: boolean
24
+ showOnMobile?: boolean
25
+ delayDuration?: number
26
+ }
27
+
28
+ interface CurrentTooltip {
29
+ id: string
30
+ content: ReactNode
31
+ side: 'top' | 'right' | 'bottom' | 'left'
32
+ sideOffset: number
33
+ showOnMobile: boolean
34
+ targetElement: HTMLElement
35
+ delayDuration: number
36
+ }
37
+
38
+ // Singleton tooltip manager
39
+ class TooltipManager {
40
+ private static instance: TooltipManager | null = null
41
+ private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
42
+ private destroyTimeoutId: number | null = null
43
+
44
+ static getInstance(): TooltipManager {
45
+ if (!TooltipManager.instance) {
46
+ TooltipManager.instance = new TooltipManager()
47
+ }
48
+ return TooltipManager.instance
49
+ }
50
+
51
+ showTooltip(
52
+ tooltipId: string,
53
+ content: string | React.ReactNode,
54
+ targetElement: HTMLElement,
55
+ side: 'top' | 'right' | 'bottom' | 'left',
56
+ sideOffset: number,
57
+ showOnMobile: boolean,
58
+ delayDuration: number
59
+ ) {
60
+ // Clear any existing destroy timeout
61
+ if (this.destroyTimeoutId) {
62
+ clearTimeout(this.destroyTimeoutId)
63
+ this.destroyTimeoutId = null
64
+ }
65
+
66
+ // Update current tooltip
67
+ this.currentTooltip.set({
68
+ id: tooltipId,
69
+ content,
70
+ side,
71
+ sideOffset,
72
+ showOnMobile,
73
+ targetElement,
74
+ delayDuration,
75
+ })
76
+ }
77
+
78
+ updateCurrentTooltip(tooltipId: string, update: (tooltip: CurrentTooltip) => CurrentTooltip) {
79
+ this.currentTooltip.update((tooltip) => {
80
+ if (tooltip?.id === tooltipId) {
81
+ return update(tooltip)
82
+ }
83
+ return tooltip
84
+ })
85
+ }
86
+
87
+ hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
88
+ const hide = () => {
89
+ // Only hide if this is the current tooltip
90
+ if (this.currentTooltip.get()?.id === tooltipId) {
91
+ this.currentTooltip.set(null)
92
+ this.destroyTimeoutId = null
93
+ }
94
+ }
95
+
96
+ if (editor && !instant) {
97
+ // Start destroy timeout (1 second)
98
+ this.destroyTimeoutId = editor.timers.setTimeout(hide, 300)
99
+ } else {
100
+ hide()
101
+ }
102
+ }
103
+
104
+ hideAllTooltips() {
105
+ this.currentTooltip.set(null)
106
+ this.destroyTimeoutId = null
107
+ }
108
+
109
+ getCurrentTooltipData() {
110
+ const currentTooltip = this.currentTooltip.get()
111
+ if (!currentTooltip) return null
112
+ if (!this.supportsHover() && !currentTooltip.showOnMobile) return null
113
+ return currentTooltip
114
+ }
115
+
116
+ private supportsHoverAtom: Atom<boolean> | null = null
117
+ supportsHover() {
118
+ if (!this.supportsHoverAtom) {
119
+ const mediaQuery = window.matchMedia('(hover: hover)')
120
+ const supportsHover = atom('has hover', mediaQuery.matches)
121
+ this.supportsHoverAtom = supportsHover
122
+ mediaQuery.addEventListener('change', (e) => {
123
+ supportsHover.set(e.matches)
124
+ })
125
+ }
126
+ return this.supportsHoverAtom.get()
127
+ }
128
+ }
129
+
130
+ export const tooltipManager = TooltipManager.getInstance()
131
+
132
+ // Context for the tooltip singleton
133
+ const TooltipSingletonContext = createContext<boolean>(false)
134
+
135
+ /** @public */
136
+ export interface TldrawUiTooltipProviderProps {
137
+ children: React.ReactNode
138
+ }
139
+
140
+ /** @public @react */
141
+ export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderProps) {
142
+ return (
143
+ <_Tooltip.Provider skipDelayDuration={700}>
144
+ <TooltipSingletonContext.Provider value={true}>
145
+ {children}
146
+ <TooltipSingleton />
147
+ </TooltipSingletonContext.Provider>
148
+ </_Tooltip.Provider>
149
+ )
150
+ }
151
+
152
+ // The singleton tooltip component that renders once
153
+ function TooltipSingleton() {
154
+ const [isOpen, setIsOpen] = useState(false)
155
+ const triggerRef = useRef<HTMLDivElement>(null)
156
+ const isFirstShowRef = useRef(true)
157
+ const editor = useMaybeEditor()
158
+
159
+ const currentTooltip = useValue(
160
+ 'current tooltip',
161
+ () => tooltipManager.getCurrentTooltipData(),
162
+ []
163
+ )
164
+
165
+ const cameraState = useValue('camera state', () => editor?.getCameraState(), [editor])
166
+
167
+ // Hide tooltip when camera is moving (panning/zooming)
168
+ useEffect(() => {
169
+ if (cameraState === 'moving' && isOpen && currentTooltip) {
170
+ tooltipManager.hideTooltip(editor, currentTooltip.id, true)
171
+ }
172
+ }, [cameraState, isOpen, currentTooltip, editor])
173
+
174
+ // Update open state and trigger position
175
+ useEffect(() => {
176
+ let timer: ReturnType<typeof setTimeout> | null = null
177
+ if (currentTooltip && triggerRef.current) {
178
+ // Position the invisible trigger element over the active element
179
+ const activeRect = currentTooltip.targetElement.getBoundingClientRect()
180
+ const trigger = triggerRef.current
181
+
182
+ trigger.style.position = 'fixed'
183
+ trigger.style.left = `${activeRect.left}px`
184
+ trigger.style.top = `${activeRect.top}px`
185
+ trigger.style.width = `${activeRect.width}px`
186
+ trigger.style.height = `${activeRect.height}px`
187
+ trigger.style.pointerEvents = 'none'
188
+ trigger.style.zIndex = '9999'
189
+
190
+ // Handle delay for first show
191
+ if (isFirstShowRef.current) {
192
+ // eslint-disable-next-line no-restricted-globals
193
+ timer = setTimeout(() => {
194
+ setIsOpen(true)
195
+ isFirstShowRef.current = false
196
+ }, currentTooltip.delayDuration)
197
+ } else {
198
+ // Subsequent tooltips show immediately
199
+ setIsOpen(true)
200
+ }
201
+ } else {
202
+ // Hide tooltip immediately
203
+ setIsOpen(false)
204
+ // Reset first show state after tooltip is hidden
205
+ isFirstShowRef.current = true
206
+ }
207
+
208
+ return () => {
209
+ if (timer !== null) {
210
+ clearTimeout(timer)
211
+ }
212
+ }
213
+ }, [currentTooltip])
214
+
215
+ if (!currentTooltip) {
216
+ return null
217
+ }
218
+
219
+ return (
220
+ <_Tooltip.Root open={isOpen} delayDuration={0}>
221
+ <_Tooltip.Trigger asChild>
222
+ <div ref={triggerRef} />
223
+ </_Tooltip.Trigger>
224
+ <_Tooltip.Content
225
+ className="tlui-tooltip"
226
+ side={currentTooltip.side}
227
+ sideOffset={currentTooltip.sideOffset}
228
+ avoidCollisions
229
+ collisionPadding={8}
230
+ dir="ltr"
231
+ >
232
+ {currentTooltip.content}
233
+ <_Tooltip.Arrow className="tlui-tooltip__arrow" />
234
+ </_Tooltip.Content>
235
+ </_Tooltip.Root>
236
+ )
237
+ }
238
+
239
+ /** @public @react */
240
+ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(
241
+ (
242
+ {
243
+ children,
244
+ content,
245
+ side,
246
+ sideOffset = 5,
247
+ disabled = false,
248
+ showOnMobile = false,
249
+ delayDuration,
250
+ },
251
+ ref
252
+ ) => {
253
+ const editor = useMaybeEditor()
254
+ const tooltipId = useRef<string>(uniqueId())
255
+ const hasProvider = useContext(TooltipSingletonContext)
256
+ const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
257
+
258
+ const orientationCtx = useTldrawUiOrientation()
259
+ const sideToUse = side ?? orientationCtx.tooltipSide
260
+
261
+ useEffect(() => {
262
+ const currentTooltipId = tooltipId.current
263
+ return () => {
264
+ if (hasProvider) {
265
+ tooltipManager.hideTooltip(editor, currentTooltipId, true)
266
+ }
267
+ }
268
+ }, [editor, hasProvider])
269
+
270
+ useLayoutEffect(() => {
271
+ if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
272
+ tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
273
+ ...tooltip,
274
+ content,
275
+ side: sideToUse,
276
+ sideOffset,
277
+ showOnMobile,
278
+ }))
279
+ }
280
+ }, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
281
+
282
+ // Don't show tooltip if disabled, no content, or UI labels are disabled
283
+ if (disabled || !content) {
284
+ return <>{children}</>
285
+ }
286
+
287
+ let delayDurationToUse
288
+ if (showUiLabels) {
289
+ delayDurationToUse = 0
290
+ } else {
291
+ delayDurationToUse =
292
+ delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
293
+ }
294
+
295
+ // Fallback to old behavior if no provider
296
+ if (!hasProvider) {
297
+ return (
298
+ <_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent>
299
+ <_Tooltip.Trigger asChild ref={ref}>
300
+ {children}
301
+ </_Tooltip.Trigger>
302
+ <_Tooltip.Content
303
+ className="tlui-tooltip"
304
+ side={sideToUse}
305
+ sideOffset={sideOffset}
306
+ avoidCollisions
307
+ collisionPadding={8}
308
+ dir="ltr"
309
+ >
310
+ {content}
311
+ <_Tooltip.Arrow className="tlui-tooltip__arrow" />
312
+ </_Tooltip.Content>
313
+ </_Tooltip.Root>
314
+ )
315
+ }
316
+
317
+ const child = React.Children.only(children)
318
+ assert(React.isValidElement(child), 'TldrawUiTooltip children must be a single element')
319
+
320
+ const handleMouseEnter = (event: React.MouseEvent<HTMLElement>) => {
321
+ child.props.onMouseEnter?.(event)
322
+ tooltipManager.showTooltip(
323
+ tooltipId.current,
324
+ content,
325
+ event.currentTarget as HTMLElement,
326
+ sideToUse,
327
+ sideOffset,
328
+ showOnMobile,
329
+ delayDurationToUse
330
+ )
331
+ }
332
+
333
+ const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
334
+ child.props.onMouseLeave?.(event)
335
+ tooltipManager.hideTooltip(editor, tooltipId.current)
336
+ }
337
+
338
+ const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
339
+ child.props.onFocus?.(event)
340
+ tooltipManager.showTooltip(
341
+ tooltipId.current,
342
+ content,
343
+ event.currentTarget as HTMLElement,
344
+ sideToUse,
345
+ sideOffset,
346
+ showOnMobile,
347
+ delayDurationToUse
348
+ )
349
+ }
350
+
351
+ const handleBlur = (event: React.FocusEvent<HTMLElement>) => {
352
+ child.props.onBlur?.(event)
353
+ tooltipManager.hideTooltip(editor, tooltipId.current)
354
+ }
355
+
356
+ const childrenWithHandlers = React.cloneElement(children as React.ReactElement, {
357
+ onMouseEnter: handleMouseEnter,
358
+ onMouseLeave: handleMouseLeave,
359
+ onFocus: handleFocus,
360
+ onBlur: handleBlur,
361
+ })
362
+
363
+ return childrenWithHandlers
364
+ }
365
+ )