import { type ReactNode, type RefObject } from "react"; import { View, type StyleProp, type ViewStyle, type ViewProps } from "react-native"; import { type OverlayBesideSide, type OverlaySide } from "./overlay-layout.js"; /** * The resolved side plus where the trigger's center sits along the card (`centerX`, * measured from the card edge a decoration's `left` inset is measured from: the * physical left, or the start edge where React Native swaps `left` and `right` in a * right-to-left layout) and the card's width, for a decoration that aims at the trigger. */ export declare const useOverlayAnchor: () => { side: OverlaySide; centerX?: number; cardWidth?: number; }; /** Whether the anchored card around this node is presented as a phone sheet. Read inside the card. */ export declare const useOverlaySheet: () => boolean; /** * The props of AnchoredOverlay. The defaults: below the trigger, by its leading edge, * 4 apart, in the app's layout direction, closable by an outside tap and Android's * back, the functional layer under glass, anchored at every form factor. */ export interface AnchoredOverlayProps { /** Whether the card is shown. */ open: boolean; /** Called when a tap off the card should dismiss it. */ onDismiss: () => void; /** Native accessibility escape for the owning overlay scope. */ onAccessibilityEscape?: ViewProps["onAccessibilityEscape"]; /** Ref to the trigger view the card is placed against. */ triggerRef: RefObject; /** Gap between the trigger and the card, on whichever side the card resolves to (default 4). */ gap?: number; /** The floating card's contents. */ children: ReactNode; /** Non-scrolling card decoration, such as an anchor arrow. */ decoration?: ReactNode; /** Style for the card wrapper (the skin's card fill/border/shadow + width). */ cardStyle?: StyleProp; /** The caller's inline absolute anchor (e.g. position:absolute, top:"100%"), * used only in the no-host fallback. */ inlineStyle?: StyleProp; /** * Whether an outside tap or Android's hardware back can actually dismiss the * card (default true). Pass false when dismissal is a no-op (a controlled * `open` with no change handler, e.g. a docs example pinned open), so the * full-bleed dismiss backdrop is skipped instead of silently swallowing every * tap under an overlay that can never close, and back is left to the page. */ dismissable?: boolean; /** * The card's known width, when the caller fixes it. Enables horizontal * placement logic: the card is clamped inside the outlet's bounds (8px * inset), so a card anchored to a trigger near the outlet's right edge slides * left instead of overflowing. Omit it to anchor the card by its leading edge; * a card that then renders too wide for the room is pinned by its far edge, 8px * inside the outlet, instead (see placeOverlay). */ cardWidth?: number; /** * Center the card on the trigger (tooltip-style) instead of aligning it by an edge: * horizontally above or below the trigger, vertically beside it. A card without * `cardWidth` is centered by the width it rendered at, which the card is held hidden * until it reports. Still clamped inside the outlet. */ centered?: boolean; /** * Align the card's TRAILING edge with the trigger's trailing edge instead of * its leading edge (the default). Needs no `cardWidth`: the card is pinned by * an inset from the outlet's own edge. A card that renders too wide to fit that * way is pinned by its other edge, 8px inside the outlet, instead. */ alignEnd?: boolean; /** * The layout direction the card's logical alignment follows: leading is the * physical left in a left-to-right layout and the physical right in a right-to-left * one, and `besideStart` / `besideEnd` mirror the same way. Defaults to the app's * layout direction (`I18nManager`); pass it only to override that. */ rtl?: boolean; /** * Prefer placing the card ABOVE the trigger. It flips below when the band above * is too short and the band below has more room, and is otherwise capped to the * larger band; it never falls back to beside. Placement axis: `besideStart` > * `besideEnd` > `above` > below (the default). */ above?: boolean; /** * Prefer placing the card BESIDE the trigger at its LEADING side (the left in a * left-to-right layout), top-aligned with it; then at its trailing side; and when * neither side has room, above or below it, centered on it. Needs the card's width: * `cardWidth`, or the width a content-sized card reports before it is revealed. */ besideStart?: boolean; /** * Prefer placing the card BESIDE the trigger at its TRAILING side (the right in a * left-to-right layout), then its leading side, then above or below it as * `besideStart` does. For popovers anchored to small cells (a calendar day peek) * where below the trigger would cover the grid. */ besideEnd?: boolean; /** * Paint the card as an OPAQUE surface: the skin's own `popover` fill on a * plain box, with NO glass material, in glass mode exactly as in solid mode. * The kit's own option lists take the dense layer instead (`dense`); this stays * for a consumer that wants the plain surface outright. Not a per-component * glass prop and no hand-painted glass: it selects the kit's plain surface. */ opaque?: boolean; /** * Paint the card on the DENSE layer of the glass model: the same material as * every anchored card, under the densest tint (`glass-tint-dense`), for the * anchored surfaces that are option lists (Dropdown, Select, Autocomplete, * RowMenu, SplitButton's overflow menu, the PhoneInput country list, and so the * AvatarMenu built on Dropdown). Those cards carry rows the user reads and picks * from, and under the functional layer's sheer tint the page behind them read * through between the rows; the dense tint keeps them legible while the card * still takes the material. Not a per-component glass prop and no hand-painted * glass: it selects the layer, and in solid mode it changes nothing. `opaque` * wins when both are passed. */ dense?: boolean; /** * Fired once per opening after the card's children mount and its measured * placement is committed. `open` flipping true is not that moment on the hosted * path: there the card is held back until the trigger measurement lands, so a * caller that moves focus into its content (the WAI-ARIA menu pattern: focus * the first row on open) would otherwise focus a card that does not exist yet. * This fires on both paths, from an effect inside the card's own subtree. * Hosted cards also wait for fitting, so focusing a child cannot scroll the * page toward an uncapped, still-invisible card. A card that cannot close * (`dismissable` false: pinned open, a docs example) is content on the page that * nobody opened, so it never fires: nothing moves focus into it as the page loads. */ onCardMount?: () => void; /** * The children own the card's scrolling: they mount exactly one OverlayScrollView * themselves (an option list with its own scroll handling), and the card does not * wrap them in one. The contract of the kit's option lists. */ ownsScroll?: boolean; /** * The card is a menu or an option list: a Tab that takes keyboard focus out of the * card (or off its trigger anywhere but into the card) closes it, and focus goes on * in the page's order (the WAI-ARIA menu and listbox patterns). Its rows are its one * tab stop, so its scrollport takes none. Without it the card stays open, Tab moves * through and past it in that order, and an overflowing scrollport is a stop. */ dismissOnTab?: boolean; /** * The card is a combobox's popup: its field keeps editing focus and must stay * reachable, so the card is not modal to VoiceOver and TalkBack. Every other card * that can close is modal to them while open (see the header). */ combobox?: boolean; /** * The control that opened the card, where `triggerRef` is a wrapper around it (an anchor * box that also holds other controls): the card's controls follow it in the tab order, and * focus returns to it when the card closes (TalkBack moves only to an accessibility * element). Defaults to `triggerRef`. */ returnFocusRef?: RefObject; /** * Present the card as a SHEET at the phone form factor: on the bottom edge of its * window (the keyboard's top while it is up), over the app's declared chrome as a modal * sheet covers a tab bar, across the window's safe width up to 640, over a dimming * scrim, wearing this style (the skin's sheet: its corners, padding, fill and any float * off the edges) in place of `cardStyle`, with no `decoration`, on the dense layer under * glass; its content is padded clear of the home indicator. Only a card that can close becomes a sheet; a card * pinned open stays anchored. Omit it to stay anchored at every form factor (menus and * option lists do, as HIG and Material 3 keep them). */ sheetStyle?: StyleProp; } /** * The kit's anchored card: a floating card placed against a trigger (below it by * default, above it or beside it on request), fitted inside the window's visible band * and safe area, over a transparent backdrop that closes it on an outside tap, on the * window layer of the nearest OverlayProvider. It renders the card's surface (the * functional or dense glass layer, or a plain surface) and one scrollport for the * children, holds the card hidden until its placement is measured, and at the phone * form factor presents a card that offers a sheet as one. It never renders a trigger, * never dims the page (except behind a sheet), never sizes the card's width (the * caller's `cardStyle` does), and never moves focus into the card itself: the caller * does that at `onCardMount`. With no OverlayProvider it renders the card inline under * the trigger. */ export declare function AnchoredOverlay({ open, onDismiss, onAccessibilityEscape, triggerRef, gap, children, decoration, cardStyle, inlineStyle, dismissable, cardWidth, centered, above, besideStart, besideEnd, alignEnd, rtl, opaque, dense, onCardMount, ownsScroll, dismissOnTab, combobox, returnFocusRef, sheetStyle, }: AnchoredOverlayProps): import("react").JSX.Element | null; interface Rect { x: number; y: number; width: number; height: number; } /** What placeOverlay reads besides the trigger's box. */ export interface PlaceOverlayOptions { /** The card's caller-fixed width, when it has one. */ cardWidth?: number; /** The width a card without a fixed one rendered at, once its layout reports it. */ measuredWidth?: number | null; /** Center the card on the trigger instead of aligning an edge, by `cardWidth` or else * by `measuredWidth`. */ centered?: boolean; /** Prefer beside the trigger at its leading side, then its trailing side. */ besideStart?: boolean; /** Prefer beside the trigger at its trailing side, then its leading side. */ besideEnd?: boolean; /** Align the card's trailing edge with the trigger's instead of its leading edge. */ alignEnd?: boolean; /** The layout direction is right to left: leading is the physical right. */ rtl?: boolean; /** The trigger-to-card gap. */ gap: number; /** The outlet's width, once measured. */ outletWidth: number | null; /** The visible band's left edge in the outlet (the window's safe area); default 0. */ visibleLeft?: number; /** The visible band's right edge in the outlet; default the outlet's width. */ visibleRight?: number; } /** * The card's outlet-relative position (pure, so the branch logic is testable). The * result is PHYSICAL: `left` and `right` are insets from the outlet's left and right * edges, and the hosted overlay hands them to the renderer under the keys it resolves * them by (React Native swaps `left` and `right` in a right-to-left layout). `rtl` * only selects the logical preferences: which physical side is leading. * * Every edge keeps 8px inside the visible band (`visibleLeft` to `visibleRight`, the * outlet less the window's unsafe edges). * * Beside (`besideStart` or `besideEnd`): the card is placed * beside the trigger, top-aligned, at the preferred side when it fits there, then at * the other side; `side` names the side it took. When neither fits, or before a card * of no fixed width has reported its width, it falls back to the vertical placement, * centered on the trigger. * * Above or below (the vertical side is fitOverlayHeight's): `top` is the below * placement's top edge, and the horizontal alignment is the card's leading edge on * the trigger's leading edge (default), its trailing edge on the trigger's (`alignEnd`), * or its center on the trigger's (`centered`). * * A card of known width (`cardWidth`) is clamped inside the band. A card without one is * kept inside the band by the width it rendered at (`measuredWidth`, which the hosted * overlay reads from the card's own layout before it reveals it): when anchoring it by * the trigger would cross the far edge, it is pinned by that far edge instead, and it * stays exactly where it was anchored whenever it fits. It is PINNED, not shifted by its * width: a content-sized card is as wide as the room its anchor leaves, so moving it * over by its measured width would give it more room, let it grow and move it again, a * frame at a time. Pinned by the far edge, it takes the width it wants in one layout, * and a wider card only confirms the pin. Without a measurement yet, it is placed as * anchored. */ export declare function placeOverlay(rect: Rect, opts: PlaceOverlayOptions): { left?: number; right?: number; top: number; side?: OverlayBesideSide; }; export {}; //# sourceMappingURL=anchored-overlay.d.ts.map