@apollohg/react-native-prose-editor 0.5.19 → 0.5.21
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 +23 -1
- package/android/build.gradle +5 -6
- package/android/src/main/java/com/apollohg/editor/CaretGeometry.kt +50 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditText.kt +187 -16
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +543 -74
- package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +14 -0
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +10 -2
- package/app.plugin.js +62 -0
- package/dist/EditorToolbar.d.ts +3 -2
- package/dist/EditorToolbar.js +41 -13
- package/dist/NativeRichTextEditor.d.ts +9 -0
- package/dist/NativeRichTextEditor.js +252 -81
- package/dist/YjsCollaboration.d.ts +5 -0
- package/dist/YjsCollaboration.js +44 -8
- package/dist/index.d.ts +1 -1
- package/ios/EditorCore.xcframework/Info.plist +5 -5
- package/ios/EditorCore.xcframework/ios-arm64/libeditor_core.a +0 -0
- package/ios/EditorCore.xcframework/ios-arm64_x86_64-simulator/libeditor_core.a +0 -0
- package/ios/NativeEditorExpoView.swift +49 -2
- package/package.json +5 -2
- package/rust/android/arm64-v8a/libeditor_core.so +0 -0
- package/rust/android/armeabi-v7a/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
|
@@ -64,6 +64,25 @@ function isImageDataUrl(value) {
|
|
|
64
64
|
function isRetryableNativeCommandBlock(reason) {
|
|
65
65
|
return reason === 'composition' || (react_native_1.Platform.OS === 'android' && reason === 'pendingUpdate');
|
|
66
66
|
}
|
|
67
|
+
function restoreSelectionInBridge(bridge, selection) {
|
|
68
|
+
if (selection.type === 'text') {
|
|
69
|
+
const { anchor, head } = selection;
|
|
70
|
+
if (anchor == null || head == null) {
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
bridge.setSelection(anchor, head);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (selection.type === 'node') {
|
|
77
|
+
const { pos } = selection;
|
|
78
|
+
if (pos == null) {
|
|
79
|
+
return false;
|
|
80
|
+
}
|
|
81
|
+
bridge.setSelection(pos, pos);
|
|
82
|
+
return true;
|
|
83
|
+
}
|
|
84
|
+
return false;
|
|
85
|
+
}
|
|
67
86
|
function isPromiseLike(value) {
|
|
68
87
|
return (value != null &&
|
|
69
88
|
typeof value === 'object' &&
|
|
@@ -543,23 +562,35 @@ function doesLiveMentionQueryConflictWithNativeSelectRequest(request, currentQue
|
|
|
543
562
|
currentQuery.range.anchor !== request.range.anchor ||
|
|
544
563
|
currentQuery.range.head !== request.range.head);
|
|
545
564
|
}
|
|
546
|
-
exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEditor({ initialContent, initialJSON, value, valueJSON, valueJSONRevision, schema, placeholder, editable = true, maxLength, autoFocus = false, autoCapitalize, autoCorrect, keyboardType, heightBehavior = 'autoGrow', showToolbar = true, toolbarPlacement = 'keyboard', toolbarItems = EditorToolbar_1.DEFAULT_EDITOR_TOOLBAR_ITEMS, onToolbarAction, onRequestLink, onRequestImage, autoDetectLinks = false, onContentChange, onContentChangeJSON, onSelectionChange, onActiveStateChange, onHistoryStateChange, onFocus, onBlur, style, containerStyle, theme, addons, remoteSelections, allowBase64Images = false, allowImageResizing = true, }, ref) {
|
|
565
|
+
exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEditor({ initialContent, initialJSON, value, valueJSON, valueJSONRevision, valueJSONUpdateMode = 'replace', preserveSelectionOnValueJSONReset = false, selectionOnValueJSONReset, schema, placeholder, editable = true, maxLength, autoFocus = false, autoCapitalize, autoCorrect, keyboardType, heightBehavior = 'autoGrow', showToolbar = true, toolbarPlacement = 'keyboard', toolbarItems = EditorToolbar_1.DEFAULT_EDITOR_TOOLBAR_ITEMS, onToolbarAction, onRequestLink, onRequestImage, autoDetectLinks = false, onContentChange, onContentChangeJSON, onSelectionChange, onActiveStateChange, onHistoryStateChange, onFocus, onBlur, style, containerStyle, theme, addons, remoteSelections, allowBase64Images = false, allowImageResizing = true, }, ref) {
|
|
547
566
|
const bridgeRef = (0, react_1.useRef)(null);
|
|
548
567
|
const nativeViewRef = (0, react_1.useRef)(null);
|
|
549
568
|
const [isReady, setIsReady] = (0, react_1.useState)(false);
|
|
550
569
|
const [editorInstanceId, setEditorInstanceId] = (0, react_1.useState)(0);
|
|
570
|
+
const editorInstanceIdRef = (0, react_1.useRef)(0);
|
|
571
|
+
editorInstanceIdRef.current = editorInstanceId;
|
|
551
572
|
const [isFocused, setIsFocused] = (0, react_1.useState)(false);
|
|
552
573
|
const isFocusedRef = (0, react_1.useRef)(false);
|
|
553
574
|
const [inlineToolbarFrame, setInlineToolbarFrame] = (0, react_1.useState)(null);
|
|
554
|
-
const registeredToolbarFrames = (0, EditorToolbar_1.useEditorToolbarFrames)();
|
|
575
|
+
const registeredToolbarFrames = (0, EditorToolbar_1.useEditorToolbarFrames)(editorInstanceId);
|
|
555
576
|
const [pendingNativeUpdate, setPendingNativeUpdate] = (0, react_1.useState)({
|
|
556
577
|
json: undefined,
|
|
557
578
|
editorId: undefined,
|
|
558
579
|
revision: 0,
|
|
559
580
|
});
|
|
560
|
-
const
|
|
561
|
-
|
|
581
|
+
const [pendingNativeResetUpdate, setPendingNativeResetUpdate] = (0, react_1.useState)({
|
|
582
|
+
json: undefined,
|
|
583
|
+
editorId: undefined,
|
|
584
|
+
revision: 0,
|
|
585
|
+
});
|
|
562
586
|
const pendingNativeUpdateInFlightRef = (0, react_1.useRef)(null);
|
|
587
|
+
const pendingNativeResetUpdateInFlightRef = (0, react_1.useRef)(null);
|
|
588
|
+
const nativeUpdateRevisionRef = (0, react_1.useRef)(0);
|
|
589
|
+
const nextNativeUpdateRevision = (0, react_1.useCallback)(() => {
|
|
590
|
+
const revision = nativeUpdateRevisionRef.current + 1;
|
|
591
|
+
nativeUpdateRevisionRef.current = revision;
|
|
592
|
+
return revision;
|
|
593
|
+
}, []);
|
|
563
594
|
const [blockedNativeCommandRetry, setBlockedNativeCommandRetry] = (0, react_1.useState)(0);
|
|
564
595
|
const [detachedControlledSyncRetry, setDetachedControlledSyncRetry] = (0, react_1.useState)(0);
|
|
565
596
|
const [controlledNativeUpdateRetry, setControlledNativeUpdateRetry] = (0, react_1.useState)(0);
|
|
@@ -753,19 +784,26 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
753
784
|
if (inFlight != null && inFlight.editorId === editorId) {
|
|
754
785
|
pendingNativeUpdateInFlightRef.current = null;
|
|
755
786
|
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
787
|
+
const next = {
|
|
788
|
+
json: undefined,
|
|
789
|
+
editorId,
|
|
790
|
+
revision: nextNativeUpdateRevision(),
|
|
791
|
+
};
|
|
792
|
+
setPendingNativeUpdate(next);
|
|
793
|
+
}, [nextNativeUpdateRevision]);
|
|
794
|
+
const queuePendingNativeResetUpdate = (0, react_1.useCallback)((updateJson) => {
|
|
795
|
+
if (react_native_1.Platform.OS !== 'android')
|
|
796
|
+
return;
|
|
797
|
+
const editorId = bridgeRef.current?.editorId;
|
|
798
|
+
const revision = nextNativeUpdateRevision();
|
|
799
|
+
const next = {
|
|
800
|
+
json: updateJson,
|
|
801
|
+
editorId,
|
|
802
|
+
revision,
|
|
803
|
+
};
|
|
804
|
+
pendingNativeResetUpdateInFlightRef.current = { editorId, revision };
|
|
805
|
+
setPendingNativeResetUpdate(next);
|
|
806
|
+
}, [nextNativeUpdateRevision]);
|
|
769
807
|
const consumeBlockedCommandInfoForRetry = (0, react_1.useCallback)((bridge) => {
|
|
770
808
|
const blockedInfo = bridge.consumeLastCommandBlockedInfo();
|
|
771
809
|
if (!blockedInfo.blocked)
|
|
@@ -819,17 +857,14 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
819
857
|
const updateJson = JSON.stringify(update);
|
|
820
858
|
if (react_native_1.Platform.OS === 'android') {
|
|
821
859
|
const editorId = bridgeRef.current?.editorId;
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
pendingNativeUpdateInFlightRef.current = { editorId, revision };
|
|
831
|
-
return next;
|
|
832
|
-
});
|
|
860
|
+
const revision = nextNativeUpdateRevision();
|
|
861
|
+
const next = {
|
|
862
|
+
json: updateJson,
|
|
863
|
+
editorId,
|
|
864
|
+
revision,
|
|
865
|
+
};
|
|
866
|
+
pendingNativeUpdateInFlightRef.current = { editorId, revision };
|
|
867
|
+
setPendingNativeUpdate(next);
|
|
833
868
|
}
|
|
834
869
|
else {
|
|
835
870
|
try {
|
|
@@ -853,7 +888,35 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
853
888
|
}
|
|
854
889
|
}
|
|
855
890
|
return true;
|
|
856
|
-
}, []);
|
|
891
|
+
}, [nextNativeUpdateRevision]);
|
|
892
|
+
const applyResetUpdateToNativeView = (0, react_1.useCallback)((update, previousDocumentVersion) => {
|
|
893
|
+
const updateJson = JSON.stringify(update);
|
|
894
|
+
if (react_native_1.Platform.OS === 'android') {
|
|
895
|
+
clearPendingNativeUpdateForCurrentEditor();
|
|
896
|
+
queuePendingNativeResetUpdate(updateJson);
|
|
897
|
+
const applyResetUpdate = nativeViewRef.current?.applyEditorResetUpdate;
|
|
898
|
+
if (applyResetUpdate) {
|
|
899
|
+
try {
|
|
900
|
+
const applyResult = applyResetUpdate(updateJson);
|
|
901
|
+
if (isPromiseLike(applyResult)) {
|
|
902
|
+
void applyResult.catch(() => {
|
|
903
|
+
// The native view may already be torn down during navigation.
|
|
904
|
+
});
|
|
905
|
+
}
|
|
906
|
+
return;
|
|
907
|
+
}
|
|
908
|
+
catch {
|
|
909
|
+
// Fall through to the regular prop-based apply path.
|
|
910
|
+
}
|
|
911
|
+
}
|
|
912
|
+
return;
|
|
913
|
+
}
|
|
914
|
+
applyUpdateToNativeView(update, previousDocumentVersion);
|
|
915
|
+
}, [
|
|
916
|
+
applyUpdateToNativeView,
|
|
917
|
+
clearPendingNativeUpdateForCurrentEditor,
|
|
918
|
+
queuePendingNativeResetUpdate,
|
|
919
|
+
]);
|
|
857
920
|
const maybeApplyAutoDetectedLink = (0, react_1.useCallback)((update, previousDocumentVersion) => {
|
|
858
921
|
const applyAutoLink = (candidateUpdate, allowPreflightRetry) => {
|
|
859
922
|
if (!autoDetectLinks ||
|
|
@@ -916,10 +979,10 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
916
979
|
syncStateFromUpdate(update);
|
|
917
980
|
onActiveStateChangeRef.current?.(update.activeState);
|
|
918
981
|
onHistoryStateChangeRef.current?.(update.historyState);
|
|
982
|
+
onSelectionChangeRef.current?.(update.selection);
|
|
919
983
|
if (!options?.suppressContentCallbacks) {
|
|
920
984
|
emitContentCallbacksForUpdate(update, previousDocumentVersion);
|
|
921
985
|
}
|
|
922
|
-
onSelectionChangeRef.current?.(update.selection);
|
|
923
986
|
return update;
|
|
924
987
|
}, [
|
|
925
988
|
applyUpdateToNativeView,
|
|
@@ -982,10 +1045,10 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
982
1045
|
syncStateFromUpdate(update);
|
|
983
1046
|
onActiveStateChangeRef.current?.(update.activeState);
|
|
984
1047
|
onHistoryStateChangeRef.current?.(update.historyState);
|
|
1048
|
+
onSelectionChangeRef.current?.(update.selection);
|
|
985
1049
|
if (!options?.suppressContentCallbacks) {
|
|
986
1050
|
emitContentCallbacksForUpdate(update, previousDocumentVersion);
|
|
987
1051
|
}
|
|
988
|
-
onSelectionChangeRef.current?.(update.selection);
|
|
989
1052
|
return update;
|
|
990
1053
|
}, [
|
|
991
1054
|
applyUpdateToNativeView,
|
|
@@ -1014,6 +1077,40 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1014
1077
|
return (options?.skipWhenContentChanged !== true ||
|
|
1015
1078
|
!didContentChange(previousDocumentVersion, preflightUpdate));
|
|
1016
1079
|
}, [consumeBlockedCommandForRetry, syncNativeUpdateFromBridge]);
|
|
1080
|
+
const resetContentJsonString = (0, react_1.useCallback)((jsonString, options) => {
|
|
1081
|
+
const bridge = bridgeRef.current;
|
|
1082
|
+
if (!bridge || bridge.isDestroyed)
|
|
1083
|
+
return null;
|
|
1084
|
+
const previousDocumentVersion = documentVersionRef.current;
|
|
1085
|
+
const preservedSelection = options?.preserveLiveTextSelection === true
|
|
1086
|
+
? (options.selection ?? selectionRef.current)
|
|
1087
|
+
: null;
|
|
1088
|
+
bridge.setJsonString(jsonString);
|
|
1089
|
+
const update = bridge.getCurrentState();
|
|
1090
|
+
if (!update)
|
|
1091
|
+
return null;
|
|
1092
|
+
if (preservedSelection != null &&
|
|
1093
|
+
restoreSelectionInBridge(bridge, preservedSelection)) {
|
|
1094
|
+
const selectionState = bridge.getSelectionState();
|
|
1095
|
+
if (selectionState) {
|
|
1096
|
+
update.selection = selectionState.selection;
|
|
1097
|
+
update.activeState = selectionState.activeState;
|
|
1098
|
+
update.historyState = selectionState.historyState;
|
|
1099
|
+
if (typeof selectionState.documentVersion === 'number') {
|
|
1100
|
+
update.documentVersion = selectionState.documentVersion;
|
|
1101
|
+
}
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
applyResetUpdateToNativeView(update, previousDocumentVersion);
|
|
1105
|
+
syncStateFromUpdate(update);
|
|
1106
|
+
onActiveStateChangeRef.current?.(update.activeState);
|
|
1107
|
+
onHistoryStateChangeRef.current?.(update.historyState);
|
|
1108
|
+
onSelectionChangeRef.current?.(update.selection);
|
|
1109
|
+
if (!options?.suppressContentCallbacks) {
|
|
1110
|
+
emitContentCallbacksForUpdate(update, previousDocumentVersion);
|
|
1111
|
+
}
|
|
1112
|
+
return update;
|
|
1113
|
+
}, [applyResetUpdateToNativeView, emitContentCallbacksForUpdate, syncStateFromUpdate]);
|
|
1017
1114
|
const syncPreflightUpdateFromNativeEvent = (0, react_1.useCallback)((updateJson) => {
|
|
1018
1115
|
if (typeof updateJson !== 'string' || updateJson.length === 0) {
|
|
1019
1116
|
return true;
|
|
@@ -1104,6 +1201,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1104
1201
|
bridgeRef.current = null;
|
|
1105
1202
|
}
|
|
1106
1203
|
pendingNativeUpdateInFlightRef.current = null;
|
|
1204
|
+
pendingNativeResetUpdateInFlightRef.current = null;
|
|
1107
1205
|
pendingDetachedControlledSyncRef.current = false;
|
|
1108
1206
|
pendingControlledSyncAfterNativeUpdateRef.current = false;
|
|
1109
1207
|
pendingBlockedNativeCommandRetryRef.current = false;
|
|
@@ -1113,15 +1211,18 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1113
1211
|
mentionQueryEditorIdRef.current = null;
|
|
1114
1212
|
clearBlockedNativeCommandRetryTimer();
|
|
1115
1213
|
setMentionQueryEvent(null);
|
|
1116
|
-
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1214
|
+
const clearedNativeUpdate = {
|
|
1215
|
+
json: undefined,
|
|
1216
|
+
editorId: undefined,
|
|
1217
|
+
revision: nextNativeUpdateRevision(),
|
|
1218
|
+
};
|
|
1219
|
+
setPendingNativeUpdate(clearedNativeUpdate);
|
|
1220
|
+
const clearedNativeResetUpdate = {
|
|
1221
|
+
json: undefined,
|
|
1222
|
+
editorId: undefined,
|
|
1223
|
+
revision: nextNativeUpdateRevision(),
|
|
1224
|
+
};
|
|
1225
|
+
setPendingNativeResetUpdate(clearedNativeResetUpdate);
|
|
1125
1226
|
setEditorInstanceId(0);
|
|
1126
1227
|
setIsReady(false);
|
|
1127
1228
|
};
|
|
@@ -1132,6 +1233,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1132
1233
|
allowBase64Images,
|
|
1133
1234
|
serializedSchemaJson,
|
|
1134
1235
|
clearBlockedNativeCommandRetryTimer,
|
|
1236
|
+
nextNativeUpdateRevision,
|
|
1135
1237
|
]);
|
|
1136
1238
|
(0, react_1.useEffect)(() => {
|
|
1137
1239
|
if (value == null)
|
|
@@ -1203,6 +1305,27 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1203
1305
|
const didControlledValueChange = previousSync.value !== serializedValueJson;
|
|
1204
1306
|
const didDocumentAdvanceForSameValue = !didControlledValueChange &&
|
|
1205
1307
|
previousSync.documentVersion !== documentVersionRef.current;
|
|
1308
|
+
if (valueJSONUpdateMode === 'reset') {
|
|
1309
|
+
const currentJson = bridgeRef.current.getJsonString();
|
|
1310
|
+
if (currentJson === serializedValueJson) {
|
|
1311
|
+
clearPendingNativeUpdateForCurrentEditor();
|
|
1312
|
+
controlledJsonSyncRef.current = {
|
|
1313
|
+
value: serializedValueJson,
|
|
1314
|
+
documentVersion: documentVersionRef.current,
|
|
1315
|
+
};
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
resetContentJsonString(serializedValueJson, {
|
|
1319
|
+
suppressContentCallbacks: true,
|
|
1320
|
+
preserveLiveTextSelection: preserveSelectionOnValueJSONReset,
|
|
1321
|
+
selection: selectionOnValueJSONReset,
|
|
1322
|
+
});
|
|
1323
|
+
controlledJsonSyncRef.current = {
|
|
1324
|
+
value: serializedValueJson,
|
|
1325
|
+
documentVersion: documentVersionRef.current,
|
|
1326
|
+
};
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1206
1329
|
if (!prepareBridgeForExternalContentRead({
|
|
1207
1330
|
skipWhenContentChanged: !didControlledValueChange,
|
|
1208
1331
|
})) {
|
|
@@ -1248,6 +1371,9 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1248
1371
|
}, [
|
|
1249
1372
|
serializedValueJson,
|
|
1250
1373
|
value,
|
|
1374
|
+
valueJSONUpdateMode,
|
|
1375
|
+
preserveSelectionOnValueJSONReset,
|
|
1376
|
+
selectionOnValueJSONReset,
|
|
1251
1377
|
runAndApply,
|
|
1252
1378
|
blockedNativeCommandRetry,
|
|
1253
1379
|
controlledNativeUpdateRetry,
|
|
@@ -1255,6 +1381,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1255
1381
|
prepareBridgeForExternalContentRead,
|
|
1256
1382
|
clearPendingNativeUpdateForCurrentEditor,
|
|
1257
1383
|
hasPendingNativeUpdateInFlightForCurrentEditor,
|
|
1384
|
+
resetContentJsonString,
|
|
1258
1385
|
]);
|
|
1259
1386
|
const updateToolbarFrame = (0, react_1.useCallback)(() => {
|
|
1260
1387
|
const toolbar = toolbarRef.current;
|
|
@@ -1384,29 +1511,13 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1384
1511
|
}
|
|
1385
1512
|
onSelectionChangeRef.current?.(nextSelection);
|
|
1386
1513
|
}, [syncSelectionStateFromUpdate]);
|
|
1387
|
-
const refocusAfterToolbarInteraction = (0, react_1.useCallback)(() => {
|
|
1388
|
-
nativeViewRef.current?.focus?.();
|
|
1389
|
-
requestAnimationFrame(() => {
|
|
1390
|
-
nativeViewRef.current?.focus?.();
|
|
1391
|
-
});
|
|
1392
|
-
setTimeout(() => {
|
|
1393
|
-
nativeViewRef.current?.focus?.();
|
|
1394
|
-
}, 50);
|
|
1395
|
-
}, []);
|
|
1396
1514
|
const handleFocusChange = (0, react_1.useCallback)((event) => {
|
|
1397
1515
|
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridgeRef.current))
|
|
1398
1516
|
return;
|
|
1399
1517
|
const { isFocused: focused } = event.nativeEvent;
|
|
1400
|
-
if (!focused &&
|
|
1401
|
-
editable &&
|
|
1402
|
-
isFocusedRef.current &&
|
|
1403
|
-
(0, EditorToolbar_1.isEditorToolbarFocusPreservationActive)()) {
|
|
1404
|
-
setIsFocused(true);
|
|
1405
|
-
refocusAfterToolbarInteraction();
|
|
1406
|
-
return;
|
|
1407
|
-
}
|
|
1408
1518
|
const wasFocused = isFocusedRef.current;
|
|
1409
1519
|
isFocusedRef.current = focused;
|
|
1520
|
+
(0, EditorToolbar_1.setActiveEditorToolbarFrameOwnerForEditor)(editorInstanceIdRef.current, focused);
|
|
1410
1521
|
setIsFocused(focused);
|
|
1411
1522
|
if (!focused) {
|
|
1412
1523
|
setMentionQueryEventState(null);
|
|
@@ -1419,7 +1530,10 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1419
1530
|
else if (wasFocused) {
|
|
1420
1531
|
onBlurRef.current?.();
|
|
1421
1532
|
}
|
|
1422
|
-
}, [
|
|
1533
|
+
}, [setMentionQueryEventState]);
|
|
1534
|
+
(0, react_1.useEffect)(() => () => {
|
|
1535
|
+
(0, EditorToolbar_1.setActiveEditorToolbarFrameOwnerForEditor)(editorInstanceId, false);
|
|
1536
|
+
}, [editorInstanceId]);
|
|
1423
1537
|
(0, react_1.useEffect)(() => {
|
|
1424
1538
|
if (addons?.mentions != null) {
|
|
1425
1539
|
return;
|
|
@@ -1443,30 +1557,57 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1443
1557
|
const editorId = bridgeRef.current?.editorId;
|
|
1444
1558
|
const acknowledgedRevision = event.nativeEvent.editorUpdateRevision;
|
|
1445
1559
|
const inFlight = pendingNativeUpdateInFlightRef.current;
|
|
1560
|
+
const resetInFlight = pendingNativeResetUpdateInFlightRef.current;
|
|
1446
1561
|
let didClearInFlight = false;
|
|
1562
|
+
let didMatchInFlight = false;
|
|
1447
1563
|
if (inFlight != null) {
|
|
1448
1564
|
const matchesRevision = typeof acknowledgedRevision === 'number' &&
|
|
1449
1565
|
inFlight.editorId === editorId &&
|
|
1450
1566
|
inFlight.revision === acknowledgedRevision;
|
|
1451
|
-
if (
|
|
1452
|
-
|
|
1567
|
+
if (matchesRevision) {
|
|
1568
|
+
didMatchInFlight = true;
|
|
1569
|
+
pendingNativeUpdateInFlightRef.current = null;
|
|
1570
|
+
didClearInFlight = true;
|
|
1571
|
+
setPendingNativeUpdate((current) => {
|
|
1572
|
+
if (current.editorId !== editorId ||
|
|
1573
|
+
current.revision !== acknowledgedRevision ||
|
|
1574
|
+
current.json == null) {
|
|
1575
|
+
return current;
|
|
1576
|
+
}
|
|
1577
|
+
const next = {
|
|
1578
|
+
json: undefined,
|
|
1579
|
+
editorId,
|
|
1580
|
+
revision: current.revision,
|
|
1581
|
+
};
|
|
1582
|
+
return next;
|
|
1583
|
+
});
|
|
1453
1584
|
}
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
editorId
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1585
|
+
}
|
|
1586
|
+
if (resetInFlight != null) {
|
|
1587
|
+
const matchesRevision = typeof acknowledgedRevision === 'number' &&
|
|
1588
|
+
resetInFlight.editorId === editorId &&
|
|
1589
|
+
resetInFlight.revision === acknowledgedRevision;
|
|
1590
|
+
if (matchesRevision) {
|
|
1591
|
+
didMatchInFlight = true;
|
|
1592
|
+
pendingNativeResetUpdateInFlightRef.current = null;
|
|
1593
|
+
didClearInFlight = true;
|
|
1594
|
+
setPendingNativeResetUpdate((current) => {
|
|
1595
|
+
if (current.editorId !== editorId ||
|
|
1596
|
+
current.revision !== acknowledgedRevision ||
|
|
1597
|
+
current.json == null) {
|
|
1598
|
+
return current;
|
|
1599
|
+
}
|
|
1600
|
+
const next = {
|
|
1601
|
+
json: undefined,
|
|
1602
|
+
editorId,
|
|
1603
|
+
revision: current.revision,
|
|
1604
|
+
};
|
|
1605
|
+
return next;
|
|
1606
|
+
});
|
|
1607
|
+
}
|
|
1608
|
+
}
|
|
1609
|
+
if ((inFlight != null || resetInFlight != null) && !didMatchInFlight) {
|
|
1610
|
+
return;
|
|
1470
1611
|
}
|
|
1471
1612
|
flushBlockedNativeCommandRetry();
|
|
1472
1613
|
if (didClearInFlight && pendingControlledSyncAfterNativeUpdateRef.current) {
|
|
@@ -1623,6 +1764,24 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1623
1764
|
}
|
|
1624
1765
|
return { update, queued: didQueueRetry };
|
|
1625
1766
|
}, [isCommandRetryScopeCurrent, runAndApply]);
|
|
1767
|
+
const runPersistentContentCommand = (0, react_1.useCallback)((mutate, options) => {
|
|
1768
|
+
const requestedEditorId = bridgeRef.current?.editorId;
|
|
1769
|
+
let run = null;
|
|
1770
|
+
const retry = () => {
|
|
1771
|
+
const bridge = bridgeRef.current;
|
|
1772
|
+
if (bridge == null ||
|
|
1773
|
+
bridge.isDestroyed ||
|
|
1774
|
+
bridge.editorId !== requestedEditorId) {
|
|
1775
|
+
return false;
|
|
1776
|
+
}
|
|
1777
|
+
return run?.() != null;
|
|
1778
|
+
};
|
|
1779
|
+
run = () => runAndApply(mutate, {
|
|
1780
|
+
...options,
|
|
1781
|
+
retryBlockedCommand: retry,
|
|
1782
|
+
});
|
|
1783
|
+
return run();
|
|
1784
|
+
}, [runAndApply]);
|
|
1626
1785
|
const insertImage = (0, react_1.useCallback)((src, attrs, selection) => {
|
|
1627
1786
|
const trimmedSrc = src.trim();
|
|
1628
1787
|
if (!trimmedSrc)
|
|
@@ -2069,10 +2228,15 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
2069
2228
|
runAndApply(() => bridgeRef.current?.insertContentJson(doc) ?? null);
|
|
2070
2229
|
},
|
|
2071
2230
|
setContent(html) {
|
|
2072
|
-
|
|
2231
|
+
runPersistentContentCommand(() => bridgeRef.current?.replaceHtml(html) ?? null);
|
|
2073
2232
|
},
|
|
2074
2233
|
setContentJson(doc) {
|
|
2075
|
-
|
|
2234
|
+
const jsonString = stringifyCachedJson((0, schemas_1.normalizeDocumentJson)(doc, documentSchema));
|
|
2235
|
+
runPersistentContentCommand(() => bridgeRef.current?.replaceJsonString(jsonString) ?? null);
|
|
2236
|
+
},
|
|
2237
|
+
clearContent() {
|
|
2238
|
+
const jsonString = stringifyCachedJson((0, schemas_1.normalizeDocumentJson)({ type: 'doc', content: [] }, documentSchema));
|
|
2239
|
+
resetContentJsonString(jsonString);
|
|
2076
2240
|
},
|
|
2077
2241
|
getContent() {
|
|
2078
2242
|
if (!bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
@@ -2121,7 +2285,14 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
2121
2285
|
return false;
|
|
2122
2286
|
return bridgeRef.current.canRedo();
|
|
2123
2287
|
},
|
|
2124
|
-
}), [
|
|
2288
|
+
}), [
|
|
2289
|
+
documentSchema,
|
|
2290
|
+
insertImage,
|
|
2291
|
+
prepareBridgeForExternalContentRead,
|
|
2292
|
+
runAndApply,
|
|
2293
|
+
runPersistentContentCommand,
|
|
2294
|
+
resetContentJsonString,
|
|
2295
|
+
]);
|
|
2125
2296
|
const activeMentionTrigger = mentionQueryEvent?.trigger || resolveMentionTrigger(addons);
|
|
2126
2297
|
const activeMentionSuggestions = (0, react_1.useMemo)(() => isFocused && mentionQueryEvent != null && addons?.mentions != null
|
|
2127
2298
|
? filterMentionSuggestions(addons.mentions.suggestions ?? [], mentionQueryEvent.query, activeMentionTrigger)
|
|
@@ -2273,7 +2444,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
2273
2444
|
nativeViewStyleParts.push({ height: autoGrowHeight });
|
|
2274
2445
|
}
|
|
2275
2446
|
const nativeViewStyle = nativeViewStyleParts.length <= 1 ? nativeViewStyleParts[0] : nativeViewStyleParts;
|
|
2276
|
-
const toolbarFrameJson = serializeToolbarFrames(editable
|
|
2447
|
+
const toolbarFrameJson = serializeToolbarFrames(editable && isFocused
|
|
2277
2448
|
? [
|
|
2278
2449
|
...(toolbarPlacement === 'inline' && inlineToolbarFrame != null
|
|
2279
2450
|
? [inlineToolbarFrame]
|
|
@@ -2361,7 +2532,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
2361
2532
|
}), onToggleStrike: () => runAndApply(() => bridgeRef.current?.toggleMark('strike') ?? null, {
|
|
2362
2533
|
skipNativeApplyIfContentUnchanged: true,
|
|
2363
2534
|
}), onToggleBulletList: () => runAndApply(() => bridgeRef.current?.toggleList('bulletList') ?? null), onToggleOrderedList: () => runAndApply(() => bridgeRef.current?.toggleList('orderedList') ?? null), onIndentList: () => runAndApply(() => bridgeRef.current?.indentListItem() ?? null), onOutdentList: () => runAndApply(() => bridgeRef.current?.outdentListItem() ?? null), onInsertHorizontalRule: () => runAndApply(() => bridgeRef.current?.insertNode('horizontalRule') ?? null), onInsertLineBreak: () => runAndApply(() => bridgeRef.current?.insertNode('hardBreak') ?? null), onUndo: () => runAndApply(() => bridgeRef.current?.undo() ?? null), onRedo: () => runAndApply(() => bridgeRef.current?.redo() ?? null) })) }));
|
|
2364
|
-
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [styles.container, containerStyle], children: [(0, jsx_runtime_1.jsx)(NativeEditorView, { ref: nativeViewRef, style: nativeViewStyle, editorId: editorInstanceId, placeholder: placeholder, editable: editable, autoFocus: autoFocus, autoCapitalize: autoCapitalize, autoCorrect: autoCorrect, keyboardType: keyboardType, showToolbar: showToolbar, toolbarPlacement: toolbarPlacement, heightBehavior: heightBehavior, allowImageResizing: allowImageResizing, themeJson: themeJson, addonsJson: addonsJson, toolbarItemsJson: toolbarItemsJson, remoteSelectionsJson: remoteSelectionsJson, toolbarFrameJson: toolbarFrameJson, editorUpdateJson: pendingNativeUpdate.json, editorUpdateEditorId: pendingNativeUpdate.editorId, editorUpdateRevision: pendingNativeUpdate.revision, onEditorUpdate: handleUpdate, onSelectionChange: handleSelectionChange, onFocusChange: handleFocusChange, onContentHeightChange: handleContentHeightChange, ...(react_native_1.Platform.OS === 'android' ? { onEditorReady: handleEditorReady } : {}), onToolbarAction: handleToolbarAction, onAddonEvent: handleAddonEvent }, DEV_NATIVE_VIEW_KEY), shouldRenderJsToolbar && jsToolbar] }));
|
|
2535
|
+
return ((0, jsx_runtime_1.jsxs)(react_native_1.View, { style: [styles.container, containerStyle], children: [(0, jsx_runtime_1.jsx)(NativeEditorView, { ref: nativeViewRef, style: nativeViewStyle, editorId: editorInstanceId, placeholder: placeholder, editable: editable, autoFocus: autoFocus, autoCapitalize: autoCapitalize, autoCorrect: autoCorrect, keyboardType: keyboardType, showToolbar: showToolbar, toolbarPlacement: toolbarPlacement, heightBehavior: heightBehavior, allowImageResizing: allowImageResizing, themeJson: themeJson, addonsJson: addonsJson, toolbarItemsJson: toolbarItemsJson, remoteSelectionsJson: remoteSelectionsJson, toolbarFrameJson: toolbarFrameJson, editorUpdateJson: pendingNativeUpdate.json, editorUpdateEditorId: pendingNativeUpdate.editorId, editorUpdateRevision: pendingNativeUpdate.revision, editorResetUpdateJson: pendingNativeResetUpdate.json, editorResetUpdateEditorId: pendingNativeResetUpdate.editorId, editorResetUpdateRevision: pendingNativeResetUpdate.revision, onEditorUpdate: handleUpdate, onSelectionChange: handleSelectionChange, onFocusChange: handleFocusChange, onContentHeightChange: handleContentHeightChange, ...(react_native_1.Platform.OS === 'android' ? { onEditorReady: handleEditorReady } : {}), onToolbarAction: handleToolbarAction, onAddonEvent: handleAddonEvent }, DEV_NATIVE_VIEW_KEY), shouldRenderJsToolbar && jsToolbar] }));
|
|
2365
2536
|
});
|
|
2366
2537
|
const styles = react_native_1.StyleSheet.create({
|
|
2367
2538
|
container: {
|
|
@@ -28,6 +28,8 @@ export interface YjsCollaborationState {
|
|
|
28
28
|
status: YjsTransportStatus;
|
|
29
29
|
isConnected: boolean;
|
|
30
30
|
documentJson: DocumentJSON;
|
|
31
|
+
/** Local selection remapped through the latest collaboration document update. */
|
|
32
|
+
selectionOnValueJSONReset?: Selection;
|
|
31
33
|
lastError?: Error;
|
|
32
34
|
}
|
|
33
35
|
export interface YjsCollaborationOptions {
|
|
@@ -74,6 +76,9 @@ export interface UseYjsCollaborationResult {
|
|
|
74
76
|
updateLocalAwareness(partial: Partial<LocalAwarenessState>): void;
|
|
75
77
|
editorBindings: {
|
|
76
78
|
valueJSON: DocumentJSON;
|
|
79
|
+
valueJSONUpdateMode: 'reset';
|
|
80
|
+
preserveSelectionOnValueJSONReset: true;
|
|
81
|
+
selectionOnValueJSONReset?: Selection;
|
|
77
82
|
remoteSelections: RemoteSelectionDecoration[];
|
|
78
83
|
onContentChangeJSON: (doc: DocumentJSON) => void;
|
|
79
84
|
onSelectionChange: (selection: Selection) => void;
|
package/dist/YjsCollaboration.js
CHANGED
|
@@ -177,6 +177,22 @@ function selectionToAwarenessRange(selection) {
|
|
|
177
177
|
head: selection.head ?? selection.anchor ?? 0,
|
|
178
178
|
};
|
|
179
179
|
}
|
|
180
|
+
function selectionFromPeerState(state) {
|
|
181
|
+
if (!state || typeof state !== 'object')
|
|
182
|
+
return undefined;
|
|
183
|
+
const selection = state.selection;
|
|
184
|
+
if (!selection || typeof selection !== 'object')
|
|
185
|
+
return undefined;
|
|
186
|
+
const anchor = Number(selection.anchor);
|
|
187
|
+
const head = Number(selection.head);
|
|
188
|
+
if (!Number.isFinite(anchor) || !Number.isFinite(head))
|
|
189
|
+
return undefined;
|
|
190
|
+
return { type: 'text', anchor, head };
|
|
191
|
+
}
|
|
192
|
+
function localSelectionFromPeers(peers) {
|
|
193
|
+
const localPeer = peers.find((peer) => peer.isLocal);
|
|
194
|
+
return localPeer ? selectionFromPeerState(localPeer.state) : undefined;
|
|
195
|
+
}
|
|
180
196
|
function peersToRemoteSelections(peers) {
|
|
181
197
|
return peers.flatMap((peer) => {
|
|
182
198
|
if (peer.isLocal || !peer.state || typeof peer.state !== 'object') {
|
|
@@ -240,17 +256,24 @@ class YjsCollaborationControllerImpl {
|
|
|
240
256
|
localAwareness: awarenessToRecord(this.localAwarenessState),
|
|
241
257
|
});
|
|
242
258
|
const nativeDocumentJson = this.bridge.getDocumentJson();
|
|
259
|
+
this._peers = this.bridge.getPeers();
|
|
260
|
+
let initialDocumentJson;
|
|
261
|
+
if (options.initialDocumentJson != null) {
|
|
262
|
+
initialDocumentJson = cloneJsonValue(options.initialDocumentJson);
|
|
263
|
+
}
|
|
264
|
+
else if (shouldUseFallbackForNativeDocument(nativeDocumentJson, options)) {
|
|
265
|
+
initialDocumentJson = defaultEmptyDocument(options.schema);
|
|
266
|
+
}
|
|
267
|
+
else {
|
|
268
|
+
initialDocumentJson = nativeDocumentJson;
|
|
269
|
+
}
|
|
243
270
|
this._state = {
|
|
244
271
|
documentId: options.documentId,
|
|
245
272
|
status: 'idle',
|
|
246
273
|
isConnected: false,
|
|
247
|
-
documentJson:
|
|
248
|
-
|
|
249
|
-
: shouldUseFallbackForNativeDocument(nativeDocumentJson, options)
|
|
250
|
-
? defaultEmptyDocument(options.schema)
|
|
251
|
-
: nativeDocumentJson,
|
|
274
|
+
documentJson: initialDocumentJson,
|
|
275
|
+
selectionOnValueJSONReset: localSelectionFromPeers(this._peers),
|
|
252
276
|
};
|
|
253
|
-
this._peers = this.bridge.getPeers();
|
|
254
277
|
if (options.connect !== false) {
|
|
255
278
|
this.connect();
|
|
256
279
|
}
|
|
@@ -333,6 +356,9 @@ class YjsCollaborationControllerImpl {
|
|
|
333
356
|
return;
|
|
334
357
|
}
|
|
335
358
|
try {
|
|
359
|
+
if (this.pendingAwarenessTimer != null) {
|
|
360
|
+
this.commitLocalAwareness();
|
|
361
|
+
}
|
|
336
362
|
const result = this.bridge.handleMessage(bytes);
|
|
337
363
|
this.applyResult(result);
|
|
338
364
|
sendBinaryMessages(socket, result.messages);
|
|
@@ -438,6 +464,9 @@ class YjsCollaborationControllerImpl {
|
|
|
438
464
|
const result = this.bridge.applyLocalDocumentJson(doc);
|
|
439
465
|
this.applyResult(result);
|
|
440
466
|
sendBinaryMessages(this.socket, result.messages);
|
|
467
|
+
if (this.pendingAwarenessTimer != null) {
|
|
468
|
+
this.commitLocalAwareness();
|
|
469
|
+
}
|
|
441
470
|
}
|
|
442
471
|
handleSelectionChange(selection) {
|
|
443
472
|
if (this.destroyed)
|
|
@@ -466,13 +495,17 @@ class YjsCollaborationControllerImpl {
|
|
|
466
495
|
this.commitLocalAwareness();
|
|
467
496
|
}
|
|
468
497
|
applyResult(result) {
|
|
498
|
+
const didPeersChange = result.peersChanged && result.peers != null;
|
|
499
|
+
if (didPeersChange) {
|
|
500
|
+
this._peers = result.peers;
|
|
501
|
+
}
|
|
469
502
|
if (result.documentChanged && result.documentJson) {
|
|
470
503
|
this.setState({
|
|
471
504
|
documentJson: result.documentJson,
|
|
505
|
+
selectionOnValueJSONReset: localSelectionFromPeers(this._peers),
|
|
472
506
|
});
|
|
473
507
|
}
|
|
474
|
-
if (
|
|
475
|
-
this._peers = result.peers;
|
|
508
|
+
if (didPeersChange) {
|
|
476
509
|
this.callbacks.onPeersChange?.(this._peers);
|
|
477
510
|
}
|
|
478
511
|
}
|
|
@@ -697,6 +730,9 @@ function useYjsCollaboration(options) {
|
|
|
697
730
|
updateLocalAwareness: (partial) => controllerRef.current?.updateLocalAwareness(partial),
|
|
698
731
|
editorBindings: {
|
|
699
732
|
valueJSON: state.documentJson,
|
|
733
|
+
valueJSONUpdateMode: 'reset',
|
|
734
|
+
preserveSelectionOnValueJSONReset: true,
|
|
735
|
+
selectionOnValueJSONReset: state.selectionOnValueJSONReset,
|
|
700
736
|
remoteSelections: peersToRemoteSelections(peers),
|
|
701
737
|
onContentChangeJSON: (doc) => controllerRef.current?.handleLocalDocumentChange(doc),
|
|
702
738
|
onSelectionChange: (selection) => controllerRef.current?.handleSelectionChange(selection),
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export { NativeRichTextEditor, type NativeRichTextEditorProps, type NativeRichTextEditorRef, type NativeRichTextEditorCaretRect, type NativeRichTextEditorHeightBehavior, type NativeRichTextEditorToolbarPlacement, type NativeRichTextEditorAutoCapitalize, type NativeRichTextEditorKeyboardType, type RemoteSelectionDecoration, type LinkRequestContext, type ImageRequestContext, } from './NativeRichTextEditor';
|
|
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
2
|
export { NativeProseViewer, type NativeProseViewerProps, type NativeProseViewerAddons, type NativeProseViewerMentionsAddonConfig, type NativeProseViewerMentionPrefix, type NativeProseViewerLinkPressEvent, type NativeProseViewerMentionRenderContext, type NativeProseViewerMentionPressEvent, } 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';
|