summaryrefslogtreecommitdiff
path: root/src/components/shared/ToggleSwitch.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/shared/ToggleSwitch.tsx')
-rw-r--r--src/components/shared/ToggleSwitch.tsx67
1 files changed, 67 insertions, 0 deletions
diff --git a/src/components/shared/ToggleSwitch.tsx b/src/components/shared/ToggleSwitch.tsx
new file mode 100644
index 0000000..56d7ffe
--- /dev/null
+++ b/src/components/shared/ToggleSwitch.tsx
@@ -0,0 +1,67 @@
+import React, { useCallback, useMemo } from 'react';
+
+import s0 from './ToggleSwitch.module.scss';
+
+type Props = {
+ options: Array<{ label: string; value: string }>;
+ value: string;
+ name: string;
+ onChange: React.ChangeEventHandler<HTMLInputElement>;
+};
+
+function ToggleSwitch({ options, value, name, onChange }: Props) {
+ const idxSelected = useMemo(() => options.map((o) => o.value).indexOf(value), [options, value]);
+
+ const getPortionPercentage = useCallback(
+ (idx: number) => {
+ const w = Math.floor(100 / options.length);
+ if (idx === options.length - 1) {
+ return 100 - options.length * w + w;
+ } else if (idx > -1) {
+ return w;
+ }
+ // value 对不上任何一项时 idxSelected 是 -1,滑块宽度按 0 算
+ return 0;
+ },
+ [options],
+ );
+
+ const sliderStyle = useMemo(() => {
+ return {
+ width: getPortionPercentage(idxSelected) + '%',
+ left: idxSelected * getPortionPercentage(0) + '%',
+ };
+ }, [idxSelected, getPortionPercentage]);
+
+ return (
+ <div className={s0.ToggleSwitch}>
+ <div className={s0.slider} style={sliderStyle} />
+ {options.map((o, idx) => {
+ const id = `${name}-${o.label}`;
+ const className = idx === 0 ? '' : 'border-left';
+ return (
+ <label
+ htmlFor={id}
+ key={id}
+ className={className}
+ style={{
+ width: getPortionPercentage(idx) + '%',
+ }}
+ >
+ <input
+ id={id}
+ name={name}
+ type="radio"
+ value={o.value}
+ checked={value === o.value}
+ onChange={onChange}
+ />
+ <div>{o.label}</div>
+ </label>
+ );
+ })}
+ </div>
+ );
+}
+
+export default React.memo(ToggleSwitch);