# Badge — Figma alignment fix spec (X.4.2 batch)

## Inputs (✓ all read)

- ✓ `figma-data/normalized/figma-mcp-cache/badge.tsx` (axes: type(Circle/Rectangle) × color(Green/Blue/Orange/Red/Black) × tag(Filled/Line))
- ✓ `src/canonical/Badge.vue` (canonical SoT — Figma-aligned API)
- ✗ NOT auditing `src/components/Badge/Badge.vue` (legacy, npm-exported source = canonical/Badge.vue per file header)
- ✓ `figma-data/normalized/figma-styles.json`
- ✓ `src/design-system/translation/token-aliases.ts`
- ✓ `src/design-system/translation/prop-aliases.md`
- ✓ `src/design-system/translation/icon-aliases.ts`
- ✓ `src/tokens/variables.css`

## Mismatches by dimension

### Spacing

| Location | Canonical (`src/canonical/Badge.vue`) | Figma 真源 | Fix |
|---|---|---|---|
| Rectangle padding-inline | `12px` raw (via `--badge-padding-inline`) | `px-[var(--spacing\/s,12px)]` → `--sp-s` | replace `'12px'` with `'var(--sp-s)'` in `badgeVars` ternary |
| Rectangle padding-block | (canonical does NOT set padding-block; relies on `height: 24px`) | `py-[var(--spacing\/xxs,4px)]` → `--sp-xxs` | add `--badge-padding-block` domain var, set to `var(--sp-xxs)` for Rectangle, `0` for Circle |
| Circle width | `24px` raw | `w-[var(--size\/xxxs,24px)]` (figma "size" scale not in canonical token map) | propose new `--badge-circle-size: 24px` domain token, OR alias to existing `--sp-l` (24); recommend domain token for clarity |
| Circle height | `24px` raw on `.canonical-badge` | `h-[24px]` figma raw | same as above |
| Border thickness | `1px solid` (canonical) | `border` (1px solid) figma | ✓ match — keep 1px raw (no border-width token in canonical) |

### Color

| Location | Canonical | Figma 真源 | Fix |
|---|---|---|---|
| `palette.Black` | `var(--line-deep)` | `var(--color-type\/line\/deep-divider,#353535)` → `--line-deep` | ✓ match |
| `palette.Blue` | `var(--blue)` | `var(--ux\/blue\/default,#3892f3)` → `--blue` | ✓ match |
| `palette.Green` | `var(--brand)` | `var(--ux\/brand\/brand,#2fb54e)` → `--brand` | ✓ match |
| `palette.Orange` | `var(--orange)` | `var(--ux\/orange\/default,#f68512)` → `--orange` | ✓ match |
| `palette.Red` | `var(--red)` | `var(--ux\/red\/default,#ea4233)` → `--red` | ✓ match |
| Badge text color | `var(--text-primary-btn)` | `text-[color:var(--color-type\/text\/primary-button,white)]` → `--text-primary-btn` | ✓ match |

### Typography

| Location | Canonical | Figma 真源 | Fix |
|---|---|---|---|
| `.canonical-badge` `font-size` `12px` + `line-height` `16px` + `font-weight` `400` + `font-family: inherit` | three separate raw lines | `Roboto/12 tips` (12 / 16 / 400) → `--text-style-tips` | replace 4 lines with `font: var(--text-style-tips);` |

### Effect

- No shadows in figma source. Canonical has none. ✓ aligned.

### Composition

- Figma renders text content `5` for Circle; `Msg`/`Error`/`Warn`/`Active`/`Done` for Rectangle (color-keyed). Canonical hardcodes `'5'` (Circle) / `'Msg'` (Rectangle). **Mismatch**: rectangle text changes per color in figma (`Black=Msg`, `Red=Error`, `Orange=Warn`, `Blue=Active`, `Green=Done`).
  - **Fix**: extend `content` computed to color-keyed lookup table for Rectangle case (or accept slot-driven only — but default fallback should match figma). Recommend: keep `<slot>` for override, but default `content` should map color → label per figma.

### Variant coverage

| Axis | Figma values | Canonical | Status |
|---|---|---|---|
| type | `Circle`, `Rectangle` | `'Circle' \| 'Rectangle'` | ✓ match |
| color | `Green`, `Blue`, `Orange`, `Red`, `Black` | `'Black' \| 'Blue' \| 'Green' \| 'Orange' \| 'Red'` | ✓ match (default differs: figma `Green`, canonical `Black` — open decision) |
| tag | `Filled`, `Line` | `'Filled' \| 'Line'` | ✓ match |

Note: canonical default `color: 'Black'` deviates from figma default `color: 'Green'`. **Open decision**: align defaults? Recommend follow figma (`Green`) unless product reason exists.

## Token usage summary

After fix, canonical Badge should reference only:

- Spacing: `--sp-xxs`, `--sp-s`
- Color: `--brand`, `--blue`, `--orange`, `--red`, `--line-deep`, `--text-primary-btn`
- Typography: `--text-style-tips`
- Domain (proposed): `--badge-circle-size` (24px), `--badge-radius` (alias `--r-xl`)

Existing token usage (`--r-xl` via `border-radius: 16px`) — current canonical hardcodes `16px`. Replace with `var(--r-xl)` (16px in canonical scale).

## Refactor scope

1. `src/canonical/Badge.vue` `<script setup>`:
   - Update `badgeVars` ternaries:
     - `'--badge-width': props.type === 'Circle' ? 'var(--badge-circle-size)' : 'auto'`
     - `'--badge-padding-inline': props.type === 'Circle' ? '0' : 'var(--sp-s)'`
     - new: `'--badge-padding-block': props.type === 'Circle' ? '0' : 'var(--sp-xxs)'`
   - Extend `content` computed: when Rectangle, return color-keyed default (`{Black:'Msg', Red:'Error', Orange:'Warn', Blue:'Active', Green:'Done'}[color]`); when Circle, `'5'`.
   - Optionally change default `color: 'Black'` → `'Green'` (open).
2. `src/canonical/Badge.vue` `<style scoped>`:
   - Replace `font-size: 12px; font-weight: 400; line-height: 16px; font-family: inherit` with single `font: var(--text-style-tips);`
   - Replace `border-radius: 16px` with `border-radius: var(--r-xl)`.
   - Replace `height: 24px` with `height: var(--badge-circle-size)`.
   - Add `padding-block: var(--badge-padding-block)`.
3. `src/tokens/variables.css` — add under "Derived aliases":
   ```
   --badge-circle-size: 24px;  /* figma size/xxxs (no canonical size scale yet) */
   ```
4. `src/design-system/translation/prop-aliases.md` — Badge component entries already absent (legacy listed under composition aliases). Add to "组件级命名映射" if needed; note `Badge` canonical = `src/canonical/Badge.vue` per its header.

## Blockers / open decisions

- **Default color**: figma `Green`, canonical `Black`. Recommend align with figma.
- **Rectangle default text**: currently always `'Msg'`. Should it be color-keyed per figma? (Yes — see Composition row).
- **Circle size token name**: `--badge-circle-size` is descriptive; alternative is to introduce a project-wide `--size-xxxs: 24px` matching figma's `size/xxxs` token family — but figma `size/*` not yet imported into canonical. Recommend localized domain token now; revisit when global size scale lands.
- Canonical Badge.vue does not currently appear in `prop-aliases.md` "Boolean Property Aliases" or "Sub-component Composition" — figma Badge has no boolean / sub-component, so no entries needed. ✓
