diff --git a/README.md b/README.md index 30e71ad..c6fcaa2 100644 --- a/README.md +++ b/README.md @@ -1,32 +1,25 @@ # MetonaEditor -> TypeScript 重构 · 零依赖 · 轻量级的桌面端 Markdown Editor 库。单文件,开箱即用。 +> TypeScript 重构 · 零运行时依赖 · 轻量级桌面端 Markdown Editor 库 -[![npm version](https://img.shields.io/badge/version-0.2.0-blue.svg)](https://www.npmjs.com/package/@metona-team/metona-editor) -[![license](https://img.shields.io/badge/license-MIT-green.svg)](./LICENSE) -[![tests](https://img.shields.io/badge/tests-583%20passed-brightgreen.svg)](./tests) -[![coverage](https://img.shields.io/badge/coverage-95%25%20(parser)-brightgreen.svg)](./tests) - ---- +[![version](https://img.shields.io/badge/version-0.2.0-blue)](https://git.metona.cn/MetonaTeam/-/packages/npm/@metona-team%2Fmetona-editor) +[![license](https://img.shields.io/badge/license-MIT-green)](./LICENSE) +[![tests](https://img.shields.io/badge/tests-610%20passed-brightgreen)](./tests) +[![coverage](https://img.shields.io/badge/coverage-parser%2099%25-brightgreen)](./tests) +[![types](https://img.shields.io/badge/types-TypeScript%20strict-blue)](./tsconfig.json) ## 特性 -- **TypeScript 源码** — v0.2.0 全模块 TypeScript 重构,完整类型支持,IDE 智能提示 -- **零依赖** — 单文件打包,无任何运行时依赖,UMD/ESM/CJS 三种格式 -- **现代化** — 原生 ES2020+ 实现,CSS 变量主题系统,响应式布局,无障碍支持 -- **易扩展** — 完整插件系统 v2(依赖拓扑排序、异步插件、生命周期钩子、`unuse` 卸载),自定义工具栏按钮与快捷键,预设插件开箱即用 -- **易维护** — 模块化源码,JSDoc 注释完整,TypeScript 类型声明,425 个单元测试覆盖 -- **易使用** — 工厂函数 `create()` 一行接入,链式 API,中文优先文档与翻译 -- **安全** — 内置 XSS 防护(`javascript:`/`vbscript:`/`file:` 协议过滤),HTML 转义,`safeUrl` 净化 -- **内置解析器** — 自研 CommonMark 子集 + GFM 扩展(表格含列对齐、任务列表、上下标、数学公式、脚注、嵌套列表、emoji 短码、三重强调、反斜杠转义等),可整体替换;v0.1.15 新增 parseTokens/renderTokens 分离 API + registerBlockHandler 块级扩展 -- **三模式视图** — edit / split / preview 自由切换,分屏拖拽调整比例,滚动同步,模式切换保持滚动位置 -- **编辑体验** — 语法高亮编辑区、行号装订线 + 当前行高亮、智能 Enter、括号闭合、拖放文件、大纲面板、Zen 专注模式、预览链接拦截 -- **主题系统** — light / dark / auto / warm 四套预设,CSS 变量定制,实例级主题隔离,外部主题跟随(syncWithElement / adoptFromParent),主题继承(extends),跟随系统主题,@media print 打印样式 -- **国际化** — zh-CN / en-US 完整翻译,实例级语言隔离,复数规则,命名空间,动态远程加载翻译包,RTL 支持 -- **历史栈** — 撤销/重做,防抖合并(可配置延迟),可配置上限 -- **只读模式** — `readOnly` 配置 / `setReadOnly()` API,适用于预览/展示场景 -- **预设插件** — autoSave、exportTool、searchReplace、imagePaste、shortcutHelp、fileSystem(IndexedDB 存储) -- **性能优化** — 渲染缓存跳过重复解析,`refresh()` 强制刷新,模式切换无冗余渲染 +- **TypeScript 源码** — 全模块 TypeScript 严格模式,完整类型导出,IDE 智能提示 +- **零运行时依赖** — 打包后单文件,无任何第三方库,UMD / ESM / CJS 三种格式 +- **自研解析器** — CommonMark + GFM 扩展,96% 语句覆盖率,parseTokens / renderTokens 分离 API,registerBlockHandler 自定义块语法 +- **插件系统 v2** — 拓扑排序依赖管理,6 个预设插件开箱即用,安装 / 卸载生命周期 +- **三模式视图** — edit / split / preview,拖拽分隔条调整比例,双向滚动同步 +- **主题系统** — light / dark / warm / auto,CSS 变量可定制,实例级隔离,主题继承,外部跟随 +- **国际化** — zh-CN / en-US 完整翻译,实例级语言隔离,远程加载翻译包 +- **编辑体验** — 行号装订线、智能 Enter、括号自动闭合、拖放文件、大纲面板、Zen 专注模式 +- **安全** — HTML 转义,XSS 协议过滤(javascript / vbscript / file / data),sanitize 钩子 +- **桌面端优先** — 纯电脑端设计,无移动端冗余代码 --- @@ -34,511 +27,477 @@ - [快速开始](#快速开始) - [配置项](#配置项) -- [API 参考](#api-参考) +- [工具栏](#工具栏) +- [实例 API](#实例-api) +- [静态 API](#静态-api) - [事件系统](#事件系统) +- [Markdown 解析器](#markdown-解析器) - [插件系统](#插件系统) - [主题系统](#主题系统) - [国际化](#国际化) -- [Markdown 解析器](#markdown-解析器) -- [TypeScript 支持](#typescript-支持) -- [测试](#测试) -- [构建](#构建) -- [浏览器兼容性](#浏览器兼容性) +- [构建与测试](#构建与测试) - [License](#license) --- ## 快速开始 -### 安装 +### npm 安装 ```bash npm install @metona-team/metona-editor ``` -### 浏览器直接引入(UMD) - -> 样式由 JS 自动注入(`styles.js` 运行时动态创建 `
-

文档

-

MetonaEditor v0.1.15 完整 API、配置与使用指南

+

API 文档

+

MetonaEditor v0.2.0 · TypeScript · 完整配置、API 与使用指南

@@ -191,19 +80,20 @@ 内容操作 命令执行 历史栈 - 模式与全屏 + 模式 / 全屏 / Zen 统计与状态 - 启用/禁用/只读 + 启用 / 禁用 / 只读 事件系统 插件管理 - 生命周期 + 快捷键管理 + 生命周期
静态 API
- 顶层函数 -
语法参考
- 解析器语法 - 解析器 API(v0.1.15) + 全局函数 +
解析器
+ 语法参考 + 解析器 API
插件
- 插件约定 + 插件约定 预设插件
主题
主题系统 @@ -213,94 +103,77 @@
- +

安装与引入

-
# npm 安装
 npm install @metona-team/metona-editor
 
-# ES Module
+// TypeScript / ES Module
 import MeEditor from '@metona-team/metona-editor';
 const editor = MeEditor.create('#editor', {
   value: '# Hello World',
   mode: 'split',
 });
 
-# 浏览器 UMD
+// 浏览器 UMD
 <script src="dist/metona-editor.js"></script>
 <script>
 const editor = MeEditor.create('#editor');
 </script>
- +

全部配置项

-

所有配置均为可选,以下是默认值:

- +

所有配置均为可选。

MeEditor.create(container, {
   // 内容
-  value: '',              // 初始 Markdown 文本
-  placeholder: '',        // 占位符
+  value: '',              placeholder: '',
 
   // 视图
-  mode: 'split',          // 'edit' | 'split' | 'preview'
-  height: 400,            // 数字为 px,字符串原样使用
-  toolbar: DEFAULT_TOOLBAR, // 工具栏配置,false 隐藏
-  wordCount: true,        // 字数统计状态栏
+  mode: 'split',          height: 400,
+  toolbar: DEFAULT_TOOLBAR, wordCount: true,
+  lineNumbers: true,       outline: false,
 
   // 行为
-  autofocus: false,       // 自动聚焦
-  spellcheck: false,      // 拼写检查
-  readOnly: false,        // 只读模式
-  historyLimit: 100,      // 历史栈上限
-  historyDebounce: 400,   // 历史防抖延迟(ms)
-  syncScroll: true,       // 分屏模式同步滚动
-  tabSize: 2,             // 制表符空格数(0 表示 \t)
+  autofocus: false,       spellcheck: false,
+  readOnly: false,        tabSize: 2,
+  historyLimit: 100,      historyDebounce: 400,
+  syncScroll: true,       autoBrackets: true,
+  zenMode: false,         wordWrap: true,
 
-  // 主题与国际化
-  theme: 'auto',          // 'light' | 'dark' | 'auto' | 'warm' | 自定义
-  locale: 'zh-CN',        // 'zh-CN' | 'en-US' | 自定义
+  // 主题 / 语言
+  theme: 'auto',          locale: 'zh-CN',
 
-  // 自定义渲染
-  render: null,           // (md, env) => html
-  highlight: null,        // (code, lang) => html
-  sanitize: null,         // (html) => safeHtml
+  // 钩子
+  render: null,           highlight: null,
+  sanitize: null,
 
   // 外观
-  className: '',          // 容器额外 class
-  style: {},              // 内联样式
+  className: '',          style: {},
 
-  // 插件与回调
-  plugins: [],            // 实例级插件数组
-  onChange: null,         // (value, editor) => void
-  onInput: null,          // (value, editor) => void
-  onFocus: null,          // (editor) => void
-  onBlur: null,           // (editor) => void
-  onSave: null,           // (value, editor) => void
-  onModeChange: null,     // (mode, editor) => void
-  onFullscreen: null,    // (fullscreen, editor) => void
-  onCreate: null,         // (editor) => void
-  onDestroy: null,        // (editor) => void
+  // 插件 / 回调
+  plugins: [],
+  onChange: null,         onInput: null,
+  onFocus: null,          onBlur: null,
+  onSave: null,           onModeChange: null,
+  onFullscreen: null,    onCreate: null,
+  onDestroy: null,        onLinkClick: null,
 });
- +
-

工具栏配置

- -
// 默认工具栏(完整按钮)
+

工具栏

+
// 默认完整工具栏
 MeEditor.create(container, { toolbar: true });
 
-// 隐藏工具栏
+// 隐藏
 MeEditor.create(container, { toolbar: false });
 
-// 自定义工具栏 — '|' 为分隔符
-MeEditor.create(container, {
-  toolbar: ['bold', 'italic', '|', 'h1', 'h2', '|', 'undo', 'redo'],
-});
- +// 自定义 | 为分隔符 +MeEditor.create(container, { toolbar: ['bold', 'italic', '|', 'undo', 'redo'] });

可用动作:

bolditalicstrikethroughunderlinecode @@ -312,346 +185,244 @@ MeEditor.create

- -
-

实例 API

- + +

实例 API

内容操作

-
editor.getValue();                    // 获取 Markdown 文本
-editor.setValue(md, { silent });      // 设置内容,silent 不触发 change
-editor.getHTML();                     // 获取渲染后的 HTML
-editor.refresh();                     // 强制刷新预览(内容未变时)
-editor.insert(text, { replace });     // 光标处插入 / 替换选区
-editor.wrap(before, after);           // 选区包裹
-editor.focus();                       // 聚焦
-editor.blur();                        // 失焦
+
editor.getValue();                    // => string
+editor.setValue(md, { silent });      // => this
+editor.getHTML();                     // => string
+editor.refresh();                     // 强制重渲染
+editor.insert(text, { replace });     // => this
+editor.wrap(before, after);           // => this
+editor.focus(); blur();
-
-

命令执行

-
editor.exec(action, ...args);         // 执行命令,返回 this 链式调用
-
-editor.exec('bold').exec('h1');        // 链式调用
- +

命令执行

+
editor.exec(action) // => this, 支持链式
- - - - - - - - - - - - + + + + + + + + + + - + + + - + + +
action效果快捷键
bold加粗 **text**Ctrl+B
italic斜体 *text*Ctrl+I
strikethrough删除线 ~~text~~
underline下划线 <u>text</u>Ctrl+U
code行内代码 `text`Ctrl+E
h1/h2/h3标题 # / ## / ###Ctrl+1/2/3
quote引用 >Ctrl+Q
ul/ol无序/有序列表
indent/outdent缩进/反缩进Tab/Shift+Tab
hr水平线 ---
link插入链接 [text](url)Ctrl+K
image插入图片 ![alt](url)
bold**text**Ctrl+B
italic*text*Ctrl+I
strikethrough~~text~~
underline<u>text</u>Ctrl+U
code`text`Ctrl+E
h1/h2/h3# / ## / ###Ctrl+1/2/3
quote> textCtrl+Q
ul/ol- / 1. 列表
link[text](url)Ctrl+K
image![alt](url)
table插入表格
undo/redo撤销/重做Ctrl+Z / Ctrl+Y
hr---水平线
indent/outdent缩进/反缩进Tab / Shift+Tab
undo/redo撤销/重做Ctrl+Z / Y
edit/split/preview切换模式
fullscreen切换全屏
fullscreen全屏
zenZen 模式
wordwrap自动换行
-
-

历史栈

-
editor.undo();                        // 撤销
-editor.redo();                        // 重做
-editor.canUndo();                     // 是否可撤销
-editor.canRedo();                     // 是否可重做
+

历史栈

+
editor.undo();    editor.redo();
+editor.canUndo();  editor.canRedo();
-
-

模式与全屏

-
editor.setMode('split');              // 设置模式:edit | split | preview
-editor.getMode();                     // 获取当前模式
-editor.toggleFullscreen();            // 切换全屏
-editor.exitFullscreen();              // 退出全屏
-editor.isFullscreen();                // 是否全屏
+

模式 / 全屏 / Zen

+
editor.setMode('split');  editor.getMode();
+editor.toggleFullscreen();  isFullscreen();  exitFullscreen();
+editor.toggleZen();  isZen();
+editor.toggleWordWrap();  setWordWrap(true);  isWordWrap();
-
-

统计与状态

+

统计与状态

editor.getStats();
-// => { characters, words, chineseChars, englishWords, lines, readingTime }
-
+// => { characters, words, chineseChars, englishWords, lines, readingTime }
 editor.getStatus();
-// => { id, mode, theme, locale, fullscreen, readOnly, disabled, destroyed, plugins }
+// => { id, mode, theme, locale, fullscreen, readOnly, disabled, destroyed, plugins }
-
-

启用/禁用/只读

-
editor.enable();                      // 启用
-editor.disable();                     // 禁用
-editor.isDisabled();                  // 是否禁用
-editor.setReadOnly(true);             // 只读模式
-editor.isReadOnly();                  // 是否只读
+

启用 / 禁用 / 只读

+
editor.enable();  disable();  isDisabled();
+editor.setReadOnly(true);  isReadOnly();
-
-

事件系统

- +

事件系统

- - + + - - - + + + + + - - - + + +
事件名触发时机回调参数
inputtextarea 原生 input(value, editor)
事件触发时机参数
inputtextarea 输入(value, editor)
change内容变化(value, editor)
focus聚焦(editor)
blur失焦(editor)
saveCtrl+S(value, editor)
focus / blur聚焦/失焦(editor)
saveCtrl+S(editor)
modeChange模式切换(mode, editor)
fullscreen全屏切换(fullscreen, editor)
themeChange主题变更({ theme, resolved, config })
localeChange语言变更({ locale, direction })
zenChangeZen 切换(zen, editor)
destroy销毁()
autosaveautoSave 保存({ key, value })
beforeRender渲染前(editor)
afterRender渲染后(editor)
beforeRender / afterRender渲染前后(editor)
autosaveautoSave 触发({ key, value })
linkClick预览链接点击({ href, text })
- -

全局钩子(所有实例共享)

+

全局钩子

- - - - - - + + +
钩子触发时机
beforeCreate构造函数初始化前
afterCreate构造函数初始化完成
beforeRender每次渲染前(全局)
afterRender每次渲染后(全局)
beforeDestroydestroy 前
afterDestroydestroy 后
beforeCreate / afterCreate实例构造前后
beforeRender / afterRender全局渲染前后
beforeDestroy / afterDestroy销毁前后
-
-

插件管理

-
editor.use(plugin, options);          // 安装插件
-editor.getPlugins();                  // 获取已安装插件列表
-editor.addToolbarButton(config);      // 追加工具栏按钮
+

插件管理

+
editor.use(plugin, options);      // 安装
+editor.unuse(name);               // 卸载
+editor.getPlugins();              // 已安装列表
+editor.addToolbarButton(config);  // 追加按钮
-
-

生命周期

-
editor.destroy();                     // 销毁实例
-editor.isDestroyed();                 // 是否已销毁
+

快捷键管理

+
editor.registerShortcut('Ctrl+Shift+T', handler, 'desc');
+editor.unregisterShortcut('Ctrl+Shift+T');
+editor.getShortcuts();
- -
-

静态 API

+

生命周期 / Toast

+
editor.destroy();  isDestroyed();
+editor.toast(msg, { type, duration, animation });
+
+ +

静态 API

import MeEditor from '@metona-team/metona-editor';
 
 // 工厂函数
 MeEditor.create(container, options);
 
 // 全局默认插件
-MeEditor.use(presetPlugins.autoSave, { delay: 2000 });
-MeEditor.use('searchReplace');
+MeEditor.use('autoSave', { delay: 2000 });
 MeEditor.use(customPlugin);
 
-// 全局事件钩子
-MeEditor.on('beforeCreate', (editor) => {});
+// 全局钩子
+MeEditor.on('beforeCreate', (editor) => {});
 MeEditor.off('beforeCreate', handler);
 
-// 主题与语言
+// 全局主题 / 语言
 MeEditor.setTheme('dark');
 MeEditor.setLocale('en-US');
 
-// 状态查询
-MeEditor.getStatus(); // => { version, theme, locale, globalPlugins, presetPlugins }
-
-// 销毁全局资源
-MeEditor.destroy();
-
-// 内置解析器
-import { parseMarkdown, safeUrl, slugify } from '@metona-team/metona-editor';
-parseMarkdown('# Hello');           // => '<h1 id="hello">Hello</h1>'
-safeUrl('javascript:alert(1)');     // => ''
-slugify('Hello World');             // => 'hello-world'
+// 解析器独立使用 +import { parseMarkdown, parseTokens, renderTokens } from '@metona-team/metona-editor';
- -
-

解析器语法参考

- + +

解析器语法参考

- - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + +
语法示例输出
标题# H1 ~ ###### H6<h1> ~ <h6>
段落纯文本<p>
粗体**bold** __bold__<strong>
粗斜体 v0.1.15***text*** ___text___<em><strong>
斜体*italic* _italic_<em>
删除线~~text~~<del>
高亮标记==text==<mark>
上标x^2^<sup>
下标H~2~O<sub>
行内代码`code`<code>
代码块```lang<pre><code>
引用> quote<blockquote>
无序列表- item<ul><li>
有序列表1. item<ol><li>
任务列表- [x] done<li class="me-task-item">
水平线--- *** ___<hr>
表格| a | b |<table>(支持 :---: 列对齐)
链接 v0.1.15[**text**](url)链接文本内支持行内格式
图片![alt](url)<img>
自动链接<https://...><a>
Emoji:smile: :rocket:😊 🚀(150+ 常用)
反斜杠转义 v0.1.15\* \_ \\取消标点特殊含义
标题# H1 ~ ###### H6<h1> ~ <h6>
Setext 标题H1\n===<h1> / <h2>
粗体**bold** __bold__<strong>
粗斜体 v0.1.15***text*** ___text___<em><strong>
斜体*italic* _italic_<em>
删除线 / 高亮~~del~~ ==mark==<del> / <mark>
上标 / 下标x^2^ H~2~O<sup> / <sub>
行内代码`code`<code>
代码块```lang<pre><code>
缩进代码块 code<pre><code>
引用> quote<blockquote>
无序列表- * + item<ul><li>
有序列表1. item<ol><li>
嵌套列表多级缩进多级 <ul>/<ol>
任务列表- [x] done<li class="me-task-item">
水平线--- *** ___<hr>
表格| a | b |<table> + 列对齐
链接 v0.1.15[**t**](url)文本内支持行内格式
图片![alt](url)<img>
自动链接<https://...><a>
数学公式$E=mc^2$<span> / <div>
脚注text[^1]<sup> + 底部
定义列表Term\n: def<dl><dt><dd>
Emoji:smile: :rocket:😊 🚀(150+)
反斜杠转义 v0.1.15\* \_取消标点特殊含义
- -

XSS 防护

-

所有文本经 HTML 转义。URL 自动过滤 javascript: vbscript: file: 及非图片 data: 协议。

+

XSS 防护

+

所有文本经 escapeHTML 转义,URL 过滤 javascript: / vbscript: / file: / 非图片 data:,提供 sanitize 钩子。

- -
-

解析器 API v0.1.15 新增

- -

parseTokens / renderTokens(解析与渲染分离)

-

将 Markdown 解析为中间 Token 数组,可在渲染前变换,再输出 HTML。

+

解析器 API

+

parseTokens / renderTokens

import { parseTokens, renderTokens } from '@metona-team/metona-editor';
 
-// 解析为 Token 数组
 const { tokens, footnotes } = parseTokens('# Hello\n\n**world**');
-// tokens = [
-//   { type: 'heading', level: 1, text: 'Hello' },
-//   { type: 'paragraph', text: '**world**' }
-// ]
-
-// 你可以在渲染前变换 token 数组
-tokens.unshift({ type: 'hr' });
-
-// 渲染为 HTML
+tokens.unshift({ type: 'hr' });  // 渲染前变换
 const html = renderTokens(tokens, env, footnotes);
-

registerBlockHandler(注册自定义块级语法)

-

无需替换整个解析器,按优先级注册自定义块级语法处理器。

+

registerBlockHandler

import { registerBlockHandler } from '@metona-team/metona-editor';
-
 registerBlockHandler({
-  name: 'customAlert',
-  priority: 8.5,        // 越小越先尝试
-  test: (line) => line.match(/^:::(\w+)/),
-  parse: (lines, i, match) => {
-    // 返回 { token: {...}, newIndex }
-    return { token: { type: 'alert', alertType: match[1] }, newIndex: j };
-  },
+  name: 'custom', priority: 8.5,
+  test: (line) => line.match(/^:::/),
+  parse: (lines, i, match) => ({ token: { type: 'alert' }, newIndex: j })
 });
- -

TIP:如果自定义 token 的 type 不被 renderTokens 识别,可以在渲染前通过 tokens.map() 转换为已知 type,或自行实现渲染逻辑。

- -
-

插件约定

- + +

插件约定

const myPlugin = {
-  name: 'myPlugin',
-  description: '我的自定义插件',
-
-  install(editor, options) {
-    // this 指向插件对象本身
-    this._timer = null;
-    editor.on('change', this._onChange);
-  },
-
-  destroy(editor) {
-    if (this._timer) clearTimeout(this._timer);
-    editor.off('change', this._onChange);
-  },
+  name: 'myPlugin', description: '我的插件',
+  install(editor) { editor.on('change', this._onChange); },
+  destroy(editor) { editor.off('change', this._onChange); },
 };
-
-

预设插件

- -

autoSave — 自动保存草稿

-
editor.use(presetPlugins.autoSave, {
-  key: 'me-draft-' + editor.id,  // localStorage key
-  delay: 1000,                    // 防抖延迟(ms)
-});
-editor.restoreDraft();             // 恢复草稿
-editor.clearDraft();               // 清除草稿
-editor.getDraftKey();              // 获取存储 key
- -

exportTool — 导出文件

-
editor.use(presetPlugins.exportTool);
-editor.exportMarkdown('my-doc.md');
-editor.exportHTML('my-doc.html', {
-  title: '文档标题',
-  css: 'body { font-family: sans-serif; }',
-  lang: 'zh-CN',
-});
- -

searchReplace — 查找替换

-
editor.use(presetPlugins.searchReplace);
-// Ctrl+F → 查找  Ctrl+H → 替换
-// Enter → 下一个  Shift+Enter → 上一个  Escape → 关闭
- -

imagePaste — 粘贴图片转 base64

-
editor.use(presetPlugins.imagePaste);
-// 在编辑区 Ctrl+V 粘贴剪贴板图片
-// 自动插入 ![](data:image/png;base64,...)
+

预设插件

+

autoSave

+
editor.use('autoSave', { key: 'draft-key', delay: 1000 });
+editor.restoreDraft();  editor.clearDraft();
+

exportTool

+
editor.use('exportTool');
+editor.exportMarkdown('doc.md');  editor.exportHTML('doc.html');
+

searchReplace

+
editor.use('searchReplace');
+// Ctrl+F 查找 / Ctrl+H 替换
+

imagePaste

+
editor.use('imagePaste');  // 粘贴图片自动转 base64
+

shortcutHelp

+
editor.use('shortcutHelp');  // 按 ? 弹出快捷键面板
+

fileSystem

+
editor.use('fileSystem');
+editor.openFile();  editor.saveFile();  editor.saveFileAs();
- -
-

主题系统

+ +

主题系统

+
// 实例级
+editor.setTheme('dark');  editor.getTheme();
 
-
// 全局切换主题
-MeEditor.setTheme('light');         // 亮色
-MeEditor.setTheme('dark');          // 暗色
-MeEditor.setTheme('warm');          // 暖色
-MeEditor.setTheme('auto');          // 自动(默认)
-
-// 实例级主题(v0.1.5,每个编辑器独立)
-editor.setTheme('dark');
-editor.getTheme();                   // 'dark'
-editor.on('themeChange', ({ theme }) => {});
-
-// 注册自定义主题(v0.1.5: 支持继承)
+// 注册自定义
 import { themeUtils } from '@metona-team/metona-editor';
-themeUtils.registerTheme('ocean', {
-  extends: 'dark',                  // 继承 dark 主题
-  accent: '#00ddff',
-});
+themeUtils.registerTheme('ocean', { extends: 'dark', accent: '#00ddff' });
 
-// 外部主题跟随(v0.1.5)
-themeUtils.followExternalTheme(
-  { element: document.body, attr: 'data-theme' },
-  (theme) => editor.setTheme(theme)
-);
-
-// 从父容器继承主题
-themeUtils.adoptFromParent(editor.container,
-  (theme) => editor.setTheme(theme)
-);
+// 外部跟随
+editor.getThemeContext().adopt();  // 从父容器继承
 
 // CSS 变量导出
-themeUtils.exportCSSVars();              // { '--md-bg': '#fff', ... }
-themeUtils.getCSSVariable('accent');    // '#3b82f6'
- -

CSS 变量限定在 .me-wrapper 元素上,不污染全局。支持 @media print 打印样式。v0.1.5 新增实例级主题隔离、外部跟随、主题继承。

+themeUtils.exportCSSVars(); themeUtils.getCSSVariable('accent');
- -
-

国际化

+ +

国际化

+
// 切换
+editor.setLocale('en-US');  MeEditor.setLocale('zh-CN');
 
-
// 切换语言
-MeEditor.setLocale('en-US');
-MeEditor.setLocale('zh-CN');
-
-// 翻译函数
+// 添加翻译
 import { i18nUtils } from '@metona-team/metona-editor';
-i18nUtils.t('bold');                 // => '粗体'(zh-CN)
-i18nUtils.t('bold');                 // => 'Bold'(en-US)
+i18nUtils.addTranslations('ja', { bold: '太字' });
 
-// 添加语言
-i18nUtils.addTranslations('ja', { bold: '太字', italic: '斜体' });
+// 远程加载
+await i18nUtils.loadRemote('/locales/ja.json', 'ja');
 
 // 格式化
-i18nUtils.formatNumber(1234567);              // => '1,234,567'
-i18nUtils.formatCurrency(99.99, 'USD');       // => '$99.99'
-i18nUtils.formatDate('2024-01-15');           // => '1/15/2024'
+i18nUtils.formatNumber(1234567); +i18nUtils.formatDate('2024-01-15');
@@ -660,24 +431,18 @@ i18nUtils.formatDate
- MetonaEditor v0.1.15 · 源码仓库 · MIT License + MetonaEditor v0.2.0 · TypeScript · 源码仓库 · MIT License
- diff --git a/site/index.html b/site/index.html index d4fdee7..a52a21d 100644 --- a/site/index.html +++ b/site/index.html @@ -6,432 +6,122 @@ MetonaEditor v0.2.0 · TypeScript · 桌面端 Markdown 编辑器 -