iter(g98): 弹窗与抽屉补遮罩关闭开关

This commit is contained in:
HIsheR
2026-10-26 13:16:32 +08:00
parent 13266f0816
commit c32f20cc9b
8 changed files with 53 additions and 5 deletions
+8
View File
@@ -1140,6 +1140,14 @@
"acceptance": "npm run changelog 重新生成(267 提交),changelog:check 一致(提交本条后按约定再差一条);npm run check 全绿",
"notes": "自补:发版前刷新步骤,收尾统一执行",
"status": "done"
},
{
"id": "g98",
"title": "弹窗与抽屉补遮罩关闭开关",
"motivation": "modal/drawer 点遮罩必关,表单类弹窗填到一半误触就丢内容;调用方没有任何开关能保留 × 与 Esc 的同时禁掉遮罩关闭",
"acceptance": "ModalProps / DrawerProps 新增 closeOnOverlay(缺省 true);传 false 时点遮罩不关闭,× 与 Esc 行为不变;文档参数表与演示(防误关弹窗实例)同步;npm run check 全绿",
"notes": "自补:可用性;遮罩点击处理改成显式卫语句,语义比一长串 && 更清楚",
"status": "open"
}
]
}
+11 -1
View File
@@ -1,6 +1,6 @@
{
"$schema": "ui-arch-registry-index/0.1",
"generatedAt": "2026-10-26T05:14:42.470Z",
"generatedAt": "2026-10-26T05:15:56.401Z",
"repoRoot": ".",
"packages": [
{
@@ -1578,6 +1578,11 @@
"t": "unknown",
"d": "底部操作区内容(常见为按钮组,右对齐);缺省不渲染"
},
{
"n": "closeOnOverlay",
"t": "boolean",
"d": "点遮罩是否关闭弹窗;缺省 true,表单类可传 false 防误关(× 与 Esc 仍可用)"
},
{
"n": "onClose",
"t": "() => void",
@@ -1634,6 +1639,11 @@
"t": "unknown",
"d": "底部操作区内容;缺省不渲染"
},
{
"n": "closeOnOverlay",
"t": "boolean",
"d": "点遮罩是否关闭抽屉;缺省 true(× 与 Esc 始终可用)"
},
{
"n": "onClose",
"t": "() => void",
+13 -1
View File
@@ -140,6 +140,7 @@ const name = signal('');
const agreed = signal(false);
const nightMode = signal(true);
const sheetOpen = signal(false); // 底部抽屉开合
const stickyOpen = signal(false); // 防误关弹窗开合
const sound = signal(true); // 无可见文案的开关演示
const city = signal('');
const size = signal('m');
@@ -445,10 +446,21 @@ const content = h(
section(
'sec-tabs-modal',
'标签页与弹窗',
'tabs 滑动指示条 + 方向键切换(←→),禁用页签置灰;modal 支持 Esc / 遮罩 / × 关闭,弹窗内的下拉展开时 Esc 先收下拉、再按才关弹窗(逐层关闭)。',
'tabs 滑动指示条 + 方向键切换(←→),禁用页签置灰;modal 支持 Esc / 遮罩 / × 关闭(closeOnOverlay: false 时点遮罩不关、防填一半误触),弹窗内的下拉展开时 Esc 先收下拉、再按才关弹窗(逐层关闭)。',
tabs({ tabs: [{ value: 'a', label: '概览' }, { value: 'b', label: '明细' }, { value: 'c', label: '设置' }, { value: 'd', label: '已停用', disabled: true }], active: activeTab }),
h('span', { class: 'out' }, () => `当前页签:${activeTab()}`),
button({ label: '打开弹窗', onClick: () => modalOpen(true) }),
button({ label: '打开防误关弹窗', variant: 'ghost', onClick: () => stickyOpen(true) }),
modal(
{
title: '填写中,点遮罩不关闭',
open: stickyOpen,
closeOnOverlay: false,
onClose: () => stickyOpen(false),
footer: h('div', { class: 'row' }, button({ label: '关闭', variant: 'ghost', onClick: () => stickyOpen(false) })),
},
h('p', null, 'closeOnOverlay: false —— 点遮罩不会关闭,防止填到一半误触丢失内容;× 与 Esc 仍然有效。'),
),
modal(
{
title: '确认操作',
+3 -1
View File
@@ -1,6 +1,6 @@
# @ui-arch 组件库 Agent 文档(无图形版)
> 自动生成于 2026-10-26T05:14:42.470Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 自动生成于 2026-10-26T05:15:56.401Z,数据源:各包 ua.manifest.json,勿手改。人类版文档站:apps/docs/index.html。
> 组件 = 普通函数,传 props 返回 DOM;状态用 signal 双向绑定:读 signal() 写 signal(v)。
## 快速上手
@@ -842,6 +842,7 @@ const page = signal(1); pagination({ page, pageSize: 3, total: 24, onChange: (p)
- title(必填):string —— 标题
- size(默认 md):'sm' | 'md' | 'lg' —— 宽度档位:sm 340px / md 420px / lg 640px;缺省 md
- footer:unknown —— 底部操作区内容(常见为按钮组,右对齐);缺省不渲染
- closeOnOverlay:boolean —— 点遮罩是否关闭弹窗;缺省 true,表单类可传 false 防误关(× 与 Esc 仍可用)
- onClose(回调):() => void —— 关闭回调(点遮罩、× 或 Esc 触发)
- ...children:unknown[] —— 弹窗内容子节点
@@ -871,6 +872,7 @@ const open = signal(false); modal({ title: '确认操作', open, onClose: () =>
- placement(默认 right):'left' | 'right' | 'top' | 'bottom' —— 滑出方向;缺省 right
- width(默认 320):number —— 面板尺寸(像素):左右滑出为宽度,上下滑出为高度;缺省 320
- footer:unknown —— 底部操作区内容;缺省不渲染
- closeOnOverlay:boolean —— 点遮罩是否关闭抽屉;缺省 true(× 与 Esc 始终可用)
- onClose(回调):() => void —— 关闭回调(点遮罩 / × / Esc 触发)
- ...children:unknown[] —— 面板内容子节点
+3 -1
View File
@@ -15,7 +15,9 @@ export function drawer(props: DrawerProps, ...children: unknown[]): HTMLElement
const overlay = h('div', {
class: () => `ua-drawer-overlay${props.open() ? ' ua-open' : ''}`,
onClick: (e: Event) => {
if (e.target === overlay) close(); // 卫语句:仅点遮罩本身关闭
if (e.target !== overlay) return; // 卫语句:只处理点在遮罩本身的
if (props.closeOnOverlay === false) return; // 显式禁止时防误关,× 与 Esc 仍可用
close();
},
});
const panel = h(
+3 -1
View File
@@ -15,7 +15,9 @@ export function modal(props: ModalProps, ...children: unknown[]): HTMLElement {
const overlay = h('div', {
class: 'ua-modal-overlay',
onClick: (e: Event) => {
if (e.target === overlay) close(); // 卫语句:仅点遮罩本身关闭
if (e.target !== overlay) return; // 卫语句:只处理点在遮罩本身的
if (props.closeOnOverlay === false) return; // 显式禁止时防误关,× 与 Esc 仍可用
close();
},
});
const box = h(
+2
View File
@@ -336,6 +336,7 @@ export interface ModalProps {
open: Signal<boolean>; // 开关信号:true 显示 / false 隐藏
size?: 'sm' | 'md' | 'lg'; // 宽度档位;缺省 md(420px),sm 340px / lg 640px
footer?: unknown; // 底部操作区内容(常见为按钮组);缺省不渲染
closeOnOverlay?: boolean; // 点遮罩是否关闭;缺省 true(表单类弹窗可传 false 防误关,× 与 Esc 仍可用)
onClose?: () => void; // 关闭回调(点遮罩、× 或 Esc 触发)
}
@@ -346,6 +347,7 @@ export interface DrawerProps {
placement?: 'left' | 'right' | 'top' | 'bottom'; // 滑出方向;缺省 right
width?: number; // 面板尺寸像素:左右滑出为宽度,上下滑出为高度;缺省 320
footer?: unknown; // 底部操作区内容;缺省不渲染
closeOnOverlay?: boolean; // 点遮罩是否关闭;缺省 true(× 与 Esc 始终可用)
onClose?: () => void; // 关闭回调(遮罩 / × / Esc 触发)
}
+10
View File
@@ -1449,6 +1449,11 @@
"t": "unknown",
"d": "底部操作区内容(常见为按钮组,右对齐);缺省不渲染"
},
{
"n": "closeOnOverlay",
"t": "boolean",
"d": "点遮罩是否关闭弹窗;缺省 true,表单类可传 false 防误关(× 与 Esc 仍可用)"
},
{
"n": "onClose",
"t": "() => void",
@@ -1505,6 +1510,11 @@
"t": "unknown",
"d": "底部操作区内容;缺省不渲染"
},
{
"n": "closeOnOverlay",
"t": "boolean",
"d": "点遮罩是否关闭抽屉;缺省 true(× 与 Esc 始终可用)"
},
{
"n": "onClose",
"t": "() => void",