@@ -20,18 +20,21 @@ export default class RangeStepInput extends React.Component {
2020 this . onMouseDown = this . onMouseDown . bind ( this ) ;
2121 this . onMouseUp = this . onMouseUp . bind ( this ) ;
2222 this . onMouseMove = this . onMouseMove . bind ( this ) ;
23+ this . domRef = React . createRef ( ) ;
2324 }
2425
2526 render ( ) {
2627 return React . createElement ( "input" , {
2728 type : "range" ,
29+ ref : this . domRef ,
2830 className : this . props . className ,
2931 min : this . props . min ,
3032 max : this . props . max ,
3133 step : this . props . step ,
3234 value : this . props . value ,
3335 name : this . props . name ,
3436 id : this . props . id ,
37+ disabled : this . props . disabled ,
3538 onChange : this . props . onChange ,
3639 onMouseDown : this . onMouseDown ,
3740 onMouseUp : this . onMouseUp ,
@@ -45,13 +48,26 @@ export default class RangeStepInput extends React.Component {
4548 this . setState ( {
4649 isMouseDown : true
4750 } ) ;
51+
52+ if ( this . props . hold ) {
53+ const oldVal = this . props . value ;
54+ const self = this ; // Add some initial delay on the click-hold functionality.
55+
56+ setTimeout ( function ( ) {
57+ self . holdLoop = self . makeHoldLoop ( oldVal ) ;
58+ } , 600 ) ;
59+ }
4860 }
4961
5062 onMouseUp ( ) {
5163 this . setState ( {
5264 isMouseDown : false ,
5365 isDragging : false
5466 } ) ;
67+
68+ if ( this . holdLoop ) {
69+ clearInterval ( this . holdLoop ) ;
70+ }
5571 }
5672
5773 onMouseMove ( ) {
@@ -74,7 +90,47 @@ export default class RangeStepInput extends React.Component {
7490 }
7591 }
7692
93+ makeHoldLoop ( oldVal ) {
94+ const self = this ;
95+ return setInterval ( function ( ) {
96+ if ( ! self . state . isMouseDown ) {
97+ // The user isn't holding the cursor anymore: clean up
98+ // and cancel.
99+ if ( self . holdLoop ) {
100+ clearInterval ( self . holdLoop ) ;
101+ }
102+
103+ return false ;
104+ }
105+
106+ const input = self . domRef . current ;
107+ let newVal = self . props . value ;
108+
109+ if ( oldVal > newVal ) {
110+ newVal -= self . props . step ;
111+ } else if ( oldVal < newVal ) {
112+ newVal += self . props . step ;
113+ } else {
114+ // The user is just holding the cursor at the current
115+ // value, so don't do anything.
116+ return false ;
117+ } // Directly setting input.value will cause the new value
118+ // to not be recognized, because of React.
119+ // https://stackoverflow.com/a/46012210/173630
120+
121+
122+ const nativeInputValueSetter = Object . getOwnPropertyDescriptor ( window . HTMLInputElement . prototype , 'value' ) . set ;
123+ nativeInputValueSetter . call ( input , newVal ) ; // Trigger an onChange event.
124+
125+ const e = new Event ( 'change' , {
126+ bubbles : true
127+ } ) ;
128+ return input . dispatchEvent ( e ) ;
129+ } , 100 ) ;
130+ }
131+
77132}
133+ ;
78134RangeStepInput . propTypes = {
79135 value : PropTypes . number . isRequired ,
80136 onChange : PropTypes . func . isRequired ,
@@ -83,5 +139,12 @@ RangeStepInput.propTypes = {
83139 min : PropTypes . number ,
84140 max : PropTypes . number ,
85141 id : PropTypes . string ,
86- name : PropTypes . string
142+ name : PropTypes . string ,
143+ disabled : PropTypes . bool ,
144+ // Determines whether the slider changes value when the cursor is
145+ // held on it.
146+ hold : PropTypes . bool
147+ } ;
148+ RangeStepInput . defaultProps = {
149+ hold : true
87150} ;
0 commit comments