footprint-explainable-ui 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/flowchart.js CHANGED
@@ -373,75 +373,13 @@ function FlowchartView({
373
373
  );
374
374
  }
375
375
 
376
- // src/components/FlowchartView/SubflowBreadcrumb.tsx
377
- import { memo as memo2 } from "react";
378
- import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
379
- var SubflowBreadcrumb = memo2(function SubflowBreadcrumb2({
380
- breadcrumbs,
381
- onNavigate
382
- }) {
383
- if (breadcrumbs.length <= 1) return null;
384
- return /* @__PURE__ */ jsx4(
385
- "div",
386
- {
387
- style: {
388
- display: "flex",
389
- alignItems: "center",
390
- gap: 4,
391
- padding: "6px 12px",
392
- background: theme.bgSecondary,
393
- borderBottom: `1px solid ${theme.border}`,
394
- fontSize: 12,
395
- fontFamily: theme.fontSans,
396
- flexShrink: 0,
397
- overflowX: "auto"
398
- },
399
- children: breadcrumbs.map((crumb, i) => {
400
- const isLast = i === breadcrumbs.length - 1;
401
- return /* @__PURE__ */ jsxs2("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
402
- i > 0 && /* @__PURE__ */ jsx4("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
403
- isLast ? /* @__PURE__ */ jsx4(
404
- "span",
405
- {
406
- style: {
407
- color: theme.primary,
408
- fontWeight: 600
409
- },
410
- children: crumb.label
411
- }
412
- ) : /* @__PURE__ */ jsx4(
413
- "button",
414
- {
415
- onClick: () => onNavigate(i),
416
- style: {
417
- background: "none",
418
- border: "none",
419
- color: theme.textSecondary,
420
- cursor: "pointer",
421
- padding: "2px 4px",
422
- borderRadius: 4,
423
- fontSize: 12,
424
- fontFamily: "inherit",
425
- fontWeight: 500,
426
- transition: "color 0.15s"
427
- },
428
- onMouseEnter: (e) => {
429
- e.currentTarget.style.color = `${theme.primary}`;
430
- },
431
- onMouseLeave: (e) => {
432
- e.currentTarget.style.color = `${theme.textSecondary}`;
433
- },
434
- children: crumb.label
435
- }
436
- )
437
- ] }, i);
438
- })
439
- }
440
- );
441
- });
442
-
443
- // src/components/FlowchartView/useSubflowNavigation.ts
444
- import { useState, useCallback as useCallback2, useMemo as useMemo2 } from "react";
376
+ // src/components/FlowchartView/TracedFlowchartView.tsx
377
+ import { useMemo as useMemo3, useCallback as useCallback3 } from "react";
378
+ import {
379
+ ReactFlow as ReactFlow2,
380
+ Background as Background2,
381
+ BackgroundVariant as BackgroundVariant2
382
+ } from "@xyflow/react";
445
383
 
446
384
  // src/components/FlowchartView/specToReactFlow.ts
447
385
  var DEFAULT_COLORS = {
@@ -623,6 +561,7 @@ function specToReactFlow(spec, overlay, colors) {
623
561
  }
624
562
 
625
563
  // src/components/FlowchartView/useSubflowNavigation.ts
564
+ import { useState, useCallback as useCallback2, useMemo as useMemo2 } from "react";
626
565
  function useSubflowNavigation(rootSpec, overlay, colors) {
627
566
  const [stack, setStack] = useState([]);
628
567
  const currentSpec = stack.length > 0 ? stack[stack.length - 1].spec : rootSpec;
@@ -687,12 +626,169 @@ function useSubflowNavigation(rootSpec, overlay, colors) {
687
626
  };
688
627
  }
689
628
 
629
+ // src/components/FlowchartView/SubflowBreadcrumb.tsx
630
+ import { memo as memo2 } from "react";
631
+ import { jsx as jsx4, jsxs as jsxs2 } from "react/jsx-runtime";
632
+ var SubflowBreadcrumb = memo2(function SubflowBreadcrumb2({
633
+ breadcrumbs,
634
+ onNavigate
635
+ }) {
636
+ if (breadcrumbs.length <= 1) return null;
637
+ return /* @__PURE__ */ jsx4(
638
+ "div",
639
+ {
640
+ style: {
641
+ display: "flex",
642
+ alignItems: "center",
643
+ gap: 4,
644
+ padding: "6px 12px",
645
+ background: theme.bgSecondary,
646
+ borderBottom: `1px solid ${theme.border}`,
647
+ fontSize: 12,
648
+ fontFamily: theme.fontSans,
649
+ flexShrink: 0,
650
+ overflowX: "auto"
651
+ },
652
+ children: breadcrumbs.map((crumb, i) => {
653
+ const isLast = i === breadcrumbs.length - 1;
654
+ return /* @__PURE__ */ jsxs2("span", { style: { display: "flex", alignItems: "center", gap: 4 }, children: [
655
+ i > 0 && /* @__PURE__ */ jsx4("span", { style: { color: theme.textMuted, fontSize: 10 }, children: "\u203A" }),
656
+ isLast ? /* @__PURE__ */ jsx4(
657
+ "span",
658
+ {
659
+ style: {
660
+ color: theme.primary,
661
+ fontWeight: 600
662
+ },
663
+ children: crumb.label
664
+ }
665
+ ) : /* @__PURE__ */ jsx4(
666
+ "button",
667
+ {
668
+ onClick: () => onNavigate(i),
669
+ style: {
670
+ background: "none",
671
+ border: "none",
672
+ color: theme.textSecondary,
673
+ cursor: "pointer",
674
+ padding: "2px 4px",
675
+ borderRadius: 4,
676
+ fontSize: 12,
677
+ fontFamily: "inherit",
678
+ fontWeight: 500,
679
+ transition: "color 0.15s"
680
+ },
681
+ onMouseEnter: (e) => {
682
+ e.currentTarget.style.color = `${theme.primary}`;
683
+ },
684
+ onMouseLeave: (e) => {
685
+ e.currentTarget.style.color = `${theme.textSecondary}`;
686
+ },
687
+ children: crumb.label
688
+ }
689
+ )
690
+ ] }, i);
691
+ })
692
+ }
693
+ );
694
+ });
695
+
696
+ // src/components/FlowchartView/TracedFlowchartView.tsx
697
+ import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
698
+ var nodeTypes2 = { stage: StageNode };
699
+ function TracedFlowchartView({
700
+ spec,
701
+ snapshots,
702
+ snapshotIndex = 0,
703
+ onNodeClick,
704
+ onSubflowChange,
705
+ unstyled = false,
706
+ className,
707
+ style
708
+ }) {
709
+ const subflowNav = useSubflowNavigation(spec);
710
+ const currentSpec = subflowNav.breadcrumbs.length > 0 ? subflowNav.breadcrumbs[subflowNav.breadcrumbs.length - 1].spec : null;
711
+ const overlay = useMemo3(() => {
712
+ if (!snapshots || snapshots.length === 0) return void 0;
713
+ const executionOrder = snapshots.slice(0, snapshotIndex + 1).map((s) => s.stageLabel);
714
+ const doneStages = new Set(
715
+ snapshots.slice(0, snapshotIndex).map((s) => s.stageLabel)
716
+ );
717
+ const activeStage = snapshots[snapshotIndex]?.stageLabel ?? null;
718
+ const executedStages = /* @__PURE__ */ new Set([...doneStages]);
719
+ if (activeStage) executedStages.add(activeStage);
720
+ return { doneStages, activeStage, executedStages, executionOrder };
721
+ }, [snapshots, snapshotIndex]);
722
+ const { nodes, edges } = useMemo3(() => {
723
+ if (!currentSpec) return { nodes: [], edges: [] };
724
+ return specToReactFlow(currentSpec, overlay);
725
+ }, [currentSpec, overlay]);
726
+ const handleNodeClick = useCallback3(
727
+ (_, node) => {
728
+ if (subflowNav.handleNodeClick(node.id)) {
729
+ onSubflowChange?.(true, node.id);
730
+ return;
731
+ }
732
+ if (onNodeClick && snapshots) {
733
+ const idx = snapshots.findIndex((s) => s.stageLabel === node.id);
734
+ if (idx >= 0) onNodeClick(idx);
735
+ } else if (onNodeClick) {
736
+ onNodeClick(node.id);
737
+ }
738
+ },
739
+ [subflowNav, onNodeClick, onSubflowChange, snapshots]
740
+ );
741
+ const handleBreadcrumbNavigate = useCallback3(
742
+ (level) => {
743
+ subflowNav.navigateTo(level);
744
+ onSubflowChange?.(level > 0, null);
745
+ },
746
+ [subflowNav, onSubflowChange]
747
+ );
748
+ return /* @__PURE__ */ jsxs3(
749
+ "div",
750
+ {
751
+ className,
752
+ style: { width: "100%", height: "100%", display: "flex", flexDirection: "column", ...style },
753
+ "data-fp": "traced-flowchart",
754
+ children: [
755
+ subflowNav.isInSubflow && /* @__PURE__ */ jsx5(
756
+ SubflowBreadcrumb,
757
+ {
758
+ breadcrumbs: subflowNav.breadcrumbs,
759
+ onNavigate: handleBreadcrumbNavigate
760
+ }
761
+ ),
762
+ /* @__PURE__ */ jsx5("div", { style: { flex: 1, minHeight: 0 }, children: /* @__PURE__ */ jsx5(
763
+ ReactFlow2,
764
+ {
765
+ nodes,
766
+ edges,
767
+ onNodeClick: handleNodeClick,
768
+ nodeTypes: nodeTypes2,
769
+ fitView: true,
770
+ panOnDrag: false,
771
+ zoomOnScroll: false,
772
+ zoomOnPinch: false,
773
+ zoomOnDoubleClick: false,
774
+ preventScrolling: false,
775
+ nodesDraggable: false,
776
+ nodesConnectable: false,
777
+ elementsSelectable: !!onNodeClick,
778
+ children: !unstyled && /* @__PURE__ */ jsx5(Background2, { variant: BackgroundVariant2.Dots, gap: 16, size: 1 })
779
+ }
780
+ ) })
781
+ ]
782
+ }
783
+ );
784
+ }
785
+
690
786
  // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
691
- import { useState as useState2 } from "react";
787
+ import { useState as useState3 } from "react";
692
788
 
693
789
  // src/components/MemoryInspector/MemoryInspector.tsx
694
- import { useMemo as useMemo3 } from "react";
695
- import { jsx as jsx5, jsxs as jsxs3 } from "react/jsx-runtime";
790
+ import { useMemo as useMemo4 } from "react";
791
+ import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
696
792
  function MemoryInspector({
697
793
  data,
698
794
  snapshots,
@@ -704,7 +800,7 @@ function MemoryInspector({
704
800
  className,
705
801
  style
706
802
  }) {
707
- const { memory, newKeys } = useMemo3(() => {
803
+ const { memory, newKeys } = useMemo4(() => {
708
804
  if (data) {
709
805
  return { memory: data, newKeys: /* @__PURE__ */ new Set() };
710
806
  }
@@ -734,12 +830,12 @@ function MemoryInspector({
734
830
  const fs = fontSize[size];
735
831
  const pad = padding[size];
736
832
  if (unstyled) {
737
- return /* @__PURE__ */ jsxs3("div", { className, style, "data-fp": "memory-inspector", children: [
738
- /* @__PURE__ */ jsx5("div", { "data-fp": "memory-label", children: "Memory State" }),
739
- /* @__PURE__ */ jsx5("pre", { "data-fp": "memory-json", children: JSON.stringify(memory, null, 2) })
833
+ return /* @__PURE__ */ jsxs4("div", { className, style, "data-fp": "memory-inspector", children: [
834
+ /* @__PURE__ */ jsx6("div", { "data-fp": "memory-label", children: "Memory State" }),
835
+ /* @__PURE__ */ jsx6("pre", { "data-fp": "memory-json", children: JSON.stringify(memory, null, 2) })
740
836
  ] });
741
837
  }
742
- return /* @__PURE__ */ jsxs3(
838
+ return /* @__PURE__ */ jsxs4(
743
839
  "div",
744
840
  {
745
841
  className,
@@ -750,7 +846,7 @@ function MemoryInspector({
750
846
  },
751
847
  "data-fp": "memory-inspector",
752
848
  children: [
753
- /* @__PURE__ */ jsx5(
849
+ /* @__PURE__ */ jsx6(
754
850
  "span",
755
851
  {
756
852
  style: {
@@ -763,7 +859,7 @@ function MemoryInspector({
763
859
  children: "Memory State"
764
860
  }
765
861
  ),
766
- /* @__PURE__ */ jsxs3(
862
+ /* @__PURE__ */ jsxs4(
767
863
  "div",
768
864
  {
769
865
  style: {
@@ -777,8 +873,8 @@ function MemoryInspector({
777
873
  lineHeight: 1.8
778
874
  },
779
875
  children: [
780
- /* @__PURE__ */ jsx5("span", { style: { color: theme.textMuted }, children: "{" }),
781
- entries.length === 0 && /* @__PURE__ */ jsx5(
876
+ /* @__PURE__ */ jsx6("span", { style: { color: theme.textMuted }, children: "{" }),
877
+ entries.length === 0 && /* @__PURE__ */ jsx6(
782
878
  "div",
783
879
  {
784
880
  style: {
@@ -792,7 +888,7 @@ function MemoryInspector({
792
888
  entries.map(([key, value], i) => {
793
889
  const isNew = newKeys.has(key);
794
890
  const isLast = i === entries.length - 1;
795
- return /* @__PURE__ */ jsxs3(
891
+ return /* @__PURE__ */ jsxs4(
796
892
  "div",
797
893
  {
798
894
  style: {
@@ -804,14 +900,14 @@ function MemoryInspector({
804
900
  paddingRight: 4
805
901
  },
806
902
  children: [
807
- /* @__PURE__ */ jsxs3("span", { style: { color: theme.primary }, children: [
903
+ /* @__PURE__ */ jsxs4("span", { style: { color: theme.primary }, children: [
808
904
  '"',
809
905
  key,
810
906
  '"'
811
907
  ] }),
812
- /* @__PURE__ */ jsx5("span", { style: { color: theme.textMuted }, children: ": " }),
813
- /* @__PURE__ */ jsx5("span", { style: { color: theme.success }, children: formatValue(value) }),
814
- showTypes && /* @__PURE__ */ jsxs3(
908
+ /* @__PURE__ */ jsx6("span", { style: { color: theme.textMuted }, children: ": " }),
909
+ /* @__PURE__ */ jsx6("span", { style: { color: theme.success }, children: formatValue(value) }),
910
+ showTypes && /* @__PURE__ */ jsxs4(
815
911
  "span",
816
912
  {
817
913
  style: {
@@ -827,13 +923,13 @@ function MemoryInspector({
827
923
  ]
828
924
  }
829
925
  ),
830
- !isLast && /* @__PURE__ */ jsx5("span", { style: { color: theme.textMuted }, children: "," })
926
+ !isLast && /* @__PURE__ */ jsx6("span", { style: { color: theme.textMuted }, children: "," })
831
927
  ]
832
928
  },
833
929
  key
834
930
  );
835
931
  }),
836
- /* @__PURE__ */ jsx5("span", { style: { color: theme.textMuted }, children: "}" })
932
+ /* @__PURE__ */ jsx6("span", { style: { color: theme.textMuted }, children: "}" })
837
933
  ]
838
934
  }
839
935
  )
@@ -848,8 +944,8 @@ function formatValue(value) {
848
944
  }
849
945
 
850
946
  // src/components/NarrativeLog/NarrativeLog.tsx
851
- import { useMemo as useMemo4 } from "react";
852
- import { jsx as jsx6, jsxs as jsxs4 } from "react/jsx-runtime";
947
+ import { useMemo as useMemo5 } from "react";
948
+ import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
853
949
  function NarrativeLog({
854
950
  snapshots,
855
951
  selectedIndex,
@@ -859,7 +955,7 @@ function NarrativeLog({
859
955
  className,
860
956
  style
861
957
  }) {
862
- const entries = useMemo4(() => {
958
+ const entries = useMemo5(() => {
863
959
  if (narrative) {
864
960
  return [{ label: "Output", text: narrative, isCurrent: true }];
865
961
  }
@@ -873,19 +969,19 @@ function NarrativeLog({
873
969
  const fs = fontSize[size];
874
970
  const pad = padding[size];
875
971
  if (unstyled) {
876
- return /* @__PURE__ */ jsx6("div", { className, style, "data-fp": "narrative-log", children: entries.map((entry, i) => /* @__PURE__ */ jsxs4("div", { "data-fp": "narrative-entry", "data-current": entry.isCurrent, children: [
877
- /* @__PURE__ */ jsx6("strong", { children: entry.label }),
878
- /* @__PURE__ */ jsx6("p", { children: entry.text })
972
+ return /* @__PURE__ */ jsx7("div", { className, style, "data-fp": "narrative-log", children: entries.map((entry, i) => /* @__PURE__ */ jsxs5("div", { "data-fp": "narrative-entry", "data-current": entry.isCurrent, children: [
973
+ /* @__PURE__ */ jsx7("strong", { children: entry.label }),
974
+ /* @__PURE__ */ jsx7("p", { children: entry.text })
879
975
  ] }, i)) });
880
976
  }
881
- return /* @__PURE__ */ jsxs4(
977
+ return /* @__PURE__ */ jsxs5(
882
978
  "div",
883
979
  {
884
980
  className,
885
981
  style: { padding: pad, fontFamily: theme.fontSans, ...style },
886
982
  "data-fp": "narrative-log",
887
983
  children: [
888
- /* @__PURE__ */ jsx6(
984
+ /* @__PURE__ */ jsx7(
889
985
  "span",
890
986
  {
891
987
  style: {
@@ -898,7 +994,7 @@ function NarrativeLog({
898
994
  children: "Execution Log"
899
995
  }
900
996
  ),
901
- /* @__PURE__ */ jsx6("div", { style: { marginTop: 8, display: "flex", flexDirection: "column" }, children: entries.map((entry, i) => /* @__PURE__ */ jsxs4(
997
+ /* @__PURE__ */ jsx7("div", { style: { marginTop: 8, display: "flex", flexDirection: "column" }, children: entries.map((entry, i) => /* @__PURE__ */ jsxs5(
902
998
  "div",
903
999
  {
904
1000
  style: {
@@ -908,7 +1004,7 @@ function NarrativeLog({
908
1004
  borderBottom: i < entries.length - 1 ? `1px solid ${theme.border}` : "none"
909
1005
  },
910
1006
  children: [
911
- /* @__PURE__ */ jsxs4(
1007
+ /* @__PURE__ */ jsxs5(
912
1008
  "div",
913
1009
  {
914
1010
  style: {
@@ -920,7 +1016,7 @@ function NarrativeLog({
920
1016
  paddingTop: 5
921
1017
  },
922
1018
  children: [
923
- /* @__PURE__ */ jsx6(
1019
+ /* @__PURE__ */ jsx7(
924
1020
  "div",
925
1021
  {
926
1022
  style: {
@@ -932,7 +1028,7 @@ function NarrativeLog({
932
1028
  }
933
1029
  }
934
1030
  ),
935
- i < entries.length - 1 && /* @__PURE__ */ jsx6(
1031
+ i < entries.length - 1 && /* @__PURE__ */ jsx7(
936
1032
  "div",
937
1033
  {
938
1034
  style: {
@@ -946,8 +1042,8 @@ function NarrativeLog({
946
1042
  ]
947
1043
  }
948
1044
  ),
949
- /* @__PURE__ */ jsxs4("div", { style: { flex: 1, minWidth: 0 }, children: [
950
- /* @__PURE__ */ jsx6(
1045
+ /* @__PURE__ */ jsxs5("div", { style: { flex: 1, minWidth: 0 }, children: [
1046
+ /* @__PURE__ */ jsx7(
951
1047
  "span",
952
1048
  {
953
1049
  style: {
@@ -958,7 +1054,7 @@ function NarrativeLog({
958
1054
  children: entry.label
959
1055
  }
960
1056
  ),
961
- /* @__PURE__ */ jsx6(
1057
+ /* @__PURE__ */ jsx7(
962
1058
  "div",
963
1059
  {
964
1060
  style: {
@@ -981,8 +1077,8 @@ function NarrativeLog({
981
1077
  }
982
1078
 
983
1079
  // src/components/GanttTimeline/GanttTimeline.tsx
984
- import { useMemo as useMemo5 } from "react";
985
- import { jsx as jsx7, jsxs as jsxs5 } from "react/jsx-runtime";
1080
+ import { useState as useState2, useMemo as useMemo6, useRef, useEffect } from "react";
1081
+ import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
986
1082
  function GanttTimeline({
987
1083
  snapshots,
988
1084
  selectedIndex = 0,
@@ -990,9 +1086,13 @@ function GanttTimeline({
990
1086
  size = "default",
991
1087
  unstyled = false,
992
1088
  className,
993
- style
1089
+ style,
1090
+ maxVisibleRows = 5
994
1091
  }) {
995
- const totalWallTime = useMemo5(
1092
+ const [expanded, setExpanded] = useState2(false);
1093
+ const activeRowRef = useRef(null);
1094
+ const scrollContainerRef = useRef(null);
1095
+ const totalWallTime = useMemo6(
996
1096
  () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),
997
1097
  [snapshots]
998
1098
  );
@@ -1000,8 +1100,19 @@ function GanttTimeline({
1000
1100
  const pad = padding[size];
1001
1101
  const labelWidth = size === "compact" ? 50 : size === "detailed" ? 100 : 80;
1002
1102
  const msWidth = size === "compact" ? 28 : 36;
1103
+ const rowHeight = size === "compact" ? 18 : 22;
1104
+ const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;
1105
+ const showAll = expanded || !collapsible;
1106
+ useEffect(() => {
1107
+ if (!showAll && activeRowRef.current && scrollContainerRef.current) {
1108
+ activeRowRef.current.scrollIntoView({
1109
+ block: "nearest",
1110
+ behavior: "smooth"
1111
+ });
1112
+ }
1113
+ }, [selectedIndex, showAll]);
1003
1114
  if (unstyled) {
1004
- return /* @__PURE__ */ jsx7("div", { className, style, "data-fp": "gantt-timeline", children: snapshots.map((snap, idx) => /* @__PURE__ */ jsxs5(
1115
+ return /* @__PURE__ */ jsx8("div", { className, style, "data-fp": "gantt-timeline", children: snapshots.map((snap, idx) => /* @__PURE__ */ jsxs6(
1005
1116
  "div",
1006
1117
  {
1007
1118
  "data-fp": "gantt-bar",
@@ -1009,8 +1120,8 @@ function GanttTimeline({
1009
1120
  "data-visible": idx <= selectedIndex,
1010
1121
  onClick: () => onSelect?.(idx),
1011
1122
  children: [
1012
- /* @__PURE__ */ jsx7("span", { "data-fp": "gantt-label", children: snap.stageLabel }),
1013
- /* @__PURE__ */ jsxs5("span", { "data-fp": "gantt-duration", children: [
1123
+ /* @__PURE__ */ jsx8("span", { "data-fp": "gantt-label", children: snap.stageLabel }),
1124
+ /* @__PURE__ */ jsxs6("span", { "data-fp": "gantt-duration", children: [
1014
1125
  snap.durationMs,
1015
1126
  "ms"
1016
1127
  ] })
@@ -1019,43 +1130,79 @@ function GanttTimeline({
1019
1130
  snap.stageName
1020
1131
  )) });
1021
1132
  }
1022
- return /* @__PURE__ */ jsxs5(
1133
+ return /* @__PURE__ */ jsxs6(
1023
1134
  "div",
1024
1135
  {
1025
1136
  className,
1026
1137
  style: { padding: pad, fontFamily: theme.fontSans, ...style },
1027
1138
  "data-fp": "gantt-timeline",
1028
1139
  children: [
1029
- /* @__PURE__ */ jsx7(
1030
- "span",
1140
+ /* @__PURE__ */ jsxs6(
1141
+ "div",
1031
1142
  {
1032
1143
  style: {
1033
- fontSize: fs.label,
1034
- fontWeight: 600,
1035
- color: theme.textMuted,
1036
- textTransform: "uppercase",
1037
- letterSpacing: "0.08em"
1144
+ display: "flex",
1145
+ alignItems: "center",
1146
+ justifyContent: "space-between"
1038
1147
  },
1039
- children: size === "compact" ? "Timeline" : "Execution Timeline"
1148
+ children: [
1149
+ /* @__PURE__ */ jsx8(
1150
+ "span",
1151
+ {
1152
+ style: {
1153
+ fontSize: fs.label,
1154
+ fontWeight: 600,
1155
+ color: theme.textMuted,
1156
+ textTransform: "uppercase",
1157
+ letterSpacing: "0.08em"
1158
+ },
1159
+ children: size === "compact" ? "Timeline" : "Execution Timeline"
1160
+ }
1161
+ ),
1162
+ collapsible && /* @__PURE__ */ jsx8(
1163
+ "button",
1164
+ {
1165
+ onClick: () => setExpanded((e) => !e),
1166
+ style: {
1167
+ background: "none",
1168
+ border: `1px solid ${theme.border}`,
1169
+ borderRadius: 4,
1170
+ color: theme.textSecondary,
1171
+ fontSize: fs.small,
1172
+ padding: "2px 8px",
1173
+ cursor: "pointer",
1174
+ fontFamily: theme.fontSans
1175
+ },
1176
+ children: expanded ? "Collapse" : `${snapshots.length - maxVisibleRows} more...`
1177
+ }
1178
+ )
1179
+ ]
1040
1180
  }
1041
1181
  ),
1042
- /* @__PURE__ */ jsx7(
1182
+ /* @__PURE__ */ jsx8(
1043
1183
  "div",
1044
1184
  {
1185
+ ref: scrollContainerRef,
1045
1186
  style: {
1046
1187
  marginTop: 8,
1047
1188
  display: "flex",
1048
1189
  flexDirection: "column",
1049
- gap: 4
1190
+ gap: 4,
1191
+ ...showAll ? {} : {
1192
+ maxHeight: maxVisibleRows * (rowHeight + 4),
1193
+ overflowY: "auto",
1194
+ scrollbarWidth: "thin"
1195
+ }
1050
1196
  },
1051
1197
  children: snapshots.map((snap, idx) => {
1052
1198
  const leftPct = snap.startMs / totalWallTime * 100;
1053
1199
  const widthPct = Math.max(snap.durationMs / totalWallTime * 100, 1);
1054
1200
  const isSelected = idx === selectedIndex;
1055
1201
  const isVisible = idx <= selectedIndex;
1056
- return /* @__PURE__ */ jsxs5(
1202
+ return /* @__PURE__ */ jsxs6(
1057
1203
  "div",
1058
1204
  {
1205
+ ref: isSelected ? activeRowRef : void 0,
1059
1206
  onClick: () => onSelect?.(idx),
1060
1207
  style: {
1061
1208
  display: "flex",
@@ -1063,10 +1210,12 @@ function GanttTimeline({
1063
1210
  gap: size === "compact" ? 4 : 8,
1064
1211
  cursor: onSelect ? "pointer" : "default",
1065
1212
  opacity: isVisible ? 1 : 0.3,
1066
- transition: "opacity 0.3s ease"
1213
+ transition: "opacity 0.3s ease",
1214
+ height: rowHeight,
1215
+ flexShrink: 0
1067
1216
  },
1068
1217
  children: [
1069
- /* @__PURE__ */ jsx7(
1218
+ /* @__PURE__ */ jsx8(
1070
1219
  "span",
1071
1220
  {
1072
1221
  style: {
@@ -1083,7 +1232,7 @@ function GanttTimeline({
1083
1232
  children: snap.stageLabel
1084
1233
  }
1085
1234
  ),
1086
- /* @__PURE__ */ jsx7(
1235
+ /* @__PURE__ */ jsx8(
1087
1236
  "div",
1088
1237
  {
1089
1238
  style: {
@@ -1093,7 +1242,7 @@ function GanttTimeline({
1093
1242
  background: theme.bgTertiary,
1094
1243
  borderRadius: 3
1095
1244
  },
1096
- children: isVisible && /* @__PURE__ */ jsx7(
1245
+ children: isVisible && /* @__PURE__ */ jsx8(
1097
1246
  "div",
1098
1247
  {
1099
1248
  style: {
@@ -1110,7 +1259,7 @@ function GanttTimeline({
1110
1259
  )
1111
1260
  }
1112
1261
  ),
1113
- /* @__PURE__ */ jsxs5(
1262
+ /* @__PURE__ */ jsxs6(
1114
1263
  "span",
1115
1264
  {
1116
1265
  style: {
@@ -1133,7 +1282,7 @@ function GanttTimeline({
1133
1282
  })
1134
1283
  }
1135
1284
  ),
1136
- /* @__PURE__ */ jsxs5(
1285
+ /* @__PURE__ */ jsxs6(
1137
1286
  "div",
1138
1287
  {
1139
1288
  style: {
@@ -1147,12 +1296,12 @@ function GanttTimeline({
1147
1296
  fontFamily: theme.fontMono
1148
1297
  },
1149
1298
  children: [
1150
- /* @__PURE__ */ jsx7("span", { children: "0ms" }),
1151
- size !== "compact" && /* @__PURE__ */ jsxs5("span", { children: [
1299
+ /* @__PURE__ */ jsx8("span", { children: "0ms" }),
1300
+ size !== "compact" && /* @__PURE__ */ jsxs6("span", { children: [
1152
1301
  (totalWallTime / 2).toFixed(1),
1153
1302
  "ms"
1154
1303
  ] }),
1155
- /* @__PURE__ */ jsxs5("span", { children: [
1304
+ /* @__PURE__ */ jsxs6("span", { children: [
1156
1305
  totalWallTime.toFixed(1),
1157
1306
  "ms"
1158
1307
  ] })
@@ -1165,7 +1314,7 @@ function GanttTimeline({
1165
1314
  }
1166
1315
 
1167
1316
  // src/components/TimeTravelDebugger/TimeTravelDebugger.tsx
1168
- import { jsx as jsx8, jsxs as jsxs6 } from "react/jsx-runtime";
1317
+ import { jsx as jsx9, jsxs as jsxs7 } from "react/jsx-runtime";
1169
1318
  function TimeTravelDebugger({
1170
1319
  snapshots,
1171
1320
  nodes,
@@ -1178,11 +1327,11 @@ function TimeTravelDebugger({
1178
1327
  className,
1179
1328
  style
1180
1329
  }) {
1181
- const [selectedIndex, setSelectedIndex] = useState2(0);
1330
+ const [selectedIndex, setSelectedIndex] = useState3(0);
1182
1331
  const fs = fontSize[size];
1183
1332
  const pad = padding[size];
1184
1333
  if (snapshots.length === 0) {
1185
- return /* @__PURE__ */ jsx8(
1334
+ return /* @__PURE__ */ jsx9(
1186
1335
  "div",
1187
1336
  {
1188
1337
  className,
@@ -1198,9 +1347,9 @@ function TimeTravelDebugger({
1198
1347
  }
1199
1348
  const isHorizontal = layout === "horizontal";
1200
1349
  if (unstyled) {
1201
- return /* @__PURE__ */ jsxs6("div", { className, style, "data-fp": "time-travel-debugger", children: [
1202
- /* @__PURE__ */ jsx8("h3", { children: title }),
1203
- /* @__PURE__ */ jsx8(
1350
+ return /* @__PURE__ */ jsxs7("div", { className, style, "data-fp": "time-travel-debugger", children: [
1351
+ /* @__PURE__ */ jsx9("h3", { children: title }),
1352
+ /* @__PURE__ */ jsx9(
1204
1353
  "input",
1205
1354
  {
1206
1355
  type: "range",
@@ -1210,7 +1359,7 @@ function TimeTravelDebugger({
1210
1359
  onChange: (e) => setSelectedIndex(parseInt(e.target.value))
1211
1360
  }
1212
1361
  ),
1213
- /* @__PURE__ */ jsx8(
1362
+ /* @__PURE__ */ jsx9(
1214
1363
  FlowchartView,
1215
1364
  {
1216
1365
  nodes,
@@ -1221,7 +1370,7 @@ function TimeTravelDebugger({
1221
1370
  unstyled: true
1222
1371
  }
1223
1372
  ),
1224
- /* @__PURE__ */ jsx8(
1373
+ /* @__PURE__ */ jsx9(
1225
1374
  MemoryInspector,
1226
1375
  {
1227
1376
  snapshots,
@@ -1229,7 +1378,7 @@ function TimeTravelDebugger({
1229
1378
  unstyled: true
1230
1379
  }
1231
1380
  ),
1232
- /* @__PURE__ */ jsx8(
1381
+ /* @__PURE__ */ jsx9(
1233
1382
  NarrativeLog,
1234
1383
  {
1235
1384
  snapshots,
@@ -1237,7 +1386,7 @@ function TimeTravelDebugger({
1237
1386
  unstyled: true
1238
1387
  }
1239
1388
  ),
1240
- showGantt && /* @__PURE__ */ jsx8(
1389
+ showGantt && /* @__PURE__ */ jsx9(
1241
1390
  GanttTimeline,
1242
1391
  {
1243
1392
  snapshots,
@@ -1248,7 +1397,7 @@ function TimeTravelDebugger({
1248
1397
  )
1249
1398
  ] });
1250
1399
  }
1251
- return /* @__PURE__ */ jsxs6(
1400
+ return /* @__PURE__ */ jsxs7(
1252
1401
  "div",
1253
1402
  {
1254
1403
  className,
@@ -1263,7 +1412,7 @@ function TimeTravelDebugger({
1263
1412
  },
1264
1413
  "data-fp": "time-travel-debugger",
1265
1414
  children: [
1266
- /* @__PURE__ */ jsxs6(
1415
+ /* @__PURE__ */ jsxs7(
1267
1416
  "div",
1268
1417
  {
1269
1418
  style: {
@@ -1273,7 +1422,7 @@ function TimeTravelDebugger({
1273
1422
  flexShrink: 0
1274
1423
  },
1275
1424
  children: [
1276
- /* @__PURE__ */ jsxs6(
1425
+ /* @__PURE__ */ jsxs7(
1277
1426
  "div",
1278
1427
  {
1279
1428
  style: {
@@ -1283,7 +1432,7 @@ function TimeTravelDebugger({
1283
1432
  marginBottom: 8
1284
1433
  },
1285
1434
  children: [
1286
- /* @__PURE__ */ jsx8(
1435
+ /* @__PURE__ */ jsx9(
1287
1436
  "span",
1288
1437
  {
1289
1438
  style: {
@@ -1294,7 +1443,7 @@ function TimeTravelDebugger({
1294
1443
  children: title
1295
1444
  }
1296
1445
  ),
1297
- /* @__PURE__ */ jsx8(
1446
+ /* @__PURE__ */ jsx9(
1298
1447
  "span",
1299
1448
  {
1300
1449
  style: {
@@ -1307,8 +1456,8 @@ function TimeTravelDebugger({
1307
1456
  ]
1308
1457
  }
1309
1458
  ),
1310
- /* @__PURE__ */ jsxs6("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1311
- /* @__PURE__ */ jsx8(
1459
+ /* @__PURE__ */ jsxs7("div", { style: { display: "flex", alignItems: "center", gap: 8 }, children: [
1460
+ /* @__PURE__ */ jsx9(
1312
1461
  ScrubButton,
1313
1462
  {
1314
1463
  label: "\\u25C0",
@@ -1316,7 +1465,7 @@ function TimeTravelDebugger({
1316
1465
  onClick: () => setSelectedIndex((i) => Math.max(0, i - 1))
1317
1466
  }
1318
1467
  ),
1319
- /* @__PURE__ */ jsx8(
1468
+ /* @__PURE__ */ jsx9(
1320
1469
  "input",
1321
1470
  {
1322
1471
  type: "range",
@@ -1332,7 +1481,7 @@ function TimeTravelDebugger({
1332
1481
  }
1333
1482
  }
1334
1483
  ),
1335
- /* @__PURE__ */ jsx8(
1484
+ /* @__PURE__ */ jsx9(
1336
1485
  ScrubButton,
1337
1486
  {
1338
1487
  label: "\\u25B6",
@@ -1340,7 +1489,7 @@ function TimeTravelDebugger({
1340
1489
  onClick: () => setSelectedIndex((i) => Math.min(snapshots.length - 1, i + 1))
1341
1490
  }
1342
1491
  ),
1343
- /* @__PURE__ */ jsxs6(
1492
+ /* @__PURE__ */ jsxs7(
1344
1493
  "span",
1345
1494
  {
1346
1495
  style: {
@@ -1360,7 +1509,7 @@ function TimeTravelDebugger({
1360
1509
  ]
1361
1510
  }
1362
1511
  ),
1363
- /* @__PURE__ */ jsxs6(
1512
+ /* @__PURE__ */ jsxs7(
1364
1513
  "div",
1365
1514
  {
1366
1515
  style: {
@@ -1370,7 +1519,7 @@ function TimeTravelDebugger({
1370
1519
  overflow: "hidden"
1371
1520
  },
1372
1521
  children: [
1373
- /* @__PURE__ */ jsx8(
1522
+ /* @__PURE__ */ jsx9(
1374
1523
  "div",
1375
1524
  {
1376
1525
  style: {
@@ -1379,7 +1528,7 @@ function TimeTravelDebugger({
1379
1528
  borderRight: isHorizontal ? `1px solid ${theme.border}` : "none",
1380
1529
  borderBottom: !isHorizontal ? `1px solid ${theme.border}` : "none"
1381
1530
  },
1382
- children: /* @__PURE__ */ jsx8(
1531
+ children: /* @__PURE__ */ jsx9(
1383
1532
  FlowchartView,
1384
1533
  {
1385
1534
  nodes,
@@ -1392,8 +1541,8 @@ function TimeTravelDebugger({
1392
1541
  )
1393
1542
  }
1394
1543
  ),
1395
- /* @__PURE__ */ jsxs6("div", { style: { flex: 1, overflow: "auto" }, children: [
1396
- /* @__PURE__ */ jsx8(
1544
+ /* @__PURE__ */ jsxs7("div", { style: { flex: 1, overflow: "auto" }, children: [
1545
+ /* @__PURE__ */ jsx9(
1397
1546
  MemoryInspector,
1398
1547
  {
1399
1548
  snapshots,
@@ -1401,7 +1550,7 @@ function TimeTravelDebugger({
1401
1550
  size
1402
1551
  }
1403
1552
  ),
1404
- /* @__PURE__ */ jsx8(
1553
+ /* @__PURE__ */ jsx9(
1405
1554
  "div",
1406
1555
  {
1407
1556
  style: {
@@ -1411,7 +1560,7 @@ function TimeTravelDebugger({
1411
1560
  }
1412
1561
  }
1413
1562
  ),
1414
- /* @__PURE__ */ jsx8(
1563
+ /* @__PURE__ */ jsx9(
1415
1564
  NarrativeLog,
1416
1565
  {
1417
1566
  snapshots,
@@ -1423,7 +1572,7 @@ function TimeTravelDebugger({
1423
1572
  ]
1424
1573
  }
1425
1574
  ),
1426
- showGantt && /* @__PURE__ */ jsx8(
1575
+ showGantt && /* @__PURE__ */ jsx9(
1427
1576
  "div",
1428
1577
  {
1429
1578
  style: {
@@ -1431,7 +1580,7 @@ function TimeTravelDebugger({
1431
1580
  background: theme.bgSecondary,
1432
1581
  flexShrink: 0
1433
1582
  },
1434
- children: /* @__PURE__ */ jsx8(
1583
+ children: /* @__PURE__ */ jsx9(
1435
1584
  GanttTimeline,
1436
1585
  {
1437
1586
  snapshots,
@@ -1451,7 +1600,7 @@ function ScrubButton({
1451
1600
  disabled,
1452
1601
  onClick
1453
1602
  }) {
1454
- return /* @__PURE__ */ jsx8(
1603
+ return /* @__PURE__ */ jsx9(
1455
1604
  "button",
1456
1605
  {
1457
1606
  onClick,
@@ -1480,6 +1629,7 @@ export {
1480
1629
  StageNode,
1481
1630
  SubflowBreadcrumb,
1482
1631
  TimeTravelDebugger,
1632
+ TracedFlowchartView,
1483
1633
  specToReactFlow,
1484
1634
  useSubflowNavigation
1485
1635
  };