docs: 重写 README 与 site 站点 — 精美酷炫全新视觉

- README 全面更新:对齐 v0.5.0(钩子系统完整表、React 适配器、dragThreshold、工程质量章节)
- site 三页全新设计:深色渐变 + 玻璃拟态 + 光球漂浮 + 网格背景 + 终端风格代码块 + 滚动淡入
- index.html:Hero 自动演示、数据统计条、12 特性卡、环境支持、CTA
- docs.html:28 项 API 导航、滚动高亮、补全钩子系统/React/配置项/动画/主题章节
- demo.html:18 交互卡片、新增钩子拦截/dedupe 去重/自定义动画/拖拽阈值演示、107 图标网格
- jsdom 冒烟验证:三页 MeToast 全局注册、toast 渲染、图标网格/卡片/代码块完整
This commit is contained in:
tianhao
2026-08-08 15:11:04 +08:00
parent 1f718c4ef8
commit dd061025e0
4 changed files with 1019 additions and 688 deletions
+110 -44
View File
@@ -5,18 +5,21 @@
[![npm version](https://img.shields.io/npm/v/@metona-team/metona-toast.svg)](https://www.npmjs.com/package/@metona-team/metona-toast)
[![bundle size](https://img.shields.io/bundlephobia/minzip/@metona-team/metona-toast)](https://bundlephobia.com/package/@metona-team/metona-toast)
[![license](https://img.shields.io/badge/license-MIT-green.svg)](https://git.metona.cn/MetonaTeam/MetonaToast)
[![coverage](https://img.shields.io/badge/coverage-96%25-brightgreen.svg)](https://git.metona.cn/MetonaTeam/MetonaToast)
## 特性
- **零依赖** — TypeScript 严格模式源码,gzip 后不到 10KB
- **107 种图标类型** — success/error/warning/info/loading 及更多扩展类型,覆盖所有常见场景
- **11 种动画** — slide/fade/scale/bounce/flip/rotate/zoom/slideUp/slideDown/slideLeft/slideRight每种效果明显不同
- **主题系统** — light/dark/auto/warm 四种内置主题,支持 `registerTheme()` 注册自定义主题
- **国际化** — 内置 zh-CN / en-US 完整翻译(去重优化),可通过 `addTranslations()` 扩展
- **插件系统** — 4 款预设插件 (keyboard/persistence/accessibility/dedupe) + 自定义插件
- **可拖拽关闭** — 拖动 Toast 任意方向即可关闭,阈值可配置
- **TypeScript** — 严格模式,源码级类型安全,类型从源码自动生成无手动维护
- **全局错误回调** — `onError` 捕获所有钩子异常和定时器错误,方便接入监控系统
- **零依赖** — TypeScript 严格模式源码,gzip 后不到 10KB,无任何运行时依赖
- **107 种图标类型** — success/error/warning/info/loading 及 100+ 扩展类型,覆盖所有常见场景
- **11 种动画 + 自定义** — slide/fade/scale/bounce/flip/rotate/zoom/slideUp/slideDown/slideLeft/slideRight`animations.register()` 可注册任意自定义动画(动态注入 keyframes,真实生效)
- **主题系统** — light/dark/auto/warm 四种内置主题,`registerTheme()` 注册自定义主题,跟随系统主题自动切换
- **国际化** — 内置 zh-CN / en-US 完整翻译`addTranslations()` 扩展任意语言,RTL 语言完整适配
- **插件系统** — 4 款预设插件 (keyboard / persistence / accessibility / dedupe) + 自定义插件
- **完整钩子系统** — 17 个生命周期与事件钩子,`beforeShow` / `beforeClose` / `beforeUpdate` 支持返回 `false` 拦截
- **可拖拽关闭** — 拖动 Toast 任意方向即可关闭,阈值 `dragThreshold` 可配置
- **React 适配器** — `@metona-team/metona-toast/react` 子路径导入,`useToast()` hook + 声明式 `<Toast />` 组件,主包保持零依赖
- **全局错误回调** — `onError` 捕获所有钩子异常和定时器错误,方便接入 Sentry、DataDog 等监控系统
- **工程质量** — 385 个测试全过,行覆盖率 96.42%,lint 零警告,CI 含覆盖率门禁(≥95%)
## 安装
@@ -59,13 +62,13 @@ const MeToast = require('@metona-team/metona-toast');
| iOS Safari | 11+ |
| Android Chrome | 64+ |
| Node.js | 16+ESM & CJS 双格式) |
| TypeScript | 4.5+(完整类型声明) |
| TypeScript | 4.5+(完整类型声明,类型从源码自动生成 |
核心依赖:Web Animations APIChrome 64+, Firefox 63+, Safari 11+)、Pointer Events、CSS Grid、CSS Custom Properties。
## 快速开始
浏览器 `window`注册两个全局变量:`MeToast``Met`两者完全等价,任选其一使用
浏览器 `window` 上注册两个全局变量:`MeToast``Met`,完全等价。
```javascript
import MeToast from '@metona-team/metona-toast';
@@ -82,13 +85,11 @@ MeToast.info('系统维护中');
// 带标题
MeToast.success({ title: '保存成功', message: '文件已同步到云端' });
// 加载 → 成功链式转换(原地更新同一实例,id 稳定)
// 加载 → 链式转换(原地更新同一实例,id 稳定)
const loading = MeToast.loading('正在提交...');
const toast = await wait();
loading.success('提交成功!');
// toast.id === loading.id
setTimeout(() => loading.success('提交成功!'), 2000);
// Promise 风格
// Promise 风格 — 自动 loading → success/error
await MeToast.promise(fetch('/api/data'), {
loading: '加载中...',
success: '加载完成!',
@@ -102,17 +103,22 @@ await MeToast.promise(fetch('/api/data'), {
MeToast.configure({
position: 'top-right', // top-left | top-center | top-right | bottom-left | bottom-center | bottom-right
duration: 4000, // 显示时长(ms),0 为不自动关闭
max: 6, // 同最多显示条数
theme: 'auto', // light | dark | auto | warm
animation: 'slide', // slide | fade | scale | bounce | flip | rotate | zoom | slideUp | slideDown | slideLeft | slideRight
max: 6, // 同一位置最多显示条数,超出关闭最早的
gap: 12, // Toast 间距(px)
offset: 24, // 容器距屏幕边缘(px)
theme: 'auto', // light | dark | auto(跟随系统)| warm
animation: 'slide', // 11 种内置动画或自定义动画名
pauseOnHover: true, // 悬停暂停计时
closeOnClick: true, // 点击关闭
draggable: true, // 允许拖拽关闭
dragThreshold: 120, // 拖拽关闭阈值(px)
showProgress: true, // 显示进度条
draggable: true, // 允许拖拽关闭
progressDirection: 'horizontal', // horizontal | vertical
zIndex: 9999,
width: 360,
locale: 'zh-CN', // 语言
onError: ({ hook, error, toast }) => { // 全局错误回调(钩子/定时器异常)
onError: ({ hook, source, error, toast }) => {
// 钩子/定时器异常全局捕获,可接入监控系统
console.error('Toast error:', hook, error);
},
});
@@ -120,40 +126,42 @@ MeToast.configure({
## 动画效果
11 种动画,每种感官差异明显:
11 种内置动画,每种感官差异明显:
| 动画 | 效果描述 |
|------|----------|
| `slide` | 从右侧滑入 + 轻微过冲回弹 |
| `fade` | 纯淡入(blur→清晰),从容优雅 |
| `scale` | 弹性放大(0.55→1.07→1.0 |
| `bounce` | 从天而降四段弹跳 |
| `flip` | 3D 翻转入场 + 回摆 |
| `rotate` | 旋转摇摆进入 |
| `zoom` | 从中心爆发式弹出 |
| `slideUp` | 从下方弹入 |
| `slideDown` | 从上方弹入 |
| `slideLeft` | 从左侧滑入 |
| `slideRight` | 从右侧滑入 |
| 动画 | 效果描述 | 时长 |
|------|----------|------|
| `slide` | 从右侧滑入 + 轻微过冲回弹 | 400ms |
| `fade` | 纯淡入(blur→清晰),从容优雅 | 500ms |
| `scale` | 弹性放大(0.55→1.07→1.0 | 450ms |
| `bounce` | 从天而降四段弹跳 | 650ms |
| `flip` | 3D 翻转入场 + 回摆 | 500ms |
| `rotate` | 旋转摇摆进入 | 500ms |
| `zoom` | 从中心爆发式弹出 | 500ms |
| `slideUp` | 从下方弹入 | 400ms |
| `slideDown` | 从上方弹入 | 400ms |
| `slideLeft` | 从左侧滑入 | 400ms |
| `slideRight` | 从右侧滑入 | 400ms |
```javascript
MeToast.success('弹跳动画', { animation: 'bounce' });
// 注册自定义动画
// 注册自定义动画 — 动态注入 keyframes,真实生效
MeToast.animations.register('myAnim', {
enter: { transform: 'rotate(-30deg) scale(0.5)', opacity: 0 },
leave: { transform: 'rotate(0) scale(1)', opacity: 1 },
duration: 500,
easing: 'cubic-bezier(0.34, 1.56, 0.64, 1)',
});
MeToast.success('自定义动画', { animation: 'myAnim' });
```
## 主题
```javascript
// 切换主题
// 切换主题(自动持久化到 localStorage
MeToast.themes.switchTheme('dark');
MeToast.themes.switchTheme('warm');
MeToast.themes.toggleTheme(); // light ↔ dark
// 注册自定义主题
MeToast.themes.registerTheme('ocean', {
@@ -192,6 +200,18 @@ await MeToast.queue(['步骤一', '步骤二', '步骤三'], { delay: 800 });
// 堆叠展示(同时错峰)
MeToast.stack(['消息1', '消息2', '消息3'], { stagger: 150 });
// Action Toast — 内嵌操作按钮(close:false 可多次点击不关闭)
MeToast.action('文件已删除', [
{ text: '撤销', onClick: () => restore(), color: '#3b82f6' },
{ text: '查看', onClick: () => open(), color: '#10b981', close: false },
]);
// 分组管理
const orders = MeToast.group('orders');
orders.success('订单已创建');
orders.count(); // 该组 toast 数量
orders.dismiss(); // 一键关闭整组
```
## 插件
@@ -203,7 +223,7 @@ MeToast.use('persistence'); // 配置持久化到 localStorage
MeToast.use('accessibility'); // 屏幕阅读器朗读公告
MeToast.use('dedupe'); // 相同 type+message 自动去重(更新已有实例)
// 自定义插件(通过 install 中注册 Toast 生命周期钩子)
// 自定义插件(install 中注册生命周期钩子)
import MeToast, { Toast } from '@metona-team/metona-toast';
MeToast.use({
@@ -213,6 +233,36 @@ MeToast.use({
console.log('Toast shown:', toast.message);
});
},
uninstall() {
console.log('plugin removed');
},
});
```
## 钩子系统
`Toast.on(name, handler)` 注册钩子,返回取消函数。`beforeShow` / `beforeClose` / `beforeUpdate` 的 handler 返回 `false` 可拦截对应操作。
| 钩子 | 触发时机 | 拦截 |
|------|----------|------|
| `beforeInit` / `afterInit` | `init()` 前后 | — |
| `beforeDestroy` / `afterDestroy` | `destroy()` 前后 | — |
| `beforeShow` / `afterShow` | Toast 显示前后 | ✅ 返回 false 阻止显示 |
| `beforeClose` / `afterClose` | Toast 关闭前后 | ✅ 返回 false 阻止关闭 |
| `beforeUpdate` / `afterUpdate` | `update()` 前后 | ✅ 返回 false 阻止更新 |
| `configChange` | `configure`/`updateConfig`/`resetConfig` | — |
| `themeChange` | 主题切换 | — |
| `localeChange` | 语言切换 | — |
| `click` | 点击 Toast 主体 | — |
| `hover` | 鼠标悬停进出 | — |
| `dragStart` / `dragEnd` | 拖拽开始/结束 | — |
| `animationStart` / `animationEnd` | 入场动画开始/结束 | — |
| `progressStart` / `progressEnd` | 倒计时开始/归零 | — |
```javascript
// 拦截示例:指定类型禁止显示
Toast.on('beforeShow', (toast) => {
if (toast.type === 'error' && !isAllowed) return false;
});
```
@@ -221,7 +271,7 @@ MeToast.use({
```javascript
MeToast.i18n.switchLocale('en-US');
// 添加语言
// 添加语言(嵌套结构支持深度合并)
MeToast.i18n.addTranslations('ja', {
success: '成功',
error: 'エラー',
@@ -229,9 +279,11 @@ MeToast.i18n.addTranslations('ja', {
cancel: 'キャンセル',
});
// 格式化工具
// 格式化工具(基于 Intl
MeToast.i18n.formatNumber(1234567); // "1,234,567"
MeToast.i18n.formatCurrency(99, 'CNY'); // "¥99.00"
MeToast.i18n.formatDate(new Date());
MeToast.i18n.formatRelativeTime(Date.now() + 3600000); // "1 小时后"
```
## Toast 管理
@@ -240,11 +292,17 @@ MeToast.i18n.formatCurrency(99, 'CNY'); // "¥99.00"
MeToast.count(); // 当前数量
MeToast.getAll(); // 获取原生 Map<id, ToastInstance>
MeToast.getToasts(); // 获取所有实例数组
MeToast.find(id); // 查找实例(不存在返回 undefined)
MeToast.findByType(type); // 按类型过滤
MeToast.findByPosition(pos);// 按位置过滤
MeToast.dismiss(); // 关闭所有
MeToast.dismiss(id); // 关闭指定
MeToast.removeToast(id); // 立即移除(无离场动画)
MeToast.clear(position?); // 按位置清除
MeToast.pauseAll(); // 暂停所有计时
MeToast.resumeAll(); // 恢复所有计时
MeToast.destroy(); // 完全销毁(支持重复调用)
MeToast.updateAll(partial); // 批量更新
MeToast.destroy(); // 完全销毁(支持重复调用,init() 可恢复)
```
## 回调
@@ -252,6 +310,7 @@ MeToast.destroy(); // 完全销毁(支持重复调用)
```javascript
MeToast.success({
message: '操作成功',
onBeforeShow: (toast) => true, // 返回 false 阻止显示
onShow: (toast) => console.log('显示:', toast.id),
onClose: (toast) => console.log('关闭:', toast.id),
onClick: (toast) => console.log('点击:', toast.id),
@@ -261,7 +320,6 @@ MeToast.success({
// 全局错误回调 — 捕获钩子异常和定时器错误
MeToast.configure({
onError: ({ hook, source, error, toast }) => {
// 接入监控系统 (Sentry, DataDog 等)
reportError(error, { hook, source, toastId: toast?.id });
},
});
@@ -269,7 +327,7 @@ MeToast.configure({
## React 适配器
主包保持零依赖;React 适配器通过子路径导入,`react` 为 optional peerDependency。
主包保持零依赖;React 适配器通过子路径导入,`react` 为 optional peerDependency,未使用 React 的项目不受影响
```bash
npm install @metona-team/metona-toast react
@@ -295,12 +353,20 @@ function SubmitButton() {
return <button onClick={submit}></button>;
}
// 声明式 Toast — props 变化时更新,组件卸载时自动移除
// 声明式 Toast — props 变化时更新内容,组件卸载时自动移除autoClose 默认 true
function SaveIndicator({ saving }: { saving: boolean }) {
return saving ? <Toast type="info" message="正在保存..." /> : null;
}
```
## 工程质量
- **385 个测试** 全部通过(单元 + DOM 交互 + React 渲染 + SSR 环境隔离)
- **行覆盖率 96.42%**jest 覆盖率门禁 `lines >= 95%`,未达标构建即失败
- **lint 零警告**TypeScript ESLint 严格检查)
- **CI**Gitea Actions):Node 18/20/22/24 矩阵 — typecheck → lint → 测试+覆盖率门禁 → 构建 → bundle size 检查
- **自动发布**:推送 `v*` tag 触发测试、构建并发布到 Gitea npm registry
## License
MIT