@bigbluebutton/tldraw 2.0.0-alpha.19

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 (1357) hide show
  1. package/LICENSE +190 -0
  2. package/dist-cjs/index.d.ts +2954 -0
  3. package/dist-cjs/index.js +216 -0
  4. package/dist-cjs/index.js.map +7 -0
  5. package/dist-cjs/lib/Tldraw.js +136 -0
  6. package/dist-cjs/lib/Tldraw.js.map +7 -0
  7. package/dist-cjs/lib/canvas/TldrawCropHandles.js +164 -0
  8. package/dist-cjs/lib/canvas/TldrawCropHandles.js.map +7 -0
  9. package/dist-cjs/lib/canvas/TldrawHandles.js +37 -0
  10. package/dist-cjs/lib/canvas/TldrawHandles.js.map +7 -0
  11. package/dist-cjs/lib/canvas/TldrawHoveredShapeIndicator.js +42 -0
  12. package/dist-cjs/lib/canvas/TldrawHoveredShapeIndicator.js.map +7 -0
  13. package/dist-cjs/lib/canvas/TldrawScribble.js +72 -0
  14. package/dist-cjs/lib/canvas/TldrawScribble.js.map +7 -0
  15. package/dist-cjs/lib/canvas/TldrawSelectionBackground.js +44 -0
  16. package/dist-cjs/lib/canvas/TldrawSelectionBackground.js.map +7 -0
  17. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js +509 -0
  18. package/dist-cjs/lib/canvas/TldrawSelectionForeground.js.map +7 -0
  19. package/dist-cjs/lib/defaultExternalContentHandlers.js +400 -0
  20. package/dist-cjs/lib/defaultExternalContentHandlers.js.map +7 -0
  21. package/dist-cjs/lib/defaultShapeTools.js +42 -0
  22. package/dist-cjs/lib/defaultShapeTools.js.map +7 -0
  23. package/dist-cjs/lib/defaultShapeUtils.js +50 -0
  24. package/dist-cjs/lib/defaultShapeUtils.js.map +7 -0
  25. package/dist-cjs/lib/defaultSideEffects.js +69 -0
  26. package/dist-cjs/lib/defaultSideEffects.js.map +7 -0
  27. package/dist-cjs/lib/defaultTools.js +30 -0
  28. package/dist-cjs/lib/defaultTools.js.map +7 -0
  29. package/dist-cjs/lib/shapes/arrow/ArrowShapeTool.js +33 -0
  30. package/dist-cjs/lib/shapes/arrow/ArrowShapeTool.js.map +7 -0
  31. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js +805 -0
  32. package/dist-cjs/lib/shapes/arrow/ArrowShapeUtil.js.map +7 -0
  33. package/dist-cjs/lib/shapes/arrow/components/ArrowTextLabel.js +114 -0
  34. package/dist-cjs/lib/shapes/arrow/components/ArrowTextLabel.js.map +7 -0
  35. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js +53 -0
  36. package/dist-cjs/lib/shapes/arrow/toolStates/Idle.js.map +7 -0
  37. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js +182 -0
  38. package/dist-cjs/lib/shapes/arrow/toolStates/Pointing.js.map +7 -0
  39. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js +163 -0
  40. package/dist-cjs/lib/shapes/bookmark/BookmarkShapeUtil.js.map +7 -0
  41. package/dist-cjs/lib/shapes/draw/DrawShapeTool.js +37 -0
  42. package/dist-cjs/lib/shapes/draw/DrawShapeTool.js.map +7 -0
  43. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js +243 -0
  44. package/dist-cjs/lib/shapes/draw/DrawShapeUtil.js.map +7 -0
  45. package/dist-cjs/lib/shapes/draw/getPath.js +102 -0
  46. package/dist-cjs/lib/shapes/draw/getPath.js.map +7 -0
  47. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js +556 -0
  48. package/dist-cjs/lib/shapes/draw/toolStates/Drawing.js.map +7 -0
  49. package/dist-cjs/lib/shapes/draw/toolStates/Idle.js +37 -0
  50. package/dist-cjs/lib/shapes/draw/toolStates/Idle.js.map +7 -0
  51. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js +192 -0
  52. package/dist-cjs/lib/shapes/embed/EmbedShapeUtil.js.map +7 -0
  53. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js +66 -0
  54. package/dist-cjs/lib/shapes/frame/FrameShapeTool.js.map +7 -0
  55. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js +234 -0
  56. package/dist-cjs/lib/shapes/frame/FrameShapeUtil.js.map +7 -0
  57. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js +106 -0
  58. package/dist-cjs/lib/shapes/frame/components/FrameHeading.js.map +7 -0
  59. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js +101 -0
  60. package/dist-cjs/lib/shapes/frame/components/FrameLabelInput.js.map +7 -0
  61. package/dist-cjs/lib/shapes/geo/GeoShapeTool.js +33 -0
  62. package/dist-cjs/lib/shapes/geo/GeoShapeTool.js.map +7 -0
  63. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js +999 -0
  64. package/dist-cjs/lib/shapes/geo/GeoShapeUtil.js.map +7 -0
  65. package/dist-cjs/lib/shapes/geo/cloudOutline.js +288 -0
  66. package/dist-cjs/lib/shapes/geo/cloudOutline.js.map +7 -0
  67. package/dist-cjs/lib/shapes/geo/components/DashStyleCloud.js +124 -0
  68. package/dist-cjs/lib/shapes/geo/components/DashStyleCloud.js.map +7 -0
  69. package/dist-cjs/lib/shapes/geo/components/DashStyleEllipse.js +123 -0
  70. package/dist-cjs/lib/shapes/geo/components/DashStyleEllipse.js.map +7 -0
  71. package/dist-cjs/lib/shapes/geo/components/DashStyleOval.js +118 -0
  72. package/dist-cjs/lib/shapes/geo/components/DashStyleOval.js.map +7 -0
  73. package/dist-cjs/lib/shapes/geo/components/DashStylePolygon.js +155 -0
  74. package/dist-cjs/lib/shapes/geo/components/DashStylePolygon.js.map +7 -0
  75. package/dist-cjs/lib/shapes/geo/components/DrawStyleCloud.js +79 -0
  76. package/dist-cjs/lib/shapes/geo/components/DrawStyleCloud.js.map +7 -0
  77. package/dist-cjs/lib/shapes/geo/components/DrawStyleEllipse.js +133 -0
  78. package/dist-cjs/lib/shapes/geo/components/DrawStyleEllipse.js.map +7 -0
  79. package/dist-cjs/lib/shapes/geo/components/DrawStylePolygon.js +93 -0
  80. package/dist-cjs/lib/shapes/geo/components/DrawStylePolygon.js.map +7 -0
  81. package/dist-cjs/lib/shapes/geo/components/SolidStyleCloud.js +79 -0
  82. package/dist-cjs/lib/shapes/geo/components/SolidStyleCloud.js.map +7 -0
  83. package/dist-cjs/lib/shapes/geo/components/SolidStyleEllipse.js +84 -0
  84. package/dist-cjs/lib/shapes/geo/components/SolidStyleEllipse.js.map +7 -0
  85. package/dist-cjs/lib/shapes/geo/components/SolidStyleOval.js +99 -0
  86. package/dist-cjs/lib/shapes/geo/components/SolidStyleOval.js.map +7 -0
  87. package/dist-cjs/lib/shapes/geo/components/SolidStylePolygon.js +86 -0
  88. package/dist-cjs/lib/shapes/geo/components/SolidStylePolygon.js.map +7 -0
  89. package/dist-cjs/lib/shapes/geo/helpers.js +53 -0
  90. package/dist-cjs/lib/shapes/geo/helpers.js.map +7 -0
  91. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js +53 -0
  92. package/dist-cjs/lib/shapes/geo/toolStates/Idle.js.map +7 -0
  93. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js +118 -0
  94. package/dist-cjs/lib/shapes/geo/toolStates/Pointing.js.map +7 -0
  95. package/dist-cjs/lib/shapes/highlight/HighlightShapeTool.js +37 -0
  96. package/dist-cjs/lib/shapes/highlight/HighlightShapeTool.js.map +7 -0
  97. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js +208 -0
  98. package/dist-cjs/lib/shapes/highlight/HighlightShapeUtil.js.map +7 -0
  99. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js +262 -0
  100. package/dist-cjs/lib/shapes/image/ImageShapeUtil.js.map +7 -0
  101. package/dist-cjs/lib/shapes/line/LineShapeTool.js +33 -0
  102. package/dist-cjs/lib/shapes/line/LineShapeTool.js.map +7 -0
  103. package/dist-cjs/lib/shapes/line/LineShapeUtil.js +359 -0
  104. package/dist-cjs/lib/shapes/line/LineShapeUtil.js.map +7 -0
  105. package/dist-cjs/lib/shapes/line/components/getLinePath.js +88 -0
  106. package/dist-cjs/lib/shapes/line/components/getLinePath.js.map +7 -0
  107. package/dist-cjs/lib/shapes/line/components/svg.js +73 -0
  108. package/dist-cjs/lib/shapes/line/components/svg.js.map +7 -0
  109. package/dist-cjs/lib/shapes/line/toolStates/Idle.js +39 -0
  110. package/dist-cjs/lib/shapes/line/toolStates/Idle.js.map +7 -0
  111. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js +145 -0
  112. package/dist-cjs/lib/shapes/line/toolStates/Pointing.js.map +7 -0
  113. package/dist-cjs/lib/shapes/note/NoteShapeTool.js +33 -0
  114. package/dist-cjs/lib/shapes/note/NoteShapeTool.js.map +7 -0
  115. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js +205 -0
  116. package/dist-cjs/lib/shapes/note/NoteShapeUtil.js.map +7 -0
  117. package/dist-cjs/lib/shapes/note/toolStates/Idle.js +37 -0
  118. package/dist-cjs/lib/shapes/note/toolStates/Idle.js.map +7 -0
  119. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js +114 -0
  120. package/dist-cjs/lib/shapes/note/toolStates/Pointing.js.map +7 -0
  121. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js +65 -0
  122. package/dist-cjs/lib/shapes/shared/HyperlinkButton.js.map +7 -0
  123. package/dist-cjs/lib/shapes/shared/ShapeFill.js +117 -0
  124. package/dist-cjs/lib/shapes/shared/ShapeFill.js.map +7 -0
  125. package/dist-cjs/lib/shapes/shared/TextHelpers.js +228 -0
  126. package/dist-cjs/lib/shapes/shared/TextHelpers.js.map +7 -0
  127. package/dist-cjs/lib/shapes/shared/TextLabel.js +138 -0
  128. package/dist-cjs/lib/shapes/shared/TextLabel.js.map +7 -0
  129. package/dist-cjs/lib/shapes/shared/createTextSvgElementFromSpans.js +75 -0
  130. package/dist-cjs/lib/shapes/shared/createTextSvgElementFromSpans.js.map +7 -0
  131. package/dist-cjs/lib/shapes/shared/default-shape-constants.js +72 -0
  132. package/dist-cjs/lib/shapes/shared/default-shape-constants.js.map +7 -0
  133. package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js +252 -0
  134. package/dist-cjs/lib/shapes/shared/defaultStyleDefs.js.map +7 -0
  135. package/dist-cjs/lib/shapes/shared/freehand/getStroke.js +33 -0
  136. package/dist-cjs/lib/shapes/shared/freehand/getStroke.js.map +7 -0
  137. package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js +175 -0
  138. package/dist-cjs/lib/shapes/shared/freehand/getStrokeOutlinePoints.js.map +7 -0
  139. package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js +144 -0
  140. package/dist-cjs/lib/shapes/shared/freehand/getStrokePoints.js.map +7 -0
  141. package/dist-cjs/lib/shapes/shared/freehand/getStrokeRadius.js +27 -0
  142. package/dist-cjs/lib/shapes/shared/freehand/getStrokeRadius.js.map +7 -0
  143. package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js +101 -0
  144. package/dist-cjs/lib/shapes/shared/freehand/setStrokePointRadii.js.map +7 -0
  145. package/dist-cjs/lib/shapes/shared/freehand/svg.js +56 -0
  146. package/dist-cjs/lib/shapes/shared/freehand/svg.js.map +7 -0
  147. package/dist-cjs/lib/shapes/shared/freehand/svgInk.js +163 -0
  148. package/dist-cjs/lib/shapes/shared/freehand/svgInk.js.map +7 -0
  149. package/dist-cjs/lib/shapes/shared/freehand/types.js +17 -0
  150. package/dist-cjs/lib/shapes/shared/freehand/types.js.map +7 -0
  151. package/dist-cjs/lib/shapes/shared/getBrowserCanvasMaxSize.js +52 -0
  152. package/dist-cjs/lib/shapes/shared/getBrowserCanvasMaxSize.js.map +7 -0
  153. package/dist-cjs/lib/shapes/shared/getPerfectDashProps.js +96 -0
  154. package/dist-cjs/lib/shapes/shared/getPerfectDashProps.js.map +7 -0
  155. package/dist-cjs/lib/shapes/shared/getTextLabelSvgElement.js +56 -0
  156. package/dist-cjs/lib/shapes/shared/getTextLabelSvgElement.js.map +7 -0
  157. package/dist-cjs/lib/shapes/shared/legacyProps.js +42 -0
  158. package/dist-cjs/lib/shapes/shared/legacyProps.js.map +7 -0
  159. package/dist-cjs/lib/shapes/shared/polygon-helpers.js +116 -0
  160. package/dist-cjs/lib/shapes/shared/polygon-helpers.js.map +7 -0
  161. package/dist-cjs/lib/shapes/shared/resizeBox.js +117 -0
  162. package/dist-cjs/lib/shapes/shared/resizeBox.js.map +7 -0
  163. package/dist-cjs/lib/shapes/shared/resizeScaled.js +48 -0
  164. package/dist-cjs/lib/shapes/shared/resizeScaled.js.map +7 -0
  165. package/dist-cjs/lib/shapes/shared/rotated-box-shadow.js +50 -0
  166. package/dist-cjs/lib/shapes/shared/rotated-box-shadow.js.map +7 -0
  167. package/dist-cjs/lib/shapes/shared/useColorSpace.js +39 -0
  168. package/dist-cjs/lib/shapes/shared/useColorSpace.js.map +7 -0
  169. package/dist-cjs/lib/shapes/shared/useEditableText.js +179 -0
  170. package/dist-cjs/lib/shapes/shared/useEditableText.js.map +7 -0
  171. package/dist-cjs/lib/shapes/shared/useForceSolid.js +29 -0
  172. package/dist-cjs/lib/shapes/shared/useForceSolid.js.map +7 -0
  173. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js +38 -0
  174. package/dist-cjs/lib/shapes/shared/usePrefersReducedMotion.js.map +7 -0
  175. package/dist-cjs/lib/shapes/text/TextShapeTool.js +33 -0
  176. package/dist-cjs/lib/shapes/text/TextShapeTool.js.map +7 -0
  177. package/dist-cjs/lib/shapes/text/TextShapeUtil.js +341 -0
  178. package/dist-cjs/lib/shapes/text/TextShapeUtil.js.map +7 -0
  179. package/dist-cjs/lib/shapes/text/toolStates/Idle.js +62 -0
  180. package/dist-cjs/lib/shapes/text/toolStates/Idle.js.map +7 -0
  181. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js +109 -0
  182. package/dist-cjs/lib/shapes/text/toolStates/Pointing.js.map +7 -0
  183. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js +202 -0
  184. package/dist-cjs/lib/shapes/video/VideoShapeUtil.js.map +7 -0
  185. package/dist-cjs/lib/tools/EraserTool/EraserTool.js +36 -0
  186. package/dist-cjs/lib/tools/EraserTool/EraserTool.js.map +7 -0
  187. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js +111 -0
  188. package/dist-cjs/lib/tools/EraserTool/childStates/Erasing.js.map +7 -0
  189. package/dist-cjs/lib/tools/EraserTool/childStates/Idle.js +34 -0
  190. package/dist-cjs/lib/tools/EraserTool/childStates/Idle.js.map +7 -0
  191. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js +84 -0
  192. package/dist-cjs/lib/tools/EraserTool/childStates/Pointing.js.map +7 -0
  193. package/dist-cjs/lib/tools/HandTool/HandTool.js +58 -0
  194. package/dist-cjs/lib/tools/HandTool/HandTool.js.map +7 -0
  195. package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js +58 -0
  196. package/dist-cjs/lib/tools/HandTool/childStates/Dragging.js.map +7 -0
  197. package/dist-cjs/lib/tools/HandTool/childStates/Idle.js +37 -0
  198. package/dist-cjs/lib/tools/HandTool/childStates/Idle.js.map +7 -0
  199. package/dist-cjs/lib/tools/HandTool/childStates/Pointing.js +55 -0
  200. package/dist-cjs/lib/tools/HandTool/childStates/Pointing.js.map +7 -0
  201. package/dist-cjs/lib/tools/LaserTool/LaserTool.js +35 -0
  202. package/dist-cjs/lib/tools/LaserTool/LaserTool.js.map +7 -0
  203. package/dist-cjs/lib/tools/LaserTool/childStates/Idle.js +31 -0
  204. package/dist-cjs/lib/tools/LaserTool/childStates/Idle.js.map +7 -0
  205. package/dist-cjs/lib/tools/LaserTool/childStates/Lasering.js +66 -0
  206. package/dist-cjs/lib/tools/LaserTool/childStates/Lasering.js.map +7 -0
  207. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js +100 -0
  208. package/dist-cjs/lib/tools/SelectTool/DragAndDropManager.js.map +7 -0
  209. package/dist-cjs/lib/tools/SelectTool/SelectTool.js +70 -0
  210. package/dist-cjs/lib/tools/SelectTool/SelectTool.js.map +7 -0
  211. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js +145 -0
  212. package/dist-cjs/lib/tools/SelectTool/childStates/Brushing.js.map +7 -0
  213. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js +33 -0
  214. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/Crop.js.map +7 -0
  215. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js +204 -0
  216. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/Idle.js.map +7 -0
  217. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.js +39 -0
  218. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.js.map +7 -0
  219. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.js +101 -0
  220. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.js.map +7 -0
  221. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.js +58 -0
  222. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.js.map +7 -0
  223. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/crop-constants.js +25 -0
  224. package/dist-cjs/lib/tools/SelectTool/childStates/Crop/crop-constants.js.map +7 -0
  225. package/dist-cjs/lib/tools/SelectTool/childStates/Cropping.js +210 -0
  226. package/dist-cjs/lib/tools/SelectTool/childStates/Cropping.js.map +7 -0
  227. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js +230 -0
  228. package/dist-cjs/lib/tools/SelectTool/childStates/DraggingHandle.js.map +7 -0
  229. package/dist-cjs/lib/tools/SelectTool/childStates/EditingShape.js +121 -0
  230. package/dist-cjs/lib/tools/SelectTool/childStates/EditingShape.js.map +7 -0
  231. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js +461 -0
  232. package/dist-cjs/lib/tools/SelectTool/childStates/Idle.js.map +7 -0
  233. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js +56 -0
  234. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCanvas.js.map +7 -0
  235. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCropHandle.js +89 -0
  236. package/dist-cjs/lib/tools/SelectTool/childStates/PointingCropHandle.js.map +7 -0
  237. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js +67 -0
  238. package/dist-cjs/lib/tools/SelectTool/childStates/PointingHandle.js.map +7 -0
  239. package/dist-cjs/lib/tools/SelectTool/childStates/PointingResizeHandle.js +91 -0
  240. package/dist-cjs/lib/tools/SelectTool/childStates/PointingResizeHandle.js.map +7 -0
  241. package/dist-cjs/lib/tools/SelectTool/childStates/PointingRotateHandle.js +83 -0
  242. package/dist-cjs/lib/tools/SelectTool/childStates/PointingRotateHandle.js.map +7 -0
  243. package/dist-cjs/lib/tools/SelectTool/childStates/PointingSelection.js +73 -0
  244. package/dist-cjs/lib/tools/SelectTool/childStates/PointingSelection.js.map +7 -0
  245. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js +176 -0
  246. package/dist-cjs/lib/tools/SelectTool/childStates/PointingShape.js.map +7 -0
  247. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js +371 -0
  248. package/dist-cjs/lib/tools/SelectTool/childStates/Resizing.js.map +7 -0
  249. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js +148 -0
  250. package/dist-cjs/lib/tools/SelectTool/childStates/Rotating.js.map +7 -0
  251. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js +140 -0
  252. package/dist-cjs/lib/tools/SelectTool/childStates/ScribbleBrushing.js.map +7 -0
  253. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js +315 -0
  254. package/dist-cjs/lib/tools/SelectTool/childStates/Translating.js.map +7 -0
  255. package/dist-cjs/lib/tools/SelectTool/children/DraggingHandle.js +230 -0
  256. package/dist-cjs/lib/tools/SelectTool/children/DraggingHandle.js.map +7 -0
  257. package/dist-cjs/lib/tools/ZoomTool/ZoomTool.js +79 -0
  258. package/dist-cjs/lib/tools/ZoomTool/ZoomTool.js.map +7 -0
  259. package/dist-cjs/lib/tools/ZoomTool/childStates/Idle.js +35 -0
  260. package/dist-cjs/lib/tools/ZoomTool/childStates/Idle.js.map +7 -0
  261. package/dist-cjs/lib/tools/ZoomTool/childStates/Pointing.js +55 -0
  262. package/dist-cjs/lib/tools/ZoomTool/childStates/Pointing.js.map +7 -0
  263. package/dist-cjs/lib/tools/ZoomTool/childStates/ZoomBrushing.js +72 -0
  264. package/dist-cjs/lib/tools/ZoomTool/childStates/ZoomBrushing.js.map +7 -0
  265. package/dist-cjs/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.js +41 -0
  266. package/dist-cjs/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.js.map +7 -0
  267. package/dist-cjs/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.js +28 -0
  268. package/dist-cjs/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.js.map +7 -0
  269. package/dist-cjs/lib/tools/selection-logic/selectOnCanvasPointerUp.js +80 -0
  270. package/dist-cjs/lib/tools/selection-logic/selectOnCanvasPointerUp.js.map +7 -0
  271. package/dist-cjs/lib/tools/selection-logic/updateHoveredId.js +47 -0
  272. package/dist-cjs/lib/tools/selection-logic/updateHoveredId.js.map +7 -0
  273. package/dist-cjs/lib/ui/TldrawUi.js +155 -0
  274. package/dist-cjs/lib/ui/TldrawUi.js.map +7 -0
  275. package/dist-cjs/lib/ui/TldrawUiContextProvider.js +57 -0
  276. package/dist-cjs/lib/ui/TldrawUiContextProvider.js.map +7 -0
  277. package/dist-cjs/lib/ui/assetUrls.js +67 -0
  278. package/dist-cjs/lib/ui/assetUrls.js.map +7 -0
  279. package/dist-cjs/lib/ui/components/ActionsMenu.js +96 -0
  280. package/dist-cjs/lib/ui/components/ActionsMenu.js.map +7 -0
  281. package/dist-cjs/lib/ui/components/BackToContent.js +67 -0
  282. package/dist-cjs/lib/ui/components/BackToContent.js.map +7 -0
  283. package/dist-cjs/lib/ui/components/ContextMenu.js +214 -0
  284. package/dist-cjs/lib/ui/components/ContextMenu.js.map +7 -0
  285. package/dist-cjs/lib/ui/components/DebugPanel.js +334 -0
  286. package/dist-cjs/lib/ui/components/DebugPanel.js.map +7 -0
  287. package/dist-cjs/lib/ui/components/Dialogs.js +64 -0
  288. package/dist-cjs/lib/ui/components/Dialogs.js.map +7 -0
  289. package/dist-cjs/lib/ui/components/DuplicateButton.js +47 -0
  290. package/dist-cjs/lib/ui/components/DuplicateButton.js.map +7 -0
  291. package/dist-cjs/lib/ui/components/EditLinkDialog.js +161 -0
  292. package/dist-cjs/lib/ui/components/EditLinkDialog.js.map +7 -0
  293. package/dist-cjs/lib/ui/components/EmbedDialog.js +152 -0
  294. package/dist-cjs/lib/ui/components/EmbedDialog.js.map +7 -0
  295. package/dist-cjs/lib/ui/components/FollowingIndicator.js +41 -0
  296. package/dist-cjs/lib/ui/components/FollowingIndicator.js.map +7 -0
  297. package/dist-cjs/lib/ui/components/HTMLCanvas.js +66 -0
  298. package/dist-cjs/lib/ui/components/HTMLCanvas.js.map +7 -0
  299. package/dist-cjs/lib/ui/components/HelpMenu.js +116 -0
  300. package/dist-cjs/lib/ui/components/HelpMenu.js.map +7 -0
  301. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog.js +74 -0
  302. package/dist-cjs/lib/ui/components/KeyboardShortcutsDialog.js.map +7 -0
  303. package/dist-cjs/lib/ui/components/LanguageMenu.js +60 -0
  304. package/dist-cjs/lib/ui/components/LanguageMenu.js.map +7 -0
  305. package/dist-cjs/lib/ui/components/Menu.js +139 -0
  306. package/dist-cjs/lib/ui/components/Menu.js.map +7 -0
  307. package/dist-cjs/lib/ui/components/MenuZone.js +51 -0
  308. package/dist-cjs/lib/ui/components/MenuZone.js.map +7 -0
  309. package/dist-cjs/lib/ui/components/MobileStylePanel.js +69 -0
  310. package/dist-cjs/lib/ui/components/MobileStylePanel.js.map +7 -0
  311. package/dist-cjs/lib/ui/components/MoveToPageMenu.js +142 -0
  312. package/dist-cjs/lib/ui/components/MoveToPageMenu.js.map +7 -0
  313. package/dist-cjs/lib/ui/components/NavigationZone/Minimap.js +208 -0
  314. package/dist-cjs/lib/ui/components/NavigationZone/Minimap.js.map +7 -0
  315. package/dist-cjs/lib/ui/components/NavigationZone/MinimapManager.js +293 -0
  316. package/dist-cjs/lib/ui/components/NavigationZone/MinimapManager.js.map +7 -0
  317. package/dist-cjs/lib/ui/components/NavigationZone/NavigationZone.js +103 -0
  318. package/dist-cjs/lib/ui/components/NavigationZone/NavigationZone.js.map +7 -0
  319. package/dist-cjs/lib/ui/components/NavigationZone/ZoomMenu.js +118 -0
  320. package/dist-cjs/lib/ui/components/NavigationZone/ZoomMenu.js.map +7 -0
  321. package/dist-cjs/lib/ui/components/OfflineIndicator/OfflineIndicator.js +47 -0
  322. package/dist-cjs/lib/ui/components/OfflineIndicator/OfflineIndicator.js.map +7 -0
  323. package/dist-cjs/lib/ui/components/PageMenu/PageItemInput.js +63 -0
  324. package/dist-cjs/lib/ui/components/PageMenu/PageItemInput.js.map +7 -0
  325. package/dist-cjs/lib/ui/components/PageMenu/PageItemSubmenu.js +88 -0
  326. package/dist-cjs/lib/ui/components/PageMenu/PageItemSubmenu.js.map +7 -0
  327. package/dist-cjs/lib/ui/components/PageMenu/PageMenu.js +395 -0
  328. package/dist-cjs/lib/ui/components/PageMenu/PageMenu.js.map +7 -0
  329. package/dist-cjs/lib/ui/components/PageMenu/edit-pages-shared.js +45 -0
  330. package/dist-cjs/lib/ui/components/PageMenu/edit-pages-shared.js.map +7 -0
  331. package/dist-cjs/lib/ui/components/PenModeToggle.js +45 -0
  332. package/dist-cjs/lib/ui/components/PenModeToggle.js.map +7 -0
  333. package/dist-cjs/lib/ui/components/RedoButton.js +49 -0
  334. package/dist-cjs/lib/ui/components/RedoButton.js.map +7 -0
  335. package/dist-cjs/lib/ui/components/Spinner.js +41 -0
  336. package/dist-cjs/lib/ui/components/Spinner.js.map +7 -0
  337. package/dist-cjs/lib/ui/components/StopFollowing.js +45 -0
  338. package/dist-cjs/lib/ui/components/StopFollowing.js.map +7 -0
  339. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js +138 -0
  340. package/dist-cjs/lib/ui/components/StylePanel/DoubleDropdownPicker.js.map +7 -0
  341. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js +89 -0
  342. package/dist-cjs/lib/ui/components/StylePanel/DropdownPicker.js.map +7 -0
  343. package/dist-cjs/lib/ui/components/StylePanel/StylePanel.js +313 -0
  344. package/dist-cjs/lib/ui/components/StylePanel/StylePanel.js.map +7 -0
  345. package/dist-cjs/lib/ui/components/StylePanel/styles.js +119 -0
  346. package/dist-cjs/lib/ui/components/StylePanel/styles.js.map +7 -0
  347. package/dist-cjs/lib/ui/components/Toasts.js +101 -0
  348. package/dist-cjs/lib/ui/components/Toasts.js.map +7 -0
  349. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js +73 -0
  350. package/dist-cjs/lib/ui/components/Toolbar/ToggleToolLockedButton.js.map +7 -0
  351. package/dist-cjs/lib/ui/components/Toolbar/Toolbar.js +247 -0
  352. package/dist-cjs/lib/ui/components/Toolbar/Toolbar.js.map +7 -0
  353. package/dist-cjs/lib/ui/components/TrashButton.js +51 -0
  354. package/dist-cjs/lib/ui/components/TrashButton.js.map +7 -0
  355. package/dist-cjs/lib/ui/components/UndoButton.js +49 -0
  356. package/dist-cjs/lib/ui/components/UndoButton.js.map +7 -0
  357. package/dist-cjs/lib/ui/components/primitives/Button.js +79 -0
  358. package/dist-cjs/lib/ui/components/primitives/Button.js.map +7 -0
  359. package/dist-cjs/lib/ui/components/primitives/ButtonPicker.js +121 -0
  360. package/dist-cjs/lib/ui/components/primitives/ButtonPicker.js.map +7 -0
  361. package/dist-cjs/lib/ui/components/primitives/Dialog.js +70 -0
  362. package/dist-cjs/lib/ui/components/primitives/Dialog.js.map +7 -0
  363. package/dist-cjs/lib/ui/components/primitives/DropdownMenu.js +187 -0
  364. package/dist-cjs/lib/ui/components/primitives/DropdownMenu.js.map +7 -0
  365. package/dist-cjs/lib/ui/components/primitives/Icon.js +71 -0
  366. package/dist-cjs/lib/ui/components/primitives/Icon.js.map +7 -0
  367. package/dist-cjs/lib/ui/components/primitives/Input.js +155 -0
  368. package/dist-cjs/lib/ui/components/primitives/Input.js.map +7 -0
  369. package/dist-cjs/lib/ui/components/primitives/Kbd.js +29 -0
  370. package/dist-cjs/lib/ui/components/primitives/Kbd.js.map +7 -0
  371. package/dist-cjs/lib/ui/components/primitives/Popover.js +69 -0
  372. package/dist-cjs/lib/ui/components/primitives/Popover.js.map +7 -0
  373. package/dist-cjs/lib/ui/components/primitives/Slider.js +69 -0
  374. package/dist-cjs/lib/ui/components/primitives/Slider.js.map +7 -0
  375. package/dist-cjs/lib/ui/components/primitives/shared.js +44 -0
  376. package/dist-cjs/lib/ui/components/primitives/shared.js.map +7 -0
  377. package/dist-cjs/lib/ui/constants.js +25 -0
  378. package/dist-cjs/lib/ui/constants.js.map +7 -0
  379. package/dist-cjs/lib/ui/hooks/clipboard/pasteExcalidrawContent.js +454 -0
  380. package/dist-cjs/lib/ui/hooks/clipboard/pasteExcalidrawContent.js.map +7 -0
  381. package/dist-cjs/lib/ui/hooks/clipboard/pasteFiles.js +37 -0
  382. package/dist-cjs/lib/ui/hooks/clipboard/pasteFiles.js.map +7 -0
  383. package/dist-cjs/lib/ui/hooks/clipboard/pasteTldrawContent.js +32 -0
  384. package/dist-cjs/lib/ui/hooks/clipboard/pasteTldrawContent.js.map +7 -0
  385. package/dist-cjs/lib/ui/hooks/clipboard/pasteUrl.js +48 -0
  386. package/dist-cjs/lib/ui/hooks/clipboard/pasteUrl.js.map +7 -0
  387. package/dist-cjs/lib/ui/hooks/menuHelpers.js +172 -0
  388. package/dist-cjs/lib/ui/hooks/menuHelpers.js.map +7 -0
  389. package/dist-cjs/lib/ui/hooks/useActions.js +1152 -0
  390. package/dist-cjs/lib/ui/hooks/useActions.js.map +7 -0
  391. package/dist-cjs/lib/ui/hooks/useActionsMenuSchema.js +112 -0
  392. package/dist-cjs/lib/ui/hooks/useActionsMenuSchema.js.map +7 -0
  393. package/dist-cjs/lib/ui/hooks/useAssetUrls.js +41 -0
  394. package/dist-cjs/lib/ui/hooks/useAssetUrls.js.map +7 -0
  395. package/dist-cjs/lib/ui/hooks/useBreakpoint.js +64 -0
  396. package/dist-cjs/lib/ui/hooks/useBreakpoint.js.map +7 -0
  397. package/dist-cjs/lib/ui/hooks/useCanRedo.js +29 -0
  398. package/dist-cjs/lib/ui/hooks/useCanRedo.js.map +7 -0
  399. package/dist-cjs/lib/ui/hooks/useCanUndo.js +29 -0
  400. package/dist-cjs/lib/ui/hooks/useCanUndo.js.map +7 -0
  401. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js +463 -0
  402. package/dist-cjs/lib/ui/hooks/useClipboardEvents.js.map +7 -0
  403. package/dist-cjs/lib/ui/hooks/useContextMenuSchema.js +228 -0
  404. package/dist-cjs/lib/ui/hooks/useContextMenuSchema.js.map +7 -0
  405. package/dist-cjs/lib/ui/hooks/useCopyAs.js +47 -0
  406. package/dist-cjs/lib/ui/hooks/useCopyAs.js.map +7 -0
  407. package/dist-cjs/lib/ui/hooks/useDialogsProvider.js +108 -0
  408. package/dist-cjs/lib/ui/hooks/useDialogsProvider.js.map +7 -0
  409. package/dist-cjs/lib/ui/hooks/useEditorEvents.js +43 -0
  410. package/dist-cjs/lib/ui/hooks/useEditorEvents.js.map +7 -0
  411. package/dist-cjs/lib/ui/hooks/useEventsProvider.js +47 -0
  412. package/dist-cjs/lib/ui/hooks/useEventsProvider.js.map +7 -0
  413. package/dist-cjs/lib/ui/hooks/useExportAs.js +51 -0
  414. package/dist-cjs/lib/ui/hooks/useExportAs.js.map +7 -0
  415. package/dist-cjs/lib/ui/hooks/useHasLinkShapeSelected.js +36 -0
  416. package/dist-cjs/lib/ui/hooks/useHasLinkShapeSelected.js.map +7 -0
  417. package/dist-cjs/lib/ui/hooks/useHelpMenuSchema.js +103 -0
  418. package/dist-cjs/lib/ui/hooks/useHelpMenuSchema.js.map +7 -0
  419. package/dist-cjs/lib/ui/hooks/useHighDpiCanvas.js +35 -0
  420. package/dist-cjs/lib/ui/hooks/useHighDpiCanvas.js.map +7 -0
  421. package/dist-cjs/lib/ui/hooks/useInsertMedia.js +57 -0
  422. package/dist-cjs/lib/ui/hooks/useInsertMedia.js.map +7 -0
  423. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js +138 -0
  424. package/dist-cjs/lib/ui/hooks/useKeyboardShortcuts.js.map +7 -0
  425. package/dist-cjs/lib/ui/hooks/useKeyboardShortcutsSchema.js +134 -0
  426. package/dist-cjs/lib/ui/hooks/useKeyboardShortcutsSchema.js.map +7 -0
  427. package/dist-cjs/lib/ui/hooks/useLocalStorageState.js +59 -0
  428. package/dist-cjs/lib/ui/hooks/useLocalStorageState.js.map +7 -0
  429. package/dist-cjs/lib/ui/hooks/useMenuIsOpen.js +74 -0
  430. package/dist-cjs/lib/ui/hooks/useMenuIsOpen.js.map +7 -0
  431. package/dist-cjs/lib/ui/hooks/useMenuSchema.js +260 -0
  432. package/dist-cjs/lib/ui/hooks/useMenuSchema.js.map +7 -0
  433. package/dist-cjs/lib/ui/hooks/useOnlyFlippableShape.js +38 -0
  434. package/dist-cjs/lib/ui/hooks/useOnlyFlippableShape.js.map +7 -0
  435. package/dist-cjs/lib/ui/hooks/usePreloadAssets.js +106 -0
  436. package/dist-cjs/lib/ui/hooks/usePreloadAssets.js.map +7 -0
  437. package/dist-cjs/lib/ui/hooks/usePreloadIcons.js +51 -0
  438. package/dist-cjs/lib/ui/hooks/usePreloadIcons.js.map +7 -0
  439. package/dist-cjs/lib/ui/hooks/usePrint.js +220 -0
  440. package/dist-cjs/lib/ui/hooks/usePrint.js.map +7 -0
  441. package/dist-cjs/lib/ui/hooks/useReadonly.js +29 -0
  442. package/dist-cjs/lib/ui/hooks/useReadonly.js.map +7 -0
  443. package/dist-cjs/lib/ui/hooks/useRevelantStyles.js +45 -0
  444. package/dist-cjs/lib/ui/hooks/useRevelantStyles.js.map +7 -0
  445. package/dist-cjs/lib/ui/hooks/useShowAutoSizeToggle.js +36 -0
  446. package/dist-cjs/lib/ui/hooks/useShowAutoSizeToggle.js.map +7 -0
  447. package/dist-cjs/lib/ui/hooks/useToastsProvider.js +53 -0
  448. package/dist-cjs/lib/ui/hooks/useToastsProvider.js.map +7 -0
  449. package/dist-cjs/lib/ui/hooks/useToolbarSchema.js +99 -0
  450. package/dist-cjs/lib/ui/hooks/useToolbarSchema.js.map +7 -0
  451. package/dist-cjs/lib/ui/hooks/useTools.js +235 -0
  452. package/dist-cjs/lib/ui/hooks/useTools.js.map +7 -0
  453. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js +17 -0
  454. package/dist-cjs/lib/ui/hooks/useTranslation/TLUiTranslationKey.js.map +7 -0
  455. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js +377 -0
  456. package/dist-cjs/lib/ui/hooks/useTranslation/defaultTranslation.js.map +7 -0
  457. package/dist-cjs/lib/ui/hooks/useTranslation/translations.js +67 -0
  458. package/dist-cjs/lib/ui/hooks/useTranslation/translations.js.map +7 -0
  459. package/dist-cjs/lib/ui/hooks/useTranslation/useLanguages.js +32 -0
  460. package/dist-cjs/lib/ui/hooks/useTranslation/useLanguages.js.map +7 -0
  461. package/dist-cjs/lib/ui/hooks/useTranslation/useTranslation.js +101 -0
  462. package/dist-cjs/lib/ui/hooks/useTranslation/useTranslation.js.map +7 -0
  463. package/dist-cjs/lib/ui/icon-types.js +190 -0
  464. package/dist-cjs/lib/ui/icon-types.js.map +7 -0
  465. package/dist-cjs/lib/ui/overrides.js +178 -0
  466. package/dist-cjs/lib/ui/overrides.js.map +7 -0
  467. package/dist-cjs/lib/ui/version.js +25 -0
  468. package/dist-cjs/lib/ui/version.js.map +7 -0
  469. package/dist-cjs/lib/utils/assets/assets.js +91 -0
  470. package/dist-cjs/lib/utils/assets/assets.js.map +7 -0
  471. package/dist-cjs/lib/utils/assets/is-gif-animated.js +74 -0
  472. package/dist-cjs/lib/utils/assets/is-gif-animated.js.map +7 -0
  473. package/dist-cjs/lib/utils/assets.js +91 -0
  474. package/dist-cjs/lib/utils/assets.js.map +7 -0
  475. package/dist-cjs/lib/utils/embeds/embeds.js +85 -0
  476. package/dist-cjs/lib/utils/embeds/embeds.js.map +7 -0
  477. package/dist-cjs/lib/utils/export/copyAs.js +116 -0
  478. package/dist-cjs/lib/utils/export/copyAs.js.map +7 -0
  479. package/dist-cjs/lib/utils/export/export.js +117 -0
  480. package/dist-cjs/lib/utils/export/export.js.map +7 -0
  481. package/dist-cjs/lib/utils/export/exportAs.js +88 -0
  482. package/dist-cjs/lib/utils/export/exportAs.js.map +7 -0
  483. package/dist-cjs/lib/utils/frames/frames.js +92 -0
  484. package/dist-cjs/lib/utils/frames/frames.js.map +7 -0
  485. package/dist-cjs/lib/utils/static-assets/assetUrls.js +48 -0
  486. package/dist-cjs/lib/utils/static-assets/assetUrls.js.map +7 -0
  487. package/dist-cjs/lib/utils/text/text.js +57 -0
  488. package/dist-cjs/lib/utils/text/text.js.map +7 -0
  489. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js +792 -0
  490. package/dist-cjs/lib/utils/tldr/buildFromV1Document.js.map +7 -0
  491. package/dist-cjs/lib/utils/tldr/file.js +230 -0
  492. package/dist-cjs/lib/utils/tldr/file.js.map +7 -0
  493. package/dist-esm/index.d.mts +2954 -0
  494. package/dist-esm/index.mjs +234 -0
  495. package/dist-esm/index.mjs.map +7 -0
  496. package/dist-esm/lib/Tldraw.mjs +127 -0
  497. package/dist-esm/lib/Tldraw.mjs.map +7 -0
  498. package/dist-esm/lib/canvas/TldrawCropHandles.mjs +134 -0
  499. package/dist-esm/lib/canvas/TldrawCropHandles.mjs.map +7 -0
  500. package/dist-esm/lib/canvas/TldrawHandles.mjs +17 -0
  501. package/dist-esm/lib/canvas/TldrawHandles.mjs.map +7 -0
  502. package/dist-esm/lib/canvas/TldrawHoveredShapeIndicator.mjs +26 -0
  503. package/dist-esm/lib/canvas/TldrawHoveredShapeIndicator.mjs.map +7 -0
  504. package/dist-esm/lib/canvas/TldrawScribble.mjs +42 -0
  505. package/dist-esm/lib/canvas/TldrawScribble.mjs.map +7 -0
  506. package/dist-esm/lib/canvas/TldrawSelectionBackground.mjs +28 -0
  507. package/dist-esm/lib/canvas/TldrawSelectionBackground.mjs.map +7 -0
  508. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs +487 -0
  509. package/dist-esm/lib/canvas/TldrawSelectionForeground.mjs.map +7 -0
  510. package/dist-esm/lib/defaultExternalContentHandlers.mjs +387 -0
  511. package/dist-esm/lib/defaultExternalContentHandlers.mjs.map +7 -0
  512. package/dist-esm/lib/defaultShapeTools.mjs +22 -0
  513. package/dist-esm/lib/defaultShapeTools.mjs.map +7 -0
  514. package/dist-esm/lib/defaultShapeUtils.mjs +30 -0
  515. package/dist-esm/lib/defaultShapeUtils.mjs.map +7 -0
  516. package/dist-esm/lib/defaultSideEffects.mjs +49 -0
  517. package/dist-esm/lib/defaultSideEffects.mjs.map +7 -0
  518. package/dist-esm/lib/defaultTools.mjs +10 -0
  519. package/dist-esm/lib/defaultTools.mjs.map +7 -0
  520. package/dist-esm/lib/shapes/arrow/ArrowShapeTool.mjs +13 -0
  521. package/dist-esm/lib/shapes/arrow/ArrowShapeTool.mjs.map +7 -0
  522. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs +808 -0
  523. package/dist-esm/lib/shapes/arrow/ArrowShapeUtil.mjs.map +7 -0
  524. package/dist-esm/lib/shapes/arrow/components/ArrowTextLabel.mjs +84 -0
  525. package/dist-esm/lib/shapes/arrow/components/ArrowTextLabel.mjs.map +7 -0
  526. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs +33 -0
  527. package/dist-esm/lib/shapes/arrow/toolStates/Idle.mjs.map +7 -0
  528. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs +162 -0
  529. package/dist-esm/lib/shapes/arrow/toolStates/Pointing.mjs.map +7 -0
  530. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs +154 -0
  531. package/dist-esm/lib/shapes/bookmark/BookmarkShapeUtil.mjs.map +7 -0
  532. package/dist-esm/lib/shapes/draw/DrawShapeTool.mjs +17 -0
  533. package/dist-esm/lib/shapes/draw/DrawShapeTool.mjs.map +7 -0
  534. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs +237 -0
  535. package/dist-esm/lib/shapes/draw/DrawShapeUtil.mjs.map +7 -0
  536. package/dist-esm/lib/shapes/draw/getPath.mjs +87 -0
  537. package/dist-esm/lib/shapes/draw/getPath.mjs.map +7 -0
  538. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs +546 -0
  539. package/dist-esm/lib/shapes/draw/toolStates/Drawing.mjs.map +7 -0
  540. package/dist-esm/lib/shapes/draw/toolStates/Idle.mjs +17 -0
  541. package/dist-esm/lib/shapes/draw/toolStates/Idle.mjs.map +7 -0
  542. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs +181 -0
  543. package/dist-esm/lib/shapes/embed/EmbedShapeUtil.mjs.map +7 -0
  544. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs +46 -0
  545. package/dist-esm/lib/shapes/frame/FrameShapeTool.mjs.map +7 -0
  546. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs +216 -0
  547. package/dist-esm/lib/shapes/frame/FrameShapeUtil.mjs.map +7 -0
  548. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs +93 -0
  549. package/dist-esm/lib/shapes/frame/components/FrameHeading.mjs.map +7 -0
  550. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs +81 -0
  551. package/dist-esm/lib/shapes/frame/components/FrameLabelInput.mjs.map +7 -0
  552. package/dist-esm/lib/shapes/geo/GeoShapeTool.mjs +13 -0
  553. package/dist-esm/lib/shapes/geo/GeoShapeTool.mjs.map +7 -0
  554. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs +1010 -0
  555. package/dist-esm/lib/shapes/geo/GeoShapeUtil.mjs.map +7 -0
  556. package/dist-esm/lib/shapes/geo/cloudOutline.mjs +275 -0
  557. package/dist-esm/lib/shapes/geo/cloudOutline.mjs.map +7 -0
  558. package/dist-esm/lib/shapes/geo/components/DashStyleCloud.mjs +102 -0
  559. package/dist-esm/lib/shapes/geo/components/DashStyleCloud.mjs.map +7 -0
  560. package/dist-esm/lib/shapes/geo/components/DashStyleEllipse.mjs +101 -0
  561. package/dist-esm/lib/shapes/geo/components/DashStyleEllipse.mjs.map +7 -0
  562. package/dist-esm/lib/shapes/geo/components/DashStyleOval.mjs +93 -0
  563. package/dist-esm/lib/shapes/geo/components/DashStyleOval.mjs.map +7 -0
  564. package/dist-esm/lib/shapes/geo/components/DashStylePolygon.mjs +130 -0
  565. package/dist-esm/lib/shapes/geo/components/DashStylePolygon.mjs.map +7 -0
  566. package/dist-esm/lib/shapes/geo/components/DrawStyleCloud.mjs +54 -0
  567. package/dist-esm/lib/shapes/geo/components/DrawStyleCloud.mjs.map +7 -0
  568. package/dist-esm/lib/shapes/geo/components/DrawStyleEllipse.mjs +116 -0
  569. package/dist-esm/lib/shapes/geo/components/DrawStyleEllipse.mjs.map +7 -0
  570. package/dist-esm/lib/shapes/geo/components/DrawStylePolygon.mjs +68 -0
  571. package/dist-esm/lib/shapes/geo/components/DrawStylePolygon.mjs.map +7 -0
  572. package/dist-esm/lib/shapes/geo/components/SolidStyleCloud.mjs +54 -0
  573. package/dist-esm/lib/shapes/geo/components/SolidStyleCloud.mjs.map +7 -0
  574. package/dist-esm/lib/shapes/geo/components/SolidStyleEllipse.mjs +59 -0
  575. package/dist-esm/lib/shapes/geo/components/SolidStyleEllipse.mjs.map +7 -0
  576. package/dist-esm/lib/shapes/geo/components/SolidStyleOval.mjs +74 -0
  577. package/dist-esm/lib/shapes/geo/components/SolidStyleOval.mjs.map +7 -0
  578. package/dist-esm/lib/shapes/geo/components/SolidStylePolygon.mjs +61 -0
  579. package/dist-esm/lib/shapes/geo/components/SolidStylePolygon.mjs.map +7 -0
  580. package/dist-esm/lib/shapes/geo/helpers.mjs +33 -0
  581. package/dist-esm/lib/shapes/geo/helpers.mjs.map +7 -0
  582. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs +33 -0
  583. package/dist-esm/lib/shapes/geo/toolStates/Idle.mjs.map +7 -0
  584. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs +104 -0
  585. package/dist-esm/lib/shapes/geo/toolStates/Pointing.mjs.map +7 -0
  586. package/dist-esm/lib/shapes/highlight/HighlightShapeTool.mjs +17 -0
  587. package/dist-esm/lib/shapes/highlight/HighlightShapeTool.mjs.map +7 -0
  588. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs +198 -0
  589. package/dist-esm/lib/shapes/highlight/HighlightShapeUtil.mjs.map +7 -0
  590. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs +252 -0
  591. package/dist-esm/lib/shapes/image/ImageShapeUtil.mjs.map +7 -0
  592. package/dist-esm/lib/shapes/line/LineShapeTool.mjs +13 -0
  593. package/dist-esm/lib/shapes/line/LineShapeTool.mjs.map +7 -0
  594. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs +357 -0
  595. package/dist-esm/lib/shapes/line/LineShapeUtil.mjs.map +7 -0
  596. package/dist-esm/lib/shapes/line/components/getLinePath.mjs +68 -0
  597. package/dist-esm/lib/shapes/line/components/getLinePath.mjs.map +7 -0
  598. package/dist-esm/lib/shapes/line/components/svg.mjs +57 -0
  599. package/dist-esm/lib/shapes/line/components/svg.mjs.map +7 -0
  600. package/dist-esm/lib/shapes/line/toolStates/Idle.mjs +19 -0
  601. package/dist-esm/lib/shapes/line/toolStates/Idle.mjs.map +7 -0
  602. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs +134 -0
  603. package/dist-esm/lib/shapes/line/toolStates/Pointing.mjs.map +7 -0
  604. package/dist-esm/lib/shapes/note/NoteShapeTool.mjs +13 -0
  605. package/dist-esm/lib/shapes/note/NoteShapeTool.mjs.map +7 -0
  606. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs +193 -0
  607. package/dist-esm/lib/shapes/note/NoteShapeUtil.mjs.map +7 -0
  608. package/dist-esm/lib/shapes/note/toolStates/Idle.mjs +17 -0
  609. package/dist-esm/lib/shapes/note/toolStates/Idle.mjs.map +7 -0
  610. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs +97 -0
  611. package/dist-esm/lib/shapes/note/toolStates/Pointing.mjs.map +7 -0
  612. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs +35 -0
  613. package/dist-esm/lib/shapes/shared/HyperlinkButton.mjs.map +7 -0
  614. package/dist-esm/lib/shapes/shared/ShapeFill.mjs +93 -0
  615. package/dist-esm/lib/shapes/shared/ShapeFill.mjs.map +7 -0
  616. package/dist-esm/lib/shapes/shared/TextHelpers.mjs +208 -0
  617. package/dist-esm/lib/shapes/shared/TextHelpers.mjs.map +7 -0
  618. package/dist-esm/lib/shapes/shared/TextLabel.mjs +112 -0
  619. package/dist-esm/lib/shapes/shared/TextLabel.mjs.map +7 -0
  620. package/dist-esm/lib/shapes/shared/createTextSvgElementFromSpans.mjs +57 -0
  621. package/dist-esm/lib/shapes/shared/createTextSvgElementFromSpans.mjs.map +7 -0
  622. package/dist-esm/lib/shapes/shared/default-shape-constants.mjs +52 -0
  623. package/dist-esm/lib/shapes/shared/default-shape-constants.mjs.map +7 -0
  624. package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs +240 -0
  625. package/dist-esm/lib/shapes/shared/defaultStyleDefs.mjs.map +7 -0
  626. package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs +13 -0
  627. package/dist-esm/lib/shapes/shared/freehand/getStroke.mjs.map +7 -0
  628. package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs +155 -0
  629. package/dist-esm/lib/shapes/shared/freehand/getStrokeOutlinePoints.mjs.map +7 -0
  630. package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs +124 -0
  631. package/dist-esm/lib/shapes/shared/freehand/getStrokePoints.mjs.map +7 -0
  632. package/dist-esm/lib/shapes/shared/freehand/getStrokeRadius.mjs +7 -0
  633. package/dist-esm/lib/shapes/shared/freehand/getStrokeRadius.mjs.map +7 -0
  634. package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs +81 -0
  635. package/dist-esm/lib/shapes/shared/freehand/setStrokePointRadii.mjs.map +7 -0
  636. package/dist-esm/lib/shapes/shared/freehand/svg.mjs +36 -0
  637. package/dist-esm/lib/shapes/shared/freehand/svg.mjs.map +7 -0
  638. package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs +150 -0
  639. package/dist-esm/lib/shapes/shared/freehand/svgInk.mjs.map +7 -0
  640. package/dist-esm/lib/shapes/shared/freehand/types.mjs +1 -0
  641. package/dist-esm/lib/shapes/shared/freehand/types.mjs.map +7 -0
  642. package/dist-esm/lib/shapes/shared/getBrowserCanvasMaxSize.mjs +22 -0
  643. package/dist-esm/lib/shapes/shared/getBrowserCanvasMaxSize.mjs.map +7 -0
  644. package/dist-esm/lib/shapes/shared/getPerfectDashProps.mjs +76 -0
  645. package/dist-esm/lib/shapes/shared/getPerfectDashProps.mjs.map +7 -0
  646. package/dist-esm/lib/shapes/shared/getTextLabelSvgElement.mjs +36 -0
  647. package/dist-esm/lib/shapes/shared/getTextLabelSvgElement.mjs.map +7 -0
  648. package/dist-esm/lib/shapes/shared/legacyProps.mjs +22 -0
  649. package/dist-esm/lib/shapes/shared/legacyProps.mjs.map +7 -0
  650. package/dist-esm/lib/shapes/shared/polygon-helpers.mjs +96 -0
  651. package/dist-esm/lib/shapes/shared/polygon-helpers.mjs.map +7 -0
  652. package/dist-esm/lib/shapes/shared/resizeBox.mjs +99 -0
  653. package/dist-esm/lib/shapes/shared/resizeBox.mjs.map +7 -0
  654. package/dist-esm/lib/shapes/shared/resizeScaled.mjs +28 -0
  655. package/dist-esm/lib/shapes/shared/resizeScaled.mjs.map +7 -0
  656. package/dist-esm/lib/shapes/shared/rotated-box-shadow.mjs +30 -0
  657. package/dist-esm/lib/shapes/shared/rotated-box-shadow.mjs.map +7 -0
  658. package/dist-esm/lib/shapes/shared/useColorSpace.mjs +19 -0
  659. package/dist-esm/lib/shapes/shared/useColorSpace.mjs.map +7 -0
  660. package/dist-esm/lib/shapes/shared/useEditableText.mjs +165 -0
  661. package/dist-esm/lib/shapes/shared/useEditableText.mjs.map +7 -0
  662. package/dist-esm/lib/shapes/shared/useForceSolid.mjs +9 -0
  663. package/dist-esm/lib/shapes/shared/useForceSolid.mjs.map +7 -0
  664. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs +18 -0
  665. package/dist-esm/lib/shapes/shared/usePrefersReducedMotion.mjs.map +7 -0
  666. package/dist-esm/lib/shapes/text/TextShapeTool.mjs +13 -0
  667. package/dist-esm/lib/shapes/text/TextShapeTool.mjs.map +7 -0
  668. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs +334 -0
  669. package/dist-esm/lib/shapes/text/TextShapeUtil.mjs.map +7 -0
  670. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs +42 -0
  671. package/dist-esm/lib/shapes/text/toolStates/Idle.mjs.map +7 -0
  672. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs +89 -0
  673. package/dist-esm/lib/shapes/text/toolStates/Pointing.mjs.map +7 -0
  674. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs +180 -0
  675. package/dist-esm/lib/shapes/video/VideoShapeUtil.mjs.map +7 -0
  676. package/dist-esm/lib/tools/EraserTool/EraserTool.mjs +16 -0
  677. package/dist-esm/lib/tools/EraserTool/EraserTool.mjs.map +7 -0
  678. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs +95 -0
  679. package/dist-esm/lib/tools/EraserTool/childStates/Erasing.mjs.map +7 -0
  680. package/dist-esm/lib/tools/EraserTool/childStates/Idle.mjs +14 -0
  681. package/dist-esm/lib/tools/EraserTool/childStates/Idle.mjs.map +7 -0
  682. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs +67 -0
  683. package/dist-esm/lib/tools/EraserTool/childStates/Pointing.mjs.map +7 -0
  684. package/dist-esm/lib/tools/HandTool/HandTool.mjs +38 -0
  685. package/dist-esm/lib/tools/HandTool/HandTool.mjs.map +7 -0
  686. package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs +38 -0
  687. package/dist-esm/lib/tools/HandTool/childStates/Dragging.mjs.map +7 -0
  688. package/dist-esm/lib/tools/HandTool/childStates/Idle.mjs +17 -0
  689. package/dist-esm/lib/tools/HandTool/childStates/Idle.mjs.map +7 -0
  690. package/dist-esm/lib/tools/HandTool/childStates/Pointing.mjs +35 -0
  691. package/dist-esm/lib/tools/HandTool/childStates/Pointing.mjs.map +7 -0
  692. package/dist-esm/lib/tools/LaserTool/LaserTool.mjs +15 -0
  693. package/dist-esm/lib/tools/LaserTool/LaserTool.mjs.map +7 -0
  694. package/dist-esm/lib/tools/LaserTool/childStates/Idle.mjs +11 -0
  695. package/dist-esm/lib/tools/LaserTool/childStates/Idle.mjs.map +7 -0
  696. package/dist-esm/lib/tools/LaserTool/childStates/Lasering.mjs +46 -0
  697. package/dist-esm/lib/tools/LaserTool/childStates/Lasering.mjs.map +7 -0
  698. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs +80 -0
  699. package/dist-esm/lib/tools/SelectTool/DragAndDropManager.mjs.map +7 -0
  700. package/dist-esm/lib/tools/SelectTool/SelectTool.mjs +50 -0
  701. package/dist-esm/lib/tools/SelectTool/SelectTool.mjs.map +7 -0
  702. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs +131 -0
  703. package/dist-esm/lib/tools/SelectTool/childStates/Brushing.mjs.map +7 -0
  704. package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs +13 -0
  705. package/dist-esm/lib/tools/SelectTool/childStates/Crop/Crop.mjs.map +7 -0
  706. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs +187 -0
  707. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/Idle.mjs.map +7 -0
  708. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.mjs +19 -0
  709. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.mjs.map +7 -0
  710. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.mjs +81 -0
  711. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.mjs.map +7 -0
  712. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.mjs +40 -0
  713. package/dist-esm/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.mjs.map +7 -0
  714. package/dist-esm/lib/tools/SelectTool/childStates/Crop/crop-constants.mjs +5 -0
  715. package/dist-esm/lib/tools/SelectTool/childStates/Crop/crop-constants.mjs.map +7 -0
  716. package/dist-esm/lib/tools/SelectTool/childStates/Cropping.mjs +194 -0
  717. package/dist-esm/lib/tools/SelectTool/childStates/Cropping.mjs.map +7 -0
  718. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs +217 -0
  719. package/dist-esm/lib/tools/SelectTool/childStates/DraggingHandle.mjs.map +7 -0
  720. package/dist-esm/lib/tools/SelectTool/childStates/EditingShape.mjs +103 -0
  721. package/dist-esm/lib/tools/SelectTool/childStates/EditingShape.mjs.map +7 -0
  722. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs +447 -0
  723. package/dist-esm/lib/tools/SelectTool/childStates/Idle.mjs.map +7 -0
  724. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs +36 -0
  725. package/dist-esm/lib/tools/SelectTool/childStates/PointingCanvas.mjs.map +7 -0
  726. package/dist-esm/lib/tools/SelectTool/childStates/PointingCropHandle.mjs +69 -0
  727. package/dist-esm/lib/tools/SelectTool/childStates/PointingCropHandle.mjs.map +7 -0
  728. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs +47 -0
  729. package/dist-esm/lib/tools/SelectTool/childStates/PointingHandle.mjs.map +7 -0
  730. package/dist-esm/lib/tools/SelectTool/childStates/PointingResizeHandle.mjs +73 -0
  731. package/dist-esm/lib/tools/SelectTool/childStates/PointingResizeHandle.mjs.map +7 -0
  732. package/dist-esm/lib/tools/SelectTool/childStates/PointingRotateHandle.mjs +63 -0
  733. package/dist-esm/lib/tools/SelectTool/childStates/PointingRotateHandle.mjs.map +7 -0
  734. package/dist-esm/lib/tools/SelectTool/childStates/PointingSelection.mjs +55 -0
  735. package/dist-esm/lib/tools/SelectTool/childStates/PointingSelection.mjs.map +7 -0
  736. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs +159 -0
  737. package/dist-esm/lib/tools/SelectTool/childStates/PointingShape.mjs.map +7 -0
  738. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs +360 -0
  739. package/dist-esm/lib/tools/SelectTool/childStates/Resizing.mjs.map +7 -0
  740. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs +136 -0
  741. package/dist-esm/lib/tools/SelectTool/childStates/Rotating.mjs.map +7 -0
  742. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs +125 -0
  743. package/dist-esm/lib/tools/SelectTool/childStates/ScribbleBrushing.mjs.map +7 -0
  744. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs +302 -0
  745. package/dist-esm/lib/tools/SelectTool/childStates/Translating.mjs.map +7 -0
  746. package/dist-esm/lib/tools/SelectTool/children/DraggingHandle.mjs +217 -0
  747. package/dist-esm/lib/tools/SelectTool/children/DraggingHandle.mjs.map +7 -0
  748. package/dist-esm/lib/tools/ZoomTool/ZoomTool.mjs +61 -0
  749. package/dist-esm/lib/tools/ZoomTool/ZoomTool.mjs.map +7 -0
  750. package/dist-esm/lib/tools/ZoomTool/childStates/Idle.mjs +15 -0
  751. package/dist-esm/lib/tools/ZoomTool/childStates/Idle.mjs.map +7 -0
  752. package/dist-esm/lib/tools/ZoomTool/childStates/Pointing.mjs +35 -0
  753. package/dist-esm/lib/tools/ZoomTool/childStates/Pointing.mjs.map +7 -0
  754. package/dist-esm/lib/tools/ZoomTool/childStates/ZoomBrushing.mjs +52 -0
  755. package/dist-esm/lib/tools/ZoomTool/childStates/ZoomBrushing.mjs.map +7 -0
  756. package/dist-esm/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.mjs +21 -0
  757. package/dist-esm/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.mjs.map +7 -0
  758. package/dist-esm/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.mjs +8 -0
  759. package/dist-esm/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.mjs.map +7 -0
  760. package/dist-esm/lib/tools/selection-logic/selectOnCanvasPointerUp.mjs +60 -0
  761. package/dist-esm/lib/tools/selection-logic/selectOnCanvasPointerUp.mjs.map +7 -0
  762. package/dist-esm/lib/tools/selection-logic/updateHoveredId.mjs +27 -0
  763. package/dist-esm/lib/tools/selection-logic/updateHoveredId.mjs.map +7 -0
  764. package/dist-esm/lib/ui/TldrawUi.mjs +125 -0
  765. package/dist-esm/lib/ui/TldrawUi.mjs.map +7 -0
  766. package/dist-esm/lib/ui/TldrawUiContextProvider.mjs +37 -0
  767. package/dist-esm/lib/ui/TldrawUiContextProvider.mjs.map +7 -0
  768. package/dist-esm/lib/ui/assetUrls.mjs +47 -0
  769. package/dist-esm/lib/ui/assetUrls.mjs.map +7 -0
  770. package/dist-esm/lib/ui/components/ActionsMenu.mjs +66 -0
  771. package/dist-esm/lib/ui/components/ActionsMenu.mjs.map +7 -0
  772. package/dist-esm/lib/ui/components/BackToContent.mjs +47 -0
  773. package/dist-esm/lib/ui/components/BackToContent.mjs.map +7 -0
  774. package/dist-esm/lib/ui/components/ContextMenu.mjs +184 -0
  775. package/dist-esm/lib/ui/components/ContextMenu.mjs.map +7 -0
  776. package/dist-esm/lib/ui/components/DebugPanel.mjs +315 -0
  777. package/dist-esm/lib/ui/components/DebugPanel.mjs.map +7 -0
  778. package/dist-esm/lib/ui/components/Dialogs.mjs +34 -0
  779. package/dist-esm/lib/ui/components/Dialogs.mjs.map +7 -0
  780. package/dist-esm/lib/ui/components/DuplicateButton.mjs +27 -0
  781. package/dist-esm/lib/ui/components/DuplicateButton.mjs.map +7 -0
  782. package/dist-esm/lib/ui/components/EditLinkDialog.mjs +131 -0
  783. package/dist-esm/lib/ui/components/EditLinkDialog.mjs.map +7 -0
  784. package/dist-esm/lib/ui/components/EmbedDialog.mjs +122 -0
  785. package/dist-esm/lib/ui/components/EmbedDialog.mjs.map +7 -0
  786. package/dist-esm/lib/ui/components/FollowingIndicator.mjs +21 -0
  787. package/dist-esm/lib/ui/components/FollowingIndicator.mjs.map +7 -0
  788. package/dist-esm/lib/ui/components/HTMLCanvas.mjs +36 -0
  789. package/dist-esm/lib/ui/components/HTMLCanvas.mjs.map +7 -0
  790. package/dist-esm/lib/ui/components/HelpMenu.mjs +86 -0
  791. package/dist-esm/lib/ui/components/HelpMenu.mjs.map +7 -0
  792. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog.mjs +44 -0
  793. package/dist-esm/lib/ui/components/KeyboardShortcutsDialog.mjs.map +7 -0
  794. package/dist-esm/lib/ui/components/LanguageMenu.mjs +30 -0
  795. package/dist-esm/lib/ui/components/LanguageMenu.mjs.map +7 -0
  796. package/dist-esm/lib/ui/components/Menu.mjs +109 -0
  797. package/dist-esm/lib/ui/components/Menu.mjs.map +7 -0
  798. package/dist-esm/lib/ui/components/MenuZone.mjs +31 -0
  799. package/dist-esm/lib/ui/components/MenuZone.mjs.map +7 -0
  800. package/dist-esm/lib/ui/components/MobileStylePanel.mjs +54 -0
  801. package/dist-esm/lib/ui/components/MobileStylePanel.mjs.map +7 -0
  802. package/dist-esm/lib/ui/components/MoveToPageMenu.mjs +112 -0
  803. package/dist-esm/lib/ui/components/MoveToPageMenu.mjs.map +7 -0
  804. package/dist-esm/lib/ui/components/NavigationZone/Minimap.mjs +191 -0
  805. package/dist-esm/lib/ui/components/NavigationZone/Minimap.mjs.map +7 -0
  806. package/dist-esm/lib/ui/components/NavigationZone/MinimapManager.mjs +279 -0
  807. package/dist-esm/lib/ui/components/NavigationZone/MinimapManager.mjs.map +7 -0
  808. package/dist-esm/lib/ui/components/NavigationZone/NavigationZone.mjs +83 -0
  809. package/dist-esm/lib/ui/components/NavigationZone/NavigationZone.mjs.map +7 -0
  810. package/dist-esm/lib/ui/components/NavigationZone/ZoomMenu.mjs +88 -0
  811. package/dist-esm/lib/ui/components/NavigationZone/ZoomMenu.mjs.map +7 -0
  812. package/dist-esm/lib/ui/components/OfflineIndicator/OfflineIndicator.mjs +17 -0
  813. package/dist-esm/lib/ui/components/OfflineIndicator/OfflineIndicator.mjs.map +7 -0
  814. package/dist-esm/lib/ui/components/PageMenu/PageItemInput.mjs +43 -0
  815. package/dist-esm/lib/ui/components/PageMenu/PageItemInput.mjs.map +7 -0
  816. package/dist-esm/lib/ui/components/PageMenu/PageItemSubmenu.mjs +58 -0
  817. package/dist-esm/lib/ui/components/PageMenu/PageItemSubmenu.mjs.map +7 -0
  818. package/dist-esm/lib/ui/components/PageMenu/PageMenu.mjs +381 -0
  819. package/dist-esm/lib/ui/components/PageMenu/PageMenu.mjs.map +7 -0
  820. package/dist-esm/lib/ui/components/PageMenu/edit-pages-shared.mjs +29 -0
  821. package/dist-esm/lib/ui/components/PageMenu/edit-pages-shared.mjs.map +7 -0
  822. package/dist-esm/lib/ui/components/PenModeToggle.mjs +25 -0
  823. package/dist-esm/lib/ui/components/PenModeToggle.mjs.map +7 -0
  824. package/dist-esm/lib/ui/components/RedoButton.mjs +29 -0
  825. package/dist-esm/lib/ui/components/RedoButton.mjs.map +7 -0
  826. package/dist-esm/lib/ui/components/Spinner.mjs +21 -0
  827. package/dist-esm/lib/ui/components/Spinner.mjs.map +7 -0
  828. package/dist-esm/lib/ui/components/StopFollowing.mjs +25 -0
  829. package/dist-esm/lib/ui/components/StopFollowing.mjs.map +7 -0
  830. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs +108 -0
  831. package/dist-esm/lib/ui/components/StylePanel/DoubleDropdownPicker.mjs.map +7 -0
  832. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs +59 -0
  833. package/dist-esm/lib/ui/components/StylePanel/DropdownPicker.mjs.map +7 -0
  834. package/dist-esm/lib/ui/components/StylePanel/StylePanel.mjs +297 -0
  835. package/dist-esm/lib/ui/components/StylePanel/StylePanel.mjs.map +7 -0
  836. package/dist-esm/lib/ui/components/StylePanel/styles.mjs +99 -0
  837. package/dist-esm/lib/ui/components/StylePanel/styles.mjs.map +7 -0
  838. package/dist-esm/lib/ui/components/Toasts.mjs +71 -0
  839. package/dist-esm/lib/ui/components/Toasts.mjs.map +7 -0
  840. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs +43 -0
  841. package/dist-esm/lib/ui/components/Toolbar/ToggleToolLockedButton.mjs.map +7 -0
  842. package/dist-esm/lib/ui/components/Toolbar/Toolbar.mjs +217 -0
  843. package/dist-esm/lib/ui/components/Toolbar/Toolbar.mjs.map +7 -0
  844. package/dist-esm/lib/ui/components/TrashButton.mjs +31 -0
  845. package/dist-esm/lib/ui/components/TrashButton.mjs.map +7 -0
  846. package/dist-esm/lib/ui/components/UndoButton.mjs +29 -0
  847. package/dist-esm/lib/ui/components/UndoButton.mjs.map +7 -0
  848. package/dist-esm/lib/ui/components/primitives/Button.mjs +49 -0
  849. package/dist-esm/lib/ui/components/primitives/Button.mjs.map +7 -0
  850. package/dist-esm/lib/ui/components/primitives/ButtonPicker.mjs +96 -0
  851. package/dist-esm/lib/ui/components/primitives/ButtonPicker.mjs.map +7 -0
  852. package/dist-esm/lib/ui/components/primitives/Dialog.mjs +40 -0
  853. package/dist-esm/lib/ui/components/primitives/Dialog.mjs.map +7 -0
  854. package/dist-esm/lib/ui/components/primitives/DropdownMenu.mjs +157 -0
  855. package/dist-esm/lib/ui/components/primitives/DropdownMenu.mjs.map +7 -0
  856. package/dist-esm/lib/ui/components/primitives/Icon.mjs +41 -0
  857. package/dist-esm/lib/ui/components/primitives/Icon.mjs.map +7 -0
  858. package/dist-esm/lib/ui/components/primitives/Input.mjs +125 -0
  859. package/dist-esm/lib/ui/components/primitives/Input.mjs.map +7 -0
  860. package/dist-esm/lib/ui/components/primitives/Kbd.mjs +9 -0
  861. package/dist-esm/lib/ui/components/primitives/Kbd.mjs.map +7 -0
  862. package/dist-esm/lib/ui/components/primitives/Popover.mjs +39 -0
  863. package/dist-esm/lib/ui/components/primitives/Popover.mjs.map +7 -0
  864. package/dist-esm/lib/ui/components/primitives/Slider.mjs +49 -0
  865. package/dist-esm/lib/ui/components/primitives/Slider.mjs.map +7 -0
  866. package/dist-esm/lib/ui/components/primitives/shared.mjs +24 -0
  867. package/dist-esm/lib/ui/components/primitives/shared.mjs.map +7 -0
  868. package/dist-esm/lib/ui/constants.mjs +5 -0
  869. package/dist-esm/lib/ui/constants.mjs.map +7 -0
  870. package/dist-esm/lib/ui/hooks/clipboard/pasteExcalidrawContent.mjs +444 -0
  871. package/dist-esm/lib/ui/hooks/clipboard/pasteExcalidrawContent.mjs.map +7 -0
  872. package/dist-esm/lib/ui/hooks/clipboard/pasteFiles.mjs +17 -0
  873. package/dist-esm/lib/ui/hooks/clipboard/pasteFiles.mjs.map +7 -0
  874. package/dist-esm/lib/ui/hooks/clipboard/pasteTldrawContent.mjs +12 -0
  875. package/dist-esm/lib/ui/hooks/clipboard/pasteTldrawContent.mjs.map +7 -0
  876. package/dist-esm/lib/ui/hooks/clipboard/pasteUrl.mjs +28 -0
  877. package/dist-esm/lib/ui/hooks/clipboard/pasteUrl.mjs.map +7 -0
  878. package/dist-esm/lib/ui/hooks/menuHelpers.mjs +157 -0
  879. package/dist-esm/lib/ui/hooks/menuHelpers.mjs.map +7 -0
  880. package/dist-esm/lib/ui/hooks/useActions.mjs +1132 -0
  881. package/dist-esm/lib/ui/hooks/useActions.mjs.map +7 -0
  882. package/dist-esm/lib/ui/hooks/useActionsMenuSchema.mjs +87 -0
  883. package/dist-esm/lib/ui/hooks/useActionsMenuSchema.mjs.map +7 -0
  884. package/dist-esm/lib/ui/hooks/useAssetUrls.mjs +21 -0
  885. package/dist-esm/lib/ui/hooks/useAssetUrls.mjs.map +7 -0
  886. package/dist-esm/lib/ui/hooks/useBreakpoint.mjs +34 -0
  887. package/dist-esm/lib/ui/hooks/useBreakpoint.mjs.map +7 -0
  888. package/dist-esm/lib/ui/hooks/useCanRedo.mjs +9 -0
  889. package/dist-esm/lib/ui/hooks/useCanRedo.mjs.map +7 -0
  890. package/dist-esm/lib/ui/hooks/useCanUndo.mjs +9 -0
  891. package/dist-esm/lib/ui/hooks/useCanUndo.mjs.map +7 -0
  892. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs +448 -0
  893. package/dist-esm/lib/ui/hooks/useClipboardEvents.mjs.map +7 -0
  894. package/dist-esm/lib/ui/hooks/useContextMenuSchema.mjs +208 -0
  895. package/dist-esm/lib/ui/hooks/useContextMenuSchema.mjs.map +7 -0
  896. package/dist-esm/lib/ui/hooks/useCopyAs.mjs +27 -0
  897. package/dist-esm/lib/ui/hooks/useCopyAs.mjs.map +7 -0
  898. package/dist-esm/lib/ui/hooks/useDialogsProvider.mjs +88 -0
  899. package/dist-esm/lib/ui/hooks/useDialogsProvider.mjs.map +7 -0
  900. package/dist-esm/lib/ui/hooks/useEditorEvents.mjs +23 -0
  901. package/dist-esm/lib/ui/hooks/useEditorEvents.mjs.map +7 -0
  902. package/dist-esm/lib/ui/hooks/useEventsProvider.mjs +17 -0
  903. package/dist-esm/lib/ui/hooks/useEventsProvider.mjs.map +7 -0
  904. package/dist-esm/lib/ui/hooks/useExportAs.mjs +31 -0
  905. package/dist-esm/lib/ui/hooks/useExportAs.mjs.map +7 -0
  906. package/dist-esm/lib/ui/hooks/useHasLinkShapeSelected.mjs +16 -0
  907. package/dist-esm/lib/ui/hooks/useHasLinkShapeSelected.mjs.map +7 -0
  908. package/dist-esm/lib/ui/hooks/useHelpMenuSchema.mjs +73 -0
  909. package/dist-esm/lib/ui/hooks/useHelpMenuSchema.mjs.map +7 -0
  910. package/dist-esm/lib/ui/hooks/useHighDpiCanvas.mjs +15 -0
  911. package/dist-esm/lib/ui/hooks/useHighDpiCanvas.mjs.map +7 -0
  912. package/dist-esm/lib/ui/hooks/useInsertMedia.mjs +37 -0
  913. package/dist-esm/lib/ui/hooks/useInsertMedia.mjs.map +7 -0
  914. package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs +108 -0
  915. package/dist-esm/lib/ui/hooks/useKeyboardShortcuts.mjs.map +7 -0
  916. package/dist-esm/lib/ui/hooks/useKeyboardShortcutsSchema.mjs +104 -0
  917. package/dist-esm/lib/ui/hooks/useKeyboardShortcutsSchema.mjs.map +7 -0
  918. package/dist-esm/lib/ui/hooks/useLocalStorageState.mjs +29 -0
  919. package/dist-esm/lib/ui/hooks/useLocalStorageState.mjs.map +7 -0
  920. package/dist-esm/lib/ui/hooks/useMenuIsOpen.mjs +54 -0
  921. package/dist-esm/lib/ui/hooks/useMenuIsOpen.mjs.map +7 -0
  922. package/dist-esm/lib/ui/hooks/useMenuSchema.mjs +239 -0
  923. package/dist-esm/lib/ui/hooks/useMenuSchema.mjs.map +7 -0
  924. package/dist-esm/lib/ui/hooks/useOnlyFlippableShape.mjs +21 -0
  925. package/dist-esm/lib/ui/hooks/useOnlyFlippableShape.mjs.map +7 -0
  926. package/dist-esm/lib/ui/hooks/usePreloadAssets.mjs +86 -0
  927. package/dist-esm/lib/ui/hooks/usePreloadAssets.mjs.map +7 -0
  928. package/dist-esm/lib/ui/hooks/usePreloadIcons.mjs +31 -0
  929. package/dist-esm/lib/ui/hooks/usePreloadIcons.mjs.map +7 -0
  930. package/dist-esm/lib/ui/hooks/usePrint.mjs +200 -0
  931. package/dist-esm/lib/ui/hooks/usePrint.mjs.map +7 -0
  932. package/dist-esm/lib/ui/hooks/useReadonly.mjs +9 -0
  933. package/dist-esm/lib/ui/hooks/useReadonly.mjs.map +7 -0
  934. package/dist-esm/lib/ui/hooks/useRevelantStyles.mjs +33 -0
  935. package/dist-esm/lib/ui/hooks/useRevelantStyles.mjs.map +7 -0
  936. package/dist-esm/lib/ui/hooks/useShowAutoSizeToggle.mjs +16 -0
  937. package/dist-esm/lib/ui/hooks/useShowAutoSizeToggle.mjs.map +7 -0
  938. package/dist-esm/lib/ui/hooks/useToastsProvider.mjs +33 -0
  939. package/dist-esm/lib/ui/hooks/useToastsProvider.mjs.map +7 -0
  940. package/dist-esm/lib/ui/hooks/useToolbarSchema.mjs +69 -0
  941. package/dist-esm/lib/ui/hooks/useToolbarSchema.mjs.map +7 -0
  942. package/dist-esm/lib/ui/hooks/useTools.mjs +205 -0
  943. package/dist-esm/lib/ui/hooks/useTools.mjs.map +7 -0
  944. package/dist-esm/lib/ui/hooks/useTranslation/TLUiTranslationKey.mjs +1 -0
  945. package/dist-esm/lib/ui/hooks/useTranslation/TLUiTranslationKey.mjs.map +7 -0
  946. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs +357 -0
  947. package/dist-esm/lib/ui/hooks/useTranslation/defaultTranslation.mjs.map +7 -0
  948. package/dist-esm/lib/ui/hooks/useTranslation/translations.mjs +47 -0
  949. package/dist-esm/lib/ui/hooks/useTranslation/translations.mjs.map +7 -0
  950. package/dist-esm/lib/ui/hooks/useTranslation/useLanguages.mjs +12 -0
  951. package/dist-esm/lib/ui/hooks/useTranslation/useLanguages.mjs.map +7 -0
  952. package/dist-esm/lib/ui/hooks/useTranslation/useTranslation.mjs +71 -0
  953. package/dist-esm/lib/ui/hooks/useTranslation/useTranslation.mjs.map +7 -0
  954. package/dist-esm/lib/ui/icon-types.mjs +170 -0
  955. package/dist-esm/lib/ui/icon-types.mjs.map +7 -0
  956. package/dist-esm/lib/ui/overrides.mjs +158 -0
  957. package/dist-esm/lib/ui/overrides.mjs.map +7 -0
  958. package/dist-esm/lib/ui/version.mjs +5 -0
  959. package/dist-esm/lib/ui/version.mjs.map +7 -0
  960. package/dist-esm/lib/utils/assets/assets.mjs +61 -0
  961. package/dist-esm/lib/utils/assets/assets.mjs.map +7 -0
  962. package/dist-esm/lib/utils/assets/is-gif-animated.mjs +54 -0
  963. package/dist-esm/lib/utils/assets/is-gif-animated.mjs.map +7 -0
  964. package/dist-esm/lib/utils/assets.mjs +61 -0
  965. package/dist-esm/lib/utils/assets.mjs.map +7 -0
  966. package/dist-esm/lib/utils/embeds/embeds.mjs +65 -0
  967. package/dist-esm/lib/utils/embeds/embeds.mjs.map +7 -0
  968. package/dist-esm/lib/utils/export/copyAs.mjs +96 -0
  969. package/dist-esm/lib/utils/export/copyAs.mjs.map +7 -0
  970. package/dist-esm/lib/utils/export/export.mjs +97 -0
  971. package/dist-esm/lib/utils/export/export.mjs.map +7 -0
  972. package/dist-esm/lib/utils/export/exportAs.mjs +68 -0
  973. package/dist-esm/lib/utils/export/exportAs.mjs.map +7 -0
  974. package/dist-esm/lib/utils/frames/frames.mjs +76 -0
  975. package/dist-esm/lib/utils/frames/frames.mjs.map +7 -0
  976. package/dist-esm/lib/utils/static-assets/assetUrls.mjs +28 -0
  977. package/dist-esm/lib/utils/static-assets/assetUrls.mjs.map +7 -0
  978. package/dist-esm/lib/utils/text/text.mjs +37 -0
  979. package/dist-esm/lib/utils/text/text.mjs.map +7 -0
  980. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs +779 -0
  981. package/dist-esm/lib/utils/tldr/buildFromV1Document.mjs.map +7 -0
  982. package/dist-esm/lib/utils/tldr/file.mjs +219 -0
  983. package/dist-esm/lib/utils/tldr/file.mjs.map +7 -0
  984. package/package.json +105 -0
  985. package/src/index.ts +174 -0
  986. package/src/lib/Tldraw.test.tsx +78 -0
  987. package/src/lib/Tldraw.tsx +179 -0
  988. package/src/lib/canvas/TldrawCropHandles.tsx +126 -0
  989. package/src/lib/canvas/TldrawHandles.tsx +15 -0
  990. package/src/lib/canvas/TldrawHoveredShapeIndicator.tsx +30 -0
  991. package/src/lib/canvas/TldrawScribble.tsx +45 -0
  992. package/src/lib/canvas/TldrawSelectionBackground.tsx +29 -0
  993. package/src/lib/canvas/TldrawSelectionForeground.tsx +526 -0
  994. package/src/lib/defaultExternalContentHandlers.ts +533 -0
  995. package/src/lib/defaultShapeTools.ts +20 -0
  996. package/src/lib/defaultShapeUtils.ts +29 -0
  997. package/src/lib/defaultSideEffects.ts +48 -0
  998. package/src/lib/defaultTools.ts +8 -0
  999. package/src/lib/shapes/arrow/ArrowShapeTool.test.ts +558 -0
  1000. package/src/lib/shapes/arrow/ArrowShapeTool.ts +12 -0
  1001. package/src/lib/shapes/arrow/ArrowShapeUtil.test.ts +595 -0
  1002. package/src/lib/shapes/arrow/ArrowShapeUtil.tsx +1036 -0
  1003. package/src/lib/shapes/arrow/components/ArrowTextLabel.tsx +87 -0
  1004. package/src/lib/shapes/arrow/toolStates/Idle.ts +37 -0
  1005. package/src/lib/shapes/arrow/toolStates/Pointing.ts +190 -0
  1006. package/src/lib/shapes/bookmark/BookmarkShapeUtil.tsx +196 -0
  1007. package/src/lib/shapes/draw/DrawShapeTool.test.ts +52 -0
  1008. package/src/lib/shapes/draw/DrawShapeTool.ts +17 -0
  1009. package/src/lib/shapes/draw/DrawShapeUtil.tsx +298 -0
  1010. package/src/lib/shapes/draw/getPath.ts +108 -0
  1011. package/src/lib/shapes/draw/toolStates/Drawing.ts +722 -0
  1012. package/src/lib/shapes/draw/toolStates/Idle.ts +17 -0
  1013. package/src/lib/shapes/embed/EmbedShapeUtil.tsx +218 -0
  1014. package/src/lib/shapes/frame/FrameShapeTool.test.ts +169 -0
  1015. package/src/lib/shapes/frame/FrameShapeTool.ts +53 -0
  1016. package/src/lib/shapes/frame/FrameShapeUtil.tsx +258 -0
  1017. package/src/lib/shapes/frame/components/FrameHeading.tsx +115 -0
  1018. package/src/lib/shapes/frame/components/FrameLabelInput.tsx +85 -0
  1019. package/src/lib/shapes/geo/GeoShapeTool.test.ts +191 -0
  1020. package/src/lib/shapes/geo/GeoShapeTool.ts +11 -0
  1021. package/src/lib/shapes/geo/GeoShapeUtil.tsx +1153 -0
  1022. package/src/lib/shapes/geo/cloudOutline.ts +391 -0
  1023. package/src/lib/shapes/geo/components/DashStyleCloud.tsx +135 -0
  1024. package/src/lib/shapes/geo/components/DashStyleEllipse.tsx +117 -0
  1025. package/src/lib/shapes/geo/components/DashStyleOval.tsx +102 -0
  1026. package/src/lib/shapes/geo/components/DashStylePolygon.tsx +152 -0
  1027. package/src/lib/shapes/geo/components/DrawStyleCloud.tsx +65 -0
  1028. package/src/lib/shapes/geo/components/DrawStyleEllipse.tsx +145 -0
  1029. package/src/lib/shapes/geo/components/DrawStylePolygon.tsx +263 -0
  1030. package/src/lib/shapes/geo/components/SolidStyleCloud.tsx +65 -0
  1031. package/src/lib/shapes/geo/components/SolidStyleEllipse.tsx +68 -0
  1032. package/src/lib/shapes/geo/components/SolidStyleOval.tsx +83 -0
  1033. package/src/lib/shapes/geo/components/SolidStylePolygon.tsx +77 -0
  1034. package/src/lib/shapes/geo/helpers.ts +34 -0
  1035. package/src/lib/shapes/geo/toolStates/Idle.ts +38 -0
  1036. package/src/lib/shapes/geo/toolStates/Pointing.ts +131 -0
  1037. package/src/lib/shapes/highlight/HighlightShapeTool.test.ts +3 -0
  1038. package/src/lib/shapes/highlight/HighlightShapeTool.ts +17 -0
  1039. package/src/lib/shapes/highlight/HighlightShapeUtil.tsx +255 -0
  1040. package/src/lib/shapes/image/ImageShapeUtil.tsx +313 -0
  1041. package/src/lib/shapes/line/LineShapeTool.test.ts +228 -0
  1042. package/src/lib/shapes/line/LineShapeTool.ts +12 -0
  1043. package/src/lib/shapes/line/LineShapeUtil.test.ts +222 -0
  1044. package/src/lib/shapes/line/LineShapeUtil.tsx +421 -0
  1045. package/src/lib/shapes/line/__snapshots__/LineShapeUtil.test.ts.snap +41 -0
  1046. package/src/lib/shapes/line/components/getLinePath.ts +91 -0
  1047. package/src/lib/shapes/line/components/svg.ts +62 -0
  1048. package/src/lib/shapes/line/toolStates/Idle.ts +20 -0
  1049. package/src/lib/shapes/line/toolStates/Pointing.ts +165 -0
  1050. package/src/lib/shapes/note/NoteShapeTool.test.ts +146 -0
  1051. package/src/lib/shapes/note/NoteShapeTool.ts +11 -0
  1052. package/src/lib/shapes/note/NoteShapeUtil.tsx +221 -0
  1053. package/src/lib/shapes/note/toolStates/Idle.ts +17 -0
  1054. package/src/lib/shapes/note/toolStates/Pointing.ts +121 -0
  1055. package/src/lib/shapes/shared/HyperlinkButton.tsx +30 -0
  1056. package/src/lib/shapes/shared/ShapeFill.tsx +113 -0
  1057. package/src/lib/shapes/shared/TextHelpers.ts +289 -0
  1058. package/src/lib/shapes/shared/TextLabel.tsx +131 -0
  1059. package/src/lib/shapes/shared/createTextSvgElementFromSpans.ts +101 -0
  1060. package/src/lib/shapes/shared/default-shape-constants.ts +57 -0
  1061. package/src/lib/shapes/shared/defaultStyleDefs.tsx +276 -0
  1062. package/src/lib/shapes/shared/freehand/getStroke.ts +23 -0
  1063. package/src/lib/shapes/shared/freehand/getStrokeOutlinePoints.ts +333 -0
  1064. package/src/lib/shapes/shared/freehand/getStrokePoints.ts +187 -0
  1065. package/src/lib/shapes/shared/freehand/getStrokeRadius.ts +13 -0
  1066. package/src/lib/shapes/shared/freehand/setStrokePointRadii.ts +127 -0
  1067. package/src/lib/shapes/shared/freehand/svg.ts +50 -0
  1068. package/src/lib/shapes/shared/freehand/svgInk.ts +195 -0
  1069. package/src/lib/shapes/shared/freehand/types.ts +49 -0
  1070. package/src/lib/shapes/shared/getBrowserCanvasMaxSize.tsx +28 -0
  1071. package/src/lib/shapes/shared/getPerfectDashProps.ts +96 -0
  1072. package/src/lib/shapes/shared/getTextLabelSvgElement.ts +42 -0
  1073. package/src/lib/shapes/shared/legacyProps.ts +25 -0
  1074. package/src/lib/shapes/shared/polygon-helpers.ts +131 -0
  1075. package/src/lib/shapes/shared/resizeBox.ts +130 -0
  1076. package/src/lib/shapes/shared/resizeScaled.ts +40 -0
  1077. package/src/lib/shapes/shared/rotated-box-shadow.ts +29 -0
  1078. package/src/lib/shapes/shared/useColorSpace.tsx +21 -0
  1079. package/src/lib/shapes/shared/useEditableText.ts +211 -0
  1080. package/src/lib/shapes/shared/useForceSolid.ts +6 -0
  1081. package/src/lib/shapes/shared/usePrefersReducedMotion.tsx +18 -0
  1082. package/src/lib/shapes/text/TextShapeTool.test.ts +157 -0
  1083. package/src/lib/shapes/text/TextShapeTool.ts +11 -0
  1084. package/src/lib/shapes/text/TextShapeUtil.tsx +401 -0
  1085. package/src/lib/shapes/text/toolStates/Idle.ts +47 -0
  1086. package/src/lib/shapes/text/toolStates/Pointing.ts +105 -0
  1087. package/src/lib/shapes/video/VideoShapeUtil.tsx +215 -0
  1088. package/src/lib/tools/EraserTool/EraserTool.ts +15 -0
  1089. package/src/lib/tools/EraserTool/childStates/Erasing.ts +131 -0
  1090. package/src/lib/tools/EraserTool/childStates/Idle.ts +13 -0
  1091. package/src/lib/tools/EraserTool/childStates/Pointing.ts +93 -0
  1092. package/src/lib/tools/HandTool/HandTool.ts +40 -0
  1093. package/src/lib/tools/HandTool/childStates/Dragging.ts +45 -0
  1094. package/src/lib/tools/HandTool/childStates/Idle.ts +17 -0
  1095. package/src/lib/tools/HandTool/childStates/Pointing.ts +39 -0
  1096. package/src/lib/tools/LaserTool/LaserTool.ts +14 -0
  1097. package/src/lib/tools/LaserTool/childStates/Idle.ts +9 -0
  1098. package/src/lib/tools/LaserTool/childStates/Lasering.ts +53 -0
  1099. package/src/lib/tools/SelectTool/DragAndDropManager.ts +112 -0
  1100. package/src/lib/tools/SelectTool/SelectTool.ts +49 -0
  1101. package/src/lib/tools/SelectTool/childStates/Brushing.ts +206 -0
  1102. package/src/lib/tools/SelectTool/childStates/Crop/Crop.ts +10 -0
  1103. package/src/lib/tools/SelectTool/childStates/Crop/children/Idle.ts +217 -0
  1104. package/src/lib/tools/SelectTool/childStates/Crop/children/PointingCrop.ts +19 -0
  1105. package/src/lib/tools/SelectTool/childStates/Crop/children/TranslatingCrop.ts +108 -0
  1106. package/src/lib/tools/SelectTool/childStates/Crop/children/crop_helpers.ts +64 -0
  1107. package/src/lib/tools/SelectTool/childStates/Crop/crop-constants.ts +2 -0
  1108. package/src/lib/tools/SelectTool/childStates/Cropping.ts +249 -0
  1109. package/src/lib/tools/SelectTool/childStates/DraggingHandle.ts +308 -0
  1110. package/src/lib/tools/SelectTool/childStates/EditingShape.ts +130 -0
  1111. package/src/lib/tools/SelectTool/childStates/Idle.ts +575 -0
  1112. package/src/lib/tools/SelectTool/childStates/PointingCanvas.ts +41 -0
  1113. package/src/lib/tools/SelectTool/childStates/PointingCropHandle.ts +83 -0
  1114. package/src/lib/tools/SelectTool/childStates/PointingHandle.ts +56 -0
  1115. package/src/lib/tools/SelectTool/childStates/PointingResizeHandle.ts +90 -0
  1116. package/src/lib/tools/SelectTool/childStates/PointingRotateHandle.ts +76 -0
  1117. package/src/lib/tools/SelectTool/childStates/PointingSelection.ts +71 -0
  1118. package/src/lib/tools/SelectTool/childStates/PointingShape.ts +218 -0
  1119. package/src/lib/tools/SelectTool/childStates/Resizing.ts +511 -0
  1120. package/src/lib/tools/SelectTool/childStates/Rotating.ts +175 -0
  1121. package/src/lib/tools/SelectTool/childStates/ScribbleBrushing.ts +167 -0
  1122. package/src/lib/tools/SelectTool/childStates/Translating.ts +418 -0
  1123. package/src/lib/tools/SelectTool/children/DraggingHandle.ts +308 -0
  1124. package/src/lib/tools/ZoomTool/ZoomTool.ts +72 -0
  1125. package/src/lib/tools/ZoomTool/childStates/Idle.ts +15 -0
  1126. package/src/lib/tools/ZoomTool/childStates/Pointing.ts +39 -0
  1127. package/src/lib/tools/ZoomTool/childStates/ZoomBrushing.ts +62 -0
  1128. package/src/lib/tools/selection-logic/getHitShapeOnCanvasPointerDown.ts +20 -0
  1129. package/src/lib/tools/selection-logic/getShouldEnterCropModeOnPointerDown.ts +10 -0
  1130. package/src/lib/tools/selection-logic/selectOnCanvasPointerUp.ts +94 -0
  1131. package/src/lib/tools/selection-logic/selection.tldr +1041 -0
  1132. package/src/lib/tools/selection-logic/updateHoveredId.ts +32 -0
  1133. package/src/lib/ui/TldrawUi.tsx +195 -0
  1134. package/src/lib/ui/TldrawUiContextProvider.tsx +99 -0
  1135. package/src/lib/ui/assetUrls.ts +57 -0
  1136. package/src/lib/ui/components/ActionsMenu.tsx +75 -0
  1137. package/src/lib/ui/components/BackToContent.tsx +55 -0
  1138. package/src/lib/ui/components/ContextMenu.tsx +234 -0
  1139. package/src/lib/ui/components/DebugPanel.tsx +355 -0
  1140. package/src/lib/ui/components/Dialogs.tsx +52 -0
  1141. package/src/lib/ui/components/DuplicateButton.tsx +23 -0
  1142. package/src/lib/ui/components/EditLinkDialog.tsx +180 -0
  1143. package/src/lib/ui/components/EmbedDialog.tsx +143 -0
  1144. package/src/lib/ui/components/FollowingIndicator.tsx +16 -0
  1145. package/src/lib/ui/components/HTMLCanvas.tsx +54 -0
  1146. package/src/lib/ui/components/HelpMenu.tsx +109 -0
  1147. package/src/lib/ui/components/KeyboardShortcutsDialog.tsx +62 -0
  1148. package/src/lib/ui/components/LanguageMenu.tsx +38 -0
  1149. package/src/lib/ui/components/Menu.tsx +129 -0
  1150. package/src/lib/ui/components/MenuZone.tsx +35 -0
  1151. package/src/lib/ui/components/MobileStylePanel.tsx +61 -0
  1152. package/src/lib/ui/components/MoveToPageMenu.tsx +104 -0
  1153. package/src/lib/ui/components/NavigationZone/Minimap.tsx +245 -0
  1154. package/src/lib/ui/components/NavigationZone/MinimapManager.ts +382 -0
  1155. package/src/lib/ui/components/NavigationZone/NavigationZone.tsx +81 -0
  1156. package/src/lib/ui/components/NavigationZone/ZoomMenu.tsx +87 -0
  1157. package/src/lib/ui/components/OfflineIndicator/OfflineIndicator.tsx +17 -0
  1158. package/src/lib/ui/components/PageMenu/PageItemInput.tsx +46 -0
  1159. package/src/lib/ui/components/PageMenu/PageItemSubmenu.tsx +86 -0
  1160. package/src/lib/ui/components/PageMenu/PageMenu.tsx +415 -0
  1161. package/src/lib/ui/components/PageMenu/edit-pages-shared.ts +32 -0
  1162. package/src/lib/ui/components/PenModeToggle.tsx +24 -0
  1163. package/src/lib/ui/components/RedoButton.tsx +26 -0
  1164. package/src/lib/ui/components/Spinner.tsx +22 -0
  1165. package/src/lib/ui/components/StopFollowing.tsx +23 -0
  1166. package/src/lib/ui/components/StylePanel/DoubleDropdownPicker.tsx +150 -0
  1167. package/src/lib/ui/components/StylePanel/DropdownPicker.tsx +76 -0
  1168. package/src/lib/ui/components/StylePanel/StylePanel.tsx +332 -0
  1169. package/src/lib/ui/components/StylePanel/styles.tsx +100 -0
  1170. package/src/lib/ui/components/Toasts.tsx +104 -0
  1171. package/src/lib/ui/components/Toolbar/ToggleToolLockedButton.tsx +45 -0
  1172. package/src/lib/ui/components/Toolbar/Toolbar.tsx +281 -0
  1173. package/src/lib/ui/components/TrashButton.tsx +28 -0
  1174. package/src/lib/ui/components/UndoButton.tsx +26 -0
  1175. package/src/lib/ui/components/primitives/Button.tsx +69 -0
  1176. package/src/lib/ui/components/primitives/ButtonPicker.tsx +128 -0
  1177. package/src/lib/ui/components/primitives/Dialog.tsx +57 -0
  1178. package/src/lib/ui/components/primitives/DropdownMenu.tsx +229 -0
  1179. package/src/lib/ui/components/primitives/Icon.tsx +55 -0
  1180. package/src/lib/ui/components/primitives/Input.tsx +165 -0
  1181. package/src/lib/ui/components/primitives/Kbd.tsx +17 -0
  1182. package/src/lib/ui/components/primitives/Popover.tsx +61 -0
  1183. package/src/lib/ui/components/primitives/Slider.tsx +62 -0
  1184. package/src/lib/ui/components/primitives/shared.ts +40 -0
  1185. package/src/lib/ui/constants.ts +2 -0
  1186. package/src/lib/ui/hooks/clipboard/pasteExcalidrawContent.ts +514 -0
  1187. package/src/lib/ui/hooks/clipboard/pasteFiles.ts +31 -0
  1188. package/src/lib/ui/hooks/clipboard/pasteTldrawContent.ts +19 -0
  1189. package/src/lib/ui/hooks/clipboard/pasteUrl.ts +44 -0
  1190. package/src/lib/ui/hooks/menuHelpers.ts +247 -0
  1191. package/src/lib/ui/hooks/useActions.tsx +1180 -0
  1192. package/src/lib/ui/hooks/useActionsMenuSchema.tsx +123 -0
  1193. package/src/lib/ui/hooks/useAssetUrls.tsx +28 -0
  1194. package/src/lib/ui/hooks/useBreakpoint.tsx +42 -0
  1195. package/src/lib/ui/hooks/useCanRedo.ts +7 -0
  1196. package/src/lib/ui/hooks/useCanUndo.ts +7 -0
  1197. package/src/lib/ui/hooks/useClipboardEvents.ts +705 -0
  1198. package/src/lib/ui/hooks/useContextMenuSchema.tsx +260 -0
  1199. package/src/lib/ui/hooks/useCopyAs.ts +26 -0
  1200. package/src/lib/ui/hooks/useDialogsProvider.tsx +128 -0
  1201. package/src/lib/ui/hooks/useEditorEvents.ts +23 -0
  1202. package/src/lib/ui/hooks/useEventsProvider.tsx +129 -0
  1203. package/src/lib/ui/hooks/useExportAs.ts +30 -0
  1204. package/src/lib/ui/hooks/useHasLinkShapeSelected.ts +17 -0
  1205. package/src/lib/ui/hooks/useHelpMenuSchema.tsx +105 -0
  1206. package/src/lib/ui/hooks/useHighDpiCanvas.ts +14 -0
  1207. package/src/lib/ui/hooks/useInsertMedia.ts +35 -0
  1208. package/src/lib/ui/hooks/useKeyboardShortcuts.ts +121 -0
  1209. package/src/lib/ui/hooks/useKeyboardShortcutsSchema.tsx +127 -0
  1210. package/src/lib/ui/hooks/useLocalStorageState.ts +30 -0
  1211. package/src/lib/ui/hooks/useMenuIsOpen.ts +73 -0
  1212. package/src/lib/ui/hooks/useMenuSchema.tsx +280 -0
  1213. package/src/lib/ui/hooks/useOnlyFlippableShape.ts +29 -0
  1214. package/src/lib/ui/hooks/usePreloadAssets.ts +120 -0
  1215. package/src/lib/ui/hooks/usePreloadIcons.ts +38 -0
  1216. package/src/lib/ui/hooks/usePrint.ts +223 -0
  1217. package/src/lib/ui/hooks/useReadonly.ts +7 -0
  1218. package/src/lib/ui/hooks/useRevelantStyles.ts +38 -0
  1219. package/src/lib/ui/hooks/useShowAutoSizeToggle.ts +17 -0
  1220. package/src/lib/ui/hooks/useToastsProvider.tsx +75 -0
  1221. package/src/lib/ui/hooks/useToolbarSchema.tsx +99 -0
  1222. package/src/lib/ui/hooks/useTools.tsx +245 -0
  1223. package/src/lib/ui/hooks/useTranslation/TLUiTranslationKey.ts +356 -0
  1224. package/src/lib/ui/hooks/useTranslation/defaultTranslation.ts +367 -0
  1225. package/src/lib/ui/hooks/useTranslation/translations.ts +74 -0
  1226. package/src/lib/ui/hooks/useTranslation/useLanguages.tsx +10 -0
  1227. package/src/lib/ui/hooks/useTranslation/useTranslation.tsx +117 -0
  1228. package/src/lib/ui/icon-types.ts +337 -0
  1229. package/src/lib/ui/overrides.ts +211 -0
  1230. package/src/lib/ui/version.ts +1 -0
  1231. package/src/lib/ui.css +1603 -0
  1232. package/src/lib/utils/assets/assets.ts +103 -0
  1233. package/src/lib/utils/assets/is-gif-animated.ts +106 -0
  1234. package/src/lib/utils/assets.ts +103 -0
  1235. package/src/lib/utils/embeds/embeds.test.ts +612 -0
  1236. package/src/lib/utils/embeds/embeds.ts +99 -0
  1237. package/src/lib/utils/export/copyAs.ts +139 -0
  1238. package/src/lib/utils/export/export.ts +128 -0
  1239. package/src/lib/utils/export/exportAs.ts +94 -0
  1240. package/src/lib/utils/frames/frames.ts +101 -0
  1241. package/src/lib/utils/static-assets/assetUrls.ts +41 -0
  1242. package/src/lib/utils/text/text.test.ts +11 -0
  1243. package/src/lib/utils/text/text.ts +59 -0
  1244. package/src/lib/utils/tldr/buildFromV1Document.ts +1171 -0
  1245. package/src/lib/utils/tldr/file.ts +303 -0
  1246. package/src/test/ClickManager.test.ts +258 -0
  1247. package/src/test/Editor.test.tsx +647 -0
  1248. package/src/test/EraserTool.test.ts +446 -0
  1249. package/src/test/HandTool.test.ts +191 -0
  1250. package/src/test/HighlightShape.test.ts +24 -0
  1251. package/src/test/LaserTool.test.ts +3 -0
  1252. package/src/test/SelectTool.test.ts +445 -0
  1253. package/src/test/TLSessionStateSnapshot.test.ts +152 -0
  1254. package/src/test/TLUserPreferences.test.ts +123 -0
  1255. package/src/test/TestEditor.test.ts +7 -0
  1256. package/src/test/TestEditor.ts +661 -0
  1257. package/src/test/TldrawEditor.test.tsx +377 -0
  1258. package/src/test/ZoomTool.test.ts +210 -0
  1259. package/src/test/__snapshots__/groups.test.ts.snap +46 -0
  1260. package/src/test/__snapshots__/resizing.test.ts.snap +43 -0
  1261. package/src/test/arrowBindingsIndex.test.tsx +295 -0
  1262. package/src/test/arrows-megabus.test.ts +652 -0
  1263. package/src/test/assets.test.ts +38 -0
  1264. package/src/test/bookmark-shapes.test.ts +141 -0
  1265. package/src/test/cleanup.test.ts +127 -0
  1266. package/src/test/commands/__snapshots__/getSvg.test.ts.snap +174 -0
  1267. package/src/test/commands/__snapshots__/packShapes.test.ts.snap +185 -0
  1268. package/src/test/commands/__snapshots__/zoomToFit.test.ts.snap +12 -0
  1269. package/src/test/commands/alignShapes.test.tsx +388 -0
  1270. package/src/test/commands/allShapesCommonBounds.test.ts +91 -0
  1271. package/src/test/commands/animateShapes.test.ts +3 -0
  1272. package/src/test/commands/animateToShape.test.ts +3 -0
  1273. package/src/test/commands/animationSpeed.test.ts +38 -0
  1274. package/src/test/commands/blur.test.ts +3 -0
  1275. package/src/test/commands/cancel.test.ts +3 -0
  1276. package/src/test/commands/centerOnPoint.test.ts +21 -0
  1277. package/src/test/commands/clipboard.test.ts +481 -0
  1278. package/src/test/commands/complete.test.ts +3 -0
  1279. package/src/test/commands/createPage.test.ts +65 -0
  1280. package/src/test/commands/createShapes.test.ts +141 -0
  1281. package/src/test/commands/deletePage.test.ts +79 -0
  1282. package/src/test/commands/deleteShapes.test.ts +113 -0
  1283. package/src/test/commands/distributeShapes.test.ts +232 -0
  1284. package/src/test/commands/duplicatePage.test.ts +55 -0
  1285. package/src/test/commands/getContent.test.ts +9 -0
  1286. package/src/test/commands/getInitialMetaForShape.test.ts +21 -0
  1287. package/src/test/commands/getSvg.test.ts +110 -0
  1288. package/src/test/commands/groupShapes.test.ts +42 -0
  1289. package/src/test/commands/guide.md +12 -0
  1290. package/src/test/commands/interrupt.test.ts +3 -0
  1291. package/src/test/commands/lockShapes.test.ts +176 -0
  1292. package/src/test/commands/moveShapesToPage.test.ts +254 -0
  1293. package/src/test/commands/nudge.test.ts +292 -0
  1294. package/src/test/commands/packShapes.test.ts +62 -0
  1295. package/src/test/commands/pageToScreen.test.ts +25 -0
  1296. package/src/test/commands/pan.test.ts +32 -0
  1297. package/src/test/commands/penmode.test.ts +27 -0
  1298. package/src/test/commands/pinch.test.ts +11 -0
  1299. package/src/test/commands/putContent.test.ts +39 -0
  1300. package/src/test/commands/reorderShapes.test.ts +950 -0
  1301. package/src/test/commands/reparentShapesById.test.ts +162 -0
  1302. package/src/test/commands/resetZoom.test.ts +30 -0
  1303. package/src/test/commands/resizeShape.test.ts +58 -0
  1304. package/src/test/commands/rotateShapes.test.ts +82 -0
  1305. package/src/test/commands/screenToPage.test.ts +246 -0
  1306. package/src/test/commands/setAppState.test.ts +9 -0
  1307. package/src/test/commands/setBrush.test.ts +38 -0
  1308. package/src/test/commands/setCurrentPage.test.ts +88 -0
  1309. package/src/test/commands/setPageState.test.ts +9 -0
  1310. package/src/test/commands/setSelectedIds.test.ts +57 -0
  1311. package/src/test/commands/setSelectedTool.test.ts +23 -0
  1312. package/src/test/commands/setSettings.test.ts +9 -0
  1313. package/src/test/commands/setStyle.test.ts +11 -0
  1314. package/src/test/commands/squash.test.ts +13 -0
  1315. package/src/test/commands/stackShapes.test.ts +227 -0
  1316. package/src/test/commands/stretch.test.tsx +245 -0
  1317. package/src/test/commands/ungroup.test.ts +17 -0
  1318. package/src/test/commands/updateShapes.test.ts +192 -0
  1319. package/src/test/commands/updateViewportPageBounds.test.ts +123 -0
  1320. package/src/test/commands/zoomIn.test.ts +43 -0
  1321. package/src/test/commands/zoomOut.test.ts +31 -0
  1322. package/src/test/commands/zoomToBounds.test.ts +50 -0
  1323. package/src/test/commands/zoomToFit.test.ts +20 -0
  1324. package/src/test/commands/zoomToSelection.test.ts +42 -0
  1325. package/src/test/cropping.test.ts +1033 -0
  1326. package/src/test/drawing.test.ts +262 -0
  1327. package/src/test/duplicate.test.ts +217 -0
  1328. package/src/test/flipShapes.test.ts +581 -0
  1329. package/src/test/frames.test.ts +995 -0
  1330. package/src/test/getShapeAtPoint.test.ts +168 -0
  1331. package/src/test/getSnapLines.ts +25 -0
  1332. package/src/test/groups.test.ts +2005 -0
  1333. package/src/test/middleMouseButtonPanning.test.ts +31 -0
  1334. package/src/test/modifiers.test.ts +36 -0
  1335. package/src/test/panning.test.ts +25 -0
  1336. package/src/test/parentsToChildrenWithIndexes.test.ts +117 -0
  1337. package/src/test/paste.test.ts +494 -0
  1338. package/src/test/renderingShapes.test.tsx +223 -0
  1339. package/src/test/resizeBox.test.ts +106 -0
  1340. package/src/test/resizing.test.ts +3901 -0
  1341. package/src/test/rotating.test.ts +321 -0
  1342. package/src/test/roundedBox.ts +13 -0
  1343. package/src/test/select.test.tsx +172 -0
  1344. package/src/test/selection-omnibus.test.ts +1710 -0
  1345. package/src/test/shapeIdsInCurrentPage.test.ts +75 -0
  1346. package/src/test/shapeutils.test.ts +204 -0
  1347. package/src/test/spacebarPanning.test.ts +50 -0
  1348. package/src/test/styles2.test.tsx +199 -0
  1349. package/src/test/styles3.test.ts +70 -0
  1350. package/src/test/test-jsx.tsx +134 -0
  1351. package/src/test/testutils/getSnapLines.ts +25 -0
  1352. package/src/test/testutils/roundedBox.ts +13 -0
  1353. package/src/test/text.test.ts +269 -0
  1354. package/src/test/translating-snapping.test.ts +584 -0
  1355. package/src/test/translating.test.ts +1829 -0
  1356. package/src/test/viewport-following.test.ts +18 -0
  1357. package/tldraw.css +3264 -0
@@ -0,0 +1,3901 @@
1
+ import {
2
+ EPSILON,
3
+ GapsSnapLine,
4
+ PI,
5
+ PI2,
6
+ PointsSnapLine,
7
+ RotateCorner,
8
+ TLSelectionHandle,
9
+ TLShapeId,
10
+ TLShapePartial,
11
+ Vec2d,
12
+ canonicalizeRotation,
13
+ createShapeId,
14
+ rotateSelectionHandle,
15
+ } from '@bigbluebutton/editor'
16
+ import { TestEditor } from './TestEditor'
17
+ import { getSnapLines } from './getSnapLines'
18
+ import { roundedBox } from './roundedBox'
19
+
20
+ jest.useFakeTimers()
21
+
22
+ const ORDERED_ROTATE_CORNERS: TLSelectionHandle[] = [
23
+ 'top_left_rotate',
24
+ 'top_right_rotate',
25
+ 'bottom_right_rotate',
26
+ 'bottom_left_rotate',
27
+ ]
28
+
29
+ export function rotateRotateCorner(corner: RotateCorner, rotation: number): TLSelectionHandle {
30
+ // first find out how many 90deg we need to rotate by
31
+ rotation = rotation % PI2
32
+ const numSteps = Math.round(rotation / (PI / 2))
33
+
34
+ const currentIndex = ORDERED_ROTATE_CORNERS.indexOf(corner)
35
+ return ORDERED_ROTATE_CORNERS[(currentIndex + numSteps) % ORDERED_ROTATE_CORNERS.length]
36
+ }
37
+
38
+ const box = (id: TLShapeId, x: number, y: number, w = 10, h = 10): TLShapePartial => ({
39
+ type: 'geo',
40
+ id,
41
+ x,
42
+ y,
43
+ props: {
44
+ w,
45
+ h,
46
+ },
47
+ })
48
+
49
+ const roundedPageBounds = (shapeId: TLShapeId, accuracy = 0.01) => {
50
+ return roundedBox(editor.getShapePageBounds(shapeId)!, accuracy)
51
+ }
52
+
53
+ // function getGapAndPointLines(snaps: SnapLine[]) {
54
+ // const gapLines = snaps.filter((snap) => snap.type === 'gaps') as GapsSnapLine[]
55
+ // const pointLines = snaps.filter((snap) => snap.type === 'points') as PointsSnapLine[]
56
+ // return { gapLines, pointLines }
57
+ // }
58
+
59
+ let editor: TestEditor
60
+
61
+ afterEach(() => {
62
+ editor?.dispose()
63
+ })
64
+
65
+ const ids = {
66
+ boxA: createShapeId('boxA'),
67
+ boxB: createShapeId('boxB'),
68
+ boxC: createShapeId('boxC'),
69
+ boxD: createShapeId('boxD'),
70
+
71
+ boxX: createShapeId('boxX'),
72
+
73
+ lineA: createShapeId('lineA'),
74
+
75
+ iconA: createShapeId('iconA'),
76
+ }
77
+
78
+ beforeEach(() => {
79
+ editor = new TestEditor()
80
+
81
+ editor.createShapes([
82
+ {
83
+ id: ids.boxA,
84
+ type: 'geo',
85
+ x: 10,
86
+ y: 10,
87
+ props: {
88
+ w: 100,
89
+ h: 100,
90
+ },
91
+ },
92
+ {
93
+ id: ids.boxB,
94
+ type: 'geo',
95
+ parentId: ids.boxA,
96
+ x: 100,
97
+ y: 100,
98
+ props: {
99
+ w: 100,
100
+ h: 100,
101
+ },
102
+ },
103
+ {
104
+ id: ids.boxC,
105
+ type: 'geo',
106
+ parentId: ids.boxA,
107
+ x: 200,
108
+ y: 200,
109
+ props: {
110
+ w: 100,
111
+ h: 100,
112
+ },
113
+ },
114
+ ])
115
+ })
116
+
117
+ describe('When pointing a resizer handle...', () => {
118
+ it('enters and exits the pointing_resize_handle state', () => {
119
+ editor
120
+ .select(ids.boxA)
121
+ .pointerDown(60, 60, {
122
+ target: 'selection',
123
+ handle: 'bottom_right',
124
+ })
125
+ .expectToBeIn('select.pointing_resize_handle')
126
+ .pointerUp()
127
+ .expectToBeIn('select.idle')
128
+ })
129
+
130
+ it('exits the pointing_resize_handle state when cancelled', () => {
131
+ editor
132
+ .select(ids.boxA)
133
+ .pointerDown(60, 60, {
134
+ target: 'selection',
135
+ handle: 'bottom_right',
136
+ })
137
+ .expectToBeIn('select.pointing_resize_handle')
138
+ .cancel()
139
+ .expectToBeIn('select.idle')
140
+ })
141
+ })
142
+
143
+ describe('When dragging a resize handle...', () => {
144
+ it('enters and exits the resizing state', () => {
145
+ editor
146
+ .select(ids.boxA)
147
+ .pointerDown(60, 60, {
148
+ target: 'selection',
149
+ handle: 'bottom_right',
150
+ })
151
+ .pointerMove(10, 10)
152
+ .expectToBeIn('select.resizing')
153
+ })
154
+
155
+ it('exits the resizing state on pointer up', () => {
156
+ editor
157
+ .select(ids.boxA)
158
+ .pointerDown(60, 60, {
159
+ target: 'selection',
160
+ handle: 'bottom_right',
161
+ })
162
+ .pointerMove(10, 10)
163
+ .pointerUp()
164
+ .expectToBeIn('select.idle')
165
+ })
166
+
167
+ it('exits the resizing state when cancelled', () => {
168
+ editor
169
+ .select(ids.boxA)
170
+ .pointerDown(60, 60, {
171
+ target: 'selection',
172
+ handle: 'bottom_right',
173
+ })
174
+ .pointerMove(10, 10)
175
+ .cancel()
176
+ .expectToBeIn('select.idle')
177
+ })
178
+ })
179
+
180
+ describe('When resizing...', () => {
181
+ it('Resizes a single shape from the top left', () => {
182
+ editor
183
+ .select(ids.boxA)
184
+ .pointerDown(10, 10, {
185
+ type: 'pointer',
186
+ target: 'selection',
187
+ handle: 'top_left',
188
+ })
189
+ .expectShapeToMatch({ id: ids.boxA, x: 10, y: 10, props: { w: 100, h: 100 } })
190
+ .pointerMove(0, 0)
191
+ .expectShapeToMatch({ id: ids.boxA, x: 0, y: 0, props: { w: 110, h: 110 } })
192
+ })
193
+
194
+ it('Resizes a single shape from the top right', () => {
195
+ editor
196
+ .select(ids.boxA)
197
+ .pointerDown(60, 10, {
198
+ target: 'selection',
199
+ handle: 'top_right',
200
+ })
201
+ .expectShapeToMatch({ id: ids.boxA, x: 10, y: 10, props: { w: 100, h: 100 } })
202
+ .pointerMove(70, 0)
203
+ .expectShapeToMatch({ id: ids.boxA, x: 10, y: 0, props: { w: 110, h: 110 } })
204
+ })
205
+
206
+ it('Resizes a single shape from the bottom right', () => {
207
+ editor
208
+ .select(ids.boxA)
209
+ .pointerDown(60, 60, {
210
+ target: 'selection',
211
+ handle: 'bottom_right',
212
+ })
213
+ .expectShapeToMatch({ id: ids.boxA, x: 10, y: 10, props: { w: 100, h: 100 } })
214
+ .pointerMove(70, 70)
215
+ .expectShapeToMatch({ id: ids.boxA, x: 10, y: 10, props: { w: 110, h: 110 } })
216
+ })
217
+
218
+ it('Resizes a single shape from the bottom left', () => {
219
+ editor
220
+ .select(ids.boxA)
221
+ .pointerDown(10, 60, {
222
+ target: 'selection',
223
+ handle: 'bottom_left',
224
+ })
225
+ .expectShapeToMatch({ id: ids.boxA, x: 10, y: 10, props: { w: 100, h: 100 } })
226
+ .pointerMove(0, 70)
227
+ .expectShapeToMatch({ id: ids.boxA, x: 0, y: 10, props: { w: 110, h: 110 } })
228
+ })
229
+ })
230
+
231
+ describe('When resizing a rotated shape...', () => {
232
+ it.each([
233
+ 0,
234
+ Math.PI / 2,
235
+ // Math.PI / 4, Math.PI
236
+ ])('Resizes a shape rotated %i from the top left', (rotation) => {
237
+ const offset = new Vec2d(10, 10)
238
+
239
+ // Rotate the shape by $rotation from its top left corner
240
+
241
+ editor.select(ids.boxA)
242
+
243
+ const initialPagePoint = editor.getShapePageTransform(ids.boxA)!.point()
244
+
245
+ const pt0 = Vec2d.From(initialPagePoint)
246
+ const pt1 = Vec2d.RotWith(initialPagePoint, editor.getSelectionPageBounds()!.center, rotation)
247
+ const pt2 = Vec2d.Sub(initialPagePoint, offset).rotWith(
248
+ editor.getSelectionPageBounds()!.center!,
249
+ rotation
250
+ )
251
+
252
+ editor
253
+ .pointerDown(pt0.x, pt0.y, {
254
+ target: 'selection',
255
+ handle: 'top_left_rotate',
256
+ })
257
+ .pointerMove(pt1.x, pt1.y)
258
+ .pointerUp()
259
+
260
+ // The shape's point should now be at pt1 (it rotates from the top left corner)
261
+
262
+ expect(editor.getShapePageTransform(ids.boxA)!.rotation()).toBeCloseTo(rotation)
263
+ expect(editor.getShapePageTransform(ids.boxA)!.point()).toCloselyMatchObject(pt1)
264
+
265
+ // Resize by moving the top left resize handle to pt2. Should be a delta of [10, 10].
266
+
267
+ expect(Vec2d.Dist(editor.getShapePageTransform(ids.boxA)!.point(), pt2)).toBeCloseTo(
268
+ offset.len()
269
+ )
270
+
271
+ editor
272
+ .pointerDown(pt1.x, pt1.y, {
273
+ target: 'selection',
274
+ handle: 'top_left',
275
+ })
276
+ .pointerMove(pt2.x, pt2.y)
277
+ .pointerUp()
278
+
279
+ // The shape should have moved its point to pt2 and be delta bigger.
280
+
281
+ expect(editor.getShapePageTransform(ids.boxA)!.point()).toCloselyMatchObject(pt2)
282
+ editor.expectShapeToMatch({ id: ids.boxA, props: { w: 110, h: 110 } })
283
+ })
284
+ })
285
+
286
+ describe('When resizing mulitple shapes...', () => {
287
+ it.each([
288
+ [0, 0, 0, 0],
289
+ [10, 10, 0, 0],
290
+ [0, 0, Math.PI, 0],
291
+ [10, 10, 0, Math.PI / 4],
292
+ ])(
293
+ 'Resizes B and C when: \n\tA = { x: %s, y: %s, rotation: %s }\n\tB = { rotation: %s }',
294
+ (x, y, rotation, rotationB) => {
295
+ const shapeA = editor.getShape(ids.boxA)!
296
+ const shapeB = editor.getShape(ids.boxB)!
297
+ const shapeC = editor.getShape(ids.boxC)!
298
+
299
+ editor.updateShapes([
300
+ {
301
+ id: ids.boxA,
302
+ type: 'geo',
303
+ x,
304
+ y,
305
+ rotation,
306
+ },
307
+ {
308
+ id: ids.boxB,
309
+ parentId: ids.boxA,
310
+ type: 'geo',
311
+ x: 100,
312
+ y: 100,
313
+ rotation: rotationB,
314
+ },
315
+ {
316
+ id: ids.boxC,
317
+ parentId: ids.boxA,
318
+ type: 'geo',
319
+ x: 200,
320
+ y: 200,
321
+ rotation: rotationB,
322
+ },
323
+ ])
324
+
325
+ // Rotate the shape by $rotation from its top left corner
326
+
327
+ const rotateStart = editor.getShapePageTransform(ids.boxA)!.point()
328
+ const rotateCenter = editor.getPageCenter(shapeA)!
329
+ const rotateEnd = Vec2d.RotWith(rotateStart, rotateCenter, rotation)
330
+
331
+ editor
332
+ .select(ids.boxA)
333
+ .pointerDown(rotateStart.x, rotateStart.y, {
334
+ target: 'selection',
335
+ handle: rotateRotateCorner('top_left_rotate', -editor.getSelectionRotation()),
336
+ })
337
+ .pointerMove(rotateEnd.x, rotateEnd.y)
338
+ .pointerUp()
339
+
340
+ expect(canonicalizeRotation(shapeA.rotation) % Math.PI).toBeCloseTo(
341
+ canonicalizeRotation(rotation) % Math.PI
342
+ )
343
+ expect(editor.getPageRotation(shapeB)).toBeCloseTo(rotation + rotationB)
344
+ expect(editor.getPageRotation(shapeC)).toBeCloseTo(rotation + rotationB)
345
+
346
+ editor.select(ids.boxB, ids.boxC)
347
+
348
+ // Now drag to resize the selection bounds
349
+
350
+ const initialBounds = editor.getSelectionPageBounds()!
351
+
352
+ // oddly rotated shapes maintain aspect ratio when being resized (for now)
353
+ const aspectRatio = initialBounds.width / initialBounds.height
354
+ const offsetX = initialBounds.width + 200
355
+ const offset = new Vec2d(offsetX, offsetX / aspectRatio)
356
+ const resizeStart = initialBounds.point
357
+ const resizeEnd = Vec2d.Sub(resizeStart, offset)
358
+
359
+ expect(Vec2d.Dist(resizeStart, resizeEnd)).toBeCloseTo(offset.len())
360
+ expect(
361
+ Vec2d.Min(
362
+ editor.getShapePageBounds(shapeB)!.point,
363
+ editor.getShapePageBounds(shapeC)!.point
364
+ )
365
+ ).toCloselyMatchObject(resizeStart)
366
+
367
+ editor
368
+ .pointerDown(resizeStart.x, resizeStart.y, {
369
+ target: 'selection',
370
+ handle: rotateSelectionHandle('top_left', -editor.getSelectionRotation()),
371
+ })
372
+ .pointerMove(resizeStart.x - 10, resizeStart.y - 10)
373
+ .pointerMove(resizeEnd.x, resizeEnd.y)
374
+ .pointerUp()
375
+
376
+ expect(editor.getSelectionPageBounds()!.point).toCloselyMatchObject(resizeEnd)
377
+ expect(new Vec2d(initialBounds.maxX, initialBounds.maxY)).toCloselyMatchObject(
378
+ new Vec2d(editor.getSelectionPageBounds()!.maxX, editor.getSelectionPageBounds()!.maxY)
379
+ )
380
+ }
381
+ )
382
+ })
383
+
384
+ describe('Reisizing a selection of multiple shapes', () => {
385
+ beforeEach(() => {
386
+ // 0 10 20 30
387
+ //
388
+ // ┌──────────┐
389
+ // │ │
390
+ // │ │
391
+ // │ A │
392
+ // │ │
393
+ // │ │
394
+ // 10 └──────────┘
395
+ //
396
+ //
397
+ //
398
+ //
399
+ // 20 ┌──────────┐
400
+ // │ │
401
+ // │ │
402
+ // │ B │
403
+ // │ │
404
+ // │ │
405
+ // 30 └──────────┘
406
+ editor.createShapes([box(ids.boxA, 0, 0), box(ids.boxB, 20, 20)])
407
+ })
408
+ it('works correctly when the shapes are not rotated', () => {
409
+ editor.select(ids.boxA, ids.boxB)
410
+ // shrink
411
+
412
+ // 0 15
413
+ // ┌──────────────────┐
414
+ // │ ┌───┐ │
415
+ // │ │ A │ │
416
+ // │ └───┘ │
417
+ // │ │
418
+ // │ ┌───┐ │
419
+ // │ │ B │ │
420
+ // │ └───┘ │
421
+ // └──────────────────O
422
+
423
+ editor.pointerDown(30, 30, { target: 'selection', handle: 'bottom_right' })
424
+ editor.pointerMove(15, 15)
425
+
426
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 15, h: 15 })
427
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 5, h: 5 })
428
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 10, y: 10, w: 5, h: 5 })
429
+
430
+ // strech horizontally
431
+
432
+ // 0 20 40 60
433
+ //
434
+ // ┌──────────────────────────────────────────────────────────────────┐
435
+ // │ ┌───────────────────────┐ │
436
+ // │ │ │ │
437
+ // │ │ A │ │
438
+ // │ │ │ │
439
+ // │ └───────────────────────┘ │
440
+ // │ │
441
+ // │ │
442
+ // │ ┌───────────────────────┐ │
443
+ // │ │ │ │
444
+ // │ │ B │ │
445
+ // │ │ │ │
446
+ // │ └───────────────────────┘ │
447
+ // └──────────────────────────────────────────────────────────────────O
448
+
449
+ editor.pointerMove(60, 30)
450
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 60, h: 30 })
451
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 20, h: 10 })
452
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 40, y: 20, w: 20, h: 10 })
453
+ // stretch vertically
454
+ // 0 10 20 30
455
+ // ┌─────────────────────────────────┐
456
+ // │ ┌──────────┐ │
457
+ // │ │ │ │
458
+ // │ │ │ │
459
+ // │ │ │ │
460
+ // │ │ │ │
461
+ // │ │ A │ │
462
+ // │ │ │ │
463
+ // │ │ │ │
464
+ // │ │ │ │
465
+ // 20 │ └──────────┘ │
466
+ // │ │
467
+ // │ │
468
+ // │ │
469
+ // │ │
470
+ // │ │
471
+ // │ │
472
+ // │ │
473
+ // 40 │ ┌──────────┐ │
474
+ // │ │ │ │
475
+ // │ │ │ │
476
+ // │ │ │ │
477
+ // │ │ B │ │
478
+ // │ │ │ │
479
+ // │ │ │ │
480
+ // │ │ │ │
481
+ // │ │ │ │
482
+ // 60 │ └──────────┘ │
483
+ // └─────────────────────────────────O
484
+ editor.pointerMove(30, 60)
485
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 30, h: 60 })
486
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 10, h: 20 })
487
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 20, y: 40, w: 10, h: 20 })
488
+
489
+ // invert + shrink
490
+
491
+ // -15 0
492
+ // O───────────────┐
493
+ // │ ┌───┐ │
494
+ // │ │ B │ │
495
+ // │ └───┘ │
496
+ // │ │
497
+ // │ ┌───┐ │
498
+ // │ │ A │ │
499
+ // │ └───┘ │
500
+ // └───────────────┘
501
+ editor.pointerMove(-15, -15)
502
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 15, h: 15 })
503
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: -5, w: 5, h: 5 })
504
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -15, y: -15, w: 5, h: 5 })
505
+
506
+ // resize from center
507
+
508
+ // -15 5 15 25 45
509
+ // ┌───────────────────────────────────┐
510
+ // │ ┌──────────┐ │
511
+ // │ │ │ │
512
+ // │ │ A │ │
513
+ // │ │ │ │
514
+ // │ └──────────┘ │
515
+ // │ │
516
+ // │ x │
517
+ // │ │
518
+ // │ ┌──────────┐ │
519
+ // │ │ │ │
520
+ // │ │ B │ │
521
+ // │ │ │ │
522
+ // │ └──────────┘ │
523
+ // └───────────────────────────────────O
524
+ editor.pointerMove(45, 45, { altKey: true })
525
+
526
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({
527
+ w: 60,
528
+ h: 60,
529
+ x: -15,
530
+ y: -15,
531
+ })
532
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -15, y: -15, w: 20, h: 20 })
533
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 25, y: 25, w: 20, h: 20 })
534
+
535
+ // resize with aspect ratio locked
536
+
537
+ // 0 15
538
+ // ┌──────────────────┐
539
+ // │ ┌───┐ │
540
+ // │ │ A │ │
541
+ // │ └───┘ │
542
+ // │ │ <- mouse is here
543
+ // │ ┌───┐ │
544
+ // │ │ B │ │
545
+ // │ └───┘ │
546
+ // └──────────────────O
547
+
548
+ editor.pointerMove(15, 8, { altKey: false, shiftKey: true })
549
+ jest.advanceTimersByTime(200)
550
+
551
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 15, h: 15 })
552
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 5, h: 5 })
553
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 10, y: 10, w: 5, h: 5 })
554
+
555
+ // resize from center with aspect ratio locked
556
+
557
+ // -15 5 15 25 45
558
+ // ┌───────────────────────────────────┐
559
+ // │ ┌──────────┐ │
560
+ // │ │ │ │
561
+ // │ │ A │ │
562
+ // │ │ │ │
563
+ // │ └──────────┘ │
564
+ // │ │
565
+ // │ x │ <- mouse is here
566
+ // │ │
567
+ // │ ┌──────────┐ │
568
+ // │ │ │ │
569
+ // │ │ B │ │
570
+ // │ │ │ │
571
+ // │ └──────────┘ │
572
+ // └───────────────────────────────────O
573
+ editor.pointerMove(45, 16, { altKey: true, shiftKey: true })
574
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({
575
+ w: 60,
576
+ h: 60,
577
+ x: -15,
578
+ y: -15,
579
+ })
580
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -15, y: -15, w: 20, h: 20 })
581
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 25, y: 25, w: 20, h: 20 })
582
+ })
583
+
584
+ it('works the same when shapes are rotated by a multiple of 90 degrees', () => {
585
+ // rotate A by 90 degrees
586
+ editor.select(ids.boxA)
587
+ editor.pointerDown(0, 0, { target: 'selection', handle: 'top_left_rotate' })
588
+ editor.pointerMove(10, 0, { shiftKey: true })
589
+ editor.pointerUp(10, 0, { shiftKey: false })
590
+
591
+ expect(editor.getShape(ids.boxA)!.rotation).toBeCloseTo(PI / 2)
592
+
593
+ // rotate B by -90 degrees
594
+ editor.select(ids.boxB)
595
+ editor.pointerDown(30, 20, { target: 'selection', handle: 'top_left_rotate' })
596
+ editor.pointerMove(20, 20, { shiftKey: true })
597
+ editor.pointerUp(20, 20, { shiftKey: false })
598
+ jest.advanceTimersByTime(200)
599
+
600
+ expect(editor.getShape(ids.boxB)!.rotation).toBeCloseTo(canonicalizeRotation(-PI / 2))
601
+
602
+ editor.select(ids.boxA, ids.boxB)
603
+ // shrink
604
+
605
+ // 0 15
606
+ // ┌──────────────────┐
607
+ // │ ┌───┐ │
608
+ // │ │ A │ │
609
+ // │ └───┘ │
610
+ // │ │
611
+ // │ ┌───┐ │
612
+ // │ │ B │ │
613
+ // │ └───┘ │
614
+ // └──────────────────O
615
+
616
+ editor.pointerDown(30, 30, {
617
+ target: 'selection',
618
+ handle: rotateSelectionHandle('bottom_right', -editor.getSelectionRotation()),
619
+ })
620
+ editor.pointerMove(15, 15)
621
+
622
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 5, h: 5 })
623
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 10, y: 10, w: 5, h: 5 })
624
+
625
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 15, h: 15 })
626
+
627
+ // strech horizontally
628
+
629
+ // 0 20 40 60
630
+ //
631
+ // ┌──────────────────────────────────────────────────────────────────┐
632
+ // │ ┌───────────────────────┐ │
633
+ // │ │ │ │
634
+ // │ │ A │ │
635
+ // │ │ │ │
636
+ // │ └───────────────────────┘ │
637
+ // │ │
638
+ // │ │
639
+ // │ ┌───────────────────────┐ │
640
+ // │ │ │ │
641
+ // │ │ B │ │
642
+ // │ │ │ │
643
+ // │ └───────────────────────┘ │
644
+ // └──────────────────────────────────────────────────────────────────O
645
+
646
+ editor.pointerMove(60, 30)
647
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 60, h: 30 })
648
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 20, h: 10 })
649
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 40, y: 20, w: 20, h: 10 })
650
+ // stretch vertically
651
+ // 0 10 20 30
652
+ // ┌─────────────────────────────────┐
653
+ // │ ┌──────────┐ │
654
+ // │ │ │ │
655
+ // │ │ │ │
656
+ // │ │ │ │
657
+ // │ │ │ │
658
+ // │ │ A │ │
659
+ // │ │ │ │
660
+ // │ │ │ │
661
+ // │ │ │ │
662
+ // 20 │ └──────────┘ │
663
+ // │ │
664
+ // │ │
665
+ // │ │
666
+ // │ │
667
+ // │ │
668
+ // │ │
669
+ // │ │
670
+ // 40 │ ┌──────────┐ │
671
+ // │ │ │ │
672
+ // │ │ │ │
673
+ // │ │ │ │
674
+ // │ │ B │ │
675
+ // │ │ │ │
676
+ // │ │ │ │
677
+ // │ │ │ │
678
+ // │ │ │ │
679
+ // 60 │ └──────────┘ │
680
+ // └─────────────────────────────────O
681
+ editor.pointerMove(30, 60)
682
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 30, h: 60 })
683
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 10, h: 20 })
684
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 20, y: 40, w: 10, h: 20 })
685
+
686
+ // invert + shrink
687
+
688
+ // -15 0
689
+ // O───────────────┐
690
+ // │ ┌───┐ │
691
+ // │ │ B │ │
692
+ // │ └───┘ │
693
+ // │ │
694
+ // │ ┌───┐ │
695
+ // │ │ A │ │
696
+ // │ └───┘ │
697
+ // └───────────────┘
698
+ editor.pointerMove(-15, -15)
699
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 15, h: 15 })
700
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: -5, w: 5, h: 5 })
701
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -15, y: -15, w: 5, h: 5 })
702
+
703
+ // resize from center
704
+
705
+ // -15 5 15 25 45
706
+ // ┌───────────────────────────────────┐
707
+ // │ ┌──────────┐ │
708
+ // │ │ │ │
709
+ // │ │ A │ │
710
+ // │ │ │ │
711
+ // │ └──────────┘ │
712
+ // │ │
713
+ // │ x │
714
+ // │ │
715
+ // │ ┌──────────┐ │
716
+ // │ │ │ │
717
+ // │ │ B │ │
718
+ // │ │ │ │
719
+ // │ └──────────┘ │
720
+ // └───────────────────────────────────O
721
+ editor.pointerMove(45, 45, { altKey: true })
722
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({
723
+ w: 60,
724
+ h: 60,
725
+ x: -15,
726
+ y: -15,
727
+ })
728
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -15, y: -15, w: 20, h: 20 })
729
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 25, y: 25, w: 20, h: 20 })
730
+
731
+ // resize with aspect ratio locked
732
+
733
+ // 0 15
734
+ // ┌──────────────────┐
735
+ // │ ┌───┐ │
736
+ // │ │ A │ │
737
+ // │ └───┘ │
738
+ // │ │ <- mouse is here
739
+ // │ ┌───┐ │
740
+ // │ │ B │ │
741
+ // │ └───┘ │
742
+ // └──────────────────O
743
+
744
+ editor.pointerMove(15, 8, { altKey: false, shiftKey: true })
745
+ jest.advanceTimersByTime(200)
746
+
747
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 15, h: 15 })
748
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 5, h: 5 })
749
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 10, y: 10, w: 5, h: 5 })
750
+
751
+ // resize from center with aspect ratio locked
752
+
753
+ // -15 5 15 25 45
754
+ // ┌───────────────────────────────────┐
755
+ // │ ┌──────────┐ │
756
+ // │ │ │ │
757
+ // │ │ A │ │
758
+ // │ │ │ │
759
+ // │ └──────────┘ │
760
+ // │ │
761
+ // │ x │ <- mouse is here
762
+ // │ │
763
+ // │ ┌──────────┐ │
764
+ // │ │ │ │
765
+ // │ │ B │ │
766
+ // │ │ │ │
767
+ // │ └──────────┘ │
768
+ // └───────────────────────────────────O
769
+ editor.pointerMove(45, 16, { altKey: true, shiftKey: true })
770
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({
771
+ w: 60,
772
+ h: 60,
773
+ x: -15,
774
+ y: -15,
775
+ })
776
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -15, y: -15, w: 20, h: 20 })
777
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 25, y: 25, w: 20, h: 20 })
778
+ })
779
+ it('will not change the apsect ratio on shapes that have been rotated by some number that is not a multiple of 90 degrees', () => {
780
+ // rotate B a tiny bit
781
+ editor.select(ids.boxB)
782
+ editor.pointerDown(30, 20, { target: 'selection', handle: 'top_left_rotate' })
783
+ editor.pointerMove(30, 21)
784
+ editor.pointerUp(30, 21)
785
+ // strech horizontally
786
+
787
+ // 0 20 40 60
788
+ // ┌──────────────────────────────────────────────────────────────────┐
789
+ // │ ┌───────────────────────┐ │
790
+ // │ │ │ │
791
+ // │ │ A │ │
792
+ // │ │ │ │
793
+ // │ └───────────────────────┘ │
794
+ // │ │
795
+ // │ │
796
+ // │ ┌────────────┐ │
797
+ // │ │ │ │
798
+ // │ │ B │ │
799
+ // │ │ │ │
800
+ // │ └────────────┘ │
801
+ // └──────────────────────────────────────────────────────────────────O
802
+
803
+ editor.select(ids.boxA, ids.boxB)
804
+ editor.pointerDown(30, 30, { target: 'selection', handle: 'bottom_right' })
805
+ editor.pointerMove(60, 30)
806
+ expect(roundedBox(editor.getSelectionPageBounds()!)).toMatchObject({ w: 60, h: 30 })
807
+ // A should stretch
808
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 20, h: 10 })
809
+ // B should not
810
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ w: 20, h: 10 })
811
+ })
812
+ })
813
+
814
+ describe('When resizing a shape with children', () => {
815
+ it("Offsets children when the shape's top left corner changes", () => {
816
+ editor
817
+ .updateShapes([
818
+ {
819
+ id: ids.boxC,
820
+ type: 'geo',
821
+ parentId: ids.boxB,
822
+ },
823
+ ])
824
+ .select(ids.boxA)
825
+ .pointerDown(10, 10, {
826
+ target: 'selection',
827
+ handle: 'top_left',
828
+ })
829
+ .pointerMove(0, 0)
830
+ // A's model should have changed by the offset
831
+ .expectShapeToMatch({
832
+ id: ids.boxA,
833
+ x: 0,
834
+ y: 0,
835
+ })
836
+ // B's model should have changed by the offset
837
+ .expectShapeToMatch({
838
+ id: ids.boxB,
839
+ x: 110,
840
+ y: 110,
841
+ })
842
+ // C's model should also have changed
843
+ .expectShapeToMatch({
844
+ id: ids.boxC,
845
+ x: 220,
846
+ y: 220,
847
+ })
848
+ })
849
+
850
+ it('Offsets children when the shape is rotated', () => {
851
+ editor
852
+ .updateShapes([
853
+ {
854
+ id: ids.boxA,
855
+ type: 'geo',
856
+ rotation: Math.PI,
857
+ },
858
+ ])
859
+ .select(ids.boxA)
860
+ .pointerDown(10, 10, {
861
+ target: 'selection',
862
+ handle: 'top_left',
863
+ })
864
+ .pointerMove(0, 0)
865
+ .expectToBeIn('select.resizing')
866
+ // A's model should have changed by the offset
867
+ .expectShapeToMatch({
868
+ id: ids.boxA,
869
+ x: 0,
870
+ y: 0,
871
+ })
872
+ // B's model should have changed by the offset
873
+ .expectShapeToMatch({
874
+ id: ids.boxB,
875
+ x: 90,
876
+ y: 90,
877
+ })
878
+ })
879
+
880
+ it('Resizes a rotated draw shape', () => {
881
+ editor
882
+ .updateShapes([
883
+ {
884
+ id: ids.boxA,
885
+ type: 'geo',
886
+ rotation: 0,
887
+ x: 10,
888
+ y: 10,
889
+ },
890
+ {
891
+ id: ids.boxB,
892
+ type: 'geo',
893
+ parentId: ids.boxA,
894
+ rotation: 0,
895
+ x: 0,
896
+ y: 0,
897
+ },
898
+ ])
899
+ .createShapes([
900
+ {
901
+ id: ids.lineA,
902
+ parentId: ids.boxA,
903
+ rotation: Math.PI,
904
+ type: 'draw',
905
+ x: 100,
906
+ y: 100,
907
+ props: {
908
+ segments: [
909
+ {
910
+ type: 'free',
911
+ points: [
912
+ { x: 0, y: 0, z: 0.5 },
913
+ { x: 100, y: 100, z: 0.5 },
914
+ ],
915
+ },
916
+ ],
917
+ },
918
+ },
919
+ ])
920
+ .select(ids.boxB, ids.lineA)
921
+
922
+ editor
923
+ .pointerDown(10, 10, {
924
+ target: 'selection',
925
+ handle: 'top_left',
926
+ })
927
+ .pointerMove(0, 0)
928
+ // .pointerMove(10, 10)
929
+ .expectToBeIn('select.resizing')
930
+ // A's model should have changed by the offset
931
+ .expectShapeToMatch({
932
+ id: ids.boxB,
933
+ x: -10,
934
+ y: -10,
935
+ })
936
+ // B's model should have changed by the offset
937
+
938
+ expect(editor.getShape(ids.lineA)).toMatchSnapshot('draw shape after rotating')
939
+ })
940
+ })
941
+
942
+ function getGapAndPointLines() {
943
+ const gapLines = editor.snaps.getLines().filter((snap) => snap.type === 'gaps') as GapsSnapLine[]
944
+ const pointLines = editor.snaps
945
+ .getLines()
946
+ .filter((snap) => snap.type === 'points') as PointsSnapLine[]
947
+ return { gapLines, pointLines }
948
+ }
949
+
950
+ describe('snapping while resizing', () => {
951
+ beforeEach(() => {
952
+ // 0 40 60 160 180
953
+ //
954
+ // 0 ┌────────────┐
955
+ // │ A │
956
+ // 40 └────────────┘
957
+ //
958
+ // 60 ┌──┐ 80 140 ┌──┐
959
+ // │D │ 80 ┌──────┐ │B │
960
+ // │ │ │ │ │ │
961
+ // │ │ │ X │ │ │
962
+ // │ │ │ │ │ │
963
+ // │ │ 140 └──────┘ │ │
964
+ // 160 └──┘ └──┘
965
+ //
966
+ // 180 ┌────────────┐
967
+ // │ C │
968
+ // └────────────┘
969
+
970
+ editor.createShapes([
971
+ box(ids.boxA, 60, 0, 100, 40),
972
+ box(ids.boxB, 180, 60, 40, 100),
973
+ box(ids.boxC, 60, 180, 100, 40),
974
+ box(ids.boxD, 0, 60, 40, 100),
975
+ box(ids.boxX, 80, 80, 60, 60),
976
+ ])
977
+ })
978
+
979
+ it('works for dragging the top edge', () => {
980
+ // snap to top edges of D and B
981
+ editor
982
+ .select(ids.boxX)
983
+ .pointerDown(115, 80, {
984
+ target: 'selection',
985
+ handle: 'top',
986
+ })
987
+ .pointerMove(115, 59, { ctrlKey: true })
988
+
989
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 60, props: { w: 60, h: 80 } })
990
+ expect(editor.snaps.getLines().length).toBe(1)
991
+
992
+ // moving the mouse horizontally should not change things
993
+ editor.pointerMove(15, 65, { ctrlKey: true })
994
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 60, props: { w: 60, h: 80 } })
995
+ expect(editor.snaps.getLines().length).toBe(1)
996
+
997
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(6)
998
+
999
+ // snap to bottom edge of A
1000
+ editor.pointerMove(15, 43, { ctrlKey: true })
1001
+
1002
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 40, props: { w: 60, h: 100 } })
1003
+ expect(editor.snaps.getLines().length).toBe(1)
1004
+
1005
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(4)
1006
+ })
1007
+
1008
+ it('works for dragging the right edge', () => {
1009
+ // Snap to right edges of A and C
1010
+
1011
+ editor
1012
+ .select(ids.boxX)
1013
+ .pointerDown(140, 115, {
1014
+ target: 'selection',
1015
+ handle: 'right',
1016
+ })
1017
+ .pointerMove(156, 115, { ctrlKey: true })
1018
+
1019
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 80, h: 60 } })
1020
+ expect(editor.snaps.getLines().length).toBe(1)
1021
+
1022
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(6)
1023
+
1024
+ // moving the mouse vertically should not change things
1025
+ editor.pointerMove(156, 180, { ctrlKey: true })
1026
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 80, h: 60 } })
1027
+
1028
+ // snap to left edge of B
1029
+ editor.pointerMove(173, 280, { ctrlKey: true })
1030
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 100, h: 60 } })
1031
+ expect(editor.snaps.getLines().length).toBe(1)
1032
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(4)
1033
+ })
1034
+
1035
+ it('works for dragging the bottom edge', () => {
1036
+ // snap to bottom edges of B and D
1037
+ editor
1038
+ .select(ids.boxX)
1039
+ .pointerDown(115, 140, {
1040
+ target: 'selection',
1041
+ handle: 'bottom',
1042
+ })
1043
+ .pointerMove(115, 159, { ctrlKey: true })
1044
+
1045
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 60, h: 80 } })
1046
+ expect(editor.snaps.getLines().length).toBe(1)
1047
+
1048
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(6)
1049
+
1050
+ // changing horzontal mouse position should not change things
1051
+ editor.pointerMove(315, 163, { ctrlKey: true })
1052
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 60, h: 80 } })
1053
+ expect(editor.snaps.getLines().length).toBe(1)
1054
+
1055
+ // snap to top edge of C
1056
+ editor.pointerMove(115, 183, { ctrlKey: true })
1057
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 60, h: 100 } })
1058
+ expect(editor.snaps.getLines().length).toBe(1)
1059
+
1060
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(4)
1061
+ })
1062
+
1063
+ it('works for dragging the left edge', () => {
1064
+ // snap to left edges of A and C
1065
+ editor
1066
+ .select(ids.boxX)
1067
+ .pointerDown(80, 115, {
1068
+ target: 'selection',
1069
+ handle: 'left',
1070
+ })
1071
+ .pointerMove(59, 115, { ctrlKey: true })
1072
+
1073
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 60, y: 80, props: { w: 80, h: 60 } })
1074
+
1075
+ expect(editor.snaps.getLines().length).toBe(1)
1076
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(6)
1077
+
1078
+ // moving the mouse vertically should not change things
1079
+ editor.pointerMove(63, 180, { ctrlKey: true })
1080
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 60, y: 80, props: { w: 80, h: 60 } })
1081
+
1082
+ // snap to right edge of D
1083
+ editor.pointerMove(39, 280, { ctrlKey: true })
1084
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 40, y: 80, props: { w: 100, h: 60 } })
1085
+
1086
+ expect(editor.snaps.getLines().length).toBe(1)
1087
+ expect(getGapAndPointLines().pointLines[0].points).toHaveLength(4)
1088
+ })
1089
+ it('works for dragging the top left corner', () => {
1090
+ // snap to left edges of A and C
1091
+ // x ┌───────────────────────────┐
1092
+ // │ │ A │
1093
+ // │ │ │
1094
+ // x └───────────────────────────┘
1095
+ // │
1096
+ // │
1097
+ // ┌─────┐ │
1098
+ // │ │ │
1099
+ // │ │ x O────────────────┐
1100
+ // │ D │ │ │ │
1101
+ // │ │ │ │ │
1102
+ // │ │ │ │ X │
1103
+ // │ │ │ │ │
1104
+ // │ │ │ │ │
1105
+ // │ │ x └────────────────┘
1106
+ // │ │ │
1107
+ // └─────┘ │
1108
+ // │
1109
+ // │
1110
+ // x ┌───────────────────────────┐
1111
+ // │ │ c │
1112
+ // │ │ │
1113
+ // x └───────────────────────────┘
1114
+
1115
+ editor.select(ids.boxX).pointerDown(80, 80, {
1116
+ target: 'selection',
1117
+ handle: 'top_left',
1118
+ })
1119
+
1120
+ editor.pointerMove(62, 81, { ctrlKey: true })
1121
+
1122
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 60, y: 81, props: { w: 80, h: 59 } })
1123
+
1124
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1125
+ Array [
1126
+ "60,0 60,40 60,81 60,140 60,180 60,220",
1127
+ ]
1128
+ `)
1129
+
1130
+ // snap to top edges of B and D
1131
+ //
1132
+ // ┌────────────────────┐
1133
+ // │ │
1134
+ // │ A │
1135
+ // │ │
1136
+ // └────────────────────┘
1137
+ //
1138
+ // x─────x────────x─────────────x─────────x─────x
1139
+ // ┌─────┐ O─────────────┐ ┌─────┐
1140
+ // │ │ │ │ │ │
1141
+ // │ │ │ │ │ │
1142
+ // │ D │ │ │ │ B │
1143
+ // │ │ │ X │ │ │
1144
+ // │ │ │ │ │ │
1145
+ // │ │ │ │ │ │
1146
+ // │ │ │ │ │ │
1147
+ // │ │ └─────────────┘ │ │
1148
+ // │ │ │ │
1149
+ // │ │ │ │
1150
+ // └─────┘ └─────┘
1151
+ //
1152
+ // ┌────────────────────┐
1153
+ // │ │
1154
+ // │ C │
1155
+ // │ │
1156
+ // └────────────────────┘
1157
+ editor.pointerMove(81, 58, { ctrlKey: true })
1158
+
1159
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 81, y: 60, props: { w: 59, h: 80 } })
1160
+
1161
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1162
+ Array [
1163
+ "0,60 40,60 81,60 140,60 180,60 220,60",
1164
+ ]
1165
+ `)
1166
+
1167
+ // sanp to both at the same time
1168
+ // x ┌────────────────────┐
1169
+ // │ │ │
1170
+ // │ │ A │
1171
+ // │ │ │
1172
+ // x └────────────────────┘
1173
+ // │
1174
+ // x─────x───x──────────────────x─────────x─────x
1175
+ // ┌─────┐ │ O────────────────┐ ┌─────┐
1176
+ // │ │ │ │ │ │ │
1177
+ // │ │ │ │ │ │ │
1178
+ // │ D │ │ │ │ │ B │
1179
+ // │ │ │ │ X │ │ │
1180
+ // │ │ │ │ │ │ │
1181
+ // │ │ │ │ │ │ │
1182
+ // │ │ │ │ │ │ │
1183
+ // │ │ x └────────────────┘ │ │
1184
+ // │ │ │ │ │
1185
+ // │ │ │ │ │
1186
+ // └─────┘ │ └─────┘
1187
+ // │
1188
+ // x ┌────────────────────┐
1189
+ // │ │ │
1190
+ // │ │ C │
1191
+ // │ │ │
1192
+ // x └────────────────────┘
1193
+ editor.pointerMove(59, 62, { ctrlKey: true })
1194
+
1195
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 60, y: 60, props: { w: 80, h: 80 } })
1196
+
1197
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1198
+ Array [
1199
+ "0,60 40,60 60,60 140,60 180,60 220,60",
1200
+ "60,0 60,40 60,60 60,140 60,180 60,220",
1201
+ ]
1202
+ `)
1203
+ })
1204
+ it('works for dragging the top right corner', () => {
1205
+ // ┌────────────────────┐ x
1206
+ // │ │ │
1207
+ // │ A │ │
1208
+ // │ │ │
1209
+ // └────────────────────┘ x
1210
+ // │
1211
+ // x─────x──────────x─────────────────x───x─────x
1212
+ // ┌─────┐ ┌───────────────O │ ┌─────┐
1213
+ // │ │ │ │ │ │ │
1214
+ // │ │ │ │ │ │ │
1215
+ // │ D │ │ │ │ │ B │
1216
+ // │ │ │ X │ │ │ │
1217
+ // │ │ │ │ │ │ │
1218
+ // │ │ │ │ │ │ │
1219
+ // │ │ │ │ │ │ │
1220
+ // │ │ └───────────────┘ x │ │
1221
+ // │ │ │ │ │
1222
+ // │ │ │ │ │
1223
+ // └─────┘ │ └─────┘
1224
+ // │
1225
+ // ┌────────────────────┐ x
1226
+ // │ │ │
1227
+ // │ C │ │
1228
+ // │ │ │
1229
+ // └────────────────────┘ x
1230
+
1231
+ editor
1232
+ .select(ids.boxX)
1233
+ .pointerDown(140, 80, {
1234
+ target: 'selection',
1235
+ handle: 'top_right',
1236
+ })
1237
+ .pointerMove(161, 59, { ctrlKey: true })
1238
+
1239
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 60, props: { w: 80, h: 80 } })
1240
+ })
1241
+ it('works for dragging the bottom right corner', () => {
1242
+ // ┌────────────────────┐ x
1243
+ // │ │ │
1244
+ // │ A │ │
1245
+ // │ │ │
1246
+ // └────────────────────┘ x
1247
+ // │
1248
+ // │
1249
+ // │
1250
+ // ┌─────┐ │ ┌─────┐
1251
+ // │ │ │ │ │
1252
+ // │ │ ┌───────────────┐ x │ │
1253
+ // │ D │ │ │ │ │ B │
1254
+ // │ │ │ X │ │ │ │
1255
+ // │ │ │ │ │ │ │
1256
+ // │ │ │ │ │ │ │
1257
+ // │ │ │ │ │ │ │
1258
+ // │ │ │ │ │ │ │
1259
+ // │ │ │ │ │ │ │
1260
+ // │ │ │ │ │ │ │
1261
+ // └─────┘ └───────────────O │ └─────┘
1262
+ // x─────x──────────x─────────────────x───x─────x
1263
+ // ┌────────────────────┐ x
1264
+ // │ │ │
1265
+ // │ C │ │
1266
+ // │ │ │
1267
+ // └────────────────────┘ x
1268
+
1269
+ editor
1270
+ .select(ids.boxX)
1271
+ .pointerDown(140, 140, {
1272
+ target: 'selection',
1273
+ handle: 'bottom_right',
1274
+ })
1275
+ .pointerMove(161, 159, { ctrlKey: true })
1276
+
1277
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 80, y: 80, props: { w: 80, h: 80 } })
1278
+ })
1279
+ it('works for dragging the bottom left corner', () => {
1280
+ // x ┌────────────────────┐
1281
+ // │ │ │
1282
+ // │ │ A │
1283
+ // │ │ │
1284
+ // x └────────────────────┘
1285
+ // │
1286
+ // │
1287
+ // │
1288
+ // ┌─────┐ │ ┌─────┐
1289
+ // │ │ │ │ │
1290
+ // │ │ x ┌────────────────┐ │ │
1291
+ // │ D │ │ │ │ │ B │
1292
+ // │ │ │ │ X │ │ │
1293
+ // │ │ │ │ │ │ │
1294
+ // │ │ │ │ │ │ │
1295
+ // │ │ │ │ │ │ │
1296
+ // │ │ │ │ │ │ │
1297
+ // │ │ │ │ │ │ │
1298
+ // │ │ │ │ │ │ │
1299
+ // └─────┘ │ O────────────────┘ └─────┘
1300
+ // x─────x───x──────────────────x─────────x─────x
1301
+ // │
1302
+ // x ┌────────────────────┐
1303
+ // │ │ │
1304
+ // │ │ C │
1305
+ // │ │ │
1306
+ // x └────────────────────┘
1307
+
1308
+ editor
1309
+ .select(ids.boxX)
1310
+ .pointerDown(80, 140, {
1311
+ target: 'selection',
1312
+ handle: 'bottom_left',
1313
+ })
1314
+ .pointerMove(59, 159, { ctrlKey: true })
1315
+
1316
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 60, y: 80, props: { w: 80, h: 80 } })
1317
+ })
1318
+ })
1319
+
1320
+ describe('snapping while resizing from center', () => {
1321
+ beforeEach(() => {
1322
+ // 0 20 40 60 80 100 120 140
1323
+ // 0 ┌───┐
1324
+ // │ A │
1325
+ // 20 └───┘
1326
+ //
1327
+ // 40 ┌─────────────┐
1328
+ // │ │
1329
+ // 60 ┌───┐ │ │ ┌───┐
1330
+ // │ D │ │ X │ │ B │
1331
+ // 80 └───┘ │ │ └───┘
1332
+ // │ │
1333
+ // 100 └─────────────┘
1334
+ //
1335
+ // 120 ┌───┐
1336
+ // │ C │
1337
+ // 140 └───┘
1338
+
1339
+ editor.createShapes([
1340
+ box(ids.boxA, 60, 0, 20, 20),
1341
+ box(ids.boxB, 120, 60, 20, 20),
1342
+ box(ids.boxC, 60, 120, 20, 20),
1343
+ box(ids.boxD, 0, 60, 20, 20),
1344
+ box(ids.boxX, 40, 40, 60, 60),
1345
+ ])
1346
+ })
1347
+ it('should work from the top', () => {
1348
+ editor
1349
+ .select(ids.boxX)
1350
+ .pointerDown(70, 40, {
1351
+ target: 'selection',
1352
+ handle: 'top',
1353
+ })
1354
+ .pointerMove(70, 21, { ctrlKey: true, altKey: true })
1355
+
1356
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1357
+ x: 40,
1358
+ y: 20,
1359
+ props: { w: 60, h: 100 },
1360
+ })
1361
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1362
+ Array [
1363
+ "40,120 60,120 80,120 100,120",
1364
+ "40,20 60,20 80,20 100,20",
1365
+ ]
1366
+ `)
1367
+ })
1368
+ it('should work from the right', () => {
1369
+ editor
1370
+ .select(ids.boxX)
1371
+ .pointerDown(100, 70, {
1372
+ target: 'selection',
1373
+ handle: 'right',
1374
+ })
1375
+ .pointerMove(121, 70, { ctrlKey: true, altKey: true })
1376
+
1377
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1378
+ x: 20,
1379
+ y: 40,
1380
+ props: { w: 100, h: 60 },
1381
+ })
1382
+ })
1383
+ it('should work from the bottom', () => {
1384
+ editor
1385
+ .select(ids.boxX)
1386
+ .pointerDown(70, 100, {
1387
+ target: 'selection',
1388
+ handle: 'bottom',
1389
+ })
1390
+ .pointerMove(70, 121, { ctrlKey: true, altKey: true })
1391
+
1392
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1393
+ x: 40,
1394
+ y: 20,
1395
+ props: { w: 60, h: 100 },
1396
+ })
1397
+ })
1398
+ it('should work from the left', () => {
1399
+ editor
1400
+ .select(ids.boxX)
1401
+ .pointerDown(40, 70, {
1402
+ target: 'selection',
1403
+ handle: 'left',
1404
+ })
1405
+ .pointerMove(21, 70, { ctrlKey: true, altKey: true })
1406
+
1407
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1408
+ x: 20,
1409
+ y: 40,
1410
+ props: { w: 100, h: 60 },
1411
+ })
1412
+ })
1413
+
1414
+ it('should work from the top right', () => {
1415
+ // 0 20 40 60 80 100 120 140
1416
+ // 0 ┌───┐
1417
+ // │ A │
1418
+ // 20 └───┘
1419
+ //
1420
+ // 40 x───────────────────────O
1421
+ // │ │
1422
+ // 60 ┌───x x───┐
1423
+ // │ D │ X │ B │
1424
+ // 80 └───x x───┘
1425
+ // │ │
1426
+ // 100 x───────────────────────x
1427
+ //
1428
+ // 120 ┌───┐
1429
+ // │ C │
1430
+ // 140 └───┘
1431
+ editor
1432
+ .select(ids.boxX)
1433
+ .pointerDown(100, 40, {
1434
+ target: 'selection',
1435
+ handle: 'top_right',
1436
+ })
1437
+ .pointerMove(123, 40, { ctrlKey: true, altKey: true })
1438
+
1439
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1440
+ x: 20,
1441
+ y: 40,
1442
+ props: { w: 100, h: 60 },
1443
+ })
1444
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1445
+ Array [
1446
+ "120,40 120,60 120,80 120,100",
1447
+ "20,40 20,60 20,80 20,100",
1448
+ ]
1449
+ `)
1450
+ // 0 20 40 60 80 100 120 140
1451
+ // 0 ┌───┐
1452
+ // │ A │
1453
+ // 20 x─────────x───x─────────O
1454
+ // │ │
1455
+ // 40 │ │
1456
+ // │ │
1457
+ // 60 ┌───x x───┐
1458
+ // │ D │ X │ B │
1459
+ // 80 └───x x───┘
1460
+ // │ │
1461
+ // 100 │ │
1462
+ // │ │
1463
+ // 120 x─────────x───x─────────x
1464
+ // │ C │
1465
+ // 140 └───┘
1466
+ editor.pointerMove(123, 18, { ctrlKey: true, altKey: true })
1467
+
1468
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1469
+ x: 20,
1470
+ y: 20,
1471
+ props: { w: 100, h: 100 },
1472
+ })
1473
+
1474
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1475
+ Array [
1476
+ "120,20 120,60 120,80 120,120",
1477
+ "20,120 60,120 80,120 120,120",
1478
+ "20,20 20,60 20,80 20,120",
1479
+ "20,20 60,20 80,20 120,20",
1480
+ ]
1481
+ `)
1482
+ })
1483
+ it('should work from the bottom right', () => {
1484
+ // 0 20 40 60 80 100 120 140
1485
+ // 0 ┌───┐
1486
+ // │ A │
1487
+ // 20 └───┘
1488
+ //
1489
+ // 40 x───────────────────────x
1490
+ // │ │
1491
+ // 60 ┌───x x───┐
1492
+ // │ D │ X │ B │
1493
+ // 80 └───x x───┘
1494
+ // │ │
1495
+ // 100 x───────────────────────O
1496
+ //
1497
+ // 120 ┌───┐
1498
+ // │ C │
1499
+ // 140 └───┘
1500
+ editor
1501
+ .select(ids.boxX)
1502
+ .pointerDown(100, 100, {
1503
+ target: 'selection',
1504
+ handle: 'bottom_right',
1505
+ })
1506
+ .pointerMove(123, 100, { ctrlKey: true, altKey: true })
1507
+
1508
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1509
+ x: 20,
1510
+ y: 40,
1511
+ props: { w: 100, h: 60 },
1512
+ })
1513
+
1514
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1515
+ Array [
1516
+ "120,40 120,60 120,80 120,100",
1517
+ "20,40 20,60 20,80 20,100",
1518
+ ]
1519
+ `)
1520
+
1521
+ // 0 20 40 60 80 100 120 140
1522
+ // 0 ┌───┐
1523
+ // │ A │
1524
+ // 20 x─────────x───x─────────x
1525
+ // │ │
1526
+ // 40 │ │
1527
+ // │ │
1528
+ // 60 ┌───x x───┐
1529
+ // │ D │ X │ B │
1530
+ // 80 └───x x───┘
1531
+ // │ │
1532
+ // 100 │ │
1533
+ // │ │
1534
+ // 120 x─────────x───x─────────O
1535
+ // │ C │
1536
+ // 140 └───┘
1537
+ editor.pointerMove(123, 118, { ctrlKey: true, altKey: true })
1538
+
1539
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1540
+ x: 20,
1541
+ y: 20,
1542
+ props: { w: 100, h: 100 },
1543
+ })
1544
+
1545
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1546
+ Array [
1547
+ "120,20 120,60 120,80 120,120",
1548
+ "20,120 60,120 80,120 120,120",
1549
+ "20,20 20,60 20,80 20,120",
1550
+ "20,20 60,20 80,20 120,20",
1551
+ ]
1552
+ `)
1553
+ })
1554
+ it('should work from the bottom left', () => {
1555
+ // 0 20 40 60 80 100 120 140
1556
+ // 0 ┌───┐
1557
+ // │ A │
1558
+ // 20 └───┘
1559
+ //
1560
+ // 40 x───────────────────────x
1561
+ // │ │
1562
+ // 60 ┌───x x───┐
1563
+ // │ D │ X │ B │
1564
+ // 80 └───x x───┘
1565
+ // │ │
1566
+ // 100 O───────────────────────x
1567
+ //
1568
+ // 120 ┌───┐
1569
+ // │ C │
1570
+ // 140 └───┘
1571
+ editor
1572
+ .select(ids.boxX)
1573
+ .pointerDown(40, 100, {
1574
+ target: 'selection',
1575
+ handle: 'bottom_left',
1576
+ })
1577
+ .pointerMove(23, 100, { ctrlKey: true, altKey: true })
1578
+
1579
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1580
+ x: 20,
1581
+ y: 40,
1582
+ props: { w: 100, h: 60 },
1583
+ })
1584
+
1585
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1586
+ Array [
1587
+ "120,40 120,60 120,80 120,100",
1588
+ "20,40 20,60 20,80 20,100",
1589
+ ]
1590
+ `)
1591
+
1592
+ // 0 20 40 60 80 100 120 140
1593
+ // 0 ┌───┐
1594
+ // │ A │
1595
+ // 20 x─────────x───x─────────x
1596
+ // │ │
1597
+ // 40 │ │
1598
+ // │ │
1599
+ // 60 ┌───x x───┐
1600
+ // │ D │ X │ B │
1601
+ // 80 └───x x───┘
1602
+ // │ │
1603
+ // 100 │ │
1604
+ // │ │
1605
+ // 120 O─────────x───x─────────x
1606
+ // │ C │
1607
+ // 140 └───┘
1608
+
1609
+ editor.pointerMove(23, 118, { ctrlKey: true, altKey: true })
1610
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1611
+ x: 20,
1612
+ y: 20,
1613
+ props: { w: 100, h: 100 },
1614
+ })
1615
+
1616
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1617
+ Array [
1618
+ "120,20 120,60 120,80 120,120",
1619
+ "20,120 60,120 80,120 120,120",
1620
+ "20,20 20,60 20,80 20,120",
1621
+ "20,20 60,20 80,20 120,20",
1622
+ ]
1623
+ `)
1624
+ })
1625
+ it('should work from the top left', () => {
1626
+ // 0 20 40 60 80 100 120 140
1627
+ // 0 ┌───┐
1628
+ // │ A │
1629
+ // 20 └───┘
1630
+ //
1631
+ // 40 O───────────────────────x
1632
+ // │ │
1633
+ // 60 ┌───x x───┐
1634
+ // │ D │ X │ B │
1635
+ // 80 └───x x───┘
1636
+ // │ │
1637
+ // 100 x───────────────────────x
1638
+ //
1639
+ // 120 ┌───┐
1640
+ // │ C │
1641
+ // 140 └───┘
1642
+ editor
1643
+ .select(ids.boxX)
1644
+ .pointerDown(40, 40, {
1645
+ target: 'selection',
1646
+ handle: 'top_left',
1647
+ })
1648
+ .pointerMove(23, 40, { ctrlKey: true, altKey: true })
1649
+
1650
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1651
+ x: 20,
1652
+ y: 40,
1653
+ props: { w: 100, h: 60 },
1654
+ })
1655
+
1656
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1657
+ Array [
1658
+ "120,40 120,60 120,80 120,100",
1659
+ "20,40 20,60 20,80 20,100",
1660
+ ]
1661
+ `)
1662
+
1663
+ // 0 20 40 60 80 100 120 140
1664
+ // 0 ┌───┐
1665
+ // │ A │
1666
+ // 20 O─────────x───x─────────x
1667
+ // │ │
1668
+ // 40 │ │
1669
+ // │ │
1670
+ // 60 ┌───x x───┐
1671
+ // │ D │ X │ B │
1672
+ // 80 └───x x───┘
1673
+ // │ │
1674
+ // 100 │ │
1675
+ // │ │
1676
+ // 120 x─────────x───x─────────x
1677
+ // │ C │
1678
+ // 140 └───┘
1679
+
1680
+ editor.pointerMove(23, 19, { ctrlKey: true, altKey: true })
1681
+ expect(editor.getShape(ids.boxX)).toMatchObject({
1682
+ x: 20,
1683
+ y: 20,
1684
+ props: { w: 100, h: 100 },
1685
+ })
1686
+
1687
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1688
+ Array [
1689
+ "120,20 120,60 120,80 120,120",
1690
+ "20,120 60,120 80,120 120,120",
1691
+ "20,20 20,60 20,80 20,120",
1692
+ "20,20 60,20 80,20 120,20",
1693
+ ]
1694
+ `)
1695
+ })
1696
+ })
1697
+
1698
+ describe('snapping while resizing with aspect ratio locked', () => {
1699
+ beforeEach(() => {
1700
+ // 0 20 40 60 80 100 120 140
1701
+ // 0 ┌───┐
1702
+ // │ A │
1703
+ // 20 └───┘
1704
+ //
1705
+ // 40 ┌─────────────┐
1706
+ // │ │
1707
+ // 60 ┌───┐ │ │ ┌───┐
1708
+ // │ D │ │ X │ │ B │
1709
+ // 80 └───┘ │ │ └───┘
1710
+ // │ │
1711
+ // 100 └─────────────┘
1712
+ //
1713
+ // 120 ┌───┐
1714
+ // │ C │
1715
+ // 140 └───┘
1716
+
1717
+ editor.createShapes([
1718
+ box(ids.boxA, 60, 0, 20, 20),
1719
+ box(ids.boxB, 120, 60, 20, 20),
1720
+ box(ids.boxC, 60, 120, 20, 20),
1721
+ box(ids.boxD, 0, 60, 20, 20),
1722
+ box(ids.boxX, 40, 40, 60, 60),
1723
+ ])
1724
+ })
1725
+ it('should work from the top', () => {
1726
+ // 0 20 40 60 80 100 120 140
1727
+ // 0 ┌───┐
1728
+ // │ A │
1729
+ // 20 x──────x─O─x──────x
1730
+ // │ │
1731
+ // 40 │ │
1732
+ // │ │
1733
+ // 60 ┌───┐ │ │ ┌───┐
1734
+ // │ D │ │ X │ │ B │
1735
+ // 80 └───┘ │ │ └───┘
1736
+ // │ │
1737
+ // 100 └─────────────────┘
1738
+ //
1739
+ // 120 ┌───┐
1740
+ // │ C │
1741
+ // 140 └───┘
1742
+ editor
1743
+ .select(ids.boxX)
1744
+ .pointerDown(70, 40, {
1745
+ target: 'selection',
1746
+ handle: 'top',
1747
+ })
1748
+ .pointerMove(70, 18, { ctrlKey: true, shiftKey: true })
1749
+
1750
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 30, y: 20, props: { w: 80, h: 80 } })
1751
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1752
+ Array [
1753
+ "30,20 60,20 80,20 110,20",
1754
+ ]
1755
+ `)
1756
+ })
1757
+
1758
+ it('should work from the right', () => {
1759
+ // 0 20 40 60 80 100 120 140
1760
+ // 0 ┌───┐
1761
+ // │ A │
1762
+ // 20 └───┘
1763
+ // ┌──────────────────x
1764
+ // 40 │ │
1765
+ // │ │
1766
+ // 60 ┌───┐ │ x───┐
1767
+ // │ D │ │ X O B │
1768
+ // 80 └───┘ │ x───┘
1769
+ // │ │
1770
+ // 100 │ │
1771
+ // └──────────────────x
1772
+ // 120 ┌───┐
1773
+ // │ C │
1774
+ // 140 └───┘
1775
+ editor
1776
+ .select(ids.boxX)
1777
+ .pointerDown(100, 70, {
1778
+ target: 'selection',
1779
+ handle: 'right',
1780
+ })
1781
+ .pointerMove(123, 79, { ctrlKey: true, shiftKey: true })
1782
+
1783
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 40, y: 30, props: { w: 80, h: 80 } })
1784
+
1785
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1786
+ Array [
1787
+ "120,30 120,60 120,80 120,110",
1788
+ ]
1789
+ `)
1790
+ })
1791
+
1792
+ it('should work from the bottom', () => {
1793
+ // 0 20 40 60 80 100 120 140
1794
+ // 0 ┌───┐
1795
+ // │ A │
1796
+ // 20 └───┘
1797
+ //
1798
+ // 40 ┌─────────────────┐
1799
+ // │ │
1800
+ // 60 ┌───┐ │ │ ┌───┐
1801
+ // │ D │ │ X │ │ B │
1802
+ // 80 └───┘ │ │ └───┘
1803
+ // │ │
1804
+ // 100 │ │
1805
+ // │ │
1806
+ // 120 x──────x─O─x──────x
1807
+ // │ C │
1808
+ // 140 └───┘
1809
+ editor
1810
+ .select(ids.boxX)
1811
+ .pointerDown(70, 100, {
1812
+ target: 'selection',
1813
+ handle: 'bottom',
1814
+ })
1815
+ .pointerMove(70, 123, { ctrlKey: true, shiftKey: true })
1816
+
1817
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 30, y: 40, props: { w: 80, h: 80 } })
1818
+
1819
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1820
+ Array [
1821
+ "30,120 60,120 80,120 110,120",
1822
+ ]
1823
+ `)
1824
+ })
1825
+ it('should work from the left', () => {
1826
+ // 0 20 40 60 80 100 120 140
1827
+ // 0 ┌───┐
1828
+ // │ A │
1829
+ // 20 └───┘
1830
+ // x──────────────────┐
1831
+ // 40 │ │
1832
+ // │ │
1833
+ // 60 ┌───x │ ┌───┐
1834
+ // │ D O X │ │ B │
1835
+ // 80 └───x │ └───┘
1836
+ // │ │
1837
+ // 100 │ │
1838
+ // x──────────────────┘
1839
+ // 120 ┌───┐
1840
+ // │ C │
1841
+ // 140 └───┘
1842
+
1843
+ editor
1844
+ .select(ids.boxX)
1845
+ .pointerDown(40, 70, {
1846
+ target: 'selection',
1847
+ handle: 'left',
1848
+ })
1849
+ .pointerMove(18, 70, { ctrlKey: true, shiftKey: true })
1850
+
1851
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 20, y: 30, props: { w: 80, h: 80 } })
1852
+
1853
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1854
+ Array [
1855
+ "20,30 20,60 20,80 20,110",
1856
+ ]
1857
+ `)
1858
+ })
1859
+ it('should work from the top right', () => {
1860
+ // 0 20 40 60 80 100 120 140
1861
+ // 0 ┌───┐
1862
+ // │ A │
1863
+ // 20 ┌────x───x────▲────x
1864
+ // │ │
1865
+ // 40 │ │
1866
+ // │ │
1867
+ // 60 ┌───┐ │ x───┐
1868
+ // │ D │ │ X │ B │
1869
+ // 80 └───┘ │ x───┘
1870
+ // │ │
1871
+ // 100 └──────────────────┘
1872
+ //
1873
+ // 120 ┌───┐
1874
+ // │ C │
1875
+ // 140 └───┘
1876
+ editor
1877
+ .select(ids.boxX)
1878
+ .pointerDown(100, 40, {
1879
+ target: 'selection',
1880
+ handle: 'top_right',
1881
+ })
1882
+ .pointerMove(100, 18, { ctrlKey: true, shiftKey: true })
1883
+
1884
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 40, y: 20, props: { w: 80, h: 80 } })
1885
+
1886
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1887
+ Array [
1888
+ "120,20 120,60 120,80 120,100",
1889
+ "40,20 60,20 80,20 120,20",
1890
+ ]
1891
+ `)
1892
+ })
1893
+ it('should work from the bottom right', () => {
1894
+ // 0 20 40 60 80 100 120 140
1895
+ // 0 ┌───┐
1896
+ // │ A │
1897
+ // 20 └───┘
1898
+ //
1899
+ // 40 ┌──────────────────┐
1900
+ // │ │
1901
+ // 60 ┌───┐ │ x───┐
1902
+ // │ D │ │ X │ B │
1903
+ // 80 └───┘ │ x───┘
1904
+ // │ │
1905
+ // 100 │ ─┤►
1906
+ // │ │
1907
+ // 120 └────x───x─────────x
1908
+ // │ C │
1909
+ // 140 └───┘
1910
+ editor
1911
+ .select(ids.boxX)
1912
+ .pointerDown(100, 100, {
1913
+ target: 'selection',
1914
+ handle: 'bottom_right',
1915
+ })
1916
+ .pointerMove(118, 100, { ctrlKey: true, shiftKey: true })
1917
+
1918
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 40, y: 40, props: { w: 80, h: 80 } })
1919
+
1920
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1921
+ Array [
1922
+ "120,40 120,60 120,80 120,120",
1923
+ "40,120 60,120 80,120 120,120",
1924
+ ]
1925
+ `)
1926
+ })
1927
+ it('should work from the bottom left', () => {
1928
+ // 0 20 40 60 80 100 120 140
1929
+ // 0 ┌───┐
1930
+ // │ A │
1931
+ // 20 └───┘
1932
+ //
1933
+ // 40 x──────────────────┐
1934
+ // │ │
1935
+ // 60 ┌───x │ ┌───┐
1936
+ // │ D │ X │ │ B │
1937
+ // 80 └───x │ └───┘
1938
+ // │ │
1939
+ // 100 ◄├─ │
1940
+ // │ │
1941
+ // 120 x─────────x───x────x
1942
+ // │ C │
1943
+ // 140 └───┘
1944
+ editor
1945
+ .select(ids.boxX)
1946
+ .pointerDown(40, 100, {
1947
+ target: 'selection',
1948
+ handle: 'bottom_left',
1949
+ })
1950
+ .pointerMove(18, 100, { ctrlKey: true, shiftKey: true })
1951
+
1952
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 20, y: 40, props: { w: 80, h: 80 } })
1953
+
1954
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1955
+ Array [
1956
+ "20,120 60,120 80,120 100,120",
1957
+ "20,40 20,60 20,80 20,120",
1958
+ ]
1959
+ `)
1960
+ })
1961
+ it('should work from the top left', () => {
1962
+ // 0 20 40 60 80 100 120 140
1963
+ // 0 ┌───┐
1964
+ // ▲ │ A │
1965
+ // 20 x────┬────x───x────x
1966
+ // │ │
1967
+ // 40 │ │
1968
+ // │ │
1969
+ // 60 ┌───x │ ┌───┐
1970
+ // │ D │ X │ │ B │
1971
+ // 80 └───x │ └───┘
1972
+ // │ │
1973
+ // 100 x──────────────────┘
1974
+ //
1975
+ // 120 ┌───┐
1976
+ // │ C │
1977
+ // 140 └───┘
1978
+ editor
1979
+ .select(ids.boxX)
1980
+ .pointerDown(40, 40, {
1981
+ target: 'selection',
1982
+ handle: 'top_left',
1983
+ })
1984
+ .pointerMove(40, 18, { ctrlKey: true, shiftKey: true })
1985
+
1986
+ expect(editor.getShape(ids.boxX)).toMatchObject({ x: 20, y: 20, props: { w: 80, h: 80 } })
1987
+
1988
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
1989
+ Array [
1990
+ "20,20 20,60 20,80 20,100",
1991
+ "20,20 60,20 80,20 100,20",
1992
+ ]
1993
+ `)
1994
+ })
1995
+ })
1996
+
1997
+ describe('snapping while resizing from center with aspect ratio locked', () => {
1998
+ beforeEach(() => {
1999
+ // 0 20 40 60 80 100 120 140
2000
+ // 0 ┌───┐
2001
+ // │ A │
2002
+ // 20 └───┘
2003
+ //
2004
+ // 40 ┌─────────────┐
2005
+ // │ │
2006
+ // 60 ┌───┐ │ │ ┌───┐
2007
+ // │ D │ │ X │ │ B │
2008
+ // 80 └───┘ │ │ └───┘
2009
+ // │ │
2010
+ // 100 └─────────────┘
2011
+ //
2012
+ // 120 ┌───┐
2013
+ // │ C │
2014
+ // 140 └───┘
2015
+
2016
+ editor.createShapes([
2017
+ box(ids.boxA, 60, 0, 20, 20),
2018
+ box(ids.boxB, 120, 60, 20, 20),
2019
+ box(ids.boxC, 60, 120, 20, 20),
2020
+ box(ids.boxD, 0, 60, 20, 20),
2021
+ box(ids.boxX, 40, 40, 60, 60),
2022
+ ])
2023
+ })
2024
+ const expectedSnapLines = [
2025
+ '120,20 120,60 120,80 120,120',
2026
+ '20,120 60,120 80,120 120,120',
2027
+ '20,20 20,60 20,80 20,120',
2028
+ '20,20 60,20 80,20 120,20',
2029
+ ] as const
2030
+ it('should work from the top', () => {
2031
+ // 0 20 40 60 80 100 120 140
2032
+ // 0 ┌───┐
2033
+ // │ A │
2034
+ // 20 x─────────x─O─x─────────x
2035
+ // │ │
2036
+ // 40 │ │
2037
+ // │ │
2038
+ // 60 ┌───x x───┐
2039
+ // │ D │ X │ B │
2040
+ // 80 └───x x───┘
2041
+ // │ │
2042
+ // 100 │ │
2043
+ // │ │
2044
+ // 120 x─────────x───x─────────x
2045
+ // │ C │
2046
+ // 140 └───┘
2047
+
2048
+ editor
2049
+ .select(ids.boxX)
2050
+ .pointerDown(70, 40, {
2051
+ target: 'selection',
2052
+ handle: 'top',
2053
+ })
2054
+ .pointerMove(70, 18, { ctrlKey: true, shiftKey: true, altKey: true })
2055
+
2056
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2057
+ x: 20,
2058
+ y: 20,
2059
+ props: { w: 100, h: 100 },
2060
+ })
2061
+
2062
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2063
+ })
2064
+ it('should work from the right', () => {
2065
+ // 0 20 40 60 80 100 120 140
2066
+ // 0 ┌───┐
2067
+ // │ A │
2068
+ // 20 x─────────x───x─────────x
2069
+ // │ │
2070
+ // 40 │ │
2071
+ // │ │
2072
+ // 60 ┌───x x───┐
2073
+ // │ D │ X O B │
2074
+ // 80 └───x x───┘
2075
+ // │ │
2076
+ // 100 │ │
2077
+ // │ │
2078
+ // 120 x─────────x───x─────────x
2079
+ // │ C │
2080
+ // 140 └───┘
2081
+ editor
2082
+ .select(ids.boxX)
2083
+ .pointerDown(100, 70, {
2084
+ target: 'selection',
2085
+ handle: 'right',
2086
+ })
2087
+ .pointerMove(123, 40, { ctrlKey: true, shiftKey: true, altKey: true })
2088
+
2089
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2090
+ x: 20,
2091
+ y: 20,
2092
+ props: { w: 100, h: 100 },
2093
+ })
2094
+
2095
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2096
+ })
2097
+ it('should work from the bottom', () => {
2098
+ // 0 20 40 60 80 100 120 140
2099
+ // 0 ┌───┐
2100
+ // │ A │
2101
+ // 20 x─────────x───x─────────x
2102
+ // │ │
2103
+ // 40 │ │
2104
+ // │ │
2105
+ // 60 ┌───x x───┐
2106
+ // │ D │ X │ B │
2107
+ // 80 └───x x───┘
2108
+ // │ │
2109
+ // 100 │ │
2110
+ // │ │
2111
+ // 120 x─────────x─O─x─────────x
2112
+ // │ C │
2113
+ // 140 └───┘
2114
+ editor
2115
+ .select(ids.boxX)
2116
+ .pointerDown(70, 100, {
2117
+ target: 'selection',
2118
+ handle: 'bottom',
2119
+ })
2120
+ .pointerMove(70, 121, { ctrlKey: true, shiftKey: true, altKey: true })
2121
+
2122
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2123
+ x: 20,
2124
+ y: 20,
2125
+ props: { w: 100, h: 100 },
2126
+ })
2127
+
2128
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2129
+ })
2130
+ it('should work from the left', () => {
2131
+ // 0 20 40 60 80 100 120 140
2132
+ // 0 ┌───┐
2133
+ // │ A │
2134
+ // 20 x─────────x───x─────────x
2135
+ // │ │
2136
+ // 40 │ │
2137
+ // │ │
2138
+ // 60 ┌───x x───┐
2139
+ // │ D O X │ B │
2140
+ // 80 └───x x───┘
2141
+ // │ │
2142
+ // 100 │ │
2143
+ // │ │
2144
+ // 120 x─────────x───x─────────x
2145
+ // │ C │
2146
+ // 140 └───┘
2147
+ editor
2148
+ .select(ids.boxX)
2149
+ .pointerDown(40, 70, {
2150
+ target: 'selection',
2151
+ handle: 'left',
2152
+ })
2153
+ .pointerMove(18, 87, { ctrlKey: true, shiftKey: true, altKey: true })
2154
+
2155
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2156
+ x: 20,
2157
+ y: 20,
2158
+ props: { w: 100, h: 100 },
2159
+ })
2160
+
2161
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2162
+ })
2163
+
2164
+ it('should work from the top right', () => {
2165
+ // 0 20 40 60 80 100 120 140
2166
+ // 0 ┌───┐
2167
+ // │ A │
2168
+ // 20 x─────────x───x─────────O
2169
+ // │ │
2170
+ // 40 │ │
2171
+ // │ │
2172
+ // 60 ┌───x x───┐
2173
+ // │ D │ X │ B │
2174
+ // 80 └───x x───┘
2175
+ // │ │
2176
+ // 100 │ │
2177
+ // │ │
2178
+ // 120 x─────────x───x─────────x
2179
+ // │ C │
2180
+ // 140 └───┘
2181
+
2182
+ editor
2183
+ .select(ids.boxX)
2184
+ .pointerDown(100, 40, {
2185
+ target: 'selection',
2186
+ handle: 'top_right',
2187
+ })
2188
+ .pointerMove(100, 18, { ctrlKey: true, shiftKey: true, altKey: true })
2189
+
2190
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2191
+ x: 20,
2192
+ y: 20,
2193
+ props: { w: 100, h: 100 },
2194
+ })
2195
+
2196
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2197
+ })
2198
+ it('should work from the bottom right', () => {
2199
+ // 0 20 40 60 80 100 120 140
2200
+ // 0 ┌───┐
2201
+ // │ A │
2202
+ // 20 x─────────x───x─────────x
2203
+ // │ │
2204
+ // 40 │ │
2205
+ // │ │
2206
+ // 60 ┌───x x───┐
2207
+ // │ D │ X │ B │
2208
+ // 80 └───x x───┘
2209
+ // │ │
2210
+ // 100 │ │
2211
+ // │ │
2212
+ // 120 x─────────x───x─────────O
2213
+ // │ C │
2214
+ // 140 └───┘
2215
+ editor
2216
+ .select(ids.boxX)
2217
+ .pointerDown(100, 100, {
2218
+ target: 'selection',
2219
+ handle: 'bottom_right',
2220
+ })
2221
+ .pointerMove(123, 118, { ctrlKey: true, shiftKey: true, altKey: true })
2222
+
2223
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2224
+ x: 20,
2225
+ y: 20,
2226
+ props: { w: 100, h: 100 },
2227
+ })
2228
+
2229
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2230
+ })
2231
+ it('should work from the bottom left', () => {
2232
+ // 0 20 40 60 80 100 120 140
2233
+ // 0 ┌───┐
2234
+ // │ A │
2235
+ // 20 x─────────x───x─────────x
2236
+ // │ │
2237
+ // 40 │ │
2238
+ // │ │
2239
+ // 60 ┌───x x───┐
2240
+ // │ D │ X │ B │
2241
+ // 80 └───x x───┘
2242
+ // │ │
2243
+ // 100 │ │
2244
+ // │ │
2245
+ // 120 O─────────x───x─────────x
2246
+ // │ C │
2247
+ // 140 └───┘
2248
+ editor
2249
+ .select(ids.boxX)
2250
+ .pointerDown(40, 100, {
2251
+ target: 'selection',
2252
+ handle: 'bottom_left',
2253
+ })
2254
+ .pointerMove(18, 125, { ctrlKey: true, shiftKey: true, altKey: true })
2255
+
2256
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2257
+ x: 20,
2258
+ y: 20,
2259
+ props: { w: 100, h: 100 },
2260
+ })
2261
+
2262
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2263
+ })
2264
+ it('should work from the top left', () => {
2265
+ // 0 20 40 60 80 100 120 140
2266
+ // 0 ┌───┐
2267
+ // │ A │
2268
+ // 20 O─────────x───x─────────x
2269
+ // │ │
2270
+ // 40 │ │
2271
+ // │ │
2272
+ // 60 ┌───x x───┐
2273
+ // │ D │ X │ B │
2274
+ // 80 └───x x───┘
2275
+ // │ │
2276
+ // 100 │ │
2277
+ // │ │
2278
+ // 120 x─────────x───x─────────x
2279
+ // │ C │
2280
+ // 140 └───┘
2281
+ editor
2282
+ .select(ids.boxX)
2283
+ .pointerDown(40, 40, {
2284
+ target: 'selection',
2285
+ handle: 'top_left',
2286
+ })
2287
+ .pointerMove(23, 18, { ctrlKey: true, shiftKey: true, altKey: true })
2288
+
2289
+ expect(editor.getShape(ids.boxX)).toMatchObject({
2290
+ x: 20,
2291
+ y: 20,
2292
+ props: { w: 100, h: 100 },
2293
+ })
2294
+
2295
+ expect(getSnapLines(editor)).toEqual(expectedSnapLines)
2296
+ })
2297
+ })
2298
+
2299
+ describe('snapping while resizing a shape that has been rotated by multiples of 90 deg', () => {
2300
+ beforeEach(() => {
2301
+ // 0 20 40 60 80 100 120 140
2302
+ // 0 ┌───┐
2303
+ // │ A │
2304
+ // 20 └───┘
2305
+ //
2306
+ // 40 ┌─────────────┐
2307
+ // │ │
2308
+ // 60 ┌───┐ │ │ ┌───┐
2309
+ // │ D │ │ X │ │ B │
2310
+ // 80 └───┘ │ │ └───┘
2311
+ // │ │
2312
+ // 100 └─────────────┘
2313
+ //
2314
+ // 120 ┌───┐
2315
+ // │ C │
2316
+ // 140 └───┘
2317
+
2318
+ editor.createShapes([
2319
+ box(ids.boxA, 60, 0, 20, 20),
2320
+ box(ids.boxB, 120, 60, 20, 20),
2321
+ box(ids.boxC, 60, 120, 20, 20),
2322
+ box(ids.boxD, 0, 60, 20, 20),
2323
+ box(ids.boxX, 40, 40, 60, 60),
2324
+ ])
2325
+ })
2326
+
2327
+ function rotateX(times: number) {
2328
+ editor.select(ids.boxX)
2329
+ for (let i = 0; i < times; i++) {
2330
+ editor
2331
+ .pointerDown(40, 40, { target: 'selection', handle: 'top_left_rotate' })
2332
+ .pointerMove(100, 40, { shiftKey: true })
2333
+ .pointerUp(100, 40, { shiftKey: true })
2334
+ }
2335
+
2336
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(40)
2337
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(40)
2338
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(60)
2339
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(60)
2340
+ expect(editor.getShape(ids.boxX)!.rotation).toEqual(
2341
+ canonicalizeRotation(((PI / 2) * times) % (PI * 2))
2342
+ )
2343
+ }
2344
+
2345
+ it('should work for 90deg', () => {
2346
+ rotateX(1)
2347
+ // 0 20 40 60 80 100 120 140
2348
+ // 0 ┌───┐
2349
+ // │ A │
2350
+ // 20 └───┘
2351
+ //
2352
+ // 40 ┌──────────────────x
2353
+ // │ │
2354
+ // 60 ┌───┐ │ x───┐
2355
+ // │ D │ │ X O B │
2356
+ // 80 └───┘ │ x───┘
2357
+ // │ │
2358
+ // 100 └──────────────────x
2359
+ //
2360
+ // 120 ┌───┐
2361
+ // │ C │
2362
+ // 140 └───┘
2363
+ editor
2364
+ .select(ids.boxX)
2365
+ .pointerDown(100, 70, { target: 'selection', handle: 'top' })
2366
+ .pointerMove(121, 70, { ctrlKey: true, shiftKey: false })
2367
+ jest.advanceTimersByTime(200)
2368
+
2369
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2370
+ x: 40,
2371
+ y: 40,
2372
+ w: 80,
2373
+ h: 60,
2374
+ })
2375
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2376
+ Array [
2377
+ "120,40 120,60 120,80 120,100",
2378
+ ]
2379
+ `)
2380
+
2381
+ // 0 20 40 60 80 100 120 140
2382
+ // 0 ┌───┐
2383
+ // │ A │
2384
+ // 20 └───┘
2385
+ //
2386
+ // 40 x───────────────────────x
2387
+ // │ │
2388
+ // 60 ┌───x x───┐
2389
+ // │ D │ X O B │
2390
+ // 80 └───x x───┘
2391
+ // │ │
2392
+ // 100 x───────────────────────x
2393
+ //
2394
+ // 120 ┌───┐
2395
+ // │ C │
2396
+ // 140 └───┘
2397
+ editor.keyDown('Alt', { altKey: true, ctrlKey: true })
2398
+
2399
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2400
+ x: 20,
2401
+ y: 40,
2402
+ w: 100,
2403
+ h: 60,
2404
+ })
2405
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2406
+ Array [
2407
+ "120,40 120,60 120,80 120,100",
2408
+ "20,40 20,60 20,80 20,100",
2409
+ ]
2410
+ `)
2411
+ })
2412
+ it('should work for 180', () => {
2413
+ rotateX(2)
2414
+
2415
+ // 0 20 40 60 80 100 120 140
2416
+ // 0 ┌───┐
2417
+ // │ A │
2418
+ // 20 x────x─O─x────x
2419
+ // │ │
2420
+ // 40 │ │
2421
+ // │ │
2422
+ // 60 ┌───┐ │ │ ┌───┐
2423
+ // │ D │ │ X │ │ B │
2424
+ // 80 └───┘ │ │ └───┘
2425
+ // │ │
2426
+ // 100 └─────────────┘
2427
+ //
2428
+ // 120 ┌───┐
2429
+ // │ C │
2430
+ // 140 └───┘
2431
+ editor
2432
+ .select(ids.boxX)
2433
+ .pointerDown(70, 40, { target: 'selection', handle: 'bottom' })
2434
+ .pointerMove(70, 18, { ctrlKey: true, shiftKey: false })
2435
+ jest.advanceTimersByTime(200)
2436
+
2437
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(40)
2438
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(20)
2439
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(60)
2440
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(80)
2441
+
2442
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2443
+ Array [
2444
+ "40,20 60,20 80,20 100,20",
2445
+ ]
2446
+ `)
2447
+
2448
+ // 0 20 40 60 80 100 120 140
2449
+ // 0 ┌───┐
2450
+ // │ A │
2451
+ // 20 x──────x─O─x──────x
2452
+ // │ │
2453
+ // 40 │ │
2454
+ // │ │
2455
+ // 60 ┌───┐ │ │ ┌───┐
2456
+ // │ D │ │ X │ │ B │
2457
+ // 80 └───┘ │ │ └───┘
2458
+ // │ │
2459
+ // 100 └─────────────────┘
2460
+ //
2461
+ // 120 ┌───┐
2462
+ // │ C │
2463
+ // 140 └───┘
2464
+ editor.keyDown('Shift', { ctrlKey: true })
2465
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(30)
2466
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(20)
2467
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(80)
2468
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(80)
2469
+
2470
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2471
+ Array [
2472
+ "30,20 60,20 80,20 110,20",
2473
+ ]
2474
+ `)
2475
+ })
2476
+ it('should work for 270deg', () => {
2477
+ rotateX(3)
2478
+ // 0 20 40 60 80 100 120 140
2479
+ // 0 ┌───┐
2480
+ // │ A │
2481
+ // 20 └───┘
2482
+ //
2483
+ // 40 x──────────────────┐
2484
+ // │ │
2485
+ // 60 ┌───x │ ┌───┐
2486
+ // │ D │ X │ │ B │
2487
+ // 80 └───x │ └───┘
2488
+ // │ │
2489
+ // 100 │ │
2490
+ // │ │
2491
+ // 120 O─────────x───x────x
2492
+ // │ C │
2493
+ // 140 └───┘
2494
+
2495
+ editor
2496
+ .select(ids.boxX)
2497
+ .pointerDown(40, 100, { target: 'selection', handle: 'top_left' })
2498
+ .pointerMove(18, 118, { ctrlKey: true, shiftKey: false })
2499
+
2500
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(20)
2501
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(40)
2502
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(80)
2503
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(80)
2504
+
2505
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2506
+ Array [
2507
+ "20,120 60,120 80,120 100,120",
2508
+ "20,40 20,60 20,80 20,120",
2509
+ ]
2510
+ `)
2511
+
2512
+ // 0 20 40 60 80 100 120 140
2513
+ // 0 ┌───┐
2514
+ // │ A │
2515
+ // 20 x─────────x───x─────────x
2516
+ // │ │
2517
+ // 40 │ │
2518
+ // │ │
2519
+ // 60 ┌───x x───┐
2520
+ // │ D │ X │ B │
2521
+ // 80 └───x x───┘
2522
+ // │ │
2523
+ // 100 │ │
2524
+ // │ │
2525
+ // 120 O─────────x───x─────────x
2526
+ // │ C │
2527
+ // 140 └───┘
2528
+
2529
+ editor.keyDown('Alt', { ctrlKey: true })
2530
+
2531
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(20)
2532
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(20)
2533
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(100)
2534
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(100)
2535
+
2536
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2537
+ Array [
2538
+ "120,20 120,60 120,80 120,120",
2539
+ "20,120 60,120 80,120 120,120",
2540
+ "20,20 20,60 20,80 20,120",
2541
+ "20,20 60,20 80,20 120,20",
2542
+ ]
2543
+ `)
2544
+ })
2545
+ it('should work for 360deg', () => {
2546
+ rotateX(4)
2547
+ // 0 20 40 60 80 100 120 140
2548
+ // 0 ┌───┐
2549
+ // │ A │
2550
+ // 20 └───┘
2551
+ //
2552
+ // 40 ┌──────────────────x
2553
+ // │ │
2554
+ // 60 ┌───┐ │ x───┐
2555
+ // │ D │ │ X O B │
2556
+ // 80 └───┘ │ x───┘
2557
+ // │ │
2558
+ // 100 └──────────────────x
2559
+ //
2560
+ // 120 ┌───┐
2561
+ // │ C │
2562
+ // 140 └───┘
2563
+ editor
2564
+ .select(ids.boxX)
2565
+ .pointerDown(100, 70, { target: 'selection', handle: 'right' })
2566
+ .pointerMove(121, 70, { ctrlKey: true, shiftKey: false })
2567
+ jest.advanceTimersByTime(200)
2568
+
2569
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(40)
2570
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(40)
2571
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(80)
2572
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(60)
2573
+
2574
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2575
+ Array [
2576
+ "120,40 120,60 120,80 120,100",
2577
+ ]
2578
+ `)
2579
+
2580
+ // 0 20 40 60 80 100 120 140
2581
+ // 0 ┌───┐
2582
+ // │ A │
2583
+ // 20 └───┘
2584
+ //
2585
+ // 40 x───────────────────────x
2586
+ // │ │
2587
+ // 60 ┌───x x───┐
2588
+ // │ D │ X O B │
2589
+ // 80 └───x x───┘
2590
+ // │ │
2591
+ // 100 x───────────────────────x
2592
+ //
2593
+ // 120 ┌───┐
2594
+ // │ C │
2595
+ // 140 └───┘
2596
+ editor.keyDown('Alt', { ctrlKey: true })
2597
+
2598
+ expect(editor.getShapePageBounds(ids.boxX)!.x).toBeCloseTo(20)
2599
+ expect(editor.getShapePageBounds(ids.boxX)!.y).toBeCloseTo(40)
2600
+ expect(editor.getShapePageBounds(ids.boxX)!.w).toBeCloseTo(100)
2601
+ expect(editor.getShapePageBounds(ids.boxX)!.h).toBeCloseTo(60)
2602
+
2603
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2604
+ Array [
2605
+ "120,40 120,60 120,80 120,100",
2606
+ "20,40 20,60 20,80 20,100",
2607
+ ]
2608
+ `)
2609
+ })
2610
+ })
2611
+
2612
+ describe('snapping while resizing an inverted shape', () => {
2613
+ beforeEach(() => {
2614
+ // 0 20 40 60 80 100 120 140
2615
+ // 0 ┌───┐
2616
+ // │ A │
2617
+ // 20 └───┘
2618
+ //
2619
+ // 40 ┌─────────────┐
2620
+ // │ │
2621
+ // 60 ┌───┐ │ │ ┌───┐
2622
+ // │ D │ │ X │ │ B │
2623
+ // 80 └───┘ │ │ └───┘
2624
+ // │ │
2625
+ // 100 └─────────────┘
2626
+ //
2627
+ // 120 ┌───┐
2628
+ // │ C │
2629
+ // 140 └───┘
2630
+
2631
+ editor.createShapes([
2632
+ box(ids.boxA, 60, 0, 20, 20),
2633
+ box(ids.boxB, 120, 60, 20, 20),
2634
+ box(ids.boxC, 60, 120, 20, 20),
2635
+ box(ids.boxD, 0, 60, 20, 20),
2636
+ box(ids.boxX, 40, 40, 60, 60),
2637
+ ])
2638
+ })
2639
+ it('should work for the top edge', () => {
2640
+ // 0 20 40 60 80 100 120 140
2641
+ // 0 ┌───┐
2642
+ // │ A │
2643
+ // 20 └───┘
2644
+ //
2645
+ // 40
2646
+ //
2647
+ // 60 ┌───┐ ┌───┐
2648
+ // │ D │ X │ B │
2649
+ // 80 └───┘ └───┘
2650
+ //
2651
+ // 100 ┌─────────────┐
2652
+ // │ │
2653
+ // 120 x────x─O─x────x
2654
+ // │ C │
2655
+ // 140 └───┘
2656
+ editor
2657
+ .select(ids.boxX)
2658
+ .pointerDown(70, 40, {
2659
+ target: 'selection',
2660
+ handle: 'top',
2661
+ })
2662
+ .pointerMove(70, 123, { ctrlKey: true })
2663
+
2664
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2665
+ x: 40,
2666
+ y: 100,
2667
+ w: 60,
2668
+ h: 20,
2669
+ })
2670
+
2671
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2672
+ Array [
2673
+ "40,120 60,120 80,120 100,120",
2674
+ ]
2675
+ `)
2676
+ })
2677
+
2678
+ it('should work for the right edge', () => {
2679
+ // 0 20 40 60 80 100 120 140
2680
+ // 0 ┌───┐
2681
+ // │ A │
2682
+ // 20 └───┘
2683
+ //
2684
+ // 40 x────┐
2685
+ // │ │
2686
+ // 60 ┌───x │ ┌───┐
2687
+ // │ D O │ X │ B │
2688
+ // 80 └───x │ └───┘
2689
+ // │ │
2690
+ // 100 x────┘
2691
+ //
2692
+ // 120 ┌───┐
2693
+ // │ C │
2694
+ // 140 └───┘
2695
+ editor
2696
+ .select(ids.boxX)
2697
+ .pointerDown(100, 70, {
2698
+ target: 'selection',
2699
+ handle: 'right',
2700
+ })
2701
+ .pointerMove(18, 70, { ctrlKey: true })
2702
+
2703
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2704
+ x: 20,
2705
+ y: 40,
2706
+ w: 20,
2707
+ h: 60,
2708
+ })
2709
+
2710
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2711
+ Array [
2712
+ "20,40 20,60 20,80 20,100",
2713
+ ]
2714
+ `)
2715
+ })
2716
+
2717
+ it('should work for the bottom edge', () => {
2718
+ // 0 20 40 60 80 100 120 140
2719
+ // 0 ┌───┐
2720
+ // │ A │
2721
+ // 20 x────x─O─x────x
2722
+ // │ │
2723
+ // 40 └─────────────┘
2724
+ //
2725
+ // 60 ┌───┐ ┌───┐
2726
+ // │ D │ X │ B │
2727
+ // 80 └───┘ └───┘
2728
+ //
2729
+ // 100
2730
+ //
2731
+ // 120 ┌───┐
2732
+ // │ C │
2733
+ // 140 └───┘
2734
+ editor
2735
+ .select(ids.boxX)
2736
+ .pointerDown(70, 100, {
2737
+ target: 'selection',
2738
+ handle: 'bottom',
2739
+ })
2740
+ .pointerMove(70, 23, { ctrlKey: true })
2741
+
2742
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2743
+ x: 40,
2744
+ y: 20,
2745
+ w: 60,
2746
+ h: 20,
2747
+ })
2748
+
2749
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2750
+ Array [
2751
+ "40,20 60,20 80,20 100,20",
2752
+ ]
2753
+ `)
2754
+ })
2755
+
2756
+ it('should work for the left edge', () => {
2757
+ // 0 20 40 60 80 100 120 140
2758
+ // 0 ┌───┐
2759
+ // │ A │
2760
+ // 20 └───┘
2761
+ //
2762
+ // 40 ┌────x
2763
+ // │ │
2764
+ // 60 ┌───┐ │ x───┐
2765
+ // │ D │ X │ O B │
2766
+ // 80 └───┘ │ x───┘
2767
+ // │ │
2768
+ // 100 └────x
2769
+ //
2770
+ // 120 ┌───┐
2771
+ // │ C │
2772
+ // 140 └───┘
2773
+ editor
2774
+ .select(ids.boxX)
2775
+ .pointerDown(40, 70, {
2776
+ target: 'selection',
2777
+ handle: 'left',
2778
+ })
2779
+ .pointerMove(122, 70, { ctrlKey: true })
2780
+
2781
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2782
+ x: 100,
2783
+ y: 40,
2784
+ w: 20,
2785
+ h: 60,
2786
+ })
2787
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2788
+ Array [
2789
+ "120,40 120,60 120,80 120,100",
2790
+ ]
2791
+ `)
2792
+ })
2793
+
2794
+ it('should work for the top right corner', () => {
2795
+ // 0 20 40 60 80 100 120 140
2796
+ // 0 ┌───┐
2797
+ // │ A │
2798
+ // 20 └───┘
2799
+ //
2800
+ // 40
2801
+ //
2802
+ // 60 ┌───x ┌───┐
2803
+ // │ D │ X │ B │
2804
+ // 80 └───x └───┘
2805
+ //
2806
+ // 100 x────┐
2807
+ // │ │
2808
+ // 120 O────x x───x
2809
+ // │ C │
2810
+ // 140 └───┘
2811
+ editor
2812
+ .select(ids.boxX)
2813
+ .pointerDown(100, 40, {
2814
+ target: 'selection',
2815
+ handle: 'top_right',
2816
+ })
2817
+ .pointerMove(19, 121, { ctrlKey: true })
2818
+
2819
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2820
+ x: 20,
2821
+ y: 100,
2822
+ w: 20,
2823
+ h: 20,
2824
+ })
2825
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2826
+ Array [
2827
+ "20,120 40,120 60,120 80,120",
2828
+ "20,60 20,80 20,100 20,120",
2829
+ ]
2830
+ `)
2831
+ })
2832
+
2833
+ it('should work for the bottom right corner', () => {
2834
+ // 0 20 40 60 80 100 120 140
2835
+ // 0 ┌───┐
2836
+ // │ A │
2837
+ // 20 O────x x───x
2838
+ // │ │
2839
+ // 40 x────┘
2840
+ //
2841
+ // 60 ┌───x ┌───┐
2842
+ // │ D │ X │ B │
2843
+ // 80 └───x └───┘
2844
+ //
2845
+ // 100
2846
+ //
2847
+ // 120 ┌───┐
2848
+ // │ C │
2849
+ // 140 └───┘
2850
+
2851
+ editor
2852
+ .select(ids.boxX)
2853
+ .pointerDown(100, 100, {
2854
+ target: 'selection',
2855
+ handle: 'bottom_right',
2856
+ })
2857
+ .pointerMove(19, 21, { ctrlKey: true })
2858
+
2859
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2860
+ x: 20,
2861
+ y: 20,
2862
+ w: 20,
2863
+ h: 20,
2864
+ })
2865
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2866
+ Array [
2867
+ "20,20 20,40 20,60 20,80",
2868
+ "20,20 40,20 60,20 80,20",
2869
+ ]
2870
+ `)
2871
+ })
2872
+ it('should work for the bototm left corner', () => {
2873
+ // 0 20 40 60 80 100 120 140
2874
+ // 0 ┌───┐
2875
+ // │ A │
2876
+ // 20 x───x x────O
2877
+ // │ │
2878
+ // 40 └────x
2879
+ //
2880
+ // 60 ┌───┐ x───┐
2881
+ // │ D │ │ B │
2882
+ // 80 └───┘ x───┘
2883
+ //
2884
+ // 100
2885
+ //
2886
+ // 120 ┌───┐
2887
+ // │ C │
2888
+ // 140 └───┘
2889
+ editor
2890
+ .select(ids.boxX)
2891
+ .pointerDown(40, 100, {
2892
+ target: 'selection',
2893
+ handle: 'bottom_left',
2894
+ })
2895
+ .pointerMove(123, 21, { ctrlKey: true })
2896
+
2897
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2898
+ x: 100,
2899
+ y: 20,
2900
+ w: 20,
2901
+ h: 20,
2902
+ })
2903
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2904
+ Array [
2905
+ "120,20 120,40 120,60 120,80",
2906
+ "60,20 80,20 100,20 120,20",
2907
+ ]
2908
+ `)
2909
+ })
2910
+ it('should work for the top left corner', () => {
2911
+ // 0 20 40 60 80 100 120 140
2912
+ // 0 ┌───┐
2913
+ // │ A │
2914
+ // 20 └───┘
2915
+ //
2916
+ // 40
2917
+ //
2918
+ // 60 ┌───┐ x───┐
2919
+ // │ D │ │ B │
2920
+ // 80 └───┘ x───┘
2921
+ //
2922
+ // 100 ┌────x
2923
+ // │ │
2924
+ // 120 x───x x────O
2925
+ // │ C │
2926
+ // 140 └───┘
2927
+ editor
2928
+ .select(ids.boxX)
2929
+ .pointerDown(40, 40, {
2930
+ target: 'selection',
2931
+ handle: 'top_left',
2932
+ })
2933
+ .pointerMove(123, 118, { ctrlKey: true })
2934
+
2935
+ expect(editor.getShapePageBounds(ids.boxX)!).toMatchObject({
2936
+ x: 100,
2937
+ y: 100,
2938
+ w: 20,
2939
+ h: 20,
2940
+ })
2941
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2942
+ Array [
2943
+ "120,60 120,80 120,100 120,120",
2944
+ "60,120 80,120 100,120 120,120",
2945
+ ]
2946
+ `)
2947
+ })
2948
+ })
2949
+
2950
+ describe('snapping while the grid is enabled', () => {
2951
+ it('does not snap to the grid', () => {
2952
+ // 0 20 60 80
2953
+ // ┌───┐ ┌───┐
2954
+ // │ A │ │ B │
2955
+ // └───┘ └───┘
2956
+
2957
+ editor.createShapes([box(ids.boxA, 0, 0, 20, 20), box(ids.boxB, 60, 0, 20, 20)])
2958
+
2959
+ editor.updateInstanceState({ isGridMode: true })
2960
+
2961
+ // try to move right side of A to left side of B
2962
+ // doesn't work because of the grid
2963
+
2964
+ // 0 20 60 80
2965
+ // ┌──────────┐┌───┐
2966
+ // │ A O│ B │
2967
+ // └──────────┘└───┘
2968
+
2969
+ editor
2970
+ .select(ids.boxA)
2971
+ .pointerDown(20, 10, {
2972
+ target: 'selection',
2973
+ handle: 'right',
2974
+ })
2975
+ .pointerMove(59, 10)
2976
+
2977
+ // rounds up to nearest 10
2978
+ expect(editor.getShapePageBounds(ids.boxA)!.w).toEqual(60)
2979
+
2980
+ // engage snap mode and it should indeed snap to B
2981
+
2982
+ // 0 20 60 80
2983
+ // x───────────x───x
2984
+ // │ A │ B │
2985
+ // x───────────x───x
2986
+ editor.keyDown('Control')
2987
+ expect(editor.getShapePageBounds(ids.boxA)!.w).toEqual(60)
2988
+ expect(getSnapLines(editor)).toMatchInlineSnapshot(`
2989
+ Array [
2990
+ "0,0 60,0 80,0",
2991
+ "0,20 60,20 80,20",
2992
+ "60,0 60,20",
2993
+ ]
2994
+ `)
2995
+
2996
+ // and if not snapping we can make the box any size
2997
+ editor.pointerMove(19, 10, { ctrlKey: true })
2998
+ expect(editor.getShapePageBounds(ids.boxA)!.w).toEqual(19)
2999
+ })
3000
+ })
3001
+
3002
+ describe('resizing a shape with a child', () => {
3003
+ it('should not snap to the child', () => {
3004
+ // 0 1 11 50
3005
+ // ┌───────────────────┐
3006
+ // │ ┌───┐ │
3007
+ // │ │ B │ │
3008
+ // │ └───┘ │
3009
+ // │ │
3010
+ // │ A │
3011
+ // │ │
3012
+ // │ │
3013
+ // │ │
3014
+ // └───────────────────┘
3015
+
3016
+ editor.createShapes([
3017
+ box(ids.boxA, 0, 0, 50, 50),
3018
+ { ...box(ids.boxB, 1, 1), parentId: ids.boxA },
3019
+ ])
3020
+ editor
3021
+ .select(ids.boxA)
3022
+ .pointerDown(0, 0, { target: 'selection', handle: 'top_left' })
3023
+ .pointerMove(25, 25, { ctrlKey: true })
3024
+
3025
+ expect(editor.snaps.getLines().length).toBe(0)
3026
+ expect(editor.getShape(ids.boxA)).toMatchObject({ x: 25, y: 25, props: { w: 25, h: 25 } })
3027
+ expect(editor.getShape(ids.boxB)).toMatchObject({ x: 0.5, y: 0.5, props: { w: 5, h: 5 } })
3028
+ expect(editor.getShapePageBounds(ids.boxB)).toMatchObject({
3029
+ x: 25.5,
3030
+ y: 25.5,
3031
+ w: 5,
3032
+ h: 5,
3033
+ })
3034
+ })
3035
+ })
3036
+
3037
+ describe('reisizing shapes with aspect ratio locked', () => {
3038
+ beforeEach(() => {
3039
+ // 0 10 40 50
3040
+ //
3041
+ // 0 ┌───┐ ┌───┐
3042
+ // │ A │ │ B │ rot 90
3043
+ // 10 └───┘ └───┘
3044
+ //
3045
+ //
3046
+ //
3047
+ // 40 ┌───┐ ┌───┐
3048
+ // │ D │ rot 270 │ C │ rot 180
3049
+ // 50 └───┘ └───┘
3050
+ editor.createShapes([
3051
+ box(ids.boxA, 0, 0),
3052
+ { ...box(ids.boxB, 50, 0), rotation: Math.PI / 2 },
3053
+ { ...box(ids.boxC, 50, 50), rotation: Math.PI },
3054
+ { ...box(ids.boxD, 0, 50), rotation: Math.PI * 1.5 },
3055
+ ])
3056
+ })
3057
+ it('does not flip Y when resizing with left edge', () => {
3058
+ // 0 10 40 50
3059
+ // ┌───────────────────────┐
3060
+ // 0 │ ┌───┐ ┌───┐ │ 50 55 70 75
3061
+ // │ │ A │ │ B │ │ ┌───────────┐ 12.5
3062
+ // 10 │ └───┘ └───┘ │ │ B A │
3063
+ // │ │ │ │ 17.5
3064
+ // ┌┼┐drag -> │ ──► │ ┌┼┐
3065
+ // └┼┘ │ │ └┼┘
3066
+ // │ │ │ │ 32.5
3067
+ // 40 │ ┌───┐ ┌───┐ │ │ C D │
3068
+ // │ │ D │ │ C │ │ └───────────┘ 37.5
3069
+ // 50 │ └───┘ └───┘ │
3070
+ // └───────────────────────┘
3071
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3072
+ editor
3073
+ .pointerDown(0, 25, {
3074
+ target: 'selection',
3075
+ handle: 'left',
3076
+ })
3077
+ .pointerMove(75, 25, { shiftKey: true })
3078
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 70, y: 12.5, w: 5, h: 5 })
3079
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 50, y: 12.5, w: 5, h: 5 })
3080
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 50, y: 32.5, w: 5, h: 5 })
3081
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 70, y: 32.5, w: 5, h: 5 })
3082
+ })
3083
+ it('does not flip Y when resizing with right edge', () => {
3084
+ // 0 10 40 50
3085
+ // ┌───────────────────────┐
3086
+ // 0 │ ┌───┐ ┌───┐ │ -25 -20 -5 0
3087
+ // │ │ A │ │ B │ │ ┌───────────┐ 12.5
3088
+ // 10 │ └───┘ └───┘ │ │ B A │
3089
+ // │ │ │ │ 17.5
3090
+ // │ <-drag┌┼┐ ──► ┌┼┐ │
3091
+ // │ └┼┘ └┼┘ │
3092
+ // │ │ │ │ 32.5
3093
+ // 40 │ ┌───┐ ┌───┐ │ │ C D │
3094
+ // │ │ D │ │ C │ │ └───────────┘ 37.5
3095
+ // 50 │ └───┘ └───┘ │
3096
+ // └───────────────────────┘
3097
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3098
+ editor
3099
+ .pointerDown(50, 25, {
3100
+ target: 'selection',
3101
+ handle: 'right',
3102
+ })
3103
+ .pointerMove(-25, 25, { shiftKey: true })
3104
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: 12.5, w: 5, h: 5 })
3105
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -25, y: 12.5, w: 5, h: 5 })
3106
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: -25, y: 32.5, w: 5, h: 5 })
3107
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: -5, y: 32.5, w: 5, h: 5 })
3108
+ })
3109
+ it('does not flip X when resizing top edge', () => {
3110
+ // 0 10 40 50
3111
+ // ┌─┐
3112
+ // ┌──────────┼┼┼──────────┐
3113
+ // │ └─┘ │
3114
+ // 0 │ ┌───┐ ┌───┐ │
3115
+ // │ │ A │ │ │ B │ │
3116
+ // 10 │ └───┘ ▼ └───┘ │
3117
+ // │ │
3118
+ // │ drag │
3119
+ // │ │
3120
+ // │ │
3121
+ // 40 │ ┌───┐ ┌───┐ │
3122
+ // │ │ D │ │ C │ │
3123
+ // 50 │ └───┘ └───┘ │
3124
+ // └───────────────────────┘
3125
+ // │
3126
+ // ▼
3127
+ //
3128
+ // 12.5 17.5 32.5 37.5
3129
+ // 50 ┌───────────┐
3130
+ // │ D C │
3131
+ // 55 │ │
3132
+ // │ │
3133
+ // │ │
3134
+ // 70 │ │
3135
+ // │ A ┌─┐ B │
3136
+ // 75 └────┼┼┼────┘
3137
+ // └─┘
3138
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3139
+ editor
3140
+ .pointerDown(25, 0, {
3141
+ target: 'selection',
3142
+ handle: 'top',
3143
+ })
3144
+ .pointerMove(25, 75, { shiftKey: true })
3145
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 12.5, y: 70, w: 5, h: 5 })
3146
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 32.5, y: 70, w: 5, h: 5 })
3147
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 32.5, y: 50, w: 5, h: 5 })
3148
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 12.5, y: 50, w: 5, h: 5 })
3149
+ })
3150
+ it('does not flip X when resizing bottom edge', () => {
3151
+ // 0 10 40 50
3152
+ //
3153
+ // ┌───────────────────────┐
3154
+ // 0 │ ┌───┐ ┌───┐ │
3155
+ // │ │ A │ │ B │ │
3156
+ // 10 │ └───┘ └───┘ │
3157
+ // │ │
3158
+ // │ │
3159
+ // │ │
3160
+ // │ drag up │
3161
+ // 40 │ ┌───┐ ┌───┐ │
3162
+ // │ │ D │ ▲ │ C │ │
3163
+ // 50 │ └───┘ │ └───┘ │
3164
+ // │ ┌┼┐ │
3165
+ // └──────────┼┼┼──────────┘
3166
+ // └─┘
3167
+ //
3168
+ //
3169
+ // │
3170
+ // ▼
3171
+ //
3172
+ //
3173
+ // 12.5 17.5 32.5 37.5
3174
+ // ┌─┐
3175
+ // -25 ┌────┼┼┼────┐
3176
+ // │ D └─┘ C │
3177
+ // -20 │ │
3178
+ // │ │
3179
+ // │ │
3180
+ // -5 │ │
3181
+ // │ A B │
3182
+ // 0 └───────────┘
3183
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3184
+ editor
3185
+ .pointerDown(25, 50, {
3186
+ target: 'selection',
3187
+ handle: 'bottom',
3188
+ })
3189
+ .pointerMove(25, -25, { shiftKey: true })
3190
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 12.5, y: -5, w: 5, h: 5 })
3191
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 32.5, y: -5, w: 5, h: 5 })
3192
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 32.5, y: -25, w: 5, h: 5 })
3193
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 12.5, y: -25, w: 5, h: 5 })
3194
+ })
3195
+ it('preserves the correct alignment when dragging the top left corner around', () => {
3196
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3197
+ editor.pointerDown(0, 0, { target: 'selection', handle: 'top_left' })
3198
+ // 25 30 45 50
3199
+ // ┌───────────┐ 50
3200
+ // │ D C │
3201
+ // │ │ 55
3202
+ // │ │
3203
+ // │ │
3204
+ // │ │ 70
3205
+ // │ A B │
3206
+ // ──► x───────────┘ 75
3207
+ // top left corner
3208
+ // scale 0.5
3209
+ editor.pointerMove(25, 51, { shiftKey: true })
3210
+
3211
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 25, y: 70, w: 5, h: 5 })
3212
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 45, y: 70, w: 5, h: 5 })
3213
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 45, y: 50, w: 5, h: 5 })
3214
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 25, y: 50, w: 5, h: 5 })
3215
+
3216
+ //
3217
+ // 50 55 70 75
3218
+ // ┌───────────┐ 50
3219
+ // │ C D │
3220
+ // │ │ 55
3221
+ // │ │
3222
+ // │ │
3223
+ // │ │ 70
3224
+ // │ B A │
3225
+ // └───────────x 75
3226
+ // top left corner ▲
3227
+ // scale 0.5 │
3228
+ editor.pointerMove(51, 75, { shiftKey: true })
3229
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 70, y: 70, w: 5, h: 5 })
3230
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 50, y: 70, w: 5, h: 5 })
3231
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 50, y: 50, w: 5, h: 5 })
3232
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 70, y: 50, w: 5, h: 5 })
3233
+
3234
+ // top left corner │
3235
+ // scale 0.5 ▼
3236
+ // ┌───────────x 25
3237
+ // │ B A │
3238
+ // │ │ 30
3239
+ // │ │
3240
+ // │ │
3241
+ // │ │ 45
3242
+ // │ C D │
3243
+ // └───────────┘ 50
3244
+ // 50 55 70 75
3245
+ editor.pointerMove(51, 25, { shiftKey: true })
3246
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 70, y: 25, w: 5, h: 5 })
3247
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 50, y: 25, w: 5, h: 5 })
3248
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 50, y: 45, w: 5, h: 5 })
3249
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 70, y: 45, w: 5, h: 5 })
3250
+ })
3251
+ it('preserves the correct alignment when dragging the top right corner around', () => {
3252
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3253
+ editor.pointerDown(50, 0, { target: 'selection', handle: 'top_right' })
3254
+ // -25 -20 -5 0
3255
+ // ┌───────────┐ 50
3256
+ // │ C D │
3257
+ // │ │ 55
3258
+ // │ │
3259
+ // │ │
3260
+ // │ │ 70
3261
+ // │ B A │
3262
+ // ──► x───────────┘ 75
3263
+ // top right corner
3264
+ // scale 0.5
3265
+ editor.pointerMove(-25, 75, { shiftKey: true })
3266
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: 70, w: 5, h: 5 })
3267
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -25, y: 70, w: 5, h: 5 })
3268
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: -25, y: 50, w: 5, h: 5 })
3269
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: -5, y: 50, w: 5, h: 5 })
3270
+
3271
+ // 0 5 20 25
3272
+ // ┌───────────┐ 50
3273
+ // │ D C │
3274
+ // │ │ 55
3275
+ // │ │
3276
+ // │ │
3277
+ // │ │ 70
3278
+ // │ A B │
3279
+ // └───────────x 75
3280
+ // top right corner ▲
3281
+ // scale 0.5 │
3282
+ editor.pointerMove(25, 75, { shiftKey: true })
3283
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 70, w: 5, h: 5 })
3284
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 20, y: 70, w: 5, h: 5 })
3285
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 20, y: 50, w: 5, h: 5 })
3286
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 0, y: 50, w: 5, h: 5 })
3287
+
3288
+ // top right corner
3289
+ // │ scale 0.5
3290
+ // ▼
3291
+ // x───────────┐ 25
3292
+ // │ B A │
3293
+ // │ │ 30
3294
+ // │ │
3295
+ // │ │
3296
+ // │ │ 45
3297
+ // │ C D │
3298
+ // └───────────┘ 50
3299
+ // -25 -20 -5 0
3300
+ editor.pointerMove(-25, 25, { shiftKey: true })
3301
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: 25, w: 5, h: 5 })
3302
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -25, y: 25, w: 5, h: 5 })
3303
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: -25, y: 45, w: 5, h: 5 })
3304
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: -5, y: 45, w: 5, h: 5 })
3305
+ })
3306
+ it('preserves the correct alignment when dragging the bottom right corner around', () => {
3307
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3308
+ editor.pointerDown(50, 50, { target: 'selection', handle: 'bottom_right' })
3309
+ // -25 -20 -5 0
3310
+ // ┌───────────┐ 0
3311
+ // │ B A │
3312
+ // │ │ 5
3313
+ // │ │
3314
+ // │ │
3315
+ // │ │ 20
3316
+ // │ C D │
3317
+ // ──► x───────────┘ 25
3318
+ // bottom right corner
3319
+ // scale 0.5
3320
+ editor.pointerMove(-25, 25, { shiftKey: true })
3321
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: 0, w: 5, h: 5 })
3322
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -25, y: 0, w: 5, h: 5 })
3323
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: -25, y: 20, w: 5, h: 5 })
3324
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: -5, y: 20, w: 5, h: 5 })
3325
+ // bottom right corner │
3326
+ // scale 0.5 ▼
3327
+ // ┌───────────x -25
3328
+ // │ D C │
3329
+ // │ │ -20
3330
+ // │ │
3331
+ // │ │
3332
+ // │ │ -5
3333
+ // │ A B │
3334
+ // └───────────┘ 0
3335
+ // 0 5 20 25
3336
+ editor.pointerMove(25, -25, { shiftKey: true })
3337
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: -5, w: 5, h: 5 })
3338
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 20, y: -5, w: 5, h: 5 })
3339
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 20, y: -25, w: 5, h: 5 })
3340
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 0, y: -25, w: 5, h: 5 })
3341
+ // bottom right corner
3342
+ // │ scale 0.5
3343
+ // ▼
3344
+ // x───────────┐ -25
3345
+ // │ C D │
3346
+ // │ │ -20
3347
+ // │ │
3348
+ // │ │
3349
+ // │ │ -5
3350
+ // │ B A │
3351
+ // └───────────┘ 0
3352
+ // -25 -20 -5 0
3353
+ editor.pointerMove(-25, -25, { shiftKey: true })
3354
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: -5, y: -5, w: 5, h: 5 })
3355
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: -25, y: -5, w: 5, h: 5 })
3356
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: -25, y: -25, w: 5, h: 5 })
3357
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: -5, y: -25, w: 5, h: 5 })
3358
+ })
3359
+ it('preserves the correct alignment when dragging the bottom left corner around', () => {
3360
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3361
+ editor.pointerDown(0, 50, { target: 'selection', handle: 'bottom_left' })
3362
+ // 50 55 70 75
3363
+ // ┌───────────┐ 0
3364
+ // │ B A │
3365
+ // │ │ 5
3366
+ // │ │
3367
+ // │ │
3368
+ // │ │ 20
3369
+ // │ C D │
3370
+ // └───────────x 25
3371
+ // bottom left corner ▲
3372
+ // scale 0.5 │
3373
+ editor.pointerMove(75, 25, { shiftKey: true })
3374
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 70, y: 0, w: 5, h: 5 })
3375
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 50, y: 0, w: 5, h: 5 })
3376
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 50, y: 20, w: 5, h: 5 })
3377
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 70, y: 20, w: 5, h: 5 })
3378
+ // bottom left corner │
3379
+ // scale 0.5 ▼
3380
+ // ┌───────────x -25
3381
+ // │ C D │
3382
+ // │ │ -20
3383
+ // │ │
3384
+ // │ │
3385
+ // │ │ -5
3386
+ // │ B A │
3387
+ // └───────────┘ 0
3388
+ // 50 55 70 75
3389
+ editor.pointerMove(75, -25, { shiftKey: true })
3390
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 70, y: -5, w: 5, h: 5 })
3391
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 50, y: -5, w: 5, h: 5 })
3392
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 50, y: -25, w: 5, h: 5 })
3393
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 70, y: -25, w: 5, h: 5 })
3394
+ // bottom left corner
3395
+ // │ scale 0.5
3396
+ // ▼
3397
+ // x───────────┐ -25
3398
+ // │ D C │
3399
+ // │ │ -20
3400
+ // │ │
3401
+ // │ │
3402
+ // │ │ -5
3403
+ // │ A B │
3404
+ // └───────────┘ 0
3405
+ // 25 30 45 50
3406
+ editor.pointerMove(25, -25, { shiftKey: true })
3407
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 25, y: -5, w: 5, h: 5 })
3408
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 45, y: -5, w: 5, h: 5 })
3409
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 45, y: -25, w: 5, h: 5 })
3410
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 25, y: -25, w: 5, h: 5 })
3411
+ })
3412
+ })
3413
+
3414
+ describe('resizing a selection of mixed rotations', () => {
3415
+ beforeEach(() => {
3416
+ // 0 10 40 50
3417
+ //
3418
+ // 0 ┌───┐ ┌───┐
3419
+ // │ A │ │ B │ rot 90
3420
+ // 10 └───┘ └───┘
3421
+ //
3422
+ //
3423
+ //
3424
+ // 40 ┌───┐ ┌───┐
3425
+ // │ D │ rot 270 │ C │ rot 180
3426
+ // 50 └───┘ └───┘
3427
+ editor.createShapes([
3428
+ box(ids.boxA, 0, 0),
3429
+ { ...box(ids.boxB, 50, 0), rotation: Math.PI / 2 },
3430
+ { ...box(ids.boxC, 50, 50), rotation: Math.PI },
3431
+ { ...box(ids.boxD, 0, 50), rotation: Math.PI * 1.5 },
3432
+ ])
3433
+ })
3434
+ it('does not lock the aspect ratio if the rotations are compatible', () => {
3435
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3436
+ // 0 20 80 100
3437
+ //
3438
+ // ┌──────────────────────────────────┐
3439
+ // 0 │ ┌───────┐ ┌───────┐ │
3440
+ // │ │ A │ │ B │ │
3441
+ // 5 │ └───────┘ └───────┘ │
3442
+ // │ │
3443
+ // │ │
3444
+ // 20 │ ┌───────┐ ┌───────┐ │
3445
+ // │ │ D │ │ C │ │
3446
+ // 25 │ └───────┘ └───────┘ │
3447
+ // └──────────────────────────────────x drag
3448
+ editor.pointerDown(50, 50, { target: 'selection', handle: 'bottom_right' }).pointerMove(100, 25)
3449
+ expect(roundedPageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 20, h: 5 })
3450
+ expect(roundedPageBounds(ids.boxB)).toMatchObject({ x: 80, y: 0, w: 20, h: 5 })
3451
+ expect(roundedPageBounds(ids.boxC)).toMatchObject({ x: 80, y: 20, w: 20, h: 5 })
3452
+ expect(roundedPageBounds(ids.boxD)).toMatchObject({ x: 0, y: 20, w: 20, h: 5 })
3453
+ })
3454
+ it('does lock the aspect ratio if the rotations are not compatible', () => {
3455
+ editor.updateShapes([{ id: ids.boxC, type: 'geo', rotation: Math.PI + EPSILON }])
3456
+ editor.select(ids.boxA, ids.boxB, ids.boxC, ids.boxD)
3457
+ editor.pointerDown(50, 50, { target: 'selection', handle: 'bottom_right' }).pointerMove(100, 25)
3458
+ expect(roundedPageBounds(ids.boxA, 0.5)).toMatchObject({ x: 0, y: 0, w: 20, h: 20 })
3459
+ })
3460
+
3461
+ it('does lock the aspect ratio if one of the shapes has a child with an incompatible aspect ratio', () => {
3462
+ editor.updateShapes([
3463
+ { id: ids.boxC, type: 'geo', rotation: Math.PI + EPSILON, parentId: ids.boxA },
3464
+ ])
3465
+
3466
+ editor.select(ids.boxA, ids.boxB, ids.boxD)
3467
+ editor.pointerDown(50, 50, { target: 'selection', handle: 'bottom_right' }).pointerMove(100, 25)
3468
+ expect(roundedPageBounds(ids.boxA, 0.5)).toMatchObject({ x: 0, y: 0, w: 20, h: 20 })
3469
+ })
3470
+ })
3471
+
3472
+ // describe('Icons', () => {
3473
+ // beforeEach(() => {
3474
+ // editor =new TestEditor()
3475
+
3476
+ // editor.createShapes([
3477
+ // {
3478
+ // id: ids.iconA,
3479
+ // type: 'icon',
3480
+ // x: 0,
3481
+ // y: 0,
3482
+ // props: {
3483
+ // size: 'm',
3484
+ // },
3485
+ // },
3486
+ // ])
3487
+ // })
3488
+
3489
+ // it('scale correctly from each corner', () => {
3490
+ // editor.select(ids.iconA)
3491
+
3492
+ // // Scale to 2x from bottom right corner
3493
+ // app
3494
+ // .pointerDown(32, 32, { target: 'selection', handle: 'bottom_right' })
3495
+ // .pointerMove(64, 64)
3496
+ // .pointerUp()
3497
+
3498
+ // expect(editor.getShape(ids.iconA)).toMatchObject({
3499
+ // x: 0,
3500
+ // y: 0,
3501
+ // props: {
3502
+ // scale: 2,
3503
+ // },
3504
+ // })
3505
+ // expect(editor.getPageBounds(ids.iconA)).toMatchObject({
3506
+ // width: 64,
3507
+ // height: 64,
3508
+ // })
3509
+
3510
+ // // Scale to 1x from top right corner
3511
+ // app
3512
+ // .pointerDown(64, 0, { target: 'selection', handle: 'top_right' })
3513
+ // .pointerMove(32, 32)
3514
+ // .pointerUp()
3515
+ // expect(editor.getShape(ids.iconA)).toMatchObject({
3516
+ // x: 0,
3517
+ // y: 32,
3518
+ // props: {
3519
+ // scale: 1,
3520
+ // },
3521
+ // })
3522
+ // expect(editor.getPageBounds(ids.iconA)).toMatchObject({
3523
+ // width: 32,
3524
+ // height: 32,
3525
+ // })
3526
+
3527
+ // // Scale to 0.5x from top left corner but make sure
3528
+ // // the min scale works
3529
+ // app
3530
+ // .pointerDown(0, 32, { target: 'selection', handle: 'top_left' })
3531
+ // .pointerMove(16, 48)
3532
+ // .pointerUp()
3533
+ // expect(editor.getShape(ids.iconA)).toMatchObject({
3534
+ // x: 16,
3535
+ // y: 48,
3536
+ // props: {
3537
+ // scale: 0.5,
3538
+ // },
3539
+ // })
3540
+ // expect(editor.getPageBounds(ids.iconA)).toMatchObject({
3541
+ // width: 16,
3542
+ // height: 16,
3543
+ // })
3544
+ // })
3545
+ // })
3546
+
3547
+ describe('nodes that have do not resize', () => {
3548
+ it('are still translated if part of a selection', () => {
3549
+ const noteBId = createShapeId('noteB')
3550
+ editor.createShapes([box(ids.boxA, 0, 0, 200, 200), { id: noteBId, type: 'note', x: 0, y: 0 }])
3551
+
3552
+ // the default width and height of a note is 200
3553
+ expect(editor.getShapePageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 200, h: 200 })
3554
+ expect(editor.getShapePageBounds(noteBId)).toMatchObject({ x: 0, y: 0, w: 200, h: 200 })
3555
+
3556
+ editor.select(ids.boxA, noteBId)
3557
+
3558
+ editor.resizeSelection({ scaleX: 2, scaleY: 2 }, 'bottom_right')
3559
+
3560
+ expect(editor.getShapePageBounds(ids.boxA)).toMatchObject({ x: 0, y: 0, w: 400, h: 400 })
3561
+ // noteB should be in the middle of boxA
3562
+ expect(editor.getShapePageBounds(noteBId)).toMatchObject({ x: 100, y: 100, w: 200, h: 200 })
3563
+ })
3564
+ it('can flip', () => {
3565
+ const noteBId = createShapeId('noteB')
3566
+ const noteCId = createShapeId('noteC')
3567
+ editor.createShapes([
3568
+ box(ids.boxA, 0, 0, 200, 200),
3569
+ { id: noteBId, type: 'note', x: 300, y: 0 },
3570
+ { id: noteCId, type: 'note', x: 0, y: 300 },
3571
+ ])
3572
+
3573
+ editor.select(ids.boxA, noteBId, noteCId)
3574
+
3575
+ editor.flipShapes(editor.getSelectedShapeIds(), 'horizontal')
3576
+
3577
+ expect(editor.getShapePageBounds(ids.boxA)).toMatchObject({ x: 300, y: 0, w: 200, h: 200 })
3578
+ expect(editor.getShapePageBounds(noteBId)).toMatchObject({ x: 0, y: 0, w: 200, h: 200 })
3579
+ expect(editor.getShapePageBounds(noteCId)).toMatchObject({ x: 300, y: 300, w: 200, h: 200 })
3580
+
3581
+ editor.flipShapes(editor.getSelectedShapeIds(), 'vertical')
3582
+
3583
+ expect(editor.getShapePageBounds(ids.boxA)).toMatchObject({
3584
+ x: 300,
3585
+ y: 300,
3586
+ w: 200,
3587
+ h: 200,
3588
+ })
3589
+ expect(editor.getShapePageBounds(noteBId)).toMatchObject({ x: 0, y: 300, w: 200, h: 200 })
3590
+ expect(editor.getShapePageBounds(noteCId)).toMatchObject({ x: 300, y: 0, w: 200, h: 200 })
3591
+ })
3592
+ })
3593
+
3594
+ // describe('clicking the drag handle imprecisely', () => {
3595
+ // it('does not prevent grid snapping', () => {
3596
+ // // 0 10
3597
+ // // ┌───┐
3598
+ // // │ A │
3599
+ // // └───┘
3600
+
3601
+ // editor =new TestScene({
3602
+ // nodes: [box(ids.boxA, 0, 0)],
3603
+ // })
3604
+
3605
+ // editor.setGrid(true)
3606
+
3607
+ // // click bottom right handle with x: 2, y: -3 offset
3608
+ // app
3609
+ // .select(ids.boxA)
3610
+ // .pointerDown(12, 7, {
3611
+ // target: 'selection',
3612
+ // handle: 'bottom_right',
3613
+ // })
3614
+ // .pointerMove(20, 20)
3615
+
3616
+ // // corner point is actually at 18, 23
3617
+ // // nearest grid point is at 16, 24
3618
+ // expect(roundedPageBounds(ids.boxA)).toEqual({ x: 0, y: 0, w: 16, h: 24 })
3619
+ // })
3620
+ // it('does not prevent edge snapping', () => {
3621
+ // // 0 20 60 100
3622
+ // // ┌───┐ ┌───────┐
3623
+ // // │ A │ │ B │
3624
+ // // └───┘ │ │
3625
+ // // │ │
3626
+ // // └───────┘
3627
+
3628
+ // editor =new TestScene({
3629
+ // nodes: [box(ids.boxA, 0, 0, 20, 20), box(ids.boxB, 60, 0, 40, 40)],
3630
+ // })
3631
+
3632
+ // // offset by x: 5, y: -3
3633
+ // app
3634
+ // .select(ids.boxA)
3635
+ // .pointerDown(25, 17, { target: 'selection', handle: 'bottom_right' })
3636
+
3637
+ // // 0 20 60 100
3638
+ // // x───────────x───────x
3639
+ // // │ A │ B │
3640
+ // // x───────────x x │
3641
+ // // │ │
3642
+ // // └───────┘
3643
+ // // snap bottom-right corner of A to left edge and center of B
3644
+ // editor.pointerMove(72, 9, undefined, { ctrlKey: true })
3645
+ // // actual corner point is 67, 12, should snap to 60, 20
3646
+
3647
+ // expect(roundedPageBounds(ids.boxA)).toEqual({ x: 0, y: 0, w: 60, h: 20 })
3648
+ // })
3649
+ // })
3650
+
3651
+ // describe('nodes that have aspect ratio locked', () => {
3652
+ // // no onResize return value
3653
+ // class AspectRatioAlwaysLocked extends TLBoxShape {
3654
+ // static override id = 'aspect_ratio_always_locked'
3655
+ // override canChangeAspectRatio = () => {
3656
+ // return false
3657
+ // }
3658
+ // }
3659
+
3660
+ // beforeEach(() => {
3661
+ // // 0 10 20 30
3662
+ // // ┌───┐ ┌───┐
3663
+ // // │ A │ │ B │
3664
+ // // 10 └───┘ └───┘
3665
+ // //
3666
+ // // 20 ┌───┐
3667
+ // // │ C │
3668
+ // // 30 └───┘
3669
+ // editor =new TestScene({
3670
+ // shapeUtils: [TLBoxShape, AspectRatioAlwaysLocked],
3671
+ // nodes: [
3672
+ // {
3673
+ // id: ids.boxA,
3674
+ // type: 'geo',
3675
+ // x: 0,
3676
+ // y: 0,
3677
+ // width: 10,
3678
+ // height: 10,
3679
+ // isAspectRatioLocked: false,
3680
+ // },
3681
+ // {
3682
+ // id: ids.boxB,
3683
+ // type: 'geo',
3684
+ // x: 20,
3685
+ // y: 0,
3686
+ // width: 10,
3687
+ // height: 10,
3688
+ // isAspectRatioLocked: true,
3689
+ // },
3690
+ // { id: ids.boxC, type: AspectRatioAlwaysLocked.id, x: 0, y: 20, width: 10, height: 10 },
3691
+ // ],
3692
+ // })
3693
+ // })
3694
+
3695
+ // it('can have their aspect ratio locked by the class property', () => {
3696
+ // // 0 10 20 30
3697
+ // // ┌───┐ ┌───┐
3698
+ // // │ A │ │ B │
3699
+ // // 10 └───┘ └───┘
3700
+ // //
3701
+ // // 20 ┌───┐
3702
+ // // │ C │
3703
+ // // 30 └───x drag ->
3704
+ // app
3705
+ // .select(ids.boxC)
3706
+ // .pointerDown(10, 30, { target: 'selection', handle: 'bottom_right' })
3707
+ // .pointerMove(20, 30)
3708
+ // // 0 10 20 30
3709
+ // // ┌───┐ ┌───┐
3710
+ // // │ A │ │ B │
3711
+ // // 10 └───┘ └───┘
3712
+ // //
3713
+ // // 20 ┌───────┐
3714
+ // // │ C │
3715
+ // // 30 │ x pointer is here
3716
+ // // │ │
3717
+ // // └───────┘
3718
+ // expect(roundedPageBounds(ids.boxC)).toEqual({ x: 0, y: 20, w: 20, h: 20 })
3719
+ // })
3720
+
3721
+ // it('can have their aspect ratio locked by the model property', () => {
3722
+ // // 0 10 20 30
3723
+ // // ┌───┐ ┌───┐
3724
+ // // │ A │ │ B │
3725
+ // // 10 └───┘ └───x drag ->
3726
+ // //
3727
+ // // 20 ┌───┐
3728
+ // // │ C │
3729
+ // // 30 └───┘
3730
+ // app
3731
+ // .select(ids.boxB)
3732
+ // .pointerDown(30, 10, { target: 'selection', handle: 'bottom_right' })
3733
+ // .pointerMove(40, 10)
3734
+ // // 0 10 20 30
3735
+ // // ┌───┐ ┌───────┐
3736
+ // // │ A │ │ B │
3737
+ // // 10 └───┘ │ x pointer is here
3738
+ // // │ │
3739
+ // // 20 ┌───┐ └───────┘
3740
+ // // │ C │
3741
+ // // 30 └───┘
3742
+ // expect(roundedPageBounds(ids.boxB)).toEqual({ x: 20, y: 0, w: 20, h: 20 })
3743
+ // })
3744
+ // it('cause the whole selection to have the aspect ratio locked (model)', () => {
3745
+ // // 0 10 20 30
3746
+ // // ┌───┐- -┌───┐
3747
+ // // │ A │ │ B │
3748
+ // // 10 └───┘- -└───x drag ->
3749
+ // //
3750
+ // // 20 ┌───┐
3751
+ // // │ C │
3752
+ // // 30 └───┘
3753
+ // //
3754
+
3755
+ // app
3756
+ // .select(ids.boxA, ids.boxB)
3757
+ // .pointerDown(30, 10, { target: 'selection', handle: 'bottom_right' })
3758
+ // .pointerMove(60, 10)
3759
+ // // 0 10 40 60
3760
+ // // ┌───────┬·······┬───────┐
3761
+ // // │ A │ │ B │
3762
+ // // 10 │ │ │ x pointer
3763
+ // // │ │ │ │
3764
+ // // 20 ├───┬───┴·······┴───────┘
3765
+ // // │ C │
3766
+ // // 30 └───┘
3767
+ // expect(roundedPageBounds(ids.boxA)).toEqual({ x: 0, y: 0, w: 20, h: 20 })
3768
+ // expect(roundedPageBounds(ids.boxB)).toEqual({ x: 40, y: 0, w: 20, h: 20 })
3769
+ // })
3770
+ // it('cause the whole selection to have the aspect ratio locked (class property)', () => {
3771
+ // // 0 10 20 30
3772
+ // // ┌───┐ ┌───┐
3773
+ // // │ A │ │ B │
3774
+ // // 10 └───┘ └───┘
3775
+ // // | |
3776
+ // // 20 ┌───┐
3777
+ // // │ C │
3778
+ // // 30 └───x drag ->
3779
+ // app
3780
+ // .select(ids.boxA, ids.boxC)
3781
+ // .pointerDown(10, 30, { target: 'selection', handle: 'bottom_right' })
3782
+ // .pointerMove(10, 60)
3783
+ // // 0 10 20 30
3784
+ // // ┌───────┬───┐
3785
+ // // │ A │ B │
3786
+ // // 10 │ ├───┘
3787
+ // // │ │
3788
+ // // └───────┘
3789
+ // // | |
3790
+ // // | x pointer is here
3791
+ // // ┌───────┐
3792
+ // // │ C │
3793
+ // // │ │
3794
+ // // │ │
3795
+ // // └───────┘
3796
+ // expect(roundedPageBounds(ids.boxA)).toEqual({ x: 0, y: 0, w: 20, h: 20 })
3797
+ // expect(roundedPageBounds(ids.boxC)).toEqual({ x: 0, y: 40, w: 20, h: 20 })
3798
+ // })
3799
+ // })
3800
+
3801
+ describe('bugs', () => {
3802
+ // it('resizing a zero width shape', () => {
3803
+ // // Draw shapes can no longer have zero width / height
3804
+ // const shapeId = createShapeId()
3805
+ // app
3806
+ // .createShapes([
3807
+ // {
3808
+ // id: shapeId,
3809
+ // type: 'draw',
3810
+ // x: 0,
3811
+ // y: 0,
3812
+ // props: {
3813
+ // segments: [
3814
+ // {
3815
+ // type: 'straight',
3816
+ // points: [
3817
+ // { x: 0, y: 0 },
3818
+ // { x: 0, y: 100 },
3819
+ // ],
3820
+ // },
3821
+ // ],
3822
+ // },
3823
+ // },
3824
+ // ])
3825
+ // .select(shapeId)
3826
+ // expect(editor.selectionRotatedBounds!.width).toBe(0)
3827
+ // editor.pointerDown(0, 100, { target: 'selection', handle: 'bottom_right' }).pointerMove(10, 110)
3828
+ // expect(editor.selectionRotatedBounds!.width).toBe(0)
3829
+ // })
3830
+ })
3831
+
3832
+ it('uses the cross cursor when create resizing', () => {
3833
+ editor.setCurrentTool('geo')
3834
+ editor.pointerDown(0, 0)
3835
+ editor.pointerMove(100, 100)
3836
+ editor.expectToBeIn('select.resizing')
3837
+ expect(editor.getInstanceState().cursor.type).toBe('cross')
3838
+ expect(editor.getInstanceState().cursor.rotation).toBe(0)
3839
+
3840
+ editor.pointerMove(120, 120)
3841
+ expect(editor.getInstanceState().cursor.type).toBe('cross')
3842
+ expect(editor.getInstanceState().cursor.rotation).toBe(0)
3843
+
3844
+ editor.pointerMove(-120, -120)
3845
+ expect(editor.getInstanceState().cursor.type).toBe('cross')
3846
+ expect(editor.getInstanceState().cursor.rotation).toBe(0)
3847
+ })
3848
+
3849
+ describe('Resizing text from the right edge', () => {
3850
+ it('Resizes text from the right edge', () => {
3851
+ const id = createShapeId()
3852
+ editor.createShapes([{ id, type: 'text', props: { text: 'H' } }])
3853
+ editor.updateShapes([{ id, type: 'text', props: { text: 'Hello World' } }]) // auto size
3854
+
3855
+ editor.select(id)
3856
+
3857
+ const bounds = editor.getShapeGeometry(id).bounds
3858
+
3859
+ editor.updateInstanceState({ isCoarsePointer: false })
3860
+
3861
+ // Resize from the right edge
3862
+ editor.pointerDown(bounds.maxX, bounds.midY, { target: 'selection', handle: 'right' }) // right edge
3863
+ editor.expectToBeIn('select.pointing_resize_handle')
3864
+ editor.pointerMove(bounds.maxX + 5, bounds.midY, { target: 'selection', handle: 'right' })
3865
+ editor.expectToBeIn('select.resizing')
3866
+ editor.pointerUp()
3867
+
3868
+ editor.expectShapeToMatch({
3869
+ id,
3870
+ type: 'text',
3871
+ props: { text: 'Hello World', w: bounds.width + 5 },
3872
+ })
3873
+ })
3874
+
3875
+ it('Resizes text from the right edge when pointer is coarse', () => {
3876
+ editor.updateInstanceState({ isCoarsePointer: true })
3877
+
3878
+ const id = createShapeId()
3879
+ editor.createShapes([{ id, type: 'text', props: { text: 'H' } }])
3880
+ editor.updateShapes([{ id, type: 'text', props: { text: 'Hello World' } }]) // auto size
3881
+
3882
+ editor.select(id)
3883
+
3884
+ const bounds = editor.getShapeGeometry(id).bounds
3885
+
3886
+ // Resize from the right edge
3887
+ editor.pointerDown(bounds.maxX, bounds.midY, { target: 'selection', handle: 'right' }) // right edge
3888
+ editor.expectToBeIn('select.pointing_resize_handle')
3889
+ editor.pointerMove(bounds.maxX + 5, bounds.midY, { target: 'selection', handle: 'right' })
3890
+ editor.expectToBeIn('select.pointing_resize_handle')
3891
+ editor.pointerMove(bounds.maxX + 10, bounds.midY, { target: 'selection', handle: 'right' })
3892
+ editor.expectToBeIn('select.resizing')
3893
+ editor.pointerUp()
3894
+
3895
+ editor.expectShapeToMatch({
3896
+ id,
3897
+ type: 'text',
3898
+ props: { text: 'Hello World', w: bounds.width + 10 },
3899
+ })
3900
+ })
3901
+ })