iter: d14 新增抽屉 drawer 组件
This commit is contained in:
@@ -0,0 +1,39 @@
|
||||
import { effect, h } from '@ui-arch/frame';
|
||||
import type { DrawerProps } from './types.js';
|
||||
|
||||
/*** 抽屉:open 信号驱动侧滑面板,点遮罩 / × / Esc 关闭;与 modal 的分工是不打断主视图、可从侧边保留上下文 ***/
|
||||
export function drawer(props: DrawerProps, ...children: unknown[]): HTMLElement {
|
||||
const close = (): void => {
|
||||
if (!props.open()) return; // 卫语句:已关闭不重复触发回调
|
||||
props.open(false);
|
||||
props.onClose?.();
|
||||
};
|
||||
const overlay = h('div', {
|
||||
class: () => `ua-drawer-overlay${props.open() ? ' ua-open' : ''}`,
|
||||
onClick: (e: Event) => {
|
||||
if (e.target === overlay) close(); // 卫语句:仅点遮罩本身关闭
|
||||
},
|
||||
});
|
||||
const panel = h(
|
||||
'aside',
|
||||
{
|
||||
class: `ua-drawer ua-drawer-${props.placement ?? 'right'}`,
|
||||
style: `width:${props.width ?? 320}px`,
|
||||
role: 'dialog',
|
||||
'aria-hidden': () => String(!props.open()),
|
||||
},
|
||||
h('div', { class: 'ua-drawer-head' }, h('h3', { class: 'ua-drawer-title' }, props.title), h('button', { class: 'ua-drawer-close', 'aria-label': '关闭抽屉', onClick: close }, '×')),
|
||||
h('div', { class: 'ua-drawer-body' }, ...children),
|
||||
props.footer ? h('div', { class: 'ua-drawer-foot' }, props.footer) : null,
|
||||
);
|
||||
overlay.append(panel);
|
||||
|
||||
effect(() => {
|
||||
if (!props.open()) return;
|
||||
(panel.querySelector('button, input, textarea') as HTMLElement | null)?.focus(); // 打开时聚焦首个可交互元素
|
||||
});
|
||||
document.addEventListener('keydown', (e: KeyboardEvent) => {
|
||||
if (e.key === 'Escape' && props.open()) close();
|
||||
});
|
||||
return overlay;
|
||||
}
|
||||
Reference in New Issue
Block a user