# T03 — UI Primitive Contract (Recipe Manager UI Kit)

Date: 2026-03-27  
Scope: `recipe-manager/frontend`

## Goal
Stabilize core UI primitives so pages stop re-implementing button/card/chip/layout class strings.

This is a **low-risk contract layer**, not a redesign system.

---

## Contract surface (v1)

Implemented in:
- `frontend/src/components/ui/cn.ts`
- `frontend/src/components/ui/primitives.tsx`

### `cn(...values)`
- Lightweight class composer used by primitives and page-level variant helpers.
- Avoids repetitive template-string class logic.

### `UiPage`
- Canonical page shell wrapper (`ui-page` + optional additions).
- Use for top-level layout regions (header container, footer container, page root if needed).

### `UiSection`
- Canonical section shell (`ui-section`) with controlled padding options:
  - `padding="md"` (default)
  - `padding="lg"`
  - `padding="none"`
- Use for grouped content blocks and major page sections.

### `UiCard`
- Canonical card surface (`ui-card`) with optional tone:
  - `tone="default"`
  - `tone="muted"`
- Use for repeatable content cards and skeleton containers.

### `UiButton`
- Canonical button primitive (`ui-btn` + variant mapping):
  - `variant="primary"`
  - `variant="secondary"` (default)
- Use for interactive `<button>` actions.

### `UiLinkButton`
- Anchor-style button for actual links (kept for future use where semantic `<a>` is needed).

### `UiChip` / `UiBadge`
- Canonical chip and badge wrappers around `ui-chip` / `ui-badge`.
- Use for compact status pills/filter tokens.

---

## Representative adoption in T03

### 1) App shell (`src/App.tsx`)
- Header and footer wrappers now use `UiPage`.
- Navigation active/inactive styles now use a `cn(...)` helper contract rather than bespoke duplicated class strings.
- Shell color treatment shifted to tokenized variables (`var(--...)`) instead of slate/blue freelancing.

### 2) Mission Control (`src/components/MissionControlPanel.tsx`)
- Converted from gray utility block to tokenized contract primitives:
  - `UiSection` for panel shell
  - `UiChip` for status pills
- Removes bespoke gray class styling drift from this shared panel.

### 3) Recipe list page (`src/pages/RecipeListPage.tsx`)
- Core repeated shells now use primitives:
  - hero wrapper and filter blocks via `UiSection`
  - feature cards and loading skeleton via `UiCard`
  - key actions (`Search`, `Load More`, `Clear all filters`) via `UiButton`
- This proves the contract on a high-traffic page without broad redesign.

---

## Usage guidance for follow-on tasks

1. Prefer `UiSection`/`UiCard`/`UiButton` before writing new utility-heavy class blocks.
2. Use tokenized vars (`var(--...)`) for one-off values; avoid raw palette classes in shared surfaces.
3. Keep inline `style={{ ... }}` for runtime values only (e.g., tag color from data), not static radius/shadow/colors.
4. When classes need conditional composition, use `cn(...)` in one helper instead of many inlined strings.

---

## Intentionally deferred (not in T03)
- Broad conversion of `CookModePage`, `ImportUrlPage`, and full `RecipeDetailPage`.
- Full button/link semantic normalization (e.g., dedicated router-aware LinkButton primitive).
- Removal of all legacy one-off class usage in older components.

These are better handled in T04/T05 to keep T03 low-risk.
