{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "dependencies": [],
  "description": "Base-UI-shaped APG menu button on a lean native manual-Popover and CSS-anchor shell. Controlled state is authoritative and cancellable. Open-only owner-document listeners provide composed light dismiss across native or custom Triggers: pointer down and up must both be outside, focus exit is reasoned independently, and Escape is owned by the topmost applicable menu. A Root can register multiple in-tree Triggers, tracks one active trigger through defaultTriggerId/triggerId, exposes open state only on that trigger, and anchors its single Popup to the active trigger. Root disabled state blocks open-state requests and cascades through triggers, items, checked-item groups, and submenus. Registered submenu branches close accepted same-level siblings with the Base-shaped sibling-open reason, propagate accepted parent closure through open descendants, and request structural closure when their only SubTrigger unmounts. The menu supports focusable disabled items, reset-on-close locale-aware typeahead, exact Tab exit, configurable focus looping and pointer highlighting, direction-aware nested submenus, semantic links/groups/separators, checkbox and radio items, physical side placement, and viewport-contained popup geometry without a positioning dependency.",
  "files": [
    {
      "content": "\"use client\";\n\n/**\n * heidi-ui Menu — a Base-shaped APG menu button on the browser's native\n * Popover top layer. CSS anchors own placement and collision fallback; this\n * module owns authoritative state, composed light dismiss, focus,\n * keyboard/typeahead, selection, checked items, and submenu intent.\n *\n * Manual native popovers deliberately replace Base UI's Portal/Positioner\n * wrappers while allowing every custom Trigger to share one dismiss zone. The\n * result stays dependency-free while controlled state, light dismiss, lazy\n * presence, and nested menus remain one coherent contract.\n */\n\nimport {\n  type ComponentPropsWithoutRef,\n  type CSSProperties,\n  type KeyboardEvent,\n  type MouseEvent,\n  type PointerEvent,\n  type ReactNode,\n  type Ref,\n  type SyntheticEvent,\n  type ToggleEvent,\n  useCallback,\n  useContext,\n  useEffect,\n  useId,\n  useMemo,\n  useRef,\n  useState\n} from \"react\";\nimport { ariaDisabledAttrs, nativeDisabledAttrs } from \"../_internal/disabled\";\nimport { synchronizeNativePopoverOpen } from \"../_internal/native-popover-sync\";\nimport { finiteDelay } from \"../_internal/range\";\nimport { focusHeidiElementNextFrame } from \"../_internal/focus-scope\";\nimport { closeDescendantSubmenus } from \"../_internal/menu-items\";\nimport {\n  createItemChangeDetails,\n  createRootChangeDetails,\n  type MenuItemChangeEventDetails,\n  type MenuRootChangeEventDetails,\n  type MenuRootChangeEventReason\n} from \"../_internal/menu-change-details\";\nimport {\n  MenuCheckboxItemContext,\n  MenuContext,\n  MenuDismissLayerContext,\n  MenuGroupLabelContext,\n  MenuOpenContext,\n  MenuRadioGroupContext,\n  MenuRadioItemContext,\n  MenuSubContext,\n  MenuSubOpenContext,\n  type MenuContextValue,\n  type MenuSubContextValue,\n  type RegisteredMenuSubmenu,\n  useMenuContext,\n  useMenuOpen,\n  useMenuSubContext\n} from \"../_internal/menu-context\";\nimport {\n  checkedStateAttributes,\n  dataState,\n  DISABLED_MENU_PRESS_HANDLERS,\n  dispatchMouseGestureClick,\n  firstRegisteredTrigger,\n  type MenuTriggerHoverSession,\n  type NativeHostProps,\n  openStateAttributes,\n  type RegisteredMenuTrigger,\n  showPopoverFrom\n} from \"../_internal/menu-host-state\";\nimport {\n  extendActiveTypeaheadWithSpace,\n  type FocusTarget,\n  initialMenuItem,\n  moveMenuFocus,\n  resetTypeahead,\n  runTypeahead,\n  tabTargetAfterTrigger,\n  type TypeaheadState\n} from \"../_internal/menu-keyboard-navigation\";\nimport {\n  focusMovedIntoNestedLayer,\n  menuOwnsKeyboardTarget,\n  useMenuManualDismiss\n} from \"../_internal/menu-manual-dismiss\";\nimport {\n  completeAfterPopoverAnimations,\n  usePopoverPresence\n} from \"../_internal/menu-popover-presence\";\nimport { clampMenuToVisualViewport, useMenuViewportClamp } from \"../_internal/menu-viewport-clamp\";\nimport {\n  composeHeidiEventHandlers,\n  mergeHeidiRefs,\n  renderHeidiElement,\n  type HeidiIntrinsicHostProps\n} from \"../_internal/render-element\";\nimport { pointInTriangle, pointerBridgeEdge } from \"../_internal/safe-triangle\";\n// Aliased: `safeId` is an established local variable name in Root/SubRoot.\nimport { safeId as toSafeId } from \"../_internal/safe-id\";\nimport { useHeidiLayoutEffect } from \"../_internal/use-layout-effect\";\nimport { type MenuAlign, type MenuSide } from \"./menu.anatomy.generated\";\nimport { MENU_CLASSES } from \"./menu.classes.generated\";\n\nexport type { MenuAlign, MenuSide };\nexport type {\n  MenuItemChangeEventDetails,\n  MenuRootChangeEventDetails,\n  MenuRootChangeEventReason\n};\n\ntype MenuPhysicalSide = Exclude<MenuSide, \"inline-end\" | \"inline-start\">;\n\nfunction resolvePhysicalSide(\n  side: MenuSide,\n  direction: \"ltr\" | \"rtl\"\n): MenuPhysicalSide {\n  if (side === \"inline-start\") {\n    return direction === \"rtl\" ? \"right\" : \"left\";\n  }\n  if (side === \"inline-end\") {\n    return direction === \"rtl\" ? \"left\" : \"right\";\n  }\n  return side;\n}\n\nfunction usePhysicalSide(\n  side: MenuSide,\n  elementRef: { current: HTMLElement | null },\n  open: boolean\n): MenuPhysicalSide {\n  const [physicalSide, setPhysicalSide] = useState<MenuPhysicalSide>(() =>\n    resolvePhysicalSide(side, \"ltr\")\n  );\n  useHeidiLayoutEffect(() => {\n    const element = elementRef.current;\n    const direction =\n      element && getComputedStyle(element).direction === \"rtl\" ? \"rtl\" : \"ltr\";\n    setPhysicalSide(resolvePhysicalSide(side, direction));\n  }, [elementRef, open, side]);\n  return physicalSide;\n}\n\nexport type MenuRootProps = {\n  children?: ReactNode;\n  defaultOpen?: boolean;\n  /** Initial active in-tree Trigger id when more than one Trigger is rendered. */\n  defaultTriggerId?: string | null;\n  disabled?: boolean;\n  /** Focus the pointed item while a mouse moves over it. */\n  highlightItemOnHover?: boolean;\n  /** Wrap ArrowUp/ArrowDown at the menu boundaries. */\n  loopFocus?: boolean;\n  onOpenChange?: (open: boolean, details: MenuRootChangeEventDetails) => void;\n  onOpenChangeComplete?: (open: boolean) => void;\n  open?: boolean;\n  /** Legacy Root-wide fallback; SubTrigger.closeDelay takes precedence. */\n  submenuCloseDelay?: number;\n  /** Legacy Root-wide fallback; SubTrigger.delay takes precedence. */\n  submenuOpenDelay?: number;\n  /** Active in-tree Trigger id. Control it alongside `open` for trigger switching. */\n  triggerId?: string | null;\n};\n\nexport function MenuRoot({\n  children,\n  defaultOpen = false,\n  defaultTriggerId = null,\n  disabled = false,\n  highlightItemOnHover = true,\n  loopFocus = true,\n  onOpenChange,\n  onOpenChangeComplete,\n  open: openProp,\n  submenuCloseDelay = 0,\n  submenuOpenDelay = 100,\n  triggerId: triggerIdProp\n}: MenuRootProps) {\n  const safeId = toSafeId(useId());\n  const contentId = `hui-menu-${safeId}`;\n  const [internalOpen, setInternalOpen] = useState(defaultOpen);\n  const [internalTriggerId, setInternalTriggerId] = useState<string | null>(\n    defaultTriggerId\n  );\n  const controlled = openProp !== undefined;\n  const triggerControlled = triggerIdProp !== undefined;\n  const open = openProp ?? internalOpen;\n  const activeTriggerId = triggerControlled\n    ? (triggerIdProp ?? null)\n    : internalTriggerId;\n  const openRef = useRef(open);\n  openRef.current = open;\n  const pendingAcceptedOpenRef = useRef<boolean | null>(null);\n  const pendingRenderedCloseRef = useRef(0);\n  const previousRenderedOpenRef = useRef(open);\n  const activeTriggerIdRef = useRef<string | null>(activeTriggerId);\n  activeTriggerIdRef.current = activeTriggerId;\n  const triggerElementsRef = useRef(new Map<string, RegisteredMenuTrigger>());\n  const submenuRegistryRef = useRef(new Map<string, RegisteredMenuSubmenu>());\n  const mountedRef = useRef(true);\n  const [, setTriggerRegistryVersion] = useState(0);\n  const triggerRef = useRef<HTMLElement | null>(null);\n  const contentRef = useRef<HTMLDivElement | null>(null);\n  const focusTargetRef = useRef<FocusTarget>(\"first\");\n  const focusReturnTargetRef = useRef<HTMLElement | null>(null);\n  const restoreFocusOnCloseRef = useRef(false);\n  const completedStateRef = useRef<boolean | null>(null);\n  const mouseUpSelectionAllowedRef = useRef(false);\n  const submenuPointerGraceRef = useRef(new Set<string>());\n  const triggerHoverOpenTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const triggerHoverPendingRef = useRef<HTMLElement | null>(null);\n  const triggerHoverCloseTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const triggerHoverGraceCleanupRef = useRef<(() => void) | null>(null);\n  const triggerHoverSessionRef = useRef<MenuTriggerHoverSession | null>(null);\n  const lastOpenReasonRef = useRef<MenuRootChangeEventReason | null>(null);\n  const closeForMissingTriggerRef = useRef<() => void>(() => undefined);\n\n  const getOpen = useCallback(() => openRef.current, []);\n  const setContentElement = useCallback((element: HTMLDivElement | null) => {\n    contentRef.current = element;\n  }, []);\n  const getOwnerDocument = useCallback(\n    () =>\n      contentRef.current?.ownerDocument ??\n      triggerRef.current?.ownerDocument ??\n      null,\n    []\n  );\n  const rememberFocusReturnTarget = useCallback(\n    (preferred: HTMLElement | null = null) => {\n      const ownerDocument = preferred?.ownerDocument ?? getOwnerDocument();\n      const activeElement = ownerDocument?.activeElement;\n      const activeTarget =\n        activeElement instanceof HTMLElement &&\n        activeElement !== ownerDocument?.body &&\n        !contentRef.current?.contains(activeElement)\n          ? activeElement\n          : null;\n      const target = preferred ?? activeTarget ?? triggerRef.current;\n      focusReturnTargetRef.current = target?.isConnected ? target : null;\n    },\n    [getOwnerDocument]\n  );\n  const isWithinDismissZone = useCallback((target: EventTarget | null) => {\n    if (!(target instanceof Node)) {\n      return false;\n    }\n    if (contentRef.current?.contains(target)) {\n      return true;\n    }\n    return [...triggerElementsRef.current.values()].some((trigger) =>\n      trigger.element.contains(target)\n    );\n  }, []);\n  const activateTrigger = useCallback(\n    (id: string, element: HTMLElement) => {\n      const registration = triggerElementsRef.current.get(id);\n      if (registration) {\n        registration.element = element;\n      }\n      if (triggerControlled) {\n        return;\n      }\n      activeTriggerIdRef.current = id;\n      triggerRef.current = element;\n      setInternalTriggerId(id);\n    },\n    [triggerControlled]\n  );\n  const registerTrigger = useCallback(\n    (id: string, anchorName: string, element: HTMLElement | null) => {\n      if (element) {\n        triggerElementsRef.current.set(id, { anchorName, element });\n        if (activeTriggerIdRef.current === id) {\n          triggerRef.current = element;\n          setTriggerRegistryVersion((version) => version + 1);\n        } else if (!triggerControlled && activeTriggerIdRef.current === null) {\n          activeTriggerIdRef.current = id;\n          triggerRef.current = element;\n          setInternalTriggerId(id);\n        }\n        return;\n      }\n\n      const removedTrigger = triggerElementsRef.current.get(id)?.element;\n      if (triggerHoverPendingRef.current === removedTrigger) {\n        queueMicrotask(() => {\n          if (\n            triggerElementsRef.current.get(id)?.element === removedTrigger ||\n            triggerHoverPendingRef.current !== removedTrigger\n          ) {\n            return;\n          }\n          if (triggerHoverOpenTimerRef.current !== null) {\n            clearTimeout(triggerHoverOpenTimerRef.current);\n            triggerHoverOpenTimerRef.current = null;\n          }\n          triggerHoverPendingRef.current = null;\n        });\n      }\n      triggerElementsRef.current.delete(id);\n      if (activeTriggerIdRef.current !== id) {\n        return;\n      }\n      triggerRef.current = null;\n      // React ref cleanup can transiently unregister a host that is replaced or\n      // receives a new callback ref in the same commit. Defer fallback so a\n      // same-id registration retains active ownership and anchor identity.\n      queueMicrotask(() => {\n        if (!mountedRef.current || activeTriggerIdRef.current !== id) {\n          return;\n        }\n        const replacement = triggerElementsRef.current.get(id);\n        if (replacement) {\n          triggerRef.current = replacement.element;\n          setTriggerRegistryVersion((version) => version + 1);\n          return;\n        }\n        if (triggerControlled) {\n          setTriggerRegistryVersion((version) => version + 1);\n          return;\n        }\n        const next = firstRegisteredTrigger(triggerElementsRef.current);\n        activeTriggerIdRef.current = next?.[0] ?? null;\n        triggerRef.current = next?.[1].element ?? null;\n        setInternalTriggerId(next?.[0] ?? null);\n        if (!next && openRef.current) {\n          closeForMissingTriggerRef.current();\n        }\n      });\n    },\n    [triggerControlled]\n  );\n  const registerSubmenu = useCallback(\n    (id: string, submenu: RegisteredMenuSubmenu | null) => {\n      if (submenu) {\n        submenuRegistryRef.current.set(id, submenu);\n      } else {\n        submenuRegistryRef.current.delete(id);\n      }\n    },\n    []\n  );\n  const closeMenuBranches = useCallback(\n    (\n      parentMenu: HTMLElement,\n      exceptId: string | null,\n      reason: MenuRootChangeEventReason,\n      event: Event,\n      trigger?: Element\n    ) => {\n      for (const [id, submenu] of submenuRegistryRef.current) {\n        if (\n          id === exceptId ||\n          !submenu.getOpen() ||\n          submenu.triggerRef.current?.closest('[role=\"menu\"]') !== parentMenu\n        ) {\n          continue;\n        }\n        submenu.requestClose(reason, event, trigger);\n      }\n    },\n    []\n  );\n  const scheduleSubmenuItemHoverClose = useCallback(\n    (\n      parentMenu: HTMLElement,\n      event: globalThis.PointerEvent,\n      source: HTMLElement\n    ) => {\n      for (const submenu of submenuRegistryRef.current.values()) {\n        if (\n          submenu.getOpen() &&\n          submenu.triggerRef.current?.closest('[role=\"menu\"]') === parentMenu\n        ) {\n          submenu.schedulePointerClose(event, source, \"sibling-open\");\n        }\n      }\n    },\n    []\n  );\n  const isSubmenuPointerGraceActive = useCallback(\n    () => submenuPointerGraceRef.current.size > 0,\n    []\n  );\n  const setSubmenuPointerGrace = useCallback((id: string, active: boolean) => {\n    if (active) {\n      submenuPointerGraceRef.current.add(id);\n    } else {\n      submenuPointerGraceRef.current.delete(id);\n    }\n  }, []);\n  const takeFocusTarget = useCallback(() => {\n    const target = focusTargetRef.current;\n    focusTargetRef.current = \"first\";\n    return target;\n  }, []);\n\n  useHeidiLayoutEffect(() => {\n    triggerRef.current = activeTriggerId\n      ? (triggerElementsRef.current.get(activeTriggerId)?.element ?? null)\n      : null;\n  }, [activeTriggerId]);\n\n  const requestOpen = useCallback(\n    (\n      next: boolean,\n      reason: MenuRootChangeEventReason,\n      event: Event,\n      trigger?: Element,\n      focusTarget: FocusTarget = \"first\"\n    ) => {\n      const triggerElement = trigger instanceof HTMLElement ? trigger : null;\n      const requestedTriggerId = triggerElement?.id ?? null;\n      const switchingTrigger =\n        next &&\n        openRef.current &&\n        requestedTriggerId !== null &&\n        requestedTriggerId !== activeTriggerIdRef.current;\n      if (disabled) {\n        return null;\n      }\n      const effectiveOpen = pendingAcceptedOpenRef.current ?? openRef.current;\n      if (next === effectiveOpen && !switchingTrigger) {\n        if (next && focusTarget !== \"none\") {\n          focusTargetRef.current = focusTarget;\n          requestAnimationFrame(() => {\n            if (\n              !openRef.current ||\n              (requestedTriggerId !== null &&\n                activeTriggerIdRef.current !== requestedTriggerId)\n            ) {\n              return;\n            }\n            const content = contentRef.current;\n            if (!content?.matches(\":popover-open\")) {\n              return;\n            }\n            (initialMenuItem(content, focusTarget) ?? content).focus({\n              preventScroll: true\n            });\n            focusTargetRef.current = \"first\";\n          });\n        }\n        return null;\n      }\n      const details = createRootChangeDetails(\n        reason,\n        event,\n        next ? trigger : (triggerRef.current ?? trigger)\n      );\n      onOpenChange?.(next, details);\n      if (details.isCanceled) {\n        return details;\n      }\n      if (controlled) {\n        pendingAcceptedOpenRef.current = next;\n        queueMicrotask(() => {\n          if (pendingAcceptedOpenRef.current === next) {\n            pendingAcceptedOpenRef.current = null;\n          }\n        });\n      }\n      if (next) {\n        focusTargetRef.current = focusTarget;\n        restoreFocusOnCloseRef.current = false;\n        rememberFocusReturnTarget(\n          reason === \"trigger-hover\" || reason === \"trigger-press\"\n            ? triggerElement\n            : null\n        );\n        if (triggerElement && requestedTriggerId) {\n          activateTrigger(requestedTriggerId, triggerElement);\n        }\n      } else {\n        const pendingClose = pendingRenderedCloseRef.current + 1;\n        pendingRenderedCloseRef.current = pendingClose;\n        queueMicrotask(() => {\n          if (pendingRenderedCloseRef.current === pendingClose) {\n            pendingRenderedCloseRef.current = 0;\n          }\n        });\n        if (contentRef.current) {\n          closeMenuBranches(contentRef.current, null, reason, event, trigger);\n        }\n        restoreFocusOnCloseRef.current =\n          reason === \"escape-key\" || reason === \"item-press\";\n      }\n      lastOpenReasonRef.current = reason;\n      if (!controlled && next !== openRef.current) {\n        openRef.current = next;\n        setInternalOpen(next);\n      }\n      if (switchingTrigger && focusTarget !== \"none\") {\n        requestAnimationFrame(() => {\n          if (activeTriggerIdRef.current !== requestedTriggerId) {\n            return;\n          }\n          const item = contentRef.current\n            ? initialMenuItem(contentRef.current, focusTarget)\n            : undefined;\n          (item ?? contentRef.current)?.focus({ preventScroll: true });\n          focusTargetRef.current = \"first\";\n        });\n      }\n      return details;\n    },\n    [\n      activateTrigger,\n      closeMenuBranches,\n      controlled,\n      disabled,\n      onOpenChange,\n      rememberFocusReturnTarget\n    ]\n  );\n\n  useHeidiLayoutEffect(() => {\n    mountedRef.current = true;\n    return () => {\n      mountedRef.current = false;\n    };\n  }, []);\n\n  useHeidiLayoutEffect(() => {\n    const previousOpen = previousRenderedOpenRef.current;\n    previousRenderedOpenRef.current = open;\n    if (!previousOpen && open) {\n      if (!focusReturnTargetRef.current) {\n        rememberFocusReturnTarget();\n      }\n      return;\n    }\n    if (!previousOpen || open) {\n      return;\n    }\n    if (pendingRenderedCloseRef.current !== 0) {\n      pendingRenderedCloseRef.current = 0;\n      return;\n    }\n    const activeElement = getOwnerDocument()?.activeElement;\n    restoreFocusOnCloseRef.current =\n      activeElement instanceof Node &&\n      contentRef.current?.contains(activeElement) === true;\n    if (contentRef.current) {\n      closeMenuBranches(\n        contentRef.current,\n        null,\n        \"none\",\n        new Event(\"state-close\"),\n        triggerRef.current ?? undefined\n      );\n    }\n  }, [closeMenuBranches, getOwnerDocument, open, rememberFocusReturnTarget]);\n\n  const requestDismiss = useCallback(\n    (\n      reason: \"escape-key\" | \"focus-out\" | \"outside-press\",\n      event: Event\n    ) => requestOpen(false, reason, event, undefined, \"none\"),\n    [requestOpen]\n  );\n\n  useMenuManualDismiss({\n    contentRef,\n    getOwnerDocument,\n    isWithinZone: isWithinDismissZone,\n    open,\n    requestClose: requestDismiss\n  });\n\n  closeForMissingTriggerRef.current = () => {\n    requestOpen(false, \"none\", new Event(\"trigger-unmount\"), undefined, \"none\");\n  };\n\n  const cancelTriggerHover = useCallback(() => {\n    if (triggerHoverOpenTimerRef.current !== null) {\n      clearTimeout(triggerHoverOpenTimerRef.current);\n      triggerHoverOpenTimerRef.current = null;\n    }\n    triggerHoverPendingRef.current = null;\n    if (triggerHoverCloseTimerRef.current !== null) {\n      clearTimeout(triggerHoverCloseTimerRef.current);\n      triggerHoverCloseTimerRef.current = null;\n    }\n    triggerHoverGraceCleanupRef.current?.();\n    triggerHoverGraceCleanupRef.current = null;\n  }, []);\n\n  useEffect(() => () => cancelTriggerHover(), [cancelTriggerHover]);\n\n  useEffect(() => {\n    if (!disabled) {\n      return;\n    }\n    cancelTriggerHover();\n    triggerHoverSessionRef.current = null;\n    if (lastOpenReasonRef.current === \"trigger-hover\") {\n      lastOpenReasonRef.current = null;\n    }\n  }, [cancelTriggerHover, disabled]);\n\n  useEffect(() => {\n    if (open) {\n      return;\n    }\n    mouseUpSelectionAllowedRef.current = false;\n    cancelTriggerHover();\n    triggerHoverSessionRef.current = null;\n  }, [cancelTriggerHover, open]);\n\n  const scheduleTriggerHoverOpen = useCallback(\n    (\n      event: globalThis.PointerEvent,\n      trigger: HTMLElement,\n      delay: number,\n      closeDelay: number\n    ) => {\n      if (event.pointerType !== \"mouse\" || disabled) {\n        return;\n      }\n      cancelTriggerHover();\n      const run = () => {\n        triggerHoverOpenTimerRef.current = null;\n        if (triggerHoverPendingRef.current === trigger) {\n          triggerHoverPendingRef.current = null;\n        }\n        if (\n          !trigger.isConnected ||\n          triggerElementsRef.current.get(trigger.id)?.element !== trigger\n        ) {\n          return;\n        }\n        const details = requestOpen(\n          true,\n          \"trigger-hover\",\n          event,\n          trigger,\n          \"none\"\n        );\n        if (details?.isCanceled) {\n          triggerHoverSessionRef.current = null;\n          return;\n        }\n        if (\n          details ||\n          (openRef.current &&\n            activeTriggerIdRef.current === trigger.id &&\n            lastOpenReasonRef.current === \"trigger-hover\")\n        ) {\n          triggerHoverSessionRef.current = {\n            closeDelay: finiteDelay(closeDelay),\n            openedAt: performance.now(),\n            trigger\n          };\n        }\n      };\n      triggerHoverPendingRef.current = trigger;\n      if (!Number.isFinite(delay) || delay <= 0) {\n        run();\n      } else {\n        triggerHoverOpenTimerRef.current = setTimeout(run, finiteDelay(delay));\n      }\n    },\n    [cancelTriggerHover, disabled, requestOpen]\n  );\n\n  const scheduleTriggerHoverClose = useCallback(\n    (event: globalThis.PointerEvent, source: HTMLElement) => {\n      const session = triggerHoverSessionRef.current;\n      if (event.pointerType !== \"mouse\" || disabled) {\n        return;\n      }\n      if (!session || lastOpenReasonRef.current !== \"trigger-hover\") {\n        cancelTriggerHover();\n        return;\n      }\n      cancelTriggerHover();\n      const run = () => {\n        triggerHoverCloseTimerRef.current = null;\n        const details = requestOpen(\n          false,\n          \"trigger-hover\",\n          event,\n          source,\n          \"none\"\n        );\n        if (details && !details.isCanceled) {\n          triggerHoverSessionRef.current = null;\n        }\n      };\n      const schedule = (minimumDelay = 0) => {\n        const delay = Math.max(session.closeDelay, minimumDelay);\n        if (!Number.isFinite(delay) || delay <= 0) {\n          run();\n        } else {\n          triggerHoverCloseTimerRef.current = setTimeout(run, delay);\n        }\n      };\n\n      const content = contentRef.current;\n      const trigger = session.trigger;\n      if (\n        openRef.current &&\n        content &&\n        trigger.isConnected &&\n        (source === trigger || source === content)\n      ) {\n        const destination = source === trigger ? content : trigger;\n        const start = { x: event.clientX, y: event.clientY };\n        const [a, b] = pointerBridgeEdge(destination.getBoundingClientRect(), start);\n        const ownerDocument = source.ownerDocument;\n        const handleMove = (moveEvent: globalThis.PointerEvent) => {\n          const target = moveEvent.target;\n          if (\n            target instanceof Node &&\n            (content.contains(target) || trigger.contains(target))\n          ) {\n            cancelTriggerHover();\n            return;\n          }\n          if (pointInTriangle({ x: moveEvent.clientX, y: moveEvent.clientY }, start, a, b)) {\n            return;\n          }\n          triggerHoverGraceCleanupRef.current?.();\n          triggerHoverGraceCleanupRef.current = null;\n          if (triggerHoverCloseTimerRef.current !== null) {\n            clearTimeout(triggerHoverCloseTimerRef.current);\n            triggerHoverCloseTimerRef.current = null;\n          }\n          schedule(120);\n        };\n        ownerDocument.addEventListener(\"pointermove\", handleMove);\n        triggerHoverGraceCleanupRef.current = () =>\n          ownerDocument.removeEventListener(\"pointermove\", handleMove);\n        schedule(400);\n        return;\n      }\n      schedule();\n    },\n    [cancelTriggerHover, disabled, requestOpen]\n  );\n\n  const wasRecentlyHoverOpened = useCallback(\n    (trigger: HTMLElement) => {\n      const session = triggerHoverSessionRef.current;\n      const recent =\n        openRef.current &&\n        lastOpenReasonRef.current === \"trigger-hover\" &&\n        session?.trigger === trigger &&\n        performance.now() - session.openedAt < 500;\n      if (recent) {\n        cancelTriggerHover();\n        lastOpenReasonRef.current = \"trigger-press\";\n      }\n      return recent;\n    },\n    [cancelTriggerHover]\n  );\n\n  const completeOpenChange = useCallback(\n    (next: boolean) => {\n      if (completedStateRef.current === next) {\n        return;\n      }\n      completedStateRef.current = next;\n      onOpenChangeComplete?.(next);\n    },\n    [onOpenChangeComplete]\n  );\n\n  const restoreFocus = useCallback(() => {\n    const shouldRestore = restoreFocusOnCloseRef.current;\n    const rememberedTarget = focusReturnTargetRef.current;\n    restoreFocusOnCloseRef.current = false;\n    focusReturnTargetRef.current = null;\n    if (!shouldRestore) {\n      return;\n    }\n    const ownerDocument = getOwnerDocument();\n    if (\n      ownerDocument &&\n      focusMovedIntoNestedLayer(\n        contentRef.current,\n        ownerDocument.activeElement,\n        ownerDocument\n      )\n    ) {\n      return;\n    }\n    const target = rememberedTarget?.isConnected\n      ? rememberedTarget\n      : triggerRef.current;\n    target?.focus({ preventScroll: true });\n  }, [getOwnerDocument]);\n\n  const activeTriggerAnchorName =\n    (activeTriggerId\n      ? triggerElementsRef.current.get(activeTriggerId)?.anchorName\n      : undefined) ?? `--hui-menu-anchor-${safeId}`;\n\n  const value = useMemo<MenuContextValue>(\n    () => ({\n      activeTriggerAnchorName,\n      activeTriggerId,\n      activateTrigger,\n      cancelTriggerHover,\n      closeMenuBranches,\n      completeOpenChange,\n      contentId,\n      disabled,\n      getOpen,\n      highlightItemOnHover,\n      isWithinDismissZone,\n      isSubmenuPointerGraceActive,\n      loopFocus,\n      mouseUpSelectionAllowedRef,\n      requestOpen,\n      registerTrigger,\n      registerSubmenu,\n      restoreFocus,\n      scheduleSubmenuItemHoverClose,\n      scheduleTriggerHoverClose,\n      scheduleTriggerHoverOpen,\n      setContentElement,\n      setSubmenuPointerGrace,\n      submenuCloseDelay: finiteDelay(submenuCloseDelay),\n      submenuOpenDelay: finiteDelay(submenuOpenDelay),\n      takeFocusTarget,\n      triggerRef,\n      wasRecentlyHoverOpened\n    }),\n    [\n      activeTriggerAnchorName,\n      activeTriggerId,\n      activateTrigger,\n      cancelTriggerHover,\n      closeMenuBranches,\n      completeOpenChange,\n      contentId,\n      disabled,\n      getOpen,\n      highlightItemOnHover,\n      isWithinDismissZone,\n      isSubmenuPointerGraceActive,\n      loopFocus,\n      registerTrigger,\n      registerSubmenu,\n      requestOpen,\n      restoreFocus,\n      scheduleSubmenuItemHoverClose,\n      scheduleTriggerHoverClose,\n      scheduleTriggerHoverOpen,\n      setContentElement,\n      setSubmenuPointerGrace,\n      submenuCloseDelay,\n      submenuOpenDelay,\n      takeFocusTarget,\n      wasRecentlyHoverOpened\n    ]\n  );\n\n  return (\n    <MenuContext value={value}>\n      <MenuOpenContext value={open}>\n        <MenuDismissLayerContext value={isWithinDismissZone}>\n          {children}\n        </MenuDismissLayerContext>\n      </MenuOpenContext>\n    </MenuContext>\n  );\n}\n\nexport type MenuTriggerState = { disabled: boolean; open: boolean };\n\ntype MenuTriggerNativeProps = Omit<\n  NativeHostProps<\"button\">,\n  | \"aria-controls\"\n  | \"aria-disabled\"\n  | \"aria-expanded\"\n  | \"aria-haspopup\"\n  | \"disabled\"\n  | \"id\"\n  | \"onClick\"\n  | \"onKeyDown\"\n  | \"onMouseDown\"\n  | \"onPointerEnter\"\n  | \"onPointerLeave\"\n  | \"role\"\n  | \"tabIndex\"\n  | \"type\"\n>;\n\nexport type MenuTriggerProps = HeidiIntrinsicHostProps<MenuTriggerState, \"button\"> &\n  MenuTriggerNativeProps & {\n    children?: ReactNode;\n    /** Delay before pointer hover may open the menu, in milliseconds. */\n    delay?: number;\n    /** Delay before a hover-opened menu closes, in milliseconds. */\n    closeDelay?: number;\n    disabled?: boolean;\n    id?: string;\n    /** Set false when `render` returns a non-button host. */\n    nativeButton?: boolean;\n    onClick?: ComponentPropsWithoutRef<\"button\">[\"onClick\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"button\">[\"onKeyDown\"];\n    onMouseDown?: ComponentPropsWithoutRef<\"button\">[\"onMouseDown\"];\n    /** Also open this menu from mouse hover. */\n    openOnHover?: boolean;\n    onPointerEnter?: ComponentPropsWithoutRef<\"button\">[\"onPointerEnter\"];\n    onPointerLeave?: ComponentPropsWithoutRef<\"button\">[\"onPointerLeave\"];\n    ref?: Ref<HTMLButtonElement>;\n  };\n\nexport function MenuTrigger({\n  children,\n  className,\n  closeDelay = 0,\n  delay = 100,\n  disabled: disabledProp = false,\n  id: idProp,\n  nativeButton = true,\n  onClick,\n  onKeyDown,\n  onMouseDown,\n  onPointerEnter,\n  onPointerLeave,\n  openOnHover = false,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuTriggerProps) {\n  const context = useMenuContext(\"Trigger\");\n  const rootOpen = useMenuOpen();\n  const localId = toSafeId(useId());\n  const triggerId = idProp ?? `hui-menu-trigger-${localId}`;\n  const anchorName = `--hui-menu-anchor-${localId}`;\n  const open = rootOpen && context.activeTriggerId === triggerId;\n  const disabled = disabledProp || context.disabled;\n  const gestureCleanupRef = useRef<(() => void) | null>(null);\n  const suppressNextClickRef = useRef(false);\n  const suppressClearTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const { registerTrigger } = context;\n  const setTriggerRef = useCallback(\n    (element: HTMLButtonElement | null) =>\n      registerTrigger(triggerId, anchorName, element),\n    [anchorName, registerTrigger, triggerId]\n  );\n  const state = { disabled, open };\n\n  const clearGestureSession = useCallback(() => {\n    gestureCleanupRef.current?.();\n    gestureCleanupRef.current = null;\n    context.mouseUpSelectionAllowedRef.current = false;\n    if (suppressClearTimerRef.current !== null) {\n      clearTimeout(suppressClearTimerRef.current);\n      suppressClearTimerRef.current = null;\n    }\n  }, [context.mouseUpSelectionAllowedRef]);\n\n  useEffect(() => clearGestureSession, [clearGestureSession]);\n\n  const beginMouseGesture = (\n    trigger: HTMLElement,\n    allowItemRelease: boolean,\n    closeOnOutsideRelease: boolean\n  ) => {\n    clearGestureSession();\n    const ownerDocument = trigger.ownerDocument;\n    let eligibilityTimer: ReturnType<typeof setTimeout> | null = null;\n    if (allowItemRelease) {\n      eligibilityTimer = setTimeout(() => {\n        eligibilityTimer = null;\n        context.mouseUpSelectionAllowedRef.current = true;\n      }, 200);\n    }\n    const handleDocumentMouseUp = (event: globalThis.MouseEvent) => {\n      gestureCleanupRef.current?.();\n      gestureCleanupRef.current = null;\n      suppressClearTimerRef.current = setTimeout(() => {\n        suppressClearTimerRef.current = null;\n        suppressNextClickRef.current = false;\n      }, 0);\n      if (!closeOnOutsideRelease || context.isWithinDismissZone(event.target)) {\n        return;\n      }\n      const bounds = trigger.getBoundingClientRect();\n      const withinTriggerSlop =\n        event.clientX >= bounds.left - 5 &&\n        event.clientX <= bounds.right + 5 &&\n        event.clientY >= bounds.top - 5 &&\n        event.clientY <= bounds.bottom + 5;\n      if (!withinTriggerSlop) {\n        context.requestOpen(\n          false,\n          \"cancel-open\",\n          event,\n          trigger,\n          \"none\"\n        );\n      }\n    };\n    ownerDocument.addEventListener(\"mouseup\", handleDocumentMouseUp, {\n      once: true\n    });\n    gestureCleanupRef.current = () => {\n      if (eligibilityTimer !== null) {\n        clearTimeout(eligibilityTimer);\n        eligibilityTimer = null;\n      }\n      context.mouseUpSelectionAllowedRef.current = false;\n      ownerDocument.removeEventListener(\"mouseup\", handleDocumentMouseUp);\n    };\n  };\n\n  const handleMouseDown = (event: MouseEvent<HTMLButtonElement>) => {\n    if (event.button !== 0) {\n      onMouseDown?.(event);\n      return;\n    }\n    onMouseDown?.(event);\n    suppressNextClickRef.current = true;\n    if (disabled || event.defaultPrevented) {\n      beginMouseGesture(event.currentTarget, false, false);\n      return;\n    }\n    context.cancelTriggerHover();\n    if (context.wasRecentlyHoverOpened(event.currentTarget)) {\n      beginMouseGesture(event.currentTarget, false, true);\n      return;\n    }\n    const wasOpen = context.getOpen();\n    const next = !(wasOpen && context.activeTriggerId === triggerId);\n    const details = context.requestOpen(\n      next,\n      \"trigger-press\",\n      event.nativeEvent,\n      event.currentTarget,\n      \"first\"\n    );\n    beginMouseGesture(\n      event.currentTarget,\n      next && !wasOpen && !details?.isCanceled,\n      next && !details?.isCanceled\n    );\n  };\n\n  const handleClick = (event: MouseEvent<HTMLButtonElement>) => {\n    if (disabled) {\n      event.preventDefault();\n      return;\n    }\n    onClick?.(event);\n    const suppressed = suppressNextClickRef.current;\n    suppressNextClickRef.current = false;\n    if (event.defaultPrevented) {\n      return;\n    }\n    if (suppressed) {\n      return;\n    }\n    context.cancelTriggerHover();\n    if (context.wasRecentlyHoverOpened(event.currentTarget)) {\n      return;\n    }\n    context.requestOpen(\n      !(context.getOpen() && context.activeTriggerId === triggerId),\n      \"trigger-press\",\n      event.nativeEvent,\n      event.currentTarget,\n      \"first\"\n    );\n  };\n\n  const handleKeyDown = composeHeidiEventHandlers(\n    onKeyDown,\n    (event: KeyboardEvent<HTMLButtonElement>) => {\n      if (disabled) {\n        return;\n      }\n      if (event.key === \"ArrowDown\" || event.key === \"ArrowUp\") {\n        event.preventDefault();\n        context.cancelTriggerHover();\n        context.requestOpen(\n          true,\n          \"trigger-press\",\n          event.nativeEvent,\n          event.currentTarget,\n          event.key === \"ArrowUp\" ? \"last\" : \"first\"\n        );\n        return;\n      }\n      if (!nativeButton && (event.key === \"Enter\" || event.key === \" \")) {\n        event.preventDefault();\n        if (!event.repeat) {\n          event.currentTarget.click();\n        }\n      }\n    }\n  );\n\n  return renderHeidiElement({\n    className: MENU_CLASSES.trigger,\n    dataPart: \"menu-trigger\",\n    element: \"button\",\n    props: {\n      ...nativeProps,\n      ...(nativeButton ? nativeDisabledAttrs(disabled) : ariaDisabledAttrs(disabled)),\n      \"aria-controls\": context.contentId,\n      \"aria-expanded\": open,\n      \"aria-haspopup\": \"menu\",\n      children,\n      // ponytail: `true`, not `\"\"`. Dialog and HoverCard emit this hook as a\n      // boolean and are the only two primitives that ship a selector for it —\n      // both value-exact (`[data-popup-open=\"true\"]`). Menu/ContextMenu emitted\n      // `\"\"`, so a consumer copying the documented trigger-lift selector onto a\n      // Menu trigger got a silently dead rule. Rejected changing the two\n      // selectors to attribute-presence instead: the published anatomy for\n      // dialog/hover-card declares the value `\"true\"`, and the anatomy build\n      // validates declared states against value-exact selectors.\n      \"data-popup-open\": open ? true : undefined,\n      \"data-pressed\": open ? \"\" : undefined,\n      \"data-state\": dataState(open),\n      id: triggerId,\n      onClick: handleClick,\n      onKeyDown: handleKeyDown,\n      onMouseDown: handleMouseDown,\n      onPointerEnter: composeHeidiEventHandlers(\n        onPointerEnter,\n        (event: PointerEvent<HTMLButtonElement>) => {\n          if (openOnHover && !disabled) {\n            context.scheduleTriggerHoverOpen(\n              event.nativeEvent,\n              event.currentTarget,\n              finiteDelay(delay),\n              finiteDelay(closeDelay)\n            );\n          }\n        }\n      ),\n      onPointerLeave: composeHeidiEventHandlers(\n        onPointerLeave,\n        (event: PointerEvent<HTMLButtonElement>) => {\n          if (openOnHover && !disabled) {\n            context.scheduleTriggerHoverClose(event.nativeEvent, event.currentTarget);\n          }\n        }\n      ),\n      ref: mergeHeidiRefs(setTriggerRef, ref),\n      role: nativeButton ? undefined : \"button\",\n      tabIndex: nativeButton ? undefined : disabled ? -1 : 0,\n      type: nativeButton ? \"button\" : undefined\n    },\n    renderProps: { className, render, style },\n    state,\n    structuralStyle: { anchorName } as CSSProperties\n  });\n}\n\nexport type MenuContentState = {\n  align: MenuAlign;\n  open: boolean;\n  side: MenuSide;\n};\n\ntype MenuContentNativeProps = Omit<\n  NativeHostProps<\"div\">,\n  | \"aria-labelledby\"\n  | \"id\"\n  | \"onBeforeToggle\"\n  | \"onKeyDown\"\n  | \"onKeyDownCapture\"\n  | \"onPointerEnter\"\n  | \"onPointerLeave\"\n  | \"onToggle\"\n  | \"popover\"\n  | \"role\"\n  | \"tabIndex\"\n>;\n\nexport type MenuContentProps = HeidiIntrinsicHostProps<MenuContentState, \"div\"> &\n  MenuContentNativeProps & {\n    align?: MenuAlign;\n    /** Cross-axis offset in CSS pixels. */\n    alignOffset?: number;\n    children?: ReactNode;\n    keepMounted?: boolean;\n    onBeforeToggle?: ComponentPropsWithoutRef<\"div\">[\"onBeforeToggle\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onKeyDownCapture?: ComponentPropsWithoutRef<\"div\">[\"onKeyDownCapture\"];\n    onPointerEnter?: ComponentPropsWithoutRef<\"div\">[\"onPointerEnter\"];\n    onPointerLeave?: ComponentPropsWithoutRef<\"div\">[\"onPointerLeave\"];\n    onToggle?: (event: SyntheticEvent<HTMLDivElement>) => void;\n    ref?: Ref<HTMLDivElement>;\n    side?: MenuSide;\n    /** Main-axis gap in CSS pixels. */\n    sideOffset?: number;\n  };\n\nexport function MenuContent({\n  align = \"start\",\n  alignOffset = 0,\n  children,\n  className,\n  keepMounted = false,\n  onBeforeToggle,\n  onKeyDown,\n  onKeyDownCapture,\n  onPointerEnter,\n  onPointerLeave,\n  onToggle,\n  ref,\n  render,\n  side = \"bottom\",\n  sideOffset = 4,\n  style,\n  ...nativeProps\n}: MenuContentProps) {\n  const context = useMenuContext(\"Content\");\n  const open = useMenuOpen();\n  const localRef = useRef<HTMLDivElement | null>(null);\n  const completionCleanupRef = useRef<() => void>(() => undefined);\n  const internalNativeTransitionRef = useRef(false);\n  const lastBeforeToggleRef = useRef<{\n    internal: boolean;\n    open: boolean;\n  } | null>(null);\n  const typeaheadRef = useRef<TypeaheadState>({ buffer: \"\", timer: null });\n  const physicalSide = usePhysicalSide(side, localRef, open);\n  useMenuViewportClamp(localRef, open);\n  const { scheduleUnmount, shouldRender } = usePopoverPresence(\n    open,\n    keepMounted,\n    context.getOpen\n  );\n\n  const synchronizeNativeOpen = useCallback(\n    (element: HTMLDivElement, next: boolean) => {\n      synchronizeNativePopoverOpen(element, next, {\n        show: (target) => showPopoverFrom(target, context.triggerRef.current),\n        transitionRef: internalNativeTransitionRef\n      });\n    },\n    [context.triggerRef]\n  );\n\n  useEffect(() => {\n    resetTypeahead(typeaheadRef.current);\n  }, [context.activeTriggerId, open]);\n\n  useEffect(\n    () => () => {\n      completionCleanupRef.current();\n      resetTypeahead(typeaheadRef.current);\n    },\n    []\n  );\n\n  useEffect(() => {\n    const element = localRef.current;\n    if (!element || typeof element.showPopover !== \"function\") {\n      return;\n    }\n    const nativeOpen = element.matches(\":popover-open\");\n    if (open && !nativeOpen) {\n      const timer = window.setTimeout(() => {\n        if (context.getOpen() && element.isConnected) {\n          synchronizeNativeOpen(element, true);\n        }\n      }, 0);\n      return () => window.clearTimeout(timer);\n    }\n    if (!open && nativeOpen) {\n      // Manual popovers do not implicitly close manual descendants. Hide the\n      // deepest native layers while their ancestor is still in the top layer.\n      closeDescendantSubmenus(element);\n      synchronizeNativeOpen(element, false);\n    }\n    if (!open && !nativeOpen) {\n      scheduleUnmount(element);\n      requestAnimationFrame(context.restoreFocus);\n    }\n    return undefined;\n  }, [context, open, scheduleUnmount, synchronizeNativeOpen]);\n\n  if (!shouldRender) {\n    return null;\n  }\n\n  const handleBeforeToggle = (event: ToggleEvent<HTMLDivElement>) => {\n    if (event.target !== event.currentTarget) {\n      return;\n    }\n    const nativeToggle = event.nativeEvent as Event & { newState?: string };\n    const internal = internalNativeTransitionRef.current;\n    // Consume the synchronous library marker before invoking consumer code so\n    // a nested native transition started by that code is classified external.\n    internalNativeTransitionRef.current = false;\n    lastBeforeToggleRef.current = {\n      internal,\n      open: nativeToggle.newState === \"open\"\n    };\n    onBeforeToggle?.(event);\n    if (internal && event.defaultPrevented) {\n      lastBeforeToggleRef.current = null;\n      context.requestOpen(\n        nativeToggle.newState !== \"open\",\n        \"none\",\n        nativeToggle,\n        context.triggerRef.current ?? undefined,\n        \"none\"\n      );\n    }\n  };\n\n  const handleToggle = (event: SyntheticEvent<HTMLDivElement>) => {\n    if (event.target !== event.currentTarget) {\n      return;\n    }\n    // `toggle` is observational and non-cancelable at the platform layer.\n    // Synthetic preventDefault must not strand native-state bookkeeping.\n    onToggle?.(event);\n    const element = event.currentTarget;\n    const nativeToggle = event.nativeEvent as Event & { newState?: string };\n    const nativeOpen = nativeToggle.newState === \"open\";\n    if (nativeOpen) clampMenuToVisualViewport(element);\n    const transition = lastBeforeToggleRef.current;\n    lastBeforeToggleRef.current = null;\n    const internallySynchronized =\n      transition?.internal === true && transition.open === nativeOpen;\n\n    let details: MenuRootChangeEventDetails | null = null;\n    if (!internallySynchronized && nativeOpen !== context.getOpen()) {\n      details = context.requestOpen(\n        nativeOpen,\n        nativeOpen ? \"none\" : \"outside-press\",\n        nativeToggle,\n        context.triggerRef.current ?? undefined,\n        \"first\"\n      );\n    }\n    if (nativeOpen !== context.getOpen()) {\n      requestAnimationFrame(() => {\n        if (element.isConnected) {\n          synchronizeNativeOpen(element, context.getOpen());\n        }\n      });\n    }\n\n    completionCleanupRef.current();\n    completionCleanupRef.current = completeAfterPopoverAnimations(element, nativeOpen, () => {\n      if (context.getOpen() === nativeOpen) {\n        context.completeOpenChange(nativeOpen);\n      }\n    });\n\n    if (nativeOpen && context.getOpen()) {\n      const target = context.takeFocusTarget();\n      if (target !== \"none\") {\n        queueMicrotask(() => {\n          (initialMenuItem(element, target) ?? element).focus({\n            preventScroll: true\n          });\n        });\n      }\n    } else if (!nativeOpen && !context.getOpen()) {\n      closeDescendantSubmenus(element);\n      scheduleUnmount(element);\n      requestAnimationFrame(context.restoreFocus);\n    } else if (details?.isCanceled) {\n      requestAnimationFrame(() => synchronizeNativeOpen(element, context.getOpen()));\n    }\n  };\n\n  const handleKeyDown = composeHeidiEventHandlers(\n    onKeyDown,\n    (event: KeyboardEvent<HTMLDivElement>) => {\n      if (!menuOwnsKeyboardTarget(event.currentTarget, event.target)) {\n        return;\n      }\n      if (context.disabled) {\n        return;\n      }\n      if (event.key === \"Escape\") {\n        event.preventDefault();\n        event.stopPropagation();\n        context.requestOpen(false, \"escape-key\", event.nativeEvent, event.currentTarget);\n        return;\n      }\n      if (event.key === \"Tab\") {\n        const target = event.shiftKey\n          ? context.triggerRef.current\n          : tabTargetAfterTrigger(context.triggerRef.current);\n        const details = context.requestOpen(\n          false,\n          \"focus-out\",\n          event.nativeEvent,\n          event.currentTarget\n        );\n        if (!details || details.isCanceled) {\n          event.preventDefault();\n          return;\n        }\n        if (target) {\n          event.preventDefault();\n          requestAnimationFrame(() => target.focus({ preventScroll: true }));\n        }\n        return;\n      }\n      if (\n        event.key === \"ArrowDown\" ||\n        event.key === \"ArrowUp\" ||\n        event.key === \"End\" ||\n        event.key === \"Home\"\n      ) {\n        event.preventDefault();\n        moveMenuFocus(event.currentTarget, event.key, context.loopFocus, () => {\n          context.closeMenuBranches(\n            event.currentTarget,\n            null,\n            \"none\",\n            event.nativeEvent,\n            event.currentTarget\n          );\n        });\n        return;\n      }\n      if (\n        event.key.length === 1 &&\n        event.key !== \" \" &&\n        !event.nativeEvent.isComposing &&\n        !event.altKey &&\n        !event.ctrlKey &&\n        !event.metaKey\n      ) {\n        runTypeahead(event.currentTarget, event.key, typeaheadRef.current);\n      }\n    }\n  );\n\n  const state = { align, open, side };\n  const ariaLabel = nativeProps[\"aria-label\"];\n  return renderHeidiElement({\n    className: MENU_CLASSES.content,\n    dataPart: \"menu-content\",\n    element: \"div\",\n    props: {\n      ...nativeProps,\n      ...openStateAttributes(open),\n      \"aria-labelledby\": ariaLabel ? undefined : context.activeTriggerId ?? undefined,\n      children,\n      \"data-align\": align,\n      \"data-position-side\": physicalSide,\n      \"data-side\": side,\n      \"data-state\": dataState(open),\n      id: context.contentId,\n      onBeforeToggle: handleBeforeToggle,\n      onKeyDown: handleKeyDown,\n      onKeyDownCapture: composeHeidiEventHandlers(\n        onKeyDownCapture,\n        (event: KeyboardEvent<HTMLDivElement>) => {\n          if (\n            !context.disabled &&\n            menuOwnsKeyboardTarget(event.currentTarget, event.target)\n          ) {\n            extendActiveTypeaheadWithSpace(event, typeaheadRef.current);\n          }\n        }\n      ),\n      onPointerEnter: composeHeidiEventHandlers(\n        onPointerEnter,\n        context.cancelTriggerHover\n      ),\n      onPointerLeave: composeHeidiEventHandlers(\n        onPointerLeave,\n        (event: PointerEvent<HTMLDivElement>) => {\n          context.scheduleTriggerHoverClose(event.nativeEvent, event.currentTarget);\n        }\n      ),\n      onToggle: handleToggle,\n      popover: \"manual\",\n      ref: mergeHeidiRefs(localRef, context.setContentElement, ref),\n      role: \"menu\",\n      tabIndex: -1\n    },\n    renderProps: { className, render, style },\n    state,\n    structuralStyle: {\n      \"--_hui-menu-align-offset\": `${alignOffset}px`,\n      \"--_hui-menu-side-offset\": `${Math.max(0, sideOffset)}px`,\n      positionAnchor: context.activeTriggerAnchorName\n    } as CSSProperties\n  });\n}\n\nexport const MenuPopup = MenuContent;\nexport type MenuPopupProps = MenuContentProps;\n\nexport type MenuItemState = { disabled: boolean; highlighted: boolean };\n\ntype MenuItemNativeProps = Omit<\n  NativeHostProps<\"div\">,\n  | \"aria-disabled\"\n  | \"onBlur\"\n  | \"onClick\"\n  | \"onFocus\"\n  | \"onKeyDown\"\n  | \"onMouseUp\"\n  | \"onPointerMove\"\n  | \"role\"\n  | \"tabIndex\"\n>;\n\nexport type MenuItemProps = HeidiIntrinsicHostProps<MenuItemState, \"div\"> &\n  MenuItemNativeProps & {\n    children?: ReactNode;\n    closeOnClick?: boolean;\n    disabled?: boolean;\n    label?: string;\n    /** Set true when `render` returns a native button. */\n    nativeButton?: boolean;\n    onBlur?: ComponentPropsWithoutRef<\"div\">[\"onBlur\"];\n    onClick?: ComponentPropsWithoutRef<\"div\">[\"onClick\"];\n    onFocus?: ComponentPropsWithoutRef<\"div\">[\"onFocus\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onMouseUp?: ComponentPropsWithoutRef<\"div\">[\"onMouseUp\"];\n    onPointerMove?: ComponentPropsWithoutRef<\"div\">[\"onPointerMove\"];\n    onSelect?: () => void;\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function MenuItem({\n  children,\n  className,\n  closeOnClick = true,\n  disabled: disabledProp = false,\n  label,\n  nativeButton = false,\n  onBlur,\n  onClick,\n  onFocus,\n  onKeyDown,\n  onMouseUp,\n  onPointerMove,\n  onSelect,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuItemProps) {\n  const context = useMenuContext(\"Item\");\n  const disabled = disabledProp || context.disabled;\n  const [highlighted, setHighlighted] = useState(false);\n  const state = useMemo(() => ({ disabled, highlighted }), [disabled, highlighted]);\n\n  const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n    if (disabled) {\n      event.preventDefault();\n      return;\n    }\n    onClick?.(event);\n    if (event.defaultPrevented) {\n      return;\n    }\n    onSelect?.();\n    if (closeOnClick) {\n      context.requestOpen(false, \"item-press\", event.nativeEvent, event.currentTarget);\n    }\n  };\n\n  return renderHeidiElement({\n    className: MENU_CLASSES.item,\n    dataPart: \"menu-item\",\n    element: \"div\",\n    props: {\n      ...nativeProps,\n      onKeyUp: disabled ? undefined : nativeProps.onKeyUp,\n      onMouseDown: disabled ? undefined : nativeProps.onMouseDown,\n      onPointerDown: disabled ? undefined : nativeProps.onPointerDown,\n      ...ariaDisabledAttrs(disabled),\n      children,\n      \"data-highlighted\": highlighted ? \"true\" : undefined,\n      \"data-label\": label,\n      onBlur: composeHeidiEventHandlers(onBlur, () => setHighlighted(false)),\n      onClick: handleClick,\n      onFocus: composeHeidiEventHandlers(onFocus, () => setHighlighted(true)),\n      onKeyDown: composeHeidiEventHandlers(\n        disabled ? undefined : onKeyDown,\n        (event: KeyboardEvent<HTMLDivElement>) => {\n          if (nativeButton || disabled || event.target !== event.currentTarget) {\n            return;\n          }\n          if ((event.key === \" \" || event.key === \"Enter\") && !event.repeat) {\n            event.preventDefault();\n            event.currentTarget.click();\n          }\n        }\n      ),\n      onMouseUp: composeHeidiEventHandlers(\n        onMouseUp,\n        (event: MouseEvent<HTMLDivElement>) => {\n          if (\n            !disabled &&\n            event.button === 0 &&\n            context.mouseUpSelectionAllowedRef.current\n          ) {\n            dispatchMouseGestureClick(event.currentTarget, event);\n          }\n        }\n      ),\n      onPointerMove: composeHeidiEventHandlers(\n        onPointerMove,\n        (event: PointerEvent<HTMLDivElement>) => {\n          if (context.disabled) {\n            return;\n          }\n          const menu = event.currentTarget.closest('[role=\"menu\"]');\n          const pointerGraceActive = context.isSubmenuPointerGraceActive();\n          if (menu instanceof HTMLElement && !pointerGraceActive) {\n            context.scheduleSubmenuItemHoverClose(\n              menu,\n              event.nativeEvent,\n              event.currentTarget\n            );\n          }\n          if (\n            !pointerGraceActive &&\n            context.highlightItemOnHover &&\n            event.pointerType === \"mouse\"\n          ) {\n            event.currentTarget.focus({ preventScroll: true });\n          }\n        }\n      ),\n      ref,\n      role: \"menuitem\",\n      tabIndex: -1,\n      type: nativeButton ? \"button\" : undefined\n    },\n    renderProps: { className, render, style },\n    state,\n    suppressRenderedHandlers: disabled ? DISABLED_MENU_PRESS_HANDLERS : undefined\n  });\n}\n\nexport type MenuLinkItemState = MenuItemState;\n\ntype MenuLinkItemNativeProps = Omit<\n  NativeHostProps<\"a\">,\n  | \"aria-disabled\"\n  | \"onBlur\"\n  | \"onClick\"\n  | \"onFocus\"\n  | \"onKeyDown\"\n  | \"onMouseUp\"\n  | \"onPointerMove\"\n  | \"role\"\n  | \"tabIndex\"\n>;\n\nexport type MenuLinkItemProps = HeidiIntrinsicHostProps<MenuLinkItemState, \"a\"> &\n  MenuLinkItemNativeProps & {\n    children?: ReactNode;\n    closeOnClick?: boolean;\n    disabled?: boolean;\n    label?: string;\n    onBlur?: ComponentPropsWithoutRef<\"a\">[\"onBlur\"];\n    onClick?: ComponentPropsWithoutRef<\"a\">[\"onClick\"];\n    onFocus?: ComponentPropsWithoutRef<\"a\">[\"onFocus\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"a\">[\"onKeyDown\"];\n    onMouseUp?: ComponentPropsWithoutRef<\"a\">[\"onMouseUp\"];\n    onPointerMove?: ComponentPropsWithoutRef<\"a\">[\"onPointerMove\"];\n    onSelect?: () => void;\n    ref?: Ref<HTMLAnchorElement>;\n  };\n\nexport function MenuLinkItem({\n  children,\n  className,\n  closeOnClick = false,\n  disabled: disabledProp = false,\n  label,\n  onBlur,\n  onClick,\n  onFocus,\n  onKeyDown,\n  onMouseUp,\n  onPointerMove,\n  onSelect,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuLinkItemProps) {\n  const context = useMenuContext(\"LinkItem\");\n  const disabled = disabledProp || context.disabled;\n  const [highlighted, setHighlighted] = useState(false);\n  const state = useMemo(() => ({ disabled, highlighted }), [disabled, highlighted]);\n\n  const handleClick = (event: MouseEvent<HTMLAnchorElement>) => {\n    if (disabled) {\n      event.preventDefault();\n      return;\n    }\n    onClick?.(event);\n    if (event.defaultPrevented) {\n      return;\n    }\n    onSelect?.();\n    if (closeOnClick) {\n      context.requestOpen(false, \"item-press\", event.nativeEvent, event.currentTarget);\n    }\n  };\n\n  return renderHeidiElement({\n    className: MENU_CLASSES.linkItem,\n    dataPart: \"menu-link-item\",\n    element: \"a\",\n    props: {\n      ...nativeProps,\n      onKeyUp: disabled ? undefined : nativeProps.onKeyUp,\n      onMouseDown: disabled ? undefined : nativeProps.onMouseDown,\n      onPointerDown: disabled ? undefined : nativeProps.onPointerDown,\n      ...ariaDisabledAttrs(disabled),\n      children,\n      \"data-highlighted\": highlighted ? \"true\" : undefined,\n      \"data-label\": label,\n      onBlur: composeHeidiEventHandlers(onBlur, () => setHighlighted(false)),\n      onClick: handleClick,\n      onFocus: composeHeidiEventHandlers(onFocus, () => setHighlighted(true)),\n      onKeyDown: composeHeidiEventHandlers(\n        disabled ? undefined : onKeyDown,\n        (event: KeyboardEvent<HTMLAnchorElement>) => {\n          if (!disabled && event.key === \" \" && !event.repeat) {\n            event.preventDefault();\n            event.currentTarget.click();\n          }\n        }\n      ),\n      onMouseUp: composeHeidiEventHandlers(\n        onMouseUp,\n        (event: MouseEvent<HTMLAnchorElement>) => {\n          if (\n            !disabled &&\n            event.button === 0 &&\n            context.mouseUpSelectionAllowedRef.current\n          ) {\n            dispatchMouseGestureClick(event.currentTarget, event);\n          }\n        }\n      ),\n      onPointerMove: composeHeidiEventHandlers(\n        onPointerMove,\n        (event: PointerEvent<HTMLAnchorElement>) => {\n          if (context.disabled) {\n            return;\n          }\n          const menu = event.currentTarget.closest('[role=\"menu\"]');\n          const pointerGraceActive = context.isSubmenuPointerGraceActive();\n          if (menu instanceof HTMLElement && !pointerGraceActive) {\n            context.scheduleSubmenuItemHoverClose(\n              menu,\n              event.nativeEvent,\n              event.currentTarget\n            );\n          }\n          if (\n            !pointerGraceActive &&\n            context.highlightItemOnHover &&\n            event.pointerType === \"mouse\"\n          ) {\n            event.currentTarget.focus({ preventScroll: true });\n          }\n        }\n      ),\n      ref,\n      role: \"menuitem\",\n      tabIndex: -1\n    },\n    renderProps: { className, render, style },\n    state,\n    suppressRenderedHandlers: disabled ? DISABLED_MENU_PRESS_HANDLERS : undefined\n  });\n}\n\nexport type MenuGroupState = { labelled: boolean };\nexport type MenuGroupProps = HeidiIntrinsicHostProps<MenuGroupState, \"div\"> &\n  Omit<NativeHostProps<\"div\">, \"aria-labelledby\" | \"role\"> & {\n    children?: ReactNode;\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function MenuGroup({\n  children,\n  className,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuGroupProps) {\n  const labelId = `hui-menu-group-label-${toSafeId(useId())}`;\n  const [labelled, setLabelled] = useState(false);\n  const registerLabel = useCallback((present: boolean) => setLabelled(present), []);\n  const value = useMemo(() => ({ labelId, registerLabel }), [labelId, registerLabel]);\n  const state = { labelled };\n  return (\n    <MenuGroupLabelContext value={value}>\n      {renderHeidiElement({\n        className: MENU_CLASSES.group,\n        dataPart: \"menu-group\",\n        element: \"div\",\n        props: {\n          ...nativeProps,\n          \"aria-labelledby\": labelled ? labelId : undefined,\n          children,\n          ref,\n          role: \"group\"\n        },\n        renderProps: { className, render, style },\n        state\n      })}\n    </MenuGroupLabelContext>\n  );\n}\n\nexport type MenuGroupLabelState = Record<string, never>;\nexport type MenuGroupLabelProps = HeidiIntrinsicHostProps<MenuGroupLabelState, \"div\"> &\n  Omit<NativeHostProps<\"div\">, \"id\"> & {\n    children?: ReactNode;\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function MenuGroupLabel({\n  children,\n  className,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuGroupLabelProps) {\n  const group = useContext(MenuGroupLabelContext);\n  if (!group) {\n    throw new Error(\"Menu.GroupLabel must be rendered inside Menu.Group or Menu.RadioGroup.\");\n  }\n  useHeidiLayoutEffect(() => {\n    group.registerLabel(true);\n    return () => group.registerLabel(false);\n  }, [group]);\n  return renderHeidiElement({\n    className: MENU_CLASSES.groupLabel,\n    dataPart: \"menu-group-label\",\n    element: \"div\",\n    props: { ...nativeProps, children, id: group.labelId, ref },\n    renderProps: { className, render, style },\n    state: {}\n  });\n}\n\nexport type MenuSeparatorState = Record<string, never>;\nexport type MenuSeparatorProps = HeidiIntrinsicHostProps<MenuSeparatorState, \"div\"> &\n  Omit<NativeHostProps<\"div\">, \"aria-orientation\" | \"role\"> & {\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function MenuSeparator({\n  className,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuSeparatorProps) {\n  return renderHeidiElement({\n    className: MENU_CLASSES.separator,\n    dataPart: \"menu-separator\",\n    element: \"div\",\n    props: { ...nativeProps, \"aria-orientation\": \"horizontal\", ref, role: \"separator\" },\n    renderProps: { className, render, style },\n    state: {}\n  });\n}\n\nexport type MenuCheckboxItemState = MenuItemState & { checked: boolean };\ntype MenuCheckboxItemNativeProps = Omit<\n  MenuItemNativeProps,\n  \"aria-checked\" | \"role\"\n>;\n\nexport type MenuCheckboxItemProps = HeidiIntrinsicHostProps<\n  MenuCheckboxItemState,\n  \"div\"\n> &\n  MenuCheckboxItemNativeProps & {\n    checked?: boolean;\n    children?: ReactNode;\n    closeOnClick?: boolean;\n    defaultChecked?: boolean;\n    disabled?: boolean;\n    label?: string;\n    nativeButton?: boolean;\n    onBlur?: ComponentPropsWithoutRef<\"div\">[\"onBlur\"];\n    onCheckedChange?: (\n      checked: boolean,\n      details: MenuItemChangeEventDetails\n    ) => void;\n    onClick?: ComponentPropsWithoutRef<\"div\">[\"onClick\"];\n    onFocus?: ComponentPropsWithoutRef<\"div\">[\"onFocus\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onMouseUp?: ComponentPropsWithoutRef<\"div\">[\"onMouseUp\"];\n    onPointerMove?: ComponentPropsWithoutRef<\"div\">[\"onPointerMove\"];\n    onSelect?: () => void;\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function MenuCheckboxItem({\n  checked: checkedProp,\n  children,\n  className,\n  closeOnClick = false,\n  defaultChecked = false,\n  disabled: disabledProp = false,\n  label,\n  nativeButton = false,\n  onBlur,\n  onCheckedChange,\n  onClick,\n  onFocus,\n  onKeyDown,\n  onMouseUp,\n  onPointerMove,\n  onSelect,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuCheckboxItemProps) {\n  const root = useMenuContext(\"CheckboxItem\");\n  const disabled = disabledProp || root.disabled;\n  const [internalChecked, setInternalChecked] = useState(defaultChecked);\n  const controlled = checkedProp !== undefined;\n  const checked = checkedProp ?? internalChecked;\n  const [highlighted, setHighlighted] = useState(false);\n  const state = useMemo(\n    () => ({ checked, disabled, highlighted }),\n    [checked, disabled, highlighted]\n  );\n  const indicatorValue = useMemo(() => ({ checked, disabled }), [checked, disabled]);\n\n  const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n    if (disabled) {\n      event.preventDefault();\n      return;\n    }\n    onClick?.(event);\n    if (event.defaultPrevented) {\n      return;\n    }\n    const next = !checked;\n    const details = createItemChangeDetails(event.nativeEvent);\n    onCheckedChange?.(next, details);\n    if (details.isCanceled) {\n      return;\n    }\n    if (!controlled) {\n      setInternalChecked(next);\n    }\n    onSelect?.();\n    if (closeOnClick) {\n      root.requestOpen(false, \"item-press\", event.nativeEvent, event.currentTarget);\n    }\n  };\n\n  return (\n    <MenuCheckboxItemContext value={indicatorValue}>\n      {renderHeidiElement({\n        className: MENU_CLASSES.checkboxItem,\n        dataPart: \"menu-checkbox-item\",\n        element: \"div\",\n        props: {\n          ...nativeProps,\n          onKeyUp: disabled ? undefined : nativeProps.onKeyUp,\n          onMouseDown: disabled ? undefined : nativeProps.onMouseDown,\n          onPointerDown: disabled ? undefined : nativeProps.onPointerDown,\n          ...ariaDisabledAttrs(disabled),\n          ...checkedStateAttributes(checked),\n          \"aria-checked\": checked,\n          children,\n          \"data-highlighted\": highlighted ? \"true\" : undefined,\n          \"data-label\": label,\n          \"data-checked-state\": checked ? \"checked\" : \"unchecked\",\n          onBlur: composeHeidiEventHandlers(onBlur, () => setHighlighted(false)),\n          onClick: handleClick,\n          onFocus: composeHeidiEventHandlers(onFocus, () => setHighlighted(true)),\n          onKeyDown: composeHeidiEventHandlers(\n            disabled ? undefined : onKeyDown,\n            (event: KeyboardEvent<HTMLDivElement>) => {\n              if (nativeButton || disabled || event.target !== event.currentTarget) {\n                return;\n              }\n              if ((event.key === \" \" || event.key === \"Enter\") && !event.repeat) {\n                event.preventDefault();\n                event.currentTarget.click();\n              }\n            }\n          ),\n          onMouseUp: composeHeidiEventHandlers(\n            onMouseUp,\n            (event: MouseEvent<HTMLDivElement>) => {\n              if (\n                !disabled &&\n                event.button === 0 &&\n                root.mouseUpSelectionAllowedRef.current\n              ) {\n                dispatchMouseGestureClick(event.currentTarget, event);\n              }\n            }\n          ),\n          onPointerMove: composeHeidiEventHandlers(\n            onPointerMove,\n            (event: PointerEvent<HTMLDivElement>) => {\n              if (root.disabled) {\n                return;\n              }\n              const menu = event.currentTarget.closest('[role=\"menu\"]');\n              const pointerGraceActive = root.isSubmenuPointerGraceActive();\n              if (menu instanceof HTMLElement && !pointerGraceActive) {\n                root.scheduleSubmenuItemHoverClose(\n                  menu,\n                  event.nativeEvent,\n                  event.currentTarget\n                );\n              }\n              if (\n                !pointerGraceActive &&\n                root.highlightItemOnHover &&\n                event.pointerType === \"mouse\"\n              ) {\n                event.currentTarget.focus({ preventScroll: true });\n              }\n            }\n          ),\n          ref,\n          role: \"menuitemcheckbox\",\n          tabIndex: -1,\n          type: nativeButton ? \"button\" : undefined\n        },\n        renderProps: { className, render, style },\n        state,\n        suppressRenderedHandlers: disabled ? DISABLED_MENU_PRESS_HANDLERS : undefined\n      })}\n    </MenuCheckboxItemContext>\n  );\n}\n\nexport type MenuCheckboxItemIndicatorState = { checked: boolean; disabled: boolean };\nexport type MenuCheckboxItemIndicatorProps = HeidiIntrinsicHostProps<\n  MenuCheckboxItemIndicatorState,\n  \"span\"\n> &\n  NativeHostProps<\"span\"> & {\n    children?: ReactNode;\n    keepMounted?: boolean;\n    ref?: Ref<HTMLSpanElement>;\n  };\n\nexport function MenuCheckboxItemIndicator({\n  children,\n  className,\n  keepMounted = false,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuCheckboxItemIndicatorProps) {\n  const context = useContext(MenuCheckboxItemContext);\n  if (!context) {\n    throw new Error(\"Menu.CheckboxItemIndicator must be inside Menu.CheckboxItem.\");\n  }\n  if (!keepMounted && !context.checked) {\n    return null;\n  }\n  const state = context;\n  return renderHeidiElement({\n    className: MENU_CLASSES.checkboxItemIndicator,\n    dataPart: \"menu-checkbox-item-indicator\",\n    element: \"span\",\n    props: {\n      ...nativeProps,\n      ...checkedStateAttributes(context.checked),\n      \"aria-hidden\": true,\n      children,\n      \"data-checked-state\": context.checked ? \"checked\" : \"unchecked\",\n      \"data-default-indicator\": children == null ? \"\" : undefined,\n      ref\n    },\n    renderProps: { className, render, style },\n    state\n  });\n}\n\nexport type MenuRadioGroupState = { disabled: boolean; labelled: boolean };\nexport type MenuRadioGroupProps = HeidiIntrinsicHostProps<\n  MenuRadioGroupState,\n  \"div\"\n> &\n  Omit<NativeHostProps<\"div\">, \"aria-disabled\" | \"aria-labelledby\" | \"role\"> & {\n    children?: ReactNode;\n    defaultValue?: string;\n    disabled?: boolean;\n    onValueChange?: (value: string, details: MenuItemChangeEventDetails) => void;\n    ref?: Ref<HTMLDivElement>;\n    value?: string;\n  };\n\nexport function MenuRadioGroup({\n  children,\n  className,\n  defaultValue,\n  disabled: disabledProp = false,\n  onValueChange,\n  ref,\n  render,\n  style,\n  value: valueProp,\n  ...nativeProps\n}: MenuRadioGroupProps) {\n  const root = useMenuContext(\"RadioGroup\");\n  const disabled = disabledProp || root.disabled;\n  const labelId = `hui-menu-radio-label-${toSafeId(useId())}`;\n  const [internalValue, setInternalValue] = useState(defaultValue);\n  const [labelled, setLabelled] = useState(false);\n  const controlled = valueProp !== undefined;\n  const value = valueProp ?? internalValue;\n  const registerLabel = useCallback((present: boolean) => setLabelled(present), []);\n  const requestValue = useCallback(\n    (next: string, event: Event) => {\n      if (disabled || next === value) {\n        return null;\n      }\n      const details = createItemChangeDetails(event);\n      onValueChange?.(next, details);\n      if (!details.isCanceled && !controlled) {\n        setInternalValue(next);\n      }\n      return details;\n    },\n    [controlled, disabled, onValueChange, value]\n  );\n  const groupValue = useMemo(\n    () => ({ disabled, requestValue, value }),\n    [disabled, requestValue, value]\n  );\n  const labelValue = useMemo(\n    () => ({ labelId, registerLabel }),\n    [labelId, registerLabel]\n  );\n  const state = { disabled, labelled };\n\n  return (\n    <MenuRadioGroupContext value={groupValue}>\n      <MenuGroupLabelContext value={labelValue}>\n        {renderHeidiElement({\n          className: MENU_CLASSES.radioGroup,\n          dataPart: \"menu-radio-group\",\n          element: \"div\",\n          props: {\n            ...nativeProps,\n            ...ariaDisabledAttrs(disabled),\n            \"aria-labelledby\": labelled ? labelId : undefined,\n            children,\n            ref,\n            role: \"group\"\n          },\n          renderProps: { className, render, style },\n          state\n        })}\n      </MenuGroupLabelContext>\n    </MenuRadioGroupContext>\n  );\n}\n\nexport type MenuRadioItemState = MenuItemState & { checked: boolean };\ntype MenuRadioItemNativeProps = Omit<MenuItemNativeProps, \"aria-checked\" | \"role\">;\nexport type MenuRadioItemProps = HeidiIntrinsicHostProps<MenuRadioItemState, \"div\"> &\n  MenuRadioItemNativeProps & {\n    children?: ReactNode;\n    closeOnClick?: boolean;\n    disabled?: boolean;\n    label?: string;\n    nativeButton?: boolean;\n    onBlur?: ComponentPropsWithoutRef<\"div\">[\"onBlur\"];\n    onClick?: ComponentPropsWithoutRef<\"div\">[\"onClick\"];\n    onFocus?: ComponentPropsWithoutRef<\"div\">[\"onFocus\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onMouseUp?: ComponentPropsWithoutRef<\"div\">[\"onMouseUp\"];\n    onPointerMove?: ComponentPropsWithoutRef<\"div\">[\"onPointerMove\"];\n    onSelect?: () => void;\n    ref?: Ref<HTMLDivElement>;\n    value: string;\n  };\n\nexport function MenuRadioItem({\n  children,\n  className,\n  closeOnClick = false,\n  disabled: disabledProp = false,\n  label,\n  nativeButton = false,\n  onBlur,\n  onClick,\n  onFocus,\n  onKeyDown,\n  onMouseUp,\n  onPointerMove,\n  onSelect,\n  ref,\n  render,\n  style,\n  value,\n  ...nativeProps\n}: MenuRadioItemProps) {\n  const root = useMenuContext(\"RadioItem\");\n  const group = useContext(MenuRadioGroupContext);\n  if (!group) {\n    throw new Error(\"Menu.RadioItem must be rendered inside Menu.RadioGroup.\");\n  }\n  const disabled = disabledProp || group.disabled;\n  const checked = group.value === value;\n  const [highlighted, setHighlighted] = useState(false);\n  const state = useMemo(\n    () => ({ checked, disabled, highlighted }),\n    [checked, disabled, highlighted]\n  );\n  const indicatorValue = useMemo(() => ({ checked, disabled }), [checked, disabled]);\n\n  const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n    if (disabled) {\n      event.preventDefault();\n      return;\n    }\n    onClick?.(event);\n    if (event.defaultPrevented) {\n      return;\n    }\n    const details = group.requestValue(value, event.nativeEvent);\n    if (details?.isCanceled) {\n      return;\n    }\n    onSelect?.();\n    if (closeOnClick) {\n      root.requestOpen(false, \"item-press\", event.nativeEvent, event.currentTarget);\n    }\n  };\n\n  return (\n    <MenuRadioItemContext value={indicatorValue}>\n      {renderHeidiElement({\n        className: MENU_CLASSES.radioItem,\n        dataPart: \"menu-radio-item\",\n        element: \"div\",\n        props: {\n          ...nativeProps,\n          onKeyUp: disabled ? undefined : nativeProps.onKeyUp,\n          onMouseDown: disabled ? undefined : nativeProps.onMouseDown,\n          onPointerDown: disabled ? undefined : nativeProps.onPointerDown,\n          ...ariaDisabledAttrs(disabled),\n          ...checkedStateAttributes(checked),\n          \"aria-checked\": checked,\n          children,\n          \"data-highlighted\": highlighted ? \"true\" : undefined,\n          \"data-label\": label,\n          \"data-checked-state\": checked ? \"checked\" : \"unchecked\",\n          onBlur: composeHeidiEventHandlers(onBlur, () => setHighlighted(false)),\n          onClick: handleClick,\n          onFocus: composeHeidiEventHandlers(onFocus, () => setHighlighted(true)),\n          onKeyDown: composeHeidiEventHandlers(\n            disabled ? undefined : onKeyDown,\n            (event: KeyboardEvent<HTMLDivElement>) => {\n              if (nativeButton || disabled || event.target !== event.currentTarget) {\n                return;\n              }\n              if ((event.key === \" \" || event.key === \"Enter\") && !event.repeat) {\n                event.preventDefault();\n                event.currentTarget.click();\n              }\n            }\n          ),\n          onMouseUp: composeHeidiEventHandlers(\n            onMouseUp,\n            (event: MouseEvent<HTMLDivElement>) => {\n              if (\n                !disabled &&\n                event.button === 0 &&\n                root.mouseUpSelectionAllowedRef.current\n              ) {\n                dispatchMouseGestureClick(event.currentTarget, event);\n              }\n            }\n          ),\n          onPointerMove: composeHeidiEventHandlers(\n            onPointerMove,\n            (event: PointerEvent<HTMLDivElement>) => {\n              if (root.disabled) {\n                return;\n              }\n              const menu = event.currentTarget.closest('[role=\"menu\"]');\n              const pointerGraceActive = root.isSubmenuPointerGraceActive();\n              if (menu instanceof HTMLElement && !pointerGraceActive) {\n                root.scheduleSubmenuItemHoverClose(\n                  menu,\n                  event.nativeEvent,\n                  event.currentTarget\n                );\n              }\n              if (\n                !pointerGraceActive &&\n                root.highlightItemOnHover &&\n                event.pointerType === \"mouse\"\n              ) {\n                event.currentTarget.focus({ preventScroll: true });\n              }\n            }\n          ),\n          ref,\n          role: \"menuitemradio\",\n          tabIndex: -1,\n          type: nativeButton ? \"button\" : undefined\n        },\n        renderProps: { className, render, style },\n        state,\n        suppressRenderedHandlers: disabled ? DISABLED_MENU_PRESS_HANDLERS : undefined\n      })}\n    </MenuRadioItemContext>\n  );\n}\n\nexport type MenuRadioItemIndicatorState = { checked: boolean; disabled: boolean };\nexport type MenuRadioItemIndicatorProps = HeidiIntrinsicHostProps<\n  MenuRadioItemIndicatorState,\n  \"span\"\n> &\n  NativeHostProps<\"span\"> & {\n    children?: ReactNode;\n    keepMounted?: boolean;\n    ref?: Ref<HTMLSpanElement>;\n  };\n\nexport function MenuRadioItemIndicator({\n  children,\n  className,\n  keepMounted = false,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuRadioItemIndicatorProps) {\n  const context = useContext(MenuRadioItemContext);\n  if (!context) {\n    throw new Error(\"Menu.RadioItemIndicator must be inside Menu.RadioItem.\");\n  }\n  if (!keepMounted && !context.checked) {\n    return null;\n  }\n  return renderHeidiElement({\n    className: MENU_CLASSES.radioItemIndicator,\n    dataPart: \"menu-radio-item-indicator\",\n    element: \"span\",\n    props: {\n      ...nativeProps,\n      ...checkedStateAttributes(context.checked),\n      \"aria-hidden\": true,\n      children,\n      \"data-checked-state\": context.checked ? \"checked\" : \"unchecked\",\n      \"data-default-indicator\": children == null ? \"\" : undefined,\n      ref\n    },\n    renderProps: { className, render, style },\n    state: context\n  });\n}\n\nexport type MenuSubProps = {\n  children?: ReactNode;\n  defaultOpen?: boolean;\n  onOpenChange?: (open: boolean, details: MenuRootChangeEventDetails) => void;\n  open?: boolean;\n};\n\nexport function MenuSub({\n  children,\n  defaultOpen = false,\n  onOpenChange,\n  open: openProp\n}: MenuSubProps) {\n  const root = useMenuContext(\"SubmenuRoot\");\n  const isWithinParentZone = useContext(MenuDismissLayerContext);\n  const parentEffectiveOpen = useMenuOpen();\n  const safeId = toSafeId(useId());\n  const [internalOpen, setInternalOpen] = useState(defaultOpen);\n  const controlled = openProp !== undefined;\n  const open = openProp ?? internalOpen;\n  const effectiveOpen = parentEffectiveOpen && open;\n  const openRef = useRef(open);\n  openRef.current = open;\n  const effectiveOpenRef = useRef(effectiveOpen);\n  effectiveOpenRef.current = effectiveOpen;\n  const parentEffectiveOpenRef = useRef(parentEffectiveOpen);\n  parentEffectiveOpenRef.current = parentEffectiveOpen;\n  const pendingAcceptedOpenRef = useRef<boolean | null>(null);\n  const pendingRenderedCloseRef = useRef(0);\n  const previousEffectiveOpenRef = useRef(effectiveOpen);\n  const announcedEffectiveOpenRef = useRef(false);\n  const focusOnOpenRef = useRef(false);\n  const triggerRef = useRef<HTMLElement | null>(null);\n  const contentRef = useRef<HTMLElement | null>(null);\n  const openTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const pendingOpenTriggerRef = useRef<HTMLElement | null>(null);\n  const closeTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null);\n  const pendingPointerCloseRef = useRef<{\n    event: globalThis.PointerEvent;\n    reason: MenuRootChangeEventReason;\n    source: HTMLElement;\n  } | null>(null);\n  const graceCleanupRef = useRef<(() => void) | null>(null);\n  const pointerHoverEnabledRef = useRef(true);\n  const pointerCloseDelayRef = useRef(root.submenuCloseDelay);\n  const closeForMissingSubTriggerRef = useRef<(trigger: HTMLElement) => void>(\n    () => undefined\n  );\n\n  const getOpen = useCallback(() => openRef.current, []);\n  const getEffectiveOpen = useCallback(() => effectiveOpenRef.current, []);\n  const getParentEffectiveOpen = useCallback(\n    () => parentEffectiveOpenRef.current,\n    []\n  );\n  const setTriggerElement = useCallback((element: HTMLElement | null) => {\n    const previous = triggerRef.current;\n    if (!element && pendingOpenTriggerRef.current === previous) {\n      queueMicrotask(() => {\n        if (\n          triggerRef.current === previous ||\n          pendingOpenTriggerRef.current !== previous\n        ) {\n          return;\n        }\n        if (openTimerRef.current !== null) {\n          clearTimeout(openTimerRef.current);\n          openTimerRef.current = null;\n        }\n        pendingOpenTriggerRef.current = null;\n      });\n    }\n    triggerRef.current = element;\n    if (!element && previous && openRef.current) {\n      queueMicrotask(() => {\n        if (triggerRef.current === null && openRef.current) {\n          closeForMissingSubTriggerRef.current(previous);\n        }\n      });\n    }\n  }, []);\n  const setContentElement = useCallback((element: HTMLElement | null) => {\n    contentRef.current = element;\n  }, []);\n  const getOwnerDocument = useCallback(\n    () =>\n      contentRef.current?.ownerDocument ??\n      triggerRef.current?.ownerDocument ??\n      null,\n    []\n  );\n  const isWithinDismissZone = useCallback((target: EventTarget | null) => {\n    if (!(target instanceof Node)) {\n      return false;\n    }\n    return Boolean(\n      contentRef.current?.contains(target) || triggerRef.current?.contains(target)\n    );\n  }, []);\n  const setPointerConfig = useCallback((enabled: boolean, closeDelay: number) => {\n    pointerHoverEnabledRef.current = enabled;\n    pointerCloseDelayRef.current = finiteDelay(closeDelay);\n  }, []);\n  const cancelPointerTimers = useCallback(() => {\n    if (openTimerRef.current !== null) {\n      clearTimeout(openTimerRef.current);\n      openTimerRef.current = null;\n    }\n    pendingOpenTriggerRef.current = null;\n    if (closeTimerRef.current !== null) {\n      clearTimeout(closeTimerRef.current);\n      closeTimerRef.current = null;\n    }\n    pendingPointerCloseRef.current = null;\n    graceCleanupRef.current?.();\n    graceCleanupRef.current = null;\n    root.setSubmenuPointerGrace(safeId, false);\n  }, [root, safeId]);\n\n  useEffect(() => () => cancelPointerTimers(), [cancelPointerTimers]);\n\n  useEffect(() => {\n    if (parentEffectiveOpen) {\n      return;\n    }\n    cancelPointerTimers();\n  }, [cancelPointerTimers, parentEffectiveOpen]);\n\n  useEffect(() => {\n    if (root.disabled) {\n      cancelPointerTimers();\n    }\n  }, [cancelPointerTimers, root.disabled]);\n\n  const requestOpen = useCallback(\n    (\n      next: boolean,\n      reason: MenuRootChangeEventReason,\n      event: Event,\n      trigger?: Element,\n      focus = false,\n      structural = false\n    ) => {\n      const logicalOpen = pendingAcceptedOpenRef.current ?? openRef.current;\n      if ((!structural && root.disabled) || next === logicalOpen) {\n        return null;\n      }\n      const details = createRootChangeDetails(\n        reason,\n        event,\n        next || reason === \"sibling-open\"\n          ? trigger\n          : (triggerRef.current ?? trigger)\n      );\n      onOpenChange?.(next, details);\n      if (details.isCanceled) {\n        return details;\n      }\n      if (controlled) {\n        pendingAcceptedOpenRef.current = next;\n        queueMicrotask(() => {\n          if (pendingAcceptedOpenRef.current === next) {\n            pendingAcceptedOpenRef.current = null;\n          }\n        });\n      }\n      if (next) {\n        const parentMenu = triggerRef.current?.closest<HTMLElement>('[role=\"menu\"]');\n        if (parentMenu) {\n          root.closeMenuBranches(\n            parentMenu,\n            safeId,\n            \"sibling-open\",\n            event,\n            trigger ?? triggerRef.current ?? undefined\n          );\n        }\n        announcedEffectiveOpenRef.current = true;\n      } else {\n        const pendingClose = pendingRenderedCloseRef.current + 1;\n        pendingRenderedCloseRef.current = pendingClose;\n        queueMicrotask(() => {\n          if (pendingRenderedCloseRef.current === pendingClose) {\n            pendingRenderedCloseRef.current = 0;\n          }\n        });\n        if (contentRef.current) {\n          root.closeMenuBranches(\n            contentRef.current,\n            null,\n            reason,\n            event,\n            trigger\n          );\n        }\n      }\n      focusOnOpenRef.current = next && focus;\n      if (!controlled) {\n        openRef.current = next;\n        setInternalOpen(next);\n      }\n      return details;\n    },\n    [controlled, onOpenChange, root, safeId]\n  );\n\n  const requestRegisteredClose = useCallback(\n    (reason: MenuRootChangeEventReason, event: Event, trigger?: Element) =>\n      requestOpen(false, reason, event, trigger, false, true),\n    [requestOpen]\n  );\n\n  closeForMissingSubTriggerRef.current = (trigger) => {\n    requestOpen(\n      false,\n      \"none\",\n      new Event(\"trigger-unmount\"),\n      trigger,\n      false,\n      true\n    );\n  };\n\n  const requestDismiss = useCallback(\n    (\n      reason: \"escape-key\" | \"focus-out\" | \"outside-press\",\n      event: Event\n    ) => {\n      const pendingClose = pendingPointerCloseRef.current;\n      if (\n        reason === \"focus-out\" &&\n        closeTimerRef.current !== null &&\n        pendingClose &&\n        event.target instanceof Node &&\n        pendingClose.source.contains(event.target)\n      ) {\n        // Pointer highlighting may focus the hovered sibling immediately, but\n        // the submenu still owns its authored closeDelay deadline.\n        return null;\n      }\n      return requestOpen(false, reason, event, undefined, false);\n    },\n    [requestOpen]\n  );\n\n  useMenuManualDismiss({\n    contentRef,\n    getOwnerDocument,\n    isWithinParentZone: isWithinParentZone ?? undefined,\n    isWithinZone: isWithinDismissZone,\n    open: effectiveOpen,\n    requestClose: requestDismiss\n  });\n\n  useHeidiLayoutEffect(() => {\n    const previousEffectiveOpen = previousEffectiveOpenRef.current;\n    previousEffectiveOpenRef.current = effectiveOpen;\n    if (!previousEffectiveOpen || effectiveOpen) {\n      return;\n    }\n    if (pendingRenderedCloseRef.current !== 0) {\n      pendingRenderedCloseRef.current = 0;\n      return;\n    }\n    if (contentRef.current) {\n      root.closeMenuBranches(\n        contentRef.current,\n        null,\n        \"none\",\n        new Event(\"state-close\"),\n        triggerRef.current ?? undefined\n      );\n    }\n  }, [effectiveOpen, root]);\n\n  const schedulePointerOpen = useCallback(\n    (event: globalThis.PointerEvent, trigger: HTMLElement, delay: number) => {\n      if (event.pointerType !== \"mouse\" || !pointerHoverEnabledRef.current) {\n        return;\n      }\n      cancelPointerTimers();\n      const run = () => {\n        openTimerRef.current = null;\n        if (pendingOpenTriggerRef.current === trigger) {\n          pendingOpenTriggerRef.current = null;\n        }\n        if (!trigger.isConnected || triggerRef.current !== trigger) {\n          return;\n        }\n        requestOpen(true, \"trigger-hover\", event, trigger, false);\n      };\n      pendingOpenTriggerRef.current = trigger;\n      if (!Number.isFinite(delay) || delay <= 0) {\n        run();\n      } else {\n        openTimerRef.current = setTimeout(run, finiteDelay(delay));\n      }\n    },\n    [cancelPointerTimers, requestOpen]\n  );\n\n  const schedulePointerClose = useCallback(\n    (\n      event: globalThis.PointerEvent,\n      source: HTMLElement,\n      reason: MenuRootChangeEventReason = \"trigger-hover\"\n    ) => {\n      if (event.pointerType !== \"mouse\" || !pointerHoverEnabledRef.current) {\n        cancelPointerTimers();\n        return;\n      }\n      const content = contentRef.current;\n      const trigger = triggerRef.current;\n      const leavingOwnBranch = source === trigger || source === content;\n      if (closeTimerRef.current !== null && !leavingOwnBranch) {\n        // Item-hover events may repeat at pointer-frame frequency. Preserve the\n        // first deadline while updating the close semantics to the sibling.\n        pendingPointerCloseRef.current = { event, reason, source };\n        return;\n      }\n      cancelPointerTimers();\n      pendingPointerCloseRef.current = { event, reason, source };\n      const run = () => {\n        closeTimerRef.current = null;\n        root.setSubmenuPointerGrace(safeId, false);\n        const pending = pendingPointerCloseRef.current;\n        pendingPointerCloseRef.current = null;\n        if (pending) {\n          requestOpen(false, pending.reason, pending.event, pending.source);\n        }\n      };\n      const schedule = (minimumDelay = 0) => {\n        const delay = Math.max(pointerCloseDelayRef.current, minimumDelay);\n        if (!Number.isFinite(delay) || delay <= 0) {\n          run();\n        } else {\n          closeTimerRef.current = setTimeout(run, delay);\n        }\n      };\n\n      if (\n        openRef.current &&\n        content &&\n        trigger &&\n        (source === trigger || source === content)\n      ) {\n        const destination = source === trigger ? content : trigger;\n        const start = { x: event.clientX, y: event.clientY };\n        const rect = destination.getBoundingClientRect();\n        const [a, b] = pointerBridgeEdge(rect, start);\n        const ownerDocument = source.ownerDocument;\n        const handleMove = (moveEvent: globalThis.PointerEvent) => {\n          const target = moveEvent.target;\n          if (\n            target instanceof Node &&\n            (content.contains(target) || trigger.contains(target))\n          ) {\n            cancelPointerTimers();\n            return;\n          }\n          if (pointInTriangle({ x: moveEvent.clientX, y: moveEvent.clientY }, start, a, b)) {\n            return;\n          }\n          graceCleanupRef.current?.();\n          graceCleanupRef.current = null;\n          root.setSubmenuPointerGrace(safeId, false);\n          if (closeTimerRef.current !== null) {\n            clearTimeout(closeTimerRef.current);\n            closeTimerRef.current = null;\n          }\n          const siblingItem =\n            target instanceof Element\n              ? target.closest<HTMLElement>(\n                  '[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"]'\n                )\n              : null;\n          if (\n            siblingItem &&\n            siblingItem !== trigger &&\n            siblingItem.closest('[role=\"menu\"]') === trigger.closest('[role=\"menu\"]')\n          ) {\n            pendingPointerCloseRef.current = {\n              event: moveEvent,\n              reason: \"sibling-open\",\n              source: siblingItem\n            };\n          }\n          schedule(120);\n        };\n        ownerDocument.addEventListener(\"pointermove\", handleMove);\n        graceCleanupRef.current = () =>\n          ownerDocument.removeEventListener(\"pointermove\", handleMove);\n        root.setSubmenuPointerGrace(safeId, true);\n        schedule(400);\n        return;\n      }\n      schedule();\n    },\n    [cancelPointerTimers, requestOpen, root, safeId]\n  );\n\n  useHeidiLayoutEffect(() => {\n    root.registerSubmenu(safeId, {\n      getOpen,\n      requestClose: requestRegisteredClose,\n      schedulePointerClose,\n      triggerRef\n    });\n    if (!effectiveOpen) {\n      announcedEffectiveOpenRef.current = false;\n    } else if (!announcedEffectiveOpenRef.current) {\n      announcedEffectiveOpenRef.current = true;\n      const parentMenu = triggerRef.current?.closest<HTMLElement>('[role=\"menu\"]');\n      if (parentMenu) {\n        root.closeMenuBranches(\n          parentMenu,\n          safeId,\n          \"sibling-open\",\n          new Event(\"state-open\"),\n          triggerRef.current ?? undefined\n        );\n      }\n    }\n    return () => root.registerSubmenu(safeId, null);\n  }, [\n    getOpen,\n    effectiveOpen,\n    requestRegisteredClose,\n    root,\n    safeId,\n    schedulePointerClose\n  ]);\n\n  const focusOnOpen = useCallback(() => {\n    const focus = focusOnOpenRef.current;\n    focusOnOpenRef.current = false;\n    return focus;\n  }, []);\n\n  const value = useMemo<MenuSubContextValue>(\n    () => ({\n      anchorName: `--hui-menu-sub-anchor-${safeId}`,\n      cancelPointerTimers,\n      contentId: `hui-menu-sub-${safeId}`,\n      contentRef,\n      focusOnOpen,\n      getEffectiveOpen,\n      getOpen,\n      getParentEffectiveOpen,\n      requestOpen,\n      schedulePointerClose,\n      schedulePointerOpen,\n      setContentElement,\n      setPointerConfig,\n      setTriggerElement,\n      triggerId: `hui-menu-sub-trigger-${safeId}`,\n      triggerRef\n    }),\n    [\n      cancelPointerTimers,\n      focusOnOpen,\n      getEffectiveOpen,\n      getOpen,\n      getParentEffectiveOpen,\n      requestOpen,\n      safeId,\n      schedulePointerClose,\n      schedulePointerOpen,\n      setContentElement,\n      setPointerConfig,\n      setTriggerElement\n    ]\n  );\n\n  return (\n    <MenuDismissLayerContext value={isWithinDismissZone}>\n      <MenuSubContext value={value}>\n        <MenuOpenContext value={effectiveOpen}>\n          <MenuSubOpenContext value={open}>\n            {children}\n          </MenuSubOpenContext>\n        </MenuOpenContext>\n      </MenuSubContext>\n    </MenuDismissLayerContext>\n  );\n}\n\nexport const MenuSubmenuRoot = MenuSub;\nexport type MenuSubmenuRootProps = MenuSubProps;\n\nexport type MenuSubTriggerState = {\n  disabled: boolean;\n  highlighted: boolean;\n  open: boolean;\n};\n\ntype MenuSubTriggerNativeProps = Omit<\n  NativeHostProps<\"div\">,\n  | \"aria-controls\"\n  | \"aria-disabled\"\n  | \"aria-expanded\"\n  | \"aria-haspopup\"\n  | \"id\"\n  | \"onBlur\"\n  | \"onClick\"\n  | \"onFocus\"\n  | \"onKeyDown\"\n  | \"onPointerEnter\"\n  | \"onPointerLeave\"\n  | \"onPointerMove\"\n  | \"role\"\n  | \"tabIndex\"\n>;\n\nexport type MenuSubTriggerProps = HeidiIntrinsicHostProps<\n  MenuSubTriggerState,\n  \"div\"\n> &\n  MenuSubTriggerNativeProps & {\n    children?: ReactNode;\n    /** Delay before hover may open this submenu. Defaults to 100ms. */\n    delay?: number;\n    /** Delay before this hover-opened submenu closes. Defaults to 0ms. */\n    closeDelay?: number;\n    disabled?: boolean;\n    label?: string;\n    /** Set true when `render` returns a native button. */\n    nativeButton?: boolean;\n    onBlur?: ComponentPropsWithoutRef<\"div\">[\"onBlur\"];\n    onClick?: ComponentPropsWithoutRef<\"div\">[\"onClick\"];\n    onFocus?: ComponentPropsWithoutRef<\"div\">[\"onFocus\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onPointerEnter?: ComponentPropsWithoutRef<\"div\">[\"onPointerEnter\"];\n    onPointerLeave?: ComponentPropsWithoutRef<\"div\">[\"onPointerLeave\"];\n    onPointerMove?: ComponentPropsWithoutRef<\"div\">[\"onPointerMove\"];\n    /** Whether mouse hover opens this submenu. */\n    openOnHover?: boolean;\n    ref?: Ref<HTMLDivElement>;\n  };\n\nexport function MenuSubTrigger({\n  children,\n  className,\n  closeDelay: closeDelayProp,\n  delay: delayProp,\n  disabled: disabledProp = false,\n  label,\n  nativeButton = false,\n  onBlur,\n  onClick,\n  onFocus,\n  onKeyDown,\n  onPointerEnter,\n  onPointerLeave,\n  onPointerMove,\n  openOnHover = true,\n  ref,\n  render,\n  style,\n  ...nativeProps\n}: MenuSubTriggerProps) {\n  const root = useMenuContext(\"SubmenuTrigger\");\n  const sub = useMenuSubContext(\"SubmenuTrigger\");\n  const open = useContext(MenuSubOpenContext);\n  const disabled = disabledProp || root.disabled;\n  const delay = finiteDelay(delayProp ?? root.submenuOpenDelay);\n  const closeDelay = finiteDelay(closeDelayProp ?? root.submenuCloseDelay);\n  const [highlighted, setHighlighted] = useState(false);\n  const setTriggerRef = useCallback(\n    (element: HTMLDivElement | null) => sub.setTriggerElement(element),\n    [sub]\n  );\n  const state = useMemo(\n    () => ({ disabled, highlighted, open }),\n    [disabled, highlighted, open]\n  );\n\n  useEffect(() => {\n    sub.setPointerConfig(openOnHover, closeDelay);\n  }, [closeDelay, openOnHover, sub]);\n\n  const focusFirstSubmenuItem = useCallback(() => {\n    requestAnimationFrame(() => {\n      const content = sub.contentRef.current;\n      if (!sub.getOpen() || !content?.isConnected) {\n        return;\n      }\n      (initialMenuItem(content, \"first\") ?? content).focus({\n        preventScroll: true\n      });\n    });\n  }, [sub]);\n\n  const handleClick = (event: MouseEvent<HTMLDivElement>) => {\n    if (disabled) {\n      event.preventDefault();\n      return;\n    }\n    onClick?.(event);\n    if (event.defaultPrevented) {\n      return;\n    }\n    sub.cancelPointerTimers();\n    if (event.detail === 0 && sub.getOpen()) {\n      focusFirstSubmenuItem();\n      return;\n    }\n    sub.requestOpen(\n      openOnHover ? true : !sub.getOpen(),\n      \"trigger-press\",\n      event.nativeEvent,\n      event.currentTarget,\n      event.detail === 0\n    );\n  };\n\n  return renderHeidiElement({\n    className: MENU_CLASSES.subTrigger,\n    dataPart: \"menu-sub-trigger\",\n    element: \"div\",\n    props: {\n      ...nativeProps,\n      onKeyUp: disabled ? undefined : nativeProps.onKeyUp,\n      onMouseDown: disabled ? undefined : nativeProps.onMouseDown,\n      onPointerDown: disabled ? undefined : nativeProps.onPointerDown,\n      ...ariaDisabledAttrs(disabled),\n      \"aria-controls\": sub.contentId,\n      \"aria-expanded\": open,\n      \"aria-haspopup\": \"menu\",\n      children,\n      \"data-highlighted\": highlighted ? \"true\" : undefined,\n      \"data-label\": label,\n      \"data-popup-open\": open ? true : undefined,\n      \"data-state\": dataState(open),\n      id: sub.triggerId,\n      onBlur: composeHeidiEventHandlers(onBlur, () => setHighlighted(false)),\n      onClick: handleClick,\n      onFocus: composeHeidiEventHandlers(onFocus, () => setHighlighted(true)),\n      onKeyDown: composeHeidiEventHandlers(\n        disabled ? undefined : onKeyDown,\n        (event: KeyboardEvent<HTMLDivElement>) => {\n          if (disabled) {\n            return;\n          }\n          const openKey =\n            getComputedStyle(event.currentTarget).direction === \"rtl\"\n              ? \"ArrowLeft\"\n              : \"ArrowRight\";\n          const closeKey = openKey === \"ArrowLeft\" ? \"ArrowRight\" : \"ArrowLeft\";\n          if (\n            sub.getOpen() &&\n            (event.key === \"Escape\" || event.key === closeKey)\n          ) {\n            event.preventDefault();\n            event.stopPropagation();\n            sub.cancelPointerTimers();\n            // ponytail: React clears SyntheticEvent.currentTarget immediately\n            // after this listener returns. Capture the host before deferring\n            // focus beyond the native popover close.\n            const trigger = event.currentTarget;\n            const details = sub.requestOpen(\n              false,\n              event.key === \"Escape\" ? \"escape-key\" : \"none\",\n              event.nativeEvent,\n              trigger,\n              false\n            );\n            if (!details?.isCanceled) {\n              focusHeidiElementNextFrame(trigger);\n            }\n            return;\n          }\n          if (event.key === openKey) {\n            event.preventDefault();\n            event.stopPropagation();\n            sub.cancelPointerTimers();\n            if (sub.getOpen()) {\n              focusFirstSubmenuItem();\n              return;\n            }\n            sub.requestOpen(\n              true,\n              \"trigger-press\",\n              event.nativeEvent,\n              event.currentTarget,\n              true\n            );\n            return;\n          }\n          if (\n            !nativeButton &&\n            (event.key === \"Enter\" || event.key === \" \") &&\n            !event.repeat\n          ) {\n            event.preventDefault();\n            event.stopPropagation();\n            event.currentTarget.click();\n          }\n        }\n      ),\n      onPointerEnter: composeHeidiEventHandlers(\n        onPointerEnter,\n        (event: PointerEvent<HTMLDivElement>) => {\n          if (openOnHover && !disabled) {\n            sub.schedulePointerOpen(event.nativeEvent, event.currentTarget, delay);\n          }\n        }\n      ),\n      onPointerLeave: composeHeidiEventHandlers(\n        onPointerLeave,\n        (event: PointerEvent<HTMLDivElement>) => {\n          if (openOnHover && !disabled) {\n            sub.schedulePointerClose(event.nativeEvent, event.currentTarget);\n          }\n        }\n      ),\n      onPointerMove: composeHeidiEventHandlers(\n        onPointerMove,\n        (event: PointerEvent<HTMLDivElement>) => {\n          if (root.disabled) {\n            return;\n          }\n          if (\n            !root.isSubmenuPointerGraceActive() &&\n            root.highlightItemOnHover &&\n            event.pointerType === \"mouse\"\n          ) {\n            event.currentTarget.focus({ preventScroll: true });\n          }\n        }\n      ),\n      ref: mergeHeidiRefs(setTriggerRef, ref),\n      role: \"menuitem\",\n      tabIndex: -1,\n      type: nativeButton ? \"button\" : undefined\n    },\n    renderProps: { className, render, style },\n    state,\n    structuralStyle: { anchorName: sub.anchorName } as CSSProperties,\n    suppressRenderedHandlers: disabled ? DISABLED_MENU_PRESS_HANDLERS : undefined\n  });\n}\n\nexport const MenuSubmenuTrigger = MenuSubTrigger;\nexport type MenuSubmenuTriggerProps = MenuSubTriggerProps;\n\nexport type MenuSubContentState = {\n  align: MenuAlign;\n  open: boolean;\n  side: MenuSide;\n};\n\ntype MenuSubContentNativeProps = Omit<\n  NativeHostProps<\"div\">,\n  | \"aria-labelledby\"\n  | \"id\"\n  | \"onBeforeToggle\"\n  | \"onKeyDown\"\n  | \"onKeyDownCapture\"\n  | \"onPointerEnter\"\n  | \"onPointerLeave\"\n  | \"onToggle\"\n  | \"popover\"\n  | \"role\"\n  | \"tabIndex\"\n>;\n\nexport type MenuSubContentProps = HeidiIntrinsicHostProps<\n  MenuSubContentState,\n  \"div\"\n> &\n  MenuSubContentNativeProps & {\n    align?: MenuAlign;\n    /** Cross-axis offset in CSS pixels. */\n    alignOffset?: number;\n    children?: ReactNode;\n    keepMounted?: boolean;\n    onBeforeToggle?: ComponentPropsWithoutRef<\"div\">[\"onBeforeToggle\"];\n    onKeyDown?: ComponentPropsWithoutRef<\"div\">[\"onKeyDown\"];\n    onKeyDownCapture?: ComponentPropsWithoutRef<\"div\">[\"onKeyDownCapture\"];\n    onPointerEnter?: ComponentPropsWithoutRef<\"div\">[\"onPointerEnter\"];\n    onPointerLeave?: ComponentPropsWithoutRef<\"div\">[\"onPointerLeave\"];\n    onToggle?: (event: SyntheticEvent<HTMLDivElement>) => void;\n    ref?: Ref<HTMLDivElement>;\n    side?: MenuSide;\n    /** Main-axis gap in CSS pixels. */\n    sideOffset?: number;\n  };\n\nexport function MenuSubContent({\n  align = \"start\",\n  alignOffset = 0,\n  children,\n  className,\n  keepMounted = false,\n  onBeforeToggle,\n  onKeyDown,\n  onKeyDownCapture,\n  onPointerEnter,\n  onPointerLeave,\n  onToggle,\n  ref,\n  render,\n  side = \"inline-end\",\n  sideOffset = 4,\n  style,\n  ...nativeProps\n}: MenuSubContentProps) {\n  const root = useMenuContext(\"SubContent\");\n  const rootOpen = useMenuOpen();\n  const sub = useMenuSubContext(\"SubContent\");\n  const subOpen = useContext(MenuSubOpenContext);\n  const open = subOpen && rootOpen;\n  const localRef = useRef<HTMLDivElement | null>(null);\n  const internalNativeTransitionRef = useRef(false);\n  const lastBeforeToggleRef = useRef<{\n    internal: boolean;\n    open: boolean;\n  } | null>(null);\n  const typeaheadRef = useRef<TypeaheadState>({ buffer: \"\", timer: null });\n  const physicalSide = usePhysicalSide(side, localRef, open);\n  const getEffectiveOpen = useCallback(() => sub.getEffectiveOpen(), [sub]);\n  const { scheduleUnmount, shouldRender } = usePopoverPresence(\n    open,\n    keepMounted,\n    getEffectiveOpen\n  );\n  const setContentRef = useCallback(\n    (element: HTMLDivElement | null) => sub.setContentElement(element),\n    [sub]\n  );\n\n  const synchronizeNativeOpen = useCallback(\n    (element: HTMLDivElement, next: boolean) => {\n      synchronizeNativePopoverOpen(element, next, {\n        show: (target) => showPopoverFrom(target, sub.triggerRef.current),\n        transitionRef: internalNativeTransitionRef\n      });\n    },\n    [sub.triggerRef]\n  );\n\n  useEffect(() => {\n    resetTypeahead(typeaheadRef.current);\n  }, [open]);\n\n  useEffect(() => () => resetTypeahead(typeaheadRef.current), []);\n\n  useEffect(() => {\n    const element = localRef.current;\n    if (!element || typeof element.showPopover !== \"function\") {\n      return;\n    }\n    const nativeOpen = element.matches(\":popover-open\");\n    if (open && !nativeOpen) {\n      let timer: number | null = null;\n      const parentPopover = element.parentElement?.closest<HTMLElement>(\"[popover]\");\n      const show = () => {\n        if (sub.getEffectiveOpen() && element.isConnected) {\n          synchronizeNativeOpen(element, true);\n        }\n      };\n      const scheduleShow = () => {\n        timer = window.setTimeout(show, 0);\n      };\n      const handleParentToggle = (event: Event) => {\n        const toggle = event as Event & { newState?: string };\n        if (toggle.newState === \"open\") {\n          scheduleShow();\n        }\n      };\n      if (parentPopover && !parentPopover.matches(\":popover-open\")) {\n        parentPopover.addEventListener(\"toggle\", handleParentToggle);\n      } else {\n        scheduleShow();\n      }\n      return () => {\n        parentPopover?.removeEventListener(\"toggle\", handleParentToggle);\n        if (timer !== null) {\n          window.clearTimeout(timer);\n        }\n      };\n    }\n    if (!open && nativeOpen) {\n      closeDescendantSubmenus(element);\n      synchronizeNativeOpen(element, false);\n    }\n    if (!open && !nativeOpen) {\n      scheduleUnmount(element);\n    }\n    return undefined;\n  }, [open, root, scheduleUnmount, sub, synchronizeNativeOpen]);\n\n  if (!shouldRender) {\n    return null;\n  }\n\n  const handleBeforeToggle = (event: ToggleEvent<HTMLDivElement>) => {\n    if (event.target !== event.currentTarget) {\n      return;\n    }\n    const nativeToggle = event.nativeEvent as Event & { newState?: string };\n    const internal = internalNativeTransitionRef.current;\n    internalNativeTransitionRef.current = false;\n    lastBeforeToggleRef.current = {\n      internal,\n      open: nativeToggle.newState === \"open\"\n    };\n    onBeforeToggle?.(event);\n    if (internal && event.defaultPrevented) {\n      lastBeforeToggleRef.current = null;\n      const fallbackOpen = nativeToggle.newState !== \"open\";\n      if (sub.getParentEffectiveOpen() && fallbackOpen !== sub.getOpen()) {\n        sub.requestOpen(\n          fallbackOpen,\n          \"none\",\n          nativeToggle,\n          sub.triggerRef.current ?? undefined,\n          false\n        );\n      }\n    }\n  };\n\n  const handleToggle = (event: SyntheticEvent<HTMLDivElement>) => {\n    if (event.target !== event.currentTarget) {\n      return;\n    }\n    // Native toggle events cannot be canceled. Keep the consumer callback\n    // observational even when React marks its SyntheticEvent as prevented.\n    onToggle?.(event);\n    const element = event.currentTarget;\n    const nativeToggle = event.nativeEvent as Event & { newState?: string };\n    const nativeOpen = nativeToggle.newState === \"open\";\n    const expectedNativeOpen = sub.getEffectiveOpen();\n    const transition = lastBeforeToggleRef.current;\n    lastBeforeToggleRef.current = null;\n    const internallySynchronized =\n      transition?.internal === true && transition.open === nativeOpen;\n    if (\n      !internallySynchronized &&\n      sub.getParentEffectiveOpen() &&\n      nativeOpen !== sub.getOpen()\n    ) {\n      sub.requestOpen(\n        nativeOpen,\n        nativeOpen ? \"trigger-press\" : \"outside-press\",\n        nativeToggle,\n        sub.triggerRef.current ?? undefined,\n        false\n      );\n    }\n    if (nativeOpen !== expectedNativeOpen) {\n      requestAnimationFrame(() => {\n        if (element.isConnected) {\n          synchronizeNativeOpen(element, sub.getEffectiveOpen());\n        }\n      });\n    }\n    if (nativeOpen && expectedNativeOpen && sub.focusOnOpen()) {\n      queueMicrotask(() => {\n        (initialMenuItem(element, \"first\") ?? element).focus({\n          preventScroll: true\n        });\n      });\n    }\n    if (!nativeOpen && !expectedNativeOpen) {\n      closeDescendantSubmenus(element);\n      sub.cancelPointerTimers();\n      scheduleUnmount(element);\n    }\n  };\n\n  const handleKeyDown = composeHeidiEventHandlers(\n    onKeyDown,\n    (event: KeyboardEvent<HTMLDivElement>) => {\n      if (!menuOwnsKeyboardTarget(event.currentTarget, event.target)) {\n        return;\n      }\n      if (root.disabled) {\n        return;\n      }\n      const closeKey =\n        getComputedStyle(event.currentTarget).direction === \"rtl\"\n          ? \"ArrowRight\"\n          : \"ArrowLeft\";\n      if (event.key === closeKey || event.key === \"Escape\") {\n        event.preventDefault();\n        event.stopPropagation();\n        const details = sub.requestOpen(\n          false,\n          \"escape-key\",\n          event.nativeEvent,\n          event.currentTarget\n        );\n        if (!details?.isCanceled) {\n          requestAnimationFrame(() => {\n            sub.triggerRef.current?.focus({ preventScroll: true });\n          });\n        }\n        return;\n      }\n      if (event.key === \"Tab\") {\n        if (event.shiftKey) {\n          const details = sub.requestOpen(\n            false,\n            \"focus-out\",\n            event.nativeEvent,\n            event.currentTarget\n          );\n          event.preventDefault();\n          if (details && !details.isCanceled) {\n            requestAnimationFrame(() => {\n              sub.triggerRef.current?.focus({ preventScroll: true });\n            });\n          }\n          return;\n        }\n        const target = tabTargetAfterTrigger(root.triggerRef.current);\n        const details = root.requestOpen(\n          false,\n          \"focus-out\",\n          event.nativeEvent,\n          event.currentTarget\n        );\n        if (!details || details.isCanceled) {\n          event.preventDefault();\n          return;\n        }\n        if (target) {\n          event.preventDefault();\n          requestAnimationFrame(() => target.focus({ preventScroll: true }));\n        }\n        return;\n      }\n      if (\n        event.key === \"ArrowDown\" ||\n        event.key === \"ArrowUp\" ||\n        event.key === \"End\" ||\n        event.key === \"Home\"\n      ) {\n        event.preventDefault();\n        moveMenuFocus(event.currentTarget, event.key, root.loopFocus, () => {\n          root.closeMenuBranches(\n            event.currentTarget,\n            null,\n            \"none\",\n            event.nativeEvent,\n            event.currentTarget\n          );\n        });\n        return;\n      }\n      if (\n        event.key.length === 1 &&\n        event.key !== \" \" &&\n        !event.nativeEvent.isComposing &&\n        !event.altKey &&\n        !event.ctrlKey &&\n        !event.metaKey\n      ) {\n        runTypeahead(event.currentTarget, event.key, typeaheadRef.current);\n      }\n    }\n  );\n\n  const state = { align, open, side };\n  const ariaLabel = nativeProps[\"aria-label\"];\n  return renderHeidiElement({\n    className: MENU_CLASSES.subContent,\n    dataPart: \"menu-sub-content\",\n    element: \"div\",\n    props: {\n      ...nativeProps,\n      ...openStateAttributes(open),\n      \"aria-labelledby\": ariaLabel ? undefined : sub.triggerId,\n      children,\n      \"data-align\": align,\n      \"data-position-side\": physicalSide,\n      \"data-side\": side,\n      \"data-state\": dataState(open),\n      id: sub.contentId,\n      onBeforeToggle: handleBeforeToggle,\n      onKeyDown: handleKeyDown,\n      onKeyDownCapture: composeHeidiEventHandlers(\n        onKeyDownCapture,\n        (event: KeyboardEvent<HTMLDivElement>) => {\n          if (\n            !root.disabled &&\n            menuOwnsKeyboardTarget(event.currentTarget, event.target)\n          ) {\n            extendActiveTypeaheadWithSpace(event, typeaheadRef.current);\n          }\n        }\n      ),\n      onPointerEnter: composeHeidiEventHandlers(onPointerEnter, sub.cancelPointerTimers),\n      onPointerLeave: composeHeidiEventHandlers(\n        onPointerLeave,\n        (event: PointerEvent<HTMLDivElement>) => {\n          sub.schedulePointerClose(event.nativeEvent, event.currentTarget);\n        }\n      ),\n      onToggle: handleToggle,\n      popover: \"manual\",\n      ref: mergeHeidiRefs(localRef, setContentRef, ref),\n      role: \"menu\",\n      tabIndex: -1\n    },\n    renderProps: { className, render, style },\n    state,\n    structuralStyle: {\n      \"--_hui-menu-align-offset\": `${alignOffset}px`,\n      \"--_hui-menu-side-offset\": `${Math.max(0, sideOffset)}px`,\n      positionAnchor: sub.anchorName\n    } as CSSProperties\n  });\n}\n\nexport const MenuSubmenuContent = MenuSubContent;\nexport type MenuSubmenuContentProps = MenuSubContentProps;\n\n/**\n * Namespace sugar for client components (`<Menu.Root>`). Named exports remain\n * canonical when crossing a Server Component boundary.\n */\nexport const Menu = {\n  CheckboxItem: MenuCheckboxItem,\n  CheckboxItemIndicator: MenuCheckboxItemIndicator,\n  Content: MenuContent,\n  Group: MenuGroup,\n  GroupLabel: MenuGroupLabel,\n  Item: MenuItem,\n  LinkItem: MenuLinkItem,\n  Popup: MenuPopup,\n  RadioGroup: MenuRadioGroup,\n  RadioItem: MenuRadioItem,\n  RadioItemIndicator: MenuRadioItemIndicator,\n  Root: MenuRoot,\n  Separator: MenuSeparator,\n  Sub: MenuSub,\n  SubContent: MenuSubContent,\n  SubTrigger: MenuSubTrigger,\n  SubmenuContent: MenuSubmenuContent,\n  SubmenuRoot: MenuSubmenuRoot,\n  SubmenuTrigger: MenuSubmenuTrigger,\n  Trigger: MenuTrigger\n} as const;\n",
      "path": "packages/heidi-ui/src/menu/menu.tsx",
      "target": "components/ui/heidi/menu/menu.tsx",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui menu — STRUCTURAL CSS only (platform behavior).\n * Native top layer + CSS anchors, viewport containment, and APG item geometry.\n * No --hui-* / --heidi-* theme tokens.\n */\n\n@layer heidi-ui-base {\n  .hui-menu-content:is(\n    [data-side=\"bottom\"],\n    [data-side=\"inline-end\"],\n    [data-side=\"inline-start\"],\n    [data-side=\"left\"],\n    [data-side=\"right\"],\n    [data-side=\"top\"]\n  ),\n  .hui-menu-sub-content:is(\n    [data-side=\"bottom\"],\n    [data-side=\"inline-end\"],\n    [data-side=\"inline-start\"],\n    [data-side=\"left\"],\n    [data-side=\"right\"],\n    [data-side=\"top\"]\n  ) {\n    --_hui-menu-align-offset: 0px;\n    --_hui-menu-side-offset: 4px;\n    --_hui-menu-viewport-shift-x: 0px;\n    --_hui-menu-viewport-shift-y: 0px;\n\n    box-sizing: border-box;\n    flex-direction: column;\n    /* Undo the UA's centered popover styles so anchor positioning takes over. */\n    inset: auto;\n    /* main-axis gap between anchor and menu; sideOffset writes this var */\n    margin: var(--_hui-menu-side-offset);\n    max-block-size: calc(100dvb - 1rem);\n    max-inline-size: calc(100dvi - 1rem);\n    min-inline-size: 0;\n    overflow: auto;\n    overscroll-behavior: contain;\n    position: fixed;\n    position-try-fallbacks: flip-block, flip-inline, flip-block flip-inline;\n    scrollbar-gutter: stable;\n    transition-behavior: allow-discrete;\n    transition-property: display, overlay;\n  }\n\n  /* Author layout classes must never override the UA's closed-popover state. */\n  .hui-menu-content:not(:popover-open),\n  .hui-menu-sub-content:not(:popover-open) {\n    display: none !important;\n  }\n\n  .hui-menu-content:popover-open,\n  .hui-menu-sub-content:popover-open {\n    display: flex;\n  }\n\n  .hui-menu-content[data-state=\"closed\"],\n  .hui-menu-sub-content[data-state=\"closed\"] {\n    pointer-events: none;\n  }\n\n  .hui-menu-content[data-state=\"open\"],\n  .hui-menu-sub-content[data-state=\"open\"] {\n    pointer-events: auto;\n  }\n\n  /* Cross-axis nudge (alignOffset) runs along the side's perpendicular axis.\n     ponytail: `translate`, not `transform`. menu.theme.css animates the panel\n     with `transform: scale(.97)`; folding the nudge into that shorthand would\n     have made the theme's open-state `transform: none` erase alignOffset the\n     moment the panel finished opening. The individual transform properties\n     compose (translate, then rotate, then scale, then transform), so the two\n     stay independent. */\n  .hui-menu-content[data-position-side=\"top\"],\n  .hui-menu-content[data-position-side=\"bottom\"],\n  .hui-menu-sub-content[data-position-side=\"top\"],\n  .hui-menu-sub-content[data-position-side=\"bottom\"] {\n    translate:\n      calc(var(--_hui-menu-align-offset) + var(--_hui-menu-viewport-shift-x))\n      var(--_hui-menu-viewport-shift-y);\n  }\n\n  .hui-menu-content[data-position-side=\"left\"],\n  .hui-menu-content[data-position-side=\"right\"],\n  .hui-menu-sub-content[data-position-side=\"left\"],\n  .hui-menu-sub-content[data-position-side=\"right\"] {\n    translate:\n      var(--_hui-menu-viewport-shift-x)\n      calc(var(--_hui-menu-align-offset) + var(--_hui-menu-viewport-shift-y));\n  }\n\n  /*\n   * Physical side × logical align. `data-side` remains the public API value;\n   * runtime direction resolution writes `data-position-side` for placement.\n   */\n  .hui-menu-content[data-position-side=\"top\"][data-align=\"start\"],\n  .hui-menu-sub-content[data-position-side=\"top\"][data-align=\"start\"] {\n    position-area: block-start span-inline-end;\n  }\n\n  .hui-menu-content[data-position-side=\"top\"][data-align=\"center\"],\n  .hui-menu-sub-content[data-position-side=\"top\"][data-align=\"center\"] {\n    position-area: block-start;\n  }\n\n  .hui-menu-content[data-position-side=\"top\"][data-align=\"end\"],\n  .hui-menu-sub-content[data-position-side=\"top\"][data-align=\"end\"] {\n    position-area: block-start span-inline-start;\n  }\n\n  .hui-menu-content[data-position-side=\"bottom\"][data-align=\"start\"],\n  .hui-menu-sub-content[data-position-side=\"bottom\"][data-align=\"start\"] {\n    position-area: block-end span-inline-end;\n  }\n\n  .hui-menu-content[data-position-side=\"bottom\"][data-align=\"center\"],\n  .hui-menu-sub-content[data-position-side=\"bottom\"][data-align=\"center\"] {\n    position-area: block-end;\n  }\n\n  .hui-menu-content[data-position-side=\"bottom\"][data-align=\"end\"],\n  .hui-menu-sub-content[data-position-side=\"bottom\"][data-align=\"end\"] {\n    position-area: block-end span-inline-start;\n  }\n\n  .hui-menu-content[data-position-side=\"left\"][data-align=\"start\"],\n  .hui-menu-sub-content[data-position-side=\"left\"][data-align=\"start\"] {\n    position-area: left span-bottom;\n  }\n\n  .hui-menu-content[data-position-side=\"left\"][data-align=\"center\"],\n  .hui-menu-sub-content[data-position-side=\"left\"][data-align=\"center\"] {\n    position-area: left;\n  }\n\n  .hui-menu-content[data-position-side=\"left\"][data-align=\"end\"],\n  .hui-menu-sub-content[data-position-side=\"left\"][data-align=\"end\"] {\n    position-area: left span-top;\n  }\n\n  .hui-menu-content[data-position-side=\"right\"][data-align=\"start\"],\n  .hui-menu-sub-content[data-position-side=\"right\"][data-align=\"start\"] {\n    position-area: right span-bottom;\n  }\n\n  .hui-menu-content[data-position-side=\"right\"][data-align=\"center\"],\n  .hui-menu-sub-content[data-position-side=\"right\"][data-align=\"center\"] {\n    position-area: right;\n  }\n\n  .hui-menu-content[data-position-side=\"right\"][data-align=\"end\"],\n  .hui-menu-sub-content[data-position-side=\"right\"][data-align=\"end\"] {\n    position-area: right span-top;\n  }\n\n  .hui-menu-group,\n  .hui-menu-radio-group {\n    display: flex;\n    flex-direction: column;\n    min-inline-size: 0;\n  }\n\n  .hui-menu-trigger,\n  .hui-menu-group-label,\n  .hui-menu-item,\n  .hui-menu-link-item,\n  .hui-menu-sub-trigger,\n  .hui-menu-checkbox-item,\n  .hui-menu-radio-item {\n    box-sizing: border-box;\n    max-inline-size: 100%;\n    min-inline-size: 0;\n    overflow-wrap: anywhere;\n  }\n\n  .hui-menu-trigger {\n    white-space: normal;\n  }\n\n  .hui-menu-item,\n  .hui-menu-link-item,\n  .hui-menu-sub-trigger,\n  .hui-menu-checkbox-item,\n  .hui-menu-radio-item {\n    inline-size: 100%;\n    white-space: normal;\n  }\n\n  .hui-menu-link-item {\n    display: block;\n  }\n\n  .hui-menu-checkbox-item-indicator,\n  .hui-menu-radio-item-indicator {\n    align-items: center;\n    display: inline-flex;\n    flex: none;\n    justify-content: center;\n    pointer-events: none;\n  }\n\n  .hui-menu-checkbox-item-indicator[data-checked-state=\"unchecked\"],\n  .hui-menu-radio-item-indicator[data-checked-state=\"unchecked\"] {\n    visibility: hidden;\n  }\n\n  .hui-menu-separator {\n    block-size: 0;\n    inline-size: auto;\n    min-block-size: 0;\n  }\n}\n",
      "path": "packages/heidi-ui/src/menu/menu.base.css",
      "target": "components/ui/heidi/menu/menu.base.css",
      "type": "registry:ui"
    },
    {
      "content": "/* heidi-ui menu — VISUAL theme (opt-in). Consumes --hui-* only. */\n\n@layer heidi-ui {\n  .hui-menu-trigger {\n    background: var(--hui-color-bg-elevated);\n    border: var(--hui-border-width) var(--hui-border-style) var(--hui-color-border-default);\n    border-radius: var(--hui-radius-md);\n    color: var(--hui-color-fg-default);\n    cursor: pointer;\n    font: inherit;\n    padding: var(--hui-space-1-5) var(--hui-space-3);\n  }\n\n  .hui-menu-trigger:focus-visible {\n    outline: var(--hui-focus-ring-width) solid var(--hui-color-focus-ring);\n    outline-offset: var(--hui-focus-ring-offset);\n  }\n\n  .hui-menu-trigger:disabled,\n  .hui-menu-trigger[data-disabled=\"true\"] {\n    cursor: default;\n    opacity: 0.5;\n  }\n\n  /* ponytail: no `margin` here. The trigger↔menu gap is the structural\n     sideOffset (--_hui-menu-side-offset, default 4px = space-1) in\n     menu.base.css, so the shipped skin and a headless consumer get the same\n     prop. Rejected: keeping `margin: var(--hui-space-1)` and having the prop\n     write a var the theme also sets — the theme layer wins over base, so\n     sideOffset would have been silently inert under the Heidi skin. */\n  .hui-menu-content,\n  .hui-menu-sub-content {\n    background: var(--hui-color-bg-raised);\n    border: 0;\n    border-radius: var(--hui-radius-2xl);\n    box-shadow: var(--hui-shadow-surface-lg);\n    color: var(--hui-color-fg-default);\n    gap: var(--hui-space-0-5);\n    min-inline-size: min(12rem, calc(100dvi - 1rem));\n    opacity: 0;\n    padding: var(--hui-space-1-5);\n    transform: scale(0.97);\n    transition-duration: var(--hui-duration-fast);\n    transition-property: display, opacity, overlay, transform;\n    transition-timing-function: var(--hui-ease-out);\n  }\n\n  .hui-menu-content[data-position-side=\"top\"],\n  .hui-menu-sub-content[data-position-side=\"top\"] {\n    transform-origin: bottom center;\n  }\n\n  .hui-menu-content[data-position-side=\"bottom\"],\n  .hui-menu-sub-content[data-position-side=\"bottom\"] {\n    transform-origin: top center;\n  }\n\n  .hui-menu-content[data-position-side=\"left\"],\n  .hui-menu-sub-content[data-position-side=\"left\"] {\n    transform-origin: right center;\n  }\n\n  .hui-menu-content[data-position-side=\"right\"],\n  .hui-menu-sub-content[data-position-side=\"right\"] {\n    transform-origin: left center;\n  }\n\n  .hui-menu-content:popover-open,\n  .hui-menu-sub-content:popover-open {\n    opacity: 1;\n    transform: none;\n  }\n\n  @starting-style {\n    .hui-menu-content:popover-open,\n    .hui-menu-sub-content:popover-open {\n      opacity: 0;\n      transform: scale(0.97);\n    }\n  }\n\n  .hui-menu-group,\n  .hui-menu-radio-group {\n    gap: var(--hui-space-0-5);\n  }\n\n  .hui-menu-group-label {\n    color: var(--hui-color-fg-muted);\n    font: inherit;\n    font-weight: var(--hui-font-weight-medium);\n    padding: var(--hui-space-1) var(--hui-space-2);\n  }\n\n  .hui-menu-item,\n  .hui-menu-link-item,\n  .hui-menu-sub-trigger,\n  .hui-menu-checkbox-item,\n  .hui-menu-radio-item {\n    align-items: center;\n    background: transparent;\n    border: none;\n    border-radius: var(--hui-radius-full);\n    color: var(--hui-color-fg-default);\n    cursor: pointer;\n    display: flex;\n    font: inherit;\n    gap: var(--hui-space-2);\n    padding: var(--hui-space-1-5) var(--hui-space-2);\n    text-align: start;\n    text-decoration: none;\n  }\n\n  .hui-menu-sub-trigger {\n    justify-content: space-between;\n  }\n\n  .hui-menu-item:hover,\n  .hui-menu-link-item:hover,\n  .hui-menu-sub-trigger:hover,\n  .hui-menu-checkbox-item:hover,\n  .hui-menu-radio-item:hover,\n  .hui-menu-item[data-highlighted=\"true\"],\n  .hui-menu-link-item[data-highlighted=\"true\"],\n  .hui-menu-sub-trigger[data-highlighted=\"true\"],\n  .hui-menu-checkbox-item[data-highlighted=\"true\"],\n  .hui-menu-radio-item[data-highlighted=\"true\"] {\n    background: var(--hui-color-interactive-ghost-bg-hover);\n    outline: none;\n  }\n\n  .hui-menu-item:focus-visible,\n  .hui-menu-link-item:focus-visible,\n  .hui-menu-sub-trigger:focus-visible,\n  .hui-menu-checkbox-item:focus-visible,\n  .hui-menu-radio-item:focus-visible {\n    outline: var(--hui-focus-ring-width) solid var(--hui-color-focus-ring);\n    outline-offset: calc(-1 * var(--hui-focus-ring-offset));\n  }\n\n  .hui-menu-checkbox-item[data-checked-state=\"checked\"],\n  .hui-menu-checkbox-item[data-checked-state=\"unchecked\"],\n  .hui-menu-radio-item[data-checked-state=\"checked\"],\n  .hui-menu-radio-item[data-checked-state=\"unchecked\"] {\n    color: var(--hui-color-fg-default);\n  }\n\n  .hui-menu-item:disabled,\n  .hui-menu-item[data-disabled=\"true\"],\n  .hui-menu-link-item[data-disabled=\"true\"],\n  .hui-menu-sub-trigger:disabled,\n  .hui-menu-sub-trigger[data-disabled=\"true\"],\n  .hui-menu-checkbox-item[data-disabled=\"true\"],\n  .hui-menu-radio-item[data-disabled=\"true\"] {\n    cursor: default;\n    opacity: 0.5;\n  }\n\n  .hui-menu-item:disabled:hover,\n  .hui-menu-item[data-disabled=\"true\"]:hover,\n  .hui-menu-link-item[data-disabled=\"true\"]:hover,\n  .hui-menu-sub-trigger:disabled:hover,\n  .hui-menu-sub-trigger[data-disabled=\"true\"]:hover,\n  .hui-menu-checkbox-item[data-disabled=\"true\"]:hover,\n  .hui-menu-radio-item[data-disabled=\"true\"]:hover,\n  .hui-menu-item[data-disabled=\"true\"][data-highlighted=\"true\"],\n  .hui-menu-link-item[data-disabled=\"true\"][data-highlighted=\"true\"],\n  .hui-menu-sub-trigger[data-disabled=\"true\"][data-highlighted=\"true\"],\n  .hui-menu-checkbox-item[data-disabled=\"true\"][data-highlighted=\"true\"],\n  .hui-menu-radio-item[data-disabled=\"true\"][data-highlighted=\"true\"] {\n    background: transparent;\n  }\n\n  .hui-menu-checkbox-item-indicator,\n  .hui-menu-radio-item-indicator {\n    block-size: var(--hui-space-4);\n    color: currentColor;\n    inline-size: var(--hui-space-4);\n  }\n\n  .hui-menu-checkbox-item-indicator[data-default-indicator][data-checked-state=\"checked\"]::before {\n    background: currentColor;\n    block-size: var(--hui-space-4);\n    content: \"\";\n    display: block;\n    inline-size: var(--hui-space-4);\n    mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white'%3E%3Cpath d='m2.5 8.5 4 4 7-9'/%3E%3C/svg%3E\") center / 1rem 1rem no-repeat;\n    -webkit-mask: url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='none' stroke='white'%3E%3Cpath d='m2.5 8.5 4 4 7-9'/%3E%3C/svg%3E\") center / 1rem 1rem no-repeat;\n  }\n\n  .hui-menu-radio-item-indicator[data-default-indicator][data-checked-state=\"checked\"]::before {\n    background: currentColor;\n    block-size: var(--hui-space-2);\n    border-radius: var(--hui-radius-full);\n    content: \"\";\n    display: block;\n    inline-size: var(--hui-space-2);\n  }\n\n  .hui-menu-separator {\n    border: 0;\n    border-block-start: var(--hui-border-width) var(--hui-border-style)\n      var(--hui-color-border-default);\n    margin: var(--hui-space-1) var(--hui-space-2);\n  }\n\n  @media (prefers-reduced-motion: reduce) {\n    .hui-menu-content,\n    .hui-menu-sub-content {\n      transform: none;\n      transition-duration: 0s;\n    }\n\n    .hui-menu-content:popover-open,\n    .hui-menu-sub-content:popover-open {\n      opacity: 1;\n      transform: none;\n    }\n  }\n\n  @media (forced-colors: active) {\n    .hui-menu-content,\n    .hui-menu-sub-content {\n      border: var(--hui-border-width) solid CanvasText;\n    }\n\n    .hui-menu-trigger {\n      border-color: CanvasText;\n    }\n\n    .hui-menu-separator {\n      border-block-start-color: CanvasText;\n    }\n\n    .hui-menu-trigger:focus-visible,\n    .hui-menu-item:focus-visible,\n    .hui-menu-link-item:focus-visible,\n    .hui-menu-sub-trigger:focus-visible,\n    .hui-menu-checkbox-item:focus-visible,\n    .hui-menu-radio-item:focus-visible {\n      outline-color: Highlight;\n    }\n\n    .hui-menu-trigger:disabled,\n    .hui-menu-trigger[data-disabled=\"true\"],\n    .hui-menu-item:disabled,\n    .hui-menu-item[data-disabled=\"true\"],\n    .hui-menu-link-item[data-disabled=\"true\"],\n    .hui-menu-sub-trigger:disabled,\n    .hui-menu-sub-trigger[data-disabled=\"true\"],\n    .hui-menu-checkbox-item[data-disabled=\"true\"],\n    .hui-menu-radio-item[data-disabled=\"true\"] {\n      color: GrayText;\n      opacity: 1;\n    }\n  }\n}\n",
      "path": "packages/heidi-ui/src/menu/menu.theme.css",
      "target": "components/ui/heidi/menu/menu.theme.css",
      "type": "registry:ui"
    },
    {
      "content": "/*\n * heidi-ui menu — aggregator (base + Heidi adapter + theme).\n * Headless: import menu.base.css only.\n * Themed: import this file (or heidi-ui/styles.css).\n */\n\n@import \"./menu.base.css\";\n@import \"../../../../styles/heidi-ui-adapter.css\";\n@import \"./menu.theme.css\";\n",
      "path": "packages/heidi-ui/src/menu/menu.css",
      "target": "components/ui/heidi/menu/menu.css",
      "type": "registry:ui"
    },
    {
      "content": "/** GENERATED from packages/heidi-ui/src/menu/menu.base.css + packages/heidi-ui/src/menu/menu.theme.css — do not edit by hand.\n * Rebuild: `bun run hui:build`. Freshness: `bun run contracts:check`. */\nexport const MENU_CLASSES = {\n  checkboxItem: \"hui-menu-checkbox-item\",\n  checkboxItemIndicator: \"hui-menu-checkbox-item-indicator\",\n  content: \"hui-menu-content\",\n  group: \"hui-menu-group\",\n  groupLabel: \"hui-menu-group-label\",\n  item: \"hui-menu-item\",\n  linkItem: \"hui-menu-link-item\",\n  radioGroup: \"hui-menu-radio-group\",\n  radioItem: \"hui-menu-radio-item\",\n  radioItemIndicator: \"hui-menu-radio-item-indicator\",\n  separator: \"hui-menu-separator\",\n  subContent: \"hui-menu-sub-content\",\n  subTrigger: \"hui-menu-sub-trigger\",\n  trigger: \"hui-menu-trigger\",\n} as const;\n",
      "path": "packages/heidi-ui/src/menu/menu.classes.generated.ts",
      "target": "components/ui/heidi/menu/menu.classes.generated.ts",
      "type": "registry:ui"
    },
    {
      "content": "/** GENERATED from menu.anatomy.json + menu.base.css + menu.theme.css — do not edit by hand.\n * Rebuild: `bun run hui:build`. Freshness: `bun run contracts:check`. */\n\nexport type MenuAlign = \"center\" | \"end\" | \"start\";\nexport type MenuCheckedState = \"checked\" | \"unchecked\";\nexport type MenuDisabled = \"true\";\nexport type MenuHighlighted = \"true\";\nexport type MenuPositionSide = \"bottom\" | \"left\" | \"right\" | \"top\";\nexport type MenuSide = \"bottom\" | \"inline-end\" | \"inline-start\" | \"left\" | \"right\" | \"top\";\nexport type MenuState = \"closed\" | \"open\";\n\nexport const MENU_ANATOMY = {\n  \"component\": \"menu\",\n  \"description\": \"Base-UI-shaped APG menu button on a lean native manual-Popover and CSS-anchor shell. Controlled state is authoritative and cancellable. Open-only owner-document listeners provide composed light dismiss across native or custom Triggers: pointer down and up must both be outside, focus exit is reasoned independently, and Escape is owned by the topmost applicable menu. A Root can register multiple in-tree Triggers, tracks one active trigger through defaultTriggerId/triggerId, exposes open state only on that trigger, and anchors its single Popup to the active trigger. Root disabled state blocks open-state requests and cascades through triggers, items, checked-item groups, and submenus. Registered submenu branches close accepted same-level siblings with the Base-shaped sibling-open reason, propagate accepted parent closure through open descendants, and request structural closure when their only SubTrigger unmounts. The menu supports focusable disabled items, reset-on-close locale-aware typeahead, exact Tab exit, configurable focus looping and pointer highlighting, direction-aware nested submenus, semantic links/groups/separators, checkbox and radio items, physical side placement, and viewport-contained popup geometry without a positioning dependency.\",\n  \"schemaVersion\": 2,\n  \"parts\": {\n    \"checkbox-item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-checked\",\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitemcheckbox\"\n      },\n      \"class\": \"hui-menu-checkbox-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-checkbox-item\",\n      \"description\": \"Focusable menuitemcheckbox with controlled or uncontrolled checked state. Disabled items remain in the APG focus ring; selection stays open unless closeOnClick is true.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"checked\",\n        \"className\",\n        \"closeOnClick\",\n        \"defaultChecked\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"onCheckedChange\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ],\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"checkbox-item-indicator\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-hidden\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-checkbox-item-indicator\",\n      \"css\": {\n        \"structural\": [\n          \"align-items\",\n          \"display\",\n          \"flex\",\n          \"justify-content\",\n          \"pointer-events\",\n          \"visibility\"\n        ]\n      },\n      \"dataPart\": \"menu-checkbox-item-indicator\",\n      \"description\": \"Decorative checked mark. It is absent while unchecked unless keepMounted is true and paints the theme fallback only when custom children are absent.\",\n      \"element\": \"span\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"content\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-labelledby\"\n        ],\n        \"role\": \"menu\"\n      },\n      \"class\": \"hui-menu-content\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"display\",\n          \"flex-direction\",\n          \"inset\",\n          \"margin\",\n          \"max-block-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow\",\n          \"overscroll-behavior\",\n          \"pointer-events\",\n          \"position\",\n          \"position-area\",\n          \"position-try-fallbacks\",\n          \"scrollbar-gutter\",\n          \"transition-behavior\",\n          \"transition-property\",\n          \"translate\"\n        ]\n      },\n      \"dataPart\": \"menu-content\",\n      \"description\": \"Content (also exported as Popup) is the single lazy native role=menu manual popover. It owns APG focus movement and reset-on-close typeahead, retains exit transitions, and follows the active Trigger's private CSS anchor without a portal. Its composed dismiss zone includes every registered Trigger; pointer down/up light dismiss, programmatic focus exit, and Escape produce one cancellable reasoned request. Shift+Tab closes and returns to the active Trigger; forward Tab closes and moves to the next sequential tabbable after it, scoped to an owning native modal Dialog when present. Canceled controlled closes retain focus and native open state.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"align\",\n        \"alignOffset\",\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"side\",\n        \"sideOffset\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":popover-open\"\n      ],\n      \"states\": {\n        \"data-align\": [\n          \"center\",\n          \"end\",\n          \"start\"\n        ],\n        \"data-position-side\": [\n          \"bottom\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-side\": [\n          \"bottom\",\n          \"inline-end\",\n          \"inline-start\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    },\n    \"group\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-labelledby\"\n        ],\n        \"role\": \"group\"\n      },\n      \"class\": \"hui-menu-group\",\n      \"css\": {\n        \"structural\": [\n          \"display\",\n          \"flex-direction\",\n          \"min-inline-size\"\n        ]\n      },\n      \"dataPart\": \"menu-group\",\n      \"description\": \"Semantic menu item group which automatically references its mounted GroupLabel without leaving a dangling aria-labelledby value.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {}\n    },\n    \"group-label\": {\n      \"aria\": {\n        \"owns\": [],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-group-label\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-group-label\",\n      \"description\": \"Visible label registered with the nearest Group or RadioGroup.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {}\n    },\n    \"item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitem\"\n      },\n      \"class\": \"hui-menu-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-item\",\n      \"description\": \"Polymorphic role=menuitem with non-native keyboard activation. Disabled items remain focusable but inert; selection closes unless closeOnClick is false.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeOnClick\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"onSelect\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ]\n      }\n    },\n    \"link-item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitem\"\n      },\n      \"class\": \"hui-menu-link-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"display\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-link-item\",\n      \"description\": \"Semantic anchor menu item with APG Space activation. Disabled links are inert but focusable, and navigation stays open unless closeOnClick is true.\",\n      \"element\": \"a\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeOnClick\",\n        \"disabled\",\n        \"label\",\n        \"onSelect\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ]\n      }\n    },\n    \"radio-group\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-disabled\",\n          \"aria-labelledby\"\n        ],\n        \"role\": \"group\"\n      },\n      \"class\": \"hui-menu-radio-group\",\n      \"css\": {\n        \"structural\": [\n          \"display\",\n          \"flex-direction\",\n          \"min-inline-size\"\n        ]\n      },\n      \"dataPart\": \"menu-radio-group\",\n      \"description\": \"Controlled or uncontrolled group of mutually exclusive RadioItems, automatically named by its mounted GroupLabel.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"defaultValue\",\n        \"disabled\",\n        \"onValueChange\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"value\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ]\n      }\n    },\n    \"radio-item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-checked\",\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitemradio\"\n      },\n      \"class\": \"hui-menu-radio-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-radio-item\",\n      \"description\": \"Focusable menuitemradio controlled by its RadioGroup. Disabled items remain in the focus ring; selection stays open unless closeOnClick is true.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeOnClick\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"value\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ],\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"radio-item-indicator\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-hidden\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-radio-item-indicator\",\n      \"css\": {\n        \"structural\": [\n          \"align-items\",\n          \"display\",\n          \"flex\",\n          \"justify-content\",\n          \"pointer-events\",\n          \"visibility\"\n        ]\n      },\n      \"dataPart\": \"menu-radio-item-indicator\",\n      \"description\": \"Decorative selected mark. It is absent while unchecked unless keepMounted is true and paints the theme fallback only when custom children are absent.\",\n      \"element\": \"span\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"separator\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-orientation\"\n        ],\n        \"role\": \"separator\"\n      },\n      \"class\": \"hui-menu-separator\",\n      \"css\": {\n        \"structural\": [\n          \"block-size\",\n          \"inline-size\",\n          \"min-block-size\"\n        ]\n      },\n      \"dataPart\": \"menu-separator\",\n      \"description\": \"Horizontal semantic separator excluded from the menu focus ring.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {}\n    },\n    \"sub-content\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-labelledby\"\n        ],\n        \"role\": \"menu\"\n      },\n      \"class\": \"hui-menu-sub-content\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"display\",\n          \"flex-direction\",\n          \"inset\",\n          \"margin\",\n          \"max-block-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow\",\n          \"overscroll-behavior\",\n          \"pointer-events\",\n          \"position\",\n          \"position-area\",\n          \"position-try-fallbacks\",\n          \"scrollbar-gutter\",\n          \"transition-behavior\",\n          \"transition-property\",\n          \"translate\"\n        ]\n      },\n      \"dataPart\": \"menu-sub-content\",\n      \"description\": \"Lazy nested role=menu manual popover with authoritative controlled state, direction-aware navigation, reset-on-close typeahead, physical placement, composed SubTrigger/Content light dismiss, and pointer-intent bridge handling. Accepted opening closes same-level branches with sibling-open; accepted closing propagates through open descendants. Shift+Tab closes only the submenu and returns to SubTrigger; forward Tab closes the root menu and advances after its active Trigger.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"align\",\n        \"alignOffset\",\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"side\",\n        \"sideOffset\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":popover-open\"\n      ],\n      \"states\": {\n        \"data-align\": [\n          \"center\",\n          \"end\",\n          \"start\"\n        ],\n        \"data-position-side\": [\n          \"bottom\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-side\": [\n          \"bottom\",\n          \"inline-end\",\n          \"inline-start\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    },\n    \"sub-trigger\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-controls\",\n          \"aria-disabled\",\n          \"aria-expanded\",\n          \"aria-haspopup\"\n        ],\n        \"role\": \"menuitem\"\n      },\n      \"class\": \"hui-menu-sub-trigger\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-sub-trigger\",\n      \"description\": \"Focusable submenu item with authoritative controlled state, per-trigger mouse intent, and component-direction-aware open/close-key handling. It defaults to hover opening, supports per-trigger delay/closeDelay overrides, reports hover opens and leaves with the trigger-hover reason, and can render a native button without duplicating its Enter/Space activation. Keyboard activation or the logical open arrow enters the first enabled child even when hover already opened the submenu; Escape on an open SubTrigger closes only that child layer. Unmounting the only SubTrigger cancels a pending hover open and requests structural closure for an already-open child.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeDelay\",\n        \"delay\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"openOnHover\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    },\n    \"trigger\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-controls\",\n          \"aria-expanded\",\n          \"aria-haspopup\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-trigger\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\"\n        ]\n      },\n      \"dataPart\": \"menu-trigger\",\n      \"description\": \"Registered menu invoker with consumer-first native prop composition. Each Trigger has a unique public id and private CSS anchor; only the active Trigger exposes open state and labels/positions the shared Popup. ArrowDown opens at the first item, ArrowUp at the last, optional mouse hover uses per-trigger delays, and nativeButton preserves correct custom-host semantics.\",\n      \"element\": \"button\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeDelay\",\n        \"delay\",\n        \"disabled\",\n        \"id\",\n        \"nativeButton\",\n        \"openOnHover\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":disabled\",\n        \":focus-visible\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    }\n  },\n  \"rootProps\": [\n    \"defaultOpen\",\n    \"defaultTriggerId\",\n    \"disabled\",\n    \"highlightItemOnHover\",\n    \"loopFocus\",\n    \"onOpenChange\",\n    \"onOpenChangeComplete\",\n    \"open\",\n    \"submenuCloseDelay\",\n    \"submenuOpenDelay\",\n    \"triggerId\"\n  ],\n  \"tokens\": [\n    \"--hui-border-style\",\n    \"--hui-border-width\",\n    \"--hui-color-bg-elevated\",\n    \"--hui-color-bg-raised\",\n    \"--hui-color-border-default\",\n    \"--hui-color-fg-default\",\n    \"--hui-color-fg-muted\",\n    \"--hui-color-focus-ring\",\n    \"--hui-color-interactive-ghost-bg-hover\",\n    \"--hui-duration-fast\",\n    \"--hui-ease-out\",\n    \"--hui-focus-ring-offset\",\n    \"--hui-focus-ring-width\",\n    \"--hui-font-weight-medium\",\n    \"--hui-radius-2xl\",\n    \"--hui-radius-full\",\n    \"--hui-radius-md\",\n    \"--hui-shadow-surface-lg\",\n    \"--hui-space-0-5\",\n    \"--hui-space-1\",\n    \"--hui-space-1-5\",\n    \"--hui-space-2\",\n    \"--hui-space-3\",\n    \"--hui-space-4\"\n  ]\n} as const;\n",
      "path": "packages/heidi-ui/src/menu/menu.anatomy.generated.ts",
      "target": "components/ui/heidi/menu/menu.anatomy.generated.ts",
      "type": "registry:ui"
    },
    {
      "content": "{\n  \"component\": \"menu\",\n  \"description\": \"Base-UI-shaped APG menu button on a lean native manual-Popover and CSS-anchor shell. Controlled state is authoritative and cancellable. Open-only owner-document listeners provide composed light dismiss across native or custom Triggers: pointer down and up must both be outside, focus exit is reasoned independently, and Escape is owned by the topmost applicable menu. A Root can register multiple in-tree Triggers, tracks one active trigger through defaultTriggerId/triggerId, exposes open state only on that trigger, and anchors its single Popup to the active trigger. Root disabled state blocks open-state requests and cascades through triggers, items, checked-item groups, and submenus. Registered submenu branches close accepted same-level siblings with the Base-shaped sibling-open reason, propagate accepted parent closure through open descendants, and request structural closure when their only SubTrigger unmounts. The menu supports focusable disabled items, reset-on-close locale-aware typeahead, exact Tab exit, configurable focus looping and pointer highlighting, direction-aware nested submenus, semantic links/groups/separators, checkbox and radio items, physical side placement, and viewport-contained popup geometry without a positioning dependency.\",\n  \"schemaVersion\": 2,\n  \"parts\": {\n    \"checkbox-item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-checked\",\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitemcheckbox\"\n      },\n      \"class\": \"hui-menu-checkbox-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-checkbox-item\",\n      \"description\": \"Focusable menuitemcheckbox with controlled or uncontrolled checked state. Disabled items remain in the APG focus ring; selection stays open unless closeOnClick is true.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"checked\",\n        \"className\",\n        \"closeOnClick\",\n        \"defaultChecked\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"onCheckedChange\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ],\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"checkbox-item-indicator\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-hidden\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-checkbox-item-indicator\",\n      \"css\": {\n        \"structural\": [\n          \"align-items\",\n          \"display\",\n          \"flex\",\n          \"justify-content\",\n          \"pointer-events\",\n          \"visibility\"\n        ]\n      },\n      \"dataPart\": \"menu-checkbox-item-indicator\",\n      \"description\": \"Decorative checked mark. It is absent while unchecked unless keepMounted is true and paints the theme fallback only when custom children are absent.\",\n      \"element\": \"span\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"content\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-labelledby\"\n        ],\n        \"role\": \"menu\"\n      },\n      \"class\": \"hui-menu-content\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"display\",\n          \"flex-direction\",\n          \"inset\",\n          \"margin\",\n          \"max-block-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow\",\n          \"overscroll-behavior\",\n          \"pointer-events\",\n          \"position\",\n          \"position-area\",\n          \"position-try-fallbacks\",\n          \"scrollbar-gutter\",\n          \"transition-behavior\",\n          \"transition-property\",\n          \"translate\"\n        ]\n      },\n      \"dataPart\": \"menu-content\",\n      \"description\": \"Content (also exported as Popup) is the single lazy native role=menu manual popover. It owns APG focus movement and reset-on-close typeahead, retains exit transitions, and follows the active Trigger's private CSS anchor without a portal. Its composed dismiss zone includes every registered Trigger; pointer down/up light dismiss, programmatic focus exit, and Escape produce one cancellable reasoned request. Shift+Tab closes and returns to the active Trigger; forward Tab closes and moves to the next sequential tabbable after it, scoped to an owning native modal Dialog when present. Canceled controlled closes retain focus and native open state.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"align\",\n        \"alignOffset\",\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"side\",\n        \"sideOffset\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":popover-open\"\n      ],\n      \"states\": {\n        \"data-align\": [\n          \"center\",\n          \"end\",\n          \"start\"\n        ],\n        \"data-position-side\": [\n          \"bottom\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-side\": [\n          \"bottom\",\n          \"inline-end\",\n          \"inline-start\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    },\n    \"group\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-labelledby\"\n        ],\n        \"role\": \"group\"\n      },\n      \"class\": \"hui-menu-group\",\n      \"css\": {\n        \"structural\": [\n          \"display\",\n          \"flex-direction\",\n          \"min-inline-size\"\n        ]\n      },\n      \"dataPart\": \"menu-group\",\n      \"description\": \"Semantic menu item group which automatically references its mounted GroupLabel without leaving a dangling aria-labelledby value.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {}\n    },\n    \"group-label\": {\n      \"aria\": {\n        \"owns\": [],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-group-label\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-group-label\",\n      \"description\": \"Visible label registered with the nearest Group or RadioGroup.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {}\n    },\n    \"item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitem\"\n      },\n      \"class\": \"hui-menu-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-item\",\n      \"description\": \"Polymorphic role=menuitem with non-native keyboard activation. Disabled items remain focusable but inert; selection closes unless closeOnClick is false.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeOnClick\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"onSelect\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ]\n      }\n    },\n    \"link-item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitem\"\n      },\n      \"class\": \"hui-menu-link-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"display\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-link-item\",\n      \"description\": \"Semantic anchor menu item with APG Space activation. Disabled links are inert but focusable, and navigation stays open unless closeOnClick is true.\",\n      \"element\": \"a\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeOnClick\",\n        \"disabled\",\n        \"label\",\n        \"onSelect\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ]\n      }\n    },\n    \"radio-group\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-disabled\",\n          \"aria-labelledby\"\n        ],\n        \"role\": \"group\"\n      },\n      \"class\": \"hui-menu-radio-group\",\n      \"css\": {\n        \"structural\": [\n          \"display\",\n          \"flex-direction\",\n          \"min-inline-size\"\n        ]\n      },\n      \"dataPart\": \"menu-radio-group\",\n      \"description\": \"Controlled or uncontrolled group of mutually exclusive RadioItems, automatically named by its mounted GroupLabel.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"defaultValue\",\n        \"disabled\",\n        \"onValueChange\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"value\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ]\n      }\n    },\n    \"radio-item\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-checked\",\n          \"aria-disabled\"\n        ],\n        \"role\": \"menuitemradio\"\n      },\n      \"class\": \"hui-menu-radio-item\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-radio-item\",\n      \"description\": \"Focusable menuitemradio controlled by its RadioGroup. Disabled items remain in the focus ring; selection stays open unless closeOnClick is true.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeOnClick\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"ref\",\n        \"render\",\n        \"style\",\n        \"value\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ],\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"radio-item-indicator\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-hidden\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-radio-item-indicator\",\n      \"css\": {\n        \"structural\": [\n          \"align-items\",\n          \"display\",\n          \"flex\",\n          \"justify-content\",\n          \"pointer-events\",\n          \"visibility\"\n        ]\n      },\n      \"dataPart\": \"menu-radio-item-indicator\",\n      \"description\": \"Decorative selected mark. It is absent while unchecked unless keepMounted is true and paints the theme fallback only when custom children are absent.\",\n      \"element\": \"span\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {\n        \"data-checked-state\": [\n          \"checked\",\n          \"unchecked\"\n        ]\n      }\n    },\n    \"separator\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-orientation\"\n        ],\n        \"role\": \"separator\"\n      },\n      \"class\": \"hui-menu-separator\",\n      \"css\": {\n        \"structural\": [\n          \"block-size\",\n          \"inline-size\",\n          \"min-block-size\"\n        ]\n      },\n      \"dataPart\": \"menu-separator\",\n      \"description\": \"Horizontal semantic separator excluded from the menu focus ring.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [],\n      \"states\": {}\n    },\n    \"sub-content\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-labelledby\"\n        ],\n        \"role\": \"menu\"\n      },\n      \"class\": \"hui-menu-sub-content\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"display\",\n          \"flex-direction\",\n          \"inset\",\n          \"margin\",\n          \"max-block-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow\",\n          \"overscroll-behavior\",\n          \"pointer-events\",\n          \"position\",\n          \"position-area\",\n          \"position-try-fallbacks\",\n          \"scrollbar-gutter\",\n          \"transition-behavior\",\n          \"transition-property\",\n          \"translate\"\n        ]\n      },\n      \"dataPart\": \"menu-sub-content\",\n      \"description\": \"Lazy nested role=menu manual popover with authoritative controlled state, direction-aware navigation, reset-on-close typeahead, physical placement, composed SubTrigger/Content light dismiss, and pointer-intent bridge handling. Accepted opening closes same-level branches with sibling-open; accepted closing propagates through open descendants. Shift+Tab closes only the submenu and returns to SubTrigger; forward Tab closes the root menu and advances after its active Trigger.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"align\",\n        \"alignOffset\",\n        \"className\",\n        \"keepMounted\",\n        \"ref\",\n        \"render\",\n        \"side\",\n        \"sideOffset\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":popover-open\"\n      ],\n      \"states\": {\n        \"data-align\": [\n          \"center\",\n          \"end\",\n          \"start\"\n        ],\n        \"data-position-side\": [\n          \"bottom\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-side\": [\n          \"bottom\",\n          \"inline-end\",\n          \"inline-start\",\n          \"left\",\n          \"right\",\n          \"top\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    },\n    \"sub-trigger\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-controls\",\n          \"aria-disabled\",\n          \"aria-expanded\",\n          \"aria-haspopup\"\n        ],\n        \"role\": \"menuitem\"\n      },\n      \"class\": \"hui-menu-sub-trigger\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"inline-size\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\",\n          \"white-space\"\n        ]\n      },\n      \"dataPart\": \"menu-sub-trigger\",\n      \"description\": \"Focusable submenu item with authoritative controlled state, per-trigger mouse intent, and component-direction-aware open/close-key handling. It defaults to hover opening, supports per-trigger delay/closeDelay overrides, reports hover opens and leaves with the trigger-hover reason, and can render a native button without duplicating its Enter/Space activation. Keyboard activation or the logical open arrow enters the first enabled child even when hover already opened the submenu; Escape on an open SubTrigger closes only that child layer. Unmounting the only SubTrigger cancels a pending hover open and requests structural closure for an already-open child.\",\n      \"element\": \"div\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeDelay\",\n        \"delay\",\n        \"disabled\",\n        \"label\",\n        \"nativeButton\",\n        \"openOnHover\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":focus-visible\",\n        \":hover\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-highlighted\": [\n          \"true\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    },\n    \"trigger\": {\n      \"aria\": {\n        \"owns\": [\n          \"aria-controls\",\n          \"aria-expanded\",\n          \"aria-haspopup\"\n        ],\n        \"role\": null\n      },\n      \"class\": \"hui-menu-trigger\",\n      \"css\": {\n        \"structural\": [\n          \"box-sizing\",\n          \"max-inline-size\",\n          \"min-inline-size\",\n          \"overflow-wrap\"\n        ]\n      },\n      \"dataPart\": \"menu-trigger\",\n      \"description\": \"Registered menu invoker with consumer-first native prop composition. Each Trigger has a unique public id and private CSS anchor; only the active Trigger exposes open state and labels/positions the shared Popup. ArrowDown opens at the first item, ArrowUp at the last, optional mouse hover uses per-trigger delays, and nativeButton preserves correct custom-host semantics.\",\n      \"element\": \"button\",\n      \"nativeProps\": true,\n      \"props\": [\n        \"className\",\n        \"closeDelay\",\n        \"delay\",\n        \"disabled\",\n        \"id\",\n        \"nativeButton\",\n        \"openOnHover\",\n        \"ref\",\n        \"render\",\n        \"style\"\n      ],\n      \"pseudoStates\": [\n        \":disabled\",\n        \":focus-visible\"\n      ],\n      \"states\": {\n        \"data-disabled\": [\n          \"true\"\n        ],\n        \"data-state\": [\n          \"closed\",\n          \"open\"\n        ]\n      }\n    }\n  },\n  \"rootProps\": [\n    \"defaultOpen\",\n    \"defaultTriggerId\",\n    \"disabled\",\n    \"highlightItemOnHover\",\n    \"loopFocus\",\n    \"onOpenChange\",\n    \"onOpenChangeComplete\",\n    \"open\",\n    \"submenuCloseDelay\",\n    \"submenuOpenDelay\",\n    \"triggerId\"\n  ]\n}\n",
      "path": "packages/heidi-ui/src/menu/menu.anatomy.json",
      "target": "components/ui/heidi/menu/menu.anatomy.json",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared Web-Animations settling helpers (P6).\n *\n * Dialog, HoverCard and Collapsible each carried a byte-identical async\n * \"wait for this element's animations, but never forever\" routine, and all\n * four popover-family components carried their own `finiteAnimationDuration`.\n *\n * ponytail: the audit read this as one helper duplicated four times and\n * prescribed a single `waitForElementAnimations` covering \"the four call-site\n * variants\". Diffing them first — which that same entry insisted on — shows\n * that is not the shape. THREE are the same async routine differing only in\n * two flags. Menu's `afterPopoverAnimations` is a different algorithm: it is\n * callback-shaped rather than awaited, returns a canceller, subscribes to\n * `finish`/`cancel` events instead of racing `animation.finished`, and falls\n * back to computed CSS on engines without `getAnimations`. Forcing it into the\n * awaited shape would have rewritten working popover-dismissal logic to make a\n * count go from four to one. So Menu keeps its own routine and shares only the\n * duration helper it genuinely had in common.\n *\n * The duration helper resolves to MENU's copy, which was the strict one: the\n * other three returned `timing.endTime` raw, so a non-finite or negative\n * `endTime` (reachable via a negative `endDelay`) propagated into\n * `setTimeout` — and `setTimeout(fn, NaN)` fires at 0ms, collapsing the wait\n * it was supposed to bound. Same class as the non-finite bounds that reached\n * Slider's and Progress's ARIA.\n */\n\n/** Ceiling on any settle wait. A stuck animation must not strand a component. */\nexport const MAX_ANIMATION_WAIT_MS = 30_000;\n\n/** Grace added to the longest observed animation before the wait gives up. */\nexport const ANIMATION_WAIT_GRACE_MS = 250;\n\nexport function finiteAnimationDuration(\n  animation: Animation\n): number | undefined {\n  const timing = animation.effect?.getComputedTiming();\n  if (\n    !timing ||\n    timing.iterations === Infinity ||\n    typeof timing.endTime !== \"number\" ||\n    !Number.isFinite(timing.endTime)\n  ) {\n    return undefined;\n  }\n  return Math.max(0, timing.endTime);\n}\n\nexport async function afterNextPaint(): Promise<void> {\n  await new Promise<void>((resolve) => {\n    requestAnimationFrame(() => requestAnimationFrame(() => resolve()));\n  });\n}\n\n/** Animations worth waiting on: real, still running, and finitely long. */\nexport function pendingAnimations(\n  element: Element,\n  subtree: boolean\n): Array<{ animation: Animation; duration: number }> {\n  // Embedded and older engines can omit the Web Animations inspection API.\n  // In that no-observer path the state must still settle instead of throwing.\n  if (typeof element.getAnimations !== \"function\") {\n    return [];\n  }\n  return element\n    .getAnimations(subtree ? { subtree: true } : undefined)\n    .map((animation) => ({\n      animation,\n      duration: finiteAnimationDuration(animation)\n    }))\n    .filter(\n      (entry): entry is { animation: Animation; duration: number } =>\n        entry.duration !== undefined &&\n        entry.duration > 0 &&\n        entry.animation.playState !== \"finished\" &&\n        entry.animation.playState !== \"idle\"\n    );\n}\n\nexport type WaitForElementAnimationsOptions = {\n  /**\n   * Wait two frames before inspecting. Dialog and HoverCard need this: they\n   * ask immediately after a state flip, before the engine has started the\n   * animations they mean to wait for. Collapsible asks after the fact and\n   * must NOT gain the extra frames — that would be an observable timing\n   * change, and this slice does not make those.\n   */\n  awaitPaint?: boolean;\n  /** Inspect descendants too — for panels whose motion lives on children. */\n  subtree?: boolean;\n};\n\nexport async function waitForElementAnimations(\n  element: Element,\n  { awaitPaint = false, subtree = false }: WaitForElementAnimationsOptions = {}\n): Promise<void> {\n  if (awaitPaint) {\n    await afterNextPaint();\n    // ponytail: the connectedness check is deliberately INSIDE the awaitPaint\n    // branch rather than unconditional. It is not a general safety net — it\n    // exists because those two frames are a window in which the element can be\n    // torn down, and it was present in exactly the two copies that wait. The\n    // non-waiting caller has no such window: nothing can run between its own\n    // check and this call, so hoisting the guard would be adding behaviour to\n    // Collapsible in a slice whose whole premise is changing none.\n    if (!element.isConnected) {\n      return;\n    }\n  }\n  const animations = pendingAnimations(element, subtree);\n  if (animations.length === 0) {\n    return;\n  }\n  const maximum = Math.min(\n    MAX_ANIMATION_WAIT_MS,\n    Math.max(...animations.map(({ duration }) => duration)) +\n      ANIMATION_WAIT_GRACE_MS\n  );\n  let timeout = 0;\n  await Promise.race([\n    Promise.allSettled(animations.map(({ animation }) => animation.finished)),\n    new Promise<void>((resolve) => {\n      timeout = window.setTimeout(resolve, maximum);\n    })\n  ]);\n  window.clearTimeout(timeout);\n}\n",
      "path": "packages/heidi-ui/src/_internal/animation-wait.ts",
      "target": "components/ui/heidi/_internal/animation-wait.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Cross-cutting disabled attrs for heidi-ui interactive hosts.\n *\n * House convention (Phase 23):\n * - Button widgets → native `disabled` + `data-disabled=\"true\"` (CSS + a11y).\n * - Non-button options (Select.Item) → `aria-disabled` + `data-disabled=\"true\"`\n *   (native disabled is invalid on role=option divs).\n * - Group roots may cascade `disabled` to children and mirror `data-disabled`.\n * - Keyboard nav / activation always skip disabled hosts.\n */\n\nexport type NativeDisabledAttrs = {\n  \"data-disabled\"?: true;\n  disabled?: true;\n};\n\nexport type AriaDisabledAttrs = {\n  \"aria-disabled\"?: true;\n  \"data-disabled\"?: true;\n};\n\nexport type DataDisabledAttrs = {\n  \"data-disabled\"?: true;\n};\n\n/** Native button/input disabled + styling hook. */\nexport function nativeDisabledAttrs(disabled: boolean | undefined): NativeDisabledAttrs {\n  if (!disabled) {\n    return {};\n  }\n  return {\n    \"data-disabled\": true,\n    disabled: true\n  };\n}\n\n/** ARIA-disabled for non-native hosts (e.g. role=option). */\nexport function ariaDisabledAttrs(disabled: boolean | undefined): AriaDisabledAttrs {\n  if (!disabled) {\n    return {};\n  }\n  return {\n    \"aria-disabled\": true,\n    \"data-disabled\": true\n  };\n}\n\n/** Styling hook only (group roots that cascade disabled). */\nexport function dataDisabledAttrs(disabled: boolean | undefined): DataDisabledAttrs {\n  if (!disabled) {\n    return {};\n  }\n  return {\n    \"data-disabled\": true\n  };\n}\n\nexport function isDisabledElement(el: Element | null | undefined): boolean {\n  if (!el || !(el instanceof HTMLElement)) {\n    return false;\n  }\n  if (el.matches(\":disabled\")) {\n    return true;\n  }\n  return el.getAttribute(\"aria-disabled\") === \"true\" || el.getAttribute(\"data-disabled\") === \"true\";\n}\n",
      "path": "packages/heidi-ui/src/_internal/disabled.ts",
      "target": "components/ui/heidi/_internal/disabled.ts",
      "type": "registry:ui"
    },
    {
      "content": "import type { KeyboardEvent as ReactKeyboardEvent } from \"react\";\n\nconst TABBABLE_SELECTOR = [\n  \"a[href]\",\n  \"area[href]\",\n  \"audio[controls]\",\n  \"button\",\n  \"details > summary:first-of-type\",\n  \"embed\",\n  \"iframe\",\n  \"input\",\n  \"object\",\n  \"select\",\n  \"textarea\",\n  \"video[controls]\",\n  \"[contenteditable]:not([contenteditable='false'])\",\n  \"[tabindex]\"\n].join(\",\");\n\nfunction isActuallyTabbable(element: HTMLElement): boolean {\n  if (\n    element.tabIndex < 0 ||\n    element.closest(\"[hidden], [inert], [aria-hidden='true']\") !== null\n  ) {\n    return false;\n  }\n  if (\n    (element instanceof HTMLButtonElement ||\n      element instanceof HTMLInputElement ||\n      element instanceof HTMLSelectElement ||\n      element instanceof HTMLTextAreaElement) &&\n    (element.disabled || element.matches(\":disabled\"))\n  ) {\n    return false;\n  }\n  if (element instanceof HTMLInputElement && element.type === \"hidden\") {\n    return false;\n  }\n  const style = getComputedStyle(element);\n  return style.display !== \"none\" && style.visibility !== \"hidden\" && element.getClientRects().length > 0;\n}\n\nfunction isActiveRadio(element: HTMLElement, candidates: HTMLElement[]): boolean {\n  if (!(element instanceof HTMLInputElement) || element.type !== \"radio\" || !element.name) {\n    return true;\n  }\n  const group = candidates.filter(\n    (candidate): candidate is HTMLInputElement =>\n      candidate instanceof HTMLInputElement &&\n      candidate.type === \"radio\" &&\n      candidate.name === element.name &&\n      candidate.form === element.form\n  );\n  const checked = group.find((radio) => radio.checked);\n  return checked ? checked === element : group[0] === element;\n}\n\n/** Return the elements reached by sequential keyboard focus in browser order. */\nexport function getHeidiTabbableElements(container: HTMLElement): HTMLElement[] {\n  const candidates = Array.from(\n    container.querySelectorAll<HTMLElement>(TABBABLE_SELECTOR)\n  ).filter(isActuallyTabbable);\n\n  return candidates\n    .filter((element) => isActiveRadio(element, candidates))\n    .map((element, index) => ({ element, index }))\n    .sort((left, right) => {\n      const leftOrder = left.element.tabIndex > 0 ? left.element.tabIndex : Number.MAX_SAFE_INTEGER;\n      const rightOrder = right.element.tabIndex > 0 ? right.element.tabIndex : Number.MAX_SAFE_INTEGER;\n      return leftOrder - rightOrder || left.index - right.index;\n    })\n    .map(({ element }) => element);\n}\n\n/**\n * Restore focus after the browser has settled a top-layer transition.\n *\n * Callers must pass the host captured synchronously from a React event:\n * React clears `SyntheticEvent.currentTarget` after listener dispatch.\n */\nexport function focusHeidiElementNextFrame(element: HTMLElement): void {\n  element.ownerDocument.defaultView?.requestAnimationFrame(() => {\n    if (element.isConnected) {\n      element.focus({ preventScroll: true });\n    }\n  });\n}\n\n/**\n * Keep sequential Tab navigation inside a modal. The native dialog top layer\n * makes the rest of the document inert, but Chromium can still place focus on\n * `body` for one keystroke at either edge; APG requires an immediate wrap.\n */\nexport function containHeidiModalTabFocus(\n  event: ReactKeyboardEvent<HTMLElement>\n): void {\n  if (\n    event.key !== \"Tab\" ||\n    event.defaultPrevented ||\n    event.altKey ||\n    event.ctrlKey ||\n    event.metaKey\n  ) {\n    return;\n  }\n\n  const container = event.currentTarget;\n  const tabbables = getHeidiTabbableElements(container);\n  const active = document.activeElement;\n  const first = tabbables[0];\n  const last = tabbables.at(-1);\n\n  if (!first || !last) {\n    event.preventDefault();\n    container\n      .querySelector<HTMLElement>(\"[data-hui-focus-fallback]\")\n      ?.focus({ preventScroll: true });\n    return;\n  }\n\n  if (event.shiftKey) {\n    if (active === first || !(active instanceof Node) || !container.contains(active)) {\n      event.preventDefault();\n      last.focus();\n    }\n    return;\n  }\n\n  if (active === last || active === container || !(active instanceof Node) || !container.contains(active)) {\n    event.preventDefault();\n    first.focus();\n  }\n}\n",
      "path": "packages/heidi-ui/src/_internal/focus-scope.ts",
      "target": "components/ui/heidi/_internal/focus-scope.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Menu's cancellable change-event details (Base-shaped `details.cancel()`).\n *\n * Root and every rich item hand a consumer the same two shapes, and the\n * factories are the only place `isCanceled` is allowed to become true, so they\n * live together rather than inside the component module that spends them.\n */\n\nexport type MenuRootChangeEventReason =\n  | \"cancel-open\"\n  | \"escape-key\"\n  | \"focus-out\"\n  | \"item-press\"\n  | \"none\"\n  | \"outside-press\"\n  | \"sibling-open\"\n  | \"trigger-hover\"\n  | \"trigger-press\";\n\nexport type MenuRootChangeEventDetails = {\n  /** Cancels Heidi's requested state transition. */\n  cancel: () => void;\n  /** Native event that requested the transition. */\n  event: Event;\n  readonly isCanceled: boolean;\n  reason: MenuRootChangeEventReason;\n  trigger: Element | undefined;\n};\n\nexport function createRootChangeDetails(\n  reason: MenuRootChangeEventReason,\n  event: Event,\n  trigger?: Element\n): MenuRootChangeEventDetails {\n  let canceled = false;\n  return {\n    cancel: () => {\n      canceled = true;\n    },\n    event,\n    get isCanceled() {\n      return canceled;\n    },\n    reason,\n    trigger\n  };\n}\n\nexport type MenuItemChangeEventDetails = {\n  cancel: () => void;\n  event: Event;\n  readonly isCanceled: boolean;\n};\n\nexport function createItemChangeDetails(event: Event): MenuItemChangeEventDetails {\n  let canceled = false;\n  return {\n    cancel: () => {\n      canceled = true;\n    },\n    event,\n    get isCanceled() {\n      return canceled;\n    }\n  };\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-change-details.ts",
      "target": "components/ui/heidi/_internal/menu-change-details.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Menu's React context surface: the Root authority object every part reads,\n * the open/dismiss-zone channels a SubmenuRoot re-scopes, and the four small\n * item contexts an indicator or a labelled group needs.\n *\n * Kept in one module so the shape a part may depend on is legible in one\n * place, and so `useMenuContext` throws the same sentence for every part.\n */\n\nimport { createContext, useContext } from \"react\";\nimport {\n  type MenuItemChangeEventDetails,\n  type MenuRootChangeEventDetails,\n  type MenuRootChangeEventReason\n} from \"./menu-change-details\";\nimport { type FocusTarget } from \"./menu-keyboard-navigation\";\n\nexport type MenuContextValue = {\n  activeTriggerId: string | null;\n  activeTriggerAnchorName: string;\n  activateTrigger: (id: string, element: HTMLElement) => void;\n  cancelTriggerHover: () => void;\n  closeMenuBranches: (\n    parentMenu: HTMLElement,\n    exceptId: string | null,\n    reason: MenuRootChangeEventReason,\n    event: Event,\n    trigger?: Element\n  ) => void;\n  completeOpenChange: (open: boolean) => void;\n  contentId: string;\n  disabled: boolean;\n  getOpen: () => boolean;\n  highlightItemOnHover: boolean;\n  isWithinDismissZone: (target: EventTarget | null) => boolean;\n  isSubmenuPointerGraceActive: () => boolean;\n  loopFocus: boolean;\n  mouseUpSelectionAllowedRef: { current: boolean };\n  requestOpen: (\n    open: boolean,\n    reason: MenuRootChangeEventReason,\n    event: Event,\n    trigger?: Element,\n    focusTarget?: FocusTarget\n  ) => MenuRootChangeEventDetails | null;\n  registerTrigger: (\n    id: string,\n    anchorName: string,\n    element: HTMLElement | null\n  ) => void;\n  registerSubmenu: (id: string, submenu: RegisteredMenuSubmenu | null) => void;\n  restoreFocus: () => void;\n  scheduleSubmenuItemHoverClose: (\n    parentMenu: HTMLElement,\n    event: globalThis.PointerEvent,\n    source: HTMLElement\n  ) => void;\n  scheduleTriggerHoverClose: (\n    event: globalThis.PointerEvent,\n    source: HTMLElement\n  ) => void;\n  scheduleTriggerHoverOpen: (\n    event: globalThis.PointerEvent,\n    trigger: HTMLElement,\n    delay: number,\n    closeDelay: number\n  ) => void;\n  setContentElement: (element: HTMLDivElement | null) => void;\n  setSubmenuPointerGrace: (id: string, active: boolean) => void;\n  submenuCloseDelay: number;\n  submenuOpenDelay: number;\n  takeFocusTarget: () => FocusTarget;\n  triggerRef: { current: HTMLElement | null };\n  wasRecentlyHoverOpened: (trigger: HTMLElement) => boolean;\n};\n\nexport type RegisteredMenuSubmenu = {\n  getOpen: () => boolean;\n  requestClose: (\n    reason: MenuRootChangeEventReason,\n    event: Event,\n    trigger?: Element\n  ) => MenuRootChangeEventDetails | null;\n  schedulePointerClose: (\n    event: globalThis.PointerEvent,\n    source: HTMLElement,\n    reason: MenuRootChangeEventReason\n  ) => void;\n  triggerRef: { current: HTMLElement | null };\n};\n\nexport const MenuContext = createContext<MenuContextValue | null>(null);\nexport const MenuOpenContext = createContext(false);\nexport const MenuDismissLayerContext = createContext<\n  ((target: EventTarget | null) => boolean) | null\n>(null);\n\nexport function useMenuContext(part: string): MenuContextValue {\n  const context = useContext(MenuContext);\n  if (!context) {\n    throw new Error(`Menu.${part} must be rendered inside Menu.Root.`);\n  }\n  return context;\n}\n\nexport function useMenuOpen(): boolean {\n  return useContext(MenuOpenContext);\n}\n\ntype MenuGroupLabelContextValue = {\n  labelId: string;\n  registerLabel: (present: boolean) => void;\n};\n\nexport const MenuGroupLabelContext = createContext<MenuGroupLabelContextValue | null>(null);\n\ntype MenuCheckboxItemContextValue = { checked: boolean; disabled: boolean };\nexport const MenuCheckboxItemContext = createContext<MenuCheckboxItemContextValue | null>(null);\n\ntype MenuRadioGroupContextValue = {\n  disabled: boolean;\n  requestValue: (value: string, event: Event) => MenuItemChangeEventDetails | null;\n  value: string | undefined;\n};\nexport const MenuRadioGroupContext = createContext<MenuRadioGroupContextValue | null>(null);\n\ntype MenuRadioItemContextValue = { checked: boolean; disabled: boolean };\nexport const MenuRadioItemContext = createContext<MenuRadioItemContextValue | null>(null);\n\nexport type MenuSubContextValue = {\n  anchorName: string;\n  cancelPointerTimers: () => void;\n  contentId: string;\n  contentRef: { current: HTMLElement | null };\n  focusOnOpen: () => boolean;\n  getEffectiveOpen: () => boolean;\n  getOpen: () => boolean;\n  getParentEffectiveOpen: () => boolean;\n  requestOpen: (\n    open: boolean,\n    reason: MenuRootChangeEventReason,\n    event: Event,\n    trigger?: Element,\n    focus?: boolean\n  ) => MenuRootChangeEventDetails | null;\n  schedulePointerClose: (event: globalThis.PointerEvent, source: HTMLElement) => void;\n  schedulePointerOpen: (\n    event: globalThis.PointerEvent,\n    trigger: HTMLElement,\n    delay: number\n  ) => void;\n  setContentElement: (element: HTMLElement | null) => void;\n  setPointerConfig: (enabled: boolean, closeDelay: number) => void;\n  setTriggerElement: (element: HTMLElement | null) => void;\n  triggerId: string;\n  triggerRef: { current: HTMLElement | null };\n};\n\nexport const MenuSubContext = createContext<MenuSubContextValue | null>(null);\nexport const MenuSubOpenContext = createContext(false);\n\nexport function useMenuSubContext(part: string): MenuSubContextValue {\n  const context = useContext(MenuSubContext);\n  if (!context) {\n    throw new Error(`Menu.${part} must be rendered inside Menu.SubmenuRoot.`);\n  }\n  return context;\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-context.ts",
      "target": "components/ui/heidi/_internal/menu-context.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Menu's host-attribute and trigger-registry primitives.\n *\n * The `data-open`/`data-closed`/`data-checked` pairs are a published styling\n * surface, so every part must emit them from one place; the rest is the\n * trigger bookkeeping and the synthetic click that a press-drag-release\n * gesture needs. Plain functions, no menu-directory dependencies.\n */\n\nimport { type ComponentPropsWithoutRef, type MouseEvent } from \"react\";\n\nexport type NativeHostProps<Tag extends keyof HTMLElementTagNameMap> = Omit<\n  ComponentPropsWithoutRef<Tag>,\n  \"children\" | \"className\" | \"ref\" | \"style\"\n>;\n\nexport type MenuTriggerHoverSession = {\n  closeDelay: number;\n  openedAt: number;\n  trigger: HTMLElement;\n};\n\nexport type RegisteredMenuTrigger = {\n  anchorName: string;\n  element: HTMLElement;\n};\n\nexport function firstRegisteredTrigger(\n  triggers: Map<string, RegisteredMenuTrigger>\n): [string, RegisteredMenuTrigger] | undefined {\n  return [...triggers.entries()]\n    .filter(([, trigger]) => trigger.element.isConnected)\n    .sort((left, right) => {\n      const position = left[1].element.compareDocumentPosition(right[1].element);\n      return position & Node.DOCUMENT_POSITION_PRECEDING ? 1 : -1;\n    })[0];\n}\n\nexport function dataState(open: boolean): \"closed\" | \"open\" {\n  return open ? \"open\" : \"closed\";\n}\n\nexport function openStateAttributes(open: boolean): Record<string, true | undefined> {\n  return open\n    ? { \"data-closed\": undefined, \"data-open\": true }\n    : { \"data-closed\": true, \"data-open\": undefined };\n}\n\nexport function checkedStateAttributes(checked: boolean): Record<string, true | undefined> {\n  return checked\n    ? { \"data-checked\": true, \"data-unchecked\": undefined }\n    : { \"data-checked\": undefined, \"data-unchecked\": true };\n}\n\nexport function showPopoverFrom(element: HTMLElement, source?: HTMLElement | null): void {\n  const show = element.showPopover as unknown as (\n    this: HTMLElement,\n    options?: { source?: HTMLElement }\n  ) => void;\n  if (source) {\n    show.call(element, { source });\n  } else {\n    show.call(element);\n  }\n}\n\nexport function dispatchMouseGestureClick(\n  target: HTMLElement,\n  sourceEvent: MouseEvent<HTMLElement>\n): void {\n  const ownerWindow = target.ownerDocument.defaultView;\n  const EventConstructor = ownerWindow?.PointerEvent ?? ownerWindow?.MouseEvent;\n  if (!EventConstructor) {\n    target.click();\n    return;\n  }\n  target.dispatchEvent(\n    new EventConstructor(\"click\", {\n      altKey: sourceEvent.altKey,\n      bubbles: true,\n      cancelable: true,\n      composed: true,\n      ctrlKey: sourceEvent.ctrlKey,\n      detail: 1,\n      metaKey: sourceEvent.metaKey,\n      shiftKey: sourceEvent.shiftKey\n    })\n  );\n}\n\nexport const DISABLED_MENU_PRESS_HANDLERS = [\n  \"onClick\",\n  \"onKeyDown\",\n  \"onKeyUp\",\n  \"onMouseDown\",\n  \"onPointerDown\"\n] as const;\n",
      "path": "packages/heidi-ui/src/_internal/menu-host-state.ts",
      "target": "components/ui/heidi/_internal/menu-host-state.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared menu keyboard + pointer helpers — Menu + ContextMenu (+ nested SubContent).\n * Items are scoped to the nearest role=menu so nested submenu menuitems are\n * not part of the parent menu's ArrowUp/ArrowDown ring.\n */\n\nimport { isDisabledElement } from \"./disabled\";\n\nexport type MenuItemsOptions = {\n  /**\n   * APG menus keep disabled items in the roving-focus order. Pass false only\n   * for non-menu listbox-style consumers that intentionally omit them.\n   */\n  includeDisabled?: boolean;\n};\n\nexport function menuItemsIn(container: HTMLElement): HTMLElement[];\nexport function menuItemsIn(\n  container: HTMLElement,\n  options: MenuItemsOptions & { includeDisabled: true }\n): HTMLElement[];\nexport function menuItemsIn(\n  container: HTMLElement,\n  options: MenuItemsOptions\n): HTMLElement[];\nexport function menuItemsIn(\n  container: HTMLElement,\n  options: MenuItemsOptions = { includeDisabled: true }\n): HTMLElement[] {\n  return [\n    ...container.querySelectorAll<HTMLElement>(\n      '[role=\"menuitem\"], [role=\"menuitemcheckbox\"], [role=\"menuitemradio\"]'\n    )\n  ].filter((element) => {\n    // A genuinely disabled native control cannot receive focus. It must never\n    // enter a menu focus ring, even though aria-disabled menu items remain\n    // discoverable per APG and Base UI's focusable-when-disabled contract.\n    if (element.matches(\":disabled\")) {\n      return false;\n    }\n    if (options.includeDisabled === false && isDisabledElement(element)) {\n      return false;\n    }\n    if (\n      element.closest('[role=\"menu\"]') !== container ||\n      element.closest(\"[hidden], [inert], [aria-hidden='true']\") !== null ||\n      element.getClientRects().length === 0\n    ) {\n      return false;\n    }\n    const styles = element.ownerDocument.defaultView?.getComputedStyle(element);\n    return styles?.display !== \"none\" && styles?.visibility !== \"hidden\";\n  });\n}\n\nexport type OpenSubmenuOptions = {\n  /** When true (default), focus the first enabled item after open (keyboard). */\n  focus?: boolean;\n};\n\n/** Open a submenu from its trigger (menuitem + aria-haspopup=menu). */\nexport function openSubmenuFromTrigger(\n  trigger: HTMLElement,\n  options: OpenSubmenuOptions = {}\n): HTMLElement | null {\n  const focus = options.focus !== false;\n  const targetId = trigger.getAttribute(\"popovertarget\");\n  if (!targetId) {\n    return null;\n  }\n  const sub = trigger.ownerDocument.getElementById(targetId);\n  if (!sub || typeof sub.showPopover !== \"function\") {\n    return null;\n  }\n  closeSiblingSubmenus(sub);\n  try {\n    sub.showPopover();\n  } catch {\n    return null;\n  }\n  if (focus) {\n    menuItemsIn(sub, { includeDisabled: false })[0]?.focus();\n  }\n  return sub;\n}\n\n/** Hide every open nested role=menu under parentMenu (not parentMenu itself). */\nexport function closeDescendantSubmenus(parentMenu: HTMLElement): void {\n  for (const el of parentMenu.querySelectorAll<HTMLElement>('[role=\"menu\"]')) {\n    if (el === parentMenu) {\n      continue;\n    }\n    if (el.matches(\":popover-open\") && typeof el.hidePopover === \"function\") {\n      try {\n        el.hidePopover();\n      } catch {\n        // ignore\n      }\n    }\n  }\n}\n\nfunction closeSiblingSubmenus(except: HTMLElement): void {\n  const parentMenu = except.parentElement?.closest('[role=\"menu\"]');\n  if (!parentMenu) {\n    return;\n  }\n  for (const el of parentMenu.querySelectorAll<HTMLElement>('[role=\"menu\"]')) {\n    if (el === except || el === parentMenu) {\n      continue;\n    }\n    if (el.matches(\":popover-open\") && typeof el.hidePopover === \"function\") {\n      try {\n        el.hidePopover();\n      } catch {\n        // ignore\n      }\n    }\n  }\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-items.ts",
      "target": "components/ui/heidi/_internal/menu-items.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Menu's APG keyboard model: buffered typeahead, arrow/Home/End focus\n * movement, real sequential Tab targets, and the enabled-only initial item.\n *\n * Root Content and SubContent run byte-identical keyboard logic, so it lives\n * beside them rather than inside either one.\n */\n\nimport { type KeyboardEvent } from \"react\";\nimport { getHeidiTabbableElements } from \"./focus-scope\";\nimport { menuItemsIn } from \"./menu-items\";\n\nexport type FocusTarget = \"first\" | \"last\" | \"none\";\n\nexport type TypeaheadState = {\n  buffer: string;\n  timer: ReturnType<typeof setTimeout> | null;\n};\n\nexport function resetTypeahead(state: TypeaheadState): void {\n  if (state.timer !== null) {\n    clearTimeout(state.timer);\n  }\n  state.buffer = \"\";\n  state.timer = null;\n}\n\nfunction normalizedItemLabel(item: HTMLElement): string {\n  return (item.dataset.label ?? item.getAttribute(\"aria-label\") ?? item.textContent ?? \"\")\n    .trim()\n    .toLocaleLowerCase();\n}\n\nexport function runTypeahead(menu: HTMLElement, key: string, state: TypeaheadState): void {\n  if (state.timer !== null) {\n    clearTimeout(state.timer);\n  }\n  state.buffer += key.toLocaleLowerCase();\n  state.timer = setTimeout(() => {\n    state.buffer = \"\";\n    state.timer = null;\n  }, 500);\n\n  const query = [...state.buffer].every((character) => character === state.buffer[0])\n    ? state.buffer[0]\n    : state.buffer;\n  const items = menuItemsIn(menu, { includeDisabled: true });\n  const activeIndex = items.indexOf(menu.ownerDocument.activeElement as HTMLElement);\n  const ordered = [...items.slice(activeIndex + 1), ...items.slice(0, activeIndex + 1)];\n  const match = ordered.find((item) => normalizedItemLabel(item).startsWith(query));\n  match?.focus({ preventScroll: true });\n  match?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n}\n\nexport function extendActiveTypeaheadWithSpace(\n  event: KeyboardEvent<HTMLDivElement>,\n  state: TypeaheadState\n): void {\n  const sourceMenu = (event.target as HTMLElement | null)?.closest('[role=\"menu\"]');\n  if (\n    sourceMenu !== event.currentTarget ||\n    event.key !== \" \" ||\n    state.buffer.length === 0 ||\n    event.altKey ||\n    event.ctrlKey ||\n    event.metaKey ||\n    event.nativeEvent.isComposing\n  ) {\n    return;\n  }\n  event.preventDefault();\n  event.stopPropagation();\n  runTypeahead(event.currentTarget, event.key, state);\n}\n\nexport function moveMenuFocus(\n  menu: HTMLElement,\n  key: \"ArrowDown\" | \"ArrowUp\" | \"End\" | \"Home\",\n  loopFocus: boolean,\n  closeChildMenus: () => void\n): void {\n  const items = menuItemsIn(menu, { includeDisabled: true });\n  if (items.length === 0) {\n    return;\n  }\n  const activeIndex = items.indexOf(menu.ownerDocument.activeElement as HTMLElement);\n  let nextIndex: number;\n  if (key === \"Home\") {\n    nextIndex = 0;\n  } else if (key === \"End\") {\n    nextIndex = items.length - 1;\n  } else if (key === \"ArrowUp\") {\n    nextIndex = activeIndex < 0 ? items.length - 1 : activeIndex - 1;\n    if (nextIndex < 0) {\n      nextIndex = loopFocus ? items.length - 1 : 0;\n    }\n  } else {\n    nextIndex = activeIndex < 0 ? 0 : activeIndex + 1;\n    if (nextIndex >= items.length) {\n      nextIndex = loopFocus ? 0 : items.length - 1;\n    }\n  }\n  closeChildMenus();\n  const item = items[nextIndex];\n  item?.focus({ preventScroll: true });\n  item?.scrollIntoView({ block: \"nearest\", inline: \"nearest\" });\n}\n\nexport function tabTargetAfterTrigger(trigger: HTMLElement | null): HTMLElement | null {\n  if (!trigger) {\n    return null;\n  }\n  const focusScope =\n    trigger.closest<HTMLElement>(\"dialog:modal\") ?? trigger.ownerDocument.body;\n  const candidates = getHeidiTabbableElements(focusScope).filter(\n    (element) => element.closest('[role=\"menu\"]') === null\n  );\n  const index = candidates.indexOf(trigger);\n  if (index < 0) {\n    return null;\n  }\n  return candidates[index + 1] ?? null;\n}\n\nexport function initialMenuItem(\n  menu: HTMLElement,\n  target: Exclude<FocusTarget, \"none\">\n): HTMLElement | undefined {\n  const enabled = menuItemsIn(menu, { includeDisabled: false });\n  return target === \"last\" ? enabled.at(-1) : enabled[0];\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-keyboard-navigation.ts",
      "target": "components/ui/heidi/_internal/menu-keyboard-navigation.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Menu's composed light-dismiss layer for native `[popover=manual]` popups.\n *\n * Manual popovers get no platform light dismiss, so Menu mirrors the platform\n * algorithm itself. Extracted from `menu/menu.tsx` unchanged: Root and every\n * SubmenuRoot mount this same hook, and the pointer/focus/Escape rules it\n * encodes are the contract, not an implementation detail of either caller.\n */\n\nimport { useEffect } from \"react\";\nimport { type MenuRootChangeEventDetails } from \"./menu-change-details\";\n\ntype MenuManualDismissOptions = {\n  contentRef: { current: HTMLElement | null };\n  getOwnerDocument: () => Document | null;\n  isWithinParentZone?: (target: EventTarget | null) => boolean;\n  isWithinZone: (target: EventTarget | null) => boolean;\n  open: boolean;\n  requestClose: (\n    reason: \"escape-key\" | \"focus-out\" | \"outside-press\",\n    event: Event\n  ) => MenuRootChangeEventDetails | null;\n};\n\nexport function menuOwnsKeyboardTarget(\n  menu: HTMLElement,\n  target: EventTarget | null\n): boolean {\n  if (!(target instanceof Element) || target.closest('[role=\"menu\"]') !== menu) {\n    return false;\n  }\n  const dialog = target.closest(\"dialog,[role='dialog'],[role='alertdialog']\");\n  if (dialog && dialog !== menu && menu.contains(dialog)) {\n    return false;\n  }\n  const popover = target.closest<HTMLElement>(\"[popover]\");\n  return !(popover && popover !== menu && menu.contains(popover));\n}\n\nexport function focusMovedIntoNestedLayer(\n  menu: HTMLElement | null,\n  activeElement: Element | null,\n  ownerDocument: Document\n): boolean {\n  if (\n    !(activeElement instanceof HTMLElement) ||\n    !activeElement.isConnected ||\n    activeElement === ownerDocument.body\n  ) {\n    return false;\n  }\n  if (!menu?.contains(activeElement)) {\n    return true;\n  }\n  const dialog = activeElement.closest(\n    \"dialog[open],[role='dialog'],[role='alertdialog']\"\n  );\n  if (dialog && dialog !== menu && menu.contains(dialog)) {\n    return true;\n  }\n  const popover = activeElement.closest<HTMLElement>(\"[popover]\");\n  return Boolean(\n    popover &&\n      popover !== menu &&\n      menu.contains(popover) &&\n      popover.matches(\":popover-open\")\n  );\n}\n\n/**\n * Manual popovers keep every composed Trigger—native button or otherwise—in\n * one dismissal zone. This mirrors the platform light-dismiss algorithm:\n * pointer down and up must both occur outside, canceled drags do not dismiss,\n * focus leaving without a pointer closes as focus-out, and Escape only acts\n * on the menu layer containing the event target.\n */\nexport function useMenuManualDismiss({\n  contentRef,\n  getOwnerDocument,\n  isWithinParentZone,\n  isWithinZone,\n  open,\n  requestClose\n}: MenuManualDismissOptions): void {\n  useEffect(() => {\n    if (!open) {\n      return;\n    }\n    const ownerDocument = getOwnerDocument();\n    if (!ownerDocument) {\n      return;\n    }\n\n    let focusWithin = isWithinZone(ownerDocument.activeElement);\n    let ownedModalDialog: HTMLDialogElement | null = null;\n    let pointerDownOutside: boolean | null = null;\n    let pendingFocusOutside: globalThis.FocusEvent | null = null;\n\n    const isWithinOwnedModalDialog = (target: EventTarget | null) => {\n      if (\n        ownedModalDialog &&\n        (!ownedModalDialog.isConnected || !ownedModalDialog.matches(\":modal\"))\n      ) {\n        ownedModalDialog = null;\n      }\n      return target instanceof Node && Boolean(ownedModalDialog?.contains(target));\n    };\n\n    const isWithinComposedZone = (target: EventTarget | null) =>\n      isWithinZone(target) || isWithinOwnedModalDialog(target);\n\n    const restoreCanceledFocus = (event?: globalThis.FocusEvent) => {\n      const relatedTarget = event?.relatedTarget;\n      const fallback = ownerDocument.activeElement;\n      const candidate =\n        relatedTarget instanceof HTMLElement && isWithinZone(relatedTarget)\n          ? relatedTarget\n          : fallback instanceof HTMLElement && isWithinZone(fallback)\n            ? fallback\n            : contentRef.current;\n      ownerDocument.defaultView?.requestAnimationFrame(() => {\n        if (candidate?.isConnected) {\n          candidate.focus({ preventScroll: true });\n        }\n      });\n    };\n\n    const requestFocusClose = (event: globalThis.FocusEvent) => {\n      const details = requestClose(\"focus-out\", event);\n      if (details?.isCanceled) {\n        restoreCanceledFocus(event);\n      }\n    };\n\n    const handlePointerDown = (event: globalThis.PointerEvent) => {\n      if (isWithinParentZone && !isWithinParentZone(event.target)) {\n        pointerDownOutside = null;\n        pendingFocusOutside = null;\n        return;\n      }\n      pointerDownOutside = !isWithinComposedZone(event.target);\n      pendingFocusOutside = null;\n    };\n    const handlePointerUp = (event: globalThis.PointerEvent) => {\n      if (isWithinParentZone && !isWithinParentZone(event.target)) {\n        pointerDownOutside = null;\n        pendingFocusOutside = null;\n        return;\n      }\n      const startedOutside = pointerDownOutside === true;\n      pointerDownOutside = null;\n      const pendingFocus = pendingFocusOutside;\n      pendingFocusOutside = null;\n      if (startedOutside && !isWithinComposedZone(event.target)) {\n        const details = requestClose(\"outside-press\", event);\n        if (details?.isCanceled) {\n          restoreCanceledFocus(pendingFocus ?? undefined);\n        }\n        return;\n      }\n      if (pendingFocus) {\n        requestFocusClose(pendingFocus);\n      }\n    };\n    const handlePointerCancel = () => {\n      pointerDownOutside = null;\n      const pendingFocus = pendingFocusOutside;\n      pendingFocusOutside = null;\n      if (pendingFocus) {\n        requestFocusClose(pendingFocus);\n      }\n    };\n    const handleFocusIn = (event: globalThis.FocusEvent) => {\n      if (isWithinParentZone && !isWithinParentZone(event.target)) {\n        focusWithin = false;\n        pendingFocusOutside = null;\n        return;\n      }\n      if (isWithinZone(event.target)) {\n        focusWithin = true;\n        pendingFocusOutside = null;\n        return;\n      }\n      const leftZone = focusWithin || isWithinZone(event.relatedTarget);\n      const modalDialog =\n        event.target instanceof Element\n          ? event.target.closest<HTMLDialogElement>(\"dialog:modal\")\n          : null;\n      if (\n        modalDialog &&\n        (modalDialog === ownedModalDialog || leftZone)\n      ) {\n        ownedModalDialog = modalDialog;\n        focusWithin = true;\n        pendingFocusOutside = null;\n        return;\n      }\n      focusWithin = false;\n      if (!leftZone) {\n        return;\n      }\n      if (pointerDownOutside !== null) {\n        pendingFocusOutside = event;\n        return;\n      }\n      requestFocusClose(event);\n    };\n    const handleKeyDown = (event: globalThis.KeyboardEvent) => {\n      const content = contentRef.current;\n      if (\n        event.defaultPrevented ||\n        event.isComposing ||\n        event.key !== \"Escape\" ||\n        !isWithinZone(event.target) ||\n        !content ||\n        !menuOwnsKeyboardTarget(content, event.target)\n      ) {\n        return;\n      }\n      const details = requestClose(\"escape-key\", event);\n      if (details) {\n        event.preventDefault();\n        event.stopPropagation();\n      }\n    };\n\n    ownerDocument.addEventListener(\"focusin\", handleFocusIn, true);\n    ownerDocument.addEventListener(\"keydown\", handleKeyDown);\n    ownerDocument.addEventListener(\"pointercancel\", handlePointerCancel, true);\n    ownerDocument.addEventListener(\"pointerdown\", handlePointerDown, true);\n    ownerDocument.addEventListener(\"pointerup\", handlePointerUp, true);\n    return () => {\n      ownerDocument.removeEventListener(\"focusin\", handleFocusIn, true);\n      ownerDocument.removeEventListener(\"keydown\", handleKeyDown);\n      ownerDocument.removeEventListener(\"pointercancel\", handlePointerCancel, true);\n      ownerDocument.removeEventListener(\"pointerdown\", handlePointerDown, true);\n      ownerDocument.removeEventListener(\"pointerup\", handlePointerUp, true);\n    };\n  }, [\n    contentRef,\n    getOwnerDocument,\n    isWithinParentZone,\n    isWithinZone,\n    open,\n    requestClose\n  ]);\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-manual-dismiss.ts",
      "target": "components/ui/heidi/_internal/menu-manual-dismiss.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Menu's lazy-presence and motion-settling routine for top-layer popups.\n *\n * ponytail: this deliberately does NOT use `waitForElementAnimations` from\n * `animation-wait`. Menu's routine is callback-shaped rather than awaited,\n * returns a canceller, subscribes to `finish`/`cancel` instead of racing\n * `animation.finished`, and falls back to computed CSS where `getAnimations`\n * is absent. That distinction is contract-locked in 20b; moving the code out\n * of `menu/menu.tsx` must not be read as an invitation to finish an\n * extraction that was declined on purpose.\n */\n\nimport { useCallback, useEffect, useRef, useState } from \"react\";\nimport {\n  finiteAnimationDuration,\n  MAX_ANIMATION_WAIT_MS\n} from \"./animation-wait\";\nimport { useHeidiLayoutEffect } from \"./use-layout-effect\";\n\ntype PresenceApi = {\n  scheduleUnmount: (element: HTMLElement) => void;\n  shouldRender: boolean;\n};\n\nfunction parseCssTimeList(value: string): number[] {\n  return value.split(\",\").map((part) => {\n    const time = part.trim();\n    const parsed = Number.parseFloat(time);\n    if (!Number.isFinite(parsed)) {\n      return 0;\n    }\n    return time.endsWith(\"ms\") ? parsed : parsed * 1000;\n  });\n}\n\nfunction computedPopoverMotionDuration(element: HTMLElement): number {\n  const view = element.ownerDocument.defaultView;\n  const computed = view?.getComputedStyle(element) ?? getComputedStyle(element);\n  const transitionProperties = computed.transitionProperty.split(\",\");\n  const transitionDurations = parseCssTimeList(computed.transitionDuration);\n  const transitionDelays = parseCssTimeList(computed.transitionDelay);\n  const transitionCount = Math.max(\n    transitionProperties.length,\n    transitionDurations.length,\n    transitionDelays.length\n  );\n  let transitionMs = 0;\n  for (let index = 0; index < transitionCount; index += 1) {\n    const property = transitionProperties[index % transitionProperties.length]?.trim();\n    if (property === \"none\") {\n      continue;\n    }\n    transitionMs = Math.max(\n      transitionMs,\n      Math.max(\n        0,\n        (transitionDurations[index % transitionDurations.length] ?? 0) +\n          (transitionDelays[index % transitionDelays.length] ?? 0)\n      )\n    );\n  }\n\n  const animationNames = computed.animationName.split(\",\");\n  const animationDurations = parseCssTimeList(computed.animationDuration);\n  const animationDelays = parseCssTimeList(computed.animationDelay);\n  const animationIterations = computed.animationIterationCount\n    .split(\",\")\n    .map((part) => Number.parseFloat(part.trim()));\n  const animationCount = Math.max(\n    animationNames.length,\n    animationDurations.length,\n    animationDelays.length,\n    animationIterations.length\n  );\n  let animationMs = 0;\n  for (let index = 0; index < animationCount; index += 1) {\n    const name = animationNames[index % animationNames.length]?.trim();\n    const iterations = animationIterations[index % animationIterations.length];\n    if (name === \"none\" || !Number.isFinite(iterations)) {\n      continue;\n    }\n    animationMs = Math.max(\n      animationMs,\n      Math.max(\n        0,\n        (animationDurations[index % animationDurations.length] ?? 0) *\n          Math.max(0, iterations ?? 0) +\n          (animationDelays[index % animationDelays.length] ?? 0)\n      )\n    );\n  }\n\n  return Math.max(transitionMs, animationMs);\n}\n\n/**\n * Waits for authored finite motion without allowing an infinite, paused, or\n * engine-orphaned Animation.finished promise to retain content forever.\n */\nfunction afterPopoverAnimations(\n  element: HTMLElement,\n  complete: () => void\n): () => void {\n  const view = element.ownerDocument.defaultView ?? window;\n  const canObserveAnimations = typeof element.getAnimations === \"function\";\n  const animations =\n    canObserveAnimations\n      ? element\n          .getAnimations()\n          .map((animation) => ({\n            animation,\n            duration: finiteAnimationDuration(animation)\n          }))\n          .filter(\n            (entry): entry is { animation: Animation; duration: number } =>\n              entry.duration !== undefined &&\n              entry.duration > 0 &&\n              entry.animation.playState !== \"finished\" &&\n              entry.animation.playState !== \"idle\"\n          )\n      : [];\n  const observedDuration = animations.reduce(\n    (maximum, entry) => Math.max(maximum, entry.duration),\n    0\n  );\n  // Modern engines expose only motion that actually started. Computed CSS\n  // declarations are a fallback for older engines, not evidence of motion.\n  const duration = canObserveAnimations\n    ? observedDuration\n    : computedPopoverMotionDuration(element);\n  if (animations.length === 0 && duration <= 0) {\n    complete();\n    return () => undefined;\n  }\n\n  let completed = false;\n  let timeout = 0;\n  const pendingAnimations = new Set(animations.map(({ animation }) => animation));\n  const removeAnimationListeners = () => {\n    for (const animation of pendingAnimations) {\n      animation.removeEventListener(\"cancel\", handleAnimationEnd);\n      animation.removeEventListener(\"finish\", handleAnimationEnd);\n    }\n    pendingAnimations.clear();\n  };\n  const finishOnce = () => {\n    if (completed) {\n      return;\n    }\n    completed = true;\n    view.clearTimeout(timeout);\n    removeAnimationListeners();\n    complete();\n  };\n  function handleAnimationEnd(event: Event) {\n    markAnimationComplete(event.currentTarget as Animation);\n  }\n  function markAnimationComplete(animation: Animation) {\n    animation.removeEventListener(\"cancel\", handleAnimationEnd);\n    animation.removeEventListener(\"finish\", handleAnimationEnd);\n    pendingAnimations.delete(animation);\n    if (pendingAnimations.size === 0) {\n      finishOnce();\n    }\n  }\n  timeout = view.setTimeout(\n    finishOnce,\n    Math.min(MAX_ANIMATION_WAIT_MS, duration + 250)\n  );\n  for (const animation of pendingAnimations) {\n    animation.addEventListener(\"cancel\", handleAnimationEnd);\n    animation.addEventListener(\"finish\", handleAnimationEnd);\n    if (animation.playState === \"finished\" || animation.playState === \"idle\") {\n      markAnimationComplete(animation);\n    }\n  }\n  return () => {\n    completed = true;\n    view.clearTimeout(timeout);\n    removeAnimationListeners();\n  };\n}\n\nexport function usePopoverPresence(\n  open: boolean,\n  keepMounted: boolean,\n  getOpen: () => boolean\n): PresenceApi {\n  const [present, setPresent] = useState(open);\n  const runRef = useRef(0);\n  const cancelAnimationWaitRef = useRef<() => void>(() => undefined);\n\n  useHeidiLayoutEffect(() => {\n    if (open) {\n      runRef.current += 1;\n      cancelAnimationWaitRef.current();\n      cancelAnimationWaitRef.current = () => undefined;\n      setPresent(true);\n    }\n  }, [open]);\n\n  const scheduleUnmount = useCallback(\n    (element: HTMLElement) => {\n      cancelAnimationWaitRef.current();\n      cancelAnimationWaitRef.current = () => undefined;\n      if (keepMounted) {\n        return;\n      }\n      const run = ++runRef.current;\n      const view = element.ownerDocument.defaultView ?? window;\n      let canceled = false;\n      const frame = view.requestAnimationFrame(() => {\n        if (canceled) {\n          return;\n        }\n        const finish = () => {\n          if (run === runRef.current && !getOpen()) {\n            setPresent(false);\n          }\n        };\n        cancelAnimationWaitRef.current = afterPopoverAnimations(element, finish);\n      });\n      cancelAnimationWaitRef.current = () => {\n        canceled = true;\n        view.cancelAnimationFrame(frame);\n      };\n    },\n    [getOpen, keepMounted]\n  );\n\n  useEffect(\n    () => () => {\n      runRef.current += 1;\n      cancelAnimationWaitRef.current();\n    },\n    []\n  );\n\n  return { scheduleUnmount, shouldRender: keepMounted || open || present };\n}\n\nexport function completeAfterPopoverAnimations(\n  element: HTMLElement,\n  expectedOpen: boolean,\n  complete: () => void\n): () => void {\n  const view = element.ownerDocument.defaultView ?? window;\n  let canceled = false;\n  let cancelWait: () => void = () => undefined;\n  const frame = view.requestAnimationFrame(() => {\n    if (canceled) {\n      return;\n    }\n    let completed = false;\n    const finishOnce = () => {\n      if (completed) {\n        return;\n      }\n      completed = true;\n      if (element.matches(\":popover-open\") === expectedOpen) {\n        complete();\n      }\n    };\n    cancelWait = afterPopoverAnimations(element, finishOnce);\n  });\n  return () => {\n    canceled = true;\n    view.cancelAnimationFrame(frame);\n    cancelWait();\n  };\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-popover-presence.ts",
      "target": "components/ui/heidi/_internal/menu-popover-presence.ts",
      "type": "registry:ui"
    },
    {
      "content": "\"use client\";\n\nimport { type RefObject, useEffect } from \"react\";\n\nconst SHIFT_X = \"--_hui-menu-viewport-shift-x\";\nconst SHIFT_Y = \"--_hui-menu-viewport-shift-y\";\n\nfunction clearViewportShift(element: HTMLElement): void {\n  element.style.setProperty(SHIFT_X, \"0px\");\n  element.style.setProperty(SHIFT_Y, \"0px\");\n}\n\nexport function clampMenuToVisualViewport(element: HTMLElement): void {\n  clearViewportShift(element);\n  const rect = element.getBoundingClientRect();\n  if (rect.width === 0 || rect.height === 0) {\n    return;\n  }\n\n  const viewport = window.visualViewport;\n  const viewportLeft = viewport?.offsetLeft ?? 0;\n  const viewportTop = viewport?.offsetTop ?? 0;\n  const viewportRight = viewportLeft + (viewport?.width ?? window.innerWidth);\n  const viewportBottom = viewportTop + (viewport?.height ?? window.innerHeight);\n  const rootFontSize = Number.parseFloat(\n    getComputedStyle(document.documentElement).fontSize\n  );\n  // menu.base.css reserves one rem total, split evenly across both edges.\n  const gutter = Number.isFinite(rootFontSize) ? rootFontSize / 2 : 8;\n  const minX = viewportLeft + gutter;\n  const maxX = viewportRight - gutter;\n  const minY = viewportTop + gutter;\n  const maxY = viewportBottom - gutter;\n  const shiftX = rect.left < minX\n    ? minX - rect.left\n    : rect.right > maxX\n      ? maxX - rect.right\n      : 0;\n  const shiftY = rect.top < minY\n    ? minY - rect.top\n    : rect.bottom > maxY\n      ? maxY - rect.bottom\n      : 0;\n\n  element.style.setProperty(SHIFT_X, `${shiftX}px`);\n  element.style.setProperty(SHIFT_Y, `${shiftY}px`);\n}\n\n/**\n * CSS anchor fallbacks choose a side, then this hook corrects a browser edge\n * case where a fixed top-layer popup is clamped against the document rather\n * than the currently visible scrollport. The shift is physical because\n * getBoundingClientRect and the visual viewport are physical coordinates.\n */\nexport function useMenuViewportClamp(\n  elementRef: RefObject<HTMLElement | null>,\n  open: boolean\n): void {\n  useEffect(() => {\n    const element = elementRef.current;\n    if (!element) {\n      return undefined;\n    }\n    if (!open) {\n      clearViewportShift(element);\n      return undefined;\n    }\n\n    let frame = 0;\n    const scheduleClamp = () => {\n      window.cancelAnimationFrame(frame);\n      frame = window.requestAnimationFrame(() => {\n        if (element.isConnected && element.matches(\":popover-open\")) {\n          clampMenuToVisualViewport(element);\n        }\n      });\n    };\n    const resizeObserver = new ResizeObserver(scheduleClamp);\n    resizeObserver.observe(element);\n    window.addEventListener(\"resize\", scheduleClamp);\n    window.addEventListener(\"scroll\", scheduleClamp, true);\n    window.visualViewport?.addEventListener(\"resize\", scheduleClamp);\n    window.visualViewport?.addEventListener(\"scroll\", scheduleClamp);\n    scheduleClamp();\n\n    return () => {\n      window.cancelAnimationFrame(frame);\n      resizeObserver.disconnect();\n      window.removeEventListener(\"resize\", scheduleClamp);\n      window.removeEventListener(\"scroll\", scheduleClamp, true);\n      window.visualViewport?.removeEventListener(\"resize\", scheduleClamp);\n      window.visualViewport?.removeEventListener(\"scroll\", scheduleClamp);\n      clearViewportShift(element);\n    };\n  }, [elementRef, open]);\n}\n",
      "path": "packages/heidi-ui/src/_internal/menu-viewport-clamp.ts",
      "target": "components/ui/heidi/_internal/menu-viewport-clamp.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Pushing React's open state onto the native popover, once (P5).\n *\n * Popover, Toast, Select, NavigationMenu and Menu (root + submenu) each carried\n * this block. It exists because `showPopover()`/`hidePopover()` fire `toggle`\n * synchronously, and the `toggle` listener is also what reconciles NATIVE\n * dismissal (Esc, light dismiss) back into React. Without a marker, every\n * React-driven open would look like a user-driven one and echo a redundant\n * open-change request back to the owner.\n *\n * ponytail: six of the seven copies the audit counted share this boolean-flag\n * model and differ only in how they SHOW — four call `element.showPopover()`,\n * Menu's two call `showPopoverFrom(element, trigger)` so the popover anchors to\n * its trigger. That is the `show` option and nothing else.\n *\n * ContextMenu is the seventh and does NOT adopt this. It marks transitions by\n * pushing onto a queue that a later `toggle` drains, rather than by raising a\n * flag it lowers in `finally`. Those answer \"is this transition ours?\" at\n * different times — synchronously inside the call, versus whenever the event\n * arrives — and a nested context menu can have more than one transition in\n * flight, which is what the queue is for. Forcing it into the flag model would\n * be a rewrite of its reentrancy handling to make a count read 1 instead of 7,\n * which is the same trade P6 and P9 declined.\n */\n\nexport type NativePopoverSyncOptions = {\n  /**\n   * Anchored show, for popovers that position against a trigger. Defaults to\n   * `element.showPopover()`.\n   */\n  show?: (element: HTMLElement) => void;\n  /**\n   * Raised for the duration of the native call so the component's own `toggle`\n   * listener can tell its own transition from a user's.\n   */\n  transitionRef: { current: boolean };\n};\n\nexport function synchronizeNativePopoverOpen(\n  element: HTMLElement,\n  next: boolean,\n  { show, transitionRef }: NativePopoverSyncOptions\n): void {\n  if (element.matches(\":popover-open\") === next) {\n    return;\n  }\n  transitionRef.current = true;\n  try {\n    if (next) {\n      if (show) {\n        show(element);\n      } else {\n        element.showPopover();\n      }\n    } else {\n      element.hidePopover();\n    }\n  } catch {\n    // A detached or already-transitioning popover can reject the request. The\n    // next state/effect pass retries against React's authority, so swallowing\n    // it here loses nothing — and throwing would take down a render.\n  } finally {\n    // `finally`, not the end of `try`: a rejected request must still lower the\n    // flag, or the component would treat every later native transition as its\n    // own and stop reconciling user dismissal for the rest of its life.\n    transitionRef.current = false;\n  }\n}\n",
      "path": "packages/heidi-ui/src/_internal/native-popover-sync.ts",
      "target": "components/ui/heidi/_internal/native-popover-sync.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared numeric-range normalization for measurement/input primitives\n * (Meter, Progress, Slider): non-finite inputs degrade to usable defaults\n * instead of propagating NaN/Infinity into aria-value* attributes or geometry.\n */\n\n/**\n * Span used when `max` is missing or not greater than `min` — mirrors the\n * platform's default 0–100 range for meter/range semantics, re-based onto the\n * normalized `min`.\n */\nexport const DEFAULT_RANGE_SPAN = 100;\n\nexport function finiteNumber(value: number, fallback: number): number {\n  return Number.isFinite(value) ? value : fallback;\n}\n\nexport type NormalizedRange = {\n  max: number;\n  min: number;\n};\n\nexport function normalizeRange(min: number, max: number): NormalizedRange {\n  const normalizedMin = finiteNumber(min, 0);\n  const normalizedMax =\n    Number.isFinite(max) && max > normalizedMin\n      ? max\n      : normalizedMin + DEFAULT_RANGE_SPAN;\n  return { max: normalizedMax, min: normalizedMin };\n}\n\n/**\n * Hover/dismiss delays for Tooltip, HoverCard and Menu.\n *\n * ponytail: every call site already wrote `Math.max(0, delay)` or `delay <= 0`,\n * which reads like sanitization and is not — `Math.max(0, NaN)` is `NaN`,\n * `NaN <= 0` is false, and `setTimeout(fn, NaN)` fires at 0ms. A non-finite\n * delay therefore SKIPPED the delay entirely: the pointer-transit protection\n * these props exist to provide silently stopped applying, and the component\n * still looked configured. The degradation is to `0`, which is a supported\n * value, so this is a robustness gap rather than a break — but it is the same\n * class as the non-finite bounds that reached Slider's and Progress's ARIA,\n * and it is fixed the same way: at the funnel, not at each guard.\n */\nexport function finiteDelay(value: number): number {\n  return Math.max(0, finiteNumber(value, 0));\n}\n",
      "path": "packages/heidi-ui/src/_internal/range.ts",
      "target": "components/ui/heidi/_internal/range.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared host rendering for heidi-ui parts — Base-UI-shaped composition\n * (docs/HEIDI-UI-HEADLESS.md § 4 / HEIDI-UI.md § 4.5):\n *   - className / style as value or (state) => value\n *   - render as ReactElement or (props, state) => ReactElement\n *   - ref forwarding\n *   - data-hui-part always set (stable unstyled hook)\n *\n * Structural inline styles (e.g. anchorName) are merged last so a consumer\n * style override cannot drop platform wiring.\n */\n\nimport {\n  cloneElement,\n  createElement,\n  isValidElement,\n  type CSSProperties,\n  type ComponentPropsWithRef,\n  type HTMLAttributes,\n  type ReactElement,\n  type ReactNode,\n  type Ref,\n  type RefCallback\n} from \"react\";\n\nexport type HeidiClassName<State> = string | ((state: State) => string | undefined) | undefined;\n\nexport type HeidiStyle<State> =\n  | CSSProperties\n  | ((state: State) => CSSProperties | undefined)\n  | undefined;\n\nexport type HeidiRenderFn<State, Props> = (\n  props: Props,\n  state: State\n) => ReactElement;\n\nexport type HeidiRender<State, Props> =\n  | ReactElement\n  | HeidiRenderFn<State, Props>\n  | undefined;\n\ntype DefaultRenderProps = HTMLAttributes<HTMLElement> & { ref?: Ref<HTMLElement> };\n\nexport type HeidiHostProps<\n  State,\n  RenderProps extends object = DefaultRenderProps\n> = {\n  className?: HeidiClassName<State>;\n  render?: HeidiRender<State, RenderProps>;\n  style?: HeidiStyle<State>;\n};\n\nexport type HeidiIntrinsicHostProps<\n  State,\n  Tag extends keyof HTMLElementTagNameMap\n> = HeidiHostProps<State, ComponentPropsWithRef<Tag>>;\n\nfunction resolveClassName<State>(\n  className: HeidiClassName<State>,\n  state: State\n): string | undefined {\n  return typeof className === \"function\" ? className(state) : className;\n}\n\nfunction resolveStyle<State>(style: HeidiStyle<State>, state: State): CSSProperties | undefined {\n  return typeof style === \"function\" ? style(state) : style;\n}\n\nfunction mergeClassNames(...parts: Array<string | undefined>): string | undefined {\n  const merged = parts.filter(Boolean).join(\" \");\n  return merged.length > 0 ? merged : undefined;\n}\n\n/**\n * Compose a consumer event with library behavior. Consumers run first and may\n * cancel the component behavior with `event.preventDefault()`. Heidi keeps\n * this native-event convention intentionally: it avoids a second branded event\n * API while still making async/controlled actions vetoable.\n */\nexport function composeHeidiEventHandlers<Event extends { defaultPrevented: boolean }>(\n  consumer: ((event: Event) => void) | undefined,\n  library: (event: Event) => void\n): (event: Event) => void {\n  return (event) => {\n    consumer?.(event);\n    if (!event.defaultPrevented) {\n      library(event);\n    }\n  };\n}\n\n/** React 19-safe ref fan-out, including callback-ref cleanup functions. */\nexport function mergeHeidiRefs<Element>(\n  ...inputRefs: Array<Ref<Element> | undefined>\n): Ref<Element> | undefined {\n  const refs = Array.from(\n    new Set(\n      inputRefs.filter(\n        (ref): ref is Exclude<Ref<Element>, null> => ref != null\n      )\n    )\n  );\n  if (refs.length === 0) {\n    return undefined;\n  }\n  if (refs.length === 1) {\n    return refs[0];\n  }\n\n  let cache = mergedRefCache;\n  for (const ref of refs) {\n    const key = ref as object;\n    let child = cache.children.get(key);\n    if (!child) {\n      child = { children: new WeakMap() };\n      cache.children.set(key, child);\n    }\n    cache = child;\n  }\n  if (cache.callback) {\n    return cache.callback as RefCallback<Element>;\n  }\n\n  const callback: RefCallback<Element> = (node) => {\n    const cleanups: Array<() => void> = [];\n    for (const ref of refs) {\n      if (typeof ref === \"function\") {\n        const cleanup = ref(node);\n        if (node !== null) {\n          cleanups.push(typeof cleanup === \"function\" ? cleanup : () => ref(null));\n        }\n      } else if (ref) {\n        ref.current = node;\n        if (node !== null) {\n          cleanups.push(() => {\n            ref.current = null;\n          });\n        }\n      }\n    }\n    return cleanups.length > 0\n      ? () => {\n          for (const cleanup of cleanups) {\n            cleanup();\n          }\n        }\n      : undefined;\n  };\n  cache.callback = callback as RefCallback<unknown>;\n  return callback;\n}\n\ntype MergedRefCache = {\n  callback?: RefCallback<unknown>;\n  children: WeakMap<object, MergedRefCache>;\n};\n\nconst mergedRefCache: MergedRefCache = { children: new WeakMap() };\n\ntype UnknownHandler = (...args: never[]) => unknown;\n\nfunction isEventHandler(key: string, value: unknown): value is UnknownHandler {\n  return /^on[A-Z]/.test(key) && typeof value === \"function\";\n}\n\nfunction defaultPrevented(args: unknown[]): boolean {\n  const event = args[0];\n  return (\n    typeof event === \"object\" &&\n    event !== null &&\n    \"defaultPrevented\" in event &&\n    event.defaultPrevented === true\n  );\n}\n\nfunction composeUnknownHandlers(\n  consumer: UnknownHandler,\n  library: UnknownHandler\n): UnknownHandler {\n  if (consumer === library) {\n    return library;\n  }\n  return ((...args: unknown[]) => {\n    (consumer as (...handlerArgs: unknown[]) => unknown)(...args);\n    if (!defaultPrevented(args)) {\n      (library as (...handlerArgs: unknown[]) => unknown)(...args);\n    }\n  }) as UnknownHandler;\n}\n\n/** Library-owned host props — permissive so button `type`, `data-*`, `popover`, etc. type-check. */\nexport type HeidiElementProps<Tag extends keyof HTMLElementTagNameMap> = Record<\n  string,\n  unknown\n> & {\n  children?: ReactNode;\n  className?: string;\n  ref?: Ref<HTMLElementTagNameMap[Tag]>;\n  style?: CSSProperties;\n};\n\ntype RenderElementParams<\n  State,\n  Tag extends keyof HTMLElementTagNameMap,\n  RenderProps extends object = DefaultRenderProps\n> = {\n  /** Default class from the generated hui-* map (theme/base target). */\n  className?: string;\n  /** Stable machine hook — always emitted. */\n  dataPart: string;\n  /** Intrinsic tag when `render` is omitted. */\n  element: Tag;\n  /** Props the library owns (aria, ids, handlers, popover, …). */\n  props: HeidiElementProps<Tag>;\n  /** Optional consumer composition props. */\n  renderProps?: HeidiHostProps<State, RenderProps>;\n  /** Typed state passed to functional className/style/render. */\n  state: State;\n  /** Structural inline styles that must survive consumer style merges. */\n  structuralStyle?: CSSProperties;\n  /**\n   * Render-element handlers to remove instead of composing. This is reserved\n   * for states such as a focusable disabled composite item where the public\n   * contract requires press handlers to be completely inert.\n   */\n  suppressRenderedHandlers?: readonly string[];\n};\n\n/**\n * Render a heidi-ui host element with optional Base-shaped composition.\n */\nexport function renderHeidiElement<\n  State,\n  Tag extends keyof HTMLElementTagNameMap,\n  RenderProps extends object = DefaultRenderProps\n>(\n  params: RenderElementParams<State, Tag, RenderProps>\n): ReactElement {\n  const {\n    className,\n    dataPart,\n    element,\n    props,\n    renderProps,\n    state,\n    structuralStyle,\n    suppressRenderedHandlers\n  } = params;\n  const consumerClass = resolveClassName(renderProps?.className, state);\n  const consumerStyle = resolveStyle(renderProps?.style, state);\n  const mergedStyle: CSSProperties | undefined =\n    props.style || consumerStyle || structuralStyle\n      ? { ...props.style, ...consumerStyle, ...structuralStyle }\n      : undefined;\n\n  const outProps: HTMLAttributes<HTMLElement> & {\n    \"data-hui-part\": string;\n    ref?: Ref<HTMLElement>;\n  } = {\n    ...(props as HTMLAttributes<HTMLElement> & { ref?: Ref<HTMLElement> }),\n    className: mergeClassNames(consumerClass, className),\n    \"data-hui-part\": dataPart,\n    style: mergedStyle\n  };\n\n  const render = renderProps?.render;\n  if (typeof render === \"function\") {\n    // Post-merge the returned element as well. This deliberately makes the\n    // stable data hook, owned semantics, refs, and internal handlers survive\n    // even when a render function forgets to spread one of the supplied props.\n    return mergeRenderedElement(\n      render(outProps as unknown as RenderProps, state),\n      outProps,\n      dataPart,\n      structuralStyle,\n      suppressRenderedHandlers\n    );\n  }\n  if (isValidElement(render)) {\n    return mergeRenderedElement(\n      render,\n      outProps,\n      dataPart,\n      structuralStyle,\n      suppressRenderedHandlers\n    );\n  }\n\n  return createElement(element, outProps as never, props.children);\n}\n\ntype RenderedProps = Record<string, unknown> & {\n  children?: ReactNode;\n  className?: string;\n  ref?: Ref<HTMLElement>;\n  style?: CSSProperties;\n};\n\nfunction mergeRenderedElement(\n  element: ReactElement,\n  libraryProps: HTMLAttributes<HTMLElement> & {\n    \"data-hui-part\": string;\n    ref?: Ref<HTMLElement>;\n  },\n  dataPart: string,\n  structuralStyle: CSSProperties | undefined,\n  suppressRenderedHandlers: readonly string[] | undefined\n): ReactElement {\n  const rendered = element as ReactElement<RenderedProps>;\n  const renderedProps = rendered.props;\n  const renderedClass =\n    renderedProps.className === libraryProps.className\n      ? undefined\n      : renderedProps.className;\n  const merged: RenderedProps = {\n    ...renderedProps,\n    ...libraryProps,\n    className: mergeClassNames(renderedClass, libraryProps.className),\n    \"data-hui-part\": dataPart,\n    ref: mergeHeidiRefs(libraryProps.ref, renderedProps.ref),\n    style: {\n      ...libraryProps.style,\n      ...renderedProps.style,\n      ...structuralStyle\n    }\n  };\n\n  if (Object.prototype.hasOwnProperty.call(renderedProps, \"children\")) {\n    merged.children = renderedProps.children;\n  }\n\n  const suppressedHandlers = suppressRenderedHandlers\n    ? new Set(suppressRenderedHandlers)\n    : null;\n  for (const key of new Set([...Object.keys(renderedProps), ...Object.keys(libraryProps)])) {\n    const consumer = renderedProps[key];\n    const library = (libraryProps as unknown as Record<string, unknown>)[key];\n    if (suppressedHandlers?.has(key)) {\n      merged[key] = library;\n      continue;\n    }\n    if (isEventHandler(key, consumer) && isEventHandler(key, library)) {\n      merged[key] = composeUnknownHandlers(consumer, library);\n    }\n  }\n\n  return cloneElement(rendered, merged as never);\n}\n",
      "path": "packages/heidi-ui/src/_internal/render-element.ts",
      "target": "components/ui/heidi/_internal/render-element.ts",
      "type": "registry:ui"
    },
    {
      "content": "/**\n * Shared id sanitizer for heidi-ui hosts.\n *\n * React's useId() emits characters that are invalid in HTML id / attribute\n * selectors and in CSS identifiers (`«r0»` in React 19, `:r0:` earlier).\n * heidi-ui interpolates these ids into element ids, aria relationships, and\n * dashed-ident anchor names (`--hui-*-anchor-…`), so everything outside\n * [a-zA-Z0-9_-] is stripped.\n */\n\nexport function safeId(id: string): string {\n  return id.replace(/[^a-zA-Z0-9_-]/g, \"\");\n}\n",
      "path": "packages/heidi-ui/src/_internal/safe-id.ts",
      "target": "components/ui/heidi/_internal/safe-id.ts",
      "type": "registry:ui"
    },
    {
      "content": "export type SafeTrianglePoint = {\n  x: number;\n  y: number;\n};\n\ntype SafeTriangleRect = Pick<DOMRect, \"bottom\" | \"left\" | \"right\" | \"top\">;\n\nexport function pointInTriangle(\n  point: SafeTrianglePoint,\n  first: SafeTrianglePoint,\n  second: SafeTrianglePoint,\n  third: SafeTrianglePoint\n): boolean {\n  const sign = (\n    value: SafeTrianglePoint,\n    edgeStart: SafeTrianglePoint,\n    edgeEnd: SafeTrianglePoint\n  ) =>\n    (value.x - edgeEnd.x) * (edgeStart.y - edgeEnd.y) -\n    (edgeStart.x - edgeEnd.x) * (value.y - edgeEnd.y);\n  const firstSign = sign(point, first, second);\n  const secondSign = sign(point, second, third);\n  const thirdSign = sign(point, third, first);\n  const hasNegative =\n    firstSign < 0 || secondSign < 0 || thirdSign < 0;\n  const hasPositive =\n    firstSign > 0 || secondSign > 0 || thirdSign > 0;\n  return !(hasNegative && hasPositive);\n}\n\n/**\n * Return the padded destination edge facing the pointer's departure point.\n *\n * ponytail: choosing the edge at the smallest scalar distance is a different\n * question and fails for an ordinary top-aligned submenu. A pointer leaving\n * below its trigger can be numerically closer to the submenu's top than its\n * left, even though it approaches from the left. That puts the whole bridge\n * above the diagonal and drops pointer grace on the first move. Containment\n * chooses the approach axis first; horizontal wins because submenus open\n * beside their triggers, with vertical as the collision-flip fallback.\n */\nexport function pointerBridgeEdge(\n  rect: SafeTriangleRect,\n  start: SafeTrianglePoint\n): [SafeTrianglePoint, SafeTrianglePoint] {\n  const padding = 8;\n  if (start.x <= rect.left) {\n    return [\n      { x: rect.left, y: rect.top - padding },\n      { x: rect.left, y: rect.bottom + padding }\n    ];\n  }\n  if (start.x >= rect.right) {\n    return [\n      { x: rect.right, y: rect.top - padding },\n      { x: rect.right, y: rect.bottom + padding }\n    ];\n  }\n  if (start.y <= rect.top) {\n    return [\n      { x: rect.left - padding, y: rect.top },\n      { x: rect.right + padding, y: rect.top }\n    ];\n  }\n  return [\n    { x: rect.left - padding, y: rect.bottom },\n    { x: rect.right + padding, y: rect.bottom }\n  ];\n}\n",
      "path": "packages/heidi-ui/src/_internal/safe-triangle.ts",
      "target": "components/ui/heidi/_internal/safe-triangle.ts",
      "type": "registry:ui"
    },
    {
      "content": "import { useEffect, useLayoutEffect } from \"react\";\n\n/**\n * `useLayoutEffect` that does not warn on the server.\n *\n * ponytail: fifteen primitives imported `useLayoutEffect` straight from React.\n * Every one of them carries `\"use client\"`, which is easy to misread as\n * \"client-only\" — in the App Router it means \"hydrated on the client\", and the\n * component is still rendered to HTML on the server first. React logs\n * \"useLayoutEffect does nothing on the server\" for each one, so a consumer\n * doing SSR saw a wall of warnings the app that ships this library never saw,\n * because it renders these routes on the client path.\n *\n * The branch is evaluated ONCE at module scope, not per render, and it is\n * therefore stable across a component's lifetime — swapping which hook is\n * called between renders would violate the rules of hooks. `typeof document`\n * rather than `typeof window`: both work, but `document` is the thing the\n * effect actually needs, and it keeps the check honest in exotic runtimes that\n * define a partial `window`.\n *\n * Rejected: `useInsertionEffect`, which runs earlier but is specified for\n * style injection and is not a general layout hook; and per-file guards, which\n * is what the 15 copies would have become.\n */\nexport const useHeidiLayoutEffect =\n  typeof document === \"undefined\" ? useEffect : useLayoutEffect;\n",
      "path": "packages/heidi-ui/src/_internal/use-layout-effect.ts",
      "target": "components/ui/heidi/_internal/use-layout-effect.ts",
      "type": "registry:ui"
    }
  ],
  "name": "menu",
  "registryDependencies": [
    "@heidi-ui/heidi-tokens"
  ],
  "title": "Menu",
  "type": "registry:ui"
}
