canvu-react 0.3.26 → 0.3.28

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.cjs CHANGED
@@ -6455,6 +6455,7 @@ function InteractionOverlay({
6455
6455
  }
6456
6456
  );
6457
6457
  }
6458
+ init_shape_builders();
6458
6459
 
6459
6460
  // src/react/presence/peer-color.ts
6460
6461
  function defaultPresenceColorForId(id) {
@@ -6480,6 +6481,9 @@ function strokePaint(tool, fallback) {
6480
6481
  return { stroke: fallback, strokeOpacity: 0.95, widthWorld: 3.5 };
6481
6482
  }
6482
6483
  }
6484
+ function isFreehandTool(tool) {
6485
+ return tool === "draw" || tool === "marker" || tool === "pencil" || tool === "brush";
6486
+ }
6483
6487
  function PresenceRemoteLayer({
6484
6488
  camera,
6485
6489
  cameraVersion: _cameraVersion,
@@ -6521,34 +6525,72 @@ function PresenceRemoteLayer({
6521
6525
  strokeOpacity: markup.strokeOpacity ?? fallbackPaint.strokeOpacity,
6522
6526
  widthWorld: markup.strokeWidth ?? fallbackPaint.widthWorld
6523
6527
  };
6524
- const d = markup.points.length >= 2 ? smoothFreehandPointsToPathD([...markup.points]) : null;
6525
- if (d) {
6526
- strokeNode = /* @__PURE__ */ jsxRuntime.jsx(
6527
- "path",
6528
- {
6529
- d,
6530
- fill: "none",
6531
- stroke: paint.stroke,
6532
- strokeOpacity: paint.strokeOpacity,
6533
- strokeWidth: Math.max(paint.widthWorld / z, overlayStrokePx),
6534
- strokeLinecap: "round",
6535
- strokeLinejoin: "round",
6536
- shapeRendering: "geometricPrecision",
6537
- vectorEffect: "non-scaling-stroke"
6538
- }
6528
+ if (markup.tool === "laser") {
6529
+ const d = markup.points.length >= 2 ? smoothFreehandPointsToPathD([...markup.points]) : null;
6530
+ if (d) {
6531
+ strokeNode = /* @__PURE__ */ jsxRuntime.jsx(
6532
+ "path",
6533
+ {
6534
+ d,
6535
+ fill: "none",
6536
+ stroke: paint.stroke,
6537
+ strokeOpacity: paint.strokeOpacity,
6538
+ strokeWidth: Math.max(paint.widthWorld / z, overlayStrokePx),
6539
+ strokeLinecap: "round",
6540
+ strokeLinejoin: "round",
6541
+ shapeRendering: "geometricPrecision",
6542
+ vectorEffect: "non-scaling-stroke"
6543
+ }
6544
+ );
6545
+ }
6546
+ } else if (isFreehandTool(markup.tool)) {
6547
+ const style = {
6548
+ stroke: paint.stroke,
6549
+ strokeWidth: paint.widthWorld,
6550
+ ...paint.strokeOpacity != null ? { strokeOpacity: paint.strokeOpacity } : {}
6551
+ };
6552
+ const payload = computeFreehandSvgPayload(
6553
+ markup.points.map((p) => ({ x: p.x, y: p.y })),
6554
+ style,
6555
+ markup.tool,
6556
+ false
6539
6557
  );
6540
- } else {
6541
- const p0 = markup.points[0];
6542
- if (p0) {
6558
+ if (payload?.kind === "circle") {
6543
6559
  strokeNode = /* @__PURE__ */ jsxRuntime.jsx(
6544
6560
  "circle",
6545
6561
  {
6546
- cx: p0.x,
6547
- cy: p0.y,
6548
- r: Math.max(3 / z, 2),
6549
- fill: paint.stroke,
6550
- fillOpacity: paint.strokeOpacity,
6551
- vectorEffect: "non-scaling-stroke"
6562
+ cx: payload.cx,
6563
+ cy: payload.cy,
6564
+ r: payload.r,
6565
+ fill: payload.fill,
6566
+ ...payload.fillOpacity != null ? { fillOpacity: payload.fillOpacity } : {},
6567
+ shapeRendering: "geometricPrecision"
6568
+ }
6569
+ );
6570
+ } else if (payload?.kind === "fillPath") {
6571
+ strokeNode = /* @__PURE__ */ jsxRuntime.jsx(
6572
+ "path",
6573
+ {
6574
+ d: payload.d,
6575
+ fill: payload.fill,
6576
+ fillRule: "nonzero",
6577
+ stroke: "none",
6578
+ ...payload.fillOpacity != null ? { fillOpacity: payload.fillOpacity } : {},
6579
+ shapeRendering: "geometricPrecision"
6580
+ }
6581
+ );
6582
+ } else if (payload?.kind === "strokePath") {
6583
+ strokeNode = /* @__PURE__ */ jsxRuntime.jsx(
6584
+ "path",
6585
+ {
6586
+ d: payload.d,
6587
+ fill: "none",
6588
+ stroke: payload.stroke,
6589
+ strokeWidth: payload.strokeWidth,
6590
+ ...payload.strokeOpacity != null ? { strokeOpacity: payload.strokeOpacity } : {},
6591
+ strokeLinecap: "round",
6592
+ strokeLinejoin: "round",
6593
+ shapeRendering: "geometricPrecision"
6552
6594
  }
6553
6595
  );
6554
6596
  }
@@ -7428,7 +7470,14 @@ var VectorViewport = react.forwardRef(
7428
7470
  onPlacementPreviewChangeRef.current = onPlacementPreviewChange;
7429
7471
  const directRemoteStrokePreviewRef = react.useRef(false);
7430
7472
  const remoteStrokePreviewFrameRef = react.useRef(null);
7473
+ const remoteStrokePreviewClearTimerRef = react.useRef(null);
7431
7474
  const pendingRemoteStrokePreviewRef = react.useRef(null);
7475
+ const cancelPendingRemoteStrokePreviewClear = react.useCallback(() => {
7476
+ if (remoteStrokePreviewClearTimerRef.current != null) {
7477
+ clearTimeout(remoteStrokePreviewClearTimerRef.current);
7478
+ remoteStrokePreviewClearTimerRef.current = null;
7479
+ }
7480
+ }, []);
7432
7481
  const flushRemoteStrokePreviewWithStyle = react.useCallback(() => {
7433
7482
  remoteStrokePreviewFrameRef.current = null;
7434
7483
  const pending = pendingRemoteStrokePreviewRef.current;
@@ -7443,6 +7492,7 @@ var VectorViewport = react.forwardRef(
7443
7492
  const emitRemoteStrokePreview = react.useCallback(
7444
7493
  (tool, points) => {
7445
7494
  if (tool === "laser") return;
7495
+ cancelPendingRemoteStrokePreviewClear();
7446
7496
  directRemoteStrokePreviewRef.current = true;
7447
7497
  pendingRemoteStrokePreviewRef.current = { tool, points };
7448
7498
  if (remoteStrokePreviewFrameRef.current != null) return;
@@ -7450,17 +7500,22 @@ var VectorViewport = react.forwardRef(
7450
7500
  flushRemoteStrokePreviewWithStyle
7451
7501
  );
7452
7502
  },
7453
- [flushRemoteStrokePreviewWithStyle]
7503
+ [cancelPendingRemoteStrokePreviewClear, flushRemoteStrokePreviewWithStyle]
7454
7504
  );
7505
+ const REMOTE_STROKE_PREVIEW_HOLD_MS = 350;
7455
7506
  const emitRemoteStrokePreviewClear = react.useCallback(() => {
7456
7507
  if (remoteStrokePreviewFrameRef.current != null) {
7457
7508
  cancelAnimationFrame(remoteStrokePreviewFrameRef.current);
7458
7509
  remoteStrokePreviewFrameRef.current = null;
7459
7510
  }
7460
- pendingRemoteStrokePreviewRef.current = null;
7461
- directRemoteStrokePreviewRef.current = false;
7462
- onPlacementPreviewChangeRef.current?.(null);
7463
- }, []);
7511
+ cancelPendingRemoteStrokePreviewClear();
7512
+ remoteStrokePreviewClearTimerRef.current = window.setTimeout(() => {
7513
+ remoteStrokePreviewClearTimerRef.current = null;
7514
+ pendingRemoteStrokePreviewRef.current = null;
7515
+ directRemoteStrokePreviewRef.current = false;
7516
+ onPlacementPreviewChangeRef.current?.(null);
7517
+ }, REMOTE_STROKE_PREVIEW_HOLD_MS);
7518
+ }, [cancelPendingRemoteStrokePreviewClear]);
7464
7519
  const overlayCameraTickRef = react.useRef(false);
7465
7520
  overlayCameraTickRef.current = interactive || remotePresence != null && remotePresence.length > 0 || presenceOverlay != null;
7466
7521
  const pruneEraserTrail = react.useCallback(
@@ -7713,6 +7768,9 @@ var VectorViewport = react.forwardRef(
7713
7768
  if (remoteStrokePreviewFrameRef.current != null) {
7714
7769
  cancelAnimationFrame(remoteStrokePreviewFrameRef.current);
7715
7770
  }
7771
+ if (remoteStrokePreviewClearTimerRef.current != null) {
7772
+ clearTimeout(remoteStrokePreviewClearTimerRef.current);
7773
+ }
7716
7774
  };
7717
7775
  }, []);
7718
7776
  react.useEffect(() => {