From 6364bc0a25854b336aa44e3794ce86f3aafacd18 Mon Sep 17 00:00:00 2001 From: Cong Pham Date: Tue, 9 Jul 2024 01:42:37 +0700 Subject: [PATCH] handle visual viewport scroll incorrect on chrome ios --- src/hooks/useTackInputFocus/index.ts | 9 ++++++++- src/hooks/useWindowDimensions/index.ts | 2 +- src/libs/Browser/index.ts | 6 ++++-- src/libs/Browser/index.website.ts | 12 ++++++++++-- src/libs/Browser/types.ts | 4 +++- src/pages/signin/SignInPage.tsx | 1 + 6 files changed, 27 insertions(+), 7 deletions(-) diff --git a/src/hooks/useTackInputFocus/index.ts b/src/hooks/useTackInputFocus/index.ts index 124f8460127c..e6caa15f9dde 100644 --- a/src/hooks/useTackInputFocus/index.ts +++ b/src/hooks/useTackInputFocus/index.ts @@ -1,5 +1,6 @@ import {useCallback, useEffect} from 'react'; import useDebouncedState from '@hooks/useDebouncedState'; +import * as Browser from '@libs/Browser'; /** * Detects input or text area focus on browsers, to avoid scrolling on virtual viewports @@ -28,7 +29,13 @@ export default function useTackInputFocus(enable = false): boolean { ); const resetScrollPositionOnVisualViewport = useCallback(() => { - window.scrollTo({top: 0}); + if (Browser.isChromeIOS() && window.visualViewport?.offsetTop) { + // On Chrome iOS, the visual viewport triggers a scroll event when the keyboard is opened, but some time the scroll position is not correct. + // So this change is specific to Chrome iOS, helping to reset the viewport position correctly. + window.scrollTo({top: -window.visualViewport.offsetTop}); + } else { + window.scrollTo({top: 0}); + } }, []); useEffect(() => { diff --git a/src/hooks/useWindowDimensions/index.ts b/src/hooks/useWindowDimensions/index.ts index 25757fda17e5..b391e45a61aa 100644 --- a/src/hooks/useWindowDimensions/index.ts +++ b/src/hooks/useWindowDimensions/index.ts @@ -23,7 +23,7 @@ export default function (useCachedViewportHeight = false): WindowDimensions { unlockWindowDimensions: () => {}, }; - const isCachedViewportHeight = useCachedViewportHeight && Browser.isMobileSafari(); + const isCachedViewportHeight = useCachedViewportHeight && Browser.isMobileWebKit(); const cachedViewportHeightWithKeyboardRef = useRef(initalViewportHeight); const {width: windowWidth, height: windowHeight} = useWindowDimensions(); diff --git a/src/libs/Browser/index.ts b/src/libs/Browser/index.ts index 98ad449c3dd0..aeec4f4def4a 100644 --- a/src/libs/Browser/index.ts +++ b/src/libs/Browser/index.ts @@ -1,4 +1,4 @@ -import type {GetBrowser, IsMobile, IsMobileChrome, IsMobileSafari, IsMobileWebKit, IsSafari, OpenRouteInDesktopApp} from './types'; +import type {GetBrowser, IsChromeIOS, IsMobile, IsMobileChrome, IsMobileSafari, IsMobileWebKit, IsSafari, OpenRouteInDesktopApp} from './types'; const getBrowser: GetBrowser = () => ''; @@ -10,8 +10,10 @@ const isMobileChrome: IsMobileChrome = () => false; const isMobileWebKit: IsMobileWebKit = () => false; +const isChromeIOS: IsChromeIOS = () => false; + const isSafari: IsSafari = () => false; const openRouteInDesktopApp: OpenRouteInDesktopApp = () => {}; -export {getBrowser, isMobile, isMobileSafari, isMobileWebKit, isSafari, isMobileChrome, openRouteInDesktopApp}; +export {getBrowser, isMobile, isMobileSafari, isMobileWebKit, isSafari, isMobileChrome, isChromeIOS, openRouteInDesktopApp}; diff --git a/src/libs/Browser/index.website.ts b/src/libs/Browser/index.website.ts index a83fa1cac70e..b89190dc7f78 100644 --- a/src/libs/Browser/index.website.ts +++ b/src/libs/Browser/index.website.ts @@ -1,7 +1,7 @@ import CONFIG from '@src/CONFIG'; import CONST from '@src/CONST'; import ROUTES from '@src/ROUTES'; -import type {GetBrowser, IsMobile, IsMobileChrome, IsMobileSafari, IsMobileWebKit, IsSafari, OpenRouteInDesktopApp} from './types'; +import type {GetBrowser, IsChromeIOS, IsMobile, IsMobileChrome, IsMobileSafari, IsMobileWebKit, IsSafari, OpenRouteInDesktopApp} from './types'; /** * Fetch browser name from UA string @@ -66,6 +66,14 @@ const isMobileWebKit: IsMobileWebKit = () => { return /iP(ad|od|hone)/i.test(userAgent) && /WebKit/i.test(userAgent); }; +/** + * Checks if the requesting user agent is a Chrome browser on an iOS mobile device. + */ +const isChromeIOS: IsChromeIOS = () => { + const userAgent = navigator.userAgent; + return /iP(ad|od|hone)/i.test(userAgent) && /CriOS/i.test(userAgent); +}; + const isSafari: IsSafari = () => getBrowser() === 'safari' || isMobileSafari(); /** @@ -109,4 +117,4 @@ const openRouteInDesktopApp: OpenRouteInDesktopApp = (shortLivedAuthToken = '', } }; -export {getBrowser, isMobile, isMobileSafari, isMobileWebKit, isSafari, isMobileChrome, openRouteInDesktopApp}; +export {getBrowser, isMobile, isMobileSafari, isMobileWebKit, isSafari, isMobileChrome, isChromeIOS, openRouteInDesktopApp}; diff --git a/src/libs/Browser/types.ts b/src/libs/Browser/types.ts index 25f305953c87..cb242d3729aa 100644 --- a/src/libs/Browser/types.ts +++ b/src/libs/Browser/types.ts @@ -8,8 +8,10 @@ type IsMobileChrome = () => boolean; type IsMobileWebKit = () => boolean; +type IsChromeIOS = () => boolean; + type IsSafari = () => boolean; type OpenRouteInDesktopApp = (shortLivedAuthToken?: string, email?: string) => void; -export type {GetBrowser, IsMobile, IsMobileSafari, IsMobileChrome, IsMobileWebKit, IsSafari, OpenRouteInDesktopApp}; +export type {GetBrowser, IsMobile, IsMobileSafari, IsMobileChrome, IsMobileWebKit, IsSafari, IsChromeIOS, OpenRouteInDesktopApp}; diff --git a/src/pages/signin/SignInPage.tsx b/src/pages/signin/SignInPage.tsx index 0b4310cce337..024d5a7c5610 100644 --- a/src/pages/signin/SignInPage.tsx +++ b/src/pages/signin/SignInPage.tsx @@ -266,6 +266,7 @@ function SignInPage({credentials, account, activeClients = [], preferredLocale,