@kud/gh-ink 0.14.0 → 0.15.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.
Files changed (2) hide show
  1. package/dist/index.js +63 -18
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -607,7 +607,7 @@ var healthLegend = [
607
607
  ["closed", "Closed"]
608
608
  ];
609
609
  var CACHE_TTL_MS = 12e4;
610
- var CACHE_VERSION = 1;
610
+ var CACHE_VERSION = 2;
611
611
  var cacheDir = () => join(process.env.XDG_CACHE_HOME || join(homedir(), ".cache"), "ambre");
612
612
  var cacheFile = (key) => join(cacheDir(), `${key.replace(/[^a-z0-9._-]/gi, "-")}.json`);
613
613
  var readCache = (key) => {
@@ -733,6 +733,15 @@ var transientOf = (transients, item) => {
733
733
  const key = keyOf(item);
734
734
  return key ? transients.get(key) : void 0;
735
735
  };
736
+ var tabsOfMarks = (sections, marks) => {
737
+ const out = /* @__PURE__ */ new Map();
738
+ for (const section of sections)
739
+ for (const item of section.items) {
740
+ const key = keyOf(item);
741
+ if (key && marks.has(key)) out.set(key, section.id);
742
+ }
743
+ return out;
744
+ };
736
745
  var quietly = $({ quiet: true });
737
746
  var relativeTime = (iso) => {
738
747
  const diff = (Date.now() - new Date(iso).getTime()) / 1e3;
@@ -1947,7 +1956,8 @@ var BrowseScreen = ({
1947
1956
  initialIncludeWork,
1948
1957
  brand,
1949
1958
  mergedUrls,
1950
- transients
1959
+ transients,
1960
+ onTabChange
1951
1961
  }) => {
1952
1962
  const { rows } = useWindowSize();
1953
1963
  const [includeWork, setIncludeWork] = useState(
@@ -1963,6 +1973,9 @@ var BrowseScreen = ({
1963
1973
  const [viewStarts, setViewStarts] = useState({});
1964
1974
  const safeTabIdx = Math.min(tabIdx, Math.max(0, localSections.length - 1));
1965
1975
  const activeId = localSections[safeTabIdx]?.id ?? "";
1976
+ useEffect(() => {
1977
+ onTabChange?.(activeId);
1978
+ }, [activeId]);
1966
1979
  const [flash, setFlash] = useState(null);
1967
1980
  const menu = useActionMenu();
1968
1981
  const [search, setSearch] = useState(null);
@@ -2038,7 +2051,7 @@ var BrowseScreen = ({
2038
2051
  setTimeout(() => setFlash(null), 2e3);
2039
2052
  };
2040
2053
  const [sparkFrame, setSparkFrame] = useState(0);
2041
- const sparkling = (mergedUrls?.length ?? 0) > 0 || (transients?.size ?? 0) > 0;
2054
+ const sparkling = (mergedUrls?.length ?? 0) > 0 || !!transients?.size && section.items.some((item) => transientOf(transients, item));
2042
2055
  useEffect(() => {
2043
2056
  if (!sparkling) return;
2044
2057
  const id = setInterval(() => setSparkFrame((f) => f + 1), MERGED_FRAME_MS);
@@ -2515,13 +2528,8 @@ var App = ({
2515
2528
  const displayedKey = useRef("");
2516
2529
  const displayedSections = useRef([]);
2517
2530
  const [transients, setTransients] = useState(NO_TRANSIENTS);
2518
- const transitTimer = useRef(null);
2519
- useEffect(
2520
- () => () => {
2521
- if (transitTimer.current) clearTimeout(transitTimer.current);
2522
- },
2523
- []
2524
- );
2531
+ const transitTabs = useRef(/* @__PURE__ */ new Map());
2532
+ const [visibleTab, setVisibleTab] = useState("");
2525
2533
  const showData = (sections, login) => {
2526
2534
  const before = displayedSections.current;
2527
2535
  displayedSections.current = sections;
@@ -2529,25 +2537,61 @@ var App = ({
2529
2537
  setPending(null);
2530
2538
  setFetchedAt(Date.now());
2531
2539
  if (before.length === 0) {
2540
+ transitTabs.current = /* @__PURE__ */ new Map();
2532
2541
  setTransients(NO_TRANSIENTS);
2533
2542
  setState({ phase: "browse", sections, login });
2534
2543
  return;
2535
2544
  }
2536
- const { transients: marks, union } = diffSections(before, sections);
2545
+ const { transients: fresh, union } = diffSections(before, sections);
2546
+ const marks = new Map(fresh);
2547
+ for (const [key, mark] of transients)
2548
+ if (!marks.has(key)) marks.set(key, mark);
2549
+ const tabs = tabsOfMarks(union, marks);
2550
+ for (const key of [...marks.keys()]) if (!tabs.has(key)) marks.delete(key);
2537
2551
  if (marks.size === 0) {
2552
+ transitTabs.current = /* @__PURE__ */ new Map();
2553
+ setTransients(NO_TRANSIENTS);
2538
2554
  setState({ phase: "browse", sections, login });
2539
2555
  return;
2540
2556
  }
2557
+ transitTabs.current = tabs;
2541
2558
  setTransients(marks);
2542
2559
  setState({ phase: "browse", sections: union, login });
2543
- if (transitTimer.current) clearTimeout(transitTimer.current);
2544
- transitTimer.current = setTimeout(() => {
2545
- setTransients(NO_TRANSIENTS);
2546
- setState(
2547
- (prev) => prev.phase === "browse" && prev.sections === union ? { ...prev, sections } : prev
2548
- );
2549
- }, TRANSIT_HOLD_MS);
2550
2560
  };
2561
+ const settleTab = (tabId, marks) => {
2562
+ const keys = [...transitTabs.current].filter(([, tab]) => tab === tabId).map(([key]) => key);
2563
+ for (const key of keys) transitTabs.current.delete(key);
2564
+ const gone = new Set(keys.filter((key) => marks.get(key) === "out"));
2565
+ setTransients((prev) => {
2566
+ const next = new Map(prev);
2567
+ for (const key of keys) next.delete(key);
2568
+ return next.size === 0 ? NO_TRANSIENTS : next;
2569
+ });
2570
+ setState(
2571
+ (prev) => prev.phase !== "browse" ? prev : {
2572
+ ...prev,
2573
+ sections: prev.sections.map(
2574
+ (section) => section.id !== tabId ? section : {
2575
+ ...section,
2576
+ items: section.items.filter((item) => {
2577
+ const key = keyOf(item);
2578
+ return !(key && gone.has(key));
2579
+ })
2580
+ }
2581
+ )
2582
+ }
2583
+ );
2584
+ };
2585
+ useEffect(() => {
2586
+ if (transients.size === 0) return;
2587
+ if (state.phase !== "browse" || !visibleTab) return;
2588
+ if (![...transitTabs.current.values()].includes(visibleTab)) return;
2589
+ const timer = setTimeout(
2590
+ () => settleTab(visibleTab, transients),
2591
+ TRANSIT_HOLD_MS
2592
+ );
2593
+ return () => clearTimeout(timer);
2594
+ }, [transients, visibleTab, state.phase]);
2551
2595
  const pendingSummary = useMemo(
2552
2596
  () => pending ? summariseDiff(
2553
2597
  diffSections(displayedSections.current, pending.sections).counts
@@ -2732,6 +2776,7 @@ var App = ({
2732
2776
  hidden: overlay !== null,
2733
2777
  mergedUrls,
2734
2778
  transients,
2779
+ onTabChange: setVisibleTab,
2735
2780
  ciStatusState: hasCiStatus ? ciStatusState : void 0,
2736
2781
  ciJob,
2737
2782
  tabHelp,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kud/gh-ink",
3
- "version": "0.14.0",
3
+ "version": "0.15.0",
4
4
  "description": "Ink components for rendering GitHub PR review comments and health — controlled, presentation-only, built on @kud/ink-ui and fed by @kud/gh.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",