diff --git a/.ua/backlog.json b/.ua/backlog.json index fc9c3ff..1a7c8e0 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -40,6 +40,14 @@ "acceptance": "ua CLI 新增 docs-gen 逻辑:读取各组件 ua.manifest.json 中的 components 参数表,自动生成 props 表 HTML 片段注入文档站模板;生成结果与现有手写版信息量对齐(props 名/类型/默认值/说明);npm run check 全绿且文档站可正常打开", "status": "done", "notes": "核查确认 props 表/示例/步骤/演示 iframe 早已由 ua docs 从 manifest docs.components 单一来源驱动;真正的缺口是信息量不含默认值——本轮 CLI propsTable 新增「默认值」列(props 条目可选 df 字段,缺省渲染 —),llms-full.txt 参数行同步追加「默认 x」标注;16 处可机读默认值从描述文案提取进 df;check 全绿 + 文档站结构完整性校验通过" + }, + { + "id": "c01", + "title": "button / checkbox / switch 补 disabled 禁用态", + "motivation": "三个基础交互组件缺禁用能力,表单只读/权限控制场景刚需", + "acceptance": "ButtonProps / CheckboxProps / SwitchProps 新增可选 disabled(boolean | Signal):静态布尔与信号绑定都支持,禁用时事件不触发、置灰 + not-allowed 光标;demo 表单区加静态禁用与信号联动示例;manifest/文档/llms-full.txt 同步;npm run check 全绿", + "status": "done", + "notes": "零新增辅助代码:复用 frame h() 对 false/undefined 移除属性、Signal 函数走响应式绑定的既有语义,disabled 透传即可;CSS 补通用禁用态(opacity 0.45 + not-allowed,开关轨道同级置灰);demo 用同一 locked 信号绑定 switch 的 checked 与 checkbox 的 disabled 展示联动" } ] -} +} \ No newline at end of file diff --git a/.ua/index.json b/.ua/index.json index 6f60f10..ed1f359 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-23T08:03:18.018Z", + "generatedAt": "2026-10-23T08:07:27.570Z", "repoRoot": ".", "packages": [ { @@ -142,11 +142,11 @@ "api": { "entry": "src/index.ts", "exports": [ - "button(props):按钮,variant = primary | ghost | danger", + "button(props):按钮,variant = primary | ghost | danger,disabled 支持布尔或信号禁用", "textField(props):文本输入,value 信号双向绑定", "textarea(props):多行输入,value 信号双向绑定", - "checkbox(props):复选框,checked 信号双向绑定", - "switchButton(props):开关,checked 信号双向绑定", + "checkbox(props):复选框,checked 信号双向绑定,disabled 支持布尔或信号禁用", + "switchButton(props):开关,checked 信号双向绑定,disabled 支持布尔或信号禁用", "select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画", "radioGroup(props):单选组,options + value 信号双向绑定", "card(props, ...children):卡片容器", @@ -224,6 +224,11 @@ "d": "视觉强度;缺省 primary", "df": "primary" }, + { + "n": "disabled", + "t": "boolean | Signal", + "d": "禁用态:布尔直接置位,传信号则动态同步" + }, { "n": "onClick", "t": "() => void", @@ -317,6 +322,11 @@ "t": "string", "d": "右侧文案;缺省只渲染勾选框" }, + { + "n": "disabled", + "t": "boolean | Signal", + "d": "禁用态:布尔直接置位,传信号则动态同步" + }, { "n": "onChange", "t": "(checked: boolean) => void", @@ -346,6 +356,11 @@ "t": "string", "d": "左侧文案" }, + { + "n": "disabled", + "t": "boolean | Signal", + "d": "禁用态:布尔直接置位,传信号则动态同步" + }, { "n": "onChange", "t": "(checked: boolean) => void", diff --git a/.ua/iterations.log b/.ua/iterations.log index 0a5e162..4ba7788 100644 --- a/.ua/iterations.log +++ b/.ua/iterations.log @@ -3,3 +3,4 @@ {"time":"2026-10-23T15:53:33+08:00","id":"b03","result":"done","summary":"新增 skeleton 骨架屏组件:text/rect/circle 三形状 + 扫光微动画 + reduced-motion 静态化;manifest/docs/llms/demo 同步,check 全绿"} {"time":"2026-10-23T16:00:11+08:00","id":"b04","result":"done","summary":"新增独立 pagination 分页器(page 信号双向绑定 + 省略号折叠 + 键盘可达),dataTable 新增 page 受控桥接实现联动;demo 联动卡片,check 全绿"} {"time":"2026-10-23T16:03:46+08:00","id":"b05","result":"done","summary":"文档站核查确认已 manifest 驱动;补齐默认值信息量缺口:CLI propsTable 新增默认值列(df 字段)+ llms-full 默认标注,16 处默认值提取;check 全绿"} +{"time":"2026-10-23T16:08:17+08:00","id":"c01","result":"done","summary":"button/checkbox/switchButton 补 disabled(boolean|Signal),复用 h() 布尔/信号既有语义零辅助代码;CSS 通用禁用态 + demo 信号联动示例;check 全绿"} diff --git a/apps/demo/main.ts b/apps/demo/main.ts index 69fcf3b..d95b83a 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -71,6 +71,9 @@ const formResult = signal(''); // —— 分页联动状态:dataTable 与独立 pagination 共用同一页码信号 —— const tablePage = signal(1); +// —— 禁用态演示:开关信号同时绑定 switch 的 checked 与 checkbox 的 disabled —— +const locked = signal(true); + const app = h( 'div', { class: 'page' }, @@ -105,6 +108,13 @@ const app = h( h('div', { class: 'row' }, radioGroup({ options: [{ value: 's', label: '小' }, { value: 'm', label: '中' }, { value: 'l', label: '大' }], value: size })), textarea({ placeholder: '一句话介绍…', value: bio, rows: 2 }), h('span', { class: 'out' }, () => `简介 ${bio().length} 字`), + h( + 'div', + { class: 'row' }, + button({ label: '禁用按钮', variant: 'ghost', disabled: true }), + checkbox({ label: '信号禁用的勾选', disabled: locked }), + switchButton({ label: '锁定', checked: locked }), // 关掉开关即解锁上面的勾选框 + ), ), section( 'sec-feedback', diff --git a/llms-full.txt b/llms-full.txt index 1757176..e2dfe2d 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-23T08:02:39.002Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-23T08:07:27.570Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -48,6 +48,7 @@ - label(必填):string —— 按钮文案 - variant(默认 primary):'primary' | 'ghost' | 'danger' —— 视觉强度;缺省 primary +- disabled:boolean | Signal —— 禁用态:布尔直接置位,传信号则动态同步 - onClick(回调):() => void —— 点击回调 示例: @@ -115,6 +116,7 @@ const bio = signal(''); textarea({ value: bio, rows: 4, placeholder: '一句话 - checked:Signal —— 勾选状态信号,双向绑定 - label:string —— 右侧文案;缺省只渲染勾选框 +- disabled:boolean | Signal —— 禁用态:布尔直接置位,传信号则动态同步 - onChange(回调):(checked: boolean) => void —— 变更回调 示例: @@ -137,6 +139,7 @@ const agreed = signal(false); checkbox({ label: '同意条款', checked: agreed, - checked:Signal —— 开关状态信号,双向绑定 - label:string —— 左侧文案 +- disabled:boolean | Signal —— 禁用态:布尔直接置位,传信号则动态同步 - onChange(回调):(checked: boolean) => void —— 变更回调 示例: @@ -506,11 +509,11 @@ dataTable({ data: users, selectable: true, columns: [{ key: 'name', header: '姓 API 速览: -- button(props):按钮,variant = primary | ghost | danger +- button(props):按钮,variant = primary | ghost | danger,disabled 支持布尔或信号禁用 - textField(props):文本输入,value 信号双向绑定 - textarea(props):多行输入,value 信号双向绑定 -- checkbox(props):复选框,checked 信号双向绑定 -- switchButton(props):开关,checked 信号双向绑定 +- checkbox(props):复选框,checked 信号双向绑定,disabled 支持布尔或信号禁用 +- switchButton(props):开关,checked 信号双向绑定,disabled 支持布尔或信号禁用 - select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画 - radioGroup(props):单选组,options + value 信号双向绑定 - card(props, ...children):卡片容器 diff --git a/llms.txt b/llms.txt index 75fcfc7..53e1ca9 100644 --- a/llms.txt +++ b/llms.txt @@ -47,11 +47,11 @@ - 类型: skin-dom · 目录: packages/skin/ui - 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / radioGroup / card / badge / alert / toast / tooltip / skeleton / spinner / progress / tabs / pagination / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。 - API: - - button(props):按钮,variant = primary | ghost | danger + - button(props):按钮,variant = primary | ghost | danger,disabled 支持布尔或信号禁用 - textField(props):文本输入,value 信号双向绑定 - textarea(props):多行输入,value 信号双向绑定 - - checkbox(props):复选框,checked 信号双向绑定 - - switchButton(props):开关,checked 信号双向绑定 + - checkbox(props):复选框,checked 信号双向绑定,disabled 支持布尔或信号禁用 + - switchButton(props):开关,checked 信号双向绑定,disabled 支持布尔或信号禁用 - select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画 - radioGroup(props):单选组,options + value 信号双向绑定 - card(props, ...children):卡片容器 diff --git a/packages/skin/ui/src/button.ts b/packages/skin/ui/src/button.ts index 1e81c74..ccce1b4 100644 --- a/packages/skin/ui/src/button.ts +++ b/packages/skin/ui/src/button.ts @@ -1,11 +1,11 @@ import { h } from '@ui-arch/frame'; import type { ButtonProps } from './types.js'; -/*** 按钮:variant 控制视觉强度,onClick 为点击回调 ***/ +/*** 按钮:variant 控制视觉强度,disabled 支持布尔或信号禁用,onClick 为点击回调 ***/ export function button(props: ButtonProps): HTMLElement { return h( 'button', - { class: `ua-btn ua-btn-${props.variant ?? 'primary'}`, onClick: props.onClick }, + { class: `ua-btn ua-btn-${props.variant ?? 'primary'}`, disabled: props.disabled, onClick: props.onClick }, // false/undefined 移除属性,Signal 走响应式 props.label, ); } diff --git a/packages/skin/ui/src/checkbox.ts b/packages/skin/ui/src/checkbox.ts index 8ad7c74..bd60420 100644 --- a/packages/skin/ui/src/checkbox.ts +++ b/packages/skin/ui/src/checkbox.ts @@ -1,9 +1,9 @@ import { effect, h } from '@ui-arch/frame'; import type { CheckboxProps } from './types.js'; -/*** 复选框:checked 信号双向绑定,onChange 为变更回调 ***/ +/*** 复选框:checked 信号双向绑定,disabled 支持布尔或信号禁用,onChange 为变更回调 ***/ export function checkbox(props: CheckboxProps): HTMLElement { - const el = h('input', { type: 'checkbox', class: 'ua-checkbox' }) as HTMLInputElement; + const el = h('input', { type: 'checkbox', class: 'ua-checkbox', disabled: props.disabled }) as HTMLInputElement; // false/undefined 移除属性,Signal 走响应式 if (props.checked) { const checked = props.checked; el.addEventListener('change', () => checked(el.checked)); // 用户勾选写回信号 diff --git a/packages/skin/ui/src/switch.ts b/packages/skin/ui/src/switch.ts index a4b1283..d8ede67 100644 --- a/packages/skin/ui/src/switch.ts +++ b/packages/skin/ui/src/switch.ts @@ -1,9 +1,9 @@ import { effect, h } from '@ui-arch/frame'; import type { SwitchProps } from './types.js'; -/*** 开关:checked 信号双向绑定,轨道 + 滑块的纯 CSS 实现 ***/ +/*** 开关:checked 信号双向绑定,disabled 支持布尔或信号禁用,轨道 + 滑块的纯 CSS 实现 ***/ export function switchButton(props: SwitchProps): HTMLElement { - const input = h('input', { type: 'checkbox', class: 'ua-switch-input' }) as HTMLInputElement; + const input = h('input', { type: 'checkbox', class: 'ua-switch-input', disabled: props.disabled }) as HTMLInputElement; // false/undefined 移除属性,Signal 走响应式 if (props.checked) { const checked = props.checked; input.addEventListener('change', () => checked(input.checked)); // 用户切换写回信号 diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index d655796..b427363 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -12,6 +12,7 @@ export interface TooltipProps { export interface ButtonProps { label: string; // 按钮文案 variant?: 'primary' | 'ghost' | 'danger'; // 视觉强度;缺省 primary + disabled?: boolean | Signal; // 禁用态:布尔直接置位,传信号则动态同步 onClick?: () => void; // 点击回调 } @@ -48,6 +49,7 @@ export interface OptionItem { export interface CheckboxProps { label?: string; // 右侧文案;缺省不渲染 checked?: Signal; // 勾选状态信号,双向绑定 + disabled?: boolean | Signal; // 禁用态:布尔直接置位,传信号则动态同步 onChange?: (checked: boolean) => void; // 变更回调 } @@ -55,6 +57,7 @@ export interface CheckboxProps { export interface SwitchProps { label?: string; // 左侧文案;缺省不渲染 checked?: Signal; // 开关状态信号,双向绑定 + disabled?: boolean | Signal; // 禁用态:布尔直接置位,传信号则动态同步 onChange?: (checked: boolean) => void; // 变更回调 } diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 43943ce..8a40467 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -13,11 +13,11 @@ "api": { "entry": "src/index.ts", "exports": [ - "button(props):按钮,variant = primary | ghost | danger", + "button(props):按钮,variant = primary | ghost | danger,disabled 支持布尔或信号禁用", "textField(props):文本输入,value 信号双向绑定", "textarea(props):多行输入,value 信号双向绑定", - "checkbox(props):复选框,checked 信号双向绑定", - "switchButton(props):开关,checked 信号双向绑定", + "checkbox(props):复选框,checked 信号双向绑定,disabled 支持布尔或信号禁用", + "switchButton(props):开关,checked 信号双向绑定,disabled 支持布尔或信号禁用", "select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画", "radioGroup(props):单选组,options + value 信号双向绑定", "card(props, ...children):卡片容器", @@ -95,6 +95,11 @@ "d": "视觉强度;缺省 primary", "df": "primary" }, + { + "n": "disabled", + "t": "boolean | Signal", + "d": "禁用态:布尔直接置位,传信号则动态同步" + }, { "n": "onClick", "t": "() => void", @@ -188,6 +193,11 @@ "t": "string", "d": "右侧文案;缺省只渲染勾选框" }, + { + "n": "disabled", + "t": "boolean | Signal", + "d": "禁用态:布尔直接置位,传信号则动态同步" + }, { "n": "onChange", "t": "(checked: boolean) => void", @@ -217,6 +227,11 @@ "t": "string", "d": "左侧文案" }, + { + "n": "disabled", + "t": "boolean | Signal", + "d": "禁用态:布尔直接置位,传信号则动态同步" + }, { "n": "onChange", "t": "(checked: boolean) => void", diff --git a/packages/skin/ui/ui.css b/packages/skin/ui/ui.css index 8db5b38..00cedbe 100644 --- a/packages/skin/ui/ui.css +++ b/packages/skin/ui/ui.css @@ -773,6 +773,17 @@ transform: translateX(-50%) translateY(0); } +/* —— 通用禁用态:置灰 + 禁用光标 —— */ +.ua-btn:disabled, +.ua-checkbox:disabled, +.ua-switch-input:disabled { + opacity: 0.45; + cursor: not-allowed; +} +.ua-switch-input:disabled + .ua-switch-track { + opacity: 0.45; +} + /* —— 无障碍:用户偏好减少动效时关闭全部动画 —— */ @media (prefers-reduced-motion: reduce) { .ua-btn,