# TabItem — Fix Spec (Phase X.4.2 batch D)

- Canonical: `src/components/Tab/TabItem.vue`
- Figma cache: `figma-data/normalized/figma-mcp-cache/tabitem.tsx`
- Figma node ids: `4265:16083` (Normal/White/Line) · `4265:16085` (Active/Green/Line) · `4265:16087` (Active/White/Line) · `4452:7116` (Active/Green/Filled) · `4452:7118` (Normal/White/Filled) · `4605:7204` (Active/White/Text)

Figma axes: `property1: Active|Normal` × `property2: Green|White` × `type: Line|Filled|Text`. Canonical exposes `state: normal|active`, `type: line|text|filled`, `activeColor: white|green`. Mapping is consistent (state↔property1, activeColor↔property2). Add canonical entries to `prop-aliases.md` Boolean / enum tables when wiring this fix (Code `state` ↔ Figma `property1`; Code `activeColor` ↔ Figma `property2`; values `normal/active` ↔ `Normal/Active`, `white/green` ↔ `White/Green`).

## Mismatch matrix

### a. Spacing

| Element | Figma 真源 | Canonical 现状 | Token to use |
| --- | --- | --- | --- |
| Item height | `--size/xxs` (32px) | `height: 32px` raw | keep `32px` literal (`--size/*` not in canonical scale) — see blockers |
| Item horizontal padding | `--spacing/m` (16px) | `padding: 0 16px` raw | `padding: 0 var(--sp-m)` |
| Item gap (when wrapped by TabList Line/Text) | `--spacing/l` (0px in figma map → 24px gap rendered via `gap-[24px]` in cache) | n/a (TabList side) | n/a here — handled in TabList spec |

### b. Color

| Element / state | Figma 真源 | Canonical 现状 | Token to use |
| --- | --- | --- | --- |
| Default text (Normal × any) | `Color Type/Text/Tips` (#9e9e9e) | `color: #9e9e9e` raw | `color: var(--text-tips)` |
| Active text — Line/Text/White | `Color Type/Text/Text_1` (#f8f8f8) | `color: #f8f8f8` raw | `color: var(--text-body)` |
| Active text — Line/Green | `UX/Brand/Brand` (#2fb54e) | `color: #2fb54e` raw | `color: var(--brand)` |
| Active text — Filled/Green | `Color Type/Text/Primary Button` (white) | `color: #ffffff` raw | `color: var(--text-primary-btn)` |
| Filled bg — Active/Green | `UX/Brand/Brand` | `background: #2fb54e` raw | `background: var(--brand)` |
| Filled bg — Normal/White (canonical missing) | `Color Type/Background/Layer_4` (#353535) | not modeled (canonical only paints filled when `--active`) | `background: var(--bg-layer4)` for `tab-item--filled.tab-item--normal` (variant gap — see f) |
| Active text — Filled/White (canonical missing) | `Color Type/Text/Text_1` | not modeled | `color: var(--text-body)` for `tab-item--filled.tab-item--active-white` (variant gap — see f) |
| Line bottom-border — Active/White | `Color Type/Line/Light Divider` (figma cache token name) → canonical `--line-light` (#434343) | `border-bottom-color: #434343` raw | `border-bottom-color: var(--line-light)` |
| Line bottom-border — Active/Green | `UX/Brand/Brand` | `border-bottom-color: #2fb54e` raw | `border-bottom-color: var(--brand)` |
| Disabled text (canonical-only) | n/a in figma | `color: #6d6d6d` raw (NOT a canonical token value) | `color: var(--text-disabled)` (#595959) — see blockers |

### c. Typography

| Element | Figma 真源 | Canonical 现状 | Token to use |
| --- | --- | --- | --- |
| Body (Normal / Active Filled-Green / Filled-Normal) | `Roboto/14 body` (400 / 14 / 21) | `font-size: 14px; line-height: 21px; font-family: Roboto, sans-serif;` raw | `font: var(--text-style-body)` |
| Bold (Active Line/Text White & Green) | `Roboto/14` family + `Bold (700)` weight (cache uses `Roboto:Bold`) | not modeled (canonical applies no weight on active) | partial-override: keep `font: var(--text-style-body)` and add `font-weight: 700` on active states (no composite token covers 700; see blockers) |

### d. Effects

None — no shadows / masks in any TabItem variant.

### e. Composition

Atomic component: text node only, no nested icons or sub-components. Figma cache `data-name` set is empty for inner content. No composition mismatches.

### f. Variant coverage

Canonical missing the following figma variants:

1. `Filled × Normal × White` — figma node `4452:7118`: bg `--bg-layer4`, text `--text-2` (#ccc). Canonical `tab-item--filled` has no neutral state styling (only `.tab-item--active`).
2. `Filled × Active × White` — figma node n/a directly but implied symmetric to Filled/Green; cache only lists Filled/Green active. Canonical currently maps `tab-item--filled.tab-item--active-white` to `background: #353535` — that matches figma "Normal/White Filled" not "Active/White Filled". **Decision**: align canonical Filled/Active-White semantics with figma `4452:7118` (use as default container chrome for non-active items inside Filled list); pure Active/White Filled is not a figma variant — drop the dedicated Active/White Filled CSS rule or document it as canonical-only.
3. `type=Text` × `state=normal` — canonical works (inherits base `.tab-item`); figma confirms tips color. No fix needed beyond color tokens.
4. Active/Filled/White is **not** a figma variant — current canonical rule should be re-purposed to "Filled list non-active item" (bg `--bg-layer4`, text `--text-2`).

## New tokens proposed

None. All values map to existing canonical tokens.

## Blockers / open questions

1. `--size/xxs` (32px) — figma uses a `size/*` scale not currently mirrored in `src/tokens/variables.css`. Current canonical convention in other components is to keep raw `32px` literal until a `--size-*` scale is introduced. **Action**: keep `32px` literal; flag `--size-xxs` (32px) as a future scale token (rationale: appears in Tabs / Inputs / Buttons control heights — worth a single-source token).
2. Bold (700) text style — figma `Roboto:Bold` weight 700 has no matching canonical Text Style token (canonical Text Styles top out at 600 semibold). **Action**: keep partial-override `font-weight: 700` on active items; do **not** invent a new composite token unless figma adds a "Roboto/14 body bold" Style.
3. `#6d6d6d` disabled color — not a figma value (figma has no `disabled` variant on TabItem). Replace with `--text-disabled` (#595959 dark / #cccccc light) which is the canonical disabled text token used elsewhere; alternative is `--text-grey-dis` (#7b7b7b dark / #9e9e9e light). **Decision needed**: pick one; spec recommends `--text-disabled` for consistency with disabled buttons / inputs.

## Files (canonical fix scope)

- `src/components/Tab/TabItem.vue` (style block)
- `src/design-system/translation/prop-aliases.md` (add TabItem entries to "枚举值命名映射" + "组件级命名映射")
