tldraw 3.16.0-canary.e9c30b532b82 → 3.16.0-canary.ea008b31887f

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 (301) hide show
  1. package/dist-cjs/index.d.ts +227 -103
  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 +5 -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/frame/FrameShapeUtil.js +8 -1
  11. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  13. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  14. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -0
  15. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  17. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  18. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  19. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  20. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  21. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +0 -2
  22. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  23. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  24. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  25. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  26. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  27. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  28. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  29. package/dist-cjs/lib/ui/TldrawUi.js +13 -12
  30. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  31. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  32. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  33. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  34. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  35. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  36. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  37. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  38. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  39. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  40. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  41. package/dist-cjs/lib/ui/components/{primitives/TldrawUiButtonPicker.js → StylePanel/StylePanelButtonPicker.js} +52 -45
  42. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  43. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  44. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  45. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  46. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  47. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +24 -21
  48. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  49. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  50. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  51. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +3 -2
  52. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  53. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
  54. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  55. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  56. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  57. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +3 -3
  58. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  59. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +10 -1
  60. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  61. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  62. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  63. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +2 -0
  64. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  65. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +83 -42
  66. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  67. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +7 -6
  68. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  69. package/dist-cjs/lib/ui/context/actions.js +23 -10
  70. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  71. package/dist-cjs/lib/ui/context/components.js +2 -0
  72. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  73. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  74. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  75. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  76. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  77. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  78. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  79. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +4 -2
  80. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  81. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  82. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  83. package/dist-cjs/lib/ui/version.js +3 -3
  84. package/dist-cjs/lib/ui/version.js.map +1 -1
  85. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  86. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  87. package/dist-cjs/lib/utils/export/export.js +0 -20
  88. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  89. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  90. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  91. package/dist-esm/index.d.mts +227 -103
  92. package/dist-esm/index.mjs +61 -29
  93. package/dist-esm/index.mjs.map +2 -2
  94. package/dist-esm/lib/Tldraw.mjs +14 -4
  95. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  96. package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -4
  97. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  98. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  99. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  100. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +8 -1
  101. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  102. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  103. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  104. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -0
  105. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  106. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  107. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  108. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  109. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  110. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  111. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +0 -2
  112. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  113. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  114. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  115. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  116. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  117. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  118. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  119. package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
  120. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  121. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  122. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  123. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  124. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  125. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  126. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  127. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  128. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  129. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  130. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  131. package/dist-esm/lib/ui/components/{primitives/TldrawUiButtonPicker.mjs → StylePanel/StylePanelButtonPicker.mjs} +54 -43
  132. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  133. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  134. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  135. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  136. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  137. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +21 -18
  138. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  139. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  140. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  141. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +3 -2
  142. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  143. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
  144. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  145. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  146. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  147. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +3 -3
  148. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  149. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +10 -1
  150. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  151. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  152. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  153. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +2 -0
  154. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  155. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +84 -42
  156. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  157. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +7 -6
  158. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  159. package/dist-esm/lib/ui/context/actions.mjs +23 -10
  160. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  161. package/dist-esm/lib/ui/context/components.mjs +2 -0
  162. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  163. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  164. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  165. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  166. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  167. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  168. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +4 -2
  169. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  170. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  171. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  172. package/dist-esm/lib/ui/version.mjs +3 -3
  173. package/dist-esm/lib/ui/version.mjs.map +1 -1
  174. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  175. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  176. package/dist-esm/lib/utils/export/export.mjs +0 -20
  177. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  178. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  179. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  180. package/package.json +11 -34
  181. package/src/index.ts +44 -22
  182. package/src/lib/Tldraw.tsx +15 -2
  183. package/src/lib/defaultExternalContentHandlers.ts +12 -4
  184. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  185. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +6 -5
  186. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  187. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  188. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  189. package/src/lib/shapes/frame/FrameShapeUtil.tsx +9 -0
  190. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  191. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
  192. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  193. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  194. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  195. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  196. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  197. package/src/lib/shapes/shared/useEditablePlainText.ts +0 -6
  198. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  199. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  200. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  201. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  202. package/src/lib/ui/TldrawUi.tsx +16 -10
  203. package/src/lib/ui/assetUrls.ts +13 -10
  204. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  205. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  206. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  207. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  208. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +63 -50
  209. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  210. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  211. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  212. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  213. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +4 -3
  214. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
  215. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  216. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +5 -5
  217. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +6 -1
  218. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  219. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +3 -0
  220. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +94 -30
  221. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +9 -8
  222. package/src/lib/ui/context/actions.tsx +23 -10
  223. package/src/lib/ui/context/components.tsx +3 -0
  224. package/src/lib/ui/context/events.tsx +1 -1
  225. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  226. package/src/lib/ui/hooks/useTools.tsx +1 -1
  227. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
  228. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +4 -2
  229. package/src/lib/ui/kbd-utils.ts +10 -3
  230. package/src/lib/ui/version.ts +3 -3
  231. package/src/lib/ui.css +19 -2
  232. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  233. package/src/lib/utils/export/copyAs.ts +1 -24
  234. package/src/lib/utils/export/export.ts +0 -36
  235. package/src/lib/utils/export/exportAs.ts +1 -32
  236. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  237. package/src/test/A11y.test.tsx +3 -2
  238. package/src/test/ClickManager.test.ts +7 -6
  239. package/src/test/Editor.test.tsx +20 -19
  240. package/src/test/EraserTool.test.ts +184 -13
  241. package/src/test/HandTool.test.ts +10 -9
  242. package/src/test/HighlightShape.test.ts +2 -1
  243. package/src/test/SelectTool.test.ts +3 -2
  244. package/src/test/TLUserPreferences.test.ts +4 -3
  245. package/src/test/TestEditor.ts +13 -15
  246. package/src/test/TldrawEditor.test.tsx +11 -10
  247. package/src/test/ZoomTool.test.ts +7 -6
  248. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  249. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  250. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  251. package/src/test/arrows-megabus.test.tsx +5 -4
  252. package/src/test/bindings.test.tsx +24 -37
  253. package/src/test/bookmark-shapes.test.ts +1 -8
  254. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  255. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  256. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  257. package/src/test/commands/alignShapes.test.tsx +25 -24
  258. package/src/test/commands/animationSpeed.test.ts +2 -1
  259. package/src/test/commands/centerOnPoint.test.ts +3 -2
  260. package/src/test/commands/clipboard.test.ts +3 -2
  261. package/src/test/commands/createShapes.test.ts +2 -1
  262. package/src/test/commands/deleteShapes.test.ts +2 -1
  263. package/src/test/commands/distributeShapes.test.tsx +11 -10
  264. package/src/test/commands/getSvgString.test.ts +2 -1
  265. package/src/test/commands/packShapes.test.ts +5 -4
  266. package/src/test/commands/resizeShape.test.ts +2 -1
  267. package/src/test/commands/rotateShapes.test.ts +7 -6
  268. package/src/test/commands/setCamera.test.ts +4 -3
  269. package/src/test/commands/setCurrentPage.test.ts +3 -2
  270. package/src/test/commands/stackShapes.test.ts +11 -10
  271. package/src/test/commands/stretch.test.tsx +13 -12
  272. package/src/test/createDeepLink.test.tsx +2 -1
  273. package/src/test/cropping.test.ts +3 -2
  274. package/src/test/custom-clipping.test.ts +436 -0
  275. package/src/test/drawing.test.ts +2 -1
  276. package/src/test/flipShapes.test.ts +4 -3
  277. package/src/test/frames.test.ts +25 -24
  278. package/src/test/getCulledShapes.test.tsx +74 -4
  279. package/src/test/groups.test.tsx +1 -1
  280. package/src/test/handleDeepLink.test.tsx +2 -1
  281. package/src/test/maxShapes.test.ts +3 -2
  282. package/src/test/modifiers.test.ts +5 -4
  283. package/src/test/navigation.test.ts +12 -11
  284. package/src/test/panning.test.ts +2 -1
  285. package/src/test/perf/perf.test.ts +2 -1
  286. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  287. package/src/test/resizing.test.ts +39 -38
  288. package/src/test/select.test.tsx +4 -3
  289. package/src/test/selection-omnibus.test.ts +11 -10
  290. package/src/test/shapeutils.test.ts +4 -3
  291. package/src/test/translating.test.ts +9 -8
  292. package/tldraw.css +35 -5
  293. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  294. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  295. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  296. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  297. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  298. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  299. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  300. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  301. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -1,7 +1,9 @@
1
+ import { tltime } from '@tldraw/editor'
1
2
  import { Slider as _Slider } from 'radix-ui'
2
3
  import React, { useCallback, useEffect, useState } from 'react'
3
4
  import { TLUiTranslationKey } from '../../hooks/useTranslation/TLUiTranslationKey'
4
5
  import { useTranslation } from '../../hooks/useTranslation/useTranslation'
6
+ import { TldrawUiTooltip, tooltipManager } from './TldrawUiTooltip'
5
7
 
6
8
  /** @public */
7
9
  export interface TLUiSliderProps {
@@ -11,7 +13,7 @@ export interface TLUiSliderProps {
11
13
  label: string
12
14
  title: string
13
15
  onValueChange(value: number): void
14
- onHistoryMark(id: string): void
16
+ onHistoryMark?(id: string): void
15
17
  'data-testid'?: string
16
18
  ariaValueModifier?: number
17
19
  }
@@ -32,6 +34,7 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
32
34
  ref
33
35
  ) {
34
36
  const msg = useTranslation()
37
+ const [titleAndLabel, setTitleAndLabel] = useState('')
35
38
 
36
39
  // XXX: Radix starts out our slider with a tabIndex of 0
37
40
  // This causes some tab focusing issues, most prevelant in MobileStylePanel,
@@ -49,9 +52,25 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
49
52
  )
50
53
 
51
54
  const handlePointerDown = useCallback(() => {
52
- onHistoryMark('click slider')
55
+ tooltipManager.hideAllTooltips()
56
+ onHistoryMark?.('click slider')
53
57
  }, [onHistoryMark])
54
58
 
59
+ // N.B. This is a bit silly. The Radix slider auto-focuses which
60
+ // triggers TldrawUiTooltip handleFocus when we dbl-click to edit an image,
61
+ // which in turn makes the tooltip display prematurely.
62
+ // This makes it wait until we've focused to show the tooltip.
63
+ useEffect(() => {
64
+ const timeout = tltime.setTimeout(
65
+ 'set title and label',
66
+ () => {
67
+ setTitleAndLabel(title + ' — ' + msg(label as TLUiTranslationKey))
68
+ },
69
+ 0
70
+ )
71
+ return () => clearTimeout(timeout)
72
+ }, [label, msg, title])
73
+
55
74
  // N.B. Annoying. For a11y purposes, we need Tab to work.
56
75
  // For some reason, Radix has some custom behavior here
57
76
  // that interferes with tabbing past the slider and then
@@ -64,36 +83,37 @@ export const TldrawUiSlider = React.forwardRef<HTMLDivElement, TLUiSliderProps>(
64
83
 
65
84
  return (
66
85
  <div className="tlui-slider__container">
67
- <_Slider.Root
68
- data-testid={testId}
69
- className="tlui-slider"
70
- dir="ltr"
71
- min={min ?? 0}
72
- max={steps}
73
- step={1}
74
- value={value !== null ? [value] : undefined}
75
- onPointerDown={handlePointerDown}
76
- onValueChange={handleValueChange}
77
- onKeyDownCapture={handleKeyEvent}
78
- onKeyUpCapture={handleKeyEvent}
79
- title={title + ' — ' + msg(label as TLUiTranslationKey)}
80
- >
81
- <_Slider.Track className="tlui-slider__track" dir="ltr">
82
- {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
83
- </_Slider.Track>
84
- {value !== null && (
85
- <_Slider.Thumb
86
- aria-valuemin={(min ?? 0) * ariaValueModifier}
87
- aria-valuenow={value * ariaValueModifier}
88
- aria-valuemax={steps * ariaValueModifier}
89
- aria-label={title + ' — ' + msg(label as TLUiTranslationKey)}
90
- className="tlui-slider__thumb"
91
- dir="ltr"
92
- ref={ref}
93
- tabIndex={tabIndex}
94
- />
95
- )}
96
- </_Slider.Root>
86
+ <TldrawUiTooltip content={titleAndLabel}>
87
+ <_Slider.Root
88
+ data-testid={testId}
89
+ className="tlui-slider"
90
+ dir="ltr"
91
+ min={min ?? 0}
92
+ max={steps}
93
+ step={1}
94
+ value={value !== null ? [value] : undefined}
95
+ onPointerDown={handlePointerDown}
96
+ onValueChange={handleValueChange}
97
+ onKeyDownCapture={handleKeyEvent}
98
+ onKeyUpCapture={handleKeyEvent}
99
+ >
100
+ <_Slider.Track className="tlui-slider__track" dir="ltr">
101
+ {value !== null && <_Slider.Range className="tlui-slider__range" dir="ltr" />}
102
+ </_Slider.Track>
103
+ {value !== null && (
104
+ <_Slider.Thumb
105
+ aria-valuemin={(min ?? 0) * ariaValueModifier}
106
+ aria-valuenow={value * ariaValueModifier}
107
+ aria-valuemax={steps * ariaValueModifier}
108
+ aria-label={titleAndLabel}
109
+ className="tlui-slider__thumb"
110
+ dir="ltr"
111
+ ref={ref}
112
+ tabIndex={tabIndex}
113
+ />
114
+ )}
115
+ </_Slider.Root>
116
+ </TldrawUiTooltip>
97
117
  </div>
98
118
  )
99
119
  })
@@ -94,6 +94,7 @@ export interface TLUiToolbarToggleGroupProps extends React.HTMLAttributes<HTMLDi
94
94
  // TODO: fix up this type later
95
95
  defaultValue?: any
96
96
  type: 'single' | 'multiple'
97
+ asChild?: boolean
97
98
  }
98
99
 
99
100
  /** @public @react */
@@ -101,10 +102,12 @@ export const TldrawUiToolbarToggleGroup = ({
101
102
  children,
102
103
  className,
103
104
  type,
105
+ asChild,
104
106
  ...props
105
107
  }: TLUiToolbarToggleGroupProps) => {
106
108
  return (
107
109
  <_Toolbar.ToggleGroup
110
+ asChild={asChild}
108
111
  type={type}
109
112
  {...props}
110
113
  // TODO: this fixes a bug in Radix until they fix it.
@@ -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,18 @@ 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)
151
171
  }
172
+ }, [cameraState, isOpen, currentTooltip, editor])
152
173
 
174
+ // Update open state and trigger position
175
+ useEffect(() => {
176
+ let timer: ReturnType<typeof setTimeout> | null = null
153
177
  if (currentTooltip && triggerRef.current) {
154
178
  // Position the invisible trigger element over the active element
155
179
  const activeRect = currentTooltip.targetElement.getBoundingClientRect()
@@ -164,11 +188,12 @@ function TooltipSingleton() {
164
188
  trigger.style.zIndex = '9999'
165
189
 
166
190
  // Handle delay for first show
167
- if (isFirstShowRef.current && editor) {
168
- showTimeoutRef.current = editor.timers.setTimeout(() => {
191
+ if (isFirstShowRef.current) {
192
+ // eslint-disable-next-line no-restricted-globals
193
+ timer = setTimeout(() => {
169
194
  setIsOpen(true)
170
195
  isFirstShowRef.current = false
171
- }, editor.options.tooltipDelayMs)
196
+ }, currentTooltip.delayDuration)
172
197
  } else {
173
198
  // Subsequent tooltips show immediately
174
199
  setIsOpen(true)
@@ -179,7 +204,13 @@ function TooltipSingleton() {
179
204
  // Reset first show state after tooltip is hidden
180
205
  isFirstShowRef.current = true
181
206
  }
182
- }, [editor, currentTooltip])
207
+
208
+ return () => {
209
+ if (timer !== null) {
210
+ clearTimeout(timer)
211
+ }
212
+ }
213
+ }, [currentTooltip])
183
214
 
184
215
  if (!currentTooltip) {
185
216
  return null
@@ -207,10 +238,22 @@ function TooltipSingleton() {
207
238
 
208
239
  /** @public @react */
209
240
  export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProps>(
210
- ({ children, content, side, sideOffset = 5, disabled = false }, ref) => {
241
+ (
242
+ {
243
+ children,
244
+ content,
245
+ side,
246
+ sideOffset = 5,
247
+ disabled = false,
248
+ showOnMobile = false,
249
+ delayDuration,
250
+ },
251
+ ref
252
+ ) => {
211
253
  const editor = useMaybeEditor()
212
254
  const tooltipId = useRef<string>(uniqueId())
213
255
  const hasProvider = useContext(TooltipSingletonContext)
256
+ const showUiLabels = useValue('showUiLabels', () => editor?.user.getShowUiLabels(), [editor])
214
257
 
215
258
  const orientationCtx = useTldrawUiOrientation()
216
259
  const sideToUse = side ?? orientationCtx.tooltipSide
@@ -224,18 +267,35 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
224
267
  }
225
268
  }, [editor, hasProvider])
226
269
 
270
+ useLayoutEffect(() => {
271
+ if (hasProvider && tooltipManager.getCurrentTooltipData()?.id === tooltipId.current) {
272
+ tooltipManager.updateCurrentTooltip(tooltipId.current, (tooltip) => ({
273
+ ...tooltip,
274
+ content,
275
+ side: sideToUse,
276
+ sideOffset,
277
+ showOnMobile,
278
+ }))
279
+ }
280
+ }, [content, sideToUse, sideOffset, showOnMobile, hasProvider])
281
+
227
282
  // Don't show tooltip if disabled, no content, or UI labels are disabled
228
283
  if (disabled || !content) {
229
284
  return <>{children}</>
230
285
  }
231
286
 
287
+ let delayDurationToUse
288
+ if (showUiLabels) {
289
+ delayDurationToUse = 0
290
+ } else {
291
+ delayDurationToUse =
292
+ delayDuration ?? (editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS)
293
+ }
294
+
232
295
  // Fallback to old behavior if no provider
233
296
  if (!hasProvider) {
234
297
  return (
235
- <_Tooltip.Root
236
- delayDuration={editor?.options.tooltipDelayMs || DEFAULT_TOOLTIP_DELAY_MS}
237
- disableHoverableContent
238
- >
298
+ <_Tooltip.Root delayDuration={delayDurationToUse} disableHoverableContent>
239
299
  <_Tooltip.Trigger asChild ref={ref}>
240
300
  {children}
241
301
  </_Tooltip.Trigger>
@@ -264,7 +324,9 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
264
324
  content,
265
325
  event.currentTarget as HTMLElement,
266
326
  sideToUse,
267
- sideOffset
327
+ sideOffset,
328
+ showOnMobile,
329
+ delayDurationToUse
268
330
  )
269
331
  }
270
332
 
@@ -280,7 +342,9 @@ export const TldrawUiTooltip = forwardRef<HTMLButtonElement, TldrawUiTooltipProp
280
342
  content,
281
343
  event.currentTarget as HTMLElement,
282
344
  sideToUse,
283
- sideOffset
345
+ sideOffset,
346
+ showOnMobile,
347
+ delayDurationToUse
284
348
  )
285
349
  }
286
350
 
@@ -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
  {
@@ -1755,7 +1758,17 @@ export function ActionsProvider({ overrides, children }: ActionsProviderProps) {
1755
1758
  }
1756
1759
 
1757
1760
  return actions
1758
- }, [helpers, _editor, trackEvent, overrides, defaultDocumentName, showCollaborationUi, msg, a11y])
1761
+ }, [
1762
+ helpers,
1763
+ _editor,
1764
+ trackEvent,
1765
+ overrides,
1766
+ defaultDocumentName,
1767
+ showCollaborationUi,
1768
+ msg,
1769
+ a11y,
1770
+ components,
1771
+ ])
1759
1772
 
1760
1773
  return <ActionsContext.Provider value={asActions(actions)}>{children}</ActionsContext.Provider>
1761
1774
  }
@@ -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
@@ -11,12 +11,13 @@ export function useExportAs() {
11
11
  const msg = useTranslation()
12
12
 
13
13
  return useCallback(
14
- (ids: TLShapeId[], format: TLExportType = 'png', name: string | undefined) => {
14
+ (ids: TLShapeId[], opts: { format?: TLExportType; name?: string; scale?: number } = {}) => {
15
15
  assert(editor, 'useExportAs: editor is required')
16
+ const { format = 'png', name, scale = 1 } = opts
16
17
  exportAs(editor, ids, {
17
18
  format,
18
19
  name,
19
- scale: 1,
20
+ scale,
20
21
  }).catch((e) => {
21
22
  console.error(e.message)
22
23
  addToast({
@@ -176,7 +176,7 @@ export function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {
176
176
  editor.createShape({
177
177
  id,
178
178
  type: 'arrow',
179
- props: { start: { x: 0, y: 0 }, end: { x: 200, y: 0 } },
179
+ props: { start: { x: 0, y: 200 }, end: { x: 200, y: 0 } },
180
180
  }),
181
181
  })
182
182
  trackEvent('drag-tool', { source, id: 'arrow' })
@@ -186,6 +186,7 @@ export type TLUiTranslationKey =
186
186
  | 'geo-style.pentagon'
187
187
  | 'geo-style.rectangle'
188
188
  | 'geo-style.rhombus'
189
+ | 'geo-style.rhombus-2'
189
190
  | 'geo-style.star'
190
191
  | 'geo-style.trapezoid'
191
192
  | 'geo-style.triangle'
@@ -260,6 +261,7 @@ export type TLUiTranslationKey =
260
261
  | 'tool.aspect-ratio.wide'
261
262
  | 'tool.image-toolbar-title'
262
263
  | 'tool.image-crop'
264
+ | 'tool.image-crop-confirm'
263
265
  | 'tool.media-alt-text'
264
266
  | 'tool.media-alt-text-desc'
265
267
  | 'tool.media-alt-text-confirm'
@@ -92,9 +92,9 @@ export const DEFAULT_TRANSLATION = {
92
92
  'action.toggle-wrap-mode': 'Toggle Select on wrap',
93
93
  'action.toggle-reduce-motion.menu': 'Reduce motion',
94
94
  'action.toggle-reduce-motion': 'Toggle reduce motion',
95
- 'action.toggle-keyboard-shortcuts.menu': 'Keyboard shortcuts',
95
+ 'action.toggle-keyboard-shortcuts.menu': 'Enable keyboard shortcuts',
96
96
  'action.toggle-keyboard-shortcuts': 'Toggle keyboard shortcuts',
97
- 'action.toggle-ui-labels.menu': 'UI labels',
97
+ 'action.toggle-ui-labels.menu': 'Enable UI labels',
98
98
  'action.toggle-ui-labels': 'Toggle UI labels',
99
99
  'action.toggle-edge-scrolling.menu': 'Edge scrolling',
100
100
  'action.toggle-edge-scrolling': 'Toggle edge scrolling',
@@ -187,6 +187,7 @@ export const DEFAULT_TRANSLATION = {
187
187
  'geo-style.pentagon': 'Pentagon',
188
188
  'geo-style.rectangle': 'Rectangle',
189
189
  'geo-style.rhombus': 'Rhombus',
190
+ 'geo-style.rhombus-2': 'Rhombus left',
190
191
  'geo-style.star': 'Star',
191
192
  'geo-style.trapezoid': 'Trapezoid',
192
193
  'geo-style.triangle': 'Triangle',
@@ -261,6 +262,7 @@ export const DEFAULT_TRANSLATION = {
261
262
  'tool.aspect-ratio.wide': 'Wide (16:9)',
262
263
  'tool.image-toolbar-title': 'Image tools',
263
264
  'tool.image-crop': 'Crop image',
265
+ 'tool.image-crop-confirm': 'Confirm',
264
266
  'tool.media-alt-text': 'Alternative text',
265
267
  'tool.media-alt-text-desc': 'Give a description…',
266
268
  'tool.media-alt-text-confirm': 'Confirm',
@@ -31,9 +31,16 @@ export function kbd(str: string) {
31
31
  )
32
32
  .flat()
33
33
  .map((sub, index) => {
34
- if (sub === '__CTRL__') return 'Ctrl'
35
- if (sub === '__ALT__') return 'Alt'
36
- const modifiedKey = sub[0].toUpperCase() + sub.slice(1)
34
+ if (sub[0] === '+') return []
35
+
36
+ let modifiedKey
37
+ if (sub === '__CTRL__') {
38
+ modifiedKey = 'Ctrl'
39
+ } else if (sub === '__ALT__') {
40
+ modifiedKey = 'Alt'
41
+ } else {
42
+ modifiedKey = sub[0].toUpperCase() + sub.slice(1)
43
+ }
37
44
  return tlenv.isDarwin || !index ? modifiedKey : ['+', modifiedKey]
38
45
  })
39
46
  .flat()
@@ -1,9 +1,9 @@
1
1
  // This file is automatically generated by internal/scripts/refresh-assets.ts.
2
2
  // Do not edit manually. Or do, I'm a comment, not a cop.
3
3
 
4
- export const version = '3.16.0-canary.e9c30b532b82'
4
+ export const version = '3.16.0-canary.ea008b31887f'
5
5
  export const publishDates = {
6
6
  major: '2024-09-13T14:36:29.063Z',
7
- minor: '2025-08-14T07:45:09.188Z',
8
- patch: '2025-08-14T07:45:09.188Z',
7
+ minor: '2025-09-12T09:57:41.475Z',
8
+ patch: '2025-09-12T09:57:41.475Z',
9
9
  }