55 lines
1.5 KiB
TypeScript
55 lines
1.5 KiB
TypeScript
import { cn } from '@/lib/utils'
|
|
|
|
export function Tabs({
|
|
value,
|
|
onValueChange,
|
|
items,
|
|
className,
|
|
size = 'md',
|
|
}: {
|
|
value: string
|
|
onValueChange: (v: string) => void
|
|
items: { value: string; label: string }[]
|
|
className?: string
|
|
size?: 'sm' | 'md' | 'lg'
|
|
}) {
|
|
const tabSizes = {
|
|
sm: 'px-2.5 py-1 text-[12px]',
|
|
md: 'px-3.5 py-1.5 text-[13px]',
|
|
lg: 'px-4 py-2 text-[14px]',
|
|
}
|
|
return (
|
|
<div
|
|
className={cn(
|
|
'flex max-w-full items-center gap-1.5 overflow-x-auto rounded-lg border border-[var(--border)] bg-[var(--bg-tertiary)] p-1.5',
|
|
'[scrollbar-width:thin]',
|
|
className,
|
|
)}
|
|
role="tablist"
|
|
>
|
|
{items.map((item) => {
|
|
const active = value === item.value
|
|
return (
|
|
<button
|
|
key={item.value}
|
|
type="button"
|
|
role="tab"
|
|
aria-selected={active}
|
|
className={cn(
|
|
'relative shrink-0 rounded-md font-medium whitespace-nowrap transition-colors',
|
|
tabSizes[size],
|
|
'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--focus-ring)]',
|
|
active
|
|
? 'bg-[var(--bg-secondary)] text-[var(--text-primary)] shadow-[var(--shadow-sm)] ring-1 ring-[var(--border)]'
|
|
: 'text-[var(--text-muted)] hover:bg-[var(--bg-hover)]/60 hover:text-[var(--text-secondary)]',
|
|
)}
|
|
onClick={() => onValueChange(item.value)}
|
|
>
|
|
{item.label}
|
|
</button>
|
|
)
|
|
})}
|
|
</div>
|
|
)
|
|
}
|