@apollohg/react-native-prose-editor 0.5.15 → 0.5.17
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/android/src/main/java/com/apollohg/editor/EditorEditText.kt +1454 -127
- package/android/src/main/java/com/apollohg/editor/EditorInputConnection.kt +403 -59
- package/android/src/main/java/com/apollohg/editor/NativeEditorExpoView.kt +1666 -79
- package/android/src/main/java/com/apollohg/editor/NativeEditorModule.kt +209 -87
- package/android/src/main/java/com/apollohg/editor/PositionBridge.kt +27 -0
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +58 -9
- package/dist/NativeEditorBridge.d.ts +34 -1
- package/dist/NativeEditorBridge.js +243 -83
- package/dist/NativeRichTextEditor.js +998 -137
- package/dist/addons.d.ts +7 -0
- 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 +830 -17
- package/ios/NativeEditorModule.swift +304 -108
- package/ios/PositionBridge.swift +24 -1
- package/ios/RichTextEditorView.swift +787 -51
- package/package.json +2 -1
- 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
|
@@ -61,6 +61,9 @@ function mapToolbarItemsForNative(items, activeState, editable, onRequestLink, o
|
|
|
61
61
|
function isImageDataUrl(value) {
|
|
62
62
|
return /^data:image\//i.test(value.trim());
|
|
63
63
|
}
|
|
64
|
+
function isRetryableNativeCommandBlock(reason) {
|
|
65
|
+
return reason === 'composition' || (react_native_1.Platform.OS === 'android' && reason === 'pendingUpdate');
|
|
66
|
+
}
|
|
64
67
|
function isPromiseLike(value) {
|
|
65
68
|
return (value != null &&
|
|
66
69
|
typeof value === 'object' &&
|
|
@@ -398,15 +401,34 @@ function didContentChange(previousDocumentVersion, update) {
|
|
|
398
401
|
typeof update.documentVersion !== 'number' ||
|
|
399
402
|
update.documentVersion !== previousDocumentVersion);
|
|
400
403
|
}
|
|
404
|
+
function documentVersionFromUpdateJson(json) {
|
|
405
|
+
try {
|
|
406
|
+
const parsed = JSON.parse(json);
|
|
407
|
+
return typeof parsed.documentVersion === 'number' ? parsed.documentVersion : null;
|
|
408
|
+
}
|
|
409
|
+
catch {
|
|
410
|
+
return null;
|
|
411
|
+
}
|
|
412
|
+
}
|
|
413
|
+
function isCurrentNativeEditorEvent(event, bridge) {
|
|
414
|
+
if (react_native_1.Platform.OS === 'android') {
|
|
415
|
+
return typeof event.editorId === 'number' && bridge?.editorId === event.editorId;
|
|
416
|
+
}
|
|
417
|
+
if (typeof event.editorId !== 'number')
|
|
418
|
+
return true;
|
|
419
|
+
return event.editorId === 0 || bridge?.editorId === event.editorId;
|
|
420
|
+
}
|
|
401
421
|
function computeRenderedTextLength(elements) {
|
|
402
422
|
let len = 0;
|
|
403
423
|
let blockCount = 0;
|
|
404
424
|
for (const el of elements) {
|
|
405
425
|
if (el.type === 'blockStart' && el.listContext) {
|
|
406
|
-
len += el.listContext.ordered
|
|
426
|
+
len += el.listContext.ordered
|
|
427
|
+
? unicodeScalarCount(`${el.listContext.index}. `)
|
|
428
|
+
: unicodeScalarCount('• ');
|
|
407
429
|
}
|
|
408
430
|
else if (el.type === 'textRun' && el.text) {
|
|
409
|
-
len += el.text
|
|
431
|
+
len += unicodeScalarCount(el.text);
|
|
410
432
|
}
|
|
411
433
|
else if (el.type === 'voidInline' ||
|
|
412
434
|
el.type === 'voidBlock' ||
|
|
@@ -414,7 +436,7 @@ function computeRenderedTextLength(elements) {
|
|
|
414
436
|
el.type === 'opaqueBlockAtom') {
|
|
415
437
|
if (el.type === 'opaqueInlineAtom' || el.type === 'opaqueBlockAtom') {
|
|
416
438
|
const visibleText = el.nodeType === 'mention' ? (el.label ?? '?') : `[${el.label ?? '?'}]`;
|
|
417
|
-
len += visibleText
|
|
439
|
+
len += unicodeScalarCount(visibleText);
|
|
418
440
|
}
|
|
419
441
|
else {
|
|
420
442
|
// U+FFFC placeholder / hard break
|
|
@@ -508,6 +530,19 @@ function useSerializedValue(value, serialize, revision) {
|
|
|
508
530
|
};
|
|
509
531
|
return serialized;
|
|
510
532
|
}
|
|
533
|
+
function doesLiveMentionQueryConflictWithNativeSelectRequest(request, currentQuery, requestDocumentVersion, currentDocumentVersion) {
|
|
534
|
+
if (currentQuery == null)
|
|
535
|
+
return false;
|
|
536
|
+
const currentQueryDocumentVersion = typeof currentQuery.documentVersion === 'number' ? currentQuery.documentVersion : null;
|
|
537
|
+
const isSameDocument = currentQueryDocumentVersion != null
|
|
538
|
+
? currentQueryDocumentVersion === requestDocumentVersion
|
|
539
|
+
: requestDocumentVersion == null || requestDocumentVersion === currentDocumentVersion;
|
|
540
|
+
if (!isSameDocument)
|
|
541
|
+
return false;
|
|
542
|
+
return (currentQuery.trigger !== request.trigger ||
|
|
543
|
+
currentQuery.range.anchor !== request.range.anchor ||
|
|
544
|
+
currentQuery.range.head !== request.range.head);
|
|
545
|
+
}
|
|
511
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) {
|
|
512
547
|
const bridgeRef = (0, react_1.useRef)(null);
|
|
513
548
|
const nativeViewRef = (0, react_1.useRef)(null);
|
|
@@ -519,8 +554,20 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
519
554
|
const registeredToolbarFrames = (0, EditorToolbar_1.useEditorToolbarFrames)();
|
|
520
555
|
const [pendingNativeUpdate, setPendingNativeUpdate] = (0, react_1.useState)({
|
|
521
556
|
json: undefined,
|
|
557
|
+
editorId: undefined,
|
|
522
558
|
revision: 0,
|
|
523
559
|
});
|
|
560
|
+
const pendingNativeUpdateRef = (0, react_1.useRef)(pendingNativeUpdate);
|
|
561
|
+
pendingNativeUpdateRef.current = pendingNativeUpdate;
|
|
562
|
+
const pendingNativeUpdateInFlightRef = (0, react_1.useRef)(null);
|
|
563
|
+
const [blockedNativeCommandRetry, setBlockedNativeCommandRetry] = (0, react_1.useState)(0);
|
|
564
|
+
const [detachedControlledSyncRetry, setDetachedControlledSyncRetry] = (0, react_1.useState)(0);
|
|
565
|
+
const [controlledNativeUpdateRetry, setControlledNativeUpdateRetry] = (0, react_1.useState)(0);
|
|
566
|
+
const pendingDetachedControlledSyncRef = (0, react_1.useRef)(false);
|
|
567
|
+
const pendingControlledSyncAfterNativeUpdateRef = (0, react_1.useRef)(false);
|
|
568
|
+
const pendingBlockedNativeCommandRetryRef = (0, react_1.useRef)(false);
|
|
569
|
+
const pendingNativeCommandRetryRef = (0, react_1.useRef)(null);
|
|
570
|
+
const blockedNativeCommandRetryTimerRef = (0, react_1.useRef)(null);
|
|
524
571
|
const [autoGrowHeight, setAutoGrowHeight] = (0, react_1.useState)(null);
|
|
525
572
|
// Toolbar state from EditorUpdate events
|
|
526
573
|
const [activeState, setActiveState] = (0, react_1.useState)({
|
|
@@ -531,6 +578,8 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
531
578
|
allowedMarks: [],
|
|
532
579
|
insertableNodes: [],
|
|
533
580
|
});
|
|
581
|
+
const activeStateRef = (0, react_1.useRef)(activeState);
|
|
582
|
+
activeStateRef.current = activeState;
|
|
534
583
|
const [historyState, setHistoryState] = (0, react_1.useState)({
|
|
535
584
|
canUndo: false,
|
|
536
585
|
canRedo: false,
|
|
@@ -540,9 +589,28 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
540
589
|
const selectionRef = (0, react_1.useRef)({ type: 'text', anchor: 0, head: 0 });
|
|
541
590
|
const renderedTextLengthRef = (0, react_1.useRef)(0);
|
|
542
591
|
const documentVersionRef = (0, react_1.useRef)(null);
|
|
592
|
+
const controlledHtmlSyncRef = (0, react_1.useRef)({
|
|
593
|
+
value: undefined,
|
|
594
|
+
documentVersion: null,
|
|
595
|
+
});
|
|
596
|
+
const controlledJsonSyncRef = (0, react_1.useRef)({
|
|
597
|
+
value: undefined,
|
|
598
|
+
documentVersion: null,
|
|
599
|
+
});
|
|
543
600
|
const toolbarRef = (0, react_1.useRef)(null);
|
|
544
601
|
const mentionQueryEventRef = (0, react_1.useRef)(null);
|
|
602
|
+
const mentionQueryEditorIdRef = (0, react_1.useRef)(null);
|
|
545
603
|
mentionQueryEventRef.current = mentionQueryEvent;
|
|
604
|
+
const setMentionQueryEventState = (0, react_1.useCallback)((nextEvent, editorId) => {
|
|
605
|
+
mentionQueryEventRef.current = nextEvent;
|
|
606
|
+
mentionQueryEditorIdRef.current =
|
|
607
|
+
nextEvent == null
|
|
608
|
+
? null
|
|
609
|
+
: typeof editorId === 'number'
|
|
610
|
+
? editorId
|
|
611
|
+
: (bridgeRef.current?.editorId ?? null);
|
|
612
|
+
setMentionQueryEvent(nextEvent);
|
|
613
|
+
}, []);
|
|
546
614
|
const toolbarItemsSerializationCacheRef = (0, react_1.useRef)(null);
|
|
547
615
|
// Stable callback refs to avoid re-renders
|
|
548
616
|
const onContentChangeRef = (0, react_1.useRef)(onContentChange);
|
|
@@ -574,27 +642,81 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
574
642
|
const themeJson = useSerializedValue(theme, EditorTheme_1.serializeEditorTheme);
|
|
575
643
|
const addonsJson = useSerializedValue(addons, addons_1.serializeEditorAddons);
|
|
576
644
|
const remoteSelectionsJson = useSerializedValue(remoteSelections, (selections) => serializeRemoteSelections(selections));
|
|
645
|
+
const clearBlockedNativeCommandRetryTimer = (0, react_1.useCallback)(() => {
|
|
646
|
+
const timer = blockedNativeCommandRetryTimerRef.current;
|
|
647
|
+
if (timer == null)
|
|
648
|
+
return;
|
|
649
|
+
clearTimeout(timer);
|
|
650
|
+
blockedNativeCommandRetryTimerRef.current = null;
|
|
651
|
+
}, []);
|
|
652
|
+
const flushBlockedNativeCommandRetry = (0, react_1.useCallback)(() => {
|
|
653
|
+
const hadPendingRetry = pendingBlockedNativeCommandRetryRef.current ||
|
|
654
|
+
blockedNativeCommandRetryTimerRef.current != null;
|
|
655
|
+
if (!hadPendingRetry)
|
|
656
|
+
return;
|
|
657
|
+
pendingBlockedNativeCommandRetryRef.current = false;
|
|
658
|
+
clearBlockedNativeCommandRetryTimer();
|
|
659
|
+
setBlockedNativeCommandRetry((revision) => revision + 1);
|
|
660
|
+
}, [clearBlockedNativeCommandRetryTimer]);
|
|
661
|
+
const scheduleBlockedNativeCommandRetry = (0, react_1.useCallback)(() => {
|
|
662
|
+
pendingBlockedNativeCommandRetryRef.current = true;
|
|
663
|
+
if (blockedNativeCommandRetryTimerRef.current != null)
|
|
664
|
+
return;
|
|
665
|
+
blockedNativeCommandRetryTimerRef.current = setTimeout(() => {
|
|
666
|
+
blockedNativeCommandRetryTimerRef.current = null;
|
|
667
|
+
if (!pendingBlockedNativeCommandRetryRef.current)
|
|
668
|
+
return;
|
|
669
|
+
pendingBlockedNativeCommandRetryRef.current = false;
|
|
670
|
+
setBlockedNativeCommandRetry((revision) => revision + 1);
|
|
671
|
+
}, 50);
|
|
672
|
+
}, []);
|
|
673
|
+
const enqueueBlockedNativeCommandRetry = (0, react_1.useCallback)((retry) => {
|
|
674
|
+
pendingNativeCommandRetryRef.current = retry;
|
|
675
|
+
scheduleBlockedNativeCommandRetry();
|
|
676
|
+
}, [scheduleBlockedNativeCommandRetry]);
|
|
677
|
+
const clearStaleMentionQueryForDocumentVersion = (0, react_1.useCallback)((documentVersion) => {
|
|
678
|
+
const currentMentionQuery = mentionQueryEventRef.current;
|
|
679
|
+
if (currentMentionQuery != null &&
|
|
680
|
+
(typeof currentMentionQuery.documentVersion !== 'number' ||
|
|
681
|
+
currentMentionQuery.documentVersion < documentVersion)) {
|
|
682
|
+
setMentionQueryEventState(null);
|
|
683
|
+
}
|
|
684
|
+
}, [setMentionQueryEventState]);
|
|
577
685
|
const syncStateFromUpdate = (0, react_1.useCallback)((update) => {
|
|
578
686
|
if (!update)
|
|
579
687
|
return;
|
|
688
|
+
activeStateRef.current = update.activeState;
|
|
580
689
|
setActiveState(update.activeState);
|
|
581
690
|
setHistoryState(update.historyState);
|
|
582
691
|
selectionRef.current = update.selection;
|
|
583
692
|
renderedTextLengthRef.current = computeRenderedTextLength(update.renderElements);
|
|
584
693
|
if (typeof update.documentVersion === 'number') {
|
|
694
|
+
const previousDocumentVersion = documentVersionRef.current;
|
|
585
695
|
documentVersionRef.current = update.documentVersion;
|
|
696
|
+
if (previousDocumentVersion == null ||
|
|
697
|
+
update.documentVersion > previousDocumentVersion) {
|
|
698
|
+
clearStaleMentionQueryForDocumentVersion(update.documentVersion);
|
|
699
|
+
}
|
|
586
700
|
}
|
|
587
|
-
|
|
701
|
+
flushBlockedNativeCommandRetry();
|
|
702
|
+
}, [clearStaleMentionQueryForDocumentVersion, flushBlockedNativeCommandRetry]);
|
|
588
703
|
const syncSelectionStateFromUpdate = (0, react_1.useCallback)((update) => {
|
|
589
704
|
if (!update)
|
|
590
705
|
return;
|
|
706
|
+
activeStateRef.current = update.activeState;
|
|
591
707
|
setActiveState(update.activeState);
|
|
592
708
|
setHistoryState(update.historyState);
|
|
593
709
|
selectionRef.current = update.selection;
|
|
594
710
|
if (typeof update.documentVersion === 'number') {
|
|
711
|
+
const previousDocumentVersion = documentVersionRef.current;
|
|
595
712
|
documentVersionRef.current = update.documentVersion;
|
|
713
|
+
if (previousDocumentVersion == null ||
|
|
714
|
+
update.documentVersion > previousDocumentVersion) {
|
|
715
|
+
clearStaleMentionQueryForDocumentVersion(update.documentVersion);
|
|
716
|
+
}
|
|
596
717
|
}
|
|
597
|
-
|
|
718
|
+
flushBlockedNativeCommandRetry();
|
|
719
|
+
}, [clearStaleMentionQueryForDocumentVersion, flushBlockedNativeCommandRetry]);
|
|
598
720
|
const emitContentCallbacksForUpdate = (0, react_1.useCallback)((update, previousDocumentVersion) => {
|
|
599
721
|
if (!update || !bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
600
722
|
return;
|
|
@@ -620,85 +742,222 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
620
742
|
onContentChangeJSONRef.current?.(bridgeRef.current.getJson());
|
|
621
743
|
}
|
|
622
744
|
}, []);
|
|
745
|
+
const clearPendingNativeUpdateForCurrentEditor = (0, react_1.useCallback)(() => {
|
|
746
|
+
if (react_native_1.Platform.OS !== 'android')
|
|
747
|
+
return;
|
|
748
|
+
const editorId = bridgeRef.current?.editorId;
|
|
749
|
+
if (typeof editorId !== 'number')
|
|
750
|
+
return;
|
|
751
|
+
const inFlight = pendingNativeUpdateInFlightRef.current;
|
|
752
|
+
if (inFlight != null && inFlight.editorId === editorId) {
|
|
753
|
+
pendingNativeUpdateInFlightRef.current = null;
|
|
754
|
+
}
|
|
755
|
+
setPendingNativeUpdate((current) => {
|
|
756
|
+
if (current.json == null && current.editorId === editorId) {
|
|
757
|
+
return current;
|
|
758
|
+
}
|
|
759
|
+
const next = {
|
|
760
|
+
json: undefined,
|
|
761
|
+
editorId,
|
|
762
|
+
revision: current.revision + 1,
|
|
763
|
+
};
|
|
764
|
+
pendingNativeUpdateRef.current = next;
|
|
765
|
+
return next;
|
|
766
|
+
});
|
|
767
|
+
}, []);
|
|
768
|
+
const consumeBlockedCommandInfoForRetry = (0, react_1.useCallback)((bridge) => {
|
|
769
|
+
const blockedInfo = bridge.consumeLastCommandBlockedInfo();
|
|
770
|
+
if (!blockedInfo.blocked)
|
|
771
|
+
return blockedInfo;
|
|
772
|
+
if (blockedInfo.reason === 'detached') {
|
|
773
|
+
pendingDetachedControlledSyncRef.current = true;
|
|
774
|
+
}
|
|
775
|
+
else if (blockedInfo.reason === 'destroyed') {
|
|
776
|
+
pendingDetachedControlledSyncRef.current = false;
|
|
777
|
+
pendingBlockedNativeCommandRetryRef.current = false;
|
|
778
|
+
pendingNativeCommandRetryRef.current = null;
|
|
779
|
+
clearBlockedNativeCommandRetryTimer();
|
|
780
|
+
clearPendingNativeUpdateForCurrentEditor();
|
|
781
|
+
}
|
|
782
|
+
else {
|
|
783
|
+
scheduleBlockedNativeCommandRetry();
|
|
784
|
+
}
|
|
785
|
+
return blockedInfo;
|
|
786
|
+
}, [
|
|
787
|
+
clearBlockedNativeCommandRetryTimer,
|
|
788
|
+
clearPendingNativeUpdateForCurrentEditor,
|
|
789
|
+
scheduleBlockedNativeCommandRetry,
|
|
790
|
+
]);
|
|
791
|
+
const consumeBlockedCommandForRetry = (0, react_1.useCallback)((bridge) => consumeBlockedCommandInfoForRetry(bridge).blocked, [consumeBlockedCommandInfoForRetry]);
|
|
792
|
+
(0, react_1.useEffect)(() => {
|
|
793
|
+
const retry = pendingNativeCommandRetryRef.current;
|
|
794
|
+
if (retry == null)
|
|
795
|
+
return;
|
|
796
|
+
pendingNativeCommandRetryRef.current = null;
|
|
797
|
+
retry();
|
|
798
|
+
}, [blockedNativeCommandRetry]);
|
|
799
|
+
const hasPendingNativeUpdateInFlightForCurrentEditor = (0, react_1.useCallback)(() => {
|
|
800
|
+
if (react_native_1.Platform.OS !== 'android')
|
|
801
|
+
return false;
|
|
802
|
+
const editorId = bridgeRef.current?.editorId;
|
|
803
|
+
if (typeof editorId !== 'number')
|
|
804
|
+
return false;
|
|
805
|
+
const inFlight = pendingNativeUpdateInFlightRef.current;
|
|
806
|
+
return inFlight != null && inFlight.editorId === editorId;
|
|
807
|
+
}, []);
|
|
623
808
|
const applyUpdateToNativeView = (0, react_1.useCallback)((update, previousDocumentVersion, skipNativeApplyIfContentUnchanged = false) => {
|
|
624
809
|
const contentChanged = didContentChange(previousDocumentVersion, update);
|
|
810
|
+
const handleApplyResult = (result) => {
|
|
811
|
+
if (result === false) {
|
|
812
|
+
setBlockedNativeCommandRetry((revision) => revision + 1);
|
|
813
|
+
return false;
|
|
814
|
+
}
|
|
815
|
+
return true;
|
|
816
|
+
};
|
|
625
817
|
if (!skipNativeApplyIfContentUnchanged || contentChanged) {
|
|
626
818
|
const updateJson = JSON.stringify(update);
|
|
627
819
|
if (react_native_1.Platform.OS === 'android') {
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
revision
|
|
631
|
-
|
|
820
|
+
const editorId = bridgeRef.current?.editorId;
|
|
821
|
+
setPendingNativeUpdate((current) => {
|
|
822
|
+
const revision = current.revision + 1;
|
|
823
|
+
const next = {
|
|
824
|
+
json: updateJson,
|
|
825
|
+
editorId,
|
|
826
|
+
revision,
|
|
827
|
+
};
|
|
828
|
+
pendingNativeUpdateRef.current = next;
|
|
829
|
+
pendingNativeUpdateInFlightRef.current = { editorId, revision };
|
|
830
|
+
return next;
|
|
831
|
+
});
|
|
632
832
|
}
|
|
633
833
|
else {
|
|
634
834
|
try {
|
|
635
835
|
const applyResult = nativeViewRef.current?.applyEditorUpdate(updateJson);
|
|
636
836
|
if (isPromiseLike(applyResult)) {
|
|
637
|
-
void applyResult
|
|
837
|
+
void applyResult
|
|
838
|
+
.then((result) => {
|
|
839
|
+
handleApplyResult(result);
|
|
840
|
+
})
|
|
841
|
+
.catch(() => {
|
|
638
842
|
// The native view may already be torn down during navigation.
|
|
639
843
|
});
|
|
640
844
|
}
|
|
845
|
+
else {
|
|
846
|
+
return handleApplyResult(applyResult);
|
|
847
|
+
}
|
|
641
848
|
}
|
|
642
849
|
catch {
|
|
643
850
|
// The native view may already be torn down during navigation.
|
|
644
851
|
}
|
|
645
852
|
}
|
|
646
853
|
}
|
|
647
|
-
return
|
|
854
|
+
return true;
|
|
648
855
|
}, []);
|
|
649
856
|
const maybeApplyAutoDetectedLink = (0, react_1.useCallback)((update, previousDocumentVersion) => {
|
|
650
|
-
|
|
651
|
-
!
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
857
|
+
const applyAutoLink = (candidateUpdate, allowPreflightRetry) => {
|
|
858
|
+
if (!autoDetectLinks ||
|
|
859
|
+
!candidateUpdate ||
|
|
860
|
+
!didContentChange(previousDocumentVersion, candidateUpdate) ||
|
|
861
|
+
!bridgeRef.current ||
|
|
862
|
+
bridgeRef.current.isDestroyed ||
|
|
863
|
+
!candidateUpdate.activeState.allowedMarks.includes('link') ||
|
|
864
|
+
candidateUpdate.selection.type !== 'text' ||
|
|
865
|
+
candidateUpdate.selection.anchor == null ||
|
|
866
|
+
candidateUpdate.selection.head == null ||
|
|
867
|
+
candidateUpdate.selection.anchor !== candidateUpdate.selection.head) {
|
|
868
|
+
return candidateUpdate;
|
|
869
|
+
}
|
|
870
|
+
const cursorDocPos = candidateUpdate.selection.head;
|
|
871
|
+
const candidate = findAutoLinkCandidateInDocument(bridgeRef.current.getJson(), cursorDocPos);
|
|
872
|
+
if (!candidate) {
|
|
873
|
+
return candidateUpdate;
|
|
874
|
+
}
|
|
875
|
+
const scalarFrom = bridgeRef.current.docToScalar(candidate.docFrom);
|
|
876
|
+
const scalarTo = bridgeRef.current.docToScalar(candidate.docTo);
|
|
877
|
+
if (!(scalarTo > scalarFrom)) {
|
|
878
|
+
return candidateUpdate;
|
|
879
|
+
}
|
|
880
|
+
const autoLinkUpdate = bridgeRef.current.setMarkAtSelectionScalar(scalarFrom, scalarTo, 'link', { href: candidate.href });
|
|
881
|
+
if (!autoLinkUpdate) {
|
|
882
|
+
const preflightUpdate = bridgeRef.current.consumeLastCommandPreflightUpdate();
|
|
883
|
+
if (preflightUpdate) {
|
|
884
|
+
return allowPreflightRetry
|
|
885
|
+
? applyAutoLink(preflightUpdate, false)
|
|
886
|
+
: preflightUpdate;
|
|
887
|
+
}
|
|
888
|
+
consumeBlockedCommandForRetry(bridgeRef.current);
|
|
889
|
+
return candidateUpdate;
|
|
890
|
+
}
|
|
891
|
+
bridgeRef.current.setSelection(candidateUpdate.selection.anchor, candidateUpdate.selection.head);
|
|
892
|
+
const selectionState = bridgeRef.current.getSelectionState();
|
|
893
|
+
if (selectionState) {
|
|
894
|
+
autoLinkUpdate.selection = selectionState.selection;
|
|
895
|
+
autoLinkUpdate.activeState = selectionState.activeState;
|
|
896
|
+
autoLinkUpdate.historyState = selectionState.historyState;
|
|
897
|
+
if (typeof selectionState.documentVersion === 'number') {
|
|
898
|
+
autoLinkUpdate.documentVersion = selectionState.documentVersion;
|
|
899
|
+
}
|
|
684
900
|
}
|
|
901
|
+
else {
|
|
902
|
+
autoLinkUpdate.selection = candidateUpdate.selection;
|
|
903
|
+
}
|
|
904
|
+
return autoLinkUpdate;
|
|
905
|
+
};
|
|
906
|
+
return applyAutoLink(update, true);
|
|
907
|
+
}, [autoDetectLinks, consumeBlockedCommandForRetry]);
|
|
908
|
+
const syncNativeUpdateFromBridge = (0, react_1.useCallback)((nativeUpdate, previousDocumentVersion, options) => {
|
|
909
|
+
const update = maybeApplyAutoDetectedLink(nativeUpdate, previousDocumentVersion);
|
|
910
|
+
if (!update)
|
|
911
|
+
return null;
|
|
912
|
+
if (update !== nativeUpdate) {
|
|
913
|
+
applyUpdateToNativeView(update, previousDocumentVersion, options?.skipNativeApplyIfContentUnchanged);
|
|
685
914
|
}
|
|
686
|
-
|
|
687
|
-
|
|
915
|
+
syncStateFromUpdate(update);
|
|
916
|
+
onActiveStateChangeRef.current?.(update.activeState);
|
|
917
|
+
onHistoryStateChangeRef.current?.(update.historyState);
|
|
918
|
+
if (!options?.suppressContentCallbacks) {
|
|
919
|
+
emitContentCallbacksForUpdate(update, previousDocumentVersion);
|
|
688
920
|
}
|
|
689
|
-
|
|
690
|
-
|
|
921
|
+
onSelectionChangeRef.current?.(update.selection);
|
|
922
|
+
return update;
|
|
923
|
+
}, [
|
|
924
|
+
applyUpdateToNativeView,
|
|
925
|
+
emitContentCallbacksForUpdate,
|
|
926
|
+
maybeApplyAutoDetectedLink,
|
|
927
|
+
syncStateFromUpdate,
|
|
928
|
+
]);
|
|
691
929
|
// Warn if both value and valueJSON are set
|
|
692
930
|
if (__DEV__ && value != null && valueJSON != null) {
|
|
693
931
|
console.warn('NativeRichTextEditor: value and valueJSON are mutually exclusive. ' +
|
|
694
932
|
'Only value will be used.');
|
|
695
933
|
}
|
|
696
934
|
const runAndApply = (0, react_1.useCallback)((mutate, options) => {
|
|
935
|
+
if (hasPendingNativeUpdateInFlightForCurrentEditor()) {
|
|
936
|
+
if (options?.retryBlockedCommand != null) {
|
|
937
|
+
enqueueBlockedNativeCommandRetry(options.retryBlockedCommand);
|
|
938
|
+
options.onBlockedCommandRetryQueued?.();
|
|
939
|
+
}
|
|
940
|
+
return null;
|
|
941
|
+
}
|
|
697
942
|
const previousDocumentVersion = documentVersionRef.current;
|
|
698
943
|
const preservedSelection = options?.preserveLiveTextSelection === true ? selectionRef.current : null;
|
|
699
944
|
let update = mutate();
|
|
700
|
-
if (!update)
|
|
945
|
+
if (!update) {
|
|
946
|
+
const bridge = bridgeRef.current;
|
|
947
|
+
if (bridge != null && !bridge.isDestroyed) {
|
|
948
|
+
const preflightUpdate = bridge.consumeLastCommandPreflightUpdate();
|
|
949
|
+
if (preflightUpdate) {
|
|
950
|
+
syncNativeUpdateFromBridge(preflightUpdate, previousDocumentVersion);
|
|
951
|
+
}
|
|
952
|
+
const blockedInfo = consumeBlockedCommandInfoForRetry(bridge);
|
|
953
|
+
if (options?.retryBlockedCommand != null &&
|
|
954
|
+
isRetryableNativeCommandBlock(blockedInfo.reason)) {
|
|
955
|
+
enqueueBlockedNativeCommandRetry(options.retryBlockedCommand);
|
|
956
|
+
options.onBlockedCommandRetryQueued?.();
|
|
957
|
+
}
|
|
958
|
+
}
|
|
701
959
|
return null;
|
|
960
|
+
}
|
|
702
961
|
if (!options?.skipAutoDetectLinks) {
|
|
703
962
|
update = maybeApplyAutoDetectedLink(update, previousDocumentVersion);
|
|
704
963
|
if (!update) {
|
|
@@ -708,6 +967,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
708
967
|
if (preservedSelection?.type === 'text' &&
|
|
709
968
|
typeof preservedSelection.anchor === 'number' &&
|
|
710
969
|
typeof preservedSelection.head === 'number' &&
|
|
970
|
+
!didContentChange(previousDocumentVersion, update) &&
|
|
711
971
|
bridgeRef.current != null &&
|
|
712
972
|
!bridgeRef.current.isDestroyed) {
|
|
713
973
|
bridgeRef.current.setSelection(preservedSelection.anchor, preservedSelection.head);
|
|
@@ -728,10 +988,56 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
728
988
|
return update;
|
|
729
989
|
}, [
|
|
730
990
|
applyUpdateToNativeView,
|
|
991
|
+
consumeBlockedCommandInfoForRetry,
|
|
992
|
+
enqueueBlockedNativeCommandRetry,
|
|
731
993
|
emitContentCallbacksForUpdate,
|
|
994
|
+
hasPendingNativeUpdateInFlightForCurrentEditor,
|
|
732
995
|
maybeApplyAutoDetectedLink,
|
|
996
|
+
syncNativeUpdateFromBridge,
|
|
733
997
|
syncStateFromUpdate,
|
|
734
998
|
]);
|
|
999
|
+
const prepareBridgeForExternalContentRead = (0, react_1.useCallback)((options) => {
|
|
1000
|
+
const bridge = bridgeRef.current;
|
|
1001
|
+
if (!bridge || bridge.isDestroyed)
|
|
1002
|
+
return false;
|
|
1003
|
+
const previousDocumentVersion = documentVersionRef.current;
|
|
1004
|
+
const ready = bridge.prepareForNativeCommand();
|
|
1005
|
+
const preflightUpdate = bridge.consumeLastCommandPreflightUpdate();
|
|
1006
|
+
if (preflightUpdate) {
|
|
1007
|
+
syncNativeUpdateFromBridge(preflightUpdate, previousDocumentVersion);
|
|
1008
|
+
}
|
|
1009
|
+
if (!ready) {
|
|
1010
|
+
consumeBlockedCommandForRetry(bridge);
|
|
1011
|
+
return false;
|
|
1012
|
+
}
|
|
1013
|
+
return (options?.skipWhenContentChanged !== true ||
|
|
1014
|
+
!didContentChange(previousDocumentVersion, preflightUpdate));
|
|
1015
|
+
}, [consumeBlockedCommandForRetry, syncNativeUpdateFromBridge]);
|
|
1016
|
+
const syncPreflightUpdateFromNativeEvent = (0, react_1.useCallback)((updateJson) => {
|
|
1017
|
+
if (typeof updateJson !== 'string' || updateJson.length === 0) {
|
|
1018
|
+
return true;
|
|
1019
|
+
}
|
|
1020
|
+
const bridge = bridgeRef.current;
|
|
1021
|
+
if (!bridge || bridge.isDestroyed)
|
|
1022
|
+
return false;
|
|
1023
|
+
const previousDocumentVersion = documentVersionRef.current;
|
|
1024
|
+
try {
|
|
1025
|
+
const parsed = JSON.parse(updateJson);
|
|
1026
|
+
if (react_native_1.Platform.OS === 'android' &&
|
|
1027
|
+
typeof previousDocumentVersion === 'number' &&
|
|
1028
|
+
typeof parsed.documentVersion !== 'number') {
|
|
1029
|
+
return false;
|
|
1030
|
+
}
|
|
1031
|
+
const update = bridge.parseUpdateJson(updateJson);
|
|
1032
|
+
if (!update)
|
|
1033
|
+
return false;
|
|
1034
|
+
syncNativeUpdateFromBridge(update, previousDocumentVersion);
|
|
1035
|
+
return true;
|
|
1036
|
+
}
|
|
1037
|
+
catch {
|
|
1038
|
+
return false;
|
|
1039
|
+
}
|
|
1040
|
+
}, [syncNativeUpdateFromBridge]);
|
|
735
1041
|
(0, react_1.useEffect)(() => {
|
|
736
1042
|
const bridgeConfig = maxLength != null || serializedSchemaJson || allowBase64Images
|
|
737
1043
|
? {
|
|
@@ -762,39 +1068,159 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
762
1068
|
bridge.destroy();
|
|
763
1069
|
bridgeRef.current = null;
|
|
764
1070
|
nativeViewRef.current = null;
|
|
1071
|
+
pendingNativeUpdateInFlightRef.current = null;
|
|
1072
|
+
pendingDetachedControlledSyncRef.current = false;
|
|
1073
|
+
pendingControlledSyncAfterNativeUpdateRef.current = false;
|
|
1074
|
+
pendingBlockedNativeCommandRetryRef.current = false;
|
|
1075
|
+
pendingNativeCommandRetryRef.current = null;
|
|
1076
|
+
documentVersionRef.current = null;
|
|
1077
|
+
mentionQueryEventRef.current = null;
|
|
1078
|
+
mentionQueryEditorIdRef.current = null;
|
|
1079
|
+
clearBlockedNativeCommandRetryTimer();
|
|
1080
|
+
setMentionQueryEvent(null);
|
|
1081
|
+
setPendingNativeUpdate((current) => {
|
|
1082
|
+
const next = {
|
|
1083
|
+
json: undefined,
|
|
1084
|
+
editorId: undefined,
|
|
1085
|
+
revision: current.revision + 1,
|
|
1086
|
+
};
|
|
1087
|
+
pendingNativeUpdateRef.current = next;
|
|
1088
|
+
return next;
|
|
1089
|
+
});
|
|
765
1090
|
setEditorInstanceId(0);
|
|
766
1091
|
setIsReady(false);
|
|
767
1092
|
};
|
|
768
1093
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
769
|
-
}, [
|
|
1094
|
+
}, [
|
|
1095
|
+
maxLength,
|
|
1096
|
+
syncStateFromUpdate,
|
|
1097
|
+
allowBase64Images,
|
|
1098
|
+
serializedSchemaJson,
|
|
1099
|
+
clearBlockedNativeCommandRetryTimer,
|
|
1100
|
+
]);
|
|
770
1101
|
(0, react_1.useEffect)(() => {
|
|
771
1102
|
if (value == null)
|
|
772
1103
|
return;
|
|
773
1104
|
if (!bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
774
1105
|
return;
|
|
1106
|
+
const previousSync = controlledHtmlSyncRef.current;
|
|
1107
|
+
const didControlledValueChange = previousSync.value !== value;
|
|
1108
|
+
const didDocumentAdvanceForSameValue = !didControlledValueChange &&
|
|
1109
|
+
previousSync.documentVersion !== documentVersionRef.current;
|
|
1110
|
+
if (!prepareBridgeForExternalContentRead({
|
|
1111
|
+
skipWhenContentChanged: !didControlledValueChange,
|
|
1112
|
+
})) {
|
|
1113
|
+
controlledHtmlSyncRef.current = {
|
|
1114
|
+
value,
|
|
1115
|
+
documentVersion: documentVersionRef.current,
|
|
1116
|
+
};
|
|
1117
|
+
return;
|
|
1118
|
+
}
|
|
1119
|
+
if (didDocumentAdvanceForSameValue) {
|
|
1120
|
+
controlledHtmlSyncRef.current = {
|
|
1121
|
+
value,
|
|
1122
|
+
documentVersion: documentVersionRef.current,
|
|
1123
|
+
};
|
|
1124
|
+
return;
|
|
1125
|
+
}
|
|
775
1126
|
const currentHtml = bridgeRef.current.getHtml();
|
|
776
|
-
if (currentHtml === value)
|
|
1127
|
+
if (currentHtml === value) {
|
|
1128
|
+
clearPendingNativeUpdateForCurrentEditor();
|
|
1129
|
+
controlledHtmlSyncRef.current = {
|
|
1130
|
+
value,
|
|
1131
|
+
documentVersion: documentVersionRef.current,
|
|
1132
|
+
};
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
if (hasPendingNativeUpdateInFlightForCurrentEditor()) {
|
|
1136
|
+
pendingControlledSyncAfterNativeUpdateRef.current = true;
|
|
777
1137
|
return;
|
|
778
|
-
|
|
1138
|
+
}
|
|
1139
|
+
const update = runAndApply(() => bridgeRef.current.replaceHtml(value), {
|
|
779
1140
|
suppressContentCallbacks: true,
|
|
780
1141
|
preserveLiveTextSelection: true,
|
|
781
1142
|
skipAutoDetectLinks: true,
|
|
782
1143
|
});
|
|
783
|
-
|
|
1144
|
+
if (!update && hasPendingNativeUpdateInFlightForCurrentEditor()) {
|
|
1145
|
+
pendingControlledSyncAfterNativeUpdateRef.current = true;
|
|
1146
|
+
return;
|
|
1147
|
+
}
|
|
1148
|
+
controlledHtmlSyncRef.current = {
|
|
1149
|
+
value,
|
|
1150
|
+
documentVersion: documentVersionRef.current,
|
|
1151
|
+
};
|
|
1152
|
+
}, [
|
|
1153
|
+
value,
|
|
1154
|
+
runAndApply,
|
|
1155
|
+
blockedNativeCommandRetry,
|
|
1156
|
+
controlledNativeUpdateRetry,
|
|
1157
|
+
detachedControlledSyncRetry,
|
|
1158
|
+
prepareBridgeForExternalContentRead,
|
|
1159
|
+
clearPendingNativeUpdateForCurrentEditor,
|
|
1160
|
+
hasPendingNativeUpdateInFlightForCurrentEditor,
|
|
1161
|
+
]);
|
|
784
1162
|
(0, react_1.useEffect)(() => {
|
|
785
1163
|
if (serializedValueJson == null || value != null)
|
|
786
1164
|
return;
|
|
787
1165
|
if (!bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
788
1166
|
return;
|
|
1167
|
+
const previousSync = controlledJsonSyncRef.current;
|
|
1168
|
+
const didControlledValueChange = previousSync.value !== serializedValueJson;
|
|
1169
|
+
const didDocumentAdvanceForSameValue = !didControlledValueChange &&
|
|
1170
|
+
previousSync.documentVersion !== documentVersionRef.current;
|
|
1171
|
+
if (!prepareBridgeForExternalContentRead({
|
|
1172
|
+
skipWhenContentChanged: !didControlledValueChange,
|
|
1173
|
+
})) {
|
|
1174
|
+
controlledJsonSyncRef.current = {
|
|
1175
|
+
value: serializedValueJson,
|
|
1176
|
+
documentVersion: documentVersionRef.current,
|
|
1177
|
+
};
|
|
1178
|
+
return;
|
|
1179
|
+
}
|
|
1180
|
+
if (didDocumentAdvanceForSameValue) {
|
|
1181
|
+
controlledJsonSyncRef.current = {
|
|
1182
|
+
value: serializedValueJson,
|
|
1183
|
+
documentVersion: documentVersionRef.current,
|
|
1184
|
+
};
|
|
1185
|
+
return;
|
|
1186
|
+
}
|
|
789
1187
|
const currentJson = bridgeRef.current.getJsonString();
|
|
790
|
-
if (currentJson === serializedValueJson)
|
|
1188
|
+
if (currentJson === serializedValueJson) {
|
|
1189
|
+
clearPendingNativeUpdateForCurrentEditor();
|
|
1190
|
+
controlledJsonSyncRef.current = {
|
|
1191
|
+
value: serializedValueJson,
|
|
1192
|
+
documentVersion: documentVersionRef.current,
|
|
1193
|
+
};
|
|
1194
|
+
return;
|
|
1195
|
+
}
|
|
1196
|
+
if (hasPendingNativeUpdateInFlightForCurrentEditor()) {
|
|
1197
|
+
pendingControlledSyncAfterNativeUpdateRef.current = true;
|
|
791
1198
|
return;
|
|
792
|
-
|
|
1199
|
+
}
|
|
1200
|
+
const update = runAndApply(() => bridgeRef.current.replaceJsonString(serializedValueJson), {
|
|
793
1201
|
suppressContentCallbacks: true,
|
|
794
1202
|
preserveLiveTextSelection: true,
|
|
795
1203
|
skipAutoDetectLinks: true,
|
|
796
1204
|
});
|
|
797
|
-
|
|
1205
|
+
if (!update && hasPendingNativeUpdateInFlightForCurrentEditor()) {
|
|
1206
|
+
pendingControlledSyncAfterNativeUpdateRef.current = true;
|
|
1207
|
+
return;
|
|
1208
|
+
}
|
|
1209
|
+
controlledJsonSyncRef.current = {
|
|
1210
|
+
value: serializedValueJson,
|
|
1211
|
+
documentVersion: documentVersionRef.current,
|
|
1212
|
+
};
|
|
1213
|
+
}, [
|
|
1214
|
+
serializedValueJson,
|
|
1215
|
+
value,
|
|
1216
|
+
runAndApply,
|
|
1217
|
+
blockedNativeCommandRetry,
|
|
1218
|
+
controlledNativeUpdateRetry,
|
|
1219
|
+
detachedControlledSyncRetry,
|
|
1220
|
+
prepareBridgeForExternalContentRead,
|
|
1221
|
+
clearPendingNativeUpdateForCurrentEditor,
|
|
1222
|
+
hasPendingNativeUpdateInFlightForCurrentEditor,
|
|
1223
|
+
]);
|
|
798
1224
|
const updateToolbarFrame = (0, react_1.useCallback)(() => {
|
|
799
1225
|
const toolbar = toolbarRef.current;
|
|
800
1226
|
if (!toolbar) {
|
|
@@ -826,62 +1252,96 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
826
1252
|
}
|
|
827
1253
|
}, [heightBehavior]);
|
|
828
1254
|
const handleUpdate = (0, react_1.useCallback)((event) => {
|
|
829
|
-
|
|
1255
|
+
const bridge = bridgeRef.current;
|
|
1256
|
+
if (!bridge || bridge.isDestroyed)
|
|
1257
|
+
return;
|
|
1258
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridge))
|
|
830
1259
|
return;
|
|
831
1260
|
try {
|
|
832
1261
|
const previousDocumentVersion = documentVersionRef.current;
|
|
833
|
-
|
|
1262
|
+
if (react_native_1.Platform.OS === 'android' && typeof previousDocumentVersion === 'number') {
|
|
1263
|
+
const parsed = JSON.parse(event.nativeEvent.updateJson);
|
|
1264
|
+
if (typeof parsed.documentVersion !== 'number') {
|
|
1265
|
+
return;
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
const nativeUpdate = bridge.parseUpdateJson(event.nativeEvent.updateJson, { rejectSameDocumentVersion: true });
|
|
834
1269
|
if (!nativeUpdate)
|
|
835
1270
|
return;
|
|
836
|
-
|
|
837
|
-
if (!update)
|
|
838
|
-
return;
|
|
839
|
-
if (update !== nativeUpdate) {
|
|
840
|
-
applyUpdateToNativeView(update, previousDocumentVersion);
|
|
841
|
-
}
|
|
842
|
-
syncStateFromUpdate(update);
|
|
843
|
-
onActiveStateChangeRef.current?.(update.activeState);
|
|
844
|
-
onHistoryStateChangeRef.current?.(update.historyState);
|
|
845
|
-
emitContentCallbacksForUpdate(update, previousDocumentVersion);
|
|
846
|
-
onSelectionChangeRef.current?.(update.selection);
|
|
1271
|
+
syncNativeUpdateFromBridge(nativeUpdate, previousDocumentVersion);
|
|
847
1272
|
}
|
|
848
1273
|
catch {
|
|
849
1274
|
// Invalid JSON from native — skip
|
|
850
1275
|
}
|
|
851
|
-
}, [
|
|
852
|
-
applyUpdateToNativeView,
|
|
853
|
-
emitContentCallbacksForUpdate,
|
|
854
|
-
maybeApplyAutoDetectedLink,
|
|
855
|
-
syncStateFromUpdate,
|
|
856
|
-
]);
|
|
1276
|
+
}, [syncNativeUpdateFromBridge]);
|
|
857
1277
|
const handleSelectionChange = (0, react_1.useCallback)((event) => {
|
|
858
|
-
|
|
1278
|
+
const bridge = bridgeRef.current;
|
|
1279
|
+
if (!bridge || bridge.isDestroyed)
|
|
1280
|
+
return;
|
|
1281
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridge))
|
|
1282
|
+
return;
|
|
1283
|
+
const { anchor, head, stateJson, documentVersion } = event.nativeEvent;
|
|
1284
|
+
const currentDocumentVersion = documentVersionRef.current;
|
|
1285
|
+
if (typeof documentVersion === 'number' &&
|
|
1286
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1287
|
+
documentVersion < currentDocumentVersion) {
|
|
859
1288
|
return;
|
|
860
|
-
const { anchor, head, stateJson } = event.nativeEvent;
|
|
861
|
-
let selection;
|
|
862
|
-
if (anchor === 0 &&
|
|
863
|
-
head >= renderedTextLengthRef.current &&
|
|
864
|
-
renderedTextLengthRef.current > 0) {
|
|
865
|
-
selection = { type: 'all' };
|
|
866
|
-
}
|
|
867
|
-
else {
|
|
868
|
-
selection = { type: 'text', anchor, head };
|
|
869
1289
|
}
|
|
870
|
-
bridgeRef.current.updateSelectionFromNative(anchor, head);
|
|
871
1290
|
let currentState = null;
|
|
872
1291
|
if (typeof stateJson === 'string' && stateJson.length > 0) {
|
|
1292
|
+
if (react_native_1.Platform.OS === 'android' &&
|
|
1293
|
+
typeof currentDocumentVersion === 'number') {
|
|
1294
|
+
const stateDocumentVersion = documentVersionFromUpdateJson(stateJson);
|
|
1295
|
+
if (typeof stateDocumentVersion !== 'number' ||
|
|
1296
|
+
stateDocumentVersion < currentDocumentVersion) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
}
|
|
873
1300
|
try {
|
|
874
|
-
currentState =
|
|
1301
|
+
currentState = bridge.parseUpdateJson(stateJson);
|
|
1302
|
+
if (!currentState)
|
|
1303
|
+
return;
|
|
875
1304
|
}
|
|
876
1305
|
catch {
|
|
877
|
-
currentState =
|
|
1306
|
+
currentState = bridge.getSelectionState();
|
|
878
1307
|
}
|
|
879
1308
|
}
|
|
880
1309
|
else {
|
|
881
|
-
currentState =
|
|
1310
|
+
currentState = bridge.getSelectionState();
|
|
1311
|
+
}
|
|
1312
|
+
if (currentState != null &&
|
|
1313
|
+
typeof currentState.documentVersion === 'number' &&
|
|
1314
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1315
|
+
currentState.documentVersion < currentDocumentVersion) {
|
|
1316
|
+
return;
|
|
1317
|
+
}
|
|
1318
|
+
if (currentState != null &&
|
|
1319
|
+
react_native_1.Platform.OS === 'android' &&
|
|
1320
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1321
|
+
typeof currentState.documentVersion !== 'number') {
|
|
1322
|
+
return;
|
|
1323
|
+
}
|
|
1324
|
+
if (currentState == null &&
|
|
1325
|
+
react_native_1.Platform.OS === 'android' &&
|
|
1326
|
+
typeof currentDocumentVersion === 'number') {
|
|
1327
|
+
return;
|
|
1328
|
+
}
|
|
1329
|
+
let selection;
|
|
1330
|
+
const selectionStart = Math.min(anchor, head);
|
|
1331
|
+
const selectionEnd = Math.max(anchor, head);
|
|
1332
|
+
if (selectionStart === 0 &&
|
|
1333
|
+
selectionEnd >= renderedTextLengthRef.current &&
|
|
1334
|
+
renderedTextLengthRef.current > 0) {
|
|
1335
|
+
selection = { type: 'all' };
|
|
1336
|
+
}
|
|
1337
|
+
else {
|
|
1338
|
+
selection = { type: 'text', anchor, head };
|
|
882
1339
|
}
|
|
883
|
-
syncSelectionStateFromUpdate(currentState);
|
|
884
1340
|
const nextSelection = selection.type === 'all' ? selection : (currentState?.selection ?? selection);
|
|
1341
|
+
if (currentState == null) {
|
|
1342
|
+
bridge.updateSelectionFromNative(anchor, head);
|
|
1343
|
+
}
|
|
1344
|
+
syncSelectionStateFromUpdate(currentState);
|
|
885
1345
|
selectionRef.current = nextSelection;
|
|
886
1346
|
if (currentState) {
|
|
887
1347
|
onActiveStateChangeRef.current?.(currentState.activeState);
|
|
@@ -899,6 +1359,8 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
899
1359
|
}, 50);
|
|
900
1360
|
}, []);
|
|
901
1361
|
const handleFocusChange = (0, react_1.useCallback)((event) => {
|
|
1362
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridgeRef.current))
|
|
1363
|
+
return;
|
|
902
1364
|
const { isFocused: focused } = event.nativeEvent;
|
|
903
1365
|
if (!focused &&
|
|
904
1366
|
editable &&
|
|
@@ -912,7 +1374,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
912
1374
|
isFocusedRef.current = focused;
|
|
913
1375
|
setIsFocused(focused);
|
|
914
1376
|
if (!focused) {
|
|
915
|
-
|
|
1377
|
+
setMentionQueryEventState(null);
|
|
916
1378
|
}
|
|
917
1379
|
if (focused) {
|
|
918
1380
|
if (!wasFocused) {
|
|
@@ -922,14 +1384,16 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
922
1384
|
else if (wasFocused) {
|
|
923
1385
|
onBlurRef.current?.();
|
|
924
1386
|
}
|
|
925
|
-
}, [editable, refocusAfterToolbarInteraction]);
|
|
1387
|
+
}, [editable, refocusAfterToolbarInteraction, setMentionQueryEventState]);
|
|
926
1388
|
(0, react_1.useEffect)(() => {
|
|
927
1389
|
if (addons?.mentions != null) {
|
|
928
1390
|
return;
|
|
929
1391
|
}
|
|
930
|
-
|
|
931
|
-
}, [addons?.mentions]);
|
|
1392
|
+
setMentionQueryEventState(null);
|
|
1393
|
+
}, [addons?.mentions, setMentionQueryEventState]);
|
|
932
1394
|
const handleContentHeightChange = (0, react_1.useCallback)((event) => {
|
|
1395
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridgeRef.current))
|
|
1396
|
+
return;
|
|
933
1397
|
if (heightBehavior !== 'autoGrow')
|
|
934
1398
|
return;
|
|
935
1399
|
const density = react_native_1.Platform.OS === 'android' ? react_native_1.PixelRatio.get() : 1;
|
|
@@ -938,6 +1402,47 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
938
1402
|
return;
|
|
939
1403
|
setAutoGrowHeight((prev) => (prev === nextHeight ? prev : nextHeight));
|
|
940
1404
|
}, [autoGrowHeight, heightBehavior]);
|
|
1405
|
+
const handleEditorReady = (0, react_1.useCallback)((event) => {
|
|
1406
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridgeRef.current))
|
|
1407
|
+
return;
|
|
1408
|
+
const editorId = bridgeRef.current?.editorId;
|
|
1409
|
+
const acknowledgedRevision = event.nativeEvent.editorUpdateRevision;
|
|
1410
|
+
const inFlight = pendingNativeUpdateInFlightRef.current;
|
|
1411
|
+
let didClearInFlight = false;
|
|
1412
|
+
if (inFlight != null) {
|
|
1413
|
+
const matchesRevision = typeof acknowledgedRevision === 'number' &&
|
|
1414
|
+
inFlight.editorId === editorId &&
|
|
1415
|
+
inFlight.revision === acknowledgedRevision;
|
|
1416
|
+
if (!matchesRevision) {
|
|
1417
|
+
return;
|
|
1418
|
+
}
|
|
1419
|
+
pendingNativeUpdateInFlightRef.current = null;
|
|
1420
|
+
didClearInFlight = true;
|
|
1421
|
+
setPendingNativeUpdate((current) => {
|
|
1422
|
+
if (current.editorId !== editorId ||
|
|
1423
|
+
current.revision !== acknowledgedRevision ||
|
|
1424
|
+
current.json == null) {
|
|
1425
|
+
return current;
|
|
1426
|
+
}
|
|
1427
|
+
const next = {
|
|
1428
|
+
json: undefined,
|
|
1429
|
+
editorId,
|
|
1430
|
+
revision: current.revision,
|
|
1431
|
+
};
|
|
1432
|
+
pendingNativeUpdateRef.current = next;
|
|
1433
|
+
return next;
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
flushBlockedNativeCommandRetry();
|
|
1437
|
+
if (didClearInFlight && pendingControlledSyncAfterNativeUpdateRef.current) {
|
|
1438
|
+
pendingControlledSyncAfterNativeUpdateRef.current = false;
|
|
1439
|
+
setControlledNativeUpdateRetry((revision) => revision + 1);
|
|
1440
|
+
}
|
|
1441
|
+
if (!pendingDetachedControlledSyncRef.current)
|
|
1442
|
+
return;
|
|
1443
|
+
pendingDetachedControlledSyncRef.current = false;
|
|
1444
|
+
setDetachedControlledSyncRetry((revision) => revision + 1);
|
|
1445
|
+
}, [flushBlockedNativeCommandRetry]);
|
|
941
1446
|
const restoreSelection = (0, react_1.useCallback)((selection) => {
|
|
942
1447
|
if (selection.type === 'text') {
|
|
943
1448
|
const { anchor, head } = selection;
|
|
@@ -955,6 +1460,134 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
955
1460
|
bridgeRef.current?.setSelection(pos, pos);
|
|
956
1461
|
}
|
|
957
1462
|
}, []);
|
|
1463
|
+
const isAsyncRequestCurrent = (0, react_1.useCallback)((requestEditorId, requestDocumentVersion) => {
|
|
1464
|
+
const bridge = bridgeRef.current;
|
|
1465
|
+
return (bridge != null &&
|
|
1466
|
+
!bridge.isDestroyed &&
|
|
1467
|
+
bridge.editorId === requestEditorId &&
|
|
1468
|
+
documentVersionRef.current === requestDocumentVersion);
|
|
1469
|
+
}, []);
|
|
1470
|
+
const scalarRangeFromSelection = (0, react_1.useCallback)((selection) => {
|
|
1471
|
+
const bridge = bridgeRef.current;
|
|
1472
|
+
if (!bridge || bridge.isDestroyed)
|
|
1473
|
+
return null;
|
|
1474
|
+
if (selection.type === 'text') {
|
|
1475
|
+
const anchor = selection.anchor ?? 0;
|
|
1476
|
+
const head = selection.head ?? anchor;
|
|
1477
|
+
return {
|
|
1478
|
+
anchor: bridge.docToScalar(anchor),
|
|
1479
|
+
head: bridge.docToScalar(head),
|
|
1480
|
+
};
|
|
1481
|
+
}
|
|
1482
|
+
if (selection.type === 'node' && typeof selection.pos === 'number') {
|
|
1483
|
+
const scalar = bridge.docToScalar(selection.pos);
|
|
1484
|
+
return { anchor: scalar, head: scalar };
|
|
1485
|
+
}
|
|
1486
|
+
return null;
|
|
1487
|
+
}, []);
|
|
1488
|
+
const isCommandRetryScopeCurrent = (0, react_1.useCallback)((scope) => {
|
|
1489
|
+
const bridge = bridgeRef.current;
|
|
1490
|
+
if (!bridge || bridge.isDestroyed || bridge.editorId !== scope.editorId) {
|
|
1491
|
+
return false;
|
|
1492
|
+
}
|
|
1493
|
+
const currentDocumentVersion = documentVersionRef.current;
|
|
1494
|
+
const hasMentionScope = scope.mentionQuery != null ||
|
|
1495
|
+
scope.mentionRange != null ||
|
|
1496
|
+
scope.nativeMentionSelectRequest != null;
|
|
1497
|
+
if (currentDocumentVersion !== scope.documentVersion) {
|
|
1498
|
+
if (!hasMentionScope) {
|
|
1499
|
+
return false;
|
|
1500
|
+
}
|
|
1501
|
+
if (typeof currentDocumentVersion === 'number' &&
|
|
1502
|
+
typeof scope.documentVersion === 'number' &&
|
|
1503
|
+
currentDocumentVersion > scope.documentVersion) {
|
|
1504
|
+
return false;
|
|
1505
|
+
}
|
|
1506
|
+
}
|
|
1507
|
+
if (hasMentionScope &&
|
|
1508
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1509
|
+
scope.documentVersion == null) {
|
|
1510
|
+
return false;
|
|
1511
|
+
}
|
|
1512
|
+
if (typeof scope.scalarAnchor === 'number' &&
|
|
1513
|
+
typeof scope.scalarHead === 'number') {
|
|
1514
|
+
const currentRange = scalarRangeFromSelection(selectionRef.current);
|
|
1515
|
+
if (currentRange?.anchor !== scope.scalarAnchor ||
|
|
1516
|
+
currentRange?.head !== scope.scalarHead) {
|
|
1517
|
+
return false;
|
|
1518
|
+
}
|
|
1519
|
+
}
|
|
1520
|
+
if (scope.mentionQuery) {
|
|
1521
|
+
const mentionQueryEditorId = mentionQueryEditorIdRef.current;
|
|
1522
|
+
if (mentionQueryEditorId != null &&
|
|
1523
|
+
mentionQueryEditorId !== scope.editorId) {
|
|
1524
|
+
return false;
|
|
1525
|
+
}
|
|
1526
|
+
const currentQuery = mentionQueryEventRef.current;
|
|
1527
|
+
if (currentQuery == null ||
|
|
1528
|
+
currentQuery.trigger !== scope.mentionQuery.trigger ||
|
|
1529
|
+
currentQuery.query !== scope.mentionQuery.query ||
|
|
1530
|
+
currentQuery.range.anchor !== scope.mentionQuery.range.anchor ||
|
|
1531
|
+
currentQuery.range.head !== scope.mentionQuery.range.head ||
|
|
1532
|
+
currentQuery.documentVersion !== scope.mentionQuery.documentVersion) {
|
|
1533
|
+
return false;
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
if (scope.mentionRange) {
|
|
1537
|
+
const mentionQueryEditorId = mentionQueryEditorIdRef.current;
|
|
1538
|
+
if (mentionQueryEditorId != null &&
|
|
1539
|
+
mentionQueryEditorId !== scope.editorId) {
|
|
1540
|
+
return false;
|
|
1541
|
+
}
|
|
1542
|
+
const currentQuery = mentionQueryEventRef.current;
|
|
1543
|
+
if (currentQuery == null ||
|
|
1544
|
+
currentQuery.range.anchor !== scope.mentionRange.anchor ||
|
|
1545
|
+
currentQuery.range.head !== scope.mentionRange.head ||
|
|
1546
|
+
(currentQuery.documentVersion ?? null) !== scope.documentVersion) {
|
|
1547
|
+
return false;
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
if (scope.nativeMentionSelectRequest) {
|
|
1551
|
+
const mentionQueryEditorId = mentionQueryEditorIdRef.current;
|
|
1552
|
+
if (mentionQueryEditorId != null &&
|
|
1553
|
+
mentionQueryEditorId !== scope.editorId) {
|
|
1554
|
+
return false;
|
|
1555
|
+
}
|
|
1556
|
+
if (doesLiveMentionQueryConflictWithNativeSelectRequest(scope.nativeMentionSelectRequest, mentionQueryEventRef.current, scope.documentVersion, currentDocumentVersion)) {
|
|
1557
|
+
return false;
|
|
1558
|
+
}
|
|
1559
|
+
}
|
|
1560
|
+
return true;
|
|
1561
|
+
}, [scalarRangeFromSelection]);
|
|
1562
|
+
const runAndApplyWithCommandRetry = (0, react_1.useCallback)((scope, mutate, options, onApplied) => {
|
|
1563
|
+
let didQueueRetry = false;
|
|
1564
|
+
let run = null;
|
|
1565
|
+
const runIfScopeCurrent = () => {
|
|
1566
|
+
if (!isCommandRetryScopeCurrent(scope))
|
|
1567
|
+
return null;
|
|
1568
|
+
return run?.() ?? null;
|
|
1569
|
+
};
|
|
1570
|
+
const retry = () => {
|
|
1571
|
+
const update = runIfScopeCurrent();
|
|
1572
|
+
if (update) {
|
|
1573
|
+
onApplied?.(update);
|
|
1574
|
+
}
|
|
1575
|
+
return update != null;
|
|
1576
|
+
};
|
|
1577
|
+
run = () => runAndApply(mutate, {
|
|
1578
|
+
...options,
|
|
1579
|
+
retryBlockedCommand: retry,
|
|
1580
|
+
onBlockedCommandRetryQueued: () => {
|
|
1581
|
+
didQueueRetry = true;
|
|
1582
|
+
options?.onBlockedCommandRetryQueued?.();
|
|
1583
|
+
},
|
|
1584
|
+
});
|
|
1585
|
+
const update = runIfScopeCurrent();
|
|
1586
|
+
if (update) {
|
|
1587
|
+
onApplied?.(update);
|
|
1588
|
+
}
|
|
1589
|
+
return { update, queued: didQueueRetry };
|
|
1590
|
+
}, [isCommandRetryScopeCurrent, runAndApply]);
|
|
958
1591
|
const insertImage = (0, react_1.useCallback)((src, attrs, selection) => {
|
|
959
1592
|
const trimmedSrc = src.trim();
|
|
960
1593
|
if (!trimmedSrc)
|
|
@@ -974,38 +1607,116 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
974
1607
|
}, [allowBase64Images, restoreSelection, runAndApply]);
|
|
975
1608
|
const openLinkRequest = (0, react_1.useCallback)(() => {
|
|
976
1609
|
const requestSelection = selectionRef.current;
|
|
1610
|
+
const requestDocumentVersion = documentVersionRef.current;
|
|
1611
|
+
const requestEditorId = bridgeRef.current?.editorId ?? null;
|
|
1612
|
+
const linkState = activeStateRef.current;
|
|
1613
|
+
const requestLinkHref = typeof linkState.markAttrs?.link?.href === 'string'
|
|
1614
|
+
? linkState.markAttrs.link.href
|
|
1615
|
+
: undefined;
|
|
977
1616
|
onRequestLink?.({
|
|
978
|
-
href:
|
|
979
|
-
isActive:
|
|
1617
|
+
href: requestLinkHref,
|
|
1618
|
+
isActive: linkState.marks.link === true,
|
|
980
1619
|
selection: requestSelection,
|
|
981
1620
|
setLink: (href) => {
|
|
982
1621
|
const trimmedHref = href.trim();
|
|
983
1622
|
if (!trimmedHref)
|
|
984
1623
|
return;
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
1624
|
+
if (!isAsyncRequestCurrent(requestEditorId, requestDocumentVersion))
|
|
1625
|
+
return;
|
|
1626
|
+
const bridge = bridgeRef.current;
|
|
1627
|
+
if (!bridge || bridge.isDestroyed)
|
|
1628
|
+
return;
|
|
1629
|
+
const scalarSelection = scalarRangeFromSelection(requestSelection);
|
|
1630
|
+
if (!scalarSelection)
|
|
1631
|
+
return;
|
|
1632
|
+
runAndApplyWithCommandRetry({
|
|
1633
|
+
editorId: bridge.editorId,
|
|
1634
|
+
documentVersion: requestDocumentVersion,
|
|
1635
|
+
scalarAnchor: scalarSelection.anchor,
|
|
1636
|
+
scalarHead: scalarSelection.head,
|
|
1637
|
+
}, () => bridgeRef.current?.setMarkAtSelectionScalar(scalarSelection.anchor, scalarSelection.head, 'link', { href: trimmedHref }) ?? null, { skipNativeApplyIfContentUnchanged: true });
|
|
991
1638
|
},
|
|
992
1639
|
unsetLink: () => {
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
|
|
1640
|
+
if (!isAsyncRequestCurrent(requestEditorId, requestDocumentVersion))
|
|
1641
|
+
return;
|
|
1642
|
+
const bridge = bridgeRef.current;
|
|
1643
|
+
if (!bridge || bridge.isDestroyed)
|
|
1644
|
+
return;
|
|
1645
|
+
const scalarSelection = scalarRangeFromSelection(requestSelection);
|
|
1646
|
+
if (!scalarSelection)
|
|
1647
|
+
return;
|
|
1648
|
+
runAndApplyWithCommandRetry({
|
|
1649
|
+
editorId: bridge.editorId,
|
|
1650
|
+
documentVersion: requestDocumentVersion,
|
|
1651
|
+
scalarAnchor: scalarSelection.anchor,
|
|
1652
|
+
scalarHead: scalarSelection.head,
|
|
1653
|
+
}, () => bridgeRef.current?.unsetMarkAtSelectionScalar(scalarSelection.anchor, scalarSelection.head, 'link') ?? null, { skipNativeApplyIfContentUnchanged: true });
|
|
997
1654
|
},
|
|
998
1655
|
});
|
|
999
|
-
}, [
|
|
1656
|
+
}, [
|
|
1657
|
+
isAsyncRequestCurrent,
|
|
1658
|
+
onRequestLink,
|
|
1659
|
+
runAndApplyWithCommandRetry,
|
|
1660
|
+
scalarRangeFromSelection,
|
|
1661
|
+
]);
|
|
1000
1662
|
const openImageRequest = (0, react_1.useCallback)(() => {
|
|
1001
1663
|
const requestSelection = selectionRef.current;
|
|
1664
|
+
const requestDocumentVersion = documentVersionRef.current;
|
|
1665
|
+
const requestEditorId = bridgeRef.current?.editorId ?? null;
|
|
1002
1666
|
onRequestImage?.({
|
|
1003
1667
|
selection: requestSelection,
|
|
1004
1668
|
allowBase64: allowBase64Images,
|
|
1005
|
-
insertImage: (src, attrs) =>
|
|
1669
|
+
insertImage: (src, attrs) => {
|
|
1670
|
+
const trimmedSrc = src.trim();
|
|
1671
|
+
if (!trimmedSrc)
|
|
1672
|
+
return;
|
|
1673
|
+
if (!allowBase64Images && isImageDataUrl(trimmedSrc))
|
|
1674
|
+
return;
|
|
1675
|
+
if (!isAsyncRequestCurrent(requestEditorId, requestDocumentVersion))
|
|
1676
|
+
return;
|
|
1677
|
+
const bridge = bridgeRef.current;
|
|
1678
|
+
if (!bridge || bridge.isDestroyed)
|
|
1679
|
+
return;
|
|
1680
|
+
const scalarSelection = scalarRangeFromSelection(requestSelection);
|
|
1681
|
+
if (!scalarSelection)
|
|
1682
|
+
return;
|
|
1683
|
+
runAndApplyWithCommandRetry({
|
|
1684
|
+
editorId: bridge.editorId,
|
|
1685
|
+
documentVersion: requestDocumentVersion,
|
|
1686
|
+
scalarAnchor: scalarSelection.anchor,
|
|
1687
|
+
scalarHead: scalarSelection.head,
|
|
1688
|
+
}, () => bridgeRef.current?.insertContentJsonAtSelectionScalar(scalarSelection.anchor, scalarSelection.head, (0, schemas_1.buildImageFragmentJson)({
|
|
1689
|
+
src: trimmedSrc,
|
|
1690
|
+
...(attrs ?? {}),
|
|
1691
|
+
})) ?? null);
|
|
1692
|
+
},
|
|
1006
1693
|
});
|
|
1007
|
-
}, [
|
|
1694
|
+
}, [
|
|
1695
|
+
allowBase64Images,
|
|
1696
|
+
isAsyncRequestCurrent,
|
|
1697
|
+
onRequestImage,
|
|
1698
|
+
runAndApplyWithCommandRetry,
|
|
1699
|
+
scalarRangeFromSelection,
|
|
1700
|
+
]);
|
|
1008
1701
|
const handleToolbarAction = (0, react_1.useCallback)((event) => {
|
|
1702
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridgeRef.current))
|
|
1703
|
+
return;
|
|
1704
|
+
const currentDocumentVersion = documentVersionRef.current;
|
|
1705
|
+
const eventDocumentVersion = event.nativeEvent.documentVersion;
|
|
1706
|
+
if (typeof eventDocumentVersion === 'number' &&
|
|
1707
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1708
|
+
eventDocumentVersion < currentDocumentVersion) {
|
|
1709
|
+
return;
|
|
1710
|
+
}
|
|
1711
|
+
if (react_native_1.Platform.OS === 'android' &&
|
|
1712
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1713
|
+
typeof eventDocumentVersion !== 'number' &&
|
|
1714
|
+
typeof event.nativeEvent.updateJson !== 'string') {
|
|
1715
|
+
return;
|
|
1716
|
+
}
|
|
1717
|
+
if (!syncPreflightUpdateFromNativeEvent(event.nativeEvent.updateJson)) {
|
|
1718
|
+
return;
|
|
1719
|
+
}
|
|
1009
1720
|
if (event.nativeEvent.key === LINK_TOOLBAR_ACTION_KEY) {
|
|
1010
1721
|
openLinkRequest();
|
|
1011
1722
|
return;
|
|
@@ -1015,7 +1726,12 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1015
1726
|
return;
|
|
1016
1727
|
}
|
|
1017
1728
|
onToolbarAction?.(event.nativeEvent.key);
|
|
1018
|
-
}, [
|
|
1729
|
+
}, [
|
|
1730
|
+
onToolbarAction,
|
|
1731
|
+
openImageRequest,
|
|
1732
|
+
openLinkRequest,
|
|
1733
|
+
syncPreflightUpdateFromNativeEvent,
|
|
1734
|
+
]);
|
|
1019
1735
|
const resolveMentionSelectionAttrs = (0, react_1.useCallback)((selectionEvent) => {
|
|
1020
1736
|
let resolvedAttrs;
|
|
1021
1737
|
try {
|
|
@@ -1056,23 +1772,88 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1056
1772
|
bridgeRef.current.isDestroyed) {
|
|
1057
1773
|
return;
|
|
1058
1774
|
}
|
|
1059
|
-
const
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
|
|
1063
|
-
|
|
1064
|
-
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1775
|
+
const currentDocumentVersion = documentVersionRef.current;
|
|
1776
|
+
if (typeof mentionQuery.documentVersion === 'number' &&
|
|
1777
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1778
|
+
mentionQuery.documentVersion < currentDocumentVersion) {
|
|
1779
|
+
setMentionQueryEventState(null);
|
|
1780
|
+
return;
|
|
1781
|
+
}
|
|
1782
|
+
let attrs = null;
|
|
1783
|
+
const requestDocumentVersion = typeof mentionQuery.documentVersion === 'number'
|
|
1784
|
+
? mentionQuery.documentVersion
|
|
1785
|
+
: currentDocumentVersion;
|
|
1786
|
+
const retryScope = {
|
|
1787
|
+
editorId: bridgeRef.current.editorId,
|
|
1788
|
+
documentVersion: requestDocumentVersion,
|
|
1789
|
+
mentionQuery,
|
|
1790
|
+
};
|
|
1791
|
+
let queuedRetry = false;
|
|
1792
|
+
let retry = null;
|
|
1793
|
+
const finishSelection = (selectedAttrs) => {
|
|
1794
|
+
setMentionQueryEventState(null);
|
|
1068
1795
|
mentions.onSelect?.({
|
|
1069
1796
|
trigger: mentionQuery.trigger,
|
|
1070
1797
|
suggestion,
|
|
1071
|
-
attrs,
|
|
1798
|
+
attrs: selectedAttrs,
|
|
1799
|
+
...(typeof mentionQuery.documentVersion === 'number'
|
|
1800
|
+
? { documentVersion: mentionQuery.documentVersion }
|
|
1801
|
+
: {}),
|
|
1802
|
+
});
|
|
1803
|
+
};
|
|
1804
|
+
const attemptInsertion = () => {
|
|
1805
|
+
if (!isCommandRetryScopeCurrent(retryScope))
|
|
1806
|
+
return false;
|
|
1807
|
+
attrs = null;
|
|
1808
|
+
const update = runAndApply(() => bridgeRef.current?.insertContentJsonAtSelectionScalarLazy(mentionQuery.range.anchor, mentionQuery.range.head, () => {
|
|
1809
|
+
attrs = resolveMentionInsertionAttrs({
|
|
1810
|
+
trigger: mentionQuery.trigger,
|
|
1811
|
+
suggestion,
|
|
1812
|
+
attrs: resolveMentionSuggestionAttrs(suggestion, mentionQuery.trigger),
|
|
1813
|
+
range: mentionQuery.range,
|
|
1814
|
+
...(typeof mentionQuery.documentVersion === 'number'
|
|
1815
|
+
? { documentVersion: mentionQuery.documentVersion }
|
|
1816
|
+
: {}),
|
|
1817
|
+
});
|
|
1818
|
+
return (0, addons_1.buildMentionFragmentJson)(attrs);
|
|
1819
|
+
}) ?? null, {
|
|
1820
|
+
retryBlockedCommand: () => retry?.() === true,
|
|
1821
|
+
onBlockedCommandRetryQueued: () => {
|
|
1822
|
+
queuedRetry = true;
|
|
1823
|
+
},
|
|
1072
1824
|
});
|
|
1825
|
+
if (update && attrs) {
|
|
1826
|
+
finishSelection(attrs);
|
|
1827
|
+
return true;
|
|
1828
|
+
}
|
|
1829
|
+
return false;
|
|
1830
|
+
};
|
|
1831
|
+
retry = attemptInsertion;
|
|
1832
|
+
if (attemptInsertion()) {
|
|
1833
|
+
return;
|
|
1834
|
+
}
|
|
1835
|
+
if (queuedRetry) {
|
|
1836
|
+
return;
|
|
1073
1837
|
}
|
|
1074
|
-
|
|
1838
|
+
const latestMentionQuery = mentionQueryEventRef.current;
|
|
1839
|
+
if (latestMentionQuery == null ||
|
|
1840
|
+
(latestMentionQuery.trigger === mentionQuery.trigger &&
|
|
1841
|
+
latestMentionQuery.query === mentionQuery.query &&
|
|
1842
|
+
latestMentionQuery.range.anchor === mentionQuery.range.anchor &&
|
|
1843
|
+
latestMentionQuery.range.head === mentionQuery.range.head &&
|
|
1844
|
+
latestMentionQuery.documentVersion === mentionQuery.documentVersion)) {
|
|
1845
|
+
setMentionQueryEventState(null);
|
|
1846
|
+
}
|
|
1847
|
+
}, [
|
|
1848
|
+
isCommandRetryScopeCurrent,
|
|
1849
|
+
resolveMentionInsertionAttrs,
|
|
1850
|
+
runAndApply,
|
|
1851
|
+
setMentionQueryEventState,
|
|
1852
|
+
]);
|
|
1075
1853
|
const handleAddonEvent = (0, react_1.useCallback)((event) => {
|
|
1854
|
+
const bridge = bridgeRef.current;
|
|
1855
|
+
if (!isCurrentNativeEditorEvent(event.nativeEvent, bridge))
|
|
1856
|
+
return;
|
|
1076
1857
|
let parsed = null;
|
|
1077
1858
|
try {
|
|
1078
1859
|
parsed = JSON.parse(event.nativeEvent.eventJson);
|
|
@@ -1082,44 +1863,105 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1082
1863
|
}
|
|
1083
1864
|
if (!parsed)
|
|
1084
1865
|
return;
|
|
1866
|
+
let parsedDocumentVersion = typeof parsed.documentVersion === 'number' ? parsed.documentVersion : undefined;
|
|
1867
|
+
if (typeof parsedDocumentVersion !== 'number' &&
|
|
1868
|
+
parsed.type === 'mentionsSelectRequest' &&
|
|
1869
|
+
typeof parsed.updateJson === 'string') {
|
|
1870
|
+
try {
|
|
1871
|
+
const parsedUpdate = JSON.parse(parsed.updateJson);
|
|
1872
|
+
if (typeof parsedUpdate.documentVersion === 'number') {
|
|
1873
|
+
parsedDocumentVersion = parsedUpdate.documentVersion;
|
|
1874
|
+
}
|
|
1875
|
+
}
|
|
1876
|
+
catch {
|
|
1877
|
+
return;
|
|
1878
|
+
}
|
|
1879
|
+
}
|
|
1880
|
+
const currentDocumentVersion = documentVersionRef.current;
|
|
1881
|
+
const isStaleAddonEvent = typeof parsedDocumentVersion === 'number' &&
|
|
1882
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1883
|
+
parsedDocumentVersion < currentDocumentVersion;
|
|
1884
|
+
const isVersionlessAndroidAddonEvent = react_native_1.Platform.OS === 'android' &&
|
|
1885
|
+
typeof currentDocumentVersion === 'number' &&
|
|
1886
|
+
typeof parsedDocumentVersion !== 'number';
|
|
1085
1887
|
if (parsed.type === 'mentionsQueryChange') {
|
|
1888
|
+
if (isStaleAddonEvent || isVersionlessAndroidAddonEvent)
|
|
1889
|
+
return;
|
|
1086
1890
|
const nextEvent = {
|
|
1087
1891
|
query: parsed.query,
|
|
1088
1892
|
trigger: parsed.trigger,
|
|
1089
1893
|
range: parsed.range,
|
|
1090
1894
|
isActive: parsed.isActive,
|
|
1895
|
+
documentVersion: parsedDocumentVersion,
|
|
1091
1896
|
};
|
|
1092
|
-
|
|
1897
|
+
setMentionQueryEventState(parsed.isActive ? nextEvent : null, event.nativeEvent.editorId ?? bridgeRef.current?.editorId ?? null);
|
|
1093
1898
|
addonsRef.current?.mentions?.onQueryChange?.({
|
|
1094
1899
|
query: nextEvent.query,
|
|
1095
1900
|
trigger: nextEvent.trigger,
|
|
1096
1901
|
range: nextEvent.range,
|
|
1097
1902
|
isActive: nextEvent.isActive,
|
|
1903
|
+
...(typeof nextEvent.documentVersion === 'number'
|
|
1904
|
+
? { documentVersion: nextEvent.documentVersion }
|
|
1905
|
+
: {}),
|
|
1098
1906
|
});
|
|
1099
1907
|
return;
|
|
1100
1908
|
}
|
|
1101
1909
|
if (parsed.type === 'mentionsSelectRequest') {
|
|
1102
|
-
|
|
1103
|
-
if (!suggestion || !bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
1910
|
+
if (isStaleAddonEvent || isVersionlessAndroidAddonEvent)
|
|
1104
1911
|
return;
|
|
1105
|
-
const
|
|
1912
|
+
const requestDocumentVersion = typeof parsedDocumentVersion === 'number'
|
|
1913
|
+
? parsedDocumentVersion
|
|
1914
|
+
: currentDocumentVersion;
|
|
1915
|
+
const nativeMentionSelectRequest = {
|
|
1106
1916
|
trigger: parsed.trigger,
|
|
1107
|
-
|
|
1108
|
-
attrs: parsed.attrs,
|
|
1917
|
+
suggestionKey: parsed.suggestionKey,
|
|
1109
1918
|
range: parsed.range,
|
|
1110
1919
|
};
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1920
|
+
if (doesLiveMentionQueryConflictWithNativeSelectRequest(nativeMentionSelectRequest, mentionQueryEventRef.current, requestDocumentVersion, currentDocumentVersion)) {
|
|
1921
|
+
return;
|
|
1922
|
+
}
|
|
1923
|
+
if (!syncPreflightUpdateFromNativeEvent(parsed.updateJson))
|
|
1924
|
+
return;
|
|
1925
|
+
const suggestion = mentionSuggestionsByKeyRef.current.get(parsed.suggestionKey);
|
|
1926
|
+
if (!suggestion || !bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
1927
|
+
return;
|
|
1928
|
+
let finalAttrs = null;
|
|
1929
|
+
runAndApplyWithCommandRetry({
|
|
1930
|
+
editorId: bridgeRef.current.editorId,
|
|
1931
|
+
documentVersion: requestDocumentVersion,
|
|
1932
|
+
nativeMentionSelectRequest,
|
|
1933
|
+
}, () => {
|
|
1934
|
+
return (bridgeRef.current?.insertContentJsonAtSelectionScalarLazy(parsed.range.anchor, parsed.range.head, () => {
|
|
1935
|
+
const selectionEvent = {
|
|
1936
|
+
trigger: parsed.trigger,
|
|
1937
|
+
suggestion,
|
|
1938
|
+
attrs: parsed.attrs,
|
|
1939
|
+
range: parsed.range,
|
|
1940
|
+
...(typeof parsedDocumentVersion === 'number'
|
|
1941
|
+
? { documentVersion: parsedDocumentVersion }
|
|
1942
|
+
: {}),
|
|
1943
|
+
};
|
|
1944
|
+
const attrs = resolveMentionInsertionAttrs(selectionEvent);
|
|
1945
|
+
finalAttrs = attrs;
|
|
1946
|
+
return (0, addons_1.buildMentionFragmentJson)(attrs);
|
|
1947
|
+
}) ?? null);
|
|
1948
|
+
}, undefined, () => {
|
|
1949
|
+
if (!finalAttrs)
|
|
1950
|
+
return;
|
|
1114
1951
|
addonsRef.current?.mentions?.onSelect?.({
|
|
1115
1952
|
trigger: parsed.trigger,
|
|
1116
1953
|
suggestion,
|
|
1117
1954
|
attrs: finalAttrs,
|
|
1955
|
+
...(typeof parsedDocumentVersion === 'number'
|
|
1956
|
+
? { documentVersion: parsedDocumentVersion }
|
|
1957
|
+
: {}),
|
|
1118
1958
|
});
|
|
1119
|
-
}
|
|
1959
|
+
});
|
|
1120
1960
|
return;
|
|
1121
1961
|
}
|
|
1122
1962
|
if (parsed.type === 'mentionsSelect') {
|
|
1963
|
+
if (isStaleAddonEvent || isVersionlessAndroidAddonEvent)
|
|
1964
|
+
return;
|
|
1123
1965
|
const suggestion = mentionSuggestionsByKeyRef.current.get(parsed.suggestionKey);
|
|
1124
1966
|
if (!suggestion)
|
|
1125
1967
|
return;
|
|
@@ -1127,9 +1969,17 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1127
1969
|
trigger: parsed.trigger,
|
|
1128
1970
|
suggestion,
|
|
1129
1971
|
attrs: parsed.attrs,
|
|
1972
|
+
...(typeof parsedDocumentVersion === 'number'
|
|
1973
|
+
? { documentVersion: parsedDocumentVersion }
|
|
1974
|
+
: {}),
|
|
1130
1975
|
});
|
|
1131
1976
|
}
|
|
1132
|
-
}, [
|
|
1977
|
+
}, [
|
|
1978
|
+
resolveMentionInsertionAttrs,
|
|
1979
|
+
runAndApplyWithCommandRetry,
|
|
1980
|
+
setMentionQueryEventState,
|
|
1981
|
+
syncPreflightUpdateFromNativeEvent,
|
|
1982
|
+
]);
|
|
1133
1983
|
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
1134
1984
|
focus() {
|
|
1135
1985
|
nativeViewRef.current?.focus?.();
|
|
@@ -1192,16 +2042,25 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1192
2042
|
getContent() {
|
|
1193
2043
|
if (!bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
1194
2044
|
return '';
|
|
2045
|
+
if (!prepareBridgeForExternalContentRead()) {
|
|
2046
|
+
return bridgeRef.current.getCachedHtml() ?? '';
|
|
2047
|
+
}
|
|
1195
2048
|
return bridgeRef.current.getHtml();
|
|
1196
2049
|
},
|
|
1197
2050
|
getContentJson() {
|
|
1198
2051
|
if (!bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
1199
2052
|
return {};
|
|
2053
|
+
if (!prepareBridgeForExternalContentRead()) {
|
|
2054
|
+
return bridgeRef.current.getCachedJson() ?? {};
|
|
2055
|
+
}
|
|
1200
2056
|
return bridgeRef.current.getJson();
|
|
1201
2057
|
},
|
|
1202
2058
|
getTextContent() {
|
|
1203
2059
|
if (!bridgeRef.current || bridgeRef.current.isDestroyed)
|
|
1204
2060
|
return '';
|
|
2061
|
+
if (!prepareBridgeForExternalContentRead()) {
|
|
2062
|
+
return (bridgeRef.current.getCachedHtml() ?? '').replace(/<[^>]+>/g, '');
|
|
2063
|
+
}
|
|
1205
2064
|
return bridgeRef.current.getHtml().replace(/<[^>]+>/g, '');
|
|
1206
2065
|
},
|
|
1207
2066
|
async getCaretRect() {
|
|
@@ -1227,7 +2086,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1227
2086
|
return false;
|
|
1228
2087
|
return bridgeRef.current.canRedo();
|
|
1229
2088
|
},
|
|
1230
|
-
}), [insertImage, runAndApply]);
|
|
2089
|
+
}), [insertImage, prepareBridgeForExternalContentRead, runAndApply]);
|
|
1231
2090
|
const activeMentionTrigger = mentionQueryEvent?.trigger || resolveMentionTrigger(addons);
|
|
1232
2091
|
const activeMentionSuggestions = (0, react_1.useMemo)(() => isFocused && mentionQueryEvent != null && addons?.mentions != null
|
|
1233
2092
|
? filterMentionSuggestions(addons.mentions.suggestions ?? [], mentionQueryEvent.query, activeMentionTrigger)
|
|
@@ -1247,6 +2106,9 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1247
2106
|
suggestion,
|
|
1248
2107
|
attrs: resolveMentionSuggestionAttrs(suggestion, activeMentionTrigger),
|
|
1249
2108
|
range: mentionQueryEvent.range,
|
|
2109
|
+
...(typeof mentionQueryEvent.documentVersion === 'number'
|
|
2110
|
+
? { documentVersion: mentionQueryEvent.documentVersion }
|
|
2111
|
+
: {}),
|
|
1250
2112
|
};
|
|
1251
2113
|
const attrs = resolveMentionSelectionAttrs(selectionEvent);
|
|
1252
2114
|
let resolvedTheme;
|
|
@@ -1414,8 +2276,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1414
2276
|
'rgba(0, 122, 255, 0.12)')
|
|
1415
2277
|
: (suggestionTheme?.backgroundColor ??
|
|
1416
2278
|
'#F2F2F7'),
|
|
1417
|
-
borderColor: suggestionTheme?.borderColor ??
|
|
1418
|
-
'transparent',
|
|
2279
|
+
borderColor: suggestionTheme?.borderColor ?? 'transparent',
|
|
1419
2280
|
borderWidth: suggestionTheme?.borderWidth ?? 0,
|
|
1420
2281
|
borderRadius: suggestionTheme?.borderRadius ?? 12,
|
|
1421
2282
|
},
|
|
@@ -1465,7 +2326,7 @@ exports.NativeRichTextEditor = (0, react_1.forwardRef)(function NativeRichTextEd
|
|
|
1465
2326
|
}), onToggleStrike: () => runAndApply(() => bridgeRef.current?.toggleMark('strike') ?? null, {
|
|
1466
2327
|
skipNativeApplyIfContentUnchanged: true,
|
|
1467
2328
|
}), 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) })) }));
|
|
1468
|
-
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, editorUpdateRevision: pendingNativeUpdate.revision, onEditorUpdate: handleUpdate, onSelectionChange: handleSelectionChange, onFocusChange: handleFocusChange, onContentHeightChange: handleContentHeightChange, onToolbarAction: handleToolbarAction, onAddonEvent: handleAddonEvent }, DEV_NATIVE_VIEW_KEY), shouldRenderJsToolbar && jsToolbar] }));
|
|
2329
|
+
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] }));
|
|
1469
2330
|
});
|
|
1470
2331
|
const styles = react_native_1.StyleSheet.create({
|
|
1471
2332
|
container: {
|