@mhamz.01/easyflow-whiteboard 2.35.0 → 2.36.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;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,2CAgczB"}
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;AAwBD,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,2CAmezB"}
@@ -24,6 +24,7 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
24
24
  canvasObjectsStartPos: new Map(),
25
25
  offsetX: 0,
26
26
  offsetY: 0,
27
+ fabricDragHtmlIds: new Set(),
27
28
  });
28
29
  const rafIdRef = useRef(null);
29
30
  const overlayRef = useRef(null);
@@ -84,16 +85,39 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
84
85
  const target = e.transform?.target || e.target;
85
86
  if (!target)
86
87
  return;
88
+ // If an HTML-node drag is already in progress (handleDragStart was called),
89
+ // object:moving should not also move HTML nodes — the HTML drag loop owns that.
90
+ // itemIds.length > 0 means HTML drag is active.
91
+ if (dragStateRef.current.isDragging && dragStateRef.current.itemIds.length > 0)
92
+ return;
93
+ // On the very first object:moving frame of a FABRIC-initiated drag,
94
+ // snapshot which HTML nodes were selected at mousedown time — BEFORE
95
+ // selection:created/updated had a chance to clear them.
96
+ if (!dragStateRef.current.isDragging) {
97
+ dragStateRef.current.isDragging = true;
98
+ dragStateRef.current.fabricDragHtmlIds = new Set(selectedIdsRef.current);
99
+ }
87
100
  const deltaX = target.left - (target._prevLeft ?? target.left);
88
101
  const deltaY = target.top - (target._prevTop ?? target.top);
89
102
  target._prevLeft = target.left;
90
103
  target._prevTop = target.top;
91
104
  if (deltaX === 0 && deltaY === 0)
92
105
  return;
93
- const sel = selectedIdsRef.current; // always fresh
106
+ // Use the snapshotted ids immune to any post-mousedown selection clearing
107
+ const sel = dragStateRef.current.fabricDragHtmlIds;
108
+ if (sel.size === 0)
109
+ return;
94
110
  setLocalTasks((prev) => prev.map((t) => sel.has(t.id) ? { ...t, x: t.x + deltaX, y: t.y + deltaY } : t));
95
111
  setLocalDocuments((prev) => prev.map((d) => sel.has(d.id) ? { ...d, x: d.x + deltaX, y: d.y + deltaY } : d));
96
112
  };
113
+ // When Fabric drag ends, reset so next gesture gets a fresh snapshot
114
+ const handleObjectModified = () => {
115
+ // Only reset if this was a Fabric-initiated drag (not HTML drag)
116
+ if (dragStateRef.current.isDragging && dragStateRef.current.itemIds.length === 0) {
117
+ dragStateRef.current.isDragging = false;
118
+ dragStateRef.current.fabricDragHtmlIds = new Set();
119
+ }
120
+ };
97
121
  const handleMouseDown = (e) => {
98
122
  const target = e.target;
99
123
  if (target) {
@@ -106,24 +130,32 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
106
130
  return;
107
131
  }
108
132
  // Clicked a Fabric object — only deselect HTML nodes if NOT already in
109
- // the active selection (preserves mixed-group drag behaviour)
133
+ // the active selection (preserves mixed-group drag behaviour).
134
+ // Note: getActiveObjects() here reflects the selection BEFORE this click,
135
+ // which is exactly what we want — it tells us if this is a continuation
136
+ // of an existing selection (drag) vs a fresh click (deselect).
110
137
  const activeObjects = canvas.getActiveObjects();
111
138
  if (!activeObjects.includes(target)) {
112
139
  setSelectedIds(new Set());
113
140
  }
141
+ // If already selected: selectedIds stays intact.
142
+ // handleObjectMoving will snapshot it on the first move frame.
114
143
  };
115
- // Clear HTML selection on fresh Fabric selection, but never mid-drag
144
+ // Clear HTML selection on fresh Fabric selection, but never while a
145
+ // Fabric drag is active (fabricDragHtmlIds.size > 0 = drag in progress)
116
146
  const handleFabricSelection = () => {
117
147
  if (!dragStateRef.current.isDragging) {
118
148
  setSelectedIds(new Set());
119
149
  }
120
150
  };
121
151
  canvas.on("object:moving", handleObjectMoving);
152
+ canvas.on("object:modified", handleObjectModified);
122
153
  canvas.on("mouse:down", handleMouseDown);
123
154
  canvas.on("selection:created", handleFabricSelection);
124
155
  canvas.on("selection:updated", handleFabricSelection);
125
156
  return () => {
126
157
  canvas.off("object:moving", handleObjectMoving);
158
+ canvas.off("object:modified", handleObjectModified);
127
159
  canvas.off("mouse:down", handleMouseDown);
128
160
  canvas.off("selection:created", handleFabricSelection);
129
161
  canvas.off("selection:updated", handleFabricSelection);
@@ -280,6 +312,7 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
280
312
  canvasObjectsStartPos,
281
313
  offsetX: (pointer.clientX - liveVpX) / liveZoom - clickedPos.x,
282
314
  offsetY: (pointer.clientY - liveVpY) / liveZoom - clickedPos.y,
315
+ fabricDragHtmlIds: new Set(),
283
316
  };
284
317
  document.body.style.cursor = "grabbing";
285
318
  document.body.style.userSelect = "none";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.35.0",
3
+ "version": "2.36.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",