@mhamz.01/easyflow-whiteboard 2.47.0 → 2.48.0
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.
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useCanvasInit.d.ts","sourceRoot":"","sources":["../../src/hooks/useCanvasInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAK,MAAM,CAAC;IACnB,KAAK,CAAC,EAAM,GAAG,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;CACnB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAW,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACxD,eAAe,EAAK,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,UAAU,EAAU,MAAM,CAAC;IAC3B,kBAAkB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,cAAc,EAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,WAAW,EAAS,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,EAAY,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC3C,YAAY,EAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"useCanvasInit.d.ts","sourceRoot":"","sources":["../../src/hooks/useCanvasInit.ts"],"names":[],"mappings":"AAAA,OAAO,EAAa,SAAS,EAAE,MAAM,OAAO,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAKhC,MAAM,WAAW,qBAAqB;IACpC,MAAM,CAAC,EAAK,MAAM,CAAC;IACnB,KAAK,CAAC,EAAM,GAAG,EAAE,CAAC;IAClB,SAAS,CAAC,EAAE,GAAG,EAAE,CAAC;CACnB;AAED,UAAU,kBAAkB;IAC1B,SAAS,EAAW,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IACxD,eAAe,EAAK,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,UAAU,EAAU,MAAM,CAAC;IAC3B,kBAAkB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,cAAc,EAAM,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,WAAW,EAAS,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5C,QAAQ,EAAY,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC3C,YAAY,EAAQ,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IAC1C,WAAW,CAAC,EAAQ,qBAAqB,CAAC;CAC3C;AAID,eAAO,MAAM,aAAa,GAAI,mIAU3B,kBAAkB,SAuHpB,CAAC"}
|
|
@@ -4,7 +4,6 @@ import { initializeFabricCanvas, addWelcomeContent } from "../lib/fabric-utils";
|
|
|
4
4
|
// ─── Hook ─────────────────────────────────────────────────────────────────────
|
|
5
5
|
export const useCanvasInit = ({ canvasRef, fabricCanvasRef, activeTool, suppressHistoryRef, isRestoringRef, pushHistory, setTasks, setDocuments, initialData, }) => {
|
|
6
6
|
useEffect(() => {
|
|
7
|
-
// Guard: prevent re-initialization if canvas already exists
|
|
8
7
|
if (!canvasRef.current || fabricCanvasRef.current)
|
|
9
8
|
return;
|
|
10
9
|
const canvas = new Canvas(canvasRef.current, {
|
|
@@ -20,31 +19,44 @@ export const useCanvasInit = ({ canvasRef, fabricCanvasRef, activeTool, suppress
|
|
|
20
19
|
initializeFabricCanvas(canvas);
|
|
21
20
|
const canvasElement = canvas.getElement();
|
|
22
21
|
canvasElement.style.touchAction = "none";
|
|
23
|
-
//
|
|
24
|
-
//
|
|
25
|
-
|
|
22
|
+
// Tracks whether cleanup has run — prevents hydrateCanvas from
|
|
23
|
+
// running after canvas.dispose() if rAFs fire post-unmount
|
|
24
|
+
let disposed = false;
|
|
25
|
+
let raf1;
|
|
26
|
+
let raf2;
|
|
26
27
|
const hydrateCanvas = async () => {
|
|
28
|
+
// Guard 1: unmounted before rAF fired — canvas already disposed
|
|
29
|
+
if (disposed)
|
|
30
|
+
return;
|
|
31
|
+
// Guard 2: check Fabric's internal ctx directly.
|
|
32
|
+
// canvas.getContext() is NOT a valid Fabric v6 API — always undefined.
|
|
33
|
+
// contextContainer is the actual 2D ctx Fabric uses internally.
|
|
34
|
+
// If undefined, Fabric hasn't finished attaching to the DOM yet.
|
|
35
|
+
const fabricCtx = canvas.contextContainer;
|
|
36
|
+
if (!fabricCtx) {
|
|
37
|
+
console.warn("[useCanvasInit] Fabric ctx not ready, skipping hydration");
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
27
40
|
const hasCanvas = !!initialData?.canvas;
|
|
28
41
|
const hasNodes = !!(initialData?.tasks || initialData?.documents);
|
|
29
42
|
if (hasCanvas || hasNodes) {
|
|
30
43
|
isRestoringRef.current = true;
|
|
31
44
|
if (hasCanvas) {
|
|
32
45
|
try {
|
|
33
|
-
// Guard: ensure the canvas context is available before loading
|
|
34
|
-
if (!canvas.getContext()) {
|
|
35
|
-
console.warn("[useCanvasInit] Canvas context not ready, skipping load");
|
|
36
|
-
return;
|
|
37
|
-
}
|
|
38
46
|
await canvas.loadFromJSON(JSON.parse(initialData.canvas));
|
|
47
|
+
if (disposed)
|
|
48
|
+
return; // re-check after async gap — dispose may have run during await
|
|
39
49
|
canvas.renderAll();
|
|
40
50
|
pushHistory(JSON.stringify(canvas.toJSON()));
|
|
41
51
|
}
|
|
42
52
|
catch (err) {
|
|
43
53
|
console.error("[useCanvasInit] Canvas load failed:", err);
|
|
44
|
-
|
|
54
|
+
if (!disposed) {
|
|
55
|
+
addWelcomeContent(canvas, "https://res.cloudinary.com/dqyjffc9q/image/upload/v1773420161/easyflow-logo_nbpfd7.png");
|
|
56
|
+
}
|
|
45
57
|
}
|
|
46
58
|
}
|
|
47
|
-
if (hasNodes) {
|
|
59
|
+
if (hasNodes && !disposed) {
|
|
48
60
|
try {
|
|
49
61
|
if (initialData?.tasks)
|
|
50
62
|
setTasks(initialData.tasks);
|
|
@@ -58,13 +70,17 @@ export const useCanvasInit = ({ canvasRef, fabricCanvasRef, activeTool, suppress
|
|
|
58
70
|
isRestoringRef.current = false;
|
|
59
71
|
}
|
|
60
72
|
else {
|
|
61
|
-
|
|
62
|
-
|
|
73
|
+
if (!disposed) {
|
|
74
|
+
addWelcomeContent(canvas, "https://res.cloudinary.com/dqyjffc9q/image/upload/v1773420161/easyflow-logo_nbpfd7.png");
|
|
75
|
+
pushHistory(JSON.stringify(canvas.toJSON()));
|
|
76
|
+
}
|
|
63
77
|
}
|
|
64
78
|
};
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
-
|
|
79
|
+
// Double rAF ensures Fabric's internal ctx is fully attached:
|
|
80
|
+
// - raf1: fires when browser is about to paint (Fabric constructor done)
|
|
81
|
+
// - raf2: fires after first paint (contextContainer guaranteed attached)
|
|
82
|
+
raf1 = requestAnimationFrame(() => {
|
|
83
|
+
raf2 = requestAnimationFrame(() => {
|
|
68
84
|
hydrateCanvas();
|
|
69
85
|
});
|
|
70
86
|
});
|
|
@@ -83,11 +99,17 @@ export const useCanvasInit = ({ canvasRef, fabricCanvasRef, activeTool, suppress
|
|
|
83
99
|
canvasElement.addEventListener("touchmove", preventDefaults, { passive: false });
|
|
84
100
|
// ── Cleanup ───────────────────────────────────────────────────────────────
|
|
85
101
|
return () => {
|
|
102
|
+
// Set disposed FIRST and cancel rAFs BEFORE canvas.dispose().
|
|
103
|
+
// This ensures hydrateCanvas cannot run on an already-disposed canvas
|
|
104
|
+
// which is what causes the ctx/clearRect errors.
|
|
105
|
+
disposed = true;
|
|
106
|
+
cancelAnimationFrame(raf1);
|
|
107
|
+
cancelAnimationFrame(raf2);
|
|
86
108
|
window.removeEventListener("resize", handleResize);
|
|
87
109
|
canvasElement.removeEventListener("touchstart", preventDefaults);
|
|
88
110
|
canvasElement.removeEventListener("touchmove", preventDefaults);
|
|
89
111
|
canvas.dispose();
|
|
90
112
|
fabricCanvasRef.current = null;
|
|
91
113
|
};
|
|
92
|
-
}, []);
|
|
114
|
+
}, []);
|
|
93
115
|
};
|