@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/providers/index.cjs
CHANGED
|
@@ -37970,6 +37970,12 @@ function getGroupColor(group, groups) {
|
|
|
37970
37970
|
const idx = groups.indexOf(group);
|
|
37971
37971
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
37972
37972
|
}
|
|
37973
|
+
function resolveColor2(color, el) {
|
|
37974
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
37975
|
+
if (!m) return color;
|
|
37976
|
+
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
37977
|
+
return resolved || (m[2]?.trim() ?? "#888888");
|
|
37978
|
+
}
|
|
37973
37979
|
var GROUP_COLORS2, GraphCanvas;
|
|
37974
37980
|
var init_GraphCanvas = __esm({
|
|
37975
37981
|
"components/core/molecules/GraphCanvas.tsx"() {
|
|
@@ -38000,6 +38006,9 @@ var init_GraphCanvas = __esm({
|
|
|
38000
38006
|
actions,
|
|
38001
38007
|
onNodeClick,
|
|
38002
38008
|
nodeClickEvent,
|
|
38009
|
+
selectedNodeId,
|
|
38010
|
+
repulsion = 800,
|
|
38011
|
+
linkDistance = 100,
|
|
38003
38012
|
layout = "force",
|
|
38004
38013
|
entity,
|
|
38005
38014
|
isLoading = false,
|
|
@@ -38015,6 +38024,37 @@ var init_GraphCanvas = __esm({
|
|
|
38015
38024
|
const [hoveredNode, setHoveredNode] = React82.useState(null);
|
|
38016
38025
|
const nodesRef = React82.useRef([]);
|
|
38017
38026
|
const [, forceUpdate] = React82.useState(0);
|
|
38027
|
+
const interactionRef = React82.useRef({
|
|
38028
|
+
mode: "none",
|
|
38029
|
+
dragNodeId: null,
|
|
38030
|
+
startMouse: { x: 0, y: 0 },
|
|
38031
|
+
startOffset: { x: 0, y: 0 },
|
|
38032
|
+
downPos: { x: 0, y: 0 }
|
|
38033
|
+
});
|
|
38034
|
+
const toCoords = React82.useCallback(
|
|
38035
|
+
(e) => {
|
|
38036
|
+
const canvas = canvasRef.current;
|
|
38037
|
+
if (!canvas) return null;
|
|
38038
|
+
const rect = canvas.getBoundingClientRect();
|
|
38039
|
+
const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
38040
|
+
const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
38041
|
+
const screenX = (e.clientX - rect.left) * scaleX;
|
|
38042
|
+
const screenY = (e.clientY - rect.top) * scaleY;
|
|
38043
|
+
return {
|
|
38044
|
+
screenX,
|
|
38045
|
+
screenY,
|
|
38046
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38047
|
+
graphY: (screenY - offset.y) / zoom
|
|
38048
|
+
};
|
|
38049
|
+
},
|
|
38050
|
+
[offset, zoom]
|
|
38051
|
+
);
|
|
38052
|
+
const nodeAt = React82.useCallback((graphX, graphY) => {
|
|
38053
|
+
return nodesRef.current.find((n) => {
|
|
38054
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38055
|
+
return dist < (n.size || 8) + 4;
|
|
38056
|
+
});
|
|
38057
|
+
}, []);
|
|
38018
38058
|
const handleAction = React82.useCallback(
|
|
38019
38059
|
(action) => {
|
|
38020
38060
|
if (action.event) {
|
|
@@ -38080,7 +38120,7 @@ var init_GraphCanvas = __esm({
|
|
|
38080
38120
|
const dx = nodes[j].x - nodes[i].x;
|
|
38081
38121
|
const dy = nodes[j].y - nodes[i].y;
|
|
38082
38122
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38083
|
-
const force =
|
|
38123
|
+
const force = repulsion / (dist * dist);
|
|
38084
38124
|
const fx = dx / dist * force;
|
|
38085
38125
|
const fy = dy / dist * force;
|
|
38086
38126
|
nodes[i].fx -= fx;
|
|
@@ -38096,7 +38136,7 @@ var init_GraphCanvas = __esm({
|
|
|
38096
38136
|
const dx = target.x - source.x;
|
|
38097
38137
|
const dy = target.y - source.y;
|
|
38098
38138
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38099
|
-
const force = (dist -
|
|
38139
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38100
38140
|
const fx = dx / dist * force;
|
|
38101
38141
|
const fy = dy / dist * force;
|
|
38102
38142
|
source.fx += fx;
|
|
@@ -38130,7 +38170,7 @@ var init_GraphCanvas = __esm({
|
|
|
38130
38170
|
return () => {
|
|
38131
38171
|
cancelAnimationFrame(animRef.current);
|
|
38132
38172
|
};
|
|
38133
|
-
}, [propNodes, propEdges, layout]);
|
|
38173
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38134
38174
|
React82.useEffect(() => {
|
|
38135
38175
|
const canvas = canvasRef.current;
|
|
38136
38176
|
if (!canvas) return;
|
|
@@ -38139,6 +38179,7 @@ var init_GraphCanvas = __esm({
|
|
|
38139
38179
|
const w = canvas.width;
|
|
38140
38180
|
const h = canvas.height;
|
|
38141
38181
|
const nodes = nodesRef.current;
|
|
38182
|
+
const accentColor = resolveColor2("var(--color-accent)", canvas);
|
|
38142
38183
|
ctx.clearRect(0, 0, w, h);
|
|
38143
38184
|
ctx.save();
|
|
38144
38185
|
ctx.translate(offset.x, offset.y);
|
|
@@ -38164,20 +38205,27 @@ var init_GraphCanvas = __esm({
|
|
|
38164
38205
|
}
|
|
38165
38206
|
for (const node of nodes) {
|
|
38166
38207
|
const size = node.size || 8;
|
|
38167
|
-
const color = node.color || getGroupColor(node.group, groups);
|
|
38208
|
+
const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
|
|
38168
38209
|
const isHovered = hoveredNode === node.id;
|
|
38210
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38211
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38169
38212
|
ctx.beginPath();
|
|
38170
|
-
ctx.arc(node.x, node.y,
|
|
38213
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38171
38214
|
ctx.fillStyle = color;
|
|
38172
38215
|
ctx.fill();
|
|
38173
|
-
|
|
38174
|
-
|
|
38216
|
+
if (isSelected) {
|
|
38217
|
+
ctx.strokeStyle = accentColor;
|
|
38218
|
+
ctx.lineWidth = 3;
|
|
38219
|
+
} else {
|
|
38220
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38221
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38222
|
+
}
|
|
38175
38223
|
ctx.stroke();
|
|
38176
38224
|
if (showLabels && node.label) {
|
|
38177
38225
|
ctx.fillStyle = "#666666";
|
|
38178
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38226
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38179
38227
|
ctx.textAlign = "center";
|
|
38180
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38228
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38181
38229
|
}
|
|
38182
38230
|
}
|
|
38183
38231
|
ctx.restore();
|
|
@@ -38188,6 +38236,97 @@ var init_GraphCanvas = __esm({
|
|
|
38188
38236
|
setZoom(1);
|
|
38189
38237
|
setOffset({ x: 0, y: 0 });
|
|
38190
38238
|
}, []);
|
|
38239
|
+
const handleWheel = React82.useCallback(
|
|
38240
|
+
(e) => {
|
|
38241
|
+
if (!interactive) return;
|
|
38242
|
+
e.preventDefault();
|
|
38243
|
+
const coords = toCoords(e);
|
|
38244
|
+
if (!coords) return;
|
|
38245
|
+
const oldZoom = zoom;
|
|
38246
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38247
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38248
|
+
if (newZoom === oldZoom) return;
|
|
38249
|
+
setOffset((o) => ({
|
|
38250
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38251
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38252
|
+
}));
|
|
38253
|
+
setZoom(newZoom);
|
|
38254
|
+
},
|
|
38255
|
+
[interactive, toCoords, zoom]
|
|
38256
|
+
);
|
|
38257
|
+
const handleMouseDown = React82.useCallback(
|
|
38258
|
+
(e) => {
|
|
38259
|
+
const coords = toCoords(e);
|
|
38260
|
+
if (!coords) return;
|
|
38261
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38262
|
+
const state = interactionRef.current;
|
|
38263
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38264
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38265
|
+
state.startOffset = { ...offset };
|
|
38266
|
+
if (draggable && node) {
|
|
38267
|
+
state.mode = "dragging";
|
|
38268
|
+
state.dragNodeId = node.id;
|
|
38269
|
+
} else if (interactive) {
|
|
38270
|
+
state.mode = "panning";
|
|
38271
|
+
state.dragNodeId = null;
|
|
38272
|
+
} else {
|
|
38273
|
+
state.mode = "none";
|
|
38274
|
+
state.dragNodeId = null;
|
|
38275
|
+
}
|
|
38276
|
+
},
|
|
38277
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38278
|
+
);
|
|
38279
|
+
const handleMouseMove = React82.useCallback(
|
|
38280
|
+
(e) => {
|
|
38281
|
+
const state = interactionRef.current;
|
|
38282
|
+
if (state.mode === "panning") {
|
|
38283
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38284
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38285
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38286
|
+
return;
|
|
38287
|
+
}
|
|
38288
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38289
|
+
const coords2 = toCoords(e);
|
|
38290
|
+
if (!coords2) return;
|
|
38291
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38292
|
+
if (node2) {
|
|
38293
|
+
node2.x = coords2.graphX;
|
|
38294
|
+
node2.y = coords2.graphY;
|
|
38295
|
+
node2.vx = 0;
|
|
38296
|
+
node2.vy = 0;
|
|
38297
|
+
forceUpdate((n) => n + 1);
|
|
38298
|
+
}
|
|
38299
|
+
return;
|
|
38300
|
+
}
|
|
38301
|
+
const coords = toCoords(e);
|
|
38302
|
+
if (!coords) return;
|
|
38303
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38304
|
+
setHoveredNode(node?.id ?? null);
|
|
38305
|
+
},
|
|
38306
|
+
[toCoords, nodeAt]
|
|
38307
|
+
);
|
|
38308
|
+
const handleMouseUp = React82.useCallback(
|
|
38309
|
+
(e) => {
|
|
38310
|
+
const state = interactionRef.current;
|
|
38311
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38312
|
+
state.mode = "none";
|
|
38313
|
+
state.dragNodeId = null;
|
|
38314
|
+
if (moved < 4) {
|
|
38315
|
+
const coords = toCoords(e);
|
|
38316
|
+
if (!coords) return;
|
|
38317
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38318
|
+
if (node) {
|
|
38319
|
+
handleNodeClick(node);
|
|
38320
|
+
}
|
|
38321
|
+
}
|
|
38322
|
+
},
|
|
38323
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38324
|
+
);
|
|
38325
|
+
const handleMouseLeave = React82.useCallback(() => {
|
|
38326
|
+
interactionRef.current.mode = "none";
|
|
38327
|
+
interactionRef.current.dragNodeId = null;
|
|
38328
|
+
setHoveredNode(null);
|
|
38329
|
+
}, []);
|
|
38191
38330
|
if (isLoading) {
|
|
38192
38331
|
return /* @__PURE__ */ jsxRuntime.jsx(LoadingState, { message: t("common.loading"), className });
|
|
38193
38332
|
}
|
|
@@ -38249,20 +38388,11 @@ var init_GraphCanvas = __esm({
|
|
|
38249
38388
|
height,
|
|
38250
38389
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38251
38390
|
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
|
-
}
|
|
38391
|
+
onWheel: handleWheel,
|
|
38392
|
+
onMouseDown: handleMouseDown,
|
|
38393
|
+
onMouseMove: handleMouseMove,
|
|
38394
|
+
onMouseUp: handleMouseUp,
|
|
38395
|
+
onMouseLeave: handleMouseLeave
|
|
38266
38396
|
}
|
|
38267
38397
|
) }),
|
|
38268
38398
|
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/providers/index.js
CHANGED
|
@@ -37923,6 +37923,12 @@ function getGroupColor(group, groups) {
|
|
|
37923
37923
|
const idx = groups.indexOf(group);
|
|
37924
37924
|
return GROUP_COLORS2[idx % GROUP_COLORS2.length];
|
|
37925
37925
|
}
|
|
37926
|
+
function resolveColor2(color, el) {
|
|
37927
|
+
const m = /^var\((--[^,)]+)(?:,\s*([^)]+))?\)$/.exec(color.trim());
|
|
37928
|
+
if (!m) return color;
|
|
37929
|
+
const resolved = getComputedStyle(el).getPropertyValue(m[1]).trim();
|
|
37930
|
+
return resolved || (m[2]?.trim() ?? "#888888");
|
|
37931
|
+
}
|
|
37926
37932
|
var GROUP_COLORS2, GraphCanvas;
|
|
37927
37933
|
var init_GraphCanvas = __esm({
|
|
37928
37934
|
"components/core/molecules/GraphCanvas.tsx"() {
|
|
@@ -37953,6 +37959,9 @@ var init_GraphCanvas = __esm({
|
|
|
37953
37959
|
actions,
|
|
37954
37960
|
onNodeClick,
|
|
37955
37961
|
nodeClickEvent,
|
|
37962
|
+
selectedNodeId,
|
|
37963
|
+
repulsion = 800,
|
|
37964
|
+
linkDistance = 100,
|
|
37956
37965
|
layout = "force",
|
|
37957
37966
|
entity,
|
|
37958
37967
|
isLoading = false,
|
|
@@ -37968,6 +37977,37 @@ var init_GraphCanvas = __esm({
|
|
|
37968
37977
|
const [hoveredNode, setHoveredNode] = useState(null);
|
|
37969
37978
|
const nodesRef = useRef([]);
|
|
37970
37979
|
const [, forceUpdate] = useState(0);
|
|
37980
|
+
const interactionRef = useRef({
|
|
37981
|
+
mode: "none",
|
|
37982
|
+
dragNodeId: null,
|
|
37983
|
+
startMouse: { x: 0, y: 0 },
|
|
37984
|
+
startOffset: { x: 0, y: 0 },
|
|
37985
|
+
downPos: { x: 0, y: 0 }
|
|
37986
|
+
});
|
|
37987
|
+
const toCoords = useCallback(
|
|
37988
|
+
(e) => {
|
|
37989
|
+
const canvas = canvasRef.current;
|
|
37990
|
+
if (!canvas) return null;
|
|
37991
|
+
const rect = canvas.getBoundingClientRect();
|
|
37992
|
+
const scaleX = rect.width > 0 ? canvas.width / rect.width : 1;
|
|
37993
|
+
const scaleY = rect.height > 0 ? canvas.height / rect.height : 1;
|
|
37994
|
+
const screenX = (e.clientX - rect.left) * scaleX;
|
|
37995
|
+
const screenY = (e.clientY - rect.top) * scaleY;
|
|
37996
|
+
return {
|
|
37997
|
+
screenX,
|
|
37998
|
+
screenY,
|
|
37999
|
+
graphX: (screenX - offset.x) / zoom,
|
|
38000
|
+
graphY: (screenY - offset.y) / zoom
|
|
38001
|
+
};
|
|
38002
|
+
},
|
|
38003
|
+
[offset, zoom]
|
|
38004
|
+
);
|
|
38005
|
+
const nodeAt = useCallback((graphX, graphY) => {
|
|
38006
|
+
return nodesRef.current.find((n) => {
|
|
38007
|
+
const dist = Math.sqrt((n.x - graphX) ** 2 + (n.y - graphY) ** 2);
|
|
38008
|
+
return dist < (n.size || 8) + 4;
|
|
38009
|
+
});
|
|
38010
|
+
}, []);
|
|
37971
38011
|
const handleAction = useCallback(
|
|
37972
38012
|
(action) => {
|
|
37973
38013
|
if (action.event) {
|
|
@@ -38033,7 +38073,7 @@ var init_GraphCanvas = __esm({
|
|
|
38033
38073
|
const dx = nodes[j].x - nodes[i].x;
|
|
38034
38074
|
const dy = nodes[j].y - nodes[i].y;
|
|
38035
38075
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38036
|
-
const force =
|
|
38076
|
+
const force = repulsion / (dist * dist);
|
|
38037
38077
|
const fx = dx / dist * force;
|
|
38038
38078
|
const fy = dy / dist * force;
|
|
38039
38079
|
nodes[i].fx -= fx;
|
|
@@ -38049,7 +38089,7 @@ var init_GraphCanvas = __esm({
|
|
|
38049
38089
|
const dx = target.x - source.x;
|
|
38050
38090
|
const dy = target.y - source.y;
|
|
38051
38091
|
const dist = Math.sqrt(dx * dx + dy * dy) || 1;
|
|
38052
|
-
const force = (dist -
|
|
38092
|
+
const force = (dist - linkDistance) * 0.05;
|
|
38053
38093
|
const fx = dx / dist * force;
|
|
38054
38094
|
const fy = dy / dist * force;
|
|
38055
38095
|
source.fx += fx;
|
|
@@ -38083,7 +38123,7 @@ var init_GraphCanvas = __esm({
|
|
|
38083
38123
|
return () => {
|
|
38084
38124
|
cancelAnimationFrame(animRef.current);
|
|
38085
38125
|
};
|
|
38086
|
-
}, [propNodes, propEdges, layout]);
|
|
38126
|
+
}, [propNodes, propEdges, layout, repulsion, linkDistance]);
|
|
38087
38127
|
useEffect(() => {
|
|
38088
38128
|
const canvas = canvasRef.current;
|
|
38089
38129
|
if (!canvas) return;
|
|
@@ -38092,6 +38132,7 @@ var init_GraphCanvas = __esm({
|
|
|
38092
38132
|
const w = canvas.width;
|
|
38093
38133
|
const h = canvas.height;
|
|
38094
38134
|
const nodes = nodesRef.current;
|
|
38135
|
+
const accentColor = resolveColor2("var(--color-accent)", canvas);
|
|
38095
38136
|
ctx.clearRect(0, 0, w, h);
|
|
38096
38137
|
ctx.save();
|
|
38097
38138
|
ctx.translate(offset.x, offset.y);
|
|
@@ -38117,20 +38158,27 @@ var init_GraphCanvas = __esm({
|
|
|
38117
38158
|
}
|
|
38118
38159
|
for (const node of nodes) {
|
|
38119
38160
|
const size = node.size || 8;
|
|
38120
|
-
const color = node.color || getGroupColor(node.group, groups);
|
|
38161
|
+
const color = resolveColor2(node.color || getGroupColor(node.group, groups), canvas);
|
|
38121
38162
|
const isHovered = hoveredNode === node.id;
|
|
38163
|
+
const isSelected = selectedNodeId !== void 0 && node.id === selectedNodeId;
|
|
38164
|
+
const radius = isSelected ? size + 4 : isHovered ? size + 2 : size;
|
|
38122
38165
|
ctx.beginPath();
|
|
38123
|
-
ctx.arc(node.x, node.y,
|
|
38166
|
+
ctx.arc(node.x, node.y, radius, 0, Math.PI * 2);
|
|
38124
38167
|
ctx.fillStyle = color;
|
|
38125
38168
|
ctx.fill();
|
|
38126
|
-
|
|
38127
|
-
|
|
38169
|
+
if (isSelected) {
|
|
38170
|
+
ctx.strokeStyle = accentColor;
|
|
38171
|
+
ctx.lineWidth = 3;
|
|
38172
|
+
} else {
|
|
38173
|
+
ctx.strokeStyle = isHovered ? "#ffffff" : "#00000020";
|
|
38174
|
+
ctx.lineWidth = isHovered ? 2 : 1;
|
|
38175
|
+
}
|
|
38128
38176
|
ctx.stroke();
|
|
38129
38177
|
if (showLabels && node.label) {
|
|
38130
38178
|
ctx.fillStyle = "#666666";
|
|
38131
|
-
ctx.font = `${isHovered ? "bold " : ""}10px system-ui`;
|
|
38179
|
+
ctx.font = `${isSelected || isHovered ? "bold " : ""}10px system-ui`;
|
|
38132
38180
|
ctx.textAlign = "center";
|
|
38133
|
-
ctx.fillText(node.label, node.x, node.y +
|
|
38181
|
+
ctx.fillText(node.label, node.x, node.y + radius + 12);
|
|
38134
38182
|
}
|
|
38135
38183
|
}
|
|
38136
38184
|
ctx.restore();
|
|
@@ -38141,6 +38189,97 @@ var init_GraphCanvas = __esm({
|
|
|
38141
38189
|
setZoom(1);
|
|
38142
38190
|
setOffset({ x: 0, y: 0 });
|
|
38143
38191
|
}, []);
|
|
38192
|
+
const handleWheel = useCallback(
|
|
38193
|
+
(e) => {
|
|
38194
|
+
if (!interactive) return;
|
|
38195
|
+
e.preventDefault();
|
|
38196
|
+
const coords = toCoords(e);
|
|
38197
|
+
if (!coords) return;
|
|
38198
|
+
const oldZoom = zoom;
|
|
38199
|
+
const factor = e.deltaY < 0 ? 1.1 : 1 / 1.1;
|
|
38200
|
+
const newZoom = Math.max(0.3, Math.min(3, oldZoom * factor));
|
|
38201
|
+
if (newZoom === oldZoom) return;
|
|
38202
|
+
setOffset((o) => ({
|
|
38203
|
+
x: coords.screenX - (coords.screenX - o.x) * (newZoom / oldZoom),
|
|
38204
|
+
y: coords.screenY - (coords.screenY - o.y) * (newZoom / oldZoom)
|
|
38205
|
+
}));
|
|
38206
|
+
setZoom(newZoom);
|
|
38207
|
+
},
|
|
38208
|
+
[interactive, toCoords, zoom]
|
|
38209
|
+
);
|
|
38210
|
+
const handleMouseDown = useCallback(
|
|
38211
|
+
(e) => {
|
|
38212
|
+
const coords = toCoords(e);
|
|
38213
|
+
if (!coords) return;
|
|
38214
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38215
|
+
const state = interactionRef.current;
|
|
38216
|
+
state.downPos = { x: e.clientX, y: e.clientY };
|
|
38217
|
+
state.startMouse = { x: e.clientX, y: e.clientY };
|
|
38218
|
+
state.startOffset = { ...offset };
|
|
38219
|
+
if (draggable && node) {
|
|
38220
|
+
state.mode = "dragging";
|
|
38221
|
+
state.dragNodeId = node.id;
|
|
38222
|
+
} else if (interactive) {
|
|
38223
|
+
state.mode = "panning";
|
|
38224
|
+
state.dragNodeId = null;
|
|
38225
|
+
} else {
|
|
38226
|
+
state.mode = "none";
|
|
38227
|
+
state.dragNodeId = null;
|
|
38228
|
+
}
|
|
38229
|
+
},
|
|
38230
|
+
[toCoords, nodeAt, draggable, interactive, offset]
|
|
38231
|
+
);
|
|
38232
|
+
const handleMouseMove = useCallback(
|
|
38233
|
+
(e) => {
|
|
38234
|
+
const state = interactionRef.current;
|
|
38235
|
+
if (state.mode === "panning") {
|
|
38236
|
+
const dx = e.clientX - state.startMouse.x;
|
|
38237
|
+
const dy = e.clientY - state.startMouse.y;
|
|
38238
|
+
setOffset({ x: state.startOffset.x + dx, y: state.startOffset.y + dy });
|
|
38239
|
+
return;
|
|
38240
|
+
}
|
|
38241
|
+
if (state.mode === "dragging" && state.dragNodeId) {
|
|
38242
|
+
const coords2 = toCoords(e);
|
|
38243
|
+
if (!coords2) return;
|
|
38244
|
+
const node2 = nodesRef.current.find((n) => n.id === state.dragNodeId);
|
|
38245
|
+
if (node2) {
|
|
38246
|
+
node2.x = coords2.graphX;
|
|
38247
|
+
node2.y = coords2.graphY;
|
|
38248
|
+
node2.vx = 0;
|
|
38249
|
+
node2.vy = 0;
|
|
38250
|
+
forceUpdate((n) => n + 1);
|
|
38251
|
+
}
|
|
38252
|
+
return;
|
|
38253
|
+
}
|
|
38254
|
+
const coords = toCoords(e);
|
|
38255
|
+
if (!coords) return;
|
|
38256
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38257
|
+
setHoveredNode(node?.id ?? null);
|
|
38258
|
+
},
|
|
38259
|
+
[toCoords, nodeAt]
|
|
38260
|
+
);
|
|
38261
|
+
const handleMouseUp = useCallback(
|
|
38262
|
+
(e) => {
|
|
38263
|
+
const state = interactionRef.current;
|
|
38264
|
+
const moved = Math.abs(e.clientX - state.downPos.x) + Math.abs(e.clientY - state.downPos.y);
|
|
38265
|
+
state.mode = "none";
|
|
38266
|
+
state.dragNodeId = null;
|
|
38267
|
+
if (moved < 4) {
|
|
38268
|
+
const coords = toCoords(e);
|
|
38269
|
+
if (!coords) return;
|
|
38270
|
+
const node = nodeAt(coords.graphX, coords.graphY);
|
|
38271
|
+
if (node) {
|
|
38272
|
+
handleNodeClick(node);
|
|
38273
|
+
}
|
|
38274
|
+
}
|
|
38275
|
+
},
|
|
38276
|
+
[toCoords, nodeAt, handleNodeClick]
|
|
38277
|
+
);
|
|
38278
|
+
const handleMouseLeave = useCallback(() => {
|
|
38279
|
+
interactionRef.current.mode = "none";
|
|
38280
|
+
interactionRef.current.dragNodeId = null;
|
|
38281
|
+
setHoveredNode(null);
|
|
38282
|
+
}, []);
|
|
38144
38283
|
if (isLoading) {
|
|
38145
38284
|
return /* @__PURE__ */ jsx(LoadingState, { message: t("common.loading"), className });
|
|
38146
38285
|
}
|
|
@@ -38202,20 +38341,11 @@ var init_GraphCanvas = __esm({
|
|
|
38202
38341
|
height,
|
|
38203
38342
|
className: "w-full cursor-grab active:cursor-grabbing",
|
|
38204
38343
|
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
|
-
}
|
|
38344
|
+
onWheel: handleWheel,
|
|
38345
|
+
onMouseDown: handleMouseDown,
|
|
38346
|
+
onMouseMove: handleMouseMove,
|
|
38347
|
+
onMouseUp: handleMouseUp,
|
|
38348
|
+
onMouseLeave: handleMouseLeave
|
|
38219
38349
|
}
|
|
38220
38350
|
) }),
|
|
38221
38351
|
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: [
|