diff --git a/.ua/index.json b/.ua/index.json index 0c1ec82..965a436 100644 --- a/.ua/index.json +++ b/.ua/index.json @@ -1,6 +1,6 @@ { "$schema": "ui-arch-registry-index/0.1", - "generatedAt": "2026-10-26T08:21:19.789Z", + "generatedAt": "2026-10-26T08:22:46.231Z", "repoRoot": ".", "packages": [ { @@ -3181,7 +3181,7 @@ "n": "onConfirm", "t": "() => void", "k": 1, - "d": "点确定后的回调(此时弹层已收起)" + "d": "点确定后的回调:普通回调先收起再执行;返回 Promise 时按钮转「处理中…」并禁用,成功才收起、失败留在气泡里可重试" }, { "n": "onCancel", @@ -3200,7 +3200,8 @@ "把要保护的触发器元素(按钮 / 图标)作为第二个参数传进去,返回的包裹节点替换原位置", "写清 title(问句)与 description(影响范围),删除类操作把 variant 设成 danger,确认按钮会自动变成危险色", "点确定先收起弹层再触发 onConfirm,回调里可以放心同步改数据;取消、点外部、Esc 一律走 onCancel", - "展开时焦点自动落在「取消」上,误按回车不会执行危险操作;需要外部控制开合时传 open 信号" + "展开时焦点自动落在「取消」上,误按回车不会执行危险操作;需要外部控制开合时传 open 信号", + "删除 / 归档这类要打后端的操作把 onConfirm 写成 async:气泡不会立刻收起,确认按钮变「处理中…」并禁用,resolve 后才关,reject 时保持展开供重试" ] }, { diff --git a/apps/demo/main.ts b/apps/demo/main.ts index 67c7b2d..8fc4bc5 100644 --- a/apps/demo/main.ts +++ b/apps/demo/main.ts @@ -1370,6 +1370,12 @@ const content = h( onCancel: () => toast.info('已取消'), }, button({ label: '删除记录', variant: 'danger' })), popconfirm({ title: '发布到生产?', description: '发布后 1 分钟内全量生效。', confirmText: '发布', onConfirm: () => toast.success('已发布') }, button({ label: '发布', variant: 'ghost' })), + popconfirm({ // 异步确认:Promise 期间按钮转「处理中…」并禁用,成功才收起 + title: '归档这批任务?', + description: '调用后端需要约 1 秒,期间按钮保持 loading,失败则留在气泡里可重试。', + confirmText: '归档', + onConfirm: async () => { await new Promise((r) => setTimeout(r, 1000)); toast.success('已归档'); }, + }, button({ label: '归档(异步)', variant: 'ghost' })), ), section( 'sec-calendar', diff --git a/llms-full.txt b/llms-full.txt index 15b9a8d..4c02ada 100644 --- a/llms-full.txt +++ b/llms-full.txt @@ -1,6 +1,6 @@ # @ui-arch 组件库 Agent 文档(无图形版) -> 自动生成于 2026-10-26T08:21:19.789Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 +> 自动生成于 2026-10-26T08:22:46.231Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。 > 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。 ## 快速上手 @@ -1671,7 +1671,7 @@ anchor({ items: [{ href: '#sec-button', title: '按钮' }, { href: '#sec-card', - cancelText:string —— 取消按钮文案;缺省「取消」 - variant:'default' | 'danger' —— 确认按钮语义色;删除类操作传 danger,缺省 default - placement:'top' | 'bottom' —— 气泡方位;缺省 top,压在触发器上方不盖住被操作的行 -- onConfirm(回调):() => void —— 点确定后的回调(此时弹层已收起) +- onConfirm(回调):() => void —— 点确定后的回调:普通回调先收起再执行;返回 Promise 时按钮转「处理中…」并禁用,成功才收起、失败留在气泡里可重试 - onCancel(回调):() => void —— 取消 / 点外部 / Esc 收起时的回调 - open:Signal —— 受控开合信号;不传则内部维护,传了可由外部编程开合 @@ -1687,6 +1687,7 @@ popconfirm({ title: '删除这条记录?', description: '删除后无法恢复 2. 写清 title(问句)与 description(影响范围),删除类操作把 variant 设成 danger,确认按钮会自动变成危险色 3. 点确定先收起弹层再触发 onConfirm,回调里可以放心同步改数据;取消、点外部、Esc 一律走 onCancel 4. 展开时焦点自动落在「取消」上,误按回车不会执行危险操作;需要外部控制开合时传 open 信号 +5. 删除 / 归档这类要打后端的操作把 onConfirm 写成 async:气泡不会立刻收起,确认按钮变「处理中…」并禁用,resolve 后才关,reject 时保持展开供重试 现场演示:apps/docs/demo.html#sec-popconfirm diff --git a/packages/skin/ui/src/popconfirm.ts b/packages/skin/ui/src/popconfirm.ts index fb9384f..0771952 100644 --- a/packages/skin/ui/src/popconfirm.ts +++ b/packages/skin/ui/src/popconfirm.ts @@ -12,12 +12,19 @@ export function popconfirm(props: PopconfirmProps, trigger: HTMLElement): HTMLEl /*** 收起弹层:写回信号即触发 popover 的显隐与 Esc 栈清理 ***/ const close = (): void => { open(false); }; - /*** 确认:先收起再回调,避免回调里同步改数据时弹层还开着 ***/ + const idle = props.confirmText ?? '确定'; // 确认按钮常态文案,异步结束后还原 + + /*** 确认:同步回调先收起再执行(避免回调里改数据时弹层还开着);返回 Promise 时就地 loading,成功才收起、失败留在弹层重试 ***/ const accept = (): void => { - accepted = true; - close(); - props.onConfirm(); + const out = props.onConfirm(); + if (!(out instanceof Promise)) { accepted = true; close(); return; } + okBtn.disabled = true; + okBtn.textContent = '处理中…'; + out.then(() => { accepted = true; close(); }) + .catch(() => { /* 失败保持展开:提示交给调用方的 toast */ }) + .finally(() => { okBtn.disabled = false; okBtn.textContent = idle; }); }; + const okBtn = button({ label: idle, variant: props.variant === 'danger' ? 'danger' : 'primary', onClick: () => accept() }) as HTMLButtonElement; const body = h( 'div', @@ -27,7 +34,7 @@ export function popconfirm(props: PopconfirmProps, trigger: HTMLElement): HTMLEl 'div', { class: 'ua-popconfirm-actions' }, button({ label: props.cancelText ?? '取消', variant: 'ghost', onClick: () => close() }), - button({ label: props.confirmText ?? '确定', variant: props.variant === 'danger' ? 'danger' : 'primary', onClick: () => accept() }), + okBtn, ), ); diff --git a/packages/skin/ui/src/types.ts b/packages/skin/ui/src/types.ts index 0f21d48..e4497d3 100644 --- a/packages/skin/ui/src/types.ts +++ b/packages/skin/ui/src/types.ts @@ -367,7 +367,7 @@ export interface ModalProps { footer?: unknown; // 底部操作区内容(常见为按钮组);缺省不渲染 confirmText?: string; // 内置页脚:确认按钮文案;与 footer 二选一(footer 优先),缺省「确定」 cancelText?: string; // 内置页脚:取消按钮文案;缺省「取消」 - onConfirm?: () => void | Promise; // 内置页脚:确认回调;返回 Promise 时装 loading 禁用按钮,成功才收窗、失败留在窗口重试 + onConfirm?: () => unknown; // 内置页脚:确认回调;返回 Promise 时按钮装 loading 并禁用,成功才收窗、失败留在窗口重试 closeOnOverlay?: boolean; // 点遮罩是否关闭;缺省 true(表单类弹窗可传 false 防误关,× 与 Esc 仍可用) onClose?: () => void; // 关闭回调(点遮罩、× 或 Esc 触发) } @@ -769,7 +769,7 @@ export interface PopconfirmProps { cancelText?: string; // 取消按钮文案;缺省「取消」 variant?: 'default' | 'danger'; // 确认按钮语义色;缺省 default,删除类操作传 danger placement?: 'top' | 'bottom'; // 气泡方位;缺省 top(不盖住被操作的行) - onConfirm: () => void; // 点确定后的回调(弹层已收起) + onConfirm: () => unknown; // 点确定后的回调:普通回调先收起再执行;返回 Promise 时留在弹层等结果(成功才收起、失败可重试) onCancel?: () => void; // 取消 / 点外部 / Esc 收起时的回调 open?: Signal; // 受控开合信号;不传则内部维护 } diff --git a/packages/skin/ui/ua.manifest.json b/packages/skin/ui/ua.manifest.json index 497c26c..80d7965 100644 --- a/packages/skin/ui/ua.manifest.json +++ b/packages/skin/ui/ua.manifest.json @@ -3052,7 +3052,7 @@ "n": "onConfirm", "t": "() => void", "k": 1, - "d": "点确定后的回调(此时弹层已收起)" + "d": "点确定后的回调:普通回调先收起再执行;返回 Promise 时按钮转「处理中…」并禁用,成功才收起、失败留在气泡里可重试" }, { "n": "onCancel", @@ -3071,7 +3071,8 @@ "把要保护的触发器元素(按钮 / 图标)作为第二个参数传进去,返回的包裹节点替换原位置", "写清 title(问句)与 description(影响范围),删除类操作把 variant 设成 danger,确认按钮会自动变成危险色", "点确定先收起弹层再触发 onConfirm,回调里可以放心同步改数据;取消、点外部、Esc 一律走 onCancel", - "展开时焦点自动落在「取消」上,误按回车不会执行危险操作;需要外部控制开合时传 open 信号" + "展开时焦点自动落在「取消」上,误按回车不会执行危险操作;需要外部控制开合时传 open 信号", + "删除 / 归档这类要打后端的操作把 onConfirm 写成 async:气泡不会立刻收起,确认按钮变「处理中…」并禁用,resolve 后才关,reject 时保持展开供重试" ] }, {