function hasScrollableParent(target: HTMLElement): boolean {
let el: HTMLElement | null = target;
while (el && el !== document.body) {
const { overflowY } = window.getComputedStyle(el);
if ((overflowY === 'auto' || overflowY === 'scroll') && el.scrollHeight > el.clientHeight) {
return true;
}
el = el.parentElement;
}
return false;
}
function preventTouchScroll(e: TouchEvent) {
if (!hasScrollableParent(e.target as HTMLElement)) {
e.preventDefault();
}
}
/** Управляет глобальной блокировкой прокрутки с счётчиком вложенности; корректно блокирует тач-скролл на мобильных. */
export function useGlobalScrollLock() {
const lockCount = useState('global-scroll-lock-count', () => 0);
function scrollLock() {
lockCount.value++;
if (lockCount.value === 1 && import.meta.client) {
document.body.style.overflow = 'hidden';
document.addEventListener('touchmove', preventTouchScroll, { passive: false });
}
}
function scrollUnlock() {
lockCount.value--;
if (lockCount.value <= 0) {
lockCount.value = 0;
if (import.meta.client) {
document.body.style.overflow = '';
document.removeEventListener('touchmove', preventTouchScroll);
}
}
}
return { scrollLock, scrollUnlock };
}