@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,444 @@
1
+ import {
2
+ StateNode,
3
+ Vec,
4
+ reparentShapeToContainingParent,
5
+ type Editor,
6
+ type PointerEditorEvent,
7
+ type ShapeId,
8
+ } from "@land/canvas-core";
9
+ import {
10
+ appendGuardedDrawPoint,
11
+ getDrawInputPointGuardOptions,
12
+ getDrawSegmentPointLimit,
13
+ type DrawInputPointGuardOptions,
14
+ } from "./drawPath";
15
+ import { cloneDrawShapeSegmentsForUpdate } from "./drawGeometry";
16
+ import type {
17
+ DrawShapePoint,
18
+ DrawShapeProps,
19
+ DrawShapeRecord,
20
+ DrawShapeSegment,
21
+ } from "./types";
22
+
23
+ const DRAW_CREATE_HISTORY_MARK = "draw.create";
24
+ const DRAW_CREATE_THRESHOLD = 2;
25
+ const DRAW_UPDATE_FALLBACK_DELAY_MS = 16;
26
+
27
+ type DrawUpdateFrame =
28
+ | { type: "animation"; id: number }
29
+ | { type: "timeout"; id: ReturnType<typeof setTimeout> };
30
+
31
+ interface DrawingInfo {
32
+ originPagePoint: Vec;
33
+ shapeId: ShapeId | null;
34
+ segments: DrawShapeSegment[];
35
+ stroke: DrawShapeProps["stroke"];
36
+ strokeWidth: DrawShapeProps["strokeWidth"];
37
+ fill: DrawShapeProps["fill"];
38
+ isClosed: DrawShapeProps["isClosed"];
39
+ isPen: boolean;
40
+ pointGuard: DrawInputPointGuardOptions;
41
+ straightSegmentAnchorPoint: DrawShapePoint | null;
42
+ preserveStraightEndpointOnNextFreePoint: boolean;
43
+ }
44
+
45
+ export class DrawTool extends StateNode {
46
+ constructor(editor: Editor) {
47
+ super(editor, "draw");
48
+ this.initial = "idle";
49
+ this.addChild(new DrawIdleState(editor, this));
50
+ this.addChild(new DrawDrawingState(editor, this));
51
+ }
52
+
53
+ getDefaultProps(): DrawShapeProps {
54
+ return this.editor.getDefaultShapeProps<DrawShapeProps>("draw");
55
+ }
56
+ }
57
+
58
+ class DrawIdleState extends StateNode {
59
+ constructor(editor: Editor, parent: DrawTool) {
60
+ super(editor, "idle", parent);
61
+ }
62
+
63
+ protected onEnter(): void {
64
+ this.editor.clearSelectionTransients();
65
+ }
66
+
67
+ protected onPointerDown(event: PointerEditorEvent): void {
68
+ const defaultProps = (this.parent as DrawTool).getDefaultProps();
69
+ this.transition("drawing", {
70
+ originPagePoint: event.pagePoint.clone(),
71
+ shapeId: null,
72
+ stroke: defaultProps.stroke,
73
+ strokeWidth: defaultProps.strokeWidth,
74
+ fill: defaultProps.fill,
75
+ isClosed: defaultProps.isClosed,
76
+ isPen: event.pointerType === "pen",
77
+ pointGuard: getDrawInputPointGuardOptions(
78
+ defaultProps.strokeWidth,
79
+ event.pointerType === "pen",
80
+ ),
81
+ straightSegmentAnchorPoint: null,
82
+ preserveStraightEndpointOnNextFreePoint: false,
83
+ segments: [
84
+ {
85
+ points: [
86
+ toLocalDrawPoint(
87
+ event.pagePoint,
88
+ event.pagePoint,
89
+ event.pressure,
90
+ event.pointerType === "pen",
91
+ ),
92
+ ],
93
+ },
94
+ ],
95
+ } satisfies DrawingInfo);
96
+ }
97
+ }
98
+
99
+ class DrawDrawingState extends StateNode {
100
+ private info: DrawingInfo | null = null;
101
+ private pendingUpdateFrame: DrawUpdateFrame | null = null;
102
+
103
+ constructor(
104
+ editor: Editor,
105
+ private readonly tool: DrawTool,
106
+ ) {
107
+ super(editor, "drawing", tool);
108
+ }
109
+
110
+ protected onEnter(info?: unknown): void {
111
+ this.info = info as DrawingInfo;
112
+ this.editor.clearSelectionTransients();
113
+ this.editor.commands.setSelectedShapeIds([], { source: "system" });
114
+ this.editor.history.mark(DRAW_CREATE_HISTORY_MARK);
115
+ }
116
+
117
+ protected onPointerMove(event: PointerEditorEvent): void {
118
+ this.appendPoint(event, false);
119
+ }
120
+
121
+ protected onPointerUp(event: PointerEditorEvent): void {
122
+ this.appendPoint(event, true);
123
+ this.flushShapeUpdate();
124
+
125
+ const shapeId = this.info?.shapeId ?? null;
126
+ if (!shapeId) {
127
+ this.editor.history.bailToMark(DRAW_CREATE_HISTORY_MARK);
128
+ this.transition("idle");
129
+ return;
130
+ }
131
+
132
+ reparentShapeToContainingParent(this.editor, shapeId, {
133
+ source: "user",
134
+ });
135
+ this.editor.history.squashToMark(DRAW_CREATE_HISTORY_MARK);
136
+ this.transition("idle");
137
+ }
138
+
139
+ protected onCancel(): void {
140
+ this.cancelScheduledShapeUpdate();
141
+ this.editor.history.bailToMark(DRAW_CREATE_HISTORY_MARK);
142
+ this.transition("idle");
143
+ }
144
+
145
+ protected onExit(): void {
146
+ this.cancelScheduledShapeUpdate();
147
+ this.info = null;
148
+ }
149
+
150
+ private appendPoint(
151
+ event: PointerEditorEvent,
152
+ allowCreate: boolean,
153
+ ): void {
154
+ if (!this.info) {
155
+ return;
156
+ }
157
+
158
+ const point = toLocalDrawPoint(
159
+ event.pagePoint,
160
+ this.info.originPagePoint,
161
+ event.pressure,
162
+ this.info.isPen,
163
+ );
164
+
165
+ if (event.shiftKey) {
166
+ this.appendStraightSegmentPoint(point);
167
+ } else {
168
+ this.exitStraightSegmentMode();
169
+ if (this.info.preserveStraightEndpointOnNextFreePoint) {
170
+ if (this.appendDistinctCurrentPoint(point)) {
171
+ this.info.preserveStraightEndpointOnNextFreePoint = false;
172
+ }
173
+ } else {
174
+ this.appendGuardedCurrentPoint(point);
175
+ }
176
+ }
177
+ this.splitCurrentSegmentAtLimit();
178
+
179
+ if (!this.info.shapeId) {
180
+ const dragDistance = this.info.originPagePoint.dist(event.pagePoint);
181
+ if (!allowCreate && dragDistance < DRAW_CREATE_THRESHOLD) {
182
+ return;
183
+ }
184
+
185
+ const created = this.createShape();
186
+ this.info.shapeId = created.id;
187
+ return;
188
+ }
189
+
190
+ this.scheduleShapeUpdate();
191
+ }
192
+
193
+ private scheduleShapeUpdate(): void {
194
+ if (this.pendingUpdateFrame !== null) {
195
+ return;
196
+ }
197
+
198
+ this.pendingUpdateFrame = scheduleDrawUpdateFrame(() => {
199
+ this.pendingUpdateFrame = null;
200
+ this.flushShapeUpdate();
201
+ });
202
+ }
203
+
204
+ private cancelScheduledShapeUpdate(): void {
205
+ if (this.pendingUpdateFrame === null) {
206
+ return;
207
+ }
208
+
209
+ cancelDrawUpdateFrame(this.pendingUpdateFrame);
210
+ this.pendingUpdateFrame = null;
211
+ }
212
+
213
+ private flushShapeUpdate(): void {
214
+ this.cancelScheduledShapeUpdate();
215
+ if (!this.info?.shapeId) {
216
+ return;
217
+ }
218
+
219
+ this.editor.commands.updateShapes(
220
+ [
221
+ {
222
+ id: this.info.shapeId,
223
+ props: getDrawShapePropsForSegments(this.info.segments),
224
+ },
225
+ ],
226
+ { source: "user" },
227
+ );
228
+ }
229
+
230
+ private createShape(): DrawShapeRecord {
231
+ const defaultProps = this.tool.getDefaultProps();
232
+ const [created] = this.editor.commands.createShapes(
233
+ [
234
+ {
235
+ type: "draw",
236
+ x: this.info?.originPagePoint.x ?? 0,
237
+ y: this.info?.originPagePoint.y ?? 0,
238
+ props: {
239
+ ...defaultProps,
240
+ stroke: this.info?.stroke ?? defaultProps.stroke,
241
+ strokeWidth:
242
+ this.info?.strokeWidth ?? defaultProps.strokeWidth,
243
+ fill: this.info?.fill ?? defaultProps.fill,
244
+ isClosed: this.info?.isClosed ?? defaultProps.isClosed,
245
+ ...getDrawShapePropsForSegments(this.info?.segments ?? []),
246
+ isPen: this.info?.isPen ?? false,
247
+ },
248
+ },
249
+ ],
250
+ { source: "user" },
251
+ );
252
+
253
+ if (!created || created.type !== "draw") {
254
+ throw new Error("Failed to create draw shape");
255
+ }
256
+
257
+ return created as DrawShapeRecord;
258
+ }
259
+
260
+ private appendStraightSegmentPoint(point: DrawShapePoint): void {
261
+ if (!this.info) {
262
+ return;
263
+ }
264
+
265
+ this.info.preserveStraightEndpointOnNextFreePoint = false;
266
+
267
+ const points = getCurrentSegmentPoints(this.info);
268
+ const lastPoint = points[points.length - 1];
269
+ if (!this.info.straightSegmentAnchorPoint) {
270
+ if (!lastPoint) {
271
+ this.replaceCurrentSegmentPoints([{ ...point, segment: "straight" }]);
272
+ return;
273
+ }
274
+
275
+ this.info.straightSegmentAnchorPoint = clonePoint(lastPoint);
276
+ }
277
+
278
+ const straightPoint: DrawShapePoint = {
279
+ ...point,
280
+ segment: "straight",
281
+ };
282
+ if (lastPoint?.segment === "straight") {
283
+ this.replaceCurrentSegmentPoints([
284
+ ...points.slice(0, -1),
285
+ straightPoint,
286
+ ]);
287
+ return;
288
+ }
289
+
290
+ this.replaceCurrentSegmentPoints([...points, straightPoint]);
291
+ }
292
+
293
+ private exitStraightSegmentMode(): void {
294
+ if (!this.info?.straightSegmentAnchorPoint) {
295
+ return;
296
+ }
297
+
298
+ this.info.straightSegmentAnchorPoint = null;
299
+ this.info.preserveStraightEndpointOnNextFreePoint = true;
300
+ }
301
+
302
+ private appendDistinctCurrentPoint(point: DrawShapePoint): boolean {
303
+ if (!this.info) {
304
+ return false;
305
+ }
306
+
307
+ const points = getCurrentSegmentPoints(this.info);
308
+ const previous = points[points.length - 1];
309
+ if (previous && arePointsEqual(previous, point)) {
310
+ return false;
311
+ }
312
+
313
+ this.replaceCurrentSegmentPoints([...points, clonePoint(point)]);
314
+ return true;
315
+ }
316
+
317
+ private appendGuardedCurrentPoint(point: DrawShapePoint): void {
318
+ if (!this.info) {
319
+ return;
320
+ }
321
+
322
+ const points = getCurrentSegmentPoints(this.info).map(clonePoint);
323
+ appendGuardedDrawPoint(points, point, this.info.pointGuard);
324
+ this.replaceCurrentSegmentPoints(points);
325
+ }
326
+
327
+ private replaceCurrentSegmentPoints(points: DrawShapePoint[]): void {
328
+ if (!this.info) {
329
+ return;
330
+ }
331
+
332
+ const segments = ensureDrawingSegments(this.info.segments);
333
+ this.info.segments = [
334
+ ...segments.slice(0, -1),
335
+ { points: points.map(clonePoint) },
336
+ ];
337
+ }
338
+
339
+ private splitCurrentSegmentAtLimit(): void {
340
+ if (!this.info) {
341
+ return;
342
+ }
343
+
344
+ const limit = getDrawSegmentPointLimit(this.info.isPen);
345
+ let segments = ensureDrawingSegments(this.info.segments);
346
+ let current = segments[segments.length - 1]!;
347
+
348
+ while (current.points.length > limit) {
349
+ const frozenPoints = current.points.slice(0, limit).map(clonePoint);
350
+ const overlapPoint = frozenPoints[frozenPoints.length - 1];
351
+ const overflowPoints = current.points.slice(limit).map(clonePoint);
352
+ if (!overlapPoint || overflowPoints.length === 0) {
353
+ break;
354
+ }
355
+
356
+ const nextCurrent: DrawShapeSegment = {
357
+ points: [clonePoint(overlapPoint), ...overflowPoints],
358
+ };
359
+ segments = [
360
+ ...segments.slice(0, -1),
361
+ { points: frozenPoints },
362
+ nextCurrent,
363
+ ];
364
+ current = nextCurrent;
365
+ }
366
+
367
+ this.info.segments = segments;
368
+ }
369
+ }
370
+
371
+ function toLocalDrawPoint(
372
+ pagePoint: Vec,
373
+ originPagePoint: Vec,
374
+ pressure: number,
375
+ isPen: boolean,
376
+ ): DrawShapePoint {
377
+ return {
378
+ x: pagePoint.x - originPagePoint.x,
379
+ y: pagePoint.y - originPagePoint.y,
380
+ ...(isPen && pressure > 0 ? { pressure } : null),
381
+ };
382
+ }
383
+
384
+ function clonePoint(point: DrawShapePoint): DrawShapePoint {
385
+ return {
386
+ x: point.x,
387
+ y: point.y,
388
+ ...(point.pressure === undefined ? null : { pressure: point.pressure }),
389
+ ...(point.segment === undefined ? null : { segment: point.segment }),
390
+ };
391
+ }
392
+
393
+ function getCurrentSegmentPoints(info: DrawingInfo): DrawShapePoint[] {
394
+ const segments = ensureDrawingSegments(info.segments);
395
+ const current = segments[segments.length - 1];
396
+ return current ? current.points.map(clonePoint) : [];
397
+ }
398
+
399
+ function ensureDrawingSegments(
400
+ segments: readonly DrawShapeSegment[],
401
+ ): DrawShapeSegment[] {
402
+ return segments.length > 0 ? [...segments] : [{ points: [] }];
403
+ }
404
+
405
+ function getDrawShapePropsForSegments(
406
+ segments: readonly DrawShapeSegment[],
407
+ ): Pick<DrawShapeProps, "segments"> {
408
+ const nextSegments = ensureDrawingSegments(segments);
409
+ return {
410
+ segments: cloneDrawShapeSegmentsForUpdate(nextSegments),
411
+ };
412
+ }
413
+
414
+ function arePointsEqual(a: DrawShapePoint, b: DrawShapePoint): boolean {
415
+ return (
416
+ a.x === b.x &&
417
+ a.y === b.y &&
418
+ a.pressure === b.pressure &&
419
+ a.segment === b.segment
420
+ );
421
+ }
422
+
423
+ function scheduleDrawUpdateFrame(callback: () => void): DrawUpdateFrame {
424
+ if (typeof requestAnimationFrame === "function") {
425
+ return {
426
+ type: "animation",
427
+ id: requestAnimationFrame(callback),
428
+ };
429
+ }
430
+
431
+ return {
432
+ type: "timeout",
433
+ id: setTimeout(callback, DRAW_UPDATE_FALLBACK_DELAY_MS),
434
+ };
435
+ }
436
+
437
+ function cancelDrawUpdateFrame(frame: DrawUpdateFrame): void {
438
+ if (frame.type === "animation") {
439
+ cancelAnimationFrame(frame.id);
440
+ return;
441
+ }
442
+
443
+ clearTimeout(frame.id);
444
+ }
@@ -0,0 +1,24 @@
1
+ import type {
2
+ LandCanvasPlugin,
3
+ ShapeRendererProps,
4
+ } from "@land/canvas-plugin-api";
5
+ import { DrawShapeSvg } from "./DrawShapeRenderer";
6
+ import type { DrawShapeRecord } from "./types";
7
+
8
+ export function createDrawCanvasPlugin(): LandCanvasPlugin {
9
+ return {
10
+ id: "land.draw.react",
11
+ setup(registerShapeRenderer) {
12
+ registerShapeRenderer({
13
+ type: "draw",
14
+ component: DrawShapeRenderer,
15
+ });
16
+ },
17
+ };
18
+ }
19
+
20
+ function DrawShapeRenderer({
21
+ shape,
22
+ }: ShapeRendererProps<DrawShapeRecord>) {
23
+ return <DrawShapeSvg shape={shape} />;
24
+ }