iter(g83): 开关改 switch 语义并补可访问名

This commit is contained in:
HIsheR
2026-10-26 13:01:16 +08:00
parent ab0f1a5286
commit 151b54243e
7 changed files with 32 additions and 4 deletions
+8
View File
@@ -1020,6 +1020,14 @@
"acceptance": "新增 maxSize(字节)/ maxCount(多选上限)两个可选参数;accept 支持 .ext / type/subtype / type/* 且对拖拽同样生效;被拒文件不进清单并在 role=status 提示行写明原因(类型不符 / 超上限 / 数量已满);不改onChange 语义;文档与演示同步;npm run check 全绿",
"notes": "自补:可用性;校验入口收敛到 add(),点选与拖拽共用同一条路径",
"status": "done"
},
{
"id": "g83",
"title": "开关改用 switch 语义并补可访问名兜底",
"motivation": "开关底层是 input type=checkbox,读屏一律播报成「复选框」,与视觉上的开关语义不符;不留 label 时更是完全没有可访问名(只有一个匿名复选框)",
"acceptance": "input 补 role=switch(选中态沿用原生 checked 映射);新增可选 ariaLabel,缺省取 label,纯图标开关也有可访问名;文档 props 与演示(无文案开关实例)同步;npm run check 全绿",
"notes": "自补:无障碍;沿用原生 checkbox 的 Space 切换行为,不重造键盘交互",
"status": "open"
}
]
}
+6 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "ui-arch-registry-index/0.1",
"generatedAt": "2026-10-26T05:00:02.358Z",
"generatedAt": "2026-10-26T05:00:45.858Z",
"repoRoot": ".",
"packages": [
{
@@ -607,6 +607,11 @@
"t": "Signal<boolean>",
"d": "开关状态信号,双向绑定"
},
{
"n": "ariaLabel",
"t": "string",
"d": "无可见文案时的可访问名(如纯图标开关);缺省取 label"
},
{
"n": "label",
"t": "string",
+2
View File
@@ -139,6 +139,7 @@ const name = signal('');
// —— 表单控件状态集中声明 ——
const agreed = signal(false);
const nightMode = signal(true);
const sound = signal(true); // 无可见文案的开关演示
const city = signal('');
const size = signal('m');
const bio = signal('');
@@ -254,6 +255,7 @@ const content = h(
'checkbox / switch / select / radioGroup / textarea:状态一律由调用方信号持有;select 弹层在视口下方空间不足时自动翻到上方,展开后键入字母可快跳选项;textarea 传 maxCount 显示实时字数。',
h('div', { class: 'row' }, checkbox({ label: '同意条款', checked: agreed }), h('span', { class: 'out' }, () => (agreed() ? '已同意' : '未同意'))),
h('div', { class: 'row' }, switchButton({ label: '夜间模式', checked: nightMode }), h('span', { class: 'out' }, () => (nightMode() ? '开' : '关'))),
h('div', { class: 'row' }, switchButton({ checked: sound, ariaLabel: '通知声音' }), h('span', { class: 'out' }, () => `无可见文案的开关(ariaLabel 兜底,读屏念「通知声音」):${sound() ? '开' : '关'}`)),
h('div', { class: 'row' }, select({ options: cities.map((c) => ({ value: c, label: c })), value: city, placeholder: '选择城市…' }), h('span', { class: 'out' }, () => (city() ? `城市:${city()}` : '未选择'))),
h('div', { class: 'row' }, radioGroup({ options: [{ value: 's', label: '小' }, { value: 'm', label: '中' }, { value: 'l', label: '大' }], value: size })),
textarea({ placeholder: '一句话介绍…', value: bio, rows: 2, maxCount: 30 }),
+2 -1
View File
@@ -1,6 +1,6 @@
# @ui-arch 组件库 Agent 文档(无图形版)
> 自动生成于 2026-10-26T05:00:02.358Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 自动生成于 2026-10-26T05:00:45.858Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
## 快速上手
@@ -239,6 +239,7 @@ const agreed = signal(false); checkbox({ label: '同意条款', checked: agreed,
参数:
- checked:Signal<boolean> —— 开关状态信号,双向绑定
- ariaLabel:string —— 无可见文案时的可访问名(如纯图标开关);缺省取 label
- label:string —— 左侧文案
- disabled:boolean | Signal<boolean> —— 禁用态:布尔直接置位,传信号则动态同步
- onChange(回调):(checked: boolean) => void —— 变更回调
+7 -1
View File
@@ -3,7 +3,13 @@ import type { SwitchProps } from './types.js';
/*** 开关:checked 信号双向绑定,disabled 支持布尔或信号禁用,轨道 + 滑块的纯 CSS 实现 ***/
export function switchButton(props: SwitchProps): HTMLElement {
const input = h('input', { type: 'checkbox', class: 'ua-switch-input', disabled: props.disabled }) as HTMLInputElement; // false/undefined 移除属性,Signal 走响应式
const input = h('input', {
type: 'checkbox',
class: 'ua-switch-input',
role: 'switch', // 用开关语义而非复选框:读屏播报「开关」并跟随选中态
'aria-label': props.ariaLabel ?? props.label, // 无可见文案时也要有可访问名
disabled: props.disabled, // false/undefined 移除属性,Signal 走响应式
}) as HTMLInputElement;
if (props.checked) {
const checked = props.checked;
input.addEventListener('change', () => checked(input.checked)); // 用户切换写回信号
+2 -1
View File
@@ -91,7 +91,8 @@ export interface CheckboxProps {
/*** 开关入参 ***/
export interface SwitchProps {
label?: string; // 左侧文案;缺省不渲染
label?: string; // 左侧文案;缺省不渲染(此时读屏名靠 ariaLabel 兜底)
ariaLabel?: string; // 无可见文案时的可访问名,如纯图标开关;缺省取 label
checked?: Signal<boolean>; // 开关状态信号,双向绑定
disabled?: boolean | Signal<boolean>; // 禁用态:布尔直接置位,传信号则动态同步
onChange?: (checked: boolean) => void; // 变更回调
+5
View File
@@ -478,6 +478,11 @@
"t": "Signal<boolean>",
"d": "开关状态信号,双向绑定"
},
{
"n": "ariaLabel",
"t": "string",
"d": "无可见文案时的可访问名(如纯图标开关);缺省取 label"
},
{
"n": "label",
"t": "string",