@almadar/ui 5.58.0 → 5.60.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 +153 -23
- package/dist/avl/index.js +153 -23
- package/dist/components/core/molecules/GraphCanvas.d.ts +6 -0
- package/dist/components/index.cjs +153 -23
- package/dist/components/index.js +153 -23
- package/dist/providers/index.cjs +153 -23
- package/dist/providers/index.js +153 -23
- package/dist/runtime/index.cjs +153 -23
- package/dist/runtime/index.js +153 -23
- package/package.json +1 -1
package/dist/runtime/index.cjs
CHANGED
|
@@ -37668,6 +37668,12 @@ function getGroupColor(group, groups) {
|
|
|
37668
37668
|
const idx = groups.indexOf(group);
|
|
37669
37669
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
37670
37670
|
}
|
|
37671
|
+
function resolveColor2(color, el) {
|
|
37672
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
37673
|
+
if (!m) return color;
|
|
37674
|
+
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
37675
|
+
return resolved || (m[2]?.trim() ?? "#888888");
|
|
37676
|
+
}
|
|
37671
37677
|
var GROUP_COLORS2, GraphCanvas;
|
|
37672
37678
|
var init_GraphCanvas = __esm({
|
|
37673
37679
|
"components/core/molecules/GraphCanvas.tsx"() {
|
|
@@ -37698,6 +37704,9 @@ var init_GraphCanvas = __esm({
|
|
|
37698
37704
|
actions,
|
|
37699
37705
|
onNodeClick,
|
|
37700
37706
|
nodeClickEvent,
|
|
37707
|
+
selectedNodeId,
|
|
37708
|
+
repulsion = 800,
|
|
37709
|
+
linkDistance = 100,
|
|
37701
37710
|
layout = "force",
|
|
37702
37711
|
entity,
|
|
37703
37712
|
isLoading = false,
|
|
@@ -37713,6 +37722,37 @@ var init_GraphCanvas = __esm({
|
|
|
37713
37722
|
const [hoveredNode, setHoveredNode] = React81.useState(null);
|
|
37714
37723
|
const nodesRef = React81.useRef([]);
|
|
37715
37724
|
const [, forceUpdate] = React81.useState(0);
|
|
37725
|
+
const interactionRef = React81.useRef({
|
|
37726
|
+
mode: "none",
|
|
37727
|
+
dragNodeId: null,
|
|
37728
|
+
startMouse: { x: 0, y: 0 },
|
|
37729
|
+
startOffset: { x: 0, y: 0 },
|
|
37730
|
+
downPos: { x: 0, y: 0 }
|
|
37731
|
+
});
|
|
37732
|
+
const toCoords = React81.useCallback(
|
|
37733
|
+
(e) => {
|
|
37734
|
+
const canvas = canvasRef.current;
|
|
37735
|
+
if (!canvas) return null;
|
|
37736
|
+
const rect = canvas.getBoundingClientRect();
|
|
37737
|
+
const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
37738
|
+
const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
37739
|
+
const screenX = (e.clientX - rect.left) * scaleX;
|
|
37740
|
+
const screenY = (e.clientY - rect.top) * scaleY;
|
|
37741
|
+
return {
|
|
37742
|
+
screenX,
|
|
37743
|
+
screenY,
|
|
37744
|
+
graphX: (screenX - offset.x) / zoom,
|
|
37745
|
+
graphY: (screenY - offset.y) / zoom
|
|
37746
|
+
};
|
|
37747
|
+
},
|
|
37748
|
+
[offset, zoom]
|
|
37749
|
+
);
|
|
37750
|
+
const nodeAt = React81.useCallback((graphX, graphY) => {
|
|
37751
|
+
return nodesRef.current.find((n) => {
|
|
37752
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
37753
|
+
return dist < (n.size || 8) + 4;
|
|
37754
|
+
});
|
|
37755
|
+
}, []);
|
|
37716
37756
|
const handleAction = React81.useCallback(
|
|
37717
37757
|
(action) => {
|
|
37718
37758
|
if (action.event) {
|
|
@@ -37778,7 +37818,7 @@ var init_GraphCanvas = __esm({
|
|
|
37778
37818
|
const dx = nodes[j].x - nodes[i].x;
|
|
37779
37819
|
const dy = nodes[j].y - nodes[i].y;
|
|
37780
37820
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37781
|
-
const force =
|
|
37821
|
+
const force = repulsion / (dist * dist);
|
|
37782
37822
|
const fx = dx / dist * force;
|
|
37783
37823
|
const fy = dy / dist * force;
|
|
37784
37824
|
nodes[i].fx -= fx;
|
|
@@ -37794,7 +37834,7 @@ var init_GraphCanvas = __esm({
|
|
|
37794
37834
|
const dx = target.x - source.x;
|
|
37795
37835
|
const dy = target.y - source.y;
|
|
37796
37836
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37797
|
-
const force = (dist -
|
|
37837
|
+
const force = (dist - linkDistance) * 0.05;
|
|
37798
37838
|
const fx = dx / dist * force;
|
|
37799
37839
|
const fy = dy / dist * force;
|
|
37800
37840
|
source.fx += fx;
|
|
@@ -37828,7 +37868,7 @@ var init_GraphCanvas = __esm({
|
|
|
37828
37868
|
return () => {
|
|
37829
37869
|
cancelAnimationFrame(animRef.current);
|
|
37830
37870
|
};
|
|
37831
|
-
}, [propNodes, propEdges, layout]);
|
|
37871
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
37832
37872
|
React81.useEffect(() => {
|
|
37833
37873
|
const canvas = canvasRef.current;
|
|
37834
37874
|
if (!canvas) return;
|
|
@@ -37837,6 +37877,7 @@ var init_GraphCanvas = __esm({
|
|
|
37837
37877
|
const w = canvas.width;
|
|
37838
37878
|
const h = canvas.height;
|
|
37839
37879
|
const nodes = nodesRef.current;
|
|
37880
|
+
const accentColor = resolveColor2("var(--color-accent)", canvas);
|
|
37840
37881
|
ctx.clearRect(0, 0, w, h);
|
|
37841
37882
|
ctx.save();
|
|
37842
37883
|
ctx.translate(offset.x, offset.y);
|
|
@@ -37862,20 +37903,27 @@ var init_GraphCanvas = __esm({
|
|
|
37862
37903
|
}
|
|
37863
37904
|
for (const node of nodes) {
|
|
37864
37905
|
const size = node.size || 8;
|
|
37865
|
-
const color = node.color || getGroupColor(node.group, groups);
|
|
37906
|
+
const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
|
|
37866
37907
|
const isHovered = hoveredNode === node.id;
|
|
37908
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
37909
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
37867
37910
|
ctx.beginPath();
|
|
37868
|
-
ctx.arc(node.x, node.y,
|
|
37911
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
37869
37912
|
ctx.fillStyle = color;
|
|
37870
37913
|
ctx.fill();
|
|
37871
|
-
|
|
37872
|
-
|
|
37914
|
+
if (isSelected) {
|
|
37915
|
+
ctx.strokeStyle = accentColor;
|
|
37916
|
+
ctx.lineWidth = 3;
|
|
37917
|
+
} else {
|
|
37918
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
37919
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
37920
|
+
}
|
|
37873
37921
|
ctx.stroke();
|
|
37874
37922
|
if (showLabels && node.label) {
|
|
37875
37923
|
ctx.fillStyle = "#666666";
|
|
37876
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
37924
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
37877
37925
|
ctx.textAlign = "center";
|
|
37878
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
37926
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
37879
37927
|
}
|
|
37880
37928
|
}
|
|
37881
37929
|
ctx.restore();
|
|
@@ -37886,6 +37934,97 @@ var init_GraphCanvas = __esm({
|
|
|
37886
37934
|
setZoom(1);
|
|
37887
37935
|
setOffset({ x: 0, y: 0 });
|
|
37888
37936
|
}, []);
|
|
37937
|
+
const handleWheel = React81.useCallback(
|
|
37938
|
+
(e) => {
|
|
37939
|
+
if (!interactive) return;
|
|
37940
|
+
e.preventDefault();
|
|
37941
|
+
const coords = toCoords(e);
|
|
37942
|
+
if (!coords) return;
|
|
37943
|
+
const oldZoom = zoom;
|
|
37944
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
37945
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
37946
|
+
if (newZoom === oldZoom) return;
|
|
37947
|
+
setOffset((o) => ({
|
|
37948
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
37949
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
37950
|
+
}));
|
|
37951
|
+
setZoom(newZoom);
|
|
37952
|
+
},
|
|
37953
|
+
[interactive, toCoords, zoom]
|
|
37954
|
+
);
|
|
37955
|
+
const handleMouseDown = React81.useCallback(
|
|
37956
|
+
(e) => {
|
|
37957
|
+
const coords = toCoords(e);
|
|
37958
|
+
if (!coords) return;
|
|
37959
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37960
|
+
const state = interactionRef.current;
|
|
37961
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
37962
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
37963
|
+
state.startOffset = { ...offset };
|
|
37964
|
+
if (draggable && node) {
|
|
37965
|
+
state.mode = "dragging";
|
|
37966
|
+
state.dragNodeId = node.id;
|
|
37967
|
+
} else if (interactive) {
|
|
37968
|
+
state.mode = "panning";
|
|
37969
|
+
state.dragNodeId = null;
|
|
37970
|
+
} else {
|
|
37971
|
+
state.mode = "none";
|
|
37972
|
+
state.dragNodeId = null;
|
|
37973
|
+
}
|
|
37974
|
+
},
|
|
37975
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
37976
|
+
);
|
|
37977
|
+
const handleMouseMove = React81.useCallback(
|
|
37978
|
+
(e) => {
|
|
37979
|
+
const state = interactionRef.current;
|
|
37980
|
+
if (state.mode === "panning") {
|
|
37981
|
+
const dx = e.clientX - state.startMouse.x;
|
|
37982
|
+
const dy = e.clientY - state.startMouse.y;
|
|
37983
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
37984
|
+
return;
|
|
37985
|
+
}
|
|
37986
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
37987
|
+
const coords2 = toCoords(e);
|
|
37988
|
+
if (!coords2) return;
|
|
37989
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
37990
|
+
if (node2) {
|
|
37991
|
+
node2.x = coords2.graphX;
|
|
37992
|
+
node2.y = coords2.graphY;
|
|
37993
|
+
node2.vx = 0;
|
|
37994
|
+
node2.vy = 0;
|
|
37995
|
+
forceUpdate((n) => n + 1);
|
|
37996
|
+
}
|
|
37997
|
+
return;
|
|
37998
|
+
}
|
|
37999
|
+
const coords = toCoords(e);
|
|
38000
|
+
if (!coords) return;
|
|
38001
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38002
|
+
setHoveredNode(node?.id ?? null);
|
|
38003
|
+
},
|
|
38004
|
+
[toCoords, nodeAt]
|
|
38005
|
+
);
|
|
38006
|
+
const handleMouseUp = React81.useCallback(
|
|
38007
|
+
(e) => {
|
|
38008
|
+
const state = interactionRef.current;
|
|
38009
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38010
|
+
state.mode = "none";
|
|
38011
|
+
state.dragNodeId = null;
|
|
38012
|
+
if (moved < 4) {
|
|
38013
|
+
const coords = toCoords(e);
|
|
38014
|
+
if (!coords) return;
|
|
38015
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38016
|
+
if (node) {
|
|
38017
|
+
handleNodeClick(node);
|
|
38018
|
+
}
|
|
38019
|
+
}
|
|
38020
|
+
},
|
|
38021
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38022
|
+
);
|
|
38023
|
+
const handleMouseLeave = React81.useCallback(() => {
|
|
38024
|
+
interactionRef.current.mode = "none";
|
|
38025
|
+
interactionRef.current.dragNodeId = null;
|
|
38026
|
+
setHoveredNode(null);
|
|
38027
|
+
}, []);
|
|
37889
38028
|
if (isLoading) {
|
|
37890
38029
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
37891
38030
|
}
|
|
@@ -37947,20 +38086,11 @@ var init_GraphCanvas = __esm({
|
|
|
37947
38086
|
height,
|
|
37948
38087
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
37949
38088
|
style: { height },
|
|
37950
|
-
|
|
37951
|
-
|
|
37952
|
-
|
|
37953
|
-
|
|
37954
|
-
|
|
37955
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
37956
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
37957
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
37958
|
-
return dist < (n.size || 8) + 4;
|
|
37959
|
-
});
|
|
37960
|
-
if (clickedNode) {
|
|
37961
|
-
handleNodeClick(clickedNode);
|
|
37962
|
-
}
|
|
37963
|
-
}
|
|
38089
|
+
onWheel: handleWheel,
|
|
38090
|
+
onMouseDown: handleMouseDown,
|
|
38091
|
+
onMouseMove: handleMouseMove,
|
|
38092
|
+
onMouseUp: handleMouseUp,
|
|
38093
|
+
onMouseLeave: handleMouseLeave
|
|
37964
38094
|
}
|
|
37965
38095
|
) }),
|
|
37966
38096
|
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: [
|
package/dist/runtime/index.js
CHANGED
|
@@ -37621,6 +37621,12 @@ function getGroupColor(group, groups) {
|
|
|
37621
37621
|
const idx = groups.indexOf(group);
|
|
37622
37622
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
37623
37623
|
}
|
|
37624
|
+
function resolveColor2(color, el) {
|
|
37625
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
37626
|
+
if (!m) return color;
|
|
37627
|
+
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
37628
|
+
return resolved || (m[2]?.trim() ?? "#888888");
|
|
37629
|
+
}
|
|
37624
37630
|
var GROUP_COLORS2, GraphCanvas;
|
|
37625
37631
|
var init_GraphCanvas = __esm({
|
|
37626
37632
|
"components/core/molecules/GraphCanvas.tsx"() {
|
|
@@ -37651,6 +37657,9 @@ var init_GraphCanvas = __esm({
|
|
|
37651
37657
|
actions,
|
|
37652
37658
|
onNodeClick,
|
|
37653
37659
|
nodeClickEvent,
|
|
37660
|
+
selectedNodeId,
|
|
37661
|
+
repulsion = 800,
|
|
37662
|
+
linkDistance = 100,
|
|
37654
37663
|
layout = "force",
|
|
37655
37664
|
entity,
|
|
37656
37665
|
isLoading = false,
|
|
@@ -37666,6 +37675,37 @@ var init_GraphCanvas = __esm({
|
|
|
37666
37675
|
const [hoveredNode, setHoveredNode] = useState(null);
|
|
37667
37676
|
const nodesRef = useRef([]);
|
|
37668
37677
|
const [, forceUpdate] = useState(0);
|
|
37678
|
+
const interactionRef = useRef({
|
|
37679
|
+
mode: "none",
|
|
37680
|
+
dragNodeId: null,
|
|
37681
|
+
startMouse: { x: 0, y: 0 },
|
|
37682
|
+
startOffset: { x: 0, y: 0 },
|
|
37683
|
+
downPos: { x: 0, y: 0 }
|
|
37684
|
+
});
|
|
37685
|
+
const toCoords = useCallback(
|
|
37686
|
+
(e) => {
|
|
37687
|
+
const canvas = canvasRef.current;
|
|
37688
|
+
if (!canvas) return null;
|
|
37689
|
+
const rect = canvas.getBoundingClientRect();
|
|
37690
|
+
const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
37691
|
+
const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
37692
|
+
const screenX = (e.clientX - rect.left) * scaleX;
|
|
37693
|
+
const screenY = (e.clientY - rect.top) * scaleY;
|
|
37694
|
+
return {
|
|
37695
|
+
screenX,
|
|
37696
|
+
screenY,
|
|
37697
|
+
graphX: (screenX - offset.x) / zoom,
|
|
37698
|
+
graphY: (screenY - offset.y) / zoom
|
|
37699
|
+
};
|
|
37700
|
+
},
|
|
37701
|
+
[offset, zoom]
|
|
37702
|
+
);
|
|
37703
|
+
const nodeAt = useCallback((graphX, graphY) => {
|
|
37704
|
+
return nodesRef.current.find((n) => {
|
|
37705
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
37706
|
+
return dist < (n.size || 8) + 4;
|
|
37707
|
+
});
|
|
37708
|
+
}, []);
|
|
37669
37709
|
const handleAction = useCallback(
|
|
37670
37710
|
(action) => {
|
|
37671
37711
|
if (action.event) {
|
|
@@ -37731,7 +37771,7 @@ var init_GraphCanvas = __esm({
|
|
|
37731
37771
|
const dx = nodes[j].x - nodes[i].x;
|
|
37732
37772
|
const dy = nodes[j].y - nodes[i].y;
|
|
37733
37773
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37734
|
-
const force =
|
|
37774
|
+
const force = repulsion / (dist * dist);
|
|
37735
37775
|
const fx = dx / dist * force;
|
|
37736
37776
|
const fy = dy / dist * force;
|
|
37737
37777
|
nodes[i].fx -= fx;
|
|
@@ -37747,7 +37787,7 @@ var init_GraphCanvas = __esm({
|
|
|
37747
37787
|
const dx = target.x - source.x;
|
|
37748
37788
|
const dy = target.y - source.y;
|
|
37749
37789
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37750
|
-
const force = (dist -
|
|
37790
|
+
const force = (dist - linkDistance) * 0.05;
|
|
37751
37791
|
const fx = dx / dist * force;
|
|
37752
37792
|
const fy = dy / dist * force;
|
|
37753
37793
|
source.fx += fx;
|
|
@@ -37781,7 +37821,7 @@ var init_GraphCanvas = __esm({
|
|
|
37781
37821
|
return () => {
|
|
37782
37822
|
cancelAnimationFrame(animRef.current);
|
|
37783
37823
|
};
|
|
37784
|
-
}, [propNodes, propEdges, layout]);
|
|
37824
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
37785
37825
|
useEffect(() => {
|
|
37786
37826
|
const canvas = canvasRef.current;
|
|
37787
37827
|
if (!canvas) return;
|
|
@@ -37790,6 +37830,7 @@ var init_GraphCanvas = __esm({
|
|
|
37790
37830
|
const w = canvas.width;
|
|
37791
37831
|
const h = canvas.height;
|
|
37792
37832
|
const nodes = nodesRef.current;
|
|
37833
|
+
const accentColor = resolveColor2("var(--color-accent)", canvas);
|
|
37793
37834
|
ctx.clearRect(0, 0, w, h);
|
|
37794
37835
|
ctx.save();
|
|
37795
37836
|
ctx.translate(offset.x, offset.y);
|
|
@@ -37815,20 +37856,27 @@ var init_GraphCanvas = __esm({
|
|
|
37815
37856
|
}
|
|
37816
37857
|
for (const node of nodes) {
|
|
37817
37858
|
const size = node.size || 8;
|
|
37818
|
-
const color = node.color || getGroupColor(node.group, groups);
|
|
37859
|
+
const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
|
|
37819
37860
|
const isHovered = hoveredNode === node.id;
|
|
37861
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
37862
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
37820
37863
|
ctx.beginPath();
|
|
37821
|
-
ctx.arc(node.x, node.y,
|
|
37864
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
37822
37865
|
ctx.fillStyle = color;
|
|
37823
37866
|
ctx.fill();
|
|
37824
|
-
|
|
37825
|
-
|
|
37867
|
+
if (isSelected) {
|
|
37868
|
+
ctx.strokeStyle = accentColor;
|
|
37869
|
+
ctx.lineWidth = 3;
|
|
37870
|
+
} else {
|
|
37871
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
37872
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
37873
|
+
}
|
|
37826
37874
|
ctx.stroke();
|
|
37827
37875
|
if (showLabels && node.label) {
|
|
37828
37876
|
ctx.fillStyle = "#666666";
|
|
37829
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
37877
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
37830
37878
|
ctx.textAlign = "center";
|
|
37831
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
37879
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
37832
37880
|
}
|
|
37833
37881
|
}
|
|
37834
37882
|
ctx.restore();
|
|
@@ -37839,6 +37887,97 @@ var init_GraphCanvas = __esm({
|
|
|
37839
37887
|
setZoom(1);
|
|
37840
37888
|
setOffset({ x: 0, y: 0 });
|
|
37841
37889
|
}, []);
|
|
37890
|
+
const handleWheel = useCallback(
|
|
37891
|
+
(e) => {
|
|
37892
|
+
if (!interactive) return;
|
|
37893
|
+
e.preventDefault();
|
|
37894
|
+
const coords = toCoords(e);
|
|
37895
|
+
if (!coords) return;
|
|
37896
|
+
const oldZoom = zoom;
|
|
37897
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
37898
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
37899
|
+
if (newZoom === oldZoom) return;
|
|
37900
|
+
setOffset((o) => ({
|
|
37901
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
37902
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
37903
|
+
}));
|
|
37904
|
+
setZoom(newZoom);
|
|
37905
|
+
},
|
|
37906
|
+
[interactive, toCoords, zoom]
|
|
37907
|
+
);
|
|
37908
|
+
const handleMouseDown = useCallback(
|
|
37909
|
+
(e) => {
|
|
37910
|
+
const coords = toCoords(e);
|
|
37911
|
+
if (!coords) return;
|
|
37912
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37913
|
+
const state = interactionRef.current;
|
|
37914
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
37915
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
37916
|
+
state.startOffset = { ...offset };
|
|
37917
|
+
if (draggable && node) {
|
|
37918
|
+
state.mode = "dragging";
|
|
37919
|
+
state.dragNodeId = node.id;
|
|
37920
|
+
} else if (interactive) {
|
|
37921
|
+
state.mode = "panning";
|
|
37922
|
+
state.dragNodeId = null;
|
|
37923
|
+
} else {
|
|
37924
|
+
state.mode = "none";
|
|
37925
|
+
state.dragNodeId = null;
|
|
37926
|
+
}
|
|
37927
|
+
},
|
|
37928
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
37929
|
+
);
|
|
37930
|
+
const handleMouseMove = useCallback(
|
|
37931
|
+
(e) => {
|
|
37932
|
+
const state = interactionRef.current;
|
|
37933
|
+
if (state.mode === "panning") {
|
|
37934
|
+
const dx = e.clientX - state.startMouse.x;
|
|
37935
|
+
const dy = e.clientY - state.startMouse.y;
|
|
37936
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
37937
|
+
return;
|
|
37938
|
+
}
|
|
37939
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
37940
|
+
const coords2 = toCoords(e);
|
|
37941
|
+
if (!coords2) return;
|
|
37942
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
37943
|
+
if (node2) {
|
|
37944
|
+
node2.x = coords2.graphX;
|
|
37945
|
+
node2.y = coords2.graphY;
|
|
37946
|
+
node2.vx = 0;
|
|
37947
|
+
node2.vy = 0;
|
|
37948
|
+
forceUpdate((n) => n + 1);
|
|
37949
|
+
}
|
|
37950
|
+
return;
|
|
37951
|
+
}
|
|
37952
|
+
const coords = toCoords(e);
|
|
37953
|
+
if (!coords) return;
|
|
37954
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37955
|
+
setHoveredNode(node?.id ?? null);
|
|
37956
|
+
},
|
|
37957
|
+
[toCoords, nodeAt]
|
|
37958
|
+
);
|
|
37959
|
+
const handleMouseUp = useCallback(
|
|
37960
|
+
(e) => {
|
|
37961
|
+
const state = interactionRef.current;
|
|
37962
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
37963
|
+
state.mode = "none";
|
|
37964
|
+
state.dragNodeId = null;
|
|
37965
|
+
if (moved < 4) {
|
|
37966
|
+
const coords = toCoords(e);
|
|
37967
|
+
if (!coords) return;
|
|
37968
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37969
|
+
if (node) {
|
|
37970
|
+
handleNodeClick(node);
|
|
37971
|
+
}
|
|
37972
|
+
}
|
|
37973
|
+
},
|
|
37974
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
37975
|
+
);
|
|
37976
|
+
const handleMouseLeave = useCallback(() => {
|
|
37977
|
+
interactionRef.current.mode = "none";
|
|
37978
|
+
interactionRef.current.dragNodeId = null;
|
|
37979
|
+
setHoveredNode(null);
|
|
37980
|
+
}, []);
|
|
37842
37981
|
if (isLoading) {
|
|
37843
37982
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
37844
37983
|
}
|
|
@@ -37900,20 +38039,11 @@ var init_GraphCanvas = __esm({
|
|
|
37900
38039
|
height,
|
|
37901
38040
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
37902
38041
|
style: { height },
|
|
37903
|
-
|
|
37904
|
-
|
|
37905
|
-
|
|
37906
|
-
|
|
37907
|
-
|
|
37908
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
37909
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
37910
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
37911
|
-
return dist < (n.size || 8) + 4;
|
|
37912
|
-
});
|
|
37913
|
-
if (clickedNode) {
|
|
37914
|
-
handleNodeClick(clickedNode);
|
|
37915
|
-
}
|
|
37916
|
-
}
|
|
38042
|
+
onWheel: handleWheel,
|
|
38043
|
+
onMouseDown: handleMouseDown,
|
|
38044
|
+
onMouseMove: handleMouseMove,
|
|
38045
|
+
onMouseUp: handleMouseUp,
|
|
38046
|
+
onMouseLeave: handleMouseLeave
|
|
37917
38047
|
}
|
|
37918
38048
|
) }),
|
|
37919
38049
|
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: [
|