release: v0.4.0 — React 适配器、loading链式id稳定、dragThreshold、RTL适配、dedupe插件
- React 适配器子包:@metona-team/metona-toast/react — useToast() hook + 声明式 <Toast /> 组件,组件卸载自动清理;react 为 optional peerDependency,主包保持零依赖 - loading 链式转换改原地 update:id 稳定不重建 DOM,转换后 duration 恢复默认自动关闭;update() 支持 duration 变更动态重启计时器 - _emit 幽灵实例修复:beforeShow 拦截后的 toast 不再注册进 _toasts - dragThreshold 配置项(默认 120px,原硬编码);RTL 容器 dir 属性 + 进度条/side 条/色条镜像 - dedupe 预设插件:相同 type+message 自动去重,支持 uninstall - jest 环境隔离测试独立成 tests/ssr.test.ts(resetModules 不再污染共享模块状态);新增 tests/setup.ts 补 TextEncoder - 文档:README/docs.html 补 React 适配器、dedupe、dragThreshold;CHANGELOG 更新;328 测试全过
This commit is contained in:
Vendored
+108
-20
@@ -7,7 +7,7 @@
|
||||
/**
|
||||
* MetonaToast Utils — 工具函数
|
||||
* @module utils
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 生成唯一ID
|
||||
@@ -44,7 +44,7 @@
|
||||
/**
|
||||
* MetonaToast Icons — 图标SVG定义
|
||||
* @module icons
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description 107 个内置 SVG 图标
|
||||
*/
|
||||
const ICONS = {
|
||||
@@ -541,7 +541,7 @@
|
||||
/**
|
||||
* MetonaToast Locales — 国际化翻译数据
|
||||
* @module locales
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description 内置 zh-CN / en-US 完整翻译
|
||||
*/
|
||||
const LOCALES = {
|
||||
@@ -1028,12 +1028,12 @@
|
||||
/**
|
||||
* MetonaToast Constants — 常量定义
|
||||
* @module constants
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 版本号 — 唯一来源,发布时只需修改此处
|
||||
*/
|
||||
const VERSION = '0.3.0';
|
||||
const VERSION = '0.4.0';
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
@@ -1046,6 +1046,7 @@
|
||||
pauseOnHover: true,
|
||||
closeOnClick: true,
|
||||
draggable: true,
|
||||
dragThreshold: 120,
|
||||
showProgress: true,
|
||||
progressDirection: 'horizontal',
|
||||
icon: true,
|
||||
@@ -1299,7 +1300,7 @@
|
||||
/**
|
||||
* MetonaToast Styles — 样式管理
|
||||
* @module styles
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 样式缓存
|
||||
let styleElement = null;
|
||||
@@ -1657,6 +1658,41 @@
|
||||
transition: transform 0.1s linear;
|
||||
}
|
||||
|
||||
/* RTL 镜像:进度条从右向左收缩、side 条移到右侧、类型色条翻转到右边 */
|
||||
[dir="rtl"] .met-bar {
|
||||
transform-origin: right;
|
||||
}
|
||||
[dir="rtl"] .met-side {
|
||||
left: auto;
|
||||
right: 0;
|
||||
border-radius: 0 12px 12px 0;
|
||||
}
|
||||
[dir="rtl"] .met-progress-v {
|
||||
left: auto;
|
||||
right: 0;
|
||||
border-radius: 0 12px 12px 0;
|
||||
}
|
||||
[dir="rtl"] .met-toast.met-success {
|
||||
border-left-width: 1px;
|
||||
border-right: 4px solid #10b981;
|
||||
}
|
||||
[dir="rtl"] .met-toast.met-error {
|
||||
border-left-width: 1px;
|
||||
border-right: 4px solid #ef4444;
|
||||
}
|
||||
[dir="rtl"] .met-toast.met-warning {
|
||||
border-left-width: 1px;
|
||||
border-right: 4px solid #f59e0b;
|
||||
}
|
||||
[dir="rtl"] .met-toast.met-info {
|
||||
border-left-width: 1px;
|
||||
border-right: 4px solid #3b82f6;
|
||||
}
|
||||
[dir="rtl"] .met-toast.met-loading {
|
||||
border-left-width: 1px;
|
||||
border-right: 4px solid #6366f1;
|
||||
}
|
||||
|
||||
.met-container::-webkit-scrollbar { width: 6px; height: 6px; }
|
||||
.met-container::-webkit-scrollbar-track { background: transparent; }
|
||||
.met-container::-webkit-scrollbar-thumb { background: rgba(0,0,0,0.2); border-radius: 3px; }
|
||||
@@ -1753,7 +1789,7 @@
|
||||
/**
|
||||
* MetonaToast Themes — 主题管理
|
||||
* @module themes
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 当前主题状态
|
||||
let currentTheme = 'auto';
|
||||
@@ -2097,7 +2133,7 @@
|
||||
/**
|
||||
* MetonaToast i18n — 国际化管理
|
||||
* @module i18n
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 当前语言状态
|
||||
let currentLocale = 'zh-CN';
|
||||
@@ -2772,7 +2808,7 @@
|
||||
/**
|
||||
* MetonaToast Toast — Toast 类
|
||||
* @module toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* Toast 类 — 核心通知组件
|
||||
@@ -2933,6 +2969,9 @@
|
||||
el.className = `met-container ${position}`;
|
||||
el.setAttribute('aria-label', 'Notifications');
|
||||
el.setAttribute('role', 'region');
|
||||
// RTL 语言设置容器文字方向,使内容/关闭按钮/进度条正确镜像
|
||||
if (isRTL)
|
||||
el.setAttribute('dir', 'rtl');
|
||||
const posStyles = {
|
||||
'top-left': 'top:0;left:0;align-items:flex-start',
|
||||
'top-center': 'top:0;left:0;right:0;align-items:center',
|
||||
@@ -3124,7 +3163,8 @@
|
||||
dragging = false;
|
||||
el.releasePointerCapture(e.pointerId);
|
||||
el.style.transition = '';
|
||||
if (Math.abs(dx) > 120) {
|
||||
const threshold = this.config.dragThreshold ?? 120;
|
||||
if (Math.abs(dx) > threshold) {
|
||||
el.style.transform = `translate(${dx * 2}px, ${dy}px) rotate(${dx * 0.2}deg)`;
|
||||
el.style.opacity = '0';
|
||||
setTimeout(() => this.close(true), 250);
|
||||
@@ -3242,6 +3282,18 @@
|
||||
: (this.message ? `<div class="met-message">${escapeHTML(this.message)}</div>` : '');
|
||||
content.innerHTML = `${safeTitle}${safeMessage}`;
|
||||
}
|
||||
// duration 变更:重启或停止计时器(loading 0 → N 转换、动态调整时长等场景)
|
||||
if (partial.duration !== undefined && partial.duration !== this.config.duration) {
|
||||
this.config.duration = partial.duration;
|
||||
if (this.rafId !== null)
|
||||
cancelAnimationFrame(this.rafId);
|
||||
this.rafId = null;
|
||||
this.remaining = Math.max(0, partial.duration);
|
||||
if (partial.duration > 0 && !this.paused) {
|
||||
this.startedAt = Date.now();
|
||||
this._startTimer();
|
||||
}
|
||||
}
|
||||
// resetTimerOnUpdate: 更新内容后重置计时器
|
||||
if (this.config.resetTimerOnUpdate && (this.config.duration || 0) > 0) {
|
||||
if (this.rafId !== null)
|
||||
@@ -3388,7 +3440,7 @@
|
||||
/**
|
||||
* MetonaToast Templates — HTML 模板辅助函数
|
||||
* @module templates
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description confirm / prompt / progress / action 的 DOM 模板
|
||||
*/
|
||||
/**
|
||||
@@ -3460,7 +3512,7 @@
|
||||
/**
|
||||
* MetonaToast Plugins — 插件系统
|
||||
* @module plugins
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 插件管理器
|
||||
@@ -3638,6 +3690,32 @@
|
||||
el.parentNode.removeChild(el); }, 3000);
|
||||
},
|
||||
},
|
||||
/**
|
||||
* 去重插件 — 相同 type + message 的 toast 自动合并(更新已有的一条)
|
||||
*/
|
||||
dedupe: {
|
||||
name: 'dedupe',
|
||||
version: '1.0.0',
|
||||
description: '相同类型和消息的 Toast 自动去重,更新已有实例而非重复弹出',
|
||||
_off: null,
|
||||
install() {
|
||||
const off = Toast.on('beforeShow', (toast) => {
|
||||
const existing = Array.from(Toast._registry.values()).find(t => !t.closing && t.type === toast.type && t.message === toast.message);
|
||||
if (existing) {
|
||||
existing.update({ title: toast.title || existing.title });
|
||||
return false;
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
this._off = off;
|
||||
},
|
||||
uninstall() {
|
||||
const off = this._off;
|
||||
if (off)
|
||||
off();
|
||||
this._off = null;
|
||||
},
|
||||
},
|
||||
};
|
||||
/**
|
||||
* 插件工具
|
||||
@@ -3680,7 +3758,7 @@
|
||||
/**
|
||||
* MetonaToast API — meToast 核心 API 对象
|
||||
* @module api
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 参数标准化工具
|
||||
@@ -3731,7 +3809,10 @@
|
||||
merged.message = merged.content;
|
||||
const t = new Toast(merged);
|
||||
t.create();
|
||||
this._toasts.set(t.id, t);
|
||||
// beforeShow/onBeforeShow 拦截(返回 false)时 el 为 null,不注册幽灵实例
|
||||
if (t.el !== null) {
|
||||
this._toasts.set(t.id, t);
|
||||
}
|
||||
return t;
|
||||
},
|
||||
_remove(id) {
|
||||
@@ -3797,14 +3878,21 @@
|
||||
throw err;
|
||||
});
|
||||
},
|
||||
/**
|
||||
* loading 链式转换 — 原地 update 同一实例(id 稳定,不重建 DOM)
|
||||
* duration 从 0 恢复为默认值,使转换后的 toast 自动关闭
|
||||
*/
|
||||
_resolve(loadingToast, type, message, opts) {
|
||||
const id = loadingToast.id;
|
||||
const old = this._toasts.get(id);
|
||||
const old = this._toasts.get(loadingToast.id);
|
||||
if (!old)
|
||||
return null;
|
||||
const position = old.config.position;
|
||||
old.close();
|
||||
return this._emit({ ...opts, type, message, position });
|
||||
old.update({
|
||||
...opts,
|
||||
type,
|
||||
message,
|
||||
duration: opts.duration ?? (old.config.duration || this._config.duration),
|
||||
});
|
||||
return old;
|
||||
},
|
||||
confirm(message, opts = {}) {
|
||||
if (typeof message !== 'string') {
|
||||
@@ -4342,7 +4430,7 @@
|
||||
/**
|
||||
* MetonaToast — 轻量级Toast通知库
|
||||
* @module metona-toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @author thzxx
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user