@bwp-web/canvas 0.8.1 → 0.8.3
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/context/EditCanvasContext.d.ts +61 -0
- package/dist/context/EditCanvasContext.d.ts.map +1 -0
- package/dist/context/ViewCanvasContext.d.ts +59 -0
- package/dist/context/ViewCanvasContext.d.ts.map +1 -0
- package/dist/context/index.d.ts +6 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/useCanvasRef.d.ts +13 -0
- package/dist/context/useCanvasRef.d.ts.map +1 -0
- package/dist/hooks/useCanvasClick.d.ts +14 -0
- package/dist/hooks/useCanvasClick.d.ts.map +1 -1
- package/dist/hooks/useCanvasEvents.d.ts +13 -0
- package/dist/hooks/useCanvasEvents.d.ts.map +1 -1
- package/dist/hooks/useCanvasTooltip.d.ts +13 -0
- package/dist/hooks/useCanvasTooltip.d.ts.map +1 -1
- package/dist/hooks/useEditCanvas.d.ts +28 -3
- package/dist/hooks/useEditCanvas.d.ts.map +1 -1
- package/dist/hooks/useViewCanvas.d.ts +22 -0
- package/dist/hooks/useViewCanvas.d.ts.map +1 -1
- package/dist/index.cjs +377 -170
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +5 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +364 -161
- package/dist/index.js.map +1 -1
- package/dist/overlay/FixedSizeContent.d.ts +1 -1
- package/dist/overlay/ObjectOverlay.d.ts +16 -3
- package/dist/overlay/ObjectOverlay.d.ts.map +1 -1
- package/dist/overlay/OverlayBadge.d.ts +1 -1
- package/dist/overlay/OverlayContent.d.ts +1 -1
- package/dist/serialization.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -27,6 +27,7 @@ __export(index_exports, {
|
|
|
27
27
|
DEFAULT_DRAG_SHAPE_STYLE: () => DEFAULT_DRAG_SHAPE_STYLE,
|
|
28
28
|
DEFAULT_GUIDELINE_SHAPE_STYLE: () => DEFAULT_GUIDELINE_SHAPE_STYLE,
|
|
29
29
|
DEFAULT_SHAPE_STYLE: () => DEFAULT_SHAPE_STYLE,
|
|
30
|
+
EditCanvasProvider: () => EditCanvasProvider,
|
|
30
31
|
FabricCanvas: () => import_fabric19.Canvas,
|
|
31
32
|
FabricImage: () => import_fabric19.FabricImage,
|
|
32
33
|
FabricObject: () => import_fabric19.FabricObject,
|
|
@@ -37,6 +38,7 @@ __export(index_exports, {
|
|
|
37
38
|
Point: () => import_fabric19.Point,
|
|
38
39
|
Polygon: () => import_fabric19.Polygon,
|
|
39
40
|
Rect: () => import_fabric19.Rect,
|
|
41
|
+
ViewCanvasProvider: () => ViewCanvasProvider,
|
|
40
42
|
createCircle: () => createCircle,
|
|
41
43
|
createCircleAtPoint: () => createCircleAtPoint,
|
|
42
44
|
createHistoryTracker: () => createHistoryTracker,
|
|
@@ -77,9 +79,12 @@ __export(index_exports, {
|
|
|
77
79
|
snapCursorPoint: () => snapCursorPoint,
|
|
78
80
|
useCanvasClick: () => useCanvasClick,
|
|
79
81
|
useCanvasEvents: () => useCanvasEvents,
|
|
82
|
+
useCanvasRef: () => useCanvasRef,
|
|
80
83
|
useCanvasTooltip: () => useCanvasTooltip,
|
|
81
84
|
useEditCanvas: () => useEditCanvas,
|
|
85
|
+
useEditCanvasContext: () => useEditCanvasContext,
|
|
82
86
|
useViewCanvas: () => useViewCanvas,
|
|
87
|
+
useViewCanvasContext: () => useViewCanvasContext,
|
|
83
88
|
util: () => import_fabric19.util
|
|
84
89
|
});
|
|
85
90
|
module.exports = __toCommonJS(index_exports);
|
|
@@ -2389,6 +2394,10 @@ async function loadCanvas(canvas, json, options) {
|
|
|
2389
2394
|
});
|
|
2390
2395
|
bg.setCoords();
|
|
2391
2396
|
}
|
|
2397
|
+
if (bg.filters?.some((f) => f instanceof import_fabric16.filters.Invert)) {
|
|
2398
|
+
bg.filters = bg.filters.filter((f) => !(f instanceof import_fabric16.filters.Invert));
|
|
2399
|
+
bg.applyFilters();
|
|
2400
|
+
}
|
|
2392
2401
|
}
|
|
2393
2402
|
if (options?.filter) {
|
|
2394
2403
|
const toRemove = [];
|
|
@@ -2520,6 +2529,7 @@ function useEditCanvas(options) {
|
|
|
2520
2529
|
const vertexEditCleanupRef = (0, import_react3.useRef)(null);
|
|
2521
2530
|
const keyboardCleanupRef = (0, import_react3.useRef)(null);
|
|
2522
2531
|
const historyRef = (0, import_react3.useRef)(null);
|
|
2532
|
+
const isInitialLoadRef = (0, import_react3.useRef)(false);
|
|
2523
2533
|
const optionsRef = (0, import_react3.useRef)(options);
|
|
2524
2534
|
optionsRef.current = options;
|
|
2525
2535
|
const savedSelectabilityRef = (0, import_react3.useRef)(
|
|
@@ -2532,6 +2542,11 @@ function useEditCanvas(options) {
|
|
|
2532
2542
|
const [isDirty, setIsDirty] = (0, import_react3.useState)(false);
|
|
2533
2543
|
const [canUndo, setCanUndo] = (0, import_react3.useState)(false);
|
|
2534
2544
|
const [canRedo, setCanRedo] = (0, import_react3.useState)(false);
|
|
2545
|
+
const [objects, setObjects] = (0, import_react3.useState)([]);
|
|
2546
|
+
const [isLoading, setIsLoading] = (0, import_react3.useState)(false);
|
|
2547
|
+
const [lockLightMode, setLockLightModeState] = (0, import_react3.useState)(
|
|
2548
|
+
void 0
|
|
2549
|
+
);
|
|
2535
2550
|
const setMode = (0, import_react3.useCallback)((setup) => {
|
|
2536
2551
|
vertexEditCleanupRef.current?.();
|
|
2537
2552
|
vertexEditCleanupRef.current = null;
|
|
@@ -2616,11 +2631,14 @@ function useEditCanvas(options) {
|
|
|
2616
2631
|
canvas.on("selection:created", (e) => setSelected(e.selected ?? []));
|
|
2617
2632
|
canvas.on("selection:updated", (e) => setSelected(e.selected ?? []));
|
|
2618
2633
|
canvas.on("selection:cleared", () => setSelected([]));
|
|
2619
|
-
if (opts?.trackChanges) {
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
canvas.on("
|
|
2634
|
+
if (opts?.trackChanges !== false) {
|
|
2635
|
+
const markDirtyIfNotLoading = () => {
|
|
2636
|
+
if (!isInitialLoadRef.current) setIsDirty(true);
|
|
2637
|
+
};
|
|
2638
|
+
canvas.on("object:added", markDirtyIfNotLoading);
|
|
2639
|
+
canvas.on("object:removed", markDirtyIfNotLoading);
|
|
2640
|
+
canvas.on("object:modified", markDirtyIfNotLoading);
|
|
2641
|
+
canvas.on("background:modified", markDirtyIfNotLoading);
|
|
2624
2642
|
}
|
|
2625
2643
|
if (opts?.history) {
|
|
2626
2644
|
const syncHistoryState = () => {
|
|
@@ -2658,8 +2676,31 @@ function useEditCanvas(options) {
|
|
|
2658
2676
|
}
|
|
2659
2677
|
}
|
|
2660
2678
|
function invokeOnReady() {
|
|
2661
|
-
const
|
|
2662
|
-
|
|
2679
|
+
const initPromise = (async () => {
|
|
2680
|
+
if (opts?.canvasData) {
|
|
2681
|
+
setIsLoading(true);
|
|
2682
|
+
isInitialLoadRef.current = true;
|
|
2683
|
+
try {
|
|
2684
|
+
const loaded = await loadCanvas(canvas, opts.canvasData, {
|
|
2685
|
+
filter: opts.filter,
|
|
2686
|
+
borderRadius: opts.borderRadius
|
|
2687
|
+
});
|
|
2688
|
+
setObjects(loaded);
|
|
2689
|
+
} finally {
|
|
2690
|
+
isInitialLoadRef.current = false;
|
|
2691
|
+
setIsLoading(false);
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
})();
|
|
2695
|
+
initPromise.then(async () => {
|
|
2696
|
+
const onReadyResult = opts?.onReady?.(canvas);
|
|
2697
|
+
await Promise.resolve(onReadyResult);
|
|
2698
|
+
if (opts?.invertBackground !== void 0) {
|
|
2699
|
+
setBackgroundInverted(canvas, opts.invertBackground);
|
|
2700
|
+
}
|
|
2701
|
+
if (canvas.lockLightMode !== void 0) {
|
|
2702
|
+
setLockLightModeState(canvas.lockLightMode);
|
|
2703
|
+
}
|
|
2663
2704
|
if (opts?.autoFitToBackground !== false && canvas.backgroundImage) {
|
|
2664
2705
|
fitViewportToBackground(canvas);
|
|
2665
2706
|
syncZoom(canvasRef, setZoom);
|
|
@@ -2689,37 +2730,25 @@ function useEditCanvas(options) {
|
|
|
2689
2730
|
alignmentCleanupRef.current = null;
|
|
2690
2731
|
}
|
|
2691
2732
|
}, [options?.enableAlignment]);
|
|
2733
|
+
(0, import_react3.useEffect)(() => {
|
|
2734
|
+
const canvas = canvasRef.current;
|
|
2735
|
+
if (!canvas || options?.invertBackground === void 0) return;
|
|
2736
|
+
setBackgroundInverted(canvas, options.invertBackground);
|
|
2737
|
+
}, [options?.invertBackground]);
|
|
2738
|
+
const setLockLightMode = (0, import_react3.useCallback)((value) => {
|
|
2739
|
+
const canvas = canvasRef.current;
|
|
2740
|
+
if (canvas) {
|
|
2741
|
+
canvas.lockLightMode = value;
|
|
2742
|
+
}
|
|
2743
|
+
setLockLightModeState(value);
|
|
2744
|
+
}, []);
|
|
2692
2745
|
const setViewportMode = (0, import_react3.useCallback)((mode) => {
|
|
2693
2746
|
viewportRef.current?.setMode(mode);
|
|
2694
2747
|
setViewportModeState(mode);
|
|
2695
2748
|
}, []);
|
|
2696
2749
|
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject, zoomToFit } = useViewportActions(canvasRef, viewportRef, setZoom);
|
|
2697
|
-
const
|
|
2698
|
-
|
|
2699
|
-
const canvas = canvasRef.current;
|
|
2700
|
-
if (!canvas) throw new Error("Canvas not ready");
|
|
2701
|
-
const opts = optionsRef.current;
|
|
2702
|
-
const resizeOpts = opts?.backgroundResize !== false ? typeof opts?.backgroundResize === "object" ? { ...opts.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveContrast ? { preserveContrast: true } : void 0;
|
|
2703
|
-
const img = await setBackgroundImage(canvas, url, resizeOpts);
|
|
2704
|
-
if (opts?.autoFitToBackground !== false) {
|
|
2705
|
-
fitViewportToBackground(canvas);
|
|
2706
|
-
syncZoom(canvasRef, setZoom);
|
|
2707
|
-
}
|
|
2708
|
-
return img;
|
|
2709
|
-
},
|
|
2710
|
-
[]
|
|
2711
|
-
);
|
|
2712
|
-
return {
|
|
2713
|
-
/** Pass this to `<Canvas onReady={...} />` */
|
|
2714
|
-
onReady,
|
|
2715
|
-
/** Ref to the underlying Fabric canvas instance. */
|
|
2716
|
-
canvasRef,
|
|
2717
|
-
/** Current zoom level (reactive). */
|
|
2718
|
-
zoom,
|
|
2719
|
-
/** Currently selected objects (reactive). */
|
|
2720
|
-
selected,
|
|
2721
|
-
/** Viewport controls. */
|
|
2722
|
-
viewport: {
|
|
2750
|
+
const viewport = (0, import_react3.useMemo)(
|
|
2751
|
+
() => ({
|
|
2723
2752
|
/** Current viewport mode (reactive). */
|
|
2724
2753
|
mode: viewportMode,
|
|
2725
2754
|
/** Switch between 'select' and 'pan' viewport modes. */
|
|
@@ -2734,61 +2763,125 @@ function useEditCanvas(options) {
|
|
|
2734
2763
|
panToObject,
|
|
2735
2764
|
/** Zoom and pan to fit a specific object in the viewport. */
|
|
2736
2765
|
zoomToFit
|
|
2766
|
+
}),
|
|
2767
|
+
[
|
|
2768
|
+
viewportMode,
|
|
2769
|
+
setViewportMode,
|
|
2770
|
+
resetViewport2,
|
|
2771
|
+
zoomIn,
|
|
2772
|
+
zoomOut,
|
|
2773
|
+
panToObject,
|
|
2774
|
+
zoomToFit
|
|
2775
|
+
]
|
|
2776
|
+
);
|
|
2777
|
+
const resetDirty = (0, import_react3.useCallback)(() => setIsDirty(false), []);
|
|
2778
|
+
const markDirty = (0, import_react3.useCallback)(() => setIsDirty(true), []);
|
|
2779
|
+
const undo = (0, import_react3.useCallback)(async () => {
|
|
2780
|
+
const h = historyRef.current;
|
|
2781
|
+
if (!h) return;
|
|
2782
|
+
await h.undo();
|
|
2783
|
+
setCanUndo(h.canUndo());
|
|
2784
|
+
setCanRedo(h.canRedo());
|
|
2785
|
+
}, []);
|
|
2786
|
+
const redo = (0, import_react3.useCallback)(async () => {
|
|
2787
|
+
const h = historyRef.current;
|
|
2788
|
+
if (!h) return;
|
|
2789
|
+
await h.redo();
|
|
2790
|
+
setCanUndo(h.canUndo());
|
|
2791
|
+
setCanRedo(h.canRedo());
|
|
2792
|
+
}, []);
|
|
2793
|
+
const setBackground = (0, import_react3.useCallback)(
|
|
2794
|
+
async (url, bgOpts) => {
|
|
2795
|
+
const canvas = canvasRef.current;
|
|
2796
|
+
if (!canvas) throw new Error("Canvas not ready");
|
|
2797
|
+
const opts = optionsRef.current;
|
|
2798
|
+
const resizeOpts = opts?.backgroundResize !== false ? typeof opts?.backgroundResize === "object" ? { ...opts.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveContrast ? { preserveContrast: true } : void 0;
|
|
2799
|
+
const img = await setBackgroundImage(canvas, url, resizeOpts);
|
|
2800
|
+
if (opts?.autoFitToBackground !== false) {
|
|
2801
|
+
fitViewportToBackground(canvas);
|
|
2802
|
+
syncZoom(canvasRef, setZoom);
|
|
2803
|
+
}
|
|
2804
|
+
return img;
|
|
2737
2805
|
},
|
|
2738
|
-
|
|
2739
|
-
|
|
2740
|
-
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2744
|
-
|
|
2745
|
-
|
|
2746
|
-
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2778
|
-
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2791
|
-
|
|
2806
|
+
[]
|
|
2807
|
+
);
|
|
2808
|
+
return (0, import_react3.useMemo)(
|
|
2809
|
+
() => ({
|
|
2810
|
+
/** Pass this to `<Canvas onReady={...} />` */
|
|
2811
|
+
onReady,
|
|
2812
|
+
/** Ref to the underlying Fabric canvas instance. */
|
|
2813
|
+
canvasRef,
|
|
2814
|
+
/** Current zoom level (reactive). */
|
|
2815
|
+
zoom,
|
|
2816
|
+
/** Loaded objects (reactive). Populated when `canvasData` is provided. */
|
|
2817
|
+
objects,
|
|
2818
|
+
/** Whether canvas data is currently being loaded. */
|
|
2819
|
+
isLoading,
|
|
2820
|
+
/** Currently selected objects (reactive). */
|
|
2821
|
+
selected,
|
|
2822
|
+
/** Viewport controls. */
|
|
2823
|
+
viewport,
|
|
2824
|
+
/** Whether vertex edit mode is currently active (reactive). */
|
|
2825
|
+
isEditingVertices,
|
|
2826
|
+
/**
|
|
2827
|
+
* Activate an interaction mode or return to select mode.
|
|
2828
|
+
*
|
|
2829
|
+
* Pass a setup function to activate a creation mode:
|
|
2830
|
+
* ```ts
|
|
2831
|
+
* canvas.setMode((c, viewport) =>
|
|
2832
|
+
* enableClickToCreate(c, factory, { viewport })
|
|
2833
|
+
* );
|
|
2834
|
+
* ```
|
|
2835
|
+
*
|
|
2836
|
+
* Pass `null` to deactivate and return to select mode:
|
|
2837
|
+
* ```ts
|
|
2838
|
+
* canvas.setMode(null);
|
|
2839
|
+
* ```
|
|
2840
|
+
*/
|
|
2841
|
+
setMode,
|
|
2842
|
+
/**
|
|
2843
|
+
* Set a background image from a URL. Automatically resizes if the image
|
|
2844
|
+
* exceeds the configured limits (opt out via `backgroundResize: false`),
|
|
2845
|
+
* and fits the viewport after setting if `autoFitToBackground` is enabled.
|
|
2846
|
+
*
|
|
2847
|
+
* Pass `{ preserveContrast: true }` to keep the current background contrast
|
|
2848
|
+
* when replacing the image.
|
|
2849
|
+
*/
|
|
2850
|
+
setBackground,
|
|
2851
|
+
/** Whether the canvas has been modified since the last `resetDirty()` call. Enabled by default (disable via `trackChanges: false`). */
|
|
2852
|
+
isDirty,
|
|
2853
|
+
/** Reset the dirty flag (e.g., after a successful save). */
|
|
2854
|
+
resetDirty,
|
|
2855
|
+
/** Manually mark the canvas as dirty (e.g., after a custom operation not tracked automatically). */
|
|
2856
|
+
markDirty,
|
|
2857
|
+
/** Undo the last change. Requires `history: true`. */
|
|
2858
|
+
undo,
|
|
2859
|
+
/** Redo a previously undone change. Requires `history: true`. */
|
|
2860
|
+
redo,
|
|
2861
|
+
/** Whether an undo operation is available (reactive). Requires `history: true`. */
|
|
2862
|
+
canUndo,
|
|
2863
|
+
/** Whether a redo operation is available (reactive). Requires `history: true`. */
|
|
2864
|
+
canRedo,
|
|
2865
|
+
/** Whether the canvas is locked to light mode. Read from loaded canvas data. */
|
|
2866
|
+
lockLightMode,
|
|
2867
|
+
/** Update lockLightMode on both the canvas instance and React state. */
|
|
2868
|
+
setLockLightMode
|
|
2869
|
+
}),
|
|
2870
|
+
// Only reactive state in deps — refs and stable callbacks are omitted
|
|
2871
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2872
|
+
[
|
|
2873
|
+
zoom,
|
|
2874
|
+
objects,
|
|
2875
|
+
isLoading,
|
|
2876
|
+
selected,
|
|
2877
|
+
viewport,
|
|
2878
|
+
isEditingVertices,
|
|
2879
|
+
isDirty,
|
|
2880
|
+
canUndo,
|
|
2881
|
+
canRedo,
|
|
2882
|
+
lockLightMode
|
|
2883
|
+
]
|
|
2884
|
+
);
|
|
2792
2885
|
}
|
|
2793
2886
|
|
|
2794
2887
|
// src/hooks/useViewCanvas.ts
|
|
@@ -2805,6 +2898,8 @@ function useViewCanvas(options) {
|
|
|
2805
2898
|
const optionsRef = (0, import_react4.useRef)(options);
|
|
2806
2899
|
optionsRef.current = options;
|
|
2807
2900
|
const [zoom, setZoom] = (0, import_react4.useState)(1);
|
|
2901
|
+
const [objects, setObjects] = (0, import_react4.useState)([]);
|
|
2902
|
+
const [isLoading, setIsLoading] = (0, import_react4.useState)(false);
|
|
2808
2903
|
const onReady = (0, import_react4.useCallback)(
|
|
2809
2904
|
(canvas) => {
|
|
2810
2905
|
canvasRef.current = canvas;
|
|
@@ -2831,20 +2926,57 @@ function useViewCanvas(options) {
|
|
|
2831
2926
|
canvas.on("mouse:wheel", () => {
|
|
2832
2927
|
setZoom(canvas.getZoom());
|
|
2833
2928
|
});
|
|
2834
|
-
const
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2929
|
+
const initPromise = (async () => {
|
|
2930
|
+
if (opts?.canvasData) {
|
|
2931
|
+
setIsLoading(true);
|
|
2932
|
+
try {
|
|
2933
|
+
const loaded = await loadCanvas(canvas, opts.canvasData, {
|
|
2934
|
+
filter: opts.filter,
|
|
2935
|
+
borderRadius: opts.borderRadius
|
|
2936
|
+
});
|
|
2937
|
+
lockCanvas(canvas);
|
|
2938
|
+
setObjects(loaded);
|
|
2939
|
+
} finally {
|
|
2940
|
+
setIsLoading(false);
|
|
2840
2941
|
}
|
|
2841
|
-
}
|
|
2842
|
-
}
|
|
2942
|
+
}
|
|
2943
|
+
})();
|
|
2944
|
+
initPromise.then(async () => {
|
|
2945
|
+
const onReadyResult = opts?.onReady?.(canvas);
|
|
2946
|
+
await Promise.resolve(onReadyResult);
|
|
2947
|
+
if (opts?.invertBackground !== void 0) {
|
|
2948
|
+
setBackgroundInverted(canvas, opts.invertBackground);
|
|
2949
|
+
}
|
|
2950
|
+
if (opts?.autoFitToBackground !== false && canvas.backgroundImage) {
|
|
2951
|
+
fitViewportToBackground(canvas);
|
|
2952
|
+
syncZoom(canvasRef, setZoom);
|
|
2953
|
+
}
|
|
2954
|
+
});
|
|
2843
2955
|
},
|
|
2844
2956
|
// onReady and panAndZoom are intentionally excluded — we only initialize once
|
|
2845
2957
|
[]
|
|
2846
2958
|
);
|
|
2959
|
+
(0, import_react4.useEffect)(() => {
|
|
2960
|
+
const canvas = canvasRef.current;
|
|
2961
|
+
if (!canvas || options?.invertBackground === void 0) return;
|
|
2962
|
+
setBackgroundInverted(canvas, options.invertBackground);
|
|
2963
|
+
}, [options?.invertBackground]);
|
|
2847
2964
|
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject, zoomToFit } = useViewportActions(canvasRef, viewportRef, setZoom);
|
|
2965
|
+
const viewport = (0, import_react4.useMemo)(
|
|
2966
|
+
() => ({
|
|
2967
|
+
/** Reset viewport to default (no pan, zoom = 1), or fit to background if one is set. */
|
|
2968
|
+
reset: resetViewport2,
|
|
2969
|
+
/** Zoom in toward the canvas center. Default step: 0.2. */
|
|
2970
|
+
zoomIn,
|
|
2971
|
+
/** Zoom out from the canvas center. Default step: 0.2. */
|
|
2972
|
+
zoomOut,
|
|
2973
|
+
/** Pan the viewport to center on a specific object. */
|
|
2974
|
+
panToObject,
|
|
2975
|
+
/** Zoom and pan to fit a specific object in the viewport. */
|
|
2976
|
+
zoomToFit
|
|
2977
|
+
}),
|
|
2978
|
+
[resetViewport2, zoomIn, zoomOut, panToObject, zoomToFit]
|
|
2979
|
+
);
|
|
2848
2980
|
const findObject = (id) => {
|
|
2849
2981
|
const c = canvasRef.current;
|
|
2850
2982
|
if (!c) return void 0;
|
|
@@ -2860,9 +2992,9 @@ function useViewCanvas(options) {
|
|
|
2860
2992
|
(styles) => {
|
|
2861
2993
|
const c = canvasRef.current;
|
|
2862
2994
|
if (!c) return;
|
|
2863
|
-
const
|
|
2995
|
+
const objects2 = c.getObjects();
|
|
2864
2996
|
const idMap = /* @__PURE__ */ new Map();
|
|
2865
|
-
for (const obj of
|
|
2997
|
+
for (const obj of objects2) {
|
|
2866
2998
|
if (obj.data?.id) idMap.set(obj.data.id, obj);
|
|
2867
2999
|
}
|
|
2868
3000
|
let updated = false;
|
|
@@ -2892,42 +3024,101 @@ function useViewCanvas(options) {
|
|
|
2892
3024
|
},
|
|
2893
3025
|
[]
|
|
2894
3026
|
);
|
|
2895
|
-
return
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
|
-
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
setObjectStyleByType
|
|
2921
|
-
};
|
|
3027
|
+
return (0, import_react4.useMemo)(
|
|
3028
|
+
() => ({
|
|
3029
|
+
/** Pass this to `<Canvas onReady={...} />` */
|
|
3030
|
+
onReady,
|
|
3031
|
+
/** Ref to the underlying Fabric canvas instance. */
|
|
3032
|
+
canvasRef,
|
|
3033
|
+
/** Current zoom level (reactive). */
|
|
3034
|
+
zoom,
|
|
3035
|
+
/** Loaded objects (reactive). Populated when `canvasData` is provided. */
|
|
3036
|
+
objects,
|
|
3037
|
+
/** Whether canvas data is currently being loaded. */
|
|
3038
|
+
isLoading,
|
|
3039
|
+
/** Viewport controls. */
|
|
3040
|
+
viewport,
|
|
3041
|
+
/** Update a single object's visual style by its `data.id`. */
|
|
3042
|
+
setObjectStyle,
|
|
3043
|
+
/** Batch-update multiple objects' visual styles in one render. Keyed by `data.id`. */
|
|
3044
|
+
setObjectStyles,
|
|
3045
|
+
/** Apply a visual style to all objects whose `data.type` matches. */
|
|
3046
|
+
setObjectStyleByType
|
|
3047
|
+
}),
|
|
3048
|
+
// Only reactive state in deps — refs and stable callbacks are omitted
|
|
3049
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
3050
|
+
[zoom, objects, isLoading, viewport]
|
|
3051
|
+
);
|
|
2922
3052
|
}
|
|
2923
3053
|
|
|
2924
3054
|
// src/hooks/useCanvasEvents.ts
|
|
3055
|
+
var import_react7 = require("react");
|
|
3056
|
+
|
|
3057
|
+
// src/context/ViewCanvasContext.tsx
|
|
2925
3058
|
var import_react5 = require("react");
|
|
2926
|
-
|
|
2927
|
-
|
|
3059
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
3060
|
+
var ViewCanvasContext = (0, import_react5.createContext)(null);
|
|
3061
|
+
function ViewCanvasProvider({
|
|
3062
|
+
options,
|
|
3063
|
+
children
|
|
3064
|
+
}) {
|
|
3065
|
+
const canvas = useViewCanvas(options);
|
|
3066
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(ViewCanvasContext.Provider, { value: canvas, children });
|
|
3067
|
+
}
|
|
3068
|
+
function useViewCanvasContext() {
|
|
3069
|
+
const ctx = (0, import_react5.useContext)(ViewCanvasContext);
|
|
3070
|
+
if (ctx === null) {
|
|
3071
|
+
throw new Error(
|
|
3072
|
+
"useViewCanvasContext must be used within a <ViewCanvasProvider>"
|
|
3073
|
+
);
|
|
3074
|
+
}
|
|
3075
|
+
return ctx;
|
|
3076
|
+
}
|
|
3077
|
+
function useViewCanvasContextSafe() {
|
|
3078
|
+
return (0, import_react5.useContext)(ViewCanvasContext);
|
|
3079
|
+
}
|
|
3080
|
+
|
|
3081
|
+
// src/context/EditCanvasContext.tsx
|
|
3082
|
+
var import_react6 = require("react");
|
|
3083
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
3084
|
+
var EditCanvasContext = (0, import_react6.createContext)(null);
|
|
3085
|
+
function EditCanvasProvider({
|
|
3086
|
+
options,
|
|
3087
|
+
children
|
|
3088
|
+
}) {
|
|
3089
|
+
const canvas = useEditCanvas(options);
|
|
3090
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EditCanvasContext.Provider, { value: canvas, children });
|
|
3091
|
+
}
|
|
3092
|
+
function useEditCanvasContext() {
|
|
3093
|
+
const ctx = (0, import_react6.useContext)(EditCanvasContext);
|
|
3094
|
+
if (ctx === null) {
|
|
3095
|
+
throw new Error(
|
|
3096
|
+
"useEditCanvasContext must be used within an <EditCanvasProvider>"
|
|
3097
|
+
);
|
|
3098
|
+
}
|
|
3099
|
+
return ctx;
|
|
3100
|
+
}
|
|
3101
|
+
function useEditCanvasContextSafe() {
|
|
3102
|
+
return (0, import_react6.useContext)(EditCanvasContext);
|
|
3103
|
+
}
|
|
3104
|
+
|
|
3105
|
+
// src/context/useCanvasRef.ts
|
|
3106
|
+
function useCanvasRef() {
|
|
3107
|
+
const viewCtx = useViewCanvasContextSafe();
|
|
3108
|
+
const editCtx = useEditCanvasContextSafe();
|
|
3109
|
+
return viewCtx?.canvasRef ?? editCtx?.canvasRef ?? null;
|
|
3110
|
+
}
|
|
3111
|
+
|
|
3112
|
+
// src/hooks/useCanvasEvents.ts
|
|
3113
|
+
function useCanvasEvents(canvasRefOrEvents, maybeEvents) {
|
|
3114
|
+
const isContextOverload = maybeEvents === void 0;
|
|
3115
|
+
const contextCanvasRef = useCanvasRef();
|
|
3116
|
+
const resolvedCanvasRef = isContextOverload ? contextCanvasRef : canvasRefOrEvents;
|
|
3117
|
+
const events = isContextOverload ? canvasRefOrEvents : maybeEvents;
|
|
3118
|
+
const eventsRef = (0, import_react7.useRef)(events);
|
|
2928
3119
|
eventsRef.current = events;
|
|
2929
|
-
(0,
|
|
2930
|
-
const canvas =
|
|
3120
|
+
(0, import_react7.useEffect)(() => {
|
|
3121
|
+
const canvas = resolvedCanvasRef?.current;
|
|
2931
3122
|
if (!canvas) return;
|
|
2932
3123
|
const wrappers = /* @__PURE__ */ new Map();
|
|
2933
3124
|
for (const key of Object.keys(eventsRef.current)) {
|
|
@@ -2943,22 +3134,26 @@ function useCanvasEvents(canvasRef, events) {
|
|
|
2943
3134
|
canvas.off(name, handler);
|
|
2944
3135
|
});
|
|
2945
3136
|
};
|
|
2946
|
-
}, [
|
|
3137
|
+
}, [resolvedCanvasRef]);
|
|
2947
3138
|
}
|
|
2948
3139
|
|
|
2949
3140
|
// src/hooks/useCanvasTooltip.ts
|
|
2950
|
-
var
|
|
2951
|
-
function useCanvasTooltip(
|
|
2952
|
-
const
|
|
3141
|
+
var import_react8 = require("react");
|
|
3142
|
+
function useCanvasTooltip(canvasRefOrOptions, maybeOptions) {
|
|
3143
|
+
const isContextOverload = maybeOptions === void 0;
|
|
3144
|
+
const contextCanvasRef = useCanvasRef();
|
|
3145
|
+
const resolvedCanvasRef = isContextOverload ? contextCanvasRef : canvasRefOrOptions;
|
|
3146
|
+
const options = isContextOverload ? canvasRefOrOptions : maybeOptions;
|
|
3147
|
+
const [state, setState] = (0, import_react8.useState)({
|
|
2953
3148
|
visible: false,
|
|
2954
3149
|
content: null,
|
|
2955
3150
|
position: { x: 0, y: 0 }
|
|
2956
3151
|
});
|
|
2957
|
-
const hoveredObjectRef = (0,
|
|
2958
|
-
const optionsRef = (0,
|
|
3152
|
+
const hoveredObjectRef = (0, import_react8.useRef)(null);
|
|
3153
|
+
const optionsRef = (0, import_react8.useRef)(options);
|
|
2959
3154
|
optionsRef.current = options;
|
|
2960
|
-
(0,
|
|
2961
|
-
const canvas =
|
|
3155
|
+
(0, import_react8.useEffect)(() => {
|
|
3156
|
+
const canvas = resolvedCanvasRef?.current;
|
|
2962
3157
|
if (!canvas) return;
|
|
2963
3158
|
function calculatePosition(target) {
|
|
2964
3159
|
const bounds = target.getBoundingRect();
|
|
@@ -3006,19 +3201,24 @@ function useCanvasTooltip(canvasRef, options) {
|
|
|
3006
3201
|
canvas.off("after:render", updatePosition);
|
|
3007
3202
|
canvas.off("mouse:wheel", updatePosition);
|
|
3008
3203
|
};
|
|
3009
|
-
}, [
|
|
3204
|
+
}, [resolvedCanvasRef]);
|
|
3010
3205
|
return state;
|
|
3011
3206
|
}
|
|
3012
3207
|
|
|
3013
3208
|
// src/hooks/useCanvasClick.ts
|
|
3014
|
-
var
|
|
3015
|
-
function useCanvasClick(
|
|
3016
|
-
const
|
|
3209
|
+
var import_react9 = require("react");
|
|
3210
|
+
function useCanvasClick(canvasRefOrOnClick, onClickOrOptions, maybeOptions) {
|
|
3211
|
+
const isContextOverload = typeof canvasRefOrOnClick === "function";
|
|
3212
|
+
const contextCanvasRef = useCanvasRef();
|
|
3213
|
+
const resolvedCanvasRef = isContextOverload ? contextCanvasRef : canvasRefOrOnClick;
|
|
3214
|
+
const onClick = isContextOverload ? canvasRefOrOnClick : onClickOrOptions;
|
|
3215
|
+
const options = isContextOverload ? onClickOrOptions : maybeOptions;
|
|
3216
|
+
const onClickRef = (0, import_react9.useRef)(onClick);
|
|
3017
3217
|
onClickRef.current = onClick;
|
|
3018
|
-
const optionsRef = (0,
|
|
3218
|
+
const optionsRef = (0, import_react9.useRef)(options);
|
|
3019
3219
|
optionsRef.current = options;
|
|
3020
|
-
(0,
|
|
3021
|
-
const canvas =
|
|
3220
|
+
(0, import_react9.useEffect)(() => {
|
|
3221
|
+
const canvas = resolvedCanvasRef?.current;
|
|
3022
3222
|
if (!canvas) return;
|
|
3023
3223
|
let mouseDown = null;
|
|
3024
3224
|
let isPanning = false;
|
|
@@ -3058,24 +3258,26 @@ function useCanvasClick(canvasRef, onClick, options) {
|
|
|
3058
3258
|
canvas.off("mouse:move", handleMouseMove);
|
|
3059
3259
|
canvas.off("mouse:up", handleMouseUp);
|
|
3060
3260
|
};
|
|
3061
|
-
}, [
|
|
3261
|
+
}, [resolvedCanvasRef]);
|
|
3062
3262
|
}
|
|
3063
3263
|
|
|
3064
3264
|
// src/overlay/ObjectOverlay.tsx
|
|
3065
|
-
var
|
|
3265
|
+
var import_react10 = require("react");
|
|
3066
3266
|
var import_material = require("@mui/material");
|
|
3067
3267
|
var import_fabric18 = require("fabric");
|
|
3068
|
-
var
|
|
3268
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
3069
3269
|
function ObjectOverlay({
|
|
3070
|
-
canvasRef,
|
|
3270
|
+
canvasRef: canvasRefProp,
|
|
3071
3271
|
object,
|
|
3072
3272
|
sx,
|
|
3073
3273
|
children,
|
|
3074
3274
|
...rest
|
|
3075
3275
|
}) {
|
|
3076
|
-
const
|
|
3077
|
-
|
|
3078
|
-
|
|
3276
|
+
const contextCanvasRef = useCanvasRef();
|
|
3277
|
+
const canvasRef = canvasRefProp ?? contextCanvasRef;
|
|
3278
|
+
const stackRef = (0, import_react10.useRef)(null);
|
|
3279
|
+
(0, import_react10.useEffect)(() => {
|
|
3280
|
+
const canvas = canvasRef?.current;
|
|
3079
3281
|
if (!canvas || !object) return;
|
|
3080
3282
|
function update() {
|
|
3081
3283
|
const el = stackRef.current;
|
|
@@ -3109,7 +3311,7 @@ function ObjectOverlay({
|
|
|
3109
3311
|
};
|
|
3110
3312
|
}, [canvasRef, object]);
|
|
3111
3313
|
if (!object) return null;
|
|
3112
|
-
return /* @__PURE__ */ (0,
|
|
3314
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
3113
3315
|
import_material.Stack,
|
|
3114
3316
|
{
|
|
3115
3317
|
ref: stackRef,
|
|
@@ -3129,8 +3331,8 @@ function ObjectOverlay({
|
|
|
3129
3331
|
|
|
3130
3332
|
// src/overlay/OverlayContent.tsx
|
|
3131
3333
|
var import_material2 = require("@mui/material");
|
|
3132
|
-
var
|
|
3133
|
-
var
|
|
3334
|
+
var import_react11 = require("react");
|
|
3335
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
3134
3336
|
function OverlayContent({
|
|
3135
3337
|
children,
|
|
3136
3338
|
padding = 4,
|
|
@@ -3138,9 +3340,9 @@ function OverlayContent({
|
|
|
3138
3340
|
sx,
|
|
3139
3341
|
...rest
|
|
3140
3342
|
}) {
|
|
3141
|
-
const outerRef = (0,
|
|
3142
|
-
const innerRef = (0,
|
|
3143
|
-
(0,
|
|
3343
|
+
const outerRef = (0, import_react11.useRef)(null);
|
|
3344
|
+
const innerRef = (0, import_react11.useRef)(null);
|
|
3345
|
+
(0, import_react11.useEffect)(() => {
|
|
3144
3346
|
const outer = outerRef.current;
|
|
3145
3347
|
const inner = innerRef.current;
|
|
3146
3348
|
if (!outer || !inner) return;
|
|
@@ -3169,7 +3371,7 @@ function OverlayContent({
|
|
|
3169
3371
|
fit();
|
|
3170
3372
|
return () => observer.disconnect();
|
|
3171
3373
|
}, [padding, maxScale]);
|
|
3172
|
-
return /* @__PURE__ */ (0,
|
|
3374
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3173
3375
|
import_material2.Stack,
|
|
3174
3376
|
{
|
|
3175
3377
|
ref: outerRef,
|
|
@@ -3182,7 +3384,7 @@ function OverlayContent({
|
|
|
3182
3384
|
...sx
|
|
3183
3385
|
},
|
|
3184
3386
|
...rest,
|
|
3185
|
-
children: /* @__PURE__ */ (0,
|
|
3387
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
3186
3388
|
import_material2.Stack,
|
|
3187
3389
|
{
|
|
3188
3390
|
ref: innerRef,
|
|
@@ -3201,8 +3403,8 @@ function OverlayContent({
|
|
|
3201
3403
|
|
|
3202
3404
|
// src/overlay/FixedSizeContent.tsx
|
|
3203
3405
|
var import_material3 = require("@mui/material");
|
|
3204
|
-
var
|
|
3205
|
-
var
|
|
3406
|
+
var import_react12 = require("react");
|
|
3407
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
3206
3408
|
function FixedSizeContent({
|
|
3207
3409
|
children,
|
|
3208
3410
|
hideOnOverflow = true,
|
|
@@ -3210,9 +3412,9 @@ function FixedSizeContent({
|
|
|
3210
3412
|
sx,
|
|
3211
3413
|
...rest
|
|
3212
3414
|
}) {
|
|
3213
|
-
const ref = (0,
|
|
3214
|
-
const totalContentHeightRef = (0,
|
|
3215
|
-
(0,
|
|
3415
|
+
const ref = (0, import_react12.useRef)(null);
|
|
3416
|
+
const totalContentHeightRef = (0, import_react12.useRef)(0);
|
|
3417
|
+
(0, import_react12.useEffect)(() => {
|
|
3216
3418
|
const el = ref.current;
|
|
3217
3419
|
if (!el) return;
|
|
3218
3420
|
let clipAncestor = el.parentElement;
|
|
@@ -3249,7 +3451,7 @@ function FixedSizeContent({
|
|
|
3249
3451
|
check();
|
|
3250
3452
|
return () => observer.disconnect();
|
|
3251
3453
|
}, [hideOnOverflow, truncationPadding]);
|
|
3252
|
-
return /* @__PURE__ */ (0,
|
|
3454
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3253
3455
|
import_material3.Stack,
|
|
3254
3456
|
{
|
|
3255
3457
|
ref,
|
|
@@ -3275,8 +3477,8 @@ function FixedSizeContent({
|
|
|
3275
3477
|
|
|
3276
3478
|
// src/overlay/OverlayBadge.tsx
|
|
3277
3479
|
var import_material4 = require("@mui/material");
|
|
3278
|
-
var
|
|
3279
|
-
var
|
|
3480
|
+
var import_react13 = require("react");
|
|
3481
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3280
3482
|
function toPx(v) {
|
|
3281
3483
|
if (v === void 0) return void 0;
|
|
3282
3484
|
return typeof v === "number" ? `${v}px` : v;
|
|
@@ -3318,9 +3520,9 @@ function OverlayBadge({
|
|
|
3318
3520
|
sx,
|
|
3319
3521
|
...rest
|
|
3320
3522
|
}) {
|
|
3321
|
-
const ref = (0,
|
|
3322
|
-
const baseSize = (0,
|
|
3323
|
-
(0,
|
|
3523
|
+
const ref = (0, import_react13.useRef)(null);
|
|
3524
|
+
const baseSize = (0, import_react13.useRef)(null);
|
|
3525
|
+
(0, import_react13.useEffect)(() => {
|
|
3324
3526
|
const el = ref.current;
|
|
3325
3527
|
if (!el) return;
|
|
3326
3528
|
const ancestor = el.parentElement;
|
|
@@ -3372,7 +3574,7 @@ function OverlayBadge({
|
|
|
3372
3574
|
bottom: toPx(bottom),
|
|
3373
3575
|
left: toPx(left)
|
|
3374
3576
|
};
|
|
3375
|
-
return /* @__PURE__ */ (0,
|
|
3577
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3376
3578
|
import_material4.Stack,
|
|
3377
3579
|
{
|
|
3378
3580
|
ref,
|
|
@@ -3403,6 +3605,7 @@ var import_fabric19 = require("fabric");
|
|
|
3403
3605
|
DEFAULT_DRAG_SHAPE_STYLE,
|
|
3404
3606
|
DEFAULT_GUIDELINE_SHAPE_STYLE,
|
|
3405
3607
|
DEFAULT_SHAPE_STYLE,
|
|
3608
|
+
EditCanvasProvider,
|
|
3406
3609
|
FabricCanvas,
|
|
3407
3610
|
FabricImage,
|
|
3408
3611
|
FabricObject,
|
|
@@ -3413,6 +3616,7 @@ var import_fabric19 = require("fabric");
|
|
|
3413
3616
|
Point,
|
|
3414
3617
|
Polygon,
|
|
3415
3618
|
Rect,
|
|
3619
|
+
ViewCanvasProvider,
|
|
3416
3620
|
createCircle,
|
|
3417
3621
|
createCircleAtPoint,
|
|
3418
3622
|
createHistoryTracker,
|
|
@@ -3453,9 +3657,12 @@ var import_fabric19 = require("fabric");
|
|
|
3453
3657
|
snapCursorPoint,
|
|
3454
3658
|
useCanvasClick,
|
|
3455
3659
|
useCanvasEvents,
|
|
3660
|
+
useCanvasRef,
|
|
3456
3661
|
useCanvasTooltip,
|
|
3457
3662
|
useEditCanvas,
|
|
3663
|
+
useEditCanvasContext,
|
|
3458
3664
|
useViewCanvas,
|
|
3665
|
+
useViewCanvasContext,
|
|
3459
3666
|
util
|
|
3460
3667
|
});
|
|
3461
3668
|
//# sourceMappingURL=index.cjs.map
|