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

## Inputs (✓ all read)

- ✓ `figma-data/normalized/figma-mcp-cache/slider.tsx` (4934:7206 — Slider component, axes: theme(dark/light) × size(M/S))
- ✓ `src/canonical/Slider.vue` (wrapper → BaseSlider)
- ✓ `src/components/Slider/Slider.vue` (impl)
- ✓ `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 (impl) | Figma 真源 | Fix |
|---|---|---|---|
| `.slider` `column-gap` | `8px` (raw) | `gap-[8px]` = `--sp-xs` | use `var(--sp-xs)` |
| `.slider__value` `min-width` | `40px` (raw) | `w-[40px]` (label box, not in spacing scale) | keep raw 40px (label width is layout literal, no token); document as design-literal |
| `.slider` width | `240px` (raw) | `w-[240px]` (raw, no token) | keep raw — non-token layout dimension |
| Track size M `--slider-track-height` | `8px` raw | `h-[8px]` figma raw | propose new `--slider-track-h-m: var(--sp-xs)` (8px maps to `--sp-xs`) |
| Track size S `--slider-track-height` | `4px` raw | `h-[4px]` figma raw | propose new `--slider-track-h-s: var(--sp-xxs)` (4px maps to `--sp-xxs`) |
| Thumb sizes (M=16, S=12) | `16px` / `12px` raw | `size-[16px]` / `size-[12px]` figma raw | use `var(--sp-m)` (16) and `var(--sp-s)` (12) — but these are width/height of a control element, not gap; **propose domain tokens** below |

### Color

| Location | Canonical (impl) | Figma 真源 | Fix |
|---|---|---|---|
| `--slider-fill-color` default | `var(--brand, #2fb54e)` w/ literal fallback | `var(--ux\/brand\/brand,#2fb54e)` → `--brand` | drop hex fallback: `var(--brand)` |
| `--slider-track-bg` default (dark) | `#262626` raw hex | `var(--color-type\/background\/layer_3,#262626)` → `--bg-layer3` | use `var(--bg-layer3)` |
| `--slider-track-bg` light | `#dbdbdb` raw hex | `var(--ux\/grey\/grey-4-\#dbdbdb,#dbdbdb)` → `--color-grey-4` | use `var(--color-grey-4)` |
| `--slider-value-color` | `#cccccc` raw hex | `text-[color:var(--color-type\/text\/text_2,#ccc)]` → `--text-2` | use `var(--text-2)` |
| Thumb dot center (M/S) | `#ffffff` raw hex in `radial-gradient(...)` | `bg-white` = `--color-white` | use `var(--color-white)` |
| `:focus-visible` outline | `color-mix(... 75%, white 25%)` raw white | n/a (figma 无 focus state) | keep `color-mix` runtime addition; replace `white` with `var(--color-white)` |

### Typography

| Location | Canonical (impl) | Figma 真源 | Fix |
|---|---|---|---|
| `.slider__value` `font-size`/`line-height`/`weight` | `14px` / `21px` / `400` raw | figma uses `Roboto/14 body` (size 14, lh 1.5≈21, weight 400) → `--text-style-body` | replace 4 lines with `font: var(--text-style-body);` (composite shorthand) |

### Effect

- No shadows in figma slider source (no L1/L2/L3 referenced). Canonical has none. ✓ aligned.

### Composition

- Figma uses bare DOM `<div>` track + fill + thumb. Canonical uses native `<input type="range">` (Vue ecosystem addition for accessibility / form binding). Approved divergence — register as runtime addition (already implicit; consider linking in `prop-aliases.md` Vue ecosystem section).
- Figma label is `<p>` after track; canonical `<span class="slider__value">`. Semantic tag mismatch only — no fix needed (visual identical).
- Figma fill uses solid `bg` div with computed width; canonical uses CSS `linear-gradient` on `<input>`. Visual parity preserved; runtime mechanism diverges — acceptable for native range input.

### Variant coverage

| Axis × value | Figma variants | Canonical | Status |
|---|---|---|---|
| theme | `dark`, `light` | `'dark' \| 'light'` | ✓ match |
| size | `M`, `S` | `'m' \| 's'` (lowercase) | ✓ value alias (consistent with Input/Select pattern) — register in prop-aliases.md "枚举值命名映射" if not yet |
| disabled | (figma 无 enable axis on Slider) | runtime addition | ✓ Vue ecosystem (already in prop-aliases.md) |
| showValue | (figma always shows value `60`) | runtime addition | runtime addition; document |

Note: canonical Slider.vue declares `size: 'M' \| 'S'` (uppercase), then maps via `size === 'S' ? 's' : 'm'` to BaseSlider. Inner impl uses lowercase. **Open**: align to single case at one layer (recommend: keep canonical wrapper uppercase to match figma, impl lowercase as today).

## Token usage summary

After fix the file should reference only:

- Spacing: `--sp-xxs`, `--sp-xs`, `--sp-s`, `--sp-m` (via proposed domain tokens for thumb/track)
- Color: `--brand`, `--bg-layer3`, `--color-grey-4`, `--text-2`, `--color-white`
- Typography: `--text-style-body`
- Effect: none
- Domain (proposed): `--slider-track-h-m`, `--slider-track-h-s`, `--slider-thumb-size-m`, `--slider-thumb-size-s`, `--slider-thumb-dot-radius-m`, `--slider-thumb-dot-radius-s`

## Refactor scope

1. `src/components/Slider/Slider.vue` `<style scoped>`:
   - Replace all hex literals with tokens listed above.
   - Replace 4 `.slider__value` typography lines with `font: var(--text-style-body)`.
   - Replace `column-gap: 8px` with `column-gap: var(--sp-xs)`.
   - Replace size-variant `--slider-track-height` / `--slider-input-height` / `--slider-thumb-size` raw values with proposed domain tokens.
   - In thumb `radial-gradient`, replace `#ffffff` with `var(--color-white)`.
   - In `:focus-visible` `color-mix`, replace `white` with `var(--color-white)`.
2. `src/tokens/variables.css` — add domain tokens (theme-stable, not in light/dark override) under "Derived aliases":
   ```
   --slider-track-h-m: var(--sp-xs);     /* 8px */
   --slider-track-h-s: var(--sp-xxs);    /* 4px */
   --slider-thumb-size-m: var(--sp-m);   /* 16px */
   --slider-thumb-size-s: var(--sp-s);   /* 12px */
   --slider-thumb-dot-radius-m: 3.2px;   /* design-literal sub-px */
   --slider-thumb-dot-radius-s: 2.4px;   /* design-literal sub-px */
   ```
3. `src/design-system/translation/prop-aliases.md` — add Slider entries to "枚举值命名映射" (size `m` ↔ `M`, `s` ↔ `S`) and to "Vue ecosystem" (`disabled`, `modelValue`/`update:modelValue`, `showValue`, `min`/`max`/`step`).

## Blockers / open decisions

- Thumb dot radii (3.2px, 2.4px) are sub-pixel design literals. They can stay as raw px in the domain token, OR be expressed as fractional ratios of `--slider-thumb-size-*`. Recommend raw px in named domain token (clarity > parametrization).
- Whether the 240px slider width should become a layout token (`--slider-width-default`) or stay raw — recommend raw, single use site.
- Canonical wrapper still passes lowercase to inner impl. If we ever drop the legacy lowercase impl, we can simplify.
