footprint-explainable-ui 0.25.0 → 0.25.1

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,148 @@ 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");
1957
+
1958
+ // src/components/FlowchartView/_internal/snapLinearSuccessors.ts
1959
+ function snapLinearSuccessors(graph, options = {}) {
1960
+ if (graph.nodes.length === 0) return graph;
1961
+ const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
1962
+ const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
1963
+ const byId = /* @__PURE__ */ new Map();
1964
+ const width = /* @__PURE__ */ new Map();
1965
+ for (const n of graph.nodes) {
1966
+ byId.set(n.id, n);
1967
+ width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
1968
+ }
1969
+ const preds = /* @__PURE__ */ new Map();
1970
+ const outDegree = /* @__PURE__ */ new Map();
1971
+ const seenEdge = /* @__PURE__ */ new Set();
1972
+ for (const e of graph.edges) {
1973
+ if (e.data?.kind === "loop") continue;
1974
+ if (!byId.has(e.source) || !byId.has(e.target)) continue;
1975
+ const key = `${e.source}\0${e.target}`;
1976
+ if (seenEdge.has(key)) continue;
1977
+ seenEdge.add(key);
1978
+ const list = preds.get(e.target);
1979
+ if (list) list.push(e.source);
1980
+ else preds.set(e.target, [e.source]);
1981
+ outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
1982
+ }
1983
+ const workingX = /* @__PURE__ */ new Map();
1984
+ for (const n of graph.nodes) workingX.set(n.id, n.position.x);
1985
+ const centerX = (id) => workingX.get(id) + width.get(id) / 2;
1986
+ const order = [...graph.nodes].sort(
1987
+ (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)
1988
+ );
1989
+ for (const n of order) {
1990
+ const p = preds.get(n.id);
1991
+ if (!p || p.length !== 1) continue;
1992
+ const pid = p[0];
1993
+ if ((outDegree.get(pid) ?? 0) !== 1) continue;
1994
+ const P = byId.get(pid);
1995
+ if ((n.parentId ?? void 0) !== (P.parentId ?? void 0)) continue;
1996
+ workingX.set(n.id, centerX(pid) - width.get(n.id) / 2);
1997
+ }
1998
+ const nodes = graph.nodes.map((n) => {
1999
+ const nx = workingX.get(n.id);
2000
+ return nx === n.position.x ? n : { ...n, position: { x: nx, y: n.position.y } };
2001
+ });
2002
+ return { nodes, edges: graph.edges };
2003
+ }
2004
+ function createSnappedDagreLayout(base, options = {}) {
2005
+ return (graph) => snapLinearSuccessors(base(graph), options);
2006
+ }
2007
+
2008
+ // src/components/FlowchartView/_internal/centerForkParents.ts
2009
+ function centerForkParents(graph, options = {}) {
2010
+ if (graph.nodes.length === 0) return graph;
2011
+ const fallbackW = options.nodeWidth ?? DEFAULT_NODE_W2;
2012
+ const fallbackH = options.nodeHeight ?? DEFAULT_NODE_H2;
2013
+ const byId = /* @__PURE__ */ new Map();
2014
+ const width = /* @__PURE__ */ new Map();
2015
+ for (const n of graph.nodes) {
2016
+ byId.set(n.id, n);
2017
+ width.set(n.id, sizeOf(n, fallbackW, fallbackH, options.nodeSize).width);
2018
+ }
2019
+ const childrenOf = /* @__PURE__ */ new Map();
2020
+ const predsOf = /* @__PURE__ */ new Map();
2021
+ const outDegree = /* @__PURE__ */ new Map();
2022
+ const inDegree = /* @__PURE__ */ new Map();
2023
+ const seen = /* @__PURE__ */ new Set();
2024
+ for (const e of graph.edges) {
2025
+ if (e.data?.kind === "loop") continue;
2026
+ if (!byId.has(e.source) || !byId.has(e.target)) continue;
2027
+ const key = `${e.source} ${e.target}`;
2028
+ if (seen.has(key)) continue;
2029
+ seen.add(key);
2030
+ const cl = childrenOf.get(e.source);
2031
+ if (cl) cl.push(e.target);
2032
+ else childrenOf.set(e.source, [e.target]);
2033
+ const pl = predsOf.get(e.target);
2034
+ if (pl) pl.push(e.source);
2035
+ else predsOf.set(e.target, [e.source]);
2036
+ outDegree.set(e.source, (outDegree.get(e.source) ?? 0) + 1);
2037
+ inDegree.set(e.target, (inDegree.get(e.target) ?? 0) + 1);
2038
+ }
2039
+ const workingX = /* @__PURE__ */ new Map();
2040
+ for (const n of graph.nodes) workingX.set(n.id, n.position.x);
2041
+ const centerX = (id) => workingX.get(id) + width.get(id) / 2;
2042
+ const nodeSep = options.nodeSep ?? 60;
2043
+ const clampX = (id, desiredX) => {
2044
+ const w = width.get(id);
2045
+ const x0 = workingX.get(id);
2046
+ const self = byId.get(id);
2047
+ let minX = -Infinity;
2048
+ let maxX = Infinity;
2049
+ for (const m of graph.nodes) {
2050
+ if (m.id === id || m.parentId !== self.parentId) continue;
2051
+ if (Math.abs(m.position.y - self.position.y) > 1) continue;
2052
+ const mLeft = workingX.get(m.id);
2053
+ const mRight = mLeft + width.get(m.id);
2054
+ if (mRight <= x0) minX = Math.max(minX, mRight + nodeSep);
2055
+ else if (mLeft >= x0 + w) maxX = Math.min(maxX, mLeft - nodeSep - w);
2056
+ }
2057
+ return minX <= maxX ? Math.max(minX, Math.min(maxX, desiredX)) : x0;
2058
+ };
2059
+ const order = [...graph.nodes].sort(
2060
+ (a, b) => b.position.y - a.position.y || a.position.x - b.position.x || a.id.localeCompare(b.id)
2061
+ );
2062
+ for (const n of order) {
2063
+ if ((outDegree.get(n.id) ?? 0) < 2) continue;
2064
+ if ((inDegree.get(n.id) ?? 0) > 1) continue;
2065
+ const kids = (childrenOf.get(n.id) ?? []).filter(
2066
+ (k) => byId.get(k)?.parentId === n.parentId
2067
+ // same compound only
2068
+ );
2069
+ if (kids.length < 2) continue;
2070
+ const centers = kids.map(centerX);
2071
+ const wN = width.get(n.id);
2072
+ const span = (Math.min(...centers) + Math.max(...centers)) / 2;
2073
+ workingX.set(n.id, clampX(n.id, span - wN / 2));
2074
+ let curId = n.id;
2075
+ const walked = /* @__PURE__ */ new Set([curId]);
2076
+ for (; ; ) {
2077
+ const ps = predsOf.get(curId);
2078
+ if (!ps || ps.length !== 1) break;
2079
+ const p = ps[0];
2080
+ if (walked.has(p)) break;
2081
+ if ((outDegree.get(p) ?? 0) !== 1) break;
2082
+ if ((inDegree.get(p) ?? 0) > 1) break;
2083
+ if (byId.get(p)?.parentId !== byId.get(curId)?.parentId) break;
2084
+ workingX.set(p, clampX(p, centerX(curId) - width.get(p) / 2));
2085
+ walked.add(p);
2086
+ curId = p;
2087
+ }
2088
+ }
2089
+ const nodes = graph.nodes.map(
2090
+ (n) => workingX.get(n.id) === n.position.x ? n : { ...n, position: { x: workingX.get(n.id), y: n.position.y } }
2091
+ );
2092
+ return { nodes, edges: graph.edges };
2093
+ }
2094
+ function withForkCentering(base, options = {}) {
2095
+ return (graph) => centerForkParents(base(graph), options);
2096
+ }
1938
2097
 
1939
2098
  // src/components/FlowchartView/_internal/devWarn.ts
1940
2099
  function isDevModeEnv() {
@@ -2303,6 +2462,49 @@ function GroupContainerNode({ data }) {
2303
2462
  );
2304
2463
  }
2305
2464
 
2465
+ // src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
2466
+ var import_react16 = require("react");
2467
+ var import_react17 = require("@xyflow/react");
2468
+
2469
+ // src/components/FlowchartView/_internal/measuredFootprints.ts
2470
+ function extractMeasuredFootprints(entries) {
2471
+ const sizes = /* @__PURE__ */ new Map();
2472
+ for (const [id, node] of entries) {
2473
+ const width = node.measured?.width;
2474
+ const height = node.measured?.height;
2475
+ if (typeof width === "number" && typeof height === "number" && width > 0 && height > 0) {
2476
+ sizes.set(id, { width: Math.round(width), height: Math.round(height) });
2477
+ }
2478
+ }
2479
+ return sizes;
2480
+ }
2481
+ function sameFootprints(a, b) {
2482
+ if (a === b) return true;
2483
+ if (a.size !== b.size) return false;
2484
+ for (const [id, s] of a) {
2485
+ const t = b.get(id);
2486
+ if (!t || t.width !== s.width || t.height !== s.height) return false;
2487
+ }
2488
+ return true;
2489
+ }
2490
+
2491
+ // src/components/FlowchartView/_internal/MeasuredNodeSizes.tsx
2492
+ function MeasuredNodeSizes({
2493
+ onSizes,
2494
+ includeHiddenNodes = false
2495
+ }) {
2496
+ const initialized = (0, import_react17.useNodesInitialized)({ includeHiddenNodes });
2497
+ const sizes = (0, import_react17.useStore)(
2498
+ (s) => extractMeasuredFootprints(s.nodeLookup),
2499
+ sameFootprints
2500
+ );
2501
+ (0, import_react16.useEffect)(() => {
2502
+ if (!initialized || sizes.size === 0) return;
2503
+ onSizes(sizes);
2504
+ }, [initialized, sizes, onSizes]);
2505
+ return null;
2506
+ }
2507
+
2306
2508
  // src/components/FlowchartView/TracedFlow.tsx
2307
2509
  var import_jsx_runtime11 = require("react/jsx-runtime");
2308
2510
  var DEFAULT_COLORS = {
@@ -2412,7 +2614,7 @@ function styleEdgeWithOverlay(edge, doneStageIds, activeStageId, colors) {
2412
2614
  type: kind === "loop" ? "loopBack" : "smartStep",
2413
2615
  animated: isLeadingEdge,
2414
2616
  style: { stroke: color, strokeWidth: traversed ? 2 : 1.5 },
2415
- markerEnd: { type: import_react17.MarkerType.ArrowClosed, color, width: 16, height: 16 }
2617
+ markerEnd: { type: import_react19.MarkerType.ArrowClosed, color, width: 16, height: 16 }
2416
2618
  };
2417
2619
  if (kind === "loop") {
2418
2620
  styled.style = { ...styled.style, strokeDasharray: "4 3" };
@@ -2442,21 +2644,21 @@ function TracedFlow({
2442
2644
  style
2443
2645
  }) {
2444
2646
  const layout = layoutProp ?? dagreTraceLayout;
2445
- const colors = (0, import_react16.useMemo)(
2647
+ const colors = (0, import_react18.useMemo)(
2446
2648
  () => ({ ...DEFAULT_COLORS, ...colorOverrides ?? {} }),
2447
2649
  [colorOverrides]
2448
2650
  );
2449
- const mergedNodeTypes = (0, import_react16.useMemo)(
2651
+ const mergedNodeTypes = (0, import_react18.useMemo)(
2450
2652
  () => userNodeTypes ? { ...DEFAULT_NODE_TYPES2, ...userNodeTypes } : DEFAULT_NODE_TYPES2,
2451
2653
  [userNodeTypes]
2452
2654
  );
2453
- const mergedEdgeTypes = (0, import_react16.useMemo)(
2655
+ const mergedEdgeTypes = (0, import_react18.useMemo)(
2454
2656
  () => userEdgeTypes ? { ...DEFAULT_EDGE_TYPES2, ...userEdgeTypes } : DEFAULT_EDGE_TYPES2,
2455
2657
  [userEdgeTypes]
2456
2658
  );
2457
2659
  const drill = useSubflowDrill(graph, onSubflowChange);
2458
- const groupedSet = (0, import_react16.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
2459
- const filteredGraph = (0, import_react16.useMemo)(() => {
2660
+ const groupedSet = (0, import_react18.useMemo)(() => new Set(groupedSubflows ?? []), [groupedSubflows]);
2661
+ const filteredGraph = (0, import_react18.useMemo)(() => {
2460
2662
  const base = filterGraphForDrill(graph, drill.currentSubflowId);
2461
2663
  if (groupedSet.size === 0) return base;
2462
2664
  const baseIds = new Set(base.nodes.map((n) => n.id));
@@ -2471,12 +2673,23 @@ function TracedFlow({
2471
2673
  );
2472
2674
  return { nodes: [...base.nodes, ...extraNodes], edges: [...base.edges, ...extraEdges] };
2473
2675
  }, [graph, drill.currentSubflowId, groupedSet]);
2474
- const breadcrumb = (0, import_react16.useMemo)(
2676
+ const breadcrumb = (0, import_react18.useMemo)(
2475
2677
  () => buildSubflowBreadcrumb(graph, drill.currentSubflowId),
2476
2678
  [graph, drill.currentSubflowId]
2477
2679
  );
2478
- const positioned = (0, import_react16.useMemo)(() => {
2479
- const realBase = layout === "passthrough" ? (g) => g : layout;
2680
+ const [measuredSizes, setMeasuredSizes] = (0, import_react18.useState)(null);
2681
+ const positioned = (0, import_react18.useMemo)(() => {
2682
+ const nodeSize = measuredSizes ? (n) => measuredSizes.get(n.id) : void 0;
2683
+ const sizeOpts = nodeSize ? { nodeSize } : {};
2684
+ const dagreBase = withForkCentering(
2685
+ createSnappedDagreLayout(
2686
+ createDagreTraceLayout({ ...sizeOpts, rankSep: 52, nodeSep: 36 }),
2687
+ sizeOpts
2688
+ ),
2689
+ { ...sizeOpts, nodeSep: 36 }
2690
+ // same nodeSep → clamp preserves dagre's reserved gap
2691
+ );
2692
+ const realBase = layout === "passthrough" ? (g) => g : layoutProp === void 0 ? dagreBase : layout;
2480
2693
  if (groupedSet.size > 0) {
2481
2694
  const grouped = applyGroupLayout(filteredGraph, {
2482
2695
  groupedSubflowIds: [...groupedSet],
@@ -2487,9 +2700,9 @@ function TracedFlow({
2487
2700
  if (mainChartBox) {
2488
2701
  return wrapInMainChartBox(filteredGraph, { baseLayout: realBase, ...mainChartBox });
2489
2702
  }
2490
- return layout === "passthrough" ? filteredGraph : layout(filteredGraph);
2491
- }, [filteredGraph, layout, groupedSet, mainChartBox]);
2492
- const slice = (0, import_react16.useMemo)(() => {
2703
+ return realBase(filteredGraph);
2704
+ }, [filteredGraph, layout, layoutProp, groupedSet, mainChartBox, measuredSizes]);
2705
+ const slice = (0, import_react18.useMemo)(() => {
2493
2706
  const empty = {
2494
2707
  doneStageIds: /* @__PURE__ */ new Set(),
2495
2708
  activeStageId: null,
@@ -2501,7 +2714,7 @@ function TracedFlow({
2501
2714
  const idx = scrubIndex ?? Math.max(0, overlay.executionOrder.length - 1);
2502
2715
  return aggregateMountStatus(sliceOverlay(overlay, idx), graph, drill.currentSubflowId);
2503
2716
  }, [overlay, scrubIndex, graph, drill.currentSubflowId]);
2504
- const reactFlowNodes = (0, import_react16.useMemo)(
2717
+ const reactFlowNodes = (0, import_react18.useMemo)(
2505
2718
  () => positioned.nodes.map(
2506
2719
  (n) => toStageNodeWithOverlay(
2507
2720
  n,
@@ -2514,13 +2727,13 @@ function TracedFlow({
2514
2727
  ),
2515
2728
  [positioned.nodes, slice, coActiveStageIds]
2516
2729
  );
2517
- const reactFlowEdges = (0, import_react16.useMemo)(
2730
+ const reactFlowEdges = (0, import_react18.useMemo)(
2518
2731
  () => positioned.edges.map(
2519
2732
  (e) => styleEdgeWithOverlay(e, slice.doneStageIds, slice.activeStageId, colors)
2520
2733
  ),
2521
2734
  [positioned.edges, slice, colors]
2522
2735
  );
2523
- const handleNodeClick = (0, import_react16.useCallback)(
2736
+ const handleNodeClick = (0, import_react18.useCallback)(
2524
2737
  (_, node) => {
2525
2738
  const data = node.data ?? {};
2526
2739
  if (data.isSubflow && data.subflowId && !groupedSet.has(data.subflowId)) {
@@ -2530,9 +2743,13 @@ function TracedFlow({
2530
2743
  },
2531
2744
  [drill, onNodeClick, groupedSet]
2532
2745
  );
2533
- const wrapperRef = (0, import_react16.useRef)(null);
2534
- const [rfInstance, setRfInstance] = (0, import_react16.useState)(null);
2535
- useChartAutoRefit(wrapperRef, rfInstance, { refitKey: drill.currentSubflowId });
2746
+ const wrapperRef = (0, import_react18.useRef)(null);
2747
+ const [rfInstance, setRfInstance] = (0, import_react18.useState)(null);
2748
+ useChartAutoRefit(wrapperRef, rfInstance, {
2749
+ // Re-fit on drill AND after the measured-size re-layout settles.
2750
+ refitKey: `${drill.currentSubflowId ?? ""}:${measuredSizes ? "measured" : "estimated"}`,
2751
+ padding: 0.18
2752
+ });
2536
2753
  return /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2537
2754
  "div",
2538
2755
  {
@@ -2555,7 +2772,7 @@ function TracedFlow({
2555
2772
  }
2556
2773
  ),
2557
2774
  /* @__PURE__ */ (0, import_jsx_runtime11.jsx)("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime11.jsxs)(
2558
- import_react17.ReactFlow,
2775
+ import_react19.ReactFlow,
2559
2776
  {
2560
2777
  nodes: reactFlowNodes,
2561
2778
  edges: reactFlowEdges,
@@ -2564,9 +2781,12 @@ function TracedFlow({
2564
2781
  onNodeClick: handleNodeClick,
2565
2782
  onInit: setRfInstance,
2566
2783
  fitView: true,
2784
+ fitViewOptions: { padding: 0.18 },
2785
+ minZoom: 0.1,
2567
2786
  proOptions: { hideAttribution: true },
2568
2787
  children: [
2569
- /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react17.Background, { variant: import_react17.BackgroundVariant.Dots, gap: 20, size: 1 }),
2788
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(MeasuredNodeSizes, { onSizes: setMeasuredSizes }),
2789
+ /* @__PURE__ */ (0, import_jsx_runtime11.jsx)(import_react19.Background, { variant: import_react19.BackgroundVariant.Dots, gap: 20, size: 1 }),
2570
2790
  children
2571
2791
  ]
2572
2792
  }
@@ -2590,7 +2810,7 @@ function TimeTravelDebugger({
2590
2810
  className,
2591
2811
  style
2592
2812
  }) {
2593
- const [selectedIndex, setSelectedIndex] = (0, import_react18.useState)(0);
2813
+ const [selectedIndex, setSelectedIndex] = (0, import_react20.useState)(0);
2594
2814
  const fs = fontSize[size];
2595
2815
  const pad = padding[size];
2596
2816
  if (snapshots.length === 0) {
@@ -2884,9 +3104,9 @@ function ScrubButton({
2884
3104
  }
2885
3105
 
2886
3106
  // src/components/FlowchartView/SubflowBreadcrumb.tsx
2887
- var import_react19 = require("react");
3107
+ var import_react21 = require("react");
2888
3108
  var import_jsx_runtime13 = require("react/jsx-runtime");
2889
- var SubflowBreadcrumb = (0, import_react19.memo)(function SubflowBreadcrumb2({
3109
+ var SubflowBreadcrumb = (0, import_react21.memo)(function SubflowBreadcrumb2({
2890
3110
  breadcrumbs,
2891
3111
  onNavigate
2892
3112
  }) {
@@ -2967,12 +3187,12 @@ var SubflowBreadcrumb = (0, import_react19.memo)(function SubflowBreadcrumb2({
2967
3187
  });
2968
3188
 
2969
3189
  // src/components/FlowchartView/useSubflowNavigation.ts
2970
- var import_react20 = require("react");
3190
+ var import_react22 = require("react");
2971
3191
  var EMPTY_GRAPH2 = { nodes: [], edges: [] };
2972
3192
  function useSubflowNavigation(rootGraph) {
2973
- const [stack, setStack] = (0, import_react20.useState)([]);
3193
+ const [stack, setStack] = (0, import_react22.useState)([]);
2974
3194
  const safeRootGraph = rootGraph ?? EMPTY_GRAPH2;
2975
- const subflowMounts = (0, import_react20.useMemo)(() => {
3195
+ const subflowMounts = (0, import_react22.useMemo)(() => {
2976
3196
  const map = /* @__PURE__ */ new Map();
2977
3197
  for (const node of safeRootGraph.nodes) {
2978
3198
  if (!node.data?.isSubflow) continue;
@@ -2990,12 +3210,12 @@ function useSubflowNavigation(rootGraph) {
2990
3210
  }
2991
3211
  return map;
2992
3212
  }, [safeRootGraph]);
2993
- const breadcrumbs = (0, import_react20.useMemo)(() => {
3213
+ const breadcrumbs = (0, import_react22.useMemo)(() => {
2994
3214
  const rootLabel = "Flowchart";
2995
3215
  const root = { label: rootLabel };
2996
3216
  return [root, ...stack];
2997
3217
  }, [stack]);
2998
- const handleNodeClick = (0, import_react20.useCallback)(
3218
+ const handleNodeClick = (0, import_react22.useCallback)(
2999
3219
  (nodeId) => {
3000
3220
  const mount = subflowMounts.get(nodeId);
3001
3221
  if (!mount) return false;
@@ -3011,7 +3231,7 @@ function useSubflowNavigation(rootGraph) {
3011
3231
  },
3012
3232
  [subflowMounts]
3013
3233
  );
3014
- const navigateTo = (0, import_react20.useCallback)((level) => {
3234
+ const navigateTo = (0, import_react22.useCallback)((level) => {
3015
3235
  if (level === 0) {
3016
3236
  setStack([]);
3017
3237
  } else {
@@ -3033,7 +3253,7 @@ function useSubflowNavigation(rootGraph) {
3033
3253
  }
3034
3254
 
3035
3255
  // src/components/FlowchartView/SubflowTree.tsx
3036
- var import_react21 = require("react");
3256
+ var import_react23 = require("react");
3037
3257
  var import_jsx_runtime14 = require("react/jsx-runtime");
3038
3258
  function graphToSubflowEntries(graph) {
3039
3259
  if (!graph?.nodes?.length) return [];
@@ -3050,18 +3270,18 @@ function graphToSubflowEntries(graph) {
3050
3270
  }
3051
3271
  return entries;
3052
3272
  }
3053
- var TreeNode = (0, import_react21.memo)(function TreeNode2({
3273
+ var TreeNode = (0, import_react23.memo)(function TreeNode2({
3054
3274
  entry,
3055
3275
  depth,
3056
3276
  activeStage,
3057
3277
  doneStages,
3058
3278
  onNodeSelect
3059
3279
  }) {
3060
- const [expanded, setExpanded] = (0, import_react21.useState)(true);
3280
+ const [expanded, setExpanded] = (0, import_react23.useState)(true);
3061
3281
  const hasChildren = entry.children && entry.children.length > 0;
3062
3282
  const isActive = activeStage === entry.name;
3063
3283
  const isDone = doneStages?.has(entry.name);
3064
- const handleClick = (0, import_react21.useCallback)(() => {
3284
+ const handleClick = (0, import_react23.useCallback)(() => {
3065
3285
  if (hasChildren) {
3066
3286
  setExpanded((prev) => !prev);
3067
3287
  }
@@ -3174,7 +3394,7 @@ var TreeNode = (0, import_react21.memo)(function TreeNode2({
3174
3394
  )) })
3175
3395
  ] });
3176
3396
  });
3177
- var SectionLabel = (0, import_react21.memo)(function SectionLabel2({ children }) {
3397
+ var SectionLabel = (0, import_react23.memo)(function SectionLabel2({ children }) {
3178
3398
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsx)(
3179
3399
  "div",
3180
3400
  {
@@ -3190,7 +3410,7 @@ var SectionLabel = (0, import_react21.memo)(function SectionLabel2({ children })
3190
3410
  }
3191
3411
  );
3192
3412
  });
3193
- var SubflowTree = (0, import_react21.memo)(function SubflowTree2({
3413
+ var SubflowTree = (0, import_react23.memo)(function SubflowTree2({
3194
3414
  graph,
3195
3415
  activeStage,
3196
3416
  doneStages,
@@ -3199,7 +3419,7 @@ var SubflowTree = (0, import_react21.memo)(function SubflowTree2({
3199
3419
  className,
3200
3420
  style
3201
3421
  }) {
3202
- const subflowStages = (0, import_react21.useMemo)(() => graphToSubflowEntries(graph), [graph]);
3422
+ const subflowStages = (0, import_react23.useMemo)(() => graphToSubflowEntries(graph), [graph]);
3203
3423
  if (subflowStages.length === 0) return null;
3204
3424
  return /* @__PURE__ */ (0, import_jsx_runtime14.jsxs)(
3205
3425
  "div",
@@ -3524,7 +3744,7 @@ function createTraceStructureRecorder(options = {}) {
3524
3744
  }
3525
3745
 
3526
3746
  // src/components/SlotPillNode/SlotPillNode.tsx
3527
- var import_react22 = require("@xyflow/react");
3747
+ var import_react24 = require("@xyflow/react");
3528
3748
  var import_jsx_runtime15 = require("react/jsx-runtime");
3529
3749
  var C2 = rawDefaults.colors;
3530
3750
  function SlotPillNode({ data }) {
@@ -3573,63 +3793,13 @@ function SlotPillNode({ data }) {
3573
3793
  ),
3574
3794
  d.icon ? /* @__PURE__ */ (0, import_jsx_runtime15.jsx)("span", { "aria-hidden": true, style: { flexShrink: 0 }, children: d.icon }) : null,
3575
3795
  /* @__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 } })
3796
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react24.Handle, { type: "target", position: import_react24.Position.Top, style: { opacity: 0 } }),
3797
+ /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(import_react24.Handle, { type: "source", position: import_react24.Position.Bottom, style: { opacity: 0 } })
3578
3798
  ]
3579
3799
  }
3580
3800
  );
3581
3801
  }
3582
3802
 
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
3803
  // src/components/FlowchartView/_internal/traceGroupLayout.ts
3634
3804
  function buildAdjacency(graph, fallbackW, fallbackH, nodeSize) {
3635
3805
  const preds = /* @__PURE__ */ new Map();
@@ -4299,12 +4469,12 @@ function createTraceBundle(options = {}) {
4299
4469
  }
4300
4470
 
4301
4471
  // src/components/FlowchartView/_internal/useTranslator.ts
4302
- var import_react23 = require("react");
4472
+ var import_react25 = require("react");
4303
4473
  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]);
4474
+ const subscribe = (0, import_react25.useMemo)(() => handle.subscribe.bind(handle), [handle]);
4475
+ const getVersion = (0, import_react25.useMemo)(() => handle.version.bind(handle), [handle]);
4476
+ const version = (0, import_react25.useSyncExternalStore)(subscribe, getVersion, getVersion);
4477
+ return (0, import_react25.useMemo)(() => getSnapshot(), [version, getSnapshot]);
4308
4478
  }
4309
4479
 
4310
4480
  // src/components/FlowchartView/walkHelpers.ts
@@ -4387,7 +4557,7 @@ function bfsWalk(index, startId, neighborsOf, options) {
4387
4557
  }
4388
4558
 
4389
4559
  // src/components/FlowchartView/NodeInspector.tsx
4390
- var import_react24 = require("react");
4560
+ var import_react26 = require("react");
4391
4561
  var import_jsx_runtime16 = require("react/jsx-runtime");
4392
4562
  function NodeInspector({
4393
4563
  index,
@@ -4398,11 +4568,11 @@ function NodeInspector({
4398
4568
  style
4399
4569
  }) {
4400
4570
  const view = selectedId ? index.byStageId.get(selectedId) ?? null : null;
4401
- const prevChain = (0, import_react24.useMemo)(
4571
+ const prevChain = (0, import_react26.useMemo)(
4402
4572
  () => view ? backtraceStructural(index, view.stageId, { onlyVisited }) : [],
4403
4573
  [index, view, onlyVisited]
4404
4574
  );
4405
- const nextChain = (0, import_react24.useMemo)(
4575
+ const nextChain = (0, import_react26.useMemo)(
4406
4576
  () => view ? forwardtraceStructural(index, view.stageId, { onlyVisited }) : [],
4407
4577
  [index, view, onlyVisited]
4408
4578
  );
@@ -4528,7 +4698,7 @@ function Crumbs({ nodes, onClick }) {
4528
4698
  }
4529
4699
 
4530
4700
  // src/components/FlowchartView/CommitInspector.tsx
4531
- var import_react25 = require("react");
4701
+ var import_react27 = require("react");
4532
4702
  var import_jsx_runtime17 = require("react/jsx-runtime");
4533
4703
  function CommitInspector({
4534
4704
  index,
@@ -4538,7 +4708,7 @@ function CommitInspector({
4538
4708
  style
4539
4709
  }) {
4540
4710
  const view = selectedRuntimeStageId ? index.byRuntimeStageId.get(selectedRuntimeStageId) ?? null : null;
4541
- const lineage = (0, import_react25.useMemo)(
4711
+ const lineage = (0, import_react27.useMemo)(
4542
4712
  () => view ? backtraceDataFlow(index, view.runtimeStageId) : [],
4543
4713
  [index, view]
4544
4714
  );
@@ -5124,10 +5294,10 @@ var boxBaseStyle = {
5124
5294
  };
5125
5295
 
5126
5296
  // src/components/FlowchartView/TraceExplorerShell.tsx
5127
- var import_react27 = require("react");
5297
+ var import_react29 = require("react");
5128
5298
 
5129
5299
  // src/components/FlowchartView/RunSlider.tsx
5130
- var import_react26 = require("react");
5300
+ var import_react28 = require("react");
5131
5301
  var import_jsx_runtime19 = require("react/jsx-runtime");
5132
5302
  function RunSlider({
5133
5303
  index,
@@ -5138,12 +5308,12 @@ function RunSlider({
5138
5308
  style
5139
5309
  }) {
5140
5310
  const total = index.commits.length;
5141
- const cursorCommitIdx = (0, import_react26.useMemo)(() => {
5311
+ const cursorCommitIdx = (0, import_react28.useMemo)(() => {
5142
5312
  if (!cursorRuntimeStageId) return 0;
5143
5313
  const view = index.byRuntimeStageId.get(cursorRuntimeStageId);
5144
5314
  return view ? view.commitIdx : 0;
5145
5315
  }, [index, cursorRuntimeStageId]);
5146
- const handleSliderChange = (0, import_react26.useCallback)(
5316
+ const handleSliderChange = (0, import_react28.useCallback)(
5147
5317
  (e) => {
5148
5318
  const value = Number(e.target.value);
5149
5319
  const view = index.commits[value];
@@ -5151,7 +5321,7 @@ function RunSlider({
5151
5321
  },
5152
5322
  [index, onCursorChange]
5153
5323
  );
5154
- const label = (0, import_react26.useMemo)(() => {
5324
+ const label = (0, import_react28.useMemo)(() => {
5155
5325
  const commit = index.commits[cursorCommitIdx] ?? null;
5156
5326
  const rsid = cursorRuntimeStageId ?? commit?.runtimeStageId ?? null;
5157
5327
  if (renderLabel)
@@ -5235,39 +5405,39 @@ function TraceExplorerShell({
5235
5405
  className,
5236
5406
  style
5237
5407
  }) {
5238
- const [internalSel, setInternalSel] = (0, import_react27.useState)(null);
5408
+ const [internalSel, setInternalSel] = (0, import_react29.useState)(null);
5239
5409
  const isControlled = controlledSel !== void 0;
5240
5410
  const selectedRuntimeStageId = isControlled ? controlledSel : internalSel;
5241
- const handleSelect = (0, import_react27.useCallback)(
5411
+ const handleSelect = (0, import_react29.useCallback)(
5242
5412
  (rsid) => {
5243
5413
  if (!isControlled) setInternalSel(rsid);
5244
5414
  onSelectionChange?.(rsid);
5245
5415
  },
5246
5416
  [isControlled, onSelectionChange]
5247
5417
  );
5248
- const handleSelectCommit = (0, import_react27.useCallback)(
5418
+ const handleSelectCommit = (0, import_react29.useCallback)(
5249
5419
  (rsid) => handleSelect(rsid),
5250
5420
  [handleSelect]
5251
5421
  );
5252
- const selectedStageId = (0, import_react27.useMemo)(() => {
5422
+ const selectedStageId = (0, import_react29.useMemo)(() => {
5253
5423
  if (!selectedRuntimeStageId) return null;
5254
5424
  const hashIdx = selectedRuntimeStageId.lastIndexOf("#");
5255
5425
  if (hashIdx <= 0) return null;
5256
5426
  return asStageId(selectedRuntimeStageId.slice(0, hashIdx));
5257
5427
  }, [selectedRuntimeStageId]);
5258
- const ChainPane = (0, import_react27.useMemo)(
5428
+ const ChainPane = (0, import_react29.useMemo)(
5259
5429
  () => slots?.chain ?? DefaultChainPane,
5260
5430
  [slots?.chain]
5261
5431
  );
5262
- const CommitPane = (0, import_react27.useMemo)(
5432
+ const CommitPane = (0, import_react29.useMemo)(
5263
5433
  () => slots?.commitInspector ?? DefaultCommitPane,
5264
5434
  [slots?.commitInspector]
5265
5435
  );
5266
- const NodePane = (0, import_react27.useMemo)(
5436
+ const NodePane = (0, import_react29.useMemo)(
5267
5437
  () => slots?.nodeInspector ?? DefaultNodePane,
5268
5438
  [slots?.nodeInspector]
5269
5439
  );
5270
- const SliderPane = (0, import_react27.useMemo)(() => {
5440
+ const SliderPane = (0, import_react29.useMemo)(() => {
5271
5441
  if (slots && "slider" in slots) {
5272
5442
  return slots.slider ?? null;
5273
5443
  }
@@ -5282,7 +5452,7 @@ function TraceExplorerShell({
5282
5452
  () => bundle.commitFlow.getIndex()
5283
5453
  );
5284
5454
  const nodeIndex = useTranslator(bundle.nodeView, () => bundle.nodeView.getIndex());
5285
- const handleStageNavigate = (0, import_react27.useCallback)(
5455
+ const handleStageNavigate = (0, import_react29.useCallback)(
5286
5456
  (stageId) => {
5287
5457
  const candidates = commitIndex.commits.filter((c) => c.stageId === stageId);
5288
5458
  const first = candidates[0];
@@ -5290,12 +5460,12 @@ function TraceExplorerShell({
5290
5460
  },
5291
5461
  [commitIndex, handleSelect]
5292
5462
  );
5293
- const revealedThroughCommitIdx = (0, import_react27.useMemo)(() => {
5463
+ const revealedThroughCommitIdx = (0, import_react29.useMemo)(() => {
5294
5464
  if (!selectedRuntimeStageId) return null;
5295
5465
  const view = commitIndex.byRuntimeStageId.get(selectedRuntimeStageId);
5296
5466
  return view ? view.commitIdx : -1;
5297
5467
  }, [selectedRuntimeStageId, commitIndex]);
5298
- const layoutStyle = (0, import_react27.useMemo)(
5468
+ const layoutStyle = (0, import_react29.useMemo)(
5299
5469
  () => SliderPane ? SHELL_STYLE_WITH_SLIDER : SHELL_STYLE_NO_SLIDER,
5300
5470
  [SliderPane]
5301
5471
  );