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/index.js CHANGED
@@ -644,7 +644,7 @@ function NarrativeTrace({
644
644
  }
645
645
 
646
646
  // src/components/GanttTimeline/GanttTimeline.tsx
647
- import { useMemo as useMemo4 } from "react";
647
+ import { useState as useState2, useMemo as useMemo4, useRef as useRef2, useEffect as useEffect2 } from "react";
648
648
  import { jsx as jsx5, jsxs as jsxs4 } from "react/jsx-runtime";
649
649
  function GanttTimeline({
650
650
  snapshots,
@@ -653,8 +653,12 @@ function GanttTimeline({
653
653
  size = "default",
654
654
  unstyled = false,
655
655
  className,
656
- style
656
+ style,
657
+ maxVisibleRows = 5
657
658
  }) {
659
+ const [expanded, setExpanded] = useState2(false);
660
+ const activeRowRef = useRef2(null);
661
+ const scrollContainerRef = useRef2(null);
658
662
  const totalWallTime = useMemo4(
659
663
  () => Math.max(...snapshots.map((s) => s.startMs + s.durationMs), 1),
660
664
  [snapshots]
@@ -663,6 +667,17 @@ function GanttTimeline({
663
667
  const pad = padding[size];
664
668
  const labelWidth = size === "compact" ? 50 : size === "detailed" ? 100 : 80;
665
669
  const msWidth = size === "compact" ? 28 : 36;
670
+ const rowHeight = size === "compact" ? 18 : 22;
671
+ const collapsible = maxVisibleRows > 0 && snapshots.length > maxVisibleRows;
672
+ const showAll = expanded || !collapsible;
673
+ useEffect2(() => {
674
+ if (!showAll && activeRowRef.current && scrollContainerRef.current) {
675
+ activeRowRef.current.scrollIntoView({
676
+ block: "nearest",
677
+ behavior: "smooth"
678
+ });
679
+ }
680
+ }, [selectedIndex, showAll]);
666
681
  if (unstyled) {
667
682
  return /* @__PURE__ */ jsx5("div", { className, style, "data-fp": "gantt-timeline", children: snapshots.map((snap, idx) => /* @__PURE__ */ jsxs4(
668
683
  "div",
@@ -689,27 +704,62 @@ function GanttTimeline({
689
704
  style: { padding: pad, fontFamily: theme.fontSans, ...style },
690
705
  "data-fp": "gantt-timeline",
691
706
  children: [
692
- /* @__PURE__ */ jsx5(
693
- "span",
707
+ /* @__PURE__ */ jsxs4(
708
+ "div",
694
709
  {
695
710
  style: {
696
- fontSize: fs.label,
697
- fontWeight: 600,
698
- color: theme.textMuted,
699
- textTransform: "uppercase",
700
- letterSpacing: "0.08em"
711
+ display: "flex",
712
+ alignItems: "center",
713
+ justifyContent: "space-between"
701
714
  },
702
- children: size === "compact" ? "Timeline" : "Execution Timeline"
715
+ children: [
716
+ /* @__PURE__ */ jsx5(
717
+ "span",
718
+ {
719
+ style: {
720
+ fontSize: fs.label,
721
+ fontWeight: 600,
722
+ color: theme.textMuted,
723
+ textTransform: "uppercase",
724
+ letterSpacing: "0.08em"
725
+ },
726
+ children: size === "compact" ? "Timeline" : "Execution Timeline"
727
+ }
728
+ ),
729
+ collapsible && /* @__PURE__ */ jsx5(
730
+ "button",
731
+ {
732
+ onClick: () => setExpanded((e) => !e),
733
+ style: {
734
+ background: "none",
735
+ border: `1px solid ${theme.border}`,
736
+ borderRadius: 4,
737
+ color: theme.textSecondary,
738
+ fontSize: fs.small,
739
+ padding: "2px 8px",
740
+ cursor: "pointer",
741
+ fontFamily: theme.fontSans
742
+ },
743
+ children: expanded ? "Collapse" : `${snapshots.length - maxVisibleRows} more...`
744
+ }
745
+ )
746
+ ]
703
747
  }
704
748
  ),
705
749
  /* @__PURE__ */ jsx5(
706
750
  "div",
707
751
  {
752
+ ref: scrollContainerRef,
708
753
  style: {
709
754
  marginTop: 8,
710
755
  display: "flex",
711
756
  flexDirection: "column",
712
- gap: 4
757
+ gap: 4,
758
+ ...showAll ? {} : {
759
+ maxHeight: maxVisibleRows * (rowHeight + 4),
760
+ overflowY: "auto",
761
+ scrollbarWidth: "thin"
762
+ }
713
763
  },
714
764
  children: snapshots.map((snap, idx) => {
715
765
  const leftPct = snap.startMs / totalWallTime * 100;
@@ -719,6 +769,7 @@ function GanttTimeline({
719
769
  return /* @__PURE__ */ jsxs4(
720
770
  "div",
721
771
  {
772
+ ref: isSelected ? activeRowRef : void 0,
722
773
  onClick: () => onSelect?.(idx),
723
774
  style: {
724
775
  display: "flex",
@@ -726,7 +777,9 @@ function GanttTimeline({
726
777
  gap: size === "compact" ? 4 : 8,
727
778
  cursor: onSelect ? "pointer" : "default",
728
779
  opacity: isVisible ? 1 : 0.3,
729
- transition: "opacity 0.3s ease"
780
+ transition: "opacity 0.3s ease",
781
+ height: rowHeight,
782
+ flexShrink: 0
730
783
  },
731
784
  children: [
732
785
  /* @__PURE__ */ jsx5(
@@ -828,7 +881,7 @@ function GanttTimeline({
828
881
  }
829
882
 
830
883
  // src/components/SnapshotPanel/SnapshotPanel.tsx
831
- import { useState as useState2 } from "react";
884
+ import { useState as useState3 } from "react";
832
885
  import { jsx as jsx6, jsxs as jsxs5 } from "react/jsx-runtime";
833
886
  function SnapshotPanel({
834
887
  snapshots,
@@ -840,7 +893,7 @@ function SnapshotPanel({
840
893
  className,
841
894
  style
842
895
  }) {
843
- const [selectedIndex, setSelectedIndex] = useState2(0);
896
+ const [selectedIndex, setSelectedIndex] = useState3(0);
844
897
  const fs = fontSize[size];
845
898
  const pad = padding[size];
846
899
  if (snapshots.length === 0) {
@@ -1331,7 +1384,7 @@ function ResultPanel({
1331
1384
  }
1332
1385
 
1333
1386
  // src/components/TimeTravelControls/TimeTravelControls.tsx
1334
- import { useState as useState3, useEffect as useEffect2, useRef as useRef2, useCallback as useCallback2 } from "react";
1387
+ import { useState as useState4, useEffect as useEffect3, useRef as useRef3, useCallback as useCallback2 } from "react";
1335
1388
  import { jsx as jsx9, jsxs as jsxs8 } from "react/jsx-runtime";
1336
1389
  function TimeTravelControls({
1337
1390
  snapshots,
@@ -1343,12 +1396,12 @@ function TimeTravelControls({
1343
1396
  className,
1344
1397
  style
1345
1398
  }) {
1346
- const [playing, setPlaying] = useState3(false);
1347
- const playRef = useRef2(null);
1399
+ const [playing, setPlaying] = useState4(false);
1400
+ const playRef = useRef3(null);
1348
1401
  const total = snapshots.length;
1349
1402
  const canPrev = selectedIndex > 0;
1350
1403
  const canNext = selectedIndex < total - 1;
1351
- useEffect2(() => {
1404
+ useEffect3(() => {
1352
1405
  if (!playing || !autoPlayable) return;
1353
1406
  if (selectedIndex >= total - 1) {
1354
1407
  setPlaying(false);
@@ -1535,7 +1588,7 @@ function TimeTravelControls({
1535
1588
  }
1536
1589
 
1537
1590
  // src/components/ExplainableShell/ExplainableShell.tsx
1538
- import { useState as useState4, useCallback as useCallback3, useMemo as useMemo6 } from "react";
1591
+ import { useState as useState5, useCallback as useCallback3, useMemo as useMemo6 } from "react";
1539
1592
  import { Fragment as Fragment2, jsx as jsx10, jsxs as jsxs9 } from "react/jsx-runtime";
1540
1593
  function ExplainableShell({
1541
1594
  snapshots,
@@ -1551,8 +1604,8 @@ function ExplainableShell({
1551
1604
  className,
1552
1605
  style
1553
1606
  }) {
1554
- const [activeTab, setActiveTab] = useState4(defaultTab ?? tabs[0]);
1555
- const [snapshotIdx, setSnapshotIdx] = useState4(0);
1607
+ const [activeTab, setActiveTab] = useState5(defaultTab ?? tabs[0]);
1608
+ const [snapshotIdx, setSnapshotIdx] = useState5(0);
1556
1609
  const fs = fontSize[size];
1557
1610
  const pad = padding[size];
1558
1611
  const handleSnapshotChange = useCallback3((idx) => {