import { useEffect } from 'react'; /** Admin shell scroll container — lock only this when the shell is active. */ const ADMIN_SHELL_OUTLET = '.llms-admin-shell-outlet'; type SavedOverflow = { overflow: string; overflowX: string; overflowY: string; }; let lockCount = 0; let savedStyles: Map | null = null; function getScrollLockElements(): HTMLElement[] { const outlet = document.querySelector(ADMIN_SHELL_OUTLET); if (outlet) { return [outlet]; } // Elementor editor and other contexts without the admin shell outlet. return [document.documentElement, document.body]; } function applyScrollLock(): void { const elements = getScrollLockElements(); savedStyles = new Map(); elements.forEach((el) => { savedStyles!.set(el, { overflow: el.style.overflow, overflowX: el.style.overflowX, overflowY: el.style.overflowY, }); el.style.overflow = 'hidden'; }); } function releaseScrollLock(): void { if (!savedStyles) { return; } savedStyles.forEach((styles, el) => { el.style.overflow = styles.overflow; el.style.overflowX = styles.overflowX; el.style.overflowY = styles.overflowY; }); savedStyles = null; } /** * Prevent background scroll while a drawer/modal is open. * Admin shell: locks only `.llms-admin-shell-outlet` (WP is already 100vh-contained). * Elementor / other: locks document scroll roots. * Supports nested overlays via a shared lock counter. */ export function useScrollLock(active: boolean): void { useEffect(() => { if (!active) { return; } lockCount += 1; if (lockCount === 1) { applyScrollLock(); } return () => { lockCount = Math.max(0, lockCount - 1); if (lockCount === 0) { releaseScrollLock(); } }; }, [active]); }