{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "sidebar-nav",
  "title": "Sidebar Nav",
  "description": "The nx-ui Sidebar Nav block.",
  "dependencies": [
    "@untitledui/icons@^0.0.22"
  ],
  "registryDependencies": [
    "@nx-ui/collapsible",
    "@nx-ui/sidebar",
    "@nx-ui/utils"
  ],
  "files": [
    {
      "path": "components/blocks/sidebar-nav.tsx",
      "content": "\"use client\"\n\nimport * as React from \"react\"\nimport Link from \"next/link\"\nimport { ChevronDown } from \"@untitledui/icons\"\n\nimport { cn } from \"@/lib/utils\"\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"@/components/ui/collapsible\"\nimport {\n  SidebarGroup,\n  SidebarGroupLabel,\n  SidebarMenu,\n  SidebarMenuButton,\n  SidebarMenuItem,\n  SidebarMenuSub,\n  SidebarMenuSubButton,\n  SidebarMenuSubItem,\n} from \"@/components/ui/sidebar\"\n\nexport type SidebarNavItem = {\n  title: string\n  href?: string\n  /**\n   * State-driven alternative to `href`: when set, the item renders as a\n   * button and selection stays with the consumer (SPA tabs, the scoped-app\n   * example). Provide one of `href` / `onSelect`.\n   */\n  onSelect?: () => void\n  icon?: React.ComponentType<{ className?: string }>\n  badge?: React.ReactNode\n  isActive?: boolean\n  items?: {\n    title: string\n    href?: string\n    onSelect?: () => void\n    isActive?: boolean\n  }[]\n}\n\nexport type SidebarNavGroup = {\n  label?: string\n  items: SidebarNavItem[]\n}\n\n/**\n * The active-item indicator: a small brand-coloured bar hugging the item's\n * left edge that scales/fades in as the item becomes active — the same 200ms\n * ease-out vocabulary as the scoped-nav level slide. Instant under reduced\n * motion.\n */\nconst activeIndicatorClass =\n  \"relative before:absolute before:top-1/2 before:left-0 before:h-4 before:w-0.5 before:-translate-y-1/2 before:scale-y-0 before:rounded-full before:bg-sidebar-primary before:opacity-0 before:transition-[transform,opacity] before:duration-200 before:ease-out before:content-[''] data-active:before:scale-y-100 data-active:before:opacity-100 motion-reduce:before:transition-none\"\n\n/** The nx nav-item look layered over the shadcn SidebarMenuButton. */\nconst navButtonClass = cn(\n  \"h-9 gap-3 rounded-lg font-semibold [&>svg]:size-5 [&>svg]:text-fg-quaternary\",\n  // Hover/active micro-transitions: the leading icon eases towards a darker\n  // step alongside the button's own background/text transition.\n  \"[&>svg]:transition-colors [&>svg]:duration-150 hover:[&>svg]:text-fg-quaternary_hover data-active:[&>svg]:text-fg-tertiary\",\n  activeIndicatorClass\n)\n\n/** Sub-items keep the same colour easing as their parents (no indicator bar —\n * the sub-menu rail already anchors them). */\nconst subButtonClass =\n  \"transition-[background-color,color] duration-150 ease-out motion-reduce:transition-none\"\n\nfunction NavBadge({ badge }: { badge: React.ReactNode }) {\n  if (badge == null) return null\n  if (typeof badge === \"string\" || typeof badge === \"number\") {\n    return (\n      <span className=\"ml-auto inline-flex h-5 min-w-5 shrink-0 items-center justify-center rounded-full bg-muted px-1.5 text-xs font-semibold text-muted-foreground tabular-nums\">\n        {badge}\n      </span>\n    )\n  }\n  return <span className=\"ml-auto shrink-0\">{badge}</span>\n}\n\nfunction NavItem({ item }: { item: SidebarNavItem }) {\n  const Icon = item.icon\n\n  // Collapsible group with sub-items.\n  if (item.items?.length) {\n    const groupActive =\n      item.isActive || item.items.some((sub) => sub.isActive)\n\n    return (\n      <Collapsible defaultOpen={groupActive} render={<SidebarMenuItem />}>\n        <CollapsibleTrigger\n          render={\n            <SidebarMenuButton\n              isActive={item.isActive}\n              className={cn(navButtonClass, \"group/collapsible\")}\n            />\n          }\n        >\n          {Icon ? <Icon /> : null}\n          <span>{item.title}</span>\n          <NavBadge badge={item.badge} />\n          <ChevronDown className=\"ml-auto size-4 shrink-0 text-fg-quaternary transition-transform group-data-[panel-open]/collapsible:rotate-180\" />\n        </CollapsibleTrigger>\n        <CollapsibleContent>\n          <SidebarMenuSub>\n            {item.items.map((sub) => (\n              <SidebarMenuSubItem key={`${sub.title}${sub.href ?? \"\"}`}>\n                <SidebarMenuSubButton\n                  isActive={sub.isActive}\n                  className={subButtonClass}\n                  {...(sub.onSelect\n                    ? { onClick: sub.onSelect }\n                    : { render: <Link href={sub.href ?? \"#\"} /> })}\n                >\n                  <span>{sub.title}</span>\n                </SidebarMenuSubButton>\n              </SidebarMenuSubItem>\n            ))}\n          </SidebarMenuSub>\n        </CollapsibleContent>\n      </Collapsible>\n    )\n  }\n\n  return (\n    <SidebarMenuItem>\n      <SidebarMenuButton\n        isActive={item.isActive}\n        className={navButtonClass}\n        {...(item.onSelect\n          ? { onClick: item.onSelect }\n          : { render: <Link href={item.href ?? \"#\"} /> })}\n      >\n        {Icon ? <Icon /> : null}\n        <span>{item.title}</span>\n        <NavBadge badge={item.badge} />\n      </SidebarMenuButton>\n    </SidebarMenuItem>\n  )\n}\n\n/**\n * SidebarNav — renders grouped navigation inside an AppSidebar's content area.\n * Each group is an optionally-labelled section; items become links, and items\n * with `items` become collapsible sub-navigation. Active state is passed in via\n * `isActive` (blocks are data-driven — routing stays with the consumer).\n */\nfunction SidebarNav({ groups }: { groups: SidebarNavGroup[] }) {\n  return (\n    <>\n      {groups.map((group, index) => (\n        <SidebarGroup key={group.label ?? index}>\n          {group.label ? (\n            <SidebarGroupLabel>{group.label}</SidebarGroupLabel>\n          ) : null}\n          <SidebarMenu>\n            {group.items.map((item) => (\n              <NavItem key={`${item.title}${item.href ?? \"\"}`} item={item} />\n            ))}\n          </SidebarMenu>\n        </SidebarGroup>\n      ))}\n    </>\n  )\n}\n\nexport { SidebarNav }\n",
      "type": "registry:component"
    }
  ],
  "type": "registry:block"
}