import { useLayoutEffect, useMemo, useRef, useState } from "react"; interface UseMountedTabSetInput { activeTabId: string | null; allTabIds: string[]; cap: number; } interface UseMountedTabSetResult { mountedTabIds: Set; } function createInitialMountedTabIds(input: UseMountedTabSetInput): Set { if (!input.activeTabId || !input.allTabIds.includes(input.activeTabId)) { return new Set(); } return new Set([input.activeTabId]); } function setsEqual(left: Set, right: Set): boolean { if (left.size !== right.size) { return false; } for (const value of left) { if (!right.has(value)) { return false; } } return true; } export function useMountedTabSet(input: UseMountedTabSetInput): UseMountedTabSetResult { const { activeTabId, allTabIds, cap } = input; const allTabIdsKey = allTabIds.join("\u0000"); const availableTabIds = useMemo(() => new Set(allTabIds), [allTabIdsKey]); const [mountedTabIds, setMountedTabIds] = useState(() => createInitialMountedTabIds(input)); const lruRef = useRef( activeTabId && allTabIds.includes(activeTabId) ? [activeTabId] : [], ); useLayoutEffect(() => { const nextLru = lruRef.current.filter((tabId) => availableTabIds.has(tabId)); if (activeTabId && availableTabIds.has(activeTabId)) { const existingIndex = nextLru.indexOf(activeTabId); if (existingIndex >= 0) { nextLru.splice(existingIndex, 1); } nextLru.unshift(activeTabId); } if (nextLru.length > cap) { nextLru.length = cap; } lruRef.current = nextLru; setMountedTabIds((previousMountedTabIds) => { const nextMountedTabIds = new Set(nextLru); return setsEqual(previousMountedTabIds, nextMountedTabIds) ? previousMountedTabIds : nextMountedTabIds; }); }, [activeTabId, availableTabIds, cap]); return { mountedTabIds }; }