{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "core-module-navbar",
  "type": "registry:ui",
  "title": "Module Navbar",
  "description": "A composition-first module faceplate navbar with brand, preset, action, preferences, status, and controlled power slots in a stable responsive order.",
  "dependencies": [
    "maruaudio@>=0.0.3 <0.1.0",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "https://pluginui.com/r/core-module-power-button.json"
  ],
  "files": [
    {
      "path": "components/ui/module-navbar.tsx",
      "content": "/**\n * Source: https://maru.audio/ui-kit/module-navbar\n * Copyright © [Maru](https://maru.audio)\n *\n * Maru UI Kit — https://maru.audio/ui-kit\n *\n * Installed from the Maru UI registry. This file is yours now: edit it\n * freely, it will not be overwritten unless you re-run the add command.\n *\n * Keep this item’s companion files and CSS imports together. Dependencies\n * declared by the registry are installed with the source.\n */\nimport type {\n  CSSProperties,\n  HTMLAttributes,\n  KeyboardEvent,\n  ReactNode,\n} from \"react\"\nimport { twMerge } from \"tailwind-merge\"\nimport { UI_KIT_PORTABLE_STYLES } from \"maruaudio/ui/shared/portable-styles\"\n\nimport {\n  ModulePowerButton,\n  type ModulePowerButtonProps,\n} from \"@/components/ui/module-power-button\"\n\nexport type ModuleNavbarTone = \"light\" | \"dark\" | \"inherit\"\n\nexport interface ModuleNavbarClassNames {\n  root?: string\n  brand?: string\n  name?: string\n  subtitle?: string\n  beforePreset?: string\n  preset?: string\n  actions?: string\n  preferences?: string\n  status?: string\n  power?: string\n}\n\nexport interface ModuleNavbarPowerProps extends Omit<\n  ModulePowerButtonProps,\n  \"className\"\n> {\n  className?: string\n}\n\nexport interface ModuleNavbarProps extends Omit<\n  HTMLAttributes<HTMLElement>,\n  \"children\"\n> {\n  /** Rich identity slot. When absent, `name` renders the normalized wordmark. */\n  brand?: ReactNode\n  name?: string\n  subtitle?: ReactNode\n  /** Optional control immediately before the preset selector. */\n  beforePreset?: ReactNode\n  /** Usually the shared PresetSelector, but intentionally accepts any host adapter. */\n  preset?: ReactNode\n  /** Module-local actions that are not preferences. */\n  actions?: ReactNode\n  /** Trigger + popover supplied by the host's preferred accessible popover base. */\n  preferences?: ReactNode\n  /** Optional read-only state, for example a generator's Live LED. */\n  status?: ReactNode\n  /** Controlled module power. The host remains the source of truth. */\n  power?: ModuleNavbarPowerProps | false\n  /** Escape hatch for a custom power renderer that still occupies the canonical slot. */\n  powerSlot?: ReactNode\n  /** Remove the default surface and layout while retaining toolbar semantics. */\n  unstyled?: boolean\n  tone?: ModuleNavbarTone\n  classNames?: ModuleNavbarClassNames\n  style?: CSSProperties\n}\n\nexport interface ModuleNavbarRootProps extends HTMLAttributes<HTMLElement> {\n  tone?: ModuleNavbarTone\n  /** Behavior-only mode for fully custom faceplate composition. */\n  unstyled?: boolean\n}\n\nexport interface ModuleLiveIndicatorProps {\n  live: boolean\n  label?: string\n  className?: string\n}\n\nconst toneStyles: Record<\n  Exclude<ModuleNavbarTone, \"inherit\">,\n  CSSProperties\n> = {\n  light: {\n    \"--module-navbar-surface\": \"rgba(250, 250, 250, 0.92)\",\n    \"--module-navbar-border\": \"rgba(24, 24, 27, 0.14)\",\n    \"--module-navbar-ink\": \"#27272a\",\n    \"--module-navbar-muted\": \"#71717a\",\n  } as CSSProperties,\n  dark: {\n    \"--module-navbar-surface\": \"rgba(24, 24, 27, 0.88)\",\n    \"--module-navbar-border\": \"rgba(244, 244, 245, 0.14)\",\n    \"--module-navbar-ink\": \"#f4f4f5\",\n    \"--module-navbar-muted\": \"#a1a1aa\",\n  } as CSSProperties,\n}\n\nconst inheritToneStyle = {\n  \"--module-navbar-surface\": \"transparent\",\n  \"--module-navbar-border\":\n    \"color-mix(in oklab, currentColor 14%, transparent)\",\n  \"--module-navbar-ink\": \"currentColor\",\n  \"--module-navbar-muted\": \"color-mix(in oklab, currentColor 62%, transparent)\",\n} as CSSProperties\n\nfunction join(...values: Array<string | undefined | false>): string {\n  return twMerge(values.filter(Boolean).join(\" \"))\n}\n\nfunction moveToolbarFocus(event: KeyboardEvent<HTMLElement>) {\n  if (![\"ArrowLeft\", \"ArrowRight\", \"Home\", \"End\"].includes(event.key)) return\n  if (event.defaultPrevented) return\n  const controls = Array.from(\n    event.currentTarget.querySelectorAll<HTMLElement>(\n      'button:not(:disabled), select:not(:disabled), input:not(:disabled), [tabindex]:not([tabindex=\"-1\"])'\n    )\n  ).filter((control) => control.getAttribute(\"aria-hidden\") !== \"true\")\n  if (controls.length === 0) return\n  const current = controls.indexOf(document.activeElement as HTMLElement)\n  if (current < 0) return\n  event.preventDefault()\n  const next =\n    event.key === \"Home\"\n      ? 0\n      : event.key === \"End\"\n        ? controls.length - 1\n        : (current + (event.key === \"ArrowRight\" ? 1 : -1) + controls.length) %\n          controls.length\n  controls[next]?.focus()\n}\n\nconst ROOT_CLASS_NAME =\n  \"relative flex min-h-12 min-w-0 flex-wrap items-center gap-x-3 gap-y-2 border-b border-[color:var(--module-navbar-border,currentColor)] bg-[var(--module-navbar-surface,transparent)] px-4 py-2 text-[var(--module-navbar-ink,currentColor)]\"\n\n/** Headless composition root for consumers that need a fully custom template. */\nexport function ModuleNavbarRoot({\n  tone = \"inherit\",\n  unstyled = false,\n  className,\n  style,\n  onKeyDown,\n  ...props\n}: ModuleNavbarRootProps) {\n  return (\n    <header\n      role=\"toolbar\"\n      data-module-navbar\n      data-tone={tone}\n      className={join(!unstyled && ROOT_CLASS_NAME, className)}\n      style={{\n        ...(tone === \"inherit\" ? inheritToneStyle : toneStyles[tone]),\n        ...style,\n      }}\n      onKeyDown={(event) => {\n        onKeyDown?.(event)\n        moveToolbarFocus(event)\n      }}\n      {...props}\n    />\n  )\n}\n\n/** Read-only counterpart to ModulePowerButton for non-bypassable modules. */\nexport function ModuleLiveIndicator({\n  live,\n  label = \"Live\",\n  className,\n}: ModuleLiveIndicatorProps) {\n  return (\n    <span\n      role=\"status\"\n      aria-label={`${label}: ${live ? \"on\" : \"off\"}`}\n      data-live={live}\n      data-module-live-indicator\n      className={join(\n        \"inline-flex h-8 cursor-default items-center gap-2 px-1 text-[10px] leading-none font-semibold tracking-[0.14em] uppercase opacity-60 data-[live=true]:opacity-100\",\n        className\n      )}\n    >\n      <span\n        aria-hidden=\"true\"\n        data-module-live-dot\n        className=\"size-1.5 rounded-full bg-current opacity-35 data-[live=true]:opacity-100\"\n        data-live={live}\n      />\n      {label}\n    </span>\n  )\n}\n\n/**\n * Shared module faceplate navigation.\n *\n * This component owns order, spacing, responsive behavior, and the standard\n * power treatment. It deliberately owns no module state: preset selection,\n * preference values, and bypass remain controlled by the caller.\n */\nexport function ModuleNavbar({\n  brand,\n  name,\n  subtitle,\n  beforePreset,\n  preset,\n  actions,\n  preferences,\n  status,\n  power,\n  powerSlot,\n  unstyled = false,\n  tone = \"inherit\",\n  className,\n  classNames,\n  style,\n  ...props\n}: ModuleNavbarProps) {\n  const resolvedBrand = brand ?? (name ? <span>{name}</span> : null)\n  const resolvedPower =\n    powerSlot ??\n    (power ? (\n      <ModulePowerButton\n        variant=\"live\"\n        tone={tone === \"light\" ? \"light\" : \"dark\"}\n        {...power}\n        className={join(classNames?.power, power.className)}\n      />\n    ) : null)\n\n  return ModuleNavbarRoot({\n    ...props,\n    \"aria-label\": name ? `${name} controls` : \"Module controls\",\n    tone,\n    unstyled,\n    className: join(className, classNames?.root),\n    style,\n    children: (\n      <>\n        {/* Local injection keeps this registry item standalone in iframe/webview consumers. */}\n        <style data-maru-ui-kit-portable>{UI_KIT_PORTABLE_STYLES}</style>\n        {resolvedBrand ? (\n          <div\n            data-module-navbar-brand\n            className={join(\"min-w-0 shrink-0\", classNames?.brand)}\n          >\n            <div\n              className={join(\n                \"truncate text-sm font-semibold tracking-[0.12em]\",\n                classNames?.name\n              )}\n            >\n              {resolvedBrand}\n            </div>\n            {subtitle ? (\n              <div\n                className={join(\n                  \"truncate text-[10px] text-[var(--module-navbar-muted,currentColor)]\",\n                  classNames?.subtitle\n                )}\n              >\n                {subtitle}\n              </div>\n            ) : null}\n          </div>\n        ) : null}\n\n        {beforePreset ? (\n          <div\n            data-module-navbar-before-preset\n            className={join(\"flex shrink-0 items-center\", classNames?.beforePreset)}\n          >\n            {beforePreset}\n          </div>\n        ) : null}\n\n        {preset ? (\n          <div\n            data-module-navbar-preset\n            className={join(\n              \"min-w-0 flex-1 basis-44 sm:flex-initial sm:basis-auto\",\n              classNames?.preset\n            )}\n          >\n            {preset}\n          </div>\n        ) : (\n          <span className=\"min-w-0 flex-1\" aria-hidden=\"true\" />\n        )}\n\n        <div\n          data-module-navbar-trailing\n          className=\"ml-auto flex shrink-0 items-center gap-2\"\n        >\n          {actions ? (\n            <div\n              data-module-navbar-actions\n              className={join(\"flex items-center gap-1\", classNames?.actions)}\n            >\n              {actions}\n            </div>\n          ) : null}\n          {status ? (\n            <div\n              data-module-navbar-status\n              className={join(\"flex items-center\", classNames?.status)}\n            >\n              {status}\n            </div>\n          ) : null}\n          {preferences ? (\n            <div\n              data-module-navbar-preferences\n              className={join(\"flex items-center\", classNames?.preferences)}\n            >\n              {preferences}\n            </div>\n          ) : null}\n          {resolvedPower}\n        </div>\n      </>\n    ),\n  })\n}\n",
      "type": "registry:component",
      "target": "@ui/module-navbar.tsx"
    }
  ]
}
