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:
tianhao
2026-08-08 14:45:19 +08:00
parent 2937ce5e2d
commit bbff631f4f
41 changed files with 10761 additions and 161 deletions
+49
View File
@@ -0,0 +1,49 @@
/**
* 环境隔离测试 — 需要切换 document/window/localStorage 环境并调用 jest.resetModules()。
* 独立成文件:resetModules 会清空模块缓存,若与其他测试同文件会导致
* 后续 require 拿到新模块实例、与 import 时绑定的实例状态分裂。
* @module tests
* @version 0.4.0
*/
describe('环境隔离(SSR / localStorage 异常路径)', () => {
test('escapeHTML SSR 路径(无 document', () => {
const originalDoc = (global as Record<string, unknown>).document;
(global as Record<string, unknown>).document = undefined;
jest.resetModules();
const { escapeHTML } = require('../src/utils.js');
const result = escapeHTML('<script>alert("xss")</script>');
expect(result).not.toContain('<script>');
expect(result).toContain('&lt;script&gt;');
(global as Record<string, unknown>).document = originalDoc;
});
test('prefersDark 无 window 时返回 false', () => {
const originalWindow = (global as Record<string, unknown>).window;
(global as Record<string, unknown>).window = undefined;
jest.resetModules();
const { prefersDark } = require('../src/utils.js');
expect(prefersDark()).toBe(false);
(global as Record<string, unknown>).window = originalWindow;
});
test('saveTheme localStorage 异常被捕获', () => {
const orig = (global as Record<string, unknown>).localStorage;
(global as Record<string, unknown>).localStorage = undefined;
jest.resetModules();
const { saveTheme } = require('../src/themes.js');
expect(() => saveTheme('dark')).not.toThrow();
(global as Record<string, unknown>).localStorage = orig;
});
test('loadLocale localStorage 异常返回 default', () => {
const orig = (global as Record<string, unknown>).localStorage;
(global as Record<string, unknown>).localStorage = {
getItem: () => { throw new Error('quota'); },
};
jest.resetModules();
const { loadLocale } = require('../src/i18n.js');
expect(typeof loadLocale()).toBe('string');
(global as Record<string, unknown>).localStorage = orig;
});
});