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

- Canonical: `src/components/Table/Table.vue`
- Figma cache: `figma-data/normalized/figma-mcp-cache/table.tsx`
- Figma node ids — Header row: `4265:16132` (Left), `4605:7111` (Center), `4605:7118` (Right). Tbody row: `4605:7125` (Left), `4265:16167` (Center), `4605:7131` (Right).
- Composition expectation per `prop-aliases.md` 表 B: `icon/Arrow/Dropdown` → `<Icon name="dropdown">`; `icon/Arrow/Sorting` → `<Icon name="sorting">`; `icon/Edit/Copy` → `<Icon name="copy">` (or current canonical alias).
- Figma boolean props per `prop-aliases.md`: `showLeftIcon` exact match, `showRightIcon` exact match.

> Important framing: figma cache exposes the **per-cell** primitive (one cell of a row, with `align`, `type=Header|Tbody`, `showLeftIcon`, `showRightIcon`). Canonical `Table.vue` is the **composed table** (table/thead/tbody/tr/td) that renders all cells from `columns + data`. The fix below flags both per-cell mismatches (which must end up reflected in cell rendering inside the table) and table-level concerns.

## Mismatch matrix

### a. Spacing

| Element | Figma 真源 | Canonical 现状 | Token to use |
| --- | --- | --- | --- |
| Cell vertical padding | `--spacing/xs` (8px) | `padding: 10px 16px` (10px is invented) | `padding: var(--sp-xs) var(--sp-m)` (8px / 16px) |
| Cell horizontal right-padding | `--spacing/xs` (8px right) | `16px` symmetric | replace with `var(--sp-xs)` if we honor cache exactly; OR keep `var(--sp-m)` symmetric and document deviation. Spec recommends figma-truth: `padding: var(--sp-xs)` on right and left (cache uses `pr-xs py-xs` only, no explicit left). See blockers. |
| Gap (cell content ↔ icons) | `--spacing/xs` (8px) inside content; `--spacing/xxs` (4px) between content and trailing right-icon at row level | n/a (no inline-icon support in canonical cell) | when icon support added: `gap: var(--sp-xs)` for left-icon-to-text, `gap: var(--sp-xxs)` between content block and right-icon |
| Cell minimum width | `120px` raw in cache (no scale token; figma authoring literal) | none | keep `min-width: 120px` literal (no canonical token; flag as future) |
| Icon size | 16px (size-[16px]) | n/a | rely on `<Icon>` default size; if needed: `width: 16px; height: 16px` literal (no `--size-*` scale token yet — see blockers) |

### b. Color

| Element | Figma 真源 | Canonical 现状 | Token to use |
| --- | --- | --- | --- |
| Header text | `Color Type/Text/Tips` (#9e9e9e) | `color: var(--text-2)` (#cccccc) — drift | `color: var(--text-tips)` |
| Tbody text | `Color Type/Text/Text_1` (#f8f8f8) | `color: var(--text-body)` | already correct (canonical uses `--text-body`) |
| Header background | (figma cache shows none — cell is transparent) | `background: var(--bg-layer3)` — invented | remove background; `background: transparent` (header chrome decided by row-divider only — see e) |
| Tbody background | none in cache | `background: var(--bg-layer2)` on root + hover `var(--bg-layer3)` | hover/striped rows are canonical-only enrichment (no figma equivalent). Document as runtime addition (similar to existing `striped` prop that lacks figma counterpart). |
| Row-divider line | not visible in single-cell cache; assumed `Color Type/Line/Light Divider` (canonical convention) | `border-bottom: 1px solid var(--line-divider-deep)` (header) and `var(--line-divider-light)` (rows) | header divider: `var(--line-deep)`; row divider: `var(--line-light)` (use canonical raw aliases — `--line-divider-deep` is a derived alias = `--line-deep`, fine to keep) |

### c. Typography

| Element | Figma 真源 | Canonical 现状 | Token to use |
| --- | --- | --- | --- |
| Header text | `Helvetica Neue: Bold` 14 / lh 1.2 | `font-weight: 600` raw, `font-size: 14px` inherited | **see blockers** — figma uses Helvetica Neue intentionally? Cell uses non-Roboto. No canonical Text Style covers Helvetica/14/Bold/lh-1.2. Recommend: keep `font: var(--text-style-body)` (Roboto 400 14 / 21) + override `font-weight: 700` to align with project font system (canonical uses `--font-family-base` Roboto). Flag figma authoring inconsistency. |
| Tbody text | `Helvetica Neue: Regular` 14 / lh 1.2 | `font-size: 14px; color: var(--text-body)` | `font: var(--text-style-body)` (Roboto 400 14 / 21) — same family decision as header |

### d. Effects

None — no shadows / masks on any cell variant.

### e. Composition

| figma `data-name` | canonical | status |
| --- | --- | --- |
| `icon/Arrow/Dropdown` (Header / Tbody left-icon) | `<Icon name="dropdown">` | not implemented — canonical has no inline-icon prop / slot per cell |
| `icon/Arrow/Sorting` (Header right-icon) | `<Icon name="sorting">` | not implemented |
| `icon/Edit/Copy` (Tbody right-icon) | `<Icon name="copy">` | not implemented |
| Header / Tbody container `data-name="Content"` | (no canonical mapping; layout container) | n/a |
| `align: Left|Center|Right` | `--tbl-cell-${align}` | mapped (text-align only) |

Composition gaps:

1. `TableColumn` interface needs to expose `showLeftIcon?: boolean`, `leftIconName?: string`, `showRightIcon?: boolean`, `rightIconName?: string` (or a `headerIcons` / `cellIcons` slot pattern) to match figma's `Tab/Item`-equivalent per-cell icon contract.
2. `align: 'right'` cells in cache use `justify-end`, `'center'` uses `justify-center` on the **row** (flex), but canonical relies on `text-align`. For text-only cells text-align suffices; once icons are added, the row needs `display: flex; justify-content: flex-end | center | flex-start; align-items: center;` to match figma layout.
3. Sorting on header is a figma boolean (`showRightIcon` on Header) — canonical should add `sortable?: boolean` + emit `sort` event when wiring (runtime-addition; document in `prop-aliases.md`).

### f. Variant coverage

| Variant axis | Figma values | Canonical | Status |
| --- | --- | --- | --- |
| `type` | Header / Tbody | thead / tbody (covered by element semantics) | ok |
| `align` | Left / Center / Right | left / center / right | ok |
| `showLeftIcon` | true / false | not modeled | gap |
| `showRightIcon` | true / false | not modeled | gap |
| `striped` (canonical-only) | n/a | yes (zebra rows) | runtime addition; ok per `prop-aliases.md` (mark in 表 D / runtime additions) |
| `hover` (canonical-only) | n/a | yes (`background: var(--bg-layer3)`) | runtime addition |

## New tokens proposed

None. All values map to existing canonical tokens.

## Blockers / open questions

1. **Helvetica Neue vs Roboto** (typography blocker): figma cache uses `Helvetica_Neue:Bold` for header and `Helvetica_Neue:Regular` for tbody — different family from every other figma component (which all use Roboto). The figma `textStyles` map (`figma-data/normalized/figma-styles.json`) has **no Helvetica Neue style**; only `Roboto/*`. **Hypothesis**: figma authoring inconsistency (designer overrode the text style in this Component Set). **Recommendation**: align with canonical Roboto / `--text-style-body` and flag for plan-owner / designer confirmation before writing any code. Do NOT introduce a new Helvetica Neue token.
2. **Header `font-weight: Bold (700)` + `lineHeight: 1.2`** — does not match `--text-style-body` (400 / 1.5) or `--text-style-pop-title` (600 / 1.5). No canonical token covers 700 + 1.2 line-height. **Recommendation**: use `font: var(--text-style-body)` + override `font-weight: 700` (or `600` to match canonical-elsewhere convention) and document. Same blocker family as TabItem bold-active.
3. **Cell padding asymmetry** (`pr-xs py-xs` only, no explicit left padding in cache) — implies figma intends left padding to come from parent / column-gap rather than cell padding. Canonical applies symmetric `padding: 10px 16px`. **Recommendation**: switch to symmetric `var(--sp-xs) var(--sp-m)` (8px / 16px) which matches figma vertical (`--spacing/xs`) and a common cell horizontal padding (`--spacing/m`). Flag for designer confirmation; alternative is figma-exact `padding: var(--sp-xs)` (8px all sides) which makes header text feel cramped.
4. **`--size-16` scale token** — icon size 16px is not a canonical token. Same scale-token gap as TabItem. Keep raw `16px` for now.
5. **Cell minimum width 120px** — figma cache hard-codes `w-[120px]`. Canonical does not enforce. Unclear whether figma intends a fixed minimum or a default for the variant preview only. Recommend treating as preview-only and not enforcing in canonical (column `width` prop already exists).
6. Header's invented `--bg-layer3` background is a canonical-only enrichment that does not exist in figma — removing it (per b) is the figma-truth choice but may be surprising for current consumers. Plan-owner to confirm.

## Files (canonical fix scope)

- `src/components/Table/Table.vue` (style block + script: extend `TableColumn` interface for icon support if feature is in scope)
- `src/design-system/translation/prop-aliases.md` (record `striped`, `hover` as runtime additions; record `sortable` if added; clarify `showLeftIcon` / `showRightIcon` apply per-column)
- `src/design-system/translation/icon-aliases.ts` (verify `dropdown`, `sorting`, `copy` aliases exist — currently not in the file; add entries `'arrow/dropdown'`, `'arrow/sorting'`, `'edit/copy'` if Table icon support is wired in this fix)
