# 组件层 Theme 实现审计（2026-04-29）

## 触发原因

用户反馈 ProgressPage 截图：dark 站点主题下 dark 和 light variant 同时渲染，且视觉差异微弱。
深入排查发现：**问题不只在 docs page，组件本体的 theme 实现也有缺陷**。

本审计核查 11 个有 theme 轴的组件，回答："runtime/canonical 实现是否真按 theme prop 渲染不同 CSS？"

## 审计方法

由 Claude 主 session 通过 2 个并行 Explore agent 完成。每个组件核查：

- Q1: theme prop 是否在 `defineProps` 里
- Q2: template 是否真的用 theme（条件 class / computed）
- Q3: CSS 是否有 theme 条件样式（`*--dark`、`*--light` 选择器或对应 CSS 变量）
- Q4: Figma normalized JSON 是否真有 dark vs light 视觉差异（fills hex 是否不同）

## 11 组件审计结果

### Class A — 完整实现（3 个）

| 组件 | runtime theme prop | template 用 | CSS 差异 | Figma 真差异 |
|---|:-:|:-:|:-:|:-:|
| Notification | ✅ `'dark' \| 'light'` | ✅ `notif--${theme}` | ✅ bg / stroke 都换 | ✅ `#353535` vs `#f8f8f8` |
| FormItem | ✅ `'Dark' \| 'Light'` | ✅ `form-item--dark/light` | ✅ label / surface / border token | N/A（无 tokenized data） |
| Tooltip | ✅ `'dark' \| 'light'`（**runtime 层**） | ✅ `tooltip-box--dark/light` | ✅ bg-layer4 vs bg-layer1 | ✅ |

**特别说明 Tooltip**：唯一双层都暴露 theme 的特例。runtime 用 `theme=[dark|light]`，canonical 用 `darkTheme=[on|off]`。
**`darkTheme=on → theme=dark` 映射未在 [prop-aliases.md](../../src/design-system/translation/prop-aliases.md) 登记** —— 是新发现的未登记 divergence。

### Class B — 命名漂移但实现真（5 个）

这 5 个组件 Figma 用 `dark theme=[on, off]` 命名（on=dark, off=light）。
**runtime 层不暴露 theme prop**，由站点级 ThemeProvider + CSS 变量驱动；canonical 层用 `darkTheme` prop 透传。

| 组件 | canonical | runtime | Figma 真差异 |
|---|---|:-:|:-:|
| Input | `darkTheme: 'on'\|'off'` | ❌ 无 prop | ✅ 文本 `#f8f8f8` vs `#141414` |
| CheckBox | `darkTheme: 'on'\|'off'` | ❌ 无 prop | ✅ |
| Radio | `darkTheme: 'on'\|'off'` | ❌ 无 prop | ✅ |
| Switch | `darkTheme: 'on'\|'off'` | ❌ 无 prop | ✅ |
| Select | `darkTheme: 'on'\|'off'` | ❌ 无 prop | ✅ |

**这 5 个在 [divergences.md:81-87](../../src/design-system/translation/divergences.md#L81) 已登记**为"设计态主题预览开关；运行时主题由全局 ThemeProvider / CSS 变量处理"。

**含义**：docs page 上这 5 个组件的 dark/light 视觉切换**靠站点 theme**，不靠组件 prop。Tooltip 不是这种模式（它有 prop）。

### Class C — 伪主题 / 部分实现（3 个，**最痛**）

| 组件 | template 用 | CSS 条件样式 | Figma 真差异 | 判定 |
|---|:-:|:-:|:-:|:--|
| **Progress** | ✅ `progress--${theme}` | ⚠️ 仅 `progress--light` 改 track bg；dark 默认 | **❌ Figma fills 一致 (`#cccccc`)，无真实差异** | **⚠️ 伪主题** |
| Slider | ✅ `slider--${theme}` | ✅ `--slider-track-bg` dark vs light | ❌ Figma 仅含 nodeIds，无 fill 数据 | ⚠️ 部分 |
| Rating | ✅ `rating--${theme}` | ✅ `--rating-star-on/off` dark vs light | ❌ Figma 缺 icon fills | ⚠️ 部分 |

**Progress 是关键案例**：
- 代码侧 [src/components/Progress/Progress.vue:71-74](../../src/components/Progress/Progress.vue#L71-L74) 通过 `progress--light` 改 track 背景
- 但 Figma normalized data ([components-tokenized/progress__4915_7287.json](../../figma-data/normalized/components-tokenized/progress__4915_7287.json)) 里 dark 和 light variant 的 `fills[0].hex` 完全相同
- **代码做了视觉差异，但不来自 Figma token**——属于代码自创视觉

Slider 和 Rating 的 CSS 实现可能正确，但 Figma JSON 缺数据无法验证。

## 关键发现汇总

### 发现 1：theme 命名分裂为 3 套

- **runtime + canonical 都用 `theme=[dark|light]`**：Notification / Progress / Slider / Rating / FormItem(Title Case) / **Tooltip**
- **canonical 用 `darkTheme=[on|off]`，runtime 不暴露**：Input / CheckBox / Radio / Switch / Select
- **同时有两套**：Tooltip（独此一家）

### 发现 2：Tooltip 的命名映射未登记

[src/canonical/Tooltip.vue](../../src/canonical/Tooltip.vue) 用 `darkTheme=[on|off]` 透传给 [src/components/Tooltip/Tooltip.vue](../../src/components/Tooltip/Tooltip.vue) 的 `theme=[dark|light]` —— 这一映射应在 [prop-aliases.md](../../src/design-system/translation/prop-aliases.md) 登记。

### 发现 3：Progress 是伪主题，不仅是 docs 页问题

即便 docs 页改成单主题渲染，Progress 视觉差异微弱依然存在——因为组件本体的 dark/light 实现就缺 Figma token 锚点。**必须先在组件层修复**。

### 发现 4：Slider / Rating Figma 数据缺失

不是组件层 bug，是 figma-data 提取没拿全。`components-tokenized/*` 里 Slider / Rating 缺 fill / icon 颜色信息。**这是 figma-data pipeline 的问题，需要回到 Figma 重新提取**。

## 对 Phase D-Guard 设计的影响

### 必须分 3 步串行

```
Step 1 (component-layer 修复)：
  • 解决 Progress 伪主题（按 Figma token 重写 CSS）
  • 补 figma-data pipeline 提取 Slider / Rating 缺失的 fills
  • 登记 Tooltip 的 darkTheme→theme 映射到 prop-aliases.md

Step 2 (audit + generator)：
  • 写 audit:component-token（机器化版本，防止 Class C 类问题再发生）
  • 写 generate:docs-figma-spec + <FigmaMembersGrid> 组件
  • Step 1 没修完前，generator 跑出来的 Progress members 视觉上仍然没差异——所以 Step 1 必须先

Step 3 (page refactor + 4 page-level audits)：
  • 22 页 refactor 用 generator + FigmaMembersGrid
  • 删 hardcoded variant arrays
  • 跑 4 个 page-level audit 全绿
```

**先 Step 1 后 Step 2** 的硬约束理由：组件本体 token 不对齐，generator 生成的 members 渲染出来还是错的。

### Tooltip 的特殊处理

Tooltip 是唯一在 runtime 层暴露 theme prop 的组件——这意味着 docs page 用 Tooltip 时**必须用 `theme=[dark|light]`** 不能用 `darkTheme=[on|off]`。其它 5 个 Class B 组件靠站点 theme 自动响应，docs page **不应**显式传 theme/darkTheme 给它们（让 ThemeProvider 处理）。

## 数据出处

- `figma-data/normalized/canonical-components.json` — 11 个组件的 Figma axes
- `figma-data/normalized/components-tokenized/<X>__<nodeId>.json` — 各组件的 variant fills（部分缺失）
- `src/components/<X>/<X>.vue` — runtime 实现
- `src/canonical/<X>.vue` — canonical 包装
- `src/design-system/translation/divergences.md` — 翻译层登记
- 由 Claude + 2 个 Explore agent 在 2026-04-29 上午采集
