@dxos/ui-editor 0.0.0 → 0.8.4-main.1c7ec43d41
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 +8633 -0
- package/dist/lib/browser/index.mjs.map +7 -0
- package/dist/lib/browser/meta.json +1 -0
- package/dist/lib/browser/types/index.mjs +33 -0
- package/dist/lib/browser/types/index.mjs.map +7 -0
- package/dist/lib/node-esm/index.mjs +8635 -0
- package/dist/lib/node-esm/index.mjs.map +7 -0
- package/dist/lib/node-esm/meta.json +1 -0
- package/dist/lib/node-esm/types/index.mjs +35 -0
- package/dist/lib/node-esm/types/index.mjs.map +7 -0
- package/dist/types/src/defaults.d.ts +6 -0
- package/dist/types/src/defaults.d.ts.map +1 -0
- package/dist/types/src/extensions/annotations.d.ts +9 -0
- package/dist/types/src/extensions/annotations.d.ts.map +1 -0
- package/dist/types/src/extensions/auto-scroll.d.ts +18 -0
- package/dist/types/src/extensions/auto-scroll.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/autocomplete.d.ts +17 -0
- package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/index.d.ts +5 -0
- package/dist/types/src/extensions/autocomplete/index.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/match.d.ts +13 -0
- package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts +23 -0
- package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -0
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts +10 -0
- package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts +4 -0
- package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
- package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts +4 -0
- package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/defs.d.ts +17 -0
- package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/index.d.ts +2 -0
- package/dist/types/src/extensions/automerge/index.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/sync.d.ts +17 -0
- package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts +6 -0
- package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts +5 -0
- package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts +31 -0
- package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness/awareness.d.ts +46 -0
- package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/awareness/index.d.ts +3 -0
- package/dist/types/src/extensions/awareness/index.d.ts.map +1 -0
- package/dist/types/src/extensions/blast.d.ts +25 -0
- package/dist/types/src/extensions/blast.d.ts.map +1 -0
- package/dist/types/src/extensions/blocks.d.ts +2 -0
- package/dist/types/src/extensions/blocks.d.ts.map +1 -0
- package/dist/types/src/extensions/bookmarks.d.ts +12 -0
- package/dist/types/src/extensions/bookmarks.d.ts.map +1 -0
- package/dist/types/src/extensions/comments.d.ts +90 -0
- package/dist/types/src/extensions/comments.d.ts.map +1 -0
- package/dist/types/src/extensions/debug.d.ts +3 -0
- package/dist/types/src/extensions/debug.d.ts.map +1 -0
- package/dist/types/src/extensions/dnd.d.ts +9 -0
- package/dist/types/src/extensions/dnd.d.ts.map +1 -0
- package/dist/types/src/extensions/factories.d.ts +88 -0
- package/dist/types/src/extensions/factories.d.ts.map +1 -0
- package/dist/types/src/extensions/factories.test.d.ts +2 -0
- package/dist/types/src/extensions/factories.test.d.ts.map +1 -0
- package/dist/types/src/extensions/focus.d.ts +7 -0
- package/dist/types/src/extensions/focus.d.ts.map +1 -0
- package/dist/types/src/extensions/folding.d.ts +6 -0
- package/dist/types/src/extensions/folding.d.ts.map +1 -0
- package/dist/types/src/extensions/hashtag.d.ts +3 -0
- package/dist/types/src/extensions/hashtag.d.ts.map +1 -0
- package/dist/types/src/extensions/index.d.ts +32 -0
- package/dist/types/src/extensions/index.d.ts.map +1 -0
- package/dist/types/src/extensions/json.d.ts +7 -0
- package/dist/types/src/extensions/json.d.ts.map +1 -0
- package/dist/types/src/extensions/listener.d.ts +13 -0
- package/dist/types/src/extensions/listener.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/action.d.ts +12 -0
- package/dist/types/src/extensions/markdown/action.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/bundle.d.ts +25 -0
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/changes.d.ts +10 -0
- package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/changes.test.d.ts +2 -0
- package/dist/types/src/extensions/markdown/changes.test.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/debug.d.ts +11 -0
- package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/decorate.d.ts +25 -0
- package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts +63 -0
- package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts +3 -0
- package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts +37 -0
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/image.d.ts +7 -0
- package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/index.d.ts +10 -0
- package/dist/types/src/extensions/markdown/index.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/link.d.ts +7 -0
- package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/parser.test.d.ts +2 -0
- package/dist/types/src/extensions/markdown/parser.test.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/styles.d.ts +4 -0
- package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -0
- package/dist/types/src/extensions/markdown/table.d.ts +8 -0
- package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
- package/dist/types/src/extensions/mention.d.ts +7 -0
- package/dist/types/src/extensions/mention.d.ts.map +1 -0
- package/dist/types/src/extensions/modal.d.ts +7 -0
- package/dist/types/src/extensions/modal.d.ts.map +1 -0
- package/dist/types/src/extensions/modes.d.ts +10 -0
- package/dist/types/src/extensions/modes.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/commands.d.ts +10 -0
- package/dist/types/src/extensions/outliner/commands.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/editor.d.ts +5 -0
- package/dist/types/src/extensions/outliner/editor.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/editor.test.d.ts +2 -0
- package/dist/types/src/extensions/outliner/editor.test.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/index.d.ts +4 -0
- package/dist/types/src/extensions/outliner/index.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/menu.d.ts +8 -0
- package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/outliner.d.ts +11 -0
- package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/outliner.test.d.ts +2 -0
- package/dist/types/src/extensions/outliner/outliner.test.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/selection.d.ts +12 -0
- package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/tree.d.ts +79 -0
- package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -0
- package/dist/types/src/extensions/outliner/tree.test.d.ts +2 -0
- package/dist/types/src/extensions/outliner/tree.test.d.ts.map +1 -0
- package/dist/types/src/extensions/preview/index.d.ts +2 -0
- package/dist/types/src/extensions/preview/index.d.ts.map +1 -0
- package/dist/types/src/extensions/preview/preview.d.ts +34 -0
- package/dist/types/src/extensions/preview/preview.d.ts.map +1 -0
- package/dist/types/src/extensions/replacer.d.ts +21 -0
- package/dist/types/src/extensions/replacer.d.ts.map +1 -0
- package/dist/types/src/extensions/replacer.test.d.ts +2 -0
- package/dist/types/src/extensions/replacer.test.d.ts.map +1 -0
- package/dist/types/src/extensions/scroll-past-end.d.ts +3 -0
- package/dist/types/src/extensions/scroll-past-end.d.ts.map +1 -0
- package/dist/types/src/extensions/scroller.d.ts +68 -0
- package/dist/types/src/extensions/scroller.d.ts.map +1 -0
- package/dist/types/src/extensions/selection.d.ts +24 -0
- package/dist/types/src/extensions/selection.d.ts.map +1 -0
- package/dist/types/src/extensions/snippets.d.ts +10 -0
- package/dist/types/src/extensions/snippets.d.ts.map +1 -0
- package/dist/types/src/extensions/state.d.ts +2 -0
- package/dist/types/src/extensions/state.d.ts.map +1 -0
- package/dist/types/src/extensions/submit.d.ts +10 -0
- package/dist/types/src/extensions/submit.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/extended-markdown.d.ts +10 -0
- package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/extended-markdown.test.d.ts +2 -0
- package/dist/types/src/extensions/tags/extended-markdown.test.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/fader.d.ts +12 -0
- package/dist/types/src/extensions/tags/fader.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/index.d.ts +7 -0
- package/dist/types/src/extensions/tags/index.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/typewriter.d.ts +43 -0
- package/dist/types/src/extensions/tags/typewriter.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/typewriter.test.d.ts +2 -0
- package/dist/types/src/extensions/tags/typewriter.test.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +31 -0
- package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/xml-formatting.d.ts +24 -0
- package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/xml-tags.d.ts +117 -0
- package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/xml-util.d.ts +10 -0
- package/dist/types/src/extensions/tags/xml-util.d.ts.map +1 -0
- package/dist/types/src/extensions/tags/xml-util.test.d.ts +2 -0
- package/dist/types/src/extensions/tags/xml-util.test.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +8 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +2 -0
- package/dist/types/src/styles/index.d.ts.map +1 -0
- package/dist/types/src/styles/theme.d.ts +58 -0
- package/dist/types/src/styles/theme.d.ts.map +1 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/index.d.ts.map +1 -0
- package/dist/types/src/types/types.d.ts +21 -0
- package/dist/types/src/types/types.d.ts.map +1 -0
- package/dist/types/src/util/cursor.d.ts +31 -0
- package/dist/types/src/util/cursor.d.ts.map +1 -0
- package/dist/types/src/util/debug.d.ts +17 -0
- package/dist/types/src/util/debug.d.ts.map +1 -0
- package/dist/types/src/util/decorations.d.ts +4 -0
- package/dist/types/src/util/decorations.d.ts.map +1 -0
- package/dist/types/src/util/dom.d.ts +10 -0
- package/dist/types/src/util/dom.d.ts.map +1 -0
- package/dist/types/src/util/facet.d.ts +3 -0
- package/dist/types/src/util/facet.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +7 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/util.d.ts +8 -0
- package/dist/types/src/util/util.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +42 -43
- package/src/defaults.ts +33 -20
- package/src/extensions/annotations.ts +1 -1
- package/src/extensions/auto-scroll.ts +234 -0
- package/src/extensions/autocomplete/placeholder.ts +37 -18
- package/src/extensions/automerge/automerge.test.tsx +37 -11
- package/src/extensions/automerge/automerge.ts +5 -7
- package/src/extensions/blocks.ts +5 -5
- package/src/extensions/comments.ts +5 -6
- package/src/extensions/dnd.ts +2 -2
- package/src/extensions/factories.test.ts +88 -0
- package/src/extensions/factories.ts +32 -15
- package/src/extensions/folding.ts +5 -22
- package/src/extensions/index.ts +4 -3
- package/src/extensions/markdown/action.ts +0 -1
- package/src/extensions/markdown/bundle.ts +23 -9
- package/src/extensions/markdown/decorate.ts +15 -12
- package/src/extensions/markdown/formatting.ts +5 -10
- package/src/extensions/markdown/highlight.ts +15 -7
- package/src/extensions/markdown/link.ts +27 -33
- package/src/extensions/markdown/parser.test.ts +0 -1
- package/src/extensions/markdown/styles.ts +42 -9
- package/src/extensions/markdown/table.ts +24 -2
- package/src/extensions/outliner/outliner.test.ts +0 -1
- package/src/extensions/outliner/outliner.ts +3 -4
- package/src/extensions/outliner/tree.test.ts +0 -1
- package/src/extensions/preview/preview.ts +62 -15
- package/src/extensions/scroll-past-end.ts +32 -0
- package/src/extensions/scroller.ts +256 -0
- package/src/extensions/selection.ts +1 -1
- package/src/extensions/snippets.ts +67 -0
- package/src/extensions/tags/extended-markdown.test.ts +120 -2
- package/src/extensions/tags/extended-markdown.ts +80 -1
- package/src/extensions/tags/fader.ts +195 -0
- package/src/extensions/tags/index.ts +4 -1
- package/src/extensions/tags/testing/text.md +36 -0
- package/src/extensions/tags/testing/text.txt +35 -0
- package/src/extensions/tags/typewriter.test.ts +65 -0
- package/src/extensions/tags/typewriter.ts +594 -0
- package/src/extensions/tags/xml-block-decoration.ts +123 -0
- package/src/extensions/tags/xml-formatting.ts +125 -0
- package/src/extensions/tags/xml-tags.ts +186 -35
- package/src/extensions/tags/xml-util.test.ts +199 -24
- package/src/extensions/tags/xml-util.ts +62 -5
- package/src/index.ts +0 -1
- package/src/styles/index.ts +0 -2
- package/src/styles/theme.ts +124 -33
- package/src/types/types.ts +10 -2
- package/src/typings.d.ts +8 -0
- package/src/util/cursor.ts +1 -2
- package/src/extensions/autoscroll.ts +0 -165
- package/src/extensions/scrolling.ts +0 -189
- package/src/extensions/tags/streamer.ts +0 -243
- package/src/extensions/typewriter.ts +0 -68
- package/src/styles/markdown.ts +0 -26
- package/src/styles/tokens.ts +0 -17
package/package.json
CHANGED
|
@@ -1,9 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@dxos/ui-editor",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.8.4-main.1c7ec43d41",
|
|
4
4
|
"description": "Text editor components.",
|
|
5
5
|
"homepage": "https://dxos.org",
|
|
6
6
|
"bugs": "https://github.com/dxos/dxos/issues",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "https://github.com/dxos/dxos"
|
|
10
|
+
},
|
|
7
11
|
"license": "MIT",
|
|
8
12
|
"author": "DXOS.org",
|
|
9
13
|
"sideEffects": false,
|
|
@@ -23,15 +27,12 @@
|
|
|
23
27
|
}
|
|
24
28
|
},
|
|
25
29
|
"types": "dist/types/src/index.d.ts",
|
|
26
|
-
"typesVersions": {
|
|
27
|
-
"*": {}
|
|
28
|
-
},
|
|
29
30
|
"files": [
|
|
30
31
|
"dist",
|
|
31
32
|
"src"
|
|
32
33
|
],
|
|
33
34
|
"dependencies": {
|
|
34
|
-
"@automerge/automerge": "3.2.
|
|
35
|
+
"@automerge/automerge": "3.2.6",
|
|
35
36
|
"@codemirror/autocomplete": "^6.19.0",
|
|
36
37
|
"@codemirror/commands": "^6.8.1",
|
|
37
38
|
"@codemirror/lang-html": "^6.4.11",
|
|
@@ -46,7 +47,7 @@
|
|
|
46
47
|
"@codemirror/search": "^6.5.11",
|
|
47
48
|
"@codemirror/state": "^6.5.2",
|
|
48
49
|
"@codemirror/theme-one-dark": "^6.1.3",
|
|
49
|
-
"@codemirror/view": "^6.38.
|
|
50
|
+
"@codemirror/view": "^6.38.5",
|
|
50
51
|
"@lezer/common": "^1.2.2",
|
|
51
52
|
"@lezer/generator": "^1.7.1",
|
|
52
53
|
"@lezer/highlight": "^1.2.1",
|
|
@@ -54,36 +55,35 @@
|
|
|
54
55
|
"@replit/codemirror-vim": "^6.2.1",
|
|
55
56
|
"@replit/codemirror-vscode-keymap": "^6.0.2",
|
|
56
57
|
"@uiw/codemirror-theme-vscode": "^4.25.2",
|
|
57
|
-
"ajv": "^8.
|
|
58
|
+
"ajv": "^8.18.0",
|
|
58
59
|
"codemirror": "^6.0.1",
|
|
59
60
|
"lib0": "^0.2.65",
|
|
60
61
|
"lodash.defaultsdeep": "^4.6.1",
|
|
61
62
|
"lodash.merge": "^4.6.2",
|
|
62
63
|
"lodash.sortby": "^4.7.0",
|
|
63
64
|
"style-mod": "^4.1.0",
|
|
64
|
-
"@dxos/
|
|
65
|
-
"@dxos/
|
|
66
|
-
"@dxos/
|
|
67
|
-
"@dxos/
|
|
68
|
-
"@dxos/
|
|
69
|
-
"@dxos/
|
|
70
|
-
"@dxos/echo-db": "0.8.
|
|
71
|
-
"@dxos/
|
|
72
|
-
"@dxos/
|
|
73
|
-
"@dxos/log": "0.8.
|
|
74
|
-
"@dxos/
|
|
75
|
-
"@dxos/
|
|
76
|
-
"@dxos/ui-
|
|
77
|
-
"@dxos/ui": "0.
|
|
78
|
-
"@dxos/
|
|
79
|
-
"@dxos/
|
|
80
|
-
"@dxos/util": "0.8.3"
|
|
65
|
+
"@dxos/async": "0.8.4-main.1c7ec43d41",
|
|
66
|
+
"@dxos/app-graph": "0.8.4-main.1c7ec43d41",
|
|
67
|
+
"@dxos/context": "0.8.4-main.1c7ec43d41",
|
|
68
|
+
"@dxos/debug": "0.8.4-main.1c7ec43d41",
|
|
69
|
+
"@dxos/display-name": "0.8.4-main.1c7ec43d41",
|
|
70
|
+
"@dxos/client": "0.8.4-main.1c7ec43d41",
|
|
71
|
+
"@dxos/echo-db": "0.8.4-main.1c7ec43d41",
|
|
72
|
+
"@dxos/invariant": "0.8.4-main.1c7ec43d41",
|
|
73
|
+
"@dxos/echo": "0.8.4-main.1c7ec43d41",
|
|
74
|
+
"@dxos/log": "0.8.4-main.1c7ec43d41",
|
|
75
|
+
"@dxos/lit-ui": "0.8.4-main.1c7ec43d41",
|
|
76
|
+
"@dxos/ui": "0.8.4-main.1c7ec43d41",
|
|
77
|
+
"@dxos/ui-theme": "0.8.4-main.1c7ec43d41",
|
|
78
|
+
"@dxos/ui-types": "0.8.4-main.1c7ec43d41",
|
|
79
|
+
"@dxos/util": "0.8.4-main.1c7ec43d41",
|
|
80
|
+
"@dxos/protocols": "0.8.4-main.1c7ec43d41"
|
|
81
81
|
},
|
|
82
82
|
"devDependencies": {
|
|
83
|
-
"@automerge/automerge": "3.2.
|
|
84
|
-
"@automerge/automerge-repo": "2.
|
|
85
|
-
"@automerge/automerge-repo-network-broadcastchannel": "2.
|
|
86
|
-
"@effect/platform": "0.
|
|
83
|
+
"@automerge/automerge": "3.2.6",
|
|
84
|
+
"@automerge/automerge-repo": "2.6.0-subduction.17",
|
|
85
|
+
"@automerge/automerge-repo-network-broadcastchannel": "2.6.0-subduction.17",
|
|
86
|
+
"@effect/platform": "0.94.4",
|
|
87
87
|
"@types/chai": "^4.2.15",
|
|
88
88
|
"@types/chai-dom": "^1.11.0",
|
|
89
89
|
"@types/lodash.defaultsdeep": "^4.6.6",
|
|
@@ -91,26 +91,25 @@
|
|
|
91
91
|
"@types/lodash.sortby": "^4.7.7",
|
|
92
92
|
"chai": "^4.4.1",
|
|
93
93
|
"chai-dom": "^1.11.0",
|
|
94
|
-
"effect": "3.
|
|
95
|
-
"happy-dom": "^
|
|
94
|
+
"effect": "3.20.0",
|
|
95
|
+
"happy-dom": "^20.0.0",
|
|
96
96
|
"jsdom": "^27.0.0",
|
|
97
97
|
"mocha": "^10.6.0",
|
|
98
|
-
"vite": "
|
|
98
|
+
"vite": "^8.0.10",
|
|
99
99
|
"vite-plugin-top-level-await": "^1.6.0",
|
|
100
|
-
"vite-plugin-wasm": "^3.
|
|
101
|
-
"@dxos/echo": "0.8.
|
|
102
|
-
"@dxos/
|
|
103
|
-
"@dxos/
|
|
104
|
-
"@dxos/
|
|
105
|
-
"@dxos/
|
|
106
|
-
"@dxos/storybook-utils": "0.8.
|
|
107
|
-
"@dxos/ui-theme": "0.
|
|
108
|
-
"@dxos/schema": "0.8.3"
|
|
100
|
+
"vite-plugin-wasm": "^3.6.0",
|
|
101
|
+
"@dxos/echo": "0.8.4-main.1c7ec43d41",
|
|
102
|
+
"@dxos/config": "0.8.4-main.1c7ec43d41",
|
|
103
|
+
"@dxos/keyboard": "0.8.4-main.1c7ec43d41",
|
|
104
|
+
"@dxos/random": "0.8.4-main.1c7ec43d41",
|
|
105
|
+
"@dxos/schema": "0.8.4-main.1c7ec43d41",
|
|
106
|
+
"@dxos/storybook-utils": "0.8.4-main.1c7ec43d41",
|
|
107
|
+
"@dxos/ui-theme": "0.8.4-main.1c7ec43d41"
|
|
109
108
|
},
|
|
110
109
|
"peerDependencies": {
|
|
111
|
-
"@effect/platform": "0.
|
|
112
|
-
"effect": "3.
|
|
113
|
-
"@dxos/ui-theme": "0.
|
|
110
|
+
"@effect/platform": "0.94.4",
|
|
111
|
+
"effect": "3.20.0",
|
|
112
|
+
"@dxos/ui-theme": "0.8.4-main.1c7ec43d41"
|
|
114
113
|
},
|
|
115
114
|
"publishConfig": {
|
|
116
115
|
"access": "public"
|
package/src/defaults.ts
CHANGED
|
@@ -6,29 +6,42 @@ import { mx } from '@dxos/ui-theme';
|
|
|
6
6
|
|
|
7
7
|
import { type ThemeExtensionsOptions } from './extensions';
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
export const editorWidth = '!mli-auto is-full max-is-[min(50rem,100%-4rem)]';
|
|
9
|
+
// NOTE: Padding is added to the editor to account for the focus ring (since otherwise the CM gutter will clip it)
|
|
10
|
+
export const editorClassNames = (role?: string) =>
|
|
11
|
+
mx(
|
|
12
|
+
'dx-attention-surface p-0.5 data-[toolbar=disabled]:pt-2 dx-focus-ring-inset',
|
|
13
|
+
role === 'section' ? '[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-h-24' : 'dx-container overflow-hidden',
|
|
14
|
+
);
|
|
16
15
|
|
|
17
|
-
export const
|
|
18
|
-
scroll: {
|
|
19
|
-
className: 'pbs-2',
|
|
20
|
-
},
|
|
16
|
+
export const documentSlots: ThemeExtensionsOptions['slots'] = {
|
|
21
17
|
content: {
|
|
22
|
-
|
|
18
|
+
/**
|
|
19
|
+
* CodeMirror content width.
|
|
20
|
+
* 40rem = 640px. Corresponds to initial plank width (Google docs, Stashpad, etc.)
|
|
21
|
+
* 50rem = 800px. Maximum content width for solo mode.
|
|
22
|
+
* NOTE: Max width - 4rem = 2rem left/right margin (or 2rem gutter plus 1rem left/right margin).
|
|
23
|
+
*/
|
|
24
|
+
className: mx(
|
|
25
|
+
// Inline-size container for widget sizing (children use `max-w-[100cqi]`).
|
|
26
|
+
// NOTE: Use inline-size, not full size containment — `container-type: size` on the
|
|
27
|
+
// editor content breaks CodeMirror's viewport measurement, leaving blank gaps during
|
|
28
|
+
// scroll until a click forces a re-measure.
|
|
29
|
+
'dx-inline-size-container',
|
|
30
|
+
// Wider margin for web (vs. mobile).
|
|
31
|
+
'pointer-fine:max-w-[min(50rem,100%-4rem)] pointer-coarse:max-w-[min(50rem,100%-2rem)]',
|
|
32
|
+
'mx-auto! w-full',
|
|
33
|
+
),
|
|
23
34
|
},
|
|
24
35
|
};
|
|
25
36
|
|
|
26
|
-
export const
|
|
27
|
-
|
|
37
|
+
export const compactSlots: ThemeExtensionsOptions['slots'] = {
|
|
38
|
+
content: {
|
|
39
|
+
className: 'mx-2!',
|
|
40
|
+
},
|
|
41
|
+
};
|
|
28
42
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
);
|
|
43
|
+
export const mobileSlots: ThemeExtensionsOptions['slots'] = {
|
|
44
|
+
content: {
|
|
45
|
+
className: 'mx-2!',
|
|
46
|
+
},
|
|
47
|
+
};
|
|
@@ -48,7 +48,7 @@ export const annotations = ({ match }: AnnotationOptions = {}): Extension => {
|
|
|
48
48
|
'.cm-annotation': {
|
|
49
49
|
textDecoration: 'underline',
|
|
50
50
|
textDecorationStyle: 'wavy',
|
|
51
|
-
textDecorationColor: 'var(--
|
|
51
|
+
textDecorationColor: 'var(--color-error-text)',
|
|
52
52
|
},
|
|
53
53
|
}),
|
|
54
54
|
];
|
|
@@ -0,0 +1,234 @@
|
|
|
1
|
+
//
|
|
2
|
+
// Copyright 2025 DXOS.org
|
|
3
|
+
//
|
|
4
|
+
|
|
5
|
+
import { StateEffect } from '@codemirror/state';
|
|
6
|
+
import { EditorView, ViewPlugin } from '@codemirror/view';
|
|
7
|
+
|
|
8
|
+
import { addEventListener, combine, throttle } from '@dxos/async';
|
|
9
|
+
import { Domino } from '@dxos/ui';
|
|
10
|
+
import { getSize } from '@dxos/ui-theme';
|
|
11
|
+
|
|
12
|
+
import { scrollerCrawlEffect, scrollerLineEffect } from './scroller';
|
|
13
|
+
|
|
14
|
+
/** Enable or disable autoscroll. */
|
|
15
|
+
export const autoScrollEffect = StateEffect.define<boolean>();
|
|
16
|
+
|
|
17
|
+
export type AutoScrollProps = {
|
|
18
|
+
/**
|
|
19
|
+
* If true, immediately jump to the bottom and re-pin whenever the size of the
|
|
20
|
+
* document view (the scroll container) changes — e.g. when a sidebar toggles
|
|
21
|
+
* or the window is resized. This avoids the visible "stuck near bottom" gap
|
|
22
|
+
* that otherwise appears because the previous `scrollTop` no longer reaches
|
|
23
|
+
* the new content height.
|
|
24
|
+
* @default true
|
|
25
|
+
*/
|
|
26
|
+
scrollOnResize?: boolean;
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Extension that supports pinning the scroll position and automatically scrolls to the bottom when content is added.
|
|
31
|
+
*/
|
|
32
|
+
export const autoScroll = ({ scrollOnResize = true }: AutoScrollProps = {}) => {
|
|
33
|
+
let buttonContainer: HTMLDivElement | undefined;
|
|
34
|
+
let isPinned = true;
|
|
35
|
+
let jumpPending = false;
|
|
36
|
+
let enabled = true;
|
|
37
|
+
let firstUpdate = true;
|
|
38
|
+
|
|
39
|
+
const setPinned = (pinned: boolean) => {
|
|
40
|
+
buttonContainer?.classList.toggle('opacity-0', pinned);
|
|
41
|
+
isPinned = pinned;
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return [
|
|
45
|
+
// Update listener for scrolling when content changes.
|
|
46
|
+
EditorView.updateListener.of((update) => {
|
|
47
|
+
const { view, heightChanged, state, startState } = update;
|
|
48
|
+
|
|
49
|
+
// Handle enable/disable effect.
|
|
50
|
+
for (const tr of update.transactions) {
|
|
51
|
+
for (const effect of tr.effects) {
|
|
52
|
+
if (effect.is(autoScrollEffect)) {
|
|
53
|
+
enabled = effect.value;
|
|
54
|
+
if (enabled) {
|
|
55
|
+
setPinned(true);
|
|
56
|
+
view.dispatch({
|
|
57
|
+
effects: scrollerCrawlEffect.of(true),
|
|
58
|
+
});
|
|
59
|
+
} else {
|
|
60
|
+
view.dispatch({
|
|
61
|
+
effects: scrollerCrawlEffect.of(false),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
if (!enabled) {
|
|
69
|
+
return;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
// Jump to bottom instantly when content first appears (either inserted into
|
|
73
|
+
// an empty doc, or present as initialValue when the editor is created).
|
|
74
|
+
if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
|
|
75
|
+
firstUpdate = false;
|
|
76
|
+
jumpPending = true;
|
|
77
|
+
requestAnimationFrame(() => {
|
|
78
|
+
view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
|
|
79
|
+
jumpPending = false;
|
|
80
|
+
});
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
firstUpdate = false;
|
|
84
|
+
|
|
85
|
+
// Suppress crawl while the initial jump is pending.
|
|
86
|
+
if (jumpPending) {
|
|
87
|
+
return;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
// Maybe scroll if doc changed and pinned.
|
|
91
|
+
// NOTE: Geometry changed is triggered when widgets change height (e.g., toggle tool block).
|
|
92
|
+
if (heightChanged) {
|
|
93
|
+
if (isPinned) {
|
|
94
|
+
// NOTE: Use scroll geometry instead of coordsAtPos to avoid forced layout/scroll side-effects.
|
|
95
|
+
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
96
|
+
const delta = scrollHeight - scrollTop - clientHeight;
|
|
97
|
+
if (delta > 0) {
|
|
98
|
+
setPinned(true);
|
|
99
|
+
view.dispatch({ effects: scrollerCrawlEffect.of(true) });
|
|
100
|
+
} else if (delta < -1) {
|
|
101
|
+
setPinned(false);
|
|
102
|
+
}
|
|
103
|
+
} else {
|
|
104
|
+
// TODO(burdon): Should re-pin if content shrinks.
|
|
105
|
+
if (state.doc.length === 0) {
|
|
106
|
+
setPinned(true);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}),
|
|
111
|
+
|
|
112
|
+
// Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
|
|
113
|
+
// window resize). Doc-driven height changes are handled by the updateListener above; this
|
|
114
|
+
// observer covers the case where the viewport changes while the doc length is unchanged.
|
|
115
|
+
scrollOnResize
|
|
116
|
+
? ViewPlugin.fromClass(
|
|
117
|
+
class {
|
|
118
|
+
private readonly observer: ResizeObserver;
|
|
119
|
+
private firstObservation = true;
|
|
120
|
+
private destroyed = false;
|
|
121
|
+
constructor(view: EditorView) {
|
|
122
|
+
// Throttle so a continuous drag-resize (or a flurry of layout changes) coalesces
|
|
123
|
+
// into a single re-pin per ~50ms instead of dispatching every frame.
|
|
124
|
+
const onResize = throttle(() => {
|
|
125
|
+
if (this.destroyed || !enabled) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
setPinned(true);
|
|
130
|
+
requestAnimationFrame(() => {
|
|
131
|
+
if (this.destroyed) {
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
view.scrollDOM.scrollTo({ top: view.scrollDOM.scrollHeight, behavior: 'instant' });
|
|
136
|
+
view.dispatch({ effects: scrollerCrawlEffect.of(false) });
|
|
137
|
+
});
|
|
138
|
+
}, 50);
|
|
139
|
+
|
|
140
|
+
this.observer = new ResizeObserver(() => {
|
|
141
|
+
// Skip the initial fire that ResizeObserver emits on `observe()`.
|
|
142
|
+
if (this.firstObservation) {
|
|
143
|
+
this.firstObservation = false;
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
onResize();
|
|
147
|
+
});
|
|
148
|
+
|
|
149
|
+
this.observer.observe(view.scrollDOM);
|
|
150
|
+
}
|
|
151
|
+
destroy() {
|
|
152
|
+
this.destroyed = true;
|
|
153
|
+
this.observer.disconnect();
|
|
154
|
+
}
|
|
155
|
+
},
|
|
156
|
+
)
|
|
157
|
+
: [],
|
|
158
|
+
|
|
159
|
+
// Detect user scroll and unpin (or re-pin if scrolled to the bottom).
|
|
160
|
+
ViewPlugin.fromClass(
|
|
161
|
+
class {
|
|
162
|
+
private readonly cleanup: () => void;
|
|
163
|
+
constructor(view: EditorView) {
|
|
164
|
+
this.cleanup = createUserScrollDetector(
|
|
165
|
+
view.scrollDOM,
|
|
166
|
+
throttle(() => {
|
|
167
|
+
requestAnimationFrame(() => {
|
|
168
|
+
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
169
|
+
const delta = scrollHeight - scrollTop - clientHeight;
|
|
170
|
+
const pinned = delta === 0;
|
|
171
|
+
setPinned(pinned);
|
|
172
|
+
if (!pinned) {
|
|
173
|
+
view.dispatch({ effects: scrollerCrawlEffect.of(false) });
|
|
174
|
+
}
|
|
175
|
+
});
|
|
176
|
+
}, 500),
|
|
177
|
+
);
|
|
178
|
+
}
|
|
179
|
+
destroy() {
|
|
180
|
+
this.cleanup();
|
|
181
|
+
}
|
|
182
|
+
},
|
|
183
|
+
),
|
|
184
|
+
|
|
185
|
+
// Scroll button.
|
|
186
|
+
ViewPlugin.fromClass(
|
|
187
|
+
class {
|
|
188
|
+
constructor(view: EditorView) {
|
|
189
|
+
const icon = Domino.of('dx-icon' as any)
|
|
190
|
+
.classNames(getSize(4))
|
|
191
|
+
.attributes({ icon: 'ph--arrow-down--regular' });
|
|
192
|
+
const button = Domino.of('button')
|
|
193
|
+
.classNames('dx-button bg-accent-surface')
|
|
194
|
+
.attributes({ 'data-density': 'fine' })
|
|
195
|
+
.append(icon)
|
|
196
|
+
.on('click', () => {
|
|
197
|
+
setPinned(true);
|
|
198
|
+
view.dispatch({
|
|
199
|
+
effects: scrollerLineEffect.of({ line: -1, position: 'end', behavior: 'smooth' }),
|
|
200
|
+
});
|
|
201
|
+
});
|
|
202
|
+
|
|
203
|
+
buttonContainer = Domino.of('div')
|
|
204
|
+
.classNames('cm-scroll-button transition-opacity duration-300 opacity-0')
|
|
205
|
+
.append(button).root as HTMLDivElement;
|
|
206
|
+
|
|
207
|
+
view.scrollDOM.parentElement!.appendChild(buttonContainer);
|
|
208
|
+
}
|
|
209
|
+
},
|
|
210
|
+
),
|
|
211
|
+
];
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
/**
|
|
215
|
+
* Attaches listeners to detect genuine user-initiated scrolling on an element.
|
|
216
|
+
* Two sources are covered:
|
|
217
|
+
* - `wheel`: fires only from physical mouse wheel / trackpad gestures.
|
|
218
|
+
* - `pointerdown` on the scrollbar gutter: detected by comparing clientX to
|
|
219
|
+
* the element's clientWidth (the content area, excluding the scrollbar).
|
|
220
|
+
* Returns a cleanup function that removes the listeners.
|
|
221
|
+
*/
|
|
222
|
+
// TODO(burdon): Still jumps when widgets are rendered.
|
|
223
|
+
// - Track position of specific element/line in document and scroll relative to that.
|
|
224
|
+
function createUserScrollDetector(element: HTMLElement, onUserScroll: () => void): () => void {
|
|
225
|
+
return combine(
|
|
226
|
+
addEventListener(element, 'wheel', () => onUserScroll(), { passive: true }),
|
|
227
|
+
addEventListener(element, 'pointerdown', (event) => {
|
|
228
|
+
// If the pointer lands beyond the content width it hit the scrollbar gutter.
|
|
229
|
+
if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {
|
|
230
|
+
onUserScroll();
|
|
231
|
+
}
|
|
232
|
+
}),
|
|
233
|
+
);
|
|
234
|
+
}
|
|
@@ -13,42 +13,61 @@ type Content = string | HTMLElement | ((view: EditorView) => HTMLElement);
|
|
|
13
13
|
export type PlaceholderOptions = {
|
|
14
14
|
content: Content;
|
|
15
15
|
delay?: number;
|
|
16
|
+
focusOnly?: boolean;
|
|
16
17
|
};
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
|
-
* Shows a transient placeholder at the current cursor position.
|
|
20
|
+
* Shows a transient placeholder at the current cursor position. When
|
|
21
|
+
* `focusOnly` is set the placeholder is suppressed unless the editor has DOM
|
|
22
|
+
* focus, and is hidden again when focus is lost.
|
|
20
23
|
*/
|
|
21
|
-
export const placeholder = ({ content, delay = 3_000 }: PlaceholderOptions): Extension => {
|
|
24
|
+
export const placeholder = ({ content, delay = 3_000, focusOnly = false }: PlaceholderOptions): Extension => {
|
|
22
25
|
const plugin = ViewPlugin.fromClass(
|
|
23
26
|
class {
|
|
24
27
|
_timeout: ReturnType<typeof setTimeout> | undefined;
|
|
25
28
|
_decorations = Decoration.none;
|
|
26
29
|
|
|
27
30
|
update(update: ViewUpdate) {
|
|
31
|
+
// React to actual user activity only. The empty `view.update([])`
|
|
32
|
+
// dispatched from the timeout below carries no doc/selection/focus
|
|
33
|
+
// change, so it falls through here as a no-op — that's how the
|
|
34
|
+
// freshly-set widget survives long enough for the decoration
|
|
35
|
+
// provider to read it. Without this gate, the unconditional reset
|
|
36
|
+
// would clobber the decoration in the same tick and the placeholder
|
|
37
|
+
// would never visibly render.
|
|
38
|
+
if (!update.docChanged && !update.selectionSet && !update.focusChanged) {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
|
|
28
42
|
if (this._timeout) {
|
|
29
43
|
window.clearTimeout(this._timeout);
|
|
30
44
|
this._timeout = undefined;
|
|
31
45
|
}
|
|
46
|
+
this._decorations = Decoration.none;
|
|
47
|
+
|
|
48
|
+
// Honour `focusOnly`: when the option is set and the editor isn't
|
|
49
|
+
// focused, leave the placeholder hidden and skip rescheduling. The
|
|
50
|
+
// next `focusChanged` update reschedules once focus returns.
|
|
51
|
+
if (focusOnly && !update.view.hasFocus) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
32
54
|
|
|
33
|
-
// Check if the active line (where cursor is) is empty.
|
|
34
55
|
const activeLine = update.view.state.doc.lineAt(update.view.state.selection.main.head);
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
// Create widget decoration at the start of the current line.
|
|
38
|
-
const lineStart = activeLine.from;
|
|
39
|
-
this._timeout = setTimeout(() => {
|
|
40
|
-
this._decorations = Decoration.set([
|
|
41
|
-
Decoration.widget({
|
|
42
|
-
widget: new PlaceholderWidget(content),
|
|
43
|
-
side: 1,
|
|
44
|
-
}).range(lineStart),
|
|
45
|
-
]);
|
|
46
|
-
|
|
47
|
-
update.view.update([]);
|
|
48
|
-
}, delay);
|
|
56
|
+
if (activeLine.text.trim() !== '') {
|
|
57
|
+
return;
|
|
49
58
|
}
|
|
50
59
|
|
|
51
|
-
|
|
60
|
+
const lineStart = activeLine.from;
|
|
61
|
+
const view = update.view;
|
|
62
|
+
this._timeout = setTimeout(() => {
|
|
63
|
+
this._decorations = Decoration.set([
|
|
64
|
+
Decoration.widget({
|
|
65
|
+
widget: new PlaceholderWidget(content),
|
|
66
|
+
side: 1,
|
|
67
|
+
}).range(lineStart),
|
|
68
|
+
]);
|
|
69
|
+
view.update([]);
|
|
70
|
+
}, delay);
|
|
52
71
|
}
|
|
53
72
|
|
|
54
73
|
destroy() {
|
|
@@ -2,23 +2,43 @@
|
|
|
2
2
|
// Copyright 2024 DXOS.org
|
|
3
3
|
//
|
|
4
4
|
|
|
5
|
-
import { type
|
|
5
|
+
import { type ChangeFn, type ChangeOptions, type Doc, type Heads } from '@automerge/automerge';
|
|
6
|
+
import { type DocHandle, Repo, decodeHeads, encodeHeads, initSubduction } from '@automerge/automerge-repo';
|
|
6
7
|
import { EditorState } from '@codemirror/state';
|
|
7
8
|
import { EditorView } from '@codemirror/view';
|
|
8
9
|
import { render, screen } from '@testing-library/react';
|
|
9
10
|
import React, { type FC, useEffect, useRef, useState } from 'react';
|
|
10
|
-
import { describe, test } from 'vitest';
|
|
11
|
+
import { beforeAll, describe, test } from 'vitest';
|
|
11
12
|
|
|
12
|
-
import {
|
|
13
|
+
import { type IDocHandle } from '@dxos/echo-db';
|
|
14
|
+
import { getDeep } from '@dxos/util';
|
|
13
15
|
|
|
14
16
|
import { automerge } from './automerge';
|
|
15
17
|
|
|
18
|
+
// Adapter: `IDocHandle` (used by `DocHandleProxy` in production) takes raw `Heads` (hex)
|
|
19
|
+
// at `changeAt`, but automerge-repo's `DocHandle.changeAt` expects bs58check-encoded
|
|
20
|
+
// `UrlHeads`. Encode on the way in, decode on the way out so the test's repo-backed
|
|
21
|
+
// handle satisfies the extension's `IDocHandle` contract.
|
|
22
|
+
const adaptRepoHandle = <T,>(handle: DocHandle<T>): IDocHandle<T> => ({
|
|
23
|
+
doc: () => handle.doc() as Doc<T> | undefined,
|
|
24
|
+
change: (callback: ChangeFn<T>, options?: ChangeOptions<T>) =>
|
|
25
|
+
options ? handle.change(callback, options) : handle.change(callback),
|
|
26
|
+
changeAt: (heads: Heads, callback: ChangeFn<T>, options?: ChangeOptions<T>): Heads | undefined => {
|
|
27
|
+
const encoded = options
|
|
28
|
+
? handle.changeAt(encodeHeads(heads), callback, options)
|
|
29
|
+
: handle.changeAt(encodeHeads(heads), callback);
|
|
30
|
+
return encoded ? decodeHeads(encoded) : undefined;
|
|
31
|
+
},
|
|
32
|
+
addListener: (event, listener) => handle.on(event, listener),
|
|
33
|
+
removeListener: (event, listener) => handle.off(event, listener),
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
const path = ['text'];
|
|
37
|
+
|
|
16
38
|
type TestObject = {
|
|
17
39
|
text: string;
|
|
18
40
|
};
|
|
19
41
|
|
|
20
|
-
const path = ['text'];
|
|
21
|
-
|
|
22
42
|
class Generator {
|
|
23
43
|
constructor(private readonly _handle: DocHandle<TestObject>) {}
|
|
24
44
|
update(text: string): void {
|
|
@@ -33,8 +53,7 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
|
33
53
|
const [view, setView] = useState<EditorView>();
|
|
34
54
|
useEffect(() => {
|
|
35
55
|
const extensions = [
|
|
36
|
-
|
|
37
|
-
automerge({ handle: handle as any, path }),
|
|
56
|
+
automerge({ handle: adaptRepoHandle(handle), path }),
|
|
38
57
|
EditorView.updateListener.of((update) => {
|
|
39
58
|
if (view.state.doc.toString() === 'hello!') {
|
|
40
59
|
// Update editor.
|
|
@@ -46,7 +65,7 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
|
46
65
|
];
|
|
47
66
|
|
|
48
67
|
const view = new EditorView({
|
|
49
|
-
state: EditorState.create({ doc:
|
|
68
|
+
state: EditorState.create({ doc: getDeep(handle.doc()!, path), extensions }),
|
|
50
69
|
parent: ref.current!,
|
|
51
70
|
});
|
|
52
71
|
|
|
@@ -58,19 +77,26 @@ const Test: FC<{ handle: DocHandle<TestObject>; generator: Generator }> = ({ han
|
|
|
58
77
|
return <div ref={ref} data-testid='editor' />;
|
|
59
78
|
};
|
|
60
79
|
|
|
80
|
+
// TODO(burdon): Test history/undo.
|
|
81
|
+
// TODO(burdon): https://testing-library.com/docs/react-testing-library/example-intro/
|
|
82
|
+
|
|
61
83
|
describe('Automerge', () => {
|
|
84
|
+
// Subduction-fork `Repo` constructs a `MemorySigner` internally; WASM must be
|
|
85
|
+
// initialized first or the constructor throws `'set_subduction_logger' of undefined`.
|
|
86
|
+
beforeAll(async () => {
|
|
87
|
+
await initSubduction();
|
|
88
|
+
});
|
|
89
|
+
|
|
62
90
|
test('basic sync', ({ expect }) => {
|
|
63
91
|
const repo = new Repo({ network: [] });
|
|
64
92
|
const handle = repo.create<TestObject>();
|
|
65
93
|
const generator = new Generator(handle);
|
|
66
94
|
render(<Test handle={handle} generator={generator} />);
|
|
95
|
+
|
|
67
96
|
const editor = screen.getByTestId('editor');
|
|
68
97
|
expect(editor.textContent).toBe('');
|
|
69
98
|
|
|
70
99
|
generator.update('hello!');
|
|
71
100
|
expect(editor.textContent).toBe('hello world!');
|
|
72
101
|
});
|
|
73
|
-
|
|
74
|
-
// TODO(burdon): Test history/undo.
|
|
75
|
-
// TODO(burdon): https://testing-library.com/docs/react-testing-library/example-intro/
|
|
76
102
|
});
|
|
@@ -12,9 +12,8 @@ import { DocAccessor } from '@dxos/echo-db';
|
|
|
12
12
|
|
|
13
13
|
import { Cursor } from '../../util';
|
|
14
14
|
import { initialSync } from '../state';
|
|
15
|
-
|
|
16
15
|
import { cursorConverter } from './cursor';
|
|
17
|
-
import { type State, isReconcile, updateHeadsEffect } from './defs';
|
|
16
|
+
import { type State, isReconcile, reconcileAnnotation, updateHeadsEffect } from './defs';
|
|
18
17
|
import { Syncer } from './sync';
|
|
19
18
|
|
|
20
19
|
export const automerge = (accessor: DocAccessor): Extension => {
|
|
@@ -72,11 +71,10 @@ export const automerge = (accessor: DocAccessor): Extension => {
|
|
|
72
71
|
const value = DocAccessor.getValue<string>(accessor);
|
|
73
72
|
const current = this._view.state.doc.toString();
|
|
74
73
|
if (value !== current) {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
// });
|
|
74
|
+
this._view.dispatch({
|
|
75
|
+
changes: { from: 0, to: this._view.state.doc.length, insert: value },
|
|
76
|
+
annotations: [initialSync, reconcileAnnotation.of(true)],
|
|
77
|
+
});
|
|
80
78
|
}
|
|
81
79
|
});
|
|
82
80
|
}
|