feat: v0.2.1 — reference links, context menu, RTL, ja/ko, regex search, hooks, copy API
## Added - Reference link/image resolution: [text][ref] + ![alt][ref] with [ref]: url definitions - Right-click context menu: undo/redo/cut/copy/paste/selectAll + custom items - RTL CSS layout support for Arabic, Hebrew, Persian etc. - Japanese (ja) and Korean (ko) locales with 60+ keys each - Divider position localStorage persistence - Regex search toggle in search/replace panel - Export HTML with embedded CSS styles - beforeChange / afterChange lifecycle hooks (instance + global) - copyAsMarkdown() / copyAsHTML() clipboard APIs - CHANGELOG.md, CONTRIBUTING.md, CI workflow (.github/workflows/ci.yml) - 2 new test suites: index.test.ts, styles.test.ts (684 total tests, +74) ## Changed - autoSave plugin: closure-based state per instance instead of this context - Plugin install() now receives options as second argument - RTL locale detection: now uses language prefix (ar-SA → RTL) - Rollup dev mode: only builds UMD format - prepublishOnly now includes typecheck + test - Version bumped to 0.2.1 ## Fixed - [text][ref] now correctly renders as link (was raw text) - ![alt][ref] no longer produces empty src - autoSave plugin state isolation across multiple editor instances - Footnote definitions no longer consumed by refDef handler
This commit is contained in:
@@ -0,0 +1,109 @@
|
||||
/**
|
||||
* styles.ts 单元测试
|
||||
* 覆盖 injectStyles / updateStyles / removeStyles
|
||||
*/
|
||||
|
||||
import { injectStyles, updateStyles, removeStyles, getSystemTheme, watchSystemTheme } from '../src/styles';
|
||||
|
||||
describe('styles.ts - injectStyles', () => {
|
||||
afterEach(() => {
|
||||
removeStyles();
|
||||
});
|
||||
|
||||
test('injectStyles 创建 <style> 元素', () => {
|
||||
injectStyles();
|
||||
const el = document.getElementById('metona-editor-styles');
|
||||
expect(el).not.toBeNull();
|
||||
expect(el!.tagName).toBe('STYLE');
|
||||
});
|
||||
|
||||
test('injectStyles 重复调用不创建重复元素', () => {
|
||||
injectStyles();
|
||||
injectStyles();
|
||||
const els = document.querySelectorAll('#metona-editor-styles');
|
||||
expect(els.length).toBe(1);
|
||||
});
|
||||
|
||||
test('注入的 CSS 包含编辑器样式规则', () => {
|
||||
injectStyles();
|
||||
const el = document.getElementById('metona-editor-styles');
|
||||
const css = el!.textContent || '';
|
||||
expect(css).toContain('.me-wrapper');
|
||||
expect(css).toContain('.me-toolbar');
|
||||
expect(css).toContain('.me-textarea');
|
||||
expect(css).toContain('.me-preview');
|
||||
expect(css).toContain('--md-bg');
|
||||
expect(css).toContain('--md-accent');
|
||||
});
|
||||
|
||||
test('注入的 CSS 包含 RTL 规则', () => {
|
||||
injectStyles();
|
||||
const el = document.getElementById('metona-editor-styles');
|
||||
const css = el!.textContent || '';
|
||||
expect(css).toContain('[dir=rtl]');
|
||||
});
|
||||
|
||||
test('注入的 CSS 包含打印样式', () => {
|
||||
injectStyles();
|
||||
const el = document.getElementById('metona-editor-styles');
|
||||
const css = el!.textContent || '';
|
||||
expect(css).toContain('@media print');
|
||||
});
|
||||
|
||||
test('注入的 CSS 包含 reduced-motion', () => {
|
||||
injectStyles();
|
||||
const el = document.getElementById('metona-editor-styles');
|
||||
const css = el!.textContent || '';
|
||||
expect(css).toContain('prefers-reduced-motion');
|
||||
});
|
||||
});
|
||||
|
||||
describe('styles.ts - updateStyles', () => {
|
||||
afterEach(() => {
|
||||
removeStyles();
|
||||
});
|
||||
|
||||
test('updateStyles 更新已注入的样式', () => {
|
||||
injectStyles();
|
||||
const el = document.getElementById('metona-editor-styles')!;
|
||||
const original = el.textContent;
|
||||
updateStyles();
|
||||
expect(el.textContent).toBe(original); // 内容一致
|
||||
});
|
||||
|
||||
test('updateStyles 在未注入时自动注入', () => {
|
||||
removeStyles();
|
||||
expect(document.getElementById('metona-editor-styles')).toBeNull();
|
||||
updateStyles();
|
||||
expect(document.getElementById('metona-editor-styles')).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe('styles.ts - removeStyles', () => {
|
||||
test('removeStyles 移除样式元素', () => {
|
||||
injectStyles();
|
||||
expect(document.getElementById('metona-editor-styles')).not.toBeNull();
|
||||
removeStyles();
|
||||
expect(document.getElementById('metona-editor-styles')).toBeNull();
|
||||
});
|
||||
|
||||
test('removeStyles 重复调用不抛错', () => {
|
||||
removeStyles();
|
||||
expect(() => removeStyles()).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
||||
describe('styles.ts - getSystemTheme', () => {
|
||||
test('返回 light 或 dark', () => {
|
||||
const theme = getSystemTheme();
|
||||
expect(['light', 'dark']).toContain(theme);
|
||||
});
|
||||
});
|
||||
|
||||
describe('styles.ts - watchSystemTheme', () => {
|
||||
test('返回取消函数', () => {
|
||||
const unsub = watchSystemTheme(() => {});
|
||||
expect(typeof unsub).toBe('function');
|
||||
unsub();
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user