canvu-react 0.4.72 → 0.4.74

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.
package/dist/react.d.cts CHANGED
@@ -205,6 +205,10 @@ type ImagesMenuCollapsedButtonRenderProps = {
205
205
  */
206
206
  buttonProps: ImagesMenuCollapsedButtonProps;
207
207
  };
208
+ /**
209
+ * Built-in action ids available in each row of {@link ImagesMenu}.
210
+ */
211
+ type ImagesMenuActionId = "duplicate" | "rotate" | "delete";
208
212
  type ImagesMenuProps = {
209
213
  items: readonly VectorSceneItem[];
210
214
  onItemsChange: (items: VectorSceneItem[]) => void;
@@ -214,6 +218,22 @@ type ImagesMenuProps = {
214
218
  */
215
219
  onFocusItem?: (item: VectorSceneItem) => void;
216
220
  labels?: ImagesMenuLabels;
221
+ /**
222
+ * Built-in row actions to omit from the managed images menu UI.
223
+ *
224
+ * Use this when an app needs to keep the managed image behavior available in
225
+ * code while preventing specific actions from being shown to users.
226
+ *
227
+ * @example
228
+ * ```tsx
229
+ * <ImagesMenu
230
+ * items={items}
231
+ * onItemsChange={setItems}
232
+ * hiddenActions={["duplicate"]}
233
+ * />
234
+ * ```
235
+ */
236
+ hiddenActions?: readonly ImagesMenuActionId[];
217
237
  /**
218
238
  * Whether the menu starts expanded. Defaults to `false` (collapsed), showing
219
239
  * only the floating toggle button until the user opens it.
@@ -269,7 +289,7 @@ type ImagesMenuProps = {
269
289
  * drag-to-reorder actions. Managed images are also `locked`, so they do not
270
290
  * respond to direct canvas interaction.
271
291
  */
272
- declare function ImagesMenu({ items, onItemsChange, onFocusItem, labels, defaultOpen, collapsedButtonClassName, collapsedButtonStyle, renderCollapsedButton, }: ImagesMenuProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
292
+ declare function ImagesMenu({ items, onItemsChange, onFocusItem, labels, hiddenActions, defaultOpen, collapsedButtonClassName, collapsedButtonStyle, renderCollapsedButton, }: ImagesMenuProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
273
293
 
274
294
  type NavMenuMinimapProps = {
275
295
  className?: string;
@@ -825,4 +845,4 @@ type VectorToolbarWithStatics = ((props: VectorToolbarProps) => ReactElement) &
825
845
  */
826
846
  declare const VectorToolbar: VectorToolbarWithStatics;
827
847
 
828
- export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
848
+ export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuActionId, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
package/dist/react.d.ts CHANGED
@@ -205,6 +205,10 @@ type ImagesMenuCollapsedButtonRenderProps = {
205
205
  */
206
206
  buttonProps: ImagesMenuCollapsedButtonProps;
207
207
  };
208
+ /**
209
+ * Built-in action ids available in each row of {@link ImagesMenu}.
210
+ */
211
+ type ImagesMenuActionId = "duplicate" | "rotate" | "delete";
208
212
  type ImagesMenuProps = {
209
213
  items: readonly VectorSceneItem[];
210
214
  onItemsChange: (items: VectorSceneItem[]) => void;
@@ -214,6 +218,22 @@ type ImagesMenuProps = {
214
218
  */
215
219
  onFocusItem?: (item: VectorSceneItem) => void;
216
220
  labels?: ImagesMenuLabels;
221
+ /**
222
+ * Built-in row actions to omit from the managed images menu UI.
223
+ *
224
+ * Use this when an app needs to keep the managed image behavior available in
225
+ * code while preventing specific actions from being shown to users.
226
+ *
227
+ * @example
228
+ * ```tsx
229
+ * <ImagesMenu
230
+ * items={items}
231
+ * onItemsChange={setItems}
232
+ * hiddenActions={["duplicate"]}
233
+ * />
234
+ * ```
235
+ */
236
+ hiddenActions?: readonly ImagesMenuActionId[];
217
237
  /**
218
238
  * Whether the menu starts expanded. Defaults to `false` (collapsed), showing
219
239
  * only the floating toggle button until the user opens it.
@@ -269,7 +289,7 @@ type ImagesMenuProps = {
269
289
  * drag-to-reorder actions. Managed images are also `locked`, so they do not
270
290
  * respond to direct canvas interaction.
271
291
  */
272
- declare function ImagesMenu({ items, onItemsChange, onFocusItem, labels, defaultOpen, collapsedButtonClassName, collapsedButtonStyle, renderCollapsedButton, }: ImagesMenuProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
292
+ declare function ImagesMenu({ items, onItemsChange, onFocusItem, labels, hiddenActions, defaultOpen, collapsedButtonClassName, collapsedButtonStyle, renderCollapsedButton, }: ImagesMenuProps): string | number | bigint | boolean | Iterable<ReactNode> | Promise<string | number | bigint | boolean | react.ReactPortal | react.ReactElement<unknown, string | react.JSXElementConstructor<any>> | Iterable<ReactNode> | null | undefined> | react_jsx_runtime.JSX.Element | null | undefined;
273
293
 
274
294
  type NavMenuMinimapProps = {
275
295
  className?: string;
@@ -825,4 +845,4 @@ type VectorToolbarWithStatics = ((props: VectorToolbarProps) => ReactElement) &
825
845
  */
826
846
  declare const VectorToolbar: VectorToolbarWithStatics;
827
847
 
828
- export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
848
+ export { BoardComponentPosition, CanvasPlugin, CanvuAfterInteractionHook, CanvuBeforeInteractionHook, type CreateLocalStoragePersistenceAdapterOptions, type CreateToolPluginOptions, CustomShapePlacementOptions, DEFAULT_OVERFLOW_TOOL_IDS, DEFAULT_VECTOR_CANVAS_STORAGE_KEY, DEFAULT_VECTOR_TOOLS, IconArchitecturalCloud, IconArrow, IconDraw, IconEllipse, IconHand, IconImage, IconLaser, IconLine, IconRect, IconSelect, IconText, ImagesMenu, type ImagesMenuActionId, type ImagesMenuCollapsedButtonProps, type ImagesMenuCollapsedButtonRenderProps, type ImagesMenuLabels, type ImagesMenuProps, type IngestAssetFileError, type IngestAssetFilesToSceneItemsOptions, type IngestAssetFilesToSceneItemsResult, type IngestedAssetItemContext, NavMenu, type NavMenuMinimapProps, type NavMenuProps, type NavMenuUndoRedoProps, type NavMenuZoomControlsProps, type UseVectorCanvasDocumentOptions, type UseVectorCanvasDocumentResult, VectorCanvas, VectorCanvasBody, VectorCanvasHeader, VectorCanvasMain, VectorCanvasPersistenceAdapter, VectorCanvasRemoteAdapter, VectorCanvasRoot, type VectorCanvasSlotProps, type VectorCanvasSpaceProps, VectorCanvasToolbar, type VectorCanvasToolbarProps, VectorCanvasViewportSurface, VectorSelectionInspector, VectorToolDefinition, VectorToolbar, type VectorToolbarOverflowProps, type VectorToolbarProps, type VectorToolbarRenderContext, type VectorToolbarToolLockProps, type VectorToolbarToolProps, VectorViewportAssetKind, VectorViewportAssetStore, createIndexedDbPersistenceAdapter, createLocalStoragePersistenceAdapter, createNoopPersistenceAdapter, createToolPlugin, cursorForVectorToolId, ingestAssetFilesToSceneItems, useVectorCanvasDocument };
package/dist/react.js CHANGED
@@ -2253,6 +2253,7 @@ function ImagesMenu({
2253
2253
  onItemsChange,
2254
2254
  onFocusItem,
2255
2255
  labels,
2256
+ hiddenActions,
2256
2257
  defaultOpen = false,
2257
2258
  collapsedButtonClassName,
2258
2259
  collapsedButtonStyle,
@@ -2268,6 +2269,10 @@ function ImagesMenu({
2268
2269
  useEffect(() => {
2269
2270
  ensureOpenKeyframe();
2270
2271
  }, []);
2272
+ const hiddenActionSet = useMemo(
2273
+ () => new Set(hiddenActions ?? []),
2274
+ [hiddenActions]
2275
+ );
2271
2276
  if (managed.length === 0) {
2272
2277
  return null;
2273
2278
  }
@@ -2342,6 +2347,7 @@ function ImagesMenu({
2342
2347
  {
2343
2348
  item,
2344
2349
  labels: resolvedLabels,
2350
+ hiddenActionSet,
2345
2351
  onFocus: onFocusItem ? () => onFocusItem(item) : void 0,
2346
2352
  onCopy: () => onItemsChange(copyManagedImage(items, item.id)),
2347
2353
  onRotate: () => onItemsChange(rotateManagedImage(items, item.id)),
@@ -2358,6 +2364,7 @@ function ImagesMenu({
2358
2364
  function ImagesMenuRow({
2359
2365
  item,
2360
2366
  labels,
2367
+ hiddenActionSet,
2361
2368
  onFocus,
2362
2369
  onCopy,
2363
2370
  onRotate,
@@ -2397,9 +2404,9 @@ function ImagesMenuRow({
2397
2404
  ),
2398
2405
  /* @__PURE__ */ jsx(FocusTarget, { label: labels.focus, onFocus, children: /* @__PURE__ */ jsx("div", { style: thumbBoxStyle, children: src ? /* @__PURE__ */ jsx("img", { src, alt: "", style: thumbImgStyle, draggable: false }) : null }) }),
2399
2406
  /* @__PURE__ */ jsxs("div", { style: actionsColumnStyle, children: [
2400
- /* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.duplicate, onClick: onCopy, children: /* @__PURE__ */ jsx(CopyPlus, { size: 18 }) }),
2401
- /* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.rotate, onClick: onRotate, children: /* @__PURE__ */ jsx(RotateCw, { size: 18 }) }),
2402
- /* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.delete, onClick: onDelete, danger: true, children: /* @__PURE__ */ jsx(Trash2, { size: 18 }) })
2407
+ !hiddenActionSet.has("duplicate") ? /* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.duplicate, onClick: onCopy, children: /* @__PURE__ */ jsx(CopyPlus, { size: 18 }) }) : null,
2408
+ !hiddenActionSet.has("rotate") ? /* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.rotate, onClick: onRotate, children: /* @__PURE__ */ jsx(RotateCw, { size: 18 }) }) : null,
2409
+ !hiddenActionSet.has("delete") ? /* @__PURE__ */ jsx(ImagesMenuAction, { label: labels.delete, onClick: onDelete, danger: true, children: /* @__PURE__ */ jsx(Trash2, { size: 18 }) }) : null
2403
2410
  ] })
2404
2411
  ] });
2405
2412
  }
@@ -8547,6 +8554,11 @@ function shallowEqualStringArray(a, b) {
8547
8554
 
8548
8555
  // src/react/stroke-input.ts
8549
8556
  var MAX_INTERPOLATED_POINTS_PER_SAMPLE = 192;
8557
+ var MIN_CURVED_INTERPOLATION_DOT = -0.15;
8558
+ var MAX_STRAIGHT_INTERPOLATION_DOT = 0.985;
8559
+ var CURVED_INTERPOLATION_TENSION = 0.22;
8560
+ var MAX_CURVED_CONTROL_DISTANCE_RATIO = 0.5;
8561
+ var MIN_POINT_DISTANCE_SQUARED = 1e-12;
8550
8562
  function getPointerEventSamples(event) {
8551
8563
  if (typeof event.getCoalescedEvents !== "function") {
8552
8564
  return [event];
@@ -8561,6 +8573,62 @@ var resolveInterpolatedPressure = (lastPoint, nextPoint, ratio) => {
8561
8573
  return ratio === 1 ? nextPoint.pressure : void 0;
8562
8574
  };
8563
8575
  var resolveMaxStepWorld = (maxStepWorld) => Number.isFinite(maxStepWorld) && maxStepWorld > 0 ? maxStepWorld : Number.POSITIVE_INFINITY;
8576
+ var squaredDistance = (firstPoint, secondPoint) => {
8577
+ const deltaX = secondPoint.x - firstPoint.x;
8578
+ const deltaY = secondPoint.y - firstPoint.y;
8579
+ return deltaX * deltaX + deltaY * deltaY;
8580
+ };
8581
+ var resolvePreviousDistinctPoint = (points, lastPoint) => {
8582
+ for (let index = points.length - 2; index >= 0; index--) {
8583
+ const candidatePoint = points[index];
8584
+ if (candidatePoint && squaredDistance(candidatePoint, lastPoint) > MIN_POINT_DISTANCE_SQUARED) {
8585
+ return candidatePoint;
8586
+ }
8587
+ }
8588
+ return void 0;
8589
+ };
8590
+ var shouldUseCurvedInterpolation = (previousPoint, lastPoint, nextPoint) => {
8591
+ if (!previousPoint) return false;
8592
+ const incomingX = lastPoint.x - previousPoint.x;
8593
+ const incomingY = lastPoint.y - previousPoint.y;
8594
+ const outgoingX = nextPoint.x - lastPoint.x;
8595
+ const outgoingY = nextPoint.y - lastPoint.y;
8596
+ const incomingLengthSquared = incomingX * incomingX + incomingY * incomingY;
8597
+ const outgoingLengthSquared = outgoingX * outgoingX + outgoingY * outgoingY;
8598
+ if (incomingLengthSquared <= MIN_POINT_DISTANCE_SQUARED || outgoingLengthSquared <= MIN_POINT_DISTANCE_SQUARED) {
8599
+ return false;
8600
+ }
8601
+ const directionDot = (incomingX * outgoingX + incomingY * outgoingY) / Math.sqrt(incomingLengthSquared * outgoingLengthSquared);
8602
+ return directionDot >= MIN_CURVED_INTERPOLATION_DOT && directionDot <= MAX_STRAIGHT_INTERPOLATION_DOT;
8603
+ };
8604
+ var resolveCurvedControlPoint = (previousPoint, lastPoint, nextPoint, distance) => {
8605
+ const tangentX = nextPoint.x - previousPoint.x;
8606
+ const tangentY = nextPoint.y - previousPoint.y;
8607
+ const tangentLength = Math.sqrt(tangentX * tangentX + tangentY * tangentY);
8608
+ if (tangentLength <= MIN_POINT_DISTANCE_SQUARED) return void 0;
8609
+ const controlDistance = Math.min(
8610
+ distance * MAX_CURVED_CONTROL_DISTANCE_RATIO,
8611
+ tangentLength * CURVED_INTERPOLATION_TENSION
8612
+ );
8613
+ const scale = controlDistance / tangentLength;
8614
+ return {
8615
+ x: lastPoint.x + tangentX * scale,
8616
+ y: lastPoint.y + tangentY * scale
8617
+ };
8618
+ };
8619
+ var resolveInterpolatedPosition = (lastPoint, nextPoint, controlPoint, ratio) => {
8620
+ if (!controlPoint) {
8621
+ return {
8622
+ x: lastPoint.x + (nextPoint.x - lastPoint.x) * ratio,
8623
+ y: lastPoint.y + (nextPoint.y - lastPoint.y) * ratio
8624
+ };
8625
+ }
8626
+ const inverseRatio = 1 - ratio;
8627
+ return {
8628
+ x: inverseRatio * inverseRatio * lastPoint.x + 2 * inverseRatio * ratio * controlPoint.x + ratio * ratio * nextPoint.x,
8629
+ y: inverseRatio * inverseRatio * lastPoint.y + 2 * inverseRatio * ratio * controlPoint.y + ratio * ratio * nextPoint.y
8630
+ };
8631
+ };
8564
8632
  function appendInterpolatedStrokePoint(points, nextPoint, maxStepWorld) {
8565
8633
  if (points.length === 0) return [nextPoint];
8566
8634
  const lastPoint = points[points.length - 1];
@@ -8568,19 +8636,31 @@ function appendInterpolatedStrokePoint(points, nextPoint, maxStepWorld) {
8568
8636
  const deltaX = nextPoint.x - lastPoint.x;
8569
8637
  const deltaY = nextPoint.y - lastPoint.y;
8570
8638
  const distanceSquared = deltaX * deltaX + deltaY * deltaY;
8571
- if (distanceSquared < 1e-12) return points;
8639
+ if (distanceSquared < MIN_POINT_DISTANCE_SQUARED) return points;
8572
8640
  const distance = Math.sqrt(distanceSquared);
8573
8641
  const stepCount = Math.min(
8574
8642
  MAX_INTERPOLATED_POINTS_PER_SAMPLE,
8575
8643
  Math.max(1, Math.ceil(distance / resolveMaxStepWorld(maxStepWorld)))
8576
8644
  );
8577
8645
  if (stepCount === 1) return [...points, nextPoint];
8646
+ const previousPoint = resolvePreviousDistinctPoint(points, lastPoint);
8647
+ const controlPoint = shouldUseCurvedInterpolation(
8648
+ previousPoint,
8649
+ lastPoint,
8650
+ nextPoint
8651
+ ) ? resolveCurvedControlPoint(previousPoint, lastPoint, nextPoint, distance) : void 0;
8578
8652
  const interpolatedPoints = Array.from({ length: stepCount }, (_, index) => {
8579
8653
  const ratio = (index + 1) / stepCount;
8580
8654
  const pressure = resolveInterpolatedPressure(lastPoint, nextPoint, ratio);
8655
+ const position = resolveInterpolatedPosition(
8656
+ lastPoint,
8657
+ nextPoint,
8658
+ controlPoint,
8659
+ ratio
8660
+ );
8581
8661
  return {
8582
- x: lastPoint.x + deltaX * ratio,
8583
- y: lastPoint.y + deltaY * ratio,
8662
+ x: position.x,
8663
+ y: position.y,
8584
8664
  ...pressure != null ? { pressure } : {}
8585
8665
  };
8586
8666
  });