{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "connector-card",
  "type": "registry:ui",
  "title": "Connector Card",
  "description": "Integration card with OAuth states, per-conversation enable switch, and a discovered-tools disclosure.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "registryDependencies": [
    "https://seamui.dev/r/utils.json",
    "https://seamui.dev/r/motion.json",
    "https://seamui.dev/r/button.json",
    "https://seamui.dev/r/badge.json",
    "https://seamui.dev/r/switch.json",
    "https://seamui.dev/r/collapsible.json"
  ],
  "files": [
    {
      "path": "registry/seam/ui/connector-card.tsx",
      "content": "\"use client\"\n\nimport type * as React from \"react\"\nimport { motion } from \"motion/react\"\nimport { ChevronDown, Plug } from \"lucide-react\"\n\nimport { cn } from \"@/lib/utils\"\nimport { springs, fades, depth, reduced, useReducedMotion } from \"@/lib/motion\"\nimport { Badge } from \"./badge\"\nimport { Button, buttonVariants } from \"./button\"\nimport {\n  Collapsible,\n  CollapsibleContent,\n  CollapsibleTrigger,\n} from \"./collapsible\"\nimport { Switch } from \"./switch\"\n\n// The Claude.ai connector directory as components: an integration card with\n// connect/disconnect, OAuth states, the per-conversation enable switch, and\n// a discovered-tools disclosure. No OAuth or MCP runtime coupling — state in,\n// callbacks out.\n\ntype ConnectorState = \"connected\" | \"disconnected\" | \"needs-auth\" | \"error\"\n\nconst STATUS_TEXT: Record<ConnectorState, string> = {\n  connected: \"Connected\",\n  disconnected: \"Not connected\",\n  \"needs-auth\": \"Needs re-authentication\",\n  error: \"Connection error\",\n}\n\nfunction ConnectorCard({\n  name,\n  description,\n  icon,\n  connection = \"disconnected\",\n  enabled,\n  onEnabledChange,\n  onConnect,\n  onDisconnect,\n  tools,\n  className,\n  ...props\n}: React.ComponentProps<\"div\"> & {\n  name: React.ReactNode\n  description?: React.ReactNode\n  /** Logo / lucide icon; sits in a small carved well on the key. */\n  icon?: React.ReactNode\n  connection?: ConnectorState\n  /** Per-conversation enablement — only rendered while connected. */\n  enabled?: boolean\n  onEnabledChange?: (enabled: boolean) => void\n  onConnect?: () => void\n  onDisconnect?: () => void\n  /** Discovered tool names — renders the \"N tools\" disclosure. */\n  tools?: string[]\n}) {\n  const reduceMotion = useReducedMotion()\n  const attention = connection === \"needs-auth\" || connection === \"error\"\n\n  return (\n    <div\n      data-slot=\"connector-card\"\n      data-connection={connection}\n      role=\"group\"\n      aria-label={`${typeof name === \"string\" ? name : \"Connector\"}: ${STATUS_TEXT[connection]}`}\n      className={cn(\n        \"bg-card text-card-foreground rounded-xl squircle border border-border/60 p-4 shadow-resting\",\n        className\n      )}\n      {...props}\n    >\n      <div className=\"flex items-start gap-3\">\n        <div\n          data-slot=\"connector-card-icon\"\n          aria-hidden\n          className=\"bg-muted text-muted-foreground flex size-9 shrink-0 items-center justify-center rounded-md squircle border border-border/60 shadow-well [&_svg:not([class*='size-'])]:size-4\"\n        >\n          {icon ?? <Plug />}\n        </div>\n        <div className=\"min-w-0 flex-1\">\n          <div className=\"truncate text-sm font-medium\">{name}</div>\n          <div\n            data-slot=\"connector-card-status\"\n            className={cn(\n              \"truncate text-xs\",\n              attention ? \"text-destructive\" : \"text-muted-foreground\"\n            )}\n          >\n            {STATUS_TEXT[connection]}\n          </div>\n        </div>\n        <div className=\"flex shrink-0 items-center gap-2\">\n          {connection === \"connected\" ? (\n            <>\n              <Switch\n                aria-label=\"Use in this conversation\"\n                checked={enabled}\n                onCheckedChange={(checked) => onEnabledChange?.(checked)}\n              />\n              <Button\n                variant=\"ghost\"\n                size=\"sm\"\n                className=\"text-muted-foreground h-7 px-2 text-xs\"\n                onClick={() => onDisconnect?.()}\n              >\n                Disconnect\n              </Button>\n            </>\n          ) : (\n            <Button\n              variant={attention ? \"outline\" : \"secondary\"}\n              size=\"sm\"\n              className={cn(\n                \"h-7 px-2.5 text-xs\",\n                attention && \"text-destructive\"\n              )}\n              onClick={() => onConnect?.()}\n            >\n              {attention ? \"Reconnect\" : \"Connect\"}\n            </Button>\n          )}\n        </div>\n      </div>\n\n      {description ? (\n        <p className=\"text-muted-foreground mt-2 text-xs\">{description}</p>\n      ) : null}\n\n      {tools && tools.length > 0 ? (\n        <Collapsible data-slot=\"connector-card-tools\" className=\"mt-2\">\n          <CollapsibleTrigger\n            className={cn(\n              buttonVariants({ variant: \"ghost\", size: \"sm\" }),\n              \"group/tools text-muted-foreground h-6 gap-1 px-1.5 text-xs font-normal\"\n            )}\n            render={\n              <motion.button\n                whileTap={reduceMotion ? reduced.pressed : depth.pressed}\n                transition={reduceMotion ? fades.fast : springs.press}\n              />\n            }\n          >\n            {tools.length} {tools.length === 1 ? \"tool\" : \"tools\"}\n            <ChevronDown\n              aria-hidden\n              className=\"size-3 transition-transform duration-200 group-data-[panel-open]/tools:rotate-180 motion-reduce:transition-none\"\n            />\n          </CollapsibleTrigger>\n          <CollapsibleContent>\n            <div className=\"flex flex-wrap gap-1 pt-1.5\">\n              {tools.map((tool) => (\n                <Badge\n                  key={tool}\n                  variant=\"muted\"\n                  className=\"font-mono text-[10px]\"\n                >\n                  {tool}\n                </Badge>\n              ))}\n            </div>\n          </CollapsibleContent>\n        </Collapsible>\n      ) : null}\n    </div>\n  )\n}\n\n// The grid the cards sit in — layout only.\nfunction ConnectorList({ className, ...props }: React.ComponentProps<\"div\">) {\n  return (\n    <div\n      data-slot=\"connector-list\"\n      className={cn(\"grid w-full gap-3 sm:grid-cols-2\", className)}\n      {...props}\n    />\n  )\n}\n\nexport { ConnectorCard, ConnectorList, type ConnectorState }\n",
      "type": "registry:ui",
      "target": "components/ui/connector-card.tsx"
    }
  ]
}