@mhamz.01/easyflow-whiteboard 1.28.0 → 2.0.1
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/components/node/custom-node-overlay-layer.d.ts.map +1 -1
- package/dist/components/node/custom-node-overlay-layer.js +31 -33
- package/dist/components/whiteboard/whiteboard-test.d.ts +1 -0
- package/dist/components/whiteboard/whiteboard-test.d.ts.map +1 -1
- package/dist/components/whiteboard/whiteboard-test.js +207 -274
- package/dist/components/whiteboard/whiteboard.d.ts +0 -1
- package/dist/components/whiteboard/whiteboard.d.ts.map +1 -1
- package/dist/components/whiteboard/whiteboard.js +913 -951
- package/dist/hooks/useSelection.d.ts.map +1 -1
- package/dist/hooks/useSelection.js +53 -35
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,EAAe,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,EAAe,MAAM,QAAQ,CAAC;AAMjE,UAAU,iBAAiB;IACzB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,eAAe,EAAE,CAAC,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1F,wBAAwB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,eAAO,MAAM,YAAY,GAAI,oHAQ1B,iBAAiB,SAgLnB,CAAC"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// hooks/useSelection.ts
|
|
2
|
-
import { useEffect } from "react";
|
|
2
|
+
import { useEffect, useRef } from "react";
|
|
3
3
|
import { Rect, FabricImage } from "fabric";
|
|
4
4
|
import { Frame } from "../lib/fabric-frame";
|
|
5
5
|
import { Arrow } from "../lib/fabric-arrow";
|
|
@@ -8,6 +8,15 @@ import { useWhiteboardStore } from "../store/whiteboard-store";
|
|
|
8
8
|
export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, }) => {
|
|
9
9
|
const setSelectedObjectType = useWhiteboardStore((state) => state.setSelectedObjectType);
|
|
10
10
|
const setActiveTool = useWhiteboardStore((state) => state.setActiveTool);
|
|
11
|
+
// ── KEY FIX 1: Store zoom/viewport in refs so the effect never re-registers ──
|
|
12
|
+
// This prevents listener teardown/re-attach during pan/zoom gestures
|
|
13
|
+
const zoomRef = useRef(canvasZoom);
|
|
14
|
+
const viewportRef = useRef(canvasViewport);
|
|
15
|
+
const activeToolRef = useRef(activeTool);
|
|
16
|
+
// Keep refs in sync with latest props on every render
|
|
17
|
+
useEffect(() => { zoomRef.current = canvasZoom; }, [canvasZoom]);
|
|
18
|
+
useEffect(() => { viewportRef.current = canvasViewport; }, [canvasViewport]);
|
|
19
|
+
useEffect(() => { activeToolRef.current = activeTool; }, [activeTool]);
|
|
11
20
|
useEffect(() => {
|
|
12
21
|
const canvas = fabricCanvas.current;
|
|
13
22
|
if (!canvas)
|
|
@@ -17,9 +26,11 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
17
26
|
let selRect = null;
|
|
18
27
|
let rafId = null;
|
|
19
28
|
const onDown = (e) => {
|
|
20
|
-
|
|
29
|
+
// ── KEY FIX 2: Use ref instead of closure-captured activeTool ──
|
|
30
|
+
if (activeToolRef.current !== "select" || e.target)
|
|
21
31
|
return;
|
|
22
32
|
isSelecting = true;
|
|
33
|
+
// getScenePoint returns world coordinates (zoom + pan already factored in by Fabric)
|
|
23
34
|
const p = canvas.getScenePoint(e.e);
|
|
24
35
|
selStart = { x: p.x, y: p.y };
|
|
25
36
|
selRect = new Rect({
|
|
@@ -27,17 +38,18 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
27
38
|
top: p.y,
|
|
28
39
|
width: 0,
|
|
29
40
|
height: 0,
|
|
30
|
-
fill: "
|
|
31
|
-
stroke: "
|
|
32
|
-
strokeWidth:
|
|
41
|
+
fill: "rgba(2, 154, 255, 0.08)",
|
|
42
|
+
stroke: "#029AFF",
|
|
43
|
+
strokeWidth: 1 / zoomRef.current, // stays 1px visually at any zoom
|
|
33
44
|
selectable: false,
|
|
34
45
|
evented: false,
|
|
35
|
-
|
|
46
|
+
// ── KEY FIX 3: Make it visible so user sees the selection rect ──
|
|
47
|
+
// was `visible: false` before — invisible but still blocking
|
|
48
|
+
excludeFromExport: true,
|
|
36
49
|
});
|
|
37
50
|
canvas.add(selRect);
|
|
38
51
|
canvas.renderAll();
|
|
39
52
|
};
|
|
40
|
-
// hooks/useSelection.ts - UPDATED
|
|
41
53
|
const onMove = (e) => {
|
|
42
54
|
if (!isSelecting || !selRect)
|
|
43
55
|
return;
|
|
@@ -47,34 +59,46 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
47
59
|
const p = canvas.getScenePoint(e.e);
|
|
48
60
|
const w = p.x - selStart.x;
|
|
49
61
|
const h = p.y - selStart.y;
|
|
50
|
-
const x1 = Math.min(selStart.x, p.x);
|
|
51
|
-
const y1 = Math.min(selStart.y, p.y);
|
|
52
|
-
const x2 = Math.max(selStart.x, p.x);
|
|
53
|
-
const y2 = Math.max(selStart.y, p.y);
|
|
54
62
|
selRect.set({
|
|
55
|
-
left:
|
|
56
|
-
top:
|
|
57
|
-
width:
|
|
58
|
-
height:
|
|
63
|
+
left: w < 0 ? p.x : selStart.x,
|
|
64
|
+
top: h < 0 ? p.y : selStart.y,
|
|
65
|
+
width: Math.abs(w),
|
|
66
|
+
height: Math.abs(h),
|
|
67
|
+
strokeWidth: 1 / zoomRef.current, // keep stroke sharp at any zoom
|
|
59
68
|
});
|
|
60
69
|
selRect.setCoords();
|
|
61
70
|
canvas.renderAll();
|
|
62
|
-
//
|
|
63
|
-
|
|
71
|
+
// ── KEY FIX 4: Read from refs — always fresh, no stale closure ──
|
|
72
|
+
const zoom = zoomRef.current;
|
|
73
|
+
const vp = viewportRef.current;
|
|
74
|
+
// World → Screen conversion:
|
|
75
|
+
// screenX = worldX * zoom + panX (matches exactly how nodes are rendered)
|
|
76
|
+
setSelectionBox({
|
|
77
|
+
x1: Math.min(selStart.x, p.x) * zoom + vp.x,
|
|
78
|
+
y1: Math.min(selStart.y, p.y) * zoom + vp.y,
|
|
79
|
+
x2: Math.max(selStart.x, p.x) * zoom + vp.x,
|
|
80
|
+
y2: Math.max(selStart.y, p.y) * zoom + vp.y,
|
|
81
|
+
});
|
|
64
82
|
});
|
|
65
83
|
};
|
|
66
84
|
const onUp = () => {
|
|
67
|
-
if (!isSelecting
|
|
85
|
+
if (!isSelecting)
|
|
68
86
|
return;
|
|
69
87
|
if (rafId !== null) {
|
|
70
88
|
cancelAnimationFrame(rafId);
|
|
71
89
|
rafId = null;
|
|
72
90
|
}
|
|
73
|
-
|
|
74
|
-
|
|
91
|
+
if (selRect) {
|
|
92
|
+
canvas.remove(selRect);
|
|
93
|
+
canvas.renderAll();
|
|
94
|
+
selRect = null;
|
|
95
|
+
}
|
|
75
96
|
isSelecting = false;
|
|
76
|
-
|
|
77
|
-
|
|
97
|
+
// ── KEY FIX 5: Delay clear long enough for overlay useEffect to fire ──
|
|
98
|
+
// onDeselected (selection:cleared) was calling setSelectionBox(null) immediately,
|
|
99
|
+
// racing with the overlay's useEffect. 150ms ensures the React render cycle
|
|
100
|
+
// processes the final box position before it's cleared.
|
|
101
|
+
setTimeout(() => setSelectionBox(null), 150);
|
|
78
102
|
};
|
|
79
103
|
const onSelected = () => {
|
|
80
104
|
const sel = canvas.getActiveObject();
|
|
@@ -105,9 +129,11 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
105
129
|
};
|
|
106
130
|
const onDeselected = () => {
|
|
107
131
|
setSelectedObjectType(null);
|
|
108
|
-
|
|
132
|
+
// ── KEY FIX 6: Do NOT clear selectionBox here ──
|
|
133
|
+
// This was racing with onUp's setTimeout and clearing before overlay processed it.
|
|
134
|
+
// onUp owns the selectionBox lifecycle. Only clear canvas objects here.
|
|
109
135
|
setSelectedCanvasObjects([]);
|
|
110
|
-
if (!isDrawingRef.current &&
|
|
136
|
+
if (!isDrawingRef.current && activeToolRef.current !== "select" && activeToolRef.current !== "pan") {
|
|
111
137
|
setActiveTool("select");
|
|
112
138
|
}
|
|
113
139
|
};
|
|
@@ -129,15 +155,7 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
129
155
|
if (selRect)
|
|
130
156
|
canvas.remove(selRect);
|
|
131
157
|
};
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
canvasViewport,
|
|
136
|
-
fabricCanvas,
|
|
137
|
-
setSelectionBox,
|
|
138
|
-
setSelectedCanvasObjects,
|
|
139
|
-
setSelectedObjectType,
|
|
140
|
-
setActiveTool,
|
|
141
|
-
isDrawingRef
|
|
142
|
-
]);
|
|
158
|
+
// ── KEY FIX 7: Remove canvasZoom/canvasViewport/activeTool from deps ──
|
|
159
|
+
// They are now read via refs — effect only registers once per canvas mount.
|
|
160
|
+
}, [fabricCanvas, setSelectionBox, setSelectedCanvasObjects, setSelectedObjectType, setActiveTool, isDrawingRef]);
|
|
143
161
|
};
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { default as EasyflowWhiteboard } from "./components/whiteboard/whiteboard";
|
|
1
|
+
export { default as EasyflowWhiteboard } from "./components/whiteboard/whiteboard-test";
|
|
2
2
|
export { useWhiteboardStore } from './store/whiteboard-store';
|
|
3
3
|
export type { TaskNodeData, DocumentNodeData } from './types/canvas-node';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAkCA,OAAO,EAAE,OAAO,IAAI,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AACxF,OAAO,EAAE,kBAAkB,EAAE,MAAM,0BAA0B,CAAC;AAE9D,YAAY,EAAE,YAAY,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC"}
|
package/dist/index.js
CHANGED
|
@@ -26,5 +26,5 @@
|
|
|
26
26
|
// export * from "./components/toolbar/document-dropdown";
|
|
27
27
|
// export * from "./components/toolbar/task-dropdown";
|
|
28
28
|
// export * from "./components/toolbar/document-dropdown";
|
|
29
|
-
export { default as EasyflowWhiteboard } from "./components/whiteboard/whiteboard";
|
|
29
|
+
export { default as EasyflowWhiteboard } from "./components/whiteboard/whiteboard-test";
|
|
30
30
|
export { useWhiteboardStore } from './store/whiteboard-store';
|