import type { ReactElement } from "react"; import type { CategoryTreeNode } from "../api/types.js"; import type { LinkComponentProp } from "./CategoryLink.js"; import type { ThemeModeProp } from "./types.js"; /** * The rail's narrowest width, in px — see {@link CategoryMegaMenuProps.railWidth}. * * The rail used to be `minmax(180px, 1fr)` beside a `3fr` pane: a quarter of * the panel at 1440 (338px of 1400) and 236px at a 1024 guard, where a * four-word root wraps onto two lines. The owner's read * of the stand (2026-09-14) was that the column is too narrow; the reference's * overlay could not be measured from this host (its edge refuses the address), * so the number is a floor a host can move, not a measurement: 360px never * wraps a two-word root at 16px, and above the floor the rail takes * 1/(1 + {@link MEGA_MENU_PANE_FRACTION}) of the panel. */ export declare const MEGA_MENU_RAIL_WIDTH = 360; /** The pane's share of the panel against the rail's `1fr`: 2.5 puts the rail * at two sevenths of the width (386px of 1400) — wider than the old quarter, * still the narrower of the two columns. */ export declare const MEGA_MENU_PANE_FRACTION = 2.5; /** * The panel's own height ceiling — see {@link CategoryMegaMenuProps.maxHeight}. * * `dvh`, not `vh`: on a phone-class browser with a collapsing address bar the * `vh` unit is the LARGEST viewport, and a panel sized by it would put its * last rows under the bar. `spacing[6]` (32px) is the room for whatever the * host stood the panel under — a header row typically — when it passes no * measure of its own. */ export declare const MEGA_MENU_MAX_HEIGHT: string; /** The class every rail root carries — the hover/focus fill hangs on it. */ export declare const MEGA_MENU_ROOT_CLASS = "stapel-mega-menu-root"; /** The modifier the DISCLOSED root carries: the row whose pane is showing. */ export declare const MEGA_MENU_ROOT_ACTIVE_CLASS = "stapel-mega-menu-root-active"; /** The `href` the hoisted mega-menu sheet is deduplicated by. */ export declare const MEGA_MENU_STYLE_HREF = "stapel-mega-menu"; /** * The rail row's rule set. * * A sheet rather than inline styles because `:hover` and `:focus-visible` * cannot be said in a style attribute — and the row's fill could not stay * inline either, since an inline `background` beats any sheet rule and the * hover would never paint. So the fill LEAVES the style attribute and every * state of it lives here, with `--stapel-*` custom properties so both themes * resolve at paint time. * * `surface-sunken` — the design system's neutral tertiary fill — for the * hovered, the focused and the disclosed row alike, and deliberately not * `brand-subtle` (which the disclosed row drew before 0.32.0). The reference's * overlay highlights its hovered root in light grey; a pointer resting on a row * is an answer about THAT row and a brand tint there reads as a selection the * person has not made. The three states share one fill because on this rail * they are one state — hovering or focusing a root discloses it — and the * disclosed row still says which it is by weight. * * `background-color`, never the shorthand: a host that put an image behind a * row of its own keeps it. */ export declare function megaMenuCss(): string; export interface CategoryMegaMenuProps extends ThemeModeProp, LinkComponentProp { /** Path prefix for a node's link, and the fallback href builder's base. * Default `/c` — the same `/c/:slug` convention the rest of the pair uses. */ readonly basePath?: string; /** * Where a node leads. Default `${basePath}/${node.slug}`. * * A builder rather than a prefix because a storefront may route a category * through its feed with the node's `path` (`"141/151/166"` — the exact form * the search query's `category` parameter takes) instead of its slug. */ readonly href?: (node: CategoryTreeNode) => string; /** Levels to ask for. Default {@link DEFAULT_TREE_DEPTH}; below 3 the third * level is simply absent and every column is its header alone. */ readonly depth?: number; /** * Nodes the HOST supplies, instead of the tree read. * * Given, this component asks the server nothing — the same bargain * ``'s `entries` strikes: a host that already mounted * `useCategoryTree` for its own chrome should not pay for a second read, and * an override that "swapped the data" would still fire the request and * discard it. An empty array is a real answer and draws the empty state. */ readonly nodes?: readonly CategoryTreeNode[]; /** Third-level links per column before the tail link. Default 5. */ readonly maxLinksPerColumn?: number; /** * Narrowest viewport this panel may appear at. Default `breakpoints.desktop` * (1200) — the tokens' own rung, not a number picked here. * * A deployment whose catalogue button appears earlier than the ladder says * passes its own width, and passes the SAME one it uses everywhere else: the * fleet storefront opens this panel at its `SERP_RAIL_MIN_WIDTH` (1024, the * owner's tablet rule), which is one number that deployment names once and * hands to every pair that needs it. */ readonly minWidth?: number; /** * The panel's height ceiling, above which its own box scrolls. Default * {@link MEGA_MENU_MAX_HEIGHT} (`100dvh` less 32px). A host that stands the * panel under a measured header passes the room that is actually left — * `calc(100dvh - ${headerBottom}px - 16px)` — and drops any scroll box of * its own around the panel: two nested scroll containers give the wheel * to whichever has the taller content, which is the OUTER one exactly when * the panel fits, and the outer one has no containment. */ readonly maxHeight?: number | string; /** The rail's narrowest width in px. Default {@link MEGA_MENU_RAIL_WIDTH}. */ readonly railWidth?: number; /** * Hold the document still while the panel is mounted on a wide viewport. * Default `true`. * * A mounted panel is an open panel — this component never hides itself, * the host mounts it when it opens — so the lock follows the mount. A host * that draws the panel INLINE, as a page region rather than an overlay (a * demo, a sitemap page), passes `false`. The lock is `overflow: hidden` on * the root element with a stable scrollbar gutter, reference-counted * against any other panel or dialog holding the same lock. */ readonly lockScroll?: boolean; /** Escape, or a click outside the panel. The host owns the open state; this * component never hides itself, because a panel that closed on its own and a * button that still reads "open" are two answers to one question. */ readonly onClose?: () => void; /** * Fired on click (or Enter — a link and this panel's rail buttons both * dispatch a native `click` for that) of ANY item: a rail root, a column's * own header link, or one of its third-level links. `kind` says which rung. * * Before this the only way a host learned WHICH row was picked was reading * `data-category-id`/`data-testid` back off the DOM through a delegated * listener of its own — this replaces that with the seam every other * `onSelect` in the fleet takes. Additive: the row still navigates through * `href`/`linkComponent` exactly as before, and a host still owns closing * the panel (this never calls `onClose` itself). */ readonly onSelect?: (node: CategoryTreeNode, kind: "root" | "child" | "grandchild") => void; } export declare function CategoryMegaMenu(props: CategoryMegaMenuProps): ReactElement | null; //# sourceMappingURL=CategoryMegaMenu.d.ts.map