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