@mhamz.01/easyflow-whiteboard 1.12.0 → 1.14.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,2CAshBzB"}
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"}
@@ -22,57 +22,6 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
22
22
  // ── Sync props → local state ────────────────────────────────────────────────
23
23
  useEffect(() => { setLocalTasks(tasks); }, [tasks]);
24
24
  useEffect(() => { setLocalDocuments(documents); }, [documents]);
25
- // ----Sync with Fabric canvas-------------------------------------------------
26
- useEffect(() => {
27
- const canvas = fabricCanvas?.current;
28
- if (!canvas)
29
- return;
30
- const handleSelectionCleared = () => {
31
- setSelectedIds(new Set());
32
- };
33
- const handleMouseDown = (e) => {
34
- if (!e.target) {
35
- setSelectedIds(new Set());
36
- }
37
- };
38
- canvas.on("selection:cleared", handleSelectionCleared);
39
- canvas.on("mouse:down", handleMouseDown);
40
- return () => {
41
- canvas.off("selection:cleared", handleSelectionCleared);
42
- canvas.off("mouse:down", handleMouseDown);
43
- };
44
- }, [fabricCanvas]);
45
- // 3. Update your existing keyboard handler to include clearing on click outside
46
- useEffect(() => {
47
- const handleKeyDown = (e) => {
48
- if (e.target instanceof HTMLInputElement || e.target instanceof HTMLTextAreaElement)
49
- return;
50
- // Clear selection on Escape
51
- if (e.key === "Escape") {
52
- setSelectedIds(new Set());
53
- fabricCanvas?.current?.discardActiveObject();
54
- fabricCanvas?.current?.renderAll();
55
- }
56
- // Select All
57
- if ((e.ctrlKey || e.metaKey) && e.key === "a") {
58
- e.preventDefault();
59
- setSelectedIds(new Set([...localTasks.map((t) => t.id), ...localDocuments.map((d) => d.id)]));
60
- }
61
- // Delete
62
- if ((e.key === "Delete" || e.key === "Backspace") && selectedIds.size > 0) {
63
- e.preventDefault();
64
- const updatedTasks = localTasks.filter((t) => !selectedIds.has(t.id));
65
- const updatedDocs = localDocuments.filter((d) => !selectedIds.has(d.id));
66
- setLocalTasks(updatedTasks);
67
- setLocalDocuments(updatedDocs);
68
- setSelectedIds(new Set());
69
- onTasksUpdate?.(updatedTasks);
70
- onDocumentsUpdate?.(updatedDocs);
71
- }
72
- };
73
- window.addEventListener("keydown", handleKeyDown);
74
- return () => window.removeEventListener("keydown", handleKeyDown);
75
- }, [localTasks, localDocuments, selectedIds, fabricCanvas, onTasksUpdate, onDocumentsUpdate]);
76
25
  // ── Event Forwarding (Fixes Zooming on Nodes) ───────────────────────────────
77
26
  const handleOverlayWheel = (e) => {
78
27
  if (e.ctrlKey || e.metaKey || e.shiftKey) {
@@ -179,15 +128,22 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
179
128
  return { x: doc.x, y: doc.y };
180
129
  return undefined;
181
130
  };
131
+ // In CanvasOverlayLayer, update isItemInSelectionBox to recalculate offset
182
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)
136
+ return false;
137
+ // Item position in screen space (relative to whiteboard container)
183
138
  const itemX1 = x * canvasZoom + canvasViewport.x;
184
139
  const itemY1 = y * canvasZoom + canvasViewport.y;
185
140
  const itemX2 = itemX1 + width * canvasZoom;
186
141
  const itemY2 = itemY1 + height * canvasZoom;
187
- const boxX1 = Math.min(box.x1, box.x2);
188
- const boxY1 = Math.min(box.y1, box.y2);
189
- const boxX2 = Math.max(box.x1, box.x2);
190
- const boxY2 = Math.max(box.y1, box.y2);
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;
191
147
  return !(boxX2 < itemX1 || boxX1 > itemX2 || boxY2 < itemY1 || boxY1 > itemY2);
192
148
  };
193
149
  // ── Selection box detection ──────────────────────────────────────────────────
@@ -395,13 +351,8 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
395
351
  }, children: children }, id));
396
352
  };
397
353
  return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
398
- // Clear selection when clicking on overlay background
399
- if (e.target === e.currentTarget) {
354
+ if (e.target === e.currentTarget)
400
355
  setSelectedIds(new Set());
401
- // Also clear Fabric selection
402
- fabricCanvas?.current?.discardActiveObject();
403
- fabricCanvas?.current?.renderAll();
404
- }
405
356
  }, children: _jsxs("div", { className: "absolute top-0 left-0 pointer-events-none", style: {
406
357
  transform: `translate(${canvasViewport.x}px, ${canvasViewport.y}px)`,
407
358
  transformOrigin: "top left",
@@ -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,4CAqQvC"}
@@ -134,6 +134,7 @@ export default function FabricWhiteboard() {
134
134
  setSelectionBox,
135
135
  setSelectedCanvasObjects,
136
136
  isDrawingRef,
137
+ clearCustomNodeSelection: () => setSelectedIds(new Set()), // ← ADD THIS
137
138
  });
138
139
  // Text style updates
139
140
  useTextStyle({
@@ -205,3 +206,6 @@ export default function FabricWhiteboard() {
205
206
  zIndex: 0,
206
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 }), _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
  }
209
+ function setSelectedIds(arg0) {
210
+ throw new Error("Function not implemented.");
211
+ }
@@ -15,7 +15,8 @@ interface UseSelectionProps {
15
15
  } | null) => void;
16
16
  setSelectedCanvasObjects: (objects: FabricObject[]) => void;
17
17
  isDrawingRef: React.MutableRefObject<boolean>;
18
+ clearCustomNodeSelection?: () => void;
18
19
  }
19
- export declare const useSelection: ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, }: UseSelectionProps) => void;
20
+ export declare const useSelection: ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, clearCustomNodeSelection, }: UseSelectionProps) => void;
20
21
  export {};
21
22
  //# 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;CAC/C;AAED,eAAO,MAAM,YAAY,GAAI,oHAQ1B,iBAAiB,SAkKnB,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;IAC9C,wBAAwB,CAAC,EAAE,MAAM,IAAI,CAAC;CACvC;AAED,eAAO,MAAM,YAAY,GAAI,8IAS1B,iBAAiB,SA2KnB,CAAC"}
@@ -5,7 +5,8 @@ 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, }) => {
8
+ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewport, setSelectionBox, setSelectedCanvasObjects, isDrawingRef, clearCustomNodeSelection, // ← Add this
9
+ }) => {
9
10
  const setSelectedObjectType = useWhiteboardStore((state) => state.setSelectedObjectType);
10
11
  const setActiveTool = useWhiteboardStore((state) => state.setActiveTool);
11
12
  useEffect(() => {
@@ -54,19 +55,15 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
54
55
  });
55
56
  selRect.setCoords();
56
57
  canvas.renderAll();
57
- // ═══════════════════════════════════════════════════════════════
58
- // FIX: Get canvas element offset from viewport
59
- // ═══════════════════════════════════════════════════════════════
58
+ // Get FRESH canvas offset on every move (handles sidebar open/close)
60
59
  const canvasElement = canvas.getElement();
61
60
  const rect = canvasElement.getBoundingClientRect();
62
- // Calculate selection box in screen coordinates (including canvas offset)
63
61
  setSelectionBox({
64
62
  x1: Math.min(selStart.x, p.x) * canvasZoom + canvasViewport.x + rect.left,
65
63
  y1: Math.min(selStart.y, p.y) * canvasZoom + canvasViewport.y + rect.top,
66
64
  x2: Math.max(selStart.x, p.x) * canvasZoom + canvasViewport.x + rect.left,
67
65
  y2: Math.max(selStart.y, p.y) * canvasZoom + canvasViewport.y + rect.top,
68
66
  });
69
- // ═══════════════════════════════════════════════════════════════
70
67
  });
71
68
  };
72
69
  const onUp = () => {
@@ -113,16 +110,25 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
113
110
  setSelectedObjectType(null);
114
111
  setSelectionBox(null);
115
112
  setSelectedCanvasObjects([]);
113
+ // ← ADD: Clear custom node selection too
114
+ clearCustomNodeSelection?.();
116
115
  if (!isDrawingRef.current && activeTool !== "select" && activeTool !== "pan") {
117
116
  setActiveTool("select");
118
117
  }
119
118
  };
119
+ // ← ADD: Clear custom nodes when clicking empty canvas
120
+ const handleCanvasClick = (e) => {
121
+ if (!e.target && activeTool === "select") {
122
+ clearCustomNodeSelection?.();
123
+ }
124
+ };
120
125
  canvas.on("selection:created", onSelected);
121
126
  canvas.on("selection:updated", onSelected);
122
127
  canvas.on("selection:cleared", onDeselected);
123
128
  canvas.on("mouse:down", onDown);
124
129
  canvas.on("mouse:move", onMove);
125
130
  canvas.on("mouse:up", onUp);
131
+ canvas.on("mouse:down", handleCanvasClick); // ← ADD
126
132
  return () => {
127
133
  canvas.off("selection:created", onSelected);
128
134
  canvas.off("selection:updated", onSelected);
@@ -130,6 +136,7 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
130
136
  canvas.off("mouse:down", onDown);
131
137
  canvas.off("mouse:move", onMove);
132
138
  canvas.off("mouse:up", onUp);
139
+ canvas.off("mouse:down", handleCanvasClick); // ← ADD
133
140
  if (rafId !== null)
134
141
  cancelAnimationFrame(rafId);
135
142
  if (selRect)
@@ -144,6 +151,7 @@ export const useSelection = ({ fabricCanvas, activeTool, canvasZoom, canvasViewp
144
151
  setSelectedCanvasObjects,
145
152
  setSelectedObjectType,
146
153
  setActiveTool,
147
- isDrawingRef
154
+ isDrawingRef,
155
+ clearCustomNodeSelection // ← ADD
148
156
  ]);
149
157
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "1.12.0",
3
+ "version": "1.14.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",