Enhance scroll locking in ConnectionModal and TopUpModal: improve cross-platform support by adding touchmove event prevention for Android, and update styling to ensure consistent behavior and responsiveness across devices.

This commit is contained in:
PEDZEO
2026-01-20 03:46:27 +03:00
parent d54279baf7
commit 626a0b8da6
2 changed files with 43 additions and 2 deletions

View File

@@ -237,7 +237,7 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
modalContentRef.current?.scrollTo({ top: 0, behavior: 'instant' }) modalContentRef.current?.scrollTo({ top: 0, behavior: 'instant' })
}, [showAppSelector]) }, [showAppSelector])
// Scroll lock when modal is open (cross-platform) // Scroll lock when modal is open (cross-platform including Android)
useEffect(() => { useEffect(() => {
const scrollY = window.scrollY const scrollY = window.scrollY
const body = document.body const body = document.body
@@ -249,7 +249,10 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
bodyPosition: body.style.position, bodyPosition: body.style.position,
bodyTop: body.style.top, bodyTop: body.style.top,
bodyWidth: body.style.width, bodyWidth: body.style.width,
bodyHeight: body.style.height,
htmlOverflow: html.style.overflow, htmlOverflow: html.style.overflow,
htmlHeight: html.style.height,
bodyTouchAction: body.style.touchAction,
} }
// Lock scroll // Lock scroll
@@ -257,14 +260,30 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
body.style.position = 'fixed' body.style.position = 'fixed'
body.style.top = `-${scrollY}px` body.style.top = `-${scrollY}px`
body.style.width = '100%' body.style.width = '100%'
body.style.height = '100%'
body.style.touchAction = 'none'
html.style.overflow = 'hidden' html.style.overflow = 'hidden'
html.style.height = '100%'
// Prevent touchmove on backdrop (Android fix)
const preventScroll = (e: TouchEvent) => {
const target = e.target as HTMLElement
// Allow scroll inside modal content
if (target.closest('[data-modal-content]')) return
e.preventDefault()
}
document.addEventListener('touchmove', preventScroll, { passive: false })
return () => { return () => {
body.style.overflow = originalStyles.bodyOverflow body.style.overflow = originalStyles.bodyOverflow
body.style.position = originalStyles.bodyPosition body.style.position = originalStyles.bodyPosition
body.style.top = originalStyles.bodyTop body.style.top = originalStyles.bodyTop
body.style.width = originalStyles.bodyWidth body.style.width = originalStyles.bodyWidth
body.style.height = originalStyles.bodyHeight
body.style.touchAction = originalStyles.bodyTouchAction
html.style.overflow = originalStyles.htmlOverflow html.style.overflow = originalStyles.htmlOverflow
html.style.height = originalStyles.htmlHeight
document.removeEventListener('touchmove', preventScroll)
window.scrollTo(0, scrollY) window.scrollTo(0, scrollY)
} }
}, []) }, [])
@@ -354,11 +373,13 @@ export default function ConnectionModal({ onClose }: ConnectionModalProps) {
> >
<div <div
ref={modalContentRef} ref={modalContentRef}
data-modal-content
tabIndex={-1} tabIndex={-1}
className="w-[calc(100%-2rem)] max-w-sm bg-dark-900 rounded-2xl border border-dark-700/50 overflow-y-auto overscroll-contain animate-scale-in shadow-2xl flex flex-col outline-none" className="w-[calc(100%-2rem)] max-w-sm bg-dark-900 rounded-2xl border border-dark-700/50 overflow-y-auto overscroll-contain animate-scale-in shadow-2xl flex flex-col outline-none"
style={{ style={{
maxHeight: 'calc(100dvh - 6rem)', maxHeight: 'calc(100dvh - 6rem)',
WebkitOverflowScrolling: 'touch', WebkitOverflowScrolling: 'touch',
touchAction: 'pan-y',
}} }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >

View File

@@ -55,7 +55,7 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top
) )
const popupRef = useRef<Window | null>(null) const popupRef = useRef<Window | null>(null)
// Scroll lock when modal is open (cross-platform) // Scroll lock when modal is open (cross-platform including Android)
useEffect(() => { useEffect(() => {
const scrollY = window.scrollY const scrollY = window.scrollY
const body = document.body const body = document.body
@@ -67,7 +67,10 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top
bodyPosition: body.style.position, bodyPosition: body.style.position,
bodyTop: body.style.top, bodyTop: body.style.top,
bodyWidth: body.style.width, bodyWidth: body.style.width,
bodyHeight: body.style.height,
htmlOverflow: html.style.overflow, htmlOverflow: html.style.overflow,
htmlHeight: html.style.height,
bodyTouchAction: body.style.touchAction,
} }
// Lock scroll // Lock scroll
@@ -75,14 +78,29 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top
body.style.position = 'fixed' body.style.position = 'fixed'
body.style.top = `-${scrollY}px` body.style.top = `-${scrollY}px`
body.style.width = '100%' body.style.width = '100%'
body.style.height = '100%'
body.style.touchAction = 'none'
html.style.overflow = 'hidden' html.style.overflow = 'hidden'
html.style.height = '100%'
// Prevent touchmove on backdrop (Android fix)
const preventScroll = (e: TouchEvent) => {
const target = e.target as HTMLElement
if (target.closest('[data-modal-content]')) return
e.preventDefault()
}
document.addEventListener('touchmove', preventScroll, { passive: false })
return () => { return () => {
body.style.overflow = originalStyles.bodyOverflow body.style.overflow = originalStyles.bodyOverflow
body.style.position = originalStyles.bodyPosition body.style.position = originalStyles.bodyPosition
body.style.top = originalStyles.bodyTop body.style.top = originalStyles.bodyTop
body.style.width = originalStyles.bodyWidth body.style.width = originalStyles.bodyWidth
body.style.height = originalStyles.bodyHeight
body.style.touchAction = originalStyles.bodyTouchAction
html.style.overflow = originalStyles.htmlOverflow html.style.overflow = originalStyles.htmlOverflow
html.style.height = originalStyles.htmlHeight
document.removeEventListener('touchmove', preventScroll)
window.scrollTo(0, scrollY) window.scrollTo(0, scrollY)
} }
}, []) }, [])
@@ -179,7 +197,9 @@ export default function TopUpModal({ method, onClose, initialAmountRubles }: Top
onClick={onClose} onClick={onClose}
> >
<div <div
data-modal-content
className="w-[calc(100%-2rem)] max-w-sm bg-dark-900 rounded-2xl border border-dark-700/50 shadow-2xl overflow-hidden animate-scale-in" className="w-[calc(100%-2rem)] max-w-sm bg-dark-900 rounded-2xl border border-dark-700/50 shadow-2xl overflow-hidden animate-scale-in"
style={{ touchAction: 'pan-y' }}
onClick={(e) => e.stopPropagation()} onClick={(e) => e.stopPropagation()}
> >
{/* Header */} {/* Header */}