import { effect, h } from '@ui-arch/frame'; import type { ModalProps } from './types.js'; /*** 弹窗:open 信号驱动显隐,点遮罩、× 或 Esc 触发 onClose ***/ export function modal(props: ModalProps, ...children: unknown[]): HTMLElement { const close = () => { if (!props.open()) return; // 卫语句:已关闭不重复触发回调 props.open(false); // 写回信号触发隐藏 props.onClose?.(); }; const overlay = h('div', { class: 'ua-modal-overlay', onClick: (e: Event) => { if (e.target === overlay) close(); // 卫语句:仅点遮罩本身关闭 }, }); const box = h( 'div', { class: `ua-modal ua-modal-${props.size ?? 'md'}` }, h('div', { class: 'ua-modal-head' }, h('h3', { class: 'ua-modal-title' }, props.title), h('button', { type: 'button', class: 'ua-modal-close', 'aria-label': '关闭弹窗', onClick: close }, '×')), h('div', { class: 'ua-modal-body' }, ...children), props.footer ? h('div', { class: 'ua-modal-foot' }, props.footer) : null, // 底部操作区:右对齐,仅传了才渲染 ); overlay.append(box); effect(() => { const open = props.open(); overlay.classList.toggle('ua-open', open); // 显隐跟随信号 if (open) (box.querySelector('button, input, textarea') as HTMLElement | null)?.focus(); // 打开时聚焦首个可交互元素 }); document.addEventListener('keydown', (e: KeyboardEvent) => { if (e.key === 'Escape' && props.open()) close(); // Esc 关闭当前打开的弹窗 }); return overlay; }