tldraw 3.16.0-canary.7f4043b128a3 → 3.16.0-canary.887377ec7acc

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 (349) hide show
  1. package/dist-cjs/index.d.ts +228 -104
  2. package/dist-cjs/index.js +33 -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/arrowLabel.js +6 -0
  11. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  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/embed/EmbedShapeUtil.js +1 -1
  15. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
  16. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +12 -5
  17. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
  19. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
  20. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  21. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  22. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +6 -3
  23. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  24. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  25. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  26. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  27. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  28. package/dist-cjs/lib/shapes/shared/ShapeFill.js +1 -1
  29. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  30. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  31. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +0 -2
  32. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  33. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  34. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  35. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  36. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  37. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  38. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  39. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  40. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  41. package/dist-cjs/lib/ui/TldrawUi.js +13 -12
  42. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  43. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  44. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  45. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  46. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  47. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  48. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  49. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  50. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  51. package/dist-cjs/lib/ui/components/MobileStylePanel.js +1 -1
  52. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  53. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  54. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  55. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  56. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  57. package/dist-cjs/lib/ui/components/{primitives/TldrawUiButtonPicker.js → StylePanel/StylePanelButtonPicker.js} +52 -45
  58. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  59. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  60. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  61. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  62. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  63. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +24 -21
  64. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  65. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  66. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  67. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +3 -2
  68. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  69. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +39 -10
  70. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  71. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  72. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  73. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +3 -3
  74. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +10 -1
  76. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  78. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +2 -0
  80. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +125 -122
  82. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  84. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +0 -10
  85. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  86. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +8 -24
  87. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  88. package/dist-cjs/lib/ui/context/actions.js +23 -10
  89. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  90. package/dist-cjs/lib/ui/context/components.js +2 -0
  91. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  92. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  93. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  94. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  95. package/dist-cjs/lib/ui/hooks/useTools.js +22 -4
  96. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  97. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  98. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +4 -2
  99. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  100. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  101. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  102. package/dist-cjs/lib/ui/version.js +3 -3
  103. package/dist-cjs/lib/ui/version.js.map +1 -1
  104. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  105. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  106. package/dist-cjs/lib/utils/export/export.js +0 -20
  107. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  108. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  109. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  110. package/dist-esm/index.d.mts +228 -104
  111. package/dist-esm/index.mjs +61 -29
  112. package/dist-esm/index.mjs.map +2 -2
  113. package/dist-esm/lib/Tldraw.mjs +14 -4
  114. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  115. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  116. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  117. package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -4
  118. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  119. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  120. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  121. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  122. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  123. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  124. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  125. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +12 -5
  126. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  127. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  128. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  129. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  130. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  131. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +6 -3
  132. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  133. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  134. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  135. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  136. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  137. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +1 -1
  138. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  139. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  140. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +0 -2
  141. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  142. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  143. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  144. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  145. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  146. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  147. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  148. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  149. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  150. package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
  151. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  152. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  153. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  154. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  155. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  156. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  157. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  158. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  159. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  160. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +1 -1
  161. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  162. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  163. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  164. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  165. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  166. package/dist-esm/lib/ui/components/{primitives/TldrawUiButtonPicker.mjs → StylePanel/StylePanelButtonPicker.mjs} +54 -43
  167. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  168. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  169. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  170. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  171. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  172. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +21 -18
  173. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  174. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  175. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  176. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +3 -2
  177. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  178. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +39 -10
  179. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  180. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  181. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  182. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +3 -3
  183. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  184. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +10 -1
  185. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  186. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  187. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  188. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +2 -0
  189. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  190. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +135 -124
  191. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  192. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  193. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +0 -10
  194. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  195. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +8 -24
  196. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  197. package/dist-esm/lib/ui/context/actions.mjs +23 -10
  198. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  199. package/dist-esm/lib/ui/context/components.mjs +2 -0
  200. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  201. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  202. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  203. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  204. package/dist-esm/lib/ui/hooks/useTools.mjs +23 -4
  205. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  206. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +4 -2
  207. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  208. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  209. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  210. package/dist-esm/lib/ui/version.mjs +3 -3
  211. package/dist-esm/lib/ui/version.mjs.map +1 -1
  212. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  213. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  214. package/dist-esm/lib/utils/export/export.mjs +0 -20
  215. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  216. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  217. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  218. package/package.json +11 -34
  219. package/src/index.ts +44 -22
  220. package/src/lib/Tldraw.tsx +15 -2
  221. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  222. package/src/lib/defaultExternalContentHandlers.ts +12 -4
  223. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  224. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +6 -5
  225. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  226. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  227. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  228. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  229. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  230. package/src/lib/shapes/frame/FrameShapeUtil.tsx +21 -4
  231. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  232. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  233. package/src/lib/shapes/image/ImageShapeUtil.tsx +6 -3
  234. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  235. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  236. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  237. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  238. package/src/lib/shapes/shared/ShapeFill.tsx +1 -1
  239. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  240. package/src/lib/shapes/shared/useEditablePlainText.ts +0 -6
  241. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  242. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  243. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  244. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  245. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  246. package/src/lib/ui/TldrawUi.tsx +16 -10
  247. package/src/lib/ui/assetUrls.ts +13 -10
  248. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  249. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  250. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  251. package/src/lib/ui/components/MobileStylePanel.tsx +1 -1
  252. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  253. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  254. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +63 -50
  255. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  256. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  257. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  258. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  259. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +4 -3
  260. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +33 -16
  261. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  262. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +5 -5
  263. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +6 -1
  264. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  265. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +3 -0
  266. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +146 -124
  267. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  268. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +0 -10
  269. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +11 -24
  270. package/src/lib/ui/context/actions.tsx +23 -10
  271. package/src/lib/ui/context/components.tsx +3 -0
  272. package/src/lib/ui/context/events.tsx +1 -1
  273. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  274. package/src/lib/ui/hooks/useTools.tsx +26 -4
  275. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
  276. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +4 -2
  277. package/src/lib/ui/kbd-utils.ts +10 -3
  278. package/src/lib/ui/version.ts +3 -3
  279. package/src/lib/ui.css +246 -230
  280. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  281. package/src/lib/utils/export/copyAs.ts +1 -24
  282. package/src/lib/utils/export/export.ts +0 -36
  283. package/src/lib/utils/export/exportAs.ts +1 -32
  284. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  285. package/src/test/A11y.test.tsx +3 -2
  286. package/src/test/ClickManager.test.ts +7 -6
  287. package/src/test/Editor.test.tsx +20 -19
  288. package/src/test/EraserTool.test.ts +184 -13
  289. package/src/test/HandTool.test.ts +10 -9
  290. package/src/test/HighlightShape.test.ts +2 -1
  291. package/src/test/SelectTool.test.ts +3 -2
  292. package/src/test/TLUserPreferences.test.ts +4 -3
  293. package/src/test/TestEditor.ts +13 -15
  294. package/src/test/TldrawEditor.test.tsx +11 -10
  295. package/src/test/ZoomTool.test.ts +7 -6
  296. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  297. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  298. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  299. package/src/test/arrows-megabus.test.tsx +5 -4
  300. package/src/test/bindings.test.tsx +24 -37
  301. package/src/test/bookmark-shapes.test.ts +1 -8
  302. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  303. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  304. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  305. package/src/test/commands/alignShapes.test.tsx +25 -24
  306. package/src/test/commands/animationSpeed.test.ts +2 -1
  307. package/src/test/commands/centerOnPoint.test.ts +3 -2
  308. package/src/test/commands/clipboard.test.ts +3 -2
  309. package/src/test/commands/createShapes.test.ts +2 -1
  310. package/src/test/commands/deleteShapes.test.ts +2 -1
  311. package/src/test/commands/distributeShapes.test.tsx +11 -10
  312. package/src/test/commands/getSvgString.test.ts +2 -1
  313. package/src/test/commands/packShapes.test.ts +5 -4
  314. package/src/test/commands/resizeShape.test.ts +2 -1
  315. package/src/test/commands/rotateShapes.test.ts +7 -6
  316. package/src/test/commands/setCamera.test.ts +4 -3
  317. package/src/test/commands/setCurrentPage.test.ts +3 -2
  318. package/src/test/commands/stackShapes.test.ts +11 -10
  319. package/src/test/commands/stretch.test.tsx +13 -12
  320. package/src/test/createDeepLink.test.tsx +2 -1
  321. package/src/test/cropping.test.ts +3 -2
  322. package/src/test/custom-clipping.test.ts +436 -0
  323. package/src/test/drawing.test.ts +2 -1
  324. package/src/test/flipShapes.test.ts +4 -3
  325. package/src/test/frames.test.ts +25 -24
  326. package/src/test/getCulledShapes.test.tsx +74 -4
  327. package/src/test/groups.test.tsx +1 -1
  328. package/src/test/handleDeepLink.test.tsx +2 -1
  329. package/src/test/maxShapes.test.ts +3 -2
  330. package/src/test/modifiers.test.ts +5 -4
  331. package/src/test/navigation.test.ts +12 -11
  332. package/src/test/panning.test.ts +2 -1
  333. package/src/test/perf/perf.test.ts +2 -1
  334. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  335. package/src/test/resizing.test.ts +39 -38
  336. package/src/test/select.test.tsx +4 -3
  337. package/src/test/selection-omnibus.test.ts +11 -10
  338. package/src/test/shapeutils.test.ts +4 -3
  339. package/src/test/translating.test.ts +9 -8
  340. package/tldraw.css +554 -522
  341. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  342. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  343. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  344. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  345. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  346. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  347. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  348. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  349. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -1,7 +1,9 @@
1
+ import { tltime } from '@tldraw/editor'
1
2
  import { Slider as _Slider } from 'radix-ui'
2
3
  import React, { useCallback, useEffect, useState } from 'react'
3
4
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
4
5
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
6
+ import { TldrawUiTooltip, tooltipManager } from './TldrawUiTooltip'
5
7
 
6
8
  /** @public */
7
9
  export interface TLUiSliderProps {
@@ -11,7 +13,7 @@ export interface TLUiSliderProps {
11
13
  label: string
12
14
  title: string
13
15
  onValueChange(value: number): void
14
- onHistoryMark(id: string): void
16
+ onHistoryMark?(id: string): void
15
17
  'data-testid'?: string
16
18
  ariaValueModifier?: number
17
19
  }
@@ -32,6 +34,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
32
34
  ref
33
35
  ) {
34
36
  const msg = useTranslation()
37
+ const [titleAndLabel, setTitleAndLabel] = useState('')
35
38
 
36
39
  // XXX: Radix starts out our slider with a tabIndex of 0
37
40
  // This causes some tab focusing issues, most prevelant in MobileStylePanel,
@@ -49,9 +52,25 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
49
52
  )
50
53
 
51
54
  const handlePointerDown = useCallback(() => {
52
- onHistoryMark('click slider')
55
+ tooltipManager.hideAllTooltips()
56
+ onHistoryMark?.('click slider')
53
57
  }, [onHistoryMark])
54
58
 
59
+ // N.B. This is a bit silly. The Radix slider auto-focuses which
60
+ // triggers TldrawUiTooltip handleFocus when we dbl-click to edit an image,
61
+ // which in turn makes the tooltip display prematurely.
62
+ // This makes it wait until we've focused to show the tooltip.
63
+ useEffect(() => {
64
+ const timeout = tltime.setTimeout(
65
+ 'set title and label',
66
+ () => {
67
+ setTitleAndLabel(title + ' — ' + msg(label as TLUiTranslationKey))
68
+ },
69
+ 0
70
+ )
71
+ return () => clearTimeout(timeout)
72
+ }, [label, msg, title])
73
+
55
74
  // N.B. Annoying. For a11y purposes, we need Tab to work.
56
75
  // For some reason, Radix has some custom behavior here
57
76
  // that interferes with tabbing past the slider and then
@@ -64,36 +83,37 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
64
83
 
65
84
  return (
66
85
  <div className="tlui-slider__container">
67
- <_Slider.Root
68
- data-testid={testId}
69
- className="tlui-slider"
70
- dir="ltr"
71
- min={min ?? 0}
72
- max={steps}
73
- step={1}
74
- value={value !== null ? [value] : undefined}
75
- onPointerDown={handlePointerDown}
76
- onValueChange={handleValueChange}
77
- onKeyDownCapture={handleKeyEvent}
78
- onKeyUpCapture={handleKeyEvent}
79
- title={title + ' — ' + msg(label as TLUiTranslationKey)}
80
- >
81
- <_Slider.Track className="tlui-slider__track" dir="ltr">
82
- {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
83
- </_Slider.Track>
84
- {value !== null && (
85
- <_Slider.Thumb
86
- aria-valuemin={(min ?? 0) * ariaValueModifier}
87
- aria-valuenow={value * ariaValueModifier}
88
- aria-valuemax={steps * ariaValueModifier}
89
- aria-label={title + ' — ' + msg(label as TLUiTranslationKey)}
90
- className="tlui-slider__thumb"
91
- dir="ltr"
92
- ref={ref}
93
- tabIndex={tabIndex}
94
- />
95
- )}
96
- </_Slider.Root>
86
+ <TldrawUiTooltip content={titleAndLabel}>
87
+ <_Slider.Root
88
+ data-testid={testId}
89
+ className="tlui-slider"
90
+ dir="ltr"
91
+ min={min ?? 0}
92
+ max={steps}
93
+ step={1}
94
+ value={value !== null ? [value] : undefined}
95
+ onPointerDown={handlePointerDown}
96
+ onValueChange={handleValueChange}
97
+ onKeyDownCapture={handleKeyEvent}
98
+ onKeyUpCapture={handleKeyEvent}
99
+ >
100
+ <_Slider.Track className="tlui-slider__track" dir="ltr">
101
+ {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
102
+ </_Slider.Track>
103
+ {value !== null && (
104
+ <_Slider.Thumb
105
+ aria-valuemin={(min ?? 0) * ariaValueModifier}
106
+ aria-valuenow={value * ariaValueModifier}
107
+ aria-valuemax={steps * ariaValueModifier}
108
+ aria-label={titleAndLabel}
109
+ className="tlui-slider__thumb"
110
+ dir="ltr"
111
+ ref={ref}
112
+ tabIndex={tabIndex}
113
+ />
114
+ )}
115
+ </_Slider.Root>
116
+ </TldrawUiTooltip>
97
117
  </div>
98
118
  )
99
119
  })
@@ -94,6 +94,7 @@ export interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDi
94
94
  // TODO: fix up this type later
95
95
  defaultValue?: any
96
96
  type: 'single' | 'multiple'
97
+ asChild?: boolean
97
98
  }
98
99
 
99
100
  /** @public @react */
@@ -101,10 +102,12 @@ export const TldrawUiToolbarToggleGroup = ({
101
102
  children,
102
103
  className,
103
104
  type,
105
+ asChild,
104
106
  ...props
105
107
  }: TLUiToolbarToggleGroupProps) => {
106
108
  return (
107
109
  <_Toolbar.ToggleGroup
110
+ asChild={asChild}
108
111
  type={type}
109
112
  {...props}
110
113
  // TODO: this fixes a bug in Radix until they fix it.
@@ -1,7 +1,15 @@
1
- import { assert, 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, forwardRef, 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
+ useLayoutEffect,
10
+ useRef,
11
+ useState,
12
+ } from 'react'
5
13
  import { useTldrawUiOrientation } from './layout'
6
14
 
7
15
  const DEFAULT_TOOLTIP_DELAY_MS = 700
@@ -13,19 +21,25 @@ export interface TldrawUiTooltipProps {
13
21
  side?: 'top' | 'right' | 'bottom' | 'left'
14
22
  sideOffset?: number
15
23
  disabled?: boolean
24
+ showOnMobile?: boolean
25
+ delayDuration?: number
26
+ }
27
+
28
+ interface CurrentTooltip {
29
+ id: string
30
+ content: ReactNode
31
+ side: 'top' | 'right' | 'bottom' | 'left'
32
+ sideOffset: number
33
+ showOnMobile: boolean
34
+ targetElement: HTMLElement
35
+ delayDuration: number
16
36
  }
17
37
 
18
38
  // Singleton tooltip manager
19
39
  class TooltipManager {
20
40
  private static instance: TooltipManager | null = null
21
- private currentTooltipId: string | null = null
22
- private currentContent: string | React.ReactNode = ''
23
- private currentSide: 'top' | 'right' | 'bottom' | 'left' = 'bottom'
24
- private currentSideOffset: number = 5
41
+ private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
25
42
  private destroyTimeoutId: number | null = null
26
- private subscribers: Set<() => void> = new Set()
27
- private activeElement: HTMLElement | null = null
28
- private editor: Editor | null = null
29
43
 
30
44
  static getInstance(): TooltipManager {
31
45
  if (!TooltipManager.instance) {
@@ -34,25 +48,14 @@ class TooltipManager {
34
48
  return TooltipManager.instance
35
49
  }
36
50
 
37
- setEditor(editor: Editor | null) {
38
- this.editor = editor
39
- }
40
-
41
- subscribe(callback: () => void): () => void {
42
- this.subscribers.add(callback)
43
- return () => this.subscribers.delete(callback)
44
- }
45
-
46
- private notify() {
47
- this.subscribers.forEach((callback) => callback())
48
- }
49
-
50
51
  showTooltip(
51
52
  tooltipId: string,
52
53
  content: string | React.ReactNode,
53
- element: HTMLElement,
54
- side: 'top' | 'right' | 'bottom' | 'left' = 'bottom',
55
- sideOffset: number = 5
54
+ targetElement: HTMLElement,
55
+ side: 'top' | 'right' | 'bottom' | 'left',
56
+ sideOffset: number,
57
+ showOnMobile: boolean,
58
+ delayDuration: number
56
59
  ) {
57
60
  // Clear any existing destroy timeout
58
61
  if (this.destroyTimeoutId) {
@@ -61,51 +64,66 @@ class TooltipManager {
61
64
  }
62
65
 
63
66
  // Update current tooltip
64
- this.currentTooltipId = tooltipId
65
- this.currentContent = content
66
- this.currentSide = side
67
- this.currentSideOffset = sideOffset
68
- this.activeElement = element
67
+ this.currentTooltip.set({
68
+ id: tooltipId,
69
+ content,
70
+ side,
71
+ sideOffset,
72
+ showOnMobile,
73
+ targetElement,
74
+ delayDuration,
75
+ })
76
+ }
69
77
 
70
- this.notify()
78
+ updateCurrentTooltip(tooltipId: string, update: (tooltip: CurrentTooltip) => CurrentTooltip) {
79
+ this.currentTooltip.update((tooltip) => {
80
+ if (tooltip?.id === tooltipId) {
81
+ return update(tooltip)
82
+ }
83
+ return tooltip
84
+ })
71
85
  }
72
86
 
73
- hideTooltip(tooltipId: string, instant: boolean = false) {
87
+ hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
74
88
  const hide = () => {
75
89
  // Only hide if this is the current tooltip
76
- if (this.currentTooltipId === tooltipId) {
77
- this.currentTooltipId = null
78
- this.currentContent = ''
79
- this.activeElement = null
90
+ if (this.currentTooltip.get()?.id === tooltipId) {
91
+ this.currentTooltip.set(null)
80
92
  this.destroyTimeoutId = null
81
- this.notify()
82
93
  }
83
94
  }
84
95
 
85
- if (instant) {
86
- hide()
87
- } else if (this.editor) {
96
+ if (editor && !instant) {
88
97
  // Start destroy timeout (1 second)
89
- this.destroyTimeoutId = this.editor.timers.setTimeout(hide, 300)
98
+ this.destroyTimeoutId = editor.timers.setTimeout(hide, 300)
99
+ } else {
100
+ hide()
90
101
  }
91
102
  }
92
103
 
93
104
  hideAllTooltips() {
94
- this.currentTooltipId = null
95
- this.currentContent = ''
96
- this.activeElement = null
105
+ this.currentTooltip.set(null)
97
106
  this.destroyTimeoutId = null
98
- this.notify()
99
107
  }
100
108
 
101
109
  getCurrentTooltipData() {
102
- return {
103
- id: this.currentTooltipId,
104
- content: this.currentContent,
105
- side: this.currentSide,
106
- sideOffset: this.currentSideOffset,
107
- element: this.activeElement,
110
+ const currentTooltip = this.currentTooltip.get()
111
+ if (!currentTooltip) return null
112
+ if (!this.supportsHover() && !currentTooltip.showOnMobile) return null
113
+ return currentTooltip
114
+ }
115
+
116
+ private supportsHoverAtom: Atom<boolean> | null = null
117
+ supportsHover() {
118
+ if (!this.supportsHoverAtom) {
119
+ const mediaQuery = window.matchMedia('(hover: hover)')
120
+ const supportsHover = atom('has hover', mediaQuery.matches)
121
+ this.supportsHoverAtom = supportsHover
122
+ mediaQuery.addEventListener('change', (e) => {
123
+ supportsHover.set(e.matches)
124
+ })
108
125
  }
126
+ return this.supportsHoverAtom.get()
109
127
  }
110
128
  }
111
129
 
@@ -133,66 +151,34 @@ export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderPro
133
151
 
134
152
  // The singleton tooltip component that renders once
135
153
  function TooltipSingleton() {
136
- const editor = useMaybeEditor()
137
- const [, forceUpdate] = useState({})
138
154
  const [isOpen, setIsOpen] = useState(false)
139
155
  const triggerRef = useRef<HTMLDivElement>(null)
140
- const previousPositionRef = useRef<{ x: number; y: number } | null>(null)
141
- const prefersReducedMotion = usePrefersReducedMotion()
142
- const [shouldAnimate, setShouldAnimate] = useState(false)
143
156
  const isFirstShowRef = useRef(true)
144
- const showTimeoutRef = useRef<number | null>(null)
145
-
146
- // Set editor in tooltip manager
147
- useEffect(() => {
148
- tooltipManager.setEditor(editor)
149
- }, [editor])
157
+ const editor = useMaybeEditor()
150
158
 
151
- // Subscribe to tooltip manager updates
152
- useEffect(() => {
153
- const unsubscribe = tooltipManager.subscribe(() => {
154
- forceUpdate({})
155
- })
156
- return unsubscribe
157
- }, [])
159
+ const currentTooltip = useValue(
160
+ 'current tooltip',
161
+ () => tooltipManager.getCurrentTooltipData(),
162
+ []
163
+ )
158
164
 
159
- const tooltipData = tooltipManager.getCurrentTooltipData()
165
+ const cameraState = useValue('camera state', () => editor?.getCameraState(), [editor])
160
166
 
161
- // Update open state and trigger position
167
+ // Hide tooltip when camera is moving (panning/zooming)
162
168
  useEffect(() => {
163
- const shouldBeOpen = Boolean(tooltipData.id && tooltipData.element)
164
-
165
- // Clear any existing show timeout
166
- if (showTimeoutRef.current) {
167
- clearTimeout(showTimeoutRef.current)
168
- showTimeoutRef.current = null
169
+ if (cameraState === 'moving' && isOpen && currentTooltip) {
170
+ tooltipManager.hideTooltip(editor, currentTooltip.id, true)
169
171
  }
172
+ }, [cameraState, isOpen, currentTooltip, editor])
170
173
 
171
- if (shouldBeOpen && tooltipData.element && triggerRef.current) {
174
+ // Update open state and trigger position
175
+ useEffect(() => {
176
+ let timer: ReturnType<typeof setTimeout> | null = null
177
+ if (currentTooltip && triggerRef.current) {
172
178
  // Position the invisible trigger element over the active element
173
- const activeRect = tooltipData.element.getBoundingClientRect()
179
+ const activeRect = currentTooltip.targetElement.getBoundingClientRect()
174
180
  const trigger = triggerRef.current
175
181
 
176
- const newPosition = {
177
- x: activeRect.left + activeRect.width / 2,
178
- y: activeRect.top + activeRect.height / 2,
179
- }
180
-
181
- // Determine if we should animate
182
- let shouldAnimateCheck = false
183
- if (previousPositionRef.current) {
184
- const isNearPrevious = Vec.DistMin(previousPositionRef.current, newPosition, 200)
185
- // Only animate if the distance is less than 200px (nearby tooltips)
186
- shouldAnimateCheck =
187
- !prefersReducedMotion &&
188
- isNearPrevious &&
189
- Math.abs(newPosition.y - previousPositionRef.current.y) < 50
190
- }
191
- // Don't animate on initial show (previousPositionRef.current is null)
192
-
193
- setShouldAnimate(isFirstShowRef.current ? false : shouldAnimateCheck)
194
- previousPositionRef.current = newPosition
195
-
196
182
  trigger.style.position = 'fixed'
197
183
  trigger.style.left = `${activeRect.left}px`
198
184
  trigger.style.top = `${activeRect.top}px`
@@ -202,27 +188,31 @@ function TooltipSingleton() {
202
188
  trigger.style.zIndex = '9999'
203
189
 
204
190
  // Handle delay for first show
205
- if (isFirstShowRef.current && editor) {
206
- showTimeoutRef.current = editor.timers.setTimeout(() => {
191
+ if (isFirstShowRef.current) {
192
+ // eslint-disable-next-line no-restricted-globals
193
+ timer = setTimeout(() => {
207
194
  setIsOpen(true)
208
195
  isFirstShowRef.current = false
209
- }, editor.options.tooltipDelayMs)
196
+ }, currentTooltip.delayDuration)
210
197
  } else {
211
198
  // Subsequent tooltips show immediately
212
199
  setIsOpen(true)
213
200
  }
214
- } else if (!shouldBeOpen) {
201
+ } else {
215
202
  // Hide tooltip immediately
216
203
  setIsOpen(false)
217
- // Reset position tracking when tooltip closes
218
- previousPositionRef.current = null
219
- setShouldAnimate(false)
220
204
  // Reset first show state after tooltip is hidden
221
205
  isFirstShowRef.current = true
222
206
  }
223
- }, [tooltipData.id, tooltipData.element, editor, prefersReducedMotion])
224
207
 
225
- if (!tooltipData.id) {
208
+ return () => {
209
+ if (timer !== null) {
210
+ clearTimeout(timer)
211
+ }
212
+ }
213
+ }, [currentTooltip])
214
+
215
+ if (!currentTooltip) {
226
216
  return null
227
217
  }
228
218
 
@@ -233,14 +223,13 @@ function TooltipSingleton() {
233
223
  </_Tooltip.Trigger>
234
224
  <_Tooltip.Content
235
225
  className="tlui-tooltip"
236
- data-should-animate={shouldAnimate}
237
- side={tooltipData.side}
238
- sideOffset={tooltipData.sideOffset}
226
+ side={currentTooltip.side}
227
+ sideOffset={currentTooltip.sideOffset}
239
228
  avoidCollisions
240
229
  collisionPadding={8}
241
230
  dir="ltr"
242
231
  >
243
- {tooltipData.content}
232
+ {currentTooltip.content}
244
233
  <_Tooltip.Arrow className="tlui-tooltip__arrow" />
245
234
  </_Tooltip.Content>
246
235
  </_Tooltip.Root>
@@ -249,10 +238,22 @@ function TooltipSingleton() {
249
238
 
250
239
  /** @public @react */
251
240
  export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(
252
- ({ children, content, side, sideOffset = 5, disabled = false }, ref) => {
241
+ (
242
+ {
243
+ children,
244
+ content,
245
+ side,
246
+ sideOffset = 5,
247
+ disabled = false,
248
+ showOnMobile = false,
249
+ delayDuration,
250
+ },
251
+ ref
252
+ ) => {
253
253
  const editor = useMaybeEditor()
254
254
  const tooltipId = useRef<string>(uniqueId())
255
255
  const hasProvider = useContext(TooltipSingletonContext)
256
+ const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
256
257
 
257
258
  const orientationCtx = useTldrawUiOrientation()
258
259
  const sideToUse = side ?? orientationCtx.tooltipSide
@@ -261,23 +262,40 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
261
262
  const currentTooltipId = tooltipId.current
262
263
  return () => {
263
264
  if (hasProvider) {
264
- tooltipManager.hideTooltip(currentTooltipId, true)
265
+ tooltipManager.hideTooltip(editor, currentTooltipId, true)
265
266
  }
266
267
  }
267
- }, [hasProvider])
268
+ }, [editor, hasProvider])
269
+
270
+ useLayoutEffect(() => {
271
+ if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
272
+ tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
273
+ ...tooltip,
274
+ content,
275
+ side: sideToUse,
276
+ sideOffset,
277
+ showOnMobile,
278
+ }))
279
+ }
280
+ }, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
268
281
 
269
282
  // Don't show tooltip if disabled, no content, or UI labels are disabled
270
283
  if (disabled || !content) {
271
284
  return <>{children}</>
272
285
  }
273
286
 
287
+ let delayDurationToUse
288
+ if (showUiLabels) {
289
+ delayDurationToUse = 0
290
+ } else {
291
+ delayDurationToUse =
292
+ delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
293
+ }
294
+
274
295
  // Fallback to old behavior if no provider
275
296
  if (!hasProvider) {
276
297
  return (
277
- <_Tooltip.Root
278
- delayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}
279
- disableHoverableContent
280
- >
298
+ <_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent>
281
299
  <_Tooltip.Trigger asChild ref={ref}>
282
300
  {children}
283
301
  </_Tooltip.Trigger>
@@ -306,13 +324,15 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
306
324
  content,
307
325
  event.currentTarget as HTMLElement,
308
326
  sideToUse,
309
- sideOffset
327
+ sideOffset,
328
+ showOnMobile,
329
+ delayDurationToUse
310
330
  )
311
331
  }
312
332
 
313
333
  const handleMouseLeave = (event: React.MouseEvent<HTMLElement>) => {
314
334
  child.props.onMouseLeave?.(event)
315
- tooltipManager.hideTooltip(tooltipId.current)
335
+ tooltipManager.hideTooltip(editor, tooltipId.current)
316
336
  }
317
337
 
318
338
  const handleFocus = (event: React.FocusEvent<HTMLElement>) => {
@@ -322,13 +342,15 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
322
342
  content,
323
343
  event.currentTarget as HTMLElement,
324
344
  sideToUse,
325
- sideOffset
345
+ sideOffset,
346
+ showOnMobile,
347
+ delayDurationToUse
326
348
  )
327
349
  }
328
350
 
329
351
  const handleBlur = (event: React.FocusEvent<HTMLElement>) => {
330
352
  child.props.onBlur?.(event)
331
- tooltipManager.hideTooltip(tooltipId.current)
353
+ tooltipManager.hideTooltip(editor, tooltipId.current)
332
354
  }
333
355
 
334
356
  const childrenWithHandlers = React.cloneElement(children as React.ReactElement, {
@@ -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'
@@ -27,16 +27,6 @@ export function TldrawUiMenuGroup({ id, label, className, children }: TLUiMenuGr
27
27
  const labelStr = labelToUse ? msg(labelToUse as TLUiTranslationKey) : undefined
28
28
 
29
29
  switch (menu.type) {
30
- case 'panel': {
31
- return (
32
- <div
33
- className={classNames('tlui-menu__group', className)}
34
- data-testid={`${menu.sourceId}-group.${id}`}
35
- >
36
- {children}
37
- </div>
38
- )
39
- }
40
30
  case 'menu': {
41
31
  return (
42
32
  <TldrawUiDropdownMenuGroup