11import { useIsFocused } from '@react-navigation/native' ;
22import type { ForwardedRef } from 'react' ;
3- import React , { useEffect , useImperativeHandle , useRef , useState } from 'react' ;
3+ import React , { useCallback , useEffect , useImperativeHandle , useRef , useState } from 'react' ;
44import type { NativeSyntheticEvent } from 'react-native' ;
55import { View } from 'react-native' ;
6- import { useMemoizedLazyExpensifyIcons } from '@hooks/useLazyAsset' ;
76import useLocalize from '@hooks/useLocalize' ;
87import { useMouseContext } from '@hooks/useMouseContext' ;
98import usePrevious from '@hooks/usePrevious' ;
@@ -26,6 +25,7 @@ import CONST from '@src/CONST';
2625import BigNumberPad from './BigNumberPad' ;
2726import Button from './Button' ;
2827import FormHelpMessage from './FormHelpMessage' ;
28+ import * as Expensicons from './Icon/Expensicons' ;
2929import ScrollView from './ScrollView' ;
3030import TextInput from './TextInput' ;
3131import isTextInputFocused from './TextInput/BaseTextInput/isTextInputFocused' ;
@@ -84,9 +84,6 @@ type NumberWithSymbolFormProps = {
8484
8585 /** Reference to the outer element */
8686 ref ?: ForwardedRef < BaseTextInputRef > ;
87-
88- /** Callback when the user presses the submit key (Enter) */
89- onSubmitEditing ?: ( ) => void ;
9087} & Omit < TextInputWithSymbolProps , 'formattedAmount' | 'onAmountChange' | 'placeholder' | 'onSelectionChange' | 'onKeyPress' | 'onMouseDown' | 'onMouseUp' > ;
9188
9289type NumberWithSymbolFormRef = {
@@ -148,29 +145,15 @@ function NumberWithSymbolForm({
148145 clearNegative,
149146 ref,
150147 disabled,
151- onSubmitEditing,
152148 ...props
153149} : NumberWithSymbolFormProps ) {
154150 const styles = useThemeStyles ( ) ;
155151 const { toLocaleDigit, numberFormat, translate} = useLocalize ( ) ;
156- const icons = useMemoizedLazyExpensifyIcons ( [ 'DownArrow' , 'PlusMinus' ] as const ) ;
157152
158153 const textInput = useRef < BaseTextInputRef | null > ( null ) ;
159154 const numberRef = useRef < string | undefined > ( undefined ) ;
160155 const [ currentNumber , setCurrentNumber ] = useState ( typeof number === 'string' ? number : '' ) ;
161156
162- // sync currentNumber with number prop when it changes externally
163- useEffect ( ( ) => {
164- const newNumber = typeof number === 'string' ? number : '' ;
165-
166- if ( newNumber === currentNumber || ( newNumber && currentNumber && Number ( newNumber ) === Number ( currentNumber ) ) ) {
167- return ;
168- }
169-
170- setCurrentNumber ( newNumber ) ;
171- // eslint-disable-next-line react-compiler/react-compiler, react-hooks/exhaustive-deps
172- } , [ number ] ) ;
173-
174157 const [ shouldUpdateSelection , setShouldUpdateSelection ] = useState ( true ) ;
175158
176159 const isFocused = useIsFocused ( ) ;
@@ -195,9 +178,9 @@ function NumberWithSymbolForm({
195178 setMouseUp ( ) ;
196179 } ;
197180
198- const clearSelection = ( ) => {
181+ const clearSelection = useCallback ( ( ) => {
199182 setSelection ( { start : selection . end , end : selection . end } ) ;
200- } ;
183+ } , [ selection . end ] ) ;
201184
202185 /**
203186 * Event occurs when a user presses a mouse button over an DOM element.
@@ -223,36 +206,39 @@ function NumberWithSymbolForm({
223206 * Sets the selection and the number accordingly to the number passed to the input
224207 * @param newNumber - Changed number from user input
225208 */
226- const setNewNumber = ( newNumber : string ) => {
227- // Remove spaces from the newNumber number because Safari on iOS adds spaces when pasting a copied number
228- // More info: https://github.com/Expensify/App/issues/16974
229- const newNumberWithoutSpaces = stripSpacesFromAmount ( newNumber ) ;
230- const rawFinalNumber = newNumberWithoutSpaces . includes ( '.' ) ? stripCommaFromAmount ( newNumberWithoutSpaces ) : replaceCommasWithPeriod ( newNumberWithoutSpaces ) ;
231-
232- const finalNumber = handleNegativeAmountFlipping ( rawFinalNumber , allowFlippingAmount , toggleNegative ) ;
233-
234- // Use a shallow copy of selection to trigger setSelection
235- // More info: https://github.com/Expensify/App/issues/16385
236- if ( ! validateAmount ( finalNumber , decimals , maxLength ) ) {
237- setSelection ( ( prevSelection ) => ( { ...prevSelection } ) ) ;
238- return ;
239- }
240-
241- willSelectionBeUpdatedManually . current = true ;
242- let hasSelectionBeenSet = false ;
243- const strippedNumber = stripCommaFromAmount ( finalNumber ) ;
244- numberRef . current = strippedNumber ;
245- setCurrentNumber ( ( prevNumber ) => {
246- const isForwardDelete = prevNumber . length > strippedNumber . length && forwardDeletePressedRef . current ;
247- if ( ! hasSelectionBeenSet ) {
248- hasSelectionBeenSet = true ;
249- setSelection ( ( prevSelection ) => getNewSelection ( prevSelection , isForwardDelete ? strippedNumber . length : prevNumber . length , strippedNumber . length ) ) ;
250- willSelectionBeUpdatedManually . current = false ;
209+ const setNewNumber = useCallback (
210+ ( newNumber : string ) => {
211+ // Remove spaces from the newNumber number because Safari on iOS adds spaces when pasting a copied number
212+ // More info: https://github.com/Expensify/App/issues/16974
213+ const newNumberWithoutSpaces = stripSpacesFromAmount ( newNumber ) ;
214+ const rawFinalNumber = newNumberWithoutSpaces . includes ( '.' ) ? stripCommaFromAmount ( newNumberWithoutSpaces ) : replaceCommasWithPeriod ( newNumberWithoutSpaces ) ;
215+
216+ const finalNumber = handleNegativeAmountFlipping ( rawFinalNumber , allowFlippingAmount , toggleNegative ) ;
217+
218+ // Use a shallow copy of selection to trigger setSelection
219+ // More info: https://github.com/Expensify/App/issues/16385
220+ if ( ! validateAmount ( finalNumber , decimals , maxLength ) ) {
221+ setSelection ( ( prevSelection ) => ( { ...prevSelection } ) ) ;
222+ return ;
251223 }
252- return strippedNumber ;
253- } ) ;
254- onInputChange ?.( strippedNumber ) ;
255- } ;
224+
225+ willSelectionBeUpdatedManually . current = true ;
226+ let hasSelectionBeenSet = false ;
227+ const strippedNumber = stripCommaFromAmount ( finalNumber ) ;
228+ numberRef . current = strippedNumber ;
229+ setCurrentNumber ( ( prevNumber ) => {
230+ const isForwardDelete = prevNumber . length > strippedNumber . length && forwardDeletePressedRef . current ;
231+ if ( ! hasSelectionBeenSet ) {
232+ hasSelectionBeenSet = true ;
233+ setSelection ( ( prevSelection ) => getNewSelection ( prevSelection , isForwardDelete ? strippedNumber . length : prevNumber . length , strippedNumber . length ) ) ;
234+ willSelectionBeUpdatedManually . current = false ;
235+ }
236+ return strippedNumber ;
237+ } ) ;
238+ onInputChange ?.( strippedNumber ) ;
239+ } ,
240+ [ decimals , maxLength , onInputChange , allowFlippingAmount , toggleNegative ] ,
241+ ) ;
256242
257243 /**
258244 * Set a new number number properly formatted, used for the TextInput
@@ -304,34 +290,37 @@ function NumberWithSymbolForm({
304290 * Update number with number or Backspace pressed for BigNumberPad.
305291 * Validate new number with decimal number regex up to 6 digits and 2 decimal digit to enable Next button
306292 */
307- const updateValueNumberPad = ( key : string ) => {
308- if ( shouldUpdateSelection && ! isTextInputFocused ( textInput ) ) {
309- textInput . current ?. focus ( ) ;
310- }
311- // Backspace button is pressed
312- if ( key === '<' || key === 'Backspace' ) {
313- if ( currentNumber . length > 0 ) {
314- const selectionStart = selection . start === selection . end ? selection . start - 1 : selection . start ;
315- const newNumber = `${ currentNumber . substring ( 0 , selectionStart ) } ${ currentNumber . substring ( selection . end ) } ` ;
316- setNewNumber ( addLeadingZero ( newNumber ) ) ;
293+ const updateValueNumberPad = useCallback (
294+ ( key : string ) => {
295+ if ( shouldUpdateSelection && ! isTextInputFocused ( textInput ) ) {
296+ textInput . current ?. focus ( ) ;
317297 }
318- return ;
319- }
320- const newNumber = addLeadingZero ( `${ currentNumber . substring ( 0 , selection . start ) } ${ key } ${ currentNumber . substring ( selection . end ) } ` ) ;
321- setNewNumber ( newNumber ) ;
322- } ;
298+ // Backspace button is pressed
299+ if ( key === '<' || key === 'Backspace' ) {
300+ if ( currentNumber . length > 0 ) {
301+ const selectionStart = selection . start === selection . end ? selection . start - 1 : selection . start ;
302+ const newNumber = `${ currentNumber . substring ( 0 , selectionStart ) } ${ currentNumber . substring ( selection . end ) } ` ;
303+ setNewNumber ( addLeadingZero ( newNumber ) ) ;
304+ }
305+ return ;
306+ }
307+ const newNumber = addLeadingZero ( `${ currentNumber . substring ( 0 , selection . start ) } ${ key } ${ currentNumber . substring ( selection . end ) } ` ) ;
308+ setNewNumber ( newNumber ) ;
309+ } ,
310+ [ currentNumber , selection . start , selection . end , shouldUpdateSelection , setNewNumber ] ,
311+ ) ;
323312
324313 /**
325314 * Update long press number, to remove items pressing on <
326315 *
327316 * @param value - Changed text from user input
328317 */
329- const updateLongPressHandlerState = ( value : boolean ) => {
318+ const updateLongPressHandlerState = useCallback ( ( value : boolean ) => {
330319 setShouldUpdateSelection ( ! value ) ;
331320 if ( ! value && ! isTextInputFocused ( textInput ) ) {
332321 textInput . current ?. focus ( ) ;
333322 }
334- } ;
323+ } , [ ] ) ;
335324
336325 /**
337326 * Input handler to check for a forward-delete key (or keyboard shortcut) press.
@@ -397,7 +386,6 @@ function NumberWithSymbolForm({
397386 autoFocus = { props . autoFocus }
398387 autoGrowExtraSpace = { props . autoGrowExtraSpace }
399388 autoGrowMarginSide = { props . autoGrowMarginSide }
400- onSubmitEditing = { onSubmitEditing }
401389 />
402390 ) ;
403391 }
@@ -484,7 +472,7 @@ function NumberWithSymbolForm({
484472 < Button
485473 shouldShowRightIcon
486474 small
487- iconRight = { icons . DownArrow }
475+ iconRight = { Expensicons . DownArrow }
488476 onPress = { onSymbolButtonPress }
489477 style = { styles . minWidth18 }
490478 isContentCentered
@@ -509,7 +497,7 @@ function NumberWithSymbolForm({
509497 < Button
510498 shouldShowRightIcon
511499 small
512- iconRight = { icons . DownArrow }
500+ iconRight = { Expensicons . DownArrow }
513501 onPress = { onSymbolButtonPress }
514502 style = { styles . minWidth18 }
515503 isContentCentered
@@ -520,7 +508,7 @@ function NumberWithSymbolForm({
520508 < Button
521509 shouldShowRightIcon
522510 small
523- iconRight = { icons . PlusMinus }
511+ iconRight = { Expensicons . PlusMinus }
524512 onPress = { toggleNegative }
525513 style = { styles . minWidth18 }
526514 isContentCentered
0 commit comments