tldraw 3.16.0-canary.a962044c3d3b → 3.16.0-canary.aaf20c977c01

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