pages235/src/react/Slider.tsx
Vitaly 3b4d5e04b8 fix: minimal value of settings by default is now 0 which is important for sound
fix: don't start audiocontext when muted, so browser don't try to take exclusive control over sound output device when it's busy in super advanced setups
2023-11-10 11:13:58 +03:00

83 lines
2 KiB
TypeScript

// Slider.tsx
import React, { useState, useEffect } from 'react'
import styles from './slider.module.css'
interface Props extends React.ComponentProps<'div'> {
label: string;
value: number;
unit?: string;
width?: number;
valueDisplay?: string | number;
min?: number;
max?: number;
disabledReason?: string;
updateValue?: (value: number) => void;
updateOnDragEnd?: boolean;
}
const Slider: React.FC<Props> = ({
label,
unit = '%',
width,
value: valueProp,
valueDisplay,
min = 0,
max = 100,
disabledReason,
updateOnDragEnd = false,
updateValue,
...divProps
}) => {
const [value, setValue] = useState(valueProp)
const getRatio = (v = value) => Math.max(Math.min((v - min) / (max - min), 1), 0)
const [ratio, setRatio] = useState(getRatio())
useEffect(() => {
setValue(valueProp)
}, [valueProp])
useEffect(() => {
setRatio(getRatio())
}, [value, min, max])
const fireValueUpdate = (dragEnd: boolean, v = value) => {
if (updateOnDragEnd !== dragEnd) return
updateValue?.(v)
}
return (
<div className={styles['slider-container']} style={{ width }} {...divProps}>
<input
type="range"
className={styles.slider}
min={min}
max={max}
value={value}
disabled={!!disabledReason}
onChange={(e) => {
const newValue = Number(e.target.value)
setValue(newValue)
fireValueUpdate(false, newValue)
}}
// todo improve correct handling of drag end
onLostPointerCapture={() => {
fireValueUpdate(true)
}}
onPointerUp={() => {
fireValueUpdate(true)
}}
onKeyUp={() => {
fireValueUpdate(true)
}}
/>
<div className={styles.disabled} title={disabledReason}></div>
<div className={styles['slider-thumb']} style={{ left: `calc((100% * ${ratio}) - (8px * ${ratio}))` }}></div>
<label className={styles.label}>
{label}: {valueDisplay ?? value} {unit}
</label>
</div>
)
}
export default Slider