import type { ReactNode, RefObject } from "react"; /** * The portalled, backdrop-backed, focus-trapping panel that `Modal` * renders. No chrome — that is `Dialog`'s job — only the four things * every backdrop overlay needs: it portals to `document.body`, a * scrim stands behind it, focus is trapped inside it, and Escape or an * outside press closes it. * * ### Portalled, and the top layer is gone on purpose * * This supersedes the `.showModal()` top-layer approach. The * top layer paints above everything but cannot escape an * `overflow: hidden` ancestor's *clipping* in every case the fleet * hit; a portal to `document.body` does. The objection the old * decision raised — a portal moves the node out of a scoped query — * is answered by `useRole` writing `aria-controls`/`aria-labelledby` * so the trigger→panel link is followable across the boundary, and by * the stories scoping panels to `within(document.body)` while the * structural `expectAgentDrivable` needs no change. * * ### Only the top of the stack is live * * `useDismiss` (Escape + outside press) is enabled **only when this is * the top** of the stack, so an outside press or Escape closes the * innermost modal and nothing under it — the same rule the platform's * nested `` gave for free, without a hand-rolled document * keydown racing the focus manager. Everything below the top is * `inert`, which is what `expectHiddenFromAgents` asserts and what * makes `FloatingFocusManager`'s trap unambiguous. * * ### One accessible name, required * * A `role="dialog"` takes no name from its content, so one of * `aria-label` / `aria-labelledby` must be present. Missing both is a * dev-time warning, not a throw — the lesson `Spinner`, `Popover`, and * `Modal` each learned, applied without breaking a render. */ export type OverlayPanelProps = { "aria-label"?: string; "aria-labelledby"?: string; children: ReactNode; className?: string; /** * Which element takes the caret when the panel opens. * * Without it the focus manager takes the first tabbable element, * which for anything with chrome is the **Close button** — so a * panel wrapping a form opens with the caret on "Close" and the * first thing typed goes nowhere. A consumer cannot fix that from * outside: focusing in its own effect races the manager, and the * manager wins, which reads as the app ignoring you. */ initialFocus?: RefObject; /** Escape and an outside press both close. */ isDismissable?: boolean; isVisible: boolean; onClose: () => void; role?: "alertdialog" | "dialog"; }; export declare const OverlayPanel: ({ "aria-label": ariaLabel, "aria-labelledby": ariaLabelledBy, children, className, initialFocus, isDismissable, isVisible, onClose, role, }: OverlayPanelProps) => ReactNode; //# sourceMappingURL=OverlayPanel.d.ts.map