import type { ReactElement, ReactNode, Ref } from "react"; export type MenuPlacement = "bottom-start" | "bottom-end" | "top-start" | "top-end"; export interface MenuContextValue { close: (reason: "item-select") => void; } export declare const MenuContext: import("react").Context; export interface MenuProps { /** Controlled open state; syncs to showPopover()/hidePopover(). */ open: boolean; /** * Called when a dismissal is *requested*; the consumer flips `open`. * * Menu never closes itself on `"esc"` or `"item-select"` — the popover stays * open until `open` becomes false (D50). `"outside"` is the one exception: * light dismiss is performed by the browser before it tells us, so by the * time that reason is reported the popover is already closed. Flipping * `open` to false is still required, to keep React's state in step. * * Invariant (D58): a dismissal is only ever reported for a menu that is * currently open according to its own `open` prop. The platform can close * an auto popover before the consumer's state catches up — clicking another * menu's trigger light-dismisses this one before the consumer's click * handler runs — and a report for an already-closed menu would clear a * selection that has since moved on. */ onClose: (reason: "esc" | "outside" | "item-select") => void; /** * The trigger element. Must be a single React element that spreads unknown * props onto a focusable node (a Psi `Button`, say): Menu clones it to add * `aria-haspopup="menu"` and `aria-expanded`, so assistive tech associates * the menu with the control users actually focus. */ trigger: ReactElement>; /** Placement relative to the trigger. @default "bottom-start" */ placement?: MenuPlacement; /** Accessible name for the menu when there is no visible label. */ "aria-label"?: string; /** MenuItem and MenuSeparator children. */ children: ReactNode; className?: string; /** Forwarded ref to the popover element. */ ref?: Ref; } /** Action menu on the native Popover API top layer: the top layer and light * dismiss come from the platform; Esc, roving keyboard, placement and * dismissal reasons are Psi's (D53). Controlled-only, like Dialog (D50). * * Controlled-only means Menu does not change its own visibility. Esc and * item-select *report* a dismissal via onClose(reason) and leave the popover * open; only the consumer flipping `open` to false actually closes it. Esc * calls preventDefault() to suppress the platform's own popover dismissal, * which is what makes that possible. * * Light dismiss (outside click) is the one asymmetry, and it is forced by the * platform: the browser hides the popover itself and the hide-side * `beforetoggle` is not cancelable, so the popover is already closed by the * time the resulting `toggle` lets us report onClose("outside"). The consumer * must still flip `open` to false so React's state matches the DOM. * * `toggle` therefore reports only that one reason. A close driven by the * consumer (`open` true -> false) runs through the sync effect's own * hidePopover(), which raises a `toggle` too — that one is suppressed, because * a programmatic close is not a dismissal and must not call onClose. */ export declare function Menu({ open, onClose, trigger, placement, children, className, ref, ...rest }: MenuProps): import("react").JSX.Element; //# sourceMappingURL=Menu.d.ts.map