From 4a3a45dfdf5102be3fdc12d8e70d2f77c438bc63 Mon Sep 17 00:00:00 2001 From: Dan Abramov Date: Sat, 23 Dec 2023 19:30:59 +0000 Subject: [PATCH] Add body scroll lock --- src/lib/hooks/useWebBodyScrollLock.ts | 28 ++++++++++++++++++++++++++ src/view/com/lightbox/Lightbox.web.tsx | 5 ++++- src/view/com/modals/Modal.web.tsx | 2 ++ src/view/shell/Composer.web.tsx | 5 ++++- src/view/shell/index.web.tsx | 2 ++ 5 files changed, 40 insertions(+), 2 deletions(-) create mode 100644 src/lib/hooks/useWebBodyScrollLock.ts diff --git a/src/lib/hooks/useWebBodyScrollLock.ts b/src/lib/hooks/useWebBodyScrollLock.ts new file mode 100644 index 0000000000..585f193f1f --- /dev/null +++ b/src/lib/hooks/useWebBodyScrollLock.ts @@ -0,0 +1,28 @@ +import {useEffect} from 'react' +import {isWeb} from '#/platform/detection' + +let refCount = 0 + +function incrementRefCount() { + if (refCount === 0) { + document.body.style.overflow = 'hidden' + } + refCount++ +} + +function decrementRefCount() { + refCount-- + if (refCount === 0) { + document.body.style.overflow = '' + } +} + +export function useWebBodyScrollLock(isLockActive: boolean) { + useEffect(() => { + if (!isWeb || !isLockActive) { + return + } + incrementRefCount() + return () => decrementRefCount() + }) +} diff --git a/src/view/com/lightbox/Lightbox.web.tsx b/src/view/com/lightbox/Lightbox.web.tsx index 19228570d0..f01b14a44c 100644 --- a/src/view/com/lightbox/Lightbox.web.tsx +++ b/src/view/com/lightbox/Lightbox.web.tsx @@ -23,6 +23,7 @@ import { ImagesLightbox, ProfileImageLightbox, } from '#/state/lightbox' +import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' interface Img { uri: string @@ -32,8 +33,10 @@ interface Img { export function Lightbox() { const {activeLightbox} = useLightbox() const {closeLightbox} = useLightboxControls() + const isActive = !!activeLightbox + useWebBodyScrollLock(isActive) - if (!activeLightbox) { + if (!isActive) { return null } diff --git a/src/view/com/modals/Modal.web.tsx b/src/view/com/modals/Modal.web.tsx index 1510084af4..b73550b581 100644 --- a/src/view/com/modals/Modal.web.tsx +++ b/src/view/com/modals/Modal.web.tsx @@ -3,6 +3,7 @@ import {TouchableWithoutFeedback, StyleSheet, View} from 'react-native' import Animated, {FadeIn, FadeOut} from 'react-native-reanimated' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' import {useModals, useModalControls} from '#/state/modals' import type {Modal as ModalIface} from '#/state/modals' @@ -37,6 +38,7 @@ import * as LinkWarningModal from './LinkWarning' export function ModalsContainer() { const {isModalActive, activeModals} = useModals() + useWebBodyScrollLock(isModalActive) if (!isModalActive) { return null diff --git a/src/view/shell/Composer.web.tsx b/src/view/shell/Composer.web.tsx index 61a3616cb1..2e68508edb 100644 --- a/src/view/shell/Composer.web.tsx +++ b/src/view/shell/Composer.web.tsx @@ -5,6 +5,7 @@ import {ComposePost} from '../com/composer/Composer' import {useComposerState} from 'state/shell/composer' import {usePalette} from 'lib/hooks/usePalette' import {useWebMediaQueries} from 'lib/hooks/useWebMediaQueries' +import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' const BOTTOM_BAR_HEIGHT = 61 @@ -12,11 +13,13 @@ export function Composer({}: {winHeight: number}) { const pal = usePalette('default') const {isMobile} = useWebMediaQueries() const state = useComposerState() + const isActive = !!state + useWebBodyScrollLock(isActive) // rendering // = - if (!state) { + if (!isActive) { return } diff --git a/src/view/shell/index.web.tsx b/src/view/shell/index.web.tsx index cc627da8d1..030a607fcb 100644 --- a/src/view/shell/index.web.tsx +++ b/src/view/shell/index.web.tsx @@ -15,6 +15,7 @@ import {useAuxClick} from 'lib/hooks/useAuxClick' import {t} from '@lingui/macro' import {useIsDrawerOpen, useSetDrawerOpen} from '#/state/shell' import {useCloseAllActiveElements} from '#/state/util' +import {useWebBodyScrollLock} from '#/lib/hooks/useWebBodyScrollLock' function ShellInner() { const isDrawerOpen = useIsDrawerOpen() @@ -23,6 +24,7 @@ function ShellInner() { const navigator = useNavigation() const closeAllActiveElements = useCloseAllActiveElements() + useWebBodyScrollLock(isDrawerOpen) useAuxClick() useEffect(() => {