Files
blitzkit/packages/website/src/components/SegmentedControl/index.tsx
T

59 lines
1.4 KiB
TypeScript
Raw Normal View History

2026-10-11 15:44:42 -05:00
import { type ReactNode } from "react";
import styles from "./index.module.css";
2026-10-12 00:04:47 -05:00
export interface SegmentedControlOption {
value: string;
2026-10-11 15:44:42 -05:00
label: ReactNode;
}
2026-10-12 00:04:47 -05:00
export interface SegmentedControlProps {
options: readonly SegmentedControlOption[];
value: string;
onValueChange(value: string): void;
size?: "regular" | "minor";
variant?: "solid" | "underline";
2026-10-11 15:44:42 -05:00
}
2026-10-12 00:04:47 -05:00
export function SegmentedControl({
2026-10-11 15:44:42 -05:00
options,
value,
onValueChange,
2026-10-12 00:04:47 -05:00
size = "regular",
variant = "solid",
}: SegmentedControlProps) {
2026-10-11 15:44:42 -05:00
const selectedIndex = options.findIndex((option) => option.value === value);
const segmentWidth = 100 / options.length;
return (
<div
className={styles.options}
role="radiogroup"
2026-10-12 00:04:47 -05:00
data-size={size}
data-variant={variant}
style={{
gridTemplateColumns: `repeat(${options.length}, minmax(0, 1fr))`,
}}
2026-10-11 15:44:42 -05:00
>
<div
className={styles.indicator}
style={{
left: `${Math.max(selectedIndex, 0) * segmentWidth}%`,
width: `${segmentWidth}%`,
}}
aria-hidden="true"
/>
{options.map((option) => (
<label className={styles.option} key={option.value}>
<input
type="radio"
value={option.value}
checked={option.value === value}
onChange={() => onValueChange(option.value)}
/>
<span className={styles.label}>{option.label}</span>
</label>
))}
</div>
);
}