import type * as React from 'react'; import type { PopperContentProps } from '../utils/popper.cjs'; import type { PrimitivePropsWithRef } from '../utils/primitive.cjs'; /** * One entry of {@link NavigationMenuProps.items}: a plain link, or a trigger * whose panel holds a list of links. Narrow with `'items' in item`. */ export type NavigationMenuItem = { /** Text rendered inside the derived `NavigationMenuLink`. */ label: string; /** Destination of the derived `NavigationMenuLink`. */ href: string; /** * Marks the link as the current page — `aria-current="page"` and `data-active`. * @default false */ active?: boolean | undefined; /** * Identifier matched against the root's open `value`. * @default undefined — the entry's index in `items`, as a string. */ value?: string | undefined; } | { /** Text rendered inside the derived `NavigationMenuTrigger`. */ label: string; /** * Identifier matched against the root's open `value`. * @default undefined — the entry's index in `items`, as a string. */ value?: string | undefined; /** The links the derived panel holds. */ items: { /** Text rendered inside the derived `NavigationMenuLink`. */ label: string; /** Destination of the derived `NavigationMenuLink`. */ href: string; /** * Marks the link as the current page — `aria-current="page"` and `data-active`. * @default false */ active?: boolean | undefined; }[]; }; /** @internal Shared state distributed from {@link NavigationMenu} to its parts via context. */ export interface NavigationMenuContextValue { /** Value of the open item, or `null` when nothing is open. */ value: string | null; /** Axis the list lays out and arrow-keys travel along. Set on the root. */ orientation: 'horizontal' | 'vertical'; onTriggerEnter: (itemValue: string) => void; onTriggerLeave: () => void; onContentEnter: () => void; onContentLeave: () => void; onItemSelect: (itemValue: string) => void; onClose: () => void; /** What a Link's click does — closes the menu, or nothing when `closeOnSelect` is false. */ onLinkSelect: () => void; } /** Props for the {@link NavigationMenu} root, with `defaultValue` redeclared to accept `null` as the closed sentinel. */ export interface NavigationMenuProps extends Omit, 'defaultValue'> { /** * The menu's entries, rendered into a derived list. Ignored when `children` * is given, which switches to full manual composition. * @default undefined — an empty menu. */ items?: NavigationMenuItem[] | undefined; /** * Render override for entry bodies (panel contents or link text). Called once * per entry, never for nested links. Library owns roles, ids, href, aria-current. * @default undefined — the panel's links, or the entry's `label`, is rendered. */ /** Return one router link element forwarding ref, className and anchor attributes. */ renderLink?: ((item: { label: string; href: string; active?: boolean | undefined; }) => React.ReactElement) | undefined; /** * Custom renderer for the derived navigation item content. * @default undefined */ renderItem?: ((item: NavigationMenuItem) => React.ReactNode) | undefined; /** * Axis the menu runs along; sets `data-orientation`, switches arrow keys, keys * layout. Use `'vertical'` for sidebars, footers, or mobile. * @default 'horizontal' */ orientation?: 'horizontal' | 'vertical' | undefined; /** * Currently open item value (controlled). Pair with `onValueChange`; `null` * means nothing is open. Use `null` not `''` to avoid ambiguity. * @default undefined — uncontrolled, tracks its own open item internally. */ value?: string | null | undefined; /** * Initially open item's value, for uncontrolled usage. `null` starts closed. * @default null — no item open initially. */ defaultValue?: string | null | undefined; /** * Fires with the new value whenever the open item changes, controlled or * not, and with `null` when everything closes. * @default undefined — no-op if omitted. */ onValueChange?: ((value: string | null) => void) | undefined; /** * Delay before hovering a trigger opens its content (ms). * @default 200 */ delayDuration?: number | undefined; /** * Window after closing during which re-hovering a sibling trigger opens instantly (ms). * @default 300 */ skipDelayDuration?: number | undefined; /** * Grace period after pointer leaves trigger or panel (ms). Accommodates layout * gaps; too short closes panels while pointer travels between boxes. * @default 150 */ closeDelayDuration?: number | undefined; /** * Whether activating a link closes the open panel. `false` keeps it open * during route transitions. No menu event fires; link click is the event. * @default true */ closeOnSelect?: boolean | undefined; } /** Props for {@link NavigationMenuList}, the roving-focus container for `NavigationMenuItem`s. */ export interface NavigationMenuListProps extends PrimitivePropsWithRef<'ul'> { /** * Whether arrow-key navigation wraps from the last trigger back to the first * (and vice versa). * @default true */ loop?: boolean | undefined; } /** @internal Per-item identifiers distributed from {@link NavigationMenuItem} to its descendants via context. */ export interface NavigationMenuItemContextValue { value: string; triggerId: string; contentId: string; } /** Props for a single {@link NavigationMenuItem}. */ export interface NavigationMenuItemProps extends PrimitivePropsWithRef<'li'> { /** Unique identifier matched against the root's open `value`. */ value: string; } /** Props for {@link NavigationMenuTrigger}, the hoverable/clickable button that opens an item's content. */ export interface NavigationMenuTriggerProps extends PrimitivePropsWithRef<'button'> { } /** Props for {@link NavigationMenuContent}, the panel revealed by a trigger. */ export interface NavigationMenuContentProps extends PopperContentProps { /** Opt into shared trigger-relative collision handling. CSS positioning remains the default. @default 'css' */ positioning?: 'css' | 'floating' | undefined; /** * Keeps this panel mounted even while inactive, instead of unmounting it, for animation libraries needing the outgoing content present. * @default false */ forceMount?: boolean | undefined; } /** Props for {@link NavigationMenuLink}, a plain navigable item within the menu (list item or content panel). */ export interface NavigationMenuLinkProps extends PrimitivePropsWithRef<'a'> { /** * Marks this link as representing the current page (sets `data-active` and `aria-current="page"`). * @default false */ active?: boolean | undefined; } /** Props for {@link NavigationMenuIndicator}, a visual pointer that tracks the active trigger. */ export interface NavigationMenuIndicatorProps extends PrimitivePropsWithRef<'div'> { /** * Keeps this indicator mounted even while no item is open, instead of unmounting it, for animation libraries needing it present. * @default false */ forceMount?: boolean | undefined; }