@apollohg/react-native-rich-text-editor 2.0.0 → 2.0.1
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 +1 -1
- package/THIRD_PARTY_NOTICES.md +1 -1
- package/android/build.gradle +3 -0
- 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 +84 -37
- 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/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/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/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
package/dist/EditorTheme.js
CHANGED
|
@@ -5,7 +5,7 @@ const EditorStyleSheetNormalization_1 = require("./EditorStyleSheetNormalization
|
|
|
5
5
|
const EditorMentionThemeNormalization_1 = require("./EditorMentionThemeNormalization");
|
|
6
6
|
function stripUndefined(value) {
|
|
7
7
|
if (Array.isArray(value)) {
|
|
8
|
-
return value.map(
|
|
8
|
+
return value.map(item => stripUndefined(item)).filter(item => item !== undefined);
|
|
9
9
|
}
|
|
10
10
|
if (value != null && typeof value === 'object') {
|
|
11
11
|
const entries = Object.entries(value)
|
|
@@ -21,8 +21,10 @@ function stripUndefined(value) {
|
|
|
21
21
|
}
|
|
22
22
|
return value;
|
|
23
23
|
}
|
|
24
|
-
|
|
25
|
-
|
|
24
|
+
/**
|
|
25
|
+
* Mentions are configured on the mentions addon, not on EditorTheme; native
|
|
26
|
+
* still reads them from the theme payload.
|
|
27
|
+
*/
|
|
26
28
|
function serializeEditorTheme(theme, mentionTheme) {
|
|
27
29
|
const normalized = theme === undefined ? undefined : (0, EditorStyleSheetNormalization_1.normalizeEditorTheme)(theme);
|
|
28
30
|
const cleanedTheme = normalized && (normalized.styles || normalized.toolbar)
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { type EditorToolbarProps } from './EditorToolbarTypes';
|
|
2
2
|
/**
|
|
3
3
|
* A JavaScript formatting toolbar. `RichTextEditor` renders one for you
|
|
4
|
-
* when `showToolbar` is set
|
|
4
|
+
* when `showToolbar` is set : reach for this component directly only to place
|
|
5
5
|
* the toolbar somewhere the editor cannot, in which case wire every handler
|
|
6
6
|
* to the editor's ref and feed it `activeState` and `historyState` from the
|
|
7
7
|
* editor's callbacks.
|
|
@@ -7,7 +7,7 @@ const useEditorToolbarInteractions_1 = require("./useEditorToolbarInteractions")
|
|
|
7
7
|
const useEditorToolbarPresentation_1 = require("./useEditorToolbarPresentation");
|
|
8
8
|
/**
|
|
9
9
|
* A JavaScript formatting toolbar. `RichTextEditor` renders one for you
|
|
10
|
-
* when `showToolbar` is set
|
|
10
|
+
* when `showToolbar` is set : reach for this component directly only to place
|
|
11
11
|
* the toolbar somewhere the editor cannot, in which case wire every handler
|
|
12
12
|
* to the editor's ref and feed it `activeState` and `historyState` from the
|
|
13
13
|
* editor's callbacks.
|
|
@@ -55,16 +55,16 @@ function areToolbarFrameListsEqual(left, right) {
|
|
|
55
55
|
return left.every((frame, index) => areToolbarFramesEqual(frame, right[index]));
|
|
56
56
|
}
|
|
57
57
|
function notifyEditorToolbarFrameListeners() {
|
|
58
|
-
exports.editorToolbarFrameListeners.forEach(
|
|
58
|
+
exports.editorToolbarFrameListeners.forEach(listener => listener());
|
|
59
59
|
}
|
|
60
60
|
function notifyEditorToolbarMentionStateListeners() {
|
|
61
|
-
exports.editorToolbarMentionStateListeners.forEach(
|
|
61
|
+
exports.editorToolbarMentionStateListeners.forEach(listener => listener());
|
|
62
62
|
}
|
|
63
63
|
function getEditorToolbarFramesSnapshot(ownerId) {
|
|
64
64
|
return Array.from(exports.editorToolbarFrames.values())
|
|
65
|
-
.filter(
|
|
65
|
+
.filter(registration => registration.ownerId === ownerId ||
|
|
66
66
|
(registration.ownerId == null && exports.activeEditorToolbarFrameOwnerId === ownerId))
|
|
67
|
-
.map(
|
|
67
|
+
.map(registration => registration.frame);
|
|
68
68
|
}
|
|
69
69
|
function subscribeEditorToolbarMentionState(listener) {
|
|
70
70
|
exports.editorToolbarMentionStateListeners.add(listener);
|
|
@@ -129,7 +129,7 @@ function useEditorToolbarFrames(ownerId) {
|
|
|
129
129
|
(0, react_1.useEffect)(() => {
|
|
130
130
|
const listener = () => {
|
|
131
131
|
const nextFrames = getEditorToolbarFramesSnapshot(ownerId);
|
|
132
|
-
setFrames(
|
|
132
|
+
setFrames(currentFrames => areToolbarFrameListsEqual(currentFrames, nextFrames) ? currentFrames : nextFrames);
|
|
133
133
|
};
|
|
134
134
|
exports.editorToolbarFrameListeners.add(listener);
|
|
135
135
|
listener();
|
|
@@ -34,9 +34,9 @@ export interface EditorToolbarMaterialIcon {
|
|
|
34
34
|
/**
|
|
35
35
|
* A toolbar button's icon:
|
|
36
36
|
*
|
|
37
|
-
* - `default`
|
|
38
|
-
* - `glyph`
|
|
39
|
-
* - `platform`
|
|
37
|
+
* - `default` : one of the package's built-in icons.
|
|
38
|
+
* - `glyph` : arbitrary text or an emoji, drawn as-is.
|
|
39
|
+
* - `platform` : per-platform native icons, with `fallbackText` when the
|
|
40
40
|
* platform cannot resolve the named icon.
|
|
41
41
|
*/
|
|
42
42
|
export type EditorToolbarIcon = {
|
|
@@ -67,14 +67,14 @@ export interface EditorToolbarButtonStyle {
|
|
|
67
67
|
* name), an `icon`, an optional `key` (defaults to something derived from the
|
|
68
68
|
* variant), and an optional `placement`.
|
|
69
69
|
*
|
|
70
|
-
* - `mark`
|
|
71
|
-
* - `link` / `image`
|
|
72
|
-
* - `heading`
|
|
73
|
-
* - `blockquote`
|
|
74
|
-
* - `list`
|
|
75
|
-
* - `command`
|
|
76
|
-
* - `node`
|
|
77
|
-
* - `action`
|
|
70
|
+
* - `mark` : toggles the named mark; active and enabled state come from the engine.
|
|
71
|
+
* - `link` / `image` : calls the editor's `onRequestLink` / `onRequestImage`.
|
|
72
|
+
* - `heading` : toggles the given heading level.
|
|
73
|
+
* - `blockquote` : toggles blockquote wrapping.
|
|
74
|
+
* - `list` : toggles the given list type.
|
|
75
|
+
* - `command` : runs an {@link EditorToolbarCommand}.
|
|
76
|
+
* - `node` : inserts the named node type, e.g. `'horizontalRule'`.
|
|
77
|
+
* - `action` : host-defined; calls `onToolbarAction` with its `key`, and the
|
|
78
78
|
* host supplies `isActive`/`isDisabled` since the engine knows nothing about it.
|
|
79
79
|
*/
|
|
80
80
|
export type EditorToolbarLeafItem = ({
|
|
@@ -144,7 +144,7 @@ export type EditorToolbarLeafItem = ({
|
|
|
144
144
|
/** What a group may contain. Groups do not nest. */
|
|
145
145
|
export type EditorToolbarGroupChildItem = EditorToolbarLeafItem;
|
|
146
146
|
/**
|
|
147
|
-
* Several buttons collapsed behind one
|
|
147
|
+
* Several buttons collapsed behind one : heading levels, say. The group
|
|
148
148
|
* reports active when any child is active, and disabled when every child is.
|
|
149
149
|
*/
|
|
150
150
|
export interface EditorToolbarGroupItem {
|
|
@@ -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;
|