canvu-react 0.3.24 → 0.3.26

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
@@ -3,8 +3,8 @@ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAsse
3
3
  import { V as VectorSceneItem } from './types-CB0TZZuk.cjs';
4
4
  import { V as VectorViewportAssetKind, u as VectorViewportAssetStore } from './shape-builders-DFudWDFI.cjs';
5
5
  export { v as VectorViewportAssetHydrationRequest, w as VectorViewportAssetResolveRequest, x as VectorViewportAssetResolveResult, y as VectorViewportAssetUploadRequest, z as VectorViewportAssetUploadResult } from './shape-builders-DFudWDFI.cjs';
6
- import { B as BoardComponentPosition, V as VectorToolDefinition, C as CanvasPlugin, a as VectorSelectionInspector } from './types-7kfWcm0L.cjs';
7
- export { b as CanvasPluginComponentProps, c as CanvasPluginContribution, d as CanvasPluginItemsChangeMiddlewareContext, e as CanvasPluginRenderContext, f as CanvuChromeActiveToolStyle, g as CanvuChromeContext, h as CanvuChromeContextValue, i as CanvuChromeSelectionStyleChange, j as CanvuPluginContext, k as CanvuPluginContextValue, l as CanvuPluginViewportSnapshot, m as CustomShapePlacementOptions, P as PlacementPreview, n as VectorCanvasSpacePosition, o as VectorSelectionInspectorProps, p as VectorViewport, q as VectorViewportHandle, r as VectorViewportProps, W as WorldPointerDownDetail, s as createCanvuPlugin, t as getBoardPositionStyle, u as useCanvuChromeContext, v as useCanvuDocumentContext, w as useCanvuPluginContext, x as useCanvuPluginContribution, y as useCanvuResolvedTools, z as useCanvuViewportContext } from './types-7kfWcm0L.cjs';
6
+ import { B as BoardComponentPosition, V as VectorToolDefinition, C as CanvasPlugin, a as VectorSelectionInspector } from './types-BLXR7g_L.cjs';
7
+ export { b as CanvasPluginComponentProps, c as CanvasPluginContribution, d as CanvasPluginItemsChangeMiddlewareContext, e as CanvasPluginRenderContext, f as CanvuChromeActiveToolStyle, g as CanvuChromeContext, h as CanvuChromeContextValue, i as CanvuChromeSelectionStyleChange, j as CanvuPluginContext, k as CanvuPluginContextValue, l as CanvuPluginViewportSnapshot, m as CustomShapePlacementOptions, P as PlacementPreview, n as VectorCanvasSpacePosition, o as VectorSelectionInspectorProps, p as VectorViewport, q as VectorViewportHandle, r as VectorViewportProps, W as WorldPointerDownDetail, s as createCanvuPlugin, t as getBoardPositionStyle, u as useCanvuChromeContext, v as useCanvuDocumentContext, w as useCanvuPluginContext, x as useCanvuPluginContribution, y as useCanvuResolvedTools, z as useCanvuViewportContext } from './types-BLXR7g_L.cjs';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
9
  import * as react from 'react';
10
10
  import { CSSProperties, ReactNode, ReactElement, SVGProps } from 'react';
package/dist/react.d.ts CHANGED
@@ -3,8 +3,8 @@ export { H as HydratedSceneItemsWithAssetsResult, h as hydrateSceneItemsWithAsse
3
3
  import { V as VectorSceneItem } from './types-CB0TZZuk.js';
4
4
  import { V as VectorViewportAssetKind, u as VectorViewportAssetStore } from './shape-builders-ENwnK-zT.js';
5
5
  export { v as VectorViewportAssetHydrationRequest, w as VectorViewportAssetResolveRequest, x as VectorViewportAssetResolveResult, y as VectorViewportAssetUploadRequest, z as VectorViewportAssetUploadResult } from './shape-builders-ENwnK-zT.js';
6
- import { B as BoardComponentPosition, V as VectorToolDefinition, C as CanvasPlugin, a as VectorSelectionInspector } from './types-C4k_AMvi.js';
7
- export { b as CanvasPluginComponentProps, c as CanvasPluginContribution, d as CanvasPluginItemsChangeMiddlewareContext, e as CanvasPluginRenderContext, f as CanvuChromeActiveToolStyle, g as CanvuChromeContext, h as CanvuChromeContextValue, i as CanvuChromeSelectionStyleChange, j as CanvuPluginContext, k as CanvuPluginContextValue, l as CanvuPluginViewportSnapshot, m as CustomShapePlacementOptions, P as PlacementPreview, n as VectorCanvasSpacePosition, o as VectorSelectionInspectorProps, p as VectorViewport, q as VectorViewportHandle, r as VectorViewportProps, W as WorldPointerDownDetail, s as createCanvuPlugin, t as getBoardPositionStyle, u as useCanvuChromeContext, v as useCanvuDocumentContext, w as useCanvuPluginContext, x as useCanvuPluginContribution, y as useCanvuResolvedTools, z as useCanvuViewportContext } from './types-C4k_AMvi.js';
6
+ import { B as BoardComponentPosition, V as VectorToolDefinition, C as CanvasPlugin, a as VectorSelectionInspector } from './types-Cm7IsgL4.js';
7
+ export { b as CanvasPluginComponentProps, c as CanvasPluginContribution, d as CanvasPluginItemsChangeMiddlewareContext, e as CanvasPluginRenderContext, f as CanvuChromeActiveToolStyle, g as CanvuChromeContext, h as CanvuChromeContextValue, i as CanvuChromeSelectionStyleChange, j as CanvuPluginContext, k as CanvuPluginContextValue, l as CanvuPluginViewportSnapshot, m as CustomShapePlacementOptions, P as PlacementPreview, n as VectorCanvasSpacePosition, o as VectorSelectionInspectorProps, p as VectorViewport, q as VectorViewportHandle, r as VectorViewportProps, W as WorldPointerDownDetail, s as createCanvuPlugin, t as getBoardPositionStyle, u as useCanvuChromeContext, v as useCanvuDocumentContext, w as useCanvuPluginContext, x as useCanvuPluginContribution, y as useCanvuResolvedTools, z as useCanvuViewportContext } from './types-Cm7IsgL4.js';
8
8
  import * as react_jsx_runtime from 'react/jsx-runtime';
9
9
  import * as react from 'react';
10
10
  import { CSSProperties, ReactNode, ReactElement, SVGProps } from 'react';
package/dist/react.js CHANGED
@@ -711,6 +711,47 @@ var init_shape_builders = __esm({
711
711
  }
712
712
  });
713
713
 
714
+ // src/image/canvas-encode.ts
715
+ var DEFAULT_FALLBACK_MIME_TYPES = ["image/png"];
716
+ var tryCanvasToBlob = (canvas, mimeType, quality) => new Promise((resolve) => {
717
+ canvas.toBlob((blob) => resolve(blob), mimeType, quality);
718
+ });
719
+ var blobFromDataUrl = async (dataUrl) => {
720
+ const response = await fetch(dataUrl);
721
+ const blob = await response.blob();
722
+ if (blob.size === 0) {
723
+ throw new Error("Failed to encode canvas to blob");
724
+ }
725
+ return blob;
726
+ };
727
+ async function encodeCanvasToBlob(canvas, options) {
728
+ const primaryMimeType = options?.mimeType ?? "image/png";
729
+ const quality = options?.quality;
730
+ const mimeTypes = [
731
+ primaryMimeType,
732
+ ...options?.fallbackMimeTypes ?? DEFAULT_FALLBACK_MIME_TYPES
733
+ ].filter(
734
+ (mimeType, index, mimeTypeList) => mimeTypeList.indexOf(mimeType) === index
735
+ );
736
+ for (const mimeType of mimeTypes) {
737
+ const blob = await tryCanvasToBlob(
738
+ canvas,
739
+ mimeType,
740
+ mimeType === primaryMimeType ? quality : void 0
741
+ );
742
+ if (blob) {
743
+ return blob;
744
+ }
745
+ }
746
+ for (const mimeType of mimeTypes) {
747
+ const dataUrl = canvas.toDataURL(mimeType, quality);
748
+ if (dataUrl && dataUrl !== "data:,") {
749
+ return blobFromDataUrl(dataUrl);
750
+ }
751
+ }
752
+ throw new Error("Failed to encode canvas to blob");
753
+ }
754
+
714
755
  // src/image/indexed-db-image-store.ts
715
756
  var DB_NAME = "canvu-image-store";
716
757
  var DB_VERSION = 1;
@@ -829,19 +870,7 @@ function decodeImageToCanvas(blob, maxDimension) {
829
870
  });
830
871
  }
831
872
  function canvasToBlob(canvas, mime, quality) {
832
- return new Promise((resolve, reject) => {
833
- canvas.toBlob(
834
- (blob) => {
835
- if (!blob) {
836
- reject(new Error("Could not encode blob"));
837
- return;
838
- }
839
- resolve(blob);
840
- },
841
- mime,
842
- quality
843
- );
844
- });
873
+ return encodeCanvasToBlob(canvas, { mimeType: mime, quality });
845
874
  }
846
875
  async function loadImageToStore(file, store) {
847
876
  const originalBlob = file;
@@ -909,21 +938,6 @@ async function renderPageToCanvas(page, scale) {
909
938
  await page.render({ canvas, viewport }).promise;
910
939
  return { canvas, width: w, height: h };
911
940
  }
912
- function canvasToBlob2(canvas, mime, quality) {
913
- return new Promise((resolve, reject) => {
914
- canvas.toBlob(
915
- (blob) => {
916
- if (!blob) {
917
- reject(new Error("Could not encode blob"));
918
- return;
919
- }
920
- resolve(blob);
921
- },
922
- mime,
923
- quality
924
- );
925
- });
926
- }
927
941
  function normalizePdfPageNumbers(pageNumbers, pageCount) {
928
942
  if (!pageNumbers || pageNumbers.length === 0) {
929
943
  return Array.from({ length: pageCount }, (_, index) => index + 1);
@@ -985,7 +999,7 @@ async function loadPdfToStore(file, store, options) {
985
999
  const page = await pdf.getPage(pageNumber);
986
1000
  const { canvas, width, height } = await renderPageToCanvas(page, scale);
987
1001
  const mime = "image/png";
988
- const pageBlob = await canvasToBlob2(canvas, mime);
1002
+ const pageBlob = await encodeCanvasToBlob(canvas, { mimeType: mime });
989
1003
  const blobId = await store.storeOriginal(pageBlob);
990
1004
  const thumbnailBlobId = storeThumbnails ? await (async () => {
991
1005
  const thumbScale = Math.min(1, 256 / Math.max(width, height));
@@ -1000,7 +1014,9 @@ async function loadPdfToStore(file, store, options) {
1000
1014
  tCtx.imageSmoothingQuality = "high";
1001
1015
  tCtx.drawImage(canvas, 0, 0, tw, th);
1002
1016
  }
1003
- const thumbBlob = await canvasToBlob2(thumbCanvas, mime);
1017
+ const thumbBlob = await encodeCanvasToBlob(thumbCanvas, {
1018
+ mimeType: mime
1019
+ });
1004
1020
  return await store.storeThumbnail(thumbBlob);
1005
1021
  })() : "";
1006
1022
  const pageResult = {
@@ -6492,7 +6508,12 @@ function PresenceRemoteLayer({
6492
6508
  const markup = peer.markupStroke;
6493
6509
  let strokeNode = null;
6494
6510
  if (markup && markup.points.length > 0) {
6495
- const paint = strokePaint(markup.tool, color);
6511
+ const fallbackPaint = strokePaint(markup.tool, color);
6512
+ const paint = {
6513
+ stroke: markup.stroke ?? fallbackPaint.stroke,
6514
+ strokeOpacity: markup.strokeOpacity ?? fallbackPaint.strokeOpacity,
6515
+ widthWorld: markup.strokeWidth ?? fallbackPaint.widthWorld
6516
+ };
6496
6517
  const d = markup.points.length >= 2 ? smoothFreehandPointsToPathD([...markup.points]) : null;
6497
6518
  if (d) {
6498
6519
  strokeNode = /* @__PURE__ */ jsx(
@@ -7398,6 +7419,41 @@ var VectorViewport = forwardRef(
7398
7419
  onWorldPointerLeaveRef.current = onWorldPointerLeave;
7399
7420
  const onPlacementPreviewChangeRef = useRef(onPlacementPreviewChange);
7400
7421
  onPlacementPreviewChangeRef.current = onPlacementPreviewChange;
7422
+ const directRemoteStrokePreviewRef = useRef(false);
7423
+ const remoteStrokePreviewFrameRef = useRef(null);
7424
+ const pendingRemoteStrokePreviewRef = useRef(null);
7425
+ const flushRemoteStrokePreviewWithStyle = useCallback(() => {
7426
+ remoteStrokePreviewFrameRef.current = null;
7427
+ const pending = pendingRemoteStrokePreviewRef.current;
7428
+ if (!pending) return;
7429
+ onPlacementPreviewChangeRef.current?.({
7430
+ kind: "stroke",
7431
+ tool: pending.tool,
7432
+ points: pending.points,
7433
+ style: { ...strokeStyleRef.current }
7434
+ });
7435
+ }, []);
7436
+ const emitRemoteStrokePreview = useCallback(
7437
+ (tool, points) => {
7438
+ if (tool === "laser") return;
7439
+ directRemoteStrokePreviewRef.current = true;
7440
+ pendingRemoteStrokePreviewRef.current = { tool, points };
7441
+ if (remoteStrokePreviewFrameRef.current != null) return;
7442
+ remoteStrokePreviewFrameRef.current = requestAnimationFrame(
7443
+ flushRemoteStrokePreviewWithStyle
7444
+ );
7445
+ },
7446
+ [flushRemoteStrokePreviewWithStyle]
7447
+ );
7448
+ const emitRemoteStrokePreviewClear = useCallback(() => {
7449
+ if (remoteStrokePreviewFrameRef.current != null) {
7450
+ cancelAnimationFrame(remoteStrokePreviewFrameRef.current);
7451
+ remoteStrokePreviewFrameRef.current = null;
7452
+ }
7453
+ pendingRemoteStrokePreviewRef.current = null;
7454
+ directRemoteStrokePreviewRef.current = false;
7455
+ onPlacementPreviewChangeRef.current?.(null);
7456
+ }, []);
7401
7457
  const overlayCameraTickRef = useRef(false);
7402
7458
  overlayCameraTickRef.current = interactive || remotePresence != null && remotePresence.length > 0 || presenceOverlay != null;
7403
7459
  const pruneEraserTrail = useCallback(
@@ -7516,6 +7572,7 @@ var VectorViewport = forwardRef(
7516
7572
  if (itemId) {
7517
7573
  renderSceneWithLivePenStroke(null);
7518
7574
  }
7575
+ emitRemoteStrokePreviewClear();
7519
7576
  setPlacementPreview(null);
7520
7577
  commitCompletedStroke({
7521
7578
  tool,
@@ -7527,6 +7584,7 @@ var VectorViewport = forwardRef(
7527
7584
  },
7528
7585
  [
7529
7586
  commitCompletedStroke,
7587
+ emitRemoteStrokePreviewClear,
7530
7588
  releaseInteractionPointer,
7531
7589
  renderSceneWithLivePenStroke
7532
7590
  ]
@@ -7638,8 +7696,18 @@ var VectorViewport = forwardRef(
7638
7696
  };
7639
7697
  }, [onWorldPointerMove]);
7640
7698
  useEffect(() => {
7699
+ if (directRemoteStrokePreviewRef.current && placementPreview === null) {
7700
+ return;
7701
+ }
7641
7702
  onPlacementPreviewChangeRef.current?.(placementPreview);
7642
7703
  }, [placementPreview]);
7704
+ useEffect(() => {
7705
+ return () => {
7706
+ if (remoteStrokePreviewFrameRef.current != null) {
7707
+ cancelAnimationFrame(remoteStrokePreviewFrameRef.current);
7708
+ }
7709
+ };
7710
+ }, []);
7643
7711
  useEffect(() => {
7644
7712
  const scene = sceneRef.current;
7645
7713
  if (scene) {
@@ -8633,11 +8701,13 @@ var VectorViewport = forwardRef(
8633
8701
  setPlacementPreview(null);
8634
8702
  } else if (directPenStroke) {
8635
8703
  setPlacementPreview(null);
8704
+ emitRemoteStrokePreview(tool, [startPoint]);
8636
8705
  } else {
8637
8706
  setPlacementPreview({
8638
8707
  kind: "stroke",
8639
8708
  tool,
8640
- points: [startPoint]
8709
+ points: [startPoint],
8710
+ style: { ...strokeStyleRef.current }
8641
8711
  });
8642
8712
  }
8643
8713
  captureInteractionPointer(e.currentTarget, e.pointerId);
@@ -8674,6 +8744,7 @@ var VectorViewport = forwardRef(
8674
8744
  [
8675
8745
  applePencilNav,
8676
8746
  captureInteractionPointer,
8747
+ emitRemoteStrokePreview,
8677
8748
  finalizeStrokeDragState,
8678
8749
  renderSceneWithLivePenStroke,
8679
8750
  screenToWorld
@@ -8732,6 +8803,7 @@ var VectorViewport = forwardRef(
8732
8803
  activeInteractionPointerIdRef.current = e.pointerId;
8733
8804
  activeInteractionPointerTargetRef.current = null;
8734
8805
  setPlacementPreview(null);
8806
+ emitRemoteStrokePreview(tool, [startPoint]);
8735
8807
  debugApplePencilPointer("native-pointerdown", {
8736
8808
  pointerType: e.pointerType,
8737
8809
  pointerId: e.pointerId,
@@ -8749,6 +8821,7 @@ var VectorViewport = forwardRef(
8749
8821
  };
8750
8822
  }, [
8751
8823
  applePencilNav,
8824
+ emitRemoteStrokePreview,
8752
8825
  finalizeStrokeDragState,
8753
8826
  interactive,
8754
8827
  renderSceneWithLivePenStroke,
@@ -8832,6 +8905,7 @@ var VectorViewport = forwardRef(
8832
8905
  activeInteractionPointerTargetRef.current = null;
8833
8906
  activeInteractionTouchIdRef.current = touch.identifier;
8834
8907
  setPlacementPreview(null);
8908
+ emitRemoteStrokePreview(tool, [startPoint]);
8835
8909
  debugApplePencilPointer("touchstart-stroke", {
8836
8910
  touchId: touch.identifier,
8837
8911
  touchType: touchKind(touch),
@@ -8863,6 +8937,7 @@ var VectorViewport = forwardRef(
8863
8937
  renderSceneWithLivePenStroke(item);
8864
8938
  }
8865
8939
  setPlacementPreview(null);
8940
+ emitRemoteStrokePreview(st.tool, interpolated);
8866
8941
  }
8867
8942
  debugApplePencilPointer("touchmove-stroke", {
8868
8943
  touchId: touch.identifier,
@@ -8925,6 +9000,7 @@ var VectorViewport = forwardRef(
8925
9000
  };
8926
9001
  }, [
8927
9002
  applePencilNav,
9003
+ emitRemoteStrokePreview,
8928
9004
  finalizeStrokeDragState,
8929
9005
  interactive,
8930
9006
  renderSceneWithLivePenStroke,
@@ -8979,6 +9055,7 @@ var VectorViewport = forwardRef(
8979
9055
  renderSceneWithLivePenStroke(item);
8980
9056
  }
8981
9057
  setPlacementPreview(null);
9058
+ emitRemoteStrokePreview(st.tool, interpolated);
8982
9059
  return;
8983
9060
  }
8984
9061
  if (st.tool === "laser") {
@@ -8997,7 +9074,8 @@ var VectorViewport = forwardRef(
8997
9074
  setPlacementPreview({
8998
9075
  kind: "stroke",
8999
9076
  tool: st.tool,
9000
- points: interpolated
9077
+ points: interpolated,
9078
+ style: { ...strokeStyleRef.current }
9001
9079
  });
9002
9080
  }
9003
9081
  return;
@@ -9120,6 +9198,9 @@ var VectorViewport = forwardRef(
9120
9198
  }
9121
9199
  const cam = cameraRef.current;
9122
9200
  if (!cam) {
9201
+ if (st.kind === "stroke") {
9202
+ emitRemoteStrokePreviewClear();
9203
+ }
9123
9204
  if (st.kind === "erase") {
9124
9205
  eraserPreviewIdsRef.current.clear();
9125
9206
  setEraserPreviewIds([]);
@@ -9351,6 +9432,8 @@ var VectorViewport = forwardRef(
9351
9432
  document.removeEventListener("pointercancel", onUp);
9352
9433
  };
9353
9434
  }, [
9435
+ emitRemoteStrokePreview,
9436
+ emitRemoteStrokePreviewClear,
9354
9437
  interactive,
9355
9438
  pruneEraserTrail,
9356
9439
  pruneLaserTrail,