@mhamz.01/easyflow-whiteboard 2.155.0 → 2.156.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":"AAEA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAI9C,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;IACtB,qBAAqB,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,IAAI,CAAC,CAAC;CAC5D;;AAaD,wBA6sBG"}
1
+ {"version":3,"file":"custom-node-overlay-layer.d.ts","sourceRoot":"","sources":["../../../src/components/node/custom-node-overlay-layer.tsx"],"names":[],"mappings":"AAEA,OAAO,KAAsC,MAAM,OAAO,CAAC;AAC3D,OAAO,EAAE,YAAY,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAC;AAK9C,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;IACtB,qBAAqB,CAAC,EAAE,KAAK,CAAC,gBAAgB,CAAC,MAAM,IAAI,CAAC,CAAC;CAC5D;;AAaD,wBA+tBG"}
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React, { useState, useEffect, useRef } from "react";
4
4
  import TaskNode from "./custom-node";
5
5
  import DocumentNode from "./document-node";
6
+ import { util } from "fabric";
6
7
  // ─── Component ────────────────────────────────────────────────────────────────
7
8
  export default React.memo(function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, onDocumentsUpdate, canvasZoom = 1, canvasViewport = { x: 0, y: 0 }, selectionBox = null, selectedCanvasObjects = [], fabricCanvas, canvasReady: canvasReadyProp = false, clearHtmlSelectionRef, }) {
8
9
  const [localTasks, setLocalTasks] = useState(tasks);
@@ -308,23 +309,24 @@ export default React.memo(function CanvasOverlayLayer({ tasks, documents, onTask
308
309
  if (pos)
309
310
  startPositions.set(id, pos);
310
311
  });
312
+ // In handleDragStart — replace the activeSelection branch:
311
313
  const liveActiveObjects = canvas.getActiveObjects();
312
314
  const activeSelection = canvas.getActiveObject();
313
315
  const canvasObjectsStartPos = new Map();
314
- if (activeSelection && activeSelection.type === "activeSelection") {
315
- // Move the whole multi-selection as one rigid body. It has no parent
316
- // group, so its own left/top are already canvas-absolute unlike its
317
- // children, whose left/top are relative to the group's center. Writing
318
- // world-space deltas into a child's left/top while it's still parented
319
- // to the group double-transforms it on render, causing drift.
320
- canvasObjectsStartPos.set(activeSelection, {
321
- left: activeSelection.left || 0,
322
- top: activeSelection.top || 0,
316
+ if (activeSelection && activeSelection.type === "activeSelection" && liveActiveObjects.length > 1) {
317
+ // Snapshot each child's TRUE canvas-absolute position via its transform matrix,
318
+ // not its group-relative left/top. This avoids drift caused by activeSelection's
319
+ // internal bounding-box recalculation during the drag.
320
+ liveActiveObjects.forEach((obj) => {
321
+ const matrix = obj.calcTransformMatrix();
322
+ canvasObjectsStartPos.set(obj, {
323
+ left: matrix[4],
324
+ top: matrix[5],
325
+ });
323
326
  });
324
327
  }
325
328
  else {
326
329
  liveActiveObjects.forEach((obj) => {
327
- // Single object — left/top IS world position
328
330
  canvasObjectsStartPos.set(obj, {
329
331
  left: obj.left || 0,
330
332
  top: obj.top || 0,
@@ -406,15 +408,26 @@ export default React.memo(function CanvasOverlayLayer({ tasks, documents, onTask
406
408
  y: (startPositions.get(d.id)?.y ?? d.y) + deltaY,
407
409
  }
408
410
  : d));
409
- // 7. Sync Fabric Objects (Imperative update for performance)
411
+ const activeObj = canvas.getActiveObject();
412
+ const isGroup = activeObj && activeObj.type === "activeSelection" && canvasObjectsStartPos.size > 1;
413
+ // Precompute the group's inverse matrix ONCE per frame, not per child
414
+ let groupInverseMatrix = null;
415
+ if (isGroup) {
416
+ const groupMatrix = activeObj.calcOwnMatrix();
417
+ groupInverseMatrix = util.invertTransform(groupMatrix);
418
+ }
410
419
  canvasObjectsStartPos.forEach((startPos, obj) => {
411
- obj.set({
412
- left: startPos.left + deltaX,
413
- top: startPos.top + deltaY,
414
- });
415
- obj.setCoords(); // Required for selection/intersection accuracy
420
+ const targetAbsoluteLeft = startPos.left + deltaX;
421
+ const targetAbsoluteTop = startPos.top + deltaY;
422
+ if (isGroup && groupInverseMatrix) {
423
+ const localPoint = util.transformPoint({ x: targetAbsoluteLeft, y: targetAbsoluteTop }, groupInverseMatrix);
424
+ obj.set({ left: localPoint.x, top: localPoint.y });
425
+ }
426
+ else {
427
+ obj.set({ left: targetAbsoluteLeft, top: targetAbsoluteTop });
428
+ }
429
+ obj.setCoords();
416
430
  });
417
- // 8. Single render call for all Fabric changes
418
431
  canvas.requestRenderAll();
419
432
  });
420
433
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.155.0",
3
+ "version": "2.156.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",