@aiready/components 0.13.6 → 0.13.7
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/charts/ForceDirectedGraph.js +265 -281
- package/dist/charts/ForceDirectedGraph.js.map +1 -1
- package/dist/index.d.ts +32 -77
- package/dist/index.js +428 -637
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/charts/ForceDirectedGraph.tsx +192 -393
- package/src/charts/PackageBoundaries.tsx +55 -0
- package/src/charts/constants.ts +30 -0
- package/src/charts/hooks.ts +87 -0
- package/src/charts/layout-utils.ts +93 -0
- package/src/components/icons/IconBase.tsx +38 -0
- package/src/components/icons/index.tsx +367 -0
- package/src/components/icons.tsx +3 -564
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { forwardRef, useRef, useState, useEffect, useCallback, useImperativeHandle } from 'react';
|
|
2
|
-
import * as
|
|
2
|
+
import * as d32 from 'd3';
|
|
3
3
|
import { clsx } from 'clsx';
|
|
4
4
|
import { twMerge } from 'tailwind-merge';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -137,6 +137,155 @@ var LinkItem = ({
|
|
|
137
137
|
] });
|
|
138
138
|
};
|
|
139
139
|
var LinkItem_default = LinkItem;
|
|
140
|
+
|
|
141
|
+
// src/charts/constants.ts
|
|
142
|
+
var DEFAULT_NODE_COLOR = "#64748b";
|
|
143
|
+
var DEFAULT_NODE_SIZE = 10;
|
|
144
|
+
var DEFAULT_LINK_COLOR = "#94a3b8";
|
|
145
|
+
var DEFAULT_LINK_WIDTH = 1;
|
|
146
|
+
var CIRCULAR_LAYOUT_RADIUS_RATIO = 0.35;
|
|
147
|
+
var FIT_VIEW_PADDING = 40;
|
|
148
|
+
var TRANSITION_DURATION_MS = 300;
|
|
149
|
+
var PACKAGE_BOUNDARY_FILL = "rgba(148,163,184,0.06)";
|
|
150
|
+
var PACKAGE_BOUNDARY_STROKE = "#475569";
|
|
151
|
+
var PACKAGE_BOUNDARY_STROKE_WIDTH = 2;
|
|
152
|
+
var PACKAGE_BOUNDARY_DASH = "6 6";
|
|
153
|
+
var PACKAGE_LABEL_FONT_SIZE = 11;
|
|
154
|
+
var PACKAGE_LABEL_COLOR = "#475569";
|
|
155
|
+
var PackageBoundaries = ({
|
|
156
|
+
packageBounds
|
|
157
|
+
}) => {
|
|
158
|
+
if (!packageBounds || Object.keys(packageBounds).length === 0) return null;
|
|
159
|
+
return /* @__PURE__ */ jsx("g", { className: "package-boundaries", pointerEvents: "none", children: Object.entries(packageBounds).map(([pid, b]) => /* @__PURE__ */ jsxs("g", { children: [
|
|
160
|
+
/* @__PURE__ */ jsx(
|
|
161
|
+
"circle",
|
|
162
|
+
{
|
|
163
|
+
cx: b.x,
|
|
164
|
+
cy: b.y,
|
|
165
|
+
r: b.r,
|
|
166
|
+
fill: PACKAGE_BOUNDARY_FILL,
|
|
167
|
+
stroke: PACKAGE_BOUNDARY_STROKE,
|
|
168
|
+
strokeWidth: PACKAGE_BOUNDARY_STROKE_WIDTH,
|
|
169
|
+
strokeDasharray: PACKAGE_BOUNDARY_DASH,
|
|
170
|
+
opacity: 0.9
|
|
171
|
+
}
|
|
172
|
+
),
|
|
173
|
+
/* @__PURE__ */ jsx(
|
|
174
|
+
"text",
|
|
175
|
+
{
|
|
176
|
+
x: b.x,
|
|
177
|
+
y: Math.max(12, b.y - b.r + 14),
|
|
178
|
+
fill: PACKAGE_LABEL_COLOR,
|
|
179
|
+
fontSize: PACKAGE_LABEL_FONT_SIZE,
|
|
180
|
+
textAnchor: "middle",
|
|
181
|
+
pointerEvents: "none",
|
|
182
|
+
children: pid.replace(/^pkg:/, "")
|
|
183
|
+
}
|
|
184
|
+
)
|
|
185
|
+
] }, pid)) });
|
|
186
|
+
};
|
|
187
|
+
PackageBoundaries.displayName = "PackageBoundaries";
|
|
188
|
+
|
|
189
|
+
// src/charts/layout-utils.ts
|
|
190
|
+
function applyCircularLayout(nodes, width, height) {
|
|
191
|
+
const centerX = width / 2;
|
|
192
|
+
const centerY = height / 2;
|
|
193
|
+
const radius = Math.min(width, height) * CIRCULAR_LAYOUT_RADIUS_RATIO;
|
|
194
|
+
nodes.forEach((node, i) => {
|
|
195
|
+
const angle = 2 * Math.PI * i / nodes.length;
|
|
196
|
+
node.fx = centerX + Math.cos(angle) * radius;
|
|
197
|
+
node.fy = centerY + Math.sin(angle) * radius;
|
|
198
|
+
node.x = node.fx;
|
|
199
|
+
node.y = node.fy;
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
function applyHierarchicalLayout(nodes, width, height) {
|
|
203
|
+
const groups = /* @__PURE__ */ new Map();
|
|
204
|
+
nodes.forEach((n) => {
|
|
205
|
+
const key = n.packageGroup || n.group || "root";
|
|
206
|
+
if (!groups.has(key)) groups.set(key, []);
|
|
207
|
+
groups.get(key).push(n);
|
|
208
|
+
});
|
|
209
|
+
const groupArray = Array.from(groups.entries());
|
|
210
|
+
const cols = Math.ceil(Math.sqrt(groupArray.length));
|
|
211
|
+
const groupSpacingX = width * 0.8 / cols;
|
|
212
|
+
const groupSpacingY = height * 0.8 / Math.ceil(groupArray.length / cols);
|
|
213
|
+
groupArray.forEach(([groupKey, groupNodes], gi) => {
|
|
214
|
+
const col = gi % cols;
|
|
215
|
+
const row = Math.floor(gi / cols);
|
|
216
|
+
const groupX = (col + 0.5) * groupSpacingX;
|
|
217
|
+
const groupY = (row + 0.5) * groupSpacingY;
|
|
218
|
+
if (groupKey.startsWith("pkg:") || groupKey === groupKey) {
|
|
219
|
+
groupNodes.forEach((n, ni) => {
|
|
220
|
+
const angle = 2 * Math.PI * ni / groupNodes.length;
|
|
221
|
+
const r = Math.min(80, 20 + groupNodes.length * 8);
|
|
222
|
+
n.fx = groupX + Math.cos(angle) * r;
|
|
223
|
+
n.fy = groupY + Math.sin(angle) * r;
|
|
224
|
+
n.x = n.fx;
|
|
225
|
+
n.y = n.fy;
|
|
226
|
+
});
|
|
227
|
+
}
|
|
228
|
+
});
|
|
229
|
+
}
|
|
230
|
+
function applyInitialForceLayout(nodes, width, height) {
|
|
231
|
+
nodes.forEach((node) => {
|
|
232
|
+
if (node.fx === void 0 || node.fx === null) {
|
|
233
|
+
node.x = Math.random() * width;
|
|
234
|
+
node.y = Math.random() * height;
|
|
235
|
+
}
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
function useGraphZoom(svgRef, gRef, enableZoom, setTransform, transformRef) {
|
|
239
|
+
useEffect(() => {
|
|
240
|
+
if (!enableZoom || !svgRef.current || !gRef.current) return;
|
|
241
|
+
const svg = d32.select(svgRef.current);
|
|
242
|
+
const g = d32.select(gRef.current);
|
|
243
|
+
const zoom3 = d32.zoom().scaleExtent([0.1, 10]).on("zoom", (event) => {
|
|
244
|
+
g.attr("transform", event.transform);
|
|
245
|
+
transformRef.current = event.transform;
|
|
246
|
+
setTransform(event.transform);
|
|
247
|
+
});
|
|
248
|
+
svg.call(zoom3);
|
|
249
|
+
return () => {
|
|
250
|
+
svg.on(".zoom", null);
|
|
251
|
+
};
|
|
252
|
+
}, [enableZoom, svgRef, gRef, setTransform, transformRef]);
|
|
253
|
+
}
|
|
254
|
+
function useWindowDrag(enableDrag, svgRef, transformRef, dragActiveRef, dragNodeRef, onDragEnd) {
|
|
255
|
+
useEffect(() => {
|
|
256
|
+
if (!enableDrag) return;
|
|
257
|
+
const handleWindowMove = (event) => {
|
|
258
|
+
if (!dragActiveRef.current || !dragNodeRef.current) return;
|
|
259
|
+
const svg = svgRef.current;
|
|
260
|
+
if (!svg) return;
|
|
261
|
+
const rect = svg.getBoundingClientRect();
|
|
262
|
+
const t = transformRef.current;
|
|
263
|
+
const x = (event.clientX - rect.left - t.x) / t.k;
|
|
264
|
+
const y = (event.clientY - rect.top - t.y) / t.k;
|
|
265
|
+
dragNodeRef.current.fx = x;
|
|
266
|
+
dragNodeRef.current.fy = y;
|
|
267
|
+
};
|
|
268
|
+
const handleWindowUp = () => {
|
|
269
|
+
if (!dragActiveRef.current) return;
|
|
270
|
+
onDragEnd();
|
|
271
|
+
dragNodeRef.current = null;
|
|
272
|
+
dragActiveRef.current = false;
|
|
273
|
+
};
|
|
274
|
+
const handleWindowLeave = (event) => {
|
|
275
|
+
if (event.relatedTarget === null) handleWindowUp();
|
|
276
|
+
};
|
|
277
|
+
window.addEventListener("mousemove", handleWindowMove);
|
|
278
|
+
window.addEventListener("mouseup", handleWindowUp);
|
|
279
|
+
window.addEventListener("mouseout", handleWindowLeave);
|
|
280
|
+
window.addEventListener("blur", handleWindowUp);
|
|
281
|
+
return () => {
|
|
282
|
+
window.removeEventListener("mousemove", handleWindowMove);
|
|
283
|
+
window.removeEventListener("mouseup", handleWindowUp);
|
|
284
|
+
window.removeEventListener("mouseout", handleWindowLeave);
|
|
285
|
+
window.removeEventListener("blur", handleWindowUp);
|
|
286
|
+
};
|
|
287
|
+
}, [enableDrag, svgRef, transformRef, dragActiveRef, dragNodeRef, onDragEnd]);
|
|
288
|
+
}
|
|
140
289
|
var ForceDirectedGraph = forwardRef(
|
|
141
290
|
({
|
|
142
291
|
nodes: initialNodes,
|
|
@@ -150,10 +299,10 @@ var ForceDirectedGraph = forwardRef(
|
|
|
150
299
|
onLinkClick,
|
|
151
300
|
selectedNodeId,
|
|
152
301
|
hoveredNodeId,
|
|
153
|
-
defaultNodeColor =
|
|
154
|
-
defaultNodeSize =
|
|
155
|
-
defaultLinkColor =
|
|
156
|
-
defaultLinkWidth =
|
|
302
|
+
defaultNodeColor = DEFAULT_NODE_COLOR,
|
|
303
|
+
defaultNodeSize = DEFAULT_NODE_SIZE,
|
|
304
|
+
defaultLinkColor = DEFAULT_LINK_COLOR,
|
|
305
|
+
defaultLinkWidth = DEFAULT_LINK_WIDTH,
|
|
157
306
|
showNodeLabels = true,
|
|
158
307
|
showLinkLabels = false,
|
|
159
308
|
className,
|
|
@@ -176,7 +325,7 @@ var ForceDirectedGraph = forwardRef(
|
|
|
176
325
|
if (externalLayout && externalLayout !== layout) {
|
|
177
326
|
setLayout(externalLayout);
|
|
178
327
|
}
|
|
179
|
-
}, [externalLayout]);
|
|
328
|
+
}, [externalLayout, layout]);
|
|
180
329
|
const handleLayoutChange = useCallback(
|
|
181
330
|
(newLayout) => {
|
|
182
331
|
setLayout(newLayout);
|
|
@@ -189,36 +338,13 @@ var ForceDirectedGraph = forwardRef(
|
|
|
189
338
|
}, [enableDrag]);
|
|
190
339
|
const nodes = React.useMemo(() => {
|
|
191
340
|
if (!initialNodes || !initialNodes.length) return initialNodes;
|
|
192
|
-
const
|
|
193
|
-
|
|
194
|
-
if (layout === "
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
y: Math.random() * height
|
|
199
|
-
}));
|
|
200
|
-
}
|
|
201
|
-
if (layout === "circular") {
|
|
202
|
-
const radius = Math.min(width, height) * 0.35;
|
|
203
|
-
return initialNodes.map((n, i) => ({
|
|
204
|
-
...n,
|
|
205
|
-
x: centerX + Math.cos(2 * Math.PI * i / initialNodes.length) * radius,
|
|
206
|
-
y: centerY + Math.sin(2 * Math.PI * i / initialNodes.length) * radius
|
|
207
|
-
}));
|
|
208
|
-
}
|
|
209
|
-
if (layout === "hierarchical") {
|
|
210
|
-
const cols = Math.ceil(Math.sqrt(initialNodes.length));
|
|
211
|
-
const spacingX = width / (cols + 1);
|
|
212
|
-
const spacingY = height / (Math.ceil(initialNodes.length / cols) + 1);
|
|
213
|
-
return initialNodes.map((n, i) => ({
|
|
214
|
-
...n,
|
|
215
|
-
x: spacingX * (i % cols + 1),
|
|
216
|
-
y: spacingY * (Math.floor(i / cols) + 1)
|
|
217
|
-
}));
|
|
218
|
-
}
|
|
219
|
-
return initialNodes;
|
|
341
|
+
const copy = initialNodes.map((n) => ({ ...n }));
|
|
342
|
+
if (layout === "circular") applyCircularLayout(copy, width, height);
|
|
343
|
+
else if (layout === "hierarchical")
|
|
344
|
+
applyHierarchicalLayout(copy, width, height);
|
|
345
|
+
else applyInitialForceLayout(copy, width, height);
|
|
346
|
+
return copy;
|
|
220
347
|
}, [initialNodes, width, height, layout]);
|
|
221
|
-
const links = initialLinks;
|
|
222
348
|
const restart = React.useCallback(() => {
|
|
223
349
|
}, []);
|
|
224
350
|
const stop = React.useCallback(() => {
|
|
@@ -227,55 +353,14 @@ var ForceDirectedGraph = forwardRef(
|
|
|
227
353
|
}, []);
|
|
228
354
|
useEffect(() => {
|
|
229
355
|
if (!nodes || nodes.length === 0) return;
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
const radius = Math.min(width, height) * 0.35;
|
|
235
|
-
nodes.forEach((node, i) => {
|
|
236
|
-
const angle = 2 * Math.PI * i / nodes.length;
|
|
237
|
-
node.fx = centerX + Math.cos(angle) * radius;
|
|
238
|
-
node.fy = centerY + Math.sin(angle) * radius;
|
|
239
|
-
});
|
|
240
|
-
} else if (layout === "hierarchical") {
|
|
241
|
-
const groups = /* @__PURE__ */ new Map();
|
|
242
|
-
nodes.forEach((n) => {
|
|
243
|
-
const key = n.packageGroup || n.group || "root";
|
|
244
|
-
if (!groups.has(key)) groups.set(key, []);
|
|
245
|
-
groups.get(key).push(n);
|
|
246
|
-
});
|
|
247
|
-
const groupArray = Array.from(groups.entries());
|
|
248
|
-
const cols = Math.ceil(Math.sqrt(groupArray.length));
|
|
249
|
-
const groupSpacingX = width * 0.8 / cols;
|
|
250
|
-
const groupSpacingY = height * 0.8 / Math.ceil(groupArray.length / cols);
|
|
251
|
-
groupArray.forEach(([groupKey, groupNodes], gi) => {
|
|
252
|
-
const col = gi % cols;
|
|
253
|
-
const row = Math.floor(gi / cols);
|
|
254
|
-
const groupX = (col + 0.5) * groupSpacingX;
|
|
255
|
-
const groupY = (row + 0.5) * groupSpacingY;
|
|
256
|
-
if (groupKey.startsWith("pkg:") || groupKey === groupKey) {
|
|
257
|
-
groupNodes.forEach((n, ni) => {
|
|
258
|
-
const angle = 2 * Math.PI * ni / groupNodes.length;
|
|
259
|
-
const r = Math.min(80, 20 + groupNodes.length * 8);
|
|
260
|
-
n.fx = groupX + Math.cos(angle) * r;
|
|
261
|
-
n.fy = groupY + Math.sin(angle) * r;
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
});
|
|
265
|
-
}
|
|
266
|
-
try {
|
|
267
|
-
restart();
|
|
268
|
-
} catch (e) {
|
|
269
|
-
}
|
|
270
|
-
};
|
|
271
|
-
applyLayout();
|
|
356
|
+
if (layout === "circular") applyCircularLayout(nodes, width, height);
|
|
357
|
+
else if (layout === "hierarchical")
|
|
358
|
+
applyHierarchicalLayout(nodes, width, height);
|
|
359
|
+
restart();
|
|
272
360
|
}, [layout, nodes, width, height, restart]);
|
|
273
361
|
useEffect(() => {
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
else setForcesEnabled(true);
|
|
277
|
-
} catch (e) {
|
|
278
|
-
}
|
|
362
|
+
if (manualLayout || pinnedNodes.size > 0) setForcesEnabled(false);
|
|
363
|
+
else setForcesEnabled(true);
|
|
279
364
|
}, [manualLayout, pinnedNodes, setForcesEnabled]);
|
|
280
365
|
useImperativeHandle(
|
|
281
366
|
ref,
|
|
@@ -311,7 +396,7 @@ var ForceDirectedGraph = forwardRef(
|
|
|
311
396
|
let minX = Infinity, maxX = -Infinity, minY = Infinity, maxY = -Infinity;
|
|
312
397
|
nodes.forEach((node) => {
|
|
313
398
|
if (node.x !== void 0 && node.y !== void 0) {
|
|
314
|
-
const size = node.size ||
|
|
399
|
+
const size = node.size || DEFAULT_NODE_SIZE;
|
|
315
400
|
minX = Math.min(minX, node.x - size);
|
|
316
401
|
maxX = Math.max(maxX, node.x + size);
|
|
317
402
|
minY = Math.min(minY, node.y - size);
|
|
@@ -319,22 +404,17 @@ var ForceDirectedGraph = forwardRef(
|
|
|
319
404
|
}
|
|
320
405
|
});
|
|
321
406
|
if (!isFinite(minX)) return;
|
|
322
|
-
const padding = 40;
|
|
323
|
-
const nodeWidth = maxX - minX;
|
|
324
|
-
const nodeHeight = maxY - minY;
|
|
325
407
|
const scale = Math.min(
|
|
326
|
-
(width -
|
|
327
|
-
(height -
|
|
408
|
+
(width - FIT_VIEW_PADDING * 2) / (maxX - minX),
|
|
409
|
+
(height - FIT_VIEW_PADDING * 2) / (maxY - minY),
|
|
328
410
|
10
|
|
329
411
|
);
|
|
330
|
-
const
|
|
331
|
-
const
|
|
332
|
-
const x = width / 2 - centerX * scale;
|
|
333
|
-
const y = height / 2 - centerY * scale;
|
|
412
|
+
const x = width / 2 - (minX + maxX) / 2 * scale;
|
|
413
|
+
const y = height / 2 - (minY + maxY) / 2 * scale;
|
|
334
414
|
if (gRef.current && svgRef.current) {
|
|
335
|
-
const svg =
|
|
336
|
-
const newTransform =
|
|
337
|
-
svg.transition().duration(
|
|
415
|
+
const svg = d32.select(svgRef.current);
|
|
416
|
+
const newTransform = d32.zoomIdentity.translate(x, y).scale(scale);
|
|
417
|
+
svg.transition().duration(TRANSITION_DURATION_MS).call(d32.zoom().transform, newTransform);
|
|
338
418
|
setTransform(newTransform);
|
|
339
419
|
}
|
|
340
420
|
},
|
|
@@ -342,57 +422,56 @@ var ForceDirectedGraph = forwardRef(
|
|
|
342
422
|
setDragMode: (enabled) => {
|
|
343
423
|
internalDragEnabledRef.current = enabled;
|
|
344
424
|
},
|
|
345
|
-
setLayout: (newLayout) =>
|
|
346
|
-
handleLayoutChange(newLayout);
|
|
347
|
-
},
|
|
425
|
+
setLayout: (newLayout) => handleLayoutChange(newLayout),
|
|
348
426
|
getLayout: () => layout
|
|
349
427
|
}),
|
|
350
|
-
[
|
|
428
|
+
[
|
|
429
|
+
nodes,
|
|
430
|
+
pinnedNodes,
|
|
431
|
+
restart,
|
|
432
|
+
width,
|
|
433
|
+
height,
|
|
434
|
+
layout,
|
|
435
|
+
handleLayoutChange,
|
|
436
|
+
setForcesEnabled
|
|
437
|
+
]
|
|
351
438
|
);
|
|
352
439
|
useEffect(() => {
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
onManualLayoutChange(manualLayout);
|
|
356
|
-
} catch (e) {
|
|
357
|
-
}
|
|
440
|
+
if (typeof onManualLayoutChange === "function")
|
|
441
|
+
onManualLayoutChange(manualLayout);
|
|
358
442
|
}, [manualLayout, onManualLayoutChange]);
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
};
|
|
372
|
-
}, [enableZoom]);
|
|
443
|
+
useGraphZoom(svgRef, gRef, enableZoom, setTransform, transformRef);
|
|
444
|
+
useWindowDrag(
|
|
445
|
+
enableDrag,
|
|
446
|
+
svgRef,
|
|
447
|
+
transformRef,
|
|
448
|
+
dragActiveRef,
|
|
449
|
+
dragNodeRef,
|
|
450
|
+
() => {
|
|
451
|
+
setForcesEnabled(true);
|
|
452
|
+
restart();
|
|
453
|
+
}
|
|
454
|
+
);
|
|
373
455
|
useEffect(() => {
|
|
374
456
|
if (!gRef.current) return;
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
} catch (e) {
|
|
394
|
-
}
|
|
395
|
-
}, [nodes, links]);
|
|
457
|
+
const g = d32.select(gRef.current);
|
|
458
|
+
g.selectAll("g.node").each(function() {
|
|
459
|
+
const datum = d32.select(this).datum();
|
|
460
|
+
if (!datum) return;
|
|
461
|
+
d32.select(this).attr(
|
|
462
|
+
"transform",
|
|
463
|
+
`translate(${datum.x || 0},${datum.y || 0})`
|
|
464
|
+
);
|
|
465
|
+
});
|
|
466
|
+
g.selectAll("line").each(function() {
|
|
467
|
+
const l = d32.select(this).datum();
|
|
468
|
+
if (!l) return;
|
|
469
|
+
const s = typeof l.source === "object" ? l.source : nodes.find((n) => n.id === l.source) || l.source;
|
|
470
|
+
const t = typeof l.target === "object" ? l.target : nodes.find((n) => n.id === l.target) || l.target;
|
|
471
|
+
if (!s || !t) return;
|
|
472
|
+
d32.select(this).attr("x1", s.x).attr("y1", s.y).attr("x2", t.x).attr("y2", t.y);
|
|
473
|
+
});
|
|
474
|
+
}, [nodes, initialLinks]);
|
|
396
475
|
const handleDragStart = useCallback(
|
|
397
476
|
(event, node) => {
|
|
398
477
|
if (!enableDrag) return;
|
|
@@ -403,103 +482,50 @@ var ForceDirectedGraph = forwardRef(
|
|
|
403
482
|
node.fx = node.x;
|
|
404
483
|
node.fy = node.y;
|
|
405
484
|
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
406
|
-
|
|
407
|
-
stop();
|
|
408
|
-
} catch (e) {
|
|
409
|
-
}
|
|
485
|
+
stop();
|
|
410
486
|
},
|
|
411
|
-
[enableDrag,
|
|
487
|
+
[enableDrag, stop]
|
|
412
488
|
);
|
|
413
|
-
useEffect(() => {
|
|
414
|
-
if (!enableDrag) return;
|
|
415
|
-
const handleWindowMove = (event) => {
|
|
416
|
-
if (!dragActiveRef.current || !dragNodeRef.current) return;
|
|
417
|
-
const svg = svgRef.current;
|
|
418
|
-
if (!svg) return;
|
|
419
|
-
const rect = svg.getBoundingClientRect();
|
|
420
|
-
const t = transformRef.current;
|
|
421
|
-
const x = (event.clientX - rect.left - t.x) / t.k;
|
|
422
|
-
const y = (event.clientY - rect.top - t.y) / t.k;
|
|
423
|
-
dragNodeRef.current.fx = x;
|
|
424
|
-
dragNodeRef.current.fy = y;
|
|
425
|
-
};
|
|
426
|
-
const handleWindowUp = () => {
|
|
427
|
-
if (!dragActiveRef.current) return;
|
|
428
|
-
try {
|
|
429
|
-
setForcesEnabled(true);
|
|
430
|
-
restart();
|
|
431
|
-
} catch (e) {
|
|
432
|
-
}
|
|
433
|
-
dragNodeRef.current = null;
|
|
434
|
-
dragActiveRef.current = false;
|
|
435
|
-
};
|
|
436
|
-
const handleWindowLeave = (event) => {
|
|
437
|
-
if (event.relatedTarget === null) handleWindowUp();
|
|
438
|
-
};
|
|
439
|
-
window.addEventListener("mousemove", handleWindowMove);
|
|
440
|
-
window.addEventListener("mouseup", handleWindowUp);
|
|
441
|
-
window.addEventListener("mouseout", handleWindowLeave);
|
|
442
|
-
window.addEventListener("blur", handleWindowUp);
|
|
443
|
-
return () => {
|
|
444
|
-
window.removeEventListener("mousemove", handleWindowMove);
|
|
445
|
-
window.removeEventListener("mouseup", handleWindowUp);
|
|
446
|
-
window.removeEventListener("mouseout", handleWindowLeave);
|
|
447
|
-
window.removeEventListener("blur", handleWindowUp);
|
|
448
|
-
};
|
|
449
|
-
}, [enableDrag]);
|
|
450
489
|
useEffect(() => {
|
|
451
490
|
if (!gRef.current || !enableDrag) return;
|
|
452
|
-
const g =
|
|
453
|
-
const dragBehavior =
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
468
|
-
} catch (e) {
|
|
469
|
-
}
|
|
470
|
-
}).on("drag", function(event) {
|
|
491
|
+
const g = d32.select(gRef.current);
|
|
492
|
+
const dragBehavior = d32.drag().on("start", (event) => {
|
|
493
|
+
const target = event.sourceEvent && event.sourceEvent.target || event.target;
|
|
494
|
+
const grp = target.closest?.("g.node");
|
|
495
|
+
const id = grp?.getAttribute("data-id");
|
|
496
|
+
if (!id || !internalDragEnabledRef.current) return;
|
|
497
|
+
const node = nodes.find((n) => n.id === id);
|
|
498
|
+
if (!node) return;
|
|
499
|
+
if (!event.active) restart();
|
|
500
|
+
dragActiveRef.current = true;
|
|
501
|
+
dragNodeRef.current = node;
|
|
502
|
+
node.fx = node.x;
|
|
503
|
+
node.fy = node.y;
|
|
504
|
+
setPinnedNodes((prev) => /* @__PURE__ */ new Set([...prev, node.id]));
|
|
505
|
+
}).on("drag", (event) => {
|
|
471
506
|
if (!dragActiveRef.current || !dragNodeRef.current) return;
|
|
472
507
|
const svg = svgRef.current;
|
|
473
508
|
if (!svg) return;
|
|
474
509
|
const rect = svg.getBoundingClientRect();
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
try {
|
|
481
|
-
setForcesEnabled(true);
|
|
482
|
-
restart();
|
|
483
|
-
} catch (e) {
|
|
484
|
-
}
|
|
510
|
+
dragNodeRef.current.fx = (event.sourceEvent.clientX - rect.left - transform.x) / transform.k;
|
|
511
|
+
dragNodeRef.current.fy = (event.sourceEvent.clientY - rect.top - transform.y) / transform.k;
|
|
512
|
+
}).on("end", () => {
|
|
513
|
+
setForcesEnabled(true);
|
|
514
|
+
restart();
|
|
485
515
|
});
|
|
486
|
-
|
|
487
|
-
g.selectAll("g.node").call(dragBehavior);
|
|
488
|
-
} catch (e) {
|
|
489
|
-
}
|
|
516
|
+
g.selectAll("g.node").call(dragBehavior);
|
|
490
517
|
return () => {
|
|
491
|
-
|
|
492
|
-
g.selectAll("g.node").on(".drag", null);
|
|
493
|
-
} catch (e) {
|
|
494
|
-
}
|
|
518
|
+
g.selectAll("g.node").on(".drag", null);
|
|
495
519
|
};
|
|
496
|
-
}, [
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
520
|
+
}, [
|
|
521
|
+
gRef,
|
|
522
|
+
enableDrag,
|
|
523
|
+
nodes,
|
|
524
|
+
transform,
|
|
525
|
+
restart,
|
|
526
|
+
setForcesEnabled,
|
|
527
|
+
internalDragEnabledRef
|
|
528
|
+
]);
|
|
503
529
|
const handleNodeDoubleClick = useCallback(
|
|
504
530
|
(event, node) => {
|
|
505
531
|
event.stopPropagation();
|
|
@@ -521,29 +547,6 @@ var ForceDirectedGraph = forwardRef(
|
|
|
521
547
|
},
|
|
522
548
|
[enableDrag, restart]
|
|
523
549
|
);
|
|
524
|
-
const handleCanvasDoubleClick = useCallback(() => {
|
|
525
|
-
nodes.forEach((node) => {
|
|
526
|
-
node.fx = null;
|
|
527
|
-
node.fy = null;
|
|
528
|
-
});
|
|
529
|
-
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
530
|
-
restart();
|
|
531
|
-
}, [nodes, restart]);
|
|
532
|
-
const handleNodeMouseEnter = useCallback(
|
|
533
|
-
(node) => {
|
|
534
|
-
onNodeHover?.(node);
|
|
535
|
-
},
|
|
536
|
-
[onNodeHover]
|
|
537
|
-
);
|
|
538
|
-
const handleNodeMouseLeave = useCallback(() => {
|
|
539
|
-
onNodeHover?.(null);
|
|
540
|
-
}, [onNodeHover]);
|
|
541
|
-
const handleLinkClick = useCallback(
|
|
542
|
-
(link) => {
|
|
543
|
-
onLinkClick?.(link);
|
|
544
|
-
},
|
|
545
|
-
[onLinkClick]
|
|
546
|
-
);
|
|
547
550
|
return /* @__PURE__ */ jsxs(
|
|
548
551
|
"svg",
|
|
549
552
|
{
|
|
@@ -551,7 +554,14 @@ var ForceDirectedGraph = forwardRef(
|
|
|
551
554
|
width,
|
|
552
555
|
height,
|
|
553
556
|
className: cn("bg-white dark:bg-gray-900", className),
|
|
554
|
-
onDoubleClick:
|
|
557
|
+
onDoubleClick: () => {
|
|
558
|
+
nodes.forEach((n) => {
|
|
559
|
+
n.fx = null;
|
|
560
|
+
n.fy = null;
|
|
561
|
+
});
|
|
562
|
+
setPinnedNodes(/* @__PURE__ */ new Set());
|
|
563
|
+
restart();
|
|
564
|
+
},
|
|
555
565
|
children: [
|
|
556
566
|
/* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
|
|
557
567
|
"marker",
|
|
@@ -567,11 +577,11 @@ var ForceDirectedGraph = forwardRef(
|
|
|
567
577
|
}
|
|
568
578
|
) }),
|
|
569
579
|
/* @__PURE__ */ jsxs("g", { ref: gRef, children: [
|
|
570
|
-
|
|
580
|
+
initialLinks.map((link, i) => /* @__PURE__ */ jsx(
|
|
571
581
|
LinkItem_default,
|
|
572
582
|
{
|
|
573
583
|
link,
|
|
574
|
-
onClick:
|
|
584
|
+
onClick: onLinkClick,
|
|
575
585
|
defaultWidth: defaultLinkWidth,
|
|
576
586
|
showLabel: showLinkLabels,
|
|
577
587
|
nodes
|
|
@@ -588,41 +598,15 @@ var ForceDirectedGraph = forwardRef(
|
|
|
588
598
|
defaultNodeSize,
|
|
589
599
|
defaultNodeColor,
|
|
590
600
|
showLabel: showNodeLabels,
|
|
591
|
-
onClick:
|
|
601
|
+
onClick: onNodeClick,
|
|
592
602
|
onDoubleClick: handleNodeDoubleClick,
|
|
593
|
-
onMouseEnter:
|
|
594
|
-
onMouseLeave:
|
|
603
|
+
onMouseEnter: (n) => onNodeHover?.(n),
|
|
604
|
+
onMouseLeave: () => onNodeHover?.(null),
|
|
595
605
|
onMouseDown: handleDragStart
|
|
596
606
|
},
|
|
597
607
|
node.id
|
|
598
608
|
)),
|
|
599
|
-
|
|
600
|
-
/* @__PURE__ */ jsx(
|
|
601
|
-
"circle",
|
|
602
|
-
{
|
|
603
|
-
cx: b.x,
|
|
604
|
-
cy: b.y,
|
|
605
|
-
r: b.r,
|
|
606
|
-
fill: "rgba(148,163,184,0.06)",
|
|
607
|
-
stroke: "#475569",
|
|
608
|
-
strokeWidth: 2,
|
|
609
|
-
strokeDasharray: "6 6",
|
|
610
|
-
opacity: 0.9
|
|
611
|
-
}
|
|
612
|
-
),
|
|
613
|
-
/* @__PURE__ */ jsx(
|
|
614
|
-
"text",
|
|
615
|
-
{
|
|
616
|
-
x: b.x,
|
|
617
|
-
y: Math.max(12, b.y - b.r + 14),
|
|
618
|
-
fill: "#475569",
|
|
619
|
-
fontSize: 11,
|
|
620
|
-
textAnchor: "middle",
|
|
621
|
-
pointerEvents: "none",
|
|
622
|
-
children: pid.replace(/^pkg:/, "")
|
|
623
|
-
}
|
|
624
|
-
)
|
|
625
|
-
] }, pid)) })
|
|
609
|
+
/* @__PURE__ */ jsx(PackageBoundaries, { packageBounds: packageBounds || {} })
|
|
626
610
|
] })
|
|
627
611
|
]
|
|
628
612
|
}
|