@mhamz.01/easyflow-whiteboard 2.70.0 → 2.72.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,
|
|
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,2CAikBzB"}
|
|
@@ -22,15 +22,10 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
22
22
|
offsetX: 0,
|
|
23
23
|
offsetY: 0,
|
|
24
24
|
});
|
|
25
|
-
const finalPositionsRef = useRef(null);
|
|
26
25
|
const rafIdRef = useRef(null);
|
|
27
26
|
const overlayRef = useRef(null);
|
|
28
|
-
const localTasksRef = useRef(localTasks);
|
|
29
|
-
const localDocumentsRef = useRef(localDocuments);
|
|
30
27
|
const selectedIdsRef = useRef(selectedIds);
|
|
31
28
|
selectedIdsRef.current = selectedIds;
|
|
32
|
-
localTasksRef.current = localTasks;
|
|
33
|
-
localDocumentsRef.current = localDocuments;
|
|
34
29
|
// ── Sync props → local state ────────────────────────────────────────────────
|
|
35
30
|
useEffect(() => { setLocalTasks(tasks); }, [tasks]);
|
|
36
31
|
useEffect(() => { setLocalDocuments(documents); }, [documents]);
|
|
@@ -236,8 +231,8 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
236
231
|
// 3. Determine which items are being dragged
|
|
237
232
|
// selection update DOES NOT trigger before drag snapshot
|
|
238
233
|
let itemsToDrag;
|
|
239
|
-
if (
|
|
240
|
-
itemsToDrag = Array.from(
|
|
234
|
+
if (selectedIds.has(itemId)) {
|
|
235
|
+
itemsToDrag = Array.from(selectedIds);
|
|
241
236
|
}
|
|
242
237
|
else {
|
|
243
238
|
itemsToDrag = [itemId];
|
|
@@ -281,7 +276,7 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
281
276
|
offsetX: worldOffsetX, // Now stored as World Units
|
|
282
277
|
offsetY: worldOffsetY, // Now stored as World Units
|
|
283
278
|
};
|
|
284
|
-
if (!
|
|
279
|
+
if (!selectedIds.has(itemId) && dragStateRef.current.itemIds.length === 0) {
|
|
285
280
|
setSelectedIds(new Set([itemId]));
|
|
286
281
|
}
|
|
287
282
|
// 11. Trigger UI states
|
|
@@ -330,22 +325,16 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
330
325
|
const deltaX = newWorldX - firstStart.x;
|
|
331
326
|
const deltaY = newWorldY - firstStart.y;
|
|
332
327
|
// 6. Update HTML Nodes (Batching these into one state update)
|
|
333
|
-
setLocalTasks((prev) => {
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
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
|
-
});
|
|
328
|
+
setLocalTasks((prev) => prev.map((t) => itemIds.includes(t.id) ? {
|
|
329
|
+
...t,
|
|
330
|
+
x: (startPositions.get(t.id)?.x ?? t.x) + deltaX,
|
|
331
|
+
y: (startPositions.get(t.id)?.y ?? t.y) + deltaY,
|
|
332
|
+
} : t));
|
|
333
|
+
setLocalDocuments((prev) => prev.map((d) => itemIds.includes(d.id) ? {
|
|
334
|
+
...d,
|
|
335
|
+
x: (startPositions.get(d.id)?.x ?? d.x) + deltaX,
|
|
336
|
+
y: (startPositions.get(d.id)?.y ?? d.y) + deltaY,
|
|
337
|
+
} : d));
|
|
349
338
|
// 7. Sync Fabric Objects (Imperative update for performance)
|
|
350
339
|
canvasObjectsStartPos.forEach((startPos, obj) => {
|
|
351
340
|
obj.set({
|
|
@@ -354,29 +343,20 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
354
343
|
});
|
|
355
344
|
obj.setCoords(); // Required for selection/intersection accuracy
|
|
356
345
|
});
|
|
357
|
-
finalPositionsRef.current = {
|
|
358
|
-
tasks: localTasksRef.current, // will be updated by React after setState flushes
|
|
359
|
-
documents: localDocumentsRef.current,
|
|
360
|
-
};
|
|
361
346
|
// 8. Single render call for all Fabric changes
|
|
362
347
|
canvas.requestRenderAll();
|
|
363
348
|
});
|
|
364
349
|
};
|
|
365
350
|
const handleEnd = () => {
|
|
366
|
-
if (rafIdRef.current !== null)
|
|
351
|
+
if (rafIdRef.current !== null)
|
|
367
352
|
cancelAnimationFrame(rafIdRef.current);
|
|
368
|
-
rafIdRef.current = null;
|
|
369
|
-
}
|
|
370
353
|
dragStateRef.current.isDragging = false;
|
|
371
354
|
setDragging(null);
|
|
372
355
|
document.body.style.cursor = "";
|
|
373
356
|
document.body.style.userSelect = "";
|
|
374
357
|
document.body.style.touchAction = "";
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
// the position after the last committed setState, not the t=0 snapshot.
|
|
378
|
-
onTasksUpdate?.(localTasksRef.current);
|
|
379
|
-
onDocumentsUpdate?.(localDocumentsRef.current);
|
|
358
|
+
onTasksUpdate?.(localTasks);
|
|
359
|
+
onDocumentsUpdate?.(localDocuments);
|
|
380
360
|
};
|
|
381
361
|
window.addEventListener("mousemove", handleMove, { passive: false });
|
|
382
362
|
window.addEventListener("mouseup", handleEnd);
|
|
@@ -438,27 +418,33 @@ export default function CanvasOverlayLayer({ tasks, documents, onTasksUpdate, on
|
|
|
438
418
|
window.addEventListener("keydown", handleKeyDown);
|
|
439
419
|
return () => window.removeEventListener("keydown", handleKeyDown);
|
|
440
420
|
}, [localTasks, localDocuments, selectedIds, onTasksUpdate, onDocumentsUpdate]);
|
|
441
|
-
const getAbsoluteTransform = (x, y) => {
|
|
442
|
-
// We calculate the screen position in one go, matching Fabric's internal VPT logic
|
|
443
|
-
const screenX = x * canvasZoom + canvasViewport.x;
|
|
444
|
-
const screenY = y * canvasZoom + canvasViewport.y;
|
|
445
|
-
return `translate3d(${screenX}px, ${screenY}px, 0) scale(${canvasZoom})`;
|
|
446
|
-
};
|
|
447
421
|
// ── Render helper ────────────────────────────────────────────────────────────
|
|
448
422
|
const renderItem = (id, x, y, children) => {
|
|
423
|
+
const screenX = x * canvasZoom;
|
|
424
|
+
const screenY = y * canvasZoom;
|
|
425
|
+
// 1. Detect if the user is interacting with the canvas at all
|
|
426
|
+
// 'dragging' is your existing state.
|
|
427
|
+
// You might want to pass 'isZooming' or 'isPanning' from your main canvas component here.
|
|
449
428
|
const isDragging = dragging?.itemIds.includes(id);
|
|
450
429
|
return (_jsx("div", { className: "pointer-events-auto absolute", style: {
|
|
451
430
|
left: 0,
|
|
452
431
|
top: 0,
|
|
453
|
-
//
|
|
454
|
-
transform:
|
|
432
|
+
// 2. Use translate3d for GPU performance
|
|
433
|
+
transform: `translate3d(${screenX}px, ${screenY}px, 0) scale(${canvasZoom})`,
|
|
455
434
|
transformOrigin: "top left",
|
|
456
|
-
|
|
435
|
+
// 3. THE FIX: Remove transition entirely during any viewport change
|
|
436
|
+
// Any 'ease' during zoom causes the "shaking" behavior.
|
|
437
|
+
transition: "none",
|
|
438
|
+
// 4. Optimization
|
|
457
439
|
willChange: "transform",
|
|
458
440
|
zIndex: isDragging ? 1000 : 1,
|
|
459
441
|
}, children: children }, id));
|
|
460
442
|
};
|
|
461
|
-
return (
|
|
462
|
-
|
|
463
|
-
|
|
443
|
+
return (_jsx("div", { ref: overlayRef, className: "absolute inset-0 pointer-events-none", style: { zIndex: 50 }, onWheel: handleOverlayWheel, onClick: (e) => {
|
|
444
|
+
if (e.target === e.currentTarget)
|
|
445
|
+
setSelectedIds(new Set());
|
|
446
|
+
}, children: _jsxs("div", { className: "absolute top-0 left-0 pointer-events-none", style: {
|
|
447
|
+
transform: `translate(${canvasViewport.x}px, ${canvasViewport.y}px)`,
|
|
448
|
+
transformOrigin: "top left",
|
|
449
|
+
}, children: [localTasks.map((task) => renderItem(task.id, task.x, task.y, _jsx(TaskNode, { ...task, isSelected: selectedIds.has(task.id), onSelect: handleSelect, onDragStart: handleDragStart, onStatusChange: handleStatusChange, zoom: 1 }))), localDocuments.map((doc) => renderItem(doc.id, doc.x, doc.y, _jsx(DocumentNode, { ...doc, isSelected: selectedIds.has(doc.id), onSelect: handleSelect, onDragStart: handleDragStart })))] }) }));
|
|
464
450
|
}
|
|
@@ -6,5 +6,5 @@ import { Slider } from "../../../components/ui/slider";
|
|
|
6
6
|
export default function ImageOptions() {
|
|
7
7
|
const toolOptions = useWhiteboardStore((state) => state.toolOptions);
|
|
8
8
|
const setToolOption = useWhiteboardStore((state) => state.setToolOption);
|
|
9
|
-
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs text-neutral-400", children: "Opacity" }), _jsxs("span", { className: "text-xs text-neutral-500", children: [Math.round(toolOptions.image.opacity * 100), "%"] })] }), _jsx(Slider, { value: [toolOptions.image.opacity], min: 0, max:
|
|
9
|
+
return (_jsxs("div", { className: "space-y-4", children: [_jsxs("div", { className: "space-y-2", children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsx(Label, { className: "text-xs text-neutral-400", children: "Opacity" }), _jsxs("span", { className: "text-xs text-neutral-500", children: [Math.round(toolOptions.image.opacity * 100), "%"] })] }), _jsx(Slider, { value: [toolOptions.image.opacity], min: 0, max: 100, step: 1, onValueChange: ([value]) => setToolOption("image", "opacity", value / 100), className: "w-full" })] }), _jsxs("div", { className: "mt-4 p-3 bg-neutral-800/50 rounded-lg border border-neutral-700", children: [_jsxs("p", { className: "text-xs text-neutral-400", children: ["Click the ", _jsx("strong", { className: "text-neutral-200", children: "Image" }), " button to upload an image from your computer."] }), _jsx("p", { className: "text-xs text-neutral-500 mt-2", children: "Supported formats: JPG, PNG, GIF, WebP" })] }), _jsxs("div", { className: "space-y-2", children: [_jsx(Label, { className: "text-xs text-neutral-400", children: "Tips" }), _jsxs("ul", { className: "text-xs text-neutral-500 space-y-1 list-disc list-inside", children: [_jsx("li", { children: "Drag corners to resize" }), _jsx("li", { children: "Click and drag to move" }), _jsx("li", { children: "Use Delete key to remove" }), _jsx("li", { children: "Double-click to edit properties" })] })] })] }));
|
|
10
10
|
}
|