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