# Draft — FigmaMembersGrid contract 表达层

> Round 1 draft only. This file proposes the Vue API and rendering algorithm for `playground/docs/components/FigmaMembersGrid.vue`; it does not create the `.vue` file.

## Vue props API

```vue
<script setup lang="ts" generic="TProps extends Record<string, string>">
import type { Component } from 'vue'
import type { DocsFigmaMembers } from '../../../figma-data/normalized/docs-figma-members/types'

const props = withDefaults(defineProps<{
  members: DocsFigmaMembers<TProps>
  component: Component
  siteTheme?: 'light' | 'dark'
  metaLabel?: (members: DocsFigmaMembers<TProps>, visibleCount: number) => string
  getCellLabel?: (variant: DocsFigmaMembers<TProps>['variants'][number]) => string
}>(), {
  siteTheme: 'light',
})
</script>
```

Draft API intent:

- `members` is the single generator-output input for Figma axes, variants, source, and meta.
- `component` injects the runtime Vue component, e.g. `Badge`; grid does not import canonical files directly.
- `siteTheme` is page-injected. The grid does not discover global theme by itself.
- `metaLabel` and `getCellLabel` are optional formatting hooks only; they must not inject new axis or variant data.

### Site theme 注入方式

- Option A: prop `siteTheme?: 'light' | 'dark'`
  - Pros: explicit, static-audit-friendly, grid remains pure.
  - Cons: every page must pass it once theme-aware components enter T2.
- Option B: Vue `inject('siteTheme')`
  - Pros: less prop plumbing.
  - Cons: hidden dependency; harder for α audit to prove which theme was used.
- Option C: global ref/store import
  - Pros: convenient in app shell.
  - Cons: grid starts depending on docs-site runtime state, weaker isolation.

Draft 建议倾向 Option A，但待 plan owner 拍板。

### 待渲染组件注入方式

- Option A: `component` prop + `<component :is="component" v-bind="variant.props" />`
  - Pros: simple, works for Badge and later examples, keeps grid generic.
  - Cons: TS cannot fully validate component-specific props inside template.
- Option B: default scoped slot
  - Pros: page controls exact render, can handle slots like Badge label text.
  - Cons: page can accidentally handwrite non-generator variants inside grid unless audit anchor rules are strict.
- Option C: generic component type only
  - Pros: stronger type aspiration.
  - Cons: Vue SFC generics still need runtime component injection; more complexity for little gain.

Draft 建议倾向 Option A for component injection, with an optional scoped slot only for child content after audit rules are fixed.

## 渲染算法（伪代码）

```text
input:
  members: DocsFigmaMembers
  component: Vue component
  siteTheme: 'light' | 'dark'

hasThemeAxis =
  any variant in members.variants has own property "theme"

visibleVariants =
  if hasThemeAxis:
    members.variants filtered where variant.theme == siteTheme
  else:
    members.variants

metaText =
  metaLabel?.(members, visibleVariants.length)
  ?? `source=${members.component} · nodeId=${members.source.figmaNodeId} · variant count=${visibleVariants.length}`

render:
  section root with data-figma-members
    meta row with metaText
    axis summary chips from members.axes
    grid
      for each variant in visibleVariants:
        cell root with generator audit attrs
          label text from getCellLabel(variant)
            default: join variant.props entries as `Type=Circle, Color=Green, Tag=Filled`
            display labels may use members.axes figmaAxis order
          component wrapper with the same generator audit attrs
            <component :is="component" v-bind="variant.props">
              optional default slot content, if page provides one
            </component>
```

Badge behavior:

- `hasThemeAxis=false`, so all 20 variants render.
- α audit expected verdict is `N/A`.

Theme-axis behavior for later Tooltip/Select:

- `hasThemeAxis=true`, so only variants whose `theme` equals `siteTheme` render.
- The filtered count is the count shown in the grid meta line unless plan owner decides meta should always show total source count.

## 审计锚点 attr

- Option A: `data-figma-member`
  - Pros: concise; says each cell is a Figma member.
  - Cons: less explicit that data comes from generator.
- Option B: `data-from-generator`
  - Pros: directly communicates generation source.
  - Cons: generic; could mean non-Figma generator.
- Option C: `data-figma-source="generator"`
  - Pros: combines Figma origin and generator provenance; easy grep.
  - Cons: value matching is slightly more verbose than boolean attrs.

Draft proposal for auditable DOM:

```vue
<section data-figma-members :data-figma-component="members.component">
  <article
    v-for="variant in visibleVariants"
    :key="variant.variantId"
    class="figma-members-grid__cell"
    data-figma-source="generator"
    :data-figma-member="variant.variantId"
    :data-figma-component="members.component"
  >
    <component
      :is="component"
      v-bind="variant.props"
      data-figma-source="generator"
      :data-figma-member="variant.variantId"
    />
  </article>
</section>
```

Key distinction for γ audit:

- Grid cells and component instances inside the grid carry `data-figma-source="generator"`.
- Try It / hand-written demos must not carry this marker.
- `data-figma-members` marks the section boundary.

## Grid 顶部 meta 行

Default built-in template:

```text
source=<Component> · nodeId=<id> · variant count=<visible variant count>
```

Decision needed:

- Option A: grid owns this string template
  - Pros: all pages are consistent; no hand-written `variant count=20` drift.
  - Cons: localization is limited unless grid takes locale-aware labels.
- Option B: page injects `metaLabel`
  - Pros: page can localize and decide total vs visible count.
  - Cons: reintroduces drift risk if page hardcodes counts.

Draft 建议: grid owns the default string; optional `metaLabel` may format text but receives `visibleCount` from grid, not from page literals.

## CSS 草图

No full CSS in Round 1. Necessary classes and layout intent only:

```css
.figma-members-grid {}
.figma-members-grid__meta {}
.figma-members-grid__axes {}
.figma-members-grid__axis {}
.figma-members-grid__chips {}
.figma-members-grid__chip {}
.figma-members-grid__list {}
.figma-members-grid__cell {}
.figma-members-grid__label {}
.figma-members-grid__preview {}
```

Layout intent:

- root is a grid with token-based `gap`.
- axes summary is a wrapping chip row.
- variant list uses responsive CSS grid, e.g. `grid-template-columns: repeat(auto-fit, minmax(160px, 1fr))`.
- cells use existing docs-site tokens only: `var(--bg-layer*)`, `var(--line-divider-light)`, `var(--text-*)`.
- δ audit entry: CSS must contain zero hex/rgb literals after comments are stripped.

## 关键决策点（plan owner 拍板）

- [ ] site theme 注入方式
  - Option A: prop `siteTheme`
    - Pros: explicit and auditable.
    - Cons: page has to pass it.
  - Option B: `inject`
    - Pros: less prop plumbing.
    - Cons: hidden dependency for α audit.
  - Option C: global store/ref
    - Pros: app-level convenience.
    - Cons: weakens pure derivation from page input.
- [ ] 待渲染组件注入方式
  - Option A: `component` prop
    - Pros: simple and generic.
    - Cons: weaker template prop typing.
  - Option B: scoped slot
    - Pros: maximum render flexibility.
    - Cons: easier to handwrite runtime fabrication inside grid.
  - Option C: generic-only component typing
    - Pros: better type intent.
    - Cons: more SFC complexity.
- [ ] data-* attr 名定稿
  - Option A: `data-figma-member`
    - Pros: concise.
    - Cons: provenance less explicit.
  - Option B: `data-from-generator`
    - Pros: clear generated origin.
    - Cons: not Figma-specific.
  - Option C: `data-figma-source="generator"` + `data-figma-member="<id>"`
    - Pros: strongest γ audit signal.
    - Cons: two attrs to maintain.
- [ ] meta 行字符串内置 vs prop
  - Option A: built in by grid
    - Pros: prevents count drift.
    - Cons: less page formatting control.
  - Option B: page-supplied `metaLabel`
    - Pros: localizable/customizable.
    - Cons: hardcoded count can sneak back unless callback receives grid count.

## 自检

| 自检项 | 结果 |
|---|---|
| 数据流单输入（仅 generator 输出） | ✓ `members` is the only Figma data input |
| 组件由 page 注入，grid 不硬编码 canonical 路径 | ✓ `component` prop proposal |
| theme isolation 语义符合 plan §2.3 | ✓ no theme -> all variants; theme -> filter by `siteTheme` |
| γ audit 锚点设计可机械识别 | ✓ `data-figma-members` boundary + `data-figma-source="generator"` cells |
| Grid 不内嵌 Try It / 手写 demo 渲染逻辑 | ✓ |
| 不内嵌 normalization 逻辑 | ✓ consumes generated TS only |
| CSS 草图避免 hex/rgb literal | ✓ token-only intent |
| 没自决 | ✓ all API/attr choices listed as decision points |
| 没扩范围 | ✓ no `.vue` implementation, no `src/`, `figma-sync/`, or `playground/` edits |
