@@ -2,14 +2,15 @@ import React, {Component} from "react";
22import { Text , TextInput , TouchableHighlight , View } from "react-native" ;
33import PropTypes from "prop-types" ;
44import { Style } from "./style" ;
5- import { debounce , isNumeric , isEmpty , isStringEmpty } from "./utils" ;
5+ import { debounce , isNumeric , isEmpty } from "./utils" ;
66
77/**
88 * Default constants
99 */
1010const defaultColor = "#3E525F" ;
11- const defaultLongPressStartTimeout = 1000 ;
12- const defaultLongPressTimeout = 200 ;
11+ const defaultLongPressDelay = 750 ;
12+ const defaultLongPressSpeed = 7 ;
13+ const defaultDebounceTime = 500 ;
1314
1415/**
1516 * Input Spinner
@@ -42,6 +43,10 @@ class InputSpinner extends Component {
4243 initialValue = this . parseNum ( initialValue ) ;
4344 initialValue = this . withinRange ( initialValue , min , max ) ;
4445
46+ // Set debounce
47+ this . _debounceSetMax = debounce ( this . _setStateMax . bind ( this ) , this . props . debounceTime ) ;
48+ this . _debounceSetMin = debounce ( this . _setStateMin . bind ( this ) , this . props . debounceTime ) ;
49+
4550 this . state = {
4651 min : min ,
4752 max : max ,
@@ -86,11 +91,34 @@ class InputSpinner extends Component {
8691 }
8792 }
8893
94+ /**
95+ * Set state to min
96+ * @param callback
97+ * @private
98+ */
99+ _setStateMin ( callback = null ) {
100+ return this . setState ( { value : this . state . max } , callback ) ;
101+ }
102+
103+ /**
104+ * Set state to max
105+ * @param callback
106+ * @private
107+ */
108+ _setStateMax ( callback = null ) {
109+ return this . setState ( { value : this . state . max } , callback ) ;
110+ }
111+
89112 /**
90113 * On value change
91- * @param num
114+ * @param value
92115 */
93- async onChange ( num ) {
116+ async onChange ( value ) {
117+ let num = value ;
118+ let parsedNum = value ;
119+ if ( isEmpty ( value ) ) {
120+ num = this . state . min ;
121+ }
94122 if ( this . props . disabled ) return ;
95123 const current_value = this . state . value ;
96124 const separator = ! isEmpty ( this . props . decimalSeparator )
@@ -102,29 +130,41 @@ class InputSpinner extends Component {
102130 ) {
103131 this . decimalInput = true ;
104132 }
105- num = this . parseNum ( String ( num ) . replace ( / ^ 0 + / , "" ) ) || 0 ;
133+ num = parsedNum = this . parseNum ( String ( num ) . replace ( / ^ 0 + / , "" ) ) || 0 ;
106134 if ( ! this . minReached ( num ) ) {
107135 if ( this . maxReached ( num ) ) {
108- num = this . state . max ;
136+ parsedNum = this . state . max ;
137+ this . maxTimer = this . _debounceSetMax ( ) ;
109138 if ( this . props . onMax ) {
110139 this . props . onMax ( this . state . max ) ;
111140 }
112141 }
113142 } else {
143+ parsedNum = this . state . min ;
144+ this . minTimer = this . _debounceSetMin ( ) ;
114145 if ( this . props . onMin ) {
115146 this . props . onMin ( this . state . min ) ;
116147 }
117- num = this . state . min ;
118148 }
119149 if ( current_value !== num && this . props . onChange ) {
120- const res = await this . props . onChange ( num ) ;
121- if ( res === false ) {
122- return ;
123- } else if ( isNumeric ( res ) ) {
124- num = this . parseNum ( res ) ;
150+ const res = await this . props . onChange ( parsedNum ) ;
151+ if ( ! isEmpty ( value ) ) {
152+ if ( res === false ) {
153+ return ;
154+ } else if ( isNumeric ( res ) ) {
155+ num = this . parseNum ( res ) ;
156+ }
125157 }
126158 }
127- this . setState ( { value : num } ) ;
159+ if ( ! isEmpty ( value ) ) {
160+ if ( parsedNum === num ) {
161+ clearTimeout ( this . minTimer ) ;
162+ clearTimeout ( this . maxTimer ) ;
163+ }
164+ this . setState ( { value : num } ) ;
165+ } else {
166+ this . setState ( { value : value } ) ;
167+ }
128168 }
129169
130170 /**
@@ -212,6 +252,9 @@ class InputSpinner extends Component {
212252 */
213253 getValue ( ) {
214254 let value = this . state . value ;
255+ if ( isEmpty ( value ) ) {
256+ return "" ;
257+ }
215258 if ( this . typeDecimal ( ) && this . decimalInput ) {
216259 this . decimalInput = false ;
217260 value = this . parseNum ( value ) . toFixed ( 1 ) . replace ( / 0 + $ / , "" ) ;
@@ -226,11 +269,23 @@ class InputSpinner extends Component {
226269 return hasPlaceholder
227270 ? ""
228271 : value . replace (
229- "." ,
230- ! isEmpty ( this . props . decimalSeparator )
231- ? this . props . decimalSeparator
232- : "." ,
233- ) ;
272+ "." ,
273+ ! isEmpty ( this . props . decimalSeparator )
274+ ? this . props . decimalSeparator
275+ : "." ,
276+ ) ;
277+ }
278+
279+ /**
280+ * Get Placeholder
281+ * @returns {* }
282+ */
283+ getPlaceholder ( ) {
284+ if ( isEmpty ( this . props . placeholder ) ) {
285+ return this . state . min ;
286+ } else {
287+ return this . state . placeholder ;
288+ }
234289 }
235290
236291 /**
@@ -262,23 +317,33 @@ class InputSpinner extends Component {
262317 clearTimers ( ) {
263318 if ( this . increaseTimer ) {
264319 clearTimeout ( this . increaseTimer ) ;
320+ this . increaseTimer = null ;
265321 }
266322 if ( this . decreaseTimer ) {
267323 clearTimeout ( this . decreaseTimer ) ;
324+ this . decreaseTimer = null ;
268325 }
269326 }
270327
328+ /**
329+ * Get time to wait before increase/decrease on long press
330+ * @returns {number }
331+ */
332+ getLongPressWaitingTime ( ) {
333+ return 1000 / this . withinRange ( this . props . onLongPressSpeed , 1 , 10 ) ;
334+ }
335+
271336 /**
272337 * Increase
273338 */
274339 async increase ( ) {
275340 if ( this . _isDisabledButtonRight ( ) ) return ;
276341 let num = this . parseNum ( this . state . value ) + this . parseNum ( this . state . step ) ;
342+ if ( this . maxReached ( num ) ) {
343+ return ;
344+ }
277345 if ( this . props . onIncrease ) {
278346 let increased_num = num ;
279- if ( this . maxReached ( num ) ) {
280- increased_num = this . state . max ;
281- }
282347 const res = await this . props . onIncrease ( increased_num ) ;
283348 if ( res === false ) {
284349 return ;
@@ -287,12 +352,12 @@ class InputSpinner extends Component {
287352 }
288353 }
289354
290- let wait = this . props . onLongPressTimeout ;
355+ let wait = this . getLongPressWaitingTime ( ) ;
291356 if ( this . increaseTimer === null ) {
292- wait = this . props . onLongPressStartTimeout ;
357+ wait = this . props . onLongPressDelay ;
293358 }
294359
295- this . increaseTimer = setTimeout ( this . increase , wait ) ;
360+ this . increaseTimer = setTimeout ( this . increase . bind ( this ) , wait ) ;
296361 this . onChange ( num ) ;
297362 }
298363
@@ -302,11 +367,11 @@ class InputSpinner extends Component {
302367 async decrease ( ) {
303368 if ( this . _isDisabledButtonLeft ( ) ) return ;
304369 let num = this . parseNum ( this . state . value ) - this . parseNum ( this . state . step ) ;
370+ if ( this . minReached ( num ) ) {
371+ return ;
372+ }
305373 if ( this . props . onDecrease ) {
306374 let decreased_num = num ;
307- if ( this . minReached ( num ) ) {
308- decreased_num = this . state . min ;
309- }
310375 const res = await this . props . onDecrease ( decreased_num ) ;
311376 if ( res === false ) {
312377 return ;
@@ -315,12 +380,12 @@ class InputSpinner extends Component {
315380 }
316381 }
317382
318- let wait = this . props . onLongPressTimeout ;
319- if ( this . increaseTimer === null ) {
320- wait = this . props . onLongPressStartTimeout ;
383+ let wait = this . getLongPressWaitingTime ( ) ;
384+ if ( this . decreaseTimer === null ) {
385+ wait = this . props . onLongPressDelay ;
321386 }
322387
323- this . decreaseTimer = setTimeout ( this . decrease , wait ) ;
388+ this . decreaseTimer = setTimeout ( this . decrease . bind ( this ) , wait ) ;
324389 this . onChange ( num ) ;
325390 }
326391
@@ -498,8 +563,8 @@ class InputSpinner extends Component {
498563 return this . maxReached ( )
499564 ? this . _getColorMax ( )
500565 : this . minReached ( )
501- ? this . _getColorMin ( )
502- : this . props . color ;
566+ ? this . _getColorMin ( )
567+ : this . props . color ;
503568 }
504569
505570 /**
@@ -539,8 +604,8 @@ class InputSpinner extends Component {
539604 return this . maxReached ( )
540605 ? this . _getColorMax ( )
541606 : this . minReached ( )
542- ? this . _getColorMin ( )
543- : color ;
607+ ? this . _getColorMin ( )
608+ : color ;
544609 }
545610
546611 /**
@@ -760,8 +825,8 @@ class InputSpinner extends Component {
760825 onShowUnderlay = { this . onShowUnderlay . bind ( this , "left" ) }
761826 disabled = { this . _isDisabledButtonLeft ( ) }
762827 style = { buttonStyle }
763- onPressIn = { this . decrease }
764- onPressOut = { this . clearTimers }
828+ onPressIn = { this . decrease . bind ( this ) }
829+ onPressOut = { this . clearTimers . bind ( this ) }
765830 { ...this . props . leftButtonProps } >
766831 { this . _renderLeftButtonElement ( ) }
767832 </ TouchableHighlight >
@@ -796,8 +861,8 @@ class InputSpinner extends Component {
796861 onShowUnderlay = { this . onShowUnderlay . bind ( this , "right" ) }
797862 disabled = { this . _isDisabledButtonRight ( ) }
798863 style = { buttonStyle }
799- onPressIn = { this . increase }
800- onPressOut = { this . clearTimers }
864+ onPressIn = { this . increase . bind ( this ) }
865+ onPressOut = { this . clearTimers . bind ( this ) }
801866 { ...this . props . rightButtonProps } >
802867 { this . _renderRightButtonElement ( ) }
803868 </ TouchableHighlight >
@@ -819,7 +884,7 @@ class InputSpinner extends Component {
819884 ref = { ( input ) => ( this . textInput = input ) }
820885 style = { this . _getInputTextStyle ( ) }
821886 value = { this . getValue ( ) }
822- placeholder = { this . props . placeholder }
887+ placeholder = { this . getPlaceholder ( ) }
823888 placeholderTextColor = { this . props . placeholderTextColor }
824889 selectionColor = { this . props . selectionColor }
825890 selectTextOnFocus = { this . props . selectTextOnFocus }
@@ -891,8 +956,9 @@ InputSpinner.propTypes = {
891956 onIncrease : PropTypes . func ,
892957 onDecrease : PropTypes . func ,
893958 onSubmit : PropTypes . func ,
894- onLongPressStartTimeout : PropTypes . number ,
895- onLongPressTimeout : PropTypes . number ,
959+ onLongPressDelay : PropTypes . number ,
960+ onLongPressSpeed : PropTypes . number ,
961+ debounceTime : PropTypes . number ,
896962 buttonLeftDisabled : PropTypes . bool ,
897963 buttonRightDisabled : PropTypes . bool ,
898964 buttonLeftText : PropTypes . string ,
@@ -948,8 +1014,9 @@ InputSpinner.defaultProps = {
9481014 returnKeyType : null ,
9491015 width : 150 ,
9501016 height : 50 ,
951- onLongPressStartTimeout : defaultLongPressStartTimeout ,
952- onLongPressTimeout : defaultLongPressTimeout ,
1017+ onLongPressDelay : defaultLongPressDelay ,
1018+ onLongPressSpeed : defaultLongPressSpeed ,
1019+ debounceTime : defaultDebounceTime ,
9531020 buttonLeftDisabled : false ,
9541021 buttonRightDisabled : false ,
9551022 buttonLeftText : null ,
0 commit comments