tldraw 3.16.0-canary.fa3749606e52 → 3.16.0-canary.faec5de49906

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 (466) hide show
  1. package/dist-cjs/index.d.ts +323 -106
  2. package/dist-cjs/index.js +45 -14
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/Tldraw.js +12 -2
  5. package/dist-cjs/lib/Tldraw.js.map +2 -2
  6. package/dist-cjs/lib/canvas/TldrawScribble.js +1 -1
  7. package/dist-cjs/lib/canvas/TldrawScribble.js.map +2 -2
  8. package/dist-cjs/lib/defaultExternalContentHandlers.js +5 -4
  9. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +3 -3
  11. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  13. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  14. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +1 -1
  15. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  16. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js +3 -3
  17. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js.map +1 -1
  18. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
  19. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  20. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +1 -1
  21. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
  22. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +20 -13
  23. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  24. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
  25. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
  26. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +3 -2
  27. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  28. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
  29. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
  30. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
  31. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  32. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +6 -3
  33. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  34. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +5 -1
  35. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  36. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +6 -5
  37. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  38. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  39. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  40. package/dist-cjs/lib/shapes/shared/ShapeFill.js +4 -4
  41. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  42. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  43. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +0 -2
  44. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  45. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  46. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  47. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js +10 -1
  48. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +2 -2
  49. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
  50. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
  51. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  52. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  53. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  54. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  55. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  56. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  57. package/dist-cjs/lib/ui/TldrawUi.js +27 -12
  58. package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
  59. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  60. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  61. package/dist-cjs/lib/ui/components/AccessibilityMenu.js +35 -0
  62. package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +7 -0
  63. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +12 -3
  64. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  65. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  66. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  67. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
  68. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
  69. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  70. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  71. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +3 -3
  72. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
  73. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  74. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  75. package/dist-cjs/lib/ui/components/MobileStylePanel.js +5 -3
  76. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +1 -1
  78. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +2 -1
  80. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
  82. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
  84. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +11 -4
  86. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +249 -279
  88. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/{primitives/TldrawUiButtonPicker.js → StylePanel/StylePanelButtonPicker.js} +52 -56
  90. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  91. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  92. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  93. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +26 -25
  94. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  95. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +47 -43
  96. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  97. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  98. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  99. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +3 -2
  100. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  101. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +39 -10
  102. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  103. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -21
  104. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
  105. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  106. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  107. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +3 -3
  108. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  109. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +189 -80
  110. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
  111. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +5 -4
  112. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  113. package/dist-cjs/lib/ui/components/menu-items.js +6 -0
  114. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  115. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +10 -1
  116. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  117. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
  118. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
  119. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  120. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  121. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +32 -7
  122. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  123. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +294 -0
  124. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +7 -0
  125. package/dist-cjs/lib/ui/components/primitives/layout.js +76 -0
  126. package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
  127. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  128. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
  129. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  130. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +17 -31
  131. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  132. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js +3 -2
  133. package/dist-cjs/lib/ui/context/TldrawUiContextProvider.js.map +2 -2
  134. package/dist-cjs/lib/ui/context/actions.js +38 -10
  135. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  136. package/dist-cjs/lib/ui/context/components.js +2 -0
  137. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  138. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  139. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  140. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  141. package/dist-cjs/lib/ui/hooks/useTools.js +22 -4
  142. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  143. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  144. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -1
  145. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  146. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  147. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  148. package/dist-cjs/lib/ui/version.js +3 -3
  149. package/dist-cjs/lib/ui/version.js.map +1 -1
  150. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  151. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  152. package/dist-cjs/lib/utils/export/export.js +0 -20
  153. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  154. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  155. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  156. package/dist-esm/index.d.mts +323 -106
  157. package/dist-esm/index.mjs +83 -29
  158. package/dist-esm/index.mjs.map +2 -2
  159. package/dist-esm/lib/Tldraw.mjs +14 -4
  160. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  161. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  162. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  163. package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -4
  164. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  165. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +4 -3
  166. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  167. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  168. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  169. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +1 -1
  170. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  171. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  172. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  173. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
  174. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  175. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  176. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  177. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +21 -13
  178. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  179. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  180. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  181. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +4 -2
  182. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  183. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
  184. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
  185. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
  186. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  187. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +6 -3
  188. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  189. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +6 -1
  190. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  191. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +7 -5
  192. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  193. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  194. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  195. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +5 -4
  196. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  197. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  198. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +0 -2
  199. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  200. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  201. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  202. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +10 -1
  203. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +2 -2
  204. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
  205. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
  206. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  207. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  208. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  209. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  210. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  211. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  212. package/dist-esm/lib/ui/TldrawUi.mjs +29 -14
  213. package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
  214. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  215. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  216. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +19 -0
  217. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +7 -0
  218. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +12 -3
  219. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  220. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  221. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  222. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
  223. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
  224. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  225. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  226. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +3 -5
  227. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs.map +2 -2
  228. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  229. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  230. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +6 -3
  231. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  232. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
  233. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
  234. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +2 -1
  235. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  236. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
  237. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
  238. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
  239. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs.map +2 -2
  240. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +16 -5
  241. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  242. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +251 -283
  243. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  244. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +126 -0
  245. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  246. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  247. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  248. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +23 -22
  249. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  250. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +44 -40
  251. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  252. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  253. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  254. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +3 -2
  255. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  256. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +39 -10
  257. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  258. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -21
  259. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
  260. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  261. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  262. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +3 -3
  263. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  264. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -81
  265. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
  266. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +5 -4
  267. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  268. package/dist-esm/lib/ui/components/menu-items.mjs +6 -0
  269. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  270. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +10 -1
  271. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  272. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
  273. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
  274. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  275. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  276. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +32 -7
  277. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  278. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +272 -0
  279. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +7 -0
  280. package/dist-esm/lib/ui/components/primitives/layout.mjs +46 -0
  281. package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
  282. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  283. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
  284. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  285. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +17 -31
  286. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  287. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs +3 -2
  288. package/dist-esm/lib/ui/context/TldrawUiContextProvider.mjs.map +2 -2
  289. package/dist-esm/lib/ui/context/actions.mjs +38 -10
  290. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  291. package/dist-esm/lib/ui/context/components.mjs +2 -0
  292. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  293. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  294. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  295. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  296. package/dist-esm/lib/ui/hooks/useTools.mjs +23 -4
  297. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  298. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -1
  299. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  300. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  301. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  302. package/dist-esm/lib/ui/version.mjs +3 -3
  303. package/dist-esm/lib/ui/version.mjs.map +1 -1
  304. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  305. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  306. package/dist-esm/lib/utils/export/export.mjs +0 -20
  307. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  308. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  309. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  310. package/package.json +11 -34
  311. package/src/index.ts +62 -22
  312. package/src/lib/Tldraw.tsx +15 -2
  313. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  314. package/src/lib/defaultExternalContentHandlers.ts +12 -4
  315. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  316. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +4 -3
  317. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  318. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +4 -3
  319. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  320. package/src/lib/shapes/arrow/arrowTargetState.ts +2 -1
  321. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  322. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  323. package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
  324. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  325. package/src/lib/shapes/frame/FrameShapeUtil.tsx +30 -14
  326. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  327. package/src/lib/shapes/geo/GeoShapeUtil.tsx +4 -2
  328. package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
  329. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
  330. package/src/lib/shapes/image/ImageShapeUtil.tsx +6 -3
  331. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  332. package/src/lib/shapes/line/LineShapeUtil.tsx +6 -1
  333. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  334. package/src/lib/shapes/note/NoteShapeUtil.tsx +10 -4
  335. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  336. package/src/lib/shapes/shared/ShapeFill.tsx +5 -4
  337. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  338. package/src/lib/shapes/shared/useEditablePlainText.ts +0 -6
  339. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  340. package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +11 -1
  341. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  342. package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
  343. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  344. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  345. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  346. package/src/lib/ui/TldrawUi.tsx +33 -12
  347. package/src/lib/ui/assetUrls.ts +13 -10
  348. package/src/lib/ui/components/AccessibilityMenu.tsx +20 -0
  349. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +15 -3
  350. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  351. package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
  352. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  353. package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -4
  354. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  355. package/src/lib/ui/components/MobileStylePanel.tsx +9 -6
  356. package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
  357. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +3 -2
  358. package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
  359. package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
  360. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +28 -12
  361. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +261 -343
  362. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +66 -50
  363. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  364. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +31 -22
  365. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  366. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  367. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +4 -3
  368. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +33 -16
  369. package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -23
  370. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  371. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +5 -5
  372. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +212 -61
  373. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +14 -11
  374. package/src/lib/ui/components/menu-items.tsx +8 -0
  375. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +6 -1
  376. package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
  377. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  378. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +54 -12
  379. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +365 -0
  380. package/src/lib/ui/components/primitives/layout.tsx +107 -0
  381. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  382. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
  383. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +24 -33
  384. package/src/lib/ui/context/TldrawUiContextProvider.tsx +23 -20
  385. package/src/lib/ui/context/actions.tsx +38 -10
  386. package/src/lib/ui/context/components.tsx +3 -0
  387. package/src/lib/ui/context/events.tsx +2 -1
  388. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  389. package/src/lib/ui/hooks/useTools.tsx +26 -4
  390. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +5 -0
  391. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -1
  392. package/src/lib/ui/kbd-utils.ts +10 -3
  393. package/src/lib/ui/version.ts +3 -3
  394. package/src/lib/ui.css +424 -293
  395. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  396. package/src/lib/utils/export/copyAs.ts +1 -24
  397. package/src/lib/utils/export/export.ts +0 -36
  398. package/src/lib/utils/export/exportAs.ts +1 -32
  399. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  400. package/src/test/A11y.test.tsx +3 -2
  401. package/src/test/ClickManager.test.ts +7 -6
  402. package/src/test/Editor.test.tsx +20 -19
  403. package/src/test/EraserTool.test.ts +184 -13
  404. package/src/test/HandTool.test.ts +10 -9
  405. package/src/test/HighlightShape.test.ts +2 -1
  406. package/src/test/SelectTool.test.ts +3 -2
  407. package/src/test/TLUserPreferences.test.ts +4 -3
  408. package/src/test/TestEditor.ts +13 -15
  409. package/src/test/TldrawEditor.test.tsx +11 -10
  410. package/src/test/ZoomTool.test.ts +7 -6
  411. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  412. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  413. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  414. package/src/test/arrows-megabus.test.tsx +17 -10
  415. package/src/test/bindings.test.tsx +24 -37
  416. package/src/test/bookmark-shapes.test.ts +1 -8
  417. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  418. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  419. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  420. package/src/test/commands/alignShapes.test.tsx +25 -24
  421. package/src/test/commands/animationSpeed.test.ts +2 -1
  422. package/src/test/commands/centerOnPoint.test.ts +3 -2
  423. package/src/test/commands/clipboard.test.ts +3 -2
  424. package/src/test/commands/createShapes.test.ts +2 -1
  425. package/src/test/commands/deleteShapes.test.ts +2 -1
  426. package/src/test/commands/distributeShapes.test.tsx +11 -10
  427. package/src/test/commands/getSvgString.test.ts +2 -1
  428. package/src/test/commands/packShapes.test.ts +5 -4
  429. package/src/test/commands/resizeShape.test.ts +2 -1
  430. package/src/test/commands/rotateShapes.test.ts +7 -6
  431. package/src/test/commands/setCamera.test.ts +4 -3
  432. package/src/test/commands/setCurrentPage.test.ts +3 -2
  433. package/src/test/commands/stackShapes.test.ts +11 -10
  434. package/src/test/commands/stretch.test.tsx +13 -12
  435. package/src/test/createDeepLink.test.tsx +2 -1
  436. package/src/test/cropping.test.ts +3 -2
  437. package/src/test/custom-clipping.test.ts +436 -0
  438. package/src/test/drawing.test.ts +2 -1
  439. package/src/test/flipShapes.test.ts +4 -3
  440. package/src/test/frames.test.ts +25 -24
  441. package/src/test/getCulledShapes.test.tsx +74 -4
  442. package/src/test/groups.test.tsx +1 -1
  443. package/src/test/handleDeepLink.test.tsx +2 -1
  444. package/src/test/inner-outer-margin.test.ts +315 -0
  445. package/src/test/maxShapes.test.ts +3 -2
  446. package/src/test/modifiers.test.ts +5 -4
  447. package/src/test/navigation.test.ts +12 -11
  448. package/src/test/panning.test.ts +2 -1
  449. package/src/test/perf/perf.test.ts +2 -1
  450. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  451. package/src/test/resizing.test.ts +39 -38
  452. package/src/test/select.test.tsx +4 -3
  453. package/src/test/selection-omnibus.test.ts +11 -10
  454. package/src/test/shapeutils.test.ts +4 -3
  455. package/src/test/translating.test.ts +9 -8
  456. package/tldraw.css +732 -583
  457. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  458. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  459. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  460. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  461. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  462. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  463. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  464. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  465. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  466. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -109
@@ -8,13 +8,14 @@ import {
8
8
  createShapeId,
9
9
  toRichText,
10
10
  } from '@tldraw/editor'
11
+ import { vi } from 'vitest'
11
12
  import { getArrowBindings } from '../lib/shapes/arrow/shared'
12
13
  import { DEFAULT_FRAME_PADDING, fitFrameToContent, removeFrame } from '../lib/utils/frames/frames'
13
14
  import { TestEditor } from './TestEditor'
14
15
 
15
16
  let editor: TestEditor
16
17
 
17
- jest.useFakeTimers()
18
+ vi.useFakeTimers()
18
19
 
19
20
  beforeEach(() => {
20
21
  editor = new TestEditor()
@@ -335,7 +336,7 @@ describe('frame shapes', () => {
335
336
  // move to the center of the frame
336
337
  editor.pointerMove(100, 100)
337
338
 
338
- jest.advanceTimersByTime(300)
339
+ vi.advanceTimersByTime(300)
339
340
 
340
341
  // Expect the shape to be inside the frame
341
342
  expect(editor.getOnlySelectedShape()!.id).toBe(ids.boxA)
@@ -343,13 +344,13 @@ describe('frame shapes', () => {
343
344
 
344
345
  // Move out of the frame
345
346
  editor.pointerMove(275, 275)
346
- jest.advanceTimersByTime(250)
347
+ vi.advanceTimersByTime(250)
347
348
 
348
349
  expect(editor.getOnlySelectedShape()!.parentId).toBe(editor.getCurrentPageId())
349
350
 
350
351
  // Move back into the frame
351
352
  editor.pointerMove(150, 150)
352
- jest.advanceTimersByTime(250)
353
+ vi.advanceTimersByTime(250)
353
354
 
354
355
  // Expect the shape to be inside the frame again
355
356
  expect(editor.getOnlySelectedShape()!.parentId).toBe(frameId)
@@ -384,7 +385,7 @@ describe('frame shapes', () => {
384
385
 
385
386
  editor.setCurrentTool('select').select(box1.id).pointerDown(127, 127).pointerMove(132, 127)
386
387
 
387
- jest.advanceTimersByTime(250)
388
+ vi.advanceTimersByTime(250)
388
389
 
389
390
  expect(editor.getOnlySelectedShape()!.id).toBe(box1.id)
390
391
  if (editor.getShape(box1)?.parentId !== frame.id) {
@@ -403,14 +404,14 @@ describe('frame shapes', () => {
403
404
  editor.pointerMove(175, 175)
404
405
  expect(editor.getOnlySelectedShape()!.parentId).toBe(frame.id)
405
406
 
406
- jest.advanceTimersByTime(250)
407
+ vi.advanceTimersByTime(250)
407
408
  expect(editor.getOnlySelectedShape()!.parentId).toBe(frame.id)
408
409
 
409
410
  // Let's try that
410
411
  editor.pointerMove(1750, 1750)
411
- jest.advanceTimersByTime(200)
412
+ vi.advanceTimersByTime(200)
412
413
  editor.pointerMove(175, 175)
413
- jest.advanceTimersByTime(200)
414
+ vi.advanceTimersByTime(200)
414
415
 
415
416
  // yay
416
417
  expect(editor.getHintingShapeIds()).toHaveLength(1)
@@ -958,7 +959,7 @@ describe('When dragging a shape inside a group inside a frame', () => {
958
959
  editor.pointerMove(150, 150).pointerDown(150, 150).pointerMove(140, 140)
959
960
 
960
961
  expect(editor.getOnlySelectedShapeId()).toBe(ids.box1)
961
- jest.advanceTimersByTime(300)
962
+ vi.advanceTimersByTime(300)
962
963
 
963
964
  expect(editor.getShape(ids.box1)!.parentId).toBe(ids.group1)
964
965
  })
@@ -973,7 +974,7 @@ it('Drags into a frame', () => {
973
974
  editor.pointerDown(550, 550)
974
975
  editor.pointerMove(250, 250)
975
976
 
976
- jest.advanceTimersByTime(200)
977
+ vi.advanceTimersByTime(200)
977
978
 
978
979
  expect(editor.getShape(box1)!.parentId).toBe(frame.id)
979
980
  })
@@ -992,7 +993,7 @@ it('Allows dragging grouped shapes into frames if every shape in the group is in
992
993
  editor.pointerDown(1100, 1100)
993
994
  editor.pointerMove(250, 250)
994
995
 
995
- jest.advanceTimersByTime(250)
996
+ vi.advanceTimersByTime(250)
996
997
 
997
998
  expect(editor.getHintingShapeIds()).toMatchObject([frame.id])
998
999
 
@@ -1068,7 +1069,7 @@ describe('When dragging a shape', () => {
1068
1069
  editor.pointerMove(30, 50)
1069
1070
  editor.pointerUp(30, 50)
1070
1071
  const parent = editor.getShape(rectId)?.parentId
1071
- jest.advanceTimersByTime(200)
1072
+ vi.advanceTimersByTime(200)
1072
1073
  expect(parent).toBe(frameId)
1073
1074
  })
1074
1075
 
@@ -1185,7 +1186,7 @@ describe('Unparenting behavior', () => {
1185
1186
  // expect(editor.getShape(rect.id)!.parentId).toBe(frame.id)
1186
1187
  // editor.pointerDown(90, 50)
1187
1188
  // editor.pointerMove(110, 50)
1188
- // jest.advanceTimersByTime(200)
1189
+ // vi.advanceTimersByTime(200)
1189
1190
  // expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
1190
1191
  // editor.pointerUp(110, 50)
1191
1192
  // expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
@@ -1199,7 +1200,7 @@ describe('Unparenting behavior', () => {
1199
1200
  expect(editor.getShape(rect.id)!.parentId).toBe(frame.id)
1200
1201
  editor.pointerDown(90, 50)
1201
1202
  editor.pointerMove(110, 50)
1202
- jest.advanceTimersByTime(200)
1203
+ vi.advanceTimersByTime(200)
1203
1204
  expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
1204
1205
  editor.pointerUp(110, 50)
1205
1206
  expect(editor.getShape(rect.id)!.parentId).toBe(editor.getCurrentPageId())
@@ -1299,7 +1300,7 @@ describe('Unparenting behavior', () => {
1299
1300
  expect(editor.getShape(triangle.id)!.parentId).toBe(frame.id)
1300
1301
 
1301
1302
  // But after a delay, the triangle is reparented because it's not overlapping
1302
- jest.advanceTimersByTime(200)
1303
+ vi.advanceTimersByTime(200)
1303
1304
  expect(editor.getShape(triangle.id)!.parentId).toBe(editor.getCurrentPageId())
1304
1305
 
1305
1306
  editor.pointerMove(50, 50)
@@ -1308,7 +1309,7 @@ describe('Unparenting behavior', () => {
1308
1309
  expect(editor.getShape(triangle.id)!.parentId).toBe(editor.getCurrentPageId())
1309
1310
 
1310
1311
  // But after a delay, the triangle is reparented because it's overlapping
1311
- jest.advanceTimersByTime(200)
1312
+ vi.advanceTimersByTime(200)
1312
1313
  expect(editor.getShape(triangle.id)!.parentId).toBe(frame.id)
1313
1314
  })
1314
1315
 
@@ -1348,12 +1349,12 @@ describe('Unparenting behavior', () => {
1348
1349
  expect(editor.isIn('select.translating')).toBe(true)
1349
1350
 
1350
1351
  // Wait for reparenting to happen
1351
- jest.advanceTimersByTime(250)
1352
+ vi.advanceTimersByTime(250)
1352
1353
  expect(editor.getShape(largeRect.id)!.parentId).toBe(frameId)
1353
1354
 
1354
1355
  // The large rectangle should now be reparented to the frame, even though the frame covers it
1355
1356
  editor.pointerUp(250, 250)
1356
- jest.advanceTimersByTime(250)
1357
+ vi.advanceTimersByTime(250)
1357
1358
  }
1358
1359
 
1359
1360
  // When the shape has no fill and an empty label, it should fall out of the frame
@@ -1503,7 +1504,7 @@ describe('When dragging groups or shapes within a group', () => {
1503
1504
  editor.pointerDown(1100, 1100)
1504
1505
  editor.pointerMove(250, 250)
1505
1506
 
1506
- jest.advanceTimersByTime(200)
1507
+ vi.advanceTimersByTime(200)
1507
1508
 
1508
1509
  expect(editor.getShape(group)!.parentId).toBe(frame.id)
1509
1510
  })
@@ -1526,14 +1527,14 @@ describe('When dragging groups or shapes within a group', () => {
1526
1527
  editor.select(rect1ID)
1527
1528
  editor.pointerDown(15, 15)
1528
1529
  editor.pointerMove(100, 100)
1529
- jest.advanceTimersByTime(200)
1530
+ vi.advanceTimersByTime(200)
1530
1531
 
1531
1532
  expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
1532
1533
  expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
1533
1534
  expect(group.parentId).toBe(frame.id)
1534
1535
 
1535
1536
  editor.pointerUp(100, 100)
1536
- jest.advanceTimersByTime(200)
1537
+ vi.advanceTimersByTime(200)
1537
1538
 
1538
1539
  expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
1539
1540
  expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
@@ -1558,7 +1559,7 @@ describe('When dragging groups or shapes within a group', () => {
1558
1559
  editor.pointerDown(15, 15)
1559
1560
  editor.pointerMove(200, 200)
1560
1561
 
1561
- jest.advanceTimersByTime(200)
1562
+ vi.advanceTimersByTime(200)
1562
1563
  expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
1563
1564
  expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
1564
1565
  expect(editor.getShape(group.id)?.parentId).toBe(editor.getCurrentPageId())
@@ -1587,7 +1588,7 @@ describe('When dragging groups or shapes within a group', () => {
1587
1588
  editor.pointerDown(15, 15)
1588
1589
  editor.pointerMove(200, 200)
1589
1590
 
1590
- jest.advanceTimersByTime(200)
1591
+ vi.advanceTimersByTime(200)
1591
1592
  expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
1592
1593
  expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
1593
1594
  expect(editor.getShape(group.id)?.parentId).toBe(editor.getCurrentPageId())
@@ -1638,7 +1639,7 @@ describe('When dragging groups or shapes within a group', () => {
1638
1639
  editor.pointerDown(215, 215)
1639
1640
  editor.pointerMove(15, 15)
1640
1641
 
1641
- jest.advanceTimersByTime(200)
1642
+ vi.advanceTimersByTime(200)
1642
1643
  expect(editor.getShape(rect1ID)?.parentId).toBe(group.id)
1643
1644
  expect(editor.getShape(rect2ID)?.parentId).toBe(group.id)
1644
1645
  expect(editor.getShape(group.id)?.parentId).toBe(frameID)
@@ -1,11 +1,50 @@
1
- import { Box, TLShapeId, createShapeId } from '@tldraw/editor'
1
+ import {
2
+ BaseBoxShapeUtil,
3
+ Box,
4
+ RecordProps,
5
+ T,
6
+ TLBaseShape,
7
+ TLShapeId,
8
+ createShapeId,
9
+ } from '@tldraw/editor'
10
+ import { vi } from 'vitest'
2
11
  import { TestEditor } from './TestEditor'
3
12
  import { TL } from './test-jsx'
4
13
 
14
+ // Custom uncullable shape type for testing canCull override
15
+ type UncullableShape = TLBaseShape<'uncullable', { w: number; h: number }>
16
+
17
+ class UncullableShapeUtil extends BaseBoxShapeUtil<UncullableShape> {
18
+ static override type = 'uncullable' as const
19
+ static override props: RecordProps<UncullableShape> = {
20
+ w: T.number,
21
+ h: T.number,
22
+ }
23
+
24
+ override canCull() {
25
+ return false
26
+ }
27
+
28
+ override getDefaultProps(): UncullableShape['props'] {
29
+ return {
30
+ w: 100,
31
+ h: 100,
32
+ }
33
+ }
34
+
35
+ override component() {
36
+ return <div>Uncullable shape</div>
37
+ }
38
+
39
+ override indicator() {
40
+ return <div>Uncullable shape</div>
41
+ }
42
+ }
43
+
5
44
  let editor: TestEditor
6
45
 
7
46
  beforeEach(() => {
8
- editor = new TestEditor()
47
+ editor = new TestEditor({ shapeUtils: [UncullableShapeUtil] })
9
48
  editor.setScreenBounds({ x: 0, y: 0, w: 1800, h: 900 })
10
49
  })
11
50
 
@@ -28,13 +67,13 @@ it('lists shapes in viewport', () => {
28
67
 
29
68
  // Move the camera 201 pixels to the right and 201 pixels down
30
69
  editor.pan({ x: -201, y: -201 })
31
- jest.advanceTimersByTime(500)
70
+ vi.advanceTimersByTime(500)
32
71
 
33
72
  // A is now outside of the viewport, like D
34
73
  expect(editor.getCulledShapes()).toStrictEqual(new Set([ids.A, ids.D]))
35
74
 
36
75
  editor.pan({ x: -900, y: -900 })
37
- jest.advanceTimersByTime(500)
76
+ vi.advanceTimersByTime(500)
38
77
  // Now all shapes are outside of the viewport, except for D (which is clipped)
39
78
  expect(editor.getCulledShapes()).toStrictEqual(new Set([ids.A, ids.B, ids.C]))
40
79
 
@@ -202,3 +241,34 @@ it('works for shapes that are outside of the viewport, but are then moved inside
202
241
  // Arrow should also not be culled
203
242
  expect(editor.getCulledShapes()).toEqual(new Set())
204
243
  })
244
+
245
+ it('respects canCull override - shapes that cannot be culled are never culled', () => {
246
+ const cullableShapeId = createShapeId()
247
+ const uncullableShapeId = createShapeId()
248
+
249
+ // Create both shapes outside the viewport
250
+ editor.createShapes([
251
+ {
252
+ id: cullableShapeId,
253
+ type: 'geo',
254
+ x: -2000, // Way outside viewport
255
+ y: -2000,
256
+ props: { w: 100, h: 100 },
257
+ },
258
+ {
259
+ id: uncullableShapeId,
260
+ type: 'uncullable',
261
+ x: -2000, // Way outside viewport
262
+ y: -2000,
263
+ props: { w: 100, h: 100 },
264
+ },
265
+ ])
266
+
267
+ const culledShapes = editor.getCulledShapes()
268
+
269
+ // The regular geo shape should be culled since it's outside the viewport
270
+ expect(culledShapes).toContain(cullableShapeId)
271
+
272
+ // The uncullable shape should NOT be culled even though it's outside the viewport
273
+ expect(culledShapes).not.toContain(uncullableShapeId)
274
+ })
@@ -1070,7 +1070,7 @@ describe('the select tool', () => {
1070
1070
  // that we're doing hit testing manually—we'll catch that it was inside a shape
1071
1071
 
1072
1072
  // editor.keyUp('Shift')
1073
- // jest.advanceTimersByTime(200)
1073
+ // vi.advanceTimersByTime(200)
1074
1074
 
1075
1075
  // expect(editor.selectedShapeIds.includes(ids.boxA)).toBe(false)
1076
1076
  // expect(editor.selectedShapeIds.includes(ids.boxB)).toBe(true)
@@ -1,8 +1,9 @@
1
1
  import { PageRecordType, TLDeepLink, createDeepLinkString, createShapeId } from '@tldraw/editor'
2
+ import { vi } from 'vitest'
2
3
  import { TestEditor } from './TestEditor'
3
4
  import { TL } from './test-jsx'
4
5
 
5
- jest.useFakeTimers()
6
+ vi.useFakeTimers()
6
7
 
7
8
  let editor: TestEditor
8
9
 
@@ -0,0 +1,315 @@
1
+ import { TLArrowShape, createShapeId } from '@tldraw/editor'
2
+ import { getArrowBindings } from '../lib/shapes/arrow/shared'
3
+ import { TestEditor } from './TestEditor'
4
+
5
+ let editor: TestEditor
6
+
7
+ const ids = {
8
+ solidShape: createShapeId('solidShape'),
9
+ hollowShape: createShapeId('hollowShape'),
10
+ arrow: createShapeId('arrow'),
11
+ }
12
+
13
+ const _arrow = () => editor.getOnlySelectedShape() as TLArrowShape
14
+
15
+ beforeEach(() => {
16
+ editor = new TestEditor()
17
+ })
18
+
19
+ describe('Inner/Outer Margin Shape Detection', () => {
20
+ describe('getShapeAtPoint with inner/outer margins', () => {
21
+ beforeEach(() => {
22
+ // Create a solid filled shape
23
+ editor.createShape({
24
+ id: ids.solidShape,
25
+ type: 'geo',
26
+ x: 100,
27
+ y: 100,
28
+ props: {
29
+ w: 100,
30
+ h: 100,
31
+ fill: 'solid',
32
+ },
33
+ })
34
+
35
+ // Create a hollow shape on top (same position, smaller size)
36
+ editor.createShape({
37
+ id: ids.hollowShape,
38
+ type: 'geo',
39
+ x: 125,
40
+ y: 125,
41
+ props: {
42
+ w: 50,
43
+ h: 50,
44
+ // No fill property - defaults to 'none' (hollow)
45
+ },
46
+ })
47
+ })
48
+
49
+ it('should support inner/outer margin options', () => {
50
+ // Test that the new margin options are accepted
51
+ const point = { x: 150, y: 150 }
52
+
53
+ // Test with array margin [innerMargin, outerMargin]
54
+ const arrayMarginHit = editor.getShapeAtPoint(point, {
55
+ hitInside: true,
56
+ margin: [8, 4],
57
+ })
58
+ expect(arrayMarginHit).toBeDefined()
59
+
60
+ // Test with insideMargin option
61
+ const insideMarginHit = editor.getShapeAtPoint(point, {
62
+ hitInside: true,
63
+ })
64
+ expect(insideMarginHit).toBeDefined()
65
+
66
+ // Test with single number margin (should use same for both)
67
+ const singleMarginHit = editor.getShapeAtPoint(point, {
68
+ hitInside: true,
69
+ margin: 8,
70
+ })
71
+ expect(singleMarginHit).toBeDefined()
72
+ })
73
+
74
+ it('should respect hitInside option for hollow shapes', () => {
75
+ const point = { x: 150, y: 150 }
76
+
77
+ // Without hitInside, should not hit hollow shape
78
+ const noHitInsideHit = editor.getShapeAtPoint(point, {
79
+ margin: [8, 0],
80
+ })
81
+ expect(noHitInsideHit?.id).toBe(ids.solidShape)
82
+
83
+ // With hitInside, should be able to hit hollow shape
84
+ const withHitInsideHit = editor.getShapeAtPoint(point, {
85
+ hitInside: true,
86
+ margin: [8, 0],
87
+ })
88
+ expect(withHitInsideHit).toBeDefined()
89
+ })
90
+
91
+ it('should handle edge cases correctly', () => {
92
+ // Test point exactly on the edge of hollow shape
93
+ const edgePoint = { x: 125, y: 150 }
94
+
95
+ const edgeHit = editor.getShapeAtPoint(edgePoint, {
96
+ hitInside: true,
97
+ margin: [8, 8],
98
+ })
99
+ expect(edgeHit).toBeDefined()
100
+ })
101
+ })
102
+
103
+ describe('Arrow binding with inner/outer margins', () => {
104
+ beforeEach(() => {
105
+ // Create a solid filled shape
106
+ editor.createShape({
107
+ id: ids.solidShape,
108
+ type: 'geo',
109
+ x: 100,
110
+ y: 100,
111
+ props: {
112
+ w: 100,
113
+ h: 100,
114
+ fill: 'solid',
115
+ },
116
+ })
117
+
118
+ // Create a hollow shape on top (same position, smaller size)
119
+ editor.createShape({
120
+ id: ids.hollowShape,
121
+ type: 'geo',
122
+ x: 125,
123
+ y: 125,
124
+ props: {
125
+ w: 50,
126
+ h: 50,
127
+ // No fill property - defaults to 'none' (hollow)
128
+ },
129
+ })
130
+ })
131
+
132
+ it('should create arrow bindings with inner/outer margin support', () => {
133
+ editor.setCurrentTool('arrow')
134
+
135
+ // Start arrow outside both shapes
136
+ editor.pointerDown(50, 150)
137
+
138
+ // Move to center of hollow shape (which overlaps solid shape)
139
+ editor.pointerMove(150, 150)
140
+ editor.pointerUp()
141
+
142
+ const createdArrow = editor
143
+ .getCurrentPageShapes()
144
+ .find((s) => s.type === 'arrow') as TLArrowShape
145
+ expect(createdArrow).toBeDefined()
146
+
147
+ const arrowBindings = getArrowBindings(editor, createdArrow)
148
+ expect(arrowBindings.end).toBeDefined()
149
+ // The binding should be to one of the shapes
150
+ expect([ids.solidShape, ids.hollowShape]).toContain(arrowBindings.end?.toId)
151
+ })
152
+
153
+ it('should bind to solid shape when no hollow shape is present', () => {
154
+ // Remove the hollow shape
155
+ editor.deleteShape(ids.hollowShape)
156
+
157
+ editor.setCurrentTool('arrow')
158
+
159
+ // Start arrow outside shape
160
+ editor.pointerDown(50, 150)
161
+
162
+ // Move to center of solid shape
163
+ editor.pointerMove(150, 150)
164
+ editor.pointerUp()
165
+
166
+ const createdArrow = editor
167
+ .getCurrentPageShapes()
168
+ .find((s) => s.type === 'arrow') as TLArrowShape
169
+ expect(createdArrow).toBeDefined()
170
+
171
+ const arrowBindings = getArrowBindings(editor, createdArrow)
172
+ expect(arrowBindings.end).toBeDefined()
173
+ expect(arrowBindings.end?.toId).toBe(ids.solidShape)
174
+ })
175
+ })
176
+
177
+ describe('Complex overlapping scenarios', () => {
178
+ it('should handle multiple overlapping shapes correctly', () => {
179
+ // Create multiple shapes with different fill states
180
+ editor.createShape({
181
+ id: ids.solidShape,
182
+ type: 'geo',
183
+ x: 100,
184
+ y: 100,
185
+ props: {
186
+ w: 100,
187
+ h: 100,
188
+ fill: 'solid',
189
+ },
190
+ })
191
+
192
+ editor.createShape({
193
+ id: ids.hollowShape,
194
+ type: 'geo',
195
+ x: 125,
196
+ y: 125,
197
+ props: {
198
+ w: 50,
199
+ h: 50,
200
+ // No fill property - defaults to 'none' (hollow)
201
+ },
202
+ })
203
+
204
+ // Create another hollow shape
205
+ const hollowShape2 = createShapeId('hollowShape2')
206
+ editor.createShape({
207
+ id: hollowShape2,
208
+ type: 'geo',
209
+ x: 140,
210
+ y: 140,
211
+ props: {
212
+ w: 30,
213
+ h: 30,
214
+ // No fill property - defaults to 'none' (hollow)
215
+ },
216
+ })
217
+
218
+ // Test point in the innermost hollow shape
219
+ const point = { x: 155, y: 155 }
220
+
221
+ const hit = editor.getShapeAtPoint(point, {
222
+ hitInside: true,
223
+ margin: [8, 8],
224
+ })
225
+ expect(hit).toBeDefined()
226
+ // Should hit one of the shapes
227
+ expect([ids.solidShape, ids.hollowShape, hollowShape2]).toContain(hit?.id)
228
+ })
229
+
230
+ it('should handle shapes with different geometries', () => {
231
+ // Create a solid rectangle
232
+ editor.createShape({
233
+ id: ids.solidShape,
234
+ type: 'geo',
235
+ x: 100,
236
+ y: 100,
237
+ props: {
238
+ w: 100,
239
+ h: 100,
240
+ fill: 'solid',
241
+ },
242
+ })
243
+
244
+ // Create a hollow circle on top
245
+ editor.createShape({
246
+ id: ids.hollowShape,
247
+ type: 'geo',
248
+ x: 125,
249
+ y: 125,
250
+ props: {
251
+ w: 50,
252
+ h: 50,
253
+ geo: 'ellipse',
254
+ // No fill property - defaults to 'none' (hollow)
255
+ },
256
+ })
257
+
258
+ // Test point inside the circle
259
+ const point = { x: 150, y: 150 }
260
+
261
+ const hit = editor.getShapeAtPoint(point, {
262
+ hitInside: true,
263
+ margin: [8, 8],
264
+ })
265
+ expect(hit).toBeDefined()
266
+ // Should hit one of the shapes
267
+ expect([ids.solidShape, ids.hollowShape]).toContain(hit?.id)
268
+ })
269
+ })
270
+
271
+ describe('Regression tests for the original bug', () => {
272
+ it('should support binding to hollow shapes when overlapping solid shapes', () => {
273
+ // This test verifies that the infrastructure exists for the bug fix
274
+ // Create a solid shape
275
+ editor.createShape({
276
+ id: ids.solidShape,
277
+ type: 'geo',
278
+ x: 100,
279
+ y: 100,
280
+ props: {
281
+ w: 100,
282
+ h: 100,
283
+ fill: 'solid',
284
+ },
285
+ })
286
+
287
+ // Create a hollow shape on top
288
+ editor.createShape({
289
+ id: ids.hollowShape,
290
+ type: 'geo',
291
+ x: 125,
292
+ y: 125,
293
+ props: {
294
+ w: 50,
295
+ h: 50,
296
+ // No fill property - defaults to 'none' (hollow)
297
+ },
298
+ })
299
+
300
+ // Test that we can detect both shapes
301
+ const point = { x: 150, y: 150 }
302
+
303
+ // Should be able to hit the solid shape without hitInside
304
+ const solidHit = editor.getShapeAtPoint(point)
305
+ expect(solidHit?.id).toBe(ids.solidShape)
306
+
307
+ // Should be able to hit the hollow shape with hitInside and inner margin
308
+ const hollowHit = editor.getShapeAtPoint(point, {
309
+ hitInside: true,
310
+ margin: [8, 0],
311
+ })
312
+ expect(hollowHit).toBeDefined()
313
+ })
314
+ })
315
+ })
@@ -1,4 +1,5 @@
1
1
  import { createShapeId } from '@tldraw/editor'
2
+ import { vi } from 'vitest'
2
3
  import { TestEditor } from './TestEditor'
3
4
 
4
5
  let editor: TestEditor
@@ -82,7 +83,7 @@ describe('Maximum shapes behavior', () => {
82
83
  })
83
84
 
84
85
  it('should emit max-shapes event when limit is reached', () => {
85
- const maxShapesHandler = jest.fn()
86
+ const maxShapesHandler = vi.fn()
86
87
  editor.addListener('max-shapes', maxShapesHandler)
87
88
 
88
89
  // Set up the note tool
@@ -282,7 +283,7 @@ describe('Maximum shapes behavior', () => {
282
283
  expect(editor.getCurrentPageShapeIds().size).toBe(5)
283
284
 
284
285
  // Try to create one more shape
285
- const maxShapesHandler = jest.fn()
286
+ const maxShapesHandler = vi.fn()
286
287
  editor.addListener('max-shapes', maxShapesHandler)
287
288
 
288
289
  const extraShapeId = createShapeId('extra-shape')
@@ -1,3 +1,4 @@
1
+ import { vi } from 'vitest'
1
2
  import { TestEditor } from './TestEditor'
2
3
 
3
4
  let editor: TestEditor
@@ -6,14 +7,14 @@ beforeEach(() => {
6
7
  editor = new TestEditor()
7
8
  })
8
9
 
9
- jest.useFakeTimers()
10
+ vi.useFakeTimers()
10
11
 
11
12
  it('Shift Key', () => {
12
13
  editor.pointerDown(0, 0)
13
14
  editor.pointerMove(100, 100, { shiftKey: true })
14
15
  editor.pointerMove(100, 100, { shiftKey: false })
15
16
  expect(editor.inputs.shiftKey).toBe(true)
16
- jest.advanceTimersByTime(200)
17
+ vi.advanceTimersByTime(200)
17
18
  expect(editor.inputs.shiftKey).toBe(false)
18
19
  })
19
20
 
@@ -22,7 +23,7 @@ it('Alt Key', () => {
22
23
  editor.pointerMove(100, 100, { altKey: true })
23
24
  editor.pointerMove(100, 100, { altKey: false })
24
25
  expect(editor.inputs.altKey).toBe(true)
25
- jest.advanceTimersByTime(200)
26
+ vi.advanceTimersByTime(200)
26
27
  expect(editor.inputs.altKey).toBe(false)
27
28
  })
28
29
 
@@ -31,6 +32,6 @@ it('Ctrl Key', () => {
31
32
  editor.pointerMove(100, 100, { ctrlKey: true })
32
33
  editor.pointerMove(100, 100, { ctrlKey: false })
33
34
  expect(editor.inputs.ctrlKey).toBe(true)
34
- jest.advanceTimersByTime(200)
35
+ vi.advanceTimersByTime(200)
35
36
  expect(editor.inputs.ctrlKey).toBe(false)
36
37
  })