import * as React from 'react'; import { X, type LucideIcon } from 'lucide-react'; import { cn } from '@/lib/utils'; import { Sheet, SheetContent, SheetTitle, SheetDescription } from '@/components/ui/sheet'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Button } from '@/components/ui/button'; const KICKER_CLASS = 'font-mono text-[10px] uppercase tracking-[0.22em]'; const CRUMB_CLASS = `${KICKER_CLASS} text-stat-subtitle`; type SystemSheetSize = 'sm' | 'md' | 'lg' | 'xl'; const SIZE_CLASS: Record = { sm: 'sm:max-w-[420px]', md: 'sm:max-w-[560px]', lg: 'sm:max-w-[720px]', xl: 'sm:max-w-[960px]', }; export interface SystemSheetAction { label: React.ReactNode; onClick: () => void; disabled?: boolean; icon?: LucideIcon; } export interface SystemSheetTab { id: string; label: string; count?: number; } export interface SystemSheetProps { open: boolean; onOpenChange: (open: boolean) => void; // Header crumb: string[]; name: React.ReactNode; meta?: React.ReactNode; // Toolbar band (omit entirely when no actions provided) primaryAction?: SystemSheetAction; secondaryActions?: SystemSheetAction[]; destructiveAction?: SystemSheetAction; // Tabs band (omit entirely when undefined) tabs?: SystemSheetTab[]; activeTab?: string; onTabChange?: (id: string) => void; // Footer freshness band (omit entirely when undefined) footerContext?: React.ReactNode; size?: SystemSheetSize; children?: React.ReactNode; } export function SystemSheet({ open, onOpenChange, crumb, name, meta, primaryAction, secondaryActions, destructiveAction, tabs, activeTab, onTabChange, footerContext, size = 'md', children, }: SystemSheetProps) { const hasToolbar = !!(primaryAction || (secondaryActions && secondaryActions.length > 0) || destructiveAction); const hasTabs = !!(tabs && tabs.length > 0); const hasFooter = footerContext !== undefined && footerContext !== null; return ( {crumb.join(' › ')} onOpenChange(false)} /> {hasToolbar && ( )} {hasTabs && ( )}
{children}
{hasFooter && }
); } interface SheetHeaderBandProps { crumb: string[]; name: React.ReactNode; meta?: React.ReactNode; onDismiss: () => void; } function SheetHeaderBand({ crumb, name, meta, onDismiss }: SheetHeaderBandProps) { const lastIdx = crumb.length - 1; return (
{name} {meta && (
{meta}
)}
); } function CloseSlot({ onDismiss }: { onDismiss: () => void }) { return (
ESC
); } interface ToolbarBandProps { primary?: SystemSheetAction; secondaries?: SystemSheetAction[]; destructive?: SystemSheetAction; } function ToolbarBand({ primary, secondaries, destructive }: ToolbarBandProps) { return (
{primary && ( )} {secondaries?.map((action, idx) => ( ))} {destructive && ( )}
); } interface TabsBandProps { tabs: SystemSheetTab[]; activeTab: string; onTabChange?: (id: string) => void; } function TabsBand({ tabs, activeTab, onTabChange }: TabsBandProps) { return (
{tabs.map((tab) => { const isActive = tab.id === activeTab; return ( ); })}
); } function FooterBand({ context }: { context: React.ReactNode }) { return (
{context}
); } export interface SheetSectionProps { title: string; /** Hide the title rule + label (useful when a section is the only one in a tab). */ hideHeader?: boolean; className?: string; children: React.ReactNode; } export function SheetSection({ title, hideHeader, className, children }: SheetSectionProps) { return (
{!hideHeader && (

{title}

)} {children}
); }