@dxos/react-ui-editor 0.3.9-main.632a97f → 0.3.9-main.71124bf
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 +962 -608
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts +9 -0
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +1 -0
- package/dist/types/src/automerge/automerge-plugin/index.d.ts +2 -2
- package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts +6 -5
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +1 -1
- package/dist/types/src/automerge/automerge.stories.d.ts +2 -1
- package/dist/types/src/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +24 -20
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +8 -10
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/{stories/html/code-mirror.stories.d.ts → src/components/TextEditor/codemirror.stories.d.ts} +2 -2
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/basic/bundle.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/basic/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts +10 -0
- package/dist/types/src/components/TextEditor/extensions/basic/theme.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/change.d.ts +7 -0
- package/dist/types/src/components/TextEditor/extensions/change.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts +11 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts +10 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts +4 -0
- package/dist/types/src/components/TextEditor/extensions/hyperlink/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts +5 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts +3 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/components/{Markdown/markdownTags.d.ts → TextEditor/extensions/markdown/tags.d.ts} +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/tags.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts +21 -0
- package/dist/types/src/components/TextEditor/extensions/markdown/theme.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/index.d.ts +1 -2
- package/dist/types/src/components/TextEditor/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts +11 -0
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/components/index.d.ts +0 -3
- package/dist/types/src/components/index.d.ts.map +1 -1
- package/dist/types/src/hooks/index.d.ts +4 -0
- package/dist/types/src/hooks/index.d.ts.map +1 -0
- package/dist/types/src/hooks/useCollaboration.d.ts +9 -0
- package/dist/types/src/hooks/useCollaboration.d.ts.map +1 -0
- package/dist/types/src/{model.d.ts → hooks/useTextModel.d.ts} +3 -15
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/cursors.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/index.d.ts.map +1 -0
- package/dist/types/src/hooks/yjs/space-provider.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -2
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +4 -0
- package/dist/types/src/styles/tokens.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts +1 -1
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/package.json +32 -26
- package/src/automerge/automerge-plugin/PatchSemaphore.ts +5 -5
- package/src/automerge/automerge-plugin/codeMirrorToAm.ts +10 -7
- package/src/automerge/automerge-plugin/handle.ts +14 -0
- package/src/automerge/automerge-plugin/index.ts +2 -2
- package/src/automerge/automerge-plugin/plugin.ts +39 -10
- package/src/automerge/automerge.stories.tsx +32 -47
- package/src/components/TextEditor/TextEditor.stories.tsx +56 -8
- package/src/components/TextEditor/TextEditor.tsx +113 -55
- package/src/components/TextEditor/codemirror.stories.ts +114 -0
- package/src/components/TextEditor/extensions/basic/bundle.ts +26 -0
- package/src/components/TextEditor/extensions/basic/index.ts +6 -0
- package/src/components/TextEditor/extensions/basic/theme.ts +49 -0
- package/src/components/TextEditor/extensions/change.ts +22 -0
- package/src/components/TextEditor/extensions/hyperlink/hyperlinkDecoration.ts +99 -0
- package/src/components/TextEditor/extensions/hyperlink/hyperlinkTooltip.tsx +61 -0
- package/src/components/TextEditor/extensions/hyperlink/hyperlinkWidget.tsx +119 -0
- package/src/components/TextEditor/extensions/hyperlink/index.ts +7 -0
- package/src/components/TextEditor/extensions/index.ts +8 -0
- package/src/components/TextEditor/extensions/markdown/bundle.ts +99 -0
- package/src/components/TextEditor/extensions/markdown/index.ts +6 -0
- package/src/components/{Markdown/markdownTheme.ts → TextEditor/extensions/markdown/theme.ts} +42 -27
- package/src/components/TextEditor/index.ts +1 -2
- package/src/components/TextEditor/yjs.stories.tsx +55 -0
- package/src/components/index.ts +0 -3
- package/src/hooks/index.ts +7 -0
- package/src/hooks/useCollaboration.ts +45 -0
- package/src/{model.ts → hooks/useTextModel.ts} +42 -17
- package/src/index.ts +3 -3
- package/src/styles/tokens.ts +6 -0
- package/src/testing/replicator.ts +1 -2
- package/dist/types/src/automerge/demo.d.ts +0 -25
- package/dist/types/src/automerge/demo.d.ts.map +0 -1
- package/dist/types/src/components/Editor/Editor.d.ts +0 -15
- package/dist/types/src/components/Editor/Editor.d.ts.map +0 -1
- package/dist/types/src/components/Editor/Editor.stories.d.ts +0 -28
- package/dist/types/src/components/Editor/Editor.stories.d.ts.map +0 -1
- package/dist/types/src/components/Editor/index.d.ts +0 -2
- package/dist/types/src/components/Editor/index.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/Markdown.d.ts +0 -19
- package/dist/types/src/components/Markdown/Markdown.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/Markdown.stories.d.ts +0 -19
- package/dist/types/src/components/Markdown/Markdown.stories.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/index.d.ts +0 -2
- package/dist/types/src/components/Markdown/index.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/markdownTags.d.ts.map +0 -1
- package/dist/types/src/components/Markdown/markdownTheme.d.ts +0 -107
- package/dist/types/src/components/Markdown/markdownTheme.d.ts.map +0 -1
- package/dist/types/src/components/RichText/RichText.d.ts +0 -20
- package/dist/types/src/components/RichText/RichText.d.ts.map +0 -1
- package/dist/types/src/components/RichText/RichText.stories.d.ts +0 -26
- package/dist/types/src/components/RichText/RichText.stories.d.ts.map +0 -1
- package/dist/types/src/components/RichText/index.d.ts +0 -2
- package/dist/types/src/components/RichText/index.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/theme.d.ts +0 -8
- package/dist/types/src/components/TextEditor/theme.d.ts.map +0 -1
- package/dist/types/src/model.d.ts.map +0 -1
- package/dist/types/src/yjs/cursors.d.ts.map +0 -1
- package/dist/types/src/yjs/index.d.ts.map +0 -1
- package/dist/types/src/yjs/space-provider.d.ts.map +0 -1
- package/dist/types/stories/html/code-mirror.stories.d.ts.map +0 -1
- package/src/automerge/demo.ts +0 -106
- package/src/components/Editor/Editor.stories.tsx +0 -80
- package/src/components/Editor/Editor.tsx +0 -33
- package/src/components/Editor/index.ts +0 -5
- package/src/components/Markdown/Markdown.stories.tsx +0 -57
- package/src/components/Markdown/Markdown.tsx +0 -210
- package/src/components/Markdown/index.ts +0 -5
- package/src/components/RichText/RichText.stories.tsx +0 -68
- package/src/components/RichText/RichText.tsx +0 -181
- package/src/components/RichText/index.ts +0 -5
- package/src/components/TextEditor/theme.ts +0 -29
- /package/dist/types/src/{yjs → hooks/yjs}/cursors.d.ts +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/index.d.ts +0 -0
- /package/dist/types/src/{yjs → hooks/yjs}/space-provider.d.ts +0 -0
- /package/src/components/{Markdown/markdownTags.ts → TextEditor/extensions/markdown/tags.ts} +0 -0
- /package/src/{yjs → hooks/yjs}/cursors.ts +0 -0
- /package/src/{yjs → hooks/yjs}/index.ts +0 -0
- /package/src/{yjs → hooks/yjs}/space-provider.ts +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/react-ui-editor",
|
|
3
|
-
"version": "0.3.9-main.
|
|
3
|
+
"version": "0.3.9-main.71124bf",
|
|
4
4
|
"description": "Document editing experience within a DXOS shell.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
@@ -13,16 +13,16 @@
|
|
|
13
13
|
"src"
|
|
14
14
|
],
|
|
15
15
|
"dependencies": {
|
|
16
|
-
"@codemirror/autocomplete": "^6.11.
|
|
17
|
-
"@codemirror/commands": "^6.3.
|
|
18
|
-
"@codemirror/lang-markdown": "^6.2.
|
|
19
|
-
"@codemirror/language": "^6.9.
|
|
16
|
+
"@codemirror/autocomplete": "^6.11.1",
|
|
17
|
+
"@codemirror/commands": "^6.3.2",
|
|
18
|
+
"@codemirror/lang-markdown": "^6.2.3",
|
|
19
|
+
"@codemirror/language": "^6.9.3",
|
|
20
20
|
"@codemirror/language-data": "^6.3.1",
|
|
21
21
|
"@codemirror/lint": "^6.4.2",
|
|
22
|
-
"@codemirror/search": "^6.5.
|
|
23
|
-
"@codemirror/state": "^6.3.
|
|
22
|
+
"@codemirror/search": "^6.5.5",
|
|
23
|
+
"@codemirror/state": "^6.3.3",
|
|
24
24
|
"@codemirror/theme-one-dark": "^6.1.2",
|
|
25
|
-
"@codemirror/view": "^6.22.
|
|
25
|
+
"@codemirror/view": "^6.22.2",
|
|
26
26
|
"@fluentui/react-tabster": "^9.12.0",
|
|
27
27
|
"@lezer/common": "^1.1.1",
|
|
28
28
|
"@lezer/highlight": "^1.2.0",
|
|
@@ -37,8 +37,9 @@
|
|
|
37
37
|
"@tiptap/pm": "2.0.0-beta.220",
|
|
38
38
|
"@tiptap/react": "2.0.0-beta.220",
|
|
39
39
|
"@tiptap/starter-kit": "2.0.0-beta.220",
|
|
40
|
-
"codemirror": "
|
|
40
|
+
"codemirror": "6.0.1",
|
|
41
41
|
"lib0": "^0.2.65",
|
|
42
|
+
"lodash.defaultsdeep": "^4.6.1",
|
|
42
43
|
"lodash.get": "^4.4.2",
|
|
43
44
|
"prosemirror-model": "^1.19.0",
|
|
44
45
|
"prosemirror-state": "^1.4.2",
|
|
@@ -48,34 +49,39 @@
|
|
|
48
49
|
"y-prosemirror": "~1.0.20",
|
|
49
50
|
"y-protocols": "^1.0.5",
|
|
50
51
|
"yjs": "^13.6.10",
|
|
51
|
-
"@dxos/debug": "0.3.9-main.
|
|
52
|
-
"@dxos/
|
|
53
|
-
"@dxos/
|
|
54
|
-
"@dxos/
|
|
55
|
-
"@dxos/
|
|
56
|
-
"@dxos/
|
|
57
|
-
"@dxos/protocols": "0.3.9-main.
|
|
58
|
-
"@dxos/
|
|
59
|
-
"@dxos/
|
|
52
|
+
"@dxos/debug": "0.3.9-main.71124bf",
|
|
53
|
+
"@dxos/automerge": "0.3.9-main.71124bf",
|
|
54
|
+
"@dxos/display-name": "0.3.9-main.71124bf",
|
|
55
|
+
"@dxos/echo-schema": "0.3.9-main.71124bf",
|
|
56
|
+
"@dxos/invariant": "0.3.9-main.71124bf",
|
|
57
|
+
"@dxos/log": "0.3.9-main.71124bf",
|
|
58
|
+
"@dxos/protocols": "0.3.9-main.71124bf",
|
|
59
|
+
"@dxos/react-async": "0.3.9-main.71124bf",
|
|
60
|
+
"@dxos/react-ui": "0.3.9-main.71124bf",
|
|
61
|
+
"@dxos/react-ui-theme": "0.3.9-main.71124bf",
|
|
62
|
+
"@dxos/text-model": "0.3.9-main.71124bf",
|
|
63
|
+
"@dxos/util": "0.3.9-main.71124bf"
|
|
60
64
|
},
|
|
61
65
|
"devDependencies": {
|
|
62
|
-
"@
|
|
63
|
-
"@
|
|
66
|
+
"@automerge/automerge-repo-network-broadcastchannel": "^1.0.19",
|
|
67
|
+
"@phosphor-icons/react": "^2.0.5",
|
|
68
|
+
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
64
69
|
"@types/lodash.get": "^4.4.7",
|
|
65
70
|
"@types/react": "^18.0.21",
|
|
66
71
|
"@types/react-dom": "^18.0.6",
|
|
67
72
|
"react": "^18.2.0",
|
|
68
73
|
"react-dom": "^18.2.0",
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/
|
|
74
|
+
"@dxos/echo-typegen": "0.3.9-main.71124bf",
|
|
75
|
+
"@dxos/react-client": "0.3.9-main.71124bf",
|
|
76
|
+
"@dxos/react-ui": "0.3.9-main.71124bf",
|
|
77
|
+
"@dxos/storybook-utils": "0.3.9-main.71124bf",
|
|
78
|
+
"@dxos/config": "0.3.9-main.71124bf"
|
|
74
79
|
},
|
|
75
80
|
"peerDependencies": {
|
|
81
|
+
"@phosphor-icons/react": "^2.0.5",
|
|
76
82
|
"react": "^18.2.0",
|
|
77
83
|
"react-dom": "^18.2.0",
|
|
78
|
-
"@dxos/react-client": "0.3.9-main.
|
|
84
|
+
"@dxos/react-client": "0.3.9-main.71124bf"
|
|
79
85
|
},
|
|
80
86
|
"publishConfig": {
|
|
81
87
|
"access": "public"
|
|
@@ -8,8 +8,8 @@ import { next as automerge } from '@dxos/automerge/automerge';
|
|
|
8
8
|
|
|
9
9
|
import amToCodemirror from './amToCodemirror';
|
|
10
10
|
import codeMirrorToAm from './codeMirrorToAm';
|
|
11
|
+
import { type IDocHandle } from './handle';
|
|
11
12
|
import { type Field, isReconcileTx, getPath, reconcileAnnotationType, updateHeads, getLastHeads } from './plugin';
|
|
12
|
-
import { type Peer } from '../demo';
|
|
13
13
|
|
|
14
14
|
type Doc<T> = automerge.Doc<T>;
|
|
15
15
|
type Heads = automerge.Heads;
|
|
@@ -27,8 +27,8 @@ export class PatchSemaphore {
|
|
|
27
27
|
}
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
-
reconcile = (handle:
|
|
31
|
-
if (
|
|
30
|
+
reconcile = (handle: IDocHandle, view: EditorView) => {
|
|
31
|
+
if (this._inReconcile) {
|
|
32
32
|
return;
|
|
33
33
|
}
|
|
34
34
|
this._inReconcile = true;
|
|
@@ -56,12 +56,12 @@ export class PatchSemaphore {
|
|
|
56
56
|
// NOTE: null and undefined each come from automerge and repo respectively
|
|
57
57
|
if (newHeads === null || newHeads === undefined) {
|
|
58
58
|
// TODO: @alexjg this is the call that's resetting the editor state on click
|
|
59
|
-
newHeads = automerge.getHeads(handle.
|
|
59
|
+
newHeads = automerge.getHeads(handle.docSync()!);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
62
|
// now get the diff between the updated state of the document and the heads
|
|
63
63
|
// and apply that to the codemirror doc
|
|
64
|
-
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.
|
|
64
|
+
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync()!, oldHeads, newHeads);
|
|
65
65
|
amToCodemirror(view, selection, path, diff);
|
|
66
66
|
|
|
67
67
|
view.dispatch({
|
|
@@ -6,21 +6,24 @@ import { type EditorState, type Text, type Transaction } from '@codemirror/state
|
|
|
6
6
|
|
|
7
7
|
import { next as am, type Heads } from '@dxos/automerge/automerge';
|
|
8
8
|
|
|
9
|
+
import { type IDocHandle } from './handle';
|
|
9
10
|
import { type Field } from './plugin';
|
|
10
|
-
import { type Peer } from '../demo';
|
|
11
11
|
|
|
12
|
-
export default (
|
|
12
|
+
export default (
|
|
13
|
+
field: Field,
|
|
14
|
+
handle: IDocHandle,
|
|
15
|
+
transactions: Transaction[],
|
|
16
|
+
state: EditorState,
|
|
17
|
+
): Heads | undefined => {
|
|
13
18
|
const { lastHeads, path } = state.field(field);
|
|
14
19
|
|
|
15
20
|
// We don't want to call `automerge.updateAt` if there are no changes.
|
|
16
21
|
// Otherwise later on `automerge.diff` will return empty patches that result in a no-op but still mess up the selection.
|
|
17
22
|
let hasChanges = false;
|
|
18
23
|
for (const tr of transactions) {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
});
|
|
23
|
-
}
|
|
24
|
+
tr.changes.iterChanges(() => {
|
|
25
|
+
hasChanges = true;
|
|
26
|
+
});
|
|
24
27
|
}
|
|
25
28
|
|
|
26
29
|
if (!hasChanges) {
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2023 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import type * as A from '@dxos/automerge/automerge';
|
|
6
|
+
|
|
7
|
+
export type IDocHandle<T = any> = {
|
|
8
|
+
docSync(): A.Doc<T> | undefined;
|
|
9
|
+
change(callback: A.ChangeFn<T>, options?: A.ChangeOptions<T>): void;
|
|
10
|
+
changeAt(heads: A.Heads, callback: A.ChangeFn<T>, options?: A.ChangeOptions<T>): string[] | undefined;
|
|
11
|
+
|
|
12
|
+
addListener(event: 'change', listener: () => void): void;
|
|
13
|
+
removeListener(event: 'change', listener: () => void): void;
|
|
14
|
+
};
|
|
@@ -12,13 +12,13 @@ import {
|
|
|
12
12
|
type Transaction,
|
|
13
13
|
type TransactionSpec,
|
|
14
14
|
} from '@codemirror/state';
|
|
15
|
-
import { type EditorView } from '@codemirror/view';
|
|
15
|
+
import { ViewPlugin, type EditorView, type PluginValue, type ViewUpdate } from '@codemirror/view';
|
|
16
16
|
|
|
17
17
|
import * as automerge from '@dxos/automerge/automerge';
|
|
18
|
-
import { type
|
|
18
|
+
import { type Heads, type Prop } from '@dxos/automerge/automerge';
|
|
19
19
|
|
|
20
20
|
import { PatchSemaphore } from './PatchSemaphore';
|
|
21
|
-
import { type
|
|
21
|
+
import { type IDocHandle } from './handle';
|
|
22
22
|
|
|
23
23
|
export type Value = {
|
|
24
24
|
lastHeads: Heads;
|
|
@@ -44,10 +44,14 @@ const semaphoreFacet = Facet.define<PatchSemaphore, PatchSemaphore>({
|
|
|
44
44
|
combine: (values) => values.at(-1)!, // Take last.
|
|
45
45
|
});
|
|
46
46
|
|
|
47
|
-
export
|
|
47
|
+
export type AutomergePlugin = {
|
|
48
|
+
extension: Extension;
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
export const automergePlugin = (handle: IDocHandle, path: Prop[]): AutomergePlugin => {
|
|
48
52
|
const stateField: StateField<Value> = StateField.define({
|
|
49
53
|
create: () => ({
|
|
50
|
-
lastHeads: automerge.getHeads(
|
|
54
|
+
lastHeads: automerge.getHeads(handle.docSync()!),
|
|
51
55
|
unreconciledTransactions: [],
|
|
52
56
|
path: path.slice(),
|
|
53
57
|
}),
|
|
@@ -76,7 +80,36 @@ export const plugin = <T>(doc: Doc<T>, path: Prop[]): Extension => {
|
|
|
76
80
|
});
|
|
77
81
|
const semaphore = new PatchSemaphore(stateField);
|
|
78
82
|
|
|
79
|
-
|
|
83
|
+
const viewPlugin = ViewPlugin.fromClass(
|
|
84
|
+
class AutomergeCodemirrorViewPlugin implements PluginValue {
|
|
85
|
+
private _view: EditorView;
|
|
86
|
+
|
|
87
|
+
constructor(view: EditorView) {
|
|
88
|
+
this._view = view;
|
|
89
|
+
handle.addListener('change', this._handleChange);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
update(update: ViewUpdate) {
|
|
93
|
+
if (update.transactions.length > 0 && update.transactions.some((t) => !isReconcileTx(t))) {
|
|
94
|
+
queueMicrotask(() => {
|
|
95
|
+
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
destroy() {
|
|
101
|
+
handle.addListener('change', this._handleChange);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
private _handleChange = () => {
|
|
105
|
+
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
106
|
+
};
|
|
107
|
+
},
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
return {
|
|
111
|
+
extension: [stateField, semaphoreFacet.of(semaphore), viewPlugin],
|
|
112
|
+
};
|
|
80
113
|
};
|
|
81
114
|
|
|
82
115
|
export const reconcileAnnotationType = Annotation.define<unknown>();
|
|
@@ -98,7 +131,3 @@ export const makeReconcile = (tr: TransactionSpec) => {
|
|
|
98
131
|
// annotations: reconcileAnnotationType.of({})
|
|
99
132
|
// }
|
|
100
133
|
};
|
|
101
|
-
|
|
102
|
-
export const reconcile = (handle: Peer, view: EditorView) => {
|
|
103
|
-
view.state.facet(semaphoreFacet).reconcile(handle, view);
|
|
104
|
-
};
|
|
@@ -2,17 +2,20 @@
|
|
|
2
2
|
// Copyright 2023 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import
|
|
5
|
+
import '@preact/signals-react'; // Register react integration
|
|
6
|
+
import { BroadcastChannelNetworkAdapter } from '@automerge/automerge-repo-network-broadcastchannel';
|
|
6
7
|
import { EditorView } from '@codemirror/view';
|
|
8
|
+
import { basicSetup } from 'codemirror';
|
|
9
|
+
import get from 'lodash.get';
|
|
7
10
|
import React, { useEffect, useRef, useState } from 'react';
|
|
8
11
|
|
|
9
|
-
import { type Prop
|
|
12
|
+
import { type Prop } from '@dxos/automerge/automerge';
|
|
13
|
+
import { type DocHandle, Repo } from '@dxos/automerge/automerge-repo';
|
|
10
14
|
|
|
11
|
-
import {
|
|
12
|
-
import { Peer } from './demo';
|
|
15
|
+
import { type IDocHandle, automergePlugin } from './automerge-plugin';
|
|
13
16
|
|
|
14
17
|
type EditorProps = {
|
|
15
|
-
handle:
|
|
18
|
+
handle: IDocHandle;
|
|
16
19
|
path: Prop[];
|
|
17
20
|
};
|
|
18
21
|
|
|
@@ -21,27 +24,13 @@ const Editor = ({ handle, path }: EditorProps) => {
|
|
|
21
24
|
const editorRoot = useRef<EditorView>();
|
|
22
25
|
|
|
23
26
|
useEffect(() => {
|
|
24
|
-
const doc = handle.doc;
|
|
25
|
-
const source = doc.text; // this should use path
|
|
26
|
-
const plugin = amgPlugin(doc, path);
|
|
27
27
|
const view = (editorRoot.current = new EditorView({
|
|
28
|
-
doc:
|
|
29
|
-
extensions: [basicSetup,
|
|
30
|
-
dispatch: (transaction) => {
|
|
31
|
-
view.update([transaction]);
|
|
32
|
-
reconcile(handle, view);
|
|
33
|
-
},
|
|
28
|
+
doc: get(handle.docSync()!, path),
|
|
29
|
+
extensions: [basicSetup, automergePlugin(handle, path)],
|
|
34
30
|
parent: containerRef.current as any,
|
|
35
31
|
}));
|
|
36
32
|
|
|
37
|
-
const handleChange = () => {
|
|
38
|
-
reconcile(handle, view);
|
|
39
|
-
};
|
|
40
|
-
|
|
41
|
-
handle.changeEvent.on(handleChange);
|
|
42
|
-
|
|
43
33
|
return () => {
|
|
44
|
-
handle.changeEvent.off(handleChange);
|
|
45
34
|
view.destroy();
|
|
46
35
|
};
|
|
47
36
|
}, []);
|
|
@@ -50,31 +39,29 @@ const Editor = ({ handle, path }: EditorProps) => {
|
|
|
50
39
|
};
|
|
51
40
|
|
|
52
41
|
const Story = () => {
|
|
53
|
-
const [object1, setObject1] = useState<
|
|
54
|
-
const [object2, setObject2] = useState<
|
|
55
|
-
const [stats1, setStats1] = useState<any>({});
|
|
56
|
-
const [stats2, setStats2] = useState<any>({});
|
|
42
|
+
const [object1, setObject1] = useState<DocHandle<any> | null>(null);
|
|
43
|
+
const [object2, setObject2] = useState<DocHandle<any> | null>(null);
|
|
57
44
|
|
|
58
45
|
useEffect(() => {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
}
|
|
46
|
+
queueMicrotask(async () => {
|
|
47
|
+
const repo1 = new Repo({
|
|
48
|
+
network: [new BroadcastChannelNetworkAdapter()],
|
|
49
|
+
});
|
|
50
|
+
const repo2 = new Repo({
|
|
51
|
+
network: [new BroadcastChannelNetworkAdapter()],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
const object1 = repo1.create();
|
|
55
|
+
object1.change((doc: any) => {
|
|
56
|
+
doc.text = 'Hello world!';
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const object2 = repo2.find(object1.url);
|
|
60
|
+
await object2.whenReady();
|
|
61
|
+
|
|
62
|
+
setObject1(object1);
|
|
63
|
+
setObject2(object2);
|
|
64
|
+
});
|
|
78
65
|
}, []);
|
|
79
66
|
|
|
80
67
|
if (!object1 || !object2) {
|
|
@@ -85,11 +72,9 @@ const Story = () => {
|
|
|
85
72
|
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', width: '100vw' }}>
|
|
86
73
|
<div>
|
|
87
74
|
<Editor handle={object1} path={['text']} />
|
|
88
|
-
<div style={{ whiteSpace: 'pre' }}>{JSON.stringify(stats1, null, 2)}</div>
|
|
89
75
|
</div>
|
|
90
76
|
<div>
|
|
91
77
|
<Editor handle={object2} path={['text']} />
|
|
92
|
-
<div style={{ whiteSpace: 'pre' }}>{JSON.stringify(stats2, null, 2)}</div>
|
|
93
78
|
</div>
|
|
94
79
|
</div>
|
|
95
80
|
);
|
|
@@ -99,6 +84,6 @@ export default {
|
|
|
99
84
|
title: 'Automerge',
|
|
100
85
|
};
|
|
101
86
|
|
|
102
|
-
export const
|
|
87
|
+
export const AutomergeRepo = {
|
|
103
88
|
render: () => <Story />,
|
|
104
89
|
};
|
|
@@ -3,29 +3,77 @@
|
|
|
3
3
|
//
|
|
4
4
|
|
|
5
5
|
import '@dxosTheme';
|
|
6
|
-
import
|
|
6
|
+
import { markdown } from '@codemirror/lang-markdown';
|
|
7
|
+
import { ArrowCircleUp } from '@phosphor-icons/react';
|
|
8
|
+
import React, { StrictMode, useState } from 'react';
|
|
9
|
+
import { createRoot } from 'react-dom/client';
|
|
7
10
|
|
|
8
11
|
import { TextObject } from '@dxos/echo-schema';
|
|
9
|
-
import { fixedInsetFlexLayout, groupSurface, inputSurface, mx } from '@dxos/react-ui-theme';
|
|
12
|
+
import { fixedInsetFlexLayout, getSize, groupSurface, inputSurface, mx } from '@dxos/react-ui-theme';
|
|
13
|
+
import { withTheme } from '@dxos/storybook-utils';
|
|
10
14
|
|
|
11
15
|
import { TextEditor } from './TextEditor';
|
|
12
|
-
import {
|
|
16
|
+
import { createHyperlinkTooltip, hyperlinkDecoration } from './extensions';
|
|
17
|
+
import { useTextModel } from '../../hooks';
|
|
13
18
|
|
|
14
|
-
const
|
|
15
|
-
|
|
19
|
+
const text = [
|
|
20
|
+
'',
|
|
21
|
+
'',
|
|
22
|
+
'This is all about [DXOS](https://dxos.org); read more [here](https://docs.dxos.org/guide/getting-started.html).',
|
|
23
|
+
'',
|
|
24
|
+
'',
|
|
25
|
+
].join('\n');
|
|
26
|
+
|
|
27
|
+
const hyperLinkTooltip = () =>
|
|
28
|
+
createHyperlinkTooltip((el, url) => {
|
|
29
|
+
const web = new URL(url);
|
|
30
|
+
createRoot(el).render(
|
|
31
|
+
<StrictMode>
|
|
32
|
+
<div className='flex gap-1 items-center'>
|
|
33
|
+
<ArrowCircleUp className={mx(getSize(6), 'text-blue-500')} />
|
|
34
|
+
<p className='pr-1'>{web.origin}</p>
|
|
35
|
+
</div>
|
|
36
|
+
</StrictMode>,
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
const Story = ({ automerge }: { automerge?: boolean }) => {
|
|
41
|
+
const [item] = useState({ text: new TextObject(text, undefined, undefined, { useAutomergeBackend: !!automerge }) });
|
|
16
42
|
const model = useTextModel({ text: item.text });
|
|
43
|
+
if (!model) {
|
|
44
|
+
return <></>;
|
|
45
|
+
}
|
|
17
46
|
|
|
18
47
|
return (
|
|
19
|
-
<div className={mx(fixedInsetFlexLayout, groupSurface
|
|
20
|
-
<
|
|
21
|
-
|
|
48
|
+
<div className={mx(fixedInsetFlexLayout, groupSurface)}>
|
|
49
|
+
<div className='flex justify-center p-8'>
|
|
50
|
+
<div className='w-[800px]'>
|
|
51
|
+
<TextEditor
|
|
52
|
+
model={model}
|
|
53
|
+
extensions={[
|
|
54
|
+
markdown(),
|
|
55
|
+
hyperlinkDecoration({ link: false }),
|
|
56
|
+
hyperLinkTooltip(),
|
|
57
|
+
// EditorView.domEventHandlers({
|
|
58
|
+
// mousedown: (e, view) => {},
|
|
59
|
+
// }),
|
|
60
|
+
]}
|
|
61
|
+
slots={{ root: { className: mx(inputSurface, 'p-2') } }}
|
|
62
|
+
/>
|
|
63
|
+
</div>
|
|
64
|
+
</div>
|
|
22
65
|
</div>
|
|
23
66
|
);
|
|
24
67
|
};
|
|
25
68
|
|
|
26
69
|
export default {
|
|
27
70
|
component: TextEditor,
|
|
71
|
+
decorators: [withTheme],
|
|
28
72
|
render: Story,
|
|
29
73
|
};
|
|
30
74
|
|
|
31
75
|
export const Default = {};
|
|
76
|
+
|
|
77
|
+
export const Automerge = {
|
|
78
|
+
render: () => <Story automerge />,
|
|
79
|
+
};
|