@almadar/ui 5.58.0 → 5.59.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.
- package/dist/avl/index.cjs +143 -22
- package/dist/avl/index.js +143 -22
- package/dist/components/core/molecules/GraphCanvas.d.ts +6 -0
- package/dist/components/index.cjs +143 -22
- package/dist/components/index.js +143 -22
- package/dist/providers/index.cjs +143 -22
- package/dist/providers/index.js +143 -22
- package/dist/runtime/index.cjs +143 -22
- package/dist/runtime/index.js +143 -22
- package/package.json +1 -1
|
@@ -38419,6 +38419,9 @@ var init_GraphCanvas = __esm({
|
|
|
38419
38419
|
actions,
|
|
38420
38420
|
onNodeClick,
|
|
38421
38421
|
nodeClickEvent,
|
|
38422
|
+
selectedNodeId,
|
|
38423
|
+
repulsion = 800,
|
|
38424
|
+
linkDistance = 100,
|
|
38422
38425
|
layout = "force",
|
|
38423
38426
|
entity,
|
|
38424
38427
|
isLoading = false,
|
|
@@ -38434,6 +38437,35 @@ var init_GraphCanvas = __esm({
|
|
|
38434
38437
|
const [hoveredNode, setHoveredNode] = React76.useState(null);
|
|
38435
38438
|
const nodesRef = React76.useRef([]);
|
|
38436
38439
|
const [, forceUpdate] = React76.useState(0);
|
|
38440
|
+
const interactionRef = React76.useRef({
|
|
38441
|
+
mode: "none",
|
|
38442
|
+
dragNodeId: null,
|
|
38443
|
+
startMouse: { x: 0, y: 0 },
|
|
38444
|
+
startOffset: { x: 0, y: 0 },
|
|
38445
|
+
downPos: { x: 0, y: 0 }
|
|
38446
|
+
});
|
|
38447
|
+
const toCoords = React76.useCallback(
|
|
38448
|
+
(e) => {
|
|
38449
|
+
const canvas = canvasRef.current;
|
|
38450
|
+
if (!canvas) return null;
|
|
38451
|
+
const rect = canvas.getBoundingClientRect();
|
|
38452
|
+
const screenX = e.clientX - rect.left;
|
|
38453
|
+
const screenY = e.clientY - rect.top;
|
|
38454
|
+
return {
|
|
38455
|
+
screenX,
|
|
38456
|
+
screenY,
|
|
38457
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38458
|
+
graphY: (screenY - offset.y) / zoom
|
|
38459
|
+
};
|
|
38460
|
+
},
|
|
38461
|
+
[offset, zoom]
|
|
38462
|
+
);
|
|
38463
|
+
const nodeAt = React76.useCallback((graphX, graphY) => {
|
|
38464
|
+
return nodesRef.current.find((n) => {
|
|
38465
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38466
|
+
return dist < (n.size || 8) + 4;
|
|
38467
|
+
});
|
|
38468
|
+
}, []);
|
|
38437
38469
|
const handleAction = React76.useCallback(
|
|
38438
38470
|
(action) => {
|
|
38439
38471
|
if (action.event) {
|
|
@@ -38499,7 +38531,7 @@ var init_GraphCanvas = __esm({
|
|
|
38499
38531
|
const dx = nodes[j].x - nodes[i].x;
|
|
38500
38532
|
const dy = nodes[j].y - nodes[i].y;
|
|
38501
38533
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38502
|
-
const force =
|
|
38534
|
+
const force = repulsion / (dist * dist);
|
|
38503
38535
|
const fx = dx / dist * force;
|
|
38504
38536
|
const fy = dy / dist * force;
|
|
38505
38537
|
nodes[i].fx -= fx;
|
|
@@ -38515,7 +38547,7 @@ var init_GraphCanvas = __esm({
|
|
|
38515
38547
|
const dx = target.x - source.x;
|
|
38516
38548
|
const dy = target.y - source.y;
|
|
38517
38549
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38518
|
-
const force = (dist -
|
|
38550
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38519
38551
|
const fx = dx / dist * force;
|
|
38520
38552
|
const fy = dy / dist * force;
|
|
38521
38553
|
source.fx += fx;
|
|
@@ -38549,7 +38581,7 @@ var init_GraphCanvas = __esm({
|
|
|
38549
38581
|
return () => {
|
|
38550
38582
|
cancelAnimationFrame(animRef.current);
|
|
38551
38583
|
};
|
|
38552
|
-
}, [propNodes, propEdges, layout]);
|
|
38584
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38553
38585
|
React76.useEffect(() => {
|
|
38554
38586
|
const canvas = canvasRef.current;
|
|
38555
38587
|
if (!canvas) return;
|
|
@@ -38585,18 +38617,25 @@ var init_GraphCanvas = __esm({
|
|
|
38585
38617
|
const size = node.size || 8;
|
|
38586
38618
|
const color = node.color || getGroupColor(node.group, groups);
|
|
38587
38619
|
const isHovered = hoveredNode === node.id;
|
|
38620
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38621
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38588
38622
|
ctx.beginPath();
|
|
38589
|
-
ctx.arc(node.x, node.y,
|
|
38623
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38590
38624
|
ctx.fillStyle = color;
|
|
38591
38625
|
ctx.fill();
|
|
38592
|
-
|
|
38593
|
-
|
|
38626
|
+
if (isSelected) {
|
|
38627
|
+
ctx.strokeStyle = "var(--color-accent)";
|
|
38628
|
+
ctx.lineWidth = 3;
|
|
38629
|
+
} else {
|
|
38630
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38631
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38632
|
+
}
|
|
38594
38633
|
ctx.stroke();
|
|
38595
38634
|
if (showLabels && node.label) {
|
|
38596
38635
|
ctx.fillStyle = "#666666";
|
|
38597
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38636
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38598
38637
|
ctx.textAlign = "center";
|
|
38599
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38638
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38600
38639
|
}
|
|
38601
38640
|
}
|
|
38602
38641
|
ctx.restore();
|
|
@@ -38607,6 +38646,97 @@ var init_GraphCanvas = __esm({
|
|
|
38607
38646
|
setZoom(1);
|
|
38608
38647
|
setOffset({ x: 0, y: 0 });
|
|
38609
38648
|
}, []);
|
|
38649
|
+
const handleWheel = React76.useCallback(
|
|
38650
|
+
(e) => {
|
|
38651
|
+
if (!interactive) return;
|
|
38652
|
+
e.preventDefault();
|
|
38653
|
+
const coords = toCoords(e);
|
|
38654
|
+
if (!coords) return;
|
|
38655
|
+
const oldZoom = zoom;
|
|
38656
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38657
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38658
|
+
if (newZoom === oldZoom) return;
|
|
38659
|
+
setOffset((o) => ({
|
|
38660
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38661
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38662
|
+
}));
|
|
38663
|
+
setZoom(newZoom);
|
|
38664
|
+
},
|
|
38665
|
+
[interactive, toCoords, zoom]
|
|
38666
|
+
);
|
|
38667
|
+
const handleMouseDown = React76.useCallback(
|
|
38668
|
+
(e) => {
|
|
38669
|
+
const coords = toCoords(e);
|
|
38670
|
+
if (!coords) return;
|
|
38671
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38672
|
+
const state = interactionRef.current;
|
|
38673
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38674
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38675
|
+
state.startOffset = { ...offset };
|
|
38676
|
+
if (draggable && node) {
|
|
38677
|
+
state.mode = "dragging";
|
|
38678
|
+
state.dragNodeId = node.id;
|
|
38679
|
+
} else if (interactive) {
|
|
38680
|
+
state.mode = "panning";
|
|
38681
|
+
state.dragNodeId = null;
|
|
38682
|
+
} else {
|
|
38683
|
+
state.mode = "none";
|
|
38684
|
+
state.dragNodeId = null;
|
|
38685
|
+
}
|
|
38686
|
+
},
|
|
38687
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38688
|
+
);
|
|
38689
|
+
const handleMouseMove = React76.useCallback(
|
|
38690
|
+
(e) => {
|
|
38691
|
+
const state = interactionRef.current;
|
|
38692
|
+
if (state.mode === "panning") {
|
|
38693
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38694
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38695
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38696
|
+
return;
|
|
38697
|
+
}
|
|
38698
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38699
|
+
const coords2 = toCoords(e);
|
|
38700
|
+
if (!coords2) return;
|
|
38701
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38702
|
+
if (node2) {
|
|
38703
|
+
node2.x = coords2.graphX;
|
|
38704
|
+
node2.y = coords2.graphY;
|
|
38705
|
+
node2.vx = 0;
|
|
38706
|
+
node2.vy = 0;
|
|
38707
|
+
forceUpdate((n) => n + 1);
|
|
38708
|
+
}
|
|
38709
|
+
return;
|
|
38710
|
+
}
|
|
38711
|
+
const coords = toCoords(e);
|
|
38712
|
+
if (!coords) return;
|
|
38713
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38714
|
+
setHoveredNode(node?.id ?? null);
|
|
38715
|
+
},
|
|
38716
|
+
[toCoords, nodeAt]
|
|
38717
|
+
);
|
|
38718
|
+
const handleMouseUp = React76.useCallback(
|
|
38719
|
+
(e) => {
|
|
38720
|
+
const state = interactionRef.current;
|
|
38721
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38722
|
+
state.mode = "none";
|
|
38723
|
+
state.dragNodeId = null;
|
|
38724
|
+
if (moved < 4) {
|
|
38725
|
+
const coords = toCoords(e);
|
|
38726
|
+
if (!coords) return;
|
|
38727
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38728
|
+
if (node) {
|
|
38729
|
+
handleNodeClick(node);
|
|
38730
|
+
}
|
|
38731
|
+
}
|
|
38732
|
+
},
|
|
38733
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38734
|
+
);
|
|
38735
|
+
const handleMouseLeave = React76.useCallback(() => {
|
|
38736
|
+
interactionRef.current.mode = "none";
|
|
38737
|
+
interactionRef.current.dragNodeId = null;
|
|
38738
|
+
setHoveredNode(null);
|
|
38739
|
+
}, []);
|
|
38610
38740
|
if (isLoading) {
|
|
38611
38741
|
return /* @__PURE__ */ jsxRuntime.jsx(exports.LoadingState, { message: t("common.loading"), className });
|
|
38612
38742
|
}
|
|
@@ -38668,20 +38798,11 @@ var init_GraphCanvas = __esm({
|
|
|
38668
38798
|
height,
|
|
38669
38799
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38670
38800
|
style: { height },
|
|
38671
|
-
|
|
38672
|
-
|
|
38673
|
-
|
|
38674
|
-
|
|
38675
|
-
|
|
38676
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
38677
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
38678
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
38679
|
-
return dist < (n.size || 8) + 4;
|
|
38680
|
-
});
|
|
38681
|
-
if (clickedNode) {
|
|
38682
|
-
handleNodeClick(clickedNode);
|
|
38683
|
-
}
|
|
38684
|
-
}
|
|
38801
|
+
onWheel: handleWheel,
|
|
38802
|
+
onMouseDown: handleMouseDown,
|
|
38803
|
+
onMouseMove: handleMouseMove,
|
|
38804
|
+
onMouseUp: handleMouseUp,
|
|
38805
|
+
onMouseLeave: handleMouseLeave
|
|
38685
38806
|
}
|
|
38686
38807
|
) }),
|
|
38687
38808
|
groups.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(exports.HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxRuntime.jsxs(exports.HStack, { gap: "xs", align: "center", children: [
|
package/dist/components/index.js
CHANGED
|
@@ -38373,6 +38373,9 @@ var init_GraphCanvas = __esm({
|
|
|
38373
38373
|
actions,
|
|
38374
38374
|
onNodeClick,
|
|
38375
38375
|
nodeClickEvent,
|
|
38376
|
+
selectedNodeId,
|
|
38377
|
+
repulsion = 800,
|
|
38378
|
+
linkDistance = 100,
|
|
38376
38379
|
layout = "force",
|
|
38377
38380
|
entity,
|
|
38378
38381
|
isLoading = false,
|
|
@@ -38388,6 +38391,35 @@ var init_GraphCanvas = __esm({
|
|
|
38388
38391
|
const [hoveredNode, setHoveredNode] = useState(null);
|
|
38389
38392
|
const nodesRef = useRef([]);
|
|
38390
38393
|
const [, forceUpdate] = useState(0);
|
|
38394
|
+
const interactionRef = useRef({
|
|
38395
|
+
mode: "none",
|
|
38396
|
+
dragNodeId: null,
|
|
38397
|
+
startMouse: { x: 0, y: 0 },
|
|
38398
|
+
startOffset: { x: 0, y: 0 },
|
|
38399
|
+
downPos: { x: 0, y: 0 }
|
|
38400
|
+
});
|
|
38401
|
+
const toCoords = useCallback(
|
|
38402
|
+
(e) => {
|
|
38403
|
+
const canvas = canvasRef.current;
|
|
38404
|
+
if (!canvas) return null;
|
|
38405
|
+
const rect = canvas.getBoundingClientRect();
|
|
38406
|
+
const screenX = e.clientX - rect.left;
|
|
38407
|
+
const screenY = e.clientY - rect.top;
|
|
38408
|
+
return {
|
|
38409
|
+
screenX,
|
|
38410
|
+
screenY,
|
|
38411
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38412
|
+
graphY: (screenY - offset.y) / zoom
|
|
38413
|
+
};
|
|
38414
|
+
},
|
|
38415
|
+
[offset, zoom]
|
|
38416
|
+
);
|
|
38417
|
+
const nodeAt = useCallback((graphX, graphY) => {
|
|
38418
|
+
return nodesRef.current.find((n) => {
|
|
38419
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38420
|
+
return dist < (n.size || 8) + 4;
|
|
38421
|
+
});
|
|
38422
|
+
}, []);
|
|
38391
38423
|
const handleAction = useCallback(
|
|
38392
38424
|
(action) => {
|
|
38393
38425
|
if (action.event) {
|
|
@@ -38453,7 +38485,7 @@ var init_GraphCanvas = __esm({
|
|
|
38453
38485
|
const dx = nodes[j].x - nodes[i].x;
|
|
38454
38486
|
const dy = nodes[j].y - nodes[i].y;
|
|
38455
38487
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38456
|
-
const force =
|
|
38488
|
+
const force = repulsion / (dist * dist);
|
|
38457
38489
|
const fx = dx / dist * force;
|
|
38458
38490
|
const fy = dy / dist * force;
|
|
38459
38491
|
nodes[i].fx -= fx;
|
|
@@ -38469,7 +38501,7 @@ var init_GraphCanvas = __esm({
|
|
|
38469
38501
|
const dx = target.x - source.x;
|
|
38470
38502
|
const dy = target.y - source.y;
|
|
38471
38503
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38472
|
-
const force = (dist -
|
|
38504
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38473
38505
|
const fx = dx / dist * force;
|
|
38474
38506
|
const fy = dy / dist * force;
|
|
38475
38507
|
source.fx += fx;
|
|
@@ -38503,7 +38535,7 @@ var init_GraphCanvas = __esm({
|
|
|
38503
38535
|
return () => {
|
|
38504
38536
|
cancelAnimationFrame(animRef.current);
|
|
38505
38537
|
};
|
|
38506
|
-
}, [propNodes, propEdges, layout]);
|
|
38538
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38507
38539
|
useEffect(() => {
|
|
38508
38540
|
const canvas = canvasRef.current;
|
|
38509
38541
|
if (!canvas) return;
|
|
@@ -38539,18 +38571,25 @@ var init_GraphCanvas = __esm({
|
|
|
38539
38571
|
const size = node.size || 8;
|
|
38540
38572
|
const color = node.color || getGroupColor(node.group, groups);
|
|
38541
38573
|
const isHovered = hoveredNode === node.id;
|
|
38574
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38575
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38542
38576
|
ctx.beginPath();
|
|
38543
|
-
ctx.arc(node.x, node.y,
|
|
38577
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38544
38578
|
ctx.fillStyle = color;
|
|
38545
38579
|
ctx.fill();
|
|
38546
|
-
|
|
38547
|
-
|
|
38580
|
+
if (isSelected) {
|
|
38581
|
+
ctx.strokeStyle = "var(--color-accent)";
|
|
38582
|
+
ctx.lineWidth = 3;
|
|
38583
|
+
} else {
|
|
38584
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38585
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38586
|
+
}
|
|
38548
38587
|
ctx.stroke();
|
|
38549
38588
|
if (showLabels && node.label) {
|
|
38550
38589
|
ctx.fillStyle = "#666666";
|
|
38551
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38590
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38552
38591
|
ctx.textAlign = "center";
|
|
38553
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38592
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38554
38593
|
}
|
|
38555
38594
|
}
|
|
38556
38595
|
ctx.restore();
|
|
@@ -38561,6 +38600,97 @@ var init_GraphCanvas = __esm({
|
|
|
38561
38600
|
setZoom(1);
|
|
38562
38601
|
setOffset({ x: 0, y: 0 });
|
|
38563
38602
|
}, []);
|
|
38603
|
+
const handleWheel = useCallback(
|
|
38604
|
+
(e) => {
|
|
38605
|
+
if (!interactive) return;
|
|
38606
|
+
e.preventDefault();
|
|
38607
|
+
const coords = toCoords(e);
|
|
38608
|
+
if (!coords) return;
|
|
38609
|
+
const oldZoom = zoom;
|
|
38610
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38611
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38612
|
+
if (newZoom === oldZoom) return;
|
|
38613
|
+
setOffset((o) => ({
|
|
38614
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38615
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38616
|
+
}));
|
|
38617
|
+
setZoom(newZoom);
|
|
38618
|
+
},
|
|
38619
|
+
[interactive, toCoords, zoom]
|
|
38620
|
+
);
|
|
38621
|
+
const handleMouseDown = useCallback(
|
|
38622
|
+
(e) => {
|
|
38623
|
+
const coords = toCoords(e);
|
|
38624
|
+
if (!coords) return;
|
|
38625
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38626
|
+
const state = interactionRef.current;
|
|
38627
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38628
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38629
|
+
state.startOffset = { ...offset };
|
|
38630
|
+
if (draggable && node) {
|
|
38631
|
+
state.mode = "dragging";
|
|
38632
|
+
state.dragNodeId = node.id;
|
|
38633
|
+
} else if (interactive) {
|
|
38634
|
+
state.mode = "panning";
|
|
38635
|
+
state.dragNodeId = null;
|
|
38636
|
+
} else {
|
|
38637
|
+
state.mode = "none";
|
|
38638
|
+
state.dragNodeId = null;
|
|
38639
|
+
}
|
|
38640
|
+
},
|
|
38641
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38642
|
+
);
|
|
38643
|
+
const handleMouseMove = useCallback(
|
|
38644
|
+
(e) => {
|
|
38645
|
+
const state = interactionRef.current;
|
|
38646
|
+
if (state.mode === "panning") {
|
|
38647
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38648
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38649
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38650
|
+
return;
|
|
38651
|
+
}
|
|
38652
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38653
|
+
const coords2 = toCoords(e);
|
|
38654
|
+
if (!coords2) return;
|
|
38655
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38656
|
+
if (node2) {
|
|
38657
|
+
node2.x = coords2.graphX;
|
|
38658
|
+
node2.y = coords2.graphY;
|
|
38659
|
+
node2.vx = 0;
|
|
38660
|
+
node2.vy = 0;
|
|
38661
|
+
forceUpdate((n) => n + 1);
|
|
38662
|
+
}
|
|
38663
|
+
return;
|
|
38664
|
+
}
|
|
38665
|
+
const coords = toCoords(e);
|
|
38666
|
+
if (!coords) return;
|
|
38667
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38668
|
+
setHoveredNode(node?.id ?? null);
|
|
38669
|
+
},
|
|
38670
|
+
[toCoords, nodeAt]
|
|
38671
|
+
);
|
|
38672
|
+
const handleMouseUp = useCallback(
|
|
38673
|
+
(e) => {
|
|
38674
|
+
const state = interactionRef.current;
|
|
38675
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38676
|
+
state.mode = "none";
|
|
38677
|
+
state.dragNodeId = null;
|
|
38678
|
+
if (moved < 4) {
|
|
38679
|
+
const coords = toCoords(e);
|
|
38680
|
+
if (!coords) return;
|
|
38681
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38682
|
+
if (node) {
|
|
38683
|
+
handleNodeClick(node);
|
|
38684
|
+
}
|
|
38685
|
+
}
|
|
38686
|
+
},
|
|
38687
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38688
|
+
);
|
|
38689
|
+
const handleMouseLeave = useCallback(() => {
|
|
38690
|
+
interactionRef.current.mode = "none";
|
|
38691
|
+
interactionRef.current.dragNodeId = null;
|
|
38692
|
+
setHoveredNode(null);
|
|
38693
|
+
}, []);
|
|
38564
38694
|
if (isLoading) {
|
|
38565
38695
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
38566
38696
|
}
|
|
@@ -38622,20 +38752,11 @@ var init_GraphCanvas = __esm({
|
|
|
38622
38752
|
height,
|
|
38623
38753
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38624
38754
|
style: { height },
|
|
38625
|
-
|
|
38626
|
-
|
|
38627
|
-
|
|
38628
|
-
|
|
38629
|
-
|
|
38630
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
38631
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
38632
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
38633
|
-
return dist < (n.size || 8) + 4;
|
|
38634
|
-
});
|
|
38635
|
-
if (clickedNode) {
|
|
38636
|
-
handleNodeClick(clickedNode);
|
|
38637
|
-
}
|
|
38638
|
-
}
|
|
38755
|
+
onWheel: handleWheel,
|
|
38756
|
+
onMouseDown: handleMouseDown,
|
|
38757
|
+
onMouseMove: handleMouseMove,
|
|
38758
|
+
onMouseUp: handleMouseUp,
|
|
38759
|
+
onMouseLeave: handleMouseLeave
|
|
38639
38760
|
}
|
|
38640
38761
|
) }),
|
|
38641
38762
|
groups.length > 1 && /* @__PURE__ */ jsx(HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxs(HStack, { gap: "xs", align: "center", children: [
|
package/dist/providers/index.cjs
CHANGED
|
@@ -38000,6 +38000,9 @@ var init_GraphCanvas = __esm({
|
|
|
38000
38000
|
actions,
|
|
38001
38001
|
onNodeClick,
|
|
38002
38002
|
nodeClickEvent,
|
|
38003
|
+
selectedNodeId,
|
|
38004
|
+
repulsion = 800,
|
|
38005
|
+
linkDistance = 100,
|
|
38003
38006
|
layout = "force",
|
|
38004
38007
|
entity,
|
|
38005
38008
|
isLoading = false,
|
|
@@ -38015,6 +38018,35 @@ var init_GraphCanvas = __esm({
|
|
|
38015
38018
|
const [hoveredNode, setHoveredNode] = React82.useState(null);
|
|
38016
38019
|
const nodesRef = React82.useRef([]);
|
|
38017
38020
|
const [, forceUpdate] = React82.useState(0);
|
|
38021
|
+
const interactionRef = React82.useRef({
|
|
38022
|
+
mode: "none",
|
|
38023
|
+
dragNodeId: null,
|
|
38024
|
+
startMouse: { x: 0, y: 0 },
|
|
38025
|
+
startOffset: { x: 0, y: 0 },
|
|
38026
|
+
downPos: { x: 0, y: 0 }
|
|
38027
|
+
});
|
|
38028
|
+
const toCoords = React82.useCallback(
|
|
38029
|
+
(e) => {
|
|
38030
|
+
const canvas = canvasRef.current;
|
|
38031
|
+
if (!canvas) return null;
|
|
38032
|
+
const rect = canvas.getBoundingClientRect();
|
|
38033
|
+
const screenX = e.clientX - rect.left;
|
|
38034
|
+
const screenY = e.clientY - rect.top;
|
|
38035
|
+
return {
|
|
38036
|
+
screenX,
|
|
38037
|
+
screenY,
|
|
38038
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38039
|
+
graphY: (screenY - offset.y) / zoom
|
|
38040
|
+
};
|
|
38041
|
+
},
|
|
38042
|
+
[offset, zoom]
|
|
38043
|
+
);
|
|
38044
|
+
const nodeAt = React82.useCallback((graphX, graphY) => {
|
|
38045
|
+
return nodesRef.current.find((n) => {
|
|
38046
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38047
|
+
return dist < (n.size || 8) + 4;
|
|
38048
|
+
});
|
|
38049
|
+
}, []);
|
|
38018
38050
|
const handleAction = React82.useCallback(
|
|
38019
38051
|
(action) => {
|
|
38020
38052
|
if (action.event) {
|
|
@@ -38080,7 +38112,7 @@ var init_GraphCanvas = __esm({
|
|
|
38080
38112
|
const dx = nodes[j].x - nodes[i].x;
|
|
38081
38113
|
const dy = nodes[j].y - nodes[i].y;
|
|
38082
38114
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38083
|
-
const force =
|
|
38115
|
+
const force = repulsion / (dist * dist);
|
|
38084
38116
|
const fx = dx / dist * force;
|
|
38085
38117
|
const fy = dy / dist * force;
|
|
38086
38118
|
nodes[i].fx -= fx;
|
|
@@ -38096,7 +38128,7 @@ var init_GraphCanvas = __esm({
|
|
|
38096
38128
|
const dx = target.x - source.x;
|
|
38097
38129
|
const dy = target.y - source.y;
|
|
38098
38130
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38099
|
-
const force = (dist -
|
|
38131
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38100
38132
|
const fx = dx / dist * force;
|
|
38101
38133
|
const fy = dy / dist * force;
|
|
38102
38134
|
source.fx += fx;
|
|
@@ -38130,7 +38162,7 @@ var init_GraphCanvas = __esm({
|
|
|
38130
38162
|
return () => {
|
|
38131
38163
|
cancelAnimationFrame(animRef.current);
|
|
38132
38164
|
};
|
|
38133
|
-
}, [propNodes, propEdges, layout]);
|
|
38165
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38134
38166
|
React82.useEffect(() => {
|
|
38135
38167
|
const canvas = canvasRef.current;
|
|
38136
38168
|
if (!canvas) return;
|
|
@@ -38166,18 +38198,25 @@ var init_GraphCanvas = __esm({
|
|
|
38166
38198
|
const size = node.size || 8;
|
|
38167
38199
|
const color = node.color || getGroupColor(node.group, groups);
|
|
38168
38200
|
const isHovered = hoveredNode === node.id;
|
|
38201
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38202
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38169
38203
|
ctx.beginPath();
|
|
38170
|
-
ctx.arc(node.x, node.y,
|
|
38204
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38171
38205
|
ctx.fillStyle = color;
|
|
38172
38206
|
ctx.fill();
|
|
38173
|
-
|
|
38174
|
-
|
|
38207
|
+
if (isSelected) {
|
|
38208
|
+
ctx.strokeStyle = "var(--color-accent)";
|
|
38209
|
+
ctx.lineWidth = 3;
|
|
38210
|
+
} else {
|
|
38211
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38212
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38213
|
+
}
|
|
38175
38214
|
ctx.stroke();
|
|
38176
38215
|
if (showLabels && node.label) {
|
|
38177
38216
|
ctx.fillStyle = "#666666";
|
|
38178
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38217
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38179
38218
|
ctx.textAlign = "center";
|
|
38180
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38219
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38181
38220
|
}
|
|
38182
38221
|
}
|
|
38183
38222
|
ctx.restore();
|
|
@@ -38188,6 +38227,97 @@ var init_GraphCanvas = __esm({
|
|
|
38188
38227
|
setZoom(1);
|
|
38189
38228
|
setOffset({ x: 0, y: 0 });
|
|
38190
38229
|
}, []);
|
|
38230
|
+
const handleWheel = React82.useCallback(
|
|
38231
|
+
(e) => {
|
|
38232
|
+
if (!interactive) return;
|
|
38233
|
+
e.preventDefault();
|
|
38234
|
+
const coords = toCoords(e);
|
|
38235
|
+
if (!coords) return;
|
|
38236
|
+
const oldZoom = zoom;
|
|
38237
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38238
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38239
|
+
if (newZoom === oldZoom) return;
|
|
38240
|
+
setOffset((o) => ({
|
|
38241
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38242
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38243
|
+
}));
|
|
38244
|
+
setZoom(newZoom);
|
|
38245
|
+
},
|
|
38246
|
+
[interactive, toCoords, zoom]
|
|
38247
|
+
);
|
|
38248
|
+
const handleMouseDown = React82.useCallback(
|
|
38249
|
+
(e) => {
|
|
38250
|
+
const coords = toCoords(e);
|
|
38251
|
+
if (!coords) return;
|
|
38252
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38253
|
+
const state = interactionRef.current;
|
|
38254
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38255
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38256
|
+
state.startOffset = { ...offset };
|
|
38257
|
+
if (draggable && node) {
|
|
38258
|
+
state.mode = "dragging";
|
|
38259
|
+
state.dragNodeId = node.id;
|
|
38260
|
+
} else if (interactive) {
|
|
38261
|
+
state.mode = "panning";
|
|
38262
|
+
state.dragNodeId = null;
|
|
38263
|
+
} else {
|
|
38264
|
+
state.mode = "none";
|
|
38265
|
+
state.dragNodeId = null;
|
|
38266
|
+
}
|
|
38267
|
+
},
|
|
38268
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38269
|
+
);
|
|
38270
|
+
const handleMouseMove = React82.useCallback(
|
|
38271
|
+
(e) => {
|
|
38272
|
+
const state = interactionRef.current;
|
|
38273
|
+
if (state.mode === "panning") {
|
|
38274
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38275
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38276
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38277
|
+
return;
|
|
38278
|
+
}
|
|
38279
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38280
|
+
const coords2 = toCoords(e);
|
|
38281
|
+
if (!coords2) return;
|
|
38282
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38283
|
+
if (node2) {
|
|
38284
|
+
node2.x = coords2.graphX;
|
|
38285
|
+
node2.y = coords2.graphY;
|
|
38286
|
+
node2.vx = 0;
|
|
38287
|
+
node2.vy = 0;
|
|
38288
|
+
forceUpdate((n) => n + 1);
|
|
38289
|
+
}
|
|
38290
|
+
return;
|
|
38291
|
+
}
|
|
38292
|
+
const coords = toCoords(e);
|
|
38293
|
+
if (!coords) return;
|
|
38294
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38295
|
+
setHoveredNode(node?.id ?? null);
|
|
38296
|
+
},
|
|
38297
|
+
[toCoords, nodeAt]
|
|
38298
|
+
);
|
|
38299
|
+
const handleMouseUp = React82.useCallback(
|
|
38300
|
+
(e) => {
|
|
38301
|
+
const state = interactionRef.current;
|
|
38302
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38303
|
+
state.mode = "none";
|
|
38304
|
+
state.dragNodeId = null;
|
|
38305
|
+
if (moved < 4) {
|
|
38306
|
+
const coords = toCoords(e);
|
|
38307
|
+
if (!coords) return;
|
|
38308
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38309
|
+
if (node) {
|
|
38310
|
+
handleNodeClick(node);
|
|
38311
|
+
}
|
|
38312
|
+
}
|
|
38313
|
+
},
|
|
38314
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38315
|
+
);
|
|
38316
|
+
const handleMouseLeave = React82.useCallback(() => {
|
|
38317
|
+
interactionRef.current.mode = "none";
|
|
38318
|
+
interactionRef.current.dragNodeId = null;
|
|
38319
|
+
setHoveredNode(null);
|
|
38320
|
+
}, []);
|
|
38191
38321
|
if (isLoading) {
|
|
38192
38322
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
38193
38323
|
}
|
|
@@ -38249,20 +38379,11 @@ var init_GraphCanvas = __esm({
|
|
|
38249
38379
|
height,
|
|
38250
38380
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38251
38381
|
style: { height },
|
|
38252
|
-
|
|
38253
|
-
|
|
38254
|
-
|
|
38255
|
-
|
|
38256
|
-
|
|
38257
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
38258
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
38259
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
38260
|
-
return dist < (n.size || 8) + 4;
|
|
38261
|
-
});
|
|
38262
|
-
if (clickedNode) {
|
|
38263
|
-
handleNodeClick(clickedNode);
|
|
38264
|
-
}
|
|
38265
|
-
}
|
|
38382
|
+
onWheel: handleWheel,
|
|
38383
|
+
onMouseDown: handleMouseDown,
|
|
38384
|
+
onMouseMove: handleMouseMove,
|
|
38385
|
+
onMouseUp: handleMouseUp,
|
|
38386
|
+
onMouseLeave: handleMouseLeave
|
|
38266
38387
|
}
|
|
38267
38388
|
) }),
|
|
38268
38389
|
groups.length > 1 && /* @__PURE__ */ jsxRuntime.jsx(HStack, { gap: "md", className: "px-4 py-2 border-t border-border", wrap: true, children: groups.map((group, idx) => /* @__PURE__ */ jsxRuntime.jsxs(HStack, { gap: "xs", align: "center", children: [
|