fiddy/apps/web/shared/components/forms/toggle-button-group.tsx

78 lines
2.5 KiB
TypeScript

"use client";
type ToggleButtonOption<T extends string> = {
value: T;
label: string;
className?: string;
activeClassName?: string;
inactiveClassName?: string;
disabled?: boolean;
ariaLabel?: string;
onClick?: () => void;
};
type ToggleButtonGroupProps<T extends string> = {
value?: T | null;
options: ToggleButtonOption<T>[];
onChange?: (value: T) => void;
ariaLabel?: string;
role?: "group" | "radiogroup";
className?: string;
buttonBaseClassName?: string;
buttonClassName?: string;
activeClassName?: string;
inactiveClassName?: string;
sizeClassName?: string;
};
function joinClasses(parts: Array<string | undefined | null | false>) {
return parts.filter(Boolean).join(" ");
}
export default function ToggleButtonGroup<T extends string>({
value,
options,
onChange,
ariaLabel,
role = "group",
className = "flex items-center gap-0 rounded-full border border-accent-weak bg-panel",
buttonBaseClassName = "rounded-full",
buttonClassName,
activeClassName = "btn-accent",
inactiveClassName = "text-muted",
sizeClassName = "px-3 py-2 text-xs font-semibold"
}: ToggleButtonGroupProps<T>) {
return (
<div className={className} role={role} aria-label={ariaLabel}>
{options.map(option => {
const isActive = value != null && option.value === value;
const onClick = option.onClick
? option.onClick
: onChange
? () => onChange(option.value)
: undefined;
return (
<button
key={option.value}
type="button"
className={joinClasses([
buttonBaseClassName,
sizeClassName,
buttonClassName,
isActive ? option.activeClassName ?? activeClassName : option.inactiveClassName ?? inactiveClassName,
option.className
])}
onClick={onClick}
disabled={option.disabled}
aria-pressed={value != null ? isActive : undefined}
aria-label={option.ariaLabel}
>
{option.label}
</button>
);
})}
</div>
);
}