/** * Port of Base UI React's `@base-ui/utils/useScrollLock` * (`packages/utils/src/useScrollLock.ts`). * * Single global scroll lock with ref-counting, ``/body inset-scrollbar * compensation, iOS overlay-scrollbar path, and resize handling. This * supersedes the minimal `use-anchored-popup-scroll-lock` overflow toggle — * that file is now a thin wrapper that forwards to this module so existing * popover / tooltip call sites keep working without changes. * * ## React → Solid deviations * * - The React hook body uses `useIsoLayoutEffect` — here it maps to * `createRenderEffect` via the `useIsoLayoutEffect` alias. The compute * half re-reads `enabled` / `referenceElement` and the apply half * returns a disposer; Solid's effect machinery invokes the previous * disposer on every re-run and on owner dispose, mirroring React's * useEffect cleanup semantics. * - `Accessor | T` is accepted for both inputs so consumers don't have * to wrap bare values. Matches the hook-parameter shape elsewhere in * the port. * - `addEventListener` is inlined (one-off use for the window resize * listener) since this codebase doesn't have a dedicated helper. * * ## happy-dom gaps * * Real-browser-only paths that unit tests cannot exercise: * * - **Inset-scrollbar compensation**: `isOverflowElement(html)` + `body` * height/width rewriting requires real layout metrics. happy-dom * returns 0 for `offsetWidth` / `clientWidth` — the inset branch runs * but writes zero-valued styles. * - **iOS overlay-scrollbar path**: gated on `isIOS`; test env reports * `false` so the path is inert. * - **`scrollbar-gutter: stable` detection**: relies on `CSS.supports` + * real `offsetWidth` diffs; result in happy-dom is environment- * dependent. * - **`visualViewport.scale` pinch-zoom bail-out**: happy-dom has no * `visualViewport`. * - **Window `resize` event**: happy-dom dispatches events but doesn't * emit native layout changes. * * The unit tests in `test/internals/popups/use-scroll-lock.test.tsx` * cover the ref-counting state machine, the `overflow: hidden` / `clip` * site-author bailout, and basic enable/disable lifecycle. */ import { type Accessor } from "solid-js"; /** * Inputs for `useScrollLock`. Both parameters accept a raw value or a * Solid `Accessor` — passing an accessor lets the hook react to prop * changes without the caller needing to set up their own effect. */ export interface UseScrollLockParameters { /** Whether scroll lock is enabled. */ enabled?: boolean | Accessor | undefined; /** * The element used as a reference for lock calculations — typically * the popup / positioner. The owner document/window are inferred off * of this. */ referenceElement?: Element | null | Accessor | undefined; } /** * Locks the scroll of the document when `enabled` is true. Ref-counted * globally — multiple simultaneous callers share one lock/unlock cycle. * * Usage: * * ```ts * useScrollLock({ * enabled: () => props.modal === true && open(), * referenceElement: popupElement, * }); * ``` */ export declare function useScrollLock(parameters?: UseScrollLockParameters): void; /** * Test-only peek into the lock state. Not part of the public hook * surface; tests import it directly. * * @internal */ export declare function __peekScrollLockerState(): { count: number; locked: boolean; }; /** * Test-only reset. Forces the singleton back to its pristine state so * tests don't leak ref counts across each other. * * @internal */ export declare function __resetScrollLockerForTests(): void; //# sourceMappingURL=use-scroll-lock.d.ts.map