@openeditor/react-native-prose-editor 0.0.7 → 0.0.9

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.
Files changed (68) hide show
  1. package/android/build.gradle +35 -0
  2. package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +2 -2
  3. package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +138 -597
  4. package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +13 -3
  5. package/android/src/main/java/com/apollohg/editor/InputSnapshotSupport.kt +6 -0
  6. package/android/src/main/java/com/apollohg/editor/NativeBlockEditorSurface.kt +1086 -0
  7. package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +1 -1
  8. package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +26 -50
  9. package/android/src/main/java/com/apollohg/editor/NativeImageLoader.kt +89 -0
  10. package/android/src/main/java/com/apollohg/editor/RemoteSelectionOverlayView.kt +31 -66
  11. package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +98 -33
  12. package/dist/EditorToolbar.d.ts +1 -1
  13. package/dist/EditorToolbar.js +19 -0
  14. package/dist/NativeEditorBridge.d.ts +62 -35
  15. package/dist/NativeEditorBridge.js +122 -79
  16. package/dist/NativeProseViewer.d.ts +13 -34
  17. package/dist/NativeProseViewer.js +40 -465
  18. package/dist/NativeRichTextEditor.d.ts +10 -1
  19. package/dist/NativeRichTextEditor.js +72 -34
  20. package/dist/index.d.ts +2 -2
  21. package/dist/index.js +2 -1
  22. package/dist/schemas.d.ts +11 -0
  23. package/dist/schemas.js +149 -0
  24. package/dist/useNativeEditor.d.ts +3 -3
  25. package/dist/useNativeEditor.js +3 -3
  26. package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
  27. package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
  28. package/ios/Generated_editor_core.swift +97 -2
  29. package/ios/NativeBlockEditorSurface.swift +1445 -0
  30. package/ios/NativeEditorExpoView.swift +3 -3
  31. package/ios/NativeEditorModule.swift +31 -46
  32. package/ios/NativeInputSupport.swift +396 -0
  33. package/ios/PositionBridge.swift +4 -4
  34. package/ios/RichTextEditorView.swift +352 -786
  35. package/ios/editor_coreFFI/editor_coreFFI.h +147 -70
  36. package/package.json +1 -1
  37. package/rust/android/arm64-v8a/libeditor_core.so +0 -0
  38. package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
  39. package/rust/android/x86_64/libeditor_core.so +0 -0
  40. package/rust/bindings/kotlin/uniffi/editor_core/editor_core.kt +2087 -1399
  41. package/android/src/androidTest/AndroidManifest.xml +0 -8
  42. package/android/src/androidTest/java/com/apollohg/editor/MeasureHeightInstrumentedTest.kt +0 -53
  43. package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceCollaborationInitialSyncTest.kt +0 -241
  44. package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceImeRegressionTest.kt +0 -338
  45. package/android/src/androidTest/java/com/apollohg/editor/NativeDeviceOutsideTapTest.kt +0 -789
  46. package/android/src/androidTest/java/com/apollohg/editor/NativeDevicePerformanceTest.kt +0 -350
  47. package/android/src/androidTest/java/com/apollohg/editor/NativeEditorOutsideTapActivity.kt +0 -5
  48. package/android/src/main/java/com/apollohg/editor/NativeProseViewerExpoView.kt +0 -315
  49. package/android/src/main/java/com/apollohg/editor/RenderBridge.kt +0 -2172
  50. package/android/src/sharedTest/java/com/apollohg/editor/NativePerformanceSupport.kt +0 -482
  51. package/android/src/test/java/com/apollohg/editor/CaretGeometryTest.kt +0 -137
  52. package/android/src/test/java/com/apollohg/editor/EditorEditTextHardwareKeyTest.kt +0 -321
  53. package/android/src/test/java/com/apollohg/editor/EditorInputConnectionTest.kt +0 -4202
  54. package/android/src/test/java/com/apollohg/editor/NativeEditorExpoViewTest.kt +0 -2581
  55. package/android/src/test/java/com/apollohg/editor/NativeEditorModuleTest.kt +0 -27
  56. package/android/src/test/java/com/apollohg/editor/NativePerformanceTest.kt +0 -197
  57. package/android/src/test/java/com/apollohg/editor/NativeProseViewerExpoViewTest.kt +0 -84
  58. package/android/src/test/java/com/apollohg/editor/NativeToolbarTest.kt +0 -544
  59. package/android/src/test/java/com/apollohg/editor/PositionBridgeTest.kt +0 -461
  60. package/android/src/test/java/com/apollohg/editor/RenderBridgeTest.kt +0 -2054
  61. package/android/src/test/java/com/apollohg/editor/RichTextEditorViewTest.kt +0 -1367
  62. package/ios/EditorLayoutManager.swift +0 -774
  63. package/ios/NativeProseViewerExpoView.swift +0 -276
  64. package/ios/RenderBridge.swift +0 -1708
  65. package/ios/Tests/NativePerformanceTests.swift +0 -687
  66. package/ios/Tests/PositionBridgeTests.swift +0 -706
  67. package/ios/Tests/RenderBridgeTests.swift +0 -2236
  68. package/ios/Tests/RichTextEditorViewTests.swift +0 -6548
@@ -36,6 +36,7 @@ export interface NativeEditorModule {
36
36
  editorToggleBlockquote(editorId: number): string;
37
37
  editorToggleHeading(editorId: number, level: number): string;
38
38
  editorSetSelection(editorId: number, anchor: number, head: number): void;
39
+ editorSetCellSelection?(editorId: number, anchor: number, head: number): void;
39
40
  editorGetSelection(editorId: number): string;
40
41
  editorGetSelectionState(editorId: number): string;
41
42
  editorGetCurrentState(editorId: number): string;
@@ -61,6 +62,11 @@ export interface NativeEditorModule {
61
62
  editorUnwrapFromList(editorId: number): string;
62
63
  editorIndentListItem(editorId: number): string;
63
64
  editorOutdentListItem(editorId: number): string;
65
+ editorInsertTableRow(editorId: number, after: boolean): string;
66
+ editorDeleteTableRow(editorId: number): string;
67
+ editorInsertTableColumn(editorId: number, after: boolean): string;
68
+ editorDeleteTableColumn(editorId: number): string;
69
+ editorMoveTableCell(editorId: number, forward: boolean): string;
64
70
  editorInsertNode(editorId: number, nodeType: string): string;
65
71
  editorUndo(editorId: number): string;
66
72
  editorRedo(editorId: number): string;
@@ -68,42 +74,55 @@ export interface NativeEditorModule {
68
74
  editorCanRedo(editorId: number): boolean;
69
75
  }
70
76
  export interface Selection {
71
- type: 'text' | 'node' | 'all';
77
+ type: 'text' | 'node' | 'cell' | 'all';
72
78
  anchor?: number;
73
79
  head?: number;
74
80
  pos?: number;
81
+ anchorScalar?: number;
82
+ headScalar?: number;
83
+ posScalar?: number;
75
84
  }
76
- export interface ListContext {
77
- ordered: boolean;
78
- index: number;
79
- total: number;
80
- start: number;
81
- isFirst: boolean;
82
- isLast: boolean;
83
- kind?: string | null;
84
- checked?: boolean | null;
85
- }
86
- export interface RenderMarkWithAttrs {
85
+ export interface RenderTreeMarkWithAttrs {
87
86
  type: string;
88
87
  [key: string]: unknown;
89
88
  }
90
- export type RenderMark = string | RenderMarkWithAttrs;
91
- export interface RenderElement {
92
- type: 'textRun' | 'blockStart' | 'blockEnd' | 'voidInline' | 'voidBlock' | 'opaqueInlineAtom' | 'opaqueBlockAtom';
89
+ export type RenderTreeMark = string | RenderTreeMarkWithAttrs;
90
+ export type RenderTreeNodeKind = 'doc' | 'block' | 'textBlock' | 'list' | 'listItem' | 'columns' | 'column' | 'table' | 'tableRow' | 'tableCell' | 'text' | 'inlineAtom' | 'blockAtom' | 'inlineContainer';
91
+ export interface RenderTreeNode {
92
+ kind: RenderTreeNodeKind;
93
+ nodeType: string;
94
+ docPos: number;
95
+ docSize: number;
96
+ attrs?: Record<string, unknown>;
97
+ marks?: RenderTreeMark[];
93
98
  text?: string;
94
- marks?: RenderMark[];
95
- nodeType?: string;
96
- depth?: number;
97
- docPos?: number;
98
99
  label?: string;
99
- attrs?: Record<string, unknown>;
100
100
  mentionTheme?: EditorMentionTheme;
101
- listContext?: ListContext;
101
+ children?: RenderTreeNode[];
102
+ }
103
+ export interface RenderTree {
104
+ version: number;
105
+ root: RenderTreeNode;
102
106
  }
103
- interface RenderBlocksPatch {
107
+ export type RenderTreePatchOperation = {
108
+ type: 'updateMetadata';
109
+ path: number[];
110
+ docPos: number;
111
+ docSize: number;
112
+ } | {
113
+ type: 'replaceNode';
114
+ path: number[];
115
+ node: RenderTreeNode;
116
+ } | {
117
+ type: 'spliceChildren';
118
+ path: number[];
104
119
  startIndex: number;
105
120
  deleteCount: number;
106
- renderBlocks: RenderElement[][];
121
+ children: RenderTreeNode[];
122
+ };
123
+ export interface RenderTreePatch {
124
+ version: number;
125
+ operations: RenderTreePatchOperation[];
107
126
  }
108
127
  export interface ActiveState {
109
128
  marks: Record<string, boolean>;
@@ -118,9 +137,10 @@ export interface HistoryState {
118
137
  canRedo: boolean;
119
138
  }
120
139
  export interface EditorUpdate {
121
- renderElements: RenderElement[];
122
- renderBlocks?: RenderElement[][];
123
- renderPatch?: RenderBlocksPatch;
140
+ renderTree: RenderTree;
141
+ renderPatch?: RenderTreePatch;
142
+ /** Canonical flat IME snapshot; offsets match scalar selection fields. */
143
+ inputText: string;
124
144
  selection: Selection;
125
145
  activeState: ActiveState;
126
146
  historyState: HistoryState;
@@ -156,7 +176,8 @@ export interface CommandBlockedInfo {
156
176
  }
157
177
  export type EncodedCollaborationStateInput = Uint8Array | readonly number[] | string;
158
178
  export declare function normalizeActiveState(raw: unknown): ActiveState;
159
- export declare function parseEditorUpdateJson(json: string, previousRenderBlocks?: RenderElement[][]): EditorUpdate | null;
179
+ export declare function parseEditorUpdateJson(json: string, previousRenderTree?: RenderTree): EditorUpdate | null;
180
+ export declare function applyRenderTreePatch(tree: RenderTree, patch: RenderTreePatch): RenderTree;
160
181
  export declare function encodeCollaborationStateBase64(encodedState: EncodedCollaborationStateInput): string;
161
182
  export declare function decodeCollaborationStateBase64(base64: string): Uint8Array;
162
183
  export declare function parseCollaborationResultJson(json: string): CollaborationResult;
@@ -170,7 +191,7 @@ export declare class NativeEditorBridge {
170
191
  private _documentVersion;
171
192
  private _cachedHtml;
172
193
  private _cachedJsonString;
173
- private _renderBlocksCache;
194
+ private _renderTreeCache;
174
195
  private _lastCommandBlocked;
175
196
  private _lastCommandBlockedReason;
176
197
  private _lastCommandPreflightUpdate;
@@ -194,16 +215,16 @@ export declare class NativeEditorBridge {
194
215
  prepareForNativeCommand(): boolean;
195
216
  /** Destroy the editor instance and free native resources. */
196
217
  destroy(): void;
197
- /** Set content from HTML. Returns render elements for display. */
198
- setHtml(html: string): RenderElement[];
218
+ /** Set content from HTML. Returns the structural editor state. */
219
+ setHtml(html: string): EditorUpdate | null;
199
220
  /** Get content as HTML. */
200
221
  getHtml(): string;
201
222
  /** Get cached HTML without making a native roundtrip. */
202
223
  getCachedHtml(): string | null;
203
- /** Set content from ProseMirror JSON. Returns render elements. */
204
- setJson(doc: DocumentJSON): RenderElement[];
205
- /** Set content from a serialized ProseMirror JSON string. Returns render elements. */
206
- setJsonString(jsonString: string): RenderElement[];
224
+ /** Set content from ProseMirror JSON. Returns the structural editor state. */
225
+ setJson(doc: DocumentJSON): EditorUpdate | null;
226
+ /** Set content from a serialized ProseMirror JSON string. Returns the structural editor state. */
227
+ setJsonString(jsonString: string): EditorUpdate | null;
207
228
  /** Get content as raw ProseMirror JSON string. */
208
229
  getJsonString(): string;
209
230
  /** Get cached raw ProseMirror JSON without making a native roundtrip. */
@@ -236,6 +257,8 @@ export declare class NativeEditorBridge {
236
257
  toggleHeading(level: number): EditorUpdate | null;
237
258
  /** Set the document selection by anchor and head positions. */
238
259
  setSelection(anchor: number, head: number): void;
260
+ /** Set a table cell selection by cell document positions. */
261
+ setCellSelection(anchor: number, head: number): void;
239
262
  /** Convert a document position to a scalar position used by native text views. */
240
263
  docToScalar(docPos: number): number;
241
264
  /** Convert a native scalar position back to a document position. */
@@ -282,6 +305,11 @@ export declare class NativeEditorBridge {
282
305
  indentListItem(): EditorUpdate | null;
283
306
  /** Outdent the current list item to the parent list level. */
284
307
  outdentListItem(): EditorUpdate | null;
308
+ insertTableRow(after?: boolean): EditorUpdate | null;
309
+ deleteTableRow(): EditorUpdate | null;
310
+ insertTableColumn(after?: boolean): EditorUpdate | null;
311
+ deleteTableColumn(): EditorUpdate | null;
312
+ moveTableCell(forward?: boolean): EditorUpdate | null;
285
313
  /** Insert a void node (e.g. 'horizontalRule') at the current selection. */
286
314
  insertNode(nodeType: string): EditorUpdate | null;
287
315
  parseUpdateJson(json: string, options?: ParseUpdateOptions): EditorUpdate | null;
@@ -322,4 +350,3 @@ export declare class NativeCollaborationBridge {
322
350
  clearLocalAwareness(): CollaborationResult;
323
351
  private assertNotDestroyed;
324
352
  }
325
- export {};
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.NativeCollaborationBridge = exports.NativeEditorBridge = void 0;
4
4
  exports.normalizeActiveState = normalizeActiveState;
5
5
  exports.parseEditorUpdateJson = parseEditorUpdateJson;
6
+ exports.applyRenderTreePatch = applyRenderTreePatch;
6
7
  exports.encodeCollaborationStateBase64 = encodeCollaborationStateBase64;
7
8
  exports.decodeCollaborationStateBase64 = decodeCollaborationStateBase64;
8
9
  exports.parseCollaborationResultJson = parseCollaborationResultJson;
@@ -25,30 +26,7 @@ function normalizeActiveState(raw) {
25
26
  insertableNodes: (obj.insertableNodes ?? []),
26
27
  };
27
28
  }
28
- function parseRenderElements(json) {
29
- if (!json || json === '[]')
30
- return [];
31
- try {
32
- const parsed = JSON.parse(json);
33
- if (parsed != null &&
34
- typeof parsed === 'object' &&
35
- !Array.isArray(parsed) &&
36
- 'error' in parsed) {
37
- throw new Error(`NativeEditorBridge: ${parsed.error}`);
38
- }
39
- if (!Array.isArray(parsed)) {
40
- throw new Error(ERR_NATIVE_RESPONSE);
41
- }
42
- return parsed;
43
- }
44
- catch (e) {
45
- if (e instanceof Error && e.message.startsWith('NativeEditorBridge:')) {
46
- throw e;
47
- }
48
- throw new Error(ERR_NATIVE_RESPONSE);
49
- }
50
- }
51
- function parseEditorUpdateJson(json, previousRenderBlocks) {
29
+ function parseEditorUpdateJson(json, previousRenderTree) {
52
30
  if (!json || json === '')
53
31
  return null;
54
32
  try {
@@ -56,20 +34,21 @@ function parseEditorUpdateJson(json, previousRenderBlocks) {
56
34
  if ('error' in parsed) {
57
35
  throw new Error(`NativeEditorBridge: ${parsed.error}`);
58
36
  }
59
- const renderBlocks = Array.isArray(parsed.renderBlocks)
60
- ? parsed.renderBlocks
61
- : applyRenderBlocksPatch(previousRenderBlocks, parsed.renderPatch != null && typeof parsed.renderPatch === 'object'
62
- ? parsed.renderPatch
63
- : undefined);
64
- const renderPatch = parsed.renderPatch != null && typeof parsed.renderPatch === 'object'
65
- ? parsed.renderPatch
37
+ const renderPatch = parsed.renderPatch != null
38
+ ? parseRenderTreePatch(parsed.renderPatch)
66
39
  : undefined;
40
+ const renderTree = parsed.renderTree != null
41
+ ? parseRenderTree(parsed.renderTree)
42
+ : previousRenderTree && renderPatch
43
+ ? applyRenderTreePatch(previousRenderTree, renderPatch)
44
+ : previousRenderTree;
45
+ if (!renderTree) {
46
+ throw new Error(ERR_NATIVE_RESPONSE);
47
+ }
67
48
  return {
68
- renderElements: Array.isArray(parsed.renderElements)
69
- ? parsed.renderElements
70
- : flattenRenderBlocks(renderBlocks),
71
- renderBlocks,
49
+ renderTree,
72
50
  renderPatch,
51
+ inputText: typeof parsed.inputText === 'string' ? parsed.inputText : '',
73
52
  selection: (parsed.selection ?? { type: 'text', anchor: 0, head: 0 }),
74
53
  activeState: normalizeActiveState(parsed.activeState),
75
54
  historyState: (parsed.historyState ?? {
@@ -86,30 +65,79 @@ function parseEditorUpdateJson(json, previousRenderBlocks) {
86
65
  throw new Error(ERR_NATIVE_RESPONSE);
87
66
  }
88
67
  }
89
- function flattenRenderBlocks(renderBlocks) {
90
- if (!renderBlocks || renderBlocks.length === 0) {
91
- return [];
68
+ function parseRenderTreePatch(raw) {
69
+ if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) {
70
+ throw new Error(ERR_NATIVE_RESPONSE);
92
71
  }
93
- return renderBlocks.flat();
72
+ const candidate = raw;
73
+ if (typeof candidate.version !== 'number' || !Array.isArray(candidate.operations)) {
74
+ throw new Error(ERR_NATIVE_RESPONSE);
75
+ }
76
+ return candidate;
94
77
  }
95
- function applyRenderBlocksPatch(previousRenderBlocks, renderPatch) {
96
- if (!previousRenderBlocks || !renderPatch) {
97
- return undefined;
98
- }
99
- const { startIndex, deleteCount, renderBlocks } = renderPatch;
100
- if (!Number.isInteger(startIndex) ||
101
- !Number.isInteger(deleteCount) ||
102
- startIndex < 0 ||
103
- deleteCount < 0 ||
104
- startIndex > previousRenderBlocks.length ||
105
- startIndex + deleteCount > previousRenderBlocks.length) {
106
- return undefined;
107
- }
108
- return [
109
- ...previousRenderBlocks.slice(0, startIndex),
110
- ...renderBlocks,
111
- ...previousRenderBlocks.slice(startIndex + deleteCount),
112
- ];
78
+ function applyRenderTreePatch(tree, patch) {
79
+ let root = cloneRenderTreeNode(tree.root);
80
+ for (const operation of patch.operations) {
81
+ if (operation.type === 'replaceNode' && operation.path.length === 0) {
82
+ root = cloneRenderTreeNode(operation.node);
83
+ continue;
84
+ }
85
+ const target = resolveRenderTreeNode(root, operation.path);
86
+ if (!target)
87
+ throw new Error(ERR_NATIVE_RESPONSE);
88
+ switch (operation.type) {
89
+ case 'updateMetadata':
90
+ target.docPos = operation.docPos;
91
+ target.docSize = operation.docSize;
92
+ break;
93
+ case 'replaceNode': {
94
+ const parent = resolveRenderTreeNode(root, operation.path.slice(0, -1));
95
+ const index = operation.path[operation.path.length - 1];
96
+ if (!parent?.children || index == null || !parent.children[index]) {
97
+ throw new Error(ERR_NATIVE_RESPONSE);
98
+ }
99
+ parent.children[index] = cloneRenderTreeNode(operation.node);
100
+ break;
101
+ }
102
+ case 'spliceChildren':
103
+ target.children ?? (target.children = []);
104
+ target.children.splice(operation.startIndex, operation.deleteCount, ...operation.children.map(cloneRenderTreeNode));
105
+ break;
106
+ }
107
+ }
108
+ return { version: tree.version, root };
109
+ }
110
+ function resolveRenderTreeNode(root, path) {
111
+ let current = root;
112
+ for (const index of path) {
113
+ const child = current.children?.[index];
114
+ if (!child)
115
+ return null;
116
+ current = child;
117
+ }
118
+ return current;
119
+ }
120
+ function cloneRenderTreeNode(node) {
121
+ return {
122
+ ...node,
123
+ ...(node.attrs ? { attrs: { ...node.attrs } } : {}),
124
+ ...(node.marks ? { marks: node.marks.map((mark) => typeof mark === 'string' ? mark : { ...mark }) } : {}),
125
+ ...(node.mentionTheme ? { mentionTheme: { ...node.mentionTheme } } : {}),
126
+ ...(node.children ? { children: node.children.map(cloneRenderTreeNode) } : {}),
127
+ };
128
+ }
129
+ function parseRenderTree(raw) {
130
+ if (raw == null || typeof raw !== 'object' || Array.isArray(raw)) {
131
+ throw new Error(ERR_NATIVE_RESPONSE);
132
+ }
133
+ const candidate = raw;
134
+ if (typeof candidate.version !== 'number' ||
135
+ candidate.root == null ||
136
+ typeof candidate.root !== 'object' ||
137
+ Array.isArray(candidate.root)) {
138
+ throw new Error(ERR_NATIVE_RESPONSE);
139
+ }
140
+ return candidate;
113
141
  }
114
142
  function parseContentSnapshotJson(json) {
115
143
  try {
@@ -321,7 +349,7 @@ class NativeEditorBridge {
321
349
  this._documentVersion = 0;
322
350
  this._cachedHtml = null;
323
351
  this._cachedJsonString = null;
324
- this._renderBlocksCache = null;
352
+ this._renderTreeCache = null;
325
353
  this._lastCommandBlocked = false;
326
354
  this._lastCommandBlockedReason = null;
327
355
  this._lastCommandPreflightUpdate = null;
@@ -394,19 +422,18 @@ class NativeEditorBridge {
394
422
  if (this._destroyed)
395
423
  return;
396
424
  this._destroyed = true;
397
- this._renderBlocksCache = null;
425
+ this._renderTreeCache = null;
398
426
  this._lastCommandBlocked = false;
399
427
  this._lastCommandBlockedReason = null;
400
428
  this._lastCommandPreflightUpdate = null;
401
429
  getNativeModule().editorDestroy(this._editorId);
402
430
  }
403
- /** Set content from HTML. Returns render elements for display. */
431
+ /** Set content from HTML. Returns the structural editor state. */
404
432
  setHtml(html) {
405
433
  this.assertNotDestroyed();
406
434
  this.invalidateContentCaches();
407
- this._renderBlocksCache = null;
408
- const json = getNativeModule().editorSetHtml(this._editorId, html);
409
- return parseRenderElements(json);
435
+ getNativeModule().editorSetHtml(this._editorId, html);
436
+ return this.getCurrentState();
410
437
  }
411
438
  /** Get content as HTML. */
412
439
  getHtml() {
@@ -423,18 +450,17 @@ class NativeEditorBridge {
423
450
  this.assertNotDestroyed();
424
451
  return this._cachedHtml?.value ?? null;
425
452
  }
426
- /** Set content from ProseMirror JSON. Returns render elements. */
453
+ /** Set content from ProseMirror JSON. Returns the structural editor state. */
427
454
  setJson(doc) {
428
455
  return this.setJsonString(JSON.stringify((0, schemas_1.normalizeDocumentJson)(doc, this._schema)));
429
456
  }
430
- /** Set content from a serialized ProseMirror JSON string. Returns render elements. */
457
+ /** Set content from a serialized ProseMirror JSON string. Returns the structural editor state. */
431
458
  setJsonString(jsonString) {
432
459
  this.assertNotDestroyed();
433
460
  this.invalidateContentCaches();
434
- this._renderBlocksCache = null;
435
461
  const normalizedJsonString = normalizeDocumentJsonString(jsonString, this._schema);
436
- const json = getNativeModule().editorSetJson(this._editorId, normalizedJsonString);
437
- return parseRenderElements(json);
462
+ getNativeModule().editorSetJson(this._editorId, normalizedJsonString);
463
+ return this.getCurrentState();
438
464
  }
439
465
  /** Get content as raw ProseMirror JSON string. */
440
466
  getJsonString() {
@@ -563,6 +589,12 @@ class NativeEditorBridge {
563
589
  getNativeModule().editorSetSelection(this._editorId, anchor, head);
564
590
  this._lastSelection = { type: 'text', anchor, head };
565
591
  }
592
+ /** Set a table cell selection by cell document positions. */
593
+ setCellSelection(anchor, head) {
594
+ this.assertNotDestroyed();
595
+ getNativeModule().editorSetCellSelection?.(this._editorId, anchor, head);
596
+ this._lastSelection = { type: 'cell', anchor, head };
597
+ }
566
598
  /** Convert a document position to a scalar position used by native text views. */
567
599
  docToScalar(docPos) {
568
600
  this.assertNotDestroyed();
@@ -711,6 +743,26 @@ class NativeEditorBridge {
711
743
  : getNativeModule().editorOutdentListItem(this._editorId);
712
744
  }, { refreshSelectionAfterPreflight: true });
713
745
  }
746
+ insertTableRow(after = true) {
747
+ this.assertNotDestroyed();
748
+ return this.runPreparedCommand(() => getNativeModule().editorInsertTableRow(this._editorId, after));
749
+ }
750
+ deleteTableRow() {
751
+ this.assertNotDestroyed();
752
+ return this.runPreparedCommand(() => getNativeModule().editorDeleteTableRow(this._editorId));
753
+ }
754
+ insertTableColumn(after = true) {
755
+ this.assertNotDestroyed();
756
+ return this.runPreparedCommand(() => getNativeModule().editorInsertTableColumn(this._editorId, after));
757
+ }
758
+ deleteTableColumn() {
759
+ this.assertNotDestroyed();
760
+ return this.runPreparedCommand(() => getNativeModule().editorDeleteTableColumn(this._editorId));
761
+ }
762
+ moveTableCell(forward = true) {
763
+ this.assertNotDestroyed();
764
+ return this.runPreparedCommand(() => getNativeModule().editorMoveTableCell(this._editorId, forward));
765
+ }
714
766
  /** Insert a void node (e.g. 'horizontalRule') at the current selection. */
715
767
  insertNode(nodeType) {
716
768
  this.assertNotDestroyed();
@@ -730,9 +782,7 @@ class NativeEditorBridge {
730
782
  return;
731
783
  }
732
784
  this._lastSelection = update.selection;
733
- if (update.renderBlocks) {
734
- this._renderBlocksCache = update.renderBlocks;
735
- }
785
+ this._renderTreeCache = update.renderTree;
736
786
  if (typeof update.documentVersion !== 'number') {
737
787
  this.invalidateContentCaches();
738
788
  return;
@@ -765,17 +815,10 @@ class NativeEditorBridge {
765
815
  return false;
766
816
  }
767
817
  parseAndNoteUpdate(json, options) {
768
- let update = parseEditorUpdateJson(json, this._renderBlocksCache ?? undefined);
818
+ const update = parseEditorUpdateJson(json, this._renderTreeCache ?? undefined);
769
819
  if (this.shouldRejectUpdate(update, json, options)) {
770
820
  return null;
771
821
  }
772
- if (update?.renderPatch && !update.renderBlocks) {
773
- json = getNativeModule().editorGetCurrentState(this._editorId);
774
- update = parseEditorUpdateJson(json, this._renderBlocksCache ?? undefined);
775
- if (this.shouldRejectUpdate(update, json, options)) {
776
- return null;
777
- }
778
- }
779
822
  this.noteUpdate(update);
780
823
  if (update) {
781
824
  this._lastAcceptedUpdateJson = json;
@@ -1,53 +1,32 @@
1
1
  import React from 'react';
2
2
  import { type StyleProp, type ViewStyle } from 'react-native';
3
- import { type EditorMentionTheme, type EditorTheme } from './EditorTheme';
3
+ import type { EditorTheme } from './EditorTheme';
4
4
  import type { DocumentJSON } from './NativeEditorBridge';
5
5
  import { type SchemaDefinition } from './schemas';
6
- export interface NativeProseViewerMentionRenderContext {
7
- docPos: number;
8
- label: string;
9
- attrs: Record<string, unknown>;
10
- }
11
- export interface NativeProseViewerMentionPressEvent extends NativeProseViewerMentionRenderContext {
12
- }
13
- export interface NativeProseViewerLinkPressEvent {
14
- href: string;
15
- text: string;
16
- }
17
- type NativeProseViewerContent = DocumentJSON | string;
18
- export type NativeProseViewerMentionPrefix = string | ((mention: NativeProseViewerMentionRenderContext) => string | null | undefined);
19
- export interface NativeProseViewerMentionsAddonConfig {
20
- trigger?: string;
21
- prefix?: NativeProseViewerMentionPrefix;
22
- theme?: EditorMentionTheme;
23
- resolveTheme?: (mention: NativeProseViewerMentionRenderContext) => EditorMentionTheme | null | undefined;
24
- onPress?: (event: NativeProseViewerMentionPressEvent) => void;
25
- }
26
- export interface NativeProseViewerAddons {
27
- mentions?: NativeProseViewerMentionsAddonConfig;
28
- }
29
6
  interface NativeProseViewerBaseProps {
30
- contentRevision?: string | number;
31
- contentJSONRevision?: string | number;
7
+ revision?: string | number;
32
8
  schema?: SchemaDefinition;
33
9
  theme?: EditorTheme;
34
10
  style?: StyleProp<ViewStyle>;
35
11
  allowBase64Images?: boolean;
36
- collapseTrailingEmptyParagraphs?: boolean;
37
- enableLinkTaps?: boolean;
38
- addons?: NativeProseViewerAddons;
39
- onPressLink?: (event: NativeProseViewerLinkPressEvent) => void;
40
- contentId?: string;
41
- containerWidth?: number;
42
12
  }
43
13
  interface NativeProseViewerJsonProps extends NativeProseViewerBaseProps {
44
- contentJSON: NativeProseViewerContent;
14
+ contentJSON: DocumentJSON | string;
45
15
  contentHTML?: never;
16
+ collapseWhenEmpty?: boolean;
46
17
  }
47
18
  interface NativeProseViewerHtmlProps extends NativeProseViewerBaseProps {
48
19
  contentHTML: string;
49
20
  contentJSON?: never;
50
21
  }
51
22
  export type NativeProseViewerProps = NativeProseViewerJsonProps | NativeProseViewerHtmlProps;
52
- export declare function NativeProseViewer({ ...props }: NativeProseViewerProps): React.JSX.Element;
23
+ /**
24
+ * Read-only presentation of the canonical block-editor surface.
25
+ *
26
+ * The viewer deliberately shares the editor's document parser, render tree,
27
+ * layout surface, theme implementation, and native views. Keeping it as a
28
+ * configured editor prevents the read-only product from becoming a second
29
+ * rendering engine with subtly different schema behavior.
30
+ */
31
+ export declare function NativeProseViewer(props: NativeProseViewerProps): React.JSX.Element;
53
32
  export {};