{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"corded-channel-list","title":"Corded Channel List","description":"Collapsible channel groups with selection, unread indicators, mentions, and text, voice, and private channels.","dependencies":["lucide-react"],"registryDependencies":["utils","corded-theme"],"files":[{"path":"registry/default/ui/corded-channel-list.tsx","content":"\"use client\"\n\nimport * as React from \"react\"\nimport { ChevronRight, Hash, LockKeyhole, Volume2 } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\n\nexport interface CordedChannel {\n  id: string\n  name: string\n  type?: \"text\" | \"voice\" | \"private\"\n  unread?: boolean\n  mentions?: number\n  disabled?: boolean\n}\n\nexport interface CordedChannelGroup {\n  id: string\n  label: string\n  channels: CordedChannel[]\n  defaultOpen?: boolean\n}\n\nexport interface CordedChannelListProps extends Omit<React.ComponentProps<\"nav\">, \"onSelect\"> {\n  groups: CordedChannelGroup[]\n  value?: string\n  defaultValue?: string\n  onValueChange?: (id: string) => void\n}\n\nexport function CordedChannelList({ groups, value, defaultValue, onValueChange, className, \"aria-label\": label = \"Channels\", ...props }: CordedChannelListProps) {\n  const [internalValue, setInternalValue] = React.useState(defaultValue)\n  const selected = value === undefined ? internalValue : value\n\n  return (\n    <nav aria-label={label} className={cn(\"space-y-4\", className)} {...props}>\n      {groups.map((group) => (\n        <details key={group.id} open={group.defaultOpen ?? true} className=\"group/category\">\n          <summary className=\"mb-1 flex cursor-pointer list-none items-center gap-1 rounded px-1 py-2 text-xs font-bold uppercase tracking-wide text-[var(--text-muted)] hover:text-[var(--text-default)] focus-visible:outline-2 focus-visible:outline-[var(--border-focus)] [&::-webkit-details-marker]:hidden\">\n            <ChevronRight aria-hidden=\"true\" className=\"size-3 transition-transform group-open/category:rotate-90\" />\n            {group.label}\n          </summary>\n          <ul className=\"space-y-0.5\">\n            {group.channels.map((channel) => {\n              const Icon = channel.type === \"voice\" ? Volume2 : channel.type === \"private\" ? LockKeyhole : Hash\n              const active = selected === channel.id\n              return (\n                <li key={channel.id}>\n                  <button\n                    type=\"button\"\n                    disabled={channel.disabled}\n                    aria-current={active ? \"page\" : undefined}\n                    onClick={() => {\n                      if (value === undefined) setInternalValue(channel.id)\n                      onValueChange?.(channel.id)\n                    }}\n                    className={cn(\"relative flex w-full items-center gap-2 rounded-md px-2 py-2 text-left text-sm text-[var(--text-muted)] hover:bg-[var(--background-mod-subtle)] hover:text-[var(--text-default)] focus-visible:outline-2 focus-visible:outline-[var(--border-focus)] disabled:pointer-events-none disabled:opacity-40\", channel.unread && \"font-semibold text-[var(--text-default)]\", active && \"bg-[var(--background-mod-normal)] text-[var(--text-default)]\")}\n                  >\n                    {channel.unread && <span aria-hidden=\"true\" className=\"absolute -left-2 h-2 w-1 rounded-r bg-[var(--text-default)]\" />}\n                    <Icon aria-hidden=\"true\" className=\"size-5 shrink-0 opacity-70\" />\n                    <span className=\"min-w-0 flex-1 truncate\">{channel.name}</span>\n                    {channel.unread && <span className=\"sr-only\">Unread</span>}\n                    {(channel.mentions ?? 0) > 0 && <span className=\"rounded-full bg-[var(--status-danger)] px-1.5 text-xs font-bold text-white\"><span className=\"sr-only\">Mentions: </span>{channel.mentions}</span>}\n                  </button>\n                </li>\n              )\n            })}\n          </ul>\n        </details>\n      ))}\n    </nav>\n  )\n}\n","type":"registry:ui","target":"components/ui/corded-channel-list.tsx"}],"type":"registry:ui"}