tldraw 3.16.0-canary.9a94aba7bcaa → 3.16.0-canary.9abe0dac1e0f

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 (380) hide show
  1. package/dist-cjs/index.d.ts +240 -110
  2. package/dist-cjs/index.js +33 -14
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/Tldraw.js +12 -2
  5. package/dist-cjs/lib/Tldraw.js.map +2 -2
  6. package/dist-cjs/lib/defaultExternalContentHandlers.js +15 -4
  7. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  8. package/dist-cjs/lib/shapes/arrow/arrow-types.js.map +1 -1
  9. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  10. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  11. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +3 -2
  12. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  13. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  14. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  15. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +8 -1
  16. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  17. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +8 -2
  18. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  19. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  20. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  21. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -0
  22. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  23. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  24. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  25. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  26. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  27. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  28. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  29. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  30. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -5
  31. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  32. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  33. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  34. package/dist-cjs/lib/shapes/text/PlainTextArea.js +3 -2
  35. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  36. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  37. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  38. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  39. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  40. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  41. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  42. package/dist-cjs/lib/ui/TldrawUi.js +13 -12
  43. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  44. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  45. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  46. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  47. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  48. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  49. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  50. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  51. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  52. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  53. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  54. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +2 -1
  55. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  56. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  57. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  58. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  59. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  60. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  61. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  62. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  63. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  64. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  65. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  66. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  67. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  68. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +24 -21
  69. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  70. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  71. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  72. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +2 -0
  73. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  74. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
  75. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  76. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  77. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  78. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
  79. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  80. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +1 -1
  81. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
  82. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +6 -2
  83. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  84. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  85. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  86. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +5 -3
  87. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  88. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  89. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  90. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
  91. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  92. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +96 -43
  93. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  94. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  95. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  96. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +10 -9
  97. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  98. package/dist-cjs/lib/ui/context/actions.js +29 -10
  99. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  100. package/dist-cjs/lib/ui/context/components.js +2 -0
  101. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  102. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  103. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  104. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  105. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  106. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  107. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  108. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  109. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  110. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -2
  111. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  112. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  113. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  114. package/dist-cjs/lib/ui/version.js +3 -3
  115. package/dist-cjs/lib/ui/version.js.map +1 -1
  116. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  117. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  118. package/dist-cjs/lib/utils/export/export.js +0 -20
  119. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  120. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  121. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  122. package/dist-esm/index.d.mts +240 -110
  123. package/dist-esm/index.mjs +61 -29
  124. package/dist-esm/index.mjs.map +2 -2
  125. package/dist-esm/lib/Tldraw.mjs +14 -4
  126. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  127. package/dist-esm/lib/defaultExternalContentHandlers.mjs +15 -4
  128. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  129. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  130. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  131. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +3 -2
  132. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  133. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +4 -5
  134. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  135. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +8 -1
  136. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  137. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +9 -3
  138. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  139. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  140. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  141. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -0
  142. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  143. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  144. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  145. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  146. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  147. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  148. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  149. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  150. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +3 -6
  151. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  152. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  153. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  154. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +4 -3
  155. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  156. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  157. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  158. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  159. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  160. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  161. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  162. package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
  163. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  164. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  165. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  166. package/dist-esm/lib/ui/components/A11y.mjs +1 -2
  167. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  168. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  169. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  170. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  171. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  172. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  173. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  174. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +2 -1
  175. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  176. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +1 -2
  177. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  178. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  179. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  180. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  181. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  182. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
  183. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  184. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  185. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  186. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  187. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  188. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +21 -18
  189. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  190. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  191. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  192. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +2 -0
  193. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  194. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
  195. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  196. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  197. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  198. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +2 -1
  199. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  200. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +1 -1
  201. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
  202. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +6 -2
  203. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  204. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +11 -3
  205. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  206. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +6 -4
  207. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  208. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  209. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  210. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
  211. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  212. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +97 -43
  213. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  214. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  215. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  216. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +10 -9
  217. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  218. package/dist-esm/lib/ui/context/actions.mjs +29 -10
  219. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  220. package/dist-esm/lib/ui/context/components.mjs +2 -0
  221. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  222. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  223. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +1 -2
  224. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  225. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  226. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  227. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  228. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  229. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -2
  230. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  231. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  232. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  233. package/dist-esm/lib/ui/version.mjs +3 -3
  234. package/dist-esm/lib/ui/version.mjs.map +1 -1
  235. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  236. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  237. package/dist-esm/lib/utils/export/export.mjs +0 -20
  238. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  239. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  240. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  241. package/package.json +11 -34
  242. package/src/index.ts +44 -22
  243. package/src/lib/Tldraw.tsx +15 -2
  244. package/src/lib/defaultExternalContentHandlers.ts +26 -4
  245. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +85 -14
  246. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +6 -5
  247. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  248. package/src/lib/shapes/arrow/arrow-types.ts +3 -5
  249. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  250. package/src/lib/shapes/arrow/arrowTargetState.ts +4 -3
  251. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +4 -5
  252. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  253. package/src/lib/shapes/frame/FrameShapeUtil.tsx +9 -0
  254. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
  255. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  256. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
  257. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  258. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  259. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  260. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  261. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  262. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  263. package/src/lib/shapes/shared/useEditablePlainText.ts +3 -10
  264. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  265. package/src/lib/shapes/text/PlainTextArea.tsx +4 -3
  266. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  267. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  268. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  269. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  270. package/src/lib/ui/TldrawUi.tsx +16 -10
  271. package/src/lib/ui/assetUrls.ts +13 -10
  272. package/src/lib/ui/components/A11y.tsx +1 -2
  273. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  274. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  275. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  276. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +2 -1
  277. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +1 -2
  278. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  279. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  280. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  281. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  282. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  283. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  284. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  285. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -0
  286. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
  287. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  288. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
  289. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +1 -1
  290. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +9 -2
  291. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +7 -3
  292. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
  293. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  294. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
  295. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +109 -31
  296. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  297. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +12 -11
  298. package/src/lib/ui/context/actions.tsx +36 -10
  299. package/src/lib/ui/context/components.tsx +3 -0
  300. package/src/lib/ui/context/events.tsx +1 -1
  301. package/src/lib/ui/hooks/useClipboardEvents.ts +1 -2
  302. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  303. package/src/lib/ui/hooks/useTools.tsx +1 -1
  304. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +4 -0
  305. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -2
  306. package/src/lib/ui/kbd-utils.ts +10 -3
  307. package/src/lib/ui/version.ts +3 -3
  308. package/src/lib/ui.css +33 -2
  309. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  310. package/src/lib/utils/export/copyAs.ts +1 -24
  311. package/src/lib/utils/export/export.ts +0 -36
  312. package/src/lib/utils/export/exportAs.ts +1 -32
  313. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  314. package/src/test/A11y.test.tsx +3 -2
  315. package/src/test/ClickManager.test.ts +7 -6
  316. package/src/test/Editor.test.tsx +20 -19
  317. package/src/test/EraserTool.test.ts +184 -13
  318. package/src/test/HandTool.test.ts +10 -9
  319. package/src/test/HighlightShape.test.ts +2 -1
  320. package/src/test/SelectTool.test.ts +3 -2
  321. package/src/test/TLUserPreferences.test.ts +4 -3
  322. package/src/test/TestEditor.ts +13 -15
  323. package/src/test/TldrawEditor.test.tsx +11 -10
  324. package/src/test/ZoomTool.test.ts +7 -6
  325. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  326. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  327. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  328. package/src/test/arrows-megabus.test.tsx +5 -4
  329. package/src/test/bindings.test.tsx +24 -37
  330. package/src/test/bookmark-shapes.test.ts +1 -8
  331. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  332. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  333. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  334. package/src/test/commands/alignShapes.test.tsx +25 -24
  335. package/src/test/commands/animationSpeed.test.ts +2 -1
  336. package/src/test/commands/centerOnPoint.test.ts +3 -2
  337. package/src/test/commands/clipboard.test.ts +3 -2
  338. package/src/test/commands/createShapes.test.ts +2 -1
  339. package/src/test/commands/deleteShapes.test.ts +2 -1
  340. package/src/test/commands/distributeShapes.test.tsx +11 -10
  341. package/src/test/commands/getSvgString.test.ts +2 -1
  342. package/src/test/commands/packShapes.test.ts +5 -4
  343. package/src/test/commands/resizeShape.test.ts +2 -1
  344. package/src/test/commands/rotateShapes.test.ts +7 -6
  345. package/src/test/commands/setCamera.test.ts +4 -3
  346. package/src/test/commands/setCurrentPage.test.ts +3 -2
  347. package/src/test/commands/stackShapes.test.ts +11 -10
  348. package/src/test/commands/stretch.test.tsx +13 -12
  349. package/src/test/createDeepLink.test.tsx +2 -1
  350. package/src/test/cropping.test.ts +3 -2
  351. package/src/test/custom-clipping.test.ts +436 -0
  352. package/src/test/drawing.test.ts +2 -1
  353. package/src/test/flipShapes.test.ts +4 -3
  354. package/src/test/frames.test.ts +25 -24
  355. package/src/test/getCulledShapes.test.tsx +74 -4
  356. package/src/test/groups.test.tsx +1 -1
  357. package/src/test/handleDeepLink.test.tsx +2 -1
  358. package/src/test/maxShapes.test.ts +3 -2
  359. package/src/test/modifiers.test.ts +5 -4
  360. package/src/test/navigation.test.ts +12 -11
  361. package/src/test/panning.test.ts +2 -1
  362. package/src/test/perf/perf.test.ts +2 -1
  363. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  364. package/src/test/resizing.test.ts +39 -38
  365. package/src/test/select.test.tsx +4 -3
  366. package/src/test/selection-omnibus.test.ts +11 -10
  367. package/src/test/shapeutils.test.ts +4 -3
  368. package/src/test/translating.test.ts +9 -8
  369. package/tldraw.css +49 -5
  370. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  371. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  372. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  373. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  374. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  375. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  376. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  377. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  378. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  379. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  380. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -4,7 +4,6 @@ import {
4
4
  clamp,
5
5
  Editor,
6
6
  react,
7
- stopEventPropagation,
8
7
  useAtom,
9
8
  useEditor,
10
9
  usePassThroughMouseOverEvents,
@@ -170,9 +169,14 @@ export const TldrawUiContextualToolbar = ({
170
169
  data-visible={false}
171
170
  data-testid="contextual-toolbar"
172
171
  className={classNames('tlui-contextual-toolbar', className)}
173
- onPointerDown={stopEventPropagation}
172
+ onPointerDown={editor.markEventAsHandled}
174
173
  >
175
- <TldrawUiToolbar orientation="horizontal" className="tlui-menu" label={label}>
174
+ <TldrawUiToolbar
175
+ orientation="horizontal"
176
+ className="tlui-menu"
177
+ label={label}
178
+ tooltipSide="top"
179
+ >
176
180
  {children}
177
181
  </TldrawUiToolbar>
178
182
  </div>
@@ -1,4 +1,4 @@
1
- import { stopEventPropagation, tlenv, tltime, useMaybeEditor } from '@tldraw/editor'
1
+ import { tlenv, tltime, useMaybeEditor } from '@tldraw/editor'
2
2
  import classNames from 'classnames'
3
3
  import * as React from 'react'
4
4
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
@@ -35,6 +35,7 @@ export interface TLUiInputProps {
35
35
  shouldManuallyMaintainScrollPositionWhenFocused?: boolean
36
36
  value?: string
37
37
  'data-testid'?: string
38
+ 'aria-label'?: string
38
39
  }
39
40
 
40
41
  /** @public @react */
@@ -60,6 +61,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
60
61
  value,
61
62
  'data-testid': dataTestId,
62
63
  disabled,
64
+ 'aria-label': ariaLabel,
63
65
  },
64
66
  ref
65
67
  ) {
@@ -118,7 +120,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
118
120
  // `onChange` with a duplicated text value.
119
121
  if (isComposing.current) return
120
122
  e.currentTarget.blur()
121
- stopEventPropagation(e)
123
+ e.stopPropagation()
122
124
  onComplete?.(e.currentTarget.value)
123
125
  break
124
126
  }
@@ -126,7 +128,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
126
128
  e.currentTarget.value = rInitialValue.current
127
129
  onCancel?.(e.currentTarget.value)
128
130
  e.currentTarget.blur()
129
- stopEventPropagation(e)
131
+ e.stopPropagation()
130
132
  break
131
133
  }
132
134
  }
@@ -198,6 +200,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
198
200
  onCompositionStart={handleCompositionStart}
199
201
  onCompositionEnd={handleCompositionEnd}
200
202
  autoFocus={autoFocus}
203
+ aria-label={ariaLabel}
201
204
  placeholder={placeholder}
202
205
  value={value}
203
206
  data-testid={dataTestId}
@@ -1,7 +1,9 @@
1
+ import { tltime } from '@tldraw/editor'
1
2
  import { Slider as _Slider } from 'radix-ui'
2
3
  import React, { useCallback, useEffect, useState } from 'react'
3
4
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
4
5
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
6
+ import { TldrawUiTooltip, tooltipManager } from './TldrawUiTooltip'
5
7
 
6
8
  /** @public */
7
9
  export interface TLUiSliderProps {
@@ -11,7 +13,7 @@ export interface TLUiSliderProps {
11
13
  label: string
12
14
  title: string
13
15
  onValueChange(value: number): void
14
- onHistoryMark(id: string): void
16
+ onHistoryMark?(id: string): void
15
17
  'data-testid'?: string
16
18
  ariaValueModifier?: number
17
19
  }
@@ -32,6 +34,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
32
34
  ref
33
35
  ) {
34
36
  const msg = useTranslation()
37
+ const [titleAndLabel, setTitleAndLabel] = useState('')
35
38
 
36
39
  // XXX: Radix starts out our slider with a tabIndex of 0
37
40
  // This causes some tab focusing issues, most prevelant in MobileStylePanel,
@@ -49,9 +52,25 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
49
52
  )
50
53
 
51
54
  const handlePointerDown = useCallback(() => {
52
- onHistoryMark('click slider')
55
+ tooltipManager.hideAllTooltips()
56
+ onHistoryMark?.('click slider')
53
57
  }, [onHistoryMark])
54
58
 
59
+ // N.B. This is a bit silly. The Radix slider auto-focuses which
60
+ // triggers TldrawUiTooltip handleFocus when we dbl-click to edit an image,
61
+ // which in turn makes the tooltip display prematurely.
62
+ // This makes it wait until we've focused to show the tooltip.
63
+ useEffect(() => {
64
+ const timeout = tltime.setTimeout(
65
+ 'set title and label',
66
+ () => {
67
+ setTitleAndLabel(title + ' — ' + msg(label as TLUiTranslationKey))
68
+ },
69
+ 0
70
+ )
71
+ return () => clearTimeout(timeout)
72
+ }, [label, msg, title])
73
+
55
74
  // N.B. Annoying. For a11y purposes, we need Tab to work.
56
75
  // For some reason, Radix has some custom behavior here
57
76
  // that interferes with tabbing past the slider and then
@@ -64,36 +83,37 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
64
83
 
65
84
  return (
66
85
  <div className="tlui-slider__container">
67
- <_Slider.Root
68
- data-testid={testId}
69
- className="tlui-slider"
70
- dir="ltr"
71
- min={min ?? 0}
72
- max={steps}
73
- step={1}
74
- value={value !== null ? [value] : undefined}
75
- onPointerDown={handlePointerDown}
76
- onValueChange={handleValueChange}
77
- onKeyDownCapture={handleKeyEvent}
78
- onKeyUpCapture={handleKeyEvent}
79
- title={title + ' — ' + msg(label as TLUiTranslationKey)}
80
- >
81
- <_Slider.Track className="tlui-slider__track" dir="ltr">
82
- {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
83
- </_Slider.Track>
84
- {value !== null && (
85
- <_Slider.Thumb
86
- aria-valuemin={(min ?? 0) * ariaValueModifier}
87
- aria-valuenow={value * ariaValueModifier}
88
- aria-valuemax={steps * ariaValueModifier}
89
- aria-label={title + ' — ' + msg(label as TLUiTranslationKey)}
90
- className="tlui-slider__thumb"
91
- dir="ltr"
92
- ref={ref}
93
- tabIndex={tabIndex}
94
- />
95
- )}
96
- </_Slider.Root>
86
+ <TldrawUiTooltip content={titleAndLabel}>
87
+ <_Slider.Root
88
+ data-testid={testId}
89
+ className="tlui-slider"
90
+ dir="ltr"
91
+ min={min ?? 0}
92
+ max={steps}
93
+ step={1}
94
+ value={value !== null ? [value] : undefined}
95
+ onPointerDown={handlePointerDown}
96
+ onValueChange={handleValueChange}
97
+ onKeyDownCapture={handleKeyEvent}
98
+ onKeyUpCapture={handleKeyEvent}
99
+ >
100
+ <_Slider.Track className="tlui-slider__track" dir="ltr">
101
+ {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
102
+ </_Slider.Track>
103
+ {value !== null && (
104
+ <_Slider.Thumb
105
+ aria-valuemin={(min ?? 0) * ariaValueModifier}
106
+ aria-valuenow={value * ariaValueModifier}
107
+ aria-valuemax={steps * ariaValueModifier}
108
+ aria-label={titleAndLabel}
109
+ className="tlui-slider__thumb"
110
+ dir="ltr"
111
+ ref={ref}
112
+ tabIndex={tabIndex}
113
+ />
114
+ )}
115
+ </_Slider.Root>
116
+ </TldrawUiTooltip>
97
117
  </div>
98
118
  )
99
119
  })
@@ -71,6 +71,7 @@ export const TldrawUiToolbarButton = React.forwardRef<HTMLButtonElement, TLUiToo
71
71
  draggable={false}
72
72
  data-isactive={isActive}
73
73
  {...props}
74
+ aria-label={props.title}
74
75
  // The tooltip takes care of this.
75
76
  title={undefined}
76
77
  className={classnames('tlui-button', `tlui-button__${type}`, props.className)}
@@ -94,6 +95,7 @@ export interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDi
94
95
  // TODO: fix up this type later
95
96
  defaultValue?: any
96
97
  type: 'single' | 'multiple'
98
+ asChild?: boolean
97
99
  }
98
100
 
99
101
  /** @public @react */
@@ -101,10 +103,12 @@ export const TldrawUiToolbarToggleGroup = ({
101
103
  children,
102
104
  className,
103
105
  type,
106
+ asChild,
104
107
  ...props
105
108
  }: TLUiToolbarToggleGroupProps) => {
106
109
  return (
107
110
  <_Toolbar.ToggleGroup
111
+ asChild={asChild}
108
112
  type={type}
109
113
  {...props}
110
114
  // TODO: this fixes a bug in Radix until they fix it.
@@ -124,7 +128,7 @@ export interface TLUiToolbarToggleItemProps extends React.HTMLAttributes<HTMLBut
124
128
  className?: string
125
129
  type: 'icon' | 'tool'
126
130
  value: string
127
- tooltip?: string
131
+ tooltip?: React.ReactNode
128
132
  }
129
133
 
130
134
  /** @public @react */
@@ -6,6 +6,7 @@ import React, {
6
6
  ReactNode,
7
7
  useContext,
8
8
  useEffect,
9
+ useLayoutEffect,
9
10
  useRef,
10
11
  useState,
11
12
  } from 'react'
@@ -20,20 +21,25 @@ export interface TldrawUiTooltipProps {
20
21
  side?: 'top' | 'right' | 'bottom' | 'left'
21
22
  sideOffset?: number
22
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
23
36
  }
24
37
 
25
38
  // Singleton tooltip manager
26
39
  class TooltipManager {
27
40
  private static instance: TooltipManager | null = null
28
- private currentTooltip = atom<{
29
- id: string
30
- content: ReactNode
31
- side: 'top' | 'right' | 'bottom' | 'left'
32
- sideOffset: number
33
- targetElement: HTMLElement
34
- } | null>('current tooltip', null)
41
+ private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
35
42
  private destroyTimeoutId: number | null = null
36
- private subscribers: Set<() => void> = new Set()
37
43
 
38
44
  static getInstance(): TooltipManager {
39
45
  if (!TooltipManager.instance) {
@@ -46,8 +52,10 @@ class TooltipManager {
46
52
  tooltipId: string,
47
53
  content: string | React.ReactNode,
48
54
  targetElement: HTMLElement,
49
- side: 'top' | 'right' | 'bottom' | 'left' = 'bottom',
50
- sideOffset: number = 5
55
+ side: 'top' | 'right' | 'bottom' | 'left',
56
+ sideOffset: number,
57
+ showOnMobile: boolean,
58
+ delayDuration: number
51
59
  ) {
52
60
  // Clear any existing destroy timeout
53
61
  if (this.destroyTimeoutId) {
@@ -61,7 +69,18 @@ class TooltipManager {
61
69
  content,
62
70
  side,
63
71
  sideOffset,
72
+ showOnMobile,
64
73
  targetElement,
74
+ delayDuration,
75
+ })
76
+ }
77
+
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
65
84
  })
66
85
  }
67
86
 
@@ -88,8 +107,10 @@ class TooltipManager {
88
107
  }
89
108
 
90
109
  getCurrentTooltipData() {
91
- if (!this.supportsHover()) return null
92
- return this.currentTooltip.get()
110
+ const currentTooltip = this.currentTooltip.get()
111
+ if (!currentTooltip) return null
112
+ if (!this.supportsHover() && !currentTooltip.showOnMobile) return null
113
+ return currentTooltip
93
114
  }
94
115
 
95
116
  private supportsHoverAtom: Atom<boolean> | null = null
@@ -130,11 +151,10 @@ export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderPro
130
151
 
131
152
  // The singleton tooltip component that renders once
132
153
  function TooltipSingleton() {
133
- const editor = useMaybeEditor()
134
154
  const [isOpen, setIsOpen] = useState(false)
135
155
  const triggerRef = useRef<HTMLDivElement>(null)
136
156
  const isFirstShowRef = useRef(true)
137
- const showTimeoutRef = useRef<number | null>(null)
157
+ const editor = useMaybeEditor()
138
158
 
139
159
  const currentTooltip = useValue(
140
160
  'current tooltip',
@@ -142,14 +162,32 @@ function TooltipSingleton() {
142
162
  []
143
163
  )
144
164
 
145
- // Update open state and trigger position
165
+ const cameraState = useValue('camera state', () => editor?.getCameraState(), [editor])
166
+
167
+ // Hide tooltip when camera is moving (panning/zooming)
146
168
  useEffect(() => {
147
- // Clear any existing show timeout
148
- if (showTimeoutRef.current) {
149
- clearTimeout(showTimeoutRef.current)
150
- showTimeoutRef.current = null
169
+ if (cameraState === 'moving' && isOpen && currentTooltip) {
170
+ tooltipManager.hideTooltip(editor, currentTooltip.id, true)
171
+ }
172
+ }, [cameraState, isOpen, currentTooltip, editor])
173
+
174
+ useEffect(() => {
175
+ function handleKeyDown(event: KeyboardEvent) {
176
+ if (event.key === 'Escape' && currentTooltip && isOpen) {
177
+ tooltipManager.hideTooltip(editor, currentTooltip.id)
178
+ event.stopPropagation()
179
+ }
151
180
  }
152
181
 
182
+ document.addEventListener('keydown', handleKeyDown, { capture: true })
183
+ return () => {
184
+ document.removeEventListener('keydown', handleKeyDown, { capture: true })
185
+ }
186
+ }, [editor, currentTooltip, isOpen])
187
+
188
+ // Update open state and trigger position
189
+ useEffect(() => {
190
+ let timer: ReturnType<typeof setTimeout> | null = null
153
191
  if (currentTooltip && triggerRef.current) {
154
192
  // Position the invisible trigger element over the active element
155
193
  const activeRect = currentTooltip.targetElement.getBoundingClientRect()
@@ -164,11 +202,12 @@ function TooltipSingleton() {
164
202
  trigger.style.zIndex = '9999'
165
203
 
166
204
  // Handle delay for first show
167
- if (isFirstShowRef.current && editor) {
168
- showTimeoutRef.current = editor.timers.setTimeout(() => {
205
+ if (isFirstShowRef.current) {
206
+ // eslint-disable-next-line no-restricted-globals
207
+ timer = setTimeout(() => {
169
208
  setIsOpen(true)
170
209
  isFirstShowRef.current = false
171
- }, editor.options.tooltipDelayMs)
210
+ }, currentTooltip.delayDuration)
172
211
  } else {
173
212
  // Subsequent tooltips show immediately
174
213
  setIsOpen(true)
@@ -179,7 +218,13 @@ function TooltipSingleton() {
179
218
  // Reset first show state after tooltip is hidden
180
219
  isFirstShowRef.current = true
181
220
  }
182
- }, [editor, currentTooltip])
221
+
222
+ return () => {
223
+ if (timer !== null) {
224
+ clearTimeout(timer)
225
+ }
226
+ }
227
+ }, [currentTooltip])
183
228
 
184
229
  if (!currentTooltip) {
185
230
  return null
@@ -207,10 +252,22 @@ function TooltipSingleton() {
207
252
 
208
253
  /** @public @react */
209
254
  export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(
210
- ({ children, content, side, sideOffset = 5, disabled = false }, ref) => {
255
+ (
256
+ {
257
+ children,
258
+ content,
259
+ side,
260
+ sideOffset = 5,
261
+ disabled = false,
262
+ showOnMobile = false,
263
+ delayDuration,
264
+ },
265
+ ref
266
+ ) => {
211
267
  const editor = useMaybeEditor()
212
268
  const tooltipId = useRef<string>(uniqueId())
213
269
  const hasProvider = useContext(TooltipSingletonContext)
270
+ const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
214
271
 
215
272
  const orientationCtx = useTldrawUiOrientation()
216
273
  const sideToUse = side ?? orientationCtx.tooltipSide
@@ -224,18 +281,35 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
224
281
  }
225
282
  }, [editor, hasProvider])
226
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])
295
+
227
296
  // Don't show tooltip if disabled, no content, or UI labels are disabled
228
297
  if (disabled || !content) {
229
298
  return <>{children}</>
230
299
  }
231
300
 
301
+ let delayDurationToUse
302
+ if (showUiLabels) {
303
+ delayDurationToUse = 0
304
+ } else {
305
+ delayDurationToUse =
306
+ delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
307
+ }
308
+
232
309
  // Fallback to old behavior if no provider
233
- if (!hasProvider) {
310
+ if (!hasProvider || showUiLabels) {
234
311
  return (
235
- <_Tooltip.Root
236
- delayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}
237
- disableHoverableContent
238
- >
312
+ <_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent={!showUiLabels}>
239
313
  <_Tooltip.Trigger asChild ref={ref}>
240
314
  {children}
241
315
  </_Tooltip.Trigger>
@@ -264,7 +338,9 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
264
338
  content,
265
339
  event.currentTarget as HTMLElement,
266
340
  sideToUse,
267
- sideOffset
341
+ sideOffset,
342
+ showOnMobile,
343
+ delayDurationToUse
268
344
  )
269
345
  }
270
346
 
@@ -280,7 +356,9 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
280
356
  content,
281
357
  event.currentTarget as HTMLElement,
282
358
  sideToUse,
283
- sideOffset
359
+ sideOffset,
360
+ showOnMobile,
361
+ delayDurationToUse
284
362
  )
285
363
  }
286
364
 
@@ -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)
@@ -213,7 +213,7 @@ export function TldrawUiMenuItem<
213
213
  icon={icon}
214
214
  onSelect={onSelect}
215
215
  onDragStart={onDragStart}
216
- labelToUse={labelToUse}
216
+ labelStr={labelStr}
217
217
  titleStr={titleStr}
218
218
  disabled={disabled}
219
219
  isSelected={isSelected}
@@ -247,7 +247,7 @@ export function TldrawUiMenuItem<
247
247
  icon={icon}
248
248
  onSelect={onSelect}
249
249
  onDragStart={onDragStart}
250
- labelToUse={labelToUse}
250
+ labelStr={labelStr}
251
251
  titleStr={titleStr}
252
252
  disabled={disabled}
253
253
  isSelected={isSelected}
@@ -316,8 +316,8 @@ function useDraggableEvents(
316
316
  if (
317
317
  distanceSq >
318
318
  (editor.getInstanceState().isCoarsePointer
319
- ? editor.options.coarseDragDistanceSquared
320
- : editor.options.dragDistanceSquared)
319
+ ? editor.options.uiCoarseDragDistanceSquared
320
+ : editor.options.uiDragDistanceSquared)
321
321
  ) {
322
322
  const screenSpaceStart = state.screenSpaceStart
323
323
  state = {
@@ -333,7 +333,7 @@ function useDraggableEvents(
333
333
  type: 'pointer',
334
334
  target: 'canvas',
335
335
  name: 'pointer_down',
336
- ...getPointerInfo(e),
336
+ ...getPointerInfo(editor, e),
337
337
  point: screenSpaceStart,
338
338
  })
339
339
 
@@ -345,11 +345,12 @@ function useDraggableEvents(
345
345
  type: 'pointer',
346
346
  target: 'canvas',
347
347
  name: 'pointer_move',
348
- ...getPointerInfo(e),
348
+ ...getPointerInfo(editor, e),
349
349
  point: screenSpaceStart,
350
350
  })
351
351
 
352
352
  tooltipManager.hideAllTooltips()
353
+ editor.getContainer().focus()
353
354
  })
354
355
  }
355
356
  }
@@ -364,7 +365,7 @@ function useDraggableEvents(
364
365
  type: 'pointer',
365
366
  target: 'canvas',
366
367
  name: 'pointer_up',
367
- ...getPointerInfo(e),
368
+ ...getPointerInfo(editor, e),
368
369
  })
369
370
  }
370
371
 
@@ -391,7 +392,7 @@ function useDraggableEvents(
391
392
 
392
393
  function DraggableToolbarButton({
393
394
  id,
394
- labelToUse,
395
+ labelStr,
395
396
  titleStr,
396
397
  disabled,
397
398
  isSelected,
@@ -402,7 +403,7 @@ function DraggableToolbarButton({
402
403
  }: {
403
404
  id: string
404
405
  disabled: boolean
405
- labelToUse?: string
406
+ labelStr?: string
406
407
  titleStr?: string
407
408
  isSelected?: boolean
408
409
  icon: TLUiMenuItemProps['icon']
@@ -415,7 +416,7 @@ function DraggableToolbarButton({
415
416
  if (overflow) {
416
417
  return (
417
418
  <TldrawUiToolbarButton
418
- aria-label={labelToUse}
419
+ aria-label={labelStr}
419
420
  aria-pressed={isSelected ? 'true' : 'false'}
420
421
  isActive={isSelected}
421
422
  className="tlui-button-grid__button"
@@ -433,7 +434,7 @@ function DraggableToolbarButton({
433
434
 
434
435
  return (
435
436
  <TldrawUiToolbarButton
436
- aria-label={labelToUse}
437
+ aria-label={labelStr}
437
438
  aria-pressed={isSelected ? 'true' : 'false'}
438
439
  data-testid={`tools.${id}`}
439
440
  data-value={id}