iter(g28): 浮层 Esc 逐层关闭,阻止冒泡连带关外层
This commit is contained in:
@@ -35,7 +35,7 @@ function openViewer(src: string, alt?: string): void {
|
||||
document.removeEventListener('keydown', onKey);
|
||||
prev?.focus?.();
|
||||
};
|
||||
const onKey = (e: KeyboardEvent) => e.key === 'Escape' && close();
|
||||
const onKey = (e: KeyboardEvent) => { if (e.key !== 'Escape') return; e.stopPropagation(); close(); }; // 预览层 Esc 自关,不连带关外层
|
||||
mask.addEventListener('click', close);
|
||||
document.addEventListener('keydown', onKey);
|
||||
document.body.appendChild(mask);
|
||||
|
||||
@@ -73,6 +73,7 @@ export function menu(props: MenuProps): HTMLElement {
|
||||
|
||||
root.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') {
|
||||
e.stopPropagation(); // 只关本层:不再冒泡去关外层的弹窗/抽屉
|
||||
open(false);
|
||||
trigger.focus(); // 收起后焦点回到触发器,键盘流不断
|
||||
return;
|
||||
|
||||
@@ -53,6 +53,7 @@ export function popover(props: PopoverProps, trigger: HTMLElement): HTMLElement
|
||||
}
|
||||
root.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key !== 'Escape' || !open()) return; // 卫语句:未展开时 Esc 不处理
|
||||
e.stopPropagation(); // 只关本层,避免连带关闭外层弹窗
|
||||
setOpen(false);
|
||||
trigger.focus(); // 收起后焦点回触发器
|
||||
});
|
||||
|
||||
@@ -65,7 +65,7 @@ export function select(props: SelectProps): HTMLElement {
|
||||
};
|
||||
|
||||
root.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') { open(false); trigger.focus(); return; } // Esc 关闭并回焦触发器
|
||||
if (e.key === 'Escape') { e.stopPropagation(); open(false); trigger.focus(); return; } // Esc 只关本层并回焦触发器
|
||||
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
|
||||
e.preventDefault(); // 阻止页面滚动
|
||||
if (!open()) { open(true); options[0]?.focus(); return; } // 未展开:展开并聚焦首个选项
|
||||
|
||||
@@ -49,7 +49,7 @@ export function tooltip(props: TooltipProps, trigger: HTMLElement): HTMLElement
|
||||
root.addEventListener('focusout', hide); // 失焦
|
||||
effect(() => { if (open()) place(flip(trigger, bubble, props.placement ?? 'top')); }); // 每次出场重算方位:空间不足自动翻转
|
||||
root.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape') hide(); // Esc 立即收起,不必等延迟
|
||||
if (e.key === 'Escape') { e.stopPropagation(); hide(); } // Esc 立即收起且不影响外层弹层
|
||||
});
|
||||
return root;
|
||||
}
|
||||
|
||||
@@ -498,7 +498,8 @@
|
||||
"准备 options 数组,value 是提交用值、label 是展示文案",
|
||||
"创建信号并传入 value;未传时组件内部自持状态",
|
||||
"点击触发器展开弹层,点选项写回信号并收起;点外部或按 Esc 也会收起",
|
||||
"选中项在弹层中用淡色弱化标记,不抢视觉焦点"
|
||||
"选中项在弹层中用淡色弱化标记,不抢视觉焦点",
|
||||
"弹层展开时按 Esc 只收起下拉并回焦触发器;若下拉在弹窗/抽屉内,再按一次 Esc 才关外层(逐层关闭)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -544,7 +545,8 @@
|
||||
"点触发器展开弹层,点条目收起并触发 onSelect;点外部或按 Esc 也会收起(Esc 后焦点回到触发器)",
|
||||
"条目要给快捷键提示时传 shortcut(如 '⌘K'):右侧灰字展示,组件不绑定按键,实际快捷键由调用方在全局监听",
|
||||
"键盘:Tab 聚焦触发器,↑↓ 展开并在可用条目间环形移动,Enter / Space 选中;disabled 项自动跳过",
|
||||
"靠右对齐避免溢出时传 align: 'end';危险操作给条目加 danger: true"
|
||||
"靠右对齐避免溢出时传 align: 'end';危险操作给条目加 danger: true",
|
||||
"展开时按 Esc 只收起菜单并回焦触发器,不会连带关闭所在弹窗(逐层关闭)"
|
||||
]
|
||||
},
|
||||
{
|
||||
@@ -979,7 +981,8 @@
|
||||
"点击触发器开合;点弹层外部或按 Esc 收起(Esc 后焦点回触发器)",
|
||||
"content 里可以放 button / checkbox 等交互元素(tooltip 只能纯文本),点击弹层内部不会误关",
|
||||
"hover 场景传 trigger: 'hover' + delay 控制多快出场;placement: 'top' 让弹层往上翻",
|
||||
"需要感知开合做副作用(如懒加载数据)时用 onOpenChange"
|
||||
"需要感知开合做副作用(如懒加载数据)时用 onOpenChange",
|
||||
"展开时按 Esc 只收起气泡并回焦触发器,不会连带关闭所在弹窗(逐层关闭)"
|
||||
]
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user