@@ -4,10 +4,12 @@ import Track from './Track';
44import Label from './Label' ;
55import defaultClassNames from './defaultClassNames' ;
66import valueTransformer from './valueTransformer' ;
7- import { autobind , captialize , distanceTo , isObject , length } from './util' ;
7+ import { autobind , captialize , distanceTo , isDefined , isObject , length } from './util' ;
88import { maxMinValuePropType } from './propTypes' ;
99
1010// Constants
11+ const internals = new WeakMap ( ) ;
12+
1113const KeyCode = {
1214 LEFT_ARROW : 37 ,
1315 RIGHT_ARROW : 39 ,
@@ -40,6 +42,12 @@ function shouldUpdate(inputRange, values) {
4042 hasStepDifference ( inputRange , values ) ;
4143}
4244
45+ function getDocument ( inputRange ) {
46+ const { inputRange : { ownerDocument } } = inputRange . refs ;
47+
48+ return ownerDocument ;
49+ }
50+
4351function getComponentClassName ( inputRange ) {
4452 const { props } = inputRange ;
4553
@@ -142,10 +150,21 @@ class InputRange extends React.Component {
142150 constructor ( props ) {
143151 super ( props ) ;
144152
153+ // Private
154+ internals . set ( this , { } ) ;
155+
145156 // Auto-bind
146157 autobind ( [
147- 'handleSliderMouseMove' ,
158+ 'handleInteractionEnd' ,
159+ 'handleInteractionStart' ,
160+ 'handleKeyDown' ,
161+ 'handleKeyUp' ,
162+ 'handleMouseDown' ,
163+ 'handleMouseUp' ,
148164 'handleSliderKeyDown' ,
165+ 'handleSliderMouseMove' ,
166+ 'handleTouchStart' ,
167+ 'handleTouchEnd' ,
149168 'handleTrackMouseDown' ,
150169 ] , this ) ;
151170 }
@@ -230,7 +249,7 @@ class InputRange extends React.Component {
230249 }
231250
232251 // Handlers
233- handleSliderMouseMove ( slider , event ) {
252+ handleSliderMouseMove ( event , slider ) {
234253 if ( this . props . disabled ) {
235254 return ;
236255 }
@@ -241,7 +260,7 @@ class InputRange extends React.Component {
241260 this . updatePosition ( key , position ) ;
242261 }
243262
244- handleSliderKeyDown ( slider , event ) {
263+ handleSliderKeyDown ( event , slider ) {
245264 if ( this . props . disabled ) {
246265 return ;
247266 }
@@ -262,7 +281,7 @@ class InputRange extends React.Component {
262281 }
263282 }
264283
265- handleTrackMouseDown ( track , position ) {
284+ handleTrackMouseDown ( event , track , position ) {
266285 if ( this . props . disabled ) {
267286 return ;
268287 }
@@ -272,6 +291,70 @@ class InputRange extends React.Component {
272291 this . updatePosition ( key , position ) ;
273292 }
274293
294+ handleInteractionStart ( ) {
295+ const _this = internals . get ( this ) ;
296+
297+ if ( ! this . props . onChangeComplete || isDefined ( _this . startValue ) ) {
298+ return ;
299+ }
300+
301+ _this . startValue = this . props . value ;
302+ }
303+
304+ handleInteractionEnd ( ) {
305+ const _this = internals . get ( this ) ;
306+
307+ if ( ! this . props . onChangeComplete || ! isDefined ( _this . startValue ) ) {
308+ return ;
309+ }
310+
311+ if ( _this . startValue !== this . props . value ) {
312+ this . props . onChangeComplete ( this , this . props . value ) ;
313+ }
314+
315+ _this . startValue = null ;
316+ }
317+
318+ handleKeyDown ( event ) {
319+ this . handleInteractionStart ( event ) ;
320+ }
321+
322+ handleKeyUp ( event ) {
323+ this . handleInteractionEnd ( event ) ;
324+ }
325+
326+ handleMouseDown ( event ) {
327+ const document = getDocument ( this ) ;
328+
329+ this . handleInteractionStart ( event ) ;
330+
331+ document . addEventListener ( 'mouseup' , this . handleMouseUp ) ;
332+ }
333+
334+ handleMouseUp ( event ) {
335+ const document = getDocument ( this ) ;
336+
337+ this . handleInteractionEnd ( event ) ;
338+
339+ document . removeEventListener ( 'mouseup' , this . handleMouseUp ) ;
340+ }
341+
342+ handleTouchStart ( event ) {
343+ const document = getDocument ( this ) ;
344+
345+ this . handleInteractionStart ( event ) ;
346+
347+ document . addEventListener ( 'touchend' , this . handleTouchEnd ) ;
348+ }
349+
350+ handleTouchEnd ( event ) {
351+ const document = getDocument ( this ) ;
352+
353+ this . handleInteractionEnd ( event ) ;
354+
355+ document . removeEventListener ( 'touchend' , this . handleTouchEnd ) ;
356+ }
357+
275358 // Render
276359 render ( ) {
277360 const { classNames } = this . props ;
@@ -283,7 +366,11 @@ class InputRange extends React.Component {
283366 < div
284367 aria-disabled = { this . props . disabled }
285368 ref = "inputRange"
286- className = { componentClassName } >
369+ className = { componentClassName }
370+ onKeyDown = { this . handleKeyDown }
371+ onKeyUp = { this . handleKeyUp }
372+ onMouseDown = { this . handleMouseDown }
373+ onTouchStart = { this . handleTouchStart } >
287374 < Label
288375 className = { classNames . labelMin }
289376 containerClassName = { classNames . labelContainer } >
@@ -320,6 +407,7 @@ InputRange.propTypes = {
320407 minValue : maxMinValuePropType ,
321408 name : React . PropTypes . string ,
322409 onChange : React . PropTypes . func . isRequired ,
410+ onChangeComplete : React . PropTypes . func ,
323411 step : React . PropTypes . number ,
324412 value : maxMinValuePropType ,
325413} ;
0 commit comments