summaryrefslogtreecommitdiff
path: root/src/components/shared/SegmentedControl.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/shared/SegmentedControl.tsx')
-rw-r--r--src/components/shared/SegmentedControl.tsx48
1 files changed, 48 insertions, 0 deletions
diff --git a/src/components/shared/SegmentedControl.tsx b/src/components/shared/SegmentedControl.tsx
new file mode 100644
index 0000000..93ff64e
--- /dev/null
+++ b/src/components/shared/SegmentedControl.tsx
@@ -0,0 +1,48 @@
+import cx from 'clsx';
+import * as React from 'react';
+
+import s from './SegmentedControl.module.scss';
+
+export type SegmentedOption<T extends string | number> = {
+ value: T;
+ label: React.ReactNode;
+ title?: string;
+};
+
+type Props<T extends string | number> = {
+ options: SegmentedOption<T>[];
+ value: T;
+ onChange: (value: T) => void;
+ label?: string;
+ className?: string;
+};
+
+/** 分段选择器:一条轨道内若干选项,选中项以白色药丸高亮 */
+export function SegmentedControl<T extends string | number>({
+ options,
+ value,
+ onChange,
+ label,
+ className,
+}: Props<T>) {
+ return (
+ <div className={cx(s.track, className)} role="radiogroup" aria-label={label}>
+ {options.map((o) => {
+ const selected = o.value === value;
+ return (
+ <button
+ key={o.value}
+ type="button"
+ role="radio"
+ aria-checked={selected}
+ title={o.title}
+ className={cx(s.segment, { [s.selected]: selected })}
+ onClick={() => onChange(o.value)}
+ >
+ {o.label}
+ </button>
+ );
+ })}
+ </div>
+ );
+}