Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

33546 visual viewport deplay #34254

Merged
merged 9 commits into from
Feb 8, 2024
2 changes: 1 addition & 1 deletion src/components/ScreenWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ function ScreenWrapper(
*/
const navigationFallback = useNavigation<StackNavigationProp<RootStackParamList>>();
const navigation = navigationProp ?? navigationFallback;
const {windowHeight, isSmallScreenWidth} = useWindowDimensions();
const {windowHeight, isSmallScreenWidth} = useWindowDimensions(shouldEnableMaxHeight);
const {initialHeight} = useInitialDimensions();
const styles = useThemeStyles();
const keyboardState = useKeyboardState();
Expand Down
64 changes: 62 additions & 2 deletions src/hooks/useWindowDimensions/index.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,83 @@
import {useEffect, useRef, useState} from 'react';
// eslint-disable-next-line no-restricted-imports
import {Dimensions, useWindowDimensions} from 'react-native';
import * as Browser from '@libs/Browser';
import variables from '@styles/variables';
import type WindowDimensions from './types';

const initalViewportHeight = window.visualViewport?.height ?? window.innerHeight;
const tagNamesOpenKeyboard = ['INPUT', 'TEXTAREA'];

/**
* A convenience wrapper around React Native's useWindowDimensions hook that also provides booleans for our breakpoints.
*/
export default function (): WindowDimensions {
export default function (useCachedViewportHeight = false): WindowDimensions {
const isCachedViewportHeight = useCachedViewportHeight && Browser.isMobileSafari();
const cachedViewportHeightWithKeyboardRef = useRef(initalViewportHeight);
const {width: windowWidth, height: windowHeight} = useWindowDimensions();

// When the soft keyboard opens on mWeb, the window height changes. Use static screen height instead to get real screenHeight.
const screenHeight = Dimensions.get('screen').height;
const isExtraSmallScreenHeight = screenHeight <= variables.extraSmallMobileResponsiveHeightBreakpoint;
const isSmallScreenWidth = windowWidth <= variables.mobileResponsiveWidthBreakpoint;
const isMediumScreenWidth = windowWidth > variables.mobileResponsiveWidthBreakpoint && windowWidth <= variables.tabletResponsiveWidthBreakpoint;
const isLargeScreenWidth = windowWidth > variables.tabletResponsiveWidthBreakpoint;

const [cachedViewportHeight, setCachedViewportHeight] = useState(windowHeight);

const handleFocusIn = useRef((event: FocusEvent) => {
const targetElement = event.target as HTMLElement;
if (tagNamesOpenKeyboard.includes(targetElement.tagName)) {
setCachedViewportHeight(cachedViewportHeightWithKeyboardRef.current);
}
});

useEffect(() => {
if (!isCachedViewportHeight) {
return;
}
window.addEventListener('focusin', handleFocusIn.current);
return () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
window.removeEventListener('focusin', handleFocusIn.current);
};
}, [isCachedViewportHeight]);

const handleFocusOut = useRef((event: FocusEvent) => {
const targetElement = event.target as HTMLElement;
if (tagNamesOpenKeyboard.includes(targetElement.tagName)) {
setCachedViewportHeight(initalViewportHeight);
}
});

useEffect(() => {
if (!isCachedViewportHeight) {
return;
}
window.addEventListener('focusout', handleFocusOut.current);
return () => {
// eslint-disable-next-line react-hooks/exhaustive-deps
window.removeEventListener('focusout', handleFocusOut.current);
};
}, [isCachedViewportHeight]);

useEffect(() => {
if (!isCachedViewportHeight && windowHeight >= cachedViewportHeightWithKeyboardRef.current) {
return;
}
setCachedViewportHeight(windowHeight);
}, [windowHeight, isCachedViewportHeight]);

useEffect(() => {
if (!isCachedViewportHeight || !window.matchMedia('(orientation: portrait)').matches || windowHeight >= initalViewportHeight) {
return;
}
cachedViewportHeightWithKeyboardRef.current = windowHeight;
}, [isCachedViewportHeight, windowHeight]);

return {
windowWidth,
windowHeight,
windowHeight: isCachedViewportHeight ? cachedViewportHeight : windowHeight,
isExtraSmallScreenHeight,
isSmallScreenWidth,
isMediumScreenWidth,
Expand Down
Loading