@os-team-11/editor 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +26 -0
- package/README.md +285 -0
- package/dist/index.cjs +1358 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.css +326 -0
- package/dist/index.css.map +1 -0
- package/dist/index.d.cts +721 -0
- package/dist/index.d.ts +721 -0
- package/dist/index.js +1315 -0
- package/dist/index.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 os-team-11 contributors
|
|
4
|
+
|
|
5
|
+
This software bundles or references @hufe921/canvas-editor
|
|
6
|
+
(https://github.com/Hufe921/canvas-editor), which is licensed under the MIT
|
|
7
|
+
License by Hufe921. All rights in the upstream software remain with its
|
|
8
|
+
authors.
|
|
9
|
+
|
|
10
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
11
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
12
|
+
in the Software without restriction, including without limitation the rights
|
|
13
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
14
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
15
|
+
furnished to do so, subject to the following conditions:
|
|
16
|
+
|
|
17
|
+
The above copyright notice and this permission notice shall be included in all
|
|
18
|
+
copies or substantial portions of the Software.
|
|
19
|
+
|
|
20
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
21
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
22
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
23
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
24
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
25
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
26
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,285 @@
|
|
|
1
|
+
# @os-team-11/editor
|
|
2
|
+
|
|
3
|
+
基于 [@hufe921/canvas-editor](https://github.com/Hufe921/canvas-editor) 的招投标文档编辑器 React 组件,提供结构化 JSON 数据(`BidSchema`)与所见即所得编辑之间的双向适配。
|
|
4
|
+
|
|
5
|
+
- **结构化数据优先**:以 `BidSchema` 作为单一数据源,AI/后端无需直接操作 canvas-editor 内部结构
|
|
6
|
+
- **工具栏开箱即用**:内置 36 个常用按钮(字体、段落、列表、表格、图片、公式等),支持动态溢出折叠到「更多」
|
|
7
|
+
- **可定制**:主题(亮/暗)、工具栏按钮、渲染器均可覆盖
|
|
8
|
+
- **AI 问答**:M5.2 起内置选区右键菜单接入自定义 `ask` 函数
|
|
9
|
+
|
|
10
|
+
## 安装
|
|
11
|
+
|
|
12
|
+
```bash
|
|
13
|
+
npm install @os-team-11/editor
|
|
14
|
+
# 或
|
|
15
|
+
pnpm add @os-team-11/editor
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
### Peer dependencies
|
|
19
|
+
|
|
20
|
+
本包把以下依赖声明为 `peerDependencies`,需要使用方自行安装:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
npm install react@^18 react-dom@^18 @hufe921/canvas-editor@^0.9.0
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
React 19 也支持。canvas-editor 必须与 peer range 内版本兼容。
|
|
27
|
+
|
|
28
|
+
## 快速开始
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { BidEditor, validateBid, type BidSchema } from '@os-team-11/editor'
|
|
32
|
+
|
|
33
|
+
const sample: BidSchema = {
|
|
34
|
+
meta: {
|
|
35
|
+
title: 'XX 项目招标文件',
|
|
36
|
+
docNo: 'ZB-2026-001',
|
|
37
|
+
tenderer: 'XX 采购中心',
|
|
38
|
+
version: '1.0.0',
|
|
39
|
+
generatedAt: '2026-06-16T00:00:00Z',
|
|
40
|
+
},
|
|
41
|
+
page: {
|
|
42
|
+
size: 'A4',
|
|
43
|
+
margins: { top: 96, right: 96, bottom: 96, left: 96 },
|
|
44
|
+
},
|
|
45
|
+
sections: [
|
|
46
|
+
{
|
|
47
|
+
id: 'sec-1',
|
|
48
|
+
title: '第一章 投标邀请',
|
|
49
|
+
level: 1,
|
|
50
|
+
blocks: [
|
|
51
|
+
{ type: 'heading', level: 2, text: '一、项目概况' },
|
|
52
|
+
{ type: 'paragraph', text: '本次招标的项目为 XX 系统建设。' },
|
|
53
|
+
{ type: 'list', ordered: true, items: ['独立法人', '具备相关资质'] },
|
|
54
|
+
],
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
export default function App() {
|
|
60
|
+
const result = validateBid(sample)
|
|
61
|
+
if (!result.success) throw new Error('invalid bid')
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<div style={{ height: '100vh' }}>
|
|
65
|
+
<BidEditor bid={result.data} onChange={next => console.log(next)} />
|
|
66
|
+
</div>
|
|
67
|
+
)
|
|
68
|
+
}
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
样式通过入口 `import './react/styles.css'` 自动注入,多数构建器(Vite / Webpack 5 / Rollup)会自动打包到产物里。若样式没生效,手动 `import '@os-team-11/editor/dist/index.css'` 即可。
|
|
72
|
+
|
|
73
|
+
## Props
|
|
74
|
+
|
|
75
|
+
### `BidEditorProps`
|
|
76
|
+
|
|
77
|
+
| Prop | 类型 | 默认值 | 说明 |
|
|
78
|
+
| ------------- | ----------------------------------- | -------- | ------------------------------------------------------ |
|
|
79
|
+
| `bid` | `BidSchema` | - | **必填**,编辑器数据源 |
|
|
80
|
+
| `onChange` | `(bid: BidSchema) => void` | - | 调用 `handle.getBid()` 时触发(读时触发,非实时) |
|
|
81
|
+
| `readOnly` | `boolean` | `false` | 只读模式,工具栏隐藏 |
|
|
82
|
+
| `toolbar` | `ToolbarConfig \| false` | `true` | 工具栏配置,`false` 完全隐藏 |
|
|
83
|
+
| `theme` | `Partial<Theme>` | 内置亮色 | 主题覆盖,`{ dark: true }` 切换暗色 |
|
|
84
|
+
| `renderers` | `Renderers` | - | 覆盖按钮、下拉、AI 对话等渲染 |
|
|
85
|
+
| `fieldPanel` | `boolean` | `false` | 显示右侧字段面板 |
|
|
86
|
+
| `ai` | `AIConfig` | - | AI 问答配置(必传 `ask` 函数才启用) |
|
|
87
|
+
| `breakpoint` | `'mobile' \| 'tablet' \| 'desktop'` | 自动 | 强制断点;`mobile` 隐藏工具栏 |
|
|
88
|
+
| `className` | `string` | - | 根容器 class |
|
|
89
|
+
| `style` | `CSSProperties` | - | 根容器 inline style |
|
|
90
|
+
| `ref` | `Ref<BidEditorHandle>` | - | 命令式 API 句柄 |
|
|
91
|
+
|
|
92
|
+
### `BidEditorHandle`(ref 方法)
|
|
93
|
+
|
|
94
|
+
| Method | 签名 | 说明 |
|
|
95
|
+
| ------------ | ------------------- | ------------------------------------------------------------ |
|
|
96
|
+
| `getBid` | `() => BidSchema` | 拉取当前文档,触发 `onChange` |
|
|
97
|
+
| `getCommand` | `() => unknown` | 暴露 canvas-editor 的 `command` 对象(执行具体格式化命令) |
|
|
98
|
+
| `print` | `() => void` | 调用浏览器打印,可用于导出 PDF |
|
|
99
|
+
| `focus` | `() => void` | 当前版本为 noop(canvas-editor 0.9.x 无公开 focus API) |
|
|
100
|
+
|
|
101
|
+
## 工具栏配置
|
|
102
|
+
|
|
103
|
+
`ToolbarConfig` 三种形态:
|
|
104
|
+
|
|
105
|
+
```tsx
|
|
106
|
+
// 1. 默认全套(36 个按钮分 8 组)
|
|
107
|
+
<BidEditor bid={bid} toolbar={true} />
|
|
108
|
+
|
|
109
|
+
// 2. 自定义扁平按钮列表
|
|
110
|
+
<BidEditor bid={bid} toolbar={['bold', 'italic', 'underline', '|', 'undo', 'redo']} />
|
|
111
|
+
|
|
112
|
+
// 3. 按组配置 + 隐藏指定按钮
|
|
113
|
+
<BidEditor
|
|
114
|
+
bid={bid}
|
|
115
|
+
toolbar={{
|
|
116
|
+
hide: ['math', 'comment'], // 从默认配置里移除指定按钮
|
|
117
|
+
}}
|
|
118
|
+
/>
|
|
119
|
+
|
|
120
|
+
// 4. 关闭工具栏
|
|
121
|
+
<BidEditor bid={bid} toolbar={false} />
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
### 36 个可用按钮 ID
|
|
125
|
+
|
|
126
|
+
```
|
|
127
|
+
font-family, font-size,
|
|
128
|
+
bold, italic, underline, strikeout, superscript, subscript,
|
|
129
|
+
color, highlight,
|
|
130
|
+
align-left, align-center, align-right, align-justify, line-height,
|
|
131
|
+
h1, h2, h3, h4, list-ol, list-ul, indent, outdent,
|
|
132
|
+
undo, redo, format-painter, clear-format,
|
|
133
|
+
table, image, hyperlink, separator, page-break, math, control, date,
|
|
134
|
+
comment
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
工具栏宽度超出容器时,溢出的按钮组会自动折叠到「⋯ 更多」下拉,无需手动配置。
|
|
138
|
+
|
|
139
|
+
## 主题
|
|
140
|
+
|
|
141
|
+
```tsx
|
|
142
|
+
<BidEditor
|
|
143
|
+
bid={bid}
|
|
144
|
+
theme={{
|
|
145
|
+
dark: true, // 切换暗色
|
|
146
|
+
colors: { primary: '#FF7A00' }, // 覆盖品牌色
|
|
147
|
+
fontSize: 14,
|
|
148
|
+
}}
|
|
149
|
+
/>
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
完整 `Theme` 结构:
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
interface Theme {
|
|
156
|
+
colors: {
|
|
157
|
+
primary: string
|
|
158
|
+
text: string
|
|
159
|
+
border: string
|
|
160
|
+
background: string
|
|
161
|
+
hover: string
|
|
162
|
+
active: string
|
|
163
|
+
}
|
|
164
|
+
radius: { button: number; container: number }
|
|
165
|
+
spacing: { button: number; group: number }
|
|
166
|
+
fontSize: number
|
|
167
|
+
fontFamily: string
|
|
168
|
+
dark?: boolean
|
|
169
|
+
}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
## AI 问答(M5.2)
|
|
173
|
+
|
|
174
|
+
传入 `ask` 函数即可启用。用户选中文本后右键菜单会出现「AI 问答」选项。
|
|
175
|
+
|
|
176
|
+
```tsx
|
|
177
|
+
<BidEditor
|
|
178
|
+
bid={bid}
|
|
179
|
+
ai={{
|
|
180
|
+
ask: async ({ selectedText, question, fullDocument }) => {
|
|
181
|
+
const res = await fetch('/api/ai-ask', {
|
|
182
|
+
method: 'POST',
|
|
183
|
+
body: JSON.stringify({ selectedText, question, fullDocument }),
|
|
184
|
+
})
|
|
185
|
+
return (await res.json()).answer
|
|
186
|
+
},
|
|
187
|
+
label: 'AI 问答',
|
|
188
|
+
placeholder: '问 AI 任何问题...',
|
|
189
|
+
includeFullDocument: false,
|
|
190
|
+
}}
|
|
191
|
+
/>
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
AI 对话 UI 默认内置,可通过 `renderers.aiDialog` 完全替换。
|
|
195
|
+
|
|
196
|
+
## 数据结构
|
|
197
|
+
|
|
198
|
+
### `BidSchema`
|
|
199
|
+
|
|
200
|
+
```ts
|
|
201
|
+
interface BidSchema {
|
|
202
|
+
meta: BidMeta
|
|
203
|
+
page: BidPage
|
|
204
|
+
sections: BidSection[]
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
interface BidMeta {
|
|
208
|
+
title: string
|
|
209
|
+
docNo: string
|
|
210
|
+
tenderer: string
|
|
211
|
+
version: string
|
|
212
|
+
generatedAt: string
|
|
213
|
+
generator?: string
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
interface BidPage {
|
|
217
|
+
size: 'A4' | 'Letter' | { width: number; height: number }
|
|
218
|
+
margins: { top: number; right: number; bottom: number; left: number }
|
|
219
|
+
header?: { template: string; showOnFirstPage: boolean }
|
|
220
|
+
footer?: { template: string }
|
|
221
|
+
watermark?: { text: string; opacity: number }
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
interface BidSection {
|
|
225
|
+
id: string
|
|
226
|
+
title: string
|
|
227
|
+
level: 1 | 2 | 3
|
|
228
|
+
blocks: BidBlock[]
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
type BidBlock =
|
|
232
|
+
| { type: 'heading'; level: 2 | 3 | 4; text: string }
|
|
233
|
+
| { type: 'paragraph'; text: string }
|
|
234
|
+
| { type: 'list'; ordered: boolean; items: string[] }
|
|
235
|
+
| { type: 'table'; rows: string[][]; caption?: string }
|
|
236
|
+
| { type: 'image'; src: string; alt?: string; caption?: string }
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
用 `validateBid(sample)` 在渲染前校验数据合法性,避免坏数据导致运行时崩溃。
|
|
240
|
+
|
|
241
|
+
## 命令式 API 示例
|
|
242
|
+
|
|
243
|
+
```tsx
|
|
244
|
+
import { useRef } from 'react'
|
|
245
|
+
import { BidEditor, type BidEditorHandle } from '@os-team-11/editor'
|
|
246
|
+
|
|
247
|
+
function App() {
|
|
248
|
+
const ref = useRef<BidEditorHandle>(null)
|
|
249
|
+
|
|
250
|
+
const handlePrint = () => ref.current?.print()
|
|
251
|
+
const handleSave = () => {
|
|
252
|
+
const latest = ref.current?.getBid() // 触发 onChange
|
|
253
|
+
// 发送到后端
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
return (
|
|
257
|
+
<>
|
|
258
|
+
<button onClick={handlePrint}>打印 / PDF</button>
|
|
259
|
+
<button onClick={handleSave}>保存</button>
|
|
260
|
+
<BidEditor ref={ref} bid={bid} />
|
|
261
|
+
</>
|
|
262
|
+
)
|
|
263
|
+
}
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
## 已知限制
|
|
267
|
+
|
|
268
|
+
- **`onChange` 是读时触发**:仅在调用 `ref.getBid()` 时触发,不是编辑时实时推送。canvas-editor 0.9.x 没有公开的内容变更事件,M6 评估接入事件化。
|
|
269
|
+
- **`bid` prop 对身份敏感**:传入新对象(即使内容相同)会触发 destroy + recreate。父组件频繁重渲染时用 `useState` / `useMemo` 记忆。
|
|
270
|
+
- **`readOnly` 仅隐藏工具栏**:底层 canvas-editor 仍可编辑。完整只读等上游支持,计划 M5.1。
|
|
271
|
+
- **部分命令可能不生效**:`indent` / `outdent` / `comment` 在 canvas-editor 0.9.x 上方法名可能不一致,M5.1 修复。
|
|
272
|
+
|
|
273
|
+
## 浏览器支持
|
|
274
|
+
|
|
275
|
+
- Chrome / Edge ≥ 90
|
|
276
|
+
- Safari ≥ 14
|
|
277
|
+
- Firefox ≥ 88
|
|
278
|
+
|
|
279
|
+
依赖 `ResizeObserver`、`PointerEvent`、CSS Custom Properties。
|
|
280
|
+
|
|
281
|
+
## 许可证
|
|
282
|
+
|
|
283
|
+
[MIT](./LICENSE) © os-team-11 contributors
|
|
284
|
+
|
|
285
|
+
本包基于 [@hufe921/canvas-editor](https://github.com/Hufe921/canvas-editor)(MIT License, © Hufe921)构建。
|