@mhamz.01/easyflow-whiteboard 1.14.0 → 1.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"file":"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,2CAsdzB"}
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"}
@@ -128,36 +128,42 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
128
128
  return { x: doc.x, y: doc.y };
129
129
  return undefined;
130
130
  };
131
- // In CanvasOverlayLayer, update isItemInSelectionBox to recalculate offset
132
- const isItemInSelectionBox = (x, y, width, height, box) => {
133
- // Get FRESH overlay offset (handles sidebar open/close)
134
- const overlayRect = overlayRef.current?.getBoundingClientRect();
135
- if (!overlayRect)
131
+ const isItemInSelectionBox = (itemX, itemY, itemWidth, itemHeight, box) => {
132
+ const canvas = fabricCanvas?.current;
133
+ if (!canvas)
136
134
  return false;
137
- // Item position in screen space (relative to whiteboard container)
138
- const itemX1 = x * canvasZoom + canvasViewport.x;
139
- const itemY1 = y * canvasZoom + canvasViewport.y;
140
- const itemX2 = itemX1 + width * canvasZoom;
141
- const itemY2 = itemY1 + height * canvasZoom;
142
- // Selection box adjusted for overlay offset
143
- const boxX1 = Math.min(box.x1, box.x2) - overlayRect.left;
144
- const boxY1 = Math.min(box.y1, box.y2) - overlayRect.top;
145
- const boxX2 = Math.max(box.x1, box.x2) - overlayRect.left;
146
- const boxY2 = Math.max(box.y1, box.y2) - overlayRect.top;
147
- return !(boxX2 < itemX1 || boxX1 > itemX2 || boxY2 < itemY1 || boxY1 > itemY2);
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);
148
150
  };
149
151
  // ── Selection box detection ──────────────────────────────────────────────────
150
152
  useEffect(() => {
151
153
  if (!selectionBox)
152
154
  return;
153
155
  const newSelected = new Set();
156
+ // Use standard widths for your nodes if they are fixed,
157
+ // or pass their actual dimensions if dynamic.
154
158
  localTasks.forEach((task) => {
155
- if (isItemInSelectionBox(task.x, task.y, 300, 140, selectionBox))
159
+ if (isItemInSelectionBox(task.x, task.y, 300, 140, selectionBox)) {
156
160
  newSelected.add(task.id);
161
+ }
157
162
  });
158
163
  localDocuments.forEach((doc) => {
159
- if (isItemInSelectionBox(doc.x, doc.y, 300, 160, selectionBox))
164
+ if (isItemInSelectionBox(doc.x, doc.y, 300, 160, selectionBox)) {
160
165
  newSelected.add(doc.id);
166
+ }
161
167
  });
162
168
  setSelectedIds(newSelected);
163
169
  }, [selectionBox, localTasks, localDocuments, canvasZoom, canvasViewport]);
@@ -350,11 +356,11 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
350
356
  zIndex: isDragging ? 1000 : 1,
351
357
  }, children: children }, id));
352
358
  };
353
- return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
359
+ return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none overflow-hidden", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
354
360
  if (e.target === e.currentTarget)
355
361
  setSelectedIds(new Set());
356
362
  }, children: _jsxs("div", { className: "absolute top-0 left-0 pointer-events-none", style: {
357
- transform: `translate(${canvasViewport.x}px, ${canvasViewport.y}px)`,
358
- transformOrigin: "top left",
363
+ transform: `translate3d(${canvasViewport.x}px, ${canvasViewport.y}px, 0)`,
364
+ willChange: "transform",
359
365
  }, 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 })))] }) }));
360
366
  }
@@ -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,4CAqQvC"}
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"}
@@ -134,7 +134,6 @@ export default function FabricWhiteboard() {
134
134
  setSelectionBox,
135
135
  setSelectedCanvasObjects,
136
136
  isDrawingRef,
137
- clearCustomNodeSelection: () => setSelectedIds(new Set()), // ← ADD THIS
138
137
  });
139
138
  // Text style updates
140
139
  useTextStyle({
@@ -206,6 +205,3 @@ export default function FabricWhiteboard() {
206
205
  zIndex: 0,
207
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 }) })] })] }) }));
208
207
  }
209
- function setSelectedIds(arg0) {
210
- throw new Error("Function not implemented.");
211
- }
@@ -15,8 +15,7 @@ interface UseSelectionProps {
15
15
  } | null) => void;
16
16
  setSelectedCanvasObjects: (objects: FabricObject[]) => void;
17
17
  isDrawingRef: React.MutableRefObject<boolean>;
18
- clearCustomNodeSelection?: () => void;
19
18
  }
20
- export declare const useSelection: ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, clearCustomNodeSelection, }: UseSelectionProps) => void;
19
+ export declare const useSelection: ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, }: UseSelectionProps) => void;
21
20
  export {};
22
21
  //# sourceMappingURL=useSelection.d.ts.map
@@ -1 +1 @@
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;IAC9C,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,YAAY,GAAI,8IAS1B,iBAAiB,SA2KnB,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,SAsKnB,CAAC"}
@@ -5,8 +5,7 @@ import { Frame } from "../lib/fabric-frame";
5
5
  import { Arrow } from "../lib/fabric-arrow";
6
6
  import { BidirectionalArrow } from "../lib/fabric-bidirectional-arrow";
7
7
  import { useWhiteboardStore } from "../store/whiteboard-store";
8
- export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, clearCustomNodeSelection, // ← Add this
9
- }) => {
8
+ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, }) => {
10
9
  const setSelectedObjectType = useWhiteboardStore((state) => state.setSelectedObjectType);
11
10
  const setActiveTool = useWhiteboardStore((state) => state.setActiveTool);
12
11
  useEffect(() => {
@@ -55,14 +54,11 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
55
54
  });
56
55
  selRect.setCoords();
57
56
  canvas.renderAll();
58
- // Get FRESH canvas offset on every move (handles sidebar open/close)
59
- const canvasElement = canvas.getElement();
60
- const rect = canvasElement.getBoundingClientRect();
61
57
  setSelectionBox({
62
- x1: Math.min(selStart.x, p.x) * canvasZoom + canvasViewport.x + rect.left,
63
- y1: Math.min(selStart.y, p.y) * canvasZoom + canvasViewport.y + rect.top,
64
- x2: Math.max(selStart.x, p.x) * canvasZoom + canvasViewport.x + rect.left,
65
- y2: Math.max(selStart.y, p.y) * canvasZoom + canvasViewport.y + rect.top,
58
+ x1: Math.min(selStart.x, p.x) * canvasZoom + canvasViewport.x,
59
+ y1: Math.min(selStart.y, p.y) * canvasZoom + canvasViewport.y,
60
+ x2: Math.max(selStart.x, p.x) * canvasZoom + canvasViewport.x,
61
+ y2: Math.max(selStart.y, p.y) * canvasZoom + canvasViewport.y,
66
62
  });
67
63
  });
68
64
  };
@@ -110,25 +106,24 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
110
106
  setSelectedObjectType(null);
111
107
  setSelectionBox(null);
112
108
  setSelectedCanvasObjects([]);
113
- // ← ADD: Clear custom node selection too
114
- clearCustomNodeSelection?.();
115
109
  if (!isDrawingRef.current && activeTool !== "select" && activeTool !== "pan") {
116
110
  setActiveTool("select");
117
111
  }
118
112
  };
119
- // ← ADD: Clear custom nodes when clicking empty canvas
120
113
  const handleCanvasClick = (e) => {
121
- if (!e.target && activeTool === "select") {
122
- clearCustomNodeSelection?.();
114
+ // If user clicks the canvas background (not an object), clear overlay selection
115
+ if (!e.target) {
116
+ // You should pass a setter to clear selected IDs in your overlay
117
+ // setOverlaySelectedIds(new Set());
123
118
  }
124
119
  };
120
+ canvas.on("mouse:down", handleCanvasClick);
125
121
  canvas.on("selection:created", onSelected);
126
122
  canvas.on("selection:updated", onSelected);
127
123
  canvas.on("selection:cleared", onDeselected);
128
124
  canvas.on("mouse:down", onDown);
129
125
  canvas.on("mouse:move", onMove);
130
126
  canvas.on("mouse:up", onUp);
131
- canvas.on("mouse:down", handleCanvasClick); // ← ADD
132
127
  return () => {
133
128
  canvas.off("selection:created", onSelected);
134
129
  canvas.off("selection:updated", onSelected);
@@ -136,7 +131,6 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
136
131
  canvas.off("mouse:down", onDown);
137
132
  canvas.off("mouse:move", onMove);
138
133
  canvas.off("mouse:up", onUp);
139
- canvas.off("mouse:down", handleCanvasClick); // ← ADD
140
134
  if (rafId !== null)
141
135
  cancelAnimationFrame(rafId);
142
136
  if (selRect)
@@ -151,7 +145,6 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
151
145
  setSelectedCanvasObjects,
152
146
  setSelectedObjectType,
153
147
  setActiveTool,
154
- isDrawingRef,
155
- clearCustomNodeSelection // ← ADD
148
+ isDrawingRef
156
149
  ]);
157
150
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "1.14.0",
3
+ "version": "1.16.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",