@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.
@@ -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,2CA4dzB"}
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 = (nodeX, nodeY, width, height, box) => {
132
- // EVERYTHING HERE IS NOW IN WORLD (SCENE) COORDINATES
133
- // No canvasZoom or canvasViewport needed for the check!
134
- const nodeX2 = nodeX + width;
135
- const nodeY2 = nodeY + height;
136
- return !(box.x2 < nodeX ||
137
- box.x1 > nodeX2 ||
138
- box.y2 < nodeY ||
139
- box.y1 > nodeY2);
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
- // Use the actual dimensions of your components
147
- // Better yet: Pass these as props if they are dynamic
148
- const NODE_WIDTH = 300;
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((d) => {
157
- if (isItemInSelectionBox(d.x, d.y, NODE_WIDTH, DOC_HEIGHT, selectionBox)) {
158
- newSelected.add(d.id);
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
- setSelectedIds(newSelected);
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
- // Using translate3d(x, y, 0) is non-negotiable for 2026 performance
340
+ // 2. Use translate3d for GPU performance
341
341
  transform: `translate3d(${screenX}px, ${screenY}px, 0) scale(${canvasZoom})`,
342
342
  transformOrigin: "top left",
343
- // CRITICAL: Disable all transitions.
344
- // Even a 100ms transition will cause the node to "float" away during zoom.
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,2 @@
1
+ export default function FabricWhiteboard(): import("react/jsx-runtime").JSX.Element;
1
2
  //# sourceMappingURL=whiteboard-test.d.ts.map
@@ -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 strict";
2
- // "use client";
3
- // import React, { useRef, useState } from "react";
4
- // import { Canvas, FabricObject, Circle, 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 type { Document } from "../node/custom-node-overlay-layer";
10
- // import ZoomControls from "../zoomcontrol/zoom-control";
11
- // import { Frame } from "../../lib/fabric-frame";
12
- // import * as fabric from "fabric";
13
- // // Import all hooks
14
- // import { useCanvasInit } from "../../hooks/useCanvasInit";
15
- // import { useToolManager } from "../../hooks/useToolManager";
16
- // import { useDrawing } from "../../hooks/useDrawing";
17
- // import { useEraser } from "../../hooks/useEraser";
18
- // import { usePan } from "../../hooks/usePan";
19
- // import { useZoom } from "../../hooks/useZoom";
20
- // import { useSelection } from "../../hooks/useSelection";
21
- // import { useTextStyle } from "../../hooks/useTextStyle";
22
- // import { useLiveUpdate } from "../../hooks/useLiveUpdate";
23
- // import { useMouseHandlers } from "../../hooks/useMouseHandlers";
24
- // import { usePersistence } from "../../hooks/usePersistance";
25
- // interface Task {
26
- // id: string;
27
- // title: string;
28
- // status: "todo" | "in-progress" | "done";
29
- // x: number;
30
- // y: number;
31
- // project?: string;
32
- // assignee?: string;
33
- // priority?: "low" | "medium" | "high";
34
- // dueDate?: string;
35
- // }
36
- // classRegistry.setClass(Frame, "frame");
37
- // export default function FabricWhiteboard() {
38
- // // Refs
39
- // const canvasRef = useRef<HTMLCanvasElement>(null);
40
- // const fabricCanvasRef = useRef<Canvas | null>(null);
41
- // const containerRef = useRef<HTMLDivElement>(null);
42
- // const isDrawingRef = useRef(false);
43
- // const startPointRef = useRef<{ x: number; y: number } | null>(null);
44
- // const currentShapeRef = useRef<FabricObject | null>(null);
45
- // const suppressHistoryRef = useRef(false);
46
- // const isRestoringRef = useRef(false);
47
- // // Eraser refs
48
- // const eraserTraceRef = useRef<Circle | null>(null);
49
- // const eraserTargetsRef = useRef<Set<FabricObject>>(new Set());
50
- // const eraserActiveRef = useRef(false);
51
- // const eraserPathRef = useRef<fabric.Path | null>(null);
52
- // const eraserPathPointsRef = useRef<string[]>([]);
53
- // // Store
54
- // const activeTool = useWhiteboardStore((state) => state.activeTool);
55
- // const toolOptions = useWhiteboardStore((state) => state.toolOptions);
56
- // const addCanvasObject = useWhiteboardStore((state) => state.addCanvasObject);
57
- // const pushHistory = useWhiteboardStore((state) => state.pushHistory);
58
- // // State
59
- // const [tasks, setTasks] = useState<Task[]>([]);
60
- // const [documents, setDocuments] = useState<Document[]>([]);
61
- // const [canvasZoom, setCanvasZoom] = useState(1);
62
- // const [canvasViewport, setCanvasViewport] = useState({ x: 0, y: 0 });
63
- // const [selectionBox, setSelectionBox] = useState<{
64
- // x1: number;
65
- // y1: number;
66
- // x2: number;
67
- // y2: number;
68
- // } | null>(null);
69
- // const [selectedCanvasObjects, setSelectedCanvasObjects] = useState<
70
- // FabricObject[]
71
- // >([]);
72
- // const MIN_ZOOM = 0.1;
73
- // const MAX_ZOOM = 5;
74
- // const ZOOM_STEP = 0.1;
75
- // // Initialize canvas
76
- // useCanvasInit({
77
- // canvasRef,
78
- // fabricCanvasRef,
79
- // activeTool,
80
- // suppressHistoryRef,
81
- // isRestoringRef,
82
- // pushHistory,
83
- // setTasks, // Passed so hook can load saved tasks
84
- // setDocuments, // Passed so hook can load saved docs
85
- // });
86
- // // 2. High-Efficiency Persistence (Auto-saving)
87
- // // This replaces the inline "saveState" listeners you had before
88
- // usePersistence({
89
- // fabricCanvas: fabricCanvasRef,
90
- // tasks,
91
- // documents,
92
- // pushHistory,
93
- // isRestoringRef,
94
- // suppressHistoryRef,
95
- // });
96
- // // 3. Tool management (Existing)
97
- // useToolManager({
98
- // fabricCanvas: fabricCanvasRef,
99
- // activeTool,
100
- // toolOptions,
101
- // eraserTraceRef,
102
- // eraserPathRef,
103
- // eraserPathPointsRef,
104
- // eraserTargetsRef,
105
- // });
106
- // // Drawing handlers
107
- // const drawingHandlers = useDrawing({
108
- // fabricCanvas: fabricCanvasRef,
109
- // activeTool,
110
- // toolOptions,
111
- // isDrawingRef,
112
- // startPointRef,
113
- // currentShapeRef,
114
- // suppressHistoryRef,
115
- // pushHistory,
116
- // addCanvasObject,
117
- // });
118
- // // Eraser handlers
119
- // const eraserHandlers = useEraser({
120
- // fabricCanvas: fabricCanvasRef,
121
- // activeTool,
122
- // toolOptions,
123
- // eraserTraceRef,
124
- // eraserTargetsRef,
125
- // eraserActiveRef,
126
- // eraserPathRef,
127
- // eraserPathPointsRef,
128
- // suppressHistoryRef,
129
- // pushHistory,
130
- // });
131
- // // Zoom
132
- // const { handleZoom } = useZoom({
133
- // fabricCanvas: fabricCanvasRef,
134
- // MIN_ZOOM,
135
- // MAX_ZOOM,
136
- // canvasZoom,
137
- // canvasViewport,
138
- // setCanvasZoom,
139
- // setCanvasViewport,
140
- // });
141
- // // Pan
142
- // usePan({
143
- // fabricCanvas: fabricCanvasRef,
144
- // activeTool,
145
- // handleZoom,
146
- // setCanvasViewport,
147
- // });
148
- // // Selection
149
- // useSelection({
150
- // fabricCanvas: fabricCanvasRef,
151
- // activeTool,
152
- // canvasZoom,
153
- // canvasViewport,
154
- // setSelectionBox,
155
- // setSelectedCanvasObjects,
156
- // isDrawingRef,
157
- // });
158
- // // Text style updates
159
- // useTextStyle({
160
- // fabricCanvas: fabricCanvasRef,
161
- // toolOptions,
162
- // });
163
- // // Live updates
164
- // useLiveUpdate({
165
- // fabricCanvas: fabricCanvasRef,
166
- // toolOptions,
167
- // });
168
- // // Mouse handlers
169
- // useMouseHandlers({
170
- // fabricCanvas: fabricCanvasRef,
171
- // activeTool,
172
- // toolOptions,
173
- // drawingHandlers,
174
- // eraserHandlers,
175
- // });
176
- // // Zoom controls
177
- // const handleZoomIn = () => handleZoom(canvasZoom + ZOOM_STEP);
178
- // const handleZoomOut = () => handleZoom(canvasZoom - ZOOM_STEP);
179
- // const handleResetZoom = () => handleZoom(1);
180
- // // Dropdown handlers
181
- // const handleAddTaskFromDropdown = (taskTemplate: any) => {
182
- // const canvas = fabricCanvasRef.current;
183
- // if (!canvas) return;
184
- // const vpt = canvas.viewportTransform;
185
- // if (!vpt) return;
186
- // const cx = (canvas.getWidth() / 2 - vpt[4]) / canvasZoom;
187
- // const cy = (canvas.getHeight() / 2 - vpt[5]) / canvasZoom;
188
- // setTasks((prev) => [
189
- // ...prev,
190
- // {
191
- // ...taskTemplate,
192
- // id: `${taskTemplate.id}-${Date.now()}`,
193
- // x: cx - 150,
194
- // y: cy - 60,
195
- // },
196
- // ]);
197
- // };
198
- // const handleAddDocumentFromDropdown = (
199
- // docTemplate: Omit<Document, "x" | "y">
200
- // ) => {
201
- // const canvas = fabricCanvasRef.current;
202
- // if (!canvas) return;
203
- // const vpt = canvas.viewportTransform;
204
- // if (!vpt) return;
205
- // const cx = (canvas.getWidth() / 2 - vpt[4]) / canvasZoom;
206
- // const cy = (canvas.getHeight() / 2 - vpt[5]) / canvasZoom;
207
- // setDocuments((prev) => [
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,2 +1 @@
1
- export default function FabricWhiteboard(): import("react/jsx-runtime").JSX.Element;
2
1
  //# sourceMappingURL=whiteboard.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"whiteboard.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard.tsx"],"names":[],"mappings":"AAwCA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CA6iCvC"}
1
+ {"version":3,"file":"whiteboard.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard.tsx"],"names":[],"mappings":""}