tldraw 3.16.0-canary.6f3aedaa1c01 → 3.16.0-canary.7379d3553d7e

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