{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "socket",
  "title": "Socket",
  "description": "One socket: a perk column (stacked circles) or a mod socket (squares).",
  "dependencies": [
    "@engram/core"
  ],
  "registryDependencies": [
    "@engram/cn",
    "@engram/item-hover-card",
    "@engram/plug",
    "@engram/plug-badge",
    "@engram/tokens"
  ],
  "files": [
    {
      "path": "src/components/socket.tsx",
      "content": "import type {\n  PlugAnnotation,\n  PlugProps as PlugData,\n  SocketProps as SocketData,\n} from \"@engram/core\";\nimport type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn.js\";\nimport { ItemHoverCard } from \"./item-hover-card.js\";\nimport { Plug } from \"./plug.js\";\nimport { PlugBadge } from \"./plug-badge.js\";\n\nexport interface SocketProps extends SocketData {\n  className?: string;\n  /** Pixel size for this socket's plugs. */\n  plugSize?: number;\n  /** Typed curated-roll annotations keyed by plug hash (rendered as default badges). */\n  annotations?: Record<number, PlugAnnotation>;\n  /** Fully override the badge for a plug (takes precedence over `annotations`). */\n  renderBadge?: (plug: PlugData) => ReactNode;\n  /** Called when a plug is clicked. */\n  onPlugClick?: (plug: PlugData) => void;\n  /** A plug's inspect popup (e.g. a {@link ModPopup}). When it returns a node,\n   *  the plug reveals it on hover beside the parent inspect panel — the in-game\n   *  \"hover a mod to read it\" detail. Return `null` for plugs with no inspect. */\n  plugPopup?: (plug: PlugData) => ReactNode;\n}\n\n/**\n * One socket: a perk column (stacked circles) or a mod socket (squares). Perk\n * columns list the rolled options; the inserted plug is `selected`.\n */\nexport function Socket({\n  kind,\n  plugs,\n  className,\n  plugSize,\n  annotations,\n  renderBadge,\n  onPlugClick,\n  plugPopup,\n}: SocketProps) {\n  const isPerk = kind === \"perk\";\n  const badgeFor = (plug: PlugData): ReactNode => {\n    if (renderBadge) return renderBadge(plug);\n    const ann = annotations?.[plug.hash];\n    return ann ? <PlugBadge annotation={ann} /> : undefined;\n  };\n  return (\n    <div\n      className={cn(\n        \"flex gap-1.5\",\n        isPerk ? \"flex-col items-center\" : \"flex-row flex-wrap\",\n        className,\n      )}\n    >\n      {plugs.map((plug) => {\n        const node = (\n          <Plug\n            key={plug.hash}\n            {...plug}\n            kind={kind}\n            size={plugSize ?? (isPerk ? 34 : 40)}\n            badge={badgeFor(plug)}\n            onClick={onPlugClick ? () => onPlugClick(plug) : undefined}\n          />\n        );\n        const pop = plugPopup?.(plug);\n        // Hover the plug → its inspect appears beside the parent panel.\n        return pop ? (\n          <ItemHoverCard key={plug.hash} as=\"span\" anchor=\"panel\" popup={pop}>\n            {node}\n          </ItemHoverCard>\n        ) : (\n          node\n        );\n      })}\n    </div>\n  );\n}\n",
      "type": "registry:component",
      "target": "components/engram/socket.tsx"
    }
  ],
  "meta": {
    "level": "component"
  },
  "docs": "Extend without forking: edit the copied source, use `asChild` (Radix Slot) to change the rendered element, pass the typed `annotations` prop for curated data (verdict/tags/per-plug), or use slot / render-prop props for arbitrary content. Requires the @engram/tokens theme (--engram-* CSS variables).",
  "categories": [
    "socket"
  ],
  "type": "registry:component"
}