diff --git a/.ua/backlog.json b/.ua/backlog.json index c9ab626..1d50f16 100644 --- a/.ua/backlog.json +++ b/.ua/backlog.json @@ -232,6 +232,14 @@ "acceptance": "新增 avatar.ts:name 必填(alt / title / 首字来源),src 可选(有则图片、无则首字占位),size 可调,variant 四档语义底色;只消费 --ua-* 令牌;导出 / manifest / 文档 / llms-full.txt / demo 同步;npm run check 全绿", "status": "done", "notes": "首字占位对中文取首字、英文大写,空名兜底 ?;flex:none 保证不被挤压;首次跑 verify 被自身新门禁拦下(声明 sec-avatar 但 demo 缺区块),补独立区块后通过——门禁有效性再次得到验证" + }, + { + "id": "d23", + "title": "alert 补标题行与可关闭,并补 role=alert", + "motivation": "常驻提示无法消除(错误已处理完仍占版面),且只有单层正文放不下「结论 + 详情」;role=alert 缺失导致读屏不播报", + "acceptance": "AlertProps 新增 title? / closable? / onClose?;关闭时先退场(opacity+上移,200ms)再从 DOM 移除;容器 role=alert;只消费 --ua-* 令牌;demo 新增 sec-alert 展示无标题与可关闭带标题两种;manifest/文档/llms-full.txt 同步;npm run check 全绿", + "status": "done", + "notes": "与 toast 的分工保持:alert 常驻在页面流里、toast 全局浮动;关闭后由调用方自行决定是否重新渲染;body/title/message 三层结构让 flex 布局能把 × 对齐到首行;对现有 alert({message}) 调用完全兼容" } ] } diff --git a/.ua/index.json b/.ua/index.json index ae84f5c..0fd39cb 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-23T09:03:43.931Z", + "generatedAt": "2026-10-23T09:04:21.317Z", "repoRoot": ".", "packages": [ { @@ -157,7 +157,7 @@ "badge(props):徽标,variant = default | success | warning | danger", "tag(props):可关闭标签,variant 五档语义色,closable + onClose 支持从数据源移除(纯展示请用 badge)", "avatar(props):头像,有 src 渲染图片(alt 用名称)、无 src 用首字占位,size 可调 + 四档语义底色", - "alert(props):提示条,variant = info | success | warning | danger", + "alert(props):提示条,variant 四档语义色 + 可选 title 与 closable 关闭按钮,role=alert 读屏可播报", "toast.info/success/warning/error(message, duration?):消息提示工厂,右上角堆叠,默认 3s 自动消失,出入场微动画;showToast(props) 为完整入参版本(closable 显示关闭按钮,同屏最多 4 条)", "tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起", "popover(props, trigger):可交互气泡卡片,包裹触发器,默认点击开合 + 点外部 / Esc 收起,content 可放按钮等交互元素", @@ -788,18 +788,37 @@ "r": 1, "d": "提示内容" }, + { + "n": "title", + "t": "string", + "d": "加粗标题行;缺省只渲染正文" + }, { "n": "variant", "t": "'info' | 'success' | 'warning' | 'danger'", "d": "语义色;缺省 info", "df": "info" + }, + { + "n": "closable", + "t": "boolean", + "d": "显示 × 关闭按钮,退场后从 DOM 移除;缺省 false", + "df": "false" + }, + { + "n": "onClose", + "t": "() => void", + "k": 1, + "d": "关闭回调,供调用方同步业务状态" } ], "example": "alert({ message: '操作可能存在风险', variant: 'warning' })", "steps": [ "按信息级别选 variant:info 提示、success 成功、warning 警告、danger 错误", "传入 message 即可,入场自带下滑动画", - "需要可关闭或带操作按钮时,外层用 h() 组合 button 自行拼装,alert 只负责语义底色" + "需要可关闭或带操作按钮时,外层用 h() 组合 button 自行拼装,alert 只负责语义底色", + "需要用户可自行消除的提示传 closable: true:点 × 淡出并从 DOM 移除,配合 onClose 同步业务状态", + "有标题与正文两层信息时传 title(加粗首行),正文仍走 message" ] }, { diff --git a/.ua/iterations.log b/.ua/iterations.log index c673172..110c0b9 100644 --- a/.ua/iterations.log +++ b/.ua/iterations.log @@ -27,3 +27,4 @@ {"time": "2026-10-23T17:02:24+08:00", "id": "d20", "result": "done", "summary": "progress 支持不确定态:value 可选,缺省时 35% 填充块往复 + aria-label 进行中;定量态补 aria-valuenow;demo/manifest/llms 同步,check 全绿"} {"time": "2026-10-23T17:03:02+08:00", "id": "d21", "result": "done", "summary": "无障碍收尾:modal × 补 aria-label/type、spinner role=status、skeleton aria-hidden、tablist aria-label + 禁用页签 aria-disabled;conventions 记录基线;check 全绿"} {"time": "2026-10-23T17:03:49+08:00", "id": "d22", "result": "done", "summary": "新增头像 avatar(src 图片 / 首字占位 + size + 四档语义底色),demo 独立 sec-avatar;中途被 verify 的 demo 锚点检查拦下已补;check 全绿"} +{"time": "2026-10-23T17:04:27+08:00", "id": "d23", "result": "done", "summary": "alert 新增 title / closable / onClose 与 role=alert,关闭走 200ms 退场后摘除;demo 独立 sec-alert;manifest/llms 同步,check 全绿"} diff --git a/apps/demo/main.ts b/apps/demo/main.ts index a3e566c..8c8055c 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -246,6 +246,13 @@ const content = h( progress({ value: percent }), h('div', { class: 'row' }, h('span', { class: 'out' }, '不确定态:'), progress()), ), + section( + 'sec-alert', + '提示条', + 'alert:四档语义色 + 可选标题与关闭按钮,role=alert 由读屏播报。', + alert({ message: '这是一条中性提示(无标题)', variant: 'info' }), + alert({ title: '保存失败', message: '网络波动,请稍后重试;本次修改已保留在本地草稿。', variant: 'danger', closable: true, onClose: () => toast.warning('提示已关闭') }), + ), section( 'sec-tooltip', '悬浮提示', diff --git a/llms-full.txt b/llms-full.txt index aa82717..e62b07f 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-23T09:03:43.931Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-23T09:04:21.317Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -413,7 +413,10 @@ avatar({ name: '张三' }); avatar({ name: 'Alice', size: 40, variant: 'success' 参数: - message(必填):string —— 提示内容 +- title:string —— 加粗标题行;缺省只渲染正文 - variant(默认 info):'info' | 'success' | 'warning' | 'danger' —— 语义色;缺省 info +- closable(默认 false):boolean —— 显示 × 关闭按钮,退场后从 DOM 移除;缺省 false +- onClose(回调):() => void —— 关闭回调,供调用方同步业务状态 示例: @@ -426,6 +429,8 @@ alert({ message: '操作可能存在风险', variant: 'warning' }) 1. 按信息级别选 variant:info 提示、success 成功、warning 警告、danger 错误 2. 传入 message 即可,入场自带下滑动画 3. 需要可关闭或带操作按钮时,外层用 h() 组合 button 自行拼装,alert 只负责语义底色 +4. 需要用户可自行消除的提示传 closable: true:点 × 淡出并从 DOM 移除,配合 onClose 同步业务状态 +5. 有标题与正文两层信息时传 title(加粗首行),正文仍走 message 现场演示:apps/docs/demo.html#sec-feedback @@ -762,7 +767,7 @@ API 速览: - badge(props):徽标,variant = default | success | warning | danger - tag(props):可关闭标签,variant 五档语义色,closable + onClose 支持从数据源移除(纯展示请用 badge) - avatar(props):头像,有 src 渲染图片(alt 用名称)、无 src 用首字占位,size 可调 + 四档语义底色 -- alert(props):提示条,variant = info | success | warning | danger +- alert(props):提示条,variant 四档语义色 + 可选 title 与 closable 关闭按钮,role=alert 读屏可播报 - toast.info/success/warning/error(message, duration?):消息提示工厂,右上角堆叠,默认 3s 自动消失,出入场微动画;showToast(props) 为完整入参版本(closable 显示关闭按钮,同屏最多 4 条) - tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起 - popover(props, trigger):可交互气泡卡片,包裹触发器,默认点击开合 + 点外部 / Esc 收起,content 可放按钮等交互元素 diff --git a/llms.txt b/llms.txt index 11005ee..c35fba0 100644 --- a/llms.txt +++ b/llms.txt @@ -62,7 +62,7 @@ - badge(props):徽标,variant = default | success | warning | danger - tag(props):可关闭标签,variant 五档语义色,closable + onClose 支持从数据源移除(纯展示请用 badge) - avatar(props):头像,有 src 渲染图片(alt 用名称)、无 src 用首字占位,size 可调 + 四档语义底色 - - alert(props):提示条,variant = info | success | warning | danger + - alert(props):提示条,variant 四档语义色 + 可选 title 与 closable 关闭按钮,role=alert 读屏可播报 - toast.info/success/warning/error(message, duration?):消息提示工厂,右上角堆叠,默认 3s 自动消失,出入场微动画;showToast(props) 为完整入参版本(closable 显示关闭按钮,同屏最多 4 条) - tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起 - popover(props, trigger):可交互气泡卡片,包裹触发器,默认点击开合 + 点外部 / Esc 收起,content 可放按钮等交互元素 diff --git a/packages/skin/ui/src/alert.ts b/packages/skin/ui/src/alert.ts index 3ac64c6..77a9d3e 100644 --- a/packages/skin/ui/src/alert.ts +++ b/packages/skin/ui/src/alert.ts @@ -1,7 +1,32 @@ import { h } from '@ui-arch/frame'; import type { AlertProps } from './types.js'; -/*** 提示条:variant 决定语义色,纯展示不持有状态 ***/ +/*** 提示条:variant 决定语义色,可选标题与关闭按钮;关闭即退场并从 DOM 移除(内容由调用方持有) ***/ export function alert(props: AlertProps): HTMLElement { - return h('div', { class: `ua-alert ua-alert-${props.variant ?? 'info'}` }, props.message); + const body = h( + 'div', + { class: 'ua-alert-body' }, + props.title ? h('div', { class: 'ua-alert-title' }, props.title) : null, + h('div', { class: 'ua-alert-message' }, props.message), + ); + const el = h('div', { class: `ua-alert ua-alert-${props.variant ?? 'info'}`, role: 'alert' }, body); + + if (!props.closable) return el; // 纯展示形态 + el.append( + h( + 'button', + { + type: 'button', + class: 'ua-alert-close', + 'aria-label': '关闭提示', + onClick: () => { + el.classList.add('ua-alert-out'); // 先退场 + window.setTimeout(() => el.isConnected && el.remove(), 200); // 过渡结束再摘除 + props.onClose?.(); + }, + }, + '×', + ), + ); + return el; } diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index 9c70f27..50430d7 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -189,7 +189,10 @@ export interface TagProps { /*** 提示条入参 ***/ export interface AlertProps { message: string; // 提示内容 + title?: string; // 可选的加粗标题行;缺省只渲染正文 variant?: 'info' | 'success' | 'warning' | 'danger'; // 语义色;缺省 info + closable?: boolean; // 显示 × 关闭按钮(退场后从 DOM 移除);缺省 false + onClose?: () => void; // 关闭回调,供调用方同步业务状态 } /*** 骨架屏入参 ***/ diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index effcc22..fe12354 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -28,7 +28,7 @@ "badge(props):徽标,variant = default | success | warning | danger", "tag(props):可关闭标签,variant 五档语义色,closable + onClose 支持从数据源移除(纯展示请用 badge)", "avatar(props):头像,有 src 渲染图片(alt 用名称)、无 src 用首字占位,size 可调 + 四档语义底色", - "alert(props):提示条,variant = info | success | warning | danger", + "alert(props):提示条,variant 四档语义色 + 可选 title 与 closable 关闭按钮,role=alert 读屏可播报", "toast.info/success/warning/error(message, duration?):消息提示工厂,右上角堆叠,默认 3s 自动消失,出入场微动画;showToast(props) 为完整入参版本(closable 显示关闭按钮,同屏最多 4 条)", "tooltip(props, trigger):悬浮提示,包裹触发器,hover / focus 延迟 150ms 出场,移出 / 失焦 / Esc 收起", "popover(props, trigger):可交互气泡卡片,包裹触发器,默认点击开合 + 点外部 / Esc 收起,content 可放按钮等交互元素", @@ -659,18 +659,37 @@ "r": 1, "d": "提示内容" }, + { + "n": "title", + "t": "string", + "d": "加粗标题行;缺省只渲染正文" + }, { "n": "variant", "t": "'info' | 'success' | 'warning' | 'danger'", "d": "语义色;缺省 info", "df": "info" + }, + { + "n": "closable", + "t": "boolean", + "d": "显示 × 关闭按钮,退场后从 DOM 移除;缺省 false", + "df": "false" + }, + { + "n": "onClose", + "t": "() => void", + "k": 1, + "d": "关闭回调,供调用方同步业务状态" } ], "example": "alert({ message: '操作可能存在风险', variant: 'warning' })", "steps": [ "按信息级别选 variant:info 提示、success 成功、warning 警告、danger 错误", "传入 message 即可,入场自带下滑动画", - "需要可关闭或带操作按钮时,外层用 h() 组合 button 自行拼装,alert 只负责语义底色" + "需要可关闭或带操作按钮时,外层用 h() 组合 button 自行拼装,alert 只负责语义底色", + "需要用户可自行消除的提示传 closable: true:点 × 淡出并从 DOM 移除,配合 onClose 同步业务状态", + "有标题与正文两层信息时传 title(加粗首行),正文仍走 message" ] }, { diff --git a/packages/skin/ui/ui.css b/packages/skin/ui/ui.css index e0f05dd..d0e2b67 100644 --- a/packages/skin/ui/ui.css +++ b/packages/skin/ui/ui.css @@ -697,8 +697,12 @@ /* —— 提示条 —— */ .ua-alert { + display: flex; + align-items: flex-start; + gap: var(--ua-space-2); width: 100%; padding: 8px 12px; + transition: opacity 0.2s ease, transform 0.2s ease; border-radius: var(--ua-radius-md); border: 1px solid; font-size: var(--ua-font-size-md); @@ -710,6 +714,33 @@ transform: translateY(-6px); } } +.ua-alert-body { + flex: 1; + min-width: 0; +} +.ua-alert-title { + margin-bottom: 2px; + font-weight: 600; +} +.ua-alert-close { + flex: none; + padding: 0 2px; + border: none; + background: none; + color: var(--ua-color-text-muted); + font-size: 14px; + line-height: 1.4; + cursor: pointer; + transition: color 0.15s; +} +.ua-alert-close:hover { + color: var(--ua-color-text); +} +/* 关闭退场:淡出 + 轻微上移,配合 200ms 后摘除节点 */ +.ua-alert-out { + opacity: 0; + transform: translateY(-4px); +} .ua-alert-info { border-color: var(--ua-color-accent); background: color-mix(in srgb, var(--ua-color-accent) 10%, transparent);