@mhamz.01/easyflow-whiteboard 2.6.0 → 2.7.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,2CAwezB"}
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,2CAmfzB"}
@@ -19,6 +19,8 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
19
19
  });
20
20
  const rafIdRef = useRef(null);
21
21
  const overlayRef = useRef(null);
22
+ // Add this ref at top of CanvasOverlayLayer:
23
+ const isHtmlDraggingRef = useRef(false);
22
24
  // ── Sync props → local state ────────────────────────────────────────────────
23
25
  useEffect(() => { setLocalTasks(tasks); }, [tasks]);
24
26
  useEffect(() => { setLocalDocuments(documents); }, [documents]);
@@ -89,20 +91,20 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
89
91
  if (!canvas)
90
92
  return;
91
93
  const handleObjectMoving = (e) => {
94
+ // ── Skip if user is dragging via HTML node — avoid position conflict ──
95
+ if (isHtmlDraggingRef.current)
96
+ return;
92
97
  const target = e.transform?.target || e.target;
93
98
  if (!target)
94
99
  return;
95
- // 1. Calculate delta in raw Scene Coordinates
96
- // We do NOT divide by zoom here because target.left/top are world units.
97
100
  const deltaX = target.left - (target._prevLeft ?? target.left);
98
101
  const deltaY = target.top - (target._prevTop ?? target.top);
99
102
  target._prevLeft = target.left;
100
103
  target._prevTop = target.top;
101
104
  if (deltaX === 0 && deltaY === 0)
102
105
  return;
103
- // 2. Apply the raw delta to HTML items
104
- setLocalTasks((prev) => prev.map((t) => (selectedIds.has(t.id) ? { ...t, x: t.x + deltaX, y: t.y + deltaY } : t)));
105
- setLocalDocuments((prev) => prev.map((d) => (selectedIds.has(d.id) ? { ...d, x: d.x + deltaX, y: d.y + deltaY } : d)));
106
+ setLocalTasks((prev) => prev.map((t) => selectedIds.has(t.id) ? { ...t, x: t.x + deltaX, y: t.y + deltaY } : t));
107
+ setLocalDocuments((prev) => prev.map((d) => selectedIds.has(d.id) ? { ...d, x: d.x + deltaX, y: d.y + deltaY } : d));
106
108
  };
107
109
  const handleMouseDown = (e) => {
108
110
  const target = e.target;
@@ -175,46 +177,52 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
175
177
  if (e.cancelable)
176
178
  e.preventDefault();
177
179
  const pointer = getPointerEvent(e);
180
+ // ── Snapshot VPT immediately — before anything else ──
181
+ const vpt = fabricCanvas?.current?.viewportTransform;
182
+ const liveZoom = vpt ? vpt[0] : 1;
183
+ const liveVpX = vpt ? vpt[4] : 0;
184
+ const liveVpY = vpt ? vpt[5] : 0;
185
+ // ── Snapshot ALL positions immediately from ref — before any state update ──
186
+ const allItems = [
187
+ ...localTasks.map(t => ({ id: t.id, x: t.x, y: t.y })),
188
+ ...localDocuments.map(d => ({ id: d.id, x: d.x, y: d.y })),
189
+ ];
178
190
  let itemsToDrag;
179
191
  if (selectedIds.has(itemId)) {
180
192
  itemsToDrag = Array.from(selectedIds);
181
193
  }
182
194
  else {
183
195
  itemsToDrag = [itemId];
196
+ // setSelectedIds AFTER snapshot — doesn't affect already-captured positions
184
197
  setSelectedIds(new Set([itemId]));
185
198
  }
186
199
  const startPositions = new Map();
187
- itemsToDrag.forEach((id) => {
188
- const pos = getItemPosition(id);
189
- if (pos)
190
- startPositions.set(id, pos);
200
+ allItems.forEach(({ id, x, y }) => {
201
+ if (itemsToDrag.includes(id))
202
+ startPositions.set(id, { x, y });
191
203
  });
192
204
  const canvasObjectsStartPos = new Map();
193
205
  selectedCanvasObjects.forEach((obj) => {
194
206
  canvasObjectsStartPos.set(obj, { left: obj.left || 0, top: obj.top || 0 });
195
207
  });
196
- const clickedPos = getItemPosition(itemId);
208
+ const clickedPos = startPositions.get(itemId);
197
209
  if (!clickedPos)
198
210
  return;
199
- // ── FIX: Read VPT directly — never stale, always frame-perfect ──
200
- const vpt = fabricCanvas?.current?.viewportTransform;
201
- const liveZoom = vpt ? vpt[0] : 1;
202
- const liveVpX = vpt ? vpt[4] : 0;
203
- const liveVpY = vpt ? vpt[5] : 0;
204
- const screenX = clickedPos.x * liveZoom + liveVpX;
205
- const screenY = clickedPos.y * liveZoom + liveVpY;
206
- console.log("pointer screen:", pointer.clientX, pointer.clientY);
207
- console.log("clickedPos world:", clickedPos?.x, clickedPos?.y);
208
- console.log("vpt zoom/vpX/vpY:", liveZoom, liveVpX, liveVpY);
209
- console.log("node screen should be:", clickedPos ? clickedPos.x * liveZoom + liveVpX : "?", clickedPos ? clickedPos.y * liveZoom + liveVpY : "?");
211
+ // ── World-space offset ──
212
+ const pointerWorldX = (pointer.clientX - liveVpX) / liveZoom;
213
+ const pointerWorldY = (pointer.clientY - liveVpY) / liveZoom;
214
+ const offsetWorldX = pointerWorldX - clickedPos.x;
215
+ const offsetWorldY = pointerWorldY - clickedPos.y;
210
216
  dragStateRef.current = {
211
217
  isDragging: true,
212
218
  itemIds: itemsToDrag,
213
219
  startPositions,
214
220
  canvasObjectsStartPos,
215
- offsetX: pointer.clientX - screenX,
216
- offsetY: pointer.clientY - screenY,
221
+ offsetX: offsetWorldX,
222
+ offsetY: offsetWorldY,
217
223
  };
224
+ // ── Block object:moving sync for the duration of this HTML drag ──
225
+ isHtmlDraggingRef.current = true;
218
226
  setDragging({ itemIds: itemsToDrag });
219
227
  document.body.style.cursor = "grabbing";
220
228
  document.body.style.userSelect = "none";
@@ -274,6 +282,8 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
274
282
  if (rafIdRef.current !== null)
275
283
  cancelAnimationFrame(rafIdRef.current);
276
284
  dragStateRef.current.isDragging = false;
285
+ // ── Re-enable object:moving sync ──
286
+ isHtmlDraggingRef.current = false;
277
287
  setDragging(null);
278
288
  document.body.style.cursor = "";
279
289
  document.body.style.userSelect = "";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.6.0",
3
+ "version": "2.7.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",