diff options
Diffstat (limited to 'src/components/shared/ToggleSwitch.tsx')
| -rw-r--r-- | src/components/shared/ToggleSwitch.tsx | 67 |
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); |
