{"id":51418064,"url":"https://github.com/flycran/document-editor","last_synced_at":"2026-07-04T22:01:26.731Z","repository":{"id":367522594,"uuid":"1277504590","full_name":"flycran/document-editor","owner":"flycran","description":null,"archived":false,"fork":false,"pushed_at":"2026-06-26T09:43:34.000Z","size":711,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-26T11:15:00.795Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/flycran.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-06-23T00:39:05.000Z","updated_at":"2026-06-26T09:43:38.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/flycran/document-editor","commit_stats":null,"previous_names":["flycran/document-editor"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/flycran/document-editor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flycran%2Fdocument-editor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flycran%2Fdocument-editor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flycran%2Fdocument-editor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flycran%2Fdocument-editor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/flycran","download_url":"https://codeload.github.com/flycran/document-editor/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/flycran%2Fdocument-editor/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35136712,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-07-04T22:01:25.810Z","updated_at":"2026-07-04T22:01:26.720Z","avatar_url":"https://github.com/flycran.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# document-editor\n\n基于 Tiptap + React 19 的文书编辑器组件库，提供富文本编辑、变量插入、文档预览等能力，同时支持原生 Web Component 方式在非 React 项目中使用。\n\n## 特性\n\n- 🚀 **开箱即用** — 提供完整的 React 组件和原生 Web Component\n- ✍️ **富文本编辑** — 基于 Tiptap，支持标题、加粗、斜体、下划线、删除线、列表、对齐、缩进、字体大小、文字颜色、高亮等\n- 📊 **表格支持** — 插入表格、行列增删、合并单元格\n- 🔢 **变量系统** — 在文档中插入变量节点，支持多种数据类型（文本、数字、日期、时间、布尔、下拉选择）\n- 🖨️ **打印预览** — 内置打印和 HTML 导出功能\n- 🎨 **自定义扩展** — 分页符、签名节点、首行缩进等自定义节点\n- 🌐 **跨框架使用** — 通过 Web Component 在 Vue、Angular、原生 HTML 等非 React 项目中使用\n\n---\n\n## 安装\n\n```bash\nbun add document-editor\n# 或\nnpm install document-editor\n```\n\n\u003e **React 组件模式**：宿主项目需自行安装 `react` ^19.2 和 `react-dom` ^19.2。\n\u003e\n\u003e **Web Component 模式**：本包自带完整的react 19运行时。\n\n---\n\n## 使用\n\n### React 组件\n\n#### 编辑器（DocumentEditor）\n\n编辑器是核心组件，提供完整的富文本编辑体验，包含工具栏、变量抽屉、签名支持和引导教程。\n\n```tsx\nimport { DocumentEditor, EditorRef } from 'document-editor'\nimport 'document-editor/document-editor.css'\n\nfunction App() {\n  const editorRef = useRef\u003cEditorRef\u003e(null)\n\n  return (\n    \u003cDocumentEditor\n      ref={editorRef}\n      placeholder=\"开始输入...\"\n      content={initialContent}\n      inputable\n      onSave={({ editor }) =\u003e {\n        console.log('保存内容:', editor.getJSON())\n      }}\n      onUpdate={({ editor }) =\u003e {\n        console.log('内容更新:', editor.getJSON())\n      }}\n      variableListProps={{\n        templateList: [],        // 模板列表数据\n        templateListLoading: false,\n        variableList: [],        // 变量列表数据\n        variableListLoading: false,\n        onTemplateSelect: (id) =\u003e {\n          // 选中模板后的回调\n        },\n      }}\n      getEnumsQuery={(params) =\u003e {\n        // 返回枚举列表，用于下拉选择型变量\n        return [{ value: '1', label: '选项1' }]\n      }}\n      // 签名相关\n      doctorSginImage=\"data:image/png;base64,...\"\n      patientSginImage=\"data:image/png;base64,...\"\n      onDoctorSgin={() =\u003e console.log('医生签名')}\n      onPatientSgin={() =\u003e console.log('患者签名')}\n    /\u003e\n  )\n}\n```\n\n#### 预览器（DocumentPreviewer）\n\n预览器用于只读模式展示文档内容，支持变量表单输入和打印导出。\n\n```tsx\nimport { DocumentPreviewer, PreviewerRef } from 'document-editor'\n\nfunction Preview() {\n  const previewRef = useRef\u003cPreviewerRef\u003e(null)\n\n  return (\n    \u003cDocumentPreviewer\n      ref={previewRef}\n      content={docContent}       // JSONContent 格式的文档内容\n      formData={{ field1: '值' }} // 预填充的表单数据\n      inputable                   // 是否允许在预览中填写变量\n      getEnumsQuery={(params) =\u003e []}\n    /\u003e\n  )\n}\n```\n\n#### 变量列表（VariableList）\n\n变量列表组件可独立使用，展示模板和变量树，支持搜索和点击插入/替换变量。\n\n```tsx\nimport { VariableList } from 'document-editor'\n\n\u003cVariableList\n  templateList={templates}\n  templateListLoading={loading}\n  templateValue={selectedId}\n  variableList={variables}\n  variableListLoading={false}\n  onTemplateSelect={(medicalId) =\u003e fetchVariables(medicalId)}\n  mode=\"insert\"  // 'insert' | 'replace'\n/\u003e\n```\n\n---\n\n### 原生组件（Web Component）\n\n当项目不使用 React 19 时（如 Vue、Angular、Svelte 或原生 HTML），可以通过 Web Component 方式使用文档预览器。\n\n#### 1. 导入并注册\n\n```ts\n// 导入即自动注册 \u003cdocument-previewer\u003e 自定义元素\nimport 'document-editor/wc'\nimport 'document-editor/wc/document-editor.css'\n```\n\n#### 2. 在 React 中使用（JSX）\n\n```tsx\nimport type { HTMLPreviewerElement } from 'document-editor/wc'\n\nfunction App() {\n  const ref = useRef\u003cHTMLPreviewerElement\u003e(null)\n\n  return (\n    \u003cdiv\u003e\n      \u003cdocument-previewer\n        ref={ref}\n        content={initialContent}\n        inputable\n      /\u003e\n      \u003cbutton onClick={() =\u003e console.log(ref.current?.getPreviewHTML?.())}\u003e\n        输出 HTML\n      \u003c/button\u003e\n      \u003cbutton onClick={() =\u003e ref.current?.print?.()}\u003e\n        打印\n      \u003c/button\u003e\n    \u003c/div\u003e\n  )\n}\n```\n\n---\n\n## 通用 API\n\n### EditorRef（编辑器引用）\n\n| 属性/方法 | 类型 | 说明 |\n|---|---|---|\n| `editor` | `Editor` | Tiptap Editor 实例，可直接调用所有 Tiptap API |\n| `print()` | `() =\u003e Promise\u003cvoid\u003e` | 触发打印 |\n| `form` | `FormInstance` | antd Form 实例，用于获取变量表单值 |\n| `getPreviewHTML()` | `() =\u003e string` | 获取预览用 HTML 字符串 |\n\n### PreviewerRef（预览器引用）\n\n| 属性/方法 | 类型 | 说明 |\n|---|---|---|\n| `editor` | `Editor` | Tiptap Editor 实例 |\n| `print()` | `() =\u003e void` | 触发打印 |\n| `form` | `FormInstance` | antd Form 实例 |\n| `getPreviewHTML()` | `() =\u003e string` | 获取预览用 HTML 字符串 |\n\n### DocumentEditor Props\n\n| 属性 | 类型 | 默认值 | 说明 |\n|---|---|---|---|\n| `placeholder` | `string` | `'开始输入...'` | 编辑器占位文本 |\n| `content` | `JSONContent` | — | 编辑器初始内容（Tiptap JSON 格式） |\n| `inputable` | `boolean` | — | 是否允许在编辑器中输入变量值 |\n| `onSave` | `({ editor }) =\u003e void` | — | 保存回调 |\n| `onUpdate` | `({ editor }) =\u003e void` | — | 内容更新回调 |\n| `onFocus` | `({ editor }) =\u003e void` | — | 聚焦回调 |\n| `onBlur` | `({ editor }) =\u003e void` | — | 失焦回调 |\n| `variableListProps` | `Omit\u003cVariableListProps, 'mode'\u003e` | **必填** | 变量列表配置 |\n| `getEnumsQuery` | `(params) =\u003e EnumsItem[]` | — | 枚举查询函数，用于下拉变量 |\n| `doctorSginImage` | `string` | — | 医生签名图片（Base64） |\n| `patientSginImage` | `string` | — | 患者签名图片（Base64） |\n| `familySginImage` | `string` | — | 家属签名图片（Base64） |\n| `onDoctorSgin` | `() =\u003e void` | — | 医生签名点击回调 |\n| `onPatientSgin` | `() =\u003e void` | — | 患者签名点击回调 |\n| `onFamilySgin` | `() =\u003e void` | — | 家属签名点击回调 |\n\n### DocumentPreviewer Props\n\n| 属性 | 类型 | 说明 |\n|---|---|---|\n| `content` | `JSONContent` | 预览的文档内容 |\n| `formData` | `any` | 预填充的表单数据 |\n| `inputable` | `boolean` | 是否允许在预览中填写变量 |\n| `getEnumsQuery` | `(params) =\u003e EnumsItem[]` | 枚举查询函数 |\n\n### VariableList Props\n\n| 属性 | 类型 | 说明 |\n|---|---|---|\n| `templateList` | `Array` | 模板列表数据 |\n| `templateListLoading` | `boolean` | 模板列表加载状态 |\n| `templateValue` | `string` | 当前选中的模板 ID |\n| `variableList` | `InformedTemplateParagraphListItem[]` | 变量/段落列表 |\n| `variableListLoading` | `boolean` | 变量列表加载状态 |\n| `onTemplateSelect` | `(medicalId: string) =\u003e void` | 模板选中回调 |\n\n---\n\n## 编辑器使用技巧\n\n### 变量系统\n\n编辑器支持在文档中插入**变量节点**，变量分为以下类型：\n\n| 类型 | 说明 | 渲染形式 |\n|---|---|---|\n| `text` | 文本输入 | `\u003cInput /\u003e` |\n| `number` | 数字输入 | `\u003cInput type=\"number\" /\u003e` |\n| `date` | 日期选择 | `\u003cDatePicker /\u003e` |\n| `time` | 时间选择 | `\u003cTimePicker /\u003e` |\n| `date-time` | 日期时间选择 | `\u003cDatePicker showTime /\u003e` |\n| `boolean` | 布尔选择 | 单选按钮组 |\n| `select` | 下拉选择（有值域） | `\u003cSelect /\u003e`（通过 `getEnumsQuery` 获取选项） |\n\n#### 插入变量\n\n1. 点击工具栏 **「插入变量」** 按钮打开变量抽屉\n2. 选择模板 → 展开节点 → 点击变量元素即可插入\n3. 支持搜索过滤变量\n\n#### 替换变量\n\n1. 选中已有的变量节点\n2. 在弹出的气泡菜单中点击 **「替换变量」**\n3. 在抽屉中选择新变量即可替换\n\n#### 变量别名\n\n选中变量后，可在气泡菜单中点击 **「设置别名」** 为该变量设置显示别名，别名会替代原始标签显示。\n\n#### 显示/隐藏字段名\n\n变量节点默认显示字段名标签，可通过气泡菜单中的 **「显示字段名」** 按钮切换。\n\n### 签名节点\n\n工具栏提供三种签名类型按钮：医生签名、患者签名、家属签名。点击即可在光标处插入签名占位符。签名节点也支持别名设置和字段名显示切换。\n\n### 分页符\n\n点击工具栏 **「分页符」** 按钮可在光标处插入分页符，打印时会在分页符处换页。\n\n### 表格操作\n\n- **插入表格**：点击工具栏表格按钮，拖拽选择行列数（1×1 ~ 8×8）\n- **选中表格后**，气泡菜单提供：上方/下方添加行、左侧/右侧添加列、删除行/列、删除表格\n- 支持合并单元格（通过 Tiptap 原生表格命令）\n\n### 导入/导出\n\n工具栏提供导入和导出按钮，支持将编辑器内容导出为 JSON 文件，或从 JSON 文件导入内容。\n\n### 快捷键\n\n| 快捷键 | 功能 |\n|---|---|\n| `Ctrl+B` | 加粗 |\n| `Ctrl+I` | 斜体 |\n| `Ctrl+U` | 下划线 |\n| `Ctrl+Z` | 撤销 |\n| `Ctrl+Shift+Z` / `Ctrl+Y` | 重做 |\n\n### 获取编辑器内容\n\n```tsx\nconst ref = useRef\u003cEditorRef\u003e(null)\n\n// 获取 JSON 格式内容（用于存储）\nconst json = ref.current?.editor.getJSON()\n\n// 获取 HTML 格式内容\nconst html = ref.current?.editor.getHTML()\n\n// 获取预览用 HTML（含样式）\nconst previewHtml = ref.current?.getPreviewHTML()\n\n// 获取表单数据（变量值）\nconst formValues = ref.current?.form.getFieldsValue()\n\n// 打印\nawait ref.current?.print()\n```\n\n---\n\n## 在不支持 React 19 的项目中使用原生组件\n\n如果你的项目使用 Vue、Angular、Svelte、jQuery 或原生 HTML，无法直接使用 React 组件，可以通过 Web Component 方式集成。\n\n### 原理\n\n项目使用 `@r2wc/react-to-web-component` 将 React 组件包装为标准的 Custom Element。`\u003cdocument-previewer\u003e` 是一个注册在全局的自定义元素，可以在任何框架中使用。\n\n### 完整示例\n\n参考 `examples/wc-demo/` 目录，其中包含一个完整的使用示例。\n\n### 属性传递\n\nWeb Component 的属性通过 HTML attribute 或 JavaScript property 传递：\n\n```js\nconst el = document.querySelector('document-previewer')\n\n// JSON 类型属性\nel.content = { type: 'doc', content: [...] }\nel.formData = { field1: 'value' }\n\n// 布尔类型属性\nel.inputable = true\n\n// 函数类型属性\nel.getEnumsQuery = (params) =\u003e [{ value: '1', label: '选项' }]\n\n// 字符串类型属性\nel.className = 'my-previewer'\n```\n\n### 调用方法\n\n```js\nconst el = document.querySelector('document-previewer')\n\n// 获取预览 HTML\nconst html = el.getPreviewHTML()\n\n// 打印\nel.print()\n\n// 获取表单值\nconst values = el.form.getFieldsValue()\n\n// 访问 Tiptap Editor 实例\nconst json = el.editor.getJSON()\n```\n\n### 注意事项\n\n1. **样式隔离**：Web Component 使用 Light DOM 模式，样式需要手动引入 CSS 文件\n2. **React 依赖**：即使使用 Web Component，宿主项目仍需安装 `react` 和 `react-dom` 作为 peer dependency\n3. **JSON 属性**：`content` 和 `formData` 为 JSON 类型，需通过 JS property 设置，不能通过 HTML attribute 传递\n\n---\n\n## 开发\n\n```bash\n# 如果使用 mise 则执行这一步\nmise install\n# 如果不使用 mise 则执行这两步\nnvm use 24\nnpm install bun@1 -g\n\nbun install\nbun dev\n```\n\n#### 访问地址\n\n```\nhttp://localhost:4004/editor?account=900101\u0026tenant_id=900101\u0026password=240408\n```\n\n### 构建\n\n```bash\n# 构建 React 组件库\nbun run build\n\n# 构建 Web Component\nbun run build:wc\n\n# 构建 Demo\nbun run build:demo\n```\n\n### API 文件自动生成\n\n```bash\n# 单次生成\nbun run codegen\n\n# 监听模式（文件变更自动重新生成）\nbun run codegen:watch\n```\n\nAPI 代码生成配置位于 `scripts/codegen-api/`，基于 OpenAPI 规范文件 `openapi/openapi.json` 自动生成 TypeScript 类型和请求函数。\n\n### 项目结构\n\n```\nsrc/\n├── components/\n│   ├── DocumentEditor/       # 编辑器组件\n│   │   ├── contexts/         # Context（编辑器实例、枚举、签名事件）\n│   │   ├── extensions/       # Tiptap 自定义扩展\n│   │   │   ├── VariableExtension.ts   # 变量抽屉状态管理\n│   │   │   ├── VariableNode/          # 变量节点\n│   │   │   ├── SginNode/              # 签名节点\n│   │   │   ├── PageBreakNode.ts       # 分页符节点\n│   │   │   ├── TextIndentNode.ts      # 首行缩进\n│   │   │   └── TableExtension.ts      # 表格扩展\n│   │   ├── Toolbar/          # 工具栏\n│   │   └── EditorTour/       # 新手引导\n│   ├── DocumentPreviewer/    # 预览器组件\n│   ├── VariableList/         # 变量列表组件\n│   └── PreviewField/         # 预览字段组件\n├── wc.ts                     # Web Component 入口\n├── index.ts                  # React 组件入口\n└── utils/                    # 工具函数（打印、HTML 导出）\n```\n\n## 其他\n\n! 禁止修改generated目录下的文件，这些文件由插件生成，任何修改都会被覆盖。\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflycran%2Fdocument-editor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fflycran%2Fdocument-editor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fflycran%2Fdocument-editor/lists"}