@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
|
@@ -41,7 +41,7 @@ function isRecord(value) {
|
|
|
41
41
|
}
|
|
42
42
|
function hasExactKeys(value, keys) {
|
|
43
43
|
const actual = Object.keys(value);
|
|
44
|
-
return actual.length === keys.length && actual.every(
|
|
44
|
+
return actual.length === keys.length && actual.every(key => keys.includes(key));
|
|
45
45
|
}
|
|
46
46
|
const ERROR_KEYS = [
|
|
47
47
|
'domain',
|
|
@@ -54,8 +54,9 @@ const ERROR_KEYS = [
|
|
|
54
54
|
'details',
|
|
55
55
|
];
|
|
56
56
|
function parseError(value) {
|
|
57
|
-
if (!isRecord(value) || !hasExactKeys(value, ERROR_KEYS))
|
|
57
|
+
if (!isRecord(value) || !hasExactKeys(value, ERROR_KEYS)) {
|
|
58
58
|
return null;
|
|
59
|
+
}
|
|
59
60
|
return (0, NativeEditorBoundaryError_1.normalizeNativeEditorV2Error)({ error: value });
|
|
60
61
|
}
|
|
61
62
|
function parseNativeCompositionResult(resultJson) {
|
|
@@ -78,8 +79,19 @@ function parseNativeCompositionResult(resultJson) {
|
|
|
78
79
|
}
|
|
79
80
|
if (value.type === 'ended') {
|
|
80
81
|
const keys = Object.prototype.hasOwnProperty.call(value, 'error')
|
|
81
|
-
? ['version',
|
|
82
|
-
|
|
82
|
+
? ['version',
|
|
83
|
+
'type',
|
|
84
|
+
'sessionId',
|
|
85
|
+
'outcome',
|
|
86
|
+
'cause',
|
|
87
|
+
'text',
|
|
88
|
+
'error']
|
|
89
|
+
: ['version',
|
|
90
|
+
'type',
|
|
91
|
+
'sessionId',
|
|
92
|
+
'outcome',
|
|
93
|
+
'cause',
|
|
94
|
+
'text'];
|
|
83
95
|
const validOutcome = value.outcome === 'committed' || value.outcome === 'cancelled';
|
|
84
96
|
const validCause = value.cause === 'consumer' ||
|
|
85
97
|
value.cause === 'interaction' ||
|
|
@@ -140,10 +152,12 @@ function requireEndResult(result, sessionId) {
|
|
|
140
152
|
}
|
|
141
153
|
function settleWaiters(waiters, error) {
|
|
142
154
|
for (const waiter of waiters) {
|
|
143
|
-
if (error === undefined)
|
|
155
|
+
if (error === undefined) {
|
|
144
156
|
waiter.resolve();
|
|
145
|
-
|
|
157
|
+
}
|
|
158
|
+
else {
|
|
146
159
|
waiter.reject(error);
|
|
160
|
+
}
|
|
147
161
|
}
|
|
148
162
|
}
|
|
149
163
|
class ManagedExternalTextCompositionSession {
|
|
@@ -155,7 +169,7 @@ class ManagedExternalTextCompositionSession {
|
|
|
155
169
|
this.terminal = false;
|
|
156
170
|
this.terminalResult = null;
|
|
157
171
|
this.terminalError = null;
|
|
158
|
-
this.terminalCompletion = new Promise(
|
|
172
|
+
this.terminalCompletion = new Promise(resolve => {
|
|
159
173
|
this.resolveTerminal = resolve;
|
|
160
174
|
});
|
|
161
175
|
this.closing = null;
|
|
@@ -165,8 +179,9 @@ class ManagedExternalTextCompositionSession {
|
|
|
165
179
|
this.cancelPromise = null;
|
|
166
180
|
}
|
|
167
181
|
update(text) {
|
|
168
|
-
if (!this.canMutate())
|
|
182
|
+
if (!this.canMutate()) {
|
|
169
183
|
return Promise.reject(endedLifecycleError());
|
|
184
|
+
}
|
|
170
185
|
this.latestText = text;
|
|
171
186
|
return new Promise((resolve, reject) => {
|
|
172
187
|
const waiter = { resolve, reject };
|
|
@@ -184,8 +199,9 @@ class ManagedExternalTextCompositionSession {
|
|
|
184
199
|
});
|
|
185
200
|
}
|
|
186
201
|
async commit(finalText) {
|
|
187
|
-
if (!this.canMutate())
|
|
202
|
+
if (!this.canMutate()) {
|
|
188
203
|
throw endedLifecycleError();
|
|
204
|
+
}
|
|
189
205
|
this.closing = 'commit';
|
|
190
206
|
this.latestText = finalText;
|
|
191
207
|
if (this.updateInFlight != null) {
|
|
@@ -194,28 +210,32 @@ class ManagedExternalTextCompositionSession {
|
|
|
194
210
|
this.requireSuccessfulConsumerCommit(update.result, finalText);
|
|
195
211
|
return;
|
|
196
212
|
}
|
|
197
|
-
if (update.type === 'failed')
|
|
213
|
+
if (update.type === 'failed') {
|
|
198
214
|
throw update.error;
|
|
215
|
+
}
|
|
199
216
|
}
|
|
200
217
|
if (this.terminalResult != null) {
|
|
201
218
|
this.requireSuccessfulConsumerCommit(this.terminalResult, finalText);
|
|
202
219
|
return;
|
|
203
220
|
}
|
|
204
|
-
if (!this.canFinish())
|
|
221
|
+
if (!this.canFinish()) {
|
|
205
222
|
throw endedLifecycleError();
|
|
223
|
+
}
|
|
206
224
|
const foldedWaiters = this.takePendingWaiters();
|
|
207
225
|
const commit = await this.raceWithTerminal(this.host.commit(this.id, finalText));
|
|
208
226
|
if (commit.type === 'terminal') {
|
|
209
227
|
const error = this.explicitCommitError(commit.result, finalText);
|
|
210
228
|
settleWaiters(foldedWaiters, error);
|
|
211
|
-
if (error)
|
|
229
|
+
if (error) {
|
|
212
230
|
throw error;
|
|
231
|
+
}
|
|
213
232
|
return;
|
|
214
233
|
}
|
|
215
234
|
if (commit.type === 'failed') {
|
|
216
235
|
settleWaiters(foldedWaiters, commit.error);
|
|
217
|
-
if (!this.terminal && this.host.owns(this))
|
|
236
|
+
if (!this.terminal && this.host.owns(this)) {
|
|
218
237
|
this.closing = null;
|
|
238
|
+
}
|
|
219
239
|
throw commit.error;
|
|
220
240
|
}
|
|
221
241
|
try {
|
|
@@ -224,39 +244,48 @@ class ManagedExternalTextCompositionSession {
|
|
|
224
244
|
const endError = this.explicitCommitError(endResult, finalText);
|
|
225
245
|
this.finish(endResult);
|
|
226
246
|
settleWaiters(foldedWaiters, endError);
|
|
227
|
-
if (endError)
|
|
247
|
+
if (endError) {
|
|
228
248
|
throw endError;
|
|
249
|
+
}
|
|
229
250
|
}
|
|
230
251
|
catch (error) {
|
|
231
252
|
settleWaiters(foldedWaiters, error);
|
|
232
|
-
if (!this.terminal && this.host.owns(this))
|
|
253
|
+
if (!this.terminal && this.host.owns(this)) {
|
|
233
254
|
this.closing = null;
|
|
255
|
+
}
|
|
234
256
|
throw error;
|
|
235
257
|
}
|
|
236
258
|
}
|
|
237
259
|
cancel() {
|
|
238
|
-
if (this.terminal)
|
|
260
|
+
if (this.terminal) {
|
|
239
261
|
return Promise.resolve();
|
|
240
|
-
|
|
262
|
+
}
|
|
263
|
+
if (this.cancelPromise != null) {
|
|
241
264
|
return this.cancelPromise;
|
|
242
|
-
|
|
265
|
+
}
|
|
266
|
+
if (!this.canMutate()) {
|
|
243
267
|
return Promise.reject(endedLifecycleError());
|
|
268
|
+
}
|
|
244
269
|
this.cancelPromise = this.cancelWithCause('consumer');
|
|
245
270
|
return this.cancelPromise;
|
|
246
271
|
}
|
|
247
272
|
cancelForDocumentChange() {
|
|
248
|
-
if (this.terminal)
|
|
273
|
+
if (this.terminal) {
|
|
249
274
|
return Promise.resolve();
|
|
250
|
-
|
|
275
|
+
}
|
|
276
|
+
if (this.cancelPromise != null) {
|
|
251
277
|
return this.cancelPromise;
|
|
252
|
-
|
|
278
|
+
}
|
|
279
|
+
if (!this.canMutate()) {
|
|
253
280
|
return Promise.reject(endedLifecycleError());
|
|
281
|
+
}
|
|
254
282
|
this.cancelPromise = this.cancelWithCause('documentChange');
|
|
255
283
|
return this.cancelPromise;
|
|
256
284
|
}
|
|
257
285
|
finish(result) {
|
|
258
|
-
if (this.terminal)
|
|
286
|
+
if (this.terminal) {
|
|
259
287
|
return;
|
|
288
|
+
}
|
|
260
289
|
this.terminal = true;
|
|
261
290
|
this.terminalResult = result;
|
|
262
291
|
const error = result.error
|
|
@@ -302,8 +331,9 @@ class ManagedExternalTextCompositionSession {
|
|
|
302
331
|
settleWaiters(waiters, error);
|
|
303
332
|
}
|
|
304
333
|
finally {
|
|
305
|
-
if (this.inFlightWaiters === waiters)
|
|
334
|
+
if (this.inFlightWaiters === waiters) {
|
|
306
335
|
this.inFlightWaiters = [];
|
|
336
|
+
}
|
|
307
337
|
this.updateInFlight = null;
|
|
308
338
|
if (!this.terminal && this.closing == null && this.pendingUpdate != null) {
|
|
309
339
|
const pending = this.pendingUpdate;
|
|
@@ -318,13 +348,14 @@ class ManagedExternalTextCompositionSession {
|
|
|
318
348
|
return waiters;
|
|
319
349
|
}
|
|
320
350
|
requireOwnership() {
|
|
321
|
-
if (!this.host.owns(this))
|
|
351
|
+
if (!this.host.owns(this)) {
|
|
322
352
|
throw endedLifecycleError();
|
|
353
|
+
}
|
|
323
354
|
}
|
|
324
355
|
raceWithTerminal(work) {
|
|
325
356
|
return Promise.race([
|
|
326
|
-
work.then(
|
|
327
|
-
this.terminalCompletion.then(
|
|
357
|
+
work.then(value => ({ type: 'completed', value }), (error) => ({ type: 'failed', error })),
|
|
358
|
+
this.terminalCompletion.then(result => ({
|
|
328
359
|
type: 'terminal',
|
|
329
360
|
result,
|
|
330
361
|
})),
|
|
@@ -341,8 +372,9 @@ class ManagedExternalTextCompositionSession {
|
|
|
341
372
|
}
|
|
342
373
|
requireSuccessfulConsumerCommit(result, finalText) {
|
|
343
374
|
const error = this.explicitCommitError(result, finalText);
|
|
344
|
-
if (error)
|
|
375
|
+
if (error) {
|
|
345
376
|
throw error;
|
|
377
|
+
}
|
|
346
378
|
}
|
|
347
379
|
settleTerminalWaiters(waiters) {
|
|
348
380
|
settleWaiters(waiters, this.terminalError ?? endedLifecycleError());
|
|
@@ -351,13 +383,16 @@ class ManagedExternalTextCompositionSession {
|
|
|
351
383
|
this.closing = 'cancel';
|
|
352
384
|
if (this.updateInFlight != null) {
|
|
353
385
|
const update = await this.raceWithTerminal(this.updateInFlight);
|
|
354
|
-
if (update.type === 'terminal')
|
|
386
|
+
if (update.type === 'terminal') {
|
|
355
387
|
return;
|
|
356
|
-
|
|
388
|
+
}
|
|
389
|
+
if (update.type === 'failed') {
|
|
357
390
|
throw update.error;
|
|
391
|
+
}
|
|
358
392
|
}
|
|
359
|
-
if (!this.canFinish())
|
|
393
|
+
if (!this.canFinish()) {
|
|
360
394
|
return;
|
|
395
|
+
}
|
|
361
396
|
const pendingWaiters = this.takePendingWaiters();
|
|
362
397
|
const cancellation = await this.raceWithTerminal(this.host.cancel(this.id, cause));
|
|
363
398
|
if (cancellation.type === 'terminal') {
|
|
@@ -380,8 +415,9 @@ class ManagedExternalTextCompositionSession {
|
|
|
380
415
|
: undefined;
|
|
381
416
|
this.finish(endResult);
|
|
382
417
|
settleWaiters(pendingWaiters, endError);
|
|
383
|
-
if (endError)
|
|
418
|
+
if (endError) {
|
|
384
419
|
throw endError;
|
|
420
|
+
}
|
|
385
421
|
}
|
|
386
422
|
catch (error) {
|
|
387
423
|
settleWaiters(pendingWaiters, error);
|
|
@@ -403,10 +439,11 @@ class ExternalTextCompositionManager {
|
|
|
403
439
|
this.disposed = false;
|
|
404
440
|
this.beginTail = Promise.resolve();
|
|
405
441
|
this.sessionHost = {
|
|
406
|
-
owns:
|
|
407
|
-
release:
|
|
408
|
-
if (this.active === session)
|
|
442
|
+
owns: session => !this.disposed && this.active === session,
|
|
443
|
+
release: session => {
|
|
444
|
+
if (this.active === session) {
|
|
409
445
|
this.active = null;
|
|
446
|
+
}
|
|
410
447
|
},
|
|
411
448
|
update: (sessionId, text) => this.invokeUpdate(sessionId, text),
|
|
412
449
|
commit: (sessionId, text) => this.invokeCommit(sessionId, text),
|
|
@@ -426,11 +463,13 @@ class ExternalTextCompositionManager {
|
|
|
426
463
|
return pending;
|
|
427
464
|
}
|
|
428
465
|
handleNativeEnd(editorId, resultJson) {
|
|
429
|
-
if (editorId !== this.editorId)
|
|
466
|
+
if (editorId !== this.editorId) {
|
|
430
467
|
return;
|
|
468
|
+
}
|
|
431
469
|
const result = parseNativeCompositionResult(resultJson);
|
|
432
|
-
if (result.type !== 'ended')
|
|
470
|
+
if (result.type !== 'ended') {
|
|
433
471
|
return;
|
|
472
|
+
}
|
|
434
473
|
if (result.sessionId === this.active?.id) {
|
|
435
474
|
this.active.finish(result);
|
|
436
475
|
return;
|
|
@@ -444,12 +483,14 @@ class ExternalTextCompositionManager {
|
|
|
444
483
|
return this.active?.cancelForDocumentChange() ?? Promise.resolve();
|
|
445
484
|
}
|
|
446
485
|
dispose() {
|
|
447
|
-
if (this.disposed)
|
|
486
|
+
if (this.disposed) {
|
|
448
487
|
return;
|
|
488
|
+
}
|
|
449
489
|
this.disposed = true;
|
|
450
490
|
const active = this.active;
|
|
451
|
-
if (!active)
|
|
491
|
+
if (!active) {
|
|
452
492
|
return;
|
|
493
|
+
}
|
|
453
494
|
active.finish({
|
|
454
495
|
version: 1,
|
|
455
496
|
type: 'ended',
|
|
@@ -500,15 +541,18 @@ class ExternalTextCompositionManager {
|
|
|
500
541
|
return parseNativeCompositionResult(resultJson);
|
|
501
542
|
}
|
|
502
543
|
async beginSerialized(options) {
|
|
503
|
-
if (this.disposed)
|
|
544
|
+
if (this.disposed) {
|
|
504
545
|
throw endedLifecycleError();
|
|
546
|
+
}
|
|
505
547
|
if (!this.supports()) {
|
|
506
548
|
throw this.unsupportedError();
|
|
507
549
|
}
|
|
508
|
-
if (this.active)
|
|
550
|
+
if (this.active) {
|
|
509
551
|
await this.active.commit(this.active.latestText);
|
|
510
|
-
|
|
552
|
+
}
|
|
553
|
+
if (this.disposed) {
|
|
511
554
|
throw endedLifecycleError();
|
|
555
|
+
}
|
|
512
556
|
const session = new ManagedExternalTextCompositionSession(allocateExternalCompositionId(), this.sessionHost, options);
|
|
513
557
|
this.pendingBegin = session;
|
|
514
558
|
this.pendingEnd = null;
|
|
@@ -518,11 +562,13 @@ class ExternalTextCompositionManager {
|
|
|
518
562
|
void this.invokeCancel(session.id, 'lifecycle').catch(() => undefined);
|
|
519
563
|
throw endedLifecycleError();
|
|
520
564
|
}
|
|
521
|
-
if (this.pendingBegin !== session)
|
|
565
|
+
if (this.pendingBegin !== session) {
|
|
522
566
|
throw endedLifecycleError();
|
|
567
|
+
}
|
|
523
568
|
requireActiveResult(result, session.id);
|
|
524
|
-
if (this.pendingEnd != null)
|
|
569
|
+
if (this.pendingEnd != null) {
|
|
525
570
|
throw endedLifecycleError();
|
|
571
|
+
}
|
|
526
572
|
this.active = session;
|
|
527
573
|
return session;
|
|
528
574
|
}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
* Every field is optional; an omitted one uses
|
|
7
7
|
* {@link DEFAULT_EDITOR_IMAGE_LOADING_POLICY}. Each value must be a positive
|
|
8
8
|
* integer no greater than the matching
|
|
9
|
-
* {@link HARD_EDITOR_IMAGE_LOADING_POLICY} ceiling
|
|
9
|
+
* {@link HARD_EDITOR_IMAGE_LOADING_POLICY} ceiling : anything else throws
|
|
10
10
|
* `NativeEditorBoundaryError` (`IMAGE_POLICY_INVALID`).
|
|
11
11
|
*/
|
|
12
12
|
export interface EditorImageLoadingPolicy {
|
|
@@ -8,12 +8,12 @@ export declare const NATIVE_EDITOR_ERROR_DOMAINS: readonly ["boundary", "documen
|
|
|
8
8
|
/**
|
|
9
9
|
* Which subsystem raised a failure:
|
|
10
10
|
*
|
|
11
|
-
* - `boundary`
|
|
12
|
-
* - `document`
|
|
13
|
-
* - `operation`
|
|
14
|
-
* - `lifecycle`
|
|
15
|
-
* - `snapshot`
|
|
16
|
-
* - `transport`
|
|
11
|
+
* - `boundary` : the value never reached the engine (bad config, oversized input).
|
|
12
|
+
* - `document` : the document or schema was rejected.
|
|
13
|
+
* - `operation` : a mutation could not be applied (stale revision, invalid position).
|
|
14
|
+
* - `lifecycle` : the session was destroyed or is being destroyed.
|
|
15
|
+
* - `snapshot` : a room snapshot could not be exported or restored.
|
|
16
|
+
* - `transport` : collaboration transport failure.
|
|
17
17
|
*/
|
|
18
18
|
export type NativeEditorErrorDomain = (typeof NATIVE_EDITOR_ERROR_DOMAINS)[number];
|
|
19
19
|
/** Codes carried by `operation`-domain failures. */
|
|
@@ -39,7 +39,7 @@ export interface NativeEditorError {
|
|
|
39
39
|
details: Record<string, unknown> | null;
|
|
40
40
|
}
|
|
41
41
|
/**
|
|
42
|
-
* A value rejected before it reached the engine
|
|
42
|
+
* A value rejected before it reached the engine : an out-of-range resource
|
|
43
43
|
* limit, an invalid image policy, an oversized input. Thrown synchronously by
|
|
44
44
|
* the validating helpers in this package.
|
|
45
45
|
*/
|
|
@@ -50,7 +50,7 @@ exports.NATIVE_EDITOR_OPERATION_ERROR_CODES = [
|
|
|
50
50
|
'ENGINE_INVARIANT_FAILED',
|
|
51
51
|
];
|
|
52
52
|
/**
|
|
53
|
-
* A value rejected before it reached the engine
|
|
53
|
+
* A value rejected before it reached the engine : an out-of-range resource
|
|
54
54
|
* limit, an invalid image policy, an oversized input. Thrown synchronously by
|
|
55
55
|
* the validating helpers in this package.
|
|
56
56
|
*/
|
|
@@ -81,8 +81,9 @@ function parseNativeBoundaryError(value) {
|
|
|
81
81
|
: undefined);
|
|
82
82
|
}
|
|
83
83
|
function nullableCanonicalDecimal(value) {
|
|
84
|
-
if (value == null)
|
|
84
|
+
if (value == null) {
|
|
85
85
|
return null;
|
|
86
|
+
}
|
|
86
87
|
return (0, NativeEditorV2Decimal_1.normalizeNativeEditorV2U64)(value) ?? undefined;
|
|
87
88
|
}
|
|
88
89
|
function parseDetails(nativeError) {
|
|
@@ -92,10 +93,12 @@ function parseDetails(nativeError) {
|
|
|
92
93
|
}
|
|
93
94
|
return nativeError.details;
|
|
94
95
|
}
|
|
95
|
-
if (nativeError.detailsJson == null)
|
|
96
|
+
if (nativeError.detailsJson == null) {
|
|
96
97
|
return null;
|
|
97
|
-
|
|
98
|
+
}
|
|
99
|
+
if (typeof nativeError.detailsJson !== 'string') {
|
|
98
100
|
return undefined;
|
|
101
|
+
}
|
|
99
102
|
try {
|
|
100
103
|
const details = JSON.parse(nativeError.detailsJson);
|
|
101
104
|
return details != null && typeof details === 'object' && !Array.isArray(details)
|
|
@@ -132,8 +135,9 @@ function hasValidKnownDetails(code, details) {
|
|
|
132
135
|
function normalizeNativeEditorV2Error(value) {
|
|
133
136
|
const envelope = value;
|
|
134
137
|
const nativeError = envelope?.error;
|
|
135
|
-
if (nativeError == null || typeof nativeError !== 'object')
|
|
138
|
+
if (nativeError == null || typeof nativeError !== 'object') {
|
|
136
139
|
return null;
|
|
140
|
+
}
|
|
137
141
|
const { domain, code, message } = nativeError;
|
|
138
142
|
if (typeof domain !== 'string' ||
|
|
139
143
|
!exports.NATIVE_EDITOR_ERROR_DOMAINS.includes(domain) ||
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { NativeEditorErrorBase } from './NativeEditorBoundaryError';
|
|
1
|
+
import { type NativeEditorErrorBase } from './NativeEditorBoundaryError';
|
|
2
2
|
import { type NativeEditorTransportState, type NativeEditorState } from './NativeEditorResultNormalization';
|
|
3
3
|
/** One peer's awareness record, as Rust currently holds it. */
|
|
4
4
|
export interface NativeEditorPeerInfo {
|
|
@@ -27,9 +27,9 @@ export type NativeCollaborationProtocolFrame = {
|
|
|
27
27
|
/**
|
|
28
28
|
* What the transport does next after an adapter callback:
|
|
29
29
|
*
|
|
30
|
-
* - `continue`
|
|
31
|
-
* - `ready`
|
|
32
|
-
* - `reject`
|
|
30
|
+
* - `continue` : stay in the prelude and await the next frame.
|
|
31
|
+
* - `ready` : the prelude succeeded; release Yjs traffic.
|
|
32
|
+
* - `reject` : abandon this attempt.
|
|
33
33
|
*/
|
|
34
34
|
export type NativeCollaborationProtocolAdapterAction = 'continue' | 'ready' | 'reject';
|
|
35
35
|
/** An adapter callback's decision, plus any frames to send before it takes effect. */
|
|
@@ -61,21 +61,21 @@ export interface NativeCollaborationProtocolAdapter {
|
|
|
61
61
|
timeoutMillis?: number;
|
|
62
62
|
/** Close codes that park the Rust transport instead of entering automatic retry. */
|
|
63
63
|
terminalCloseCodes?: readonly number[];
|
|
64
|
-
/** Runs once when the socket opens
|
|
64
|
+
/** Runs once when the socket opens : send credentials here. */
|
|
65
65
|
onOpen(context: NativeCollaborationProtocolAdapterContext): NativeCollaborationProtocolAdapterResult | Promise<NativeCollaborationProtocolAdapterResult>;
|
|
66
66
|
/** Runs for each frame received before the prelude returns `ready`. */
|
|
67
67
|
onMessage(context: NativeCollaborationProtocolAdapterContext, frame: NativeCollaborationProtocolFrame): NativeCollaborationProtocolAdapterResult | Promise<NativeCollaborationProtocolAdapterResult>;
|
|
68
68
|
}
|
|
69
69
|
/** Where the native transport connects, and whether it should. */
|
|
70
70
|
export interface NativeCollaborationTransportConfig {
|
|
71
|
-
/** WebSocket endpoint, `ws:` or `wss:`. Treat it as sensitive
|
|
71
|
+
/** WebSocket endpoint, `ws:` or `wss:`. Treat it as sensitive : it may carry credentials. */
|
|
72
72
|
url: string;
|
|
73
73
|
/** Whether to open the connection now. False configures the endpoint without connecting. */
|
|
74
74
|
connect: boolean;
|
|
75
75
|
/** Optional RN-owned prelude that gates the native Yjs transport. */
|
|
76
76
|
protocolAdapter?: NativeCollaborationProtocolAdapter;
|
|
77
77
|
}
|
|
78
|
-
/** Why the transport woke and what it did
|
|
78
|
+
/** Why the transport woke and what it did : diagnostic only; no contract depends on these. */
|
|
79
79
|
export interface NativeCollaborationTransportDiagnostics {
|
|
80
80
|
/** What woke the transport, e.g. a received message or an elapsed timer. */
|
|
81
81
|
wakeReason: string;
|
|
@@ -27,7 +27,7 @@ function collaborationProtocolAdapterDescriptor(value) {
|
|
|
27
27
|
typeof value.onMessage !== 'function') {
|
|
28
28
|
throw (0, NativeEditorResultNormalization_1.invalidV2RequestError)('NativeEditorBridge: invalid collaboration protocol adapter');
|
|
29
29
|
}
|
|
30
|
-
const protocols = value.protocols.map(
|
|
30
|
+
const protocols = value.protocols.map(protocol => {
|
|
31
31
|
if (typeof protocol !== 'string' ||
|
|
32
32
|
protocol.length === 0 ||
|
|
33
33
|
(0, NativeEditorCreateJson_1.utf8V2JsonByteLength)(protocol) > exports.MAX_COLLABORATION_PROTOCOL_BYTES ||
|
|
@@ -49,7 +49,7 @@ function collaborationProtocolAdapterDescriptor(value) {
|
|
|
49
49
|
const rawTerminalCloseCodes = value.terminalCloseCodes;
|
|
50
50
|
if (rawTerminalCloseCodes !== undefined &&
|
|
51
51
|
(!Array.isArray(rawTerminalCloseCodes) ||
|
|
52
|
-
rawTerminalCloseCodes.some(
|
|
52
|
+
rawTerminalCloseCodes.some(code => !Number.isSafeInteger(code) || code < 1000 || code > 4999))) {
|
|
53
53
|
throw (0, NativeEditorResultNormalization_1.invalidV2RequestError)('NativeEditorBridge: invalid collaboration terminal close code');
|
|
54
54
|
}
|
|
55
55
|
const terminalCloseCodes = rawTerminalCloseCodes === undefined ? undefined : [...rawTerminalCloseCodes];
|
|
@@ -115,8 +115,9 @@ function serializeCollaborationProtocolAdapterResult(value) {
|
|
|
115
115
|
});
|
|
116
116
|
}
|
|
117
117
|
function normalizeNativeCollaborationTransportDiagnostics(value) {
|
|
118
|
-
if (!(0, NativeEditorResultNormalization_1.isPlainRecord)(value))
|
|
118
|
+
if (!(0, NativeEditorResultNormalization_1.isPlainRecord)(value)) {
|
|
119
119
|
return null;
|
|
120
|
+
}
|
|
120
121
|
const transportState = (0, NativeEditorResultNormalization_1.whitelisted)(value.transportState, NativeEditorResultNormalization_1.V2_TRANSPORT_STATES);
|
|
121
122
|
const nextDeadlineMillis = value.nextDeadlineMillis === null
|
|
122
123
|
? null
|
|
@@ -160,11 +161,13 @@ function encodeNativeCollaborationProtocolBytes(bytes) {
|
|
|
160
161
|
return encoded;
|
|
161
162
|
}
|
|
162
163
|
function decodeNativeCollaborationProtocolBytes(value) {
|
|
163
|
-
if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value))
|
|
164
|
+
if (value.length % 4 !== 0 || !/^[A-Za-z0-9+/]*={0,2}$/.test(value)) {
|
|
164
165
|
return null;
|
|
166
|
+
}
|
|
165
167
|
const firstPadding = value.indexOf('=');
|
|
166
|
-
if (firstPadding >= 0 && firstPadding < value.length - 2)
|
|
168
|
+
if (firstPadding >= 0 && firstPadding < value.length - 2) {
|
|
167
169
|
return null;
|
|
170
|
+
}
|
|
168
171
|
const outputLength = (value.length / 4) * 3 - (value.endsWith('==') ? 2 : value.endsWith('=') ? 1 : 0);
|
|
169
172
|
const bytes = new Uint8Array(outputLength);
|
|
170
173
|
let outputIndex = 0;
|
|
@@ -173,21 +176,26 @@ function decodeNativeCollaborationProtocolBytes(value) {
|
|
|
173
176
|
const second = exports.BASE64_ALPHABET.indexOf(value[index + 1]);
|
|
174
177
|
const third = value[index + 2] === '=' ? 0 : exports.BASE64_ALPHABET.indexOf(value[index + 2]);
|
|
175
178
|
const fourth = value[index + 3] === '=' ? 0 : exports.BASE64_ALPHABET.indexOf(value[index + 3]);
|
|
176
|
-
if (first < 0 || second < 0 || third < 0 || fourth < 0)
|
|
179
|
+
if (first < 0 || second < 0 || third < 0 || fourth < 0) {
|
|
177
180
|
return null;
|
|
181
|
+
}
|
|
178
182
|
const decoded = (first << 18) | (second << 12) | (third << 6) | fourth;
|
|
179
|
-
if (outputIndex < outputLength)
|
|
183
|
+
if (outputIndex < outputLength) {
|
|
180
184
|
bytes[outputIndex++] = (decoded >>> 16) & 0xff;
|
|
181
|
-
|
|
185
|
+
}
|
|
186
|
+
if (outputIndex < outputLength) {
|
|
182
187
|
bytes[outputIndex++] = (decoded >>> 8) & 0xff;
|
|
183
|
-
|
|
188
|
+
}
|
|
189
|
+
if (outputIndex < outputLength) {
|
|
184
190
|
bytes[outputIndex++] = decoded & 0xff;
|
|
191
|
+
}
|
|
185
192
|
}
|
|
186
193
|
return bytes;
|
|
187
194
|
}
|
|
188
195
|
function normalizeNativeCollaborationTransportEvent(value) {
|
|
189
|
-
if (!(0, NativeEditorResultNormalization_1.isPlainRecord)(value))
|
|
196
|
+
if (!(0, NativeEditorResultNormalization_1.isPlainRecord)(value)) {
|
|
190
197
|
return null;
|
|
198
|
+
}
|
|
191
199
|
const editorId = (0, NativeEditorResultNormalization_1.normalizeNativeEditorV2DecimalId)(value.editorId);
|
|
192
200
|
const eventSequence = (0, NativeEditorResultNormalization_1.normalizeNativeEditorV2DecimalId)(value.eventSequence);
|
|
193
201
|
const generation = value.generation === null ? null : (0, NativeEditorResultNormalization_1.normalizeNativeEditorV2DecimalId)(value.generation);
|
|
@@ -202,8 +210,9 @@ function normalizeNativeCollaborationTransportEvent(value) {
|
|
|
202
210
|
const state = (0, NativeEditorResultNormalization_1.normalizeNativeEditorV2StateValue)(value.state);
|
|
203
211
|
const peers = (0, NativeEditorResultNormalization_1.normalizeNativeEditorV2PeersValue)({ peers: value.peers });
|
|
204
212
|
const diagnostics = normalizeNativeCollaborationTransportDiagnostics(value.diagnostics);
|
|
205
|
-
if (state == null || peers == null || diagnostics == null)
|
|
213
|
+
if (state == null || peers == null || diagnostics == null) {
|
|
206
214
|
return null;
|
|
215
|
+
}
|
|
207
216
|
return {
|
|
208
217
|
editorId,
|
|
209
218
|
eventSequence,
|
|
@@ -216,8 +225,9 @@ function normalizeNativeCollaborationTransportEvent(value) {
|
|
|
216
225
|
}
|
|
217
226
|
if (value.kind === 'error') {
|
|
218
227
|
const error = (0, NativeEditorBoundaryError_1.normalizeNativeEditorV2Error)({ error: value.error });
|
|
219
|
-
if (error == null)
|
|
228
|
+
if (error == null) {
|
|
220
229
|
return null;
|
|
230
|
+
}
|
|
221
231
|
return {
|
|
222
232
|
editorId,
|
|
223
233
|
eventSequence,
|
|
@@ -247,12 +257,14 @@ function normalizeNativeCollaborationTransportEvent(value) {
|
|
|
247
257
|
negotiatedProtocol: value.negotiatedProtocol,
|
|
248
258
|
};
|
|
249
259
|
if (value.phase === 'open') {
|
|
250
|
-
if (value.frame !== undefined)
|
|
260
|
+
if (value.frame !== undefined) {
|
|
251
261
|
return null;
|
|
262
|
+
}
|
|
252
263
|
return { ...base, phase: 'open' };
|
|
253
264
|
}
|
|
254
|
-
if (!(0, NativeEditorResultNormalization_1.isPlainRecord)(value.frame) || typeof value.frame.data !== 'string')
|
|
265
|
+
if (!(0, NativeEditorResultNormalization_1.isPlainRecord)(value.frame) || typeof value.frame.data !== 'string') {
|
|
255
266
|
return null;
|
|
267
|
+
}
|
|
256
268
|
if (value.frame.type === 'text') {
|
|
257
269
|
return {
|
|
258
270
|
...base,
|
|
@@ -262,8 +274,9 @@ function normalizeNativeCollaborationTransportEvent(value) {
|
|
|
262
274
|
}
|
|
263
275
|
if (value.frame.type === 'binary') {
|
|
264
276
|
const data = decodeNativeCollaborationProtocolBytes(value.frame.data);
|
|
265
|
-
if (data == null)
|
|
277
|
+
if (data == null) {
|
|
266
278
|
return null;
|
|
279
|
+
}
|
|
267
280
|
return {
|
|
268
281
|
...base,
|
|
269
282
|
phase: 'message',
|
|
@@ -96,8 +96,9 @@ function buildV2CreateRequestUnchecked(config) {
|
|
|
96
96
|
if (fragmentName !== undefined && typeof fragmentName !== 'string') {
|
|
97
97
|
throw (0, NativeEditorCreateValidation_1.invalidV2CreateRequestError)('NativeEditorBridge: invalid fragmentName for v2 create');
|
|
98
98
|
}
|
|
99
|
-
if (fragmentName !== undefined)
|
|
99
|
+
if (fragmentName !== undefined) {
|
|
100
100
|
envelope.fragmentName = fragmentName;
|
|
101
|
+
}
|
|
101
102
|
let snapshotState = null;
|
|
102
103
|
const initialization = initializationValue;
|
|
103
104
|
const initializationType = (0, NativeEditorCreateValidation_1.ownV2CreateValue)(initialization, 'type');
|
|
@@ -161,19 +162,22 @@ function buildV2CreateRequestUnchecked(config) {
|
|
|
161
162
|
default:
|
|
162
163
|
throw (0, NativeEditorCreateValidation_1.invalidV2CreateRequestError)('NativeEditorBridge: unknown v2 initialization type');
|
|
163
164
|
}
|
|
164
|
-
if (policy !== undefined)
|
|
165
|
+
if (policy !== undefined) {
|
|
165
166
|
envelope.policy = policy;
|
|
166
|
-
|
|
167
|
+
}
|
|
168
|
+
if (limits !== undefined) {
|
|
167
169
|
envelope.limits = limits;
|
|
170
|
+
}
|
|
168
171
|
return {
|
|
169
172
|
envelope,
|
|
170
|
-
limits
|
|
173
|
+
limits,
|
|
171
174
|
snapshotState,
|
|
172
175
|
};
|
|
173
176
|
}
|
|
174
177
|
function cloneAndFreezeDescriptorValue(value) {
|
|
175
|
-
if (value == null || typeof value !== 'object')
|
|
178
|
+
if (value == null || typeof value !== 'object') {
|
|
176
179
|
return value;
|
|
180
|
+
}
|
|
177
181
|
const setOwnValue = (target, key, child) => {
|
|
178
182
|
Object.defineProperty(target, key, {
|
|
179
183
|
value: child,
|
|
@@ -188,8 +192,9 @@ function cloneAndFreezeDescriptorValue(value) {
|
|
|
188
192
|
const created = [cloneRoot];
|
|
189
193
|
while (pending.length > 0) {
|
|
190
194
|
const current = pending.pop();
|
|
191
|
-
if (current === undefined)
|
|
195
|
+
if (current === undefined) {
|
|
192
196
|
break;
|
|
197
|
+
}
|
|
193
198
|
const keys = Array.isArray(current.source)
|
|
194
199
|
? Array.from({ length: current.source.length }, (_, index) => String(index))
|
|
195
200
|
: Object.keys(current.source);
|