52 lines
1.4 KiB
TypeScript
52 lines
1.4 KiB
TypeScript
import * as React from 'react';
|
|
import { clsx } from 'clsx';
|
|
|
|
export interface SegmentedControlOption {
|
|
value: string;
|
|
label: React.ReactNode;
|
|
disabled?: boolean;
|
|
}
|
|
|
|
export interface SegmentedControlProps {
|
|
value: string;
|
|
options: SegmentedControlOption[];
|
|
onValueChange: (value: string) => void;
|
|
'aria-label': string;
|
|
className?: string;
|
|
}
|
|
|
|
export function SegmentedControl({
|
|
value,
|
|
options,
|
|
onValueChange,
|
|
className,
|
|
'aria-label': ariaLabel,
|
|
}: SegmentedControlProps) {
|
|
return (
|
|
<div
|
|
role="radiogroup"
|
|
aria-label={ariaLabel}
|
|
className={clsx('inline-flex rounded-lg bg-[var(--bl-surface-muted)] p-1', className)}
|
|
>
|
|
{options.map(option => (
|
|
<button
|
|
key={option.value}
|
|
type="button"
|
|
role="radio"
|
|
aria-checked={option.value === value}
|
|
disabled={option.disabled}
|
|
className={clsx(
|
|
'min-h-8 rounded-md px-3 text-sm font-medium text-[var(--bl-text-secondary)] transition-colors',
|
|
'hover:text-[var(--bl-text-primary)] focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--bl-accent)]',
|
|
'disabled:pointer-events-none disabled:opacity-50',
|
|
option.value === value && 'bg-[var(--bl-surface-card)] text-[var(--bl-text-primary)]'
|
|
)}
|
|
onClick={() => onValueChange(option.value)}
|
|
>
|
|
{option.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|