@dxos/react-ui-editor 0.3.11-main.a996413 → 0.3.11-main.b00882f
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 +2010 -1505
- 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 +16 -13
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +20 -17
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -3
- 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/comments.stories.d.ts +26 -0
- package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
- 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 -1
- 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 +24 -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/extensions/automerge/semaphore.d.ts +14 -0
- 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 +48 -0
- package/dist/types/src/extensions/awareness.d.ts.map +1 -0
- package/dist/types/src/extensions/basic.d.ts +4 -5
- package/dist/types/src/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/extensions/code.d.ts.map +1 -1
- package/dist/types/src/extensions/comments.d.ts +32 -19
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/extensions/cursor.d.ts +25 -0
- package/dist/types/src/extensions/cursor.d.ts.map +1 -0
- package/dist/types/src/extensions/hr.d.ts.map +1 -1
- package/dist/types/src/extensions/image.d.ts.map +1 -1
- package/dist/types/src/extensions/index.d.ts +5 -1
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/link.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/bundle.d.ts +2 -5
- package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/extensions/mention.d.ts.map +1 -1
- package/dist/types/src/extensions/outliner.d.ts +4 -0
- package/dist/types/src/extensions/outliner.d.ts.map +1 -0
- package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
- 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 +4 -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/defs.d.ts +28 -0
- package/dist/types/src/hooks/defs.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +5 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
- package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
- package/dist/types/src/hooks/useTextModel.d.ts +2 -31
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/hooks/{yjs/space-provider.d.ts → yjs.d.ts} +9 -8
- package/dist/types/src/hooks/yjs.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +3 -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/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/styles/tokens.d.ts +1 -0
- package/dist/types/src/styles/tokens.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/themes/default.d.ts.map +1 -1
- package/dist/types/src/util.d.ts +7 -0
- package/dist/types/src/util.d.ts.map +1 -0
- package/package.json +32 -30
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +77 -80
- package/src/components/TextEditor/TextEditor.stories.tsx +13 -34
- package/src/components/TextEditor/TextEditor.tsx +125 -93
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/codemirror.stories.ts +3 -2
- package/src/components/TextEditor/comments.stories.tsx +357 -0
- package/src/{hooks/yjs → components/TextEditor}/yjs.stories.tsx +1 -1
- package/src/extensions/autocomplete.ts +23 -19
- package/src/extensions/automerge/automerge.ts +88 -0
- package/src/extensions/automerge/cursor.ts +52 -0
- package/src/extensions/automerge/defs.ts +41 -0
- package/src/extensions/automerge/index.ts +6 -0
- package/src/{hooks → extensions}/automerge/semaphore.ts +34 -29
- 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 +327 -0
- package/src/extensions/basic.ts +22 -17
- package/src/extensions/code.ts +28 -23
- package/src/extensions/comments.ts +252 -229
- package/src/extensions/cursor.ts +50 -0
- package/src/extensions/hr.ts +50 -52
- package/src/extensions/image.ts +40 -22
- package/src/extensions/index.ts +5 -1
- package/src/extensions/link.ts +86 -88
- package/src/extensions/markdown/bundle.ts +18 -24
- package/src/extensions/markdown/highlight.ts +3 -12
- package/src/extensions/mention.ts +9 -2
- package/src/extensions/outliner.ts +12 -0
- package/src/extensions/table.ts +10 -4
- package/src/extensions/tasklist.ts +78 -88
- package/src/extensions/yjs/cursor.ts +22 -0
- package/src/extensions/yjs/index.ts +5 -0
- package/src/{hooks → extensions}/yjs/yjs.test.ts +2 -26
- package/src/extensions/yjs/yjs.ts +16 -0
- package/src/hooks/automerge.ts +53 -0
- package/src/hooks/awareness-provider.ts +120 -0
- package/src/hooks/defs.ts +47 -0
- package/src/hooks/index.ts +6 -1
- package/src/hooks/useTextEditor.ts +29 -0
- package/src/hooks/useTextModel.ts +9 -129
- package/src/hooks/{yjs/space-provider.ts → yjs.ts} +50 -19
- package/src/index.ts +3 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/markdown.ts +0 -2
- package/src/styles/tokens.ts +3 -0
- package/src/testing/replicator.ts +10 -15
- package/src/themes/default.ts +51 -78
- package/src/util.ts +41 -0
- package/dist/types/src/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/extensions/util.d.ts +0 -5
- package/dist/types/src/extensions/util.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 +0 -19
- 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/extensions/mermaid.ts +0 -11
- package/src/extensions/util.ts +0 -18
- package/src/hooks/automerge/handle.ts +0 -14
- package/src/hooks/automerge/index.ts +0 -6
- package/src/hooks/automerge/plugin.ts +0 -132
- package/src/hooks/yjs/index.ts +0 -6
- /package/dist/types/src/{hooks → extensions}/automerge/update-codemirror.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/src/{hooks/yjs → styles}/cursors.ts +0 -0
|
@@ -7,784 +7,976 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
7
7
|
|
|
8
8
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
9
9
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
10
|
-
import { EditorView as
|
|
10
|
+
import { EditorView as EditorView13 } from "@codemirror/view";
|
|
11
11
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
12
12
|
import { vim } from "@replit/codemirror-vim";
|
|
13
13
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
14
|
-
import React, { forwardRef, useCallback, useEffect as
|
|
15
|
-
import {
|
|
16
|
-
import { useThemeContext } from "@dxos/react-ui";
|
|
17
|
-
import {
|
|
14
|
+
import React, { forwardRef, useCallback, useEffect as useEffect3, useImperativeHandle, useRef, useState } from "react";
|
|
15
|
+
import { log as log2 } from "@dxos/log";
|
|
16
|
+
import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
|
|
17
|
+
import { inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
18
18
|
|
|
19
19
|
// packages/ui/react-ui-editor/src/extensions/autocomplete.ts
|
|
20
20
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
21
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
21
22
|
import { keymap } from "@codemirror/view";
|
|
22
23
|
var autocomplete = ({ onSearch }) => {
|
|
23
24
|
return [
|
|
24
25
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
25
26
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
27
|
+
// TODO(burdon): Set custom keymap.
|
|
26
28
|
keymap.of(completionKeymap),
|
|
27
29
|
// https://codemirror.net/examples/autocompletion
|
|
28
30
|
// https://codemirror.net/docs/ref/#autocomplete.autocompletion
|
|
29
31
|
autocompletion({
|
|
30
|
-
|
|
32
|
+
activateOnTyping: true,
|
|
33
|
+
// closeOnBlur: false,
|
|
31
34
|
// defaultKeymap: false,
|
|
32
|
-
//
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
return {
|
|
43
|
-
from: match.from,
|
|
44
|
-
options: onSearch(match.text.toLowerCase())
|
|
45
|
-
};
|
|
35
|
+
// TODO(burdon): Styles/fragments.
|
|
36
|
+
tooltipClass: () => "shadow rounded"
|
|
37
|
+
}),
|
|
38
|
+
// TODO(burdon): Option to create new page?
|
|
39
|
+
// TODO(burdon): Optional decoration via addToOptions
|
|
40
|
+
markdownLanguage.data.of({
|
|
41
|
+
autocomplete: (context) => {
|
|
42
|
+
const match = context.matchBefore(/\w*/);
|
|
43
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
44
|
+
return null;
|
|
46
45
|
}
|
|
47
|
-
|
|
46
|
+
return {
|
|
47
|
+
from: match.from,
|
|
48
|
+
options: onSearch(match.text.toLowerCase())
|
|
49
|
+
};
|
|
50
|
+
}
|
|
48
51
|
})
|
|
49
52
|
];
|
|
50
53
|
};
|
|
51
54
|
|
|
52
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
53
|
-
import {
|
|
54
|
-
import {
|
|
55
|
-
import {
|
|
56
|
-
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
57
|
-
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
58
|
-
EditorView.lineWrapping,
|
|
59
|
-
// TODO(burdon): Compare with minimalSetup.
|
|
60
|
-
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
61
|
-
bracketMatching(),
|
|
62
|
-
closeBrackets(),
|
|
63
|
-
drawSelection(),
|
|
64
|
-
_placeholder && placeholder(_placeholder),
|
|
65
|
-
// TODO(burdon): Is this required?
|
|
66
|
-
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
67
|
-
].filter(Boolean);
|
|
68
|
-
|
|
69
|
-
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
70
|
-
import { EditorView as EditorView2, keymap as keymap2 } from "@codemirror/view";
|
|
71
|
-
import defaultsDeep from "lodash.defaultsdeep";
|
|
55
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
56
|
+
import { StateField } from "@codemirror/state";
|
|
57
|
+
import { EditorView, ViewPlugin } from "@codemirror/view";
|
|
58
|
+
import { next as A } from "@dxos/automerge/automerge";
|
|
72
59
|
import { invariant } from "@dxos/invariant";
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
-1,
|
|
90
|
-
1
|
|
91
|
-
],
|
|
92
|
-
y: [
|
|
93
|
-
-3.5,
|
|
94
|
-
-1.5
|
|
95
|
-
]
|
|
60
|
+
|
|
61
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
|
|
62
|
+
import get from "lodash.get";
|
|
63
|
+
import { next as automerge } from "@dxos/automerge/automerge";
|
|
64
|
+
var cursorConverter = (handle, path) => ({
|
|
65
|
+
// TODO(burdon): Handle assoc to associate with a previous character.
|
|
66
|
+
toCursor: (pos) => {
|
|
67
|
+
const doc = handle.docSync();
|
|
68
|
+
if (!doc) {
|
|
69
|
+
return "";
|
|
70
|
+
}
|
|
71
|
+
const value = get(doc, path);
|
|
72
|
+
if (typeof value === "string" && value.length <= pos) {
|
|
73
|
+
return "end";
|
|
74
|
+
}
|
|
75
|
+
return automerge.getCursor(doc, path.slice(), pos);
|
|
96
76
|
},
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
y: y - top
|
|
110
|
-
};
|
|
111
|
-
return {
|
|
112
|
-
element,
|
|
113
|
-
point
|
|
114
|
-
};
|
|
115
|
-
};
|
|
116
|
-
return [
|
|
117
|
-
// Cursor moved.
|
|
118
|
-
EditorView2.updateListener.of((update4) => {
|
|
119
|
-
if (blaster?.node !== update4.view.scrollDOM) {
|
|
120
|
-
if (blaster) {
|
|
121
|
-
blaster.destroy();
|
|
122
|
-
}
|
|
123
|
-
blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({
|
|
124
|
-
particleGravity: 0.2,
|
|
125
|
-
particleShrinkRate: 0.995,
|
|
126
|
-
color: () => [
|
|
127
|
-
100 + Math.random() * 100,
|
|
128
|
-
0,
|
|
129
|
-
0
|
|
130
|
-
]
|
|
131
|
-
}, options, defaultOptions));
|
|
132
|
-
blaster.initialize();
|
|
133
|
-
blaster.start();
|
|
77
|
+
fromCursor: (cursor) => {
|
|
78
|
+
if (cursor === "") {
|
|
79
|
+
return 0;
|
|
80
|
+
}
|
|
81
|
+
const doc = handle.docSync();
|
|
82
|
+
if (!doc) {
|
|
83
|
+
return 0;
|
|
84
|
+
}
|
|
85
|
+
if (cursor === "end") {
|
|
86
|
+
const value = get(doc, path);
|
|
87
|
+
if (typeof value === "string") {
|
|
88
|
+
return value.length;
|
|
134
89
|
} else {
|
|
135
|
-
|
|
136
|
-
}
|
|
137
|
-
const current = update4.state.selection.main.head;
|
|
138
|
-
if (current !== last) {
|
|
139
|
-
last = current;
|
|
140
|
-
const { element, point } = getPoint(update4.view, current - 1);
|
|
141
|
-
if (element && point) {
|
|
142
|
-
blaster.spawn({
|
|
143
|
-
element,
|
|
144
|
-
point
|
|
145
|
-
});
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
}),
|
|
149
|
-
keymap2.of([
|
|
150
|
-
{
|
|
151
|
-
any: (_, event) => {
|
|
152
|
-
if (blaster) {
|
|
153
|
-
if (event.key === "Enter" && event.shiftKey) {
|
|
154
|
-
blaster.shake({
|
|
155
|
-
time: 0.8
|
|
156
|
-
});
|
|
157
|
-
return true;
|
|
158
|
-
}
|
|
159
|
-
}
|
|
160
|
-
return false;
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
])
|
|
164
|
-
];
|
|
165
|
-
};
|
|
166
|
-
var Blaster = class {
|
|
167
|
-
constructor(_node, _options) {
|
|
168
|
-
this._node = _node;
|
|
169
|
-
this._options = _options;
|
|
170
|
-
this._running = false;
|
|
171
|
-
this._shakeTime = 0;
|
|
172
|
-
this._shakeTimeMax = 0;
|
|
173
|
-
this._particles = [];
|
|
174
|
-
this._particlePointer = 0;
|
|
175
|
-
this._lastPoint = {
|
|
176
|
-
x: 0,
|
|
177
|
-
y: 0
|
|
178
|
-
};
|
|
179
|
-
this.shake = throttle(({ time }) => {
|
|
180
|
-
this._shakeTime = this._shakeTimeMax || time;
|
|
181
|
-
this._shakeTimeMax = time;
|
|
182
|
-
}, 100);
|
|
183
|
-
this.spawn = throttle(({ element, point }) => {
|
|
184
|
-
const color = getRGBComponents(element, this._options.color);
|
|
185
|
-
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
186
|
-
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
187
|
-
this._lastPoint = point;
|
|
188
|
-
for (let i = numParticles; i--; i > 0) {
|
|
189
|
-
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
190
|
-
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
90
|
+
return 0;
|
|
191
91
|
}
|
|
192
|
-
}, 100);
|
|
193
|
-
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
194
|
-
}
|
|
195
|
-
get node() {
|
|
196
|
-
return this._node;
|
|
197
|
-
}
|
|
198
|
-
initialize() {
|
|
199
|
-
invariant(!this._canvas && !this._ctx, void 0, {
|
|
200
|
-
F: __dxlog_file,
|
|
201
|
-
L: 138,
|
|
202
|
-
S: this,
|
|
203
|
-
A: [
|
|
204
|
-
"!this._canvas && !this._ctx",
|
|
205
|
-
""
|
|
206
|
-
]
|
|
207
|
-
});
|
|
208
|
-
this._canvas = document.createElement("canvas");
|
|
209
|
-
this._canvas.id = "code-blast-canvas";
|
|
210
|
-
this._canvas.style.position = "absolute";
|
|
211
|
-
this._canvas.style.zIndex = "0";
|
|
212
|
-
this._canvas.style.pointerEvents = "none";
|
|
213
|
-
this._ctx = this._canvas.getContext("2d");
|
|
214
|
-
const parent = this._node.parentElement?.parentElement;
|
|
215
|
-
parent?.appendChild(this._canvas);
|
|
216
|
-
this.resize();
|
|
217
|
-
}
|
|
218
|
-
destroy() {
|
|
219
|
-
this.stop();
|
|
220
|
-
if (this._canvas) {
|
|
221
|
-
this._canvas.remove();
|
|
222
|
-
this._canvas = void 0;
|
|
223
|
-
this._ctx = void 0;
|
|
224
|
-
}
|
|
225
|
-
}
|
|
226
|
-
resize() {
|
|
227
|
-
if (this._node.parentElement && this._canvas) {
|
|
228
|
-
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
229
|
-
this._canvas.style.top = `${y}px`;
|
|
230
|
-
this._canvas.style.left = `${x}px`;
|
|
231
|
-
this._canvas.width = width;
|
|
232
|
-
this._canvas.height = height;
|
|
233
92
|
}
|
|
93
|
+
return automerge.getCursorPosition(doc, path.slice(), cursor);
|
|
234
94
|
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
|
|
98
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
99
|
+
var effectType = StateEffect.define({});
|
|
100
|
+
var reconcileAnnotationType = Annotation.define();
|
|
101
|
+
var getPath = (state, field) => state.field(field).path;
|
|
102
|
+
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
103
|
+
var updateHeads = (newHeads) => effectType.of({
|
|
104
|
+
newHeads
|
|
105
|
+
});
|
|
106
|
+
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
107
|
+
|
|
108
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
109
|
+
import { next as automerge2 } from "@dxos/automerge/automerge";
|
|
110
|
+
|
|
111
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
|
|
112
|
+
import { next as am } from "@dxos/automerge/automerge";
|
|
113
|
+
var updateAutomerge = (field, handle, transactions, state) => {
|
|
114
|
+
const { lastHeads, path } = state.field(field);
|
|
115
|
+
let hasChanges = false;
|
|
116
|
+
for (const tr of transactions) {
|
|
117
|
+
tr.changes.iterChanges(() => {
|
|
118
|
+
hasChanges = true;
|
|
244
119
|
});
|
|
245
|
-
this._running = true;
|
|
246
|
-
this.loop();
|
|
247
120
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
this._node.style.transform = "translate(0px, 0px)";
|
|
121
|
+
if (!hasChanges) {
|
|
122
|
+
return void 0;
|
|
251
123
|
}
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
124
|
+
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
125
|
+
for (const tr of transactions) {
|
|
126
|
+
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
127
|
+
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
128
|
+
});
|
|
255
129
|
}
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
for (let i = this._particles.length; i--; i > 0) {
|
|
273
|
-
const particle = this._particles[i];
|
|
274
|
-
if (!particle) {
|
|
275
|
-
continue;
|
|
276
|
-
}
|
|
277
|
-
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
278
|
-
continue;
|
|
279
|
-
}
|
|
280
|
-
this._effect.update(this._ctx, particle);
|
|
130
|
+
});
|
|
131
|
+
return newHeads ?? void 0;
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/update-codemirror.ts
|
|
135
|
+
import { ChangeSet } from "@codemirror/state";
|
|
136
|
+
var updateCodeMirror = (view, selection, target, patches) => {
|
|
137
|
+
for (const patch of patches) {
|
|
138
|
+
const changeSpec = handlePatch(patch, target, view.state);
|
|
139
|
+
if (changeSpec != null) {
|
|
140
|
+
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
141
|
+
selection = selection.map(changeSet, 1);
|
|
142
|
+
view.dispatch({
|
|
143
|
+
changes: changeSet,
|
|
144
|
+
annotations: reconcileAnnotationType.of({})
|
|
145
|
+
});
|
|
281
146
|
}
|
|
282
147
|
}
|
|
148
|
+
view.dispatch({
|
|
149
|
+
selection,
|
|
150
|
+
annotations: reconcileAnnotationType.of({})
|
|
151
|
+
});
|
|
283
152
|
};
|
|
284
|
-
var
|
|
285
|
-
|
|
286
|
-
|
|
153
|
+
var handlePatch = (patch, target, state) => {
|
|
154
|
+
if (patch.action === "insert") {
|
|
155
|
+
return handleInsert(target, patch);
|
|
156
|
+
} else if (patch.action === "splice") {
|
|
157
|
+
return handleSplice(target, patch);
|
|
158
|
+
} else if (patch.action === "del") {
|
|
159
|
+
return handleDel(target, patch);
|
|
160
|
+
} else if (patch.action === "put") {
|
|
161
|
+
return handlePut(target, patch, state);
|
|
162
|
+
} else {
|
|
163
|
+
return null;
|
|
287
164
|
}
|
|
288
165
|
};
|
|
289
|
-
var
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
y: y + 10,
|
|
294
|
-
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
295
|
-
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
296
|
-
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
297
|
-
color,
|
|
298
|
-
alpha: 1
|
|
299
|
-
};
|
|
300
|
-
}
|
|
301
|
-
update(ctx, particle) {
|
|
302
|
-
particle.vy += this._options.particleGravity;
|
|
303
|
-
particle.x += particle.vx;
|
|
304
|
-
particle.y += particle.vy;
|
|
305
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
306
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
307
|
-
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
166
|
+
var handleInsert = (target, patch) => {
|
|
167
|
+
const index = charPath(target, patch.path);
|
|
168
|
+
if (index == null) {
|
|
169
|
+
return [];
|
|
308
170
|
}
|
|
171
|
+
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
172
|
+
return [
|
|
173
|
+
{
|
|
174
|
+
from: index,
|
|
175
|
+
to: index,
|
|
176
|
+
insert: text
|
|
177
|
+
}
|
|
178
|
+
];
|
|
309
179
|
};
|
|
310
|
-
var
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
y: y + 10,
|
|
315
|
-
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
316
|
-
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
317
|
-
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
318
|
-
color,
|
|
319
|
-
alpha: 1,
|
|
320
|
-
theta: random(0, 360) * Math.PI / 180,
|
|
321
|
-
drag: 0.92,
|
|
322
|
-
wander: 0.15
|
|
323
|
-
};
|
|
324
|
-
}
|
|
325
|
-
update(ctx, particle) {
|
|
326
|
-
particle.vy += this._options.particleGravity;
|
|
327
|
-
particle.x += particle.vx;
|
|
328
|
-
particle.y += particle.vy;
|
|
329
|
-
particle.vx *= particle.drag;
|
|
330
|
-
particle.vy *= particle.drag;
|
|
331
|
-
particle.theta += random(-0.5, 0.5);
|
|
332
|
-
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
333
|
-
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
334
|
-
particle.size *= this._options.particleShrinkRate;
|
|
335
|
-
particle.alpha *= this._options.particleAlphaFadeout;
|
|
336
|
-
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
337
|
-
ctx.beginPath();
|
|
338
|
-
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
339
|
-
ctx.fill();
|
|
180
|
+
var handleSplice = (target, patch) => {
|
|
181
|
+
const index = charPath(target, patch.path);
|
|
182
|
+
if (index == null) {
|
|
183
|
+
return [];
|
|
340
184
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
if (!wait) {
|
|
346
|
-
callback.apply(this, args);
|
|
347
|
-
wait = true;
|
|
348
|
-
setTimeout(() => {
|
|
349
|
-
wait = false;
|
|
350
|
-
}, limit);
|
|
185
|
+
return [
|
|
186
|
+
{
|
|
187
|
+
from: index,
|
|
188
|
+
insert: patch.value
|
|
351
189
|
}
|
|
352
|
-
|
|
353
|
-
}
|
|
354
|
-
var
|
|
355
|
-
|
|
356
|
-
|
|
190
|
+
];
|
|
191
|
+
};
|
|
192
|
+
var handleDel = (target, patch) => {
|
|
193
|
+
const index = charPath(target, patch.path);
|
|
194
|
+
if (index == null) {
|
|
195
|
+
return [];
|
|
357
196
|
}
|
|
358
|
-
const
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
197
|
+
const length = patch.length || 1;
|
|
198
|
+
return [
|
|
199
|
+
{
|
|
200
|
+
from: index,
|
|
201
|
+
to: index + length
|
|
363
202
|
}
|
|
203
|
+
];
|
|
204
|
+
};
|
|
205
|
+
var handlePut = (target, patch, state) => {
|
|
206
|
+
const index = charPath(target, [
|
|
207
|
+
...patch.path,
|
|
208
|
+
0
|
|
209
|
+
]);
|
|
210
|
+
if (index == null) {
|
|
211
|
+
return [];
|
|
212
|
+
}
|
|
213
|
+
const length = state.doc.length;
|
|
214
|
+
if (typeof patch.value !== "string") {
|
|
215
|
+
return [];
|
|
364
216
|
}
|
|
365
217
|
return [
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
218
|
+
{
|
|
219
|
+
from: 0,
|
|
220
|
+
to: length,
|
|
221
|
+
insert: patch.value
|
|
222
|
+
}
|
|
369
223
|
];
|
|
370
224
|
};
|
|
371
|
-
var
|
|
372
|
-
if (
|
|
373
|
-
|
|
374
|
-
min = 0;
|
|
225
|
+
var charPath = (textPath, candidatePath) => {
|
|
226
|
+
if (candidatePath.length !== textPath.length + 1) {
|
|
227
|
+
return null;
|
|
375
228
|
}
|
|
376
|
-
|
|
229
|
+
for (let i = 0; i < textPath.length; i++) {
|
|
230
|
+
if (textPath[i] !== candidatePath[i]) {
|
|
231
|
+
return null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
const index = candidatePath[candidatePath.length - 1];
|
|
235
|
+
if (typeof index === "number") {
|
|
236
|
+
return index;
|
|
237
|
+
}
|
|
238
|
+
return null;
|
|
377
239
|
};
|
|
378
240
|
|
|
379
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
241
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
|
|
242
|
+
var PatchSemaphore = class {
|
|
243
|
+
// prettier-ignore
|
|
244
|
+
constructor(_handle, _state) {
|
|
245
|
+
this._handle = _handle;
|
|
246
|
+
this._state = _state;
|
|
247
|
+
this._inReconcile = false;
|
|
248
|
+
}
|
|
249
|
+
// NOTE: Cannot destruct view.state.
|
|
250
|
+
reconcile(view) {
|
|
251
|
+
if (this._inReconcile) {
|
|
252
|
+
return;
|
|
253
|
+
}
|
|
254
|
+
this._inReconcile = true;
|
|
255
|
+
const path = getPath(view.state, this._state);
|
|
256
|
+
const oldHeads = getLastHeads(view.state, this._state);
|
|
257
|
+
let selection = view.state.selection;
|
|
258
|
+
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
259
|
+
const toInvert = transactions.slice().reverse();
|
|
260
|
+
for (const tx of toInvert) {
|
|
261
|
+
const inverted = tx.changes.invert(tx.startState.doc);
|
|
262
|
+
selection = selection.map(inverted);
|
|
263
|
+
view.dispatch({
|
|
264
|
+
changes: inverted,
|
|
265
|
+
annotations: reconcileAnnotationType.of(true)
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
269
|
+
if (newHeads === null || newHeads === void 0) {
|
|
270
|
+
newHeads = automerge2.getHeads(this._handle.docSync());
|
|
271
|
+
}
|
|
272
|
+
const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
|
|
273
|
+
updateCodeMirror(view, selection, path, diff);
|
|
274
|
+
view.dispatch({
|
|
275
|
+
effects: updateHeads(newHeads),
|
|
276
|
+
annotations: reconcileAnnotationType.of({})
|
|
277
|
+
});
|
|
278
|
+
this._inReconcile = false;
|
|
279
|
+
}
|
|
280
|
+
};
|
|
383
281
|
|
|
384
|
-
// packages/ui/react-ui-editor/src/
|
|
385
|
-
import {
|
|
386
|
-
var
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
"-ml-[10px]"
|
|
390
|
-
],
|
|
391
|
-
2: [
|
|
392
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
393
|
-
"-ml-[8px]"
|
|
394
|
-
],
|
|
395
|
-
3: [
|
|
396
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
397
|
-
"-ml-[7px]"
|
|
398
|
-
],
|
|
399
|
-
4: [
|
|
400
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
401
|
-
"-ml-[6px]"
|
|
402
|
-
],
|
|
403
|
-
5: [
|
|
404
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
405
|
-
"-ml-[5px]"
|
|
406
|
-
],
|
|
407
|
-
6: [
|
|
408
|
-
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
409
|
-
"-ml-[4px]"
|
|
410
|
-
]
|
|
282
|
+
// packages/ui/react-ui-editor/src/extensions/cursor.ts
|
|
283
|
+
import { Facet } from "@codemirror/state";
|
|
284
|
+
var defaultCursorConverter = {
|
|
285
|
+
toCursor: (position) => position.toString(),
|
|
286
|
+
fromCursor: (cursor) => parseInt(cursor)
|
|
411
287
|
};
|
|
412
|
-
var
|
|
413
|
-
|
|
414
|
-
|
|
288
|
+
var Cursor = class _Cursor {
|
|
289
|
+
static {
|
|
290
|
+
this.converter = Facet.define({
|
|
291
|
+
combine: (providers) => providers[0] ?? defaultCursorConverter
|
|
292
|
+
});
|
|
293
|
+
}
|
|
294
|
+
static {
|
|
295
|
+
this.getCursorFromRange = (state, range) => {
|
|
296
|
+
const cursorConverter3 = state.facet(_Cursor.converter);
|
|
297
|
+
const from = cursorConverter3.toCursor(range.from);
|
|
298
|
+
const to = cursorConverter3.toCursor(range.to, -1);
|
|
299
|
+
return [
|
|
300
|
+
from,
|
|
301
|
+
to
|
|
302
|
+
].join(":");
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
static {
|
|
306
|
+
this.getRangeFromCursor = (state, cursor) => {
|
|
307
|
+
const cursorConverter3 = state.facet(_Cursor.converter);
|
|
308
|
+
const parts = cursor.split(":");
|
|
309
|
+
const from = cursorConverter3.fromCursor(parts[0]);
|
|
310
|
+
const to = cursorConverter3.fromCursor(parts[1]);
|
|
311
|
+
return from !== void 0 && to !== void 0 ? {
|
|
312
|
+
from,
|
|
313
|
+
to
|
|
314
|
+
} : void 0;
|
|
315
|
+
};
|
|
316
|
+
}
|
|
415
317
|
};
|
|
416
|
-
var light = "text-neutral-200 dark:text-neutral-800";
|
|
417
|
-
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
418
|
-
var bold = "font-bold";
|
|
419
|
-
var italic = "italic";
|
|
420
|
-
var strikethrough = "line-through";
|
|
421
|
-
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
422
|
-
var codeMark = "font-mono text-primary-500";
|
|
423
|
-
var inlineUrl = mx(code, "px-1");
|
|
424
|
-
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
425
|
-
|
|
426
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
427
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
428
|
-
var tokens = tailwindConfig({}).theme;
|
|
429
318
|
|
|
430
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
431
|
-
var
|
|
432
|
-
var
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
var getLineRange = (lines, from, to) => {
|
|
458
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
459
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
460
|
-
return [
|
|
461
|
-
start,
|
|
462
|
-
end
|
|
463
|
-
];
|
|
464
|
-
};
|
|
465
|
-
var code2 = () => {
|
|
466
|
-
const getDecorations = (view) => {
|
|
467
|
-
const decorations = [];
|
|
468
|
-
if (view.state.readOnly) {
|
|
469
|
-
const text = view.state.doc.sliceString(0);
|
|
470
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
471
|
-
const blocks = view.viewportLineBlocks;
|
|
472
|
-
for (const match of matches) {
|
|
473
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
474
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
475
|
-
const block = blocks[i];
|
|
476
|
-
decorations.push(Decoration.line({
|
|
477
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
478
|
-
}).range(block.from));
|
|
319
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
320
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts";
|
|
321
|
+
var automerge3 = ({ handle, path }) => {
|
|
322
|
+
const state = StateField.define({
|
|
323
|
+
create: () => ({
|
|
324
|
+
path: path.slice(),
|
|
325
|
+
lastHeads: A.getHeads(handle.docSync()),
|
|
326
|
+
unreconciledTransactions: []
|
|
327
|
+
}),
|
|
328
|
+
update: (value, tr) => {
|
|
329
|
+
const result = {
|
|
330
|
+
path: path.slice(),
|
|
331
|
+
lastHeads: value.lastHeads,
|
|
332
|
+
unreconciledTransactions: value.unreconciledTransactions.slice()
|
|
333
|
+
};
|
|
334
|
+
let clearUnreconciled = false;
|
|
335
|
+
for (const effect of tr.effects) {
|
|
336
|
+
if (effect.is(effectType)) {
|
|
337
|
+
result.lastHeads = effect.value.newHeads;
|
|
338
|
+
clearUnreconciled = true;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
if (clearUnreconciled) {
|
|
342
|
+
result.unreconciledTransactions = [];
|
|
343
|
+
} else {
|
|
344
|
+
if (!isReconcileTx(tr)) {
|
|
345
|
+
result.unreconciledTransactions.push(tr);
|
|
479
346
|
}
|
|
480
347
|
}
|
|
348
|
+
return result;
|
|
481
349
|
}
|
|
482
|
-
|
|
483
|
-
|
|
350
|
+
});
|
|
351
|
+
const semaphore = new PatchSemaphore(handle, state);
|
|
484
352
|
return [
|
|
353
|
+
Cursor.converter.of(cursorConverter(handle, path)),
|
|
354
|
+
// Reconcile external updates.
|
|
485
355
|
ViewPlugin.fromClass(class {
|
|
486
|
-
constructor(
|
|
487
|
-
this.
|
|
356
|
+
constructor(_view) {
|
|
357
|
+
this._view = _view;
|
|
358
|
+
invariant(this._view, void 0, {
|
|
359
|
+
F: __dxlog_file,
|
|
360
|
+
L: 66,
|
|
361
|
+
S: this,
|
|
362
|
+
A: [
|
|
363
|
+
"this._view",
|
|
364
|
+
""
|
|
365
|
+
]
|
|
366
|
+
});
|
|
367
|
+
handle.addListener("change", this._handleChange.bind(this));
|
|
488
368
|
}
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
369
|
+
destroy() {
|
|
370
|
+
handle.removeListener("change", this._handleChange.bind(this));
|
|
371
|
+
}
|
|
372
|
+
_handleChange() {
|
|
373
|
+
semaphore.reconcile(this._view);
|
|
493
374
|
}
|
|
494
|
-
}, {
|
|
495
|
-
decorations: (value) => value.decorations
|
|
496
375
|
}),
|
|
497
|
-
|
|
376
|
+
// Reconcile local updates.
|
|
377
|
+
EditorView.updateListener.of(({ view, changes }) => {
|
|
378
|
+
if (!changes.empty) {
|
|
379
|
+
semaphore.reconcile(view);
|
|
380
|
+
}
|
|
381
|
+
}),
|
|
382
|
+
state
|
|
498
383
|
];
|
|
499
384
|
};
|
|
500
385
|
|
|
501
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
502
|
-
import {
|
|
503
|
-
import {
|
|
504
|
-
import
|
|
505
|
-
import
|
|
506
|
-
import {
|
|
507
|
-
import {
|
|
508
|
-
import {
|
|
509
|
-
import {
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
}
|
|
518
|
-
|
|
519
|
-
F: __dxlog_file2,
|
|
520
|
-
L: 16,
|
|
521
|
-
S: void 0,
|
|
522
|
-
C: (f, a) => f(...a)
|
|
523
|
-
});
|
|
524
|
-
}
|
|
386
|
+
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
387
|
+
import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
|
|
388
|
+
import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
389
|
+
import { useEffect } from "react";
|
|
390
|
+
import { Event } from "@dxos/async";
|
|
391
|
+
import { Context } from "@dxos/context";
|
|
392
|
+
import { generateName } from "@dxos/display-name";
|
|
393
|
+
import { useThemeContext } from "@dxos/react-ui";
|
|
394
|
+
import { getColorForValue } from "@dxos/react-ui-theme";
|
|
395
|
+
var dummyProvider = {
|
|
396
|
+
remoteStateChange: new Event(),
|
|
397
|
+
open: () => {
|
|
398
|
+
},
|
|
399
|
+
close: () => {
|
|
400
|
+
},
|
|
401
|
+
update: () => {
|
|
402
|
+
},
|
|
403
|
+
getRemoteStates: () => []
|
|
525
404
|
};
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
}
|
|
555
|
-
if (!hasChanges) {
|
|
556
|
-
return void 0;
|
|
557
|
-
}
|
|
558
|
-
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
559
|
-
for (const tr of transactions) {
|
|
560
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
561
|
-
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
405
|
+
var AwarenessProvider = Facet2.define({
|
|
406
|
+
combine: (providers) => providers[0] ?? dummyProvider
|
|
407
|
+
});
|
|
408
|
+
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
409
|
+
var awareness = (provider = dummyProvider) => {
|
|
410
|
+
return [
|
|
411
|
+
AwarenessProvider.of(provider),
|
|
412
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
413
|
+
decorations: (value) => value.decorations
|
|
414
|
+
}),
|
|
415
|
+
styles
|
|
416
|
+
];
|
|
417
|
+
};
|
|
418
|
+
var useAwareness = ({ awareness: awareness2, peer }) => {
|
|
419
|
+
const { themeMode } = useThemeContext();
|
|
420
|
+
useEffect(() => {
|
|
421
|
+
if (awareness2 && peer) {
|
|
422
|
+
awareness2.setLocalStateField("user", {
|
|
423
|
+
name: peer.name ?? generateName(peer.id),
|
|
424
|
+
color: getColorForValue({
|
|
425
|
+
value: peer.id,
|
|
426
|
+
type: "color"
|
|
427
|
+
}),
|
|
428
|
+
colorLight: getColorForValue({
|
|
429
|
+
value: peer.id,
|
|
430
|
+
themeMode,
|
|
431
|
+
type: "highlight"
|
|
432
|
+
})
|
|
562
433
|
});
|
|
563
434
|
}
|
|
564
|
-
}
|
|
565
|
-
|
|
435
|
+
}, [
|
|
436
|
+
awareness2,
|
|
437
|
+
peer,
|
|
438
|
+
themeMode
|
|
439
|
+
]);
|
|
566
440
|
};
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
441
|
+
var RemoteSelectionsDecorator = class {
|
|
442
|
+
constructor(view) {
|
|
443
|
+
this.decorations = RangeSet.of([]);
|
|
444
|
+
this._ctx = new Context();
|
|
445
|
+
this._lastAnchor = void 0;
|
|
446
|
+
this._lastHead = void 0;
|
|
447
|
+
this._cursorConverter = view.state.facet(Cursor.converter);
|
|
448
|
+
this._provider = view.state.facet(AwarenessProvider);
|
|
449
|
+
this._provider.open();
|
|
450
|
+
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
576
451
|
view.dispatch({
|
|
577
|
-
|
|
578
|
-
|
|
452
|
+
annotations: [
|
|
453
|
+
RemoteSelectionChangedAnnotation.of([])
|
|
454
|
+
]
|
|
579
455
|
});
|
|
580
|
-
}
|
|
456
|
+
});
|
|
581
457
|
}
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
});
|
|
586
|
-
};
|
|
587
|
-
var handlePatch = (patch, target, state) => {
|
|
588
|
-
if (patch.action === "insert") {
|
|
589
|
-
return handleInsert(target, patch);
|
|
590
|
-
} else if (patch.action === "splice") {
|
|
591
|
-
return handleSplice(target, patch);
|
|
592
|
-
} else if (patch.action === "del") {
|
|
593
|
-
return handleDel(target, patch);
|
|
594
|
-
} else if (patch.action === "put") {
|
|
595
|
-
return handlePut(target, patch, state);
|
|
596
|
-
} else {
|
|
597
|
-
return null;
|
|
458
|
+
destroy() {
|
|
459
|
+
void this._ctx.dispose();
|
|
460
|
+
this._provider.close();
|
|
598
461
|
}
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
if (index == null) {
|
|
603
|
-
return [];
|
|
462
|
+
update(update2) {
|
|
463
|
+
this._updateLocalSelection(update2);
|
|
464
|
+
this._updateRemoteSelections(update2);
|
|
604
465
|
}
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
{
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
insert: text
|
|
466
|
+
_updateLocalSelection(update2) {
|
|
467
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
468
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
469
|
+
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
470
|
+
return;
|
|
611
471
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
472
|
+
this._lastAnchor = anchor;
|
|
473
|
+
this._lastHead = head;
|
|
474
|
+
this._provider.update(anchor !== void 0 && head !== void 0 ? {
|
|
475
|
+
anchor: this._cursorConverter.toCursor(anchor),
|
|
476
|
+
head: this._cursorConverter.toCursor(head)
|
|
477
|
+
} : void 0);
|
|
478
|
+
}
|
|
479
|
+
_updateRemoteSelections(update2) {
|
|
480
|
+
const decorations = [];
|
|
481
|
+
const awarenessStates = this._provider.getRemoteStates();
|
|
482
|
+
for (const state of awarenessStates) {
|
|
483
|
+
const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
|
|
484
|
+
const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
|
|
485
|
+
if (anchor == null || head == null) {
|
|
486
|
+
continue;
|
|
487
|
+
}
|
|
488
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
489
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
490
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
491
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
492
|
+
const color = state.info.color ?? "#30bced";
|
|
493
|
+
const lightColor = state.info.lightColor ?? color + "33";
|
|
494
|
+
if (startLine.number === endLine.number) {
|
|
495
|
+
decorations.push({
|
|
496
|
+
from: start,
|
|
497
|
+
to: end,
|
|
498
|
+
value: Decoration.mark({
|
|
499
|
+
attributes: {
|
|
500
|
+
style: `background-color: ${lightColor}`
|
|
501
|
+
},
|
|
502
|
+
class: "cm-collab-selection"
|
|
503
|
+
})
|
|
504
|
+
});
|
|
505
|
+
} else {
|
|
506
|
+
decorations.push({
|
|
507
|
+
from: start,
|
|
508
|
+
to: startLine.from + startLine.length,
|
|
509
|
+
value: Decoration.mark({
|
|
510
|
+
attributes: {
|
|
511
|
+
style: `background-color: ${color}`
|
|
512
|
+
},
|
|
513
|
+
class: "cm-collab-selection"
|
|
514
|
+
})
|
|
515
|
+
});
|
|
516
|
+
decorations.push({
|
|
517
|
+
from: endLine.from,
|
|
518
|
+
to: end,
|
|
519
|
+
value: Decoration.mark({
|
|
520
|
+
attributes: {
|
|
521
|
+
style: `background-color: ${color}`
|
|
522
|
+
},
|
|
523
|
+
class: "cm-collab-selection"
|
|
524
|
+
})
|
|
525
|
+
});
|
|
526
|
+
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
527
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
528
|
+
decorations.push({
|
|
529
|
+
from: linePos,
|
|
530
|
+
to: linePos,
|
|
531
|
+
value: Decoration.line({
|
|
532
|
+
attributes: {
|
|
533
|
+
style: `background-color: ${color}`,
|
|
534
|
+
class: "cm-collab-selectionLine"
|
|
535
|
+
}
|
|
536
|
+
})
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
}
|
|
540
|
+
decorations.push({
|
|
541
|
+
from: head,
|
|
542
|
+
to: head,
|
|
543
|
+
value: Decoration.widget({
|
|
544
|
+
side: head - anchor > 0 ? -1 : 1,
|
|
545
|
+
block: false,
|
|
546
|
+
widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
|
|
547
|
+
})
|
|
548
|
+
});
|
|
623
549
|
}
|
|
624
|
-
|
|
625
|
-
};
|
|
626
|
-
var handleDel = (target, patch) => {
|
|
627
|
-
const index = charPath(target, patch.path);
|
|
628
|
-
if (index == null) {
|
|
629
|
-
return [];
|
|
550
|
+
this.decorations = Decoration.set(decorations, true);
|
|
630
551
|
}
|
|
631
|
-
const length = patch.length || 1;
|
|
632
|
-
return [
|
|
633
|
-
{
|
|
634
|
-
from: index,
|
|
635
|
-
to: index + length
|
|
636
|
-
}
|
|
637
|
-
];
|
|
638
552
|
};
|
|
639
|
-
var
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
if (index == null) {
|
|
645
|
-
return [];
|
|
553
|
+
var RemoteCaretWidget = class extends WidgetType {
|
|
554
|
+
constructor(_name, _color) {
|
|
555
|
+
super();
|
|
556
|
+
this._name = _name;
|
|
557
|
+
this._color = _color;
|
|
646
558
|
}
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
559
|
+
toDOM() {
|
|
560
|
+
const span = document.createElement("span");
|
|
561
|
+
span.className = "cm-collab-selectionCaret";
|
|
562
|
+
span.style.backgroundColor = this._color;
|
|
563
|
+
span.style.borderColor = this._color;
|
|
564
|
+
const dot = document.createElement("div");
|
|
565
|
+
dot.className = "cm-collab-selectionCaretDot";
|
|
566
|
+
const info = document.createElement("div");
|
|
567
|
+
info.className = "cm-collab-selectionInfo";
|
|
568
|
+
info.innerText = this._name;
|
|
569
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
570
|
+
span.appendChild(dot);
|
|
571
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
572
|
+
span.appendChild(info);
|
|
573
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
574
|
+
return span;
|
|
650
575
|
}
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
from: 0,
|
|
654
|
-
to: length,
|
|
655
|
-
insert: patch.value
|
|
656
|
-
}
|
|
657
|
-
];
|
|
658
|
-
};
|
|
659
|
-
var charPath = (textPath, candidatePath) => {
|
|
660
|
-
if (candidatePath.length !== textPath.length + 1) {
|
|
661
|
-
return null;
|
|
576
|
+
updateDOM() {
|
|
577
|
+
return false;
|
|
662
578
|
}
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
return null;
|
|
666
|
-
}
|
|
579
|
+
eq(widget) {
|
|
580
|
+
return widget._color === this._color;
|
|
667
581
|
}
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
return index;
|
|
582
|
+
get estimatedHeight() {
|
|
583
|
+
return -1;
|
|
671
584
|
}
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/semaphore.ts
|
|
676
|
-
var PatchSemaphore = class {
|
|
677
|
-
constructor(field) {
|
|
678
|
-
this._inReconcile = false;
|
|
679
|
-
this._queue = [];
|
|
680
|
-
this.reconcile = (handle, view) => {
|
|
681
|
-
if (this._inReconcile) {
|
|
682
|
-
return;
|
|
683
|
-
}
|
|
684
|
-
this._inReconcile = true;
|
|
685
|
-
const path = getPath(view.state, this._field);
|
|
686
|
-
const oldHeads = getLastHeads(view.state, this._field);
|
|
687
|
-
let selection = view.state.selection;
|
|
688
|
-
const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
689
|
-
const toInvert = transactions.slice().reverse();
|
|
690
|
-
for (const tx of toInvert) {
|
|
691
|
-
const inverted = tx.changes.invert(tx.startState.doc);
|
|
692
|
-
selection = selection.map(inverted);
|
|
693
|
-
view.dispatch({
|
|
694
|
-
changes: inverted,
|
|
695
|
-
annotations: reconcileAnnotationType.of(true)
|
|
696
|
-
});
|
|
697
|
-
}
|
|
698
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
699
|
-
if (newHeads === null || newHeads === void 0) {
|
|
700
|
-
newHeads = automerge.getHeads(handle.docSync());
|
|
701
|
-
}
|
|
702
|
-
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
703
|
-
updateCodeMirror(view, selection, path, diff);
|
|
704
|
-
view.dispatch({
|
|
705
|
-
effects: updateHeads(newHeads),
|
|
706
|
-
annotations: reconcileAnnotationType.of({})
|
|
707
|
-
});
|
|
708
|
-
this._inReconcile = false;
|
|
709
|
-
};
|
|
710
|
-
if (field !== void 0) {
|
|
711
|
-
this._field = field;
|
|
712
|
-
}
|
|
585
|
+
ignoreEvent() {
|
|
586
|
+
return true;
|
|
713
587
|
}
|
|
714
588
|
};
|
|
589
|
+
var styles = EditorView2.baseTheme({
|
|
590
|
+
".cm-collab-selection": {},
|
|
591
|
+
".cm-collab-selectionLine": {
|
|
592
|
+
padding: 0,
|
|
593
|
+
margin: "0px 2px 0px 4px"
|
|
594
|
+
},
|
|
595
|
+
".cm-collab-selectionCaret": {
|
|
596
|
+
position: "relative",
|
|
597
|
+
borderLeft: "1px solid black",
|
|
598
|
+
borderRight: "1px solid black",
|
|
599
|
+
marginLeft: "-1px",
|
|
600
|
+
marginRight: "-1px",
|
|
601
|
+
boxSizing: "border-box",
|
|
602
|
+
display: "inline"
|
|
603
|
+
},
|
|
604
|
+
".cm-collab-selectionCaretDot": {
|
|
605
|
+
borderRadius: "50%",
|
|
606
|
+
position: "absolute",
|
|
607
|
+
width: ".4em",
|
|
608
|
+
height: ".4em",
|
|
609
|
+
top: "-.2em",
|
|
610
|
+
left: "-.2em",
|
|
611
|
+
backgroundColor: "inherit",
|
|
612
|
+
transition: "transform .3s ease-in-out",
|
|
613
|
+
boxSizing: "border-box"
|
|
614
|
+
},
|
|
615
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
|
|
616
|
+
transformOrigin: "bottom center",
|
|
617
|
+
transform: "scale(0)"
|
|
618
|
+
},
|
|
619
|
+
".cm-collab-selectionInfo": {
|
|
620
|
+
position: "absolute",
|
|
621
|
+
top: "-1.05em",
|
|
622
|
+
left: "-1px",
|
|
623
|
+
fontSize: ".75em",
|
|
624
|
+
fontFamily: "serif",
|
|
625
|
+
fontStyle: "normal",
|
|
626
|
+
fontWeight: "normal",
|
|
627
|
+
lineHeight: "normal",
|
|
628
|
+
userSelect: "none",
|
|
629
|
+
color: "white",
|
|
630
|
+
paddingLeft: "2px",
|
|
631
|
+
paddingRight: "2px",
|
|
632
|
+
zIndex: 101,
|
|
633
|
+
transition: "opacity .3s ease-in-out",
|
|
634
|
+
backgroundColor: "inherit",
|
|
635
|
+
// These should be separate.
|
|
636
|
+
opacity: 0,
|
|
637
|
+
transitionDelay: "0s",
|
|
638
|
+
whiteSpace: "nowrap"
|
|
639
|
+
},
|
|
640
|
+
".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
|
|
641
|
+
opacity: 1,
|
|
642
|
+
transitionDelay: "0s"
|
|
643
|
+
}
|
|
644
|
+
});
|
|
715
645
|
|
|
716
|
-
// packages/ui/react-ui-editor/src/
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
}
|
|
721
|
-
|
|
722
|
-
var
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
646
|
+
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
647
|
+
import { closeBrackets } from "@codemirror/autocomplete";
|
|
648
|
+
import { history } from "@codemirror/commands";
|
|
649
|
+
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
650
|
+
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
651
|
+
import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
|
|
652
|
+
var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
|
|
653
|
+
lineWrapping ? EditorView3.lineWrapping : [],
|
|
654
|
+
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
655
|
+
bracketMatching(),
|
|
656
|
+
closeBrackets(),
|
|
657
|
+
drawSelection(),
|
|
658
|
+
highlightActiveLine(),
|
|
659
|
+
history(),
|
|
660
|
+
_placeholder ? placeholder(_placeholder) : [],
|
|
661
|
+
// https://github.com/codemirror/theme-one-dark
|
|
662
|
+
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
663
|
+
];
|
|
664
|
+
|
|
665
|
+
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
666
|
+
import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
|
|
667
|
+
import defaultsDeep from "lodash.defaultsdeep";
|
|
668
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
669
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
670
|
+
var defaultOptions = {
|
|
671
|
+
effect: 2,
|
|
672
|
+
maxParticles: 200,
|
|
673
|
+
particleGravity: 0.08,
|
|
674
|
+
particleAlphaFadeout: 0.996,
|
|
675
|
+
particleSize: {
|
|
676
|
+
min: 2,
|
|
677
|
+
max: 8
|
|
678
|
+
},
|
|
679
|
+
particleNumRange: {
|
|
680
|
+
min: 5,
|
|
681
|
+
max: 10
|
|
682
|
+
},
|
|
683
|
+
particleVelocityRange: {
|
|
684
|
+
x: [
|
|
685
|
+
-1,
|
|
686
|
+
1
|
|
687
|
+
],
|
|
688
|
+
y: [
|
|
689
|
+
-3.5,
|
|
690
|
+
-1.5
|
|
691
|
+
]
|
|
692
|
+
},
|
|
693
|
+
particleShrinkRate: 0.95,
|
|
694
|
+
shakeIntensity: 5
|
|
695
|
+
};
|
|
696
|
+
var blast = (options = defaultOptions) => {
|
|
697
|
+
let blaster;
|
|
698
|
+
let last = 0;
|
|
699
|
+
const getPoint = (view, pos) => {
|
|
700
|
+
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
701
|
+
const element = document.elementFromPoint(x, y);
|
|
702
|
+
const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
|
|
703
|
+
const point = {
|
|
704
|
+
x: x - left,
|
|
705
|
+
y: y - top
|
|
706
|
+
};
|
|
707
|
+
return {
|
|
708
|
+
element,
|
|
709
|
+
point
|
|
710
|
+
};
|
|
711
|
+
};
|
|
712
|
+
return [
|
|
713
|
+
// Cursor moved.
|
|
714
|
+
EditorView4.updateListener.of((update2) => {
|
|
715
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
716
|
+
if (blaster) {
|
|
717
|
+
blaster.destroy();
|
|
744
718
|
}
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
719
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
720
|
+
particleGravity: 0.2,
|
|
721
|
+
particleShrinkRate: 0.995,
|
|
722
|
+
color: () => [
|
|
723
|
+
100 + Math.random() * 100,
|
|
724
|
+
0,
|
|
725
|
+
0
|
|
726
|
+
]
|
|
727
|
+
}, options, defaultOptions));
|
|
728
|
+
blaster.initialize();
|
|
729
|
+
blaster.start();
|
|
748
730
|
} else {
|
|
749
|
-
|
|
750
|
-
|
|
731
|
+
blaster.resize();
|
|
732
|
+
}
|
|
733
|
+
const current = update2.state.selection.main.head;
|
|
734
|
+
if (current !== last) {
|
|
735
|
+
last = current;
|
|
736
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
737
|
+
if (element && point) {
|
|
738
|
+
blaster.spawn({
|
|
739
|
+
element,
|
|
740
|
+
point
|
|
741
|
+
});
|
|
751
742
|
}
|
|
752
743
|
}
|
|
753
|
-
|
|
744
|
+
}),
|
|
745
|
+
keymap2.of([
|
|
746
|
+
{
|
|
747
|
+
any: (_, event) => {
|
|
748
|
+
if (blaster) {
|
|
749
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
750
|
+
blaster.shake({
|
|
751
|
+
time: 0.8
|
|
752
|
+
});
|
|
753
|
+
return true;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
return false;
|
|
757
|
+
}
|
|
758
|
+
}
|
|
759
|
+
])
|
|
760
|
+
];
|
|
761
|
+
};
|
|
762
|
+
var Blaster = class {
|
|
763
|
+
constructor(_node, _options) {
|
|
764
|
+
this._node = _node;
|
|
765
|
+
this._options = _options;
|
|
766
|
+
this._running = false;
|
|
767
|
+
this._shakeTime = 0;
|
|
768
|
+
this._shakeTimeMax = 0;
|
|
769
|
+
this._particles = [];
|
|
770
|
+
this._particlePointer = 0;
|
|
771
|
+
this._lastPoint = {
|
|
772
|
+
x: 0,
|
|
773
|
+
y: 0
|
|
774
|
+
};
|
|
775
|
+
this.shake = throttle(({ time }) => {
|
|
776
|
+
this._shakeTime = this._shakeTimeMax || time;
|
|
777
|
+
this._shakeTimeMax = time;
|
|
778
|
+
}, 100);
|
|
779
|
+
this.spawn = throttle(({ element, point }) => {
|
|
780
|
+
const color = getRGBComponents(element, this._options.color);
|
|
781
|
+
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
782
|
+
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
783
|
+
this._lastPoint = point;
|
|
784
|
+
for (let i = numParticles; i--; i > 0) {
|
|
785
|
+
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
786
|
+
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
787
|
+
}
|
|
788
|
+
}, 100);
|
|
789
|
+
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
790
|
+
}
|
|
791
|
+
get node() {
|
|
792
|
+
return this._node;
|
|
793
|
+
}
|
|
794
|
+
initialize() {
|
|
795
|
+
invariant2(!this._canvas && !this._ctx, void 0, {
|
|
796
|
+
F: __dxlog_file2,
|
|
797
|
+
L: 138,
|
|
798
|
+
S: this,
|
|
799
|
+
A: [
|
|
800
|
+
"!this._canvas && !this._ctx",
|
|
801
|
+
""
|
|
802
|
+
]
|
|
803
|
+
});
|
|
804
|
+
this._canvas = document.createElement("canvas");
|
|
805
|
+
this._canvas.id = "code-blast-canvas";
|
|
806
|
+
this._canvas.style.position = "absolute";
|
|
807
|
+
this._canvas.style.zIndex = "0";
|
|
808
|
+
this._canvas.style.pointerEvents = "none";
|
|
809
|
+
this._ctx = this._canvas.getContext("2d");
|
|
810
|
+
const parent = this._node.parentElement?.parentElement;
|
|
811
|
+
parent?.appendChild(this._canvas);
|
|
812
|
+
this.resize();
|
|
813
|
+
}
|
|
814
|
+
destroy() {
|
|
815
|
+
this.stop();
|
|
816
|
+
if (this._canvas) {
|
|
817
|
+
this._canvas.remove();
|
|
818
|
+
this._canvas = void 0;
|
|
819
|
+
this._ctx = void 0;
|
|
754
820
|
}
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
this.
|
|
760
|
-
this.
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
handle.addListener("change", this._handleChange);
|
|
821
|
+
}
|
|
822
|
+
resize() {
|
|
823
|
+
if (this._node.parentElement && this._canvas) {
|
|
824
|
+
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
825
|
+
this._canvas.style.top = `${y}px`;
|
|
826
|
+
this._canvas.style.left = `${x}px`;
|
|
827
|
+
this._canvas.width = width;
|
|
828
|
+
this._canvas.height = height;
|
|
764
829
|
}
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
830
|
+
}
|
|
831
|
+
start() {
|
|
832
|
+
invariant2(this._canvas && this._ctx, void 0, {
|
|
833
|
+
F: __dxlog_file2,
|
|
834
|
+
L: 177,
|
|
835
|
+
S: this,
|
|
836
|
+
A: [
|
|
837
|
+
"this._canvas && this._ctx",
|
|
838
|
+
""
|
|
839
|
+
]
|
|
840
|
+
});
|
|
841
|
+
this._running = true;
|
|
842
|
+
this.loop();
|
|
843
|
+
}
|
|
844
|
+
stop() {
|
|
845
|
+
this._running = false;
|
|
846
|
+
this._node.style.transform = "translate(0px, 0px)";
|
|
847
|
+
}
|
|
848
|
+
loop() {
|
|
849
|
+
if (!this._running || !this._canvas || !this._ctx) {
|
|
850
|
+
return;
|
|
851
|
+
}
|
|
852
|
+
this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
|
|
853
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
854
|
+
this._lastTime ??= now;
|
|
855
|
+
const dt = (now - this._lastTime) / 1e3;
|
|
856
|
+
this._lastTime = now;
|
|
857
|
+
if (this._shakeTime > 0) {
|
|
858
|
+
this._shakeTime -= dt;
|
|
859
|
+
const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
|
|
860
|
+
const shakeX = random(-magnitude, magnitude);
|
|
861
|
+
const shakeY = random(-magnitude, magnitude);
|
|
862
|
+
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
863
|
+
}
|
|
864
|
+
this.drawParticles();
|
|
865
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
866
|
+
}
|
|
867
|
+
drawParticles() {
|
|
868
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
869
|
+
const particle = this._particles[i];
|
|
870
|
+
if (!particle) {
|
|
871
|
+
continue;
|
|
872
|
+
}
|
|
873
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
874
|
+
continue;
|
|
770
875
|
}
|
|
876
|
+
this._effect.update(this._ctx, particle);
|
|
771
877
|
}
|
|
772
|
-
|
|
773
|
-
|
|
878
|
+
}
|
|
879
|
+
};
|
|
880
|
+
var Effect = class {
|
|
881
|
+
constructor(_options) {
|
|
882
|
+
this._options = _options;
|
|
883
|
+
}
|
|
884
|
+
};
|
|
885
|
+
var Effect1 = class extends Effect {
|
|
886
|
+
create(x, y, color) {
|
|
887
|
+
return {
|
|
888
|
+
x,
|
|
889
|
+
y: y + 10,
|
|
890
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
891
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
892
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
893
|
+
color,
|
|
894
|
+
alpha: 1
|
|
895
|
+
};
|
|
896
|
+
}
|
|
897
|
+
update(ctx, particle) {
|
|
898
|
+
particle.vy += this._options.particleGravity;
|
|
899
|
+
particle.x += particle.vx;
|
|
900
|
+
particle.y += particle.vy;
|
|
901
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
902
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
903
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
904
|
+
}
|
|
905
|
+
};
|
|
906
|
+
var Effect2 = class extends Effect {
|
|
907
|
+
create(x, y, color) {
|
|
908
|
+
return {
|
|
909
|
+
x,
|
|
910
|
+
y: y + 10,
|
|
911
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
912
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
913
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
914
|
+
color,
|
|
915
|
+
alpha: 1,
|
|
916
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
917
|
+
drag: 0.92,
|
|
918
|
+
wander: 0.15
|
|
919
|
+
};
|
|
920
|
+
}
|
|
921
|
+
update(ctx, particle) {
|
|
922
|
+
particle.vy += this._options.particleGravity;
|
|
923
|
+
particle.x += particle.vx;
|
|
924
|
+
particle.y += particle.vy;
|
|
925
|
+
particle.vx *= particle.drag;
|
|
926
|
+
particle.vy *= particle.drag;
|
|
927
|
+
particle.theta += random(-0.5, 0.5);
|
|
928
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
929
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
930
|
+
particle.size *= this._options.particleShrinkRate;
|
|
931
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
932
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
933
|
+
ctx.beginPath();
|
|
934
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
935
|
+
ctx.fill();
|
|
936
|
+
}
|
|
937
|
+
};
|
|
938
|
+
function throttle(callback, limit) {
|
|
939
|
+
let wait = false;
|
|
940
|
+
return function(...args) {
|
|
941
|
+
if (!wait) {
|
|
942
|
+
callback.apply(this, args);
|
|
943
|
+
wait = true;
|
|
944
|
+
setTimeout(() => {
|
|
945
|
+
wait = false;
|
|
946
|
+
}, limit);
|
|
774
947
|
}
|
|
775
|
-
});
|
|
776
|
-
return {
|
|
777
|
-
extension: [
|
|
778
|
-
stateField,
|
|
779
|
-
semaphoreFacet.of(semaphore),
|
|
780
|
-
viewPlugin
|
|
781
|
-
]
|
|
782
948
|
};
|
|
949
|
+
}
|
|
950
|
+
var getRGBComponents = (node, color) => {
|
|
951
|
+
if (typeof color === "function") {
|
|
952
|
+
return color();
|
|
953
|
+
}
|
|
954
|
+
const bgColor = getComputedStyle(node).color;
|
|
955
|
+
if (bgColor) {
|
|
956
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
957
|
+
if (x) {
|
|
958
|
+
return x;
|
|
959
|
+
}
|
|
960
|
+
}
|
|
961
|
+
return [
|
|
962
|
+
50,
|
|
963
|
+
50,
|
|
964
|
+
50
|
|
965
|
+
];
|
|
966
|
+
};
|
|
967
|
+
var random = (min, max) => {
|
|
968
|
+
if (!max) {
|
|
969
|
+
max = min;
|
|
970
|
+
min = 0;
|
|
971
|
+
}
|
|
972
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
783
973
|
};
|
|
784
|
-
var reconcileAnnotationType = Annotation.define();
|
|
785
|
-
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
786
974
|
|
|
787
|
-
// packages/ui/react-ui-editor/src/
|
|
975
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
976
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
|
|
977
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
978
|
+
|
|
979
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
788
980
|
import * as random2 from "lib0/random";
|
|
789
981
|
var cursorColors = [
|
|
790
982
|
{
|
|
@@ -822,282 +1014,243 @@ var cursorColors = [
|
|
|
822
1014
|
];
|
|
823
1015
|
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
824
1016
|
|
|
825
|
-
// packages/ui/react-ui-editor/src/
|
|
826
|
-
import
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
857
|
-
}
|
|
858
|
-
get awareness() {
|
|
859
|
-
return this._awareness;
|
|
860
|
-
}
|
|
861
|
-
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
862
|
-
log2("awareness update", {
|
|
863
|
-
added,
|
|
864
|
-
updated,
|
|
865
|
-
removed,
|
|
866
|
-
origin
|
|
867
|
-
}, {
|
|
868
|
-
F: __dxlog_file3,
|
|
869
|
-
L: 67,
|
|
870
|
-
S: this,
|
|
871
|
-
C: (f, a) => f(...a)
|
|
872
|
-
});
|
|
873
|
-
const changedClients = added.concat(updated).concat(removed);
|
|
874
|
-
const encoderAwareness = encoding.createEncoder();
|
|
875
|
-
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
876
|
-
encoding.writeVarUint8Array(encoderAwareness, awarenessProtocol.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
877
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
878
|
-
}
|
|
879
|
-
_handleSpaceMessage({ payload }) {
|
|
880
|
-
log2("space message", payload, {
|
|
881
|
-
F: __dxlog_file3,
|
|
882
|
-
L: 79,
|
|
883
|
-
S: this,
|
|
884
|
-
C: (f, a) => f(...a)
|
|
885
|
-
});
|
|
886
|
-
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
887
|
-
const encoder = this._readMessage(data);
|
|
888
|
-
if (encoder) {
|
|
889
|
-
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
890
|
-
}
|
|
891
|
-
}
|
|
892
|
-
_readMessage(message) {
|
|
893
|
-
const decoder = decoding.createDecoder(message);
|
|
894
|
-
const encoder = encoding.createEncoder();
|
|
895
|
-
const messageType = decoding.readVarUint(decoder);
|
|
896
|
-
let sendReply = false;
|
|
897
|
-
switch (messageType) {
|
|
898
|
-
case messageAwareness: {
|
|
899
|
-
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
900
|
-
break;
|
|
901
|
-
}
|
|
902
|
-
case messageQueryAwareness: {
|
|
903
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
904
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
905
|
-
sendReply = true;
|
|
906
|
-
break;
|
|
907
|
-
}
|
|
908
|
-
default: {
|
|
909
|
-
console.error("Invalid message:", messageType);
|
|
910
|
-
return encoder;
|
|
911
|
-
}
|
|
912
|
-
}
|
|
913
|
-
if (!sendReply) {
|
|
914
|
-
return null;
|
|
915
|
-
}
|
|
916
|
-
return encoder;
|
|
917
|
-
}
|
|
918
|
-
_handleBeforeUnload() {
|
|
919
|
-
awarenessProtocol.removeAwarenessStates(this._awareness, [
|
|
920
|
-
this._clientId
|
|
921
|
-
], "window unload");
|
|
922
|
-
}
|
|
1017
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
1018
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
1019
|
+
var headings = {
|
|
1020
|
+
1: [
|
|
1021
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
1022
|
+
"-ml-[10px]"
|
|
1023
|
+
],
|
|
1024
|
+
2: [
|
|
1025
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
1026
|
+
"-ml-[8px]"
|
|
1027
|
+
],
|
|
1028
|
+
3: [
|
|
1029
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
1030
|
+
"-ml-[7px]"
|
|
1031
|
+
],
|
|
1032
|
+
4: [
|
|
1033
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
1034
|
+
"-ml-[6px]"
|
|
1035
|
+
],
|
|
1036
|
+
5: [
|
|
1037
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
1038
|
+
"-ml-[5px]"
|
|
1039
|
+
],
|
|
1040
|
+
6: [
|
|
1041
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
1042
|
+
"-ml-[4px]"
|
|
1043
|
+
]
|
|
1044
|
+
};
|
|
1045
|
+
var heading = (level, readonly) => {
|
|
1046
|
+
const [style, offset] = headings[level];
|
|
1047
|
+
return mx(style, readonly && offset);
|
|
923
1048
|
};
|
|
1049
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1050
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
1051
|
+
var bold = "font-bold";
|
|
1052
|
+
var italic = "italic";
|
|
1053
|
+
var strikethrough = "line-through";
|
|
1054
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
1055
|
+
var codeMark = "font-mono text-primary-500";
|
|
1056
|
+
var inlineUrl = mx(code, "px-1");
|
|
1057
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
924
1058
|
|
|
925
|
-
// packages/ui/react-ui-editor/src/
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
-
|
|
1059
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1060
|
+
import get2 from "lodash.get";
|
|
1061
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1062
|
+
var tokens = tailwindConfig({}).theme;
|
|
1063
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1064
|
+
|
|
1065
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1066
|
+
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1067
|
+
var styles2 = EditorView5.baseTheme({
|
|
1068
|
+
"& .cm-codeblock": {
|
|
1069
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1070
|
+
},
|
|
1071
|
+
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1072
|
+
background: getToken("extend.colors.neutral.50")
|
|
1073
|
+
},
|
|
1074
|
+
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1075
|
+
background: getToken("extend.colors.neutral.850")
|
|
1076
|
+
},
|
|
1077
|
+
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1078
|
+
display: "block",
|
|
1079
|
+
paddingInline: "4px !important"
|
|
1080
|
+
},
|
|
1081
|
+
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1082
|
+
paddingTop: "4px !important",
|
|
1083
|
+
borderTopLeftRadius: "4px",
|
|
1084
|
+
borderTopRightRadius: "4px"
|
|
1085
|
+
},
|
|
1086
|
+
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1087
|
+
paddingBottom: "4px !important",
|
|
1088
|
+
borderBottomLeftRadius: "4px",
|
|
1089
|
+
borderBottomRightRadius: "4px"
|
|
1090
|
+
}
|
|
930
1091
|
});
|
|
931
|
-
var
|
|
932
|
-
const
|
|
933
|
-
const
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
]);
|
|
939
|
-
return model;
|
|
1092
|
+
var getLineRange = (lines, from, to) => {
|
|
1093
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1094
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1095
|
+
return [
|
|
1096
|
+
start,
|
|
1097
|
+
end
|
|
1098
|
+
];
|
|
940
1099
|
};
|
|
941
|
-
var
|
|
942
|
-
const
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
947
|
-
|
|
1100
|
+
var code2 = () => {
|
|
1101
|
+
const buildDecorations5 = (view) => {
|
|
1102
|
+
const decorations = [];
|
|
1103
|
+
const text = view.state.doc.sliceString(0);
|
|
1104
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1105
|
+
const blocks = view.viewportLineBlocks;
|
|
1106
|
+
for (const match of matches) {
|
|
1107
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1108
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1109
|
+
const block = blocks[i];
|
|
1110
|
+
decorations.push(Decoration2.line({
|
|
1111
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1112
|
+
}).range(block.from));
|
|
1113
|
+
}
|
|
948
1114
|
}
|
|
949
|
-
return
|
|
950
|
-
}
|
|
951
|
-
};
|
|
952
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
953
|
-
invariant2(text?.doc && text?.content, void 0, {
|
|
954
|
-
F: __dxlog_file4,
|
|
955
|
-
L: 97,
|
|
956
|
-
S: void 0,
|
|
957
|
-
A: [
|
|
958
|
-
"text?.doc && text?.content",
|
|
959
|
-
""
|
|
960
|
-
]
|
|
961
|
-
});
|
|
962
|
-
const provider = space ? new SpaceAwarenessProvider({
|
|
963
|
-
space,
|
|
964
|
-
doc: text.doc,
|
|
965
|
-
channel: `yjs.awareness.${text.id}`
|
|
966
|
-
}) : void 0;
|
|
967
|
-
const model = {
|
|
968
|
-
id: text.doc.guid,
|
|
969
|
-
content: text.content,
|
|
970
|
-
text: () => text.content.toString(),
|
|
971
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
972
|
-
getCursorFromRange: (range) => {
|
|
973
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
974
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
975
|
-
return [
|
|
976
|
-
arrayToString(from),
|
|
977
|
-
arrayToString(to)
|
|
978
|
-
].join(":");
|
|
979
|
-
},
|
|
980
|
-
getRangeFromCursor: (cursor) => {
|
|
981
|
-
invariant2(text.doc, void 0, {
|
|
982
|
-
F: __dxlog_file4,
|
|
983
|
-
L: 113,
|
|
984
|
-
S: void 0,
|
|
985
|
-
A: [
|
|
986
|
-
"text.doc",
|
|
987
|
-
""
|
|
988
|
-
]
|
|
989
|
-
});
|
|
990
|
-
const parts = cursor.split(":");
|
|
991
|
-
const from = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[0])), text.doc);
|
|
992
|
-
const to = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[1])), text.doc);
|
|
993
|
-
return from && to ? {
|
|
994
|
-
from: from.index,
|
|
995
|
-
to: to.index
|
|
996
|
-
} : void 0;
|
|
997
|
-
},
|
|
998
|
-
extension: [
|
|
999
|
-
yCollab(text.content, provider?.awareness),
|
|
1000
|
-
modelState.init(() => model)
|
|
1001
|
-
],
|
|
1002
|
-
awareness: provider?.awareness,
|
|
1003
|
-
peer: identity ? {
|
|
1004
|
-
id: identity.identityKey.toHex(),
|
|
1005
|
-
name: identity.profile?.displayName
|
|
1006
|
-
} : void 0
|
|
1115
|
+
return Decoration2.set(decorations);
|
|
1007
1116
|
};
|
|
1008
|
-
return
|
|
1117
|
+
return [
|
|
1118
|
+
ViewPlugin3.fromClass(class {
|
|
1119
|
+
constructor(view) {
|
|
1120
|
+
this.hasFocus = false;
|
|
1121
|
+
this.decorations = buildDecorations5(view);
|
|
1122
|
+
}
|
|
1123
|
+
update(update2) {
|
|
1124
|
+
if (
|
|
1125
|
+
// TODO(burdon): Generalize for other extensions.
|
|
1126
|
+
this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
|
|
1127
|
+
) {
|
|
1128
|
+
this.hasFocus = update2.view.hasFocus;
|
|
1129
|
+
this.decorations = buildDecorations5(update2.view);
|
|
1130
|
+
}
|
|
1131
|
+
}
|
|
1132
|
+
}, {
|
|
1133
|
+
decorations: (value) => value.decorations
|
|
1134
|
+
}),
|
|
1135
|
+
styles2
|
|
1136
|
+
];
|
|
1009
1137
|
};
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
|
|
1027
|
-
|
|
1028
|
-
|
|
1029
|
-
|
|
1138
|
+
|
|
1139
|
+
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1140
|
+
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1141
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
|
|
1142
|
+
import sortBy from "lodash.sortby";
|
|
1143
|
+
import { useEffect as useEffect2 } from "react";
|
|
1144
|
+
import { debounce } from "@dxos/async";
|
|
1145
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1146
|
+
import { nonNullable } from "@dxos/util";
|
|
1147
|
+
|
|
1148
|
+
// packages/ui/react-ui-editor/src/util.ts
|
|
1149
|
+
import { log } from "@dxos/log";
|
|
1150
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
|
|
1151
|
+
var callbackWrapper = (fn) => (...args) => {
|
|
1152
|
+
try {
|
|
1153
|
+
return fn(...args);
|
|
1154
|
+
} catch (err) {
|
|
1155
|
+
log.catch(err, void 0, {
|
|
1156
|
+
F: __dxlog_file3,
|
|
1157
|
+
L: 18,
|
|
1158
|
+
S: void 0,
|
|
1159
|
+
C: (f, a) => f(...a)
|
|
1160
|
+
});
|
|
1161
|
+
}
|
|
1162
|
+
};
|
|
1163
|
+
var logChanges = (trs) => {
|
|
1164
|
+
const changes = trs.flatMap((tr) => {
|
|
1165
|
+
if (tr.changes.empty) {
|
|
1166
|
+
return void 0;
|
|
1167
|
+
}
|
|
1168
|
+
const changes2 = [];
|
|
1169
|
+
tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
|
|
1170
|
+
fromA,
|
|
1171
|
+
toA,
|
|
1172
|
+
fromB,
|
|
1173
|
+
toB,
|
|
1174
|
+
inserted: inserted.toString()
|
|
1175
|
+
})));
|
|
1176
|
+
return changes2;
|
|
1177
|
+
}).filter(Boolean);
|
|
1178
|
+
if (changes.length) {
|
|
1179
|
+
console.log("changes", changes);
|
|
1180
|
+
}
|
|
1030
1181
|
};
|
|
1031
1182
|
|
|
1032
1183
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1033
|
-
var
|
|
1034
|
-
var
|
|
1035
|
-
"& .cm-bookmark": {
|
|
1036
|
-
cursor: "pointer",
|
|
1037
|
-
margin: "4px",
|
|
1038
|
-
padding: "4px",
|
|
1039
|
-
backgroundColor: "yellow"
|
|
1040
|
-
},
|
|
1041
|
-
"& .cm-bookmark-selected": {
|
|
1042
|
-
backgroundColor: "orange"
|
|
1043
|
-
},
|
|
1184
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1185
|
+
var styles3 = EditorView6.baseTheme({
|
|
1044
1186
|
"& .cm-comment": {
|
|
1045
|
-
backgroundColor:
|
|
1187
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1046
1188
|
},
|
|
1047
|
-
"& .cm-comment-
|
|
1048
|
-
backgroundColor:
|
|
1189
|
+
"& .cm-comment-current": {
|
|
1190
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1049
1191
|
}
|
|
1050
1192
|
});
|
|
1051
1193
|
var marks = {
|
|
1052
|
-
highlight:
|
|
1194
|
+
highlight: Decoration3.mark({
|
|
1053
1195
|
class: "cm-comment"
|
|
1054
1196
|
}),
|
|
1055
|
-
highlightActive:
|
|
1056
|
-
class: "cm-comment-
|
|
1197
|
+
highlightActive: Decoration3.mark({
|
|
1198
|
+
class: "cm-comment-current"
|
|
1057
1199
|
})
|
|
1058
1200
|
};
|
|
1059
|
-
var setFocus = (view,
|
|
1060
|
-
const
|
|
1061
|
-
if (!
|
|
1201
|
+
var setFocus = (view, id, center = true) => {
|
|
1202
|
+
const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
|
|
1203
|
+
if (!comment?.comment.cursor) {
|
|
1062
1204
|
return;
|
|
1063
1205
|
}
|
|
1064
|
-
view.
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1206
|
+
const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
|
|
1207
|
+
if (range) {
|
|
1208
|
+
view.dispatch({
|
|
1209
|
+
selection: {
|
|
1210
|
+
anchor: range.from
|
|
1211
|
+
},
|
|
1212
|
+
effects: [
|
|
1213
|
+
//
|
|
1214
|
+
EditorView6.scrollIntoView(range.from, center ? {
|
|
1215
|
+
y: "center"
|
|
1216
|
+
} : void 0),
|
|
1217
|
+
setSelection.of({
|
|
1218
|
+
current: id
|
|
1219
|
+
})
|
|
1220
|
+
]
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1073
1223
|
};
|
|
1074
|
-
var
|
|
1224
|
+
var setComments = StateEffect2.define();
|
|
1075
1225
|
var setSelection = StateEffect2.define();
|
|
1076
1226
|
var setCommentState = StateEffect2.define();
|
|
1077
|
-
var
|
|
1227
|
+
var commentsState = StateField2.define({
|
|
1078
1228
|
create: () => ({
|
|
1079
|
-
|
|
1229
|
+
comments: [],
|
|
1230
|
+
selection: {}
|
|
1080
1231
|
}),
|
|
1081
1232
|
update: (value, tr) => {
|
|
1082
1233
|
for (const effect of tr.effects) {
|
|
1083
1234
|
if (effect.is(setSelection)) {
|
|
1084
1235
|
return {
|
|
1085
1236
|
...value,
|
|
1086
|
-
|
|
1237
|
+
selection: effect.value
|
|
1087
1238
|
};
|
|
1088
1239
|
}
|
|
1089
|
-
if (effect.is(
|
|
1090
|
-
const
|
|
1091
|
-
|
|
1092
|
-
|
|
1240
|
+
if (effect.is(setComments)) {
|
|
1241
|
+
const comments2 = effect.value.map((comment) => {
|
|
1242
|
+
if (!comment.cursor) {
|
|
1243
|
+
return void 0;
|
|
1244
|
+
}
|
|
1245
|
+
const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
|
|
1093
1246
|
return range && {
|
|
1094
|
-
|
|
1095
|
-
|
|
1247
|
+
comment,
|
|
1248
|
+
range
|
|
1096
1249
|
};
|
|
1097
1250
|
}).filter(nonNullable);
|
|
1098
1251
|
return {
|
|
1099
1252
|
...value,
|
|
1100
|
-
|
|
1253
|
+
comments: comments2
|
|
1101
1254
|
};
|
|
1102
1255
|
}
|
|
1103
1256
|
if (effect.is(setCommentState)) {
|
|
@@ -1107,142 +1260,133 @@ var commentsStateField = StateField3.define({
|
|
|
1107
1260
|
return value;
|
|
1108
1261
|
}
|
|
1109
1262
|
});
|
|
1110
|
-
var highlightDecorations =
|
|
1111
|
-
|
|
1263
|
+
var highlightDecorations = EditorView6.decorations.compute([
|
|
1264
|
+
commentsState
|
|
1112
1265
|
], (state) => {
|
|
1113
|
-
const {
|
|
1114
|
-
const decorations = sortBy(
|
|
1115
|
-
|
|
1266
|
+
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
1267
|
+
const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
1268
|
+
const range = comment.range;
|
|
1269
|
+
if (!range || range.from === range.to) {
|
|
1270
|
+
console.warn("Invalid range:", range);
|
|
1116
1271
|
return void 0;
|
|
1117
1272
|
}
|
|
1118
|
-
|
|
1119
|
-
from: selection.from,
|
|
1120
|
-
to: selection.to
|
|
1121
|
-
};
|
|
1122
|
-
if (selection.id === active) {
|
|
1273
|
+
if (comment.comment.id === current) {
|
|
1123
1274
|
return marks.highlightActive.range(range.from, range.to);
|
|
1124
1275
|
} else {
|
|
1125
1276
|
return marks.highlight.range(range.from, range.to);
|
|
1126
1277
|
}
|
|
1127
|
-
}).filter(nonNullable)
|
|
1128
|
-
return
|
|
1278
|
+
}).filter(nonNullable);
|
|
1279
|
+
return Decoration3.set(decorations);
|
|
1129
1280
|
});
|
|
1130
|
-
var
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
|
|
1134
|
-
|
|
1135
|
-
|
|
1136
|
-
|
|
1137
|
-
|
|
1138
|
-
|
|
1139
|
-
|
|
1140
|
-
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
return this._anchor === other._anchor && this._id === other._id;
|
|
1148
|
-
}
|
|
1149
|
-
toDOM() {
|
|
1150
|
-
const span = document.createElement("span");
|
|
1151
|
-
span.className = "cm-bookmark";
|
|
1152
|
-
span.textContent = "\u203B";
|
|
1153
|
-
if (this._handleClick) {
|
|
1154
|
-
span.onclick = () => this._handleClick();
|
|
1281
|
+
var trackPastedComments = (onUpdate) => {
|
|
1282
|
+
let tracked = null;
|
|
1283
|
+
const handleTrack = (event, view) => {
|
|
1284
|
+
const comments2 = view.state.field(commentsState);
|
|
1285
|
+
const { main } = view.state.selection;
|
|
1286
|
+
const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
|
|
1287
|
+
if (!selectedRanges.length) {
|
|
1288
|
+
tracked = null;
|
|
1289
|
+
} else {
|
|
1290
|
+
tracked = {
|
|
1291
|
+
text: view.state.doc.slice(main.from, main.to),
|
|
1292
|
+
comments: selectedRanges.map(({ comment, range }) => ({
|
|
1293
|
+
id: comment.id,
|
|
1294
|
+
from: range.from - main.from,
|
|
1295
|
+
to: range.to - main.from
|
|
1296
|
+
}))
|
|
1297
|
+
};
|
|
1155
1298
|
}
|
|
1156
|
-
|
|
1157
|
-
|
|
1299
|
+
};
|
|
1300
|
+
return [
|
|
1301
|
+
EditorView6.domEventHandlers({
|
|
1302
|
+
cut: handleTrack,
|
|
1303
|
+
copy: handleTrack
|
|
1304
|
+
}),
|
|
1305
|
+
// Handle paste.
|
|
1306
|
+
EditorView6.updateListener.of(({ view, state, transactions }) => {
|
|
1307
|
+
if (tracked) {
|
|
1308
|
+
const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
|
|
1309
|
+
if (paste) {
|
|
1310
|
+
let found = -1;
|
|
1311
|
+
paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
|
|
1312
|
+
if (text.eq(tracked.text)) {
|
|
1313
|
+
for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
|
|
1314
|
+
fromB = transactions[i].changes.mapPos(fromB);
|
|
1315
|
+
}
|
|
1316
|
+
found = fromB;
|
|
1317
|
+
}
|
|
1318
|
+
});
|
|
1319
|
+
if (found > -1) {
|
|
1320
|
+
for (const moved of tracked.comments) {
|
|
1321
|
+
const range = {
|
|
1322
|
+
from: found + moved.from,
|
|
1323
|
+
to: found + moved.to
|
|
1324
|
+
};
|
|
1325
|
+
const cursor = Cursor.getCursorFromRange(state, range);
|
|
1326
|
+
onUpdate(moved.id, cursor);
|
|
1327
|
+
}
|
|
1328
|
+
}
|
|
1329
|
+
tracked = null;
|
|
1330
|
+
}
|
|
1331
|
+
}
|
|
1332
|
+
})
|
|
1333
|
+
];
|
|
1158
1334
|
};
|
|
1159
1335
|
var comments = (options = {}) => {
|
|
1336
|
+
const { key: shortcut = "meta-'" } = options;
|
|
1160
1337
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1161
1338
|
const createCommentThread = (view) => {
|
|
1162
1339
|
invariant3(options.onCreate, void 0, {
|
|
1163
|
-
F:
|
|
1164
|
-
L:
|
|
1340
|
+
F: __dxlog_file4,
|
|
1341
|
+
L: 259,
|
|
1165
1342
|
S: void 0,
|
|
1166
1343
|
A: [
|
|
1167
1344
|
"options.onCreate",
|
|
1168
1345
|
""
|
|
1169
1346
|
]
|
|
1170
1347
|
});
|
|
1171
|
-
const {
|
|
1348
|
+
const { from, to } = view.state.selection.main;
|
|
1172
1349
|
if (from === to) {
|
|
1173
1350
|
return false;
|
|
1174
1351
|
}
|
|
1175
|
-
|
|
1176
|
-
|
|
1352
|
+
if (to === view.state.doc.length) {
|
|
1353
|
+
view.dispatch({
|
|
1354
|
+
changes: {
|
|
1355
|
+
from: to,
|
|
1356
|
+
insert: "\n"
|
|
1357
|
+
}
|
|
1358
|
+
});
|
|
1359
|
+
}
|
|
1360
|
+
const cursor = Cursor.getCursorFromRange(view.state, {
|
|
1177
1361
|
from,
|
|
1178
1362
|
to
|
|
1179
1363
|
});
|
|
1180
|
-
if (
|
|
1181
|
-
const id =
|
|
1364
|
+
if (cursor) {
|
|
1365
|
+
const id = options.onCreate?.(cursor, view.coordsAtPos(from));
|
|
1182
1366
|
if (id) {
|
|
1183
1367
|
view.dispatch({
|
|
1184
1368
|
effects: setSelection.of({
|
|
1185
|
-
|
|
1369
|
+
current: id
|
|
1186
1370
|
}),
|
|
1187
1371
|
selection: {
|
|
1188
1372
|
anchor: from
|
|
1189
1373
|
}
|
|
1190
1374
|
});
|
|
1191
|
-
if (options.footnote) {
|
|
1192
|
-
const tag = `[^${id}]`;
|
|
1193
|
-
view.dispatch({
|
|
1194
|
-
changes: {
|
|
1195
|
-
from: head,
|
|
1196
|
-
insert: tag
|
|
1197
|
-
},
|
|
1198
|
-
selection: {
|
|
1199
|
-
anchor: head + tag.length
|
|
1200
|
-
}
|
|
1201
|
-
});
|
|
1202
|
-
}
|
|
1203
1375
|
return true;
|
|
1204
1376
|
}
|
|
1205
1377
|
}
|
|
1206
1378
|
return false;
|
|
1207
1379
|
};
|
|
1208
|
-
const bookmarksViewPlugin = ViewPlugin3.fromClass(class BookmarkViewPlugin {
|
|
1209
|
-
static {
|
|
1210
|
-
// Match markdown footnotes (option).
|
|
1211
|
-
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
1212
|
-
this.bookmarkMatcher = new MatchDecorator({
|
|
1213
|
-
regexp: /\[\^(\w+)\]/g,
|
|
1214
|
-
decoration: (match, view, pos) => {
|
|
1215
|
-
const id = match[1];
|
|
1216
|
-
return Decoration2.replace({
|
|
1217
|
-
id,
|
|
1218
|
-
widget: new BookmarkWidget(pos, id)
|
|
1219
|
-
});
|
|
1220
|
-
}
|
|
1221
|
-
});
|
|
1222
|
-
}
|
|
1223
|
-
constructor(view) {
|
|
1224
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1225
|
-
}
|
|
1226
|
-
update(update4) {
|
|
1227
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
1228
|
-
}
|
|
1229
|
-
}, {
|
|
1230
|
-
decorations: (instance) => instance.bookmarks,
|
|
1231
|
-
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
1232
|
-
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
1233
|
-
})
|
|
1234
|
-
});
|
|
1235
1380
|
return [
|
|
1236
|
-
|
|
1237
|
-
commentsStateField,
|
|
1381
|
+
commentsState,
|
|
1238
1382
|
highlightDecorations,
|
|
1239
|
-
|
|
1383
|
+
styles3,
|
|
1240
1384
|
//
|
|
1241
1385
|
// Keymap.
|
|
1242
1386
|
//
|
|
1243
1387
|
options.onCreate ? keymap3.of([
|
|
1244
1388
|
{
|
|
1245
|
-
key:
|
|
1389
|
+
key: shortcut,
|
|
1246
1390
|
run: callbackWrapper(createCommentThread)
|
|
1247
1391
|
}
|
|
1248
1392
|
]) : [],
|
|
@@ -1259,7 +1403,7 @@ var comments = (options = {}) => {
|
|
|
1259
1403
|
above: true,
|
|
1260
1404
|
create: () => {
|
|
1261
1405
|
const el = document.createElement("div");
|
|
1262
|
-
options.onHover
|
|
1406
|
+
options.onHover(el, shortcut);
|
|
1263
1407
|
return {
|
|
1264
1408
|
dom: el,
|
|
1265
1409
|
offset: {
|
|
@@ -1272,178 +1416,206 @@ var comments = (options = {}) => {
|
|
|
1272
1416
|
}
|
|
1273
1417
|
return null;
|
|
1274
1418
|
}, {
|
|
1275
|
-
|
|
1419
|
+
// TODO(burdon): Hide on change triggered immediately?
|
|
1420
|
+
// hideOnChange: true,
|
|
1276
1421
|
hoverTime: 1e3
|
|
1277
1422
|
}) : [],
|
|
1278
1423
|
//
|
|
1279
|
-
//
|
|
1280
|
-
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1424
|
+
// Track deleted ranges and update ranges for decorations.
|
|
1281
1425
|
//
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
S: void 0,
|
|
1292
|
-
A: [
|
|
1293
|
-
"model",
|
|
1294
|
-
""
|
|
1295
|
-
]
|
|
1296
|
-
});
|
|
1297
|
-
ranges.forEach((range) => {
|
|
1298
|
-
if (from2 === to2) {
|
|
1299
|
-
const newRange = model.getRangeFromCursor(range.cursor);
|
|
1300
|
-
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1301
|
-
log3.info("deleted comment", {
|
|
1302
|
-
thread: range.id
|
|
1303
|
-
}, {
|
|
1304
|
-
F: __dxlog_file5,
|
|
1305
|
-
L: 356,
|
|
1306
|
-
S: void 0,
|
|
1307
|
-
C: (f, a) => f(...a)
|
|
1308
|
-
});
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
if (from <= range.to) {
|
|
1312
|
-
const newRange = model.getRangeFromCursor(range.cursor);
|
|
1313
|
-
Object.assign(range, newRange);
|
|
1314
|
-
mod = true;
|
|
1426
|
+
EditorView6.updateListener.of(({ view, state, changes }) => {
|
|
1427
|
+
let mod = false;
|
|
1428
|
+
const { comments: comments2, ...value } = state.field(commentsState);
|
|
1429
|
+
changes.iterChanges((from, to, from2, to2) => {
|
|
1430
|
+
comments2.forEach(({ comment, range }) => {
|
|
1431
|
+
if (from2 === to2) {
|
|
1432
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1433
|
+
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1434
|
+
options.onDelete?.(comment.id);
|
|
1315
1435
|
}
|
|
1316
|
-
}
|
|
1436
|
+
}
|
|
1437
|
+
if (from <= range.to) {
|
|
1438
|
+
const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
|
|
1439
|
+
Object.assign(range, newRange);
|
|
1440
|
+
mod = true;
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
});
|
|
1444
|
+
if (mod) {
|
|
1445
|
+
view.dispatch({
|
|
1446
|
+
effects: setCommentState.of({
|
|
1447
|
+
comments: comments2,
|
|
1448
|
+
...value
|
|
1449
|
+
})
|
|
1317
1450
|
});
|
|
1318
|
-
if (mod) {
|
|
1319
|
-
view.dispatch({
|
|
1320
|
-
effects: setCommentState.of({
|
|
1321
|
-
active,
|
|
1322
|
-
ranges
|
|
1323
|
-
})
|
|
1324
|
-
});
|
|
1325
|
-
}
|
|
1326
1451
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1452
|
+
}),
|
|
1453
|
+
//
|
|
1454
|
+
// Track selection/proximity.
|
|
1455
|
+
//
|
|
1456
|
+
EditorView6.updateListener.of(({ view, state }) => {
|
|
1457
|
+
let min = Infinity;
|
|
1458
|
+
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
1459
|
+
const { head } = state.selection.main;
|
|
1460
|
+
const selection = {};
|
|
1461
|
+
comments2.forEach(({ comment, range }) => {
|
|
1462
|
+
if (head >= range.from && head <= range.to) {
|
|
1463
|
+
selection.current = comment.id;
|
|
1464
|
+
selection.closest = void 0;
|
|
1465
|
+
}
|
|
1466
|
+
if (!selection.current) {
|
|
1467
|
+
const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
|
|
1340
1468
|
if (d < min) {
|
|
1341
|
-
|
|
1469
|
+
selection.closest = comment.id;
|
|
1342
1470
|
min = d;
|
|
1343
1471
|
}
|
|
1344
|
-
});
|
|
1345
|
-
if (selected.active !== active || selected.closest !== closest) {
|
|
1346
|
-
view.dispatch({
|
|
1347
|
-
effects: setSelection.of(selected)
|
|
1348
|
-
});
|
|
1349
|
-
handleSelect({
|
|
1350
|
-
...selected,
|
|
1351
|
-
ranges: ranges.map((range) => ({
|
|
1352
|
-
...range,
|
|
1353
|
-
location: view.coordsAtPos(range.from)
|
|
1354
|
-
}))
|
|
1355
|
-
});
|
|
1356
1472
|
}
|
|
1473
|
+
});
|
|
1474
|
+
if (selection.current !== current || selection.closest !== closest) {
|
|
1475
|
+
view.dispatch({
|
|
1476
|
+
effects: setSelection.of(selection)
|
|
1477
|
+
});
|
|
1478
|
+
handleSelect({
|
|
1479
|
+
selection,
|
|
1480
|
+
comments: comments2.map(({ comment, range }) => ({
|
|
1481
|
+
comment,
|
|
1482
|
+
range,
|
|
1483
|
+
location: view.coordsAtPos(range.from)
|
|
1484
|
+
}))
|
|
1485
|
+
});
|
|
1357
1486
|
}
|
|
1358
|
-
})
|
|
1487
|
+
}),
|
|
1488
|
+
options.onUpdate ? trackPastedComments(options.onUpdate) : []
|
|
1359
1489
|
];
|
|
1360
1490
|
};
|
|
1491
|
+
var useComments = (view, comments2 = []) => {
|
|
1492
|
+
useEffect2(() => {
|
|
1493
|
+
if (view) {
|
|
1494
|
+
view.dispatch({
|
|
1495
|
+
effects: setComments.of(comments2)
|
|
1496
|
+
});
|
|
1497
|
+
}
|
|
1498
|
+
}, [
|
|
1499
|
+
view,
|
|
1500
|
+
comments2
|
|
1501
|
+
]);
|
|
1502
|
+
};
|
|
1361
1503
|
|
|
1362
1504
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1363
|
-
import {
|
|
1364
|
-
import
|
|
1365
|
-
|
|
1505
|
+
import { syntaxTree } from "@codemirror/language";
|
|
1506
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1507
|
+
import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1508
|
+
var styles4 = EditorView7.baseTheme({
|
|
1366
1509
|
"& .cm-hr": {
|
|
1367
|
-
// TODO(burdon): ???
|
|
1368
1510
|
// Note that block-level decorations should not have vertical margins,
|
|
1369
|
-
|
|
1511
|
+
borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1370
1512
|
}
|
|
1371
1513
|
});
|
|
1372
1514
|
var HorizontalRuleWidget = class extends WidgetType2 {
|
|
1373
|
-
|
|
1374
|
-
super();
|
|
1375
|
-
this._pos = _pos;
|
|
1376
|
-
}
|
|
1377
|
-
eq(other) {
|
|
1378
|
-
return this._pos === other._pos;
|
|
1379
|
-
}
|
|
1380
|
-
toDOM(view) {
|
|
1515
|
+
toDOM() {
|
|
1381
1516
|
const el = document.createElement("div");
|
|
1382
1517
|
el.className = "cm-hr";
|
|
1383
1518
|
return el;
|
|
1384
1519
|
}
|
|
1385
1520
|
};
|
|
1386
|
-
var
|
|
1387
|
-
|
|
1388
|
-
decoration: (match, view, pos) => Decoration3.replace({
|
|
1389
|
-
widget: new HorizontalRuleWidget(pos)
|
|
1390
|
-
})
|
|
1521
|
+
var decoration = Decoration4.replace({
|
|
1522
|
+
widget: new HorizontalRuleWidget()
|
|
1391
1523
|
});
|
|
1392
|
-
var
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1524
|
+
var buildDecorations = (view) => {
|
|
1525
|
+
const builder = new RangeSetBuilder();
|
|
1526
|
+
const { state } = view;
|
|
1527
|
+
const cursor = state.selection.main.head;
|
|
1528
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1529
|
+
syntaxTree(state).iterate({
|
|
1530
|
+
enter: (node) => {
|
|
1531
|
+
if (node.name === "HorizontalRule") {
|
|
1532
|
+
if (cursor <= node.from || cursor >= node.to) {
|
|
1533
|
+
builder.add(node.from, node.to, decoration);
|
|
1534
|
+
}
|
|
1535
|
+
}
|
|
1536
|
+
},
|
|
1537
|
+
from,
|
|
1538
|
+
to
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
return builder.finish();
|
|
1542
|
+
};
|
|
1543
|
+
var hr = () => {
|
|
1544
|
+
return [
|
|
1545
|
+
styles4,
|
|
1546
|
+
ViewPlugin4.fromClass(class {
|
|
1547
|
+
constructor(view) {
|
|
1548
|
+
this.decorations = buildDecorations(view);
|
|
1549
|
+
}
|
|
1550
|
+
update(update2) {
|
|
1551
|
+
this.decorations = buildDecorations(update2.view);
|
|
1552
|
+
}
|
|
1553
|
+
}, {
|
|
1554
|
+
decorations: (v) => v.decorations
|
|
1406
1555
|
})
|
|
1407
|
-
|
|
1408
|
-
|
|
1556
|
+
];
|
|
1557
|
+
};
|
|
1409
1558
|
|
|
1410
1559
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1411
|
-
import { syntaxTree } from "@codemirror/language";
|
|
1412
|
-
import {
|
|
1413
|
-
import { Decoration as
|
|
1560
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1561
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
1562
|
+
import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1414
1563
|
var image = (options = {}) => {
|
|
1415
|
-
return
|
|
1416
|
-
create: (state) =>
|
|
1417
|
-
|
|
1418
|
-
|
|
1564
|
+
return StateField3.define({
|
|
1565
|
+
create: (state) => {
|
|
1566
|
+
return Decoration5.set(buildDecorations2(0, state.doc.length, state));
|
|
1567
|
+
},
|
|
1568
|
+
update: (value, tr) => {
|
|
1569
|
+
if (!tr.docChanged && !tr.selection) {
|
|
1570
|
+
return value;
|
|
1571
|
+
}
|
|
1572
|
+
const cursor = tr.state.selection.main.head;
|
|
1573
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1574
|
+
let from = Math.min(cursor, oldCursor);
|
|
1575
|
+
let to = Math.max(cursor, oldCursor);
|
|
1576
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1577
|
+
from = Math.min(from, fromB);
|
|
1578
|
+
to = Math.max(to, toB);
|
|
1579
|
+
});
|
|
1580
|
+
from = tr.state.doc.lineAt(from).from;
|
|
1581
|
+
to = tr.state.doc.lineAt(to).to;
|
|
1582
|
+
return value.map(tr.changes).update({
|
|
1583
|
+
filterFrom: from,
|
|
1584
|
+
filterTo: to,
|
|
1585
|
+
filter: () => false,
|
|
1586
|
+
add: buildDecorations2(from, to, tr.state)
|
|
1587
|
+
});
|
|
1588
|
+
},
|
|
1589
|
+
provide: (field) => EditorView8.decorations.from(field)
|
|
1419
1590
|
});
|
|
1420
1591
|
};
|
|
1421
|
-
var
|
|
1422
|
-
const
|
|
1592
|
+
var buildDecorations2 = (from, to, state) => {
|
|
1593
|
+
const decorations = [];
|
|
1423
1594
|
const cursor = state.selection.main.head;
|
|
1424
|
-
|
|
1595
|
+
syntaxTree2(state).iterate({
|
|
1425
1596
|
enter: (node) => {
|
|
1426
1597
|
if (node.name === "Image") {
|
|
1427
1598
|
const urlNode = node.node.getChild("URL");
|
|
1428
1599
|
if (urlNode) {
|
|
1429
1600
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1430
1601
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1431
|
-
|
|
1602
|
+
decorations.push(Decoration5.replace({
|
|
1432
1603
|
block: true,
|
|
1433
1604
|
widget: new ImageWidget(url)
|
|
1434
|
-
}));
|
|
1605
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1435
1606
|
}
|
|
1436
1607
|
}
|
|
1437
|
-
}
|
|
1608
|
+
},
|
|
1609
|
+
from,
|
|
1610
|
+
to
|
|
1438
1611
|
});
|
|
1439
|
-
return
|
|
1612
|
+
return decorations;
|
|
1440
1613
|
};
|
|
1441
1614
|
var ImageWidget = class extends WidgetType3 {
|
|
1442
1615
|
constructor(_url) {
|
|
1443
1616
|
super();
|
|
1444
1617
|
this._url = _url;
|
|
1445
1618
|
}
|
|
1446
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1447
1619
|
eq(other) {
|
|
1448
1620
|
return this._url === other._url;
|
|
1449
1621
|
}
|
|
@@ -1451,22 +1623,29 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1451
1623
|
const img = document.createElement("img");
|
|
1452
1624
|
img.setAttribute("src", this._url);
|
|
1453
1625
|
img.setAttribute("class", "cm-image");
|
|
1626
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1454
1627
|
return img;
|
|
1455
1628
|
}
|
|
1456
1629
|
};
|
|
1457
1630
|
|
|
1458
1631
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1459
|
-
import { syntaxTree as
|
|
1460
|
-
import { RangeSetBuilder as RangeSetBuilder2
|
|
1461
|
-
import {
|
|
1632
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1633
|
+
import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
|
|
1634
|
+
import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1462
1635
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1463
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1464
1636
|
var link = (options = {}) => {
|
|
1465
1637
|
const extensions = [
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
|
|
1638
|
+
ViewPlugin5.fromClass(class {
|
|
1639
|
+
constructor(view) {
|
|
1640
|
+
this.decorations = buildDecorations3(view, options);
|
|
1641
|
+
}
|
|
1642
|
+
update(update2) {
|
|
1643
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1644
|
+
this.decorations = buildDecorations3(update2.view, options);
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
}, {
|
|
1648
|
+
decorations: (v) => v.decorations
|
|
1470
1649
|
})
|
|
1471
1650
|
];
|
|
1472
1651
|
if (options.onHover) {
|
|
@@ -1474,35 +1653,25 @@ var link = (options = {}) => {
|
|
|
1474
1653
|
// https://codemirror.net/examples/tooltip
|
|
1475
1654
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1476
1655
|
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1477
|
-
hoverTooltip2((view, pos) => {
|
|
1478
|
-
const
|
|
1479
|
-
|
|
1480
|
-
let
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
match = void 0;
|
|
1486
|
-
break;
|
|
1487
|
-
}
|
|
1488
|
-
idx = text.indexOf(match[0]);
|
|
1489
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1490
|
-
break;
|
|
1491
|
-
}
|
|
1492
|
-
idx += match[0].length;
|
|
1493
|
-
} while (true);
|
|
1494
|
-
if (!match) {
|
|
1656
|
+
hoverTooltip2((view, pos, side) => {
|
|
1657
|
+
const syntax = syntaxTree3(view.state).resolveInner(pos, side);
|
|
1658
|
+
let link2 = null;
|
|
1659
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1660
|
+
link2 = node.name === "Link" ? node : null;
|
|
1661
|
+
}
|
|
1662
|
+
const url = link2 && link2.getChild("URL");
|
|
1663
|
+
if (!url || !link2) {
|
|
1495
1664
|
return null;
|
|
1496
1665
|
}
|
|
1497
|
-
const
|
|
1666
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1498
1667
|
return {
|
|
1499
|
-
pos:
|
|
1500
|
-
end:
|
|
1668
|
+
pos: link2.from,
|
|
1669
|
+
end: link2.to,
|
|
1501
1670
|
above: true,
|
|
1502
1671
|
create: () => {
|
|
1503
1672
|
const el = document.createElement("div");
|
|
1504
1673
|
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1505
|
-
options.onHover(el,
|
|
1674
|
+
options.onHover(el, urlText);
|
|
1506
1675
|
return {
|
|
1507
1676
|
dom: el,
|
|
1508
1677
|
offset: {
|
|
@@ -1518,14 +1687,13 @@ var link = (options = {}) => {
|
|
|
1518
1687
|
return extensions;
|
|
1519
1688
|
};
|
|
1520
1689
|
var LinkButton = class extends WidgetType4 {
|
|
1521
|
-
constructor(
|
|
1690
|
+
constructor(_url, _onAttach) {
|
|
1522
1691
|
super();
|
|
1523
|
-
this._pos = _pos;
|
|
1524
1692
|
this._url = _url;
|
|
1525
1693
|
this._onAttach = _onAttach;
|
|
1526
1694
|
}
|
|
1527
1695
|
eq(other) {
|
|
1528
|
-
return this.
|
|
1696
|
+
return this._url === other._url;
|
|
1529
1697
|
}
|
|
1530
1698
|
toDOM(view) {
|
|
1531
1699
|
const el = document.createElement("span");
|
|
@@ -1562,74 +1730,77 @@ var LinkText = class extends WidgetType4 {
|
|
|
1562
1730
|
return link2;
|
|
1563
1731
|
}
|
|
1564
1732
|
};
|
|
1565
|
-
var
|
|
1733
|
+
var buildDecorations3 = (view, options) => {
|
|
1566
1734
|
const builder = new RangeSetBuilder2();
|
|
1735
|
+
const { state } = view;
|
|
1567
1736
|
const cursor = state.selection.main.head;
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1737
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1738
|
+
syntaxTree3(state).iterate({
|
|
1739
|
+
enter: (node) => {
|
|
1740
|
+
if (node.name === "Link") {
|
|
1741
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
1742
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1743
|
+
const urlNode = node.node.getChild("URL");
|
|
1744
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1745
|
+
if (!url) {
|
|
1746
|
+
return false;
|
|
1747
|
+
}
|
|
1748
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1749
|
+
builder.add(node.from, node.to, Decoration6.replace({
|
|
1750
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
1751
|
+
}));
|
|
1752
|
+
}
|
|
1753
|
+
if (options.onRender) {
|
|
1754
|
+
builder.add(node.to, node.to, Decoration6.replace({
|
|
1755
|
+
widget: new LinkButton(url, options.onRender)
|
|
1756
|
+
}));
|
|
1757
|
+
}
|
|
1576
1758
|
return false;
|
|
1577
1759
|
}
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1582
|
-
|
|
1583
|
-
if (options.onRender) {
|
|
1584
|
-
builder.add(node.to, node.to, Decoration5.replace({
|
|
1585
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1586
|
-
}));
|
|
1587
|
-
}
|
|
1588
|
-
return false;
|
|
1589
|
-
}
|
|
1590
|
-
}
|
|
1591
|
-
});
|
|
1760
|
+
},
|
|
1761
|
+
from,
|
|
1762
|
+
to
|
|
1763
|
+
});
|
|
1764
|
+
}
|
|
1592
1765
|
return builder.finish();
|
|
1593
1766
|
};
|
|
1594
1767
|
|
|
1595
1768
|
// packages/ui/react-ui-editor/src/extensions/listener.ts
|
|
1596
|
-
import { EditorView as
|
|
1769
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
1597
1770
|
var listener = ({ onFocus, onChange }) => {
|
|
1598
1771
|
const extensions = [];
|
|
1599
|
-
onFocus && extensions.push(
|
|
1772
|
+
onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
|
|
1600
1773
|
onFocus(focused);
|
|
1601
1774
|
return null;
|
|
1602
1775
|
}));
|
|
1603
|
-
onChange && extensions.push(
|
|
1604
|
-
onChange(
|
|
1776
|
+
onChange && extensions.push(EditorView9.updateListener.of((update2) => {
|
|
1777
|
+
onChange(update2.state.doc.toString());
|
|
1605
1778
|
}));
|
|
1606
1779
|
return extensions;
|
|
1607
1780
|
};
|
|
1608
1781
|
|
|
1609
1782
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1610
1783
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1611
|
-
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1612
|
-
import { markdownLanguage as
|
|
1784
|
+
import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1785
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1613
1786
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1614
1787
|
import { languages } from "@codemirror/language-data";
|
|
1615
1788
|
import { searchKeymap } from "@codemirror/search";
|
|
1616
1789
|
import { EditorState } from "@codemirror/state";
|
|
1617
1790
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
1618
|
-
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as
|
|
1791
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1619
1792
|
|
|
1620
1793
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1621
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1794
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1622
1795
|
import { HighlightStyle } from "@codemirror/language";
|
|
1623
1796
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1624
1797
|
import { Table } from "@lezer/markdown";
|
|
1625
|
-
import get5 from "lodash.get";
|
|
1626
1798
|
var markdownTags = {
|
|
1627
1799
|
Blockquote: Tag.define(),
|
|
1628
1800
|
CodeMark: Tag.define(),
|
|
1629
1801
|
CodeText: Tag.define(),
|
|
1630
1802
|
EmphasisMark: Tag.define(),
|
|
1631
1803
|
HeaderMark: Tag.define(),
|
|
1632
|
-
// HorizontalRule: Tag.define(),
|
|
1633
1804
|
InlineCode: Tag.define(),
|
|
1634
1805
|
LinkLabel: Tag.define(),
|
|
1635
1806
|
LinkReference: Tag.define(),
|
|
@@ -1793,12 +1964,6 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1793
1964
|
],
|
|
1794
1965
|
class: blockquote
|
|
1795
1966
|
},
|
|
1796
|
-
// TODO(burdon): Replace with extension.
|
|
1797
|
-
// {
|
|
1798
|
-
// tag: [markdownTags.HorizontalRule],
|
|
1799
|
-
// class: mx(horizontalRule, readonly && '-indent-[100rem]'),
|
|
1800
|
-
// },
|
|
1801
|
-
// TODO(burdon): Only if being edited.
|
|
1802
1967
|
{
|
|
1803
1968
|
tag: [
|
|
1804
1969
|
markdownTags.TableCell
|
|
@@ -1806,9 +1971,9 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1806
1971
|
class: "font-mono"
|
|
1807
1972
|
}
|
|
1808
1973
|
], {
|
|
1809
|
-
scope:
|
|
1974
|
+
scope: markdownLanguage2,
|
|
1810
1975
|
all: {
|
|
1811
|
-
fontFamily:
|
|
1976
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1812
1977
|
}
|
|
1813
1978
|
});
|
|
1814
1979
|
};
|
|
@@ -1818,17 +1983,17 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1818
1983
|
return [
|
|
1819
1984
|
EditorState.allowMultipleSelections.of(true),
|
|
1820
1985
|
EditorState.tabSize.of(2),
|
|
1821
|
-
|
|
1822
|
-
|
|
1986
|
+
EditorView10.lineWrapping,
|
|
1987
|
+
// https://github.com/codemirror/basic-setup
|
|
1823
1988
|
bracketMatching2(),
|
|
1824
1989
|
closeBrackets2(),
|
|
1825
1990
|
crosshairCursor(),
|
|
1826
1991
|
dropCursor(),
|
|
1827
1992
|
drawSelection2(),
|
|
1828
|
-
|
|
1829
|
-
|
|
1993
|
+
highlightActiveLine2(),
|
|
1994
|
+
history2(),
|
|
1830
1995
|
indentOnInput(),
|
|
1831
|
-
_placeholder
|
|
1996
|
+
_placeholder ? placeholder2(_placeholder) : [],
|
|
1832
1997
|
// Main extension.
|
|
1833
1998
|
// https://github.com/codemirror/lang-markdown
|
|
1834
1999
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -1838,7 +2003,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1838
2003
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1839
2004
|
// https://github.github.com/gfm
|
|
1840
2005
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1841
|
-
base:
|
|
2006
|
+
base: markdownLanguage3,
|
|
1842
2007
|
// Languages for syntax highlighting fenced code blocks.
|
|
1843
2008
|
codeLanguages: languages,
|
|
1844
2009
|
// Parser extensions.
|
|
@@ -1850,34 +2015,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1850
2015
|
// https://github.com/codemirror/theme-one-dark
|
|
1851
2016
|
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
1852
2017
|
// Custom styles.
|
|
1853
|
-
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
2018
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly)),
|
|
2019
|
+
keymap4.of([
|
|
2020
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
2021
|
+
indentWithTab,
|
|
2022
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
2023
|
+
...closeBracketsKeymap,
|
|
2024
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
2025
|
+
...historyKeymap,
|
|
2026
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
2027
|
+
...searchKeymap,
|
|
2028
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
2029
|
+
...standardKeymap
|
|
2030
|
+
])
|
|
2031
|
+
];
|
|
2032
|
+
};
|
|
1868
2033
|
|
|
1869
2034
|
// packages/ui/react-ui-editor/src/extensions/mention.ts
|
|
1870
2035
|
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1871
2036
|
var mention = ({ onSearch }) => {
|
|
1872
2037
|
return autocompletion2({
|
|
2038
|
+
// TODO(burdon): Not working.
|
|
2039
|
+
activateOnTyping: true,
|
|
2040
|
+
// activateOnTypingDelay: 100,
|
|
2041
|
+
// selectOnOpen: true,
|
|
1873
2042
|
closeOnBlur: false,
|
|
2043
|
+
// defaultKeymap: false,
|
|
2044
|
+
icons: false,
|
|
1874
2045
|
override: [
|
|
1875
2046
|
(context) => {
|
|
2047
|
+
console.log(context);
|
|
1876
2048
|
const match = context.matchBefore(/@(\w+)?/);
|
|
1877
2049
|
if (!match || match.from === match.to && !context.explicit) {
|
|
1878
2050
|
return null;
|
|
1879
2051
|
}
|
|
1880
|
-
console.log(match);
|
|
1881
2052
|
return {
|
|
1882
2053
|
from: match.from,
|
|
1883
2054
|
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
@@ -1889,23 +2060,23 @@ var mention = ({ onSearch }) => {
|
|
|
1889
2060
|
});
|
|
1890
2061
|
};
|
|
1891
2062
|
|
|
1892
|
-
// packages/ui/react-ui-editor/src/extensions/
|
|
1893
|
-
var
|
|
2063
|
+
// packages/ui/react-ui-editor/src/extensions/outliner.ts
|
|
2064
|
+
var outliner = (options = {}) => {
|
|
1894
2065
|
return [];
|
|
1895
2066
|
};
|
|
1896
2067
|
|
|
1897
2068
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1898
|
-
import { syntaxTree as
|
|
1899
|
-
import { RangeSetBuilder as RangeSetBuilder3, StateField as
|
|
1900
|
-
import { Decoration as
|
|
2069
|
+
import { syntaxTree as syntaxTree4 } from "@codemirror/language";
|
|
2070
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
|
|
2071
|
+
import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
|
|
1901
2072
|
var table = (options = {}) => {
|
|
1902
|
-
return
|
|
1903
|
-
create: (state) =>
|
|
1904
|
-
update: (_, tr) =>
|
|
1905
|
-
provide: (field) =>
|
|
2073
|
+
return StateField4.define({
|
|
2074
|
+
create: (state) => update(state, options),
|
|
2075
|
+
update: (_, tr) => update(tr.state, options),
|
|
2076
|
+
provide: (field) => EditorView11.decorations.from(field)
|
|
1906
2077
|
});
|
|
1907
2078
|
};
|
|
1908
|
-
var
|
|
2079
|
+
var update = (state, options) => {
|
|
1909
2080
|
const builder = new RangeSetBuilder3();
|
|
1910
2081
|
const cursor = state.selection.main.head;
|
|
1911
2082
|
const tables = [];
|
|
@@ -1914,7 +2085,7 @@ var update3 = (state, options) => {
|
|
|
1914
2085
|
const table2 = getTable();
|
|
1915
2086
|
return table2.rows?.[table2.rows.length - 1];
|
|
1916
2087
|
};
|
|
1917
|
-
|
|
2088
|
+
syntaxTree4(state).iterate({
|
|
1918
2089
|
enter: (node) => {
|
|
1919
2090
|
switch (node.name) {
|
|
1920
2091
|
case "Table": {
|
|
@@ -1946,11 +2117,10 @@ var update3 = (state, options) => {
|
|
|
1946
2117
|
});
|
|
1947
2118
|
tables.forEach((table2) => {
|
|
1948
2119
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1949
|
-
hide && builder.add(table2.from, table2.to,
|
|
1950
|
-
block: true,
|
|
2120
|
+
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
1951
2121
|
widget: new TableWidget(table2)
|
|
1952
2122
|
}));
|
|
1953
|
-
builder.add(table2.from, table2.to,
|
|
2123
|
+
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
1954
2124
|
class: "cm-table"
|
|
1955
2125
|
}));
|
|
1956
2126
|
});
|
|
@@ -1962,7 +2132,7 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1962
2132
|
this._table = _table;
|
|
1963
2133
|
}
|
|
1964
2134
|
eq(other) {
|
|
1965
|
-
return this._table.
|
|
2135
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
1966
2136
|
}
|
|
1967
2137
|
toDOM(view) {
|
|
1968
2138
|
const table2 = document.createElement("table");
|
|
@@ -1988,90 +2158,105 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1988
2158
|
}
|
|
1989
2159
|
return table2;
|
|
1990
2160
|
}
|
|
2161
|
+
ignoreEvent(e) {
|
|
2162
|
+
return !/^mouse/.test(e.type);
|
|
2163
|
+
}
|
|
1991
2164
|
};
|
|
1992
2165
|
|
|
1993
2166
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
1994
|
-
import {
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
2167
|
+
import { syntaxTree as syntaxTree5 } from "@codemirror/language";
|
|
2168
|
+
import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
|
|
2169
|
+
import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
2170
|
+
var styles5 = EditorView12.baseTheme({
|
|
2171
|
+
"& .cm-task": {
|
|
2172
|
+
color: getToken("extend.colors.blue.500")
|
|
2173
|
+
},
|
|
2174
|
+
"& .cm-task-checkbox": {
|
|
2175
|
+
marginLeft: "4px",
|
|
2176
|
+
marginRight: "4px"
|
|
1999
2177
|
}
|
|
2000
2178
|
});
|
|
2001
2179
|
var CheckboxWidget = class extends WidgetType6 {
|
|
2002
|
-
constructor(
|
|
2180
|
+
constructor(_checked) {
|
|
2003
2181
|
super();
|
|
2004
|
-
this._pos = _pos;
|
|
2005
2182
|
this._checked = _checked;
|
|
2006
|
-
this._indent = _indent;
|
|
2007
|
-
this._onCheck = _onCheck;
|
|
2008
2183
|
}
|
|
2009
2184
|
eq(other) {
|
|
2010
|
-
return this.
|
|
2185
|
+
return this._checked === other._checked;
|
|
2011
2186
|
}
|
|
2012
2187
|
toDOM(view) {
|
|
2013
|
-
const
|
|
2014
|
-
|
|
2015
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
2016
|
-
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
2017
|
-
const input = wrap.appendChild(document.createElement("input"));
|
|
2188
|
+
const input = document.createElement("input");
|
|
2189
|
+
input.className = "cm-task-checkbox";
|
|
2018
2190
|
input.type = "checkbox";
|
|
2019
2191
|
input.checked = this._checked;
|
|
2020
|
-
if (
|
|
2192
|
+
if (view.state.readOnly) {
|
|
2021
2193
|
input.setAttribute("disabled", "true");
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2194
|
+
} else {
|
|
2195
|
+
input.onmousedown = (event) => {
|
|
2196
|
+
const pos = view.posAtDOM(input);
|
|
2197
|
+
const text = view.state.sliceDoc(pos, pos + 3);
|
|
2198
|
+
if (text === (this._checked ? "[x]" : "[ ]")) {
|
|
2199
|
+
view.dispatch({
|
|
2200
|
+
changes: {
|
|
2201
|
+
from: pos + 1,
|
|
2202
|
+
to: pos + 2,
|
|
2203
|
+
insert: this._checked ? " " : "x"
|
|
2204
|
+
}
|
|
2205
|
+
});
|
|
2206
|
+
event.preventDefault();
|
|
2207
|
+
}
|
|
2027
2208
|
};
|
|
2028
2209
|
}
|
|
2029
|
-
return
|
|
2210
|
+
return input;
|
|
2030
2211
|
}
|
|
2031
2212
|
ignoreEvent() {
|
|
2032
2213
|
return false;
|
|
2033
2214
|
}
|
|
2034
2215
|
};
|
|
2216
|
+
var checkedDecoration = Decoration8.replace({
|
|
2217
|
+
widget: new CheckboxWidget(true)
|
|
2218
|
+
});
|
|
2219
|
+
var uncheckedDecoration = Decoration8.replace({
|
|
2220
|
+
widget: new CheckboxWidget(false)
|
|
2221
|
+
});
|
|
2222
|
+
var buildDecorations4 = (view) => {
|
|
2223
|
+
const builder = new RangeSetBuilder4();
|
|
2224
|
+
const { state } = view;
|
|
2225
|
+
const cursor = state.selection.main.head;
|
|
2226
|
+
for (const { from, to } of view.visibleRanges) {
|
|
2227
|
+
syntaxTree5(state).iterate({
|
|
2228
|
+
enter: (node) => {
|
|
2229
|
+
if (node.name === "TaskMarker") {
|
|
2230
|
+
if (cursor < node.from || cursor > node.to) {
|
|
2231
|
+
const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
|
|
2232
|
+
builder.add(node.from - 2, node.from - 1, Decoration8.mark({
|
|
2233
|
+
class: "cm-task"
|
|
2234
|
+
}));
|
|
2235
|
+
builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2238
|
+
},
|
|
2239
|
+
from,
|
|
2240
|
+
to
|
|
2241
|
+
});
|
|
2242
|
+
}
|
|
2243
|
+
return builder.finish();
|
|
2244
|
+
};
|
|
2035
2245
|
var tasklist = (options = {}) => {
|
|
2036
|
-
const taskMatcher = new MatchDecorator3({
|
|
2037
|
-
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
2038
|
-
decoration: (match, view, pos) => {
|
|
2039
|
-
const indent = Math.floor(match[1].length / 2);
|
|
2040
|
-
const checked = match[2] === "x" || match[2] === "X";
|
|
2041
|
-
return Decoration7.replace({
|
|
2042
|
-
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2043
|
-
const idx = pos + match[0].indexOf("[") + 1;
|
|
2044
|
-
view.dispatch({
|
|
2045
|
-
changes: {
|
|
2046
|
-
from: idx,
|
|
2047
|
-
to: idx + 1,
|
|
2048
|
-
insert: checked2 ? "x" : " "
|
|
2049
|
-
},
|
|
2050
|
-
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
2051
|
-
selection: {
|
|
2052
|
-
anchor: idx + 3
|
|
2053
|
-
}
|
|
2054
|
-
});
|
|
2055
|
-
})
|
|
2056
|
-
});
|
|
2057
|
-
}
|
|
2058
|
-
});
|
|
2059
|
-
const tasks = ViewPlugin5.fromClass(class {
|
|
2060
|
-
constructor(view) {
|
|
2061
|
-
this.tasks = taskMatcher.createDeco(view);
|
|
2062
|
-
}
|
|
2063
|
-
update(update4) {
|
|
2064
|
-
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
2065
|
-
}
|
|
2066
|
-
}, {
|
|
2067
|
-
decorations: (value) => value.tasks,
|
|
2068
|
-
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2069
|
-
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
2070
|
-
})
|
|
2071
|
-
});
|
|
2072
2246
|
return [
|
|
2073
|
-
|
|
2074
|
-
|
|
2247
|
+
ViewPlugin6.fromClass(class {
|
|
2248
|
+
constructor(view) {
|
|
2249
|
+
this.decorations = buildDecorations4(view);
|
|
2250
|
+
}
|
|
2251
|
+
update(update2) {
|
|
2252
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
2253
|
+
this.decorations = buildDecorations4(update2.view);
|
|
2254
|
+
}
|
|
2255
|
+
}
|
|
2256
|
+
}, {
|
|
2257
|
+
decorations: (v) => v.decorations
|
|
2258
|
+
}),
|
|
2259
|
+
styles5
|
|
2075
2260
|
];
|
|
2076
2261
|
};
|
|
2077
2262
|
|
|
@@ -2132,8 +2317,29 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2132
2317
|
];
|
|
2133
2318
|
};
|
|
2134
2319
|
|
|
2320
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2321
|
+
import { yCollab } from "y-codemirror.next";
|
|
2322
|
+
|
|
2323
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2324
|
+
import * as Y from "yjs";
|
|
2325
|
+
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2326
|
+
var cursorConverter2 = (text) => ({
|
|
2327
|
+
toCursor: (index, assoc) => {
|
|
2328
|
+
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2329
|
+
},
|
|
2330
|
+
fromCursor: (cursor) => {
|
|
2331
|
+
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2332
|
+
}
|
|
2333
|
+
});
|
|
2334
|
+
|
|
2335
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2336
|
+
var yjs = (content, awareness2) => [
|
|
2337
|
+
Cursor.converter.of(cursorConverter2(content)),
|
|
2338
|
+
yCollab(content, awareness2)
|
|
2339
|
+
];
|
|
2340
|
+
|
|
2135
2341
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2136
|
-
import
|
|
2342
|
+
import get3 from "lodash.get";
|
|
2137
2343
|
var defaultTheme = {
|
|
2138
2344
|
//
|
|
2139
2345
|
// Main layout:
|
|
@@ -2162,21 +2368,21 @@ var defaultTheme = {
|
|
|
2162
2368
|
"&.cm-focused": {
|
|
2163
2369
|
outline: "none"
|
|
2164
2370
|
},
|
|
2165
|
-
"
|
|
2371
|
+
".cm-scroller": {
|
|
2166
2372
|
overflow: "visible",
|
|
2167
|
-
fontFamily:
|
|
2373
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2168
2374
|
},
|
|
2169
|
-
"
|
|
2375
|
+
".cm-content": {
|
|
2170
2376
|
padding: 0,
|
|
2171
2377
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2172
2378
|
fontSize: "16px"
|
|
2173
2379
|
},
|
|
2174
2380
|
"&light .cm-content": {
|
|
2175
|
-
color:
|
|
2381
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2176
2382
|
caretColor: "black"
|
|
2177
2383
|
},
|
|
2178
2384
|
"&dark .cm-content": {
|
|
2179
|
-
color:
|
|
2385
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2180
2386
|
caretColor: "white"
|
|
2181
2387
|
},
|
|
2182
2388
|
//
|
|
@@ -2188,158 +2394,120 @@ var defaultTheme = {
|
|
|
2188
2394
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2189
2395
|
borderLeft: "2px solid white"
|
|
2190
2396
|
},
|
|
2191
|
-
"
|
|
2397
|
+
".cm-placeholder": {
|
|
2192
2398
|
fontWeight: 100
|
|
2193
2399
|
},
|
|
2194
2400
|
//
|
|
2195
2401
|
// line
|
|
2196
2402
|
//
|
|
2197
|
-
"
|
|
2403
|
+
".cm-line": {
|
|
2198
2404
|
paddingInline: 0
|
|
2199
2405
|
},
|
|
2200
|
-
"
|
|
2406
|
+
".cm-activeLine": {
|
|
2201
2407
|
background: "inherit"
|
|
2202
2408
|
},
|
|
2203
2409
|
//
|
|
2204
2410
|
// Selection
|
|
2205
2411
|
//
|
|
2206
2412
|
"&light .cm-selectionBackground": {
|
|
2207
|
-
background:
|
|
2413
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2208
2414
|
},
|
|
2209
2415
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2210
|
-
background:
|
|
2416
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2211
2417
|
},
|
|
2212
2418
|
"&dark .cm-selectionBackground": {
|
|
2213
|
-
background:
|
|
2419
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2214
2420
|
},
|
|
2215
2421
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2216
|
-
background:
|
|
2422
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2217
2423
|
},
|
|
2218
2424
|
//
|
|
2219
2425
|
// Search
|
|
2220
2426
|
//
|
|
2221
|
-
"&light .cm-searchMatch": {
|
|
2222
|
-
backgroundColor:
|
|
2223
|
-
},
|
|
2224
|
-
"&dark .cm-searchMatch": {
|
|
2225
|
-
backgroundColor: get6(tokens, "extend.colors.yellow.700")
|
|
2226
|
-
},
|
|
2227
|
-
//
|
|
2228
|
-
// collaboration
|
|
2229
|
-
// TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
|
|
2230
|
-
//
|
|
2231
|
-
"&light .cm-ySelection, &light .cm-yLineSelection": {
|
|
2232
|
-
mixBlendMode: "multiply"
|
|
2233
|
-
},
|
|
2234
|
-
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2235
|
-
mixBlendMode: "screen"
|
|
2236
|
-
},
|
|
2237
|
-
"& .cm-ySelectionInfo": {
|
|
2238
|
-
padding: "2px 4px",
|
|
2239
|
-
marginBlockStart: "-4px"
|
|
2240
|
-
},
|
|
2241
|
-
"& .cm-ySelection, & .cm-selectionMatch": {
|
|
2242
|
-
paddingBlockStart: ".15em",
|
|
2243
|
-
paddingBlockEnd: ".15em"
|
|
2244
|
-
},
|
|
2245
|
-
"& .cm-ySelectionCaret": {
|
|
2246
|
-
display: "inline-block",
|
|
2247
|
-
insetBlockStart: ".1em",
|
|
2248
|
-
blockSize: "1.4em",
|
|
2249
|
-
verticalAlign: "top"
|
|
2427
|
+
"&light .cm-searchMatch": {
|
|
2428
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2250
2429
|
},
|
|
2251
|
-
"& .cm-
|
|
2252
|
-
|
|
2430
|
+
"&dark .cm-searchMatch": {
|
|
2431
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2253
2432
|
},
|
|
2254
2433
|
//
|
|
2255
2434
|
// link
|
|
2256
2435
|
//
|
|
2257
|
-
"
|
|
2258
|
-
color:
|
|
2436
|
+
".cm-link": {
|
|
2437
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2259
2438
|
textDecorationLine: "underline",
|
|
2260
2439
|
textDecorationThickness: "1px",
|
|
2261
2440
|
textUnderlineOffset: "2px",
|
|
2262
2441
|
borderRadius: ".125rem",
|
|
2263
|
-
fontFamily:
|
|
2442
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2264
2443
|
},
|
|
2265
2444
|
//
|
|
2266
2445
|
// tooltip
|
|
2267
2446
|
//
|
|
2268
|
-
"
|
|
2447
|
+
".cm-tooltip": {
|
|
2269
2448
|
border: "none"
|
|
2270
2449
|
},
|
|
2271
|
-
"
|
|
2450
|
+
".cm-tooltip-below": {},
|
|
2272
2451
|
//
|
|
2273
2452
|
// autocomplete
|
|
2274
2453
|
//
|
|
2275
|
-
"
|
|
2454
|
+
".cm-tooltip-autocomplete": {
|
|
2276
2455
|
marginTop: "4px",
|
|
2277
2456
|
marginLeft: "-3px"
|
|
2278
2457
|
},
|
|
2279
|
-
"
|
|
2280
|
-
"
|
|
2281
|
-
"
|
|
2458
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2459
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2460
|
+
".cm-completionIcon": {
|
|
2282
2461
|
display: "none"
|
|
2283
2462
|
},
|
|
2284
|
-
"
|
|
2285
|
-
fontFamily:
|
|
2463
|
+
".cm-completionLabel": {
|
|
2464
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2286
2465
|
},
|
|
2287
|
-
"
|
|
2466
|
+
".cm-completionMatchedText": {
|
|
2288
2467
|
textDecoration: "none"
|
|
2289
2468
|
},
|
|
2290
2469
|
//
|
|
2291
|
-
// widgets
|
|
2292
|
-
//
|
|
2293
|
-
"& .cm-widgetBuffer": {
|
|
2294
|
-
display: "none",
|
|
2295
|
-
height: 0
|
|
2296
|
-
},
|
|
2297
|
-
//
|
|
2298
2470
|
// table
|
|
2299
2471
|
//
|
|
2300
|
-
"
|
|
2301
|
-
fontFamily: `${
|
|
2472
|
+
".cm-table *": {
|
|
2473
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2302
2474
|
textDecoration: "none !important"
|
|
2303
2475
|
},
|
|
2304
|
-
"
|
|
2476
|
+
".cm-table-head": {
|
|
2305
2477
|
padding: "2px 16px 2px 0px",
|
|
2306
|
-
borderBottom: `1px solid ${
|
|
2478
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2307
2479
|
fontWeight: 100,
|
|
2308
2480
|
textAlign: "left",
|
|
2309
|
-
color:
|
|
2481
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2310
2482
|
},
|
|
2311
|
-
"
|
|
2483
|
+
".cm-table-cell": {
|
|
2312
2484
|
padding: "2px 16px 2px 0px"
|
|
2313
2485
|
},
|
|
2314
2486
|
//
|
|
2315
2487
|
// image
|
|
2316
2488
|
//
|
|
2317
|
-
"
|
|
2318
|
-
|
|
2489
|
+
".cm-image": {
|
|
2490
|
+
display: "block",
|
|
2491
|
+
height: "0"
|
|
2492
|
+
},
|
|
2493
|
+
".cm-image.cm-loaded-image": {
|
|
2494
|
+
height: "auto",
|
|
2495
|
+
borderTop: "0.5rem solid transparent",
|
|
2496
|
+
borderBottom: "0.5rem solid transparent"
|
|
2319
2497
|
},
|
|
2320
2498
|
//
|
|
2321
2499
|
// font size
|
|
2322
|
-
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2500
|
+
// TODO(thure): This appears to be the best or only way to set selection caret heights,
|
|
2501
|
+
// but it's far more verbose than it needs to be.
|
|
2323
2502
|
//
|
|
2324
|
-
...Object.keys(
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
|
|
2333
|
-
height
|
|
2334
|
-
};
|
|
2335
|
-
acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
|
|
2336
|
-
height
|
|
2337
|
-
};
|
|
2338
|
-
acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
|
|
2339
|
-
height
|
|
2340
|
-
};
|
|
2341
|
-
return acc;
|
|
2342
|
-
}, {}),
|
|
2503
|
+
// ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
|
|
2504
|
+
// const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
|
|
2505
|
+
//
|
|
2506
|
+
// acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
|
|
2507
|
+
// acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
|
|
2508
|
+
// acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
|
|
2509
|
+
// return acc;
|
|
2510
|
+
// }, {}),
|
|
2343
2511
|
/**
|
|
2344
2512
|
* Panels
|
|
2345
2513
|
* TODO(burdon): Needs styling attention (esp. dark mode).
|
|
@@ -2356,144 +2524,141 @@ var defaultTheme = {
|
|
|
2356
2524
|
* </div>
|
|
2357
2525
|
* </div
|
|
2358
2526
|
*/
|
|
2359
|
-
"
|
|
2360
|
-
border: `1px solid ${
|
|
2527
|
+
".cm-panels": {
|
|
2528
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2361
2529
|
},
|
|
2362
|
-
"
|
|
2363
|
-
background:
|
|
2364
|
-
fontFamily:
|
|
2530
|
+
".cm-panel": {
|
|
2531
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2532
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2365
2533
|
},
|
|
2366
|
-
"
|
|
2534
|
+
".cm-button": {
|
|
2367
2535
|
margin: "4px",
|
|
2368
|
-
fontFamily:
|
|
2369
|
-
background:
|
|
2536
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2537
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2370
2538
|
backgroundImage: "none",
|
|
2371
2539
|
border: "none",
|
|
2372
2540
|
"&:hover": {
|
|
2373
|
-
background:
|
|
2541
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2374
2542
|
},
|
|
2375
2543
|
"&:active": {
|
|
2376
|
-
background:
|
|
2544
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2377
2545
|
backgroundImage: "none"
|
|
2378
2546
|
}
|
|
2379
2547
|
},
|
|
2380
|
-
"
|
|
2548
|
+
".cm-panel input[type=checkbox]": {
|
|
2381
2549
|
marginRight: "0.4rem !important"
|
|
2382
2550
|
}
|
|
2383
2551
|
};
|
|
2384
2552
|
var textTheme = {
|
|
2385
|
-
"
|
|
2386
|
-
fontFamily:
|
|
2553
|
+
".cm-scroller": {
|
|
2554
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2387
2555
|
},
|
|
2388
|
-
"
|
|
2389
|
-
fontFamily:
|
|
2556
|
+
".cm-placeholder": {
|
|
2557
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2390
2558
|
}
|
|
2391
2559
|
};
|
|
2392
2560
|
var markdownTheme = {
|
|
2393
|
-
|
|
2394
|
-
|
|
2395
|
-
|
|
2561
|
+
".cm-scroller": {
|
|
2562
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2563
|
+
},
|
|
2564
|
+
".cm-placeholder": {
|
|
2565
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2396
2566
|
}
|
|
2397
2567
|
};
|
|
2398
2568
|
var codeTheme = {
|
|
2399
|
-
"
|
|
2400
|
-
fontFamily:
|
|
2569
|
+
".cm-scroller": {
|
|
2570
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2401
2571
|
},
|
|
2402
|
-
"
|
|
2403
|
-
fontFamily:
|
|
2572
|
+
".cm-placeholder": {
|
|
2573
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2404
2574
|
}
|
|
2405
2575
|
};
|
|
2406
2576
|
|
|
2407
2577
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
2578
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
|
|
2408
2579
|
var EditorModes = [
|
|
2409
2580
|
"default",
|
|
2410
2581
|
"vim"
|
|
2411
2582
|
];
|
|
2412
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly,
|
|
2413
|
-
const { themeMode } = useThemeContext();
|
|
2583
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
|
|
2414
2584
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2415
2585
|
tabBehavior: "limited"
|
|
2416
2586
|
});
|
|
2417
|
-
const
|
|
2418
|
-
const
|
|
2419
|
-
|
|
2420
|
-
|
|
2421
|
-
state,
|
|
2587
|
+
const { themeMode } = useThemeContext2();
|
|
2588
|
+
const rootRef = useRef(null);
|
|
2589
|
+
const [view, setView] = useState(null);
|
|
2590
|
+
useImperativeHandle(forwardedRef, () => view, [
|
|
2422
2591
|
view
|
|
2423
|
-
}), [
|
|
2424
|
-
view,
|
|
2425
|
-
state,
|
|
2426
|
-
root
|
|
2427
|
-
]);
|
|
2428
|
-
const { awareness, peer } = model;
|
|
2429
|
-
useEffect2(() => {
|
|
2430
|
-
if (awareness && peer) {
|
|
2431
|
-
awareness.setLocalStateField("user", {
|
|
2432
|
-
name: peer.name ?? generateName(peer.id),
|
|
2433
|
-
color: getColorForValue({
|
|
2434
|
-
value: peer.id,
|
|
2435
|
-
type: "color"
|
|
2436
|
-
}),
|
|
2437
|
-
colorLight: getColorForValue({
|
|
2438
|
-
value: peer.id,
|
|
2439
|
-
themeMode,
|
|
2440
|
-
type: "highlight"
|
|
2441
|
-
})
|
|
2442
|
-
});
|
|
2443
|
-
}
|
|
2444
|
-
}, [
|
|
2445
|
-
awareness,
|
|
2446
|
-
peer,
|
|
2447
|
-
themeMode
|
|
2448
2592
|
]);
|
|
2449
|
-
|
|
2450
|
-
if (
|
|
2451
|
-
view
|
|
2452
|
-
effects: setCommentRange.of({
|
|
2453
|
-
model,
|
|
2454
|
-
comments: comments2
|
|
2455
|
-
})
|
|
2456
|
-
});
|
|
2593
|
+
useEffect3(() => {
|
|
2594
|
+
if (autoFocus) {
|
|
2595
|
+
view?.focus();
|
|
2457
2596
|
}
|
|
2458
2597
|
}, [
|
|
2459
2598
|
view,
|
|
2460
|
-
|
|
2599
|
+
autoFocus
|
|
2461
2600
|
]);
|
|
2462
|
-
|
|
2463
|
-
|
|
2601
|
+
useAwareness(model);
|
|
2602
|
+
useEffect3(() => {
|
|
2603
|
+
if (!model || !rootRef.current) {
|
|
2464
2604
|
return;
|
|
2465
2605
|
}
|
|
2466
|
-
const
|
|
2606
|
+
const state = EditorState2.create({
|
|
2467
2607
|
doc: model.text(),
|
|
2608
|
+
selection,
|
|
2468
2609
|
extensions: [
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
|
|
2610
|
+
// TODO(burdon): Doesn't catch errors in keymap functions.
|
|
2611
|
+
EditorView13.exceptionSink.of((err) => {
|
|
2612
|
+
log2.catch(err, void 0, {
|
|
2613
|
+
F: __dxlog_file5,
|
|
2614
|
+
L: 126,
|
|
2615
|
+
S: void 0,
|
|
2616
|
+
C: (f, a) => f(...a)
|
|
2617
|
+
});
|
|
2618
|
+
}),
|
|
2472
2619
|
// Theme.
|
|
2473
|
-
// TODO(burdon): Make
|
|
2474
|
-
|
|
2475
|
-
|
|
2476
|
-
|
|
2620
|
+
// TODO(burdon): Make configurable.
|
|
2621
|
+
EditorView13.baseTheme(defaultTheme),
|
|
2622
|
+
EditorView13.theme(theme ?? {}),
|
|
2623
|
+
EditorView13.darkTheme.of(themeMode === "dark"),
|
|
2624
|
+
EditorView13.editorAttributes.of({
|
|
2625
|
+
class: slots.editor?.className ?? ""
|
|
2626
|
+
}),
|
|
2627
|
+
EditorView13.contentAttributes.of({
|
|
2628
|
+
class: slots.content?.className ?? ""
|
|
2629
|
+
}),
|
|
2630
|
+
// State.
|
|
2631
|
+
EditorState2.readOnly.of(!!readonly),
|
|
2477
2632
|
// Storage and replication.
|
|
2633
|
+
// NOTE: This must come before user extensions.
|
|
2478
2634
|
model.extension,
|
|
2635
|
+
// TODO(burdon): Factor out (requires special handling for Escape/focus).
|
|
2636
|
+
editorMode === "vim" && vim(),
|
|
2479
2637
|
// Custom.
|
|
2480
2638
|
...extensions
|
|
2481
2639
|
].filter(Boolean)
|
|
2482
2640
|
});
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
|
|
2486
|
-
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2641
|
+
const newView = new EditorView13({
|
|
2642
|
+
state,
|
|
2643
|
+
parent: rootRef.current,
|
|
2644
|
+
scrollTo,
|
|
2645
|
+
// NOTE: Uncomment to debug/monitor all transactions.
|
|
2646
|
+
// https://codemirror.net/docs/ref/#view.EditorView.dispatch
|
|
2647
|
+
dispatchTransactions: (trs, view2) => {
|
|
2648
|
+
if (debug) {
|
|
2649
|
+
logChanges(trs);
|
|
2650
|
+
}
|
|
2651
|
+
view2.update(trs);
|
|
2652
|
+
}
|
|
2490
2653
|
});
|
|
2654
|
+
view?.destroy();
|
|
2655
|
+
setView(newView);
|
|
2491
2656
|
return () => {
|
|
2492
|
-
|
|
2493
|
-
|
|
2657
|
+
newView?.destroy();
|
|
2658
|
+
setView(null);
|
|
2494
2659
|
};
|
|
2495
2660
|
}, [
|
|
2496
|
-
|
|
2661
|
+
rootRef,
|
|
2497
2662
|
model,
|
|
2498
2663
|
readonly,
|
|
2499
2664
|
editorMode,
|
|
@@ -2503,11 +2668,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2503
2668
|
const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
|
|
2504
2669
|
switch (key) {
|
|
2505
2670
|
case "Enter": {
|
|
2506
|
-
view?.
|
|
2671
|
+
view?.focus();
|
|
2507
2672
|
break;
|
|
2508
2673
|
}
|
|
2509
2674
|
case "Escape": {
|
|
2510
|
-
editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)
|
|
2675
|
+
if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
|
|
2676
|
+
rootRef.current?.focus();
|
|
2677
|
+
}
|
|
2511
2678
|
break;
|
|
2512
2679
|
}
|
|
2513
2680
|
}
|
|
@@ -2517,101 +2684,435 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2517
2684
|
]);
|
|
2518
2685
|
return /* @__PURE__ */ React.createElement("div", {
|
|
2519
2686
|
key: model.id,
|
|
2520
|
-
|
|
2687
|
+
role: "none",
|
|
2521
2688
|
tabIndex: 0,
|
|
2522
|
-
|
|
2689
|
+
onKeyUp: handleKeyUp,
|
|
2690
|
+
...slots.root,
|
|
2523
2691
|
...editorMode !== "vim" && tabsterDOMAttribute,
|
|
2524
|
-
|
|
2692
|
+
ref: rootRef
|
|
2525
2693
|
});
|
|
2526
2694
|
});
|
|
2527
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2528
|
-
const { themeMode } =
|
|
2529
|
-
const
|
|
2695
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2696
|
+
const { themeMode } = useThemeContext2();
|
|
2697
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
|
|
2530
2698
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2531
2699
|
ref: forwardedRef,
|
|
2532
2700
|
readonly,
|
|
2533
2701
|
extensions: [
|
|
2534
2702
|
basicBundle({
|
|
2535
|
-
readonly,
|
|
2536
2703
|
themeMode,
|
|
2537
|
-
placeholder:
|
|
2704
|
+
placeholder: placeholder3,
|
|
2705
|
+
lineWrapping
|
|
2538
2706
|
}),
|
|
2539
2707
|
...extensions
|
|
2540
2708
|
],
|
|
2541
|
-
|
|
2709
|
+
theme,
|
|
2710
|
+
slots: updatedSlots,
|
|
2542
2711
|
...props
|
|
2543
2712
|
});
|
|
2544
2713
|
});
|
|
2545
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly,
|
|
2546
|
-
const { themeMode } =
|
|
2547
|
-
const
|
|
2714
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
|
|
2715
|
+
const { themeMode } = useThemeContext2();
|
|
2716
|
+
const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
|
|
2548
2717
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
2549
2718
|
ref: forwardedRef,
|
|
2550
2719
|
readonly,
|
|
2551
2720
|
extensions: [
|
|
2552
2721
|
markdownBundle({
|
|
2553
|
-
readonly,
|
|
2554
2722
|
themeMode,
|
|
2555
|
-
|
|
2723
|
+
readonly,
|
|
2724
|
+
placeholder: placeholder3
|
|
2556
2725
|
}),
|
|
2557
2726
|
...extensions
|
|
2558
2727
|
],
|
|
2559
|
-
|
|
2728
|
+
theme,
|
|
2729
|
+
slots: updatedSlots,
|
|
2560
2730
|
...props
|
|
2561
2731
|
});
|
|
2562
2732
|
});
|
|
2563
2733
|
var defaultSlots = {
|
|
2564
2734
|
root: {
|
|
2565
|
-
|
|
2735
|
+
// TODO(burdon): Add focusRing by default/as property?
|
|
2736
|
+
className: mx3("flex flex-col grow overflow-y-auto", inputSurface)
|
|
2737
|
+
},
|
|
2738
|
+
editor: {
|
|
2739
|
+
className: "h-full p-2"
|
|
2566
2740
|
}
|
|
2567
2741
|
};
|
|
2568
2742
|
var defaultTextSlots = {
|
|
2569
|
-
...defaultSlots
|
|
2570
|
-
editor: {
|
|
2571
|
-
theme: textTheme
|
|
2572
|
-
}
|
|
2743
|
+
...defaultSlots
|
|
2573
2744
|
};
|
|
2574
2745
|
var defaultMarkdownSlots = {
|
|
2575
|
-
...defaultSlots
|
|
2576
|
-
|
|
2577
|
-
|
|
2746
|
+
...defaultSlots
|
|
2747
|
+
};
|
|
2748
|
+
|
|
2749
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2750
|
+
import get4 from "lodash.get";
|
|
2751
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2752
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2753
|
+
|
|
2754
|
+
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2755
|
+
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2756
|
+
import { Context as Context2 } from "@dxos/context";
|
|
2757
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2758
|
+
import { log as log3 } from "@dxos/log";
|
|
2759
|
+
var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2760
|
+
var DEBOUNCE_INTERVAL = 100;
|
|
2761
|
+
var SpaceAwarenessProvider = class {
|
|
2762
|
+
constructor(params) {
|
|
2763
|
+
this.remoteStateChange = new Event2();
|
|
2764
|
+
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2765
|
+
this._space = params.space;
|
|
2766
|
+
this._channel = params.channel;
|
|
2767
|
+
this._peerId = params.peerId;
|
|
2768
|
+
this._info = params.info;
|
|
2769
|
+
}
|
|
2770
|
+
open() {
|
|
2771
|
+
this._ctx = new Context2();
|
|
2772
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
2773
|
+
if (this._localState) {
|
|
2774
|
+
await this._space.postMessage(this._channel, {
|
|
2775
|
+
kind: "post",
|
|
2776
|
+
state: this._localState
|
|
2777
|
+
});
|
|
2778
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
2779
|
+
}
|
|
2780
|
+
});
|
|
2781
|
+
const unsubscribe = this._space.listen(this._channel, (message) => {
|
|
2782
|
+
switch (message.payload.kind) {
|
|
2783
|
+
case "query": {
|
|
2784
|
+
this._handleQueryMessage();
|
|
2785
|
+
break;
|
|
2786
|
+
}
|
|
2787
|
+
case "post": {
|
|
2788
|
+
this._handlePostMessage(message.payload);
|
|
2789
|
+
break;
|
|
2790
|
+
}
|
|
2791
|
+
}
|
|
2792
|
+
});
|
|
2793
|
+
this._ctx.onDispose(unsubscribe);
|
|
2794
|
+
void this._space.postMessage(this._channel, {
|
|
2795
|
+
kind: "query"
|
|
2796
|
+
}).catch((err) => {
|
|
2797
|
+
log3.debug("failed to query awareness", {
|
|
2798
|
+
err
|
|
2799
|
+
}, {
|
|
2800
|
+
F: __dxlog_file6,
|
|
2801
|
+
L: 85,
|
|
2802
|
+
S: this,
|
|
2803
|
+
C: (f, a) => f(...a)
|
|
2804
|
+
});
|
|
2805
|
+
});
|
|
2806
|
+
}
|
|
2807
|
+
close() {
|
|
2808
|
+
void this._ctx?.dispose();
|
|
2809
|
+
this._ctx = void 0;
|
|
2810
|
+
this._postTask = void 0;
|
|
2811
|
+
}
|
|
2812
|
+
update(position) {
|
|
2813
|
+
invariant4(this._postTask, void 0, {
|
|
2814
|
+
F: __dxlog_file6,
|
|
2815
|
+
L: 96,
|
|
2816
|
+
S: this,
|
|
2817
|
+
A: [
|
|
2818
|
+
"this._postTask",
|
|
2819
|
+
""
|
|
2820
|
+
]
|
|
2821
|
+
});
|
|
2822
|
+
this._localState = {
|
|
2823
|
+
peerId: this._peerId,
|
|
2824
|
+
position,
|
|
2825
|
+
info: this._info
|
|
2826
|
+
};
|
|
2827
|
+
this._postTask.schedule();
|
|
2828
|
+
}
|
|
2829
|
+
getRemoteStates() {
|
|
2830
|
+
return Array.from(this._remoteStates.values());
|
|
2831
|
+
}
|
|
2832
|
+
_handleQueryMessage() {
|
|
2833
|
+
invariant4(this._postTask, void 0, {
|
|
2834
|
+
F: __dxlog_file6,
|
|
2835
|
+
L: 111,
|
|
2836
|
+
S: this,
|
|
2837
|
+
A: [
|
|
2838
|
+
"this._postTask",
|
|
2839
|
+
""
|
|
2840
|
+
]
|
|
2841
|
+
});
|
|
2842
|
+
this._postTask.schedule();
|
|
2843
|
+
}
|
|
2844
|
+
_handlePostMessage(message) {
|
|
2845
|
+
invariant4(message.kind === "post", void 0, {
|
|
2846
|
+
F: __dxlog_file6,
|
|
2847
|
+
L: 116,
|
|
2848
|
+
S: this,
|
|
2849
|
+
A: [
|
|
2850
|
+
"message.kind === 'post'",
|
|
2851
|
+
""
|
|
2852
|
+
]
|
|
2853
|
+
});
|
|
2854
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
2855
|
+
this.remoteStateChange.emit();
|
|
2856
|
+
}
|
|
2857
|
+
};
|
|
2858
|
+
|
|
2859
|
+
// packages/ui/react-ui-editor/src/hooks/defs.ts
|
|
2860
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
2861
|
+
var modelState = StateField5.define({
|
|
2862
|
+
create: () => void 0,
|
|
2863
|
+
update: (model) => model
|
|
2864
|
+
});
|
|
2865
|
+
|
|
2866
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2867
|
+
var createAutomergeModel = ({ space, identity, text }) => {
|
|
2868
|
+
const obj = text;
|
|
2869
|
+
const doc = getRawDoc(obj, [
|
|
2870
|
+
obj.field
|
|
2871
|
+
]);
|
|
2872
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
2873
|
+
space,
|
|
2874
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
2875
|
+
info: {
|
|
2876
|
+
displayName: identity?.profile?.displayName ?? "",
|
|
2877
|
+
color: cursorColor.color,
|
|
2878
|
+
lightColor: cursorColor.light
|
|
2879
|
+
},
|
|
2880
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
2881
|
+
});
|
|
2882
|
+
const model = {
|
|
2883
|
+
id: obj.id,
|
|
2884
|
+
content: doc,
|
|
2885
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2886
|
+
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
2887
|
+
extension: [
|
|
2888
|
+
modelState.init(() => model),
|
|
2889
|
+
automerge3({
|
|
2890
|
+
handle: doc.handle,
|
|
2891
|
+
path: doc.path
|
|
2892
|
+
}),
|
|
2893
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
2894
|
+
awareness()
|
|
2895
|
+
].filter(isNotNullOrUndefined),
|
|
2896
|
+
peer: identity ? {
|
|
2897
|
+
id: identity.identityKey.toHex(),
|
|
2898
|
+
name: identity.profile?.displayName
|
|
2899
|
+
} : void 0
|
|
2900
|
+
};
|
|
2901
|
+
return model;
|
|
2902
|
+
};
|
|
2903
|
+
|
|
2904
|
+
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2905
|
+
import * as decoding from "lib0/decoding";
|
|
2906
|
+
import * as encoding from "lib0/encoding";
|
|
2907
|
+
import { Observable } from "lib0/observable";
|
|
2908
|
+
import * as YP from "y-protocols/awareness";
|
|
2909
|
+
import { invariant as invariant5 } from "@dxos/invariant";
|
|
2910
|
+
import { log as log4 } from "@dxos/log";
|
|
2911
|
+
var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2912
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
2913
|
+
invariant5(text?.doc && text?.content, void 0, {
|
|
2914
|
+
F: __dxlog_file7,
|
|
2915
|
+
L: 22,
|
|
2916
|
+
S: void 0,
|
|
2917
|
+
A: [
|
|
2918
|
+
"text?.doc && text?.content",
|
|
2919
|
+
""
|
|
2920
|
+
]
|
|
2921
|
+
});
|
|
2922
|
+
const provider = space ? new YAwarenessProvider({
|
|
2923
|
+
space,
|
|
2924
|
+
doc: text.doc,
|
|
2925
|
+
channel: `yjs.awareness.${text.id}`
|
|
2926
|
+
}) : void 0;
|
|
2927
|
+
const model = {
|
|
2928
|
+
id: text.doc.guid,
|
|
2929
|
+
content: text.content,
|
|
2930
|
+
text: () => text.content.toString(),
|
|
2931
|
+
extension: [
|
|
2932
|
+
modelState.init(() => model),
|
|
2933
|
+
yjs(text.content, provider?.awareness)
|
|
2934
|
+
],
|
|
2935
|
+
awareness: provider?.awareness,
|
|
2936
|
+
peer: identity ? {
|
|
2937
|
+
id: identity.identityKey.toHex(),
|
|
2938
|
+
name: identity.profile?.displayName
|
|
2939
|
+
} : void 0
|
|
2940
|
+
};
|
|
2941
|
+
return model;
|
|
2942
|
+
};
|
|
2943
|
+
var messageAwareness = 1;
|
|
2944
|
+
var messageQueryAwareness = 3;
|
|
2945
|
+
var YAwarenessProvider = class extends Observable {
|
|
2946
|
+
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2947
|
+
super();
|
|
2948
|
+
this._space = space;
|
|
2949
|
+
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2950
|
+
this._channel = channel;
|
|
2951
|
+
this._clientId = doc.clientID;
|
|
2952
|
+
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2953
|
+
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2954
|
+
if (typeof window !== "undefined") {
|
|
2955
|
+
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2956
|
+
} else if (typeof process !== "undefined") {
|
|
2957
|
+
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2958
|
+
}
|
|
2959
|
+
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2960
|
+
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2961
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2962
|
+
const encoderAwarenessState = encoding.createEncoder();
|
|
2963
|
+
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2964
|
+
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2965
|
+
this._clientId
|
|
2966
|
+
]));
|
|
2967
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2968
|
+
}
|
|
2969
|
+
get awareness() {
|
|
2970
|
+
return this._awareness;
|
|
2971
|
+
}
|
|
2972
|
+
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2973
|
+
log4("awareness update", {
|
|
2974
|
+
added,
|
|
2975
|
+
updated,
|
|
2976
|
+
removed,
|
|
2977
|
+
origin
|
|
2978
|
+
}, {
|
|
2979
|
+
F: __dxlog_file7,
|
|
2980
|
+
L: 101,
|
|
2981
|
+
S: this,
|
|
2982
|
+
C: (f, a) => f(...a)
|
|
2983
|
+
});
|
|
2984
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
2985
|
+
const encoderAwareness = encoding.createEncoder();
|
|
2986
|
+
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2987
|
+
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2988
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2989
|
+
}
|
|
2990
|
+
_handleSpaceMessage({ payload }) {
|
|
2991
|
+
log4("space message", payload, {
|
|
2992
|
+
F: __dxlog_file7,
|
|
2993
|
+
L: 110,
|
|
2994
|
+
S: this,
|
|
2995
|
+
C: (f, a) => f(...a)
|
|
2996
|
+
});
|
|
2997
|
+
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2998
|
+
const encoder = this._readMessage(data);
|
|
2999
|
+
if (encoder) {
|
|
3000
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
_readMessage(message) {
|
|
3004
|
+
const decoder = decoding.createDecoder(message);
|
|
3005
|
+
const encoder = encoding.createEncoder();
|
|
3006
|
+
const messageType = decoding.readVarUint(decoder);
|
|
3007
|
+
let sendReply = false;
|
|
3008
|
+
switch (messageType) {
|
|
3009
|
+
case messageAwareness: {
|
|
3010
|
+
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
3011
|
+
break;
|
|
3012
|
+
}
|
|
3013
|
+
case messageQueryAwareness: {
|
|
3014
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
3015
|
+
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
3016
|
+
sendReply = true;
|
|
3017
|
+
break;
|
|
3018
|
+
}
|
|
3019
|
+
default: {
|
|
3020
|
+
console.error("Invalid message:", messageType);
|
|
3021
|
+
return encoder;
|
|
3022
|
+
}
|
|
3023
|
+
}
|
|
3024
|
+
if (!sendReply) {
|
|
3025
|
+
return null;
|
|
3026
|
+
}
|
|
3027
|
+
return encoder;
|
|
3028
|
+
}
|
|
3029
|
+
_handleBeforeUnload() {
|
|
3030
|
+
YP.removeAwarenessStates(this._awareness, [
|
|
3031
|
+
this._clientId
|
|
3032
|
+
], "window unload");
|
|
3033
|
+
}
|
|
3034
|
+
};
|
|
3035
|
+
|
|
3036
|
+
// packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
|
|
3037
|
+
import { useState as useState2 } from "react";
|
|
3038
|
+
var useTextEditor = () => {
|
|
3039
|
+
const [view, setView] = useState2(null);
|
|
3040
|
+
return [
|
|
3041
|
+
(ref) => {
|
|
3042
|
+
setView(ref);
|
|
3043
|
+
},
|
|
3044
|
+
view
|
|
3045
|
+
];
|
|
3046
|
+
};
|
|
3047
|
+
|
|
3048
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
3049
|
+
import { useEffect as useEffect4, useState as useState3 } from "react";
|
|
3050
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
3051
|
+
var useTextModel = (props) => {
|
|
3052
|
+
const { identity, space, text } = props;
|
|
3053
|
+
const [model, setModel] = useState3();
|
|
3054
|
+
useEffect4(() => setModel(createModel(props)), [
|
|
3055
|
+
identity,
|
|
3056
|
+
space,
|
|
3057
|
+
text
|
|
3058
|
+
]);
|
|
3059
|
+
return model;
|
|
3060
|
+
};
|
|
3061
|
+
var createModel = (props) => {
|
|
3062
|
+
const { text } = props;
|
|
3063
|
+
if (isAutomergeObject(text)) {
|
|
3064
|
+
return createAutomergeModel(props);
|
|
3065
|
+
} else if (text?.doc) {
|
|
3066
|
+
return createYjsModel(props);
|
|
3067
|
+
} else {
|
|
3068
|
+
return void 0;
|
|
2578
3069
|
}
|
|
2579
3070
|
};
|
|
2580
3071
|
export {
|
|
3072
|
+
AwarenessProvider,
|
|
2581
3073
|
BaseTextEditor,
|
|
3074
|
+
Cursor,
|
|
2582
3075
|
Doc,
|
|
2583
3076
|
EditorModes,
|
|
2584
3077
|
MarkdownEditor,
|
|
3078
|
+
RemoteSelectionsDecorator,
|
|
2585
3079
|
SpaceAwarenessProvider,
|
|
2586
3080
|
TextEditor,
|
|
2587
3081
|
TextKind,
|
|
3082
|
+
YAwarenessProvider,
|
|
2588
3083
|
YText,
|
|
2589
3084
|
YXmlFragment,
|
|
2590
3085
|
autocomplete,
|
|
3086
|
+
automerge3 as automerge,
|
|
3087
|
+
awareness,
|
|
2591
3088
|
basicBundle,
|
|
2592
3089
|
blast,
|
|
3090
|
+
callbackWrapper,
|
|
2593
3091
|
code2 as code,
|
|
2594
3092
|
codeTheme,
|
|
2595
3093
|
comments,
|
|
2596
|
-
|
|
3094
|
+
createAutomergeModel,
|
|
3095
|
+
createYjsModel,
|
|
2597
3096
|
defaultMarkdownSlots,
|
|
2598
3097
|
defaultOptions,
|
|
2599
3098
|
defaultSlots,
|
|
2600
3099
|
defaultTextSlots,
|
|
2601
3100
|
defaultTheme,
|
|
3101
|
+
getToken,
|
|
2602
3102
|
hr,
|
|
2603
3103
|
image,
|
|
2604
3104
|
link,
|
|
2605
3105
|
listener,
|
|
3106
|
+
logChanges,
|
|
2606
3107
|
markdownBundle,
|
|
2607
3108
|
markdownHighlightStyle,
|
|
2608
3109
|
markdownTags,
|
|
2609
3110
|
markdownTagsExtensions,
|
|
2610
3111
|
markdownTheme,
|
|
2611
3112
|
mention,
|
|
2612
|
-
mermaid,
|
|
2613
3113
|
modelState,
|
|
2614
|
-
|
|
3114
|
+
outliner,
|
|
3115
|
+
setComments,
|
|
2615
3116
|
setFocus,
|
|
2616
3117
|
setSelection,
|
|
2617
3118
|
table,
|
|
@@ -2619,6 +3120,10 @@ export {
|
|
|
2619
3120
|
tasklist,
|
|
2620
3121
|
textTheme,
|
|
2621
3122
|
typewriter,
|
|
2622
|
-
|
|
3123
|
+
useAwareness,
|
|
3124
|
+
useComments,
|
|
3125
|
+
useTextEditor,
|
|
3126
|
+
useTextModel,
|
|
3127
|
+
yjs
|
|
2623
3128
|
};
|
|
2624
3129
|
//# sourceMappingURL=index.mjs.map
|