@dsh-workbench/core 0.2.11 → 0.2.13
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/client.js +519 -2781
- package/dist/client/client.body.js +519 -2781
- package/dist/client/index.js +519 -2781
- package/dist/host/index.js +78 -78
- package/dist/types/app/client.d.ts +27 -58
- package/dist/types/app/layouts/__tests__/kit-preview-nav.test.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/board-mock.d.ts +1 -1
- package/dist/types/app/layouts/rightbar/board-plan.d.ts +2 -14
- package/dist/types/app/layouts/rightbar/board-shape.d.ts +14 -0
- package/dist/types/app/layouts/rightbar/kit-preview-frame.d.ts +4 -0
- package/dist/types/app/layouts/rightbar/kit-preview-hash.d.ts +1 -0
- package/dist/types/app/layouts/rightbar/kit-preview-rows.d.ts +1 -0
- package/dist/types/dev/MockStrip.d.ts +15 -0
- package/dist/types/dev/surface-types.d.ts +53 -0
- package/dist/types/dev/surface.d.ts +2 -0
- package/dist/types/dev/surface.stub.d.ts +2 -0
- package/package.json +2 -2
- package/skills/workbench-module-diy/DATASOURCE.md +1 -1
- package/skills/workbench-module-diy/KIT.md +55 -5
- package/skills/workbench-module-diy/PANEL.md +2 -2
- package/skills/workbench-module-diy/REVIEW.md +1 -1
|
@@ -82,7 +82,7 @@ h(Field, { label: t('myunit.mode'), hint: t('myunit.modeHint') },
|
|
|
82
82
|
```
|
|
83
83
|
|
|
84
84
|
**`TextField`** —— 单行输入(`invalid` 标红;其余是原生 input 的 props)。
|
|
85
|
-
**`ChoiceGroup`** —— 单选 / 多选(`multi` 区分;`value` 或 `values` + `onChange`;选项 `{ value, label,
|
|
85
|
+
**`ChoiceGroup`** —— 单选 / 多选(`multi` 区分;`value` 或 `values` + `onChange`;选项 `{ value, label, description? }`;`disabled` 在整组上)。
|
|
86
86
|
**`SelectField`** —— 下拉:默认是**常规下拉框**(跟 `TextField` 一套),无边框那种给 `variant: 'ghost'`;
|
|
87
87
|
搜索、分组、禁用项、加载态、空态、页脚都是它的 prop。
|
|
88
88
|
**`SaveBar`** —— 设置面底下那条"取消 / 保存"(`busy` / `disabled` / `labels` / `onCancel` / `onSave`)。
|
|
@@ -91,7 +91,57 @@ h(Field, { label: t('myunit.mode'), hint: t('myunit.modeHint') },
|
|
|
91
91
|
kit 有上面这几件;手写的会拿到浏览器默认样式,而且**判据会红**(`check:style`)。
|
|
92
92
|
`<textarea>` 例外(dsh 与 kit 都没有多行输入)——真要用就直接写,其余形态别开这个口子。
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
控件怎么排成一行(标签位置、错误态、尺寸)见 §5。
|
|
95
|
+
|
|
96
|
+
## 5 表单这一层:面 → 行 → 控件
|
|
97
|
+
|
|
98
|
+
表单三层:**面**(`SettingsSection` / `SaveBar`)→ **行**(`FormRows` + `FormRow`)→
|
|
99
|
+
**控件**(`TextField` / `SelectField` / `ChoiceGroup`)。**一行一个字段**,行这一层只有一个出处。
|
|
100
|
+
|
|
101
|
+
```tsx
|
|
102
|
+
h(FormRows, null,
|
|
103
|
+
h(FormRow, { label: t('myunit.mode'), hint: t('myunit.modeHint') },
|
|
104
|
+
h(SelectField, { value, options, onChange: setMode })),
|
|
105
|
+
h(FormRow, { label: t('myunit.env'), problem: problemOfEnv },
|
|
106
|
+
h(ChoiceGroup, { label: t('myunit.env'), name: 'env', options, value: env, onChange: setEnv })))
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
- **标签归 `FormRow`**(`label`):默认标签在左,`layout: 'stacked'` 才是上下堆叠(等于原来的 `Field`)。
|
|
110
|
+
**控件只给数据与语义 prop**,不写外观类名(§7 第 1 条)。进了 `FormRow` 就别再给控件自己的
|
|
111
|
+
`label` / `hint`(`SelectField` 那两件是没 `FormRow` 时的兜底,重复给会多一个标签、还退回上下堆叠)。
|
|
112
|
+
- **`hint` 与 `problem` 二选一**:给了 `problem` 就不画 `hint` —— 同一格不叠两段话,有错先显示错。
|
|
113
|
+
|
|
114
|
+
**错误态**:位置与长相由 `FormRow.problem` + 控件的 `invalid` 定(`SelectField` / `TextField` 同形,
|
|
115
|
+
`ChoiceGroup` 见它自己的档)。**校验逻辑留在模块**:只写"算错误"的纯函数与文案
|
|
116
|
+
(例:cmdb 的 `CmdbFormProblem` 那类),**别指望外壳给校验引擎**(不做 `rules` / `validate`、
|
|
117
|
+
不做联动、不持有值)。提交失败后调 `kit.lib.revealFirstProblem(root)`(`root` = 表单容器)——
|
|
118
|
+
把第一处错误带进视口、并聚焦它里面的控件。
|
|
119
|
+
|
|
120
|
+
**选择类用哪件**:候选多 / 要搜索 / 要分组 / 名单可能读不到 ⇒ `SelectField`(`search` 默认开、
|
|
121
|
+
`emptyText`、`loading` + `loadingText`、`fallback`、`variant: 'boxed' | 'ghost'`);
|
|
122
|
+
候选少、要一眼看全 / 多选 ⇒ `ChoiceGroup`(`multi`、`variant`、`loading` + `loadingText`、
|
|
123
|
+
`emptyText`、`options[].description`)。两件的 `loading` / `loadingText` / `emptyText` / `variant`
|
|
124
|
+
是一个意思;**loading 那颗一律是 `Spinner`**(`h(Spinner, { size: 14 })`)—— **别自己写转圈**。
|
|
125
|
+
|
|
126
|
+
**尺寸口径**:字段控件默认 **28**(dsh 紧凑档),**别自己调高**;行距**只有一档**、归 `FormRow(s)`,
|
|
127
|
+
模块里不该出现管行距的 `gap` / `margin`(横向的、卡片/清单网格的不算)。
|
|
128
|
+
|
|
129
|
+
**反例(别这么写)**:
|
|
130
|
+
|
|
131
|
+
```tsx
|
|
132
|
+
h('span', { className: styles.label }, t('myunit.mode')) // ← 紧邻控件的手写标签行:check:style 红
|
|
133
|
+
h('div', { className: styles.form }, …) // ← .form { gap: 8px }:自己管行距也红
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
`<span className={styles.label}>` 紧邻控件、或给表单容器自己写 `gap` —— 这正是 `check:style` 那条
|
|
137
|
+
棘轮(F1 手写行 / F2 自己管行距)盯的东西;`FORM_ROW_EXEMPT` 是**等外壳发版后要清空的历史账**
|
|
138
|
+
("迁一处删一行"),**不是"可以继续这么写"的许可**。
|
|
139
|
+
|
|
140
|
+
**时点**:这一层随外壳**发版**后模块才能用 —— 模块的 `peerDependencies` 下限得先有它
|
|
141
|
+
(`check:kit` 拿 peer 下限那份外壳比,不抬必红);迁移步骤见
|
|
142
|
+
[ADR-0052](../../../../docs/adr/0052-the-form-row-is-one-component.md) §10。
|
|
143
|
+
|
|
144
|
+
## 6 别的
|
|
95
145
|
|
|
96
146
|
- **`Link`** —— **唯一**的外链写法:`h(Link, { href, children })`。自带新窗口 + `rel="noopener noreferrer"`
|
|
97
147
|
+ 正文色 + hover 下划线 + 那颗小箭头。**别去掉箭头、别在文案里自带 `→`、别手写 `<a>`**(判据红)。
|
|
@@ -99,11 +149,11 @@ kit 有上面这几件;手写的会拿到浏览器默认样式,而且**判
|
|
|
99
149
|
- **`Stack`** —— 竖排 + 统一间距(懒得分组时的默认容器)。
|
|
100
150
|
- **`BlockerState`** —— 阻断屏:要登录 / 没权限 / 能力没装好那一类(`blocker` / `t` / `onRetry` / `onOpenMarket`)。
|
|
101
151
|
- **`Tip`** —— Tooltip:图标钮与只有图的地方**必须**有它(或 `aria-label`)。
|
|
102
|
-
-
|
|
152
|
+
- **别给模块带夹具**:2026-10-16 起模板 / `init` 文案 / 这份指引都不带评审夹具了(`?wbMock=1` 那套、`useFixturePick` / `MockStrip` / `mockNote` 都从模板里删了)。夹具是模块作者负担里最不值的那一份 —— 而**你自己那份 `plugin.test.ts` 就能把五态各喂一遍**,门禁从来只问"空数据画不画得出"(`check:cards`)。外壳自己那套 `?wbMock=1` 夹具是给**外壳的卡片**用的,模块不必跟(机制仍在,谁想要仍然可以用,但**不是你要做的事**)。
|
|
103
153
|
- **图标** —— `IconPanelScreen`(面板/卡片那类)、`IconModuleMark`(我们的模块类型标)、
|
|
104
154
|
`IconNpm` / `IconOpencli`(包类型);其余图形一律从 dsh 的 `Icon*Regular` 拿,**别自己画图标**。
|
|
105
155
|
|
|
106
|
-
##
|
|
156
|
+
## 7 三条纪律
|
|
107
157
|
|
|
108
158
|
1. **调用点只给数据与语义**:`h(Card, { title, refreshing, onRefresh }, …)`。别从外面塞外观类名
|
|
109
159
|
—— 只有布局槽例外(通栏、外边距、网格位置)。
|
|
@@ -114,7 +164,7 @@ kit 有上面这几件;手写的会拿到浏览器默认样式,而且**判
|
|
|
114
164
|
3. **自己写 CSS 只写布局**(flex / grid / gap / 对齐)。要一个新的"长得像控件"的东西时,
|
|
115
165
|
先问一句:kit 里是不是已经有了?
|
|
116
166
|
|
|
117
|
-
##
|
|
167
|
+
## 8 kit 里没有、但你确定要标准控件
|
|
118
168
|
|
|
119
169
|
见 [PANEL.md](PANEL.md) §9:可以引 dsh 的客户端原语,但**只在浏览器侧**、并在
|
|
120
170
|
`package.json` 的 `dsh.client.external` 里声明 `@deepseek-ai/dsh-client-ui-primitives`
|
|
@@ -164,7 +164,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
|
|
|
164
164
|
- **平台没给的那一格就不占位**(不留孤零零的字段名、不留空的一行)。
|
|
165
165
|
- **读不到就说读不到**,并说清为什么(例:手上这份能力太旧);**绝不显示 0**。
|
|
166
166
|
- 有确定答案就不打扰他(能按默认读出来就别弹设置面)。
|
|
167
|
-
-
|
|
167
|
+
- 真机上造不出来的状态也要**在设计上**画出来(照这一格写清)—— 但**不必为它写夹具**:2026-10-16 起模板与指引都不带评审夹具,模块自己的 `plugin.test.ts` 把五态各喂一遍就够(门禁只问"空数据画不画得出")。
|
|
168
168
|
|
|
169
169
|
### 7.1 图例就是把屏幕画成 ASCII
|
|
170
170
|
|
|
@@ -187,7 +187,7 @@ agent 那一侧也要能通过模块自己的能力读到同一份偏好。
|
|
|
187
187
|
- **用真字**:图里的文案用界面上真实那句(例「没有指派给你的缺陷。」),别写"一句空态文案"。
|
|
188
188
|
- **别拿图标代替画面**:给状态起个名字、配个 `⛔` 这类符号,用户还是分不清;一眼能认的是**形状**(整卡换掉 vs 多一行)与**位置**(行首的点、行尾的两颗)。
|
|
189
189
|
- **画不成的才写词**:动作、agent 的下一步、时间性的"不变 / 自己变",写成词并说清意思。
|
|
190
|
-
-
|
|
190
|
+
- **真机上造不出来的状态**:沟通时照样画(画的是设计意图);实现时**要让它能用真实输入走到**(换个空目录、换个坏路径、先不选),而不是给它写夹具 —— 2026-10-16 起模板与指引都不带评审夹具,模块自己的 `plugin.test.ts` 把五态各喂一遍就够。
|
|
191
191
|
|
|
192
192
|
## 8 范例(真实产出的形状)
|
|
193
193
|
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
| `standalone` | "只有工作台源码在场才编得过" ⇒ 发布出去就散架 | `build 在外壳源码不在场时失败` / `typecheck 在外壳源码不在场时失败` | 别引用工作台源码;`tsconfig` 里 `paths` 的值必须是**相对路径**(`"./src/*"`,不是 `"src/*"`) |
|
|
16
16
|
| `markers` | 内网域名 / 企业内部名泄进要公开发布的包 | `命中内网 npm 源` / `命中内网域名` | 那些值不该写进包里;要配就落到模块自己的配置面,或走用户自己声明的来源 |
|
|
17
17
|
| `alias` | `@/` 伸进工作台源码 ⇒ 装的人手上没有那份源码 | `…指向外壳源码` | `@/` 只许指自己的 `src/`;跨包的东西走包名 |
|
|
18
|
-
| `style` | 模块定义 `.wb-*` 去覆盖外壳的类(全局类名,两份规则按注入顺序打架) | `定义了外壳前缀 wb-* 的 CSS 规则` / `借用了契约里没有的类` | 自己的样式走 `*.module.css`(类名**不带** `wb-` 前缀,构建时按文件路径哈希);外壳给的类只能用契约里列出的那些,要借就写 `:global(.wb-…)` |
|
|
18
|
+
| `style` | 模块定义 `.wb-*` 去覆盖外壳的类(全局类名,两份规则按注入顺序打架) | `定义了外壳前缀 wb-* 的 CSS 规则` / `借用了契约里没有的类` | 自己的样式走 `*.module.css`(类名**不带** `wb-` 前缀,构建时按文件路径哈希);外壳给的类只能用契约里列出的那些,要借就写 `:global(.wb-…)`;被 `样式归属` 判红的手写「标签+控件」行或模块自己管的行距 ⇒ 改用 `FormRow(s)`([KIT.md](KIT.md) §5) |
|
|
19
19
|
|
|
20
20
|
## 什么时候该怀疑门禁本身
|
|
21
21
|
|