tldraw 3.16.0-canary.7cd3b8a5bfd6 → 3.16.0-canary.7facbd2d2b7f

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 (390) hide show
  1. package/dist-cjs/index.d.ts +315 -110
  2. package/dist-cjs/index.js +37 -14
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/Tldraw.js +12 -2
  5. package/dist-cjs/lib/Tldraw.js.map +2 -2
  6. package/dist-cjs/lib/defaultExternalContentHandlers.js +15 -4
  7. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  8. package/dist-cjs/lib/shapes/arrow/arrow-types.js.map +1 -1
  9. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  10. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  11. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +3 -2
  12. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  13. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +1 -1
  14. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  15. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  16. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  17. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +8 -1
  18. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  19. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +8 -2
  20. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  21. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -0
  22. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  23. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -0
  24. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  25. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +2 -1
  26. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  27. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  28. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  29. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  30. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  31. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  32. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -5
  33. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  34. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  35. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  36. package/dist-cjs/lib/shapes/text/PlainTextArea.js +3 -2
  37. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  38. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  39. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  40. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  41. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  42. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  43. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  44. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +3 -1
  45. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  46. package/dist-cjs/lib/ui/TldrawUi.js +13 -12
  47. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  48. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  49. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  50. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  51. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  52. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  53. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  54. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  55. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  56. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  57. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  58. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +2 -1
  59. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  60. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  61. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  62. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  63. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  64. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  65. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  66. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  67. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  68. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  69. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  70. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  71. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  72. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +24 -21
  73. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  74. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  75. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  76. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +2 -0
  77. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  78. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
  79. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  80. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  81. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  82. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
  83. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  84. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +1 -1
  85. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
  86. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +6 -2
  87. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  88. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  89. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  90. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +5 -3
  91. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  92. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  93. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  94. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
  95. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  96. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +75 -37
  97. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  98. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  99. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  100. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +10 -9
  101. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  102. package/dist-cjs/lib/ui/context/actions.js +29 -10
  103. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  104. package/dist-cjs/lib/ui/context/components.js +2 -0
  105. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  106. package/dist-cjs/lib/ui/context/events.js.map +1 -1
  107. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  108. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  109. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  110. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  111. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  112. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  113. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  114. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +6 -2
  115. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  116. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  117. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  118. package/dist-cjs/lib/ui/version.js +3 -3
  119. package/dist-cjs/lib/ui/version.js.map +1 -1
  120. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  121. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  122. package/dist-cjs/lib/utils/export/export.js +0 -20
  123. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  124. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  125. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  126. package/dist-esm/index.d.mts +315 -110
  127. package/dist-esm/index.mjs +69 -29
  128. package/dist-esm/index.mjs.map +2 -2
  129. package/dist-esm/lib/Tldraw.mjs +14 -4
  130. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  131. package/dist-esm/lib/defaultExternalContentHandlers.mjs +15 -4
  132. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  133. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  134. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  135. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +3 -2
  136. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  137. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +1 -1
  138. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  139. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +4 -5
  140. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  141. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +8 -1
  142. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  143. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +9 -3
  144. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  145. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  146. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  147. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -0
  148. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  149. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  150. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  151. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  152. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  153. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  154. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  155. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  156. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +3 -6
  157. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  158. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  159. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  160. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +4 -3
  161. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  162. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  163. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  164. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  165. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  166. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  167. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  168. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +3 -1
  169. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  170. package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
  171. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  172. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  173. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  174. package/dist-esm/lib/ui/components/A11y.mjs +1 -2
  175. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  176. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  177. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  178. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  179. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  180. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  181. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  182. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +2 -1
  183. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  184. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +1 -2
  185. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  186. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  187. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  188. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  189. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  190. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +135 -0
  191. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  192. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  193. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  194. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +20 -19
  195. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  196. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +21 -18
  197. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  198. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  199. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  200. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +2 -0
  201. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  202. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +38 -9
  203. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  204. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  205. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  206. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +2 -1
  207. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  208. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +1 -1
  209. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +2 -2
  210. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +6 -2
  211. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  212. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +11 -3
  213. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  214. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +6 -4
  215. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  216. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  217. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  218. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
  219. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  220. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +76 -37
  221. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  222. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  223. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  224. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +10 -9
  225. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  226. package/dist-esm/lib/ui/context/actions.mjs +29 -10
  227. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  228. package/dist-esm/lib/ui/context/components.mjs +2 -0
  229. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  230. package/dist-esm/lib/ui/context/events.mjs.map +1 -1
  231. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +1 -2
  232. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  233. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  234. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  235. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  236. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  237. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +6 -2
  238. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  239. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  240. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  241. package/dist-esm/lib/ui/version.mjs +3 -3
  242. package/dist-esm/lib/ui/version.mjs.map +1 -1
  243. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  244. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  245. package/dist-esm/lib/utils/export/export.mjs +0 -20
  246. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  247. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  248. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  249. package/package.json +11 -34
  250. package/src/index.ts +51 -22
  251. package/src/lib/Tldraw.tsx +15 -2
  252. package/src/lib/defaultExternalContentHandlers.ts +26 -4
  253. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +85 -14
  254. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +103 -8
  255. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  256. package/src/lib/shapes/arrow/arrow-types.ts +3 -5
  257. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  258. package/src/lib/shapes/arrow/arrowTargetState.ts +34 -3
  259. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
  260. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +4 -5
  261. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  262. package/src/lib/shapes/frame/FrameShapeUtil.tsx +9 -0
  263. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
  264. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  265. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
  266. package/src/lib/shapes/line/LineShapeUtil.test.tsx +4 -3
  267. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  268. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  269. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  270. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  271. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  272. package/src/lib/shapes/shared/useEditablePlainText.ts +3 -10
  273. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  274. package/src/lib/shapes/text/PlainTextArea.tsx +4 -3
  275. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  276. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  277. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  278. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  279. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +6 -2
  280. package/src/lib/ui/TldrawUi.tsx +16 -10
  281. package/src/lib/ui/assetUrls.ts +13 -10
  282. package/src/lib/ui/components/A11y.tsx +1 -2
  283. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  284. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  285. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  286. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +2 -1
  287. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +1 -2
  288. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  289. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -381
  290. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  291. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  292. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  293. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  294. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  295. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -0
  296. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
  297. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  298. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
  299. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +1 -1
  300. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +9 -2
  301. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +7 -3
  302. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
  303. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  304. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
  305. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +82 -30
  306. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  307. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +12 -11
  308. package/src/lib/ui/context/actions.tsx +36 -10
  309. package/src/lib/ui/context/components.tsx +3 -0
  310. package/src/lib/ui/context/events.tsx +1 -1
  311. package/src/lib/ui/hooks/useClipboardEvents.ts +1 -2
  312. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  313. package/src/lib/ui/hooks/useTools.tsx +1 -1
  314. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +4 -0
  315. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +6 -2
  316. package/src/lib/ui/kbd-utils.ts +10 -3
  317. package/src/lib/ui/version.ts +3 -3
  318. package/src/lib/ui.css +43 -3
  319. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  320. package/src/lib/utils/export/copyAs.ts +1 -24
  321. package/src/lib/utils/export/export.ts +0 -36
  322. package/src/lib/utils/export/exportAs.ts +1 -32
  323. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  324. package/src/test/A11y.test.tsx +3 -2
  325. package/src/test/ClickManager.test.ts +7 -6
  326. package/src/test/Editor.test.tsx +20 -19
  327. package/src/test/EraserTool.test.ts +184 -13
  328. package/src/test/HandTool.test.ts +10 -9
  329. package/src/test/HighlightShape.test.ts +2 -1
  330. package/src/test/SelectTool.test.ts +3 -2
  331. package/src/test/TLUserPreferences.test.ts +4 -3
  332. package/src/test/TestEditor.ts +21 -17
  333. package/src/test/TldrawEditor.test.tsx +11 -10
  334. package/src/test/ZoomTool.test.ts +7 -6
  335. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  336. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  337. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  338. package/src/test/arrows-megabus.test.tsx +5 -4
  339. package/src/test/bindings.test.tsx +24 -37
  340. package/src/test/bookmark-shapes.test.ts +1 -8
  341. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  342. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  343. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  344. package/src/test/commands/alignShapes.test.tsx +25 -24
  345. package/src/test/commands/animationSpeed.test.ts +2 -1
  346. package/src/test/commands/centerOnPoint.test.ts +3 -2
  347. package/src/test/commands/clipboard.test.ts +3 -2
  348. package/src/test/commands/createShapes.test.ts +2 -1
  349. package/src/test/commands/deleteShapes.test.ts +2 -1
  350. package/src/test/commands/distributeShapes.test.tsx +11 -10
  351. package/src/test/commands/getSvgString.test.ts +2 -1
  352. package/src/test/commands/packShapes.test.ts +5 -4
  353. package/src/test/commands/resizeShape.test.ts +2 -1
  354. package/src/test/commands/rotateShapes.test.ts +7 -6
  355. package/src/test/commands/setCamera.test.ts +4 -3
  356. package/src/test/commands/setCurrentPage.test.ts +3 -2
  357. package/src/test/commands/stackShapes.test.ts +11 -10
  358. package/src/test/commands/stretch.test.tsx +13 -12
  359. package/src/test/createDeepLink.test.tsx +2 -1
  360. package/src/test/cropping.test.ts +3 -2
  361. package/src/test/custom-clipping.test.ts +436 -0
  362. package/src/test/drawing.test.ts +2 -1
  363. package/src/test/flipShapes.test.ts +4 -3
  364. package/src/test/frames.test.ts +25 -24
  365. package/src/test/getCulledShapes.test.tsx +74 -4
  366. package/src/test/groups.test.tsx +1 -1
  367. package/src/test/handleDeepLink.test.tsx +2 -1
  368. package/src/test/maxShapes.test.ts +3 -2
  369. package/src/test/modifiers.test.ts +5 -4
  370. package/src/test/navigation.test.ts +12 -11
  371. package/src/test/panning.test.ts +2 -1
  372. package/src/test/perf/perf.test.ts +2 -1
  373. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  374. package/src/test/resizing.test.ts +39 -38
  375. package/src/test/select.test.tsx +4 -3
  376. package/src/test/selection-omnibus.test.ts +11 -10
  377. package/src/test/shapeutils.test.ts +4 -3
  378. package/src/test/translating.test.ts +9 -8
  379. package/tldraw.css +59 -6
  380. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  381. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  382. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  383. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  384. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  385. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  386. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  387. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  388. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  389. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  390. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -0,0 +1,436 @@
1
+ import {
2
+ atom,
3
+ BaseBoxShapeUtil,
4
+ Circle2d,
5
+ createShapeId,
6
+ Geometry2d,
7
+ RecordProps,
8
+ resizeBox,
9
+ StateNode,
10
+ T,
11
+ TLBaseShape,
12
+ TLEventHandlers,
13
+ TLGeoShape,
14
+ TLResizeInfo,
15
+ TLShape,
16
+ TLTextShape,
17
+ toRichText,
18
+ Vec,
19
+ } from '@tldraw/editor'
20
+ import { TestEditor } from './TestEditor'
21
+
22
+ // Custom Circle Clip Shape Definition
23
+ export type CircleClipShape = TLBaseShape<
24
+ 'circle-clip',
25
+ {
26
+ w: number
27
+ h: number
28
+ }
29
+ >
30
+
31
+ export const isClippingEnabled$ = atom('isClippingEnabled', true)
32
+
33
+ export class CircleClipShapeUtil extends BaseBoxShapeUtil<CircleClipShape> {
34
+ static override type = 'circle-clip' as const
35
+ static override props: RecordProps<CircleClipShape> = {
36
+ w: T.number,
37
+ h: T.number,
38
+ }
39
+
40
+ override canBind() {
41
+ return false
42
+ }
43
+
44
+ override canReceiveNewChildrenOfType(shape: TLShape) {
45
+ return !shape.isLocked
46
+ }
47
+
48
+ override getDefaultProps(): CircleClipShape['props'] {
49
+ return {
50
+ w: 200,
51
+ h: 200,
52
+ }
53
+ }
54
+
55
+ override getGeometry(shape: CircleClipShape): Geometry2d {
56
+ const radius = Math.min(shape.props.w, shape.props.h) / 2
57
+ return new Circle2d({
58
+ radius,
59
+ x: shape.props.w / 2 - radius,
60
+ y: shape.props.h / 2 - radius,
61
+ isFilled: true,
62
+ })
63
+ }
64
+
65
+ override getClipPath(shape: CircleClipShape): Vec[] | undefined {
66
+ // Generate a polygon approximation of the circle
67
+ const centerX = shape.props.w / 2
68
+ const centerY = shape.props.h / 2
69
+ const radius = Math.min(shape.props.w, shape.props.h) / 2
70
+ const segments = 48 // More segments = smoother circle
71
+
72
+ const points: Vec[] = []
73
+ for (let i = 0; i < segments; i++) {
74
+ const angle = (i / segments) * Math.PI * 2
75
+ const x = centerX + Math.cos(angle) * radius
76
+ const y = centerY + Math.sin(angle) * radius
77
+ points.push(new Vec(x, y))
78
+ }
79
+
80
+ return points
81
+ }
82
+
83
+ override shouldClipChild(_child: TLShape): boolean {
84
+ // For now, clip all children - we removed the onlyClipText feature for simplicity
85
+ return isClippingEnabled$.get()
86
+ }
87
+
88
+ override component(_shape: CircleClipShape) {
89
+ // For testing purposes, we'll just return null
90
+ // In a real implementation, this would return JSX
91
+ return null as any
92
+ }
93
+
94
+ override indicator(_shape: CircleClipShape) {
95
+ // For testing purposes, we'll just return null
96
+ // In a real implementation, this would return JSX
97
+ return null as any
98
+ }
99
+
100
+ override onResize(shape: CircleClipShape, info: TLResizeInfo<CircleClipShape>) {
101
+ return resizeBox(shape, info)
102
+ }
103
+ }
104
+
105
+ export class CircleClipShapeTool extends StateNode {
106
+ static override id = 'circle-clip'
107
+
108
+ override onEnter(): void {
109
+ this.editor.setCursor({ type: 'cross', rotation: 0 })
110
+ }
111
+
112
+ override onPointerDown(info: Parameters<TLEventHandlers['onPointerDown']>[0]) {
113
+ if (info.target === 'canvas') {
114
+ const { originPagePoint } = this.editor.inputs
115
+
116
+ this.editor.createShape<CircleClipShape>({
117
+ type: 'circle-clip',
118
+ x: originPagePoint.x - 100,
119
+ y: originPagePoint.y - 100,
120
+ props: {
121
+ w: 200,
122
+ h: 200,
123
+ },
124
+ })
125
+ }
126
+ }
127
+ }
128
+
129
+ let editor: TestEditor
130
+
131
+ afterEach(() => {
132
+ editor?.dispose()
133
+ })
134
+
135
+ const ids = {
136
+ circleClip1: createShapeId('circleClip1'),
137
+ circleClip2: createShapeId('circleClip2'),
138
+ text1: createShapeId('text1'),
139
+ geo1: createShapeId('geo1'),
140
+ geo2: createShapeId('geo2'),
141
+ }
142
+
143
+ beforeEach(() => {
144
+ editor = new TestEditor({
145
+ shapeUtils: [CircleClipShapeUtil],
146
+ tools: [CircleClipShapeTool],
147
+ })
148
+
149
+ // Reset clipping state
150
+ isClippingEnabled$.set(true)
151
+ })
152
+
153
+ describe('CircleClipShapeUtil', () => {
154
+ describe('shape creation and properties', () => {
155
+ it('should create a circle clip shape with default properties', () => {
156
+ editor.createShape<CircleClipShape>({
157
+ id: ids.circleClip1,
158
+ type: 'circle-clip',
159
+ x: 100,
160
+ y: 100,
161
+ props: {
162
+ w: 200,
163
+ h: 200,
164
+ },
165
+ })
166
+
167
+ const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
168
+ expect(shape).toBeDefined()
169
+ expect(shape!.type).toBe('circle-clip')
170
+ expect(shape!.props.w).toBe(200)
171
+ expect(shape!.props.h).toBe(200)
172
+ })
173
+
174
+ it('should use default props when not specified', () => {
175
+ editor.createShape<CircleClipShape>({
176
+ id: ids.circleClip1,
177
+ type: 'circle-clip',
178
+ x: 100,
179
+ y: 100,
180
+ props: {},
181
+ })
182
+
183
+ const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
184
+ expect(shape!.props.w).toBe(200) // default from getDefaultProps
185
+ expect(shape!.props.h).toBe(200) // default from getDefaultProps
186
+ })
187
+ })
188
+
189
+ describe('geometry and clipping', () => {
190
+ it('should generate correct circle geometry', () => {
191
+ editor.createShape<CircleClipShape>({
192
+ id: ids.circleClip1,
193
+ type: 'circle-clip',
194
+ x: 100,
195
+ y: 100,
196
+ props: {
197
+ w: 200,
198
+ h: 200,
199
+ },
200
+ })
201
+
202
+ const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
203
+ const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
204
+ const geometry = util.getGeometry(shape!)
205
+
206
+ expect(geometry).toBeDefined()
207
+ expect(geometry.bounds).toBeDefined()
208
+ expect(geometry.bounds.width).toBe(200)
209
+ expect(geometry.bounds.height).toBe(200)
210
+ })
211
+
212
+ it('should generate clip path for circle', () => {
213
+ editor.createShape<CircleClipShape>({
214
+ id: ids.circleClip1,
215
+ type: 'circle-clip',
216
+ x: 100,
217
+ y: 100,
218
+ props: {
219
+ w: 200,
220
+ h: 200,
221
+ },
222
+ })
223
+
224
+ const shape = editor.getShape<CircleClipShape>(ids.circleClip1)
225
+ const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
226
+ const clipPath = util.getClipPath?.(shape!)
227
+ if (!clipPath) throw new Error('Clip path is undefined')
228
+
229
+ expect(clipPath).toBeDefined()
230
+ expect(Array.isArray(clipPath)).toBe(true)
231
+ expect(clipPath.length).toBeGreaterThan(0)
232
+
233
+ // Should be a polygon approximation of a circle
234
+ // Check that points are roughly in a circle pattern
235
+ const centerX = 100 // shape.x
236
+ const centerY = 100 // shape.y
237
+ const radius = 100 // min(w, h) / 2
238
+
239
+ clipPath.forEach((point) => {
240
+ const distance = Math.sqrt(Math.pow(point.x - centerX, 2) + Math.pow(point.y - centerY, 2))
241
+ expect(distance).toBeCloseTo(radius, 0)
242
+ })
243
+ })
244
+ })
245
+
246
+ describe('child clipping behavior', () => {
247
+ it('should clip children when clipping is enabled', () => {
248
+ editor.createShape<CircleClipShape>({
249
+ id: ids.circleClip1,
250
+ type: 'circle-clip',
251
+ x: 100,
252
+ y: 100,
253
+ props: {
254
+ w: 200,
255
+ h: 200,
256
+ },
257
+ })
258
+
259
+ editor.createShape<TLTextShape>({
260
+ id: ids.text1,
261
+ type: 'text',
262
+ x: 0,
263
+ y: 0,
264
+ parentId: ids.circleClip1,
265
+ props: {
266
+ richText: toRichText('Test text'),
267
+ },
268
+ })
269
+
270
+ const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
271
+ const textShape = editor.getShape<TLTextShape>(ids.text1)
272
+
273
+ // Clipping should be enabled by default
274
+ expect(isClippingEnabled$.get()).toBe(true)
275
+ expect(util.shouldClipChild?.(textShape!)).toBe(true)
276
+ expect(editor.getShapeClipPath(ids.text1)).toBeDefined()
277
+ })
278
+
279
+ it('should not clip children when clipping is disabled', () => {
280
+ isClippingEnabled$.set(false)
281
+
282
+ editor.createShape<CircleClipShape>({
283
+ id: ids.circleClip1,
284
+ type: 'circle-clip',
285
+ x: 100,
286
+ y: 100,
287
+ props: {
288
+ w: 200,
289
+ h: 200,
290
+ },
291
+ })
292
+
293
+ editor.createShape<TLTextShape>({
294
+ id: ids.text1,
295
+ type: 'text',
296
+ x: 0,
297
+ y: 0,
298
+ parentId: ids.circleClip1,
299
+ props: {
300
+ richText: toRichText('Test text'),
301
+ },
302
+ })
303
+
304
+ const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
305
+ const textShape = editor.getShape<TLTextShape>(ids.text1)
306
+
307
+ expect(isClippingEnabled$.get()).toBe(false)
308
+ expect(util.shouldClipChild?.(textShape!)).toBe(false)
309
+ expect(editor.getShapeClipPath(ids.text1)).toBeUndefined()
310
+ })
311
+ })
312
+ })
313
+
314
+ describe('Integration tests', () => {
315
+ it('should create and manage circle clip shapes with children', () => {
316
+ // Create circle clip shape
317
+ editor.createShape<CircleClipShape>({
318
+ id: ids.circleClip1,
319
+ type: 'circle-clip',
320
+ x: 100,
321
+ y: 100,
322
+ props: {
323
+ w: 200,
324
+ h: 200,
325
+ },
326
+ })
327
+
328
+ // Add text child
329
+ editor.createShape<TLTextShape>({
330
+ id: ids.text1,
331
+ type: 'text',
332
+ x: 50,
333
+ y: 50,
334
+ parentId: ids.circleClip1,
335
+ props: {
336
+ richText: toRichText('Clipped text'),
337
+ },
338
+ })
339
+
340
+ // Add geo child
341
+ editor.createShape<TLGeoShape>({
342
+ id: ids.geo1,
343
+ type: 'geo',
344
+ x: 150,
345
+ y: 150,
346
+ parentId: ids.circleClip1,
347
+ props: {
348
+ w: 50,
349
+ h: 50,
350
+ },
351
+ })
352
+
353
+ const circleClipShape = editor.getShape<CircleClipShape>(ids.circleClip1)
354
+ const textShape = editor.getShape<TLTextShape>(ids.text1)
355
+ const geoShape = editor.getShape<TLGeoShape>(ids.geo1)
356
+
357
+ expect(circleClipShape).toBeDefined()
358
+ expect(textShape!.parentId).toBe(ids.circleClip1)
359
+ expect(geoShape!.parentId).toBe(ids.circleClip1)
360
+
361
+ // Verify clipping behavior
362
+ const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
363
+ expect(util.shouldClipChild?.(textShape!)).toBe(true)
364
+ expect(util.shouldClipChild?.(geoShape!)).toBe(true)
365
+ expect(editor.getShapeClipPath(ids.text1)).toBeDefined()
366
+ expect(editor.getShapeClipPath(ids.geo1)).toBeDefined()
367
+
368
+ // Test clipping toggle
369
+ isClippingEnabled$.set(false)
370
+ expect(util.shouldClipChild?.(textShape!)).toBe(false)
371
+ expect(util.shouldClipChild?.(geoShape!)).toBe(false)
372
+ expect(editor.getShapeClipPath(ids.text1)).toBeUndefined()
373
+ expect(editor.getShapeClipPath(ids.geo1)).toBeUndefined()
374
+ })
375
+
376
+ it('should handle multiple circle clip shapes independently', () => {
377
+ // Create two circle clip shapes
378
+ editor.createShape<CircleClipShape>({
379
+ id: ids.circleClip1,
380
+ type: 'circle-clip',
381
+ x: 100,
382
+ y: 100,
383
+ props: {
384
+ w: 200,
385
+ h: 200,
386
+ },
387
+ })
388
+
389
+ editor.createShape<CircleClipShape>({
390
+ id: ids.circleClip2,
391
+ type: 'circle-clip',
392
+ x: 400,
393
+ y: 100,
394
+ props: {
395
+ w: 150,
396
+ h: 150,
397
+ },
398
+ })
399
+
400
+ // Add children to both
401
+ editor.createShape<TLTextShape>({
402
+ id: ids.text1,
403
+ type: 'text',
404
+ x: 0,
405
+ y: 0,
406
+ parentId: ids.circleClip1,
407
+ props: {
408
+ richText: toRichText('First clip'),
409
+ },
410
+ })
411
+
412
+ editor.createShape<TLTextShape>({
413
+ id: ids.geo1,
414
+ type: 'text',
415
+ x: 0,
416
+ y: 0,
417
+ parentId: ids.circleClip2,
418
+ props: {
419
+ richText: toRichText('Second clip'),
420
+ },
421
+ })
422
+
423
+ const util = editor.getShapeUtil<CircleClipShape>('circle-clip')
424
+ const text1 = editor.getShape<TLTextShape>(ids.text1)
425
+ const text2 = editor.getShape<TLTextShape>(ids.geo1)
426
+
427
+ // Both should be clipped when enabled
428
+ expect(util.shouldClipChild?.(text1!)).toBe(true)
429
+ expect(util.shouldClipChild?.(text2!)).toBe(true)
430
+
431
+ // Both should not be clipped when disabled
432
+ isClippingEnabled$.set(false)
433
+ expect(util.shouldClipChild?.(text1!)).toBe(false)
434
+ expect(util.shouldClipChild?.(text2!)).toBe(false)
435
+ })
436
+ })
@@ -1,8 +1,9 @@
1
1
  import { TLDrawShape, TLHighlightShape, last } from '@tldraw/editor'
2
+ import { vi } from 'vitest'
2
3
  import { TestEditor } from './TestEditor'
3
4
  import { TEST_DRAW_SHAPE_SCREEN_POINTS } from './drawing.data'
4
5
 
5
- jest.useFakeTimers()
6
+ vi.useFakeTimers()
6
7
 
7
8
  let editor: TestEditor
8
9
 
@@ -10,12 +10,13 @@ import {
10
10
  createBindingId,
11
11
  createShapeId,
12
12
  } from '@tldraw/editor'
13
+ import { vi } from 'vitest'
13
14
  import { getArrowBindings } from '../lib/shapes/arrow/shared'
14
15
  import { TestEditor } from './TestEditor'
15
16
 
16
17
  let editor: TestEditor
17
18
 
18
- jest.useFakeTimers()
19
+ vi.useFakeTimers()
19
20
 
20
21
  const ids = {
21
22
  boxA: createShapeId('boxA'),
@@ -297,7 +298,7 @@ describe('When one shape is selected', () => {
297
298
  })
298
299
 
299
300
  it('Flips the direct child shape positions if the shape is a group', async () => {
300
- const fn = jest.fn()
301
+ const fn = vi.fn()
301
302
 
302
303
  editor.selectAll()
303
304
  editor.groupShapes(editor.getSelectedShapeIds()) // this will also select the new group
@@ -306,7 +307,7 @@ describe('When one shape is selected', () => {
306
307
  editor.flipShapes(editor.getSelectedShapeIds(), 'horizontal')
307
308
 
308
309
  // The change event should have been called
309
- jest.runOnlyPendingTimers()
310
+ vi.runOnlyPendingTimers()
310
311
  expect(fn).toHaveBeenCalled()
311
312
 
312
313
  editor.expectShapeToMatch(
@@ -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)