import { useRef, useState, type ReactNode } from 'react'; import clsx from 'clsx'; import Card from '../Card/index.js'; import WindowBar from '../WindowBar/index.js'; import { useMeasuredHeight } from '../../hooks/useMeasuredHeight.js'; import styles from './styles.module.css'; export interface WindowPanelTab { label: string; /** Panel body for this tab. */ content: ReactNode; /** Skip the default padded body wrapper — for a full-bleed child (e.g. a bare CodeBlock). */ bare?: boolean; } export interface WindowPanelProps { tabs: WindowPanelTab[]; /** aria-labels for the collapse toggle (passed in so the component stays i18n-free). */ collapseLabel: string; expandLabel: string; /** Extra title-bar content between the tabs and the collapse toggle, e.g. code size. */ toolbar?: (activeIndex: number, open: boolean) => ReactNode; /** Which tab the collapse toggle re-opens: the first, or the last one viewed. */ expandTo?: 'first' | 'last'; } // A WindowBar tab strip over a collapsible viewport whose height // animates to the measured content. Clicking the active tab collapses it. export default function WindowPanel({ tabs, collapseLabel, expandLabel, toolbar, expandTo = 'first', }: WindowPanelProps) { const [active, setActive] = useState(0); // Hold the last opened tab so its content stays visible mid-collapse. const lastIdx = useRef(0); if (active !== null) lastIdx.current = active; const open = active !== null; const shownIdx = active ?? lastIdx.current; const shown = tabs[shownIdx]; const [contentRef, contentHeight] = useMeasuredHeight(active); return (
{tabs.map((t, i) => ( ))}
{toolbar?.(shownIdx, open)}
{shown.bare ? shown.content :
{shown.content}
}
); }