footprint-explainable-ui 0.25.0 → 0.25.2
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/flowchart.cjs +301 -120
- package/dist/flowchart.cjs.map +1 -1
- package/dist/flowchart.d.cts +87 -13
- package/dist/flowchart.d.ts +87 -13
- package/dist/flowchart.js +238 -57
- package/dist/flowchart.js.map +1 -1
- package/dist/index.cjs +326 -82
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +15 -16
- package/dist/index.d.ts +15 -16
- package/dist/index.js +255 -11
- package/dist/index.js.map +1 -1
- package/package.json +31 -12
package/dist/flowchart.js
CHANGED
|
@@ -490,7 +490,7 @@ var StageNode = memo(function StageNode2({
|
|
|
490
490
|
background: bg,
|
|
491
491
|
border: `${isHero ? "2.5px" : isMuted ? "1px" : "2px"} ${isLazyUnresolved ? "dashed" : "solid"} ${borderColor}`,
|
|
492
492
|
borderRadius: theme.radius,
|
|
493
|
-
padding: description ? `${Math.round(
|
|
493
|
+
padding: description ? `${Math.round(6 * sizeScale)}px ${Math.round(12 * sizeScale)}px` : `${Math.round(7 * sizeScale)}px ${Math.round(14 * sizeScale)}px`,
|
|
494
494
|
display: "flex",
|
|
495
495
|
flexDirection: "column",
|
|
496
496
|
alignItems: "center",
|
|
@@ -1464,6 +1464,14 @@ function staggeredBendY(sourceBottom, targetTop, others, minGapFromTarget = 8) {
|
|
|
1464
1464
|
if (lowestSkippedBottom === -Infinity) return null;
|
|
1465
1465
|
return Math.min((lowestSkippedBottom + targetTop) / 2, targetTop - minGapFromTarget);
|
|
1466
1466
|
}
|
|
1467
|
+
function forkFanBendY(sourceBottom, childTops, minGapFromTarget = 8) {
|
|
1468
|
+
if (childTops.length < 2) return null;
|
|
1469
|
+
const nearestTop = Math.min(...childTops);
|
|
1470
|
+
return Math.min((sourceBottom + nearestTop) / 2, nearestTop - minGapFromTarget);
|
|
1471
|
+
}
|
|
1472
|
+
function resolveStepBendY(forkBend, staggeredBend) {
|
|
1473
|
+
return staggeredBend ?? forkBend;
|
|
1474
|
+
}
|
|
1467
1475
|
|
|
1468
1476
|
// src/components/SmartStepEdge/SmartStepEdge.tsx
|
|
1469
1477
|
import { jsx as jsx7 } from "react/jsx-runtime";
|
|
@@ -1486,6 +1494,16 @@ function SmartStepEdge({
|
|
|
1486
1494
|
if (!src || !tgt) return null;
|
|
1487
1495
|
const sourceBottom = src.internals.positionAbsolute.y + (src.measured.height ?? 0);
|
|
1488
1496
|
const targetTop = tgt.internals.positionAbsolute.y;
|
|
1497
|
+
const childTops = [];
|
|
1498
|
+
for (const e of s.edges) {
|
|
1499
|
+
if (e.source !== source) continue;
|
|
1500
|
+
if (e.data?.kind === "loop") continue;
|
|
1501
|
+
const c = s.nodeLookup.get(e.target);
|
|
1502
|
+
if (c && c.type !== GROUP_CONTAINER_NODE_TYPE) {
|
|
1503
|
+
childTops.push(c.internals.positionAbsolute.y);
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
const fan = forkFanBendY(sourceBottom, childTops);
|
|
1489
1507
|
const others = [];
|
|
1490
1508
|
for (const n of s.nodeLookup.values()) {
|
|
1491
1509
|
if (n.id === source || n.id === target) continue;
|
|
@@ -1493,7 +1511,8 @@ function SmartStepEdge({
|
|
|
1493
1511
|
const top = n.internals.positionAbsolute.y;
|
|
1494
1512
|
others.push({ top, bottom: top + (n.measured.height ?? 0) });
|
|
1495
1513
|
}
|
|
1496
|
-
|
|
1514
|
+
const staggered = staggeredBendY(sourceBottom, targetTop, others);
|
|
1515
|
+
return resolveStepBendY(fan, staggered);
|
|
1497
1516
|
});
|
|
1498
1517
|
const [path] = getSmoothStepPath({
|
|
1499
1518
|
sourceX,
|
|
@@ -1856,7 +1875,7 @@ function TraceFlow(props) {
|
|
|
1856
1875
|
}
|
|
1857
1876
|
|
|
1858
1877
|
// src/components/FlowchartView/TracedFlow.tsx
|
|
1859
|
-
import { useCallback as useCallback3, useMemo as useMemo5, useRef as useRef5, useState as useState4 } from "react";
|
|
1878
|
+
import { useCallback as useCallback3, useEffect as useEffect7, useMemo as useMemo5, useRef as useRef5, useState as useState4 } from "react";
|
|
1860
1879
|
import {
|
|
1861
1880
|
ReactFlow as ReactFlow2,
|
|
1862
1881
|
Background as Background2,
|
|
@@ -1874,6 +1893,150 @@ function devWarn(messageFn, ...extras) {
|
|
|
1874
1893
|
console.warn(messageFn(), ...extras);
|
|
1875
1894
|
}
|
|
1876
1895
|
|
|
1896
|
+
// src/components/FlowchartView/_internal/snapLinearSuccessors.ts
|
|
1897
|
+
function snapLinearSuccessors(graph, options = {}) {
|
|
1898
|
+
if (graph.nodes.length === 0) return graph;
|
|
1899
|
+
const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
|
|
1900
|
+
const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
|
|
1901
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1902
|
+
const width = /* @__PURE__ */ new Map();
|
|
1903
|
+
for (const n of graph.nodes) {
|
|
1904
|
+
byId.set(n.id, n);
|
|
1905
|
+
width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
|
|
1906
|
+
}
|
|
1907
|
+
const preds = /* @__PURE__ */ new Map();
|
|
1908
|
+
const outDegree = /* @__PURE__ */ new Map();
|
|
1909
|
+
const seenEdge = /* @__PURE__ */ new Set();
|
|
1910
|
+
for (const e of graph.edges) {
|
|
1911
|
+
if (e.data?.kind === "loop") continue;
|
|
1912
|
+
if (!byId.has(e.source) || !byId.has(e.target)) continue;
|
|
1913
|
+
const key = `${e.source}\0${e.target}`;
|
|
1914
|
+
if (seenEdge.has(key)) continue;
|
|
1915
|
+
seenEdge.add(key);
|
|
1916
|
+
const list = preds.get(e.target);
|
|
1917
|
+
if (list) list.push(e.source);
|
|
1918
|
+
else preds.set(e.target, [e.source]);
|
|
1919
|
+
outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
|
|
1920
|
+
}
|
|
1921
|
+
const workingX = /* @__PURE__ */ new Map();
|
|
1922
|
+
for (const n of graph.nodes) workingX.set(n.id, n.position.x);
|
|
1923
|
+
const centerX = (id) => workingX.get(id) + width.get(id) / 2;
|
|
1924
|
+
const order = [...graph.nodes].sort(
|
|
1925
|
+
(a, b) => a.position.y - b.position.y || a.position.x - b.position.x || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
1926
|
+
);
|
|
1927
|
+
for (const n of order) {
|
|
1928
|
+
const p = preds.get(n.id);
|
|
1929
|
+
if (!p || p.length !== 1) continue;
|
|
1930
|
+
const pid = p[0];
|
|
1931
|
+
if ((outDegree.get(pid) ?? 0) !== 1) continue;
|
|
1932
|
+
const P = byId.get(pid);
|
|
1933
|
+
if ((n.parentId ?? void 0) !== (P.parentId ?? void 0)) continue;
|
|
1934
|
+
workingX.set(n.id, centerX(pid) - width.get(n.id) / 2);
|
|
1935
|
+
}
|
|
1936
|
+
const nodes = graph.nodes.map((n) => {
|
|
1937
|
+
const nx = workingX.get(n.id);
|
|
1938
|
+
return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };
|
|
1939
|
+
});
|
|
1940
|
+
return { nodes, edges: graph.edges };
|
|
1941
|
+
}
|
|
1942
|
+
function createSnappedDagreLayout(base, options = {}) {
|
|
1943
|
+
return (graph) => snapLinearSuccessors(base(graph), options);
|
|
1944
|
+
}
|
|
1945
|
+
|
|
1946
|
+
// src/components/FlowchartView/_internal/centerForkParents.ts
|
|
1947
|
+
function centerForkParents(graph, options = {}) {
|
|
1948
|
+
if (graph.nodes.length === 0) return graph;
|
|
1949
|
+
const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
|
|
1950
|
+
const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
|
|
1951
|
+
const byId = /* @__PURE__ */ new Map();
|
|
1952
|
+
const width = /* @__PURE__ */ new Map();
|
|
1953
|
+
for (const n of graph.nodes) {
|
|
1954
|
+
byId.set(n.id, n);
|
|
1955
|
+
width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
|
|
1956
|
+
}
|
|
1957
|
+
const childrenOf = /* @__PURE__ */ new Map();
|
|
1958
|
+
const predsOf = /* @__PURE__ */ new Map();
|
|
1959
|
+
const outDegree = /* @__PURE__ */ new Map();
|
|
1960
|
+
const inDegree = /* @__PURE__ */ new Map();
|
|
1961
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1962
|
+
for (const e of graph.edges) {
|
|
1963
|
+
if (e.data?.kind === "loop") continue;
|
|
1964
|
+
if (!byId.has(e.source) || !byId.has(e.target)) continue;
|
|
1965
|
+
const key = `${e.source} ${e.target}`;
|
|
1966
|
+
if (seen.has(key)) continue;
|
|
1967
|
+
seen.add(key);
|
|
1968
|
+
const cl = childrenOf.get(e.source);
|
|
1969
|
+
if (cl) cl.push(e.target);
|
|
1970
|
+
else childrenOf.set(e.source, [e.target]);
|
|
1971
|
+
const pl = predsOf.get(e.target);
|
|
1972
|
+
if (pl) pl.push(e.source);
|
|
1973
|
+
else predsOf.set(e.target, [e.source]);
|
|
1974
|
+
outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
|
|
1975
|
+
inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
|
|
1976
|
+
}
|
|
1977
|
+
const workingX = /* @__PURE__ */ new Map();
|
|
1978
|
+
for (const n of graph.nodes) workingX.set(n.id, n.position.x);
|
|
1979
|
+
const centerX = (id) => workingX.get(id) + width.get(id) / 2;
|
|
1980
|
+
const nodeSep = options.nodeSep ?? 60;
|
|
1981
|
+
const clampX = (id, desiredX) => {
|
|
1982
|
+
const w = width.get(id);
|
|
1983
|
+
const x0 = workingX.get(id);
|
|
1984
|
+
const self = byId.get(id);
|
|
1985
|
+
let minX = -Infinity;
|
|
1986
|
+
let maxX = Infinity;
|
|
1987
|
+
for (const m of graph.nodes) {
|
|
1988
|
+
if (m.id === id || m.parentId !== self.parentId) continue;
|
|
1989
|
+
if (Math.abs(m.position.y - self.position.y) > 1) continue;
|
|
1990
|
+
const mLeft = workingX.get(m.id);
|
|
1991
|
+
const mRight = mLeft + width.get(m.id);
|
|
1992
|
+
if (mRight <= x0) minX = Math.max(minX, mRight + nodeSep);
|
|
1993
|
+
else if (mLeft >= x0 + w) maxX = Math.min(maxX, mLeft - nodeSep - w);
|
|
1994
|
+
}
|
|
1995
|
+
return minX <= maxX ? Math.max(minX, Math.min(maxX, desiredX)) : x0;
|
|
1996
|
+
};
|
|
1997
|
+
const order = [...graph.nodes].sort(
|
|
1998
|
+
(a, b) => b.position.y - a.position.y || a.position.x - b.position.x || a.id.localeCompare(b.id)
|
|
1999
|
+
);
|
|
2000
|
+
for (const n of order) {
|
|
2001
|
+
const outD = outDegree.get(n.id) ?? 0;
|
|
2002
|
+
const inD = inDegree.get(n.id) ?? 0;
|
|
2003
|
+
const isFork = outD >= 2 && inD <= 1;
|
|
2004
|
+
const isMerge = inD >= 2 && outD <= 1;
|
|
2005
|
+
if (!isFork && !isMerge) continue;
|
|
2006
|
+
const kin = ((isFork ? childrenOf.get(n.id) : predsOf.get(n.id)) ?? []).filter(
|
|
2007
|
+
(k) => byId.get(k)?.parentId === n.parentId
|
|
2008
|
+
// same compound only
|
|
2009
|
+
);
|
|
2010
|
+
if (kin.length < 2) continue;
|
|
2011
|
+
const centers = kin.map(centerX);
|
|
2012
|
+
const wN = width.get(n.id);
|
|
2013
|
+
const span = (Math.min(...centers) + Math.max(...centers)) / 2;
|
|
2014
|
+
workingX.set(n.id, clampX(n.id, span - wN / 2));
|
|
2015
|
+
const stepOf = isFork ? predsOf : childrenOf;
|
|
2016
|
+
let curId = n.id;
|
|
2017
|
+
const walked = /* @__PURE__ */ new Set([curId]);
|
|
2018
|
+
for (; ; ) {
|
|
2019
|
+
const nexts = stepOf.get(curId);
|
|
2020
|
+
if (!nexts || nexts.length !== 1) break;
|
|
2021
|
+
const m = nexts[0];
|
|
2022
|
+
if (walked.has(m)) break;
|
|
2023
|
+
if ((outDegree.get(m) ?? 0) > 1) break;
|
|
2024
|
+
if ((inDegree.get(m) ?? 0) > 1) break;
|
|
2025
|
+
if (byId.get(m)?.parentId !== byId.get(curId)?.parentId) break;
|
|
2026
|
+
workingX.set(m, clampX(m, centerX(curId) - width.get(m) / 2));
|
|
2027
|
+
walked.add(m);
|
|
2028
|
+
curId = m;
|
|
2029
|
+
}
|
|
2030
|
+
}
|
|
2031
|
+
const nodes = graph.nodes.map(
|
|
2032
|
+
(n) => workingX.get(n.id) === n.position.x ? n : { ...n, position: { x: workingX.get(n.id), y: n.position.y } }
|
|
2033
|
+
);
|
|
2034
|
+
return { nodes, edges: graph.edges };
|
|
2035
|
+
}
|
|
2036
|
+
function withForkCentering(base, options = {}) {
|
|
2037
|
+
return (graph) => centerForkParents(base(graph), options);
|
|
2038
|
+
}
|
|
2039
|
+
|
|
1877
2040
|
// src/components/FlowchartView/_internal/notifyChange.ts
|
|
1878
2041
|
function createNotifier(label = "notifier") {
|
|
1879
2042
|
const listeners = /* @__PURE__ */ new Set();
|
|
@@ -2231,6 +2394,49 @@ function GroupContainerNode({ data }) {
|
|
|
2231
2394
|
);
|
|
2232
2395
|
}
|
|
2233
2396
|
|
|
2397
|
+
// src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
|
|
2398
|
+
import { useEffect as useEffect6 } from "react";
|
|
2399
|
+
import { useNodesInitialized, useStore as useStore3 } from "@xyflow/react";
|
|
2400
|
+
|
|
2401
|
+
// src/components/FlowchartView/_internal/measuredFootprints.ts
|
|
2402
|
+
function extractMeasuredFootprints(entries) {
|
|
2403
|
+
const sizes = /* @__PURE__ */ new Map();
|
|
2404
|
+
for (const [id, node] of entries) {
|
|
2405
|
+
const width = node.measured?.width;
|
|
2406
|
+
const height = node.measured?.height;
|
|
2407
|
+
if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
|
|
2408
|
+
sizes.set(id, { width: Math.round(width), height: Math.round(height) });
|
|
2409
|
+
}
|
|
2410
|
+
}
|
|
2411
|
+
return sizes;
|
|
2412
|
+
}
|
|
2413
|
+
function sameFootprints(a, b) {
|
|
2414
|
+
if (a === b) return true;
|
|
2415
|
+
if (a.size !== b.size) return false;
|
|
2416
|
+
for (const [id, s] of a) {
|
|
2417
|
+
const t = b.get(id);
|
|
2418
|
+
if (!t || t.width !== s.width || t.height !== s.height) return false;
|
|
2419
|
+
}
|
|
2420
|
+
return true;
|
|
2421
|
+
}
|
|
2422
|
+
|
|
2423
|
+
// src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
|
|
2424
|
+
function MeasuredNodeSizes({
|
|
2425
|
+
onSizes,
|
|
2426
|
+
includeHiddenNodes = false
|
|
2427
|
+
}) {
|
|
2428
|
+
const initialized = useNodesInitialized({ includeHiddenNodes });
|
|
2429
|
+
const sizes = useStore3(
|
|
2430
|
+
(s) => extractMeasuredFootprints(s.nodeLookup),
|
|
2431
|
+
sameFootprints
|
|
2432
|
+
);
|
|
2433
|
+
useEffect6(() => {
|
|
2434
|
+
if (!initialized || sizes.size === 0) return;
|
|
2435
|
+
onSizes(sizes);
|
|
2436
|
+
}, [initialized, sizes, onSizes]);
|
|
2437
|
+
return null;
|
|
2438
|
+
}
|
|
2439
|
+
|
|
2234
2440
|
// src/components/FlowchartView/TracedFlow.tsx
|
|
2235
2441
|
import { jsx as jsx11, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2236
2442
|
var DEFAULT_COLORS = {
|
|
@@ -2370,6 +2576,13 @@ function TracedFlow({
|
|
|
2370
2576
|
style
|
|
2371
2577
|
}) {
|
|
2372
2578
|
const layout = layoutProp ?? dagreTraceLayout;
|
|
2579
|
+
useEffect7(() => {
|
|
2580
|
+
if (layoutProp === dagreTraceLayout) {
|
|
2581
|
+
devWarn(
|
|
2582
|
+
() => "[footprint-explainable-ui] <TracedFlow layout={dagreTraceLayout}> bypasses the built-in measure-then-layout pipeline (content-exact sizing, fork/merge centering, straight spines). OMIT the `layout` prop to use it \u2014 passing the raw dagreTraceLayout silently forfeits every layout improvement eui ships."
|
|
2583
|
+
);
|
|
2584
|
+
}
|
|
2585
|
+
}, [layoutProp]);
|
|
2373
2586
|
const colors = useMemo5(
|
|
2374
2587
|
() => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
|
|
2375
2588
|
[colorOverrides]
|
|
@@ -2403,8 +2616,19 @@ function TracedFlow({
|
|
|
2403
2616
|
() => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
|
|
2404
2617
|
[graph, drill.currentSubflowId]
|
|
2405
2618
|
);
|
|
2619
|
+
const [measuredSizes, setMeasuredSizes] = useState4(null);
|
|
2406
2620
|
const positioned = useMemo5(() => {
|
|
2407
|
-
const
|
|
2621
|
+
const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
|
|
2622
|
+
const sizeOpts = nodeSize ? { nodeSize } : {};
|
|
2623
|
+
const dagreBase = withForkCentering(
|
|
2624
|
+
createSnappedDagreLayout(
|
|
2625
|
+
createDagreTraceLayout({ ...sizeOpts, rankSep: 52, nodeSep: 36 }),
|
|
2626
|
+
sizeOpts
|
|
2627
|
+
),
|
|
2628
|
+
{ ...sizeOpts, nodeSep: 36 }
|
|
2629
|
+
// same nodeSep → clamp preserves dagre's reserved gap
|
|
2630
|
+
);
|
|
2631
|
+
const realBase = layout === "passthrough" ? (g) => g : layoutProp === void 0 ? dagreBase : layout;
|
|
2408
2632
|
if (groupedSet.size > 0) {
|
|
2409
2633
|
const grouped = applyGroupLayout(filteredGraph, {
|
|
2410
2634
|
groupedSubflowIds: [...groupedSet],
|
|
@@ -2415,8 +2639,8 @@ function TracedFlow({
|
|
|
2415
2639
|
if (mainChartBox) {
|
|
2416
2640
|
return wrapInMainChartBox(filteredGraph, { baseLayout: realBase, ...mainChartBox });
|
|
2417
2641
|
}
|
|
2418
|
-
return
|
|
2419
|
-
}, [filteredGraph, layout, groupedSet, mainChartBox]);
|
|
2642
|
+
return realBase(filteredGraph);
|
|
2643
|
+
}, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
|
|
2420
2644
|
const slice = useMemo5(() => {
|
|
2421
2645
|
const empty = {
|
|
2422
2646
|
doneStageIds: /* @__PURE__ */ new Set(),
|
|
@@ -2460,7 +2684,11 @@ function TracedFlow({
|
|
|
2460
2684
|
);
|
|
2461
2685
|
const wrapperRef = useRef5(null);
|
|
2462
2686
|
const [rfInstance, setRfInstance] = useState4(null);
|
|
2463
|
-
useChartAutoRefit(wrapperRef, rfInstance, {
|
|
2687
|
+
useChartAutoRefit(wrapperRef, rfInstance, {
|
|
2688
|
+
// Re-fit on drill AND after the measured-size re-layout settles.
|
|
2689
|
+
refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
|
|
2690
|
+
padding: 0.18
|
|
2691
|
+
});
|
|
2464
2692
|
return /* @__PURE__ */ jsxs8(
|
|
2465
2693
|
"div",
|
|
2466
2694
|
{
|
|
@@ -2492,8 +2720,11 @@ function TracedFlow({
|
|
|
2492
2720
|
onNodeClick: handleNodeClick,
|
|
2493
2721
|
onInit: setRfInstance,
|
|
2494
2722
|
fitView: true,
|
|
2723
|
+
fitViewOptions: { padding: 0.18 },
|
|
2724
|
+
minZoom: 0.1,
|
|
2495
2725
|
proOptions: { hideAttribution: true },
|
|
2496
2726
|
children: [
|
|
2727
|
+
/* @__PURE__ */ jsx11(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
|
|
2497
2728
|
/* @__PURE__ */ jsx11(Background2, { variant: BackgroundVariant2.Dots, gap: 20, size: 1 }),
|
|
2498
2729
|
children
|
|
2499
2730
|
]
|
|
@@ -3508,56 +3739,6 @@ function SlotPillNode({ data }) {
|
|
|
3508
3739
|
);
|
|
3509
3740
|
}
|
|
3510
3741
|
|
|
3511
|
-
// src/components/FlowchartView/_internal/snapLinearSuccessors.ts
|
|
3512
|
-
function snapLinearSuccessors(graph, options = {}) {
|
|
3513
|
-
if (graph.nodes.length === 0) return graph;
|
|
3514
|
-
const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
|
|
3515
|
-
const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
|
|
3516
|
-
const byId = /* @__PURE__ */ new Map();
|
|
3517
|
-
const width = /* @__PURE__ */ new Map();
|
|
3518
|
-
for (const n of graph.nodes) {
|
|
3519
|
-
byId.set(n.id, n);
|
|
3520
|
-
width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
|
|
3521
|
-
}
|
|
3522
|
-
const preds = /* @__PURE__ */ new Map();
|
|
3523
|
-
const outDegree = /* @__PURE__ */ new Map();
|
|
3524
|
-
const seenEdge = /* @__PURE__ */ new Set();
|
|
3525
|
-
for (const e of graph.edges) {
|
|
3526
|
-
if (e.data?.kind === "loop") continue;
|
|
3527
|
-
if (!byId.has(e.source) || !byId.has(e.target)) continue;
|
|
3528
|
-
const key = `${e.source}\0${e.target}`;
|
|
3529
|
-
if (seenEdge.has(key)) continue;
|
|
3530
|
-
seenEdge.add(key);
|
|
3531
|
-
const list = preds.get(e.target);
|
|
3532
|
-
if (list) list.push(e.source);
|
|
3533
|
-
else preds.set(e.target, [e.source]);
|
|
3534
|
-
outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
|
|
3535
|
-
}
|
|
3536
|
-
const workingX = /* @__PURE__ */ new Map();
|
|
3537
|
-
for (const n of graph.nodes) workingX.set(n.id, n.position.x);
|
|
3538
|
-
const centerX = (id) => workingX.get(id) + width.get(id) / 2;
|
|
3539
|
-
const order = [...graph.nodes].sort(
|
|
3540
|
-
(a, b) => a.position.y - b.position.y || a.position.x - b.position.x || (a.id < b.id ? -1 : a.id > b.id ? 1 : 0)
|
|
3541
|
-
);
|
|
3542
|
-
for (const n of order) {
|
|
3543
|
-
const p = preds.get(n.id);
|
|
3544
|
-
if (!p || p.length !== 1) continue;
|
|
3545
|
-
const pid = p[0];
|
|
3546
|
-
if ((outDegree.get(pid) ?? 0) !== 1) continue;
|
|
3547
|
-
const P = byId.get(pid);
|
|
3548
|
-
if ((n.parentId ?? void 0) !== (P.parentId ?? void 0)) continue;
|
|
3549
|
-
workingX.set(n.id, centerX(pid) - width.get(n.id) / 2);
|
|
3550
|
-
}
|
|
3551
|
-
const nodes = graph.nodes.map((n) => {
|
|
3552
|
-
const nx = workingX.get(n.id);
|
|
3553
|
-
return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };
|
|
3554
|
-
});
|
|
3555
|
-
return { nodes, edges: graph.edges };
|
|
3556
|
-
}
|
|
3557
|
-
function createSnappedDagreLayout(base, options = {}) {
|
|
3558
|
-
return (graph) => snapLinearSuccessors(base(graph), options);
|
|
3559
|
-
}
|
|
3560
|
-
|
|
3561
3742
|
// src/components/FlowchartView/_internal/traceGroupLayout.ts
|
|
3562
3743
|
function buildAdjacency(graph, fallbackW, fallbackH, nodeSize) {
|
|
3563
3744
|
const preds = /* @__PURE__ */ new Map();
|