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.
@@ -572,7 +572,7 @@ var StageNode = (0, import_react3.memo)(function StageNode2({
572
572
  background: bg,
573
573
  border: `${isHero ? "2.5px" : isMuted ? "1px" : "2px"} ${isLazyUnresolved ? "dashed" : "solid"} ${borderColor}`,
574
574
  borderRadius: theme.radius,
575
- padding: description ? `${Math.round(8 * sizeScale)}px ${Math.round(16 * sizeScale)}px` : `${Math.round(10 * sizeScale)}px ${Math.round(20 * sizeScale)}px`,
575
+ padding: description ? `${Math.round(6 * sizeScale)}px ${Math.round(12 * sizeScale)}px` : `${Math.round(7 * sizeScale)}px ${Math.round(14 * sizeScale)}px`,
576
576
  display: "flex",
577
577
  flexDirection: "column",
578
578
  alignItems: "center",
@@ -687,7 +687,7 @@ var StageNode = (0, import_react3.memo)(function StageNode2({
687
687
  });
688
688
 
689
689
  // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
690
- var import_react18 = require("react");
690
+ var import_react20 = require("react");
691
691
 
692
692
  // src/components/MemoryInspector/MemoryInspector.tsx
693
693
  var import_react5 = require("react");
@@ -1541,6 +1541,14 @@ function staggeredBendY(sourceBottom, targetTop, others, minGapFromTarget = 8) {
1541
1541
  if (lowestSkippedBottom === -Infinity) return null;
1542
1542
  return Math.min((lowestSkippedBottom + targetTop) / 2, targetTop - minGapFromTarget);
1543
1543
  }
1544
+ function forkFanBendY(sourceBottom, childTops, minGapFromTarget = 8) {
1545
+ if (childTops.length < 2) return null;
1546
+ const nearestTop = Math.min(...childTops);
1547
+ return Math.min((sourceBottom + nearestTop) / 2, nearestTop - minGapFromTarget);
1548
+ }
1549
+ function resolveStepBendY(forkBend, staggeredBend) {
1550
+ return staggeredBend ?? forkBend;
1551
+ }
1544
1552
 
1545
1553
  // src/components/SmartStepEdge/SmartStepEdge.tsx
1546
1554
  var import_jsx_runtime7 = require("react/jsx-runtime");
@@ -1563,6 +1571,16 @@ function SmartStepEdge({
1563
1571
  if (!src || !tgt) return null;
1564
1572
  const sourceBottom = src.internals.positionAbsolute.y + (src.measured.height ?? 0);
1565
1573
  const targetTop = tgt.internals.positionAbsolute.y;
1574
+ const childTops = [];
1575
+ for (const e of s.edges) {
1576
+ if (e.source !== source) continue;
1577
+ if (e.data?.kind === "loop") continue;
1578
+ const c = s.nodeLookup.get(e.target);
1579
+ if (c && c.type !== GROUP_CONTAINER_NODE_TYPE) {
1580
+ childTops.push(c.internals.positionAbsolute.y);
1581
+ }
1582
+ }
1583
+ const fan = forkFanBendY(sourceBottom, childTops);
1566
1584
  const others = [];
1567
1585
  for (const n of s.nodeLookup.values()) {
1568
1586
  if (n.id === source || n.id === target) continue;
@@ -1570,7 +1588,8 @@ function SmartStepEdge({
1570
1588
  const top = n.internals.positionAbsolute.y;
1571
1589
  others.push({ top, bottom: top + (n.measured.height ?? 0) });
1572
1590
  }
1573
- return staggeredBendY(sourceBottom, targetTop, others);
1591
+ const staggered = staggeredBendY(sourceBottom, targetTop, others);
1592
+ return resolveStepBendY(fan, staggered);
1574
1593
  });
1575
1594
  const [path] = (0, import_react9.getSmoothStepPath)({
1576
1595
  sourceX,
@@ -1933,8 +1952,8 @@ function TraceFlow(props) {
1933
1952
  }
1934
1953
 
1935
1954
  // src/components/FlowchartView/TracedFlow.tsx
1936
- var import_react16 = require("react");
1937
- var import_react17 = require("@xyflow/react");
1955
+ var import_react18 = require("react");
1956
+ var import_react19 = require("@xyflow/react");
1938
1957
 
1939
1958
  // src/components/FlowchartView/_internal/devWarn.ts
1940
1959
  function isDevModeEnv() {
@@ -1946,6 +1965,150 @@ function devWarn(messageFn, ...extras) {
1946
1965
  console.warn(messageFn(), ...extras);
1947
1966
  }
1948
1967
 
1968
+ // src/components/FlowchartView/_internal/snapLinearSuccessors.ts
1969
+ function snapLinearSuccessors(graph, options = {}) {
1970
+ if (graph.nodes.length === 0) return graph;
1971
+ const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
1972
+ const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
1973
+ const byId = /* @__PURE__ */ new Map();
1974
+ const width = /* @__PURE__ */ new Map();
1975
+ for (const n of graph.nodes) {
1976
+ byId.set(n.id, n);
1977
+ width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
1978
+ }
1979
+ const preds = /* @__PURE__ */ new Map();
1980
+ const outDegree = /* @__PURE__ */ new Map();
1981
+ const seenEdge = /* @__PURE__ */ new Set();
1982
+ for (const e of graph.edges) {
1983
+ if (e.data?.kind === "loop") continue;
1984
+ if (!byId.has(e.source) || !byId.has(e.target)) continue;
1985
+ const key = `${e.source}\0${e.target}`;
1986
+ if (seenEdge.has(key)) continue;
1987
+ seenEdge.add(key);
1988
+ const list = preds.get(e.target);
1989
+ if (list) list.push(e.source);
1990
+ else preds.set(e.target, [e.source]);
1991
+ outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
1992
+ }
1993
+ const workingX = /* @__PURE__ */ new Map();
1994
+ for (const n of graph.nodes) workingX.set(n.id, n.position.x);
1995
+ const centerX = (id) => workingX.get(id) + width.get(id) / 2;
1996
+ const order = [...graph.nodes].sort(
1997
+ (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)
1998
+ );
1999
+ for (const n of order) {
2000
+ const p = preds.get(n.id);
2001
+ if (!p || p.length !== 1) continue;
2002
+ const pid = p[0];
2003
+ if ((outDegree.get(pid) ?? 0) !== 1) continue;
2004
+ const P = byId.get(pid);
2005
+ if ((n.parentId ?? void 0) !== (P.parentId ?? void 0)) continue;
2006
+ workingX.set(n.id, centerX(pid) - width.get(n.id) / 2);
2007
+ }
2008
+ const nodes = graph.nodes.map((n) => {
2009
+ const nx = workingX.get(n.id);
2010
+ return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };
2011
+ });
2012
+ return { nodes, edges: graph.edges };
2013
+ }
2014
+ function createSnappedDagreLayout(base, options = {}) {
2015
+ return (graph) => snapLinearSuccessors(base(graph), options);
2016
+ }
2017
+
2018
+ // src/components/FlowchartView/_internal/centerForkParents.ts
2019
+ function centerForkParents(graph, options = {}) {
2020
+ if (graph.nodes.length === 0) return graph;
2021
+ const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
2022
+ const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
2023
+ const byId = /* @__PURE__ */ new Map();
2024
+ const width = /* @__PURE__ */ new Map();
2025
+ for (const n of graph.nodes) {
2026
+ byId.set(n.id, n);
2027
+ width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
2028
+ }
2029
+ const childrenOf = /* @__PURE__ */ new Map();
2030
+ const predsOf = /* @__PURE__ */ new Map();
2031
+ const outDegree = /* @__PURE__ */ new Map();
2032
+ const inDegree = /* @__PURE__ */ new Map();
2033
+ const seen = /* @__PURE__ */ new Set();
2034
+ for (const e of graph.edges) {
2035
+ if (e.data?.kind === "loop") continue;
2036
+ if (!byId.has(e.source) || !byId.has(e.target)) continue;
2037
+ const key = `${e.source} ${e.target}`;
2038
+ if (seen.has(key)) continue;
2039
+ seen.add(key);
2040
+ const cl = childrenOf.get(e.source);
2041
+ if (cl) cl.push(e.target);
2042
+ else childrenOf.set(e.source, [e.target]);
2043
+ const pl = predsOf.get(e.target);
2044
+ if (pl) pl.push(e.source);
2045
+ else predsOf.set(e.target, [e.source]);
2046
+ outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
2047
+ inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
2048
+ }
2049
+ const workingX = /* @__PURE__ */ new Map();
2050
+ for (const n of graph.nodes) workingX.set(n.id, n.position.x);
2051
+ const centerX = (id) => workingX.get(id) + width.get(id) / 2;
2052
+ const nodeSep = options.nodeSep ?? 60;
2053
+ const clampX = (id, desiredX) => {
2054
+ const w = width.get(id);
2055
+ const x0 = workingX.get(id);
2056
+ const self = byId.get(id);
2057
+ let minX = -Infinity;
2058
+ let maxX = Infinity;
2059
+ for (const m of graph.nodes) {
2060
+ if (m.id === id || m.parentId !== self.parentId) continue;
2061
+ if (Math.abs(m.position.y - self.position.y) > 1) continue;
2062
+ const mLeft = workingX.get(m.id);
2063
+ const mRight = mLeft + width.get(m.id);
2064
+ if (mRight <= x0) minX = Math.max(minX, mRight + nodeSep);
2065
+ else if (mLeft >= x0 + w) maxX = Math.min(maxX, mLeft - nodeSep - w);
2066
+ }
2067
+ return minX <= maxX ? Math.max(minX, Math.min(maxX, desiredX)) : x0;
2068
+ };
2069
+ const order = [...graph.nodes].sort(
2070
+ (a, b) => b.position.y - a.position.y || a.position.x - b.position.x || a.id.localeCompare(b.id)
2071
+ );
2072
+ for (const n of order) {
2073
+ const outD = outDegree.get(n.id) ?? 0;
2074
+ const inD = inDegree.get(n.id) ?? 0;
2075
+ const isFork = outD >= 2 && inD <= 1;
2076
+ const isMerge = inD >= 2 && outD <= 1;
2077
+ if (!isFork && !isMerge) continue;
2078
+ const kin = ((isFork ? childrenOf.get(n.id) : predsOf.get(n.id)) ?? []).filter(
2079
+ (k) => byId.get(k)?.parentId === n.parentId
2080
+ // same compound only
2081
+ );
2082
+ if (kin.length < 2) continue;
2083
+ const centers = kin.map(centerX);
2084
+ const wN = width.get(n.id);
2085
+ const span = (Math.min(...centers) + Math.max(...centers)) / 2;
2086
+ workingX.set(n.id, clampX(n.id, span - wN / 2));
2087
+ const stepOf = isFork ? predsOf : childrenOf;
2088
+ let curId = n.id;
2089
+ const walked = /* @__PURE__ */ new Set([curId]);
2090
+ for (; ; ) {
2091
+ const nexts = stepOf.get(curId);
2092
+ if (!nexts || nexts.length !== 1) break;
2093
+ const m = nexts[0];
2094
+ if (walked.has(m)) break;
2095
+ if ((outDegree.get(m) ?? 0) > 1) break;
2096
+ if ((inDegree.get(m) ?? 0) > 1) break;
2097
+ if (byId.get(m)?.parentId !== byId.get(curId)?.parentId) break;
2098
+ workingX.set(m, clampX(m, centerX(curId) - width.get(m) / 2));
2099
+ walked.add(m);
2100
+ curId = m;
2101
+ }
2102
+ }
2103
+ const nodes = graph.nodes.map(
2104
+ (n) => workingX.get(n.id) === n.position.x ? n : { ...n, position: { x: workingX.get(n.id), y: n.position.y } }
2105
+ );
2106
+ return { nodes, edges: graph.edges };
2107
+ }
2108
+ function withForkCentering(base, options = {}) {
2109
+ return (graph) => centerForkParents(base(graph), options);
2110
+ }
2111
+
1949
2112
  // src/components/FlowchartView/_internal/notifyChange.ts
1950
2113
  function createNotifier(label = "notifier") {
1951
2114
  const listeners = /* @__PURE__ */ new Set();
@@ -2303,6 +2466,49 @@ function GroupContainerNode({ data }) {
2303
2466
  );
2304
2467
  }
2305
2468
 
2469
+ // src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
2470
+ var import_react16 = require("react");
2471
+ var import_react17 = require("@xyflow/react");
2472
+
2473
+ // src/components/FlowchartView/_internal/measuredFootprints.ts
2474
+ function extractMeasuredFootprints(entries) {
2475
+ const sizes = /* @__PURE__ */ new Map();
2476
+ for (const [id, node] of entries) {
2477
+ const width = node.measured?.width;
2478
+ const height = node.measured?.height;
2479
+ if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
2480
+ sizes.set(id, { width: Math.round(width), height: Math.round(height) });
2481
+ }
2482
+ }
2483
+ return sizes;
2484
+ }
2485
+ function sameFootprints(a, b) {
2486
+ if (a === b) return true;
2487
+ if (a.size !== b.size) return false;
2488
+ for (const [id, s] of a) {
2489
+ const t = b.get(id);
2490
+ if (!t || t.width !== s.width || t.height !== s.height) return false;
2491
+ }
2492
+ return true;
2493
+ }
2494
+
2495
+ // src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
2496
+ function MeasuredNodeSizes({
2497
+ onSizes,
2498
+ includeHiddenNodes = false
2499
+ }) {
2500
+ const initialized = (0, import_react17.useNodesInitialized)({ includeHiddenNodes });
2501
+ const sizes = (0, import_react17.useStore)(
2502
+ (s) => extractMeasuredFootprints(s.nodeLookup),
2503
+ sameFootprints
2504
+ );
2505
+ (0, import_react16.useEffect)(() => {
2506
+ if (!initialized || sizes.size === 0) return;
2507
+ onSizes(sizes);
2508
+ }, [initialized, sizes, onSizes]);
2509
+ return null;
2510
+ }
2511
+
2306
2512
  // src/components/FlowchartView/TracedFlow.tsx
2307
2513
  var import_jsx_runtime11 = require("react/jsx-runtime");
2308
2514
  var DEFAULT_COLORS = {
@@ -2412,7 +2618,7 @@ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
2412
2618
  type: kind === "loop" ? "loopBack" : "smartStep",
2413
2619
  animated: isLeadingEdge,
2414
2620
  style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },
2415
- markerEnd: { type: import_react17.MarkerType.ArrowClosed, color, width: 16, height: 16 }
2621
+ markerEnd: { type: import_react19.MarkerType.ArrowClosed, color, width: 16, height: 16 }
2416
2622
  };
2417
2623
  if (kind === "loop") {
2418
2624
  styled.style = { ...styled.style, strokeDasharray: "4 3" };
@@ -2442,21 +2648,28 @@ function TracedFlow({
2442
2648
  style
2443
2649
  }) {
2444
2650
  const layout = layoutProp ?? dagreTraceLayout;
2445
- const colors = (0, import_react16.useMemo)(
2651
+ (0, import_react18.useEffect)(() => {
2652
+ if (layoutProp === dagreTraceLayout) {
2653
+ devWarn(
2654
+ () => "[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."
2655
+ );
2656
+ }
2657
+ }, [layoutProp]);
2658
+ const colors = (0, import_react18.useMemo)(
2446
2659
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
2447
2660
  [colorOverrides]
2448
2661
  );
2449
- const mergedNodeTypes = (0, import_react16.useMemo)(
2662
+ const mergedNodeTypes = (0, import_react18.useMemo)(
2450
2663
  () => userNodeTypes ? { ...DEFAULT_NODE_TYPES2, ...userNodeTypes } : DEFAULT_NODE_TYPES2,
2451
2664
  [userNodeTypes]
2452
2665
  );
2453
- const mergedEdgeTypes = (0, import_react16.useMemo)(
2666
+ const mergedEdgeTypes = (0, import_react18.useMemo)(
2454
2667
  () => userEdgeTypes ? { ...DEFAULT_EDGE_TYPES2, ...userEdgeTypes } : DEFAULT_EDGE_TYPES2,
2455
2668
  [userEdgeTypes]
2456
2669
  );
2457
2670
  const drill = useSubflowDrill(graph, onSubflowChange);
2458
- const groupedSet = (0, import_react16.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
2459
- const filteredGraph = (0, import_react16.useMemo)(() => {
2671
+ const groupedSet = (0, import_react18.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
2672
+ const filteredGraph = (0, import_react18.useMemo)(() => {
2460
2673
  const base = filterGraphForDrill(graph, drill.currentSubflowId);
2461
2674
  if (groupedSet.size === 0) return base;
2462
2675
  const baseIds = new Set(base.nodes.map((n) => n.id));
@@ -2471,12 +2684,23 @@ function TracedFlow({
2471
2684
  );
2472
2685
  return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };
2473
2686
  }, [graph, drill.currentSubflowId, groupedSet]);
2474
- const breadcrumb = (0, import_react16.useMemo)(
2687
+ const breadcrumb = (0, import_react18.useMemo)(
2475
2688
  () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
2476
2689
  [graph, drill.currentSubflowId]
2477
2690
  );
2478
- const positioned = (0, import_react16.useMemo)(() => {
2479
- const realBase = layout === "passthrough" ? (g) => g : layout;
2691
+ const [measuredSizes, setMeasuredSizes] = (0, import_react18.useState)(null);
2692
+ const positioned = (0, import_react18.useMemo)(() => {
2693
+ const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
2694
+ const sizeOpts = nodeSize ? { nodeSize } : {};
2695
+ const dagreBase = withForkCentering(
2696
+ createSnappedDagreLayout(
2697
+ createDagreTraceLayout({ ...sizeOpts, rankSep: 52, nodeSep: 36 }),
2698
+ sizeOpts
2699
+ ),
2700
+ { ...sizeOpts, nodeSep: 36 }
2701
+ // same nodeSep → clamp preserves dagre's reserved gap
2702
+ );
2703
+ const realBase = layout === "passthrough" ? (g) => g : layoutProp === void 0 ? dagreBase : layout;
2480
2704
  if (groupedSet.size > 0) {
2481
2705
  const grouped = applyGroupLayout(filteredGraph, {
2482
2706
  groupedSubflowIds: [...groupedSet],
@@ -2487,9 +2711,9 @@ function TracedFlow({
2487
2711
  if (mainChartBox) {
2488
2712
  return wrapInMainChartBox(filteredGraph, { baseLayout: realBase, ...mainChartBox });
2489
2713
  }
2490
- return layout === "passthrough" ? filteredGraph : layout(filteredGraph);
2491
- }, [filteredGraph, layout, groupedSet, mainChartBox]);
2492
- const slice = (0, import_react16.useMemo)(() => {
2714
+ return realBase(filteredGraph);
2715
+ }, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
2716
+ const slice = (0, import_react18.useMemo)(() => {
2493
2717
  const empty = {
2494
2718
  doneStageIds: /* @__PURE__ */ new Set(),
2495
2719
  activeStageId: null,
@@ -2501,7 +2725,7 @@ function TracedFlow({
2501
2725
  const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
2502
2726
  return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);
2503
2727
  }, [overlay, scrubIndex, graph, drill.currentSubflowId]);
2504
- const reactFlowNodes = (0, import_react16.useMemo)(
2728
+ const reactFlowNodes = (0, import_react18.useMemo)(
2505
2729
  () => positioned.nodes.map(
2506
2730
  (n) => toStageNodeWithOverlay(
2507
2731
  n,
@@ -2514,13 +2738,13 @@ function TracedFlow({
2514
2738
  ),
2515
2739
  [positioned.nodes, slice, coActiveStageIds]
2516
2740
  );
2517
- const reactFlowEdges = (0, import_react16.useMemo)(
2741
+ const reactFlowEdges = (0, import_react18.useMemo)(
2518
2742
  () => positioned.edges.map(
2519
2743
  (e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
2520
2744
  ),
2521
2745
  [positioned.edges, slice, colors]
2522
2746
  );
2523
- const handleNodeClick = (0, import_react16.useCallback)(
2747
+ const handleNodeClick = (0, import_react18.useCallback)(
2524
2748
  (_, node) => {
2525
2749
  const data = node.data ?? {};
2526
2750
  if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {
@@ -2530,9 +2754,13 @@ function TracedFlow({
2530
2754
  },
2531
2755
  [drill, onNodeClick, groupedSet]
2532
2756
  );
2533
- const wrapperRef = (0, import_react16.useRef)(null);
2534
- const [rfInstance, setRfInstance] = (0, import_react16.useState)(null);
2535
- useChartAutoRefit(wrapperRef, rfInstance, { refitKey: drill.currentSubflowId });
2757
+ const wrapperRef = (0, import_react18.useRef)(null);
2758
+ const [rfInstance, setRfInstance] = (0, import_react18.useState)(null);
2759
+ useChartAutoRefit(wrapperRef, rfInstance, {
2760
+ // Re-fit on drill AND after the measured-size re-layout settles.
2761
+ refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
2762
+ padding: 0.18
2763
+ });
2536
2764
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2537
2765
  "div",
2538
2766
  {
@@ -2555,7 +2783,7 @@ function TracedFlow({
2555
2783
  }
2556
2784
  ),
2557
2785
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2558
- import_react17.ReactFlow,
2786
+ import_react19.ReactFlow,
2559
2787
  {
2560
2788
  nodes: reactFlowNodes,
2561
2789
  edges: reactFlowEdges,
@@ -2564,9 +2792,12 @@ function TracedFlow({
2564
2792
  onNodeClick: handleNodeClick,
2565
2793
  onInit: setRfInstance,
2566
2794
  fitView: true,
2795
+ fitViewOptions: { padding: 0.18 },
2796
+ minZoom: 0.1,
2567
2797
  proOptions: { hideAttribution: true },
2568
2798
  children: [
2569
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react17.Background, { variant: import_react17.BackgroundVariant.Dots, gap: 20, size: 1 }),
2799
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
2800
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react19.Background, { variant: import_react19.BackgroundVariant.Dots, gap: 20, size: 1 }),
2570
2801
  children
2571
2802
  ]
2572
2803
  }
@@ -2590,7 +2821,7 @@ function TimeTravelDebugger({
2590
2821
  className,
2591
2822
  style
2592
2823
  }) {
2593
- const [selectedIndex, setSelectedIndex] = (0, import_react18.useState)(0);
2824
+ const [selectedIndex, setSelectedIndex] = (0, import_react20.useState)(0);
2594
2825
  const fs = fontSize[size];
2595
2826
  const pad = padding[size];
2596
2827
  if (snapshots.length === 0) {
@@ -2884,9 +3115,9 @@ function ScrubButton({
2884
3115
  }
2885
3116
 
2886
3117
  // src/components/FlowchartView/SubflowBreadcrumb.tsx
2887
- var import_react19 = require("react");
3118
+ var import_react21 = require("react");
2888
3119
  var import_jsx_runtime13 = require("react/jsx-runtime");
2889
- var SubflowBreadcrumb = (0, import_react19.memo)(function SubflowBreadcrumb2({
3120
+ var SubflowBreadcrumb = (0, import_react21.memo)(function SubflowBreadcrumb2({
2890
3121
  breadcrumbs,
2891
3122
  onNavigate
2892
3123
  }) {
@@ -2967,12 +3198,12 @@ var SubflowBreadcrumb = (0, import_react19.memo)(function SubflowBreadcrumb2({
2967
3198
  });
2968
3199
 
2969
3200
  // src/components/FlowchartView/useSubflowNavigation.ts
2970
- var import_react20 = require("react");
3201
+ var import_react22 = require("react");
2971
3202
  var EMPTY_GRAPH2 = { nodes: [], edges: [] };
2972
3203
  function useSubflowNavigation(rootGraph) {
2973
- const [stack, setStack] = (0, import_react20.useState)([]);
3204
+ const [stack, setStack] = (0, import_react22.useState)([]);
2974
3205
  const safeRootGraph = rootGraph ?? EMPTY_GRAPH2;
2975
- const subflowMounts = (0, import_react20.useMemo)(() => {
3206
+ const subflowMounts = (0, import_react22.useMemo)(() => {
2976
3207
  const map = /* @__PURE__ */ new Map();
2977
3208
  for (const node of safeRootGraph.nodes) {
2978
3209
  if (!node.data?.isSubflow) continue;
@@ -2990,12 +3221,12 @@ function useSubflowNavigation(rootGraph) {
2990
3221
  }
2991
3222
  return map;
2992
3223
  }, [safeRootGraph]);
2993
- const breadcrumbs = (0, import_react20.useMemo)(() => {
3224
+ const breadcrumbs = (0, import_react22.useMemo)(() => {
2994
3225
  const rootLabel = "Flowchart";
2995
3226
  const root = { label: rootLabel };
2996
3227
  return [root, ...stack];
2997
3228
  }, [stack]);
2998
- const handleNodeClick = (0, import_react20.useCallback)(
3229
+ const handleNodeClick = (0, import_react22.useCallback)(
2999
3230
  (nodeId) => {
3000
3231
  const mount = subflowMounts.get(nodeId);
3001
3232
  if (!mount) return false;
@@ -3011,7 +3242,7 @@ function useSubflowNavigation(rootGraph) {
3011
3242
  },
3012
3243
  [subflowMounts]
3013
3244
  );
3014
- const navigateTo = (0, import_react20.useCallback)((level) => {
3245
+ const navigateTo = (0, import_react22.useCallback)((level) => {
3015
3246
  if (level === 0) {
3016
3247
  setStack([]);
3017
3248
  } else {
@@ -3033,7 +3264,7 @@ function useSubflowNavigation(rootGraph) {
3033
3264
  }
3034
3265
 
3035
3266
  // src/components/FlowchartView/SubflowTree.tsx
3036
- var import_react21 = require("react");
3267
+ var import_react23 = require("react");
3037
3268
  var import_jsx_runtime14 = require("react/jsx-runtime");
3038
3269
  function graphToSubflowEntries(graph) {
3039
3270
  if (!graph?.nodes?.length) return [];
@@ -3050,18 +3281,18 @@ function graphToSubflowEntries(graph) {
3050
3281
  }
3051
3282
  return entries;
3052
3283
  }
3053
- var TreeNode = (0, import_react21.memo)(function TreeNode2({
3284
+ var TreeNode = (0, import_react23.memo)(function TreeNode2({
3054
3285
  entry,
3055
3286
  depth,
3056
3287
  activeStage,
3057
3288
  doneStages,
3058
3289
  onNodeSelect
3059
3290
  }) {
3060
- const [expanded, setExpanded] = (0, import_react21.useState)(true);
3291
+ const [expanded, setExpanded] = (0, import_react23.useState)(true);
3061
3292
  const hasChildren = entry.children && entry.children.length > 0;
3062
3293
  const isActive = activeStage === entry.name;
3063
3294
  const isDone = doneStages?.has(entry.name);
3064
- const handleClick = (0, import_react21.useCallback)(() => {
3295
+ const handleClick = (0, import_react23.useCallback)(() => {
3065
3296
  if (hasChildren) {
3066
3297
  setExpanded((prev) => !prev);
3067
3298
  }
@@ -3174,7 +3405,7 @@ var TreeNode = (0, import_react21.memo)(function TreeNode2({
3174
3405
  )) })
3175
3406
  ] });
3176
3407
  });
3177
- var SectionLabel = (0, import_react21.memo)(function SectionLabel2({ children }) {
3408
+ var SectionLabel = (0, import_react23.memo)(function SectionLabel2({ children }) {
3178
3409
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3179
3410
  "div",
3180
3411
  {
@@ -3190,7 +3421,7 @@ var SectionLabel = (0, import_react21.memo)(function SectionLabel2({ children })
3190
3421
  }
3191
3422
  );
3192
3423
  });
3193
- var SubflowTree = (0, import_react21.memo)(function SubflowTree2({
3424
+ var SubflowTree = (0, import_react23.memo)(function SubflowTree2({
3194
3425
  graph,
3195
3426
  activeStage,
3196
3427
  doneStages,
@@ -3199,7 +3430,7 @@ var SubflowTree = (0, import_react21.memo)(function SubflowTree2({
3199
3430
  className,
3200
3431
  style
3201
3432
  }) {
3202
- const subflowStages = (0, import_react21.useMemo)(() => graphToSubflowEntries(graph), [graph]);
3433
+ const subflowStages = (0, import_react23.useMemo)(() => graphToSubflowEntries(graph), [graph]);
3203
3434
  if (subflowStages.length === 0) return null;
3204
3435
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3205
3436
  "div",
@@ -3524,7 +3755,7 @@ function createTraceStructureRecorder(options = {}) {
3524
3755
  }
3525
3756
 
3526
3757
  // src/components/SlotPillNode/SlotPillNode.tsx
3527
- var import_react22 = require("@xyflow/react");
3758
+ var import_react24 = require("@xyflow/react");
3528
3759
  var import_jsx_runtime15 = require("react/jsx-runtime");
3529
3760
  var C2 = rawDefaults.colors;
3530
3761
  function SlotPillNode({ data }) {
@@ -3573,63 +3804,13 @@ function SlotPillNode({ data }) {
3573
3804
  ),
3574
3805
  d.icon ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": true, style: { flexShrink: 0 }, children: d.icon }) : null,
3575
3806
  /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { style: { overflow: "hidden", textOverflow: "ellipsis" }, children: d.label }),
3576
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react22.Handle, { type: "target", position: import_react22.Position.Top, style: { opacity: 0 } }),
3577
- /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react22.Handle, { type: "source", position: import_react22.Position.Bottom, style: { opacity: 0 } })
3807
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react24.Handle, { type: "target", position: import_react24.Position.Top, style: { opacity: 0 } }),
3808
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react24.Handle, { type: "source", position: import_react24.Position.Bottom, style: { opacity: 0 } })
3578
3809
  ]
3579
3810
  }
3580
3811
  );
3581
3812
  }
3582
3813
 
3583
- // src/components/FlowchartView/_internal/snapLinearSuccessors.ts
3584
- function snapLinearSuccessors(graph, options = {}) {
3585
- if (graph.nodes.length === 0) return graph;
3586
- const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
3587
- const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
3588
- const byId = /* @__PURE__ */ new Map();
3589
- const width = /* @__PURE__ */ new Map();
3590
- for (const n of graph.nodes) {
3591
- byId.set(n.id, n);
3592
- width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
3593
- }
3594
- const preds = /* @__PURE__ */ new Map();
3595
- const outDegree = /* @__PURE__ */ new Map();
3596
- const seenEdge = /* @__PURE__ */ new Set();
3597
- for (const e of graph.edges) {
3598
- if (e.data?.kind === "loop") continue;
3599
- if (!byId.has(e.source) || !byId.has(e.target)) continue;
3600
- const key = `${e.source}\0${e.target}`;
3601
- if (seenEdge.has(key)) continue;
3602
- seenEdge.add(key);
3603
- const list = preds.get(e.target);
3604
- if (list) list.push(e.source);
3605
- else preds.set(e.target, [e.source]);
3606
- outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
3607
- }
3608
- const workingX = /* @__PURE__ */ new Map();
3609
- for (const n of graph.nodes) workingX.set(n.id, n.position.x);
3610
- const centerX = (id) => workingX.get(id) + width.get(id) / 2;
3611
- const order = [...graph.nodes].sort(
3612
- (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)
3613
- );
3614
- for (const n of order) {
3615
- const p = preds.get(n.id);
3616
- if (!p || p.length !== 1) continue;
3617
- const pid = p[0];
3618
- if ((outDegree.get(pid) ?? 0) !== 1) continue;
3619
- const P = byId.get(pid);
3620
- if ((n.parentId ?? void 0) !== (P.parentId ?? void 0)) continue;
3621
- workingX.set(n.id, centerX(pid) - width.get(n.id) / 2);
3622
- }
3623
- const nodes = graph.nodes.map((n) => {
3624
- const nx = workingX.get(n.id);
3625
- return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };
3626
- });
3627
- return { nodes, edges: graph.edges };
3628
- }
3629
- function createSnappedDagreLayout(base, options = {}) {
3630
- return (graph) => snapLinearSuccessors(base(graph), options);
3631
- }
3632
-
3633
3814
  // src/components/FlowchartView/_internal/traceGroupLayout.ts
3634
3815
  function buildAdjacency(graph, fallbackW, fallbackH, nodeSize) {
3635
3816
  const preds = /* @__PURE__ */ new Map();
@@ -4299,12 +4480,12 @@ function createTraceBundle(options = {}) {
4299
4480
  }
4300
4481
 
4301
4482
  // src/components/FlowchartView/_internal/useTranslator.ts
4302
- var import_react23 = require("react");
4483
+ var import_react25 = require("react");
4303
4484
  function useTranslator(handle, getSnapshot) {
4304
- const subscribe = (0, import_react23.useMemo)(() => handle.subscribe.bind(handle), [handle]);
4305
- const getVersion = (0, import_react23.useMemo)(() => handle.version.bind(handle), [handle]);
4306
- const version = (0, import_react23.useSyncExternalStore)(subscribe, getVersion, getVersion);
4307
- return (0, import_react23.useMemo)(() => getSnapshot(), [version, getSnapshot]);
4485
+ const subscribe = (0, import_react25.useMemo)(() => handle.subscribe.bind(handle), [handle]);
4486
+ const getVersion = (0, import_react25.useMemo)(() => handle.version.bind(handle), [handle]);
4487
+ const version = (0, import_react25.useSyncExternalStore)(subscribe, getVersion, getVersion);
4488
+ return (0, import_react25.useMemo)(() => getSnapshot(), [version, getSnapshot]);
4308
4489
  }
4309
4490
 
4310
4491
  // src/components/FlowchartView/walkHelpers.ts
@@ -4387,7 +4568,7 @@ function bfsWalk(index, startId, neighborsOf, options) {
4387
4568
  }
4388
4569
 
4389
4570
  // src/components/FlowchartView/NodeInspector.tsx
4390
- var import_react24 = require("react");
4571
+ var import_react26 = require("react");
4391
4572
  var import_jsx_runtime16 = require("react/jsx-runtime");
4392
4573
  function NodeInspector({
4393
4574
  index,
@@ -4398,11 +4579,11 @@ function NodeInspector({
4398
4579
  style
4399
4580
  }) {
4400
4581
  const view = selectedId ? index.byStageId.get(selectedId) ?? null : null;
4401
- const prevChain = (0, import_react24.useMemo)(
4582
+ const prevChain = (0, import_react26.useMemo)(
4402
4583
  () => view ? backtraceStructural(index, view.stageId, { onlyVisited }) : [],
4403
4584
  [index, view, onlyVisited]
4404
4585
  );
4405
- const nextChain = (0, import_react24.useMemo)(
4586
+ const nextChain = (0, import_react26.useMemo)(
4406
4587
  () => view ? forwardtraceStructural(index, view.stageId, { onlyVisited }) : [],
4407
4588
  [index, view, onlyVisited]
4408
4589
  );
@@ -4528,7 +4709,7 @@ function Crumbs({ nodes, onClick }) {
4528
4709
  }
4529
4710
 
4530
4711
  // src/components/FlowchartView/CommitInspector.tsx
4531
- var import_react25 = require("react");
4712
+ var import_react27 = require("react");
4532
4713
  var import_jsx_runtime17 = require("react/jsx-runtime");
4533
4714
  function CommitInspector({
4534
4715
  index,
@@ -4538,7 +4719,7 @@ function CommitInspector({
4538
4719
  style
4539
4720
  }) {
4540
4721
  const view = selectedRuntimeStageId ? index.byRuntimeStageId.get(selectedRuntimeStageId) ?? null : null;
4541
- const lineage = (0, import_react25.useMemo)(
4722
+ const lineage = (0, import_react27.useMemo)(
4542
4723
  () => view ? backtraceDataFlow(index, view.runtimeStageId) : [],
4543
4724
  [index, view]
4544
4725
  );
@@ -5124,10 +5305,10 @@ var boxBaseStyle = {
5124
5305
  };
5125
5306
 
5126
5307
  // src/components/FlowchartView/TraceExplorerShell.tsx
5127
- var import_react27 = require("react");
5308
+ var import_react29 = require("react");
5128
5309
 
5129
5310
  // src/components/FlowchartView/RunSlider.tsx
5130
- var import_react26 = require("react");
5311
+ var import_react28 = require("react");
5131
5312
  var import_jsx_runtime19 = require("react/jsx-runtime");
5132
5313
  function RunSlider({
5133
5314
  index,
@@ -5138,12 +5319,12 @@ function RunSlider({
5138
5319
  style
5139
5320
  }) {
5140
5321
  const total = index.commits.length;
5141
- const cursorCommitIdx = (0, import_react26.useMemo)(() => {
5322
+ const cursorCommitIdx = (0, import_react28.useMemo)(() => {
5142
5323
  if (!cursorRuntimeStageId) return 0;
5143
5324
  const view = index.byRuntimeStageId.get(cursorRuntimeStageId);
5144
5325
  return view ? view.commitIdx : 0;
5145
5326
  }, [index, cursorRuntimeStageId]);
5146
- const handleSliderChange = (0, import_react26.useCallback)(
5327
+ const handleSliderChange = (0, import_react28.useCallback)(
5147
5328
  (e) => {
5148
5329
  const value = Number(e.target.value);
5149
5330
  const view = index.commits[value];
@@ -5151,7 +5332,7 @@ function RunSlider({
5151
5332
  },
5152
5333
  [index, onCursorChange]
5153
5334
  );
5154
- const label = (0, import_react26.useMemo)(() => {
5335
+ const label = (0, import_react28.useMemo)(() => {
5155
5336
  const commit = index.commits[cursorCommitIdx] ?? null;
5156
5337
  const rsid = cursorRuntimeStageId ?? commit?.runtimeStageId ?? null;
5157
5338
  if (renderLabel)
@@ -5235,39 +5416,39 @@ function TraceExplorerShell({
5235
5416
  className,
5236
5417
  style
5237
5418
  }) {
5238
- const [internalSel, setInternalSel] = (0, import_react27.useState)(null);
5419
+ const [internalSel, setInternalSel] = (0, import_react29.useState)(null);
5239
5420
  const isControlled = controlledSel !== void 0;
5240
5421
  const selectedRuntimeStageId = isControlled ? controlledSel : internalSel;
5241
- const handleSelect = (0, import_react27.useCallback)(
5422
+ const handleSelect = (0, import_react29.useCallback)(
5242
5423
  (rsid) => {
5243
5424
  if (!isControlled) setInternalSel(rsid);
5244
5425
  onSelectionChange?.(rsid);
5245
5426
  },
5246
5427
  [isControlled, onSelectionChange]
5247
5428
  );
5248
- const handleSelectCommit = (0, import_react27.useCallback)(
5429
+ const handleSelectCommit = (0, import_react29.useCallback)(
5249
5430
  (rsid) => handleSelect(rsid),
5250
5431
  [handleSelect]
5251
5432
  );
5252
- const selectedStageId = (0, import_react27.useMemo)(() => {
5433
+ const selectedStageId = (0, import_react29.useMemo)(() => {
5253
5434
  if (!selectedRuntimeStageId) return null;
5254
5435
  const hashIdx = selectedRuntimeStageId.lastIndexOf("#");
5255
5436
  if (hashIdx <= 0) return null;
5256
5437
  return asStageId(selectedRuntimeStageId.slice(0, hashIdx));
5257
5438
  }, [selectedRuntimeStageId]);
5258
- const ChainPane = (0, import_react27.useMemo)(
5439
+ const ChainPane = (0, import_react29.useMemo)(
5259
5440
  () => slots?.chain ?? DefaultChainPane,
5260
5441
  [slots?.chain]
5261
5442
  );
5262
- const CommitPane = (0, import_react27.useMemo)(
5443
+ const CommitPane = (0, import_react29.useMemo)(
5263
5444
  () => slots?.commitInspector ?? DefaultCommitPane,
5264
5445
  [slots?.commitInspector]
5265
5446
  );
5266
- const NodePane = (0, import_react27.useMemo)(
5447
+ const NodePane = (0, import_react29.useMemo)(
5267
5448
  () => slots?.nodeInspector ?? DefaultNodePane,
5268
5449
  [slots?.nodeInspector]
5269
5450
  );
5270
- const SliderPane = (0, import_react27.useMemo)(() => {
5451
+ const SliderPane = (0, import_react29.useMemo)(() => {
5271
5452
  if (slots && "slider" in slots) {
5272
5453
  return slots.slider ?? null;
5273
5454
  }
@@ -5282,7 +5463,7 @@ function TraceExplorerShell({
5282
5463
  () => bundle.commitFlow.getIndex()
5283
5464
  );
5284
5465
  const nodeIndex = useTranslator(bundle.nodeView, () => bundle.nodeView.getIndex());
5285
- const handleStageNavigate = (0, import_react27.useCallback)(
5466
+ const handleStageNavigate = (0, import_react29.useCallback)(
5286
5467
  (stageId) => {
5287
5468
  const candidates = commitIndex.commits.filter((c) => c.stageId === stageId);
5288
5469
  const first = candidates[0];
@@ -5290,12 +5471,12 @@ function TraceExplorerShell({
5290
5471
  },
5291
5472
  [commitIndex, handleSelect]
5292
5473
  );
5293
- const revealedThroughCommitIdx = (0, import_react27.useMemo)(() => {
5474
+ const revealedThroughCommitIdx = (0, import_react29.useMemo)(() => {
5294
5475
  if (!selectedRuntimeStageId) return null;
5295
5476
  const view = commitIndex.byRuntimeStageId.get(selectedRuntimeStageId);
5296
5477
  return view ? view.commitIdx : -1;
5297
5478
  }, [selectedRuntimeStageId, commitIndex]);
5298
- const layoutStyle = (0, import_react27.useMemo)(
5479
+ const layoutStyle = (0, import_react29.useMemo)(
5299
5480
  () => SliderPane ? SHELL_STYLE_WITH_SLIDER : SHELL_STYLE_NO_SLIDER,
5300
5481
  [SliderPane]
5301
5482
  );