release: v0.3.0 — 自定义动画真实生效、max超限修复、钩子系统完整化、destroy全量清理
- 自定义动画:animations.register() 注册的动画动态注入 keyframes 真实生效(此前仅存 Map 实际 fallback slide) - max 超限:通过实例注册表真正 close() 最早的 toast(此前仅删内存记录,DOM 残留) - 钩子收敛:beforeClose/beforeUpdate 支持返回 false 拦截;接入 click/hover/dragStart/dragEnd/animationStart/animationEnd/progressStart/progressEnd/configChange/themeChange/localeChange/beforeInit/afterInit/beforeDestroy/afterDestroy;HOOK_NAMES 移除永不触发的声明 - destroy() 全量清理:hooks、实例注册表、全部 metona-toast-* 样式标签;动画注册表真正清空 - applyThemeVariables 重复注入修复;init() 支持插件对象并复活 _destroyed;AnimationConfig 类型放宽 - VERSION 统一到 constants.ts 唯一维护;删除失效 scripts;新增 .gitattributes 统一 LF - docs.html 补 v0.2.1 新 API 文档;CHANGELOG 更新;测试 309 用例全过
This commit is contained in:
Vendored
+212
-99
@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/**
|
||||
* MetonaToast Utils — 工具函数
|
||||
* @module utils
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
/**
|
||||
* 生成唯一ID
|
||||
@@ -42,7 +42,7 @@ const prefersDark = () => {
|
||||
/**
|
||||
* MetonaToast Icons — 图标SVG定义
|
||||
* @module icons
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
* @description 107 个内置 SVG 图标
|
||||
*/
|
||||
const ICONS = {
|
||||
@@ -539,7 +539,7 @@ const ICONS = {
|
||||
/**
|
||||
* MetonaToast Locales — 国际化翻译数据
|
||||
* @module locales
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
* @description 内置 zh-CN / en-US 完整翻译
|
||||
*/
|
||||
const LOCALES = {
|
||||
@@ -1026,8 +1026,12 @@ const LOCALES = {
|
||||
/**
|
||||
* MetonaToast Constants — 常量定义
|
||||
* @module constants
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
/**
|
||||
* 版本号 — 唯一来源,发布时只需修改此处
|
||||
*/
|
||||
const VERSION = '0.3.0';
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
@@ -1285,11 +1289,15 @@ const THEMES = {
|
||||
closeHoverBg: 'rgba(245, 158, 11, 0.1)',
|
||||
},
|
||||
};
|
||||
/**
|
||||
* 动画类型
|
||||
*/
|
||||
const ANIMATION_TYPES = ['slide', 'fade', 'scale', 'bounce', 'flip', 'rotate', 'zoom', 'slideUp', 'slideDown', 'slideLeft', 'slideRight'];
|
||||
|
||||
/**
|
||||
* MetonaToast Styles — 样式管理
|
||||
* @module styles
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
// 样式缓存
|
||||
let styleElement = null;
|
||||
@@ -1743,7 +1751,7 @@ const injectStyles = () => {
|
||||
/**
|
||||
* MetonaToast Themes — 主题管理
|
||||
* @module themes
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
// 当前主题状态
|
||||
let currentTheme = 'auto';
|
||||
@@ -2087,7 +2095,7 @@ const themeUtils = {
|
||||
/**
|
||||
* MetonaToast i18n — 国际化管理
|
||||
* @module i18n
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
// 当前语言状态
|
||||
let currentLocale = 'zh-CN';
|
||||
@@ -2643,10 +2651,126 @@ const i18nUtils = {
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* MetonaToast Animations — 动画管理
|
||||
* @module animations
|
||||
* @version 0.2.1
|
||||
*/
|
||||
// 动画缓存
|
||||
const animationMap = new Map();
|
||||
// 内置动画(keyframes 由 styles.ts 注入,无需动态生成)
|
||||
const BUILTIN_ANIMATIONS = new Set(ANIMATION_TYPES);
|
||||
// 动态注入的自定义动画样式(惰性创建)
|
||||
let animStyleElement = null;
|
||||
const injectedAnimations = new Set();
|
||||
/**
|
||||
* 将 CSS 属性对象转换为内联 CSS 字符串
|
||||
*/
|
||||
const toCss = (props) => Object.entries(props)
|
||||
.map(([key, value]) => `${key}:${value}`)
|
||||
.join(';');
|
||||
/**
|
||||
* 为自定义动画生成入场 keyframes + 类规则
|
||||
*/
|
||||
const buildAnimationCSS = (name, config) => {
|
||||
const enter = toCss(config.enter);
|
||||
return `
|
||||
@keyframes met-${name}-in {
|
||||
from { ${enter}; }
|
||||
}
|
||||
.met-anim-${name}.met-toast { opacity: 0; }
|
||||
.met-anim-${name}.met-toast.met-show {
|
||||
animation: met-${name}-in ${config.duration}ms ${config.easing} forwards;
|
||||
}
|
||||
`;
|
||||
};
|
||||
/**
|
||||
* 确保自定义动画的 CSS 已注入文档(幂等,内置动画自动跳过)
|
||||
*/
|
||||
const ensureAnimationCSS = (name) => {
|
||||
if (typeof document === 'undefined')
|
||||
return;
|
||||
if (BUILTIN_ANIMATIONS.has(name))
|
||||
return;
|
||||
const config = animationMap.get(name);
|
||||
if (!config || injectedAnimations.has(name))
|
||||
return;
|
||||
if (!animStyleElement) {
|
||||
animStyleElement = document.getElementById('metona-toast-anim-styles');
|
||||
if (!animStyleElement) {
|
||||
animStyleElement = document.createElement('style');
|
||||
animStyleElement.id = 'metona-toast-anim-styles';
|
||||
document.head.appendChild(animStyleElement);
|
||||
}
|
||||
}
|
||||
animStyleElement.textContent += buildAnimationCSS(name, config);
|
||||
injectedAnimations.add(name);
|
||||
};
|
||||
/**
|
||||
* 检查动画是否存在(内置或自定义)
|
||||
*/
|
||||
const hasAnimation = (name) => animationMap.has(name);
|
||||
// 注册默认动画
|
||||
Object.entries(ANIMATIONS).forEach(([name, config]) => {
|
||||
animationMap.set(name, {
|
||||
name,
|
||||
enter: config.enter,
|
||||
leave: config.leave,
|
||||
duration: config.duration,
|
||||
easing: config.easing,
|
||||
});
|
||||
});
|
||||
/**
|
||||
* 动画工具函数
|
||||
*/
|
||||
const animationUtils = {
|
||||
register(name, config) {
|
||||
animationMap.set(name, {
|
||||
name,
|
||||
enter: config.enter || {},
|
||||
leave: config.leave || {},
|
||||
duration: config.duration || 300,
|
||||
easing: config.easing || 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
});
|
||||
},
|
||||
unregister(name) {
|
||||
animationMap.delete(name);
|
||||
},
|
||||
get(name) {
|
||||
return animationMap.get(name) || null;
|
||||
},
|
||||
getAnimationNames() {
|
||||
return Array.from(animationMap.keys());
|
||||
},
|
||||
getActiveCount() {
|
||||
return animationMap.size;
|
||||
},
|
||||
cancelAll() {
|
||||
// CSS动画由浏览器原生管理,无需手动取消
|
||||
},
|
||||
reset() {
|
||||
animationMap.clear();
|
||||
Object.entries(ANIMATIONS).forEach(([name, config]) => {
|
||||
animationMap.set(name, {
|
||||
name,
|
||||
enter: config.enter,
|
||||
leave: config.leave,
|
||||
duration: config.duration,
|
||||
easing: config.easing,
|
||||
});
|
||||
});
|
||||
},
|
||||
destroy() {
|
||||
animationMap.clear();
|
||||
injectedAnimations.clear();
|
||||
animStyleElement = null;
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* MetonaToast Toast — Toast 类
|
||||
* @module toast
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
/**
|
||||
* Toast 类 — 核心通知组件
|
||||
@@ -2674,8 +2798,9 @@ class Toast {
|
||||
}
|
||||
/**
|
||||
* 触发钩子 — 如果任意钩子返回 false 则整体返回 false
|
||||
* toast 参数可选:全局事件(configChange/themeChange 等)不关联具体 toast
|
||||
*/
|
||||
static trigger(name, toast) {
|
||||
static trigger(name, toast = null) {
|
||||
const list = this._hooks.get(name);
|
||||
if (!list || list.length === 0)
|
||||
return true;
|
||||
@@ -2690,7 +2815,7 @@ class Toast {
|
||||
console.error('Hook error:', name, e);
|
||||
if (Toast._onError) {
|
||||
try {
|
||||
Toast._onError({ hook: name, error: e, toast });
|
||||
Toast._onError({ hook: name, error: e, toast: toast });
|
||||
}
|
||||
catch (_e) { /* noop */ }
|
||||
}
|
||||
@@ -2745,6 +2870,7 @@ class Toast {
|
||||
}
|
||||
}
|
||||
injectStyles();
|
||||
ensureAnimationCSS(this.config.animation || 'slide');
|
||||
const container = this._getContainer();
|
||||
const { theme, c, t } = this._palette();
|
||||
this._limitToasts(container);
|
||||
@@ -2764,6 +2890,7 @@ class Toast {
|
||||
else {
|
||||
container.appendChild(el);
|
||||
}
|
||||
Toast._registry.set(this.id, this);
|
||||
this._bindEvents(el);
|
||||
this._startTimer();
|
||||
// 进入动画
|
||||
@@ -2831,18 +2958,22 @@ class Toast {
|
||||
_limitToasts(container) {
|
||||
const max = this.config.max || 6;
|
||||
const list = Array.from(container.querySelectorAll('.met-toast'));
|
||||
if (list.length >= max) {
|
||||
const first = list[0];
|
||||
const id = first?.dataset.id;
|
||||
if (id && Toast._removeToast) {
|
||||
while (list.length >= max) {
|
||||
const el = list.shift();
|
||||
const id = el?.dataset.id;
|
||||
if (!id)
|
||||
continue;
|
||||
const existing = Toast._registry.get(id);
|
||||
if (existing) {
|
||||
existing.close(true);
|
||||
}
|
||||
else if (Toast._removeToast) {
|
||||
Toast._removeToast(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
_buildClassName(theme) {
|
||||
const CSS_ANIMS = ['slide', 'fade', 'scale', 'bounce', 'flip', 'rotate', 'zoom',
|
||||
'slideUp', 'slideDown', 'slideLeft', 'slideRight'];
|
||||
const anim = CSS_ANIMS.includes(this.config.animation || '') ? this.config.animation : 'slide';
|
||||
const anim = hasAnimation(this.config.animation || '') ? this.config.animation : 'slide';
|
||||
return [
|
||||
'met-toast',
|
||||
`met-${this.type}`,
|
||||
@@ -2919,6 +3050,7 @@ class Toast {
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
Toast.trigger('click', this);
|
||||
if (this.config.closeOnClick && !target.closest('.met-close')) {
|
||||
if (typeof this.config.onClick === 'function') {
|
||||
try {
|
||||
@@ -2935,8 +3067,14 @@ class Toast {
|
||||
el.addEventListener('click', eventHandler);
|
||||
this._cleanups.push(() => el.removeEventListener('click', eventHandler));
|
||||
if (this.config.pauseOnHover && (this.config.duration || 0) > 0) {
|
||||
const mouseEnter = () => this._pause();
|
||||
const mouseLeave = () => this._resume();
|
||||
const mouseEnter = () => {
|
||||
Toast.trigger('hover', this);
|
||||
this._pause();
|
||||
};
|
||||
const mouseLeave = () => {
|
||||
Toast.trigger('hover', this);
|
||||
this._resume();
|
||||
};
|
||||
el.addEventListener('mouseenter', mouseEnter);
|
||||
el.addEventListener('mouseleave', mouseLeave);
|
||||
this._cleanups.push(() => {
|
||||
@@ -2944,6 +3082,15 @@ class Toast {
|
||||
el.removeEventListener('mouseleave', mouseLeave);
|
||||
});
|
||||
}
|
||||
// 入场动画生命周期钩子(离场为过渡/内联样式,不产生 animation 事件)
|
||||
const animStart = () => Toast.trigger('animationStart', this);
|
||||
const animEnd = () => Toast.trigger('animationEnd', this);
|
||||
el.addEventListener('animationstart', animStart);
|
||||
el.addEventListener('animationend', animEnd);
|
||||
this._cleanups.push(() => {
|
||||
el.removeEventListener('animationstart', animStart);
|
||||
el.removeEventListener('animationend', animEnd);
|
||||
});
|
||||
if (this.config.draggable) {
|
||||
this._bindDrag(el);
|
||||
}
|
||||
@@ -2959,6 +3106,7 @@ class Toast {
|
||||
el.setPointerCapture(e.pointerId);
|
||||
el.style.transition = 'none';
|
||||
this._pause();
|
||||
Toast.trigger('dragStart', this);
|
||||
};
|
||||
const move = (e) => {
|
||||
if (!dragging)
|
||||
@@ -2985,6 +3133,7 @@ class Toast {
|
||||
this._resume();
|
||||
}
|
||||
dx = dy = 0;
|
||||
Toast.trigger('dragEnd', this);
|
||||
};
|
||||
el.addEventListener('pointerdown', down);
|
||||
el.addEventListener('pointermove', move);
|
||||
@@ -3003,6 +3152,7 @@ class Toast {
|
||||
if (!resuming) {
|
||||
this.startedAt = Date.now();
|
||||
this.remaining = this.config.duration || 0;
|
||||
Toast.trigger('progressStart', this);
|
||||
}
|
||||
const tick = () => {
|
||||
if (this.paused || this.closing)
|
||||
@@ -3017,6 +3167,7 @@ class Toast {
|
||||
this.barEl.style.transform = t;
|
||||
}
|
||||
if (this.remaining <= 0) {
|
||||
Toast.trigger('progressEnd', this);
|
||||
this.close();
|
||||
return;
|
||||
}
|
||||
@@ -3050,7 +3201,9 @@ class Toast {
|
||||
this._startTimer(true);
|
||||
}
|
||||
update(partial) {
|
||||
Toast.trigger('beforeUpdate', this);
|
||||
// beforeUpdate 钩子 — 返回 false 可阻止更新
|
||||
if (!Toast.trigger('beforeUpdate', this))
|
||||
return this;
|
||||
const typeChanged = partial.type && partial.type !== this.type;
|
||||
if (partial.type)
|
||||
this.type = partial.type;
|
||||
@@ -3147,14 +3300,17 @@ class Toast {
|
||||
this.el.parentNode.removeChild(this.el);
|
||||
}
|
||||
this.el = null;
|
||||
Toast._registry.delete(this.id);
|
||||
if (Toast._removeToast)
|
||||
Toast._removeToast(this.id);
|
||||
}
|
||||
close(immediate = false) {
|
||||
if (this.closing)
|
||||
return;
|
||||
// beforeClose 钩子 — 返回 false 可阻止关闭
|
||||
if (!Toast.trigger('beforeClose', this))
|
||||
return;
|
||||
this.closing = true;
|
||||
Toast.trigger('beforeClose', this);
|
||||
if (this.rafId !== null)
|
||||
cancelAnimationFrame(this.rafId);
|
||||
this._cleanups.forEach(fn => { try {
|
||||
@@ -3210,12 +3366,15 @@ class Toast {
|
||||
}
|
||||
}
|
||||
Toast.trigger('afterClose', this);
|
||||
Toast._registry.delete(this.id);
|
||||
if (Toast._removeToast)
|
||||
Toast._removeToast(this.id);
|
||||
}
|
||||
}
|
||||
// 静态钩子系统
|
||||
Toast._hooks = new Map();
|
||||
// 实例注册表 — 用于通过 id 反查实例(max 超限移除、外部接管等)
|
||||
Toast._registry = new Map();
|
||||
// 由 api.ts 注入的回调,通过 setCallbacks() 设置
|
||||
Toast._onError = null;
|
||||
Toast._removeToast = null;
|
||||
@@ -3227,7 +3386,7 @@ const _containerCache = new Map();
|
||||
/**
|
||||
* MetonaToast Templates — HTML 模板辅助函数
|
||||
* @module templates
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
* @description confirm / prompt / progress / action 的 DOM 模板
|
||||
*/
|
||||
/**
|
||||
@@ -3299,7 +3458,7 @@ const actionHTML = (actions) => {
|
||||
/**
|
||||
* MetonaToast Plugins — 插件系统
|
||||
* @module plugins
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
/**
|
||||
* 插件管理器
|
||||
@@ -3519,7 +3678,7 @@ const defaultPluginManager = new PluginManager();
|
||||
/**
|
||||
* MetonaToast API — meToast 核心 API 对象
|
||||
* @module api
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
*/
|
||||
/**
|
||||
* 参数标准化工具
|
||||
@@ -3544,15 +3703,13 @@ const normalizeArgs = (args, defaultType = 'default') => {
|
||||
message: '',
|
||||
};
|
||||
};
|
||||
/** 版本号常量 */
|
||||
const VERSION$1 = '0.2.1';
|
||||
/**
|
||||
* meToast API 对象
|
||||
*/
|
||||
const meToast = {
|
||||
_toasts: new Map(),
|
||||
_config: { ...DEFAULTS },
|
||||
version: '0.2.1',
|
||||
version: VERSION,
|
||||
configure(opts) {
|
||||
if (!opts || typeof opts !== 'object')
|
||||
return this;
|
||||
@@ -3563,6 +3720,7 @@ const meToast = {
|
||||
if (opts.locale) {
|
||||
setCurrentLocale(opts.locale);
|
||||
}
|
||||
Toast.trigger('configChange');
|
||||
return this;
|
||||
},
|
||||
_emit(opts) {
|
||||
@@ -4034,6 +4192,8 @@ const meToast = {
|
||||
},
|
||||
// ====== 以下方法依赖子模块(themes/i18n/plugins/animations),由 index.ts 注入 ======
|
||||
init(options = {}) {
|
||||
Toast.trigger('beforeInit');
|
||||
this._destroyed = false;
|
||||
if (options.config) {
|
||||
this.configure(options.config);
|
||||
}
|
||||
@@ -4048,11 +4208,12 @@ const meToast = {
|
||||
this.use(p);
|
||||
});
|
||||
}
|
||||
Toast.trigger('afterInit');
|
||||
return this;
|
||||
},
|
||||
getStatus() {
|
||||
return {
|
||||
version: VERSION$1,
|
||||
version: VERSION,
|
||||
toasts: this._toasts.size,
|
||||
theme: this.themes?.getCurrentTheme?.() || 'auto',
|
||||
locale: this.i18n?.getCurrentLocale?.() || 'zh-CN',
|
||||
@@ -4066,6 +4227,7 @@ const meToast = {
|
||||
updateConfig(config) {
|
||||
if (config && typeof config === 'object') {
|
||||
Object.assign(this._config, config);
|
||||
Toast.trigger('configChange');
|
||||
}
|
||||
return this;
|
||||
},
|
||||
@@ -4073,6 +4235,7 @@ const meToast = {
|
||||
const keys = Object.keys(this._config);
|
||||
keys.forEach(k => delete this._config[k]);
|
||||
Object.assign(this._config, DEFAULTS);
|
||||
Toast.trigger('configChange');
|
||||
return this;
|
||||
},
|
||||
use(plugin, options = {}) {
|
||||
@@ -4113,6 +4276,7 @@ const meToast = {
|
||||
if (this._destroyed)
|
||||
return;
|
||||
this._destroyed = true;
|
||||
Toast.trigger('beforeDestroy');
|
||||
this.dismiss();
|
||||
// 清理子模块
|
||||
if (this.plugins && typeof this.plugins.destroy === 'function') {
|
||||
@@ -4129,20 +4293,26 @@ const meToast = {
|
||||
if (this.i18n && typeof this.i18n.clearLocaleListeners === 'function') {
|
||||
this.i18n.clearLocaleListeners();
|
||||
}
|
||||
if (this.animations && typeof this.animations.cancelAll === 'function') {
|
||||
this.animations.cancelAll();
|
||||
if (this.animations && typeof this.animations.destroy === 'function') {
|
||||
this.animations.destroy();
|
||||
}
|
||||
// 清理 DOM
|
||||
// 清理 DOM 与静态资源
|
||||
if (typeof document !== 'undefined') {
|
||||
const containers = document.querySelectorAll('.met-container');
|
||||
containers.forEach((c) => { if (c.parentNode)
|
||||
c.parentNode.removeChild(c); });
|
||||
const style = document.getElementById('metona-toast-styles');
|
||||
if (style && style.parentNode)
|
||||
style.parentNode.removeChild(style);
|
||||
['metona-toast-styles', 'metona-toast-theme-css', 'metona-toast-custom-styles', 'metona-toast-anim-styles'].forEach((id) => {
|
||||
const el = document.getElementById(id);
|
||||
if (el && el.parentNode)
|
||||
el.parentNode.removeChild(el);
|
||||
});
|
||||
}
|
||||
this._toasts.clear();
|
||||
_containerCache.clear();
|
||||
Toast._registry.clear();
|
||||
// afterDestroy 必须在清理 hooks 之前触发
|
||||
Toast.trigger('afterDestroy');
|
||||
Toast._hooks.clear();
|
||||
},
|
||||
// 子模块引用(由 index.ts 注入实际实现)
|
||||
animations: null,
|
||||
@@ -4167,77 +4337,13 @@ Toast.setCallbacks({
|
||||
},
|
||||
});
|
||||
|
||||
/**
|
||||
* MetonaToast Animations — 动画管理
|
||||
* @module animations
|
||||
* @version 0.2.1
|
||||
*/
|
||||
// 动画缓存
|
||||
const animationMap = new Map();
|
||||
// 注册默认动画
|
||||
Object.entries(ANIMATIONS).forEach(([name, config]) => {
|
||||
animationMap.set(name, {
|
||||
name,
|
||||
enter: config.enter,
|
||||
leave: config.leave,
|
||||
duration: config.duration,
|
||||
easing: config.easing,
|
||||
});
|
||||
});
|
||||
/**
|
||||
* 动画工具函数
|
||||
*/
|
||||
const animationUtils = {
|
||||
register(name, config) {
|
||||
animationMap.set(name, {
|
||||
name,
|
||||
enter: config.enter || {},
|
||||
leave: config.leave || {},
|
||||
duration: config.duration || 300,
|
||||
easing: config.easing || 'cubic-bezier(0.4, 0, 0.2, 1)',
|
||||
});
|
||||
},
|
||||
unregister(name) {
|
||||
animationMap.delete(name);
|
||||
},
|
||||
get(name) {
|
||||
return animationMap.get(name) || null;
|
||||
},
|
||||
getAnimationNames() {
|
||||
return Array.from(animationMap.keys());
|
||||
},
|
||||
getActiveCount() {
|
||||
return animationMap.size;
|
||||
},
|
||||
cancelAll() {
|
||||
// CSS动画由浏览器原生管理,无需手动取消
|
||||
},
|
||||
reset() {
|
||||
animationMap.clear();
|
||||
Object.entries(ANIMATIONS).forEach(([name, config]) => {
|
||||
animationMap.set(name, {
|
||||
name,
|
||||
enter: config.enter,
|
||||
leave: config.leave,
|
||||
duration: config.duration,
|
||||
easing: config.easing,
|
||||
});
|
||||
});
|
||||
},
|
||||
destroy() {
|
||||
animationMap.clear();
|
||||
},
|
||||
};
|
||||
|
||||
/**
|
||||
* MetonaToast — 轻量级Toast通知库
|
||||
* @module metona-toast
|
||||
* @version 0.2.1
|
||||
* @version 0.3.0
|
||||
* @author thzxx
|
||||
* @license MIT
|
||||
*/
|
||||
// 版本信息
|
||||
const VERSION = '0.2.1';
|
||||
/**
|
||||
* 增强的 MeToast 对象 — 在 meToast 基础上注入子模块
|
||||
*/
|
||||
@@ -4257,6 +4363,13 @@ if (typeof themeUtils.initTheme === 'function') {
|
||||
if (typeof i18nUtils.initI18n === 'function') {
|
||||
i18nUtils.initI18n();
|
||||
}
|
||||
// 全局钩子 — 主题/语言变化转发到 Toast 钩子系统
|
||||
if (typeof themeUtils.addThemeListener === 'function') {
|
||||
themeUtils.addThemeListener(() => Toast.trigger('themeChange'));
|
||||
}
|
||||
if (typeof i18nUtils.addLocaleListener === 'function') {
|
||||
i18nUtils.addLocaleListener(() => Toast.trigger('localeChange'));
|
||||
}
|
||||
// 浏览器环境全局注册
|
||||
if (typeof window !== 'undefined') {
|
||||
window.MeToast = enhancedMeToast;
|
||||
|
||||
Reference in New Issue
Block a user