{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-navigation-menu",
  "type": "registry:component",
  "title": "Navigation menu",
  "description": "A horizontal nav that opens one anchored panel at a time",
  "author": "sudo-kw <https://github.com/sudo-kw>",
  "dependencies": [
    "@gpuix/native@0.11.0",
    "@gpuix/react@0.11.0",
    "effect@4.1.2",
    "react@^19.2.4"
  ],
  "registryDependencies": [
    "https://gpuixui.sudokw.com/gpuix-icons.json",
    "https://gpuixui.sudokw.com/gpuix-motion.json",
    "https://gpuixui.sudokw.com/gpuix-primitives.json",
    "https://gpuixui.sudokw.com/gpuix-tokens.json",
    "https://gpuixui.sudokw.com/gpuix-tw.json"
  ],
  "files": [
    {
      "path": "packages/components/src/internal/button.tsx",
      "target": "@ui/gpuixui/components/internal/button.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { Props } from \"@gpuix/react\";\nimport type { ReactNode } from \"react\";\nimport {\n  Button as PrimitiveButton,\n  IconButton as PrimitiveIconButton,\n  actionOnColor as primitiveActionOnColor,\n  type ButtonVariant as PrimitiveVariant,\n} from \"../../primitives/button.js\";\nimport { cn } from \"../../tw/index.js\";\nimport * as Schema from \"effect/Schema\";\nimport type { Theme } from \"./theme.js\";\n\nconst ButtonVariants = Schema.Literals([\n  \"primary\",\n  \"secondary\",\n  \"ghost\",\n  \"danger\",\n  \"link\",\n]);\n\nexport type ButtonVariant = typeof ButtonVariants.Type;\n\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface ButtonProps extends Props {\n  readonly variant?: ButtonVariant;\n\n  readonly size?: ButtonSize;\n\n  readonly disabled?: boolean;\n\n  readonly loading?: boolean;\n\n  readonly loadingLabel?: string;\n\n  readonly reducedMotion?: boolean;\n\n  readonly leading?: ReactNode;\n\n  readonly trailing?: ReactNode;\n}\n\nexport interface IconButtonProps extends Props {\n  readonly label: string;\n\n  readonly size?: ButtonSize;\n  readonly disabled?: boolean;\n}\n\ninterface Look {\n  readonly variant: PrimitiveVariant;\n  readonly className: string;\n}\n\nconst LOOKS: Readonly<Record<ButtonVariant, Look>> = {\n  primary: { variant: \"primary\", className: \"\" },\n  secondary: { variant: \"secondary\", className: \"border border-strong\" },\n  ghost: { variant: \"ghost\", className: \"\" },\n  danger: { variant: \"destructive\", className: \"\" },\n\n  link: { variant: \"link\", className: \"underline underline-offset-4\" },\n};\n\nconst lookOf = (variant: unknown): Look =>\n  LOOKS[Schema.is(ButtonVariants)(variant) ? variant : \"secondary\"];\n\nexport const actionOnColor = (theme: Theme, variant: ButtonVariant): string =>\n  primitiveActionOnColor(theme, lookOf(variant).variant);\n\nexport const Button = ({\n  variant = \"secondary\",\n  size = \"md\",\n  disabled = false,\n  onClick,\n  style,\n  \"aria-label\": ariaLabel,\n  ...rest\n}: ButtonProps) => {\n  const look = lookOf(variant);\n  return (\n    <PrimitiveButton\n      {...rest}\n      variant={look.variant}\n      size={size}\n      disabled={disabled}\n      label={ariaLabel}\n      className={cn(look.className)}\n      onActivate={onClick}\n      style={style}\n    />\n  );\n};\n\nexport const IconButton = ({\n  label,\n  size = \"md\",\n  disabled = false,\n  onClick,\n  style,\n  children,\n  ...rest\n}: IconButtonProps) => (\n  <PrimitiveIconButton\n    {...rest}\n    icon={children}\n    variant=\"ghost\"\n    size={size}\n    disabled={disabled}\n    label={label}\n    className=\"text-muted-foreground hover:text-foreground\"\n    onActivate={onClick}\n    style={style}\n  />\n);\n"
    },
    {
      "path": "packages/components/src/internal/clock.ts",
      "target": "@ui/gpuixui/components/internal/clock.ts",
      "type": "registry:lib",
      "content": "import { Effect } from \"effect\";\nimport * as Clock from \"effect/Clock\";\n\nexport const monotonicNanos = (): bigint =>\n  Effect.runSync(Clock.monotonicTimeNanos);\n\nexport const hoverDelay = (value: number, fallback: number): number =>\n  Number.isFinite(value) ? Math.max(0, value) : fallback;\n"
    },
    {
      "path": "packages/components/src/internal/controllable.ts",
      "target": "@ui/gpuixui/components/internal/controllable.ts",
      "type": "registry:lib",
      "content": "import { useCallback, useState } from \"react\";\n\nexport type ControllableState<Value> = readonly [Value, (next: Value) => void];\n\nexport interface ControllableStateOptions<Value> {\n  readonly value: Value | undefined;\n\n  readonly defaultValue: Value;\n\n  readonly onChange?: (next: Value) => void;\n}\n\nexport const useControllableState = <Value>({\n  value,\n  defaultValue,\n  onChange,\n}: ControllableStateOptions<Value>): ControllableState<Value> => {\n  const [internal, setInternal] = useState(defaultValue);\n  const controlled = value !== undefined;\n\n  const setValue = useCallback(\n    (next: Value) => {\n      if (!controlled) setInternal(next);\n      if (value !== next) onChange?.(next);\n    },\n    [controlled, value, onChange],\n  );\n\n  return [controlled ? value : internal, setValue];\n};\n"
    },
    {
      "path": "packages/components/src/internal/dismiss-layer.ts",
      "target": "@ui/gpuixui/components/internal/dismiss-layer.ts",
      "type": "registry:lib",
      "content": "import type { EventPayload } from \"@gpuix/react\";\nimport * as Arr from \"effect/Array\";\nimport * as Duration from \"effect/Duration\";\nimport * as Option from \"effect/Option\";\nimport * as Order from \"effect/Order\";\nimport { monotonicNanos } from \"./clock.js\";\n\nexport type DismissHandler = (event: EventPayload) => void;\n\ninterface Layer {\n  readonly onDismiss: DismissHandler;\n  readonly depth: number;\n}\n\nlet layers: ReadonlyArray<Layer> = [];\n\nlet dismissedKeystroke: Option.Option<number> = Option.none();\n\ninterface Press {\n  readonly shape: string;\n  readonly at: bigint;\n}\n\nlet dismissedPress: Option.Option<Press> = Option.none();\n\nexport const pointerGestureWindow: Duration.Duration = Duration.millis(64);\n\nconst PRESS_WINDOW_NANOS =\n  BigInt(Duration.toMillis(pointerGestureWindow)) * 1_000_000n;\n\nconst pressShape = (event: EventPayload): string =>\n  Arr.join(\":\")(\n    Arr.map(\n      [event.eventType, event.x, event.y, event.button, event.clickCount],\n      (part) => (part === undefined ? \"\" : `${part}`),\n    ),\n  );\n\nconst consumedPress = (event: EventPayload, now: bigint): boolean => {\n  const shape = pressShape(event);\n  const repeated = Option.exists(\n    dismissedPress,\n    (press) => press.shape === shape && now - press.at <= PRESS_WINDOW_NANOS,\n  );\n  if (!repeated) dismissedPress = Option.some({ shape, at: now });\n  return repeated;\n};\n\nlet lastDismissedPoint: Option.Option<{\n  readonly point: string;\n  readonly at: bigint;\n}> = Option.none();\n\nconst pointOf = (event: EventPayload): string =>\n  Arr.join(\":\")(\n    Arr.map([event.x, event.y, event.button], (part) =>\n      part === undefined ? \"\" : `${part}`,\n    ),\n  );\n\nexport const isDismissalClick = (\n  event: EventPayload,\n  now: bigint = monotonicNanos(),\n): boolean =>\n  Option.exists(\n    lastDismissedPoint,\n    (dismissed) =>\n      dismissed.point === pointOf(event) &&\n      now - dismissed.at <= PRESS_WINDOW_NANOS,\n  );\n\nconst consumedKeystroke = (keystrokeId: number): boolean => {\n  if (Option.contains(dismissedKeystroke, keystrokeId)) return true;\n  dismissedKeystroke = Option.some(keystrokeId);\n  return false;\n};\n\nconst consume = (event: EventPayload, now: bigint): boolean =>\n  Option.match(Option.fromNullishOr(event.keystrokeId), {\n    onNone: () => consumedPress(event, now),\n    onSome: consumedKeystroke,\n  });\n\nconst byDepth: Order.Order<Layer> = Order.mapInput(\n  Order.Number,\n  (layer: Layer) => layer.depth,\n);\n\nconst topmost = (): Option.Option<DismissHandler> =>\n  Option.map(Arr.last(Arr.sort(layers, byDepth)), (layer) => layer.onDismiss);\n\nexport const pushDismissLayer = (\n  onDismiss: DismissHandler,\n  depth: number,\n): (() => void) => {\n  const layer: Layer = { onDismiss, depth };\n  layers = Arr.append(layers, layer);\n  return () => {\n    layers = Arr.filter(layers, (candidate) => candidate !== layer);\n    if (Arr.length(layers) === 0) {\n      dismissedKeystroke = Option.none();\n      dismissedPress = Option.none();\n    }\n  };\n};\n\nexport const dismissTopLayer = (\n  event: EventPayload,\n  now: bigint = monotonicNanos(),\n): boolean => {\n  if (consume(event, now)) return false;\n  return Option.match(topmost(), {\n    onNone: () => false,\n    onSome: (onDismiss) => {\n      lastDismissedPoint = Option.some({ point: pointOf(event), at: now });\n      onDismiss(event);\n      return true;\n    },\n  });\n};\n\nexport const dismissLayerCount = (): number => Arr.length(layers);\n"
    },
    {
      "path": "packages/components/src/internal/dismiss-scope.tsx",
      "target": "@ui/gpuixui/components/internal/dismiss-scope.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport { createContext, useContext, type ReactNode } from \"react\";\n\nconst AmbientDepth = createContext(0);\n\nexport const useDismissDepth = (): number => useContext(AmbientDepth) + 1;\n\nexport const DismissScope = ({\n  children,\n}: {\n  readonly children: ReactNode;\n}) => (\n  <AmbientDepth.Provider value={useDismissDepth()}>\n    {children}\n  </AmbientDepth.Provider>\n);\n"
    },
    {
      "path": "packages/components/src/internal/flip-mark.tsx",
      "target": "@ui/gpuixui/components/internal/flip-mark.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport { Icon, iconPixels, type IconName, type IconSize } from \"../../icons/index.js\";\nimport { useRef } from \"react\";\nimport { useSurfaceTiming } from \"./presence.js\";\n\nconst TRAVEL = 2;\n\nconst Mark = ({\n  name,\n  shown,\n  travel,\n  label,\n  color,\n  size,\n  testId,\n}: {\n  readonly name: IconName;\n  readonly shown: boolean;\n  readonly travel: number;\n  readonly label: string | undefined;\n  readonly color: string;\n  readonly size: IconSize | number;\n  readonly testId?: string;\n}) => {\n  const timing = useSurfaceTiming(\"normal\");\n  const mountedShown = useRef(shown).current;\n  const frame = (atRest: boolean) => ({\n    opacity: atRest ? 1 : 0,\n    top: atRest ? 0 : travel,\n  });\n\n  return (\n    <div\n      motion={{\n        initial: frame(mountedShown),\n        animate: frame(shown),\n        transition: shown ? timing.enter : timing.exit,\n      }}\n      style={{ position: \"absolute\", left: 0, pointerEvents: \"none\" }}\n      testId={testId}\n    >\n      <Icon\n        name={name}\n        size={size}\n        color={color}\n        label={shown ? label : undefined}\n      />\n    </div>\n  );\n};\n\nexport type FlipMarkName = \"off\" | \"on\";\n\nexport interface FlipMarkProps {\n  readonly off: IconName;\n\n  readonly on: IconName;\n  readonly shown: boolean;\n  readonly color: string;\n  readonly size?: IconSize | number;\n\n  readonly travel?: number;\n\n  readonly offLabel?: string;\n\n  readonly onLabel?: string;\n\n  readonly testIdFor?: (mark: FlipMarkName) => string | undefined;\n}\n\nexport const FlipMark = ({\n  off: offName,\n  on: onName,\n  shown,\n  color,\n  size = \"xs\",\n  travel = TRAVEL,\n  offLabel,\n  onLabel,\n  testIdFor,\n}: FlipMarkProps) => {\n  const pixels = iconPixels(size);\n  return (\n    <div\n      style={{\n        position: \"relative\",\n        width: pixels,\n        height: pixels,\n        flexShrink: 0,\n      }}\n    >\n      <Mark\n        name={offName}\n        shown={!shown}\n        travel={-travel}\n        label={offLabel}\n        color={color}\n        size={size}\n        {...(testIdFor === undefined ? {} : { testId: testIdFor(\"off\") })}\n      />\n      <Mark\n        name={onName}\n        shown={shown}\n        travel={travel}\n        label={onLabel}\n        color={color}\n        size={size}\n        {...(testIdFor === undefined ? {} : { testId: testIdFor(\"on\") })}\n      />\n    </div>\n  );\n};\n"
    },
    {
      "path": "packages/components/src/internal/key.ts",
      "target": "@ui/gpuixui/components/internal/key.ts",
      "type": "registry:lib",
      "content": "import type { EventPayload, KeyEvent, Props } from \"@gpuix/react\";\nimport * as Option from \"effect/Option\";\n\nexport type KeyPhase = \"down\" | \"up\";\n\nexport const isActivation = (event: EventPayload, phase: KeyPhase): boolean => {\n  if (event.isHeld === true) return false;\n  if (event.key === \"enter\") return phase === \"down\";\n  return event.key === \"space\" && phase === \"up\";\n};\n\nexport const swallowsDefault = (\n  event: EventPayload,\n  phase: KeyPhase,\n): boolean => event.key === \"space\" && phase === \"down\";\n\nexport const activationHandlers = (\n  activate: (event: KeyEvent) => void,\n  observe: Pick<Props, \"onKeyDown\" | \"onKeyUp\"> = {},\n): Pick<Props, \"onKeyDown\" | \"onKeyUp\"> => ({\n  onKeyDown: (event: KeyEvent) => {\n    if (swallowsDefault(event, \"down\")) event.preventDefault();\n    if (isActivation(event, \"down\")) activate(event);\n    observe.onKeyDown?.(event);\n  },\n  onKeyUp: (event: KeyEvent) => {\n    if (isActivation(event, \"up\")) activate(event);\n    observe.onKeyUp?.(event);\n  },\n});\n\nexport const isEnter = (event: EventPayload): boolean => event.key === \"enter\";\n\nexport const isDown = (event: EventPayload): boolean =>\n  event.key === \"down\" || (event.key === \"n\" && event.modifiers?.ctrl === true);\n\nexport const isUp = (event: EventPayload): boolean =>\n  event.key === \"up\" || (event.key === \"p\" && event.modifiers?.ctrl === true);\n\nexport const isRight = (event: EventPayload): boolean => event.key === \"right\";\n\nexport const isLeft = (event: EventPayload): boolean => event.key === \"left\";\n\nexport const isFirst = (event: EventPayload): boolean => event.key === \"home\";\n\nexport const isLast = (event: EventPayload): boolean => event.key === \"end\";\n\nexport const isPageUp = (event: EventPayload): boolean =>\n  event.key === \"pageup\";\n\nexport const isPageDown = (event: EventPayload): boolean =>\n  event.key === \"pagedown\";\n\nexport const isDismiss = (event: EventPayload): boolean =>\n  event.key === \"escape\";\n\nexport const isTab = (event: EventPayload): boolean => event.key === \"tab\";\n\nexport const isSelectAll = (event: EventPayload): boolean =>\n  event.key === \"a\" &&\n  (event.modifiers?.cmd === true || event.modifiers?.ctrl === true);\n\nexport const isMenuKey = (event: EventPayload): boolean =>\n  (event.key === \"f10\" && event.modifiers?.shift === true) ||\n  event.key === \"contextmenu\";\n\nexport const axisDirection = (\n  event: EventPayload,\n  orientation: \"horizontal\" | \"vertical\",\n): Option.Option<1 | -1> => {\n  if (event.key === \"right\") return Option.some(1);\n  if (event.key === \"left\") return Option.some(-1);\n  if (orientation === \"vertical\") {\n    if (isDown(event)) return Option.some(1);\n    if (isUp(event)) return Option.some(-1);\n  }\n  return Option.none();\n};\n"
    },
    {
      "path": "packages/components/src/internal/overlay.ts",
      "target": "@ui/gpuixui/components/internal/overlay.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport { cn } from \"../../tw/index.js\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport { recipeStyle } from \"./recipe.js\";\nimport {\n  alpha,\n  elevationShadow,\n  type BoxShadow,\n  type ElevationLevel,\n  type Theme,\n} from \"./theme.js\";\n\nexport const OVERLAY_WASH = 0.55;\n\nexport const overlayVeilColor = (theme: Theme): string =>\n  alpha(theme.colors.background, OVERLAY_WASH);\n\nconst isEdge = (shadow: BoxShadow): boolean =>\n  shadow.blurRadius === 0 && shadow.spreadRadius > 0;\n\nconst shadows = (painted: StyleDesc[\"boxShadow\"]): ReadonlyArray<BoxShadow> =>\n  Option.match(Option.fromNullishOr(painted), {\n    onNone: () => [],\n    onSome: (value) => Arr.ensure(value),\n  });\n\nexport const overlaySurfaceStyle = (\n  recipe: string,\n  className: string | undefined,\n  theme: Theme,\n  elevation?: ElevationLevel,\n): StyleDesc => {\n  const style = recipeStyle(cn(recipe, className), theme);\n  const lift = Option.fromNullishOr(elevation).pipe(\n    Option.flatMap((level) =>\n      Option.fromNullishOr(elevationShadow(theme, level)),\n    ),\n  );\n\n  return Option.match(lift, {\n    onNone: () => style,\n    onSome: (shadow) => {\n      const painted = shadows(style.boxShadow);\n      const lost = Arr.every(painted, isEdge) && painted.length > 0;\n      return lost ? { ...style, boxShadow: [shadow, ...painted] } : style;\n    },\n  });\n};\n"
    },
    {
      "path": "packages/components/src/internal/parts.ts",
      "target": "@ui/gpuixui/components/internal/parts.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as P from \"effect/Predicate\";\nimport {\n  Children,\n  Fragment,\n  isValidElement,\n  type ReactElement,\n  type ReactNode,\n} from \"react\";\n\nexport type PartComponent = (props: never) => ReactNode;\n\nexport type PartChildren =\n  | ReactElement<unknown>\n  | boolean\n  | null\n  | undefined\n  | ReadonlyArray<PartChildren>;\n\nexport interface PartsContract {\n  readonly parent: string;\n\n  readonly family: ReadonlyArray<PartComponent>;\n\n  readonly accepts: ReadonlyArray<PartComponent>;\n\n  readonly hint?: string;\n}\n\nconst componentName = (type: unknown): string =>\n  P.isString(type)\n    ? type\n    : P.isFunction(type)\n      ? type.name || \"anonymous\"\n      : \"element\";\n\nconst fragmentChildren = (element: ReactElement<unknown>): ReactNode =>\n  hasChildren(element.props) ? element.props.children : undefined;\n\nconst hasChildren = (\n  value: unknown,\n): value is { readonly children?: ReactNode } =>\n  P.isObject(value) && \"children\" in value;\n\nconst leaves = (children: ReactNode): ReadonlyArray<unknown> =>\n  Arr.flatMap(Children.toArray(children), (child) =>\n    isValidElement<unknown>(child) && child.type === Fragment\n      ? leaves(fragmentChildren(child))\n      : [child],\n  );\n\nexport const assertParts = (\n  contract: PartsContract,\n  children: ReactNode,\n): void => {\n  Arr.forEach(leaves(children), (leaf) => {\n    if (!isValidElement(leaf)) return;\n    if (Arr.some(contract.accepts, (part) => part === leaf.type)) return;\n    if (!Arr.some(contract.family, (part) => part === leaf.type)) return;\n\n    throw new Error(\n      `${componentName(leaf.type)} cannot be used inside ${contract.parent}.` +\n        (contract.hint === undefined ? \"\" : ` ${contract.hint}`),\n    );\n  });\n};\n"
    },
    {
      "path": "packages/components/src/internal/presence.tsx",
      "target": "@ui/gpuixui/components/internal/presence.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { MotionProps } from \"@gpuix/react\";\nimport {\n  delayedTiming,\n  exitWindowMs,\n  fadeFrom,\n  fadeFromAnchor,\n  fadeFromSide,\n  fadeOnly,\n  presenceMotion as motionOfPresence,\n  presenceStyle,\n  transitionWindowMs,\n  type PresenceFrames,\n  type PresenceHitRule,\n  type PresenceSide,\n  type PresenceTiming,\n  type PresenceTransition,\n} from \"../../motion/presence.js\";\nimport {\n  MotionProvider,\n  useMotionPreference,\n  useSurfacePresence,\n  useSurfaceTiming,\n  type MotionProviderProps,\n  type SurfacePresence,\n} from \"../../motion/react/presence.js\";\nimport {\n  motionTiming,\n  type MotionLevel,\n  type MotionPreference,\n} from \"../../motion/timing.js\";\n\nexport { MotionProvider, useMotionPreference, type MotionProviderProps };\n\nexport type SurfaceFrames = PresenceFrames;\n\nexport type SurfaceTiming = PresenceTiming;\n\nexport type PanelSide = PresenceSide;\n\nexport {\n  delayedTiming,\n  exitWindowMs,\n  fadeFrom,\n  fadeFromAnchor,\n  fadeFromSide,\n  fadeOnly,\n  presenceStyle,\n  transitionWindowMs,\n};\nexport type { PresenceHitRule };\n\nexport { useSurfacePresence, useSurfaceTiming, type SurfacePresence };\n\nexport const moveTiming = (\n  level: MotionLevel,\n  preference: MotionPreference,\n): PresenceTransition => motionTiming(level, { phase: \"standard\", preference });\n\nexport const useMoveTiming = (level: MotionLevel): PresenceTransition =>\n  moveTiming(level, useMotionPreference());\n\nexport const presenceMotion = (\n  frames: SurfaceFrames,\n  presence: SurfacePresence,\n  timing: SurfaceTiming = presence.timing,\n): MotionProps => motionOfPresence(frames, presence.present, timing);\n\nexport const PresenceShield = ({ present }: { readonly present: boolean }) =>\n  present ? null : (\n    <div\n      testId=\"presence-shield\"\n      style={{ position: \"absolute\", top: 0, right: 0, bottom: 0, left: 0 }}\n    />\n  );\n\nexport const presenceTabStop = (\n  present: boolean,\n): { readonly tabIndex?: number } => (present ? {} : { tabIndex: -1 });\n"
    },
    {
      "path": "packages/components/src/internal/recipe.ts",
      "target": "@ui/gpuixui/components/internal/recipe.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport { createRecipeCache } from \"../../tw/index.js\";\nimport type { Theme } from \"./theme.js\";\n\nexport const recipeStyle: (recipe: string, theme: Theme) => StyleDesc =\n  createRecipeCache(512);\n"
    },
    {
      "path": "packages/components/src/internal/ref.ts",
      "target": "@ui/gpuixui/components/internal/ref.ts",
      "type": "registry:lib",
      "content": "import type { Ref, RefCallback } from \"react\";\nimport { useCallback } from \"react\";\n\nconst assign = <T>(ref: Ref<T> | undefined, value: T): void => {\n  if (ref === null || ref === undefined) return;\n  if (typeof ref === \"function\") {\n    ref(value);\n    return;\n  }\n  ref.current = value;\n};\n\nexport const useMergedRef = <T>(\n  internal: Ref<T>,\n  caller: Ref<T> | undefined,\n): RefCallback<T> =>\n  useCallback(\n    (value: T) => {\n      assign(internal, value);\n      assign(caller, value);\n    },\n    [internal, caller],\n  );\n"
    },
    {
      "path": "packages/components/src/internal/theme.ts",
      "target": "@ui/gpuixui/components/internal/theme.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport * as Schema from \"effect/Schema\";\nimport {\n  alpha,\n  avatarPixels,\n  avatarSize,\n  brandTextOn,\n  controlFocusRing,\n  controlHeight,\n  controlPaddingX,\n  currentPlatform,\n  darkTheme,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  findHighlight,\n  focusRing,\n  keyboardFocusRing,\n  lightTheme,\n  nativeTextTheme,\n  pointerWash,\n  selectionOn,\n  statusTone,\n  syntaxColors,\n  targetSize,\n  textStyle,\n  type BoxShadow,\n  type ElevationLevel,\n  type FindHighlightSource,\n  type NativeTextFill,\n  type PlatformName,\n  type PointerWashSurface,\n  type StatusTone,\n  type SyntaxColors,\n  type SyntaxRole,\n  type TextRole,\n  type Theme,\n  type ThemeColors,\n} from \"../../tokens/index.js\";\n\nexport {\n  alpha,\n  avatarPixels,\n  avatarSize,\n  controlFocusRing,\n  controlHeight,\n  controlPaddingX,\n  currentPlatform,\n  darkTheme,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  findHighlight,\n  focusRing,\n  keyboardFocusRing,\n  lightTheme,\n  nativeTextTheme,\n  statusTone,\n  syntaxColors,\n  targetSize,\n  textStyle,\n};\nexport type {\n  BoxShadow,\n  ElevationLevel,\n  FindHighlightSource,\n  NativeTextFill,\n  PlatformName,\n  StatusTone,\n  SyntaxColors,\n  SyntaxRole,\n  TextRole,\n  Theme,\n};\nexport { ThemeProvider, useTheme } from \"../../tokens/react.js\";\n\nexport const keyboardRing = (theme: Theme, invalid = false): StyleDesc =>\n  controlFocusRing(theme, { invalid }) ?? {};\n\nexport interface ControlRingState {\n  readonly disabled?: boolean;\n\n  readonly invalid?: boolean;\n}\n\nexport const controlRing = (\n  theme: Theme,\n  state: ControlRingState = {},\n): StyleDesc => controlFocusRing(theme, state) ?? {};\n\nexport const pressWash = (theme: Theme, replaced: PointerWashSurface): string =>\n  pointerWash(theme, \"active\", replaced) ?? theme.colors.active;\n\nexport const selectionWash = (theme: Theme): StyleDesc => ({\n  selectionColor: theme.colors.selection,\n});\n\nexport const keepContent: StyleDesc = { keyboardFocusDim: false };\n\nexport const disabledFade = (\n  disabled: boolean,\n): { readonly opacity: number } | undefined =>\n  disabled ? { opacity: disabledOpacity } : undefined;\n\nconst Tones = Schema.Literals([\"info\", \"success\", \"warning\", \"danger\"]);\n\nexport type Tone = typeof Tones.Type;\n\nexport const toneOf = (value: unknown): Tone =>\n  Schema.is(Tones)(value) ? value : \"info\";\n\nexport interface ToneStyle {\n  readonly fg: string;\n  readonly bg: string;\n  readonly border: string;\n}\n\nconst TOKEN_TONE: Readonly<Record<Tone, StatusTone>> = {\n  info: \"info\",\n  success: \"success\",\n  warning: \"warning\",\n  danger: \"destructive\",\n};\n\nexport const tone = (theme: Theme, value: Tone): ToneStyle => {\n  const { background, border, foreground } = statusTone(\n    theme,\n    TOKEN_TONE[value],\n  );\n  return { bg: background, border, fg: foreground };\n};\n\nconst softRoles: Readonly<Record<Tone, keyof ThemeColors>> = {\n  info: \"infoSoft\",\n  success: \"successSoft\",\n  warning: \"warningSoft\",\n  danger: \"destructiveSoft\",\n};\n\nexport const messageLink = (theme: Theme, value: Tone): string =>\n  brandTextOn(theme, softRoles[value]);\n\nexport const messageSelection = (theme: Theme, value: Tone): string =>\n  selectionOn(theme, softRoles[value]);\n\nexport const toneSurface = (theme: Theme, value: Tone): StyleDesc => {\n  const { bg, border, fg } = tone(theme, value);\n  return {\n    backgroundColor: bg,\n    color: fg,\n    borderWidth: theme.borderWidth.thin,\n    borderColor: border,\n  };\n};\n"
    },
    {
      "path": "packages/components/src/navigation-menu.tsx",
      "target": "@ui/gpuixui/components/navigation-menu.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type {\n  EventPayload,\n  KeyEvent,\n  Props,\n  PublicInstance,\n} from \"@gpuix/react\";\nimport { useGpuix } from \"@gpuix/react\";\nimport {\n  FloatingLayer,\n  floatingRootStyle,\n  mergeStyles,\n  resolveStyle,\n} from \"@gpuix/react/floating\";\nimport {\n  Button as PrimitiveButton,\n  type ButtonProps as PrimitiveButtonProps,\n} from \"../primitives/button.js\";\nimport {\n  cn,\n  NAVIGATION_MENU_CONTENT,\n  NAVIGATION_MENU_ITEM,\n  NAVIGATION_MENU_LINK,\n  NAVIGATION_MENU_LIST,\n  NAVIGATION_MENU_ROOT,\n} from \"../tw/index.js\";\nimport * as Option from \"effect/Option\";\nimport {\n  createContext,\n  useCallback,\n  useContext,\n  useLayoutEffect,\n  useMemo,\n  useRef,\n  useState,\n} from \"react\";\nimport { Button, type ButtonProps } from \"./internal/button.js\";\nimport { FlipMark } from \"./internal/flip-mark.js\";\nimport { hoverDelay } from \"./internal/clock.js\";\nimport { useControllableState } from \"./internal/controllable.js\";\nimport { dismissTopLayer, pushDismissLayer } from \"./internal/dismiss-layer.js\";\nimport { DismissScope, useDismissDepth } from \"./internal/dismiss-scope.js\";\nimport {\n  isDismiss,\n  isDown,\n  isFirst,\n  isLast,\n  isLeft,\n  isRight,\n} from \"./internal/key.js\";\nimport { overlaySurfaceStyle } from \"./internal/overlay.js\";\nimport {\n  fadeFromAnchor,\n  PresenceShield,\n  presenceMotion,\n  presenceStyle,\n  useSurfacePresence,\n  useSurfaceTiming,\n} from \"./internal/presence.js\";\nimport {\n  assertParts,\n  type PartChildren,\n  type PartComponent,\n  type PartsContract,\n} from \"./internal/parts.js\";\nimport { recipeStyle } from \"./internal/recipe.js\";\nimport { useMergedRef } from \"./internal/ref.js\";\nimport { useTheme } from \"./internal/theme.js\";\n\ninterface NavigationMenuContextValue {\n  readonly open: string | null;\n  readonly setOpen: (value: string | null) => void;\n  readonly registerTrigger: (\n    value: string,\n    instance: PublicInstance | null,\n  ) => void;\n  readonly moveFocus: (value: string, delta: 1 | -1 | \"first\" | \"last\") => void;\n  readonly focusTrigger: (value: string) => void;\n  readonly panelFocus: string | null;\n  readonly requestPanelFocus: (value: string) => void;\n  readonly clearPanelFocus: () => void;\n\n  readonly hoverOpen: (value: string) => void;\n\n  readonly hoverClose: (value: string) => void;\n\n  readonly hoverPanel: (inside: boolean) => void;\n\n  readonly cancelOpening: () => void;\n\n  readonly stopHover: () => void;\n\n  readonly isTriggerPoint: (\n    x: number | undefined,\n    y: number | undefined,\n  ) => boolean;\n}\n\nconst NavigationMenuContext = createContext<\n  NavigationMenuContextValue | undefined\n>(undefined);\n\nconst ItemContext = createContext<\n  { readonly value: string; readonly open: boolean } | undefined\n>(undefined);\n\nconst PanelLeaving = createContext(false);\n\nconst usePanelLeaving = (): boolean => useContext(PanelLeaving);\n\nconst useNavigationMenu = (): NavigationMenuContextValue => {\n  const value = useContext(NavigationMenuContext);\n  if (value === undefined) {\n    throw new Error(\"NavigationMenu parts must be used inside NavigationMenu\");\n  }\n  return value;\n};\n\nconst useNavItem = (): { readonly value: string; readonly open: boolean } => {\n  const value = useContext(ItemContext);\n  if (value === undefined) {\n    throw new Error(\n      \"NavigationMenu items must be used inside NavigationMenuItem\",\n    );\n  }\n  return value;\n};\n\nexport interface NavigationMenuProps extends Omit<Props, \"children\"> {\n  readonly label: string;\n\n  readonly value?: string | null;\n  readonly defaultValue?: string | null;\n  readonly onValueChange?: (value: string | null) => void;\n\n  readonly openDelay?: number;\n\n  readonly closeDelay?: number;\n\n  readonly className?: string;\n  readonly children?: PartChildren;\n}\n\nconst OPEN_DELAY_MS = 150;\nconst CLOSE_DELAY_MS = 150;\n\nexport const NavigationMenu = ({\n  label,\n  value: valueProp,\n  defaultValue = null,\n  onValueChange,\n  openDelay = OPEN_DELAY_MS,\n  closeDelay = CLOSE_DELAY_MS,\n  className,\n  children,\n  style,\n  onKeyDown,\n  ...rest\n}: NavigationMenuProps) => {\n  const theme = useTheme();\n  const renderer = useGpuix().renderer;\n  const [open, setOpen] = useControllableState({\n    value: valueProp,\n    defaultValue,\n    onChange: onValueChange,\n  });\n  const triggers = useRef(new Map<string, PublicInstance>());\n  const [order, setOrder] = useState<ReadonlyArray<string>>([]);\n  const [panelFocus, setPanelFocus] = useState<string | null>(null);\n  const openTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n    undefined,\n  );\n  const closeTimer = useRef<ReturnType<typeof setTimeout> | undefined>(\n    undefined,\n  );\n\n  const hovered = useRef<string | null>(null);\n  const panelHovered = useRef(false);\n\n  const suspended = useRef(false);\n  assertParts(navigationMenuRoot, children);\n\n  const openMs = hoverDelay(openDelay, OPEN_DELAY_MS);\n  const closeMs = hoverDelay(closeDelay, CLOSE_DELAY_MS);\n\n  const clearOpenTimer = useCallback(() => {\n    if (openTimer.current !== undefined) {\n      clearTimeout(openTimer.current);\n      openTimer.current = undefined;\n    }\n  }, []);\n\n  const clearCloseTimer = useCallback(() => {\n    if (closeTimer.current !== undefined) {\n      clearTimeout(closeTimer.current);\n      closeTimer.current = undefined;\n    }\n  }, []);\n\n  const stopHover = useCallback(() => {\n    clearOpenTimer();\n    clearCloseTimer();\n    hovered.current = null;\n    panelHovered.current = false;\n    suspended.current = true;\n  }, [clearCloseTimer, clearOpenTimer]);\n\n  const cancelOpening = useCallback(() => {\n    clearOpenTimer();\n    hovered.current = null;\n  }, [clearOpenTimer]);\n\n  useLayoutEffect(() => stopHover, [stopHover]);\n\n  useLayoutEffect(() => {\n    if (open === null) panelHovered.current = false;\n  }, [open]);\n\n  const hoverOpen = useCallback(\n    (value: string) => {\n      suspended.current = false;\n      hovered.current = value;\n      clearOpenTimer();\n      clearCloseTimer();\n      if (open === value) return;\n      const show = () => {\n        openTimer.current = undefined;\n        setOpen(value);\n      };\n      if (openMs === 0) show();\n      else openTimer.current = setTimeout(show, openMs);\n    },\n    [clearCloseTimer, clearOpenTimer, open, openMs, setOpen],\n  );\n\n  const scheduleClose = useCallback(() => {\n    if (hovered.current !== null || panelHovered.current) return;\n    if (open === null) return;\n    clearCloseTimer();\n    const hide = () => {\n      closeTimer.current = undefined;\n      setOpen(null);\n    };\n    if (closeMs === 0) hide();\n    else closeTimer.current = setTimeout(hide, closeMs);\n  }, [clearCloseTimer, closeMs, open, setOpen]);\n\n  const hoverClose = useCallback(\n    (value: string) => {\n      if (suspended.current) return;\n      if (hovered.current !== value) return;\n      hovered.current = null;\n      scheduleClose();\n    },\n    [scheduleClose],\n  );\n\n  const hoverPanel = useCallback(\n    (inside: boolean) => {\n      if (inside) {\n        suspended.current = false;\n        panelHovered.current = true;\n        clearCloseTimer();\n        return;\n      }\n      if (suspended.current) return;\n      panelHovered.current = false;\n      scheduleClose();\n    },\n    [clearCloseTimer, scheduleClose],\n  );\n\n  const registerTrigger = useCallback(\n    (value: string, instance: PublicInstance | null) => {\n      if (instance === null) {\n        triggers.current.delete(value);\n      } else {\n        triggers.current.set(value, instance);\n      }\n      const keys = Array.from(triggers.current.keys());\n      setOrder((current) =>\n        current.length === keys.length &&\n        keys.every((key, index) => key === current[index])\n          ? current\n          : keys,\n      );\n    },\n    [],\n  );\n\n  const focusTrigger = useCallback(\n    (value: string) => {\n      const instance = triggers.current.get(value);\n      if (instance !== undefined) renderer?.focusElement?.(instance.id);\n    },\n    [renderer],\n  );\n\n  const isTriggerPoint = useCallback(\n    (x: number | undefined, y: number | undefined): boolean => {\n      if (x === undefined || y === undefined) return false;\n      return Array.from(triggers.current.values()).some((instance) =>\n        Option.match(\n          Option.fromNullishOr(renderer?.getElementBounds?.(instance.id)),\n          {\n            onNone: () => false,\n            onSome: (bounds) =>\n              x >= bounds.x &&\n              x <= bounds.x + bounds.width &&\n              y >= bounds.y &&\n              y <= bounds.y + bounds.height,\n          },\n        ),\n      );\n    },\n    [renderer],\n  );\n\n  const moveFocus = useCallback(\n    (value: string, delta: 1 | -1 | \"first\" | \"last\") => {\n      if (order.length === 0) return;\n      const index = order.indexOf(value);\n      const next =\n        delta === \"first\"\n          ? 0\n          : delta === \"last\"\n            ? order.length - 1\n            : (((index + delta) % order.length) + order.length) % order.length;\n      const target = order[next];\n      if (target !== undefined) focusTrigger(target);\n    },\n    [focusTrigger, order],\n  );\n\n  const dismiss = useRef<() => void>(() => undefined);\n  useLayoutEffect(() => {\n    dismiss.current = () => {\n      const current = open;\n      stopHover();\n      setOpen(null);\n      if (current !== null) focusTrigger(current);\n    };\n  });\n  const depth = useDismissDepth();\n  useLayoutEffect(() => {\n    if (open === null) return;\n    return pushDismissLayer((event) => {\n      if (event.eventType === \"keyDown\") {\n        dismiss.current();\n        return;\n      }\n      stopHover();\n      setOpen(null);\n    }, depth);\n  }, [depth, open, setOpen, stopHover]);\n\n  const context = useMemo<NavigationMenuContextValue>(\n    () => ({\n      open,\n      setOpen,\n      registerTrigger,\n      moveFocus,\n      focusTrigger,\n      panelFocus,\n      requestPanelFocus: setPanelFocus,\n      clearPanelFocus: () => setPanelFocus(null),\n      hoverOpen,\n      hoverClose,\n      hoverPanel,\n      cancelOpening,\n      stopHover,\n      isTriggerPoint,\n    }),\n    [\n      cancelOpening,\n      focusTrigger,\n      hoverClose,\n      hoverOpen,\n      hoverPanel,\n      isTriggerPoint,\n      moveFocus,\n      open,\n      panelFocus,\n      registerTrigger,\n      setOpen,\n      stopHover,\n    ],\n  );\n\n  return (\n    <NavigationMenuContext.Provider value={context}>\n      <div style={floatingRootStyle()}>\n        <div\n          role=\"navigation\"\n          aria-label={label}\n          {...rest}\n          onKeyDown={(event: KeyEvent) => {\n            onKeyDown?.(event);\n            if (isDismiss(event)) dismissTopLayer(event);\n          }}\n          style={mergeStyles(\n            recipeStyle(cn(NAVIGATION_MENU_ROOT, className), theme),\n            style,\n          )}\n        >\n          {children}\n        </div>\n      </div>\n    </NavigationMenuContext.Provider>\n  );\n};\n\nexport interface NavigationMenuListProps extends Omit<Props, \"children\"> {\n  readonly className?: string;\n  readonly children?: PartChildren;\n}\n\nexport const NavigationMenuList = ({\n  children,\n  className,\n  style,\n  ...rest\n}: NavigationMenuListProps) => {\n  const theme = useTheme();\n  assertParts(navigationMenuList, children);\n  return (\n    <div\n      role=\"list\"\n      {...rest}\n      style={mergeStyles(\n        recipeStyle(cn(NAVIGATION_MENU_LIST, className), theme),\n        style,\n      )}\n    >\n      {children}\n    </div>\n  );\n};\n\nexport interface NavigationMenuItemProps extends Omit<Props, \"children\"> {\n  readonly value: string;\n\n  readonly className?: string;\n  readonly children?: PartChildren;\n}\n\nexport const NavigationMenuItem = ({\n  value,\n  className,\n  children,\n  style,\n  ...rest\n}: NavigationMenuItemProps) => {\n  const theme = useTheme();\n  const { open } = useNavigationMenu();\n  assertParts(navigationMenuItem, children);\n  return (\n    <ItemContext.Provider value={{ value, open: open === value }}>\n      <div\n        role=\"listitem\"\n        {...rest}\n        style={mergeStyles(\n          recipeStyle(cn(NAVIGATION_MENU_ITEM, className), theme),\n          style,\n        )}\n      >\n        {children}\n      </div>\n    </ItemContext.Provider>\n  );\n};\n\nexport const NavigationMenuTrigger = ({\n  onClick,\n  ref,\n  onKeyDown,\n  onMouseEnter,\n  onMouseLeave,\n  trailing,\n  disabled = false,\n  ...rest\n}: ButtonProps) => {\n  const theme = useTheme();\n  const {\n    open,\n    setOpen,\n    registerTrigger,\n    moveFocus,\n    requestPanelFocus,\n    hoverOpen,\n    hoverClose,\n    cancelOpening,\n    stopHover,\n  } = useNavigationMenu();\n  const { value } = useNavItem();\n  const expanded = open === value;\n\n  const chevronId = (mark: \"up\" | \"down\"): string | undefined =>\n    rest.testId === undefined ? undefined : `${rest.testId}-chevron-${mark}`;\n  const register = useCallback(\n    (instance: PublicInstance | null) => registerTrigger(value, instance),\n    [registerTrigger, value],\n  );\n  const setTrigger = useMergedRef<PublicInstance | null>(register, ref);\n\n  useLayoutEffect(() => {\n    if (disabled) cancelOpening();\n  }, [cancelOpening, disabled]);\n\n  return (\n    <Button\n      {...rest}\n      ref={setTrigger}\n      disabled={disabled}\n      aria-expanded={expanded}\n      trailing={\n        <>\n          {trailing}\n          <FlipMark\n            off=\"chevron-down\"\n            on=\"chevron-up\"\n            shown={expanded}\n            color={theme.colors.mutedForeground}\n            testIdFor={(mark) => chevronId(mark === \"on\" ? \"up\" : \"down\")}\n          />\n        </>\n      }\n      onMouseEnter={(event) => {\n        onMouseEnter?.(event);\n        if (!disabled) hoverOpen(value);\n      }}\n      onMouseLeave={(event) => {\n        onMouseLeave?.(event);\n        if (!disabled) hoverClose(value);\n      }}\n      onClick={(event) => {\n        onClick?.(event);\n        if (disabled) return;\n        stopHover();\n        setOpen(expanded ? null : value);\n      }}\n      onKeyDown={(event: KeyEvent) => {\n        onKeyDown?.(event);\n        if (disabled) return;\n        if (isDown(event)) {\n          stopHover();\n          setOpen(value);\n          requestPanelFocus(value);\n        } else if (isLeft(event)) {\n          moveFocus(value, -1);\n        } else if (isRight(event)) {\n          moveFocus(value, 1);\n        } else if (isFirst(event)) {\n          moveFocus(value, \"first\");\n        } else if (isLast(event)) {\n          moveFocus(value, \"last\");\n        }\n      }}\n    />\n  );\n};\n\nexport interface NavigationMenuContentProps extends Omit<Props, \"children\"> {\n  readonly className?: string;\n  readonly children?: PartChildren;\n}\n\nexport const NavigationMenuContent = ({\n  children,\n  className,\n  style,\n  onMouseDownOutside,\n  onMouseEnter,\n  onMouseLeave,\n  ...rest\n}: NavigationMenuContentProps) => {\n  const theme = useTheme();\n  const renderer = useGpuix().renderer;\n  const { value, open } = useNavItem();\n  const { panelFocus, clearPanelFocus, hoverPanel, isTriggerPoint } =\n    useNavigationMenu();\n  const [panel, setPanel] = useState<PublicInstance | undefined>(undefined);\n  const panelId = panel?.id;\n  const timing = useSurfaceTiming(\"normal\");\n  const presence = useSurfacePresence(open, timing);\n  assertParts(navigationMenuContent, children);\n\n  useLayoutEffect(() => {\n    if (!open || panelFocus !== value || panelId === undefined) return;\n    renderer?.focusElement?.(panelId);\n    clearPanelFocus();\n  }, [clearPanelFocus, open, panelFocus, panelId, renderer, value]);\n\n  if (!presence.mounted) return null;\n\n  return (\n    <FloatingLayer\n      motion={presenceMotion(fadeFromAnchor(\"bottom\", 4), presence)}\n      side=\"bottom\"\n      align=\"start\"\n      sideOffset={4}\n      collisionPadding={8}\n      role=\"group\"\n      aria-label={value}\n      tabIndex={-1}\n      {...rest}\n      ref={(instance) => setPanel(instance ?? undefined)}\n      onMouseEnter={(event) => {\n        hoverPanel(true);\n        onMouseEnter?.(event);\n      }}\n      onMouseLeave={(event) => {\n        hoverPanel(false);\n        onMouseLeave?.(event);\n      }}\n      onMouseDownOutside={(event) => {\n        onMouseDownOutside?.(event);\n        if (isTriggerPoint(event.x, event.y)) return;\n        dismissTopLayer(event);\n      }}\n      style={mergeStyles(\n        mergeStyles(\n          overlaySurfaceStyle(NAVIGATION_MENU_CONTENT, className, theme),\n\n          { position: \"relative\", ...presenceStyle(presence.present) },\n        ),\n        style,\n      )}\n    >\n      <DismissScope>\n        <PanelLeaving.Provider value={!presence.present}>\n          {children}\n        </PanelLeaving.Provider>\n      </DismissScope>\n      <PresenceShield present={presence.present} />\n    </FloatingLayer>\n  );\n};\n\nexport interface NavigationMenuLinkProps extends Omit<\n  PrimitiveButtonProps,\n  \"variant\"\n> {\n  readonly onSelect?: () => void;\n\n  readonly className?: string;\n\n  readonly onClick?: (event: EventPayload) => void;\n}\n\nexport const NavigationMenuLink = ({\n  onSelect,\n  onActivate,\n  onClick,\n  className,\n  style,\n  tabIndex,\n  ...rest\n}: NavigationMenuLinkProps) => {\n  const theme = useTheme();\n  const { setOpen, stopHover } = useNavigationMenu();\n\n  const leaving = usePanelLeaving();\n  const linkStyle = mergeStyles(\n    recipeStyle(cn(NAVIGATION_MENU_LINK, className), theme),\n    {\n      hover: {\n        backgroundColor: theme.colors.accent,\n        color: theme.colors.accentForeground,\n      },\n    },\n  );\n  return (\n    <PrimitiveButton\n      {...rest}\n      tabIndex={leaving ? -1 : tabIndex}\n      variant=\"ghost\"\n      onActivate={(event) => {\n        (onActivate ?? onClick)?.(event);\n        onSelect?.();\n        stopHover();\n        setOpen(null);\n      }}\n      style={(state) =>\n        mergeStyles(linkStyle, resolveStyle(style, state)) ?? {}\n      }\n    />\n  );\n};\n\nconst navigationMenuParts: ReadonlyArray<PartComponent> = [\n  NavigationMenu,\n  NavigationMenuList,\n  NavigationMenuItem,\n  NavigationMenuTrigger,\n  NavigationMenuContent,\n  NavigationMenuLink,\n];\n\nconst navigationMenuRoot: PartsContract = {\n  parent: \"NavigationMenu\",\n  family: navigationMenuParts,\n  accepts: [NavigationMenuList],\n  hint: \"Put NavigationMenuList directly inside NavigationMenu.\",\n};\n\nconst navigationMenuList: PartsContract = {\n  parent: \"NavigationMenuList\",\n  family: navigationMenuParts,\n  accepts: [NavigationMenuItem],\n  hint: \"Put NavigationMenuItem directly inside NavigationMenuList.\",\n};\n\nconst navigationMenuItem: PartsContract = {\n  parent: \"NavigationMenuItem\",\n  family: navigationMenuParts,\n  accepts: [NavigationMenuTrigger, NavigationMenuContent],\n  hint: \"Put NavigationMenuTrigger and NavigationMenuContent directly inside NavigationMenuItem.\",\n};\n\nconst navigationMenuContent: PartsContract = {\n  parent: \"NavigationMenuContent\",\n  family: navigationMenuParts,\n  accepts: [NavigationMenuLink],\n  hint: \"Put NavigationMenuLink rows directly inside NavigationMenuContent.\",\n};\n\nexport const navigationMenuMeta = {\n  name: \"Navigation Menu\",\n  tier: 2,\n  status: \"done\",\n  gpuixSupport: \"partial\",\n  limitations: [\n    \"no anchor/href in 0.11.0: NavigationMenuLink is a button with onSelect\",\n    \"hover opens after `openDelay` and closes after `closeDelay`; 0.11.0 has no pointer-type signal, so touch opens by press\",\n    \"ArrowDown moves focus to the panel surface, not straight to the first link\",\n    \"no aria-haspopup in 0.11.0\",\n  ],\n  docs: \"docs/navigation-menu.mdx\",\n  example: \"examples/navigation-menu.example.tsx\",\n  testFile: \"src/behaviour/navigation-menu.test.tsx\",\n} as const;\n"
    }
  ],
  "docs": "[Navigation menu](https://gpuixui.sudokw.com/components/navigation-menu) — These are GPUix native components: the files render through GPUix's reconciler against `@gpuix/react`, not the DOM, and need the per-platform `@gpuix/native` binding. The CLI installs the `@gpuixui/*` runtime the components import as registry items, so the copied tree resolves on its own; wrap it in `ThemeProvider` before it renders.",
  "meta": {
    "url": "/components/navigation-menu",
    "kind": "component",
    "runtime": "gpuix",
    "registry": "gpuixui"
  }
}