"use client"; import { createContext, useContext } from "react"; import { Tabs as TabsPrimitive } from "@base-ui/react/tabs"; import { cva, type VariantProps } from "class-variance-authority"; import { cn } from "./cn"; /* * The primitive owns arrow-key navigation, the roving tabindex and the * tab/panel wiring that keeps a screen reader in step. * * Note the state attribute: Tabs marks the active tab with `data-active`, * while Checkbox and Radio use `data-selected`. Base UI is not uniform here, so * styling one from memory of another silently produces a tab row where nothing * ever looks selected. * * Two variants because the products genuinely differ in kind, not degree: * `line` is an underlined row that sits on a page rule, `solid` is a filled * segmented control. Neither is a brand default — a product picks per surface. */ const tabsListVariants = cva( ["inline-flex max-w-full items-center overflow-x-auto"], { variants: { variant: { line: "gap-6 border-b border-(color:--color-border) bg-transparent", solid: "gap-1 rounded-(--tabs-radius) bg-(color:--color-action-neutral) p-[3px]", }, }, defaultVariants: { variant: "line" }, }, ); const tabsTriggerVariants = cva( [ "group inline-flex items-center justify-center gap-2 whitespace-nowrap", "text-(length:--font-size-control) font-medium", "transition-colors duration-(--motion-duration) ease-(--motion-ease)", "outline-none focus-visible:outline-solid", "focus-visible:outline-(length:--focus-ring-width)", "focus-visible:outline-(color:--color-focus-ring)", "disabled:pointer-events-none disabled:opacity-50", "hover:text-(color:--color-content)", "data-active:text-(color:--color-content)", ], { variants: { variant: { line: [ "-mb-px border-b-2 border-transparent px-0 pt-1 pb-2", "text-(color:--color-content-muted)", "focus-visible:outline-offset-2", "data-active:border-(color:--color-content)", ], solid: [ "rounded-(--tabs-item-radius) px-2.5 py-1", "text-(color:--color-action-neutral-content)", "focus-visible:-outline-offset-1", "data-active:bg-(color:--color-surface)", ], }, }, defaultVariants: { variant: "line" }, }, ); function Tabs({ className, ...props }: TabsPrimitive.Root.Props) { return ( ); } /* * The list publishes its variant so triggers inherit it. Without this a * `solid` list full of default triggers renders an underlined row inside a * filled container -- each part defaults independently, and the mismatch only * shows once a product picks the non-default variant. Enterprise never hit it * because it uses `line`, the default for both. A trigger can still override * explicitly. */ const TabsVariantContext = createContext< VariantProps["variant"] | undefined >(undefined); export interface TabsListProps extends Omit, VariantProps { className?: string; } function TabsList({ className, variant, ...props }: TabsListProps) { return ( ); } export interface TabsTriggerProps extends Omit, VariantProps { className?: string; } function TabsTrigger({ className, variant, ...props }: TabsTriggerProps) { const inherited = useContext(TabsVariantContext); return ( ); } function TabsContent({ className, keepMounted = false, ...props }: TabsPrimitive.Panel.Props) { return ( ); } export { Tabs, TabsList, TabsTrigger, TabsContent, tabsListVariants, tabsTriggerVariants };