@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.js
CHANGED
|
@@ -85,7 +85,7 @@ function Canvas({
|
|
|
85
85
|
}
|
|
86
86
|
|
|
87
87
|
// src/hooks/useEditCanvas.ts
|
|
88
|
-
import { useCallback, useEffect as useEffect2, useRef as useRef2, useState } from "react";
|
|
88
|
+
import { useCallback, useEffect as useEffect2, useMemo as useMemo2, useRef as useRef2, useState } from "react";
|
|
89
89
|
import { Polygon as Polygon4 } from "fabric";
|
|
90
90
|
|
|
91
91
|
// src/viewport.ts
|
|
@@ -2126,7 +2126,8 @@ function enableVertexEdit(canvas, polygon, options, onExit) {
|
|
|
2126
2126
|
// src/serialization.ts
|
|
2127
2127
|
import {
|
|
2128
2128
|
FabricImage as FabricImage2,
|
|
2129
|
-
Rect as Rect5
|
|
2129
|
+
Rect as Rect5,
|
|
2130
|
+
filters as filters2
|
|
2130
2131
|
} from "fabric";
|
|
2131
2132
|
var strokeBaseMap = /* @__PURE__ */ new WeakMap();
|
|
2132
2133
|
var borderRadiusBaseMap = /* @__PURE__ */ new WeakMap();
|
|
@@ -2319,6 +2320,10 @@ async function loadCanvas(canvas, json, options) {
|
|
|
2319
2320
|
});
|
|
2320
2321
|
bg.setCoords();
|
|
2321
2322
|
}
|
|
2323
|
+
if (bg.filters?.some((f) => f instanceof filters2.Invert)) {
|
|
2324
|
+
bg.filters = bg.filters.filter((f) => !(f instanceof filters2.Invert));
|
|
2325
|
+
bg.applyFilters();
|
|
2326
|
+
}
|
|
2322
2327
|
}
|
|
2323
2328
|
if (options?.filter) {
|
|
2324
2329
|
const toRemove = [];
|
|
@@ -2450,6 +2455,7 @@ function useEditCanvas(options) {
|
|
|
2450
2455
|
const vertexEditCleanupRef = useRef2(null);
|
|
2451
2456
|
const keyboardCleanupRef = useRef2(null);
|
|
2452
2457
|
const historyRef = useRef2(null);
|
|
2458
|
+
const isInitialLoadRef = useRef2(false);
|
|
2453
2459
|
const optionsRef = useRef2(options);
|
|
2454
2460
|
optionsRef.current = options;
|
|
2455
2461
|
const savedSelectabilityRef = useRef2(
|
|
@@ -2462,6 +2468,11 @@ function useEditCanvas(options) {
|
|
|
2462
2468
|
const [isDirty, setIsDirty] = useState(false);
|
|
2463
2469
|
const [canUndo, setCanUndo] = useState(false);
|
|
2464
2470
|
const [canRedo, setCanRedo] = useState(false);
|
|
2471
|
+
const [objects, setObjects] = useState([]);
|
|
2472
|
+
const [isLoading, setIsLoading] = useState(false);
|
|
2473
|
+
const [lockLightMode, setLockLightModeState] = useState(
|
|
2474
|
+
void 0
|
|
2475
|
+
);
|
|
2465
2476
|
const setMode = useCallback((setup) => {
|
|
2466
2477
|
vertexEditCleanupRef.current?.();
|
|
2467
2478
|
vertexEditCleanupRef.current = null;
|
|
@@ -2546,11 +2557,14 @@ function useEditCanvas(options) {
|
|
|
2546
2557
|
canvas.on("selection:created", (e) => setSelected(e.selected ?? []));
|
|
2547
2558
|
canvas.on("selection:updated", (e) => setSelected(e.selected ?? []));
|
|
2548
2559
|
canvas.on("selection:cleared", () => setSelected([]));
|
|
2549
|
-
if (opts?.trackChanges) {
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
canvas.on("
|
|
2560
|
+
if (opts?.trackChanges !== false) {
|
|
2561
|
+
const markDirtyIfNotLoading = () => {
|
|
2562
|
+
if (!isInitialLoadRef.current) setIsDirty(true);
|
|
2563
|
+
};
|
|
2564
|
+
canvas.on("object:added", markDirtyIfNotLoading);
|
|
2565
|
+
canvas.on("object:removed", markDirtyIfNotLoading);
|
|
2566
|
+
canvas.on("object:modified", markDirtyIfNotLoading);
|
|
2567
|
+
canvas.on("background:modified", markDirtyIfNotLoading);
|
|
2554
2568
|
}
|
|
2555
2569
|
if (opts?.history) {
|
|
2556
2570
|
const syncHistoryState = () => {
|
|
@@ -2588,8 +2602,31 @@ function useEditCanvas(options) {
|
|
|
2588
2602
|
}
|
|
2589
2603
|
}
|
|
2590
2604
|
function invokeOnReady() {
|
|
2591
|
-
const
|
|
2592
|
-
|
|
2605
|
+
const initPromise = (async () => {
|
|
2606
|
+
if (opts?.canvasData) {
|
|
2607
|
+
setIsLoading(true);
|
|
2608
|
+
isInitialLoadRef.current = true;
|
|
2609
|
+
try {
|
|
2610
|
+
const loaded = await loadCanvas(canvas, opts.canvasData, {
|
|
2611
|
+
filter: opts.filter,
|
|
2612
|
+
borderRadius: opts.borderRadius
|
|
2613
|
+
});
|
|
2614
|
+
setObjects(loaded);
|
|
2615
|
+
} finally {
|
|
2616
|
+
isInitialLoadRef.current = false;
|
|
2617
|
+
setIsLoading(false);
|
|
2618
|
+
}
|
|
2619
|
+
}
|
|
2620
|
+
})();
|
|
2621
|
+
initPromise.then(async () => {
|
|
2622
|
+
const onReadyResult = opts?.onReady?.(canvas);
|
|
2623
|
+
await Promise.resolve(onReadyResult);
|
|
2624
|
+
if (opts?.invertBackground !== void 0) {
|
|
2625
|
+
setBackgroundInverted(canvas, opts.invertBackground);
|
|
2626
|
+
}
|
|
2627
|
+
if (canvas.lockLightMode !== void 0) {
|
|
2628
|
+
setLockLightModeState(canvas.lockLightMode);
|
|
2629
|
+
}
|
|
2593
2630
|
if (opts?.autoFitToBackground !== false && canvas.backgroundImage) {
|
|
2594
2631
|
fitViewportToBackground(canvas);
|
|
2595
2632
|
syncZoom(canvasRef, setZoom);
|
|
@@ -2619,37 +2656,25 @@ function useEditCanvas(options) {
|
|
|
2619
2656
|
alignmentCleanupRef.current = null;
|
|
2620
2657
|
}
|
|
2621
2658
|
}, [options?.enableAlignment]);
|
|
2659
|
+
useEffect2(() => {
|
|
2660
|
+
const canvas = canvasRef.current;
|
|
2661
|
+
if (!canvas || options?.invertBackground === void 0) return;
|
|
2662
|
+
setBackgroundInverted(canvas, options.invertBackground);
|
|
2663
|
+
}, [options?.invertBackground]);
|
|
2664
|
+
const setLockLightMode = useCallback((value) => {
|
|
2665
|
+
const canvas = canvasRef.current;
|
|
2666
|
+
if (canvas) {
|
|
2667
|
+
canvas.lockLightMode = value;
|
|
2668
|
+
}
|
|
2669
|
+
setLockLightModeState(value);
|
|
2670
|
+
}, []);
|
|
2622
2671
|
const setViewportMode = useCallback((mode) => {
|
|
2623
2672
|
viewportRef.current?.setMode(mode);
|
|
2624
2673
|
setViewportModeState(mode);
|
|
2625
2674
|
}, []);
|
|
2626
2675
|
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject, zoomToFit } = useViewportActions(canvasRef, viewportRef, setZoom);
|
|
2627
|
-
const
|
|
2628
|
-
|
|
2629
|
-
const canvas = canvasRef.current;
|
|
2630
|
-
if (!canvas) throw new Error("Canvas not ready");
|
|
2631
|
-
const opts = optionsRef.current;
|
|
2632
|
-
const resizeOpts = opts?.backgroundResize !== false ? typeof opts?.backgroundResize === "object" ? { ...opts.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveContrast ? { preserveContrast: true } : void 0;
|
|
2633
|
-
const img = await setBackgroundImage(canvas, url, resizeOpts);
|
|
2634
|
-
if (opts?.autoFitToBackground !== false) {
|
|
2635
|
-
fitViewportToBackground(canvas);
|
|
2636
|
-
syncZoom(canvasRef, setZoom);
|
|
2637
|
-
}
|
|
2638
|
-
return img;
|
|
2639
|
-
},
|
|
2640
|
-
[]
|
|
2641
|
-
);
|
|
2642
|
-
return {
|
|
2643
|
-
/** Pass this to `<Canvas onReady={...} />` */
|
|
2644
|
-
onReady,
|
|
2645
|
-
/** Ref to the underlying Fabric canvas instance. */
|
|
2646
|
-
canvasRef,
|
|
2647
|
-
/** Current zoom level (reactive). */
|
|
2648
|
-
zoom,
|
|
2649
|
-
/** Currently selected objects (reactive). */
|
|
2650
|
-
selected,
|
|
2651
|
-
/** Viewport controls. */
|
|
2652
|
-
viewport: {
|
|
2676
|
+
const viewport = useMemo2(
|
|
2677
|
+
() => ({
|
|
2653
2678
|
/** Current viewport mode (reactive). */
|
|
2654
2679
|
mode: viewportMode,
|
|
2655
2680
|
/** Switch between 'select' and 'pan' viewport modes. */
|
|
@@ -2664,65 +2689,129 @@ function useEditCanvas(options) {
|
|
|
2664
2689
|
panToObject,
|
|
2665
2690
|
/** Zoom and pan to fit a specific object in the viewport. */
|
|
2666
2691
|
zoomToFit
|
|
2692
|
+
}),
|
|
2693
|
+
[
|
|
2694
|
+
viewportMode,
|
|
2695
|
+
setViewportMode,
|
|
2696
|
+
resetViewport2,
|
|
2697
|
+
zoomIn,
|
|
2698
|
+
zoomOut,
|
|
2699
|
+
panToObject,
|
|
2700
|
+
zoomToFit
|
|
2701
|
+
]
|
|
2702
|
+
);
|
|
2703
|
+
const resetDirty = useCallback(() => setIsDirty(false), []);
|
|
2704
|
+
const markDirty = useCallback(() => setIsDirty(true), []);
|
|
2705
|
+
const undo = useCallback(async () => {
|
|
2706
|
+
const h = historyRef.current;
|
|
2707
|
+
if (!h) return;
|
|
2708
|
+
await h.undo();
|
|
2709
|
+
setCanUndo(h.canUndo());
|
|
2710
|
+
setCanRedo(h.canRedo());
|
|
2711
|
+
}, []);
|
|
2712
|
+
const redo = useCallback(async () => {
|
|
2713
|
+
const h = historyRef.current;
|
|
2714
|
+
if (!h) return;
|
|
2715
|
+
await h.redo();
|
|
2716
|
+
setCanUndo(h.canUndo());
|
|
2717
|
+
setCanRedo(h.canRedo());
|
|
2718
|
+
}, []);
|
|
2719
|
+
const setBackground = useCallback(
|
|
2720
|
+
async (url, bgOpts) => {
|
|
2721
|
+
const canvas = canvasRef.current;
|
|
2722
|
+
if (!canvas) throw new Error("Canvas not ready");
|
|
2723
|
+
const opts = optionsRef.current;
|
|
2724
|
+
const resizeOpts = opts?.backgroundResize !== false ? typeof opts?.backgroundResize === "object" ? { ...opts.backgroundResize, ...bgOpts } : { ...bgOpts } : bgOpts?.preserveContrast ? { preserveContrast: true } : void 0;
|
|
2725
|
+
const img = await setBackgroundImage(canvas, url, resizeOpts);
|
|
2726
|
+
if (opts?.autoFitToBackground !== false) {
|
|
2727
|
+
fitViewportToBackground(canvas);
|
|
2728
|
+
syncZoom(canvasRef, setZoom);
|
|
2729
|
+
}
|
|
2730
|
+
return img;
|
|
2667
2731
|
},
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
2672
|
-
|
|
2673
|
-
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
|
|
2710
|
-
|
|
2711
|
-
|
|
2712
|
-
|
|
2713
|
-
|
|
2714
|
-
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
|
|
2721
|
-
|
|
2732
|
+
[]
|
|
2733
|
+
);
|
|
2734
|
+
return useMemo2(
|
|
2735
|
+
() => ({
|
|
2736
|
+
/** Pass this to `<Canvas onReady={...} />` */
|
|
2737
|
+
onReady,
|
|
2738
|
+
/** Ref to the underlying Fabric canvas instance. */
|
|
2739
|
+
canvasRef,
|
|
2740
|
+
/** Current zoom level (reactive). */
|
|
2741
|
+
zoom,
|
|
2742
|
+
/** Loaded objects (reactive). Populated when `canvasData` is provided. */
|
|
2743
|
+
objects,
|
|
2744
|
+
/** Whether canvas data is currently being loaded. */
|
|
2745
|
+
isLoading,
|
|
2746
|
+
/** Currently selected objects (reactive). */
|
|
2747
|
+
selected,
|
|
2748
|
+
/** Viewport controls. */
|
|
2749
|
+
viewport,
|
|
2750
|
+
/** Whether vertex edit mode is currently active (reactive). */
|
|
2751
|
+
isEditingVertices,
|
|
2752
|
+
/**
|
|
2753
|
+
* Activate an interaction mode or return to select mode.
|
|
2754
|
+
*
|
|
2755
|
+
* Pass a setup function to activate a creation mode:
|
|
2756
|
+
* ```ts
|
|
2757
|
+
* canvas.setMode((c, viewport) =>
|
|
2758
|
+
* enableClickToCreate(c, factory, { viewport })
|
|
2759
|
+
* );
|
|
2760
|
+
* ```
|
|
2761
|
+
*
|
|
2762
|
+
* Pass `null` to deactivate and return to select mode:
|
|
2763
|
+
* ```ts
|
|
2764
|
+
* canvas.setMode(null);
|
|
2765
|
+
* ```
|
|
2766
|
+
*/
|
|
2767
|
+
setMode,
|
|
2768
|
+
/**
|
|
2769
|
+
* Set a background image from a URL. Automatically resizes if the image
|
|
2770
|
+
* exceeds the configured limits (opt out via `backgroundResize: false`),
|
|
2771
|
+
* and fits the viewport after setting if `autoFitToBackground` is enabled.
|
|
2772
|
+
*
|
|
2773
|
+
* Pass `{ preserveContrast: true }` to keep the current background contrast
|
|
2774
|
+
* when replacing the image.
|
|
2775
|
+
*/
|
|
2776
|
+
setBackground,
|
|
2777
|
+
/** Whether the canvas has been modified since the last `resetDirty()` call. Enabled by default (disable via `trackChanges: false`). */
|
|
2778
|
+
isDirty,
|
|
2779
|
+
/** Reset the dirty flag (e.g., after a successful save). */
|
|
2780
|
+
resetDirty,
|
|
2781
|
+
/** Manually mark the canvas as dirty (e.g., after a custom operation not tracked automatically). */
|
|
2782
|
+
markDirty,
|
|
2783
|
+
/** Undo the last change. Requires `history: true`. */
|
|
2784
|
+
undo,
|
|
2785
|
+
/** Redo a previously undone change. Requires `history: true`. */
|
|
2786
|
+
redo,
|
|
2787
|
+
/** Whether an undo operation is available (reactive). Requires `history: true`. */
|
|
2788
|
+
canUndo,
|
|
2789
|
+
/** Whether a redo operation is available (reactive). Requires `history: true`. */
|
|
2790
|
+
canRedo,
|
|
2791
|
+
/** Whether the canvas is locked to light mode. Read from loaded canvas data. */
|
|
2792
|
+
lockLightMode,
|
|
2793
|
+
/** Update lockLightMode on both the canvas instance and React state. */
|
|
2794
|
+
setLockLightMode
|
|
2795
|
+
}),
|
|
2796
|
+
// Only reactive state in deps — refs and stable callbacks are omitted
|
|
2797
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2798
|
+
[
|
|
2799
|
+
zoom,
|
|
2800
|
+
objects,
|
|
2801
|
+
isLoading,
|
|
2802
|
+
selected,
|
|
2803
|
+
viewport,
|
|
2804
|
+
isEditingVertices,
|
|
2805
|
+
isDirty,
|
|
2806
|
+
canUndo,
|
|
2807
|
+
canRedo,
|
|
2808
|
+
lockLightMode
|
|
2809
|
+
]
|
|
2810
|
+
);
|
|
2722
2811
|
}
|
|
2723
2812
|
|
|
2724
2813
|
// src/hooks/useViewCanvas.ts
|
|
2725
|
-
import { useCallback as useCallback2, useRef as useRef3, useState as useState2 } from "react";
|
|
2814
|
+
import { useCallback as useCallback2, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef3, useState as useState2 } from "react";
|
|
2726
2815
|
function lockCanvas(canvas) {
|
|
2727
2816
|
canvas.selection = false;
|
|
2728
2817
|
canvas.forEachObject((obj) => {
|
|
@@ -2735,6 +2824,8 @@ function useViewCanvas(options) {
|
|
|
2735
2824
|
const optionsRef = useRef3(options);
|
|
2736
2825
|
optionsRef.current = options;
|
|
2737
2826
|
const [zoom, setZoom] = useState2(1);
|
|
2827
|
+
const [objects, setObjects] = useState2([]);
|
|
2828
|
+
const [isLoading, setIsLoading] = useState2(false);
|
|
2738
2829
|
const onReady = useCallback2(
|
|
2739
2830
|
(canvas) => {
|
|
2740
2831
|
canvasRef.current = canvas;
|
|
@@ -2761,20 +2852,57 @@ function useViewCanvas(options) {
|
|
|
2761
2852
|
canvas.on("mouse:wheel", () => {
|
|
2762
2853
|
setZoom(canvas.getZoom());
|
|
2763
2854
|
});
|
|
2764
|
-
const
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
|
|
2768
|
-
|
|
2769
|
-
|
|
2855
|
+
const initPromise = (async () => {
|
|
2856
|
+
if (opts?.canvasData) {
|
|
2857
|
+
setIsLoading(true);
|
|
2858
|
+
try {
|
|
2859
|
+
const loaded = await loadCanvas(canvas, opts.canvasData, {
|
|
2860
|
+
filter: opts.filter,
|
|
2861
|
+
borderRadius: opts.borderRadius
|
|
2862
|
+
});
|
|
2863
|
+
lockCanvas(canvas);
|
|
2864
|
+
setObjects(loaded);
|
|
2865
|
+
} finally {
|
|
2866
|
+
setIsLoading(false);
|
|
2770
2867
|
}
|
|
2771
|
-
}
|
|
2772
|
-
}
|
|
2868
|
+
}
|
|
2869
|
+
})();
|
|
2870
|
+
initPromise.then(async () => {
|
|
2871
|
+
const onReadyResult = opts?.onReady?.(canvas);
|
|
2872
|
+
await Promise.resolve(onReadyResult);
|
|
2873
|
+
if (opts?.invertBackground !== void 0) {
|
|
2874
|
+
setBackgroundInverted(canvas, opts.invertBackground);
|
|
2875
|
+
}
|
|
2876
|
+
if (opts?.autoFitToBackground !== false && canvas.backgroundImage) {
|
|
2877
|
+
fitViewportToBackground(canvas);
|
|
2878
|
+
syncZoom(canvasRef, setZoom);
|
|
2879
|
+
}
|
|
2880
|
+
});
|
|
2773
2881
|
},
|
|
2774
2882
|
// onReady and panAndZoom are intentionally excluded — we only initialize once
|
|
2775
2883
|
[]
|
|
2776
2884
|
);
|
|
2885
|
+
useEffect3(() => {
|
|
2886
|
+
const canvas = canvasRef.current;
|
|
2887
|
+
if (!canvas || options?.invertBackground === void 0) return;
|
|
2888
|
+
setBackgroundInverted(canvas, options.invertBackground);
|
|
2889
|
+
}, [options?.invertBackground]);
|
|
2777
2890
|
const { resetViewport: resetViewport2, zoomIn, zoomOut, panToObject, zoomToFit } = useViewportActions(canvasRef, viewportRef, setZoom);
|
|
2891
|
+
const viewport = useMemo3(
|
|
2892
|
+
() => ({
|
|
2893
|
+
/** Reset viewport to default (no pan, zoom = 1), or fit to background if one is set. */
|
|
2894
|
+
reset: resetViewport2,
|
|
2895
|
+
/** Zoom in toward the canvas center. Default step: 0.2. */
|
|
2896
|
+
zoomIn,
|
|
2897
|
+
/** Zoom out from the canvas center. Default step: 0.2. */
|
|
2898
|
+
zoomOut,
|
|
2899
|
+
/** Pan the viewport to center on a specific object. */
|
|
2900
|
+
panToObject,
|
|
2901
|
+
/** Zoom and pan to fit a specific object in the viewport. */
|
|
2902
|
+
zoomToFit
|
|
2903
|
+
}),
|
|
2904
|
+
[resetViewport2, zoomIn, zoomOut, panToObject, zoomToFit]
|
|
2905
|
+
);
|
|
2778
2906
|
const findObject = (id) => {
|
|
2779
2907
|
const c = canvasRef.current;
|
|
2780
2908
|
if (!c) return void 0;
|
|
@@ -2790,9 +2918,9 @@ function useViewCanvas(options) {
|
|
|
2790
2918
|
(styles) => {
|
|
2791
2919
|
const c = canvasRef.current;
|
|
2792
2920
|
if (!c) return;
|
|
2793
|
-
const
|
|
2921
|
+
const objects2 = c.getObjects();
|
|
2794
2922
|
const idMap = /* @__PURE__ */ new Map();
|
|
2795
|
-
for (const obj of
|
|
2923
|
+
for (const obj of objects2) {
|
|
2796
2924
|
if (obj.data?.id) idMap.set(obj.data.id, obj);
|
|
2797
2925
|
}
|
|
2798
2926
|
let updated = false;
|
|
@@ -2822,42 +2950,101 @@ function useViewCanvas(options) {
|
|
|
2822
2950
|
},
|
|
2823
2951
|
[]
|
|
2824
2952
|
);
|
|
2825
|
-
return
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2833
|
-
|
|
2834
|
-
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2953
|
+
return useMemo3(
|
|
2954
|
+
() => ({
|
|
2955
|
+
/** Pass this to `<Canvas onReady={...} />` */
|
|
2956
|
+
onReady,
|
|
2957
|
+
/** Ref to the underlying Fabric canvas instance. */
|
|
2958
|
+
canvasRef,
|
|
2959
|
+
/** Current zoom level (reactive). */
|
|
2960
|
+
zoom,
|
|
2961
|
+
/** Loaded objects (reactive). Populated when `canvasData` is provided. */
|
|
2962
|
+
objects,
|
|
2963
|
+
/** Whether canvas data is currently being loaded. */
|
|
2964
|
+
isLoading,
|
|
2965
|
+
/** Viewport controls. */
|
|
2966
|
+
viewport,
|
|
2967
|
+
/** Update a single object's visual style by its `data.id`. */
|
|
2968
|
+
setObjectStyle,
|
|
2969
|
+
/** Batch-update multiple objects' visual styles in one render. Keyed by `data.id`. */
|
|
2970
|
+
setObjectStyles,
|
|
2971
|
+
/** Apply a visual style to all objects whose `data.type` matches. */
|
|
2972
|
+
setObjectStyleByType
|
|
2973
|
+
}),
|
|
2974
|
+
// Only reactive state in deps — refs and stable callbacks are omitted
|
|
2975
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
2976
|
+
[zoom, objects, isLoading, viewport]
|
|
2977
|
+
);
|
|
2978
|
+
}
|
|
2979
|
+
|
|
2980
|
+
// src/hooks/useCanvasEvents.ts
|
|
2981
|
+
import { useEffect as useEffect4, useRef as useRef4 } from "react";
|
|
2982
|
+
|
|
2983
|
+
// src/context/ViewCanvasContext.tsx
|
|
2984
|
+
import { createContext, useContext } from "react";
|
|
2985
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
2986
|
+
var ViewCanvasContext = createContext(null);
|
|
2987
|
+
function ViewCanvasProvider({
|
|
2988
|
+
options,
|
|
2989
|
+
children
|
|
2990
|
+
}) {
|
|
2991
|
+
const canvas = useViewCanvas(options);
|
|
2992
|
+
return /* @__PURE__ */ jsx2(ViewCanvasContext.Provider, { value: canvas, children });
|
|
2993
|
+
}
|
|
2994
|
+
function useViewCanvasContext() {
|
|
2995
|
+
const ctx = useContext(ViewCanvasContext);
|
|
2996
|
+
if (ctx === null) {
|
|
2997
|
+
throw new Error(
|
|
2998
|
+
"useViewCanvasContext must be used within a <ViewCanvasProvider>"
|
|
2999
|
+
);
|
|
3000
|
+
}
|
|
3001
|
+
return ctx;
|
|
3002
|
+
}
|
|
3003
|
+
function useViewCanvasContextSafe() {
|
|
3004
|
+
return useContext(ViewCanvasContext);
|
|
3005
|
+
}
|
|
3006
|
+
|
|
3007
|
+
// src/context/EditCanvasContext.tsx
|
|
3008
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
3009
|
+
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
3010
|
+
var EditCanvasContext = createContext2(null);
|
|
3011
|
+
function EditCanvasProvider({
|
|
3012
|
+
options,
|
|
3013
|
+
children
|
|
3014
|
+
}) {
|
|
3015
|
+
const canvas = useEditCanvas(options);
|
|
3016
|
+
return /* @__PURE__ */ jsx3(EditCanvasContext.Provider, { value: canvas, children });
|
|
3017
|
+
}
|
|
3018
|
+
function useEditCanvasContext() {
|
|
3019
|
+
const ctx = useContext2(EditCanvasContext);
|
|
3020
|
+
if (ctx === null) {
|
|
3021
|
+
throw new Error(
|
|
3022
|
+
"useEditCanvasContext must be used within an <EditCanvasProvider>"
|
|
3023
|
+
);
|
|
3024
|
+
}
|
|
3025
|
+
return ctx;
|
|
3026
|
+
}
|
|
3027
|
+
function useEditCanvasContextSafe() {
|
|
3028
|
+
return useContext2(EditCanvasContext);
|
|
3029
|
+
}
|
|
3030
|
+
|
|
3031
|
+
// src/context/useCanvasRef.ts
|
|
3032
|
+
function useCanvasRef() {
|
|
3033
|
+
const viewCtx = useViewCanvasContextSafe();
|
|
3034
|
+
const editCtx = useEditCanvasContextSafe();
|
|
3035
|
+
return viewCtx?.canvasRef ?? editCtx?.canvasRef ?? null;
|
|
2852
3036
|
}
|
|
2853
3037
|
|
|
2854
3038
|
// src/hooks/useCanvasEvents.ts
|
|
2855
|
-
|
|
2856
|
-
|
|
3039
|
+
function useCanvasEvents(canvasRefOrEvents, maybeEvents) {
|
|
3040
|
+
const isContextOverload = maybeEvents === void 0;
|
|
3041
|
+
const contextCanvasRef = useCanvasRef();
|
|
3042
|
+
const resolvedCanvasRef = isContextOverload ? contextCanvasRef : canvasRefOrEvents;
|
|
3043
|
+
const events = isContextOverload ? canvasRefOrEvents : maybeEvents;
|
|
2857
3044
|
const eventsRef = useRef4(events);
|
|
2858
3045
|
eventsRef.current = events;
|
|
2859
|
-
|
|
2860
|
-
const canvas =
|
|
3046
|
+
useEffect4(() => {
|
|
3047
|
+
const canvas = resolvedCanvasRef?.current;
|
|
2861
3048
|
if (!canvas) return;
|
|
2862
3049
|
const wrappers = /* @__PURE__ */ new Map();
|
|
2863
3050
|
for (const key of Object.keys(eventsRef.current)) {
|
|
@@ -2873,12 +3060,16 @@ function useCanvasEvents(canvasRef, events) {
|
|
|
2873
3060
|
canvas.off(name, handler);
|
|
2874
3061
|
});
|
|
2875
3062
|
};
|
|
2876
|
-
}, [
|
|
3063
|
+
}, [resolvedCanvasRef]);
|
|
2877
3064
|
}
|
|
2878
3065
|
|
|
2879
3066
|
// src/hooks/useCanvasTooltip.ts
|
|
2880
|
-
import { useEffect as
|
|
2881
|
-
function useCanvasTooltip(
|
|
3067
|
+
import { useEffect as useEffect5, useRef as useRef5, useState as useState3 } from "react";
|
|
3068
|
+
function useCanvasTooltip(canvasRefOrOptions, maybeOptions) {
|
|
3069
|
+
const isContextOverload = maybeOptions === void 0;
|
|
3070
|
+
const contextCanvasRef = useCanvasRef();
|
|
3071
|
+
const resolvedCanvasRef = isContextOverload ? contextCanvasRef : canvasRefOrOptions;
|
|
3072
|
+
const options = isContextOverload ? canvasRefOrOptions : maybeOptions;
|
|
2882
3073
|
const [state, setState] = useState3({
|
|
2883
3074
|
visible: false,
|
|
2884
3075
|
content: null,
|
|
@@ -2887,8 +3078,8 @@ function useCanvasTooltip(canvasRef, options) {
|
|
|
2887
3078
|
const hoveredObjectRef = useRef5(null);
|
|
2888
3079
|
const optionsRef = useRef5(options);
|
|
2889
3080
|
optionsRef.current = options;
|
|
2890
|
-
|
|
2891
|
-
const canvas =
|
|
3081
|
+
useEffect5(() => {
|
|
3082
|
+
const canvas = resolvedCanvasRef?.current;
|
|
2892
3083
|
if (!canvas) return;
|
|
2893
3084
|
function calculatePosition(target) {
|
|
2894
3085
|
const bounds = target.getBoundingRect();
|
|
@@ -2936,19 +3127,24 @@ function useCanvasTooltip(canvasRef, options) {
|
|
|
2936
3127
|
canvas.off("after:render", updatePosition);
|
|
2937
3128
|
canvas.off("mouse:wheel", updatePosition);
|
|
2938
3129
|
};
|
|
2939
|
-
}, [
|
|
3130
|
+
}, [resolvedCanvasRef]);
|
|
2940
3131
|
return state;
|
|
2941
3132
|
}
|
|
2942
3133
|
|
|
2943
3134
|
// src/hooks/useCanvasClick.ts
|
|
2944
|
-
import { useEffect as
|
|
2945
|
-
function useCanvasClick(
|
|
3135
|
+
import { useEffect as useEffect6, useRef as useRef6 } from "react";
|
|
3136
|
+
function useCanvasClick(canvasRefOrOnClick, onClickOrOptions, maybeOptions) {
|
|
3137
|
+
const isContextOverload = typeof canvasRefOrOnClick === "function";
|
|
3138
|
+
const contextCanvasRef = useCanvasRef();
|
|
3139
|
+
const resolvedCanvasRef = isContextOverload ? contextCanvasRef : canvasRefOrOnClick;
|
|
3140
|
+
const onClick = isContextOverload ? canvasRefOrOnClick : onClickOrOptions;
|
|
3141
|
+
const options = isContextOverload ? onClickOrOptions : maybeOptions;
|
|
2946
3142
|
const onClickRef = useRef6(onClick);
|
|
2947
3143
|
onClickRef.current = onClick;
|
|
2948
3144
|
const optionsRef = useRef6(options);
|
|
2949
3145
|
optionsRef.current = options;
|
|
2950
|
-
|
|
2951
|
-
const canvas =
|
|
3146
|
+
useEffect6(() => {
|
|
3147
|
+
const canvas = resolvedCanvasRef?.current;
|
|
2952
3148
|
if (!canvas) return;
|
|
2953
3149
|
let mouseDown = null;
|
|
2954
3150
|
let isPanning = false;
|
|
@@ -2988,24 +3184,26 @@ function useCanvasClick(canvasRef, onClick, options) {
|
|
|
2988
3184
|
canvas.off("mouse:move", handleMouseMove);
|
|
2989
3185
|
canvas.off("mouse:up", handleMouseUp);
|
|
2990
3186
|
};
|
|
2991
|
-
}, [
|
|
3187
|
+
}, [resolvedCanvasRef]);
|
|
2992
3188
|
}
|
|
2993
3189
|
|
|
2994
3190
|
// src/overlay/ObjectOverlay.tsx
|
|
2995
|
-
import { useEffect as
|
|
3191
|
+
import { useEffect as useEffect7, useRef as useRef7 } from "react";
|
|
2996
3192
|
import { Stack } from "@mui/material";
|
|
2997
3193
|
import { util as util4 } from "fabric";
|
|
2998
|
-
import { jsx as
|
|
3194
|
+
import { jsx as jsx4 } from "react/jsx-runtime";
|
|
2999
3195
|
function ObjectOverlay({
|
|
3000
|
-
canvasRef,
|
|
3196
|
+
canvasRef: canvasRefProp,
|
|
3001
3197
|
object,
|
|
3002
3198
|
sx,
|
|
3003
3199
|
children,
|
|
3004
3200
|
...rest
|
|
3005
3201
|
}) {
|
|
3202
|
+
const contextCanvasRef = useCanvasRef();
|
|
3203
|
+
const canvasRef = canvasRefProp ?? contextCanvasRef;
|
|
3006
3204
|
const stackRef = useRef7(null);
|
|
3007
|
-
|
|
3008
|
-
const canvas = canvasRef
|
|
3205
|
+
useEffect7(() => {
|
|
3206
|
+
const canvas = canvasRef?.current;
|
|
3009
3207
|
if (!canvas || !object) return;
|
|
3010
3208
|
function update() {
|
|
3011
3209
|
const el = stackRef.current;
|
|
@@ -3039,7 +3237,7 @@ function ObjectOverlay({
|
|
|
3039
3237
|
};
|
|
3040
3238
|
}, [canvasRef, object]);
|
|
3041
3239
|
if (!object) return null;
|
|
3042
|
-
return /* @__PURE__ */
|
|
3240
|
+
return /* @__PURE__ */ jsx4(
|
|
3043
3241
|
Stack,
|
|
3044
3242
|
{
|
|
3045
3243
|
ref: stackRef,
|
|
@@ -3059,8 +3257,8 @@ function ObjectOverlay({
|
|
|
3059
3257
|
|
|
3060
3258
|
// src/overlay/OverlayContent.tsx
|
|
3061
3259
|
import { Stack as Stack2 } from "@mui/material";
|
|
3062
|
-
import { useEffect as
|
|
3063
|
-
import { jsx as
|
|
3260
|
+
import { useEffect as useEffect8, useRef as useRef8 } from "react";
|
|
3261
|
+
import { jsx as jsx5 } from "react/jsx-runtime";
|
|
3064
3262
|
function OverlayContent({
|
|
3065
3263
|
children,
|
|
3066
3264
|
padding = 4,
|
|
@@ -3070,7 +3268,7 @@ function OverlayContent({
|
|
|
3070
3268
|
}) {
|
|
3071
3269
|
const outerRef = useRef8(null);
|
|
3072
3270
|
const innerRef = useRef8(null);
|
|
3073
|
-
|
|
3271
|
+
useEffect8(() => {
|
|
3074
3272
|
const outer = outerRef.current;
|
|
3075
3273
|
const inner = innerRef.current;
|
|
3076
3274
|
if (!outer || !inner) return;
|
|
@@ -3099,7 +3297,7 @@ function OverlayContent({
|
|
|
3099
3297
|
fit();
|
|
3100
3298
|
return () => observer.disconnect();
|
|
3101
3299
|
}, [padding, maxScale]);
|
|
3102
|
-
return /* @__PURE__ */
|
|
3300
|
+
return /* @__PURE__ */ jsx5(
|
|
3103
3301
|
Stack2,
|
|
3104
3302
|
{
|
|
3105
3303
|
ref: outerRef,
|
|
@@ -3112,7 +3310,7 @@ function OverlayContent({
|
|
|
3112
3310
|
...sx
|
|
3113
3311
|
},
|
|
3114
3312
|
...rest,
|
|
3115
|
-
children: /* @__PURE__ */
|
|
3313
|
+
children: /* @__PURE__ */ jsx5(
|
|
3116
3314
|
Stack2,
|
|
3117
3315
|
{
|
|
3118
3316
|
ref: innerRef,
|
|
@@ -3131,8 +3329,8 @@ function OverlayContent({
|
|
|
3131
3329
|
|
|
3132
3330
|
// src/overlay/FixedSizeContent.tsx
|
|
3133
3331
|
import { Stack as Stack3 } from "@mui/material";
|
|
3134
|
-
import { useEffect as
|
|
3135
|
-
import { jsx as
|
|
3332
|
+
import { useEffect as useEffect9, useRef as useRef9 } from "react";
|
|
3333
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
3136
3334
|
function FixedSizeContent({
|
|
3137
3335
|
children,
|
|
3138
3336
|
hideOnOverflow = true,
|
|
@@ -3142,7 +3340,7 @@ function FixedSizeContent({
|
|
|
3142
3340
|
}) {
|
|
3143
3341
|
const ref = useRef9(null);
|
|
3144
3342
|
const totalContentHeightRef = useRef9(0);
|
|
3145
|
-
|
|
3343
|
+
useEffect9(() => {
|
|
3146
3344
|
const el = ref.current;
|
|
3147
3345
|
if (!el) return;
|
|
3148
3346
|
let clipAncestor = el.parentElement;
|
|
@@ -3179,7 +3377,7 @@ function FixedSizeContent({
|
|
|
3179
3377
|
check();
|
|
3180
3378
|
return () => observer.disconnect();
|
|
3181
3379
|
}, [hideOnOverflow, truncationPadding]);
|
|
3182
|
-
return /* @__PURE__ */
|
|
3380
|
+
return /* @__PURE__ */ jsx6(
|
|
3183
3381
|
Stack3,
|
|
3184
3382
|
{
|
|
3185
3383
|
ref,
|
|
@@ -3205,8 +3403,8 @@ function FixedSizeContent({
|
|
|
3205
3403
|
|
|
3206
3404
|
// src/overlay/OverlayBadge.tsx
|
|
3207
3405
|
import { Stack as Stack4 } from "@mui/material";
|
|
3208
|
-
import { useEffect as
|
|
3209
|
-
import { jsx as
|
|
3406
|
+
import { useEffect as useEffect10, useRef as useRef10 } from "react";
|
|
3407
|
+
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
3210
3408
|
function toPx(v) {
|
|
3211
3409
|
if (v === void 0) return void 0;
|
|
3212
3410
|
return typeof v === "number" ? `${v}px` : v;
|
|
@@ -3250,7 +3448,7 @@ function OverlayBadge({
|
|
|
3250
3448
|
}) {
|
|
3251
3449
|
const ref = useRef10(null);
|
|
3252
3450
|
const baseSize = useRef10(null);
|
|
3253
|
-
|
|
3451
|
+
useEffect10(() => {
|
|
3254
3452
|
const el = ref.current;
|
|
3255
3453
|
if (!el) return;
|
|
3256
3454
|
const ancestor = el.parentElement;
|
|
@@ -3302,7 +3500,7 @@ function OverlayBadge({
|
|
|
3302
3500
|
bottom: toPx(bottom),
|
|
3303
3501
|
left: toPx(left)
|
|
3304
3502
|
};
|
|
3305
|
-
return /* @__PURE__ */
|
|
3503
|
+
return /* @__PURE__ */ jsx7(
|
|
3306
3504
|
Stack4,
|
|
3307
3505
|
{
|
|
3308
3506
|
ref,
|
|
@@ -3340,6 +3538,7 @@ export {
|
|
|
3340
3538
|
DEFAULT_DRAG_SHAPE_STYLE,
|
|
3341
3539
|
DEFAULT_GUIDELINE_SHAPE_STYLE,
|
|
3342
3540
|
DEFAULT_SHAPE_STYLE,
|
|
3541
|
+
EditCanvasProvider,
|
|
3343
3542
|
Canvas2 as FabricCanvas,
|
|
3344
3543
|
FabricImage3 as FabricImage,
|
|
3345
3544
|
FabricObject5 as FabricObject,
|
|
@@ -3350,6 +3549,7 @@ export {
|
|
|
3350
3549
|
Point9 as Point,
|
|
3351
3550
|
Polygon5 as Polygon,
|
|
3352
3551
|
Rect6 as Rect,
|
|
3552
|
+
ViewCanvasProvider,
|
|
3353
3553
|
createCircle,
|
|
3354
3554
|
createCircleAtPoint,
|
|
3355
3555
|
createHistoryTracker,
|
|
@@ -3390,9 +3590,12 @@ export {
|
|
|
3390
3590
|
snapCursorPoint,
|
|
3391
3591
|
useCanvasClick,
|
|
3392
3592
|
useCanvasEvents,
|
|
3593
|
+
useCanvasRef,
|
|
3393
3594
|
useCanvasTooltip,
|
|
3394
3595
|
useEditCanvas,
|
|
3596
|
+
useEditCanvasContext,
|
|
3395
3597
|
useViewCanvas,
|
|
3598
|
+
useViewCanvasContext,
|
|
3396
3599
|
util5 as util
|
|
3397
3600
|
};
|
|
3398
3601
|
//# sourceMappingURL=index.js.map
|