init: @ui-arch 私人组件库 monorepo
- core/table-core: Headless 表格内核(排序/筛选/分页/选择插件 + 冒烟 9 项) - core/frame: signal/computed/effect + hyperscript 微框架(零依赖) - skin/ui: 16 个 DOM 组件(含自绘 select、滑动指示条 tabs、行选择 dataTable、form 表单校验) - design/tokens: --ua-* 设计令牌(light/dark) - tools/cli: ua 命令行(index/list/info/docs/style/mcp)+ MCP 注册表服务 - apps: demo 演示站(esbuild 单文件)+ docs 双轨文档(人类版 + llms-full.txt)
This commit is contained in:
@@ -0,0 +1,33 @@
|
||||
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' },
|
||||
h('div', { class: 'ua-modal-head' }, h('h3', { class: 'ua-modal-title' }, props.title), h('button', { class: 'ua-modal-close', onClick: close }, '×')),
|
||||
h('div', { class: 'ua-modal-body' }, ...children),
|
||||
);
|
||||
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;
|
||||
}
|
||||
Reference in New Issue
Block a user