@mhamz.01/easyflow-whiteboard 2.5.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,2CAiezB"}
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,42 +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;
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;
206
216
  dragStateRef.current = {
207
217
  isDragging: true,
208
218
  itemIds: itemsToDrag,
209
219
  startPositions,
210
220
  canvasObjectsStartPos,
211
- offsetX: pointer.clientX - screenX,
212
- offsetY: pointer.clientY - screenY,
221
+ offsetX: offsetWorldX,
222
+ offsetY: offsetWorldY,
213
223
  };
224
+ // ── Block object:moving sync for the duration of this HTML drag ──
225
+ isHtmlDraggingRef.current = true;
214
226
  setDragging({ itemIds: itemsToDrag });
215
227
  document.body.style.cursor = "grabbing";
216
228
  document.body.style.userSelect = "none";
@@ -270,6 +282,8 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
270
282
  if (rafIdRef.current !== null)
271
283
  cancelAnimationFrame(rafIdRef.current);
272
284
  dragStateRef.current.isDragging = false;
285
+ // ── Re-enable object:moving sync ──
286
+ isHtmlDraggingRef.current = false;
273
287
  setDragging(null);
274
288
  document.body.style.cursor = "";
275
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.5.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",