@mhamz.01/easyflow-whiteboard 1.28.0 → 2.0.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.
- 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":"custom-node-overlay-layer.d.ts","sourceRoot":"","sources":["../../../src/components/node/custom-node-overlay-layer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAM9C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,uBAAuB;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACxC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,YAAY,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzE,qBAAqB,CAAC,EAAE,YAAY,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/C;AAaD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,UAAc,EACd,cAA+B,EAC/B,YAAmB,EACnB,qBAA0B,EAC1B,YAAY,GACb,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"custom-node-overlay-layer.d.ts","sourceRoot":"","sources":["../../../src/components/node/custom-node-overlay-layer.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAM9C,MAAM,WAAW,IAAI;IACnB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACxC,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IACrC,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;CACX;AAED,UAAU,uBAAuB;IAC/B,KAAK,EAAE,IAAI,EAAE,CAAC;IACd,SAAS,EAAE,QAAQ,EAAE,CAAC;IACtB,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,IAAI,CAAC;IACxC,iBAAiB,CAAC,EAAE,CAAC,SAAS,EAAE,QAAQ,EAAE,KAAK,IAAI,CAAC;IACpD,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,cAAc,CAAC,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IAC1C,YAAY,CAAC,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC;IACzE,qBAAqB,CAAC,EAAE,YAAY,EAAE,CAAC;IACvC,YAAY,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/C;AAaD,MAAM,CAAC,OAAO,UAAU,kBAAkB,CAAC,EACzC,KAAK,EACL,SAAS,EACT,aAAa,EACb,iBAAiB,EACjB,UAAc,EACd,cAA+B,EAC/B,YAAmB,EACnB,qBAA0B,EAC1B,YAAY,GACb,EAAE,uBAAuB,2CAudzB"}
|
|
@@ -128,38 +128,37 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
128
128
|
return { x: doc.x, y: doc.y };
|
|
129
129
|
return undefined;
|
|
130
130
|
};
|
|
131
|
-
const isItemInSelectionBox = (
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
const
|
|
135
|
-
const
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
131
|
+
const isItemInSelectionBox = (x, y, width, height, box) => {
|
|
132
|
+
const itemX1 = x * canvasZoom + canvasViewport.x;
|
|
133
|
+
const itemY1 = y * canvasZoom + canvasViewport.y;
|
|
134
|
+
const itemX2 = itemX1 + width * canvasZoom;
|
|
135
|
+
const itemY2 = itemY1 + height * canvasZoom;
|
|
136
|
+
const boxX1 = Math.min(box.x1, box.x2);
|
|
137
|
+
const boxY1 = Math.min(box.y1, box.y2);
|
|
138
|
+
const boxX2 = Math.max(box.x1, box.x2);
|
|
139
|
+
const boxY2 = Math.max(box.y1, box.y2);
|
|
140
|
+
return !(boxX2 < itemX1 || boxX1 > itemX2 || boxY2 < itemY1 || boxY1 > itemY2);
|
|
140
141
|
};
|
|
141
142
|
// ── Selection box detection ──────────────────────────────────────────────────
|
|
142
143
|
useEffect(() => {
|
|
143
144
|
if (!selectionBox)
|
|
144
|
-
return;
|
|
145
|
+
return; // Don't clear on null — let keyboard/click handlers do that
|
|
145
146
|
const newSelected = new Set();
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
const TASK_HEIGHT = 140;
|
|
150
|
-
const DOC_HEIGHT = 160;
|
|
151
|
-
localTasks.forEach((t) => {
|
|
152
|
-
if (isItemInSelectionBox(t.x, t.y, NODE_WIDTH, TASK_HEIGHT, selectionBox)) {
|
|
153
|
-
newSelected.add(t.id);
|
|
154
|
-
}
|
|
147
|
+
localTasks.forEach((task) => {
|
|
148
|
+
if (isItemInSelectionBox(task.x, task.y, 300, 140, selectionBox))
|
|
149
|
+
newSelected.add(task.id);
|
|
155
150
|
});
|
|
156
|
-
localDocuments.forEach((
|
|
157
|
-
if (isItemInSelectionBox(
|
|
158
|
-
newSelected.add(
|
|
159
|
-
|
|
151
|
+
localDocuments.forEach((doc) => {
|
|
152
|
+
if (isItemInSelectionBox(doc.x, doc.y, 300, 160, selectionBox))
|
|
153
|
+
newSelected.add(doc.id);
|
|
154
|
+
});
|
|
155
|
+
// Only update if something actually changed (avoids re-render churn)
|
|
156
|
+
setSelectedIds((prev) => {
|
|
157
|
+
const prevArr = Array.from(prev).sort().join(",");
|
|
158
|
+
const nextArr = Array.from(newSelected).sort().join(",");
|
|
159
|
+
return prevArr === nextArr ? prev : newSelected;
|
|
160
160
|
});
|
|
161
|
-
|
|
162
|
-
}, [selectionBox]);
|
|
161
|
+
}, [selectionBox, localTasks, localDocuments]);
|
|
163
162
|
// ── Drag start (HTML Node side) ──────────────────────────────────────────────
|
|
164
163
|
// Helper to extract coordinates regardless of event type
|
|
165
164
|
const getPointerEvent = (e) => {
|
|
@@ -329,25 +328,24 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
329
328
|
}, [localTasks, localDocuments, selectedIds, onTasksUpdate, onDocumentsUpdate]);
|
|
330
329
|
// ── Render helper ────────────────────────────────────────────────────────────
|
|
331
330
|
const renderItem = (id, x, y, children) => {
|
|
332
|
-
// We apply the viewport offset to the container,
|
|
333
|
-
// so here we only care about the scaled local position.
|
|
334
331
|
const screenX = x * canvasZoom;
|
|
335
332
|
const screenY = y * canvasZoom;
|
|
333
|
+
// 1. Detect if the user is interacting with the canvas at all
|
|
334
|
+
// 'dragging' is your existing state.
|
|
335
|
+
// You might want to pass 'isZooming' or 'isPanning' from your main canvas component here.
|
|
336
336
|
const isDragging = dragging?.itemIds.includes(id);
|
|
337
337
|
return (_jsx("div", { className: "pointer-events-auto absolute", style: {
|
|
338
338
|
left: 0,
|
|
339
339
|
top: 0,
|
|
340
|
-
//
|
|
340
|
+
// 2. Use translate3d for GPU performance
|
|
341
341
|
transform: `translate3d(${screenX}px, ${screenY}px, 0) scale(${canvasZoom})`,
|
|
342
342
|
transformOrigin: "top left",
|
|
343
|
-
//
|
|
344
|
-
//
|
|
343
|
+
// 3. THE FIX: Remove transition entirely during any viewport change
|
|
344
|
+
// Any 'ease' during zoom causes the "shaking" behavior.
|
|
345
345
|
transition: "none",
|
|
346
|
+
// 4. Optimization
|
|
346
347
|
willChange: "transform",
|
|
347
348
|
zIndex: isDragging ? 1000 : 1,
|
|
348
|
-
// Added: Prevent browser from trying to optimize text rendering during move
|
|
349
|
-
// which causes the "shaking" text bug.
|
|
350
|
-
backfaceVisibility: "hidden",
|
|
351
349
|
}, children: children }, id));
|
|
352
350
|
};
|
|
353
351
|
return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard-test.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard-test.tsx"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"whiteboard-test.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard-test.tsx"],"names":[],"mappings":"AA4CA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CAoQvC"}
|
|
@@ -1,274 +1,207 @@
|
|
|
1
|
-
"use
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
//
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
//
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
//
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
//
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
//
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
//
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
//
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
//
|
|
67
|
-
//
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
//
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
//
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
//
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
//
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
//
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
//
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
//
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
//
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
//
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
//
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
//
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
// ...prev,
|
|
209
|
-
// {
|
|
210
|
-
// ...docTemplate,
|
|
211
|
-
// id: `${docTemplate.id}-${Date.now()}`,
|
|
212
|
-
// x: cx - 150,
|
|
213
|
-
// y: cy - 80,
|
|
214
|
-
// },
|
|
215
|
-
// ]);
|
|
216
|
-
// };
|
|
217
|
-
// return (
|
|
218
|
-
// <div className="easyflow-whiteboard w-screen h-screen">
|
|
219
|
-
// <div
|
|
220
|
-
// ref={containerRef}
|
|
221
|
-
// className="relative w-full h-full overflow-hidden bg-[#0b0b0b]"
|
|
222
|
-
// style={{
|
|
223
|
-
// touchAction: "none",
|
|
224
|
-
// overscrollBehavior: "none",
|
|
225
|
-
// }}
|
|
226
|
-
// >
|
|
227
|
-
// <div
|
|
228
|
-
// className="absolute inset-0 pointer-events-none"
|
|
229
|
-
// style={{
|
|
230
|
-
// backgroundImage: `radial-gradient(circle, rgba(255,255,255,0.2) 1.2px, transparent 1.2px)`,
|
|
231
|
-
// backgroundSize: "40px 40px",
|
|
232
|
-
// zIndex: 0,
|
|
233
|
-
// }}
|
|
234
|
-
// />
|
|
235
|
-
// <canvas ref={canvasRef} className="absolute inset-0" style={{ zIndex: 1 }} />
|
|
236
|
-
// <CanvasOverlayLayer
|
|
237
|
-
// tasks={tasks}
|
|
238
|
-
// documents={documents}
|
|
239
|
-
// onTasksUpdate={setTasks}
|
|
240
|
-
// onDocumentsUpdate={setDocuments}
|
|
241
|
-
// canvasZoom={canvasZoom}
|
|
242
|
-
// canvasViewport={canvasViewport}
|
|
243
|
-
// selectionBox={selectionBox}
|
|
244
|
-
// selectedCanvasObjects={selectedCanvasObjects}
|
|
245
|
-
// fabricCanvas={fabricCanvasRef}
|
|
246
|
-
// />
|
|
247
|
-
// <div
|
|
248
|
-
// className="absolute inset-0 pointer-events-none"
|
|
249
|
-
// style={{ zIndex: 100 }}
|
|
250
|
-
// >
|
|
251
|
-
// <div className="pointer-events-auto">
|
|
252
|
-
// <WhiteboardToolbar
|
|
253
|
-
// fabricCanvas={fabricCanvasRef}
|
|
254
|
-
// isRestoringRef={isRestoringRef}
|
|
255
|
-
// onAddTask={handleAddTaskFromDropdown}
|
|
256
|
-
// onAddDocument={handleAddDocumentFromDropdown}
|
|
257
|
-
// />
|
|
258
|
-
// </div>
|
|
259
|
-
// <div className="pointer-events-auto">
|
|
260
|
-
// <ToolOptionsPanel fabricCanvas={fabricCanvasRef} />
|
|
261
|
-
// </div>
|
|
262
|
-
// <div className="pointer-events-auto">
|
|
263
|
-
// <ZoomControls
|
|
264
|
-
// zoom={canvasZoom}
|
|
265
|
-
// onZoomIn={handleZoomIn}
|
|
266
|
-
// onZoomOut={handleZoomOut}
|
|
267
|
-
// onResetZoom={handleResetZoom}
|
|
268
|
-
// />
|
|
269
|
-
// </div>
|
|
270
|
-
// </div>
|
|
271
|
-
// </div>
|
|
272
|
-
// </div>
|
|
273
|
-
// );
|
|
274
|
-
// }
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useRef, useState } from "react";
|
|
4
|
+
import { classRegistry } from "fabric";
|
|
5
|
+
import { useWhiteboardStore } from "../../store/whiteboard-store";
|
|
6
|
+
import WhiteboardToolbar from "../toolbar/whiteboard-toolbar";
|
|
7
|
+
import ToolOptionsPanel from "../toolbar/tooloptions-panel";
|
|
8
|
+
import CanvasOverlayLayer from "../node/custom-node-overlay-layer";
|
|
9
|
+
import ZoomControls from "../zoomcontrol/zoom-control";
|
|
10
|
+
import { Frame } from "../../lib/fabric-frame";
|
|
11
|
+
// Import all hooks
|
|
12
|
+
import { useCanvasInit } from "../../hooks/useCanvasInit";
|
|
13
|
+
import { useToolManager } from "../../hooks/useToolManager";
|
|
14
|
+
import { useDrawing } from "../../hooks/useDrawing";
|
|
15
|
+
import { useEraser } from "../../hooks/useEraser";
|
|
16
|
+
import { usePan } from "../../hooks/usePan";
|
|
17
|
+
import { useZoom } from "../../hooks/useZoom";
|
|
18
|
+
import { useSelection } from "../../hooks/useSelection";
|
|
19
|
+
import { useTextStyle } from "../../hooks/useTextStyle";
|
|
20
|
+
import { useLiveUpdate } from "../../hooks/useLiveUpdate";
|
|
21
|
+
import { useMouseHandlers } from "../../hooks/useMouseHandlers";
|
|
22
|
+
import { usePersistence } from "../../hooks/usePersistance";
|
|
23
|
+
classRegistry.setClass(Frame, "frame");
|
|
24
|
+
export default function FabricWhiteboard() {
|
|
25
|
+
// Refs
|
|
26
|
+
const canvasRef = useRef(null);
|
|
27
|
+
const fabricCanvasRef = useRef(null);
|
|
28
|
+
const containerRef = useRef(null);
|
|
29
|
+
const isDrawingRef = useRef(false);
|
|
30
|
+
const startPointRef = useRef(null);
|
|
31
|
+
const currentShapeRef = useRef(null);
|
|
32
|
+
const suppressHistoryRef = useRef(false);
|
|
33
|
+
const isRestoringRef = useRef(false);
|
|
34
|
+
// Eraser refs
|
|
35
|
+
const eraserTraceRef = useRef(null);
|
|
36
|
+
const eraserTargetsRef = useRef(new Set());
|
|
37
|
+
const eraserActiveRef = useRef(false);
|
|
38
|
+
const eraserPathRef = useRef(null);
|
|
39
|
+
const eraserPathPointsRef = useRef([]);
|
|
40
|
+
// Store
|
|
41
|
+
const activeTool = useWhiteboardStore((state) => state.activeTool);
|
|
42
|
+
const toolOptions = useWhiteboardStore((state) => state.toolOptions);
|
|
43
|
+
const addCanvasObject = useWhiteboardStore((state) => state.addCanvasObject);
|
|
44
|
+
const pushHistory = useWhiteboardStore((state) => state.pushHistory);
|
|
45
|
+
// State
|
|
46
|
+
const [tasks, setTasks] = useState([]);
|
|
47
|
+
const [documents, setDocuments] = useState([]);
|
|
48
|
+
const [canvasZoom, setCanvasZoom] = useState(1);
|
|
49
|
+
const [canvasViewport, setCanvasViewport] = useState({ x: 0, y: 0 });
|
|
50
|
+
const [selectionBox, setSelectionBox] = useState(null);
|
|
51
|
+
const [selectedCanvasObjects, setSelectedCanvasObjects] = useState([]);
|
|
52
|
+
const MIN_ZOOM = 0.1;
|
|
53
|
+
const MAX_ZOOM = 5;
|
|
54
|
+
const ZOOM_STEP = 0.1;
|
|
55
|
+
// Initialize canvas
|
|
56
|
+
useCanvasInit({
|
|
57
|
+
canvasRef,
|
|
58
|
+
fabricCanvasRef,
|
|
59
|
+
activeTool,
|
|
60
|
+
suppressHistoryRef,
|
|
61
|
+
isRestoringRef,
|
|
62
|
+
pushHistory,
|
|
63
|
+
setTasks, // Passed so hook can load saved tasks
|
|
64
|
+
setDocuments, // Passed so hook can load saved docs
|
|
65
|
+
});
|
|
66
|
+
// 2. High-Efficiency Persistence (Auto-saving)
|
|
67
|
+
// This replaces the inline "saveState" listeners you had before
|
|
68
|
+
usePersistence({
|
|
69
|
+
fabricCanvas: fabricCanvasRef,
|
|
70
|
+
tasks,
|
|
71
|
+
documents,
|
|
72
|
+
pushHistory,
|
|
73
|
+
isRestoringRef,
|
|
74
|
+
suppressHistoryRef,
|
|
75
|
+
});
|
|
76
|
+
// 3. Tool management (Existing)
|
|
77
|
+
useToolManager({
|
|
78
|
+
fabricCanvas: fabricCanvasRef,
|
|
79
|
+
activeTool,
|
|
80
|
+
toolOptions,
|
|
81
|
+
eraserTraceRef,
|
|
82
|
+
eraserPathRef,
|
|
83
|
+
eraserPathPointsRef,
|
|
84
|
+
eraserTargetsRef,
|
|
85
|
+
});
|
|
86
|
+
// Drawing handlers
|
|
87
|
+
const drawingHandlers = useDrawing({
|
|
88
|
+
fabricCanvas: fabricCanvasRef,
|
|
89
|
+
activeTool,
|
|
90
|
+
toolOptions,
|
|
91
|
+
isDrawingRef,
|
|
92
|
+
startPointRef,
|
|
93
|
+
currentShapeRef,
|
|
94
|
+
suppressHistoryRef,
|
|
95
|
+
pushHistory,
|
|
96
|
+
addCanvasObject,
|
|
97
|
+
});
|
|
98
|
+
// Eraser handlers
|
|
99
|
+
const eraserHandlers = useEraser({
|
|
100
|
+
fabricCanvas: fabricCanvasRef,
|
|
101
|
+
activeTool,
|
|
102
|
+
toolOptions,
|
|
103
|
+
eraserTraceRef,
|
|
104
|
+
eraserTargetsRef,
|
|
105
|
+
eraserActiveRef,
|
|
106
|
+
eraserPathRef,
|
|
107
|
+
eraserPathPointsRef,
|
|
108
|
+
suppressHistoryRef,
|
|
109
|
+
pushHistory,
|
|
110
|
+
});
|
|
111
|
+
// Zoom
|
|
112
|
+
const { handleZoom } = useZoom({
|
|
113
|
+
fabricCanvas: fabricCanvasRef,
|
|
114
|
+
MIN_ZOOM,
|
|
115
|
+
MAX_ZOOM,
|
|
116
|
+
canvasZoom,
|
|
117
|
+
canvasViewport,
|
|
118
|
+
setCanvasZoom,
|
|
119
|
+
setCanvasViewport,
|
|
120
|
+
});
|
|
121
|
+
// Pan
|
|
122
|
+
usePan({
|
|
123
|
+
fabricCanvas: fabricCanvasRef,
|
|
124
|
+
activeTool,
|
|
125
|
+
handleZoom,
|
|
126
|
+
setCanvasViewport,
|
|
127
|
+
});
|
|
128
|
+
// Selection
|
|
129
|
+
useSelection({
|
|
130
|
+
fabricCanvas: fabricCanvasRef,
|
|
131
|
+
activeTool,
|
|
132
|
+
canvasZoom,
|
|
133
|
+
canvasViewport,
|
|
134
|
+
setSelectionBox,
|
|
135
|
+
setSelectedCanvasObjects,
|
|
136
|
+
isDrawingRef,
|
|
137
|
+
});
|
|
138
|
+
// Text style updates
|
|
139
|
+
useTextStyle({
|
|
140
|
+
fabricCanvas: fabricCanvasRef,
|
|
141
|
+
toolOptions,
|
|
142
|
+
});
|
|
143
|
+
// Live updates
|
|
144
|
+
useLiveUpdate({
|
|
145
|
+
fabricCanvas: fabricCanvasRef,
|
|
146
|
+
toolOptions,
|
|
147
|
+
});
|
|
148
|
+
// Mouse handlers
|
|
149
|
+
useMouseHandlers({
|
|
150
|
+
fabricCanvas: fabricCanvasRef,
|
|
151
|
+
activeTool,
|
|
152
|
+
toolOptions,
|
|
153
|
+
drawingHandlers,
|
|
154
|
+
eraserHandlers,
|
|
155
|
+
});
|
|
156
|
+
// Zoom controls
|
|
157
|
+
const handleZoomIn = () => handleZoom(canvasZoom + ZOOM_STEP);
|
|
158
|
+
const handleZoomOut = () => handleZoom(canvasZoom - ZOOM_STEP);
|
|
159
|
+
const handleResetZoom = () => handleZoom(1);
|
|
160
|
+
// Dropdown handlers
|
|
161
|
+
const handleAddTaskFromDropdown = (taskTemplate) => {
|
|
162
|
+
const canvas = fabricCanvasRef.current;
|
|
163
|
+
if (!canvas)
|
|
164
|
+
return;
|
|
165
|
+
const vpt = canvas.viewportTransform;
|
|
166
|
+
if (!vpt)
|
|
167
|
+
return;
|
|
168
|
+
const cx = (canvas.getWidth() / 2 - vpt[4]) / canvasZoom;
|
|
169
|
+
const cy = (canvas.getHeight() / 2 - vpt[5]) / canvasZoom;
|
|
170
|
+
setTasks((prev) => [
|
|
171
|
+
...prev,
|
|
172
|
+
{
|
|
173
|
+
...taskTemplate,
|
|
174
|
+
id: `${taskTemplate.id}-${Date.now()}`,
|
|
175
|
+
x: cx - 150,
|
|
176
|
+
y: cy - 60,
|
|
177
|
+
},
|
|
178
|
+
]);
|
|
179
|
+
};
|
|
180
|
+
const handleAddDocumentFromDropdown = (docTemplate) => {
|
|
181
|
+
const canvas = fabricCanvasRef.current;
|
|
182
|
+
if (!canvas)
|
|
183
|
+
return;
|
|
184
|
+
const vpt = canvas.viewportTransform;
|
|
185
|
+
if (!vpt)
|
|
186
|
+
return;
|
|
187
|
+
const cx = (canvas.getWidth() / 2 - vpt[4]) / canvasZoom;
|
|
188
|
+
const cy = (canvas.getHeight() / 2 - vpt[5]) / canvasZoom;
|
|
189
|
+
setDocuments((prev) => [
|
|
190
|
+
...prev,
|
|
191
|
+
{
|
|
192
|
+
...docTemplate,
|
|
193
|
+
id: `${docTemplate.id}-${Date.now()}`,
|
|
194
|
+
x: cx - 150,
|
|
195
|
+
y: cy - 80,
|
|
196
|
+
},
|
|
197
|
+
]);
|
|
198
|
+
};
|
|
199
|
+
return (_jsx("div", { className: "easyflow-whiteboard w-screen h-screen", children: _jsxs("div", { ref: containerRef, className: "relative w-full h-full overflow-hidden bg-[#0b0b0b]", style: {
|
|
200
|
+
touchAction: "none",
|
|
201
|
+
overscrollBehavior: "none",
|
|
202
|
+
}, children: [_jsx("div", { className: "absolute inset-0 pointer-events-none", style: {
|
|
203
|
+
backgroundImage: `radial-gradient(circle, rgba(255,255,255,0.2) 1.2px, transparent 1.2px)`,
|
|
204
|
+
backgroundSize: "40px 40px",
|
|
205
|
+
zIndex: 0,
|
|
206
|
+
} }), _jsx("canvas", { ref: canvasRef, className: "absolute inset-0", style: { zIndex: 1 } }), _jsx(CanvasOverlayLayer, { tasks: tasks, documents: documents, onTasksUpdate: setTasks, onDocumentsUpdate: setDocuments, canvasZoom: canvasZoom, canvasViewport: canvasViewport, selectionBox: selectionBox, selectedCanvasObjects: selectedCanvasObjects, fabricCanvas: fabricCanvasRef }), _jsxs("div", { className: "absolute inset-0 pointer-events-none", style: { zIndex: 100 }, children: [_jsx("div", { className: "pointer-events-auto", children: _jsx(WhiteboardToolbar, { fabricCanvas: fabricCanvasRef, isRestoringRef: isRestoringRef, onAddTask: handleAddTaskFromDropdown, onAddDocument: handleAddDocumentFromDropdown }) }), _jsx("div", { className: "pointer-events-auto", children: _jsx(ToolOptionsPanel, { fabricCanvas: fabricCanvasRef }) }), _jsx("div", { className: "pointer-events-auto", children: _jsx(ZoomControls, { zoom: canvasZoom, onZoomIn: handleZoomIn, onZoomOut: handleZoomOut, onResetZoom: handleResetZoom }) })] })] }) }));
|
|
207
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"whiteboard.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard.tsx"],"names":[],"mappings":""}
|