@changfenhuang/dsh-genui 0.9.10-preview.1 → 0.11.0
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/CHANGELOG.md +45 -3
- package/README.md +1 -1
- package/README.zh-CN.md +9 -1
- package/SKILL.md +132 -6
- package/lib/assets/echarts-core.js +43 -0
- package/lib/assets/{echarts.js → echarts-full.js} +1 -1
- package/lib/assets/mermaid.js +1 -1
- package/lib/client.js +261 -3
- package/lib/index.js +240 -77
- package/lib/types/client/EChartNode.d.ts +9 -0
- package/lib/types/client/GenuiBlock.d.ts +3 -4
- package/lib/types/client/asset-echarts-core.d.ts +1 -0
- package/lib/types/client/asset-echarts.d.ts +3 -2
- package/lib/types/client/asset-loader.d.ts +4 -2
- package/lib/types/client/blocks/advanced.d.ts +0 -3
- package/lib/types/client/blocks/basic.d.ts +0 -5
- package/lib/types/client/blocks/charts.d.ts +23 -12
- package/lib/types/client/blocks/diagram/theme.d.ts +3 -1
- package/lib/types/client/blocks/state.d.ts +9 -3
- package/lib/types/client/echarts-lazy.d.ts +4 -1
- package/lib/types/client/embed.d.ts +8 -0
- package/lib/types/client/genui-runtime/schema.d.ts +11 -1
- package/lib/types/client/inline.d.ts +5 -0
- package/lib/types/client/spec.d.ts +76 -6
- package/lib/types/plugin/index.d.ts +2 -1
- package/package.json +66 -4
- package/src/client/EChartNode.tsx +236 -21
- package/src/client/GenuiBlock.module.css +906 -145
- package/src/client/GenuiBlock.tsx +53 -37
- package/src/client/PlotBlock.module.css +17 -1
- package/src/client/PlotBlock.tsx +35 -2
- package/src/client/asset-echarts-core.ts +39 -0
- package/src/client/asset-echarts.ts +4 -3
- package/src/client/asset-loader.ts +12 -3
- package/src/client/blocks/advanced.tsx +75 -31
- package/src/client/blocks/basic.tsx +3 -2
- package/src/client/blocks/charts.tsx +761 -145
- package/src/client/blocks/checkbox.tsx +2 -1
- package/src/client/blocks/diagram/index.tsx +33 -24
- package/src/client/blocks/diagram/layout.ts +4 -1
- package/src/client/blocks/diagram/theme.ts +22 -3
- package/src/client/blocks/forms.tsx +15 -14
- package/src/client/blocks/image.tsx +2 -1
- package/src/client/blocks/render-node.tsx +261 -20
- package/src/client/blocks/state.ts +9 -3
- package/src/client/dom-fence.tsx +79 -16
- package/src/client/echarts-lazy.ts +11 -2
- package/src/client/embed.ts +9 -0
- package/src/client/fence-render.tsx +6 -5
- package/src/client/gallery.ts +84 -2
- package/src/client/genui-runtime/schema.ts +45 -11
- package/src/client/guard.ts +170 -26
- package/src/client/index.tsx +14 -3
- package/src/client/inline.ts +65 -0
- package/src/client/mermaid-core.ts +42 -5
- package/src/client/spec.ts +79 -6
- package/src/plugin/index.ts +37 -47
- package/src/plugin/tool.ts +7 -3
- package/tsdown.config.ts +2 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,10 +1,52 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
-
## [
|
|
3
|
+
## [0.11.0] - 2026-09-15
|
|
4
|
+
|
|
5
|
+
### 新增
|
|
6
|
+
- 数学公式支持 `$...$`、`$$...$$`、`\(...\)`、`\[...\]`,覆盖文本、表格、标题、步骤、时间线、选项与显示标签,以及强调中的公式、矩阵、分段和多行推导(#162、#168、#169)。使用 KaTeX 渲染,保留交互原值;不提供完整 LaTeX 文档或任意宏包编译,代码、输入原值、原生下拉选项与图形引擎内部标签仍遵循各自格式。
|
|
7
|
+
- 提供应用嵌入入口、图形资源入口与技能文档导出;支持宿主传入初始状态、接收交互状态和配置资源地址,修复状态保存回调变化引起的重复回传(#167)。
|
|
8
|
+
|
|
9
|
+
### 修复
|
|
10
|
+
- 图示随宿主浅深主题即时更新配色,修正背景、高度与图例截断,移除水印序号(#152、#157)。
|
|
11
|
+
- 浅色卡片恢复明亮卡面,保留描边与阴影层次(#159、#166)。
|
|
12
|
+
- 被丢弃组件的校验结果保留具体字段错误;补齐字段速查中的类型与缺失字段(#163、#164、#168)。
|
|
13
|
+
- 围栏识别忽略语言标签两端空白,拒绝疑似消息容器时记录结构原因并保留原文,便于定位未渲染问题(#158、#168)。
|
|
14
|
+
- 常驻提示与技能明确要求正文和界面文案跟随用户语言(#165、#168)。
|
|
15
|
+
- 按宿主插件规范导出插件名称(#155)。
|
|
16
|
+
- 保留 ECharts 中有意留空的合法配置,同时继续移除不安全配置(#167)。
|
|
17
|
+
|
|
18
|
+
### 验证与体积
|
|
19
|
+
- 覆盖 Node.js 22/24、DSH 0.1.2-rc.1 与 0.1.5-rc.2,以及 Windows 打包检查;真实安装包验证公式、浅深主题和窄宽布局。
|
|
20
|
+
- 数学渲染使浏览器脚本增加约 260 KB(未压缩)。
|
|
21
|
+
|
|
22
|
+
## [0.10.0] - 2026-09-11
|
|
4
23
|
|
|
5
|
-
|
|
24
|
+
- CI 与发布包验收固定到 DSH 0.1.5-rc.2;保留 0.1.2-rc.1 支持下限验证。
|
|
25
|
+
- 入场动画完成后不再随宿主重新插入节点重放;恢复已有交互状态的组件直接展示,保留新组件的首次入场动画(#101)。
|
|
26
|
+
- 补充五个可渲染场景范例与短回答反例;新增行内富文本、图表按需加载、表格明细,以及图表缩放与筛选交互修复。
|
|
6
27
|
|
|
7
|
-
|
|
28
|
+
### 新增
|
|
29
|
+
- **表格列类型**:`table.types` 支持 `index` / `spark` / `ring` / `bar` / `badge` / `delta` / `num` / `group`;`table.total` 追加合计行(数值列求和);`group` 首列渲染为**可折叠的分组标题**(chevron + 组内行数),组内行缩进并带引导线,分组内排序不会打乱结构。
|
|
30
|
+
- **图表形态**:`chart` 新增 `horizontal`(横向柱)与 `stacked`(series 堆叠);`line` 支持 `series` 多序列;横向/堆叠/折线/环形图全部支持**即时自绘 tooltip**(堆叠段显示该段数值 + 合计)。
|
|
31
|
+
- **指标增强**:`stat.spark` 微趋势线(面积 + 末点,贴卡片下沿);`stat.size:"hero"` 超大数字;数值与单位自动拆分(单位半字号弱化)。
|
|
32
|
+
- **进度组件**:`progress.variant:"ring"` 环形进度;`progress.target` 目标刻度。
|
|
33
|
+
- **卡片语气**:`card.tone`(info / success / warning / danger)。
|
|
34
|
+
- **流式骨架**:围栏正文仍在流式且尚无完整组件时显示骨架,首个组件解析后换成真组件,settle 仍不可解析则归还原始代码块。
|
|
35
|
+
- **采纳度审计**:`scripts/genui-usage-audit.mjs`,扫本地会话日志量化 `dsh-ui` 围栏采纳率与组件分布。
|
|
36
|
+
|
|
37
|
+
### 变更
|
|
38
|
+
- 设计系统 v3–v10:字号下限 12.5px、标题层级拉开、CJK 行高与字距、表格数据化(斑马纹 / 大写表头 / 首列加粗 / 带符号自动着色);指标卡以数字为主体,单位半字号。
|
|
39
|
+
- 常驻系统提示加入硬触发规则与关键组件字段速查,SKILL.md 同步;`echart` 引导改为场景化(≤8 点用 `chart`,多序列/交互/大数据用 `echart`)。
|
|
40
|
+
- 移除早期版本引入的强调色竖条/色块,层级改由字号、留白与结构表达。
|
|
41
|
+
|
|
42
|
+
### 修复
|
|
43
|
+
- **分组柱状图无法渲染**:`data: []` + `series` 的合法写法被图表契约整份拒绝,导致含此类图的围栏完全不渲染。
|
|
44
|
+
- **图表契约**:`line` + `series` 由「拒绝」改为「支持」;`donut` 仍为单序列。
|
|
45
|
+
- **可视化回归脚本**:`scripts/e2e-visual.mts` 在 rc7 之后失效(宿主机路径、缺 `--profile`/`--no-open`、401 token、漏 `await`、空 profile 遮罩拦截指针事件),并新增流式骨架与 tooltip 的真实浏览器断言。
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
### 修复
|
|
49
|
+
- **插件热重载生命周期(issue #121)**:assets 路由与模型工具改由可选服务的依赖 fiber 管理;插件或服务卸载时自动注销,服务重新提供时自动注册,避免热重载残留路由导致新 fiber 启动失败。
|
|
8
50
|
|
|
9
51
|
## [0.9.9] - 2026-09-09
|
|
10
52
|
|
package/README.md
CHANGED
|
@@ -93,7 +93,7 @@ The repository ships both renderer channels, the host plugin, and the built brow
|
|
|
93
93
|
|
|
94
94
|
Prerequisites — all required:
|
|
95
95
|
|
|
96
|
-
1. **dsh `^0.1.2-rc.1 || ^0.1.5-alpha.1`** (dsh-genui 0.
|
|
96
|
+
1. **dsh `^0.1.2-rc.1 || ^0.1.5-alpha.1`** (dsh-genui 0.11.0 is verified on DSH 0.1.5-rc.2 and the 0.1.2-rc.1 minimum; users on DSH `<=0.1.1-rc.x` should use dsh-genui `0.9.8`)
|
|
97
97
|
2. **`pnpm` on your PATH**: the `dsh plugin` command depends on it. If missing: `corepack enable` (or `npm i -g pnpm`), then **open a new terminal** and confirm `pnpm -v` prints a version
|
|
98
98
|
|
|
99
99
|
Install and activate in DSH (one command, all dependencies included):
|
package/README.zh-CN.md
CHANGED
|
@@ -93,7 +93,7 @@ https://github.com/user-attachments/assets/f5db33ec-7471-4d4a-a85b-79c9962ab4ef
|
|
|
93
93
|
|
|
94
94
|
前置条件,缺一不可:
|
|
95
95
|
|
|
96
|
-
1. **dsh `^0.1.2-rc.1 || ^0.1.5-alpha.1`**(dsh-genui 0.
|
|
96
|
+
1. **dsh `^0.1.2-rc.1 || ^0.1.5-alpha.1`**(dsh-genui 0.11.0 已验证 DSH 0.1.5-rc.2,并保留 0.1.2-rc.1 下限验证;使用 DSH `<=0.1.1-rc.x` 的用户请使用 dsh-genui `0.9.8`)
|
|
97
97
|
2. **`pnpm` 在 PATH 上**:`dsh plugin` 命令依赖它。没有就 `corepack enable`(或 `npm i -g pnpm`),然后**新开一个终端**,确认 `pnpm -v` 有输出
|
|
98
98
|
|
|
99
99
|
安装并在 DSH 中激活(一行命令,自动带上全部依赖):
|
|
@@ -230,6 +230,14 @@ dsh plugin --profile web add link:$PWD
|
|
|
230
230
|
|
|
231
231
|
## 🧑💻 开发
|
|
232
232
|
|
|
233
|
+
### 嵌入其他应用
|
|
234
|
+
|
|
235
|
+
支持 CSS Modules 和 TypeScript 的浏览器构建器可以从 `@changfenhuang/dsh-genui/embed` 导入 `GenuiBlock`、`GenuiActionContext`、`ErrorBoundary` 和 `processGenuiSpec`,复用同一份组件、样式与规格校验,无需加载 DSH 的插件入口。
|
|
236
|
+
|
|
237
|
+
嵌入宿主通过 `initialState` / `onStateChange` 接管持久化,使用稳定的 `stateKey` 区分界面,通过 `GenuiActionContext.Provider` 接收动作。改变 `stateKey` 会开始新的交互生命周期;同一界面的后续刷新保留输入。设置 `onStateChange` 后不读写浏览器的交互状态存储。
|
|
238
|
+
|
|
239
|
+
调用 `setGenuiAssetBase` 设置本地引擎目录;从公开的 `@changfenhuang/dsh-genui/assets/mermaid`、`assets/three`、`assets/echarts-core`、`assets/echarts` 构建对应脚本。模型指引从 `@changfenhuang/dsh-genui/skill` 读取。宿主只补自己的交付通道和设计变量;渲染器仍使用本包与 `@deepseek-ai/dsh-client-ui-primitives` 的组件。构建时提供 React、CSS Modules、KaTeX 字体及所用引擎依赖。
|
|
240
|
+
|
|
233
241
|
```sh
|
|
234
242
|
pnpm install
|
|
235
243
|
pnpm run check # 类型检查 + 全量测试 + 构建
|
package/SKILL.md
CHANGED
|
@@ -5,12 +5,16 @@ description: "Render structured interactive UI inline in your reply via the dsh-
|
|
|
5
5
|
|
|
6
6
|
# GenUI — 生成式 UI 输出规范
|
|
7
7
|
|
|
8
|
+
**Language:** Match the user's requested language (otherwise the language of their message) in both surrounding prose and all user-visible UI text: titles, labels, content, options, and explanations. Chinese examples below illustrate the schema only; do not switch the conversation to Chinese after loading this skill. Keep JSON keys, component types, IDs, and actions unchanged. An English request gets English prose and UI text; a Chinese request gets Chinese prose and UI text.
|
|
9
|
+
|
|
8
10
|
你可以**在回答正文中间**输出可交互 UI 组件:写一个 `dsh-ui` 围栏(fenced block with language tag `dsh-ui`),内含 JSON 规格,渲染器会把这一整块画成真实组件,文字照常穿插在前后。组件**就是回答的一部分**,不是工具调用。
|
|
9
11
|
|
|
10
12
|
```dsh-ui
|
|
11
13
|
{"title":"可选标题","gap":14,"items":[...]}
|
|
12
14
|
```
|
|
13
15
|
|
|
16
|
+
公式:`$...$` / `\(...\)` 为行内公式,`$$...$$` / `\[...\]` 为独立公式;支持矩阵、分段函数、多行对齐推导,以及加粗/高亮内的公式。正文、列表、键值、表头/单元格、卡片/步骤/时间线/标签页标题、题目与说明、按钮与表单标签、指标、媒体说明和图表外层标题共用此能力。JSON 字符串中的反斜杠必须双写,如 `"content": "\\(\\frac{a}{b}\\)"`。代码源码、输入值/占位符、原生下拉选项和图表引擎内部绘图文本仍遵循各自的原生格式,不解析富文本。数学语法以 KaTeX 为准,不执行 HTML、外部资源或脚本;不支持 LaTeX 文档编译、加载任意宏包。
|
|
17
|
+
|
|
14
18
|
## 组件词汇(只允许这些 type)
|
|
15
19
|
|
|
16
20
|
布局:`text` `row` `col` `grid` `card` `divider` `spacer`
|
|
@@ -22,19 +26,22 @@ description: "Render structured interactive UI inline in your reply via the dsh-
|
|
|
22
26
|
- text: `{"type":"text","size":"h1|h2|h3|body|muted|caption","content":"...","center":true?}`
|
|
23
27
|
- row / col: `{"type":"row"|"col","items":[...],"wrap":true?,"spacer":true?,"gap":n?}`
|
|
24
28
|
- grid: `{"type":"grid","cols":n,"items":[...]}`
|
|
25
|
-
-
|
|
29
|
+
- hero: `{"type":"hero","title":"...","subtitle":"...","value":"99.96%","label":"可用率","delta":"+0.02%","spark":[...],"tone":"accent|success|warning|danger"}` — **封面块**:eyebrow + 超大数字(52px,带入场计数)+ 标题 + 副标题 + tone 渐变底色。**一条回答最多用一个**,放在最前面当视觉锚点
|
|
30
|
+
- span: 任意节点都可加 `"span":2`(grid 子节点占几列)——bento 排版的唯一原语:一张 `span:2` 宽卡配一张窄卡,比一列方块堆下去好看得多
|
|
31
|
+
- card: `{"type":"card","title":"...","items":[...]}`;`"accent":"#f59e0b"` 指定强调色(边框 + 标题 + 极淡底色)
|
|
32
|
+
- palette: `chart` / `echart` 都支持 `"palette":["#ff8800","#3ecf8e"]` 覆盖分类色板(默认跟随宿主主题)。**只有语义上需要指定颜色时才写**(成本=红、收益=绿),否则跟随主题更稳;`"tone":"info|success|warning|danger"` 给卡片底色(用于结论卡/风险卡)
|
|
26
33
|
- divider: `{"type":"divider"}`; spacer: `{"type":"spacer"}`
|
|
27
34
|
|
|
28
35
|
### 展示
|
|
29
|
-
- stat: `{"type":"stat","label":"...","value":"...","delta":"+12.4%|-3%"}`(`-` 开头自动红、`+`
|
|
36
|
+
- stat: `{"type":"stat","label":"...","value":"...","delta":"+12.4%|-3%"}`(`-` 开头自动红、`+` 绿);可选 `"spark":[3,5,4,8,6]` 画一条微趋势线(2–60 个有限数值);`"size":"hero"` 渲染超大数字(一条回答最多用一次,作为视觉锚点)
|
|
30
37
|
- badge: `{"type":"badge","label":"...","tone":"success|warn|danger|accent","icon":"emoji?"}`
|
|
31
|
-
- progress: `{"type":"progress","label":"...","value":0-100,"valueLabel":"70%"}`
|
|
38
|
+
- progress: `{"type":"progress","label":"...","value":0-100,"valueLabel":"70%"}`;`"variant":"ring"` 画环形进度,`"target":70` 在轨道上标出目标刻度
|
|
32
39
|
- avatar: `{"type":"avatar","name":"...","color":"#hex?"}`
|
|
33
40
|
- image: `{"type":"image","src":"/mmx-files/result.png","alt":"结果图片"}` — 展示浏览器可访问的 http(s) 或同源相对图片地址;懒加载;不支持 `file:`/`data:` 等本地或主动协议
|
|
34
41
|
- audio: `{"type":"audio","src":"/mmx-files/result.mp3","alt":"语音结果","loop":true?}` — 原生控制条;用户主动播放,不自动播放;仅 http(s) 或同源相对地址
|
|
35
42
|
- video: `{"type":"video","src":"/mmx-files/result.mp4","alt":"视频结果","poster":"/mmx-files/poster.jpg"?,"loop":true?,"muted":true?,"aspectRatio":"16:9|4:3|1:1|9:16"?}` — 原生播放/音量/全屏控制;不自动播放
|
|
36
43
|
- list: `{"type":"list","items":["..."] 或 [{"title":"...","desc":"..."}] 或嵌套节点(如 {"type":"badge","label":"TS"})}` — 行内可嵌节点(计入节点预算)
|
|
37
|
-
- table: `{"type":"table","columns":["..."],"rows":[["...","..."]]}` — 表头点击本地排序(升/降/还原,零往返);数值感知:千分位(`1,234`)、`k/m/b
|
|
44
|
+
- table: `{"type":"table","columns":["..."],"rows":[["...","..."]],"types":["text|num|delta|bar|badge"]?,"details":[[...]]?,"total":true?}` — 表头点击本地排序(升/降/还原,零往返);数值感知:千分位(`1,234`)、`k/m/b`、`万/亿`、`%`、货币符号都能按真实数值比较,纯数值列自动右对齐;**带符号单元格自动着色**(`+12.4%` 绿、`-3` 红,无需额外字段);`types` 可按列指定 `bar`(0-100 内联进度条)、`ring`(0-100 小环)、`spark`(单元格写 `"3,5,4,8"` 画微趋势线)、`badge`(胶囊标签)、`delta`(强制涨跌色)、`num`(强制右对齐)、`index`(行号)、`group`(首列当分组标题:该行只有第一格有内容时渲染成跨列小标题);`"total":true` 追加合计行(数值列自动求和);**`"export":true`**:表格上方出现「复制 Markdown / 复制 CSV」两个小按钮(纯本地剪贴板,不发请求);**`"filter":"输入框id"`**:把表格和某个 input/select 绑定,读者输入即时过滤(`filterColumn` 可限定列)——数据多时**默认就该配一个**;**`"sortField":"下拉id"`** 用下拉的值(列名)排序;**`"details"` 与 rows 同序**,第 i 项是该行展开后的内容(可放任意组件,`null` = 该行不可展开)——首列出现 chevron,点开在整行下方展开明细,适合「主表 + 明细」
|
|
38
45
|
- keyvalue: `{"type":"keyvalue","pairs":[{"key":"...","value":"..."}]}`
|
|
39
46
|
- timeline: `{"type":"timeline","items":[{"title":"...","desc":"...","time":"..."}]}`
|
|
40
47
|
- file-tree: `{"type":"file-tree","items":[{"name":"...","type":"file|dir","children":[...]?}]}` — 目录行可点击折叠/展开(本地,零往返)
|
|
@@ -46,9 +53,11 @@ description: "Render structured interactive UI inline in your reply via the dsh-
|
|
|
46
53
|
- steps: `{"type":"steps","current":n,"steps":[{"title":"...","desc":"..."}]}`
|
|
47
54
|
|
|
48
55
|
### 图表
|
|
49
|
-
- chart: `{"type":"chart","kind":"bars|line|donut","data":[{"label":"...","value":n,"color":"#hex?"}],"series":[...]?}` — bars 默认;line 趋势;donut
|
|
56
|
+
- chart: `{"type":"chart","kind":"bars|line|donut","data":[{"label":"...","value":n,"color":"#hex?"}],"series":[{"label":"...","data":[...]}]?,"horizontal":true?}` — bars 默认;line 趋势;donut 占比;**series:bars 是分组柱,line 是多序列折线**;**`horizontal:true` 画横向柱**(排行/长标签首选);**`stacked:true` 把 series 堆叠**(构成/占比随时间);堆叠段够高时数值直接印在段内,鼠标悬停任意柱/段/点/扇区都会弹出即时 tooltip(堆叠显示该段数值 + 合计)。v3 渲染:宽度自适应、Y 轴 1/2/5 刻度、单序列负值在零线以下真实绘制、line 带面积渐变与抽稀 X 标签、donut 图例显示数值与百分比。**≤8 个点的快速对比用 chart;多序列、需要缩放/交互或数据量大时用 echart**
|
|
50
57
|
- plot: `{"type":"plot","series":[{"expr":"a*sin(b*x)","label":"...","color":"#hex?","params":[{"name":"a","value":1,"min":0,"max":5,"animateTo":3,"durationMs":4000,"loop":true},{"name":"b","value":1,"min":0.5,"max":5}]}],"xMin":-6.28,"xMax":6.28,"title":"..."}` — SVG 函数图;**series 可带 `"kind":"line|area|scatter"`**(缺省 line;area 填色到基线;scatter 散点);**params 渲染成实时滑块**(拖动即时重绘,**y 轴锁定**=只变曲线不变数轴);**animateTo 参数会显示播放按钮**(自动动画演示);SVG 可拖拽平移、滚轮缩放;表达式支持 sin/cos/tan/asin/acos/atan/sqrt/cbrt/exp/log/ln/abs/floor/ceil/round/min/max/pow,常量 pi/e/tau,变量 x(其他字母=参数)
|
|
51
|
-
- echart: `{"type":"echart","title":"...","height":300,"preset":"bar|line|area|pie|scatter","data":[{"label":"...","value":n}],"series":[...]?}` — **ECharts 全功能图表**,视觉效果远超 `chart`(渐变、tooltip、动画、图例交互);**preset 模式**:用和 `chart` 一样的 `data`/`series` 格式,自动构建主题化的 ECharts 配置(颜色跟随宿主主题);**
|
|
58
|
+
- echart: `{"type":"echart","title":"...","height":300,"preset":"bar|line|area|pie|scatter","data":[{"label":"...","value":n}],"series":[...]?}` — **ECharts 全功能图表**,视觉效果远超 `chart`(渐变、tooltip、动画、图例交互);**preset 模式**:用和 `chart` 一样的 `data`/`series` 格式,自动构建主题化的 ECharts 配置(颜色跟随宿主主题);**preset 一览**(只写 preset + data/series/links,主题自动跟随):
|
|
59
|
+
`bar` · `line` · `area` · `pie` · `scatter` · **`radar`**(每 series 一个多边形,指标取第一条 series 的 label)· **`gauge`**(每个 datum 一个仪表,适合单 KPI)· **`funnel`**(漏斗/转化)· **`treemap`**(体积/层级占比)· **`sankey`**(流向,用 `links:[{from,to,value}]`)· **`graph`**(关系图,`links` 驱动,节点大小随连接数)· **`heatmap`**(`series` 当行、第一条 series 的 label 当列)· **`bigline`**(长序列 + 内置缩放)
|
|
60
|
+
**full option 模式**:传 `"option":{...}` 直接写 ECharts 原生配置(支持 dataZoom/visualMap/radar/gauge/heatmap 等所有图表类型),option 中的函数会被过滤(只接受数据)。选择原则:**chart 轻量(无额外下载)适合 ≤8 点的快速对比;echart 视觉更丰富(渐变、tooltip、图例交互、dataZoom),但会按需下载约 1MB 引擎,多序列/大屏/交互场景优先**
|
|
52
61
|
|
|
53
62
|
### 交互
|
|
54
63
|
**本地优先(v2.6)**:UI 自己能做的状态变化——判卷、判题、重置、展开、选中——一律本地即时完成,**零模型往返**。action 只用于必须模型参与的事(生成新内容、执行工具、下一步建议)。**交互组件必须带 action:不带 action 的按钮渲染为禁用态,用户点不了;带 action 的按钮点击后有「已触发」本地反馈。**
|
|
@@ -81,12 +90,21 @@ description: "Render structured interactive UI inline in your reply via the dsh-
|
|
|
81
90
|
|
|
82
91
|
**判断口诀**:这段内容换成结构化组件,会不会比纯文字更好扫、更好懂、更好操作?会 → 就用,**不需要等用户开口要 UI**。
|
|
83
92
|
|
|
93
|
+
**硬触发(出现就至少出一个围栏,不要退回纯文字段落)**:
|
|
94
|
+
- ≥3 条并列要点 → `list`;≥2 组数字对比 → `table`;指标/进度/状态 → `stat`/`progress`/`badge`
|
|
95
|
+
- 步骤/时间线 → `steps`/`timeline`/`mermaid`;架构/流程 → `diagram`/`mermaid`;风险/结论 → `callout`;代码/改动 → `code`/`diff`/`json`
|
|
96
|
+
- 趋势/占比 → `chart`(≤8 点)或 `echart`(多序列/要交互/数据量大)
|
|
97
|
+
- 收尾自检:回答超过约 10 行时确认至少有一个围栏;同一份信息不要既写文字又重复出组件;纯问答不套 UI。
|
|
98
|
+
|
|
84
99
|
| 你要呈现的内容 | 用这些组件 |
|
|
85
100
|
|---|---|
|
|
86
101
|
| 关键结论 / 要点罗列(≥2 条) | `list`、`keyvalue`、`callout` |
|
|
87
102
|
| 重点强调 / 警告 / 注意事项 | `callout`(info/success/warning/error)、`badge`、`stat` |
|
|
88
103
|
| 数据对比 / 趋势 / 占比 | `chart`(bars/line/donut)、`echart`(ECharts 全功能)、`table` |
|
|
89
104
|
| 关键指标数字 / 进度状态 | `stat`、`progress`、`badge` |
|
|
105
|
+
| 回答的视觉锚点(第一个组件) | `hero`(封面块,一条回答最多一个) |
|
|
106
|
+
| 想排版不呆板 | `grid` + 子节点 `span`(bento:宽窄混排) |
|
|
107
|
+
| 数据多、需要读者自己找 | `input`(id)+ `table`/`chart`/`list` 的 `filter` 绑定 |
|
|
90
108
|
| 流程 / 步骤 / 阶段 / 时间线 | `steps`、`timeline`、`mermaid`(flowchart/sequence/gantt) |
|
|
91
109
|
| 架构 / 系统拓扑 / 数据流 / 品牌图 | `diagram`(编辑级,27 种类型;自动布局需求才用 `mermaid`) |
|
|
92
110
|
| 目录 / 文件结构 / 层级关系 | `file-tree`、`mermaid`、`accordion` |
|
|
@@ -102,6 +120,114 @@ description: "Render structured interactive UI inline in your reply via the dsh-
|
|
|
102
120
|
|
|
103
121
|
**别用的情况**:一句话能说清的事、纯闲聊、用户明确说不要 UI、以及"为了炫技硬塞"——组件服务内容,不是内容服务组件。
|
|
104
122
|
|
|
123
|
+
## 行内富文本(文字类回答的底座)
|
|
124
|
+
|
|
125
|
+
`text.content`、`list` 项、`table` 文本列、`keyvalue` 值、`callout` 标题与正文里可以直接写四种行内标记——**重点留在句子里,不必为一个词单起一个组件**:
|
|
126
|
+
|
|
127
|
+
| 写法 | 渲染 |
|
|
128
|
+
|---|---|
|
|
129
|
+
| `` `code` `` | 行内代码胶囊 |
|
|
130
|
+
| `**加粗**` | 强调(不换行、不成块) |
|
|
131
|
+
| `==高亮==` | 极淡底色标记 |
|
|
132
|
+
| `[文字](https://…)` | 行内链接(http/https/mailto;非法目标退化为纯文字) |
|
|
133
|
+
|
|
134
|
+
不嵌套、不解析 HTML(每个标记生成 React 元素,不走 innerHTML);标记没闭合时原样显示。数值列 / badge / spark 单元格不解析(数字没什么可强调的)。
|
|
135
|
+
|
|
136
|
+
## 回答级版式:默认无卡,焦点唯一
|
|
137
|
+
|
|
138
|
+
**规则来自设计规范,不是口味**(`design` skill 的 `references/design-reference.md`):
|
|
139
|
+
「通用圆角矩形卡片当默认容器 = 模板思维,默认无卡;只有内容类型确实需要时才加卡片处理」,
|
|
140
|
+
「如果替换内容不需要改布局,那就是模板,重做」。
|
|
141
|
+
|
|
142
|
+
### 三条判据(不设组件数量上限)
|
|
143
|
+
|
|
144
|
+
1. **必要性**:这个组件承载的信息,用文字表达会明显更差吗?数字对比、趋势、空间关系、代码/数据原文才算过关,否则删掉。
|
|
145
|
+
2. **焦点唯一**:一条回答只有一个视觉焦点(最大那张图或那组数字);其余组件的视觉权重必须明显更低,靠尺寸/位置/色彩强度拉开,**不是靠数组件个数**。
|
|
146
|
+
3. **不重复**:同一批数据不做两种表达(表格与图表二选一)。
|
|
147
|
+
|
|
148
|
+
### 卡片(`card`)只在两种场合用
|
|
149
|
+
|
|
150
|
+
- 需要**并排**的 `grid` 子项(没有边界就分不清内容归属);
|
|
151
|
+
- 承载**数据对象**:表格、图、keyvalue、指标组。
|
|
152
|
+
|
|
153
|
+
单段文字、单个列表、已经自带边界的表格/图表,**不要包卡**。用 `h3` 标题 + 正文 + 间距代替。
|
|
154
|
+
|
|
155
|
+
### 层级靠字,不靠框
|
|
156
|
+
|
|
157
|
+
- 卡片标题 16px / 字重 650 / 句首大小写(**不是** 12.5px 全大写小标签);
|
|
158
|
+
- 12.5px 全大写只用于 eyebrow(如 hero 上方那一行);
|
|
159
|
+
- 大字号带负字距(≥32px 约 -0.022em,20–28px 约 -0.012em),数字列 `tabular-nums`;
|
|
160
|
+
- CJK 正文行高 1.7,长段落行宽 ≤68ch;
|
|
161
|
+
- 表面对比遵循规范:浅色相邻表面明度差 ≥4%,或阴影 ≥ `0 1px 3px rgba(0,0,0,0.10)`;深色靠半透明白叠加(卡片约 4%,抬升面 8%),投影在深色几乎无效。
|
|
162
|
+
|
|
163
|
+
### 不要
|
|
164
|
+
|
|
165
|
+
- 装饰性编号(①②③):该分点用 `list`,该分节用标题;
|
|
166
|
+
- 同一套骨架每条回答复用(标题栏 → 卡片网格 → 表格 → callout);
|
|
167
|
+
- 为了"显得丰富"堆组件:读者找不到重点就是失败。
|
|
168
|
+
|
|
169
|
+
### 怎么验证没模板化
|
|
170
|
+
|
|
171
|
+
`node scripts/genui-usage-audit.mjs` 输出「版式多样性」:不同版式签名数、最常见签名占比、归一化熵(越接近 1 越多样)、每回答 card 数分布。熵明显下降或 card 数不降反升,就说明规则没生效。
|
|
172
|
+
|
|
173
|
+
## 范例:示范「判断」,不要照抄组件序列
|
|
174
|
+
|
|
175
|
+
每个范例后面都跟着**什么时候不要这样**。组件多是好事——只要每个都在承载不同信息、并且有焦点和层次;真正的毛病是重复表达、以及把纯文字段落包进卡片。
|
|
176
|
+
|
|
177
|
+
### 1. 状态汇报(多点 + 有构图)
|
|
178
|
+
|
|
179
|
+
```json dsh-ui
|
|
180
|
+
{"items":[{"type":"grid","cols":4,"items":[{"type":"stat","label":"已合并","value":"26","delta":"#123–#148"},{"type":"stat","label":"未合并","value":"0"},{"type":"stat","label":"测试","value":"556","delta":"全绿"},{"type":"stat","label":"组件","value":"45"}]},{"type":"table","columns":["层","状态","生效方式"],"types":["text","badge","text"],"rows":[["组件与样式","已生效","每次从磁盘读"],["系统提示","待重启","Node 半只在启动时加载"]]},{"type":"callout","tone":"info","title":"结论","content":"改动都上了,但 **效果还没证据**。"}]}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
不要这样:把同一句话既写进正文又放进卡片;也不要为每条信息配一张卡(4 个 stat 排一行就够)。
|
|
184
|
+
|
|
185
|
+
### 2. 解释/教学(文字为主,一个点睛组件)
|
|
186
|
+
|
|
187
|
+
```json dsh-ui
|
|
188
|
+
{"items":[{"type":"text","size":"body","content":"根因不是记性,是规则自相矛盾:一条说「≥3 条并列 → 出 list」,另一条说「组件只在 ==文字表达会更差== 时出现」。"},{"type":"list","items":[{"title":"先修规则","desc":"把闸门限定为「不要包卡片」,而不是「少用组件」"},{"title":"再看数据","desc":"如果漏发率不降,才考虑兜底手段"}]},{"type":"callout","tone":"warning","title":"别急着加监控","content":"事后提醒来得太晚,还会逼人在不需要组件的地方硬塞。"}]}
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
不要这样:每段都配一个组件;把一句话拆成好几个 text 节点(用行内标记就够了)。
|
|
192
|
+
|
|
193
|
+
### 3. 对比选型
|
|
194
|
+
|
|
195
|
+
```json dsh-ui
|
|
196
|
+
{"items":[{"type":"table","columns":["方案","代价","判断"],"types":["text","text","badge"],"rows":[["改规则","改一行字","推荐"],["加看门狗","事后才提醒,会变噪音","不推荐"]]},{"type":"callout","tone":"success","title":"选前者","content":"成本一行,且解决根因。"}]}
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
不要这样:表格里放同一批数据后又画一张图。
|
|
200
|
+
|
|
201
|
+
反例(这条会被围栏校验直接拒绝,所以别抄):
|
|
202
|
+
|
|
203
|
+
```json dsh-ui-bad
|
|
204
|
+
{"items":[{"type":"chart","kind":"donut","data":[{"label":"A","value":1}],"series":[{"label":"B","data":[{"label":"B","value":2}]}]}]}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
为什么拒:`series` 只对 `bars`/`line` 有效;环形图给了 `series` 属于契约冲突,围栏会**静默降级为代码块**。
|
|
208
|
+
|
|
209
|
+
### 4. 排查诊断(顺序即叙事)
|
|
210
|
+
|
|
211
|
+
```json dsh-ui
|
|
212
|
+
{"items":[{"type":"steps","current":1,"steps":[{"title":"复现","desc":"滚动页面时光标压在图上"},{"title":"定位","desc":"onWheel 无条件 preventDefault"},{"title":"修复","desc":"改为仅 ⌘/Ctrl + 滚轮缩放"}]},{"type":"diff","diffs":[{"path":"PlotBlock.tsx","oldText":"e.preventDefault()","newText":"if (!e.metaKey && !e.ctrlKey) return"}]},{"type":"callout","tone":"info","title":"另外补了退路","content":"视图偏离时显示当前区间并提供 ==回到初始区间==。"}]}
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
不要这样:把"复现/定位/修复"写成三个卡片并列(那是流程,用 steps)。
|
|
216
|
+
|
|
217
|
+
### 5. 数据结论(一个主图 + 明细)
|
|
218
|
+
|
|
219
|
+
```json dsh-ui
|
|
220
|
+
{"items":[{"type":"chart","kind":"line","data":[],"series":[{"label":"本周","data":[{"label":"一","value":8},{"label":"二","value":12},{"label":"三","value":9}]}]},{"type":"table","columns":["时段","量","环比"],"types":["text","num","delta"],"rows":[["周一","8","-4%"],["周二","12","+50%"]]}]}
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
不要这样:图与表用同一粒度表达同一批数据(图看趋势、表看明细才不重复)。
|
|
224
|
+
|
|
225
|
+
### 6. 短回答:正确地不套组件
|
|
226
|
+
|
|
227
|
+
> 这个改动我先不做了——它要动宿主的输入组件,而你说了不碰宿主。
|
|
228
|
+
|
|
229
|
+
不要这样:一句话的结论配 stat + 表格 + callout。**没有内容就不发组件,这是对的,不算漏发。**
|
|
230
|
+
|
|
105
231
|
## 使用规则
|
|
106
232
|
|
|
107
233
|
1. **围栏放哪,组件就出现在哪** —— 文字在前后自然流动,不要用工具、不要解释"这是一个围栏"。**围栏一闭合就立即渲染**(不等整条回答结束),所以可以边写文字边出组件
|