diff --git a/src/useLockBodyScroll.ts b/src/useLockBodyScroll.ts index 85b81d63..b2afaad7 100644 --- a/src/useLockBodyScroll.ts +++ b/src/useLockBodyScroll.ts @@ -15,15 +15,33 @@ export function getClosestBody(el: Element | HTMLElement | HTMLIFrameElement | n return getClosestBody((el as HTMLElement).offsetParent!); } +function preventDefault(rawEvent: TouchEvent): boolean { + const e = rawEvent || window.event; + // Do not prevent if the event has more than one touch (usually meaning this is a multi touch gesture like pinch to zoom). + if (e.touches.length > 1) return true; + + if (e.preventDefault) e.preventDefault(); + + return false; +} + export interface BodyInfoItem { counter: number; initialOverflow: CSSStyleDeclaration['overflow']; } +const isIosDevice = + typeof window !== 'undefined' && + window.navigator && + window.navigator.platform && + /iP(ad|hone|od)/.test(window.navigator.platform); + const bodies: Map = new Map(); const doc: Document | undefined = typeof document === 'object' ? document : undefined; +let documentListenerAdded = false; + export default !doc ? function useLockBodyMock(_locked: boolean = true, _elementRef?: RefObject) {} : function useLockBody(locked: boolean = true, elementRef?: RefObject) { @@ -40,7 +58,15 @@ export default !doc if (locked) { if (!bodyInfo) { bodies.set(body, { counter: 1, initialOverflow: body.style.overflow }); - body.style.overflow = 'hidden'; + if (isIosDevice) { + if (!documentListenerAdded) { + document.addEventListener('touchmove', preventDefault, { passive: false }); + + documentListenerAdded = true; + } + } else { + body.style.overflow = 'hidden'; + } } else { bodies.set(body, { counter: bodyInfo.counter + 1, initialOverflow: bodyInfo.initialOverflow }); } @@ -48,7 +74,16 @@ export default !doc if (bodyInfo) { if (bodyInfo.counter === 1) { bodies.delete(body); - body.style.overflow = bodyInfo.initialOverflow; + if (isIosDevice) { + body.ontouchmove = null; + + if (documentListenerAdded) { + document.removeEventListener('touchmove', preventDefault); + documentListenerAdded = false; + } + } else { + body.style.overflow = bodyInfo.initialOverflow; + } } else { bodies.set(body, { counter: bodyInfo.counter - 1, initialOverflow: bodyInfo.initialOverflow }); }