@mhamz.01/easyflow-whiteboard 2.3.0 → 2.5.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,2CA2dzB"}
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"}
@@ -172,7 +172,6 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
172
172
  return e;
173
173
  };
174
174
  const handleDragStart = (itemId, e) => {
175
- // Prevent browser scrolling while dragging
176
175
  if (e.cancelable)
177
176
  e.preventDefault();
178
177
  const pointer = getPointerEvent(e);
@@ -197,8 +196,13 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
197
196
  const clickedPos = getItemPosition(itemId);
198
197
  if (!clickedPos)
199
198
  return;
200
- const screenX = clickedPos.x * canvasZoom + canvasViewport.x;
201
- const screenY = clickedPos.y * canvasZoom + canvasViewport.y;
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;
202
206
  dragStateRef.current = {
203
207
  isDragging: true,
204
208
  itemIds: itemsToDrag,
@@ -210,7 +214,6 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
210
214
  setDragging({ itemIds: itemsToDrag });
211
215
  document.body.style.cursor = "grabbing";
212
216
  document.body.style.userSelect = "none";
213
- // Prevents mobile pull-to-refresh
214
217
  document.body.style.touchAction = "none";
215
218
  };
216
219
  // ── Drag move (HTML Node side) ───────────────────────────────────────────────
@@ -220,7 +223,6 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
220
223
  const handleMove = (e) => {
221
224
  if (!dragStateRef.current.isDragging)
222
225
  return;
223
- // Prevent mobile scrolling
224
226
  if (e.cancelable)
225
227
  e.preventDefault();
226
228
  const pointer = getPointerEvent(e);
@@ -232,22 +234,26 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
232
234
  const firstStart = startPositions.get(firstId);
233
235
  if (!firstStart)
234
236
  return;
235
- // Calculate new world coordinates
236
- const newX = (pointer.clientX - offsetX - canvasViewport.x) / canvasZoom;
237
- const newY = (pointer.clientY - offsetY - canvasViewport.y) / canvasZoom;
237
+ // ── FIX: Read VPT live inside rAF — perfectly in sync with Fabric ──
238
+ const vpt = fabricCanvas?.current?.viewportTransform;
239
+ const liveZoom = vpt ? vpt[0] : 1;
240
+ const liveVpX = vpt ? vpt[4] : 0;
241
+ const liveVpY = vpt ? vpt[5] : 0;
242
+ // Convert screen → world using live VPT values
243
+ const newX = (pointer.clientX - offsetX - liveVpX) / liveZoom;
244
+ const newY = (pointer.clientY - offsetY - liveVpY) / liveZoom;
238
245
  const deltaX = newX - firstStart.x;
239
246
  const deltaY = newY - firstStart.y;
240
- // Batch state updates for React
241
- setLocalTasks((prev) => prev.map((t) => (itemIds.includes(t.id) ? {
247
+ setLocalTasks((prev) => prev.map((t) => itemIds.includes(t.id) ? {
242
248
  ...t,
243
- x: (startPositions.get(t.id)?.x || 0) + deltaX,
244
- y: (startPositions.get(t.id)?.y || 0) + deltaY
245
- } : t)));
246
- setLocalDocuments((prev) => prev.map((d) => (itemIds.includes(d.id) ? {
249
+ x: (startPositions.get(t.id)?.x ?? t.x) + deltaX,
250
+ y: (startPositions.get(t.id)?.y ?? t.y) + deltaY,
251
+ } : t));
252
+ setLocalDocuments((prev) => prev.map((d) => itemIds.includes(d.id) ? {
247
253
  ...d,
248
- x: (startPositions.get(d.id)?.x || 0) + deltaX,
249
- y: (startPositions.get(d.id)?.y || 0) + deltaY
250
- } : d)));
254
+ x: (startPositions.get(d.id)?.x ?? d.x) + deltaX,
255
+ y: (startPositions.get(d.id)?.y ?? d.y) + deltaY,
256
+ } : d));
251
257
  if (fabricCanvas?.current) {
252
258
  canvasObjectsStartPos.forEach((startPos, obj) => {
253
259
  obj.set({
@@ -283,7 +289,7 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
283
289
  window.removeEventListener("touchend", handleEnd);
284
290
  window.removeEventListener("touchcancel", handleEnd);
285
291
  };
286
- }, [dragging, canvasZoom, canvasViewport, localTasks, localDocuments, fabricCanvas]);
292
+ }, [dragging, localTasks, localDocuments, fabricCanvas]);
287
293
  // ── Selection, Status, Keyboard Logic ────────────────────────────────────────
288
294
  const handleSelect = (id, e) => {
289
295
  if (e?.shiftKey || e?.ctrlKey || e?.metaKey) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mhamz.01/easyflow-whiteboard",
3
- "version": "2.3.0",
3
+ "version": "2.5.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",