@dxos/react-ui-editor 0.3.10-main.3645708 → 0.3.10-main.396fa89
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 +1495 -489
- 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 +26 -2
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +3 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -0
- package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts +3 -2
- package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts +2 -1
- package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts +25 -0
- package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/code.d.ts +2 -0
- package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts +18 -0
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/demo.d.ts +11 -0
- package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/experimental.d.ts +1 -1
- package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/highlight.d.ts +24 -0
- package/dist/types/src/components/TextEditor/extensions/highlight.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/image.d.ts +4 -0
- package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts +4 -2
- package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +10 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +9 -3
- package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts +6 -0
- package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/table.d.ts +8 -0
- package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +1 -0
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +2 -4
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/themes/default.d.ts +8 -0
- package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/PatchSemaphore.d.ts +3 -0
- package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts +16 -0
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/handle.d.ts.map +1 -0
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/index.d.ts +1 -1
- package/dist/types/src/hooks/automerge/index.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts +5 -0
- package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts +6 -0
- package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts.map +1 -0
- package/dist/types/src/hooks/automerge/translation/index.d.ts +3 -0
- package/dist/types/src/hooks/automerge/translation/index.d.ts.map +1 -0
- package/dist/types/src/hooks/index.d.ts +0 -1
- package/dist/types/src/hooks/index.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +8 -3
- package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
- package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +2 -2
- package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +1 -0
- package/dist/types/src/styles/markdown.d.ts +3 -2
- package/dist/types/src/styles/markdown.d.ts.map +1 -1
- package/dist/types/src/testing/replicator.d.ts.map +1 -1
- package/package.json +22 -19
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +161 -36
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -1
- package/src/components/TextEditor/TextEditor.tsx +49 -24
- package/src/components/TextEditor/extensions/autocomplete.ts +9 -22
- package/src/components/TextEditor/extensions/basic.ts +6 -4
- package/src/components/TextEditor/extensions/blast.ts +373 -0
- package/src/components/TextEditor/extensions/code.ts +99 -0
- package/src/components/TextEditor/extensions/comments.ts +173 -0
- package/src/components/TextEditor/extensions/demo.ts +69 -0
- package/src/components/TextEditor/extensions/experimental.tsx +15 -35
- package/src/components/TextEditor/extensions/highlight.ts +128 -0
- package/src/components/TextEditor/extensions/image.ts +67 -0
- package/src/components/TextEditor/extensions/index.ts +8 -0
- package/src/components/TextEditor/extensions/link.ts +27 -27
- package/src/components/TextEditor/extensions/listener.ts +4 -3
- package/src/components/TextEditor/extensions/markdown/bundle.ts +46 -43
- package/src/components/TextEditor/extensions/markdown/highlight.ts +148 -107
- package/src/components/TextEditor/extensions/mention.ts +31 -0
- package/src/components/TextEditor/extensions/table.ts +119 -0
- package/src/components/TextEditor/extensions/tasklist.ts +89 -81
- package/src/components/TextEditor/themes/default.ts +112 -4
- package/src/{automerge/automerge-plugin → hooks/automerge}/PatchSemaphore.ts +12 -9
- package/src/{automerge → hooks/automerge}/automerge.stories.tsx +6 -3
- package/src/{automerge/automerge-plugin → hooks/automerge}/plugin.ts +1 -0
- package/src/{automerge/automerge-plugin/amToCodemirror.ts → hooks/automerge/translation/automerge-to-codemirror.ts} +10 -2
- package/src/{automerge/automerge-plugin/codeMirrorToAm.ts → hooks/automerge/translation/codemirror-to-automerge.ts} +7 -4
- package/src/hooks/automerge/translation/index.ts +6 -0
- package/src/hooks/index.ts +0 -1
- package/src/hooks/useTextModel.ts +58 -41
- package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +2 -2
- package/src/styles/markdown.ts +15 -8
- package/src/testing/replicator.ts +7 -7
- package/dist/types/src/automerge/automerge-plugin/PatchSemaphore.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts +0 -6
- package/dist/types/src/automerge/automerge-plugin/amToCodemirror.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts +0 -7
- package/dist/types/src/automerge/automerge-plugin/codeMirrorToAm.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/handle.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/index.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge-plugin/plugin.d.ts.map +0 -1
- package/dist/types/src/automerge/automerge.stories.d.ts +0 -9
- package/dist/types/src/automerge/automerge.stories.d.ts.map +0 -1
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/useCollaboration.d.ts +0 -9
- package/dist/types/src/hooks/useCollaboration.d.ts.map +0 -1
- package/src/hooks/useCollaboration.ts +0 -45
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/handle.d.ts +0 -0
- package/dist/types/src/{automerge/automerge-plugin → hooks/automerge}/plugin.d.ts +0 -0
- package/src/{automerge/automerge-plugin → hooks/automerge}/handle.ts +0 -0
- package/src/{automerge/automerge-plugin → hooks/automerge}/index.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// packages/ui/react-ui-editor/src/index.ts
|
|
2
2
|
import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
|
|
3
|
-
import { Doc, YText
|
|
3
|
+
import { Doc, YText, YXmlFragment } from "@dxos/text-model";
|
|
4
4
|
|
|
5
5
|
// packages/ui/react-ui-editor/src/components/TextEditor/index.ts
|
|
6
6
|
import { tags as tags2 } from "@lezer/highlight";
|
|
@@ -8,7 +8,7 @@ import { tags as tags2 } from "@lezer/highlight";
|
|
|
8
8
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/autocomplete.ts
|
|
9
9
|
import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
|
|
10
10
|
import { keymap } from "@codemirror/view";
|
|
11
|
-
var autocomplete = ({
|
|
11
|
+
var autocomplete = ({ onSearch }) => {
|
|
12
12
|
return [
|
|
13
13
|
// https://codemirror.net/docs/ref/#view.keymap
|
|
14
14
|
// https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
|
|
@@ -24,13 +24,13 @@ var autocomplete = ({ getOptions }) => {
|
|
|
24
24
|
// TODO(burdon): Optional decoration via addToOptions
|
|
25
25
|
override: [
|
|
26
26
|
(context) => {
|
|
27
|
-
const
|
|
28
|
-
if (!
|
|
27
|
+
const match = context.matchBefore(/\w*/);
|
|
28
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
29
29
|
return null;
|
|
30
30
|
}
|
|
31
31
|
return {
|
|
32
|
-
from:
|
|
33
|
-
options:
|
|
32
|
+
from: match.from,
|
|
33
|
+
options: onSearch(match.text.toLowerCase())
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
]
|
|
@@ -42,23 +42,809 @@ var autocomplete = ({ getOptions }) => {
|
|
|
42
42
|
import { closeBrackets } from "@codemirror/autocomplete";
|
|
43
43
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
44
44
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
45
|
-
import { EditorView, placeholder } from "@codemirror/view";
|
|
46
|
-
var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
|
|
45
|
+
import { drawSelection, EditorView, placeholder } from "@codemirror/view";
|
|
46
|
+
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
47
|
+
EditorView.lineWrapping,
|
|
47
48
|
// TODO(burdon): Compare with minimalSetup.
|
|
48
49
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
49
50
|
bracketMatching(),
|
|
50
51
|
closeBrackets(),
|
|
51
|
-
|
|
52
|
+
drawSelection(),
|
|
52
53
|
_placeholder && placeholder(_placeholder),
|
|
53
54
|
// TODO(burdon): Is this required?
|
|
54
55
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
55
56
|
].filter(Boolean);
|
|
56
57
|
|
|
57
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
58
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/blast.ts
|
|
59
|
+
import { EditorView as EditorView2, keymap as keymap2 } from "@codemirror/view";
|
|
60
|
+
import defaultsDeep from "lodash.defaultsdeep";
|
|
61
|
+
import { invariant } from "@dxos/invariant";
|
|
62
|
+
var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/blast.ts";
|
|
63
|
+
var defaultOptions = {
|
|
64
|
+
effect: 2,
|
|
65
|
+
maxParticles: 200,
|
|
66
|
+
particleGravity: 0.08,
|
|
67
|
+
particleAlphaFadeout: 0.996,
|
|
68
|
+
particleSize: {
|
|
69
|
+
min: 2,
|
|
70
|
+
max: 8
|
|
71
|
+
},
|
|
72
|
+
particleNumRange: {
|
|
73
|
+
min: 5,
|
|
74
|
+
max: 10
|
|
75
|
+
},
|
|
76
|
+
particleVelocityRange: {
|
|
77
|
+
x: [
|
|
78
|
+
-1,
|
|
79
|
+
1
|
|
80
|
+
],
|
|
81
|
+
y: [
|
|
82
|
+
-3.5,
|
|
83
|
+
-1.5
|
|
84
|
+
]
|
|
85
|
+
},
|
|
86
|
+
particleShrinkRate: 0.95,
|
|
87
|
+
shakeIntensity: 5
|
|
88
|
+
};
|
|
89
|
+
var blast = (options = defaultOptions) => {
|
|
90
|
+
let blaster;
|
|
91
|
+
let last = 0;
|
|
92
|
+
const getPoint = (view, pos) => {
|
|
93
|
+
const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
|
|
94
|
+
const element = document.elementFromPoint(x, y);
|
|
95
|
+
const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
|
|
96
|
+
const point = {
|
|
97
|
+
x: x - left,
|
|
98
|
+
y: y - top
|
|
99
|
+
};
|
|
100
|
+
return {
|
|
101
|
+
element,
|
|
102
|
+
point
|
|
103
|
+
};
|
|
104
|
+
};
|
|
105
|
+
return [
|
|
106
|
+
// Cursor moved.
|
|
107
|
+
EditorView2.updateListener.of((update4) => {
|
|
108
|
+
if (blaster?.node !== update4.view.scrollDOM) {
|
|
109
|
+
if (blaster) {
|
|
110
|
+
blaster.destroy();
|
|
111
|
+
}
|
|
112
|
+
blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({
|
|
113
|
+
particleGravity: 0.2,
|
|
114
|
+
particleShrinkRate: 0.995,
|
|
115
|
+
color: () => [
|
|
116
|
+
100 + Math.random() * 100,
|
|
117
|
+
0,
|
|
118
|
+
0
|
|
119
|
+
]
|
|
120
|
+
}, options, defaultOptions));
|
|
121
|
+
blaster.initialize();
|
|
122
|
+
blaster.start();
|
|
123
|
+
} else {
|
|
124
|
+
blaster.resize();
|
|
125
|
+
}
|
|
126
|
+
const current = update4.state.selection.main.head;
|
|
127
|
+
if (current !== last) {
|
|
128
|
+
last = current;
|
|
129
|
+
const { element, point } = getPoint(update4.view, current - 1);
|
|
130
|
+
if (element && point) {
|
|
131
|
+
blaster.spawn({
|
|
132
|
+
element,
|
|
133
|
+
point
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
keymap2.of([
|
|
139
|
+
{
|
|
140
|
+
any: (_, event) => {
|
|
141
|
+
if (blaster) {
|
|
142
|
+
if (event.key === "Enter" && event.shiftKey) {
|
|
143
|
+
blaster.shake({
|
|
144
|
+
time: 0.8
|
|
145
|
+
});
|
|
146
|
+
return true;
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
return false;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
])
|
|
153
|
+
];
|
|
154
|
+
};
|
|
155
|
+
var Blaster = class {
|
|
156
|
+
constructor(_node, _options) {
|
|
157
|
+
this._node = _node;
|
|
158
|
+
this._options = _options;
|
|
159
|
+
this._running = false;
|
|
160
|
+
this._shakeTime = 0;
|
|
161
|
+
this._shakeTimeMax = 0;
|
|
162
|
+
this._particles = [];
|
|
163
|
+
this._particlePointer = 0;
|
|
164
|
+
this._lastPoint = {
|
|
165
|
+
x: 0,
|
|
166
|
+
y: 0
|
|
167
|
+
};
|
|
168
|
+
this.shake = throttle(({ time }) => {
|
|
169
|
+
this._shakeTime = this._shakeTimeMax || time;
|
|
170
|
+
this._shakeTimeMax = time;
|
|
171
|
+
}, 100);
|
|
172
|
+
this.spawn = throttle(({ element, point }) => {
|
|
173
|
+
const color = getRGBComponents(element, this._options.color);
|
|
174
|
+
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
175
|
+
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
176
|
+
this._lastPoint = point;
|
|
177
|
+
for (let i = numParticles; i--; i > 0) {
|
|
178
|
+
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
179
|
+
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
180
|
+
}
|
|
181
|
+
}, 100);
|
|
182
|
+
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
183
|
+
}
|
|
184
|
+
get node() {
|
|
185
|
+
return this._node;
|
|
186
|
+
}
|
|
187
|
+
initialize() {
|
|
188
|
+
invariant(!this._canvas && !this._ctx, void 0, {
|
|
189
|
+
F: __dxlog_file,
|
|
190
|
+
L: 138,
|
|
191
|
+
S: this,
|
|
192
|
+
A: [
|
|
193
|
+
"!this._canvas && !this._ctx",
|
|
194
|
+
""
|
|
195
|
+
]
|
|
196
|
+
});
|
|
197
|
+
this._canvas = document.createElement("canvas");
|
|
198
|
+
this._canvas.id = "code-blast-canvas";
|
|
199
|
+
this._canvas.style.position = "absolute";
|
|
200
|
+
this._canvas.style.zIndex = "0";
|
|
201
|
+
this._canvas.style.pointerEvents = "none";
|
|
202
|
+
this._ctx = this._canvas.getContext("2d");
|
|
203
|
+
const parent = this._node.parentElement?.parentElement;
|
|
204
|
+
parent?.appendChild(this._canvas);
|
|
205
|
+
this.resize();
|
|
206
|
+
}
|
|
207
|
+
destroy() {
|
|
208
|
+
this.stop();
|
|
209
|
+
if (this._canvas) {
|
|
210
|
+
this._canvas.remove();
|
|
211
|
+
this._canvas = void 0;
|
|
212
|
+
this._ctx = void 0;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
resize() {
|
|
216
|
+
if (this._node.parentElement && this._canvas) {
|
|
217
|
+
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
218
|
+
this._canvas.style.top = `${y}px`;
|
|
219
|
+
this._canvas.style.left = `${x}px`;
|
|
220
|
+
this._canvas.width = width;
|
|
221
|
+
this._canvas.height = height;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
start() {
|
|
225
|
+
invariant(this._canvas && this._ctx, void 0, {
|
|
226
|
+
F: __dxlog_file,
|
|
227
|
+
L: 177,
|
|
228
|
+
S: this,
|
|
229
|
+
A: [
|
|
230
|
+
"this._canvas && this._ctx",
|
|
231
|
+
""
|
|
232
|
+
]
|
|
233
|
+
});
|
|
234
|
+
this._running = true;
|
|
235
|
+
this.loop();
|
|
236
|
+
}
|
|
237
|
+
stop() {
|
|
238
|
+
this._running = false;
|
|
239
|
+
this._node.style.transform = "translate(0px, 0px)";
|
|
240
|
+
}
|
|
241
|
+
loop() {
|
|
242
|
+
if (!this._running || !this._canvas || !this._ctx) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
245
|
+
this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
|
|
246
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
247
|
+
this._lastTime ??= now;
|
|
248
|
+
const dt = (now - this._lastTime) / 1e3;
|
|
249
|
+
this._lastTime = now;
|
|
250
|
+
if (this._shakeTime > 0) {
|
|
251
|
+
this._shakeTime -= dt;
|
|
252
|
+
const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
|
|
253
|
+
const shakeX = random(-magnitude, magnitude);
|
|
254
|
+
const shakeY = random(-magnitude, magnitude);
|
|
255
|
+
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
256
|
+
}
|
|
257
|
+
this.drawParticles();
|
|
258
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
259
|
+
}
|
|
260
|
+
drawParticles() {
|
|
261
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
262
|
+
const particle = this._particles[i];
|
|
263
|
+
if (!particle) {
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
266
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
267
|
+
continue;
|
|
268
|
+
}
|
|
269
|
+
this._effect.update(this._ctx, particle);
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
var Effect = class {
|
|
274
|
+
constructor(_options) {
|
|
275
|
+
this._options = _options;
|
|
276
|
+
}
|
|
277
|
+
};
|
|
278
|
+
var Effect1 = class extends Effect {
|
|
279
|
+
create(x, y, color) {
|
|
280
|
+
return {
|
|
281
|
+
x,
|
|
282
|
+
y: y + 10,
|
|
283
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
284
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
285
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
286
|
+
color,
|
|
287
|
+
alpha: 1
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
update(ctx, particle) {
|
|
291
|
+
particle.vy += this._options.particleGravity;
|
|
292
|
+
particle.x += particle.vx;
|
|
293
|
+
particle.y += particle.vy;
|
|
294
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
295
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
296
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
297
|
+
}
|
|
298
|
+
};
|
|
299
|
+
var Effect2 = class extends Effect {
|
|
300
|
+
create(x, y, color) {
|
|
301
|
+
return {
|
|
302
|
+
x,
|
|
303
|
+
y: y + 10,
|
|
304
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
305
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
306
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
307
|
+
color,
|
|
308
|
+
alpha: 1,
|
|
309
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
310
|
+
drag: 0.92,
|
|
311
|
+
wander: 0.15
|
|
312
|
+
};
|
|
313
|
+
}
|
|
314
|
+
update(ctx, particle) {
|
|
315
|
+
particle.vy += this._options.particleGravity;
|
|
316
|
+
particle.x += particle.vx;
|
|
317
|
+
particle.y += particle.vy;
|
|
318
|
+
particle.vx *= particle.drag;
|
|
319
|
+
particle.vy *= particle.drag;
|
|
320
|
+
particle.theta += random(-0.5, 0.5);
|
|
321
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
322
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
323
|
+
particle.size *= this._options.particleShrinkRate;
|
|
324
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
325
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
326
|
+
ctx.beginPath();
|
|
327
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
328
|
+
ctx.fill();
|
|
329
|
+
}
|
|
330
|
+
};
|
|
331
|
+
function throttle(callback, limit) {
|
|
332
|
+
let wait = false;
|
|
333
|
+
return function(...args) {
|
|
334
|
+
if (!wait) {
|
|
335
|
+
callback.apply(this, args);
|
|
336
|
+
wait = true;
|
|
337
|
+
setTimeout(() => {
|
|
338
|
+
wait = false;
|
|
339
|
+
}, limit);
|
|
340
|
+
}
|
|
341
|
+
};
|
|
342
|
+
}
|
|
343
|
+
var getRGBComponents = (node, color) => {
|
|
344
|
+
if (typeof color === "function") {
|
|
345
|
+
return color();
|
|
346
|
+
}
|
|
347
|
+
const bgColor = getComputedStyle(node).color;
|
|
348
|
+
if (bgColor) {
|
|
349
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
350
|
+
if (x) {
|
|
351
|
+
return x;
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return [
|
|
355
|
+
50,
|
|
356
|
+
50,
|
|
357
|
+
50
|
|
358
|
+
];
|
|
359
|
+
};
|
|
360
|
+
var random = (min, max) => {
|
|
361
|
+
if (!max) {
|
|
362
|
+
max = min;
|
|
363
|
+
min = 0;
|
|
364
|
+
}
|
|
365
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
|
|
369
|
+
import { ViewPlugin, EditorView as EditorView3, Decoration } from "@codemirror/view";
|
|
370
|
+
import get from "lodash.get";
|
|
371
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
372
|
+
|
|
373
|
+
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
374
|
+
import { mx } from "@dxos/react-ui-theme";
|
|
375
|
+
var headings = {
|
|
376
|
+
1: [
|
|
377
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
378
|
+
"-ml-[10px]"
|
|
379
|
+
],
|
|
380
|
+
2: [
|
|
381
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
382
|
+
"-ml-[8px]"
|
|
383
|
+
],
|
|
384
|
+
3: [
|
|
385
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
386
|
+
"-ml-[7px]"
|
|
387
|
+
],
|
|
388
|
+
4: [
|
|
389
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
390
|
+
"-ml-[6px]"
|
|
391
|
+
],
|
|
392
|
+
5: [
|
|
393
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
394
|
+
"-ml-[5px]"
|
|
395
|
+
],
|
|
396
|
+
6: [
|
|
397
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
398
|
+
"-ml-[4px]"
|
|
399
|
+
]
|
|
400
|
+
};
|
|
401
|
+
var heading = (level, readonly) => {
|
|
402
|
+
const [style, offset] = headings[level];
|
|
403
|
+
return mx(style, readonly && offset);
|
|
404
|
+
};
|
|
405
|
+
var light = "text-neutral-200 dark:text-neutral-800";
|
|
406
|
+
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
407
|
+
var bold = "font-bold";
|
|
408
|
+
var italic = "italic";
|
|
409
|
+
var strikethrough = "line-through";
|
|
410
|
+
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
411
|
+
var codeMark = "font-mono text-primary-500";
|
|
412
|
+
var inlineUrl = mx(code, "px-1");
|
|
413
|
+
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
414
|
+
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
|
|
415
|
+
|
|
416
|
+
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
417
|
+
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
418
|
+
var tokens = tailwindConfig({}).theme;
|
|
419
|
+
|
|
420
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
|
|
421
|
+
var CODE_REGEX = /```[\s\S]*?```/gs;
|
|
422
|
+
var styles = EditorView3.baseTheme({
|
|
423
|
+
"& .cm-code-block": {
|
|
424
|
+
display: "block",
|
|
425
|
+
paddingInline: "4px !important"
|
|
426
|
+
},
|
|
427
|
+
"&light .cm-code-block": {
|
|
428
|
+
background: get(tokens, "extend.colors.neutral.50")
|
|
429
|
+
},
|
|
430
|
+
"&dark .cm-code-block": {
|
|
431
|
+
background: get(tokens, "extend.colors.neutral.850")
|
|
432
|
+
},
|
|
433
|
+
"& .cm-code-block-first": {
|
|
434
|
+
paddingTop: "4px !important",
|
|
435
|
+
borderTopLeftRadius: "4px",
|
|
436
|
+
borderTopRightRadius: "4px"
|
|
437
|
+
},
|
|
438
|
+
"& .cm-code-block-last": {
|
|
439
|
+
paddingBottom: "4px !important",
|
|
440
|
+
borderBottomLeftRadius: "4px",
|
|
441
|
+
borderBottomRightRadius: "4px"
|
|
442
|
+
}
|
|
443
|
+
});
|
|
444
|
+
var getLineRange = (lines, from, to) => {
|
|
445
|
+
const start = lines.findIndex((line) => line.from >= from);
|
|
446
|
+
const end = lines.findIndex((line) => line.to >= to);
|
|
447
|
+
return [
|
|
448
|
+
start,
|
|
449
|
+
end
|
|
450
|
+
];
|
|
451
|
+
};
|
|
452
|
+
var code2 = () => {
|
|
453
|
+
const getDecorations = (view) => {
|
|
454
|
+
const decorations = [];
|
|
455
|
+
if (view.state.readOnly) {
|
|
456
|
+
const text = view.state.doc.sliceString(0);
|
|
457
|
+
const matches = text.matchAll(CODE_REGEX);
|
|
458
|
+
const blocks = view.viewportLineBlocks;
|
|
459
|
+
for (const match of matches) {
|
|
460
|
+
const range = getLineRange(blocks, match.index, match.index + match[0].length);
|
|
461
|
+
for (let i = range[0]; i <= range[1]; i++) {
|
|
462
|
+
const block = blocks[i];
|
|
463
|
+
decorations.push(Decoration.line({
|
|
464
|
+
class: mx2("cm-code-block", i === range[0] && "cm-code-block-first", i === range[1] && "cm-code-block-last")
|
|
465
|
+
}).range(block.from));
|
|
466
|
+
}
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
return Decoration.set(decorations);
|
|
470
|
+
};
|
|
471
|
+
return [
|
|
472
|
+
ViewPlugin.fromClass(class {
|
|
473
|
+
constructor(view) {
|
|
474
|
+
this.decorations = getDecorations(view);
|
|
475
|
+
}
|
|
476
|
+
update(update4) {
|
|
477
|
+
if (update4.docChanged || update4.viewportChanged) {
|
|
478
|
+
this.decorations = getDecorations(update4.view);
|
|
479
|
+
}
|
|
480
|
+
}
|
|
481
|
+
}, {
|
|
482
|
+
decorations: (value) => value.decorations
|
|
483
|
+
}),
|
|
484
|
+
styles
|
|
485
|
+
];
|
|
486
|
+
};
|
|
487
|
+
|
|
488
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
|
|
489
|
+
import { keymap as keymap3 } from "@codemirror/view";
|
|
490
|
+
var defaultItems = [
|
|
491
|
+
"hello world!",
|
|
492
|
+
"this is a test.",
|
|
493
|
+
"this is [DXOS](https://dxos.org)"
|
|
494
|
+
];
|
|
495
|
+
var demo = ({ delay = 75, items = defaultItems } = {}) => {
|
|
496
|
+
let t;
|
|
497
|
+
let idx = 0;
|
|
498
|
+
return [
|
|
499
|
+
keymap3.of([
|
|
500
|
+
{
|
|
501
|
+
// Reset.
|
|
502
|
+
key: "alt-meta-'",
|
|
503
|
+
run: (view) => {
|
|
504
|
+
clearTimeout(t);
|
|
505
|
+
idx = 0;
|
|
506
|
+
return true;
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
{
|
|
510
|
+
// Next prompt.
|
|
511
|
+
// TODO(burdon): Press 1-9 to select prompt?
|
|
512
|
+
key: "shift-meta-'",
|
|
513
|
+
run: (view) => {
|
|
514
|
+
clearTimeout(t);
|
|
515
|
+
const text = items[idx++];
|
|
516
|
+
if (idx === items?.length) {
|
|
517
|
+
idx = 0;
|
|
518
|
+
}
|
|
519
|
+
let i = 0;
|
|
520
|
+
const insert = (d = 0) => {
|
|
521
|
+
t = setTimeout(() => {
|
|
522
|
+
const pos = view.state.selection.main.head;
|
|
523
|
+
view.dispatch({
|
|
524
|
+
changes: {
|
|
525
|
+
from: pos,
|
|
526
|
+
insert: text[i++]
|
|
527
|
+
},
|
|
528
|
+
selection: {
|
|
529
|
+
anchor: pos + 1
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
if (i < text.length) {
|
|
533
|
+
insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
|
|
534
|
+
}
|
|
535
|
+
}, d);
|
|
536
|
+
};
|
|
537
|
+
insert();
|
|
538
|
+
return true;
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
])
|
|
542
|
+
];
|
|
543
|
+
};
|
|
544
|
+
|
|
545
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
546
|
+
import { keymap as keymap4, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
547
|
+
import { debounce } from "@dxos/async";
|
|
548
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
549
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
|
|
550
|
+
var styles2 = EditorView4.baseTheme({
|
|
551
|
+
"& .cm-bookmark": {
|
|
552
|
+
cursor: "pointer",
|
|
553
|
+
margin: "4px",
|
|
554
|
+
padding: "4px",
|
|
555
|
+
backgroundColor: "yellow"
|
|
556
|
+
},
|
|
557
|
+
"& .cm-bookmark-selected": {
|
|
558
|
+
backgroundColor: "orange"
|
|
559
|
+
}
|
|
560
|
+
});
|
|
561
|
+
var BookmarkWidget = class extends WidgetType {
|
|
562
|
+
constructor(_pos, _id, _handleClick) {
|
|
563
|
+
super();
|
|
564
|
+
this._pos = _pos;
|
|
565
|
+
this._id = _id;
|
|
566
|
+
this._handleClick = _handleClick;
|
|
567
|
+
invariant2(this._id, void 0, {
|
|
568
|
+
F: __dxlog_file2,
|
|
569
|
+
L: 37,
|
|
570
|
+
S: this,
|
|
571
|
+
A: [
|
|
572
|
+
"this._id",
|
|
573
|
+
""
|
|
574
|
+
]
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
eq(other) {
|
|
578
|
+
return this._id === other._id;
|
|
579
|
+
}
|
|
580
|
+
toDOM() {
|
|
581
|
+
const span = document.createElement("span");
|
|
582
|
+
span.className = "cm-bookmark";
|
|
583
|
+
span.textContent = "\xA7";
|
|
584
|
+
span.onclick = () => this._handleClick();
|
|
585
|
+
return span;
|
|
586
|
+
}
|
|
587
|
+
};
|
|
588
|
+
var comments = (options = {}) => {
|
|
589
|
+
let active;
|
|
590
|
+
const bookmarkMatcher = new MatchDecorator({
|
|
591
|
+
regexp: /\[\^(\w+)\]/g,
|
|
592
|
+
decoration: (match, view, pos) => {
|
|
593
|
+
const id = match[1];
|
|
594
|
+
return Decoration2.replace({
|
|
595
|
+
id,
|
|
596
|
+
widget: new BookmarkWidget(pos, id, () => handleUpdate({
|
|
597
|
+
active: id
|
|
598
|
+
}))
|
|
599
|
+
});
|
|
600
|
+
}
|
|
601
|
+
});
|
|
602
|
+
const bookmarks = ViewPlugin2.fromClass(class {
|
|
603
|
+
constructor(view) {
|
|
604
|
+
this.bookmarks = bookmarkMatcher.createDeco(view);
|
|
605
|
+
}
|
|
606
|
+
update(update4) {
|
|
607
|
+
this.bookmarks = bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
608
|
+
}
|
|
609
|
+
}, {
|
|
610
|
+
decorations: (instance) => instance.bookmarks,
|
|
611
|
+
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
612
|
+
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
613
|
+
})
|
|
614
|
+
});
|
|
615
|
+
const handleUpdate = debounce((data) => {
|
|
616
|
+
options.onUpdate?.(data);
|
|
617
|
+
}, 200);
|
|
618
|
+
return [
|
|
619
|
+
keymap4.of([
|
|
620
|
+
{
|
|
621
|
+
key: options?.key ?? "shift-meta-c",
|
|
622
|
+
run: (view) => {
|
|
623
|
+
const { from, to, head } = view.state.selection.main;
|
|
624
|
+
const id = options.onCreate?.(from, to);
|
|
625
|
+
if (id) {
|
|
626
|
+
const tag = `[^${id}]`;
|
|
627
|
+
view.dispatch({
|
|
628
|
+
changes: {
|
|
629
|
+
from: head,
|
|
630
|
+
insert: tag
|
|
631
|
+
},
|
|
632
|
+
selection: {
|
|
633
|
+
anchor: head + tag.length
|
|
634
|
+
}
|
|
635
|
+
});
|
|
636
|
+
return true;
|
|
637
|
+
}
|
|
638
|
+
return false;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
]),
|
|
642
|
+
bookmarks,
|
|
643
|
+
// Monitor cursor movement.
|
|
644
|
+
EditorView4.updateListener.of((update4) => {
|
|
645
|
+
active = void 0;
|
|
646
|
+
if (!options.onUpdate) {
|
|
647
|
+
return;
|
|
648
|
+
}
|
|
649
|
+
const { view, state } = update4;
|
|
650
|
+
const pos = state.selection.main.head;
|
|
651
|
+
const decorations = [];
|
|
652
|
+
const rangeSet = view.plugin(bookmarks)?.bookmarks;
|
|
653
|
+
let closest = Infinity;
|
|
654
|
+
const { from, to } = (
|
|
655
|
+
/* view.visibleRanges?.[0] ?? */
|
|
656
|
+
{
|
|
657
|
+
from: 0,
|
|
658
|
+
to: state.doc.length
|
|
659
|
+
}
|
|
660
|
+
);
|
|
661
|
+
rangeSet?.between(from, to, (from2, to2, value) => {
|
|
662
|
+
decorations.push({
|
|
663
|
+
from: from2,
|
|
664
|
+
to: to2,
|
|
665
|
+
value
|
|
666
|
+
});
|
|
667
|
+
const d = Math.min(Math.abs(pos - from2), Math.abs(pos - to2));
|
|
668
|
+
if (d < closest) {
|
|
669
|
+
active = value.spec.id;
|
|
670
|
+
closest = d;
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
if (decorations.length) {
|
|
674
|
+
handleUpdate({
|
|
675
|
+
active,
|
|
676
|
+
items: decorations.map(({ from: from2, value: { spec: { id } } }) => ({
|
|
677
|
+
id,
|
|
678
|
+
pos: from2,
|
|
679
|
+
location: view.coordsAtPos(from2)
|
|
680
|
+
}))
|
|
681
|
+
});
|
|
682
|
+
}
|
|
683
|
+
}),
|
|
684
|
+
styles2
|
|
685
|
+
];
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/highlight.ts
|
|
689
|
+
import { StateEffect, StateField } from "@codemirror/state";
|
|
690
|
+
import { Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
|
|
691
|
+
import sortBy from "lodash.sortby";
|
|
692
|
+
import { useEffect } from "react";
|
|
693
|
+
var styles3 = EditorView5.baseTheme({
|
|
694
|
+
"& .cm-highlight": {
|
|
695
|
+
backgroundColor: "yellow"
|
|
696
|
+
},
|
|
697
|
+
"& .cm-highlight::before": {
|
|
698
|
+
content: "]"
|
|
699
|
+
},
|
|
700
|
+
"& .cm-highlight-active": {
|
|
701
|
+
backgroundColor: "lime"
|
|
702
|
+
}
|
|
703
|
+
});
|
|
704
|
+
var marks = {
|
|
705
|
+
highlight: Decoration3.mark({
|
|
706
|
+
class: "cm-highlight"
|
|
707
|
+
}),
|
|
708
|
+
HighlightActive: Decoration3.mark({
|
|
709
|
+
class: "cm-highlight-active"
|
|
710
|
+
})
|
|
711
|
+
};
|
|
712
|
+
var setHighlights = StateEffect.define();
|
|
713
|
+
var useHighlights = (view, ranges = []) => {
|
|
714
|
+
useEffect(() => {
|
|
715
|
+
view?.dispatch({
|
|
716
|
+
effects: setHighlights.of(ranges)
|
|
717
|
+
});
|
|
718
|
+
}, [
|
|
719
|
+
view,
|
|
720
|
+
ranges
|
|
721
|
+
]);
|
|
722
|
+
};
|
|
723
|
+
var highlightStateField = StateField.define({
|
|
724
|
+
create: () => [],
|
|
725
|
+
update: (threads, tr) => {
|
|
726
|
+
for (const effect of tr.effects) {
|
|
727
|
+
if (effect.is(setHighlights)) {
|
|
728
|
+
return effect.value;
|
|
729
|
+
}
|
|
730
|
+
}
|
|
731
|
+
return threads;
|
|
732
|
+
}
|
|
733
|
+
});
|
|
734
|
+
var highlightDecorations = EditorView5.decorations.compute([
|
|
735
|
+
highlightStateField
|
|
736
|
+
], (state) => {
|
|
737
|
+
const selectionRanges = state.field(highlightStateField);
|
|
738
|
+
const decorations = sortBy(selectionRanges ?? [], (selection) => selection.from)?.flatMap((selection) => {
|
|
739
|
+
const range = {
|
|
740
|
+
from: selection.from,
|
|
741
|
+
to: selection.to + 1
|
|
742
|
+
};
|
|
743
|
+
if (selection.to > selection.from) {
|
|
744
|
+
if (selection.active) {
|
|
745
|
+
return marks.HighlightActive.range(range.from, range.to);
|
|
746
|
+
} else {
|
|
747
|
+
return marks.highlight.range(range.from, range.to);
|
|
748
|
+
}
|
|
749
|
+
} else {
|
|
750
|
+
return [];
|
|
751
|
+
}
|
|
752
|
+
}) ?? [];
|
|
753
|
+
return Decoration3.set(decorations);
|
|
754
|
+
});
|
|
755
|
+
var listener = (options) => {
|
|
756
|
+
return EditorView5.updateListener.of((update4) => {
|
|
757
|
+
const { view, state } = update4;
|
|
758
|
+
const { head } = state.selection.main;
|
|
759
|
+
const ranges = state.field(highlightStateField);
|
|
760
|
+
let mod = false;
|
|
761
|
+
const newRanges = ranges.map((range) => {
|
|
762
|
+
const active = head >= range.from && head <= range.to;
|
|
763
|
+
if (active !== range.active) {
|
|
764
|
+
mod = true;
|
|
765
|
+
return {
|
|
766
|
+
...range,
|
|
767
|
+
active
|
|
768
|
+
};
|
|
769
|
+
} else {
|
|
770
|
+
return range;
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
if (mod) {
|
|
774
|
+
view.dispatch({
|
|
775
|
+
effects: setHighlights.of(newRanges)
|
|
776
|
+
});
|
|
777
|
+
options?.onChange?.(newRanges.find((range) => range.active)?.id);
|
|
778
|
+
}
|
|
779
|
+
});
|
|
780
|
+
};
|
|
781
|
+
var highlight = (options = {}) => {
|
|
782
|
+
return [
|
|
783
|
+
highlightStateField,
|
|
784
|
+
highlightDecorations,
|
|
785
|
+
listener(options),
|
|
786
|
+
styles3
|
|
787
|
+
];
|
|
788
|
+
};
|
|
789
|
+
|
|
790
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/image.ts
|
|
58
791
|
import { syntaxTree } from "@codemirror/language";
|
|
59
|
-
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
60
|
-
import { Decoration, EditorView as
|
|
61
|
-
var
|
|
792
|
+
import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
|
|
793
|
+
import { Decoration as Decoration4, EditorView as EditorView6, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
794
|
+
var image = (options = {}) => {
|
|
795
|
+
return StateField2.define({
|
|
796
|
+
create: (state) => update(state, options),
|
|
797
|
+
update: (_, tr) => update(tr.state, options),
|
|
798
|
+
provide: (field) => EditorView6.decorations.from(field)
|
|
799
|
+
});
|
|
800
|
+
};
|
|
801
|
+
var update = (state, options) => {
|
|
802
|
+
const builder = new RangeSetBuilder();
|
|
803
|
+
const cursor = state.selection.main.head;
|
|
804
|
+
syntaxTree(state).iterate({
|
|
805
|
+
enter: (node) => {
|
|
806
|
+
if (node.name === "Image") {
|
|
807
|
+
const urlNode = node.node.getChild("URL");
|
|
808
|
+
if (urlNode) {
|
|
809
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
810
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
811
|
+
builder.add(hide ? node.from : node.to, node.to, Decoration4.replace({
|
|
812
|
+
widget: new ImageWidget(url)
|
|
813
|
+
}));
|
|
814
|
+
}
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
|
+
return builder.finish();
|
|
819
|
+
};
|
|
820
|
+
var ImageWidget = class extends WidgetType2 {
|
|
821
|
+
constructor(_url) {
|
|
822
|
+
super();
|
|
823
|
+
this._url = _url;
|
|
824
|
+
}
|
|
825
|
+
eq(other) {
|
|
826
|
+
return this._url === other?._url;
|
|
827
|
+
}
|
|
828
|
+
toDOM(view) {
|
|
829
|
+
const img = document.createElement("img");
|
|
830
|
+
img.setAttribute("src", this._url);
|
|
831
|
+
img.setAttribute("class", "cm-image");
|
|
832
|
+
return img;
|
|
833
|
+
}
|
|
834
|
+
};
|
|
835
|
+
|
|
836
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
837
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
838
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField3 } from "@codemirror/state";
|
|
839
|
+
import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
840
|
+
var link = (options = {}) => {
|
|
841
|
+
return StateField3.define({
|
|
842
|
+
create: (state) => update2(state, options),
|
|
843
|
+
update: (_, tr) => update2(tr.state, options),
|
|
844
|
+
provide: (field) => EditorView7.decorations.from(field)
|
|
845
|
+
});
|
|
846
|
+
};
|
|
847
|
+
var LinkButton = class extends WidgetType3 {
|
|
62
848
|
constructor(_pos, _url, _onAttach) {
|
|
63
849
|
super();
|
|
64
850
|
this._pos = _pos;
|
|
@@ -74,7 +860,7 @@ var LinkButton = class extends WidgetType {
|
|
|
74
860
|
return el;
|
|
75
861
|
}
|
|
76
862
|
};
|
|
77
|
-
var LinkText = class extends
|
|
863
|
+
var LinkText = class extends WidgetType3 {
|
|
78
864
|
constructor(_pos, _text, _url) {
|
|
79
865
|
super();
|
|
80
866
|
this._pos = _pos;
|
|
@@ -104,281 +890,276 @@ var LinkText = class extends WidgetType {
|
|
|
104
890
|
return link2;
|
|
105
891
|
}
|
|
106
892
|
};
|
|
107
|
-
var
|
|
108
|
-
const builder = new
|
|
893
|
+
var update2 = (state, options) => {
|
|
894
|
+
const builder = new RangeSetBuilder2();
|
|
109
895
|
const cursor = state.selection.main.head;
|
|
110
|
-
|
|
896
|
+
syntaxTree2(state).iterate({
|
|
111
897
|
enter: (node) => {
|
|
112
898
|
if (node.name === "Link") {
|
|
113
|
-
const
|
|
114
|
-
const text =
|
|
899
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
900
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
115
901
|
const urlNode = node.node.getChild("URL");
|
|
116
902
|
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
117
|
-
if (
|
|
118
|
-
|
|
903
|
+
if (!url) {
|
|
904
|
+
return false;
|
|
905
|
+
}
|
|
906
|
+
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
907
|
+
builder.add(node.from, node.to, Decoration5.replace({
|
|
119
908
|
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
120
909
|
}));
|
|
121
910
|
}
|
|
122
911
|
if (options.onRender) {
|
|
123
|
-
builder.add(node.to, node.to,
|
|
912
|
+
builder.add(node.to, node.to, Decoration5.replace({
|
|
124
913
|
widget: new LinkButton(node.from, url, options.onRender)
|
|
125
914
|
}));
|
|
126
915
|
}
|
|
916
|
+
return false;
|
|
127
917
|
}
|
|
128
|
-
return true;
|
|
129
918
|
}
|
|
130
919
|
});
|
|
131
920
|
return builder.finish();
|
|
132
921
|
};
|
|
133
|
-
var link = (options = {}) => {
|
|
134
|
-
return StateField.define({
|
|
135
|
-
create: (state) => update(state, options),
|
|
136
|
-
update: (_, tr) => update(tr.state, options),
|
|
137
|
-
provide: (field) => EditorView2.decorations.from(field)
|
|
138
|
-
});
|
|
139
|
-
};
|
|
140
922
|
|
|
141
923
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
142
|
-
import { StateField as
|
|
143
|
-
var
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
924
|
+
import { StateField as StateField4 } from "@codemirror/state";
|
|
925
|
+
var listener2 = ({ onChange }) => {
|
|
926
|
+
return StateField4.define({
|
|
927
|
+
create: () => null,
|
|
928
|
+
update: (_value, transaction) => {
|
|
929
|
+
if (transaction.docChanged && onChange) {
|
|
930
|
+
onChange(transaction.newDoc.toString());
|
|
931
|
+
}
|
|
932
|
+
return null;
|
|
148
933
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
934
|
+
});
|
|
935
|
+
};
|
|
152
936
|
|
|
153
937
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
154
938
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
155
|
-
import {
|
|
156
|
-
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
157
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2,
|
|
158
|
-
import { languages } from "@codemirror/language-data";
|
|
159
|
-
import {
|
|
160
|
-
import {
|
|
161
|
-
import {
|
|
162
|
-
import {
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
import {
|
|
167
|
-
import {
|
|
168
|
-
import {
|
|
169
|
-
import
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
194
|
-
var tokens = tailwindConfig({}).theme;
|
|
195
|
-
|
|
196
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
197
|
-
var markdownTags = {
|
|
198
|
-
Blockquote: Tag.define(),
|
|
199
|
-
CodeMark: Tag.define(),
|
|
200
|
-
CodeText: Tag.define(),
|
|
201
|
-
EmphasisMark: Tag.define(),
|
|
202
|
-
HeaderMark: Tag.define(),
|
|
203
|
-
HorizontalRule: Tag.define(),
|
|
204
|
-
InlineCode: Tag.define(),
|
|
205
|
-
LinkLabel: Tag.define(),
|
|
206
|
-
LinkReference: Tag.define(),
|
|
207
|
-
ListMark: Tag.define(),
|
|
208
|
-
QuoteMark: Tag.define(),
|
|
209
|
-
URL: Tag.define()
|
|
210
|
-
};
|
|
211
|
-
var markdownTagsExtension = {
|
|
212
|
-
props: [
|
|
213
|
-
styleTags(markdownTags)
|
|
214
|
-
]
|
|
215
|
-
};
|
|
216
|
-
var markdownHighlightStyle = HighlightStyle.define([
|
|
217
|
-
{
|
|
218
|
-
tag: [
|
|
219
|
-
tags.keyword,
|
|
220
|
-
tags.name,
|
|
221
|
-
tags.deleted,
|
|
222
|
-
tags.character,
|
|
223
|
-
tags.propertyName,
|
|
224
|
-
tags.macroName,
|
|
225
|
-
tags.color,
|
|
226
|
-
tags.constant(tags.name),
|
|
227
|
-
tags.standard(tags.name),
|
|
228
|
-
tags.definition(tags.name),
|
|
229
|
-
tags.separator,
|
|
230
|
-
tags.typeName,
|
|
231
|
-
tags.className,
|
|
232
|
-
tags.number,
|
|
233
|
-
tags.changed,
|
|
234
|
-
tags.annotation,
|
|
235
|
-
tags.modifier,
|
|
236
|
-
tags.self,
|
|
237
|
-
tags.namespace,
|
|
238
|
-
tags.operator,
|
|
239
|
-
tags.operatorKeyword,
|
|
240
|
-
tags.escape,
|
|
241
|
-
tags.regexp,
|
|
242
|
-
tags.special(tags.string),
|
|
243
|
-
tags.meta,
|
|
244
|
-
tags.comment,
|
|
245
|
-
tags.atom,
|
|
246
|
-
tags.bool,
|
|
247
|
-
tags.special(tags.variableName),
|
|
248
|
-
tags.processingInstruction,
|
|
249
|
-
tags.string,
|
|
250
|
-
tags.inserted,
|
|
251
|
-
tags.invalid
|
|
252
|
-
],
|
|
253
|
-
color: "inherit !important"
|
|
254
|
-
},
|
|
255
|
-
// Markdown marks.
|
|
256
|
-
{
|
|
257
|
-
tag: [
|
|
258
|
-
tags.meta,
|
|
259
|
-
tags.processingInstruction,
|
|
260
|
-
markdownTags.CodeMark,
|
|
261
|
-
markdownTags.EmphasisMark,
|
|
262
|
-
markdownTags.HeaderMark,
|
|
263
|
-
markdownTags.LinkLabel,
|
|
264
|
-
markdownTags.LinkReference,
|
|
265
|
-
markdownTags.ListMark,
|
|
266
|
-
markdownTags.QuoteMark
|
|
267
|
-
],
|
|
268
|
-
class: mark
|
|
269
|
-
},
|
|
270
|
-
// Headings.
|
|
271
|
-
{
|
|
272
|
-
tag: tags.heading1,
|
|
273
|
-
class: heading[1]
|
|
274
|
-
},
|
|
275
|
-
{
|
|
276
|
-
tag: tags.heading2,
|
|
277
|
-
class: heading[2]
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
tag: tags.heading3,
|
|
281
|
-
class: heading[3]
|
|
282
|
-
},
|
|
283
|
-
{
|
|
284
|
-
tag: tags.heading4,
|
|
285
|
-
class: heading[4]
|
|
286
|
-
},
|
|
287
|
-
{
|
|
288
|
-
tag: tags.heading5,
|
|
289
|
-
class: heading[5]
|
|
290
|
-
},
|
|
291
|
-
{
|
|
292
|
-
tag: tags.heading6,
|
|
293
|
-
class: heading[6]
|
|
294
|
-
},
|
|
295
|
-
// Emphasis.
|
|
296
|
-
{
|
|
297
|
-
tag: tags.emphasis,
|
|
298
|
-
class: italic
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
tag: tags.strong,
|
|
302
|
-
class: bold
|
|
303
|
-
},
|
|
304
|
-
{
|
|
305
|
-
tag: tags.strikethrough,
|
|
306
|
-
class: strikethrough
|
|
307
|
-
},
|
|
308
|
-
// Naked URLs.
|
|
309
|
-
{
|
|
310
|
-
tag: [
|
|
311
|
-
markdownTags.URL
|
|
312
|
-
],
|
|
313
|
-
class: inlineUrl
|
|
314
|
-
},
|
|
315
|
-
// E.g., code block language (after ```).
|
|
316
|
-
{
|
|
317
|
-
tag: [
|
|
318
|
-
tags.function(tags.variableName),
|
|
319
|
-
tags.labelName
|
|
320
|
-
],
|
|
321
|
-
class: codeMark
|
|
322
|
-
},
|
|
323
|
-
// The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
324
|
-
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
325
|
-
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
326
|
-
// the code, but all other CSS properties will be inherited.
|
|
327
|
-
{
|
|
328
|
-
tag: [
|
|
329
|
-
markdownTags.CodeText,
|
|
330
|
-
markdownTags.InlineCode
|
|
331
|
-
],
|
|
332
|
-
class: code
|
|
333
|
-
},
|
|
334
|
-
{
|
|
335
|
-
tag: [
|
|
336
|
-
markdownTags.QuoteMark
|
|
337
|
-
],
|
|
338
|
-
class: blockquote
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
tag: [
|
|
342
|
-
markdownTags.HorizontalRule
|
|
343
|
-
],
|
|
344
|
-
class: horizontalRule
|
|
345
|
-
}
|
|
346
|
-
], {
|
|
347
|
-
scope: markdownLanguage,
|
|
348
|
-
all: {
|
|
349
|
-
fontFamily: get(tokens, "fontFamily.body", []).join(",")
|
|
939
|
+
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
940
|
+
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
941
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
942
|
+
import { languages } from "@codemirror/language-data";
|
|
943
|
+
import { searchKeymap } from "@codemirror/search";
|
|
944
|
+
import { EditorState } from "@codemirror/state";
|
|
945
|
+
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
946
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView8, highlightActiveLine, keymap as keymap5, placeholder as placeholder2 } from "@codemirror/view";
|
|
947
|
+
|
|
948
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
949
|
+
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
950
|
+
import { HighlightStyle } from "@codemirror/language";
|
|
951
|
+
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
952
|
+
import { Table } from "@lezer/markdown";
|
|
953
|
+
import get2 from "lodash.get";
|
|
954
|
+
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
955
|
+
var markdownTags = {
|
|
956
|
+
Blockquote: Tag.define(),
|
|
957
|
+
CodeMark: Tag.define(),
|
|
958
|
+
CodeText: Tag.define(),
|
|
959
|
+
EmphasisMark: Tag.define(),
|
|
960
|
+
HeaderMark: Tag.define(),
|
|
961
|
+
HorizontalRule: Tag.define(),
|
|
962
|
+
InlineCode: Tag.define(),
|
|
963
|
+
LinkLabel: Tag.define(),
|
|
964
|
+
LinkReference: Tag.define(),
|
|
965
|
+
ListMark: Tag.define(),
|
|
966
|
+
QuoteMark: Tag.define(),
|
|
967
|
+
URL: Tag.define(),
|
|
968
|
+
// Custom.
|
|
969
|
+
TableCell: Tag.define()
|
|
970
|
+
};
|
|
971
|
+
Table.defineNodes?.forEach((node) => {
|
|
972
|
+
switch (node?.name) {
|
|
973
|
+
case "TableCell": {
|
|
974
|
+
node.style = markdownTags.TableCell;
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
350
977
|
}
|
|
351
978
|
});
|
|
979
|
+
var markdownTagsExtensions = [
|
|
980
|
+
Table,
|
|
981
|
+
{
|
|
982
|
+
props: [
|
|
983
|
+
styleTags(markdownTags)
|
|
984
|
+
]
|
|
985
|
+
}
|
|
986
|
+
];
|
|
987
|
+
var markdownHighlightStyle = (readonly) => {
|
|
988
|
+
return HighlightStyle.define([
|
|
989
|
+
{
|
|
990
|
+
tag: [
|
|
991
|
+
tags.keyword,
|
|
992
|
+
tags.name,
|
|
993
|
+
tags.deleted,
|
|
994
|
+
tags.character,
|
|
995
|
+
tags.propertyName,
|
|
996
|
+
tags.macroName,
|
|
997
|
+
tags.color,
|
|
998
|
+
tags.constant(tags.name),
|
|
999
|
+
tags.standard(tags.name),
|
|
1000
|
+
tags.definition(tags.name),
|
|
1001
|
+
tags.separator,
|
|
1002
|
+
tags.typeName,
|
|
1003
|
+
tags.className,
|
|
1004
|
+
tags.number,
|
|
1005
|
+
tags.changed,
|
|
1006
|
+
tags.annotation,
|
|
1007
|
+
tags.modifier,
|
|
1008
|
+
tags.self,
|
|
1009
|
+
tags.namespace,
|
|
1010
|
+
tags.operator,
|
|
1011
|
+
tags.operatorKeyword,
|
|
1012
|
+
tags.escape,
|
|
1013
|
+
tags.regexp,
|
|
1014
|
+
tags.special(tags.string),
|
|
1015
|
+
tags.meta,
|
|
1016
|
+
tags.comment,
|
|
1017
|
+
tags.atom,
|
|
1018
|
+
tags.bool,
|
|
1019
|
+
tags.special(tags.variableName),
|
|
1020
|
+
tags.processingInstruction,
|
|
1021
|
+
tags.string,
|
|
1022
|
+
tags.inserted,
|
|
1023
|
+
tags.invalid
|
|
1024
|
+
],
|
|
1025
|
+
color: "inherit !important"
|
|
1026
|
+
},
|
|
1027
|
+
// Markdown marks.
|
|
1028
|
+
{
|
|
1029
|
+
tag: [
|
|
1030
|
+
tags.meta,
|
|
1031
|
+
tags.processingInstruction,
|
|
1032
|
+
markdownTags.LinkLabel,
|
|
1033
|
+
markdownTags.LinkReference,
|
|
1034
|
+
markdownTags.ListMark
|
|
1035
|
+
],
|
|
1036
|
+
class: mark
|
|
1037
|
+
},
|
|
1038
|
+
// Markdown marks.
|
|
1039
|
+
{
|
|
1040
|
+
tag: [
|
|
1041
|
+
markdownTags.CodeMark,
|
|
1042
|
+
markdownTags.HeaderMark,
|
|
1043
|
+
markdownTags.QuoteMark,
|
|
1044
|
+
markdownTags.EmphasisMark
|
|
1045
|
+
],
|
|
1046
|
+
class: readonly ? "hidden" : mark
|
|
1047
|
+
},
|
|
1048
|
+
// E.g., code block language (after ```).
|
|
1049
|
+
{
|
|
1050
|
+
tag: [
|
|
1051
|
+
tags.function(tags.variableName),
|
|
1052
|
+
tags.labelName
|
|
1053
|
+
],
|
|
1054
|
+
class: readonly ? "hidden" : codeMark
|
|
1055
|
+
},
|
|
1056
|
+
{
|
|
1057
|
+
tag: [
|
|
1058
|
+
tags.monospace
|
|
1059
|
+
],
|
|
1060
|
+
class: "font-mono"
|
|
1061
|
+
},
|
|
1062
|
+
// Headings.
|
|
1063
|
+
{
|
|
1064
|
+
tag: tags.heading1,
|
|
1065
|
+
class: heading(1, readonly)
|
|
1066
|
+
},
|
|
1067
|
+
{
|
|
1068
|
+
tag: tags.heading2,
|
|
1069
|
+
class: heading(2, readonly)
|
|
1070
|
+
},
|
|
1071
|
+
{
|
|
1072
|
+
tag: tags.heading3,
|
|
1073
|
+
class: heading(3, readonly)
|
|
1074
|
+
},
|
|
1075
|
+
{
|
|
1076
|
+
tag: tags.heading4,
|
|
1077
|
+
class: heading(4, readonly)
|
|
1078
|
+
},
|
|
1079
|
+
{
|
|
1080
|
+
tag: tags.heading5,
|
|
1081
|
+
class: heading(5, readonly)
|
|
1082
|
+
},
|
|
1083
|
+
{
|
|
1084
|
+
tag: tags.heading6,
|
|
1085
|
+
class: heading(6, readonly)
|
|
1086
|
+
},
|
|
1087
|
+
// Emphasis.
|
|
1088
|
+
{
|
|
1089
|
+
tag: tags.emphasis,
|
|
1090
|
+
class: italic
|
|
1091
|
+
},
|
|
1092
|
+
{
|
|
1093
|
+
tag: tags.strong,
|
|
1094
|
+
class: bold
|
|
1095
|
+
},
|
|
1096
|
+
{
|
|
1097
|
+
tag: tags.strikethrough,
|
|
1098
|
+
class: strikethrough
|
|
1099
|
+
},
|
|
1100
|
+
// Naked URLs.
|
|
1101
|
+
{
|
|
1102
|
+
tag: [
|
|
1103
|
+
markdownTags.URL
|
|
1104
|
+
],
|
|
1105
|
+
class: inlineUrl
|
|
1106
|
+
},
|
|
1107
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
1108
|
+
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
1109
|
+
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
1110
|
+
// the code, but all other CSS properties will be inherited.
|
|
1111
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
1112
|
+
{
|
|
1113
|
+
tag: [
|
|
1114
|
+
markdownTags.CodeText,
|
|
1115
|
+
markdownTags.InlineCode
|
|
1116
|
+
],
|
|
1117
|
+
class: code
|
|
1118
|
+
},
|
|
1119
|
+
{
|
|
1120
|
+
tag: [
|
|
1121
|
+
markdownTags.QuoteMark
|
|
1122
|
+
],
|
|
1123
|
+
class: blockquote
|
|
1124
|
+
},
|
|
1125
|
+
// TODO(burdon): Replace with extension.
|
|
1126
|
+
{
|
|
1127
|
+
tag: [
|
|
1128
|
+
markdownTags.HorizontalRule
|
|
1129
|
+
],
|
|
1130
|
+
class: mx3(horizontalRule, readonly && "-indent-[100rem]")
|
|
1131
|
+
},
|
|
1132
|
+
// TODO(burdon): Only if being edited.
|
|
1133
|
+
{
|
|
1134
|
+
tag: [
|
|
1135
|
+
markdownTags.TableCell
|
|
1136
|
+
],
|
|
1137
|
+
class: "font-mono"
|
|
1138
|
+
}
|
|
1139
|
+
], {
|
|
1140
|
+
scope: markdownLanguage,
|
|
1141
|
+
all: {
|
|
1142
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
1143
|
+
}
|
|
1144
|
+
});
|
|
1145
|
+
};
|
|
352
1146
|
|
|
353
1147
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
354
|
-
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1148
|
+
var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
355
1149
|
return [
|
|
1150
|
+
EditorState.allowMultipleSelections.of(true),
|
|
1151
|
+
EditorState.tabSize.of(2),
|
|
1152
|
+
EditorView8.lineWrapping,
|
|
1153
|
+
customKeymap(),
|
|
356
1154
|
bracketMatching2(),
|
|
357
1155
|
closeBrackets2(),
|
|
358
|
-
_placeholder && placeholder2(_placeholder),
|
|
359
|
-
EditorState.allowMultipleSelections.of(true),
|
|
360
|
-
EditorView3.lineWrapping,
|
|
361
|
-
// autocompletion(),
|
|
362
1156
|
crosshairCursor(),
|
|
363
1157
|
dropCursor(),
|
|
364
|
-
|
|
1158
|
+
drawSelection2(),
|
|
365
1159
|
highlightActiveLine(),
|
|
366
|
-
highlightActiveLineGutter(),
|
|
367
|
-
highlightSelectionMatches(),
|
|
368
|
-
highlightSpecialChars(),
|
|
369
1160
|
history(),
|
|
370
1161
|
indentOnInput(),
|
|
371
|
-
|
|
372
|
-
keymap2.of([
|
|
373
|
-
...closeBracketsKeymap,
|
|
374
|
-
// ...completionKeymap,
|
|
375
|
-
...defaultKeymap,
|
|
376
|
-
...foldKeymap,
|
|
377
|
-
...historyKeymap,
|
|
378
|
-
...lintKeymap,
|
|
379
|
-
...searchKeymap,
|
|
380
|
-
indentWithTab
|
|
381
|
-
]),
|
|
1162
|
+
_placeholder && placeholder2(_placeholder),
|
|
382
1163
|
// Main extension.
|
|
383
1164
|
// https://github.com/codemirror/lang-markdown
|
|
384
1165
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -393,102 +1174,231 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
393
1174
|
codeLanguages: languages,
|
|
394
1175
|
// Parser extensions.
|
|
395
1176
|
extensions: [
|
|
396
|
-
// GFM
|
|
397
|
-
|
|
1177
|
+
// GFM provided by default.
|
|
1178
|
+
markdownTagsExtensions
|
|
398
1179
|
]
|
|
399
1180
|
}),
|
|
1181
|
+
// https://github.com/codemirror/theme-one-dark
|
|
1182
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
400
1183
|
// Custom styles.
|
|
401
|
-
syntaxHighlighting2(markdownHighlightStyle)
|
|
402
|
-
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
403
|
-
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
1184
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
404
1185
|
].filter(Boolean);
|
|
405
1186
|
};
|
|
1187
|
+
var customKeymap = () => keymap5.of([
|
|
1188
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1189
|
+
indentWithTab,
|
|
1190
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1191
|
+
...standardKeymap,
|
|
1192
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1193
|
+
...historyKeymap,
|
|
1194
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1195
|
+
...closeBracketsKeymap,
|
|
1196
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1197
|
+
...searchKeymap
|
|
1198
|
+
]);
|
|
1199
|
+
|
|
1200
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
|
|
1201
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1202
|
+
var mention = ({ onSearch }) => {
|
|
1203
|
+
return autocompletion2({
|
|
1204
|
+
closeOnBlur: false,
|
|
1205
|
+
override: [
|
|
1206
|
+
(context) => {
|
|
1207
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
1208
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
console.log(match);
|
|
1212
|
+
return {
|
|
1213
|
+
from: match.from,
|
|
1214
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1215
|
+
label: `@${value}`
|
|
1216
|
+
}))
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
]
|
|
1220
|
+
});
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/table.ts
|
|
1224
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1225
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
|
|
1226
|
+
import { Decoration as Decoration6, EditorView as EditorView9, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1227
|
+
var table = (options = {}) => {
|
|
1228
|
+
return StateField5.define({
|
|
1229
|
+
create: (state) => update3(state, options),
|
|
1230
|
+
update: (_, tr) => update3(tr.state, options),
|
|
1231
|
+
provide: (field) => EditorView9.decorations.from(field)
|
|
1232
|
+
});
|
|
1233
|
+
};
|
|
1234
|
+
var update3 = (state, options) => {
|
|
1235
|
+
const builder = new RangeSetBuilder3();
|
|
1236
|
+
const cursor = state.selection.main.head;
|
|
1237
|
+
const tables = [];
|
|
1238
|
+
const getTable = () => tables[tables.length - 1];
|
|
1239
|
+
const getRow = () => {
|
|
1240
|
+
const table2 = getTable();
|
|
1241
|
+
return table2.rows?.[table2.rows.length - 1];
|
|
1242
|
+
};
|
|
1243
|
+
syntaxTree3(state).iterate({
|
|
1244
|
+
enter: (node) => {
|
|
1245
|
+
switch (node.name) {
|
|
1246
|
+
case "Table": {
|
|
1247
|
+
tables.push({
|
|
1248
|
+
from: node.from,
|
|
1249
|
+
to: node.to
|
|
1250
|
+
});
|
|
1251
|
+
break;
|
|
1252
|
+
}
|
|
1253
|
+
case "TableHeader": {
|
|
1254
|
+
getTable().header = [];
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
case "TableRow": {
|
|
1258
|
+
(getTable().rows ??= []).push([]);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
case "TableCell": {
|
|
1262
|
+
const row = getRow();
|
|
1263
|
+
if (row) {
|
|
1264
|
+
row.push(state.sliceDoc(node.from, node.to));
|
|
1265
|
+
} else {
|
|
1266
|
+
getTable().header?.push(state.sliceDoc(node.from, node.to));
|
|
1267
|
+
}
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
tables.forEach((table2) => {
|
|
1274
|
+
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1275
|
+
hide && builder.add(table2.from, table2.to, Decoration6.replace({
|
|
1276
|
+
widget: new TableWidget(table2)
|
|
1277
|
+
}));
|
|
1278
|
+
builder.add(table2.from, table2.to, Decoration6.mark({
|
|
1279
|
+
class: "cm-table"
|
|
1280
|
+
}));
|
|
1281
|
+
});
|
|
1282
|
+
return builder.finish();
|
|
1283
|
+
};
|
|
1284
|
+
var TableWidget = class extends WidgetType4 {
|
|
1285
|
+
constructor(_table) {
|
|
1286
|
+
super();
|
|
1287
|
+
this._table = _table;
|
|
1288
|
+
}
|
|
1289
|
+
eq(other) {
|
|
1290
|
+
return this._table.from === other?._table?.from;
|
|
1291
|
+
}
|
|
1292
|
+
toDOM(view) {
|
|
1293
|
+
const table2 = document.createElement("table");
|
|
1294
|
+
{
|
|
1295
|
+
const header = table2.appendChild(document.createElement("thead"));
|
|
1296
|
+
const tr = header.appendChild(document.createElement("tr"));
|
|
1297
|
+
this._table.header?.forEach((cell) => {
|
|
1298
|
+
const th = document.createElement("th");
|
|
1299
|
+
th.setAttribute("class", "cm-table-head");
|
|
1300
|
+
tr.appendChild(th).textContent = cell;
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
{
|
|
1304
|
+
const body = table2.appendChild(document.createElement("tbody"));
|
|
1305
|
+
this._table.rows?.forEach((row) => {
|
|
1306
|
+
const tr = body.appendChild(document.createElement("tr"));
|
|
1307
|
+
row.forEach((cell) => {
|
|
1308
|
+
const td = document.createElement("td");
|
|
1309
|
+
td.setAttribute("class", "cm-table-cell");
|
|
1310
|
+
tr.appendChild(td).textContent = cell;
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
return table2;
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
406
1317
|
|
|
407
1318
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
408
|
-
import {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
1319
|
+
import { EditorView as EditorView10, Decoration as Decoration7, WidgetType as WidgetType5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
1320
|
+
var styles4 = EditorView10.baseTheme({
|
|
1321
|
+
"& .cm-task-item": {
|
|
1322
|
+
paddingLeft: "4px",
|
|
1323
|
+
paddingRight: "8px"
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
var CheckboxWidget = class extends WidgetType5 {
|
|
1327
|
+
constructor(_pos, _checked, _indent, _onCheck) {
|
|
413
1328
|
super();
|
|
414
1329
|
this._pos = _pos;
|
|
415
|
-
this._getCursor = _getCursor;
|
|
416
1330
|
this._checked = _checked;
|
|
1331
|
+
this._indent = _indent;
|
|
1332
|
+
this._onCheck = _onCheck;
|
|
417
1333
|
}
|
|
418
1334
|
eq(other) {
|
|
419
|
-
return this._pos === other._pos && this._checked === other._checked;
|
|
1335
|
+
return this._pos === other._pos && this._checked === other._checked && this._indent === other._indent;
|
|
420
1336
|
}
|
|
421
1337
|
toDOM(view) {
|
|
422
1338
|
const wrap = document.createElement("span");
|
|
423
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
424
1339
|
wrap.className = "cm-task-item";
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
}
|
|
440
|
-
});
|
|
441
|
-
return true;
|
|
442
|
-
};
|
|
1340
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
1341
|
+
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
1342
|
+
const input = wrap.appendChild(document.createElement("input"));
|
|
1343
|
+
input.type = "checkbox";
|
|
1344
|
+
input.checked = this._checked;
|
|
1345
|
+
if (!this._onCheck) {
|
|
1346
|
+
input.setAttribute("disabled", "true");
|
|
1347
|
+
}
|
|
1348
|
+
if (this._onCheck) {
|
|
1349
|
+
input.onchange = (event) => {
|
|
1350
|
+
this._onCheck?.(event.target.checked);
|
|
1351
|
+
return true;
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
443
1354
|
return wrap;
|
|
444
1355
|
}
|
|
445
|
-
// TODO(burdon): Remove listener?
|
|
446
|
-
// override destroy() {
|
|
447
|
-
// console.log('destroy', this._pos);
|
|
448
|
-
// }
|
|
449
1356
|
ignoreEvent() {
|
|
450
1357
|
return false;
|
|
451
1358
|
}
|
|
452
1359
|
};
|
|
453
|
-
var
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
1360
|
+
var tasklist = (options = {}) => {
|
|
1361
|
+
const taskMatcher = new MatchDecorator2({
|
|
1362
|
+
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
1363
|
+
decoration: (match, view, pos) => {
|
|
1364
|
+
const indent = Math.floor(match[1].length / 2);
|
|
1365
|
+
const checked = match[2] === "x" || match[2] === "X";
|
|
1366
|
+
return Decoration7.replace({
|
|
1367
|
+
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
1368
|
+
const idx = pos + match[0].indexOf("[") + 1;
|
|
1369
|
+
view.dispatch({
|
|
1370
|
+
changes: {
|
|
1371
|
+
from: idx,
|
|
1372
|
+
to: idx + 1,
|
|
1373
|
+
insert: checked2 ? "x" : " "
|
|
1374
|
+
},
|
|
1375
|
+
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
1376
|
+
selection: {
|
|
1377
|
+
anchor: idx + 3
|
|
1378
|
+
}
|
|
1379
|
+
});
|
|
1380
|
+
})
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
460
1383
|
});
|
|
461
|
-
const
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
return builder.finish();
|
|
473
|
-
};
|
|
474
|
-
return [
|
|
475
|
-
listener2,
|
|
476
|
-
StateField3.define({
|
|
477
|
-
create: (state) => checkbox(state),
|
|
478
|
-
update: (_, tr) => checkbox(tr.state),
|
|
479
|
-
provide: (field) => EditorView4.decorations.from(field)
|
|
1384
|
+
const tasks = ViewPlugin3.fromClass(class {
|
|
1385
|
+
constructor(view) {
|
|
1386
|
+
this.tasks = taskMatcher.createDeco(view);
|
|
1387
|
+
}
|
|
1388
|
+
update(update4) {
|
|
1389
|
+
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
1390
|
+
}
|
|
1391
|
+
}, {
|
|
1392
|
+
decorations: (value) => value.tasks,
|
|
1393
|
+
provide: (plugin) => EditorView10.atomicRanges.of((view) => {
|
|
1394
|
+
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
480
1395
|
})
|
|
1396
|
+
});
|
|
1397
|
+
return [
|
|
1398
|
+
tasks,
|
|
1399
|
+
styles4
|
|
481
1400
|
];
|
|
482
1401
|
};
|
|
483
|
-
var styles = EditorView4.baseTheme({
|
|
484
|
-
"& .cm-task-item": {
|
|
485
|
-
padding: "0 4px"
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
var tasklist = () => [
|
|
489
|
-
statefield(),
|
|
490
|
-
styles
|
|
491
|
-
];
|
|
492
1402
|
|
|
493
1403
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
|
|
494
1404
|
import { hoverTooltip } from "@codemirror/view";
|
|
@@ -535,7 +1445,7 @@ var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view,
|
|
|
535
1445
|
});
|
|
536
1446
|
|
|
537
1447
|
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
538
|
-
import
|
|
1448
|
+
import get3 from "lodash.get";
|
|
539
1449
|
var defaultTheme = {
|
|
540
1450
|
//
|
|
541
1451
|
// Main layout:
|
|
@@ -560,20 +1470,20 @@ var defaultTheme = {
|
|
|
560
1470
|
fontSize: "16px"
|
|
561
1471
|
},
|
|
562
1472
|
"&light .cm-content": {
|
|
563
|
-
color:
|
|
1473
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
564
1474
|
caretColor: "black"
|
|
565
1475
|
},
|
|
566
1476
|
"&dark .cm-content": {
|
|
567
|
-
color:
|
|
1477
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
568
1478
|
caretColor: "white"
|
|
569
1479
|
},
|
|
570
1480
|
//
|
|
571
1481
|
// Cursor
|
|
572
1482
|
//
|
|
573
|
-
"&light .cm-cursor": {
|
|
1483
|
+
"&light .cm-cursor, &light .cm-dropCursor": {
|
|
574
1484
|
borderLeft: "2px solid black"
|
|
575
1485
|
},
|
|
576
|
-
"&dark .cm-cursor": {
|
|
1486
|
+
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
577
1487
|
borderLeft: "2px solid white"
|
|
578
1488
|
},
|
|
579
1489
|
"& .cm-placeholder": {
|
|
@@ -593,16 +1503,16 @@ var defaultTheme = {
|
|
|
593
1503
|
// selection
|
|
594
1504
|
//
|
|
595
1505
|
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
596
|
-
background:
|
|
1506
|
+
background: get3(tokens, "extend.colors.primary.150", "#00ffff")
|
|
597
1507
|
},
|
|
598
1508
|
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
599
|
-
background:
|
|
1509
|
+
background: get3(tokens, "extend.colors.primary.850", "#00ffff")
|
|
600
1510
|
},
|
|
601
1511
|
"&light .cm-selectionMatch": {
|
|
602
|
-
background:
|
|
1512
|
+
background: get3(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
603
1513
|
},
|
|
604
1514
|
"&dark .cm-selectionMatch": {
|
|
605
|
-
background:
|
|
1515
|
+
background: get3(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
606
1516
|
},
|
|
607
1517
|
//
|
|
608
1518
|
// collaboration
|
|
@@ -635,12 +1545,12 @@ var defaultTheme = {
|
|
|
635
1545
|
// link
|
|
636
1546
|
//
|
|
637
1547
|
"& .cm-link": {
|
|
638
|
-
color:
|
|
1548
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
639
1549
|
textDecorationLine: "underline",
|
|
640
1550
|
textDecorationThickness: "1px",
|
|
641
1551
|
textUnderlineOffset: "2px",
|
|
642
1552
|
borderRadius: ".125rem",
|
|
643
|
-
fontFamily:
|
|
1553
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
644
1554
|
},
|
|
645
1555
|
//
|
|
646
1556
|
// tooltip
|
|
@@ -648,14 +1558,61 @@ var defaultTheme = {
|
|
|
648
1558
|
"& .cm-tooltip": {
|
|
649
1559
|
border: "none"
|
|
650
1560
|
},
|
|
651
|
-
|
|
652
|
-
//
|
|
1561
|
+
"& .cm-tooltip-below": {},
|
|
1562
|
+
//
|
|
1563
|
+
// autocomplete
|
|
1564
|
+
//
|
|
1565
|
+
"& .cm-tooltip-autocomplete": {
|
|
1566
|
+
marginTop: "4px",
|
|
1567
|
+
marginLeft: "-3px"
|
|
1568
|
+
},
|
|
1569
|
+
"& .cm-tooltip-autocomplete ul li": {},
|
|
1570
|
+
"& .cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
1571
|
+
"& .cm-completionIcon": {
|
|
1572
|
+
display: "none"
|
|
1573
|
+
},
|
|
1574
|
+
"& .cm-completionLabel": {
|
|
1575
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1576
|
+
},
|
|
1577
|
+
"& .cm-completionMatchedText": {
|
|
1578
|
+
textDecoration: "none"
|
|
1579
|
+
},
|
|
1580
|
+
//
|
|
1581
|
+
// widgets
|
|
1582
|
+
//
|
|
1583
|
+
"& .cm-widgetBuffer": {
|
|
1584
|
+
display: "none",
|
|
1585
|
+
height: 0
|
|
1586
|
+
},
|
|
1587
|
+
//
|
|
1588
|
+
// table
|
|
1589
|
+
//
|
|
1590
|
+
"& .cm-table *": {
|
|
1591
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
1592
|
+
textDecoration: "none !important"
|
|
1593
|
+
},
|
|
1594
|
+
"& .cm-table-head": {
|
|
1595
|
+
padding: "2px 16px 2px 0px",
|
|
1596
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
1597
|
+
fontWeight: 100,
|
|
1598
|
+
textAlign: "left",
|
|
1599
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
1600
|
+
},
|
|
1601
|
+
"& .cm-table-cell": {
|
|
1602
|
+
padding: "2px 16px 2px 0px"
|
|
1603
|
+
},
|
|
1604
|
+
//
|
|
1605
|
+
// image
|
|
1606
|
+
//
|
|
1607
|
+
"& .cm-image": {
|
|
1608
|
+
margin: "0.5rem 0"
|
|
1609
|
+
},
|
|
653
1610
|
//
|
|
654
1611
|
// font size
|
|
655
1612
|
// TODO(thure): This appears to be the best or only way to set selection caret heights, but it's far more verbose than it needs to be.
|
|
656
1613
|
//
|
|
657
|
-
...Object.keys(
|
|
658
|
-
const height =
|
|
1614
|
+
...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
1615
|
+
const height = get3(tokens, [
|
|
659
1616
|
"extend",
|
|
660
1617
|
"fontSize",
|
|
661
1618
|
fontSize,
|
|
@@ -672,43 +1629,101 @@ var defaultTheme = {
|
|
|
672
1629
|
height
|
|
673
1630
|
};
|
|
674
1631
|
return acc;
|
|
675
|
-
}, {})
|
|
1632
|
+
}, {}),
|
|
1633
|
+
/**
|
|
1634
|
+
* Panels
|
|
1635
|
+
* https://github.com/codemirror/search/blob/main/src/search.ts#L745
|
|
1636
|
+
*
|
|
1637
|
+
* Find/replace panel.
|
|
1638
|
+
* <div class="cm-announced">...</div>
|
|
1639
|
+
* <div class="cm-scroller">...</div>
|
|
1640
|
+
* <div class="cm-panels cm-panels-bottom">
|
|
1641
|
+
* <div class="cm-search cm-panel">
|
|
1642
|
+
* <input class="cm-textfield" />
|
|
1643
|
+
* <button class="cm-button">...</button>
|
|
1644
|
+
* <label><input type="checkbox" />...</label>
|
|
1645
|
+
* </div>
|
|
1646
|
+
* </div
|
|
1647
|
+
*/
|
|
1648
|
+
"& .cm-panels": {
|
|
1649
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`,
|
|
1650
|
+
borderBottom: "none"
|
|
1651
|
+
},
|
|
1652
|
+
"& .cm-panel": {
|
|
1653
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
1654
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1655
|
+
},
|
|
1656
|
+
"& .cm-button": {
|
|
1657
|
+
margin: "4px",
|
|
1658
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
1659
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
1660
|
+
border: "none"
|
|
1661
|
+
},
|
|
1662
|
+
"& .cm-searchMatch": {
|
|
1663
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
1664
|
+
},
|
|
1665
|
+
"& .cm-searchMatch.cm-searchMatch-selected": {
|
|
1666
|
+
backgroundColor: get3(tokens, "extend.colors.primary.100")
|
|
1667
|
+
}
|
|
676
1668
|
};
|
|
677
1669
|
var textTheme = {
|
|
678
1670
|
"& .cm-scroller": {
|
|
679
|
-
fontFamily:
|
|
1671
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1672
|
+
},
|
|
1673
|
+
"& .cm-placeholder": {
|
|
1674
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1675
|
+
}
|
|
1676
|
+
};
|
|
1677
|
+
var markdownTheme = {
|
|
1678
|
+
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
1679
|
+
"& .cm-placeholder": {
|
|
1680
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
680
1681
|
}
|
|
681
1682
|
};
|
|
682
1683
|
var codeTheme = {
|
|
683
1684
|
"& .cm-scroller": {
|
|
684
|
-
fontFamily:
|
|
1685
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
1686
|
+
},
|
|
1687
|
+
"& .cm-placeholder": {
|
|
1688
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
685
1689
|
}
|
|
686
1690
|
};
|
|
687
1691
|
|
|
688
1692
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
689
1693
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
690
|
-
import { EditorView as
|
|
1694
|
+
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
691
1695
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
692
1696
|
import { vim } from "@replit/codemirror-vim";
|
|
693
|
-
import
|
|
694
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
695
|
-
import { yCollab } from "y-codemirror.next";
|
|
1697
|
+
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
1698
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
|
|
696
1699
|
import { generateName } from "@dxos/display-name";
|
|
697
1700
|
import { useThemeContext } from "@dxos/react-ui";
|
|
698
|
-
import { getColorForValue, inputSurface, mx as
|
|
1701
|
+
import { getColorForValue, inputSurface, mx as mx4 } from "@dxos/react-ui-theme";
|
|
699
1702
|
var EditorModes = [
|
|
700
1703
|
"default",
|
|
701
1704
|
"vim"
|
|
702
1705
|
];
|
|
703
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots
|
|
1706
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
|
|
704
1707
|
const { themeMode } = useThemeContext();
|
|
705
1708
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
706
1709
|
tabBehavior: "limited"
|
|
707
1710
|
});
|
|
708
|
-
const
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
1711
|
+
const [root, setRoot] = useState(null);
|
|
1712
|
+
const [state, setState] = useState();
|
|
1713
|
+
const [view, setView] = useState();
|
|
1714
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
1715
|
+
root,
|
|
1716
|
+
state,
|
|
1717
|
+
view
|
|
1718
|
+
}), [
|
|
1719
|
+
view,
|
|
1720
|
+
state,
|
|
1721
|
+
root
|
|
1722
|
+
]);
|
|
1723
|
+
const { awareness, peer } = model;
|
|
1724
|
+
useEffect2(() => {
|
|
1725
|
+
if (awareness && peer) {
|
|
1726
|
+
awareness.setLocalStateField("user", {
|
|
712
1727
|
name: peer.name ?? generateName(peer.id),
|
|
713
1728
|
color: getColorForValue({
|
|
714
1729
|
value: peer.id,
|
|
@@ -722,44 +1737,34 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
722
1737
|
});
|
|
723
1738
|
}
|
|
724
1739
|
}, [
|
|
725
|
-
|
|
1740
|
+
awareness,
|
|
726
1741
|
peer,
|
|
727
1742
|
themeMode
|
|
728
1743
|
]);
|
|
729
|
-
|
|
730
|
-
const [state, setState] = useState();
|
|
731
|
-
const [view, setView] = useState();
|
|
732
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
733
|
-
root,
|
|
734
|
-
state,
|
|
735
|
-
view
|
|
736
|
-
}), [
|
|
737
|
-
view,
|
|
738
|
-
state,
|
|
739
|
-
root
|
|
740
|
-
]);
|
|
741
|
-
useEffect(() => {
|
|
1744
|
+
useEffect2(() => {
|
|
742
1745
|
if (!root) {
|
|
743
1746
|
return;
|
|
744
1747
|
}
|
|
745
1748
|
const state2 = EditorState2.create({
|
|
746
1749
|
doc: model.text(),
|
|
747
1750
|
extensions: [
|
|
1751
|
+
readonly && EditorState2.readOnly.of(readonly),
|
|
748
1752
|
// TODO(burdon): Factor out VIM mode?
|
|
749
1753
|
editorMode === "vim" && vim(),
|
|
750
1754
|
// Theme.
|
|
751
|
-
|
|
752
|
-
|
|
1755
|
+
// TODO(burdon): Make optional.
|
|
1756
|
+
EditorView11.baseTheme(defaultTheme),
|
|
1757
|
+
EditorView11.theme(slots?.editor?.theme ?? {}),
|
|
753
1758
|
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
754
|
-
|
|
1759
|
+
EditorView11.darkTheme.of(themeMode === "dark"),
|
|
755
1760
|
// Storage and replication.
|
|
756
|
-
|
|
1761
|
+
model.extension,
|
|
757
1762
|
// Custom.
|
|
758
1763
|
...extensions
|
|
759
1764
|
].filter(Boolean)
|
|
760
1765
|
});
|
|
761
1766
|
view?.destroy();
|
|
762
|
-
setView(new
|
|
1767
|
+
setView(new EditorView11({
|
|
763
1768
|
state: state2,
|
|
764
1769
|
parent: root
|
|
765
1770
|
}));
|
|
@@ -771,8 +1776,9 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
771
1776
|
};
|
|
772
1777
|
}, [
|
|
773
1778
|
root,
|
|
774
|
-
model
|
|
1779
|
+
model,
|
|
775
1780
|
themeMode,
|
|
1781
|
+
readonly,
|
|
776
1782
|
editorMode
|
|
777
1783
|
]);
|
|
778
1784
|
const handleKeyUp = useCallback((event) => {
|
|
@@ -800,13 +1806,15 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
800
1806
|
onKeyUp: handleKeyUp
|
|
801
1807
|
});
|
|
802
1808
|
});
|
|
803
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1809
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
804
1810
|
const { themeMode } = useThemeContext();
|
|
805
|
-
const slots =
|
|
1811
|
+
const slots = defaultsDeep2({}, _slots, defaultTextSlots);
|
|
806
1812
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
807
1813
|
ref: forwardedRef,
|
|
1814
|
+
readonly,
|
|
808
1815
|
extensions: [
|
|
809
1816
|
basicBundle({
|
|
1817
|
+
readonly,
|
|
810
1818
|
themeMode,
|
|
811
1819
|
placeholder: slots?.editor?.placeholder
|
|
812
1820
|
}),
|
|
@@ -816,13 +1824,15 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, .
|
|
|
816
1824
|
...props
|
|
817
1825
|
});
|
|
818
1826
|
});
|
|
819
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1827
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
820
1828
|
const { themeMode } = useThemeContext();
|
|
821
|
-
const slots =
|
|
1829
|
+
const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
|
|
822
1830
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
823
1831
|
ref: forwardedRef,
|
|
1832
|
+
readonly,
|
|
824
1833
|
extensions: [
|
|
825
1834
|
markdownBundle({
|
|
1835
|
+
readonly,
|
|
826
1836
|
themeMode,
|
|
827
1837
|
placeholder: slots?.editor?.placeholder
|
|
828
1838
|
}),
|
|
@@ -834,7 +1844,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slot
|
|
|
834
1844
|
});
|
|
835
1845
|
var defaultSlots = {
|
|
836
1846
|
root: {
|
|
837
|
-
className:
|
|
1847
|
+
className: mx4("p-2", inputSurface)
|
|
838
1848
|
}
|
|
839
1849
|
};
|
|
840
1850
|
var defaultTextSlots = {
|
|
@@ -843,26 +1853,31 @@ var defaultTextSlots = {
|
|
|
843
1853
|
theme: textTheme
|
|
844
1854
|
}
|
|
845
1855
|
};
|
|
1856
|
+
var defaultMarkdownSlots = {
|
|
1857
|
+
...defaultSlots,
|
|
1858
|
+
editor: {
|
|
1859
|
+
theme: markdownTheme
|
|
1860
|
+
}
|
|
1861
|
+
};
|
|
846
1862
|
|
|
847
|
-
// packages/ui/react-ui-editor/src/hooks/
|
|
848
|
-
import
|
|
849
|
-
import {
|
|
850
|
-
import {
|
|
851
|
-
import {
|
|
852
|
-
import {
|
|
853
|
-
import { YText } from "@dxos/text-model";
|
|
1863
|
+
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1864
|
+
import get4 from "lodash.get";
|
|
1865
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
1866
|
+
import { yCollab } from "y-codemirror.next";
|
|
1867
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1868
|
+
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
854
1869
|
|
|
855
|
-
// packages/ui/react-ui-editor/src/
|
|
856
|
-
import { Annotation, Facet, StateEffect, StateField as
|
|
857
|
-
import { ViewPlugin } from "@codemirror/view";
|
|
1870
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
1871
|
+
import { Annotation, Facet, StateEffect as StateEffect2, StateField as StateField6 } from "@codemirror/state";
|
|
1872
|
+
import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
858
1873
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
859
1874
|
|
|
860
|
-
// packages/ui/react-ui-editor/src/
|
|
1875
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
861
1876
|
import { next as automerge } from "@dxos/automerge/automerge";
|
|
862
1877
|
|
|
863
|
-
// packages/ui/react-ui-editor/src/automerge/automerge-
|
|
1878
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/translation/automerge-to-codemirror.ts
|
|
864
1879
|
import { ChangeSet } from "@codemirror/state";
|
|
865
|
-
var
|
|
1880
|
+
var automergeToCodemirror = (view, selection, target, patches) => {
|
|
866
1881
|
for (const patch of patches) {
|
|
867
1882
|
const changeSpec = handlePatch(patch, target, view.state);
|
|
868
1883
|
if (changeSpec != null) {
|
|
@@ -967,9 +1982,9 @@ var charPath = (textPath, candidatePath) => {
|
|
|
967
1982
|
return null;
|
|
968
1983
|
};
|
|
969
1984
|
|
|
970
|
-
// packages/ui/react-ui-editor/src/automerge/automerge
|
|
1985
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/translation/codemirror-to-automerge.ts
|
|
971
1986
|
import { next as am } from "@dxos/automerge/automerge";
|
|
972
|
-
var
|
|
1987
|
+
var codemirrorToAutomerge = (field, handle, transactions, state) => {
|
|
973
1988
|
const { lastHeads, path } = state.field(field);
|
|
974
1989
|
let hasChanges = false;
|
|
975
1990
|
for (const tr of transactions) {
|
|
@@ -990,7 +2005,7 @@ var codeMirrorToAm_default = (field, handle, transactions, state) => {
|
|
|
990
2005
|
return newHeads ?? void 0;
|
|
991
2006
|
};
|
|
992
2007
|
|
|
993
|
-
// packages/ui/react-ui-editor/src/
|
|
2008
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
994
2009
|
var PatchSemaphore = class {
|
|
995
2010
|
constructor(field) {
|
|
996
2011
|
this._inReconcile = false;
|
|
@@ -1013,12 +2028,12 @@ var PatchSemaphore = class {
|
|
|
1013
2028
|
annotations: reconcileAnnotationType.of(true)
|
|
1014
2029
|
});
|
|
1015
2030
|
}
|
|
1016
|
-
let newHeads =
|
|
2031
|
+
let newHeads = codemirrorToAutomerge(this._field, handle, transactions, view.state);
|
|
1017
2032
|
if (newHeads === null || newHeads === void 0) {
|
|
1018
2033
|
newHeads = automerge.getHeads(handle.docSync());
|
|
1019
2034
|
}
|
|
1020
2035
|
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
1021
|
-
|
|
2036
|
+
automergeToCodemirror(view, selection, path, diff);
|
|
1022
2037
|
view.dispatch({
|
|
1023
2038
|
effects: updateHeads(newHeads),
|
|
1024
2039
|
annotations: reconcileAnnotationType.of({})
|
|
@@ -1031,8 +2046,8 @@ var PatchSemaphore = class {
|
|
|
1031
2046
|
}
|
|
1032
2047
|
};
|
|
1033
2048
|
|
|
1034
|
-
// packages/ui/react-ui-editor/src/
|
|
1035
|
-
var effectType =
|
|
2049
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
2050
|
+
var effectType = StateEffect2.define({});
|
|
1036
2051
|
var updateHeads = (newHeads) => effectType.of({
|
|
1037
2052
|
newHeads
|
|
1038
2053
|
});
|
|
@@ -1042,7 +2057,7 @@ var semaphoreFacet = Facet.define({
|
|
|
1042
2057
|
combine: (values) => values.at(-1)
|
|
1043
2058
|
});
|
|
1044
2059
|
var automergePlugin = (handle, path) => {
|
|
1045
|
-
const stateField =
|
|
2060
|
+
const stateField = StateField6.define({
|
|
1046
2061
|
create: () => ({
|
|
1047
2062
|
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
1048
2063
|
unreconciledTransactions: [],
|
|
@@ -1072,7 +2087,7 @@ var automergePlugin = (handle, path) => {
|
|
|
1072
2087
|
}
|
|
1073
2088
|
});
|
|
1074
2089
|
const semaphore = new PatchSemaphore(stateField);
|
|
1075
|
-
const viewPlugin =
|
|
2090
|
+
const viewPlugin = ViewPlugin4.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
1076
2091
|
constructor(view) {
|
|
1077
2092
|
this._handleChange = () => {
|
|
1078
2093
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -1080,8 +2095,8 @@ var automergePlugin = (handle, path) => {
|
|
|
1080
2095
|
this._view = view;
|
|
1081
2096
|
handle.addListener("change", this._handleChange);
|
|
1082
2097
|
}
|
|
1083
|
-
update(
|
|
1084
|
-
if (
|
|
2098
|
+
update(update4) {
|
|
2099
|
+
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
1085
2100
|
queueMicrotask(() => {
|
|
1086
2101
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
1087
2102
|
});
|
|
@@ -1102,47 +2117,8 @@ var automergePlugin = (handle, path) => {
|
|
|
1102
2117
|
var reconcileAnnotationType = Annotation.define();
|
|
1103
2118
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
1104
2119
|
|
|
1105
|
-
// packages/ui/react-ui-editor/src/hooks/useCollaboration.ts
|
|
1106
|
-
var useCollaboration = (model, themeMode) => {
|
|
1107
|
-
const { content, provider, peer } = model;
|
|
1108
|
-
const [extension] = useState2(() => {
|
|
1109
|
-
if (content instanceof YText) {
|
|
1110
|
-
return yCollab2(content, provider?.awareness);
|
|
1111
|
-
} else if (isDocAccessor(content)) {
|
|
1112
|
-
return automergePlugin(content.handle, content.path);
|
|
1113
|
-
} else {
|
|
1114
|
-
return void 0;
|
|
1115
|
-
}
|
|
1116
|
-
});
|
|
1117
|
-
useEffect2(() => {
|
|
1118
|
-
if (provider && peer) {
|
|
1119
|
-
provider.awareness.setLocalStateField("user", {
|
|
1120
|
-
name: peer.name ?? generateName2(peer.id),
|
|
1121
|
-
color: getColorForValue2({
|
|
1122
|
-
value: peer.id,
|
|
1123
|
-
type: "color"
|
|
1124
|
-
}),
|
|
1125
|
-
colorLight: getColorForValue2({
|
|
1126
|
-
value: peer.id,
|
|
1127
|
-
themeMode,
|
|
1128
|
-
type: "highlight"
|
|
1129
|
-
})
|
|
1130
|
-
});
|
|
1131
|
-
}
|
|
1132
|
-
}, [
|
|
1133
|
-
provider,
|
|
1134
|
-
peer,
|
|
1135
|
-
themeMode
|
|
1136
|
-
]);
|
|
1137
|
-
return extension;
|
|
1138
|
-
};
|
|
1139
|
-
|
|
1140
|
-
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1141
|
-
import { useMemo } from "react";
|
|
1142
|
-
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
1143
|
-
|
|
1144
2120
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
1145
|
-
import * as
|
|
2121
|
+
import * as random2 from "lib0/random";
|
|
1146
2122
|
var cursorColors = [
|
|
1147
2123
|
{
|
|
1148
2124
|
color: "#30bced",
|
|
@@ -1177,7 +2153,7 @@ var cursorColors = [
|
|
|
1177
2153
|
light: "#1be7ff33"
|
|
1178
2154
|
}
|
|
1179
2155
|
];
|
|
1180
|
-
var cursorColor = cursorColors[
|
|
2156
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
1181
2157
|
|
|
1182
2158
|
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
1183
2159
|
import * as decoding from "lib0/decoding";
|
|
@@ -1185,7 +2161,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1185
2161
|
import { Observable } from "lib0/observable";
|
|
1186
2162
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1187
2163
|
import { log } from "@dxos/log";
|
|
1188
|
-
var
|
|
2164
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1189
2165
|
var messageAwareness = 1;
|
|
1190
2166
|
var messageQueryAwareness = 3;
|
|
1191
2167
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1222,7 +2198,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1222
2198
|
removed,
|
|
1223
2199
|
origin
|
|
1224
2200
|
}, {
|
|
1225
|
-
F:
|
|
2201
|
+
F: __dxlog_file3,
|
|
1226
2202
|
L: 67,
|
|
1227
2203
|
S: this,
|
|
1228
2204
|
C: (f, a) => f(...a)
|
|
@@ -1235,7 +2211,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1235
2211
|
}
|
|
1236
2212
|
_handleSpaceMessage({ payload }) {
|
|
1237
2213
|
log("space message", payload, {
|
|
1238
|
-
F:
|
|
2214
|
+
F: __dxlog_file3,
|
|
1239
2215
|
L: 79,
|
|
1240
2216
|
S: this,
|
|
1241
2217
|
C: (f, a) => f(...a)
|
|
@@ -1280,57 +2256,76 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1280
2256
|
};
|
|
1281
2257
|
|
|
1282
2258
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
2259
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1283
2260
|
var useTextModel = ({ identity, space, text }) => {
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
2261
|
+
const [model, setModel] = useState2(() => createModel({
|
|
2262
|
+
identity,
|
|
2263
|
+
space,
|
|
2264
|
+
text
|
|
2265
|
+
}));
|
|
2266
|
+
useEffect3(() => {
|
|
2267
|
+
setModel(createModel({
|
|
2268
|
+
identity,
|
|
1292
2269
|
space,
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
});
|
|
2270
|
+
text
|
|
2271
|
+
}));
|
|
1296
2272
|
}, [
|
|
1297
2273
|
identity,
|
|
1298
2274
|
space,
|
|
1299
|
-
text,
|
|
1300
|
-
text?.doc
|
|
1301
|
-
]);
|
|
1302
|
-
const content = useMemo(() => {
|
|
1303
|
-
if (isActualAutomergeObject(text)) {
|
|
1304
|
-
const obj = text;
|
|
1305
|
-
return getRawDoc(obj, [
|
|
1306
|
-
obj.field
|
|
1307
|
-
]);
|
|
1308
|
-
} else {
|
|
1309
|
-
return text?.content;
|
|
1310
|
-
}
|
|
1311
|
-
}, [
|
|
1312
2275
|
text
|
|
1313
2276
|
]);
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
2277
|
+
return model;
|
|
2278
|
+
};
|
|
2279
|
+
var createModel = (options) => {
|
|
2280
|
+
const { text } = options;
|
|
1317
2281
|
if (isActualAutomergeObject(text)) {
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
peer: identity ? {
|
|
1325
|
-
id: identity.identityKey.toHex(),
|
|
1326
|
-
name: identity.profile?.displayName
|
|
1327
|
-
} : void 0
|
|
1328
|
-
};
|
|
2282
|
+
return createAutomergeModel(options);
|
|
2283
|
+
} else {
|
|
2284
|
+
if (!text?.doc) {
|
|
2285
|
+
return void 0;
|
|
2286
|
+
}
|
|
2287
|
+
return createYjsModel(options);
|
|
1329
2288
|
}
|
|
2289
|
+
};
|
|
2290
|
+
var createYjsModel = ({ identity, space, text }) => {
|
|
2291
|
+
invariant3(text?.doc && text?.content, void 0, {
|
|
2292
|
+
F: __dxlog_file4,
|
|
2293
|
+
L: 81,
|
|
2294
|
+
S: void 0,
|
|
2295
|
+
A: [
|
|
2296
|
+
"text?.doc && text?.content",
|
|
2297
|
+
""
|
|
2298
|
+
]
|
|
2299
|
+
});
|
|
2300
|
+
const provider = space ? new SpaceAwarenessProvider({
|
|
2301
|
+
space,
|
|
2302
|
+
doc: text.doc,
|
|
2303
|
+
channel: `yjs.awareness.${text.id}`
|
|
2304
|
+
}) : void 0;
|
|
1330
2305
|
return {
|
|
1331
2306
|
id: text.doc.guid,
|
|
1332
2307
|
content: text.content,
|
|
1333
2308
|
text: () => text.content.toString(),
|
|
2309
|
+
ranges: [],
|
|
2310
|
+
extension: yCollab(text.content, provider?.awareness),
|
|
2311
|
+
awareness: provider?.awareness,
|
|
2312
|
+
peer: identity ? {
|
|
2313
|
+
id: identity.identityKey.toHex(),
|
|
2314
|
+
name: identity.profile?.displayName
|
|
2315
|
+
} : void 0
|
|
2316
|
+
};
|
|
2317
|
+
};
|
|
2318
|
+
var createAutomergeModel = ({ identity, text }) => {
|
|
2319
|
+
const obj = text;
|
|
2320
|
+
const doc = getRawDoc(obj, [
|
|
2321
|
+
obj.field
|
|
2322
|
+
]);
|
|
2323
|
+
return {
|
|
2324
|
+
id: obj.id,
|
|
2325
|
+
content: doc,
|
|
2326
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2327
|
+
ranges: [],
|
|
2328
|
+
extension: automergePlugin(doc.handle, doc.path),
|
|
1334
2329
|
peer: identity ? {
|
|
1335
2330
|
id: identity.identityKey.toHex(),
|
|
1336
2331
|
name: identity.profile?.displayName
|
|
@@ -1345,28 +2340,39 @@ export {
|
|
|
1345
2340
|
SpaceAwarenessProvider,
|
|
1346
2341
|
TextEditor,
|
|
1347
2342
|
TextKind,
|
|
1348
|
-
|
|
2343
|
+
YText,
|
|
1349
2344
|
YXmlFragment,
|
|
1350
2345
|
autocomplete,
|
|
1351
2346
|
basicBundle,
|
|
2347
|
+
blast,
|
|
2348
|
+
code2 as code,
|
|
1352
2349
|
codeTheme,
|
|
2350
|
+
comments,
|
|
1353
2351
|
cursorColor,
|
|
2352
|
+
defaultMarkdownSlots,
|
|
2353
|
+
defaultOptions,
|
|
1354
2354
|
defaultSlots,
|
|
1355
2355
|
defaultTextSlots,
|
|
1356
2356
|
defaultTheme,
|
|
2357
|
+
demo,
|
|
2358
|
+
highlight,
|
|
2359
|
+
highlightDecorations,
|
|
2360
|
+
highlightStateField,
|
|
2361
|
+
image,
|
|
1357
2362
|
link,
|
|
1358
|
-
listener,
|
|
2363
|
+
listener2 as listener,
|
|
1359
2364
|
markdownBundle,
|
|
1360
2365
|
markdownHighlightStyle,
|
|
1361
2366
|
markdownTags,
|
|
1362
|
-
|
|
1363
|
-
|
|
1364
|
-
|
|
2367
|
+
markdownTagsExtensions,
|
|
2368
|
+
markdownTheme,
|
|
2369
|
+
mention,
|
|
2370
|
+
table,
|
|
1365
2371
|
tags2 as tags,
|
|
1366
2372
|
tasklist,
|
|
1367
2373
|
textTheme,
|
|
1368
2374
|
tooltip,
|
|
1369
|
-
|
|
2375
|
+
useHighlights,
|
|
1370
2376
|
useTextModel
|
|
1371
2377
|
};
|
|
1372
2378
|
//# sourceMappingURL=index.mjs.map
|