59 lines
1.2 KiB
TypeScript
59 lines
1.2 KiB
TypeScript
import type { ISliderProps } from "./Slider.d"
|
|
import type { JSX } from "react"
|
|
|
|
import cs from "classnames"
|
|
import { FunctionComponent, useCallback, useMemo } from "react"
|
|
|
|
import styles from "./Slider.module.scss"
|
|
|
|
export const Slider: FunctionComponent<ISliderProps> = ({
|
|
value,
|
|
min,
|
|
max,
|
|
step = 1,
|
|
label,
|
|
unit,
|
|
helpText,
|
|
onChange,
|
|
className,
|
|
}): JSX.Element => {
|
|
const handleChange = useCallback(
|
|
(e: React.ChangeEvent<HTMLInputElement>) => {
|
|
onChange(Number(e.target.value))
|
|
},
|
|
[onChange],
|
|
)
|
|
|
|
const fillPercent = useMemo(
|
|
() => ((value - min) / (max - min)) * 100,
|
|
[value, min, max],
|
|
)
|
|
|
|
return (
|
|
<div className={cs(styles.root, className)} data-testid="Slider">
|
|
<div className={styles.header}>
|
|
<span className={styles.label}>{label}</span>
|
|
<span className={styles.value}>
|
|
{value}
|
|
{unit ? ` ${unit}` : ""}
|
|
</span>
|
|
</div>
|
|
<input
|
|
type="range"
|
|
className={styles.input}
|
|
min={min}
|
|
max={max}
|
|
step={step}
|
|
value={value}
|
|
onChange={handleChange}
|
|
style={
|
|
{
|
|
"--fill-percent": `${fillPercent}%`,
|
|
} as React.CSSProperties
|
|
}
|
|
/>
|
|
{helpText && <span className={styles.helpText}>{helpText}</span>}
|
|
</div>
|
|
)
|
|
}
|