@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,319 @@
1
+ import { atom } from "@land/signals";
2
+ import type {
3
+ EditorEvent,
4
+ KeyboardEditorEvent,
5
+ PointerEditorEvent,
6
+ WheelEditorEvent,
7
+ } from "../events";
8
+ import { Vec } from "../../geometry/Vec";
9
+
10
+ export type InputDragPhase = "idle" | "pointing" | "dragging";
11
+
12
+ export interface InputsState {
13
+ originPagePoint: Vec | null;
14
+ currentPagePoint: Vec | null;
15
+ previousPagePoint: Vec | null;
16
+ originScreenPoint: Vec | null;
17
+ currentScreenPoint: Vec | null;
18
+ previousScreenPoint: Vec | null;
19
+ currentTimestamp: number | null;
20
+ previousTimestamp: number | null;
21
+ pageVelocity: Vec;
22
+ screenVelocity: Vec;
23
+ pointerId: number | null;
24
+ pointerType: PointerEditorEvent["pointerType"] | null;
25
+ buttons: number;
26
+ isPointing: boolean;
27
+ isDragging: boolean;
28
+ dragPhase: InputDragPhase;
29
+ shiftKey: boolean;
30
+ altKey: boolean;
31
+ ctrlKey: boolean;
32
+ metaKey: boolean;
33
+ accelKey: boolean;
34
+ }
35
+
36
+ const DRAG_DISTANCE = 3;
37
+ const DRAG_DISTANCE_SQUARED = DRAG_DISTANCE * DRAG_DISTANCE;
38
+
39
+ function getZeroVelocity(): Vec {
40
+ return Vec.Zero();
41
+ }
42
+
43
+ function getVelocity(previousPoint: Vec, currentPoint: Vec, elapsed: number): Vec {
44
+ if (elapsed <= 0) {
45
+ return getZeroVelocity();
46
+ }
47
+
48
+ const deltaX = currentPoint.x - previousPoint.x;
49
+ const deltaY = currentPoint.y - previousPoint.y;
50
+
51
+ if (deltaX === 0 && deltaY === 0) {
52
+ return getZeroVelocity();
53
+ }
54
+
55
+ return new Vec(deltaX / elapsed, deltaY / elapsed);
56
+ }
57
+
58
+ function areModifierKeysEqual(
59
+ state: InputsState,
60
+ event: KeyboardEditorEvent | PointerEditorEvent | WheelEditorEvent,
61
+ ): boolean {
62
+ return (
63
+ state.shiftKey === event.shiftKey &&
64
+ state.altKey === event.altKey &&
65
+ state.ctrlKey === event.ctrlKey &&
66
+ state.metaKey === event.metaKey &&
67
+ state.accelKey === event.accelKey
68
+ );
69
+ }
70
+
71
+ export class InputsManager {
72
+ readonly state = atom<InputsState>("inputs.state", {
73
+ originPagePoint: null,
74
+ currentPagePoint: null,
75
+ previousPagePoint: null,
76
+ originScreenPoint: null,
77
+ currentScreenPoint: null,
78
+ previousScreenPoint: null,
79
+ currentTimestamp: null,
80
+ previousTimestamp: null,
81
+ pageVelocity: getZeroVelocity(),
82
+ screenVelocity: getZeroVelocity(),
83
+ pointerId: null,
84
+ pointerType: null,
85
+ buttons: 0,
86
+ isPointing: false,
87
+ isDragging: false,
88
+ dragPhase: "idle",
89
+ shiftKey: false,
90
+ altKey: false,
91
+ ctrlKey: false,
92
+ metaKey: false,
93
+ accelKey: false,
94
+ });
95
+
96
+ setCurrentPointerPoint(input: {
97
+ timestamp: number;
98
+ pagePoint: Vec;
99
+ screenPoint: Vec;
100
+ shiftKey: boolean;
101
+ altKey: boolean;
102
+ ctrlKey: boolean;
103
+ metaKey: boolean;
104
+ accelKey: boolean;
105
+ }): void {
106
+ this.state.update((state) => {
107
+ if (
108
+ state.currentPagePoint?.equals(input.pagePoint) &&
109
+ state.currentScreenPoint?.equals(input.screenPoint) &&
110
+ state.currentTimestamp === input.timestamp &&
111
+ state.shiftKey === input.shiftKey &&
112
+ state.altKey === input.altKey &&
113
+ state.ctrlKey === input.ctrlKey &&
114
+ state.metaKey === input.metaKey &&
115
+ state.accelKey === input.accelKey
116
+ ) {
117
+ return state;
118
+ }
119
+
120
+ const previousPagePoint = state.currentPagePoint ?? input.pagePoint;
121
+ const previousScreenPoint = state.currentScreenPoint ?? input.screenPoint;
122
+ const previousTimestamp = state.currentTimestamp ?? input.timestamp;
123
+ const elapsed = input.timestamp - previousTimestamp;
124
+
125
+ return {
126
+ ...state,
127
+ previousPagePoint,
128
+ previousScreenPoint,
129
+ currentPagePoint: input.pagePoint,
130
+ currentScreenPoint: input.screenPoint,
131
+ previousTimestamp,
132
+ currentTimestamp: input.timestamp,
133
+ pageVelocity: getVelocity(
134
+ previousPagePoint,
135
+ input.pagePoint,
136
+ elapsed,
137
+ ),
138
+ screenVelocity: getVelocity(
139
+ previousScreenPoint,
140
+ input.screenPoint,
141
+ elapsed,
142
+ ),
143
+ shiftKey: input.shiftKey,
144
+ altKey: input.altKey,
145
+ ctrlKey: input.ctrlKey,
146
+ metaKey: input.metaKey,
147
+ accelKey: input.accelKey,
148
+ };
149
+ });
150
+ }
151
+
152
+ handleEvent(event: EditorEvent): void {
153
+ switch (event.type) {
154
+ case "pointer":
155
+ this.handlePointerEvent(event);
156
+ return;
157
+ case "keyboard":
158
+ this.handleKeyboardEvent(event);
159
+ return;
160
+ case "wheel":
161
+ this.handleWheelEvent(event);
162
+ return;
163
+ case "cancel":
164
+ this.resetPointer();
165
+ return;
166
+ }
167
+ }
168
+
169
+ resetPointer(): void {
170
+ this.state.update((state) => ({
171
+ ...state,
172
+ originPagePoint: null,
173
+ currentPagePoint: null,
174
+ previousPagePoint: null,
175
+ originScreenPoint: null,
176
+ currentScreenPoint: null,
177
+ previousScreenPoint: null,
178
+ currentTimestamp: null,
179
+ previousTimestamp: null,
180
+ pageVelocity: getZeroVelocity(),
181
+ screenVelocity: getZeroVelocity(),
182
+ pointerId: null,
183
+ pointerType: null,
184
+ buttons: 0,
185
+ isPointing: false,
186
+ isDragging: false,
187
+ dragPhase: "idle",
188
+ }));
189
+ }
190
+
191
+ private handlePointerEvent(event: PointerEditorEvent): void {
192
+ this.state.update((state) => {
193
+ switch (event.name) {
194
+ case "pointer_down":
195
+ return {
196
+ ...state,
197
+ originPagePoint: event.pagePoint,
198
+ currentPagePoint: event.pagePoint,
199
+ previousPagePoint: event.pagePoint,
200
+ originScreenPoint: event.screenPoint,
201
+ currentScreenPoint: event.screenPoint,
202
+ previousScreenPoint: event.screenPoint,
203
+ currentTimestamp: event.timestamp,
204
+ previousTimestamp: event.timestamp,
205
+ pageVelocity: getZeroVelocity(),
206
+ screenVelocity: getZeroVelocity(),
207
+ pointerId: event.pointerId,
208
+ pointerType: event.pointerType,
209
+ buttons: event.buttons,
210
+ isPointing: true,
211
+ isDragging: false,
212
+ dragPhase: "pointing",
213
+ shiftKey: event.shiftKey,
214
+ altKey: event.altKey,
215
+ ctrlKey: event.ctrlKey,
216
+ metaKey: event.metaKey,
217
+ accelKey: event.accelKey,
218
+ };
219
+ case "pointer_move": {
220
+ if (
221
+ state.currentPagePoint?.equals(event.pagePoint) &&
222
+ state.currentScreenPoint?.equals(event.screenPoint) &&
223
+ state.currentTimestamp === event.timestamp &&
224
+ state.buttons === event.buttons &&
225
+ areModifierKeysEqual(state, event)
226
+ ) {
227
+ return state;
228
+ }
229
+
230
+ const previous = state.currentPagePoint ?? event.pagePoint;
231
+ const previousScreen = state.currentScreenPoint ?? event.screenPoint;
232
+ const origin = state.originPagePoint ?? event.pagePoint;
233
+ const isDragging =
234
+ state.isDragging ||
235
+ origin.dist2(event.pagePoint) >= DRAG_DISTANCE_SQUARED;
236
+ const previousTimestamp = state.currentTimestamp ?? event.timestamp;
237
+ const elapsed = event.timestamp - previousTimestamp;
238
+ return {
239
+ ...state,
240
+ previousPagePoint: previous,
241
+ previousScreenPoint: previousScreen,
242
+ currentPagePoint: event.pagePoint,
243
+ currentScreenPoint: event.screenPoint,
244
+ previousTimestamp,
245
+ currentTimestamp: event.timestamp,
246
+ pageVelocity: getVelocity(previous, event.pagePoint, elapsed),
247
+ screenVelocity: getVelocity(
248
+ previousScreen,
249
+ event.screenPoint,
250
+ elapsed,
251
+ ),
252
+ buttons: event.buttons,
253
+ isDragging,
254
+ dragPhase: isDragging ? "dragging" : "pointing",
255
+ shiftKey: event.shiftKey,
256
+ altKey: event.altKey,
257
+ ctrlKey: event.ctrlKey,
258
+ metaKey: event.metaKey,
259
+ accelKey: event.accelKey,
260
+ };
261
+ }
262
+ case "pointer_up":
263
+ case "pointer_cancel":
264
+ return {
265
+ ...state,
266
+ previousPagePoint: state.currentPagePoint,
267
+ previousScreenPoint: state.currentScreenPoint,
268
+ currentPagePoint: event.pagePoint,
269
+ currentScreenPoint: event.screenPoint,
270
+ previousTimestamp: state.currentTimestamp,
271
+ currentTimestamp: event.timestamp,
272
+ pageVelocity: getZeroVelocity(),
273
+ screenVelocity: getZeroVelocity(),
274
+ buttons: event.buttons,
275
+ isPointing: false,
276
+ isDragging: false,
277
+ dragPhase: "idle",
278
+ shiftKey: event.shiftKey,
279
+ altKey: event.altKey,
280
+ ctrlKey: event.ctrlKey,
281
+ metaKey: event.metaKey,
282
+ accelKey: event.accelKey,
283
+ };
284
+ }
285
+ });
286
+ }
287
+
288
+ private handleKeyboardEvent(event: KeyboardEditorEvent): void {
289
+ this.state.update((state) => {
290
+ if (areModifierKeysEqual(state, event)) {
291
+ return state;
292
+ }
293
+ return {
294
+ ...state,
295
+ shiftKey: event.shiftKey,
296
+ altKey: event.altKey,
297
+ ctrlKey: event.ctrlKey,
298
+ metaKey: event.metaKey,
299
+ accelKey: event.accelKey,
300
+ };
301
+ });
302
+ }
303
+
304
+ private handleWheelEvent(event: WheelEditorEvent): void {
305
+ this.state.update((state) => {
306
+ if (areModifierKeysEqual(state, event)) {
307
+ return state;
308
+ }
309
+ return {
310
+ ...state,
311
+ shiftKey: event.shiftKey,
312
+ altKey: event.altKey,
313
+ ctrlKey: event.ctrlKey,
314
+ metaKey: event.metaKey,
315
+ accelKey: event.accelKey,
316
+ };
317
+ });
318
+ }
319
+ }
@@ -0,0 +1,218 @@
1
+ import { atom, computed, type Atom, type Signal } from "@land/signals";
2
+ import {
3
+ getFreeArrowTerminalBinding,
4
+ type ArrowTerminalBindingResolver,
5
+ type ArrowTerminalBindingResolverInput,
6
+ type ResolvedArrowTerminalBinding,
7
+ } from "../../bindings/arrow/arrowBindingHelpers";
8
+ import type { Box } from "../../geometry/Box";
9
+ import type { Vec } from "../../geometry/Vec";
10
+ import type { ShapeId } from "../../schema/records";
11
+ import type { Editor } from "../Editor";
12
+ import {
13
+ areBindingPreviewStatesEqual,
14
+ areBoxesEqual,
15
+ areShapeIdArraysEqual,
16
+ areVecArraysEqual,
17
+ } from "../editorComputedHelpers";
18
+ import type {
19
+ ArrowBindingPreviewState,
20
+ SnapIndicatorState,
21
+ } from "../selection";
22
+
23
+ export interface LaserTrailState {
24
+ sessionId: number;
25
+ phase: "active" | "ending";
26
+ points: Vec[];
27
+ }
28
+
29
+ export class InteractionTransientManager {
30
+ private readonly _brushBoxSignal: Atom<Box | null> = atom<Box | null>(
31
+ "editor.brushBox",
32
+ null,
33
+ );
34
+ readonly brushBoxSignal: Signal<Box | null> = this._brushBoxSignal;
35
+ readonly brushBoxActiveSignal = computed<boolean>(
36
+ "editor.brushBoxActive",
37
+ () => this._brushBoxSignal.get() !== null,
38
+ );
39
+
40
+ private readonly _erasingShapeIdsSignal: Atom<ShapeId[]> = atom<ShapeId[]>(
41
+ "editor.erasingShapeIds",
42
+ [],
43
+ );
44
+ readonly erasingShapeIdsSignal: Signal<ShapeId[]> =
45
+ this._erasingShapeIdsSignal;
46
+ readonly erasingShapeIdsActiveSignal = computed<boolean>(
47
+ "editor.erasingShapeIdsActive",
48
+ () => this._erasingShapeIdsSignal.get().length > 0,
49
+ );
50
+
51
+ private readonly _eraserTrailSignal: Atom<Vec[]> = atom<Vec[]>(
52
+ "editor.eraserTrail",
53
+ [],
54
+ );
55
+ readonly eraserTrailSignal: Signal<Vec[]> = this._eraserTrailSignal;
56
+ readonly eraserTrailActiveSignal = computed<boolean>(
57
+ "editor.eraserTrailActive",
58
+ () => this._eraserTrailSignal.get().length > 1,
59
+ );
60
+
61
+ private readonly _laserTrailSignal: Atom<LaserTrailState | null> =
62
+ atom<LaserTrailState | null>("editor.laserTrail", null);
63
+ readonly laserTrailSignal: Signal<LaserTrailState | null> =
64
+ this._laserTrailSignal;
65
+ readonly laserTrailActiveSignal = computed<boolean>(
66
+ "editor.laserTrailActive",
67
+ () => this._laserTrailSignal.get() !== null,
68
+ );
69
+ private nextLaserSessionId = 1;
70
+
71
+ private readonly _bindingPreviewSignal: Atom<ArrowBindingPreviewState | null> =
72
+ atom<ArrowBindingPreviewState | null>("editor.bindingPreview", null);
73
+ readonly bindingPreviewSignal: Signal<ArrowBindingPreviewState | null> =
74
+ this._bindingPreviewSignal;
75
+ readonly bindingPreviewActiveSignal = computed<boolean>(
76
+ "editor.bindingPreviewActive",
77
+ () => this._bindingPreviewSignal.get() !== null,
78
+ );
79
+
80
+ private readonly _dropTargetShapeIdSignal: Atom<ShapeId | null> =
81
+ atom<ShapeId | null>("editor.dropTargetShapeId", null);
82
+ readonly dropTargetShapeIdSignal: Signal<ShapeId | null> =
83
+ this._dropTargetShapeIdSignal;
84
+
85
+ private arrowTerminalBindingResolver: ArrowTerminalBindingResolver =
86
+ (_editor, input) => getFreeArrowTerminalBinding(input);
87
+
88
+ constructor(private readonly editor: Editor) {}
89
+
90
+ setBrushBox(brushBox: Box | null): void {
91
+ const current = this._brushBoxSignal.get();
92
+ if (areBoxesEqual(current, brushBox)) {
93
+ return;
94
+ }
95
+ this._brushBoxSignal.set(brushBox ? brushBox.clone() : null);
96
+ }
97
+
98
+ getErasingShapeIds(): ShapeId[] {
99
+ return [...this._erasingShapeIdsSignal.get()];
100
+ }
101
+
102
+ setErasingShapeIds(shapeIds: readonly ShapeId[]): void {
103
+ const uniqueIds = Array.from(new Set(shapeIds));
104
+ if (areShapeIdArraysEqual(this._erasingShapeIdsSignal.get(), uniqueIds)) {
105
+ return;
106
+ }
107
+ this._erasingShapeIdsSignal.set(uniqueIds);
108
+ }
109
+
110
+ clearErasingShapeIds(): void {
111
+ this.setErasingShapeIds([]);
112
+ }
113
+
114
+ getEraserTrail(): Vec[] {
115
+ return this._eraserTrailSignal.get().map((point) => point.clone());
116
+ }
117
+
118
+ setEraserTrail(points: readonly Vec[]): void {
119
+ const current = this._eraserTrailSignal.get();
120
+ if (areVecArraysEqual(current, points)) {
121
+ return;
122
+ }
123
+ this._eraserTrailSignal.set(points.map((point) => point.clone()));
124
+ }
125
+
126
+ clearEraserTrail(): void {
127
+ this.setEraserTrail([]);
128
+ }
129
+
130
+ startLaserTrail(): number {
131
+ const sessionId = this.nextLaserSessionId++;
132
+ this._laserTrailSignal.set({ sessionId, phase: "active", points: [] });
133
+ return sessionId;
134
+ }
135
+
136
+ setLaserTrail(sessionId: number, points: readonly Vec[]): void {
137
+ const current = this._laserTrailSignal.get();
138
+ if (!current || current.sessionId !== sessionId) {
139
+ return;
140
+ }
141
+ if (current.phase === "active" && areVecArraysEqual(current.points, points)) {
142
+ return;
143
+ }
144
+ this._laserTrailSignal.set({
145
+ sessionId,
146
+ phase: "active",
147
+ points: points.map((point) => point.clone()),
148
+ });
149
+ }
150
+
151
+ finishLaserTrail(sessionId: number): void {
152
+ const current = this._laserTrailSignal.get();
153
+ if (!current || current.sessionId !== sessionId || current.phase === "ending") {
154
+ return;
155
+ }
156
+ this._laserTrailSignal.set({ ...current, phase: "ending" });
157
+ }
158
+
159
+ clearLaserTrail(sessionId: number): void {
160
+ const current = this._laserTrailSignal.get();
161
+ if (!current || current.sessionId !== sessionId) {
162
+ return;
163
+ }
164
+ this._laserTrailSignal.set(null);
165
+ }
166
+
167
+ setBindingPreview(preview: ArrowBindingPreviewState | null): void {
168
+ const current = this._bindingPreviewSignal.get();
169
+ if (areBindingPreviewStatesEqual(current, preview)) {
170
+ return;
171
+ }
172
+ this._bindingPreviewSignal.set(
173
+ preview
174
+ ? {
175
+ ...preview,
176
+ rawPagePoint: preview.rawPagePoint.clone(),
177
+ resolvedPagePoint: preview.resolvedPagePoint.clone(),
178
+ }
179
+ : null,
180
+ );
181
+ }
182
+
183
+ setDropTargetShapeId(shapeId: ShapeId | null): void {
184
+ if (this._dropTargetShapeIdSignal.get() === shapeId) {
185
+ return;
186
+ }
187
+ this._dropTargetShapeIdSignal.set(shapeId);
188
+ }
189
+
190
+ setSnapIndicators(indicators: SnapIndicatorState[] | null): void {
191
+ if (indicators) {
192
+ this.editor.snaps.setIndicators(indicators);
193
+ } else {
194
+ this.editor.snaps.clearIndicators();
195
+ }
196
+ }
197
+
198
+ setArrowTerminalBindingResolver(
199
+ resolver: ArrowTerminalBindingResolver,
200
+ ): void {
201
+ this.arrowTerminalBindingResolver = resolver;
202
+ }
203
+
204
+ resolveArrowTerminalBinding(
205
+ input: ArrowTerminalBindingResolverInput,
206
+ ): ResolvedArrowTerminalBinding {
207
+ return this.arrowTerminalBindingResolver(this.editor, input);
208
+ }
209
+
210
+ clearSelectionTransients(): void {
211
+ this.setBrushBox(null);
212
+ this.clearErasingShapeIds();
213
+ this.clearEraserTrail();
214
+ this.setBindingPreview(null);
215
+ this.setDropTargetShapeId(null);
216
+ this.setSnapIndicators(null);
217
+ }
218
+ }