All files Tabs.tsx

100% Statements 52/52
100% Branches 15/15
100% Functions 6/6
100% Lines 52/52

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 1062x 2x               6x 6x   6x 1x 1x   6x 6x 6x     6x 6x 6x     6x             5x 5x 5x 5x 5x 5x     5x     5x               16x 16x 16x 2x 2x   13x 13x   13x 13x 13x 13x 13x 4x 9x 16x 16x   16x   16x     16x               16x 16x 16x 2x 2x   13x   16x   4x 4x             2x   1x  
import * as React from 'react';
import { cn } from '../lib/utils';
 
type TabsProps = {
  className?: string;
  children: React.ReactNode;
  defaultValue?: string;
};
 
function Tabs({ className, children, defaultValue }: TabsProps) {
  const [activeTab, setActiveTab] = React.useState(defaultValue);
 
  const handleTabChange = (value: string) => {
    setActiveTab(value);
  };
 
  const contextValue = React.useMemo(
    () => ({ activeTab, onChange: handleTabChange }),
    [activeTab]
  );
 
  return (
    <TabsContext.Provider value={contextValue}>
      <div className={cn('flex flex-col gap-2', className)}>{children}</div>
    </TabsContext.Provider>
  );
}
 
type TabsListProps = {
  className?: string;
  children: React.ReactNode;
};
 
function TabsList({ className, children }: TabsListProps) {
  return (
    <div
      className={cn(
        'bg-muted inline-flex h-9 w-fit items-center justify-center rounded-lg p-[3px]',
        className
      )}
    >
      {children}
    </div>
  );
}
 
type TabsTriggerProps = {
  className?: string;
  value: string;
  children: React.ReactNode;
};
 
function TabsTrigger({ className, value, children }: TabsTriggerProps) {
  const context = React.useContext(TabsContext);
  if (!context) {
    throw new Error('TabsTrigger must be used within a Tabs component');
  }
 
  const { activeTab, onChange } = context;
  const isActive = activeTab === value;
 
  return (
    <button
      className={cn(
        'inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md px-2 py-1 text-sm font-medium transition-[color,box-shadow]',
        isActive
          ? 'bg-background text-foreground shadow-sm'
          : 'text-muted-foreground',
        'focus-visible:ring-[3px] focus-visible:outline-ring disabled:pointer-events-none disabled:opacity-50',
        className
      )}
      onClick={() => onChange(value)}
    >
      {children}
    </button>
  );
}
 
type TabsContentProps = {
  className?: string;
  value: string;
  children: React.ReactNode;
};
 
function TabsContent({ className, value, children }: TabsContentProps) {
  const context = React.useContext(TabsContext);
  if (!context) {
    throw new Error('TabsContent must be used within a Tabs component');
  }
 
  const { activeTab } = context;
 
  if (activeTab !== value) return null;
 
  return <div className={cn('flex-1 outline-none', className)}>{children}</div>;
}
 
type TabsContextType = {
  activeTab: string | undefined;
  onChange: (value: string) => void;
};
 
const TabsContext = React.createContext<TabsContextType | undefined>(undefined);
 
export { Tabs, TabsList, TabsTrigger, TabsContent };