release: v0.1.12 — accessibility, Zen mode, scroll sync v2, shortcutHelp plugin

feat(a11y): toolbar keyboard navigation (Arrow keys, Home, End)
feat(a11y): aria-live region for screen reader announcements on mode change
feat(a11y): enhance focus-visible style (outline-offset: 2px, hide on mouse focus)

feat(core): Zen mode (editor.toggleZen() / exec('zen'))
- Toggle with Ctrl+Shift+Z shortcut concept
- Auto-hide toolbar and statusbar, mouse to top edge reveals toolbar
- Centered editor pane with max-width constraint

feat(core): heading-aware scroll sync v2
- Sync preview scroll to nearest heading before cursor position
- Falls back to proportional sync when no headings found

feat(core): Word wrap toggle (editor.toggleWordWrap() / setWordWrap(bool))

feat(plugins): shortcutHelp preset plugin
- Press '?' to open keyboard shortcuts overlay panel
- Lists built-in + user-registered shortcuts
- Click overlay or press Escape to close

style: Zen mode CSS, sr-only class, focus-visible refinement

test: 3 new tests for Zen mode, WordWrap, shortcutHelp (535 total)

chore: bump version 0.1.11 → 0.1.12 across all files
This commit is contained in:
2026-07-24 16:10:51 +08:00
parent faa329682c
commit 4e63870180
18 changed files with 337 additions and 34 deletions
+91 -1
View File
@@ -1,7 +1,7 @@
/**
* MetonaEditor Plugins — 插件系统 v2
* @module plugins
* @version 0.1.11
* @version 0.1.12
* @description 插件管理器 + 预设插件 + 依赖/生命周期/异步/卸载
*
* v0.1.6 增强:
@@ -510,6 +510,95 @@ const imagePastePlugin = {
},
};
/**
* 快捷键帮助插件(v0.1.12)
* 按 ? 弹出快捷键列表面板
*/
const shortcutHelpPlugin = {
name: 'shortcutHelp',
version: '0.1.0',
description: '按 ? 查看快捷键列表',
priority: 200,
_onKeydown: null,
_panel: null,
install(editor) {
if (!editor || !editor.textarea || typeof document === 'undefined') return;
this._injectStyle();
this._onKeydown = (e) => {
// ? 键(Shift+/),且不在输入框中时
if (e.key === '?' && !e.ctrlKey && !e.metaKey && !e.altKey) {
e.preventDefault();
this._open(editor);
}
if (e.key === 'Escape' && this._panel) {
this._close();
}
};
editor.textarea.addEventListener('keydown', this._onKeydown);
},
_injectStyle() {
if (document.getElementById('me-shortcut-style')) return;
const style = document.createElement('style');
style.id = 'me-shortcut-style';
style.textContent = `.me-shortcut-overlay{position:fixed;top:0;left:0;right:0;bottom:0;z-index:50;background:rgba(0,0,0,0.5);display:flex;align-items:center;justify-content:center}.me-shortcut-panel{background:var(--md-bg,#fff);border-radius:12px;padding:24px;max-width:560px;width:90%;max-height:80vh;overflow-y:auto;box-shadow:0 12px 40px rgba(0,0,0,0.3)}.me-shortcut-panel h3{font-size:16px;margin:0 0 16px;color:var(--md-text)}.me-shortcut-panel table{width:100%;border-collapse:collapse;font-size:13px}.me-shortcut-panel td{padding:6px 10px;border-bottom:1px solid var(--md-border)}.me-shortcut-panel td:first-child{font-family:var(--md-mono);font-size:12px;color:var(--md-accent);white-space:nowrap;width:40%}.me-shortcut-panel td:last-child{color:var(--md-text)}.me-shortcut-panel .me-shortcut-close{position:absolute;top:16px;right:20px;background:none;border:none;font-size:20px;cursor:pointer;color:var(--md-muted)}`;
document.head.appendChild(style);
},
_open(editor) {
if (this._panel) { this._close(); return; }
const builtin = [
['Ctrl+B', '粗体'], ['Ctrl+I', '斜体'], ['Ctrl+U', '下划线'],
['Ctrl+K', '链接'], ['Ctrl+E', '行内代码'],
['Ctrl+1/2/3', '标题 H1/H2/H3'], ['Ctrl+Q', '引用'],
['Ctrl+Z', '撤销'], ['Ctrl+Y / Ctrl+Shift+Z', '重做'],
['Ctrl+S', '保存'], ['Ctrl+F', '查找'], ['Ctrl+H', '替换'],
['Tab', '缩进'], ['Shift+Tab', '反缩进'],
['Ctrl+Shift+T', 'Zen 模式演示快捷键'],
['?', '显示/隐藏快捷键帮助'],
];
const custom = (editor.getShortcuts && editor.getShortcuts()) || [];
const customRows = custom.map((s) => [s.combo, s.description || s.combo]);
const allRows = [...builtin, ...customRows];
let rows = '';
allRows.forEach(([combo, desc]) => {
rows += `<tr><td>${combo}</td><td>${desc}</td></tr>`;
});
const overlay = document.createElement('div');
overlay.className = 'me-shortcut-overlay';
overlay.innerHTML = `<div class="me-shortcut-panel"><h3>⌨️ 快捷键</h3><button class="me-shortcut-close">×</button><table>${rows}</table></div>`;
overlay.addEventListener('click', (e) => {
if (e.target === overlay || e.target.classList.contains('me-shortcut-close')) {
this._close();
}
});
document.body.appendChild(overlay);
this._panel = overlay;
},
_close() {
if (this._panel) {
this._panel.remove();
this._panel = null;
}
},
destroy(editor) {
this._close();
if (this._onKeydown && editor && editor.textarea) {
editor.textarea.removeEventListener('keydown', this._onKeydown);
}
this._onKeydown = null;
},
};
// ============ 预设插件表 ============
const presetPlugins = {
@@ -517,6 +606,7 @@ const presetPlugins = {
exportTool: exportToolPlugin,
searchReplace: searchReplacePlugin,
imagePaste: imagePastePlugin,
shortcutHelp: shortcutHelpPlugin,
};
// ============ 实用工具 ============