@@ -38,31 +38,6 @@ function isValidNumber(value: number | string | undefined): value is number {
38
38
) ;
39
39
}
40
40
41
- interface GetDecrementedValueInput {
42
- value : number ;
43
- min : number | undefined ;
44
- step : number | undefined ;
45
- allowNegative : boolean | undefined ;
46
- }
47
-
48
- function getDecrementedValue ( { value, min, step = 1 , allowNegative } : GetDecrementedValueInput ) {
49
- const nextValue = value - step ;
50
-
51
- if ( min !== undefined && nextValue < min ) {
52
- return min ;
53
- }
54
-
55
- if ( ! allowNegative && nextValue < 0 && min === undefined ) {
56
- return value ;
57
- }
58
-
59
- if ( min !== undefined && min >= 0 && nextValue <= min ) {
60
- return nextValue ;
61
- }
62
-
63
- return nextValue ;
64
- }
65
-
66
41
function isInRange ( value : number | undefined , min : number | undefined , max : number | undefined ) {
67
42
if ( value === undefined ) {
68
43
return true ;
@@ -266,38 +241,58 @@ export const NumberInput = factory<NumberInputFactory>((_props, ref) => {
266
241
onValueChange ?.( payload , event ) ;
267
242
} ;
268
243
244
+ const getDecimalPlaces = ( inputValue : number | string ) : number => {
245
+ const match = String ( inputValue ) . match ( / (?: \. ( \d + ) ) ? (?: [ e E ] ( [ + - ] ? \d + ) ) ? $ / ) ;
246
+ if ( ! match ) {
247
+ return 0 ;
248
+ }
249
+ return Math . max ( 0 , ( match [ 1 ] ? match [ 1 ] . length : 0 ) - ( match [ 2 ] ? + match [ 2 ] : 0 ) ) ;
250
+ } ;
251
+
269
252
const incrementRef = useRef < ( ) => void > ( ) ;
270
253
incrementRef . current = ( ) => {
271
254
let val : number ;
255
+ const currentValuePrecision = getDecimalPlaces ( _value ) ;
256
+ const stepPrecision = getDecimalPlaces ( step ! ) ;
257
+ const maxPrecision = Math . max ( currentValuePrecision , stepPrecision ) ;
258
+ const factor = 10 ** maxPrecision ;
272
259
273
260
if ( typeof _value !== 'number' || Number . isNaN ( _value ) ) {
274
261
val = clamp ( startValue ! , min , max ) ;
275
262
} else if ( max !== undefined ) {
276
- val = _value + step ! <= max ? _value + step ! : max ;
263
+ const incrementedValue = ( Math . round ( _value * factor ) + Math . round ( step ! * factor ) ) / factor ;
264
+ val = incrementedValue <= max ? incrementedValue : max ;
277
265
} else {
278
- val = _value + step ! ;
266
+ val = ( Math . round ( _value * factor ) + Math . round ( step ! * factor ) ) / factor ;
279
267
}
280
268
281
- setValue ( val ) ;
269
+ const formattedValue = val . toFixed ( maxPrecision ) ;
270
+ setValue ( parseFloat ( formattedValue ) ) ;
282
271
onValueChange ?.(
283
- { floatValue : val , formattedValue : val . toString ( ) , value : val . toString ( ) } ,
272
+ { floatValue : parseFloat ( formattedValue ) , formattedValue, value : formattedValue } ,
284
273
{ source : 'increment' as any }
285
274
) ;
286
275
} ;
287
276
288
277
const decrementRef = useRef < ( ) => void > ( ) ;
289
278
decrementRef . current = ( ) => {
290
279
let val : number ;
280
+ const currentValuePrecision = getDecimalPlaces ( _value ) ;
281
+ const stepPrecision = getDecimalPlaces ( step ! ) ;
282
+ const maxPrecision = Math . max ( currentValuePrecision , stepPrecision ) ;
283
+ const factor = 10 ** maxPrecision ;
291
284
292
285
if ( typeof _value !== 'number' || Number . isNaN ( _value ) ) {
293
286
val = clamp ( startValue ! , min , max ) ;
294
287
} else {
295
- val = getDecrementedValue ( { value : _value , min, step, allowNegative } ) ;
288
+ const decrementedValue = ( Math . round ( _value * factor ) - Math . round ( step ! * factor ) ) / factor ;
289
+ val = min !== undefined && decrementedValue < min ? min : decrementedValue ;
296
290
}
297
291
298
- setValue ( val ) ;
292
+ const formattedValue = val . toFixed ( maxPrecision ) ;
293
+ setValue ( parseFloat ( formattedValue ) ) ;
299
294
onValueChange ?.(
300
- { floatValue : val , formattedValue : val . toString ( ) , value : val . toString ( ) } ,
295
+ { floatValue : parseFloat ( formattedValue ) , formattedValue, value : formattedValue } ,
301
296
{ source : 'decrement' as any }
302
297
) ;
303
298
} ;
0 commit comments