51 lines
1.4 KiB
TypeScript
51 lines
1.4 KiB
TypeScript
import type { ComponentType } from 'react';
|
|
import { cn } from '../../lib/cn';
|
|
|
|
export interface AnalysisScopeOption<T extends string> {
|
|
id: T;
|
|
label: string;
|
|
}
|
|
|
|
export default function AnalysisScopeSwitch<T extends string>({
|
|
ariaLabel,
|
|
value,
|
|
options,
|
|
onChange,
|
|
icon: Icon,
|
|
className,
|
|
}: {
|
|
ariaLabel: string;
|
|
value: T;
|
|
options: readonly AnalysisScopeOption<T>[];
|
|
onChange: (value: T) => void;
|
|
icon?: ComponentType<{ size?: number; className?: string }>;
|
|
className?: string;
|
|
}) {
|
|
return (
|
|
<div
|
|
role="group"
|
|
aria-label={ariaLabel}
|
|
className={cn('grid gap-1 rounded-lg bg-slate-100 p-1', className)}
|
|
style={{ gridTemplateColumns: `repeat(${options.length}, minmax(0, 1fr))` }}
|
|
>
|
|
{options.map(option => (
|
|
<button
|
|
key={option.id}
|
|
type="button"
|
|
onClick={() => onChange(option.id)}
|
|
aria-pressed={value === option.id}
|
|
className={cn(
|
|
'flex min-h-9 min-w-0 items-center justify-center gap-1.5 rounded-lg px-2 text-[12px] font-black transition-colors',
|
|
value === option.id
|
|
? 'bg-white text-slate-900 shadow-sm'
|
|
: 'text-slate-500 hover:text-slate-700',
|
|
)}
|
|
>
|
|
{Icon ? <Icon size={14} className="shrink-0" /> : null}
|
|
<span className="min-w-0 truncate">{option.label}</span>
|
|
</button>
|
|
))}
|
|
</div>
|
|
);
|
|
}
|