@dxos/react-ui-editor 0.3.11-main.0e40963 → 0.3.11-main.162de7b
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 +1599 -1108
- 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 +3 -3
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -0
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/{hooks/automerge → components/TextEditor}/automerge.stories.d.ts +6 -1
- package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +1 -1
- package/dist/types/src/{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 +3 -1
- package/dist/types/src/extensions/comments.d.ts.map +1 -1
- 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 +3 -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 +8 -7
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/hooks/{yjs/space-provider.d.ts → yjs.d.ts} +8 -8
- package/dist/types/src/hooks/yjs.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +2 -0
- package/dist/types/src/index.d.ts.map +1 -1
- package/dist/types/src/styles/cursors.d.ts.map +1 -0
- package/dist/types/src/styles/index.d.ts +1 -0
- package/dist/types/src/styles/index.d.ts.map +1 -1
- package/dist/types/src/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/cursor.d.ts +17 -0
- package/dist/types/src/util/cursor.d.ts.map +1 -0
- package/dist/types/src/util/index.d.ts +3 -0
- package/dist/types/src/util/index.d.ts.map +1 -0
- package/dist/types/src/util/util.d.ts.map +1 -0
- package/package.json +22 -21
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +6 -7
- package/src/components/TextEditor/TextEditor.stories.tsx +13 -0
- package/src/components/TextEditor/TextEditor.tsx +1 -1
- package/src/{hooks/automerge → components/TextEditor}/automerge.stories.tsx +66 -6
- package/src/components/TextEditor/codemirror.stories.ts +3 -2
- package/src/{hooks/yjs → components/TextEditor}/yjs.stories.tsx +1 -1
- package/src/extensions/autocomplete.ts +18 -17
- package/src/extensions/automerge/automerge.ts +94 -0
- package/src/extensions/automerge/cursor.ts +51 -0
- package/src/extensions/automerge/defs.ts +62 -0
- package/src/extensions/automerge/index.ts +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 +316 -0
- package/src/extensions/code.ts +4 -5
- package/src/extensions/comments.ts +44 -15
- package/src/extensions/hr.ts +2 -3
- package/src/extensions/image.ts +38 -20
- package/src/extensions/index.ts +3 -1
- package/src/extensions/link.ts +82 -84
- package/src/extensions/markdown/highlight.ts +3 -4
- package/src/extensions/table.ts +9 -3
- package/src/extensions/tasklist.ts +1 -3
- package/src/extensions/yjs/cursor.ts +21 -0
- package/src/extensions/yjs/index.ts +5 -0
- package/src/{hooks → extensions}/yjs/yjs.test.ts +1 -25
- package/src/extensions/yjs/yjs.ts +16 -0
- package/src/hooks/automerge.ts +52 -0
- package/src/hooks/awareness-provider.ts +120 -0
- package/src/hooks/index.ts +2 -0
- package/src/hooks/useTextModel.ts +19 -93
- package/src/hooks/{yjs/space-provider.ts → yjs.ts} +71 -19
- package/src/index.ts +2 -0
- package/src/styles/index.ts +1 -0
- package/src/styles/tokens.ts +3 -0
- package/src/testing/replicator.ts +10 -15
- package/src/themes/default.ts +39 -33
- package/src/util/cursor.ts +29 -0
- package/src/util/index.ts +6 -0
- package/dist/types/src/extensions/mermaid.d.ts +0 -3
- package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
- package/dist/types/src/extensions/util.d.ts.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/automerge/plugin.ts +0 -134
- 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}/util.d.ts +0 -0
- /package/src/{hooks/yjs → styles}/cursors.ts +0 -0
- /package/src/{extensions → util}/util.ts +0 -0
|
@@ -11,511 +11,288 @@ 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 } 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
89
|
}
|
|
90
|
+
return automerge.getCursorPosition(doc, path.slice(), cursor);
|
|
225
91
|
}
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
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
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
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
|
+
}
|
|
415
275
|
};
|
|
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
276
|
|
|
426
|
-
// packages/ui/react-ui-editor/src/
|
|
427
|
-
import {
|
|
428
|
-
var
|
|
277
|
+
// packages/ui/react-ui-editor/src/util/cursor.ts
|
|
278
|
+
import { Facet } from "@codemirror/state";
|
|
279
|
+
var DEFAULT_CURSOR_CONVERTER = {
|
|
280
|
+
toCursor: (position) => position.toString(),
|
|
281
|
+
fromCursor: (cursor) => parseInt(cursor)
|
|
282
|
+
};
|
|
283
|
+
var CursorConverter = Facet.define({
|
|
284
|
+
combine: (providers) => providers[0] ?? DEFAULT_CURSOR_CONVERTER
|
|
285
|
+
});
|
|
429
286
|
|
|
430
|
-
// packages/ui/react-ui-editor/src/
|
|
431
|
-
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
432
|
-
var styles = EditorView3.baseTheme({
|
|
433
|
-
"& .cm-codeblock": {
|
|
434
|
-
fontFamily: get(tokens, "fontFamily.mono", []).join(",")
|
|
435
|
-
},
|
|
436
|
-
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
437
|
-
background: get(tokens, "extend.colors.neutral.50")
|
|
438
|
-
},
|
|
439
|
-
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
440
|
-
background: get(tokens, "extend.colors.neutral.850")
|
|
441
|
-
},
|
|
442
|
-
'& [aria-readonly="true"] .cm-codeblock': {
|
|
443
|
-
display: "block",
|
|
444
|
-
paddingInline: "4px !important"
|
|
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
|
-
}
|
|
456
|
-
});
|
|
457
|
-
var getLineRange = (lines, from, to) => {
|
|
458
|
-
const start = lines.findIndex((line) => line.from >= from);
|
|
459
|
-
const end = lines.findIndex((line) => line.to >= to);
|
|
460
|
-
return [
|
|
461
|
-
start,
|
|
462
|
-
end
|
|
463
|
-
];
|
|
464
|
-
};
|
|
465
|
-
var code2 = () => {
|
|
466
|
-
const getDecorations = (view) => {
|
|
467
|
-
const decorations = [];
|
|
468
|
-
if (view.state.readOnly) {
|
|
469
|
-
const text = view.state.doc.sliceString(0);
|
|
470
|
-
const matches = text.matchAll(CODE_REGEX);
|
|
471
|
-
const blocks = view.viewportLineBlocks;
|
|
472
|
-
for (const match of matches) {
|
|
473
|
-
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
474
|
-
for (let i = range[0]; i <= range[1]; i++) {
|
|
475
|
-
const block = blocks[i];
|
|
476
|
-
decorations.push(Decoration.line({
|
|
477
|
-
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
478
|
-
}).range(block.from));
|
|
479
|
-
}
|
|
480
|
-
}
|
|
481
|
-
}
|
|
482
|
-
return Decoration.set(decorations);
|
|
483
|
-
};
|
|
484
|
-
return [
|
|
485
|
-
ViewPlugin.fromClass(class {
|
|
486
|
-
constructor(view) {
|
|
487
|
-
this.decorations = getDecorations(view);
|
|
488
|
-
}
|
|
489
|
-
update(update4) {
|
|
490
|
-
if (update4.docChanged || update4.viewportChanged) {
|
|
491
|
-
this.decorations = getDecorations(update4.view);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
}, {
|
|
495
|
-
decorations: (value) => value.decorations
|
|
496
|
-
}),
|
|
497
|
-
styles
|
|
498
|
-
];
|
|
499
|
-
};
|
|
500
|
-
|
|
501
|
-
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
502
|
-
import { StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
|
|
503
|
-
import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin3, WidgetType } from "@codemirror/view";
|
|
504
|
-
import sortBy from "lodash.sortby";
|
|
505
|
-
import { debounce } from "@dxos/async";
|
|
506
|
-
import { invariant as invariant3 } from "@dxos/invariant";
|
|
507
|
-
import { log as log3 } from "@dxos/log";
|
|
508
|
-
import { nonNullable } from "@dxos/util";
|
|
509
|
-
|
|
510
|
-
// packages/ui/react-ui-editor/src/extensions/util.ts
|
|
287
|
+
// packages/ui/react-ui-editor/src/util/util.ts
|
|
511
288
|
import { log } from "@dxos/log";
|
|
512
|
-
var
|
|
289
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
|
|
513
290
|
var callbackWrapper = (fn) => (...args) => {
|
|
514
291
|
try {
|
|
515
292
|
return fn(...args);
|
|
516
293
|
} catch (error) {
|
|
517
294
|
log.catch(error, void 0, {
|
|
518
|
-
F:
|
|
295
|
+
F: __dxlog_file,
|
|
519
296
|
L: 16,
|
|
520
297
|
S: void 0,
|
|
521
298
|
C: (f, a) => f(...a)
|
|
@@ -523,209 +300,14 @@ var callbackWrapper = (fn) => (...args) => {
|
|
|
523
300
|
}
|
|
524
301
|
};
|
|
525
302
|
|
|
526
|
-
// packages/ui/react-ui-editor/src/
|
|
527
|
-
|
|
528
|
-
import get2 from "lodash.get";
|
|
529
|
-
import { useEffect, useState } from "react";
|
|
530
|
-
import { yCollab } from "y-codemirror.next";
|
|
531
|
-
import * as Y from "yjs";
|
|
532
|
-
import { invariant as invariant2 } from "@dxos/invariant";
|
|
533
|
-
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
534
|
-
import { arrayToString, stringToArray } from "@dxos/util";
|
|
535
|
-
|
|
536
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
537
|
-
import { Annotation, Facet, StateEffect, StateField } from "@codemirror/state";
|
|
538
|
-
import { ViewPlugin as ViewPlugin2 } from "@codemirror/view";
|
|
539
|
-
import * as automerge2 from "@dxos/automerge/automerge";
|
|
540
|
-
|
|
541
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/semaphore.ts
|
|
542
|
-
import { next as automerge } from "@dxos/automerge/automerge";
|
|
543
|
-
|
|
544
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/update-automerge.ts
|
|
545
|
-
import { next as am } from "@dxos/automerge/automerge";
|
|
546
|
-
var updateAutomerge = (field, handle, transactions, state) => {
|
|
547
|
-
const { lastHeads, path } = state.field(field);
|
|
548
|
-
let hasChanges = false;
|
|
549
|
-
for (const tr of transactions) {
|
|
550
|
-
tr.changes.iterChanges(() => {
|
|
551
|
-
hasChanges = true;
|
|
552
|
-
});
|
|
553
|
-
}
|
|
554
|
-
if (!hasChanges) {
|
|
555
|
-
return void 0;
|
|
556
|
-
}
|
|
557
|
-
const newHeads = handle.changeAt(lastHeads, (doc) => {
|
|
558
|
-
for (const tr of transactions) {
|
|
559
|
-
tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
|
|
560
|
-
am.splice(doc, path, fromA, toA - fromA, inserted.toString());
|
|
561
|
-
});
|
|
562
|
-
}
|
|
563
|
-
});
|
|
564
|
-
return newHeads ?? void 0;
|
|
565
|
-
};
|
|
566
|
-
|
|
567
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/update-codemirror.ts
|
|
568
|
-
import { ChangeSet } from "@codemirror/state";
|
|
569
|
-
var updateCodeMirror = (view, selection, target, patches) => {
|
|
570
|
-
for (const patch of patches) {
|
|
571
|
-
const changeSpec = handlePatch(patch, target, view.state);
|
|
572
|
-
if (changeSpec != null) {
|
|
573
|
-
const changeSet = ChangeSet.of(changeSpec, view.state.doc.length, "\n");
|
|
574
|
-
selection = selection.map(changeSet, 1);
|
|
575
|
-
view.dispatch({
|
|
576
|
-
changes: changeSet,
|
|
577
|
-
annotations: reconcileAnnotationType.of({})
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
}
|
|
581
|
-
view.dispatch({
|
|
582
|
-
selection,
|
|
583
|
-
annotations: reconcileAnnotationType.of({})
|
|
584
|
-
});
|
|
585
|
-
};
|
|
586
|
-
var handlePatch = (patch, target, state) => {
|
|
587
|
-
if (patch.action === "insert") {
|
|
588
|
-
return handleInsert(target, patch);
|
|
589
|
-
} else if (patch.action === "splice") {
|
|
590
|
-
return handleSplice(target, patch);
|
|
591
|
-
} else if (patch.action === "del") {
|
|
592
|
-
return handleDel(target, patch);
|
|
593
|
-
} else if (patch.action === "put") {
|
|
594
|
-
return handlePut(target, patch, state);
|
|
595
|
-
} else {
|
|
596
|
-
return null;
|
|
597
|
-
}
|
|
598
|
-
};
|
|
599
|
-
var handleInsert = (target, patch) => {
|
|
600
|
-
const index = charPath(target, patch.path);
|
|
601
|
-
if (index == null) {
|
|
602
|
-
return [];
|
|
603
|
-
}
|
|
604
|
-
const text = patch.values.map((v) => v ? v.toString() : "").join("");
|
|
605
|
-
return [
|
|
606
|
-
{
|
|
607
|
-
from: index,
|
|
608
|
-
to: index,
|
|
609
|
-
insert: text
|
|
610
|
-
}
|
|
611
|
-
];
|
|
612
|
-
};
|
|
613
|
-
var handleSplice = (target, patch) => {
|
|
614
|
-
const index = charPath(target, patch.path);
|
|
615
|
-
if (index == null) {
|
|
616
|
-
return [];
|
|
617
|
-
}
|
|
618
|
-
return [
|
|
619
|
-
{
|
|
620
|
-
from: index,
|
|
621
|
-
insert: patch.value
|
|
622
|
-
}
|
|
623
|
-
];
|
|
624
|
-
};
|
|
625
|
-
var handleDel = (target, patch) => {
|
|
626
|
-
const index = charPath(target, patch.path);
|
|
627
|
-
if (index == null) {
|
|
628
|
-
return [];
|
|
629
|
-
}
|
|
630
|
-
const length = patch.length || 1;
|
|
631
|
-
return [
|
|
632
|
-
{
|
|
633
|
-
from: index,
|
|
634
|
-
to: index + length
|
|
635
|
-
}
|
|
636
|
-
];
|
|
637
|
-
};
|
|
638
|
-
var handlePut = (target, patch, state) => {
|
|
639
|
-
const index = charPath(target, [
|
|
640
|
-
...patch.path,
|
|
641
|
-
0
|
|
642
|
-
]);
|
|
643
|
-
if (index == null) {
|
|
644
|
-
return [];
|
|
645
|
-
}
|
|
646
|
-
const length = state.doc.length;
|
|
647
|
-
if (typeof patch.value !== "string") {
|
|
648
|
-
return [];
|
|
649
|
-
}
|
|
650
|
-
return [
|
|
651
|
-
{
|
|
652
|
-
from: 0,
|
|
653
|
-
to: length,
|
|
654
|
-
insert: patch.value
|
|
655
|
-
}
|
|
656
|
-
];
|
|
657
|
-
};
|
|
658
|
-
var charPath = (textPath, candidatePath) => {
|
|
659
|
-
if (candidatePath.length !== textPath.length + 1) {
|
|
660
|
-
return null;
|
|
661
|
-
}
|
|
662
|
-
for (let i = 0; i < textPath.length; i++) {
|
|
663
|
-
if (textPath[i] !== candidatePath[i]) {
|
|
664
|
-
return null;
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
const index = candidatePath[candidatePath.length - 1];
|
|
668
|
-
if (typeof index === "number") {
|
|
669
|
-
return index;
|
|
670
|
-
}
|
|
671
|
-
return null;
|
|
672
|
-
};
|
|
673
|
-
|
|
674
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/semaphore.ts
|
|
675
|
-
var PatchSemaphore = class {
|
|
676
|
-
constructor(field) {
|
|
677
|
-
this._inReconcile = false;
|
|
678
|
-
this._queue = [];
|
|
679
|
-
this.reconcile = (handle, view) => {
|
|
680
|
-
if (this._inReconcile) {
|
|
681
|
-
return;
|
|
682
|
-
}
|
|
683
|
-
this._inReconcile = true;
|
|
684
|
-
const path = getPath(view.state, this._field);
|
|
685
|
-
const oldHeads = getLastHeads(view.state, this._field);
|
|
686
|
-
let selection = view.state.selection;
|
|
687
|
-
const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
|
|
688
|
-
const toInvert = transactions.slice().reverse();
|
|
689
|
-
for (const tx of toInvert) {
|
|
690
|
-
const inverted = tx.changes.invert(tx.startState.doc);
|
|
691
|
-
selection = selection.map(inverted);
|
|
692
|
-
view.dispatch({
|
|
693
|
-
changes: inverted,
|
|
694
|
-
annotations: reconcileAnnotationType.of(true)
|
|
695
|
-
});
|
|
696
|
-
}
|
|
697
|
-
let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
|
|
698
|
-
if (newHeads === null || newHeads === void 0) {
|
|
699
|
-
newHeads = automerge.getHeads(handle.docSync());
|
|
700
|
-
}
|
|
701
|
-
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
702
|
-
updateCodeMirror(view, selection, path, diff);
|
|
703
|
-
view.dispatch({
|
|
704
|
-
effects: updateHeads(newHeads),
|
|
705
|
-
annotations: reconcileAnnotationType.of({})
|
|
706
|
-
});
|
|
707
|
-
this._inReconcile = false;
|
|
708
|
-
};
|
|
709
|
-
if (field !== void 0) {
|
|
710
|
-
this._field = field;
|
|
711
|
-
}
|
|
712
|
-
}
|
|
713
|
-
};
|
|
714
|
-
|
|
715
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
716
|
-
var effectType = StateEffect.define({});
|
|
717
|
-
var updateHeads = (newHeads) => effectType.of({
|
|
718
|
-
newHeads
|
|
719
|
-
});
|
|
720
|
-
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
721
|
-
var getPath = (state, field) => state.field(field).path;
|
|
722
|
-
var semaphoreFacet = Facet.define({
|
|
303
|
+
// packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
|
|
304
|
+
var semaphoreFacet = Facet2.define({
|
|
723
305
|
combine: (values) => values.at(-1)
|
|
724
306
|
});
|
|
725
|
-
var
|
|
307
|
+
var automerge3 = ({ handle, path }) => {
|
|
726
308
|
const stateField = StateField.define({
|
|
727
309
|
create: () => ({
|
|
728
|
-
lastHeads:
|
|
310
|
+
lastHeads: A.getHeads(handle.docSync()),
|
|
729
311
|
unreconciledTransactions: [],
|
|
730
312
|
path: path.slice()
|
|
731
313
|
}),
|
|
@@ -753,16 +335,16 @@ var automergePlugin = (handle, path) => {
|
|
|
753
335
|
}
|
|
754
336
|
});
|
|
755
337
|
const semaphore = new PatchSemaphore(stateField);
|
|
756
|
-
const viewPlugin =
|
|
757
|
-
constructor(
|
|
338
|
+
const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
339
|
+
constructor(_view) {
|
|
340
|
+
this._view = _view;
|
|
758
341
|
this._handleChange = () => {
|
|
759
342
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
760
343
|
};
|
|
761
|
-
this._view = view;
|
|
762
344
|
handle.addListener("change", this._handleChange);
|
|
763
345
|
}
|
|
764
|
-
update(
|
|
765
|
-
if (
|
|
346
|
+
update(update2) {
|
|
347
|
+
if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
|
|
766
348
|
queueMicrotask(() => {
|
|
767
349
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
768
350
|
});
|
|
@@ -774,263 +356,750 @@ var automergePlugin = (handle, path) => {
|
|
|
774
356
|
});
|
|
775
357
|
return {
|
|
776
358
|
extension: [
|
|
777
|
-
|
|
359
|
+
CursorConverter.of(cursorConverter(handle, path)),
|
|
778
360
|
semaphoreFacet.of(semaphore),
|
|
361
|
+
stateField,
|
|
779
362
|
viewPlugin
|
|
780
363
|
]
|
|
781
364
|
};
|
|
782
365
|
};
|
|
783
|
-
var reconcileAnnotationType = Annotation.define();
|
|
784
|
-
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
785
366
|
|
|
786
|
-
// packages/ui/react-ui-editor/src/
|
|
787
|
-
import
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
367
|
+
// packages/ui/react-ui-editor/src/extensions/awareness.ts
|
|
368
|
+
import { Annotation as Annotation2, Facet as Facet3, RangeSet } from "@codemirror/state";
|
|
369
|
+
import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
370
|
+
import { Event } from "@dxos/async";
|
|
371
|
+
import { Context } from "@dxos/context";
|
|
372
|
+
var dummyProvider = {
|
|
373
|
+
remoteStateChange: new Event(),
|
|
374
|
+
open: () => {
|
|
792
375
|
},
|
|
793
|
-
{
|
|
794
|
-
color: "#6eeb83",
|
|
795
|
-
light: "#6eeb8333"
|
|
376
|
+
close: () => {
|
|
796
377
|
},
|
|
797
|
-
{
|
|
798
|
-
color: "#ffbc42",
|
|
799
|
-
light: "#ffbc4233"
|
|
378
|
+
update: () => {
|
|
800
379
|
},
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
380
|
+
getRemoteStates: () => []
|
|
381
|
+
};
|
|
382
|
+
var AwarenessProvider = Facet3.define({
|
|
383
|
+
combine: (providers) => providers[0] ?? dummyProvider
|
|
384
|
+
});
|
|
385
|
+
var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
386
|
+
var awareness = (provider = dummyProvider) => {
|
|
387
|
+
return [
|
|
388
|
+
AwarenessProvider.of(provider),
|
|
389
|
+
ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
|
|
390
|
+
decorations: (value) => value.decorations
|
|
391
|
+
}),
|
|
392
|
+
styles
|
|
393
|
+
];
|
|
394
|
+
};
|
|
395
|
+
var RemoteSelectionsDecorator = class {
|
|
396
|
+
constructor(view) {
|
|
397
|
+
this.decorations = RangeSet.of([]);
|
|
398
|
+
this._ctx = new Context();
|
|
399
|
+
this._lastAnchor = void 0;
|
|
400
|
+
this._lastHead = void 0;
|
|
401
|
+
this._cursorConverter = view.state.facet(CursorConverter);
|
|
402
|
+
this._provider = view.state.facet(AwarenessProvider);
|
|
403
|
+
this._provider.open();
|
|
404
|
+
this._provider.remoteStateChange.on(this._ctx, () => {
|
|
405
|
+
view.dispatch({
|
|
406
|
+
annotations: [
|
|
407
|
+
RemoteSelectionChangedAnnotation.of([])
|
|
408
|
+
]
|
|
409
|
+
});
|
|
410
|
+
});
|
|
411
|
+
}
|
|
412
|
+
destroy() {
|
|
413
|
+
void this._ctx.dispose();
|
|
414
|
+
this._provider.close();
|
|
415
|
+
}
|
|
416
|
+
update(update2) {
|
|
417
|
+
this._updateLocalSelection(update2);
|
|
418
|
+
this._updateRemoteSelections(update2);
|
|
419
|
+
}
|
|
420
|
+
_updateLocalSelection(update2) {
|
|
421
|
+
const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
|
|
422
|
+
const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
|
|
423
|
+
if (this._lastAnchor === anchor && this._lastHead === head) {
|
|
424
|
+
return;
|
|
425
|
+
}
|
|
426
|
+
this._lastAnchor = anchor;
|
|
427
|
+
this._lastHead = head;
|
|
428
|
+
this._provider.update(anchor !== void 0 && head !== void 0 ? {
|
|
429
|
+
anchor: this._cursorConverter.toCursor(anchor),
|
|
430
|
+
head: this._cursorConverter.toCursor(head)
|
|
431
|
+
} : void 0);
|
|
432
|
+
}
|
|
433
|
+
_updateRemoteSelections(update2) {
|
|
434
|
+
const decorations = [];
|
|
435
|
+
const awarenessStates = this._provider.getRemoteStates();
|
|
436
|
+
for (const state of awarenessStates) {
|
|
437
|
+
const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
|
|
438
|
+
const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
|
|
439
|
+
if (anchor == null || head == null) {
|
|
440
|
+
continue;
|
|
441
|
+
}
|
|
442
|
+
const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
|
|
443
|
+
const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
|
|
444
|
+
const startLine = update2.view.state.doc.lineAt(start);
|
|
445
|
+
const endLine = update2.view.state.doc.lineAt(end);
|
|
446
|
+
const color = state.info.color ?? "#30bced";
|
|
447
|
+
const lightColor = state.info.lightColor ?? color + "33";
|
|
448
|
+
if (startLine.number === endLine.number) {
|
|
449
|
+
decorations.push({
|
|
450
|
+
from: start,
|
|
451
|
+
to: end,
|
|
452
|
+
value: Decoration.mark({
|
|
453
|
+
attributes: {
|
|
454
|
+
style: `background-color: ${lightColor}`
|
|
455
|
+
},
|
|
456
|
+
class: "cm-ySelection"
|
|
457
|
+
})
|
|
458
|
+
});
|
|
459
|
+
} else {
|
|
460
|
+
decorations.push({
|
|
461
|
+
from: start,
|
|
462
|
+
to: startLine.from + startLine.length,
|
|
463
|
+
value: Decoration.mark({
|
|
464
|
+
attributes: {
|
|
465
|
+
style: `background-color: ${color}`
|
|
466
|
+
},
|
|
467
|
+
class: "cm-ySelection"
|
|
468
|
+
})
|
|
469
|
+
});
|
|
470
|
+
decorations.push({
|
|
471
|
+
from: endLine.from,
|
|
472
|
+
to: end,
|
|
473
|
+
value: Decoration.mark({
|
|
474
|
+
attributes: {
|
|
475
|
+
style: `background-color: ${color}`
|
|
476
|
+
},
|
|
477
|
+
class: "cm-ySelection"
|
|
478
|
+
})
|
|
479
|
+
});
|
|
480
|
+
for (let i = startLine.number + 1; i < endLine.number; i++) {
|
|
481
|
+
const linePos = update2.view.state.doc.line(i).from;
|
|
482
|
+
decorations.push({
|
|
483
|
+
from: linePos,
|
|
484
|
+
to: linePos,
|
|
485
|
+
value: Decoration.line({
|
|
486
|
+
attributes: {
|
|
487
|
+
style: `background-color: ${color}`,
|
|
488
|
+
class: "cm-yLineSelection"
|
|
489
|
+
}
|
|
490
|
+
})
|
|
491
|
+
});
|
|
492
|
+
}
|
|
493
|
+
}
|
|
494
|
+
decorations.push({
|
|
495
|
+
from: head,
|
|
496
|
+
to: head,
|
|
497
|
+
value: Decoration.widget({
|
|
498
|
+
side: head - anchor > 0 ? -1 : 1,
|
|
499
|
+
block: false,
|
|
500
|
+
widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", color)
|
|
501
|
+
})
|
|
502
|
+
});
|
|
503
|
+
}
|
|
504
|
+
this.decorations = Decoration.set(decorations, true);
|
|
505
|
+
}
|
|
506
|
+
};
|
|
507
|
+
var RemoteCaretWidget = class extends WidgetType {
|
|
508
|
+
constructor(name, color) {
|
|
509
|
+
super();
|
|
510
|
+
this.name = name;
|
|
511
|
+
this.color = color;
|
|
512
|
+
this.name = name;
|
|
513
|
+
this.color = color;
|
|
514
|
+
}
|
|
515
|
+
toDOM() {
|
|
516
|
+
const span = document.createElement("span");
|
|
517
|
+
span.className = "cm-ySelectionCaret";
|
|
518
|
+
span.style.backgroundColor = this.color;
|
|
519
|
+
span.style.borderColor = this.color;
|
|
520
|
+
const dot = document.createElement("div");
|
|
521
|
+
dot.className = "cm-ySelectionCaretDot";
|
|
522
|
+
const info = document.createElement("div");
|
|
523
|
+
info.className = "cm-ySelectionInfo";
|
|
524
|
+
info.innerText = this.name;
|
|
525
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
526
|
+
span.appendChild(dot);
|
|
527
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
528
|
+
span.appendChild(info);
|
|
529
|
+
span.appendChild(document.createTextNode("\u2060"));
|
|
530
|
+
return span;
|
|
531
|
+
}
|
|
532
|
+
eq(widget) {
|
|
533
|
+
return widget.color === this.color;
|
|
534
|
+
}
|
|
535
|
+
compare(widget) {
|
|
536
|
+
return widget.color === this.color;
|
|
537
|
+
}
|
|
538
|
+
updateDOM() {
|
|
539
|
+
return false;
|
|
540
|
+
}
|
|
541
|
+
get estimatedHeight() {
|
|
542
|
+
return -1;
|
|
543
|
+
}
|
|
544
|
+
ignoreEvent() {
|
|
545
|
+
return true;
|
|
546
|
+
}
|
|
547
|
+
};
|
|
548
|
+
var styles = EditorView.baseTheme({
|
|
549
|
+
".cm-ySelection": {},
|
|
550
|
+
".cm-yLineSelection": {
|
|
551
|
+
padding: 0,
|
|
552
|
+
margin: "0px 2px 0px 4px"
|
|
804
553
|
},
|
|
805
|
-
{
|
|
806
|
-
|
|
807
|
-
|
|
554
|
+
".cm-ySelectionCaret": {
|
|
555
|
+
position: "relative",
|
|
556
|
+
borderLeft: "1px solid black",
|
|
557
|
+
borderRight: "1px solid black",
|
|
558
|
+
marginLeft: "-1px",
|
|
559
|
+
marginRight: "-1px",
|
|
560
|
+
boxSizing: "border-box",
|
|
561
|
+
display: "inline"
|
|
808
562
|
},
|
|
809
|
-
{
|
|
810
|
-
|
|
811
|
-
|
|
563
|
+
".cm-ySelectionCaretDot": {
|
|
564
|
+
borderRadius: "50%",
|
|
565
|
+
position: "absolute",
|
|
566
|
+
width: ".4em",
|
|
567
|
+
height: ".4em",
|
|
568
|
+
top: "-.2em",
|
|
569
|
+
left: "-.2em",
|
|
570
|
+
backgroundColor: "inherit",
|
|
571
|
+
transition: "transform .3s ease-in-out",
|
|
572
|
+
boxSizing: "border-box"
|
|
812
573
|
},
|
|
813
|
-
{
|
|
814
|
-
|
|
815
|
-
|
|
574
|
+
".cm-ySelectionCaret:hover > .cm-ySelectionCaretDot": {
|
|
575
|
+
transformOrigin: "bottom center",
|
|
576
|
+
transform: "scale(0)"
|
|
816
577
|
},
|
|
817
|
-
{
|
|
818
|
-
|
|
819
|
-
|
|
578
|
+
".cm-ySelectionInfo": {
|
|
579
|
+
position: "absolute",
|
|
580
|
+
top: "-1.05em",
|
|
581
|
+
left: "-1px",
|
|
582
|
+
fontSize: ".75em",
|
|
583
|
+
fontFamily: "serif",
|
|
584
|
+
fontStyle: "normal",
|
|
585
|
+
fontWeight: "normal",
|
|
586
|
+
lineHeight: "normal",
|
|
587
|
+
userSelect: "none",
|
|
588
|
+
color: "white",
|
|
589
|
+
paddingLeft: "2px",
|
|
590
|
+
paddingRight: "2px",
|
|
591
|
+
zIndex: 101,
|
|
592
|
+
transition: "opacity .3s ease-in-out",
|
|
593
|
+
backgroundColor: "inherit",
|
|
594
|
+
// these should be separate
|
|
595
|
+
opacity: 0,
|
|
596
|
+
transitionDelay: "0s",
|
|
597
|
+
whiteSpace: "nowrap"
|
|
598
|
+
},
|
|
599
|
+
".cm-ySelectionCaret:hover > .cm-ySelectionInfo": {
|
|
600
|
+
opacity: 1,
|
|
601
|
+
transitionDelay: "0s"
|
|
820
602
|
}
|
|
821
|
-
|
|
822
|
-
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
603
|
+
});
|
|
823
604
|
|
|
824
|
-
// packages/ui/react-ui-editor/src/
|
|
825
|
-
import
|
|
826
|
-
import
|
|
827
|
-
import {
|
|
828
|
-
import
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
605
|
+
// packages/ui/react-ui-editor/src/extensions/basic.ts
|
|
606
|
+
import { closeBrackets } from "@codemirror/autocomplete";
|
|
607
|
+
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
608
|
+
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
609
|
+
import { drawSelection, EditorView as EditorView2, placeholder } from "@codemirror/view";
|
|
610
|
+
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
611
|
+
EditorView2.lineWrapping,
|
|
612
|
+
// TODO(burdon): Compare with minimalSetup.
|
|
613
|
+
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
614
|
+
bracketMatching(),
|
|
615
|
+
closeBrackets(),
|
|
616
|
+
drawSelection(),
|
|
617
|
+
_placeholder && placeholder(_placeholder),
|
|
618
|
+
// TODO(burdon): Is this required?
|
|
619
|
+
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
620
|
+
].filter(Boolean);
|
|
621
|
+
|
|
622
|
+
// packages/ui/react-ui-editor/src/extensions/blast.ts
|
|
623
|
+
import { EditorView as EditorView3, keymap as keymap2 } from "@codemirror/view";
|
|
624
|
+
import defaultsDeep from "lodash.defaultsdeep";
|
|
625
|
+
import { invariant } from "@dxos/invariant";
|
|
626
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
|
|
627
|
+
var defaultOptions = {
|
|
628
|
+
effect: 2,
|
|
629
|
+
maxParticles: 200,
|
|
630
|
+
particleGravity: 0.08,
|
|
631
|
+
particleAlphaFadeout: 0.996,
|
|
632
|
+
particleSize: {
|
|
633
|
+
min: 2,
|
|
634
|
+
max: 8
|
|
635
|
+
},
|
|
636
|
+
particleNumRange: {
|
|
637
|
+
min: 5,
|
|
638
|
+
max: 10
|
|
639
|
+
},
|
|
640
|
+
particleVelocityRange: {
|
|
641
|
+
x: [
|
|
642
|
+
-1,
|
|
643
|
+
1
|
|
644
|
+
],
|
|
645
|
+
y: [
|
|
646
|
+
-3.5,
|
|
647
|
+
-1.5
|
|
648
|
+
]
|
|
649
|
+
},
|
|
650
|
+
particleShrinkRate: 0.95,
|
|
651
|
+
shakeIntensity: 5
|
|
652
|
+
};
|
|
653
|
+
var blast = (options = defaultOptions) => {
|
|
654
|
+
let blaster;
|
|
655
|
+
let last = 0;
|
|
656
|
+
const getPoint = (view, pos) => {
|
|
657
|
+
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
658
|
+
const element = document.elementFromPoint(x, y);
|
|
659
|
+
const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
|
|
660
|
+
const point = {
|
|
661
|
+
x: x - left,
|
|
662
|
+
y: y - top
|
|
663
|
+
};
|
|
664
|
+
return {
|
|
665
|
+
element,
|
|
666
|
+
point
|
|
667
|
+
};
|
|
668
|
+
};
|
|
669
|
+
return [
|
|
670
|
+
// Cursor moved.
|
|
671
|
+
EditorView3.updateListener.of((update2) => {
|
|
672
|
+
if (blaster?.node !== update2.view.scrollDOM) {
|
|
673
|
+
if (blaster) {
|
|
674
|
+
blaster.destroy();
|
|
675
|
+
}
|
|
676
|
+
blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
|
|
677
|
+
particleGravity: 0.2,
|
|
678
|
+
particleShrinkRate: 0.995,
|
|
679
|
+
color: () => [
|
|
680
|
+
100 + Math.random() * 100,
|
|
681
|
+
0,
|
|
682
|
+
0
|
|
683
|
+
]
|
|
684
|
+
}, options, defaultOptions));
|
|
685
|
+
blaster.initialize();
|
|
686
|
+
blaster.start();
|
|
687
|
+
} else {
|
|
688
|
+
blaster.resize();
|
|
689
|
+
}
|
|
690
|
+
const current = update2.state.selection.main.head;
|
|
691
|
+
if (current !== last) {
|
|
692
|
+
last = current;
|
|
693
|
+
const { element, point } = getPoint(update2.view, current - 1);
|
|
694
|
+
if (element && point) {
|
|
695
|
+
blaster.spawn({
|
|
696
|
+
element,
|
|
697
|
+
point
|
|
698
|
+
});
|
|
699
|
+
}
|
|
700
|
+
}
|
|
701
|
+
}),
|
|
702
|
+
keymap2.of([
|
|
703
|
+
{
|
|
704
|
+
any: (_, event) => {
|
|
705
|
+
if (blaster) {
|
|
706
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
707
|
+
blaster.shake({
|
|
708
|
+
time: 0.8
|
|
709
|
+
});
|
|
710
|
+
return true;
|
|
711
|
+
}
|
|
712
|
+
}
|
|
713
|
+
return false;
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
])
|
|
717
|
+
];
|
|
718
|
+
};
|
|
719
|
+
var Blaster = class {
|
|
720
|
+
constructor(_node, _options) {
|
|
721
|
+
this._node = _node;
|
|
722
|
+
this._options = _options;
|
|
723
|
+
this._running = false;
|
|
724
|
+
this._shakeTime = 0;
|
|
725
|
+
this._shakeTimeMax = 0;
|
|
726
|
+
this._particles = [];
|
|
727
|
+
this._particlePointer = 0;
|
|
728
|
+
this._lastPoint = {
|
|
729
|
+
x: 0,
|
|
730
|
+
y: 0
|
|
731
|
+
};
|
|
732
|
+
this.shake = throttle(({ time }) => {
|
|
733
|
+
this._shakeTime = this._shakeTimeMax || time;
|
|
734
|
+
this._shakeTimeMax = time;
|
|
735
|
+
}, 100);
|
|
736
|
+
this.spawn = throttle(({ element, point }) => {
|
|
737
|
+
const color = getRGBComponents(element, this._options.color);
|
|
738
|
+
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
739
|
+
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
740
|
+
this._lastPoint = point;
|
|
741
|
+
for (let i = numParticles; i--; i > 0) {
|
|
742
|
+
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
743
|
+
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
744
|
+
}
|
|
745
|
+
}, 100);
|
|
746
|
+
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
856
747
|
}
|
|
857
|
-
get
|
|
858
|
-
return this.
|
|
748
|
+
get node() {
|
|
749
|
+
return this._node;
|
|
859
750
|
}
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
removed,
|
|
865
|
-
origin
|
|
866
|
-
}, {
|
|
867
|
-
F: __dxlog_file3,
|
|
868
|
-
L: 67,
|
|
751
|
+
initialize() {
|
|
752
|
+
invariant(!this._canvas && !this._ctx, void 0, {
|
|
753
|
+
F: __dxlog_file2,
|
|
754
|
+
L: 138,
|
|
869
755
|
S: this,
|
|
870
|
-
|
|
756
|
+
A: [
|
|
757
|
+
"!this._canvas && !this._ctx",
|
|
758
|
+
""
|
|
759
|
+
]
|
|
871
760
|
});
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
761
|
+
this._canvas = document.createElement("canvas");
|
|
762
|
+
this._canvas.id = "code-blast-canvas";
|
|
763
|
+
this._canvas.style.position = "absolute";
|
|
764
|
+
this._canvas.style.zIndex = "0";
|
|
765
|
+
this._canvas.style.pointerEvents = "none";
|
|
766
|
+
this._ctx = this._canvas.getContext("2d");
|
|
767
|
+
const parent = this._node.parentElement?.parentElement;
|
|
768
|
+
parent?.appendChild(this._canvas);
|
|
769
|
+
this.resize();
|
|
877
770
|
}
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
771
|
+
destroy() {
|
|
772
|
+
this.stop();
|
|
773
|
+
if (this._canvas) {
|
|
774
|
+
this._canvas.remove();
|
|
775
|
+
this._canvas = void 0;
|
|
776
|
+
this._ctx = void 0;
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
resize() {
|
|
780
|
+
if (this._node.parentElement && this._canvas) {
|
|
781
|
+
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
782
|
+
this._canvas.style.top = `${y}px`;
|
|
783
|
+
this._canvas.style.left = `${x}px`;
|
|
784
|
+
this._canvas.width = width;
|
|
785
|
+
this._canvas.height = height;
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
start() {
|
|
789
|
+
invariant(this._canvas && this._ctx, void 0, {
|
|
790
|
+
F: __dxlog_file2,
|
|
791
|
+
L: 177,
|
|
882
792
|
S: this,
|
|
883
|
-
|
|
793
|
+
A: [
|
|
794
|
+
"this._canvas && this._ctx",
|
|
795
|
+
""
|
|
796
|
+
]
|
|
884
797
|
});
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
798
|
+
this._running = true;
|
|
799
|
+
this.loop();
|
|
800
|
+
}
|
|
801
|
+
stop() {
|
|
802
|
+
this._running = false;
|
|
803
|
+
this._node.style.transform = "translate(0px, 0px)";
|
|
804
|
+
}
|
|
805
|
+
loop() {
|
|
806
|
+
if (!this._running || !this._canvas || !this._ctx) {
|
|
807
|
+
return;
|
|
889
808
|
}
|
|
809
|
+
this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
|
|
810
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
811
|
+
this._lastTime ??= now;
|
|
812
|
+
const dt = (now - this._lastTime) / 1e3;
|
|
813
|
+
this._lastTime = now;
|
|
814
|
+
if (this._shakeTime > 0) {
|
|
815
|
+
this._shakeTime -= dt;
|
|
816
|
+
const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
|
|
817
|
+
const shakeX = random(-magnitude, magnitude);
|
|
818
|
+
const shakeY = random(-magnitude, magnitude);
|
|
819
|
+
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
820
|
+
}
|
|
821
|
+
this.drawParticles();
|
|
822
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
890
823
|
}
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
switch (messageType) {
|
|
897
|
-
case messageAwareness: {
|
|
898
|
-
awarenessProtocol.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
899
|
-
break;
|
|
900
|
-
}
|
|
901
|
-
case messageQueryAwareness: {
|
|
902
|
-
encoding.writeVarUint(encoder, messageAwareness);
|
|
903
|
-
encoding.writeVarUint8Array(encoder, awarenessProtocol.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
904
|
-
sendReply = true;
|
|
905
|
-
break;
|
|
824
|
+
drawParticles() {
|
|
825
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
826
|
+
const particle = this._particles[i];
|
|
827
|
+
if (!particle) {
|
|
828
|
+
continue;
|
|
906
829
|
}
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
return encoder;
|
|
830
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
831
|
+
continue;
|
|
910
832
|
}
|
|
833
|
+
this._effect.update(this._ctx, particle);
|
|
911
834
|
}
|
|
912
|
-
|
|
913
|
-
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
var Effect = class {
|
|
838
|
+
constructor(_options) {
|
|
839
|
+
this._options = _options;
|
|
840
|
+
}
|
|
841
|
+
};
|
|
842
|
+
var Effect1 = class extends Effect {
|
|
843
|
+
create(x, y, color) {
|
|
844
|
+
return {
|
|
845
|
+
x,
|
|
846
|
+
y: y + 10,
|
|
847
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
848
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
849
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
850
|
+
color,
|
|
851
|
+
alpha: 1
|
|
852
|
+
};
|
|
853
|
+
}
|
|
854
|
+
update(ctx, particle) {
|
|
855
|
+
particle.vy += this._options.particleGravity;
|
|
856
|
+
particle.x += particle.vx;
|
|
857
|
+
particle.y += particle.vy;
|
|
858
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
859
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
860
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
861
|
+
}
|
|
862
|
+
};
|
|
863
|
+
var Effect2 = class extends Effect {
|
|
864
|
+
create(x, y, color) {
|
|
865
|
+
return {
|
|
866
|
+
x,
|
|
867
|
+
y: y + 10,
|
|
868
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
869
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
870
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
871
|
+
color,
|
|
872
|
+
alpha: 1,
|
|
873
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
874
|
+
drag: 0.92,
|
|
875
|
+
wander: 0.15
|
|
876
|
+
};
|
|
877
|
+
}
|
|
878
|
+
update(ctx, particle) {
|
|
879
|
+
particle.vy += this._options.particleGravity;
|
|
880
|
+
particle.x += particle.vx;
|
|
881
|
+
particle.y += particle.vy;
|
|
882
|
+
particle.vx *= particle.drag;
|
|
883
|
+
particle.vy *= particle.drag;
|
|
884
|
+
particle.theta += random(-0.5, 0.5);
|
|
885
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
886
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
887
|
+
particle.size *= this._options.particleShrinkRate;
|
|
888
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
889
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
890
|
+
ctx.beginPath();
|
|
891
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
892
|
+
ctx.fill();
|
|
893
|
+
}
|
|
894
|
+
};
|
|
895
|
+
function throttle(callback, limit) {
|
|
896
|
+
let wait = false;
|
|
897
|
+
return function(...args) {
|
|
898
|
+
if (!wait) {
|
|
899
|
+
callback.apply(this, args);
|
|
900
|
+
wait = true;
|
|
901
|
+
setTimeout(() => {
|
|
902
|
+
wait = false;
|
|
903
|
+
}, limit);
|
|
914
904
|
}
|
|
915
|
-
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
var getRGBComponents = (node, color) => {
|
|
908
|
+
if (typeof color === "function") {
|
|
909
|
+
return color();
|
|
916
910
|
}
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
911
|
+
const bgColor = getComputedStyle(node).color;
|
|
912
|
+
if (bgColor) {
|
|
913
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
914
|
+
if (x) {
|
|
915
|
+
return x;
|
|
916
|
+
}
|
|
917
|
+
}
|
|
918
|
+
return [
|
|
919
|
+
50,
|
|
920
|
+
50,
|
|
921
|
+
50
|
|
922
|
+
];
|
|
923
|
+
};
|
|
924
|
+
var random = (min, max) => {
|
|
925
|
+
if (!max) {
|
|
926
|
+
max = min;
|
|
927
|
+
min = 0;
|
|
928
|
+
}
|
|
929
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
930
|
+
};
|
|
931
|
+
|
|
932
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
933
|
+
import { ViewPlugin as ViewPlugin3, EditorView as EditorView4, Decoration as Decoration2 } from "@codemirror/view";
|
|
934
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
935
|
+
|
|
936
|
+
// packages/ui/react-ui-editor/src/styles/cursors.ts
|
|
937
|
+
import * as random2 from "lib0/random";
|
|
938
|
+
var cursorColors = [
|
|
939
|
+
{
|
|
940
|
+
color: "#30bced",
|
|
941
|
+
light: "#30bced33"
|
|
942
|
+
},
|
|
943
|
+
{
|
|
944
|
+
color: "#6eeb83",
|
|
945
|
+
light: "#6eeb8333"
|
|
946
|
+
},
|
|
947
|
+
{
|
|
948
|
+
color: "#ffbc42",
|
|
949
|
+
light: "#ffbc4233"
|
|
950
|
+
},
|
|
951
|
+
{
|
|
952
|
+
color: "#ecd444",
|
|
953
|
+
light: "#ecd44433"
|
|
954
|
+
},
|
|
955
|
+
{
|
|
956
|
+
color: "#ee6352",
|
|
957
|
+
light: "#ee635233"
|
|
958
|
+
},
|
|
959
|
+
{
|
|
960
|
+
color: "#9ac2c9",
|
|
961
|
+
light: "#9ac2c933"
|
|
962
|
+
},
|
|
963
|
+
{
|
|
964
|
+
color: "#8acb88",
|
|
965
|
+
light: "#8acb8833"
|
|
966
|
+
},
|
|
967
|
+
{
|
|
968
|
+
color: "#1be7ff",
|
|
969
|
+
light: "#1be7ff33"
|
|
921
970
|
}
|
|
971
|
+
];
|
|
972
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
973
|
+
|
|
974
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
975
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
976
|
+
var headings = {
|
|
977
|
+
1: [
|
|
978
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
979
|
+
"-ml-[10px]"
|
|
980
|
+
],
|
|
981
|
+
2: [
|
|
982
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
983
|
+
"-ml-[8px]"
|
|
984
|
+
],
|
|
985
|
+
3: [
|
|
986
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
987
|
+
"-ml-[7px]"
|
|
988
|
+
],
|
|
989
|
+
4: [
|
|
990
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
991
|
+
"-ml-[6px]"
|
|
992
|
+
],
|
|
993
|
+
5: [
|
|
994
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
995
|
+
"-ml-[5px]"
|
|
996
|
+
],
|
|
997
|
+
6: [
|
|
998
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
999
|
+
"-ml-[4px]"
|
|
1000
|
+
]
|
|
1001
|
+
};
|
|
1002
|
+
var heading = (level, readonly) => {
|
|
1003
|
+
const [style, offset] = headings[level];
|
|
1004
|
+
return mx(style, readonly && offset);
|
|
922
1005
|
};
|
|
1006
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
1007
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
1008
|
+
var bold = "font-bold";
|
|
1009
|
+
var italic = "italic";
|
|
1010
|
+
var strikethrough = "line-through";
|
|
1011
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
1012
|
+
var codeMark = "font-mono text-primary-500";
|
|
1013
|
+
var inlineUrl = mx(code, "px-1");
|
|
1014
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
923
1015
|
|
|
924
|
-
// packages/ui/react-ui-editor/src/
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
1016
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
1017
|
+
import get2 from "lodash.get";
|
|
1018
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
1019
|
+
var tokens = tailwindConfig({}).theme;
|
|
1020
|
+
var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
|
|
1021
|
+
|
|
1022
|
+
// packages/ui/react-ui-editor/src/extensions/code.ts
|
|
1023
|
+
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
1024
|
+
var styles2 = EditorView4.baseTheme({
|
|
1025
|
+
"& .cm-codeblock": {
|
|
1026
|
+
fontFamily: getToken("fontFamily.mono", []).join(",")
|
|
1027
|
+
},
|
|
1028
|
+
'&light [aria-readonly="true"] .cm-codeblock': {
|
|
1029
|
+
background: getToken("extend.colors.neutral.50")
|
|
1030
|
+
},
|
|
1031
|
+
'&dark [aria-readonly="true"] .cm-codeblock': {
|
|
1032
|
+
background: getToken("extend.colors.neutral.850")
|
|
1033
|
+
},
|
|
1034
|
+
'& [aria-readonly="true"] .cm-codeblock': {
|
|
1035
|
+
display: "block",
|
|
1036
|
+
paddingInline: "4px !important"
|
|
1037
|
+
},
|
|
1038
|
+
'& [aria-readonly="true"] .cm-codeblock-first': {
|
|
1039
|
+
paddingTop: "4px !important",
|
|
1040
|
+
borderTopLeftRadius: "4px",
|
|
1041
|
+
borderTopRightRadius: "4px"
|
|
1042
|
+
},
|
|
1043
|
+
'& [aria-readonly="true"] .cm-codeblock-last': {
|
|
1044
|
+
paddingBottom: "4px !important",
|
|
1045
|
+
borderBottomLeftRadius: "4px",
|
|
1046
|
+
borderBottomRightRadius: "4px"
|
|
1047
|
+
}
|
|
929
1048
|
});
|
|
930
|
-
var
|
|
931
|
-
const
|
|
932
|
-
const
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
]);
|
|
938
|
-
return model;
|
|
1049
|
+
var getLineRange = (lines, from, to) => {
|
|
1050
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
1051
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
1052
|
+
return [
|
|
1053
|
+
start,
|
|
1054
|
+
end
|
|
1055
|
+
];
|
|
939
1056
|
};
|
|
940
|
-
var
|
|
941
|
-
const
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
|
|
1057
|
+
var code2 = () => {
|
|
1058
|
+
const getDecorations = (view) => {
|
|
1059
|
+
const decorations = [];
|
|
1060
|
+
if (view.state.readOnly) {
|
|
1061
|
+
const text = view.state.doc.sliceString(0);
|
|
1062
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
1063
|
+
const blocks = view.viewportLineBlocks;
|
|
1064
|
+
for (const match of matches) {
|
|
1065
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
1066
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
1067
|
+
const block = blocks[i];
|
|
1068
|
+
decorations.push(Decoration2.line({
|
|
1069
|
+
class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
|
|
1070
|
+
}).range(block.from));
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
947
1073
|
}
|
|
948
|
-
return
|
|
949
|
-
}
|
|
950
|
-
};
|
|
951
|
-
var createYjsModel = ({ identity, space, text }) => {
|
|
952
|
-
invariant2(text?.doc && text?.content, void 0, {
|
|
953
|
-
F: __dxlog_file4,
|
|
954
|
-
L: 97,
|
|
955
|
-
S: void 0,
|
|
956
|
-
A: [
|
|
957
|
-
"text?.doc && text?.content",
|
|
958
|
-
""
|
|
959
|
-
]
|
|
960
|
-
});
|
|
961
|
-
const provider = space ? new SpaceAwarenessProvider({
|
|
962
|
-
space,
|
|
963
|
-
doc: text.doc,
|
|
964
|
-
channel: `yjs.awareness.${text.id}`
|
|
965
|
-
}) : void 0;
|
|
966
|
-
const model = {
|
|
967
|
-
id: text.doc.guid,
|
|
968
|
-
content: text.content,
|
|
969
|
-
text: () => text.content.toString(),
|
|
970
|
-
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
971
|
-
getCursorFromRange: (range) => {
|
|
972
|
-
const from = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
973
|
-
const to = Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
974
|
-
return [
|
|
975
|
-
arrayToString(from),
|
|
976
|
-
arrayToString(to)
|
|
977
|
-
].join(":");
|
|
978
|
-
},
|
|
979
|
-
getRangeFromCursor: (cursor) => {
|
|
980
|
-
invariant2(text.doc, void 0, {
|
|
981
|
-
F: __dxlog_file4,
|
|
982
|
-
L: 113,
|
|
983
|
-
S: void 0,
|
|
984
|
-
A: [
|
|
985
|
-
"text.doc",
|
|
986
|
-
""
|
|
987
|
-
]
|
|
988
|
-
});
|
|
989
|
-
const parts = cursor.split(":");
|
|
990
|
-
const from = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[0])), text.doc);
|
|
991
|
-
const to = Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(parts[1])), text.doc);
|
|
992
|
-
return from && to ? {
|
|
993
|
-
from: from.index,
|
|
994
|
-
to: to.index
|
|
995
|
-
} : void 0;
|
|
996
|
-
},
|
|
997
|
-
extension: [
|
|
998
|
-
yCollab(text.content, provider?.awareness),
|
|
999
|
-
modelState.init(() => model)
|
|
1000
|
-
],
|
|
1001
|
-
awareness: provider?.awareness,
|
|
1002
|
-
peer: identity ? {
|
|
1003
|
-
id: identity.identityKey.toHex(),
|
|
1004
|
-
name: identity.profile?.displayName
|
|
1005
|
-
} : void 0
|
|
1006
|
-
};
|
|
1007
|
-
return model;
|
|
1008
|
-
};
|
|
1009
|
-
var createAutomergeModel = ({ identity, text }) => {
|
|
1010
|
-
const obj = text;
|
|
1011
|
-
const doc = getRawDoc(obj, [
|
|
1012
|
-
obj.field
|
|
1013
|
-
]);
|
|
1014
|
-
const model = {
|
|
1015
|
-
id: obj.id,
|
|
1016
|
-
content: doc,
|
|
1017
|
-
text: () => get2(doc.handle.docSync(), doc.path),
|
|
1018
|
-
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
1019
|
-
extension: [
|
|
1020
|
-
automergePlugin(doc.handle, doc.path),
|
|
1021
|
-
modelState.init(() => model)
|
|
1022
|
-
],
|
|
1023
|
-
peer: identity ? {
|
|
1024
|
-
id: identity.identityKey.toHex(),
|
|
1025
|
-
name: identity.profile?.displayName
|
|
1026
|
-
} : void 0
|
|
1074
|
+
return Decoration2.set(decorations);
|
|
1027
1075
|
};
|
|
1028
|
-
return
|
|
1076
|
+
return [
|
|
1077
|
+
ViewPlugin3.fromClass(class {
|
|
1078
|
+
constructor(view) {
|
|
1079
|
+
this.decorations = getDecorations(view);
|
|
1080
|
+
}
|
|
1081
|
+
update(update2) {
|
|
1082
|
+
if (update2.docChanged || update2.viewportChanged) {
|
|
1083
|
+
this.decorations = getDecorations(update2.view);
|
|
1084
|
+
}
|
|
1085
|
+
}
|
|
1086
|
+
}, {
|
|
1087
|
+
decorations: (value) => value.decorations
|
|
1088
|
+
}),
|
|
1089
|
+
styles2
|
|
1090
|
+
];
|
|
1029
1091
|
};
|
|
1030
1092
|
|
|
1031
1093
|
// packages/ui/react-ui-editor/src/extensions/comments.ts
|
|
1032
|
-
|
|
1033
|
-
|
|
1094
|
+
import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1095
|
+
import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
1096
|
+
import sortBy from "lodash.sortby";
|
|
1097
|
+
import { debounce } from "@dxos/async";
|
|
1098
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1099
|
+
import { log as log2 } from "@dxos/log";
|
|
1100
|
+
import { nonNullable } from "@dxos/util";
|
|
1101
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
|
|
1102
|
+
var styles3 = EditorView5.baseTheme({
|
|
1034
1103
|
"& .cm-bookmark": {
|
|
1035
1104
|
cursor: "pointer",
|
|
1036
1105
|
margin: "4px",
|
|
@@ -1041,28 +1110,44 @@ var styles2 = EditorView4.baseTheme({
|
|
|
1041
1110
|
backgroundColor: "orange"
|
|
1042
1111
|
},
|
|
1043
1112
|
"& .cm-comment": {
|
|
1044
|
-
backgroundColor: "yellow"
|
|
1113
|
+
backgroundColor: getToken("extend.colors.yellow.50")
|
|
1045
1114
|
},
|
|
1046
1115
|
"& .cm-comment-active": {
|
|
1047
|
-
backgroundColor: "
|
|
1116
|
+
backgroundColor: getToken("extend.colors.yellow.100")
|
|
1048
1117
|
}
|
|
1049
1118
|
});
|
|
1050
1119
|
var marks = {
|
|
1051
|
-
highlight:
|
|
1120
|
+
highlight: Decoration3.mark({
|
|
1052
1121
|
class: "cm-comment"
|
|
1053
1122
|
}),
|
|
1054
|
-
highlightActive:
|
|
1123
|
+
highlightActive: Decoration3.mark({
|
|
1055
1124
|
class: "cm-comment-active"
|
|
1056
1125
|
})
|
|
1057
1126
|
};
|
|
1127
|
+
var setFocus = (view, thread) => {
|
|
1128
|
+
const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
|
|
1129
|
+
if (!range) {
|
|
1130
|
+
return;
|
|
1131
|
+
}
|
|
1132
|
+
view.dispatch({
|
|
1133
|
+
effects: setSelection.of({
|
|
1134
|
+
active: thread
|
|
1135
|
+
}),
|
|
1136
|
+
selection: {
|
|
1137
|
+
anchor: range.from
|
|
1138
|
+
},
|
|
1139
|
+
scrollIntoView: true
|
|
1140
|
+
});
|
|
1141
|
+
};
|
|
1058
1142
|
var setCommentRange = StateEffect2.define();
|
|
1059
1143
|
var setSelection = StateEffect2.define();
|
|
1060
1144
|
var setCommentState = StateEffect2.define();
|
|
1061
|
-
var commentsStateField =
|
|
1145
|
+
var commentsStateField = StateField2.define({
|
|
1062
1146
|
create: () => ({
|
|
1063
1147
|
ranges: []
|
|
1064
1148
|
}),
|
|
1065
1149
|
update: (value, tr) => {
|
|
1150
|
+
const cursorConverter3 = tr.state.facet(CursorConverter);
|
|
1066
1151
|
for (const effect of tr.effects) {
|
|
1067
1152
|
if (effect.is(setSelection)) {
|
|
1068
1153
|
return {
|
|
@@ -1071,9 +1156,9 @@ var commentsStateField = StateField3.define({
|
|
|
1071
1156
|
};
|
|
1072
1157
|
}
|
|
1073
1158
|
if (effect.is(setCommentRange)) {
|
|
1074
|
-
const {
|
|
1159
|
+
const { comments: comments2 } = effect.value;
|
|
1075
1160
|
const ranges = comments2.map((comment) => {
|
|
1076
|
-
const range =
|
|
1161
|
+
const range = getRangeFromCursor(cursorConverter3, comment.cursor);
|
|
1077
1162
|
return range && {
|
|
1078
1163
|
...comment,
|
|
1079
1164
|
...range
|
|
@@ -1091,7 +1176,7 @@ var commentsStateField = StateField3.define({
|
|
|
1091
1176
|
return value;
|
|
1092
1177
|
}
|
|
1093
1178
|
});
|
|
1094
|
-
var highlightDecorations =
|
|
1179
|
+
var highlightDecorations = EditorView5.decorations.compute([
|
|
1095
1180
|
commentsStateField
|
|
1096
1181
|
], (state) => {
|
|
1097
1182
|
const { active, ranges } = state.field(commentsStateField);
|
|
@@ -1109,17 +1194,17 @@ var highlightDecorations = EditorView4.decorations.compute([
|
|
|
1109
1194
|
return marks.highlight.range(range.from, range.to);
|
|
1110
1195
|
}
|
|
1111
1196
|
}).filter(nonNullable) ?? [];
|
|
1112
|
-
return
|
|
1197
|
+
return Decoration3.set(decorations);
|
|
1113
1198
|
});
|
|
1114
|
-
var BookmarkWidget = class extends
|
|
1199
|
+
var BookmarkWidget = class extends WidgetType2 {
|
|
1115
1200
|
constructor(_anchor, _id, _handleClick) {
|
|
1116
1201
|
super();
|
|
1117
1202
|
this._anchor = _anchor;
|
|
1118
1203
|
this._id = _id;
|
|
1119
1204
|
this._handleClick = _handleClick;
|
|
1120
|
-
|
|
1121
|
-
F:
|
|
1122
|
-
L:
|
|
1205
|
+
invariant2(this._id, void 0, {
|
|
1206
|
+
F: __dxlog_file3,
|
|
1207
|
+
L: 168,
|
|
1123
1208
|
S: this,
|
|
1124
1209
|
A: [
|
|
1125
1210
|
"this._id",
|
|
@@ -1143,9 +1228,10 @@ var BookmarkWidget = class extends WidgetType {
|
|
|
1143
1228
|
var comments = (options = {}) => {
|
|
1144
1229
|
const handleSelect = debounce((state) => options.onSelect?.(state), 200);
|
|
1145
1230
|
const createCommentThread = (view) => {
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1231
|
+
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1232
|
+
invariant2(options.onCreate, void 0, {
|
|
1233
|
+
F: __dxlog_file3,
|
|
1234
|
+
L: 224,
|
|
1149
1235
|
S: void 0,
|
|
1150
1236
|
A: [
|
|
1151
1237
|
"options.onCreate",
|
|
@@ -1156,8 +1242,7 @@ var comments = (options = {}) => {
|
|
|
1156
1242
|
if (from === to) {
|
|
1157
1243
|
return false;
|
|
1158
1244
|
}
|
|
1159
|
-
const
|
|
1160
|
-
const relPos = model?.getCursorFromRange?.({
|
|
1245
|
+
const relPos = getCursorFromRange(cursorConverter3, {
|
|
1161
1246
|
from,
|
|
1162
1247
|
to
|
|
1163
1248
|
});
|
|
@@ -1189,7 +1274,7 @@ var comments = (options = {}) => {
|
|
|
1189
1274
|
}
|
|
1190
1275
|
return false;
|
|
1191
1276
|
};
|
|
1192
|
-
const bookmarksViewPlugin =
|
|
1277
|
+
const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
|
|
1193
1278
|
static {
|
|
1194
1279
|
// Match markdown footnotes (option).
|
|
1195
1280
|
// https://www.markdownguide.org/extended-syntax/#footnotes
|
|
@@ -1197,7 +1282,7 @@ var comments = (options = {}) => {
|
|
|
1197
1282
|
regexp: /\[\^(\w+)\]/g,
|
|
1198
1283
|
decoration: (match, view, pos) => {
|
|
1199
1284
|
const id = match[1];
|
|
1200
|
-
return
|
|
1285
|
+
return Decoration3.replace({
|
|
1201
1286
|
id,
|
|
1202
1287
|
widget: new BookmarkWidget(pos, id)
|
|
1203
1288
|
});
|
|
@@ -1207,20 +1292,20 @@ var comments = (options = {}) => {
|
|
|
1207
1292
|
constructor(view) {
|
|
1208
1293
|
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
|
|
1209
1294
|
}
|
|
1210
|
-
update(
|
|
1211
|
-
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(
|
|
1295
|
+
update(update2) {
|
|
1296
|
+
this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update2, this.bookmarks);
|
|
1212
1297
|
}
|
|
1213
1298
|
}, {
|
|
1214
1299
|
decorations: (instance) => instance.bookmarks,
|
|
1215
|
-
provide: (plugin) =>
|
|
1216
|
-
return view.plugin(plugin)?.bookmarks ||
|
|
1300
|
+
provide: (plugin) => EditorView5.atomicRanges.of((view) => {
|
|
1301
|
+
return view.plugin(plugin)?.bookmarks || Decoration3.none;
|
|
1217
1302
|
})
|
|
1218
1303
|
});
|
|
1219
1304
|
return [
|
|
1220
1305
|
bookmarksViewPlugin,
|
|
1221
1306
|
commentsStateField,
|
|
1222
1307
|
highlightDecorations,
|
|
1223
|
-
|
|
1308
|
+
styles3,
|
|
1224
1309
|
//
|
|
1225
1310
|
// Keymap.
|
|
1226
1311
|
//
|
|
@@ -1263,37 +1348,28 @@ var comments = (options = {}) => {
|
|
|
1263
1348
|
// Monitor cursor movement and text updates.
|
|
1264
1349
|
// TODO(burdon): Is there a better (finer grained) way to do this?
|
|
1265
1350
|
//
|
|
1266
|
-
|
|
1351
|
+
EditorView5.updateListener.of(({ view, state, changes }) => {
|
|
1352
|
+
const cursorConverter3 = view.state.facet(CursorConverter);
|
|
1267
1353
|
{
|
|
1268
1354
|
let mod = false;
|
|
1269
|
-
const model = state.field(modelState);
|
|
1270
1355
|
const { active, ranges } = state.field(commentsStateField);
|
|
1271
1356
|
changes.iterChanges((from, to, from2, to2) => {
|
|
1272
|
-
invariant3(model, void 0, {
|
|
1273
|
-
F: __dxlog_file5,
|
|
1274
|
-
L: 336,
|
|
1275
|
-
S: void 0,
|
|
1276
|
-
A: [
|
|
1277
|
-
"model",
|
|
1278
|
-
""
|
|
1279
|
-
]
|
|
1280
|
-
});
|
|
1281
1357
|
ranges.forEach((range) => {
|
|
1282
1358
|
if (from2 === to2) {
|
|
1283
|
-
const newRange =
|
|
1359
|
+
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1284
1360
|
if (!newRange || newRange.to - newRange.from === 0) {
|
|
1285
|
-
|
|
1361
|
+
log2.info("deleted comment", {
|
|
1286
1362
|
thread: range.id
|
|
1287
1363
|
}, {
|
|
1288
|
-
F:
|
|
1289
|
-
L:
|
|
1364
|
+
F: __dxlog_file3,
|
|
1365
|
+
L: 358,
|
|
1290
1366
|
S: void 0,
|
|
1291
1367
|
C: (f, a) => f(...a)
|
|
1292
1368
|
});
|
|
1293
1369
|
}
|
|
1294
1370
|
}
|
|
1295
1371
|
if (from <= range.to) {
|
|
1296
|
-
const newRange =
|
|
1372
|
+
const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
|
|
1297
1373
|
Object.assign(range, newRange);
|
|
1298
1374
|
mod = true;
|
|
1299
1375
|
}
|
|
@@ -1342,18 +1418,34 @@ var comments = (options = {}) => {
|
|
|
1342
1418
|
})
|
|
1343
1419
|
];
|
|
1344
1420
|
};
|
|
1421
|
+
var getCursorFromRange = (cursorConverter3, range) => {
|
|
1422
|
+
const from = cursorConverter3.toCursor(range.from);
|
|
1423
|
+
const to = cursorConverter3.toCursor(range.to, -1);
|
|
1424
|
+
return [
|
|
1425
|
+
from,
|
|
1426
|
+
to
|
|
1427
|
+
].join(":");
|
|
1428
|
+
};
|
|
1429
|
+
var getRangeFromCursor = (cursorConverter3, cursor) => {
|
|
1430
|
+
const parts = cursor.split(":");
|
|
1431
|
+
const from = cursorConverter3.fromCursor(parts[0]);
|
|
1432
|
+
const to = cursorConverter3.fromCursor(parts[1]);
|
|
1433
|
+
return from !== void 0 && to !== void 0 ? {
|
|
1434
|
+
from,
|
|
1435
|
+
to
|
|
1436
|
+
} : void 0;
|
|
1437
|
+
};
|
|
1345
1438
|
|
|
1346
1439
|
// packages/ui/react-ui-editor/src/extensions/hr.ts
|
|
1347
|
-
import { Decoration as
|
|
1348
|
-
|
|
1349
|
-
var styles3 = EditorView5.baseTheme({
|
|
1440
|
+
import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1441
|
+
var styles4 = EditorView6.baseTheme({
|
|
1350
1442
|
"& .cm-hr": {
|
|
1351
1443
|
// TODO(burdon): ???
|
|
1352
1444
|
// Note that block-level decorations should not have vertical margins,
|
|
1353
|
-
borderBottom: `1px solid ${
|
|
1445
|
+
borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
|
|
1354
1446
|
}
|
|
1355
1447
|
});
|
|
1356
|
-
var HorizontalRuleWidget = class extends
|
|
1448
|
+
var HorizontalRuleWidget = class extends WidgetType3 {
|
|
1357
1449
|
constructor(_pos) {
|
|
1358
1450
|
super();
|
|
1359
1451
|
this._pos = _pos;
|
|
@@ -1369,41 +1461,63 @@ var HorizontalRuleWidget = class extends WidgetType2 {
|
|
|
1369
1461
|
};
|
|
1370
1462
|
var placeholderMatcher = new MatchDecorator2({
|
|
1371
1463
|
regexp: /^---$/g,
|
|
1372
|
-
decoration: (match, view, pos) =>
|
|
1464
|
+
decoration: (match, view, pos) => Decoration4.replace({
|
|
1373
1465
|
widget: new HorizontalRuleWidget(pos)
|
|
1374
1466
|
})
|
|
1375
1467
|
});
|
|
1376
1468
|
var hr = () => [
|
|
1377
|
-
|
|
1378
|
-
|
|
1469
|
+
styles4,
|
|
1470
|
+
ViewPlugin5.fromClass(class {
|
|
1379
1471
|
constructor(view) {
|
|
1380
1472
|
this.rules = placeholderMatcher.createDeco(view);
|
|
1381
1473
|
}
|
|
1382
|
-
update(
|
|
1383
|
-
this.rules = placeholderMatcher.updateDeco(
|
|
1474
|
+
update(update2) {
|
|
1475
|
+
this.rules = placeholderMatcher.updateDeco(update2, this.rules);
|
|
1384
1476
|
}
|
|
1385
1477
|
}, {
|
|
1386
1478
|
decorations: (instance) => instance.rules,
|
|
1387
1479
|
// TODO(burdon): Is this really atomic (cursor can move into ---).
|
|
1388
|
-
provide: (plugin) =>
|
|
1389
|
-
return view.plugin(plugin)?.rules ||
|
|
1480
|
+
provide: (plugin) => EditorView6.atomicRanges.of((view) => {
|
|
1481
|
+
return view.plugin(plugin)?.rules || Decoration4.none;
|
|
1390
1482
|
})
|
|
1391
1483
|
})
|
|
1392
1484
|
];
|
|
1393
1485
|
|
|
1394
1486
|
// packages/ui/react-ui-editor/src/extensions/image.ts
|
|
1395
1487
|
import { syntaxTree } from "@codemirror/language";
|
|
1396
|
-
import {
|
|
1397
|
-
import { Decoration as
|
|
1488
|
+
import { StateField as StateField3 } from "@codemirror/state";
|
|
1489
|
+
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1398
1490
|
var image = (options = {}) => {
|
|
1399
|
-
return
|
|
1400
|
-
create: (state) =>
|
|
1401
|
-
|
|
1402
|
-
|
|
1491
|
+
return StateField3.define({
|
|
1492
|
+
create: (state) => {
|
|
1493
|
+
return Decoration5.set(buildDecorations(0, state.doc.length, state));
|
|
1494
|
+
},
|
|
1495
|
+
update: (value, tr) => {
|
|
1496
|
+
if (!tr.docChanged && !tr.selection) {
|
|
1497
|
+
return value;
|
|
1498
|
+
}
|
|
1499
|
+
const cursor = tr.state.selection.main.head;
|
|
1500
|
+
const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
|
|
1501
|
+
let from = Math.min(cursor, oldCursor);
|
|
1502
|
+
let to = Math.max(cursor, oldCursor);
|
|
1503
|
+
tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
|
|
1504
|
+
from = Math.min(from, fromB);
|
|
1505
|
+
to = Math.max(to, toB);
|
|
1506
|
+
});
|
|
1507
|
+
from = tr.state.doc.lineAt(from).from;
|
|
1508
|
+
to = tr.state.doc.lineAt(to).to;
|
|
1509
|
+
return value.map(tr.changes).update({
|
|
1510
|
+
filterFrom: from,
|
|
1511
|
+
filterTo: to,
|
|
1512
|
+
filter: () => false,
|
|
1513
|
+
add: buildDecorations(from, to, tr.state)
|
|
1514
|
+
});
|
|
1515
|
+
},
|
|
1516
|
+
provide: (field) => EditorView7.decorations.from(field)
|
|
1403
1517
|
});
|
|
1404
1518
|
};
|
|
1405
|
-
var
|
|
1406
|
-
const
|
|
1519
|
+
var buildDecorations = (from, to, state) => {
|
|
1520
|
+
const decorations = [];
|
|
1407
1521
|
const cursor = state.selection.main.head;
|
|
1408
1522
|
syntaxTree(state).iterate({
|
|
1409
1523
|
enter: (node) => {
|
|
@@ -1412,22 +1526,23 @@ var update = (state, options) => {
|
|
|
1412
1526
|
if (urlNode) {
|
|
1413
1527
|
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
1414
1528
|
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
1415
|
-
|
|
1529
|
+
decorations.push(Decoration5.replace({
|
|
1416
1530
|
block: true,
|
|
1417
1531
|
widget: new ImageWidget(url)
|
|
1418
|
-
}));
|
|
1532
|
+
}).range(hide ? node.from : node.to, node.to));
|
|
1419
1533
|
}
|
|
1420
1534
|
}
|
|
1421
|
-
}
|
|
1535
|
+
},
|
|
1536
|
+
from,
|
|
1537
|
+
to
|
|
1422
1538
|
});
|
|
1423
|
-
return
|
|
1539
|
+
return decorations;
|
|
1424
1540
|
};
|
|
1425
|
-
var ImageWidget = class extends
|
|
1541
|
+
var ImageWidget = class extends WidgetType4 {
|
|
1426
1542
|
constructor(_url) {
|
|
1427
1543
|
super();
|
|
1428
1544
|
this._url = _url;
|
|
1429
1545
|
}
|
|
1430
|
-
// TODO(burdon): Does this need to be unique for each position?
|
|
1431
1546
|
eq(other) {
|
|
1432
1547
|
return this._url === other._url;
|
|
1433
1548
|
}
|
|
@@ -1435,58 +1550,55 @@ var ImageWidget = class extends WidgetType3 {
|
|
|
1435
1550
|
const img = document.createElement("img");
|
|
1436
1551
|
img.setAttribute("src", this._url);
|
|
1437
1552
|
img.setAttribute("class", "cm-image");
|
|
1553
|
+
img.onload = () => img.classList.add("cm-loaded-image");
|
|
1438
1554
|
return img;
|
|
1439
1555
|
}
|
|
1440
1556
|
};
|
|
1441
1557
|
|
|
1442
1558
|
// packages/ui/react-ui-editor/src/extensions/link.ts
|
|
1443
1559
|
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
1444
|
-
import { RangeSetBuilder
|
|
1445
|
-
import { Decoration as
|
|
1560
|
+
import { RangeSetBuilder } from "@codemirror/state";
|
|
1561
|
+
import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
1446
1562
|
import { tooltipContent } from "@dxos/react-ui-theme";
|
|
1447
|
-
var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
|
|
1448
1563
|
var link = (options = {}) => {
|
|
1449
1564
|
const extensions = [
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1565
|
+
ViewPlugin6.fromClass(class {
|
|
1566
|
+
constructor(view) {
|
|
1567
|
+
this.decorations = buildDecorations2(view, options);
|
|
1568
|
+
}
|
|
1569
|
+
update(update2) {
|
|
1570
|
+
if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
|
|
1571
|
+
this.decorations = buildDecorations2(update2.view, options);
|
|
1572
|
+
}
|
|
1573
|
+
}
|
|
1574
|
+
}, {
|
|
1575
|
+
decorations: (v) => v.decorations
|
|
1454
1576
|
})
|
|
1455
1577
|
];
|
|
1456
1578
|
if (options.onHover) {
|
|
1457
1579
|
extensions.push(
|
|
1458
1580
|
// https://codemirror.net/examples/tooltip
|
|
1459
1581
|
// https://codemirror.net/docs/ref/#view.hoverTooltip
|
|
1460
|
-
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1461
|
-
hoverTooltip2((view, pos) => {
|
|
1462
|
-
const
|
|
1463
|
-
|
|
1464
|
-
let
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
|
|
1469
|
-
match = void 0;
|
|
1470
|
-
break;
|
|
1471
|
-
}
|
|
1472
|
-
idx = text.indexOf(match[0]);
|
|
1473
|
-
if (p >= idx && p < idx + match[0].length) {
|
|
1474
|
-
break;
|
|
1475
|
-
}
|
|
1476
|
-
idx += match[0].length;
|
|
1477
|
-
} while (true);
|
|
1478
|
-
if (!match) {
|
|
1582
|
+
// https://github.com/codemirror/view/blob/main/src/tooltip.ts
|
|
1583
|
+
hoverTooltip2((view, pos, side) => {
|
|
1584
|
+
const syntax = syntaxTree2(view.state).resolveInner(pos, side);
|
|
1585
|
+
let link2 = null;
|
|
1586
|
+
for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
|
|
1587
|
+
link2 = node.name === "Link" ? node : null;
|
|
1588
|
+
}
|
|
1589
|
+
const url = link2 && link2.getChild("URL");
|
|
1590
|
+
if (!url || !link2) {
|
|
1479
1591
|
return null;
|
|
1480
1592
|
}
|
|
1481
|
-
const
|
|
1593
|
+
const urlText = view.state.sliceDoc(url.from, url.to);
|
|
1482
1594
|
return {
|
|
1483
|
-
pos:
|
|
1484
|
-
end:
|
|
1595
|
+
pos: link2.from,
|
|
1596
|
+
end: link2.to,
|
|
1485
1597
|
above: true,
|
|
1486
1598
|
create: () => {
|
|
1487
1599
|
const el = document.createElement("div");
|
|
1488
1600
|
el.className = tooltipContent({}, "pli-2 plb-1");
|
|
1489
|
-
options.onHover(el,
|
|
1601
|
+
options.onHover(el, urlText);
|
|
1490
1602
|
return {
|
|
1491
1603
|
dom: el,
|
|
1492
1604
|
offset: {
|
|
@@ -1501,15 +1613,14 @@ var link = (options = {}) => {
|
|
|
1501
1613
|
}
|
|
1502
1614
|
return extensions;
|
|
1503
1615
|
};
|
|
1504
|
-
var LinkButton = class extends
|
|
1505
|
-
constructor(
|
|
1616
|
+
var LinkButton = class extends WidgetType5 {
|
|
1617
|
+
constructor(_url, _onAttach) {
|
|
1506
1618
|
super();
|
|
1507
|
-
this._pos = _pos;
|
|
1508
1619
|
this._url = _url;
|
|
1509
1620
|
this._onAttach = _onAttach;
|
|
1510
1621
|
}
|
|
1511
1622
|
eq(other) {
|
|
1512
|
-
return this.
|
|
1623
|
+
return this._url === other._url;
|
|
1513
1624
|
}
|
|
1514
1625
|
toDOM(view) {
|
|
1515
1626
|
const el = document.createElement("span");
|
|
@@ -1517,7 +1628,7 @@ var LinkButton = class extends WidgetType4 {
|
|
|
1517
1628
|
return el;
|
|
1518
1629
|
}
|
|
1519
1630
|
};
|
|
1520
|
-
var LinkText = class extends
|
|
1631
|
+
var LinkText = class extends WidgetType5 {
|
|
1521
1632
|
constructor(_text, _url) {
|
|
1522
1633
|
super();
|
|
1523
1634
|
this._text = _text;
|
|
@@ -1546,33 +1657,38 @@ var LinkText = class extends WidgetType4 {
|
|
|
1546
1657
|
return link2;
|
|
1547
1658
|
}
|
|
1548
1659
|
};
|
|
1549
|
-
var
|
|
1550
|
-
const builder = new
|
|
1660
|
+
var buildDecorations2 = (view, options) => {
|
|
1661
|
+
const builder = new RangeSetBuilder();
|
|
1662
|
+
const { state } = view;
|
|
1551
1663
|
const cursor = state.selection.main.head;
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1664
|
+
for (const { from, to } of view.visibleRanges) {
|
|
1665
|
+
syntaxTree2(state).iterate({
|
|
1666
|
+
enter: (node) => {
|
|
1667
|
+
if (node.name === "Link") {
|
|
1668
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
1669
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
1670
|
+
const urlNode = node.node.getChild("URL");
|
|
1671
|
+
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
1672
|
+
if (!url) {
|
|
1673
|
+
return false;
|
|
1674
|
+
}
|
|
1675
|
+
if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
|
|
1676
|
+
builder.add(node.from, node.to, Decoration6.replace({
|
|
1677
|
+
widget: new LinkText(text, options.link ? url : void 0)
|
|
1678
|
+
}));
|
|
1679
|
+
}
|
|
1680
|
+
if (options.onRender) {
|
|
1681
|
+
builder.add(node.to, node.to, Decoration6.replace({
|
|
1682
|
+
widget: new LinkButton(url, options.onRender)
|
|
1683
|
+
}));
|
|
1684
|
+
}
|
|
1560
1685
|
return false;
|
|
1561
1686
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
if (options.onRender) {
|
|
1568
|
-
builder.add(node.to, node.to, Decoration5.replace({
|
|
1569
|
-
widget: new LinkButton(node.from, url, options.onRender)
|
|
1570
|
-
}));
|
|
1571
|
-
}
|
|
1572
|
-
return false;
|
|
1573
|
-
}
|
|
1574
|
-
}
|
|
1575
|
-
});
|
|
1687
|
+
},
|
|
1688
|
+
from,
|
|
1689
|
+
to
|
|
1690
|
+
});
|
|
1691
|
+
}
|
|
1576
1692
|
return builder.finish();
|
|
1577
1693
|
};
|
|
1578
1694
|
|
|
@@ -1584,8 +1700,8 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1584
1700
|
onFocus(focused);
|
|
1585
1701
|
return null;
|
|
1586
1702
|
}));
|
|
1587
|
-
onChange && extensions.push(EditorView8.updateListener.of((
|
|
1588
|
-
onChange(
|
|
1703
|
+
onChange && extensions.push(EditorView8.updateListener.of((update2) => {
|
|
1704
|
+
onChange(update2.state.doc.toString());
|
|
1589
1705
|
}));
|
|
1590
1706
|
return extensions;
|
|
1591
1707
|
};
|
|
@@ -1593,7 +1709,7 @@ var listener = ({ onFocus, onChange }) => {
|
|
|
1593
1709
|
// packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
|
|
1594
1710
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
1595
1711
|
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
1596
|
-
import { markdownLanguage as
|
|
1712
|
+
import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
|
|
1597
1713
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
1598
1714
|
import { languages } from "@codemirror/language-data";
|
|
1599
1715
|
import { searchKeymap } from "@codemirror/search";
|
|
@@ -1602,11 +1718,10 @@ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/the
|
|
|
1602
1718
|
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
|
|
1603
1719
|
|
|
1604
1720
|
// packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
|
|
1605
|
-
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
1721
|
+
import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
|
|
1606
1722
|
import { HighlightStyle } from "@codemirror/language";
|
|
1607
1723
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
1608
1724
|
import { Table } from "@lezer/markdown";
|
|
1609
|
-
import get4 from "lodash.get";
|
|
1610
1725
|
var markdownTags = {
|
|
1611
1726
|
Blockquote: Tag.define(),
|
|
1612
1727
|
CodeMark: Tag.define(),
|
|
@@ -1790,9 +1905,9 @@ var markdownHighlightStyle = (readonly) => {
|
|
|
1790
1905
|
class: "font-mono"
|
|
1791
1906
|
}
|
|
1792
1907
|
], {
|
|
1793
|
-
scope:
|
|
1908
|
+
scope: markdownLanguage2,
|
|
1794
1909
|
all: {
|
|
1795
|
-
fontFamily:
|
|
1910
|
+
fontFamily: getToken("fontFamily.body", []).join(",")
|
|
1796
1911
|
}
|
|
1797
1912
|
});
|
|
1798
1913
|
};
|
|
@@ -1822,7 +1937,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
|
1822
1937
|
// NOTE: This extends the parser; it doesn't affect rendering.
|
|
1823
1938
|
// https://github.github.com/gfm
|
|
1824
1939
|
// https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
|
|
1825
|
-
base:
|
|
1940
|
+
base: markdownLanguage3,
|
|
1826
1941
|
// Languages for syntax highlighting fenced code blocks.
|
|
1827
1942
|
codeLanguages: languages,
|
|
1828
1943
|
// Parser extensions.
|
|
@@ -1873,24 +1988,19 @@ var mention = ({ onSearch }) => {
|
|
|
1873
1988
|
});
|
|
1874
1989
|
};
|
|
1875
1990
|
|
|
1876
|
-
// packages/ui/react-ui-editor/src/extensions/mermaid.ts
|
|
1877
|
-
var mermaid = () => {
|
|
1878
|
-
return [];
|
|
1879
|
-
};
|
|
1880
|
-
|
|
1881
1991
|
// packages/ui/react-ui-editor/src/extensions/table.ts
|
|
1882
1992
|
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1883
|
-
import { RangeSetBuilder as
|
|
1884
|
-
import { Decoration as
|
|
1993
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
|
|
1994
|
+
import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType6 } from "@codemirror/view";
|
|
1885
1995
|
var table = (options = {}) => {
|
|
1886
|
-
return
|
|
1887
|
-
create: (state) =>
|
|
1888
|
-
update: (_, tr) =>
|
|
1996
|
+
return StateField4.define({
|
|
1997
|
+
create: (state) => update(state, options),
|
|
1998
|
+
update: (_, tr) => update(tr.state, options),
|
|
1889
1999
|
provide: (field) => EditorView10.decorations.from(field)
|
|
1890
2000
|
});
|
|
1891
2001
|
};
|
|
1892
|
-
var
|
|
1893
|
-
const builder = new
|
|
2002
|
+
var update = (state, options) => {
|
|
2003
|
+
const builder = new RangeSetBuilder2();
|
|
1894
2004
|
const cursor = state.selection.main.head;
|
|
1895
2005
|
const tables = [];
|
|
1896
2006
|
const getTable = () => tables[tables.length - 1];
|
|
@@ -1930,23 +2040,22 @@ var update3 = (state, options) => {
|
|
|
1930
2040
|
});
|
|
1931
2041
|
tables.forEach((table2) => {
|
|
1932
2042
|
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1933
|
-
hide && builder.add(table2.from, table2.to,
|
|
1934
|
-
block: true,
|
|
2043
|
+
hide && builder.add(table2.from, table2.to, Decoration7.replace({
|
|
1935
2044
|
widget: new TableWidget(table2)
|
|
1936
2045
|
}));
|
|
1937
|
-
builder.add(table2.from, table2.to,
|
|
2046
|
+
builder.add(table2.from, table2.to, Decoration7.mark({
|
|
1938
2047
|
class: "cm-table"
|
|
1939
2048
|
}));
|
|
1940
2049
|
});
|
|
1941
2050
|
return builder.finish();
|
|
1942
2051
|
};
|
|
1943
|
-
var TableWidget = class extends
|
|
2052
|
+
var TableWidget = class extends WidgetType6 {
|
|
1944
2053
|
constructor(_table) {
|
|
1945
2054
|
super();
|
|
1946
2055
|
this._table = _table;
|
|
1947
2056
|
}
|
|
1948
2057
|
eq(other) {
|
|
1949
|
-
return this._table.
|
|
2058
|
+
return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
|
|
1950
2059
|
}
|
|
1951
2060
|
toDOM(view) {
|
|
1952
2061
|
const table2 = document.createElement("table");
|
|
@@ -1972,26 +2081,28 @@ var TableWidget = class extends WidgetType5 {
|
|
|
1972
2081
|
}
|
|
1973
2082
|
return table2;
|
|
1974
2083
|
}
|
|
2084
|
+
ignoreEvent(e) {
|
|
2085
|
+
return !/^mouse/.test(e.type);
|
|
2086
|
+
}
|
|
1975
2087
|
};
|
|
1976
2088
|
|
|
1977
2089
|
// packages/ui/react-ui-editor/src/extensions/tasklist.ts
|
|
1978
|
-
import { EditorView as EditorView11, Decoration as
|
|
1979
|
-
var
|
|
2090
|
+
import { EditorView as EditorView11, Decoration as Decoration8, WidgetType as WidgetType7, MatchDecorator as MatchDecorator3, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
|
|
2091
|
+
var styles5 = EditorView11.baseTheme({
|
|
1980
2092
|
"& .cm-task-item": {
|
|
1981
2093
|
paddingLeft: "4px",
|
|
1982
2094
|
paddingRight: "8px"
|
|
1983
2095
|
}
|
|
1984
2096
|
});
|
|
1985
|
-
var CheckboxWidget = class extends
|
|
1986
|
-
constructor(
|
|
2097
|
+
var CheckboxWidget = class extends WidgetType7 {
|
|
2098
|
+
constructor(_checked, _indent, _onCheck) {
|
|
1987
2099
|
super();
|
|
1988
|
-
this._pos = _pos;
|
|
1989
2100
|
this._checked = _checked;
|
|
1990
2101
|
this._indent = _indent;
|
|
1991
2102
|
this._onCheck = _onCheck;
|
|
1992
2103
|
}
|
|
1993
2104
|
eq(other) {
|
|
1994
|
-
return this.
|
|
2105
|
+
return this._checked === other._checked && this._indent === other._indent;
|
|
1995
2106
|
}
|
|
1996
2107
|
toDOM(view) {
|
|
1997
2108
|
const wrap = document.createElement("span");
|
|
@@ -2022,8 +2133,8 @@ var tasklist = (options = {}) => {
|
|
|
2022
2133
|
decoration: (match, view, pos) => {
|
|
2023
2134
|
const indent = Math.floor(match[1].length / 2);
|
|
2024
2135
|
const checked = match[2] === "x" || match[2] === "X";
|
|
2025
|
-
return
|
|
2026
|
-
widget: new CheckboxWidget(
|
|
2136
|
+
return Decoration8.replace({
|
|
2137
|
+
widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
2027
2138
|
const idx = pos + match[0].indexOf("[") + 1;
|
|
2028
2139
|
view.dispatch({
|
|
2029
2140
|
changes: {
|
|
@@ -2040,22 +2151,22 @@ var tasklist = (options = {}) => {
|
|
|
2040
2151
|
});
|
|
2041
2152
|
}
|
|
2042
2153
|
});
|
|
2043
|
-
const tasks =
|
|
2154
|
+
const tasks = ViewPlugin7.fromClass(class {
|
|
2044
2155
|
constructor(view) {
|
|
2045
2156
|
this.tasks = taskMatcher.createDeco(view);
|
|
2046
2157
|
}
|
|
2047
|
-
update(
|
|
2048
|
-
this.tasks = taskMatcher.updateDeco(
|
|
2158
|
+
update(update2) {
|
|
2159
|
+
this.tasks = taskMatcher.updateDeco(update2, this.tasks);
|
|
2049
2160
|
}
|
|
2050
2161
|
}, {
|
|
2051
2162
|
decorations: (value) => value.tasks,
|
|
2052
2163
|
provide: (plugin) => EditorView11.atomicRanges.of((view) => {
|
|
2053
|
-
return view.plugin(plugin)?.tasks ||
|
|
2164
|
+
return view.plugin(plugin)?.tasks || Decoration8.none;
|
|
2054
2165
|
})
|
|
2055
2166
|
});
|
|
2056
2167
|
return [
|
|
2057
2168
|
tasks,
|
|
2058
|
-
|
|
2169
|
+
styles5
|
|
2059
2170
|
];
|
|
2060
2171
|
};
|
|
2061
2172
|
|
|
@@ -2116,8 +2227,29 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
2116
2227
|
];
|
|
2117
2228
|
};
|
|
2118
2229
|
|
|
2230
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2231
|
+
import { yCollab } from "y-codemirror.next";
|
|
2232
|
+
|
|
2233
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
|
|
2234
|
+
import * as Y from "yjs";
|
|
2235
|
+
import { arrayToString, stringToArray } from "@dxos/util";
|
|
2236
|
+
var cursorConverter2 = (text) => ({
|
|
2237
|
+
toCursor: (index, assoc) => {
|
|
2238
|
+
return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
|
|
2239
|
+
},
|
|
2240
|
+
fromCursor: (cursor) => {
|
|
2241
|
+
return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
|
|
2242
|
+
}
|
|
2243
|
+
});
|
|
2244
|
+
|
|
2245
|
+
// packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
|
|
2246
|
+
var yjs = (content, awareness2) => [
|
|
2247
|
+
CursorConverter.of(cursorConverter2(content)),
|
|
2248
|
+
yCollab(content, awareness2)
|
|
2249
|
+
];
|
|
2250
|
+
|
|
2119
2251
|
// packages/ui/react-ui-editor/src/themes/default.ts
|
|
2120
|
-
import
|
|
2252
|
+
import get3 from "lodash.get";
|
|
2121
2253
|
var defaultTheme = {
|
|
2122
2254
|
//
|
|
2123
2255
|
// Main layout:
|
|
@@ -2146,21 +2278,21 @@ var defaultTheme = {
|
|
|
2146
2278
|
"&.cm-focused": {
|
|
2147
2279
|
outline: "none"
|
|
2148
2280
|
},
|
|
2149
|
-
"
|
|
2281
|
+
".cm-scroller": {
|
|
2150
2282
|
overflow: "visible",
|
|
2151
|
-
fontFamily:
|
|
2283
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2152
2284
|
},
|
|
2153
|
-
"
|
|
2285
|
+
".cm-content": {
|
|
2154
2286
|
padding: 0,
|
|
2155
2287
|
// NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
|
|
2156
2288
|
fontSize: "16px"
|
|
2157
2289
|
},
|
|
2158
2290
|
"&light .cm-content": {
|
|
2159
|
-
color:
|
|
2291
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
2160
2292
|
caretColor: "black"
|
|
2161
2293
|
},
|
|
2162
2294
|
"&dark .cm-content": {
|
|
2163
|
-
color:
|
|
2295
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
2164
2296
|
caretColor: "white"
|
|
2165
2297
|
},
|
|
2166
2298
|
//
|
|
@@ -2172,41 +2304,41 @@ var defaultTheme = {
|
|
|
2172
2304
|
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
2173
2305
|
borderLeft: "2px solid white"
|
|
2174
2306
|
},
|
|
2175
|
-
"
|
|
2307
|
+
".cm-placeholder": {
|
|
2176
2308
|
fontWeight: 100
|
|
2177
2309
|
},
|
|
2178
2310
|
//
|
|
2179
2311
|
// line
|
|
2180
2312
|
//
|
|
2181
|
-
"
|
|
2313
|
+
".cm-line": {
|
|
2182
2314
|
paddingInline: 0
|
|
2183
2315
|
},
|
|
2184
|
-
"
|
|
2316
|
+
".cm-activeLine": {
|
|
2185
2317
|
background: "inherit"
|
|
2186
2318
|
},
|
|
2187
2319
|
//
|
|
2188
2320
|
// Selection
|
|
2189
2321
|
//
|
|
2190
2322
|
"&light .cm-selectionBackground": {
|
|
2191
|
-
background:
|
|
2323
|
+
background: get3(tokens, "extend.colors.primary.100")
|
|
2192
2324
|
},
|
|
2193
2325
|
"&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2194
|
-
background:
|
|
2326
|
+
background: get3(tokens, "extend.colors.primary.200")
|
|
2195
2327
|
},
|
|
2196
2328
|
"&dark .cm-selectionBackground": {
|
|
2197
|
-
background:
|
|
2329
|
+
background: get3(tokens, "extend.colors.primary.700")
|
|
2198
2330
|
},
|
|
2199
2331
|
"&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
|
|
2200
|
-
background:
|
|
2332
|
+
background: get3(tokens, "extend.colors.primary.600")
|
|
2201
2333
|
},
|
|
2202
2334
|
//
|
|
2203
2335
|
// Search
|
|
2204
2336
|
//
|
|
2205
2337
|
"&light .cm-searchMatch": {
|
|
2206
|
-
backgroundColor:
|
|
2338
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
2207
2339
|
},
|
|
2208
2340
|
"&dark .cm-searchMatch": {
|
|
2209
|
-
backgroundColor:
|
|
2341
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.700")
|
|
2210
2342
|
},
|
|
2211
2343
|
//
|
|
2212
2344
|
// collaboration
|
|
@@ -2218,95 +2350,101 @@ var defaultTheme = {
|
|
|
2218
2350
|
"&dark .cm-ySelection, &dark .cm-yLineSelection": {
|
|
2219
2351
|
mixBlendMode: "screen"
|
|
2220
2352
|
},
|
|
2221
|
-
"
|
|
2353
|
+
".cm-ySelectionInfo": {
|
|
2222
2354
|
padding: "2px 4px",
|
|
2223
2355
|
marginBlockStart: "-4px"
|
|
2224
2356
|
},
|
|
2225
|
-
"
|
|
2357
|
+
".cm-ySelection, & .cm-selectionMatch": {
|
|
2226
2358
|
paddingBlockStart: ".15em",
|
|
2227
2359
|
paddingBlockEnd: ".15em"
|
|
2228
2360
|
},
|
|
2229
|
-
"
|
|
2361
|
+
".cm-ySelectionCaret": {
|
|
2230
2362
|
display: "inline-block",
|
|
2231
2363
|
insetBlockStart: ".1em",
|
|
2232
2364
|
blockSize: "1.4em",
|
|
2233
2365
|
verticalAlign: "top"
|
|
2234
2366
|
},
|
|
2235
|
-
"
|
|
2367
|
+
".cm-yLineSelection": {
|
|
2236
2368
|
margin: 0
|
|
2237
2369
|
},
|
|
2238
2370
|
//
|
|
2239
2371
|
// link
|
|
2240
2372
|
//
|
|
2241
|
-
"
|
|
2242
|
-
color:
|
|
2373
|
+
".cm-link": {
|
|
2374
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
2243
2375
|
textDecorationLine: "underline",
|
|
2244
2376
|
textDecorationThickness: "1px",
|
|
2245
2377
|
textUnderlineOffset: "2px",
|
|
2246
2378
|
borderRadius: ".125rem",
|
|
2247
|
-
fontFamily:
|
|
2379
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2248
2380
|
},
|
|
2249
2381
|
//
|
|
2250
2382
|
// tooltip
|
|
2251
2383
|
//
|
|
2252
|
-
"
|
|
2384
|
+
".cm-tooltip": {
|
|
2253
2385
|
border: "none"
|
|
2254
2386
|
},
|
|
2255
|
-
"
|
|
2387
|
+
".cm-tooltip-below": {},
|
|
2256
2388
|
//
|
|
2257
2389
|
// autocomplete
|
|
2258
2390
|
//
|
|
2259
|
-
"
|
|
2391
|
+
".cm-tooltip-autocomplete": {
|
|
2260
2392
|
marginTop: "4px",
|
|
2261
2393
|
marginLeft: "-3px"
|
|
2262
2394
|
},
|
|
2263
|
-
"
|
|
2264
|
-
"
|
|
2265
|
-
"
|
|
2395
|
+
".cm-tooltip-autocomplete ul li": {},
|
|
2396
|
+
".cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
2397
|
+
".cm-completionIcon": {
|
|
2266
2398
|
display: "none"
|
|
2267
2399
|
},
|
|
2268
|
-
"
|
|
2269
|
-
fontFamily:
|
|
2400
|
+
".cm-completionLabel": {
|
|
2401
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2270
2402
|
},
|
|
2271
|
-
"
|
|
2403
|
+
".cm-completionMatchedText": {
|
|
2272
2404
|
textDecoration: "none"
|
|
2273
2405
|
},
|
|
2274
2406
|
//
|
|
2275
2407
|
// widgets
|
|
2276
2408
|
//
|
|
2277
|
-
"
|
|
2409
|
+
".cm-widgetBuffer": {
|
|
2278
2410
|
display: "none",
|
|
2279
2411
|
height: 0
|
|
2280
2412
|
},
|
|
2281
2413
|
//
|
|
2282
2414
|
// table
|
|
2283
2415
|
//
|
|
2284
|
-
"
|
|
2285
|
-
fontFamily: `${
|
|
2416
|
+
".cm-table *": {
|
|
2417
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
2286
2418
|
textDecoration: "none !important"
|
|
2287
2419
|
},
|
|
2288
|
-
"
|
|
2420
|
+
".cm-table-head": {
|
|
2289
2421
|
padding: "2px 16px 2px 0px",
|
|
2290
|
-
borderBottom: `1px solid ${
|
|
2422
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
2291
2423
|
fontWeight: 100,
|
|
2292
2424
|
textAlign: "left",
|
|
2293
|
-
color:
|
|
2425
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
2294
2426
|
},
|
|
2295
|
-
"
|
|
2427
|
+
".cm-table-cell": {
|
|
2296
2428
|
padding: "2px 16px 2px 0px"
|
|
2297
2429
|
},
|
|
2298
2430
|
//
|
|
2299
2431
|
// image
|
|
2300
2432
|
//
|
|
2301
|
-
"
|
|
2302
|
-
|
|
2433
|
+
".cm-image": {
|
|
2434
|
+
display: "block",
|
|
2435
|
+
height: "0"
|
|
2436
|
+
},
|
|
2437
|
+
".cm-image.cm-loaded-image": {
|
|
2438
|
+
height: "auto",
|
|
2439
|
+
borderTop: "0.5rem solid transparent",
|
|
2440
|
+
borderBottom: "0.5rem solid transparent"
|
|
2303
2441
|
},
|
|
2304
2442
|
//
|
|
2305
2443
|
// font size
|
|
2306
2444
|
// TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
|
|
2307
2445
|
//
|
|
2308
|
-
...Object.keys(
|
|
2309
|
-
const height =
|
|
2446
|
+
...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
2447
|
+
const height = get3(tokens, [
|
|
2310
2448
|
"extend",
|
|
2311
2449
|
"fontSize",
|
|
2312
2450
|
fontSize,
|
|
@@ -2340,51 +2478,51 @@ var defaultTheme = {
|
|
|
2340
2478
|
* </div>
|
|
2341
2479
|
* </div
|
|
2342
2480
|
*/
|
|
2343
|
-
"
|
|
2344
|
-
border: `1px solid ${
|
|
2481
|
+
".cm-panels": {
|
|
2482
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
|
|
2345
2483
|
},
|
|
2346
|
-
"
|
|
2347
|
-
background:
|
|
2348
|
-
fontFamily:
|
|
2484
|
+
".cm-panel": {
|
|
2485
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
2486
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2349
2487
|
},
|
|
2350
|
-
"
|
|
2488
|
+
".cm-button": {
|
|
2351
2489
|
margin: "4px",
|
|
2352
|
-
fontFamily:
|
|
2353
|
-
background:
|
|
2490
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
2491
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
2354
2492
|
backgroundImage: "none",
|
|
2355
2493
|
border: "none",
|
|
2356
2494
|
"&:hover": {
|
|
2357
|
-
background:
|
|
2495
|
+
background: get3(tokens, "extend.colors.neutral.200")
|
|
2358
2496
|
},
|
|
2359
2497
|
"&:active": {
|
|
2360
|
-
background:
|
|
2498
|
+
background: get3(tokens, "extend.colors.neutral.300"),
|
|
2361
2499
|
backgroundImage: "none"
|
|
2362
2500
|
}
|
|
2363
2501
|
},
|
|
2364
|
-
"
|
|
2502
|
+
".cm-panel input[type=checkbox]": {
|
|
2365
2503
|
marginRight: "0.4rem !important"
|
|
2366
2504
|
}
|
|
2367
2505
|
};
|
|
2368
2506
|
var textTheme = {
|
|
2369
|
-
"
|
|
2370
|
-
fontFamily:
|
|
2507
|
+
".cm-scroller": {
|
|
2508
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2371
2509
|
},
|
|
2372
|
-
"
|
|
2373
|
-
fontFamily:
|
|
2510
|
+
".cm-placeholder": {
|
|
2511
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2374
2512
|
}
|
|
2375
2513
|
};
|
|
2376
2514
|
var markdownTheme = {
|
|
2377
2515
|
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
2378
|
-
"
|
|
2379
|
-
fontFamily:
|
|
2516
|
+
".cm-placeholder": {
|
|
2517
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
2380
2518
|
}
|
|
2381
2519
|
};
|
|
2382
2520
|
var codeTheme = {
|
|
2383
|
-
"
|
|
2384
|
-
fontFamily:
|
|
2521
|
+
".cm-scroller": {
|
|
2522
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2385
2523
|
},
|
|
2386
|
-
"
|
|
2387
|
-
fontFamily:
|
|
2524
|
+
".cm-placeholder": {
|
|
2525
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
2388
2526
|
}
|
|
2389
2527
|
};
|
|
2390
2528
|
|
|
@@ -2398,8 +2536,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2398
2536
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
2399
2537
|
tabBehavior: "limited"
|
|
2400
2538
|
});
|
|
2401
|
-
const [root, setRoot] =
|
|
2402
|
-
const [{ state = void 0, view = void 0 } = {}, setEditor] =
|
|
2539
|
+
const [root, setRoot] = useState(null);
|
|
2540
|
+
const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
|
|
2403
2541
|
useImperativeHandle(forwardedRef, () => ({
|
|
2404
2542
|
root,
|
|
2405
2543
|
state,
|
|
@@ -2409,10 +2547,10 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2409
2547
|
state,
|
|
2410
2548
|
root
|
|
2411
2549
|
]);
|
|
2412
|
-
const { awareness, peer } = model;
|
|
2413
|
-
|
|
2414
|
-
if (
|
|
2415
|
-
|
|
2550
|
+
const { awareness: awareness2, peer } = model;
|
|
2551
|
+
useEffect(() => {
|
|
2552
|
+
if (awareness2 && peer) {
|
|
2553
|
+
awareness2.setLocalStateField("user", {
|
|
2416
2554
|
name: peer.name ?? generateName(peer.id),
|
|
2417
2555
|
color: getColorForValue({
|
|
2418
2556
|
value: peer.id,
|
|
@@ -2426,11 +2564,11 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2426
2564
|
});
|
|
2427
2565
|
}
|
|
2428
2566
|
}, [
|
|
2429
|
-
|
|
2567
|
+
awareness2,
|
|
2430
2568
|
peer,
|
|
2431
2569
|
themeMode
|
|
2432
2570
|
]);
|
|
2433
|
-
|
|
2571
|
+
useEffect(() => {
|
|
2434
2572
|
if (view && comments2?.length) {
|
|
2435
2573
|
view.dispatch({
|
|
2436
2574
|
effects: setCommentRange.of({
|
|
@@ -2443,7 +2581,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
|
|
|
2443
2581
|
view,
|
|
2444
2582
|
comments2
|
|
2445
2583
|
]);
|
|
2446
|
-
|
|
2584
|
+
useEffect(() => {
|
|
2447
2585
|
if (!root) {
|
|
2448
2586
|
return;
|
|
2449
2587
|
}
|
|
@@ -2561,28 +2699,379 @@ var defaultMarkdownSlots = {
|
|
|
2561
2699
|
theme: markdownTheme
|
|
2562
2700
|
}
|
|
2563
2701
|
};
|
|
2702
|
+
|
|
2703
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
2704
|
+
import get4 from "lodash.get";
|
|
2705
|
+
import { getRawDoc } from "@dxos/echo-schema";
|
|
2706
|
+
import { isNotNullOrUndefined } from "@dxos/util";
|
|
2707
|
+
|
|
2708
|
+
// packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
|
|
2709
|
+
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
2710
|
+
import { Context as Context2 } from "@dxos/context";
|
|
2711
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
2712
|
+
import { log as log3 } from "@dxos/log";
|
|
2713
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
|
|
2714
|
+
var DEBOUNCE_INTERVAL = 100;
|
|
2715
|
+
var SpaceAwarenessProvider = class {
|
|
2716
|
+
constructor(params) {
|
|
2717
|
+
this.remoteStateChange = new Event2();
|
|
2718
|
+
this._remoteStates = /* @__PURE__ */ new Map();
|
|
2719
|
+
this._space = params.space;
|
|
2720
|
+
this._channel = params.channel;
|
|
2721
|
+
this._peerId = params.peerId;
|
|
2722
|
+
this._info = params.info;
|
|
2723
|
+
}
|
|
2724
|
+
open() {
|
|
2725
|
+
this._ctx = new Context2();
|
|
2726
|
+
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
2727
|
+
if (this._localState) {
|
|
2728
|
+
await this._space.postMessage(this._channel, {
|
|
2729
|
+
kind: "post",
|
|
2730
|
+
state: this._localState
|
|
2731
|
+
});
|
|
2732
|
+
await sleep(DEBOUNCE_INTERVAL);
|
|
2733
|
+
}
|
|
2734
|
+
});
|
|
2735
|
+
const unsubscribe = this._space.listen(this._channel, (message) => {
|
|
2736
|
+
switch (message.payload.kind) {
|
|
2737
|
+
case "query": {
|
|
2738
|
+
this._handleQueryMessage();
|
|
2739
|
+
break;
|
|
2740
|
+
}
|
|
2741
|
+
case "post": {
|
|
2742
|
+
this._handlePostMessage(message.payload);
|
|
2743
|
+
break;
|
|
2744
|
+
}
|
|
2745
|
+
}
|
|
2746
|
+
});
|
|
2747
|
+
this._ctx.onDispose(unsubscribe);
|
|
2748
|
+
void this._space.postMessage(this._channel, {
|
|
2749
|
+
kind: "query"
|
|
2750
|
+
}).catch((err) => {
|
|
2751
|
+
log3.debug("failed to query awareness", {
|
|
2752
|
+
err
|
|
2753
|
+
}, {
|
|
2754
|
+
F: __dxlog_file4,
|
|
2755
|
+
L: 85,
|
|
2756
|
+
S: this,
|
|
2757
|
+
C: (f, a) => f(...a)
|
|
2758
|
+
});
|
|
2759
|
+
});
|
|
2760
|
+
}
|
|
2761
|
+
close() {
|
|
2762
|
+
void this._ctx?.dispose();
|
|
2763
|
+
this._ctx = void 0;
|
|
2764
|
+
this._postTask = void 0;
|
|
2765
|
+
}
|
|
2766
|
+
update(position) {
|
|
2767
|
+
invariant3(this._postTask, void 0, {
|
|
2768
|
+
F: __dxlog_file4,
|
|
2769
|
+
L: 96,
|
|
2770
|
+
S: this,
|
|
2771
|
+
A: [
|
|
2772
|
+
"this._postTask",
|
|
2773
|
+
""
|
|
2774
|
+
]
|
|
2775
|
+
});
|
|
2776
|
+
this._localState = {
|
|
2777
|
+
peerId: this._peerId,
|
|
2778
|
+
position,
|
|
2779
|
+
info: this._info
|
|
2780
|
+
};
|
|
2781
|
+
this._postTask.schedule();
|
|
2782
|
+
}
|
|
2783
|
+
getRemoteStates() {
|
|
2784
|
+
return Array.from(this._remoteStates.values());
|
|
2785
|
+
}
|
|
2786
|
+
_handleQueryMessage() {
|
|
2787
|
+
invariant3(this._postTask, void 0, {
|
|
2788
|
+
F: __dxlog_file4,
|
|
2789
|
+
L: 111,
|
|
2790
|
+
S: this,
|
|
2791
|
+
A: [
|
|
2792
|
+
"this._postTask",
|
|
2793
|
+
""
|
|
2794
|
+
]
|
|
2795
|
+
});
|
|
2796
|
+
this._postTask.schedule();
|
|
2797
|
+
}
|
|
2798
|
+
_handlePostMessage(message) {
|
|
2799
|
+
invariant3(message.kind === "post", void 0, {
|
|
2800
|
+
F: __dxlog_file4,
|
|
2801
|
+
L: 116,
|
|
2802
|
+
S: this,
|
|
2803
|
+
A: [
|
|
2804
|
+
"message.kind === 'post'",
|
|
2805
|
+
""
|
|
2806
|
+
]
|
|
2807
|
+
});
|
|
2808
|
+
this._remoteStates.set(message.state.peerId, message.state);
|
|
2809
|
+
this.remoteStateChange.emit();
|
|
2810
|
+
}
|
|
2811
|
+
};
|
|
2812
|
+
|
|
2813
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2814
|
+
import { StateField as StateField5 } from "@codemirror/state";
|
|
2815
|
+
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
2816
|
+
import { isAutomergeObject } from "@dxos/react-client/echo";
|
|
2817
|
+
|
|
2818
|
+
// packages/ui/react-ui-editor/src/hooks/yjs.ts
|
|
2819
|
+
import * as decoding from "lib0/decoding";
|
|
2820
|
+
import * as encoding from "lib0/encoding";
|
|
2821
|
+
import { Observable } from "lib0/observable";
|
|
2822
|
+
import * as YP from "y-protocols/awareness";
|
|
2823
|
+
import * as Y2 from "yjs";
|
|
2824
|
+
import { invariant as invariant4 } from "@dxos/invariant";
|
|
2825
|
+
import { log as log4 } from "@dxos/log";
|
|
2826
|
+
import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
|
|
2827
|
+
var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
|
|
2828
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
2829
|
+
invariant4(text?.doc && text?.content, void 0, {
|
|
2830
|
+
F: __dxlog_file5,
|
|
2831
|
+
L: 23,
|
|
2832
|
+
S: void 0,
|
|
2833
|
+
A: [
|
|
2834
|
+
"text?.doc && text?.content",
|
|
2835
|
+
""
|
|
2836
|
+
]
|
|
2837
|
+
});
|
|
2838
|
+
const provider = space ? new YAwarenessProvider({
|
|
2839
|
+
space,
|
|
2840
|
+
doc: text.doc,
|
|
2841
|
+
channel: `yjs.awareness.${text.id}`
|
|
2842
|
+
}) : void 0;
|
|
2843
|
+
const model = {
|
|
2844
|
+
id: text.doc.guid,
|
|
2845
|
+
content: text.content,
|
|
2846
|
+
text: () => text.content.toString(),
|
|
2847
|
+
// https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
|
|
2848
|
+
// TODO(dmaretskyi): Refactor as cursor-converter.
|
|
2849
|
+
getCursorFromRange: (range) => {
|
|
2850
|
+
const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
|
|
2851
|
+
const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
|
|
2852
|
+
return [
|
|
2853
|
+
arrayToString2(from),
|
|
2854
|
+
arrayToString2(to)
|
|
2855
|
+
].join(":");
|
|
2856
|
+
},
|
|
2857
|
+
getRangeFromCursor: (cursor) => {
|
|
2858
|
+
invariant4(text.doc, void 0, {
|
|
2859
|
+
F: __dxlog_file5,
|
|
2860
|
+
L: 40,
|
|
2861
|
+
S: void 0,
|
|
2862
|
+
A: [
|
|
2863
|
+
"text.doc",
|
|
2864
|
+
""
|
|
2865
|
+
]
|
|
2866
|
+
});
|
|
2867
|
+
const parts = cursor.split(":");
|
|
2868
|
+
const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
|
|
2869
|
+
const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
|
|
2870
|
+
return from && to ? {
|
|
2871
|
+
from: from.index,
|
|
2872
|
+
to: to.index
|
|
2873
|
+
} : void 0;
|
|
2874
|
+
},
|
|
2875
|
+
extension: [
|
|
2876
|
+
modelState.init(() => model),
|
|
2877
|
+
yjs(text.content, provider?.awareness)
|
|
2878
|
+
],
|
|
2879
|
+
awareness: provider?.awareness,
|
|
2880
|
+
peer: identity ? {
|
|
2881
|
+
id: identity.identityKey.toHex(),
|
|
2882
|
+
name: identity.profile?.displayName
|
|
2883
|
+
} : void 0
|
|
2884
|
+
};
|
|
2885
|
+
return model;
|
|
2886
|
+
};
|
|
2887
|
+
var messageAwareness = 1;
|
|
2888
|
+
var messageQueryAwareness = 3;
|
|
2889
|
+
var YAwarenessProvider = class extends Observable {
|
|
2890
|
+
constructor({ space, doc, channel, awareness: awareness2 }) {
|
|
2891
|
+
super();
|
|
2892
|
+
this._space = space;
|
|
2893
|
+
this._awareness = awareness2 ?? new YP.Awareness(doc);
|
|
2894
|
+
this._channel = channel;
|
|
2895
|
+
this._clientId = doc.clientID;
|
|
2896
|
+
this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
|
|
2897
|
+
this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
|
|
2898
|
+
if (typeof window !== "undefined") {
|
|
2899
|
+
window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
|
|
2900
|
+
} else if (typeof process !== "undefined") {
|
|
2901
|
+
process.on("exit", this._handleBeforeUnload.bind(this));
|
|
2902
|
+
}
|
|
2903
|
+
const encoderAwarenessQuery = encoding.createEncoder();
|
|
2904
|
+
encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
|
|
2905
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
|
|
2906
|
+
const encoderAwarenessState = encoding.createEncoder();
|
|
2907
|
+
encoding.writeVarUint(encoderAwarenessState, messageAwareness);
|
|
2908
|
+
encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
|
|
2909
|
+
this._clientId
|
|
2910
|
+
]));
|
|
2911
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
|
|
2912
|
+
}
|
|
2913
|
+
get awareness() {
|
|
2914
|
+
return this._awareness;
|
|
2915
|
+
}
|
|
2916
|
+
_handleAwarenessUpdate({ added, updated, removed }, origin) {
|
|
2917
|
+
log4("awareness update", {
|
|
2918
|
+
added,
|
|
2919
|
+
updated,
|
|
2920
|
+
removed,
|
|
2921
|
+
origin
|
|
2922
|
+
}, {
|
|
2923
|
+
F: __dxlog_file5,
|
|
2924
|
+
L: 122,
|
|
2925
|
+
S: this,
|
|
2926
|
+
C: (f, a) => f(...a)
|
|
2927
|
+
});
|
|
2928
|
+
const changedClients = added.concat(updated).concat(removed);
|
|
2929
|
+
const encoderAwareness = encoding.createEncoder();
|
|
2930
|
+
encoding.writeVarUint(encoderAwareness, messageAwareness);
|
|
2931
|
+
encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
|
|
2932
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
|
|
2933
|
+
}
|
|
2934
|
+
_handleSpaceMessage({ payload }) {
|
|
2935
|
+
log4("space message", payload, {
|
|
2936
|
+
F: __dxlog_file5,
|
|
2937
|
+
L: 131,
|
|
2938
|
+
S: this,
|
|
2939
|
+
C: (f, a) => f(...a)
|
|
2940
|
+
});
|
|
2941
|
+
const data = new Uint8Array(Array.from(Object.values(payload)));
|
|
2942
|
+
const encoder = this._readMessage(data);
|
|
2943
|
+
if (encoder) {
|
|
2944
|
+
void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
|
|
2945
|
+
}
|
|
2946
|
+
}
|
|
2947
|
+
_readMessage(message) {
|
|
2948
|
+
const decoder = decoding.createDecoder(message);
|
|
2949
|
+
const encoder = encoding.createEncoder();
|
|
2950
|
+
const messageType = decoding.readVarUint(decoder);
|
|
2951
|
+
let sendReply = false;
|
|
2952
|
+
switch (messageType) {
|
|
2953
|
+
case messageAwareness: {
|
|
2954
|
+
YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
|
|
2955
|
+
break;
|
|
2956
|
+
}
|
|
2957
|
+
case messageQueryAwareness: {
|
|
2958
|
+
encoding.writeVarUint(encoder, messageAwareness);
|
|
2959
|
+
encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
|
|
2960
|
+
sendReply = true;
|
|
2961
|
+
break;
|
|
2962
|
+
}
|
|
2963
|
+
default: {
|
|
2964
|
+
console.error("Invalid message:", messageType);
|
|
2965
|
+
return encoder;
|
|
2966
|
+
}
|
|
2967
|
+
}
|
|
2968
|
+
if (!sendReply) {
|
|
2969
|
+
return null;
|
|
2970
|
+
}
|
|
2971
|
+
return encoder;
|
|
2972
|
+
}
|
|
2973
|
+
_handleBeforeUnload() {
|
|
2974
|
+
YP.removeAwarenessStates(this._awareness, [
|
|
2975
|
+
this._clientId
|
|
2976
|
+
], "window unload");
|
|
2977
|
+
}
|
|
2978
|
+
};
|
|
2979
|
+
|
|
2980
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2981
|
+
var modelState = StateField5.define({
|
|
2982
|
+
create: () => void 0,
|
|
2983
|
+
update: (model) => model
|
|
2984
|
+
});
|
|
2985
|
+
var useTextModel = (props) => {
|
|
2986
|
+
const { identity, space, text } = props;
|
|
2987
|
+
const [model, setModel] = useState2(() => createModel(props));
|
|
2988
|
+
useEffect2(() => setModel(createModel(props)), [
|
|
2989
|
+
identity,
|
|
2990
|
+
space,
|
|
2991
|
+
text
|
|
2992
|
+
]);
|
|
2993
|
+
return model;
|
|
2994
|
+
};
|
|
2995
|
+
var createModel = (props) => {
|
|
2996
|
+
const { text } = props;
|
|
2997
|
+
if (isAutomergeObject(text)) {
|
|
2998
|
+
return createAutomergeModel(props);
|
|
2999
|
+
} else if (text?.doc) {
|
|
3000
|
+
return createYjsModel(props);
|
|
3001
|
+
} else {
|
|
3002
|
+
return void 0;
|
|
3003
|
+
}
|
|
3004
|
+
};
|
|
3005
|
+
|
|
3006
|
+
// packages/ui/react-ui-editor/src/hooks/automerge.ts
|
|
3007
|
+
var createAutomergeModel = ({ space, identity, text }) => {
|
|
3008
|
+
const obj = text;
|
|
3009
|
+
const doc = getRawDoc(obj, [
|
|
3010
|
+
obj.field
|
|
3011
|
+
]);
|
|
3012
|
+
const awarenessProvider = space && new SpaceAwarenessProvider({
|
|
3013
|
+
space,
|
|
3014
|
+
channel: `automerge.awareness.${obj.id}`,
|
|
3015
|
+
info: {
|
|
3016
|
+
displayName: identity?.profile?.displayName ?? "",
|
|
3017
|
+
color: cursorColor.color,
|
|
3018
|
+
lightColor: cursorColor.light
|
|
3019
|
+
},
|
|
3020
|
+
peerId: identity?.identityKey.toHex() ?? "Anonymous"
|
|
3021
|
+
});
|
|
3022
|
+
const model = {
|
|
3023
|
+
id: obj.id,
|
|
3024
|
+
content: doc,
|
|
3025
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
3026
|
+
// TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
|
|
3027
|
+
extension: [
|
|
3028
|
+
modelState.init(() => model),
|
|
3029
|
+
automerge3({
|
|
3030
|
+
handle: doc.handle,
|
|
3031
|
+
path: doc.path
|
|
3032
|
+
}),
|
|
3033
|
+
awarenessProvider && AwarenessProvider.of(awarenessProvider),
|
|
3034
|
+
awareness()
|
|
3035
|
+
].filter(isNotNullOrUndefined),
|
|
3036
|
+
peer: identity ? {
|
|
3037
|
+
id: identity.identityKey.toHex(),
|
|
3038
|
+
name: identity.profile?.displayName
|
|
3039
|
+
} : void 0
|
|
3040
|
+
};
|
|
3041
|
+
return model;
|
|
3042
|
+
};
|
|
2564
3043
|
export {
|
|
3044
|
+
AwarenessProvider,
|
|
2565
3045
|
BaseTextEditor,
|
|
3046
|
+
CursorConverter,
|
|
2566
3047
|
Doc,
|
|
2567
3048
|
EditorModes,
|
|
2568
3049
|
MarkdownEditor,
|
|
3050
|
+
RemoteSelectionsDecorator,
|
|
2569
3051
|
SpaceAwarenessProvider,
|
|
2570
3052
|
TextEditor,
|
|
2571
3053
|
TextKind,
|
|
3054
|
+
YAwarenessProvider,
|
|
2572
3055
|
YText,
|
|
2573
3056
|
YXmlFragment,
|
|
2574
3057
|
autocomplete,
|
|
3058
|
+
automerge3 as automerge,
|
|
3059
|
+
awareness,
|
|
2575
3060
|
basicBundle,
|
|
2576
3061
|
blast,
|
|
3062
|
+
callbackWrapper,
|
|
2577
3063
|
code2 as code,
|
|
2578
3064
|
codeTheme,
|
|
2579
3065
|
comments,
|
|
2580
|
-
|
|
3066
|
+
createAutomergeModel,
|
|
3067
|
+
createYjsModel,
|
|
3068
|
+
cursorConverter,
|
|
2581
3069
|
defaultMarkdownSlots,
|
|
2582
3070
|
defaultOptions,
|
|
2583
3071
|
defaultSlots,
|
|
2584
3072
|
defaultTextSlots,
|
|
2585
3073
|
defaultTheme,
|
|
3074
|
+
getToken,
|
|
2586
3075
|
hr,
|
|
2587
3076
|
image,
|
|
2588
3077
|
link,
|
|
@@ -2593,14 +3082,16 @@ export {
|
|
|
2593
3082
|
markdownTagsExtensions,
|
|
2594
3083
|
markdownTheme,
|
|
2595
3084
|
mention,
|
|
2596
|
-
mermaid,
|
|
2597
3085
|
modelState,
|
|
2598
3086
|
setCommentRange,
|
|
3087
|
+
setFocus,
|
|
3088
|
+
setSelection,
|
|
2599
3089
|
table,
|
|
2600
3090
|
tags2 as tags,
|
|
2601
3091
|
tasklist,
|
|
2602
3092
|
textTheme,
|
|
2603
3093
|
typewriter,
|
|
2604
|
-
useTextModel
|
|
3094
|
+
useTextModel,
|
|
3095
|
+
yjs
|
|
2605
3096
|
};
|
|
2606
3097
|
//# sourceMappingURL=index.mjs.map
|