@dxos/react-ui-editor 0.3.11-main.bd26370 → 0.3.11-main.fbbdc2a
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 +1541 -1062
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +0 -3
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -2
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -0
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/automerge → components/TextEditor}/automerge.stories.d.ts +6 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/index.d.ts +0 -2
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/{hooks/yjs → components/TextEditor}/yjs.stories.d.ts +1 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +9 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +5 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +26 -0
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts +3 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -0
- package/dist/types/src/{hooks → extensions}/automerge/semaphore.d.ts +4 -4
- package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +5 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness.d.ts +46 -0
- package/dist/types/src/extensions/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/basic.d.ts.map +1 -0
- package/dist/types/src/extensions/blast.d.ts.map +1 -0
- package/dist/types/src/extensions/code.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/comments.d.ts +4 -2
- package/dist/types/src/extensions/comments.d.ts.map +1 -0
- package/dist/types/src/extensions/hr.d.ts.map +1 -0
- package/dist/types/src/extensions/image.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/index.d.ts +3 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/{components/TextEditor/extensions → extensions}/link.d.ts +1 -0
- package/dist/types/src/extensions/link.d.ts.map +1 -0
- package/dist/types/src/extensions/listener.d.ts +10 -0
- package/dist/types/src/extensions/listener.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -0
- package/dist/types/src/extensions/mermaid.d.ts.map +1 -0
- package/dist/types/src/extensions/table.d.ts.map +1 -0
- package/dist/types/src/extensions/tasklist.d.ts.map +1 -0
- package/dist/types/src/extensions/typewriter.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/cursor.d.ts +4 -0
- package/dist/types/src/extensions/yjs/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/index.d.ts +2 -0
- package/dist/types/src/extensions/yjs/index.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/yjs.d.ts +4 -0
- package/dist/types/src/extensions/yjs/yjs.d.ts.map +1 -0
- package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge.d.ts +3 -0
- package/dist/types/src/hooks/automerge.d.ts.map +1 -0
- package/dist/types/src/hooks/awareness-provider.d.ts +28 -0
- package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +2 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +9 -8
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/hooks/{yjs/space-provider.d.ts → yjs.d.ts} +8 -8
- package/dist/types/src/hooks/yjs.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/cursors.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +1 -0
- package/dist/types/src/styles/index.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts +2 -2
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/dist/types/src/{components/TextEditor/themes → themes}/default.d.ts +1 -1
- package/dist/types/src/themes/default.d.ts.map +1 -0
- package/dist/types/src/themes/index.d.ts.map +1 -0
- package/dist/types/src/util/cursor.d.ts +17 -0
- package/dist/types/src/util/cursor.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +3 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/util.d.ts.map +1 -0
- package/package.json +22 -21
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +11 -13
- package/src/components/TextEditor/TextEditor.stories.tsx +14 -1
- package/src/components/TextEditor/TextEditor.tsx +7 -7
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/codemirror.stories.ts +3 -2
- package/src/components/TextEditor/index.ts +0 -3
- package/src/{hooks/yjs → components/TextEditor}/yjs.stories.tsx +1 -1
- package/src/extensions/automerge/automerge.ts +94 -0
- package/src/extensions/automerge/cursor.ts +51 -0
- package/src/extensions/automerge/defs.ts +62 -0
- package/src/extensions/automerge/index.ts +6 -0
- package/src/{hooks → extensions}/automerge/semaphore.ts +14 -12
- package/src/{hooks → extensions}/automerge/update-automerge.ts +5 -6
- package/src/{hooks → extensions}/automerge/update-codemirror.ts +13 -5
- package/src/extensions/awareness.ts +316 -0
- package/src/{components/TextEditor/extensions → extensions}/code.ts +1 -1
- package/src/{components/TextEditor/extensions → extensions}/comments.ts +52 -19
- package/src/{components/TextEditor/extensions → extensions}/hr.ts +1 -1
- package/src/{components/TextEditor/extensions → extensions}/index.ts +3 -1
- package/src/{components/TextEditor/extensions → extensions}/link.ts +66 -10
- package/src/extensions/listener.ts +35 -0
- package/src/{components/TextEditor/extensions → extensions}/markdown/highlight.ts +1 -1
- package/src/{components/TextEditor/extensions → extensions}/typewriter.ts +1 -1
- package/src/extensions/yjs/cursor.ts +21 -0
- package/src/extensions/yjs/index.ts +5 -0
- package/src/{hooks → extensions}/yjs/yjs.test.ts +1 -25
- package/src/extensions/yjs/yjs.ts +16 -0
- package/src/hooks/automerge.ts +52 -0
- package/src/hooks/awareness-provider.ts +120 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTextModel.ts +20 -93
- package/src/hooks/{yjs/space-provider.ts → yjs.ts} +71 -19
- package/src/index.ts +2 -0
- package/src/styles/index.ts +1 -0
- package/src/testing/replicator.ts +10 -15
- package/src/{components/TextEditor/themes → themes}/default.ts +1 -1
- package/src/util/cursor.ts +29 -0
- package/src/util/index.ts +6 -0
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/hr.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts +0 -9
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts +0 -12
- package/dist/types/src/components/TextEditor/extensions/tooltip.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/typewriter.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/extensions/util.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/themes/default.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/themes/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/handle.d.ts +0 -9
- package/dist/types/src/hooks/automerge/handle.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/index.d.ts +0 -3
- package/dist/types/src/hooks/automerge/index.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/plugin.d.ts +0 -26
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/semaphore.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-automerge.d.ts +0 -6
- package/dist/types/src/hooks/automerge/update-automerge.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/update-codemirror.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/index.d.ts +0 -3
- package/dist/types/src/hooks/yjs/index.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/yjs/yjs.test.d.ts.map +0 -1
- package/src/components/TextEditor/extensions/listener.ts +0 -23
- package/src/components/TextEditor/extensions/tooltip.ts +0 -61
- package/src/hooks/automerge/handle.ts +0 -14
- package/src/hooks/automerge/index.ts +0 -6
- package/src/hooks/automerge/plugin.ts +0 -134
- package/src/hooks/yjs/index.ts +0 -6
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/autocomplete.d.ts +0 -0
- /package/dist/types/src/{hooks → extensions}/automerge/update-codemirror.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/basic.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/blast.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/code.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/hr.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/image.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/bundle.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/highlight.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/markdown/index.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/mention.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/mermaid.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/table.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/tasklist.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → extensions}/typewriter.d.ts +0 -0
- /package/dist/types/src/{hooks → extensions}/yjs/yjs.test.d.ts +0 -0
- /package/dist/types/src/{hooks/yjs → styles}/cursors.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/themes → themes}/index.d.ts +0 -0
- /package/dist/types/src/{components/TextEditor/extensions → util}/util.d.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/autocomplete.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/basic.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/blast.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/image.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/markdown/bundle.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/markdown/index.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/mention.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/mermaid.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/table.ts +0 -0
- /package/src/{components/TextEditor/extensions → extensions}/tasklist.ts +0 -0
- /package/src/{hooks/yjs → styles}/cursors.ts +0 -0
- /package/src/{components/TextEditor/themes → themes}/index.ts +0 -0
- /package/src/{components/TextEditor/extensions → util}/util.ts +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import * as Y from 'yjs';
|
|
6
|
+
|
|
7
|
+
import { arrayToString, stringToArray } from '@dxos/util';
|
|
8
|
+
|
|
9
|
+
import { type CursorConverter } from '../../util';
|
|
10
|
+
|
|
11
|
+
export const cursorConverter = (text: Y.Text): CursorConverter => ({
|
|
12
|
+
toCursor: (index, assoc) => {
|
|
13
|
+
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
14
|
+
},
|
|
15
|
+
fromCursor: (cursor) => {
|
|
16
|
+
return (
|
|
17
|
+
Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc!)?.index ??
|
|
18
|
+
0
|
|
19
|
+
);
|
|
20
|
+
},
|
|
21
|
+
});
|
|
@@ -2,13 +2,10 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { effect } from '@preact/signals-react';
|
|
6
5
|
import { expect } from 'chai';
|
|
7
6
|
import * as Y from 'yjs';
|
|
8
7
|
|
|
9
|
-
import {
|
|
10
|
-
import { Expando, setGlobalAutomergePreference, TextObject } from '@dxos/echo-schema';
|
|
11
|
-
import { registerSignalFactory } from '@dxos/echo-signals';
|
|
8
|
+
import { TextObject } from '@dxos/echo-schema';
|
|
12
9
|
import { describe, test } from '@dxos/test';
|
|
13
10
|
import { type YText } from '@dxos/text-model';
|
|
14
11
|
|
|
@@ -35,25 +32,4 @@ describe('YJS', () => {
|
|
|
35
32
|
expect(obj.text.substring(cursor!.index)).to.equal('world');
|
|
36
33
|
}
|
|
37
34
|
});
|
|
38
|
-
|
|
39
|
-
// TODO(burdon): Test deleting end character.
|
|
40
|
-
|
|
41
|
-
test.skip('effect', async () => {
|
|
42
|
-
setGlobalAutomergePreference(true);
|
|
43
|
-
registerSignalFactory();
|
|
44
|
-
const obj = new Expando({ comments: [] });
|
|
45
|
-
|
|
46
|
-
const trigger = new Trigger();
|
|
47
|
-
const unsubscribe = effect(() => {
|
|
48
|
-
// TODO(burdon): BUG: doesn't work with YJS.
|
|
49
|
-
console.log(obj.comments);
|
|
50
|
-
if (obj.comments.length > 0) {
|
|
51
|
-
trigger.wake();
|
|
52
|
-
}
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
obj.comments.push({ message: 'hello' });
|
|
56
|
-
await trigger.wait();
|
|
57
|
-
unsubscribe();
|
|
58
|
-
});
|
|
59
35
|
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { yCollab } from 'y-codemirror.next';
|
|
6
|
+
import type * as YP from 'y-protocols/awareness';
|
|
7
|
+
|
|
8
|
+
import type { YText } from '@dxos/text-model';
|
|
9
|
+
|
|
10
|
+
import { cursorConverter } from './cursor';
|
|
11
|
+
import { CursorConverter } from '../../util';
|
|
12
|
+
|
|
13
|
+
export const yjs = (content: YText, awareness?: YP.Awareness) => [
|
|
14
|
+
CursorConverter.of(cursorConverter(content)),
|
|
15
|
+
yCollab(content, awareness),
|
|
16
|
+
];
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import get from 'lodash.get';
|
|
6
|
+
|
|
7
|
+
import { type AutomergeTextCompat, getRawDoc } from '@dxos/echo-schema';
|
|
8
|
+
import { isNotNullOrUndefined } from '@dxos/util';
|
|
9
|
+
|
|
10
|
+
import { SpaceAwarenessProvider } from './awareness-provider';
|
|
11
|
+
import { type EditorModel, modelState, type UseTextModelProps } from './useTextModel';
|
|
12
|
+
import { automerge, awareness, AwarenessProvider } from '../extensions';
|
|
13
|
+
import { cursorColor } from '../styles';
|
|
14
|
+
|
|
15
|
+
export const createAutomergeModel = ({ space, identity, text }: UseTextModelProps): EditorModel => {
|
|
16
|
+
const obj = text as any as AutomergeTextCompat;
|
|
17
|
+
const doc = getRawDoc(obj, [obj.field]);
|
|
18
|
+
|
|
19
|
+
const awarenessProvider =
|
|
20
|
+
space &&
|
|
21
|
+
new SpaceAwarenessProvider({
|
|
22
|
+
space,
|
|
23
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
24
|
+
info: {
|
|
25
|
+
displayName: identity?.profile?.displayName ?? '',
|
|
26
|
+
color: cursorColor.color,
|
|
27
|
+
lightColor: cursorColor.light,
|
|
28
|
+
},
|
|
29
|
+
peerId: identity?.identityKey.toHex() ?? 'Anonymous',
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
const model: EditorModel = {
|
|
33
|
+
id: obj.id,
|
|
34
|
+
content: doc,
|
|
35
|
+
text: () => get(doc.handle.docSync(), doc.path),
|
|
36
|
+
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
37
|
+
extension: [
|
|
38
|
+
modelState.init(() => model),
|
|
39
|
+
automerge({ handle: doc.handle, path: doc.path }),
|
|
40
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
41
|
+
awareness(),
|
|
42
|
+
].filter(isNotNullOrUndefined),
|
|
43
|
+
peer: identity
|
|
44
|
+
? {
|
|
45
|
+
id: identity.identityKey.toHex(),
|
|
46
|
+
name: identity.profile?.displayName,
|
|
47
|
+
}
|
|
48
|
+
: undefined,
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
return model;
|
|
52
|
+
};
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2024 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { DeferredTask, Event, sleep } from '@dxos/async';
|
|
6
|
+
import { Context } from '@dxos/context';
|
|
7
|
+
import { invariant } from '@dxos/invariant';
|
|
8
|
+
import { log } from '@dxos/log';
|
|
9
|
+
import { type Space } from '@dxos/react-client/echo';
|
|
10
|
+
import { type GossipMessage } from '@dxos/react-client/mesh';
|
|
11
|
+
|
|
12
|
+
import { type AwarenessInfo, type AwarenessPosition, type AwarenessProvider, type AwarenessState } from '../extensions';
|
|
13
|
+
|
|
14
|
+
type ProtocolMessage =
|
|
15
|
+
| {
|
|
16
|
+
kind: 'query';
|
|
17
|
+
}
|
|
18
|
+
| {
|
|
19
|
+
kind: 'post';
|
|
20
|
+
state: AwarenessState;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const DEBOUNCE_INTERVAL = 100; // ms
|
|
24
|
+
|
|
25
|
+
export type AwarenessProviderParams = {
|
|
26
|
+
space: Space;
|
|
27
|
+
channel: string;
|
|
28
|
+
peerId: string;
|
|
29
|
+
info: AwarenessInfo;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export class SpaceAwarenessProvider implements AwarenessProvider {
|
|
33
|
+
public readonly remoteStateChange = new Event<void>();
|
|
34
|
+
|
|
35
|
+
private readonly _remoteStates = new Map<string, AwarenessState>();
|
|
36
|
+
|
|
37
|
+
private readonly _space: Space;
|
|
38
|
+
private readonly _channel: string;
|
|
39
|
+
private readonly _peerId: string;
|
|
40
|
+
private readonly _info: AwarenessInfo;
|
|
41
|
+
|
|
42
|
+
private _localState?: AwarenessState;
|
|
43
|
+
private _postTask?: DeferredTask;
|
|
44
|
+
private _ctx?: Context;
|
|
45
|
+
|
|
46
|
+
constructor(params: AwarenessProviderParams) {
|
|
47
|
+
this._space = params.space;
|
|
48
|
+
this._channel = params.channel;
|
|
49
|
+
this._peerId = params.peerId;
|
|
50
|
+
this._info = params.info;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
open() {
|
|
54
|
+
this._ctx = new Context();
|
|
55
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
56
|
+
if (this._localState) {
|
|
57
|
+
await this._space.postMessage(this._channel, {
|
|
58
|
+
kind: 'post',
|
|
59
|
+
state: this._localState,
|
|
60
|
+
} satisfies ProtocolMessage);
|
|
61
|
+
|
|
62
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
const unsubscribe = this._space.listen(this._channel, (message: GossipMessage) => {
|
|
67
|
+
switch (message.payload.kind) {
|
|
68
|
+
case 'query': {
|
|
69
|
+
this._handleQueryMessage();
|
|
70
|
+
break;
|
|
71
|
+
}
|
|
72
|
+
case 'post': {
|
|
73
|
+
this._handlePostMessage(message.payload);
|
|
74
|
+
break;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
});
|
|
78
|
+
this._ctx.onDispose(unsubscribe);
|
|
79
|
+
|
|
80
|
+
void this._space
|
|
81
|
+
.postMessage(this._channel, {
|
|
82
|
+
kind: 'query',
|
|
83
|
+
} satisfies ProtocolMessage)
|
|
84
|
+
.catch((err) => {
|
|
85
|
+
log.debug('failed to query awareness', { err });
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
close() {
|
|
90
|
+
void this._ctx?.dispose();
|
|
91
|
+
this._ctx = undefined;
|
|
92
|
+
this._postTask = undefined;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
update(position: AwarenessPosition | undefined): void {
|
|
96
|
+
invariant(this._postTask);
|
|
97
|
+
this._localState = {
|
|
98
|
+
peerId: this._peerId,
|
|
99
|
+
position,
|
|
100
|
+
info: this._info,
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
this._postTask.schedule();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
getRemoteStates(): AwarenessState[] {
|
|
107
|
+
return Array.from(this._remoteStates.values());
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
private _handleQueryMessage() {
|
|
111
|
+
invariant(this._postTask);
|
|
112
|
+
this._postTask.schedule();
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
private _handlePostMessage(message: ProtocolMessage) {
|
|
116
|
+
invariant(message.kind === 'post');
|
|
117
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
118
|
+
this.remoteStateChange.emit();
|
|
119
|
+
}
|
|
120
|
+
}
|
package/src/hooks/index.ts
CHANGED
|
@@ -2,36 +2,22 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type Extension
|
|
6
|
-
import get from 'lodash.get';
|
|
5
|
+
import { StateField, type Extension } from '@codemirror/state';
|
|
7
6
|
import { useEffect, useState } from 'react';
|
|
8
|
-
import
|
|
9
|
-
import type * as awarenessProtocol from 'y-protocols/awareness';
|
|
10
|
-
import * as Y from 'yjs';
|
|
7
|
+
import type * as YP from 'y-protocols/awareness';
|
|
11
8
|
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
type DocAccessor,
|
|
15
|
-
type Space,
|
|
16
|
-
type TextObject,
|
|
17
|
-
type AutomergeTextCompat,
|
|
18
|
-
getRawDoc,
|
|
19
|
-
isActualAutomergeObject,
|
|
20
|
-
} from '@dxos/react-client/echo';
|
|
9
|
+
import { isAutomergeObject, type DocAccessor, type Space, type TextObject } from '@dxos/react-client/echo';
|
|
21
10
|
import { type Identity } from '@dxos/react-client/halo';
|
|
22
11
|
import type { YText, YXmlFragment } from '@dxos/text-model';
|
|
23
|
-
import { arrayToString, stringToArray } from '@dxos/util';
|
|
24
12
|
|
|
25
|
-
import {
|
|
26
|
-
import {
|
|
13
|
+
import { createAutomergeModel } from './automerge';
|
|
14
|
+
import { createYjsModel } from './yjs';
|
|
27
15
|
|
|
28
|
-
// TODO(burdon):
|
|
29
|
-
type Awareness = awarenessProtocol.Awareness;
|
|
16
|
+
// TODO(burdon): Factor out defs.
|
|
30
17
|
|
|
31
18
|
/**
|
|
32
19
|
* State field makes the model available to other extensions.
|
|
33
20
|
*/
|
|
34
|
-
// TODO(burdon): Use facet?
|
|
35
21
|
export const modelState = StateField.define<EditorModel | undefined>({
|
|
36
22
|
create: () => undefined,
|
|
37
23
|
update: (model) => model,
|
|
@@ -44,20 +30,25 @@ export type Range = {
|
|
|
44
30
|
|
|
45
31
|
export type CommentRange = {
|
|
46
32
|
id: string;
|
|
47
|
-
// TODO(burdon): Split into begin/end?
|
|
48
33
|
cursor: string;
|
|
49
34
|
};
|
|
50
35
|
|
|
51
36
|
// TODO(wittjosiah): Factor out to common package? @dxos/react-client?
|
|
52
37
|
export type EditorModel = {
|
|
53
38
|
id: string;
|
|
39
|
+
text: () => string;
|
|
40
|
+
extension?: Extension;
|
|
41
|
+
|
|
54
42
|
// TODO(burdon): Remove.
|
|
55
43
|
content: string | YText | YXmlFragment | DocAccessor;
|
|
56
|
-
|
|
44
|
+
/**
|
|
45
|
+
* @deprecated Use CursorConverter.
|
|
46
|
+
*/
|
|
57
47
|
getCursorFromRange?: (value: Range) => string;
|
|
58
|
-
getRangeFromCursor?: (cursor: string) => Range;
|
|
59
|
-
extension
|
|
60
|
-
awareness?: Awareness;
|
|
48
|
+
getRangeFromCursor?: (cursor: string) => Range | undefined;
|
|
49
|
+
// TODO(burdon): Move into extension.
|
|
50
|
+
awareness?: YP.Awareness;
|
|
51
|
+
// TODO(burdon): Remove.
|
|
61
52
|
peer?: {
|
|
62
53
|
id: string;
|
|
63
54
|
name?: string;
|
|
@@ -82,75 +73,11 @@ export const useTextModel = (props: UseTextModelProps): EditorModel | undefined
|
|
|
82
73
|
|
|
83
74
|
const createModel = (props: UseTextModelProps) => {
|
|
84
75
|
const { text } = props;
|
|
85
|
-
if (
|
|
76
|
+
if (isAutomergeObject(text)) {
|
|
86
77
|
return createAutomergeModel(props);
|
|
87
|
-
} else {
|
|
88
|
-
if (!text?.doc) {
|
|
89
|
-
return undefined;
|
|
90
|
-
}
|
|
91
|
-
|
|
78
|
+
} else if (text?.doc) {
|
|
92
79
|
return createYjsModel(props);
|
|
80
|
+
} else {
|
|
81
|
+
return undefined;
|
|
93
82
|
}
|
|
94
83
|
};
|
|
95
|
-
|
|
96
|
-
const createYjsModel = ({ identity, space, text }: UseTextModelProps): EditorModel => {
|
|
97
|
-
invariant(text?.doc && text?.content);
|
|
98
|
-
const provider = space
|
|
99
|
-
? new SpaceAwarenessProvider({ space, doc: text.doc, channel: `yjs.awareness.${text.id}` })
|
|
100
|
-
: undefined;
|
|
101
|
-
|
|
102
|
-
const model: EditorModel = {
|
|
103
|
-
id: text.doc.guid,
|
|
104
|
-
content: text.content,
|
|
105
|
-
text: () => text.content!.toString(),
|
|
106
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
107
|
-
getCursorFromRange: (range: Range) => {
|
|
108
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content as YText, range.from));
|
|
109
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content as YText, range.to, -1));
|
|
110
|
-
return [arrayToString(from), arrayToString(to)].join(':');
|
|
111
|
-
},
|
|
112
|
-
getRangeFromCursor: (cursor: string) => {
|
|
113
|
-
const parts = cursor.split(':');
|
|
114
|
-
const from = Y.createAbsolutePositionFromRelativePosition(
|
|
115
|
-
Y.decodeRelativePosition(stringToArray(parts[0])),
|
|
116
|
-
text.doc!,
|
|
117
|
-
);
|
|
118
|
-
const to = Y.createAbsolutePositionFromRelativePosition(
|
|
119
|
-
Y.decodeRelativePosition(stringToArray(parts[1])),
|
|
120
|
-
text.doc!,
|
|
121
|
-
);
|
|
122
|
-
return { from: from!.index, to: to!.index };
|
|
123
|
-
},
|
|
124
|
-
extension: [yCollab(text.content as YText, provider?.awareness), modelState.init(() => model)],
|
|
125
|
-
awareness: provider?.awareness,
|
|
126
|
-
peer: identity
|
|
127
|
-
? {
|
|
128
|
-
id: identity.identityKey.toHex(),
|
|
129
|
-
name: identity.profile?.displayName,
|
|
130
|
-
}
|
|
131
|
-
: undefined,
|
|
132
|
-
};
|
|
133
|
-
|
|
134
|
-
return model;
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const createAutomergeModel = ({ identity, text }: UseTextModelProps): EditorModel => {
|
|
138
|
-
const obj = text as any as AutomergeTextCompat;
|
|
139
|
-
const doc = getRawDoc(obj, [obj.field]);
|
|
140
|
-
|
|
141
|
-
const model: EditorModel = {
|
|
142
|
-
id: obj.id,
|
|
143
|
-
content: doc,
|
|
144
|
-
text: () => get(doc.handle.docSync(), doc.path),
|
|
145
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
146
|
-
extension: [automergePlugin(doc.handle, doc.path), modelState.init(() => model)],
|
|
147
|
-
peer: identity
|
|
148
|
-
? {
|
|
149
|
-
id: identity.identityKey.toHex(),
|
|
150
|
-
name: identity.profile?.displayName,
|
|
151
|
-
}
|
|
152
|
-
: undefined,
|
|
153
|
-
};
|
|
154
|
-
|
|
155
|
-
return model;
|
|
156
|
-
};
|
|
@@ -5,14 +5,62 @@
|
|
|
5
5
|
import * as decoding from 'lib0/decoding';
|
|
6
6
|
import * as encoding from 'lib0/encoding';
|
|
7
7
|
import { Observable } from 'lib0/observable';
|
|
8
|
-
import * as
|
|
8
|
+
import * as YP from 'y-protocols/awareness';
|
|
9
|
+
import * as Y from 'yjs';
|
|
9
10
|
import { type Doc } from 'yjs';
|
|
10
11
|
|
|
12
|
+
import { invariant } from '@dxos/invariant';
|
|
11
13
|
import { log } from '@dxos/log';
|
|
12
14
|
import { type Space } from '@dxos/react-client/echo';
|
|
13
15
|
import { type GossipMessage } from '@dxos/react-client/mesh';
|
|
14
|
-
|
|
15
|
-
|
|
16
|
+
import type { YText } from '@dxos/text-model';
|
|
17
|
+
import { arrayToString, stringToArray } from '@dxos/util';
|
|
18
|
+
|
|
19
|
+
import { type EditorModel, modelState, type Range, type UseTextModelProps } from './useTextModel';
|
|
20
|
+
import { yjs } from '../extensions';
|
|
21
|
+
|
|
22
|
+
export const createYjsModel = ({ identity, space, text }: UseTextModelProps): EditorModel => {
|
|
23
|
+
invariant(text?.doc && text?.content);
|
|
24
|
+
const provider = space
|
|
25
|
+
? new YAwarenessProvider({ space, doc: text.doc, channel: `yjs.awareness.${text.id}` })
|
|
26
|
+
: undefined;
|
|
27
|
+
|
|
28
|
+
const model: EditorModel = {
|
|
29
|
+
id: text.doc.guid,
|
|
30
|
+
content: text.content,
|
|
31
|
+
text: () => text.content!.toString(),
|
|
32
|
+
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
33
|
+
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
34
|
+
getCursorFromRange: (range: Range) => {
|
|
35
|
+
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content as YText, range.from));
|
|
36
|
+
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content as YText, range.to, -1));
|
|
37
|
+
return [arrayToString(from), arrayToString(to)].join(':');
|
|
38
|
+
},
|
|
39
|
+
getRangeFromCursor: (cursor: string) => {
|
|
40
|
+
invariant(text.doc);
|
|
41
|
+
const parts = cursor.split(':');
|
|
42
|
+
const from = Y.createAbsolutePositionFromRelativePosition(
|
|
43
|
+
Y.decodeRelativePosition(stringToArray(parts[0])),
|
|
44
|
+
text.doc,
|
|
45
|
+
);
|
|
46
|
+
const to = Y.createAbsolutePositionFromRelativePosition(
|
|
47
|
+
Y.decodeRelativePosition(stringToArray(parts[1])),
|
|
48
|
+
text.doc,
|
|
49
|
+
);
|
|
50
|
+
return from && to ? { from: from.index, to: to.index } : undefined;
|
|
51
|
+
},
|
|
52
|
+
extension: [modelState.init(() => model), yjs(text.content as YText, provider?.awareness)],
|
|
53
|
+
awareness: provider?.awareness,
|
|
54
|
+
peer: identity
|
|
55
|
+
? {
|
|
56
|
+
id: identity.identityKey.toHex(),
|
|
57
|
+
name: identity.profile?.displayName,
|
|
58
|
+
}
|
|
59
|
+
: undefined,
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
return model;
|
|
63
|
+
};
|
|
16
64
|
|
|
17
65
|
// Based on https://github.com/yjs/y-webrtc/blob/88baab2/src/y-webrtc.js.
|
|
18
66
|
|
|
@@ -22,16 +70,26 @@ const messageQueryAwareness = 3;
|
|
|
22
70
|
/**
|
|
23
71
|
* Yjs awareness provider on top of a DXOS space.
|
|
24
72
|
*/
|
|
25
|
-
export class
|
|
73
|
+
export class YAwarenessProvider extends Observable<any> {
|
|
26
74
|
private readonly _space: Space;
|
|
27
|
-
private readonly _awareness: Awareness;
|
|
75
|
+
private readonly _awareness: YP.Awareness;
|
|
28
76
|
private readonly _clientId: number;
|
|
29
77
|
private readonly _channel: string;
|
|
30
78
|
|
|
31
|
-
constructor({
|
|
79
|
+
constructor({
|
|
80
|
+
space,
|
|
81
|
+
doc,
|
|
82
|
+
channel,
|
|
83
|
+
awareness,
|
|
84
|
+
}: {
|
|
85
|
+
space: Space;
|
|
86
|
+
doc: Doc;
|
|
87
|
+
channel: string;
|
|
88
|
+
awareness?: YP.Awareness;
|
|
89
|
+
}) {
|
|
32
90
|
super();
|
|
33
91
|
this._space = space;
|
|
34
|
-
this._awareness = awareness ?? new
|
|
92
|
+
this._awareness = awareness ?? new YP.Awareness(doc);
|
|
35
93
|
this._channel = channel;
|
|
36
94
|
this._clientId = doc.clientID;
|
|
37
95
|
|
|
@@ -52,14 +110,11 @@ export class SpaceAwarenessProvider extends Observable<any> {
|
|
|
52
110
|
// Post local awareness state.
|
|
53
111
|
const encoderAwarenessState = encoding.createEncoder();
|
|
54
112
|
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
55
|
-
encoding.writeVarUint8Array(
|
|
56
|
-
encoderAwarenessState,
|
|
57
|
-
awarenessProtocol.encodeAwarenessUpdate(this.awareness, [this._clientId]),
|
|
58
|
-
);
|
|
113
|
+
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [this._clientId]));
|
|
59
114
|
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
60
115
|
}
|
|
61
116
|
|
|
62
|
-
get awareness(): Awareness {
|
|
117
|
+
get awareness(): YP.Awareness {
|
|
63
118
|
return this._awareness;
|
|
64
119
|
}
|
|
65
120
|
|
|
@@ -68,10 +123,7 @@ export class SpaceAwarenessProvider extends Observable<any> {
|
|
|
68
123
|
const changedClients = added.concat(updated).concat(removed);
|
|
69
124
|
const encoderAwareness = encoding.createEncoder();
|
|
70
125
|
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
71
|
-
encoding.writeVarUint8Array(
|
|
72
|
-
encoderAwareness,
|
|
73
|
-
awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients),
|
|
74
|
-
);
|
|
126
|
+
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
75
127
|
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
76
128
|
}
|
|
77
129
|
|
|
@@ -92,7 +144,7 @@ export class SpaceAwarenessProvider extends Observable<any> {
|
|
|
92
144
|
let sendReply = false;
|
|
93
145
|
switch (messageType) {
|
|
94
146
|
case messageAwareness: {
|
|
95
|
-
|
|
147
|
+
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
96
148
|
break;
|
|
97
149
|
}
|
|
98
150
|
|
|
@@ -100,7 +152,7 @@ export class SpaceAwarenessProvider extends Observable<any> {
|
|
|
100
152
|
encoding.writeVarUint(encoder, messageAwareness);
|
|
101
153
|
encoding.writeVarUint8Array(
|
|
102
154
|
encoder,
|
|
103
|
-
|
|
155
|
+
YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())),
|
|
104
156
|
);
|
|
105
157
|
sendReply = true;
|
|
106
158
|
break;
|
|
@@ -121,6 +173,6 @@ export class SpaceAwarenessProvider extends Observable<any> {
|
|
|
121
173
|
}
|
|
122
174
|
|
|
123
175
|
private _handleBeforeUnload() {
|
|
124
|
-
|
|
176
|
+
YP.removeAwarenessStates(this._awareness, [this._clientId], 'window unload');
|
|
125
177
|
}
|
|
126
178
|
}
|
package/src/index.ts
CHANGED
package/src/styles/index.ts
CHANGED
|
@@ -7,7 +7,7 @@ import * as decoding from 'lib0/decoding';
|
|
|
7
7
|
import * as encoding from 'lib0/encoding';
|
|
8
8
|
import { Observable } from 'lib0/observable';
|
|
9
9
|
import { useMemo } from 'react';
|
|
10
|
-
import * as
|
|
10
|
+
import * as YP from 'y-protocols/awareness';
|
|
11
11
|
import * as syncProtocol from 'y-protocols/sync';
|
|
12
12
|
import { Doc } from 'yjs';
|
|
13
13
|
|
|
@@ -15,9 +15,10 @@ import { Event } from '@dxos/async';
|
|
|
15
15
|
import { log } from '@dxos/log';
|
|
16
16
|
import { TextKind } from '@dxos/protocols/proto/dxos/echo/model/text';
|
|
17
17
|
|
|
18
|
-
import {
|
|
18
|
+
import { type EditorModel } from '../hooks';
|
|
19
|
+
import { cursorColor } from '../styles';
|
|
19
20
|
|
|
20
|
-
type Awareness =
|
|
21
|
+
type Awareness = YP.Awareness;
|
|
21
22
|
|
|
22
23
|
const messageSync = 0;
|
|
23
24
|
const messageAwareness = 1;
|
|
@@ -35,7 +36,7 @@ export class AwarenessProvider extends Observable<any> {
|
|
|
35
36
|
super();
|
|
36
37
|
this._remoteUpdate = update;
|
|
37
38
|
this._doc = doc;
|
|
38
|
-
this._awareness = awareness ?? new
|
|
39
|
+
this._awareness = awareness ?? new YP.Awareness(doc);
|
|
39
40
|
|
|
40
41
|
this._doc.on('update', this._handleDocUpdate.bind(this));
|
|
41
42
|
this._awareness.on('update', this._handleAwarenessUpdate.bind(this));
|
|
@@ -55,10 +56,7 @@ export class AwarenessProvider extends Observable<any> {
|
|
|
55
56
|
// Post local awareness state.
|
|
56
57
|
const encoderAwarenessState = encoding.createEncoder();
|
|
57
58
|
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
58
|
-
encoding.writeVarUint8Array(
|
|
59
|
-
encoderAwarenessState,
|
|
60
|
-
awarenessProtocol.encodeAwarenessUpdate(this.awareness, [this._doc.clientID]),
|
|
61
|
-
);
|
|
59
|
+
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [this._doc.clientID]));
|
|
62
60
|
void this._remoteUpdate.emit(encoding.toUint8Array(encoderAwarenessState));
|
|
63
61
|
}
|
|
64
62
|
|
|
@@ -79,10 +77,7 @@ export class AwarenessProvider extends Observable<any> {
|
|
|
79
77
|
const changedClients = added.concat(updated).concat(removed);
|
|
80
78
|
const encoderAwareness = encoding.createEncoder();
|
|
81
79
|
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
82
|
-
encoding.writeVarUint8Array(
|
|
83
|
-
encoderAwareness,
|
|
84
|
-
awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients),
|
|
85
|
-
);
|
|
80
|
+
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
86
81
|
this._remoteUpdate.emit(encoding.toUint8Array(encoderAwareness));
|
|
87
82
|
}
|
|
88
83
|
|
|
@@ -109,7 +104,7 @@ export class AwarenessProvider extends Observable<any> {
|
|
|
109
104
|
}
|
|
110
105
|
|
|
111
106
|
case messageAwareness: {
|
|
112
|
-
|
|
107
|
+
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
113
108
|
break;
|
|
114
109
|
}
|
|
115
110
|
|
|
@@ -117,7 +112,7 @@ export class AwarenessProvider extends Observable<any> {
|
|
|
117
112
|
encoding.writeVarUint(encoder, messageAwareness);
|
|
118
113
|
encoding.writeVarUint8Array(
|
|
119
114
|
encoder,
|
|
120
|
-
|
|
115
|
+
YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())),
|
|
121
116
|
);
|
|
122
117
|
sendReply = true;
|
|
123
118
|
break;
|
|
@@ -138,7 +133,7 @@ export class AwarenessProvider extends Observable<any> {
|
|
|
138
133
|
}
|
|
139
134
|
|
|
140
135
|
private _handleBeforeUnload() {
|
|
141
|
-
|
|
136
|
+
YP.removeAwarenessStates(this._awareness, [this._doc.clientID], 'window unload');
|
|
142
137
|
}
|
|
143
138
|
}
|
|
144
139
|
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
import get from 'lodash.get';
|
|
6
6
|
|
|
7
|
-
import { type ThemeStyles, tokens } from '
|
|
7
|
+
import { type ThemeStyles, tokens } from '../styles';
|
|
8
8
|
|
|
9
9
|
// TODO(burdon): Can we erase All of the default CM styles?
|
|
10
10
|
// TODO(burdon): Theme styles seem to be added multiple times?
|