tldraw 3.16.0-canary.a03de714c746 → 3.16.0-canary.a2604843117c

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