"use client"; import type { ReactNode, MouseEvent } from "react"; import { Fragment } from "react"; import { Tabs, TabsList, TabsTrigger } from "@kandev/ui/tabs"; export type SessionTab = { id: string; label: string; icon?: ReactNode; /** Optional badge rendered before the label — e.g. "#3" for an ordinary terminal. */ badge?: ReactNode; closable?: boolean; alwaysShowClose?: boolean; onClose?: (event: MouseEvent) => void; onContextMenu?: (event: MouseEvent) => void; onDoubleClick?: (event: MouseEvent) => void; className?: string; testId?: string; closeTestId?: string; /** When true (default) keeps the existing 120px max-width; ordinary terminals with custom names benefit from `false`. */ truncate?: boolean; }; type SessionTabsProps = { children?: ReactNode; // TabsContent elements (optional for cases where tabs are just visible) tabs: SessionTab[]; activeTab: string; onTabChange: (tabId: string) => void; showAddButton?: boolean; onAddTab?: () => void; addButtonLabel?: string; separatorAfterIndex?: number; className?: string; /** Overrides the default `TabsList` className — use to drop the pill background, etc. */ listClassName?: string; // Collapse support collapsible?: boolean; isCollapsed?: boolean; onToggleCollapse?: () => void; // Right content (e.g., approve button) rightContent?: ReactNode; }; const SVG_PROPS = { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round" as const, strokeLinejoin: "round" as const, }; function CloseIcon() { return ( ); } function CollapseIcon({ isCollapsed }: { isCollapsed: boolean }) { return ( {isCollapsed ? : } ); } function SessionTabItem({ tab, index, separatorAfterIndex, }: { tab: SessionTab; index: number; separatorAfterIndex?: number; }) { return ( {separatorAfterIndex !== undefined && index === separatorAfterIndex + 1 && (
)} {tab.icon} {tab.badge && ( {tab.badge} )} {tab.label} {tab.closable && tab.onClose && ( )} ); } function SessionTabsHeader({ tabsList, collapsible, isCollapsed, onToggleCollapse, rightContent, hasChildren, }: { tabsList: ReactNode; collapsible: boolean; isCollapsed: boolean; onToggleCollapse?: () => void; rightContent?: ReactNode; hasChildren: boolean; }) { if (collapsible && onToggleCollapse) { return (
{tabsList}
{rightContent}
); } if (rightContent) { return (
{tabsList}
{rightContent}
); } return <>{tabsList}; } export function SessionTabs({ children, tabs, activeTab, onTabChange, showAddButton = false, onAddTab, addButtonLabel = "+", separatorAfterIndex, className, listClassName, collapsible = false, isCollapsed = false, onToggleCollapse, rightContent, }: SessionTabsProps) { const defaultListClassName = "p-0 !h-7 rounded-sm overflow-x-auto overflow-y-hidden min-w-0 shrink [&::-webkit-scrollbar]:hidden [-ms-overflow-style:none] [scrollbar-width:none]"; const tabsList = ( {tabs.map((tab, index) => ( ))} {showAddButton && onAddTab && ( )} ); return ( {children} ); }