# CLAUDE.md — `web/src/components/`

React component library for ONE web UI.

**Rules auto-loaded here (glob-matched — don't repeat their content):**
- `.claude/rules/design.md` — 6 tokens, no hex, depth levels, card/icon/form/button patterns
- `.claude/rules/ui.md` — `emitClick` on every onClick
- `.claude/rules/react.md` — typed props, named exports, React 19 patterns
- `.claude/rules/astro.md` — lazy imports for heavy modules

## Structure

```
components/
├── ui/           # Primitives: Button, Card, Drawer, Input, Icon, IconBadge, Badge
├── cards/        # 13 card types — all extend CardProps from @/lib/cards
├── chat/         # ChatDock, MessageRenderer, MessageList, InputArea
├── agents/       # AgentDrawer, AgentGrid
├── skills/       # SkillDrawer, SkillGallery
├── payments/     # EscrowBadge, PriceSelect
├── settings/     # SettingsDrawer, BrandPalette (token editor)
├── auth/         # PasskeyKeepThis (WebAuthn ceremony)
├── sidebar/      # Sidebar, GroupSwitcher, auth controls (own CLAUDE.md)
├── groups/       # MembersPanel + operator surfaces (own CLAUDE.md)
├── paths/        # PathGraph — read-only strength/resistance ReactFlow view (C8)
└── showcase/     # Design system showcase
```

## CardProps contract

All `cards/` components extend `CardProps` from `@/lib/cards`:

```tsx
import { CardProps } from '@/lib/cards'
interface AgentPreviewCardProps extends CardProps {
  agent: Agent
  onSelect?: (id: string) => void
}
```

## Heavy modules — always lazy inside islands

| Module | Size |
|--------|------|
| `@/components/ai-elements/attachments` | ~281 KB |
| `@/components/ai-elements/speech-input` | ~180 KB |
| `@/components/ai-elements/voice-menu` | ~140 KB |
| `@/components/payments/PayPanel` | ~120 KB |
| `@/components/chat/MessageList` | ~95 KB |

```tsx
const MessageList = lazy(() =>
  import('@/components/chat/MessageList').then(m => ({ default: m.MessageList })))
```

## Import paths

```tsx
import { AgentCard } from '@/components/cards/AgentCard'
import { Card } from '@/components/ui/Card'
import { emitClick } from '@/lib/ui-signal'
```

## See also

- `/design` — live token showcase
- `.claude/rules/design.md` — token enforcement, patterns
- `.claude/rules/ui.md` — emitClick contract
