tldraw 3.16.0-canary.b5a35402e79e → 3.16.0-canary.ba3bc37d4418

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 (363) hide show
  1. package/dist-cjs/index.d.ts +230 -107
  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/arrowLabel.js +6 -0
  9. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  10. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  11. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +8 -1
  13. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  14. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +2 -2
  15. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  16. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  17. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -0
  19. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  20. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  21. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  22. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  23. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  24. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  25. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  26. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  27. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -4
  28. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  29. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  30. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  31. package/dist-cjs/lib/shapes/text/PlainTextArea.js +2 -2
  32. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  33. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  34. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  35. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  36. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  37. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  38. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  39. package/dist-cjs/lib/ui/TldrawUi.js +13 -12
  40. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  41. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  42. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  43. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  44. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  45. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  46. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  47. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  48. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  49. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  50. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  51. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +1 -0
  52. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  53. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  54. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  55. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  56. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  57. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  58. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  59. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  60. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  61. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  62. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  63. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  64. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  65. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +24 -21
  66. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  67. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  68. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  69. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +4 -2
  70. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  71. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
  72. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  73. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  74. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +5 -4
  76. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  78. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -2
  80. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  82. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
  84. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +73 -36
  86. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  88. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +7 -6
  90. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  91. package/dist-cjs/lib/ui/context/actions.js +29 -10
  92. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  93. package/dist-cjs/lib/ui/context/components.js +2 -0
  94. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  95. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  96. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  97. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  98. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  99. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  100. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  101. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  102. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  103. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -2
  104. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  105. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  106. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  107. package/dist-cjs/lib/ui/version.js +3 -3
  108. package/dist-cjs/lib/ui/version.js.map +1 -1
  109. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  110. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  111. package/dist-cjs/lib/utils/export/export.js +0 -20
  112. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  113. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  114. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  115. package/dist-esm/index.d.mts +230 -107
  116. package/dist-esm/index.mjs +61 -29
  117. package/dist-esm/index.mjs.map +2 -2
  118. package/dist-esm/lib/Tldraw.mjs +14 -4
  119. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  120. package/dist-esm/lib/defaultExternalContentHandlers.mjs +15 -4
  121. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  122. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  123. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  124. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +5 -5
  125. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  126. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +8 -1
  127. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  128. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +3 -3
  129. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  130. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  131. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  132. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -0
  133. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  134. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  135. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  136. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  137. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  138. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  139. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  140. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  141. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +4 -5
  142. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  143. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  144. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  145. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +3 -3
  146. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  147. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  148. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  149. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  150. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  151. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  152. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  153. package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
  154. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  155. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  156. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  157. package/dist-esm/lib/ui/components/A11y.mjs +2 -2
  158. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  159. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  160. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  161. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  162. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  163. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  164. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  165. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +1 -0
  166. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  167. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -2
  168. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  169. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  170. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  171. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  172. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  173. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
  174. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  175. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  176. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  177. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  178. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  179. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +21 -18
  180. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  181. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  182. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  183. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +4 -2
  184. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  185. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
  186. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  187. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  188. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  189. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +5 -4
  190. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  191. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +12 -3
  192. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  193. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +3 -3
  194. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  195. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  196. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  197. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
  198. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  199. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +74 -36
  200. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  201. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  202. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  203. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +7 -6
  204. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  205. package/dist-esm/lib/ui/context/actions.mjs +29 -10
  206. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  207. package/dist-esm/lib/ui/context/components.mjs +2 -0
  208. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  209. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  210. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +2 -2
  211. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  212. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  213. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  214. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  215. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  216. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -2
  217. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  218. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  219. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  220. package/dist-esm/lib/ui/version.mjs +3 -3
  221. package/dist-esm/lib/ui/version.mjs.map +1 -1
  222. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  223. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  224. package/dist-esm/lib/utils/export/export.mjs +0 -20
  225. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  226. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  227. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  228. package/package.json +11 -34
  229. package/src/index.ts +44 -22
  230. package/src/lib/Tldraw.tsx +15 -2
  231. package/src/lib/defaultExternalContentHandlers.ts +26 -4
  232. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  233. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +6 -5
  234. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  235. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  236. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +5 -5
  237. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  238. package/src/lib/shapes/frame/FrameShapeUtil.tsx +9 -0
  239. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +3 -3
  240. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  241. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
  242. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  243. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  244. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  245. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  246. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  247. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  248. package/src/lib/shapes/shared/useEditablePlainText.ts +5 -9
  249. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  250. package/src/lib/shapes/text/PlainTextArea.tsx +3 -3
  251. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  252. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  253. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  254. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  255. package/src/lib/ui/TldrawUi.tsx +16 -10
  256. package/src/lib/ui/assetUrls.ts +13 -10
  257. package/src/lib/ui/components/A11y.tsx +2 -2
  258. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  259. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  260. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  261. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +1 -0
  262. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +2 -2
  263. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  264. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  265. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  266. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  267. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  268. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  269. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  270. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +5 -3
  271. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
  272. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  273. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +6 -5
  274. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +8 -3
  275. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +3 -3
  276. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  277. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
  278. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +80 -29
  279. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  280. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +9 -8
  281. package/src/lib/ui/context/actions.tsx +36 -10
  282. package/src/lib/ui/context/components.tsx +3 -0
  283. package/src/lib/ui/context/events.tsx +1 -1
  284. package/src/lib/ui/hooks/useClipboardEvents.ts +2 -2
  285. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  286. package/src/lib/ui/hooks/useTools.tsx +1 -1
  287. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +4 -0
  288. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -2
  289. package/src/lib/ui/kbd-utils.ts +10 -3
  290. package/src/lib/ui/version.ts +3 -3
  291. package/src/lib/ui.css +29 -2
  292. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  293. package/src/lib/utils/export/copyAs.ts +1 -24
  294. package/src/lib/utils/export/export.ts +0 -36
  295. package/src/lib/utils/export/exportAs.ts +1 -32
  296. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  297. package/src/test/A11y.test.tsx +3 -2
  298. package/src/test/ClickManager.test.ts +7 -6
  299. package/src/test/Editor.test.tsx +20 -19
  300. package/src/test/EraserTool.test.ts +184 -13
  301. package/src/test/HandTool.test.ts +10 -9
  302. package/src/test/HighlightShape.test.ts +2 -1
  303. package/src/test/SelectTool.test.ts +3 -2
  304. package/src/test/TLUserPreferences.test.ts +4 -3
  305. package/src/test/TestEditor.ts +13 -15
  306. package/src/test/TldrawEditor.test.tsx +11 -10
  307. package/src/test/ZoomTool.test.ts +7 -6
  308. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  309. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  310. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  311. package/src/test/arrows-megabus.test.tsx +5 -4
  312. package/src/test/bindings.test.tsx +24 -37
  313. package/src/test/bookmark-shapes.test.ts +1 -8
  314. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  315. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  316. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  317. package/src/test/commands/alignShapes.test.tsx +25 -24
  318. package/src/test/commands/animationSpeed.test.ts +2 -1
  319. package/src/test/commands/centerOnPoint.test.ts +3 -2
  320. package/src/test/commands/clipboard.test.ts +3 -2
  321. package/src/test/commands/createShapes.test.ts +2 -1
  322. package/src/test/commands/deleteShapes.test.ts +2 -1
  323. package/src/test/commands/distributeShapes.test.tsx +11 -10
  324. package/src/test/commands/getSvgString.test.ts +2 -1
  325. package/src/test/commands/packShapes.test.ts +5 -4
  326. package/src/test/commands/resizeShape.test.ts +2 -1
  327. package/src/test/commands/rotateShapes.test.ts +7 -6
  328. package/src/test/commands/setCamera.test.ts +4 -3
  329. package/src/test/commands/setCurrentPage.test.ts +3 -2
  330. package/src/test/commands/stackShapes.test.ts +11 -10
  331. package/src/test/commands/stretch.test.tsx +13 -12
  332. package/src/test/createDeepLink.test.tsx +2 -1
  333. package/src/test/cropping.test.ts +3 -2
  334. package/src/test/custom-clipping.test.ts +436 -0
  335. package/src/test/drawing.test.ts +2 -1
  336. package/src/test/flipShapes.test.ts +4 -3
  337. package/src/test/frames.test.ts +25 -24
  338. package/src/test/getCulledShapes.test.tsx +74 -4
  339. package/src/test/groups.test.tsx +1 -1
  340. package/src/test/handleDeepLink.test.tsx +2 -1
  341. package/src/test/maxShapes.test.ts +3 -2
  342. package/src/test/modifiers.test.ts +5 -4
  343. package/src/test/navigation.test.ts +12 -11
  344. package/src/test/panning.test.ts +2 -1
  345. package/src/test/perf/perf.test.ts +2 -1
  346. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  347. package/src/test/resizing.test.ts +39 -38
  348. package/src/test/select.test.tsx +4 -3
  349. package/src/test/selection-omnibus.test.ts +11 -10
  350. package/src/test/shapeutils.test.ts +4 -3
  351. package/src/test/translating.test.ts +9 -8
  352. package/tldraw.css +45 -5
  353. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  354. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  355. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  356. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  357. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  358. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  359. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  360. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  361. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  362. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  363. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -3,8 +3,8 @@ import {
3
3
  Box,
4
4
  clamp,
5
5
  Editor,
6
+ markEventAsHandled,
6
7
  react,
7
- stopEventPropagation,
8
8
  useAtom,
9
9
  useEditor,
10
10
  usePassThroughMouseOverEvents,
@@ -170,9 +170,14 @@ export const TldrawUiContextualToolbar = ({
170
170
  data-visible={false}
171
171
  data-testid="contextual-toolbar"
172
172
  className={classNames('tlui-contextual-toolbar', className)}
173
- onPointerDown={stopEventPropagation}
173
+ onPointerDown={markEventAsHandled}
174
174
  >
175
- <TldrawUiToolbar orientation="horizontal" className="tlui-menu" label={label}>
175
+ <TldrawUiToolbar
176
+ orientation="horizontal"
177
+ className="tlui-menu"
178
+ label={label}
179
+ tooltipSide="top"
180
+ >
176
181
  {children}
177
182
  </TldrawUiToolbar>
178
183
  </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'
@@ -118,7 +118,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
118
118
  // `onChange` with a duplicated text value.
119
119
  if (isComposing.current) return
120
120
  e.currentTarget.blur()
121
- stopEventPropagation(e)
121
+ e.stopPropagation()
122
122
  onComplete?.(e.currentTarget.value)
123
123
  break
124
124
  }
@@ -126,7 +126,7 @@ export const TldrawUiInput = React.forwardRef<HTMLInputElement, TLUiInputProps>(
126
126
  e.currentTarget.value = rInitialValue.current
127
127
  onCancel?.(e.currentTarget.value)
128
128
  e.currentTarget.blur()
129
- stopEventPropagation(e)
129
+ e.stopPropagation()
130
130
  break
131
131
  }
132
132
  }
@@ -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'
@@ -24,18 +25,20 @@ export interface TldrawUiTooltipProps {
24
25
  delayDuration?: number
25
26
  }
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
36
+ }
37
+
27
38
  // Singleton tooltip manager
28
39
  class TooltipManager {
29
40
  private static instance: TooltipManager | null = null
30
- private currentTooltip = atom<{
31
- id: string
32
- content: ReactNode
33
- side: 'top' | 'right' | 'bottom' | 'left'
34
- sideOffset: number
35
- showOnMobile: boolean
36
- targetElement: HTMLElement
37
- delayDuration: number | undefined
38
- } | null>('current tooltip', null)
41
+ private currentTooltip = atom<CurrentTooltip | null>('current tooltip', null)
39
42
  private destroyTimeoutId: number | null = null
40
43
 
41
44
  static getInstance(): TooltipManager {
@@ -52,7 +55,7 @@ class TooltipManager {
52
55
  side: 'top' | 'right' | 'bottom' | 'left',
53
56
  sideOffset: number,
54
57
  showOnMobile: boolean,
55
- delayDuration: number | undefined
58
+ delayDuration: number
56
59
  ) {
57
60
  // Clear any existing destroy timeout
58
61
  if (this.destroyTimeoutId) {
@@ -72,6 +75,15 @@ class TooltipManager {
72
75
  })
73
76
  }
74
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
84
+ })
85
+ }
86
+
75
87
  hideTooltip(editor: Editor | null, tooltipId: string, instant: boolean = false) {
76
88
  const hide = () => {
77
89
  // Only hide if this is the current tooltip
@@ -139,11 +151,10 @@ export function TldrawUiTooltipProvider({ children }: TldrawUiTooltipProviderPro
139
151
 
140
152
  // The singleton tooltip component that renders once
141
153
  function TooltipSingleton() {
142
- const editor = useMaybeEditor()
143
154
  const [isOpen, setIsOpen] = useState(false)
144
155
  const triggerRef = useRef<HTMLDivElement>(null)
145
156
  const isFirstShowRef = useRef(true)
146
- const showTimeoutRef = useRef<number | null>(null)
157
+ const editor = useMaybeEditor()
147
158
 
148
159
  const currentTooltip = useValue(
149
160
  'current tooltip',
@@ -151,14 +162,31 @@ function TooltipSingleton() {
151
162
  []
152
163
  )
153
164
 
154
- // 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)
155
168
  useEffect(() => {
156
- // Clear any existing show timeout
157
- if (showTimeoutRef.current) {
158
- clearTimeout(showTimeoutRef.current)
159
- 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) {
177
+ tooltipManager.hideTooltip(editor, currentTooltip.id)
178
+ }
160
179
  }
161
180
 
181
+ document.addEventListener('keydown', handleKeyDown)
182
+ return () => {
183
+ document.removeEventListener('keydown', handleKeyDown)
184
+ }
185
+ }, [editor, currentTooltip])
186
+
187
+ // Update open state and trigger position
188
+ useEffect(() => {
189
+ let timer: ReturnType<typeof setTimeout> | null = null
162
190
  if (currentTooltip && triggerRef.current) {
163
191
  // Position the invisible trigger element over the active element
164
192
  const activeRect = currentTooltip.targetElement.getBoundingClientRect()
@@ -173,11 +201,12 @@ function TooltipSingleton() {
173
201
  trigger.style.zIndex = '9999'
174
202
 
175
203
  // Handle delay for first show
176
- if (isFirstShowRef.current && editor) {
177
- showTimeoutRef.current = editor.timers.setTimeout(() => {
204
+ if (isFirstShowRef.current) {
205
+ // eslint-disable-next-line no-restricted-globals
206
+ timer = setTimeout(() => {
178
207
  setIsOpen(true)
179
208
  isFirstShowRef.current = false
180
- }, currentTooltip.delayDuration ?? editor.options.tooltipDelayMs)
209
+ }, currentTooltip.delayDuration)
181
210
  } else {
182
211
  // Subsequent tooltips show immediately
183
212
  setIsOpen(true)
@@ -188,7 +217,13 @@ function TooltipSingleton() {
188
217
  // Reset first show state after tooltip is hidden
189
218
  isFirstShowRef.current = true
190
219
  }
191
- }, [editor, currentTooltip])
220
+
221
+ return () => {
222
+ if (timer !== null) {
223
+ clearTimeout(timer)
224
+ }
225
+ }
226
+ }, [currentTooltip])
192
227
 
193
228
  if (!currentTooltip) {
194
229
  return null
@@ -231,6 +266,7 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
231
266
  const editor = useMaybeEditor()
232
267
  const tooltipId = useRef<string>(uniqueId())
233
268
  const hasProvider = useContext(TooltipSingletonContext)
269
+ const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
234
270
 
235
271
  const orientationCtx = useTldrawUiOrientation()
236
272
  const sideToUse = side ?? orientationCtx.tooltipSide
@@ -244,20 +280,35 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
244
280
  }
245
281
  }, [editor, hasProvider])
246
282
 
283
+ useLayoutEffect(() => {
284
+ if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
285
+ tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
286
+ ...tooltip,
287
+ content,
288
+ side: sideToUse,
289
+ sideOffset,
290
+ showOnMobile,
291
+ }))
292
+ }
293
+ }, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
294
+
247
295
  // Don't show tooltip if disabled, no content, or UI labels are disabled
248
296
  if (disabled || !content) {
249
297
  return <>{children}</>
250
298
  }
251
299
 
300
+ let delayDurationToUse
301
+ if (showUiLabels) {
302
+ delayDurationToUse = 0
303
+ } else {
304
+ delayDurationToUse =
305
+ delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
306
+ }
307
+
252
308
  // Fallback to old behavior if no provider
253
309
  if (!hasProvider) {
254
310
  return (
255
- <_Tooltip.Root
256
- delayDuration={
257
- delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
258
- }
259
- disableHoverableContent
260
- >
311
+ <_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent>
261
312
  <_Tooltip.Trigger asChild ref={ref}>
262
313
  {children}
263
314
  </_Tooltip.Trigger>
@@ -288,7 +339,7 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
288
339
  sideToUse,
289
340
  sideOffset,
290
341
  showOnMobile,
291
- delayDuration
342
+ delayDurationToUse
292
343
  )
293
344
  }
294
345
 
@@ -306,7 +357,7 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
306
357
  sideToUse,
307
358
  sideOffset,
308
359
  showOnMobile,
309
- delayDuration
360
+ delayDurationToUse
310
361
  )
311
362
  }
312
363
 
@@ -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 = {
@@ -350,6 +350,7 @@ function useDraggableEvents(
350
350
  })
351
351
 
352
352
  tooltipManager.hideAllTooltips()
353
+ editor.getContainer().focus()
353
354
  })
354
355
  }
355
356
  }
@@ -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}
@@ -36,6 +36,7 @@ import { useTranslation } from '../hooks/useTranslation/useTranslation'
36
36
  import { TLUiIconType } from '../icon-types'
37
37
  import { TLUiOverrideHelpers, useDefaultHelpers } from '../overrides'
38
38
  import { useA11y } from './a11y'
39
+ import { useTldrawUiComponents } from './components'
39
40
  import { TLUiEventSource, useUiEvents } from './events'
40
41
 
41
42
  /** @public */
@@ -98,6 +99,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
98
99
  const _editor = useMaybeEditor()
99
100
  const showCollaborationUi = useShowCollaborationUi()
100
101
  const helpers = useDefaultHelpers()
102
+ const components = useTldrawUiComponents()
101
103
  const trackEvent = useUiEvents()
102
104
  const a11y = useA11y()
103
105
  const msg = useTranslation()
@@ -176,7 +178,9 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
176
178
  kbd: 'cmd+alt+/,ctrl+alt+/',
177
179
  onSelect(source) {
178
180
  trackEvent('open-kbd-shortcuts', { source })
179
- helpers.addDialog({ component: DefaultKeyboardShortcutsDialog })
181
+ helpers.addDialog({
182
+ component: components.KeyboardShortcutsDialog ?? DefaultKeyboardShortcutsDialog,
183
+ })
180
184
  },
181
185
  },
182
186
  {
@@ -221,7 +225,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
221
225
  if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
222
226
  if (ids.length === 0) return
223
227
  trackEvent('export-as', { format: 'svg', source })
224
- helpers.exportAs(ids, 'svg', getExportName(editor, defaultDocumentName))
228
+ helpers.exportAs(ids, { format: 'svg', name: getExportName(editor, defaultDocumentName) })
225
229
  },
226
230
  },
227
231
  {
@@ -237,7 +241,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
237
241
  if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
238
242
  if (ids.length === 0) return
239
243
  trackEvent('export-as', { format: 'png', source })
240
- helpers.exportAs(ids, 'png', getExportName(editor, defaultDocumentName))
244
+ helpers.exportAs(ids, { format: 'png', name: getExportName(editor, defaultDocumentName) })
241
245
  },
242
246
  },
243
247
  {
@@ -253,11 +257,10 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
253
257
  if (ids.length === 0) ids = Array.from(editor.getCurrentPageShapeIds().values())
254
258
  if (ids.length === 0) return
255
259
  trackEvent('export-all-as', { format: 'svg', source })
256
- helpers.exportAs(
257
- Array.from(editor.getCurrentPageShapeIds()),
258
- 'svg',
259
- getExportName(editor, defaultDocumentName)
260
- )
260
+ helpers.exportAs(Array.from(editor.getCurrentPageShapeIds()), {
261
+ format: 'svg',
262
+ name: getExportName(editor, defaultDocumentName),
263
+ })
261
264
  },
262
265
  },
263
266
  {
@@ -272,7 +275,7 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
272
275
  const ids = Array.from(editor.getCurrentPageShapeIds().values())
273
276
  if (ids.length === 0) return
274
277
  trackEvent('export-all-as', { format: 'png', source })
275
- helpers.exportAs(ids, 'png', getExportName(editor, defaultDocumentName))
278
+ helpers.exportAs(ids, { format: 'png', name: getExportName(editor, defaultDocumentName) })
276
279
  },
277
280
  },
278
281
  {
@@ -1581,6 +1584,19 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1581
1584
  onSelect: async (source) => {
1582
1585
  if (!canApplySelectionAction()) return
1583
1586
 
1587
+ const onlySelectedShape = editor.getOnlySelectedShape()
1588
+ if (
1589
+ onlySelectedShape &&
1590
+ (editor.isShapeOfType<TLImageShape>(onlySelectedShape, 'image') ||
1591
+ editor.isShapeOfType<TLVideoShape>(onlySelectedShape, 'video'))
1592
+ ) {
1593
+ const firstToolbarButton = editor
1594
+ .getContainer()
1595
+ .querySelector('.tlui-contextual-toolbar button:first-child') as HTMLElement | null
1596
+ firstToolbarButton?.focus()
1597
+ return
1598
+ }
1599
+
1584
1600
  const firstButton = editor
1585
1601
  .getContainer()
1586
1602
  .querySelector('.tlui-style-panel button') as HTMLElement | null
@@ -1755,7 +1771,17 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1755
1771
  }
1756
1772
 
1757
1773
  return actions
1758
- }, [helpers, _editor, trackEvent, overrides, defaultDocumentName, showCollaborationUi, msg, a11y])
1774
+ }, [
1775
+ helpers,
1776
+ _editor,
1777
+ trackEvent,
1778
+ overrides,
1779
+ defaultDocumentName,
1780
+ showCollaborationUi,
1781
+ msg,
1782
+ a11y,
1783
+ components,
1784
+ ])
1759
1785
 
1760
1786
  return <ActionsContext.Provider value={asActions(actions)}>{children}</ActionsContext.Provider>
1761
1787
  }
@@ -12,6 +12,7 @@ import {
12
12
  import { CursorChatBubble } from '../components/CursorChatBubble'
13
13
  import { DefaultDebugMenu } from '../components/DebugMenu/DefaultDebugMenu'
14
14
  import { DefaultDebugPanel } from '../components/DefaultDebugPanel'
15
+ import { DefaultFollowingIndicator } from '../components/DefaultFollowingIndicator'
15
16
  import { DefaultMenuPanel } from '../components/DefaultMenuPanel'
16
17
  import { DefaultDialogs } from '../components/Dialogs'
17
18
  import { TLUiHelpMenuProps } from '../components/HelpMenu/DefaultHelpMenu'
@@ -72,6 +73,7 @@ export interface TLUiComponents {
72
73
  Dialogs?: ComponentType | null
73
74
  Toasts?: ComponentType | null
74
75
  A11y?: ComponentType | null
76
+ FollowingIndicator?: ComponentType | null
75
77
  }
76
78
 
77
79
  const TldrawUiComponentsContext = createContext<TLUiComponents | null>(null)
@@ -119,6 +121,7 @@ export function TldrawUiComponentsProvider({
119
121
  Dialogs: DefaultDialogs,
120
122
  Toasts: DefaultToasts,
121
123
  A11y: DefaultA11yAnnouncer,
124
+ FollowingIndicator: DefaultFollowingIndicator,
122
125
  ..._overrides,
123
126
  }),
124
127
  [_overrides, showCollaborationUi]
@@ -123,7 +123,7 @@ export interface TLUiEventMap {
123
123
  'shrink-shapes': null
124
124
  'flatten-to-image': null
125
125
  'a11y-repeat-shape-announce': null
126
- 'open-url': { url: string }
126
+ 'open-url': { destinationUrl: string }
127
127
  'open-context-menu': null
128
128
  'adjust-shape-styles': null
129
129
  'copy-link': null
@@ -7,8 +7,8 @@ import {
7
7
  assert,
8
8
  compact,
9
9
  isDefined,
10
+ markEventAsHandled,
10
11
  preventDefault,
11
- stopEventPropagation,
12
12
  uniq,
13
13
  useEditor,
14
14
  useMaybeEditor,
@@ -763,7 +763,7 @@ export function useNativeClipboardEvents() {
763
763
 
764
764
  const paste = (e: ClipboardEvent) => {
765
765
  if (disablingMiddleClickPaste) {
766
- stopEventPropagation(e)
766
+ markEventAsHandled(e)
767
767
  return
768
768
  }
769
769