@apollohg/react-native-rich-text-editor 2.0.0 → 2.0.2
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 +8 -116
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/android/build.gradle +3 -0
- package/android/src/main/java/com/apollohg/editor/EditorEditTextImages.kt +25 -0
- package/android/src/main/java/com/apollohg/editor/EditorV2RenderValidation.kt +1 -0
- package/android/src/main/java/com/apollohg/editor/ImageResizeOverlayView.kt +101 -33
- package/android/src/main/java/com/apollohg/editor/RenderMediaSpans.kt +15 -3
- package/android/src/main/java/com/apollohg/editor/RichTextEditorView.kt +14 -0
- package/android/src/main/java/com/apollohg/editor/viewer/AndroidProseLayoutEngine.kt +1 -1
- package/app.plugin.js +42 -39
- package/dist/AtomHost.js +18 -11
- package/dist/EditorAddon.js +4 -2
- package/dist/EditorAddonNormalization.js +17 -9
- package/dist/EditorMentionThemeNormalization.js +6 -3
- package/dist/EditorMentionThemeValidation.js +28 -11
- package/dist/EditorStyleSheetNormalization.js +85 -38
- package/dist/EditorStyleSheetTypes.d.ts +1 -1
- package/dist/EditorTheme.d.ts +4 -0
- package/dist/EditorTheme.js +5 -3
- package/dist/EditorToolbarComponent.d.ts +1 -1
- package/dist/EditorToolbarComponent.js +1 -1
- package/dist/EditorToolbarRegistry.js +5 -5
- package/dist/EditorToolbarTypes.d.ts +12 -12
- package/dist/EditorToolbarVisuals.js +1 -1
- package/dist/ExternalTextComposition.js +89 -43
- package/dist/ImageLoadingPolicy.d.ts +1 -1
- package/dist/NativeEditorBoundaryError.d.ts +7 -7
- package/dist/NativeEditorBoundaryError.js +9 -5
- package/dist/NativeEditorCollaborationTransport.d.ts +7 -7
- package/dist/NativeEditorCollaborationTransport.js +28 -15
- package/dist/NativeEditorCreateConfig.js +11 -6
- package/dist/NativeEditorCreateJson.js +51 -25
- package/dist/NativeEditorCreateValidation.js +11 -6
- package/dist/NativeEditorDocumentBridge.d.ts +1 -1
- package/dist/NativeEditorDocumentBridge.js +32 -18
- package/dist/NativeEditorDocumentHandle.d.ts +4 -4
- package/dist/NativeEditorDocumentHandle.js +1 -1
- package/dist/NativeEditorLocalAwareness.js +25 -13
- package/dist/NativeEditorNativeModule.d.ts +8 -1
- package/dist/NativeEditorNativeModule.js +7 -5
- package/dist/NativeEditorRenderNormalization.js +66 -25
- package/dist/NativeEditorResultNormalization.js +53 -29
- package/dist/NativeEditorTypes.d.ts +10 -10
- package/dist/NativeEditorV2Decimal.js +6 -3
- package/dist/NativeProseViewer.js +11 -3
- package/dist/ResourceLimits.d.ts +2 -2
- package/dist/ResourceLimits.js +7 -2
- package/dist/RichTextEditor.js +1 -1
- package/dist/RichTextEditorNativeTypes.d.ts +1 -1
- package/dist/RichTextEditorNativeView.d.ts +1 -3
- package/dist/RichTextEditorSerialization.js +24 -14
- package/dist/RichTextEditorTypes.d.ts +1 -1
- package/dist/YjsCollaboration.d.ts +7 -7
- package/dist/YjsCollaboration.js +42 -26
- package/dist/addons.d.ts +4 -4
- package/dist/addons.js +3 -3
- package/dist/atomInstances.js +6 -3
- package/dist/atomUpdates.js +7 -4
- package/dist/atoms.js +20 -12
- package/dist/attributeValidation.js +55 -24
- package/dist/contentExpression.js +80 -42
- package/dist/listMarkers.d.ts +1 -1
- package/dist/listMarkers.js +1 -1
- package/dist/schemaDefinition.d.ts +1 -1
- package/dist/schemaDefinition.js +23 -14
- package/dist/schemaDocument.js +1 -1
- package/dist/schemaDocumentConstruction.js +25 -14
- package/dist/schemaNormalization.js +51 -29
- package/dist/schemaPresets.d.ts +1 -1
- package/dist/schemaPresets.js +9 -4
- package/dist/schemaResolution.js +46 -25
- package/dist/specs/PreparedProseViewerNativeComponent.d.ts +4 -0
- package/dist/useEditorToolbarInteractions.d.ts +2 -2
- package/dist/useEditorToolbarInteractions.js +45 -23
- package/dist/useEditorToolbarItems.d.ts +1 -1
- package/dist/useEditorToolbarItems.js +4 -3
- package/dist/useEditorToolbarPresentation.d.ts +3 -3
- package/dist/useEditorToolbarPresentation.js +4 -4
- package/dist/useEditorToolbarState.d.ts +1 -1
- package/dist/useEditorToolbarState.js +1 -1
- package/dist/useFocusPreservingFrames.js +11 -8
- package/dist/useNativeEditor.d.ts +1 -1
- package/dist/useNativeEditor.js +21 -11
- package/dist/useRichTextEditorCommands.d.ts +2 -2
- package/dist/useRichTextEditorCommands.js +59 -29
- package/dist/useRichTextEditorEvents.d.ts +3 -3
- package/dist/useRichTextEditorEvents.js +75 -32
- package/dist/useRichTextEditorMentions.d.ts +4 -4
- package/dist/useRichTextEditorMentions.js +48 -29
- package/dist/useRichTextEditorPresentation.d.ts +4 -4
- package/dist/useRichTextEditorPresentation.js +25 -23
- package/dist/useRichTextEditorState.d.ts +3 -3
- package/dist/useRichTextEditorState.js +20 -15
- package/dist/useRichTextEditorUpdates.d.ts +1 -1
- package/dist/useRichTextEditorUpdates.js +99 -41
- package/dist/useViewerAtoms.js +63 -36
- 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/EditorInteractionOverlays.swift +114 -122
- package/ios/EditorLayoutManager.swift +13 -3
- package/ios/EditorStyleSheet.swift +12 -1
- package/ios/EditorTextView+Images.swift +32 -10
- package/ios/EditorTextView.swift +1 -1
- package/ios/EditorV2Adapter+RenderValidation.swift +2 -2
- package/ios/NativeToolbar+ButtonStyle.swift +17 -5
- package/ios/NativeToolbar+Diagnostics.swift +15 -0
- package/ios/RenderBridge+Atoms.swift +0 -1
- package/ios/RenderBridge+Attachments.swift +0 -29
- package/ios/RichTextEditorView.swift +4 -12
- package/ios/Viewer/CoreTextProseLayoutEngine+AttributedText.swift +3 -2
- package/package.json +11 -3
- package/react-native.config.js +1 -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/libeditor_core.so +0 -0
- package/rust/android/x86_64/libeditor_core.so +0 -0
- package/src/AtomHost.tsx +58 -28
- package/src/EditorAddon.ts +18 -8
- package/src/EditorAddonNormalization.ts +40 -11
- package/src/EditorMentionThemeNormalization.ts +15 -4
- package/src/EditorMentionThemeValidation.ts +51 -14
- package/src/EditorStyleSheet.ts +1 -0
- package/src/EditorStyleSheetNormalization.ts +195 -64
- package/src/EditorStyleSheetTypes.ts +1 -1
- package/src/EditorTheme.ts +13 -5
- package/src/EditorToolbarComponent.tsx +2 -1
- package/src/EditorToolbarRegistry.tsx +23 -13
- package/src/EditorToolbarTypes.tsx +12 -12
- package/src/EditorToolbarVisuals.tsx +6 -3
- package/src/EditorUpdateRevision.ts +1 -0
- package/src/ExternalTextComposition.ts +259 -49
- package/src/ImageLoadingPolicy.ts +3 -1
- package/src/NativeEditorBoundaryError.ts +38 -11
- package/src/NativeEditorCollaborationTransport.ts +108 -27
- package/src/NativeEditorCreateConfig.ts +92 -19
- package/src/NativeEditorCreateJson.ts +163 -26
- package/src/NativeEditorCreateValidation.ts +33 -12
- package/src/NativeEditorDocumentBridge.ts +111 -19
- package/src/NativeEditorDocumentHandle.ts +9 -4
- package/src/NativeEditorLocalAwareness.ts +70 -15
- package/src/NativeEditorNativeModule.ts +13 -9
- package/src/NativeEditorRenderNormalization.ts +128 -29
- package/src/NativeEditorResultNormalization.ts +143 -32
- package/src/NativeEditorTypes.ts +12 -11
- package/src/NativeEditorV2Decimal.ts +12 -3
- package/src/NativeProseViewer.tsx +46 -16
- package/src/ResourceLimits.ts +15 -8
- package/src/RichTextEditor.tsx +3 -1
- package/src/RichTextEditorNativeTypes.tsx +1 -1
- package/src/RichTextEditorNativeView.tsx +2 -8
- package/src/RichTextEditorSerialization.tsx +70 -24
- package/src/RichTextEditorTypes.tsx +1 -1
- package/src/YjsCollaboration.ts +143 -47
- package/src/addons.ts +12 -8
- package/src/atomInstances.ts +25 -5
- package/src/atomUpdates.ts +23 -6
- package/src/atoms.ts +85 -18
- package/src/attributeValidation.ts +97 -33
- package/src/contentExpression.ts +218 -63
- package/src/listMarkers.ts +1 -1
- package/src/schemaDefinition.ts +82 -20
- package/src/schemaDocument.ts +15 -1
- package/src/schemaDocumentConstruction.ts +80 -16
- package/src/schemaNormalization.ts +155 -41
- package/src/schemaPresets.ts +37 -31
- package/src/schemaResolution.ts +126 -27
- package/src/specs/PreparedProseViewerNativeComponent.ts +4 -2
- package/src/useEditorToolbarInteractions.tsx +85 -36
- package/src/useEditorToolbarItems.tsx +50 -22
- package/src/useEditorToolbarPresentation.tsx +81 -58
- package/src/useEditorToolbarState.tsx +8 -6
- package/src/useFocusPreservingFrames.ts +43 -15
- package/src/useNativeEditor.ts +111 -51
- package/src/useRichTextEditorCommands.tsx +127 -54
- package/src/useRichTextEditorEvents.tsx +144 -42
- package/src/useRichTextEditorMentions.tsx +118 -37
- package/src/useRichTextEditorPresentation.tsx +128 -114
- package/src/useRichTextEditorState.tsx +76 -40
- package/src/useRichTextEditorUpdates.tsx +207 -56
- package/src/useViewerAtoms.tsx +162 -66
|
@@ -22,7 +22,7 @@ function useRichTextEditorCommands(context) {
|
|
|
22
22
|
if (!editableRef.current) {
|
|
23
23
|
throw new atomInstances_1.AtomUpdateAttrsError('not-applicable', 'The editor is not editable');
|
|
24
24
|
}
|
|
25
|
-
const instance = atomStateRef.current.instances.find(
|
|
25
|
+
const instance = atomStateRef.current.instances.find(candidate => candidate.key === atomKey && candidate.nodeType === nodeType);
|
|
26
26
|
if (instance == null ||
|
|
27
27
|
(!hasStableKey &&
|
|
28
28
|
(atomStateRef.current.documentVersion !== expectedDocumentVersion ||
|
|
@@ -60,20 +60,29 @@ function useRichTextEditorCommands(context) {
|
|
|
60
60
|
throw new atomInstances_1.AtomUpdateAttrsError('engine-error', 'Unexpected atom update outcome');
|
|
61
61
|
}
|
|
62
62
|
afterLocalEngineMutation();
|
|
63
|
-
}, [afterLocalEngineMutation,
|
|
63
|
+
}, [afterLocalEngineMutation,
|
|
64
|
+
atomStateRef,
|
|
65
|
+
bridge,
|
|
66
|
+
document,
|
|
67
|
+
documentHandle.isDestroyed,
|
|
68
|
+
latestRevisionRef,
|
|
69
|
+
refreshAtomsFromUpdate]);
|
|
64
70
|
const runAtomAction = (0, react_1.useCallback)(async (owner, instance, documentVersion, action) => {
|
|
65
71
|
if (owner !== atomOwnerRef.current ||
|
|
66
72
|
documentHandle.isDestroyed ||
|
|
67
|
-
latestRevisionRef.current == null)
|
|
73
|
+
latestRevisionRef.current == null) {
|
|
68
74
|
throw new atomInstances_1.AtomUpdateAttrsError('not-ready', 'The editor is not ready.');
|
|
69
|
-
|
|
75
|
+
}
|
|
76
|
+
if (action === 'delete' && !editableRef.current) {
|
|
70
77
|
throw new atomInstances_1.AtomUpdateAttrsError('not-applicable', 'The editor is not editable.');
|
|
71
|
-
|
|
78
|
+
}
|
|
79
|
+
const current = atomStateRef.current.instances.find(candidate => candidate.key === instance.key && candidate.nodeType === instance.nodeType);
|
|
72
80
|
if (!current ||
|
|
73
81
|
(!instance.hasStableKey &&
|
|
74
82
|
(documentVersion !== atomStateRef.current.documentVersion ||
|
|
75
|
-
current.docPos !== instance.docPos)))
|
|
83
|
+
current.docPos !== instance.docPos))) {
|
|
76
84
|
throw new atomInstances_1.AtomUpdateAttrsError('not-applicable', 'The atom no longer exists.');
|
|
85
|
+
}
|
|
77
86
|
try {
|
|
78
87
|
const baseDocumentRevision = latestRevisionRef.current;
|
|
79
88
|
const selection = bridge.setSelection({
|
|
@@ -84,27 +93,31 @@ function useRichTextEditorCommands(context) {
|
|
|
84
93
|
edge: action === 'select' || action === 'delete' ? 'node' : action,
|
|
85
94
|
},
|
|
86
95
|
});
|
|
87
|
-
if (selection.type !== 'transaction')
|
|
96
|
+
if (selection.type !== 'transaction') {
|
|
88
97
|
throw new atomInstances_1.AtomUpdateAttrsError('not-applicable', 'The atom could not be selected.');
|
|
98
|
+
}
|
|
89
99
|
if (action === 'delete') {
|
|
90
100
|
const outcome = bridge.applyCommand({
|
|
91
101
|
baseDocumentRevision,
|
|
92
102
|
command: { type: 'deleteBackward' },
|
|
93
103
|
});
|
|
94
|
-
if (outcome.type !== 'transaction')
|
|
104
|
+
if (outcome.type !== 'transaction') {
|
|
95
105
|
throw new atomInstances_1.AtomUpdateAttrsError('not-applicable', 'The atom could not be deleted.');
|
|
106
|
+
}
|
|
96
107
|
afterLocalEngineMutation();
|
|
97
108
|
}
|
|
98
109
|
else {
|
|
99
110
|
pushEngineUpdateToView();
|
|
100
111
|
document.refresh();
|
|
101
|
-
if (action !== 'select')
|
|
112
|
+
if (action !== 'select') {
|
|
102
113
|
nativeViewRef.current?.focus?.();
|
|
114
|
+
}
|
|
103
115
|
}
|
|
104
116
|
}
|
|
105
117
|
catch (error) {
|
|
106
|
-
if (error instanceof atomInstances_1.AtomUpdateAttrsError)
|
|
118
|
+
if (error instanceof atomInstances_1.AtomUpdateAttrsError) {
|
|
107
119
|
throw error;
|
|
120
|
+
}
|
|
108
121
|
if ((0, RichTextEditorSerialization_1.isRevisionMismatchError)(error)) {
|
|
109
122
|
refreshAtomsFromUpdate(bridge.renderUpdate());
|
|
110
123
|
document.refresh();
|
|
@@ -112,14 +125,15 @@ function useRichTextEditorCommands(context) {
|
|
|
112
125
|
}
|
|
113
126
|
throw new atomInstances_1.AtomUpdateAttrsError('engine-error', error instanceof Error ? error.message : String(error));
|
|
114
127
|
}
|
|
115
|
-
}, [
|
|
116
|
-
|
|
128
|
+
}, [afterLocalEngineMutation,
|
|
129
|
+
atomStateRef,
|
|
117
130
|
bridge,
|
|
118
131
|
document,
|
|
119
|
-
documentHandle,
|
|
132
|
+
documentHandle.isDestroyed,
|
|
133
|
+
latestRevisionRef,
|
|
134
|
+
nativeViewRef,
|
|
120
135
|
pushEngineUpdateToView,
|
|
121
|
-
refreshAtomsFromUpdate
|
|
122
|
-
]);
|
|
136
|
+
refreshAtomsFromUpdate]);
|
|
123
137
|
const runEngineMutation = (0, react_1.useCallback)((invoke) => {
|
|
124
138
|
if (!editableRef.current) {
|
|
125
139
|
throw new NativeEditorBoundaryError_1.NativeEditorOperationError({
|
|
@@ -151,15 +165,16 @@ function useRichTextEditorCommands(context) {
|
|
|
151
165
|
throw error;
|
|
152
166
|
}
|
|
153
167
|
afterLocalEngineMutation();
|
|
154
|
-
}, [afterLocalEngineMutation, document]);
|
|
168
|
+
}, [afterLocalEngineMutation, document, latestRevisionRef]);
|
|
155
169
|
const applyEngineCommand = (0, react_1.useCallback)((command) => {
|
|
156
|
-
runEngineMutation(
|
|
170
|
+
runEngineMutation(baseDocumentRevision => bridge.applyCommand({ command, baseDocumentRevision }));
|
|
157
171
|
}, [bridge, runEngineMutation]);
|
|
158
172
|
const commandToggleMark = (0, react_1.useCallback)((markType) => applyEngineCommand({ type: 'toggleMark', markType }), [applyEngineCommand]);
|
|
159
173
|
const commandSetLink = (0, react_1.useCallback)((href) => {
|
|
160
174
|
const trimmedHref = href.trim();
|
|
161
|
-
if (!trimmedHref)
|
|
175
|
+
if (!trimmedHref) {
|
|
162
176
|
return;
|
|
177
|
+
}
|
|
163
178
|
applyEngineCommand({
|
|
164
179
|
type: 'setMark',
|
|
165
180
|
markType: 'link',
|
|
@@ -183,7 +198,7 @@ function useRichTextEditorCommands(context) {
|
|
|
183
198
|
? 'list_item'
|
|
184
199
|
: 'listItem',
|
|
185
200
|
});
|
|
186
|
-
}, [applyEngineCommand]);
|
|
201
|
+
}, [activeStateRef, applyEngineCommand]);
|
|
187
202
|
const commandIndentListItem = (0, react_1.useCallback)(() => applyEngineCommand({ type: 'indentListItem' }), [applyEngineCommand]);
|
|
188
203
|
const commandOutdentListItem = (0, react_1.useCallback)(() => applyEngineCommand({ type: 'outdentListItem' }), [applyEngineCommand]);
|
|
189
204
|
const commandInsertNode = (0, react_1.useCallback)((nodeType) => applyEngineCommand({ type: 'insertNode', nodeType }), [applyEngineCommand]);
|
|
@@ -194,9 +209,10 @@ function useRichTextEditorCommands(context) {
|
|
|
194
209
|
});
|
|
195
210
|
}, [applyEngineCommand, documentDescriptor]);
|
|
196
211
|
const commandInsertText = (0, react_1.useCallback)((text) => {
|
|
197
|
-
if (!text)
|
|
212
|
+
if (!text) {
|
|
198
213
|
return;
|
|
199
|
-
|
|
214
|
+
}
|
|
215
|
+
runEngineMutation(baseDocumentRevision => bridge.applyInput({ text, baseDocumentRevision }));
|
|
200
216
|
}, [bridge, runEngineMutation]);
|
|
201
217
|
const commandInsertContentHtml = (0, react_1.useCallback)((html) => applyEngineCommand({ type: 'insertContentHtml', html }), [applyEngineCommand]);
|
|
202
218
|
const commandInsertContentJson = (0, react_1.useCallback)((doc) => applyEngineCommand({ type: 'insertContentJson', json: doc }), [applyEngineCommand]);
|
|
@@ -209,13 +225,17 @@ function useRichTextEditorCommands(context) {
|
|
|
209
225
|
setLink: commandSetLink,
|
|
210
226
|
unsetLink: commandUnsetLink,
|
|
211
227
|
});
|
|
212
|
-
}, [
|
|
228
|
+
}, [activeStateRef,
|
|
229
|
+
commandSetLink,
|
|
230
|
+
commandUnsetLink,
|
|
231
|
+
onRequestLinkRef,
|
|
232
|
+
selectionRef]);
|
|
213
233
|
const openImageRequest = (0, react_1.useCallback)(() => {
|
|
214
234
|
onRequestImageRef.current?.({
|
|
215
235
|
selection: selectionRef.current,
|
|
216
236
|
insertImage: commandInsertImage,
|
|
217
237
|
});
|
|
218
|
-
}, [commandInsertImage]);
|
|
238
|
+
}, [commandInsertImage, onRequestImageRef, selectionRef]);
|
|
219
239
|
(0, react_1.useImperativeHandle)(ref, () => ({
|
|
220
240
|
focus() {
|
|
221
241
|
nativeViewRef.current?.focus?.();
|
|
@@ -254,8 +274,9 @@ function useRichTextEditorCommands(context) {
|
|
|
254
274
|
getTextContent: document.getTextContent,
|
|
255
275
|
async getCaretRect() {
|
|
256
276
|
const nativeView = nativeViewRef.current;
|
|
257
|
-
if (!nativeView?.getCaretRect)
|
|
277
|
+
if (!nativeView?.getCaretRect) {
|
|
258
278
|
return null;
|
|
279
|
+
}
|
|
259
280
|
const raw = await Promise.resolve(nativeView.getCaretRect());
|
|
260
281
|
return (0, RichTextEditorSerialization_1.parseCaretRectJson)(raw);
|
|
261
282
|
},
|
|
@@ -263,9 +284,7 @@ function useRichTextEditorCommands(context) {
|
|
|
263
284
|
redo: document.redo,
|
|
264
285
|
canUndo: document.canUndo,
|
|
265
286
|
canRedo: document.canRedo,
|
|
266
|
-
}), [
|
|
267
|
-
document,
|
|
268
|
-
commandToggleMark,
|
|
287
|
+
}), [commandToggleMark,
|
|
269
288
|
commandSetLink,
|
|
270
289
|
commandUnsetLink,
|
|
271
290
|
commandToggleBlockquote,
|
|
@@ -278,9 +297,20 @@ function useRichTextEditorCommands(context) {
|
|
|
278
297
|
commandInsertText,
|
|
279
298
|
commandInsertContentHtml,
|
|
280
299
|
commandInsertContentJson,
|
|
281
|
-
|
|
300
|
+
document.setContent,
|
|
301
|
+
document.setContentJson,
|
|
302
|
+
document.clearContent,
|
|
303
|
+
document.getContent,
|
|
304
|
+
document.getContentJson,
|
|
305
|
+
document.getIsEmpty,
|
|
306
|
+
document.getTextContent,
|
|
307
|
+
document.undo,
|
|
308
|
+
document.redo,
|
|
309
|
+
document.canUndo,
|
|
310
|
+
document.canRedo,
|
|
311
|
+
nativeViewRef,
|
|
282
312
|
externalCompositionManager,
|
|
283
|
-
|
|
313
|
+
editable]);
|
|
284
314
|
return {
|
|
285
315
|
openLinkRequest,
|
|
286
316
|
openImageRequest,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type NativeSyntheticEvent } from 'react-native';
|
|
2
|
-
import { useRichTextEditorState } from './useRichTextEditorState';
|
|
3
|
-
import { useRichTextEditorUpdates } from './useRichTextEditorUpdates';
|
|
4
|
-
import { useRichTextEditorCommands } from './useRichTextEditorCommands';
|
|
2
|
+
import { type useRichTextEditorState } from './useRichTextEditorState';
|
|
3
|
+
import { type useRichTextEditorUpdates } from './useRichTextEditorUpdates';
|
|
4
|
+
import { type useRichTextEditorCommands } from './useRichTextEditorCommands';
|
|
5
5
|
import { type NativeUpdateEvent, type NativeErrorEvent, type NativeExternalTextCompositionEvent, type NativeSelectionEvent, type NativeFocusEvent, type NativeContentHeightEvent, type NativeAtomLayoutEvent, type NativeToolbarActionEvent } from './RichTextEditorNativeTypes';
|
|
6
6
|
export declare function useRichTextEditorEvents(context: Pick<ReturnType<typeof useRichTextEditorState>, 'editorId' | 'documentHandle' | 'lastAcceptedNativeCommitRevisionRef' | 'lastNativeDrivenRevisionRef' | 'document' | 'onLocalCommitRef' | 'nativeErrorBindingRef' | 'nativeErrorBinding' | 'externalCompositionManager' | 'scalarSelectionRef' | 'selectionRef' | 'onSelectionChangeRef' | 'isFocusedRef' | 'toolbarFrameOwnerId' | 'setIsFocused' | 'onFocusRef' | 'onBlurRef' | 'heightBehavior' | 'setAutoGrowHeight' | 'setAtomContentWidth' | 'setNativeAtomViewport' | 'setAtomPositions' | 'onToolbarActionRef'> & Pick<ReturnType<typeof useRichTextEditorUpdates>, 'refreshAtomsFromUpdate' | 'applyTypedUpdateState' | 'applyUpdateState' | 'updateAtomSelection'> & Pick<ReturnType<typeof useRichTextEditorCommands>, 'openLinkRequest' | 'openImageRequest'>): {
|
|
7
7
|
isForThisEditor: (payload: {
|
|
@@ -10,11 +10,13 @@ function useRichTextEditorEvents(context) {
|
|
|
10
10
|
const { editorId, documentHandle, lastAcceptedNativeCommitRevisionRef, lastNativeDrivenRevisionRef, refreshAtomsFromUpdate, applyTypedUpdateState, document, onLocalCommitRef, nativeErrorBindingRef, nativeErrorBinding, externalCompositionManager, scalarSelectionRef, applyUpdateState, selectionRef, updateAtomSelection, onSelectionChangeRef, isFocusedRef, toolbarFrameOwnerId, setIsFocused, onFocusRef, onBlurRef, heightBehavior, setAutoGrowHeight, setAtomContentWidth, setNativeAtomViewport, setAtomPositions, openLinkRequest, openImageRequest, onToolbarActionRef, } = context;
|
|
11
11
|
const isForThisEditor = (0, react_1.useCallback)((payload) => payload.editorId === editorId, [editorId]);
|
|
12
12
|
const handleEditorUpdate = (0, react_1.useCallback)((event) => {
|
|
13
|
-
if (documentHandle.isDestroyed)
|
|
13
|
+
if (documentHandle.isDestroyed) {
|
|
14
14
|
return;
|
|
15
|
+
}
|
|
15
16
|
const accepted = (0, RichTextEditorSerialization_1.acceptNativeCommitPayload)(event.nativeEvent, documentHandle.editorId, lastAcceptedNativeCommitRevisionRef.current);
|
|
16
|
-
if (accepted == null)
|
|
17
|
+
if (accepted == null) {
|
|
17
18
|
return;
|
|
19
|
+
}
|
|
18
20
|
// Record both native-scoped revisions before any observable
|
|
19
21
|
// state/callback/refresh work. This makes duplicate delivery and
|
|
20
22
|
// the handle's same-revision signal deterministic.
|
|
@@ -25,10 +27,18 @@ function useRichTextEditorEvents(context) {
|
|
|
25
27
|
// The adapter already committed; re-read for content callbacks.
|
|
26
28
|
document.refresh();
|
|
27
29
|
onLocalCommitRef.current?.();
|
|
28
|
-
}, [applyTypedUpdateState,
|
|
30
|
+
}, [applyTypedUpdateState,
|
|
31
|
+
document,
|
|
32
|
+
documentHandle.editorId,
|
|
33
|
+
documentHandle.isDestroyed,
|
|
34
|
+
lastAcceptedNativeCommitRevisionRef,
|
|
35
|
+
lastNativeDrivenRevisionRef,
|
|
36
|
+
onLocalCommitRef,
|
|
37
|
+
refreshAtomsFromUpdate]);
|
|
29
38
|
const admitNativeBindingEvent = (0, react_1.useCallback)((payload) => {
|
|
30
|
-
if (!(0, RichTextEditorSerialization_1.isRecord)(payload))
|
|
39
|
+
if (!(0, RichTextEditorSerialization_1.isRecord)(payload)) {
|
|
31
40
|
return null;
|
|
41
|
+
}
|
|
32
42
|
const currentBinding = nativeErrorBindingRef.current;
|
|
33
43
|
if (currentBinding !== nativeErrorBinding ||
|
|
34
44
|
!currentBinding.mounted ||
|
|
@@ -45,21 +55,24 @@ function useRichTextEditorEvents(context) {
|
|
|
45
55
|
return null;
|
|
46
56
|
}
|
|
47
57
|
return currentBinding;
|
|
48
|
-
}, [nativeErrorBinding]);
|
|
58
|
+
}, [nativeErrorBinding, nativeErrorBindingRef]);
|
|
49
59
|
const handleEditorError = (0, react_1.useCallback)((event) => {
|
|
50
60
|
const payload = event?.nativeEvent;
|
|
51
61
|
const binding = admitNativeBindingEvent(payload);
|
|
52
|
-
if (binding == null || !(0, RichTextEditorSerialization_1.isRecord)(payload))
|
|
62
|
+
if (binding == null || !(0, RichTextEditorSerialization_1.isRecord)(payload)) {
|
|
53
63
|
return;
|
|
64
|
+
}
|
|
54
65
|
binding.handle.bridge._emitAutonomousError(payload.error);
|
|
55
66
|
}, [admitNativeBindingEvent]);
|
|
56
67
|
const handleExternalTextCompositionEnd = (0, react_1.useCallback)((event) => {
|
|
57
68
|
const payload = event?.nativeEvent;
|
|
58
69
|
const binding = admitNativeBindingEvent(payload);
|
|
59
|
-
if (binding == null || !(0, RichTextEditorSerialization_1.isRecord)(payload))
|
|
70
|
+
if (binding == null || !(0, RichTextEditorSerialization_1.isRecord)(payload)) {
|
|
60
71
|
return;
|
|
61
|
-
|
|
72
|
+
}
|
|
73
|
+
if (typeof payload.resultJson !== 'string') {
|
|
62
74
|
return;
|
|
75
|
+
}
|
|
63
76
|
try {
|
|
64
77
|
externalCompositionManager.handleNativeEnd(binding.editorId, payload.resultJson);
|
|
65
78
|
}
|
|
@@ -68,8 +81,9 @@ function useRichTextEditorEvents(context) {
|
|
|
68
81
|
}
|
|
69
82
|
}, [admitNativeBindingEvent, externalCompositionManager]);
|
|
70
83
|
const handleSelectionChange = (0, react_1.useCallback)((event) => {
|
|
71
|
-
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent))
|
|
84
|
+
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent)) {
|
|
72
85
|
return;
|
|
86
|
+
}
|
|
73
87
|
const { anchor, head, stateJson } = event.nativeEvent;
|
|
74
88
|
scalarSelectionRef.current = { anchor, head };
|
|
75
89
|
let selection = { type: 'text', anchor, head };
|
|
@@ -81,10 +95,17 @@ function useRichTextEditorEvents(context) {
|
|
|
81
95
|
selectionRef.current = selection;
|
|
82
96
|
updateAtomSelection(selection);
|
|
83
97
|
onSelectionChangeRef.current?.(selection);
|
|
84
|
-
}, [applyUpdateState,
|
|
98
|
+
}, [applyUpdateState,
|
|
99
|
+
documentHandle.isDestroyed,
|
|
100
|
+
isForThisEditor,
|
|
101
|
+
onSelectionChangeRef,
|
|
102
|
+
scalarSelectionRef,
|
|
103
|
+
selectionRef,
|
|
104
|
+
updateAtomSelection]);
|
|
85
105
|
const handleFocusChange = (0, react_1.useCallback)((event) => {
|
|
86
|
-
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent))
|
|
106
|
+
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent)) {
|
|
87
107
|
return;
|
|
108
|
+
}
|
|
88
109
|
const focused = event.nativeEvent.isFocused;
|
|
89
110
|
const wasFocused = isFocusedRef.current;
|
|
90
111
|
isFocusedRef.current = focused;
|
|
@@ -96,37 +117,49 @@ function useRichTextEditorEvents(context) {
|
|
|
96
117
|
else if (!focused && wasFocused) {
|
|
97
118
|
onBlurRef.current?.();
|
|
98
119
|
}
|
|
99
|
-
}, [documentHandle,
|
|
120
|
+
}, [documentHandle.isDestroyed,
|
|
121
|
+
isFocusedRef,
|
|
122
|
+
isForThisEditor,
|
|
123
|
+
onBlurRef,
|
|
124
|
+
onFocusRef,
|
|
125
|
+
setIsFocused,
|
|
126
|
+
toolbarFrameOwnerId]);
|
|
100
127
|
const handleContentHeightChange = (0, react_1.useCallback)((event) => {
|
|
101
|
-
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent))
|
|
128
|
+
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent)) {
|
|
102
129
|
return;
|
|
103
|
-
|
|
130
|
+
}
|
|
131
|
+
if (heightBehavior !== 'autoGrow') {
|
|
104
132
|
return;
|
|
133
|
+
}
|
|
105
134
|
const density = react_native_1.Platform.OS === 'android' ? react_native_1.PixelRatio.get() : 1;
|
|
106
135
|
const nextHeight = Math.ceil(event.nativeEvent.contentHeight / density);
|
|
107
|
-
if (!(nextHeight > 0))
|
|
136
|
+
if (!(nextHeight > 0)) {
|
|
108
137
|
return;
|
|
109
|
-
|
|
110
|
-
|
|
138
|
+
}
|
|
139
|
+
setAutoGrowHeight(prev => (prev === nextHeight ? prev : nextHeight));
|
|
140
|
+
}, [documentHandle.isDestroyed, heightBehavior, isForThisEditor, setAutoGrowHeight]);
|
|
111
141
|
const handleAtomLayout = (0, react_1.useCallback)((event) => {
|
|
112
|
-
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent))
|
|
142
|
+
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent)) {
|
|
113
143
|
return;
|
|
144
|
+
}
|
|
114
145
|
const width = event.nativeEvent.width;
|
|
115
|
-
if (!Number.isFinite(width) || width < 0)
|
|
146
|
+
if (!Number.isFinite(width) || width < 0) {
|
|
116
147
|
return;
|
|
117
|
-
|
|
148
|
+
}
|
|
149
|
+
setAtomContentWidth(current => (current === width ? current : width));
|
|
118
150
|
const viewport = event.nativeEvent.viewport;
|
|
119
151
|
if (viewport &&
|
|
120
152
|
Number.isFinite(viewport.y) &&
|
|
121
153
|
Number.isFinite(viewport.height) &&
|
|
122
154
|
viewport.height >= 0) {
|
|
123
|
-
setNativeAtomViewport(
|
|
155
|
+
setNativeAtomViewport(previous => previous?.y === viewport.y && previous.height === viewport.height
|
|
124
156
|
? previous
|
|
125
157
|
: viewport);
|
|
126
158
|
}
|
|
127
159
|
const positions = event.nativeEvent.positions;
|
|
128
|
-
if (!Array.isArray(positions))
|
|
160
|
+
if (!Array.isArray(positions)) {
|
|
129
161
|
return;
|
|
162
|
+
}
|
|
130
163
|
const next = new Map();
|
|
131
164
|
for (const position of positions) {
|
|
132
165
|
if (typeof position?.key !== 'string' ||
|
|
@@ -140,9 +173,10 @@ function useRichTextEditorEvents(context) {
|
|
|
140
173
|
}
|
|
141
174
|
next.set(position.key, position);
|
|
142
175
|
}
|
|
143
|
-
setAtomPositions(
|
|
144
|
-
if (current.size !== next.size)
|
|
176
|
+
setAtomPositions(current => {
|
|
177
|
+
if (current.size !== next.size) {
|
|
145
178
|
return next;
|
|
179
|
+
}
|
|
146
180
|
for (const [key, position] of next) {
|
|
147
181
|
const previous = current.get(key);
|
|
148
182
|
if (previous?.x !== position.x ||
|
|
@@ -150,15 +184,21 @@ function useRichTextEditorEvents(context) {
|
|
|
150
184
|
previous.hostY !== position.hostY ||
|
|
151
185
|
previous.y !== position.y ||
|
|
152
186
|
previous.height !== position.height ||
|
|
153
|
-
previous.width !== position.width)
|
|
187
|
+
previous.width !== position.width) {
|
|
154
188
|
return next;
|
|
189
|
+
}
|
|
155
190
|
}
|
|
156
191
|
return current;
|
|
157
192
|
});
|
|
158
|
-
}, [documentHandle,
|
|
193
|
+
}, [documentHandle.isDestroyed,
|
|
194
|
+
isForThisEditor,
|
|
195
|
+
setAtomContentWidth,
|
|
196
|
+
setAtomPositions,
|
|
197
|
+
setNativeAtomViewport]);
|
|
159
198
|
const handleToolbarAction = (0, react_1.useCallback)((event) => {
|
|
160
|
-
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent))
|
|
199
|
+
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent)) {
|
|
161
200
|
return;
|
|
201
|
+
}
|
|
162
202
|
const { key, updateJson, stateJson, documentRevision } = event.nativeEvent;
|
|
163
203
|
// A toolbar event carrying update data is a native commit. It
|
|
164
204
|
// must satisfy the same atomic admission path as typing; a pure
|
|
@@ -192,16 +232,19 @@ function useRichTextEditorEvents(context) {
|
|
|
192
232
|
return;
|
|
193
233
|
}
|
|
194
234
|
onToolbarActionRef.current?.(key);
|
|
195
|
-
}, [
|
|
196
|
-
applyTypedUpdateState,
|
|
235
|
+
}, [applyTypedUpdateState,
|
|
197
236
|
applyUpdateState,
|
|
198
237
|
document,
|
|
199
|
-
documentHandle,
|
|
238
|
+
documentHandle.editorId,
|
|
239
|
+
documentHandle.isDestroyed,
|
|
200
240
|
isForThisEditor,
|
|
241
|
+
lastAcceptedNativeCommitRevisionRef,
|
|
242
|
+
lastNativeDrivenRevisionRef,
|
|
243
|
+
onLocalCommitRef,
|
|
244
|
+
onToolbarActionRef,
|
|
201
245
|
openImageRequest,
|
|
202
246
|
openLinkRequest,
|
|
203
|
-
refreshAtomsFromUpdate
|
|
204
|
-
]);
|
|
247
|
+
refreshAtomsFromUpdate]);
|
|
205
248
|
return {
|
|
206
249
|
isForThisEditor,
|
|
207
250
|
handleEditorUpdate,
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { type EditorMentionTheme } from './EditorTheme';
|
|
2
2
|
import { type NativeSyntheticEvent } from 'react-native';
|
|
3
|
-
import { useRichTextEditorState } from './useRichTextEditorState';
|
|
4
|
-
import { useRichTextEditorCommands } from './useRichTextEditorCommands';
|
|
5
|
-
import { useRichTextEditorUpdates } from './useRichTextEditorUpdates';
|
|
6
|
-
import { useRichTextEditorEvents } from './useRichTextEditorEvents';
|
|
3
|
+
import { type useRichTextEditorState } from './useRichTextEditorState';
|
|
4
|
+
import { type useRichTextEditorCommands } from './useRichTextEditorCommands';
|
|
5
|
+
import { type useRichTextEditorUpdates } from './useRichTextEditorUpdates';
|
|
6
|
+
import { type useRichTextEditorEvents } from './useRichTextEditorEvents';
|
|
7
7
|
import { type NativeAddonEvent } from './RichTextEditorNativeTypes';
|
|
8
8
|
export declare function useRichTextEditorMentions(context: Pick<ReturnType<typeof useRichTextEditorState>, 'addonsRef' | 'bridge' | 'documentHandle' | 'currentPushedUpdateEditorIdRef' | 'documentDescriptor' | 'latestRevisionRef' | 'document' | 'setMentionQuery' | 'mentionQuery' | 'addons' | 'editable' | 'isFocused' | 'activeStateRef' | 'toolbarFrameOwnerId'> & Pick<ReturnType<typeof useRichTextEditorCommands>, 'editableRef'> & Pick<ReturnType<typeof useRichTextEditorUpdates>, 'afterLocalEngineMutation'> & Pick<ReturnType<typeof useRichTextEditorEvents>, 'isForThisEditor'>): {
|
|
9
9
|
mentionSuggestionTheme: EditorMentionTheme | undefined;
|
|
@@ -23,7 +23,7 @@ function useRichTextEditorMentions(context) {
|
|
|
23
23
|
return (0, RichTextEditorSerialization_1.isRecord)(resolvedAttrs)
|
|
24
24
|
? { ...selectionEvent.attrs, ...resolvedAttrs }
|
|
25
25
|
: selectionEvent.attrs;
|
|
26
|
-
}, []);
|
|
26
|
+
}, [addonsRef]);
|
|
27
27
|
const resolveMentionTheme = (0, react_1.useCallback)((selectionEvent) => {
|
|
28
28
|
let resolvedTheme;
|
|
29
29
|
try {
|
|
@@ -34,8 +34,9 @@ function useRichTextEditorMentions(context) {
|
|
|
34
34
|
console.error('NativeRichTextEditor: mentions.resolveTheme threw', error);
|
|
35
35
|
}
|
|
36
36
|
}
|
|
37
|
-
if (resolvedTheme === undefined || resolvedTheme === null)
|
|
37
|
+
if (resolvedTheme === undefined || resolvedTheme === null) {
|
|
38
38
|
return undefined;
|
|
39
|
+
}
|
|
39
40
|
// A rejected theme is dropped rather than written into the
|
|
40
41
|
// document: every later renderUpdate revalidates it, so one bad
|
|
41
42
|
// value would make the content permanently unrenderable.
|
|
@@ -46,7 +47,7 @@ function useRichTextEditorMentions(context) {
|
|
|
46
47
|
return undefined;
|
|
47
48
|
}
|
|
48
49
|
return resolvedTheme;
|
|
49
|
-
}, []);
|
|
50
|
+
}, [addonsRef]);
|
|
50
51
|
const resolveMentionInsertionAttrs = (0, react_1.useCallback)((selectionEvent) => {
|
|
51
52
|
const attrs = resolveMentionSelectionAttrs(selectionEvent);
|
|
52
53
|
const resolvedTheme = resolveMentionTheme({ ...selectionEvent, attrs });
|
|
@@ -56,8 +57,9 @@ function useRichTextEditorMentions(context) {
|
|
|
56
57
|
}, [resolveMentionSelectionAttrs, resolveMentionTheme]);
|
|
57
58
|
const insertMentionSuggestion = (0, react_1.useCallback)((request) => {
|
|
58
59
|
const mentions = addonsRef.current?.mentions;
|
|
59
|
-
if (!mentions || !editableRef.current)
|
|
60
|
+
if (!mentions || !editableRef.current) {
|
|
60
61
|
return;
|
|
62
|
+
}
|
|
61
63
|
const snapshot = bridge.renderUpdate({
|
|
62
64
|
anchor: request.range.anchor,
|
|
63
65
|
head: request.range.head,
|
|
@@ -93,7 +95,7 @@ function useRichTextEditorMentions(context) {
|
|
|
93
95
|
// own cursor resolution: a collapsed caret prefers After with a
|
|
94
96
|
// deterministic Before fallback at text-boundary positions; a
|
|
95
97
|
// range uses Before. The fallback changes only the stickiness
|
|
96
|
-
// of the SAME position
|
|
98
|
+
// of the SAME position : it is not a guessed-position retry.
|
|
97
99
|
const collapsed = anchorScalar === headScalar;
|
|
98
100
|
const syncSelection = (affinity) => bridge.setSelection({
|
|
99
101
|
baseDocumentRevision: snapshot.documentVersion,
|
|
@@ -108,8 +110,9 @@ function useRichTextEditorMentions(context) {
|
|
|
108
110
|
syncSelection(collapsed ? 'after' : 'before');
|
|
109
111
|
}
|
|
110
112
|
catch (error) {
|
|
111
|
-
if (!collapsed || !(0, RichTextEditorSerialization_1.isPositionInvalidError)(error))
|
|
113
|
+
if (!collapsed || !(0, RichTextEditorSerialization_1.isPositionInvalidError)(error)) {
|
|
112
114
|
throw error;
|
|
115
|
+
}
|
|
113
116
|
syncSelection('before');
|
|
114
117
|
}
|
|
115
118
|
const outcome = bridge.applyCommand({
|
|
@@ -121,8 +124,9 @@ function useRichTextEditorMentions(context) {
|
|
|
121
124
|
}),
|
|
122
125
|
},
|
|
123
126
|
});
|
|
124
|
-
if (outcome.type !== 'transaction' || !outcome.changed)
|
|
127
|
+
if (outcome.type !== 'transaction' || !outcome.changed) {
|
|
125
128
|
return;
|
|
129
|
+
}
|
|
126
130
|
latestRevisionRef.current = outcome.documentRevision;
|
|
127
131
|
}
|
|
128
132
|
catch (error) {
|
|
@@ -139,30 +143,36 @@ function useRichTextEditorMentions(context) {
|
|
|
139
143
|
attrs,
|
|
140
144
|
documentVersion: snapshot.documentVersion,
|
|
141
145
|
});
|
|
142
|
-
}, [
|
|
146
|
+
}, [addonsRef,
|
|
143
147
|
afterLocalEngineMutation,
|
|
144
148
|
bridge,
|
|
149
|
+
currentPushedUpdateEditorIdRef,
|
|
145
150
|
document,
|
|
146
151
|
documentDescriptor,
|
|
147
|
-
documentHandle,
|
|
148
|
-
|
|
149
|
-
|
|
152
|
+
documentHandle.editorId,
|
|
153
|
+
documentHandle.isDestroyed,
|
|
154
|
+
editableRef,
|
|
155
|
+
latestRevisionRef,
|
|
156
|
+
resolveMentionInsertionAttrs]);
|
|
150
157
|
const handleAddonEvent = (0, react_1.useCallback)((event) => {
|
|
151
|
-
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent))
|
|
158
|
+
if (documentHandle.isDestroyed || !isForThisEditor(event.nativeEvent)) {
|
|
152
159
|
return;
|
|
160
|
+
}
|
|
153
161
|
let parsed;
|
|
154
162
|
try {
|
|
155
163
|
const value = JSON.parse(event.nativeEvent.eventJson);
|
|
156
|
-
if (!(0, RichTextEditorSerialization_1.isRecord)(value) || typeof value.type !== 'string')
|
|
164
|
+
if (!(0, RichTextEditorSerialization_1.isRecord)(value) || typeof value.type !== 'string') {
|
|
157
165
|
return;
|
|
166
|
+
}
|
|
158
167
|
parsed = value;
|
|
159
168
|
}
|
|
160
169
|
catch {
|
|
161
170
|
return;
|
|
162
171
|
}
|
|
163
172
|
const mentions = addonsRef.current?.mentions;
|
|
164
|
-
if (!mentions)
|
|
173
|
+
if (!mentions) {
|
|
165
174
|
return;
|
|
175
|
+
}
|
|
166
176
|
const documentVersion = typeof parsed.documentVersion === 'string' ? parsed.documentVersion : undefined;
|
|
167
177
|
if (parsed.type === 'mentionsQueryChange') {
|
|
168
178
|
if (typeof parsed.query !== 'string' ||
|
|
@@ -190,9 +200,10 @@ function useRichTextEditorMentions(context) {
|
|
|
190
200
|
!(0, RichTextEditorSerialization_1.isRecord)(parsed.attrs)) {
|
|
191
201
|
return;
|
|
192
202
|
}
|
|
193
|
-
const suggestion = mentions.suggestions?.find(
|
|
194
|
-
if (!suggestion)
|
|
203
|
+
const suggestion = mentions.suggestions?.find(candidate => candidate.key === parsed.suggestionKey);
|
|
204
|
+
if (!suggestion) {
|
|
195
205
|
return;
|
|
206
|
+
}
|
|
196
207
|
mentions.onSelect?.({
|
|
197
208
|
trigger: parsed.trigger,
|
|
198
209
|
suggestion,
|
|
@@ -214,9 +225,10 @@ function useRichTextEditorMentions(context) {
|
|
|
214
225
|
parsed.range.head > 4294967295) {
|
|
215
226
|
return;
|
|
216
227
|
}
|
|
217
|
-
const suggestion = mentions.suggestions?.find(
|
|
218
|
-
if (!suggestion)
|
|
228
|
+
const suggestion = mentions.suggestions?.find(candidate => candidate.key === parsed.suggestionKey);
|
|
229
|
+
if (!suggestion) {
|
|
219
230
|
return;
|
|
231
|
+
}
|
|
220
232
|
insertMentionSuggestion({
|
|
221
233
|
trigger: parsed.trigger,
|
|
222
234
|
suggestion,
|
|
@@ -224,13 +236,19 @@ function useRichTextEditorMentions(context) {
|
|
|
224
236
|
range: parsed.range,
|
|
225
237
|
documentVersion,
|
|
226
238
|
});
|
|
227
|
-
}, [
|
|
239
|
+
}, [addonsRef,
|
|
240
|
+
documentHandle.isDestroyed,
|
|
241
|
+
insertMentionSuggestion,
|
|
242
|
+
isForThisEditor,
|
|
243
|
+
setMentionQuery]);
|
|
228
244
|
const handleMentionSuggestionPress = (0, react_1.useCallback)((suggestion) => {
|
|
229
|
-
if (mentionQuery == null)
|
|
245
|
+
if (mentionQuery == null) {
|
|
230
246
|
return;
|
|
231
|
-
|
|
232
|
-
|
|
247
|
+
}
|
|
248
|
+
const normalized = (0, addons_1.normalizeNativeEditorAddons)(addonsRef.current)?.mentions?.suggestions.find(candidate => candidate.key === suggestion.key);
|
|
249
|
+
if (normalized == null) {
|
|
233
250
|
return;
|
|
251
|
+
}
|
|
234
252
|
setMentionQuery(null);
|
|
235
253
|
insertMentionSuggestion({
|
|
236
254
|
trigger: mentionQuery.trigger,
|
|
@@ -239,7 +257,7 @@ function useRichTextEditorMentions(context) {
|
|
|
239
257
|
range: mentionQuery.range,
|
|
240
258
|
documentVersion: mentionQuery.documentVersion,
|
|
241
259
|
});
|
|
242
|
-
}, [insertMentionSuggestion, mentionQuery]);
|
|
260
|
+
}, [addonsRef, insertMentionSuggestion, mentionQuery, setMentionQuery]);
|
|
243
261
|
const mentionsEnabled = addons.mentions != null;
|
|
244
262
|
const mentionTrigger = addons.mentions?.trigger?.trim() || '@';
|
|
245
263
|
(0, react_1.useEffect)(() => {
|
|
@@ -257,13 +275,15 @@ function useRichTextEditorMentions(context) {
|
|
|
257
275
|
return undefined;
|
|
258
276
|
}
|
|
259
277
|
const normalized = (0, addons_1.normalizeNativeEditorAddons)(addons)?.mentions?.suggestions;
|
|
260
|
-
if (normalized == null)
|
|
278
|
+
if (normalized == null) {
|
|
261
279
|
return undefined;
|
|
280
|
+
}
|
|
262
281
|
const themes = {};
|
|
263
282
|
for (const suggestion of mentionSuggestions) {
|
|
264
|
-
const normalizedSuggestion = normalized.find(
|
|
265
|
-
if (normalizedSuggestion == null)
|
|
283
|
+
const normalizedSuggestion = normalized.find(candidate => candidate.key === suggestion.key);
|
|
284
|
+
if (normalizedSuggestion == null) {
|
|
266
285
|
continue;
|
|
286
|
+
}
|
|
267
287
|
const selectionEvent = {
|
|
268
288
|
trigger: mentionQuery.trigger,
|
|
269
289
|
suggestion,
|
|
@@ -281,14 +301,13 @@ function useRichTextEditorMentions(context) {
|
|
|
281
301
|
}
|
|
282
302
|
}
|
|
283
303
|
return Object.keys(themes).length > 0 ? themes : undefined;
|
|
284
|
-
}, [
|
|
304
|
+
}, [activeStateRef,
|
|
285
305
|
addons,
|
|
286
306
|
mentionQuery,
|
|
287
307
|
mentionSuggestionTheme,
|
|
288
308
|
mentionSuggestions,
|
|
289
309
|
resolveMentionSelectionAttrs,
|
|
290
|
-
resolveMentionTheme
|
|
291
|
-
]);
|
|
310
|
+
resolveMentionTheme]);
|
|
292
311
|
(0, react_1.useEffect)(() => {
|
|
293
312
|
if (!shouldPublishMentionSuggestions ||
|
|
294
313
|
mentionQuery == null ||
|