iter(g141): 通知支持四角停靠

This commit is contained in:
HIsheR
2026-10-26 15:36:28 +08:00
parent 36087b1b20
commit 6cde61829e
8 changed files with 54 additions and 13 deletions
+11 -9
View File
@@ -1,15 +1,17 @@
import { h } from '@ui-arch/frame';
import type { NotificationProps } from './types.js';
let host: HTMLElement | null = null; // 右下角堆叠容器:首条通知出现时懒创建
const MAX_STACK = 3; // 同屏最多条数,超出挤掉最早一条
const hosts = new Map<string, HTMLElement>(); // 每个角落一个堆叠容器,首次用到该角落时懒创建
const MAX_STACK = 3; // 同一角落最多条数,超出挤掉最早一条
/*** 确保堆叠容器存在:fixed 挂 body 末尾,与右上角 toast 分区不打架 ***/
function ensureHost(): HTMLElement {
if (host) return host;
host = h('div', { class: 'ua-notice-host' });
document.body.appendChild(host);
return host;
/*** 确保指定角落的堆叠容器存在:fixed 挂 body 末尾,与 toast 的右上角分区不打架 ***/
function ensureHost(place: string): HTMLElement {
const hit = hosts.get(place);
if (hit) return hit;
const el = h('div', { class: `ua-notice-host is-${place}` });
document.body.appendChild(el);
hosts.set(place, el);
return el;
}
/*** 退场并移除:摘 ua-open 触发过渡,transitionend 与 320ms 超时二选一兜底 ***/
@@ -61,7 +63,7 @@ export function notification(props: NotificationProps): { el: HTMLElement; close
el.addEventListener('focusin', pause); // 键盘聚焦到关闭/操作按钮同样暂停
el.addEventListener('focusout', resume);
const stack = ensureHost();
const stack = ensureHost(props.placement ?? 'bottom-right'); // 缺省右下,与右上角 toast 错开
if (stack.childElementCount >= MAX_STACK) stack.firstElementChild?.remove(); // 超出上限挤掉最早一条
stack.appendChild(el);
requestAnimationFrame(() => el.classList.add('ua-open')); // 下一帧入场,保证过渡生效
+1
View File
@@ -486,6 +486,7 @@ export interface NotificationProps {
duration?: number; // 自动关闭毫秒;缺省 0 = 常驻(通知通常要读完)
closable?: boolean; // 是否显示关闭按钮;缺省 true
action?: unknown; // 操作区内容(如按钮);缺省不渲染
placement?: 'top-right' | 'bottom-right' | 'top-left' | 'bottom-left'; // 停靠角落;缺省 bottom-right(避开右上角 toast)
}
/*** 文件选择入参 ***/
+8 -1
View File
@@ -2240,6 +2240,12 @@
"n": "action",
"t": "unknown",
"d": "操作区内容(如按钮);缺省不渲染"
},
{
"n": "placement",
"t": "'top-right' | 'bottom-right' | 'top-left' | 'bottom-left'",
"df": "bottom-right",
"d": "停靠角落;每个角落独立堆叠(同角最多 3 条),右上与 toast 同侧,建议次要信息放左侧"
}
],
"example": "const { close } = notification({ title: '导出完成', description: 'report.csv 已开始下载', variant: 'success', duration: 4000 }); // close() 手动关闭",
@@ -2248,7 +2254,8 @@
"缺省常驻(duration 0),需要自动消失就传毫秒数,如 duration: 4000",
"返回 { el, close } 句柄:程序化关闭用 close(),需要自己挂交互就用 el",
"action 放操作区(常见为按钮);variant 决定左侧条与圆点语义色",
"与 toast 的分工:toast 右上角轻量瞬时,notification 右下角可长读、可操作"
"与 toast 的分工:toast 右上角轻量瞬时,notification 右下角可长读、可操作",
"停靠角落用 placement 调:四个角各自独立堆叠与节流,顶部角落新通知从屏幕边缘长出、旧的往下让"
]
},
{
+13
View File
@@ -4399,3 +4399,16 @@ h5.ua-type-title { font-size: var(--ua-font-size-md); }
outline: 2px solid var(--ua-color-accent);
outline-offset: -2px; /* 环画在行内,避免被表格滚动容器裁掉 */
}
/* —— 通知角落:右上与 toast 同侧,左列放次要信息 —— */
.ua-notice-host.is-top-right,
.ua-notice-host.is-top-left {
top: var(--ua-space-4);
bottom: auto;
flex-direction: column-reverse; /* 新通知贴着屏幕边缘出现,旧的下移 */
}
.ua-notice-host.is-top-left,
.ua-notice-host.is-bottom-left {
left: var(--ua-space-4);
right: auto;
}