/** * Getting an overlay out of whatever container the host page put this component in. * * These components are published to unknown hosts, so an overlay can end up nested in an animated * modal, a slide-up footer, an accordion mid-transition or a virtualised list. Any ancestor with a * `transform`, `filter`, `backdrop-filter`, `perspective`, `contain` or a `will-change` naming one * of them becomes the containing block for `position: fixed`, and the overlay is laid out and * clipped inside that ancestor instead of against the viewport. * * The browser's top layer is the only way out that does not move the element: it paints above every * stacking context, is clipped by no ancestor, and ignores caging ancestors entirely — while the * element stays in its shadow root, so scoped styles, refs and measurements keep working. * * The two flavours are not interchangeable: * * - `modal` (dialog.showModal) inerts the rest of the page. Right for a claim form, fatal for a * hover card — it would make every other card unhoverable. * - `popover` (popover="manual" + showPopover) is non-modal, so the page stays interactive. * * Promotion is not free: the top layer cannot be overridden by a host's z-index, so a host can no * longer place its own toast or nav above us. A modal should outrank those anyway, so it always * promotes. A hover card should not, so it promotes only when staying put would actually clip it. */ /** * Walks up from the element, stepping out of every shadow root on the way, looking for an ancestor * that would become the containing block for a `position: fixed` child. */ export declare const isCaged: (element?: Element | null) => boolean; export declare const supportsModalDialog: boolean; export declare const supportsPopover: boolean; /** * Shows a modal overlay in the top layer, falling back to the `open` attribute where is * unimplemented — WebKit only shipped it in 15.4, which on iOS means Safari, every WKWebView and * every installed PWA on the device. There the overlay renders in place exactly as it did before * the top layer existed: correct, just clippable. * * Returns whether the top layer was actually used, so callers can supply what it would have given * them for free (page inerting, Escape) on the path where it did not. */ export declare const openModalOverlay: (dialog?: HTMLDialogElement | null) => boolean; export declare const closeModalOverlay: (dialog?: HTMLDialogElement | null) => void; /** * Promotes a non-modal overlay, but only when an ancestor would otherwise cage it — so in the * ordinary case the host keeps the ability to stack its own UI above ours. * * The `popover` attribute is added here rather than in markup on purpose: it carries * `[popover]:not(:popover-open) { display: none }`, which would hide an overlay that never gets * promoted, and a set of UA box styles that only need overriding while it is applied. */ export declare const promoteOverlayIfCaged: (element?: HTMLElement | null) => boolean; export declare const demoteOverlay: (element?: HTMLElement | null) => void; /** * Escape handling for the fallback path only. A modal dialog reports Escape as a `cancel` event; * without `showModal` there is no such event, so the key has to be watched directly. * * Capture, deliberately: an overlay that stacks something of its own on top (the claim form's image * viewer) listens on `document`, and a bubble-phase listener on `window` would run *after* that one * had already dismissed it and cleared the state this handler checks — closing both at once. * Capture at `window` runs first, so the inner overlay still owns the key. */ export declare const bindEscapeFallback: (handler: (event: KeyboardEvent) => void) => () => void;