import type { Placement, VirtualElement } from "@floating-ui/react";
import type { ReactElement, RefObject } from "react";
/**
* The floating-ui block every anchored overlay — `Popover`, `Menu`,
* `Listbox`, `Combobox` — wrote out for itself, consolidated once.
*
* `Popover` and `Menu` had the same twelve-line `useFloating` +
* `useInteractions` + `useClonedChild` preamble with two constants
* different (the offset and the role), and the fleet's four pickers
* hand-rolled a fifth, sixth, seventh and eighth `computePosition`
* that reimplemented `flip`/`shift` against `window.innerHeight`.
* This is the one implementation they all take.
*
* ### The owner's "configurable, but those are the basics"
*
* Escape and outside-press both close, **on by default**, for every
* anchored overlay — that is what an overlay is. A component switches
* one off through `dismiss` (a `Combobox`'s Escape clears the query
* before it closes; a menu opened from a context click wants no
* outside-press race with the thing that spawned it), but it opts out
* rather than opting in.
*
* ### `size`, for the pickers
*
* `matchTriggerWidth` and `maxHeightPx` are the two things
* `PortalDropdown` did with a hand-measured `TriggerRect` and a
* `window.innerHeight` clamp. The `size` middleware does both from the
* platform: the panel takes the trigger's width, and it never grows
* past the space actually left in the viewport.
*
* The computed width/height are written **straight onto the floating
* element's style** rather than lifted into React state, which is
* floating-ui's own documented shape and is deliberate twice over: a
* `setState` inside `apply` re-runs the position, which re-runs
* `apply`, which is a render loop; and because these properties never
* enter the `floatingStyles` object React manages, a component
* re-render (a keystroke in a combobox) does not wipe them — only an
* `autoUpdate` tick recomputes them.
*
* ### Portal-agnostic
*
* This returns the pieces — `clonedTrigger`, `getFloatingProps`,
* `setFloating`, `floatingStyles`, `context` — and renders nothing.
* Whether the panel goes in a `FloatingPortal`, the top layer, or in
* place is the component's call, which is what lets the same hook back
* a portalled `Listbox` and (for now) a top-layer `Popover`.
*/
export type AnchoredOverlayRole = "dialog" | "listbox" | "menu";
/**
* What a panel can hang off in anchor mode: a real element, or a
* **virtual** one — an object that only knows its own rectangle.
*
* The virtual half is what a context menu needs. A menu opened by
* a press-and-hold belongs at the finger, not at the corner of the
* card underneath it, and floating-ui positions against a rect
* without caring where the rect came from. `flip` and `shift` work
* unchanged, which is the whole reason to express a point this way
* rather than with `top`/`left` of our own.
*/
export type AnchoredOverlayAnchor = HTMLElement | VirtualElement;
export type UseAnchoredOverlayOptions = {
/**
* Anchor the panel to a **pre-existing** element the consumer already
* rendered, instead of cloning a `trigger`. For the attached-input
* `Combobox`, whose reference is the consumer's own `` (both the
* value and the query) — there is nothing to clone. Supply exactly one
* of `anchorRef` / `trigger`; with `anchorRef`, `clonedTrigger` is
* `null`.
*
* A **virtual** anchor is allowed here too, which is how a context
* menu opens at the point that was pressed.
*/
anchorRef?: RefObject;
/**
* Both default **on** — Escape and outside-press are what makes an
* overlay an overlay. Switch one off for the honest exception (a
* combobox that swallows the first Escape to clear its query), never
* to make a plain overlay sticky. Named for the flattened
* floating-ui `useDismiss` options they carry.
*/
isEscapeDismissable?: boolean;
/**
* Clamp the panel to the space the viewport actually leaves below
* (or above) the trigger, with no fixed cap. The panel owes itself
* an `overflow`, or a clamped one simply hides its last rows.
*
* `maxHeightPx` implies this *and* caps it at a number — a `Listbox`
* never wants to be 900px tall even on a monitor that would allow
* it. A `Menu` wants the other half only: as tall as its items need,
* and never off the bottom of the screen.
*/
isHeightClamped?: boolean;
isOutsidePressDismissable?: boolean;
/** Ports `PortalDropdown`'s anchor-width match, via `size`. */
isTriggerWidthMatched?: boolean;
/**
* Clamp the panel to the width the viewport actually leaves, with no
* fixed cap — the inline twin of `isHeightClamped`, and `maxWidthPx`
* without the number.
*
* A portalled panel is `position: fixed`, so its shrink-to-fit width
* already stops at the *viewport*, not at the space `shift` left it
* — which means a long label produces a panel exactly as wide as the
* window, positioned 8px in, with 8px of itself off the right edge.
* `availableWidth` is the shifted number, so this is what makes a
* long label wrap instead.
*/
isWidthClamped?: boolean;
isVisible: boolean;
/** Clamps the panel to `min(this, available viewport space)`. */
maxHeightPx?: number;
/**
* Caps the panel's width at `min(this, available viewport space)`,
* symmetric with `maxHeightPx`. Without it a picker grows to its
* widest content — a long `Combobox` footer sentence or option label
* drags the whole panel absurdly wide; the cap lets that content wrap
* instead. Omit for width-follows-content (the default).
*/
maxWidthPx?: number;
/** Popover 8, Menu/Listbox/Combobox 4. */
offsetValue?: number;
onDismiss: () => void;
placement?: Placement;
role: AnchoredOverlayRole;
/**
* The control the panel hangs off. **Cloned, not wrapped.** Omit only
* when `anchorRef` is supplied instead.
*/
trigger?: ReactElement;
};
export declare const useAnchoredOverlay: ({ anchorRef, isEscapeDismissable, isHeightClamped, isOutsidePressDismissable, isTriggerWidthMatched, isVisible, isWidthClamped, maxHeightPx, maxWidthPx, offsetValue, onDismiss, placement, role, trigger, }: UseAnchoredOverlayOptions) => {
clonedTrigger: ReactElement, string | import("react").JSXElementConstructor> | null;
context: {
placement: Placement;
strategy: import("@floating-ui/react").Strategy;
x: number;
y: number;
middlewareData: import("@floating-ui/react").MiddlewareData;
isPositioned: boolean;
update: () => void;
floatingStyles: React.CSSProperties;
open: boolean;
onOpenChange: (open: boolean, event?: Event, reason?: import("@floating-ui/react").OpenChangeReason) => void;
events: import("@floating-ui/react").FloatingEvents;
dataRef: React.MutableRefObject;
nodeId: string | undefined;
floatingId: string | undefined;
refs: import("@floating-ui/react").ExtendedRefs;
elements: import("@floating-ui/react").ExtendedElements;
};
floatingStyles: import("react").CSSProperties;
getFloatingProps: (userProps?: React.HTMLProps) => Record;
setFloating: ((node: HTMLElement | null) => void) & ((node: HTMLElement | null) => void);
triggerId: string;
};
//# sourceMappingURL=useAnchoredOverlay.d.ts.map