export declare const FOCUSABLE_SELECTOR: string; export declare function getFocusableElements(container: HTMLElement | undefined): HTMLElement[]; export declare function trapFocus(event: KeyboardEvent, container: HTMLElement | undefined): void; /** * Acquire a shared body-scroll lock; returns the matching release function. * * The count is module-global — the body stays `overflow: hidden` while at * least one overlay (Dialog, Drawer, mobile Sidebar) holds a lock. Ownership * is per-acquisition: only the returned release can decrement this holder's * share, and it is idempotent, so calling it from multiple teardown paths * (outro end + onDestroy safety net) releases exactly once and can never free * a lock held by another overlay instance. There is deliberately no standalone * `unlock` export — an unpaired decrement is exactly the bug this design * removes. */ export declare function lockBodyScroll(): () => void; export declare function focusFirstElement(container: HTMLElement | undefined): void; /** * Promote a `` to the top layer and move focus into its panel. * * **Precondition: `dialogEl` must already be bound.** Call this only once the * `bind:this` target exists — e.g. from `tick().then(...)` in the opener effect, * after the `{#if isVisible}` block has rendered. An earlier version deferred the * `showModal()` call with its own `tick()` in the hope of waiting for the bind, * but the ref is captured by value: if the caller passes an as-yet-unbound * `dialogEl`, the `tick()` still runs `undefined?.showModal()` — a silent no-op * that left Dialog/Drawer never actually modal. Sequencing is the caller's job; * the top-layer promotion here is synchronous (only the focus move inside * `focusFirstElement` defers by a tick). * * Acquires a body-scroll lock and returns its release function — the caller * owns the lock and must call the release on every teardown path (outro end * and destroy; it is idempotent, so overlapping paths are safe). Pass it back * through {@link closeDialogModal} on the regular close path. */ export declare function showDialogModal(dialogEl: HTMLDialogElement | undefined, panelEl: HTMLElement | undefined): () => void; export declare function closeDialogModal(dialogEl: HTMLDialogElement | undefined, previouslyFocused: HTMLElement | null, releaseScrollLock?: () => void): void; /** * True when `el` is a descendant of an OPEN *modal* `` — one opened via * `showModal()`, which matches `:modal` and occupies the browser top layer. * * A popover shown via `showPopover()` from inside such a dialog forms a *second* * top-layer element, which WebKit/iOS fails to render above the dialog (Codeberg * #23 — the documented "top layer: popover vs. dialog" conflict; Chromium * tolerates it). Anchored overlays use this to skip top-layer promotion when * nested in a modal dialog and render inside the dialog's own subtree instead. * * DOM-based on purpose: it transparently covers `Drawer` (also `showModal()`) * and even consumer-authored `` wrappers, and distinguishes modal from * non-modal (`show()`) dialogs — neither of which a context/registry would catch. * * Null-safe so it can be called during SSR, before `bind:this` resolves, or * while an anchor is mid-teardown. */ export declare function isAnchoredInModalDialog(el: HTMLElement | null | undefined): boolean;