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,11 +1,11 @@
1
1
  import {
2
2
  Box,
3
- Circle2d,
4
3
  Geometry2d,
5
4
  HALF_PI,
6
5
  Mat,
7
6
  OverlayUtil,
8
7
  Polygon2d,
8
+ Rectangle2d,
9
9
  RotateCorner,
10
10
  SelectionCorner,
11
11
  SelectionEdge,
@@ -52,12 +52,17 @@ interface SelectionState {
52
52
  rotation: number
53
53
  width: number
54
54
  height: number
55
- size: number
56
- targetSize: number
57
- targetSizeX: number
58
- targetSizeY: number
59
- expandDx: number
60
- expandDy: number
55
+ /** Visual side length of the rendered resize-handle squares. */
56
+ handleSize: number
57
+ /** Base half-extent of the interactive hit target for handles. */
58
+ hitTargetSize: number
59
+ /** Hit target half-extent along the x axis (narrower for small selections). */
60
+ hitTargetSizeX: number
61
+ /** Hit target half-extent along the y axis (narrower for small selections). */
62
+ hitTargetSizeY: number
63
+ /** Offset from the unexpanded bounds to the expanded selection outline. */
64
+ expandOffsetX: number
65
+ expandOffsetY: number
61
66
  isSmallX: boolean
62
67
  shouldDisplayControls: boolean
63
68
  shouldDisplayBox: boolean
@@ -97,6 +102,7 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
97
102
  'select.pointing_selection',
98
103
  'select.pointing_shape',
99
104
  'select.pointing_resize_handle',
105
+ 'select.pointing_rotate_handle',
100
106
  'select.resizing',
101
107
  'select.crop.idle',
102
108
  'select.crop.pointing_crop',
@@ -122,7 +128,7 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
122
128
  const transform = Mat.Compose(
123
129
  Mat.Translate(state.bounds.x, state.bounds.y),
124
130
  Mat.Rotate(state.rotation),
125
- Mat.Translate(state.expandDx, state.expandDy)
131
+ Mat.Translate(state.expandOffsetX, state.expandOffsetY)
126
132
  )
127
133
 
128
134
  const { overlayType, handle } = overlay.props
@@ -147,7 +153,7 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
147
153
  ctx.save()
148
154
  ctx.translate(state.bounds.x, state.bounds.y)
149
155
  ctx.rotate(state.rotation)
150
- ctx.translate(state.expandDx, state.expandDy)
156
+ ctx.translate(state.expandOffsetX, state.expandOffsetY)
151
157
 
152
158
  const colors = this._getThemeColors()
153
159
  this._renderSelectionBox(ctx, state, colors)
@@ -253,12 +259,19 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
253
259
  })
254
260
  }
255
261
 
256
- const cp = this._getCornerLocalPoint(handle as SelectionCorner, state.width, state.height)
257
- const s = Math.max(state.targetSizeX, state.targetSizeY) * 1.5
262
+ const cornerPoint = this._getCornerLocalPoint(
263
+ handle as SelectionCorner,
264
+ state.width,
265
+ state.height
266
+ )
267
+ const cornerHitHalfSize = Math.max(state.hitTargetSizeX, state.hitTargetSizeY) * 1.5
258
268
  return new Polygon2d({
259
- points: this._localRectToPoints(cp.x - s, cp.y - s, s * 2, s * 2).map((p) =>
260
- Mat.applyToPoint(transform, p)
261
- ),
269
+ points: this._localRectToPoints(
270
+ cornerPoint.x - cornerHitHalfSize,
271
+ cornerPoint.y - cornerHitHalfSize,
272
+ cornerHitHalfSize * 2,
273
+ cornerHitHalfSize * 2
274
+ ).map((p) => Mat.applyToPoint(transform, p)),
262
275
  isFilled: true,
263
276
  })
264
277
  }
@@ -268,13 +281,14 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
268
281
  state: SelectionState,
269
282
  transform: Mat
270
283
  ): Geometry2d {
271
- const cornerSize = Math.max(state.targetSizeX, state.targetSizeY) * 1.5
284
+ const cornerSize = Math.max(state.hitTargetSizeX, state.hitTargetSizeY) * 1.62
272
285
  const center = this._getRotateHandleLocalCenter(handle, state.width, state.height, cornerSize)
273
286
  const radius = cornerSize
274
- return new Circle2d({
287
+ return new Rectangle2d({
275
288
  x: center.x - radius,
276
289
  y: center.y - radius,
277
- radius,
290
+ width: radius * 2,
291
+ height: radius * 2,
278
292
  isFilled: true,
279
293
  }).transform(transform)
280
294
  }
@@ -310,7 +324,7 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
310
324
  ) {
311
325
  if (!state.showResizeHandles) return
312
326
 
313
- const { size, width, height, hideAlternateCornerHandles, showOnlyOneHandle, zoom } = state
327
+ const { handleSize, width, height, hideAlternateCornerHandles, showOnlyOneHandle, zoom } = state
314
328
 
315
329
  ctx.fillStyle = colors.bgColor
316
330
  ctx.strokeStyle = colors.strokeColor
@@ -318,8 +332,8 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
318
332
 
319
333
  const drawCorner = (x: number, y: number, hidden: boolean) => {
320
334
  if (hidden) return
321
- ctx.fillRect(x - size / 2, y - size / 2, size, size)
322
- ctx.strokeRect(x - size / 2, y - size / 2, size, size)
335
+ ctx.fillRect(x - handleSize / 2, y - handleSize / 2, handleSize, handleSize)
336
+ ctx.strokeRect(x - handleSize / 2, y - handleSize / 2, handleSize, handleSize)
323
337
  }
324
338
 
325
339
  drawCorner(0, 0, false) // top-left always shown
@@ -335,8 +349,8 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
335
349
  ) {
336
350
  if (!state.showCropHandles) return
337
351
 
338
- const { size, width, height, hideAlternateCropHandles } = state
339
- const cropStrokeWidth = size / 3
352
+ const { handleSize, width, height, hideAlternateCropHandles } = state
353
+ const cropStrokeWidth = handleSize / 3
340
354
  const offset = cropStrokeWidth / 2
341
355
 
342
356
  ctx.beginPath()
@@ -346,41 +360,41 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
346
360
  ctx.lineJoin = 'miter'
347
361
 
348
362
  // top_left corner (always shown)
349
- ctx.moveTo(-offset, size)
363
+ ctx.moveTo(-offset, handleSize)
350
364
  ctx.lineTo(-offset, -offset)
351
- ctx.lineTo(size, -offset)
365
+ ctx.lineTo(handleSize, -offset)
352
366
 
353
367
  // bottom_right corner (always shown)
354
- ctx.moveTo(width + offset, height - size)
368
+ ctx.moveTo(width + offset, height - handleSize)
355
369
  ctx.lineTo(width + offset, height + offset)
356
- ctx.lineTo(width - size, height + offset)
370
+ ctx.lineTo(width - handleSize, height + offset)
357
371
 
358
372
  if (!hideAlternateCropHandles) {
359
373
  // top_right corner
360
- ctx.moveTo(width - size, -offset)
374
+ ctx.moveTo(width - handleSize, -offset)
361
375
  ctx.lineTo(width + offset, -offset)
362
- ctx.lineTo(width + offset, size)
376
+ ctx.lineTo(width + offset, handleSize)
363
377
 
364
378
  // bottom_left corner
365
- ctx.moveTo(size, height + offset)
379
+ ctx.moveTo(handleSize, height + offset)
366
380
  ctx.lineTo(-offset, height + offset)
367
- ctx.lineTo(-offset, height - size)
381
+ ctx.lineTo(-offset, height - handleSize)
368
382
 
369
383
  // top edge
370
- ctx.moveTo(width / 2 - size, -offset)
371
- ctx.lineTo(width / 2 + size, -offset)
384
+ ctx.moveTo(width / 2 - handleSize, -offset)
385
+ ctx.lineTo(width / 2 + handleSize, -offset)
372
386
 
373
387
  // right edge
374
- ctx.moveTo(width + offset, height / 2 - size)
375
- ctx.lineTo(width + offset, height / 2 + size)
388
+ ctx.moveTo(width + offset, height / 2 - handleSize)
389
+ ctx.lineTo(width + offset, height / 2 + handleSize)
376
390
 
377
391
  // bottom edge
378
- ctx.moveTo(width / 2 - size, height + offset)
379
- ctx.lineTo(width / 2 + size, height + offset)
392
+ ctx.moveTo(width / 2 - handleSize, height + offset)
393
+ ctx.lineTo(width / 2 + handleSize, height + offset)
380
394
 
381
395
  // left edge
382
- ctx.moveTo(-offset, height / 2 - size)
383
- ctx.lineTo(-offset, height / 2 + size)
396
+ ctx.moveTo(-offset, height / 2 - handleSize)
397
+ ctx.lineTo(-offset, height / 2 + handleSize)
384
398
  }
385
399
 
386
400
  ctx.stroke()
@@ -394,7 +408,7 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
394
408
  if (!state.showMobileRotateHandle) return
395
409
 
396
410
  const { cx, cy } = this._getMobileRotateCenter(state)
397
- const fgRadius = state.size / SQUARE_ROOT_PI
411
+ const fgRadius = state.handleSize / SQUARE_ROOT_PI
398
412
 
399
413
  ctx.fillStyle = colors.bgColor
400
414
  ctx.strokeStyle = colors.strokeColor
@@ -417,18 +431,18 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
417
431
  zoom,
418
432
  width,
419
433
  height,
420
- size,
421
- targetSizeY,
434
+ handleSize,
435
+ hitTargetSizeY,
422
436
  } = state
423
437
  if (!shouldDisplayControls || !isCoarsePointer || !onlyShape || onlyShape.type !== 'text') {
424
438
  return
425
439
  }
426
440
 
427
- const textHandleHeight = Math.min(24 / zoom, height - targetSizeY * 3)
441
+ const textHandleHeight = Math.min(24 / zoom, height - hitTargetSizeY * 3)
428
442
  if (textHandleHeight * zoom < 4) return
429
443
 
430
- const hw = size / 2
431
- const r = size / 4
444
+ const hw = handleSize / 2
445
+ const r = handleSize / 4
432
446
 
433
447
  ctx.fillStyle = colors.strokeColor
434
448
  ctx.beginPath()
@@ -474,27 +488,31 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
474
488
 
475
489
  const width = expandedBounds.width
476
490
  const height = expandedBounds.height
477
- const size = 8 / zoom
478
- const isTinyX = width < size * 2
479
- const isTinyY = height < size * 2
480
- const isSmallX = width < size * 4
481
- const isSmallY = height < size * 4
482
- const isSmallCropX = width < size * 5
483
- const isSmallCropY = height < size * 5
491
+ const handleSize = 8 / zoom
492
+ const isTinyX = width < handleSize * 2
493
+ const isTinyY = height < handleSize * 2
494
+ const isSmallX = width < handleSize * 4
495
+ const isSmallY = height < handleSize * 4
496
+ const isSmallCropX = width < handleSize * 5
497
+ const isSmallCropY = height < handleSize * 5
484
498
 
485
499
  const mobileHandleMultiplier = isCoarsePointer ? 1.75 : 1
486
- const targetSize = (6 / zoom) * mobileHandleMultiplier
487
- const targetSizeX = (isSmallX ? targetSize / 2 : targetSize) * (mobileHandleMultiplier * 0.75)
488
- const targetSizeY = (isSmallY ? targetSize / 2 : targetSize) * (mobileHandleMultiplier * 0.75)
500
+ const hitTargetSize = (6 / zoom) * mobileHandleMultiplier
501
+ const hitTargetSizeX =
502
+ (isSmallX ? hitTargetSize / 2 : hitTargetSize) * (mobileHandleMultiplier * 0.75)
503
+ const hitTargetSizeY =
504
+ (isSmallY ? hitTargetSize / 2 : hitTargetSize) * (mobileHandleMultiplier * 0.75)
489
505
 
490
- const expandDx = expandedBounds.x - bounds.x
491
- const expandDy = expandedBounds.y - bounds.y
506
+ const expandOffsetX = expandedBounds.x - bounds.x
507
+ const expandOffsetY = expandedBounds.y - bounds.y
492
508
 
493
509
  const shouldDisplayControls =
494
510
  editor.isInAny(
495
511
  'select.idle',
496
512
  'select.pointing_selection',
497
513
  'select.pointing_shape',
514
+ 'select.pointing_resize_handle',
515
+ 'select.pointing_rotate_handle',
498
516
  'select.crop.idle'
499
517
  ) &&
500
518
  !isChangingStyle &&
@@ -552,7 +570,8 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
552
570
  'select.crop.idle',
553
571
  'select.crop.pointing_crop',
554
572
  'select.crop.pointing_crop_handle',
555
- 'select.pointing_resize_handle'
573
+ 'select.pointing_resize_handle',
574
+ 'select.pointing_rotate_handle'
556
575
  )) ||
557
576
  (showSelectionBounds &&
558
577
  editor.isIn('select.resizing') &&
@@ -566,12 +585,12 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
566
585
  rotation,
567
586
  width,
568
587
  height,
569
- size,
570
- targetSize,
571
- targetSizeX,
572
- targetSizeY,
573
- expandDx,
574
- expandDy,
588
+ handleSize,
589
+ hitTargetSize,
590
+ hitTargetSizeX,
591
+ hitTargetSizeY,
592
+ expandOffsetX,
593
+ expandOffsetY,
575
594
  isSmallX,
576
595
  shouldDisplayControls,
577
596
  shouldDisplayBox,
@@ -587,19 +606,19 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
587
606
  }
588
607
 
589
608
  private _getMobileRotateCenter(state: SelectionState): { cx: number; cy: number } {
590
- const { width, height, targetSize, isSmallX, onlyShape, rotation } = state
609
+ const { width, height, hitTargetSize, isSmallX, onlyShape, rotation } = state
591
610
  const editor = this.editor
592
611
  const isMediaShape =
593
612
  !!onlyShape &&
594
613
  (editor.isShapeOfType(onlyShape, 'image') || editor.isShapeOfType(onlyShape, 'video'))
595
614
  const isShapeTooCloseToContextualToolbar = rotation / HALF_PI > 1.6 && rotation / HALF_PI < 2.4
596
615
 
597
- const cx = isSmallX ? -targetSize * 1.5 : width / 2
616
+ const cx = isSmallX ? -hitTargetSize * 1.5 : width / 2
598
617
  const cy = isSmallX
599
618
  ? height / 2
600
619
  : isMediaShape && !isShapeTooCloseToContextualToolbar
601
- ? height + targetSize * 1.5
602
- : -targetSize * 1.5
620
+ ? height + hitTargetSize * 1.5
621
+ : -hitTargetSize * 1.5
603
622
  return { cx, cy }
604
623
  }
605
624
 
@@ -627,16 +646,16 @@ export class SelectionForegroundOverlayUtil extends OverlayUtil<TLSelectionForeg
627
646
  edge: SelectionEdge,
628
647
  state: SelectionState
629
648
  ): { x: number; y: number; w: number; h: number } {
630
- const { width, height, targetSizeX, targetSizeY } = state
649
+ const { width, height, hitTargetSizeX, hitTargetSizeY } = state
631
650
  switch (edge) {
632
651
  case 'top':
633
- return { x: 0, y: -targetSizeY, w: width, h: targetSizeY * 2 }
652
+ return { x: 0, y: -hitTargetSizeY, w: width, h: hitTargetSizeY * 2 }
634
653
  case 'right':
635
- return { x: width - targetSizeX, y: 0, w: targetSizeX * 2, h: height }
654
+ return { x: width - hitTargetSizeX, y: 0, w: hitTargetSizeX * 2, h: height }
636
655
  case 'bottom':
637
- return { x: 0, y: height - targetSizeY, w: width, h: targetSizeY * 2 }
656
+ return { x: 0, y: height - hitTargetSizeY, w: width, h: hitTargetSizeY * 2 }
638
657
  case 'left':
639
- return { x: -targetSizeX, y: 0, w: targetSizeX * 2, h: height }
658
+ return { x: -hitTargetSizeX, y: 0, w: hitTargetSizeX * 2, h: height }
640
659
  }
641
660
  }
642
661
 
@@ -38,7 +38,9 @@ export class ShapeHandleOverlayUtil extends OverlayUtil<TLShapeHandleOverlay> {
38
38
  const handles = editor.getShapeHandles(onlySelectedShape)
39
39
  if (!handles) return false
40
40
 
41
- if (editor.isInAny('select.idle', 'select.pointing_handle', 'select.pointing_shape')) {
41
+ // Not shown in select.pointing_shape: hiding handles on pointer down
42
+ // matches the arrow binding hint, which also waits for pointer up.
43
+ if (editor.isInAny('select.idle', 'select.pointing_handle')) {
42
44
  return true
43
45
  }
44
46
 
@@ -0,0 +1,133 @@
1
+ import { OverlayUtil, strokeShapeIndicators, TLOverlay } from '@tldraw/editor'
2
+ import { computed } from '@tldraw/state'
3
+ import { TLShapeId } from '@tldraw/tlschema'
4
+
5
+ /** @public */
6
+ export interface TLShapeIndicatorOverlay extends TLOverlay {
7
+ props: {
8
+ idsToDisplay: TLShapeId[]
9
+ hintingShapeIds: TLShapeId[]
10
+ }
11
+ }
12
+
13
+ interface RelevantInstanceFlags {
14
+ isChangingStyle: boolean
15
+ isHoveringCanvas: boolean | null
16
+ isCoarsePointer: boolean
17
+ }
18
+
19
+ /**
20
+ * Overlay util for shape indicators — the selection / hover / hint outlines drawn
21
+ * under the selection foreground. Paints local indicators in the theme's
22
+ * selection color.
23
+ *
24
+ * Remote collaborator selection indicators are drawn by a separate overlay util
25
+ * (e.g. `CollaboratorShapeIndicatorOverlayUtil` from `tldraw`) that runs at a
26
+ * lower z-index so peer selections appear under the local indicators.
27
+ *
28
+ * Non-interactive: contributes no hit-test geometry.
29
+ *
30
+ * @public
31
+ */
32
+ export class ShapeIndicatorOverlayUtil extends OverlayUtil<TLShapeIndicatorOverlay> {
33
+ static override type = 'shape_indicator'
34
+ override options = { zIndex: 50, lineWidth: 1.5, hintedLineWidth: 2.5 }
35
+
36
+ // Narrow projection of instance state. Reading the full record would
37
+ // re-fire getOverlays on every cursor move / brush update; gating on these
38
+ // three booleans means we only re-fire when one of them actually flips.
39
+ private _instanceFlags$ = computed<RelevantInstanceFlags>(
40
+ 'shape indicator instance flags',
41
+ () => {
42
+ const i = this.editor.getInstanceState()
43
+ return {
44
+ isChangingStyle: i.isChangingStyle,
45
+ isHoveringCanvas: i.isHoveringCanvas,
46
+ isCoarsePointer: i.isCoarsePointer,
47
+ }
48
+ },
49
+ {
50
+ isEqual: (a, b) =>
51
+ a.isChangingStyle === b.isChangingStyle &&
52
+ a.isHoveringCanvas === b.isHoveringCanvas &&
53
+ a.isCoarsePointer === b.isCoarsePointer,
54
+ }
55
+ )
56
+
57
+ override isActive(): boolean {
58
+ return true
59
+ }
60
+
61
+ override getOverlays(): TLShapeIndicatorOverlay[] {
62
+ const editor = this.editor
63
+ const renderingShapeIds = new Set(editor.getRenderingShapes().map((s) => s.id))
64
+
65
+ // Local selected / hovered indicators.
66
+ const idsToDisplay: TLShapeId[] = []
67
+ const { isChangingStyle, isHoveringCanvas, isCoarsePointer } = this._instanceFlags$.get()
68
+ const isIdleOrEditing = editor.isInAny('select.idle', 'select.editing_shape')
69
+ const isInSelectState = editor.isInAny(
70
+ 'select.brushing',
71
+ 'select.scribble_brushing',
72
+ 'select.pointing_shape',
73
+ 'select.pointing_selection',
74
+ 'select.pointing_handle',
75
+ 'select.pointing_resize_handle',
76
+ 'select.pointing_rotate_handle'
77
+ )
78
+
79
+ if (!isChangingStyle && (isIdleOrEditing || isInSelectState)) {
80
+ for (const id of editor.getSelectedShapeIds()) {
81
+ if (renderingShapeIds.has(id)) idsToDisplay.push(id)
82
+ }
83
+ if (isIdleOrEditing && isHoveringCanvas && !isCoarsePointer) {
84
+ const hovered = editor.getHoveredShapeId()
85
+ if (hovered && renderingShapeIds.has(hovered) && !idsToDisplay.includes(hovered)) {
86
+ idsToDisplay.push(hovered)
87
+ }
88
+ }
89
+ }
90
+
91
+ // Hinted shapes (drawn thicker). Already deduped at write time in
92
+ // `updateHintingShapeIds`, so no need to dedupe again here.
93
+ const hintingShapeIds: TLShapeId[] = []
94
+ for (const id of editor.getHintingShapeIds()) {
95
+ if (renderingShapeIds.has(id)) hintingShapeIds.push(id)
96
+ }
97
+
98
+ if (idsToDisplay.length === 0 && hintingShapeIds.length === 0) {
99
+ return []
100
+ }
101
+
102
+ return [
103
+ {
104
+ id: 'shape_indicator',
105
+ type: 'shape_indicator',
106
+ props: { idsToDisplay, hintingShapeIds },
107
+ },
108
+ ]
109
+ }
110
+
111
+ override render(ctx: CanvasRenderingContext2D, overlays: TLShapeIndicatorOverlay[]): void {
112
+ const overlay = overlays[0]
113
+ if (!overlay) return
114
+
115
+ const editor = this.editor
116
+ const zoom = editor.getZoomLevel()
117
+ const { idsToDisplay, hintingShapeIds } = overlay.props
118
+
119
+ ctx.lineCap = 'round'
120
+ ctx.lineJoin = 'round'
121
+
122
+ // Local selected / hovered indicators — one stroke call for the whole batch.
123
+ ctx.strokeStyle = editor.getCurrentTheme().colors[editor.getColorMode()].selectionStroke
124
+ ctx.lineWidth = this.options.lineWidth / zoom
125
+ strokeShapeIndicators(editor, ctx, idsToDisplay)
126
+
127
+ // Hinted shapes — thicker stroke, one call for the whole batch.
128
+ if (hintingShapeIds.length > 0) {
129
+ ctx.lineWidth = this.options.hintedLineWidth / zoom
130
+ strokeShapeIndicators(editor, ctx, hintingShapeIds)
131
+ }
132
+ }
133
+ }
@@ -1,4 +1,10 @@
1
- import { StateNode, TLArrowShape, createShapeId, maybeSnapToGrid } from '@tldraw/editor'
1
+ import {
2
+ StateNode,
3
+ TLArrowShape,
4
+ createShapeId,
5
+ cancelShapeCreationOnLongPress,
6
+ maybeSnapToGrid,
7
+ } from '@tldraw/editor'
2
8
  import { ArrowShapeUtil } from '../ArrowShapeUtil'
3
9
  import { clearArrowTargetState, updateArrowTargetState } from '../arrowTargetState'
4
10
 
@@ -69,6 +75,10 @@ export class Pointing extends StateNode {
69
75
  this.cancel()
70
76
  }
71
77
 
78
+ override onLongPress() {
79
+ cancelShapeCreationOnLongPress(this.editor, () => this.cancel())
80
+ }
81
+
72
82
  override onCancel() {
73
83
  this.cancel()
74
84
  }
@@ -2,6 +2,7 @@
2
2
  import {
3
3
  BaseBoxShapeUtil,
4
4
  HTMLContainer,
5
+ Rectangle2d,
5
6
  T,
6
7
  TLAssetId,
7
8
  TLBookmarkAsset,
@@ -24,7 +25,9 @@ import { getRotatedBoxShadow } from '../shared/rotated-box-shadow'
24
25
  import {
25
26
  BOOKMARK_HEIGHT,
26
27
  BOOKMARK_WIDTH,
28
+ getBookmarkShapeHeight,
27
29
  getHumanReadableAddress,
30
+ getResolvedBookmarkAssetId,
28
31
  setBookmarkHeight,
29
32
  updateBookmarkAssetOnUrlChange,
30
33
  } from './bookmarks'
@@ -87,8 +90,17 @@ export class BookmarkShapeUtil extends BaseBoxShapeUtil<TLBookmarkShape> {
87
90
  }
88
91
  }
89
92
 
93
+ override getGeometry(shape: TLBookmarkShape) {
94
+ return new Rectangle2d({
95
+ width: shape.props.w,
96
+ height: getBookmarkShapeHeight(this.editor, shape),
97
+ isFilled: true,
98
+ })
99
+ }
100
+
90
101
  override component(shape: TLBookmarkShape) {
91
- const { assetId, url, h } = shape.props
102
+ const { assetId, url } = shape.props
103
+ const h = getBookmarkShapeHeight(this.editor, shape)
92
104
  const rotation = this.editor.getShapePageTransform(shape)!.rotation()
93
105
 
94
106
  return <BookmarkShapeComponent assetId={assetId} url={url} h={h} rotation={rotation} />
@@ -96,7 +108,7 @@ export class BookmarkShapeUtil extends BaseBoxShapeUtil<TLBookmarkShape> {
96
108
 
97
109
  override getIndicatorPath(shape: TLBookmarkShape): Path2D {
98
110
  const path = new Path2D()
99
- path.rect(0, 0, shape.props.w, shape.props.h)
111
+ path.rect(0, 0, shape.props.w, getBookmarkShapeHeight(this.editor, shape))
100
112
  return path
101
113
  }
102
114
 
@@ -147,7 +159,8 @@ export function BookmarkShapeComponent({
147
159
  }) {
148
160
  const editor = useEditor()
149
161
 
150
- const asset = assetId ? (editor.getAsset(assetId) as TLBookmarkAsset) : null
162
+ const resolvedAssetId = getResolvedBookmarkAssetId(editor, assetId, url)
163
+ const asset = resolvedAssetId ? (editor.getAsset(resolvedAssetId) as TLBookmarkAsset) : null
151
164
 
152
165
  const isSafariExport = !!useSvgExportContext() && tlenv.isSafari
153
166