tldraw 5.4.0-next.ebc95cf01337 → 5.4.0

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 (284) hide show
  1. package/DOCS.md +2826 -3226
  2. package/RELEASE_NOTES.md +190 -2
  3. package/dist-cjs/index.js +1 -1
  4. package/dist-cjs/lib/defaultExternalContentHandlers.js +30 -14
  5. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  6. package/dist-cjs/lib/shapes/arrow/curved-arrow.js +2 -2
  7. package/dist-cjs/lib/shapes/arrow/curved-arrow.js.map +2 -2
  8. package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js +2 -2
  9. package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js.map +2 -2
  10. package/dist-cjs/lib/shapes/arrow/getArrowInfo.js +1 -1
  11. package/dist-cjs/lib/shapes/arrow/getArrowInfo.js.map +2 -2
  12. package/dist-cjs/lib/shapes/arrow/straight-arrow.js +2 -2
  13. package/dist-cjs/lib/shapes/arrow/straight-arrow.js.map +2 -2
  14. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js +2 -3
  15. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js.map +2 -2
  16. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +7 -5
  17. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  18. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +8 -6
  19. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
  20. package/dist-cjs/lib/shapes/geo/getGeoShapePath.js +3 -1
  21. package/dist-cjs/lib/shapes/geo/getGeoShapePath.js.map +2 -2
  22. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js +2 -3
  23. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js.map +2 -2
  24. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +1 -1
  25. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
  26. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +2 -6
  27. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
  28. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +4 -4
  29. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  30. package/dist-cjs/lib/shapes/note/noteHelpers.js +6 -5
  31. package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
  32. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +1 -1
  33. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
  34. package/dist-cjs/lib/shapes/shared/crop.js +1 -1
  35. package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
  36. package/dist-cjs/lib/shapes/text/toolStates/Idle.js +1 -1
  37. package/dist-cjs/lib/shapes/text/toolStates/Idle.js.map +2 -2
  38. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +1 -0
  39. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
  40. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +3 -2
  41. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +2 -2
  42. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +2 -0
  43. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  44. package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +6 -0
  45. package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +2 -2
  46. package/dist-cjs/lib/tools/SelectTool/SelectTool.js +3 -0
  47. package/dist-cjs/lib/tools/SelectTool/SelectTool.js.map +2 -2
  48. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js +1 -0
  49. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +2 -2
  50. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js +1 -0
  51. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js.map +2 -2
  52. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +1 -3
  53. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  54. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +6 -3
  55. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  56. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js +1 -1
  57. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
  58. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js +3 -0
  59. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js.map +2 -2
  60. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js +1 -0
  61. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +2 -2
  62. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +1 -1
  63. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
  64. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +22 -30
  65. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  66. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js +1 -3
  67. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +2 -2
  68. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +4 -1
  69. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  70. package/dist-cjs/lib/tools/SelectTool/selectHelpers.js +10 -0
  71. package/dist-cjs/lib/tools/SelectTool/selectHelpers.js.map +2 -2
  72. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js +1 -8
  73. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenu.js.map +2 -2
  74. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +6 -1
  75. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
  76. package/dist-cjs/lib/ui/components/Dialogs.js +8 -0
  77. package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
  78. package/dist-cjs/lib/ui/components/EditLinkDialog.js +5 -5
  79. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
  80. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +4 -20
  81. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  82. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js +2 -0
  83. package/dist-cjs/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.js.map +2 -2
  84. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js +1 -0
  85. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  86. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js +10 -8
  87. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbarContent.js.map +2 -2
  88. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +20 -1
  89. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  90. package/dist-cjs/lib/ui/context/actions.js +8 -7
  91. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  92. package/dist-cjs/lib/ui/hooks/useCommentingEnabled.js +1 -1
  93. package/dist-cjs/lib/ui/hooks/useCommentingEnabled.js.map +2 -2
  94. package/dist-cjs/lib/ui/version.js +3 -3
  95. package/dist-cjs/lib/ui/version.js.map +1 -1
  96. package/dist-esm/index.mjs +1 -1
  97. package/dist-esm/lib/defaultExternalContentHandlers.mjs +30 -14
  98. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  99. package/dist-esm/lib/shapes/arrow/curved-arrow.mjs +2 -2
  100. package/dist-esm/lib/shapes/arrow/curved-arrow.mjs.map +2 -2
  101. package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs +2 -2
  102. package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs.map +2 -2
  103. package/dist-esm/lib/shapes/arrow/getArrowInfo.mjs +1 -1
  104. package/dist-esm/lib/shapes/arrow/getArrowInfo.mjs.map +2 -2
  105. package/dist-esm/lib/shapes/arrow/straight-arrow.mjs +2 -2
  106. package/dist-esm/lib/shapes/arrow/straight-arrow.mjs.map +2 -2
  107. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs +3 -4
  108. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs.map +2 -2
  109. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +7 -5
  110. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  111. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +8 -6
  112. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
  113. package/dist-esm/lib/shapes/geo/getGeoShapePath.mjs +3 -1
  114. package/dist-esm/lib/shapes/geo/getGeoShapePath.mjs.map +2 -2
  115. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs +3 -4
  116. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs.map +2 -2
  117. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +1 -1
  118. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
  119. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +2 -7
  120. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
  121. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +4 -4
  122. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  123. package/dist-esm/lib/shapes/note/noteHelpers.mjs +6 -5
  124. package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
  125. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +1 -1
  126. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
  127. package/dist-esm/lib/shapes/shared/crop.mjs +1 -1
  128. package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
  129. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs +2 -2
  130. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs.map +2 -2
  131. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +1 -0
  132. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
  133. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +3 -2
  134. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +2 -2
  135. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +2 -0
  136. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  137. package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +6 -0
  138. package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +2 -2
  139. package/dist-esm/lib/tools/SelectTool/SelectTool.mjs +3 -0
  140. package/dist-esm/lib/tools/SelectTool/SelectTool.mjs.map +2 -2
  141. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs +1 -0
  142. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +2 -2
  143. package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs +1 -0
  144. package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs.map +2 -2
  145. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +1 -3
  146. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  147. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +6 -3
  148. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  149. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs +1 -1
  150. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
  151. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs +3 -0
  152. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs.map +2 -2
  153. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +5 -1
  154. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +2 -2
  155. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +1 -1
  156. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
  157. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +22 -31
  158. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  159. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs +1 -3
  160. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +2 -2
  161. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +4 -1
  162. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  163. package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs +10 -0
  164. package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs.map +2 -2
  165. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs +1 -8
  166. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenu.mjs.map +2 -2
  167. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +7 -2
  168. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
  169. package/dist-esm/lib/ui/components/Dialogs.mjs +9 -1
  170. package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
  171. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +5 -5
  172. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
  173. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +5 -22
  174. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  175. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs +2 -0
  176. package/dist-esm/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.mjs.map +2 -2
  177. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs +1 -0
  178. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  179. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs +10 -8
  180. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbarContent.mjs.map +2 -2
  181. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +20 -1
  182. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  183. package/dist-esm/lib/ui/context/actions.mjs +8 -7
  184. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  185. package/dist-esm/lib/ui/hooks/useCommentingEnabled.mjs +2 -2
  186. package/dist-esm/lib/ui/hooks/useCommentingEnabled.mjs.map +2 -2
  187. package/dist-esm/lib/ui/version.mjs +3 -3
  188. package/dist-esm/lib/ui/version.mjs.map +1 -1
  189. package/package.json +12 -6
  190. package/src/lib/defaultExternalContentHandlers.test.ts +43 -0
  191. package/src/lib/defaultExternalContentHandlers.ts +38 -16
  192. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +17 -0
  193. package/src/lib/shapes/arrow/curved-arrow.ts +2 -2
  194. package/src/lib/shapes/arrow/elbow/getElbowArrowInfo.tsx +5 -3
  195. package/src/lib/shapes/arrow/getArrowInfo.ts +2 -1
  196. package/src/lib/shapes/arrow/straight-arrow.ts +2 -2
  197. package/src/lib/shapes/arrow/toolStates/Idle.tsx +3 -4
  198. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +10 -6
  199. package/src/lib/shapes/draw/DrawShapeTool.test.ts +19 -0
  200. package/src/lib/shapes/draw/toolStates/Drawing.ts +12 -6
  201. package/src/lib/shapes/frame/FrameShapeTool.test.ts +17 -0
  202. package/src/lib/shapes/geo/GeoShapeTool.test.ts +28 -0
  203. package/src/lib/shapes/geo/getGeoShapePath.ts +3 -1
  204. package/src/lib/shapes/geo/toolStates/Idle.ts +3 -4
  205. package/src/lib/shapes/geo/toolStates/Pointing.ts +2 -1
  206. package/src/lib/shapes/line/LineShapeTool.test.ts +30 -1
  207. package/src/lib/shapes/line/toolStates/Pointing.ts +6 -7
  208. package/src/lib/shapes/note/NoteShapeTool.test.ts +45 -0
  209. package/src/lib/shapes/note/NoteShapeUtil.tsx +7 -4
  210. package/src/lib/shapes/note/noteHelpers.ts +18 -8
  211. package/src/lib/shapes/note/toolStates/Pointing.ts +2 -1
  212. package/src/lib/shapes/shared/crop.ts +7 -1
  213. package/src/lib/shapes/text/TextShapeTool.test.ts +33 -0
  214. package/src/lib/shapes/text/toolStates/Idle.ts +2 -2
  215. package/src/lib/shapes/text/toolStates/Pointing.ts +3 -0
  216. package/src/lib/shapes/video/VideoShapeUtil.tsx +4 -2
  217. package/src/lib/tools/EraserTool/childStates/Erasing.ts +5 -0
  218. package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +10 -0
  219. package/src/lib/tools/SelectTool/SelectTool.ts +4 -0
  220. package/src/lib/tools/SelectTool/childStates/Brushing.ts +4 -0
  221. package/src/lib/tools/SelectTool/childStates/Crop/Crop.ts +4 -0
  222. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +3 -4
  223. package/src/lib/tools/SelectTool/childStates/Idle.ts +10 -3
  224. package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +1 -1
  225. package/src/lib/tools/SelectTool/childStates/PointingCanvas.ts +4 -0
  226. package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +6 -1
  227. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +4 -1
  228. package/src/lib/tools/SelectTool/childStates/Resizing.ts +30 -33
  229. package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +3 -3
  230. package/src/lib/tools/SelectTool/childStates/Translating.ts +6 -0
  231. package/src/lib/tools/SelectTool/selectHelpers.ts +21 -0
  232. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenu.tsx +3 -9
  233. package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +8 -2
  234. package/src/lib/ui/components/Dialogs.tsx +17 -1
  235. package/src/lib/ui/components/EditLinkDialog.tsx +8 -7
  236. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +5 -23
  237. package/src/lib/ui/components/StylePanel/StylePanelDoubleDropdownPicker.tsx +2 -0
  238. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +1 -0
  239. package/src/lib/ui/components/Toolbar/DefaultImageToolbarContent.tsx +13 -8
  240. package/src/lib/ui/components/primitives/TldrawUiSlider.test.tsx +92 -0
  241. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +25 -1
  242. package/src/lib/ui/context/actions.tsx +25 -7
  243. package/src/lib/ui/hooks/useCommentingEnabled.ts +5 -3
  244. package/src/lib/ui/version.ts +3 -3
  245. package/src/test/ClickManager.test.ts +18 -0
  246. package/src/test/Editor.test.tsx +3 -0
  247. package/src/test/EraserTool.test.ts +18 -2
  248. package/src/test/HandTool.test.ts +21 -0
  249. package/src/test/LaserTool.test.ts +46 -0
  250. package/src/test/ScribbleManager.test.ts +19 -0
  251. package/src/test/SelectTool.test.ts +110 -0
  252. package/src/test/TldrawEditor.test.tsx +18 -0
  253. package/src/test/VideoShapeUtil.test.tsx +126 -0
  254. package/src/test/actions-menu-readonly.test.tsx +37 -0
  255. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +6 -6
  256. package/src/test/commands/lockShapes.test.ts +11 -0
  257. package/src/test/commands/packShapes.test.ts +20 -0
  258. package/src/test/commands/putContent.test.ts +35 -1
  259. package/src/test/commands/setCamera.test.ts +69 -0
  260. package/src/test/commands/stackShapes.test.ts +12 -0
  261. package/src/test/commands/updateViewportPageBounds.test.ts +8 -0
  262. package/src/test/cropping.test.ts +162 -0
  263. package/src/test/customSnapping.test.tsx +32 -0
  264. package/src/test/defaultHandleExternalFileContent.test.ts +86 -0
  265. package/src/test/drawing.test.ts +60 -1
  266. package/src/test/duplicate.test.ts +22 -0
  267. package/src/test/frames.test.ts +51 -0
  268. package/src/test/getShapeAtPoint.test.ts +44 -1
  269. package/src/test/handleDeepLink.test.tsx +15 -0
  270. package/src/test/minimap-wheel.test.tsx +48 -0
  271. package/src/test/resizing.test.ts +46 -0
  272. package/src/test/selection-omnibus.test.ts +50 -0
  273. package/src/test/spacebarPanning.test.ts +58 -0
  274. package/src/test/translating.test.ts +42 -0
  275. package/src/test/ui/AltTextEditor.test.tsx +51 -0
  276. package/src/test/ui/ContextMenu.test.tsx +61 -2
  277. package/src/test/ui/EditLinkDialog.test.tsx +77 -0
  278. package/src/test/ui/ImageToolbar.test.tsx +58 -0
  279. package/src/test/ui/StylePanel.test.tsx +33 -2
  280. package/src/test/ui/keyboardShortcuts.test.tsx +27 -0
  281. package/src/test/ui/presenceActivity.test.tsx +44 -0
  282. package/src/test/ui/unlockAll.test.tsx +55 -0
  283. package/src/test/ui-outside-editor.test.tsx +74 -0
  284. package/src/test/viewport-following.test.ts +29 -1
package/RELEASE_NOTES.md CHANGED
@@ -1,9 +1,178 @@
1
1
  # Releases
2
2
 
3
- Version: `5.4.0-next.ebc95cf01337`
3
+ Version: `5.4.0`
4
4
 
5
5
  This file is generated during package publishing from the tldraw release notes content for this exact package version.
6
6
 
7
+ ## v5.4.0
8
+
9
+ This release adds a `center` operation to `Editor.alignShapes`, a `tleditors` registry of mounted editors, `iterateGraphemes` to `@tldraw/utils`, and two new reactive methods on `AtomMap`. It also deprecates `useViewportHeight`, speeds up the signals and store layers, and lands a broad reliability pass across the SDK, with over a hundred fixes to undo history, selection and tool interactions, cropping, arrows, the signals and store layers, sync, and local persistence.
10
+
11
+ ### API changes
12
+
13
+ - 🔜 **`useViewportHeight()`** is deprecated. Read `window.visualViewport` directly instead. The hook returns only the visible viewport's bottom edge, and keeping a panel clear of the software keyboard generally needs the whole visible rectangle. ([#9826](https://github.com/tldraw/tldraw/pull/9826))
14
+ - Add `'center'` as an `Editor.alignShapes` operation. It applies the existing `'center-horizontal'` and `'center-vertical'` operations together, so shapes center on both axes in one command. ([#9074](https://github.com/tldraw/tldraw/pull/9074))
15
+ - Add `tleditors`, a reactive global registry of currently mounted editors. Use it to reach live editors from outside the React tree, for example from sidebar chrome or a keyboard shortcut handler. ([#9904](https://github.com/tldraw/tldraw/pull/9904))
16
+
17
+ ```tsx
18
+ import { tleditors, useValue } from 'tldraw'
19
+
20
+ const mounted = useValue('mounted editors', () => tleditors.getMounted(), [])
21
+ ```
22
+
23
+ - Add `getOrInsert(key, defaultValue)` and `getOrInsertComputed(key, callback)` to `AtomMap`, matching the `Map` methods added in newer JavaScript runtimes. Both are reactive, and the callback only runs when the key is absent. ([#9752](https://github.com/tldraw/tldraw/pull/9752))
24
+ - Add `isPage(record)` to `@tldraw/tlschema`, a type guard that narrows an unknown record to `TLPage`, matching the guards already exported for the other record types. ([#9774](https://github.com/tldraw/tldraw/pull/9774))
25
+ - Add `iterateGraphemes(str)` to `@tldraw/utils`. It iterates a string's grapheme clusters, using `Intl.Segmenter` when it's available and falling back to code-point iteration when it isn't. ([#9896](https://github.com/tldraw/tldraw/pull/9896))
26
+ - `EmojiPickerProps.onSelect` now receives the originating event as an optional second argument. Custom reaction palettes can forward it to opt into shift multi-select. ([#9999](https://github.com/tldraw/tldraw/pull/9999))
27
+
28
+ ### Improvements
29
+
30
+ - Shift-click an emoji in a comment's reaction palette to add several reactions without the palette closing. A plain click still applies the reaction and closes the palette. ([#9999](https://github.com/tldraw/tldraw/pull/9999))
31
+ - Keyboard input now counts as collaborator presence activity, so peers no longer fade out and disappear while someone is typing. ([#9929](https://github.com/tldraw/tldraw/pull/9929))
32
+ - Reduce per-pointer-event allocations in `Group2d` and `Editor` hit-testing. ([#8600](https://github.com/tldraw/tldraw/pull/8600))
33
+ - Speed up signal reads in `@tldraw/state`. Capturing a parent used to scan the capturing signal's parent set twice, once to check for the parent and again to add it. ([#9690](https://github.com/tldraw/tldraw/pull/9690))
34
+ - Reduce per-signal memory use and per-flush allocations in `@tldraw/state`. ([#10155](https://github.com/tldraw/tldraw/pull/10155))
35
+ - Reduce the work and allocations in `@tldraw/store` history bookkeeping, so squashing record diffs and filtering query history no longer build intermediate copies on every tick. ([#9689](https://github.com/tldraw/tldraw/pull/9689), [#9869](https://github.com/tldraw/tldraw/pull/9869))
36
+ - Move the `exportBackground` default (`true`) into the `TLInstance` record type in `@tldraw/tlschema`, so every code path that creates the instance record gets the same value. ([#10534](https://github.com/tldraw/tldraw/pull/10534))
37
+
38
+ ### Bug fixes
39
+
40
+ #### Crashes
41
+
42
+ - Fix the editor failing to load on older browsers that lack `Intl.Segmenter`, such as Firefox before 125. ([#9896](https://github.com/tldraw/tldraw/pull/9896))
43
+ - Fix the frame loop stopping permanently when a `tick` or `frame` listener threw, which silently disabled camera animations, edge scrolling, and other frame-driven behavior for the rest of the session. ([#9946](https://github.com/tldraw/tldraw/pull/9946))
44
+ - Fix a crash when computing a frame's geometry if its heading text couldn't be measured yet. ([#9496](https://github.com/tldraw/tldraw/pull/9496))
45
+ - Fix a crash in hit testing when a custom frame-like shape uses a plain, non-group geometry. ([#10328](https://github.com/tldraw/tldraw/pull/10328))
46
+ - Fix a crash when pressing Enter with a frame, video, or embed selected while the geo, arrow, or text tool is active. ([#10195](https://github.com/tldraw/tldraw/pull/10195))
47
+ - Fix default UI components such as `DefaultToolbar` crashing when mounted outside the `Tldraw` component. ([#10007](https://github.com/tldraw/tldraw/pull/10007))
48
+
49
+ #### Undo and history
50
+
51
+ - Fix undo after a cut also reverting the change made before it. ([#9920](https://github.com/tldraw/tldraw/pull/9920))
52
+ - Fix several actions merging into the previous undo step instead of creating their own: **Unlock all**, changing an arrowhead, keyboard changes to the opacity and image zoom sliders, alt+double-clicking a rectangle into a check-box, saving alt text, and dropping a file or url onto the canvas. ([#10468](https://github.com/tldraw/tldraw/pull/10468), [#10469](https://github.com/tldraw/tldraw/pull/10469), [#10470](https://github.com/tldraw/tldraw/pull/10470), [#10473](https://github.com/tldraw/tldraw/pull/10473), [#10474](https://github.com/tldraw/tldraw/pull/10474), [#10478](https://github.com/tldraw/tldraw/pull/10478))
53
+ - Fix exiting an empty text shape leaving a phantom undo entry: document changes made by `onEditEnd` are now recorded in history. ([#10369](https://github.com/tldraw/tldraw/pull/10369))
54
+ - Fix undo after `bailToMark` removing records that were not part of the undone change. ([#10207](https://github.com/tldraw/tldraw/pull/10207))
55
+ - Fix undo/redo not removing an optional record property that the change had deleted. ([#10215](https://github.com/tldraw/tldraw/pull/10215))
56
+ - Fix collaboration-mode readonly syncs ending up in the user's undo history. ([#10372](https://github.com/tldraw/tldraw/pull/10372))
57
+ - Fix changes made by `operationComplete` handlers after a remote merge being attributed to the remote source. ([#10229](https://github.com/tldraw/tldraw/pull/10229))
58
+
59
+ #### Selection and tools
60
+
61
+ - Fix Escape being ignored while pressing on the canvas with the select tool. ([#10175](https://github.com/tldraw/tldraw/pull/10175))
62
+ - Fix Escape during a scribble selection dropping the prior selection. ([#10489](https://github.com/tldraw/tldraw/pull/10489))
63
+ - Fix Space+arrow and Alt+arrow also nudging the selected shapes. ([#10453](https://github.com/tldraw/tldraw/pull/10453))
64
+ - Fix Alt not suppressing Shift/Ctrl additive selection when releasing the pointer over a selected shape. ([#10510](https://github.com/tldraw/tldraw/pull/10510))
65
+ - Fix bookmarks and other non-resizable shapes being left behind when resizing a multi-selection. ([#10491](https://github.com/tldraw/tldraw/pull/10491))
66
+ - Fix alt-cloning mid-drag reparenting the original shape instead of the clone when dropping into a frame. ([#10186](https://github.com/tldraw/tldraw/pull/10186))
67
+ - Fix the cursor staying as a resize or rotate arrow when Ctrl/Cmd+dragging a selection handle to brush-select. ([#10487](https://github.com/tldraw/tldraw/pull/10487))
68
+ - Fix handle snapping on rotated shapes landing off the snap target. ([#10168](https://github.com/tldraw/tldraw/pull/10168))
69
+ - Fix an interrupted press with the geo, frame, or note tool (undo, opening a menu, or changing page before releasing) creating a default-size shape. ([#10506](https://github.com/tldraw/tldraw/pull/10506))
70
+ - Fix an invisible empty text shape being left behind when switching tools while dragging out a text box. ([#10457](https://github.com/tldraw/tldraw/pull/10457))
71
+ - Fix the text tool undoing earlier work when cancelling a pointer-down after a drag-created text shape. ([#10194](https://github.com/tldraw/tldraw/pull/10194))
72
+ - Fix shift-click with the draw, highlight, and line tools editing a shape on the previous page after a page change. ([#10455](https://github.com/tldraw/tldraw/pull/10455))
73
+ - Fix the draw tool's shift segment threshold depending on the zoom level. ([#10240](https://github.com/tldraw/tldraw/pull/10240))
74
+ - Fix the first point of a pen stroke losing its pressure value. ([#10243](https://github.com/tldraw/tldraw/pull/10243))
75
+ - Fix small, slowly drawn loops sometimes failing to close, because dense input sampling made the stroke measure shorter than it was. ([#9930](https://github.com/tldraw/tldraw/pull/9930))
76
+ - Fix the eraser dropping a frame it was pressed on once the drag begins. ([#10507](https://github.com/tldraw/tldraw/pull/10507))
77
+ - Fix a camera jump when a second finger touches down during a one-finger zoom with the hand tool. ([#10178](https://github.com/tldraw/tldraw/pull/10178))
78
+ - Fix Escape ending a spacebar pan while Space is still held. ([#10504](https://github.com/tldraw/tldraw/pull/10504))
79
+ - Fix tools whose `onEnter` transitions to a child state ending up with two active children. ([#10354](https://github.com/tldraw/tldraw/pull/10354))
80
+ - Fix double clicks being cancelled by small pointer movements when the editor container is offset from the page origin. ([#10349](https://github.com/tldraw/tldraw/pull/10349))
81
+ - Fix modifier keys (Shift, Alt, Ctrl, Cmd) briefly being treated as held at the start of a new click or drag right after being released, which could momentarily affect snapping and other modifier-dependent behavior. ([#9523](https://github.com/tldraw/tldraw/pull/9523))
82
+ - Fix held keys, including Space panning, staying active after the window loses focus. ([#10500](https://github.com/tldraw/tldraw/pull/10500))
83
+
84
+ #### Cropping
85
+
86
+ - Fix stale crop state after leaving crop mode by switching tools. ([#10167](https://github.com/tldraw/tldraw/pull/10167))
87
+ - Fix Escape during a crop drag reverting the whole crop session instead of only the drag in progress. ([#10462](https://github.com/tldraw/tldraw/pull/10462))
88
+ - Fix Escape in image crop mode clearing the selection. ([#10463](https://github.com/tldraw/tldraw/pull/10463))
89
+ - Fix crop mode staying active when the cropping shape is deleted. ([#10370](https://github.com/tldraw/tldraw/pull/10370))
90
+ - Fix pressing Enter on a selected image entering crop mode in a readonly editor. ([#10492](https://github.com/tldraw/tldraw/pull/10492))
91
+
92
+ #### Arrows and shapes
93
+
94
+ - Fix arrows bound to custom shapes with non-standard `size` values rendering as `NaN`. ([#10214](https://github.com/tldraw/tldraw/pull/10214))
95
+ - Fix elbow arrows with a free terminal sometimes routing through the bound shape. ([#10219](https://github.com/tldraw/tldraw/pull/10219))
96
+ - Fix arrow geometry ignoring a custom stroke width from `getCustomDisplayValues`. ([#10230](https://github.com/tldraw/tldraw/pull/10230))
97
+ - Fix the arrow binding target highlight staying visible after clicking an arrow handle without dragging. ([#10191](https://github.com/tldraw/tldraw/pull/10191))
98
+ - Fix a stub arrow being left on the canvas when switching tools during an arrow press. ([#10461](https://github.com/tldraw/tldraw/pull/10461))
99
+ - Fix arrow label drag reverting when a menu opens or undo is pressed mid-drag. ([#10493](https://github.com/tldraw/tldraw/pull/10493))
100
+ - Fix Cmd+Enter / Tab on a note creating a duplicate on top of an existing neighbour. ([#10199](https://github.com/tldraw/tldraw/pull/10199))
101
+ - Fix adjacent-note snapping under a scaled, grown note. ([#10204](https://github.com/tldraw/tldraw/pull/10204))
102
+ - Fix the note tool not snapping a new note beside the note it just created when tool lock is on. ([#10484](https://github.com/tldraw/tldraw/pull/10484))
103
+ - Fix attributed notes losing their font in exports. ([#10249](https://github.com/tldraw/tldraw/pull/10249))
104
+ - Fix shift-extending a line inside a rotated frame placing the point incorrectly. ([#10238](https://github.com/tldraw/tldraw/pull/10238))
105
+ - Fix the second diagonal of an x-box shape being treated as an outer edge. ([#10245](https://github.com/tldraw/tldraw/pull/10245))
106
+ - Fix a replaced image being zoomed when the original had an explicit default crop. ([#10234](https://github.com/tldraw/tldraw/pull/10234))
107
+ - Fix video shapes showing a floating spinner with no bounding box while their asset uploads or loads. They now show the same loading plate as image shapes. ([#9994](https://github.com/tldraw/tldraw/pull/9994))
108
+ - Fix **Flatten to image** producing different groupings depending on selection order, and not merging clusters that were only connected through a bridging shape. ([#8661](https://github.com/tldraw/tldraw/pull/8661))
109
+
110
+ #### Editor
111
+
112
+ - Fix dragging a frame out of its parent when grabbed over a nested child, and restore a child's original z-order when dragged back into a frame. ([#10329](https://github.com/tldraw/tldraw/pull/10329))
113
+ - Fix camera constraints for bounds away from the page origin, and clamp padding against the correct viewport axis. ([#10337](https://github.com/tldraw/tldraw/pull/10337))
114
+ - Fix `setCameraOptions({ zoomSteps: undefined })` breaking every later camera move. ([#10387](https://github.com/tldraw/tldraw/pull/10387))
115
+ - Fix `slideCamera` zoom momentum driving the zoom to zero on a long frame. ([#10388](https://github.com/tldraw/tldraw/pull/10388))
116
+ - Fix malformed viewport deep links moving the camera to the origin instead of falling back to fitting the page content. ([#10508](https://github.com/tldraw/tldraw/pull/10508))
117
+ - Fix following a user whose own leader has left or has no presence yet. ([#10389](https://github.com/tldraw/tldraw/pull/10389))
118
+ - Fix `getSelectionRotatedScreenBounds` going stale when the editor container moves. ([#10390](https://github.com/tldraw/tldraw/pull/10390))
119
+ - Fix `duplicateShapes` throwing on unknown ids and offsetting nested duplicates twice. ([#10355](https://github.com/tldraw/tldraw/pull/10355))
120
+ - Fix `packShapes` packing shapes of different heights into a single column. ([#10381](https://github.com/tldraw/tldraw/pull/10381))
121
+ - Fix `stackShapes` reordering shapes when a gap is given. ([#10383](https://github.com/tldraw/tldraw/pull/10383))
122
+ - Fix nested 270° shapes being dropped from axis-aligned shape clustering. ([#10384](https://github.com/tldraw/tldraw/pull/10384))
123
+ - Fix `putContentOntoCurrentPage` mutating the content passed to it. ([#10367](https://github.com/tldraw/tldraw/pull/10367))
124
+ - Fix `setErasingShapes` mutating its input array, so it accepts store-owned (frozen) arrays. ([#10371](https://github.com/tldraw/tldraw/pull/10371))
125
+ - Fix the teardown returned by the `createTLStore` `onMount` option never running when the editor unmounts. ([#10375](https://github.com/tldraw/tldraw/pull/10375))
126
+ - Fix drop events inside the canvas never reaching React drop handlers, and keep Safari gesture suppression working with multiple editors on a page. ([#10360](https://github.com/tldraw/tldraw/pull/10360))
127
+ - Fix object URLs for locally persisted assets leaking across remounts. ([#10361](https://github.com/tldraw/tldraw/pull/10361))
128
+ - Fix the click-capture overlay staying over the canvas after right-click panning with a menu open. ([#10359](https://github.com/tldraw/tldraw/pull/10359))
129
+ - Fix hiding and showing menus by context id, and tolerate corrupt user-preference data in localStorage. ([#10344](https://github.com/tldraw/tldraw/pull/10344))
130
+ - Fix `Vec.Slope`, `Vec.cross`, and `areAnglesCompatible` for negative angles, `rotateSelectionHandle` for negative rotations, and dotted dash arrays for very short paths. ([#10352](https://github.com/tldraw/tldraw/pull/10352))
131
+ - Fix laser trails staying visible after changing page. ([#10509](https://github.com/tldraw/tldraw/pull/10509))
132
+ - Fix locking a mixed selection of locked and unlocked shapes leaving the shapes selected. ([#10480](https://github.com/tldraw/tldraw/pull/10480))
133
+ - Fix wheel event normalization passing through non-finite delta values. ([#9586](https://github.com/tldraw/tldraw/pull/9586))
134
+
135
+ #### UI
136
+
137
+ - Fix the **Frame selection** shortcut (Ctrl+Alt+G) not working on Windows and Linux. ([#10481](https://github.com/tldraw/tldraw/pull/10481))
138
+ - Fix pasted text shapes and bookmarks not being selected after paste. ([#10485](https://github.com/tldraw/tldraw/pull/10485))
139
+ - Fix context-menu paste landing under the pointer instead of at the right-click point. ([#10488](https://github.com/tldraw/tldraw/pull/10488))
140
+ - Fix file drops and pastes silently doing nothing when one of the files is an image that can't be decoded. The bad file is now skipped with an error toast and the other files are placed. ([#10495](https://github.com/tldraw/tldraw/pull/10495))
141
+ - Fix the **Edit link** dialog staying open as an empty panel when its shape is deleted or deselected. ([#10496](https://github.com/tldraw/tldraw/pull/10496))
142
+ - Fix wheel and trackpad scrolling over the minimap moving the camera at double rate. ([#10499](https://github.com/tldraw/tldraw/pull/10499))
143
+ - Fix the actions menu button appearing, and opening empty, in readonly mode with the hand and zoom tools. ([#10503](https://github.com/tldraw/tldraw/pull/10503))
144
+ - Fix closing a stacked dialog by touch also closing the dialog beneath it. ([#10002](https://github.com/tldraw/tldraw/pull/10002))
145
+ - Fix the loading screen not honoring the system theme on a dark OS, and the reduce motion preference not following the OS setting until a reload. ([#10528](https://github.com/tldraw/tldraw/pull/10528))
146
+ - Fix the storage read-failure alert promising a reload that never happened. ([#10530](https://github.com/tldraw/tldraw/pull/10530))
147
+ - Fix the casing of the error fallback's refresh button. ([#10362](https://github.com/tldraw/tldraw/pull/10362))
148
+ - Fix pasted links showing a broken preview image when the linked page has no Open Graph image. ([#9909](https://github.com/tldraw/tldraw/pull/9909))
149
+ - Fix the counterclockwise rotation tooltip not showing its comma key. ([#9772](https://github.com/tldraw/tldraw/pull/9772))
150
+ - Fix the spacing around the cursor chat item in the context menu. ([#9921](https://github.com/tldraw/tldraw/pull/9921))
151
+ - Fix the people menu's collaborator rows not lining up with your own row above them: the follow icon sat too close to the right edge, and collaborator names sat slightly left of your own. ([#9900](https://github.com/tldraw/tldraw/pull/9900))
152
+ - Fix the comment thread popover briefly rendering with a doubled shadow the first time a thread is opened. ([#9886](https://github.com/tldraw/tldraw/pull/9886))
153
+ #### Persistence, sync, and licensing
154
+
155
+ - Fix edits made in the last 350 ms before closing or reloading a tab being lost from local persistence. ([#10526](https://github.com/tldraw/tldraw/pull/10526))
156
+ - Fix background tabs repeatedly dropping and re-establishing their sync connection when the browser throttles timers. ([#9964](https://github.com/tldraw/tldraw/pull/9964))
157
+ - Fix `useSyncDemo` creating assets for uploads the server rejected. ([#10109](https://github.com/tldraw/tldraw/pull/10109))
158
+ - Fix `loadSnapshot` failing on better-sqlite3, and `NodeSqliteWrapper` getting stuck in a transaction when `COMMIT` fails. ([#10111](https://github.com/tldraw/tldraw/pull/10111), [#10113](https://github.com/tldraw/tldraw/pull/10113))
159
+
160
+ #### Signals and store
161
+
162
+ - Fix computeds returning stale values when read inside a transaction during an effect, from a deferred effect, or after a reactor restarts. ([#10145](https://github.com/tldraw/tldraw/pull/10145))
163
+ - Fix effects with no signal dependencies re-running on every `start()`. ([#10148](https://github.com/tldraw/tldraw/pull/10148))
164
+ - Fix nested transactions inside effects not rolling back with their parent. ([#10149](https://github.com/tldraw/tldraw/pull/10149))
165
+ - Fix effects observing half-restored state when a `deferAsyncEffects` call throws. ([#10150](https://github.com/tldraw/tldraw/pull/10150))
166
+ - Fix `@computed` on a subclass override that calls `super`, and `@computed()` with no arguments. ([#10151](https://github.com/tldraw/tldraw/pull/10151))
167
+ - Fix computeds re-running their compute function on every read after their first derive throws. ([#10152](https://github.com/tldraw/tldraw/pull/10152))
168
+ - Fix computeds read inside an atom's `computeDiff` never seeing that change, and an explicit `null` diff passed to `atom.set()` or returned from `withDiff()` clearing history. ([#10153](https://github.com/tldraw/tldraw/pull/10153))
169
+ - Fix `localStorageAtom` throwing outside the browser. ([#10154](https://github.com/tldraw/tldraw/pull/10154))
170
+ - Fix a stack overflow in `ImmutableMap` and `AtomMap` for keys named after `Object.prototype` members, and make `NaN` and `-0` key equality match native `Map`. ([#10202](https://github.com/tldraw/tldraw/pull/10202))
171
+ - Fix `AtomMap` throwing when an entry is deleted mid-iteration. ([#10209](https://github.com/tldraw/tldraw/pull/10209))
172
+ - Fix `StoreSchema.create` reporting a redundant migration dependency as circular. ([#10213](https://github.com/tldraw/tldraw/pull/10213))
173
+ - Fix the `store.query.ids()` query creator being called with a computed's `(previousValue, epoch)` arguments. ([#10218](https://github.com/tldraw/tldraw/pull/10218))
174
+ - Fix `CollectionDiff`s from `store.query.ids()` and `index()` containing an empty `added` or `removed` set after an add/remove round trip. ([#10221](https://github.com/tldraw/tldraw/pull/10221))
175
+
7
176
  ## v5.3.0
8
177
 
9
178
  [View on GitHub](https://github.com/tldraw/tldraw/releases/tag/v5.3.0)
@@ -94,6 +263,25 @@ See the [commenting docs](https://tldraw.dev/docs/commenting) for setup.
94
263
  - Fix a crash when a custom font failed to load after its editor had been disposed. ([#9494](https://github.com/tldraw/tldraw/pull/9494))
95
264
  - Fix license expiry being evaluated in local time, which could deactivate a license a calendar day early for users west of UTC; the expiry date is now treated as the last fully usable day in UTC. ([#9475](https://github.com/tldraw/tldraw/pull/9475))
96
265
 
266
+ ---
267
+
268
+ ### Patch releases
269
+
270
+ #### v5.3.1
271
+
272
+ - Fix touches in part of the canvas being ignored on iOS when the editor was inset from the edge of the page, such as beside a sidebar. ([#9989](https://github.com/tldraw/tldraw/pull/9989))
273
+
274
+ [View release on GitHub](https://github.com/tldraw/tldraw/releases/tag/v5.3.1)
275
+
276
+ #### v5.3.2
277
+
278
+ - Fix default UI components, such as `DefaultToolbar` and `DefaultQuickActionsContent`, crashing when mounted outside the `Tldraw` component. ([#10007](https://github.com/tldraw/tldraw/pull/10007))
279
+ - Fix license validation treating native apps served from custom protocols as development environments. ([#10021](https://github.com/tldraw/tldraw/pull/10021))
280
+ - Fix wildcard license host matching so `*.example.com` matches only that domain's subdomains. ([#10053](https://github.com/tldraw/tldraw/pull/10053))
281
+ - Add product metadata to each published package's `package.json`, so which product or feature a package implements is clearer, and ship the missing `LICENSE.md` files. ([#9977](https://github.com/tldraw/tldraw/pull/9977))
282
+
283
+ [View release on GitHub](https://github.com/tldraw/tldraw/releases/tag/v5.3.2)
284
+
97
285
  ## v5.2.0
98
286
 
99
287
  [View on GitHub](https://github.com/tldraw/tldraw/releases/tag/v5.2.0)
@@ -1345,7 +1533,7 @@ Draw and highlight shape point data is now stored using a compact delta-encoded
1345
1533
  <details>
1346
1534
  <summary>Breaking change details</summary>
1347
1535
 
1348
- If you were reading or writing draw shape data programatically you might need to update your code to use the new format.
1536
+ If you were reading or writing draw shape data programmatically you might need to update your code to use the new format.
1349
1537
 
1350
1538
  - `TLDrawShapeSegment.points` renamed to `.path` and changed from `VecModel[]` to `string` (base64-encoded)
1351
1539
  - Added `scaleX` and `scaleY` properties to draw and highlight shapes
package/dist-cjs/index.js CHANGED
@@ -653,7 +653,7 @@ var import_buildFromV1Document = require("./lib/utils/tldr/buildFromV1Document")
653
653
  var import_file = require("./lib/utils/tldr/file");
654
654
  (0, import_editor.registerTldrawLibraryVersion)(
655
655
  "tldraw",
656
- "5.4.0-next.ebc95cf01337",
656
+ "5.4.0",
657
657
  "cjs"
658
658
  );
659
659
  //# sourceMappingURL=index.js.map
@@ -282,7 +282,17 @@ async function defaultHandleExternalFileContent(editor, { point, files }, option
282
282
  });
283
283
  continue;
284
284
  }
285
- const assetInfo = await getAssetInfo(editor, sanitizedFile);
285
+ let assetInfo;
286
+ try {
287
+ assetInfo = await getAssetInfo(editor, sanitizedFile);
288
+ } catch (error) {
289
+ toasts.addToast({
290
+ title: msg("assets.files.upload-failed"),
291
+ severity: "error"
292
+ });
293
+ console.error(error);
294
+ continue;
295
+ }
286
296
  if (!assetInfo) continue;
287
297
  if (assetInfo.type === "image") {
288
298
  editor.createTemporaryAssetPreview(assetInfo.id, sanitizedFile);
@@ -363,21 +373,26 @@ async function defaultHandleExternalTextContent(editor, { point, text, html }) {
363
373
  }
364
374
  const newPoint = (0, import_editor.maybeSnapToGrid)(new import_editor.Vec(p.x - w / 2, p.y - h / 2), editor);
365
375
  const shapeId = (0, import_editor.createShapeId)();
366
- editor.createShapes([
367
- {
368
- id: shapeId,
369
- type: "text",
370
- x: newPoint.x,
371
- y: newPoint.y,
372
- props: {
373
- richText: richTextToPaste,
374
- // if the text has more than one line, align it to the left
375
- textAlign: align,
376
- autoSize,
377
- w
376
+ editor.run(() => {
377
+ editor.createShapes([
378
+ {
379
+ id: shapeId,
380
+ type: "text",
381
+ x: newPoint.x,
382
+ y: newPoint.y,
383
+ props: {
384
+ richText: richTextToPaste,
385
+ // if the text has more than one line, align it to the left
386
+ textAlign: align,
387
+ autoSize,
388
+ w
389
+ }
378
390
  }
391
+ ]);
392
+ if (editor.getShape(shapeId)) {
393
+ editor.select(shapeId);
379
394
  }
380
- ]);
395
+ });
381
396
  }
382
397
  async function defaultHandleExternalUrlContent(editor, { point, url }, { toasts, msg }) {
383
398
  if (!import_editor.T.linkUrl.isValid(url)) {
@@ -407,6 +422,7 @@ async function defaultHandleExternalUrlContent(editor, { point, url }, { toasts,
407
422
  });
408
423
  return;
409
424
  }
425
+ editor.select(result.value.id);
410
426
  }
411
427
  async function defaultHandleExternalTldrawContent(editor, { point, content }) {
412
428
  editor.run(() => {
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/defaultExternalContentHandlers.ts"],
4
- "sourcesContent": ["import {\n\tAssetRecordType,\n\tEditor,\n\tT,\n\tTLAsset,\n\tTLAssetId,\n\tTLBookmarkAsset,\n\tTLBookmarkShape,\n\tTLContent,\n\tTLFileExternalAsset,\n\tTLFileReplaceExternalContent,\n\tTLImageAsset,\n\tTLImageShape,\n\tTLShapeId,\n\tTLShapePartial,\n\tTLTextShape,\n\tTLTextShapeProps,\n\tTLUrlExternalAsset,\n\tTLVideoAsset,\n\tVec,\n\tVecLike,\n\tassert,\n\tcreateShapeId,\n\tfetch,\n\tgetHashForBuffer,\n\tgetHashForString,\n\tmaybeSnapToGrid,\n\ttoRichText,\n} from '@tldraw/editor'\nimport { EmbedDefinition } from './defaultEmbedDefinitions'\nimport { createBookmarkFromUrl } from './shapes/bookmark/bookmarks'\nimport { EmbedShapeUtil } from './shapes/embed/EmbedShapeUtil'\nimport { getCroppedImageDataForReplacedImage } from './shapes/shared/crop'\nimport { FONT_SIZES, TEXT_PROPS, getFontFamily } from './shapes/shared/default-shape-constants'\nimport { TLUiToastsContextType } from './ui/context/toasts'\nimport { useTranslation } from './ui/hooks/useTranslation/useTranslation'\nimport { putExcalidrawContent } from './utils/excalidraw/putExcalidrawContent'\nimport { renderHtmlFromRichTextForMeasurement, renderRichTextFromHTML } from './utils/text/richText'\nimport { cleanupText, isRightToLeftLanguage } from './utils/text/text'\n\n/**\n * 5000px\n * @public\n */\nexport const DEFAULT_MAX_IMAGE_DIMENSION = 5000\n/**\n * 10mb\n * @public\n */\nexport const DEFAULT_MAX_ASSET_SIZE = 10 * 1024 * 1024\n\n/** @public */\nexport interface TLExternalContentProps {\n\t/**\n\t * The maximum dimension (width or height) of an image. Images larger than this will be rescaled\n\t * to fit. Defaults to infinity.\n\t */\n\tmaxImageDimension?: number\n\t/**\n\t * The maximum size (in bytes) of an asset. Assets larger than this will be rejected. Defaults\n\t * to 10mb (10 * 1024 * 1024).\n\t */\n\tmaxAssetSize?: number\n\t/**\n\t * The mime types of images that are allowed to be handled. When passed to\n\t * the `Tldraw` component, this also reconfigures the default `ImageAssetUtil`\n\t * to only accept files matching these types. If you only want to accept a\n\t * subset of image types and want to additionally block videos, pass\n\t * `acceptedVideoMimeTypes={[]}`. A file is accepted if its MIME type is in\n\t * this list, in `acceptedVideoMimeTypes`, or if any registered asset util\n\t * accepts it.\n\t */\n\tacceptedImageMimeTypes?: readonly string[]\n\t/**\n\t * The mime types of videos that are allowed to be handled. When passed to\n\t * the `Tldraw` component, this also reconfigures the default `VideoAssetUtil`\n\t * to only accept files matching these types. A file is accepted if its MIME\n\t * type is in this list, in `acceptedImageMimeTypes`, or if any registered\n\t * asset util accepts it.\n\t */\n\tacceptedVideoMimeTypes?: readonly string[]\n}\n\n/** @public */\nexport interface TLDefaultExternalContentHandlerOpts extends TLExternalContentProps {\n\ttoasts: TLUiToastsContextType\n\tmsg: ReturnType<typeof useTranslation>\n}\n\n/** @public */\nexport function registerDefaultExternalContentHandlers(\n\teditor: Editor,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\t// files -> asset\n\teditor.registerExternalAssetHandler('file', async (externalAsset) => {\n\t\treturn defaultHandleExternalFileAsset(editor, externalAsset, options)\n\t})\n\n\t// urls -> bookmark asset\n\teditor.registerExternalAssetHandler('url', async (externalAsset) => {\n\t\treturn defaultHandleExternalUrlAsset(editor, externalAsset, options)\n\t})\n\n\t// svg text\n\teditor.registerExternalContentHandler('svg-text', async (externalContent) => {\n\t\treturn defaultHandleExternalSvgTextContent(editor, externalContent)\n\t})\n\n\t// embeds\n\teditor.registerExternalContentHandler<'embed', EmbedDefinition>('embed', (externalContent) => {\n\t\treturn defaultHandleExternalEmbedContent(editor, externalContent)\n\t})\n\n\t// files\n\teditor.registerExternalContentHandler('files', async (externalContent) => {\n\t\treturn defaultHandleExternalFileContent(editor, externalContent, options)\n\t})\n\n\t// file-replace -> asset\n\teditor.registerExternalContentHandler('file-replace', async (externalContent) => {\n\t\treturn defaultHandleExternalFileReplaceContent(editor, externalContent, options)\n\t})\n\n\t// text\n\teditor.registerExternalContentHandler('text', async (externalContent) => {\n\t\treturn defaultHandleExternalTextContent(editor, externalContent)\n\t})\n\n\t// url\n\teditor.registerExternalContentHandler('url', async (externalContent) => {\n\t\treturn defaultHandleExternalUrlContent(editor, externalContent, options)\n\t})\n\n\t// tldraw\n\teditor.registerExternalContentHandler('tldraw', async (externalContent) => {\n\t\treturn defaultHandleExternalTldrawContent(editor, externalContent)\n\t})\n\n\t// excalidraw\n\teditor.registerExternalContentHandler('excalidraw', async (externalContent) => {\n\t\treturn defaultHandleExternalExcalidrawContent(editor, externalContent)\n\t})\n}\n\n/** @public */\nexport async function defaultHandleExternalFileAsset(\n\teditor: Editor,\n\t{ file, assetId }: TLFileExternalAsset,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst isSuccess = notifyIfFileNotAllowed(editor, file, options)\n\tif (!isSuccess) assert(false, 'File checks failed')\n\n\tconst sanitizedFile = await maybeSanitizeSvgFile(file)\n\tif (!sanitizedFile) assert(false, 'SVG file contained no safe content')\n\tconst assetInfo = await getAssetInfo(editor, sanitizedFile, assetId)\n\tif (!assetInfo) assert(false, `No asset util found for MIME type \"${file.type}\"`)\n\tconst result = await editor.uploadAsset(assetInfo, sanitizedFile)\n\tassetInfo.props.src = result.src\n\tif (result.meta) assetInfo.meta = { ...assetInfo.meta, ...result.meta }\n\n\treturn AssetRecordType.create(assetInfo)\n}\n\n/** @public */\nexport async function defaultHandleExternalFileReplaceContent(\n\teditor: Editor,\n\t{ file, shapeId }: TLFileReplaceExternalContent,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst isSuccess = notifyIfFileNotAllowed(editor, file, options)\n\tif (!isSuccess) assert(false, 'File checks failed')\n\n\tconst sanitizedFile = await maybeSanitizeSvgFile(file)\n\tif (!sanitizedFile) return\n\tconst shape = editor.getShape(shapeId)\n\tif (!shape) assert(false, 'Shape not found')\n\n\tconst hash = getHashForBuffer(await sanitizedFile.arrayBuffer())\n\tconst assetId = AssetRecordType.createId(hash)\n\teditor.createTemporaryAssetPreview(assetId, sanitizedFile)\n\tconst assetInfoPartial = (await getAssetInfo(editor, sanitizedFile, assetId)) as\n\t\t| TLImageAsset\n\t\t| TLVideoAsset\n\t\t| null\n\tif (!assetInfoPartial) return\n\teditor.createAssets([assetInfoPartial])\n\n\t// And update the shape\n\tif (shape.type === 'image') {\n\t\tconst imageShape = shape as TLImageShape\n\t\tconst currentCrop = imageShape.props.crop\n\n\t\t// Calculate new dimensions that preserve the current visual size of the cropped area\n\t\tlet newWidth = assetInfoPartial.props.w\n\t\tlet newHeight = assetInfoPartial.props.h\n\t\tlet newX = imageShape.x\n\t\tlet newY = imageShape.y\n\t\tlet finalCrop = currentCrop\n\n\t\tif (currentCrop) {\n\t\t\t// Use the dedicated function to calculate the new crop and dimensions\n\t\t\tconst result = getCroppedImageDataForReplacedImage(\n\t\t\t\timageShape,\n\t\t\t\tassetInfoPartial.props.w,\n\t\t\t\tassetInfoPartial.props.h\n\t\t\t)\n\n\t\t\tfinalCrop = result.crop\n\t\t\tnewWidth = result.w\n\t\t\tnewHeight = result.h\n\t\t\tnewX = result.x\n\t\t\tnewY = result.y\n\t\t}\n\n\t\teditor.updateShapes([\n\t\t\t{\n\t\t\t\tid: imageShape.id,\n\t\t\t\ttype: imageShape.type,\n\t\t\t\tprops: {\n\t\t\t\t\tassetId: assetId,\n\t\t\t\t\tcrop: finalCrop,\n\t\t\t\t\tw: newWidth,\n\t\t\t\t\th: newHeight,\n\t\t\t\t},\n\t\t\t\tx: newX,\n\t\t\t\ty: newY,\n\t\t\t},\n\t\t])\n\t} else if (shape.type === 'video') {\n\t\teditor.updateShapes([\n\t\t\t{\n\t\t\t\tid: shape.id,\n\t\t\t\ttype: shape.type,\n\t\t\t\tprops: {\n\t\t\t\t\tassetId: assetId,\n\t\t\t\t\tw: assetInfoPartial.props.w,\n\t\t\t\t\th: assetInfoPartial.props.h,\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\t}\n\n\tconst asset = (await editor.getAssetForExternalContent({\n\t\ttype: 'file',\n\t\tfile: sanitizedFile,\n\t\tassetId,\n\t})) as TLAsset\n\n\teditor.updateAssets([{ ...asset, id: assetId }])\n\n\treturn asset\n}\n\n/** @public */\nexport async function defaultHandleExternalUrlAsset(\n\teditor: Editor,\n\t{ url }: TLUrlExternalAsset,\n\t{ toasts, msg }: TLDefaultExternalContentHandlerOpts\n): Promise<TLBookmarkAsset> {\n\tlet meta: { image: string; favicon: string; title: string; description: string }\n\n\ttry {\n\t\tconst resp = await fetch(url, {\n\t\t\tmethod: 'GET',\n\t\t\tmode: 'no-cors',\n\t\t})\n\t\tconst html = await resp.text()\n\t\tconst doc = new DOMParser().parseFromString(html, 'text/html')\n\t\tmeta = {\n\t\t\timage: doc.head.querySelector('meta[property=\"og:image\"]')?.getAttribute('content') ?? '',\n\t\t\tfavicon:\n\t\t\t\tdoc.head.querySelector('link[rel=\"apple-touch-icon\"]')?.getAttribute('href') ??\n\t\t\t\tdoc.head.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ??\n\t\t\t\t'',\n\t\t\ttitle: doc.head.querySelector('meta[property=\"og:title\"]')?.getAttribute('content') ?? url,\n\t\t\tdescription:\n\t\t\t\tdoc.head.querySelector('meta[property=\"og:description\"]')?.getAttribute('content') ?? '',\n\t\t}\n\t\tif (meta.image && !meta.image.startsWith('http')) {\n\t\t\tmeta.image = new URL(meta.image, url).href\n\t\t}\n\t\tif (meta.favicon && !meta.favicon.startsWith('http')) {\n\t\t\tmeta.favicon = new URL(meta.favicon, url).href\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.url.failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\tmeta = { image: '', favicon: '', title: '', description: '' }\n\t}\n\n\t// Create the bookmark asset from the meta\n\treturn {\n\t\tid: AssetRecordType.createId(getHashForString(url)),\n\t\ttypeName: 'asset',\n\t\ttype: 'bookmark',\n\t\tprops: {\n\t\t\tsrc: url,\n\t\t\tdescription: meta.description,\n\t\t\timage: meta.image,\n\t\t\tfavicon: meta.favicon,\n\t\t\ttitle: meta.title,\n\t\t},\n\t\tmeta: {},\n\t} as TLBookmarkAsset\n}\n\n/** @public */\nexport async function defaultHandleExternalSvgTextContent(\n\teditor: Editor,\n\t{ point, text }: { point?: VecLike; text: string }\n) {\n\tconst { sanitizeSvg } = await import('./utils/svg/sanitizeSvg')\n\ttext = sanitizeSvg(text)\n\tif (!text) return\n\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst svg = new DOMParser().parseFromString(text, 'image/svg+xml').querySelector('svg')\n\tif (!svg) {\n\t\tthrow new Error('No <svg/> element present')\n\t}\n\n\tlet width = parseFloat(svg.getAttribute('width') || '0')\n\tlet height = parseFloat(svg.getAttribute('height') || '0')\n\n\tif (!(width && height)) {\n\t\tconst doc = editor.getContainerDocument()\n\t\tdoc.body.appendChild(svg)\n\t\tconst box = svg.getBoundingClientRect()\n\t\tdoc.body.removeChild(svg)\n\n\t\twidth = box.width\n\t\theight = box.height\n\t}\n\n\tconst asset = await editor.getAssetForExternalContent({\n\t\ttype: 'file',\n\t\tfile: new File([text], 'asset.svg', { type: 'image/svg+xml' }),\n\t})\n\n\tif (!asset) throw Error('Could not create an asset')\n\n\tcreateShapesForAssets(editor, [asset], position)\n}\n\n/** @public */\nexport function defaultHandleExternalEmbedContent<T>(\n\teditor: Editor,\n\t{ point, url, embed }: { point?: VecLike; url: string; embed: T }\n) {\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst { width, height } = embed as { width: number; height: number }\n\n\tconst id = createShapeId()\n\n\tconst newPoint = maybeSnapToGrid(\n\t\tnew Vec(position.x - (width || 450) / 2, position.y - (height || 450) / 2),\n\t\teditor\n\t)\n\tconst shapePartial: TLShapePartial = {\n\t\tid,\n\t\ttype: 'embed',\n\t\tx: newPoint.x,\n\t\ty: newPoint.y,\n\t\tprops: {\n\t\t\tw: width,\n\t\t\th: height,\n\t\t\turl,\n\t\t},\n\t}\n\n\tif (editor.canCreateShape(shapePartial)) {\n\t\teditor.createShape(shapePartial).select(id)\n\t}\n}\n\n/** @public */\nexport async function defaultHandleExternalFileContent(\n\teditor: Editor,\n\t{ point, files }: { point?: VecLike; files: File[] },\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst { toasts, msg } = options\n\tif (files.length > editor.options.maxFilesAtOnce) {\n\t\ttoasts.addToast({ title: msg('assets.files.amount-too-many'), severity: 'error' })\n\t\treturn\n\t}\n\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst pagePoint = new Vec(position.x, position.y)\n\tconst assetPartials: TLAsset[] = []\n\tconst assetsToUpdate: {\n\t\tasset: TLAsset\n\t\tfile: File\n\t}[] = []\n\tfor (const file of files) {\n\t\tconst isSuccess = notifyIfFileNotAllowed(editor, file, options)\n\t\tif (!isSuccess) continue\n\n\t\tconst sanitizedFile = await maybeSanitizeSvgFile(file)\n\t\tif (!sanitizedFile) {\n\t\t\ttoasts.addToast({\n\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\tseverity: 'error',\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\tconst assetInfo = await getAssetInfo(editor, sanitizedFile)\n\t\tif (!assetInfo) continue\n\t\tif (assetInfo.type === 'image') {\n\t\t\teditor.createTemporaryAssetPreview(assetInfo.id, sanitizedFile)\n\t\t}\n\t\tassetPartials.push(assetInfo)\n\t\tassetsToUpdate.push({ asset: assetInfo, file: sanitizedFile })\n\t}\n\n\tPromise.allSettled(\n\t\tassetsToUpdate.map(async (assetAndFile) => {\n\t\t\ttry {\n\t\t\t\tconst newAsset = await editor.getAssetForExternalContent({\n\t\t\t\t\ttype: 'file',\n\t\t\t\t\tfile: assetAndFile.file,\n\t\t\t\t})\n\n\t\t\t\tif (!newAsset) {\n\t\t\t\t\tthrow Error('Could not create an asset')\n\t\t\t\t}\n\n\t\t\t\t// Save the new asset under the old asset's id\n\t\t\t\teditor.updateAssets([{ ...newAsset, id: assetAndFile.asset.id }])\n\t\t\t} catch (error) {\n\t\t\t\ttoasts.addToast({\n\t\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\t\t\t\tconsole.error(error)\n\t\t\t\teditor.deleteAssets([assetAndFile.asset.id])\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t)\n\n\tcreateShapesForAssets(editor, assetPartials, pagePoint)\n}\n\n/** @public */\nexport async function defaultHandleExternalTextContent(\n\teditor: Editor,\n\t{ point, text, html }: { point?: VecLike; text: string; html?: string }\n) {\n\tconst p =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst defaultProps = editor.getShapeUtil<TLTextShape>('text').getDefaultProps()\n\n\tconst cleanedUpPlaintext = cleanupText(text)\n\tconst richTextToPaste = html\n\t\t? renderRichTextFromHTML(editor, html)\n\t\t: toRichText(cleanedUpPlaintext)\n\n\t// todo: discuss\n\t// If we have one shape with rich text selected, update the shape's text.\n\t// const onlySelectedShape = editor.getOnlySelectedShape()\n\t// if (onlySelectedShape && 'richText' in onlySelectedShape.props) {\n\t// \teditor.updateShapes([\n\t// \t\t{\n\t// \t\t\tid: onlySelectedShape.id,\n\t// \t\t\ttype: onlySelectedShape.type,\n\t// \t\t\tprops: {\n\t// \t\t\t\trichText: richTextToPaste,\n\t// \t\t\t},\n\t// \t\t},\n\t// \t])\n\n\t// \treturn\n\t// }\n\n\t// Measure the text with default values\n\tlet w: number\n\tlet h: number\n\tlet autoSize: boolean\n\tlet align = 'middle' as TLTextShapeProps['textAlign']\n\n\tconst htmlToMeasure = renderHtmlFromRichTextForMeasurement(editor, richTextToPaste)\n\tconst isMultiLine = richTextToPaste.content.length > 1\n\n\t// check whether the text contains the most common characters in RTL languages\n\tconst isRtl = isRightToLeftLanguage(cleanedUpPlaintext)\n\n\tif (isMultiLine) {\n\t\talign = isMultiLine ? (isRtl ? 'end' : 'start') : 'middle'\n\t}\n\n\tconst theme = editor.getCurrentTheme()\n\n\tconst rawSize = editor.textMeasure.measureHtml(htmlToMeasure, {\n\t\t...TEXT_PROPS,\n\t\tlineHeight: theme.lineHeight,\n\t\tfontFamily: getFontFamily(theme, defaultProps.font),\n\t\tfontSize: theme.fontSize * FONT_SIZES[defaultProps.size],\n\t\tmaxWidth: null,\n\t})\n\n\tconst minWidth = Math.min(\n\t\tisMultiLine ? editor.getViewportPageBounds().width * 0.9 : 920,\n\t\tMath.max(200, editor.getViewportPageBounds().width * 0.9)\n\t)\n\n\tif (rawSize.w > minWidth) {\n\t\tconst shrunkSize = editor.textMeasure.measureHtml(htmlToMeasure, {\n\t\t\t...TEXT_PROPS,\n\t\t\tlineHeight: theme.lineHeight,\n\t\t\tfontFamily: getFontFamily(theme, defaultProps.font),\n\t\t\tfontSize: theme.fontSize * FONT_SIZES[defaultProps.size],\n\t\t\tmaxWidth: minWidth,\n\t\t})\n\t\tw = shrunkSize.w\n\t\th = shrunkSize.h\n\t\tautoSize = false\n\t\talign = isRtl ? 'end' : 'start'\n\t} else {\n\t\t// autosize is fine\n\t\tw = Math.max(rawSize.w, 10)\n\t\th = Math.max(rawSize.h, 10)\n\t\tautoSize = true\n\t}\n\n\tif (p.y - h / 2 < editor.getViewportPageBounds().minY + 40) {\n\t\tp.y = editor.getViewportPageBounds().minY + 40 + h / 2\n\t}\n\n\tconst newPoint = maybeSnapToGrid(new Vec(p.x - w / 2, p.y - h / 2), editor)\n\tconst shapeId = createShapeId()\n\n\t// Allow this to trigger the max shapes reached alert\n\teditor.createShapes([\n\t\t{\n\t\t\tid: shapeId,\n\t\t\ttype: 'text',\n\t\t\tx: newPoint.x,\n\t\t\ty: newPoint.y,\n\t\t\tprops: {\n\t\t\t\trichText: richTextToPaste,\n\t\t\t\t// if the text has more than one line, align it to the left\n\t\t\t\ttextAlign: align,\n\t\t\t\tautoSize,\n\t\t\t\tw,\n\t\t\t},\n\t\t},\n\t])\n}\n\n/** @public */\nexport async function defaultHandleExternalUrlContent(\n\teditor: Editor,\n\t{ point, url }: { point?: VecLike; url: string },\n\t{ toasts, msg }: TLDefaultExternalContentHandlerOpts\n) {\n\t// Bookmark shapes validate their `url` prop with T.linkUrl, so a url we can't\n\t// turn into a bookmark would throw a ValidationError and crash the editor\n\t// (#8097) \u2014 e.g. Chrome with an ad blocker active rewrites dragged content\n\t// urls to `about:blank#blocked`. This is a known, handled condition rather\n\t// than a bug, so we tell the user with a toast and warn (not error) with the\n\t// offending url as a local debugging breadcrumb \u2014 deliberately not reported\n\t// to error tracking, where it would just be non-actionable noise.\n\tif (!T.linkUrl.isValid(url)) {\n\t\tconsole.warn(`Could not create a bookmark from an invalid url: ${JSON.stringify(url)}`)\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.url.failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn\n\t}\n\n\t// try to paste as an embed first\n\tconst embedUtil = editor.getShapeUtil('embed') as EmbedShapeUtil | undefined\n\tconst embedInfo = embedUtil?.getEmbedDefinition(url)\n\n\tif (embedInfo && embedInfo.definition.embedOnPaste !== false) {\n\t\treturn editor.putExternalContent({\n\t\t\ttype: 'embed',\n\t\t\turl: embedInfo.url,\n\t\t\tpoint,\n\t\t\tembed: embedInfo.definition,\n\t\t})\n\t}\n\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\t// Use the new function to create the bookmark\n\tconst result = await createBookmarkFromUrl(editor, { url, center: position })\n\n\tif (!result.ok) {\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.url.failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn\n\t}\n}\n\n/** @public */\nexport async function defaultHandleExternalTldrawContent(\n\teditor: Editor,\n\t{ point, content }: { point?: VecLike; content: TLContent }\n) {\n\teditor.run(() => {\n\t\tconst selectionBoundsBefore = editor.getSelectionPageBounds()\n\t\teditor.markHistoryStoppingPoint('paste')\n\n\t\t// Unlock any locked root shapes on paste\n\t\tfor (const shape of content.shapes) {\n\t\t\tif (content.rootShapeIds.includes(shape.id)) {\n\t\t\t\tshape.isLocked = false\n\t\t\t}\n\t\t}\n\n\t\t// While the user is mid-interaction (dragging a handle, translating,\n\t\t// resizing, or rotating), selecting the pasted content would steal the\n\t\t// selection from the shape being manipulated and interrupt the\n\t\t// interaction \u2014 e.g. an arrow's in-progress binding hint disappears\n\t\t// until the drag ends. Leave the selection alone in those cases.\n\t\tconst isMidInteraction = editor.isInAny(\n\t\t\t'select.dragging_handle',\n\t\t\t'select.translating',\n\t\t\t'select.resizing',\n\t\t\t'select.rotating'\n\t\t)\n\n\t\teditor.putContentOntoCurrentPage(content, {\n\t\t\tpoint: point,\n\t\t\tselect: !isMidInteraction,\n\t\t})\n\t\tconst selectedBoundsAfter = editor.getSelectionPageBounds()\n\t\tif (\n\t\t\t// When mid-interaction we don't select the pasted content, so the\n\t\t\t// selection is unchanged and the before/after bounds are identical \u2014\n\t\t\t// the overlap check would always pass. The selection flash below\n\t\t\t// signals that the newly-selected pasted content landed on the old\n\t\t\t// selection, which is meaningless when we didn't change the\n\t\t\t// selection, so skip it.\n\t\t\t!isMidInteraction &&\n\t\t\tselectionBoundsBefore &&\n\t\t\tselectedBoundsAfter &&\n\t\t\tselectionBoundsBefore?.collides(selectedBoundsAfter)\n\t\t) {\n\t\t\t// Creates a 'puff' to show content has been pasted\n\t\t\teditor.updateInstanceState({ isChangingStyle: true })\n\t\t\teditor.timers.setTimeout(() => {\n\t\t\t\teditor.updateInstanceState({ isChangingStyle: false })\n\t\t\t}, 150)\n\t\t}\n\t})\n}\n\n/** @public */\nexport async function defaultHandleExternalExcalidrawContent(\n\teditor: Editor,\n\t{ point, content }: { point?: VecLike; content: any }\n) {\n\teditor.run(() => {\n\t\tputExcalidrawContent(editor, content, point)\n\t})\n}\n\n/**\n * A helper function for an external content handler. It creates bookmarks,\n * images or video shapes corresponding to the type of assets provided.\n *\n * @param editor - The editor instance\n *\n * @param assets - An array of asset Ids\n *\n * @param position - the position at which to create the shapes\n *\n * @public\n */\nexport async function createShapesForAssets(\n\teditor: Editor,\n\tassets: TLAsset[],\n\tposition: VecLike\n): Promise<TLShapeId[]> {\n\tif (!assets.length) return []\n\n\tconst currentPoint = Vec.From(position)\n\tconst partials: TLShapePartial[] = []\n\n\tfor (let i = 0; i < assets.length; i++) {\n\t\tconst asset = assets[i]\n\t\tconst shapeUtil = editor.getShapeUtilForAssetType(asset.type)\n\t\tconst partial = shapeUtil?.createShapeForAsset?.(asset, currentPoint) ?? null\n\t\tif (partial) {\n\t\t\tpartials.push(partial)\n\t\t\tif ('w' in asset.props && typeof asset.props.w === 'number') {\n\t\t\t\tcurrentPoint.x += asset.props.w\n\t\t\t}\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\t// Create any assets\n\t\tconst assetsToCreate = assets.filter((asset) => !editor.getAsset(asset.id))\n\n\t\teditor.store.atomic(() => {\n\t\t\tif (editor.canCreateShapes(partials)) {\n\t\t\t\tif (assetsToCreate.length) {\n\t\t\t\t\teditor.createAssets(assetsToCreate)\n\t\t\t\t}\n\n\t\t\t\t// Create the shapes\n\t\t\t\teditor.createShapes(partials).select(...partials.map((p) => p.id))\n\n\t\t\t\t// Re-position shapes so that the center of the group is at the provided point\n\t\t\t\tcenterSelectionAroundPoint(editor, position)\n\t\t\t}\n\t\t})\n\t})\n\n\treturn partials.map((p) => p.id)\n}\n\n/**\n * Repositions selected shapes do that the center of the group is\n * at the provided position\n *\n * @param editor - The editor instance\n *\n * @param position - the point to center the shapes around\n *\n * @public\n */\nexport function centerSelectionAroundPoint(editor: Editor, position: VecLike) {\n\t// Re-position shapes so that the center of the group is at the provided point\n\tconst viewportPageBounds = editor.getViewportPageBounds()\n\tlet selectionPageBounds = editor.getSelectionPageBounds()\n\n\tif (selectionPageBounds) {\n\t\tconst offset = selectionPageBounds!.center.sub(position)\n\n\t\teditor.updateShapes(\n\t\t\teditor.getSelectedShapes().map((shape) => {\n\t\t\t\tconst localRotation = editor.getShapeParentTransform(shape).decompose().rotation\n\t\t\t\tconst localDelta = Vec.Rot(offset, -localRotation)\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: shape.x! - localDelta.x,\n\t\t\t\t\ty: shape.y! - localDelta.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t}\n\tselectionPageBounds = editor.getSelectionPageBounds()\n\t// align selection with the grid if necessary\n\tif (selectionPageBounds && editor.getInstanceState().isGridMode) {\n\t\tconst gridSize = editor.getDocumentSettings().gridSize\n\t\tconst topLeft = new Vec(selectionPageBounds.minX, selectionPageBounds.minY)\n\t\tconst gridSnappedPoint = topLeft.clone().snapToGrid(gridSize)\n\t\tconst delta = Vec.Sub(topLeft, gridSnappedPoint)\n\t\teditor.updateShapes(\n\t\t\teditor.getSelectedShapes().map((shape) => {\n\t\t\t\tconst newPoint = { x: shape.x! - delta.x, y: shape.y! - delta.y }\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\ty: newPoint.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t}\n\t// Zoom out to fit the shapes, if necessary\n\tselectionPageBounds = editor.getSelectionPageBounds()\n\tif (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {\n\t\teditor.zoomToSelection({ animation: { duration: editor.options.animationMediumMs } })\n\t}\n}\n\n/** @public */\nexport function createEmptyBookmarkShape(\n\teditor: Editor,\n\turl: string,\n\tposition: VecLike\n): TLBookmarkShape {\n\tconst partial: TLShapePartial = {\n\t\tid: createShapeId(),\n\t\ttype: 'bookmark',\n\t\tx: position.x - 150,\n\t\ty: position.y - 160,\n\t\topacity: 1,\n\t\tprops: {\n\t\t\tassetId: null,\n\t\t\turl,\n\t\t},\n\t}\n\n\teditor.run(() => {\n\t\t// Allow this to trigger the max shapes reached alert\n\t\teditor.createShape(partial)\n\t\tif (!editor.getShape(partial.id)) return\n\t\teditor.select(partial.id)\n\t\tcenterSelectionAroundPoint(editor, position)\n\t})\n\n\treturn editor.getShape(partial.id) as TLBookmarkShape\n}\n\nasync function maybeSanitizeSvgFile(file: File): Promise<File | null> {\n\tif (file.type !== 'image/svg+xml') return file\n\ttry {\n\t\tconst text = await file.text()\n\t\tconst { sanitizeSvg } = await import('./utils/svg/sanitizeSvg')\n\t\tconst sanitized = sanitizeSvg(text)\n\t\tif (!sanitized) return null\n\t\treturn new File([sanitized], file.name, { type: file.type, lastModified: file.lastModified })\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Checks if a file is allowed to be uploaded. If it is not, it will show a toast explaining why to the user.\n *\n * @param editor - The editor instance\n * @param file - The file to check\n * @param options - The options for the external content handler\n * @returns True if the file is allowed, false otherwise\n * @public\n */\nexport function notifyIfFileNotAllowed(\n\teditor: Editor,\n\tfile: File,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst {\n\t\tmaxAssetSize = DEFAULT_MAX_ASSET_SIZE,\n\t\tacceptedImageMimeTypes,\n\t\tacceptedVideoMimeTypes,\n\t\ttoasts,\n\t\tmsg,\n\t} = options\n\n\t// Allow if any registered asset util accepts the MIME type, or if it matches\n\t// an explicit allow-list. The asset-util branch lets custom AssetUtils\n\t// (e.g. for PDFs) extend the default media handling \u2014 without it, files\n\t// registered via `assetUtils` would be rejected because <Tldraw> forwards\n\t// `DEFAULT_SUPPORTED_IMAGE_TYPES` / `DEFAULT_SUPPORT_VIDEO_TYPES` here, and\n\t// custom MIME types aren't in those lists. The explicit-list branch supports\n\t// callers that pass these props directly to restrict allowed types.\n\tconst isFileTypeAllowed =\n\t\t!!editor.getAssetUtilForMimeType(file.type) ||\n\t\t(acceptedImageMimeTypes?.includes(file.type) ?? false) ||\n\t\t(acceptedVideoMimeTypes?.includes(file.type) ?? false)\n\tif (!isFileTypeAllowed) {\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.files.type-not-allowed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn false\n\t}\n\n\tif (file.size > maxAssetSize) {\n\t\tconst formatBytes = (bytes: number): string => {\n\t\t\tif (bytes === 0) return '0 bytes'\n\n\t\t\tconst units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']\n\t\t\tconst base = 1024\n\t\t\tconst unitIndex = Math.floor(Math.log(bytes) / Math.log(base))\n\n\t\t\tconst value = bytes / Math.pow(base, unitIndex)\n\t\t\tconst formatted = value % 1 === 0 ? value.toString() : value.toFixed(1)\n\n\t\t\treturn `${formatted} ${units[unitIndex]}`\n\t\t}\n\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.files.size-too-big'),\n\t\t\tdescription: msg('assets.files.maximum-size').replace('{size}', formatBytes(maxAssetSize)),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn false\n\t}\n\n\t// Use mime type instead of file ext, this is because\n\t// window.navigator.clipboard does not preserve file names\n\t// of copied files.\n\tif (!file.type) {\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\tconsole.error('No mime type')\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n/** @public */\nexport async function getAssetInfo(editor: Editor, file: File, assetId?: TLAssetId) {\n\tif (!assetId) {\n\t\tconst hash = getHashForBuffer(await file.arrayBuffer())\n\t\tassetId = AssetRecordType.createId(hash)\n\t}\n\n\tconst assetUtil = editor.getAssetUtilForMimeType(file.type)\n\tif (!assetUtil) return null\n\n\treturn await assetUtil.getAssetFromFile(file, assetId)\n}\n"],
5
- "mappings": ";;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,oBA4BO;AAEP,uBAAsC;AAEtC,kBAAoD;AACpD,qCAAsD;AAGtD,kCAAqC;AACrC,sBAA6E;AAC7E,kBAAmD;AAM5C,MAAM,8BAA8B;AAKpC,MAAM,yBAAyB,KAAK,OAAO;AAyC3C,SAAS,uCACf,QACA,SACC;AAED,SAAO,6BAA6B,QAAQ,OAAO,kBAAkB;AACpE,WAAO,+BAA+B,QAAQ,eAAe,OAAO;AAAA,EACrE,CAAC;AAGD,SAAO,6BAA6B,OAAO,OAAO,kBAAkB;AACnE,WAAO,8BAA8B,QAAQ,eAAe,OAAO;AAAA,EACpE,CAAC;AAGD,SAAO,+BAA+B,YAAY,OAAO,oBAAoB;AAC5E,WAAO,oCAAoC,QAAQ,eAAe;AAAA,EACnE,CAAC;AAGD,SAAO,+BAAyD,SAAS,CAAC,oBAAoB;AAC7F,WAAO,kCAAkC,QAAQ,eAAe;AAAA,EACjE,CAAC;AAGD,SAAO,+BAA+B,SAAS,OAAO,oBAAoB;AACzE,WAAO,iCAAiC,QAAQ,iBAAiB,OAAO;AAAA,EACzE,CAAC;AAGD,SAAO,+BAA+B,gBAAgB,OAAO,oBAAoB;AAChF,WAAO,wCAAwC,QAAQ,iBAAiB,OAAO;AAAA,EAChF,CAAC;AAGD,SAAO,+BAA+B,QAAQ,OAAO,oBAAoB;AACxE,WAAO,iCAAiC,QAAQ,eAAe;AAAA,EAChE,CAAC;AAGD,SAAO,+BAA+B,OAAO,OAAO,oBAAoB;AACvE,WAAO,gCAAgC,QAAQ,iBAAiB,OAAO;AAAA,EACxE,CAAC;AAGD,SAAO,+BAA+B,UAAU,OAAO,oBAAoB;AAC1E,WAAO,mCAAmC,QAAQ,eAAe;AAAA,EAClE,CAAC;AAGD,SAAO,+BAA+B,cAAc,OAAO,oBAAoB;AAC9E,WAAO,uCAAuC,QAAQ,eAAe;AAAA,EACtE,CAAC;AACF;AAGA,eAAsB,+BACrB,QACA,EAAE,MAAM,QAAQ,GAChB,SACC;AACD,QAAM,YAAY,uBAAuB,QAAQ,MAAM,OAAO;AAC9D,MAAI,CAAC,UAAW,2BAAO,OAAO,oBAAoB;AAElD,QAAM,gBAAgB,MAAM,qBAAqB,IAAI;AACrD,MAAI,CAAC,cAAe,2BAAO,OAAO,oCAAoC;AACtE,QAAM,YAAY,MAAM,aAAa,QAAQ,eAAe,OAAO;AACnE,MAAI,CAAC,UAAW,2BAAO,OAAO,sCAAsC,KAAK,IAAI,GAAG;AAChF,QAAM,SAAS,MAAM,OAAO,YAAY,WAAW,aAAa;AAChE,YAAU,MAAM,MAAM,OAAO;AAC7B,MAAI,OAAO,KAAM,WAAU,OAAO,EAAE,GAAG,UAAU,MAAM,GAAG,OAAO,KAAK;AAEtE,SAAO,8BAAgB,OAAO,SAAS;AACxC;AAGA,eAAsB,wCACrB,QACA,EAAE,MAAM,QAAQ,GAChB,SACC;AACD,QAAM,YAAY,uBAAuB,QAAQ,MAAM,OAAO;AAC9D,MAAI,CAAC,UAAW,2BAAO,OAAO,oBAAoB;AAElD,QAAM,gBAAgB,MAAM,qBAAqB,IAAI;AACrD,MAAI,CAAC,cAAe;AACpB,QAAM,QAAQ,OAAO,SAAS,OAAO;AACrC,MAAI,CAAC,MAAO,2BAAO,OAAO,iBAAiB;AAE3C,QAAM,WAAO,gCAAiB,MAAM,cAAc,YAAY,CAAC;AAC/D,QAAM,UAAU,8BAAgB,SAAS,IAAI;AAC7C,SAAO,4BAA4B,SAAS,aAAa;AACzD,QAAM,mBAAoB,MAAM,aAAa,QAAQ,eAAe,OAAO;AAI3E,MAAI,CAAC,iBAAkB;AACvB,SAAO,aAAa,CAAC,gBAAgB,CAAC;AAGtC,MAAI,MAAM,SAAS,SAAS;AAC3B,UAAM,aAAa;AACnB,UAAM,cAAc,WAAW,MAAM;AAGrC,QAAI,WAAW,iBAAiB,MAAM;AACtC,QAAI,YAAY,iBAAiB,MAAM;AACvC,QAAI,OAAO,WAAW;AACtB,QAAI,OAAO,WAAW;AACtB,QAAI,YAAY;AAEhB,QAAI,aAAa;AAEhB,YAAM,aAAS;AAAA,QACd;AAAA,QACA,iBAAiB,MAAM;AAAA,QACvB,iBAAiB,MAAM;AAAA,MACxB;AAEA,kBAAY,OAAO;AACnB,iBAAW,OAAO;AAClB,kBAAY,OAAO;AACnB,aAAO,OAAO;AACd,aAAO,OAAO;AAAA,IACf;AAEA,WAAO,aAAa;AAAA,MACnB;AAAA,QACC,IAAI,WAAW;AAAA,QACf,MAAM,WAAW;AAAA,QACjB,OAAO;AAAA,UACN;AAAA,UACA,MAAM;AAAA,UACN,GAAG;AAAA,UACH,GAAG;AAAA,QACJ;AAAA,QACA,GAAG;AAAA,QACH,GAAG;AAAA,MACJ;AAAA,IACD,CAAC;AAAA,EACF,WAAW,MAAM,SAAS,SAAS;AAClC,WAAO,aAAa;AAAA,MACnB;AAAA,QACC,IAAI,MAAM;AAAA,QACV,MAAM,MAAM;AAAA,QACZ,OAAO;AAAA,UACN;AAAA,UACA,GAAG,iBAAiB,MAAM;AAAA,UAC1B,GAAG,iBAAiB,MAAM;AAAA,QAC3B;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAEA,QAAM,QAAS,MAAM,OAAO,2BAA2B;AAAA,IACtD,MAAM;AAAA,IACN,MAAM;AAAA,IACN;AAAA,EACD,CAAC;AAED,SAAO,aAAa,CAAC,EAAE,GAAG,OAAO,IAAI,QAAQ,CAAC,CAAC;AAE/C,SAAO;AACR;AAGA,eAAsB,8BACrB,QACA,EAAE,IAAI,GACN,EAAE,QAAQ,IAAI,GACa;AAC3B,MAAI;AAEJ,MAAI;AACH,UAAM,OAAO,UAAM,qBAAM,KAAK;AAAA,MAC7B,QAAQ;AAAA,MACR,MAAM;AAAA,IACP,CAAC;AACD,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,UAAM,MAAM,IAAI,UAAU,EAAE,gBAAgB,MAAM,WAAW;AAC7D,WAAO;AAAA,MACN,OAAO,IAAI,KAAK,cAAc,2BAA2B,GAAG,aAAa,SAAS,KAAK;AAAA,MACvF,SACC,IAAI,KAAK,cAAc,8BAA8B,GAAG,aAAa,MAAM,KAC3E,IAAI,KAAK,cAAc,kBAAkB,GAAG,aAAa,MAAM,KAC/D;AAAA,MACD,OAAO,IAAI,KAAK,cAAc,2BAA2B,GAAG,aAAa,SAAS,KAAK;AAAA,MACvF,aACC,IAAI,KAAK,cAAc,iCAAiC,GAAG,aAAa,SAAS,KAAK;AAAA,IACxF;AACA,QAAI,KAAK,SAAS,CAAC,KAAK,MAAM,WAAW,MAAM,GAAG;AACjD,WAAK,QAAQ,IAAI,IAAI,KAAK,OAAO,GAAG,EAAE;AAAA,IACvC;AACA,QAAI,KAAK,WAAW,CAAC,KAAK,QAAQ,WAAW,MAAM,GAAG;AACrD,WAAK,UAAU,IAAI,IAAI,KAAK,SAAS,GAAG,EAAE;AAAA,IAC3C;AAAA,EACD,SAAS,OAAO;AACf,YAAQ,MAAM,KAAK;AACnB,WAAO,SAAS;AAAA,MACf,OAAO,IAAI,mBAAmB;AAAA,MAC9B,UAAU;AAAA,IACX,CAAC;AACD,WAAO,EAAE,OAAO,IAAI,SAAS,IAAI,OAAO,IAAI,aAAa,GAAG;AAAA,EAC7D;AAGA,SAAO;AAAA,IACN,IAAI,8BAAgB,aAAS,gCAAiB,GAAG,CAAC;AAAA,IAClD,UAAU;AAAA,IACV,MAAM;AAAA,IACN,OAAO;AAAA,MACN,KAAK;AAAA,MACL,aAAa,KAAK;AAAA,MAClB,OAAO,KAAK;AAAA,MACZ,SAAS,KAAK;AAAA,MACd,OAAO,KAAK;AAAA,IACb;AAAA,IACA,MAAM,CAAC;AAAA,EACR;AACD;AAGA,eAAsB,oCACrB,QACA,EAAE,OAAO,KAAK,GACb;AACD,QAAM,EAAE,YAAY,IAAI,MAAM,OAAO,yBAAyB;AAC9D,SAAO,YAAY,IAAI;AACvB,MAAI,CAAC,KAAM;AAEX,QAAM,WACL,UACC,OAAO,OAAO,YAAY,IACxB,OAAO,OAAO,oBAAoB,IAClC,OAAO,sBAAsB,EAAE;AAEnC,QAAM,MAAM,IAAI,UAAU,EAAE,gBAAgB,MAAM,eAAe,EAAE,cAAc,KAAK;AACtF,MAAI,CAAC,KAAK;AACT,UAAM,IAAI,MAAM,2BAA2B;AAAA,EAC5C;AAEA,MAAI,QAAQ,WAAW,IAAI,aAAa,OAAO,KAAK,GAAG;AACvD,MAAI,SAAS,WAAW,IAAI,aAAa,QAAQ,KAAK,GAAG;AAEzD,MAAI,EAAE,SAAS,SAAS;AACvB,UAAM,MAAM,OAAO,qBAAqB;AACxC,QAAI,KAAK,YAAY,GAAG;AACxB,UAAM,MAAM,IAAI,sBAAsB;AACtC,QAAI,KAAK,YAAY,GAAG;AAExB,YAAQ,IAAI;AACZ,aAAS,IAAI;AAAA,EACd;AAEA,QAAM,QAAQ,MAAM,OAAO,2BAA2B;AAAA,IACrD,MAAM;AAAA,IACN,MAAM,IAAI,KAAK,CAAC,IAAI,GAAG,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAAA,EAC9D,CAAC;AAED,MAAI,CAAC,MAAO,OAAM,MAAM,2BAA2B;AAEnD,wBAAsB,QAAQ,CAAC,KAAK,GAAG,QAAQ;AAChD;AAGO,SAAS,kCACf,QACA,EAAE,OAAO,KAAK,MAAM,GACnB;AACD,QAAM,WACL,UACC,OAAO,OAAO,YAAY,IACxB,OAAO,OAAO,oBAAoB,IAClC,OAAO,sBAAsB,EAAE;AAEnC,QAAM,EAAE,OAAO,OAAO,IAAI;AAE1B,QAAM,SAAK,6BAAc;AAEzB,QAAM,eAAW;AAAA,IAChB,IAAI,kBAAI,SAAS,KAAK,SAAS,OAAO,GAAG,SAAS,KAAK,UAAU,OAAO,CAAC;AAAA,IACzE;AAAA,EACD;AACA,QAAM,eAA+B;AAAA,IACpC;AAAA,IACA,MAAM;AAAA,IACN,GAAG,SAAS;AAAA,IACZ,GAAG,SAAS;AAAA,IACZ,OAAO;AAAA,MACN,GAAG;AAAA,MACH,GAAG;AAAA,MACH;AAAA,IACD;AAAA,EACD;AAEA,MAAI,OAAO,eAAe,YAAY,GAAG;AACxC,WAAO,YAAY,YAAY,EAAE,OAAO,EAAE;AAAA,EAC3C;AACD;AAGA,eAAsB,iCACrB,QACA,EAAE,OAAO,MAAM,GACf,SACC;AACD,QAAM,EAAE,QAAQ,IAAI,IAAI;AACxB,MAAI,MAAM,SAAS,OAAO,QAAQ,gBAAgB;AACjD,WAAO,SAAS,EAAE,OAAO,IAAI,8BAA8B,GAAG,UAAU,QAAQ,CAAC;AACjF;AAAA,EACD;AAEA,QAAM,WACL,UACC,OAAO,OAAO,YAAY,IACxB,OAAO,OAAO,oBAAoB,IAClC,OAAO,sBAAsB,EAAE;AAEnC,QAAM,YAAY,IAAI,kBAAI,SAAS,GAAG,SAAS,CAAC;AAChD,QAAM,gBAA2B,CAAC;AAClC,QAAM,iBAGA,CAAC;AACP,aAAW,QAAQ,OAAO;AACzB,UAAM,YAAY,uBAAuB,QAAQ,MAAM,OAAO;AAC9D,QAAI,CAAC,UAAW;AAEhB,UAAM,gBAAgB,MAAM,qBAAqB,IAAI;AACrD,QAAI,CAAC,eAAe;AACnB,aAAO,SAAS;AAAA,QACf,OAAO,IAAI,4BAA4B;AAAA,QACvC,UAAU;AAAA,MACX,CAAC;AACD;AAAA,IACD;AACA,UAAM,YAAY,MAAM,aAAa,QAAQ,aAAa;AAC1D,QAAI,CAAC,UAAW;AAChB,QAAI,UAAU,SAAS,SAAS;AAC/B,aAAO,4BAA4B,UAAU,IAAI,aAAa;AAAA,IAC/D;AACA,kBAAc,KAAK,SAAS;AAC5B,mBAAe,KAAK,EAAE,OAAO,WAAW,MAAM,cAAc,CAAC;AAAA,EAC9D;AAEA,UAAQ;AAAA,IACP,eAAe,IAAI,OAAO,iBAAiB;AAC1C,UAAI;AACH,cAAM,WAAW,MAAM,OAAO,2BAA2B;AAAA,UACxD,MAAM;AAAA,UACN,MAAM,aAAa;AAAA,QACpB,CAAC;AAED,YAAI,CAAC,UAAU;AACd,gBAAM,MAAM,2BAA2B;AAAA,QACxC;AAGA,eAAO,aAAa,CAAC,EAAE,GAAG,UAAU,IAAI,aAAa,MAAM,GAAG,CAAC,CAAC;AAAA,MACjE,SAAS,OAAO;AACf,eAAO,SAAS;AAAA,UACf,OAAO,IAAI,4BAA4B;AAAA,UACvC,UAAU;AAAA,QACX,CAAC;AACD,gBAAQ,MAAM,KAAK;AACnB,eAAO,aAAa,CAAC,aAAa,MAAM,EAAE,CAAC;AAC3C;AAAA,MACD;AAAA,IACD,CAAC;AAAA,EACF;AAEA,wBAAsB,QAAQ,eAAe,SAAS;AACvD;AAGA,eAAsB,iCACrB,QACA,EAAE,OAAO,MAAM,KAAK,GACnB;AACD,QAAM,IACL,UACC,OAAO,OAAO,YAAY,IACxB,OAAO,OAAO,oBAAoB,IAClC,OAAO,sBAAsB,EAAE;AAEnC,QAAM,eAAe,OAAO,aAA0B,MAAM,EAAE,gBAAgB;AAE9E,QAAM,yBAAqB,yBAAY,IAAI;AAC3C,QAAM,kBAAkB,WACrB,wCAAuB,QAAQ,IAAI,QACnC,0BAAW,kBAAkB;AAoBhC,MAAI;AACJ,MAAI;AACJ,MAAI;AACJ,MAAI,QAAQ;AAEZ,QAAM,oBAAgB,sDAAqC,QAAQ,eAAe;AAClF,QAAM,cAAc,gBAAgB,QAAQ,SAAS;AAGrD,QAAM,YAAQ,mCAAsB,kBAAkB;AAEtD,MAAI,aAAa;AAChB,YAAQ,cAAe,QAAQ,QAAQ,UAAW;AAAA,EACnD;AAEA,QAAM,QAAQ,OAAO,gBAAgB;AAErC,QAAM,UAAU,OAAO,YAAY,YAAY,eAAe;AAAA,IAC7D,GAAG;AAAA,IACH,YAAY,MAAM;AAAA,IAClB,gBAAY,8CAAc,OAAO,aAAa,IAAI;AAAA,IAClD,UAAU,MAAM,WAAW,0CAAW,aAAa,IAAI;AAAA,IACvD,UAAU;AAAA,EACX,CAAC;AAED,QAAM,WAAW,KAAK;AAAA,IACrB,cAAc,OAAO,sBAAsB,EAAE,QAAQ,MAAM;AAAA,IAC3D,KAAK,IAAI,KAAK,OAAO,sBAAsB,EAAE,QAAQ,GAAG;AAAA,EACzD;AAEA,MAAI,QAAQ,IAAI,UAAU;AACzB,UAAM,aAAa,OAAO,YAAY,YAAY,eAAe;AAAA,MAChE,GAAG;AAAA,MACH,YAAY,MAAM;AAAA,MAClB,gBAAY,8CAAc,OAAO,aAAa,IAAI;AAAA,MAClD,UAAU,MAAM,WAAW,0CAAW,aAAa,IAAI;AAAA,MACvD,UAAU;AAAA,IACX,CAAC;AACD,QAAI,WAAW;AACf,QAAI,WAAW;AACf,eAAW;AACX,YAAQ,QAAQ,QAAQ;AAAA,EACzB,OAAO;AAEN,QAAI,KAAK,IAAI,QAAQ,GAAG,EAAE;AAC1B,QAAI,KAAK,IAAI,QAAQ,GAAG,EAAE;AAC1B,eAAW;AAAA,EACZ;AAEA,MAAI,EAAE,IAAI,IAAI,IAAI,OAAO,sBAAsB,EAAE,OAAO,IAAI;AAC3D,MAAE,IAAI,OAAO,sBAAsB,EAAE,OAAO,KAAK,IAAI;AAAA,EACtD;AAEA,QAAM,eAAW,+BAAgB,IAAI,kBAAI,EAAE,IAAI,IAAI,GAAG,EAAE,IAAI,IAAI,CAAC,GAAG,MAAM;AAC1E,QAAM,cAAU,6BAAc;AAG9B,SAAO,aAAa;AAAA,IACnB;AAAA,MACC,IAAI;AAAA,MACJ,MAAM;AAAA,MACN,GAAG,SAAS;AAAA,MACZ,GAAG,SAAS;AAAA,MACZ,OAAO;AAAA,QACN,UAAU;AAAA;AAAA,QAEV,WAAW;AAAA,QACX;AAAA,QACA;AAAA,MACD;AAAA,IACD;AAAA,EACD,CAAC;AACF;AAGA,eAAsB,gCACrB,QACA,EAAE,OAAO,IAAI,GACb,EAAE,QAAQ,IAAI,GACb;AAQD,MAAI,CAAC,gBAAE,QAAQ,QAAQ,GAAG,GAAG;AAC5B,YAAQ,KAAK,oDAAoD,KAAK,UAAU,GAAG,CAAC,EAAE;AACtF,WAAO,SAAS;AAAA,MACf,OAAO,IAAI,mBAAmB;AAAA,MAC9B,UAAU;AAAA,IACX,CAAC;AACD;AAAA,EACD;AAGA,QAAM,YAAY,OAAO,aAAa,OAAO;AAC7C,QAAM,YAAY,WAAW,mBAAmB,GAAG;AAEnD,MAAI,aAAa,UAAU,WAAW,iBAAiB,OAAO;AAC7D,WAAO,OAAO,mBAAmB;AAAA,MAChC,MAAM;AAAA,MACN,KAAK,UAAU;AAAA,MACf;AAAA,MACA,OAAO,UAAU;AAAA,IAClB,CAAC;AAAA,EACF;AAEA,QAAM,WACL,UACC,OAAO,OAAO,YAAY,IACxB,OAAO,OAAO,oBAAoB,IAClC,OAAO,sBAAsB,EAAE;AAGnC,QAAM,SAAS,UAAM,wCAAsB,QAAQ,EAAE,KAAK,QAAQ,SAAS,CAAC;AAE5E,MAAI,CAAC,OAAO,IAAI;AACf,WAAO,SAAS;AAAA,MACf,OAAO,IAAI,mBAAmB;AAAA,MAC9B,UAAU;AAAA,IACX,CAAC;AACD;AAAA,EACD;AACD;AAGA,eAAsB,mCACrB,QACA,EAAE,OAAO,QAAQ,GAChB;AACD,SAAO,IAAI,MAAM;AAChB,UAAM,wBAAwB,OAAO,uBAAuB;AAC5D,WAAO,yBAAyB,OAAO;AAGvC,eAAW,SAAS,QAAQ,QAAQ;AACnC,UAAI,QAAQ,aAAa,SAAS,MAAM,EAAE,GAAG;AAC5C,cAAM,WAAW;AAAA,MAClB;AAAA,IACD;AAOA,UAAM,mBAAmB,OAAO;AAAA,MAC/B;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACD;AAEA,WAAO,0BAA0B,SAAS;AAAA,MACzC;AAAA,MACA,QAAQ,CAAC;AAAA,IACV,CAAC;AACD,UAAM,sBAAsB,OAAO,uBAAuB;AAC1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,MAOC,CAAC,oBACD,yBACA,uBACA,uBAAuB,SAAS,mBAAmB;AAAA,MAClD;AAED,aAAO,oBAAoB,EAAE,iBAAiB,KAAK,CAAC;AACpD,aAAO,OAAO,WAAW,MAAM;AAC9B,eAAO,oBAAoB,EAAE,iBAAiB,MAAM,CAAC;AAAA,MACtD,GAAG,GAAG;AAAA,IACP;AAAA,EACD,CAAC;AACF;AAGA,eAAsB,uCACrB,QACA,EAAE,OAAO,QAAQ,GAChB;AACD,SAAO,IAAI,MAAM;AAChB,0DAAqB,QAAQ,SAAS,KAAK;AAAA,EAC5C,CAAC;AACF;AAcA,eAAsB,sBACrB,QACA,QACA,UACuB;AACvB,MAAI,CAAC,OAAO,OAAQ,QAAO,CAAC;AAE5B,QAAM,eAAe,kBAAI,KAAK,QAAQ;AACtC,QAAM,WAA6B,CAAC;AAEpC,WAAS,IAAI,GAAG,IAAI,OAAO,QAAQ,KAAK;AACvC,UAAM,QAAQ,OAAO,CAAC;AACtB,UAAM,YAAY,OAAO,yBAAyB,MAAM,IAAI;AAC5D,UAAM,UAAU,WAAW,sBAAsB,OAAO,YAAY,KAAK;AACzE,QAAI,SAAS;AACZ,eAAS,KAAK,OAAO;AACrB,UAAI,OAAO,MAAM,SAAS,OAAO,MAAM,MAAM,MAAM,UAAU;AAC5D,qBAAa,KAAK,MAAM,MAAM;AAAA,MAC/B;AAAA,IACD;AAAA,EACD;AAEA,SAAO,IAAI,MAAM;AAEhB,UAAM,iBAAiB,OAAO,OAAO,CAAC,UAAU,CAAC,OAAO,SAAS,MAAM,EAAE,CAAC;AAE1E,WAAO,MAAM,OAAO,MAAM;AACzB,UAAI,OAAO,gBAAgB,QAAQ,GAAG;AACrC,YAAI,eAAe,QAAQ;AAC1B,iBAAO,aAAa,cAAc;AAAA,QACnC;AAGA,eAAO,aAAa,QAAQ,EAAE,OAAO,GAAG,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE,CAAC;AAGjE,mCAA2B,QAAQ,QAAQ;AAAA,MAC5C;AAAA,IACD,CAAC;AAAA,EACF,CAAC;AAED,SAAO,SAAS,IAAI,CAAC,MAAM,EAAE,EAAE;AAChC;AAYO,SAAS,2BAA2B,QAAgB,UAAmB;AAE7E,QAAM,qBAAqB,OAAO,sBAAsB;AACxD,MAAI,sBAAsB,OAAO,uBAAuB;AAExD,MAAI,qBAAqB;AACxB,UAAM,SAAS,oBAAqB,OAAO,IAAI,QAAQ;AAEvD,WAAO;AAAA,MACN,OAAO,kBAAkB,EAAE,IAAI,CAAC,UAAU;AACzC,cAAM,gBAAgB,OAAO,wBAAwB,KAAK,EAAE,UAAU,EAAE;AACxE,cAAM,aAAa,kBAAI,IAAI,QAAQ,CAAC,aAAa;AACjD,eAAO;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,GAAG,MAAM,IAAK,WAAW;AAAA,UACzB,GAAG,MAAM,IAAK,WAAW;AAAA,QAC1B;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AACA,wBAAsB,OAAO,uBAAuB;AAEpD,MAAI,uBAAuB,OAAO,iBAAiB,EAAE,YAAY;AAChE,UAAM,WAAW,OAAO,oBAAoB,EAAE;AAC9C,UAAM,UAAU,IAAI,kBAAI,oBAAoB,MAAM,oBAAoB,IAAI;AAC1E,UAAM,mBAAmB,QAAQ,MAAM,EAAE,WAAW,QAAQ;AAC5D,UAAM,QAAQ,kBAAI,IAAI,SAAS,gBAAgB;AAC/C,WAAO;AAAA,MACN,OAAO,kBAAkB,EAAE,IAAI,CAAC,UAAU;AACzC,cAAM,WAAW,EAAE,GAAG,MAAM,IAAK,MAAM,GAAG,GAAG,MAAM,IAAK,MAAM,EAAE;AAChE,eAAO;AAAA,UACN,IAAI,MAAM;AAAA,UACV,MAAM,MAAM;AAAA,UACZ,GAAG,SAAS;AAAA,UACZ,GAAG,SAAS;AAAA,QACb;AAAA,MACD,CAAC;AAAA,IACF;AAAA,EACD;AAEA,wBAAsB,OAAO,uBAAuB;AACpD,MAAI,uBAAuB,CAAC,mBAAmB,SAAS,mBAAmB,GAAG;AAC7E,WAAO,gBAAgB,EAAE,WAAW,EAAE,UAAU,OAAO,QAAQ,kBAAkB,EAAE,CAAC;AAAA,EACrF;AACD;AAGO,SAAS,yBACf,QACA,KACA,UACkB;AAClB,QAAM,UAA0B;AAAA,IAC/B,QAAI,6BAAc;AAAA,IAClB,MAAM;AAAA,IACN,GAAG,SAAS,IAAI;AAAA,IAChB,GAAG,SAAS,IAAI;AAAA,IAChB,SAAS;AAAA,IACT,OAAO;AAAA,MACN,SAAS;AAAA,MACT;AAAA,IACD;AAAA,EACD;AAEA,SAAO,IAAI,MAAM;AAEhB,WAAO,YAAY,OAAO;AAC1B,QAAI,CAAC,OAAO,SAAS,QAAQ,EAAE,EAAG;AAClC,WAAO,OAAO,QAAQ,EAAE;AACxB,+BAA2B,QAAQ,QAAQ;AAAA,EAC5C,CAAC;AAED,SAAO,OAAO,SAAS,QAAQ,EAAE;AAClC;AAEA,eAAe,qBAAqB,MAAkC;AACrE,MAAI,KAAK,SAAS,gBAAiB,QAAO;AAC1C,MAAI;AACH,UAAM,OAAO,MAAM,KAAK,KAAK;AAC7B,UAAM,EAAE,YAAY,IAAI,MAAM,OAAO,yBAAyB;AAC9D,UAAM,YAAY,YAAY,IAAI;AAClC,QAAI,CAAC,UAAW,QAAO;AACvB,WAAO,IAAI,KAAK,CAAC,SAAS,GAAG,KAAK,MAAM,EAAE,MAAM,KAAK,MAAM,cAAc,KAAK,aAAa,CAAC;AAAA,EAC7F,QAAQ;AACP,WAAO;AAAA,EACR;AACD;AAWO,SAAS,uBACf,QACA,MACA,SACC;AACD,QAAM;AAAA,IACL,eAAe;AAAA,IACf;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,EACD,IAAI;AASJ,QAAM,oBACL,CAAC,CAAC,OAAO,wBAAwB,KAAK,IAAI,MACzC,wBAAwB,SAAS,KAAK,IAAI,KAAK,WAC/C,wBAAwB,SAAS,KAAK,IAAI,KAAK;AACjD,MAAI,CAAC,mBAAmB;AACvB,WAAO,SAAS;AAAA,MACf,OAAO,IAAI,+BAA+B;AAAA,MAC1C,UAAU;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACR;AAEA,MAAI,KAAK,OAAO,cAAc;AAC7B,UAAM,cAAc,CAAC,UAA0B;AAC9C,UAAI,UAAU,EAAG,QAAO;AAExB,YAAM,QAAQ,CAAC,SAAS,MAAM,MAAM,MAAM,MAAM,IAAI;AACpD,YAAM,OAAO;AACb,YAAM,YAAY,KAAK,MAAM,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,IAAI,CAAC;AAE7D,YAAM,QAAQ,QAAQ,KAAK,IAAI,MAAM,SAAS;AAC9C,YAAM,YAAY,QAAQ,MAAM,IAAI,MAAM,SAAS,IAAI,MAAM,QAAQ,CAAC;AAEtE,aAAO,GAAG,SAAS,IAAI,MAAM,SAAS,CAAC;AAAA,IACxC;AAEA,WAAO,SAAS;AAAA,MACf,OAAO,IAAI,2BAA2B;AAAA,MACtC,aAAa,IAAI,2BAA2B,EAAE,QAAQ,UAAU,YAAY,YAAY,CAAC;AAAA,MACzF,UAAU;AAAA,IACX,CAAC;AACD,WAAO;AAAA,EACR;AAKA,MAAI,CAAC,KAAK,MAAM;AACf,WAAO,SAAS;AAAA,MACf,OAAO,IAAI,4BAA4B;AAAA,MACvC,UAAU;AAAA,IACX,CAAC;AACD,YAAQ,MAAM,cAAc;AAC5B,WAAO;AAAA,EACR;AAEA,SAAO;AACR;AAGA,eAAsB,aAAa,QAAgB,MAAY,SAAqB;AACnF,MAAI,CAAC,SAAS;AACb,UAAM,WAAO,gCAAiB,MAAM,KAAK,YAAY,CAAC;AACtD,cAAU,8BAAgB,SAAS,IAAI;AAAA,EACxC;AAEA,QAAM,YAAY,OAAO,wBAAwB,KAAK,IAAI;AAC1D,MAAI,CAAC,UAAW,QAAO;AAEvB,SAAO,MAAM,UAAU,iBAAiB,MAAM,OAAO;AACtD;",
4
+ "sourcesContent": ["import {\n\tAssetRecordType,\n\tEditor,\n\tT,\n\tTLAsset,\n\tTLAssetId,\n\tTLBookmarkAsset,\n\tTLBookmarkShape,\n\tTLContent,\n\tTLFileExternalAsset,\n\tTLFileReplaceExternalContent,\n\tTLImageAsset,\n\tTLImageShape,\n\tTLShapeId,\n\tTLShapePartial,\n\tTLTextShape,\n\tTLTextShapeProps,\n\tTLUrlExternalAsset,\n\tTLVideoAsset,\n\tVec,\n\tVecLike,\n\tassert,\n\tcreateShapeId,\n\tfetch,\n\tgetHashForBuffer,\n\tgetHashForString,\n\tmaybeSnapToGrid,\n\ttoRichText,\n} from '@tldraw/editor'\nimport { EmbedDefinition } from './defaultEmbedDefinitions'\nimport { createBookmarkFromUrl } from './shapes/bookmark/bookmarks'\nimport { EmbedShapeUtil } from './shapes/embed/EmbedShapeUtil'\nimport { getCroppedImageDataForReplacedImage } from './shapes/shared/crop'\nimport { FONT_SIZES, TEXT_PROPS, getFontFamily } from './shapes/shared/default-shape-constants'\nimport { TLUiToastsContextType } from './ui/context/toasts'\nimport { useTranslation } from './ui/hooks/useTranslation/useTranslation'\nimport { putExcalidrawContent } from './utils/excalidraw/putExcalidrawContent'\nimport { renderHtmlFromRichTextForMeasurement, renderRichTextFromHTML } from './utils/text/richText'\nimport { cleanupText, isRightToLeftLanguage } from './utils/text/text'\n\n/**\n * 5000px\n * @public\n */\nexport const DEFAULT_MAX_IMAGE_DIMENSION = 5000\n/**\n * 10mb\n * @public\n */\nexport const DEFAULT_MAX_ASSET_SIZE = 10 * 1024 * 1024\n\n/** @public */\nexport interface TLExternalContentProps {\n\t/**\n\t * The maximum dimension (width or height) of an image. Images larger than this will be rescaled\n\t * to fit. Defaults to infinity.\n\t */\n\tmaxImageDimension?: number\n\t/**\n\t * The maximum size (in bytes) of an asset. Assets larger than this will be rejected. Defaults\n\t * to 10mb (10 * 1024 * 1024).\n\t */\n\tmaxAssetSize?: number\n\t/**\n\t * The mime types of images that are allowed to be handled. When passed to\n\t * the `Tldraw` component, this also reconfigures the default `ImageAssetUtil`\n\t * to only accept files matching these types. If you only want to accept a\n\t * subset of image types and want to additionally block videos, pass\n\t * `acceptedVideoMimeTypes={[]}`. A file is accepted if its MIME type is in\n\t * this list, in `acceptedVideoMimeTypes`, or if any registered asset util\n\t * accepts it.\n\t */\n\tacceptedImageMimeTypes?: readonly string[]\n\t/**\n\t * The mime types of videos that are allowed to be handled. When passed to\n\t * the `Tldraw` component, this also reconfigures the default `VideoAssetUtil`\n\t * to only accept files matching these types. A file is accepted if its MIME\n\t * type is in this list, in `acceptedImageMimeTypes`, or if any registered\n\t * asset util accepts it.\n\t */\n\tacceptedVideoMimeTypes?: readonly string[]\n}\n\n/** @public */\nexport interface TLDefaultExternalContentHandlerOpts extends TLExternalContentProps {\n\ttoasts: TLUiToastsContextType\n\tmsg: ReturnType<typeof useTranslation>\n}\n\n/** @public */\nexport function registerDefaultExternalContentHandlers(\n\teditor: Editor,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\t// files -> asset\n\teditor.registerExternalAssetHandler('file', async (externalAsset) => {\n\t\treturn defaultHandleExternalFileAsset(editor, externalAsset, options)\n\t})\n\n\t// urls -> bookmark asset\n\teditor.registerExternalAssetHandler('url', async (externalAsset) => {\n\t\treturn defaultHandleExternalUrlAsset(editor, externalAsset, options)\n\t})\n\n\t// svg text\n\teditor.registerExternalContentHandler('svg-text', async (externalContent) => {\n\t\treturn defaultHandleExternalSvgTextContent(editor, externalContent)\n\t})\n\n\t// embeds\n\teditor.registerExternalContentHandler<'embed', EmbedDefinition>('embed', (externalContent) => {\n\t\treturn defaultHandleExternalEmbedContent(editor, externalContent)\n\t})\n\n\t// files\n\teditor.registerExternalContentHandler('files', async (externalContent) => {\n\t\treturn defaultHandleExternalFileContent(editor, externalContent, options)\n\t})\n\n\t// file-replace -> asset\n\teditor.registerExternalContentHandler('file-replace', async (externalContent) => {\n\t\treturn defaultHandleExternalFileReplaceContent(editor, externalContent, options)\n\t})\n\n\t// text\n\teditor.registerExternalContentHandler('text', async (externalContent) => {\n\t\treturn defaultHandleExternalTextContent(editor, externalContent)\n\t})\n\n\t// url\n\teditor.registerExternalContentHandler('url', async (externalContent) => {\n\t\treturn defaultHandleExternalUrlContent(editor, externalContent, options)\n\t})\n\n\t// tldraw\n\teditor.registerExternalContentHandler('tldraw', async (externalContent) => {\n\t\treturn defaultHandleExternalTldrawContent(editor, externalContent)\n\t})\n\n\t// excalidraw\n\teditor.registerExternalContentHandler('excalidraw', async (externalContent) => {\n\t\treturn defaultHandleExternalExcalidrawContent(editor, externalContent)\n\t})\n}\n\n/** @public */\nexport async function defaultHandleExternalFileAsset(\n\teditor: Editor,\n\t{ file, assetId }: TLFileExternalAsset,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst isSuccess = notifyIfFileNotAllowed(editor, file, options)\n\tif (!isSuccess) assert(false, 'File checks failed')\n\n\tconst sanitizedFile = await maybeSanitizeSvgFile(file)\n\tif (!sanitizedFile) assert(false, 'SVG file contained no safe content')\n\tconst assetInfo = await getAssetInfo(editor, sanitizedFile, assetId)\n\tif (!assetInfo) assert(false, `No asset util found for MIME type \"${file.type}\"`)\n\tconst result = await editor.uploadAsset(assetInfo, sanitizedFile)\n\tassetInfo.props.src = result.src\n\tif (result.meta) assetInfo.meta = { ...assetInfo.meta, ...result.meta }\n\n\treturn AssetRecordType.create(assetInfo)\n}\n\n/** @public */\nexport async function defaultHandleExternalFileReplaceContent(\n\teditor: Editor,\n\t{ file, shapeId }: TLFileReplaceExternalContent,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst isSuccess = notifyIfFileNotAllowed(editor, file, options)\n\tif (!isSuccess) assert(false, 'File checks failed')\n\n\tconst sanitizedFile = await maybeSanitizeSvgFile(file)\n\tif (!sanitizedFile) return\n\tconst shape = editor.getShape(shapeId)\n\tif (!shape) assert(false, 'Shape not found')\n\n\tconst hash = getHashForBuffer(await sanitizedFile.arrayBuffer())\n\tconst assetId = AssetRecordType.createId(hash)\n\teditor.createTemporaryAssetPreview(assetId, sanitizedFile)\n\tconst assetInfoPartial = (await getAssetInfo(editor, sanitizedFile, assetId)) as\n\t\t| TLImageAsset\n\t\t| TLVideoAsset\n\t\t| null\n\tif (!assetInfoPartial) return\n\teditor.createAssets([assetInfoPartial])\n\n\t// And update the shape\n\tif (shape.type === 'image') {\n\t\tconst imageShape = shape as TLImageShape\n\t\tconst currentCrop = imageShape.props.crop\n\n\t\t// Calculate new dimensions that preserve the current visual size of the cropped area\n\t\tlet newWidth = assetInfoPartial.props.w\n\t\tlet newHeight = assetInfoPartial.props.h\n\t\tlet newX = imageShape.x\n\t\tlet newY = imageShape.y\n\t\tlet finalCrop = currentCrop\n\n\t\tif (currentCrop) {\n\t\t\t// Use the dedicated function to calculate the new crop and dimensions\n\t\t\tconst result = getCroppedImageDataForReplacedImage(\n\t\t\t\timageShape,\n\t\t\t\tassetInfoPartial.props.w,\n\t\t\t\tassetInfoPartial.props.h\n\t\t\t)\n\n\t\t\tfinalCrop = result.crop\n\t\t\tnewWidth = result.w\n\t\t\tnewHeight = result.h\n\t\t\tnewX = result.x\n\t\t\tnewY = result.y\n\t\t}\n\n\t\teditor.updateShapes([\n\t\t\t{\n\t\t\t\tid: imageShape.id,\n\t\t\t\ttype: imageShape.type,\n\t\t\t\tprops: {\n\t\t\t\t\tassetId: assetId,\n\t\t\t\t\tcrop: finalCrop,\n\t\t\t\t\tw: newWidth,\n\t\t\t\t\th: newHeight,\n\t\t\t\t},\n\t\t\t\tx: newX,\n\t\t\t\ty: newY,\n\t\t\t},\n\t\t])\n\t} else if (shape.type === 'video') {\n\t\teditor.updateShapes([\n\t\t\t{\n\t\t\t\tid: shape.id,\n\t\t\t\ttype: shape.type,\n\t\t\t\tprops: {\n\t\t\t\t\tassetId: assetId,\n\t\t\t\t\tw: assetInfoPartial.props.w,\n\t\t\t\t\th: assetInfoPartial.props.h,\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\t}\n\n\tconst asset = (await editor.getAssetForExternalContent({\n\t\ttype: 'file',\n\t\tfile: sanitizedFile,\n\t\tassetId,\n\t})) as TLAsset\n\n\teditor.updateAssets([{ ...asset, id: assetId }])\n\n\treturn asset\n}\n\n/** @public */\nexport async function defaultHandleExternalUrlAsset(\n\teditor: Editor,\n\t{ url }: TLUrlExternalAsset,\n\t{ toasts, msg }: TLDefaultExternalContentHandlerOpts\n): Promise<TLBookmarkAsset> {\n\tlet meta: { image: string; favicon: string; title: string; description: string }\n\n\ttry {\n\t\tconst resp = await fetch(url, {\n\t\t\tmethod: 'GET',\n\t\t\tmode: 'no-cors',\n\t\t})\n\t\tconst html = await resp.text()\n\t\tconst doc = new DOMParser().parseFromString(html, 'text/html')\n\t\tmeta = {\n\t\t\timage: doc.head.querySelector('meta[property=\"og:image\"]')?.getAttribute('content') ?? '',\n\t\t\tfavicon:\n\t\t\t\tdoc.head.querySelector('link[rel=\"apple-touch-icon\"]')?.getAttribute('href') ??\n\t\t\t\tdoc.head.querySelector('link[rel=\"icon\"]')?.getAttribute('href') ??\n\t\t\t\t'',\n\t\t\ttitle: doc.head.querySelector('meta[property=\"og:title\"]')?.getAttribute('content') ?? url,\n\t\t\tdescription:\n\t\t\t\tdoc.head.querySelector('meta[property=\"og:description\"]')?.getAttribute('content') ?? '',\n\t\t}\n\t\tif (meta.image && !meta.image.startsWith('http')) {\n\t\t\tmeta.image = new URL(meta.image, url).href\n\t\t}\n\t\tif (meta.favicon && !meta.favicon.startsWith('http')) {\n\t\t\tmeta.favicon = new URL(meta.favicon, url).href\n\t\t}\n\t} catch (error) {\n\t\tconsole.error(error)\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.url.failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\tmeta = { image: '', favicon: '', title: '', description: '' }\n\t}\n\n\t// Create the bookmark asset from the meta\n\treturn {\n\t\tid: AssetRecordType.createId(getHashForString(url)),\n\t\ttypeName: 'asset',\n\t\ttype: 'bookmark',\n\t\tprops: {\n\t\t\tsrc: url,\n\t\t\tdescription: meta.description,\n\t\t\timage: meta.image,\n\t\t\tfavicon: meta.favicon,\n\t\t\ttitle: meta.title,\n\t\t},\n\t\tmeta: {},\n\t} as TLBookmarkAsset\n}\n\n/** @public */\nexport async function defaultHandleExternalSvgTextContent(\n\teditor: Editor,\n\t{ point, text }: { point?: VecLike; text: string }\n) {\n\tconst { sanitizeSvg } = await import('./utils/svg/sanitizeSvg')\n\ttext = sanitizeSvg(text)\n\tif (!text) return\n\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst svg = new DOMParser().parseFromString(text, 'image/svg+xml').querySelector('svg')\n\tif (!svg) {\n\t\tthrow new Error('No <svg/> element present')\n\t}\n\n\tlet width = parseFloat(svg.getAttribute('width') || '0')\n\tlet height = parseFloat(svg.getAttribute('height') || '0')\n\n\tif (!(width && height)) {\n\t\tconst doc = editor.getContainerDocument()\n\t\tdoc.body.appendChild(svg)\n\t\tconst box = svg.getBoundingClientRect()\n\t\tdoc.body.removeChild(svg)\n\n\t\twidth = box.width\n\t\theight = box.height\n\t}\n\n\tconst asset = await editor.getAssetForExternalContent({\n\t\ttype: 'file',\n\t\tfile: new File([text], 'asset.svg', { type: 'image/svg+xml' }),\n\t})\n\n\tif (!asset) throw Error('Could not create an asset')\n\n\tcreateShapesForAssets(editor, [asset], position)\n}\n\n/** @public */\nexport function defaultHandleExternalEmbedContent<T>(\n\teditor: Editor,\n\t{ point, url, embed }: { point?: VecLike; url: string; embed: T }\n) {\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst { width, height } = embed as { width: number; height: number }\n\n\tconst id = createShapeId()\n\n\tconst newPoint = maybeSnapToGrid(\n\t\tnew Vec(position.x - (width || 450) / 2, position.y - (height || 450) / 2),\n\t\teditor\n\t)\n\tconst shapePartial: TLShapePartial = {\n\t\tid,\n\t\ttype: 'embed',\n\t\tx: newPoint.x,\n\t\ty: newPoint.y,\n\t\tprops: {\n\t\t\tw: width,\n\t\t\th: height,\n\t\t\turl,\n\t\t},\n\t}\n\n\tif (editor.canCreateShape(shapePartial)) {\n\t\teditor.createShape(shapePartial).select(id)\n\t}\n}\n\n/** @public */\nexport async function defaultHandleExternalFileContent(\n\teditor: Editor,\n\t{ point, files }: { point?: VecLike; files: File[] },\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst { toasts, msg } = options\n\tif (files.length > editor.options.maxFilesAtOnce) {\n\t\ttoasts.addToast({ title: msg('assets.files.amount-too-many'), severity: 'error' })\n\t\treturn\n\t}\n\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst pagePoint = new Vec(position.x, position.y)\n\tconst assetPartials: TLAsset[] = []\n\tconst assetsToUpdate: {\n\t\tasset: TLAsset\n\t\tfile: File\n\t}[] = []\n\tfor (const file of files) {\n\t\tconst isSuccess = notifyIfFileNotAllowed(editor, file, options)\n\t\tif (!isSuccess) continue\n\n\t\tconst sanitizedFile = await maybeSanitizeSvgFile(file)\n\t\tif (!sanitizedFile) {\n\t\t\ttoasts.addToast({\n\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\tseverity: 'error',\n\t\t\t})\n\t\t\tcontinue\n\t\t}\n\t\t// An undecodable image rejects here; uncaught, it aborts the whole drop,\n\t\t// including files that already succeeded, with no toast (#10438).\n\t\tlet assetInfo: TLAsset | null\n\t\ttry {\n\t\t\tassetInfo = await getAssetInfo(editor, sanitizedFile)\n\t\t} catch (error) {\n\t\t\ttoasts.addToast({\n\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\tseverity: 'error',\n\t\t\t})\n\t\t\tconsole.error(error)\n\t\t\tcontinue\n\t\t}\n\t\tif (!assetInfo) continue\n\t\tif (assetInfo.type === 'image') {\n\t\t\teditor.createTemporaryAssetPreview(assetInfo.id, sanitizedFile)\n\t\t}\n\t\tassetPartials.push(assetInfo)\n\t\tassetsToUpdate.push({ asset: assetInfo, file: sanitizedFile })\n\t}\n\n\tPromise.allSettled(\n\t\tassetsToUpdate.map(async (assetAndFile) => {\n\t\t\ttry {\n\t\t\t\tconst newAsset = await editor.getAssetForExternalContent({\n\t\t\t\t\ttype: 'file',\n\t\t\t\t\tfile: assetAndFile.file,\n\t\t\t\t})\n\n\t\t\t\tif (!newAsset) {\n\t\t\t\t\tthrow Error('Could not create an asset')\n\t\t\t\t}\n\n\t\t\t\t// Save the new asset under the old asset's id\n\t\t\t\teditor.updateAssets([{ ...newAsset, id: assetAndFile.asset.id }])\n\t\t\t} catch (error) {\n\t\t\t\ttoasts.addToast({\n\t\t\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\t\t\tseverity: 'error',\n\t\t\t\t})\n\t\t\t\tconsole.error(error)\n\t\t\t\teditor.deleteAssets([assetAndFile.asset.id])\n\t\t\t\treturn\n\t\t\t}\n\t\t})\n\t)\n\n\tcreateShapesForAssets(editor, assetPartials, pagePoint)\n}\n\n/** @public */\nexport async function defaultHandleExternalTextContent(\n\teditor: Editor,\n\t{ point, text, html }: { point?: VecLike; text: string; html?: string }\n) {\n\tconst p =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\tconst defaultProps = editor.getShapeUtil<TLTextShape>('text').getDefaultProps()\n\n\tconst cleanedUpPlaintext = cleanupText(text)\n\tconst richTextToPaste = html\n\t\t? renderRichTextFromHTML(editor, html)\n\t\t: toRichText(cleanedUpPlaintext)\n\n\t// todo: discuss\n\t// If we have one shape with rich text selected, update the shape's text.\n\t// const onlySelectedShape = editor.getOnlySelectedShape()\n\t// if (onlySelectedShape && 'richText' in onlySelectedShape.props) {\n\t// \teditor.updateShapes([\n\t// \t\t{\n\t// \t\t\tid: onlySelectedShape.id,\n\t// \t\t\ttype: onlySelectedShape.type,\n\t// \t\t\tprops: {\n\t// \t\t\t\trichText: richTextToPaste,\n\t// \t\t\t},\n\t// \t\t},\n\t// \t])\n\n\t// \treturn\n\t// }\n\n\t// Measure the text with default values\n\tlet w: number\n\tlet h: number\n\tlet autoSize: boolean\n\tlet align = 'middle' as TLTextShapeProps['textAlign']\n\n\tconst htmlToMeasure = renderHtmlFromRichTextForMeasurement(editor, richTextToPaste)\n\tconst isMultiLine = richTextToPaste.content.length > 1\n\n\t// check whether the text contains the most common characters in RTL languages\n\tconst isRtl = isRightToLeftLanguage(cleanedUpPlaintext)\n\n\tif (isMultiLine) {\n\t\talign = isMultiLine ? (isRtl ? 'end' : 'start') : 'middle'\n\t}\n\n\tconst theme = editor.getCurrentTheme()\n\n\tconst rawSize = editor.textMeasure.measureHtml(htmlToMeasure, {\n\t\t...TEXT_PROPS,\n\t\tlineHeight: theme.lineHeight,\n\t\tfontFamily: getFontFamily(theme, defaultProps.font),\n\t\tfontSize: theme.fontSize * FONT_SIZES[defaultProps.size],\n\t\tmaxWidth: null,\n\t})\n\n\tconst minWidth = Math.min(\n\t\tisMultiLine ? editor.getViewportPageBounds().width * 0.9 : 920,\n\t\tMath.max(200, editor.getViewportPageBounds().width * 0.9)\n\t)\n\n\tif (rawSize.w > minWidth) {\n\t\tconst shrunkSize = editor.textMeasure.measureHtml(htmlToMeasure, {\n\t\t\t...TEXT_PROPS,\n\t\t\tlineHeight: theme.lineHeight,\n\t\t\tfontFamily: getFontFamily(theme, defaultProps.font),\n\t\t\tfontSize: theme.fontSize * FONT_SIZES[defaultProps.size],\n\t\t\tmaxWidth: minWidth,\n\t\t})\n\t\tw = shrunkSize.w\n\t\th = shrunkSize.h\n\t\tautoSize = false\n\t\talign = isRtl ? 'end' : 'start'\n\t} else {\n\t\t// autosize is fine\n\t\tw = Math.max(rawSize.w, 10)\n\t\th = Math.max(rawSize.h, 10)\n\t\tautoSize = true\n\t}\n\n\tif (p.y - h / 2 < editor.getViewportPageBounds().minY + 40) {\n\t\tp.y = editor.getViewportPageBounds().minY + 40 + h / 2\n\t}\n\n\tconst newPoint = maybeSnapToGrid(new Vec(p.x - w / 2, p.y - h / 2), editor)\n\tconst shapeId = createShapeId()\n\n\teditor.run(() => {\n\t\t// Allow this to trigger the max shapes reached alert\n\t\teditor.createShapes([\n\t\t\t{\n\t\t\t\tid: shapeId,\n\t\t\t\ttype: 'text',\n\t\t\t\tx: newPoint.x,\n\t\t\t\ty: newPoint.y,\n\t\t\t\tprops: {\n\t\t\t\t\trichText: richTextToPaste,\n\t\t\t\t\t// if the text has more than one line, align it to the left\n\t\t\t\t\ttextAlign: align,\n\t\t\t\t\tautoSize,\n\t\t\t\t\tw,\n\t\t\t\t},\n\t\t\t},\n\t\t])\n\n\t\t// createShapes silently creates nothing when the page is full, so only\n\t\t// select the shape if it actually exists\n\t\tif (editor.getShape(shapeId)) {\n\t\t\teditor.select(shapeId)\n\t\t}\n\t})\n}\n\n/** @public */\nexport async function defaultHandleExternalUrlContent(\n\teditor: Editor,\n\t{ point, url }: { point?: VecLike; url: string },\n\t{ toasts, msg }: TLDefaultExternalContentHandlerOpts\n) {\n\t// Bookmark shapes validate their `url` prop with T.linkUrl, so a url we can't\n\t// turn into a bookmark would throw a ValidationError and crash the editor\n\t// (#8097) \u2014 e.g. Chrome with an ad blocker active rewrites dragged content\n\t// urls to `about:blank#blocked`. This is a known, handled condition rather\n\t// than a bug, so we tell the user with a toast and warn (not error) with the\n\t// offending url as a local debugging breadcrumb \u2014 deliberately not reported\n\t// to error tracking, where it would just be non-actionable noise.\n\tif (!T.linkUrl.isValid(url)) {\n\t\tconsole.warn(`Could not create a bookmark from an invalid url: ${JSON.stringify(url)}`)\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.url.failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn\n\t}\n\n\t// try to paste as an embed first\n\tconst embedUtil = editor.getShapeUtil('embed') as EmbedShapeUtil | undefined\n\tconst embedInfo = embedUtil?.getEmbedDefinition(url)\n\n\tif (embedInfo && embedInfo.definition.embedOnPaste !== false) {\n\t\treturn editor.putExternalContent({\n\t\t\ttype: 'embed',\n\t\t\turl: embedInfo.url,\n\t\t\tpoint,\n\t\t\tembed: embedInfo.definition,\n\t\t})\n\t}\n\n\tconst position =\n\t\tpoint ??\n\t\t(editor.inputs.getShiftKey()\n\t\t\t? editor.inputs.getCurrentPagePoint()\n\t\t\t: editor.getViewportPageBounds().center)\n\n\t// Use the new function to create the bookmark\n\tconst result = await createBookmarkFromUrl(editor, { url, center: position })\n\n\tif (!result.ok) {\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.url.failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn\n\t}\n\n\teditor.select(result.value.id)\n}\n\n/** @public */\nexport async function defaultHandleExternalTldrawContent(\n\teditor: Editor,\n\t{ point, content }: { point?: VecLike; content: TLContent }\n) {\n\teditor.run(() => {\n\t\tconst selectionBoundsBefore = editor.getSelectionPageBounds()\n\t\teditor.markHistoryStoppingPoint('paste')\n\n\t\t// Unlock any locked root shapes on paste\n\t\tfor (const shape of content.shapes) {\n\t\t\tif (content.rootShapeIds.includes(shape.id)) {\n\t\t\t\tshape.isLocked = false\n\t\t\t}\n\t\t}\n\n\t\t// While the user is mid-interaction (dragging a handle, translating,\n\t\t// resizing, or rotating), selecting the pasted content would steal the\n\t\t// selection from the shape being manipulated and interrupt the\n\t\t// interaction \u2014 e.g. an arrow's in-progress binding hint disappears\n\t\t// until the drag ends. Leave the selection alone in those cases.\n\t\tconst isMidInteraction = editor.isInAny(\n\t\t\t'select.dragging_handle',\n\t\t\t'select.translating',\n\t\t\t'select.resizing',\n\t\t\t'select.rotating'\n\t\t)\n\n\t\teditor.putContentOntoCurrentPage(content, {\n\t\t\tpoint: point,\n\t\t\tselect: !isMidInteraction,\n\t\t})\n\t\tconst selectedBoundsAfter = editor.getSelectionPageBounds()\n\t\tif (\n\t\t\t// When mid-interaction we don't select the pasted content, so the\n\t\t\t// selection is unchanged and the before/after bounds are identical \u2014\n\t\t\t// the overlap check would always pass. The selection flash below\n\t\t\t// signals that the newly-selected pasted content landed on the old\n\t\t\t// selection, which is meaningless when we didn't change the\n\t\t\t// selection, so skip it.\n\t\t\t!isMidInteraction &&\n\t\t\tselectionBoundsBefore &&\n\t\t\tselectedBoundsAfter &&\n\t\t\tselectionBoundsBefore?.collides(selectedBoundsAfter)\n\t\t) {\n\t\t\t// Creates a 'puff' to show content has been pasted\n\t\t\teditor.updateInstanceState({ isChangingStyle: true })\n\t\t\teditor.timers.setTimeout(() => {\n\t\t\t\teditor.updateInstanceState({ isChangingStyle: false })\n\t\t\t}, 150)\n\t\t}\n\t})\n}\n\n/** @public */\nexport async function defaultHandleExternalExcalidrawContent(\n\teditor: Editor,\n\t{ point, content }: { point?: VecLike; content: any }\n) {\n\teditor.run(() => {\n\t\tputExcalidrawContent(editor, content, point)\n\t})\n}\n\n/**\n * A helper function for an external content handler. It creates bookmarks,\n * images or video shapes corresponding to the type of assets provided.\n *\n * @param editor - The editor instance\n *\n * @param assets - An array of asset Ids\n *\n * @param position - the position at which to create the shapes\n *\n * @public\n */\nexport async function createShapesForAssets(\n\teditor: Editor,\n\tassets: TLAsset[],\n\tposition: VecLike\n): Promise<TLShapeId[]> {\n\tif (!assets.length) return []\n\n\tconst currentPoint = Vec.From(position)\n\tconst partials: TLShapePartial[] = []\n\n\tfor (let i = 0; i < assets.length; i++) {\n\t\tconst asset = assets[i]\n\t\tconst shapeUtil = editor.getShapeUtilForAssetType(asset.type)\n\t\tconst partial = shapeUtil?.createShapeForAsset?.(asset, currentPoint) ?? null\n\t\tif (partial) {\n\t\t\tpartials.push(partial)\n\t\t\tif ('w' in asset.props && typeof asset.props.w === 'number') {\n\t\t\t\tcurrentPoint.x += asset.props.w\n\t\t\t}\n\t\t}\n\t}\n\n\teditor.run(() => {\n\t\t// Create any assets\n\t\tconst assetsToCreate = assets.filter((asset) => !editor.getAsset(asset.id))\n\n\t\teditor.store.atomic(() => {\n\t\t\tif (editor.canCreateShapes(partials)) {\n\t\t\t\tif (assetsToCreate.length) {\n\t\t\t\t\teditor.createAssets(assetsToCreate)\n\t\t\t\t}\n\n\t\t\t\t// Create the shapes\n\t\t\t\teditor.createShapes(partials).select(...partials.map((p) => p.id))\n\n\t\t\t\t// Re-position shapes so that the center of the group is at the provided point\n\t\t\t\tcenterSelectionAroundPoint(editor, position)\n\t\t\t}\n\t\t})\n\t})\n\n\treturn partials.map((p) => p.id)\n}\n\n/**\n * Repositions selected shapes do that the center of the group is\n * at the provided position\n *\n * @param editor - The editor instance\n *\n * @param position - the point to center the shapes around\n *\n * @public\n */\nexport function centerSelectionAroundPoint(editor: Editor, position: VecLike) {\n\t// Re-position shapes so that the center of the group is at the provided point\n\tconst viewportPageBounds = editor.getViewportPageBounds()\n\tlet selectionPageBounds = editor.getSelectionPageBounds()\n\n\tif (selectionPageBounds) {\n\t\tconst offset = selectionPageBounds!.center.sub(position)\n\n\t\teditor.updateShapes(\n\t\t\teditor.getSelectedShapes().map((shape) => {\n\t\t\t\tconst localRotation = editor.getShapeParentTransform(shape).decompose().rotation\n\t\t\t\tconst localDelta = Vec.Rot(offset, -localRotation)\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: shape.x! - localDelta.x,\n\t\t\t\t\ty: shape.y! - localDelta.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t}\n\tselectionPageBounds = editor.getSelectionPageBounds()\n\t// align selection with the grid if necessary\n\tif (selectionPageBounds && editor.getInstanceState().isGridMode) {\n\t\tconst gridSize = editor.getDocumentSettings().gridSize\n\t\tconst topLeft = new Vec(selectionPageBounds.minX, selectionPageBounds.minY)\n\t\tconst gridSnappedPoint = topLeft.clone().snapToGrid(gridSize)\n\t\tconst delta = Vec.Sub(topLeft, gridSnappedPoint)\n\t\teditor.updateShapes(\n\t\t\teditor.getSelectedShapes().map((shape) => {\n\t\t\t\tconst newPoint = { x: shape.x! - delta.x, y: shape.y! - delta.y }\n\t\t\t\treturn {\n\t\t\t\t\tid: shape.id,\n\t\t\t\t\ttype: shape.type,\n\t\t\t\t\tx: newPoint.x,\n\t\t\t\t\ty: newPoint.y,\n\t\t\t\t}\n\t\t\t})\n\t\t)\n\t}\n\t// Zoom out to fit the shapes, if necessary\n\tselectionPageBounds = editor.getSelectionPageBounds()\n\tif (selectionPageBounds && !viewportPageBounds.contains(selectionPageBounds)) {\n\t\teditor.zoomToSelection({ animation: { duration: editor.options.animationMediumMs } })\n\t}\n}\n\n/** @public */\nexport function createEmptyBookmarkShape(\n\teditor: Editor,\n\turl: string,\n\tposition: VecLike\n): TLBookmarkShape {\n\tconst partial: TLShapePartial = {\n\t\tid: createShapeId(),\n\t\ttype: 'bookmark',\n\t\tx: position.x - 150,\n\t\ty: position.y - 160,\n\t\topacity: 1,\n\t\tprops: {\n\t\t\tassetId: null,\n\t\t\turl,\n\t\t},\n\t}\n\n\teditor.run(() => {\n\t\t// Allow this to trigger the max shapes reached alert\n\t\teditor.createShape(partial)\n\t\tif (!editor.getShape(partial.id)) return\n\t\teditor.select(partial.id)\n\t\tcenterSelectionAroundPoint(editor, position)\n\t})\n\n\treturn editor.getShape(partial.id) as TLBookmarkShape\n}\n\nasync function maybeSanitizeSvgFile(file: File): Promise<File | null> {\n\tif (file.type !== 'image/svg+xml') return file\n\ttry {\n\t\tconst text = await file.text()\n\t\tconst { sanitizeSvg } = await import('./utils/svg/sanitizeSvg')\n\t\tconst sanitized = sanitizeSvg(text)\n\t\tif (!sanitized) return null\n\t\treturn new File([sanitized], file.name, { type: file.type, lastModified: file.lastModified })\n\t} catch {\n\t\treturn null\n\t}\n}\n\n/**\n * Checks if a file is allowed to be uploaded. If it is not, it will show a toast explaining why to the user.\n *\n * @param editor - The editor instance\n * @param file - The file to check\n * @param options - The options for the external content handler\n * @returns True if the file is allowed, false otherwise\n * @public\n */\nexport function notifyIfFileNotAllowed(\n\teditor: Editor,\n\tfile: File,\n\toptions: TLDefaultExternalContentHandlerOpts\n) {\n\tconst {\n\t\tmaxAssetSize = DEFAULT_MAX_ASSET_SIZE,\n\t\tacceptedImageMimeTypes,\n\t\tacceptedVideoMimeTypes,\n\t\ttoasts,\n\t\tmsg,\n\t} = options\n\n\t// Allow if any registered asset util accepts the MIME type, or if it matches\n\t// an explicit allow-list. The asset-util branch lets custom AssetUtils\n\t// (e.g. for PDFs) extend the default media handling \u2014 without it, files\n\t// registered via `assetUtils` would be rejected because <Tldraw> forwards\n\t// `DEFAULT_SUPPORTED_IMAGE_TYPES` / `DEFAULT_SUPPORT_VIDEO_TYPES` here, and\n\t// custom MIME types aren't in those lists. The explicit-list branch supports\n\t// callers that pass these props directly to restrict allowed types.\n\tconst isFileTypeAllowed =\n\t\t!!editor.getAssetUtilForMimeType(file.type) ||\n\t\t(acceptedImageMimeTypes?.includes(file.type) ?? false) ||\n\t\t(acceptedVideoMimeTypes?.includes(file.type) ?? false)\n\tif (!isFileTypeAllowed) {\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.files.type-not-allowed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn false\n\t}\n\n\tif (file.size > maxAssetSize) {\n\t\tconst formatBytes = (bytes: number): string => {\n\t\t\tif (bytes === 0) return '0 bytes'\n\n\t\t\tconst units = ['bytes', 'KB', 'MB', 'GB', 'TB', 'PB']\n\t\t\tconst base = 1024\n\t\t\tconst unitIndex = Math.floor(Math.log(bytes) / Math.log(base))\n\n\t\t\tconst value = bytes / Math.pow(base, unitIndex)\n\t\t\tconst formatted = value % 1 === 0 ? value.toString() : value.toFixed(1)\n\n\t\t\treturn `${formatted} ${units[unitIndex]}`\n\t\t}\n\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.files.size-too-big'),\n\t\t\tdescription: msg('assets.files.maximum-size').replace('{size}', formatBytes(maxAssetSize)),\n\t\t\tseverity: 'error',\n\t\t})\n\t\treturn false\n\t}\n\n\t// Use mime type instead of file ext, this is because\n\t// window.navigator.clipboard does not preserve file names\n\t// of copied files.\n\tif (!file.type) {\n\t\ttoasts.addToast({\n\t\t\ttitle: msg('assets.files.upload-failed'),\n\t\t\tseverity: 'error',\n\t\t})\n\t\tconsole.error('No mime type')\n\t\treturn false\n\t}\n\n\treturn true\n}\n\n/** @public */\nexport async function getAssetInfo(editor: Editor, file: File, assetId?: TLAssetId) {\n\tif (!assetId) {\n\t\tconst hash = getHashForBuffer(await file.arrayBuffer())\n\t\tassetId = AssetRecordType.createId(hash)\n\t}\n\n\tconst assetUtil = editor.getAssetUtilForMimeType(file.type)\n\tif (!assetUtil) return null\n\n\treturn await assetUtil.getAssetFromFile(file, assetId)\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -126,7 +126,7 @@ function getCurvedArrowInfo(editor, shape, bindings, arrowStrokeWidth) {
126
126
  );
127
127
  startShapeInfo.didIntersect = true;
128
128
  if (arrowheadStart !== "none") {
129
- const strokeOffset = arrowSW / 2 + ("size" in startShapeInfo.shape.props ? theme.strokeWidth * import_default_shape_constants.STROKE_SIZES[startShapeInfo.shape.props.size] / 2 : 0);
129
+ const strokeOffset = arrowSW / 2 + ("size" in startShapeInfo.shape.props ? theme.strokeWidth * (import_default_shape_constants.STROKE_SIZES[startShapeInfo.shape.props.size] ?? 0) / 2 : 0);
130
130
  offsetA = (import_shared.BOUND_ARROW_OFFSET + strokeOffset) * shape.props.scale;
131
131
  minLength += strokeOffset * shape.props.scale;
132
132
  }
@@ -180,7 +180,7 @@ function getCurvedArrowInfo(editor, shape, bindings, arrowStrokeWidth) {
180
180
  );
181
181
  endShapeInfo.didIntersect = true;
182
182
  if (arrowheadEnd !== "none") {
183
- const strokeOffset = arrowSW / 2 + ("size" in endShapeInfo.shape.props ? theme.strokeWidth * import_default_shape_constants.STROKE_SIZES[endShapeInfo.shape.props.size] / 2 : 0);
183
+ const strokeOffset = arrowSW / 2 + ("size" in endShapeInfo.shape.props ? theme.strokeWidth * (import_default_shape_constants.STROKE_SIZES[endShapeInfo.shape.props.size] ?? 0) / 2 : 0);
184
184
  offsetB = (import_shared.BOUND_ARROW_OFFSET + strokeOffset) * shape.props.scale;
185
185
  minLength += strokeOffset * shape.props.scale;
186
186
  }