tldraw 3.16.0-canary.ffdf566dd0a8 → 3.16.0-internal.71f83a8a571b

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 (515) hide show
  1. package/dist-cjs/index.d.ts +348 -113
  2. package/dist-cjs/index.js +40 -14
  3. package/dist-cjs/index.js.map +2 -2
  4. package/dist-cjs/lib/Tldraw.js +12 -2
  5. package/dist-cjs/lib/Tldraw.js.map +2 -2
  6. package/dist-cjs/lib/canvas/TldrawScribble.js +1 -1
  7. package/dist-cjs/lib/canvas/TldrawScribble.js.map +2 -2
  8. package/dist-cjs/lib/defaultExternalContentHandlers.js +5 -4
  9. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +3 -3
  11. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  12. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +6 -0
  13. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +3 -3
  14. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  15. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js +3 -3
  16. package/dist-cjs/lib/shapes/arrow/elbow/ElbowArrowDebug.js.map +1 -1
  17. package/dist-cjs/lib/shapes/arrow/elbow/elbowArrowSnapLines.js.map +1 -1
  18. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +4 -4
  19. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  20. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +3 -3
  21. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  22. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +1 -1
  23. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +1 -1
  24. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +1 -1
  25. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +20 -13
  26. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  27. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +1 -1
  28. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +2 -2
  29. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +2 -2
  30. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +2 -2
  31. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +3 -2
  32. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  33. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js +2 -1
  34. package/dist-cjs/lib/shapes/geo/components/GeoShapeBody.js.map +2 -2
  35. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +5 -1
  36. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  37. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +6 -3
  38. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  39. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +5 -1
  40. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +2 -2
  41. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +6 -5
  42. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  43. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +4 -4
  44. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  45. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +1 -3
  46. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  47. package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
  48. package/dist-cjs/lib/shapes/shared/ShapeFill.js +4 -4
  49. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  50. package/dist-cjs/lib/shapes/shared/crop.js +1 -0
  51. package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
  52. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  53. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js +3 -4
  54. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  55. package/dist-cjs/lib/shapes/shared/useEditableRichText.js.map +2 -2
  56. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +0 -2
  57. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  58. package/dist-cjs/lib/shapes/text/PlainTextArea.js +2 -2
  59. package/dist-cjs/lib/shapes/text/PlainTextArea.js.map +2 -2
  60. package/dist-cjs/lib/shapes/text/RichTextArea.js +3 -3
  61. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  62. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +2 -2
  63. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
  64. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -3
  65. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +1 -1
  66. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +25 -1
  67. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  68. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +12 -0
  69. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  70. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +1 -1
  71. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  72. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  73. package/dist-cjs/lib/ui/TldrawUi.js +27 -12
  74. package/dist-cjs/lib/ui/TldrawUi.js.map +3 -3
  75. package/dist-cjs/lib/ui/assetUrls.js +13 -10
  76. package/dist-cjs/lib/ui/assetUrls.js.map +2 -2
  77. package/dist-cjs/lib/ui/components/A11y.js +1 -1
  78. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  79. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +12 -3
  80. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  81. package/dist-cjs/lib/ui/components/{FollowingIndicator.js → DefaultFollowingIndicator.js} +6 -6
  82. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +7 -0
  83. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js +3 -2
  84. package/dist-cjs/lib/ui/components/DefaultMenuPanel.js.map +2 -2
  85. package/dist-cjs/lib/ui/components/EditLinkDialog.js +11 -1
  86. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
  87. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +6 -6
  88. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +1 -1
  89. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +4 -4
  90. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  91. package/dist-cjs/lib/ui/components/MobileStylePanel.js +5 -3
  92. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +2 -2
  93. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js +1 -1
  94. package/dist-cjs/lib/ui/components/NavigationPanel/DefaultNavigationPanel.js.map +2 -2
  95. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js +3 -2
  96. package/dist-cjs/lib/ui/components/PageMenu/DefaultPageMenu.js.map +2 -2
  97. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js +3 -2
  98. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenuItem.js.map +2 -2
  99. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js +2 -2
  100. package/dist-cjs/lib/ui/components/SharePanel/UserPresenceColorPicker.js.map +2 -2
  101. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js +9 -4
  102. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanel.js.map +2 -2
  103. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js +255 -316
  104. package/dist-cjs/lib/ui/components/StylePanel/DefaultStylePanelContent.js.map +2 -2
  105. package/dist-cjs/lib/ui/components/{primitives/TldrawUiButtonPicker.js → StylePanel/StylePanelButtonPicker.js} +52 -56
  106. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +7 -0
  107. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js +68 -0
  108. package/dist-cjs/lib/ui/components/StylePanel/StylePanelContext.js.map +7 -0
  109. package/dist-cjs/lib/ui/components/StylePanel/{DoubleDropdownPicker.js → StylePanelDoubleDropdownPicker.js} +26 -25
  110. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +7 -0
  111. package/dist-cjs/lib/ui/components/StylePanel/{DropdownPicker.js → StylePanelDropdownPicker.js} +47 -43
  112. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDropdownPicker.js.map +7 -0
  113. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js +28 -0
  114. package/dist-cjs/lib/ui/components/StylePanel/StylePanelSubheading.js.map +7 -0
  115. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +3 -2
  116. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  117. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +39 -10
  118. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  119. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js +66 -21
  120. package/dist-cjs/lib/ui/components/Toolbar/DefaultToolbar.js.map +3 -3
  121. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js +15 -3
  122. package/dist-cjs/lib/ui/components/Toolbar/DefaultVideoToolbarContent.js.map +2 -2
  123. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js +3 -3
  124. package/dist-cjs/lib/ui/components/Toolbar/LinkEditor.js.map +2 -2
  125. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js +189 -80
  126. package/dist-cjs/lib/ui/components/Toolbar/OverflowingToolbar.js.map +3 -3
  127. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +2 -2
  128. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +2 -2
  129. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +11 -2
  130. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  131. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -2
  132. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  133. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +3 -2
  134. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +3 -3
  135. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +18 -5
  136. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  137. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js +21 -4
  138. package/dist-cjs/lib/ui/components/primitives/TldrawUiToolbar.js.map +2 -2
  139. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +185 -158
  140. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  141. package/dist-cjs/lib/ui/components/primitives/layout.js +76 -0
  142. package/dist-cjs/lib/ui/components/primitives/layout.js.map +7 -0
  143. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuContext.js.map +2 -2
  144. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js +25 -12
  145. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuGroup.js.map +2 -2
  146. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +154 -20
  147. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  148. package/dist-cjs/lib/ui/context/actions.js +23 -10
  149. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  150. package/dist-cjs/lib/ui/context/components.js +2 -0
  151. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  152. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  153. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +1 -1
  154. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  155. package/dist-cjs/lib/ui/hooks/useExportAs.js +3 -2
  156. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +2 -2
  157. package/dist-cjs/lib/ui/hooks/useTools.js +94 -9
  158. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  159. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  160. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +4 -2
  161. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  162. package/dist-cjs/lib/ui/kbd-utils.js +9 -3
  163. package/dist-cjs/lib/ui/kbd-utils.js.map +2 -2
  164. package/dist-cjs/lib/ui/version.js +3 -3
  165. package/dist-cjs/lib/ui/version.js.map +1 -1
  166. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js.map +1 -1
  167. package/dist-cjs/lib/utils/export/copyAs.js +1 -2
  168. package/dist-cjs/lib/utils/export/copyAs.js.map +2 -2
  169. package/dist-cjs/lib/utils/export/export.js +0 -20
  170. package/dist-cjs/lib/utils/export/export.js.map +2 -2
  171. package/dist-cjs/lib/utils/export/exportAs.js +1 -2
  172. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  173. package/dist-esm/index.d.mts +348 -113
  174. package/dist-esm/index.mjs +75 -29
  175. package/dist-esm/index.mjs.map +2 -2
  176. package/dist-esm/lib/Tldraw.mjs +14 -4
  177. package/dist-esm/lib/Tldraw.mjs.map +2 -2
  178. package/dist-esm/lib/canvas/TldrawScribble.mjs +1 -1
  179. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +2 -2
  180. package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -4
  181. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  182. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +4 -3
  183. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  184. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +6 -0
  185. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +3 -3
  186. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  187. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs +3 -3
  188. package/dist-esm/lib/shapes/arrow/elbow/ElbowArrowDebug.mjs.map +1 -1
  189. package/dist-esm/lib/shapes/arrow/elbow/elbowArrowSnapLines.mjs.map +1 -1
  190. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +5 -5
  191. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  192. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +4 -3
  193. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  194. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +1 -1
  195. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +1 -1
  196. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +1 -1
  197. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +21 -13
  198. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  199. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +1 -1
  200. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +2 -2
  201. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +3 -3
  202. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +2 -2
  203. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +4 -2
  204. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  205. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs +2 -1
  206. package/dist-esm/lib/shapes/geo/components/GeoShapeBody.mjs.map +2 -2
  207. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +6 -1
  208. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  209. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +6 -3
  210. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  211. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +6 -1
  212. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +2 -2
  213. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +7 -5
  214. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  215. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +5 -5
  216. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  217. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +1 -3
  218. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  219. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
  220. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +5 -4
  221. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  222. package/dist-esm/lib/shapes/shared/crop.mjs +1 -0
  223. package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
  224. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  225. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs +4 -5
  226. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  227. package/dist-esm/lib/shapes/shared/useEditableRichText.mjs.map +2 -2
  228. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +0 -2
  229. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  230. package/dist-esm/lib/shapes/text/PlainTextArea.mjs +3 -3
  231. package/dist-esm/lib/shapes/text/PlainTextArea.mjs.map +2 -2
  232. package/dist-esm/lib/shapes/text/RichTextArea.mjs +3 -4
  233. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  234. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +3 -2
  235. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
  236. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -3
  237. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +1 -1
  238. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +26 -1
  239. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  240. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +13 -0
  241. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  242. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +1 -1
  243. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  244. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  245. package/dist-esm/lib/ui/TldrawUi.mjs +29 -14
  246. package/dist-esm/lib/ui/TldrawUi.mjs.map +3 -3
  247. package/dist-esm/lib/ui/assetUrls.mjs +13 -10
  248. package/dist-esm/lib/ui/assetUrls.mjs.map +2 -2
  249. package/dist-esm/lib/ui/components/A11y.mjs +2 -2
  250. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  251. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +12 -3
  252. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  253. package/dist-esm/lib/ui/components/{FollowingIndicator.mjs → DefaultFollowingIndicator.mjs} +3 -3
  254. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +7 -0
  255. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs +3 -2
  256. package/dist-esm/lib/ui/components/DefaultMenuPanel.mjs.map +2 -2
  257. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +11 -1
  258. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
  259. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +6 -6
  260. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +1 -1
  261. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +4 -4
  262. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  263. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +6 -3
  264. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +2 -2
  265. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs +1 -1
  266. package/dist-esm/lib/ui/components/NavigationPanel/DefaultNavigationPanel.mjs.map +2 -2
  267. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs +4 -3
  268. package/dist-esm/lib/ui/components/PageMenu/DefaultPageMenu.mjs.map +2 -2
  269. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs +3 -2
  270. package/dist-esm/lib/ui/components/SharePanel/PeopleMenuItem.mjs.map +2 -2
  271. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs +2 -2
  272. package/dist-esm/lib/ui/components/SharePanel/UserPresenceColorPicker.mjs.map +2 -2
  273. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs +14 -5
  274. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanel.mjs.map +2 -2
  275. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs +257 -320
  276. package/dist-esm/lib/ui/components/StylePanel/DefaultStylePanelContent.mjs.map +2 -2
  277. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +126 -0
  278. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +7 -0
  279. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs +48 -0
  280. package/dist-esm/lib/ui/components/StylePanel/StylePanelContext.mjs.map +7 -0
  281. package/dist-esm/lib/ui/components/StylePanel/{DoubleDropdownPicker.mjs → StylePanelDoubleDropdownPicker.mjs} +23 -22
  282. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +7 -0
  283. package/dist-esm/lib/ui/components/StylePanel/{DropdownPicker.mjs → StylePanelDropdownPicker.mjs} +44 -40
  284. package/dist-esm/lib/ui/components/StylePanel/StylePanelDropdownPicker.mjs.map +7 -0
  285. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs +8 -0
  286. package/dist-esm/lib/ui/components/StylePanel/StylePanelSubheading.mjs.map +7 -0
  287. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +3 -2
  288. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  289. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +39 -10
  290. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  291. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs +56 -21
  292. package/dist-esm/lib/ui/components/Toolbar/DefaultToolbar.mjs.map +2 -2
  293. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs +15 -3
  294. package/dist-esm/lib/ui/components/Toolbar/DefaultVideoToolbarContent.mjs.map +2 -2
  295. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs +3 -3
  296. package/dist-esm/lib/ui/components/Toolbar/LinkEditor.mjs.map +2 -2
  297. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs +192 -81
  298. package/dist-esm/lib/ui/components/Toolbar/OverflowingToolbar.mjs.map +3 -3
  299. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +2 -2
  300. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +2 -2
  301. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +12 -3
  302. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  303. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +3 -3
  304. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  305. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +3 -2
  306. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
  307. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +18 -5
  308. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  309. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs +21 -4
  310. package/dist-esm/lib/ui/components/primitives/TldrawUiToolbar.mjs.map +2 -2
  311. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +195 -160
  312. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  313. package/dist-esm/lib/ui/components/primitives/layout.mjs +46 -0
  314. package/dist-esm/lib/ui/components/primitives/layout.mjs.map +7 -0
  315. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuContext.mjs.map +2 -2
  316. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs +25 -12
  317. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuGroup.mjs.map +2 -2
  318. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +162 -22
  319. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  320. package/dist-esm/lib/ui/context/actions.mjs +23 -10
  321. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  322. package/dist-esm/lib/ui/context/components.mjs +2 -0
  323. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  324. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  325. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +2 -2
  326. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  327. package/dist-esm/lib/ui/hooks/useExportAs.mjs +3 -2
  328. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +2 -2
  329. package/dist-esm/lib/ui/hooks/useTools.mjs +102 -10
  330. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  331. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +4 -2
  332. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  333. package/dist-esm/lib/ui/kbd-utils.mjs +9 -3
  334. package/dist-esm/lib/ui/kbd-utils.mjs.map +2 -2
  335. package/dist-esm/lib/ui/version.mjs +3 -3
  336. package/dist-esm/lib/ui/version.mjs.map +1 -1
  337. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs.map +1 -1
  338. package/dist-esm/lib/utils/export/copyAs.mjs +1 -2
  339. package/dist-esm/lib/utils/export/copyAs.mjs.map +2 -2
  340. package/dist-esm/lib/utils/export/export.mjs +0 -20
  341. package/dist-esm/lib/utils/export/export.mjs.map +2 -2
  342. package/dist-esm/lib/utils/export/exportAs.mjs +1 -2
  343. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  344. package/package.json +11 -34
  345. package/src/index.ts +56 -22
  346. package/src/lib/Tldraw.tsx +15 -2
  347. package/src/lib/canvas/TldrawScribble.tsx +1 -1
  348. package/src/lib/defaultExternalContentHandlers.ts +12 -4
  349. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +2 -1
  350. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +6 -5
  351. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +48 -6
  352. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +4 -3
  353. package/src/lib/shapes/arrow/arrowLabel.ts +8 -0
  354. package/src/lib/shapes/arrow/arrowTargetState.ts +1 -1
  355. package/src/lib/shapes/arrow/elbow/ElbowArrowDebug.tsx +3 -3
  356. package/src/lib/shapes/arrow/elbow/elbowArrowSnapLines.tsx +2 -2
  357. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +5 -5
  358. package/src/lib/shapes/draw/DrawShapeTool.test.ts +0 -5
  359. package/src/lib/shapes/draw/DrawShapeUtil.tsx +4 -3
  360. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +1 -1
  361. package/src/lib/shapes/frame/FrameShapeTool.ts +1 -1
  362. package/src/lib/shapes/frame/FrameShapeUtil.tsx +30 -14
  363. package/src/lib/shapes/frame/components/FrameHeading.tsx +1 -1
  364. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +3 -3
  365. package/src/lib/shapes/geo/GeoShapeUtil.tsx +4 -2
  366. package/src/lib/shapes/geo/components/GeoShapeBody.tsx +2 -2
  367. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +7 -1
  368. package/src/lib/shapes/image/ImageShapeUtil.tsx +6 -3
  369. package/src/lib/shapes/line/LineShapeUtil.test.tsx +8 -7
  370. package/src/lib/shapes/line/LineShapeUtil.tsx +6 -1
  371. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.tsx.snap +2 -2
  372. package/src/lib/shapes/note/NoteShapeTool.test.ts +2 -1
  373. package/src/lib/shapes/note/NoteShapeUtil.tsx +10 -4
  374. package/src/lib/shapes/shared/HyperlinkButton.tsx +5 -5
  375. package/src/lib/shapes/shared/PlainTextLabel.tsx +2 -7
  376. package/src/lib/shapes/shared/RichTextLabel.tsx +2 -1
  377. package/src/lib/shapes/shared/ShapeFill.tsx +5 -4
  378. package/src/lib/shapes/shared/crop.ts +1 -0
  379. package/src/lib/shapes/shared/freehand/svg.ts +2 -0
  380. package/src/lib/shapes/shared/useEditablePlainText.ts +12 -12
  381. package/src/lib/shapes/shared/useEditableRichText.ts +7 -3
  382. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +0 -7
  383. package/src/lib/shapes/text/PlainTextArea.tsx +3 -3
  384. package/src/lib/shapes/text/RichTextArea.tsx +3 -4
  385. package/src/lib/shapes/text/TextShapeTool.test.ts +6 -5
  386. package/src/lib/shapes/text/TextShapeUtil.tsx +3 -2
  387. package/src/lib/shapes/video/VideoShapeUtil.tsx +3 -3
  388. package/src/lib/tools/EraserTool/childStates/Erasing.ts +34 -1
  389. package/src/lib/tools/EraserTool/childStates/Pointing.ts +20 -0
  390. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +1 -1
  391. package/src/lib/tools/SelectTool/childStates/Translating.ts +0 -1
  392. package/src/lib/ui/TldrawUi.tsx +33 -12
  393. package/src/lib/ui/assetUrls.ts +13 -10
  394. package/src/lib/ui/components/A11y.tsx +2 -2
  395. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +15 -3
  396. package/src/lib/ui/components/{FollowingIndicator.tsx → DefaultFollowingIndicator.tsx} +2 -1
  397. package/src/lib/ui/components/DefaultMenuPanel.tsx +4 -3
  398. package/src/lib/ui/components/EditLinkDialog.tsx +16 -6
  399. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +6 -6
  400. package/src/lib/ui/components/Minimap/MinimapManager.ts +4 -4
  401. package/src/lib/ui/components/MobileStylePanel.tsx +9 -6
  402. package/src/lib/ui/components/NavigationPanel/DefaultNavigationPanel.tsx +1 -1
  403. package/src/lib/ui/components/PageMenu/DefaultPageMenu.tsx +5 -4
  404. package/src/lib/ui/components/SharePanel/PeopleMenuItem.tsx +4 -3
  405. package/src/lib/ui/components/SharePanel/UserPresenceColorPicker.tsx +3 -3
  406. package/src/lib/ui/components/StylePanel/DefaultStylePanel.tsx +27 -13
  407. package/src/lib/ui/components/StylePanel/DefaultStylePanelContent.tsx +260 -385
  408. package/src/lib/ui/components/{primitives/TldrawUiButtonPicker.tsx → StylePanel/StylePanelButtonPicker.tsx} +66 -50
  409. package/src/lib/ui/components/StylePanel/StylePanelContext.tsx +63 -0
  410. package/src/lib/ui/components/StylePanel/{DoubleDropdownPicker.tsx → StylePanelDoubleDropdownPicker.tsx} +31 -22
  411. package/src/lib/ui/components/StylePanel/StylePanelDropdownPicker.tsx +119 -0
  412. package/src/lib/ui/components/StylePanel/StylePanelSubheading.tsx +9 -0
  413. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +5 -4
  414. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +33 -16
  415. package/src/lib/ui/components/Toolbar/DefaultToolbar.tsx +55 -23
  416. package/src/lib/ui/components/Toolbar/DefaultVideoToolbarContent.tsx +12 -4
  417. package/src/lib/ui/components/Toolbar/LinkEditor.tsx +5 -5
  418. package/src/lib/ui/components/Toolbar/OverflowingToolbar.tsx +212 -61
  419. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +2 -2
  420. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +8 -3
  421. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +3 -3
  422. package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +4 -2
  423. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +52 -32
  424. package/src/lib/ui/components/primitives/TldrawUiToolbar.tsx +35 -9
  425. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +232 -180
  426. package/src/lib/ui/components/primitives/layout.tsx +107 -0
  427. package/src/lib/ui/components/primitives/menus/TldrawUiMenuContext.tsx +0 -1
  428. package/src/lib/ui/components/primitives/menus/TldrawUiMenuGroup.tsx +29 -16
  429. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +221 -19
  430. package/src/lib/ui/context/actions.tsx +23 -10
  431. package/src/lib/ui/context/components.tsx +3 -0
  432. package/src/lib/ui/context/events.tsx +2 -1
  433. package/src/lib/ui/hooks/useClipboardEvents.ts +2 -2
  434. package/src/lib/ui/hooks/useExportAs.ts +3 -2
  435. package/src/lib/ui/hooks/useTools.tsx +140 -10
  436. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
  437. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +4 -2
  438. package/src/lib/ui/kbd-utils.ts +10 -3
  439. package/src/lib/ui/version.ts +3 -3
  440. package/src/lib/ui.css +381 -306
  441. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +5 -5
  442. package/src/lib/utils/excalidraw/putExcalidrawContent.ts +6 -6
  443. package/src/lib/utils/export/copyAs.ts +1 -24
  444. package/src/lib/utils/export/export.ts +0 -36
  445. package/src/lib/utils/export/exportAs.ts +1 -32
  446. package/src/lib/utils/tldr/__snapshots__/buildFromV1Document.test.ts.snap +4 -4
  447. package/src/test/A11y.test.tsx +3 -2
  448. package/src/test/ClickManager.test.ts +7 -6
  449. package/src/test/Editor.test.tsx +55 -27
  450. package/src/test/EraserTool.test.ts +184 -13
  451. package/src/test/HandTool.test.ts +10 -9
  452. package/src/test/HighlightShape.test.ts +2 -1
  453. package/src/test/SelectTool.test.ts +3 -2
  454. package/src/test/TLUserPreferences.test.ts +4 -3
  455. package/src/test/TestEditor.ts +13 -15
  456. package/src/test/TldrawEditor.test.tsx +26 -19
  457. package/src/test/ZoomTool.test.ts +7 -6
  458. package/src/test/__snapshots__/drawing.test.ts.snap +2 -2
  459. package/src/test/__snapshots__/groups.test.tsx.snap +6 -6
  460. package/src/test/__snapshots__/resizing.test.ts.snap +2 -2
  461. package/src/test/arrows-megabus.test.tsx +5 -4
  462. package/src/test/bindings.test.tsx +24 -37
  463. package/src/test/bookmark-shapes.test.ts +1 -8
  464. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +23 -7
  465. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +8 -8
  466. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +2 -2
  467. package/src/test/commands/alignShapes.test.tsx +25 -24
  468. package/src/test/commands/animationSpeed.test.ts +2 -1
  469. package/src/test/commands/centerOnPoint.test.ts +3 -2
  470. package/src/test/commands/clipboard.test.ts +3 -2
  471. package/src/test/commands/createShapes.test.ts +2 -1
  472. package/src/test/commands/deleteShapes.test.ts +2 -1
  473. package/src/test/commands/distributeShapes.test.tsx +11 -10
  474. package/src/test/commands/getSvgString.test.ts +2 -1
  475. package/src/test/commands/packShapes.test.ts +5 -4
  476. package/src/test/commands/putContent.test.ts +1 -0
  477. package/src/test/commands/resizeShape.test.ts +2 -1
  478. package/src/test/commands/rotateShapes.test.ts +7 -6
  479. package/src/test/commands/setCamera.test.ts +4 -3
  480. package/src/test/commands/setCurrentPage.test.ts +3 -2
  481. package/src/test/commands/stackShapes.test.ts +11 -10
  482. package/src/test/commands/stretch.test.tsx +13 -12
  483. package/src/test/commands/updateShapes.test.ts +9 -5
  484. package/src/test/createDeepLink.test.tsx +2 -1
  485. package/src/test/cropping.test.ts +3 -2
  486. package/src/test/custom-clipping.test.ts +442 -0
  487. package/src/test/customSnapping.test.tsx +55 -41
  488. package/src/test/drawing.test.ts +2 -1
  489. package/src/test/flipShapes.test.ts +4 -3
  490. package/src/test/frames.test.ts +25 -24
  491. package/src/test/getCulledShapes.test.tsx +80 -4
  492. package/src/test/groups.test.tsx +5 -3
  493. package/src/test/handleDeepLink.test.tsx +2 -1
  494. package/src/test/maxShapes.test.ts +3 -2
  495. package/src/test/modifiers.test.ts +5 -4
  496. package/src/test/navigation.test.ts +12 -11
  497. package/src/test/panning.test.ts +2 -1
  498. package/src/test/perf/perf.test.ts +2 -1
  499. package/src/test/registerDeepLinkListener.test.tsx +10 -9
  500. package/src/test/resizing.test.ts +39 -38
  501. package/src/test/select.test.tsx +4 -3
  502. package/src/test/selection-omnibus.test.ts +11 -10
  503. package/src/test/shapeutils.test.ts +4 -3
  504. package/src/test/translating.test.ts +11 -10
  505. package/tldraw.css +689 -598
  506. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +0 -7
  507. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +0 -7
  508. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +0 -7
  509. package/dist-cjs/lib/ui/components/primitives/TldrawUiButtonPicker.js.map +0 -7
  510. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +0 -7
  511. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +0 -7
  512. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +0 -7
  513. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs +0 -115
  514. package/dist-esm/lib/ui/components/primitives/TldrawUiButtonPicker.mjs.map +0 -7
  515. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +0 -109
@@ -48,13 +48,13 @@ const ShapeFill = import_react.default.memo(function ShapeFill2({
48
48
  return null;
49
49
  }
50
50
  case "solid": {
51
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: theme[color].semi, d });
51
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: (0, import_editor.getColorValue)(theme, color, "semi"), d });
52
52
  }
53
53
  case "semi": {
54
54
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: theme.solid, d });
55
55
  }
56
56
  case "fill": {
57
- return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: theme[color].fill, d });
57
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: (0, import_editor.getColorValue)(theme, color, "fill"), d });
58
58
  }
59
59
  case "pattern": {
60
60
  return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(PatternFill, { theme, color, fill, d, scale });
@@ -68,11 +68,11 @@ function PatternFill({ d, color, theme }) {
68
68
  const getHashPatternZoomName = (0, import_defaultStyleDefs.useGetHashPatternZoomName)();
69
69
  const teenyTiny = editor.getZoomLevel() <= 0.18;
70
70
  return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
71
- /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: theme[color].pattern, d }),
71
+ /* @__PURE__ */ (0, import_jsx_runtime.jsx)("path", { fill: (0, import_editor.getColorValue)(theme, color, "pattern"), d }),
72
72
  /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
73
73
  "path",
74
74
  {
75
- fill: svgExport ? `url(#${getHashPatternZoomName(1, theme.id)})` : teenyTiny ? theme[color].semi : `url(#${getHashPatternZoomName(zoomLevel, theme.id)})`,
75
+ fill: svgExport ? `url(#${getHashPatternZoomName(1, theme.id)})` : teenyTiny ? (0, import_editor.getColorValue)(theme, color, "semi") : `url(#${getHashPatternZoomName(zoomLevel, theme.id)})`,
76
76
  d
77
77
  }
78
78
  )
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/ShapeFill.tsx"],
4
- "sourcesContent": ["import {\n\tTLDefaultColorStyle,\n\tTLDefaultColorTheme,\n\tTLDefaultFillStyle,\n\tuseEditor,\n\tuseSvgExportContext,\n\tuseValue,\n} from '@tldraw/editor'\nimport React from 'react'\nimport { useGetHashPatternZoomName } from './defaultStyleDefs'\n\ninterface ShapeFillProps {\n\td: string\n\tfill: TLDefaultFillStyle\n\tcolor: TLDefaultColorStyle\n\ttheme: TLDefaultColorTheme\n\tscale: number\n}\n\nexport const ShapeFill = React.memo(function ShapeFill({\n\ttheme,\n\td,\n\tcolor,\n\tfill,\n\tscale,\n}: ShapeFillProps) {\n\tswitch (fill) {\n\t\tcase 'none': {\n\t\t\treturn null\n\t\t}\n\t\tcase 'solid': {\n\t\t\treturn <path fill={theme[color].semi} d={d} />\n\t\t}\n\t\tcase 'semi': {\n\t\t\treturn <path fill={theme.solid} d={d} />\n\t\t}\n\t\tcase 'fill': {\n\t\t\treturn <path fill={theme[color].fill} d={d} />\n\t\t}\n\t\tcase 'pattern': {\n\t\t\treturn <PatternFill theme={theme} color={color} fill={fill} d={d} scale={scale} />\n\t\t}\n\t}\n})\n\nexport function PatternFill({ d, color, theme }: ShapeFillProps) {\n\tconst editor = useEditor()\n\tconst svgExport = useSvgExportContext()\n\tconst zoomLevel = useValue('zoomLevel', () => editor.getZoomLevel(), [editor])\n\tconst getHashPatternZoomName = useGetHashPatternZoomName()\n\n\tconst teenyTiny = editor.getZoomLevel() <= 0.18\n\n\treturn (\n\t\t<>\n\t\t\t<path fill={theme[color].pattern} d={d} />\n\t\t\t<path\n\t\t\t\tfill={\n\t\t\t\t\tsvgExport\n\t\t\t\t\t\t? `url(#${getHashPatternZoomName(1, theme.id)})`\n\t\t\t\t\t\t: teenyTiny\n\t\t\t\t\t\t\t? theme[color].semi\n\t\t\t\t\t\t\t: `url(#${getHashPatternZoomName(zoomLevel, theme.id)})`\n\t\t\t\t}\n\t\t\t\td={d}\n\t\t\t/>\n\t\t</>\n\t)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA+BU;AA/BV,oBAOO;AACP,mBAAkB;AAClB,8BAA0C;AAUnC,MAAM,YAAY,aAAAA,QAAM,KAAK,SAASC,WAAU;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAmB;AAClB,UAAQ,MAAM;AAAA,IACb,KAAK,QAAQ;AACZ,aAAO;AAAA,IACR;AAAA,IACA,KAAK,SAAS;AACb,aAAO,4CAAC,UAAK,MAAM,MAAM,KAAK,EAAE,MAAM,GAAM;AAAA,IAC7C;AAAA,IACA,KAAK,QAAQ;AACZ,aAAO,4CAAC,UAAK,MAAM,MAAM,OAAO,GAAM;AAAA,IACvC;AAAA,IACA,KAAK,QAAQ;AACZ,aAAO,4CAAC,UAAK,MAAM,MAAM,KAAK,EAAE,MAAM,GAAM;AAAA,IAC7C;AAAA,IACA,KAAK,WAAW;AACf,aAAO,4CAAC,eAAY,OAAc,OAAc,MAAY,GAAM,OAAc;AAAA,IACjF;AAAA,EACD;AACD,CAAC;AAEM,SAAS,YAAY,EAAE,GAAG,OAAO,MAAM,GAAmB;AAChE,QAAM,aAAS,yBAAU;AACzB,QAAM,gBAAY,mCAAoB;AACtC,QAAM,gBAAY,wBAAS,aAAa,MAAM,OAAO,aAAa,GAAG,CAAC,MAAM,CAAC;AAC7E,QAAM,6BAAyB,mDAA0B;AAEzD,QAAM,YAAY,OAAO,aAAa,KAAK;AAE3C,SACC,4EACC;AAAA,gDAAC,UAAK,MAAM,MAAM,KAAK,EAAE,SAAS,GAAM;AAAA,IACxC;AAAA,MAAC;AAAA;AAAA,QACA,MACC,YACG,QAAQ,uBAAuB,GAAG,MAAM,EAAE,CAAC,MAC3C,YACC,MAAM,KAAK,EAAE,OACb,QAAQ,uBAAuB,WAAW,MAAM,EAAE,CAAC;AAAA,QAExD;AAAA;AAAA,IACD;AAAA,KACD;AAEF;",
4
+ "sourcesContent": ["import {\n\tgetColorValue,\n\tTLDefaultColorStyle,\n\tTLDefaultColorTheme,\n\tTLDefaultFillStyle,\n\tuseEditor,\n\tuseSvgExportContext,\n\tuseValue,\n} from '@tldraw/editor'\nimport React from 'react'\nimport { useGetHashPatternZoomName } from './defaultStyleDefs'\n\ninterface ShapeFillProps {\n\td: string\n\tfill: TLDefaultFillStyle\n\tcolor: TLDefaultColorStyle\n\ttheme: TLDefaultColorTheme\n\tscale: number\n}\n\nexport const ShapeFill = React.memo(function ShapeFill({\n\ttheme,\n\td,\n\tcolor,\n\tfill,\n\tscale,\n}: ShapeFillProps) {\n\tswitch (fill) {\n\t\tcase 'none': {\n\t\t\treturn null\n\t\t}\n\t\tcase 'solid': {\n\t\t\treturn <path fill={getColorValue(theme, color, 'semi')} d={d} />\n\t\t}\n\t\tcase 'semi': {\n\t\t\treturn <path fill={theme.solid} d={d} />\n\t\t}\n\t\tcase 'fill': {\n\t\t\treturn <path fill={getColorValue(theme, color, 'fill')} d={d} />\n\t\t}\n\t\tcase 'pattern': {\n\t\t\treturn <PatternFill theme={theme} color={color} fill={fill} d={d} scale={scale} />\n\t\t}\n\t}\n})\n\nexport function PatternFill({ d, color, theme }: ShapeFillProps) {\n\tconst editor = useEditor()\n\tconst svgExport = useSvgExportContext()\n\tconst zoomLevel = useValue('zoomLevel', () => editor.getZoomLevel(), [editor])\n\tconst getHashPatternZoomName = useGetHashPatternZoomName()\n\n\tconst teenyTiny = editor.getZoomLevel() <= 0.18\n\n\treturn (\n\t\t<>\n\t\t\t<path fill={getColorValue(theme, color, 'pattern')} d={d} />\n\t\t\t<path\n\t\t\t\tfill={\n\t\t\t\t\tsvgExport\n\t\t\t\t\t\t? `url(#${getHashPatternZoomName(1, theme.id)})`\n\t\t\t\t\t\t: teenyTiny\n\t\t\t\t\t\t\t? getColorValue(theme, color, 'semi')\n\t\t\t\t\t\t\t: `url(#${getHashPatternZoomName(zoomLevel, theme.id)})`\n\t\t\t\t}\n\t\t\t\td={d}\n\t\t\t/>\n\t\t</>\n\t)\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAgCU;AAhCV,oBAQO;AACP,mBAAkB;AAClB,8BAA0C;AAUnC,MAAM,YAAY,aAAAA,QAAM,KAAK,SAASC,WAAU;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GAAmB;AAClB,UAAQ,MAAM;AAAA,IACb,KAAK,QAAQ;AACZ,aAAO;AAAA,IACR;AAAA,IACA,KAAK,SAAS;AACb,aAAO,4CAAC,UAAK,UAAM,6BAAc,OAAO,OAAO,MAAM,GAAG,GAAM;AAAA,IAC/D;AAAA,IACA,KAAK,QAAQ;AACZ,aAAO,4CAAC,UAAK,MAAM,MAAM,OAAO,GAAM;AAAA,IACvC;AAAA,IACA,KAAK,QAAQ;AACZ,aAAO,4CAAC,UAAK,UAAM,6BAAc,OAAO,OAAO,MAAM,GAAG,GAAM;AAAA,IAC/D;AAAA,IACA,KAAK,WAAW;AACf,aAAO,4CAAC,eAAY,OAAc,OAAc,MAAY,GAAM,OAAc;AAAA,IACjF;AAAA,EACD;AACD,CAAC;AAEM,SAAS,YAAY,EAAE,GAAG,OAAO,MAAM,GAAmB;AAChE,QAAM,aAAS,yBAAU;AACzB,QAAM,gBAAY,mCAAoB;AACtC,QAAM,gBAAY,wBAAS,aAAa,MAAM,OAAO,aAAa,GAAG,CAAC,MAAM,CAAC;AAC7E,QAAM,6BAAyB,mDAA0B;AAEzD,QAAM,YAAY,OAAO,aAAa,KAAK;AAE3C,SACC,4EACC;AAAA,gDAAC,UAAK,UAAM,6BAAc,OAAO,OAAO,SAAS,GAAG,GAAM;AAAA,IAC1D;AAAA,MAAC;AAAA;AAAA,QACA,MACC,YACG,QAAQ,uBAAuB,GAAG,MAAM,EAAE,CAAC,MAC3C,gBACC,6BAAc,OAAO,OAAO,MAAM,IAClC,QAAQ,uBAAuB,WAAW,MAAM,EAAE,CAAC;AAAA,QAExD;AAAA;AAAA,IACD;AAAA,KACD;AAEF;",
6
6
  "names": ["React", "ShapeFill"]
7
7
  }
@@ -270,6 +270,7 @@ function getCropBox(shape, info, opts = {}) {
270
270
  x: newPoint.x,
271
271
  y: newPoint.y,
272
272
  props: {
273
+ ...shape.props,
273
274
  w: tempBox.w,
274
275
  h: tempBox.h,
275
276
  crop: newCrop
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/crop.ts"],
4
- "sourcesContent": ["import {\n\tBox,\n\tShapeWithCrop,\n\tTLCropInfo,\n\tTLImageShape,\n\tTLShapeCrop,\n\tTLShapeId,\n\tVec,\n\tclamp,\n\tisEqual,\n} from '@tldraw/editor'\n\n/** @internal */\nexport const MIN_CROP_SIZE = 8\n\n/** @public */\nexport interface CropBoxOptions {\n\tminWidth?: number\n\tminHeight?: number\n}\n\n/** @public */\nexport function getDefaultCrop(): TLShapeCrop {\n\treturn {\n\t\ttopLeft: { x: 0, y: 0 },\n\t\tbottomRight: { x: 1, y: 1 },\n\t}\n}\n\n/** @public */\nexport type ASPECT_RATIO_OPTION =\n\t| 'original'\n\t| 'square'\n\t| 'circle'\n\t| 'landscape'\n\t| 'portrait'\n\t| 'wide'\n\n/** @public */\nexport const ASPECT_RATIO_OPTIONS: ASPECT_RATIO_OPTION[] = [\n\t'original',\n\t'square',\n\t'circle',\n\t'landscape',\n\t'portrait',\n\t'wide',\n]\n\n/** @public */\nexport const ASPECT_RATIO_TO_VALUE: Record<ASPECT_RATIO_OPTION, number> = {\n\toriginal: 0,\n\tsquare: 1,\n\tcircle: 1,\n\tlandscape: 4 / 3,\n\tportrait: 3 / 4,\n\twide: 16 / 9,\n}\n\n/**\n * Original (uncropped) width and height of shape.\n *\n * @public\n */\nexport function getUncroppedSize(\n\tshapeSize: { w: number; h: number },\n\tcrop: TLShapeCrop | null\n): { w: number; h: number } {\n\tif (!crop) return { w: shapeSize.w, h: shapeSize.h }\n\tconst w = shapeSize.w / (crop.bottomRight.x - crop.topLeft.x)\n\tconst h = shapeSize.h / (crop.bottomRight.y - crop.topLeft.y)\n\treturn { w, h }\n}\n\n// Utility function to get crop dimensions\nfunction getCropDimensions(crop: TLShapeCrop) {\n\treturn {\n\t\twidth: crop.bottomRight.x - crop.topLeft.x,\n\t\theight: crop.bottomRight.y - crop.topLeft.y,\n\t}\n}\n\n// Utility function to get crop center\nfunction getCropCenter(crop: TLShapeCrop) {\n\tconst { width, height } = getCropDimensions(crop)\n\treturn {\n\t\tx: crop.topLeft.x + width / 2,\n\t\ty: crop.topLeft.y + height / 2,\n\t}\n}\n\n// Utility function to create crop with specified dimensions centered on given point\nfunction createCropAroundCenter(\n\tcenterX: number,\n\tcenterY: number,\n\twidth: number,\n\theight: number,\n\tisCircle?: boolean\n) {\n\tconst topLeftX = Math.max(0, Math.min(1 - width, centerX - width / 2))\n\tconst topLeftY = Math.max(0, Math.min(1 - height, centerY - height / 2))\n\n\treturn {\n\t\ttopLeft: { x: topLeftX, y: topLeftY },\n\t\tbottomRight: { x: topLeftX + width, y: topLeftY + height },\n\t\tisCircle,\n\t}\n}\n\n/** @public */\nexport function getCropBox<T extends ShapeWithCrop>(\n\tshape: T,\n\tinfo: TLCropInfo<T>,\n\topts = {} as CropBoxOptions\n):\n\t| {\n\t\t\tid: TLShapeId\n\t\t\ttype: T['type']\n\t\t\tx: number\n\t\t\ty: number\n\t\t\tprops: ShapeWithCrop['props']\n\t }\n\t| undefined {\n\tconst { handle, change, crop, aspectRatioLocked } = info\n\tconst { w, h } = info.uncroppedSize\n\tconst { minWidth = MIN_CROP_SIZE, minHeight = MIN_CROP_SIZE } = opts\n\n\tif (w < minWidth || h < minHeight || (change.x === 0 && change.y === 0)) {\n\t\treturn\n\t}\n\n\t// Lets get a box here in pixel space. For simplicity, we'll do all the math in\n\t// pixel space, then convert to normalized space at the end.\n\tconst prevCropBox = new Box(\n\t\tcrop.topLeft.x * w,\n\t\tcrop.topLeft.y * h,\n\t\t(crop.bottomRight.x - crop.topLeft.x) * w,\n\t\t(crop.bottomRight.y - crop.topLeft.y) * h\n\t)\n\n\tconst targetRatio = prevCropBox.aspectRatio\n\tconst tempBox = prevCropBox.clone()\n\n\t// Basic resizing logic based on the handles\n\n\tif (handle === 'top_left' || handle === 'bottom_left' || handle === 'left') {\n\t\ttempBox.x = clamp(tempBox.x + change.x, 0, prevCropBox.maxX - minWidth)\n\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t} else if (handle === 'top_right' || handle === 'bottom_right' || handle === 'right') {\n\t\tconst tempRight = clamp(tempBox.maxX + change.x, prevCropBox.x + minWidth, w)\n\t\ttempBox.w = tempRight - tempBox.x\n\t}\n\n\tif (handle === 'top_left' || handle === 'top_right' || handle === 'top') {\n\t\ttempBox.y = clamp(tempBox.y + change.y, 0, prevCropBox.maxY - minHeight)\n\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t} else if (handle === 'bottom_left' || handle === 'bottom_right' || handle === 'bottom') {\n\t\tconst tempBottom = clamp(tempBox.maxY + change.y, prevCropBox.y + minHeight, h)\n\t\ttempBox.h = tempBottom - tempBox.y\n\t}\n\n\t// Aspect ratio locked resizing logic\n\n\tif (aspectRatioLocked) {\n\t\tconst isXLimiting = tempBox.aspectRatio > targetRatio\n\n\t\tif (isXLimiting) {\n\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t} else {\n\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t}\n\n\t\tswitch (handle) {\n\t\t\tcase 'top_left': {\n\t\t\t\t// preserve the bottom right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top_right': {\n\t\t\t\t// preserve the bottom left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_left': {\n\t\t\t\t// preserve the top right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_right': {\n\t\t\t\t// preserve the top left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top': {\n\t\t\t\t// preserve the bottom edge center\n\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\t// preserve the left edge center\n\t\t\t\ttempBox.w = tempBox.maxX - prevCropBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\t// preserve the top edge center\n\t\t\t\ttempBox.h = tempBox.maxY - prevCropBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\t// preserve the right edge center\n\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Convert the box back to normalized space\n\tconst newCrop: TLShapeCrop = {\n\t\ttopLeft: { x: tempBox.x / w, y: tempBox.y / h },\n\t\tbottomRight: { x: tempBox.maxX / w, y: tempBox.maxY / h },\n\t\tisCircle: crop.isCircle,\n\t}\n\n\t// If the crop hasn't changed, we can return early\n\tif (\n\t\tnewCrop.topLeft.x === crop.topLeft.x &&\n\t\tnewCrop.topLeft.y === crop.topLeft.y &&\n\t\tnewCrop.bottomRight.x === crop.bottomRight.x &&\n\t\tnewCrop.bottomRight.y === crop.bottomRight.y\n\t) {\n\t\treturn\n\t}\n\n\t// Adjust the shape's position to keep the crop's absolute coordinates correct\n\tconst newPoint = new Vec(tempBox.x - crop.topLeft.x * w, tempBox.y - crop.topLeft.y * h)\n\t\t.rot(shape.rotation)\n\t\t.add(shape)\n\n\treturn {\n\t\tid: shape.id,\n\t\ttype: shape.type,\n\t\tx: newPoint.x,\n\t\ty: newPoint.y,\n\t\tprops: {\n\t\t\tw: tempBox.w,\n\t\t\th: tempBox.h,\n\t\t\tcrop: newCrop,\n\t\t},\n\t}\n}\n\ninterface CropChange {\n\tcrop: {\n\t\ttopLeft: { x: number; y: number }\n\t\tbottomRight: { x: number; y: number }\n\t\tisCircle?: boolean\n\t}\n\tw: number\n\th: number\n\tx: number\n\ty: number\n}\n\n// Base function for calculating crop changes\nfunction calculateCropChange(\n\timageShape: TLImageShape,\n\tnewCropWidth: number,\n\tnewCropHeight: number,\n\tcenterOnCurrentCrop: boolean = true,\n\tisCircle: boolean = false\n): CropChange {\n\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\n\t// Calculate image and crop centers\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\tlet cropCenterX, cropCenterY\n\tif (centerOnCurrentCrop) {\n\t\tconst { x, y } = getCropCenter(currentCrop)\n\t\tcropCenterX = x\n\t\tcropCenterY = y\n\t} else {\n\t\tcropCenterX = 0.5\n\t\tcropCenterY = 0.5\n\t}\n\n\t// Create new crop\n\tconst newCrop = createCropAroundCenter(\n\t\tcropCenterX,\n\t\tcropCenterY,\n\t\tnewCropWidth,\n\t\tnewCropHeight,\n\t\tisCircle\n\t)\n\n\t// Calculate new dimensions\n\tconst croppedW = newCropWidth * w\n\tconst croppedH = newCropHeight * h\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: croppedW,\n\t\th: croppedH,\n\t\tx: imageCenterX - croppedW / 2,\n\t\ty: imageCenterY - croppedH / 2,\n\t}\n}\n\n/** @internal */\nexport const MAX_ZOOM = 3\n\n/**\n * Calculate new crop dimensions and position when zooming\n */\nexport function getCroppedImageDataWhenZooming(\n\tzoom: number,\n\timageShape: TLImageShape,\n\tmaxZoom?: number\n): CropChange {\n\tconst oldCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: oldWidth, height: oldHeight } = getCropDimensions(oldCrop)\n\tconst aspectRatio = oldWidth / oldHeight\n\n\t// Calculate new crop size with zoom scale\n\tconst derivedMaxZoom = maxZoom ? 1 / (1 - maxZoom) : MAX_ZOOM\n\tconst zoomScale = 1 + zoom * (derivedMaxZoom - 1)\n\tlet newWidth, newHeight\n\n\tif (aspectRatio > 1) {\n\t\tnewWidth = Math.min(1, 1 / zoomScale)\n\t\tnewHeight = newWidth / aspectRatio\n\t} else {\n\t\tnewHeight = Math.min(1, 1 / zoomScale)\n\t\tnewWidth = newHeight * aspectRatio\n\t}\n\n\t// Calculate result with base function\n\tconst result = calculateCropChange(imageShape, newWidth, newHeight, true, oldCrop.isCircle)\n\n\t// Apply zoom factor to display dimensions\n\tconst scaleFactor = Math.min(MAX_ZOOM, oldWidth / newWidth)\n\tresult.w *= scaleFactor\n\tresult.h *= scaleFactor\n\n\t// Recenter\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\tresult.x = imageCenterX - result.w / 2\n\tresult.y = imageCenterY - result.h / 2\n\n\treturn result\n}\n\n/**\n * Calculate new crop dimensions and position when replacing an image\n */\nexport function getCroppedImageDataForReplacedImage(\n\timageShape: TLImageShape,\n\tnewImageWidth: number,\n\tnewImageHeight: number\n): CropChange {\n\tconst defaultCrop = getDefaultCrop()\n\tconst currentCrop = imageShape.props.crop || defaultCrop\n\tconst origDisplayW = imageShape.props.w\n\tconst origDisplayH = imageShape.props.h\n\tconst newImageAspectRatio = newImageWidth / newImageHeight\n\n\tlet crop = defaultCrop\n\tlet newDisplayW = origDisplayW\n\tlet newDisplayH = origDisplayH\n\tconst isOriginalCrop = isEqual(imageShape.props.crop, defaultCrop)\n\n\tif (isOriginalCrop) {\n\t\tnewDisplayW = origDisplayW\n\t\tnewDisplayH = (origDisplayW * newImageHeight) / newImageWidth\n\t} else {\n\t\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\t\timageShape.props,\n\t\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t\t)\n\t\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\t\tconst targetRatio = cropW / cropH\n\t\tconst oldImageAspectRatio = uncroppedW / uncroppedH\n\t\tlet newRelativeWidth: number\n\t\tlet newRelativeHeight: number\n\n\t\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t\t// Adjust the new crop dimensions to match the current crop zoom\n\t\tnewRelativeWidth = cropW\n\t\tconst ratioConversion = newImageAspectRatio / oldImageAspectRatio / targetRatio\n\t\tnewRelativeHeight = newRelativeWidth * ratioConversion\n\n\t\t// Check that our new crop dimensions are within the MAX_ZOOM bounds\n\t\tconst maxRatioConversion = MAX_ZOOM / (MAX_ZOOM - 1)\n\t\tif (ratioConversion > maxRatioConversion) {\n\t\t\tconst minDimension = 1 / MAX_ZOOM\n\t\t\tif (1 / newRelativeHeight < 1 / newRelativeWidth) {\n\t\t\t\tconst scale = newRelativeHeight / minDimension\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t} else {\n\t\t\t\tconst scale = newRelativeWidth / minDimension\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t}\n\t\t}\n\n\t\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t\t// Create the new crop object, centered around the CURRENT crop's center\n\t\tcrop = createCropAroundCenter(\n\t\t\tcurrentCropCenter.x,\n\t\t\tcurrentCropCenter.y,\n\t\t\tnewRelativeWidth,\n\t\t\tnewRelativeHeight,\n\t\t\tcurrentCrop.isCircle\n\t\t)\n\t}\n\n\t// Position so visual center stays put\n\tconst pageCenterX = imageShape.x + origDisplayW / 2\n\tconst pageCenterY = imageShape.y + origDisplayH / 2\n\n\tconst newX = pageCenterX - newDisplayW / 2\n\tconst newY = pageCenterY - newDisplayH / 2\n\n\treturn {\n\t\tcrop,\n\t\tw: newDisplayW,\n\t\th: newDisplayH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n\n/**\n * Calculate new crop dimensions and position when changing aspect ratio\n */\nexport function getCroppedImageDataForAspectRatio(\n\taspectRatioOption: ASPECT_RATIO_OPTION,\n\timageShape: TLImageShape\n): CropChange {\n\t// If original aspect ratio is requested, use default crop\n\tif (aspectRatioOption === 'original') {\n\t\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\t\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\t\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\t\treturn {\n\t\t\tcrop: getDefaultCrop(),\n\t\t\tw,\n\t\t\th,\n\t\t\tx: imageCenterX - w / 2,\n\t\t\ty: imageCenterY - h / 2,\n\t\t}\n\t}\n\n\t// Get target ratio and uncropped image properties\n\tconst targetRatio = ASPECT_RATIO_TO_VALUE[aspectRatioOption] // Assume valid option\n\tconst isCircle = aspectRatioOption === 'circle'\n\t// Use default crop to get uncropped size relative to the *original* image bounds\n\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\timageShape.props,\n\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t)\n\t// Calculate the original image aspect ratio\n\tconst imageAspectRatio = uncroppedW / uncroppedH\n\n\t// Get the current crop and its relative dimensions\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t// Calculate the current crop zoom level\n\tconst currentCropZoom = Math.min(1 / cropW, 1 / cropH)\n\n\t// Calculate the relative width and height of the crop rectangle (0-1 scale)\n\t// Try to preserve the longest dimension of the current crop when changing aspect ratios\n\tlet newRelativeWidth: number\n\tlet newRelativeHeight: number\n\n\tif (imageAspectRatio === 0 || !Number.isFinite(imageAspectRatio) || targetRatio === 0) {\n\t\t// Avoid division by zero or NaN issues if image dimensions are invalid or target ratio is 0\n\t\tnewRelativeWidth = 1\n\t\tnewRelativeHeight = 1\n\t} else {\n\t\t// Get current crop dimensions in absolute units\n\t\tconst currentAbsoluteWidth = cropW * uncroppedW\n\t\tconst currentAbsoluteHeight = cropH * uncroppedH\n\n\t\t// Find the longest current dimension to preserve\n\t\tconst longestCurrentDimension = Math.max(currentAbsoluteWidth, currentAbsoluteHeight)\n\t\tconst isWidthLongest = currentAbsoluteWidth >= currentAbsoluteHeight\n\n\t\t// Calculate new dimensions preserving the longest dimension\n\t\tlet newAbsoluteWidth: number\n\t\tlet newAbsoluteHeight: number\n\n\t\tif (isWidthLongest) {\n\t\t\t// Preserve width, calculate height based on target ratio\n\t\t\tnewAbsoluteWidth = longestCurrentDimension\n\t\t\tnewAbsoluteHeight = newAbsoluteWidth / targetRatio\n\t\t} else {\n\t\t\t// Preserve height, calculate width based on target ratio\n\t\t\tnewAbsoluteHeight = longestCurrentDimension\n\t\t\tnewAbsoluteWidth = newAbsoluteHeight * targetRatio\n\t\t}\n\n\t\t// Convert back to relative coordinates\n\t\tnewRelativeWidth = newAbsoluteWidth / uncroppedW\n\t\tnewRelativeHeight = newAbsoluteHeight / uncroppedH\n\n\t\t// Clamp to image bounds and adjust if necessary\n\t\tif (newRelativeWidth > 1) {\n\t\t\t// Width exceeds bounds, clamp and recalculate height\n\t\t\tnewRelativeWidth = 1\n\t\t\tnewRelativeHeight = imageAspectRatio / targetRatio\n\t\t}\n\t\tif (newRelativeHeight > 1) {\n\t\t\t// Height exceeds bounds, clamp and recalculate width\n\t\t\tnewRelativeHeight = 1\n\t\t\tnewRelativeWidth = targetRatio / imageAspectRatio\n\t\t}\n\n\t\t// Final clamp to ensure we stay within bounds\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\t}\n\n\tconst newCropZoom = Math.min(1 / newRelativeWidth, 1 / newRelativeHeight)\n\t// Adjust the new crop dimensions to match the current crop zoom\n\tnewRelativeWidth *= newCropZoom / currentCropZoom\n\tnewRelativeHeight *= newCropZoom / currentCropZoom\n\n\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t// Create the new crop object, centered around the CURRENT crop's center\n\tconst newCrop = createCropAroundCenter(\n\t\tcurrentCropCenter.x,\n\t\tcurrentCropCenter.y,\n\t\tnewRelativeWidth,\n\t\tnewRelativeHeight,\n\t\tisCircle\n\t)\n\n\t// Get the actual relative dimensions from the new crop (after potential clamping)\n\tconst finalRelativeWidth = newCrop.bottomRight.x - newCrop.topLeft.x\n\tconst finalRelativeHeight = newCrop.bottomRight.y - newCrop.topLeft.y\n\n\t// Calculate the base dimensions (as if applying the new crop to the uncropped image at scale 1)\n\tconst baseW = finalRelativeWidth * uncroppedW\n\tconst baseH = finalRelativeHeight * uncroppedH\n\n\t// Determine the current effective scale of the shape\n\t// This preserves the visual size when the crop changes\n\tlet currentScale = 1.0\n\tif (cropW > 0) {\n\t\tcurrentScale = imageShape.props.w / (cropW * uncroppedW)\n\t} else if (cropH > 0) {\n\t\t// Fallback to height if width relative dimension is zero\n\t\tcurrentScale = imageShape.props.h / (cropH * uncroppedH)\n\t}\n\n\t// Apply the current scale to the base dimensions to get the final dimensions\n\tconst newW = baseW * currentScale\n\tconst newH = baseH * currentScale\n\n\t// Calculate the new top-left position (x, y) for the shape\n\t// to keep the visual center of the cropped area fixed on the page.\n\tconst currentCenterXPage = imageShape.x + imageShape.props.w / 2\n\tconst currentCenterYPage = imageShape.y + imageShape.props.h / 2\n\tconst newX = currentCenterXPage - newW / 2\n\tconst newY = currentCenterYPage - newH / 2\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: newW,\n\t\th: newH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tBox,\n\tShapeWithCrop,\n\tTLCropInfo,\n\tTLImageShape,\n\tTLShapeCrop,\n\tTLShapeId,\n\tVec,\n\tclamp,\n\tisEqual,\n} from '@tldraw/editor'\n\n/** @internal */\nexport const MIN_CROP_SIZE = 8\n\n/** @public */\nexport interface CropBoxOptions {\n\tminWidth?: number\n\tminHeight?: number\n}\n\n/** @public */\nexport function getDefaultCrop(): TLShapeCrop {\n\treturn {\n\t\ttopLeft: { x: 0, y: 0 },\n\t\tbottomRight: { x: 1, y: 1 },\n\t}\n}\n\n/** @public */\nexport type ASPECT_RATIO_OPTION =\n\t| 'original'\n\t| 'square'\n\t| 'circle'\n\t| 'landscape'\n\t| 'portrait'\n\t| 'wide'\n\n/** @public */\nexport const ASPECT_RATIO_OPTIONS: ASPECT_RATIO_OPTION[] = [\n\t'original',\n\t'square',\n\t'circle',\n\t'landscape',\n\t'portrait',\n\t'wide',\n]\n\n/** @public */\nexport const ASPECT_RATIO_TO_VALUE: Record<ASPECT_RATIO_OPTION, number> = {\n\toriginal: 0,\n\tsquare: 1,\n\tcircle: 1,\n\tlandscape: 4 / 3,\n\tportrait: 3 / 4,\n\twide: 16 / 9,\n}\n\n/**\n * Original (uncropped) width and height of shape.\n *\n * @public\n */\nexport function getUncroppedSize(\n\tshapeSize: { w: number; h: number },\n\tcrop: TLShapeCrop | null\n): { w: number; h: number } {\n\tif (!crop) return { w: shapeSize.w, h: shapeSize.h }\n\tconst w = shapeSize.w / (crop.bottomRight.x - crop.topLeft.x)\n\tconst h = shapeSize.h / (crop.bottomRight.y - crop.topLeft.y)\n\treturn { w, h }\n}\n\n// Utility function to get crop dimensions\nfunction getCropDimensions(crop: TLShapeCrop) {\n\treturn {\n\t\twidth: crop.bottomRight.x - crop.topLeft.x,\n\t\theight: crop.bottomRight.y - crop.topLeft.y,\n\t}\n}\n\n// Utility function to get crop center\nfunction getCropCenter(crop: TLShapeCrop) {\n\tconst { width, height } = getCropDimensions(crop)\n\treturn {\n\t\tx: crop.topLeft.x + width / 2,\n\t\ty: crop.topLeft.y + height / 2,\n\t}\n}\n\n// Utility function to create crop with specified dimensions centered on given point\nfunction createCropAroundCenter(\n\tcenterX: number,\n\tcenterY: number,\n\twidth: number,\n\theight: number,\n\tisCircle?: boolean\n) {\n\tconst topLeftX = Math.max(0, Math.min(1 - width, centerX - width / 2))\n\tconst topLeftY = Math.max(0, Math.min(1 - height, centerY - height / 2))\n\n\treturn {\n\t\ttopLeft: { x: topLeftX, y: topLeftY },\n\t\tbottomRight: { x: topLeftX + width, y: topLeftY + height },\n\t\tisCircle,\n\t}\n}\n\n/** @public */\nexport function getCropBox<T extends ShapeWithCrop>(\n\tshape: T,\n\tinfo: TLCropInfo<T>,\n\topts = {} as CropBoxOptions\n):\n\t| {\n\t\t\tid: TLShapeId\n\t\t\ttype: T['type']\n\t\t\tx: number\n\t\t\ty: number\n\t\t\tprops: ShapeWithCrop['props']\n\t }\n\t| undefined {\n\tconst { handle, change, crop, aspectRatioLocked } = info\n\tconst { w, h } = info.uncroppedSize\n\tconst { minWidth = MIN_CROP_SIZE, minHeight = MIN_CROP_SIZE } = opts\n\n\tif (w < minWidth || h < minHeight || (change.x === 0 && change.y === 0)) {\n\t\treturn\n\t}\n\n\t// Lets get a box here in pixel space. For simplicity, we'll do all the math in\n\t// pixel space, then convert to normalized space at the end.\n\tconst prevCropBox = new Box(\n\t\tcrop.topLeft.x * w,\n\t\tcrop.topLeft.y * h,\n\t\t(crop.bottomRight.x - crop.topLeft.x) * w,\n\t\t(crop.bottomRight.y - crop.topLeft.y) * h\n\t)\n\n\tconst targetRatio = prevCropBox.aspectRatio\n\tconst tempBox = prevCropBox.clone()\n\n\t// Basic resizing logic based on the handles\n\n\tif (handle === 'top_left' || handle === 'bottom_left' || handle === 'left') {\n\t\ttempBox.x = clamp(tempBox.x + change.x, 0, prevCropBox.maxX - minWidth)\n\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t} else if (handle === 'top_right' || handle === 'bottom_right' || handle === 'right') {\n\t\tconst tempRight = clamp(tempBox.maxX + change.x, prevCropBox.x + minWidth, w)\n\t\ttempBox.w = tempRight - tempBox.x\n\t}\n\n\tif (handle === 'top_left' || handle === 'top_right' || handle === 'top') {\n\t\ttempBox.y = clamp(tempBox.y + change.y, 0, prevCropBox.maxY - minHeight)\n\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t} else if (handle === 'bottom_left' || handle === 'bottom_right' || handle === 'bottom') {\n\t\tconst tempBottom = clamp(tempBox.maxY + change.y, prevCropBox.y + minHeight, h)\n\t\ttempBox.h = tempBottom - tempBox.y\n\t}\n\n\t// Aspect ratio locked resizing logic\n\n\tif (aspectRatioLocked) {\n\t\tconst isXLimiting = tempBox.aspectRatio > targetRatio\n\n\t\tif (isXLimiting) {\n\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t} else {\n\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t}\n\n\t\tswitch (handle) {\n\t\t\tcase 'top_left': {\n\t\t\t\t// preserve the bottom right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top_right': {\n\t\t\t\t// preserve the bottom left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_left': {\n\t\t\t\t// preserve the top right corner\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom_right': {\n\t\t\t\t// preserve the top left corner\n\t\t\t\ttempBox.x = prevCropBox.x\n\t\t\t\ttempBox.y = prevCropBox.y\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\ttempBox.w = w - prevCropBox.x\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\ttempBox.h = h - prevCropBox.y\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'top': {\n\t\t\t\t// preserve the bottom edge center\n\t\t\t\ttempBox.h = prevCropBox.maxY - tempBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\n\t\t\t\ttempBox.y = prevCropBox.maxY - tempBox.h\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'right': {\n\t\t\t\t// preserve the left edge center\n\t\t\t\ttempBox.w = tempBox.maxX - prevCropBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'bottom': {\n\t\t\t\t// preserve the top edge center\n\t\t\t\ttempBox.h = tempBox.maxY - prevCropBox.y\n\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\ttempBox.x -= (tempBox.w - prevCropBox.w) / 2\n\n\t\t\t\tif (tempBox.x <= 0) {\n\t\t\t\t\tconst leftSide = prevCropBox.midX\n\t\t\t\t\ttempBox.w = leftSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxX >= w) {\n\t\t\t\t\tconst rightSide = w - prevCropBox.midX\n\t\t\t\t\ttempBox.w = rightSide * 2\n\t\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\t\ttempBox.x = w - tempBox.w\n\t\t\t\t}\n\t\t\t\tbreak\n\t\t\t}\n\t\t\tcase 'left': {\n\t\t\t\t// preserve the right edge center\n\t\t\t\ttempBox.w = prevCropBox.maxX - tempBox.x\n\t\t\t\ttempBox.h = tempBox.w / targetRatio\n\t\t\t\ttempBox.y -= (tempBox.h - prevCropBox.h) / 2\n\n\t\t\t\tif (tempBox.y <= 0) {\n\t\t\t\t\tconst topSide = prevCropBox.midY\n\t\t\t\t\ttempBox.h = topSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = 0\n\t\t\t\t}\n\n\t\t\t\tif (tempBox.maxY >= h) {\n\t\t\t\t\tconst bottomSide = h - prevCropBox.midY\n\t\t\t\t\ttempBox.h = bottomSide * 2\n\t\t\t\t\ttempBox.w = tempBox.h * targetRatio\n\t\t\t\t\ttempBox.y = h - tempBox.h\n\t\t\t\t}\n\n\t\t\t\ttempBox.x = prevCropBox.maxX - tempBox.w\n\t\t\t\tbreak\n\t\t\t}\n\t\t}\n\t}\n\n\t// Convert the box back to normalized space\n\tconst newCrop: TLShapeCrop = {\n\t\ttopLeft: { x: tempBox.x / w, y: tempBox.y / h },\n\t\tbottomRight: { x: tempBox.maxX / w, y: tempBox.maxY / h },\n\t\tisCircle: crop.isCircle,\n\t}\n\n\t// If the crop hasn't changed, we can return early\n\tif (\n\t\tnewCrop.topLeft.x === crop.topLeft.x &&\n\t\tnewCrop.topLeft.y === crop.topLeft.y &&\n\t\tnewCrop.bottomRight.x === crop.bottomRight.x &&\n\t\tnewCrop.bottomRight.y === crop.bottomRight.y\n\t) {\n\t\treturn\n\t}\n\n\t// Adjust the shape's position to keep the crop's absolute coordinates correct\n\tconst newPoint = new Vec(tempBox.x - crop.topLeft.x * w, tempBox.y - crop.topLeft.y * h)\n\t\t.rot(shape.rotation)\n\t\t.add(shape)\n\n\treturn {\n\t\tid: shape.id,\n\t\ttype: shape.type,\n\t\tx: newPoint.x,\n\t\ty: newPoint.y,\n\t\tprops: {\n\t\t\t...shape.props,\n\t\t\tw: tempBox.w,\n\t\t\th: tempBox.h,\n\t\t\tcrop: newCrop,\n\t\t},\n\t}\n}\n\ninterface CropChange {\n\tcrop: {\n\t\ttopLeft: { x: number; y: number }\n\t\tbottomRight: { x: number; y: number }\n\t\tisCircle?: boolean\n\t}\n\tw: number\n\th: number\n\tx: number\n\ty: number\n}\n\n// Base function for calculating crop changes\nfunction calculateCropChange(\n\timageShape: TLImageShape,\n\tnewCropWidth: number,\n\tnewCropHeight: number,\n\tcenterOnCurrentCrop: boolean = true,\n\tisCircle: boolean = false\n): CropChange {\n\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\n\t// Calculate image and crop centers\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\tlet cropCenterX, cropCenterY\n\tif (centerOnCurrentCrop) {\n\t\tconst { x, y } = getCropCenter(currentCrop)\n\t\tcropCenterX = x\n\t\tcropCenterY = y\n\t} else {\n\t\tcropCenterX = 0.5\n\t\tcropCenterY = 0.5\n\t}\n\n\t// Create new crop\n\tconst newCrop = createCropAroundCenter(\n\t\tcropCenterX,\n\t\tcropCenterY,\n\t\tnewCropWidth,\n\t\tnewCropHeight,\n\t\tisCircle\n\t)\n\n\t// Calculate new dimensions\n\tconst croppedW = newCropWidth * w\n\tconst croppedH = newCropHeight * h\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: croppedW,\n\t\th: croppedH,\n\t\tx: imageCenterX - croppedW / 2,\n\t\ty: imageCenterY - croppedH / 2,\n\t}\n}\n\n/** @internal */\nexport const MAX_ZOOM = 3\n\n/**\n * Calculate new crop dimensions and position when zooming\n */\nexport function getCroppedImageDataWhenZooming(\n\tzoom: number,\n\timageShape: TLImageShape,\n\tmaxZoom?: number\n): CropChange {\n\tconst oldCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: oldWidth, height: oldHeight } = getCropDimensions(oldCrop)\n\tconst aspectRatio = oldWidth / oldHeight\n\n\t// Calculate new crop size with zoom scale\n\tconst derivedMaxZoom = maxZoom ? 1 / (1 - maxZoom) : MAX_ZOOM\n\tconst zoomScale = 1 + zoom * (derivedMaxZoom - 1)\n\tlet newWidth, newHeight\n\n\tif (aspectRatio > 1) {\n\t\tnewWidth = Math.min(1, 1 / zoomScale)\n\t\tnewHeight = newWidth / aspectRatio\n\t} else {\n\t\tnewHeight = Math.min(1, 1 / zoomScale)\n\t\tnewWidth = newHeight * aspectRatio\n\t}\n\n\t// Calculate result with base function\n\tconst result = calculateCropChange(imageShape, newWidth, newHeight, true, oldCrop.isCircle)\n\n\t// Apply zoom factor to display dimensions\n\tconst scaleFactor = Math.min(MAX_ZOOM, oldWidth / newWidth)\n\tresult.w *= scaleFactor\n\tresult.h *= scaleFactor\n\n\t// Recenter\n\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\tresult.x = imageCenterX - result.w / 2\n\tresult.y = imageCenterY - result.h / 2\n\n\treturn result\n}\n\n/**\n * Calculate new crop dimensions and position when replacing an image\n */\nexport function getCroppedImageDataForReplacedImage(\n\timageShape: TLImageShape,\n\tnewImageWidth: number,\n\tnewImageHeight: number\n): CropChange {\n\tconst defaultCrop = getDefaultCrop()\n\tconst currentCrop = imageShape.props.crop || defaultCrop\n\tconst origDisplayW = imageShape.props.w\n\tconst origDisplayH = imageShape.props.h\n\tconst newImageAspectRatio = newImageWidth / newImageHeight\n\n\tlet crop = defaultCrop\n\tlet newDisplayW = origDisplayW\n\tlet newDisplayH = origDisplayH\n\tconst isOriginalCrop = isEqual(imageShape.props.crop, defaultCrop)\n\n\tif (isOriginalCrop) {\n\t\tnewDisplayW = origDisplayW\n\t\tnewDisplayH = (origDisplayW * newImageHeight) / newImageWidth\n\t} else {\n\t\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\t\timageShape.props,\n\t\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t\t)\n\t\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\t\tconst targetRatio = cropW / cropH\n\t\tconst oldImageAspectRatio = uncroppedW / uncroppedH\n\t\tlet newRelativeWidth: number\n\t\tlet newRelativeHeight: number\n\n\t\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t\t// Adjust the new crop dimensions to match the current crop zoom\n\t\tnewRelativeWidth = cropW\n\t\tconst ratioConversion = newImageAspectRatio / oldImageAspectRatio / targetRatio\n\t\tnewRelativeHeight = newRelativeWidth * ratioConversion\n\n\t\t// Check that our new crop dimensions are within the MAX_ZOOM bounds\n\t\tconst maxRatioConversion = MAX_ZOOM / (MAX_ZOOM - 1)\n\t\tif (ratioConversion > maxRatioConversion) {\n\t\t\tconst minDimension = 1 / MAX_ZOOM\n\t\t\tif (1 / newRelativeHeight < 1 / newRelativeWidth) {\n\t\t\t\tconst scale = newRelativeHeight / minDimension\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t} else {\n\t\t\t\tconst scale = newRelativeWidth / minDimension\n\t\t\t\tnewRelativeWidth = newRelativeWidth / scale\n\t\t\t\tnewRelativeHeight = newRelativeHeight / scale\n\t\t\t}\n\t\t}\n\n\t\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t\t// Create the new crop object, centered around the CURRENT crop's center\n\t\tcrop = createCropAroundCenter(\n\t\t\tcurrentCropCenter.x,\n\t\t\tcurrentCropCenter.y,\n\t\t\tnewRelativeWidth,\n\t\t\tnewRelativeHeight,\n\t\t\tcurrentCrop.isCircle\n\t\t)\n\t}\n\n\t// Position so visual center stays put\n\tconst pageCenterX = imageShape.x + origDisplayW / 2\n\tconst pageCenterY = imageShape.y + origDisplayH / 2\n\n\tconst newX = pageCenterX - newDisplayW / 2\n\tconst newY = pageCenterY - newDisplayH / 2\n\n\treturn {\n\t\tcrop,\n\t\tw: newDisplayW,\n\t\th: newDisplayH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n\n/**\n * Calculate new crop dimensions and position when changing aspect ratio\n */\nexport function getCroppedImageDataForAspectRatio(\n\taspectRatioOption: ASPECT_RATIO_OPTION,\n\timageShape: TLImageShape\n): CropChange {\n\t// If original aspect ratio is requested, use default crop\n\tif (aspectRatioOption === 'original') {\n\t\tconst { w, h } = getUncroppedSize(imageShape.props, imageShape.props.crop ?? getDefaultCrop())\n\t\tconst imageCenterX = imageShape.x + imageShape.props.w / 2\n\t\tconst imageCenterY = imageShape.y + imageShape.props.h / 2\n\n\t\treturn {\n\t\t\tcrop: getDefaultCrop(),\n\t\t\tw,\n\t\t\th,\n\t\t\tx: imageCenterX - w / 2,\n\t\t\ty: imageCenterY - h / 2,\n\t\t}\n\t}\n\n\t// Get target ratio and uncropped image properties\n\tconst targetRatio = ASPECT_RATIO_TO_VALUE[aspectRatioOption] // Assume valid option\n\tconst isCircle = aspectRatioOption === 'circle'\n\t// Use default crop to get uncropped size relative to the *original* image bounds\n\tconst { w: uncroppedW, h: uncroppedH } = getUncroppedSize(\n\t\timageShape.props,\n\t\timageShape.props.crop || getDefaultCrop() // Use the ACTUAL current crop to correctly infer uncropped size\n\t)\n\t// Calculate the original image aspect ratio\n\tconst imageAspectRatio = uncroppedW / uncroppedH\n\n\t// Get the current crop and its relative dimensions\n\tconst currentCrop = imageShape.props.crop || getDefaultCrop()\n\tconst { width: cropW, height: cropH } = getCropDimensions(currentCrop)\n\tconst currentCropCenter = getCropCenter(currentCrop)\n\n\t// Calculate the current crop zoom level\n\tconst currentCropZoom = Math.min(1 / cropW, 1 / cropH)\n\n\t// Calculate the relative width and height of the crop rectangle (0-1 scale)\n\t// Try to preserve the longest dimension of the current crop when changing aspect ratios\n\tlet newRelativeWidth: number\n\tlet newRelativeHeight: number\n\n\tif (imageAspectRatio === 0 || !Number.isFinite(imageAspectRatio) || targetRatio === 0) {\n\t\t// Avoid division by zero or NaN issues if image dimensions are invalid or target ratio is 0\n\t\tnewRelativeWidth = 1\n\t\tnewRelativeHeight = 1\n\t} else {\n\t\t// Get current crop dimensions in absolute units\n\t\tconst currentAbsoluteWidth = cropW * uncroppedW\n\t\tconst currentAbsoluteHeight = cropH * uncroppedH\n\n\t\t// Find the longest current dimension to preserve\n\t\tconst longestCurrentDimension = Math.max(currentAbsoluteWidth, currentAbsoluteHeight)\n\t\tconst isWidthLongest = currentAbsoluteWidth >= currentAbsoluteHeight\n\n\t\t// Calculate new dimensions preserving the longest dimension\n\t\tlet newAbsoluteWidth: number\n\t\tlet newAbsoluteHeight: number\n\n\t\tif (isWidthLongest) {\n\t\t\t// Preserve width, calculate height based on target ratio\n\t\t\tnewAbsoluteWidth = longestCurrentDimension\n\t\t\tnewAbsoluteHeight = newAbsoluteWidth / targetRatio\n\t\t} else {\n\t\t\t// Preserve height, calculate width based on target ratio\n\t\t\tnewAbsoluteHeight = longestCurrentDimension\n\t\t\tnewAbsoluteWidth = newAbsoluteHeight * targetRatio\n\t\t}\n\n\t\t// Convert back to relative coordinates\n\t\tnewRelativeWidth = newAbsoluteWidth / uncroppedW\n\t\tnewRelativeHeight = newAbsoluteHeight / uncroppedH\n\n\t\t// Clamp to image bounds and adjust if necessary\n\t\tif (newRelativeWidth > 1) {\n\t\t\t// Width exceeds bounds, clamp and recalculate height\n\t\t\tnewRelativeWidth = 1\n\t\t\tnewRelativeHeight = imageAspectRatio / targetRatio\n\t\t}\n\t\tif (newRelativeHeight > 1) {\n\t\t\t// Height exceeds bounds, clamp and recalculate width\n\t\t\tnewRelativeHeight = 1\n\t\t\tnewRelativeWidth = targetRatio / imageAspectRatio\n\t\t}\n\n\t\t// Final clamp to ensure we stay within bounds\n\t\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\t\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\t}\n\n\tconst newCropZoom = Math.min(1 / newRelativeWidth, 1 / newRelativeHeight)\n\t// Adjust the new crop dimensions to match the current crop zoom\n\tnewRelativeWidth *= newCropZoom / currentCropZoom\n\tnewRelativeHeight *= newCropZoom / currentCropZoom\n\n\t// Ensure dimensions are within [0, 1] bounds after adjustment\n\tnewRelativeWidth = Math.max(0, Math.min(1, newRelativeWidth))\n\tnewRelativeHeight = Math.max(0, Math.min(1, newRelativeHeight))\n\n\t// Create the new crop object, centered around the CURRENT crop's center\n\tconst newCrop = createCropAroundCenter(\n\t\tcurrentCropCenter.x,\n\t\tcurrentCropCenter.y,\n\t\tnewRelativeWidth,\n\t\tnewRelativeHeight,\n\t\tisCircle\n\t)\n\n\t// Get the actual relative dimensions from the new crop (after potential clamping)\n\tconst finalRelativeWidth = newCrop.bottomRight.x - newCrop.topLeft.x\n\tconst finalRelativeHeight = newCrop.bottomRight.y - newCrop.topLeft.y\n\n\t// Calculate the base dimensions (as if applying the new crop to the uncropped image at scale 1)\n\tconst baseW = finalRelativeWidth * uncroppedW\n\tconst baseH = finalRelativeHeight * uncroppedH\n\n\t// Determine the current effective scale of the shape\n\t// This preserves the visual size when the crop changes\n\tlet currentScale = 1.0\n\tif (cropW > 0) {\n\t\tcurrentScale = imageShape.props.w / (cropW * uncroppedW)\n\t} else if (cropH > 0) {\n\t\t// Fallback to height if width relative dimension is zero\n\t\tcurrentScale = imageShape.props.h / (cropH * uncroppedH)\n\t}\n\n\t// Apply the current scale to the base dimensions to get the final dimensions\n\tconst newW = baseW * currentScale\n\tconst newH = baseH * currentScale\n\n\t// Calculate the new top-left position (x, y) for the shape\n\t// to keep the visual center of the cropped area fixed on the page.\n\tconst currentCenterXPage = imageShape.x + imageShape.props.w / 2\n\tconst currentCenterYPage = imageShape.y + imageShape.props.h / 2\n\tconst newX = currentCenterXPage - newW / 2\n\tconst newY = currentCenterYPage - newH / 2\n\n\treturn {\n\t\tcrop: newCrop,\n\t\tw: newW,\n\t\th: newH,\n\t\tx: newX,\n\t\ty: newY,\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../../src/lib/shapes/shared/freehand/svg.ts"],
4
- "sourcesContent": ["import { average, precise } from '@tldraw/editor'\nimport { StrokePoint } from './types'\n\n/**\n * Turn an array of stroke points into a path of quadradic curves.\n *\n * @param points - The stroke points returned from perfect-freehand\n * @param closed - Whether the shape is closed\n */\nexport function getSvgPathFromStrokePoints(points: StrokePoint[], closed = false): string {\n\tconst len = points.length\n\n\tif (len < 2) {\n\t\treturn ''\n\t}\n\n\tlet a = points[0].point\n\tlet b = points[1].point\n\n\tif (len === 2) {\n\t\treturn `M${precise(a)}L${precise(b)}`\n\t}\n\n\tlet result = ''\n\n\tfor (let i = 2, max = len - 1; i < max; i++) {\n\t\ta = points[i].point\n\t\tb = points[i + 1].point\n\t\tresult += average(a, b)\n\t}\n\n\tif (closed) {\n\t\t// If closed, draw a curve from the last point to the first\n\t\treturn `M${average(points[0].point, points[1].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}T${result}${average(points[len - 1].point, points[0].point)}${average(\n\t\t\tpoints[0].point,\n\t\t\tpoints[1].point\n\t\t)}Z`\n\t} else {\n\t\t// If not closed, draw a curve starting at the first point and\n\t\t// ending at the midpoint of the last and second-last point, then\n\t\t// complete the curve with a line segment to the last point.\n\t\treturn `M${precise(points[0].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}${points.length > 3 ? 'T' : ''}${result}L${precise(points[len - 1].point)}`\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAiC;AAS1B,SAAS,2BAA2B,QAAuB,SAAS,OAAe;AACzF,QAAM,MAAM,OAAO;AAEnB,MAAI,MAAM,GAAG;AACZ,WAAO;AAAA,EACR;AAEA,MAAI,IAAI,OAAO,CAAC,EAAE;AAClB,MAAI,IAAI,OAAO,CAAC,EAAE;AAElB,MAAI,QAAQ,GAAG;AACd,WAAO,QAAI,uBAAQ,CAAC,CAAC,QAAI,uBAAQ,CAAC,CAAC;AAAA,EACpC;AAEA,MAAI,SAAS;AAEb,WAAS,IAAI,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,KAAK;AAC5C,QAAI,OAAO,CAAC,EAAE;AACd,QAAI,OAAO,IAAI,CAAC,EAAE;AAClB,kBAAU,uBAAQ,GAAG,CAAC;AAAA,EACvB;AAEA,MAAI,QAAQ;AAEX,WAAO,QAAI,uBAAQ,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,QAAI,uBAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,OAAG;AAAA,MAClF,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,IAAI,MAAM,OAAG,uBAAQ,OAAO,MAAM,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,OAAG;AAAA,MAC/D,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC;AAAA,EACF,OAAO;AAIN,WAAO,QAAI,uBAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,QAAI,uBAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,OAAG;AAAA,MACjE,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,GAAG,OAAO,SAAS,IAAI,MAAM,EAAE,GAAG,MAAM,QAAI,uBAAQ,OAAO,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,EAC5E;AACD;",
4
+ "sourcesContent": ["import { average, precise } from '@tldraw/editor'\nimport { StrokePoint } from './types'\n\n/**\n * Turn an array of stroke points into a path of quadradic curves.\n *\n * @param points - The stroke points returned from perfect-freehand\n * @param closed - Whether the shape is closed\n *\n * @public\n */\nexport function getSvgPathFromStrokePoints(points: StrokePoint[], closed = false): string {\n\tconst len = points.length\n\n\tif (len < 2) {\n\t\treturn ''\n\t}\n\n\tlet a = points[0].point\n\tlet b = points[1].point\n\n\tif (len === 2) {\n\t\treturn `M${precise(a)}L${precise(b)}`\n\t}\n\n\tlet result = ''\n\n\tfor (let i = 2, max = len - 1; i < max; i++) {\n\t\ta = points[i].point\n\t\tb = points[i + 1].point\n\t\tresult += average(a, b)\n\t}\n\n\tif (closed) {\n\t\t// If closed, draw a curve from the last point to the first\n\t\treturn `M${average(points[0].point, points[1].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}T${result}${average(points[len - 1].point, points[0].point)}${average(\n\t\t\tpoints[0].point,\n\t\t\tpoints[1].point\n\t\t)}Z`\n\t} else {\n\t\t// If not closed, draw a curve starting at the first point and\n\t\t// ending at the midpoint of the last and second-last point, then\n\t\t// complete the curve with a line segment to the last point.\n\t\treturn `M${precise(points[0].point)}Q${precise(points[1].point)}${average(\n\t\t\tpoints[1].point,\n\t\t\tpoints[2].point\n\t\t)}${points.length > 3 ? 'T' : ''}${result}L${precise(points[len - 1].point)}`\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAiC;AAW1B,SAAS,2BAA2B,QAAuB,SAAS,OAAe;AACzF,QAAM,MAAM,OAAO;AAEnB,MAAI,MAAM,GAAG;AACZ,WAAO;AAAA,EACR;AAEA,MAAI,IAAI,OAAO,CAAC,EAAE;AAClB,MAAI,IAAI,OAAO,CAAC,EAAE;AAElB,MAAI,QAAQ,GAAG;AACd,WAAO,QAAI,uBAAQ,CAAC,CAAC,QAAI,uBAAQ,CAAC,CAAC;AAAA,EACpC;AAEA,MAAI,SAAS;AAEb,WAAS,IAAI,GAAG,MAAM,MAAM,GAAG,IAAI,KAAK,KAAK;AAC5C,QAAI,OAAO,CAAC,EAAE;AACd,QAAI,OAAO,IAAI,CAAC,EAAE;AAClB,kBAAU,uBAAQ,GAAG,CAAC;AAAA,EACvB;AAEA,MAAI,QAAQ;AAEX,WAAO,QAAI,uBAAQ,OAAO,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,QAAI,uBAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,OAAG;AAAA,MAClF,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,IAAI,MAAM,OAAG,uBAAQ,OAAO,MAAM,CAAC,EAAE,OAAO,OAAO,CAAC,EAAE,KAAK,CAAC,OAAG;AAAA,MAC/D,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC;AAAA,EACF,OAAO;AAIN,WAAO,QAAI,uBAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,QAAI,uBAAQ,OAAO,CAAC,EAAE,KAAK,CAAC,OAAG;AAAA,MACjE,OAAO,CAAC,EAAE;AAAA,MACV,OAAO,CAAC,EAAE;AAAA,IACX,CAAC,GAAG,OAAO,SAAS,IAAI,MAAM,EAAE,GAAG,MAAM,QAAI,uBAAQ,OAAO,MAAM,CAAC,EAAE,KAAK,CAAC;AAAA,EAC5E;AACD;",
6
6
  "names": []
7
7
  }
@@ -19,7 +19,6 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
19
19
  var useEditablePlainText_exports = {};
20
20
  __export(useEditablePlainText_exports, {
21
21
  useEditablePlainText: () => useEditablePlainText,
22
- useEditableText: () => useEditableText,
23
22
  useEditableTextCommon: () => useEditableTextCommon,
24
23
  useIsReadyForEditing: () => useIsReadyForEditing
25
24
  });
@@ -117,7 +116,7 @@ function useEditableTextCommon(shapeId) {
117
116
  target: "shape",
118
117
  shape: editor.getShape(shapeId)
119
118
  });
120
- (0, import_editor.stopEventPropagation)(e);
119
+ e.stopPropagation();
121
120
  },
122
121
  [editor, shapeId]
123
122
  );
@@ -135,15 +134,15 @@ function useEditableTextCommon(shapeId) {
135
134
  },
136
135
  [editor, shapeId]
137
136
  );
137
+ const handleDoubleClick = import_editor.markEventAsHandled;
138
138
  return {
139
139
  handleFocus: import_editor.noop,
140
140
  handleBlur: import_editor.noop,
141
141
  handleInputPointerDown,
142
- handleDoubleClick: import_editor.stopEventPropagation,
142
+ handleDoubleClick,
143
143
  handlePaste,
144
144
  isEditing,
145
145
  isReadyForEditing
146
146
  };
147
147
  }
148
- const useEditableText = useEditablePlainText;
149
148
  //# sourceMappingURL=useEditablePlainText.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/useEditablePlainText.ts"],
4
- "sourcesContent": ["import {\n\tEditor,\n\tTLShapeId,\n\tTLUnknownShape,\n\tgetPointerInfo,\n\tnoop,\n\tpreventDefault,\n\tstopEventPropagation,\n\ttlenv,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport React, { useCallback, useEffect, useRef } from 'react'\nimport { TextHelpers } from './TextHelpers'\n\n/** @public */\nexport function useEditablePlainText(shapeId: TLShapeId, type: string, text?: string) {\n\tconst commonUseEditableTextHandlers = useEditableTextCommon(shapeId)\n\tconst isEditing = commonUseEditableTextHandlers.isEditing\n\tconst editor = useEditor()\n\tconst rInput = useRef<HTMLTextAreaElement>(null)\n\tconst isEmpty = (text || '').trim().length === 0\n\n\tuseEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === shapeId) {\n\t\t\t\trInput.current?.select?.()\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t}\n\t}, [editor, shapeId, isEditing])\n\n\tuseEffect(() => {\n\t\tif (!isEditing) return\n\n\t\tif (document.activeElement !== rInput.current) {\n\t\t\trInput.current?.focus()\n\t\t}\n\n\t\tif (editor.getInstanceState().isCoarsePointer) {\n\t\t\trInput.current?.select()\n\t\t}\n\n\t\t// XXX(mime): This fixes iOS not showing the caret sometimes.\n\t\t// This \"shakes\" the caret awake.\n\t\tif (tlenv.isSafari) {\n\t\t\trInput.current?.blur()\n\t\t\trInput.current?.focus()\n\t\t}\n\t}, [editor, isEditing])\n\n\t// When the user presses ctrl / meta enter, complete the editing state.\n\tconst handleKeyDown = useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase 'Enter': {\n\t\t\t\t\tif (e.ctrlKey || e.metaKey) {\n\t\t\t\t\t\teditor.complete()\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\t// When the text changes, update the text value.\n\tconst handleChange = useCallback(\n\t\t({ plaintext }: { plaintext: string }) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tconst normalizedPlaintext = TextHelpers.normalizeText(plaintext || '')\n\t\t\teditor.updateShape<TLUnknownShape & { props: { text: string } }>({\n\t\t\t\tid: shapeId,\n\t\t\t\ttype,\n\t\t\t\tprops: { text: normalizedPlaintext },\n\t\t\t})\n\t\t},\n\t\t[editor, shapeId, type]\n\t)\n\n\treturn {\n\t\trInput,\n\t\thandleKeyDown,\n\t\thandleChange,\n\t\tisEmpty,\n\t\t...commonUseEditableTextHandlers,\n\t}\n}\n\n/** @internal */\nexport function useIsReadyForEditing(editor: Editor, shapeId: TLShapeId) {\n\treturn useValue(\n\t\t'isReadyForEditing',\n\t\t() => {\n\t\t\tconst editingShapeId = editor.getEditingShapeId()\n\t\t\treturn (\n\t\t\t\t// something's being editing... and either it's this shape OR this shape is hovered\n\t\t\t\teditingShapeId !== null &&\n\t\t\t\t(editingShapeId === shapeId || editor.getHoveredShapeId() === shapeId)\n\t\t\t)\n\t\t},\n\t\t[editor, shapeId]\n\t)\n}\n\n/** @internal */\nexport function useEditableTextCommon(shapeId: TLShapeId) {\n\tconst editor = useEditor()\n\tconst isEditing = useValue('isEditing', () => editor.getEditingShapeId() === shapeId, [editor])\n\tconst isReadyForEditing = useIsReadyForEditing(editor, shapeId)\n\n\tconst handleInputPointerDown = useCallback(\n\t\t(e: React.PointerEvent) => {\n\t\t\t// N.B. We used to only do this only when isEditing to help\n\t\t\t// prevent an issue where you could drag a selected shape\n\t\t\t// behind another shape. That is addressed now by the CSS logic\n\t\t\t// looking at data-isselectinganything.\n\t\t\t//\n\t\t\t// We still need to follow this logic even if not isEditing\n\t\t\t// because otherwise there is some flakiness in selection.\n\t\t\t// When selecting text, it would sometimes select some text\n\t\t\t// partially if we didn't dispatch/stop below.\n\n\t\t\teditor.dispatch({\n\t\t\t\t...getPointerInfo(e),\n\t\t\t\ttype: 'pointer',\n\t\t\t\tname: 'pointer_down',\n\t\t\t\ttarget: 'shape',\n\t\t\t\tshape: editor.getShape(shapeId)!,\n\t\t\t})\n\n\t\t\tstopEventPropagation(e) // we need to prevent blurring the input\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\tconst handlePaste = useCallback(\n\t\t(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\t\t\tif (e.clipboardData) {\n\t\t\t\t// find html in the clipboard and look for the tldraw data\n\t\t\t\tconst html = e.clipboardData.getData('text/html')\n\t\t\t\tif (html) {\n\t\t\t\t\tif (html.includes('<div data-tldraw')) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\treturn {\n\t\thandleFocus: noop,\n\t\thandleBlur: noop,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick: stopEventPropagation,\n\t\thandlePaste,\n\t\tisEditing,\n\t\tisReadyForEditing,\n\t}\n}\n\n/**\n * @deprecated Use `useEditablePlainText` instead.\n * @public\n */\nexport const useEditableText = useEditablePlainText\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import {\n\tEditor,\n\tTLShape,\n\tTLShapeId,\n\tgetPointerInfo,\n\tmarkEventAsHandled,\n\tnoop,\n\tpreventDefault,\n\ttlenv,\n\tuseEditor,\n\tuseValue,\n} from '@tldraw/editor'\nimport React, { useCallback, useEffect, useRef } from 'react'\nimport { TextHelpers } from './TextHelpers'\n\n/** @public */\nexport function useEditablePlainText(\n\tshapeId: TLShapeId,\n\ttype: Extract<TLShape, { props: { text: string } }>['type'],\n\ttext?: string\n) {\n\tconst commonUseEditableTextHandlers = useEditableTextCommon(shapeId)\n\tconst isEditing = commonUseEditableTextHandlers.isEditing\n\tconst editor = useEditor()\n\tconst rInput = useRef<HTMLTextAreaElement>(null)\n\tconst isEmpty = (text || '').trim().length === 0\n\n\tuseEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === shapeId) {\n\t\t\t\trInput.current?.select?.()\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t}\n\t}, [editor, shapeId, isEditing])\n\n\tuseEffect(() => {\n\t\tif (!isEditing) return\n\n\t\tif (document.activeElement !== rInput.current) {\n\t\t\trInput.current?.focus()\n\t\t}\n\n\t\tif (editor.getInstanceState().isCoarsePointer) {\n\t\t\trInput.current?.select()\n\t\t}\n\n\t\t// XXX(mime): This fixes iOS not showing the caret sometimes.\n\t\t// This \"shakes\" the caret awake.\n\t\tif (tlenv.isSafari) {\n\t\t\trInput.current?.blur()\n\t\t\trInput.current?.focus()\n\t\t}\n\t}, [editor, isEditing])\n\n\t// When the user presses ctrl / meta enter, complete the editing state.\n\tconst handleKeyDown = useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tswitch (e.key) {\n\t\t\t\tcase 'Enter': {\n\t\t\t\t\tif (e.ctrlKey || e.metaKey) {\n\t\t\t\t\t\teditor.complete()\n\t\t\t\t\t}\n\t\t\t\t\tbreak\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\t// When the text changes, update the text value.\n\tconst handleChange = useCallback(\n\t\t({ plaintext }: { plaintext: string }) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\tconst normalizedPlaintext = TextHelpers.normalizeText(plaintext || '')\n\t\t\teditor.updateShape({\n\t\t\t\tid: shapeId,\n\t\t\t\ttype,\n\t\t\t\tprops: { text: normalizedPlaintext },\n\t\t\t})\n\t\t},\n\t\t[editor, shapeId, type]\n\t)\n\n\treturn {\n\t\trInput,\n\t\thandleKeyDown,\n\t\thandleChange,\n\t\tisEmpty,\n\t\t...commonUseEditableTextHandlers,\n\t}\n}\n\n/** @internal */\nexport function useIsReadyForEditing(editor: Editor, shapeId: TLShapeId) {\n\treturn useValue(\n\t\t'isReadyForEditing',\n\t\t() => {\n\t\t\tconst editingShapeId = editor.getEditingShapeId()\n\t\t\treturn (\n\t\t\t\t// something's being editing... and either it's this shape OR this shape is hovered\n\t\t\t\teditingShapeId !== null &&\n\t\t\t\t(editingShapeId === shapeId || editor.getHoveredShapeId() === shapeId)\n\t\t\t)\n\t\t},\n\t\t[editor, shapeId]\n\t)\n}\n\n/** @internal */\nexport function useEditableTextCommon(shapeId: TLShapeId) {\n\tconst editor = useEditor()\n\tconst isEditing = useValue('isEditing', () => editor.getEditingShapeId() === shapeId, [editor])\n\tconst isReadyForEditing = useIsReadyForEditing(editor, shapeId)\n\n\tconst handleInputPointerDown = useCallback(\n\t\t(e: React.PointerEvent) => {\n\t\t\t// N.B. We used to only do this only when isEditing to help\n\t\t\t// prevent an issue where you could drag a selected shape\n\t\t\t// behind another shape. That is addressed now by the CSS logic\n\t\t\t// looking at data-isselectinganything.\n\t\t\t//\n\t\t\t// We still need to follow this logic even if not isEditing\n\t\t\t// because otherwise there is some flakiness in selection.\n\t\t\t// When selecting text, it would sometimes select some text\n\t\t\t// partially if we didn't dispatch/stop below.\n\n\t\t\teditor.dispatch({\n\t\t\t\t...getPointerInfo(e),\n\t\t\t\ttype: 'pointer',\n\t\t\t\tname: 'pointer_down',\n\t\t\t\ttarget: 'shape',\n\t\t\t\tshape: editor.getShape(shapeId)!,\n\t\t\t})\n\n\t\t\te.stopPropagation() // we need to prevent blurring the input\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\tconst handlePaste = useCallback(\n\t\t(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\t\t\tif (e.clipboardData) {\n\t\t\t\t// find html in the clipboard and look for the tldraw data\n\t\t\t\tconst html = e.clipboardData.getData('text/html')\n\t\t\t\tif (html) {\n\t\t\t\t\tif (html.includes('<div data-tldraw')) {\n\t\t\t\t\t\tpreventDefault(e)\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\tconst handleDoubleClick: (e: React.MouseEvent) => void = markEventAsHandled\n\n\treturn {\n\t\thandleFocus: noop,\n\t\thandleBlur: noop,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick,\n\t\thandlePaste,\n\t\tisEditing,\n\t\tisReadyForEditing,\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/useEditableRichText.ts"],
4
- "sourcesContent": ["import { TLRichText, TLShapeId, TLUnknownShape, isAccelKey, useEditor } from '@tldraw/editor'\nimport { useCallback, useEffect, useRef } from 'react'\nimport { isEmptyRichText } from '../../utils/text/richText'\nimport { useEditableTextCommon } from './useEditablePlainText'\n\n/** @public */\nexport function useEditableRichText(shapeId: TLShapeId, type: string, richText?: TLRichText) {\n\tconst commonUseEditableTextHandlers = useEditableTextCommon(shapeId)\n\tconst isEditing = commonUseEditableTextHandlers.isEditing\n\tconst editor = useEditor()\n\tconst rInput = useRef<HTMLDivElement>(null)\n\tconst isEmpty = richText && isEmptyRichText(richText)\n\n\tuseEffect(() => {\n\t\tif (!isEditing) return\n\n\t\t// N.B. In Development mode you need to ensure you're testing this without StrictMode on.\n\t\t// Otherwise it's not gonna work as expected on iOS.\n\t\tconst contentEditable = rInput.current?.querySelector('[contenteditable]')\n\t\tif (contentEditable && document.activeElement !== rInput.current) {\n\t\t\t// This is a crucial difference with useEditablePlainText, that we need to select the\n\t\t\t// child contentEditable <div> not rInput.current directly.\n\t\t\t// Specifically, this is to ensure iOS works. Otherwise, we could just use rInput.current.\n\t\t\t;(contentEditable as HTMLElement).focus()\n\t\t}\n\t}, [editor, isEditing])\n\n\t// When the user presses ctrl / meta enter, complete the editing state.\n\tconst handleKeyDown = useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\t\t\tif (e.key === 'Enter' && isAccelKey(e)) editor.complete()\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\t// When the text changes, update the text value.\n\tconst handleChange = useCallback(\n\t\t({ richText }: { richText: TLRichText }) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\teditor.updateShape<TLUnknownShape & { props: { richText: TLRichText } }>({\n\t\t\t\tid: shapeId,\n\t\t\t\ttype,\n\t\t\t\tprops: { richText },\n\t\t\t})\n\t\t},\n\t\t[editor, shapeId, type]\n\t)\n\n\treturn {\n\t\trInput,\n\t\thandleKeyDown,\n\t\thandleChange,\n\t\tisEmpty,\n\t\t...commonUseEditableTextHandlers,\n\t}\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAA6E;AAC7E,mBAA+C;AAC/C,sBAAgC;AAChC,kCAAsC;AAG/B,SAAS,oBAAoB,SAAoB,MAAc,UAAuB;AAC5F,QAAM,oCAAgC,mDAAsB,OAAO;AACnE,QAAM,YAAY,8BAA8B;AAChD,QAAM,aAAS,yBAAU;AACzB,QAAM,aAAS,qBAAuB,IAAI;AAC1C,QAAM,UAAU,gBAAY,iCAAgB,QAAQ;AAEpD,8BAAU,MAAM;AACf,QAAI,CAAC,UAAW;AAIhB,UAAM,kBAAkB,OAAO,SAAS,cAAc,mBAAmB;AACzE,QAAI,mBAAmB,SAAS,kBAAkB,OAAO,SAAS;AAIjE;AAAC,MAAC,gBAAgC,MAAM;AAAA,IACzC;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,CAAC;AAGtB,QAAM,oBAAgB;AAAA,IACrB,CAAC,MAAqB;AACrB,UAAI,OAAO,kBAAkB,MAAM,QAAS;AAC5C,UAAI,EAAE,QAAQ,eAAW,0BAAW,CAAC,EAAG,QAAO,SAAS;AAAA,IACzD;AAAA,IACA,CAAC,QAAQ,OAAO;AAAA,EACjB;AAGA,QAAM,mBAAe;AAAA,IACpB,CAAC,EAAE,UAAAA,UAAS,MAAgC;AAC3C,UAAI,OAAO,kBAAkB,MAAM,QAAS;AAE5C,aAAO,YAAkE;AAAA,QACxE,IAAI;AAAA,QACJ;AAAA,QACA,OAAO,EAAE,UAAAA,UAAS;AAAA,MACnB,CAAC;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,SAAS,IAAI;AAAA,EACvB;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ;AACD;",
4
+ "sourcesContent": ["import { TLRichText, TLShape, TLShapeId, isAccelKey, useEditor } from '@tldraw/editor'\nimport { useCallback, useEffect, useRef } from 'react'\nimport { isEmptyRichText } from '../../utils/text/richText'\nimport { useEditableTextCommon } from './useEditablePlainText'\n\n/** @public */\nexport function useEditableRichText(\n\tshapeId: TLShapeId,\n\ttype: Extract<TLShape, { props: { richText: TLRichText } }>['type'],\n\trichText?: TLRichText\n) {\n\tconst commonUseEditableTextHandlers = useEditableTextCommon(shapeId)\n\tconst isEditing = commonUseEditableTextHandlers.isEditing\n\tconst editor = useEditor()\n\tconst rInput = useRef<HTMLDivElement>(null)\n\tconst isEmpty = richText && isEmptyRichText(richText)\n\n\tuseEffect(() => {\n\t\tif (!isEditing) return\n\n\t\t// N.B. In Development mode you need to ensure you're testing this without StrictMode on.\n\t\t// Otherwise it's not gonna work as expected on iOS.\n\t\tconst contentEditable = rInput.current?.querySelector('[contenteditable]')\n\t\tif (contentEditable && document.activeElement !== rInput.current) {\n\t\t\t// This is a crucial difference with useEditablePlainText, that we need to select the\n\t\t\t// child contentEditable <div> not rInput.current directly.\n\t\t\t// Specifically, this is to ensure iOS works. Otherwise, we could just use rInput.current.\n\t\t\t;(contentEditable as HTMLElement).focus()\n\t\t}\n\t}, [editor, isEditing])\n\n\t// When the user presses ctrl / meta enter, complete the editing state.\n\tconst handleKeyDown = useCallback(\n\t\t(e: KeyboardEvent) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\t\t\tif (e.key === 'Enter' && isAccelKey(e)) editor.complete()\n\t\t},\n\t\t[editor, shapeId]\n\t)\n\n\t// When the text changes, update the text value.\n\tconst handleChange = useCallback(\n\t\t({ richText }: { richText: TLRichText }) => {\n\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\teditor.updateShape({\n\t\t\t\tid: shapeId,\n\t\t\t\ttype,\n\t\t\t\tprops: { richText },\n\t\t\t})\n\t\t},\n\t\t[editor, shapeId, type]\n\t)\n\n\treturn {\n\t\trInput,\n\t\thandleKeyDown,\n\t\thandleChange,\n\t\tisEmpty,\n\t\t...commonUseEditableTextHandlers,\n\t}\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAAsE;AACtE,mBAA+C;AAC/C,sBAAgC;AAChC,kCAAsC;AAG/B,SAAS,oBACf,SACA,MACA,UACC;AACD,QAAM,oCAAgC,mDAAsB,OAAO;AACnE,QAAM,YAAY,8BAA8B;AAChD,QAAM,aAAS,yBAAU;AACzB,QAAM,aAAS,qBAAuB,IAAI;AAC1C,QAAM,UAAU,gBAAY,iCAAgB,QAAQ;AAEpD,8BAAU,MAAM;AACf,QAAI,CAAC,UAAW;AAIhB,UAAM,kBAAkB,OAAO,SAAS,cAAc,mBAAmB;AACzE,QAAI,mBAAmB,SAAS,kBAAkB,OAAO,SAAS;AAIjE;AAAC,MAAC,gBAAgC,MAAM;AAAA,IACzC;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,CAAC;AAGtB,QAAM,oBAAgB;AAAA,IACrB,CAAC,MAAqB;AACrB,UAAI,OAAO,kBAAkB,MAAM,QAAS;AAC5C,UAAI,EAAE,QAAQ,eAAW,0BAAW,CAAC,EAAG,QAAO,SAAS;AAAA,IACzD;AAAA,IACA,CAAC,QAAQ,OAAO;AAAA,EACjB;AAGA,QAAM,mBAAe;AAAA,IACpB,CAAC,EAAE,UAAAA,UAAS,MAAgC;AAC3C,UAAI,OAAO,kBAAkB,MAAM,QAAS;AAE5C,aAAO,YAAY;AAAA,QAClB,IAAI;AAAA,QACJ;AAAA,QACA,OAAO,EAAE,UAAAA,UAAS;AAAA,MACnB,CAAC;AAAA,IACF;AAAA,IACA,CAAC,QAAQ,SAAS,IAAI;AAAA,EACvB;AAEA,SAAO;AAAA,IACN;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,GAAG;AAAA,EACJ;AACD;",
6
6
  "names": ["richText"]
7
7
  }
@@ -18,7 +18,6 @@ var __copyProps = (to, from, except, desc) => {
18
18
  var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
19
  var useImageOrVideoAsset_exports = {};
20
20
  __export(useImageOrVideoAsset_exports, {
21
- useAsset: () => useAsset,
22
21
  useImageOrVideoAsset: () => useImageOrVideoAsset
23
22
  });
24
23
  module.exports = __toCommonJS(useImageOrVideoAsset_exports);
@@ -98,5 +97,4 @@ function resolveAssetUrl(editor, assetId, screenScale, exportInfo, callback) {
98
97
  callback(url);
99
98
  });
100
99
  }
101
- const useAsset = useImageOrVideoAsset;
102
100
  //# sourceMappingURL=useImageOrVideoAsset.js.map
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/shared/useImageOrVideoAsset.ts"],
4
- "sourcesContent": ["import {\n\tEditor,\n\tSvgExportContext,\n\tTLAssetId,\n\tTLImageAsset,\n\tTLShapeId,\n\tTLVideoAsset,\n\treact,\n\tuseDelaySvgExport,\n\tuseEditor,\n\tuseSvgExportContext,\n} from '@tldraw/editor'\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * Options for {@link useImageOrVideoAsset}.\n *\n * @public\n */\nexport interface UseImageOrVideoAssetOptions {\n\t/** The asset ID you want a URL for. */\n\tassetId: TLAssetId | null\n\t/**\n\t * The shape the asset is being used for. We won't update the resolved URL while the shape is\n\t * off-screen.\n\t */\n\tshapeId?: TLShapeId\n\t/**\n\t * The width at which the asset will be displayed, in shape-space pixels.\n\t */\n\twidth: number\n}\n\n/**\n * This is a handy helper hook that resolves an asset to an optimized URL for a given shape, or its\n * {@link @tldraw/editor#Editor.createTemporaryAssetPreview | placeholder} if the asset is still\n * uploading. This is used in particular for high-resolution images when you want lower and higher\n * resolution depending on the size of the image on the canvas and the zoom level.\n *\n * For image scaling to work, you need to implement scaled URLs in\n * {@link @tldraw/tlschema#TLAssetStore.resolve}.\n *\n * @public\n */\nexport function useImageOrVideoAsset({ shapeId, assetId, width }: UseImageOrVideoAssetOptions) {\n\tconst editor = useEditor()\n\tconst exportInfo = useSvgExportContext()\n\tconst exportIsReady = useDelaySvgExport()\n\n\t// We use a state to store the result of the asset resolution, and we're going to avoid updating this whenever we can\n\tconst [result, setResult] = useState<{\n\t\tasset: (TLImageAsset | TLVideoAsset) | null\n\t\turl: string | null\n\t}>(() => ({\n\t\tasset: assetId ? (editor.getAsset<TLImageAsset | TLVideoAsset>(assetId) ?? null) : null,\n\t\turl: null as string | null,\n\t}))\n\n\t// A flag for whether we've resolved the asset URL at least once, after which we can debounce\n\tconst didAlreadyResolve = useRef(false)\n\n\t// The last URL that we've seen for the shape\n\tconst previousUrl = useRef<string | null>(null)\n\n\tuseEffect(() => {\n\t\tif (!assetId) return\n\n\t\tlet isCancelled = false\n\t\tlet cancelDebounceFn: (() => void) | undefined\n\n\t\tconst cleanupEffectScheduler = react('update state', () => {\n\t\t\tif (!exportInfo && shapeId && editor.getCulledShapes().has(shapeId)) return\n\n\t\t\t// Get the fresh asset\n\t\t\tconst asset = editor.getAsset<TLImageAsset | TLVideoAsset>(assetId)\n\t\t\tif (!asset) {\n\t\t\t\t// If the asset is deleted, such as when an upload fails, set the URL to null\n\t\t\t\tsetResult((prev) => ({ ...prev, asset: null, url: null }))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Set initial preview for the shape if it has no source (if it was pasted into a local project as base64)\n\t\t\tif (!asset.props.src) {\n\t\t\t\tconst preview = editor.getTemporaryAssetPreview(asset.id)\n\t\t\t\tif (preview) {\n\t\t\t\t\tif (previousUrl.current !== preview) {\n\t\t\t\t\t\tpreviousUrl.current = preview // just for kicks, let's save the url as the previous URL\n\t\t\t\t\t\tsetResult((prev) => ({ ...prev, isPlaceholder: true, url: preview })) // set the preview as the URL\n\t\t\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// aside ...we could bail here if the only thing that has changed is the shape has changed from culled to not culled\n\n\t\t\tconst screenScale = exportInfo\n\t\t\t\t? exportInfo.scale * (width / asset.props.w)\n\t\t\t\t: editor.getZoomLevel() * (width / asset.props.w)\n\n\t\t\tfunction resolve(asset: TLImageAsset | TLVideoAsset, url: string | null) {\n\t\t\t\tif (isCancelled) return // don't update if the hook has remounted\n\t\t\t\tif (previousUrl.current === url) return // don't update the state if the url is the same\n\t\t\t\tdidAlreadyResolve.current = true // mark that we've resolved our first image\n\t\t\t\tpreviousUrl.current = url // keep the url around to compare with the next one\n\t\t\t\tsetResult({ asset, url })\n\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t}\n\n\t\t\t// If we already resolved the URL, debounce fetching potentially multiple image variations.\n\t\t\tif (didAlreadyResolve.current) {\n\t\t\t\tlet tick = 0\n\n\t\t\t\tconst resolveAssetAfterAWhile = () => {\n\t\t\t\t\ttick++\n\t\t\t\t\tif (tick > 500 / 16) {\n\t\t\t\t\t\t// debounce for 500ms\n\t\t\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t\t\t\tcancelDebounceFn?.()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcancelDebounceFn?.()\n\t\t\t\teditor.on('tick', resolveAssetAfterAWhile)\n\t\t\t\tcancelDebounceFn = () => editor.off('tick', resolveAssetAfterAWhile)\n\t\t\t} else {\n\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t}\n\t\t})\n\n\t\treturn () => {\n\t\t\tcleanupEffectScheduler()\n\t\t\tcancelDebounceFn?.()\n\t\t\tisCancelled = true\n\t\t}\n\t}, [editor, assetId, exportInfo, exportIsReady, shapeId, width])\n\n\treturn result\n}\n\nfunction resolveAssetUrl(\n\teditor: Editor,\n\tassetId: TLAssetId,\n\tscreenScale: number,\n\texportInfo: SvgExportContext | null,\n\tcallback: (url: string | null) => void\n) {\n\teditor\n\t\t.resolveAssetUrl(assetId, {\n\t\t\tscreenScale,\n\t\t\tshouldResolveToOriginal: exportInfo ? exportInfo.pixelRatio === null : false,\n\t\t\tdpr: exportInfo?.pixelRatio ?? undefined,\n\t\t})\n\t\t// There's a weird bug with out debounce function that doesn't\n\t\t// make it work right with async functions, so we use a callback\n\t\t// here instead of returning a promise.\n\t\t.then((url) => {\n\t\t\tcallback(url)\n\t\t})\n}\n\n/**\n * @deprecated Use {@link useImageOrVideoAsset} instead.\n *\n * @public\n */\nexport const useAsset = useImageOrVideoAsset\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAWO;AACP,mBAA4C;AAgCrC,SAAS,qBAAqB,EAAE,SAAS,SAAS,MAAM,GAAgC;AAC9F,QAAM,aAAS,yBAAU;AACzB,QAAM,iBAAa,mCAAoB;AACvC,QAAM,oBAAgB,iCAAkB;AAGxC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAGzB,OAAO;AAAA,IACT,OAAO,UAAW,OAAO,SAAsC,OAAO,KAAK,OAAQ;AAAA,IACnF,KAAK;AAAA,EACN,EAAE;AAGF,QAAM,wBAAoB,qBAAO,KAAK;AAGtC,QAAM,kBAAc,qBAAsB,IAAI;AAE9C,8BAAU,MAAM;AACf,QAAI,CAAC,QAAS;AAEd,QAAI,cAAc;AAClB,QAAI;AAEJ,UAAM,6BAAyB,qBAAM,gBAAgB,MAAM;AAC1D,UAAI,CAAC,cAAc,WAAW,OAAO,gBAAgB,EAAE,IAAI,OAAO,EAAG;AAGrE,YAAM,QAAQ,OAAO,SAAsC,OAAO;AAClE,UAAI,CAAC,OAAO;AAEX,kBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,MAAM,KAAK,KAAK,EAAE;AACzD;AAAA,MACD;AAGA,UAAI,CAAC,MAAM,MAAM,KAAK;AACrB,cAAM,UAAU,OAAO,yBAAyB,MAAM,EAAE;AACxD,YAAI,SAAS;AACZ,cAAI,YAAY,YAAY,SAAS;AACpC,wBAAY,UAAU;AACtB,sBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,eAAe,MAAM,KAAK,QAAQ,EAAE;AACpE,0BAAc;AAAA,UACf;AACA;AAAA,QACD;AAAA,MACD;AAIA,YAAM,cAAc,aACjB,WAAW,SAAS,QAAQ,MAAM,MAAM,KACxC,OAAO,aAAa,KAAK,QAAQ,MAAM,MAAM;AAEhD,eAAS,QAAQA,QAAoC,KAAoB;AACxE,YAAI,YAAa;AACjB,YAAI,YAAY,YAAY,IAAK;AACjC,0BAAkB,UAAU;AAC5B,oBAAY,UAAU;AACtB,kBAAU,EAAE,OAAAA,QAAO,IAAI,CAAC;AACxB,sBAAc;AAAA,MACf;AAGA,UAAI,kBAAkB,SAAS;AAC9B,YAAI,OAAO;AAEX,cAAM,0BAA0B,MAAM;AACrC;AACA,cAAI,OAAO,MAAM,IAAI;AAEpB,4BAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AACtF,+BAAmB;AAAA,UACpB;AAAA,QACD;AAEA,2BAAmB;AACnB,eAAO,GAAG,QAAQ,uBAAuB;AACzC,2BAAmB,MAAM,OAAO,IAAI,QAAQ,uBAAuB;AAAA,MACpE,OAAO;AACN,wBAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AAAA,MACvF;AAAA,IACD,CAAC;AAED,WAAO,MAAM;AACZ,6BAAuB;AACvB,yBAAmB;AACnB,oBAAc;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,YAAY,eAAe,SAAS,KAAK,CAAC;AAE/D,SAAO;AACR;AAEA,SAAS,gBACR,QACA,SACA,aACA,YACA,UACC;AACD,SACE,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,yBAAyB,aAAa,WAAW,eAAe,OAAO;AAAA,IACvE,KAAK,YAAY,cAAc;AAAA,EAChC,CAAC,EAIA,KAAK,CAAC,QAAQ;AACd,aAAS,GAAG;AAAA,EACb,CAAC;AACH;AAOO,MAAM,WAAW;",
4
+ "sourcesContent": ["import {\n\tEditor,\n\tSvgExportContext,\n\tTLAssetId,\n\tTLImageAsset,\n\tTLShapeId,\n\tTLVideoAsset,\n\treact,\n\tuseDelaySvgExport,\n\tuseEditor,\n\tuseSvgExportContext,\n} from '@tldraw/editor'\nimport { useEffect, useRef, useState } from 'react'\n\n/**\n * Options for {@link useImageOrVideoAsset}.\n *\n * @public\n */\nexport interface UseImageOrVideoAssetOptions {\n\t/** The asset ID you want a URL for. */\n\tassetId: TLAssetId | null\n\t/**\n\t * The shape the asset is being used for. We won't update the resolved URL while the shape is\n\t * off-screen.\n\t */\n\tshapeId?: TLShapeId\n\t/**\n\t * The width at which the asset will be displayed, in shape-space pixels.\n\t */\n\twidth: number\n}\n\n/**\n * This is a handy helper hook that resolves an asset to an optimized URL for a given shape, or its\n * {@link @tldraw/editor#Editor.createTemporaryAssetPreview | placeholder} if the asset is still\n * uploading. This is used in particular for high-resolution images when you want lower and higher\n * resolution depending on the size of the image on the canvas and the zoom level.\n *\n * For image scaling to work, you need to implement scaled URLs in\n * {@link @tldraw/tlschema#TLAssetStore.resolve}.\n *\n * @public\n */\nexport function useImageOrVideoAsset({ shapeId, assetId, width }: UseImageOrVideoAssetOptions) {\n\tconst editor = useEditor()\n\tconst exportInfo = useSvgExportContext()\n\tconst exportIsReady = useDelaySvgExport()\n\n\t// We use a state to store the result of the asset resolution, and we're going to avoid updating this whenever we can\n\tconst [result, setResult] = useState<{\n\t\tasset: (TLImageAsset | TLVideoAsset) | null\n\t\turl: string | null\n\t}>(() => ({\n\t\tasset: assetId ? (editor.getAsset<TLImageAsset | TLVideoAsset>(assetId) ?? null) : null,\n\t\turl: null as string | null,\n\t}))\n\n\t// A flag for whether we've resolved the asset URL at least once, after which we can debounce\n\tconst didAlreadyResolve = useRef(false)\n\n\t// The last URL that we've seen for the shape\n\tconst previousUrl = useRef<string | null>(null)\n\n\tuseEffect(() => {\n\t\tif (!assetId) return\n\n\t\tlet isCancelled = false\n\t\tlet cancelDebounceFn: (() => void) | undefined\n\n\t\tconst cleanupEffectScheduler = react('update state', () => {\n\t\t\tif (!exportInfo && shapeId && editor.getCulledShapes().has(shapeId)) return\n\n\t\t\t// Get the fresh asset\n\t\t\tconst asset = editor.getAsset<TLImageAsset | TLVideoAsset>(assetId)\n\t\t\tif (!asset) {\n\t\t\t\t// If the asset is deleted, such as when an upload fails, set the URL to null\n\t\t\t\tsetResult((prev) => ({ ...prev, asset: null, url: null }))\n\t\t\t\treturn\n\t\t\t}\n\n\t\t\t// Set initial preview for the shape if it has no source (if it was pasted into a local project as base64)\n\t\t\tif (!asset.props.src) {\n\t\t\t\tconst preview = editor.getTemporaryAssetPreview(asset.id)\n\t\t\t\tif (preview) {\n\t\t\t\t\tif (previousUrl.current !== preview) {\n\t\t\t\t\t\tpreviousUrl.current = preview // just for kicks, let's save the url as the previous URL\n\t\t\t\t\t\tsetResult((prev) => ({ ...prev, isPlaceholder: true, url: preview })) // set the preview as the URL\n\t\t\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t\t\t}\n\t\t\t\t\treturn\n\t\t\t\t}\n\t\t\t}\n\n\t\t\t// aside ...we could bail here if the only thing that has changed is the shape has changed from culled to not culled\n\n\t\t\tconst screenScale = exportInfo\n\t\t\t\t? exportInfo.scale * (width / asset.props.w)\n\t\t\t\t: editor.getZoomLevel() * (width / asset.props.w)\n\n\t\t\tfunction resolve(asset: TLImageAsset | TLVideoAsset, url: string | null) {\n\t\t\t\tif (isCancelled) return // don't update if the hook has remounted\n\t\t\t\tif (previousUrl.current === url) return // don't update the state if the url is the same\n\t\t\t\tdidAlreadyResolve.current = true // mark that we've resolved our first image\n\t\t\t\tpreviousUrl.current = url // keep the url around to compare with the next one\n\t\t\t\tsetResult({ asset, url })\n\t\t\t\texportIsReady() // let the SVG export know we're ready for export\n\t\t\t}\n\n\t\t\t// If we already resolved the URL, debounce fetching potentially multiple image variations.\n\t\t\tif (didAlreadyResolve.current) {\n\t\t\t\tlet tick = 0\n\n\t\t\t\tconst resolveAssetAfterAWhile = () => {\n\t\t\t\t\ttick++\n\t\t\t\t\tif (tick > 500 / 16) {\n\t\t\t\t\t\t// debounce for 500ms\n\t\t\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t\t\t\tcancelDebounceFn?.()\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tcancelDebounceFn?.()\n\t\t\t\teditor.on('tick', resolveAssetAfterAWhile)\n\t\t\t\tcancelDebounceFn = () => editor.off('tick', resolveAssetAfterAWhile)\n\t\t\t} else {\n\t\t\t\tresolveAssetUrl(editor, assetId, screenScale, exportInfo, (url) => resolve(asset, url))\n\t\t\t}\n\t\t})\n\n\t\treturn () => {\n\t\t\tcleanupEffectScheduler()\n\t\t\tcancelDebounceFn?.()\n\t\t\tisCancelled = true\n\t\t}\n\t}, [editor, assetId, exportInfo, exportIsReady, shapeId, width])\n\n\treturn result\n}\n\nfunction resolveAssetUrl(\n\teditor: Editor,\n\tassetId: TLAssetId,\n\tscreenScale: number,\n\texportInfo: SvgExportContext | null,\n\tcallback: (url: string | null) => void\n) {\n\teditor\n\t\t.resolveAssetUrl(assetId, {\n\t\t\tscreenScale,\n\t\t\tshouldResolveToOriginal: exportInfo ? exportInfo.pixelRatio === null : false,\n\t\t\tdpr: exportInfo?.pixelRatio ?? undefined,\n\t\t})\n\t\t// There's a weird bug with out debounce function that doesn't\n\t\t// make it work right with async functions, so we use a callback\n\t\t// here instead of returning a promise.\n\t\t.then((url) => {\n\t\t\tcallback(url)\n\t\t})\n}\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBAWO;AACP,mBAA4C;AAgCrC,SAAS,qBAAqB,EAAE,SAAS,SAAS,MAAM,GAAgC;AAC9F,QAAM,aAAS,yBAAU;AACzB,QAAM,iBAAa,mCAAoB;AACvC,QAAM,oBAAgB,iCAAkB;AAGxC,QAAM,CAAC,QAAQ,SAAS,QAAI,uBAGzB,OAAO;AAAA,IACT,OAAO,UAAW,OAAO,SAAsC,OAAO,KAAK,OAAQ;AAAA,IACnF,KAAK;AAAA,EACN,EAAE;AAGF,QAAM,wBAAoB,qBAAO,KAAK;AAGtC,QAAM,kBAAc,qBAAsB,IAAI;AAE9C,8BAAU,MAAM;AACf,QAAI,CAAC,QAAS;AAEd,QAAI,cAAc;AAClB,QAAI;AAEJ,UAAM,6BAAyB,qBAAM,gBAAgB,MAAM;AAC1D,UAAI,CAAC,cAAc,WAAW,OAAO,gBAAgB,EAAE,IAAI,OAAO,EAAG;AAGrE,YAAM,QAAQ,OAAO,SAAsC,OAAO;AAClE,UAAI,CAAC,OAAO;AAEX,kBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,OAAO,MAAM,KAAK,KAAK,EAAE;AACzD;AAAA,MACD;AAGA,UAAI,CAAC,MAAM,MAAM,KAAK;AACrB,cAAM,UAAU,OAAO,yBAAyB,MAAM,EAAE;AACxD,YAAI,SAAS;AACZ,cAAI,YAAY,YAAY,SAAS;AACpC,wBAAY,UAAU;AACtB,sBAAU,CAAC,UAAU,EAAE,GAAG,MAAM,eAAe,MAAM,KAAK,QAAQ,EAAE;AACpE,0BAAc;AAAA,UACf;AACA;AAAA,QACD;AAAA,MACD;AAIA,YAAM,cAAc,aACjB,WAAW,SAAS,QAAQ,MAAM,MAAM,KACxC,OAAO,aAAa,KAAK,QAAQ,MAAM,MAAM;AAEhD,eAAS,QAAQA,QAAoC,KAAoB;AACxE,YAAI,YAAa;AACjB,YAAI,YAAY,YAAY,IAAK;AACjC,0BAAkB,UAAU;AAC5B,oBAAY,UAAU;AACtB,kBAAU,EAAE,OAAAA,QAAO,IAAI,CAAC;AACxB,sBAAc;AAAA,MACf;AAGA,UAAI,kBAAkB,SAAS;AAC9B,YAAI,OAAO;AAEX,cAAM,0BAA0B,MAAM;AACrC;AACA,cAAI,OAAO,MAAM,IAAI;AAEpB,4BAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AACtF,+BAAmB;AAAA,UACpB;AAAA,QACD;AAEA,2BAAmB;AACnB,eAAO,GAAG,QAAQ,uBAAuB;AACzC,2BAAmB,MAAM,OAAO,IAAI,QAAQ,uBAAuB;AAAA,MACpE,OAAO;AACN,wBAAgB,QAAQ,SAAS,aAAa,YAAY,CAAC,QAAQ,QAAQ,OAAO,GAAG,CAAC;AAAA,MACvF;AAAA,IACD,CAAC;AAED,WAAO,MAAM;AACZ,6BAAuB;AACvB,yBAAmB;AACnB,oBAAc;AAAA,IACf;AAAA,EACD,GAAG,CAAC,QAAQ,SAAS,YAAY,eAAe,SAAS,KAAK,CAAC;AAE/D,SAAO;AACR;AAEA,SAAS,gBACR,QACA,SACA,aACA,YACA,UACC;AACD,SACE,gBAAgB,SAAS;AAAA,IACzB;AAAA,IACA,yBAAyB,aAAa,WAAW,eAAe,OAAO;AAAA,IACvE,KAAK,YAAY,cAAc;AAAA,EAChC,CAAC,EAIA,KAAK,CAAC,QAAQ;AACd,aAAS,GAAG;AAAA,EACb,CAAC;AACH;",
6
6
  "names": ["asset"]
7
7
  }
@@ -70,8 +70,8 @@ const PlainTextArea = import_react.default.forwardRef(function TextArea({
70
70
  onChange,
71
71
  onKeyDown: (e) => handleKeyDown(e.nativeEvent),
72
72
  onBlur: handleBlur,
73
- onTouchEnd: import_editor.stopEventPropagation,
74
- onContextMenu: isEditing ? import_editor.stopEventPropagation : void 0,
73
+ onTouchEnd: import_editor.markEventAsHandled,
74
+ onContextMenu: isEditing ? (e) => e.stopPropagation() : void 0,
75
75
  onPointerDown: handleInputPointerDown,
76
76
  onPaste: handlePaste,
77
77
  onDoubleClick: handleDoubleClick,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/text/PlainTextArea.tsx"],
4
- "sourcesContent": ["import { preventDefault, stopEventPropagation } from '@tldraw/editor'\nimport React from 'react'\nimport { TextAreaProps } from './RichTextArea'\n\n/**\n * A plain text area that can be used for basic editing text.\n *\n * @public @react\n */\nexport const PlainTextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\n\t{\n\t\tisEditing,\n\t\ttext,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleKeyDown,\n\t\thandlePaste,\n\t\thandleBlur,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick,\n\t},\n\tref\n) {\n\tconst onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\thandleChange({ plaintext: e.target.value })\n\t}\n\n\treturn (\n\t\t<textarea\n\t\t\tref={ref}\n\t\t\tclassName=\"tl-text tl-text-input\"\n\t\t\tname=\"text\"\n\t\t\ttabIndex={-1}\n\t\t\tdisabled={!isEditing}\n\t\t\treadOnly={!isEditing}\n\t\t\tautoComplete=\"off\"\n\t\t\tautoCapitalize=\"off\"\n\t\t\tautoCorrect=\"off\"\n\t\t\tautoSave=\"off\"\n\t\t\tplaceholder=\"\"\n\t\t\tspellCheck=\"true\"\n\t\t\twrap=\"off\"\n\t\t\tdir=\"auto\"\n\t\t\tdefaultValue={text}\n\t\t\tonFocus={handleFocus}\n\t\t\tonChange={onChange}\n\t\t\tonKeyDown={(e) => handleKeyDown(e.nativeEvent)}\n\t\t\tonBlur={handleBlur}\n\t\t\tonTouchEnd={stopEventPropagation}\n\t\t\tonContextMenu={isEditing ? stopEventPropagation : undefined}\n\t\t\tonPointerDown={handleInputPointerDown}\n\t\t\tonPaste={handlePaste}\n\t\t\tonDoubleClick={handleDoubleClick}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t/>\n\t)\n})\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BE;AA5BF,oBAAqD;AACrD,mBAAkB;AAQX,MAAM,gBAAgB,aAAAA,QAAM,WAA+C,SAAS,SAC1F;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GACA,KACC;AACD,QAAM,WAAW,CAAC,MAA8C;AAC/D,iBAAa,EAAE,WAAW,EAAE,OAAO,MAAM,CAAC;AAAA,EAC3C;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,WAAU;AAAA,MACV,MAAK;AAAA,MACL,UAAU;AAAA,MACV,UAAU,CAAC;AAAA,MACX,UAAU,CAAC;AAAA,MACX,cAAa;AAAA,MACb,gBAAe;AAAA,MACf,aAAY;AAAA,MACZ,UAAS;AAAA,MACT,aAAY;AAAA,MACZ,YAAW;AAAA,MACX,MAAK;AAAA,MACL,KAAI;AAAA,MACJ,cAAc;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,WAAW,CAAC,MAAM,cAAc,EAAE,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,eAAe,YAAY,qCAAuB;AAAA,MAClD,eAAe;AAAA,MACf,SAAS;AAAA,MACT,eAAe;AAAA,MAKf,aAAa;AAAA;AAAA,EACd;AAEF,CAAC;",
4
+ "sourcesContent": ["import { markEventAsHandled, preventDefault } from '@tldraw/editor'\nimport React from 'react'\nimport { TextAreaProps } from './RichTextArea'\n\n/**\n * A plain text area that can be used for basic editing text.\n *\n * @public @react\n */\nexport const PlainTextArea = React.forwardRef<HTMLTextAreaElement, TextAreaProps>(function TextArea(\n\t{\n\t\tisEditing,\n\t\ttext,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleKeyDown,\n\t\thandlePaste,\n\t\thandleBlur,\n\t\thandleInputPointerDown,\n\t\thandleDoubleClick,\n\t},\n\tref\n) {\n\tconst onChange = (e: React.ChangeEvent<HTMLTextAreaElement>) => {\n\t\thandleChange({ plaintext: e.target.value })\n\t}\n\n\treturn (\n\t\t<textarea\n\t\t\tref={ref}\n\t\t\tclassName=\"tl-text tl-text-input\"\n\t\t\tname=\"text\"\n\t\t\ttabIndex={-1}\n\t\t\tdisabled={!isEditing}\n\t\t\treadOnly={!isEditing}\n\t\t\tautoComplete=\"off\"\n\t\t\tautoCapitalize=\"off\"\n\t\t\tautoCorrect=\"off\"\n\t\t\tautoSave=\"off\"\n\t\t\tplaceholder=\"\"\n\t\t\tspellCheck=\"true\"\n\t\t\twrap=\"off\"\n\t\t\tdir=\"auto\"\n\t\t\tdefaultValue={text}\n\t\t\tonFocus={handleFocus}\n\t\t\tonChange={onChange}\n\t\t\tonKeyDown={(e) => handleKeyDown(e.nativeEvent)}\n\t\t\tonBlur={handleBlur}\n\t\t\tonTouchEnd={markEventAsHandled}\n\t\t\tonContextMenu={isEditing ? (e) => e.stopPropagation() : undefined}\n\t\t\tonPointerDown={handleInputPointerDown}\n\t\t\tonPaste={handlePaste}\n\t\t\tonDoubleClick={handleDoubleClick}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t/>\n\t)\n})\n"],
5
+ "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AA4BE;AA5BF,oBAAmD;AACnD,mBAAkB;AAQX,MAAM,gBAAgB,aAAAA,QAAM,WAA+C,SAAS,SAC1F;AAAA,EACC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACD,GACA,KACC;AACD,QAAM,WAAW,CAAC,MAA8C;AAC/D,iBAAa,EAAE,WAAW,EAAE,OAAO,MAAM,CAAC;AAAA,EAC3C;AAEA,SACC;AAAA,IAAC;AAAA;AAAA,MACA;AAAA,MACA,WAAU;AAAA,MACV,MAAK;AAAA,MACL,UAAU;AAAA,MACV,UAAU,CAAC;AAAA,MACX,UAAU,CAAC;AAAA,MACX,cAAa;AAAA,MACb,gBAAe;AAAA,MACf,aAAY;AAAA,MACZ,UAAS;AAAA,MACT,aAAY;AAAA,MACZ,YAAW;AAAA,MACX,MAAK;AAAA,MACL,KAAI;AAAA,MACJ,cAAc;AAAA,MACd,SAAS;AAAA,MACT;AAAA,MACA,WAAW,CAAC,MAAM,cAAc,EAAE,WAAW;AAAA,MAC7C,QAAQ;AAAA,MACR,YAAY;AAAA,MACZ,eAAe,YAAY,CAAC,MAAM,EAAE,gBAAgB,IAAI;AAAA,MACxD,eAAe;AAAA,MACf,SAAS;AAAA,MACT,eAAe;AAAA,MAKf,aAAa;AAAA;AAAA,EACd;AAEF,CAAC;",
6
6
  "names": ["React"]
7
7
  }
@@ -183,9 +183,9 @@ const RichTextArea = import_react2.default.forwardRef(function RichTextArea2({
183
183
  tabIndex: -1,
184
184
  "data-testid": "rich-text-area",
185
185
  className: "tl-rich-text tl-text tl-text-input",
186
- onContextMenu: isEditing ? import_editor.stopEventPropagation : void 0,
187
- onPointerDownCapture: import_editor.stopEventPropagation,
188
- onTouchEnd: import_editor.stopEventPropagation,
186
+ onContextMenu: isEditing ? (e) => e.stopPropagation() : void 0,
187
+ onPointerDownCapture: (e) => e.stopPropagation(),
188
+ onTouchEnd: (e) => e.stopPropagation(),
189
189
  onDragStart: import_editor.preventDefault,
190
190
  children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { className: "tl-rich-text", ref: rTextEditorEl })
191
191
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/shapes/text/RichTextArea.tsx"],
4
- "sourcesContent": ["import { EditorView } from '@tiptap/pm/view'\nimport {\n\tEditorEvents,\n\tJSONContent,\n\tEditor as TextEditor,\n\ttype Editor as TTEditor,\n} from '@tiptap/react'\nimport {\n\tEditor,\n\tTLRichText,\n\tTLShapeId,\n\tpreventDefault,\n\tstopEventPropagation,\n\tuseEditor,\n\tuseEvent,\n\tuseUniqueSafeId,\n} from '@tldraw/editor'\nimport React, { useLayoutEffect, useRef } from 'react'\n\n/** @public */\nexport interface TextAreaProps {\n\tisEditing: boolean\n\ttext?: string\n\tshapeId: TLShapeId\n\trichText?: TLRichText\n\thandleFocus(): void\n\thandleBlur(): void\n\thandleKeyDown(e: KeyboardEvent): void\n\thandleChange(changeInfo: { plaintext?: string; richText?: TLRichText }): void\n\thandleInputPointerDown(e: React.PointerEvent<HTMLElement>): void\n\thandleDoubleClick(e: any): any\n\thandlePaste(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>): void\n\thasCustomTabBehavior?: boolean\n}\n\n/**\n * N.B. In Development mode you need to ensure you're testing this without StrictMode on.\n * Otherwise it's not gonna work as expected on iOS.\n * Specifically, it means that the virtual keyboard won't pop open sometimes\n * (iOS starts flipping out when you render multiple times when trying to focus something) .\n */\n\n/**\n * A rich text area that can be used for editing text with rich text formatting.\n * This component uses the TipTap editor under the hood.\n *\n * @public @react\n */\nexport const RichTextArea = React.forwardRef<HTMLDivElement, TextAreaProps>(function RichTextArea(\n\t{\n\t\tshapeId,\n\t\tisEditing,\n\t\trichText,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleBlur,\n\t\thandleKeyDown,\n\t\thandleDoubleClick,\n\t\thasCustomTabBehavior,\n\t\thandlePaste,\n\t},\n\tref\n) {\n\tconst editor = useEditor()\n\tconst tipTapId = useUniqueSafeId('tip-tap-editor')\n\tconst tipTapConfig = editor.getTextOptions().tipTapConfig\n\n\tconst rInitialRichText = useRef(richText)\n\tconst rTextEditor = useRef<TTEditor | null>(null)\n\tconst rTextEditorEl = useRef<HTMLDivElement>(null)\n\n\tuseLayoutEffect(() => {\n\t\tif (!rTextEditor.current) {\n\t\t\trInitialRichText.current = richText\n\t\t} else if (rInitialRichText.current !== richText) {\n\t\t\trTextEditor.current.commands.setContent(richText as JSONContent)\n\t\t}\n\t}, [richText])\n\n\t// The order of events is:\n\t// - editor begins editing any shape\n\t// - we set listeners for select all / place caret events\n\t// - if the user is editing this shape, this component is rendered\n\t// - editor emits the select all event / place caret event\n\t// - the text editor is onCreate callback is called\n\tconst rCreateInfo = useRef({\n\t\tselectAll: false,\n\t\tcaretPosition: null as { x: number; y: number } | null,\n\t})\n\n\tuseLayoutEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.selectAll = true\n\t\t\t}\n\t\t}\n\n\t\tfunction placeCaret(event: { shapeId: TLShapeId; point: { x: number; y: number } }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.caretPosition = event.point\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\teditor.on('place-caret', placeCaret)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t\teditor.off('place-caret', placeCaret)\n\t\t}\n\t}, [editor, isEditing])\n\n\tconst onChange = useEvent(handleChange)\n\tconst onKeyDown = useEvent(handleKeyDown)\n\tconst onFocus = useEvent(handleFocus)\n\tconst onBlur = useEvent(handleBlur)\n\tconst onDoubleClick = useEvent(handleDoubleClick)\n\tconst onPaste = useEvent(handlePaste)\n\tuseLayoutEffect(() => {\n\t\tif (!isEditing || !tipTapConfig || !rTextEditorEl.current) return\n\n\t\tconst { editorProps, ...restOfTipTapConfig } = tipTapConfig\n\n\t\t// Because React can double-render in Strict Mode, we need to make sure we're not setting\n\t\t// the text editor twice. This became more much more prevalent in React 19, but also it\n\t\t// started manifesting in some cases in Next 14.2 (which maybe patches React 18.3 in weird\n\t\t// ways). So we used to use EditorProvider but we into weird rendering issues.\n\t\tconst textEditorInstance = new TextEditor({\n\t\t\telement: rTextEditorEl.current,\n\t\t\tautofocus: true,\n\t\t\teditable: isEditing,\n\t\t\tonUpdate: (props: EditorEvents['update']) => {\n\t\t\t\tconst content: TLRichText = props.editor.state.doc.toJSON()\n\t\t\t\trInitialRichText.current = content\n\t\t\t\tonChange({ richText: content })\n\t\t\t},\n\t\t\tonFocus,\n\t\t\tonBlur,\n\t\t\t// onCreate is called after a `setTimeout(0)`\n\t\t\tonCreate: (props) => {\n\t\t\t\t// If we're not still editing the original shape, then don't do anything.\n\t\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\t\tconst textEditor = props.editor\n\t\t\t\teditor.setRichTextEditor(textEditor)\n\n\t\t\t\tconst { selectAll, caretPosition } = rCreateInfo.current\n\n\t\t\t\tif (selectAll) {\n\t\t\t\t\t// Select all of the text\n\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t} else if (caretPosition) {\n\t\t\t\t\t// Set the initial caret screen position\n\t\t\t\t\tconst pos = textEditor.view.posAtCoords({\n\t\t\t\t\t\tleft: caretPosition.x,\n\t\t\t\t\t\ttop: caretPosition.y,\n\t\t\t\t\t})?.pos\n\n\t\t\t\t\tif (pos) {\n\t\t\t\t\t\t// Focus to that position.\n\t\t\t\t\t\ttextEditor.chain().focus().setTextSelection(pos).run()\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no position, default to select all.\n\t\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\teditorProps: {\n\t\t\t\thandleKeyDown: (view: EditorView, event: KeyboardEvent) => {\n\t\t\t\t\tif (!hasCustomTabBehavior && event.key === 'Tab') {\n\t\t\t\t\t\thandleTab(editor, view, event)\n\t\t\t\t\t}\n\n\t\t\t\t\tonKeyDown(event)\n\t\t\t\t},\n\t\t\t\thandlePaste: (view: EditorView, event: ClipboardEvent) => {\n\t\t\t\t\tonPaste(event)\n\t\t\t\t\tif (event.defaultPrevented) return true\n\t\t\t\t},\n\t\t\t\thandleDoubleClick: (_view, _pos, event) => onDoubleClick(event),\n\t\t\t\t...editorProps,\n\t\t\t},\n\t\t\tcoreExtensionOptions: {\n\t\t\t\tclipboardTextSerializer: {\n\t\t\t\t\tblockSeparator: '\\n',\n\t\t\t\t},\n\t\t\t},\n\t\t\t...restOfTipTapConfig,\n\t\t\tcontent: rInitialRichText.current as JSONContent,\n\t\t})\n\n\t\t// XXX: When creating a brand new shape and double-clicking into it quickly to edit it,\n\t\t// there's some kind of race condition happening where the editor doesn't focus properly.\n\t\tconst timeout = editor.timers.setTimeout(() => {\n\t\t\tif (rCreateInfo.current.caretPosition || rCreateInfo.current.selectAll) {\n\t\t\t\ttextEditorInstance.commands.focus()\n\t\t\t} else {\n\t\t\t\ttextEditorInstance.commands.focus('end')\n\t\t\t}\n\n\t\t\trCreateInfo.current.selectAll = false\n\t\t\trCreateInfo.current.caretPosition = null\n\t\t}, 100)\n\n\t\trTextEditor.current = textEditorInstance\n\n\t\treturn () => {\n\t\t\trTextEditor.current = null\n\t\t\tclearTimeout(timeout)\n\t\t\ttextEditorInstance.destroy()\n\t\t}\n\t}, [\n\t\tisEditing,\n\t\ttipTapConfig,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonDoubleClick,\n\t\tonChange,\n\t\tonPaste,\n\t\tonKeyDown,\n\t\teditor,\n\t\tshapeId,\n\t\thasCustomTabBehavior,\n\t])\n\n\tif (!isEditing || !tipTapConfig) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tid={tipTapId}\n\t\t\tref={ref}\n\t\t\ttabIndex={-1}\n\t\t\tdata-testid=\"rich-text-area\"\n\t\t\tclassName=\"tl-rich-text tl-text tl-text-input\"\n\t\t\tonContextMenu={isEditing ? stopEventPropagation : undefined}\n\t\t\t// N.B. When PointerStateExtension was introduced, this was moved there.\n\t\t\t// However, that caused selecting over list items to break.\n\t\t\t// The handleDOMEvents in TipTap don't seem to support the pointerDownCapture event.\n\t\t\tonPointerDownCapture={stopEventPropagation}\n\t\t\t// This onTouchEnd is important for Android to be able to change selection on text.\n\t\t\tonTouchEnd={stopEventPropagation}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t>\n\t\t\t<div className=\"tl-rich-text\" ref={rTextEditorEl} />\n\t\t</div>\n\t)\n})\n\n// Prevent exiting the editor when hitting Tab.\n// Also, insert a tab character at the front of the line if the shift key isn't pressed,\n// otherwise if shift is pressed, remove a tab character from the front of the line.\nfunction handleTab(editor: Editor, view: EditorView, event: KeyboardEvent) {\n\t// Don't exit the editor.\n\tevent.preventDefault()\n\n\tconst textEditor = editor.getRichTextEditor()\n\tif (textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList')) return\n\n\tconst { state, dispatch } = view\n\tconst { $from, $to } = state.selection\n\tconst isShift = event.shiftKey\n\n\t// Create a new transaction\n\tlet tr = state.tr\n\n\t// Iterate over each line in the selection in reverse so that the positions\n\t// are stable as we modify the document.\n\tlet pos = $to.end()\n\twhile (pos >= $from.start()) {\n\t\tconst line = state.doc.resolve(pos).blockRange()\n\t\tif (!line) break\n\n\t\tconst lineStart = line.start\n\t\tconst lineEnd = line.end\n\t\tconst lineText = state.doc.textBetween(lineStart, lineEnd, '\\n')\n\n\t\t// Check if the current line or any of its parent nodes are part of a list\n\t\tlet isInList = false\n\t\tstate.doc.nodesBetween(lineStart, lineEnd, (node) => {\n\t\t\tif (node.type.name === 'bulletList' || node.type.name === 'orderedList') {\n\t\t\t\tisInList = true\n\t\t\t\treturn false // Stop iteration\n\t\t\t}\n\t\t})\n\n\t\t// TODO: for now skip over lists. Later, we might consider handling them using\n\t\t// sinkListItem and liftListItem from @tiptap/pm/schema-list\n\t\tif (!isInList) {\n\t\t\tif (!isShift) {\n\t\t\t\t// Insert a tab character at the start of the line\n\t\t\t\ttr = tr.insertText('\\t', lineStart + 1)\n\t\t\t} else {\n\t\t\t\t// Remove a tab character from the start of the line\n\t\t\t\tif (lineText.startsWith('\\t')) {\n\t\t\t\t\ttr = tr.delete(lineStart + 1, lineStart + 2)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpos = lineStart - 1\n\t}\n\n\tconst mappedSelection = state.selection.map(tr.doc, tr.mapping)\n\ttr.setSelection(mappedSelection)\n\n\tif (tr.docChanged) {\n\t\tdispatch(tr)\n\t}\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["import { EditorView } from '@tiptap/pm/view'\nimport {\n\tEditorEvents,\n\tJSONContent,\n\tEditor as TextEditor,\n\ttype Editor as TTEditor,\n} from '@tiptap/react'\nimport {\n\tEditor,\n\tTLRichText,\n\tTLShapeId,\n\tpreventDefault,\n\tuseEditor,\n\tuseEvent,\n\tuseUniqueSafeId,\n} from '@tldraw/editor'\nimport React, { useLayoutEffect, useRef } from 'react'\n\n/** @public */\nexport interface TextAreaProps {\n\tisEditing: boolean\n\ttext?: string\n\tshapeId: TLShapeId\n\trichText?: TLRichText\n\thandleFocus(): void\n\thandleBlur(): void\n\thandleKeyDown(e: KeyboardEvent): void\n\thandleChange(changeInfo: { plaintext?: string; richText?: TLRichText }): void\n\thandleInputPointerDown(e: React.PointerEvent<HTMLElement>): void\n\thandleDoubleClick(e: any): any\n\thandlePaste(e: ClipboardEvent | React.ClipboardEvent<HTMLTextAreaElement>): void\n\thasCustomTabBehavior?: boolean\n}\n\n/**\n * N.B. In Development mode you need to ensure you're testing this without StrictMode on.\n * Otherwise it's not gonna work as expected on iOS.\n * Specifically, it means that the virtual keyboard won't pop open sometimes\n * (iOS starts flipping out when you render multiple times when trying to focus something) .\n */\n\n/**\n * A rich text area that can be used for editing text with rich text formatting.\n * This component uses the TipTap editor under the hood.\n *\n * @public @react\n */\nexport const RichTextArea = React.forwardRef<HTMLDivElement, TextAreaProps>(function RichTextArea(\n\t{\n\t\tshapeId,\n\t\tisEditing,\n\t\trichText,\n\t\thandleFocus,\n\t\thandleChange,\n\t\thandleBlur,\n\t\thandleKeyDown,\n\t\thandleDoubleClick,\n\t\thasCustomTabBehavior,\n\t\thandlePaste,\n\t},\n\tref\n) {\n\tconst editor = useEditor()\n\tconst tipTapId = useUniqueSafeId('tip-tap-editor')\n\tconst tipTapConfig = editor.getTextOptions().tipTapConfig\n\n\tconst rInitialRichText = useRef(richText)\n\tconst rTextEditor = useRef<TTEditor | null>(null)\n\tconst rTextEditorEl = useRef<HTMLDivElement>(null)\n\n\tuseLayoutEffect(() => {\n\t\tif (!rTextEditor.current) {\n\t\t\trInitialRichText.current = richText\n\t\t} else if (rInitialRichText.current !== richText) {\n\t\t\trTextEditor.current.commands.setContent(richText as JSONContent)\n\t\t}\n\t}, [richText])\n\n\t// The order of events is:\n\t// - editor begins editing any shape\n\t// - we set listeners for select all / place caret events\n\t// - if the user is editing this shape, this component is rendered\n\t// - editor emits the select all event / place caret event\n\t// - the text editor is onCreate callback is called\n\tconst rCreateInfo = useRef({\n\t\tselectAll: false,\n\t\tcaretPosition: null as { x: number; y: number } | null,\n\t})\n\n\tuseLayoutEffect(() => {\n\t\tfunction selectAllIfEditing(event: { shapeId: TLShapeId }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.selectAll = true\n\t\t\t}\n\t\t}\n\n\t\tfunction placeCaret(event: { shapeId: TLShapeId; point: { x: number; y: number } }) {\n\t\t\tif (event.shapeId === editor.getEditingShapeId()) {\n\t\t\t\trCreateInfo.current.caretPosition = event.point\n\t\t\t}\n\t\t}\n\n\t\teditor.on('select-all-text', selectAllIfEditing)\n\t\teditor.on('place-caret', placeCaret)\n\t\treturn () => {\n\t\t\teditor.off('select-all-text', selectAllIfEditing)\n\t\t\teditor.off('place-caret', placeCaret)\n\t\t}\n\t}, [editor, isEditing])\n\n\tconst onChange = useEvent(handleChange)\n\tconst onKeyDown = useEvent(handleKeyDown)\n\tconst onFocus = useEvent(handleFocus)\n\tconst onBlur = useEvent(handleBlur)\n\tconst onDoubleClick = useEvent(handleDoubleClick)\n\tconst onPaste = useEvent(handlePaste)\n\tuseLayoutEffect(() => {\n\t\tif (!isEditing || !tipTapConfig || !rTextEditorEl.current) return\n\n\t\tconst { editorProps, ...restOfTipTapConfig } = tipTapConfig\n\n\t\t// Because React can double-render in Strict Mode, we need to make sure we're not setting\n\t\t// the text editor twice. This became more much more prevalent in React 19, but also it\n\t\t// started manifesting in some cases in Next 14.2 (which maybe patches React 18.3 in weird\n\t\t// ways). So we used to use EditorProvider but we into weird rendering issues.\n\t\tconst textEditorInstance = new TextEditor({\n\t\t\telement: rTextEditorEl.current,\n\t\t\tautofocus: true,\n\t\t\teditable: isEditing,\n\t\t\tonUpdate: (props: EditorEvents['update']) => {\n\t\t\t\tconst content: TLRichText = props.editor.state.doc.toJSON()\n\t\t\t\trInitialRichText.current = content\n\t\t\t\tonChange({ richText: content })\n\t\t\t},\n\t\t\tonFocus,\n\t\t\tonBlur,\n\t\t\t// onCreate is called after a `setTimeout(0)`\n\t\t\tonCreate: (props) => {\n\t\t\t\t// If we're not still editing the original shape, then don't do anything.\n\t\t\t\tif (editor.getEditingShapeId() !== shapeId) return\n\n\t\t\t\tconst textEditor = props.editor\n\t\t\t\teditor.setRichTextEditor(textEditor)\n\n\t\t\t\tconst { selectAll, caretPosition } = rCreateInfo.current\n\n\t\t\t\tif (selectAll) {\n\t\t\t\t\t// Select all of the text\n\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t} else if (caretPosition) {\n\t\t\t\t\t// Set the initial caret screen position\n\t\t\t\t\tconst pos = textEditor.view.posAtCoords({\n\t\t\t\t\t\tleft: caretPosition.x,\n\t\t\t\t\t\ttop: caretPosition.y,\n\t\t\t\t\t})?.pos\n\n\t\t\t\t\tif (pos) {\n\t\t\t\t\t\t// Focus to that position.\n\t\t\t\t\t\ttextEditor.chain().focus().setTextSelection(pos).run()\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If no position, default to select all.\n\t\t\t\t\t\ttextEditor.chain().focus().selectAll().run()\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t},\n\t\t\teditorProps: {\n\t\t\t\thandleKeyDown: (view: EditorView, event: KeyboardEvent) => {\n\t\t\t\t\tif (!hasCustomTabBehavior && event.key === 'Tab') {\n\t\t\t\t\t\thandleTab(editor, view, event)\n\t\t\t\t\t}\n\n\t\t\t\t\tonKeyDown(event)\n\t\t\t\t},\n\t\t\t\thandlePaste: (view: EditorView, event: ClipboardEvent) => {\n\t\t\t\t\tonPaste(event)\n\t\t\t\t\tif (event.defaultPrevented) return true\n\t\t\t\t},\n\t\t\t\thandleDoubleClick: (_view, _pos, event) => onDoubleClick(event),\n\t\t\t\t...editorProps,\n\t\t\t},\n\t\t\tcoreExtensionOptions: {\n\t\t\t\tclipboardTextSerializer: {\n\t\t\t\t\tblockSeparator: '\\n',\n\t\t\t\t},\n\t\t\t},\n\t\t\t...restOfTipTapConfig,\n\t\t\tcontent: rInitialRichText.current as JSONContent,\n\t\t})\n\n\t\t// XXX: When creating a brand new shape and double-clicking into it quickly to edit it,\n\t\t// there's some kind of race condition happening where the editor doesn't focus properly.\n\t\tconst timeout = editor.timers.setTimeout(() => {\n\t\t\tif (rCreateInfo.current.caretPosition || rCreateInfo.current.selectAll) {\n\t\t\t\ttextEditorInstance.commands.focus()\n\t\t\t} else {\n\t\t\t\ttextEditorInstance.commands.focus('end')\n\t\t\t}\n\n\t\t\trCreateInfo.current.selectAll = false\n\t\t\trCreateInfo.current.caretPosition = null\n\t\t}, 100)\n\n\t\trTextEditor.current = textEditorInstance\n\n\t\treturn () => {\n\t\t\trTextEditor.current = null\n\t\t\tclearTimeout(timeout)\n\t\t\ttextEditorInstance.destroy()\n\t\t}\n\t}, [\n\t\tisEditing,\n\t\ttipTapConfig,\n\t\tonFocus,\n\t\tonBlur,\n\t\tonDoubleClick,\n\t\tonChange,\n\t\tonPaste,\n\t\tonKeyDown,\n\t\teditor,\n\t\tshapeId,\n\t\thasCustomTabBehavior,\n\t])\n\n\tif (!isEditing || !tipTapConfig) {\n\t\treturn null\n\t}\n\n\treturn (\n\t\t<div\n\t\t\tid={tipTapId}\n\t\t\tref={ref}\n\t\t\ttabIndex={-1}\n\t\t\tdata-testid=\"rich-text-area\"\n\t\t\tclassName=\"tl-rich-text tl-text tl-text-input\"\n\t\t\tonContextMenu={isEditing ? (e) => e.stopPropagation() : undefined}\n\t\t\t// N.B. When PointerStateExtension was introduced, this was moved there.\n\t\t\t// However, that caused selecting over list items to break.\n\t\t\t// The handleDOMEvents in TipTap don't seem to support the pointerDownCapture event.\n\t\t\tonPointerDownCapture={(e) => e.stopPropagation()}\n\t\t\t// This onTouchEnd is important for Android to be able to change selection on text.\n\t\t\tonTouchEnd={(e) => e.stopPropagation()}\n\t\t\t// On FF, there's a behavior where dragging a selection will grab that selection into\n\t\t\t// the drag event. However, once the drag is over, and you select away from the textarea,\n\t\t\t// starting a drag over the textarea will restart a selection drag instead of a shape drag.\n\t\t\t// This prevents that default behavior in FF.\n\t\t\tonDragStart={preventDefault}\n\t\t>\n\t\t\t<div className=\"tl-rich-text\" ref={rTextEditorEl} />\n\t\t</div>\n\t)\n})\n\n// Prevent exiting the editor when hitting Tab.\n// Also, insert a tab character at the front of the line if the shift key isn't pressed,\n// otherwise if shift is pressed, remove a tab character from the front of the line.\nfunction handleTab(editor: Editor, view: EditorView, event: KeyboardEvent) {\n\t// Don't exit the editor.\n\tevent.preventDefault()\n\n\tconst textEditor = editor.getRichTextEditor()\n\tif (textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList')) return\n\n\tconst { state, dispatch } = view\n\tconst { $from, $to } = state.selection\n\tconst isShift = event.shiftKey\n\n\t// Create a new transaction\n\tlet tr = state.tr\n\n\t// Iterate over each line in the selection in reverse so that the positions\n\t// are stable as we modify the document.\n\tlet pos = $to.end()\n\twhile (pos >= $from.start()) {\n\t\tconst line = state.doc.resolve(pos).blockRange()\n\t\tif (!line) break\n\n\t\tconst lineStart = line.start\n\t\tconst lineEnd = line.end\n\t\tconst lineText = state.doc.textBetween(lineStart, lineEnd, '\\n')\n\n\t\t// Check if the current line or any of its parent nodes are part of a list\n\t\tlet isInList = false\n\t\tstate.doc.nodesBetween(lineStart, lineEnd, (node) => {\n\t\t\tif (node.type.name === 'bulletList' || node.type.name === 'orderedList') {\n\t\t\t\tisInList = true\n\t\t\t\treturn false // Stop iteration\n\t\t\t}\n\t\t})\n\n\t\t// TODO: for now skip over lists. Later, we might consider handling them using\n\t\t// sinkListItem and liftListItem from @tiptap/pm/schema-list\n\t\tif (!isInList) {\n\t\t\tif (!isShift) {\n\t\t\t\t// Insert a tab character at the start of the line\n\t\t\t\ttr = tr.insertText('\\t', lineStart + 1)\n\t\t\t} else {\n\t\t\t\t// Remove a tab character from the start of the line\n\t\t\t\tif (lineText.startsWith('\\t')) {\n\t\t\t\t\ttr = tr.delete(lineStart + 1, lineStart + 2)\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tpos = lineStart - 1\n\t}\n\n\tconst mappedSelection = state.selection.map(tr.doc, tr.mapping)\n\ttr.setSelection(mappedSelection)\n\n\tif (tr.docChanged) {\n\t\tdispatch(tr)\n\t}\n}\n"],
5
+ "mappings": "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",
6
6
  "names": ["import_react", "React", "RichTextArea", "TextEditor"]
7
7
  }
@@ -108,7 +108,7 @@ class TextShapeUtil extends import_editor.ShapeUtil {
108
108
  align: textAlign,
109
109
  verticalAlign: "middle",
110
110
  richText,
111
- labelColor: theme[color].solid,
111
+ labelColor: (0, import_editor.getColorValue)(theme, color, "solid"),
112
112
  isSelected,
113
113
  textWidth: width,
114
114
  textHeight: height,
@@ -141,7 +141,7 @@ class TextShapeUtil extends import_editor.ShapeUtil {
141
141
  align: shape.props.textAlign,
142
142
  verticalAlign: "middle",
143
143
  richText: shape.props.richText,
144
- labelColor: theme[shape.props.color].solid,
144
+ labelColor: (0, import_editor.getColorValue)(theme, shape.props.color, "solid"),
145
145
  bounds: exportBounds,
146
146
  padding: 0
147
147
  }