@dxos/react-ui-editor 0.4.2-main.330edbe → 0.4.2-main.571cfa2
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/dist/lib/browser/index.mjs +30 -40
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts +2 -2
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
- package/dist/types/src/extensions/automerge/{semaphore.d.ts → sync.d.ts} +6 -5
- package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -0
- package/package.json +24 -24
- package/src/components/TextEditor/automerge.stories.tsx +37 -41
- package/src/extensions/automerge/automerge.ts +5 -21
- package/src/extensions/automerge/{semaphore.ts → sync.ts} +32 -34
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +0 -1
|
@@ -4,15 +4,14 @@
|
|
|
4
4
|
// Ref: https://github.com/automerge/automerge-codemirror
|
|
5
5
|
//
|
|
6
6
|
|
|
7
|
-
import {
|
|
8
|
-
import { StateField, type Extension, type StateEffect } from '@codemirror/state';
|
|
7
|
+
import { StateField, type Extension } from '@codemirror/state';
|
|
9
8
|
import { EditorView, ViewPlugin } from '@codemirror/view';
|
|
10
9
|
|
|
11
10
|
import { next as A, type Prop } from '@dxos/automerge/automerge';
|
|
12
11
|
|
|
13
12
|
import { cursorConverter } from './cursor';
|
|
14
13
|
import { updateHeadsEffect, type IDocHandle, isReconcile, type State } from './defs';
|
|
15
|
-
import {
|
|
14
|
+
import { Syncer } from './sync';
|
|
16
15
|
import { Cursor } from '../cursor';
|
|
17
16
|
|
|
18
17
|
export type AutomergeOptions = {
|
|
@@ -55,7 +54,7 @@ export const automerge = ({ handle, path }: AutomergeOptions): Extension => {
|
|
|
55
54
|
},
|
|
56
55
|
});
|
|
57
56
|
|
|
58
|
-
const
|
|
57
|
+
const syncer = new Syncer(handle, syncState);
|
|
59
58
|
|
|
60
59
|
return [
|
|
61
60
|
Cursor.converter.of(cursorConverter(handle, path)),
|
|
@@ -73,7 +72,7 @@ export const automerge = ({ handle, path }: AutomergeOptions): Extension => {
|
|
|
73
72
|
}
|
|
74
73
|
|
|
75
74
|
_handleChange() {
|
|
76
|
-
|
|
75
|
+
syncer.reconcile(this._view, false);
|
|
77
76
|
}
|
|
78
77
|
},
|
|
79
78
|
),
|
|
@@ -81,23 +80,8 @@ export const automerge = ({ handle, path }: AutomergeOptions): Extension => {
|
|
|
81
80
|
// Reconcile local updates.
|
|
82
81
|
EditorView.updateListener.of(({ view, changes }) => {
|
|
83
82
|
if (!changes.empty) {
|
|
84
|
-
|
|
83
|
+
syncer.reconcile(view, true);
|
|
85
84
|
}
|
|
86
85
|
}),
|
|
87
|
-
|
|
88
|
-
// TODO(burdon): Record undo transactions.
|
|
89
|
-
// See https://github.com/yjs/y-codemirror.next/tree/main
|
|
90
|
-
// https://codemirror.net/examples/inverted-effect
|
|
91
|
-
invertedEffects.of((tr) => {
|
|
92
|
-
// Each change results it three transactions: insert, delete, insert.
|
|
93
|
-
const effects: StateEffect<any>[] = [];
|
|
94
|
-
if (!tr.changes.empty) {
|
|
95
|
-
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
|
|
96
|
-
// effects.push(effectType.of({});
|
|
97
|
-
});
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
return effects;
|
|
101
|
-
}),
|
|
102
86
|
];
|
|
103
87
|
};
|
|
@@ -12,11 +12,11 @@ import { next as A } from '@dxos/automerge/automerge';
|
|
|
12
12
|
import {
|
|
13
13
|
getLastHeads,
|
|
14
14
|
getPath,
|
|
15
|
-
isReconcile,
|
|
16
|
-
reconcileAnnotation,
|
|
17
|
-
updateHeads,
|
|
18
15
|
type IDocHandle,
|
|
19
16
|
type State,
|
|
17
|
+
reconcileAnnotation,
|
|
18
|
+
updateHeads,
|
|
19
|
+
isReconcile,
|
|
20
20
|
} from './defs';
|
|
21
21
|
import { updateAutomerge } from './update-automerge';
|
|
22
22
|
import { updateCodeMirror } from './update-codemirror';
|
|
@@ -24,8 +24,8 @@ import { updateCodeMirror } from './update-codemirror';
|
|
|
24
24
|
/**
|
|
25
25
|
* Implements three-way merge (on each mutation).
|
|
26
26
|
*/
|
|
27
|
-
export class
|
|
28
|
-
private
|
|
27
|
+
export class Syncer {
|
|
28
|
+
private _pending = false;
|
|
29
29
|
|
|
30
30
|
// prettier-ignore
|
|
31
31
|
constructor(
|
|
@@ -33,46 +33,44 @@ export class PatchSemaphore {
|
|
|
33
33
|
private readonly _state: StateField<State>
|
|
34
34
|
) {}
|
|
35
35
|
|
|
36
|
-
reconcile(view: EditorView) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
this._inReconcile = false;
|
|
36
|
+
reconcile(view: EditorView, editor: boolean) {
|
|
37
|
+
// TODO(burdon): Better way to do mutex?
|
|
38
|
+
if (this._pending) {
|
|
39
|
+
return;
|
|
41
40
|
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
private doReconcile(view: EditorView) {
|
|
45
|
-
const path = getPath(view.state, this._state);
|
|
46
41
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
42
|
+
this._pending = true;
|
|
43
|
+
if (editor) {
|
|
44
|
+
this.onEditorChange(view);
|
|
45
|
+
} else {
|
|
46
|
+
this.onAutomergeChange(view);
|
|
47
|
+
}
|
|
48
|
+
this._pending = false;
|
|
49
|
+
}
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
onEditorChange(view: EditorView) {
|
|
52
|
+
// Apply the unreconciled transactions to the document.
|
|
52
53
|
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
53
|
-
const
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
selection = selection.map(inverted);
|
|
54
|
+
const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
55
|
+
|
|
56
|
+
if (newHeads) {
|
|
57
57
|
view.dispatch({
|
|
58
|
-
|
|
59
|
-
annotations: reconcileAnnotation.of(
|
|
58
|
+
effects: updateHeads(newHeads),
|
|
59
|
+
annotations: reconcileAnnotation.of(false),
|
|
60
60
|
});
|
|
61
61
|
}
|
|
62
|
+
}
|
|
62
63
|
|
|
63
|
-
|
|
64
|
-
//
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
// TODO(alexjg): this is the call that's resetting the editor state on click.
|
|
68
|
-
newHeads = A.getHeads(this._handle.docSync()!);
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
// Now get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
|
|
64
|
+
onAutomergeChange(view: EditorView) {
|
|
65
|
+
// Get the diff between the updated state of the document and the heads and apply that to the codemirror doc.
|
|
66
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
67
|
+
const newHeads = A.getHeads(this._handle.docSync()!);
|
|
72
68
|
const diff = A.equals(oldHeads, newHeads) ? [] : A.diff(this._handle.docSync()!, oldHeads, newHeads);
|
|
69
|
+
|
|
70
|
+
const selection = view.state.selection;
|
|
71
|
+
const path = getPath(view.state, this._state);
|
|
73
72
|
updateCodeMirror(view, selection, path, diff);
|
|
74
73
|
|
|
75
|
-
// Update automerge state.
|
|
76
74
|
view.dispatch({
|
|
77
75
|
effects: updateHeads(newHeads),
|
|
78
76
|
annotations: reconcileAnnotation.of(false),
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"semaphore.d.ts","sourceRoot":"","sources":["../../../../../src/extensions/automerge/semaphore.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,KAAK,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAInD,OAAO,EAML,KAAK,UAAU,EACf,KAAK,KAAK,EACX,MAAM,QAAQ,CAAC;AAIhB;;GAEG;AACH,qBAAa,cAAc;IAKvB,OAAO,CAAC,QAAQ,CAAC,OAAO;IACxB,OAAO,CAAC,QAAQ,CAAC,MAAM;IALzB,OAAO,CAAC,YAAY,CAAS;gBAIV,OAAO,EAAE,UAAU,EACnB,MAAM,EAAE,UAAU,CAAC,KAAK,CAAC;IAG5C,SAAS,CAAC,IAAI,EAAE,UAAU;IAQ1B,OAAO,CAAC,WAAW;CAqCpB"}
|