@mhamz.01/easyflow-whiteboard 2.66.0 → 2.68.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;AAS9C,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,CAAC,EAAE,OAAO,CAAC;CACvB;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,2CAkkBzB"}
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;AAS9C,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,CAAC,EAAE,OAAO,CAAC;CACvB;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,2CAgmBzB"}
@@ -22,10 +22,15 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
22
22
  offsetX: 0,
23
23
  offsetY: 0,
24
24
  });
25
+ const finalPositionsRef = useRef(null);
25
26
  const rafIdRef = useRef(null);
26
27
  const overlayRef = useRef(null);
28
+ const localTasksRef = useRef(localTasks);
29
+ const localDocumentsRef = useRef(localDocuments);
27
30
  const selectedIdsRef = useRef(selectedIds);
28
31
  selectedIdsRef.current = selectedIds;
32
+ localTasksRef.current = localTasks;
33
+ localDocumentsRef.current = localDocuments;
29
34
  // ── Sync props → local state ────────────────────────────────────────────────
30
35
  useEffect(() => { setLocalTasks(tasks); }, [tasks]);
31
36
  useEffect(() => { setLocalDocuments(documents); }, [documents]);
@@ -231,12 +236,11 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
231
236
  // 3. Determine which items are being dragged
232
237
  // selection update DOES NOT trigger before drag snapshot
233
238
  let itemsToDrag;
234
- if (selectedIds.has(itemId)) {
235
- itemsToDrag = Array.from(selectedIds);
239
+ if (selectedIdsRef.current.has(itemId)) {
240
+ itemsToDrag = Array.from(selectedIdsRef.current);
236
241
  }
237
242
  else {
238
243
  itemsToDrag = [itemId];
239
- setSelectedIds(new Set([itemId]));
240
244
  }
241
245
  // 4. Capture current World Transform (Zoom & Pan)
242
246
  // We read directly from the canvas to ensure zero-frame lag
@@ -277,7 +281,7 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
277
281
  offsetX: worldOffsetX, // Now stored as World Units
278
282
  offsetY: worldOffsetY, // Now stored as World Units
279
283
  };
280
- if (!selectedIds.has(itemId) && dragStateRef.current.itemIds.length === 0) {
284
+ if (!selectedIdsRef.current.has(itemId) && dragStateRef.current.itemIds.length === 0) {
281
285
  setSelectedIds(new Set([itemId]));
282
286
  }
283
287
  // 11. Trigger UI states
@@ -326,16 +330,22 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
326
330
  const deltaX = newWorldX - firstStart.x;
327
331
  const deltaY = newWorldY - firstStart.y;
328
332
  // 6. Update HTML Nodes (Batching these into one state update)
329
- setLocalTasks((prev) => prev.map((t) => itemIds.includes(t.id) ? {
330
- ...t,
331
- x: (startPositions.get(t.id)?.x ?? t.x) + deltaX,
332
- y: (startPositions.get(t.id)?.y ?? t.y) + deltaY,
333
- } : t));
334
- setLocalDocuments((prev) => prev.map((d) => itemIds.includes(d.id) ? {
335
- ...d,
336
- x: (startPositions.get(d.id)?.x ?? d.x) + deltaX,
337
- y: (startPositions.get(d.id)?.y ?? d.y) + deltaY,
338
- } : d));
333
+ setLocalTasks((prev) => {
334
+ const next = prev.map((t) => itemIds.includes(t.id)
335
+ ? { ...t, x: (startPositions.get(t.id)?.x ?? t.x) + deltaX,
336
+ y: (startPositions.get(t.id)?.y ?? t.y) + deltaY }
337
+ : t);
338
+ localTasksRef.current = next; // write-through: ref always has latest
339
+ return next;
340
+ });
341
+ setLocalDocuments((prev) => {
342
+ const next = prev.map((d) => itemIds.includes(d.id)
343
+ ? { ...d, x: (startPositions.get(d.id)?.x ?? d.x) + deltaX,
344
+ y: (startPositions.get(d.id)?.y ?? d.y) + deltaY }
345
+ : d);
346
+ localDocumentsRef.current = next; // ← write-through
347
+ return next;
348
+ });
339
349
  // 7. Sync Fabric Objects (Imperative update for performance)
340
350
  canvasObjectsStartPos.forEach((startPos, obj) => {
341
351
  obj.set({
@@ -344,20 +354,29 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
344
354
  });
345
355
  obj.setCoords(); // Required for selection/intersection accuracy
346
356
  });
357
+ finalPositionsRef.current = {
358
+ tasks: localTasksRef.current, // will be updated by React after setState flushes
359
+ documents: localDocumentsRef.current,
360
+ };
347
361
  // 8. Single render call for all Fabric changes
348
362
  canvas.requestRenderAll();
349
363
  });
350
364
  };
351
365
  const handleEnd = () => {
352
- dragStateRef.current.isDragging = false;
353
- if (rafIdRef.current !== null)
366
+ if (rafIdRef.current !== null) {
354
367
  cancelAnimationFrame(rafIdRef.current);
368
+ rafIdRef.current = null;
369
+ }
370
+ dragStateRef.current.isDragging = false;
355
371
  setDragging(null);
356
372
  document.body.style.cursor = "";
357
373
  document.body.style.userSelect = "";
358
374
  document.body.style.touchAction = "";
359
- onTasksUpdate?.(localTasks);
360
- onDocumentsUpdate?.(localDocuments);
375
+ // ✅ FIX 1+3: Read from live refs — never from the stale closure.
376
+ // localTasksRef is kept in sync on every render, so this is always
377
+ // the position after the last committed setState, not the t=0 snapshot.
378
+ onTasksUpdate?.(localTasksRef.current);
379
+ onDocumentsUpdate?.(localDocumentsRef.current);
361
380
  };
362
381
  window.addEventListener("mousemove", handleMove, { passive: false });
363
382
  window.addEventListener("mouseup", handleEnd);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.66.0",
3
+ "version": "2.68.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",