@mhamz.01/easyflow-whiteboard 2.15.0 → 2.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.
- package/dist/components/node/custom-node-overlay-layer.d.ts.map +1 -1
- package/dist/components/node/custom-node-overlay-layer.js +197 -258
- package/dist/components/toolbar/task-dropdown.d.ts.map +1 -1
- package/dist/components/toolbar/tooloptions-panel.d.ts +1 -1
- package/dist/components/toolbar/tooloptions-panel.d.ts.map +1 -1
- package/dist/components/toolbar/whiteboard-toolbar.d.ts.map +1 -1
- package/dist/hooks/useCanvasInit.d.ts.map +1 -1
- package/dist/hooks/useCanvasInit.js +1 -0
- package/dist/hooks/useDrawing.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -28
- package/dist/lib/fabric-utils.d.ts.map +1 -1
- package/dist/lib/fabric-utils.js +1 -2
- 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;
|
|
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;AAoBD,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,2CAqZzB"}
|
|
@@ -1,108 +1,93 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { useState, useEffect, useRef } from "react";
|
|
3
|
+
import { useState, useEffect, useRef, useCallback, memo } from "react";
|
|
4
4
|
import TaskNode from "./custom-node";
|
|
5
5
|
import DocumentNode from "./document-node";
|
|
6
|
+
// ── PERF: Memoized node wrappers ──────────────────────────────────────────────
|
|
7
|
+
// Prevents sibling nodes from re-rendering when only one node's position changes.
|
|
8
|
+
// Without memo, every setLocalTasks call during drag re-renders ALL nodes.
|
|
9
|
+
const MemoTaskNode = memo(TaskNode);
|
|
10
|
+
const MemoDocumentNode = memo(DocumentNode);
|
|
6
11
|
// ─── Component ────────────────────────────────────────────────────────────────
|
|
7
12
|
export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, onDocumentsUpdate, canvasZoom = 1, canvasViewport = { x: 0, y: 0 }, selectionBox = null, selectedCanvasObjects = [], fabricCanvas, }) {
|
|
8
13
|
const [localTasks, setLocalTasks] = useState(tasks);
|
|
9
14
|
const [localDocuments, setLocalDocuments] = useState(documents);
|
|
10
15
|
const [selectedIds, setSelectedIds] = useState(new Set());
|
|
11
|
-
|
|
16
|
+
// ─── Core refs ────────────────────────────────────────────────────────────
|
|
12
17
|
const dragStateRef = useRef({
|
|
13
|
-
isDragging: false,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
canvasObjectsStartPos: new Map(),
|
|
17
|
-
offsetX: 0,
|
|
18
|
-
offsetY: 0,
|
|
18
|
+
isDragging: false, itemIds: [],
|
|
19
|
+
startPositions: new Map(), canvasObjectsStartPos: new Map(),
|
|
20
|
+
offsetX: 0, offsetY: 0,
|
|
19
21
|
});
|
|
20
22
|
const rafIdRef = useRef(null);
|
|
21
23
|
const overlayRef = useRef(null);
|
|
22
|
-
// ──
|
|
24
|
+
// ── PERF: Mutex prevents object:moving and handleMove writing simultaneously ─
|
|
25
|
+
const isHtmlDraggingRef = useRef(false);
|
|
26
|
+
// ── PERF: Always-fresh refs — rebuilt synchronously every render ──────────
|
|
27
|
+
// Eliminates ALL stale closure problems without any useCallback deps.
|
|
28
|
+
// nodePositionsRef: ground truth for positions at drag start
|
|
29
|
+
const nodePositionsRef = useRef(new Map());
|
|
30
|
+
nodePositionsRef.current = new Map([
|
|
31
|
+
...localTasks.map((t) => [t.id, { x: t.x, y: t.y }]),
|
|
32
|
+
...localDocuments.map((d) => [d.id, { x: d.x, y: d.y }]),
|
|
33
|
+
]);
|
|
34
|
+
// selectedIdsRef: used in stable effect closures
|
|
35
|
+
const selectedIdsRef = useRef(selectedIds);
|
|
36
|
+
selectedIdsRef.current = selectedIds;
|
|
37
|
+
// selectedCanvasObjectsRef: avoids stale prop in handleDragStart
|
|
38
|
+
const selectedCanvasObjectsRef = useRef(selectedCanvasObjects);
|
|
39
|
+
selectedCanvasObjectsRef.current = selectedCanvasObjects;
|
|
40
|
+
// Parent callbacks in refs — handleEnd never captures stale callbacks
|
|
41
|
+
const onTasksUpdateRef = useRef(onTasksUpdate);
|
|
42
|
+
const onDocumentsUpdateRef = useRef(onDocumentsUpdate);
|
|
43
|
+
onTasksUpdateRef.current = onTasksUpdate;
|
|
44
|
+
onDocumentsUpdateRef.current = onDocumentsUpdate;
|
|
45
|
+
// ─── Sync props → local state ─────────────────────────────────────────────
|
|
23
46
|
useEffect(() => { setLocalTasks(tasks); }, [tasks]);
|
|
24
47
|
useEffect(() => { setLocalDocuments(documents); }, [documents]);
|
|
25
|
-
//
|
|
26
|
-
const handleOverlayWheel = (e) => {
|
|
27
|
-
if (e.ctrlKey || e.metaKey || e.shiftKey) {
|
|
28
|
-
const canvas = fabricCanvas?.current;
|
|
29
|
-
if (!canvas)
|
|
30
|
-
return;
|
|
31
|
-
const nativeEvent = e.nativeEvent;
|
|
32
|
-
// getScenePoint handles the transformation from screen to canvas space
|
|
33
|
-
const scenePoint = canvas.getScenePoint(nativeEvent);
|
|
34
|
-
// Viewport point is simply the mouse position relative to the canvas element
|
|
35
|
-
const rect = canvas.getElement().getBoundingClientRect();
|
|
36
|
-
const viewportPoint = {
|
|
37
|
-
x: nativeEvent.clientX - rect.left,
|
|
38
|
-
y: nativeEvent.clientY - rect.top,
|
|
39
|
-
};
|
|
40
|
-
// We cast to 'any' here because we are manually triggering an internal
|
|
41
|
-
// event bus, and Fabric's internal types for .fire() can be overly strict.
|
|
42
|
-
canvas.fire("mouse:wheel", {
|
|
43
|
-
e: nativeEvent,
|
|
44
|
-
scenePoint,
|
|
45
|
-
viewportPoint,
|
|
46
|
-
});
|
|
47
|
-
e.preventDefault();
|
|
48
|
-
e.stopPropagation();
|
|
49
|
-
}
|
|
50
|
-
};
|
|
48
|
+
// ─── Wheel forwarding ─────────────────────────────────────────────────────
|
|
51
49
|
useEffect(() => {
|
|
52
50
|
const overlayEl = overlayRef.current;
|
|
53
51
|
const canvas = fabricCanvas?.current;
|
|
54
52
|
if (!overlayEl || !canvas)
|
|
55
53
|
return;
|
|
56
54
|
const handleGlobalWheel = (e) => {
|
|
57
|
-
|
|
58
|
-
// (meaning they are hovering over a Task or Document)
|
|
59
|
-
const target = e.target;
|
|
60
|
-
const isOverNode = target !== overlayEl;
|
|
55
|
+
const isOverNode = e.target !== overlayEl;
|
|
61
56
|
if ((e.ctrlKey || e.metaKey) && isOverNode) {
|
|
62
|
-
// 1. Prevent Browser Zoom immediately
|
|
63
57
|
e.preventDefault();
|
|
64
58
|
e.stopPropagation();
|
|
65
|
-
// 2. Calculate coordinates for Fabric
|
|
66
59
|
const scenePoint = canvas.getScenePoint(e);
|
|
67
60
|
const rect = canvas.getElement().getBoundingClientRect();
|
|
68
|
-
const viewportPoint = {
|
|
69
|
-
x: e.clientX - rect.left,
|
|
70
|
-
y: e.clientY - rect.top,
|
|
71
|
-
};
|
|
72
|
-
// 3. Manually fire the event into Fabric
|
|
73
61
|
canvas.fire("mouse:wheel", {
|
|
74
|
-
e
|
|
75
|
-
|
|
76
|
-
viewportPoint,
|
|
62
|
+
e, scenePoint,
|
|
63
|
+
viewportPoint: { x: e.clientX - rect.left, y: e.clientY - rect.top },
|
|
77
64
|
});
|
|
78
65
|
}
|
|
79
66
|
};
|
|
80
|
-
// CRITICAL: { passive: false } allows us to cancel the browser's zoom
|
|
81
67
|
overlayEl.addEventListener("wheel", handleGlobalWheel, { passive: false });
|
|
82
|
-
return () =>
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
}, [fabricCanvas, canvasZoom]); // Re-bind when zoom changes to keep closure fresh
|
|
86
|
-
// ── Fabric → Overlay Sync (Fixes Dragging from Fabric area) ──────────────────
|
|
68
|
+
return () => overlayEl.removeEventListener("wheel", handleGlobalWheel);
|
|
69
|
+
}, [fabricCanvas]);
|
|
70
|
+
// ─── Fabric → Overlay sync ────────────────────────────────────────────────
|
|
87
71
|
useEffect(() => {
|
|
88
72
|
const canvas = fabricCanvas?.current;
|
|
89
73
|
if (!canvas)
|
|
90
74
|
return;
|
|
91
75
|
const handleObjectMoving = (e) => {
|
|
76
|
+
// MUTEX: HTML drag and Fabric drag must never write positions simultaneously
|
|
77
|
+
if (isHtmlDraggingRef.current)
|
|
78
|
+
return;
|
|
92
79
|
const target = e.transform?.target || e.target;
|
|
93
80
|
if (!target)
|
|
94
81
|
return;
|
|
95
|
-
// 1. Calculate delta in raw Scene Coordinates
|
|
96
|
-
// We do NOT divide by zoom here because target.left/top are world units.
|
|
97
82
|
const deltaX = target.left - (target._prevLeft ?? target.left);
|
|
98
83
|
const deltaY = target.top - (target._prevTop ?? target.top);
|
|
99
84
|
target._prevLeft = target.left;
|
|
100
85
|
target._prevTop = target.top;
|
|
101
86
|
if (deltaX === 0 && deltaY === 0)
|
|
102
87
|
return;
|
|
103
|
-
|
|
104
|
-
setLocalTasks((prev) => prev.map((t) =>
|
|
105
|
-
setLocalDocuments((prev) => prev.map((d) =>
|
|
88
|
+
const sel = selectedIdsRef.current;
|
|
89
|
+
setLocalTasks((prev) => prev.map((t) => sel.has(t.id) ? { ...t, x: t.x + deltaX, y: t.y + deltaY } : t));
|
|
90
|
+
setLocalDocuments((prev) => prev.map((d) => sel.has(d.id) ? { ...d, x: d.x + deltaX, y: d.y + deltaY } : d));
|
|
106
91
|
};
|
|
107
92
|
const handleMouseDown = (e) => {
|
|
108
93
|
const target = e.target;
|
|
@@ -117,138 +102,68 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
117
102
|
canvas.off("object:moving", handleObjectMoving);
|
|
118
103
|
canvas.off("mouse:down", handleMouseDown);
|
|
119
104
|
};
|
|
120
|
-
}, [
|
|
121
|
-
//
|
|
122
|
-
const getItemPosition = (id) => {
|
|
123
|
-
const task = localTasks.find((t) => t.id === id);
|
|
124
|
-
if (task)
|
|
125
|
-
return { x: task.x, y: task.y };
|
|
126
|
-
const doc = localDocuments.find((d) => d.id === id);
|
|
127
|
-
if (doc)
|
|
128
|
-
return { x: doc.x, y: doc.y };
|
|
129
|
-
return undefined;
|
|
130
|
-
};
|
|
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);
|
|
141
|
-
};
|
|
142
|
-
// ── Selection box detection ──────────────────────────────────────────────────
|
|
105
|
+
}, [fabricCanvas]);
|
|
106
|
+
// ─── Selection box ────────────────────────────────────────────────────────
|
|
143
107
|
useEffect(() => {
|
|
144
108
|
if (!selectionBox)
|
|
145
109
|
return;
|
|
146
|
-
// ── O(n) single pass — no sort, no join, no extra allocations ──
|
|
147
110
|
const newSelected = new Set();
|
|
148
111
|
for (const task of localTasks) {
|
|
149
|
-
|
|
112
|
+
const x1 = task.x * canvasZoom + canvasViewport.x;
|
|
113
|
+
const y1 = task.y * canvasZoom + canvasViewport.y;
|
|
114
|
+
const x2 = x1 + 300 * canvasZoom;
|
|
115
|
+
const y2 = y1 + 140 * canvasZoom;
|
|
116
|
+
const bX1 = Math.min(selectionBox.x1, selectionBox.x2);
|
|
117
|
+
const bY1 = Math.min(selectionBox.y1, selectionBox.y2);
|
|
118
|
+
const bX2 = Math.max(selectionBox.x1, selectionBox.x2);
|
|
119
|
+
const bY2 = Math.max(selectionBox.y1, selectionBox.y2);
|
|
120
|
+
if (!(bX2 < x1 || bX1 > x2 || bY2 < y1 || bY1 > y2))
|
|
150
121
|
newSelected.add(task.id);
|
|
151
122
|
}
|
|
152
123
|
for (const doc of localDocuments) {
|
|
153
|
-
|
|
124
|
+
const x1 = doc.x * canvasZoom + canvasViewport.x;
|
|
125
|
+
const y1 = doc.y * canvasZoom + canvasViewport.y;
|
|
126
|
+
const x2 = x1 + 320 * canvasZoom;
|
|
127
|
+
const y2 = y1 + 160 * canvasZoom;
|
|
128
|
+
const bX1 = Math.min(selectionBox.x1, selectionBox.x2);
|
|
129
|
+
const bY1 = Math.min(selectionBox.y1, selectionBox.y2);
|
|
130
|
+
const bX2 = Math.max(selectionBox.x1, selectionBox.x2);
|
|
131
|
+
const bY2 = Math.max(selectionBox.y1, selectionBox.y2);
|
|
132
|
+
if (!(bX2 < x1 || bX1 > x2 || bY2 < y1 || bY1 > y2))
|
|
154
133
|
newSelected.add(doc.id);
|
|
155
134
|
}
|
|
156
|
-
//
|
|
135
|
+
// O(n) equality — same Set ref if unchanged, blocks unnecessary re-render
|
|
157
136
|
setSelectedIds((prev) => {
|
|
158
137
|
if (prev.size !== newSelected.size)
|
|
159
138
|
return newSelected;
|
|
160
|
-
for (const id of newSelected)
|
|
139
|
+
for (const id of newSelected)
|
|
161
140
|
if (!prev.has(id))
|
|
162
|
-
return newSelected;
|
|
163
|
-
|
|
164
|
-
return prev; // identical — return same reference, no re-render
|
|
165
|
-
});
|
|
166
|
-
}, [selectionBox, localTasks, localDocuments]);
|
|
167
|
-
// ── Drag start (HTML Node side) ──────────────────────────────────────────────
|
|
168
|
-
// Helper to extract coordinates regardless of event type
|
|
169
|
-
const getPointerEvent = (e) => {
|
|
170
|
-
if ('touches' in e && e.touches.length > 0)
|
|
171
|
-
return e.touches[0];
|
|
172
|
-
return e;
|
|
173
|
-
};
|
|
174
|
-
const handleDragStart = (itemId, e) => {
|
|
175
|
-
// 1. Safety check for the Fabric instance
|
|
176
|
-
const canvas = fabricCanvas?.current;
|
|
177
|
-
if (!canvas)
|
|
178
|
-
return;
|
|
179
|
-
// 2. Normalize the event (Touch vs Mouse)
|
|
180
|
-
if (e.cancelable)
|
|
181
|
-
e.preventDefault();
|
|
182
|
-
const pointer = getPointerEvent(e);
|
|
183
|
-
// 3. Determine which items are being dragged
|
|
184
|
-
// selection update DOES NOT trigger before drag snapshot
|
|
185
|
-
let itemsToDrag;
|
|
186
|
-
if (selectedIds.has(itemId)) {
|
|
187
|
-
itemsToDrag = Array.from(selectedIds);
|
|
188
|
-
}
|
|
189
|
-
else {
|
|
190
|
-
itemsToDrag = [itemId];
|
|
191
|
-
}
|
|
192
|
-
// 4. Capture current World Transform (Zoom & Pan)
|
|
193
|
-
// We read directly from the canvas to ensure zero-frame lag
|
|
194
|
-
const vpt = canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
|
|
195
|
-
const liveZoom = vpt[0];
|
|
196
|
-
const liveVpX = vpt[4];
|
|
197
|
-
const liveVpY = vpt[5];
|
|
198
|
-
// 5. Convert the Click Position from Screen Pixels to World Units
|
|
199
|
-
const clickWorldX = (pointer.clientX - liveVpX) / liveZoom;
|
|
200
|
-
const clickWorldY = (pointer.clientY - liveVpY) / liveZoom;
|
|
201
|
-
// 6. Get the clicked item's current World Position
|
|
202
|
-
const clickedPos = getItemPosition(itemId);
|
|
203
|
-
if (!clickedPos)
|
|
204
|
-
return;
|
|
205
|
-
// 7. Calculate the Offset in WORLD UNITS
|
|
206
|
-
// This is the distance from the mouse to the node's top-left in the infinite grid.
|
|
207
|
-
// This value remains constant even if you zoom during the drag.
|
|
208
|
-
const worldOffsetX = clickWorldX - clickedPos.x;
|
|
209
|
-
const worldOffsetY = clickWorldY - clickedPos.y;
|
|
210
|
-
// 8. Snapshot starting positions for all selected HTML nodes
|
|
211
|
-
const startPositions = new Map();
|
|
212
|
-
itemsToDrag.forEach((id) => {
|
|
213
|
-
const pos = getItemPosition(id);
|
|
214
|
-
if (pos)
|
|
215
|
-
startPositions.set(id, pos);
|
|
216
|
-
});
|
|
217
|
-
// 9. Snapshot starting positions for all selected Fabric objects
|
|
218
|
-
const canvasObjectsStartPos = new Map();
|
|
219
|
-
selectedCanvasObjects.forEach((obj) => {
|
|
220
|
-
canvasObjectsStartPos.set(obj, { left: obj.left || 0, top: obj.top || 0 });
|
|
141
|
+
return newSelected;
|
|
142
|
+
return prev;
|
|
221
143
|
});
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
document.body.style.userSelect = "none";
|
|
238
|
-
document.body.style.touchAction = "none";
|
|
239
|
-
};
|
|
240
|
-
// ── Drag move (HTML Node side) ───────────────────────────────────────────────
|
|
144
|
+
}, [selectionBox, localTasks, localDocuments, canvasZoom, canvasViewport]);
|
|
145
|
+
// ─── Global drag listeners — attached ONCE on mount ───────────────────────
|
|
146
|
+
//
|
|
147
|
+
// ROOT CAUSE OF THE POSITION JUMP — fixed here:
|
|
148
|
+
//
|
|
149
|
+
// Old pattern: useEffect(() => { mousemove }, [dragging, localTasks, localDocuments])
|
|
150
|
+
// Problem:
|
|
151
|
+
// 1. handleDragStart → setDragging() → React re-render
|
|
152
|
+
// 2. Re-render tears down mousemove listener, attaches new one
|
|
153
|
+
// 3. First real mousemove fires into old (dead) listener → ignored or wrong
|
|
154
|
+
// 4. New listener fires with potentially different startPositions → JUMP
|
|
155
|
+
//
|
|
156
|
+
// Fix: attach listeners ONCE. They read all mutable state via refs.
|
|
157
|
+
// Zero re-registration, zero double-fires, zero stale closure issues.
|
|
158
|
+
//
|
|
241
159
|
useEffect(() => {
|
|
242
|
-
if (!dragging)
|
|
243
|
-
return;
|
|
244
|
-
// Inside the useEffect that watches [dragging, localTasks, localDocuments, fabricCanvas]
|
|
245
160
|
const handleMove = (e) => {
|
|
246
161
|
if (!dragStateRef.current.isDragging)
|
|
247
162
|
return;
|
|
248
163
|
if (e.cancelable)
|
|
249
164
|
e.preventDefault();
|
|
250
|
-
const pointer =
|
|
251
|
-
|
|
165
|
+
const pointer = "touches" in e && e.touches.length > 0
|
|
166
|
+
? e.touches[0] : e;
|
|
252
167
|
if (rafIdRef.current !== null)
|
|
253
168
|
cancelAnimationFrame(rafIdRef.current);
|
|
254
169
|
rafIdRef.current = requestAnimationFrame(() => {
|
|
@@ -256,59 +171,50 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
256
171
|
const canvas = fabricCanvas?.current;
|
|
257
172
|
if (!canvas)
|
|
258
173
|
return;
|
|
259
|
-
//
|
|
174
|
+
// Live VPT — never from React state
|
|
260
175
|
const vpt = canvas.viewportTransform;
|
|
261
|
-
const liveZoom = vpt[0];
|
|
262
|
-
const liveVpX = vpt[4];
|
|
263
|
-
const liveVpY = vpt[5];
|
|
264
|
-
//
|
|
265
|
-
const
|
|
266
|
-
const
|
|
267
|
-
|
|
268
|
-
// (Current Mouse World - Initial World Offset from Start)
|
|
269
|
-
const newWorldX = currentWorldX - offsetX;
|
|
270
|
-
const newWorldY = currentWorldY - offsetY;
|
|
271
|
-
// 5. Calculate the Movement Delta in World Units
|
|
272
|
-
// We compare where the first item started vs where it is now.
|
|
273
|
-
const firstId = itemIds[0];
|
|
274
|
-
const firstStart = startPositions.get(firstId);
|
|
176
|
+
const liveZoom = vpt[0];
|
|
177
|
+
const liveVpX = vpt[4];
|
|
178
|
+
const liveVpY = vpt[5];
|
|
179
|
+
// Screen → World, subtract world-space offset
|
|
180
|
+
const newWorldX = (pointer.clientX - liveVpX) / liveZoom - offsetX;
|
|
181
|
+
const newWorldY = (pointer.clientY - liveVpY) / liveZoom - offsetY;
|
|
182
|
+
const firstStart = startPositions.get(itemIds[0]);
|
|
275
183
|
if (!firstStart)
|
|
276
184
|
return;
|
|
277
185
|
const deltaX = newWorldX - firstStart.x;
|
|
278
186
|
const deltaY = newWorldY - firstStart.y;
|
|
279
|
-
//
|
|
280
|
-
setLocalTasks((prev) => prev.map((t) => itemIds.includes(t.id)
|
|
281
|
-
...t,
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
} : d));
|
|
290
|
-
// 7. Sync Fabric Objects (Imperative update for performance)
|
|
187
|
+
// ── PERF: Only map over items being dragged ────────────────────────
|
|
188
|
+
setLocalTasks((prev) => prev.map((t) => itemIds.includes(t.id)
|
|
189
|
+
? { ...t, x: (startPositions.get(t.id)?.x ?? t.x) + deltaX,
|
|
190
|
+
y: (startPositions.get(t.id)?.y ?? t.y) + deltaY }
|
|
191
|
+
: t));
|
|
192
|
+
setLocalDocuments((prev) => prev.map((d) => itemIds.includes(d.id)
|
|
193
|
+
? { ...d, x: (startPositions.get(d.id)?.x ?? d.x) + deltaX,
|
|
194
|
+
y: (startPositions.get(d.id)?.y ?? d.y) + deltaY }
|
|
195
|
+
: d));
|
|
196
|
+
// Sync Fabric objects imperatively
|
|
291
197
|
canvasObjectsStartPos.forEach((startPos, obj) => {
|
|
292
|
-
obj.set({
|
|
293
|
-
|
|
294
|
-
top: startPos.top + deltaY,
|
|
295
|
-
});
|
|
296
|
-
obj.setCoords(); // Required for selection/intersection accuracy
|
|
198
|
+
obj.set({ left: startPos.left + deltaX, top: startPos.top + deltaY });
|
|
199
|
+
obj.setCoords();
|
|
297
200
|
});
|
|
298
|
-
// 8. Single render call for all Fabric changes
|
|
299
201
|
canvas.requestRenderAll();
|
|
300
202
|
});
|
|
301
203
|
};
|
|
302
204
|
const handleEnd = () => {
|
|
303
|
-
if (
|
|
205
|
+
if (!dragStateRef.current.isDragging)
|
|
206
|
+
return;
|
|
207
|
+
if (rafIdRef.current !== null) {
|
|
304
208
|
cancelAnimationFrame(rafIdRef.current);
|
|
209
|
+
rafIdRef.current = null;
|
|
210
|
+
}
|
|
305
211
|
dragStateRef.current.isDragging = false;
|
|
306
|
-
|
|
212
|
+
isHtmlDraggingRef.current = false;
|
|
307
213
|
document.body.style.cursor = "";
|
|
308
214
|
document.body.style.userSelect = "";
|
|
309
215
|
document.body.style.touchAction = "";
|
|
310
|
-
|
|
311
|
-
|
|
216
|
+
setLocalTasks((prev) => { onTasksUpdateRef.current?.(prev); return prev; });
|
|
217
|
+
setLocalDocuments((prev) => { onDocumentsUpdateRef.current?.(prev); return prev; });
|
|
312
218
|
};
|
|
313
219
|
window.addEventListener("mousemove", handleMove, { passive: false });
|
|
314
220
|
window.addEventListener("mouseup", handleEnd);
|
|
@@ -322,9 +228,62 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
322
228
|
window.removeEventListener("touchend", handleEnd);
|
|
323
229
|
window.removeEventListener("touchcancel", handleEnd);
|
|
324
230
|
};
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
231
|
+
// Empty deps — registered once, reads everything via refs
|
|
232
|
+
}, []); // eslint-disable-line react-hooks/exhaustive-deps
|
|
233
|
+
// ─── Drag start ───────────────────────────────────────────────────────────
|
|
234
|
+
const handleDragStart = useCallback((itemId, e) => {
|
|
235
|
+
const canvas = fabricCanvas?.current;
|
|
236
|
+
if (!canvas)
|
|
237
|
+
return;
|
|
238
|
+
if (e.cancelable)
|
|
239
|
+
e.preventDefault();
|
|
240
|
+
const pointer = "touches" in e && e.touches.length > 0
|
|
241
|
+
? e.touches[0] : e;
|
|
242
|
+
// Read from ref — not state (avoids async lag from setSelectedIds)
|
|
243
|
+
const currentSelected = selectedIdsRef.current;
|
|
244
|
+
const itemsToDrag = currentSelected.has(itemId)
|
|
245
|
+
? Array.from(currentSelected) : [itemId];
|
|
246
|
+
if (!currentSelected.has(itemId))
|
|
247
|
+
setSelectedIds(new Set([itemId]));
|
|
248
|
+
// Live VPT
|
|
249
|
+
const vpt = canvas.viewportTransform || [1, 0, 0, 1, 0, 0];
|
|
250
|
+
const liveZoom = vpt[0];
|
|
251
|
+
const liveVpX = vpt[4];
|
|
252
|
+
const liveVpY = vpt[5];
|
|
253
|
+
// Pointer → world
|
|
254
|
+
const pointerWorldX = (pointer.clientX - liveVpX) / liveZoom;
|
|
255
|
+
const pointerWorldY = (pointer.clientY - liveVpY) / liveZoom;
|
|
256
|
+
// nodePositionsRef is rebuilt synchronously every render — never stale
|
|
257
|
+
const clickedPos = nodePositionsRef.current.get(itemId);
|
|
258
|
+
if (!clickedPos)
|
|
259
|
+
return;
|
|
260
|
+
// Snapshot ALL start positions from ref synchronously
|
|
261
|
+
const startPositions = new Map();
|
|
262
|
+
for (const id of itemsToDrag) {
|
|
263
|
+
const pos = nodePositionsRef.current.get(id);
|
|
264
|
+
if (pos)
|
|
265
|
+
startPositions.set(id, { x: pos.x, y: pos.y });
|
|
266
|
+
}
|
|
267
|
+
const canvasObjectsStartPos = new Map();
|
|
268
|
+
for (const obj of selectedCanvasObjectsRef.current) {
|
|
269
|
+
canvasObjectsStartPos.set(obj, { left: obj.left || 0, top: obj.top || 0 });
|
|
270
|
+
}
|
|
271
|
+
dragStateRef.current = {
|
|
272
|
+
isDragging: true,
|
|
273
|
+
itemIds: itemsToDrag,
|
|
274
|
+
startPositions,
|
|
275
|
+
canvasObjectsStartPos,
|
|
276
|
+
// World-space offset: pointer distance from node top-left in world units
|
|
277
|
+
offsetX: pointerWorldX - clickedPos.x,
|
|
278
|
+
offsetY: pointerWorldY - clickedPos.y,
|
|
279
|
+
};
|
|
280
|
+
isHtmlDraggingRef.current = true;
|
|
281
|
+
document.body.style.cursor = "grabbing";
|
|
282
|
+
document.body.style.userSelect = "none";
|
|
283
|
+
document.body.style.touchAction = "none";
|
|
284
|
+
}, [fabricCanvas]);
|
|
285
|
+
// ─── Node interaction ─────────────────────────────────────────────────────
|
|
286
|
+
const handleSelect = useCallback((id, e) => {
|
|
328
287
|
if (e?.shiftKey || e?.ctrlKey || e?.metaKey) {
|
|
329
288
|
setSelectedIds((prev) => {
|
|
330
289
|
const next = new Set(prev);
|
|
@@ -335,68 +294,48 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
335
294
|
else {
|
|
336
295
|
setSelectedIds(new Set([id]));
|
|
337
296
|
}
|
|
338
|
-
};
|
|
339
|
-
const handleStatusChange = (taskId, newStatus) => {
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
297
|
+
}, []);
|
|
298
|
+
const handleStatusChange = useCallback((taskId, newStatus) => {
|
|
299
|
+
setLocalTasks((prev) => {
|
|
300
|
+
const updated = prev.map((t) => t.id === taskId ? { ...t, status: newStatus } : t);
|
|
301
|
+
onTasksUpdateRef.current?.(updated);
|
|
302
|
+
return updated;
|
|
303
|
+
});
|
|
304
|
+
}, []);
|
|
305
|
+
// ─── Keyboard shortcuts ───────────────────────────────────────────────────
|
|
344
306
|
useEffect(() => {
|
|
345
307
|
const handleKeyDown = (e) => {
|
|
346
|
-
// Don't trigger if typing in input
|
|
347
308
|
if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
|
|
348
309
|
return;
|
|
349
|
-
// Select All
|
|
350
310
|
if ((e.ctrlKey || e.metaKey) && e.key === "a") {
|
|
351
311
|
e.preventDefault();
|
|
352
312
|
setSelectedIds(new Set([...localTasks.map((t) => t.id), ...localDocuments.map((d) => d.id)]));
|
|
353
313
|
}
|
|
354
|
-
|
|
355
|
-
if (e.key === "Escape") {
|
|
314
|
+
if (e.key === "Escape")
|
|
356
315
|
setSelectedIds(new Set());
|
|
357
|
-
|
|
358
|
-
// ← ADD THIS: Delete selected nodes
|
|
359
|
-
if ((e.key === "Delete" || e.key === "Backspace") && selectedIds.size > 0) {
|
|
316
|
+
if ((e.key === "Delete" || e.key === "Backspace") && selectedIdsRef.current.size > 0) {
|
|
360
317
|
e.preventDefault();
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
setLocalDocuments(updatedDocs);
|
|
318
|
+
const ids = selectedIdsRef.current;
|
|
319
|
+
setLocalTasks((prev) => { const u = prev.filter((t) => !ids.has(t.id)); onTasksUpdateRef.current?.(u); return u; });
|
|
320
|
+
setLocalDocuments((prev) => { const u = prev.filter((d) => !ids.has(d.id)); onDocumentsUpdateRef.current?.(u); return u; });
|
|
365
321
|
setSelectedIds(new Set());
|
|
366
|
-
onTasksUpdate?.(updatedTasks);
|
|
367
|
-
onDocumentsUpdate?.(updatedDocs);
|
|
368
322
|
}
|
|
369
323
|
};
|
|
370
324
|
window.addEventListener("keydown", handleKeyDown);
|
|
371
325
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
372
|
-
}, [localTasks, localDocuments
|
|
373
|
-
//
|
|
374
|
-
const renderItem = (id, x, y, children) => {
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
// 2. Use translate3d for GPU performance
|
|
385
|
-
transform: `translate3d(${screenX}px, ${screenY}px, 0) scale(${canvasZoom})`,
|
|
386
|
-
transformOrigin: "top left",
|
|
387
|
-
// 3. THE FIX: Remove transition entirely during any viewport change
|
|
388
|
-
// Any 'ease' during zoom causes the "shaking" behavior.
|
|
389
|
-
transition: "none",
|
|
390
|
-
// 4. Optimization
|
|
391
|
-
willChange: "transform",
|
|
392
|
-
zIndex: isDragging ? 1000 : 1,
|
|
393
|
-
}, children: children }, id));
|
|
394
|
-
};
|
|
395
|
-
return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
|
|
396
|
-
if (e.target === e.currentTarget)
|
|
397
|
-
setSelectedIds(new Set());
|
|
398
|
-
}, children: _jsxs("div", { className: "absolute top-0 left-0 pointer-events-none", style: {
|
|
326
|
+
}, [localTasks, localDocuments]);
|
|
327
|
+
// ─── Render ───────────────────────────────────────────────────────────────
|
|
328
|
+
const renderItem = (id, x, y, children) => (_jsx("div", { className: "pointer-events-auto absolute", style: {
|
|
329
|
+
left: 0, top: 0,
|
|
330
|
+
transform: `translate3d(${x * canvasZoom}px, ${y * canvasZoom}px, 0) scale(${canvasZoom})`,
|
|
331
|
+
transformOrigin: "top left",
|
|
332
|
+
transition: "none", // No CSS transitions — causes shaking during zoom
|
|
333
|
+
willChange: "transform", // GPU layer hint
|
|
334
|
+
zIndex: dragStateRef.current.itemIds.includes(id) ? 1000 : 1,
|
|
335
|
+
}, children: children }, id));
|
|
336
|
+
return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onClick: (e) => { if (e.target === e.currentTarget)
|
|
337
|
+
setSelectedIds(new Set()); }, children: _jsxs("div", { className: "absolute top-0 left-0 pointer-events-none", style: {
|
|
399
338
|
transform: `translate(${canvasViewport.x}px, ${canvasViewport.y}px)`,
|
|
400
339
|
transformOrigin: "top left",
|
|
401
|
-
}, children: [localTasks.map((task) => renderItem(task.id, task.x, task.y, _jsx(
|
|
340
|
+
}, children: [localTasks.map((task) => renderItem(task.id, task.x, task.y, _jsx(MemoTaskNode, { ...task, isSelected: selectedIds.has(task.id), onSelect: handleSelect, onDragStart: handleDragStart, onStatusChange: handleStatusChange, zoom: 1 }))), localDocuments.map((doc) => renderItem(doc.id, doc.x, doc.y, _jsx(MemoDocumentNode, { ...doc, isSelected: selectedIds.has(doc.id), onSelect: handleSelect, onDragStart: handleDragStart })))] }) }));
|
|
402
341
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"task-dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/task-dropdown.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"task-dropdown.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/task-dropdown.tsx"],"names":[],"mappings":"AAUA,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACxC,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,UAAU,iBAAiB;IACzB,SAAS,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;CACzC;AA2DD,MAAM,CAAC,OAAO,UAAU,YAAY,CAAC,EAAE,SAAS,EAAE,EAAE,iBAAiB,2CAkGpE"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tooloptions-panel.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/tooloptions-panel.tsx"],"names":[],"mappings":"AAGA,OAAc,EAAE,SAAS,EAAgC,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"tooloptions-panel.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/tooloptions-panel.tsx"],"names":[],"mappings":"AAGA,OAAc,EAAE,SAAS,EAAgC,MAAM,OAAO,CAAC;AAUvE,OAAO,MAA2C,MAAM,QAAQ,CAAC;AAGjE,UAAU,qBAAqB;IAC7B,YAAY,EAAE,SAAS,CAAC,MAAM,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;CAC/C;AAED,MAAM,CAAC,OAAO,UAAU,gBAAgB,CAAC,EACvC,YAAY,GACb,EAAE,qBAAqB,2CAuMvB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"whiteboard-toolbar.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/whiteboard-toolbar.tsx"],"names":[],"mappings":"AAEA,OAAa,EAAqB,gBAAgB,EAAY,MAAM,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"whiteboard-toolbar.d.ts","sourceRoot":"","sources":["../../../src/components/toolbar/whiteboard-toolbar.tsx"],"names":[],"mappings":"AAEA,OAAa,EAAqB,gBAAgB,EAAY,MAAM,OAAO,CAAC;AAK5E,OAAO,EAAE,MAAM,EAAQ,MAAM,QAAQ,CAAC;AAOtC,UAAU,YAAY;IACpB,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,GAAG,aAAa,GAAG,MAAM,CAAC;IACnE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,KAAK,GAAG,QAAQ,GAAG,MAAM,CAAC;IAAC,OAAO,CAAC,EAAE,MAAM,CAAC;CAC7F;AACD,UAAU,gBAAgB;IACxB,EAAE,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAC3C,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAAC,OAAO,EAAE,MAAM,CAAC;IAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC5D;AAkBD,UAAU,sBAAsB;IAC9B,YAAY,EAAE,gBAAgB,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9C,cAAc,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC;IAC1C,SAAS,CAAC,EAAE,CAAC,IAAI,EAAE,YAAY,KAAK,IAAI,CAAC;IACzC,aAAa,CAAC,EAAE,CAAC,GAAG,EAAE,gBAAgB,KAAK,IAAI,CAAC;CACjD;AAED,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,EAAE,YAAY,EAAE,cAAc,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,sBAAsB,2CAiM3H"}
|
|
@@ -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;AAEhC,UAAU,kBAAkB;IAC1B,SAAS,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC/C,eAAe,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,cAAc,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CACrC;AAKD,eAAO,MAAM,aAAa,GAAI,sHAS3B,kBAAkB,
|
|
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;AAEhC,UAAU,kBAAkB;IAC1B,SAAS,EAAE,SAAS,CAAC,iBAAiB,GAAG,IAAI,CAAC,CAAC;IAC/C,eAAe,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC1C,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,cAAc,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACnC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAErC,QAAQ,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;IACjC,YAAY,EAAE,CAAC,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAC;CACrC;AAKD,eAAO,MAAM,aAAa,GAAI,sHAS3B,kBAAkB,SA0FpB,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useDrawing.d.ts","sourceRoot":"","sources":["../../src/hooks/useDrawing.ts"],"names":[],"mappings":"AACA,
|
|
1
|
+
{"version":3,"file":"useDrawing.d.ts","sourceRoot":"","sources":["../../src/hooks/useDrawing.ts"],"names":[],"mappings":"AACA,OAAO,EAAqB,SAAS,EAAE,MAAM,OAAO,CAAC;AACrD,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,iBAAiB,EAAsB,MAAM,QAAQ,CAAC;AAKrF,UAAU,eAAe;IACvB,YAAY,EAAE,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IACvC,UAAU,EAAE,MAAM,CAAC;IACnB,WAAW,EAAE,GAAG,CAAC;IACjB,YAAY,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACjC,aAAa,EAAE,SAAS,CAAC;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,CAAC,CAAC;IAC1D,eAAe,EAAE,SAAS,CAAC,YAAY,GAAG,IAAI,CAAC,CAAC;IAChD,kBAAkB,EAAE,SAAS,CAAC,OAAO,CAAC,CAAC;IACvC,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACrC,eAAe,EAAE,CAAC,GAAG,EAAE,YAAY,KAAK,IAAI,CAAC;CAC9C;AAED,eAAO,MAAM,UAAU,GAAI,4IAUxB,eAAe;2BACc,iBAAiB;2BAsHjB,iBAAiB;;CA8ChD,CAAC"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,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
|
@@ -1,30 +1,2 @@
|
|
|
1
|
-
// export {default as EasyflowWhiteboard} from "./components/whiteboard/whiteboard-test";
|
|
2
|
-
// export * from "./hooks/useCanvasInit";
|
|
3
|
-
// export * from "./hooks/useDrawing";
|
|
4
|
-
// export * from "./hooks/useEraser";
|
|
5
|
-
// export * from "./hooks/usePan";
|
|
6
|
-
// export * from "./hooks/useZoom";
|
|
7
|
-
// export * from "./hooks/useSelection";
|
|
8
|
-
// export * from "./hooks/useLiveUpdate";
|
|
9
|
-
// export * from "./hooks/useMouseHandlers";
|
|
10
|
-
// export * from "./hooks/usePersistance";
|
|
11
|
-
// export * from "./hooks/useToolManager";
|
|
12
|
-
// export * from "./hooks/useTextStyle";
|
|
13
|
-
// export * from "./lib/fabric-frame";
|
|
14
|
-
// export * from "./lib/fabric-arrow";
|
|
15
|
-
// export * from "./lib/fabric-bidirectional-arrow";
|
|
16
|
-
// export * from "./lib/fabric-utils";
|
|
17
|
-
// export * from "./lib/utils";
|
|
18
|
-
// export * from "./store/whiteboard-store";
|
|
19
|
-
// export * from "./components/toolbar/whiteboard-toolbar";
|
|
20
|
-
// export * from "./components/toolbar/tooloptions-panel";
|
|
21
|
-
// export * from "./components/node/custom-node-overlay-layer";
|
|
22
|
-
// export * from "./components/zoomcontrol/zoom-control";
|
|
23
|
-
// export * from "./components/whiteboard/whiteboard-test";
|
|
24
|
-
// export * from "./components/node/document-node";
|
|
25
|
-
// export * from "./components/node/custom-node";
|
|
26
|
-
// export * from "./components/toolbar/document-dropdown";
|
|
27
|
-
// export * from "./components/toolbar/task-dropdown";
|
|
28
|
-
// export * from "./components/toolbar/document-dropdown";
|
|
29
1
|
export { default as EasyflowWhiteboard } from "./components/whiteboard/whiteboard-test";
|
|
30
2
|
export { useWhiteboardStore } from './store/whiteboard-store';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fabric-utils.d.ts","sourceRoot":"","sources":["../../src/lib/fabric-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"fabric-utils.d.ts","sourceRoot":"","sources":["../../src/lib/fabric-utils.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,YAAY,EAAwE,WAAW,EAAc,MAAM,QAAQ,CAAC;AAK7I,eAAO,MAAM,sBAAsB,GAAI,QAAQ,MAAM,WAkBpD,CAAC;AAQF,eAAO,MAAM,mBAAmB,GAC9B,OAAO,YAAY,EACnB,UAAU,MAAM,EAChB,YAAY;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,EACpC,cAAc;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,SAwEvC,CAAC;AAKF,eAAO,MAAM,qBAAqB,GAAI,QAAQ,MAAM,SASnD,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,SAEhD,CAAC;AAGF,eAAO,MAAM,oBAAoB,GAC/B,QAAQ,MAAM,EACd,MAAM,MAAM,EACZ,WAAW,MAAM,IAAI,SAMtB,CAAC;AAGF,eAAO,MAAM,mBAAmB,GAC9B,QAAQ,MAAM,EACd,SAAQ,KAAK,GAAG,MAAc,WAO/B,CAAC;AAUF,eAAO,MAAM,kBAAkB,GAC7B,iBAAiB,MAAM,EAAE,GAAG,IAAI,EAChC,aAAa,MAAM,KAClB,MAAM,EAAE,GAAG,SAKb,CAAC;AAKF,eAAO,MAAM,OAAO,GAClB,QAAQ,MAAM,EACd,SAAS;IACP,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,CAAC,CAAC,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB,SAmBF,CAAC;AAEF,eAAO,MAAM,gBAAgB,GAAU,QAAQ,MAAM,EAAE,KAAK,MAAM,iJAuCjE,CAAC;AAGF,eAAO,MAAM,WAAW,GAAI,QAAQ,MAAM,SAIzC,CAAC;AAGF,eAAO,MAAM,UAAU,GAAI,QAAQ,MAAM,EAAE,WAAW,MAAM,SAG3D,CAAC;AAGF,eAAO,MAAM,kBAAkB,GAAI,QAAQ,MAAM,SAoBhD,CAAC;AAIF,eAAO,MAAM,iBAAiB,GAAU,QAAQ,MAAM,EAAE,SAAS,MAAM,kBAoFtE,CAAC"}
|
package/dist/lib/fabric-utils.js
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
|
-
import { FabricObject, Line, Group, IText, PencilBrush, FabricImage, util } from "fabric";
|
|
2
|
-
import { Text } from "fabric";
|
|
1
|
+
import { FabricObject, Text, Line, Group, IText, PencilBrush, FabricImage, util } from "fabric";
|
|
3
2
|
// Initialize canvas with default settings
|
|
4
3
|
export const initializeFabricCanvas = (canvas) => {
|
|
5
4
|
// Set default object properties
|