This commit is contained in:
weretere 2026-04-29 16:39:51 +01:00 committed by GitHub
commit b3390912cc
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 25 additions and 15 deletions

View file

@ -30,12 +30,6 @@
overflow: hidden !important;
}
.modalOpenIOS {
position: fixed;
right: 0;
left: 0;
}
/*
* Sizes
*/

View file

@ -10,7 +10,6 @@ interface CssExports {
'modalBackdrop': string;
'modalContainer': string;
'modalOpen': string;
'modalOpenIOS': string;
'small': string;
}
export const cssExports: CssExports;

View file

@ -12,7 +12,7 @@ import FocusLock from 'react-focus-lock';
import ErrorBoundary from 'Components/Error/ErrorBoundary';
import usePrevious from 'Helpers/Hooks/usePrevious';
import { Size } from 'Helpers/Props/sizes';
import { isIOS } from 'Utilities/browser';
import { isMobile } from 'Utilities/browser';
import * as keyCodes from 'Utilities/Constants/keyCodes';
import { setScrollLock } from 'Utilities/scrollLock';
import ModalError from './ModalError';
@ -29,6 +29,21 @@ function removeFromOpenModals(id: string) {
}
}
// Mobile scroll lock: block touchmove outside the modal portal. Avoids
// mutating body position/overflow — doing so resets window.scrollY to 0,
// which causes react-virtualized WindowScroller to unmount the row that
// owns the just-opened modal (Discover page regression).
function preventTouchScroll(event: TouchEvent) {
let target = event.target as HTMLElement | null;
while (target) {
if (target.id === 'portal-root') {
return;
}
target = target.parentElement;
}
event.preventDefault();
}
function findEventTarget(event: TouchEvent | MouseEvent) {
if ('changedTouches' in event) {
const changedTouches = event.changedTouches;
@ -70,7 +85,6 @@ function Modal({
}: ModalProps) {
const backgroundRef = useRef<HTMLDivElement>(null);
const isBackdropPressed = useRef(false);
const bodyScrollTop = useRef(0);
const wasOpen = usePrevious(isOpen);
const modalId = useId();
@ -125,10 +139,14 @@ function Modal({
openModals.push(modalId);
if (openModals.length === 1) {
if (isIOS()) {
if (isMobile()) {
// Don't mutate body position/overflow on mobile — it resets
// window.scrollY which makes WindowScroller unmount this row's
// modal. Use a touchmove listener to block scroll instead.
setScrollLock(true);
bodyScrollTop.current = document.body.scrollTop;
elementClass(document.body).add(styles.modalOpenIOS);
document.addEventListener('touchmove', preventTouchScroll, {
passive: false,
});
} else {
elementClass(document.body).add(styles.modalOpen);
}
@ -139,9 +157,8 @@ function Modal({
if (openModals.length === 0) {
setScrollLock(false);
if (isIOS()) {
elementClass(document.body).remove(styles.modalOpenIOS);
document.body.scrollTop = bodyScrollTop.current;
if (isMobile()) {
document.removeEventListener('touchmove', preventTouchScroll);
} else {
elementClass(document.body).remove(styles.modalOpen);
}