https://github.com/flycran/document-editor
https://github.com/flycran/document-editor
Last synced: 25 days ago
JSON representation
- Host: GitHub
- URL: https://github.com/flycran/document-editor
- Owner: flycran
- Created: 2026-06-23T00:39:05.000Z (about 1 month ago)
- Default Branch: main
- Last Pushed: 2026-06-26T09:43:34.000Z (about 1 month ago)
- Last Synced: 2026-06-26T11:15:00.795Z (about 1 month ago)
- Language: TypeScript
- Size: 694 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
# document-editor
基于 Tiptap + React 19 的文书编辑器组件库,提供富文本编辑、变量插入、文档预览等能力,同时支持原生 Web Component 方式在非 React 项目中使用。
## 特性
- 🚀 **开箱即用** — 提供完整的 React 组件和原生 Web Component
- ✍️ **富文本编辑** — 基于 Tiptap,支持标题、加粗、斜体、下划线、删除线、列表、对齐、缩进、字体大小、文字颜色、高亮等
- 📊 **表格支持** — 插入表格、行列增删、合并单元格
- 🔢 **变量系统** — 在文档中插入变量节点,支持多种数据类型(文本、数字、日期、时间、布尔、下拉选择)
- 🖨️ **打印预览** — 内置打印和 HTML 导出功能
- 🎨 **自定义扩展** — 分页符、签名节点、首行缩进等自定义节点
- 🌐 **跨框架使用** — 通过 Web Component 在 Vue、Angular、原生 HTML 等非 React 项目中使用
---
## 安装
```bash
bun add document-editor
# 或
npm install document-editor
```
> **React 组件模式**:宿主项目需自行安装 `react` ^19.2 和 `react-dom` ^19.2。
>
> **Web Component 模式**:本包自带完整的react 19运行时。
---
## 使用
### React 组件
#### 编辑器(DocumentEditor)
编辑器是核心组件,提供完整的富文本编辑体验,包含工具栏、变量抽屉、签名支持和引导教程。
```tsx
import { DocumentEditor, EditorRef } from 'document-editor'
import 'document-editor/document-editor.css'
function App() {
const editorRef = useRef(null)
return (
{
console.log('保存内容:', editor.getJSON())
}}
onUpdate={({ editor }) => {
console.log('内容更新:', editor.getJSON())
}}
variableListProps={{
templateList: [], // 模板列表数据
templateListLoading: false,
variableList: [], // 变量列表数据
variableListLoading: false,
onTemplateSelect: (id) => {
// 选中模板后的回调
},
}}
getEnumsQuery={(params) => {
// 返回枚举列表,用于下拉选择型变量
return [{ value: '1', label: '选项1' }]
}}
// 签名相关
doctorSginImage="data:image/png;base64,..."
patientSginImage="data:image/png;base64,..."
onDoctorSgin={() => console.log('医生签名')}
onPatientSgin={() => console.log('患者签名')}
/>
)
}
```
#### 预览器(DocumentPreviewer)
预览器用于只读模式展示文档内容,支持变量表单输入和打印导出。
```tsx
import { DocumentPreviewer, PreviewerRef } from 'document-editor'
function Preview() {
const previewRef = useRef(null)
return (
[]}
/>
)
}
```
#### 变量列表(VariableList)
变量列表组件可独立使用,展示模板和变量树,支持搜索和点击插入/替换变量。
```tsx
import { VariableList } from 'document-editor'
fetchVariables(medicalId)}
mode="insert" // 'insert' | 'replace'
/>
```
---
### 原生组件(Web Component)
当项目不使用 React 19 时(如 Vue、Angular、Svelte 或原生 HTML),可以通过 Web Component 方式使用文档预览器。
#### 1. 导入并注册
```ts
// 导入即自动注册 自定义元素
import 'document-editor/wc'
import 'document-editor/wc/document-editor.css'
```
#### 2. 在 React 中使用(JSX)
```tsx
import type { HTMLPreviewerElement } from 'document-editor/wc'
function App() {
const ref = useRef(null)
return (
console.log(ref.current?.getPreviewHTML?.())}>
输出 HTML
ref.current?.print?.()}>
打印
)
}
```
---
## 通用 API
### EditorRef(编辑器引用)
| 属性/方法 | 类型 | 说明 |
|---|---|---|
| `editor` | `Editor` | Tiptap Editor 实例,可直接调用所有 Tiptap API |
| `print()` | `() => Promise` | 触发打印 |
| `form` | `FormInstance` | antd Form 实例,用于获取变量表单值 |
| `getPreviewHTML()` | `() => string` | 获取预览用 HTML 字符串 |
### PreviewerRef(预览器引用)
| 属性/方法 | 类型 | 说明 |
|---|---|---|
| `editor` | `Editor` | Tiptap Editor 实例 |
| `print()` | `() => void` | 触发打印 |
| `form` | `FormInstance` | antd Form 实例 |
| `getPreviewHTML()` | `() => string` | 获取预览用 HTML 字符串 |
### DocumentEditor Props
| 属性 | 类型 | 默认值 | 说明 |
|---|---|---|---|
| `placeholder` | `string` | `'开始输入...'` | 编辑器占位文本 |
| `content` | `JSONContent` | — | 编辑器初始内容(Tiptap JSON 格式) |
| `inputable` | `boolean` | — | 是否允许在编辑器中输入变量值 |
| `onSave` | `({ editor }) => void` | — | 保存回调 |
| `onUpdate` | `({ editor }) => void` | — | 内容更新回调 |
| `onFocus` | `({ editor }) => void` | — | 聚焦回调 |
| `onBlur` | `({ editor }) => void` | — | 失焦回调 |
| `variableListProps` | `Omit` | **必填** | 变量列表配置 |
| `getEnumsQuery` | `(params) => EnumsItem[]` | — | 枚举查询函数,用于下拉变量 |
| `doctorSginImage` | `string` | — | 医生签名图片(Base64) |
| `patientSginImage` | `string` | — | 患者签名图片(Base64) |
| `familySginImage` | `string` | — | 家属签名图片(Base64) |
| `onDoctorSgin` | `() => void` | — | 医生签名点击回调 |
| `onPatientSgin` | `() => void` | — | 患者签名点击回调 |
| `onFamilySgin` | `() => void` | — | 家属签名点击回调 |
### DocumentPreviewer Props
| 属性 | 类型 | 说明 |
|---|---|---|
| `content` | `JSONContent` | 预览的文档内容 |
| `formData` | `any` | 预填充的表单数据 |
| `inputable` | `boolean` | 是否允许在预览中填写变量 |
| `getEnumsQuery` | `(params) => EnumsItem[]` | 枚举查询函数 |
### VariableList Props
| 属性 | 类型 | 说明 |
|---|---|---|
| `templateList` | `Array` | 模板列表数据 |
| `templateListLoading` | `boolean` | 模板列表加载状态 |
| `templateValue` | `string` | 当前选中的模板 ID |
| `variableList` | `InformedTemplateParagraphListItem[]` | 变量/段落列表 |
| `variableListLoading` | `boolean` | 变量列表加载状态 |
| `onTemplateSelect` | `(medicalId: string) => void` | 模板选中回调 |
---
## 编辑器使用技巧
### 变量系统
编辑器支持在文档中插入**变量节点**,变量分为以下类型:
| 类型 | 说明 | 渲染形式 |
|---|---|---|
| `text` | 文本输入 | `` |
| `number` | 数字输入 | `` |
| `date` | 日期选择 | `` |
| `time` | 时间选择 | `` |
| `date-time` | 日期时间选择 | `` |
| `boolean` | 布尔选择 | 单选按钮组 |
| `select` | 下拉选择(有值域) | ``(通过 `getEnumsQuery` 获取选项) |
#### 插入变量
1. 点击工具栏 **「插入变量」** 按钮打开变量抽屉
2. 选择模板 → 展开节点 → 点击变量元素即可插入
3. 支持搜索过滤变量
#### 替换变量
1. 选中已有的变量节点
2. 在弹出的气泡菜单中点击 **「替换变量」**
3. 在抽屉中选择新变量即可替换
#### 变量别名
选中变量后,可在气泡菜单中点击 **「设置别名」** 为该变量设置显示别名,别名会替代原始标签显示。
#### 显示/隐藏字段名
变量节点默认显示字段名标签,可通过气泡菜单中的 **「显示字段名」** 按钮切换。
### 签名节点
工具栏提供三种签名类型按钮:医生签名、患者签名、家属签名。点击即可在光标处插入签名占位符。签名节点也支持别名设置和字段名显示切换。
### 分页符
点击工具栏 **「分页符」** 按钮可在光标处插入分页符,打印时会在分页符处换页。
### 表格操作
- **插入表格**:点击工具栏表格按钮,拖拽选择行列数(1×1 ~ 8×8)
- **选中表格后**,气泡菜单提供:上方/下方添加行、左侧/右侧添加列、删除行/列、删除表格
- 支持合并单元格(通过 Tiptap 原生表格命令)
### 导入/导出
工具栏提供导入和导出按钮,支持将编辑器内容导出为 JSON 文件,或从 JSON 文件导入内容。
### 快捷键
| 快捷键 | 功能 |
|---|---|
| `Ctrl+B` | 加粗 |
| `Ctrl+I` | 斜体 |
| `Ctrl+U` | 下划线 |
| `Ctrl+Z` | 撤销 |
| `Ctrl+Shift+Z` / `Ctrl+Y` | 重做 |
### 获取编辑器内容
```tsx
const ref = useRef(null)
// 获取 JSON 格式内容(用于存储)
const json = ref.current?.editor.getJSON()
// 获取 HTML 格式内容
const html = ref.current?.editor.getHTML()
// 获取预览用 HTML(含样式)
const previewHtml = ref.current?.getPreviewHTML()
// 获取表单数据(变量值)
const formValues = ref.current?.form.getFieldsValue()
// 打印
await ref.current?.print()
```
---
## 在不支持 React 19 的项目中使用原生组件
如果你的项目使用 Vue、Angular、Svelte、jQuery 或原生 HTML,无法直接使用 React 组件,可以通过 Web Component 方式集成。
### 原理
项目使用 `@r2wc/react-to-web-component` 将 React 组件包装为标准的 Custom Element。`` 是一个注册在全局的自定义元素,可以在任何框架中使用。
### 完整示例
参考 `examples/wc-demo/` 目录,其中包含一个完整的使用示例。
### 属性传递
Web Component 的属性通过 HTML attribute 或 JavaScript property 传递:
```js
const el = document.querySelector('document-previewer')
// JSON 类型属性
el.content = { type: 'doc', content: [...] }
el.formData = { field1: 'value' }
// 布尔类型属性
el.inputable = true
// 函数类型属性
el.getEnumsQuery = (params) => [{ value: '1', label: '选项' }]
// 字符串类型属性
el.className = 'my-previewer'
```
### 调用方法
```js
const el = document.querySelector('document-previewer')
// 获取预览 HTML
const html = el.getPreviewHTML()
// 打印
el.print()
// 获取表单值
const values = el.form.getFieldsValue()
// 访问 Tiptap Editor 实例
const json = el.editor.getJSON()
```
### 注意事项
1. **样式隔离**:Web Component 使用 Light DOM 模式,样式需要手动引入 CSS 文件
2. **React 依赖**:即使使用 Web Component,宿主项目仍需安装 `react` 和 `react-dom` 作为 peer dependency
3. **JSON 属性**:`content` 和 `formData` 为 JSON 类型,需通过 JS property 设置,不能通过 HTML attribute 传递
---
## 开发
```bash
# 如果使用 mise 则执行这一步
mise install
# 如果不使用 mise 则执行这两步
nvm use 24
npm install bun@1 -g
bun install
bun dev
```
#### 访问地址
```
http://localhost:4004/editor?account=900101&tenant_id=900101&password=240408
```
### 构建
```bash
# 构建 React 组件库
bun run build
# 构建 Web Component
bun run build:wc
# 构建 Demo
bun run build:demo
```
### API 文件自动生成
```bash
# 单次生成
bun run codegen
# 监听模式(文件变更自动重新生成)
bun run codegen:watch
```
API 代码生成配置位于 `scripts/codegen-api/`,基于 OpenAPI 规范文件 `openapi/openapi.json` 自动生成 TypeScript 类型和请求函数。
### 项目结构
```
src/
├── components/
│ ├── DocumentEditor/ # 编辑器组件
│ │ ├── contexts/ # Context(编辑器实例、枚举、签名事件)
│ │ ├── extensions/ # Tiptap 自定义扩展
│ │ │ ├── VariableExtension.ts # 变量抽屉状态管理
│ │ │ ├── VariableNode/ # 变量节点
│ │ │ ├── SginNode/ # 签名节点
│ │ │ ├── PageBreakNode.ts # 分页符节点
│ │ │ ├── TextIndentNode.ts # 首行缩进
│ │ │ └── TableExtension.ts # 表格扩展
│ │ ├── Toolbar/ # 工具栏
│ │ └── EditorTour/ # 新手引导
│ ├── DocumentPreviewer/ # 预览器组件
│ ├── VariableList/ # 变量列表组件
│ └── PreviewField/ # 预览字段组件
├── wc.ts # Web Component 入口
├── index.ts # React 组件入口
└── utils/ # 工具函数(打印、HTML 导出)
```
## 其他
! 禁止修改generated目录下的文件,这些文件由插件生成,任何修改都会被覆盖。