Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .changeset/widget-contract-theme-token-vocabulary.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
---
---

docs(protocol): `protocol/objectui/widget-contract` 的 Theme 段停止教 #3494 已删除的 `density`,整段 token 词表按 #5021 的退役结果重写 (#5291)

该页 Theme 段的散文与 YAML 示例都在教 `density`(「`density` is one of `compact`,
`regular`, or `spacious`」+ 示例里的 `density: regular`)。这个键在 #3494 就被删了,
而 `ThemeSchema` 自 #4001 批 15 起是 `.strict()` —— 两件事叠加的结果是**照抄本页示例
必然 parse 失败**:`defineStack({ themes })` / `defineTheme()` 都会拒。拒绝本身是响亮
且带处方的(`THEME_RETIRED_KEY_GUIDANCE` 里 `density` 的墓碑),问题在于平台自己的权威
文档把作者送进了那次拒绝——对从这一页取样写主题的 AI 作者尤其贵。

原示例其实有**两处**解析失败:除 `density` 外,`colors:` 下只有一行注释,YAML 解析成
`null`,而 `colors` 是必填且 `primary` 必填。现在的示例是一份真能通过 `ThemeSchema`
解析的完整主题。

同时把整段的 token 词表口径刷新到 #5021 之后:

- 逐一列出 `ThemeSchema` 的**十个**可写键(`name` / `label` / `description` / `mode` /
`extends` 五个身份与继承键,加 `colors` / `borderRadius` / `shadows` / `typography` /
`customVars` 五个 token 键),并给出每个键实际落到 document 上的 CSS 变量——包括
`colors` 出门时的改名(`surface` → `--card`、`text` → `--foreground`、
`error` → `--destructive` …)、`borderRadius.base` / `shadows.base` 发的是裸
`--radius` / `--shadow`、`typography` 自 #5021 起只剩 `fontFamily.base`(发
`--font-sans`)。
- 新增一段 Callout 点名两批退役键:#3494 的 `spacing` / `breakpoints` / `logo` /
`density` / `wcagContrast` / `rtl` / `touchTarget` / `keyboardNavigation`,以及 #5021
(`@objectstack/spec` 17.0.0, ADR-0049)的 `animation` / `zIndex`、`typography` 四条
排版标尺、`fontFamily.heading` / `mono`;两批的处方都是 `customVars`,且是逐字节等价
的替代(`customVars` 里写 `font-size-lg` 发的就是同一个 `--font-size-lg`),并给出
`os migrate meta --from 16`。

页面的每条断言都对着 `packages/spec/src/ui/theme.zod.ts` 与 objectui `ThemeEngine.ts`
逐键核过:16 个退役键全部被拒、10 个活键全部被接受。

Docs-only;releases nothing.
41 changes: 37 additions & 4 deletions content/docs/protocol/objectui/widget-contract.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -316,21 +316,54 @@ The widget manifest carries **no** performance block. Virtualization for large d

## Theme

ObjectUI theming is defined by `ThemeSchema` in `packages/spec/src/ui/theme.zod.ts`. A theme requires a `name`, `label`, and `colors` palette. The `mode` is one of `light`, `dark`, or `auto`, and `density` is one of `compact`, `regular`, or `spacious`. `borderRadius` is a scale object (`none`/`sm`/`base`/`md`/`lg`/...), not a single token:
ObjectUI theming is defined by `ThemeSchema` in `packages/spec/src/ui/theme.zod.ts`, and it declares **ten** authorable keys — that list is the whole vocabulary. Five of them are identity and inheritance: `name` (a snake_case identifier) and `label` are required, `description` is optional, `mode` is one of `light`, `dark`, or `auto` (default `light`), and `extends` names another theme to inherit from. The other five are the token surface:

| Key | Required | Shape | What it puts on the document |
|-------|-------|-------|-------|
| `colors` | ✅ | `ColorPalette`; only `primary` is mandatory inside it | The shadcn palette variables — **renamed on the way out**: `surface` emits `--card`, `text` emits `--foreground`, `textSecondary` emits `--muted-foreground`, `disabled` emits `--muted`, `error` emits `--destructive`. |
| `borderRadius` | — | A scale object (`none`/`sm`/`base`/`md`/`lg`/`xl`/`2xl`/`full`), not a single token | `--radius-sm`, `--radius-md`, ... — and `base` emits the bare `--radius`. |
| `shadows` | — | The same stops plus `inner` | `--shadow-sm`, `--shadow-md`, ... — and `base` emits the bare `--shadow`. |
| `typography` | — | One live key since #5021: `fontFamily.base` | `--font-sans`. |
| `customVars` | — | A flat string map | Every entry verbatim, `--` prefixed if you omit it: `z-modal: '1050'` emits `--z-modal: 1050`. This is the declared door for any other custom property. |

```yaml
name: corporate
label: Corporate
mode: light
density: regular
colors:
# ColorPalette configuration
primary: '#2563eb'
surface: '#ffffff'
text: '#111827'
borderRadius:
base: 0.25rem
md: 0.375rem
shadows:
base: '0 1px 3px rgb(0 0 0 / 0.1)'
typography:
fontFamily:
base: 'Inter, system-ui, sans-serif'
customVars:
space-4: 1rem
```

Widgets inherit the active theme automatically; they do not each carry a full set of color/typography props.
`ThemeSchema` is `.strict()` (#4001), so a key outside that list is a **parse failure** at `defineStack({ themes })` / `defineTheme()`, carrying its own prescription — not a value silently dropped while the theme still reports valid.

<Callout type="warn">
**Older theme samples no longer parse** — check yours before copying it forward.
**#3494** removed `spacing`, `breakpoints`, `logo`, `density`, `wcagContrast`,
`rtl`, `touchTarget` and `keyboardNavigation`: the theme engine never emitted a
variable for any of them, so authoring one was a silent no-op. **#5021**
(`@objectstack/spec` 17.0.0, ADR-0049) removed `animation`, `zIndex`, the
`typography.fontSize` / `fontWeight` / `lineHeight` / `letterSpacing` scales and
`typography.fontFamily.heading` / `mono`: those *were* emitted, faithfully and
for years, but no first-party component or stylesheet has ever read one.
The prescription in both waves is `customVars`, and it is a byte-for-byte
replacement — `customVars` carrying `font-size-lg: 1.125rem` puts exactly the
same `--font-size-lg` on the document the retired scale did. Run
`os migrate meta --from 16` to rewrite stored metadata automatically.
</Callout>

Widgets inherit the active theme automatically; they do not each carry their own copy of the palette or the font stack.

## What's Next?

Expand Down
Loading