@@ -2,7 +2,7 @@ import * as React from '@theia/core/shared/react';
22import classnames from 'classnames' ;
33
44interface SettingsStepInputProps {
5- value : number ;
5+ initialValue : number ;
66 setSettingsStateValue : ( value : number ) => void ;
77 step : number ;
88 maxValue : number ;
@@ -15,7 +15,7 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
1515 props : SettingsStepInputProps
1616) => {
1717 const {
18- value ,
18+ initialValue ,
1919 setSettingsStateValue,
2020 step,
2121 maxValue,
@@ -24,18 +24,35 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
2424 classNames,
2525 } = props ;
2626
27+ const [ valueState , setValueState ] = React . useState < {
28+ currentValue : number ;
29+ isEmptyString : boolean ;
30+ } > ( {
31+ currentValue : initialValue ,
32+ isEmptyString : false ,
33+ } ) ;
34+ const { currentValue, isEmptyString } = valueState ;
35+
2736 const clamp = ( value : number , min : number , max : number ) : number => {
2837 return Math . min ( Math . max ( value , min ) , max ) ;
2938 } ;
3039
40+ const resetToInitialState = ( ) : void => {
41+ setValueState ( {
42+ currentValue : initialValue ,
43+ isEmptyString : false ,
44+ } ) ;
45+ } ;
46+
3147 const onStep = (
3248 roundingOperation : 'ceil' | 'floor' ,
3349 stepOperation : ( a : number , b : number ) => number
3450 ) : void => {
35- const valueRoundedToScale = Math [ roundingOperation ] ( value / step ) * step ;
51+ const valueRoundedToScale =
52+ Math [ roundingOperation ] ( currentValue / step ) * step ;
3653 const calculatedValue =
37- valueRoundedToScale === value
38- ? stepOperation ( value , step )
54+ valueRoundedToScale === currentValue
55+ ? stepOperation ( currentValue , step )
3956 : valueRoundedToScale ;
4057 const newValue = clamp ( calculatedValue , minValue , maxValue ) ;
4158
@@ -52,33 +69,53 @@ const SettingsStepInput: React.FC<SettingsStepInputProps> = (
5269
5370 const onUserInput = ( event : React . ChangeEvent < HTMLInputElement > ) : void => {
5471 const { value : eventValue } = event . target ;
72+ setValueState ( {
73+ currentValue : Number ( eventValue ) ,
74+ isEmptyString : eventValue === '' ,
75+ } ) ;
76+ } ;
5577
56- if ( eventValue === '' ) {
57- setSettingsStateValue ( 0 ) ;
78+ /* Prevent the user from entering invalid values */
79+ const onBlur = ( event : React . FocusEvent ) : void => {
80+ if (
81+ ( currentValue === initialValue && ! isEmptyString ) ||
82+ event . currentTarget . contains ( event . relatedTarget as Node )
83+ ) {
84+ return ;
5885 }
5986
60- const number = Number ( eventValue ) ;
61-
62- if ( ! isNaN ( number ) && number !== value ) {
63- const newValue = clamp ( number , minValue , maxValue ) ;
64-
65- setSettingsStateValue ( newValue ) ;
87+ const clampedValue = clamp ( currentValue , minValue , maxValue ) ;
88+ if ( clampedValue === initialValue || isNaN ( currentValue ) || isEmptyString ) {
89+ resetToInitialState ( ) ;
90+ return ;
6691 }
92+
93+ setSettingsStateValue ( clampedValue ) ;
6794 } ;
6895
69- const upDisabled = value >= maxValue ;
70- const downDisabled = value <= minValue ;
96+ const valueIsNotWithinRange =
97+ currentValue < minValue || currentValue > maxValue ;
98+ const isDisabledException =
99+ valueIsNotWithinRange || isEmptyString || isNaN ( currentValue ) ;
100+
101+ const upDisabled = isDisabledException || currentValue >= maxValue ;
102+ const downDisabled = isDisabledException || currentValue <= minValue ;
71103
72104 return (
73- < div className = "settings-step-input-container" >
105+ < div className = "settings-step-input-container" onBlur = { onBlur } >
74106 < input
75107 className = { classnames ( 'settings-step-input-element' , classNames ?. input ) }
76- value = { value . toString ( ) }
108+ value = { isEmptyString ? '' : String ( currentValue ) }
77109 onChange = { onUserInput }
78110 type = "number"
79111 pattern = "[0-9]+"
80112 />
81- < div className = "settings-step-input-buttons-container" >
113+ < div
114+ className = { classnames (
115+ 'settings-step-input-buttons-container' ,
116+ classNames ?. buttonsContainer
117+ ) }
118+ >
82119 < button
83120 className = "settings-step-input-button settings-step-input-up-button"
84121 disabled = { upDisabled }
0 commit comments