From 07172be78b25278b0888f84bdfb3674e2d5b7726 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Miko=C5=82ajczak?= Date: Thu, 28 Sep 2023 19:07:24 +0200 Subject: [PATCH 1/4] Fix refs --- src/pages/ReimbursementAccount/RequestorStep.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 53ca279c2cb2..324e15f3aac6 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -72,7 +72,7 @@ const validate = (values) => { return errors; }; -function RequestorStep({reimbursementAccount, shouldShowOnfido, reimbursementAccountDraft, onBackButtonPress, getDefaultStateForField}) { +const RequestorStep = React.forwardRef(({reimbursementAccount, shouldShowOnfido, reimbursementAccountDraft, onBackButtonPress, getDefaultStateForField}, ref) => { const {translate} = useLocalize(); const defaultValues = useMemo( @@ -110,6 +110,7 @@ function RequestorStep({reimbursementAccount, shouldShowOnfido, reimbursementAcc if (shouldShowOnfido) { return ( @@ -194,9 +196,9 @@ function RequestorStep({reimbursementAccount, shouldShowOnfido, reimbursementAcc ); -} +}); RequestorStep.propTypes = propTypes; RequestorStep.displayName = 'RequestorStep'; -export default React.forwardRef(RequestorStep); +export default RequestorStep; From a8e58e5e64ed723bd52b1dc3e654383c9909ca0b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Miko=C5=82ajczak?= Date: Fri, 29 Sep 2023 12:48:53 +0200 Subject: [PATCH 2/4] add clarifying comment --- src/pages/ReimbursementAccount/RequestorStep.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/pages/ReimbursementAccount/RequestorStep.js b/src/pages/ReimbursementAccount/RequestorStep.js index 324e15f3aac6..2cfea88b0c5c 100644 --- a/src/pages/ReimbursementAccount/RequestorStep.js +++ b/src/pages/ReimbursementAccount/RequestorStep.js @@ -72,6 +72,10 @@ const validate = (values) => { return errors; }; +/** + * Workaround for forwardRef + propTypes issue. + * See https://stackoverflow.com/questions/59716140/using-forwardref-with-proptypes-and-eslint + */ const RequestorStep = React.forwardRef(({reimbursementAccount, shouldShowOnfido, reimbursementAccountDraft, onBackButtonPress, getDefaultStateForField}, ref) => { const {translate} = useLocalize(); From cda0b1fd18b0ac3243f7864d56bd0ebfad6b6cc2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Miko=C5=82ajczak?= Date: Tue, 10 Oct 2023 10:57:31 +0200 Subject: [PATCH 3/4] forward ref in ScreenWrapper --- src/components/ScreenWrapper/index.js | 242 +++++++++++++------------- 1 file changed, 124 insertions(+), 118 deletions(-) diff --git a/src/components/ScreenWrapper/index.js b/src/components/ScreenWrapper/index.js index e2af40589a8a..b73dae645bf1 100644 --- a/src/components/ScreenWrapper/index.js +++ b/src/components/ScreenWrapper/index.js @@ -20,142 +20,148 @@ import useKeyboardState from '../../hooks/useKeyboardState'; import useEnvironment from '../../hooks/useEnvironment'; import useNetwork from '../../hooks/useNetwork'; -function ScreenWrapper({ - shouldEnableMaxHeight, - includePaddingTop, - keyboardAvoidingViewBehavior, - includeSafeAreaPaddingBottom, - shouldEnableKeyboardAvoidingView, - shouldEnablePickerAvoiding, - headerGapStyles, - children, - shouldShowOfflineIndicator, - offlineIndicatorStyle, - style, - shouldDismissKeyboardBeforeClose, - onEntryTransitionEnd, - testID, -}) { - const {windowHeight, isSmallScreenWidth} = useWindowDimensions(); - const keyboardState = useKeyboardState(); - const {isDevelopment} = useEnvironment(); - const {isOffline} = useNetwork(); - const navigation = useNavigation(); - const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); - const maxHeight = shouldEnableMaxHeight ? windowHeight : undefined; - const isKeyboardShown = lodashGet(keyboardState, 'isKeyboardShown', false); +const ScreenWrapper = React.forwardRef( + ( + { + shouldEnableMaxHeight, + includePaddingTop, + keyboardAvoidingViewBehavior, + includeSafeAreaPaddingBottom, + shouldEnableKeyboardAvoidingView, + shouldEnablePickerAvoiding, + headerGapStyles, + children, + shouldShowOfflineIndicator, + offlineIndicatorStyle, + style, + shouldDismissKeyboardBeforeClose, + onEntryTransitionEnd, + testID, + }, + ref, + ) => { + const {windowHeight, isSmallScreenWidth} = useWindowDimensions(); + const keyboardState = useKeyboardState(); + const {isDevelopment} = useEnvironment(); + const {isOffline} = useNetwork(); + const navigation = useNavigation(); + const [didScreenTransitionEnd, setDidScreenTransitionEnd] = useState(false); + const maxHeight = shouldEnableMaxHeight ? windowHeight : undefined; + const isKeyboardShown = lodashGet(keyboardState, 'isKeyboardShown', false); - const panResponder = useRef( - PanResponder.create({ - onStartShouldSetPanResponderCapture: (e, gestureState) => gestureState.numberActiveTouches === CONST.TEST_TOOL.NUMBER_OF_TAPS, - onPanResponderRelease: toggleTestToolsModal, - }), - ).current; + const panResponder = useRef( + PanResponder.create({ + onStartShouldSetPanResponderCapture: (e, gestureState) => gestureState.numberActiveTouches === CONST.TEST_TOOL.NUMBER_OF_TAPS, + onPanResponderRelease: toggleTestToolsModal, + }), + ).current; - const keyboardDissmissPanResponder = useRef( - PanResponder.create({ - onMoveShouldSetPanResponderCapture: (e, gestureState) => { - const isHorizontalSwipe = Math.abs(gestureState.dx) > Math.abs(gestureState.dy); - const shouldDismissKeyboard = shouldDismissKeyboardBeforeClose && isKeyboardShown && Browser.isMobile(); + const keyboardDissmissPanResponder = useRef( + PanResponder.create({ + onMoveShouldSetPanResponderCapture: (e, gestureState) => { + const isHorizontalSwipe = Math.abs(gestureState.dx) > Math.abs(gestureState.dy); + const shouldDismissKeyboard = shouldDismissKeyboardBeforeClose && isKeyboardShown && Browser.isMobile(); - return isHorizontalSwipe && shouldDismissKeyboard; - }, - onPanResponderGrant: Keyboard.dismiss, - }), - ).current; + return isHorizontalSwipe && shouldDismissKeyboard; + }, + onPanResponderGrant: Keyboard.dismiss, + }), + ).current; - useEffect(() => { - const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', (event) => { - // Prevent firing the prop callback when user is exiting the page. - if (lodashGet(event, 'data.closing')) { - return; - } + useEffect(() => { + const unsubscribeTransitionEnd = navigation.addListener('transitionEnd', (event) => { + // Prevent firing the prop callback when user is exiting the page. + if (lodashGet(event, 'data.closing')) { + return; + } - setDidScreenTransitionEnd(true); - onEntryTransitionEnd(); - }); + setDidScreenTransitionEnd(true); + onEntryTransitionEnd(); + }); - // We need to have this prop to remove keyboard before going away from the screen, to avoid previous screen look weird for a brief moment, - // also we need to have generic control in future - to prevent closing keyboard for some rare cases in which beforeRemove has limitations - // described here https://reactnavigation.org/docs/preventing-going-back/#limitations - const beforeRemoveSubscription = shouldDismissKeyboardBeforeClose - ? navigation.addListener('beforeRemove', () => { - if (!isKeyboardShown) { - return; - } - Keyboard.dismiss(); - }) - : undefined; + // We need to have this prop to remove keyboard before going away from the screen, to avoid previous screen look weird for a brief moment, + // also we need to have generic control in future - to prevent closing keyboard for some rare cases in which beforeRemove has limitations + // described here https://reactnavigation.org/docs/preventing-going-back/#limitations + const beforeRemoveSubscription = shouldDismissKeyboardBeforeClose + ? navigation.addListener('beforeRemove', () => { + if (!isKeyboardShown) { + return; + } + Keyboard.dismiss(); + }) + : undefined; - return () => { - unsubscribeTransitionEnd(); + return () => { + unsubscribeTransitionEnd(); - if (beforeRemoveSubscription) { - beforeRemoveSubscription(); - } - }; - // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); + if (beforeRemoveSubscription) { + beforeRemoveSubscription(); + } + }; + // Rule disabled because this effect is only for component did mount & will component unmount lifecycle event + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); - return ( - - {({insets, paddingTop, paddingBottom, safeAreaPaddingBottomStyle}) => { - const paddingStyle = {}; + return ( + + {({insets, paddingTop, paddingBottom, safeAreaPaddingBottomStyle}) => { + const paddingStyle = {}; - if (includePaddingTop) { - paddingStyle.paddingTop = paddingTop; - } + if (includePaddingTop) { + paddingStyle.paddingTop = paddingTop; + } - // We always need the safe area padding bottom if we're showing the offline indicator since it is bottom-docked. - if (includeSafeAreaPaddingBottom || isOffline) { - paddingStyle.paddingBottom = paddingBottom; - } + // We always need the safe area padding bottom if we're showing the offline indicator since it is bottom-docked. + if (includeSafeAreaPaddingBottom || isOffline) { + paddingStyle.paddingBottom = paddingBottom; + } - return ( - + return ( - - - - {isDevelopment && } - {isDevelopment && } - { - // If props.children is a function, call it to provide the insets to the children. - _.isFunction(children) - ? children({ - insets, - safeAreaPaddingBottomStyle, - didScreenTransitionEnd, - }) - : children - } - {isSmallScreenWidth && shouldShowOfflineIndicator && } - - + + + {isDevelopment && } + {isDevelopment && } + { + // If props.children is a function, call it to provide the insets to the children. + _.isFunction(children) + ? children({ + insets, + safeAreaPaddingBottomStyle, + didScreenTransitionEnd, + }) + : children + } + {isSmallScreenWidth && shouldShowOfflineIndicator && } + + + - - ); - }} - - ); -} + ); + }} + + ); + }, +); ScreenWrapper.displayName = 'ScreenWrapper'; ScreenWrapper.propTypes = propTypes; From 4e8f849d19efcab82582e1b878880b47543ded5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kacper=20Miko=C5=82ajczak?= Date: Mon, 6 Nov 2023 10:16:04 +0100 Subject: [PATCH 4/4] fix android DatePicker propTypes --- src/components/DatePicker/index.android.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/DatePicker/index.android.js b/src/components/DatePicker/index.android.js index 561fc700b6a5..587439208fe6 100644 --- a/src/components/DatePicker/index.android.js +++ b/src/components/DatePicker/index.android.js @@ -7,7 +7,7 @@ import styles from '@styles/styles'; import CONST from '@src/CONST'; import {defaultProps, propTypes} from './datepickerPropTypes'; -function DatePicker({value, defaultValue, label, placeholder, errorText, containerStyles, disabled, onBlur, onInputChange, maxDate, minDate}, outerRef) { +const DatePicker = forwardRef(({value, defaultValue, label, placeholder, errorText, containerStyles, disabled, onBlur, onInputChange, maxDate, minDate}, outerRef) => { const ref = useRef(); const [isPickerVisible, setIsPickerVisible] = useState(false); @@ -70,10 +70,10 @@ function DatePicker({value, defaultValue, label, placeholder, errorText, contain )} ); -} +}); DatePicker.propTypes = propTypes; DatePicker.defaultProps = defaultProps; DatePicker.displayName = 'DatePicker'; -export default forwardRef(DatePicker); +export default DatePicker;