-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathMultiRangeSlider.tsx
134 lines (122 loc) · 3.63 KB
/
MultiRangeSlider.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
// Components
import { SliderTracks } from './SliderTracks'
// Utils
import { decimalCount } from '../utils/utils'
// Types
import { SliderProps } from '../types'
// Styles
import '../styles.css'
/** Component props. */
interface MultiRangeSliderProps extends SliderProps {
/** The minimum value set on the slider. */
minValue: number;
/** The maximum value set on the slider. */
maxValue: number;
/** Minimum difference between minimum and maximum values set. Default to 0. */
margin?: number;
/** Callback function that will be invoked when `minValue` or `maxValue` change. */
onChange: (newMinValue: number, newMaxValue: number) => any;
}
/**
* A slider with a min and max value.
*
* @param props - Components props.
* @returns Component.
*/
const MultiRangeSlider = function (props: MultiRangeSliderProps) {
const {
defaultMinValue,
defaultMaxValue,
step = 1,
minValue,
maxValue,
onChange,
margin = 0,
showLabels = false,
disabled = false,
inverted = false,
color = 'green',
style,
id,
className = ''
} = props
/**
* Returns the selected slice of the slider, in percent from 0 to 100.
*
* @param value - New value set on the slider.
* @returns Percent of the slider that need to be colored, from 0 to 100.
*/
const getPercent = (value: number) => Math.round(((value - defaultMinValue) / (defaultMaxValue - defaultMinValue)) * 100)
/**
* Invokes callback function if slider value is updated.
*
* @param newMinValue - New minimum value set on the slider.
* @param newMaxValue - New maximum value set on the slider.
*/
const handleChange = (newMinValue: number, newMaxValue: number) => {
if (newMinValue + margin > newMaxValue || newMaxValue - margin < newMinValue) {
return
}
onChange(newMinValue, newMaxValue)
}
/**
* If `showLabels` is `true`, returns a `<div>` that contains a labels with the current maximum and minimum values of the slider.
*
* @returns Div element with labels.
*/
const renderLabels = () => {
if (showLabels && minValue !== undefined && maxValue !== undefined) {
return (
<>
<div className="slider__left-value">{minValue.toFixed(decimalCount(step))}</div>
<div className="slider__right-value">{maxValue.toFixed(decimalCount(step))}</div>
</>
)
}
}
const minPercent = getPercent(minValue)
const maxPercent = getPercent(maxValue)
const left = `${minPercent}%`
const width = `${maxPercent - minPercent}%`
const disabledClass = disabled ? 'disabled' : ''
return (
<div id={id} className={`slider-parent ${className}`} style={style}>
<input
type="range"
min={defaultMinValue}
max={defaultMaxValue}
value={minValue}
disabled={disabled}
style={{ pointerEvents: 'none' }}
onChange={(event) => {
handleChange(parseFloat(event.target.value), maxValue)
}}
className={`thumb thumb--left ${disabledClass}`}
/>
<input
type="range"
step={step}
min={defaultMinValue}
max={defaultMaxValue}
value={maxValue}
disabled={disabled}
style={{ pointerEvents: 'none' }}
onChange={(event) => {
handleChange(minValue, parseFloat(event.target.value))
}}
className={`thumb thumb--right ${disabledClass}`}
/>
<SliderTracks
left={left}
width={width}
color={color}
disabled={disabled}
inverted={inverted}
>
{renderLabels()}
</SliderTracks>
</div>
)
}
export { MultiRangeSlider }
export type { MultiRangeSliderProps }