{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"dropdown-menu","type":"registry:ui","title":"DropdownMenu","description":"A menu of actions or options that opens from a trigger button, with full keyboard navigation, submenus and real DOM focus on every item.","categories":["navigation"],"registryDependencies":["https://fancy-ui.rama.app/r/internals.json","https://fancy-ui.rama.app/r/internals-dom.json","https://fancy-ui.rama.app/r/internals-motion.json","https://fancy-ui.rama.app/r/sound.json","https://fancy-ui.rama.app/r/utils.json"],"files":[{"path":"react/src/components/dropdown-menu/DropdownMenu.tsx","content":"\"use client\";\n\nimport { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport type { Side, Align } from \"../../internals/anchor-position\";\nimport { useEventCallback } from \"../../internals/dom/use-event-callback\";\nimport { useLiveRef } from \"../../internals/dom/use-live-ref\";\nimport { useFancyId } from \"../../internals/use-id\";\nimport { useSoundCue } from \"../../sound/use-sound\";\nimport { DROPDOWN_MENU_KEY } from \"./types\";\nimport type { DropdownMenuRootContext, MenuCloseOptions } from \"./types\";\n\nexport interface DropdownMenuProps {\n\t/**\n\t * Whether the menu is open.\n\t *\n\t * The source declares this `$bindable(false)`; React has no two-way\n\t * channel, so the component keeps its own copy either way — seeded from\n\t * this prop and re-synced whenever the caller changes it. `onOpenChange`\n\t * fires with the same value at the same moment in every call shape.\n\t */\n\topen?: boolean;\n\t/** Called with the new value whenever the menu opens or closes, however the change happened. */\n\tonOpenChange?: (open: boolean) => void;\n\t/** Side of the trigger to place the menu on. */\n\tside?: Side;\n\t/** Alignment along the trigger's cross axis. */\n\talign?: Align;\n\t/** Gap in pixels between the trigger and the menu. */\n\toffset?: number;\n\t/** Whether arrow-key navigation wraps at the ends. */\n\tloop?: boolean;\n\t/** The `DropdownMenuTrigger` and `DropdownMenuContent`. */\n\tchildren?: ReactNode;\n\t/**\n\t * Plays the matching interface cue through the sound controller. Off by\n\t * default; only audible once the user has enabled sound.\n\t */\n\tsound?: boolean;\n}\n\n/**\n * The root of the menu compound. Renders no DOM of its own — exactly as the\n * source does — and publishes the one context its trigger and content read.\n *\n * No `forwardRef`: the source declares no `ref` binding here, and the Svelte\n * API surface is the contract, per-component.\n */\nexport function DropdownMenu({\n\topen: openProp,\n\tonOpenChange,\n\tside = \"bottom\",\n\talign = \"start\",\n\toffset = 4,\n\tloop = true,\n\tchildren,\n\tsound = false,\n}: DropdownMenuProps) {\n\t// `useFancyId()`, the counterpart of `$props.id()` — the trigger renders\n\t// its own id unconditionally (not gated on `open`), so it has to agree\n\t// with itself from the first server-rendered paint. Never `uid()`, which\n\t// throws on the server by design.\n\tconst uid = useFancyId();\n\tconst contentId = `${uid}-content`;\n\tconst triggerId = `${uid}-trigger`;\n\n\t// Both of these are plain `let`s in the source — deliberately NOT reactive\n\t// state there, and therefore plain refs here. Nothing renders off either\n\t// one: the content reads `triggerRef` lazily, from an anchor getter and an\n\t// exclude getter that both run at event time, and `focusEdge` is read once\n\t// by the effect that moves focus after the panel mounts.\n\tconst triggerRef = useRef<HTMLElement | null>(null);\n\tconst focusEdgeRef = useRef<\"first\" | \"last\">(\"first\");\n\n\t// The React shape of the source's `open = $bindable(false)`: an internal\n\t// copy seeded from the prop, re-synced during render whenever the CALLER\n\t// changes the prop, and free to move on its own in between. That is what\n\t// makes all three documented call shapes work off one implementation — a\n\t// caller driving `open` from its own state, a caller who passes only\n\t// `onOpenChange`, and a caller who passes neither and lets the trigger run\n\t// the whole thing. A strictly-controlled reading would break the third,\n\t// which the source supports: writing a bindable prop moves the local copy\n\t// whether or not the caller bound it.\n\t//\n\t// Re-synced in the render path, not an effect: an effect would paint one\n\t// frame of the stale value first. Same pattern as `Popover`/`Dialog`.\n\tconst [open, setOpenState] = useState(openProp ?? false);\n\tconst [lastOpenProp, setLastOpenProp] = useState(openProp);\n\tif (lastOpenProp !== openProp) {\n\t\tsetLastOpenProp(openProp);\n\t\tsetOpenState(openProp ?? false);\n\t}\n\n\tconst openRef = useLiveRef(open);\n\tconst handleOpenChange = useEventCallback(onOpenChange);\n\t// The `sound &&` guard moves into the hook, so `silent` keeps its exact\n\t// meaning below and a cue is decided audible inside `sound.play()` at call\n\t// time rather than at render time.\n\tconst playCue = useSoundCue(sound);\n\n\t// The one place `open` changes, in either direction — a plain function,\n\t// not an effect, so it never reads and writes `open` in the same pass and\n\t// never fights a controlled caller's own write. Not modal (no focus trap),\n\t// so returning focus to the trigger on close is this component's own job,\n\t// done here rather than left to a shared primitive: Escape and an outside\n\t// click (both routed through the same dismissable callback, on purpose)\n\t// take this path by default, and Tab does not.\n\tconst setOpen = useCallback(\n\t\t(next: boolean, options: MenuCloseOptions = {}): void => {\n\t\t\tif (openRef.current === next) return;\n\t\t\tsetOpenState(next);\n\t\t\thandleOpenChange(next);\n\t\t\tif (!options.silent) playCue(next ? \"open\" : \"close\");\n\t\t\t// `triggerRef.current?.isConnected` is checked explicitly, not left\n\t\t\t// to `.focus()`'s own silent no-op on a detached element (which\n\t\t\t// would behave identically either way) — stating the intent in\n\t\t\t// code. There is no fallback target beyond this: unlike a modal, a\n\t\t\t// menu has nothing defensible to fall back to, so a consumer who\n\t\t\t// removes the trigger from the DOM while its menu is open gets\n\t\t\t// focus left wherever the browser puts it, not a guess at somewhere\n\t\t\t// better.\n\t\t\tif (!next && (options.returnFocus ?? true) && triggerRef.current?.isConnected) {\n\t\t\t\ttriggerRef.current.focus();\n\t\t\t}\n\t\t},\n\t\t[openRef, handleOpenChange, playCue]\n\t);\n\n\t// Identity-stable, so the trigger's publish effect and the content's\n\t// callbacks never re-run just because the root re-rendered.\n\tconst setTriggerRef = useCallback((el: HTMLElement | null): void => {\n\t\ttriggerRef.current = el;\n\t}, []);\n\n\tconst openWithFocus = useCallback(\n\t\t(edge: \"first\" | \"last\"): void => {\n\t\t\tfocusEdgeRef.current = edge;\n\t\t\tsetOpen(true);\n\t\t},\n\t\t[setOpen]\n\t);\n\n\tconst close = useCallback(\n\t\t(options: MenuCloseOptions = {}): void => {\n\t\t\tsetOpen(false, options);\n\t\t},\n\t\t[setOpen]\n\t);\n\n\t// A plain object rebuilt when its scalar inputs change — the rebuild is\n\t// what makes the trigger and the content re-render. The two non-reactive\n\t// fields stay getters over their refs, which is precisely what they are on\n\t// the source side.\n\tconst context = useMemo<DropdownMenuRootContext>(\n\t\t() => ({\n\t\t\tcontentId,\n\t\t\ttriggerId,\n\t\t\tside,\n\t\t\talign,\n\t\t\toffset,\n\t\t\tloop,\n\t\t\topen,\n\t\t\tsound,\n\t\t\tget focusEdge() {\n\t\t\t\treturn focusEdgeRef.current;\n\t\t\t},\n\t\t\tget triggerRef() {\n\t\t\t\treturn triggerRef.current;\n\t\t\t},\n\t\t\tsetTriggerRef,\n\t\t\topenWithFocus,\n\t\t\tclose,\n\t\t}),\n\t\t[\n\t\t\tcontentId,\n\t\t\ttriggerId,\n\t\t\tside,\n\t\t\talign,\n\t\t\toffset,\n\t\t\tloop,\n\t\t\topen,\n\t\t\tsound,\n\t\t\tsetTriggerRef,\n\t\t\topenWithFocus,\n\t\t\tclose,\n\t\t]\n\t);\n\n\treturn <DROPDOWN_MENU_KEY.Provider value={context}>{children}</DROPDOWN_MENU_KEY.Provider>;\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenu.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuContent.tsx","content":"\"use client\";\n\nimport { forwardRef, useCallback, useEffect, useMemo } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils\";\nimport { Portal } from \"../../internals/Portal\";\nimport { useDismissable } from \"../../internals/dismissable\";\nimport { useMenuFocus } from \"../../internals/menu\";\nimport { useAnchorPosition } from \"../../internals/use-anchor-position\";\nimport { useComposedRefs } from \"../../internals/dom/use-composed-refs\";\nimport { useConstant } from \"../../internals/dom/ssr\";\nimport { useElementRef } from \"../../internals/dom/use-element-ref\";\nimport { useLiveRef } from \"../../internals/dom/use-live-ref\";\nimport { anchored, originFor } from \"../../internals/motion/anchored\";\nimport { usePresence } from \"../../internals/motion/presence\";\nimport { createOpenSubRegistry, handleMenuContentKeydown } from \"./menu-shared\";\nimport { MENU_KEY, useDropdownMenuRoot } from \"./types\";\nimport type { MenuCloseOptions, MenuContext } from \"./types\";\n\nexport interface DropdownMenuContentProps {\n\t/** The `DropdownMenuItem`/`DropdownMenuSeparator`/`DropdownMenuLabel`/`DropdownMenuSub` children. */\n\tchildren?: ReactNode;\n\t/** Additional CSS classes, merged onto the panel. */\n\tclassName?: string;\n}\n\n/**\n * The portalled, anchored panel, and the level of menu-focus wiring its own\n * direct items register with.\n *\n * The source declares `ref = $bindable(null)`, so the panel element arrives\n * through the ref channel rather than a prop.\n */\nexport const DropdownMenuContent = forwardRef<HTMLDivElement, DropdownMenuContentProps>(\n\tfunction DropdownMenuContent({ children, className }, forwardedRef) {\n\t\tconst root = useDropdownMenuRoot();\n\n\t\t// The NODE, not a ref (convention C-1): the panel is created by\n\t\t// `presence.mounted`, so a `useRef` read inside a `[]`-deps effect\n\t\t// would still be null when the position and dismiss effects fire.\n\t\tconst [panel, setPanelNode] = useElementRef<HTMLDivElement>();\n\n\t\t// `loop` as a PLAIN VALUE: the hook hands the core a getter over a live\n\t\t// ref, so `move()` reads `root.loop` fresh on every call exactly as the\n\t\t// source's `get loop()` did.\n\t\tconst focus = useMenuFocus({ loop: root.loop });\n\n\t\tconst registry = useConstant(createOpenSubRegistry);\n\t\tconst { registerOpenSub, closeSiblingSubs } = registry;\n\n\t\tconst presence = usePresence(root.open);\n\n\t\t// The placement as ACTUALLY resolved — the requested side and align\n\t\t// until `computePosition` flips or clamps it away from a viewport edge.\n\t\t// Seeded with the *requested* values by the hook itself, so the common\n\t\t// never-flipped case never shows a one-frame origin jump on open.\n\t\tconst { side: resolvedSide, align: resolvedAlign } = useAnchorPosition(panel, {\n\t\t\tanchor: () => root.triggerRef,\n\t\t\tside: root.side,\n\t\t\talign: root.align,\n\t\t\toffset: root.offset,\n\t\t});\n\n\t\t// `active: root.open` — a plain boolean where the source needed a\n\t\t// getter. The layer stays ON the stack for its whole exit and stops\n\t\t// being TOP of it the instant `open` flips, so a second Escape during\n\t\t// the fade is neither answered again nor swallowed on its way to\n\t\t// whatever sits underneath.\n\t\tuseDismissable(panel, {\n\t\t\tonDismiss: () => root.close(),\n\t\t\texclude: () => [root.triggerRef],\n\t\t\tactive: root.open,\n\t\t\tkeepFocus: true,\n\t\t});\n\n\t\t// Identity-stable for the life of the root, so this level's own context\n\t\t// is not rebuilt just because the root re-rendered.\n\t\tconst closeRoot = root.close;\n\t\tconst closeAll = useCallback(\n\t\t\t(options?: MenuCloseOptions) => {\n\t\t\t\t// Closing the root unmounts this whole subtree — every nested\n\t\t\t\t// `DropdownMenuSub`/`DropdownMenuSubContent` goes with it, so\n\t\t\t\t// there is nothing more for this level to do to close a\n\t\t\t\t// deeply-nested submenu's own state.\n\t\t\t\tcloseRoot(options);\n\t\t\t},\n\t\t\t[closeRoot]\n\t\t);\n\n\t\tconst menuContext = useMemo<MenuContext>(\n\t\t\t() => ({\n\t\t\t\tfocus,\n\t\t\t\titemTextClass: \"text-[13px]\",\n\t\t\t\trootOpen: root.open,\n\t\t\t\tsound: root.sound,\n\t\t\t\tcloseAll,\n\t\t\t\tregisterOpenSub,\n\t\t\t\tcloseSiblingSubs,\n\t\t\t}),\n\t\t\t[focus, root.open, root.sound, closeAll, registerOpenSub, closeSiblingSubs]\n\t\t);\n\n\t\t// Divergence D-9: the source waits a `tick()` here because its items\n\t\t// register from their own mount effect, which runs AFTER this\n\t\t// component's. React runs child effects before parent effects and\n\t\t// registration happens in each item's ref callback — earlier still —\n\t\t// so the items are already registered by the time this runs.\n\t\t//\n\t\t// Keyed on `presence.mounted` as well as `open`: `mounted` flips in\n\t\t// `usePresence`'s layout effect, one render after `open` does, and it\n\t\t// is that later commit which actually creates the items. `focusEdge`\n\t\t// is read through a live ref rather than listed as a dependency,\n\t\t// mirroring the source, where it is a plain `let` no effect tracks —\n\t\t// depending on it here would re-steal focus on every root re-render.\n\t\tconst mounted = presence.mounted;\n\t\tconst open = root.open;\n\t\tconst focusEdgeRef = useLiveRef(root.focusEdge);\n\t\tuseEffect(() => {\n\t\t\tif (!open || !mounted) return;\n\t\t\tfocus.moveToEdge(focusEdgeRef.current);\n\t\t}, [open, mounted, focus, focusEdgeRef]);\n\n\t\tfunction handleKeydown(event: KeyboardEvent<HTMLDivElement>): void {\n\t\t\t// Only keys pressed inside THIS panel. A `DropdownMenuSubContent`\n\t\t\t// is portalled to `document.body` — a DOM sibling of this panel,\n\t\t\t// exactly as in the source — but it stays a React-tree DESCENDANT\n\t\t\t// of this element, and React propagates synthetic events through a\n\t\t\t// portal. Without this guard every ArrowDown/ArrowUp/Home/End and\n\t\t\t// every typeahead character pressed inside an open submenu would be\n\t\t\t// handled twice: once against that submenu's own focus core, then\n\t\t\t// again here, and this level's `.focus()` on one of its own items\n\t\t\t// would yank real DOM focus — the highlight this family renders off\n\t\t\t// — out of the submenu, leaving it unnavigable by keyboard. In the\n\t\t\t// source the two panels are native DOM siblings and the second\n\t\t\t// dispatch simply does not exist.\n\t\t\tif (!event.currentTarget.contains(event.target as Node)) return;\n\t\t\thandleMenuContentKeydown(event, menuContext, {\n\t\t\t\t// Tab is never `preventDefault`ed — the browser's own traversal is\n\t\t\t\t// what moves focus on, and it moves on from wherever focus SITS.\n\t\t\t\t// This panel is portalled to `document.body`, so the item holding\n\t\t\t\t// focus is a DOM sibling of the whole app: a Tab resuming from\n\t\t\t\t// there (or from `<body>`, once the panel is gone) walks straight\n\t\t\t\t// past every control that follows the trigger. Handing focus back\n\t\t\t\t// to the trigger synchronously, inside the keydown, is what gives\n\t\t\t\t// the default action the right starting point — forward to the\n\t\t\t\t// control after the trigger, backward to the one before it.\n\t\t\t\t//\n\t\t\t\t// Divergence from the Svelte source, which passes\n\t\t\t\t// `returnFocus: false` here and leaves the same gap.\n\t\t\t\tonTab: () => root.close(),\n\t\t\t});\n\t\t}\n\n\t\t// Convention C-2: composed ABOVE the conditional below. Calling this\n\t\t// inside the JSX branch would be a conditional hook and would throw the\n\t\t// first time `mounted` flips.\n\t\t//\n\t\t// ONE bidirectional transition, never a split in/out pair: the\n\t\t// in-flight counterpart's current position is passed into the fresh\n\t\t// leg, so a menu reopened mid-exit continues from where it is instead\n\t\t// of snapping to invisible first. `entering` is what tells it which way\n\t\t// it is going, and the params are read at the instant each leg starts.\n\t\tconst panelRef = useComposedRefs(\n\t\t\tsetPanelNode,\n\t\t\tforwardedRef,\n\t\t\tpresence.register(anchored, (entering) => ({ side: resolvedSide, entering }))\n\t\t);\n\n\t\t// text-[13px]: this family's own density. Every item leaf inherits it\n\t\t// from here via normal CSS (they carry no font-size of their own); a\n\t\t// nested `DropdownMenuSubContent` gets it forwarded through\n\t\t// `menuContext.itemTextClass` instead, since a portalled submenu is a\n\t\t// DOM sibling of this panel once open, not a descendant.\n\t\tconst classes = cn(\n\t\t\t\"ft-dropdown-menu-content flex w-max min-w-[180px] flex-col gap-[1px] rounded-[10px] border border-border bg-popover p-[5px] text-[13px] text-popover-foreground shadow-lg outline-none\",\n\t\t\tclassName\n\t\t);\n\n\t\t// The `Portal` stays ABOVE the mounted gate, and the gate wraps its\n\t\t// CHILDREN. `usePortalTarget` resolves its container in a layout\n\t\t// effect, so a `Portal` that first mounts in the same commit as the\n\t\t// panel would render null on that pass — `usePresence` would then find\n\t\t// no registered leg and the entrance would be silently skipped.\n\t\t//\n\t\t// No focus trap: a dropdown menu is not modal. Tab is handled in\n\t\t// `handleKeydown` instead — it closes the menu and is never\n\t\t// `preventDefault`ed, so the browser's own Tab traversal continues from\n\t\t// wherever real DOM focus currently sits. That also means this panel\n\t\t// needs no eager focus-return handle the way a modal surface does:\n\t\t// `DropdownMenu`'s own `setOpen` refocuses the trigger from a plain\n\t\t// function outside this gate, so the return already lands at the\n\t\t// dismiss instant rather than at unmount.\n\t\t//\n\t\t// `data-state` is an ordinary attribute (divergence D-2) carrying\n\t\t// `surfaceState`'s TWO values — never `\"opening\"` (convention C-5).\n\t\t// `inert` is not written by hand either: `usePresence` sets it on every\n\t\t// registered node for the whole exit, which is what keeps a menu on its\n\t\t// way out from answering a click.\n\t\treturn (\n\t\t\t<Portal>\n\t\t\t\t<MENU_KEY.Provider value={menuContext}>\n\t\t\t\t\t{presence.mounted ? (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tref={panelRef}\n\t\t\t\t\t\t\tid={root.contentId}\n\t\t\t\t\t\t\trole=\"menu\"\n\t\t\t\t\t\t\taria-labelledby={root.triggerId}\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\tclassName={classes}\n\t\t\t\t\t\t\tdata-state={presence.surfaceState}\n\t\t\t\t\t\t\tdata-side={resolvedSide}\n\t\t\t\t\t\t\tdata-align={root.align}\n\t\t\t\t\t\t\tstyle={{ transformOrigin: originFor(resolvedSide, resolvedAlign) }}\n\t\t\t\t\t\t\tonKeyDown={handleKeydown}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : null}\n\t\t\t\t</MENU_KEY.Provider>\n\t\t\t</Portal>\n\t\t);\n\t}\n);\n\nDropdownMenuContent.displayName = \"DropdownMenuContent\";\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuContent.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuItem.tsx","content":"\"use client\";\n\nimport { useRef } from \"react\";\nimport type { ComponentPropsWithoutRef, MouseEvent, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils\";\nimport { useMenuItemRef } from \"../../internals/menu\";\nimport { useComposedRefs } from \"../../internals/dom/use-composed-refs\";\nimport { useSoundCue } from \"../../sound/use-sound\";\nimport { useMenuContext } from \"./types\";\n\ninterface DropdownMenuItemOwnProps {\n\t/** Called when the item is selected, by click or (in a real browser) by Enter/Space while it holds focus. */\n\tonSelect?: () => void;\n\t/** Disables the item: skipped by keyboard navigation and typeahead, inert to click. */\n\tdisabled?: boolean;\n\t/** Visual/semantic variant. `\"destructive\"` renders in the destructive color. */\n\tvariant?: \"default\" | \"destructive\";\n\t/** Display-only keyboard shortcut, rendered as a trailing `<kbd>`. This component binds no global keys for it. */\n\tshortcut?: string;\n\t/** Whether selecting the item closes the whole menu. Defaults to true. */\n\tcloseOnSelect?: boolean;\n\t/** Leading icon. */\n\ticon?: ReactNode;\n\t/** The item's label. */\n\tchildren?: ReactNode;\n\t/** Additional CSS classes. */\n\tclassName?: string;\n}\n\n/**\n * Native `<button>` attributes and listeners are forwarded to the button; the managed\n * ARIA, state and structural attributes stay the component's.\n */\nexport interface DropdownMenuItemProps\n\textends\n\t\tOmit<ComponentPropsWithoutRef<\"button\">, keyof DropdownMenuItemOwnProps>,\n\t\tDropdownMenuItemOwnProps {}\n\n/**\n * One selectable row.\n *\n * No `forwardRef`: the source exposes no `ref` binding for an item, and the\n * Svelte API surface is the contract, per-component.\n */\nexport function DropdownMenuItem({\n\tonSelect,\n\tdisabled = false,\n\tvariant = \"default\",\n\tshortcut,\n\tcloseOnSelect = true,\n\ticon,\n\tchildren,\n\tclassName,\n\tonClick,\n\tonMouseEnter,\n\t...rest\n}: DropdownMenuItemProps) {\n\t// `DropdownMenuContent`/`DropdownMenuSubContent` always provide this\n\t// before mounting their children, so there is no standalone-usage\n\t// fallback to design for.\n\tconst ctx = useMenuContext();\n\n\t// A plain ref, not `useElementRef`: no hook here is keyed on the node's\n\t// existence — it is only ever read from inside an event handler, by which\n\t// time it is long since attached.\n\tconst itemRef = useRef<HTMLButtonElement | null>(null);\n\t// Registration happens in the ref callback, replacing the source's\n\t// per-item mount effect. Order is irrelevant: the core sorts by\n\t// `compareDocumentPosition` at navigation time.\n\tconst registerRef = useMenuItemRef(ctx.focus);\n\tconst ref = useComposedRefs(itemRef, registerRef);\n\n\tconst playCue = useSoundCue(ctx.sound);\n\n\t// This item's own label — the `<span>{children}</span>` below, nothing\n\t// else — is already isolated from the icon and the shortcut (both separate\n\t// `aria-hidden` siblings), so the menu core's typeahead fallback (visible\n\t// text, skipping `aria-hidden` subtrees) already gets this markup right on\n\t// its own. `data-typeahead-label` is still there in the core for a\n\t// consumer hand-building menu items who hasn't marked their own icons\n\t// `aria-hidden` — this component just doesn't need the escape hatch.\n\n\t// A native `disabled` attribute already blocks a real click, and React\n\t// additionally refuses to deliver `onClick` to a disabled button; the\n\t// handler guards again rather than trusting either.\n\tfunction handleClick(event: MouseEvent<HTMLButtonElement>): void {\n\t\tif (disabled) return;\n\t\tplayCue(\"select\");\n\t\t// Mouse hover already syncs the menu core's tracked focus position\n\t\t// (see `handleMouseEnter` below), and the common `closeOnSelect` path\n\t\t// makes this redundant too — closing moves focus back to the trigger\n\t\t// regardless. The gap is `closeOnSelect: false` reached by something\n\t\t// that skips `mouseenter` entirely, a touch tap being the realistic\n\t\t// case: without this, the core's own idea of \"focused\" stays wherever\n\t\t// it last was, and the next arrow key starts from the wrong place even\n\t\t// though this row is what the user just interacted with.\n\t\tif (itemRef.current) ctx.focus.focusItem(itemRef.current);\n\t\tonSelect?.();\n\t\t// `silent: true` — this click already played `select` above; closing\n\t\t// the menu on top of it must never also play `close`, or one item\n\t\t// activation would yield two cues instead of one.\n\t\tif (closeOnSelect) ctx.closeAll({ silent: true });\n\t\tonClick?.(event);\n\t}\n\n\t// Real DOM focus IS the highlight in a `role=\"menu\"` built on the menu\n\t// core — so, unlike a listbox's rows, hovering an item deliberately moving\n\t// focus onto it is correct here. There is nothing to cancel: this is the\n\t// behaviour a mouse user needs to stay in sync with a keyboard user's own\n\t// arrow-key highlight.\n\tfunction handleMouseEnter(event: MouseEvent<HTMLButtonElement>): void {\n\t\tif (disabled || !itemRef.current) return;\n\t\tctx.focus.focusItem(itemRef.current);\n\t\tonMouseEnter?.(event);\n\t}\n\n\t// No font-size here: it inherits from whichever panel renders this item\n\t// (`DropdownMenuContent` at 13px, or a `*SubContent` carrying its own\n\t// family's size through). A hardcoded size here would win over all of\n\t// them.\n\tconst classes = cn(\n\t\t\"ft-dropdown-menu-item flex w-full cursor-pointer items-center justify-between gap-[10px] rounded-[6px] px-[10px] py-[7px] text-left text-foreground outline-none\",\n\t\t\"hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground\",\n\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\tvariant === \"destructive\" &&\n\t\t\t\"text-destructive hover:bg-destructive/10 hover:text-destructive focus-visible:bg-destructive/10 focus-visible:text-destructive\",\n\t\tclassName\n\t);\n\n\treturn (\n\t\t<button\n\t\t\t{...rest}\n\t\t\tref={ref}\n\t\t\ttype=\"button\"\n\t\t\trole=\"menuitem\"\n\t\t\ttabIndex={-1}\n\t\t\tdisabled={disabled}\n\t\t\taria-disabled={disabled ? \"true\" : undefined}\n\t\t\tdata-variant={variant}\n\t\t\tclassName={classes}\n\t\t\tonClick={handleClick}\n\t\t\tonMouseEnter={handleMouseEnter}\n\t\t>\n\t\t\t<span className=\"flex items-center gap-[10px]\">\n\t\t\t\t{icon ? (\n\t\t\t\t\t<span className=\"ft-dropdown-menu-item-icon\" aria-hidden=\"true\">\n\t\t\t\t\t\t{icon}\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t<span>{children}</span>\n\t\t\t</span>\n\t\t\t{/*\n\t\t\t\tReal DOM text, not CSS `content` — that's what lets it participate\n\t\t\t\tin the button's accessible name at all — but marked `aria-hidden`\n\t\t\t\tanyway: raw symbol glyphs like \"⌘R\" don't announce usefully as\n\t\t\t\tspeech, and this item's own label text already carries the\n\t\t\t\tmeaningful accessible name on its own.\n\t\t\t*/}\n\t\t\t{shortcut ? (\n\t\t\t\t<kbd\n\t\t\t\t\taria-hidden=\"true\"\n\t\t\t\t\tclassName=\"ft-dropdown-menu-item-shortcut text-muted-foreground font-mono text-[10px]\"\n\t\t\t\t>\n\t\t\t\t\t{shortcut}\n\t\t\t\t</kbd>\n\t\t\t) : null}\n\t\t</button>\n\t);\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuItem.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuLabel.tsx","content":"\"use client\";\n\nimport type { ReactNode } from \"react\";\n\nimport { cn } from \"../../utils\";\n\nexport interface DropdownMenuLabelProps {\n\t/** The label's text. */\n\tchildren?: ReactNode;\n\t/** Additional CSS classes. */\n\tclassName?: string;\n}\n\n/**\n * A group heading, not a menuitem: never registered with the menu-focus core,\n * never focusable, skipped entirely by arrow-key navigation and typeahead.\n * Real text content (not `aria-hidden`), so it still reads to assistive tech\n * as part of the menu — the same non-interactive-but-audible treatment\n * `DropdownMenuItem`'s own label gets, just without a role.\n */\nexport function DropdownMenuLabel({ children, className }: DropdownMenuLabelProps) {\n\treturn (\n\t\t<div\n\t\t\tclassName={cn(\n\t\t\t\t\"ft-dropdown-menu-label text-muted-foreground px-[8px] py-[4px] text-[10px] font-semibold tracking-[0.08em] uppercase opacity-60\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t>\n\t\t\t{children}\n\t\t</div>\n\t);\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuLabel.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuSeparator.tsx","content":"\"use client\";\n\nimport { cn } from \"../../utils\";\n\nexport interface DropdownMenuSeparatorProps {\n\t/** Additional CSS classes. */\n\tclassName?: string;\n}\n\n/** Not a menuitem, never registered with the menu-focus core: purely a visual/semantic divider. */\nexport function DropdownMenuSeparator({ className }: DropdownMenuSeparatorProps) {\n\treturn (\n\t\t<div\n\t\t\trole=\"separator\"\n\t\t\tclassName={cn(\"ft-dropdown-menu-separator bg-border my-[4px] h-px\", className)}\n\t\t/>\n\t);\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuSeparator.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuSub.tsx","content":"\"use client\";\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { ReactNode } from \"react\";\n\nimport type { Side, Align } from \"../../internals/anchor-position\";\nimport { useFancyId } from \"../../internals/use-id\";\nimport { useSoundCue } from \"../../sound/use-sound\";\nimport { SUB_KEY, useMenuContext } from \"./types\";\nimport type { SubContext } from \"./types\";\n\nexport interface DropdownMenuSubProps {\n\t/** The `DropdownMenuSubTrigger` and `DropdownMenuSubContent`. */\n\tchildren?: ReactNode;\n}\n\n// Close-intent delay: leaving the trigger (or the content) starts this timer\n// rather than closing immediately, so a pointer travelling from the trigger\n// row into the submenu — necessarily crossing empty space for an instant —\n// doesn't flicker the submenu shut before it arrives.\nconst CLOSE_INTENT_MS = 200;\n\n/**\n * The boundary that owns one submenu's open state and its hover-intent\n * timers. Renders no DOM of its own.\n */\nexport function DropdownMenuSub({ children }: DropdownMenuSubProps) {\n\t// The *parent* level's context — this component publishes no `MENU_KEY` of\n\t// its own (only `DropdownMenuSubContent` does, scoped to its own subtree).\n\t// This is what lets a selection deep inside this submenu close the whole\n\t// tree, and what lets opening this submenu close a sibling one at the same\n\t// level.\n\tconst parentMenu = useMenuContext();\n\n\t// One id per submenu, split into the two the pair needs: the panel carries\n\t// the first, its own row the second, and the panel points back at that row\n\t// with `aria-labelledby` so a submenu announces which item opened it.\n\tconst uid = useFancyId();\n\tconst contentId = `${uid}-content`;\n\tconst triggerId = `${uid}-trigger`;\n\n\tconst [open, setOpen] = useState(false);\n\t// A synchronous mirror of `open`, written at the same instant `setOpen` is\n\t// called. The source's `open` is a rune read back synchronously by\n\t// `openSub`/`closeSub`'s own guards, and React state is not readable until\n\t// the next render — this ref is what keeps those guards exact.\n\tconst openRef = useRef(false);\n\n\t// Plain refs, exactly as in the source, where both are non-reactive `let`s:\n\t// nothing renders off either one.\n\tconst triggerRef = useRef<HTMLElement | null>(null);\n\tconst closeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\tconst unregisterOpenSub = useRef<(() => void) | null>(null);\n\n\tconst [resolvedSide, setResolvedSide] = useState<Side>(\"right\");\n\t// Reported by `useAnchorPosition` alongside the side: a submenu clamped\n\t// along its cross axis near a viewport edge no longer touches its trigger\n\t// at the requested corner, and its entrance has to grow from the real one.\n\tconst [resolvedAlign, setResolvedAlign] = useState<Align>(\"start\");\n\n\tconst playCue = useSoundCue(parentMenu.sound);\n\t// Identity-stable members of the parent context, so the callbacks below\n\t// are not rebuilt just because a level above re-rendered.\n\tconst { closeSiblingSubs, registerOpenSub } = parentMenu;\n\n\tconst clearCloseTimer = useCallback((): void => {\n\t\tif (closeTimer.current !== null) {\n\t\t\tclearTimeout(closeTimer.current);\n\t\t\tcloseTimer.current = null;\n\t\t}\n\t}, []);\n\n\tconst closeSub = useCallback(\n\t\t(returnFocus: boolean, silent = false): void => {\n\t\t\tclearCloseTimer();\n\t\t\tif (!openRef.current) return;\n\t\t\topenRef.current = false;\n\t\t\tsetOpen(false);\n\t\t\tunregisterOpenSub.current?.();\n\t\t\tunregisterOpenSub.current = null;\n\t\t\tif (returnFocus) triggerRef.current?.focus();\n\t\t\tif (!silent) playCue(\"close\");\n\t\t},\n\t\t[clearCloseTimer, playCue]\n\t);\n\n\tconst openSub = useCallback((): void => {\n\t\tclearCloseTimer();\n\t\tif (openRef.current) return;\n\t\tif (triggerRef.current) closeSiblingSubs(triggerRef.current);\n\t\topenRef.current = true;\n\t\tsetOpen(true);\n\t\tif (triggerRef.current) {\n\t\t\t// A close driven by the parent — the whole tree closing after a\n\t\t\t// selection or Escape, or a sibling submenu opening — is silent: the\n\t\t\t// root's own cue (or the sibling's `open`) already told the story.\n\t\t\tunregisterOpenSub.current = registerOpenSub(triggerRef.current, () => closeSub(false, true));\n\t\t}\n\t\t// A submenu is a real panel opening; it sounds like one. Inherited from\n\t\t// the root's `sound` prop through the parent level's context.\n\t\tplayCue(\"open\");\n\t}, [clearCloseTimer, closeSiblingSubs, registerOpenSub, closeSub, playCue]);\n\n\tconst keepOpen = useCallback((): void => {\n\t\tclearCloseTimer();\n\t}, [clearCloseTimer]);\n\n\tconst scheduleClose = useCallback((): void => {\n\t\tclearCloseTimer();\n\t\tcloseTimer.current = setTimeout(() => {\n\t\t\tcloseTimer.current = null;\n\t\t\tcloseSub(false);\n\t\t}, CLOSE_INTENT_MS);\n\t}, [clearCloseTimer, closeSub]);\n\n\t// Cancels a pending close-intent timer, and releases this submenu's own\n\t// registration in the parent's open-sub registry, on unmount — not just\n\t// from the event handlers above. A keyed list reordering can destroy this\n\t// exact `DropdownMenuSub` while the parent context and its siblings stay\n\t// alive; without this, a stale timer or a stale `unregisterOpenSub`\n\t// closure lingers referencing a component that's already gone. Every call\n\t// along that path already guards itself against a detached/stale target,\n\t// so this was never a crash — it's hygiene.\n\tuseEffect(() => {\n\t\treturn () => {\n\t\t\tclearCloseTimer();\n\t\t\tunregisterOpenSub.current?.();\n\t\t};\n\t}, [clearCloseTimer]);\n\n\tconst setTriggerRef = useCallback((el: HTMLElement | null): void => {\n\t\ttriggerRef.current = el;\n\t}, []);\n\n\tconst setPlacement = useCallback((side: Side, align: Align): void => {\n\t\tsetResolvedSide(side);\n\t\tsetResolvedAlign(align);\n\t}, []);\n\n\tconst context = useMemo<SubContext>(\n\t\t() => ({\n\t\t\topen,\n\t\t\tcontentId,\n\t\t\ttriggerId,\n\t\t\tresolvedSide,\n\t\t\tresolvedAlign,\n\t\t\tget triggerRef() {\n\t\t\t\treturn triggerRef.current;\n\t\t\t},\n\t\t\tsetTriggerRef,\n\t\t\tsetPlacement,\n\t\t\topenSub,\n\t\t\tcloseSub,\n\t\t\tkeepOpen,\n\t\t\tscheduleClose,\n\t\t}),\n\t\t[\n\t\t\topen,\n\t\t\tcontentId,\n\t\t\ttriggerId,\n\t\t\tresolvedSide,\n\t\t\tresolvedAlign,\n\t\t\tsetTriggerRef,\n\t\t\tsetPlacement,\n\t\t\topenSub,\n\t\t\tcloseSub,\n\t\t\tkeepOpen,\n\t\t\tscheduleClose,\n\t\t]\n\t);\n\n\treturn <SUB_KEY.Provider value={context}>{children}</SUB_KEY.Provider>;\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuSub.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuSubContent.tsx","content":"\"use client\";\n\nimport { forwardRef, useCallback, useEffect, useMemo } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils\";\nimport { Portal } from \"../../internals/Portal\";\nimport { useDismissable } from \"../../internals/dismissable\";\nimport { useMenuFocus } from \"../../internals/menu\";\nimport { useAnchorPosition } from \"../../internals/use-anchor-position\";\nimport { useComposedRefs } from \"../../internals/dom/use-composed-refs\";\nimport { useConstant } from \"../../internals/dom/ssr\";\nimport { useElementRef } from \"../../internals/dom/use-element-ref\";\nimport { anchored, originFor } from \"../../internals/motion/anchored\";\nimport { usePresence } from \"../../internals/motion/presence\";\nimport { createOpenSubRegistry, handleMenuContentKeydown } from \"./menu-shared\";\nimport { MENU_KEY, useMenuContext, useSubContext } from \"./types\";\nimport type { MenuCloseOptions, MenuContext } from \"./types\";\n\nexport interface DropdownMenuSubContentProps {\n\t/** The `DropdownMenuItem`/`DropdownMenuSeparator`/`DropdownMenuLabel`/nested `DropdownMenuSub` children. */\n\tchildren?: ReactNode;\n\t/** Additional CSS classes. */\n\tclassName?: string;\n}\n\n/**\n * A submenu's own portalled, anchored panel, and the level of menu-focus\n * wiring its own direct items register with.\n *\n * The source declares `ref = $bindable(null)`, so the panel element arrives\n * through the ref channel rather than a prop.\n */\nexport const DropdownMenuSubContent = forwardRef<HTMLDivElement, DropdownMenuSubContentProps>(\n\tfunction DropdownMenuSubContent({ children, className }, forwardedRef) {\n\t\t// Captured before the provider below shadows it for this subtree —\n\t\t// `menuContext.closeAll` delegates straight to this, so a selection\n\t\t// three submenus deep still closes the whole tree in one hop.\n\t\tconst parentMenu = useMenuContext();\n\t\tconst sub = useSubContext();\n\n\t\t// `sub.open` alone is not liveness. Closing the root — selecting a root\n\t\t// item, or an external `open` write — flips only the root's state and\n\t\t// tears this subtree down with it, leaving `sub.open` true for the\n\t\t// whole global outro. Everything that has to know whether this panel is\n\t\t// a live top layer reads THIS instead: the presence clock, which would\n\t\t// otherwise run the entrance curve on the way out, and the dismissable\n\t\t// layer, which would otherwise let a fading submenu swallow an Escape\n\t\t// or an outside click that belongs to whatever is underneath.\n\t\t//\n\t\t// `parentMenu.rootOpen` rather than the family's own root context: this\n\t\t// level reads the contract every menu family implements, and\n\t\t// republishing `live` as this level's own `rootOpen` below is what\n\t\t// makes the answer compose down a chain of nested submenus.\n\t\tconst live = sub.open && parentMenu.rootOpen;\n\n\t\tconst [panel, setPanelNode] = useElementRef<HTMLDivElement>();\n\n\t\tconst focus = useMenuFocus();\n\t\tconst registry = useConstant(createOpenSubRegistry);\n\t\tconst { registerOpenSub, closeSiblingSubs } = registry;\n\n\t\tconst presence = usePresence(live);\n\n\t\t// `align` is the literal `\"start\"`, and `side` the literal `\"right\"` —\n\t\t// a submenu never asks for any other placement. The resolved pair goes\n\t\t// back onto the sub context rather than into local state: it already\n\t\t// drives `DropdownMenuSubTrigger`'s caret glyph, and a second copy here\n\t\t// would give the caret and the growth origin two sources of truth that\n\t\t// could disagree after a flip.\n\t\tconst setPlacement = sub.setPlacement;\n\t\tuseAnchorPosition(panel, {\n\t\t\tanchor: () => sub.triggerRef,\n\t\t\tside: \"right\",\n\t\t\talign: \"start\",\n\t\t\toffset: 2,\n\t\t\tonPlacement: (side, align) => setPlacement(side, align),\n\t\t});\n\n\t\t// Its own layer: Escape and an outside click close only THIS submenu\n\t\t// (returning focus to its trigger), not the root, one interaction at a\n\t\t// time.\n\t\tuseDismissable(panel, {\n\t\t\tonDismiss: () => sub.closeSub(true),\n\t\t\texclude: () => [sub.triggerRef],\n\t\t\tactive: live,\n\t\t});\n\n\t\tconst parentCloseAll = parentMenu.closeAll;\n\t\tconst closeAll = useCallback(\n\t\t\t(options?: MenuCloseOptions) => {\n\t\t\t\tparentCloseAll(options);\n\t\t\t},\n\t\t\t[parentCloseAll]\n\t\t);\n\n\t\tconst menuContext = useMemo<MenuContext>(\n\t\t\t() => ({\n\t\t\t\tfocus,\n\t\t\t\t// Forwarded, not re-decided: this level's own density is whatever\n\t\t\t\t// the level above it already resolved, all the way down. It has to\n\t\t\t\t// travel through context rather than plain CSS inheritance because\n\t\t\t\t// a portalled submenu is a DOM sibling of its parent panel, not a\n\t\t\t\t// descendant.\n\t\t\t\titemTextClass: parentMenu.itemTextClass,\n\t\t\t\t// This level's own liveness, not the root's raw state: a submenu\n\t\t\t\t// nested inside THIS one is no more alive than this one is.\n\t\t\t\trootOpen: live,\n\t\t\t\t// Copied from the parent level for the same reason as\n\t\t\t\t// `itemTextClass`: a submenu's own sound behaviour follows whatever\n\t\t\t\t// the root resolved, all the way down through nested submenus.\n\t\t\t\tsound: parentMenu.sound,\n\t\t\t\tcloseAll,\n\t\t\t\tregisterOpenSub,\n\t\t\t\tcloseSiblingSubs,\n\t\t\t}),\n\t\t\t[\n\t\t\t\tfocus,\n\t\t\t\tparentMenu.itemTextClass,\n\t\t\t\tparentMenu.sound,\n\t\t\t\tlive,\n\t\t\t\tcloseAll,\n\t\t\t\tregisterOpenSub,\n\t\t\t\tcloseSiblingSubs,\n\t\t\t]\n\t\t);\n\n\t\t// Divergence D-9, exactly as in `DropdownMenuContent`: no `tick()` wait\n\t\t// before moving to an edge, because items register in their own ref\n\t\t// callbacks, which land in the commit that creates them.\n\t\tconst mounted = presence.mounted;\n\t\tconst subOpen = sub.open;\n\t\tuseEffect(() => {\n\t\t\tif (!subOpen || !mounted) return;\n\t\t\tfocus.moveToEdge(\"first\");\n\t\t}, [subOpen, mounted, focus]);\n\n\t\tfunction handleKeydown(event: KeyboardEvent<HTMLDivElement>): void {\n\t\t\t// The same guard `DropdownMenuContent` carries, and here for the\n\t\t\t// same reason one level further down: a submenu nested inside this\n\t\t\t// one is portalled away but is still a React-tree descendant of\n\t\t\t// this element, so without it a single ArrowLeft would close two\n\t\t\t// levels at once and one arrow key would move two focus cores.\n\t\t\t//\n\t\t\t// A guard rather than `event.stopPropagation()`: React's synthetic\n\t\t\t// `stopPropagation` also stops the NATIVE event, which — because\n\t\t\t// React listens on the portal container — is only as far as\n\t\t\t// `document.body` when the handler runs. `dismissable` listens on\n\t\t\t// `document`, so stopping it there would silently cost this panel\n\t\t\t// its Escape and its outside-click dismissal.\n\t\t\tif (!event.currentTarget.contains(event.target as Node)) return;\n\t\t\tif (event.key === \"ArrowLeft\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tsub.closeSub(true);\n\t\t\t\treturn;\n\t\t\t}\n\t\t\thandleMenuContentKeydown(event, menuContext, {\n\t\t\t\t// Tab closes the *whole* tree, not just this level — the browser's\n\t\t\t\t// own Tab traversal should leave the entire menu system behind, the\n\t\t\t\t// same as it does from the root content, and resume from the root\n\t\t\t\t// trigger for the same reason it does there (both panels are\n\t\t\t\t// portalled to `document.body`). `closeAll` forwards to the root's\n\t\t\t\t// own `close`, so the default `returnFocus` lands on the trigger.\n\t\t\t\tonTab: () => parentMenu.closeAll(),\n\t\t\t});\n\t\t}\n\n\t\tfunction handleMouseEnter(): void {\n\t\t\tsub.keepOpen();\n\t\t}\n\n\t\tfunction handleMouseLeave(): void {\n\t\t\tsub.scheduleClose();\n\t\t}\n\n\t\t// Convention C-2: composed ABOVE the conditional below. ONE\n\t\t// bidirectional transition with `entering: live`, exactly as\n\t\t// `DropdownMenuContent` does and for the same reasons.\n\t\t//\n\t\t// The source spells this transition `|global` so that closing the ROOT\n\t\t// collects this panel's exit too, instead of letting it pop out of\n\t\t// existence at full opacity beside a parent already fading. React needs\n\t\t// no equivalent: `live` already folds the root's state in, so this\n\t\t// panel's own clock starts its exit in the very commit the root's does\n\t\t// and both levels fade together.\n\t\tconst panelRef = useComposedRefs(\n\t\t\tsetPanelNode,\n\t\t\tforwardedRef,\n\t\t\tpresence.register(anchored, (entering) => ({ side: sub.resolvedSide, entering }))\n\t\t);\n\n\t\t// No fixed font-size in the string below — `parentMenu.itemTextClass`\n\t\t// is spliced in instead, since this panel is portalled to\n\t\t// `document.body` independently of its own parent panel and can't\n\t\t// inherit that parent's size via plain CSS once both are open.\n\t\tconst classes = cn(\n\t\t\t\"ft-dropdown-menu-content flex w-max min-w-[160px] flex-col gap-[1px] rounded-[10px] border border-border bg-popover p-[5px] text-popover-foreground shadow-lg outline-none\",\n\t\t\tparentMenu.itemTextClass,\n\t\t\tclassName\n\t\t);\n\n\t\t// The `Portal` stays ABOVE the mounted gate for the same reason it does\n\t\t// in `DropdownMenuContent`: a `Portal` first mounting in the same commit\n\t\t// as the panel renders null on that pass, and the entrance would be\n\t\t// silently skipped.\n\t\treturn (\n\t\t\t<Portal>\n\t\t\t\t<MENU_KEY.Provider value={menuContext}>\n\t\t\t\t\t{presence.mounted ? (\n\t\t\t\t\t\t<div\n\t\t\t\t\t\t\tref={panelRef}\n\t\t\t\t\t\t\tid={sub.contentId}\n\t\t\t\t\t\t\trole=\"menu\"\n\t\t\t\t\t\t\taria-labelledby={sub.triggerId}\n\t\t\t\t\t\t\ttabIndex={-1}\n\t\t\t\t\t\t\tclassName={classes}\n\t\t\t\t\t\t\tdata-state={presence.surfaceState}\n\t\t\t\t\t\t\tdata-side={sub.resolvedSide}\n\t\t\t\t\t\t\tdata-align=\"start\"\n\t\t\t\t\t\t\tstyle={{ transformOrigin: originFor(sub.resolvedSide, sub.resolvedAlign) }}\n\t\t\t\t\t\t\tonKeyDown={handleKeydown}\n\t\t\t\t\t\t\tonMouseEnter={handleMouseEnter}\n\t\t\t\t\t\t\tonMouseLeave={handleMouseLeave}\n\t\t\t\t\t\t>\n\t\t\t\t\t\t\t{children}\n\t\t\t\t\t\t</div>\n\t\t\t\t\t) : null}\n\t\t\t\t</MENU_KEY.Provider>\n\t\t\t</Portal>\n\t\t);\n\t}\n);\n\nDropdownMenuSubContent.displayName = \"DropdownMenuSubContent\";\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuSubContent.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuSubTrigger.tsx","content":"\"use client\";\n\nimport { useCallback, useEffect, useRef } from \"react\";\nimport type { ComponentPropsWithoutRef, KeyboardEvent, MouseEvent, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils\";\nimport { useMenuItemRef } from \"../../internals/menu\";\nimport { useComposedRefs } from \"../../internals/dom/use-composed-refs\";\nimport { useMenuContext, useSubContext } from \"./types\";\n\ninterface DropdownMenuSubTriggerOwnProps {\n\t/** Disables the row: skipped by keyboard navigation and typeahead, inert to click/hover. */\n\tdisabled?: boolean;\n\t/** Leading icon. */\n\ticon?: ReactNode;\n\t/** The row's label. */\n\tchildren?: ReactNode;\n\t/** Additional CSS classes. */\n\tclassName?: string;\n}\n\n/**\n * Native `<button>` attributes and listeners are forwarded to the button; the managed\n * ARIA, state and structural attributes stay the component's.\n */\nexport interface DropdownMenuSubTriggerProps\n\textends\n\t\tOmit<ComponentPropsWithoutRef<\"button\">, keyof DropdownMenuSubTriggerOwnProps>,\n\t\tDropdownMenuSubTriggerOwnProps {}\n\n// Open-intent delay, mirroring `DropdownMenuSub`'s close-intent one: a pointer\n// merely passing over this row on its way somewhere else shouldn't pop the\n// submenu open.\nconst OPEN_INTENT_MS = 150;\n\n/**\n * The row that opens a submenu — itself a menu item at the *parent* level.\n *\n * No `forwardRef`: the source exposes no `ref` binding for this row.\n */\nexport function DropdownMenuSubTrigger({\n\tdisabled = false,\n\ticon,\n\tchildren,\n\tclassName,\n\tonClick,\n\tonMouseEnter,\n\tonMouseLeave,\n\tonKeyDown,\n\t...rest\n}: DropdownMenuSubTriggerProps) {\n\tconst parentMenu = useMenuContext();\n\tconst sub = useSubContext();\n\n\tconst itemRef = useRef<HTMLButtonElement | null>(null);\n\tconst openIntentTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n\n\t// This row takes part in the parent's arrow-key navigation and typeahead\n\t// exactly like a `DropdownMenuItem` does, on top of owning its own\n\t// submenu's open state. Its label span (below) is isolated from the icon\n\t// and the caret — both `aria-hidden` siblings — so the menu core's\n\t// typeahead fallback (visible text, skipping `aria-hidden` subtrees)\n\t// already matches this row correctly.\n\tconst registerRef = useMenuItemRef(parentMenu.focus);\n\t// The source's registration effect also publishes the element on the sub\n\t// context; both halves live in the ref callback here, so the release\n\t// happens before a replacement registers and React's own null call on\n\t// unmount clears the published element for free.\n\tconst { setTriggerRef } = sub;\n\tconst publishTrigger = useCallback(\n\t\t(node: HTMLButtonElement | null): void => {\n\t\t\tsetTriggerRef(node);\n\t\t},\n\t\t[setTriggerRef]\n\t);\n\tconst ref = useComposedRefs(itemRef, registerRef, publishTrigger);\n\n\tconst clearOpenIntent = useCallback((): void => {\n\t\tif (openIntentTimer.current !== null) {\n\t\t\tclearTimeout(openIntentTimer.current);\n\t\t\topenIntentTimer.current = null;\n\t\t}\n\t}, []);\n\n\t// Cancels a pending open-intent timer on unmount, not just on mouseleave —\n\t// a keyed list reordering can destroy this exact component while the\n\t// parent context and its siblings stay mounted, and a timer left running\n\t// past that point would call `sub.openSub()` against a `SubContext` this\n\t// component no longer owns a row in. Every downstream call along that path\n\t// happens to guard itself against a stale/detached element, so this was\n\t// never a crash — but there's no reason to leave a callback armed once the\n\t// row it belongs to is gone.\n\tuseEffect(() => clearOpenIntent, [clearOpenIntent]);\n\n\tfunction handleClick(event: MouseEvent<HTMLButtonElement>): void {\n\t\tif (disabled) return;\n\t\t// Same reasoning as `DropdownMenuItem`'s own click handler: hover\n\t\t// already syncs the parent menu's tracked focus position, but a click\n\t\t// reached without one first (a touch tap) wouldn't otherwise.\n\t\tif (itemRef.current) parentMenu.focus.focusItem(itemRef.current);\n\t\tsub.openSub();\n\t\tonClick?.(event);\n\t}\n\n\tfunction handleMouseEnter(event: MouseEvent<HTMLButtonElement>): void {\n\t\tif (disabled || !itemRef.current) return;\n\t\tsub.keepOpen();\n\t\tparentMenu.focus.focusItem(itemRef.current);\n\t\tclearOpenIntent();\n\t\topenIntentTimer.current = setTimeout(() => {\n\t\t\topenIntentTimer.current = null;\n\t\t\tsub.openSub();\n\t\t}, OPEN_INTENT_MS);\n\t\tonMouseEnter?.(event);\n\t}\n\n\tfunction handleMouseLeave(event: MouseEvent<HTMLButtonElement>): void {\n\t\tclearOpenIntent();\n\t\tsub.scheduleClose();\n\t\t// The internal cleanup above still runs while disabled (the row can turn\n\t\t// disabled while hovered); only the consumer listener is guarded.\n\t\tif (disabled) return;\n\t\tonMouseLeave?.(event);\n\t}\n\n\t// ArrowRight always means \"into the submenu\", regardless of which side it\n\t// actually rendered on after a flip. Only this row's own ArrowRight is\n\t// handled here; ArrowLeft belongs to `DropdownMenuSubContent`, on the\n\t// element it's actually about once focus has moved inside.\n\tfunction handleKeydown(event: KeyboardEvent<HTMLButtonElement>): void {\n\t\tif (disabled) return;\n\t\tif (event.key === \"ArrowRight\") {\n\t\t\tevent.preventDefault();\n\t\t\tsub.openSub();\n\t\t}\n\t\tonKeyDown?.(event);\n\t}\n\n\t// No font-size here — same reasoning as `DropdownMenuItem`'s own classes:\n\t// it inherits from whichever panel this row renders inside.\n\tconst classes = cn(\n\t\t\"ft-dropdown-menu-item flex w-full cursor-pointer items-center justify-between gap-[10px] rounded-[6px] px-[10px] py-[7px] text-left text-foreground outline-none\",\n\t\t\"hover:bg-accent hover:text-accent-foreground focus-visible:bg-accent focus-visible:text-accent-foreground\",\n\t\t\"disabled:pointer-events-none disabled:opacity-50\",\n\t\tclassName\n\t);\n\n\treturn (\n\t\t<button\n\t\t\t{...rest}\n\t\t\tref={ref}\n\t\t\tid={sub.triggerId}\n\t\t\ttype=\"button\"\n\t\t\trole=\"menuitem\"\n\t\t\ttabIndex={-1}\n\t\t\tdisabled={disabled}\n\t\t\taria-disabled={disabled ? \"true\" : undefined}\n\t\t\taria-haspopup=\"menu\"\n\t\t\taria-expanded={sub.open}\n\t\t\taria-controls={sub.open ? sub.contentId : undefined}\n\t\t\tclassName={classes}\n\t\t\tonClick={handleClick}\n\t\t\tonMouseEnter={handleMouseEnter}\n\t\t\tonMouseLeave={handleMouseLeave}\n\t\t\tonKeyDown={handleKeydown}\n\t\t>\n\t\t\t<span className=\"flex items-center gap-[10px]\">\n\t\t\t\t{icon ? (\n\t\t\t\t\t<span className=\"ft-dropdown-menu-item-icon\" aria-hidden=\"true\">\n\t\t\t\t\t\t{icon}\n\t\t\t\t\t</span>\n\t\t\t\t) : null}\n\t\t\t\t<span>{children}</span>\n\t\t\t</span>\n\t\t\t<span\n\t\t\t\taria-hidden=\"true\"\n\t\t\t\tclassName=\"ft-dropdown-menu-sub-caret text-muted-foreground text-[10px]\"\n\t\t\t>\n\t\t\t\t{sub.resolvedSide === \"left\" ? \"‹\" : \"›\"}\n\t\t\t</span>\n\t\t</button>\n\t);\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuSubTrigger.tsx"},{"path":"react/src/components/dropdown-menu/DropdownMenuTrigger.tsx","content":"\"use client\";\n\nimport { forwardRef, useEffect } from \"react\";\nimport type { ComponentPropsWithoutRef, KeyboardEvent, MouseEvent, ReactNode } from \"react\";\n\nimport { cn } from \"../../utils\";\nimport { useComposedRefs } from \"../../internals/dom/use-composed-refs\";\nimport { useElementRef } from \"../../internals/dom/use-element-ref\";\nimport { useDropdownMenuRoot } from \"./types\";\nimport \"./dropdown-menu-trigger.css\";\n\ninterface DropdownMenuTriggerOwnProps {\n\t/** Disables the trigger — the menu cannot be opened. */\n\tdisabled?: boolean;\n\t/** The trigger's content. */\n\tchildren?: ReactNode;\n\t/** Additional CSS classes, merged onto the trigger. */\n\tclassName?: string;\n}\n\n/**\n * Native `<button>` attributes and listeners are forwarded to the button; the managed\n * ARIA, state and structural attributes stay the component's.\n */\nexport interface DropdownMenuTriggerProps\n\textends\n\t\tOmit<ComponentPropsWithoutRef<\"button\">, keyof DropdownMenuTriggerOwnProps>,\n\t\tDropdownMenuTriggerOwnProps {}\n\n/**\n * The button that opens the menu.\n *\n * The source declares `ref = $bindable(null)`, so the button element arrives\n * through the ref channel rather than a prop.\n */\nexport const DropdownMenuTrigger = forwardRef<HTMLButtonElement, DropdownMenuTriggerProps>(\n\tfunction DropdownMenuTrigger(\n\t\t{ disabled = false, children, className, onClick, onKeyDown, ...rest },\n\t\tforwardedRef\n\t) {\n\t\t// `DropdownMenu` only ever mounts this alongside `DropdownMenuContent`\n\t\t// under its own context, so there is no standalone-usage fallback to\n\t\t// design for.\n\t\tconst ctx = useDropdownMenuRoot();\n\n\t\t// The NODE, not a ref (convention C-1): the publish effect below is\n\t\t// keyed on it, so it has to re-run the moment the element appears.\n\t\tconst [node, setNode] = useElementRef<HTMLButtonElement>();\n\t\tconst ref = useComposedRefs(setNode, forwardedRef);\n\n\t\t// Keyed on `setTriggerRef`, never on `ctx`: the context object is\n\t\t// rebuilt on every root render, and depending on it here would publish\n\t\t// null and then the node again on each one. `setTriggerRef` writes a\n\t\t// ref and is identity-stable for the life of the root.\n\t\tconst { setTriggerRef } = ctx;\n\t\tuseEffect(() => {\n\t\t\tsetTriggerRef(node);\n\t\t\treturn () => setTriggerRef(null);\n\t\t}, [setTriggerRef, node]);\n\n\t\tfunction handleClick(event: MouseEvent<HTMLButtonElement>): void {\n\t\t\tif (disabled) return;\n\t\t\tif (ctx.open) {\n\t\t\t\t// Focus is already here — it's the element that was just clicked —\n\t\t\t\t// so there is nothing for a forced `.focus()` to do.\n\t\t\t\tctx.close({ returnFocus: false });\n\t\t\t} else {\n\t\t\t\tctx.openWithFocus(\"first\");\n\t\t\t}\n\t\t\tonClick?.(event);\n\t\t}\n\n\t\tfunction handleKeydown(event: KeyboardEvent<HTMLButtonElement>): void {\n\t\t\tif (disabled) return;\n\t\t\tswitch (event.key) {\n\t\t\t\tcase \"Enter\":\n\t\t\t\tcase \" \":\n\t\t\t\tcase \"ArrowDown\":\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tctx.openWithFocus(\"first\");\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"ArrowUp\":\n\t\t\t\t\tevent.preventDefault();\n\t\t\t\t\tctx.openWithFocus(\"last\");\n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t\tonKeyDown?.(event);\n\t\t}\n\n\t\tconst classes = cn(\n\t\t\t\"ft-dropdown-menu-trigger border-border text-foreground hover:bg-accent hover:text-accent-foreground inline-flex cursor-pointer items-center gap-1.5 rounded-[8px] border px-[14px] py-[7px] text-[12px] font-medium transition-colors focus-visible:ring-[3px] focus-visible:ring-[var(--ft-nav-accent)]/35 focus-visible:outline-none disabled:pointer-events-none disabled:opacity-50\",\n\t\t\tclassName\n\t\t);\n\n\t\treturn (\n\t\t\t<button\n\t\t\t\t{...rest}\n\t\t\t\tref={ref}\n\t\t\t\tid={ctx.triggerId}\n\t\t\t\ttype=\"button\"\n\t\t\t\tdisabled={disabled}\n\t\t\t\tclassName={classes}\n\t\t\t\taria-haspopup=\"menu\"\n\t\t\t\taria-expanded={ctx.open}\n\t\t\t\taria-controls={ctx.open ? ctx.contentId : undefined}\n\t\t\t\tonClick={handleClick}\n\t\t\t\tonKeyDown={handleKeydown}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</button>\n\t\t);\n\t}\n);\n\nDropdownMenuTrigger.displayName = \"DropdownMenuTrigger\";\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/DropdownMenuTrigger.tsx"},{"path":"react/src/components/dropdown-menu/dropdown-menu-trigger.css","content":"/*\n * Colocated port of `DropdownMenuTrigger`'s `<style>` block. Anchored on\n * `.ft-dropdown-menu-trigger`, which is already the first token of the\n * trigger's own class string, so nothing was added to that literal.\n *\n * The custom property keeps its local fallback: the component must not depend\n * on an app-level token existing.\n */\n.ft-dropdown-menu-trigger {\n\t--ft-nav-accent: var(\n\t\t--ft-accent,\n\t\tlight-dark(oklch(0.5432 0.2528 300.22), oklch(0.604 0.2606 301.75))\n\t);\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/dropdown-menu-trigger.css"},{"path":"react/src/components/dropdown-menu/index.ts","content":"\"use client\";\n\nexport { DropdownMenu } from \"./DropdownMenu\";\nexport type { DropdownMenuProps } from \"./DropdownMenu\";\nexport { DropdownMenuTrigger } from \"./DropdownMenuTrigger\";\nexport type { DropdownMenuTriggerProps } from \"./DropdownMenuTrigger\";\nexport { DropdownMenuContent } from \"./DropdownMenuContent\";\nexport type { DropdownMenuContentProps } from \"./DropdownMenuContent\";\nexport { DropdownMenuItem } from \"./DropdownMenuItem\";\nexport type { DropdownMenuItemProps } from \"./DropdownMenuItem\";\nexport { DropdownMenuSeparator } from \"./DropdownMenuSeparator\";\nexport type { DropdownMenuSeparatorProps } from \"./DropdownMenuSeparator\";\nexport { DropdownMenuLabel } from \"./DropdownMenuLabel\";\nexport type { DropdownMenuLabelProps } from \"./DropdownMenuLabel\";\nexport { DropdownMenuSub } from \"./DropdownMenuSub\";\nexport type { DropdownMenuSubProps } from \"./DropdownMenuSub\";\nexport { DropdownMenuSubTrigger } from \"./DropdownMenuSubTrigger\";\nexport type { DropdownMenuSubTriggerProps } from \"./DropdownMenuSubTrigger\";\nexport { DropdownMenuSubContent } from \"./DropdownMenuSubContent\";\nexport type { DropdownMenuSubContentProps } from \"./DropdownMenuSubContent\";\n\n// The three context keys, kept because the source's own `index.ts` exports\n// them (as `unique symbol`s there, as the React context objects here) — the\n// public escape hatch for a consumer composing their own menu leaf.\nexport { MENU_KEY, SUB_KEY, DROPDOWN_MENU_KEY } from \"./types\";\nexport type {\n\tMenuContext,\n\tMenuCloseOptions,\n\tSubContext,\n\tDropdownMenuRootContext,\n} from \"./types\";\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/index.ts"},{"path":"react/src/components/dropdown-menu/menu-shared.ts","content":"\"use client\";\n\n// Behaviour shared by DropdownMenuContent and ContextMenuContent (and by\n// every DropdownMenuSubContent nested inside either), so it exists once\n// instead of twice. Lives here rather than in the frozen internals\n// directory for this wave, because it is specific to these two component\n// families, not a general-purpose primitive every floating surface needs.\n// Each package's own dropdown-menu README covers this file in more detail.\n\nimport type { MenuContext } from \"./types\";\n\nexport interface MenuContentKeydownOptions {\n\t/** Called on Tab. Never calls `preventDefault` itself — the browser's own Tab traversal continues from whatever the menu core left focused. */\n\tonTab?: () => void;\n}\n\n/**\n * Wires ArrowUp/Down, Home/End and single-character typeahead to a level's\n * `MenuFocus` core, and Tab to `options.onTab`. Identical semantics whether\n * the panel is a `DropdownMenuContent`, a `ContextMenuContent`, or either\n * one's nested `*SubContent` — the keys navigate whatever level currently\n * holds real DOM focus, regardless of how that level's panel was opened or\n * positioned.\n *\n * ArrowRight/ArrowLeft are deliberately not handled here: their key strings\n * are more than one character, so the typeahead fallback below already\n * ignores them, and `*SubTrigger`/`*SubContent` each own their half of that\n * pair directly on the element the key is actually about.\n *\n * The parameter is typed structurally (the handful of members this function\n * actually reads) rather than as the concrete DOM `KeyboardEvent`, so a\n * caller can pass any event shape that satisfies it — including a\n * framework's own synthetic event — with no unwrap or cast.\n */\nexport function handleMenuContentKeydown(\n\tevent: Pick<KeyboardEvent, \"key\" | \"ctrlKey\" | \"metaKey\" | \"altKey\"> & {\n\t\tpreventDefault(): void;\n\t},\n\tctx: MenuContext,\n\toptions: MenuContentKeydownOptions = {}\n): void {\n\tswitch (event.key) {\n\t\tcase \"ArrowDown\":\n\t\t\tevent.preventDefault();\n\t\t\tctx.focus.move(1);\n\t\t\treturn;\n\t\tcase \"ArrowUp\":\n\t\t\tevent.preventDefault();\n\t\t\tctx.focus.move(-1);\n\t\t\treturn;\n\t\tcase \"Home\":\n\t\t\tevent.preventDefault();\n\t\t\tctx.focus.moveToEdge(\"first\");\n\t\t\treturn;\n\t\tcase \"End\":\n\t\t\tevent.preventDefault();\n\t\t\tctx.focus.moveToEdge(\"last\");\n\t\t\treturn;\n\t\tcase \"Tab\":\n\t\t\toptions.onTab?.();\n\t\t\treturn;\n\t\tdefault:\n\t\t\tif (event.key.length === 1 && !event.ctrlKey && !event.metaKey && !event.altKey) {\n\t\t\t\tctx.focus.typeahead(event.key);\n\t\t\t}\n\t}\n}\n\n/**\n * One level's registry of currently-open submenus, keyed by each submenu's\n * own trigger element. A `*Sub` calls `closeSiblingSubs` right before\n * opening itself, so only one submenu is ever open per level — the same\n * exclusivity a native menu bar gives you for free. Each `*Content`/\n * `*SubContent` owns one of these for its own direct children; it is never\n * shared across levels, which is what keeps a deeply nested submenu from\n * closing an unrelated one two levels up.\n *\n * Allocation-only: it installs no listener and starts no timer, so building\n * one is safe to do exactly once per component instance.\n */\nexport function createOpenSubRegistry(): {\n\tregisterOpenSub(triggerEl: HTMLElement, close: () => void): () => void;\n\tcloseSiblingSubs(exceptTriggerEl: HTMLElement): void;\n} {\n\tconst openSubs = new Map<HTMLElement, () => void>();\n\n\treturn {\n\t\tregisterOpenSub(triggerEl, close) {\n\t\t\topenSubs.set(triggerEl, close);\n\t\t\treturn () => {\n\t\t\t\tif (openSubs.get(triggerEl) === close) openSubs.delete(triggerEl);\n\t\t\t};\n\t\t},\n\t\tcloseSiblingSubs(exceptTriggerEl) {\n\t\t\tfor (const [triggerEl, close] of openSubs) {\n\t\t\t\tif (triggerEl !== exceptTriggerEl) close();\n\t\t\t}\n\t\t},\n\t};\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/menu-shared.ts"},{"path":"react/src/components/dropdown-menu/types.ts","content":"\"use client\";\n\n/**\n * The three contracts this family publishes, and the React contexts that\n * carry them.\n *\n * The Svelte source publishes each one under a `unique symbol` context key;\n * React's own context object plays that role here, so the exported names are\n * kept and the values are `React.Context` objects rather than symbols — the\n * same substitution `ToggleGroup` makes for `TOGGLE_GROUP_KEY`:\n *\n * ```tsx\n * const menu = useContext(MENU_KEY);\n * ```\n */\n\nimport { createContext, useContext } from \"react\";\nimport type { Context } from \"react\";\nimport type { Side, Align } from \"../../internals/anchor-position\";\nimport type { MenuFocusState } from \"../../internals/menu\";\n\n/**\n * Reads a context this family guarantees is present.\n *\n * Every consumer below is only ever mounted by one of this folder's own\n * components, so there is no standalone-usage fallback to design for — the\n * same assumption each source sub-component makes about its own root. Not\n * exported from `index.ts`: a local convenience, not public surface.\n */\nfunction useRequiredContext<T>(context: Context<T | undefined>, name: string): T {\n\tconst value = useContext(context);\n\tif (value === undefined) {\n\t\tthrow new Error(`${name} is missing: this component must be rendered inside its provider.`);\n\t}\n\treturn value;\n}\n\n/**\n * Options accepted by a menu's own `close`/`closeAll`, shared across every\n * level (root, item, sub) so one call site's options object works\n * everywhere it's forwarded to.\n */\nexport interface MenuCloseOptions {\n\t/** Whether closing returns DOM focus to the trigger. Defaults to `true` wherever it's read. */\n\treturnFocus?: boolean;\n\t/**\n\t * Suppresses the `close` sound cue for this particular close call —\n\t * used when the caller is about to play its own cue instead (an item's\n\t * `select`), so exactly one cue fires per interaction, never both.\n\t * Has no effect when the root's own `sound` prop is off.\n\t */\n\tsilent?: boolean;\n}\n\n/**\n * Shared by a menu family's content panels for their item-level children —\n * `*Item`, `*Separator`, `*Label`, `*Sub`, `*SubTrigger`, `*SubContent`. Two\n * families behave identically once a panel is open — same menu-focus wiring,\n * same submenu intent-delay behaviour — and only how the panel itself opens\n * and where it anchors differs.\n *\n * Both a top-level `*Content` and a nested `*SubContent` provide one of\n * these under `MENU_KEY` — a `*SubContent` shadows its parent's for its own\n * subtree, so `*Item`/`*Separator`/`*Label` never need to know which level\n * they are at.\n */\nexport interface MenuContext {\n\t/** The menu-focus core for this level's own items — not a nested submenu's, which has its own. */\n\treadonly focus: MenuFocusState;\n\t/**\n\t * The Tailwind font-size class items at this level should render at —\n\t * `\"text-[13px]\"` under `DropdownMenu`. `*Item`/`*SubTrigger` set no\n\t * font-size of their own and simply inherit it via normal CSS from\n\t * whichever panel renders them — this field only exists for `*SubContent`\n\t * to read and pass through. A `*SubContent` is portalled to\n\t * `document.body` independently of its parent panel (also portalled\n\t * there), so the two end up as DOM *siblings* once open, not\n\t * ancestor/descendant — CSS inheritance from the root panel to a nested\n\t * submenu's own items doesn't reach across that gap the way it does from\n\t * a panel straight to its own direct items. React context isn't\n\t * DOM-based, though: it follows the *component* tree, which portalling a\n\t * node doesn't change, so this field crosses the same gap CSS can't.\n\t */\n\treadonly itemTextClass: string;\n\t/**\n\t * Whether this menu family plays sound cues — forwarded from the root's\n\t * own `sound` prop. Optional so a family that builds its own\n\t * `MenuContext` without this field keeps compiling unchanged; reads as\n\t * falsy there, which is the correct \"no sound\" behaviour.\n\t */\n\treadonly sound?: boolean;\n\t/**\n\t * Whether the menu TREE this level belongs to is still open — not just\n\t * this level's own mount. Closing the root flips only the root's state\n\t * and tears every nested level down with it, so a submenu's own\n\t * `sub.open` stays true for the whole of that outro. Anything asking \"is\n\t * this panel a live top layer?\" — an exit transition picking its curve, a\n\t * dismissable deciding whether an Escape is its to swallow — has to read\n\t * this instead. A `*SubContent` republishes it as its own liveness, so\n\t * the answer composes down a chain of nested submenus.\n\t */\n\treadonly rootOpen: boolean;\n\t/** Closes the whole menu, root included. What selecting an item and pressing Tab both do. */\n\tcloseAll(options?: MenuCloseOptions): void;\n\t/** Registers a currently-open submenu at this level, keyed by its trigger element. Returns an unregister function. */\n\tregisterOpenSub(triggerEl: HTMLElement, close: () => void): () => void;\n\t/** Closes every open submenu at this level except the one whose trigger is `exceptTriggerEl` — only one submenu open per level, like a native menu bar. */\n\tcloseSiblingSubs(exceptTriggerEl: HTMLElement): void;\n}\n\nexport const MENU_KEY = createContext<MenuContext | undefined>(undefined);\nMENU_KEY.displayName = \"MenuContext\";\n\n/** Reads the enclosing level's `MenuContext`. Internal. */\nexport function useMenuContext(): MenuContext {\n\treturn useRequiredContext(MENU_KEY, \"MenuContext\");\n}\n\n/**\n * The contract between a `*Sub` boundary and its own `*SubTrigger` and\n * `*SubContent` — distinct from `MenuContext`, which is about a level's\n * *items*, not the one boundary component coordinating a single submenu's\n * open state and hover-intent timers.\n */\nexport interface SubContext {\n\treadonly open: boolean;\n\treadonly contentId: string;\n\t/** The sub-trigger's own id — read by `*SubContent` for `aria-labelledby`, so the submenu panel announces the row that opened it. */\n\treadonly triggerId: string;\n\treadonly triggerRef: HTMLElement | null;\n\t/**\n\t * The side the submenu actually rendered on, as last reported by\n\t * `useAnchorPosition`'s `onPlacement` — `\"right\"` until a flip moves it\n\t * to `\"left\"`. `SubTrigger` reads this to mirror its caret;\n\t * ArrowRight/Left keep their fixed meaning (\"into the submenu\" / \"back to\n\t * the trigger\") regardless of which side that visually is.\n\t */\n\treadonly resolvedSide: Side;\n\t/**\n\t * The cross-axis alignment the submenu actually rendered with, as last\n\t * reported by `onPlacement`. `\"start\"` until a clamp near a viewport edge\n\t * slides the panel along that axis, after which the requested corner is\n\t * no longer the one touching the trigger. `SubContent` reads this for its\n\t * entrance origin, so the panel grows from the corner nearest the trigger\n\t * rather than from the far one.\n\t */\n\treadonly resolvedAlign: Align;\n\tsetTriggerRef(el: HTMLElement | null): void;\n\tsetPlacement(side: Side, align: Align): void;\n\t/** Opens the submenu. Idempotent — does nothing if already open. */\n\topenSub(): void;\n\t/**\n\t * Closes the submenu, optionally returning DOM focus to its trigger.\n\t * `silent` suppresses the submenu's `close` cue (parent-driven closes).\n\t */\n\tcloseSub(returnFocus: boolean, silent?: boolean): void;\n\t/** Cancels a pending close-intent timer. Called when the pointer enters the trigger or the content. */\n\tkeepOpen(): void;\n\t/** Starts the close-intent timer. Called when the pointer leaves the trigger or the content. */\n\tscheduleClose(): void;\n}\n\nexport const SUB_KEY = createContext<SubContext | undefined>(undefined);\nSUB_KEY.displayName = \"MenuSubContext\";\n\n/** Reads the enclosing `DropdownMenuSub`'s context. Internal. */\nexport function useSubContext(): SubContext {\n\treturn useRequiredContext(SUB_KEY, \"MenuSubContext\");\n}\n\n/** The contract between `DropdownMenu` and its own `DropdownMenuTrigger`/`DropdownMenuContent`. */\nexport interface DropdownMenuRootContext {\n\treadonly contentId: string;\n\treadonly triggerId: string;\n\treadonly side: Side;\n\treadonly align: Align;\n\treadonly offset: number;\n\treadonly loop: boolean;\n\treadonly open: boolean;\n\t/** Which end to focus once the content mounts — set by whichever key opened the trigger. */\n\treadonly focusEdge: \"first\" | \"last\";\n\treadonly triggerRef: HTMLElement | null;\n\t/** Whether this menu plays sound cues — mirrors `DropdownMenuProps.sound`. */\n\treadonly sound: boolean;\n\tsetTriggerRef(el: HTMLElement | null): void;\n\t/** Opens the menu (if not already open) and requests that its content focus `edge` once mounted. */\n\topenWithFocus(edge: \"first\" | \"last\"): void;\n\t/** Closes the menu. Returns focus to the trigger by default. */\n\tclose(options?: MenuCloseOptions): void;\n}\n\nexport const DROPDOWN_MENU_KEY = createContext<DropdownMenuRootContext | undefined>(undefined);\nDROPDOWN_MENU_KEY.displayName = \"DropdownMenuRootContext\";\n\n/** Reads the enclosing `DropdownMenu`'s context. Internal. */\nexport function useDropdownMenuRoot(): DropdownMenuRootContext {\n\treturn useRequiredContext(DROPDOWN_MENU_KEY, \"DropdownMenuRootContext\");\n}\n","type":"registry:ui","target":"@ui/fancy/components/dropdown-menu/types.ts"}]}