@mhamz.01/easyflow-whiteboard 1.17.0 → 1.18.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.
@@ -38,6 +38,8 @@ interface CanvasOverlayLayerProps {
38
38
  } | null;
39
39
  selectedCanvasObjects?: FabricObject[];
40
40
  fabricCanvas?: React.RefObject<Canvas | null>;
41
+ selectedIds: Set<string>;
42
+ setSelectedIds: React.Dispatch<React.SetStateAction<Set<string>>>;
41
43
  }
42
44
  export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, onDocumentsUpdate, canvasZoom, canvasViewport, selectionBox, selectedCanvasObjects, fabricCanvas, }: CanvasOverlayLayerProps): import("react/jsx-runtime").JSX.Element;
43
45
  export {};
@@ -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,2CAkezB"}
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;IAC9C,WAAW,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACzB,cAAc,EAAE,KAAK,CAAC,QAAQ,CAAC,KAAK,CAAC,cAAc,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;CACnE;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,2CAgfzB"}
@@ -128,42 +128,35 @@ 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 = (itemX, itemY, itemWidth, itemHeight, box) => {
132
- const canvas = fabricCanvas?.current;
133
- if (!canvas)
131
+ const isItemInSelectionBox = (x, y, width, height, box) => {
132
+ // Get overlay element offset (recalculate every time for sidebar changes)
133
+ const overlayRect = overlayRef.current?.getBoundingClientRect();
134
+ if (!overlayRect)
134
135
  return false;
135
- // Get the offset of the actual canvas element within the consumer's page
136
- const rect = canvas.getElement().getBoundingClientRect();
137
- // Adjust screen coordinates to be relative to the canvas element
138
- const boxSceneX1 = (box.x1 - rect.left - canvasViewport.x) / canvasZoom;
139
- const boxSceneY1 = (box.y1 - rect.top - canvasViewport.y) / canvasZoom;
140
- const boxSceneX2 = (box.x2 - rect.left - canvasViewport.x) / canvasZoom;
141
- const boxSceneY2 = (box.y2 - rect.top - canvasViewport.y) / canvasZoom;
142
- const bX1 = Math.min(boxSceneX1, boxSceneX2);
143
- const bY1 = Math.min(boxSceneY1, boxSceneY2);
144
- const bX2 = Math.max(boxSceneX1, boxSceneX2);
145
- const bY2 = Math.max(boxSceneY1, boxSceneY2);
146
- return !(itemX + itemWidth < bX1 ||
147
- itemX > bX2 ||
148
- itemY + itemHeight < bY1 ||
149
- itemY > bY2);
136
+ // Item position in screen space (relative to whiteboard)
137
+ const itemX1 = x * canvasZoom + canvasViewport.x;
138
+ const itemY1 = y * canvasZoom + canvasViewport.y;
139
+ const itemX2 = itemX1 + width * canvasZoom;
140
+ const itemY2 = itemY1 + height * canvasZoom;
141
+ // Selection box adjusted for overlay offset from viewport
142
+ const boxX1 = Math.min(box.x1, box.x2) - overlayRect.left;
143
+ const boxY1 = Math.min(box.y1, box.y2) - overlayRect.top;
144
+ const boxX2 = Math.max(box.x1, box.x2) - overlayRect.left;
145
+ const boxY2 = Math.max(box.y1, box.y2) - overlayRect.top;
146
+ return !(boxX2 < itemX1 || boxX1 > itemX2 || boxY2 < itemY1 || boxY1 > itemY2);
150
147
  };
151
148
  // ── Selection box detection ──────────────────────────────────────────────────
152
149
  useEffect(() => {
153
150
  if (!selectionBox)
154
151
  return;
155
152
  const newSelected = new Set();
156
- // Use standard widths for your nodes if they are fixed,
157
- // or pass their actual dimensions if dynamic.
158
153
  localTasks.forEach((task) => {
159
- if (isItemInSelectionBox(task.x, task.y, 300, 140, selectionBox)) {
154
+ if (isItemInSelectionBox(task.x, task.y, 300, 140, selectionBox))
160
155
  newSelected.add(task.id);
161
- }
162
156
  });
163
157
  localDocuments.forEach((doc) => {
164
- if (isItemInSelectionBox(doc.x, doc.y, 300, 160, selectionBox)) {
158
+ if (isItemInSelectionBox(doc.x, doc.y, 300, 160, selectionBox))
165
159
  newSelected.add(doc.id);
166
- }
167
160
  });
168
161
  setSelectedIds(newSelected);
169
162
  }, [selectionBox, localTasks, localDocuments, canvasZoom, canvasViewport]);
@@ -216,6 +209,28 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
216
209
  // Prevents mobile pull-to-refresh
217
210
  document.body.style.touchAction = "none";
218
211
  };
212
+ // Add this useEffect in CanvasOverlayLayer
213
+ useEffect(() => {
214
+ const canvas = fabricCanvas?.current;
215
+ if (!canvas)
216
+ return;
217
+ const handleCanvasClick = (e) => {
218
+ // Clear custom node selection when clicking empty canvas
219
+ if (!e.target) {
220
+ setSelectedIds(new Set());
221
+ }
222
+ };
223
+ const handleSelectionCleared = () => {
224
+ // Clear custom nodes when Fabric selection is cleared
225
+ setSelectedIds(new Set());
226
+ };
227
+ canvas.on("mouse:down", handleCanvasClick);
228
+ canvas.on("selection:cleared", handleSelectionCleared);
229
+ return () => {
230
+ canvas.off("mouse:down", handleCanvasClick);
231
+ canvas.off("selection:cleared", handleSelectionCleared);
232
+ };
233
+ }, [fabricCanvas, setSelectedIds]);
219
234
  // ── Drag move (HTML Node side) ───────────────────────────────────────────────
220
235
  useEffect(() => {
221
236
  if (!dragging)
@@ -356,11 +371,11 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
356
371
  zIndex: isDragging ? 1000 : 1,
357
372
  }, children: children }, id));
358
373
  };
359
- return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none overflow-hidden", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
374
+ return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
360
375
  if (e.target === e.currentTarget)
361
376
  setSelectedIds(new Set());
362
377
  }, children: _jsxs("div", { className: "absolute top-0 left-0 pointer-events-none", style: {
363
- transform: `translate3d(${canvasViewport.x}px, ${canvasViewport.y}px, 0)`,
364
- willChange: "transform",
378
+ transform: `translate(${canvasViewport.x}px, ${canvasViewport.y}px)`,
379
+ transformOrigin: "top left",
365
380
  }, children: [localTasks.map((task) => renderItem(task.id, task.x, task.y, _jsx(TaskNode, { ...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(DocumentNode, { ...doc, isSelected: selectedIds.has(doc.id), onSelect: handleSelect, onDragStart: handleDragStart })))] }) }));
366
381
  }
@@ -1 +1 @@
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
+ {"version":3,"file":"whiteboard-test.d.ts","sourceRoot":"","sources":["../../../src/components/whiteboard/whiteboard-test.tsx"],"names":[],"mappings":"AA4CA,MAAM,CAAC,OAAO,UAAU,gBAAgB,4CAuQvC"}
@@ -37,6 +37,7 @@ export default function FabricWhiteboard() {
37
37
  const eraserActiveRef = useRef(false);
38
38
  const eraserPathRef = useRef(null);
39
39
  const eraserPathPointsRef = useRef([]);
40
+ const [selectedIds, setSelectedIds] = useState(new Set());
40
41
  // Store
41
42
  const activeTool = useWhiteboardStore((state) => state.activeTool);
42
43
  const toolOptions = useWhiteboardStore((state) => state.toolOptions);
@@ -203,5 +204,5 @@ export default function FabricWhiteboard() {
203
204
  backgroundImage: `radial-gradient(circle, rgba(255,255,255,0.2) 1.2px, transparent 1.2px)`,
204
205
  backgroundSize: "40px 40px",
205
206
  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
+ } }), _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, selectedIds: selectedIds, setSelectedIds: setSelectedIds }), _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
208
  }
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"useSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAQ,YAAY,EAAe,MAAM,QAAQ,CAAC;AAMjE,UAAU,iBAAiB;IACzB,YAAY,EAAE,KAAK,CAAC,SAAS,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC7C,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE;QAAE,CAAC,EAAE,MAAM,CAAC;QAAC,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,eAAe,EAAE,CAAC,GAAG,EAAE;QAAE,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAC;QAAC,EAAE,EAAE,MAAM,CAAA;KAAE,GAAG,IAAI,KAAK,IAAI,CAAC;IAC1F,wBAAwB,EAAE,CAAC,OAAO,EAAE,YAAY,EAAE,KAAK,IAAI,CAAC;IAC5D,YAAY,EAAE,KAAK,CAAC,gBAAgB,CAAC,OAAO,CAAC,CAAC;CAC/C;AAED,eAAO,MAAM,YAAY,GAAI,oHAQ1B,iBAAiB,SA6JnB,CAAC"}
@@ -17,13 +17,7 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
17
17
  let selRect = null;
18
18
  let rafId = null;
19
19
  const onDown = (e) => {
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)
20
+ if (activeTool !== "select" || e.target)
27
21
  return;
28
22
  isSelecting = true;
29
23
  const p = canvas.getScenePoint(e.e);
@@ -33,12 +27,12 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
33
27
  top: p.y,
34
28
  width: 0,
35
29
  height: 0,
36
- fill: "rgba(0, 120, 255, 0.1)", // Slight tint helps debugging
37
- stroke: "rgba(0, 120, 255, 0.5)",
38
- strokeWidth: 1,
30
+ fill: "transparent",
31
+ stroke: "transparent",
32
+ strokeWidth: 0,
39
33
  selectable: false,
40
34
  evented: false,
41
- visible: false, // Keep invisible, we use the React Overlay for UI
35
+ visible: false,
42
36
  });
43
37
  canvas.add(selRect);
44
38
  canvas.renderAll();
@@ -52,21 +46,22 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
52
46
  const p = canvas.getScenePoint(e.e);
53
47
  const w = p.x - selStart.x;
54
48
  const h = p.y - selStart.y;
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 });
49
+ selRect.set({
50
+ left: w < 0 ? p.x : selStart.x,
51
+ top: h < 0 ? p.y : selStart.y,
52
+ width: Math.abs(w),
53
+ height: Math.abs(h),
54
+ });
60
55
  selRect.setCoords();
61
56
  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
+ // ← FIX: Add canvas element offset
58
+ const canvasElement = canvas.getElement();
59
+ const rect = canvasElement.getBoundingClientRect();
65
60
  setSelectionBox({
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,
61
+ x1: Math.min(selStart.x, p.x) * canvasZoom + canvasViewport.x + rect.left,
62
+ y1: Math.min(selStart.y, p.y) * canvasZoom + canvasViewport.y + rect.top,
63
+ x2: Math.max(selStart.x, p.x) * canvasZoom + canvasViewport.x + rect.left,
64
+ y2: Math.max(selStart.y, p.y) * canvasZoom + canvasViewport.y + rect.top,
70
65
  });
71
66
  });
72
67
  };
@@ -81,54 +76,35 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
81
76
  canvas.renderAll();
82
77
  isSelecting = false;
83
78
  selRect = null;
84
- // Delay clearing the box slightly to allow intersection logic to finish
85
- setTimeout(() => setSelectionBox(null), 50);
79
+ setTimeout(() => setSelectionBox(null), 100);
86
80
  };
87
81
  const onSelected = () => {
88
82
  const sel = canvas.getActiveObject();
89
83
  if (!sel || isDrawingRef.current)
90
84
  return;
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);
85
+ setSelectedCanvasObjects(sel.type === "activeSelection" ? sel.getObjects() : [sel]);
100
86
  const typeMap = {
101
87
  rect: "rectangle",
102
88
  circle: "circle",
103
89
  line: "line",
90
+ arrow: "arrow",
91
+ "bidirectional-arrow": "arrow",
104
92
  "i-text": "text",
105
93
  text: "text",
106
94
  path: "pen",
107
95
  image: "image",
108
96
  };
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";
97
+ const t = sel instanceof Frame
98
+ ? "frame"
99
+ : sel instanceof FabricImage
100
+ ? "image"
101
+ : sel instanceof Arrow
102
+ ? "arrow"
103
+ : sel instanceof BidirectionalArrow
104
+ ? "arrow"
105
+ : typeMap[sel.type] ?? null;
118
106
  setSelectedObjectType(t);
119
107
  };
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
- };
132
108
  const onDeselected = () => {
133
109
  setSelectedObjectType(null);
134
110
  setSelectionBox(null);
@@ -137,11 +113,9 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
137
113
  setActiveTool("select");
138
114
  }
139
115
  };
140
- // Event Binding
141
116
  canvas.on("selection:created", onSelected);
142
117
  canvas.on("selection:updated", onSelected);
143
118
  canvas.on("selection:cleared", onDeselected);
144
- canvas.on("object:moving", onObjectMoving);
145
119
  canvas.on("mouse:down", onDown);
146
120
  canvas.on("mouse:move", onMove);
147
121
  canvas.on("mouse:up", onUp);
@@ -149,7 +123,6 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
149
123
  canvas.off("selection:created", onSelected);
150
124
  canvas.off("selection:updated", onSelected);
151
125
  canvas.off("selection:cleared", onDeselected);
152
- canvas.off("object:moving", onObjectMoving);
153
126
  canvas.off("mouse:down", onDown);
154
127
  canvas.off("mouse:move", onMove);
155
128
  canvas.off("mouse:up", onUp);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "1.17.0",
3
+ "version": "1.18.0",
4
4
  "description": "A feature-rich whiteboard component built with Fabric.js and React",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",