From c9665501aa611f28aef762680f66350f827a51a2 Mon Sep 17 00:00:00 2001 From: HIsheR Date: Tue, 27 Oct 2026 00:43:13 +0800 Subject: [PATCH] =?UTF-8?q?iter(g312):=20=E8=A1=A8=E6=A0=BC=E7=A9=BA?= =?UTF-8?q?=E7=8A=B6=E6=80=81=E8=A1=A5=E6=93=8D=E4=BD=9C=E6=8F=92=E6=A7=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .ua/backlog.json | 9 +++++++++ .ua/index.json | 10 ++++++++-- llms-full.txt | 4 +++- packages/skin/ui/src/dataTable.ts | 2 +- packages/skin/ui/src/tableEmpty.ts | 5 +++-- packages/skin/ui/src/types.ts | 1 + packages/skin/ui/ua.manifest.json | 8 +++++++- 7 files changed, 32 insertions(+), 7 deletions(-) diff --git a/.ua/backlog.json b/.ua/backlog.json index ea650bf..3f85a65 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -3194,6 +3194,15 @@ "motivation": ".ua-skeleton-text 写死 height: 12px,而表格单元格里的正文行盒是「13px 字号 × 1.55 行高 ≈ 20px」——骨架行比真实行矮 8px,五行就差 40px,dataTable 从骨架切到数据时整表高度突跳,比没有加载态更晃眼。", "acceptance": "① .ua-skeleton-text 的高度改成 calc(正文字号 × 正文档行高),与真实文字行盒等高;② 同时消掉这处 12px 字面值;③ skeleton 手把手补一条说明为什么按行盒算;④ audit:visual / audit:motion 全绿,npm run check 通过。", "notes": "" + }, + { + "id": "g312", + "domain": "tune", + "status": "open", + "title": "表格空状态补操作出口:真没数据时只能干看着", + "motivation": "emptyRow 只区分「筛掉了」与「真没数据」,但两种情况都只给文案——列表本来就空时没有「新建」这类下一步,用户只能自己找工具栏;而筛选没结果时又该引导清条件,两种语义不该共用一个按钮位。", + "acceptance": "① DataTableProps 新增 emptyAction 插槽,只在「真没数据」时渲染在占位文案右侧;② 有筛选词时该位置仍是「清除筛选」,两者互斥;③ manifest 参数表与手把手、类型注释同步;④ npm run check 全绿。", + "notes": "" } ] } diff --git a/.ua/index.json b/.ua/index.json index ed11258..56f287a 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T16:41:28.122Z", + "generatedAt": "2026-10-26T16:42:26.169Z", "repoRoot": ".", "packages": [ { @@ -2083,6 +2083,11 @@ "d": "无数据时的空状态文案;有筛选词时仍显示「没有符合「x」的行」并给一键清除(两种语义不混用)", "df": "暂无数据" }, + { + "n": "emptyAction", + "t": "unknown", + "d": "真没数据时占位区右侧的操作(如「新建」按钮);有筛选词时这一位置换成「清除筛选」,两者互斥" + }, { "n": "selectable", "t": "boolean", @@ -2152,7 +2157,8 @@ "需要导出时开 exportable:按钮导的是筛选+排序后的全量行,与当前页无关,单元格按 format 输出", "整行可点(进详情、选中一行做后续操作)传 onRowClick:行会变成可聚焦项,Enter / 空格与点击等价;不传时行不进 Tab 序列,纯展示表不会被读屏当成按钮", "需要让用户自己调列时开 columnToggle:工具栏多一个「列」按钮,弹层勾选即刻重绘表头与单元格(隐藏列不占 colspan,空状态与骨架行同步收窄)", - "想记住用户偏好就传 hiddenColumns 信号:面板勾选实时写回,外部赋值即整表跟随;隐藏筛选列后筛选条件仍然生效,属预期而非失效" + "想记住用户偏好就传 hiddenColumns 信号:面板勾选实时写回,外部赋值即整表跟随;隐藏筛选列后筛选条件仍然生效,属预期而非失效", + "表里本来就空(不是筛掉的)时传 emptyAction 给个「新建」之类的出口:它只在「真没数据」时出现,一旦有筛选词就换成「清除筛选」——先让用户清条件,而不是急着让他新建" ] }, { diff --git a/llms-full.txt b/llms-full.txt index d819581..6364477 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T16:41:28.122Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T16:42:26.169Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -1026,6 +1026,7 @@ const name = signal(''); const f = form({ onSubmit: submit }, [formItem({ label: - pageSize(默认 5):number —— 每页行数;缺省 5 - pageSizes(默认 [5, 10, 20]):number[] —— 分页条「每页条数」候选档;缺省 [5, 10, 20],当前 pageSize 不在候选里会自动补进去 - emptyText(默认 暂无数据):string —— 无数据时的空状态文案;有筛选词时仍显示「没有符合「x」的行」并给一键清除(两种语义不混用) +- emptyAction:unknown —— 真没数据时占位区右侧的操作(如「新建」按钮);有筛选词时这一位置换成「清除筛选」,两者互斥 - selectable(默认 false):boolean —— 启用行选择列:全选三态(含半选)、行 checkbox、已选计数;缺省 false - page:Signal —— 受控页码信号:与内核分页双向同步,传同一个信号给独立 pagination 组件即可联动 - loading:boolean | Signal —— 加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy @@ -1063,6 +1064,7 @@ dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓 17. 整行可点(进详情、选中一行做后续操作)传 onRowClick:行会变成可聚焦项,Enter / 空格与点击等价;不传时行不进 Tab 序列,纯展示表不会被读屏当成按钮 18. 需要让用户自己调列时开 columnToggle:工具栏多一个「列」按钮,弹层勾选即刻重绘表头与单元格(隐藏列不占 colspan,空状态与骨架行同步收窄) 19. 想记住用户偏好就传 hiddenColumns 信号:面板勾选实时写回,外部赋值即整表跟随;隐藏筛选列后筛选条件仍然生效,属预期而非失效 +20. 表里本来就空(不是筛掉的)时传 emptyAction 给个「新建」之类的出口:它只在「真没数据」时出现,一旦有筛选词就换成「清除筛选」——先让用户清条件,而不是急着让他新建 现场演示:apps/docs/demo.html#sec-table diff --git a/packages/skin/ui/src/dataTable.ts b/packages/skin/ui/src/dataTable.ts index 3823d80..5ed751a 100644 --- a/packages/skin/ui/src/dataTable.ts +++ b/packages/skin/ui/src/dataTable.ts @@ -124,7 +124,7 @@ export function dataTable(props: DataTableProps): H if (busy()) return skeletonRows(); // 加载态优先:不看数据,避免闪出旧行 const sel = state().selection; // 读入依赖:选择变化即整表重绘(行数 = pageSize,代价可控) const rows = visible().rows; - if (!rows.length) return [emptyRow(span(), keyword, () => table.dispatch({ type: 'setFilter', key: filterKey, value: '' }), props.emptyText)]; // 空状态:筛选词与内核筛选一起清 + if (!rows.length) return [emptyRow(span(), keyword, () => table.dispatch({ type: 'setFilter', key: filterKey, value: '' }), props.emptyText, props.emptyAction)]; // 空状态:筛选词与内核筛选一起清;真没数据时给调用方的操作插槽 return rows.map((row, i) => { const key = visible().keys[i]; const selected = sel.includes(key); diff --git a/packages/skin/ui/src/tableEmpty.ts b/packages/skin/ui/src/tableEmpty.ts index ba4e193..4045d0b 100644 --- a/packages/skin/ui/src/tableEmpty.ts +++ b/packages/skin/ui/src/tableEmpty.ts @@ -3,7 +3,8 @@ import type { Signal } from '@ui-arch/frame'; import { button } from './button.js'; /*** 表格空状态行:有筛选词说明是筛掉的并给一键清除,没有筛选词就是真没数据;两种语义不该混成一句话 ***/ -export function emptyRow(colspan: number, keyword: Signal, onClear: () => void, emptyText = '暂无数据'): HTMLElement { +export function emptyRow(colspan: number, keyword: Signal, onClear: () => void, emptyText = '暂无数据', action?: unknown): HTMLElement { + // action 插槽只在「真没数据」时出现:筛选没结果时该引导清条件,不是引导新建 const q = keyword().trim(); // 读信号:筛选词变化时整表重绘会带上新文案 return h( 'tr', @@ -12,7 +13,7 @@ export function emptyRow(colspan: number, keyword: Signal, onClear: () = 'td', { colspan }, h('span', { class: 'ua-empty-tip' }, q ? `没有符合「${q}」的行` : emptyText), // 无筛选词时用调用方文案,缺省「暂无数据」 - q ? button({ label: '清除筛选', variant: 'ghost', onClick: () => { keyword(''); onClear(); } }) : null, // 清空信号与内核筛选 + q ? button({ label: '清除筛选', variant: 'ghost', onClick: () => { keyword(''); onClear(); } }) : action ?? null, // 清筛选与「新建」互斥:同一时刻只给一个下一步 ), ); } diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index 56d66c3..852a574 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -67,6 +67,7 @@ export interface DataTableProps { pageSize?: number; // 每页行数;缺省 5 pageSizes?: number[]; // 分页条「每页条数」候选;缺省 [5, 10, 20],当前 pageSize 不在候选里会自动补进去 emptyText?: string; // 无数据时的空状态文案(有筛选词时仍显示「没有符合「x」的行」);缺省「暂无数据」 + emptyAction?: unknown; // 真没数据时占位区右侧的操作(如「新建」按钮);有筛选词时换成「清除筛选」,两者互斥 selectable?: boolean; // 是否启用行选择列(含全选三态与已选计数);缺省 false page?: Signal; // 受控页码信号:与内核分页双向同步,可接独立 pagination 组件联动 loading?: boolean | Signal; // 加载态:为真时数据行换成骨架行,筛选与翻页禁用 diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index a926e35..f0849c0 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -1954,6 +1954,11 @@ "d": "无数据时的空状态文案;有筛选词时仍显示「没有符合「x」的行」并给一键清除(两种语义不混用)", "df": "暂无数据" }, + { + "n": "emptyAction", + "t": "unknown", + "d": "真没数据时占位区右侧的操作(如「新建」按钮);有筛选词时这一位置换成「清除筛选」,两者互斥" + }, { "n": "selectable", "t": "boolean", @@ -2023,7 +2028,8 @@ "需要导出时开 exportable:按钮导的是筛选+排序后的全量行,与当前页无关,单元格按 format 输出", "整行可点(进详情、选中一行做后续操作)传 onRowClick:行会变成可聚焦项,Enter / 空格与点击等价;不传时行不进 Tab 序列,纯展示表不会被读屏当成按钮", "需要让用户自己调列时开 columnToggle:工具栏多一个「列」按钮,弹层勾选即刻重绘表头与单元格(隐藏列不占 colspan,空状态与骨架行同步收窄)", - "想记住用户偏好就传 hiddenColumns 信号:面板勾选实时写回,外部赋值即整表跟随;隐藏筛选列后筛选条件仍然生效,属预期而非失效" + "想记住用户偏好就传 hiddenColumns 信号:面板勾选实时写回,外部赋值即整表跟随;隐藏筛选列后筛选条件仍然生效,属预期而非失效", + "表里本来就空(不是筛掉的)时传 emptyAction 给个「新建」之类的出口:它只在「真没数据」时出现,一旦有筛选词就换成「清除筛选」——先让用户清条件,而不是急着让他新建" ] }, {