tldraw 4.3.0-next.f4772c19540d → 4.4.0-canary.29afdff6bb04

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 (637) 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 +7 -13
  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 +12 -6
  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 +20 -6
  101. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +3 -3
  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 +22 -8
  139. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +3 -3
  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 +2 -22
  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 +7 -13
  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 +13 -6
  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 +20 -6
  319. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +3 -3
  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 +23 -8
  357. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +3 -3
  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 +4 -31
  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 +11 -11
  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 +21 -11
  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 +30 -14
  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 +34 -14
  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 +4 -43
  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/notVisibleShapes.test.ts +698 -0
  609. package/src/test/resizing.test.ts +16 -22
  610. package/src/test/selection-omnibus.test.ts +13 -13
  611. package/src/test/shapeutils.test.ts +1 -1
  612. package/src/test/spacebarPanning.test.ts +28 -10
  613. package/src/test/styles2.test.tsx +1 -1
  614. package/src/test/styles3.test.ts +5 -5
  615. package/src/test/test-jsx.tsx +72 -57
  616. package/src/test/text.test.ts +15 -17
  617. package/src/test/translating.test.ts +6 -8
  618. package/src/test/ui/BackToContent.test.tsx +111 -0
  619. package/tldraw.css +41 -35
  620. package/dist-cjs/lib/shapes/shared/useForceSolid.js.map +0 -7
  621. package/dist-cjs/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.js.map +0 -7
  622. package/dist-cjs/lib/ui/components/TopPanel/DefaultTopPanel.js +0 -32
  623. package/dist-cjs/lib/ui/components/TopPanel/DefaultTopPanel.js.map +0 -7
  624. package/dist-cjs/lib/utils/text/textDirection.js +0 -51
  625. package/dist-cjs/lib/utils/text/textDirection.js.map +0 -7
  626. package/dist-esm/lib/shapes/shared/useForceSolid.mjs +0 -9
  627. package/dist-esm/lib/shapes/shared/useForceSolid.mjs.map +0 -7
  628. package/dist-esm/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.mjs +0 -8
  629. package/dist-esm/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.mjs.map +0 -7
  630. package/dist-esm/lib/ui/components/TopPanel/DefaultTopPanel.mjs +0 -12
  631. package/dist-esm/lib/ui/components/TopPanel/DefaultTopPanel.mjs.map +0 -7
  632. package/dist-esm/lib/utils/text/textDirection.mjs +0 -31
  633. package/dist-esm/lib/utils/text/textDirection.mjs.map +0 -7
  634. package/src/lib/shapes/shared/useForceSolid.ts +0 -6
  635. package/src/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.ts +0 -10
  636. package/src/lib/ui/components/TopPanel/DefaultTopPanel.tsx +0 -10
  637. package/src/lib/utils/text/textDirection.ts +0 -32
@@ -0,0 +1,698 @@
1
+ import {
2
+ Box,
3
+ Geometry2d,
4
+ PageRecordType,
5
+ RecordProps,
6
+ Rectangle2d,
7
+ ShapeUtil,
8
+ T,
9
+ TLShape,
10
+ createShapeId,
11
+ } from '@tldraw/editor'
12
+ import { TestEditor } from './TestEditor'
13
+
14
+ let editor: TestEditor
15
+
16
+ beforeEach(() => {
17
+ editor = new TestEditor()
18
+ editor.updateViewportScreenBounds(new Box(0, 0, 1000, 1000))
19
+ editor.setCamera({ x: 0, y: 0, z: 1 })
20
+ })
21
+
22
+ afterEach(() => {
23
+ editor?.dispose()
24
+ })
25
+
26
+ // Custom test shape for testing canCull behavior
27
+ declare module '@tldraw/tlschema' {
28
+ export interface TLGlobalShapePropsMap {
29
+ 'not-visible-test-shape': { w: number; h: number; canCull: boolean }
30
+ }
31
+ }
32
+
33
+ type ITestShape = TLShape<'not-visible-test-shape'>
34
+
35
+ class TestShape extends ShapeUtil<ITestShape> {
36
+ static override type = 'not-visible-test-shape' as const
37
+ static override props: RecordProps<ITestShape> = {
38
+ w: T.number,
39
+ h: T.number,
40
+ canCull: T.boolean,
41
+ }
42
+ getDefaultProps(): ITestShape['props'] {
43
+ return { w: 100, h: 100, canCull: true }
44
+ }
45
+ getGeometry(shape: ITestShape): Geometry2d {
46
+ return new Rectangle2d({
47
+ width: shape.props.w,
48
+ height: shape.props.h,
49
+ isFilled: false,
50
+ })
51
+ }
52
+ override canCull(shape: ITestShape): boolean {
53
+ return shape.props.canCull
54
+ }
55
+ override canEdit() {
56
+ return true
57
+ }
58
+ indicator() {}
59
+ component() {}
60
+ }
61
+
62
+ describe('notVisibleShapes - basic culling', () => {
63
+ it('should identify shapes outside viewport', () => {
64
+ const insideId = createShapeId('inside')
65
+ const outsideId = createShapeId('outside')
66
+
67
+ editor.createShapes([
68
+ { id: insideId, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } },
69
+ { id: outsideId, type: 'geo', x: 2000, y: 2000, props: { w: 100, h: 100 } },
70
+ ])
71
+
72
+ const notVisible = editor.getNotVisibleShapes()
73
+
74
+ expect(notVisible.has(insideId)).toBe(false)
75
+ expect(notVisible.has(outsideId)).toBe(true)
76
+ })
77
+
78
+ it('should update when shapes move in/out of viewport', () => {
79
+ const shapeId = createShapeId('moving')
80
+ editor.createShapes([{ id: shapeId, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } }])
81
+
82
+ // Initially visible
83
+ let notVisible = editor.getNotVisibleShapes()
84
+ expect(notVisible.has(shapeId)).toBe(false)
85
+
86
+ // Move outside viewport
87
+ editor.updateShapes([{ id: shapeId, type: 'geo', x: 2000, y: 2000 }])
88
+ notVisible = editor.getNotVisibleShapes()
89
+ expect(notVisible.has(shapeId)).toBe(true)
90
+
91
+ // Move back inside
92
+ editor.updateShapes([{ id: shapeId, type: 'geo', x: 100, y: 100 }])
93
+ notVisible = editor.getNotVisibleShapes()
94
+ expect(notVisible.has(shapeId)).toBe(false)
95
+ })
96
+
97
+ it('should update when viewport moves', () => {
98
+ const shapeId = createShapeId('stationary')
99
+ editor.createShapes([{ id: shapeId, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } }])
100
+
101
+ // Initially visible
102
+ let notVisible = editor.getNotVisibleShapes()
103
+ expect(notVisible.has(shapeId)).toBe(false)
104
+
105
+ // Pan viewport away from shape
106
+ editor.setCamera({ x: -2000, y: -2000, z: 1 })
107
+ notVisible = editor.getNotVisibleShapes()
108
+ expect(notVisible.has(shapeId)).toBe(true)
109
+
110
+ // Pan back
111
+ editor.setCamera({ x: 0, y: 0, z: 1 })
112
+ notVisible = editor.getNotVisibleShapes()
113
+ expect(notVisible.has(shapeId)).toBe(false)
114
+ })
115
+
116
+ it('should update when zoom level changes', () => {
117
+ const shapeId = createShapeId('shape')
118
+
119
+ // Create shape just outside initial viewport
120
+ editor.createShapes([{ id: shapeId, type: 'geo', x: 1100, y: 500, props: { w: 100, h: 100 } }])
121
+
122
+ // Initially outside
123
+ let notVisible = editor.getNotVisibleShapes()
124
+ expect(notVisible.has(shapeId)).toBe(true)
125
+
126
+ // Zoom out - viewport bounds expand, shape becomes visible
127
+ editor.setCamera({ x: 0, y: 0, z: 0.5 })
128
+ notVisible = editor.getNotVisibleShapes()
129
+ expect(notVisible.has(shapeId)).toBe(false)
130
+
131
+ // Zoom back in
132
+ editor.setCamera({ x: 0, y: 0, z: 1 })
133
+ notVisible = editor.getNotVisibleShapes()
134
+ expect(notVisible.has(shapeId)).toBe(true)
135
+ })
136
+
137
+ it('should keep very large shape visible when partially in viewport', () => {
138
+ const largeShapeId = createShapeId('large')
139
+
140
+ // Create massive shape that extends far beyond viewport
141
+ editor.createShapes([
142
+ {
143
+ id: largeShapeId,
144
+ type: 'geo',
145
+ x: -5000,
146
+ y: -5000,
147
+ props: { w: 10000, h: 10000 },
148
+ },
149
+ ])
150
+
151
+ // Shape should be visible (viewport is inside it)
152
+ const notVisible = editor.getNotVisibleShapes()
153
+ expect(notVisible.has(largeShapeId)).toBe(false)
154
+ })
155
+ })
156
+
157
+ describe('notVisibleShapes - canCull behavior', () => {
158
+ it('should not cull shapes that return false from canCull', () => {
159
+ // Register TestShape temporarily for this test
160
+ const testEditor = new TestEditor({ shapeUtils: [TestShape] })
161
+ testEditor.updateViewportScreenBounds(new Box(0, 0, 1000, 1000))
162
+ testEditor.setCamera({ x: 0, y: 0, z: 1 })
163
+
164
+ const cullableId = createShapeId('cullable')
165
+ const nonCullableId = createShapeId('non-cullable')
166
+
167
+ testEditor.createShapes([
168
+ {
169
+ id: cullableId,
170
+ type: 'not-visible-test-shape',
171
+ x: 2000,
172
+ y: 2000,
173
+ props: { canCull: true },
174
+ },
175
+ {
176
+ id: nonCullableId,
177
+ type: 'not-visible-test-shape',
178
+ x: 2000,
179
+ y: 2000,
180
+ props: { canCull: false },
181
+ },
182
+ ])
183
+
184
+ const notVisible = testEditor.getNotVisibleShapes()
185
+
186
+ expect(notVisible.has(cullableId)).toBe(true)
187
+ expect(notVisible.has(nonCullableId)).toBe(false)
188
+
189
+ testEditor.dispose()
190
+ })
191
+ })
192
+
193
+ describe('notVisibleShapes - selected shapes', () => {
194
+ it('should not cull selected shapes even if outside viewport', () => {
195
+ const shapeId = createShapeId('selected')
196
+ editor.createShapes([{ id: shapeId, type: 'geo', x: 2000, y: 2000, props: { w: 100, h: 100 } }])
197
+
198
+ // Not selected - should be in notVisible and culled
199
+ let notVisible = editor.getNotVisibleShapes()
200
+ let culled = editor.getCulledShapes()
201
+ expect(notVisible.has(shapeId)).toBe(true)
202
+ expect(culled.has(shapeId)).toBe(true)
203
+
204
+ // Select it - still in notVisible but not culled
205
+ editor.select(shapeId)
206
+ notVisible = editor.getNotVisibleShapes()
207
+ culled = editor.getCulledShapes()
208
+ expect(notVisible.has(shapeId)).toBe(true)
209
+ expect(culled.has(shapeId)).toBe(false)
210
+
211
+ // Deselect - back in culled
212
+ editor.selectNone()
213
+ notVisible = editor.getNotVisibleShapes()
214
+ culled = editor.getCulledShapes()
215
+ expect(notVisible.has(shapeId)).toBe(true)
216
+ expect(culled.has(shapeId)).toBe(true)
217
+ })
218
+ })
219
+
220
+ describe('notVisibleShapes - caching', () => {
221
+ it('should return same Set object when contents unchanged', () => {
222
+ editor.createShapes([{ id: createShapeId('shape1'), type: 'geo', x: 2000, y: 2000 }])
223
+
224
+ const notVisible1 = editor.getNotVisibleShapes()
225
+ const notVisible2 = editor.getNotVisibleShapes()
226
+
227
+ // Should return same reference when nothing changed
228
+ expect(notVisible1).toBe(notVisible2)
229
+ })
230
+
231
+ it('should return new Set object when contents change', () => {
232
+ const shapeId = createShapeId('moving')
233
+ editor.createShapes([{ id: shapeId, type: 'geo', x: 2000, y: 2000 }])
234
+
235
+ const notVisible1 = editor.getNotVisibleShapes()
236
+
237
+ // Move shape into viewport
238
+ editor.updateShapes([{ id: shapeId, type: 'geo', x: 100, y: 100 }])
239
+
240
+ const notVisible2 = editor.getNotVisibleShapes()
241
+
242
+ // Should return different reference when contents changed
243
+ expect(notVisible1).not.toBe(notVisible2)
244
+ })
245
+ })
246
+
247
+ describe('notVisibleShapes - multiple pages', () => {
248
+ it('should only cull shapes on current page', () => {
249
+ const page1 = editor.getCurrentPageId()
250
+
251
+ // Create shapes on page 1
252
+ const page1Shape1 = createShapeId('page1-inside')
253
+ const page1Shape2 = createShapeId('page1-outside')
254
+ editor.createShapes([
255
+ { id: page1Shape1, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } },
256
+ { id: page1Shape2, type: 'geo', x: 2000, y: 2000, props: { w: 100, h: 100 } },
257
+ ])
258
+
259
+ // Create page 2
260
+ const page2 = PageRecordType.createId('page2')
261
+ editor.createPage({ name: 'page2', id: page2 })
262
+ editor.setCurrentPage(page2)
263
+
264
+ // Create shapes on page 2
265
+ const page2Shape1 = createShapeId('page2-inside')
266
+ const page2Shape2 = createShapeId('page2-outside')
267
+ editor.createShapes([
268
+ { id: page2Shape1, type: 'geo', x: 200, y: 200, props: { w: 100, h: 100 } },
269
+ { id: page2Shape2, type: 'geo', x: 3000, y: 3000, props: { w: 100, h: 100 } },
270
+ ])
271
+
272
+ // Check page 2 culling
273
+ let notVisible = editor.getNotVisibleShapes()
274
+ expect(notVisible.has(page2Shape1)).toBe(false)
275
+ expect(notVisible.has(page2Shape2)).toBe(true)
276
+ // Page 1 shapes should not be in the set at all
277
+ expect(notVisible.has(page1Shape1)).toBe(false)
278
+ expect(notVisible.has(page1Shape2)).toBe(false)
279
+
280
+ // Switch back to page 1
281
+ editor.setCurrentPage(page1)
282
+
283
+ // Check page 1 culling
284
+ notVisible = editor.getNotVisibleShapes()
285
+ expect(notVisible.has(page1Shape1)).toBe(false)
286
+ expect(notVisible.has(page1Shape2)).toBe(true)
287
+ // Page 2 shapes should not be in the set
288
+ expect(notVisible.has(page2Shape1)).toBe(false)
289
+ expect(notVisible.has(page2Shape2)).toBe(false)
290
+ })
291
+
292
+ it('should maintain separate spatial indexes per page', () => {
293
+ const page1 = editor.getCurrentPageId()
294
+
295
+ // Create many shapes on page 1
296
+ for (let i = 0; i < 100; i++) {
297
+ editor.createShapes([
298
+ {
299
+ id: createShapeId(`page1-shape-${i}`),
300
+ type: 'geo',
301
+ x: (i % 10) * 200,
302
+ y: Math.floor(i / 10) * 200,
303
+ },
304
+ ])
305
+ }
306
+
307
+ // Create page 2
308
+ const page2 = PageRecordType.createId('page2')
309
+ editor.createPage({ name: 'page2', id: page2 })
310
+ editor.setCurrentPage(page2)
311
+
312
+ // Create different shapes on page 2
313
+ for (let i = 0; i < 50; i++) {
314
+ editor.createShapes([
315
+ {
316
+ id: createShapeId(`page2-shape-${i}`),
317
+ type: 'geo',
318
+ x: (i % 5) * 300,
319
+ y: Math.floor(i / 5) * 300,
320
+ },
321
+ ])
322
+ }
323
+
324
+ // Check page 2
325
+ const notVisiblePage2 = editor.getNotVisibleShapes()
326
+ const page2ShapeIds = editor.getCurrentPageShapeIds()
327
+ expect(page2ShapeIds.size).toBe(50)
328
+
329
+ // Switch to page 1
330
+ editor.setCurrentPage(page1)
331
+ const notVisiblePage1 = editor.getNotVisibleShapes()
332
+ const page1ShapeIds = editor.getCurrentPageShapeIds()
333
+ expect(page1ShapeIds.size).toBe(100)
334
+
335
+ // Results should be different (different shapes on each page)
336
+ expect(notVisiblePage1.size).not.toBe(notVisiblePage2.size)
337
+
338
+ // No page 2 shapes should appear in page 1 results
339
+ for (const id of notVisiblePage1) {
340
+ expect(id.includes('page2')).toBe(false)
341
+ }
342
+
343
+ // No page 1 shapes should appear in page 2 results
344
+ for (const id of notVisiblePage2) {
345
+ expect(id.includes('page1')).toBe(false)
346
+ }
347
+ })
348
+
349
+ it('should update indexes when switching pages', () => {
350
+ const page1 = editor.getCurrentPageId()
351
+
352
+ // Create shape outside viewport on page 1
353
+ const page1OutsideShape = createShapeId('page1-outside')
354
+ editor.createShapes([{ id: page1OutsideShape, type: 'geo', x: 2000, y: 2000 }])
355
+
356
+ // Verify it's culled
357
+ let notVisible = editor.getNotVisibleShapes()
358
+ expect(notVisible.has(page1OutsideShape)).toBe(true)
359
+
360
+ // Create page 2 and switch to it
361
+ const page2 = PageRecordType.createId('page2')
362
+ editor.createPage({ name: 'page2', id: page2 })
363
+ editor.setCurrentPage(page2)
364
+
365
+ // Create shape inside viewport on page 2
366
+ const page2InsideShape = createShapeId('page2-inside')
367
+ editor.createShapes([{ id: page2InsideShape, type: 'geo', x: 100, y: 100 }])
368
+
369
+ // Page 2 shape should not be culled
370
+ notVisible = editor.getNotVisibleShapes()
371
+ expect(notVisible.has(page2InsideShape)).toBe(false)
372
+ // Page 1 shape should not appear in results
373
+ expect(notVisible.has(page1OutsideShape)).toBe(false)
374
+
375
+ // Switch back to page 1
376
+ editor.setCurrentPage(page1)
377
+
378
+ // Page 1 shape should still be culled
379
+ notVisible = editor.getNotVisibleShapes()
380
+ expect(notVisible.has(page1OutsideShape)).toBe(true)
381
+ // Page 2 shape should not appear
382
+ expect(notVisible.has(page2InsideShape)).toBe(false)
383
+ })
384
+ })
385
+
386
+ describe('notVisibleShapes - arrows with bindings', () => {
387
+ it('should not cull selected arrow even if outside viewport', () => {
388
+ // Create arrow outside viewport
389
+ editor.setCurrentTool('arrow')
390
+ editor.pointerDown(2000, 2000)
391
+ editor.pointerMove(2200, 2000)
392
+ editor.pointerUp(2200, 2000)
393
+
394
+ const arrow = editor.getCurrentPageShapes().find((s) => s.type === 'arrow')!
395
+ expect(arrow).toBeDefined()
396
+
397
+ // Arrow outside viewport, selected by arrow tool
398
+ let notVisible = editor.getNotVisibleShapes()
399
+ let culled = editor.getCulledShapes()
400
+ expect(notVisible.has(arrow.id)).toBe(true)
401
+ // Arrow is selected after creation, so not culled
402
+ expect(culled.has(arrow.id)).toBe(false)
403
+
404
+ // Deselect arrow
405
+ editor.selectNone()
406
+ notVisible = editor.getNotVisibleShapes()
407
+ culled = editor.getCulledShapes()
408
+ expect(notVisible.has(arrow.id)).toBe(true)
409
+ expect(culled.has(arrow.id)).toBe(true) // Now culled
410
+
411
+ // Select arrow again - should not be culled
412
+ editor.select(arrow.id)
413
+ notVisible = editor.getNotVisibleShapes()
414
+ culled = editor.getCulledShapes()
415
+ expect(notVisible.has(arrow.id)).toBe(true)
416
+ expect(culled.has(arrow.id)).toBe(false) // Not culled because selected
417
+ })
418
+
419
+ it('should make arrow visible when bound shapes move into viewport', () => {
420
+ const boxAId = createShapeId('boxA')
421
+ const boxBId = createShapeId('boxB')
422
+
423
+ // Create two boxes outside viewport
424
+ editor.createShapes([
425
+ { id: boxAId, type: 'geo', x: 2000, y: 2000, props: { w: 100, h: 100 } },
426
+ { id: boxBId, type: 'geo', x: 2200, y: 2000, props: { w: 100, h: 100 } },
427
+ ])
428
+
429
+ // Draw arrow between them (arrow is also outside viewport)
430
+ editor.setCurrentTool('arrow')
431
+ editor.pointerDown(2050, 2050)
432
+ editor.pointerMove(2250, 2050)
433
+ editor.pointerUp(2250, 2050)
434
+
435
+ const arrow = editor.getCurrentPageShapes().find((s) => s.type === 'arrow')!
436
+ expect(arrow).toBeDefined()
437
+
438
+ // Deselect all
439
+ editor.selectNone()
440
+
441
+ // Verify all invisible initially
442
+ let notVisible = editor.getNotVisibleShapes()
443
+ expect(notVisible.has(boxAId)).toBe(true)
444
+ expect(notVisible.has(boxBId)).toBe(true)
445
+ expect(notVisible.has(arrow.id)).toBe(true)
446
+
447
+ // Move bound shapes INTO viewport (arrow record doesn't change, but bounds do)
448
+ editor.updateShapes([
449
+ { id: boxAId, type: 'geo', x: 100, y: 100 },
450
+ { id: boxBId, type: 'geo', x: 300, y: 100 },
451
+ ])
452
+
453
+ // CRITICAL: Arrow should now be visible even though arrow shape didn't update
454
+ notVisible = editor.getNotVisibleShapes()
455
+ expect(notVisible.has(boxAId)).toBe(false)
456
+ expect(notVisible.has(boxBId)).toBe(false)
457
+ expect(notVisible.has(arrow.id)).toBe(false) // Arrow visible due to reactive bounds
458
+ })
459
+
460
+ it('should update arrow visibility when only one bound shape moves', () => {
461
+ const boxAId = createShapeId('boxA')
462
+ const boxBId = createShapeId('boxB')
463
+
464
+ // Create boxes inside viewport
465
+ editor.createShapes([
466
+ { id: boxAId, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } },
467
+ { id: boxBId, type: 'geo', x: 300, y: 100, props: { w: 100, h: 100 } },
468
+ ])
469
+
470
+ // Create arrow
471
+ editor.setCurrentTool('arrow')
472
+ editor.pointerDown(150, 150)
473
+ editor.pointerMove(350, 150)
474
+ editor.pointerUp(350, 150)
475
+
476
+ const arrow = editor.getCurrentPageShapes().find((s) => s.type === 'arrow')!
477
+ editor.selectNone()
478
+
479
+ // All visible
480
+ let notVisible = editor.getNotVisibleShapes()
481
+ expect(notVisible.has(arrow.id)).toBe(false)
482
+
483
+ // Move only boxA outside viewport (boxB stays visible)
484
+ editor.updateShapes([{ id: boxAId, type: 'geo', x: 2000, y: 2000 }])
485
+ notVisible = editor.getNotVisibleShapes()
486
+
487
+ // Arrow should still be visible (one endpoint visible)
488
+ expect(notVisible.has(boxAId)).toBe(true)
489
+ expect(notVisible.has(boxBId)).toBe(false)
490
+ expect(notVisible.has(arrow.id)).toBe(false)
491
+ })
492
+
493
+ it('should keep arrow visible when endpoints are in viewport but body extends outside', () => {
494
+ const boxAId = createShapeId('boxA')
495
+ const boxBId = createShapeId('boxB')
496
+
497
+ // Create boxes near opposite edges of viewport
498
+ editor.createShapes([
499
+ { id: boxAId, type: 'geo', x: 50, y: 500, props: { w: 100, h: 100 } },
500
+ { id: boxBId, type: 'geo', x: 850, y: 500, props: { w: 100, h: 100 } },
501
+ ])
502
+
503
+ // Create curved arrow that might extend outside viewport
504
+ editor.setCurrentTool('arrow')
505
+ editor.pointerDown(100, 550)
506
+ editor.pointerMove(900, 550)
507
+ editor.pointerUp(900, 550)
508
+
509
+ const arrow = editor.getCurrentPageShapes().find((s) => s.type === 'arrow')!
510
+
511
+ // Make it curved so body might extend outside
512
+ editor.updateShapes([
513
+ {
514
+ id: arrow.id,
515
+ type: 'arrow',
516
+ props: { bend: 100 }, // Significant curve
517
+ },
518
+ ])
519
+
520
+ editor.selectNone()
521
+ const notVisible = editor.getNotVisibleShapes()
522
+
523
+ // Arrow should be visible since endpoints are visible
524
+ expect(notVisible.has(arrow.id)).toBe(false)
525
+ })
526
+ })
527
+
528
+ describe('notVisibleShapes - frames', () => {
529
+ it('should cull frame when outside viewport', () => {
530
+ const frameId = createShapeId('frame')
531
+
532
+ // Create frame outside viewport
533
+ editor.createShapes([
534
+ { id: frameId, type: 'frame', x: 2000, y: 2000, props: { w: 500, h: 500 } },
535
+ ])
536
+
537
+ // Frame should be not visible
538
+ const notVisible = editor.getNotVisibleShapes()
539
+ expect(notVisible.has(frameId)).toBe(true)
540
+ })
541
+
542
+ it('should keep frame visible when inside viewport', () => {
543
+ const frameId = createShapeId('frame')
544
+
545
+ // Create frame inside viewport
546
+ editor.createShapes([{ id: frameId, type: 'frame', x: 100, y: 100, props: { w: 500, h: 500 } }])
547
+
548
+ // Frame should be visible
549
+ const notVisible = editor.getNotVisibleShapes()
550
+ expect(notVisible.has(frameId)).toBe(false)
551
+ })
552
+
553
+ it('should cull children when frame is outside viewport', () => {
554
+ const frameId = createShapeId('frame')
555
+ const childId = createShapeId('child')
556
+
557
+ // Frame outside viewport
558
+ editor.createShapes([
559
+ { id: frameId, type: 'frame', x: 2000, y: 2000, props: { w: 500, h: 500 } },
560
+ ])
561
+
562
+ // Child inside frame
563
+ editor.createShapes([
564
+ {
565
+ id: childId,
566
+ type: 'geo',
567
+ x: 2100,
568
+ y: 2100,
569
+ parentId: frameId,
570
+ props: { w: 100, h: 100 },
571
+ },
572
+ ])
573
+
574
+ const notVisible = editor.getNotVisibleShapes()
575
+
576
+ // Both should be outside viewport
577
+ expect(notVisible.has(frameId)).toBe(true)
578
+ expect(notVisible.has(childId)).toBe(true)
579
+ })
580
+
581
+ it('should handle multiple levels of nesting', () => {
582
+ const frameId = createShapeId('frame')
583
+ const groupId = createShapeId('group')
584
+ const childId = createShapeId('child')
585
+
586
+ // Frame inside viewport
587
+ editor.createShapes([{ id: frameId, type: 'frame', x: 100, y: 100, props: { w: 500, h: 500 } }])
588
+
589
+ // Create shapes inside frame to form a group
590
+ editor.createShapes([
591
+ { id: groupId, type: 'geo', x: 200, y: 200, parentId: frameId, props: { w: 100, h: 100 } },
592
+ { id: childId, type: 'geo', x: 250, y: 200, parentId: frameId, props: { w: 100, h: 100 } },
593
+ ])
594
+
595
+ // Group them (now they're nested inside frame)
596
+ editor.select(groupId, childId)
597
+ const actualGroupId = createShapeId('actual-group')
598
+ editor.groupShapes(editor.getSelectedShapeIds(), { groupId: actualGroupId })
599
+
600
+ editor.selectNone()
601
+
602
+ // All should be visible
603
+ let notVisible = editor.getNotVisibleShapes()
604
+ expect(notVisible.has(frameId)).toBe(false)
605
+ expect(notVisible.has(actualGroupId)).toBe(false)
606
+
607
+ // Move frame outside viewport
608
+ editor.updateShapes([{ id: frameId, type: 'frame', x: 3000, y: 3000 }])
609
+
610
+ notVisible = editor.getNotVisibleShapes()
611
+
612
+ // All should now be invisible
613
+ expect(notVisible.has(frameId)).toBe(true)
614
+ expect(notVisible.has(actualGroupId)).toBe(true)
615
+ })
616
+ })
617
+
618
+ describe('notVisibleShapes - groups', () => {
619
+ it('should keep group visible when any child is visible', () => {
620
+ const groupId = createShapeId('group')
621
+ const childAId = createShapeId('childA')
622
+ const childBId = createShapeId('childB')
623
+
624
+ // Create shapes - one inside, one outside viewport
625
+ editor.createShapes([
626
+ { id: childAId, type: 'geo', x: 2000, y: 2000, props: { w: 100, h: 100 } },
627
+ { id: childBId, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } },
628
+ ])
629
+
630
+ // Group the shapes
631
+ editor.select(childAId, childBId)
632
+ editor.groupShapes(editor.getSelectedShapeIds(), { groupId })
633
+
634
+ editor.selectNone()
635
+
636
+ // Group has visible child, so group bounds include visible area
637
+ const notVisible = editor.getNotVisibleShapes()
638
+ expect(notVisible.has(groupId)).toBe(false) // Group visible because childB visible
639
+ expect(notVisible.has(childBId)).toBe(false) // childB is visible
640
+ expect(notVisible.has(childAId)).toBe(true) // childA is outside
641
+ })
642
+
643
+ it('should cull group when all children are outside viewport', () => {
644
+ const groupId = createShapeId('group')
645
+ const childAId = createShapeId('childA')
646
+ const childBId = createShapeId('childB')
647
+
648
+ // Create group with all children outside viewport
649
+ editor.createShapes([
650
+ { id: childAId, type: 'geo', x: 2000, y: 2000, props: { w: 100, h: 100 } },
651
+ { id: childBId, type: 'geo', x: 2200, y: 2200, props: { w: 100, h: 100 } },
652
+ ])
653
+
654
+ // Group the shapes
655
+ editor.select(childAId, childBId)
656
+ editor.groupShapes(editor.getSelectedShapeIds(), { groupId })
657
+
658
+ // All should be not visible
659
+ const notVisible = editor.getNotVisibleShapes()
660
+ expect(notVisible.has(groupId)).toBe(true)
661
+ expect(notVisible.has(childAId)).toBe(true)
662
+ expect(notVisible.has(childBId)).toBe(true)
663
+ })
664
+
665
+ it('should update visibility when children move', () => {
666
+ const groupId = createShapeId('group')
667
+ const childAId = createShapeId('childA')
668
+ const childBId = createShapeId('childB')
669
+
670
+ // Create group with all children inside viewport
671
+ editor.createShapes([
672
+ { id: childAId, type: 'geo', x: 100, y: 100, props: { w: 100, h: 100 } },
673
+ { id: childBId, type: 'geo', x: 200, y: 200, props: { w: 100, h: 100 } },
674
+ ])
675
+
676
+ // Group the shapes
677
+ editor.select(childAId, childBId)
678
+ editor.groupShapes(editor.getSelectedShapeIds(), { groupId })
679
+
680
+ // Initially visible
681
+ let notVisible = editor.getNotVisibleShapes()
682
+ // Group is selected after creation, so not checking it
683
+ expect(notVisible.has(childAId)).toBe(false)
684
+ expect(notVisible.has(childBId)).toBe(false)
685
+
686
+ // Deselect and move both children outside viewport
687
+ editor.selectNone()
688
+ editor.updateShapes([
689
+ { id: childAId, type: 'geo', x: 2000, y: 2000 },
690
+ { id: childBId, type: 'geo', x: 2200, y: 2200 },
691
+ ])
692
+ notVisible = editor.getNotVisibleShapes()
693
+ // All should now be not visible
694
+ expect(notVisible.has(groupId)).toBe(true)
695
+ expect(notVisible.has(childAId)).toBe(true)
696
+ expect(notVisible.has(childBId)).toBe(true)
697
+ })
698
+ })