forked from claus/react-dat-gui
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathSlider.js
More file actions
107 lines (90 loc) · 2.64 KB
/
Slider.js
File metadata and controls
107 lines (90 loc) · 2.64 KB
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
/* eslint-disable jsx-a11y/click-events-have-key-events */
/* eslint-disable jsx-a11y/control-has-associated-label */
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import clamp from 'lodash.clamp';
import cx from 'classnames';
import { toNumber } from './utils';
export default class Slider extends Component {
static propTypes = {
className: PropTypes.string,
style: PropTypes.object,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]),
min: PropTypes.number,
max: PropTypes.number,
width: PropTypes.number,
onUpdate: PropTypes.func.isRequired
};
static defaultProps = {
className: null,
style: null,
value: null,
min: null,
max: null,
width: null
};
constructor() {
super();
this.state = { value: null };
this.sliderRef = React.createRef();
}
static getDerivedStateFromProps(nextProps, prevState) {
const nextValue = toNumber(nextProps.value);
if (prevState.value === nextValue) return null;
return {
value: nextValue
};
}
handleMouseDown = event => {
this.update(event.pageX);
window.addEventListener('mousemove', this.handleMouseMove);
window.addEventListener('mouseup', this.handleMouseUp);
};
handleMouseMove = event => {
this.update(event.pageX);
event.preventDefault();
};
handleMouseUp = event => {
this.update(event.pageX, false);
window.removeEventListener('mousemove', this.handleMouseMove);
window.removeEventListener('mouseup', this.handleMouseUp);
};
handleClick = event => {
// do not focus input field on slider click
event.preventDefault();
};
update(pageX, isLive = true) {
const { min, max, onUpdate } = this.props;
const rect = this.sliderRef.current.getBoundingClientRect();
const x = pageX - rect.left;
const w = rect.right - rect.left;
const value = min + clamp(x / w, 0, 1) * (max - min);
this.setState({ value }, () => {
onUpdate(value, isLive);
});
}
render() {
const { min, max, width, className, style } = this.props;
const { value } = this.state;
const widthBackground = clamp(((value - min) * 100) / (max - min), 0, 100);
const sliderStyles = {
width: `${width}%`,
backgroundSize: `${widthBackground}% 100%`,
...style
};
return (
<span
ref={this.sliderRef}
className={cx('slider', className)}
style={sliderStyles}
onClick={this.handleClick}
onMouseDown={this.handleMouseDown}
role="slider"
tabIndex={0}
aria-valuenow={value}
aria-valuemin={min}
aria-valuemax={max}
/>
);
}
}