# Mteditor
**Repository Path**: meilitao/editor
## Basic Information
- **Project Name**: Mteditor
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: MIT
- **Default Branch**: main
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2026-10-10
- **Last Updated**: 2026-10-26
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# MtEditor
> 一套**与框架无关的富文本编辑器** + **跨端富文本渲染器**。MIT 许可,UI 全自研。
MtEditor 由两块**互相解耦**的能力组成:
| # | 能力 | 说明 |
|---|---|---|
| A | **可编辑的富文本内核** | 命令式 API,可被 Vue 3 / Vue 2 / React / Svelte / Layui / 原生 JS 直接集成 |
| B | **跨端富文本渲染器** | 同一份 `MtDocument` JSON,在 Web / 小程序 / 鸿蒙上一致地**只读渲染**(不依赖编辑器运行时) |
---
## 特性
- **框架无关**:内核只依赖 Tiptap 3 Core(MIT)与原生 DOM,不绑定任何前端框架;六个框架适配包都是不含编辑逻辑的薄壳。
- **单一真相源**:文档数据模型 `MtDocument`(JSON)是唯一真相源,HTML / Markdown / 纯文本 / 小程序 nodes 全是**派生产物**,同一份数据在编辑、详情页、小程序、导出四处一致。
- **跨端渲染**:Web 端 `renderToString()` 全程不碰 DOM(SSR / 边缘函数可用);小程序端提供 `rich-text` 与递归自定义组件双通道,按文档规模自动切换。
- **UI 完全自研**:工具栏 / 气泡菜单 / 块手柄 / 移动端抽屉 / 目录侧栏均为纯原生 DOM,跨 6 个框架视觉一致,不引入任何 UI 组件库;**不使用 Shadow DOM**,宿主样式可直接覆盖。
- **开箱即用的主题与国际化**:亮 / 暗主题(纯 CSS 变量),内置 `zh-CN` / `en-US`,可注册新语言。
- **移动端三级能力分级**:`full` / `touch` / `readonly` 三档自动降级(不报错),触屏档工具栏吸底 + 抽屉。
- **安全**:AST 白名单 XSS 清洗,**零 DOM 依赖**,Node 与小程序运行时同样生效。
- **可选 AI**:`@mteditor/ai` 为叶子可选包,不装它其余包**一个字节都不多**;provider 由使用者注入,**流式期间不写文档**,确认后才落库(一步撤销)。
- **体积可控**:运行时依赖极少,且不引入 copyleft 许可依赖。实测 gzip:`core` 26.08 KB、`document` 23.58 KB、`theme-default` 3.59 KB、`renderer-mini/wechat` 2.04 KB、`ai` 8.11 KB。
- **浏览器基线**:ES2020,Chrome / Edge ≥ 90、Safari ≥ 14、Firefox ≥ 90、鸿蒙 ArkWeb、Android 9+ WebView。不支持 IE。
---
## 平台支持
| 平台 | 编辑 | 只读渲染 | 落地方式 |
|---|---|---|---|
| PC 浏览器 / 移动 H5 | ✅ | ✅ | `@mteditor/core` + `theme-default`,只读用 `renderer-web` |
| 鸿蒙 HarmonyOS Next(ArkWeb) | ✅ | ✅ | 同 Web 端(H5 能力完整) |
| 微信小程序 | ❌ | ✅ | `@mteditor/renderer-mini/wechat` |
| 阿里 / 抖音小程序、uni-app、Taro | ❌ | ⏳ 规划中 | 各端 `rich-text` 白名单需实测,未核实前调用会被拒绝 |
| 鸿蒙原生 ArkTS | ❌ | ⏳ 规划中 | `renderer-mini/arkts` |
> **小程序端不提供完整富文本编辑**:小程序无稳定 `contenteditable`,业界无可靠原生富文本方案。
> MtEditor 在小程序端提供 **100% 保真的只读渲染**;需要编辑时引导用户跳转 H5 / App 编辑页,
> 编辑后回传同一份 `MtDocument`。
---
## 安装
```bash
npm i @mteditor/core @mteditor/theme-default
```
`@mteditor/core` 已把 `@mteditor/document` 声明为普通依赖,会自动带上;
`theme-default` 是纯 CSS,不引它编辑器能跑但没有任何外观。
框架用户改装对应适配包(`core` 会一并带进来):
```bash
npm i @mteditor/vue3 # 或 vue2 / react / svelte / layui
```
只读渲染场景:
```bash
npm i @mteditor/renderer-web # Web 详情页 / SSR
npm i @mteditor/renderer-mini # 小程序 / uni-app / Taro / 鸿蒙 ArkTS
```
---
## 快速开始
### 原生 JS / 任意框架
```ts
import { MtEditor } from '@mteditor/core'
import '@mteditor/theme-default/index.css'
const editor = new MtEditor({
element: document.getElementById('editor')!,
placeholder: '请输入内容…',
onChange: ({ json }) => void save(json), // json 是唯一真相源
})
editor.command('toggleBold')
editor.command('setHeading', { level: 2 })
editor.getJSON()
editor.destroy()
```
常用 API:
| 分类 | API |
|---|---|
| 内容读写 | `getJSON()` / `setJSON(doc)` / `getHTML()` / `setHTML(html)` / `getText()` / `getMarkdown()` / `setMarkdown(md)` / `insertContent()` |
| 编辑操作 | `command(name, payload)`(56 个内置命令)/ `undo()` / `redo()` / `clear()` / `focus()` |
| 状态 | `isEmpty()` / `getSelection()` / `getOutline()` / `setReadonly()` / `setTheme()` / `setLocale()` |
| 生命周期 | `on(name, handler)` / `destroy()` |
### Vue 3
```vue
```
### React
```tsx
import { useState } from 'react'
import { MtEditor } from '@mteditor/react'
import type { MtDocument } from '@mteditor/react'
import '@mteditor/theme-default/index.css'
export const App = () => {
const [doc, setDoc] = useState()
return setDoc(json)} options={{ theme: 'light' }} />
}
```
### Vue 2
```vue
```
> `v-model` 的 `value`/`input` 与 `modelValue`/`update:modelValue` 两条协议**都收都发**。
### Svelte
包内只出**版本无关**的纯 TS(`createMtEditor` + `mtEditorStore`,Svelte 4 / 5 通用):
```ts
import { onMount } from 'svelte'
import { createMtEditor } from '@mteditor/svelte'
import '@mteditor/theme-default/index.css'
let host: HTMLDivElement
onMount(() => {
const { editor } = createMtEditor(host, { theme: 'light' })
editor.on('change', ({ json }) => void save(json))
})
```
### Layui / `
```
也可以直接引全局包(不需要 layui):`var editor = MtEditor.render({ elem: '#editor' })`。
---
## 只读渲染
### Web 端
```ts
import { renderToString, renderToDOM } from '@mteditor/renderer-web'
import '@mteditor/theme-default/index.css'
const { html } = renderToString(doc) // SSR:全程不碰 DOM
const { element } = renderToDOM(doc, document.getElementById('view')!) // 详情页:挂载
```
### 小程序端
```ts
import { render } from '@mteditor/renderer-mini/wechat'
const { mode, nodes, report, autoSwitched } = render(doc, { theme: 'dark' })
// mode 是「实际使用的通道」,宿主必须按它分支;nodes 直接喂给组件
// report 为空表示内容无损;autoSwitched 非 null 表示触发了阈值降级
```
接入三步(组件随包分发,小程序无法从 `node_modules` 直读,复制进项目即可):
1. 复制 `node_modules/@mteditor/renderer-mini/components/` 下的 `mt-renderer` / `mt-node` / `mt-theme.wxss` 到项目;
2. 页面 `usingComponents` 声明 `"mt-renderer": "/components/mt/mt-renderer/index"`;
3. WXML 写 ``,样式 `@import` 一次 `mt-theme.wxss`。
> 双通道:`component`(递归自定义组件,默认,样式来自组件 wxss + CSS 变量)与 `richText`(原生 `rich-text`,样式为序列化时内联的字面量);`mode: 'auto'` 按文档节点数自动切换。降级(如 `rich-text` 下的视频 / 音频 / 公式)**始终写入 `report`,不可关闭**。
---
## AI 能力(可选)
```ts
import { MtEditor } from '@mteditor/core'
import { createMtAi, createOpenAiCompatProvider } from '@mteditor/ai'
const editor = new MtEditor({ element: host })
const ai = createMtAi(editor, {
provider: createOpenAiCompatProvider({
baseURL: 'https://api.deepseek.com/v1', // 任何 OpenAI 兼容端点
apiKey: import.meta.env.VITE_AI_KEY,
model: 'deepseek-chat',
}),
})
const result = await ai.run('polish') // 五项动作:续写 / 润色 / 摘要 / 翻译 / 自定义
ai.applyPending('replace') // 结果停在预览里,确认才落库 —— 只占一步撤销
```
`provider` 只需实现一个 `chat()` 接口,可对接任意模型;不传 `provider` 也可以完全自建 UI
(`bubble: false, panel: false` + `ai.subscribe()`)。API key 请放服务端或由宿主注入。
---
## 包一览
| 包 | 说明 |
|---|---|
| `@mteditor/core` | 编辑器内核:命令总线(56 命令)、事件、自研 UI、主题与 i18n 接线 |
| `@mteditor/document` | 文档模型层:`MtDocument` 的解析 / 序列化 / 清洗 / 校验 / 迁移,**零 DOM 零框架**,Node 与小程序运行时均可用 |
| `@mteditor/theme-default` | 纯 CSS 变量主题(亮 / 暗),无 JS |
| `@mteditor/renderer-web` | Web 只读渲染器(`renderToString` / `renderToDOM`),不加载编辑器 |
| `@mteditor/renderer-mini` | 小程序 / uni-app / Taro / 鸿蒙 ArkTS 只读渲染器,子路径导出(`/wechat` 等) |
| `@mteditor/vue3` · `vue2` · `react` · `svelte` · `layui` | 框架适配薄壳;Layui 端额外产出 IIFE 全局包 |
| `@mteditor/ai` | 可选 AI 能力包:五项动作 + 多轮对话 |
---
## 各包文档
每个包目录下的 `README.md` 是该包的完整说明(定位 / 安装 / 用法 / props 与事件表 / 常见坑),
**随对应的 npm 包一起分发** —— 在 npm 包页面同样可读。
| 包 | 文档 |
|---|---|
| `@mteditor/core` | [`packages/core/README.md`](./packages/core/README.md) |
| `@mteditor/document` | [`packages/document/README.md`](./packages/document/README.md) |
| `@mteditor/theme-default` | [`packages/theme-default/README.md`](./packages/theme-default/README.md) |
| `@mteditor/renderer-web` | [`packages/renderer-web/README.md`](./packages/renderer-web/README.md) |
| `@mteditor/renderer-mini` | [`packages/renderer-mini/README.md`](./packages/renderer-mini/README.md) |
| `@mteditor/vue3` · `vue2` · `react` · `svelte` · `layui` | [`packages/adapter-vue3/README.md`](./packages/adapter-vue3/README.md) 等 |
| `@mteditor/ai` | [`packages/ai/README.md`](./packages/ai/README.md) |
---
## 许可
[MIT](./LICENSE)。