bridgerte 0.9.0 → 0.9.1

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/README.md CHANGED
@@ -2,8 +2,14 @@
2
2
 
3
3
  ![BridgeRTE logo](https://gitee.com/wangchuyi1122/bridgerte/raw/master/packages/bridgerte/assets/bridgerte-logo-small.png)
4
4
 
5
- BridgeRTE 是面向 Web、H5、PC、React Native WebView 和 Flutter WebView 的跨端富文本编辑器。
6
- 业务项目只需要安装并引用 `bridgerte`;局部能力可以从 `bridgerte/*` subpath 导入。
5
+ BridgeRTE 是面向 Web、PC、H5、React Native WebView 和 Flutter WebView 的跨端富文本编辑器。
6
+ 业务项目只需要安装 `bridgerte`,不需要额外安装 Lexical 相关包。
7
+
8
+ 它提供三类接入方式:
9
+
10
+ - DOM 编辑器:直接在 Web、PC、H5 页面里创建富文本编辑器。
11
+ - 编辑器和菜单分离:editor 负责内容,toolbar/tabbar 由业务按布局单独挂载。
12
+ - WebView / Native:WebView 内运行编辑器,RN/Flutter 原生侧自己渲染菜单并通过 bridge 发命令。
7
13
 
8
14
  ## 安装
9
15
 
@@ -11,123 +17,139 @@ BridgeRTE 是面向 Web、H5、PC、React Native WebView 和 Flutter WebView 的
11
17
  pnpm add bridgerte
12
18
  ```
13
19
 
14
- 如果使用 npm:
20
+ 使用 npm:
15
21
 
16
22
  ```bash
17
23
  npm install bridgerte
18
24
  ```
19
25
 
20
- DOM 编辑器需要显式导入样式:
26
+ DOM 编辑器必须显式导入样式:
21
27
 
22
28
  ```ts
23
29
  import 'bridgerte/style.css';
24
30
  ```
25
31
 
26
- ## 快速开始
32
+ ## 推荐导入方式
33
+
34
+ 推荐按能力从 subpath 导入,方便业务打包器按使用边界 tree-shaking:
27
35
 
28
36
  ```ts
29
- import { createRichTextEditor } from 'bridgerte';
37
+ import { createRichTextEditor, createRichTextToolbar } from 'bridgerte/dom';
38
+ import { createWebViewBridgeRuntime } from 'bridgerte/webview';
39
+ import { BRIDGERTE_CONTENT_VERSION } from 'bridgerte/core';
40
+ import { isBridgeMessage } from 'bridgerte/bridge';
41
+ import { defaultMenuSchema, resolveToolbarMenu } from 'bridgerte/native-spec';
30
42
  import 'bridgerte/style.css';
43
+ ```
31
44
 
32
- const container = document.querySelector<HTMLElement>('#editor');
33
-
34
- if (!container) throw new Error('editor container not found');
45
+ 入口说明:
35
46
 
36
- const editor = createRichTextEditor(container, {
37
- placeholder: '请输入内容',
38
- onContentChange(change) {
39
- console.log(change.plainTextLength, change.isOverMaxLength);
40
- }
41
- });
47
+ - `bridgerte/dom`:DOM 编辑器、独立 toolbar/tabbar、WebView runtime 的 DOM 实现。
48
+ - `bridgerte/webview`:WebView 页面内的 bridge runtime。
49
+ - `bridgerte/core`:内容模型、命令、上传、菜单、参数面板和 `EditorAPI` 类型。
50
+ - `bridgerte/bridge`:WebView 双向消息类型、默认事件节流配置和消息判断工具。
51
+ - `bridgerte/native-spec`:RN/Flutter 原生菜单 schema、toolbar 解析和命令状态匹配工具。
52
+ - `bridgerte/style.css`:DOM 默认样式。
53
+ - `bridgerte`:聚合入口,适合迁移期或小型项目;生产示例优先使用 subpath。
42
54
 
43
- window.addEventListener('beforeunload', () => {
44
- editor.destroy();
45
- });
46
- ```
55
+ ## 快速开始
47
56
 
48
- 页面里准备一个容器即可:
57
+ 页面准备两个容器:一个给 toolbar/tabbar,一个给编辑器内容区。`createRichTextEditor()`
58
+ 只创建 editor;菜单必须用 `createRichTextToolbar()` 单独挂载,并绑定同一个 `EditorAPI`。
49
59
 
50
60
  ```html
61
+ <div id="toolbar"></div>
51
62
  <div id="editor"></div>
52
63
  ```
53
64
 
54
- ## 导入入口
65
+ ```ts
66
+ import { createRichTextEditor, createRichTextToolbar } from 'bridgerte/dom';
67
+ import 'bridgerte/style.css';
55
68
 
56
- 常规 Web/PC/H5 项目从主入口导入:
69
+ const editorContainer = document.querySelector<HTMLElement>('#editor');
70
+ const toolbarContainer = document.querySelector<HTMLElement>('#toolbar');
57
71
 
58
- ```ts
59
- import {
60
- createRichTextEditor,
61
- createRichTextToolbar,
62
- createWebViewBridgeRuntime
63
- } from 'bridgerte';
72
+ if (!editorContainer) throw new Error('editor container not found');
73
+ if (!toolbarContainer) throw new Error('toolbar container not found');
64
74
 
65
- import type {
66
- EditorAPI,
67
- EditorCommand,
68
- EditorContent,
69
- MenuItem,
70
- ToolbarConfig
71
- } from 'bridgerte';
72
- ```
75
+ const editor = createRichTextEditor(editorContainer, {
76
+ placeholder: '开始输入',
77
+ onContentChange(change) {
78
+ counter.textContent = `${change.plainTextLength}/${change.maxLength ?? '∞'}`;
79
+ saveButton.disabled = !change.dirty;
80
+ }
81
+ });
73
82
 
74
- 只使用某一类能力时,可以使用 subpath:
83
+ const toolbar = createRichTextToolbar(toolbarContainer, {
84
+ editor,
85
+ placement: 'top'
86
+ });
75
87
 
76
- ```ts
77
- import { createRichTextEditor } from 'bridgerte/dom';
78
- import { createWebViewBridgeRuntime } from 'bridgerte/webview';
79
- import { BRIDGERTE_CONTENT_VERSION } from 'bridgerte/core';
80
- import { isBridgeMessage } from 'bridgerte/bridge';
81
- import { defaultMenuSchema, resolveToolbarMenu } from 'bridgerte/native-spec';
88
+ toolbar.update();
89
+
90
+ window.addEventListener('beforeunload', () => {
91
+ toolbar.destroy();
92
+ editor.destroy();
93
+ });
82
94
  ```
83
95
 
84
- - `bridgerte`:常用聚合入口。
85
- - `bridgerte/dom`:DOM 编辑器和独立 toolbar
86
- - `bridgerte/webview`:WebView 页面内的 bridge runtime。
87
- - `bridgerte/core`:内容、命令、上传、菜单、参数面板和 editor API 类型。
88
- - `bridgerte/bridge`:WebView 双向消息类型和消息判断工具。
89
- - `bridgerte/native-spec`:RN/Flutter 原生菜单 schema 和 toolbar 解析工具。
90
- - `bridgerte/style.css`:DOM 默认样式。
96
+ `placement: 'top' | 'bottom'` 只影响菜单语义、默认样式状态和无障碍命名;DOM 放在哪里、
97
+ 是否吸顶、吸底或跟随键盘,由业务自己的布局决定。销毁时建议先销毁 toolbar,再销毁 editor
98
+
99
+ WebView / RN / Flutter 也是同一心智:WebView 内的 editor 只提供内容和命令能力,原生菜单读取
100
+ ready payload 中的 schema / command state 后自行渲染,并通过 bridge 发送命令。
91
101
 
92
102
  ## 基础配置
93
103
 
94
104
  ```ts
105
+ import { createRichTextEditor } from 'bridgerte/dom';
106
+ import type { EditorContent } from 'bridgerte/core';
107
+
108
+ const initialValue: Partial<EditorContent> = {
109
+ html: '<p>Hello BridgeRTE</p>',
110
+ plainText: 'Hello BridgeRTE'
111
+ };
112
+
95
113
  const editor = createRichTextEditor(container, {
96
- value: {
97
- html: '<p>Hello BridgeRTE</p>',
98
- plainText: 'Hello BridgeRTE'
99
- },
114
+ value: initialValue,
100
115
  readonly: false,
101
- platform: 'pc',
102
- toolbarMode: 'top',
103
116
  placeholder: '写点什么',
104
117
  maxLength: 10000,
105
118
  keyboardShortcuts: true,
106
119
  onReady(api) {
107
120
  api.focus();
121
+ },
122
+ onError(error) {
123
+ reportError(error);
124
+ },
125
+ onFocus() {
126
+ console.log('focus');
127
+ },
128
+ onBlur() {
129
+ console.log('blur');
108
130
  }
109
131
  });
110
132
  ```
111
133
 
112
- 常用配置:
134
+ 常用选项:
113
135
 
114
136
  - `value`:初始内容,传 `Partial<EditorContent>`。
115
137
  - `readonly`:只读状态。
116
- - `platform`:`'pc' | 'h5' | 'webview'`。
117
- - `toolbarMode`:`'top' | 'bottom' | 'none' | 'native'`。
118
138
  - `placeholder`:空态提示。
119
139
  - `maxLength`:最大纯文本长度。
120
- - `keyboardShortcuts`:基础快捷键,默认关闭。
121
- - `onReady(api)`:编辑器 ready 后回传 `EditorAPI`。
140
+ - `keyboardShortcuts`:是否启用 DOM 基础快捷键,默认关闭。
141
+ - `onReady(api)`:编辑器初始化完成后回传 `EditorAPI`。
142
+ - `onContentChange(change)`:高频轻量内容摘要。
143
+ - `onChange(content)`:兼容旧项目的完整内容回调,大文档不建议逐字依赖。
122
144
  - `onError(error)`:运行时错误。
123
145
  - `onFocus()` / `onBlur()`:焦点变化。
124
146
 
125
- `toolbarMode` 说明:
147
+ Deprecated 兼容字段:
126
148
 
127
- - `top`:默认顶部 toolbar。
128
- - `bottom`:H5 底部 tabbar。
129
- - `none`:只创建编辑器,业务自己挂载 toolbar。
130
- - `native`:WebView/RN/Flutter 场景不渲染 DOM 菜单。
149
+ - `toolbarMode`:历史字段,当前在 `createRichTextEditor()` 中是 no-op,不再创建或控制 DOM
150
+ toolbar/tabbar。
151
+ - `toolbarConfig`:历史 editor 字段,当前不再影响 editor 创建。菜单显示结构请传给
152
+ `createRichTextToolbar()`。
131
153
 
132
154
  ## 内容读写
133
155
 
@@ -152,20 +174,25 @@ editor.setContent({
152
174
  });
153
175
  ```
154
176
 
155
- 高频内容变化建议使用轻量摘要:
177
+ 高频变化使用轻量摘要:
156
178
 
157
179
  ```ts
158
180
  createRichTextEditor(container, {
181
+ maxLength: 5000,
159
182
  onContentChange(change) {
160
183
  saveButton.disabled = !change.dirty;
161
184
  counter.textContent = `${change.plainTextLength}/${change.maxLength ?? '∞'}`;
185
+ warning.hidden = !change.isOverMaxLength;
162
186
  }
163
187
  });
164
188
  ```
165
189
 
166
- `onContentChange` 不携带完整 `html`、`json`、`plainText`,适合驱动 dirty、字数和保存按钮。
167
- 保存、提交或离开页面确认时,再主动调用 `getContent()`。`onChange(content)` 会回传完整内容,
168
- 主要用于兼容旧项目;大文档场景不建议逐字依赖它保存。
190
+ 重要边界:
191
+
192
+ - `onContentChange` 不携带完整 `html`、`json`、`plainText`,适合驱动 dirty、字数和保存按钮。
193
+ - 保存、提交、离开页面确认时,再主动调用 `getContent()`。
194
+ - `onChange(content)` 会回传完整内容,主要用于兼容旧项目;10w 内容场景不要逐字依赖它保存。
195
+ - WebView 高频 `editor.contentChange` 也只应依赖轻量摘要;完整内容通过 `requestContent` 获取。
169
196
 
170
197
  ## EditorAPI
171
198
 
@@ -178,7 +205,7 @@ editor.executeCommand({ type: 'format.bold' });
178
205
 
179
206
  const states = editor.getCommandStates();
180
207
  const unsubscribe = editor.subscribeCommandStateChange((nextStates) => {
181
- console.log(nextStates);
208
+ renderToolbarState(nextStates);
182
209
  });
183
210
 
184
211
  unsubscribe();
@@ -190,8 +217,8 @@ editor.destroy();
190
217
  - `getContent()`:读取完整内容。
191
218
  - `setContent(content)`:写入内容。
192
219
  - `executeCommand(command)`:执行命令。
193
- - `requestPayloadPanel(request)`:打开参数面板请求。
194
- - `getCommandStates()`:读取命令状态。
220
+ - `requestPayloadPanel(request)`:打开参数面板请求,供自绘菜单复用。
221
+ - `getCommandStates()`:读取当前命令状态。
195
222
  - `subscribeCommandStateChange(listener)`:订阅命令状态变化。
196
223
  - `setReadonly(readonly)`:切换只读。
197
224
  - `focus()` / `blur()`:焦点控制。
@@ -199,6 +226,8 @@ editor.destroy();
199
226
 
200
227
  ## 命令 API
201
228
 
229
+ 所有菜单最终都会落到 `EditorCommand`。业务也可以直接调用命令 API。
230
+
202
231
  文本格式:
203
232
 
204
233
  ```ts
@@ -217,7 +246,7 @@ editor.executeCommand({ type: 'format.fontFamily', value: 'Arial' });
217
246
  editor.executeCommand({ type: 'format.lineHeight', value: '1.75' });
218
247
  ```
219
248
 
220
- 段落、列表和对齐:
249
+ 段落、列表、对齐:
221
250
 
222
251
  ```ts
223
252
  editor.executeCommand({ type: 'block.paragraph' });
@@ -239,7 +268,7 @@ editor.executeCommand({ type: 'indent.increase' });
239
268
  editor.executeCommand({ type: 'indent.decrease' });
240
269
  ```
241
270
 
242
- 链接、表格、媒体和历史:
271
+ 链接、表格、媒体、历史:
243
272
 
244
273
  ```ts
245
274
  editor.executeCommand({ type: 'link.set', href: 'https://example.com', text: 'Example' });
@@ -277,21 +306,23 @@ editor.executeCommand({ type: 'content.clear' });
277
306
  ```
278
307
 
279
308
  默认 toolbar 不提供图片/视频 URL 插入入口,但保留 `media.insertImage` 和
280
- `media.insertVideo` 命令。主动链接编辑也不作为默认内置入口,业务可以通过自定义菜单调用
281
- `link.set`、`link.unset` 和 `link.open`。
309
+ `media.insertVideo` 命令。主动链接编辑也不是当前默认内置重点,业务可以通过自定义菜单调用
310
+ `link.*` 命令。
282
311
 
283
- ## Toolbar Tabbar
312
+ ## Toolbar / Tabbar 菜单配置
284
313
 
285
- 内置 toolbar/tabbar 配置:
314
+ DOM toolbar/tabbar 只通过 `createRichTextToolbar()` 创建。它使用同一套菜单 schema/config,
315
+ 并通过传入的 `EditorAPI` 订阅状态、执行命令。
286
316
 
287
317
  ```ts
288
- createRichTextEditor(container, {
289
- platform: 'h5',
290
- toolbarMode: 'bottom',
318
+ const toolbar = createRichTextToolbar(toolbarContainer, {
319
+ editor,
320
+ placement: 'bottom',
291
321
  toolbarConfig: {
292
322
  toolbarKeys: [
293
323
  'bold',
294
324
  'italic',
325
+ 'underline',
295
326
  '|',
296
327
  'heading-1',
297
328
  'quote',
@@ -306,6 +337,8 @@ createRichTextEditor(container, {
306
337
  excludeKeys: ['quote']
307
338
  }
308
339
  });
340
+
341
+ toolbar.update();
309
342
  ```
310
343
 
311
344
  `toolbarConfig` 规则:
@@ -314,37 +347,27 @@ createRichTextEditor(container, {
314
347
  - `insertKeys`:在默认菜单基础上插入。
315
348
  - `excludeKeys`:隐藏默认菜单。
316
349
  - `'|'`:分割线。
350
+ - 分组项使用 `{ key, title, icon, menuKeys }`。
317
351
 
318
- 关闭内置 toolbar,自己挂载:
352
+ 独立 toolbar
319
353
 
320
354
  ```ts
321
- import { createRichTextEditor, createRichTextToolbar, defaultMenuSchema } from 'bridgerte';
322
-
323
- const editor = createRichTextEditor(editorContainer, {
324
- toolbarMode: 'none'
325
- });
326
-
327
355
  const toolbar = createRichTextToolbar(toolbarContainer, {
328
356
  editor,
329
- menuSchema: defaultMenuSchema,
330
- placement: 'bottom',
357
+ placement: 'top',
331
358
  toolbarConfig: {
332
359
  toolbarKeys: ['bold', 'italic', '|', 'undo', 'redo']
333
360
  }
334
361
  });
335
362
 
336
363
  toolbar.update();
337
- toolbar.destroy();
338
- editor.destroy();
339
364
  ```
340
365
 
341
- `placement: 'top' | 'bottom'` 只表达菜单语义和默认样式状态。toolbar DOM 放在哪里、是否吸顶或吸底,
342
- 由业务自己的布局决定。
343
-
344
366
  ## 自定义菜单、Icon 和文案
345
367
 
346
368
  ```ts
347
- import { createRichTextEditor, defaultMenuSchema, type MenuItem } from 'bridgerte';
369
+ import { createRichTextEditor, createRichTextToolbar } from 'bridgerte/dom';
370
+ import { defaultMenuSchema, type MenuItem } from 'bridgerte/native-spec';
348
371
 
349
372
  const customMenu: MenuItem = {
350
373
  id: 'custom-clear',
@@ -354,36 +377,50 @@ const customMenu: MenuItem = {
354
377
  group: 'history'
355
378
  };
356
379
 
357
- createRichTextEditor(container, {
358
- menuSchema: [...defaultMenuSchema, customMenu],
380
+ const menuSchema = [...defaultMenuSchema, customMenu];
381
+ const icons = {
382
+ 'custom-clear': '<svg aria-hidden="true" viewBox="0 0 24 24"><path d="M4 6h16"/></svg>'
383
+ };
384
+ const menuLabels = {
385
+ 'custom-clear': '清空文档',
386
+ bold: '加粗文本'
387
+ };
388
+
389
+ const editor = createRichTextEditor(editorContainer, {
390
+ menuSchema,
391
+ icons,
392
+ menuLabels
393
+ });
394
+
395
+ const toolbar = createRichTextToolbar(toolbarContainer, {
396
+ editor,
397
+ menuSchema,
359
398
  toolbarConfig: {
360
399
  insertKeys: {
361
400
  index: 0,
362
401
  keys: ['custom-clear', '|']
363
402
  }
364
403
  },
365
- icons: {
366
- 'custom-clear': '<svg aria-hidden="true" viewBox="0 0 24 24"><path d="M4 6h16"/></svg>'
367
- },
368
- menuLabels: {
369
- 'custom-clear': '清空文档',
370
- bold: '加粗文本'
371
- }
404
+ icons,
405
+ menuLabels
372
406
  });
407
+
408
+ toolbar.update();
373
409
  ```
374
410
 
375
- 稳定规则:
411
+ 稳定约束:
376
412
 
377
413
  - `MenuItem.id` 是菜单配置使用的稳定 key。
378
414
  - `MenuItem.icon` 是稳定 icon key,不是 SVG 字符串。
379
- - 替换 icon 使用 `icons` map。
380
- - 替换文案使用 `menuLabels`。
381
- - `menuLabels` 只影响展示、tooltip 和 `aria-label`,不改变命令语义。
382
- - 缺失 icon 时,DOM 菜单会使用 label 文本兜底。
415
+ - 业务覆盖 icon 只能通过 `icons` map。
416
+ - 业务覆盖文案只能通过 `menuLabels`。
417
+ - `menuLabels` 影响按钮文本、tooltip 和 `aria-label`,不改变命令语义。
418
+ - 缺失 icon 时,DOM 菜单使用 label 文本兜底。
383
419
 
384
420
  ## Hoverbar
385
421
 
386
- 选中文本 hoverbar 默认开启,复用 `menuSchema`、`icons` 和 `menuLabels`。
422
+ 选中文本 hoverbar 默认开启,复用 `menuSchema`、`icons` 和 `menuLabels`。它有独立的
423
+ `hoverbarConfig`,可以和 toolbar 展示不同菜单。
387
424
 
388
425
  ```ts
389
426
  createRichTextEditor(container, {
@@ -412,11 +449,13 @@ createRichTextEditor(container, {
412
449
  });
413
450
  ```
414
451
 
415
- 关闭后只是不显示 DOM hoverbar,不影响底层命令 API。
452
+ 关闭后只是不显示 DOM hoverbar,不影响底层命令 API。H5/WebView 或品牌化项目可以关闭内置
453
+ hoverbar 后自绘选区菜单。
416
454
 
417
455
  ## 参数面板
418
456
 
419
- 颜色、背景色、字号、字体、行高、表格和代码语言都通过参数面板描述候选项。
457
+ 颜色、背景色、字号、字体、行高、表格和代码语言都通过 `PayloadPanelSchema` 描述候选项。
458
+ DOM 默认 UI 和业务自绘 request 使用同一份 schema。
420
459
 
421
460
  ```ts
422
461
  createRichTextEditor(container, {
@@ -432,7 +471,7 @@ createRichTextEditor(container, {
432
471
  }
433
472
  }
434
473
  },
435
- 'text-color': {
474
+ color: {
436
475
  fields: {
437
476
  value: {
438
477
  options: [
@@ -442,15 +481,22 @@ createRichTextEditor(container, {
442
481
  }
443
482
  }
444
483
  },
445
- 'table-insert': {
484
+ table: {
446
485
  fields: {
447
486
  rows: { defaultValue: '2', max: 6 },
448
487
  cols: { defaultValue: '3', max: 6 }
449
488
  }
489
+ },
490
+ 'code-block-language': {
491
+ fields: {
492
+ language: {
493
+ includeValues: ['plain', 'javascript', 'typescript', 'json']
494
+ }
495
+ }
450
496
  }
451
497
  },
452
498
  onPayloadPanelRequest(request) {
453
- if (request.panel.id === 'text-color') {
499
+ if (request.panel.id === 'color') {
454
500
  renderColorPanel(request);
455
501
  return true;
456
502
  }
@@ -458,21 +504,64 @@ createRichTextEditor(container, {
458
504
  });
459
505
  ```
460
506
 
461
- `onPayloadPanelRequest` 返回 `true` 表示业务接管渲染,DOM 默认面板不会显示。业务自绘完成后调用:
507
+ 自绘接管规则:
508
+
509
+ ```ts
510
+ createRichTextEditor(container, {
511
+ onPayloadPanelRequest(request) {
512
+ renderPanel({
513
+ title: request.panel.title,
514
+ fields: request.panel.fields,
515
+ currentValues: request.currentValues,
516
+ readonly: request.readonly,
517
+ submit: request.submit,
518
+ cancel: request.cancel
519
+ });
520
+
521
+ return true;
522
+ }
523
+ });
524
+ ```
525
+
526
+ `onPayloadPanelRequest` 返回 `true` 表示业务接管渲染,DOM 默认面板不会显示。业务自绘完成后:
462
527
 
463
528
  ```ts
464
529
  request.submit({ value: '#1677ff' });
465
530
  request.cancel();
466
531
  ```
467
532
 
468
- readonly 下 request 会带 `readonly: true`,自绘层应展示只读态。
533
+ readonly 下 request 会带 `readonly: true`,自绘层应展示只读态;DOM 默认面板不会打开。
534
+
535
+ 代码块语言也可以直接传完整 schema:
536
+
537
+ ```ts
538
+ createRichTextEditor(container, {
539
+ codeBlockLanguagePanel: {
540
+ id: 'code-block-language',
541
+ title: '代码语言',
542
+ fields: [
543
+ {
544
+ type: 'select',
545
+ name: 'language',
546
+ label: '语言',
547
+ options: [
548
+ { label: '纯文本', value: 'plain' },
549
+ { label: 'TypeScript', value: 'typescript' },
550
+ { label: 'JSON', value: 'json' }
551
+ ]
552
+ }
553
+ ]
554
+ }
555
+ });
556
+ ```
469
557
 
470
558
  ## 图片、视频和上传
471
559
 
472
- BridgeRTE 不内置上传后端。图片/视频上传需要业务实现 `uploadAdapter`。
560
+ BridgeRTE 不内置上传后端。图片/视频上传必须由业务实现 `uploadAdapter`。
473
561
 
474
562
  ```ts
475
- import type { UploadAdapter } from 'bridgerte';
563
+ import { createRichTextEditor } from 'bridgerte/dom';
564
+ import type { UploadAdapter } from 'bridgerte/core';
476
565
 
477
566
  const uploadBlob = async (url: string, file: unknown, signal?: AbortSignal) => {
478
567
  const formData = new FormData();
@@ -521,7 +610,13 @@ createRichTextEditor(container, {
521
610
  ```ts
522
611
  createRichTextEditor(container, {
523
612
  mediaControlsConfig: {
524
- toolbarKeys: ['media-align-left', 'media-align-center', 'media-align-right', '|', 'media-remove']
613
+ toolbarKeys: [
614
+ 'media-align-left',
615
+ 'media-align-center',
616
+ 'media-align-right',
617
+ '|',
618
+ 'media-remove'
619
+ ]
525
620
  },
526
621
  menuLabels: {
527
622
  'media-remove': '删除媒体'
@@ -534,10 +629,12 @@ createRichTextEditor(container, {
534
629
 
535
630
  ## Mention
536
631
 
537
- `@` mention 默认开启。provider 负责返回候选数据,展示字段由 `mentionMenuConfig` 控制。
632
+ `@` mention 默认开启。`mentionProvider` 负责返回候选数据,展示字段由
633
+ `mentionMenuConfig` 控制。
538
634
 
539
635
  ```ts
540
- import type { MentionItem } from 'bridgerte';
636
+ import { createRichTextEditor } from 'bridgerte/dom';
637
+ import type { MentionItem } from 'bridgerte/core';
541
638
 
542
639
  const mentionProvider = async (query: string): Promise<MentionItem[]> => {
543
640
  const response = await fetch(`/api/members?q=${encodeURIComponent(query)}`);
@@ -603,7 +700,7 @@ createRichTextEditor(container, {
603
700
  追加动态候选:
604
701
 
605
702
  ```ts
606
- import type { SlashCommandItem } from 'bridgerte';
703
+ import type { SlashCommandItem } from 'bridgerte/core';
607
704
 
608
705
  const slashCommandProvider = async (query: string): Promise<SlashCommandItem[]> => [
609
706
  {
@@ -653,7 +750,7 @@ createRichTextEditor(container, {
653
750
 
654
751
  ## WebView
655
752
 
656
- WebView 页面内用 `createWebViewBridgeRuntime()` 接 RN/Flutter 外壳消息。
753
+ WebView 页面内使用 `createWebViewBridgeRuntime()` 接 RN/Flutter 外壳消息。
657
754
 
658
755
  ```ts
659
756
  import { createWebViewBridgeRuntime } from 'bridgerte/webview';
@@ -714,13 +811,17 @@ runtime.receive(messageFromNative);
714
811
  - `editor.heightChange`
715
812
  - `editor.error`
716
813
 
717
- 高频自动 `editor.contentChange` 只传轻量摘要。完整 `EditorContent` 通过原生侧发送
718
- `editor.requestContent` 获取,响应消息是 `editor.content`。兼容期也会同步发送旧
719
- `editor.contentChange` 完整响应。bridge 不传 File、Blob、base64 或大体积二进制文件。
814
+ 内容消息边界:
815
+
816
+ - 高频自动 `editor.contentChange` 只传轻量摘要。
817
+ - 完整 `EditorContent` 通过原生侧发送 `editor.requestContent` 获取。
818
+ - `requestContent` 的响应消息是 `editor.content`。
819
+ - 兼容期也会同步发送旧 `editor.contentChange` 完整响应。
820
+ - bridge 不传 File、Blob、base64 或大体积二进制文件。
720
821
 
721
822
  ## RN / Flutter 原生菜单
722
823
 
723
- 原生菜单可以读取 `bridgerte/native-spec`:
824
+ RN/Flutter 原生侧可以读取 `bridgerte/native-spec` 来渲染自己的菜单:
724
825
 
725
826
  ```ts
726
827
  import {
@@ -742,7 +843,7 @@ const toolbarItems = resolveToolbarMenu(defaultToolbarConfig, defaultMenuSchema)
742
843
  - `payloadPanel` 描述需要原生侧补齐的参数。
743
844
  - 命令状态可用 `isMenuItemCommandState(item, state)` 匹配。
744
845
 
745
- 原生菜单不复用 DOM CSS;WebView 内部编辑器样式通过 `--bridgerte-*` CSS Variables 覆盖。
846
+ 原生菜单不复用 DOM CSS;WebView 内编辑器样式通过 `--bridgerte-*` CSS Variables 覆盖。
746
847
 
747
848
  ## 样式和主题
748
849
 
@@ -794,6 +895,13 @@ import 'bridgerte/style.css';
794
895
  - `--bridgerte-hoverbar-button-size`
795
896
  - `--bridgerte-editor-padding`
796
897
 
898
+ PC/H5 边界:
899
+
900
+ - DOM 默认样式只服务 Web/PC/H5。
901
+ - RN/Flutter 原生菜单不复用 DOM CSS。
902
+ - H5 触屏端不依赖 hover tooltip。
903
+ - 业务可以在外层容器覆盖 CSS Variables 实现品牌主题。
904
+
797
905
  ## 性能建议
798
906
 
799
907
  BridgeRTE 按 10w 字符级内容设计输入路径:
@@ -824,7 +932,8 @@ const save = async () => {
824
932
 
825
933
  ## 当前边界
826
934
 
935
+ - 业务项目只安装 `bridgerte`,不需要安装 Lexical。
827
936
  - 默认 toolbar 不提供图片/视频 URL 插入入口;业务用命令 API 自定义入口。
828
937
  - 主动链接编辑不作为默认内置入口;业务用 `link.*` 命令自定义入口。
829
- - BridgeRTE 不内置上传后端。
938
+ - BridgeRTE 不内置上传后端,上传必须由业务实现 `uploadAdapter`。
830
939
  - WebView bridge 不传大体积二进制和 base64 文件。