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
@@ -5,7 +5,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
||||
/**
|
||||
* MetonaToast Utils — 工具函数
|
||||
* @module utils
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 生成唯一ID
|
||||
@@ -42,7 +42,7 @@ const prefersDark = () => {
|
||||
/**
|
||||
* MetonaToast Icons — 图标SVG定义
|
||||
* @module icons
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description 107 个内置 SVG 图标
|
||||
*/
|
||||
const ICONS = {
|
||||
@@ -539,7 +539,7 @@ const ICONS = {
|
||||
/**
|
||||
* MetonaToast Locales — 国际化翻译数据
|
||||
* @module locales
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description 内置 zh-CN / en-US 完整翻译
|
||||
*/
|
||||
const LOCALES = {
|
||||
@@ -1026,12 +1026,12 @@ const LOCALES = {
|
||||
/**
|
||||
* MetonaToast Constants — 常量定义
|
||||
* @module constants
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 版本号 — 唯一来源,发布时只需修改此处
|
||||
*/
|
||||
const VERSION = '0.3.0';
|
||||
const VERSION = '0.4.0';
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
@@ -1044,6 +1044,7 @@ const DEFAULTS = Object.freeze({
|
||||
pauseOnHover: true,
|
||||
closeOnClick: true,
|
||||
draggable: true,
|
||||
dragThreshold: 120,
|
||||
showProgress: true,
|
||||
progressDirection: 'horizontal',
|
||||
icon: true,
|
||||
@@ -1297,7 +1298,7 @@ const ANIMATION_TYPES = ['slide', 'fade', 'scale', 'bounce', 'flip', 'rotate', '
|
||||
/**
|
||||
* MetonaToast Styles — 样式管理
|
||||
* @module styles
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 样式缓存
|
||||
let styleElement = null;
|
||||
@@ -1655,6 +1656,41 @@ const generateCSS = () => {
|
||||
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; }
|
||||
@@ -1751,7 +1787,7 @@ const injectStyles = () => {
|
||||
/**
|
||||
* MetonaToast Themes — 主题管理
|
||||
* @module themes
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 当前主题状态
|
||||
let currentTheme = 'auto';
|
||||
@@ -2095,7 +2131,7 @@ const themeUtils = {
|
||||
/**
|
||||
* MetonaToast i18n — 国际化管理
|
||||
* @module i18n
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 当前语言状态
|
||||
let currentLocale = 'zh-CN';
|
||||
@@ -2770,7 +2806,7 @@ const animationUtils = {
|
||||
/**
|
||||
* MetonaToast Toast — Toast 类
|
||||
* @module toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* Toast 类 — 核心通知组件
|
||||
@@ -2931,6 +2967,9 @@ class Toast {
|
||||
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',
|
||||
@@ -3122,7 +3161,8 @@ class Toast {
|
||||
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);
|
||||
@@ -3240,6 +3280,18 @@ class Toast {
|
||||
: (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)
|
||||
@@ -3386,7 +3438,7 @@ const _containerCache = new Map();
|
||||
/**
|
||||
* MetonaToast Templates — HTML 模板辅助函数
|
||||
* @module templates
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description confirm / prompt / progress / action 的 DOM 模板
|
||||
*/
|
||||
/**
|
||||
@@ -3458,7 +3510,7 @@ const actionHTML = (actions) => {
|
||||
/**
|
||||
* MetonaToast Plugins — 插件系统
|
||||
* @module plugins
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 插件管理器
|
||||
@@ -3636,6 +3688,32 @@ const presetPlugins = {
|
||||
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;
|
||||
},
|
||||
},
|
||||
};
|
||||
/**
|
||||
* 插件工具
|
||||
@@ -3678,7 +3756,7 @@ const defaultPluginManager = new PluginManager();
|
||||
/**
|
||||
* MetonaToast API — meToast 核心 API 对象
|
||||
* @module api
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 参数标准化工具
|
||||
@@ -3729,7 +3807,10 @@ const meToast = {
|
||||
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) {
|
||||
@@ -3795,14 +3876,21 @@ const meToast = {
|
||||
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') {
|
||||
@@ -4340,7 +4428,7 @@ Toast.setCallbacks({
|
||||
/**
|
||||
* MetonaToast — 轻量级Toast通知库
|
||||
* @module metona-toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @author thzxx
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+5
-4
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* MetonaToast — 核心类型定义
|
||||
* @module types
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/** Toast 通知类型(107种内置图标类型) */
|
||||
type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading' | 'check' | 'x' | 'alert' | 'question' | 'star' | 'heart' | 'bell' | 'mail' | 'settings' | 'user' | 'home' | 'search' | 'plus' | 'minus' | 'edit' | 'trash' | 'download' | 'upload' | 'share' | 'link' | 'external' | 'clock' | 'calendar' | 'map' | 'compass' | 'globe' | 'wifi' | 'cloud' | 'sun' | 'moon' | 'zap' | 'activity' | 'cpu' | 'database' | 'server' | 'terminal' | 'code' | 'git' | 'package' | 'layers' | 'grid' | 'list' | 'filter' | 'sort' | 'refresh' | 'sync' | 'power' | 'battery' | 'bluetooth' | 'volume' | 'mic' | 'camera' | 'image' | 'video' | 'music' | 'file' | 'folder' | 'clipboard' | 'save' | 'print' | 'eye' | 'eyeOff' | 'lock' | 'unlock' | 'shield' | 'key' | 'flag' | 'bookmark' | 'tag' | 'gift' | 'award' | 'target' | 'crosshair' | 'move' | 'maximize' | 'minimize' | 'copy' | 'cut' | 'paste' | 'rotateCw' | 'rotateCcw' | 'zoomIn' | 'zoomOut' | 'crop' | 'sliders' | 'toggleLeft' | 'toggleRight' | 'checkCircle' | 'xCircle' | 'alertCircle' | 'infoCircle' | 'helpCircle' | 'alertTriangle' | 'checkSquare' | 'square' | 'circle' | 'triangle' | 'hexagon' | 'octagon' | 'pentagon' | 'diamond';
|
||||
@@ -26,6 +26,7 @@ interface ToastConfig {
|
||||
pauseOnHover?: boolean;
|
||||
closeOnClick?: boolean;
|
||||
draggable?: boolean;
|
||||
dragThreshold?: number;
|
||||
showProgress?: boolean;
|
||||
progressDirection?: ToastProgressDirection;
|
||||
icon?: boolean;
|
||||
@@ -417,7 +418,7 @@ declare global {
|
||||
/**
|
||||
* MetonaToast Toast — Toast 类
|
||||
* @module toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
|
||||
/**
|
||||
@@ -491,13 +492,13 @@ declare class Toast implements ToastInstance {
|
||||
/**
|
||||
* MetonaToast Constants — 常量定义
|
||||
* @module constants
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
|
||||
/**
|
||||
* 版本号 — 唯一来源,发布时只需修改此处
|
||||
*/
|
||||
declare const VERSION = "0.3.0";
|
||||
declare const VERSION = "0.4.0";
|
||||
|
||||
/**
|
||||
* 增强的 MeToast 对象 — 在 meToast 基础上注入子模块
|
||||
|
||||
Vendored
+108
-20
@@ -1,7 +1,7 @@
|
||||
/**
|
||||
* MetonaToast Utils — 工具函数
|
||||
* @module utils
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 生成唯一ID
|
||||
@@ -38,7 +38,7 @@ const prefersDark = () => {
|
||||
/**
|
||||
* MetonaToast Icons — 图标SVG定义
|
||||
* @module icons
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description 107 个内置 SVG 图标
|
||||
*/
|
||||
const ICONS = {
|
||||
@@ -535,7 +535,7 @@ const ICONS = {
|
||||
/**
|
||||
* MetonaToast Locales — 国际化翻译数据
|
||||
* @module locales
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description 内置 zh-CN / en-US 完整翻译
|
||||
*/
|
||||
const LOCALES = {
|
||||
@@ -1022,12 +1022,12 @@ const LOCALES = {
|
||||
/**
|
||||
* MetonaToast Constants — 常量定义
|
||||
* @module constants
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 版本号 — 唯一来源,发布时只需修改此处
|
||||
*/
|
||||
const VERSION = '0.3.0';
|
||||
const VERSION = '0.4.0';
|
||||
/**
|
||||
* 默认配置
|
||||
*/
|
||||
@@ -1040,6 +1040,7 @@ const DEFAULTS = Object.freeze({
|
||||
pauseOnHover: true,
|
||||
closeOnClick: true,
|
||||
draggable: true,
|
||||
dragThreshold: 120,
|
||||
showProgress: true,
|
||||
progressDirection: 'horizontal',
|
||||
icon: true,
|
||||
@@ -1293,7 +1294,7 @@ const ANIMATION_TYPES = ['slide', 'fade', 'scale', 'bounce', 'flip', 'rotate', '
|
||||
/**
|
||||
* MetonaToast Styles — 样式管理
|
||||
* @module styles
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 样式缓存
|
||||
let styleElement = null;
|
||||
@@ -1651,6 +1652,41 @@ const generateCSS = () => {
|
||||
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; }
|
||||
@@ -1747,7 +1783,7 @@ const injectStyles = () => {
|
||||
/**
|
||||
* MetonaToast Themes — 主题管理
|
||||
* @module themes
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 当前主题状态
|
||||
let currentTheme = 'auto';
|
||||
@@ -2091,7 +2127,7 @@ const themeUtils = {
|
||||
/**
|
||||
* MetonaToast i18n — 国际化管理
|
||||
* @module i18n
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
// 当前语言状态
|
||||
let currentLocale = 'zh-CN';
|
||||
@@ -2766,7 +2802,7 @@ const animationUtils = {
|
||||
/**
|
||||
* MetonaToast Toast — Toast 类
|
||||
* @module toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* Toast 类 — 核心通知组件
|
||||
@@ -2927,6 +2963,9 @@ class Toast {
|
||||
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',
|
||||
@@ -3118,7 +3157,8 @@ class Toast {
|
||||
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);
|
||||
@@ -3236,6 +3276,18 @@ class Toast {
|
||||
: (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)
|
||||
@@ -3382,7 +3434,7 @@ const _containerCache = new Map();
|
||||
/**
|
||||
* MetonaToast Templates — HTML 模板辅助函数
|
||||
* @module templates
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @description confirm / prompt / progress / action 的 DOM 模板
|
||||
*/
|
||||
/**
|
||||
@@ -3454,7 +3506,7 @@ const actionHTML = (actions) => {
|
||||
/**
|
||||
* MetonaToast Plugins — 插件系统
|
||||
* @module plugins
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 插件管理器
|
||||
@@ -3632,6 +3684,32 @@ const presetPlugins = {
|
||||
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;
|
||||
},
|
||||
},
|
||||
};
|
||||
/**
|
||||
* 插件工具
|
||||
@@ -3674,7 +3752,7 @@ const defaultPluginManager = new PluginManager();
|
||||
/**
|
||||
* MetonaToast API — meToast 核心 API 对象
|
||||
* @module api
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/**
|
||||
* 参数标准化工具
|
||||
@@ -3725,7 +3803,10 @@ const meToast = {
|
||||
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) {
|
||||
@@ -3791,14 +3872,21 @@ const meToast = {
|
||||
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') {
|
||||
@@ -4336,7 +4424,7 @@ Toast.setCallbacks({
|
||||
/**
|
||||
* MetonaToast — 轻量级Toast通知库
|
||||
* @module metona-toast
|
||||
* @version 0.3.0
|
||||
* @version 0.4.0
|
||||
* @author thzxx
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
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
|
||||
*/
|
||||
|
||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+4582
File diff suppressed because it is too large
Load Diff
Vendored
+1
File diff suppressed because one or more lines are too long
Vendored
+509
@@ -0,0 +1,509 @@
|
||||
/**
|
||||
* MetonaToast — 核心类型定义
|
||||
* @module types
|
||||
* @version 0.4.0
|
||||
*/
|
||||
/** Toast 通知类型(107种内置图标类型) */
|
||||
type ToastType = 'default' | 'success' | 'error' | 'warning' | 'info' | 'loading' | 'check' | 'x' | 'alert' | 'question' | 'star' | 'heart' | 'bell' | 'mail' | 'settings' | 'user' | 'home' | 'search' | 'plus' | 'minus' | 'edit' | 'trash' | 'download' | 'upload' | 'share' | 'link' | 'external' | 'clock' | 'calendar' | 'map' | 'compass' | 'globe' | 'wifi' | 'cloud' | 'sun' | 'moon' | 'zap' | 'activity' | 'cpu' | 'database' | 'server' | 'terminal' | 'code' | 'git' | 'package' | 'layers' | 'grid' | 'list' | 'filter' | 'sort' | 'refresh' | 'sync' | 'power' | 'battery' | 'bluetooth' | 'volume' | 'mic' | 'camera' | 'image' | 'video' | 'music' | 'file' | 'folder' | 'clipboard' | 'save' | 'print' | 'eye' | 'eyeOff' | 'lock' | 'unlock' | 'shield' | 'key' | 'flag' | 'bookmark' | 'tag' | 'gift' | 'award' | 'target' | 'crosshair' | 'move' | 'maximize' | 'minimize' | 'copy' | 'cut' | 'paste' | 'rotateCw' | 'rotateCcw' | 'zoomIn' | 'zoomOut' | 'crop' | 'sliders' | 'toggleLeft' | 'toggleRight' | 'checkCircle' | 'xCircle' | 'alertCircle' | 'infoCircle' | 'helpCircle' | 'alertTriangle' | 'checkSquare' | 'square' | 'circle' | 'triangle' | 'hexagon' | 'octagon' | 'pentagon' | 'diamond';
|
||||
/** Toast 显示位置 */
|
||||
type ToastPosition = 'top-left' | 'top-center' | 'top-right' | 'bottom-left' | 'bottom-center' | 'bottom-right';
|
||||
/** Toast 主题 */
|
||||
type ToastTheme = 'light' | 'dark' | 'auto' | 'warm' | (string & {});
|
||||
/** Toast 动画类型 */
|
||||
type ToastAnimation = 'slide' | 'fade' | 'scale' | 'bounce' | 'flip' | 'rotate' | 'zoom' | 'slideUp' | 'slideDown' | 'slideLeft' | 'slideRight' | (string & {});
|
||||
/** 进度条方向 */
|
||||
type ToastProgressDirection = 'horizontal' | 'vertical';
|
||||
interface TypeColor {
|
||||
fg: string;
|
||||
bg: string;
|
||||
}
|
||||
interface ToastConfig {
|
||||
position?: ToastPosition;
|
||||
duration?: number;
|
||||
max?: number;
|
||||
gap?: number;
|
||||
offset?: number;
|
||||
pauseOnHover?: boolean;
|
||||
closeOnClick?: boolean;
|
||||
draggable?: boolean;
|
||||
dragThreshold?: number;
|
||||
showProgress?: boolean;
|
||||
progressDirection?: ToastProgressDirection;
|
||||
icon?: boolean;
|
||||
closeButton?: boolean;
|
||||
theme?: ToastTheme;
|
||||
animation?: ToastAnimation;
|
||||
zIndex?: number;
|
||||
width?: number | string;
|
||||
className?: string;
|
||||
style?: Record<string, string>;
|
||||
onShow?: ((toast: ToastInstance) => void) | null;
|
||||
onBeforeShow?: ((toast: ToastInstance) => boolean | void) | null;
|
||||
onClose?: ((toast: ToastInstance) => void) | null;
|
||||
onClick?: ((toast: ToastInstance) => void) | null;
|
||||
onUpdate?: ((toast: ToastInstance) => void) | null;
|
||||
render?: ((toast: ToastInstance) => string) | null;
|
||||
resetTimerOnUpdate?: boolean;
|
||||
notifyWhenHidden?: boolean;
|
||||
onError?: ((errorInfo: ErrorInfo) => void) | null;
|
||||
group?: string | null;
|
||||
locale?: string;
|
||||
plugins?: Array<string | Plugin>;
|
||||
}
|
||||
interface ErrorInfo {
|
||||
hook?: string;
|
||||
source?: string;
|
||||
error: Error;
|
||||
toast?: ToastInstance;
|
||||
}
|
||||
interface ToastOptions extends Partial<ToastConfig> {
|
||||
type?: string;
|
||||
title?: string;
|
||||
message?: string;
|
||||
content?: string;
|
||||
html?: string;
|
||||
iconHTML?: string;
|
||||
id?: string;
|
||||
}
|
||||
interface ToastInstance {
|
||||
id: string;
|
||||
type: string;
|
||||
title: string;
|
||||
message: string;
|
||||
html: string;
|
||||
iconHTML: string;
|
||||
config: ToastConfig;
|
||||
el: HTMLElement | null;
|
||||
barEl: HTMLElement | null;
|
||||
rafId: number | null;
|
||||
remaining: number;
|
||||
startedAt: number;
|
||||
paused: boolean;
|
||||
closing: boolean;
|
||||
group: string | null;
|
||||
_cleanups: Array<() => void>;
|
||||
_palette(): {
|
||||
theme: string;
|
||||
c: TypeColor;
|
||||
t: Partial<ThemeConfig>;
|
||||
};
|
||||
create(): this;
|
||||
update(partial: Partial<ToastOptions>): this;
|
||||
updatePosition(position: string): this;
|
||||
remove(): void;
|
||||
close(immediate?: boolean): void;
|
||||
_pause(): void;
|
||||
_resume(): void;
|
||||
_destroy(): void;
|
||||
}
|
||||
interface LoadingControl {
|
||||
id: string;
|
||||
success(message?: string, opts?: ToastOptions): ToastInstance | null;
|
||||
error(message?: string, opts?: ToastOptions): ToastInstance | null;
|
||||
info(message?: string, opts?: ToastOptions): ToastInstance | null;
|
||||
warning(message?: string, opts?: ToastOptions): ToastInstance | null;
|
||||
update(partial: Partial<ToastOptions>): unknown;
|
||||
dismiss(): void;
|
||||
}
|
||||
interface ProgressControl {
|
||||
id: string;
|
||||
setProgress(percent: number): void;
|
||||
complete(message?: string): void;
|
||||
error(message?: string): void;
|
||||
dismiss(): void;
|
||||
}
|
||||
interface CountdownControl {
|
||||
id: string;
|
||||
cancel(): void;
|
||||
pause(): void;
|
||||
resume(): void;
|
||||
}
|
||||
interface ActionControl {
|
||||
id: string;
|
||||
toast: ToastInstance;
|
||||
dismiss(): void;
|
||||
}
|
||||
interface QueueControl {
|
||||
then<TResult1 = void, TResult2 = never>(onfulfilled?: ((value: void) => TResult1 | PromiseLike<TResult1>) | null, onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null): Promise<TResult1 | TResult2>;
|
||||
catch<TResult = never>(onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null): Promise<void | TResult>;
|
||||
cancel(): void;
|
||||
}
|
||||
interface GroupAPI {
|
||||
_group: string;
|
||||
show: (...args: unknown[]) => ToastInstance;
|
||||
success: (...args: unknown[]) => ToastInstance;
|
||||
error: (...args: unknown[]) => ToastInstance;
|
||||
warning: (...args: unknown[]) => ToastInstance;
|
||||
info: (...args: unknown[]) => ToastInstance;
|
||||
loading: (...args: unknown[]) => LoadingControl;
|
||||
action: (...args: unknown[]) => ActionControl;
|
||||
dismiss(): void;
|
||||
count(): number;
|
||||
}
|
||||
interface ActionButton {
|
||||
text: string;
|
||||
onClick: (toast: ToastInstance) => void;
|
||||
color?: string;
|
||||
style?: Record<string, string>;
|
||||
close?: boolean;
|
||||
}
|
||||
interface PromiseOptions extends ToastOptions {
|
||||
loading?: string;
|
||||
success?: string;
|
||||
error?: string;
|
||||
}
|
||||
interface ConfirmOptions extends ToastOptions {
|
||||
confirmText?: string;
|
||||
confirmColor?: string;
|
||||
cancelText?: string;
|
||||
cancelColor?: string;
|
||||
}
|
||||
interface PromptOptions extends ToastOptions {
|
||||
inputType?: string;
|
||||
placeholder?: string;
|
||||
defaultValue?: string;
|
||||
submitText?: string;
|
||||
submitColor?: string;
|
||||
cancelText?: string;
|
||||
cancelColor?: string;
|
||||
}
|
||||
interface ProgressOptions extends ToastOptions {
|
||||
progressColor?: string;
|
||||
}
|
||||
interface CountdownOptions extends ToastOptions {
|
||||
onComplete?: (() => void) | null;
|
||||
}
|
||||
interface QueueOptions extends ToastOptions {
|
||||
delay?: number;
|
||||
}
|
||||
interface StackOptions extends ToastOptions {
|
||||
stagger?: number;
|
||||
}
|
||||
interface InitOptions {
|
||||
config?: Partial<ToastConfig>;
|
||||
theme?: ToastTheme;
|
||||
locale?: string;
|
||||
plugins?: Array<string | Plugin>;
|
||||
}
|
||||
interface StatusInfo {
|
||||
version: string;
|
||||
toasts: number;
|
||||
theme: string;
|
||||
locale: string;
|
||||
plugins: string[];
|
||||
animations: number;
|
||||
}
|
||||
interface AnimationConfig {
|
||||
enter: Record<string, string | number>;
|
||||
leave: Record<string, string | number>;
|
||||
duration: number;
|
||||
easing: string;
|
||||
name?: string;
|
||||
delay?: number;
|
||||
iterations?: number;
|
||||
direction?: 'normal' | 'reverse' | 'alternate' | 'alternate-reverse';
|
||||
fillMode?: 'none' | 'forwards' | 'backwards' | 'both';
|
||||
}
|
||||
interface AnimationUtils {
|
||||
register(name: string, config: Partial<AnimationConfig>): void;
|
||||
unregister(name: string): void;
|
||||
get(name: string): AnimationConfig | null;
|
||||
getAnimationNames(): string[];
|
||||
getActiveCount(): number;
|
||||
cancelAll(): void;
|
||||
reset(): void;
|
||||
destroy(): void;
|
||||
}
|
||||
interface ThemeConfig {
|
||||
bg: string;
|
||||
text: string;
|
||||
border: string;
|
||||
shadow: string;
|
||||
hoverShadow: string;
|
||||
progressBg: string;
|
||||
closeHoverBg: string;
|
||||
backdropFilter?: string;
|
||||
}
|
||||
interface ThemePreview {
|
||||
name: string;
|
||||
resolved: string;
|
||||
colors: {
|
||||
background: string;
|
||||
text: string;
|
||||
border: string;
|
||||
};
|
||||
isDark: boolean;
|
||||
isLight: boolean;
|
||||
isAuto: boolean;
|
||||
}
|
||||
interface ThemeUtils {
|
||||
getSystemTheme(): 'light' | 'dark';
|
||||
resolveTheme(theme: string): string;
|
||||
getThemeConfig(theme: string): ThemeConfig;
|
||||
applyTheme(theme: string): void;
|
||||
getCurrentTheme(): string;
|
||||
getResolvedTheme(): string;
|
||||
switchTheme(theme: string): void;
|
||||
toggleTheme(): void;
|
||||
resetToAuto(): void;
|
||||
initTheme(): void;
|
||||
watchSystemTheme(): void;
|
||||
unwatchSystemTheme(): void;
|
||||
addThemeListener(listener: (theme: string, resolved: string) => void): () => void;
|
||||
removeThemeListener(listener: (theme: string, resolved: string) => void): void;
|
||||
clearThemeListeners(): void;
|
||||
registerTheme(name: string, config: ThemeConfig): void;
|
||||
unregisterTheme(name: string): void;
|
||||
getAllThemes(): Record<string, ThemeConfig>;
|
||||
getThemeNames(): string[];
|
||||
hasTheme(name: string): boolean;
|
||||
getThemePreview(theme: string): ThemePreview;
|
||||
generateThemeCSS(theme: string): string;
|
||||
applyThemeCSS(theme: string): void;
|
||||
removeThemeCSS(): void;
|
||||
saveTheme(theme: string): void;
|
||||
loadTheme(): string;
|
||||
}
|
||||
interface LocaleInfo {
|
||||
code: string;
|
||||
name: string;
|
||||
direction: 'ltr' | 'rtl';
|
||||
isSupported: boolean;
|
||||
isCurrent: boolean;
|
||||
isFallback: boolean;
|
||||
}
|
||||
interface I18nUtils {
|
||||
t(key: string, params?: Record<string, string | number>): string;
|
||||
plural(key: string, count: number, params?: Record<string, string | number>): string;
|
||||
getCurrentLocale(): string;
|
||||
setCurrentLocale(locale: string): void;
|
||||
switchLocale(locale: string): void;
|
||||
getFallbackLocale(): string;
|
||||
setFallbackLocale(locale: string): void;
|
||||
hasTranslation(key: string): boolean;
|
||||
getTranslations(locale: string): Record<string, unknown>;
|
||||
addTranslations(locale: string, translations: Record<string, unknown>): void;
|
||||
removeTranslation(locale: string, key: string): void;
|
||||
clearTranslations(locale: string): void;
|
||||
getSupportedLocales(): string[];
|
||||
isLocaleSupported(locale: string): boolean;
|
||||
getLocaleName(locale: string): string;
|
||||
getLocaleDirection(locale: string): 'ltr' | 'rtl';
|
||||
getLocaleInfo(locale: string): LocaleInfo;
|
||||
getAllLocaleInfo(): LocaleInfo[];
|
||||
formatNumber(number: number, options?: Intl.NumberFormatOptions): string;
|
||||
formatCurrency(amount: number, currency?: string, options?: Intl.NumberFormatOptions): string;
|
||||
formatPercent(value: number, options?: Intl.NumberFormatOptions): string;
|
||||
formatDate(date: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
|
||||
formatTime(date: Date | number | string, options?: Intl.DateTimeFormatOptions): string;
|
||||
formatRelativeTime(date: Date | number | string, options?: Intl.RelativeTimeFormatOptions): string;
|
||||
formatList(list: string[], options?: Record<string, unknown>): string;
|
||||
formatPlural(count: number, options?: Intl.PluralRulesOptions): string;
|
||||
addLocaleListener(listener: (locale: string) => void): () => void;
|
||||
removeLocaleListener(listener: (locale: string) => void): void;
|
||||
clearLocaleListeners(): void;
|
||||
initI18n(): void;
|
||||
saveLocale(locale: string): void;
|
||||
loadLocale(): string;
|
||||
getDefaultLocale(): string;
|
||||
}
|
||||
interface Plugin {
|
||||
name: string;
|
||||
version?: string;
|
||||
description?: string;
|
||||
hooks?: Record<string, (...args: unknown[]) => void>;
|
||||
middleware?: (...args: unknown[]) => unknown;
|
||||
install?: (manager: PluginManager) => void | Record<string, unknown> | null;
|
||||
uninstall?: (manager: PluginManager) => void;
|
||||
init?: (manager: PluginManager) => void;
|
||||
destroy?: (manager: PluginManager) => void;
|
||||
installed?: boolean;
|
||||
enabled?: boolean;
|
||||
[key: string]: unknown;
|
||||
}
|
||||
interface PluginManager {
|
||||
register(name: string, plugin: Plugin): PluginManager;
|
||||
unregister(name: string): PluginManager;
|
||||
get(name: string): Plugin | null;
|
||||
has(name: string): boolean;
|
||||
getAll(): Plugin[];
|
||||
getNames(): string[];
|
||||
enable(name: string): PluginManager;
|
||||
disable(name: string): PluginManager;
|
||||
isEnabled(name: string): boolean;
|
||||
destroy(): void;
|
||||
}
|
||||
interface PluginUtils {
|
||||
createManager(): PluginManager;
|
||||
register(name: string, plugin: Plugin): PluginManager;
|
||||
unregister(name: string): PluginManager;
|
||||
get(name: string): Plugin | null;
|
||||
has(name: string): boolean;
|
||||
getAll(): Plugin[];
|
||||
getNames(): string[];
|
||||
enable(name: string): PluginManager;
|
||||
disable(name: string): PluginManager;
|
||||
isEnabled(name: string): boolean;
|
||||
getPreset(name: string): Plugin | null;
|
||||
getAllPresets(): Record<string, Plugin>;
|
||||
createPlugin(config: Partial<Plugin>): Plugin;
|
||||
validatePlugin(plugin: Partial<Plugin>): {
|
||||
valid: boolean;
|
||||
errors: string[];
|
||||
};
|
||||
}
|
||||
interface MeToast {
|
||||
version: string;
|
||||
_toasts: Map<string, ToastInstance>;
|
||||
_config: ToastConfig;
|
||||
_destroyed?: boolean;
|
||||
_emit(opts: ToastOptions): ToastInstance;
|
||||
_remove(id: string): void;
|
||||
_resolve(loadingToast: ToastInstance, type: string, message: string, opts: ToastOptions): ToastInstance | null;
|
||||
_groupCount(name: string): number;
|
||||
configure(opts: Partial<ToastConfig>): MeToast;
|
||||
init(options?: InitOptions): MeToast;
|
||||
destroy(): void;
|
||||
getStatus(): StatusInfo;
|
||||
getConfig(): ToastConfig;
|
||||
updateConfig(config: Partial<ToastConfig>): MeToast;
|
||||
resetConfig(): MeToast;
|
||||
show(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
success(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
error(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
warning(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
info(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
loading(messageOrOpts: string | ToastOptions, opts?: ToastOptions): LoadingControl;
|
||||
promise<T>(promise: Promise<T>, opts?: PromiseOptions): Promise<T>;
|
||||
confirm(message: string, opts?: ConfirmOptions): Promise<boolean>;
|
||||
prompt(message: string, opts?: PromptOptions): Promise<string | null>;
|
||||
progress(messageOrOpts: string | ToastOptions, opts?: ProgressOptions): ProgressControl;
|
||||
countdown(message: string, seconds?: number, opts?: CountdownOptions): CountdownControl;
|
||||
action(messageOrOpts: string | ToastOptions, actions?: ActionButton[], opts?: ToastOptions): ActionControl;
|
||||
queue(messages: Array<string | ToastOptions>, opts?: QueueOptions): QueueControl;
|
||||
stack(messages: Array<string | ToastOptions>, opts?: StackOptions): void;
|
||||
group(name: string): GroupAPI;
|
||||
dismissGroup(name: string): void;
|
||||
find(id: string): ToastInstance | undefined;
|
||||
dismiss(id?: string): void;
|
||||
removeToast(id: string): void;
|
||||
clear(position?: ToastPosition): void;
|
||||
getToasts(): ToastInstance[];
|
||||
count(): number;
|
||||
hasToasts(): boolean;
|
||||
getToast(id: string): ToastInstance | null;
|
||||
closeAll(): void;
|
||||
clearAll(): void;
|
||||
pauseAll(): void;
|
||||
resumeAll(): void;
|
||||
updateAll(partial: Partial<ToastOptions>): void;
|
||||
findToasts(predicate: (toast: ToastInstance) => boolean): ToastInstance[];
|
||||
findByType(type: ToastType): ToastInstance[];
|
||||
findByPosition(position: ToastPosition): ToastInstance[];
|
||||
getAll(): Map<string, ToastInstance>;
|
||||
use(plugin: string | Plugin, options?: Record<string, unknown>): MeToast;
|
||||
animations: AnimationUtils;
|
||||
themes: ThemeUtils;
|
||||
i18n: I18nUtils;
|
||||
plugins: PluginUtils;
|
||||
presetPlugins: Record<string, Plugin>;
|
||||
}
|
||||
declare global {
|
||||
interface Window {
|
||||
MeToast: MeToast;
|
||||
Met: MeToast;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 增强的 MeToast 对象 — 在 meToast 基础上注入子模块
|
||||
*/
|
||||
declare const enhancedMeToast: {
|
||||
version: string;
|
||||
animations: AnimationUtils;
|
||||
themes: ThemeUtils;
|
||||
i18n: I18nUtils;
|
||||
plugins: PluginUtils;
|
||||
presetPlugins: Record<string, Plugin>;
|
||||
_toasts: Map<string, ToastInstance>;
|
||||
_config: ToastConfig;
|
||||
_destroyed?: boolean;
|
||||
_emit(opts: ToastOptions): ToastInstance;
|
||||
_remove(id: string): void;
|
||||
_resolve(loadingToast: ToastInstance, type: string, message: string, opts: ToastOptions): ToastInstance | null;
|
||||
_groupCount(name: string): number;
|
||||
configure(opts: Partial<ToastConfig>): MeToast;
|
||||
init(options?: InitOptions): MeToast;
|
||||
destroy(): void;
|
||||
getStatus(): StatusInfo;
|
||||
getConfig(): ToastConfig;
|
||||
updateConfig(config: Partial<ToastConfig>): MeToast;
|
||||
resetConfig(): MeToast;
|
||||
show(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
success(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
error(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
warning(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
info(messageOrOpts: string | ToastOptions, opts?: ToastOptions): ToastInstance;
|
||||
loading(messageOrOpts: string | ToastOptions, opts?: ToastOptions): LoadingControl;
|
||||
promise<T>(promise: Promise<T>, opts?: PromiseOptions): Promise<T>;
|
||||
confirm(message: string, opts?: ConfirmOptions): Promise<boolean>;
|
||||
prompt(message: string, opts?: PromptOptions): Promise<string | null>;
|
||||
progress(messageOrOpts: string | ToastOptions, opts?: ProgressOptions): ProgressControl;
|
||||
countdown(message: string, seconds?: number, opts?: CountdownOptions): CountdownControl;
|
||||
action(messageOrOpts: string | ToastOptions, actions?: ActionButton[], opts?: ToastOptions): ActionControl;
|
||||
queue(messages: Array<string | ToastOptions>, opts?: QueueOptions): QueueControl;
|
||||
stack(messages: Array<string | ToastOptions>, opts?: StackOptions): void;
|
||||
group(name: string): GroupAPI;
|
||||
dismissGroup(name: string): void;
|
||||
find(id: string): ToastInstance | undefined;
|
||||
dismiss(id?: string): void;
|
||||
removeToast(id: string): void;
|
||||
clear(position?: ToastPosition): void;
|
||||
getToasts(): ToastInstance[];
|
||||
count(): number;
|
||||
hasToasts(): boolean;
|
||||
getToast(id: string): ToastInstance | null;
|
||||
closeAll(): void;
|
||||
clearAll(): void;
|
||||
pauseAll(): void;
|
||||
resumeAll(): void;
|
||||
updateAll(partial: Partial<ToastOptions>): void;
|
||||
findToasts(predicate: (toast: ToastInstance) => boolean): ToastInstance[];
|
||||
findByType(type: ToastType): ToastInstance[];
|
||||
findByPosition(position: ToastPosition): ToastInstance[];
|
||||
getAll(): Map<string, ToastInstance>;
|
||||
use(plugin: string | Plugin, options?: Record<string, unknown>): MeToast;
|
||||
};
|
||||
|
||||
/**
|
||||
* MetonaToast React — React 适配器
|
||||
* @module react
|
||||
* @version 0.4.0
|
||||
* @description useToast hook + 声明式 <Toast /> 组件。主包保持零依赖,React 为 optional peerDependency
|
||||
*/
|
||||
|
||||
/** 支持声明式渲染的 Toast 类型 */
|
||||
type ReactToastType = 'success' | 'error' | 'warning' | 'info' | 'show' | (string & {});
|
||||
interface ToastProps extends Omit<ToastOptions, 'message' | 'type'> {
|
||||
message: string;
|
||||
type?: ReactToastType;
|
||||
/** 组件卸载时自动移除该 Toast(默认 true)。设为 false 则 Toast 独立于组件生命周期 */
|
||||
autoClose?: boolean;
|
||||
}
|
||||
/**
|
||||
* 创建绑定清理集合的 API — 组件卸载时自动移除本组件创建的 Toast。
|
||||
* 纯函数,便于独立测试与扩展。
|
||||
*/
|
||||
declare const createBoundApi: (cleanup: Set<string>) => Record<string, unknown>;
|
||||
/**
|
||||
* useToast — 返回 MeToast API,但本组件创建的 Toast 会在组件卸载时自动移除。
|
||||
* 适合"通知随组件生命周期"的场景(如表单提交、异步任务页)。
|
||||
*/
|
||||
declare const useToast: () => Record<string, unknown>;
|
||||
/**
|
||||
* Toast — 声明式 Toast 组件。props 变化时更新内容(重新创建实例),
|
||||
* 组件卸载时自动移除(autoClose 默认 true)。
|
||||
*/
|
||||
declare const Toast: (props: ToastProps) => null;
|
||||
|
||||
export { enhancedMeToast as MeToast, ReactToastType, Toast, ToastProps, createBoundApi, useToast };
|
||||
Vendored
+4577
File diff suppressed because it is too large
Load Diff
Vendored
+1
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user