tldraw 5.2.0-next.e2b8d10bf10e → 5.2.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 (420) hide show
  1. package/DOCS.md +20294 -0
  2. package/README.md +13 -1
  3. package/RELEASE_NOTES.md +2908 -0
  4. package/dist-cjs/index.d.ts +110 -23
  5. package/dist-cjs/index.js +3 -3
  6. package/dist-cjs/index.js.map +2 -2
  7. package/dist-cjs/lib/TldrawImage.js +0 -1
  8. package/dist-cjs/lib/TldrawImage.js.map +2 -2
  9. package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js +2 -1
  10. package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
  11. package/dist-cjs/lib/defaultEmbedDefinitions.js +3 -2
  12. package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
  13. package/dist-cjs/lib/defaultOverlayUtils.js +11 -11
  14. package/dist-cjs/lib/defaultOverlayUtils.js.map +2 -2
  15. package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js +76 -64
  16. package/dist-cjs/lib/overlays/SelectionForegroundOverlayUtil.js.map +2 -2
  17. package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js +1 -1
  18. package/dist-cjs/lib/overlays/ShapeHandleOverlayUtil.js.map +2 -2
  19. package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js +107 -0
  20. package/dist-cjs/lib/overlays/ShapeIndicatorOverlayUtil.js.map +7 -0
  21. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +3 -0
  22. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  23. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +12 -3
  24. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  25. package/dist-cjs/lib/shapes/bookmark/bookmarks.js +54 -6
  26. package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
  27. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +2 -1
  28. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  29. package/dist-cjs/lib/shapes/draw/getPath.js +1 -1
  30. package/dist-cjs/lib/shapes/draw/getPath.js.map +2 -2
  31. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +45 -47
  32. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +2 -2
  33. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +2 -1
  34. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
  35. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js +23 -18
  36. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +2 -2
  37. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +1 -1
  38. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  39. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +3 -0
  40. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
  41. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +11 -7
  42. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  43. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +3 -11
  44. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +2 -2
  45. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +5 -1
  46. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
  47. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +31 -41
  48. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  49. package/dist-cjs/lib/shapes/note/noteHelpers.js +1 -1
  50. package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
  51. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +28 -6
  52. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
  53. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +3 -2
  54. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +2 -2
  55. package/dist-cjs/lib/shapes/shared/RichTextLabel.js +3 -3
  56. package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +2 -2
  57. package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js +17 -3
  58. package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js.map +2 -2
  59. package/dist-cjs/lib/shapes/shared/freehand/core.js +424 -0
  60. package/dist-cjs/lib/shapes/shared/freehand/core.js.map +7 -0
  61. package/dist-cjs/lib/shapes/shared/freehand/fmt.js +106 -0
  62. package/dist-cjs/lib/shapes/shared/freehand/fmt.js.map +7 -0
  63. package/dist-cjs/lib/shapes/shared/freehand/getStroke.js +6 -6
  64. package/dist-cjs/lib/shapes/shared/freehand/getStroke.js.map +2 -2
  65. package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js +320 -86
  66. package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js.map +3 -3
  67. package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js +20 -96
  68. package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js.map +3 -3
  69. package/dist-cjs/lib/shapes/shared/freehand/svg.js +55 -19
  70. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +2 -2
  71. package/dist-cjs/lib/shapes/shared/freehand/svgInk.js +189 -97
  72. package/dist-cjs/lib/shapes/shared/freehand/svgInk.js.map +3 -3
  73. package/dist-cjs/lib/shapes/shared/freehand/types.js.map +1 -1
  74. package/dist-cjs/lib/shapes/shared/interpolate-props.js +6 -2
  75. package/dist-cjs/lib/shapes/shared/interpolate-props.js.map +2 -2
  76. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +3 -0
  77. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
  78. package/dist-cjs/lib/tools/HandTool/HandTool.js +16 -6
  79. package/dist-cjs/lib/tools/HandTool/HandTool.js.map +2 -2
  80. package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js +10 -1
  81. package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js.map +2 -2
  82. package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js +84 -0
  83. package/dist-cjs/lib/tools/HandTool/childStates/OneFingerZooming.js.map +7 -0
  84. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +12 -0
  85. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  86. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +4 -0
  87. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
  88. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +107 -46
  89. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  90. package/dist-cjs/lib/ui/TldrawUi.js +4 -3
  91. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  92. package/dist-cjs/lib/ui/components/A11y.js +2 -0
  93. package/dist-cjs/lib/ui/components/A11y.js.map +2 -2
  94. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +14 -1
  95. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
  96. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js +0 -6
  97. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenuContent.js.map +2 -2
  98. package/dist-cjs/lib/ui/components/DefaultFollowingIndicator.js.map +2 -2
  99. package/dist-cjs/lib/ui/components/Dialogs.js +17 -37
  100. package/dist-cjs/lib/ui/components/Dialogs.js.map +2 -2
  101. package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js +19 -4
  102. package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js.map +2 -2
  103. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js +12 -2
  104. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.js.map +2 -2
  105. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +47 -70
  106. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  107. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js +25 -46
  108. package/dist-cjs/lib/ui/components/Minimap/MinimapManager.js.map +2 -2
  109. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.js.map +2 -2
  110. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuContent.js.map +2 -2
  111. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.js.map +2 -2
  112. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js +1 -1
  113. package/dist-cjs/lib/ui/components/SharePanel/DefaultPeopleMenuItem.js.map +2 -2
  114. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js +1 -0
  115. package/dist-cjs/lib/ui/components/StylePanel/StylePanelButtonPicker.js.map +2 -2
  116. package/dist-cjs/lib/ui/components/menu-items.js +7 -0
  117. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  118. package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js +2 -1
  119. package/dist-cjs/lib/ui/components/primitives/TldrawUiDropdownMenu.js.map +2 -2
  120. package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js +14 -3
  121. package/dist-cjs/lib/ui/components/primitives/TldrawUiIcon.js.map +2 -2
  122. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js +2 -0
  123. package/dist-cjs/lib/ui/components/primitives/TldrawUiInput.js.map +2 -2
  124. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js +2 -0
  125. package/dist-cjs/lib/ui/components/primitives/TldrawUiPopover.js.map +2 -2
  126. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js +0 -2
  127. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.js.map +2 -2
  128. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js +1 -2
  129. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.js.map +2 -2
  130. package/dist-cjs/lib/ui/context/actions.js +70 -1
  131. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  132. package/dist-cjs/lib/ui/context/asset-urls.js +5 -8
  133. package/dist-cjs/lib/ui/context/asset-urls.js.map +2 -2
  134. package/dist-cjs/lib/ui/context/events.js.map +2 -2
  135. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +13 -0
  136. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js.map +2 -2
  137. package/dist-cjs/lib/ui/hooks/useTools.js +1 -1
  138. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  139. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +1 -1
  140. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +2 -0
  141. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +2 -2
  142. package/dist-cjs/lib/ui/version.js +3 -3
  143. package/dist-cjs/lib/ui/version.js.map +1 -1
  144. package/dist-cjs/lib/utils/embeds/embeds.js +4 -4
  145. package/dist-cjs/lib/utils/embeds/embeds.js.map +2 -2
  146. package/dist-cjs/lib/utils/test-helpers.js +2 -2
  147. package/dist-cjs/lib/utils/test-helpers.js.map +2 -2
  148. package/dist-cjs/lib/utils/text/richText.js +3 -1
  149. package/dist-cjs/lib/utils/text/richText.js.map +2 -2
  150. package/dist-esm/index.d.mts +110 -23
  151. package/dist-esm/index.mjs +5 -3
  152. package/dist-esm/index.mjs.map +2 -2
  153. package/dist-esm/lib/TldrawImage.mjs +0 -1
  154. package/dist-esm/lib/TldrawImage.mjs.map +2 -2
  155. package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs +2 -1
  156. package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
  157. package/dist-esm/lib/defaultEmbedDefinitions.mjs +3 -2
  158. package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
  159. package/dist-esm/lib/defaultOverlayUtils.mjs +11 -11
  160. package/dist-esm/lib/defaultOverlayUtils.mjs.map +2 -2
  161. package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs +77 -65
  162. package/dist-esm/lib/overlays/SelectionForegroundOverlayUtil.mjs.map +2 -2
  163. package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs +1 -1
  164. package/dist-esm/lib/overlays/ShapeHandleOverlayUtil.mjs.map +2 -2
  165. package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs +87 -0
  166. package/dist-esm/lib/overlays/ShapeIndicatorOverlayUtil.mjs.map +7 -0
  167. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +9 -1
  168. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  169. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +15 -3
  170. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  171. package/dist-esm/lib/shapes/bookmark/bookmarks.mjs +54 -6
  172. package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
  173. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +3 -1
  174. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  175. package/dist-esm/lib/shapes/draw/getPath.mjs +1 -1
  176. package/dist-esm/lib/shapes/draw/getPath.mjs.map +2 -2
  177. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +46 -47
  178. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +2 -2
  179. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +2 -1
  180. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
  181. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs +23 -18
  182. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +2 -2
  183. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +2 -1
  184. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  185. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +4 -0
  186. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
  187. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +12 -7
  188. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  189. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +3 -11
  190. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +2 -2
  191. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +6 -1
  192. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
  193. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +32 -42
  194. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  195. package/dist-esm/lib/shapes/note/noteHelpers.mjs +1 -1
  196. package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
  197. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +29 -6
  198. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
  199. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +3 -2
  200. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  201. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +4 -3
  202. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
  203. package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs +17 -3
  204. package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs.map +2 -2
  205. package/dist-esm/lib/shapes/shared/freehand/core.mjs +404 -0
  206. package/dist-esm/lib/shapes/shared/freehand/core.mjs.map +7 -0
  207. package/dist-esm/lib/shapes/shared/freehand/fmt.mjs +86 -0
  208. package/dist-esm/lib/shapes/shared/freehand/fmt.mjs.map +7 -0
  209. package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs +7 -7
  210. package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs.map +2 -2
  211. package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs +332 -86
  212. package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs.map +3 -3
  213. package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs +31 -96
  214. package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs.map +3 -3
  215. package/dist-esm/lib/shapes/shared/freehand/svg.mjs +55 -19
  216. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +2 -2
  217. package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs +214 -99
  218. package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs.map +3 -3
  219. package/dist-esm/lib/shapes/shared/interpolate-props.mjs +6 -2
  220. package/dist-esm/lib/shapes/shared/interpolate-props.mjs.map +2 -2
  221. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +4 -0
  222. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
  223. package/dist-esm/lib/tools/HandTool/HandTool.mjs +16 -6
  224. package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +2 -2
  225. package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs +10 -1
  226. package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs.map +2 -2
  227. package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs +64 -0
  228. package/dist-esm/lib/tools/HandTool/childStates/OneFingerZooming.mjs.map +7 -0
  229. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +12 -0
  230. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  231. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +4 -0
  232. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
  233. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +108 -46
  234. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  235. package/dist-esm/lib/ui/TldrawUi.mjs +4 -3
  236. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  237. package/dist-esm/lib/ui/components/A11y.mjs +2 -0
  238. package/dist-esm/lib/ui/components/A11y.mjs.map +2 -2
  239. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +21 -2
  240. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
  241. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs +0 -6
  242. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenuContent.mjs.map +2 -2
  243. package/dist-esm/lib/ui/components/DefaultFollowingIndicator.mjs.map +2 -2
  244. package/dist-esm/lib/ui/components/Dialogs.mjs +19 -39
  245. package/dist-esm/lib/ui/components/Dialogs.mjs.map +2 -2
  246. package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs +20 -5
  247. package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs.map +2 -2
  248. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs +12 -2
  249. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.mjs.map +2 -2
  250. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +47 -70
  251. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  252. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs +25 -46
  253. package/dist-esm/lib/ui/components/Minimap/MinimapManager.mjs.map +2 -2
  254. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.mjs.map +2 -2
  255. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuContent.mjs.map +2 -2
  256. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.mjs.map +2 -2
  257. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs +1 -1
  258. package/dist-esm/lib/ui/components/SharePanel/DefaultPeopleMenuItem.mjs.map +2 -2
  259. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs +1 -0
  260. package/dist-esm/lib/ui/components/StylePanel/StylePanelButtonPicker.mjs.map +2 -2
  261. package/dist-esm/lib/ui/components/menu-items.mjs +7 -0
  262. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  263. package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs +2 -1
  264. package/dist-esm/lib/ui/components/primitives/TldrawUiDropdownMenu.mjs.map +2 -2
  265. package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs +14 -3
  266. package/dist-esm/lib/ui/components/primitives/TldrawUiIcon.mjs.map +2 -2
  267. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs +2 -0
  268. package/dist-esm/lib/ui/components/primitives/TldrawUiInput.mjs.map +2 -2
  269. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs +2 -0
  270. package/dist-esm/lib/ui/components/primitives/TldrawUiPopover.mjs.map +2 -2
  271. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs +0 -2
  272. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.mjs.map +2 -2
  273. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs +1 -2
  274. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.mjs.map +2 -2
  275. package/dist-esm/lib/ui/context/actions.mjs +71 -1
  276. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  277. package/dist-esm/lib/ui/context/asset-urls.mjs +5 -8
  278. package/dist-esm/lib/ui/context/asset-urls.mjs.map +2 -2
  279. package/dist-esm/lib/ui/context/events.mjs.map +2 -2
  280. package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs +13 -0
  281. package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs.map +2 -2
  282. package/dist-esm/lib/ui/hooks/useTools.mjs +1 -1
  283. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  284. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +2 -0
  285. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +2 -2
  286. package/dist-esm/lib/ui/version.mjs +3 -3
  287. package/dist-esm/lib/ui/version.mjs.map +1 -1
  288. package/dist-esm/lib/utils/embeds/embeds.mjs +4 -4
  289. package/dist-esm/lib/utils/embeds/embeds.mjs.map +2 -2
  290. package/dist-esm/lib/utils/test-helpers.mjs +2 -2
  291. package/dist-esm/lib/utils/test-helpers.mjs.map +2 -2
  292. package/dist-esm/lib/utils/text/richText.mjs +3 -1
  293. package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
  294. package/package.json +11 -6
  295. package/src/index.ts +6 -1
  296. package/src/lib/TldrawImage.tsx +2 -2
  297. package/src/lib/bindings/arrow/ArrowBindingUtil.ts +5 -1
  298. package/src/lib/defaultEmbedDefinitions.ts +28 -6
  299. package/src/lib/defaultOverlayUtils.ts +11 -11
  300. package/src/lib/overlays/SelectionForegroundOverlayUtil.ts +91 -72
  301. package/src/lib/overlays/ShapeHandleOverlayUtil.ts +3 -1
  302. package/src/lib/overlays/ShapeIndicatorOverlayUtil.ts +133 -0
  303. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +11 -1
  304. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +16 -3
  305. package/src/lib/shapes/bookmark/bookmarks.ts +105 -15
  306. package/src/lib/shapes/draw/DrawShapeUtil.tsx +7 -5
  307. package/src/lib/shapes/draw/getPath.ts +1 -1
  308. package/src/lib/shapes/draw/toolStates/Drawing.ts +55 -48
  309. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +14 -4
  310. package/src/lib/shapes/frame/FrameShapeTool.ts +35 -24
  311. package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +46 -0
  312. package/src/lib/shapes/geo/GeoShapeUtil.tsx +2 -1
  313. package/src/lib/shapes/geo/toolStates/Pointing.ts +5 -0
  314. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +14 -11
  315. package/src/lib/shapes/image/ImageShapeUtil.tsx +7 -11
  316. package/src/lib/shapes/line/LineShapeTool.test.ts +41 -0
  317. package/src/lib/shapes/line/toolStates/Pointing.ts +12 -2
  318. package/src/lib/shapes/note/NoteShapeUtil.tsx +36 -51
  319. package/src/lib/shapes/note/noteCloning.test.ts +5 -5
  320. package/src/lib/shapes/note/noteHelpers.ts +1 -1
  321. package/src/lib/shapes/note/toolStates/Pointing.ts +40 -7
  322. package/src/lib/shapes/shared/PlainTextLabel.tsx +3 -3
  323. package/src/lib/shapes/shared/RichTextLabel.tsx +4 -3
  324. package/src/lib/shapes/shared/defaultStyleDefs.tsx +25 -3
  325. package/src/lib/shapes/shared/freehand/core.ts +547 -0
  326. package/src/lib/shapes/shared/freehand/fmt.ts +106 -0
  327. package/src/lib/shapes/shared/freehand/getStroke.ts +7 -7
  328. package/src/lib/shapes/shared/freehand/getStrokeOutlinePoints.ts +451 -139
  329. package/src/lib/shapes/shared/freehand/getStrokePoints.ts +33 -153
  330. package/src/lib/shapes/shared/freehand/svg.ts +72 -23
  331. package/src/lib/shapes/shared/freehand/svgInk.ts +281 -136
  332. package/src/lib/shapes/shared/freehand/types.ts +0 -1
  333. package/src/lib/shapes/shared/interpolate-props.ts +6 -2
  334. package/src/lib/shapes/text/toolStates/Pointing.ts +5 -0
  335. package/src/lib/tools/HandTool/HandTool.ts +19 -6
  336. package/src/lib/tools/HandTool/childStates/Dragging.ts +17 -1
  337. package/src/lib/tools/HandTool/childStates/OneFingerZooming.ts +79 -0
  338. package/src/lib/tools/SelectTool/childStates/Idle.ts +16 -2
  339. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +8 -0
  340. package/src/lib/tools/SelectTool/childStates/Resizing.ts +137 -49
  341. package/src/lib/ui/TldrawUi.tsx +3 -3
  342. package/src/lib/ui/components/A11y.tsx +2 -0
  343. package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +32 -2
  344. package/src/lib/ui/components/ContextMenu/DefaultContextMenuContent.tsx +5 -6
  345. package/src/lib/ui/components/DefaultFollowingIndicator.tsx +2 -2
  346. package/src/lib/ui/components/Dialogs.tsx +20 -23
  347. package/src/lib/ui/components/HelperButtons/BackToContent.tsx +32 -4
  348. package/src/lib/ui/components/KeyboardShortcutsDialog/DefaultKeyboardShortcutsDialogContent.tsx +10 -0
  349. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +60 -74
  350. package/src/lib/ui/components/Minimap/MinimapManager.ts +35 -57
  351. package/src/lib/ui/components/SharePanel/DefaultPeopleMenuAvatar.tsx +2 -2
  352. package/src/lib/ui/components/SharePanel/DefaultPeopleMenuContent.tsx +2 -1
  353. package/src/lib/ui/components/SharePanel/DefaultPeopleMenuFacePile.tsx +2 -1
  354. package/src/lib/ui/components/SharePanel/DefaultPeopleMenuItem.tsx +3 -3
  355. package/src/lib/ui/components/StylePanel/StylePanelButtonPicker.tsx +5 -0
  356. package/src/lib/ui/components/menu-items.tsx +9 -0
  357. package/src/lib/ui/components/primitives/TldrawUiDropdownMenu.tsx +3 -1
  358. package/src/lib/ui/components/primitives/TldrawUiIcon.tsx +15 -3
  359. package/src/lib/ui/components/primitives/TldrawUiInput.tsx +4 -0
  360. package/src/lib/ui/components/primitives/TldrawUiPopover.tsx +7 -0
  361. package/src/lib/ui/components/primitives/menus/TldrawUiMenuCheckboxItem.tsx +0 -2
  362. package/src/lib/ui/components/primitives/menus/TldrawUiMenuSubmenu.tsx +0 -1
  363. package/src/lib/ui/context/actions.tsx +88 -1
  364. package/src/lib/ui/context/asset-urls.tsx +9 -8
  365. package/src/lib/ui/context/events.tsx +2 -0
  366. package/src/lib/ui/hooks/useKeyboardShortcuts.ts +45 -7
  367. package/src/lib/ui/hooks/useTools.tsx +7 -1
  368. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +2 -0
  369. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +2 -0
  370. package/src/lib/ui/version.ts +3 -3
  371. package/src/lib/ui.css +20 -9
  372. package/src/lib/utils/embeds/embeds.test.ts +14 -12
  373. package/src/lib/utils/embeds/embeds.ts +10 -4
  374. package/src/lib/utils/test-helpers.ts +3 -3
  375. package/src/lib/utils/text/richText.test.ts +36 -0
  376. package/src/lib/utils/text/richText.ts +9 -1
  377. package/src/test/HandTool.test.ts +93 -0
  378. package/src/test/ImageShapeUtil.test.ts +88 -0
  379. package/src/test/SelectTool.test.ts +102 -1
  380. package/src/test/__snapshots__/drawing.test.ts.snap +2 -1
  381. package/src/test/attribution.test.ts +40 -29
  382. package/src/test/bookmark-shapes.test.ts +256 -28
  383. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +2 -2
  384. package/src/test/commands/clipboardCallbacks.test.ts +3 -1
  385. package/src/test/commands/getSvgString.test.ts +30 -0
  386. package/src/test/commands/penmode.test.ts +97 -1
  387. package/src/test/commands/setCamera.test.ts +12 -0
  388. package/src/test/dragFromToolbar.test.ts +67 -0
  389. package/src/test/drawing.test.ts +48 -7
  390. package/src/test/frames.test.ts +72 -0
  391. package/src/test/freehand/corpus/presets.ts +71 -0
  392. package/src/test/freehand/corpus/real.ts +370 -0
  393. package/src/test/freehand/corpus/strokes.ts +50 -0
  394. package/src/test/freehand/svg.test.ts +20 -0
  395. package/src/test/freehand/wellformed.test.ts +30 -0
  396. package/src/test/long-press-create.test.ts +102 -0
  397. package/src/test/overlays/CollaboratorBrushOverlayUtil.test.ts +4 -4
  398. package/src/test/overlays/CollaboratorCursorOverlayUtil.test.ts +18 -18
  399. package/src/test/overlays/CollaboratorHintOverlayUtil.test.ts +7 -7
  400. package/src/test/overlays/CollaboratorScribbleOverlayUtil.test.ts +3 -3
  401. package/src/test/overlays/OverlayManager.test.ts +1 -1
  402. package/src/test/overlays/SelectionForegroundOverlayUtil.test.ts +58 -0
  403. package/src/test/overlays/ShapeHandleOverlayUtil.test.ts +2 -2
  404. package/src/test/overlays/ShapeIndicatorOverlayUtil.test.ts +36 -0
  405. package/src/test/resizing.test.ts +250 -0
  406. package/src/test/right-click-context-menu.test.ts +90 -0
  407. package/src/test/rightClickPanning.test.ts +11 -0
  408. package/src/test/selection-omnibus.test.ts +15 -2
  409. package/src/test/spatialIndex.test.ts +132 -0
  410. package/src/test/translating.test.ts +0 -6
  411. package/src/test/ui/ContextMenu.test.tsx +146 -3
  412. package/src/test/ui/Dialogs.test.tsx +256 -0
  413. package/src/test/ui/copyHoveredStyles.test.tsx +154 -0
  414. package/src/test/ui/keyboardShortcuts.test.tsx +266 -0
  415. package/tldraw.css +35 -12
  416. package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js +0 -100
  417. package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js.map +0 -7
  418. package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs +0 -80
  419. package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs.map +0 -7
  420. package/src/lib/shapes/shared/freehand/setStrokePointRadii.ts +0 -127
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/utils/embeds/embeds.ts"],
4
- "sourcesContent": ["import { safeParseUrl } from '@tldraw/editor'\nimport { TLEmbedDefinition } from '../../defaultEmbedDefinitions'\n\n// https://github.com/sindresorhus/escape-string-regexp/blob/main/index.js\nfunction escapeStringRegexp(string: string) {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError('Expected a string')\n\t}\n\n\t// Escape characters with special meaning either inside or outside character sets.\n\t// Use a simple backslash escape when it\u2019s always valid, and a `\\xnn` escape when the simpler form would be disallowed by Unicode patterns\u2019 stricter grammar.\n\treturn string.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d')\n}\n\n/** @public */\nexport function matchEmbedUrl(definitions: readonly TLEmbedDefinition[], url: string) {\n\tconst parsed = safeParseUrl(url)\n\tif (!parsed) return undefined\n\tconst host = parsed.host.replace('www.', '')\n\tfor (const localEmbedDef of definitions) {\n\t\tif (checkHostnames(localEmbedDef.hostnames, host)) {\n\t\t\tconst originalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\tif (originalUrl) {\n\t\t\t\treturn {\n\t\t\t\t\tdefinition: localEmbedDef,\n\t\t\t\t\turl: originalUrl,\n\t\t\t\t\tembedUrl: url,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined\n}\n\nconst globlikeRegExp = (input: string) => {\n\treturn input\n\t\t.split('*')\n\t\t.map((str) => escapeStringRegexp(str))\n\t\t.join('.+')\n}\n\nconst checkHostnames = (hostnames: readonly string[], targetHostname: string) => {\n\treturn !!hostnames.find((hostname) => {\n\t\tconst re = new RegExp(globlikeRegExp(hostname))\n\t\treturn targetHostname.match(re)\n\t})\n}\n\n/** @public */\nexport function matchUrl(definitions: readonly TLEmbedDefinition[], url: string) {\n\tconst parsed = safeParseUrl(url)\n\tif (!parsed) return undefined\n\tconst host = parsed.host.replace('www.', '')\n\tfor (const localEmbedDef of definitions) {\n\t\tif (checkHostnames(localEmbedDef.hostnames, host)) {\n\t\t\tconst embedUrl = localEmbedDef.toEmbedUrl(url)\n\n\t\t\tif (embedUrl) {\n\t\t\t\treturn {\n\t\t\t\t\tdefinition: localEmbedDef,\n\t\t\t\t\tembedUrl,\n\t\t\t\t\turl,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined\n}\n\n/** @public */\nexport type TLEmbedResult =\n\t| {\n\t\t\tdefinition: TLEmbedDefinition\n\t\t\turl: string\n\t\t\tembedUrl: string\n\t }\n\t| undefined\n\n/**\n * Tests whether an URL supports embedding and returns the result. If we encounter an error, we\n * return undefined.\n *\n * @param inputUrl - The URL to match\n * @public\n */\nexport function getEmbedInfo(\n\tdefinitions: readonly TLEmbedDefinition[],\n\tinputUrl: string\n): TLEmbedResult {\n\ttry {\n\t\treturn matchUrl(definitions, inputUrl) ?? matchEmbedUrl(definitions, inputUrl)\n\t} catch {\n\t\treturn undefined\n\t}\n}\n"],
5
- "mappings": "AAAA,SAAS,oBAAoB;AAI7B,SAAS,mBAAmB,QAAgB;AAC3C,MAAI,OAAO,WAAW,UAAU;AAC/B,UAAM,IAAI,UAAU,mBAAmB;AAAA,EACxC;AAIA,SAAO,OAAO,QAAQ,uBAAuB,MAAM,EAAE,QAAQ,MAAM,OAAO;AAC3E;AAGO,SAAS,cAAc,aAA2C,KAAa;AACrF,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ,EAAE;AAC3C,aAAW,iBAAiB,aAAa;AACxC,QAAI,eAAe,cAAc,WAAW,IAAI,GAAG;AAClD,YAAM,cAAc,cAAc,aAAa,GAAG;AAClD,UAAI,aAAa;AAChB,eAAO;AAAA,UACN,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,UAAU;AAAA,QACX;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,MAAM,iBAAiB,CAAC,UAAkB;AACzC,SAAO,MACL,MAAM,GAAG,EACT,IAAI,CAAC,QAAQ,mBAAmB,GAAG,CAAC,EACpC,KAAK,IAAI;AACZ;AAEA,MAAM,iBAAiB,CAAC,WAA8B,mBAA2B;AAChF,SAAO,CAAC,CAAC,UAAU,KAAK,CAAC,aAAa;AACrC,UAAM,KAAK,IAAI,OAAO,eAAe,QAAQ,CAAC;AAC9C,WAAO,eAAe,MAAM,EAAE;AAAA,EAC/B,CAAC;AACF;AAGO,SAAS,SAAS,aAA2C,KAAa;AAChF,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ,EAAE;AAC3C,aAAW,iBAAiB,aAAa;AACxC,QAAI,eAAe,cAAc,WAAW,IAAI,GAAG;AAClD,YAAM,WAAW,cAAc,WAAW,GAAG;AAE7C,UAAI,UAAU;AACb,eAAO;AAAA,UACN,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAkBO,SAAS,aACf,aACA,UACgB;AAChB,MAAI;AACH,WAAO,SAAS,aAAa,QAAQ,KAAK,cAAc,aAAa,QAAQ;AAAA,EAC9E,QAAQ;AACP,WAAO;AAAA,EACR;AACD;",
4
+ "sourcesContent": ["import { safeParseUrl } from '@tldraw/editor'\nimport { TLEmbedDefinition } from '../../defaultEmbedDefinitions'\n\n// https://github.com/sindresorhus/escape-string-regexp/blob/main/index.js\nfunction escapeStringRegexp(string: string) {\n\tif (typeof string !== 'string') {\n\t\tthrow new TypeError('Expected a string')\n\t}\n\n\t// Escape characters with special meaning either inside or outside character sets.\n\t// Use a simple backslash escape when it\u2019s always valid, and a `\\xnn` escape when the simpler form would be disallowed by Unicode patterns\u2019 stricter grammar.\n\treturn string.replace(/[|\\\\{}()[\\]^$+*?.]/g, '\\\\$&').replace(/-/g, '\\\\x2d')\n}\n\n/** @public */\nexport function matchEmbedUrl(definitions: readonly TLEmbedDefinition[], url: string) {\n\tconst parsed = safeParseUrl(url)\n\tif (!parsed) return undefined\n\tconst host = parsed.host.replace('www.', '')\n\tfor (const localEmbedDef of definitions) {\n\t\tif (checkHostnames(localEmbedDef.hostnames, host)) {\n\t\t\tconst originalUrl = localEmbedDef.fromEmbedUrl(url)\n\t\t\tif (originalUrl) {\n\t\t\t\treturn {\n\t\t\t\t\tdefinition: localEmbedDef,\n\t\t\t\t\turl: originalUrl,\n\t\t\t\t\tembedUrl: url,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined\n}\n\nconst globlikeRegExp = (input: string) => {\n\treturn input\n\t\t.split('*')\n\t\t.map((str) => escapeStringRegexp(str))\n\t\t.join('.+')\n}\n\nconst checkHostnames = (hostnames: readonly string[], targetHostname: string) => {\n\treturn !!hostnames.find((hostname) => {\n\t\tconst re = new RegExp(globlikeRegExp(hostname))\n\t\treturn targetHostname.match(re)\n\t})\n}\n\n/** @public */\nexport function matchUrl(\n\tdefinitions: readonly TLEmbedDefinition[],\n\turl: string,\n\tembedConfig?: Record<string, unknown>\n) {\n\tconst parsed = safeParseUrl(url)\n\tif (!parsed) return undefined\n\tconst host = parsed.host.replace('www.', '')\n\tfor (const localEmbedDef of definitions) {\n\t\tif (checkHostnames(localEmbedDef.hostnames, host)) {\n\t\t\tconst embedUrl = localEmbedDef.toEmbedUrl(url, embedConfig?.[localEmbedDef.type])\n\n\t\t\tif (embedUrl) {\n\t\t\t\treturn {\n\t\t\t\t\tdefinition: localEmbedDef,\n\t\t\t\t\tembedUrl,\n\t\t\t\t\turl,\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t}\n\treturn undefined\n}\n\n/** @public */\nexport type TLEmbedResult =\n\t| {\n\t\t\tdefinition: TLEmbedDefinition\n\t\t\turl: string\n\t\t\tembedUrl: string\n\t }\n\t| undefined\n\n/**\n * Tests whether an URL supports embedding and returns the result. If we encounter an error, we\n * return undefined.\n *\n * @param inputUrl - The URL to match\n * @param embedConfig - Optional per-embed config, keyed by embed type, passed to `toEmbedUrl`\n * @public\n */\nexport function getEmbedInfo(\n\tdefinitions: readonly TLEmbedDefinition[],\n\tinputUrl: string,\n\tembedConfig?: Record<string, unknown>\n): TLEmbedResult {\n\ttry {\n\t\treturn matchUrl(definitions, inputUrl, embedConfig) ?? matchEmbedUrl(definitions, inputUrl)\n\t} catch {\n\t\treturn undefined\n\t}\n}\n"],
5
+ "mappings": "AAAA,SAAS,oBAAoB;AAI7B,SAAS,mBAAmB,QAAgB;AAC3C,MAAI,OAAO,WAAW,UAAU;AAC/B,UAAM,IAAI,UAAU,mBAAmB;AAAA,EACxC;AAIA,SAAO,OAAO,QAAQ,uBAAuB,MAAM,EAAE,QAAQ,MAAM,OAAO;AAC3E;AAGO,SAAS,cAAc,aAA2C,KAAa;AACrF,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ,EAAE;AAC3C,aAAW,iBAAiB,aAAa;AACxC,QAAI,eAAe,cAAc,WAAW,IAAI,GAAG;AAClD,YAAM,cAAc,cAAc,aAAa,GAAG;AAClD,UAAI,aAAa;AAChB,eAAO;AAAA,UACN,YAAY;AAAA,UACZ,KAAK;AAAA,UACL,UAAU;AAAA,QACX;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAEA,MAAM,iBAAiB,CAAC,UAAkB;AACzC,SAAO,MACL,MAAM,GAAG,EACT,IAAI,CAAC,QAAQ,mBAAmB,GAAG,CAAC,EACpC,KAAK,IAAI;AACZ;AAEA,MAAM,iBAAiB,CAAC,WAA8B,mBAA2B;AAChF,SAAO,CAAC,CAAC,UAAU,KAAK,CAAC,aAAa;AACrC,UAAM,KAAK,IAAI,OAAO,eAAe,QAAQ,CAAC;AAC9C,WAAO,eAAe,MAAM,EAAE;AAAA,EAC/B,CAAC;AACF;AAGO,SAAS,SACf,aACA,KACA,aACC;AACD,QAAM,SAAS,aAAa,GAAG;AAC/B,MAAI,CAAC,OAAQ,QAAO;AACpB,QAAM,OAAO,OAAO,KAAK,QAAQ,QAAQ,EAAE;AAC3C,aAAW,iBAAiB,aAAa;AACxC,QAAI,eAAe,cAAc,WAAW,IAAI,GAAG;AAClD,YAAM,WAAW,cAAc,WAAW,KAAK,cAAc,cAAc,IAAI,CAAC;AAEhF,UAAI,UAAU;AACb,eAAO;AAAA,UACN,YAAY;AAAA,UACZ;AAAA,UACA;AAAA,QACD;AAAA,MACD;AAAA,IACD;AAAA,EACD;AACA,SAAO;AACR;AAmBO,SAAS,aACf,aACA,UACA,aACgB;AAChB,MAAI;AACH,WAAO,SAAS,aAAa,UAAU,WAAW,KAAK,cAAc,aAAa,QAAQ;AAAA,EAC3F,QAAQ;AACP,WAAO;AAAA,EACR;AACD;",
6
6
  "names": []
7
7
  }
@@ -2,8 +2,8 @@ import { b64Vecs, compressLegacySegments } from "@tldraw/editor";
2
2
  function pointsToBase64(points) {
3
3
  return b64Vecs.encodePoints(points);
4
4
  }
5
- function base64ToPoints(base64) {
6
- return b64Vecs.decodePoints(base64);
5
+ function base64ToPoints(base64, dim) {
6
+ return b64Vecs.decodePoints(base64, dim);
7
7
  }
8
8
  function createDrawSegments(pointArrays, type = "free") {
9
9
  return compressLegacySegments(
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/lib/utils/test-helpers.ts"],
4
- "sourcesContent": ["import { b64Vecs, compressLegacySegments } from '@tldraw/editor'\nimport type { TLDrawShapeSegment, VecModel } from '@tldraw/editor'\n\n/**\n * Helper function to convert draw shape points from VecModel[] to base64 string.\n * Uses delta encoding for improved Float16 precision.\n * This is useful for tests that create draw shapes with the legacy array format.\n *\n * @example\n * ```ts\n * const segments = [{ type: 'free', path: pointsToBase64([{x: 0, y: 0, z: 0.5}]) }]\n * ```\n *\n * @public\n */\nexport function pointsToBase64(points: VecModel[]): string {\n\treturn b64Vecs.encodePoints(points)\n}\n\n/**\n * Helper function to convert base64 string back to VecModel[] points.\n * Decodes delta-encoded points to absolute coordinates.\n * This is useful for tests that need to inspect draw shape points.\n *\n * @example\n * ```ts\n * const points = base64ToPoints(shape.props.segments[0].path)\n * expect(points[0].x).toBe(0)\n * ```\n *\n * @public\n */\nexport function base64ToPoints(base64: string): VecModel[] {\n\treturn b64Vecs.decodePoints(base64)\n}\n\n/**\n * Helper function to create draw shape segments from legacy array format.\n * This allows tests to use the old format while the shape uses the new base64 format.\n *\n * @example\n * ```ts\n * editor.createShapes([{\n * type: 'draw',\n * props: {\n * segments: createDrawSegments([[{x: 0, y: 0}, {x: 10, y: 10}]])\n * }\n * }])\n * ```\n * @public\n */\nexport function createDrawSegments(\n\tpointArrays: VecModel[][],\n\ttype: 'free' | 'straight' = 'free'\n): TLDrawShapeSegment[] {\n\treturn compressLegacySegments(\n\t\tpointArrays.map((points) => ({\n\t\t\ttype,\n\t\t\tpoints,\n\t\t}))\n\t)\n}\n"],
5
- "mappings": "AAAA,SAAS,SAAS,8BAA8B;AAezC,SAAS,eAAe,QAA4B;AAC1D,SAAO,QAAQ,aAAa,MAAM;AACnC;AAeO,SAAS,eAAe,QAA4B;AAC1D,SAAO,QAAQ,aAAa,MAAM;AACnC;AAiBO,SAAS,mBACf,aACA,OAA4B,QACL;AACvB,SAAO;AAAA,IACN,YAAY,IAAI,CAAC,YAAY;AAAA,MAC5B;AAAA,MACA;AAAA,IACD,EAAE;AAAA,EACH;AACD;",
4
+ "sourcesContent": ["import { b64Vecs, compressLegacySegments } from '@tldraw/editor'\nimport type { TLDrawShapeSegment, VecModel } from '@tldraw/editor'\n\n/**\n * Helper function to convert draw shape points from VecModel[] to base64 string.\n * Uses delta encoding for improved Float16 precision.\n * This is useful for tests that create draw shapes with the legacy array format.\n *\n * @example\n * ```ts\n * const segments = [{ type: 'free', path: pointsToBase64([{x: 0, y: 0, z: 0.5}]) }]\n * ```\n *\n * @public\n */\nexport function pointsToBase64(points: VecModel[]): string {\n\treturn b64Vecs.encodePoints(points)\n}\n\n/**\n * Helper function to convert base64 string back to VecModel[] points.\n * Decodes delta-encoded points to absolute coordinates.\n * This is useful for tests that need to inspect draw shape points.\n *\n * @example\n * ```ts\n * const points = base64ToPoints(shape.props.segments[0].path, shape.props.segments[0].dim)\n * expect(points[0].x).toBe(0)\n * ```\n *\n * @public\n */\nexport function base64ToPoints(base64: string, dim?: 2 | 3): VecModel[] {\n\treturn b64Vecs.decodePoints(base64, dim)\n}\n\n/**\n * Helper function to create draw shape segments from legacy array format.\n * This allows tests to use the old format while the shape uses the new base64 format.\n *\n * @example\n * ```ts\n * editor.createShapes([{\n * type: 'draw',\n * props: {\n * segments: createDrawSegments([[{x: 0, y: 0}, {x: 10, y: 10}]])\n * }\n * }])\n * ```\n * @public\n */\nexport function createDrawSegments(\n\tpointArrays: VecModel[][],\n\ttype: 'free' | 'straight' = 'free'\n): TLDrawShapeSegment[] {\n\treturn compressLegacySegments(\n\t\tpointArrays.map((points) => ({\n\t\t\ttype,\n\t\t\tpoints,\n\t\t}))\n\t)\n}\n"],
5
+ "mappings": "AAAA,SAAS,SAAS,8BAA8B;AAezC,SAAS,eAAe,QAA4B;AAC1D,SAAO,QAAQ,aAAa,MAAM;AACnC;AAeO,SAAS,eAAe,QAAgB,KAAyB;AACvE,SAAO,QAAQ,aAAa,QAAQ,GAAG;AACxC;AAiBO,SAAS,mBACf,aACA,OAA4B,QACL;AACvB,SAAO;AAAA,IACN,YAAY,IAAI,CAAC,YAAY;AAAA,MAC5B;AAAA,MACA;AAAA,IACD,EAAE;AAAA,EACH;AACD;",
6
6
  "names": []
7
7
  }
@@ -59,8 +59,10 @@ function renderHtmlFromRichTextForMeasurement(editor, richText) {
59
59
  }
60
60
  const plainTextFromRichTextCache = new WeakCache();
61
61
  function isEmptyRichText(richText) {
62
+ if (richText.content.length === 0) return true;
62
63
  if (richText.content.length === 1) {
63
- if (!richText.content[0].content) return true;
64
+ const node = richText.content[0];
65
+ if (!node.content || node.content.length === 0) return true;
64
66
  }
65
67
  return false;
66
68
  }
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../../src/lib/utils/text/richText.ts"],
4
- "sourcesContent": ["import {\n\tExtension,\n\tExtensions,\n\textensions,\n\tgenerateHTML,\n\tgenerateJSON,\n\tgenerateText,\n\tJSONContent,\n} from '@tiptap/core'\nimport { Code } from '@tiptap/extension-code'\nimport { Highlight } from '@tiptap/extension-highlight'\nimport { Node } from '@tiptap/pm/model'\nimport { StarterKit } from '@tiptap/starter-kit'\nimport {\n\tEditor,\n\tgetOwnProperty,\n\tRichTextFontVisitorState,\n\tTLFontFace,\n\tTLRichText,\n\tWeakCache,\n} from '@tldraw/editor'\nimport { DefaultFontFaces } from '../../shapes/shared/defaultFonts'\n\n/** @public */\nexport const KeyboardShiftEnterTweakExtension = Extension.create({\n\tname: 'keyboardShiftEnterHandler',\n\taddKeyboardShortcuts() {\n\t\treturn {\n\t\t\t// We don't support soft breaks, so we just use the default enter command.\n\t\t\t'Shift-Enter': ({ editor }) => editor.commands.enter(),\n\t\t}\n\t},\n})\n\n// We change the default Code to override what's in the StarterKit.\n// It allows for other attributes/extensions.\n// @ts-ignore this is fine.\nCode.config.excludes = undefined\n\n// We want the highlighting to take precedence over bolding/italics/links\n// as far as rendering is concerned. Otherwise, the highlighting\n// looks broken up.\nHighlight.config.priority = 1100\n\n/**\n * Default extensions for the TipTap editor.\n *\n * @public\n */\nexport const tipTapDefaultExtensions: Extensions = [\n\tStarterKit.configure({\n\t\tblockquote: false,\n\t\tcodeBlock: false,\n\t\thorizontalRule: false,\n\t\tlink: {\n\t\t\topenOnClick: false,\n\t\t\tautolink: true,\n\t\t},\n\t\t// Prevent trailing paragraph insertion after lists (fixes #7641)\n\t\ttrailingNode: {\n\t\t\tnotAfter: ['paragraph', 'bulletList', 'orderedList', 'listItem'],\n\t\t},\n\t}),\n\tHighlight,\n\tKeyboardShiftEnterTweakExtension,\n\n\t// N.B. We disable the text direction core extension in RichTextArea,\n\t// but we add it back in again here in our own extensions list so that\n\t// people can omit/override it if they want to.\n\textensions.TextDirection.configure({ direction: 'auto' }),\n]\n\n// todo: bust this if the editor changes, too\nconst htmlCache = new WeakCache<TLRichText, string>()\n\n/**\n * Renders HTML from a rich text string.\n *\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderHtmlFromRichText(editor: Editor, richText: TLRichText) {\n\treturn htmlCache.get(richText, () => {\n\t\tconst tipTapExtensions =\n\t\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\t\tconst html = generateHTML(richText as JSONContent, tipTapExtensions)\n\t\t// We replace empty paragraphs with a single line break to prevent the browser from collapsing them.\n\t\treturn html.replaceAll('<p dir=\"auto\"></p>', '<p><br /></p>') ?? ''\n\t})\n}\n\n/**\n * Renders HTML from a rich text string for measurement.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderHtmlFromRichTextForMeasurement(editor: Editor, richText: TLRichText) {\n\tconst html = renderHtmlFromRichText(editor, richText)\n\treturn `<div class=\"tl-rich-text\">${html}</div>`\n}\n\n// A weak cache used to store plaintext that's been extracted from rich text.\nconst plainTextFromRichTextCache = new WeakCache<TLRichText, string>()\n\nexport function isEmptyRichText(richText: TLRichText) {\n\tif (richText.content.length === 1) {\n\t\tif (!(richText.content[0] as any).content) return true\n\t}\n\treturn false\n}\n\n/**\n * Whether the editor's active rich text selection is inside a bullet or ordered list.\n * @internal\n */\nexport function isEditingRichTextList(editor: Editor) {\n\tconst textEditor = editor.getRichTextEditor()\n\treturn !!(textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList'))\n}\n\n/**\n * Renders plaintext from a rich text string.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderPlaintextFromRichText(editor: Editor, richText: TLRichText) {\n\tif (isEmptyRichText(richText)) return ''\n\n\treturn plainTextFromRichTextCache.get(richText, () => {\n\t\tconst tipTapExtensions =\n\t\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\t\treturn generateText(richText as JSONContent, tipTapExtensions, {\n\t\t\tblockSeparator: '\\n',\n\t\t})\n\t})\n}\n\n/**\n * Renders JSONContent from html.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderRichTextFromHTML(editor: Editor, html: string): TLRichText {\n\tconst tipTapExtensions =\n\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\treturn generateJSON(html, tipTapExtensions) as TLRichText\n}\n\n/** @public */\nexport function defaultAddFontsFromNode(\n\tnode: Node,\n\tstate: RichTextFontVisitorState,\n\taddFont: (font: TLFontFace) => void\n) {\n\tfor (const mark of node.marks) {\n\t\tif (mark.type.name === 'bold' && state.weight !== 'bold') {\n\t\t\tstate = { ...state, weight: 'bold' }\n\t\t}\n\t\tif (mark.type.name === 'italic' && state.style !== 'italic') {\n\t\t\tstate = { ...state, style: 'italic' }\n\t\t}\n\t\tif (mark.type.name === 'code' && state.family !== 'tldraw_mono') {\n\t\t\tstate = { ...state, family: 'tldraw_mono' }\n\t\t}\n\t}\n\n\tconst fontsForFamily = getOwnProperty(DefaultFontFaces, state.family)\n\tif (!fontsForFamily) return state\n\n\tconst fontsForStyle = getOwnProperty(fontsForFamily, state.style)\n\tif (!fontsForStyle) return state\n\n\tconst fontsForWeight = getOwnProperty(fontsForStyle, state.weight)\n\tif (!fontsForWeight) return state\n\n\taddFont(fontsForWeight)\n\n\treturn state\n}\n"],
5
- "mappings": "AAAA;AAAA,EACC;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,OAEM;AACP,SAAS,YAAY;AACrB,SAAS,iBAAiB;AAE1B,SAAS,kBAAkB;AAC3B;AAAA,EAEC;AAAA,EAIA;AAAA,OACM;AACP,SAAS,wBAAwB;AAG1B,MAAM,mCAAmC,UAAU,OAAO;AAAA,EAChE,MAAM;AAAA,EACN,uBAAuB;AACtB,WAAO;AAAA;AAAA,MAEN,eAAe,CAAC,EAAE,OAAO,MAAM,OAAO,SAAS,MAAM;AAAA,IACtD;AAAA,EACD;AACD,CAAC;AAKD,KAAK,OAAO,WAAW;AAKvB,UAAU,OAAO,WAAW;AAOrB,MAAM,0BAAsC;AAAA,EAClD,WAAW,UAAU;AAAA,IACpB,YAAY;AAAA,IACZ,WAAW;AAAA,IACX,gBAAgB;AAAA,IAChB,MAAM;AAAA,MACL,aAAa;AAAA,MACb,UAAU;AAAA,IACX;AAAA;AAAA,IAEA,cAAc;AAAA,MACb,UAAU,CAAC,aAAa,cAAc,eAAe,UAAU;AAAA,IAChE;AAAA,EACD,CAAC;AAAA,EACD;AAAA,EACA;AAAA;AAAA;AAAA;AAAA,EAKA,WAAW,cAAc,UAAU,EAAE,WAAW,OAAO,CAAC;AACzD;AAGA,MAAM,YAAY,IAAI,UAA8B;AAU7C,SAAS,uBAAuB,QAAgB,UAAsB;AAC5E,SAAO,UAAU,IAAI,UAAU,MAAM;AACpC,UAAM,mBACL,OAAO,eAAe,EAAE,cAAc,cAAc;AACrD,UAAM,OAAO,aAAa,UAAyB,gBAAgB;AAEnE,WAAO,KAAK,WAAW,sBAAsB,eAAe,KAAK;AAAA,EAClE,CAAC;AACF;AASO,SAAS,qCAAqC,QAAgB,UAAsB;AAC1F,QAAM,OAAO,uBAAuB,QAAQ,QAAQ;AACpD,SAAO,6BAA6B,IAAI;AACzC;AAGA,MAAM,6BAA6B,IAAI,UAA8B;AAE9D,SAAS,gBAAgB,UAAsB;AACrD,MAAI,SAAS,QAAQ,WAAW,GAAG;AAClC,QAAI,CAAE,SAAS,QAAQ,CAAC,EAAU,QAAS,QAAO;AAAA,EACnD;AACA,SAAO;AACR;AAMO,SAAS,sBAAsB,QAAgB;AACrD,QAAM,aAAa,OAAO,kBAAkB;AAC5C,SAAO,CAAC,EAAE,YAAY,SAAS,YAAY,KAAK,YAAY,SAAS,aAAa;AACnF;AASO,SAAS,4BAA4B,QAAgB,UAAsB;AACjF,MAAI,gBAAgB,QAAQ,EAAG,QAAO;AAEtC,SAAO,2BAA2B,IAAI,UAAU,MAAM;AACrD,UAAM,mBACL,OAAO,eAAe,EAAE,cAAc,cAAc;AACrD,WAAO,aAAa,UAAyB,kBAAkB;AAAA,MAC9D,gBAAgB;AAAA,IACjB,CAAC;AAAA,EACF,CAAC;AACF;AASO,SAAS,uBAAuB,QAAgB,MAA0B;AAChF,QAAM,mBACL,OAAO,eAAe,EAAE,cAAc,cAAc;AACrD,SAAO,aAAa,MAAM,gBAAgB;AAC3C;AAGO,SAAS,wBACf,MACA,OACA,SACC;AACD,aAAW,QAAQ,KAAK,OAAO;AAC9B,QAAI,KAAK,KAAK,SAAS,UAAU,MAAM,WAAW,QAAQ;AACzD,cAAQ,EAAE,GAAG,OAAO,QAAQ,OAAO;AAAA,IACpC;AACA,QAAI,KAAK,KAAK,SAAS,YAAY,MAAM,UAAU,UAAU;AAC5D,cAAQ,EAAE,GAAG,OAAO,OAAO,SAAS;AAAA,IACrC;AACA,QAAI,KAAK,KAAK,SAAS,UAAU,MAAM,WAAW,eAAe;AAChE,cAAQ,EAAE,GAAG,OAAO,QAAQ,cAAc;AAAA,IAC3C;AAAA,EACD;AAEA,QAAM,iBAAiB,eAAe,kBAAkB,MAAM,MAAM;AACpE,MAAI,CAAC,eAAgB,QAAO;AAE5B,QAAM,gBAAgB,eAAe,gBAAgB,MAAM,KAAK;AAChE,MAAI,CAAC,cAAe,QAAO;AAE3B,QAAM,iBAAiB,eAAe,eAAe,MAAM,MAAM;AACjE,MAAI,CAAC,eAAgB,QAAO;AAE5B,UAAQ,cAAc;AAEtB,SAAO;AACR;",
4
+ "sourcesContent": ["import {\n\tExtension,\n\tExtensions,\n\textensions,\n\tgenerateHTML,\n\tgenerateJSON,\n\tgenerateText,\n\tJSONContent,\n} from '@tiptap/core'\nimport { Code } from '@tiptap/extension-code'\nimport { Highlight } from '@tiptap/extension-highlight'\nimport { Node } from '@tiptap/pm/model'\nimport { StarterKit } from '@tiptap/starter-kit'\nimport {\n\tEditor,\n\tgetOwnProperty,\n\tRichTextFontVisitorState,\n\tTLFontFace,\n\tTLRichText,\n\tWeakCache,\n} from '@tldraw/editor'\nimport { DefaultFontFaces } from '../../shapes/shared/defaultFonts'\n\n/** @public */\nexport const KeyboardShiftEnterTweakExtension = Extension.create({\n\tname: 'keyboardShiftEnterHandler',\n\taddKeyboardShortcuts() {\n\t\treturn {\n\t\t\t// We don't support soft breaks, so we just use the default enter command.\n\t\t\t'Shift-Enter': ({ editor }) => editor.commands.enter(),\n\t\t}\n\t},\n})\n\n// We change the default Code to override what's in the StarterKit.\n// It allows for other attributes/extensions.\n// @ts-ignore this is fine.\nCode.config.excludes = undefined\n\n// We want the highlighting to take precedence over bolding/italics/links\n// as far as rendering is concerned. Otherwise, the highlighting\n// looks broken up.\nHighlight.config.priority = 1100\n\n/**\n * Default extensions for the TipTap editor.\n *\n * @public\n */\nexport const tipTapDefaultExtensions: Extensions = [\n\tStarterKit.configure({\n\t\tblockquote: false,\n\t\tcodeBlock: false,\n\t\thorizontalRule: false,\n\t\tlink: {\n\t\t\topenOnClick: false,\n\t\t\tautolink: true,\n\t\t},\n\t\t// Prevent trailing paragraph insertion after lists (fixes #7641)\n\t\ttrailingNode: {\n\t\t\tnotAfter: ['paragraph', 'bulletList', 'orderedList', 'listItem'],\n\t\t},\n\t}),\n\tHighlight,\n\tKeyboardShiftEnterTweakExtension,\n\n\t// N.B. We disable the text direction core extension in RichTextArea,\n\t// but we add it back in again here in our own extensions list so that\n\t// people can omit/override it if they want to.\n\textensions.TextDirection.configure({ direction: 'auto' }),\n]\n\n// todo: bust this if the editor changes, too\nconst htmlCache = new WeakCache<TLRichText, string>()\n\n/**\n * Renders HTML from a rich text string.\n *\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderHtmlFromRichText(editor: Editor, richText: TLRichText) {\n\treturn htmlCache.get(richText, () => {\n\t\tconst tipTapExtensions =\n\t\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\t\tconst html = generateHTML(richText as JSONContent, tipTapExtensions)\n\t\t// We replace empty paragraphs with a single line break to prevent the browser from collapsing them.\n\t\treturn html.replaceAll('<p dir=\"auto\"></p>', '<p><br /></p>') ?? ''\n\t})\n}\n\n/**\n * Renders HTML from a rich text string for measurement.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderHtmlFromRichTextForMeasurement(editor: Editor, richText: TLRichText) {\n\tconst html = renderHtmlFromRichText(editor, richText)\n\treturn `<div class=\"tl-rich-text\">${html}</div>`\n}\n\n// A weak cache used to store plaintext that's been extracted from rich text.\nconst plainTextFromRichTextCache = new WeakCache<TLRichText, string>()\n\nexport function isEmptyRichText(richText: TLRichText) {\n\t// An empty document has no text. It can be encoded several equally-valid ways:\n\t// an empty `content` array at the doc level, or a single paragraph whose own\n\t// `content` is missing or an empty array. The interactive editor emits the\n\t// single-paragraph / missing-`content` form; programmatic authoring (snapshot\n\t// loads, and agents/importers emitting tldraw JSON) commonly emits the\n\t// empty-array forms. Treat them all as empty.\n\tif (richText.content.length === 0) return true\n\tif (richText.content.length === 1) {\n\t\tconst node = richText.content[0] as any\n\t\tif (!node.content || node.content.length === 0) return true\n\t}\n\treturn false\n}\n\n/**\n * Whether the editor's active rich text selection is inside a bullet or ordered list.\n * @internal\n */\nexport function isEditingRichTextList(editor: Editor) {\n\tconst textEditor = editor.getRichTextEditor()\n\treturn !!(textEditor?.isActive('bulletList') || textEditor?.isActive('orderedList'))\n}\n\n/**\n * Renders plaintext from a rich text string.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderPlaintextFromRichText(editor: Editor, richText: TLRichText) {\n\tif (isEmptyRichText(richText)) return ''\n\n\treturn plainTextFromRichTextCache.get(richText, () => {\n\t\tconst tipTapExtensions =\n\t\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\t\treturn generateText(richText as JSONContent, tipTapExtensions, {\n\t\t\tblockSeparator: '\\n',\n\t\t})\n\t})\n}\n\n/**\n * Renders JSONContent from html.\n * @param editor - The editor instance.\n * @param richText - The rich text content.\n *\n * @public\n */\nexport function renderRichTextFromHTML(editor: Editor, html: string): TLRichText {\n\tconst tipTapExtensions =\n\t\teditor.getTextOptions().tipTapConfig?.extensions ?? tipTapDefaultExtensions\n\treturn generateJSON(html, tipTapExtensions) as TLRichText\n}\n\n/** @public */\nexport function defaultAddFontsFromNode(\n\tnode: Node,\n\tstate: RichTextFontVisitorState,\n\taddFont: (font: TLFontFace) => void\n) {\n\tfor (const mark of node.marks) {\n\t\tif (mark.type.name === 'bold' && state.weight !== 'bold') {\n\t\t\tstate = { ...state, weight: 'bold' }\n\t\t}\n\t\tif (mark.type.name === 'italic' && state.style !== 'italic') {\n\t\t\tstate = { ...state, style: 'italic' }\n\t\t}\n\t\tif (mark.type.name === 'code' && state.family !== 'tldraw_mono') {\n\t\t\tstate = { ...state, family: 'tldraw_mono' }\n\t\t}\n\t}\n\n\tconst fontsForFamily = getOwnProperty(DefaultFontFaces, state.family)\n\tif (!fontsForFamily) return state\n\n\tconst fontsForStyle = getOwnProperty(fontsForFamily, state.style)\n\tif (!fontsForStyle) return state\n\n\tconst fontsForWeight = getOwnProperty(fontsForStyle, state.weight)\n\tif (!fontsForWeight) return state\n\n\taddFont(fontsForWeight)\n\n\treturn state\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "tldraw",
3
3
  "description": "A tiny little drawing editor.",
4
- "version": "5.2.0-next.e2b8d10bf10e",
4
+ "version": "5.2.0",
5
5
  "author": {
6
6
  "name": "tldraw Inc.",
7
7
  "email": "hello@tldraw.com"
@@ -51,7 +51,9 @@
51
51
  "tldraw.css",
52
52
  "dist-esm",
53
53
  "dist-cjs",
54
- "src"
54
+ "src",
55
+ "DOCS.md",
56
+ "RELEASE_NOTES.md"
55
57
  ],
56
58
  "dependencies": {
57
59
  "@tiptap/core": "^3.12.1",
@@ -61,9 +63,9 @@
61
63
  "@tiptap/pm": "^3.12.1",
62
64
  "@tiptap/react": "^3.12.1",
63
65
  "@tiptap/starter-kit": "^3.12.1",
64
- "@tldraw/driver": "5.2.0-next.e2b8d10bf10e",
65
- "@tldraw/editor": "5.2.0-next.e2b8d10bf10e",
66
- "@tldraw/store": "5.2.0-next.e2b8d10bf10e",
66
+ "@tldraw/driver": "5.2.0",
67
+ "@tldraw/editor": "5.2.0",
68
+ "@tldraw/store": "5.2.0",
67
69
  "classnames": "^2.5.1",
68
70
  "idb": "^7.1.1",
69
71
  "lz-string": "^1.5.0",
@@ -86,7 +88,10 @@
86
88
  "react": "^19.2.1",
87
89
  "react-dom": "^19.2.1",
88
90
  "resize-observer-polyfill": "^1.5.1",
89
- "vitest": "^3.2.4"
91
+ "vitest": "^4.1.7"
92
+ },
93
+ "engines": {
94
+ "node": ">=22.12.0"
90
95
  },
91
96
  "module": "dist-esm/index.mjs",
92
97
  "source": "src/index.ts"
package/src/index.ts CHANGED
@@ -96,6 +96,10 @@ export {
96
96
  ShapeHandleOverlayUtil,
97
97
  type TLShapeHandleOverlay,
98
98
  } from './lib/overlays/ShapeHandleOverlayUtil'
99
+ export {
100
+ ShapeIndicatorOverlayUtil,
101
+ type TLShapeIndicatorOverlay,
102
+ } from './lib/overlays/ShapeIndicatorOverlayUtil'
99
103
  export {
100
104
  SelectionForegroundOverlayUtil,
101
105
  type TLSelectionForegroundOverlay,
@@ -112,8 +116,10 @@ export {
112
116
  embedShapePermissionDefaults,
113
117
  unknownEmbedShapePermissionOverrides,
114
118
  type CustomEmbedDefinition,
119
+ type DefaultEmbedConfig,
115
120
  type DefaultEmbedDefinitionType,
116
121
  type EmbedDefinition,
122
+ type GoogleMapsEmbedConfig,
117
123
  type TLEmbedDefinition,
118
124
  type TLEmbedShapePermissions,
119
125
  } from './lib/defaultEmbedDefinitions'
@@ -259,7 +265,6 @@ export {
259
265
  export { getStroke } from './lib/shapes/shared/freehand/getStroke'
260
266
  export { getStrokeOutlinePoints } from './lib/shapes/shared/freehand/getStrokeOutlinePoints'
261
267
  export { getStrokePoints } from './lib/shapes/shared/freehand/getStrokePoints'
262
- export { setStrokePointRadii } from './lib/shapes/shared/freehand/setStrokePointRadii'
263
268
  export { getSvgPathFromStrokePoints } from './lib/shapes/shared/freehand/svg'
264
269
  export { type StrokeOptions, type StrokePoint } from './lib/shapes/shared/freehand/types'
265
270
  export {
@@ -163,8 +163,8 @@ export const TldrawImage = memo(function TldrawImage(props: TldrawImageProps) {
163
163
  const shapeIds = editor.getCurrentPageShapeIds()
164
164
 
165
165
  async function setSvg() {
166
- // We have to wait for the fonts to load so that we can correctly measure text sizes
167
- await editor.fonts.loadRequiredFontsForCurrentPage(editor.options.maxFontsToLoadBeforeRender)
166
+ // toImage waits for the required fonts to load (so text is measured correctly) before
167
+ // it renders, so we don't need to do it here.
168
168
  const imageResult = await editor.toImage([...shapeIds], {
169
169
  bounds,
170
170
  scale,
@@ -92,10 +92,14 @@ export class ArrowBindingUtil extends BindingUtil<TLArrowBinding> {
92
92
  reparentArrow(this.editor, binding.fromId)
93
93
  }
94
94
 
95
- // when the arrow is isolated we need to update it's x,y positions
95
+ // when the arrow is isolated we need to update its (x,y) positions
96
96
  override onBeforeIsolateFromShape({
97
97
  binding,
98
98
  }: BindingOnShapeIsolateOptions<TLArrowBinding>): void {
99
+ // during undo/redo the history diff already contains the arrow's correct
100
+ // state, so adjusting the terminal here would corrupt the replay
101
+ if (this.editor.isReplayingHistory()) return
102
+
99
103
  const arrow = this.editor.getShape<TLArrowShape>(binding.fromId)
100
104
  if (!arrow) return
101
105
  updateArrowTerminal({
@@ -111,7 +111,7 @@ export const DEFAULT_EMBED_DEFINITIONS = [
111
111
  overridePermissions: {
112
112
  'allow-presentation': true,
113
113
  },
114
- toEmbedUrl: (url) => {
114
+ toEmbedUrl: (url, config?: GoogleMapsEmbedConfig) => {
115
115
  if (url.includes('/maps/embed?')) {
116
116
  return url
117
117
  } else if (url.includes('/maps/')) {
@@ -126,7 +126,9 @@ export const DEFAULT_EMBED_DEFINITIONS = [
126
126
  ? zoomOrMeters
127
127
  : -Math.log2(parseInt(zoomOrMeters) / 14772321) / 0.8
128
128
  const host = new URL(url).host.replace('www.', '')
129
- result = `https://${host}/maps/embed/v1/view?key=${process.env.NEXT_PUBLIC_GC_API_KEY}&center=${lat},${lng}&zoom=${z}&maptype=${mapType}`
129
+ // TODO: remove the process.env fallback once all consumers pass `apiKey` via `embedConfig`.
130
+ const apiKey = config?.apiKey ?? process.env.NEXT_PUBLIC_GC_API_KEY
131
+ result = `https://${host}/maps/embed/v1/view?key=${apiKey}&center=${lat},${lng}&zoom=${z}&maptype=${mapType}`
130
132
  } else {
131
133
  result = ''
132
134
  }
@@ -702,8 +704,28 @@ export const unknownEmbedShapePermissionOverrides: TLEmbedShapePermissions = {
702
704
  'allow-popups': false,
703
705
  }
704
706
 
707
+ /**
708
+ * Configuration for the default Google Maps embed. Provide an `apiKey` through
709
+ * {@link EmbedShapeUtil}'s `embedConfig` option to render Google Maps embeds.
710
+ *
711
+ * @public
712
+ */
713
+ export interface GoogleMapsEmbedConfig {
714
+ readonly apiKey?: string
715
+ }
716
+
717
+ /**
718
+ * Per-embed configuration for the default embed definitions, keyed by embed type.
719
+ * Passed to an embed definition's `toEmbedUrl` when building its embed URL.
720
+ *
721
+ * @public
722
+ */
723
+ export interface DefaultEmbedConfig {
724
+ readonly google_maps?: GoogleMapsEmbedConfig
725
+ }
726
+
705
727
  /** @public */
706
- export interface EmbedDefinition {
728
+ export interface EmbedDefinition<Config = never> {
707
729
  readonly type: string
708
730
  readonly title: string
709
731
  readonly hostnames: readonly string[]
@@ -721,18 +743,18 @@ export interface EmbedDefinition {
721
743
  // TODO: FIXME this is ugly be required because some embeds have their own border radius for example spotify embeds
722
744
  readonly overrideOutlineRadius?: number
723
745
  // eslint-disable-next-line tldraw/method-signature-style
724
- readonly toEmbedUrl: (url: string) => string | undefined
746
+ readonly toEmbedUrl: (url: string, config?: Config) => string | undefined
725
747
  // eslint-disable-next-line tldraw/method-signature-style
726
748
  readonly fromEmbedUrl: (url: string) => string | undefined
727
749
  }
728
750
 
729
751
  /** @public */
730
- export interface CustomEmbedDefinition extends EmbedDefinition {
752
+ export interface CustomEmbedDefinition<Config = never> extends EmbedDefinition<Config> {
731
753
  readonly icon: string
732
754
  }
733
755
 
734
756
  /** @public */
735
- export type TLEmbedDefinition = EmbedDefinition | CustomEmbedDefinition
757
+ export type TLEmbedDefinition = EmbedDefinition<any> | CustomEmbedDefinition<any>
736
758
 
737
759
  /** @public */
738
760
  export type DefaultEmbedDefinitionType = (typeof DEFAULT_EMBED_DEFINITIONS)[number]['type']
@@ -1,4 +1,3 @@
1
- import { ShapeIndicatorOverlayUtil } from '@tldraw/editor'
2
1
  import { ArrowBindingHintOverlayUtil } from './overlays/ArrowBindingHintOverlayUtil'
3
2
  import { ArrowHintOverlayUtil } from './overlays/ArrowHintOverlayUtil'
4
3
  import { BrushOverlayUtil } from './overlays/BrushOverlayUtil'
@@ -10,23 +9,24 @@ import { CollaboratorShapeIndicatorOverlayUtil } from './overlays/CollaboratorSh
10
9
  import { ScribbleOverlayUtil } from './overlays/ScribbleOverlayUtil'
11
10
  import { SelectionForegroundOverlayUtil } from './overlays/SelectionForegroundOverlayUtil'
12
11
  import { ShapeHandleOverlayUtil } from './overlays/ShapeHandleOverlayUtil'
12
+ import { ShapeIndicatorOverlayUtil } from './overlays/ShapeIndicatorOverlayUtil'
13
13
  import { SnapIndicatorOverlayUtil } from './overlays/SnapIndicatorOverlayUtil'
14
14
  import { ZoomBrushOverlayUtil } from './overlays/ZoomBrushOverlayUtil'
15
15
 
16
16
  /** @public */
17
17
  export const defaultOverlayUtils = [
18
+ ArrowBindingHintOverlayUtil,
19
+ ArrowHintOverlayUtil,
20
+ BrushOverlayUtil,
21
+ CollaboratorBrushOverlayUtil,
22
+ CollaboratorCursorOverlayUtil,
23
+ CollaboratorHintOverlayUtil,
24
+ CollaboratorScribbleOverlayUtil,
18
25
  CollaboratorShapeIndicatorOverlayUtil,
19
- ShapeIndicatorOverlayUtil,
26
+ ScribbleOverlayUtil,
20
27
  SelectionForegroundOverlayUtil,
21
28
  ShapeHandleOverlayUtil,
22
- BrushOverlayUtil,
23
- ZoomBrushOverlayUtil,
29
+ ShapeIndicatorOverlayUtil,
24
30
  SnapIndicatorOverlayUtil,
25
- ScribbleOverlayUtil,
26
- CollaboratorBrushOverlayUtil,
27
- CollaboratorScribbleOverlayUtil,
28
- CollaboratorHintOverlayUtil,
29
- ArrowHintOverlayUtil,
30
- ArrowBindingHintOverlayUtil,
31
- CollaboratorCursorOverlayUtil,
31
+ ZoomBrushOverlayUtil,
32
32
  ] as const