tldraw 3.16.0-next.6611943ca24a → 3.16.0-next.8eb6d5c2d8f4

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 (336) hide show
  1. package/dist-cjs/index.d.ts +251 -114
  2. package/dist-cjs/index.js +34 -15
  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/useEditablePlainText.js +3 -5
  32. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  33. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  34. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  35. package/dist-cjs/lib/shapes/text/PlainTextArea.js +3 -2
  36. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  37. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  38. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  39. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +3 -1
  40. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  41. package/dist-cjs/lib/ui/TldrawUi.js +13 -12
  42. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  43. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  44. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  45. package/dist-cjs/lib/ui/components/AccessibilityMenu.js +1 -1
  46. package/dist-cjs/lib/ui/components/AccessibilityMenu.js.map +2 -2
  47. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  48. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  49. package/dist-cjs/lib/ui/components/InputModeMenu.js +77 -0
  50. package/dist-cjs/lib/ui/components/InputModeMenu.js.map +7 -0
  51. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +5 -5
  52. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  53. package/dist-cjs/lib/ui/components/LanguageMenu.js +1 -0
  54. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +2 -2
  55. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js +2 -0
  56. package/dist-cjs/lib/ui/components/MainMenu/DefaultMainMenuContent.js.map +2 -2
  57. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +2 -1
  58. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  59. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +1 -1
  60. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  61. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +13 -6
  62. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  63. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  64. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  65. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +147 -0
  66. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  67. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +70 -0
  68. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  69. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +23 -22
  70. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  71. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +23 -20
  72. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  73. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  74. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  75. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +2 -0
  76. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +38 -9
  78. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  80. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +2 -1
  82. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  83. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +1 -1
  84. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +6 -2
  86. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/menu-items.js +6 -4
  88. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  89. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  90. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  91. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +5 -3
  92. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  93. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  94. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  95. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +3 -0
  96. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  97. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +63 -14
  98. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  99. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +3 -0
  100. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  101. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +8 -8
  102. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  103. package/dist-cjs/lib/ui/context/actions.js +18 -33
  104. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  105. package/dist-cjs/lib/ui/context/components.js +2 -0
  106. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  107. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  108. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  109. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  110. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  111. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  112. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  113. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  114. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  115. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +13 -3
  116. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  117. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  118. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  119. package/dist-cjs/lib/ui/version.js +3 -3
  120. package/dist-cjs/lib/ui/version.js.map +1 -1
  121. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  122. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  123. package/dist-cjs/lib/utils/export/export.js +0 -20
  124. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  125. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  126. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  127. package/dist-esm/index.d.mts +251 -114
  128. package/dist-esm/index.mjs +67 -31
  129. package/dist-esm/index.mjs.map +2 -2
  130. package/dist-esm/lib/Tldraw.mjs +14 -4
  131. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  132. package/dist-esm/lib/defaultExternalContentHandlers.mjs +15 -4
  133. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  134. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  135. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  136. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +3 -2
  137. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  138. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +1 -1
  139. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  140. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +4 -5
  141. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  142. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +8 -1
  143. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  144. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +9 -3
  145. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  146. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1 -0
  147. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  148. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -0
  149. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  150. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +2 -1
  151. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  152. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  153. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  154. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  155. package/dist-esm/lib/shapes/shared/PlainTextLabel.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/SelectTool/childStates/DraggingHandle.mjs +3 -1
  165. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  166. package/dist-esm/lib/ui/TldrawUi.mjs +13 -12
  167. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  168. package/dist-esm/lib/ui/components/A11y.mjs +1 -2
  169. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  170. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs +3 -3
  171. package/dist-esm/lib/ui/components/AccessibilityMenu.mjs.map +2 -2
  172. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  173. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  174. package/dist-esm/lib/ui/components/InputModeMenu.mjs +57 -0
  175. package/dist-esm/lib/ui/components/InputModeMenu.mjs.map +7 -0
  176. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +5 -5
  177. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  178. package/dist-esm/lib/ui/components/LanguageMenu.mjs +1 -0
  179. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +2 -2
  180. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.mjs +2 -0
  181. package/dist-esm/lib/ui/components/MainMenu/DefaultMainMenuContent.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 +18 -7
  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 +50 -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} +20 -17
  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/menu-items.mjs +6 -4
  213. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  214. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +11 -3
  215. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  216. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +6 -4
  217. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  218. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  219. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  220. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +3 -0
  221. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  222. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +64 -14
  223. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  224. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +3 -0
  225. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  226. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +8 -8
  227. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  228. package/dist-esm/lib/ui/context/actions.mjs +18 -33
  229. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  230. package/dist-esm/lib/ui/context/components.mjs +2 -0
  231. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  232. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  233. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +1 -2
  234. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  235. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  236. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  237. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  238. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  239. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +13 -3
  240. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  241. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  242. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  243. package/dist-esm/lib/ui/version.mjs +3 -3
  244. package/dist-esm/lib/ui/version.mjs.map +1 -1
  245. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  246. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  247. package/dist-esm/lib/utils/export/export.mjs +0 -20
  248. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  249. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  250. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  251. package/package.json +3 -3
  252. package/src/index.ts +49 -23
  253. package/src/lib/Tldraw.tsx +15 -2
  254. package/src/lib/defaultExternalContentHandlers.ts +26 -4
  255. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +83 -13
  256. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +99 -5
  257. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +41 -0
  258. package/src/lib/shapes/arrow/arrow-types.ts +3 -5
  259. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  260. package/src/lib/shapes/arrow/arrowTargetState.ts +34 -3
  261. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +1 -1
  262. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +4 -5
  263. package/src/lib/shapes/frame/FrameShapeUtil.tsx +9 -0
  264. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +10 -3
  265. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1 -0
  266. package/src/lib/shapes/image/ImageShapeUtil.tsx +3 -0
  267. package/src/lib/shapes/note/NoteShapeUtil.tsx +1 -0
  268. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  269. package/src/lib/shapes/shared/PlainTextLabel.tsx +0 -6
  270. package/src/lib/shapes/shared/useEditablePlainText.ts +3 -10
  271. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  272. package/src/lib/shapes/text/PlainTextArea.tsx +4 -3
  273. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  274. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +6 -2
  275. package/src/lib/ui/TldrawUi.tsx +16 -10
  276. package/src/lib/ui/components/A11y.tsx +1 -2
  277. package/src/lib/ui/components/AccessibilityMenu.tsx +2 -2
  278. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  279. package/src/lib/ui/components/InputModeMenu.tsx +65 -0
  280. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +5 -5
  281. package/src/lib/ui/components/LanguageMenu.tsx +1 -0
  282. package/src/lib/ui/components/MainMenu/DefaultMainMenuContent.tsx +4 -0
  283. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +2 -1
  284. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +1 -2
  285. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +30 -14
  286. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +262 -381
  287. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +70 -50
  288. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +65 -0
  289. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +28 -19
  290. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  291. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  292. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -0
  293. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +32 -15
  294. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  295. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +1 -0
  296. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +1 -1
  297. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +9 -2
  298. package/src/lib/ui/components/menu-items.tsx +5 -3
  299. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +7 -3
  300. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +6 -3
  301. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  302. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +5 -1
  303. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +88 -29
  304. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +4 -0
  305. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +9 -9
  306. package/src/lib/ui/context/actions.tsx +25 -35
  307. package/src/lib/ui/context/components.tsx +3 -0
  308. package/src/lib/ui/context/events.tsx +3 -2
  309. package/src/lib/ui/hooks/useClipboardEvents.ts +1 -2
  310. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  311. package/src/lib/ui/hooks/useTools.tsx +1 -1
  312. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +12 -2
  313. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +13 -3
  314. package/src/lib/ui/kbd-utils.ts +10 -3
  315. package/src/lib/ui/version.ts +3 -3
  316. package/src/lib/ui.css +41 -4
  317. package/src/lib/utils/export/copyAs.ts +1 -24
  318. package/src/lib/utils/export/export.ts +0 -36
  319. package/src/lib/utils/export/exportAs.ts +1 -32
  320. package/src/test/TestEditor.ts +8 -2
  321. package/src/test/commands/setCamera.test.ts +13 -0
  322. package/src/test/custom-clipping.test.ts +436 -0
  323. package/src/test/frames.test.ts +15 -0
  324. package/src/test/getCulledShapes.test.tsx +71 -2
  325. package/tldraw.css +57 -7
  326. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  327. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  328. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  329. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js +0 -131
  330. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  331. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  332. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  333. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  334. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  335. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  336. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -110
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/ui/hooks/useClipboardEvents.ts"],
4
- "sourcesContent": ["import {\n\tEditor,\n\tFileHelpers,\n\tTLExternalContentSource,\n\tVec,\n\tVecLike,\n\tassert,\n\tcompact,\n\tisDefined,\n\tpreventDefault,\n\tstopEventPropagation,\n\tuniq,\n\tuseEditor,\n\tuseMaybeEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport lz from 'lz-string'\nimport { useCallback, useEffect } from 'react'\nimport { TLDRAW_CUSTOM_PNG_MIME_TYPE, getCanonicalClipboardReadType } from '../../utils/clipboard'\nimport { TLUiEventSource, useUiEvents } from '../context/events'\nimport { pasteFiles } from './clipboard/pasteFiles'\nimport { pasteUrl } from './clipboard/pasteUrl'\n\n// Expected paste mime types. The earlier in this array they appear, the higher preference we give\n// them. For example, we prefer the `web image/png+tldraw` type to plain `image/png` as it does not\n// strip some of the extra metadata we write into it.\nconst expectedPasteFileMimeTypes = [\n\tTLDRAW_CUSTOM_PNG_MIME_TYPE,\n\t'image/png',\n\t'image/jpeg',\n\t'image/webp',\n\t'image/svg+xml',\n] satisfies string[]\n\n/**\n * Strip HTML tags from a string.\n * @param html - The HTML to strip.\n * @internal\n */\nfunction stripHtml(html: string) {\n\t// See <https://github.com/developit/preact-markup/blob/4788b8d61b4e24f83688710746ee36e7464f7bbc/src/parse-markup.js#L60-L69>\n\tconst doc = document.implementation.createHTMLDocument('')\n\tdoc.documentElement.innerHTML = html.trim()\n\treturn doc.body.textContent || doc.body.innerText || ''\n}\n\n/** @public */\nexport const isValidHttpURL = (url: string) => {\n\ttry {\n\t\tconst u = new URL(url)\n\t\treturn u.protocol === 'http:' || u.protocol === 'https:'\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/** @public */\nconst getValidHttpURLList = (url: string) => {\n\tconst urls = url.split(/[\\n\\s]/)\n\tfor (const url of urls) {\n\t\ttry {\n\t\t\tconst u = new URL(url)\n\t\t\tif (!(u.protocol === 'http:' || u.protocol === 'https:')) {\n\t\t\t\treturn\n\t\t\t}\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t}\n\treturn uniq(urls)\n}\n\n/** @public */\nconst isSvgText = (text: string) => {\n\treturn /^<svg/.test(text)\n}\n\nconst INPUTS = ['input', 'select', 'textarea']\n\n/**\n * Get whether to disallow clipboard events.\n *\n * @internal\n */\nfunction areShortcutsDisabled(editor: Editor) {\n\tconst { activeElement } = document\n\n\treturn (\n\t\teditor.menus.hasAnyOpenMenus() ||\n\t\t(activeElement &&\n\t\t\t((activeElement as HTMLElement).isContentEditable ||\n\t\t\t\tINPUTS.indexOf(activeElement.tagName.toLowerCase()) > -1))\n\t)\n}\n\n/**\n * Handle text pasted into the editor.\n * @param editor - The editor instance.\n * @param data - The text to paste.\n * @param point - The point at which to paste the text.\n * @internal\n */\nconst handleText = (\n\teditor: Editor,\n\tdata: string,\n\tpoint?: VecLike,\n\tsources?: TLExternalContentSource[]\n) => {\n\tconst validUrlList = getValidHttpURLList(data)\n\tif (validUrlList) {\n\t\tfor (const url of validUrlList) {\n\t\t\tpasteUrl(editor, url, point)\n\t\t}\n\t} else if (isValidHttpURL(data)) {\n\t\tpasteUrl(editor, data, point)\n\t} else if (isSvgText(data)) {\n\t\teditor.markHistoryStoppingPoint('paste')\n\t\teditor.putExternalContent({\n\t\t\ttype: 'svg-text',\n\t\t\ttext: data,\n\t\t\tpoint,\n\t\t\tsources,\n\t\t})\n\t} else {\n\t\teditor.markHistoryStoppingPoint('paste')\n\t\teditor.putExternalContent({\n\t\t\ttype: 'text',\n\t\t\ttext: data,\n\t\t\tpoint,\n\t\t\tsources,\n\t\t})\n\t}\n}\n\n/**\n * Something found on the clipboard, either through the event's clipboard data or the browser's clipboard API.\n * @internal\n */\ntype ClipboardThing =\n\t| {\n\t\t\ttype: 'file'\n\t\t\tsource: Promise<File | null>\n\t }\n\t| {\n\t\t\ttype: 'blob'\n\t\t\tsource: Promise<Blob | null>\n\t }\n\t| {\n\t\t\ttype: 'url'\n\t\t\tsource: Promise<string>\n\t }\n\t| {\n\t\t\ttype: 'html'\n\t\t\tsource: Promise<string>\n\t }\n\t| {\n\t\t\ttype: 'text'\n\t\t\tsource: Promise<string>\n\t }\n\t| {\n\t\t\ttype: string\n\t\t\tsource: Promise<string>\n\t }\n\n/**\n * Handle a paste using event clipboard data. This is the \"original\"\n * paste method that uses the clipboard data from the paste event.\n * https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData\n *\n * @param editor - The editor\n * @param clipboardData - The clipboard data\n * @param point - The point to paste at\n * @internal\n */\nconst handlePasteFromEventClipboardData = async (\n\teditor: Editor,\n\tclipboardData: DataTransfer,\n\tpoint?: VecLike\n) => {\n\t// Do not paste while in any editing state\n\tif (editor.getEditingShapeId() !== null) return\n\n\tif (!clipboardData) {\n\t\tthrow Error('No clipboard data')\n\t}\n\n\tconst things: ClipboardThing[] = []\n\n\tfor (const item of Object.values(clipboardData.items)) {\n\t\tswitch (item.kind) {\n\t\t\tcase 'file': {\n\t\t\t\t// files are always blobs\n\t\t\t\tthings.push({\n\t\t\t\t\ttype: 'file',\n\t\t\t\t\tsource: new Promise((r) => r(item.getAsFile())) as Promise<File | null>,\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'string': {\n\t\t\t\t// strings can be text or html\n\t\t\t\tif (item.type === 'text/html') {\n\t\t\t\t\tthings.push({\n\t\t\t\t\t\ttype: 'html',\n\t\t\t\t\t\tsource: new Promise((r) => item.getAsString(r)) as Promise<string>,\n\t\t\t\t\t})\n\t\t\t\t} else if (item.type === 'text/plain') {\n\t\t\t\t\tthings.push({\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\tsource: new Promise((r) => item.getAsString(r)) as Promise<string>,\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tthings.push({ type: item.type, source: new Promise((r) => item.getAsString(r)) })\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\thandleClipboardThings(editor, things, point)\n}\n\n/**\n * Handle a paste using items retrieved from the Clipboard API.\n * https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem\n *\n * @param editor - The editor\n * @param clipboardItems - The clipboard items to handle\n * @param point - The point to paste at\n * @internal\n */\nconst handlePasteFromClipboardApi = async ({\n\teditor,\n\tclipboardItems,\n\tpoint,\n\tfallbackFiles,\n}: {\n\teditor: Editor\n\tclipboardItems: ClipboardItem[]\n\tpoint?: VecLike\n\tfallbackFiles?: File[]\n}) => {\n\t// We need to populate the array of clipboard things\n\t// based on the ClipboardItems from the Clipboard API.\n\t// This is done in a different way than when using\n\t// the clipboard data from the paste event.\n\n\tconst things: ClipboardThing[] = []\n\n\tfor (const item of clipboardItems) {\n\t\tfor (const type of expectedPasteFileMimeTypes) {\n\t\t\tif (item.types.includes(type)) {\n\t\t\t\tconst blobPromise = item\n\t\t\t\t\t.getType(type)\n\t\t\t\t\t.then((blob) => FileHelpers.rewriteMimeType(blob, getCanonicalClipboardReadType(type)))\n\t\t\t\tthings.push({\n\t\t\t\t\ttype: 'blob',\n\t\t\t\t\tsource: blobPromise,\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (item.types.includes('text/html')) {\n\t\t\tthings.push({\n\t\t\t\ttype: 'html',\n\t\t\t\tsource: (async () => {\n\t\t\t\t\tconst blob = await item.getType('text/html')\n\t\t\t\t\treturn await FileHelpers.blobToText(blob)\n\t\t\t\t})(),\n\t\t\t})\n\t\t}\n\n\t\tif (item.types.includes('text/uri-list')) {\n\t\t\tthings.push({\n\t\t\t\ttype: 'url',\n\t\t\t\tsource: (async () => {\n\t\t\t\t\tconst blob = await item.getType('text/uri-list')\n\t\t\t\t\treturn await FileHelpers.blobToText(blob)\n\t\t\t\t})(),\n\t\t\t})\n\t\t}\n\n\t\tif (item.types.includes('text/plain')) {\n\t\t\tthings.push({\n\t\t\t\ttype: 'text',\n\t\t\t\tsource: (async () => {\n\t\t\t\t\tconst blob = await item.getType('text/plain')\n\t\t\t\t\treturn await FileHelpers.blobToText(blob)\n\t\t\t\t})(),\n\t\t\t})\n\t\t}\n\t}\n\n\tif (fallbackFiles?.length && things.length === 1 && things[0].type === 'text') {\n\t\tthings.pop()\n\t\tthings.push(\n\t\t\t...fallbackFiles.map((f): ClipboardThing => ({ type: 'file', source: Promise.resolve(f) }))\n\t\t)\n\t} else if (fallbackFiles?.length && things.length === 0) {\n\t\t// Files pasted in Safari from your computer don't have types, so we need to use the fallback files directly\n\t\t// if they're available. This only works if pasted keyboard shortcuts. Pasting from the menu in Safari seems to never\n\t\t// let you access files that are copied from your computer.\n\t\tthings.push(\n\t\t\t...fallbackFiles.map((f): ClipboardThing => ({ type: 'file', source: Promise.resolve(f) }))\n\t\t)\n\t}\n\n\treturn await handleClipboardThings(editor, things, point)\n}\n\nasync function handleClipboardThings(editor: Editor, things: ClipboardThing[], point?: VecLike) {\n\t// 1. Handle files\n\t//\n\t// We need to handle files separately because if we want them to\n\t// be placed next to each other, we need to create them all at once.\n\n\tconst files = things.filter(\n\t\t(t) => (t.type === 'file' || t.type === 'blob') && t.source !== null\n\t) as Extract<ClipboardThing, { type: 'file' } | { type: 'blob' }>[]\n\n\t// Just paste the files, nothing else\n\tif (files.length) {\n\t\tif (files.length > editor.options.maxFilesAtOnce) {\n\t\t\tthrow Error('Too many files')\n\t\t}\n\t\tconst fileBlobs = compact(await Promise.all(files.map((t) => t.source)))\n\t\treturn await pasteFiles(editor, fileBlobs, point)\n\t}\n\n\t// 2. Generate clipboard results for non-file things\n\t//\n\t// Getting the source from the items is async, however they must be accessed syncronously;\n\t// we can't await them in a loop. So we'll map them to promises and await them all at once,\n\t// then make decisions based on what we find.\n\n\tconst results = await Promise.all<TLExternalContentSource>(\n\t\tthings\n\t\t\t.filter((t) => t.type !== 'file')\n\t\t\t.map(\n\t\t\t\t(t) =>\n\t\t\t\t\tnew Promise((r) => {\n\t\t\t\t\t\tconst thing = t as Exclude<ClipboardThing, { type: 'file' } | { type: 'blob' }>\n\n\t\t\t\t\t\tif (thing.type === 'file') {\n\t\t\t\t\t\t\tr({ type: 'error', data: null, reason: 'unexpected file' })\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthing.source.then((text) => {\n\t\t\t\t\t\t\t// first, see if we can find tldraw content, which is JSON inside of an html comment\n\t\t\t\t\t\t\tconst tldrawHtmlComment = text.match(/<div data-tldraw[^>]*>(.*)<\\/div>/)?.[1]\n\n\t\t\t\t\t\t\tif (tldrawHtmlComment) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t// First try parsing as plain JSON (version 2/3 formats)\n\t\t\t\t\t\t\t\t\tlet json\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tjson = JSON.parse(tldrawHtmlComment)\n\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\t// Fall back to LZ decompression (legacy format)\n\t\t\t\t\t\t\t\t\t\tconst jsonComment = lz.decompressFromBase64(tldrawHtmlComment)\n\t\t\t\t\t\t\t\t\t\tif (jsonComment === null) {\n\t\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\t\tdata: null,\n\t\t\t\t\t\t\t\t\t\t\t\treason: `found tldraw data comment but could not parse`,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tjson = JSON.parse(jsonComment)\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (json.type !== 'application/tldraw') {\n\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\tdata: json,\n\t\t\t\t\t\t\t\t\t\t\treason: `found tldraw data comment but JSON was of a different type: ${json.type}`,\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle versioned clipboard format\n\t\t\t\t\t\t\t\t\tif (json.version === 3) {\n\t\t\t\t\t\t\t\t\t\t// Version 3: Assets are plain, decompress only other data\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tconst otherData = JSON.parse(\n\t\t\t\t\t\t\t\t\t\t\t\tlz.decompressFromBase64(json.data.otherCompressed) || '{}'\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\tconst reconstructedData = {\n\t\t\t\t\t\t\t\t\t\t\t\tassets: json.data.assets || [],\n\t\t\t\t\t\t\t\t\t\t\t\t...otherData,\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tr({ type: 'tldraw', data: reconstructedData })\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\t\tdata: json,\n\t\t\t\t\t\t\t\t\t\t\t\treason: `failed to decompress version 2 clipboard data: ${error}`,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (json.version === 2) {\n\t\t\t\t\t\t\t\t\t\t// Version 2: Everything is plain, this had issues with encoding... :-/\n\t\t\t\t\t\t\t\t\t\t// TODO: nix this support after some time.\n\t\t\t\t\t\t\t\t\t\tr({ type: 'tldraw', data: json.data })\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t// Version 1 or no version: Legacy format\n\t\t\t\t\t\t\t\t\t\tif (typeof json.data === 'string') {\n\t\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\t\tdata: json,\n\t\t\t\t\t\t\t\t\t\t\t\treason:\n\t\t\t\t\t\t\t\t\t\t\t\t\t'found tldraw json but data was a string instead of a TLClipboardModel object',\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tr({ type: 'tldraw', data: json.data })\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\tdata: tldrawHtmlComment,\n\t\t\t\t\t\t\t\t\t\treason:\n\t\t\t\t\t\t\t\t\t\t\t'found tldraw json but data was a string instead of a TLClipboardModel object',\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (thing.type === 'html') {\n\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'html' })\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (thing.type === 'url') {\n\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'url' })\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// if we have not found a tldraw comment, Otherwise, try to parse the text as JSON directly.\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst json = JSON.parse(text)\n\t\t\t\t\t\t\t\t\tif (json.type === 'excalidraw/clipboard') {\n\t\t\t\t\t\t\t\t\t\t// If the clipboard contains content copied from excalidraw, then paste that\n\t\t\t\t\t\t\t\t\t\tr({ type: 'excalidraw', data: json })\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'json' })\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t// If we could not parse the text as JSON, then it's just text\n\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'text' })\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tr({ type: 'error', data: text, reason: 'unhandled case' })\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t)\n\t)\n\n\t// 3.\n\t//\n\t// Now that we know what kind of stuff we're dealing with, we can actual create some content.\n\t// There are priorities here, so order matters: we've already handled images and files, which\n\t// take first priority; then we want to handle tldraw content, then excalidraw content, then\n\t// html content, then links, and finally text content.\n\n\t// Try to paste tldraw content\n\tfor (const result of results) {\n\t\tif (result.type === 'tldraw') {\n\t\t\teditor.markHistoryStoppingPoint('paste')\n\t\t\teditor.putExternalContent({ type: 'tldraw', content: result.data, point })\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Try to paste excalidraw content\n\tfor (const result of results) {\n\t\tif (result.type === 'excalidraw') {\n\t\t\teditor.markHistoryStoppingPoint('paste')\n\t\t\teditor.putExternalContent({ type: 'excalidraw', content: result.data, point })\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Try to paste html content\n\tfor (const result of results) {\n\t\tif (result.type === 'text' && result.subtype === 'html') {\n\t\t\t// try to find a link\n\t\t\tconst rootNode = new DOMParser().parseFromString(result.data, 'text/html')\n\t\t\tconst bodyNode = rootNode.querySelector('body')\n\n\t\t\t// Edge on Windows 11 home appears to paste a link as a single <a/> in\n\t\t\t// the HTML document. If we're pasting a single like tag we'll just\n\t\t\t// assume the user meant to paste the URL.\n\t\t\tconst isHtmlSingleLink =\n\t\t\t\tbodyNode &&\n\t\t\t\tArray.from(bodyNode.children).filter((el) => el.nodeType === 1).length === 1 &&\n\t\t\t\tbodyNode.firstElementChild &&\n\t\t\t\tbodyNode.firstElementChild.tagName === 'A' &&\n\t\t\t\tbodyNode.firstElementChild.hasAttribute('href') &&\n\t\t\t\tbodyNode.firstElementChild.getAttribute('href') !== ''\n\n\t\t\tif (isHtmlSingleLink) {\n\t\t\t\tconst href = bodyNode.firstElementChild.getAttribute('href')!\n\t\t\t\thandleText(editor, href, point, results)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// If the html is NOT a link, and we have NO OTHER texty content, then paste the html as text\n\t\t\tif (!results.some((r) => r.type === 'text' && r.subtype !== 'html') && result.data.trim()) {\n\t\t\t\tconst html = stripHtml(result.data) ?? ''\n\t\t\t\tif (html) {\n\t\t\t\t\thandleText(editor, stripHtml(result.data), point, results)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the html is NOT a link, and we have other texty content, then paste the html as a text shape\n\t\t\tif (results.some((r) => r.type === 'text' && r.subtype !== 'html')) {\n\t\t\t\tconst html = stripHtml(result.data) ?? ''\n\t\t\t\tif (html) {\n\t\t\t\t\teditor.markHistoryStoppingPoint('paste')\n\t\t\t\t\teditor.putExternalContent({\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\ttext: html,\n\t\t\t\t\t\thtml: result.data,\n\t\t\t\t\t\tpoint,\n\t\t\t\t\t\tsources: results,\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Allow you to paste YouTube or Google Maps embeds, for example.\n\t\tif (result.type === 'text' && result.subtype === 'text' && result.data.startsWith('<iframe ')) {\n\t\t\t// try to find an iframe\n\t\t\tconst rootNode = new DOMParser().parseFromString(result.data, 'text/html')\n\t\t\tconst bodyNode = rootNode.querySelector('body')\n\n\t\t\tconst isSingleIframe =\n\t\t\t\tbodyNode &&\n\t\t\t\tArray.from(bodyNode.children).filter((el) => el.nodeType === 1).length === 1 &&\n\t\t\t\tbodyNode.firstElementChild &&\n\t\t\t\tbodyNode.firstElementChild.tagName === 'IFRAME' &&\n\t\t\t\tbodyNode.firstElementChild.hasAttribute('src') &&\n\t\t\t\tbodyNode.firstElementChild.getAttribute('src') !== ''\n\n\t\t\tif (isSingleIframe) {\n\t\t\t\tconst src = bodyNode.firstElementChild.getAttribute('src')!\n\t\t\t\thandleText(editor, src, point, results)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Try to paste a link\n\tfor (const result of results) {\n\t\tif (result.type === 'text' && result.subtype === 'url') {\n\t\t\tpasteUrl(editor, result.data, point, results)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Finally, if we haven't bailed on anything yet, we can paste text content\n\tfor (const result of results) {\n\t\tif (result.type === 'text' && result.subtype === 'text' && result.data.trim()) {\n\t\t\t// The clipboard may include multiple text items, but we only want to paste the first one\n\t\t\thandleText(editor, result.data, point, results)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n/**\n * When the user copies, write the contents to local storage and to the clipboard\n *\n * @param editor - The editor instance.\n * @public\n */\nconst handleNativeOrMenuCopy = async (editor: Editor) => {\n\tconst content = await editor.resolveAssetsInContent(\n\t\teditor.getContentFromCurrentPage(editor.getSelectedShapeIds())\n\t)\n\tif (!content) {\n\t\tif (navigator && navigator.clipboard) {\n\t\t\tnavigator.clipboard.writeText('')\n\t\t}\n\t\treturn\n\t}\n\n\t// Use versioned clipboard format for better compression\n\t// Version 3: Don't compress assets, only compress other data\n\tconst { assets, ...otherData } = content\n\tconst clipboardData = {\n\t\ttype: 'application/tldraw',\n\t\tkind: 'content',\n\t\tversion: 3,\n\t\tdata: {\n\t\t\tassets: assets || [], // Plain JSON, no compression\n\t\t\totherCompressed: lz.compressToBase64(JSON.stringify(otherData)), // Only compress non-asset data\n\t\t},\n\t}\n\n\t// Don't compress the final structure - just use plain JSON\n\tconst stringifiedClipboard = JSON.stringify(clipboardData)\n\n\tif (typeof navigator === 'undefined') {\n\t\treturn\n\t} else {\n\t\t// Extract the text from the clipboard\n\t\tconst textItems = content.shapes\n\t\t\t.map((shape) => {\n\t\t\t\tconst util = editor.getShapeUtil(shape)\n\t\t\t\treturn util.getText(shape)\n\t\t\t})\n\t\t\t.filter(isDefined)\n\n\t\tif (navigator.clipboard?.write) {\n\t\t\tconst htmlBlob = new Blob([`<div data-tldraw>${stringifiedClipboard}</div>`], {\n\t\t\t\ttype: 'text/html',\n\t\t\t})\n\n\t\t\tlet textContent = textItems.join(' ')\n\n\t\t\t// This is a bug in chrome android where it won't paste content if\n\t\t\t// the text/plain content is \"\" so we need to always add an empty\n\t\t\t// space \uD83E\uDD2C\n\t\t\tif (textContent === '') {\n\t\t\t\ttextContent = ' '\n\t\t\t}\n\n\t\t\tnavigator.clipboard.write([\n\t\t\t\tnew ClipboardItem({\n\t\t\t\t\t'text/html': htmlBlob,\n\t\t\t\t\t// What is this second blob used for?\n\t\t\t\t\t'text/plain': new Blob([textContent], { type: 'text/plain' }),\n\t\t\t\t}),\n\t\t\t])\n\t\t} else if (navigator.clipboard.writeText) {\n\t\t\tnavigator.clipboard.writeText(`<div data-tldraw>${stringifiedClipboard}</div>`)\n\t\t}\n\t}\n}\n\n/** @public */\nexport function useMenuClipboardEvents() {\n\tconst editor = useMaybeEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst copy = useCallback(\n\t\tasync function onCopy(source: TLUiEventSource) {\n\t\t\tassert(editor, 'editor is required for copy')\n\t\t\tif (editor.getSelectedShapeIds().length === 0) return\n\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\ttrackEvent('copy', { source })\n\t\t},\n\t\t[editor, trackEvent]\n\t)\n\n\tconst cut = useCallback(\n\t\tasync function onCut(source: TLUiEventSource) {\n\t\t\tif (!editor) return\n\t\t\tif (editor.getSelectedShapeIds().length === 0) return\n\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\teditor.deleteShapes(editor.getSelectedShapeIds())\n\t\t\ttrackEvent('cut', { source })\n\t\t},\n\t\t[editor, trackEvent]\n\t)\n\n\tconst paste = useCallback(\n\t\tasync function onPaste(\n\t\t\tdata: DataTransfer | ClipboardItem[],\n\t\t\tsource: TLUiEventSource,\n\t\t\tpoint?: VecLike\n\t\t) {\n\t\t\tif (!editor) return\n\t\t\t// If we're editing a shape, or we are focusing an editable input, then\n\t\t\t// we would want the user's paste interaction to go to that element or\n\t\t\t// input instead; e.g. when pasting text into a text shape's content\n\t\t\tif (editor.getEditingShapeId() !== null) return\n\n\t\t\tif (Array.isArray(data) && data[0] instanceof ClipboardItem) {\n\t\t\t\thandlePasteFromClipboardApi({ editor, clipboardItems: data, point })\n\t\t\t\ttrackEvent('paste', { source: 'menu' })\n\t\t\t} else {\n\t\t\t\t// Read it first and then recurse, kind of weird\n\t\t\t\tnavigator.clipboard.read().then((clipboardItems) => {\n\t\t\t\t\tpaste(clipboardItems, source, point)\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\t\t[editor, trackEvent]\n\t)\n\n\treturn {\n\t\tcopy,\n\t\tcut,\n\t\tpaste,\n\t}\n}\n\n/** @public */\nexport function useNativeClipboardEvents() {\n\tconst editor = useEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst appIsFocused = useValue('editor.isFocused', () => editor.getInstanceState().isFocused, [\n\t\teditor,\n\t])\n\n\tuseEffect(() => {\n\t\tif (!appIsFocused) return\n\t\tconst copy = async (e: ClipboardEvent) => {\n\t\t\tif (\n\t\t\t\teditor.getSelectedShapeIds().length === 0 ||\n\t\t\t\teditor.getEditingShapeId() !== null ||\n\t\t\t\tareShortcutsDisabled(editor)\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpreventDefault(e)\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\ttrackEvent('copy', { source: 'kbd' })\n\t\t}\n\n\t\tasync function cut(e: ClipboardEvent) {\n\t\t\tif (\n\t\t\t\teditor.getSelectedShapeIds().length === 0 ||\n\t\t\t\teditor.getEditingShapeId() !== null ||\n\t\t\t\tareShortcutsDisabled(editor)\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpreventDefault(e)\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\teditor.deleteShapes(editor.getSelectedShapeIds())\n\t\t\ttrackEvent('cut', { source: 'kbd' })\n\t\t}\n\n\t\tlet disablingMiddleClickPaste = false\n\t\tconst pointerUpHandler = (e: PointerEvent) => {\n\t\t\tif (e.button === 1) {\n\t\t\t\t// middle mouse button\n\t\t\t\tdisablingMiddleClickPaste = true\n\t\t\t\teditor.timers.requestAnimationFrame(() => {\n\t\t\t\t\tdisablingMiddleClickPaste = false\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst paste = (e: ClipboardEvent) => {\n\t\t\tif (disablingMiddleClickPaste) {\n\t\t\t\tstopEventPropagation(e)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// If we're editing a shape, or we are focusing an editable input, then\n\t\t\t// we would want the user's paste interaction to go to that element or\n\t\t\t// input instead; e.g. when pasting text into a text shape's content\n\t\t\tif (editor.getEditingShapeId() !== null || areShortcutsDisabled(editor)) return\n\n\t\t\t// Where should the shapes go?\n\t\t\tlet point: Vec | undefined = undefined\n\t\t\tlet pasteAtCursor = false\n\n\t\t\t// | Shiftkey | Paste at cursor mode | Paste at point? |\n\t\t\t// | N \t\t| N | N \t\t\t\t |\n\t\t\t// | Y \t\t| N | Y \t\t\t\t |\n\t\t\t// | N \t\t| Y | Y \t\t\t\t |\n\t\t\t// | Y \t\t| Y | N \t\t\t\t |\n\t\t\tif (editor.inputs.shiftKey) pasteAtCursor = true\n\t\t\tif (editor.user.getIsPasteAtCursorMode()) pasteAtCursor = !pasteAtCursor\n\t\t\tif (pasteAtCursor) point = editor.inputs.currentPagePoint\n\n\t\t\tconst pasteFromEvent = () => {\n\t\t\t\tif (e.clipboardData) {\n\t\t\t\t\thandlePasteFromEventClipboardData(editor, e.clipboardData, point)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if we can read from the clipboard API, we want to try using that first. that allows\n\t\t\t// us to access most things, and doesn't strip out metadata added to tldraw's own\n\t\t\t// copy-as-png features - so copied shapes come back in at the correct size.\n\t\t\tif (navigator.clipboard?.read) {\n\t\t\t\t// We can't read files from the filesystem using the clipboard API though - they'll\n\t\t\t\t// just come in as the file names instead. So we'll use the clipboard event's files\n\t\t\t\t// as a fallback - if we only got text, but do have files, we use those instead.\n\t\t\t\tconst fallbackFiles = Array.from(e.clipboardData?.files || [])\n\t\t\t\tnavigator.clipboard.read().then(\n\t\t\t\t\t(clipboardItems) => {\n\t\t\t\t\t\tif (Array.isArray(clipboardItems) && clipboardItems[0] instanceof ClipboardItem) {\n\t\t\t\t\t\t\thandlePasteFromClipboardApi({ editor, clipboardItems, point, fallbackFiles })\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t() => {\n\t\t\t\t\t\t// if reading from the clipboard fails, try to use the event clipboard data\n\t\t\t\t\t\tpasteFromEvent()\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tpasteFromEvent()\n\t\t\t}\n\n\t\t\tpreventDefault(e)\n\t\t\ttrackEvent('paste', { source: 'kbd' })\n\t\t}\n\n\t\tdocument.addEventListener('copy', copy)\n\t\tdocument.addEventListener('cut', cut)\n\t\tdocument.addEventListener('paste', paste)\n\t\tdocument.addEventListener('pointerup', pointerUpHandler)\n\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('copy', copy)\n\t\t\tdocument.removeEventListener('cut', cut)\n\t\t\tdocument.removeEventListener('paste', paste)\n\t\t\tdocument.removeEventListener('pointerup', pointerUpHandler)\n\t\t}\n\t}, [editor, trackEvent, appIsFocused])\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tEditor,\n\tFileHelpers,\n\tTLExternalContentSource,\n\tVec,\n\tVecLike,\n\tassert,\n\tcompact,\n\tisDefined,\n\tpreventDefault,\n\tuniq,\n\tuseEditor,\n\tuseMaybeEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport lz from 'lz-string'\nimport { useCallback, useEffect } from 'react'\nimport { TLDRAW_CUSTOM_PNG_MIME_TYPE, getCanonicalClipboardReadType } from '../../utils/clipboard'\nimport { TLUiEventSource, useUiEvents } from '../context/events'\nimport { pasteFiles } from './clipboard/pasteFiles'\nimport { pasteUrl } from './clipboard/pasteUrl'\n\n// Expected paste mime types. The earlier in this array they appear, the higher preference we give\n// them. For example, we prefer the `web image/png+tldraw` type to plain `image/png` as it does not\n// strip some of the extra metadata we write into it.\nconst expectedPasteFileMimeTypes = [\n\tTLDRAW_CUSTOM_PNG_MIME_TYPE,\n\t'image/png',\n\t'image/jpeg',\n\t'image/webp',\n\t'image/svg+xml',\n] satisfies string[]\n\n/**\n * Strip HTML tags from a string.\n * @param html - The HTML to strip.\n * @internal\n */\nfunction stripHtml(html: string) {\n\t// See <https://github.com/developit/preact-markup/blob/4788b8d61b4e24f83688710746ee36e7464f7bbc/src/parse-markup.js#L60-L69>\n\tconst doc = document.implementation.createHTMLDocument('')\n\tdoc.documentElement.innerHTML = html.trim()\n\treturn doc.body.textContent || doc.body.innerText || ''\n}\n\n/** @public */\nexport const isValidHttpURL = (url: string) => {\n\ttry {\n\t\tconst u = new URL(url)\n\t\treturn u.protocol === 'http:' || u.protocol === 'https:'\n\t} catch {\n\t\treturn false\n\t}\n}\n\n/** @public */\nconst getValidHttpURLList = (url: string) => {\n\tconst urls = url.split(/[\\n\\s]/)\n\tfor (const url of urls) {\n\t\ttry {\n\t\t\tconst u = new URL(url)\n\t\t\tif (!(u.protocol === 'http:' || u.protocol === 'https:')) {\n\t\t\t\treturn\n\t\t\t}\n\t\t} catch {\n\t\t\treturn\n\t\t}\n\t}\n\treturn uniq(urls)\n}\n\n/** @public */\nconst isSvgText = (text: string) => {\n\treturn /^<svg/.test(text)\n}\n\nconst INPUTS = ['input', 'select', 'textarea']\n\n/**\n * Get whether to disallow clipboard events.\n *\n * @internal\n */\nfunction areShortcutsDisabled(editor: Editor) {\n\tconst { activeElement } = document\n\n\treturn (\n\t\teditor.menus.hasAnyOpenMenus() ||\n\t\t(activeElement &&\n\t\t\t((activeElement as HTMLElement).isContentEditable ||\n\t\t\t\tINPUTS.indexOf(activeElement.tagName.toLowerCase()) > -1))\n\t)\n}\n\n/**\n * Handle text pasted into the editor.\n * @param editor - The editor instance.\n * @param data - The text to paste.\n * @param point - The point at which to paste the text.\n * @internal\n */\nconst handleText = (\n\teditor: Editor,\n\tdata: string,\n\tpoint?: VecLike,\n\tsources?: TLExternalContentSource[]\n) => {\n\tconst validUrlList = getValidHttpURLList(data)\n\tif (validUrlList) {\n\t\tfor (const url of validUrlList) {\n\t\t\tpasteUrl(editor, url, point)\n\t\t}\n\t} else if (isValidHttpURL(data)) {\n\t\tpasteUrl(editor, data, point)\n\t} else if (isSvgText(data)) {\n\t\teditor.markHistoryStoppingPoint('paste')\n\t\teditor.putExternalContent({\n\t\t\ttype: 'svg-text',\n\t\t\ttext: data,\n\t\t\tpoint,\n\t\t\tsources,\n\t\t})\n\t} else {\n\t\teditor.markHistoryStoppingPoint('paste')\n\t\teditor.putExternalContent({\n\t\t\ttype: 'text',\n\t\t\ttext: data,\n\t\t\tpoint,\n\t\t\tsources,\n\t\t})\n\t}\n}\n\n/**\n * Something found on the clipboard, either through the event's clipboard data or the browser's clipboard API.\n * @internal\n */\ntype ClipboardThing =\n\t| {\n\t\t\ttype: 'file'\n\t\t\tsource: Promise<File | null>\n\t }\n\t| {\n\t\t\ttype: 'blob'\n\t\t\tsource: Promise<Blob | null>\n\t }\n\t| {\n\t\t\ttype: 'url'\n\t\t\tsource: Promise<string>\n\t }\n\t| {\n\t\t\ttype: 'html'\n\t\t\tsource: Promise<string>\n\t }\n\t| {\n\t\t\ttype: 'text'\n\t\t\tsource: Promise<string>\n\t }\n\t| {\n\t\t\ttype: string\n\t\t\tsource: Promise<string>\n\t }\n\n/**\n * Handle a paste using event clipboard data. This is the \"original\"\n * paste method that uses the clipboard data from the paste event.\n * https://developer.mozilla.org/en-US/docs/Web/API/ClipboardEvent/clipboardData\n *\n * @param editor - The editor\n * @param clipboardData - The clipboard data\n * @param point - The point to paste at\n * @internal\n */\nconst handlePasteFromEventClipboardData = async (\n\teditor: Editor,\n\tclipboardData: DataTransfer,\n\tpoint?: VecLike\n) => {\n\t// Do not paste while in any editing state\n\tif (editor.getEditingShapeId() !== null) return\n\n\tif (!clipboardData) {\n\t\tthrow Error('No clipboard data')\n\t}\n\n\tconst things: ClipboardThing[] = []\n\n\tfor (const item of Object.values(clipboardData.items)) {\n\t\tswitch (item.kind) {\n\t\t\tcase 'file': {\n\t\t\t\t// files are always blobs\n\t\t\t\tthings.push({\n\t\t\t\t\ttype: 'file',\n\t\t\t\t\tsource: new Promise((r) => r(item.getAsFile())) as Promise<File | null>,\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'string': {\n\t\t\t\t// strings can be text or html\n\t\t\t\tif (item.type === 'text/html') {\n\t\t\t\t\tthings.push({\n\t\t\t\t\t\ttype: 'html',\n\t\t\t\t\t\tsource: new Promise((r) => item.getAsString(r)) as Promise<string>,\n\t\t\t\t\t})\n\t\t\t\t} else if (item.type === 'text/plain') {\n\t\t\t\t\tthings.push({\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\tsource: new Promise((r) => item.getAsString(r)) as Promise<string>,\n\t\t\t\t\t})\n\t\t\t\t} else {\n\t\t\t\t\tthings.push({ type: item.type, source: new Promise((r) => item.getAsString(r)) })\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\thandleClipboardThings(editor, things, point)\n}\n\n/**\n * Handle a paste using items retrieved from the Clipboard API.\n * https://developer.mozilla.org/en-US/docs/Web/API/ClipboardItem\n *\n * @param editor - The editor\n * @param clipboardItems - The clipboard items to handle\n * @param point - The point to paste at\n * @internal\n */\nconst handlePasteFromClipboardApi = async ({\n\teditor,\n\tclipboardItems,\n\tpoint,\n\tfallbackFiles,\n}: {\n\teditor: Editor\n\tclipboardItems: ClipboardItem[]\n\tpoint?: VecLike\n\tfallbackFiles?: File[]\n}) => {\n\t// We need to populate the array of clipboard things\n\t// based on the ClipboardItems from the Clipboard API.\n\t// This is done in a different way than when using\n\t// the clipboard data from the paste event.\n\n\tconst things: ClipboardThing[] = []\n\n\tfor (const item of clipboardItems) {\n\t\tfor (const type of expectedPasteFileMimeTypes) {\n\t\t\tif (item.types.includes(type)) {\n\t\t\t\tconst blobPromise = item\n\t\t\t\t\t.getType(type)\n\t\t\t\t\t.then((blob) => FileHelpers.rewriteMimeType(blob, getCanonicalClipboardReadType(type)))\n\t\t\t\tthings.push({\n\t\t\t\t\ttype: 'blob',\n\t\t\t\t\tsource: blobPromise,\n\t\t\t\t})\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\n\t\tif (item.types.includes('text/html')) {\n\t\t\tthings.push({\n\t\t\t\ttype: 'html',\n\t\t\t\tsource: (async () => {\n\t\t\t\t\tconst blob = await item.getType('text/html')\n\t\t\t\t\treturn await FileHelpers.blobToText(blob)\n\t\t\t\t})(),\n\t\t\t})\n\t\t}\n\n\t\tif (item.types.includes('text/uri-list')) {\n\t\t\tthings.push({\n\t\t\t\ttype: 'url',\n\t\t\t\tsource: (async () => {\n\t\t\t\t\tconst blob = await item.getType('text/uri-list')\n\t\t\t\t\treturn await FileHelpers.blobToText(blob)\n\t\t\t\t})(),\n\t\t\t})\n\t\t}\n\n\t\tif (item.types.includes('text/plain')) {\n\t\t\tthings.push({\n\t\t\t\ttype: 'text',\n\t\t\t\tsource: (async () => {\n\t\t\t\t\tconst blob = await item.getType('text/plain')\n\t\t\t\t\treturn await FileHelpers.blobToText(blob)\n\t\t\t\t})(),\n\t\t\t})\n\t\t}\n\t}\n\n\tif (fallbackFiles?.length && things.length === 1 && things[0].type === 'text') {\n\t\tthings.pop()\n\t\tthings.push(\n\t\t\t...fallbackFiles.map((f): ClipboardThing => ({ type: 'file', source: Promise.resolve(f) }))\n\t\t)\n\t} else if (fallbackFiles?.length && things.length === 0) {\n\t\t// Files pasted in Safari from your computer don't have types, so we need to use the fallback files directly\n\t\t// if they're available. This only works if pasted keyboard shortcuts. Pasting from the menu in Safari seems to never\n\t\t// let you access files that are copied from your computer.\n\t\tthings.push(\n\t\t\t...fallbackFiles.map((f): ClipboardThing => ({ type: 'file', source: Promise.resolve(f) }))\n\t\t)\n\t}\n\n\treturn await handleClipboardThings(editor, things, point)\n}\n\nasync function handleClipboardThings(editor: Editor, things: ClipboardThing[], point?: VecLike) {\n\t// 1. Handle files\n\t//\n\t// We need to handle files separately because if we want them to\n\t// be placed next to each other, we need to create them all at once.\n\n\tconst files = things.filter(\n\t\t(t) => (t.type === 'file' || t.type === 'blob') && t.source !== null\n\t) as Extract<ClipboardThing, { type: 'file' } | { type: 'blob' }>[]\n\n\t// Just paste the files, nothing else\n\tif (files.length) {\n\t\tif (files.length > editor.options.maxFilesAtOnce) {\n\t\t\tthrow Error('Too many files')\n\t\t}\n\t\tconst fileBlobs = compact(await Promise.all(files.map((t) => t.source)))\n\t\treturn await pasteFiles(editor, fileBlobs, point)\n\t}\n\n\t// 2. Generate clipboard results for non-file things\n\t//\n\t// Getting the source from the items is async, however they must be accessed syncronously;\n\t// we can't await them in a loop. So we'll map them to promises and await them all at once,\n\t// then make decisions based on what we find.\n\n\tconst results = await Promise.all<TLExternalContentSource>(\n\t\tthings\n\t\t\t.filter((t) => t.type !== 'file')\n\t\t\t.map(\n\t\t\t\t(t) =>\n\t\t\t\t\tnew Promise((r) => {\n\t\t\t\t\t\tconst thing = t as Exclude<ClipboardThing, { type: 'file' } | { type: 'blob' }>\n\n\t\t\t\t\t\tif (thing.type === 'file') {\n\t\t\t\t\t\t\tr({ type: 'error', data: null, reason: 'unexpected file' })\n\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t}\n\n\t\t\t\t\t\tthing.source.then((text) => {\n\t\t\t\t\t\t\t// first, see if we can find tldraw content, which is JSON inside of an html comment\n\t\t\t\t\t\t\tconst tldrawHtmlComment = text.match(/<div data-tldraw[^>]*>(.*)<\\/div>/)?.[1]\n\n\t\t\t\t\t\t\tif (tldrawHtmlComment) {\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t// First try parsing as plain JSON (version 2/3 formats)\n\t\t\t\t\t\t\t\t\tlet json\n\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\tjson = JSON.parse(tldrawHtmlComment)\n\t\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t\t// Fall back to LZ decompression (legacy format)\n\t\t\t\t\t\t\t\t\t\tconst jsonComment = lz.decompressFromBase64(tldrawHtmlComment)\n\t\t\t\t\t\t\t\t\t\tif (jsonComment === null) {\n\t\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\t\tdata: null,\n\t\t\t\t\t\t\t\t\t\t\t\treason: `found tldraw data comment but could not parse`,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t\tjson = JSON.parse(jsonComment)\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\tif (json.type !== 'application/tldraw') {\n\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\tdata: json,\n\t\t\t\t\t\t\t\t\t\t\treason: `found tldraw data comment but JSON was of a different type: ${json.type}`,\n\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t// Handle versioned clipboard format\n\t\t\t\t\t\t\t\t\tif (json.version === 3) {\n\t\t\t\t\t\t\t\t\t\t// Version 3: Assets are plain, decompress only other data\n\t\t\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\t\t\tconst otherData = JSON.parse(\n\t\t\t\t\t\t\t\t\t\t\t\tlz.decompressFromBase64(json.data.otherCompressed) || '{}'\n\t\t\t\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t\t\t\t\tconst reconstructedData = {\n\t\t\t\t\t\t\t\t\t\t\t\tassets: json.data.assets || [],\n\t\t\t\t\t\t\t\t\t\t\t\t...otherData,\n\t\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\t\tr({ type: 'tldraw', data: reconstructedData })\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\t\tdata: json,\n\t\t\t\t\t\t\t\t\t\t\t\treason: `failed to decompress version 2 clipboard data: ${error}`,\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t\tif (json.version === 2) {\n\t\t\t\t\t\t\t\t\t\t// Version 2: Everything is plain, this had issues with encoding... :-/\n\t\t\t\t\t\t\t\t\t\t// TODO: nix this support after some time.\n\t\t\t\t\t\t\t\t\t\tr({ type: 'tldraw', data: json.data })\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\t// Version 1 or no version: Legacy format\n\t\t\t\t\t\t\t\t\t\tif (typeof json.data === 'string') {\n\t\t\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\t\t\tdata: json,\n\t\t\t\t\t\t\t\t\t\t\t\treason:\n\t\t\t\t\t\t\t\t\t\t\t\t\t'found tldraw json but data was a string instead of a TLClipboardModel object',\n\t\t\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t\t\tr({ type: 'tldraw', data: json.data })\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\tr({\n\t\t\t\t\t\t\t\t\t\ttype: 'error',\n\t\t\t\t\t\t\t\t\t\tdata: tldrawHtmlComment,\n\t\t\t\t\t\t\t\t\t\treason:\n\t\t\t\t\t\t\t\t\t\t\t'found tldraw json but data was a string instead of a TLClipboardModel object',\n\t\t\t\t\t\t\t\t\t})\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\tif (thing.type === 'html') {\n\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'html' })\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\tif (thing.type === 'url') {\n\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'url' })\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\t\t// if we have not found a tldraw comment, Otherwise, try to parse the text as JSON directly.\n\t\t\t\t\t\t\t\ttry {\n\t\t\t\t\t\t\t\t\tconst json = JSON.parse(text)\n\t\t\t\t\t\t\t\t\tif (json.type === 'excalidraw/clipboard') {\n\t\t\t\t\t\t\t\t\t\t// If the clipboard contains content copied from excalidraw, then paste that\n\t\t\t\t\t\t\t\t\t\tr({ type: 'excalidraw', data: json })\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'json' })\n\t\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t} catch {\n\t\t\t\t\t\t\t\t\t// If we could not parse the text as JSON, then it's just text\n\t\t\t\t\t\t\t\t\tr({ type: 'text', data: text, subtype: 'text' })\n\t\t\t\t\t\t\t\t\treturn\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\tr({ type: 'error', data: text, reason: 'unhandled case' })\n\t\t\t\t\t\t})\n\t\t\t\t\t})\n\t\t\t)\n\t)\n\n\t// 3.\n\t//\n\t// Now that we know what kind of stuff we're dealing with, we can actual create some content.\n\t// There are priorities here, so order matters: we've already handled images and files, which\n\t// take first priority; then we want to handle tldraw content, then excalidraw content, then\n\t// html content, then links, and finally text content.\n\n\t// Try to paste tldraw content\n\tfor (const result of results) {\n\t\tif (result.type === 'tldraw') {\n\t\t\teditor.markHistoryStoppingPoint('paste')\n\t\t\teditor.putExternalContent({ type: 'tldraw', content: result.data, point })\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Try to paste excalidraw content\n\tfor (const result of results) {\n\t\tif (result.type === 'excalidraw') {\n\t\t\teditor.markHistoryStoppingPoint('paste')\n\t\t\teditor.putExternalContent({ type: 'excalidraw', content: result.data, point })\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Try to paste html content\n\tfor (const result of results) {\n\t\tif (result.type === 'text' && result.subtype === 'html') {\n\t\t\t// try to find a link\n\t\t\tconst rootNode = new DOMParser().parseFromString(result.data, 'text/html')\n\t\t\tconst bodyNode = rootNode.querySelector('body')\n\n\t\t\t// Edge on Windows 11 home appears to paste a link as a single <a/> in\n\t\t\t// the HTML document. If we're pasting a single like tag we'll just\n\t\t\t// assume the user meant to paste the URL.\n\t\t\tconst isHtmlSingleLink =\n\t\t\t\tbodyNode &&\n\t\t\t\tArray.from(bodyNode.children).filter((el) => el.nodeType === 1).length === 1 &&\n\t\t\t\tbodyNode.firstElementChild &&\n\t\t\t\tbodyNode.firstElementChild.tagName === 'A' &&\n\t\t\t\tbodyNode.firstElementChild.hasAttribute('href') &&\n\t\t\t\tbodyNode.firstElementChild.getAttribute('href') !== ''\n\n\t\t\tif (isHtmlSingleLink) {\n\t\t\t\tconst href = bodyNode.firstElementChild.getAttribute('href')!\n\t\t\t\thandleText(editor, href, point, results)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// If the html is NOT a link, and we have NO OTHER texty content, then paste the html as text\n\t\t\tif (!results.some((r) => r.type === 'text' && r.subtype !== 'html') && result.data.trim()) {\n\t\t\t\tconst html = stripHtml(result.data) ?? ''\n\t\t\t\tif (html) {\n\t\t\t\t\thandleText(editor, stripHtml(result.data), point, results)\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// If the html is NOT a link, and we have other texty content, then paste the html as a text shape\n\t\t\tif (results.some((r) => r.type === 'text' && r.subtype !== 'html')) {\n\t\t\t\tconst html = stripHtml(result.data) ?? ''\n\t\t\t\tif (html) {\n\t\t\t\t\teditor.markHistoryStoppingPoint('paste')\n\t\t\t\t\teditor.putExternalContent({\n\t\t\t\t\t\ttype: 'text',\n\t\t\t\t\t\ttext: html,\n\t\t\t\t\t\thtml: result.data,\n\t\t\t\t\t\tpoint,\n\t\t\t\t\t\tsources: results,\n\t\t\t\t\t})\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\t// Allow you to paste YouTube or Google Maps embeds, for example.\n\t\tif (result.type === 'text' && result.subtype === 'text' && result.data.startsWith('<iframe ')) {\n\t\t\t// try to find an iframe\n\t\t\tconst rootNode = new DOMParser().parseFromString(result.data, 'text/html')\n\t\t\tconst bodyNode = rootNode.querySelector('body')\n\n\t\t\tconst isSingleIframe =\n\t\t\t\tbodyNode &&\n\t\t\t\tArray.from(bodyNode.children).filter((el) => el.nodeType === 1).length === 1 &&\n\t\t\t\tbodyNode.firstElementChild &&\n\t\t\t\tbodyNode.firstElementChild.tagName === 'IFRAME' &&\n\t\t\t\tbodyNode.firstElementChild.hasAttribute('src') &&\n\t\t\t\tbodyNode.firstElementChild.getAttribute('src') !== ''\n\n\t\t\tif (isSingleIframe) {\n\t\t\t\tconst src = bodyNode.firstElementChild.getAttribute('src')!\n\t\t\t\thandleText(editor, src, point, results)\n\t\t\t\treturn\n\t\t\t}\n\t\t}\n\t}\n\n\t// Try to paste a link\n\tfor (const result of results) {\n\t\tif (result.type === 'text' && result.subtype === 'url') {\n\t\t\tpasteUrl(editor, result.data, point, results)\n\t\t\treturn\n\t\t}\n\t}\n\n\t// Finally, if we haven't bailed on anything yet, we can paste text content\n\tfor (const result of results) {\n\t\tif (result.type === 'text' && result.subtype === 'text' && result.data.trim()) {\n\t\t\t// The clipboard may include multiple text items, but we only want to paste the first one\n\t\t\thandleText(editor, result.data, point, results)\n\t\t\treturn\n\t\t}\n\t}\n}\n\n/**\n * When the user copies, write the contents to local storage and to the clipboard\n *\n * @param editor - The editor instance.\n * @public\n */\nconst handleNativeOrMenuCopy = async (editor: Editor) => {\n\tconst content = await editor.resolveAssetsInContent(\n\t\teditor.getContentFromCurrentPage(editor.getSelectedShapeIds())\n\t)\n\tif (!content) {\n\t\tif (navigator && navigator.clipboard) {\n\t\t\tnavigator.clipboard.writeText('')\n\t\t}\n\t\treturn\n\t}\n\n\t// Use versioned clipboard format for better compression\n\t// Version 3: Don't compress assets, only compress other data\n\tconst { assets, ...otherData } = content\n\tconst clipboardData = {\n\t\ttype: 'application/tldraw',\n\t\tkind: 'content',\n\t\tversion: 3,\n\t\tdata: {\n\t\t\tassets: assets || [], // Plain JSON, no compression\n\t\t\totherCompressed: lz.compressToBase64(JSON.stringify(otherData)), // Only compress non-asset data\n\t\t},\n\t}\n\n\t// Don't compress the final structure - just use plain JSON\n\tconst stringifiedClipboard = JSON.stringify(clipboardData)\n\n\tif (typeof navigator === 'undefined') {\n\t\treturn\n\t} else {\n\t\t// Extract the text from the clipboard\n\t\tconst textItems = content.shapes\n\t\t\t.map((shape) => {\n\t\t\t\tconst util = editor.getShapeUtil(shape)\n\t\t\t\treturn util.getText(shape)\n\t\t\t})\n\t\t\t.filter(isDefined)\n\n\t\tif (navigator.clipboard?.write) {\n\t\t\tconst htmlBlob = new Blob([`<div data-tldraw>${stringifiedClipboard}</div>`], {\n\t\t\t\ttype: 'text/html',\n\t\t\t})\n\n\t\t\tlet textContent = textItems.join(' ')\n\n\t\t\t// This is a bug in chrome android where it won't paste content if\n\t\t\t// the text/plain content is \"\" so we need to always add an empty\n\t\t\t// space \uD83E\uDD2C\n\t\t\tif (textContent === '') {\n\t\t\t\ttextContent = ' '\n\t\t\t}\n\n\t\t\tnavigator.clipboard.write([\n\t\t\t\tnew ClipboardItem({\n\t\t\t\t\t'text/html': htmlBlob,\n\t\t\t\t\t// What is this second blob used for?\n\t\t\t\t\t'text/plain': new Blob([textContent], { type: 'text/plain' }),\n\t\t\t\t}),\n\t\t\t])\n\t\t} else if (navigator.clipboard.writeText) {\n\t\t\tnavigator.clipboard.writeText(`<div data-tldraw>${stringifiedClipboard}</div>`)\n\t\t}\n\t}\n}\n\n/** @public */\nexport function useMenuClipboardEvents() {\n\tconst editor = useMaybeEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst copy = useCallback(\n\t\tasync function onCopy(source: TLUiEventSource) {\n\t\t\tassert(editor, 'editor is required for copy')\n\t\t\tif (editor.getSelectedShapeIds().length === 0) return\n\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\ttrackEvent('copy', { source })\n\t\t},\n\t\t[editor, trackEvent]\n\t)\n\n\tconst cut = useCallback(\n\t\tasync function onCut(source: TLUiEventSource) {\n\t\t\tif (!editor) return\n\t\t\tif (editor.getSelectedShapeIds().length === 0) return\n\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\teditor.deleteShapes(editor.getSelectedShapeIds())\n\t\t\ttrackEvent('cut', { source })\n\t\t},\n\t\t[editor, trackEvent]\n\t)\n\n\tconst paste = useCallback(\n\t\tasync function onPaste(\n\t\t\tdata: DataTransfer | ClipboardItem[],\n\t\t\tsource: TLUiEventSource,\n\t\t\tpoint?: VecLike\n\t\t) {\n\t\t\tif (!editor) return\n\t\t\t// If we're editing a shape, or we are focusing an editable input, then\n\t\t\t// we would want the user's paste interaction to go to that element or\n\t\t\t// input instead; e.g. when pasting text into a text shape's content\n\t\t\tif (editor.getEditingShapeId() !== null) return\n\n\t\t\tif (Array.isArray(data) && data[0] instanceof ClipboardItem) {\n\t\t\t\thandlePasteFromClipboardApi({ editor, clipboardItems: data, point })\n\t\t\t\ttrackEvent('paste', { source: 'menu' })\n\t\t\t} else {\n\t\t\t\t// Read it first and then recurse, kind of weird\n\t\t\t\tnavigator.clipboard.read().then((clipboardItems) => {\n\t\t\t\t\tpaste(clipboardItems, source, point)\n\t\t\t\t})\n\t\t\t}\n\t\t},\n\t\t[editor, trackEvent]\n\t)\n\n\treturn {\n\t\tcopy,\n\t\tcut,\n\t\tpaste,\n\t}\n}\n\n/** @public */\nexport function useNativeClipboardEvents() {\n\tconst editor = useEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst appIsFocused = useValue('editor.isFocused', () => editor.getInstanceState().isFocused, [\n\t\teditor,\n\t])\n\n\tuseEffect(() => {\n\t\tif (!appIsFocused) return\n\t\tconst copy = async (e: ClipboardEvent) => {\n\t\t\tif (\n\t\t\t\teditor.getSelectedShapeIds().length === 0 ||\n\t\t\t\teditor.getEditingShapeId() !== null ||\n\t\t\t\tareShortcutsDisabled(editor)\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\tpreventDefault(e)\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\ttrackEvent('copy', { source: 'kbd' })\n\t\t}\n\n\t\tasync function cut(e: ClipboardEvent) {\n\t\t\tif (\n\t\t\t\teditor.getSelectedShapeIds().length === 0 ||\n\t\t\t\teditor.getEditingShapeId() !== null ||\n\t\t\t\tareShortcutsDisabled(editor)\n\t\t\t) {\n\t\t\t\treturn\n\t\t\t}\n\t\t\tpreventDefault(e)\n\t\t\tawait handleNativeOrMenuCopy(editor)\n\t\t\teditor.deleteShapes(editor.getSelectedShapeIds())\n\t\t\ttrackEvent('cut', { source: 'kbd' })\n\t\t}\n\n\t\tlet disablingMiddleClickPaste = false\n\t\tconst pointerUpHandler = (e: PointerEvent) => {\n\t\t\tif (e.button === 1) {\n\t\t\t\t// middle mouse button\n\t\t\t\tdisablingMiddleClickPaste = true\n\t\t\t\teditor.timers.requestAnimationFrame(() => {\n\t\t\t\t\tdisablingMiddleClickPaste = false\n\t\t\t\t})\n\t\t\t}\n\t\t}\n\n\t\tconst paste = (e: ClipboardEvent) => {\n\t\t\tif (disablingMiddleClickPaste) {\n\t\t\t\teditor.markEventAsHandled(e)\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// If we're editing a shape, or we are focusing an editable input, then\n\t\t\t// we would want the user's paste interaction to go to that element or\n\t\t\t// input instead; e.g. when pasting text into a text shape's content\n\t\t\tif (editor.getEditingShapeId() !== null || areShortcutsDisabled(editor)) return\n\n\t\t\t// Where should the shapes go?\n\t\t\tlet point: Vec | undefined = undefined\n\t\t\tlet pasteAtCursor = false\n\n\t\t\t// | Shiftkey | Paste at cursor mode | Paste at point? |\n\t\t\t// | N \t\t| N | N \t\t\t\t |\n\t\t\t// | Y \t\t| N | Y \t\t\t\t |\n\t\t\t// | N \t\t| Y | Y \t\t\t\t |\n\t\t\t// | Y \t\t| Y | N \t\t\t\t |\n\t\t\tif (editor.inputs.shiftKey) pasteAtCursor = true\n\t\t\tif (editor.user.getIsPasteAtCursorMode()) pasteAtCursor = !pasteAtCursor\n\t\t\tif (pasteAtCursor) point = editor.inputs.currentPagePoint\n\n\t\t\tconst pasteFromEvent = () => {\n\t\t\t\tif (e.clipboardData) {\n\t\t\t\t\thandlePasteFromEventClipboardData(editor, e.clipboardData, point)\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// if we can read from the clipboard API, we want to try using that first. that allows\n\t\t\t// us to access most things, and doesn't strip out metadata added to tldraw's own\n\t\t\t// copy-as-png features - so copied shapes come back in at the correct size.\n\t\t\tif (navigator.clipboard?.read) {\n\t\t\t\t// We can't read files from the filesystem using the clipboard API though - they'll\n\t\t\t\t// just come in as the file names instead. So we'll use the clipboard event's files\n\t\t\t\t// as a fallback - if we only got text, but do have files, we use those instead.\n\t\t\t\tconst fallbackFiles = Array.from(e.clipboardData?.files || [])\n\t\t\t\tnavigator.clipboard.read().then(\n\t\t\t\t\t(clipboardItems) => {\n\t\t\t\t\t\tif (Array.isArray(clipboardItems) && clipboardItems[0] instanceof ClipboardItem) {\n\t\t\t\t\t\t\thandlePasteFromClipboardApi({ editor, clipboardItems, point, fallbackFiles })\n\t\t\t\t\t\t}\n\t\t\t\t\t},\n\t\t\t\t\t() => {\n\t\t\t\t\t\t// if reading from the clipboard fails, try to use the event clipboard data\n\t\t\t\t\t\tpasteFromEvent()\n\t\t\t\t\t}\n\t\t\t\t)\n\t\t\t} else {\n\t\t\t\tpasteFromEvent()\n\t\t\t}\n\n\t\t\tpreventDefault(e)\n\t\t\ttrackEvent('paste', { source: 'kbd' })\n\t\t}\n\n\t\tdocument.addEventListener('copy', copy)\n\t\tdocument.addEventListener('cut', cut)\n\t\tdocument.addEventListener('paste', paste)\n\t\tdocument.addEventListener('pointerup', pointerUpHandler)\n\n\t\treturn () => {\n\t\t\tdocument.removeEventListener('copy', copy)\n\t\t\tdocument.removeEventListener('cut', cut)\n\t\t\tdocument.removeEventListener('paste', paste)\n\t\t\tdocument.removeEventListener('pointerup', pointerUpHandler)\n\t\t}\n\t}, [editor, trackEvent, appIsFocused])\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["url"]
7
7
  }
@@ -8,12 +8,13 @@ function useExportAs() {
8
8
  const { addToast } = useToasts();
9
9
  const msg = useTranslation();
10
10
  return useCallback(
11
- (ids, format = "png", name) => {
11
+ (ids, opts = {}) => {
12
12
  assert(editor, "useExportAs: editor is required");
13
+ const { format = "png", name, scale = 1 } = opts;
13
14
  exportAs(editor, ids, {
14
15
  format,
15
16
  name,
16
- scale: 1
17
+ scale
17
18
  }).catch((e) => {
18
19
  console.error(e.message);
19
20
  addToast({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/ui/hooks/useExportAs.ts"],
4
- "sourcesContent": ["import { TLExportType, TLShapeId, assert, useMaybeEditor } from '@tldraw/editor'\nimport { useCallback } from 'react'\nimport { exportAs } from '../../utils/export/exportAs'\nimport { useToasts } from '../context/toasts'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport function useExportAs() {\n\tconst editor = useMaybeEditor()\n\tconst { addToast } = useToasts()\n\tconst msg = useTranslation()\n\n\treturn useCallback(\n\t\t(ids: TLShapeId[], format: TLExportType = 'png', name: string | undefined) => {\n\t\t\tassert(editor, 'useExportAs: editor is required')\n\t\t\texportAs(editor, ids, {\n\t\t\t\tformat,\n\t\t\t\tname,\n\t\t\t\tscale: 1,\n\t\t\t}).catch((e) => {\n\t\t\t\tconsole.error(e.message)\n\t\t\t\taddToast({\n\t\t\t\t\tid: 'export-fail',\n\t\t\t\t\ttitle: msg('toast.error.export-fail.title'),\n\t\t\t\t\tdescription: msg('toast.error.export-fail.desc'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\t[editor, addToast, msg]\n\t)\n}\n"],
5
- "mappings": "AAAA,SAAkC,QAAQ,sBAAsB;AAChE,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAGxB,SAAS,cAAc;AAC7B,QAAM,SAAS,eAAe;AAC9B,QAAM,EAAE,SAAS,IAAI,UAAU;AAC/B,QAAM,MAAM,eAAe;AAE3B,SAAO;AAAA,IACN,CAAC,KAAkB,SAAuB,OAAO,SAA6B;AAC7E,aAAO,QAAQ,iCAAiC;AAChD,eAAS,QAAQ,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,QACA,OAAO;AAAA,MACR,CAAC,EAAE,MAAM,CAAC,MAAM;AACf,gBAAQ,MAAM,EAAE,OAAO;AACvB,iBAAS;AAAA,UACR,IAAI;AAAA,UACJ,OAAO,IAAI,+BAA+B;AAAA,UAC1C,aAAa,IAAI,8BAA8B;AAAA,UAC/C,UAAU;AAAA,QACX,CAAC;AAAA,MACF,CAAC;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,UAAU,GAAG;AAAA,EACvB;AACD;",
4
+ "sourcesContent": ["import { TLExportType, TLShapeId, assert, useMaybeEditor } from '@tldraw/editor'\nimport { useCallback } from 'react'\nimport { exportAs } from '../../utils/export/exportAs'\nimport { useToasts } from '../context/toasts'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport function useExportAs() {\n\tconst editor = useMaybeEditor()\n\tconst { addToast } = useToasts()\n\tconst msg = useTranslation()\n\n\treturn useCallback(\n\t\t(ids: TLShapeId[], opts: { format?: TLExportType; name?: string; scale?: number } = {}) => {\n\t\t\tassert(editor, 'useExportAs: editor is required')\n\t\t\tconst { format = 'png', name, scale = 1 } = opts\n\t\t\texportAs(editor, ids, {\n\t\t\t\tformat,\n\t\t\t\tname,\n\t\t\t\tscale,\n\t\t\t}).catch((e) => {\n\t\t\t\tconsole.error(e.message)\n\t\t\t\taddToast({\n\t\t\t\t\tid: 'export-fail',\n\t\t\t\t\ttitle: msg('toast.error.export-fail.title'),\n\t\t\t\t\tdescription: msg('toast.error.export-fail.desc'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\t\t\t})\n\t\t},\n\t\t[editor, addToast, msg]\n\t)\n}\n"],
5
+ "mappings": "AAAA,SAAkC,QAAQ,sBAAsB;AAChE,SAAS,mBAAmB;AAC5B,SAAS,gBAAgB;AACzB,SAAS,iBAAiB;AAC1B,SAAS,sBAAsB;AAGxB,SAAS,cAAc;AAC7B,QAAM,SAAS,eAAe;AAC9B,QAAM,EAAE,SAAS,IAAI,UAAU;AAC/B,QAAM,MAAM,eAAe;AAE3B,SAAO;AAAA,IACN,CAAC,KAAkB,OAAiE,CAAC,MAAM;AAC1F,aAAO,QAAQ,iCAAiC;AAChD,YAAM,EAAE,SAAS,OAAO,MAAM,QAAQ,EAAE,IAAI;AAC5C,eAAS,QAAQ,KAAK;AAAA,QACrB;AAAA,QACA;AAAA,QACA;AAAA,MACD,CAAC,EAAE,MAAM,CAAC,MAAM;AACf,gBAAQ,MAAM,EAAE,OAAO;AACvB,iBAAS;AAAA,UACR,IAAI;AAAA,UACJ,OAAO,IAAI,+BAA+B;AAAA,UAC1C,aAAa,IAAI,8BAA8B;AAAA,UAC/C,UAAU;AAAA,QACX,CAAC;AAAA,MACF,CAAC;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,UAAU,GAAG;AAAA,EACvB;AACD;",
6
6
  "names": []
7
7
  }
@@ -113,7 +113,7 @@ function ToolsProvider({ overrides, children }) {
113
113
  createShape: (id) => editor.createShape({
114
114
  id,
115
115
  type: "arrow",
116
- props: { start: { x: 0, y: 0 }, end: { x: 200, y: 0 } }
116
+ props: { start: { x: 0, y: 200 }, end: { x: 200, y: 0 } }
117
117
  })
118
118
  });
119
119
  trackEvent("drag-tool", { source, id: "arrow" });
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/ui/hooks/useTools.tsx"],
4
- "sourcesContent": ["import {\n\tassertExists,\n\tcreateShapeId,\n\tEditor,\n\tGeoShapeGeoStyle,\n\tgetIndicesBetween,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\ttoRichText,\n\tuseMaybeEditor,\n} from '@tldraw/editor'\nimport * as React from 'react'\nimport { EmbedDialog } from '../components/EmbedDialog'\nimport { TLUiIconJsx } from '../components/primitives/TldrawUiIcon'\nimport { useA11y } from '../context/a11y'\nimport { TLUiEventSource, useUiEvents } from '../context/events'\nimport { TLUiIconType } from '../icon-types'\nimport { TLUiOverrideHelpers, useDefaultHelpers } from '../overrides'\nimport { TLUiTranslationKey } from './useTranslation/TLUiTranslationKey'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport interface TLUiToolItem<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n> {\n\tid: string\n\tlabel: TranslationKey\n\tshortcutsLabel?: TranslationKey\n\ticon: IconType | TLUiIconJsx\n\tonSelect(source: TLUiEventSource): void\n\tonDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void\n\t/**\n\t * The keyboard shortcut for this tool. This is a string that can be a single key,\n\t * or a combination of keys.\n\t * For example, `cmd+z` or `cmd+shift+z` or `cmd+u,ctrl+u`, or just `v` or `a`.\n\t * We have backwards compatibility with the old system, where we used to use\n\t * symbols to denote cmd/alt/shift, using `!` for shift, `$` for cmd, and `?` for alt.\n\t */\n\tkbd?: string\n\treadonlyOk?: boolean\n\tmeta?: {\n\t\t[key: string]: any\n\t}\n}\n\n/** @public */\nexport type TLUiToolsContextType = Record<string, TLUiToolItem>\n\n/** @internal */\nexport const ToolsContext = React.createContext<null | TLUiToolsContextType>(null)\n\n/** @public */\nexport interface TLUiToolsProviderProps {\n\toverrides?(\n\t\teditor: Editor,\n\t\ttools: TLUiToolsContextType,\n\t\thelpers: Partial<TLUiOverrideHelpers>\n\t): TLUiToolsContextType\n\tchildren: React.ReactNode\n}\n\n/** @internal */\nexport function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {\n\tconst editor = useMaybeEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst a11y = useA11y()\n\tconst msg = useTranslation()\n\tconst helpers = useDefaultHelpers()\n\n\tconst onToolSelect = React.useCallback(\n\t\t(\n\t\t\tsource: TLUiEventSource,\n\t\t\ttool: TLUiToolItem<TLUiTranslationKey, TLUiIconType>,\n\t\t\tid?: string\n\t\t) => {\n\t\t\ta11y.announce({ msg: msg(tool.label) })\n\t\t\ttrackEvent('select-tool', { source, id: id ?? tool.id })\n\t\t},\n\t\t[a11y, msg, trackEvent]\n\t)\n\n\tconst tools = React.useMemo<TLUiToolsContextType>(() => {\n\t\tif (!editor) return {}\n\t\tconst toolsArray: TLUiToolItem<TLUiTranslationKey, TLUiIconType>[] = [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: 'tool.select',\n\t\t\t\ticon: 'tool-pointer',\n\t\t\t\tkbd: 'v',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\tif (editor.isIn('select')) {\n\t\t\t\t\t\t// There's a quirk of select mode, where editing a shape is a sub-state of select.\n\t\t\t\t\t\t// Because the text tool can be locked/sticky, we need to make sure we exit the\n\t\t\t\t\t\t// text tool.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// psst, if you're changing this code, also change the code\n\t\t\t\t\t\t// in strange-tools.test.ts! Sadly it's duplicated there.\n\t\t\t\t\t\tconst currentNode = editor.root.getCurrent()!\n\t\t\t\t\t\tcurrentNode.exit({}, currentNode.id)\n\t\t\t\t\t\tcurrentNode.enter({}, currentNode.id)\n\t\t\t\t\t}\n\t\t\t\t\teditor.setCurrentTool('select')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'hand',\n\t\t\t\tlabel: 'tool.hand',\n\t\t\t\ticon: 'tool-hand',\n\t\t\t\tkbd: 'h',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('hand')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'eraser',\n\t\t\t\tlabel: 'tool.eraser',\n\t\t\t\ticon: 'tool-eraser',\n\t\t\t\tkbd: 'e',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('eraser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'draw',\n\t\t\t\tlabel: 'tool.draw',\n\t\t\t\ticon: 'tool-pencil',\n\t\t\t\tkbd: 'd,b,x',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('draw')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t...[...GeoShapeGeoStyle.values].map((geo) => ({\n\t\t\t\tid: geo,\n\t\t\t\tlabel: `tool.${geo}` as TLUiTranslationKey,\n\t\t\t\tmeta: {\n\t\t\t\t\tgeo,\n\t\t\t\t},\n\t\t\t\tkbd: geo === 'rectangle' ? 'r' : geo === 'ellipse' ? 'o' : undefined,\n\t\t\t\ticon: ('geo-' + geo) as TLUiIconType,\n\t\t\t\tonSelect(source: TLUiEventSource) {\n\t\t\t\t\teditor.run(() => {\n\t\t\t\t\t\teditor.setStyleForNextShapes(GeoShapeGeoStyle, geo)\n\t\t\t\t\t\teditor.setCurrentTool('geo')\n\t\t\t\t\t\tonToolSelect(source, this, `geo-${geo}`)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'geo', props: { w: 200, h: 200, geo } }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'geo' })\n\t\t\t\t},\n\t\t\t})),\n\t\t\t{\n\t\t\t\tid: 'arrow',\n\t\t\t\tlabel: 'tool.arrow',\n\t\t\t\ticon: 'tool-arrow',\n\t\t\t\tkbd: 'a',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('arrow')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\t\tprops: { start: { x: 0, y: 0 }, end: { x: 200, y: 0 } },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'arrow' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'line',\n\t\t\t\tlabel: 'tool.line',\n\t\t\t\ticon: 'tool-line',\n\t\t\t\tkbd: 'l',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('line')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => {\n\t\t\t\t\t\t\tconst [start, end] = getIndicesBetween(null, null, 2)\n\t\t\t\t\t\t\teditor.createShape<TLLineShape>({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'line',\n\t\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\t\tpoints: {\n\t\t\t\t\t\t\t\t\t\t[start]: { id: start, index: start, x: 0, y: 200 },\n\t\t\t\t\t\t\t\t\t\t[end]: { id: end, index: end, x: 200, y: 0 },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'line' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'frame',\n\t\t\t\tlabel: 'tool.frame',\n\t\t\t\ticon: 'tool-frame',\n\t\t\t\tkbd: 'f',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('frame')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'frame' }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'frame' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'text',\n\t\t\t\tlabel: 'tool.text',\n\t\t\t\ticon: 'tool-text',\n\t\t\t\tkbd: 't',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('text')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'text', props: { richText: toRichText('Text') } }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'text' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'asset',\n\t\t\t\tlabel: 'tool.media',\n\t\t\t\ticon: 'tool-media',\n\t\t\t\tkbd: 'cmd+u,ctrl+u',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.insertMedia()\n\t\t\t\t\tonToolSelect(source, this, 'media')\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'note',\n\t\t\t\tlabel: 'tool.note',\n\t\t\t\ticon: 'tool-note',\n\t\t\t\tkbd: 'n',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('note')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'note' }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'note' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'laser',\n\t\t\t\tlabel: 'tool.laser',\n\t\t\t\treadonlyOk: true,\n\t\t\t\ticon: 'tool-laser',\n\t\t\t\tkbd: 'k',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('laser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'embed',\n\t\t\t\tlabel: 'tool.embed',\n\t\t\t\ticon: 'dot',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.addDialog({ component: EmbedDialog })\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'highlight',\n\t\t\t\tlabel: 'tool.highlight',\n\t\t\t\ticon: 'tool-highlight',\n\t\t\t\t// TODO: pick a better shortcut\n\t\t\t\tkbd: 'shift+d',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('highlight')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t]\n\n\t\ttoolsArray.forEach((t) => (t.onSelect = t.onSelect.bind(t)))\n\n\t\tconst tools = Object.fromEntries(toolsArray.map((t) => [t.id, t]))\n\n\t\tif (overrides) {\n\t\t\treturn overrides(editor, tools, helpers)\n\t\t}\n\n\t\treturn tools\n\t}, [overrides, editor, helpers, onToolSelect, trackEvent])\n\n\treturn <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider>\n}\n\n/** @public */\nexport function useTools() {\n\tconst ctx = React.useContext(ToolsContext)\n\n\tif (!ctx) {\n\t\tthrow new Error('useTools must be used within a ToolProvider')\n\t}\n\n\treturn ctx\n}\n\n/**\n * Options for {@link onDragFromToolbarToCreateShape}.\n * @public\n */\nexport interface OnDragFromToolbarToCreateShapesOpts {\n\t/**\n\t * Create the shape being dragged. You don't need to worry about positioning it, as it'll be\n\t * immediately updated with the correct position.\n\t */\n\tcreateShape(id: TLShapeId): void\n\t/**\n\t * Called once the drag interaction has finished.\n\t */\n\tonDragEnd?(id: TLShapeId): void\n}\n\n/**\n * A helper method to use in {@link TLUiToolItem#onDragStart} to create a shape by dragging it from\n * the toolbar.\n * @public\n */\nexport function onDragFromToolbarToCreateShape(\n\teditor: Editor,\n\tinfo: TLPointerEventInfo,\n\topts: OnDragFromToolbarToCreateShapesOpts\n) {\n\tconst { x, y } = editor.inputs.currentPagePoint\n\n\tconst stoppingPoint = editor.markHistoryStoppingPoint('drag shape tool')\n\teditor.setCurrentTool('select.translating')\n\n\tconst id = createShapeId()\n\topts.createShape(id)\n\tconst shape = assertExists(editor.getShape(id), 'Shape not found')\n\n\tconst { w, h } = editor.getShapePageBounds(id)!\n\teditor.updateShape({ id, type: shape.type, x: x - w / 2, y: y - h / 2 })\n\teditor.select(id)\n\n\teditor.setCurrentTool('select.translating', {\n\t\t...info,\n\t\ttarget: 'shape',\n\t\tshape: editor.getShape(id),\n\t\tisCreating: true,\n\t\tcreatingMarkId: stoppingPoint,\n\t\tonCreate() {\n\t\t\teditor.setCurrentTool('select.idle')\n\t\t\teditor.select(id)\n\t\t\topts.onDragEnd?.(id)\n\t\t},\n\t})\n\n\teditor.getCurrentTool().setCurrentToolIdMask(shape.type)\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tassertExists,\n\tcreateShapeId,\n\tEditor,\n\tGeoShapeGeoStyle,\n\tgetIndicesBetween,\n\tTLLineShape,\n\tTLPointerEventInfo,\n\tTLShapeId,\n\ttoRichText,\n\tuseMaybeEditor,\n} from '@tldraw/editor'\nimport * as React from 'react'\nimport { EmbedDialog } from '../components/EmbedDialog'\nimport { TLUiIconJsx } from '../components/primitives/TldrawUiIcon'\nimport { useA11y } from '../context/a11y'\nimport { TLUiEventSource, useUiEvents } from '../context/events'\nimport { TLUiIconType } from '../icon-types'\nimport { TLUiOverrideHelpers, useDefaultHelpers } from '../overrides'\nimport { TLUiTranslationKey } from './useTranslation/TLUiTranslationKey'\nimport { useTranslation } from './useTranslation/useTranslation'\n\n/** @public */\nexport interface TLUiToolItem<\n\tTranslationKey extends string = string,\n\tIconType extends string = string,\n> {\n\tid: string\n\tlabel: TranslationKey\n\tshortcutsLabel?: TranslationKey\n\ticon: IconType | TLUiIconJsx\n\tonSelect(source: TLUiEventSource): void\n\tonDragStart?(source: TLUiEventSource, info: TLPointerEventInfo): void\n\t/**\n\t * The keyboard shortcut for this tool. This is a string that can be a single key,\n\t * or a combination of keys.\n\t * For example, `cmd+z` or `cmd+shift+z` or `cmd+u,ctrl+u`, or just `v` or `a`.\n\t * We have backwards compatibility with the old system, where we used to use\n\t * symbols to denote cmd/alt/shift, using `!` for shift, `$` for cmd, and `?` for alt.\n\t */\n\tkbd?: string\n\treadonlyOk?: boolean\n\tmeta?: {\n\t\t[key: string]: any\n\t}\n}\n\n/** @public */\nexport type TLUiToolsContextType = Record<string, TLUiToolItem>\n\n/** @internal */\nexport const ToolsContext = React.createContext<null | TLUiToolsContextType>(null)\n\n/** @public */\nexport interface TLUiToolsProviderProps {\n\toverrides?(\n\t\teditor: Editor,\n\t\ttools: TLUiToolsContextType,\n\t\thelpers: Partial<TLUiOverrideHelpers>\n\t): TLUiToolsContextType\n\tchildren: React.ReactNode\n}\n\n/** @internal */\nexport function ToolsProvider({ overrides, children }: TLUiToolsProviderProps) {\n\tconst editor = useMaybeEditor()\n\tconst trackEvent = useUiEvents()\n\n\tconst a11y = useA11y()\n\tconst msg = useTranslation()\n\tconst helpers = useDefaultHelpers()\n\n\tconst onToolSelect = React.useCallback(\n\t\t(\n\t\t\tsource: TLUiEventSource,\n\t\t\ttool: TLUiToolItem<TLUiTranslationKey, TLUiIconType>,\n\t\t\tid?: string\n\t\t) => {\n\t\t\ta11y.announce({ msg: msg(tool.label) })\n\t\t\ttrackEvent('select-tool', { source, id: id ?? tool.id })\n\t\t},\n\t\t[a11y, msg, trackEvent]\n\t)\n\n\tconst tools = React.useMemo<TLUiToolsContextType>(() => {\n\t\tif (!editor) return {}\n\t\tconst toolsArray: TLUiToolItem<TLUiTranslationKey, TLUiIconType>[] = [\n\t\t\t{\n\t\t\t\tid: 'select',\n\t\t\t\tlabel: 'tool.select',\n\t\t\t\ticon: 'tool-pointer',\n\t\t\t\tkbd: 'v',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\tif (editor.isIn('select')) {\n\t\t\t\t\t\t// There's a quirk of select mode, where editing a shape is a sub-state of select.\n\t\t\t\t\t\t// Because the text tool can be locked/sticky, we need to make sure we exit the\n\t\t\t\t\t\t// text tool.\n\t\t\t\t\t\t//\n\t\t\t\t\t\t// psst, if you're changing this code, also change the code\n\t\t\t\t\t\t// in strange-tools.test.ts! Sadly it's duplicated there.\n\t\t\t\t\t\tconst currentNode = editor.root.getCurrent()!\n\t\t\t\t\t\tcurrentNode.exit({}, currentNode.id)\n\t\t\t\t\t\tcurrentNode.enter({}, currentNode.id)\n\t\t\t\t\t}\n\t\t\t\t\teditor.setCurrentTool('select')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'hand',\n\t\t\t\tlabel: 'tool.hand',\n\t\t\t\ticon: 'tool-hand',\n\t\t\t\tkbd: 'h',\n\t\t\t\treadonlyOk: true,\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('hand')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'eraser',\n\t\t\t\tlabel: 'tool.eraser',\n\t\t\t\ticon: 'tool-eraser',\n\t\t\t\tkbd: 'e',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('eraser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'draw',\n\t\t\t\tlabel: 'tool.draw',\n\t\t\t\ticon: 'tool-pencil',\n\t\t\t\tkbd: 'd,b,x',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('draw')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t...[...GeoShapeGeoStyle.values].map((geo) => ({\n\t\t\t\tid: geo,\n\t\t\t\tlabel: `tool.${geo}` as TLUiTranslationKey,\n\t\t\t\tmeta: {\n\t\t\t\t\tgeo,\n\t\t\t\t},\n\t\t\t\tkbd: geo === 'rectangle' ? 'r' : geo === 'ellipse' ? 'o' : undefined,\n\t\t\t\ticon: ('geo-' + geo) as TLUiIconType,\n\t\t\t\tonSelect(source: TLUiEventSource) {\n\t\t\t\t\teditor.run(() => {\n\t\t\t\t\t\teditor.setStyleForNextShapes(GeoShapeGeoStyle, geo)\n\t\t\t\t\t\teditor.setCurrentTool('geo')\n\t\t\t\t\t\tonToolSelect(source, this, `geo-${geo}`)\n\t\t\t\t\t})\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'geo', props: { w: 200, h: 200, geo } }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'geo' })\n\t\t\t\t},\n\t\t\t})),\n\t\t\t{\n\t\t\t\tid: 'arrow',\n\t\t\t\tlabel: 'tool.arrow',\n\t\t\t\ticon: 'tool-arrow',\n\t\t\t\tkbd: 'a',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('arrow')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source: TLUiEventSource, info: TLPointerEventInfo) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'arrow',\n\t\t\t\t\t\t\t\tprops: { start: { x: 0, y: 200 }, end: { x: 200, y: 0 } },\n\t\t\t\t\t\t\t}),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'arrow' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'line',\n\t\t\t\tlabel: 'tool.line',\n\t\t\t\ticon: 'tool-line',\n\t\t\t\tkbd: 'l',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('line')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => {\n\t\t\t\t\t\t\tconst [start, end] = getIndicesBetween(null, null, 2)\n\t\t\t\t\t\t\teditor.createShape<TLLineShape>({\n\t\t\t\t\t\t\t\tid,\n\t\t\t\t\t\t\t\ttype: 'line',\n\t\t\t\t\t\t\t\tprops: {\n\t\t\t\t\t\t\t\t\tpoints: {\n\t\t\t\t\t\t\t\t\t\t[start]: { id: start, index: start, x: 0, y: 200 },\n\t\t\t\t\t\t\t\t\t\t[end]: { id: end, index: end, x: 200, y: 0 },\n\t\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t})\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'line' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'frame',\n\t\t\t\tlabel: 'tool.frame',\n\t\t\t\ticon: 'tool-frame',\n\t\t\t\tkbd: 'f',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('frame')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'frame' }),\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'frame' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'text',\n\t\t\t\tlabel: 'tool.text',\n\t\t\t\ticon: 'tool-text',\n\t\t\t\tkbd: 't',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('text')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) =>\n\t\t\t\t\t\t\teditor.createShape({ id, type: 'text', props: { richText: toRichText('Text') } }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'text' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'asset',\n\t\t\t\tlabel: 'tool.media',\n\t\t\t\ticon: 'tool-media',\n\t\t\t\tkbd: 'cmd+u,ctrl+u',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.insertMedia()\n\t\t\t\t\tonToolSelect(source, this, 'media')\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'note',\n\t\t\t\tlabel: 'tool.note',\n\t\t\t\ticon: 'tool-note',\n\t\t\t\tkbd: 'n',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('note')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t\tonDragStart(source, info) {\n\t\t\t\t\tonDragFromToolbarToCreateShape(editor, info, {\n\t\t\t\t\t\tcreateShape: (id) => editor.createShape({ id, type: 'note' }),\n\t\t\t\t\t\tonDragEnd: (id) => {\n\t\t\t\t\t\t\teditor.setEditingShape(id)\n\t\t\t\t\t\t\teditor.emit('select-all-text', { shapeId: id })\n\t\t\t\t\t\t},\n\t\t\t\t\t})\n\t\t\t\t\ttrackEvent('drag-tool', { source, id: 'note' })\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'laser',\n\t\t\t\tlabel: 'tool.laser',\n\t\t\t\treadonlyOk: true,\n\t\t\t\ticon: 'tool-laser',\n\t\t\t\tkbd: 'k',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('laser')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'embed',\n\t\t\t\tlabel: 'tool.embed',\n\t\t\t\ticon: 'dot',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\thelpers.addDialog({ component: EmbedDialog })\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t\t{\n\t\t\t\tid: 'highlight',\n\t\t\t\tlabel: 'tool.highlight',\n\t\t\t\ticon: 'tool-highlight',\n\t\t\t\t// TODO: pick a better shortcut\n\t\t\t\tkbd: 'shift+d',\n\t\t\t\tonSelect(source) {\n\t\t\t\t\teditor.setCurrentTool('highlight')\n\t\t\t\t\tonToolSelect(source, this)\n\t\t\t\t},\n\t\t\t},\n\t\t]\n\n\t\ttoolsArray.forEach((t) => (t.onSelect = t.onSelect.bind(t)))\n\n\t\tconst tools = Object.fromEntries(toolsArray.map((t) => [t.id, t]))\n\n\t\tif (overrides) {\n\t\t\treturn overrides(editor, tools, helpers)\n\t\t}\n\n\t\treturn tools\n\t}, [overrides, editor, helpers, onToolSelect, trackEvent])\n\n\treturn <ToolsContext.Provider value={tools}>{children}</ToolsContext.Provider>\n}\n\n/** @public */\nexport function useTools() {\n\tconst ctx = React.useContext(ToolsContext)\n\n\tif (!ctx) {\n\t\tthrow new Error('useTools must be used within a ToolProvider')\n\t}\n\n\treturn ctx\n}\n\n/**\n * Options for {@link onDragFromToolbarToCreateShape}.\n * @public\n */\nexport interface OnDragFromToolbarToCreateShapesOpts {\n\t/**\n\t * Create the shape being dragged. You don't need to worry about positioning it, as it'll be\n\t * immediately updated with the correct position.\n\t */\n\tcreateShape(id: TLShapeId): void\n\t/**\n\t * Called once the drag interaction has finished.\n\t */\n\tonDragEnd?(id: TLShapeId): void\n}\n\n/**\n * A helper method to use in {@link TLUiToolItem#onDragStart} to create a shape by dragging it from\n * the toolbar.\n * @public\n */\nexport function onDragFromToolbarToCreateShape(\n\teditor: Editor,\n\tinfo: TLPointerEventInfo,\n\topts: OnDragFromToolbarToCreateShapesOpts\n) {\n\tconst { x, y } = editor.inputs.currentPagePoint\n\n\tconst stoppingPoint = editor.markHistoryStoppingPoint('drag shape tool')\n\teditor.setCurrentTool('select.translating')\n\n\tconst id = createShapeId()\n\topts.createShape(id)\n\tconst shape = assertExists(editor.getShape(id), 'Shape not found')\n\n\tconst { w, h } = editor.getShapePageBounds(id)!\n\teditor.updateShape({ id, type: shape.type, x: x - w / 2, y: y - h / 2 })\n\teditor.select(id)\n\n\teditor.setCurrentTool('select.translating', {\n\t\t...info,\n\t\ttarget: 'shape',\n\t\tshape: editor.getShape(id),\n\t\tisCreating: true,\n\t\tcreatingMarkId: stoppingPoint,\n\t\tonCreate() {\n\t\t\teditor.setCurrentTool('select.idle')\n\t\t\teditor.select(id)\n\t\t\topts.onDragEnd?.(id)\n\t\t},\n\t})\n\n\teditor.getCurrentTool().setCurrentToolIdMask(shape.type)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["tools"]
7
7
  }
@@ -1,4 +1,9 @@
1
1
  const DEFAULT_TRANSLATION = {
2
+ "action.toggle-auto-pan": "Auto (trackpad)",
3
+ "action.toggle-auto-zoom": "Auto (mouse)",
4
+ "action.toggle-auto-none": "Auto",
5
+ "action.toggle-mouse": "Mouse",
6
+ "action.toggle-trackpad": "Trackpad",
2
7
  "action.convert-to-bookmark": "Convert to Bookmark",
3
8
  "action.convert-to-embed": "Convert to Embed",
4
9
  "action.open-embed-link": "Open link",
@@ -87,10 +92,10 @@ const DEFAULT_TRANSLATION = {
87
92
  "action.toggle-wrap-mode": "Toggle Select on wrap",
88
93
  "action.toggle-reduce-motion.menu": "Reduce motion",
89
94
  "action.toggle-reduce-motion": "Toggle reduce motion",
90
- "action.toggle-keyboard-shortcuts.menu": "Keyboard shortcuts",
95
+ "action.toggle-keyboard-shortcuts.menu": "Enable keyboard shortcuts",
91
96
  "action.toggle-keyboard-shortcuts": "Toggle keyboard shortcuts",
92
- "action.toggle-ui-labels.menu": "UI labels",
93
- "action.toggle-ui-labels": "Toggle UI labels",
97
+ "action.enhanced-a11y-mode.menu": "Enhanced accessibility mode",
98
+ "action.enhanced-a11y-mode": "Toggle enhanced accessibility mode",
94
99
  "action.toggle-edge-scrolling.menu": "Edge scrolling",
95
100
  "action.toggle-edge-scrolling": "Toggle edge scrolling",
96
101
  "action.toggle-debug-mode.menu": "Debug mode",
@@ -118,6 +123,7 @@ const DEFAULT_TRANSLATION = {
118
123
  "action.zoom-to-fit": "Zoom to fit",
119
124
  "action.zoom-to-selection": "Zoom to selection",
120
125
  "assets.files.size-too-big": "File size is too big",
126
+ "assets.files.maximum-size": "Maximum file size is {size}",
121
127
  "assets.files.type-not-allowed": "File type is not allowed",
122
128
  "assets.files.upload-failed": "Upload failed",
123
129
  "assets.files.amount-too-many": "Too many files",
@@ -182,6 +188,7 @@ const DEFAULT_TRANSLATION = {
182
188
  "geo-style.pentagon": "Pentagon",
183
189
  "geo-style.rectangle": "Rectangle",
184
190
  "geo-style.rhombus": "Rhombus",
191
+ "geo-style.rhombus-2": "Rhombus left",
185
192
  "geo-style.star": "Star",
186
193
  "geo-style.trapezoid": "Trapezoid",
187
194
  "geo-style.triangle": "Triangle",
@@ -256,6 +263,7 @@ const DEFAULT_TRANSLATION = {
256
263
  "tool.aspect-ratio.wide": "Wide (16:9)",
257
264
  "tool.image-toolbar-title": "Image tools",
258
265
  "tool.image-crop": "Crop image",
266
+ "tool.image-crop-confirm": "Confirm",
259
267
  "tool.media-alt-text": "Alternative text",
260
268
  "tool.media-alt-text-desc": "Give a description\u2026",
261
269
  "tool.media-alt-text-confirm": "Confirm",
@@ -304,6 +312,7 @@ const DEFAULT_TRANSLATION = {
304
312
  "menu.language": "Language",
305
313
  "menu.preferences": "Preferences",
306
314
  "menu.view": "View",
315
+ "menu.input-mode": "Input mode",
307
316
  "context-menu.title": "Context menu",
308
317
  "context-menu.edit": "Edit",
309
318
  "context-menu.arrange": "Arrange",
@@ -405,6 +414,7 @@ const DEFAULT_TRANSLATION = {
405
414
  "style-panel.opacity": "Opacity",
406
415
  "style-panel.size": "Size",
407
416
  "style-panel.spline": "Spline",
417
+ "style-panel.selected": "selected",
408
418
  "tool-panel.title": "Tools",
409
419
  "tool-panel.more": "More",
410
420
  "navigation-zone.title": "Navigation",