diff --git a/src/components/ScreenWrapper.tsx b/src/components/ScreenWrapper.tsx index e53823860ce..45326ec822d 100644 --- a/src/components/ScreenWrapper.tsx +++ b/src/components/ScreenWrapper.tsx @@ -202,7 +202,7 @@ function ScreenWrapper( // eslint-disable-next-line react-hooks/exhaustive-deps }, []); - const isAvoidingViewportScroll = useTackInputFocus(shouldEnableMaxHeight && shouldAvoidScrollOnVirtualViewport && Browser.isMobileSafari()); + const isAvoidingViewportScroll = useTackInputFocus(shouldEnableMaxHeight && shouldAvoidScrollOnVirtualViewport && Browser.isMobileWebKit()); const contextValue = useMemo(() => ({didScreenTransitionEnd}), [didScreenTransitionEnd]); return ( diff --git a/src/pages/signin/LoginForm/BaseLoginForm.tsx b/src/pages/signin/LoginForm/BaseLoginForm.tsx index 4286a260334..f51fd2fe588 100644 --- a/src/pages/signin/LoginForm/BaseLoginForm.tsx +++ b/src/pages/signin/LoginForm/BaseLoginForm.tsx @@ -2,7 +2,7 @@ import {useIsFocused} from '@react-navigation/native'; import Str from 'expensify-common/lib/str'; import type {ForwardedRef} from 'react'; import React, {forwardRef, useCallback, useEffect, useImperativeHandle, useMemo, useRef, useState} from 'react'; -import {View} from 'react-native'; +import {InteractionManager, View} from 'react-native'; import {withOnyx} from 'react-native-onyx'; import type {OnyxEntry} from 'react-native-onyx'; import DotIndicatorMessage from '@components/DotIndicatorMessage'; @@ -19,6 +19,7 @@ import useNetwork from '@hooks/useNetwork'; import usePrevious from '@hooks/usePrevious'; import useResponsiveLayout from '@hooks/useResponsiveLayout'; import useThemeStyles from '@hooks/useThemeStyles'; +import * as Browser from '@libs/Browser'; import canFocusInputOnScreenFocus from '@libs/canFocusInputOnScreenFocus'; import * as ErrorUtils from '@libs/ErrorUtils'; import isInputAutoFilled from '@libs/isInputAutoFilled'; @@ -35,6 +36,8 @@ import type {TranslationPaths} from '@src/languages/types'; import ONYXKEYS from '@src/ONYXKEYS'; import type {CloseAccountForm} from '@src/types/form'; import type {Account, Credentials} from '@src/types/onyx'; +import htmlDivElementRef from '@src/types/utils/htmlDivElementRef'; +import viewRef from '@src/types/utils/viewRef'; import type LoginFormProps from './types'; import type {InputHandle} from './types'; @@ -216,6 +219,19 @@ function BaseLoginForm({account, credentials, closeAccount, blurOnSubmit = false const serverErrorText = useMemo(() => (account ? ErrorUtils.getLatestErrorMessage(account) : ''), [account]); const shouldShowServerError = !!serverErrorText && !formError; + const submitContainerRef = useRef(null); + const handleFocus = useCallback(() => { + if (!Browser.isMobileWebKit()) { + return; + } + // On mobile WebKit browsers, when an input field gains focus, the keyboard appears and the virtual viewport is resized and scrolled to make the input field visible. + // This occurs even when there is enough space to display both the input field and the submit button in the current view. + // so this change to correct the scroll position when the input field gains focus. + InteractionManager.runAfterInteractions(() => { + htmlDivElementRef(submitContainerRef).current?.scrollIntoView?.({behavior: 'smooth', block: 'end'}); + }); + }, []); + return ( <> +