/ src / components / ui / tabs.tsx
tabs.tsx
  1  import * as TabsPrimitive from "@radix-ui/react-tabs";
  2  import * as React from "react";
  3  
  4  import { VariantProps, cva } from "class-variance-authority";
  5  import { cn } from "../../lib/utils";
  6  
  7  const Tabs = TabsPrimitive.Root;
  8  
  9  const tabsListVariants = cva(
 10    "inline-flex items-center justify-center px-1 bg-gray-500/10",
 11    {
 12      variants: {
 13        color: {
 14          primary: "text-primary",
 15          secondary: "text-secondary",
 16          error: "text-error",
 17          success: "text-success",
 18          warning: "text-warning",
 19          info: "text-info",
 20          muted: "bg-gray-500",
 21        },
 22        round: {
 23          none: "rounded-none",
 24          both: "rounded-full",
 25          left: "rounded-l-full",
 26          right: "rounded-r-full",
 27          t: "rounded-t",
 28          b: "rounded-b",
 29          tl: "rounded-tl",
 30          tr: "rounded-tr",
 31          bl: "rounded-bl",
 32          br: "rounded-br",
 33        },
 34        radius: {
 35          full: "rounded-full",
 36          xs: "rounded-[2px]",
 37          sm: "rounded-[4px]",
 38          md: "rounded-[6px]",
 39          lg: "rounded-[8px]",
 40          xl: "rounded-[12px]",
 41        },
 42        size: {
 43          xs: "h-4",
 44          sm: "h-6",
 45          md: "h-7",
 46          lg: "px-1.5 h-9",
 47          xl: "px-2 h-10",
 48        },
 49      },
 50      defaultVariants: {
 51        size: "md",
 52        radius: "md",
 53        round: "both",
 54        color: "primary",
 55      },
 56    },
 57  );
 58  
 59  export interface TabsListProps
 60    extends Omit<
 61        React.ComponentPropsWithoutRef<typeof TabsPrimitive.List>,
 62        "color"
 63      >,
 64      VariantProps<typeof tabsListVariants> {}
 65  
 66  const TabsList = React.forwardRef<
 67    React.ElementRef<typeof TabsPrimitive.List>,
 68    TabsListProps
 69  >(({ className, size, round, radius, color, ...props }, ref) => (
 70    <TabsPrimitive.List
 71      ref={ref}
 72      className={cn(
 73        tabsListVariants({
 74          color,
 75          round,
 76          radius,
 77          size,
 78        }),
 79        size !== "xs" && `rounded-${round}-${size}`,
 80        className,
 81      )}
 82      {...props}
 83    />
 84  ));
 85  TabsList.displayName = TabsPrimitive.List.displayName;
 86  
 87  const tabsTriggerVariants = cva(
 88    "inline-flex items-center bg-transparent hover:text-foreground hover:border-foreground justify-center whitespace-nowrap text-sm font-medium ring-offset-background transition-all focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:bg-background data-[state=active]:text-foreground data-[state=active]:shadow-sm",
 89    {
 90      variants: {
 91        color: {
 92          primary: "border-primary text-primary",
 93          secondary: "border-secondary text-secondary",
 94          error: "border-error text-error",
 95          success: "border-success text-success",
 96          warning: "border-warning text-warning",
 97          info: "border-info text-info",
 98          muted: "border-gray-500",
 99        },
100        size: {
101          xs: "px-2 h-3.5 text-xs",
102          sm: "px-3 h-4.5 text-sm",
103          md: "px-4 h-5.5 text-base",
104          lg: "px-8 h-7.5 text-lg",
105          xl: "px-10 h-8.5 text-xl",
106        },
107        radius: {
108          full: "rounded-full",
109          xs: "rounded-[2px]",
110          sm: "rounded-[4px]",
111          md: "rounded-[6px]",
112          lg: "rounded-[8px]",
113          xl: "rounded-[12px]",
114        },
115      },
116      defaultVariants: {
117        color: "muted",
118        radius: "sm",
119        size: "md",
120      },
121    },
122  );
123  
124  export interface TabsTriggerProps
125    extends Omit<
126        React.ComponentPropsWithoutRef<typeof TabsPrimitive.Trigger>,
127        "color"
128      >,
129      VariantProps<typeof tabsTriggerVariants> {}
130  
131  const TabsTrigger = React.forwardRef<
132    React.ElementRef<typeof TabsPrimitive.Trigger>,
133    TabsTriggerProps
134  >(({ className, color, radius, size, ...props }, ref) => {
135    return (
136      <TabsPrimitive.Trigger
137        ref={ref}
138        className={cn(
139          tabsTriggerVariants({
140            color,
141            radius,
142            size,
143          }),
144          className,
145        )}
146        {...props}
147      />
148    );
149  });
150  
151  TabsTrigger.displayName = TabsPrimitive.Trigger.displayName;
152  
153  const TabsContent = React.forwardRef<
154    React.ElementRef<typeof TabsPrimitive.Content>,
155    React.ComponentPropsWithoutRef<typeof TabsPrimitive.Content>
156  >(({ className, ...props }, ref) => (
157    <TabsPrimitive.Content
158      ref={ref}
159      className={cn(
160        "mt-2 ring-offset-white focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-slate-950 focus-visible:ring-offset-2 dark:ring-offset-slate-950 dark:focus-visible:ring-slate-300",
161        className,
162      )}
163      {...props}
164    />
165  ));
166  TabsContent.displayName = TabsPrimitive.Content.displayName;
167  
168  export { Tabs, TabsContent, TabsList, TabsTrigger };