iter: d19 dataTable 选中态受控

This commit is contained in:
ui-arch-bot
2026-10-23 17:01:46 +08:00
parent 4012923ff1
commit 4555542811
8 changed files with 55 additions and 5 deletions
+8
View File
@@ -200,6 +200,14 @@
"acceptance": "checkSkinCss():skin-dom 类型包里所有 .css 出现 #hex 字面量即报错并指出文件行号;5 处 #fff 改为 var(--ua-color-bg)(信号色底上的反色,暗色自动翻转);负向测试(临时加 .ua-tmp{color:#fff})能拦下,移除后回归全绿;AGENTS.md 门禁说明同步;npm run check 全绿",
"status": "done",
"notes": "rgba(...) 未禁:仅用于阴影与遮罩透明度叠加,不承载品牌色,禁掉会逼出更难读的写法(已在函数注释写明边界);实现上先随 python 写文件把正则转义搞坏两次,改用编辑工具直写并做负向验证确认门禁真实生效"
},
{
"id": "d19",
"title": "dataTable 选中态受控(selected 信号)",
"motivation": "选中集只在内核里,外部拿不到也无法预设,批量操作/清空选择只能靠内部工具栏;与 page 受控桥接形成对称能力",
"acceptance": "DataTableProps 新增 selected?: Signal<RowKey[]>,与内核选择双向同步(内容比较避免来回派发,外部数组拷贝保护内核);demo 首表传 picked 信号,展示已选计数与「清空选择」按钮;manifest/文档/llms-full.txt 同步;npm run check 全绿",
"status": "done",
"notes": "复用 page 桥接的同一套思路:两个 effect 各管一向,sameKeys 内容比较收敛;内部写回拷贝 [...internal],防外部改动内核数组;demo 需 import type { RowKey } 才能对齐 Signal 的逆变"
}
]
}
+8 -2
View File
@@ -1,6 +1,6 @@
{
"$schema": "ui-arch-registry-index/0.1",
"generatedAt": "2026-10-23T09:00:48.440Z",
"generatedAt": "2026-10-23T09:01:45.831Z",
"repoRoot": ".",
"packages": [
{
@@ -1253,6 +1253,11 @@
"n": "loading",
"t": "boolean | Signal<boolean>",
"d": "加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy"
},
{
"n": "selected",
"t": "Signal<RowKey[]>",
"d": "受控选中行信号:与内核选择双向同步(内容比较,不来回派发),供批量操作读取/改写"
}
],
"example": "dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓名', sortable: true }], pageSize: 5 })",
@@ -1266,7 +1271,8 @@
"工具栏输入框即筛选,输入即时过滤并回第 1 页;无匹配时显示空状态行",
"表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供",
"数据在途时传 loading(布尔或信号):表格体换成骨架行、筛选与翻页禁用,返回后置回 false 即恢复",
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用"
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用",
"需要批量操作时传 selected 信号:内部勾选实时写回,外部置空或赋值即同步整表(跨页保留,按 rowKey 存)"
]
}
]
+1
View File
@@ -23,3 +23,4 @@
{"time": "2026-10-23T16:58:51+08:00", "id": "d16", "result": "done", "summary": "dataTable 消费内核列宽 width:colgroup 固定像素 / flex 自适应,选择列 44px;demo 三列演示宽档;manifest/llms 同步,check 全绿"}
{"time": "2026-10-23T16:59:46+08:00", "id": "d17", "result": "done", "summary": "表单错误态打通包裹式控件:focusout/change 取代 blur + aria-invalid + .ua-invalid 后代选择器覆盖 select/radio/slider;demo 加必填 select;check 全绿"}
{"time": "2026-10-23T17:00:55+08:00", "id": "d18", "result": "done", "summary": "ua verify 新增皮肤硬编码颜色门禁(#hex 禁止,rgba 仅限阴影/遮罩),清掉 ui.css 5 处 #fff 改令牌;负向测试确认能拦;check 全绿"}
{"time": "2026-10-23T17:01:46+08:00", "id": "d19", "result": "done", "summary": "dataTable 新增 selected 受控信号:与内核选择双向同步(内容比较 + 拷贝保护),demo 展示已选计数与清空;check 全绿"}
+13 -1
View File
@@ -30,6 +30,7 @@ import {
toast,
tooltip,
} from '@ui-arch/ui';
import type { RowKey } from '@ui-arch/ui';
/*** 侧边目录:挂载后从 .sec 反推锚点,IntersectionObserver 高亮视口内区块(清单改动自动跟随) ***/
function buildToc(toc: HTMLElement, content: HTMLElement): void {
@@ -109,6 +110,9 @@ const tags = signal(['设计', '前端', '组件库']);
// —— 滑块:音量与禁用态演示 ——
const volume = signal(40);
// —— 受控选中:dataTable 内部勾选实时写回,外部可清空 ——
const picked = signal<RowKey[]>([]);
// —— 表格加载态:切换后数据行变骨架行,筛选与翻页临时禁用 ——
const tableLoading = signal(false);
@@ -392,7 +396,15 @@ const content = h(
{ key: 'city', header: '城市', align: 'center', width: 'flex' },
],
pageSize: 5,
}), h('div', { class: 'row' }, switchButton({ label: '加载态', checked: tableLoading }))),
selected: picked,
}), h(
'div',
{ class: 'row' },
switchButton({ label: '加载态', checked: tableLoading }),
badge({ label: '受控选中', variant: 'default' }),
h('span', { class: 'out' }, () => `已选 ${picked().length} 行`),
button({ label: '清空选择', variant: 'ghost', onClick: () => picked([]) }),
)),
card(
{ title: '独立分页器联动(pageSize 3,共用页码信号)' },
dataTable({
+3 -1
View File
@@ -1,6 +1,6 @@
# @ui-arch 组件库 Agent 文档(无图形版)
> 自动生成于 2026-10-23T09:00:48.440Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 自动生成于 2026-10-23T09:01:45.831Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
## 快速上手
@@ -695,6 +695,7 @@ const name = signal(''); const f = form({ onSubmit: submit }, [formItem({ label:
- selectable(默认 false):boolean —— 启用行选择列:全选三态(含半选)、行 checkbox、已选计数;缺省 false
- page:Signal<number> —— 受控页码信号:与内核分页双向同步,传同一个信号给独立 pagination 组件即可联动
- loading:boolean | Signal<boolean> —— 加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy
- selected:Signal<RowKey[]> —— 受控选中行信号:与内核选择双向同步(内容比较,不来回派发),供批量操作读取/改写
示例:
@@ -714,6 +715,7 @@ dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓
8. 表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供
9. 数据在途时传 loading(布尔或信号):表格体换成骨架行、筛选与翻页禁用,返回后置回 false 即恢复
10. 需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用
11. 需要批量操作时传 selected 信号:内部勾选实时写回,外部置空或赋值即同步整表(跨页保留,按 rowKey 存)
现场演示:apps/docs/demo.html#sec-table
+14
View File
@@ -60,6 +60,20 @@ export function dataTable<T extends { id: RowKey }>(props: DataTableProps<T>): H
});
}
// —— 受控选中桥接:外部信号 ↔ 内核选择集;比较内容而非引用,避免来回派发 ——
if (props.selected) {
const selSig = props.selected;
const sameKeys = (a: RowKey[], b: RowKey[]): boolean => a.length === b.length && a.every((k, i) => k === b[i]);
effect(() => {
const external = selSig();
if (!sameKeys(external, state().selection)) table.dispatch({ type: 'setSelection', keys: external }); // 外部改写 → 内核
});
effect(() => {
const internal = state().selection;
if (!sameKeys(internal, selSig())) selSig([...internal]); // 内部勾选 → 写回外部(拷贝避免外部改到内核数组)
});
}
const filterKey = props.filterKey ?? props.columns[0].key;
const colspan = props.columns.length + (selectable ? 1 : 0);
+1
View File
@@ -54,6 +54,7 @@ export interface DataTableProps<T> {
selectable?: boolean; // 是否启用行选择列(含全选三态与已选计数);缺省 false
page?: Signal<number>; // 受控页码信号:与内核分页双向同步,可接独立 pagination 组件联动
loading?: boolean | Signal<boolean>; // 加载态:为真时数据行换成骨架行,筛选与翻页禁用
selected?: Signal<RowKey[]>; // 受控选中行信号:与内核选择双向同步,供批量操作读取
}
/*** 选项条目:select / radioGroup / tabs 共用的选项形状 ***/
+7 -1
View File
@@ -1124,6 +1124,11 @@
"n": "loading",
"t": "boolean | Signal<boolean>",
"d": "加载态:为真时数据行换成骨架行(行数随 pageSize),筛选输入与翻页按钮临时禁用,容器带 aria-busy"
},
{
"n": "selected",
"t": "Signal<RowKey[]>",
"d": "受控选中行信号:与内核选择双向同步(内容比较,不来回派发),供批量操作读取/改写"
}
],
"example": "dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓名', sortable: true }], pageSize: 5 })",
@@ -1137,7 +1142,8 @@
"工具栏输入框即筛选,输入即时过滤并回第 1 页;无匹配时显示空状态行",
"表头粘性固定(滚动容器 max-height 420px),斑马纹 + 悬停高亮由 CSS 提供",
"数据在途时传 loading(布尔或信号):表格体换成骨架行、筛选与翻页禁用,返回后置回 false 即恢复",
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用"
"需要独立分页器联动时传 page 信号:const page = signal(1),dataTable({ page }) 与 pagination({ page }) 共用",
"需要批量操作时传 selected 信号:内部勾选实时写回,外部置空或赋值即同步整表(跨页保留,按 rowKey 存)"
]
}
]