tldraw 3.16.0-canary.56eb315c11ae → 3.16.0-canary.5f82fb812214

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