@@ -11,10 +11,9 @@ import { type Decimal } from '@ui-kit/utils'
1111 * 
1212 * @param  value - The new input value to validate 
1313 * @param  current - The current input value to fall back to if validation fails 
14-  * @param  allowNegative - Whether to allow negative numbers 
1514 * @returns  The validated and normalized input value, or the current value if invalid 
1615 */ 
17- const  sanitize  =  ( value : string ,  current : string ,   allowNegative :  boolean ) : string  =>  { 
16+ const  sanitize  =  ( value : string ,  current : string ) : string  =>  { 
1817  const  normalizedValue  =  value . replace ( / , / g,  '.' ) 
1918
2019  // If more than one decimal point, return the current value (ignore the change) 
@@ -28,13 +27,8 @@ const sanitize = (value: string, current: string, allowNegative: boolean): strin
2827    return  current 
2928  } 
3029
31-   // If negative numbers are not allowed and value starts with minus, ignore the change 
32-   if  ( ! allowNegative  &&  minusIndex  ===  0 )  { 
33-     return  current 
34-   } 
35- 
3630  // Check if it contains only valid characters (numbers, optional minus at start if allowed, and one optional decimal) 
37-   const  pattern  =  allowNegative  ?  / ^ - ? [ 0 - 9 ] * \. ? [ 0 - 9 ] * ( [ e E ] [ - + ] ? [ 0 - 9 ] + ) ? $ /  :  / ^ [ 0 - 9 ] * \. ? [ 0 - 9 ] * ( [ e E ] [ - + ] ? [ 0 - 9 ] + ) ? $ / 
31+   const  pattern  =  / ^ - ? [ 0 - 9 ] * \. ? [ 0 - 9 ] * ( [ e E ] [ - + ] ? [ 0 - 9 ] + ) ? $ / 
3832  return  pattern . test ( normalizedValue )  ? normalizedValue  : current 
3933} 
4034
@@ -72,8 +66,8 @@ type NumericTextFieldProps = Omit<TextFieldProps, 'type' | 'value' | 'onChange'
7266  min ?: Decimal 
7367  /** Maximum allowed value (default: Infinity) */ 
7468  max ?: Decimal 
75-   /** Callback fired when the numeric value changes */ 
76-   onChange ?: ( value : Decimal  |  undefined )  =>  void 
69+   /** Callback fired when the numeric value changes, can be a temporary non decimal value like "5." or "-"  */ 
70+   onChange ?: ( value : string  |  undefined )  =>  void 
7771  /** Callback fired when the numeric is being submitted */ 
7872  onBlur ?: ( value : Decimal  |  undefined )  =>  void 
7973} 
@@ -82,27 +76,14 @@ export const NumericTextField = ({ value, min, max, onChange, onBlur, onFocus, .
8276  // Internal value that might be incomplete, like "4.". 
8377  const  [ inputValue ,  setInputValue ]  =  useState ( getDisplayValue ( value ) ) 
8478
85-   const  [ lastChangeValue ,  setLastChangeValue ]  =  useState ( value ) 
79+   const  [ lastChangeValue ,  setLastChangeValue ]  =  useState < string   |   undefined > ( value ) 
8680  const  [ lastBlurValue ,  setLastBlurValue ]  =  useState ( value ) 
8781
8882  // Update input value when value changes externally 
8983  useEffect ( ( )  =>  { 
9084    setInputValue ( getDisplayValue ( value ) ) 
9185  } ,  [ value ] ) 
9286
93-   /** 
94-    * Converts a string input to a numeric value with optional clamping. 
95-    * 
96-    * @param  validatedValue - The sanitized string input 
97-    * @param  shouldClamp - Whether to apply min/max bounds 
98-    * @returns  Numeric value, undefined for empty/invalid input 
99-    */ 
100-   const  parseAndClamp  =  ( validatedValue : string ,  {  shouldClamp =  false  } : {  shouldClamp ?: boolean  } )  =>  { 
101-     if  ( validatedValue  ===  '' )  return  undefined 
102-     const  result  =  shouldClamp  ? clamp ( validatedValue ,  min ,  max )  : new  BigNumber ( validatedValue ) 
103-     return  result . toString ( )  as  Decimal 
104-   } 
105- 
10687  return  ( 
10788    < TextField 
10889      { ...props } 
@@ -120,19 +101,17 @@ export const NumericTextField = ({ value, min, max, onChange, onBlur, onFocus, .
120101        onFocus ?.( e ) 
121102      } } 
122103      onChange = { ( e )  =>  { 
123-         const  sanitizedValue  =  sanitize ( e . target . value ,  inputValue ,   min   ==   null   ||   + min   <   0 ) 
104+         const  sanitizedValue  =  sanitize ( e . target . value ,  inputValue ) 
124105        setInputValue ( sanitizedValue ) 
125- 
126-         const  changedValue  =  parseAndClamp ( sanitizedValue ,  {  shouldClamp : false  } ) 
127- 
128-         if  ( changedValue  !==  lastChangeValue )  { 
129-           onChange ?.( changedValue ) 
130-           setLastChangeValue ( changedValue ) 
131-         } 
106+         onChange ?.( sanitizedValue ) 
107+         setLastChangeValue ( sanitizedValue ) 
132108      } } 
133109      onBlur = { ( )  =>  { 
134-         // Replace a sole minus with just empty input as it's not really valid. 
135-         const  finalValue  =  parseAndClamp ( inputValue  ===  '-'  ? ''  : inputValue ,  {  shouldClamp : true  } ) 
110+         // Replace a sole invalid values with just empty input as they're not really valid. 
111+         const  invalidValues  =  [ '-' ,  '.' ,  ',' ,  '' ] 
112+         const  finalValue  =  invalidValues . includes ( inputValue ) 
113+           ? undefined 
114+           : ( clamp ( inputValue ,  min ,  max ) . toString ( )  as  Decimal ) 
136115        setInputValue ( getDisplayValue ( finalValue ) ) 
137116
138117        // Also emit the changed event, because due to clamping and such the final value 
0 commit comments