import { type ComponentPropsWithRef, type ReactElement, type ReactNode, type RefObject } from 'react'; /** * The menu's surface, with none of its behaviour — an elevated box with a * hairline border, 8px radius, 8px padding and the large shadow. * * Split out of `Menu` on 2026-09-05. `Menu` owns Escape, outside-click, * placement and now the keyboard, and that is right for a menu opened from a * trigger — but a type-ahead popup inside a text editor cannot have them: the * editor's suggestion plugin already owns the keyboard and positions the * popup, and a second Escape handler fights it. So Peek's `@`, `/` and `[` * menus each drew this box by hand, and the three had already drifted apart. * * `Menu` renders this, so there is still exactly one definition of the * surface — change it here and every menu in every app follows. * * Width, height and internal rhythm belong to the caller: a picker that lists * people is not the width of one that lists verbs. */ export interface MenuPanelProps extends Omit, 'children'> { /** Optional only because Base UI fills it in when this is a `render` * target: `Menu.Popup` supplies the children. Every other caller passes * them. */ children?: ReactNode; } /** The menu's surface without the menu: the elevated box, the rows' padding, * and a divider that runs the full width of what it separates. `Menu` renders * its popup as one. On its own it is for the places that draw a menu's look * but not its behaviour — a docs page, Peek's `@`, `/` and `[` pickers. */ export declare function MenuPanel({ children, className, ...props }: MenuPanelProps): import("react").JSX.Element; export interface MenuProps { /** * The control that opens the menu. Any element that forwards its ref and * spreads its props — this package's `Button`, `IconButton` and * `PersonTrigger` all do. * * The menu owns it, and that is the point: Base UI can only do the toggle, * the placement, the focus return, the first-item highlight and the whole * hover choreography if it knows which element opened it. */ trigger: ReactElement; /** Which of the menu's edges hangs from the trigger's. Default left. */ align?: 'left' | 'right'; /** * Open on hover, and close shortly after the pointer leaves — for a control * that only appears while the pointer is on a card. * * Base UI owns the whole choreography, including the diagonal from a row * out to a submenu panel. The shell used to hand-write this and got it * wrong in two directions. */ openOnHover?: boolean; /** Controlled, for a caller that must know or must force it. Leave both * off and the menu keeps its own state. */ open?: boolean; onOpenChange?: (open: boolean) => void; /** Base UI's imperative handle. `actions.current?.close()` shuts the menu — * for a row that must close it before opening what it opens. A `MenuItem` * closes the menu by itself, so this is only for content that is not one. */ actionsRef?: RefObject<{ close: () => void; unmount: () => void; } | null>; children: ReactNode; /** On the menu's surface — its width. **Not its padding**: see * `contentClassName`. */ className?: string; /** * The padding around the rows, as a class. Default `p-2`, 8px. * * It is on the scrolling content, not on the panel, so the scrollbar hugs the * panel's edge (D63) — and so a padding class on `className` adds to it * rather than replacing it. Peek's Later menu asked for `p-1` there and got * 12px from `0.12.6` on (PLAN Finding 60). Set it here. */ contentClassName?: string; } export declare function Menu({ trigger, align, openOnHover, open, onOpenChange, actionsRef, children, className, contentClassName }: MenuProps): import("react").JSX.Element; /** * A row that opens another menu beside it — the submenu two Peek menus * hand-rolled before this, one of which dropped the ref its edge-flip * measured and shipped a submenu cut off by the screen (2026-09-03). * * Hover-timed as those were, and as ours was: it opens at once and closes * 150ms after the pointer leaves, so the diagonal from row to panel survives. * Those two numbers are all that is left of the old implementation — the * placement, the flip at a screen edge, and now the arrow keys (→ opens it, * ← closes it) are Base UI's. */ export interface MenuSubProps { /** The trigger row's label. */ label: string; leading?: ReactNode; /** Mark the trigger row as holding a current value. */ selected?: boolean; /** The submenu's rows. */ children: ReactNode; /** On the submenu panel. */ className?: string; } /** A row that opens another menu beside it; its rows are this row's children. * Never inside a menu opened on hover — leaving the submenu strands both open, * measured below. */ export declare function MenuSub({ label, leading, selected, children, className }: MenuSubProps): import("react").JSX.Element; export interface MenuItemProps extends Omit, 'children'> { label?: string; /** Replaces the label/description block — for rows whose middle is richer * than text (the launcher's form rows). Leading/trailing still apply. */ children?: ReactNode; /** `tall` is the picker row — content height with a 40px floor, px-3, * gap-3, room for a 32px face or icon tile and the description line. * `default` is the command row. */ size?: 'default' | 'tall'; /** A second line under the label — a role, an address — 12px, secondary, truncating. */ description?: string; /** * After the label, on its line — 12px, muted, never cut: where a file sits * (an issue's ref and project) when its second line is its summary (SUM-7). * The label truncates before it does. */ aside?: string; /** Before the label: a 16px icon (stroke 1.5, secondary), or an Avatar, for rows led by a face. */ leading?: ReactNode; /** At the right edge: a hint, a value — anything. Wins over `shortcut` and `submenu`. */ trailing?: ReactNode; /** * Shown at the right edge **only while this row is the one you are pointing * at or have arrowed onto** — an `EnterHint`, typically. * * Pass it unconditionally. Do not do `trailing={active ? : undefined}`: * that mounts the hint, and a mount is instant while the row's own fill is a * 150ms fade, so the hint lands ahead of the highlight on the way in and * vanishes ahead of it on the way out (measured 2026-09-05 — ~7 frames of a * chip sitting on an unhighlighted row, and two rows lit at once when * sweeping). This slot is always in the DOM and revealed by the *same* * `:hover` / `selected` the fill uses, on the same duration and curve, so * the two cannot come apart — and the row does not reflow when it appears. * * It cross-fades with `trailing`/`shortcut`/`submenu` rather than displacing * them, and reserves the wider of the two, so nothing moves either way. */ hint?: ReactNode; /** A keyboard hint, drawn as the kbd chip. */ shortcut?: string; /** The row opens another menu: draws the chevron at the right edge. */ submenu?: boolean; destructive?: boolean; /** The row the menu currently points at (a submenu's chosen value). */ selected?: boolean; } /** * The row's class list, written once because `MenuSub`'s trigger row is the * same row. * * `data-highlighted` joins `:hover` here, and that is the whole visible * consequence of the port: the fill that followed the pointer now also * follows the arrow keys, because Base UI sets one attribute for both. */ /** The row's look, shared inside the package: `MenuItem` draws it, and * `Select` puts it on Base UI's `Select.Item`, whose parts (`ItemText`, * `ItemIndicator`) have to stay the element's own. One row, two parts. Not * exported from the package's index. */ export declare function menuItemClassName({ size, selected, className }: { size: 'default' | 'tall'; selected?: boolean; className?: string; }): string; /** Everything inside the row — written once, for the same reason. Shared * inside the package like `menuItemClassName`: `CommandPalette` draws it * inside Base UI's `Autocomplete.Item`. Not exported from the index. */ export declare function MenuItemBody({ label, children, size, description, aside, leading, trailing, hint, shortcut, submenu, destructive, selected }: Pick): import("react").JSX.Element; export declare function MenuItem({ label, children, size, description, aside, leading, trailing, hint, shortcut, submenu, destructive, selected, className, ...props }: MenuItemProps): import("react").JSX.Element; /** * The keyboard hint a picker row shows while highlighted — hand-rolled in * five files before this (2026-09-01), and drawn as its own thing until * 2026-09-05, when it became the `Kbd` chip every other key hint uses. A * picker row and a menu row sit in the same menu; they named the same key * two ways. * * `target` is what pressing it gives you, when that is worth saying — the * topic picker's "↩ Enter #topic". It sits after the chip, in the picker's * own 9px voice, because it is not a key. * * Katerina, 2026-09-05, told the measurement and asked again: the chip keeps * the `↩` character. It is not in Geist Mono — the browser borrows it, so it * advances 8.63px where the font's own characters advance 6 — and that is a * knowing trade for the glyph, not an oversight. If the width ever has to go, * Tabler's IconCornerDownLeft draws the same shape. */ export declare function EnterHint({ target }: { target?: string; }): import("react").JSX.Element; /** * A section heading inside a menu: the 32px row with a SectionLabel, read * secondary — a heading inside a menu labels the rows, it is not one of * them (Katerina, 2026-09-01). * * Inside a `Menu` it is Base UI's `Menu.Group` with the heading as its * `GroupLabel`, so the rows under it are announced as a named group rather * than as a run of items with a stray line above them. Outside one — the * editor pickers, which draw the surface but not the menu — it is the two * plain elements it has always been. */ export declare function MenuSection({ label, children, className }: { label: string; children: ReactNode; /** On the heading row — a surface whose rows are px-3 aligns its heading with px-3. */ className?: string; }): import("react").JSX.Element; /** * The line between two groups of a menu, with its own 4px above and below * (UIG-14, Katerina 19 September). A plain `Divider` left that room to each * caller, and Peek's menus drew it three ways — none, 4px, 4px and inset — so * the lines in its main menus touched the rows. */ export declare function MenuSeparator(): import("react").JSX.Element; /** A non-interactive row inside a menu, at the item's own geometry. */ export declare function MenuRow({ children, className }: { children: ReactNode; className?: string; }): import("react").JSX.Element; //# sourceMappingURL=Menu.d.ts.map