@mhamz.01/easyflow-whiteboard 1.16.0 → 1.17.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":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,
|
|
1
|
+
{"version":3,"file":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,EAA8B,MAAM,QAAQ,CAAC;AAMhF,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,SAsLnB,CAAC"}
|
|
@@ -17,7 +17,13 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
17
17
|
let selRect = null;
|
|
18
18
|
let rafId = null;
|
|
19
19
|
const onDown = (e) => {
|
|
20
|
-
|
|
20
|
+
// 1. Handle Selection Clearing
|
|
21
|
+
if (!e.target) {
|
|
22
|
+
setSelectedCanvasObjects([]);
|
|
23
|
+
setSelectedObjectType(null);
|
|
24
|
+
}
|
|
25
|
+
// 2. Marquee Selection Logic
|
|
26
|
+
if (activeTool !== "select" || e.target || isDrawingRef.current)
|
|
21
27
|
return;
|
|
22
28
|
isSelecting = true;
|
|
23
29
|
const p = canvas.getScenePoint(e.e);
|
|
@@ -27,12 +33,12 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
27
33
|
top: p.y,
|
|
28
34
|
width: 0,
|
|
29
35
|
height: 0,
|
|
30
|
-
fill: "
|
|
31
|
-
stroke: "
|
|
32
|
-
strokeWidth:
|
|
36
|
+
fill: "rgba(0, 120, 255, 0.1)", // Slight tint helps debugging
|
|
37
|
+
stroke: "rgba(0, 120, 255, 0.5)",
|
|
38
|
+
strokeWidth: 1,
|
|
33
39
|
selectable: false,
|
|
34
40
|
evented: false,
|
|
35
|
-
visible: false,
|
|
41
|
+
visible: false, // Keep invisible, we use the React Overlay for UI
|
|
36
42
|
});
|
|
37
43
|
canvas.add(selRect);
|
|
38
44
|
canvas.renderAll();
|
|
@@ -46,19 +52,21 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
46
52
|
const p = canvas.getScenePoint(e.e);
|
|
47
53
|
const w = p.x - selStart.x;
|
|
48
54
|
const h = p.y - selStart.y;
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
});
|
|
55
|
+
const x1 = w < 0 ? p.x : selStart.x;
|
|
56
|
+
const y1 = h < 0 ? p.y : selStart.y;
|
|
57
|
+
const width = Math.abs(w);
|
|
58
|
+
const height = Math.abs(h);
|
|
59
|
+
selRect.set({ left: x1, top: y1, width, height });
|
|
55
60
|
selRect.setCoords();
|
|
56
61
|
canvas.renderAll();
|
|
62
|
+
// CRITICAL: Get the physical position of the canvas on the screen
|
|
63
|
+
// This prevents the "abrupt jump" when the library is inside a layout with margins/sidebars.
|
|
64
|
+
const rect = canvas.getElement().getBoundingClientRect();
|
|
57
65
|
setSelectionBox({
|
|
58
|
-
x1:
|
|
59
|
-
y1:
|
|
60
|
-
x2:
|
|
61
|
-
y2:
|
|
66
|
+
x1: x1 * canvasZoom + canvasViewport.x + rect.left,
|
|
67
|
+
y1: y1 * canvasZoom + canvasViewport.y + rect.top,
|
|
68
|
+
x2: (x1 + width) * canvasZoom + canvasViewport.x + rect.left,
|
|
69
|
+
y2: (y1 + height) * canvasZoom + canvasViewport.y + rect.top,
|
|
62
70
|
});
|
|
63
71
|
});
|
|
64
72
|
};
|
|
@@ -73,35 +81,54 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
73
81
|
canvas.renderAll();
|
|
74
82
|
isSelecting = false;
|
|
75
83
|
selRect = null;
|
|
76
|
-
|
|
84
|
+
// Delay clearing the box slightly to allow intersection logic to finish
|
|
85
|
+
setTimeout(() => setSelectionBox(null), 50);
|
|
77
86
|
};
|
|
78
87
|
const onSelected = () => {
|
|
79
88
|
const sel = canvas.getActiveObject();
|
|
80
89
|
if (!sel || isDrawingRef.current)
|
|
81
90
|
return;
|
|
82
|
-
|
|
91
|
+
const objects = sel.type === "activeSelection"
|
|
92
|
+
? sel.getObjects()
|
|
93
|
+
: [sel];
|
|
94
|
+
// Track previous positions to prevent jumping during drag
|
|
95
|
+
objects.forEach((obj) => {
|
|
96
|
+
obj._prevLeft = obj.left;
|
|
97
|
+
obj._prevTop = obj.top;
|
|
98
|
+
});
|
|
99
|
+
setSelectedCanvasObjects(objects);
|
|
83
100
|
const typeMap = {
|
|
84
101
|
rect: "rectangle",
|
|
85
102
|
circle: "circle",
|
|
86
103
|
line: "line",
|
|
87
|
-
arrow: "arrow",
|
|
88
|
-
"bidirectional-arrow": "arrow",
|
|
89
104
|
"i-text": "text",
|
|
90
105
|
text: "text",
|
|
91
106
|
path: "pen",
|
|
92
107
|
image: "image",
|
|
93
108
|
};
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
109
|
+
let t = null;
|
|
110
|
+
if (sel instanceof Frame)
|
|
111
|
+
t = "frame";
|
|
112
|
+
else if (sel instanceof Arrow || sel instanceof BidirectionalArrow)
|
|
113
|
+
t = "arrow";
|
|
114
|
+
else if (sel instanceof FabricImage)
|
|
115
|
+
t = "image";
|
|
116
|
+
else
|
|
117
|
+
t = typeMap[sel.type] ?? "object";
|
|
103
118
|
setSelectedObjectType(t);
|
|
104
119
|
};
|
|
120
|
+
// ── Sync Fabric movement to HTML Nodes ────────────────────────
|
|
121
|
+
const onObjectMoving = (e) => {
|
|
122
|
+
const target = e.transform?.target || e.target;
|
|
123
|
+
if (!target)
|
|
124
|
+
return;
|
|
125
|
+
// Ensure prev positions exist to avoid NaN or jumps
|
|
126
|
+
if (target._prevLeft === undefined)
|
|
127
|
+
target._prevLeft = target.left;
|
|
128
|
+
if (target._prevTop === undefined)
|
|
129
|
+
target._prevTop = target.top;
|
|
130
|
+
target.setCoords();
|
|
131
|
+
};
|
|
105
132
|
const onDeselected = () => {
|
|
106
133
|
setSelectedObjectType(null);
|
|
107
134
|
setSelectionBox(null);
|
|
@@ -110,17 +137,11 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
110
137
|
setActiveTool("select");
|
|
111
138
|
}
|
|
112
139
|
};
|
|
113
|
-
|
|
114
|
-
// If user clicks the canvas background (not an object), clear overlay selection
|
|
115
|
-
if (!e.target) {
|
|
116
|
-
// You should pass a setter to clear selected IDs in your overlay
|
|
117
|
-
// setOverlaySelectedIds(new Set());
|
|
118
|
-
}
|
|
119
|
-
};
|
|
120
|
-
canvas.on("mouse:down", handleCanvasClick);
|
|
140
|
+
// Event Binding
|
|
121
141
|
canvas.on("selection:created", onSelected);
|
|
122
142
|
canvas.on("selection:updated", onSelected);
|
|
123
143
|
canvas.on("selection:cleared", onDeselected);
|
|
144
|
+
canvas.on("object:moving", onObjectMoving);
|
|
124
145
|
canvas.on("mouse:down", onDown);
|
|
125
146
|
canvas.on("mouse:move", onMove);
|
|
126
147
|
canvas.on("mouse:up", onUp);
|
|
@@ -128,6 +149,7 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
|
|
|
128
149
|
canvas.off("selection:created", onSelected);
|
|
129
150
|
canvas.off("selection:updated", onSelected);
|
|
130
151
|
canvas.off("selection:cleared", onDeselected);
|
|
152
|
+
canvas.off("object:moving", onObjectMoving);
|
|
131
153
|
canvas.off("mouse:down", onDown);
|
|
132
154
|
canvas.off("mouse:move", onMove);
|
|
133
155
|
canvas.off("mouse:up", onUp);
|