iter: d03 新增折叠面板 accordion 组件
This commit is contained in:
@@ -72,6 +72,14 @@
|
||||
"acceptance": "SelectProps / RadioGroupProps 新增可选 disabled(boolean | Signal<boolean>);禁用时 select 触发器置灰且不展开弹层,radioGroup 整组置灰不可选;select 箭头在展开时旋转 180°;demo 加信号禁用与静态禁用示例;manifest/文档/llms-full.txt 同步;npm run check 全绿",
|
||||
"status": "done",
|
||||
"notes": "disabled 仍走 h() 透传(原生 button/input 拦截交互)零辅助代码;select 根节点补 class 函数加 ua-open,箭头旋转选择器命中;CSS 通用禁用态列表并入 .ua-select-trigger 与 .ua-radio,另加 :has() 让单选行整行弱化、禁用触发器 hover 不改边框色"
|
||||
},
|
||||
{
|
||||
"id": "d03",
|
||||
"title": "新增折叠面板 accordion 组件",
|
||||
"motivation": "长表单/设置页需要分区收起,皮肤包无折叠容器;grid 行高过渡可零测量实现展开动画",
|
||||
"acceptance": "新增 accordion.ts:items(value/title/content/disabled)+ 单开(手风琴)与 multiple 多开,active 信号可选受控,标题为原生 button(aria-expanded/controls + region 关联),内容区 0fr→1fr 过渡且 reduced-motion 静态化;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿",
|
||||
"status": "done",
|
||||
"notes": "contents 走 appendChild 既有语义,字符串/DOM/响应式函数通吃;未传 active 时内部 signal<string[]> 持有展开集合,受控模式只认 active 单开;CSS 用 grid-template-rows 0fr→1fr 过渡免测量,reduced-motion 列表补 ua-acc-*;demo 新增 sec-accordion(多开 + 禁用面板)"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
+44
-3
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"$schema": "ui-arch-registry-index/0.1",
|
||||
"generatedAt": "2026-10-23T08:46:56.936Z",
|
||||
"generatedAt": "2026-10-23T08:47:49.411Z",
|
||||
"repoRoot": ".",
|
||||
"packages": [
|
||||
{
|
||||
@@ -130,7 +130,7 @@
|
||||
{
|
||||
"name": "@ui-arch/ui",
|
||||
"type": "skin-dom",
|
||||
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / menu / radioGroup / card / badge / alert / toast / tooltip / skeleton / spinner / progress / tabs / pagination / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
||||
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / menu / radioGroup / accordion / card / badge / alert / toast / tooltip / skeleton / spinner / progress / tabs / pagination / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
||||
"tags": [
|
||||
"components",
|
||||
"dom",
|
||||
@@ -150,6 +150,7 @@
|
||||
"select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画,disabled 支持布尔或信号禁用",
|
||||
"menu(props):下拉菜单,触发器 + 自绘弹层,条目支持禁用 / 危险 / 分隔线,↑↓ 环形导航,点外部 / Esc 关闭",
|
||||
"radioGroup(props):单选组,options + value 信号双向绑定,disabled 整组禁用",
|
||||
"accordion(props):折叠面板,标题按钮 + grid 行高过渡,单开(手风琴)或多开,支持禁用面板与 active 信号受控",
|
||||
"card(props, ...children):卡片容器",
|
||||
"badge(props):徽标,variant = default | success | warning | danger",
|
||||
"alert(props):提示条,variant = info | success | warning | danger",
|
||||
@@ -175,6 +176,8 @@
|
||||
"RadioGroupProps",
|
||||
"MenuItem",
|
||||
"MenuProps",
|
||||
"AccordionItem",
|
||||
"AccordionProps",
|
||||
"OptionItem",
|
||||
"CardProps",
|
||||
"BadgeProps",
|
||||
@@ -201,7 +204,7 @@
|
||||
"语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色"
|
||||
],
|
||||
"docs": {
|
||||
"intro": "21 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
||||
"intro": "22 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
||||
"steps": [
|
||||
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
|
||||
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
|
||||
@@ -510,6 +513,44 @@
|
||||
"需要整组禁用时传 disabled:布尔值静态禁用,也可传信号(如 locked)实现动态锁定"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "accordion",
|
||||
"title": "折叠面板 Accordion",
|
||||
"demo": "sec-accordion",
|
||||
"props": [
|
||||
{
|
||||
"n": "items",
|
||||
"t": "AccordionItem[]",
|
||||
"r": 1,
|
||||
"d": "面板列表:{ value, title, content, disabled? }"
|
||||
},
|
||||
{
|
||||
"n": "active",
|
||||
"t": "Signal<string>",
|
||||
"d": "受控展开面板信号(单开模式);缺省由组件内部持有状态"
|
||||
},
|
||||
{
|
||||
"n": "multiple",
|
||||
"t": "boolean",
|
||||
"d": "允许多个面板同时展开;缺省 false(手风琴,单开)",
|
||||
"df": "false"
|
||||
},
|
||||
{
|
||||
"n": "onChange",
|
||||
"t": "(active: string) => void",
|
||||
"k": 1,
|
||||
"d": "展开变化回调:收起时传空串"
|
||||
}
|
||||
],
|
||||
"example": "accordion({ items: [{ value: 'a', title: '账户设置', content: '内容…' }, { value: 'b', title: '通知', content: h('p', null, '…') }] })",
|
||||
"steps": [
|
||||
"准备 items:value 作标识、title 作标题、content 可为字符串 / DOM 节点 / 响应式函数",
|
||||
"默认手风琴模式:展开一个自动收起其他;需要同时展开多个时传 multiple: true",
|
||||
"需要外部控制或读取展开项时传 active 信号(受控单开),否则组件内部自持状态",
|
||||
"标题是原生 button:Tab 聚焦、Enter / Space 切换,展开态带 aria-expanded + region 关联",
|
||||
"内容区用 grid 行高 0fr → 1fr 过渡,无需测量高度;reduced-motion 用户自动静态切换"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "card",
|
||||
"title": "卡片 Card",
|
||||
|
||||
@@ -7,3 +7,4 @@
|
||||
{"time":"2026-10-23T16:10:31+08:00","id":"c02","result":"done","summary":"textField/textarea 补 disabled(boolean|Signal),与 c01 同模式;禁用态 CSS 覆盖输入类;demo locked 信号联动;check 全绿"}
|
||||
{"time": "2026-10-23T16:55:00+08:00", "id": "d01", "result": "done", "summary": "新增下拉菜单 menu:触发器 + 自绘弹层,disabled/danger/divider 条目,↑↓ 环形导航 + Esc 回焦,reduced-motion 兜底;manifest/llms-full/demo 同步,check 全绿"}
|
||||
{"time": "2026-10-23T17:02:00+08:00", "id": "d02", "result": "done", "summary": "select/radioGroup 补 disabled(布尔|信号),并修复 select 根节点缺 ua-open 导致箭头不旋转的既有缺陷;CSS :has() 行级弱化;demo/manifest/llms 同步,check 全绿"}
|
||||
{"time": "2026-10-23T16:47:56+08:00", "id": "d03", "result": "done", "summary": "新增折叠面板 accordion:单开/多开 + active 受控 + 禁用面板,grid 行高 0fr→1fr 过渡免测量,aria 关联完整;manifest/llms/demo 同步,check 全绿"}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { h, mount, signal } from '@ui-arch/frame';
|
||||
import {
|
||||
accordion,
|
||||
alert,
|
||||
badge,
|
||||
button,
|
||||
@@ -233,6 +234,20 @@ const app = h(
|
||||
h('span', { class: 'out' }, () => (menuPick() ? `已选:${menuPick()}` : '未选择')),
|
||||
),
|
||||
),
|
||||
section(
|
||||
'sec-accordion',
|
||||
'折叠面板',
|
||||
'accordion:标题按钮 + grid 行高过渡,默认手风琴单开,multiple 可多开,支持禁用面板。',
|
||||
accordion({
|
||||
multiple: true,
|
||||
items: [
|
||||
{ value: 'a', title: '账户设置', content: '修改昵称、头像与绑定邮箱。' },
|
||||
{ value: 'b', title: '通知偏好', content: alert({ message: '通知偏好:每日摘要已开启', variant: 'info' }) },
|
||||
{ value: 'c', title: '危险操作', content: '删除账号后数据不可恢复。' },
|
||||
{ value: 'd', title: '企业版专属(禁用)', content: '升级后可配置 SSO。', disabled: true },
|
||||
],
|
||||
}),
|
||||
),
|
||||
section(
|
||||
'sec-table',
|
||||
'数据表格',
|
||||
|
||||
+28
-2
@@ -1,6 +1,6 @@
|
||||
# @ui-arch 组件库 Agent 文档(无图形版)
|
||||
|
||||
> 自动生成于 2026-10-23T08:46:56.936Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||
> 自动生成于 2026-10-23T08:47:49.411Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
|
||||
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
|
||||
|
||||
## 快速上手
|
||||
@@ -40,7 +40,7 @@
|
||||
|
||||
## @ui-arch/ui(skin-dom)v0.1.0
|
||||
|
||||
21 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。
|
||||
22 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。
|
||||
|
||||
### button — 按钮 Button
|
||||
|
||||
@@ -233,6 +233,31 @@ const size = signal('m'); radioGroup({ options: [{ value: 's', label: '小' }, {
|
||||
|
||||
现场演示:apps/docs/demo.html#sec-form
|
||||
|
||||
### accordion — 折叠面板 Accordion
|
||||
|
||||
参数:
|
||||
|
||||
- items(必填):AccordionItem[] —— 面板列表:{ value, title, content, disabled? }
|
||||
- active:Signal<string> —— 受控展开面板信号(单开模式);缺省由组件内部持有状态
|
||||
- multiple(默认 false):boolean —— 允许多个面板同时展开;缺省 false(手风琴,单开)
|
||||
- onChange(回调):(active: string) => void —— 展开变化回调:收起时传空串
|
||||
|
||||
示例:
|
||||
|
||||
```
|
||||
accordion({ items: [{ value: 'a', title: '账户设置', content: '内容…' }, { value: 'b', title: '通知', content: h('p', null, '…') }] })
|
||||
```
|
||||
|
||||
手把手:
|
||||
|
||||
1. 准备 items:value 作标识、title 作标题、content 可为字符串 / DOM 节点 / 响应式函数
|
||||
2. 默认手风琴模式:展开一个自动收起其他;需要同时展开多个时传 multiple: true
|
||||
3. 需要外部控制或读取展开项时传 active 信号(受控单开),否则组件内部自持状态
|
||||
4. 标题是原生 button:Tab 聚焦、Enter / Space 切换,展开态带 aria-expanded + region 关联
|
||||
5. 内容区用 grid 行高 0fr → 1fr 过渡,无需测量高度;reduced-motion 用户自动静态切换
|
||||
|
||||
现场演示:apps/docs/demo.html#sec-accordion
|
||||
|
||||
### card — 卡片 Card
|
||||
|
||||
参数:
|
||||
@@ -548,6 +573,7 @@ API 速览:
|
||||
- select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画,disabled 支持布尔或信号禁用
|
||||
- menu(props):下拉菜单,触发器 + 自绘弹层,条目支持禁用 / 危险 / 分隔线,↑↓ 环形导航,点外部 / Esc 关闭
|
||||
- radioGroup(props):单选组,options + value 信号双向绑定,disabled 整组禁用
|
||||
- accordion(props):折叠面板,标题按钮 + grid 行高过渡,单开(手风琴)或多开,支持禁用面板与 active 信号受控
|
||||
- card(props, ...children):卡片容器
|
||||
- badge(props):徽标,variant = default | success | warning | danger
|
||||
- alert(props):提示条,variant = info | success | warning | danger
|
||||
|
||||
@@ -45,7 +45,7 @@
|
||||
## @ui-arch/ui (v0.1.0)
|
||||
|
||||
- 类型: skin-dom · 目录: packages/skin/ui
|
||||
- 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / menu / radioGroup / card / badge / alert / toast / tooltip / skeleton / spinner / progress / tabs / pagination / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。
|
||||
- 描述: DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / menu / radioGroup / accordion / 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,disabled 支持布尔或信号禁用
|
||||
- textField(props):文本输入,value 信号双向绑定,disabled 支持布尔或信号禁用
|
||||
@@ -55,6 +55,7 @@
|
||||
- select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画,disabled 支持布尔或信号禁用
|
||||
- menu(props):下拉菜单,触发器 + 自绘弹层,条目支持禁用 / 危险 / 分隔线,↑↓ 环形导航,点外部 / Esc 关闭
|
||||
- radioGroup(props):单选组,options + value 信号双向绑定,disabled 整组禁用
|
||||
- accordion(props):折叠面板,标题按钮 + grid 行高过渡,单开(手风琴)或多开,支持禁用面板与 active 信号受控
|
||||
- card(props, ...children):卡片容器
|
||||
- badge(props):徽标,variant = default | success | warning | danger
|
||||
- alert(props):提示条,variant = info | success | warning | danger
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
import { h, signal } from '@ui-arch/frame';
|
||||
import type { AccordionItem, AccordionProps } from './types.js';
|
||||
|
||||
/*** 折叠面板:标题按钮 + grid 行高过渡;单开(手风琴)或多开,展开态由 active 信号驱动或内部持有 ***/
|
||||
export function accordion(props: AccordionProps): HTMLElement {
|
||||
// —— 状态集中声明 ——
|
||||
const internal = signal<string[]>([]); // 内部展开集合(未传 active 时使用)
|
||||
const opened = (v: string): boolean => (props.active ? props.active() === v : internal().includes(v));
|
||||
|
||||
const toggle = (item: AccordionItem): void => {
|
||||
if (props.active) {
|
||||
const next = props.active() === item.value ? '' : item.value; // 单开:再点收起
|
||||
props.active(next);
|
||||
props.onChange?.(next);
|
||||
return;
|
||||
}
|
||||
const cur = internal();
|
||||
const next = cur.includes(item.value)
|
||||
? cur.filter((v) => v !== item.value)
|
||||
: props.multiple
|
||||
? [...cur, item.value]
|
||||
: [item.value];
|
||||
internal(next);
|
||||
props.onChange?.(next[0] ?? '');
|
||||
};
|
||||
|
||||
// —— 面板:标题为原生 button(键盘可达),内容包一层 overflow 容器供过渡裁剪 ——
|
||||
const rows = props.items.map((item, i) =>
|
||||
h(
|
||||
'div',
|
||||
{ class: () => `ua-acc-item${opened(item.value) ? ' ua-open' : ''}` },
|
||||
h(
|
||||
'button',
|
||||
{
|
||||
type: 'button',
|
||||
class: 'ua-acc-head',
|
||||
id: `ua-acc-h-${i}`,
|
||||
'aria-expanded': () => String(opened(item.value)),
|
||||
'aria-controls': `ua-acc-b-${i}`,
|
||||
disabled: item.disabled ?? false, // 布尔透传即得禁用态
|
||||
onClick: () => toggle(item),
|
||||
},
|
||||
h('span', { class: 'ua-acc-title' }, item.title),
|
||||
h('span', { class: 'ua-acc-caret' }, '▸'),
|
||||
),
|
||||
h(
|
||||
'div',
|
||||
{ class: 'ua-acc-body', id: `ua-acc-b-${i}`, role: 'region', 'aria-labelledby': `ua-acc-h-${i}` },
|
||||
h('div', { class: 'ua-acc-inner' }, item.content),
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
return h('div', { class: 'ua-accordion' }, ...rows);
|
||||
}
|
||||
@@ -7,6 +7,7 @@ export { switchButton } from './switch.js';
|
||||
export { select } from './select.js';
|
||||
export { menu } from './menu.js';
|
||||
export { radioGroup } from './radioGroup.js';
|
||||
export { accordion } from './accordion.js';
|
||||
export { card } from './card.js';
|
||||
export { badge } from './badge.js';
|
||||
export { alert } from './alert.js';
|
||||
|
||||
@@ -97,6 +97,22 @@ export interface MenuProps {
|
||||
onSelect?: (value: string) => void; // 选中回调(禁用项不触发)
|
||||
}
|
||||
|
||||
/*** 折叠面板条目 ***/
|
||||
export interface AccordionItem {
|
||||
value: string; // 面板标识(回调与展开集合用)
|
||||
title: string; // 标题文案(同时作为触发器)
|
||||
content: unknown; // 面板内容:字符串 / DOM 节点 / 响应式函数
|
||||
disabled?: boolean; // 禁用该面板:标题置灰且不可展开
|
||||
}
|
||||
|
||||
/*** 折叠面板入参 ***/
|
||||
export interface AccordionProps {
|
||||
items: AccordionItem[]; // 面板列表
|
||||
active?: Signal<string>; // 展开面板信号(单开模式);缺省由组件内部持有状态
|
||||
multiple?: boolean; // 是否允许多个面板同时展开;缺省 false(手风琴)
|
||||
onChange?: (active: string) => void; // 展开变化回调:收起时传空串
|
||||
}
|
||||
|
||||
/*** 多行输入入参 ***/
|
||||
export interface TextareaProps {
|
||||
placeholder?: string; // 占位文案
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@ui-arch/ui",
|
||||
"type": "skin-dom",
|
||||
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / menu / radioGroup / card / badge / alert / toast / tooltip / skeleton / spinner / progress / tabs / pagination / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
||||
"description": "DOM 皮肤组件库:button / textField / textarea / checkbox / switch / select / menu / radioGroup / accordion / card / badge / alert / toast / tooltip / skeleton / spinner / progress / tabs / pagination / modal / form / formItem / dataTable,构建在 @ui-arch/frame 与 @ui-arch/table-core 之上,样式只消费 --ua-* 令牌。",
|
||||
"tags": [
|
||||
"components",
|
||||
"dom",
|
||||
@@ -21,6 +21,7 @@
|
||||
"select(props):自绘下拉选择(非原生 select),value 信号双向绑定,点外部 / Esc 关闭,选项弹层带微动画,disabled 支持布尔或信号禁用",
|
||||
"menu(props):下拉菜单,触发器 + 自绘弹层,条目支持禁用 / 危险 / 分隔线,↑↓ 环形导航,点外部 / Esc 关闭",
|
||||
"radioGroup(props):单选组,options + value 信号双向绑定,disabled 整组禁用",
|
||||
"accordion(props):折叠面板,标题按钮 + grid 行高过渡,单开(手风琴)或多开,支持禁用面板与 active 信号受控",
|
||||
"card(props, ...children):卡片容器",
|
||||
"badge(props):徽标,variant = default | success | warning | danger",
|
||||
"alert(props):提示条,variant = info | success | warning | danger",
|
||||
@@ -46,6 +47,8 @@
|
||||
"RadioGroupProps",
|
||||
"MenuItem",
|
||||
"MenuProps",
|
||||
"AccordionItem",
|
||||
"AccordionProps",
|
||||
"OptionItem",
|
||||
"CardProps",
|
||||
"BadgeProps",
|
||||
@@ -72,7 +75,7 @@
|
||||
"语义色 variant 四档:default|info / success / warning / danger,一律来自令牌,禁止硬编码颜色"
|
||||
],
|
||||
"docs": {
|
||||
"intro": "21 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
||||
"intro": "22 个 DOM 组件,统一用法:组件是普通函数,传入 props 返回 DOM 节点;需要状态时先创建 signal 再双向绑定。引入 CSS:import '@ui-arch/ui/ui.css'(内部已消费 tokens)。",
|
||||
"steps": [
|
||||
"安装依赖:pnpm add @ui-arch/ui @ui-arch/frame(workspace 内自动链接)",
|
||||
"引入样式:在应用入口 import '@ui-arch/ui/ui.css',暗色主题在根元素设 data-theme='dark'",
|
||||
@@ -381,6 +384,44 @@
|
||||
"需要整组禁用时传 disabled:布尔值静态禁用,也可传信号(如 locked)实现动态锁定"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "accordion",
|
||||
"title": "折叠面板 Accordion",
|
||||
"demo": "sec-accordion",
|
||||
"props": [
|
||||
{
|
||||
"n": "items",
|
||||
"t": "AccordionItem[]",
|
||||
"r": 1,
|
||||
"d": "面板列表:{ value, title, content, disabled? }"
|
||||
},
|
||||
{
|
||||
"n": "active",
|
||||
"t": "Signal<string>",
|
||||
"d": "受控展开面板信号(单开模式);缺省由组件内部持有状态"
|
||||
},
|
||||
{
|
||||
"n": "multiple",
|
||||
"t": "boolean",
|
||||
"d": "允许多个面板同时展开;缺省 false(手风琴,单开)",
|
||||
"df": "false"
|
||||
},
|
||||
{
|
||||
"n": "onChange",
|
||||
"t": "(active: string) => void",
|
||||
"k": 1,
|
||||
"d": "展开变化回调:收起时传空串"
|
||||
}
|
||||
],
|
||||
"example": "accordion({ items: [{ value: 'a', title: '账户设置', content: '内容…' }, { value: 'b', title: '通知', content: h('p', null, '…') }] })",
|
||||
"steps": [
|
||||
"准备 items:value 作标识、title 作标题、content 可为字符串 / DOM 节点 / 响应式函数",
|
||||
"默认手风琴模式:展开一个自动收起其他;需要同时展开多个时传 multiple: true",
|
||||
"需要外部控制或读取展开项时传 active 信号(受控单开),否则组件内部自持状态",
|
||||
"标题是原生 button:Tab 聚焦、Enter / Space 切换,展开态带 aria-expanded + region 关联",
|
||||
"内容区用 grid 行高 0fr → 1fr 过渡,无需测量高度;reduced-motion 用户自动静态切换"
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "card",
|
||||
"title": "卡片 Card",
|
||||
|
||||
@@ -384,6 +384,71 @@
|
||||
background: var(--ua-color-border);
|
||||
}
|
||||
|
||||
/* —— 折叠面板 —— */
|
||||
.ua-accordion {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
border: 1px solid var(--ua-color-border);
|
||||
border-radius: var(--ua-radius-md);
|
||||
overflow: hidden;
|
||||
background: var(--ua-color-bg);
|
||||
}
|
||||
.ua-acc-item + .ua-acc-item {
|
||||
border-top: 1px solid var(--ua-color-border);
|
||||
}
|
||||
.ua-acc-head {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
gap: 8px;
|
||||
padding: 10px 12px;
|
||||
border: none;
|
||||
background: none;
|
||||
color: var(--ua-color-text);
|
||||
font-size: var(--ua-font-size-lg);
|
||||
text-align: left;
|
||||
cursor: pointer;
|
||||
transition: background 0.15s;
|
||||
}
|
||||
.ua-acc-head:hover:not(:disabled) {
|
||||
background: color-mix(in srgb, var(--ua-color-accent) 6%, transparent);
|
||||
}
|
||||
.ua-acc-head:focus-visible {
|
||||
outline: none;
|
||||
box-shadow: inset 0 0 0 2px color-mix(in srgb, var(--ua-color-accent) 45%, transparent);
|
||||
}
|
||||
.ua-acc-head:disabled {
|
||||
opacity: 0.45;
|
||||
cursor: not-allowed;
|
||||
}
|
||||
.ua-acc-caret {
|
||||
font-size: 10px;
|
||||
color: var(--ua-color-text-muted);
|
||||
transition: transform 0.22s ease;
|
||||
}
|
||||
.ua-acc-item.ua-open .ua-acc-caret {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
/* 内容区用 grid 行高过渡:0fr → 1fr,无需测量高度 */
|
||||
.ua-acc-body {
|
||||
display: grid;
|
||||
grid-template-rows: 0fr;
|
||||
transition: grid-template-rows 0.24s ease;
|
||||
}
|
||||
.ua-acc-item.ua-open .ua-acc-body {
|
||||
grid-template-rows: 1fr;
|
||||
}
|
||||
.ua-acc-inner {
|
||||
overflow: hidden;
|
||||
padding: 0 12px;
|
||||
color: var(--ua-color-text-muted);
|
||||
font-size: var(--ua-font-size-md);
|
||||
}
|
||||
.ua-acc-item.ua-open .ua-acc-inner {
|
||||
padding-bottom: 12px;
|
||||
}
|
||||
|
||||
/* —— 多行输入 —— */
|
||||
.ua-textarea {
|
||||
width: 100%;
|
||||
@@ -885,6 +950,9 @@
|
||||
.ua-menu-pop,
|
||||
.ua-menu-caret,
|
||||
.ua-menu-item,
|
||||
.ua-acc-head,
|
||||
.ua-acc-caret,
|
||||
.ua-acc-body,
|
||||
.ua-switch-track,
|
||||
.ua-switch-thumb,
|
||||
.ua-tab,
|
||||
|
||||
Reference in New Issue
Block a user