tldraw 4.3.0-next.f13438eb7775 → 4.3.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 (636) hide show
  1. package/README.md +0 -2
  2. package/dist-cjs/index.d.ts +311 -242
  3. package/dist-cjs/index.js +13 -5
  4. package/dist-cjs/index.js.map +2 -2
  5. package/dist-cjs/lib/bindings/arrow/ArrowBindingUtil.js.map +2 -2
  6. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js +2 -2
  7. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +2 -2
  8. package/dist-cjs/lib/defaultEmbedDefinitions.js +1 -1
  9. package/dist-cjs/lib/defaultEmbedDefinitions.js.map +2 -2
  10. package/dist-cjs/lib/defaultExternalContentHandlers.js +5 -5
  11. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +2 -2
  12. package/dist-cjs/lib/defaultSideEffects.js +6 -1
  13. package/dist-cjs/lib/defaultSideEffects.js.map +2 -2
  14. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +14 -13
  15. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +2 -2
  16. package/dist-cjs/lib/shapes/arrow/arrow-types.js.map +1 -1
  17. package/dist-cjs/lib/shapes/arrow/arrowLabel.js +1 -1
  18. package/dist-cjs/lib/shapes/arrow/arrowLabel.js.map +2 -2
  19. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js +1 -1
  20. package/dist-cjs/lib/shapes/arrow/arrowTargetState.js.map +2 -2
  21. package/dist-cjs/lib/shapes/arrow/elbow/elbowArrowSnapLines.js.map +2 -2
  22. package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js +1 -1
  23. package/dist-cjs/lib/shapes/arrow/elbow/getElbowArrowInfo.js.map +2 -2
  24. package/dist-cjs/lib/shapes/arrow/shared.js.map +2 -2
  25. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js +4 -10
  26. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js.map +2 -2
  27. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +7 -4
  28. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +2 -2
  29. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +1 -1
  30. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +2 -2
  31. package/dist-cjs/lib/shapes/bookmark/bookmarks.js.map +2 -2
  32. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +25 -23
  33. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +2 -2
  34. package/dist-cjs/lib/shapes/draw/getPath.js +20 -11
  35. package/dist-cjs/lib/shapes/draw/getPath.js.map +2 -2
  36. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +82 -86
  37. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +3 -3
  38. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +6 -0
  39. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +2 -2
  40. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +1 -1
  41. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +6 -5
  42. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +2 -2
  43. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +146 -142
  44. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +2 -2
  45. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js +5 -10
  46. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js.map +2 -2
  47. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +3 -3
  48. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +2 -2
  49. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +23 -21
  50. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +2 -2
  51. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +3 -3
  52. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +2 -2
  53. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +6 -11
  54. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +2 -2
  55. package/dist-cjs/lib/shapes/note/noteHelpers.js.map +2 -2
  56. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +5 -10
  57. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +2 -2
  58. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +3 -2
  59. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +2 -2
  60. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js +14 -2
  61. package/dist-cjs/lib/shapes/shared/PlainTextLabel.js.map +3 -3
  62. package/dist-cjs/lib/shapes/shared/RichTextLabel.js +12 -4
  63. package/dist-cjs/lib/shapes/shared/RichTextLabel.js.map +3 -3
  64. package/dist-cjs/lib/shapes/shared/ShapeFill.js +2 -2
  65. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +2 -2
  66. package/dist-cjs/lib/shapes/shared/crop.js +1 -0
  67. package/dist-cjs/lib/shapes/shared/crop.js.map +2 -2
  68. package/dist-cjs/lib/shapes/shared/interpolate-props.js +3 -3
  69. package/dist-cjs/lib/shapes/shared/interpolate-props.js.map +2 -2
  70. package/dist-cjs/lib/shapes/shared/useEditablePlainText.js.map +2 -2
  71. package/dist-cjs/lib/shapes/shared/useEditableRichText.js.map +2 -2
  72. package/dist-cjs/lib/shapes/shared/{useForceSolid.js → useEfficientZoomThreshold.js} +10 -7
  73. package/dist-cjs/lib/shapes/shared/useEfficientZoomThreshold.js.map +7 -0
  74. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js +1 -1
  75. package/dist-cjs/lib/shapes/shared/useImageOrVideoAsset.js.map +2 -2
  76. package/dist-cjs/lib/shapes/text/RichTextArea.js +5 -0
  77. package/dist-cjs/lib/shapes/text/RichTextArea.js.map +2 -2
  78. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +5 -2
  79. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +2 -2
  80. package/dist-cjs/lib/shapes/text/toolStates/Idle.js +4 -10
  81. package/dist-cjs/lib/shapes/text/toolStates/Idle.js.map +2 -2
  82. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +7 -5
  83. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +2 -2
  84. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +1 -1
  85. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +2 -2
  86. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +4 -5
  87. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +2 -2
  88. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +2 -4
  89. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +2 -2
  90. package/dist-cjs/lib/tools/HandTool/HandTool.js +3 -5
  91. package/dist-cjs/lib/tools/HandTool/HandTool.js.map +2 -2
  92. package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js +3 -2
  93. package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js.map +2 -2
  94. package/dist-cjs/lib/tools/HandTool/childStates/Pointing.js +1 -1
  95. package/dist-cjs/lib/tools/HandTool/childStates/Pointing.js.map +2 -2
  96. package/dist-cjs/lib/tools/LaserTool/childStates/Lasering.js +1 -1
  97. package/dist-cjs/lib/tools/LaserTool/childStates/Lasering.js.map +2 -2
  98. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js +10 -11
  99. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js.map +2 -2
  100. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js +6 -5
  101. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +2 -2
  102. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Cropping.js +4 -6
  103. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Cropping.js.map +2 -2
  104. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js +1 -1
  105. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js.map +2 -2
  106. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.js +1 -1
  107. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.js.map +2 -2
  108. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.js +1 -1
  109. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.js.map +2 -2
  110. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.js +2 -1
  111. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.js.map +2 -2
  112. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.js +1 -1
  113. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.js.map +2 -2
  114. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +8 -6
  115. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +2 -2
  116. package/dist-cjs/lib/tools/SelectTool/childStates/EditingShape.js +38 -11
  117. package/dist-cjs/lib/tools/SelectTool/childStates/EditingShape.js.map +2 -2
  118. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +42 -50
  119. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +2 -2
  120. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js +6 -6
  121. package/dist-cjs/lib/tools/SelectTool/childStates/PointingArrowLabel.js.map +2 -2
  122. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js +1 -1
  123. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js.map +2 -2
  124. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js +4 -14
  125. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +2 -2
  126. package/dist-cjs/lib/tools/SelectTool/childStates/PointingResizeHandle.js +1 -1
  127. package/dist-cjs/lib/tools/SelectTool/childStates/PointingResizeHandle.js.map +2 -2
  128. package/dist-cjs/lib/tools/SelectTool/childStates/PointingRotateHandle.js +1 -1
  129. package/dist-cjs/lib/tools/SelectTool/childStates/PointingRotateHandle.js.map +2 -2
  130. package/dist-cjs/lib/tools/SelectTool/childStates/PointingSelection.js +2 -2
  131. package/dist-cjs/lib/tools/SelectTool/childStates/PointingSelection.js.map +2 -2
  132. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +4 -13
  133. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +2 -2
  134. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +5 -6
  135. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +2 -2
  136. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js +2 -3
  137. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js.map +2 -2
  138. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js +7 -6
  139. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +2 -2
  140. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +13 -11
  141. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +2 -2
  142. package/dist-cjs/lib/tools/SelectTool/selectHelpers.js +15 -4
  143. package/dist-cjs/lib/tools/SelectTool/selectHelpers.js.map +2 -2
  144. package/dist-cjs/lib/tools/ZoomTool/ZoomTool.js +1 -1
  145. package/dist-cjs/lib/tools/ZoomTool/ZoomTool.js.map +2 -2
  146. package/dist-cjs/lib/tools/ZoomTool/childStates/Pointing.js +3 -3
  147. package/dist-cjs/lib/tools/ZoomTool/childStates/Pointing.js.map +2 -2
  148. package/dist-cjs/lib/tools/ZoomTool/childStates/ZoomBrushing.js +5 -6
  149. package/dist-cjs/lib/tools/ZoomTool/childStates/ZoomBrushing.js.map +2 -2
  150. package/dist-cjs/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.js +1 -3
  151. package/dist-cjs/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.js.map +2 -2
  152. package/dist-cjs/lib/tools/selection-logic/selectOnCanvasPointerUp.js +1 -1
  153. package/dist-cjs/lib/tools/selection-logic/selectOnCanvasPointerUp.js.map +2 -2
  154. package/dist-cjs/lib/tools/selection-logic/updateHoveredShapeId.js +1 -1
  155. package/dist-cjs/lib/tools/selection-logic/updateHoveredShapeId.js.map +2 -2
  156. package/dist-cjs/lib/ui/TldrawUi.js +2 -2
  157. package/dist-cjs/lib/ui/TldrawUi.js.map +2 -2
  158. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.js +3 -9
  159. package/dist-cjs/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.js.map +2 -2
  160. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js +1 -3
  161. package/dist-cjs/lib/ui/components/ContextMenu/DefaultContextMenu.js.map +2 -2
  162. package/dist-cjs/lib/ui/components/CursorChatBubble.js +1 -1
  163. package/dist-cjs/lib/ui/components/CursorChatBubble.js.map +2 -2
  164. package/dist-cjs/lib/ui/components/DefaultDebugPanel.js +1 -21
  165. package/dist-cjs/lib/ui/components/DefaultDebugPanel.js.map +2 -2
  166. package/dist-cjs/lib/ui/components/EditLinkDialog.js +11 -1
  167. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +2 -2
  168. package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js +1 -1
  169. package/dist-cjs/lib/ui/components/HelperButtons/BackToContent.js.map +2 -2
  170. package/dist-cjs/lib/ui/components/HelperButtons/StopFollowing.js.map +2 -2
  171. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js +1 -1
  172. package/dist-cjs/lib/ui/components/Minimap/DefaultMinimap.js.map +2 -2
  173. package/dist-cjs/lib/ui/components/OfflineIndicator/OfflineIndicator.js +2 -15
  174. package/dist-cjs/lib/ui/components/OfflineIndicator/OfflineIndicator.js.map +3 -3
  175. package/dist-cjs/lib/ui/components/PageMenu/PageItemInput.js +3 -1
  176. package/dist-cjs/lib/ui/components/PageMenu/PageItemInput.js.map +2 -2
  177. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenu.js +6 -0
  178. package/dist-cjs/lib/ui/components/SharePanel/PeopleMenu.js.map +2 -2
  179. package/dist-cjs/lib/ui/components/Toolbar/AltTextEditor.js.map +2 -2
  180. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbar.js +1 -1
  181. package/dist-cjs/lib/ui/components/Toolbar/DefaultImageToolbar.js.map +2 -2
  182. package/dist-cjs/lib/ui/components/Toolbar/DefaultRichTextToolbar.js +1 -1
  183. package/dist-cjs/lib/ui/components/Toolbar/DefaultRichTextToolbar.js.map +2 -2
  184. package/dist-cjs/lib/ui/components/TopPanel/CenteredTopPanelContainer.js.map +1 -1
  185. package/dist-cjs/lib/ui/components/menu-items.js +3 -1
  186. package/dist-cjs/lib/ui/components/menu-items.js.map +2 -2
  187. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js +3 -1
  188. package/dist-cjs/lib/ui/components/primitives/TldrawUiContextualToolbar.js.map +2 -2
  189. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js +1 -1
  190. package/dist-cjs/lib/ui/components/primitives/TldrawUiSlider.js.map +2 -2
  191. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js +149 -93
  192. package/dist-cjs/lib/ui/components/primitives/TldrawUiTooltip.js.map +2 -2
  193. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuActionCheckboxItem.js.map +2 -2
  194. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuActionItem.js.map +2 -2
  195. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js +14 -7
  196. package/dist-cjs/lib/ui/components/primitives/menus/TldrawUiMenuItem.js.map +2 -2
  197. package/dist-cjs/lib/ui/context/actions.js +7 -8
  198. package/dist-cjs/lib/ui/context/actions.js.map +2 -2
  199. package/dist-cjs/lib/ui/context/components.js +1 -2
  200. package/dist-cjs/lib/ui/context/components.js.map +2 -2
  201. package/dist-cjs/lib/ui/hooks/menu-hooks.js.map +2 -2
  202. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +2 -2
  203. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +2 -2
  204. package/dist-cjs/lib/ui/hooks/useFlatten.js.map +2 -2
  205. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +2 -2
  206. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js.map +2 -2
  207. package/dist-cjs/lib/ui/hooks/useTools.js +4 -5
  208. package/dist-cjs/lib/ui/hooks/useTools.js.map +2 -2
  209. package/dist-cjs/lib/ui/version.js +3 -3
  210. package/dist-cjs/lib/ui/version.js.map +1 -1
  211. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js +16 -6
  212. package/dist-cjs/lib/utils/excalidraw/putExcalidrawContent.js.map +2 -2
  213. package/dist-cjs/lib/utils/export/exportAs.js.map +2 -2
  214. package/dist-cjs/lib/utils/frames/frames.js.map +2 -2
  215. package/dist-cjs/lib/{tools/selection-logic/getShouldEnterCropModeOnPointerDown.js → utils/test-helpers.js} +21 -8
  216. package/dist-cjs/lib/utils/test-helpers.js.map +7 -0
  217. package/dist-cjs/lib/utils/text/richText.js +15 -19
  218. package/dist-cjs/lib/utils/text/richText.js.map +3 -3
  219. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js +7 -2
  220. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js.map +2 -2
  221. package/dist-esm/index.d.mts +311 -242
  222. package/dist-esm/index.mjs +14 -5
  223. package/dist-esm/index.mjs.map +2 -2
  224. package/dist-esm/lib/bindings/arrow/ArrowBindingUtil.mjs.map +2 -2
  225. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs +2 -2
  226. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +2 -2
  227. package/dist-esm/lib/defaultEmbedDefinitions.mjs +1 -1
  228. package/dist-esm/lib/defaultEmbedDefinitions.mjs.map +2 -2
  229. package/dist-esm/lib/defaultExternalContentHandlers.mjs +5 -5
  230. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +2 -2
  231. package/dist-esm/lib/defaultSideEffects.mjs +6 -1
  232. package/dist-esm/lib/defaultSideEffects.mjs.map +2 -2
  233. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +15 -15
  234. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +2 -2
  235. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs +1 -1
  236. package/dist-esm/lib/shapes/arrow/arrowLabel.mjs.map +2 -2
  237. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs +1 -1
  238. package/dist-esm/lib/shapes/arrow/arrowTargetState.mjs.map +2 -2
  239. package/dist-esm/lib/shapes/arrow/elbow/elbowArrowSnapLines.mjs.map +2 -2
  240. package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs +1 -1
  241. package/dist-esm/lib/shapes/arrow/elbow/getElbowArrowInfo.mjs.map +2 -2
  242. package/dist-esm/lib/shapes/arrow/shared.mjs.map +2 -2
  243. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs +4 -10
  244. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs.map +2 -2
  245. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +7 -4
  246. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +2 -2
  247. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +1 -1
  248. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +2 -2
  249. package/dist-esm/lib/shapes/bookmark/bookmarks.mjs.map +2 -2
  250. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +30 -25
  251. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +2 -2
  252. package/dist-esm/lib/shapes/draw/getPath.mjs +21 -11
  253. package/dist-esm/lib/shapes/draw/getPath.mjs.map +2 -2
  254. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +83 -86
  255. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +3 -3
  256. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +6 -0
  257. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +2 -2
  258. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +1 -1
  259. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +6 -5
  260. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +2 -2
  261. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +147 -142
  262. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +2 -2
  263. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs +5 -10
  264. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs.map +2 -2
  265. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +3 -3
  266. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +2 -2
  267. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +24 -22
  268. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +2 -2
  269. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +3 -3
  270. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +2 -2
  271. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +7 -12
  272. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +2 -2
  273. package/dist-esm/lib/shapes/note/noteHelpers.mjs.map +2 -2
  274. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +5 -10
  275. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +2 -2
  276. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +4 -3
  277. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +2 -2
  278. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs +14 -2
  279. package/dist-esm/lib/shapes/shared/PlainTextLabel.mjs.map +2 -2
  280. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs +12 -4
  281. package/dist-esm/lib/shapes/shared/RichTextLabel.mjs.map +2 -2
  282. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +2 -2
  283. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +2 -2
  284. package/dist-esm/lib/shapes/shared/crop.mjs +1 -0
  285. package/dist-esm/lib/shapes/shared/crop.mjs.map +2 -2
  286. package/dist-esm/lib/shapes/shared/interpolate-props.mjs +4 -4
  287. package/dist-esm/lib/shapes/shared/interpolate-props.mjs.map +2 -2
  288. package/dist-esm/lib/shapes/shared/useEditablePlainText.mjs.map +2 -2
  289. package/dist-esm/lib/shapes/shared/useEditableRichText.mjs.map +2 -2
  290. package/dist-esm/lib/shapes/shared/useEfficientZoomThreshold.mjs +12 -0
  291. package/dist-esm/lib/shapes/shared/useEfficientZoomThreshold.mjs.map +7 -0
  292. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs +1 -1
  293. package/dist-esm/lib/shapes/shared/useImageOrVideoAsset.mjs.map +2 -2
  294. package/dist-esm/lib/shapes/text/RichTextArea.mjs +5 -0
  295. package/dist-esm/lib/shapes/text/RichTextArea.mjs.map +2 -2
  296. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +5 -2
  297. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +2 -2
  298. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs +4 -10
  299. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs.map +2 -2
  300. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +7 -5
  301. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +2 -2
  302. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +1 -1
  303. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +2 -2
  304. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +4 -5
  305. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +2 -2
  306. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +3 -8
  307. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +2 -2
  308. package/dist-esm/lib/tools/HandTool/HandTool.mjs +3 -5
  309. package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +2 -2
  310. package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs +3 -2
  311. package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs.map +2 -2
  312. package/dist-esm/lib/tools/HandTool/childStates/Pointing.mjs +1 -1
  313. package/dist-esm/lib/tools/HandTool/childStates/Pointing.mjs.map +2 -2
  314. package/dist-esm/lib/tools/LaserTool/childStates/Lasering.mjs +1 -1
  315. package/dist-esm/lib/tools/LaserTool/childStates/Lasering.mjs.map +2 -2
  316. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs +10 -11
  317. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs.map +2 -2
  318. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs +6 -5
  319. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +2 -2
  320. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Cropping.mjs +4 -6
  321. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Cropping.mjs.map +2 -2
  322. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs +1 -1
  323. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs.map +2 -2
  324. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.mjs +1 -1
  325. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.mjs.map +2 -2
  326. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.mjs +1 -1
  327. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.mjs.map +2 -2
  328. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.mjs +2 -1
  329. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.mjs.map +2 -2
  330. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.mjs +1 -1
  331. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.mjs.map +2 -2
  332. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +8 -6
  333. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +2 -2
  334. package/dist-esm/lib/tools/SelectTool/childStates/EditingShape.mjs +38 -11
  335. package/dist-esm/lib/tools/SelectTool/childStates/EditingShape.mjs.map +2 -2
  336. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +43 -51
  337. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +2 -2
  338. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs +6 -6
  339. package/dist-esm/lib/tools/SelectTool/childStates/PointingArrowLabel.mjs.map +2 -2
  340. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs +1 -1
  341. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs.map +2 -2
  342. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +6 -19
  343. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +2 -2
  344. package/dist-esm/lib/tools/SelectTool/childStates/PointingResizeHandle.mjs +1 -1
  345. package/dist-esm/lib/tools/SelectTool/childStates/PointingResizeHandle.mjs.map +2 -2
  346. package/dist-esm/lib/tools/SelectTool/childStates/PointingRotateHandle.mjs +1 -1
  347. package/dist-esm/lib/tools/SelectTool/childStates/PointingRotateHandle.mjs.map +2 -2
  348. package/dist-esm/lib/tools/SelectTool/childStates/PointingSelection.mjs +2 -2
  349. package/dist-esm/lib/tools/SelectTool/childStates/PointingSelection.mjs.map +2 -2
  350. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +4 -13
  351. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +2 -2
  352. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +5 -6
  353. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +2 -2
  354. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs +2 -3
  355. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs.map +2 -2
  356. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs +7 -6
  357. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +2 -2
  358. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +13 -11
  359. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +2 -2
  360. package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs +17 -4
  361. package/dist-esm/lib/tools/SelectTool/selectHelpers.mjs.map +2 -2
  362. package/dist-esm/lib/tools/ZoomTool/ZoomTool.mjs +1 -1
  363. package/dist-esm/lib/tools/ZoomTool/ZoomTool.mjs.map +2 -2
  364. package/dist-esm/lib/tools/ZoomTool/childStates/Pointing.mjs +3 -3
  365. package/dist-esm/lib/tools/ZoomTool/childStates/Pointing.mjs.map +2 -2
  366. package/dist-esm/lib/tools/ZoomTool/childStates/ZoomBrushing.mjs +5 -6
  367. package/dist-esm/lib/tools/ZoomTool/childStates/ZoomBrushing.mjs.map +2 -2
  368. package/dist-esm/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.mjs +1 -3
  369. package/dist-esm/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.mjs.map +2 -2
  370. package/dist-esm/lib/tools/selection-logic/selectOnCanvasPointerUp.mjs +1 -1
  371. package/dist-esm/lib/tools/selection-logic/selectOnCanvasPointerUp.mjs.map +2 -2
  372. package/dist-esm/lib/tools/selection-logic/updateHoveredShapeId.mjs +1 -1
  373. package/dist-esm/lib/tools/selection-logic/updateHoveredShapeId.mjs.map +2 -2
  374. package/dist-esm/lib/ui/TldrawUi.mjs +2 -2
  375. package/dist-esm/lib/ui/TldrawUi.mjs.map +2 -2
  376. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.mjs +2 -8
  377. package/dist-esm/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.mjs.map +2 -2
  378. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs +1 -3
  379. package/dist-esm/lib/ui/components/ContextMenu/DefaultContextMenu.mjs.map +2 -2
  380. package/dist-esm/lib/ui/components/CursorChatBubble.mjs +1 -1
  381. package/dist-esm/lib/ui/components/CursorChatBubble.mjs.map +2 -2
  382. package/dist-esm/lib/ui/components/DefaultDebugPanel.mjs +3 -30
  383. package/dist-esm/lib/ui/components/DefaultDebugPanel.mjs.map +2 -2
  384. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +11 -1
  385. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +2 -2
  386. package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs +1 -1
  387. package/dist-esm/lib/ui/components/HelperButtons/BackToContent.mjs.map +2 -2
  388. package/dist-esm/lib/ui/components/HelperButtons/StopFollowing.mjs.map +2 -2
  389. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs +1 -1
  390. package/dist-esm/lib/ui/components/Minimap/DefaultMinimap.mjs.map +2 -2
  391. package/dist-esm/lib/ui/components/OfflineIndicator/OfflineIndicator.mjs +3 -6
  392. package/dist-esm/lib/ui/components/OfflineIndicator/OfflineIndicator.mjs.map +2 -2
  393. package/dist-esm/lib/ui/components/PageMenu/PageItemInput.mjs +3 -1
  394. package/dist-esm/lib/ui/components/PageMenu/PageItemInput.mjs.map +2 -2
  395. package/dist-esm/lib/ui/components/SharePanel/PeopleMenu.mjs +6 -0
  396. package/dist-esm/lib/ui/components/SharePanel/PeopleMenu.mjs.map +2 -2
  397. package/dist-esm/lib/ui/components/Toolbar/AltTextEditor.mjs.map +2 -2
  398. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbar.mjs +1 -1
  399. package/dist-esm/lib/ui/components/Toolbar/DefaultImageToolbar.mjs.map +2 -2
  400. package/dist-esm/lib/ui/components/Toolbar/DefaultRichTextToolbar.mjs +1 -1
  401. package/dist-esm/lib/ui/components/Toolbar/DefaultRichTextToolbar.mjs.map +2 -2
  402. package/dist-esm/lib/ui/components/TopPanel/CenteredTopPanelContainer.mjs.map +1 -1
  403. package/dist-esm/lib/ui/components/menu-items.mjs +4 -5
  404. package/dist-esm/lib/ui/components/menu-items.mjs.map +2 -2
  405. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs +3 -1
  406. package/dist-esm/lib/ui/components/primitives/TldrawUiContextualToolbar.mjs.map +2 -2
  407. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs +2 -2
  408. package/dist-esm/lib/ui/components/primitives/TldrawUiSlider.mjs.map +2 -2
  409. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs +157 -95
  410. package/dist-esm/lib/ui/components/primitives/TldrawUiTooltip.mjs.map +2 -2
  411. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuActionCheckboxItem.mjs.map +2 -2
  412. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuActionItem.mjs.map +2 -2
  413. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs +15 -8
  414. package/dist-esm/lib/ui/components/primitives/menus/TldrawUiMenuItem.mjs.map +2 -2
  415. package/dist-esm/lib/ui/context/actions.mjs +7 -8
  416. package/dist-esm/lib/ui/context/actions.mjs.map +2 -2
  417. package/dist-esm/lib/ui/context/components.mjs +1 -2
  418. package/dist-esm/lib/ui/context/components.mjs.map +2 -2
  419. package/dist-esm/lib/ui/hooks/menu-hooks.mjs +1 -4
  420. package/dist-esm/lib/ui/hooks/menu-hooks.mjs.map +2 -2
  421. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +2 -2
  422. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +2 -2
  423. package/dist-esm/lib/ui/hooks/useFlatten.mjs.map +2 -2
  424. package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs +2 -2
  425. package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs.map +2 -2
  426. package/dist-esm/lib/ui/hooks/useTools.mjs +4 -5
  427. package/dist-esm/lib/ui/hooks/useTools.mjs.map +2 -2
  428. package/dist-esm/lib/ui/version.mjs +3 -3
  429. package/dist-esm/lib/ui/version.mjs.map +1 -1
  430. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs +17 -6
  431. package/dist-esm/lib/utils/excalidraw/putExcalidrawContent.mjs.map +2 -2
  432. package/dist-esm/lib/utils/export/exportAs.mjs +1 -3
  433. package/dist-esm/lib/utils/export/exportAs.mjs.map +2 -2
  434. package/dist-esm/lib/utils/frames/frames.mjs.map +2 -2
  435. package/dist-esm/lib/utils/test-helpers.mjs +21 -0
  436. package/dist-esm/lib/utils/test-helpers.mjs.map +7 -0
  437. package/dist-esm/lib/utils/text/richText.mjs +12 -5
  438. package/dist-esm/lib/utils/text/richText.mjs.map +2 -2
  439. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs +8 -2
  440. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs.map +2 -2
  441. package/package.json +18 -16
  442. package/src/index.ts +6 -2
  443. package/src/lib/Tldraw.test.tsx +46 -1
  444. package/src/lib/bindings/arrow/ArrowBindingUtil.ts +1 -1
  445. package/src/lib/canvas/TldrawSelectionForeground.tsx +6 -11
  446. package/src/lib/defaultEmbedDefinitions.ts +2 -1
  447. package/src/lib/defaultExternalContentHandlers.ts +13 -14
  448. package/src/lib/defaultSideEffects.ts +6 -1
  449. package/src/lib/shapes/arrow/ArrowShapeOptions.test.ts +40 -133
  450. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +8 -8
  451. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +2 -2
  452. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +16 -16
  453. package/src/lib/shapes/arrow/arrow-types.ts +2 -0
  454. package/src/lib/shapes/arrow/arrowLabel.ts +2 -2
  455. package/src/lib/shapes/arrow/arrowTargetState.ts +2 -2
  456. package/src/lib/shapes/arrow/elbow/elbowArrowSnapLines.tsx +3 -3
  457. package/src/lib/shapes/arrow/elbow/getElbowArrowInfo.test.ts +80 -0
  458. package/src/lib/shapes/arrow/elbow/getElbowArrowInfo.tsx +1 -1
  459. package/src/lib/shapes/arrow/shared.ts +4 -4
  460. package/src/lib/shapes/arrow/toolStates/Idle.tsx +4 -14
  461. package/src/lib/shapes/arrow/toolStates/Pointing.tsx +8 -5
  462. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +1 -1
  463. package/src/lib/shapes/bookmark/bookmarks.ts +3 -3
  464. package/src/lib/shapes/draw/DrawShapeUtil.test.ts +146 -0
  465. package/src/lib/shapes/draw/DrawShapeUtil.tsx +33 -27
  466. package/src/lib/shapes/draw/getPath.ts +31 -10
  467. package/src/lib/shapes/draw/toolStates/Drawing.ts +100 -90
  468. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +8 -1
  469. package/src/lib/shapes/frame/FrameShapeTool.ts +1 -1
  470. package/src/lib/shapes/frame/FrameShapeUtil.tsx +10 -4
  471. package/src/lib/shapes/geo/GeoShapeUtil.test.tsx +10 -2
  472. package/src/lib/shapes/geo/GeoShapeUtil.tsx +228 -176
  473. package/src/lib/shapes/geo/toolStates/Idle.ts +5 -15
  474. package/src/lib/shapes/geo/toolStates/Pointing.ts +6 -6
  475. package/src/lib/shapes/highlight/HighlightShapeUtil.test.ts +146 -0
  476. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +27 -24
  477. package/src/lib/shapes/line/LineShapeTool.test.ts +6 -6
  478. package/src/lib/shapes/line/LineShapeUtil.test.tsx +5 -5
  479. package/src/lib/shapes/line/toolStates/Pointing.ts +4 -4
  480. package/src/lib/shapes/note/NoteShapeTool.test.ts +2 -1
  481. package/src/lib/shapes/note/NoteShapeUtil.tsx +9 -10
  482. package/src/lib/shapes/note/noteCloning.test.ts +3 -1
  483. package/src/lib/shapes/note/noteHelpers.ts +2 -2
  484. package/src/lib/shapes/note/toolStates/Pointing.ts +5 -10
  485. package/src/lib/shapes/shared/HyperlinkButton.tsx +4 -3
  486. package/src/lib/shapes/shared/PlainTextLabel.tsx +12 -2
  487. package/src/lib/shapes/shared/RichTextLabel.tsx +14 -4
  488. package/src/lib/shapes/shared/ShapeFill.tsx +2 -2
  489. package/src/lib/shapes/shared/crop.ts +1 -0
  490. package/src/lib/shapes/shared/interpolate-props.ts +4 -4
  491. package/src/lib/shapes/shared/useEditablePlainText.ts +7 -3
  492. package/src/lib/shapes/shared/useEditableRichText.ts +7 -3
  493. package/src/lib/shapes/shared/useEfficientZoomThreshold.ts +10 -0
  494. package/src/lib/shapes/shared/useImageOrVideoAsset.ts +1 -1
  495. package/src/lib/shapes/text/RichTextArea.tsx +5 -0
  496. package/src/lib/shapes/text/TextShapeTool.test.ts +4 -4
  497. package/src/lib/shapes/text/TextShapeUtil.tsx +5 -0
  498. package/src/lib/shapes/text/toolStates/Idle.ts +4 -14
  499. package/src/lib/shapes/text/toolStates/Pointing.ts +8 -8
  500. package/src/lib/shapes/video/VideoShapeUtil.tsx +2 -1
  501. package/src/lib/tools/EraserTool/childStates/Erasing.ts +7 -10
  502. package/src/lib/tools/EraserTool/childStates/Pointing.ts +5 -20
  503. package/src/lib/tools/HandTool/HandTool.ts +3 -5
  504. package/src/lib/tools/HandTool/childStates/Dragging.ts +3 -2
  505. package/src/lib/tools/HandTool/childStates/Pointing.ts +1 -1
  506. package/src/lib/tools/LaserTool/childStates/Lasering.ts +1 -1
  507. package/src/lib/tools/SelectTool/DragAndDropManager.ts +14 -11
  508. package/src/lib/tools/SelectTool/childStates/Brushing.ts +8 -11
  509. package/src/lib/tools/SelectTool/childStates/Crop/children/Cropping.ts +7 -6
  510. package/src/lib/tools/SelectTool/childStates/Crop/children/Idle.ts +3 -4
  511. package/src/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.ts +1 -1
  512. package/src/lib/tools/SelectTool/childStates/Crop/children/PointingCropHandle.ts +1 -1
  513. package/src/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.ts +2 -1
  514. package/src/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.ts +1 -1
  515. package/src/lib/tools/SelectTool/childStates/DraggingHandle.tsx +11 -12
  516. package/src/lib/tools/SelectTool/childStates/EditingShape.ts +57 -16
  517. package/src/lib/tools/SelectTool/childStates/Idle.ts +64 -81
  518. package/src/lib/tools/SelectTool/childStates/PointingArrowLabel.ts +7 -8
  519. package/src/lib/tools/SelectTool/childStates/PointingCanvas.ts +1 -1
  520. package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +9 -17
  521. package/src/lib/tools/SelectTool/childStates/PointingResizeHandle.ts +1 -1
  522. package/src/lib/tools/SelectTool/childStates/PointingRotateHandle.ts +1 -1
  523. package/src/lib/tools/SelectTool/childStates/PointingSelection.ts +4 -4
  524. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +4 -14
  525. package/src/lib/tools/SelectTool/childStates/Resizing.ts +8 -10
  526. package/src/lib/tools/SelectTool/childStates/Rotating.ts +2 -3
  527. package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +9 -10
  528. package/src/lib/tools/SelectTool/childStates/Translating.ts +16 -15
  529. package/src/lib/tools/SelectTool/selectHelpers.ts +39 -4
  530. package/src/lib/tools/ZoomTool/ZoomTool.ts +1 -1
  531. package/src/lib/tools/ZoomTool/childStates/Pointing.ts +3 -3
  532. package/src/lib/tools/ZoomTool/childStates/ZoomBrushing.ts +5 -6
  533. package/src/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.ts +1 -3
  534. package/src/lib/tools/selection-logic/selectOnCanvasPointerUp.ts +1 -1
  535. package/src/lib/tools/selection-logic/updateHoveredShapeId.ts +1 -1
  536. package/src/lib/ui/TldrawUi.tsx +5 -2
  537. package/src/lib/ui/components/ActionsMenu/DefaultActionsMenuContent.tsx +1 -9
  538. package/src/lib/ui/components/ContextMenu/DefaultContextMenu.tsx +1 -3
  539. package/src/lib/ui/components/CursorChatBubble.tsx +2 -2
  540. package/src/lib/ui/components/DefaultDebugPanel.tsx +3 -42
  541. package/src/lib/ui/components/EditLinkDialog.tsx +16 -6
  542. package/src/lib/ui/components/HelperButtons/BackToContent.tsx +1 -1
  543. package/src/lib/ui/components/HelperButtons/StopFollowing.tsx +2 -2
  544. package/src/lib/ui/components/Minimap/DefaultMinimap.tsx +1 -1
  545. package/src/lib/ui/components/OfflineIndicator/OfflineIndicator.tsx +6 -5
  546. package/src/lib/ui/components/PageMenu/PageItemInput.tsx +3 -1
  547. package/src/lib/ui/components/SharePanel/PeopleMenu.tsx +8 -0
  548. package/src/lib/ui/components/Toolbar/AltTextEditor.tsx +2 -2
  549. package/src/lib/ui/components/Toolbar/DefaultImageToolbar.tsx +1 -1
  550. package/src/lib/ui/components/Toolbar/DefaultRichTextToolbar.tsx +1 -1
  551. package/src/lib/ui/components/TopPanel/CenteredTopPanelContainer.tsx +1 -1
  552. package/src/lib/ui/components/menu-items.tsx +9 -15
  553. package/src/lib/ui/components/primitives/TldrawUiContextualToolbar.tsx +5 -3
  554. package/src/lib/ui/components/primitives/TldrawUiSlider.tsx +2 -2
  555. package/src/lib/ui/components/primitives/TldrawUiTooltip.tsx +208 -113
  556. package/src/lib/ui/components/primitives/menus/TldrawUiMenuActionCheckboxItem.tsx +1 -1
  557. package/src/lib/ui/components/primitives/menus/TldrawUiMenuActionItem.tsx +1 -1
  558. package/src/lib/ui/components/primitives/menus/TldrawUiMenuItem.tsx +7 -4
  559. package/src/lib/ui/context/actions.tsx +15 -19
  560. package/src/lib/ui/context/components.tsx +1 -2
  561. package/src/lib/ui/hooks/menu-hooks.ts +9 -19
  562. package/src/lib/ui/hooks/useClipboardEvents.ts +2 -2
  563. package/src/lib/ui/hooks/useFlatten.ts +1 -2
  564. package/src/lib/ui/hooks/useKeyboardShortcuts.ts +2 -2
  565. package/src/lib/ui/hooks/useTools.tsx +5 -7
  566. package/src/lib/ui/version.ts +3 -3
  567. package/src/lib/ui.css +27 -23
  568. package/src/lib/utils/excalidraw/__snapshots__/putExcalidrawContent.test.tsx.snap +12 -48
  569. package/src/lib/utils/excalidraw/putExcalidrawContent.ts +19 -6
  570. package/src/lib/utils/export/exportAs.ts +2 -9
  571. package/src/lib/utils/frames/frames.ts +1 -1
  572. package/src/lib/utils/test-helpers.ts +62 -0
  573. package/src/lib/utils/text/richText.ts +13 -8
  574. package/src/lib/utils/tldr/buildFromV1Document.ts +21 -19
  575. package/src/test/Editor.test.tsx +78 -41
  576. package/src/test/EraserTool.test.ts +10 -12
  577. package/src/test/SelectTool.test.ts +11 -19
  578. package/src/test/TestEditor.ts +49 -51
  579. package/src/test/TldrawEditor.test.tsx +24 -20
  580. package/src/test/__snapshots__/drawing.test.ts.snap +3 -1257
  581. package/src/test/__snapshots__/resizing.test.ts.snap +3 -12
  582. package/src/test/arrows-megabus.test.tsx +1 -1
  583. package/src/test/bindings.test.tsx +29 -25
  584. package/src/test/bindingsIndex.test.tsx +4 -4
  585. package/src/test/commands/__snapshots__/getSvgString.test.ts.snap +10 -10
  586. package/src/test/commands/cameraState.test.ts +299 -0
  587. package/src/test/commands/createShape.test.ts +64 -0
  588. package/src/test/commands/createShapes.test.ts +15 -1
  589. package/src/test/commands/getSvgString.test.ts +2 -2
  590. package/src/test/commands/isShapeOfType.test.ts +44 -0
  591. package/src/test/commands/putContent.test.ts +80 -1
  592. package/src/test/commands/setCamera.test.ts +13 -11
  593. package/src/test/commands/stackShapes.test.ts +34 -8
  594. package/src/test/commands/updateShape.test.ts +67 -0
  595. package/src/test/commands/updateShapes.test.ts +21 -5
  596. package/src/test/commands/zoomToBounds.test.ts +19 -3
  597. package/src/test/commands/zoomToSelection.test.ts +14 -3
  598. package/src/test/custom-clipping.test.ts +52 -44
  599. package/src/test/customSnapping.test.tsx +77 -62
  600. package/src/test/drawing.test.ts +17 -10
  601. package/src/test/duplicate.test.ts +1 -1
  602. package/src/test/flipShapes.test.ts +33 -0
  603. package/src/test/frames.test.ts +94 -2
  604. package/src/test/getCulledShapes.test.tsx +11 -3
  605. package/src/test/getShapeAtPoint.test.ts +2 -2
  606. package/src/test/groups.test.tsx +7 -4
  607. package/src/test/modifiers.test.ts +6 -6
  608. package/src/test/resizing.test.ts +16 -22
  609. package/src/test/selection-omnibus.test.ts +13 -13
  610. package/src/test/shapeutils.test.ts +1 -1
  611. package/src/test/spacebarPanning.test.ts +28 -10
  612. package/src/test/styles2.test.tsx +1 -1
  613. package/src/test/styles3.test.ts +5 -5
  614. package/src/test/test-jsx.tsx +72 -57
  615. package/src/test/text.test.ts +15 -17
  616. package/src/test/translating.test.ts +6 -8
  617. package/src/test/ui/BackToContent.test.tsx +111 -0
  618. package/tldraw.css +41 -35
  619. package/dist-cjs/lib/shapes/shared/useForceSolid.js.map +0 -7
  620. package/dist-cjs/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.js.map +0 -7
  621. package/dist-cjs/lib/ui/components/TopPanel/DefaultTopPanel.js +0 -32
  622. package/dist-cjs/lib/ui/components/TopPanel/DefaultTopPanel.js.map +0 -7
  623. package/dist-cjs/lib/utils/text/textDirection.js +0 -51
  624. package/dist-cjs/lib/utils/text/textDirection.js.map +0 -7
  625. package/dist-esm/lib/shapes/shared/useForceSolid.mjs +0 -9
  626. package/dist-esm/lib/shapes/shared/useForceSolid.mjs.map +0 -7
  627. package/dist-esm/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.mjs +0 -8
  628. package/dist-esm/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.mjs.map +0 -7
  629. package/dist-esm/lib/ui/components/TopPanel/DefaultTopPanel.mjs +0 -12
  630. package/dist-esm/lib/ui/components/TopPanel/DefaultTopPanel.mjs.map +0 -7
  631. package/dist-esm/lib/utils/text/textDirection.mjs +0 -31
  632. package/dist-esm/lib/utils/text/textDirection.mjs.map +0 -7
  633. package/src/lib/shapes/shared/useForceSolid.ts +0 -6
  634. package/src/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.ts +0 -10
  635. package/src/lib/ui/components/TopPanel/DefaultTopPanel.tsx +0 -10
  636. package/src/lib/utils/text/textDirection.ts +0 -32
@@ -15,6 +15,7 @@ import {
15
15
  TLResizeInfo,
16
16
  TLShapeUtilCanvasSvgDef,
17
17
  Vec,
18
+ WeakCache,
18
19
  exhaustiveSwitchError,
19
20
  geoShapeMigrations,
20
21
  geoShapeProps,
@@ -43,6 +44,7 @@ import {
43
44
  import { getFillDefForCanvas, getFillDefForExport } from '../shared/defaultStyleDefs'
44
45
  import { useDefaultColorTheme } from '../shared/useDefaultColorTheme'
45
46
  import { useIsReadyForEditing } from '../shared/useEditablePlainText'
47
+ import { useEfficientZoomThreshold } from '../shared/useEfficientZoomThreshold'
46
48
  import { GeoShapeBody } from './components/GeoShapeBody'
47
49
  import { getGeoShapePath } from './getGeoShapePath'
48
50
 
@@ -54,6 +56,10 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
54
56
  static override props = geoShapeProps
55
57
  static override migrations = geoShapeMigrations
56
58
 
59
+ override options = {
60
+ showTextOutline: true,
61
+ }
62
+
57
63
  override canEdit() {
58
64
  return true
59
65
  }
@@ -81,53 +87,40 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
81
87
  }
82
88
 
83
89
  override getGeometry(shape: TLGeoShape) {
84
- const w = Math.max(1, shape.props.w)
85
- const h = Math.max(1, shape.props.h + shape.props.growY)
86
-
90
+ const { props } = shape
91
+ const { scale } = props
87
92
  const path = getGeoShapePath(shape)
88
- const unscaledlabelSize = getUnscaledLabelSize(this.editor, shape)
89
- // unscaled w and h
90
- const unscaledW = w / shape.props.scale
91
- const unscaledH = h / shape.props.scale
92
- const unscaledminWidth = Math.min(100, unscaledW / 2)
93
- const unscaledMinHeight = Math.min(
94
- LABEL_FONT_SIZES[shape.props.size] * TEXT_PROPS.lineHeight + LABEL_PADDING * 2,
95
- unscaledH / 2
96
- )
93
+ const pathGeometry = path.toGeometry()
94
+
95
+ const scaledW = Math.max(1, props.w)
96
+ const scaledH = Math.max(1, props.h + props.growY)
97
+ const unscaledW = scaledW / scale
98
+ const unscaledH = scaledH / scale
97
99
 
98
- const unscaledLabelWidth = Math.min(
100
+ const isEmptyLabel = isEmptyRichText(props.richText)
101
+ const unscaledLabelSize = isEmptyLabel
102
+ ? EMPTY_LABEL_SIZE
103
+ : getUnscaledLabelSize(this.editor, shape)
104
+
105
+ const labelBounds = getLabelBounds(
99
106
  unscaledW,
100
- Math.max(unscaledlabelSize.w, Math.min(unscaledminWidth, Math.max(1, unscaledW - 8)))
101
- )
102
- const unscaledLabelHeight = Math.min(
103
107
  unscaledH,
104
- Math.max(unscaledlabelSize.h, Math.min(unscaledMinHeight, Math.max(1, unscaledH - 8)))
108
+ unscaledLabelSize,
109
+ props.size,
110
+ props.align,
111
+ props.verticalAlign,
112
+ scale
105
113
  )
106
114
 
107
- // todo: use centroid for label position
108
-
109
115
  return new Group2d({
110
116
  children: [
111
- path.toGeometry(),
117
+ pathGeometry,
112
118
  new Rectangle2d({
113
- x:
114
- shape.props.align === 'start'
115
- ? 0
116
- : shape.props.align === 'end'
117
- ? (unscaledW - unscaledLabelWidth) * shape.props.scale
118
- : ((unscaledW - unscaledLabelWidth) / 2) * shape.props.scale,
119
- y:
120
- shape.props.verticalAlign === 'start'
121
- ? 0
122
- : shape.props.verticalAlign === 'end'
123
- ? (unscaledH - unscaledLabelHeight) * shape.props.scale
124
- : ((unscaledH - unscaledLabelHeight) / 2) * shape.props.scale,
125
- width: unscaledLabelWidth * shape.props.scale,
126
- height: unscaledLabelHeight * shape.props.scale,
119
+ ...labelBounds,
127
120
  isFilled: true,
128
121
  isLabel: true,
129
122
  excludeFromShapeBounds: true,
130
- isEmptyLabel: isEmptyRichText(shape.props.richText),
123
+ isEmptyLabel: isEmptyLabel,
131
124
  }),
132
125
  ],
133
126
  })
@@ -195,7 +188,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
195
188
  const isReadyForEditing = useIsReadyForEditing(editor, shape.id)
196
189
  const isEmpty = isEmptyRichText(shape.props.richText)
197
190
  const showHtmlContainer = isReadyForEditing || !isEmpty
198
- const isForceSolid = useValue('force solid', () => editor.getZoomLevel() < 0.2, [editor])
191
+ const isForceSolid = useEfficientZoomThreshold(shape.props.scale * 0.25)
199
192
 
200
193
  return (
201
194
  <>
@@ -224,6 +217,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
224
217
  isSelected={isOnlySelected}
225
218
  labelColor={getColorValue(theme, props.labelColor, 'solid')}
226
219
  wrap
220
+ showTextOutline={this.options.showTextOutline}
227
221
  />
228
222
  </HTMLContainer>
229
223
  )}
@@ -233,9 +227,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
233
227
  }
234
228
 
235
229
  indicator(shape: TLGeoShape) {
236
- const isZoomedOut = useValue('isZoomedOut', () => this.editor.getZoomLevel() < 0.25, [
237
- this.editor,
238
- ])
230
+ const isZoomedOut = useEfficientZoomThreshold(shape.props.scale * 0.25)
239
231
 
240
232
  const { size, dash, scale } = shape.props
241
233
  const strokeWidth = STROKE_SIZES[size]
@@ -283,6 +275,7 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
283
275
  labelColor={getColorValue(theme, props.labelColor, 'solid')}
284
276
  bounds={bounds}
285
277
  padding={LABEL_PADDING}
278
+ showTextOutline={this.options.showTextOutline}
286
279
  />
287
280
  )
288
281
  }
@@ -303,41 +296,32 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
303
296
  shape: TLGeoShape,
304
297
  { handle, newPoint, scaleX, scaleY, initialShape }: TLResizeInfo<TLGeoShape>
305
298
  ) {
306
- const unscaledInitialW = initialShape.props.w / initialShape.props.scale
307
- const unscaledInitialH = initialShape.props.h / initialShape.props.scale
308
- const unscaledGrowY = initialShape.props.growY / initialShape.props.scale
299
+ const unscaledInitial = getUnscaledGeoProps(initialShape.props)
309
300
  // use the w/h from props here instead of the initialBounds here,
310
301
  // since cloud shapes calculated bounds can differ from the props w/h.
311
- let unscaledW = unscaledInitialW * scaleX
312
- let unscaledH = (unscaledInitialH + unscaledGrowY) * scaleY
302
+ let unscaledW = unscaledInitial.w * scaleX
303
+ let unscaledH = (unscaledInitial.h + unscaledInitial.growY) * scaleY
313
304
  let overShrinkX = 0
314
305
  let overShrinkY = 0
315
306
 
316
- const min = MIN_SIZE_WITH_LABEL
317
-
318
307
  if (!isEmptyRichText(shape.props.richText)) {
319
- let newW = Math.max(Math.abs(unscaledW), min)
320
- let newH = Math.max(Math.abs(unscaledH), min)
308
+ // Use initialShape for label measurement to hit the cache.
309
+ // Creating a temp shape with new dimensions would break WeakCache and cause
310
+ // expensive measurements on every resize frame.
311
+ const unscaledLabelSize = getUnscaledLabelSize(this.editor, initialShape)
321
312
 
322
- if (newW < min && newH === min) newW = min
323
- if (newW === min && newH < min) newH = min
313
+ const absUnscaledW = Math.abs(unscaledW)
314
+ const absUnscaledH = Math.abs(unscaledH)
324
315
 
325
- const unscaledLabelSize = getUnscaledLabelSize(this.editor, {
326
- ...shape,
327
- props: {
328
- ...shape.props,
329
- w: newW * shape.props.scale,
330
- h: newH * shape.props.scale,
331
- },
332
- })
316
+ // Constrain to label size (primary constraint) and min size with label (secondary)
317
+ const constrainedW = Math.max(absUnscaledW, unscaledLabelSize.w, MIN_SIZE_WITH_LABEL)
318
+ const constrainedH = Math.max(absUnscaledH, unscaledLabelSize.h, MIN_SIZE_WITH_LABEL)
333
319
 
334
- const nextW = Math.max(Math.abs(unscaledW), unscaledLabelSize.w) * Math.sign(unscaledW)
335
- const nextH = Math.max(Math.abs(unscaledH), unscaledLabelSize.h) * Math.sign(unscaledH)
336
- overShrinkX = Math.abs(nextW) - Math.abs(unscaledW)
337
- overShrinkY = Math.abs(nextH) - Math.abs(unscaledH)
320
+ overShrinkX = constrainedW - absUnscaledW
321
+ overShrinkY = constrainedH - absUnscaledH
338
322
 
339
- unscaledW = nextW
340
- unscaledH = nextH
323
+ unscaledW = constrainedW * Math.sign(unscaledW || 1)
324
+ unscaledH = constrainedH * Math.sign(unscaledH || 1)
341
325
  }
342
326
 
343
327
  const scaledW = unscaledW * shape.props.scale
@@ -379,147 +363,93 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
379
363
  }
380
364
 
381
365
  override onBeforeCreate(shape: TLGeoShape) {
382
- if (isEmptyRichText(shape.props.richText)) {
383
- if (shape.props.growY) {
384
- // No text / some growY, set growY to 0
385
- return {
386
- ...shape,
387
- props: {
388
- ...shape.props,
389
- growY: 0,
390
- },
391
- }
392
- } else {
393
- // No text / no growY, nothing to change
394
- return
395
- }
396
- }
397
-
398
- const unscaledPrevHeight = shape.props.h / shape.props.scale
399
- const unscaledNextHeight = getUnscaledLabelSize(this.editor, shape).h
400
-
401
- let growY: number | null = null
366
+ const { props } = shape
402
367
 
403
- if (unscaledNextHeight > unscaledPrevHeight) {
404
- growY = unscaledNextHeight - unscaledPrevHeight
405
- } else {
406
- if (shape.props.growY) {
407
- growY = 0
408
- }
368
+ // No text - ensure growY is 0
369
+ if (isEmptyRichText(props.richText)) {
370
+ return props.growY !== 0 ? { ...shape, props: { ...props, growY: 0 } } : undefined
409
371
  }
410
372
 
411
- if (growY !== null) {
373
+ // Has text - calculate growY needed to fit label
374
+ const unscaledShapeH = props.h / props.scale
375
+ const unscaledLabelH = getUnscaledLabelSize(this.editor, shape).h
376
+ const unscaledGrowY = calculateGrowY(unscaledShapeH, unscaledLabelH, props.growY / props.scale)
377
+
378
+ if (unscaledGrowY !== null) {
412
379
  return {
413
380
  ...shape,
414
- props: {
415
- ...shape.props,
416
- // scale the growY
417
- growY: growY * shape.props.scale,
418
- },
381
+ props: { ...props, growY: unscaledGrowY * props.scale },
419
382
  }
420
383
  }
421
384
  }
422
385
 
423
386
  override onBeforeUpdate(prev: TLGeoShape, next: TLGeoShape) {
424
- // No change to text, font, or size, no need to update update
387
+ const { props: prevProps } = prev
388
+ const { props: nextProps } = next
389
+
390
+ // No change to text, font, or size - no update needed
425
391
  if (
426
- isEqual(prev.props.richText, next.props.richText) &&
427
- prev.props.font === next.props.font &&
428
- prev.props.size === next.props.size
392
+ isEqual(prevProps.richText, nextProps.richText) &&
393
+ prevProps.font === nextProps.font &&
394
+ prevProps.size === nextProps.size
429
395
  ) {
430
396
  return
431
397
  }
432
398
 
433
- // If we got rid of the text, cancel out any growY from the prev text
434
- const wasEmpty = isEmptyRichText(prev.props.richText)
435
- const isEmpty = isEmptyRichText(next.props.richText)
436
- if (!wasEmpty && isEmpty) {
437
- return {
438
- ...next,
439
- props: {
440
- ...next.props,
441
- growY: 0,
442
- },
443
- }
444
- }
445
-
446
- // Get the prev width and height in unscaled values
447
- const unscaledPrevWidth = prev.props.w / prev.props.scale
448
- const unscaledPrevHeight = prev.props.h / prev.props.scale
449
- const unscaledPrevGrowY = prev.props.growY / prev.props.scale
450
-
451
- // Get the next width and height in unscaled values
452
- const unscaledNextLabelSize = getUnscaledLabelSize(this.editor, next)
399
+ const wasEmpty = isEmptyRichText(prevProps.richText)
400
+ const isEmpty = isEmptyRichText(nextProps.richText)
453
401
 
454
- // When entering the first character in a label (not pasting in multiple characters...)
455
- if (wasEmpty && !isEmpty && renderPlaintextFromRichText(this.editor, next.props.richText)) {
456
- let unscaledW = Math.max(unscaledPrevWidth, unscaledNextLabelSize.w)
457
- let unscaledH = Math.max(unscaledPrevHeight, unscaledNextLabelSize.h)
402
+ // If label is empty and used to be empty, skip label measurement and dimension adjustment
403
+ if (wasEmpty && isEmpty) {
404
+ return
405
+ }
458
406
 
459
- const min = MIN_SIZE_WITH_LABEL
407
+ // Text was removed - reset growY
408
+ if (isEmpty) {
409
+ return nextProps.growY !== 0 ? { ...next, props: { ...nextProps, growY: 0 } } : undefined
410
+ }
460
411
 
461
- // If both the width and height were less than the minimum size, make the shape square
462
- if (unscaledPrevWidth < min && unscaledPrevHeight < min) {
463
- unscaledW = Math.max(unscaledW, min)
464
- unscaledH = Math.max(unscaledH, min)
465
- unscaledW = Math.max(unscaledW, unscaledH)
466
- unscaledH = Math.max(unscaledW, unscaledH)
467
- }
412
+ const unscaledPrev = getUnscaledGeoProps(prevProps)
413
+ const unscaledLabelSize = getUnscaledLabelSize(this.editor, next)
414
+ const { scale } = nextProps
468
415
 
469
- // Don't set a growY—at least, not until we've implemented a growX property
416
+ // Text was added for the first time - expand shape to fit (if wasEmpty and now there's text...
417
+ // It might be just whitespace but it is faster to assume that it is NOT just whitespace and expand
418
+ // the shape in either case (a label with just spaces text will be less performant but that's acceptable)
419
+ if (wasEmpty && !isEmpty) {
420
+ const expanded = expandShapeForFirstLabel(unscaledPrev.w, unscaledPrev.h, unscaledLabelSize)
470
421
  return {
471
422
  ...next,
472
423
  props: {
473
- ...next.props,
474
- // Scale the results
475
- w: unscaledW * next.props.scale,
476
- h: unscaledH * next.props.scale,
424
+ ...nextProps,
425
+ w: expanded.w * scale,
426
+ h: expanded.h * scale,
477
427
  growY: 0,
478
428
  },
479
429
  }
480
430
  }
481
431
 
482
- let growY: number | null = null
432
+ // Text was modified - adjust dimensions to fit new label
433
+ const unscaledNextW = next.props.w / scale
434
+ const needsWidthExpand = unscaledLabelSize.w > unscaledNextW
435
+ const unscaledGrowY = calculateGrowY(unscaledPrev.h, unscaledLabelSize.h, unscaledPrev.growY)
483
436
 
484
- if (unscaledNextLabelSize.h > unscaledPrevHeight) {
485
- growY = unscaledNextLabelSize.h - unscaledPrevHeight
486
- } else {
487
- if (unscaledPrevGrowY) {
488
- growY = 0
489
- }
490
- }
491
-
492
- if (growY !== null) {
493
- const unscaledNextWidth = next.props.w / next.props.scale
494
- return {
495
- ...next,
496
- props: {
497
- ...next.props,
498
- // Scale the results
499
- growY: growY * next.props.scale,
500
- w: Math.max(unscaledNextWidth, unscaledNextLabelSize.w) * next.props.scale,
501
- },
502
- }
503
- }
504
-
505
- if (unscaledNextLabelSize.w > unscaledPrevWidth) {
437
+ if (unscaledGrowY !== null || needsWidthExpand) {
506
438
  return {
507
439
  ...next,
508
440
  props: {
509
- ...next.props,
510
- // Scale the results
511
- w: unscaledNextLabelSize.w * next.props.scale,
441
+ ...nextProps,
442
+ growY: (unscaledGrowY ?? unscaledPrev.growY) * scale,
443
+ w: Math.max(unscaledNextW, unscaledLabelSize.w) * scale,
512
444
  },
513
445
  }
514
446
  }
515
-
516
- // otherwise, no update needed
517
447
  }
518
448
 
519
449
  override onDoubleClick(shape: TLGeoShape) {
520
450
  // Little easter egg: double-clicking a rectangle / checkbox while
521
451
  // holding alt will toggle between check-box and rectangle
522
- if (this.editor.inputs.altKey) {
452
+ if (this.editor.inputs.getAltKey()) {
523
453
  switch (shape.props.geo) {
524
454
  case 'rectangle': {
525
455
  return {
@@ -557,29 +487,151 @@ export class GeoShapeUtil extends BaseBoxShapeUtil<TLGeoShape> {
557
487
  }
558
488
 
559
489
  // imperfect but good enough, should be the width of the W in the font / size combo
560
- const minWidths = {
490
+ const MIN_WIDTHS = Object.freeze({
561
491
  s: 12,
562
492
  m: 14,
563
493
  l: 16,
564
494
  xl: 20,
565
- }
495
+ })
566
496
 
567
- const extraPaddings = {
497
+ const EXTRA_PADDINGS = Object.freeze({
568
498
  s: 2,
569
499
  m: 3.5,
570
500
  l: 5,
571
501
  xl: 10,
502
+ })
503
+
504
+ const EMPTY_LABEL_SIZE = Object.freeze({ w: 0, h: 0 })
505
+
506
+ // Margin between label edge and shape edge (in unscaled units)
507
+ const LABEL_EDGE_MARGIN = 8
508
+
509
+ /** Calculate label bounds for hit testing */
510
+ function getLabelBounds(
511
+ unscaledShapeW: number,
512
+ unscaledShapeH: number,
513
+ unscaledLabelSize: { w: number; h: number },
514
+ size: TLGeoShapeProps['size'],
515
+ align: TLGeoShapeProps['align'],
516
+ verticalAlign: TLGeoShapeProps['verticalAlign'],
517
+ scale: number
518
+ ): { x: number; y: number; width: number; height: number } {
519
+ // Calculate minimum label dimensions based on font size and shape size
520
+ const unscaledMinWidth = Math.min(100, unscaledShapeW / 2)
521
+ const unscaledMinHeight = Math.min(
522
+ LABEL_FONT_SIZES[size] * TEXT_PROPS.lineHeight + LABEL_PADDING * 2,
523
+ unscaledShapeH / 2
524
+ )
525
+
526
+ // Label dimensions: at least the measured size, but constrained to shape bounds
527
+ const unscaledLabelW = Math.min(
528
+ unscaledShapeW,
529
+ Math.max(
530
+ unscaledLabelSize.w,
531
+ Math.min(unscaledMinWidth, Math.max(1, unscaledShapeW - LABEL_EDGE_MARGIN))
532
+ )
533
+ )
534
+ const unscaledLabelH = Math.min(
535
+ unscaledShapeH,
536
+ Math.max(
537
+ unscaledLabelSize.h,
538
+ Math.min(unscaledMinHeight, Math.max(1, unscaledShapeH - LABEL_EDGE_MARGIN))
539
+ )
540
+ )
541
+
542
+ // Calculate position based on alignment
543
+ const unscaledX =
544
+ align === 'start'
545
+ ? 0
546
+ : align === 'end'
547
+ ? unscaledShapeW - unscaledLabelW
548
+ : (unscaledShapeW - unscaledLabelW) / 2
549
+
550
+ const unscaledY =
551
+ verticalAlign === 'start'
552
+ ? 0
553
+ : verticalAlign === 'end'
554
+ ? unscaledShapeH - unscaledLabelH
555
+ : (unscaledShapeH - unscaledLabelH) / 2
556
+
557
+ return {
558
+ x: unscaledX * scale,
559
+ y: unscaledY * scale,
560
+ width: unscaledLabelW * scale,
561
+ height: unscaledLabelH * scale,
562
+ }
572
563
  }
573
564
 
574
- function getUnscaledLabelSize(editor: Editor, shape: TLGeoShape) {
575
- const { richText, font, size, w } = shape.props
565
+ /** Get the unscaled dimensions from a geo shape's props */
566
+ function getUnscaledGeoProps(props: TLGeoShapeProps) {
567
+ const { w, h, growY, scale } = props
568
+ return {
569
+ w: w / scale,
570
+ h: h / scale,
571
+ growY: growY / scale,
572
+ }
573
+ }
576
574
 
577
- if (!richText || isEmptyRichText(richText)) {
578
- return { w: 0, h: 0 }
575
+ /**
576
+ * Calculate the growY needed to fit a label within a shape.
577
+ * Returns null if no change is needed, otherwise returns the new unscaled growY value.
578
+ */
579
+ function calculateGrowY(
580
+ unscaledShapeH: number,
581
+ unscaledLabelH: number,
582
+ unscaledCurrentGrowY: number
583
+ ): number | null {
584
+ if (unscaledLabelH > unscaledShapeH) {
585
+ // Label is taller than shape - need to grow
586
+ return unscaledLabelH - unscaledShapeH
587
+ }
588
+ if (unscaledCurrentGrowY > 0) {
589
+ // Label fits and we have existing growY - reset it
590
+ return 0
579
591
  }
592
+ // No change needed
593
+ return null
594
+ }
595
+
596
+ /**
597
+ * Calculate expanded dimensions when adding a label to a shape for the first time.
598
+ * Ensures the shape meets minimum size requirements and is square if originally small.
599
+ */
600
+ function expandShapeForFirstLabel(
601
+ unscaledW: number,
602
+ unscaledH: number,
603
+ unscaledLabelSize: { w: number; h: number }
604
+ ): { w: number; h: number } {
605
+ let w = Math.max(unscaledW, unscaledLabelSize.w)
606
+ let h = Math.max(unscaledH, unscaledLabelSize.h)
607
+
608
+ // If shape was smaller than min size in both dimensions, make it square
609
+ if (unscaledW < MIN_SIZE_WITH_LABEL && unscaledH < MIN_SIZE_WITH_LABEL) {
610
+ w = Math.max(w, MIN_SIZE_WITH_LABEL)
611
+ h = Math.max(h, MIN_SIZE_WITH_LABEL)
612
+ // Make square by using the larger dimension
613
+ const maxDim = Math.max(w, h)
614
+ w = maxDim
615
+ h = maxDim
616
+ }
617
+
618
+ return { w, h }
619
+ }
620
+
621
+ const labelSizesForGeo = new WeakCache<TLGeoShape, { w: number; h: number }>()
622
+
623
+ // Returns cached label size for the shape. Don't call with empty rich text.
624
+ function getUnscaledLabelSize(editor: Editor, shape: TLGeoShape) {
625
+ return labelSizesForGeo.get(shape, () => {
626
+ return measureUnscaledLabelSize(editor, shape)
627
+ })
628
+ }
629
+
630
+ // This is the expensive part of the code so we want to avoid calling it if we can
631
+ function measureUnscaledLabelSize(editor: Editor, shape: TLGeoShape) {
632
+ const { richText, font, size, w } = shape.props
580
633
 
581
- // way too expensive to be recomputing on every update
582
- const minWidth = minWidths[size]
634
+ const minWidth = MIN_WIDTHS[size]
583
635
 
584
636
  const html = renderHtmlFromRichTextForMeasurement(editor, richText)
585
637
  const textSize = editor.textMeasure.measureHtml(html, {
@@ -591,7 +643,7 @@ function getUnscaledLabelSize(editor: Editor, shape: TLGeoShape) {
591
643
  // Guard because a DOM nodes can't be less 0
592
644
  0,
593
645
  // A 'w' width that we're setting as the min-width
594
- Math.ceil(minWidth + extraPaddings[size]),
646
+ Math.ceil(minWidth + EXTRA_PADDINGS[size]),
595
647
  // The actual text size
596
648
  Math.ceil(w / shape.props.scale - LABEL_PADDING * 2)
597
649
  ),
@@ -1,4 +1,5 @@
1
1
  import { StateNode, TLKeyboardEventInfo, TLPointerEventInfo } from '@tldraw/editor'
2
+ import { startEditingShapeWithRichText } from '../../../tools/SelectTool/selectHelpers'
2
3
 
3
4
  export class Idle extends StateNode {
4
5
  static override id = 'idle'
@@ -12,22 +13,11 @@ export class Idle extends StateNode {
12
13
  }
13
14
 
14
15
  override onKeyUp(info: TLKeyboardEventInfo) {
16
+ const { editor } = this
15
17
  if (info.key === 'Enter') {
16
- if (this.editor.getIsReadonly()) return null
17
-
18
- const onlySelectedShape = this.editor.getOnlySelectedShape()
19
- // If the only selected shape is editable, start editing it
20
- if (
21
- onlySelectedShape &&
22
- this.editor.getShapeUtil(onlySelectedShape).canEdit(onlySelectedShape)
23
- ) {
24
- this.editor.setCurrentTool('select')
25
- this.editor.setEditingShape(onlySelectedShape.id)
26
- this.editor.root.getCurrent()?.transition('editing_shape', {
27
- ...info,
28
- target: 'shape',
29
- shape: onlySelectedShape,
30
- })
18
+ const onlySelectedShape = editor.getOnlySelectedShape()
19
+ if (editor.canEditShape(onlySelectedShape)) {
20
+ startEditingShapeWithRichText(editor, onlySelectedShape, { selectAll: true })
31
21
  }
32
22
  }
33
23
  }
@@ -16,15 +16,15 @@ export class Pointing extends StateNode {
16
16
  }
17
17
 
18
18
  override onPointerMove(info: TLPointerEventInfo) {
19
- if (this.editor.inputs.isDragging) {
20
- const { originPagePoint } = this.editor.inputs
19
+ if (this.editor.inputs.getIsDragging()) {
20
+ const originPagePoint = this.editor.inputs.getOriginPagePoint()
21
21
 
22
22
  const id = createShapeId()
23
23
 
24
24
  const creatingMarkId = this.editor.markHistoryStoppingPoint(`creating_geo:${id}`)
25
25
  const newPoint = maybeSnapToGrid(originPagePoint, this.editor)
26
26
  this.editor
27
- .createShapes<TLGeoShape>([
27
+ .createShapes([
28
28
  {
29
29
  id,
30
30
  type: 'geo',
@@ -71,7 +71,7 @@ export class Pointing extends StateNode {
71
71
  }
72
72
 
73
73
  private complete() {
74
- const { originPagePoint } = this.editor.inputs
74
+ const originPagePoint = this.editor.inputs.getOriginPagePoint()
75
75
 
76
76
  const id = createShapeId()
77
77
 
@@ -88,7 +88,7 @@ export class Pointing extends StateNode {
88
88
  ? { w: 300, h: 180 }
89
89
  : { w: 200, h: 200 }
90
90
 
91
- this.editor.createShapes<TLGeoShape>([
91
+ this.editor.createShapes([
92
92
  {
93
93
  id,
94
94
  type: 'geo',
@@ -115,7 +115,7 @@ export class Pointing extends StateNode {
115
115
  if (parentTransform) delta.rot(-parentTransform.rotation())
116
116
  const newPoint = maybeSnapToGrid(new Vec(shape.x - delta.x, shape.y - delta.y), this.editor)
117
117
  this.editor.select(id)
118
- this.editor.updateShape<TLGeoShape>({
118
+ this.editor.updateShape({
119
119
  id: shape.id,
120
120
  type: 'geo',
121
121
  x: newPoint.x,