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

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 +1393 -0
  30. package/ios/NativeEditorExpoView.swift +3 -3
  31. package/ios/NativeEditorModule.swift +30 -45
  32. package/ios/NativeInputSupport.swift +396 -0
  33. package/ios/PositionBridge.swift +4 -4
  34. package/ios/RichTextEditorView.swift +333 -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
@@ -439,41 +439,34 @@ function isCurrentNativeEditorEvent(event, bridge) {
439
439
  return true;
440
440
  return event.editorId === 0 || bridge?.editorId === event.editorId;
441
441
  }
442
- function computeRenderedTextLength(elements) {
443
- let len = 0;
444
- let blockCount = 0;
445
- for (const el of elements) {
446
- if (el.type === 'blockStart' && el.listContext) {
447
- len += el.listContext.kind === 'task'
448
- ? unicodeScalarCount(el.listContext.checked ? '☑ ' : '☐ ')
449
- : el.listContext.ordered
450
- ? unicodeScalarCount(`${el.listContext.index}. `)
451
- : unicodeScalarCount('• ');
452
- }
453
- else if (el.type === 'textRun' && el.text) {
454
- len += unicodeScalarCount(el.text);
455
- }
456
- else if (el.type === 'voidInline' ||
457
- el.type === 'voidBlock' ||
458
- el.type === 'opaqueInlineAtom' ||
459
- el.type === 'opaqueBlockAtom') {
460
- if (el.type === 'opaqueInlineAtom' || el.type === 'opaqueBlockAtom') {
461
- const visibleText = el.nodeType === 'mention' ? (el.label ?? '?') : `[${el.label ?? '?'}]`;
462
- len += unicodeScalarCount(visibleText);
463
- }
464
- else {
465
- // U+FFFC placeholder / hard break
466
- len += 1;
467
- }
468
- }
469
- else if (el.type === 'blockEnd') {
470
- blockCount++;
442
+ function computeRenderedTextLength(tree) {
443
+ const blockLengths = [];
444
+ collectTextSurfaceBlockLengths(tree.root, blockLengths);
445
+ if (blockLengths.length === 0)
446
+ return 0;
447
+ return blockLengths.reduce((sum, value) => sum + value, 0) + blockLengths.length - 1;
448
+ }
449
+ function collectTextSurfaceBlockLengths(node, output) {
450
+ if (node.kind === 'text') {
451
+ return unicodeScalarCount(node.text ?? '');
452
+ }
453
+ if (node.kind === 'inlineAtom' || node.kind === 'blockAtom') {
454
+ if (node.nodeType === 'mention')
455
+ return unicodeScalarCount(node.label ?? '?');
456
+ if (node.kind === 'inlineAtom' && node.nodeType !== 'hardBreak' && node.nodeType !== 'hard_break') {
457
+ return unicodeScalarCount(`[${node.label ?? '?'}]`);
471
458
  }
459
+ return 1;
472
460
  }
473
- // Block breaks add 1 scalar each, except the last block
474
- if (blockCount > 1)
475
- len += blockCount - 1;
476
- return len;
461
+ const childLength = (node.children ?? []).reduce((sum, child) => sum + collectTextSurfaceBlockLengths(child, output), 0);
462
+ if (node.kind === 'textBlock' ||
463
+ node.kind === 'listItem' ||
464
+ node.kind === 'block' ||
465
+ node.kind === 'tableCell') {
466
+ output.push(childLength);
467
+ return 0;
468
+ }
469
+ return childLength;
477
470
  }
478
471
  function serializeRemoteSelections(remoteSelections) {
479
472
  if (!remoteSelections || remoteSelections.length === 0) {
@@ -725,7 +718,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
725
718
  setActiveState(update.activeState);
726
719
  setHistoryState(update.historyState);
727
720
  selectionRef.current = update.selection;
728
- renderedTextLengthRef.current = computeRenderedTextLength(update.renderElements);
721
+ renderedTextLengthRef.current = computeRenderedTextLength(update.renderTree);
729
722
  if (typeof update.documentVersion === 'number') {
730
723
  const previousDocumentVersion = documentVersionRef.current;
731
724
  documentVersionRef.current = update.documentVersion;
@@ -2222,6 +2215,27 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
2222
2215
  insertImage(src, attrs) {
2223
2216
  insertImage(src, attrs);
2224
2217
  },
2218
+ insertColumns(options) {
2219
+ runAndApply(() => bridgeRef.current?.insertContentJson((0, schemas_1.buildColumnsFragmentJson)(options)) ?? null);
2220
+ },
2221
+ insertTable(options) {
2222
+ runAndApply(() => bridgeRef.current?.insertContentJson((0, schemas_1.buildTableFragmentJson)(options)) ?? null);
2223
+ },
2224
+ insertTableRow(after = true) {
2225
+ runAndApply(() => bridgeRef.current?.insertTableRow(after) ?? null);
2226
+ },
2227
+ deleteTableRow() {
2228
+ runAndApply(() => bridgeRef.current?.deleteTableRow() ?? null);
2229
+ },
2230
+ insertTableColumn(after = true) {
2231
+ runAndApply(() => bridgeRef.current?.insertTableColumn(after) ?? null);
2232
+ },
2233
+ deleteTableColumn() {
2234
+ runAndApply(() => bridgeRef.current?.deleteTableColumn() ?? null);
2235
+ },
2236
+ moveTableCell(forward = true) {
2237
+ runAndApply(() => bridgeRef.current?.moveTableCell(forward) ?? null);
2238
+ },
2225
2239
  insertText(text) {
2226
2240
  runAndApply(() => bridgeRef.current?.replaceSelectionText(text) ?? null);
2227
2241
  },
@@ -2520,6 +2534,30 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
2520
2534
  case 'outdentList':
2521
2535
  runAndApply(() => bridgeRef.current?.outdentListItem() ?? null);
2522
2536
  break;
2537
+ case 'insertTableRowBefore':
2538
+ runAndApply(() => bridgeRef.current?.insertTableRow(false) ?? null);
2539
+ break;
2540
+ case 'insertTableRowAfter':
2541
+ runAndApply(() => bridgeRef.current?.insertTableRow(true) ?? null);
2542
+ break;
2543
+ case 'deleteTableRow':
2544
+ runAndApply(() => bridgeRef.current?.deleteTableRow() ?? null);
2545
+ break;
2546
+ case 'insertTableColumnBefore':
2547
+ runAndApply(() => bridgeRef.current?.insertTableColumn(false) ?? null);
2548
+ break;
2549
+ case 'insertTableColumnAfter':
2550
+ runAndApply(() => bridgeRef.current?.insertTableColumn(true) ?? null);
2551
+ break;
2552
+ case 'deleteTableColumn':
2553
+ runAndApply(() => bridgeRef.current?.deleteTableColumn() ?? null);
2554
+ break;
2555
+ case 'moveToNextTableCell':
2556
+ runAndApply(() => bridgeRef.current?.moveTableCell(true) ?? null);
2557
+ break;
2558
+ case 'moveToPreviousTableCell':
2559
+ runAndApply(() => bridgeRef.current?.moveTableCell(false) ?? null);
2560
+ break;
2523
2561
  case 'undo':
2524
2562
  runAndApply(() => bridgeRef.current?.undo() ?? null);
2525
2563
  break;
package/dist/index.d.ts CHANGED
@@ -1,9 +1,9 @@
1
1
  export { NativeRichTextEditor, type NativeRichTextEditorProps, type NativeRichTextEditorRef, type NativeRichTextEditorCaretRect, type NativeRichTextEditorHeightBehavior, type NativeRichTextEditorToolbarPlacement, type NativeRichTextEditorValueJSONUpdateMode, type NativeRichTextEditorAutoCapitalize, type NativeRichTextEditorKeyboardType, type RemoteSelectionDecoration, type LinkRequestContext, type ImageRequestContext, } from './NativeRichTextEditor';
2
- export { NativeProseViewer, type NativeProseViewerProps, type NativeProseViewerAddons, type NativeProseViewerMentionsAddonConfig, type NativeProseViewerMentionPrefix, type NativeProseViewerLinkPressEvent, type NativeProseViewerMentionRenderContext, type NativeProseViewerMentionPressEvent, } from './NativeProseViewer';
2
+ export { NativeProseViewer, type NativeProseViewerProps, } from './NativeProseViewer';
3
3
  export { EditorToolbar, DEFAULT_EDITOR_TOOLBAR_ITEMS, type EditorToolbarProps, type EditorToolbarItem, type EditorToolbarLeafItem, type EditorToolbarGroupChildItem, type EditorToolbarGroupItem, type EditorToolbarGroupPresentation, type EditorToolbarIcon, type EditorToolbarDefaultIconId, type EditorToolbarSFSymbolIcon, type EditorToolbarMaterialIcon, type EditorToolbarCommand, type EditorToolbarHeadingLevel, type EditorToolbarListType, } from './EditorToolbar';
4
4
  export type { EditorContentInsets, EditorTheme, EditorTextStyle, EditorLinkTheme, EditorHeadingTheme, EditorListTheme, EditorHorizontalRuleTheme, EditorMentionTheme, EditorToolbarTheme, EditorToolbarAppearance, EditorFontStyle, EditorFontWeight, } from './EditorTheme';
5
5
  export { MENTION_NODE_NAME, mentionNodeSpec, withMentionsSchema, buildMentionFragmentJson, type EditorAddons, type MentionsAddonConfig, type MentionSuggestion, type MentionQueryChangeEvent, type MentionSelectionAttrsEvent, type MentionThemeResolveEvent, type MentionSelectEvent, type EditorAddonEvent, } from './addons';
6
- export { tiptapSchema, prosemirrorSchema, IMAGE_NODE_NAME, imageNodeSpec, withImagesSchema, buildImageFragmentJson, type SchemaDefinition, type NodeSpec, type MarkSpec, type AttrSpec, type ImageNodeAttributes, } from './schemas';
6
+ export { tiptapSchema, prosemirrorSchema, IMAGE_NODE_NAME, imageNodeSpec, withImagesSchema, buildImageFragmentJson, buildTableFragmentJson, type SchemaDefinition, type NodeSpec, type MarkSpec, type AttrSpec, type ImageNodeAttributes, type TableFragmentOptions, } from './schemas';
7
7
  export { createYjsCollaborationController, useYjsCollaboration, type YjsCollaborationOptions, type YjsCollaborationState, type YjsTransportStatus, type LocalAwarenessState, type LocalAwarenessUser, type UseYjsCollaborationResult, type YjsCollaborationController, } from './YjsCollaboration';
8
8
  export type { Selection, ActiveState, HistoryState, EditorUpdate, DocumentJSON, CollaborationPeer, EncodedCollaborationStateInput, } from './NativeEditorBridge';
9
9
  export { encodeCollaborationStateBase64, decodeCollaborationStateBase64, } from './NativeEditorBridge';
package/dist/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.clearHeightCache = exports.decodeCollaborationStateBase64 = exports.encodeCollaborationStateBase64 = exports.useYjsCollaboration = exports.createYjsCollaborationController = exports.buildImageFragmentJson = exports.withImagesSchema = exports.imageNodeSpec = exports.IMAGE_NODE_NAME = exports.prosemirrorSchema = exports.tiptapSchema = exports.buildMentionFragmentJson = exports.withMentionsSchema = exports.mentionNodeSpec = exports.MENTION_NODE_NAME = exports.DEFAULT_EDITOR_TOOLBAR_ITEMS = exports.EditorToolbar = exports.NativeProseViewer = exports.NativeRichTextEditor = void 0;
3
+ exports.clearHeightCache = exports.decodeCollaborationStateBase64 = exports.encodeCollaborationStateBase64 = exports.useYjsCollaboration = exports.createYjsCollaborationController = exports.buildTableFragmentJson = exports.buildImageFragmentJson = exports.withImagesSchema = exports.imageNodeSpec = exports.IMAGE_NODE_NAME = exports.prosemirrorSchema = exports.tiptapSchema = exports.buildMentionFragmentJson = exports.withMentionsSchema = exports.mentionNodeSpec = exports.MENTION_NODE_NAME = exports.DEFAULT_EDITOR_TOOLBAR_ITEMS = exports.EditorToolbar = exports.NativeProseViewer = exports.NativeRichTextEditor = void 0;
4
4
  var NativeRichTextEditor_1 = require("./NativeRichTextEditor");
5
5
  Object.defineProperty(exports, "NativeRichTextEditor", { enumerable: true, get: function () { return NativeRichTextEditor_1.NativeRichTextEditor; } });
6
6
  var NativeProseViewer_1 = require("./NativeProseViewer");
@@ -20,6 +20,7 @@ Object.defineProperty(exports, "IMAGE_NODE_NAME", { enumerable: true, get: funct
20
20
  Object.defineProperty(exports, "imageNodeSpec", { enumerable: true, get: function () { return schemas_1.imageNodeSpec; } });
21
21
  Object.defineProperty(exports, "withImagesSchema", { enumerable: true, get: function () { return schemas_1.withImagesSchema; } });
22
22
  Object.defineProperty(exports, "buildImageFragmentJson", { enumerable: true, get: function () { return schemas_1.buildImageFragmentJson; } });
23
+ Object.defineProperty(exports, "buildTableFragmentJson", { enumerable: true, get: function () { return schemas_1.buildTableFragmentJson; } });
23
24
  var YjsCollaboration_1 = require("./YjsCollaboration");
24
25
  Object.defineProperty(exports, "createYjsCollaborationController", { enumerable: true, get: function () { return YjsCollaboration_1.createYjsCollaborationController; } });
25
26
  Object.defineProperty(exports, "useYjsCollaboration", { enumerable: true, get: function () { return YjsCollaboration_1.useYjsCollaboration; } });
package/dist/schemas.d.ts CHANGED
@@ -8,6 +8,7 @@ export interface NodeSpec {
8
8
  group?: string;
9
9
  attrs?: Record<string, AttrSpec>;
10
10
  role: string;
11
+ layoutRole?: 'columns' | 'column' | 'table' | 'tableRow' | 'tableCell' | 'tableHeader';
11
12
  htmlTag?: string;
12
13
  isVoid?: boolean;
13
14
  }
@@ -31,6 +32,16 @@ export declare const IMAGE_NODE_NAME = "image";
31
32
  export declare function imageNodeSpec(name?: string): NodeSpec;
32
33
  export declare function withImagesSchema(schema: SchemaDefinition): SchemaDefinition;
33
34
  export declare function buildImageFragmentJson(attrs: ImageNodeAttributes): DocumentJSON;
35
+ export interface TableFragmentOptions {
36
+ rows?: number;
37
+ cols?: number;
38
+ withHeaderRow?: boolean;
39
+ }
40
+ export declare function buildTableFragmentJson({ rows, cols, withHeaderRow, }?: TableFragmentOptions): DocumentJSON;
41
+ export interface ColumnsFragmentOptions {
42
+ count?: number;
43
+ }
44
+ export declare function buildColumnsFragmentJson({ count, }?: ColumnsFragmentOptions): DocumentJSON;
34
45
  export declare const tiptapSchema: SchemaDefinition;
35
46
  export declare function defaultEmptyDocument(schema?: SchemaDefinition): DocumentJSON;
36
47
  export declare function normalizeDocumentJson(doc: DocumentJSON, schema?: SchemaDefinition): DocumentJSON;
package/dist/schemas.js CHANGED
@@ -4,6 +4,8 @@ exports.prosemirrorSchema = exports.tiptapSchema = exports.IMAGE_NODE_NAME = voi
4
4
  exports.imageNodeSpec = imageNodeSpec;
5
5
  exports.withImagesSchema = withImagesSchema;
6
6
  exports.buildImageFragmentJson = buildImageFragmentJson;
7
+ exports.buildTableFragmentJson = buildTableFragmentJson;
8
+ exports.buildColumnsFragmentJson = buildColumnsFragmentJson;
7
9
  exports.defaultEmptyDocument = defaultEmptyDocument;
8
10
  exports.normalizeDocumentJson = normalizeDocumentJson;
9
11
  exports.IMAGE_NODE_NAME = 'image';
@@ -55,6 +57,45 @@ function buildImageFragmentJson(attrs) {
55
57
  ],
56
58
  };
57
59
  }
60
+ function buildTableFragmentJson({ rows = 3, cols = 3, withHeaderRow = true, } = {}) {
61
+ const rowCount = Math.max(1, Math.floor(rows));
62
+ const colCount = Math.max(1, Math.floor(cols));
63
+ return {
64
+ type: 'doc',
65
+ content: [
66
+ {
67
+ type: 'table',
68
+ content: Array.from({ length: rowCount }, (_, rowIndex) => ({
69
+ type: 'tableRow',
70
+ content: Array.from({ length: colCount }, () => ({
71
+ type: withHeaderRow && rowIndex === 0 ? 'tableHeader' : 'tableCell',
72
+ content: [{ type: 'paragraph' }],
73
+ })),
74
+ })),
75
+ },
76
+ ],
77
+ };
78
+ }
79
+ function buildColumnsFragmentJson({ count = 2, } = {}) {
80
+ const columnCount = Math.min(Math.max(1, Math.floor(count)), 4);
81
+ return {
82
+ type: 'doc',
83
+ content: [
84
+ {
85
+ type: 'columns',
86
+ content: Array.from({ length: columnCount }, (_, index) => ({
87
+ type: 'column',
88
+ content: [
89
+ {
90
+ type: 'paragraph',
91
+ content: [{ type: 'text', text: `Column ${index + 1}` }],
92
+ },
93
+ ],
94
+ })),
95
+ },
96
+ ],
97
+ };
98
+ }
58
99
  const MARKS = [
59
100
  { name: 'bold' },
60
101
  { name: 'italic' },
@@ -122,6 +163,60 @@ exports.tiptapSchema = {
122
163
  isVoid: true,
123
164
  },
124
165
  imageNodeSpec(),
166
+ {
167
+ name: 'columns',
168
+ content: 'column+',
169
+ group: 'block',
170
+ role: 'block',
171
+ layoutRole: 'columns',
172
+ },
173
+ {
174
+ name: 'column',
175
+ content: 'block+',
176
+ role: 'block',
177
+ layoutRole: 'column',
178
+ },
179
+ {
180
+ name: 'table',
181
+ content: 'tableRow+',
182
+ group: 'block',
183
+ role: 'block',
184
+ layoutRole: 'table',
185
+ htmlTag: 'table',
186
+ },
187
+ {
188
+ name: 'tableRow',
189
+ content: '(tableCell | tableHeader)+',
190
+ role: 'block',
191
+ layoutRole: 'tableRow',
192
+ htmlTag: 'tr',
193
+ },
194
+ {
195
+ name: 'tableCell',
196
+ content: 'block+',
197
+ role: 'block',
198
+ layoutRole: 'tableCell',
199
+ attrs: {
200
+ colspan: { default: 1 },
201
+ rowspan: { default: 1 },
202
+ colwidth: { default: null },
203
+ align: { default: null },
204
+ },
205
+ htmlTag: 'td',
206
+ },
207
+ {
208
+ name: 'tableHeader',
209
+ content: 'block+',
210
+ role: 'block',
211
+ layoutRole: 'tableHeader',
212
+ attrs: {
213
+ colspan: { default: 1 },
214
+ rowspan: { default: 1 },
215
+ colwidth: { default: null },
216
+ align: { default: null },
217
+ },
218
+ htmlTag: 'th',
219
+ },
125
220
  {
126
221
  name: 'text',
127
222
  content: '',
@@ -252,6 +347,60 @@ exports.prosemirrorSchema = {
252
347
  isVoid: true,
253
348
  },
254
349
  imageNodeSpec('image'),
350
+ {
351
+ name: 'columns',
352
+ content: 'column+',
353
+ group: 'block',
354
+ role: 'block',
355
+ layoutRole: 'columns',
356
+ },
357
+ {
358
+ name: 'column',
359
+ content: 'block+',
360
+ role: 'block',
361
+ layoutRole: 'column',
362
+ },
363
+ {
364
+ name: 'table',
365
+ content: 'table_row+',
366
+ group: 'block',
367
+ role: 'block',
368
+ layoutRole: 'table',
369
+ htmlTag: 'table',
370
+ },
371
+ {
372
+ name: 'table_row',
373
+ content: '(table_cell | table_header)+',
374
+ role: 'block',
375
+ layoutRole: 'tableRow',
376
+ htmlTag: 'tr',
377
+ },
378
+ {
379
+ name: 'table_cell',
380
+ content: 'block+',
381
+ role: 'block',
382
+ layoutRole: 'tableCell',
383
+ attrs: {
384
+ colspan: { default: 1 },
385
+ rowspan: { default: 1 },
386
+ colwidth: { default: null },
387
+ align: { default: null },
388
+ },
389
+ htmlTag: 'td',
390
+ },
391
+ {
392
+ name: 'table_header',
393
+ content: 'block+',
394
+ role: 'block',
395
+ layoutRole: 'tableHeader',
396
+ attrs: {
397
+ colspan: { default: 1 },
398
+ rowspan: { default: 1 },
399
+ colwidth: { default: null },
400
+ align: { default: null },
401
+ },
402
+ htmlTag: 'th',
403
+ },
255
404
  {
256
405
  name: 'text',
257
406
  content: '',
@@ -1,4 +1,4 @@
1
- import { NativeEditorBridge, type ActiveState, type HistoryState, type RenderElement, type Selection } from './NativeEditorBridge';
1
+ import { NativeEditorBridge, type ActiveState, type HistoryState, type RenderTree, type Selection } from './NativeEditorBridge';
2
2
  export interface UseNativeEditorOptions {
3
3
  /** Maximum character length. Omit for no limit. */
4
4
  maxLength?: number;
@@ -20,8 +20,8 @@ export interface UseNativeEditorReturn {
20
20
  activeState: ActiveState;
21
21
  /** Current undo/redo availability. */
22
22
  historyState: HistoryState;
23
- /** Current render elements. */
24
- renderElements: RenderElement[];
23
+ /** Current structural render tree. */
24
+ renderTree: RenderTree | null;
25
25
  /** Toggle a mark (e.g. 'bold', 'italic', 'underline'). */
26
26
  toggleMark: (markType: string) => void;
27
27
  /** Undo the last operation. */
@@ -24,11 +24,11 @@ function useNativeEditor(options = {}) {
24
24
  const [selection, setSelection] = (0, react_1.useState)(DEFAULT_SELECTION);
25
25
  const [activeState, setActiveState] = (0, react_1.useState)(DEFAULT_ACTIVE_STATE);
26
26
  const [historyState, setHistoryState] = (0, react_1.useState)(DEFAULT_HISTORY_STATE);
27
- const [renderElements, setRenderElements] = (0, react_1.useState)([]);
27
+ const [renderTree, setRenderTree] = (0, react_1.useState)(null);
28
28
  const syncStateFromUpdate = (0, react_1.useCallback)((update) => {
29
29
  if (!update)
30
30
  return;
31
- setRenderElements(update.renderElements);
31
+ setRenderTree(update.renderTree);
32
32
  setSelection(update.selection);
33
33
  setActiveState(update.activeState);
34
34
  setHistoryState(update.historyState);
@@ -111,7 +111,7 @@ function useNativeEditor(options = {}) {
111
111
  selection,
112
112
  activeState,
113
113
  historyState,
114
- renderElements,
114
+ renderTree,
115
115
  toggleMark,
116
116
  undo,
117
117
  redo,
@@ -730,6 +730,26 @@ public func editorDeleteScalarRange(id: UInt64, scalarFrom: UInt32, scalarTo: UI
730
730
  )
731
731
  })
732
732
  }
733
+ /**
734
+ * Delete the current table column.
735
+ */
736
+ public func editorDeleteTableColumn(id: UInt64) -> String {
737
+ return try! FfiConverterString.lift(try! rustCall() {
738
+ uniffi_editor_core_fn_func_editor_delete_table_column(
739
+ FfiConverterUInt64.lower(id),$0
740
+ )
741
+ })
742
+ }
743
+ /**
744
+ * Delete the current table row.
745
+ */
746
+ public func editorDeleteTableRow(id: UInt64) -> String {
747
+ return try! FfiConverterString.lift(try! rustCall() {
748
+ uniffi_editor_core_fn_func_editor_delete_table_row(
749
+ FfiConverterUInt64.lower(id),$0
750
+ )
751
+ })
752
+ }
733
753
  /**
734
754
  * Destroy an editor instance, freeing its resources.
735
755
  */
@@ -893,6 +913,28 @@ public func editorInsertNodeAtSelectionScalar(id: UInt64, scalarAnchor: UInt32,
893
913
  )
894
914
  })
895
915
  }
916
+ /**
917
+ * Insert a table column before or after the current column.
918
+ */
919
+ public func editorInsertTableColumn(id: UInt64, after: Bool) -> String {
920
+ return try! FfiConverterString.lift(try! rustCall() {
921
+ uniffi_editor_core_fn_func_editor_insert_table_column(
922
+ FfiConverterUInt64.lower(id),
923
+ FfiConverterBool.lower(after),$0
924
+ )
925
+ })
926
+ }
927
+ /**
928
+ * Insert a table row before or after the current row.
929
+ */
930
+ public func editorInsertTableRow(id: UInt64, after: Bool) -> String {
931
+ return try! FfiConverterString.lift(try! rustCall() {
932
+ uniffi_editor_core_fn_func_editor_insert_table_row(
933
+ FfiConverterUInt64.lower(id),
934
+ FfiConverterBool.lower(after),$0
935
+ )
936
+ })
937
+ }
896
938
  /**
897
939
  * Insert text at a position. Returns an update JSON string.
898
940
  */
@@ -917,6 +959,17 @@ public func editorInsertTextScalar(id: UInt64, scalarPos: UInt32, text: String)
917
959
  )
918
960
  })
919
961
  }
962
+ /**
963
+ * Move the selection to the next or previous table cell.
964
+ */
965
+ public func editorMoveTableCell(id: UInt64, forward: Bool) -> String {
966
+ return try! FfiConverterString.lift(try! rustCall() {
967
+ uniffi_editor_core_fn_func_editor_move_table_cell(
968
+ FfiConverterUInt64.lower(id),
969
+ FfiConverterBool.lower(forward),$0
970
+ )
971
+ })
972
+ }
920
973
  /**
921
974
  * Outdent the current list item to the parent list level. Returns an update JSON string.
922
975
  */
@@ -1020,7 +1073,18 @@ public func editorScalarToDoc(id: UInt64, scalar: UInt32) -> UInt32 {
1020
1073
  })
1021
1074
  }
1022
1075
  /**
1023
- * Set the editor's content from an HTML string. Returns render elements as JSON.
1076
+ * Set a table cell selection. Anchor and head are document positions of cell nodes.
1077
+ */
1078
+ public func editorSetCellSelection(id: UInt64, anchor: UInt32, head: UInt32) {try! rustCall() {
1079
+ uniffi_editor_core_fn_func_editor_set_cell_selection(
1080
+ FfiConverterUInt64.lower(id),
1081
+ FfiConverterUInt32.lower(anchor),
1082
+ FfiConverterUInt32.lower(head),$0
1083
+ )
1084
+ }
1085
+ }
1086
+ /**
1087
+ * Set the editor's content from an HTML string. Returns an editor update JSON payload.
1024
1088
  */
1025
1089
  public func editorSetHtml(id: UInt64, html: String) -> String {
1026
1090
  return try! FfiConverterString.lift(try! rustCall() {
@@ -1067,6 +1131,16 @@ public func editorSetMarkAtSelectionScalar(id: UInt64, scalarAnchor: UInt32, sca
1067
1131
  )
1068
1132
  })
1069
1133
  }
1134
+ /**
1135
+ * Set a node selection at a selectable node's document position.
1136
+ */
1137
+ public func editorSetNodeSelection(id: UInt64, pos: UInt32) {try! rustCall() {
1138
+ uniffi_editor_core_fn_func_editor_set_node_selection(
1139
+ FfiConverterUInt64.lower(id),
1140
+ FfiConverterUInt32.lower(pos),$0
1141
+ )
1142
+ }
1143
+ }
1070
1144
  /**
1071
1145
  * Set the selection. Anchor and head are document positions.
1072
1146
  */
@@ -1349,6 +1423,12 @@ private let initializationResult: InitializationResult = {
1349
1423
  if (uniffi_editor_core_checksum_func_editor_delete_scalar_range() != 60098) {
1350
1424
  return InitializationResult.apiChecksumMismatch
1351
1425
  }
1426
+ if (uniffi_editor_core_checksum_func_editor_delete_table_column() != 12282) {
1427
+ return InitializationResult.apiChecksumMismatch
1428
+ }
1429
+ if (uniffi_editor_core_checksum_func_editor_delete_table_row() != 32001) {
1430
+ return InitializationResult.apiChecksumMismatch
1431
+ }
1352
1432
  if (uniffi_editor_core_checksum_func_editor_destroy() != 35774) {
1353
1433
  return InitializationResult.apiChecksumMismatch
1354
1434
  }
@@ -1394,12 +1474,21 @@ private let initializationResult: InitializationResult = {
1394
1474
  if (uniffi_editor_core_checksum_func_editor_insert_node_at_selection_scalar() != 32254) {
1395
1475
  return InitializationResult.apiChecksumMismatch
1396
1476
  }
1477
+ if (uniffi_editor_core_checksum_func_editor_insert_table_column() != 13873) {
1478
+ return InitializationResult.apiChecksumMismatch
1479
+ }
1480
+ if (uniffi_editor_core_checksum_func_editor_insert_table_row() != 58307) {
1481
+ return InitializationResult.apiChecksumMismatch
1482
+ }
1397
1483
  if (uniffi_editor_core_checksum_func_editor_insert_text() != 22584) {
1398
1484
  return InitializationResult.apiChecksumMismatch
1399
1485
  }
1400
1486
  if (uniffi_editor_core_checksum_func_editor_insert_text_scalar() != 30263) {
1401
1487
  return InitializationResult.apiChecksumMismatch
1402
1488
  }
1489
+ if (uniffi_editor_core_checksum_func_editor_move_table_cell() != 56610) {
1490
+ return InitializationResult.apiChecksumMismatch
1491
+ }
1403
1492
  if (uniffi_editor_core_checksum_func_editor_outdent_list_item() != 55796) {
1404
1493
  return InitializationResult.apiChecksumMismatch
1405
1494
  }
@@ -1427,7 +1516,10 @@ private let initializationResult: InitializationResult = {
1427
1516
  if (uniffi_editor_core_checksum_func_editor_scalar_to_doc() != 40126) {
1428
1517
  return InitializationResult.apiChecksumMismatch
1429
1518
  }
1430
- if (uniffi_editor_core_checksum_func_editor_set_html() != 11045) {
1519
+ if (uniffi_editor_core_checksum_func_editor_set_cell_selection() != 40422) {
1520
+ return InitializationResult.apiChecksumMismatch
1521
+ }
1522
+ if (uniffi_editor_core_checksum_func_editor_set_html() != 47581) {
1431
1523
  return InitializationResult.apiChecksumMismatch
1432
1524
  }
1433
1525
  if (uniffi_editor_core_checksum_func_editor_set_json() != 18497) {
@@ -1439,6 +1531,9 @@ private let initializationResult: InitializationResult = {
1439
1531
  if (uniffi_editor_core_checksum_func_editor_set_mark_at_selection_scalar() != 43994) {
1440
1532
  return InitializationResult.apiChecksumMismatch
1441
1533
  }
1534
+ if (uniffi_editor_core_checksum_func_editor_set_node_selection() != 61000) {
1535
+ return InitializationResult.apiChecksumMismatch
1536
+ }
1442
1537
  if (uniffi_editor_core_checksum_func_editor_set_selection() != 28236) {
1443
1538
  return InitializationResult.apiChecksumMismatch
1444
1539
  }