@composy/mail-editor-core
HTML 邮件拖拽式可视化编辑器核心库,框架无关,纯 TypeScript 实现。
@composy/mail-editor-core
是一个面向邮件模板的可视化编排核心。它以"内容块(Block)" 为基本单元,通过 MailEditor
主类在容器内渲染完整的编辑画布 / 工具栏 / 属性面板,支持文本、图片、按钮、分割线、社交图标、间距、分栏等七种内置块类型,并提供拖拽排序、撤销重做、主题(明暗)、设备预览(桌面/平板/手机)、变量插值与 HTML 导出等完整能力。核心层只依赖 DOM 全局对象,可与 Vue
/ React / 原生 JS 任意框架集成;还提供
renderer/html-renderer(生成邮件 HTML)、renderer/dom-renderer(渲染 DOM)、
blocks、templates、styles、icons 等可独立复用的子模块。
安装
pnpm add @composy/mail-editor-core
# 或
npm install @composy/mail-editor-core
目录结构
libraries/mail-editor/packages/core/
├── src/
│ ├── index.ts # 统一入口,聚合导出全部能力
│ ├── core/
│ │ ├── mail-editor.ts # MailEditor 主类 + createMailEditor 工厂
│ │ └── event-emitter.ts # 轻量事件发射器
│ ├── blocks/
│ │ └── index.ts # createBlock / blockMetas / generateBlockId 等
│ ├── templates/
│ │ └── index.ts # 内置模板与分类查询
│ ├── renderer/
│ │ ├── html-renderer.ts # renderBlock / exportHtml / interpolate
│ │ ├── dom-renderer.ts # renderBlockDOM(带交互回调)
│ │ └── shared-styles.ts # 公共样式工具函数
│ ├── styles/
│ │ └── index.ts # 主题样式注入 / 更新 / 移除 + light/dark token
│ ├── icons/
│ │ └── index.ts # 内置 SVG 图标函数
│ └── types/
│ └── index.ts # 块数据、模板、编辑器配置与实例接口类型
├── es/ # ESM 构建产物
├── lib/ # CJS 构建产物
└── dist/ # 浏览器 `<script>` 用打包产物
核心 API 详表
编辑器主类与工厂
| 名称 |
类型 |
签名 |
用途 |
MailEditor |
类 |
new MailEditor(config: MailEditorConfig) |
邮件编辑器主类,实现 MailEditorInstance |
createMailEditor |
函数 |
(config: MailEditorConfig): MailEditorInstance |
工厂函数,创建编辑器实例 |
MailEditor / MailEditorInstance
关键方法:getBlocks/setBlocks/addBlock/removeBlock/ moveBlock/updateBlock/getSelectedBlock/selectBlock/exportHtml/loadTemplate/setVariables/ getVariables/setTheme/setMode/setPreviewMode/undo/redo/canUndo/canRedo/on/destroy。
核心机制
| 名称 |
类型 |
签名 |
用途 |
EventEmitter |
类 |
new EventEmitter() |
轻量事件发射器(on/off/emit/removeAllListeners) |
VERSION |
常量 |
'0.1.0' |
库版本号 |
块(Blocks)
| 名称 |
类型 |
签名 |
用途 |
createBlock |
函数 |
(type: BlockType): Block |
按类型创建默认块 |
createDefaultBlockData |
函数 |
(type: BlockType): BlockData |
创建默认块数据 |
blockMetas |
常量 |
— |
块元信息列表(类型、标签、图标) |
generateBlockId |
函数 |
(): string |
生成唯一块 ID |
BlockMeta |
类型 |
— |
块元信息类型 |
模板(Templates)
| 名称 |
类型 |
签名 |
用途 |
builtinTemplates |
常量 |
— |
内置模板数组 |
getTemplateByKey |
函数 |
(key: string): MailTemplate | undefined |
按 key 获取模板 |
getTemplatesByCategory |
函数 |
(category: string) |
按分类获取模板 |
templateCategories |
常量 |
— |
模板分类列表 |
渲染器(Renderer)
| 名称 |
类型 |
签名 |
用途 |
renderBlock |
函数 |
(block, variables?) |
将块渲染为 HTML 字符串 |
exportHtml |
函数 |
(blocks, variables?, opts?) |
将一组块导出为完整邮件 HTML |
interpolate |
函数 |
(template, variables) |
变量插值 |
renderBlockDOM |
函数 |
(block, variables, mode, callbacks, theme) |
渲染块 DOM 节点(带选择/删除/复制/移动/编辑回调) |
DOMRenderCallbacks |
类型 |
— |
DOM 渲染回调类型 |
toStyleStr / textWrapStyle / imageWrapStyle / imageImgStyle / buttonWrapStyle / buttonLinkStyle / dividerWrapStyle / dividerHrStyle / socialWrapStyle / socialIconStyle / spacerStyle / columnsWrapStyle / columnStyle |
函数 |
— |
各内容块公共样式生成函数 |
样式与图标
| 名称 |
类型 |
签名 |
用途 |
injectStyles |
函数 |
(theme: ThemeMode) |
注入编辑器全局样式 |
updateThemeStyles |
函数 |
(theme: ThemeMode) |
更新主题样式变量 |
removeStyles |
函数 |
() |
移除注入的样式 |
cls |
函数 |
(...) |
构建 class 名称的辅助函数 |
CLS_PREFIX |
常量 |
— |
CSS class 前缀 |
lightTokens / darkTokens |
常量 |
— |
明暗主题 token |
ThemeTokens |
类型 |
— |
主题 token 类型 |
*(icons) |
函数 |
(size?) |
内置 SVG 图标函数(编辑、预览、设备、撤销/重做、主题、导出、加号等) |
常用类型
ThemeMode、PreviewMode、EditorMode、BlockType、Alignment、BlockStyle、
TextBlockData、ImageBlockData、ButtonBlockData、DividerBlockData、
SocialBlockData、SpacerBlockData、ColumnDef、ColumnsBlockData、BlockData、
Block、MailTemplate、Variables、MailEditorConfig、MailEditorInstance。
使用示例
import {
MailEditor,
createMailEditor,
createDefaultBlockData,
builtinTemplates,
type MailEditorConfig,
type Block,
} from '@composy/mail-editor-core'
// 方式一:实例化
const editor = new MailEditor({
container: '#editor',
template: 'welcome', // 以内置模板初始化
theme: 'light',
mode: 'edit',
previewMode: 'desktop',
variables: { userName: '张三', year: 2025 },
onChange: blocks => console.log('内容变化', blocks.length),
onHtmlExport: html => console.log(html),
})
editor.on('block:add', block => console.log('新增块', block.id))
// 以编程方式操作
const title = editor.addBlock('text', 0)
editor.updateBlock(title.id, {
content: '亲爱的 {{userName}}',
fontSize: '24px',
color: '#333333',
})
editor.setTheme('dark')
editor.setPreviewMode('mobile')
const html = editor.exportHtml() // 导出邮件 HTML
editor.undo() // 撤销
editor.destroy()
// 方式二:工厂函数
const editor2 = createMailEditor({ container: '#editor2' })
// 独立使用子模块
const block: Block = {
id: 'demo-1',
type: 'button',
data: createDefaultBlockData('button'),
}
const blockHtml = interpolate(renderBlock(block, { userName: '李四' }), { userName: '李四' })
构建脚本 & 验证命令
在 libraries/mail-editor/packages/core/ 下执行:
pnpm build # 使用 @composy/builder/rolldown 构建
pnpm type-check # ESM 类型检查
pnpm type-check:cjs # CJS 类型检查
pnpm clean # 清理 dist/es/esm/lib
pnpm lint # ESLint 检查
pnpm lint:check # ESLint 严格检查(--max-warnings 0)
pnpm test:run # 单元测试
pnpm test:coverage # 单元测试 + 覆盖率
产物说明
| 产物 |
路径 |
说明 |
| ESM |
es/ |
面向现代 bundler 的 ES 模块产物,含 .d.ts 类型声明 |
| ESM 源 |
esm/ |
保留模块结构的 ESM/样式源产物 |
| CJS |
lib/ |
面向 Node / require 环境的 CommonJS 产物 |
| 浏览器 |
dist/index.js、dist/index.min.js |
直接 <script> 引用的打包与压缩产物 |
| 类型入口 |
es/index.d.ts |
exports.types 指向的类型入口 |
package.json 提供丰富的子路径导出(./blocks/*、./core/*、./renderer/*、
./icons/*、./styles/*、./templates/*、./types/*),可按需按模块单独引入。
备注
- 无运行时依赖(peerDeps):本包为纯 TypeScript 实现,
devDependencies 仅包含
typescript、eslint、@composy/builder、@composy/testing、@composy/release,无强制的
peerDependencies。
- 浏览器专属 API:
MailEditor、renderBlockDOM 及样式注入依赖 HTMLElement、 document
等浏览器全局对象;HTML 字符串渲染(renderBlock/exportHtml)与模板/块工具可在无 DOM 环境使用。
- 发布配置:
publishConfig.registry 指向私有 npm registry,发布时需使用对应私服。
- 撤销历史:内置最大 50 步的历史栈,超出自动丢弃最早的记录。
- 发布产物:
files 包含 es、lib、esm、dist、README.md,发布前确保已执行
pnpm build。