@teamix-evo/mcp 0.4.0 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +64 -16
- package/dist/cli.js.map +1 -1
- package/dist/data/adr/0001-three-layer-alignment.md +11 -11
- package/dist/data/adr/0005-ui-no-variant.md +4 -4
- package/dist/data/adr/0006-ui-upgrade-no-baseline.md +6 -6
- package/dist/data/adr/0010-design-default-and-variants.md +1 -1
- package/dist/data/adr/0019-project-upgrade-flow.md +13 -13
- package/dist/data/adr/0021-semantic-color-api-unification.md +127 -0
- package/dist/data/adr/0022-preferences-css-boundary.md +75 -0
- package/dist/data/adr/0023-cursor-pointer-explicit-in-component-source.md +70 -0
- package/dist/data/adr/0024-scoped-css-radix-state-conflict.md +99 -0
- package/dist/data/adr/0025-component-props-explicit-declaration.md +145 -0
- package/dist/data/adr/0026-component-level-token-alias.md +107 -0
- package/dist/data/adr/0027-component-visual-token-alignment.md +127 -0
- package/dist/data/adr/0028-ui-component-categorization.md +112 -0
- package/dist/data/adr/0029-input-split-and-prefix-suffix-removal.md +68 -0
- package/dist/data/adr/0030-skill-uni-manager-uplift.md +56 -0
- package/dist/data/adr/0031-skill-templates-decoupling.md +77 -0
- package/dist/data/adr/0032-opentrek-v4.1-brand-token-alignment.md +129 -0
- package/dist/data/adr/0033-entry-skill-global-only-scope.md +64 -0
- package/dist/data/adr/0034-skills-cli-verb-alignment.md +61 -0
- package/dist/data/adr/0035-skills-update-scope-and-lock-gates.md +69 -0
- package/dist/data/adr/0036-ui-v2-shadcn-baseline-rebuild.md +146 -0
- package/dist/data/adr/0037-filter-bar-composable-architecture.md +426 -0
- package/dist/data/adr/0038-create-agents-md-skill-trigger-fallback.md +99 -0
- package/dist/data/adr/0040-component-source-layer-upgrade-flow.md +104 -0
- package/dist/data/adr/README.md +41 -28
- package/dist/index.js +64 -16
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# 0025. 组件 props 必须显式声明 + 数据录入类必须暴露 value/onChange 受控套
|
|
2
|
+
|
|
3
|
+
- **Status**: Superseded by [0036](./0036-ui-v2-shadcn-baseline-rebuild.md)
|
|
4
|
+
- **Date**: 2026-06-01
|
|
5
|
+
- **Region**: 0100–0999 协议与工具
|
|
6
|
+
- **Related ADR**: [ADR 0023](0023-cursor-pointer-explicit-in-component-source.md) · [ADR 0024](0024-scoped-css-radix-state-conflict.md)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
`@teamix-evo/ui` 包内多数 Radix-based 组件目前是这种写法:
|
|
11
|
+
|
|
12
|
+
```ts
|
|
13
|
+
export interface CheckboxProps
|
|
14
|
+
extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> {}
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
**空 extends + 透传 Radix Root 的 props**。优点是类型上"自动获得 Radix 全套 props",但带来三个严重缺陷:
|
|
18
|
+
|
|
19
|
+
### 缺陷 1 — meta.md props 表为空,AI 无法快速使用
|
|
20
|
+
|
|
21
|
+
`packages/ui/scripts/generate-meta.ts` 自动从 interface 字段提取 JSDoc 生成 props 表。空 interface → 表里只剩一行 `_(no props)_`。
|
|
22
|
+
|
|
23
|
+
> 真实案例:Checkbox meta props 表显示空,新业务工程的 AI 生成代码必须**额外去翻 Radix 文档**才能知道支持哪些 prop;遇到 `onCheckedChange` vs antd `onChange` 命名差异时 AI 经常生成错误回调名。
|
|
24
|
+
|
|
25
|
+
### 缺陷 2 — Storybook argTypes 缺数据源
|
|
26
|
+
|
|
27
|
+
Storybook 的 `argTypes: { ... }` 写控件时,如果对应 prop 不在 interface 字面里,IDE 没补全、controls 面板也不显示。结果 Storybook playground 退化为"只能看默认 demo,改不了任何参数"。
|
|
28
|
+
|
|
29
|
+
### 缺陷 3 — 数据录入类组件可能漏 value/onChange
|
|
30
|
+
|
|
31
|
+
Radix 的命名(`onCheckedChange` / `onValueChange`)与 antd / cd / 业务习惯(`onChange`)不一致;有些组件甚至没有清晰的"受控套"。如果不显式声明,业务侧不知道该用哪一对 prop 实现受控,常常自己写一遍非受控 + state mirror。
|
|
32
|
+
|
|
33
|
+
## Options Considered
|
|
34
|
+
|
|
35
|
+
| 选项 | 优点 | 缺点 |
|
|
36
|
+
| ----------------------------------------------- | ----------------------------------------------- | -------------------------------------------------- |
|
|
37
|
+
| A. 维持现状(空 extends 透传) | 写法少,类型自动完整 | meta props 空 / AI 不可用 / Storybook 控件缺数据源 |
|
|
38
|
+
| B. **显式列出每个支持的 prop + JSDoc 中文注释** | meta 自动表完整;Storybook controls 完整;AI 可读 | 每个组件多 ~20 行类型声明,需对齐 Radix 行为 |
|
|
39
|
+
|
|
40
|
+
## Decision
|
|
41
|
+
|
|
42
|
+
**采纳选项 B** — 数据录入类与有交互意义的 props 必须显式声明。两条规则:
|
|
43
|
+
|
|
44
|
+
### 规则 A — 所有可配置 props 必须在 interface 字面里显式声明,带 JSDoc
|
|
45
|
+
|
|
46
|
+
```ts
|
|
47
|
+
// ❌ Before
|
|
48
|
+
export interface CheckboxProps
|
|
49
|
+
extends React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root> {}
|
|
50
|
+
|
|
51
|
+
// ✅ After
|
|
52
|
+
export interface CheckboxProps
|
|
53
|
+
extends Omit<
|
|
54
|
+
React.ComponentPropsWithoutRef<typeof CheckboxPrimitive.Root>,
|
|
55
|
+
'checked' | 'defaultChecked' | 'onCheckedChange'
|
|
56
|
+
> {
|
|
57
|
+
/** 受控选中状态 — `true` / `false` / `'indeterminate'`(半选)。 */
|
|
58
|
+
checked?: boolean | 'indeterminate';
|
|
59
|
+
/** 非受控初始选中态。 */
|
|
60
|
+
defaultChecked?: boolean | 'indeterminate';
|
|
61
|
+
/**
|
|
62
|
+
* 选中状态变化回调 — Radix 命名,等价 antd `onChange(checked)`。
|
|
63
|
+
* @param checked - `true` / `false` / `'indeterminate'`
|
|
64
|
+
*/
|
|
65
|
+
onCheckedChange?: (checked: boolean | 'indeterminate') => void;
|
|
66
|
+
/** 禁用整个 checkbox。 */
|
|
67
|
+
disabled?: boolean;
|
|
68
|
+
/** 必填(HTML 原生 required;表单层校验依赖此值)。 */
|
|
69
|
+
required?: boolean;
|
|
70
|
+
/** 表单提交时的字段名。 */
|
|
71
|
+
name?: string;
|
|
72
|
+
/** 表单提交时随勾选状态发送的 value。 */
|
|
73
|
+
value?: string;
|
|
74
|
+
/** id 属性,配合 `<label htmlFor>` 关联标签。 */
|
|
75
|
+
id?: string;
|
|
76
|
+
}
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
**关键点**:
|
|
80
|
+
|
|
81
|
+
- 用 `Omit<RadixProps, 'overridden-keys'>` 排除被本地重写的字段,避免类型冲突
|
|
82
|
+
- 所有暴露给业务的 prop **必须**带中文 JSDoc(`generate-meta.ts` 提取的就是这部分)
|
|
83
|
+
- **不在 interface 暴露的 prop = 不支持** — 不允许"暗中支持但不声明"
|
|
84
|
+
|
|
85
|
+
### 规则 B — 数据录入类组件**必须**至少暴露受控套
|
|
86
|
+
|
|
87
|
+
数据录入类(用户输入 / 选择 / 调整某个 value 的组件)**必须**至少有这一对受控 prop:
|
|
88
|
+
|
|
89
|
+
| 组件类型 | 受控 value | 受控 onChange | 非受控初值 |
|
|
90
|
+
| -------------------------------------------------------------------------------------------------------------- | ---------------------------------------- | ---------------------------------------- | ------------------------ |
|
|
91
|
+
| 单值输入(Input / Textarea / NumberInput / DatePicker / TimePicker / ColorPicker / Select 单选 / Combobox 单选) | `value` | `onChange` 或 Radix 命名(透传时显式声明) | `defaultValue` |
|
|
92
|
+
| 布尔值(Checkbox / Switch) | `checked` | `onCheckedChange` | `defaultChecked` |
|
|
93
|
+
| 多值(Select 多选 / Combobox 多选 / CheckboxGroup) | `value: string[]` | `onChange: (next: string[]) => void` | `defaultValue: string[]` |
|
|
94
|
+
| 数值滑动(Slider / Rate) | `value: number[]` 或 `value: number` | `onValueChange` 或 `onChange` | `defaultValue` |
|
|
95
|
+
| 树形(Tree / TreeSelect) | `value` / `selectedKeys` / `checkedKeys` | 对应 onChange / onSelect / onCheck | `default*` |
|
|
96
|
+
| 级联(Cascader) | `value: string[]` | `onChange: (path, options) => void` | `defaultValue` |
|
|
97
|
+
|
|
98
|
+
业务工程**必须能用受控模式跑通**;非受控只是便利封装。
|
|
99
|
+
|
|
100
|
+
### 适用范围
|
|
101
|
+
|
|
102
|
+
- **必须**显式声明 props:`category: 'form'` 类组件 + 任何带交互的展示组件(Card hoverable / Tag closable / Avatar onClick 等)
|
|
103
|
+
- **可以**保持简单透传(空 extends):纯展示无交互 wrapper(Skeleton / Separator / Spinner / Progress 这种组件本身没业务可配的 prop)
|
|
104
|
+
|
|
105
|
+
## Consequences
|
|
106
|
+
|
|
107
|
+
### 强制约束(由本 ADR + [`teamix-evo-design-opentrek` skill checklist](../../packages/skills/src/teamix-evo-design-opentrek/checklist.md) 同步落地)
|
|
108
|
+
|
|
109
|
+
设计 skill checklist 强制项 #13:**"数据录入类组件 props 必须显式声明 + 至少暴露 value/onChange 受控套"**(具体类型见上表)。AI 生成 / 人工 review 都按此查。
|
|
110
|
+
|
|
111
|
+
### 工程影响
|
|
112
|
+
|
|
113
|
+
- **`pnpm gen:meta`** 自动从 interface JSDoc 生成 props 表 — interface 越完整,meta 越好用
|
|
114
|
+
- **Storybook `argTypes`** 完整 → playground controls 完整 → AI 用 storybook-mcp 读 args 可直接生成代码
|
|
115
|
+
- **业务工程升级** — 现有组件本来就支持这些 prop(Radix 透传),只是声明不显式;升级后**0 行业务代码改动**
|
|
116
|
+
|
|
117
|
+
### 已落地清单(本次 ADR 配套)
|
|
118
|
+
|
|
119
|
+
- ✅ Checkbox(本次升级,作为首个示例)
|
|
120
|
+
|
|
121
|
+
### 后续工序
|
|
122
|
+
|
|
123
|
+
按以下优先级**逐组件升级**(W4 / W5 / W6 等波次时一并做):
|
|
124
|
+
|
|
125
|
+
1. **W2 已交付组件回补**:Switch / RadioGroup / Slider / Rate / Mentions / InputNumber / Combobox(已合并入 Select,需补)
|
|
126
|
+
2. **W3 已交付**:Select(本次合并已含完整 props)/ Cascader / TreeSelect / Tree
|
|
127
|
+
3. **W4+ 待开**:DatePicker / TimePicker / Calendar / ColorPicker / Upload / Form
|
|
128
|
+
|
|
129
|
+
完成后所有 form 类组件都满足 ADR 0025。
|
|
130
|
+
|
|
131
|
+
### 验证方式
|
|
132
|
+
|
|
133
|
+
- `pnpm --filter @teamix-evo/ui gen:meta` 后检查 `<id>.meta.md` 的 `<!-- auto:props:begin -->` 块,确保非空且字段完整
|
|
134
|
+
- Storybook 打开任一 form 组件 Story,Controls 面板应能调整 value / onChange / disabled 等核心 prop
|
|
135
|
+
|
|
136
|
+
### 反模式(踩过的坑)
|
|
137
|
+
|
|
138
|
+
- ❌ `extends React.ComponentPropsWithoutRef<typeof Primitive.Root> {}` 空 extends — meta 表空,AI 不可用
|
|
139
|
+
- ❌ 只在 README / 注释里写 prop 文档,不进 TypeScript interface — 被业务工程升级 / IDE 提示忽略
|
|
140
|
+
- ❌ 数据录入类只支持 `defaultValue` 不支持 `value` — 业务做不了表单层 controlled 状态
|
|
141
|
+
|
|
142
|
+
## Source
|
|
143
|
+
|
|
144
|
+
- 真实案例:用户对比 cd hybridcloud 截图(Checkbox 暴露 ~10 个 props 含 onChange / value 等),与我们 meta 显示 `_(no props)_` 形成强烈对比 → 反推这是装机即用 / AI 可读维度的 P0 缺陷
|
|
145
|
+
- shadcn-ui 官方组件普遍使用空 extends 写法 — 这是为开源体验最大化设计的(类型自动完整),但**对 AI 友好度不是设计目标**;teamix-evo 主张 AI-first,因此显式声明优先
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
# 0026. 组件级 token 别名(`--radius-{component}` 等)的创建准则
|
|
2
|
+
|
|
3
|
+
- **Status**: Superseded by [0036](./0036-ui-v2-shadcn-baseline-rebuild.md)
|
|
4
|
+
- **Date**: 2026-06-02
|
|
5
|
+
- **Region**: 0100–0999 协议与工具
|
|
6
|
+
- **Related ADR**: [ADR 0020](0020-design-to-tokens-skill-fusion.md)(tokens 包 / skill 边界) · [ADR 0022](0022-preferences-css-boundary.md)(已 superseded,曾约束 preferences.css 不放 token alias)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
W4–W5 优化时多次遇到"组件圆角该怎么定义"的问题。早期默认做法是给每个组件加一个语义别名(`--radius-button` / `--radius-dialog` / `--radius-tag` / ...),组件 className 写 `rounded-[var(--radius-X)]` 取值。
|
|
11
|
+
|
|
12
|
+
后来 Button 优化时发现:**这种 arbitrary value 写法在 Tailwind v4 多包 `@import` 场景下不被自动派生为 utility**(实测 dev server 编译产物中 `.rounded-button { ... }` 规则不生成),组件回退到浏览器默认 8px(脱离 token 链路)。为修这个 bug,Button 改用 Tailwind v4 标准 namespace token `--radius-md`,直接走 `rounded-md` utility;`--radius-button` 被移除。
|
|
13
|
+
|
|
14
|
+
此后又因 Dialog 跨变体视觉差异大(opentrek 16px vs uni-manager 2px),发现**纯 scale 无法满足**:无论选哪个 `rounded-X` utility,都没有任何一档能让 opentrek=16 且 uni-manager=2 同时成立。因此 `--radius-dialog` 作为组件级别名被保留下来,组件内部使用 `rounded-[var(--radius-dialog)]` 语法。
|
|
15
|
+
|
|
16
|
+
这暴露了两类完全不同的 token 角色:
|
|
17
|
+
|
|
18
|
+
| 层 | 类型 | 例子 | 谁定义 | 谁消费 |
|
|
19
|
+
| ------- | ---------------- | ------------------------------------------------------------------------------ | --------------------- | ------------------------------------------------------------------- |
|
|
20
|
+
| Layer 1 | scale primitives | `--radius-sm` / `--radius-md` / `--radius-lg` / `--radius-xl` / `--radius-2xl` | 各 variant 可独立覆盖 | 所有组件,通过 Tailwind 标准 utility `rounded-{sm\|md\|lg\|xl\|2xl}` |
|
|
21
|
+
| Layer 2 | 组件语义别名 | `--radius-dialog` / `--radius-tag` | 各 variant 可独立覆盖 | 仅该组件,通过 `rounded-[var(...)]` arbitrary value |
|
|
22
|
+
|
|
23
|
+
ADR 0022(已 superseded)曾约束"preferences.css 边界",但没有规范"什么时候可以加 Layer 2 别名"。本 ADR 补这一条。
|
|
24
|
+
|
|
25
|
+
## Options Considered
|
|
26
|
+
|
|
27
|
+
| 选项 | 优点 | 缺点 |
|
|
28
|
+
| -------------------------------------------------------- | --------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------- |
|
|
29
|
+
| A. 严格一层 — 所有组件走 scale,不允许 Layer 2 | token 架构最简 / 一致性最强 | 跨变体视觉差异大的组件被强制对齐,失去变体差异化能力(opentrek Dialog 必须从 16 收到 6,失去"圆润"视觉特征) |
|
|
30
|
+
| B. **二层模式 — 优先 scale,严控 Layer 2 创建条件(推荐)** | scale 是默认路径(简单);Layer 2 作为 escape hatch,有明确触发条件 | 需要 ADR 守门;否则 Layer 2 会无序蔓延变成"杂物间" |
|
|
31
|
+
| C. 全自由 — 任何组件都可加 `--radius-{name}` | 最大灵活性 | 跟 ADR 之前踩坑的"AI / 业务工程不知道该用哪个 token"反模式重合;token 数量爆炸 |
|
|
32
|
+
|
|
33
|
+
## Decision
|
|
34
|
+
|
|
35
|
+
**采纳选项 B** — 二层模式,Layer 2 创建有硬性触发条件。
|
|
36
|
+
|
|
37
|
+
### 规则 A — 默认走 Layer 1 scale(Tailwind v4 namespace)
|
|
38
|
+
|
|
39
|
+
新增组件 / 优化组件时,**圆角默认**写:
|
|
40
|
+
|
|
41
|
+
```tsx
|
|
42
|
+
className = 'rounded-md'; // 走 --radius-md (uni-manager 2 / opentrek 6 / Tailwind 默认 6)
|
|
43
|
+
className = 'rounded-lg'; // 走 --radius-lg (uni-manager 4 / opentrek 8 / Tailwind 默认 8)
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
各 variant 在 `@theme {}` 块里覆盖 `--radius-sm/md/lg/xl/2xl` 满足该 variant 的视觉调性。
|
|
47
|
+
|
|
48
|
+
**禁止** `rounded-[6px]` / `rounded-[var(--xxx)]` 等 arbitrary value(除非满足规则 B 的硬条件)。
|
|
49
|
+
|
|
50
|
+
### 规则 B — 满足以下**全部**条件才可创建 Layer 2 别名
|
|
51
|
+
|
|
52
|
+
| # | 条件 | 备注 |
|
|
53
|
+
| --- | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
54
|
+
| 1 | 跨变体的目标值**无法被同一个 scale 档同时满足** | 例:Dialog 在 opentrek 想要 16px,uni-manager 想要 2px。无任何 `rounded-{sm\|md\|lg\|xl\|2xl}` 在两个 variant 同时落到这两个值 |
|
|
55
|
+
| 2 | 该组件视觉**确实有跨变体差异化的设计意图**,不是 token 命名洁癖 | 例:Dialog 跨变体差异是"圆润感 vs 锐利感"的设计语言,非可省略 |
|
|
56
|
+
| 3 | 不能通过组合 `cn()` / 变体 className 实现 | 同一 `<Dialog>` 源码不能写"变体感知 className",所以 Dialog 必须有 token alias |
|
|
57
|
+
| 4 | 命名清晰指向具体组件 | `--radius-{component-id}`,如 `--radius-dialog` / `--radius-tag` |
|
|
58
|
+
|
|
59
|
+
不满足全部 4 条 → **走 Layer 1 scale**。
|
|
60
|
+
|
|
61
|
+
### 规则 C — 现存 Layer 2 别名 audit(本 ADR 落地时)
|
|
62
|
+
|
|
63
|
+
| Token | 状态 | 理由 |
|
|
64
|
+
| ----------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------------------------- |
|
|
65
|
+
| `--radius-button` | **已移除**(W1-Button 优化时) | 走 `rounded-md` 即可(uni 2 / opentrek 6 / 标准 6),无变体差异化需求 |
|
|
66
|
+
| `--radius-dialog` | **保留** | uni 2 / opentrek 16 跨档不可对齐;有"圆润 vs 锐利"设计语言差异;Dialog/AlertDialog/Sheet 共享 |
|
|
67
|
+
| `--radius-tag` | **保留** | uni 4 / opentrek 4(同值但不在任一 variant 的同一 scale 档:opentrek `rounded-sm`=4 ✓ / uni `rounded-sm`=0 ✗);需 alias 才能跨变体对齐 |
|
|
68
|
+
|
|
69
|
+
### 规则 D — 同样模式适用于其他 token namespace
|
|
70
|
+
|
|
71
|
+
本 ADR 围绕 `--radius-*` 描述,但同样规则适用于 `--shadow-*` / `--spacing-*` / `--color-*` 等:
|
|
72
|
+
|
|
73
|
+
- **Layer 1 scale** 是首选(`--shadow-sm/md/lg/xl/2xl`、Tailwind v4 标准 spacing scale)
|
|
74
|
+
- **Layer 2 组件语义别名** 仅在满足规则 B 全部 4 条时创建
|
|
75
|
+
- 既有的 `--shadow-form-hover` / `--color-input-focus`(ADR 0023 引入)按此审视:它们是"form 控件 hover/focus 共用语义",跨多组件使用 → 不是单组件别名 → **算 Layer 1.5(semantic primitive)**,不违反本 ADR
|
|
76
|
+
|
|
77
|
+
## Consequences
|
|
78
|
+
|
|
79
|
+
### 工程影响
|
|
80
|
+
|
|
81
|
+
- 新增组件 / 优化既有组件时,**圆角默认走 scale**,不再随手加 `--radius-{name}`
|
|
82
|
+
- 已存在的 `--radius-dialog` / `--radius-tag` 保留(满足规则 B);未来 audit 时按规则审视
|
|
83
|
+
- ADR 设计 skill checklist 不新增条目(本 ADR 是架构层规则,不需要逐组件检查)
|
|
84
|
+
- AI / 人工新增组件 review 时:看到 `--radius-{name}` 自定义别名 → 必须能在 PR 描述里讲清楚满足规则 B 哪 4 条;说不清 → 改走 scale
|
|
85
|
+
|
|
86
|
+
### 反模式(后续 PR 不接受)
|
|
87
|
+
|
|
88
|
+
```tsx
|
|
89
|
+
// ❌ 无变体差异化诉求的随手 alias
|
|
90
|
+
--radius-input-group: 4px;
|
|
91
|
+
className="rounded-[var(--radius-input-group)]"
|
|
92
|
+
|
|
93
|
+
// ✅ 应该写
|
|
94
|
+
className="rounded-md" // uni 2 / opentrek 6
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 与现有 ADR 关系
|
|
98
|
+
|
|
99
|
+
- 取代 [ADR 0022](0022-preferences-css-boundary.md) 中"preferences.css 不放 token alias"的零散约束(那个文件已删,但精神保留)
|
|
100
|
+
- 与 [ADR 0023](0023-cursor-pointer-explicit-in-component-source.md) 关于 cursor 的显式声明、[ADR 0025](0025-component-props-explicit-declaration.md) 关于 props 显式声明并列,共同构成"AI-first 组件库"的工程约束
|
|
101
|
+
|
|
102
|
+
## Source
|
|
103
|
+
|
|
104
|
+
- 真实案例 1:Button `--radius-button` Tailwind v4 自定义 namespace 无 utility 派生 bug(W1-Button 优化时记录的"Tailwind 自定义 utility 在分层引入模式下不生效" 记忆)
|
|
105
|
+
- 真实案例 2:Dialog 跨变体视觉差异(opentrek 16 / uni-manager 2)无 scale 单档可对齐
|
|
106
|
+
- 真实案例 3:Tag 跨变体同值(4)但 scale 档不对齐(opentrek `rounded-sm`=4 / uni `rounded-sm`=0)
|
|
107
|
+
- 用户 review 反馈(2026-06-02):"按照理念不应该定义一批圆角的变量供所有组件使用,而不是单独定义某个组件?"
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
# 0027. 组件视觉属性全轴对齐设计系统基线
|
|
2
|
+
|
|
3
|
+
- **Status**: Superseded by [0036](./0036-ui-v2-shadcn-baseline-rebuild.md)
|
|
4
|
+
- **Date**: 2026-06-02
|
|
5
|
+
- **Region**: 0001–0099 工程哲学
|
|
6
|
+
- **Related ADR**: 0010 (design-default-and-variants), 0026 (component-level-token-alias), 0032 (opentrek-v4.1-brand-token-alignment)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
cd hybridcloud 主题为所有组件定义了明确的视觉基线,涵盖字号、圆角、颜色、阴影等全部轴。审计发现 **大量组件偏离基线**,且两个变体(uni-manager / opentrek)间的 token 覆盖度不一致,导致:
|
|
11
|
+
|
|
12
|
+
1. 组件在 uni-manager 变体下不符合 cd hybridcloud 视觉规范
|
|
13
|
+
2. opentrek 变体缺少显式 radius 档位定义,依赖 Tailwind 隐式默认值
|
|
14
|
+
3. 特定组件(tag / dialog)需要组件级 token 才能实现跨变体差异化
|
|
15
|
+
|
|
16
|
+
**cd hybridcloud 基线真值(medium/default 档):**
|
|
17
|
+
|
|
18
|
+
| 轴 | Token | 值 | Tailwind utility |
|
|
19
|
+
| ---- | -------------------- | ------------ | ---------------------------------- |
|
|
20
|
+
| 字号 | `--font-size-body-1` | 12px | `text-xs` |
|
|
21
|
+
| 圆角 | `--corner-1` | 2px | `rounded-md`(uni-manager 覆盖后) |
|
|
22
|
+
| 阴影 | `--shadow-1` | 通常无或极淡 | `shadow-sm` / `shadow-none` |
|
|
23
|
+
| 颜色 | `--color-text1-4` | 正文色 | `text-foreground` |
|
|
24
|
+
|
|
25
|
+
**偏差审计摘要:**
|
|
26
|
+
|
|
27
|
+
- **字号**:28 个组件 medium 使用 `text-sm`(14px),应为 `text-xs`(12px)
|
|
28
|
+
- **圆角**:tag 缺失 rounded / card·alert·sonner 用 `rounded-lg`(4px) / accordion 用 `rounded-sm`(0px)
|
|
29
|
+
- **阴影 / 颜色 / 间距**:待本轮逐项确认
|
|
30
|
+
|
|
31
|
+
## Options Considered
|
|
32
|
+
|
|
33
|
+
| 选项 | 优点 | 缺点 |
|
|
34
|
+
| -------------------------------------------------------------------- | ------------------------------------------------------ | ------------------------------------------------------------------- |
|
|
35
|
+
| A. 全组件硬编码修正(直接改 class) | 简单直接,一步到位 | opentrek 被迫接受 uni-manager 的值;无法跨变体差异化 |
|
|
36
|
+
| B. Tailwind utility 作为语义层 + 主题 token 控值 + 组件级 token 补充 | 两变体各自表达;组件代码不变即可换肤;特殊组件有逃生舱 | 需补全 opentrek 的 radius scale;需引入少量 `--radius-*` 组件 token |
|
|
37
|
+
| C. 全部走组件级 CSS 变量 | 极致灵活 | token 膨胀;失去 Tailwind utility-first 优势 |
|
|
38
|
+
|
|
39
|
+
## Decision
|
|
40
|
+
|
|
41
|
+
**采用方案 B**:三层策略覆盖全部视觉属性。
|
|
42
|
+
|
|
43
|
+
### 1. Tailwind utility 作为通用语义层
|
|
44
|
+
|
|
45
|
+
组件源码使用 Tailwind 标准 utility(`text-xs`、`rounded-md`、`shadow-sm` 等),各变体通过 `@theme` 中的 CSS 变量定义控制最终视觉值:
|
|
46
|
+
|
|
47
|
+
| utility | uni-manager | opentrek |
|
|
48
|
+
| ------------ | ----------- | ------------------------------- |
|
|
49
|
+
| `text-xs` | 12px | 12px |
|
|
50
|
+
| `text-sm` | 14px | 14px |
|
|
51
|
+
| `rounded-md` | 2px | 8px ⚠️ ADR 0032 升级(原 6px) |
|
|
52
|
+
| `rounded-lg` | 4px | 12px ⚠️ ADR 0032 升级(原 8px) |
|
|
53
|
+
| `shadow-sm` | 极淡 / 无 | 标准 shadcn |
|
|
54
|
+
|
|
55
|
+
### 2. 组件级 token 处理跨变体差异
|
|
56
|
+
|
|
57
|
+
当同一组件在不同变体需要**不同档位**的视觉值时,引入组件级 CSS token:
|
|
58
|
+
|
|
59
|
+
```css
|
|
60
|
+
/* tokens/variants/uni-manager/theme.css */
|
|
61
|
+
--radius-dialog: 2px;
|
|
62
|
+
--radius-tag: 4px;
|
|
63
|
+
|
|
64
|
+
/* tokens/variants/opentrek/theme.css */
|
|
65
|
+
--radius-dialog: 16px;
|
|
66
|
+
--radius-tag: 4px;
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
组件使用 `rounded-[var(--radius-dialog)]` 消费。
|
|
70
|
+
|
|
71
|
+
### 3. 变体 theme.css 必须显式声明全部档位
|
|
72
|
+
|
|
73
|
+
禁止依赖 Tailwind 隐式默认值。每个变体的 `theme.css` 必须显式声明:
|
|
74
|
+
|
|
75
|
+
- `--radius-sm` / `--radius-md` / `--radius-lg` / `--radius-xl`
|
|
76
|
+
- `--shadow-sm` / `--shadow-md` / `--shadow-lg`(如有差异)
|
|
77
|
+
- 字号走 Tailwind 默认即可(两变体一致),仅特殊档覆盖
|
|
78
|
+
|
|
79
|
+
### 4. medium/default 档位对齐规则
|
|
80
|
+
|
|
81
|
+
| 组件类型 | 字号 | 圆角 | 阴影 |
|
|
82
|
+
| ------------------------------------ | ---------------------------------- | -------------------------------- | ----------- |
|
|
83
|
+
| 表单控件(button/input/select 等) | `text-xs` | `rounded-md` | `shadow-sm` |
|
|
84
|
+
| 弹层容器(dialog/sheet/drawer) | `text-xs`(body) / `text-sm`(title) | `rounded-[var(--radius-dialog)]` | `shadow-lg` |
|
|
85
|
+
| 信息容器(card/alert/notification) | `text-xs` | `rounded-md` | `shadow-sm` |
|
|
86
|
+
| 标签类(tag/badge) | `text-xs` | `rounded-[var(--radius-tag)]` | 无 |
|
|
87
|
+
| 导航类(tabs/pagination/breadcrumb) | `text-xs` | `rounded-md` | 无 |
|
|
88
|
+
| 浮层(tooltip/popover/dropdown) | `text-xs` | `rounded-md` | `shadow-md` |
|
|
89
|
+
|
|
90
|
+
### 5. 颜色对齐
|
|
91
|
+
|
|
92
|
+
颜色已通过 ADR 0021 语义色体系治理,组件使用 `text-foreground` / `bg-background` / `border-input` 等语义 token,由各变体 theme.css 定义具体色值。本 ADR 不重复覆盖,但要求:
|
|
93
|
+
|
|
94
|
+
- 审计中发现的硬编码色值(如 `text-gray-500`)必须替换为语义 token
|
|
95
|
+
- 组件不得使用 Tailwind 原始色板(`blue-500`、`red-600` 等)
|
|
96
|
+
|
|
97
|
+
## Consequences
|
|
98
|
+
|
|
99
|
+
- **Positive**:
|
|
100
|
+
- 两个变体可独立演进视觉风格,组件源码无需分叉
|
|
101
|
+
- 统一 medium 基线后视觉一致性显著提升
|
|
102
|
+
- opentrek 显式声明后,token 值可追溯可审计
|
|
103
|
+
- **Negative**:
|
|
104
|
+
- 本次修改涉及 30+ 组件源码,需逐组件验证
|
|
105
|
+
- 少量组件级 token 增加了 theme.css 维护面
|
|
106
|
+
- **Trade-off**:
|
|
107
|
+
- 为保持 Tailwind utility-first 开发体验,接受组件级 token 仅用于"跨变体确需不同档位"场景;大多数属性走通用 utility
|
|
108
|
+
|
|
109
|
+
## Source
|
|
110
|
+
|
|
111
|
+
组件视觉审计对话(2026-06-02);cd hybridcloud css-var-definition.scss 真值确认。
|
|
112
|
+
|
|
113
|
+
## Amendment 2026-11(v2 决策块)
|
|
114
|
+
|
|
115
|
+
OpenTrek 设计源 v4.1(design-tokens.css)发布后,op variant radius 体系按用户决策完整对齐到新文档基线,本 ADR 中 opentrek 列对应数值被覆写:
|
|
116
|
+
|
|
117
|
+
- `--radius-md`:6px → **8px**
|
|
118
|
+
- `--radius-lg`:8px → **12px**
|
|
119
|
+
- `--radius-xl`:12px → **16px**
|
|
120
|
+
- 新增 `--radius-full: 9999px`
|
|
121
|
+
- 移除 `--radius-2xl`(新文档采 5 档体系)
|
|
122
|
+
|
|
123
|
+
受影响组件(`rounded-md` / `rounded-lg` 消费点):Button、Card、Input、Select、Dialog(仅 op,因 dialog 走 `--radius-dialog: 16px` 不变)、Tag(走 `--radius-tag: 4px` 不变)、Pagination 等。
|
|
124
|
+
|
|
125
|
+
uni-manager 锐利 radius 体系不变(`--radius-md: 2px`、`--radius-lg: 4px`),保持 cd hybridcloud 紧凑视觉。
|
|
126
|
+
|
|
127
|
+
详细决策与影响面记录在 [ADR 0032](./0032-opentrek-v4.1-brand-token-alignment.md)。本 ADR 三层策略(utility 语义层 / 组件级 token 差异化 / 变体显式声明)继续生效。
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
# 0028. UI 组件分类对齐 Ant Design 5.x + 引入 `deprecated` 类
|
|
2
|
+
|
|
3
|
+
- **Status**: Superseded by [0036](./0036-ui-v2-shadcn-baseline-rebuild.md)
|
|
4
|
+
- **Date**: 2026-06-02
|
|
5
|
+
- **Region**: 0100–0999 协议与工具
|
|
6
|
+
- **Related ADR**: 0014 (ui-biz-ui-templates-tier), 0025 (component-props-explicit)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
`@teamix-evo/ui` 包含 87 个组件,既有的分类(`foundation / form / layout / navigation / data-display / feedback / shell` 8 类)散落在 `meta.md` 与 `stories.tsx` 两处,问题:
|
|
11
|
+
|
|
12
|
+
1. **分类不规范**:`foundation / form / shell` 偏自创,与业界主流体系无对照,新人理解成本高
|
|
13
|
+
2. **错位**:`page-header` meta 标 `layout`、Storybook 标"导航与布局"(混类);多处 meta 与 stories title 不一致
|
|
14
|
+
3. **没有"废弃"类**:仓库里有些组件(`aspect-ratio / image / kbd` 等)研发完成后不打算外发,但仍需在 Storybook 留档;现状是用 `status: "deprecated"` 字段标记,但没有正式分类位
|
|
15
|
+
|
|
16
|
+
业界主流体系对比:
|
|
17
|
+
|
|
18
|
+
| 体系 | 类目数 | 类目命名 |
|
|
19
|
+
| ------------------ | --------- | ---------------------------------------------------------------------------- |
|
|
20
|
+
| **Ant Design 5.x** | 7 | General / Layout / Navigation / Data Entry / Data Display / Feedback / Other |
|
|
21
|
+
| Material UI | 6 | Inputs / Data Display / Feedback / Surfaces / Navigation / Layout |
|
|
22
|
+
| Chakra UI | 7 | Layout / Forms / Data Display / Feedback / Typography / Overlay / Disclosure |
|
|
23
|
+
| shadcn/ui | 0(字母序) | — |
|
|
24
|
+
| Radix UI | 6 | Form / Layout / Navigation / Overlay / Utilities / Visualization |
|
|
25
|
+
|
|
26
|
+
teamix-evo 定位**中后台研发**(opentrek + uni-manager 都是管控台),**Ant Design 5.x 7-类法是中文企业级生态事实标准**,且 ui 包定位本就是 shadcn ∪ antd 合集,采用 AntD 类目最自洽。
|
|
27
|
+
|
|
28
|
+
## Options Considered
|
|
29
|
+
|
|
30
|
+
| 选项 | 优点 | 缺点 |
|
|
31
|
+
| ---------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------ |
|
|
32
|
+
| A. 保持现状(8 自创类) | 不动现存代码 | 分类不专业,新人难理解,与 ui 包"shadcn ∪ antd 合集"定位不匹配 |
|
|
33
|
+
| B. 全盘照搬 AntD 7 类 | 与业界标准 1:1 对齐,认知零成本 | AntD 把 Tooltip/Popover/Tabs 归 Data Display,与团队习惯有偏差 |
|
|
34
|
+
| **C. AntD 7 类 + 引入 `deprecated` 第 8 类(本方案)** | 标准对齐 + 留档诉求满足 + 极少数务实偏离(popover 仍归 feedback) | 需要批量改 87 个 meta.md + 87 个 stories.tsx + manifest.json + storySort |
|
|
35
|
+
|
|
36
|
+
## Decision
|
|
37
|
+
|
|
38
|
+
采用方案 C。`@teamix-evo/ui` 组件分为 **7 个正式类目**(对齐 AntD 5.x)+ **1 个废弃归档类**:
|
|
39
|
+
|
|
40
|
+
### 类目定义
|
|
41
|
+
|
|
42
|
+
| key | 中文 | Storybook 前缀 | 含义 |
|
|
43
|
+
| -------------- | -------- | -------------------------- | ---------------------------------------------------------------------------- |
|
|
44
|
+
| `general` | 通用 | `通用 · General/` | 任何 UI 都需要的基础原子(Button / Icon / Typography) |
|
|
45
|
+
| `layout` | 布局 | `布局 · Layout/` | 空间结构与容器骨架(Flex / Grid / Space / Separator / Sidebar / PageHeader …) |
|
|
46
|
+
| `navigation` | 导航 | `导航 · Navigation/` | 寻路与跳转(Breadcrumb / Pagination / DropdownMenu / Steps …) |
|
|
47
|
+
| `data-entry` | 数据录入 | `数据录入 · Data Entry/` | 表单输入控件(用户**写入**数据) |
|
|
48
|
+
| `data-display` | 数据展示 | `数据展示 · Data Display/` | 只读数据呈现(用户**读取**数据;含 Tabs / Accordion / Tooltip — 对齐 AntD) |
|
|
49
|
+
| `feedback` | 反馈 | `反馈 · Feedback/` | 状态/中断式反馈(Alert / Dialog / Drawer / Progress / Spinner …) |
|
|
50
|
+
| `deprecated` | 废弃 | `废弃 · Deprecated/` | 仅 Storybook 留档,**不通过 manifest 对外发布** |
|
|
51
|
+
|
|
52
|
+
### 完整组件归类(87 个)
|
|
53
|
+
|
|
54
|
+
- **general(3)**:button、icon、typography
|
|
55
|
+
- **layout(6)**:flex、grid、page-header、resizable、separator、sidebar
|
|
56
|
+
- **navigation(5)**:affix、breadcrumb、dropdown-menu、pagination、steps
|
|
57
|
+
- **data-entry(20)**:auto-complete、cascader、checkbox、color-picker、date-picker、field、filter-bar、form、input、input-number、label、radio-group、rate、select、slider、switch、time-picker、transfer、tree-select、upload
|
|
58
|
+
- **data-display(19)**:accordion、avatar、badge、calendar、card、carousel、collapsible、data-table、descriptions、empty、hover-card、item、statistic、table、tabs、tag、timeline、tooltip、tree
|
|
59
|
+
- **feedback(14)**[^1]:alert、alert-dialog、command、dialog、notification、popconfirm、popover、progress、result、sheet、skeleton、sonner、spinner、watermark
|
|
60
|
+
- **deprecated(19)**[^1][^2]:已有 — aspect-ratio、image、kbd;新增 — app、anchor、context-menu、float-button、menubar、navigation-menu、tour、toggle-group、toggle、segmented、native-select、mentions、input-otp、scroll-area、masonry、drawer
|
|
61
|
+
|
|
62
|
+
[^1]: 2026-06-02 补丁 — `command` 原拟归 deprecated("仅 Storybook 留档"),但事实上被 active 的 `select` / `auto-complete` 运行时强 import,不能不外发;同时作为 Combobox / Select / AutoComplete 同源下拉内核(ADR 0029)在架构上起底座作用。故从 deprecated 撤回,与 popover 同档归 `feedback`(反馈式弹层底座)。
|
|
63
|
+
[^2]: 2026-06-04 补丁 — `drawer` 从 feedback 移入 deprecated,因其是 Sheet 的纯别名 re-export,无独立实现;`space` 从 layout 移除,因其从未实现为独立 entry,Flex 已完整覆盖 antd Space 能力。feedback 15→14,layout 7→6,deprecated 18→19。
|
|
64
|
+
|
|
65
|
+
### 与 AntD 的偏离
|
|
66
|
+
|
|
67
|
+
仅一处务实取舍:`popover` 归 `feedback`(AntD 归 Data Display)。
|
|
68
|
+
理由:teamix-evo 项目里 popover 多与 popconfirm、tooltip、hover-card 同形使用,放一起便于研发认知。其他全部对齐。
|
|
69
|
+
|
|
70
|
+
### `deprecated` 工程含义("仅展示不外发")
|
|
71
|
+
|
|
72
|
+
| 链路 | 行为 |
|
|
73
|
+
| ------------------------------ | -------------------------------------------------------------------------------------------------------------------------------- |
|
|
74
|
+
| `packages/ui/manifest.json` | 19 个 deprecated 组件**移出** `entries`,归入新增 `deprecatedEntries` 字段(归档可查) |
|
|
75
|
+
| `teamix-evo ui add <name>` CLI | 默认拒绝安装(报错`Refusing to install deprecated...`);加 `--include-deprecated` 才放行 |
|
|
76
|
+
| `teamix-evo ui list` CLI | 默认隐藏;加 `--include-deprecated` 后 STATUS 列显示 `DEPRECATED` / `INST/DEPR` |
|
|
77
|
+
| MCP `list_components` | 默认过滤;传 `includeDeprecated: true` 或 `status: "deprecated"` 才返回(带 `archived: true` 标记) |
|
|
78
|
+
| MCP `find_components` | 默认不匹配归档项;传 `includeDeprecated: true` 后同时搜索 active + archived |
|
|
79
|
+
| MCP `get_component_meta` | 在 `entries` 找不到时自动回退到 `deprecatedEntries`,payload 带 `archived: true` |
|
|
80
|
+
| `*.stories.tsx` | 保留,Storybook 侧栏归"废弃 · Deprecated"分组,顶部强制加 banner: `> ⚠️ **已废弃** — 仅 Storybook 留档,不通过 manifest 对外发布。` |
|
|
81
|
+
| `*.meta.md` | `category: deprecated` 即代表废弃,不需要重复 `deprecated: true` 字段 |
|
|
82
|
+
| `package.json exports` / 构建 | 不调整(源码仍存在,内部仍可 import,只是外部 add 链路屏蔽) |
|
|
83
|
+
|
|
84
|
+
### Storybook 侧栏顺序
|
|
85
|
+
|
|
86
|
+
`.storybook/preview.ts` 的 `parameters.options.storySort.order` 固定:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
设计系统 · Design System → 类目以外的总览
|
|
90
|
+
通用 · General
|
|
91
|
+
布局 · Layout
|
|
92
|
+
导航 · Navigation
|
|
93
|
+
数据录入 · Data Entry
|
|
94
|
+
数据展示 · Data Display
|
|
95
|
+
反馈 · Feedback
|
|
96
|
+
废弃 · Deprecated
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
## Consequences
|
|
100
|
+
|
|
101
|
+
- **Positive**:
|
|
102
|
+
- 分类对齐业界标准,新人对照 AntD 文档即可定位组件
|
|
103
|
+
- `deprecated` 类正式化,留档与外发解耦
|
|
104
|
+
- manifest.json 的 `deprecatedEntries` 让 MCP 可查"曾经存在过哪些 entry"
|
|
105
|
+
- **Negative**:
|
|
106
|
+
- 一次性批量改 87 × 2 文件 + manifest + preview,需脚本驱动避免遗漏
|
|
107
|
+
- **Trade-off**:
|
|
108
|
+
- popover 偏离 AntD 归类,以团队习惯为准
|
|
109
|
+
|
|
110
|
+
## Source
|
|
111
|
+
|
|
112
|
+
UI 组件分类对齐讨论(2026-06-02);Ant Design 5.x 官方组件文档 categories;Material UI / Chakra UI / Radix UI 类目对照。
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
# 0029. Input 拆分 + 移除 prefix/suffix/addon 快捷 prop + AutoComplete 内核同源化
|
|
2
|
+
|
|
3
|
+
- **Status**: Superseded by [0036](./0036-ui-v2-shadcn-baseline-rebuild.md)
|
|
4
|
+
- **Date**: 2026-06-02
|
|
5
|
+
- **Region**: 0100–0999 协议与工具
|
|
6
|
+
|
|
7
|
+
## Context
|
|
8
|
+
|
|
9
|
+
历史包袱:`<Input>` 同时承载两套表达"前后缀"的 API:
|
|
10
|
+
|
|
11
|
+
1. **antd 风格快捷 prop**:`prefix` / `suffix` / `addonBefore` / `addonAfter`
|
|
12
|
+
2. **shadcn 2025-10 复合插槽**:`<InputGroup>` + `<InputGroupAddon>` + `<InputGroupInput>`
|
|
13
|
+
|
|
14
|
+
此外,Input / Textarea / InputGroup 三件套**合并到同一个 `input` entry**(单一 533 行 .tsx 文件,6 个导出),与 shadcn 2025-10 已拆三个独立组件的方向背离。
|
|
15
|
+
|
|
16
|
+
引发的问题:
|
|
17
|
+
|
|
18
|
+
- **API 重叠 → AI 与人类选择困难**:同一个"加搜索图标"的需求,可以写 `<Input prefix={<Search />} />`,也可以写 `<InputGroup><InputGroupAddon variant="icon">...`,文档要解释两套语义,纪律靠注释强行约束。
|
|
19
|
+
- **拷贝粒度过粗**:`teamix-evo ui add input` 强制业务连带拷贝 533 行文件,即使只用单行 Input。
|
|
20
|
+
- **隐性反向依赖**:Textarea 被埋在 `input/` 目录下,AutoComplete / Mentions 等下游通过 `from '@/components/input/input'` 引 Textarea 形成奇怪的导入路径。
|
|
21
|
+
- **跟 shadcn 上游不同步**:shadcn 2025-10 已把 `input` / `textarea` / `input-group` 拆为三个独立组件。我们合在一起,后续每次 sync upstream 都要手工 diff。
|
|
22
|
+
|
|
23
|
+
平行决策点:`AutoComplete` 当前用自实现 div + `<input>` + `<ul role="listbox">`,与 `Select` 的 `Popover + cmdk Command` 内核完全独立 — 同一种"输入触发候选下拉"的视觉/键盘/a11y 维护两份。
|
|
24
|
+
|
|
25
|
+
## Options Considered
|
|
26
|
+
|
|
27
|
+
### 关于 Input / Textarea / InputGroup 拆分
|
|
28
|
+
|
|
29
|
+
| 选项 | 优点 | 缺点 |
|
|
30
|
+
| -------------------------------------------------------------- | ------------------------------------------------------------------- | --------------------------------------- |
|
|
31
|
+
| **A. 现状(三合一 entry + 双 API 并存)** | 不动迁移成本 | API 重叠不解;粒度与 shadcn 上游持续偏离 |
|
|
32
|
+
| **B. 拆三个 entry,但 Input 双 API 并存** | 与 shadcn 拆分对齐;无 BREAKING | API 重叠未解,纪律仍靠注释 |
|
|
33
|
+
| **C. 拆三个 entry + 移除 Input 的 4 个快捷 prop**(本 ADR 决策) | 与 shadcn 拆分对齐;API 单一职责;消费侧"加图标用 InputGroup"路径唯一 | major BREAKING,业务侧需迁移 |
|
|
34
|
+
|
|
35
|
+
### 关于 AutoComplete vs Select 关系
|
|
36
|
+
|
|
37
|
+
| 选项 | 优点 | 缺点 |
|
|
38
|
+
| ------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
|
|
39
|
+
| **D1. 合并 AutoComplete 入 Select(MUI freeSolo 模式)** | 减少一个 entry | value 域 closed-list vs open-list 语义本质不同,合并后需新 prop 表达,反而模糊;Select 体量与依赖被强加给所有 AutoComplete 用户 |
|
|
40
|
+
| **D2. 保留独立组件 + 内核同源化(改 AutoComplete 用 Popover + Command)**(本 ADR 决策) | 语义独立(antd / Mantine / Chakra / shadcn 主流做法);下拉视觉/a11y/键盘只维护一份;无 BREAKING | 需重构 AutoComplete 内部实现 |
|
|
41
|
+
| D3. 现状(双内核独立) | 不动 | 同行为维护两份代码 |
|
|
42
|
+
|
|
43
|
+
## Decision
|
|
44
|
+
|
|
45
|
+
1. **拆分粒度对齐 shadcn 2025-10**:`Input` / `Textarea` / `InputGroup` 各自独立 `manifest entry`、独立 `<id>/` 目录、独立 stories / meta;CLI 三条命令独立可装(`teamix-evo ui add input` / `add textarea` / `add input-group`)。
|
|
46
|
+
2. **Input 移除 4 个 antd 风格快捷 prop**:`prefix` / `suffix` / `addonBefore` / `addonAfter` 不再支持。"加图标 / 单位 / 协议头 / 按钮" 唯一路径是 `InputGroup` 复合插槽。
|
|
47
|
+
3. **Input 保留 `clearable` / `showCount` / `size` / `error`**:这些不属于"前后缀"语义,是 Input 自身的逻辑能力,继续作为内建属性。
|
|
48
|
+
4. **AutoComplete 内核同源化**:保留 `AutoComplete` 与 `Select` 为独立组件(value 域语义不同 — open-list vs closed-list),但 AutoComplete 改用 `Popover + cmdk Command` 实现内部下拉,与 Select 共享下拉视觉 / 键盘 / a11y。组件外部 API 不变。
|
|
49
|
+
|
|
50
|
+
## Consequences
|
|
51
|
+
|
|
52
|
+
- **Positive**:
|
|
53
|
+
- 三个组件粒度与 shadcn 上游同步,后续 sync 不再 diff
|
|
54
|
+
- "加前后缀"路径唯一(InputGroup),AI 与人类不再纠结
|
|
55
|
+
- Input 文件从 533 行瘦身到 ~180 行,Textarea / InputGroup 独立可装
|
|
56
|
+
- 下拉行为(键盘 / hover / a11y / 主题)只维护一份
|
|
57
|
+
- **Negative**:
|
|
58
|
+
- 一次 major BREAKING:业务侧使用 `<Input prefix={...} />` / `addonBefore` 等需迁移到 `<InputGroup>` 复合写法
|
|
59
|
+
- 仓库内有 1 处下游(`SidebarInput` 在 sidebar.stories)+ 1 处自家 stories 需改写
|
|
60
|
+
- **Trade-off**:
|
|
61
|
+
- 为了"API 单一职责 + 与 shadcn 上游同步" 放弃了"零迁移成本"。changeset 标 major,migration 表写在 input-group.meta.md 与 changeset。
|
|
62
|
+
|
|
63
|
+
## Source
|
|
64
|
+
|
|
65
|
+
- 用户对话:`AutoComplete 和 Select 是否需要合并?Input.Group 是否要脱离 Input 单独为一个组件`(本轮拍板 A1 + B + C 组合)
|
|
66
|
+
- shadcn/ui 2025-10 的 Input / Textarea / InputGroup 拆分
|
|
67
|
+
- W3C ARIA APG Combobox pattern 的 closed-list vs open-list 子模式区分
|
|
68
|
+
- ADR 0028 复合 API 优于 prop 配置(同源思路)
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# 0030. uni-manager 变体 design + code skill 落地
|
|
2
|
+
|
|
3
|
+
- **Status**: Accepted
|
|
4
|
+
- **Date**: 2026-06-02
|
|
5
|
+
- **Region**: 0001–0099 工程哲学
|
|
6
|
+
- **Related ADR**: [0010](0010-design-default-and-variants.md), [0013](0013-skills-source-mirror.md), [0014](0014-ui-biz-ui-templates-tier.md), [0015](0015-skill-description-trigger-contract.md), [0017](0017-mcp-design-group.md), [0020](0020-design-to-tokens-skill-fusion.md)
|
|
7
|
+
|
|
8
|
+
## Context
|
|
9
|
+
|
|
10
|
+
opentrek 变体已经具备完整的 design + code skill(自包含、source-mirror 双 IDE 同步)。第二个变体 **uni-manager** 面向「专有云 / 混合云 / 多租户 / 多区域」中后台控制台场景,与 opentrek 在以下维度有刚性差异:
|
|
11
|
+
|
|
12
|
+
1. **品牌视觉**:uni-manager 使用 hybridcloud 锐利风圆角(rounded-md=2px / lg=4px / xl=8px / 2xl=12px),opentrek 是圆润风
|
|
13
|
+
2. **品牌主色**:uni-manager Brand Blue B50 `#0064C8`,opentrek 是中性灰黑
|
|
14
|
+
3. **组件层级**:uni-manager 多了第二层 `biz-ui/uni-manager` 业务实物组件(首批落地 `um-topbar`),opentrek 仅依赖 `@teamix-evo/ui`
|
|
15
|
+
4. **运行时上下文**:uni-manager 业务工程必带多租户 / 多区域 / 跨云上下文(X-Tenant-Id / X-Region-Id / X-Cloud-Provider header 链路)
|
|
16
|
+
5. **危险操作语义**:uni-manager 涉及云资源释放/销毁,必须强制走「输入资源完整名称才执行」的 `useDangerConfirm` 模式,opentrek 仅推荐 AlertDialog
|
|
17
|
+
6. **Brand 文档来源**:用户提供的 `Teamix-UI 规范文档/`(20 份 docx)需要被提炼为 brand / foundations / patterns 中的具体规范
|
|
18
|
+
|
|
19
|
+
不能不做:用户已经在使用 uni-manager 主题(tokens 包早有 `[data-theme='uni-manager']` 覆盖),但 skill 层缺位,AI 在 uni-manager 项目里只能套 opentrek 规则,导致圆角错、缺 um-topbar、危险操作弱、queryKey 不带 tenantId 等持续漂移。
|
|
20
|
+
|
|
21
|
+
## Decision
|
|
22
|
+
|
|
23
|
+
1. **新建两个变体 skill**:`teamix-evo-design-uni-manager`(16 文件)+ `teamix-evo-code-uni-manager`(9 文件),文件结构与 opentrek **严格 source-mirror**(ADR 0013),便于差异审计与上游变更同步
|
|
24
|
+
2. **uni-manager 不重新发明结构**:opentrek 的章节布局(philosophy / foundations / brand / patterns / boundaries / components / rules / generation-flow / flows / checklist / SKILL)整套保留,只在每个文件的特定章节增量补 uni-manager 专有约束
|
|
25
|
+
3. **三件一致性套件 UM1/UM2/UM3** 写入 `rules/boundaries.rules.json`,scope 标记 `uni-manager`,与 opentrek 38 条通用规则解耦:
|
|
26
|
+
- UM1:全局 topbar 必须使用 `biz-ui/uni-manager/um-topbar` 实物
|
|
27
|
+
- UM2:列表/详情页 PageHeader 与 um-topbar 视觉一致
|
|
28
|
+
- UM3:跨云资源必须显示 `CloudBadge`
|
|
29
|
+
4. **概念占位拼装表**:biz-ui/uni-manager 暂只实装 um-topbar;其余 7 个跨云/上下文/危险操作组件(CloudBadge / RegionBadge / ContextSwitcher / BulkActionBar / OperationLog / ResourceCard / DangerConfirmDialog)以「概念占位」形式列出,规定推荐落点(业务工程内 `src/components/cloud/` 等子目录),后续逐步抽到 biz-ui/uni-manager
|
|
30
|
+
5. **多租户 / 多区域上下文走 interceptor**:service 函数保持纯净,不显式拼 tenantId;`lib/http.ts` 的 request interceptor 集中注入 X-Tenant-Id / X-Region-Id / X-Cloud-Provider;`lib/active-context.ts` 作为 vanilla TS 单例,与 React Context 双向同步;react-query queryKey **必须**含 tenantId / regionId
|
|
31
|
+
6. **危险操作强制 useDangerConfirm**:定义完整 Hook + 配套 `DangerConfirmDialog` 组件,输入资源完整名称才能 enable 确认按钮;列入 code-uni-manager checklist 红线
|
|
32
|
+
7. **通用规则反哺 opentrek**:从 Teamix-UI 规范文档提炼出的非变体特有规则(Form 间距三档 4/20/32 + Input 5 档宽度 104/216/328/440/552)追加到 `teamix-evo-design-opentrek/foundations.md` §3.5 / §3.6
|
|
33
|
+
8. **manifest 注册**:`packages/skills/manifest.json` 升至 0.3.0,新增两条 skill 条目,description 严格遵循 ADR 0015 的 TRIGGER / SKIP / Coordinates with 三段式契约,TRIGGER 包含中文具名变体词(云管 / 跨云 / 多租户 / 多区域 / hybrid-cloud / 专有云)以保证路由准确
|
|
34
|
+
|
|
35
|
+
## Consequences
|
|
36
|
+
|
|
37
|
+
- **Positive**:
|
|
38
|
+
- uni-manager 变体获得与 opentrek 同等覆盖度的 AI 设计/编码护栏
|
|
39
|
+
- source-mirror 结构使两变体差异可逐文件 diff,规则升级可批量同步
|
|
40
|
+
- 概念占位拼装表机制让 biz-ui/uni-manager 抽包节奏可控(先在业务工程内落定型,再上抽)
|
|
41
|
+
- 多租户上下文链路在 skill 层固化,避免每个项目各自实现导致上下文与传输层耦合漂移
|
|
42
|
+
- 通用规则反哺让 opentrek 同步受益于 Teamix-UI 规范文档
|
|
43
|
+
- **Negative**:
|
|
44
|
+
- 两变体 25 个文件总量约 4500+ 行,后续 opentrek 主结构变更需要同步两遍(已在 source-mirror 工程纪律中接受)
|
|
45
|
+
- 概念占位拼装表是一种「未来约定」,若 biz-ui/uni-manager 抽包节奏延迟,业务工程内的本地实现会成为事实标准
|
|
46
|
+
- **Trade-off**:
|
|
47
|
+
- 选择「两变体独立目录 + source-mirror」而非「单 skill 多 variant 配置块」:放弃了配置紧凑性,换取 description trigger 路由清晰、文件粒度差异审计、单 skill 单职责
|
|
48
|
+
- 选择「在业务工程内放概念占位组件」而非「立即抽 biz-ui/uni-manager 包」:放弃了首日复用,换取设计稳定后再抽包的低返工成本
|
|
49
|
+
|
|
50
|
+
## Source
|
|
51
|
+
|
|
52
|
+
- 用户原始诉求(多轮):基于 Teamix-UI 规范文档 + opentrek 镜像生成 uni-manager skill;biz-ui/uni-manager 当前仅 um-topbar 实物
|
|
53
|
+
- 用户授权(本次会话):"按照最合理的、最流行的、最适合 ai 使用 vibecoding 的 skill 方案编写就好"
|
|
54
|
+
- Teamix-UI 规范文档(20 份 docx,已解析归类)→ brand / foundations / patterns 增量
|
|
55
|
+
- ADR 0013 source-mirror、ADR 0015 description-trigger、ADR 0014 三层组件架构
|
|
56
|
+
- 执行计划:`.cache/plans/design-skill-uni-manager-uplift_100d06bc.md`
|