# Rating fix spec — Phase X.4.2 batch C

Inputs:

- Figma cache: `figma-data/normalized/figma-mcp-cache/rating.tsx`
- Canonical: `src/components/Rating/Rating.vue`
- Token aliases: `src/design-system/translation/token-aliases.ts`
- Variables: `src/tokens/variables.css`
- Icon aliases: `src/design-system/translation/icon-aliases.ts`

Figma component summary (cache):

- Variant axes: `theme: 'dark' | 'light'` × `value: '1' | '2' | '3' | '4' | '5'` (10 variants)
- Sub-icons: `icon/mark/star on` (filled) and `icon/mark/star` (outline) — both rendered at `24px`
- Wrapper: `bg-[rgba(0,0,0,0)]` (transparent) `flex gap-[4px] items-center`

Mapping per icon-aliases.ts (existing entries):

- `icon/mark/star on` → canonical `<Icon name="star-on">`
- `icon/mark/star` → canonical `<Icon name="star">`

Canonical 现 uses `name="star-filled"` / `name="star-empty"` — **mismatch** vs alias table.

---

## Mismatches

### a. Spacing

| Aspect | Figma 真源 | Canonical 现状 | Fix |
| --- | --- | --- | --- |
| Star wrapper gap | `4px` → `--sp-xxs` | `gap: 4px` literal in `.rating` | replace with `gap: var(--sp-xxs)` |
| Star size (visible icon) | `24px` icon frame | `width: 24px; height: 24px` literal on `.rating__star` button | acceptable as button hit area; but the **icon `:deep(svg)`** is forced to `16px` — figma intent is `24px` icon. Fix: change inner icon size to `24px` and update `<Icon :size="24" />`. |
| Button padding | figma has no padding (icon = full 24×24) | `padding: 0; border-radius: 4px` (focus ring) | OK as runtime affordance; document |

### b. Color

| State | Figma 真源 token | Canonical 现状 | Fix |
| --- | --- | --- | --- |
| Filled star (`star on`) — both themes | figma resolves to brand-orange ring (per icon source — confirm via icon SVG fill chain) — typically `--orange` | `.rating { --rating-star-on: var(--orange); }` and `.rating--light { --rating-star-on: #e26601; }` | dark OK; **light hardcodes hex `#e26601`** which equals current `--orange` light value (theme-aware). Repoint: `--rating-star-on: var(--orange);` only — drop the `.rating--light` override entirely; theme-aware `--orange` already handles dark/light split. |
| Empty star (`star`) — dark theme | figma uses neutral icon color (likely `--icon-active` = `#f8f8f8`) | `--rating-star-off: var(--icon-active)` | OK |
| Empty star — light theme | figma uses `--icon-active` light = `#434343` | `.rating--light { --rating-star-off: #434343; }` literal | repoint to `var(--icon-active)`; drop literal |
| Focus ring | n/a (runtime addition) | `color-mix(in srgb, var(--orange) 36%, transparent)` (dark), `rgba(226, 102, 1, 0.2)` (light) | runtime UX; light hardcode → use `color-mix(in srgb, var(--orange) 20%, transparent)` for theme-aware uniformity |

### c. Typography

N/A — Rating has no text.

### d. Effects

No drop shadow / mask. N/A.

### e. Composition

| Aspect | Figma 真源 | Canonical | Fix |
| --- | --- | --- | --- |
| Icon component reference | `icon/mark/star on` / `icon/mark/star` | `<Icon name="star-filled">` / `<Icon name="star-empty">` | **alias mismatch** with `icon-aliases.ts` Composition table B (entry `icon/mark/star on` → `star-on`, `icon/mark/star` → `star`). Fix: rename canonical icon names to `star-on` / `star` to match alias table; OR add `prop-aliases.md` entry registering `star-filled ↔ star-on`, `star-empty ↔ star` as approved aliases. **Recommend renaming canonical** (single point of usage). |
| Icon size | `24px` | `:size="16"` + `:deep(svg) { width:16px; height:16px }` | upsize to `24px` (figma 真源) |
| Wrapper element | `<div>` flex container | `<div class="rating">` | OK |
| Star element | `<div>` (display-only in figma) | `<button>` | acceptable — runtime interactivity addition |
| `--rating-star-on/off` custom props | n/a | local CSS vars | OK pattern; repoint values per Color section |

### f. Variant coverage

| Figma variant | Canonical handled? | Notes |
| --- | --- | --- |
| `theme=dark, value=1..5` | ✅ via `displayValue` computed | OK |
| `theme=light, value=1..5` | ✅ via `.rating--light` class | OK after color repoint |

Runtime additions (per `prop-aliases.md` Vue ecosystem table):

- `modelValue` + `update:modelValue` — Vue v-model contract (n/a in figma)
- `readonly?: boolean` — runtime addition (n/a in figma)
- `disabled?: boolean` — Vue/Web form (n/a in figma)
- `value` (string `'1'..'5'` Figma-aligned) — exact match

These are documented in `prop-aliases.md` "Vue 生态增强" — no figma counterpart expected.

---

## New domain tokens proposed

| Token | Value | Rationale |
| --- | --- | --- |
| `--rating-star-size` | `24px` | Figma 真源 star icon size; explicit anchor prevents drift |
| `--rating-gap` | `var(--sp-xxs)` | Alias for clarity (optional — direct `--sp-xxs` is fine) |

(Optional — `--rating-star-size` is the only one strictly worth adding; `--rating-gap` is sugar.)

---

## Token repoint summary

| Current | Proposed | Scope |
| --- | --- | --- |
| `.rating { --rating-star-on: var(--orange); }` | unchanged | OK |
| `.rating--light { --rating-star-on: #e26601; }` | **drop** (rely on `--orange` theme-aware) | Light theme |
| `.rating--light { --rating-star-off: #434343; }` | drop; rely on `var(--icon-active)` | Light theme |
| `.rating { gap: 4px }` | `gap: var(--sp-xxs)` | All |
| `.rating__star { border-radius: 4px }` | `border-radius: var(--r-s)` | All (focus ring radius) |
| Icon `:size="16"` + `:deep(svg) { width:16px }` | `:size="24"` and `:deep(svg) { width:24px; height:24px }` | All |

---

## Open items

- Confirm icon `name` decision: rename `star-filled`/`star-empty` to alias-table-aligned `star-on`/`star` **OR** register the current names in `prop-aliases.md` as approved aliases. Plan owner to pick.
- Confirm whether `--orange` light value (`#e26601`) is the figma 真源 fill for `icon/mark/star on` — current assumption is yes (visual match), needs cross-ref against figma styles JSON `iconFills` if exists.
