@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
package/dist/providers/index.js
CHANGED
|
@@ -37953,6 +37953,9 @@ var init_GraphCanvas = __esm({
|
|
|
37953
37953
|
actions,
|
|
37954
37954
|
onNodeClick,
|
|
37955
37955
|
nodeClickEvent,
|
|
37956
|
+
selectedNodeId,
|
|
37957
|
+
repulsion = 800,
|
|
37958
|
+
linkDistance = 100,
|
|
37956
37959
|
layout = "force",
|
|
37957
37960
|
entity,
|
|
37958
37961
|
isLoading = false,
|
|
@@ -37968,6 +37971,35 @@ var init_GraphCanvas = __esm({
|
|
|
37968
37971
|
const [hoveredNode, setHoveredNode] = useState(null);
|
|
37969
37972
|
const nodesRef = useRef([]);
|
|
37970
37973
|
const [, forceUpdate] = useState(0);
|
|
37974
|
+
const interactionRef = useRef({
|
|
37975
|
+
mode: "none",
|
|
37976
|
+
dragNodeId: null,
|
|
37977
|
+
startMouse: { x: 0, y: 0 },
|
|
37978
|
+
startOffset: { x: 0, y: 0 },
|
|
37979
|
+
downPos: { x: 0, y: 0 }
|
|
37980
|
+
});
|
|
37981
|
+
const toCoords = useCallback(
|
|
37982
|
+
(e) => {
|
|
37983
|
+
const canvas = canvasRef.current;
|
|
37984
|
+
if (!canvas) return null;
|
|
37985
|
+
const rect = canvas.getBoundingClientRect();
|
|
37986
|
+
const screenX = e.clientX - rect.left;
|
|
37987
|
+
const screenY = e.clientY - rect.top;
|
|
37988
|
+
return {
|
|
37989
|
+
screenX,
|
|
37990
|
+
screenY,
|
|
37991
|
+
graphX: (screenX - offset.x) / zoom,
|
|
37992
|
+
graphY: (screenY - offset.y) / zoom
|
|
37993
|
+
};
|
|
37994
|
+
},
|
|
37995
|
+
[offset, zoom]
|
|
37996
|
+
);
|
|
37997
|
+
const nodeAt = useCallback((graphX, graphY) => {
|
|
37998
|
+
return nodesRef.current.find((n) => {
|
|
37999
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38000
|
+
return dist < (n.size || 8) + 4;
|
|
38001
|
+
});
|
|
38002
|
+
}, []);
|
|
37971
38003
|
const handleAction = useCallback(
|
|
37972
38004
|
(action) => {
|
|
37973
38005
|
if (action.event) {
|
|
@@ -38033,7 +38065,7 @@ var init_GraphCanvas = __esm({
|
|
|
38033
38065
|
const dx = nodes[j].x - nodes[i].x;
|
|
38034
38066
|
const dy = nodes[j].y - nodes[i].y;
|
|
38035
38067
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38036
|
-
const force =
|
|
38068
|
+
const force = repulsion / (dist * dist);
|
|
38037
38069
|
const fx = dx / dist * force;
|
|
38038
38070
|
const fy = dy / dist * force;
|
|
38039
38071
|
nodes[i].fx -= fx;
|
|
@@ -38049,7 +38081,7 @@ var init_GraphCanvas = __esm({
|
|
|
38049
38081
|
const dx = target.x - source.x;
|
|
38050
38082
|
const dy = target.y - source.y;
|
|
38051
38083
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38052
|
-
const force = (dist -
|
|
38084
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38053
38085
|
const fx = dx / dist * force;
|
|
38054
38086
|
const fy = dy / dist * force;
|
|
38055
38087
|
source.fx += fx;
|
|
@@ -38083,7 +38115,7 @@ var init_GraphCanvas = __esm({
|
|
|
38083
38115
|
return () => {
|
|
38084
38116
|
cancelAnimationFrame(animRef.current);
|
|
38085
38117
|
};
|
|
38086
|
-
}, [propNodes, propEdges, layout]);
|
|
38118
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38087
38119
|
useEffect(() => {
|
|
38088
38120
|
const canvas = canvasRef.current;
|
|
38089
38121
|
if (!canvas) return;
|
|
@@ -38119,18 +38151,25 @@ var init_GraphCanvas = __esm({
|
|
|
38119
38151
|
const size = node.size || 8;
|
|
38120
38152
|
const color = node.color || getGroupColor(node.group, groups);
|
|
38121
38153
|
const isHovered = hoveredNode === node.id;
|
|
38154
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38155
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38122
38156
|
ctx.beginPath();
|
|
38123
|
-
ctx.arc(node.x, node.y,
|
|
38157
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38124
38158
|
ctx.fillStyle = color;
|
|
38125
38159
|
ctx.fill();
|
|
38126
|
-
|
|
38127
|
-
|
|
38160
|
+
if (isSelected) {
|
|
38161
|
+
ctx.strokeStyle = "var(--color-accent)";
|
|
38162
|
+
ctx.lineWidth = 3;
|
|
38163
|
+
} else {
|
|
38164
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38165
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38166
|
+
}
|
|
38128
38167
|
ctx.stroke();
|
|
38129
38168
|
if (showLabels && node.label) {
|
|
38130
38169
|
ctx.fillStyle = "#666666";
|
|
38131
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38170
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38132
38171
|
ctx.textAlign = "center";
|
|
38133
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38172
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38134
38173
|
}
|
|
38135
38174
|
}
|
|
38136
38175
|
ctx.restore();
|
|
@@ -38141,6 +38180,97 @@ var init_GraphCanvas = __esm({
|
|
|
38141
38180
|
setZoom(1);
|
|
38142
38181
|
setOffset({ x: 0, y: 0 });
|
|
38143
38182
|
}, []);
|
|
38183
|
+
const handleWheel = useCallback(
|
|
38184
|
+
(e) => {
|
|
38185
|
+
if (!interactive) return;
|
|
38186
|
+
e.preventDefault();
|
|
38187
|
+
const coords = toCoords(e);
|
|
38188
|
+
if (!coords) return;
|
|
38189
|
+
const oldZoom = zoom;
|
|
38190
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38191
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38192
|
+
if (newZoom === oldZoom) return;
|
|
38193
|
+
setOffset((o) => ({
|
|
38194
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38195
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38196
|
+
}));
|
|
38197
|
+
setZoom(newZoom);
|
|
38198
|
+
},
|
|
38199
|
+
[interactive, toCoords, zoom]
|
|
38200
|
+
);
|
|
38201
|
+
const handleMouseDown = useCallback(
|
|
38202
|
+
(e) => {
|
|
38203
|
+
const coords = toCoords(e);
|
|
38204
|
+
if (!coords) return;
|
|
38205
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38206
|
+
const state = interactionRef.current;
|
|
38207
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38208
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38209
|
+
state.startOffset = { ...offset };
|
|
38210
|
+
if (draggable && node) {
|
|
38211
|
+
state.mode = "dragging";
|
|
38212
|
+
state.dragNodeId = node.id;
|
|
38213
|
+
} else if (interactive) {
|
|
38214
|
+
state.mode = "panning";
|
|
38215
|
+
state.dragNodeId = null;
|
|
38216
|
+
} else {
|
|
38217
|
+
state.mode = "none";
|
|
38218
|
+
state.dragNodeId = null;
|
|
38219
|
+
}
|
|
38220
|
+
},
|
|
38221
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38222
|
+
);
|
|
38223
|
+
const handleMouseMove = useCallback(
|
|
38224
|
+
(e) => {
|
|
38225
|
+
const state = interactionRef.current;
|
|
38226
|
+
if (state.mode === "panning") {
|
|
38227
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38228
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38229
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38230
|
+
return;
|
|
38231
|
+
}
|
|
38232
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38233
|
+
const coords2 = toCoords(e);
|
|
38234
|
+
if (!coords2) return;
|
|
38235
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38236
|
+
if (node2) {
|
|
38237
|
+
node2.x = coords2.graphX;
|
|
38238
|
+
node2.y = coords2.graphY;
|
|
38239
|
+
node2.vx = 0;
|
|
38240
|
+
node2.vy = 0;
|
|
38241
|
+
forceUpdate((n) => n + 1);
|
|
38242
|
+
}
|
|
38243
|
+
return;
|
|
38244
|
+
}
|
|
38245
|
+
const coords = toCoords(e);
|
|
38246
|
+
if (!coords) return;
|
|
38247
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38248
|
+
setHoveredNode(node?.id ?? null);
|
|
38249
|
+
},
|
|
38250
|
+
[toCoords, nodeAt]
|
|
38251
|
+
);
|
|
38252
|
+
const handleMouseUp = useCallback(
|
|
38253
|
+
(e) => {
|
|
38254
|
+
const state = interactionRef.current;
|
|
38255
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38256
|
+
state.mode = "none";
|
|
38257
|
+
state.dragNodeId = null;
|
|
38258
|
+
if (moved < 4) {
|
|
38259
|
+
const coords = toCoords(e);
|
|
38260
|
+
if (!coords) return;
|
|
38261
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38262
|
+
if (node) {
|
|
38263
|
+
handleNodeClick(node);
|
|
38264
|
+
}
|
|
38265
|
+
}
|
|
38266
|
+
},
|
|
38267
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38268
|
+
);
|
|
38269
|
+
const handleMouseLeave = useCallback(() => {
|
|
38270
|
+
interactionRef.current.mode = "none";
|
|
38271
|
+
interactionRef.current.dragNodeId = null;
|
|
38272
|
+
setHoveredNode(null);
|
|
38273
|
+
}, []);
|
|
38144
38274
|
if (isLoading) {
|
|
38145
38275
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
38146
38276
|
}
|
|
@@ -38202,20 +38332,11 @@ var init_GraphCanvas = __esm({
|
|
|
38202
38332
|
height,
|
|
38203
38333
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38204
38334
|
style: { height },
|
|
38205
|
-
|
|
38206
|
-
|
|
38207
|
-
|
|
38208
|
-
|
|
38209
|
-
|
|
38210
|
-
const y = (e.clientY - rect.top - offset.y) / zoom;
|
|
38211
|
-
const clickedNode = nodesRef.current.find((n) => {
|
|
38212
|
-
const dist = Math.sqrt((n.x - x) ** 2 + (n.y - y) ** 2);
|
|
38213
|
-
return dist < (n.size || 8) + 4;
|
|
38214
|
-
});
|
|
38215
|
-
if (clickedNode) {
|
|
38216
|
-
handleNodeClick(clickedNode);
|
|
38217
|
-
}
|
|
38218
|
-
}
|
|
38335
|
+
onWheel: handleWheel,
|
|
38336
|
+
onMouseDown: handleMouseDown,
|
|
38337
|
+
onMouseMove: handleMouseMove,
|
|
38338
|
+
onMouseUp: handleMouseUp,
|
|
38339
|
+
onMouseLeave: handleMouseLeave
|
|
38219
38340
|
}
|
|
38220
38341
|
) }),
|
|
38221
38342
|
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/runtime/index.cjs
CHANGED
|
@@ -37698,6 +37698,9 @@ var init_GraphCanvas = __esm({
|
|
|
37698
37698
|
actions,
|
|
37699
37699
|
onNodeClick,
|
|
37700
37700
|
nodeClickEvent,
|
|
37701
|
+
selectedNodeId,
|
|
37702
|
+
repulsion = 800,
|
|
37703
|
+
linkDistance = 100,
|
|
37701
37704
|
layout = "force",
|
|
37702
37705
|
entity,
|
|
37703
37706
|
isLoading = false,
|
|
@@ -37713,6 +37716,35 @@ var init_GraphCanvas = __esm({
|
|
|
37713
37716
|
const [hoveredNode, setHoveredNode] = React81.useState(null);
|
|
37714
37717
|
const nodesRef = React81.useRef([]);
|
|
37715
37718
|
const [, forceUpdate] = React81.useState(0);
|
|
37719
|
+
const interactionRef = React81.useRef({
|
|
37720
|
+
mode: "none",
|
|
37721
|
+
dragNodeId: null,
|
|
37722
|
+
startMouse: { x: 0, y: 0 },
|
|
37723
|
+
startOffset: { x: 0, y: 0 },
|
|
37724
|
+
downPos: { x: 0, y: 0 }
|
|
37725
|
+
});
|
|
37726
|
+
const toCoords = React81.useCallback(
|
|
37727
|
+
(e) => {
|
|
37728
|
+
const canvas = canvasRef.current;
|
|
37729
|
+
if (!canvas) return null;
|
|
37730
|
+
const rect = canvas.getBoundingClientRect();
|
|
37731
|
+
const screenX = e.clientX - rect.left;
|
|
37732
|
+
const screenY = e.clientY - rect.top;
|
|
37733
|
+
return {
|
|
37734
|
+
screenX,
|
|
37735
|
+
screenY,
|
|
37736
|
+
graphX: (screenX - offset.x) / zoom,
|
|
37737
|
+
graphY: (screenY - offset.y) / zoom
|
|
37738
|
+
};
|
|
37739
|
+
},
|
|
37740
|
+
[offset, zoom]
|
|
37741
|
+
);
|
|
37742
|
+
const nodeAt = React81.useCallback((graphX, graphY) => {
|
|
37743
|
+
return nodesRef.current.find((n) => {
|
|
37744
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
37745
|
+
return dist < (n.size || 8) + 4;
|
|
37746
|
+
});
|
|
37747
|
+
}, []);
|
|
37716
37748
|
const handleAction = React81.useCallback(
|
|
37717
37749
|
(action) => {
|
|
37718
37750
|
if (action.event) {
|
|
@@ -37778,7 +37810,7 @@ var init_GraphCanvas = __esm({
|
|
|
37778
37810
|
const dx = nodes[j].x - nodes[i].x;
|
|
37779
37811
|
const dy = nodes[j].y - nodes[i].y;
|
|
37780
37812
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37781
|
-
const force =
|
|
37813
|
+
const force = repulsion / (dist * dist);
|
|
37782
37814
|
const fx = dx / dist * force;
|
|
37783
37815
|
const fy = dy / dist * force;
|
|
37784
37816
|
nodes[i].fx -= fx;
|
|
@@ -37794,7 +37826,7 @@ var init_GraphCanvas = __esm({
|
|
|
37794
37826
|
const dx = target.x - source.x;
|
|
37795
37827
|
const dy = target.y - source.y;
|
|
37796
37828
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37797
|
-
const force = (dist -
|
|
37829
|
+
const force = (dist - linkDistance) * 0.05;
|
|
37798
37830
|
const fx = dx / dist * force;
|
|
37799
37831
|
const fy = dy / dist * force;
|
|
37800
37832
|
source.fx += fx;
|
|
@@ -37828,7 +37860,7 @@ var init_GraphCanvas = __esm({
|
|
|
37828
37860
|
return () => {
|
|
37829
37861
|
cancelAnimationFrame(animRef.current);
|
|
37830
37862
|
};
|
|
37831
|
-
}, [propNodes, propEdges, layout]);
|
|
37863
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
37832
37864
|
React81.useEffect(() => {
|
|
37833
37865
|
const canvas = canvasRef.current;
|
|
37834
37866
|
if (!canvas) return;
|
|
@@ -37864,18 +37896,25 @@ var init_GraphCanvas = __esm({
|
|
|
37864
37896
|
const size = node.size || 8;
|
|
37865
37897
|
const color = node.color || getGroupColor(node.group, groups);
|
|
37866
37898
|
const isHovered = hoveredNode === node.id;
|
|
37899
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
37900
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
37867
37901
|
ctx.beginPath();
|
|
37868
|
-
ctx.arc(node.x, node.y,
|
|
37902
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
37869
37903
|
ctx.fillStyle = color;
|
|
37870
37904
|
ctx.fill();
|
|
37871
|
-
|
|
37872
|
-
|
|
37905
|
+
if (isSelected) {
|
|
37906
|
+
ctx.strokeStyle = "var(--color-accent)";
|
|
37907
|
+
ctx.lineWidth = 3;
|
|
37908
|
+
} else {
|
|
37909
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
37910
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
37911
|
+
}
|
|
37873
37912
|
ctx.stroke();
|
|
37874
37913
|
if (showLabels && node.label) {
|
|
37875
37914
|
ctx.fillStyle = "#666666";
|
|
37876
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
37915
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
37877
37916
|
ctx.textAlign = "center";
|
|
37878
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
37917
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
37879
37918
|
}
|
|
37880
37919
|
}
|
|
37881
37920
|
ctx.restore();
|
|
@@ -37886,6 +37925,97 @@ var init_GraphCanvas = __esm({
|
|
|
37886
37925
|
setZoom(1);
|
|
37887
37926
|
setOffset({ x: 0, y: 0 });
|
|
37888
37927
|
}, []);
|
|
37928
|
+
const handleWheel = React81.useCallback(
|
|
37929
|
+
(e) => {
|
|
37930
|
+
if (!interactive) return;
|
|
37931
|
+
e.preventDefault();
|
|
37932
|
+
const coords = toCoords(e);
|
|
37933
|
+
if (!coords) return;
|
|
37934
|
+
const oldZoom = zoom;
|
|
37935
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
37936
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
37937
|
+
if (newZoom === oldZoom) return;
|
|
37938
|
+
setOffset((o) => ({
|
|
37939
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
37940
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
37941
|
+
}));
|
|
37942
|
+
setZoom(newZoom);
|
|
37943
|
+
},
|
|
37944
|
+
[interactive, toCoords, zoom]
|
|
37945
|
+
);
|
|
37946
|
+
const handleMouseDown = React81.useCallback(
|
|
37947
|
+
(e) => {
|
|
37948
|
+
const coords = toCoords(e);
|
|
37949
|
+
if (!coords) return;
|
|
37950
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37951
|
+
const state = interactionRef.current;
|
|
37952
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
37953
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
37954
|
+
state.startOffset = { ...offset };
|
|
37955
|
+
if (draggable && node) {
|
|
37956
|
+
state.mode = "dragging";
|
|
37957
|
+
state.dragNodeId = node.id;
|
|
37958
|
+
} else if (interactive) {
|
|
37959
|
+
state.mode = "panning";
|
|
37960
|
+
state.dragNodeId = null;
|
|
37961
|
+
} else {
|
|
37962
|
+
state.mode = "none";
|
|
37963
|
+
state.dragNodeId = null;
|
|
37964
|
+
}
|
|
37965
|
+
},
|
|
37966
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
37967
|
+
);
|
|
37968
|
+
const handleMouseMove = React81.useCallback(
|
|
37969
|
+
(e) => {
|
|
37970
|
+
const state = interactionRef.current;
|
|
37971
|
+
if (state.mode === "panning") {
|
|
37972
|
+
const dx = e.clientX - state.startMouse.x;
|
|
37973
|
+
const dy = e.clientY - state.startMouse.y;
|
|
37974
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
37975
|
+
return;
|
|
37976
|
+
}
|
|
37977
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
37978
|
+
const coords2 = toCoords(e);
|
|
37979
|
+
if (!coords2) return;
|
|
37980
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
37981
|
+
if (node2) {
|
|
37982
|
+
node2.x = coords2.graphX;
|
|
37983
|
+
node2.y = coords2.graphY;
|
|
37984
|
+
node2.vx = 0;
|
|
37985
|
+
node2.vy = 0;
|
|
37986
|
+
forceUpdate((n) => n + 1);
|
|
37987
|
+
}
|
|
37988
|
+
return;
|
|
37989
|
+
}
|
|
37990
|
+
const coords = toCoords(e);
|
|
37991
|
+
if (!coords) return;
|
|
37992
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37993
|
+
setHoveredNode(node?.id ?? null);
|
|
37994
|
+
},
|
|
37995
|
+
[toCoords, nodeAt]
|
|
37996
|
+
);
|
|
37997
|
+
const handleMouseUp = React81.useCallback(
|
|
37998
|
+
(e) => {
|
|
37999
|
+
const state = interactionRef.current;
|
|
38000
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38001
|
+
state.mode = "none";
|
|
38002
|
+
state.dragNodeId = null;
|
|
38003
|
+
if (moved < 4) {
|
|
38004
|
+
const coords = toCoords(e);
|
|
38005
|
+
if (!coords) return;
|
|
38006
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38007
|
+
if (node) {
|
|
38008
|
+
handleNodeClick(node);
|
|
38009
|
+
}
|
|
38010
|
+
}
|
|
38011
|
+
},
|
|
38012
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38013
|
+
);
|
|
38014
|
+
const handleMouseLeave = React81.useCallback(() => {
|
|
38015
|
+
interactionRef.current.mode = "none";
|
|
38016
|
+
interactionRef.current.dragNodeId = null;
|
|
38017
|
+
setHoveredNode(null);
|
|
38018
|
+
}, []);
|
|
37889
38019
|
if (isLoading) {
|
|
37890
38020
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
37891
38021
|
}
|
|
@@ -37947,20 +38077,11 @@ var init_GraphCanvas = __esm({
|
|
|
37947
38077
|
height,
|
|
37948
38078
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
37949
38079
|
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
|
-
}
|
|
38080
|
+
onWheel: handleWheel,
|
|
38081
|
+
onMouseDown: handleMouseDown,
|
|
38082
|
+
onMouseMove: handleMouseMove,
|
|
38083
|
+
onMouseUp: handleMouseUp,
|
|
38084
|
+
onMouseLeave: handleMouseLeave
|
|
37964
38085
|
}
|
|
37965
38086
|
) }),
|
|
37966
38087
|
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
|
@@ -37651,6 +37651,9 @@ var init_GraphCanvas = __esm({
|
|
|
37651
37651
|
actions,
|
|
37652
37652
|
onNodeClick,
|
|
37653
37653
|
nodeClickEvent,
|
|
37654
|
+
selectedNodeId,
|
|
37655
|
+
repulsion = 800,
|
|
37656
|
+
linkDistance = 100,
|
|
37654
37657
|
layout = "force",
|
|
37655
37658
|
entity,
|
|
37656
37659
|
isLoading = false,
|
|
@@ -37666,6 +37669,35 @@ var init_GraphCanvas = __esm({
|
|
|
37666
37669
|
const [hoveredNode, setHoveredNode] = useState(null);
|
|
37667
37670
|
const nodesRef = useRef([]);
|
|
37668
37671
|
const [, forceUpdate] = useState(0);
|
|
37672
|
+
const interactionRef = useRef({
|
|
37673
|
+
mode: "none",
|
|
37674
|
+
dragNodeId: null,
|
|
37675
|
+
startMouse: { x: 0, y: 0 },
|
|
37676
|
+
startOffset: { x: 0, y: 0 },
|
|
37677
|
+
downPos: { x: 0, y: 0 }
|
|
37678
|
+
});
|
|
37679
|
+
const toCoords = useCallback(
|
|
37680
|
+
(e) => {
|
|
37681
|
+
const canvas = canvasRef.current;
|
|
37682
|
+
if (!canvas) return null;
|
|
37683
|
+
const rect = canvas.getBoundingClientRect();
|
|
37684
|
+
const screenX = e.clientX - rect.left;
|
|
37685
|
+
const screenY = e.clientY - rect.top;
|
|
37686
|
+
return {
|
|
37687
|
+
screenX,
|
|
37688
|
+
screenY,
|
|
37689
|
+
graphX: (screenX - offset.x) / zoom,
|
|
37690
|
+
graphY: (screenY - offset.y) / zoom
|
|
37691
|
+
};
|
|
37692
|
+
},
|
|
37693
|
+
[offset, zoom]
|
|
37694
|
+
);
|
|
37695
|
+
const nodeAt = useCallback((graphX, graphY) => {
|
|
37696
|
+
return nodesRef.current.find((n) => {
|
|
37697
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
37698
|
+
return dist < (n.size || 8) + 4;
|
|
37699
|
+
});
|
|
37700
|
+
}, []);
|
|
37669
37701
|
const handleAction = useCallback(
|
|
37670
37702
|
(action) => {
|
|
37671
37703
|
if (action.event) {
|
|
@@ -37731,7 +37763,7 @@ var init_GraphCanvas = __esm({
|
|
|
37731
37763
|
const dx = nodes[j].x - nodes[i].x;
|
|
37732
37764
|
const dy = nodes[j].y - nodes[i].y;
|
|
37733
37765
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37734
|
-
const force =
|
|
37766
|
+
const force = repulsion / (dist * dist);
|
|
37735
37767
|
const fx = dx / dist * force;
|
|
37736
37768
|
const fy = dy / dist * force;
|
|
37737
37769
|
nodes[i].fx -= fx;
|
|
@@ -37747,7 +37779,7 @@ var init_GraphCanvas = __esm({
|
|
|
37747
37779
|
const dx = target.x - source.x;
|
|
37748
37780
|
const dy = target.y - source.y;
|
|
37749
37781
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
37750
|
-
const force = (dist -
|
|
37782
|
+
const force = (dist - linkDistance) * 0.05;
|
|
37751
37783
|
const fx = dx / dist * force;
|
|
37752
37784
|
const fy = dy / dist * force;
|
|
37753
37785
|
source.fx += fx;
|
|
@@ -37781,7 +37813,7 @@ var init_GraphCanvas = __esm({
|
|
|
37781
37813
|
return () => {
|
|
37782
37814
|
cancelAnimationFrame(animRef.current);
|
|
37783
37815
|
};
|
|
37784
|
-
}, [propNodes, propEdges, layout]);
|
|
37816
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
37785
37817
|
useEffect(() => {
|
|
37786
37818
|
const canvas = canvasRef.current;
|
|
37787
37819
|
if (!canvas) return;
|
|
@@ -37817,18 +37849,25 @@ var init_GraphCanvas = __esm({
|
|
|
37817
37849
|
const size = node.size || 8;
|
|
37818
37850
|
const color = node.color || getGroupColor(node.group, groups);
|
|
37819
37851
|
const isHovered = hoveredNode === node.id;
|
|
37852
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
37853
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
37820
37854
|
ctx.beginPath();
|
|
37821
|
-
ctx.arc(node.x, node.y,
|
|
37855
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
37822
37856
|
ctx.fillStyle = color;
|
|
37823
37857
|
ctx.fill();
|
|
37824
|
-
|
|
37825
|
-
|
|
37858
|
+
if (isSelected) {
|
|
37859
|
+
ctx.strokeStyle = "var(--color-accent)";
|
|
37860
|
+
ctx.lineWidth = 3;
|
|
37861
|
+
} else {
|
|
37862
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
37863
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
37864
|
+
}
|
|
37826
37865
|
ctx.stroke();
|
|
37827
37866
|
if (showLabels && node.label) {
|
|
37828
37867
|
ctx.fillStyle = "#666666";
|
|
37829
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
37868
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
37830
37869
|
ctx.textAlign = "center";
|
|
37831
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
37870
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
37832
37871
|
}
|
|
37833
37872
|
}
|
|
37834
37873
|
ctx.restore();
|
|
@@ -37839,6 +37878,97 @@ var init_GraphCanvas = __esm({
|
|
|
37839
37878
|
setZoom(1);
|
|
37840
37879
|
setOffset({ x: 0, y: 0 });
|
|
37841
37880
|
}, []);
|
|
37881
|
+
const handleWheel = useCallback(
|
|
37882
|
+
(e) => {
|
|
37883
|
+
if (!interactive) return;
|
|
37884
|
+
e.preventDefault();
|
|
37885
|
+
const coords = toCoords(e);
|
|
37886
|
+
if (!coords) return;
|
|
37887
|
+
const oldZoom = zoom;
|
|
37888
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
37889
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
37890
|
+
if (newZoom === oldZoom) return;
|
|
37891
|
+
setOffset((o) => ({
|
|
37892
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
37893
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
37894
|
+
}));
|
|
37895
|
+
setZoom(newZoom);
|
|
37896
|
+
},
|
|
37897
|
+
[interactive, toCoords, zoom]
|
|
37898
|
+
);
|
|
37899
|
+
const handleMouseDown = useCallback(
|
|
37900
|
+
(e) => {
|
|
37901
|
+
const coords = toCoords(e);
|
|
37902
|
+
if (!coords) return;
|
|
37903
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37904
|
+
const state = interactionRef.current;
|
|
37905
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
37906
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
37907
|
+
state.startOffset = { ...offset };
|
|
37908
|
+
if (draggable && node) {
|
|
37909
|
+
state.mode = "dragging";
|
|
37910
|
+
state.dragNodeId = node.id;
|
|
37911
|
+
} else if (interactive) {
|
|
37912
|
+
state.mode = "panning";
|
|
37913
|
+
state.dragNodeId = null;
|
|
37914
|
+
} else {
|
|
37915
|
+
state.mode = "none";
|
|
37916
|
+
state.dragNodeId = null;
|
|
37917
|
+
}
|
|
37918
|
+
},
|
|
37919
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
37920
|
+
);
|
|
37921
|
+
const handleMouseMove = useCallback(
|
|
37922
|
+
(e) => {
|
|
37923
|
+
const state = interactionRef.current;
|
|
37924
|
+
if (state.mode === "panning") {
|
|
37925
|
+
const dx = e.clientX - state.startMouse.x;
|
|
37926
|
+
const dy = e.clientY - state.startMouse.y;
|
|
37927
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
37928
|
+
return;
|
|
37929
|
+
}
|
|
37930
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
37931
|
+
const coords2 = toCoords(e);
|
|
37932
|
+
if (!coords2) return;
|
|
37933
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
37934
|
+
if (node2) {
|
|
37935
|
+
node2.x = coords2.graphX;
|
|
37936
|
+
node2.y = coords2.graphY;
|
|
37937
|
+
node2.vx = 0;
|
|
37938
|
+
node2.vy = 0;
|
|
37939
|
+
forceUpdate((n) => n + 1);
|
|
37940
|
+
}
|
|
37941
|
+
return;
|
|
37942
|
+
}
|
|
37943
|
+
const coords = toCoords(e);
|
|
37944
|
+
if (!coords) return;
|
|
37945
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37946
|
+
setHoveredNode(node?.id ?? null);
|
|
37947
|
+
},
|
|
37948
|
+
[toCoords, nodeAt]
|
|
37949
|
+
);
|
|
37950
|
+
const handleMouseUp = useCallback(
|
|
37951
|
+
(e) => {
|
|
37952
|
+
const state = interactionRef.current;
|
|
37953
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
37954
|
+
state.mode = "none";
|
|
37955
|
+
state.dragNodeId = null;
|
|
37956
|
+
if (moved < 4) {
|
|
37957
|
+
const coords = toCoords(e);
|
|
37958
|
+
if (!coords) return;
|
|
37959
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
37960
|
+
if (node) {
|
|
37961
|
+
handleNodeClick(node);
|
|
37962
|
+
}
|
|
37963
|
+
}
|
|
37964
|
+
},
|
|
37965
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
37966
|
+
);
|
|
37967
|
+
const handleMouseLeave = useCallback(() => {
|
|
37968
|
+
interactionRef.current.mode = "none";
|
|
37969
|
+
interactionRef.current.dragNodeId = null;
|
|
37970
|
+
setHoveredNode(null);
|
|
37971
|
+
}, []);
|
|
37842
37972
|
if (isLoading) {
|
|
37843
37973
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
37844
37974
|
}
|
|
@@ -37900,20 +38030,11 @@ var init_GraphCanvas = __esm({
|
|
|
37900
38030
|
height,
|
|
37901
38031
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
37902
38032
|
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
|
-
}
|
|
38033
|
+
onWheel: handleWheel,
|
|
38034
|
+
onMouseDown: handleMouseDown,
|
|
38035
|
+
onMouseMove: handleMouseMove,
|
|
38036
|
+
onMouseUp: handleMouseUp,
|
|
38037
|
+
onMouseLeave: handleMouseLeave
|
|
37917
38038
|
}
|
|
37918
38039
|
) }),
|
|
37919
38040
|
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: [
|