canvu-react 0.3.35 → 0.3.37

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.js CHANGED
@@ -6598,7 +6598,7 @@ function InteractionOverlay({
6598
6598
  raw,
6599
6599
  previewStyle,
6600
6600
  tool === "laser" ? "draw" : tool,
6601
- false
6601
+ raw.length === 2
6602
6602
  );
6603
6603
  if (payload) {
6604
6604
  if (payload.kind === "circle") {
@@ -6891,7 +6891,7 @@ function PresenceRemoteLayer({
6891
6891
  markup.points.map((p) => ({ x: p.x, y: p.y })),
6892
6892
  style,
6893
6893
  markup.tool,
6894
- false
6894
+ markup.points.length === 2
6895
6895
  );
6896
6896
  if (payload?.kind === "circle") {
6897
6897
  strokeNode = /* @__PURE__ */ jsx(
@@ -7280,6 +7280,8 @@ body[data-canvu-pen-active="true"] [data-slot="shape-context-menu"] * {
7280
7280
  -webkit-touch-callout: none !important;
7281
7281
  }
7282
7282
  `;
7283
+ var STRAIGHT_STROKE_HOLD_DURATION_MS = 1e3;
7284
+ var STRAIGHT_STROKE_JITTER_TOLERANCE_SQUARED = 5 * 5;
7283
7285
  function debugApplePencilPointer(phase, detail) {
7284
7286
  return;
7285
7287
  }
@@ -7427,6 +7429,28 @@ function appendTouchToStrokePoints(points, touch, zoom, screenToWorldFn) {
7427
7429
  );
7428
7430
  return appendInterpolatedPoints(points, nextPoint);
7429
7431
  }
7432
+ function createStraightStrokeState(anchorPoint, clientX, clientY) {
7433
+ return {
7434
+ active: false,
7435
+ anchorPoint,
7436
+ holdScreen: { x: clientX, y: clientY },
7437
+ holdTimer: null
7438
+ };
7439
+ }
7440
+ function clearStraightStrokeHoldTimer(strokeState) {
7441
+ const straightLine = strokeState.straightLine;
7442
+ if (!straightLine?.holdTimer) return;
7443
+ clearTimeout(straightLine.holdTimer);
7444
+ straightLine.holdTimer = null;
7445
+ }
7446
+ function lastStrokePoint(points) {
7447
+ return points[points.length - 1] ?? null;
7448
+ }
7449
+ function hasMovedPastStraightStrokeJitter(straightLine, clientX, clientY) {
7450
+ const deltaX = clientX - straightLine.holdScreen.x;
7451
+ const deltaY = clientY - straightLine.holdScreen.y;
7452
+ return deltaX * deltaX + deltaY * deltaY > STRAIGHT_STROKE_JITTER_TOLERANCE_SQUARED;
7453
+ }
7430
7454
  var VectorViewport = forwardRef(
7431
7455
  function VectorViewport2({
7432
7456
  items,
@@ -7961,6 +7985,76 @@ var VectorViewport = forwardRef(
7961
7985
  },
7962
7986
  []
7963
7987
  );
7988
+ const updateStrokePreviewPoints = useCallback(
7989
+ (strokeState, points) => {
7990
+ strokeState.points = points;
7991
+ if (strokeState.itemId && strokeState.tool !== "laser") {
7992
+ const item = createFreehandStrokeItem(
7993
+ strokeState.itemId,
7994
+ points,
7995
+ strokeState.tool,
7996
+ strokeStyleRef.current
7997
+ );
7998
+ if (item) {
7999
+ renderSceneWithLivePenStroke(item);
8000
+ }
8001
+ setPlacementPreview(null);
8002
+ emitRemoteStrokePreview(strokeState.tool, points);
8003
+ return;
8004
+ }
8005
+ if (strokeState.tool === "laser") return;
8006
+ setPlacementPreview({
8007
+ kind: "stroke",
8008
+ tool: strokeState.tool,
8009
+ points,
8010
+ style: { ...strokeStyleRef.current }
8011
+ });
8012
+ },
8013
+ [emitRemoteStrokePreview, renderSceneWithLivePenStroke]
8014
+ );
8015
+ const setStraightStrokeEndpoint = useCallback(
8016
+ (strokeState, endpoint) => {
8017
+ const straightLine = strokeState.straightLine;
8018
+ if (!straightLine) return;
8019
+ straightLine.active = true;
8020
+ updateStrokePreviewPoints(strokeState, [straightLine.anchorPoint, endpoint]);
8021
+ },
8022
+ [updateStrokePreviewPoints]
8023
+ );
8024
+ const startOrRestartStraightStrokeHoldTimer = useCallback(
8025
+ (strokeState) => {
8026
+ const straightLine = strokeState.straightLine;
8027
+ if (!straightLine || strokeState.tool !== "draw") return;
8028
+ clearStraightStrokeHoldTimer(strokeState);
8029
+ straightLine.holdTimer = window.setTimeout(() => {
8030
+ straightLine.holdTimer = null;
8031
+ const currentStrokeState = dragStateRef.current;
8032
+ if (currentStrokeState.kind !== "stroke" || currentStrokeState !== strokeState) {
8033
+ return;
8034
+ }
8035
+ const endpoint = lastStrokePoint(currentStrokeState.points);
8036
+ if (!endpoint) return;
8037
+ setStraightStrokeEndpoint(currentStrokeState, endpoint);
8038
+ }, STRAIGHT_STROKE_HOLD_DURATION_MS);
8039
+ },
8040
+ [setStraightStrokeEndpoint]
8041
+ );
8042
+ const updateStraightStrokeForMove = useCallback(
8043
+ (strokeState, clientX, clientY, endpoint) => {
8044
+ const straightLine = strokeState.straightLine;
8045
+ if (!straightLine || strokeState.tool !== "draw") return false;
8046
+ if (straightLine.active) {
8047
+ setStraightStrokeEndpoint(strokeState, endpoint);
8048
+ return true;
8049
+ }
8050
+ if (straightLine.holdTimer && hasMovedPastStraightStrokeJitter(straightLine, clientX, clientY)) {
8051
+ straightLine.holdScreen = { x: clientX, y: clientY };
8052
+ startOrRestartStraightStrokeHoldTimer(strokeState);
8053
+ }
8054
+ return false;
8055
+ },
8056
+ [setStraightStrokeEndpoint, startOrRestartStraightStrokeHoldTimer]
8057
+ );
7964
8058
  const finalizeStrokeDragState = useCallback(
7965
8059
  (strokeState) => {
7966
8060
  const tool = strokeState.tool;
@@ -7971,6 +8065,7 @@ var VectorViewport = forwardRef(
7971
8065
  debugApplePencilPointer("finalize-stroke", {
7972
8066
  points: pts.length
7973
8067
  });
8068
+ clearStraightStrokeHoldTimer(strokeState);
7974
8069
  dragStateRef.current = { kind: "idle" };
7975
8070
  releaseInteractionPointer();
7976
8071
  if (itemId) {
@@ -9082,6 +9177,7 @@ var VectorViewport = forwardRef(
9082
9177
  e.clientY,
9083
9178
  e.pointerType === "pen" ? e.pressure : void 0
9084
9179
  );
9180
+ const straightLine = tool === "draw" ? createStraightStrokeState(startPoint, e.clientX, e.clientY) : void 0;
9085
9181
  const directPenStroke = e.pointerType === "pen" && (tool === "draw" || tool === "marker");
9086
9182
  let itemId;
9087
9183
  if (directPenStroke) {
@@ -9096,13 +9192,16 @@ var VectorViewport = forwardRef(
9096
9192
  renderSceneWithLivePenStroke(item);
9097
9193
  }
9098
9194
  }
9099
- dragStateRef.current = {
9195
+ const nextDragState = {
9100
9196
  kind: "stroke",
9101
9197
  tool,
9102
9198
  points: [startPoint],
9103
9199
  pointerType: e.pointerType,
9104
- ...itemId ? { itemId } : {}
9200
+ ...itemId ? { itemId } : {},
9201
+ ...straightLine ? { straightLine } : {}
9105
9202
  };
9203
+ dragStateRef.current = nextDragState;
9204
+ startOrRestartStraightStrokeHoldTimer(nextDragState);
9106
9205
  if (tool === "laser") {
9107
9206
  setLaserTrail([{ x: worldX, y: worldY, t: Date.now() }]);
9108
9207
  setPlacementPreview(null);
@@ -9154,7 +9253,8 @@ var VectorViewport = forwardRef(
9154
9253
  emitRemoteStrokePreview,
9155
9254
  finalizeStrokeDragState,
9156
9255
  renderSceneWithLivePenStroke,
9157
- screenToWorld
9256
+ screenToWorld,
9257
+ startOrRestartStraightStrokeHoldTimer
9158
9258
  ]
9159
9259
  );
9160
9260
  useEffect(() => {
@@ -9190,6 +9290,7 @@ var VectorViewport = forwardRef(
9190
9290
  e.clientY,
9191
9291
  e.pressure
9192
9292
  );
9293
+ const straightLine = tool === "draw" ? createStraightStrokeState(startPoint, e.clientX, e.clientY) : void 0;
9193
9294
  const itemId = createShapeId();
9194
9295
  const item = createFreehandStrokeItem(
9195
9296
  itemId,
@@ -9200,13 +9301,16 @@ var VectorViewport = forwardRef(
9200
9301
  if (item) {
9201
9302
  renderSceneWithLivePenStroke(item);
9202
9303
  }
9203
- dragStateRef.current = {
9304
+ const nextDragState = {
9204
9305
  kind: "stroke",
9205
9306
  tool,
9206
9307
  points: [startPoint],
9207
9308
  pointerType: e.pointerType,
9208
- itemId
9309
+ itemId,
9310
+ ...straightLine ? { straightLine } : {}
9209
9311
  };
9312
+ dragStateRef.current = nextDragState;
9313
+ startOrRestartStraightStrokeHoldTimer(nextDragState);
9210
9314
  activeInteractionPointerIdRef.current = e.pointerId;
9211
9315
  activeInteractionPointerTargetRef.current = null;
9212
9316
  setPlacementPreview(null);
@@ -9232,7 +9336,8 @@ var VectorViewport = forwardRef(
9232
9336
  finalizeStrokeDragState,
9233
9337
  interactive,
9234
9338
  renderSceneWithLivePenStroke,
9235
- screenToWorld
9339
+ screenToWorld,
9340
+ startOrRestartStraightStrokeHoldTimer
9236
9341
  ]);
9237
9342
  useEffect(() => {
9238
9343
  if (!interactive) return;
@@ -9291,6 +9396,7 @@ var VectorViewport = forwardRef(
9291
9396
  touch.clientY,
9292
9397
  touchPressure(touch)
9293
9398
  );
9399
+ const straightLine = tool === "draw" ? createStraightStrokeState(startPoint, touch.clientX, touch.clientY) : void 0;
9294
9400
  const itemId = createShapeId();
9295
9401
  const item = createFreehandStrokeItem(
9296
9402
  itemId,
@@ -9301,13 +9407,16 @@ var VectorViewport = forwardRef(
9301
9407
  if (item) {
9302
9408
  renderSceneWithLivePenStroke(item);
9303
9409
  }
9304
- dragStateRef.current = {
9410
+ const nextDragState = {
9305
9411
  kind: "stroke",
9306
9412
  tool,
9307
9413
  points: [startPoint],
9308
9414
  pointerType: "pen",
9309
- itemId
9415
+ itemId,
9416
+ ...straightLine ? { straightLine } : {}
9310
9417
  };
9418
+ dragStateRef.current = nextDragState;
9419
+ startOrRestartStraightStrokeHoldTimer(nextDragState);
9311
9420
  activeInteractionPointerIdRef.current = null;
9312
9421
  activeInteractionPointerTargetRef.current = null;
9313
9422
  activeInteractionTouchIdRef.current = touch.identifier;
@@ -9326,6 +9435,21 @@ var VectorViewport = forwardRef(
9326
9435
  if (!touch) return;
9327
9436
  const cam = cameraRef.current;
9328
9437
  if (!cam) return;
9438
+ const endpoint = pointerSampleToWorldPoint(
9439
+ screenToWorld,
9440
+ touch.clientX,
9441
+ touch.clientY,
9442
+ touchPressure(touch)
9443
+ );
9444
+ if (updateStraightStrokeForMove(st, touch.clientX, touch.clientY, endpoint)) {
9445
+ debugApplePencilPointer("touchmove-stroke", {
9446
+ touchId: touch.identifier,
9447
+ points: st.points.length,
9448
+ force: touchPressure(touch)
9449
+ });
9450
+ stopTouchEvent(ev);
9451
+ return;
9452
+ }
9329
9453
  const interpolated = appendTouchToStrokePoints(
9330
9454
  st.points,
9331
9455
  touch,
@@ -9360,13 +9484,23 @@ var VectorViewport = forwardRef(
9360
9484
  if (!touch) return;
9361
9485
  const cam = cameraRef.current;
9362
9486
  if (cam) {
9363
- const completedPoints = appendTouchToStrokePoints(
9364
- st.points,
9365
- touch,
9366
- cam.zoom,
9367
- screenToWorld
9368
- );
9369
- st.points = completedPoints;
9487
+ if (st.straightLine?.active) {
9488
+ const endpoint = pointerSampleToWorldPoint(
9489
+ screenToWorld,
9490
+ touch.clientX,
9491
+ touch.clientY,
9492
+ touchPressure(touch)
9493
+ );
9494
+ setStraightStrokeEndpoint(st, endpoint);
9495
+ } else {
9496
+ const completedPoints = appendTouchToStrokePoints(
9497
+ st.points,
9498
+ touch,
9499
+ cam.zoom,
9500
+ screenToWorld
9501
+ );
9502
+ st.points = completedPoints;
9503
+ }
9370
9504
  }
9371
9505
  debugApplePencilPointer("touchend-stroke", {
9372
9506
  touchId: touch.identifier,
@@ -9411,7 +9545,10 @@ var VectorViewport = forwardRef(
9411
9545
  finalizeStrokeDragState,
9412
9546
  interactive,
9413
9547
  renderSceneWithLivePenStroke,
9414
- screenToWorld
9548
+ screenToWorld,
9549
+ setStraightStrokeEndpoint,
9550
+ startOrRestartStraightStrokeHoldTimer,
9551
+ updateStraightStrokeForMove
9415
9552
  ]);
9416
9553
  useEffect(() => {
9417
9554
  if (!interactive) return;
@@ -9444,6 +9581,15 @@ var VectorViewport = forwardRef(
9444
9581
  pressure: ev.pointerType === "pen" ? ev.pressure : void 0
9445
9582
  });
9446
9583
  }
9584
+ const endpoint = pointerSampleToWorldPoint(
9585
+ screenToWorld,
9586
+ ev.clientX,
9587
+ ev.clientY,
9588
+ ev.pointerType === "pen" ? ev.pressure : void 0
9589
+ );
9590
+ if (updateStraightStrokeForMove(st, ev.clientX, ev.clientY, endpoint)) {
9591
+ return;
9592
+ }
9447
9593
  const interpolated = appendPointerEventSamplesToStrokePoints(
9448
9594
  st.points,
9449
9595
  ev,
@@ -9611,6 +9757,7 @@ var VectorViewport = forwardRef(
9611
9757
  const cam = cameraRef.current;
9612
9758
  if (!cam) {
9613
9759
  if (st.kind === "stroke") {
9760
+ clearStraightStrokeHoldTimer(st);
9614
9761
  emitRemoteStrokePreviewClear();
9615
9762
  }
9616
9763
  if (st.kind === "erase") {
@@ -9666,13 +9813,26 @@ var VectorViewport = forwardRef(
9666
9813
  return;
9667
9814
  }
9668
9815
  if (st.kind === "stroke") {
9669
- const completedPoints = appendPointerEventSamplesToStrokePoints(
9670
- st.points,
9671
- ev,
9672
- cam.zoom,
9673
- screenToWorld
9674
- );
9675
- st.points = completedPoints;
9816
+ const completedPoints = (() => {
9817
+ if (st.straightLine?.active) {
9818
+ const endpoint = pointerSampleToWorldPoint(
9819
+ screenToWorld,
9820
+ ev.clientX,
9821
+ ev.clientY,
9822
+ ev.pointerType === "pen" ? ev.pressure : void 0
9823
+ );
9824
+ setStraightStrokeEndpoint(st, endpoint);
9825
+ return st.points;
9826
+ }
9827
+ const points = appendPointerEventSamplesToStrokePoints(
9828
+ st.points,
9829
+ ev,
9830
+ cam.zoom,
9831
+ screenToWorld
9832
+ );
9833
+ st.points = points;
9834
+ return points;
9835
+ })();
9676
9836
  debugApplePencilPointer("pointerup-stroke-points", {
9677
9837
  pointerType: ev.pointerType,
9678
9838
  pointerId: ev.pointerId,
@@ -9859,7 +10019,9 @@ var VectorViewport = forwardRef(
9859
10019
  renderSceneWithLivePenStroke,
9860
10020
  releaseInteractionPointer,
9861
10021
  requestAutoResetTool,
9862
- screenToWorld
10022
+ screenToWorld,
10023
+ setStraightStrokeEndpoint,
10024
+ updateStraightStrokeForMove
9863
10025
  ]);
9864
10026
  const selectedItemsForOverlay = useMemo(() => {
9865
10027
  return effectiveSelectedIds.map((id) => resolvedItems.find((i) => i.id === id)).filter((i) => i != null);