@yuzhouu/canvas-kit 0.1.2

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 (263) hide show
  1. package/README.md +145 -0
  2. package/_vendor/canvas-core/bindings/BindingUtil.ts +92 -0
  3. package/_vendor/canvas-core/bindings/BindingUtilRegistry.ts +22 -0
  4. package/_vendor/canvas-core/bindings/arrow/arrowBindingHelpers.ts +52 -0
  5. package/_vendor/canvas-core/contextMenu.ts +85 -0
  6. package/_vendor/canvas-core/editor/Editor.ts +2614 -0
  7. package/_vendor/canvas-core/editor/HistoryManager.ts +83 -0
  8. package/_vendor/canvas-core/editor/StateNode.ts +162 -0
  9. package/_vendor/canvas-core/editor/camera.ts +6 -0
  10. package/_vendor/canvas-core/editor/clipboard.ts +478 -0
  11. package/_vendor/canvas-core/editor/commands.ts +833 -0
  12. package/_vendor/canvas-core/editor/edgeScroll.ts +37 -0
  13. package/_vendor/canvas-core/editor/editorComputedHelpers.ts +257 -0
  14. package/_vendor/canvas-core/editor/editorSelectionTransforms.ts +116 -0
  15. package/_vendor/canvas-core/editor/events.ts +93 -0
  16. package/_vendor/canvas-core/editor/index.ts +12 -0
  17. package/_vendor/canvas-core/editor/interactions.ts +101 -0
  18. package/_vendor/canvas-core/editor/internal.ts +22 -0
  19. package/_vendor/canvas-core/editor/managers/BindingManager.ts +262 -0
  20. package/_vendor/canvas-core/editor/managers/CameraManager.ts +147 -0
  21. package/_vendor/canvas-core/editor/managers/ClipboardManager.ts +32 -0
  22. package/_vendor/canvas-core/editor/managers/DocumentSnapshotManager.ts +256 -0
  23. package/_vendor/canvas-core/editor/managers/InputsManager.ts +319 -0
  24. package/_vendor/canvas-core/editor/managers/InteractionTransientManager.ts +218 -0
  25. package/_vendor/canvas-core/editor/managers/QueryManager.ts +837 -0
  26. package/_vendor/canvas-core/editor/managers/RenderWindowManager.ts +347 -0
  27. package/_vendor/canvas-core/editor/managers/SelectionLayoutManager.ts +196 -0
  28. package/_vendor/canvas-core/editor/managers/SelectionManager.ts +98 -0
  29. package/_vendor/canvas-core/editor/managers/SelectionOverlayManager.ts +308 -0
  30. package/_vendor/canvas-core/editor/managers/ShapeEditingManager.ts +226 -0
  31. package/_vendor/canvas-core/editor/managers/ShapeGeometryManager.ts +162 -0
  32. package/_vendor/canvas-core/editor/managers/ShapeHierarchyManager.ts +797 -0
  33. package/_vendor/canvas-core/editor/managers/SideEffectManager.ts +83 -0
  34. package/_vendor/canvas-core/editor/managers/SnapManager.ts +433 -0
  35. package/_vendor/canvas-core/editor/managers/SnapSnapshotBuilder.ts +430 -0
  36. package/_vendor/canvas-core/editor/managers/SpatialIndexManager.ts +354 -0
  37. package/_vendor/canvas-core/editor/managers/ToolManager.ts +81 -0
  38. package/_vendor/canvas-core/editor/managers/queryState.ts +583 -0
  39. package/_vendor/canvas-core/editor/managers/selectionGeometry.ts +287 -0
  40. package/_vendor/canvas-core/editor/managers/shapeOrder.ts +350 -0
  41. package/_vendor/canvas-core/editor/managers/shapeReparenting.ts +160 -0
  42. package/_vendor/canvas-core/editor/managers/snapCalculations.ts +412 -0
  43. package/_vendor/canvas-core/editor/managers/snapGeometry.ts +202 -0
  44. package/_vendor/canvas-core/editor/managers/snapIndicators.ts +403 -0
  45. package/_vendor/canvas-core/editor/managers/snapTypes.ts +122 -0
  46. package/_vendor/canvas-core/editor/queries/shapeTransforms.ts +171 -0
  47. package/_vendor/canvas-core/editor/renderWindow.ts +439 -0
  48. package/_vendor/canvas-core/editor/resizeGeometry.ts +654 -0
  49. package/_vendor/canvas-core/editor/selection.ts +489 -0
  50. package/_vendor/canvas-core/editor/selectionHandleInteractions.ts +43 -0
  51. package/_vendor/canvas-core/editor/selectionOverlay.ts +567 -0
  52. package/_vendor/canvas-core/exports/integrity.ts +174 -0
  53. package/_vendor/canvas-core/exports/svg.ts +494 -0
  54. package/_vendor/canvas-core/geometry/Box.ts +80 -0
  55. package/_vendor/canvas-core/geometry/Ellipse2d.ts +67 -0
  56. package/_vendor/canvas-core/geometry/Geometry2d.ts +52 -0
  57. package/_vendor/canvas-core/geometry/Mat.ts +92 -0
  58. package/_vendor/canvas-core/geometry/Polyline2d.ts +63 -0
  59. package/_vendor/canvas-core/geometry/Rectangle2d.ts +64 -0
  60. package/_vendor/canvas-core/geometry/Vec.ts +123 -0
  61. package/_vendor/canvas-core/geometry/index.ts +13 -0
  62. package/_vendor/canvas-core/geometry/segments.ts +65 -0
  63. package/_vendor/canvas-core/index.ts +391 -0
  64. package/_vendor/canvas-core/plugins/index.ts +5 -0
  65. package/_vendor/canvas-core/plugins/types.ts +53 -0
  66. package/_vendor/canvas-core/reactivity.ts +16 -0
  67. package/_vendor/canvas-core/schema/records.ts +221 -0
  68. package/_vendor/canvas-core/schema/snapshots.ts +527 -0
  69. package/_vendor/canvas-core/shapes/ShapeUtil.ts +516 -0
  70. package/_vendor/canvas-core/shapes/ShapeUtilRegistry.ts +26 -0
  71. package/_vendor/canvas-core/shapes/capabilities.ts +67 -0
  72. package/_vendor/canvas-core/shapes/types.ts +20 -0
  73. package/_vendor/canvas-core/toolbar.ts +148 -0
  74. package/_vendor/canvas-core/tools/hand/HandTool.ts +75 -0
  75. package/_vendor/canvas-core/tools/index.ts +2 -0
  76. package/_vendor/canvas-core/tools/select/SelectTool.ts +33 -0
  77. package/_vendor/canvas-core/tools/select/selectContainment.ts +104 -0
  78. package/_vendor/canvas-core/tools/select/selectToolHelpers.ts +801 -0
  79. package/_vendor/canvas-core/tools/select/states/BrushingState.ts +145 -0
  80. package/_vendor/canvas-core/tools/select/states/DraggingSelectionHandleInteractionState.ts +116 -0
  81. package/_vendor/canvas-core/tools/select/states/IdleState.ts +159 -0
  82. package/_vendor/canvas-core/tools/select/states/PointingCanvasState.ts +41 -0
  83. package/_vendor/canvas-core/tools/select/states/PointingResizeHandleState.ts +78 -0
  84. package/_vendor/canvas-core/tools/select/states/PointingRotateHandleState.ts +64 -0
  85. package/_vendor/canvas-core/tools/select/states/PointingSelectionHandleInteractionState.ts +34 -0
  86. package/_vendor/canvas-core/tools/select/states/PointingShapeState.ts +140 -0
  87. package/_vendor/canvas-core/tools/select/states/ResizingState.ts +171 -0
  88. package/_vendor/canvas-core/tools/select/states/RotatingState.ts +124 -0
  89. package/_vendor/canvas-core/tools/select/states/SelectStateNode.ts +128 -0
  90. package/_vendor/canvas-core/tools/select/states/TranslatingState.ts +139 -0
  91. package/_vendor/canvas-core/tools/select/states/index.ts +11 -0
  92. package/_vendor/canvas-plugin-api/feature.ts +204 -0
  93. package/_vendor/canvas-plugin-api/index.ts +142 -0
  94. package/_vendor/canvas-product-react/api/apiRegistry.ts +35 -0
  95. package/_vendor/canvas-product-react/api/canvasProductApi.ts +422 -0
  96. package/_vendor/canvas-product-react/api/index.ts +31 -0
  97. package/_vendor/canvas-product-react/capabilities/clipboard/clipboardService.ts +36 -0
  98. package/_vendor/canvas-product-react/capabilities/clipboard/systemClipboard.ts +245 -0
  99. package/_vendor/canvas-product-react/capabilities/context-menu/systemContextMenu.ts +396 -0
  100. package/_vendor/canvas-product-react/capabilities/context-menu/useContextMenuSurface.ts +59 -0
  101. package/_vendor/canvas-product-react/capabilities/export/useSvgExport.ts +156 -0
  102. package/_vendor/canvas-product-react/capabilities/history/useHistoryControls.ts +23 -0
  103. package/_vendor/canvas-product-react/capabilities/pages/usePageControls.ts +41 -0
  104. package/_vendor/canvas-product-react/capabilities/toolbar/systemToolbar.ts +490 -0
  105. package/_vendor/canvas-product-react/capabilities/toolbar/useToolbarSurfaces.ts +92 -0
  106. package/_vendor/canvas-product-react/capabilities/zoom/useZoomControls.ts +27 -0
  107. package/_vendor/canvas-product-react/index.ts +84 -0
  108. package/_vendor/canvas-product-react/persistence/index.ts +18 -0
  109. package/_vendor/canvas-product-react/persistence/localSnapshotPersistence.ts +294 -0
  110. package/_vendor/canvas-product-react/runtime/CanvasProductRoot.tsx +250 -0
  111. package/_vendor/canvas-product-react/runtime/productDefinition.ts +72 -0
  112. package/_vendor/canvas-product-react/runtime/productServices.ts +96 -0
  113. package/_vendor/canvas-react/components/CanvasView.tsx +796 -0
  114. package/_vendor/canvas-react/components/OverlayLayer.tsx +879 -0
  115. package/_vendor/canvas-react/components/PageSpace.tsx +34 -0
  116. package/_vendor/canvas-react/components/ShapeLayer.tsx +428 -0
  117. package/_vendor/canvas-react/components/index.ts +4 -0
  118. package/_vendor/canvas-react/hooks/useEditor.ts +11 -0
  119. package/_vendor/canvas-react/hooks/useValue.ts +14 -0
  120. package/_vendor/canvas-react/host/CanvasRendererRegistryContext.tsx +14 -0
  121. package/_vendor/canvas-react/host/contextMenuRegistry.ts +61 -0
  122. package/_vendor/canvas-react/host/domEventGuards.ts +61 -0
  123. package/_vendor/canvas-react/host/index.ts +38 -0
  124. package/_vendor/canvas-react/host/pluginHost.ts +635 -0
  125. package/_vendor/canvas-react/host/rendererRegistry.tsx +58 -0
  126. package/_vendor/canvas-react/host/toolbarRegistry.ts +100 -0
  127. package/_vendor/canvas-react/index.ts +3 -0
  128. package/_vendor/plugin-arrow/ArrowBindingUtil.ts +239 -0
  129. package/_vendor/plugin-arrow/ArrowShapeUtil.ts +311 -0
  130. package/_vendor/plugin-arrow/ArrowTool.ts +208 -0
  131. package/_vendor/plugin-arrow/arrowGeometry.ts +441 -0
  132. package/_vendor/plugin-arrow/arrowTerminalBindingResolver.ts +253 -0
  133. package/_vendor/plugin-arrow/arrowTerminalCommands.ts +230 -0
  134. package/_vendor/plugin-arrow/canvas.tsx +92 -0
  135. package/_vendor/plugin-arrow/core.ts +409 -0
  136. package/_vendor/plugin-arrow/feature.ts +20 -0
  137. package/_vendor/plugin-arrow/index.ts +28 -0
  138. package/_vendor/plugin-arrow/selectionHandleInteractions.ts +154 -0
  139. package/_vendor/plugin-arrow/types.ts +63 -0
  140. package/_vendor/plugin-draw/DrawShapeRenderer.tsx +60 -0
  141. package/_vendor/plugin-draw/DrawShapeUtil.ts +372 -0
  142. package/_vendor/plugin-draw/DrawTool.ts +444 -0
  143. package/_vendor/plugin-draw/canvas.tsx +24 -0
  144. package/_vendor/plugin-draw/core.ts +515 -0
  145. package/_vendor/plugin-draw/drawGeometry.ts +491 -0
  146. package/_vendor/plugin-draw/drawHitTest.ts +271 -0
  147. package/_vendor/plugin-draw/drawInterpolation.ts +250 -0
  148. package/_vendor/plugin-draw/drawPath.ts +550 -0
  149. package/_vendor/plugin-draw/drawSegments.ts +106 -0
  150. package/_vendor/plugin-draw/drawSelectionTransform.ts +67 -0
  151. package/_vendor/plugin-draw/drawShapeGeometry.ts +307 -0
  152. package/_vendor/plugin-draw/drawStrokeGeometry.ts +454 -0
  153. package/_vendor/plugin-draw/feature.ts +20 -0
  154. package/_vendor/plugin-draw/index.ts +31 -0
  155. package/_vendor/plugin-draw/types.ts +36 -0
  156. package/_vendor/plugin-eraser/EraserTool.ts +297 -0
  157. package/_vendor/plugin-eraser/canvas.tsx +616 -0
  158. package/_vendor/plugin-eraser/core.ts +49 -0
  159. package/_vendor/plugin-eraser/feature.ts +20 -0
  160. package/_vendor/plugin-eraser/index.ts +4 -0
  161. package/_vendor/plugin-frame/FrameShapeUtil.ts +173 -0
  162. package/_vendor/plugin-frame/FrameTool.ts +225 -0
  163. package/_vendor/plugin-frame/canvas.tsx +75 -0
  164. package/_vendor/plugin-frame/core.ts +534 -0
  165. package/_vendor/plugin-frame/feature.ts +20 -0
  166. package/_vendor/plugin-frame/index.ts +6 -0
  167. package/_vendor/plugin-geo/GeoShapeUtil.ts +463 -0
  168. package/_vendor/plugin-geo/GeoTools.ts +247 -0
  169. package/_vendor/plugin-geo/canvas.tsx +90 -0
  170. package/_vendor/plugin-geo/core.ts +495 -0
  171. package/_vendor/plugin-geo/feature.ts +20 -0
  172. package/_vendor/plugin-geo/index.ts +7 -0
  173. package/_vendor/plugin-geo/types.ts +27 -0
  174. package/_vendor/plugin-group/GroupShapeUtil.ts +59 -0
  175. package/_vendor/plugin-group/canvas.tsx +59 -0
  176. package/_vendor/plugin-group/core.ts +40 -0
  177. package/_vendor/plugin-group/feature.ts +20 -0
  178. package/_vendor/plugin-group/index.ts +5 -0
  179. package/_vendor/plugin-image/ImageShapeUtil.ts +95 -0
  180. package/_vendor/plugin-image/canvas.tsx +212 -0
  181. package/_vendor/plugin-image/core.ts +542 -0
  182. package/_vendor/plugin-image/crop.ts +770 -0
  183. package/_vendor/plugin-image/cropInteractions.ts +350 -0
  184. package/_vendor/plugin-image/cropSession.ts +38 -0
  185. package/_vendor/plugin-image/feature.ts +20 -0
  186. package/_vendor/plugin-image/index.ts +29 -0
  187. package/_vendor/plugin-image/types.ts +55 -0
  188. package/_vendor/plugin-image-product-react/ImageImportController.tsx +143 -0
  189. package/_vendor/plugin-image-product-react/imageAssetService.ts +52 -0
  190. package/_vendor/plugin-image-product-react/imageBlobStore.ts +315 -0
  191. package/_vendor/plugin-image-product-react/imageHostActions.ts +438 -0
  192. package/_vendor/plugin-image-product-react/imageProductApi.ts +88 -0
  193. package/_vendor/plugin-image-product-react/imageToolbarHostBridge.ts +48 -0
  194. package/_vendor/plugin-image-product-react/imageToolbarRuntime.ts +21 -0
  195. package/_vendor/plugin-image-product-react/index.ts +60 -0
  196. package/_vendor/plugin-image-product-react/snapshotGuards.ts +33 -0
  197. package/_vendor/plugin-image-product-react/svgImageAssetInliner.ts +54 -0
  198. package/_vendor/plugin-image-product-react/useImageImport.ts +64 -0
  199. package/_vendor/plugin-laser/LaserTool.ts +154 -0
  200. package/_vendor/plugin-laser/canvas.tsx +645 -0
  201. package/_vendor/plugin-laser/core.ts +49 -0
  202. package/_vendor/plugin-laser/feature.ts +20 -0
  203. package/_vendor/plugin-laser/index.ts +4 -0
  204. package/_vendor/plugin-text/ArrowLabelBindingUtil.ts +336 -0
  205. package/_vendor/plugin-text/GeoLabelBindingUtil.ts +391 -0
  206. package/_vendor/plugin-text/TextShapeSvgExporter.ts +101 -0
  207. package/_vendor/plugin-text/TextShapeUtil.ts +284 -0
  208. package/_vendor/plugin-text/TextTool.ts +228 -0
  209. package/_vendor/plugin-text/canvas.tsx +115 -0
  210. package/_vendor/plugin-text/core.ts +422 -0
  211. package/_vendor/plugin-text/feature.ts +20 -0
  212. package/_vendor/plugin-text/host/RichTextEditingBox.tsx +144 -0
  213. package/_vendor/plugin-text/host/RichTextToolbar.tsx +266 -0
  214. package/_vendor/plugin-text/host/TiptapTextEditor.tsx +191 -0
  215. package/_vendor/plugin-text/host/richTextRendering.tsx +49 -0
  216. package/_vendor/plugin-text/host/textDomSelection.ts +93 -0
  217. package/_vendor/plugin-text/host/textEditingBoxStyle.ts +36 -0
  218. package/_vendor/plugin-text/host/textEntryFocus.ts +307 -0
  219. package/_vendor/plugin-text/host/textFontLoader.ts +149 -0
  220. package/_vendor/plugin-text/host/textMeasurement.ts +258 -0
  221. package/_vendor/plugin-text/host/textMeasurementSync.ts +77 -0
  222. package/_vendor/plugin-text/host/textRangeSelection.ts +134 -0
  223. package/_vendor/plugin-text/host/textShapeRendererRuntime.tsx +89 -0
  224. package/_vendor/plugin-text/host/textShapeSync.ts +173 -0
  225. package/_vendor/plugin-text/host/tiptapTextEditorController.ts +148 -0
  226. package/_vendor/plugin-text/index.ts +18 -0
  227. package/_vendor/plugin-text/richTextUtils.ts +259 -0
  228. package/_vendor/plugin-text/textInteractions.ts +366 -0
  229. package/_vendor/plugin-text/textLabelHelpers.ts +235 -0
  230. package/_vendor/plugin-text/textShapeHelpers.ts +123 -0
  231. package/_vendor/plugin-text/textStyle.ts +96 -0
  232. package/_vendor/plugin-text/textTypes.ts +48 -0
  233. package/_vendor/signals/atom.ts +74 -0
  234. package/_vendor/signals/computed.ts +132 -0
  235. package/_vendor/signals/core.ts +130 -0
  236. package/_vendor/signals/effect.ts +117 -0
  237. package/_vendor/signals/index.ts +9 -0
  238. package/_vendor/signals/types.ts +17 -0
  239. package/_vendor/store/Store.ts +171 -0
  240. package/_vendor/store/diff.ts +229 -0
  241. package/_vendor/store/history.ts +177 -0
  242. package/_vendor/store/index.ts +32 -0
  243. package/_vendor/store/types.ts +37 -0
  244. package/api/canvasKitApi.d.ts +29 -0
  245. package/index.css +3 -0
  246. package/index.d.ts +16 -0
  247. package/index.mjs +1 -0
  248. package/internal-modules.d.ts +187 -0
  249. package/package.json +48 -0
  250. package/product/Shell.d.ts +19 -0
  251. package/product/chromeContext.d.ts +70 -0
  252. package/product/createCanvasKitEditor.d.ts +6 -0
  253. package/product/index.d.ts +7 -0
  254. package/product/persistence.d.ts +3 -0
  255. package/product/product.d.ts +22 -0
  256. package/product/useCanvasClipboardShortcuts.d.ts +6 -0
  257. package/product-iyBbEPIs.mjs +4 -0
  258. package/product.mjs +1 -0
  259. package/standard/extensions.d.ts +1 -0
  260. package/standard/index.d.ts +3 -0
  261. package/standard/standardApi.d.ts +91 -0
  262. package/standard-BmrxwqpJ.mjs +44 -0
  263. package/standard.mjs +1 -0
@@ -0,0 +1,140 @@
1
+ import type { Editor } from "../../../editor/Editor";
2
+ import { Vec } from "../../../geometry/Vec";
3
+ import { StateNode } from "../../../editor/StateNode";
4
+ import type { PointerEditorEvent } from "../../../editor/events";
5
+ import {
6
+ createTranslatingUpdates,
7
+ getTranslateShapeSnapshots,
8
+ isAdditiveSelectionActive,
9
+ isQuickClick,
10
+ type PointingShapeInfo,
11
+ type TranslatingInfo,
12
+ } from "../selectToolHelpers";
13
+ import { PointingStateNode } from "./SelectStateNode";
14
+
15
+ export class PointingShapeState extends PointingStateNode<PointingShapeInfo> {
16
+ constructor(editor: Editor, parent: StateNode) {
17
+ super(editor, "pointing_shape", parent);
18
+ }
19
+
20
+ protected onInfoEnter(): void {
21
+ if (!this.info) {
22
+ return;
23
+ }
24
+
25
+ if (this.info.quickClickSelectionTargetId) {
26
+ return;
27
+ }
28
+
29
+ if (this.info.additiveSelection) {
30
+ if (!this.info.wasSelected) {
31
+ this.editor.commands.setSelectedShapeIds(
32
+ [...this.info.previousSelection, this.info.shapeId],
33
+ { source: "system" },
34
+ );
35
+ }
36
+ return;
37
+ }
38
+
39
+ if (!this.info.wasSelected) {
40
+ this.editor.commands.setSelectedShapeIds([this.info.shapeId], {
41
+ source: "system",
42
+ });
43
+ }
44
+ }
45
+
46
+ protected onDragThresholdExceeded(): void {
47
+ if (!this.info) {
48
+ return;
49
+ }
50
+
51
+ const selectedShapes = this.editor.getSelectedShapes();
52
+ const selectedShapeIds = this.info.wasSelected
53
+ ? selectedShapes.map((shape) => shape.id)
54
+ : [this.info.translateTargetId];
55
+ if (
56
+ !this.info.wasSelected &&
57
+ selectedShapeIds.length === 1 &&
58
+ selectedShapeIds[0] !== this.info.shapeId
59
+ ) {
60
+ this.editor.commands.setSelectedShapeIds(selectedShapeIds, {
61
+ source: "system",
62
+ });
63
+ }
64
+ const selectionFrame = this.editor.getSelectionFrame();
65
+ const selectedShapeSnapshots = getTranslateShapeSnapshots(
66
+ this.editor,
67
+ selectedShapeIds,
68
+ );
69
+ const movingShapeIds = selectedShapeSnapshots.map((shape) => shape.id);
70
+ const snapRotation = selectionFrame?.hasCompatibleRotation
71
+ ? selectionFrame.rotation
72
+ : 0;
73
+ const snapRotationCenter =
74
+ selectionFrame?.rotationCenter.clone() ?? Vec.Zero();
75
+ const startBounds = selectionFrame?.hasCompatibleRotation
76
+ ? selectionFrame.bounds.clone()
77
+ : this.editor.getSelectionPageBounds();
78
+ this.transition("translating", {
79
+ originPagePoint: this.info.originPagePoint,
80
+ previousSelection: this.info.previousSelection,
81
+ selectedShapeIds,
82
+ startBounds,
83
+ snapSnapshot: this.editor.snaps.createTranslateSnapshot({
84
+ movingShapeIds,
85
+ coordinateSpace: {
86
+ rotation: snapRotation,
87
+ rotationCenter: snapRotationCenter,
88
+ },
89
+ }),
90
+ snapRotation,
91
+ selectedShapes: selectedShapeSnapshots,
92
+ updates: createTranslatingUpdates(selectedShapeSnapshots),
93
+ lockedAxis: null,
94
+ lastDeltaX: Number.NaN,
95
+ lastDeltaY: Number.NaN,
96
+ } satisfies TranslatingInfo);
97
+ }
98
+
99
+ protected onPointerUp(event: PointerEditorEvent): void {
100
+ if (this.info?.quickClickSelectionTargetId) {
101
+ const quickClick = isQuickClick(this.info, event);
102
+ if (quickClick) {
103
+ this.editor.commands.setSelectedShapeIds(
104
+ [this.info.quickClickSelectionTargetId],
105
+ { source: "system" },
106
+ );
107
+ }
108
+ const shouldForwardDoubleClick =
109
+ quickClick && (event.clickCount ?? 1) >= 2;
110
+ if (!shouldForwardDoubleClick) {
111
+ this.editor.resetPointerClickTracking();
112
+ }
113
+ } else if (isAdditiveSelectionActive(event) && this.info?.wasSelected) {
114
+ this.editor.commands.setSelectedShapeIds(
115
+ this.info.previousSelection.filter((id) => id !== this.info?.shapeId),
116
+ { source: "system" },
117
+ );
118
+ } else if (
119
+ this.info &&
120
+ !this.info.additiveSelection &&
121
+ this.info.wasSelected &&
122
+ !this.info.fromSelectionBounds &&
123
+ this.info.previousSelection.length > 1
124
+ ) {
125
+ this.editor.commands.setSelectedShapeIds([this.info.shapeId], {
126
+ source: "system",
127
+ });
128
+ }
129
+ this.transition("idle");
130
+ }
131
+
132
+ protected onCancel(): void {
133
+ if (this.info) {
134
+ this.editor.commands.setSelectedShapeIds(this.info.previousSelection, {
135
+ source: "system",
136
+ });
137
+ }
138
+ this.transition("idle");
139
+ }
140
+ }
@@ -0,0 +1,171 @@
1
+ import type { Editor } from "../../../editor/Editor";
2
+ import { getConstrainedSelectionResizeBoundsWithScale } from "../../../editor/resizeGeometry";
3
+ import { StateNode } from "../../../editor/StateNode";
4
+ import { selectionPagePointToLocalPoint } from "../../../editor/selection";
5
+ import {
6
+ RESIZE_HISTORY_MARK,
7
+ RESIZE_SNAP_DISTANCE_SCREEN,
8
+ getResizedPagePointsUpdate,
9
+ getResizedShapeUpdate,
10
+ getSelectionTransform,
11
+ type ResizingInfo,
12
+ } from "../selectToolHelpers";
13
+ import { DraggingStateNode, type DragApplyInput } from "./SelectStateNode";
14
+
15
+ export class ResizingState extends DraggingStateNode<ResizingInfo> {
16
+ protected readonly tickMode =
17
+ "apply_after_scroll_or_without_screen_point" as const;
18
+
19
+ constructor(editor: Editor, parent: StateNode) {
20
+ super(editor, "resizing", parent);
21
+ }
22
+
23
+ protected getHistoryMark(): string {
24
+ return RESIZE_HISTORY_MARK;
25
+ }
26
+
27
+ protected onDragStart(): void {
28
+ this.editor.setSnapIndicators(null);
29
+ }
30
+
31
+ protected onPointerUp(): void {
32
+ this.complete();
33
+ }
34
+
35
+ protected onCancel(): void {
36
+ if (this.info) {
37
+ this.editor.commands.setSelectedShapeIds(this.info.previousSelection, {
38
+ source: "system",
39
+ });
40
+ }
41
+ this.cancel();
42
+ }
43
+
44
+ protected onInfoExit(): void {
45
+ this.editor.setSnapIndicators(null);
46
+ }
47
+
48
+ protected apply({
49
+ pagePoint,
50
+ shiftKey,
51
+ altKey,
52
+ accelKey,
53
+ }: DragApplyInput): void {
54
+ if (!this.info) {
55
+ return;
56
+ }
57
+
58
+ if (
59
+ pagePoint.x === this.info.lastPagePointX &&
60
+ pagePoint.y === this.info.lastPagePointY &&
61
+ shiftKey === this.info.lastShiftKey &&
62
+ altKey === this.info.lastAltKey &&
63
+ accelKey === this.info.lastAccelKey
64
+ ) {
65
+ return;
66
+ }
67
+ this.info.lastPagePointX = pagePoint.x;
68
+ this.info.lastPagePointY = pagePoint.y;
69
+ this.info.lastShiftKey = shiftKey;
70
+ this.info.lastAltKey = altKey;
71
+ this.info.lastAccelKey = accelKey;
72
+
73
+ const selectionTransform = getSelectionTransform(
74
+ this.info.rotationCenter,
75
+ this.info.rotation,
76
+ );
77
+ const resizePagePoint = pagePoint.sub(this.info.cursorHandleOffset);
78
+ const localPagePoint = selectionPagePointToLocalPoint(
79
+ resizePagePoint,
80
+ selectionTransform,
81
+ );
82
+ const isAspectRatioLocked =
83
+ this.info.aspectRatioLockOverride ?? shiftKey;
84
+ const nextResize = getConstrainedSelectionResizeBoundsWithScale({
85
+ startBounds: this.info.startBounds,
86
+ handleId: this.info.handleId,
87
+ pagePoint: localPagePoint,
88
+ isAspectRatioLocked,
89
+ isResizingFromCenter: altKey,
90
+ aspectRatio: this.info.aspectRatio,
91
+ });
92
+ const canSnap =
93
+ !accelKey &&
94
+ this.info.snapSnapshot.points.length > 0;
95
+ const snappedResize = canSnap
96
+ ? this.editor.snaps.snapResize({
97
+ handleId: this.info.handleId,
98
+ initialSelectionBounds: this.info.startBounds,
99
+ resizedSelectionBounds: nextResize.bounds,
100
+ scaleX: nextResize.scaleX,
101
+ scaleY: nextResize.scaleY,
102
+ snapshot: this.info.snapSnapshot,
103
+ threshold:
104
+ RESIZE_SNAP_DISTANCE_SCREEN / this.editor.getCurrentCamera().z,
105
+ isAspectRatioLocked,
106
+ isResizingFromCenter: altKey,
107
+ })
108
+ : nextResize;
109
+
110
+ if (!canSnap) {
111
+ this.editor.snaps.clearIndicators();
112
+ }
113
+
114
+ for (let index = 0; index < this.info.shapes.length; index += 1) {
115
+ const shape = this.info.shapes[index];
116
+ const update = this.info.updates[index];
117
+ if (!shape || !update) {
118
+ continue;
119
+ }
120
+ getResizedShapeUpdate(
121
+ this.editor,
122
+ shape,
123
+ this.info.startBounds,
124
+ snappedResize.bounds,
125
+ snappedResize.scaleX,
126
+ snappedResize.scaleY,
127
+ this.info.handleId,
128
+ altKey,
129
+ this.info.rotationCenter,
130
+ this.info.rotation,
131
+ update,
132
+ );
133
+ }
134
+
135
+ for (let index = 0; index < this.info.pointShapes.length; index += 1) {
136
+ const shape = this.info.pointShapes[index];
137
+ const update = this.info.updates[this.info.shapes.length + index];
138
+ if (!shape || !update) {
139
+ continue;
140
+ }
141
+
142
+ getResizedPagePointsUpdate(
143
+ this.editor,
144
+ shape,
145
+ this.info.startBounds,
146
+ snappedResize.bounds,
147
+ snappedResize.scaleX,
148
+ snappedResize.scaleY,
149
+ this.info.handleId,
150
+ altKey,
151
+ this.info.rotationCenter,
152
+ this.info.rotation,
153
+ update,
154
+ );
155
+ }
156
+
157
+ this.editor.commands.updateShapes(this.info.updates);
158
+ }
159
+
160
+ private complete(): void {
161
+ this.editor.setSnapIndicators(null);
162
+ this.editor.history.squashToMark(RESIZE_HISTORY_MARK);
163
+ this.transition("idle");
164
+ }
165
+
166
+ private cancel(): void {
167
+ this.editor.setSnapIndicators(null);
168
+ this.editor.history.bailToMark(RESIZE_HISTORY_MARK);
169
+ this.transition("idle");
170
+ }
171
+ }
@@ -0,0 +1,124 @@
1
+ import type { Editor } from "../../../editor/Editor";
2
+ import { Vec } from "../../../geometry/Vec";
3
+ import { StateNode } from "../../../editor/StateNode";
4
+ import {
5
+ ROTATE_HISTORY_MARK,
6
+ ROTATION_SNAP_STEP,
7
+ ROTATION_SOFT_SNAP_MAX_SCREEN_VELOCITY,
8
+ ROTATION_SOFT_SNAP_STEP,
9
+ ROTATION_SOFT_SNAP_THRESHOLD,
10
+ getRotatedPagePointsUpdate,
11
+ getRotatedShapeUpdate,
12
+ normalizeAngle,
13
+ snapAngle,
14
+ type RotatingInfo,
15
+ } from "../selectToolHelpers";
16
+ import { DraggingStateNode, type DragApplyInput } from "./SelectStateNode";
17
+
18
+ export class RotatingState extends DraggingStateNode<RotatingInfo> {
19
+ protected readonly tickMode = "apply_after_scroll" as const;
20
+
21
+ constructor(editor: Editor, parent: StateNode) {
22
+ super(editor, "rotating", parent);
23
+ }
24
+
25
+ protected getHistoryMark(): string {
26
+ return ROTATE_HISTORY_MARK;
27
+ }
28
+
29
+ protected onPointerUp(): void {
30
+ this.complete();
31
+ }
32
+
33
+ protected onCancel(): void {
34
+ if (this.info) {
35
+ this.editor.commands.setSelectedShapeIds(this.info.previousSelection, {
36
+ source: "system",
37
+ });
38
+ }
39
+ this.cancel();
40
+ }
41
+
42
+ protected apply({ pagePoint, shiftKey, accelKey }: DragApplyInput): void {
43
+ if (!this.info) {
44
+ return;
45
+ }
46
+
47
+ if (
48
+ pagePoint.x === this.info.lastPointerX &&
49
+ pagePoint.y === this.info.lastPointerY &&
50
+ shiftKey === this.info.lastShiftKey &&
51
+ accelKey === this.info.lastAccelKey
52
+ ) {
53
+ return;
54
+ }
55
+ this.info.lastPointerX = pagePoint.x;
56
+ this.info.lastPointerY = pagePoint.y;
57
+ this.info.lastShiftKey = shiftKey;
58
+ this.info.lastAccelKey = accelKey;
59
+
60
+ let delta = normalizeAngle(
61
+ Vec.Angle(this.info.center, pagePoint) - this.info.startAngle,
62
+ );
63
+ if (shiftKey) {
64
+ delta = snapAngle(delta, ROTATION_SNAP_STEP);
65
+ } else {
66
+ const shouldSoftSnap =
67
+ !accelKey &&
68
+ this.editor.inputs.state.get().screenVelocity.len() <
69
+ ROTATION_SOFT_SNAP_MAX_SCREEN_VELOCITY;
70
+ if (shouldSoftSnap) {
71
+ const nextSelectionRotation =
72
+ this.info.initialSelectionRotation + delta;
73
+ const snappedSelectionRotation = snapAngle(
74
+ nextSelectionRotation,
75
+ ROTATION_SOFT_SNAP_STEP,
76
+ );
77
+ const snapOffset = normalizeAngle(
78
+ snappedSelectionRotation - nextSelectionRotation,
79
+ );
80
+ if (Math.abs(snapOffset) <= ROTATION_SOFT_SNAP_THRESHOLD) {
81
+ delta = normalizeAngle(
82
+ snappedSelectionRotation - this.info.initialSelectionRotation,
83
+ );
84
+ }
85
+ }
86
+ }
87
+
88
+ for (let index = 0; index < this.info.shapes.length; index += 1) {
89
+ const shape = this.info.shapes[index];
90
+ const update = this.info.updates[index];
91
+ if (!shape || !update) {
92
+ continue;
93
+ }
94
+ getRotatedShapeUpdate(shape, this.info.center, delta, update);
95
+ }
96
+
97
+ for (let index = 0; index < this.info.pointShapes.length; index += 1) {
98
+ const shape = this.info.pointShapes[index];
99
+ const update = this.info.updates[this.info.shapes.length + index];
100
+ if (!shape || !update) {
101
+ continue;
102
+ }
103
+ getRotatedPagePointsUpdate(
104
+ this.editor,
105
+ shape,
106
+ this.info.center,
107
+ delta,
108
+ update,
109
+ );
110
+ }
111
+
112
+ this.editor.commands.updateShapes(this.info.updates);
113
+ }
114
+
115
+ private complete(): void {
116
+ this.editor.history.squashToMark(ROTATE_HISTORY_MARK);
117
+ this.transition("idle");
118
+ }
119
+
120
+ private cancel(): void {
121
+ this.editor.history.bailToMark(ROTATE_HISTORY_MARK);
122
+ this.transition("idle");
123
+ }
124
+ }
@@ -0,0 +1,128 @@
1
+ import type { Editor } from "../../../editor/Editor";
2
+ import type { Vec } from "../../../geometry/Vec";
3
+ import { StateNode } from "../../../editor/StateNode";
4
+ import type {
5
+ PointerEditorEvent,
6
+ TickEditorEvent,
7
+ } from "../../../editor/events";
8
+ import {
9
+ applySelectionDragFromCurrentInputs,
10
+ getSelectionDragInputForTick,
11
+ hasExceededDragThreshold,
12
+ type EdgeScrollTickMode,
13
+ } from "../selectToolHelpers";
14
+
15
+ /**
16
+ * Base for every select-tool state that carries a transient `info` payload.
17
+ * Centralises the identical `info` lifecycle (assign on enter, clear on exit)
18
+ * so concrete states only express their behaviour. Cleanup that must run while
19
+ * `info` is still readable belongs in {@link onInfoExit}.
20
+ */
21
+ export abstract class InfoStateNode<T> extends StateNode {
22
+ protected info: T | null = null;
23
+
24
+ protected onEnter(info?: unknown): void {
25
+ this.info = info as T;
26
+ this.onInfoEnter();
27
+ }
28
+
29
+ protected onExit(): void {
30
+ this.onInfoExit();
31
+ this.info = null;
32
+ }
33
+
34
+ /** Runs after `info` is assigned. */
35
+ protected onInfoEnter(): void {}
36
+
37
+ /** Runs before `info` is cleared. */
38
+ protected onInfoExit(): void {}
39
+ }
40
+
41
+ /**
42
+ * Base for the "pointing_*" states. They all wait for the pointer to exceed the
43
+ * drag threshold before committing to a gesture; subclasses only implement what
44
+ * happens once that threshold is crossed.
45
+ */
46
+ export abstract class PointingStateNode<
47
+ T extends { originPagePoint: Vec },
48
+ > extends InfoStateNode<T> {
49
+ protected onPointerMove(event: PointerEditorEvent): void {
50
+ if (!this.info) {
51
+ return;
52
+ }
53
+ if (!hasExceededDragThreshold(this.info.originPagePoint, event.pagePoint)) {
54
+ return;
55
+ }
56
+ this.onDragThresholdExceeded(event);
57
+ }
58
+
59
+ protected abstract onDragThresholdExceeded(event: PointerEditorEvent): void;
60
+ }
61
+
62
+ /** Pointer/keyboard fields shared by pointer events and synthesized drag inputs. */
63
+ export interface DragApplyInput {
64
+ pagePoint: Vec;
65
+ shiftKey: boolean;
66
+ altKey: boolean;
67
+ accelKey: boolean;
68
+ }
69
+
70
+ /**
71
+ * Base for the active drag states (translate / resize / rotate / handle
72
+ * interaction). Centralises the identical event wiring: mark history on enter,
73
+ * apply on pointer-move, apply edge-scroll-aware input on tick, and re-apply the
74
+ * current input on key changes. Subclasses implement {@link apply} plus their own
75
+ * completion/cancellation and any extra cleanup.
76
+ */
77
+ export abstract class DraggingStateNode<T> extends InfoStateNode<T> {
78
+ /** Edge-scroll behaviour for this gesture's tick handling. */
79
+ protected abstract readonly tickMode: EdgeScrollTickMode;
80
+
81
+ /** History mark to open on enter (constant or derived from `info`). */
82
+ protected abstract getHistoryMark(info: T): string;
83
+
84
+ /** Apply one drag sample. Implementations must guard on `this.info`. */
85
+ protected abstract apply(input: DragApplyInput): void;
86
+
87
+ protected onInfoEnter(): void {
88
+ if (this.info) {
89
+ this.editor.history.mark(this.getHistoryMark(this.info));
90
+ }
91
+ this.onDragStart();
92
+ }
93
+
94
+ /** Extra setup after the history mark is opened (e.g. clearing indicators). */
95
+ protected onDragStart(): void {}
96
+
97
+ protected onPointerMove(event: PointerEditorEvent): void {
98
+ this.apply(event);
99
+ }
100
+
101
+ protected onTick(event: TickEditorEvent): void {
102
+ if (!this.info) {
103
+ return;
104
+ }
105
+ const input = getSelectionDragInputForTick(
106
+ this.editor,
107
+ event,
108
+ this.tickMode,
109
+ );
110
+ if (input) {
111
+ this.apply(input);
112
+ }
113
+ }
114
+
115
+ protected onKeyDown(): void {
116
+ this.applyFromInputs();
117
+ }
118
+
119
+ protected onKeyUp(): void {
120
+ this.applyFromInputs();
121
+ }
122
+
123
+ protected applyFromInputs(): void {
124
+ applySelectionDragFromCurrentInputs(this.editor, (input) =>
125
+ this.apply(input),
126
+ );
127
+ }
128
+ }
@@ -0,0 +1,139 @@
1
+ import type { Editor } from "../../../editor/Editor";
2
+ import { Vec } from "../../../geometry/Vec";
3
+ import { StateNode } from "../../../editor/StateNode";
4
+ import {
5
+ applyContainmentParent,
6
+ updateDropTarget,
7
+ } from "../selectContainment";
8
+ import {
9
+ TRANSLATE_HISTORY_MARK,
10
+ TRANSLATE_SNAP_DISTANCE_SCREEN,
11
+ TRANSLATE_SNAP_MAX_SCREEN_VELOCITY,
12
+ type TranslatingInfo,
13
+ } from "../selectToolHelpers";
14
+ import { DraggingStateNode, type DragApplyInput } from "./SelectStateNode";
15
+
16
+ export class TranslatingState extends DraggingStateNode<TranslatingInfo> {
17
+ protected readonly tickMode = "always_apply" as const;
18
+
19
+ constructor(editor: Editor, parent: StateNode) {
20
+ super(editor, "translating", parent);
21
+ }
22
+
23
+ protected getHistoryMark(): string {
24
+ return TRANSLATE_HISTORY_MARK;
25
+ }
26
+
27
+ protected onDragStart(): void {
28
+ this.editor.setSnapIndicators(null);
29
+ }
30
+
31
+ protected onPointerUp(): void {
32
+ this.complete();
33
+ }
34
+
35
+ protected onCancel(): void {
36
+ if (this.info) {
37
+ this.editor.commands.setSelectedShapeIds(this.info.previousSelection, {
38
+ source: "system",
39
+ });
40
+ }
41
+ this.cancel();
42
+ }
43
+
44
+ protected onInfoExit(): void {
45
+ this.editor.setSnapIndicators(null);
46
+ }
47
+
48
+ protected apply({ pagePoint, shiftKey, accelKey }: DragApplyInput): void {
49
+ if (!this.info) {
50
+ return;
51
+ }
52
+
53
+ const rawDeltaX = pagePoint.x - this.info.originPagePoint.x;
54
+ const rawDeltaY = pagePoint.y - this.info.originPagePoint.y;
55
+ if (!shiftKey) {
56
+ this.info.lockedAxis = null;
57
+ } else if (!this.info.lockedAxis && (rawDeltaX !== 0 || rawDeltaY !== 0)) {
58
+ this.info.lockedAxis =
59
+ Math.abs(rawDeltaX) >= Math.abs(rawDeltaY) ? "x" : "y";
60
+ }
61
+
62
+ let deltaX = rawDeltaX;
63
+ let deltaY = rawDeltaY;
64
+ if (this.info.lockedAxis === "x") {
65
+ deltaY = 0;
66
+ } else if (this.info.lockedAxis === "y") {
67
+ deltaX = 0;
68
+ }
69
+
70
+ const startBounds = this.info.startBounds;
71
+ const canSnap =
72
+ !accelKey &&
73
+ !!startBounds &&
74
+ (this.info.snapSnapshot.points.length > 0 ||
75
+ this.info.snapSnapshot.nodes.length > 0) &&
76
+ this.editor.inputs.state.get().screenVelocity.len() <
77
+ TRANSLATE_SNAP_MAX_SCREEN_VELOCITY;
78
+
79
+ if (canSnap && startBounds) {
80
+ const snapRotation = this.info.snapRotation;
81
+ const snapThreshold =
82
+ TRANSLATE_SNAP_DISTANCE_SCREEN / this.editor.getCurrentCamera().z;
83
+ const translatedDelta =
84
+ snapRotation === 0
85
+ ? new Vec(deltaX, deltaY)
86
+ : new Vec(deltaX, deltaY).rot(-snapRotation);
87
+ const { nudge: snapOffset } = this.editor.snaps.snapTranslate({
88
+ lockedAxis: this.info.lockedAxis,
89
+ initialSelectionBounds: startBounds,
90
+ dragDelta: translatedDelta,
91
+ snapshot: this.info.snapSnapshot,
92
+ threshold: snapThreshold,
93
+ });
94
+ const pageSnapOffset =
95
+ snapRotation === 0 ? snapOffset : snapOffset.rot(snapRotation);
96
+
97
+ deltaX += this.info.lockedAxis === "y" ? 0 : pageSnapOffset.x;
98
+ deltaY += this.info.lockedAxis === "x" ? 0 : pageSnapOffset.y;
99
+ } else {
100
+ this.editor.snaps.clearIndicators();
101
+ }
102
+
103
+ if (deltaX === this.info.lastDeltaX && deltaY === this.info.lastDeltaY) {
104
+ return;
105
+ }
106
+ this.info.lastDeltaX = deltaX;
107
+ this.info.lastDeltaY = deltaY;
108
+
109
+ for (let index = 0; index < this.info.selectedShapes.length; index += 1) {
110
+ const shape = this.info.selectedShapes[index];
111
+ const update = this.info.updates[index];
112
+ if (!shape || !update) {
113
+ continue;
114
+ }
115
+ update.x = shape.x + deltaX;
116
+ update.y = shape.y + deltaY;
117
+ }
118
+
119
+ this.editor.commands.updateShapes(this.info.updates);
120
+ updateDropTarget(this.editor, this.info.selectedShapeIds);
121
+ }
122
+
123
+ private complete(): void {
124
+ if (this.info) {
125
+ applyContainmentParent(this.editor, this.info.selectedShapeIds);
126
+ }
127
+ this.editor.setDropTargetShapeId(null);
128
+ this.editor.setSnapIndicators(null);
129
+ this.editor.history.squashToMark(TRANSLATE_HISTORY_MARK);
130
+ this.transition("idle");
131
+ }
132
+
133
+ private cancel(): void {
134
+ this.editor.setDropTargetShapeId(null);
135
+ this.editor.setSnapIndicators(null);
136
+ this.editor.history.bailToMark(TRANSLATE_HISTORY_MARK);
137
+ this.transition("idle");
138
+ }
139
+ }