@dxos/react-ui-editor 0.3.10-main.a21ec31 → 0.3.10-main.c5193cc
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 +1006 -219
- 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 +22 -1
- 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/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/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.map +1 -1
- 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 +6 -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 +2 -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 +6 -2
- 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/hooks/automerge/PatchSemaphore.d.ts +3 -0
- package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts +8 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/automerge/index.d.ts +1 -1
- package/dist/types/src/hooks/automerge/index.d.ts.map +1 -1
- package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -1
- 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/useTextModel.d.ts.map +1 -1
- package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +1 -1
- 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 +20 -19
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +140 -31
- package/src/components/TextEditor/TextEditor.tsx +26 -15
- package/src/components/TextEditor/extensions/autocomplete.ts +9 -22
- package/src/components/TextEditor/extensions/basic.ts +2 -1
- package/src/components/TextEditor/extensions/blast.ts +387 -0
- package/src/components/TextEditor/extensions/comments.ts +191 -0
- package/src/components/TextEditor/extensions/demo.ts +69 -0
- package/src/components/TextEditor/extensions/experimental.tsx +1 -0
- package/src/components/TextEditor/extensions/image.ts +67 -0
- package/src/components/TextEditor/extensions/index.ts +6 -0
- package/src/components/TextEditor/extensions/link.ts +26 -25
- package/src/components/TextEditor/extensions/listener.ts +4 -3
- package/src/components/TextEditor/extensions/markdown/bundle.ts +29 -26
- package/src/components/TextEditor/extensions/markdown/highlight.ts +118 -103
- package/src/components/TextEditor/extensions/mention.ts +31 -0
- package/src/components/TextEditor/extensions/table.ts +123 -0
- package/src/components/TextEditor/extensions/tasklist.ts +89 -81
- package/src/components/TextEditor/themes/default.ts +69 -2
- package/src/hooks/automerge/PatchSemaphore.ts +12 -9
- package/src/hooks/automerge/automerge.stories.tsx +3 -2
- package/src/hooks/automerge/index.ts +1 -1
- package/src/hooks/automerge/plugin.ts +1 -0
- package/src/hooks/automerge/{amToCodemirror.ts → translation/automerge-to-codemirror.ts} +10 -2
- package/src/hooks/automerge/{codeMirrorToAm.ts → translation/codemirror-to-automerge.ts} +7 -4
- package/src/hooks/automerge/translation/index.ts +6 -0
- package/src/hooks/useTextModel.ts +13 -11
- package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +1 -1
- package/src/styles/markdown.ts +14 -8
- package/src/testing/replicator.ts +5 -5
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/amToCodemirror.d.ts +0 -6
- package/dist/types/src/hooks/automerge/amToCodemirror.d.ts.map +0 -1
- package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts +0 -7
- package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts.map +0 -1
|
@@ -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
|
]
|
|
@@ -43,7 +43,7 @@ import { closeBrackets } from "@codemirror/autocomplete";
|
|
|
43
43
|
import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
|
|
44
44
|
import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
|
|
45
45
|
import { EditorView, placeholder } from "@codemirror/view";
|
|
46
|
-
var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
|
|
46
|
+
var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
|
|
47
47
|
// TODO(burdon): Compare with minimalSetup.
|
|
48
48
|
// https://codemirror.net/docs/ref/#codemirror.minimalSetup
|
|
49
49
|
bracketMatching(),
|
|
@@ -54,11 +54,589 @@ var basicBundle = ({ themeMode, placeholder: _placeholder }) => [
|
|
|
54
54
|
themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
|
|
55
55
|
].filter(Boolean);
|
|
56
56
|
|
|
57
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
57
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/blast.ts
|
|
58
|
+
import { StateField } from "@codemirror/state";
|
|
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) => {
|
|
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.view.state.selection.main.head;
|
|
127
|
+
if (current !== last) {
|
|
128
|
+
last = current;
|
|
129
|
+
const { element, point } = getPoint(update4.view, current);
|
|
130
|
+
if (element && point) {
|
|
131
|
+
blaster.spawn({
|
|
132
|
+
element,
|
|
133
|
+
point
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
}),
|
|
138
|
+
// Document changed.
|
|
139
|
+
StateField.define({
|
|
140
|
+
create: () => null,
|
|
141
|
+
update: (_value, transaction) => {
|
|
142
|
+
if (blaster && transaction.docChanged) {
|
|
143
|
+
const view = EditorView2.findFromDOM(blaster.node);
|
|
144
|
+
const { element, point } = getPoint(view, transaction.selection.main.head);
|
|
145
|
+
if (element && point) {
|
|
146
|
+
blaster.spawn({
|
|
147
|
+
element,
|
|
148
|
+
point
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
return null;
|
|
153
|
+
}
|
|
154
|
+
}),
|
|
155
|
+
keymap2.of([
|
|
156
|
+
{
|
|
157
|
+
any: (view, event) => {
|
|
158
|
+
if (blaster && event.key === "Enter" && event.shiftKey) {
|
|
159
|
+
blaster.shake({
|
|
160
|
+
time: 0.4
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
])
|
|
167
|
+
];
|
|
168
|
+
};
|
|
169
|
+
var Blaster = class {
|
|
170
|
+
constructor(_node, _options) {
|
|
171
|
+
this._node = _node;
|
|
172
|
+
this._options = _options;
|
|
173
|
+
this._running = false;
|
|
174
|
+
this._shakeTime = 0;
|
|
175
|
+
this._shakeTimeMax = 0;
|
|
176
|
+
this._particles = [];
|
|
177
|
+
this._particlePointer = 0;
|
|
178
|
+
this._lastPoint = {
|
|
179
|
+
x: 0,
|
|
180
|
+
y: 0
|
|
181
|
+
};
|
|
182
|
+
this.shake = throttle(({ time }) => {
|
|
183
|
+
this._shakeTime = this._shakeTimeMax;
|
|
184
|
+
this._shakeTimeMax = time;
|
|
185
|
+
}, 100);
|
|
186
|
+
this.spawn = throttle(({ element, point }) => {
|
|
187
|
+
const color = getRGBComponents(element, this._options.color);
|
|
188
|
+
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
189
|
+
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
190
|
+
this._lastPoint = point;
|
|
191
|
+
for (let i = numParticles; i--; i > 0) {
|
|
192
|
+
this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
|
|
193
|
+
this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
|
|
194
|
+
}
|
|
195
|
+
}, 100);
|
|
196
|
+
this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
|
|
197
|
+
}
|
|
198
|
+
get node() {
|
|
199
|
+
return this._node;
|
|
200
|
+
}
|
|
201
|
+
initialize() {
|
|
202
|
+
invariant(!this._canvas && !this._ctx, void 0, {
|
|
203
|
+
F: __dxlog_file,
|
|
204
|
+
L: 152,
|
|
205
|
+
S: this,
|
|
206
|
+
A: [
|
|
207
|
+
"!this._canvas && !this._ctx",
|
|
208
|
+
""
|
|
209
|
+
]
|
|
210
|
+
});
|
|
211
|
+
this._canvas = document.createElement("canvas");
|
|
212
|
+
this._canvas.id = "code-blast-canvas";
|
|
213
|
+
this._canvas.style.position = "absolute";
|
|
214
|
+
this._canvas.style.zIndex = "0";
|
|
215
|
+
this._canvas.style.pointerEvents = "none";
|
|
216
|
+
this._ctx = this._canvas.getContext("2d");
|
|
217
|
+
const parent = this._node.parentElement?.parentElement;
|
|
218
|
+
parent?.appendChild(this._canvas);
|
|
219
|
+
this.resize();
|
|
220
|
+
}
|
|
221
|
+
destroy() {
|
|
222
|
+
this.stop();
|
|
223
|
+
if (this._canvas) {
|
|
224
|
+
this._canvas.remove();
|
|
225
|
+
this._canvas = void 0;
|
|
226
|
+
this._ctx = void 0;
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
resize() {
|
|
230
|
+
if (this._node.parentElement && this._canvas) {
|
|
231
|
+
const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
|
|
232
|
+
this._canvas.style.top = `${y}px`;
|
|
233
|
+
this._canvas.style.left = `${x}px`;
|
|
234
|
+
this._canvas.width = width;
|
|
235
|
+
this._canvas.height = height;
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
start() {
|
|
239
|
+
invariant(this._canvas && this._ctx, void 0, {
|
|
240
|
+
F: __dxlog_file,
|
|
241
|
+
L: 191,
|
|
242
|
+
S: this,
|
|
243
|
+
A: [
|
|
244
|
+
"this._canvas && this._ctx",
|
|
245
|
+
""
|
|
246
|
+
]
|
|
247
|
+
});
|
|
248
|
+
this._running = true;
|
|
249
|
+
this.loop();
|
|
250
|
+
}
|
|
251
|
+
stop() {
|
|
252
|
+
this._running = false;
|
|
253
|
+
this._node.style.transform = "translate(0px, 0px)";
|
|
254
|
+
}
|
|
255
|
+
loop() {
|
|
256
|
+
if (!this._running || !this._canvas || !this._ctx) {
|
|
257
|
+
return;
|
|
258
|
+
}
|
|
259
|
+
this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
|
|
260
|
+
const now = (/* @__PURE__ */ new Date()).getTime();
|
|
261
|
+
this._lastTime ??= now;
|
|
262
|
+
const dt = (now - this._lastTime) / 1e3;
|
|
263
|
+
this._lastTime = now;
|
|
264
|
+
if (this._shakeTime > 0) {
|
|
265
|
+
this._shakeTime -= dt;
|
|
266
|
+
const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
|
|
267
|
+
const shakeX = random(-magnitude, magnitude);
|
|
268
|
+
const shakeY = random(-magnitude, magnitude);
|
|
269
|
+
this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
|
|
270
|
+
}
|
|
271
|
+
this.drawParticles();
|
|
272
|
+
requestAnimationFrame(this.loop.bind(this));
|
|
273
|
+
}
|
|
274
|
+
drawParticles() {
|
|
275
|
+
for (let i = this._particles.length; i--; i > 0) {
|
|
276
|
+
const particle = this._particles[i];
|
|
277
|
+
if (!particle) {
|
|
278
|
+
continue;
|
|
279
|
+
}
|
|
280
|
+
if (particle.alpha < 0.01 || particle.size <= 0.5) {
|
|
281
|
+
continue;
|
|
282
|
+
}
|
|
283
|
+
this._effect.update(this._ctx, particle);
|
|
284
|
+
}
|
|
285
|
+
}
|
|
286
|
+
};
|
|
287
|
+
var Effect = class {
|
|
288
|
+
constructor(_options) {
|
|
289
|
+
this._options = _options;
|
|
290
|
+
}
|
|
291
|
+
};
|
|
292
|
+
var Effect1 = class extends Effect {
|
|
293
|
+
create(x, y, color) {
|
|
294
|
+
return {
|
|
295
|
+
x,
|
|
296
|
+
y: y + 10,
|
|
297
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
298
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
299
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
300
|
+
color,
|
|
301
|
+
alpha: 1
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
update(ctx, particle) {
|
|
305
|
+
particle.vy += this._options.particleGravity;
|
|
306
|
+
particle.x += particle.vx;
|
|
307
|
+
particle.y += particle.vy;
|
|
308
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
309
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
310
|
+
ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
|
|
311
|
+
}
|
|
312
|
+
};
|
|
313
|
+
var Effect2 = class extends Effect {
|
|
314
|
+
create(x, y, color) {
|
|
315
|
+
return {
|
|
316
|
+
x,
|
|
317
|
+
y: y + 10,
|
|
318
|
+
vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
|
|
319
|
+
vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
|
|
320
|
+
size: random(this._options.particleSize.min, this._options.particleSize.max),
|
|
321
|
+
color,
|
|
322
|
+
alpha: 1,
|
|
323
|
+
theta: random(0, 360) * Math.PI / 180,
|
|
324
|
+
drag: 0.92,
|
|
325
|
+
wander: 0.15
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
update(ctx, particle) {
|
|
329
|
+
particle.vy += this._options.particleGravity;
|
|
330
|
+
particle.x += particle.vx;
|
|
331
|
+
particle.y += particle.vy;
|
|
332
|
+
particle.vx *= particle.drag;
|
|
333
|
+
particle.vy *= particle.drag;
|
|
334
|
+
particle.theta += random(-0.5, 0.5);
|
|
335
|
+
particle.vx += Math.sin(particle.theta) * 0.1;
|
|
336
|
+
particle.vy += Math.cos(particle.theta) * 0.1;
|
|
337
|
+
particle.size *= this._options.particleShrinkRate;
|
|
338
|
+
particle.alpha *= this._options.particleAlphaFadeout;
|
|
339
|
+
ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
|
|
340
|
+
ctx.beginPath();
|
|
341
|
+
ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
|
|
342
|
+
ctx.fill();
|
|
343
|
+
}
|
|
344
|
+
};
|
|
345
|
+
function throttle(callback, limit) {
|
|
346
|
+
let wait = false;
|
|
347
|
+
return function(...args) {
|
|
348
|
+
if (!wait) {
|
|
349
|
+
callback.apply(this, args);
|
|
350
|
+
wait = true;
|
|
351
|
+
setTimeout(() => {
|
|
352
|
+
wait = false;
|
|
353
|
+
}, limit);
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
var getRGBComponents = (node, color) => {
|
|
358
|
+
if (typeof color === "function") {
|
|
359
|
+
return color();
|
|
360
|
+
}
|
|
361
|
+
const bgColor = getComputedStyle(node).color;
|
|
362
|
+
if (bgColor) {
|
|
363
|
+
const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
|
|
364
|
+
if (x) {
|
|
365
|
+
return x;
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return [
|
|
369
|
+
50,
|
|
370
|
+
50,
|
|
371
|
+
50
|
|
372
|
+
];
|
|
373
|
+
};
|
|
374
|
+
var random = (min, max) => {
|
|
375
|
+
if (!max) {
|
|
376
|
+
max = min;
|
|
377
|
+
min = 0;
|
|
378
|
+
}
|
|
379
|
+
return min + ~~(Math.random() * (max - min + 1));
|
|
380
|
+
};
|
|
381
|
+
|
|
382
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
|
|
383
|
+
import { keymap as keymap3 } from "@codemirror/view";
|
|
384
|
+
var defaultItems = [
|
|
385
|
+
"hello world!",
|
|
386
|
+
"this is a test.",
|
|
387
|
+
"this is [DXOS](https://dxos.org)"
|
|
388
|
+
];
|
|
389
|
+
var demo = ({ delay = 75, items = defaultItems } = {}) => {
|
|
390
|
+
let t;
|
|
391
|
+
let idx = 0;
|
|
392
|
+
return [
|
|
393
|
+
keymap3.of([
|
|
394
|
+
{
|
|
395
|
+
// Reset.
|
|
396
|
+
key: "alt-meta-'",
|
|
397
|
+
run: (view) => {
|
|
398
|
+
clearTimeout(t);
|
|
399
|
+
idx = 0;
|
|
400
|
+
return true;
|
|
401
|
+
}
|
|
402
|
+
},
|
|
403
|
+
{
|
|
404
|
+
// Next prompt.
|
|
405
|
+
// TODO(burdon): Press 1-9 to select prompt?
|
|
406
|
+
key: "shift-meta-'",
|
|
407
|
+
run: (view) => {
|
|
408
|
+
clearTimeout(t);
|
|
409
|
+
const text = items[idx++];
|
|
410
|
+
if (idx === items?.length) {
|
|
411
|
+
idx = 0;
|
|
412
|
+
}
|
|
413
|
+
let i = 0;
|
|
414
|
+
const insert = (d = 0) => {
|
|
415
|
+
t = setTimeout(() => {
|
|
416
|
+
const pos = view.state.selection.main.head;
|
|
417
|
+
view.dispatch({
|
|
418
|
+
changes: {
|
|
419
|
+
from: pos,
|
|
420
|
+
insert: text[i++]
|
|
421
|
+
},
|
|
422
|
+
selection: {
|
|
423
|
+
anchor: pos + 1
|
|
424
|
+
}
|
|
425
|
+
});
|
|
426
|
+
if (i < text.length) {
|
|
427
|
+
insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
|
|
428
|
+
}
|
|
429
|
+
}, d);
|
|
430
|
+
};
|
|
431
|
+
insert();
|
|
432
|
+
return true;
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
])
|
|
436
|
+
];
|
|
437
|
+
};
|
|
438
|
+
|
|
439
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
440
|
+
import { keymap as keymap4, Decoration, EditorView as EditorView3, MatchDecorator, ViewPlugin, WidgetType } from "@codemirror/view";
|
|
441
|
+
import { debounce } from "@dxos/async";
|
|
442
|
+
import { invariant as invariant2 } from "@dxos/invariant";
|
|
443
|
+
var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
|
|
444
|
+
var BookmarkWidget = class extends WidgetType {
|
|
445
|
+
constructor(_pos, _id, _handleClick) {
|
|
446
|
+
super();
|
|
447
|
+
this._pos = _pos;
|
|
448
|
+
this._id = _id;
|
|
449
|
+
this._handleClick = _handleClick;
|
|
450
|
+
invariant2(this._id, void 0, {
|
|
451
|
+
F: __dxlog_file2,
|
|
452
|
+
L: 41,
|
|
453
|
+
S: this,
|
|
454
|
+
A: [
|
|
455
|
+
"this._id",
|
|
456
|
+
""
|
|
457
|
+
]
|
|
458
|
+
});
|
|
459
|
+
}
|
|
460
|
+
eq(other) {
|
|
461
|
+
return this._id === other._id;
|
|
462
|
+
}
|
|
463
|
+
toDOM() {
|
|
464
|
+
const span = document.createElement("span");
|
|
465
|
+
span.className = "cm-bookmark";
|
|
466
|
+
span.textContent = "\u{1F4AC}";
|
|
467
|
+
span.onclick = () => this._handleClick();
|
|
468
|
+
return span;
|
|
469
|
+
}
|
|
470
|
+
};
|
|
471
|
+
var styles = EditorView3.baseTheme({
|
|
472
|
+
"& .cm-bookmark": {
|
|
473
|
+
cursor: "pointer",
|
|
474
|
+
margin: "4px",
|
|
475
|
+
padding: "4px",
|
|
476
|
+
backgroundColor: "yellow"
|
|
477
|
+
},
|
|
478
|
+
"& .cm-bookmark-selected": {
|
|
479
|
+
backgroundColor: "orange"
|
|
480
|
+
}
|
|
481
|
+
});
|
|
482
|
+
var comments = (options = {}) => {
|
|
483
|
+
let active;
|
|
484
|
+
const bookmarkMatcher = new MatchDecorator({
|
|
485
|
+
regexp: /\[\^(\w+)\]/g,
|
|
486
|
+
decoration: (match, view, pos) => {
|
|
487
|
+
const id = match[1];
|
|
488
|
+
return Decoration.replace({
|
|
489
|
+
id,
|
|
490
|
+
widget: new BookmarkWidget(pos, id, () => handleUpdate({
|
|
491
|
+
active: id
|
|
492
|
+
}))
|
|
493
|
+
});
|
|
494
|
+
}
|
|
495
|
+
});
|
|
496
|
+
const bookmarks = ViewPlugin.fromClass(class {
|
|
497
|
+
constructor(view) {
|
|
498
|
+
this.bookmarks = bookmarkMatcher.createDeco(view);
|
|
499
|
+
}
|
|
500
|
+
update(update4) {
|
|
501
|
+
this.bookmarks = bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
502
|
+
}
|
|
503
|
+
}, {
|
|
504
|
+
decorations: (instance) => instance.bookmarks,
|
|
505
|
+
provide: (plugin) => EditorView3.atomicRanges.of((view) => {
|
|
506
|
+
return view.plugin(plugin)?.bookmarks || Decoration.none;
|
|
507
|
+
})
|
|
508
|
+
});
|
|
509
|
+
const handleUpdate = debounce((data) => {
|
|
510
|
+
options.onUpdate?.(data);
|
|
511
|
+
}, 200);
|
|
512
|
+
return [
|
|
513
|
+
keymap4.of([
|
|
514
|
+
{
|
|
515
|
+
key: options?.key ?? "shift-meta-c",
|
|
516
|
+
run: (view) => {
|
|
517
|
+
const id = options.onCreate?.();
|
|
518
|
+
if (id) {
|
|
519
|
+
const pos = view.state.selection.main.head;
|
|
520
|
+
const tag = `[^${id}]`;
|
|
521
|
+
view.dispatch({
|
|
522
|
+
changes: {
|
|
523
|
+
from: pos,
|
|
524
|
+
insert: tag
|
|
525
|
+
},
|
|
526
|
+
selection: {
|
|
527
|
+
anchor: pos + tag.length
|
|
528
|
+
}
|
|
529
|
+
});
|
|
530
|
+
return true;
|
|
531
|
+
}
|
|
532
|
+
return false;
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
]),
|
|
536
|
+
bookmarks,
|
|
537
|
+
// Monitor cursor movement.
|
|
538
|
+
EditorView3.updateListener.of((update4) => {
|
|
539
|
+
active = void 0;
|
|
540
|
+
if (!options.onUpdate) {
|
|
541
|
+
return;
|
|
542
|
+
}
|
|
543
|
+
const view = update4.view;
|
|
544
|
+
const pos = view.state.selection.main.head;
|
|
545
|
+
const decorations = [];
|
|
546
|
+
const rangeSet = view.plugin(bookmarks)?.bookmarks;
|
|
547
|
+
let closest = Infinity;
|
|
548
|
+
const { from, to } = (
|
|
549
|
+
/* view.visibleRanges?.[0] ?? */
|
|
550
|
+
{
|
|
551
|
+
from: 0,
|
|
552
|
+
to: view.state.doc.length
|
|
553
|
+
}
|
|
554
|
+
);
|
|
555
|
+
rangeSet?.between(from, to, (from2, to2, value) => {
|
|
556
|
+
decorations.push({
|
|
557
|
+
from: from2,
|
|
558
|
+
to: to2,
|
|
559
|
+
value
|
|
560
|
+
});
|
|
561
|
+
const d = Math.min(Math.abs(pos - from2), Math.abs(pos - to2));
|
|
562
|
+
if (d < closest) {
|
|
563
|
+
active = value.spec.id;
|
|
564
|
+
closest = d;
|
|
565
|
+
}
|
|
566
|
+
});
|
|
567
|
+
if (decorations.length) {
|
|
568
|
+
handleUpdate({
|
|
569
|
+
active,
|
|
570
|
+
items: decorations.map(({ from: from2, value: { spec: { id } } }) => ({
|
|
571
|
+
id,
|
|
572
|
+
pos: from2,
|
|
573
|
+
location: view.coordsAtPos(from2)
|
|
574
|
+
}))
|
|
575
|
+
});
|
|
576
|
+
}
|
|
577
|
+
}),
|
|
578
|
+
styles
|
|
579
|
+
];
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/image.ts
|
|
58
583
|
import { syntaxTree } from "@codemirror/language";
|
|
59
|
-
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
60
|
-
import { Decoration, EditorView as
|
|
61
|
-
var
|
|
584
|
+
import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
|
|
585
|
+
import { Decoration as Decoration2, EditorView as EditorView4, WidgetType as WidgetType2 } from "@codemirror/view";
|
|
586
|
+
var image = (options = {}) => {
|
|
587
|
+
return StateField2.define({
|
|
588
|
+
create: (state) => update(state, options),
|
|
589
|
+
update: (_, tr) => update(tr.state, options),
|
|
590
|
+
provide: (field) => EditorView4.decorations.from(field)
|
|
591
|
+
});
|
|
592
|
+
};
|
|
593
|
+
var update = (state, options) => {
|
|
594
|
+
const builder = new RangeSetBuilder();
|
|
595
|
+
const cursor = state.selection.main.head;
|
|
596
|
+
syntaxTree(state).iterate({
|
|
597
|
+
enter: (node) => {
|
|
598
|
+
if (node.name === "Image") {
|
|
599
|
+
const urlNode = node.node.getChild("URL");
|
|
600
|
+
if (urlNode) {
|
|
601
|
+
const hide = state.readOnly || cursor < node.from || cursor > node.to;
|
|
602
|
+
const url = state.sliceDoc(urlNode.from, urlNode.to);
|
|
603
|
+
builder.add(hide ? node.from : node.to, node.to, Decoration2.replace({
|
|
604
|
+
widget: new ImageWidget(url)
|
|
605
|
+
}));
|
|
606
|
+
}
|
|
607
|
+
}
|
|
608
|
+
}
|
|
609
|
+
});
|
|
610
|
+
return builder.finish();
|
|
611
|
+
};
|
|
612
|
+
var ImageWidget = class extends WidgetType2 {
|
|
613
|
+
constructor(_url) {
|
|
614
|
+
super();
|
|
615
|
+
this._url = _url;
|
|
616
|
+
}
|
|
617
|
+
eq(other) {
|
|
618
|
+
return this._url === other?._url;
|
|
619
|
+
}
|
|
620
|
+
toDOM(view) {
|
|
621
|
+
const img = document.createElement("img");
|
|
622
|
+
img.setAttribute("src", this._url);
|
|
623
|
+
img.setAttribute("class", "cm-image");
|
|
624
|
+
return img;
|
|
625
|
+
}
|
|
626
|
+
};
|
|
627
|
+
|
|
628
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
|
|
629
|
+
import { syntaxTree as syntaxTree2 } from "@codemirror/language";
|
|
630
|
+
import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField3 } from "@codemirror/state";
|
|
631
|
+
import { Decoration as Decoration3, EditorView as EditorView5, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
632
|
+
var link = (options = {}) => {
|
|
633
|
+
return StateField3.define({
|
|
634
|
+
create: (state) => update2(state, options),
|
|
635
|
+
update: (_, tr) => update2(tr.state, options),
|
|
636
|
+
provide: (field) => EditorView5.decorations.from(field)
|
|
637
|
+
});
|
|
638
|
+
};
|
|
639
|
+
var LinkButton = class extends WidgetType3 {
|
|
62
640
|
constructor(_pos, _url, _onAttach) {
|
|
63
641
|
super();
|
|
64
642
|
this._pos = _pos;
|
|
@@ -74,7 +652,7 @@ var LinkButton = class extends WidgetType {
|
|
|
74
652
|
return el;
|
|
75
653
|
}
|
|
76
654
|
};
|
|
77
|
-
var LinkText = class extends
|
|
655
|
+
var LinkText = class extends WidgetType3 {
|
|
78
656
|
constructor(_pos, _text, _url) {
|
|
79
657
|
super();
|
|
80
658
|
this._pos = _pos;
|
|
@@ -104,79 +682,99 @@ var LinkText = class extends WidgetType {
|
|
|
104
682
|
return link2;
|
|
105
683
|
}
|
|
106
684
|
};
|
|
107
|
-
var
|
|
108
|
-
const builder = new
|
|
685
|
+
var update2 = (state, options) => {
|
|
686
|
+
const builder = new RangeSetBuilder2();
|
|
109
687
|
const cursor = state.selection.main.head;
|
|
110
|
-
|
|
688
|
+
syntaxTree2(state).iterate({
|
|
111
689
|
enter: (node) => {
|
|
112
690
|
if (node.name === "Link") {
|
|
113
691
|
const marks = node.node.getChildren("LinkMark");
|
|
114
692
|
const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
|
|
115
693
|
const urlNode = node.node.getChild("URL");
|
|
116
694
|
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
695
|
+
if (!url) {
|
|
696
|
+
return false;
|
|
697
|
+
}
|
|
117
698
|
if (cursor < node.from || cursor > node.to) {
|
|
118
|
-
builder.add(node.from, node.to,
|
|
699
|
+
builder.add(node.from, node.to, Decoration3.replace({
|
|
119
700
|
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
120
701
|
}));
|
|
121
702
|
}
|
|
122
703
|
if (options.onRender) {
|
|
123
|
-
builder.add(node.to, node.to,
|
|
704
|
+
builder.add(node.to, node.to, Decoration3.replace({
|
|
124
705
|
widget: new LinkButton(node.from, url, options.onRender)
|
|
125
706
|
}));
|
|
126
707
|
}
|
|
708
|
+
return false;
|
|
127
709
|
}
|
|
128
|
-
return true;
|
|
129
710
|
}
|
|
130
711
|
});
|
|
131
712
|
return builder.finish();
|
|
132
713
|
};
|
|
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
714
|
|
|
141
715
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
142
|
-
import { StateField as
|
|
143
|
-
var listener = (onChange) =>
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
716
|
+
import { StateField as StateField4 } from "@codemirror/state";
|
|
717
|
+
var listener = ({ onChange }) => {
|
|
718
|
+
return StateField4.define({
|
|
719
|
+
create: () => null,
|
|
720
|
+
update: (_value, transaction) => {
|
|
721
|
+
if (transaction.docChanged && onChange) {
|
|
722
|
+
onChange(transaction.newDoc.toString());
|
|
723
|
+
}
|
|
724
|
+
return null;
|
|
148
725
|
}
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
});
|
|
726
|
+
});
|
|
727
|
+
};
|
|
152
728
|
|
|
153
729
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
154
730
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
155
|
-
import {
|
|
731
|
+
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
156
732
|
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
157
|
-
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2,
|
|
733
|
+
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
158
734
|
import { languages } from "@codemirror/language-data";
|
|
159
|
-
import { lintKeymap } from "@codemirror/lint";
|
|
160
735
|
import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
|
|
161
736
|
import { EditorState } from "@codemirror/state";
|
|
162
737
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
163
|
-
import { crosshairCursor, drawSelection, dropCursor, EditorView as
|
|
738
|
+
import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView6, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap5, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
|
|
164
739
|
|
|
165
740
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
166
741
|
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
167
742
|
import { HighlightStyle } from "@codemirror/language";
|
|
168
743
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
169
744
|
import get from "lodash.get";
|
|
745
|
+
import { mx as mx2 } from "@dxos/react-ui-theme";
|
|
170
746
|
|
|
171
747
|
// packages/ui/react-ui-editor/src/styles/markdown.ts
|
|
172
748
|
import { mx } from "@dxos/react-ui-theme";
|
|
173
|
-
var
|
|
174
|
-
1:
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
749
|
+
var headings = {
|
|
750
|
+
1: [
|
|
751
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
752
|
+
"-ml-1.5"
|
|
753
|
+
],
|
|
754
|
+
2: [
|
|
755
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
756
|
+
"-ml-1.5"
|
|
757
|
+
],
|
|
758
|
+
3: [
|
|
759
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
760
|
+
"-ml-1.5"
|
|
761
|
+
],
|
|
762
|
+
4: [
|
|
763
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
764
|
+
"-ml-[5px]"
|
|
765
|
+
],
|
|
766
|
+
5: [
|
|
767
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
768
|
+
"-ml-[5px]"
|
|
769
|
+
],
|
|
770
|
+
6: [
|
|
771
|
+
"mbs-4 mbe-2 font-medium text-inherit no-underline",
|
|
772
|
+
"-ml-[4px]"
|
|
773
|
+
]
|
|
774
|
+
};
|
|
775
|
+
var heading = (level, readonly) => {
|
|
776
|
+
const [style, offset] = headings[level];
|
|
777
|
+
return mx(style, readonly && offset);
|
|
180
778
|
};
|
|
181
779
|
var light = "text-neutral-200 dark:text-neutral-800";
|
|
182
780
|
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
@@ -187,7 +785,7 @@ var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
|
187
785
|
var codeMark = "font-mono text-primary-500";
|
|
188
786
|
var inlineUrl = mx(code, "px-1");
|
|
189
787
|
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
190
|
-
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-
|
|
788
|
+
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
|
|
191
789
|
|
|
192
790
|
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
193
791
|
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
@@ -213,7 +811,7 @@ var markdownTagsExtension = {
|
|
|
213
811
|
styleTags(markdownTags)
|
|
214
812
|
]
|
|
215
813
|
};
|
|
216
|
-
var markdownHighlightStyle = HighlightStyle.define([
|
|
814
|
+
var markdownHighlightStyle = (readonly) => HighlightStyle.define([
|
|
217
815
|
{
|
|
218
816
|
tag: [
|
|
219
817
|
tags.keyword,
|
|
@@ -257,40 +855,54 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
257
855
|
tag: [
|
|
258
856
|
tags.meta,
|
|
259
857
|
tags.processingInstruction,
|
|
260
|
-
markdownTags.CodeMark,
|
|
261
|
-
markdownTags.EmphasisMark,
|
|
262
|
-
markdownTags.HeaderMark,
|
|
263
858
|
markdownTags.LinkLabel,
|
|
264
859
|
markdownTags.LinkReference,
|
|
265
|
-
markdownTags.ListMark
|
|
266
|
-
markdownTags.QuoteMark
|
|
860
|
+
markdownTags.ListMark
|
|
267
861
|
],
|
|
268
862
|
class: mark
|
|
269
863
|
},
|
|
864
|
+
// Markdown marks.
|
|
865
|
+
{
|
|
866
|
+
tag: [
|
|
867
|
+
markdownTags.CodeMark,
|
|
868
|
+
markdownTags.HeaderMark,
|
|
869
|
+
markdownTags.QuoteMark,
|
|
870
|
+
markdownTags.EmphasisMark
|
|
871
|
+
],
|
|
872
|
+
class: readonly ? "hidden" : mark
|
|
873
|
+
},
|
|
874
|
+
// E.g., code block language (after ```).
|
|
875
|
+
{
|
|
876
|
+
tag: [
|
|
877
|
+
tags.function(tags.variableName),
|
|
878
|
+
tags.labelName
|
|
879
|
+
],
|
|
880
|
+
class: readonly ? "hidden" : codeMark
|
|
881
|
+
},
|
|
270
882
|
// Headings.
|
|
271
883
|
{
|
|
272
884
|
tag: tags.heading1,
|
|
273
|
-
class: heading
|
|
885
|
+
class: heading(1, readonly)
|
|
274
886
|
},
|
|
275
887
|
{
|
|
276
888
|
tag: tags.heading2,
|
|
277
|
-
class: heading
|
|
889
|
+
class: heading(2, readonly)
|
|
278
890
|
},
|
|
279
891
|
{
|
|
280
892
|
tag: tags.heading3,
|
|
281
|
-
class: heading
|
|
893
|
+
class: heading(3, readonly)
|
|
282
894
|
},
|
|
283
895
|
{
|
|
284
896
|
tag: tags.heading4,
|
|
285
|
-
class: heading
|
|
897
|
+
class: heading(4, readonly)
|
|
286
898
|
},
|
|
287
899
|
{
|
|
288
900
|
tag: tags.heading5,
|
|
289
|
-
class: heading
|
|
901
|
+
class: heading(5, readonly)
|
|
290
902
|
},
|
|
291
903
|
{
|
|
292
904
|
tag: tags.heading6,
|
|
293
|
-
class: heading
|
|
905
|
+
class: heading(6, readonly)
|
|
294
906
|
},
|
|
295
907
|
// Emphasis.
|
|
296
908
|
{
|
|
@@ -312,18 +924,11 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
312
924
|
],
|
|
313
925
|
class: inlineUrl
|
|
314
926
|
},
|
|
315
|
-
//
|
|
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).
|
|
927
|
+
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
324
928
|
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
325
929
|
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
326
930
|
// the code, but all other CSS properties will be inherited.
|
|
931
|
+
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
327
932
|
{
|
|
328
933
|
tag: [
|
|
329
934
|
markdownTags.CodeText,
|
|
@@ -341,7 +946,7 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
341
946
|
tag: [
|
|
342
947
|
markdownTags.HorizontalRule
|
|
343
948
|
],
|
|
344
|
-
class: horizontalRule
|
|
949
|
+
class: mx2(horizontalRule, readonly && "-indent-[100rem]")
|
|
345
950
|
}
|
|
346
951
|
], {
|
|
347
952
|
scope: markdownLanguage,
|
|
@@ -351,14 +956,13 @@ var markdownHighlightStyle = HighlightStyle.define([
|
|
|
351
956
|
});
|
|
352
957
|
|
|
353
958
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
354
|
-
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
959
|
+
var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
355
960
|
return [
|
|
356
961
|
bracketMatching2(),
|
|
357
962
|
closeBrackets2(),
|
|
358
963
|
_placeholder && placeholder2(_placeholder),
|
|
359
964
|
EditorState.allowMultipleSelections.of(true),
|
|
360
|
-
|
|
361
|
-
// autocompletion(),
|
|
965
|
+
EditorView6.lineWrapping,
|
|
362
966
|
crosshairCursor(),
|
|
363
967
|
dropCursor(),
|
|
364
968
|
drawSelection(),
|
|
@@ -369,16 +973,7 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
369
973
|
history(),
|
|
370
974
|
indentOnInput(),
|
|
371
975
|
rectangularSelection(),
|
|
372
|
-
|
|
373
|
-
...closeBracketsKeymap,
|
|
374
|
-
// ...completionKeymap,
|
|
375
|
-
...defaultKeymap,
|
|
376
|
-
...foldKeymap,
|
|
377
|
-
...historyKeymap,
|
|
378
|
-
...lintKeymap,
|
|
379
|
-
...searchKeymap,
|
|
380
|
-
indentWithTab
|
|
381
|
-
]),
|
|
976
|
+
customkeymap(),
|
|
382
977
|
// Main extension.
|
|
383
978
|
// https://github.com/codemirror/lang-markdown
|
|
384
979
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -393,102 +988,229 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
393
988
|
codeLanguages: languages,
|
|
394
989
|
// Parser extensions.
|
|
395
990
|
extensions: [
|
|
396
|
-
// GFM
|
|
991
|
+
// GFM provided by default.
|
|
397
992
|
markdownTagsExtension
|
|
398
993
|
]
|
|
399
994
|
}),
|
|
995
|
+
// https://github.com/codemirror/theme-one-dark
|
|
996
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
400
997
|
// 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)
|
|
998
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
404
999
|
].filter(Boolean);
|
|
405
1000
|
};
|
|
1001
|
+
var customkeymap = () => keymap5.of([
|
|
1002
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1003
|
+
indentWithTab,
|
|
1004
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1005
|
+
...standardKeymap,
|
|
1006
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1007
|
+
...historyKeymap,
|
|
1008
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1009
|
+
...closeBracketsKeymap,
|
|
1010
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1011
|
+
...searchKeymap
|
|
1012
|
+
]);
|
|
1013
|
+
|
|
1014
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
|
|
1015
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1016
|
+
var mention = ({ onSearch }) => {
|
|
1017
|
+
return autocompletion2({
|
|
1018
|
+
closeOnBlur: false,
|
|
1019
|
+
override: [
|
|
1020
|
+
(context) => {
|
|
1021
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
1022
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
1023
|
+
return null;
|
|
1024
|
+
}
|
|
1025
|
+
console.log(match);
|
|
1026
|
+
return {
|
|
1027
|
+
from: match.from,
|
|
1028
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1029
|
+
label: `@${value}`
|
|
1030
|
+
}))
|
|
1031
|
+
};
|
|
1032
|
+
}
|
|
1033
|
+
]
|
|
1034
|
+
});
|
|
1035
|
+
};
|
|
1036
|
+
|
|
1037
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/table.ts
|
|
1038
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1039
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
|
|
1040
|
+
import { Decoration as Decoration4, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1041
|
+
var table = (options = {}) => {
|
|
1042
|
+
return StateField5.define({
|
|
1043
|
+
create: (state) => update3(state, options),
|
|
1044
|
+
update: (_, tr) => update3(tr.state, options),
|
|
1045
|
+
provide: (field) => EditorView7.decorations.from(field)
|
|
1046
|
+
});
|
|
1047
|
+
};
|
|
1048
|
+
var update3 = (state, options) => {
|
|
1049
|
+
const builder = new RangeSetBuilder3();
|
|
1050
|
+
if (state.readOnly) {
|
|
1051
|
+
const tables = [];
|
|
1052
|
+
const getTable = () => tables[tables.length - 1];
|
|
1053
|
+
const getRow = () => {
|
|
1054
|
+
const table2 = getTable();
|
|
1055
|
+
return table2.rows?.[table2.rows.length - 1];
|
|
1056
|
+
};
|
|
1057
|
+
syntaxTree3(state).iterate({
|
|
1058
|
+
enter: (node) => {
|
|
1059
|
+
switch (node.name) {
|
|
1060
|
+
case "Table": {
|
|
1061
|
+
tables.push({
|
|
1062
|
+
from: node.from
|
|
1063
|
+
});
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
case "TableHeader": {
|
|
1067
|
+
getTable().header = [];
|
|
1068
|
+
break;
|
|
1069
|
+
}
|
|
1070
|
+
case "TableRow": {
|
|
1071
|
+
(getTable().rows ??= []).push([]);
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
case "TableCell": {
|
|
1075
|
+
const row = getRow();
|
|
1076
|
+
if (row) {
|
|
1077
|
+
row.push(state.sliceDoc(node.from, node.to));
|
|
1078
|
+
} else {
|
|
1079
|
+
getTable().header?.push(state.sliceDoc(node.from, node.to));
|
|
1080
|
+
}
|
|
1081
|
+
break;
|
|
1082
|
+
}
|
|
1083
|
+
case "TableDelimiter": {
|
|
1084
|
+
getTable().to = node.to;
|
|
1085
|
+
break;
|
|
1086
|
+
}
|
|
1087
|
+
}
|
|
1088
|
+
}
|
|
1089
|
+
});
|
|
1090
|
+
tables.forEach((table2) => builder.add(table2.from, table2.to, Decoration4.replace({
|
|
1091
|
+
widget: new TableWidget(table2)
|
|
1092
|
+
})));
|
|
1093
|
+
}
|
|
1094
|
+
return builder.finish();
|
|
1095
|
+
};
|
|
1096
|
+
var TableWidget = class extends WidgetType4 {
|
|
1097
|
+
constructor(_table) {
|
|
1098
|
+
super();
|
|
1099
|
+
this._table = _table;
|
|
1100
|
+
}
|
|
1101
|
+
eq(other) {
|
|
1102
|
+
return this._table.from === other?._table?.from;
|
|
1103
|
+
}
|
|
1104
|
+
toDOM(view) {
|
|
1105
|
+
const table2 = document.createElement("table");
|
|
1106
|
+
{
|
|
1107
|
+
const header = table2.appendChild(document.createElement("thead"));
|
|
1108
|
+
const row = header.appendChild(document.createElement("tr"));
|
|
1109
|
+
this._table.header?.forEach((cell) => {
|
|
1110
|
+
const th = document.createElement("th");
|
|
1111
|
+
th.setAttribute("class", "cm-table-head");
|
|
1112
|
+
row.appendChild(th).textContent = cell;
|
|
1113
|
+
});
|
|
1114
|
+
}
|
|
1115
|
+
{
|
|
1116
|
+
const body = table2.appendChild(document.createElement("tbody"));
|
|
1117
|
+
this._table.rows?.forEach((row) => {
|
|
1118
|
+
const tr = body.appendChild(document.createElement("tr"));
|
|
1119
|
+
row.forEach((cell) => {
|
|
1120
|
+
const td = document.createElement("td");
|
|
1121
|
+
td.setAttribute("class", "cm-table-cell");
|
|
1122
|
+
tr.appendChild(td).textContent = cell;
|
|
1123
|
+
});
|
|
1124
|
+
});
|
|
1125
|
+
}
|
|
1126
|
+
return table2;
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
406
1129
|
|
|
407
1130
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
408
|
-
import {
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
var CheckboxWidget = class extends WidgetType2 {
|
|
412
|
-
constructor(_pos, _getCursor, _checked) {
|
|
1131
|
+
import { EditorView as EditorView8, Decoration as Decoration5, WidgetType as WidgetType5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
|
|
1132
|
+
var CheckboxWidget = class extends WidgetType5 {
|
|
1133
|
+
constructor(_pos, _checked, _indent, _onCheck) {
|
|
413
1134
|
super();
|
|
414
1135
|
this._pos = _pos;
|
|
415
|
-
this._getCursor = _getCursor;
|
|
416
1136
|
this._checked = _checked;
|
|
1137
|
+
this._indent = _indent;
|
|
1138
|
+
this._onCheck = _onCheck;
|
|
417
1139
|
}
|
|
418
1140
|
eq(other) {
|
|
419
|
-
return this._pos === other._pos && this._checked === other._checked;
|
|
1141
|
+
return this._pos === other._pos && this._checked === other._checked && this._indent === other._indent;
|
|
420
1142
|
}
|
|
421
1143
|
toDOM(view) {
|
|
422
1144
|
const wrap = document.createElement("span");
|
|
423
|
-
wrap.setAttribute("aria-hidden", "true");
|
|
424
1145
|
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
|
-
};
|
|
1146
|
+
wrap.setAttribute("aria-hidden", "true");
|
|
1147
|
+
wrap.style.setProperty("margin-left", this._indent * 24 + "px");
|
|
1148
|
+
const input = wrap.appendChild(document.createElement("input"));
|
|
1149
|
+
input.type = "checkbox";
|
|
1150
|
+
input.checked = this._checked;
|
|
1151
|
+
if (!this._onCheck) {
|
|
1152
|
+
input.setAttribute("disabled", "true");
|
|
1153
|
+
}
|
|
1154
|
+
if (this._onCheck) {
|
|
1155
|
+
input.onchange = (event) => {
|
|
1156
|
+
this._onCheck?.(event.target.checked);
|
|
1157
|
+
return true;
|
|
1158
|
+
};
|
|
1159
|
+
}
|
|
443
1160
|
return wrap;
|
|
444
1161
|
}
|
|
445
|
-
// TODO(burdon): Remove listener?
|
|
446
|
-
// override destroy() {
|
|
447
|
-
// console.log('destroy', this._pos);
|
|
448
|
-
// }
|
|
449
1162
|
ignoreEvent() {
|
|
450
1163
|
return false;
|
|
451
1164
|
}
|
|
452
1165
|
};
|
|
453
|
-
var
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
1166
|
+
var styles2 = EditorView8.baseTheme({
|
|
1167
|
+
"& .cm-task-item": {
|
|
1168
|
+
paddingLeft: "4px",
|
|
1169
|
+
paddingRight: "8px"
|
|
1170
|
+
}
|
|
1171
|
+
});
|
|
1172
|
+
var tasklist = (options = {}) => {
|
|
1173
|
+
const taskMatcher = new MatchDecorator2({
|
|
1174
|
+
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
1175
|
+
decoration: (match, view, pos) => {
|
|
1176
|
+
const indent = Math.floor(match[1].length / 2);
|
|
1177
|
+
const checked = match[2] === "x" || match[2] === "X";
|
|
1178
|
+
return Decoration5.replace({
|
|
1179
|
+
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
1180
|
+
const idx = pos + match[0].indexOf("[") + 1;
|
|
1181
|
+
view.dispatch({
|
|
1182
|
+
changes: {
|
|
1183
|
+
from: idx,
|
|
1184
|
+
to: idx + 1,
|
|
1185
|
+
insert: checked2 ? "x" : " "
|
|
1186
|
+
},
|
|
1187
|
+
// TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
|
|
1188
|
+
selection: {
|
|
1189
|
+
anchor: idx + 3
|
|
1190
|
+
}
|
|
1191
|
+
});
|
|
1192
|
+
})
|
|
1193
|
+
});
|
|
1194
|
+
}
|
|
460
1195
|
});
|
|
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)
|
|
1196
|
+
const tasks = ViewPlugin2.fromClass(class {
|
|
1197
|
+
constructor(view) {
|
|
1198
|
+
this.tasks = taskMatcher.createDeco(view);
|
|
1199
|
+
}
|
|
1200
|
+
update(update4) {
|
|
1201
|
+
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
1202
|
+
}
|
|
1203
|
+
}, {
|
|
1204
|
+
decorations: (instance) => instance.tasks,
|
|
1205
|
+
provide: (plugin) => EditorView8.atomicRanges.of((view) => {
|
|
1206
|
+
return view.plugin(plugin)?.tasks || Decoration5.none;
|
|
480
1207
|
})
|
|
1208
|
+
});
|
|
1209
|
+
return [
|
|
1210
|
+
tasks,
|
|
1211
|
+
styles2
|
|
481
1212
|
];
|
|
482
1213
|
};
|
|
483
|
-
var styles = EditorView4.baseTheme({
|
|
484
|
-
"& .cm-task-item": {
|
|
485
|
-
padding: "0 4px"
|
|
486
|
-
}
|
|
487
|
-
});
|
|
488
|
-
var tasklist = () => [
|
|
489
|
-
statefield(),
|
|
490
|
-
styles
|
|
491
|
-
];
|
|
492
1214
|
|
|
493
1215
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tooltip.tsx
|
|
494
1216
|
import { hoverTooltip } from "@codemirror/view";
|
|
@@ -648,8 +1370,51 @@ var defaultTheme = {
|
|
|
648
1370
|
"& .cm-tooltip": {
|
|
649
1371
|
border: "none"
|
|
650
1372
|
},
|
|
651
|
-
|
|
652
|
-
//
|
|
1373
|
+
"& .cm-tooltip-below": {},
|
|
1374
|
+
//
|
|
1375
|
+
// autocomplete
|
|
1376
|
+
//
|
|
1377
|
+
"& .cm-tooltip-autocomplete": {
|
|
1378
|
+
marginTop: "4px",
|
|
1379
|
+
marginLeft: "-3px"
|
|
1380
|
+
},
|
|
1381
|
+
"& .cm-tooltip-autocomplete ul li": {},
|
|
1382
|
+
"& .cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
1383
|
+
"& .cm-completionIcon": {
|
|
1384
|
+
display: "none"
|
|
1385
|
+
},
|
|
1386
|
+
"& .cm-completionLabel": {
|
|
1387
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
1388
|
+
},
|
|
1389
|
+
"& .cm-completionMatchedText": {
|
|
1390
|
+
textDecoration: "none"
|
|
1391
|
+
},
|
|
1392
|
+
//
|
|
1393
|
+
// widgets
|
|
1394
|
+
//
|
|
1395
|
+
"& .cm-widgetBuffer": {
|
|
1396
|
+
display: "none",
|
|
1397
|
+
height: 0
|
|
1398
|
+
},
|
|
1399
|
+
//
|
|
1400
|
+
// table
|
|
1401
|
+
//
|
|
1402
|
+
"& .cm-table-head": {
|
|
1403
|
+
padding: "2px 16px 2px 0px",
|
|
1404
|
+
borderBottom: `1px solid ${get2(tokens, "extend.colors.neutral.500")}`,
|
|
1405
|
+
fontWeight: 100,
|
|
1406
|
+
textAlign: "left",
|
|
1407
|
+
color: get2(tokens, "extend.colors.neutral.500")
|
|
1408
|
+
},
|
|
1409
|
+
"& .cm-table-cell": {
|
|
1410
|
+
padding: "2px 16px 2px 0px"
|
|
1411
|
+
},
|
|
1412
|
+
//
|
|
1413
|
+
// image
|
|
1414
|
+
//
|
|
1415
|
+
"& .cm-image": {
|
|
1416
|
+
margin: "0.5rem 0"
|
|
1417
|
+
},
|
|
653
1418
|
//
|
|
654
1419
|
// font size
|
|
655
1420
|
// 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.
|
|
@@ -677,33 +1442,57 @@ var defaultTheme = {
|
|
|
677
1442
|
var textTheme = {
|
|
678
1443
|
"& .cm-scroller": {
|
|
679
1444
|
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
1445
|
+
},
|
|
1446
|
+
"& .cm-placeholder": {
|
|
1447
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
1448
|
+
}
|
|
1449
|
+
};
|
|
1450
|
+
var markdownTheme = {
|
|
1451
|
+
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
1452
|
+
"& .cm-placeholder": {
|
|
1453
|
+
fontFamily: get2(tokens, "fontFamily.body", []).join(",")
|
|
680
1454
|
}
|
|
681
1455
|
};
|
|
682
1456
|
var codeTheme = {
|
|
683
1457
|
"& .cm-scroller": {
|
|
684
1458
|
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
1459
|
+
},
|
|
1460
|
+
"& .cm-placeholder": {
|
|
1461
|
+
fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
|
|
685
1462
|
}
|
|
686
1463
|
};
|
|
687
1464
|
|
|
688
1465
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
689
1466
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
690
|
-
import { EditorView as
|
|
1467
|
+
import { EditorView as EditorView9 } from "@codemirror/view";
|
|
691
1468
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
692
1469
|
import { vim } from "@replit/codemirror-vim";
|
|
693
|
-
import
|
|
1470
|
+
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
694
1471
|
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
695
1472
|
import { generateName } from "@dxos/display-name";
|
|
696
1473
|
import { useThemeContext } from "@dxos/react-ui";
|
|
697
|
-
import { getColorForValue, inputSurface, mx as
|
|
1474
|
+
import { getColorForValue, inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
|
|
698
1475
|
var EditorModes = [
|
|
699
1476
|
"default",
|
|
700
1477
|
"vim"
|
|
701
1478
|
];
|
|
702
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots
|
|
1479
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
|
|
703
1480
|
const { themeMode } = useThemeContext();
|
|
704
1481
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
705
1482
|
tabBehavior: "limited"
|
|
706
1483
|
});
|
|
1484
|
+
const [root, setRoot] = useState(null);
|
|
1485
|
+
const [state, setState] = useState();
|
|
1486
|
+
const [view, setView] = useState();
|
|
1487
|
+
useImperativeHandle(forwardedRef, () => ({
|
|
1488
|
+
root,
|
|
1489
|
+
state,
|
|
1490
|
+
view
|
|
1491
|
+
}), [
|
|
1492
|
+
view,
|
|
1493
|
+
state,
|
|
1494
|
+
root
|
|
1495
|
+
]);
|
|
707
1496
|
const { awareness, peer } = model;
|
|
708
1497
|
useEffect(() => {
|
|
709
1498
|
if (awareness && peer) {
|
|
@@ -725,18 +1514,6 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
725
1514
|
peer,
|
|
726
1515
|
themeMode
|
|
727
1516
|
]);
|
|
728
|
-
const [root, setRoot] = useState(null);
|
|
729
|
-
const [state, setState] = useState();
|
|
730
|
-
const [view, setView] = useState();
|
|
731
|
-
useImperativeHandle(forwardedRef, () => ({
|
|
732
|
-
root,
|
|
733
|
-
state,
|
|
734
|
-
view
|
|
735
|
-
}), [
|
|
736
|
-
view,
|
|
737
|
-
state,
|
|
738
|
-
root
|
|
739
|
-
]);
|
|
740
1517
|
useEffect(() => {
|
|
741
1518
|
if (!root) {
|
|
742
1519
|
return;
|
|
@@ -744,13 +1521,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
744
1521
|
const state2 = EditorState2.create({
|
|
745
1522
|
doc: model.text(),
|
|
746
1523
|
extensions: [
|
|
1524
|
+
readonly && EditorState2.readOnly.of(readonly),
|
|
747
1525
|
// TODO(burdon): Factor out VIM mode?
|
|
748
1526
|
editorMode === "vim" && vim(),
|
|
749
1527
|
// Theme.
|
|
750
|
-
|
|
751
|
-
|
|
1528
|
+
EditorView9.baseTheme(defaultTheme),
|
|
1529
|
+
EditorView9.theme(slots?.editor?.theme ?? {}),
|
|
752
1530
|
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
753
|
-
|
|
1531
|
+
EditorView9.darkTheme.of(themeMode === "dark"),
|
|
754
1532
|
// Storage and replication.
|
|
755
1533
|
model.extension,
|
|
756
1534
|
// Custom.
|
|
@@ -758,7 +1536,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
758
1536
|
].filter(Boolean)
|
|
759
1537
|
});
|
|
760
1538
|
view?.destroy();
|
|
761
|
-
setView(new
|
|
1539
|
+
setView(new EditorView9({
|
|
762
1540
|
state: state2,
|
|
763
1541
|
parent: root
|
|
764
1542
|
}));
|
|
@@ -772,6 +1550,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
772
1550
|
root,
|
|
773
1551
|
model,
|
|
774
1552
|
themeMode,
|
|
1553
|
+
readonly,
|
|
775
1554
|
editorMode
|
|
776
1555
|
]);
|
|
777
1556
|
const handleKeyUp = useCallback((event) => {
|
|
@@ -799,13 +1578,15 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
799
1578
|
onKeyUp: handleKeyUp
|
|
800
1579
|
});
|
|
801
1580
|
});
|
|
802
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1581
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
803
1582
|
const { themeMode } = useThemeContext();
|
|
804
|
-
const slots =
|
|
1583
|
+
const slots = defaultsDeep2({}, _slots, defaultTextSlots);
|
|
805
1584
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
806
1585
|
ref: forwardedRef,
|
|
1586
|
+
readonly,
|
|
807
1587
|
extensions: [
|
|
808
1588
|
basicBundle({
|
|
1589
|
+
readonly,
|
|
809
1590
|
themeMode,
|
|
810
1591
|
placeholder: slots?.editor?.placeholder
|
|
811
1592
|
}),
|
|
@@ -815,13 +1596,15 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, .
|
|
|
815
1596
|
...props
|
|
816
1597
|
});
|
|
817
1598
|
});
|
|
818
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1599
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
819
1600
|
const { themeMode } = useThemeContext();
|
|
820
|
-
const slots =
|
|
1601
|
+
const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
|
|
821
1602
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
822
1603
|
ref: forwardedRef,
|
|
1604
|
+
readonly,
|
|
823
1605
|
extensions: [
|
|
824
1606
|
markdownBundle({
|
|
1607
|
+
readonly,
|
|
825
1608
|
themeMode,
|
|
826
1609
|
placeholder: slots?.editor?.placeholder
|
|
827
1610
|
}),
|
|
@@ -833,7 +1616,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slot
|
|
|
833
1616
|
});
|
|
834
1617
|
var defaultSlots = {
|
|
835
1618
|
root: {
|
|
836
|
-
className:
|
|
1619
|
+
className: mx3("p-2", inputSurface)
|
|
837
1620
|
}
|
|
838
1621
|
};
|
|
839
1622
|
var defaultTextSlots = {
|
|
@@ -842,25 +1625,31 @@ var defaultTextSlots = {
|
|
|
842
1625
|
theme: textTheme
|
|
843
1626
|
}
|
|
844
1627
|
};
|
|
1628
|
+
var defaultMarkdownSlots = {
|
|
1629
|
+
...defaultSlots,
|
|
1630
|
+
editor: {
|
|
1631
|
+
theme: markdownTheme
|
|
1632
|
+
}
|
|
1633
|
+
};
|
|
845
1634
|
|
|
846
1635
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
847
1636
|
import get3 from "lodash.get";
|
|
848
1637
|
import { useEffect as useEffect2, useState as useState2 } from "react";
|
|
849
1638
|
import { yCollab } from "y-codemirror.next";
|
|
850
|
-
import { invariant } from "@dxos/invariant";
|
|
1639
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
851
1640
|
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
852
1641
|
|
|
853
1642
|
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
854
|
-
import { Annotation, Facet, StateEffect, StateField as
|
|
855
|
-
import { ViewPlugin } from "@codemirror/view";
|
|
1643
|
+
import { Annotation, Facet, StateEffect, StateField as StateField6 } from "@codemirror/state";
|
|
1644
|
+
import { ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
856
1645
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
857
1646
|
|
|
858
1647
|
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
859
1648
|
import { next as automerge } from "@dxos/automerge/automerge";
|
|
860
1649
|
|
|
861
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/
|
|
1650
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/translation/automerge-to-codemirror.ts
|
|
862
1651
|
import { ChangeSet } from "@codemirror/state";
|
|
863
|
-
var
|
|
1652
|
+
var automergeToCodemirror = (view, selection, target, patches) => {
|
|
864
1653
|
for (const patch of patches) {
|
|
865
1654
|
const changeSpec = handlePatch(patch, target, view.state);
|
|
866
1655
|
if (changeSpec != null) {
|
|
@@ -965,9 +1754,9 @@ var charPath = (textPath, candidatePath) => {
|
|
|
965
1754
|
return null;
|
|
966
1755
|
};
|
|
967
1756
|
|
|
968
|
-
// packages/ui/react-ui-editor/src/hooks/automerge/
|
|
1757
|
+
// packages/ui/react-ui-editor/src/hooks/automerge/translation/codemirror-to-automerge.ts
|
|
969
1758
|
import { next as am } from "@dxos/automerge/automerge";
|
|
970
|
-
var
|
|
1759
|
+
var codemirrorToAutomerge = (field, handle, transactions, state) => {
|
|
971
1760
|
const { lastHeads, path } = state.field(field);
|
|
972
1761
|
let hasChanges = false;
|
|
973
1762
|
for (const tr of transactions) {
|
|
@@ -1011,12 +1800,12 @@ var PatchSemaphore = class {
|
|
|
1011
1800
|
annotations: reconcileAnnotationType.of(true)
|
|
1012
1801
|
});
|
|
1013
1802
|
}
|
|
1014
|
-
let newHeads =
|
|
1803
|
+
let newHeads = codemirrorToAutomerge(this._field, handle, transactions, view.state);
|
|
1015
1804
|
if (newHeads === null || newHeads === void 0) {
|
|
1016
1805
|
newHeads = automerge.getHeads(handle.docSync());
|
|
1017
1806
|
}
|
|
1018
1807
|
const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
|
|
1019
|
-
|
|
1808
|
+
automergeToCodemirror(view, selection, path, diff);
|
|
1020
1809
|
view.dispatch({
|
|
1021
1810
|
effects: updateHeads(newHeads),
|
|
1022
1811
|
annotations: reconcileAnnotationType.of({})
|
|
@@ -1040,7 +1829,7 @@ var semaphoreFacet = Facet.define({
|
|
|
1040
1829
|
combine: (values) => values.at(-1)
|
|
1041
1830
|
});
|
|
1042
1831
|
var automergePlugin = (handle, path) => {
|
|
1043
|
-
const stateField =
|
|
1832
|
+
const stateField = StateField6.define({
|
|
1044
1833
|
create: () => ({
|
|
1045
1834
|
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
1046
1835
|
unreconciledTransactions: [],
|
|
@@ -1070,7 +1859,7 @@ var automergePlugin = (handle, path) => {
|
|
|
1070
1859
|
}
|
|
1071
1860
|
});
|
|
1072
1861
|
const semaphore = new PatchSemaphore(stateField);
|
|
1073
|
-
const viewPlugin =
|
|
1862
|
+
const viewPlugin = ViewPlugin3.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
1074
1863
|
constructor(view) {
|
|
1075
1864
|
this._handleChange = () => {
|
|
1076
1865
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -1078,8 +1867,8 @@ var automergePlugin = (handle, path) => {
|
|
|
1078
1867
|
this._view = view;
|
|
1079
1868
|
handle.addListener("change", this._handleChange);
|
|
1080
1869
|
}
|
|
1081
|
-
update(
|
|
1082
|
-
if (
|
|
1870
|
+
update(update4) {
|
|
1871
|
+
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
1083
1872
|
queueMicrotask(() => {
|
|
1084
1873
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
1085
1874
|
});
|
|
@@ -1101,7 +1890,7 @@ var reconcileAnnotationType = Annotation.define();
|
|
|
1101
1890
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
1102
1891
|
|
|
1103
1892
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
1104
|
-
import * as
|
|
1893
|
+
import * as random2 from "lib0/random";
|
|
1105
1894
|
var cursorColors = [
|
|
1106
1895
|
{
|
|
1107
1896
|
color: "#30bced",
|
|
@@ -1136,7 +1925,7 @@ var cursorColors = [
|
|
|
1136
1925
|
light: "#1be7ff33"
|
|
1137
1926
|
}
|
|
1138
1927
|
];
|
|
1139
|
-
var cursorColor = cursorColors[
|
|
1928
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
1140
1929
|
|
|
1141
1930
|
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
1142
1931
|
import * as decoding from "lib0/decoding";
|
|
@@ -1144,7 +1933,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1144
1933
|
import { Observable } from "lib0/observable";
|
|
1145
1934
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1146
1935
|
import { log } from "@dxos/log";
|
|
1147
|
-
var
|
|
1936
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1148
1937
|
var messageAwareness = 1;
|
|
1149
1938
|
var messageQueryAwareness = 3;
|
|
1150
1939
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1181,7 +1970,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1181
1970
|
removed,
|
|
1182
1971
|
origin
|
|
1183
1972
|
}, {
|
|
1184
|
-
F:
|
|
1973
|
+
F: __dxlog_file3,
|
|
1185
1974
|
L: 67,
|
|
1186
1975
|
S: this,
|
|
1187
1976
|
C: (f, a) => f(...a)
|
|
@@ -1194,7 +1983,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1194
1983
|
}
|
|
1195
1984
|
_handleSpaceMessage({ payload }) {
|
|
1196
1985
|
log("space message", payload, {
|
|
1197
|
-
F:
|
|
1986
|
+
F: __dxlog_file3,
|
|
1198
1987
|
L: 79,
|
|
1199
1988
|
S: this,
|
|
1200
1989
|
C: (f, a) => f(...a)
|
|
@@ -1239,7 +2028,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1239
2028
|
};
|
|
1240
2029
|
|
|
1241
2030
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1242
|
-
var
|
|
2031
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1243
2032
|
var useTextModel = ({ identity, space, text }) => {
|
|
1244
2033
|
const [model, setModel] = useState2(() => createModel({
|
|
1245
2034
|
identity,
|
|
@@ -1260,53 +2049,44 @@ var useTextModel = ({ identity, space, text }) => {
|
|
|
1260
2049
|
return model;
|
|
1261
2050
|
};
|
|
1262
2051
|
var createModel = (options) => {
|
|
1263
|
-
const {
|
|
1264
|
-
if (!space || !text?.doc || !text?.content) {
|
|
1265
|
-
return void 0;
|
|
1266
|
-
}
|
|
2052
|
+
const { text } = options;
|
|
1267
2053
|
if (isActualAutomergeObject(text)) {
|
|
1268
2054
|
return createAutomergeModel(options);
|
|
1269
2055
|
} else {
|
|
2056
|
+
if (!text?.doc) {
|
|
2057
|
+
return void 0;
|
|
2058
|
+
}
|
|
1270
2059
|
return createYjsModel(options);
|
|
1271
2060
|
}
|
|
1272
2061
|
};
|
|
1273
2062
|
var createYjsModel = ({ identity, space, text }) => {
|
|
1274
|
-
|
|
1275
|
-
F:
|
|
1276
|
-
L:
|
|
2063
|
+
invariant3(text?.doc && text?.content, void 0, {
|
|
2064
|
+
F: __dxlog_file4,
|
|
2065
|
+
L: 74,
|
|
1277
2066
|
S: void 0,
|
|
1278
2067
|
A: [
|
|
1279
|
-
"
|
|
2068
|
+
"text?.doc && text?.content",
|
|
1280
2069
|
""
|
|
1281
2070
|
]
|
|
1282
2071
|
});
|
|
1283
|
-
const provider = new SpaceAwarenessProvider({
|
|
2072
|
+
const provider = space ? new SpaceAwarenessProvider({
|
|
1284
2073
|
space,
|
|
1285
2074
|
doc: text.doc,
|
|
1286
2075
|
channel: `yjs.awareness.${text.id}`
|
|
1287
|
-
});
|
|
2076
|
+
}) : void 0;
|
|
1288
2077
|
return {
|
|
1289
2078
|
id: text.doc.guid,
|
|
1290
2079
|
content: text.content,
|
|
1291
2080
|
text: () => text.content.toString(),
|
|
1292
|
-
extension: yCollab(text.content, provider
|
|
1293
|
-
awareness: provider
|
|
2081
|
+
extension: yCollab(text.content, provider?.awareness),
|
|
2082
|
+
awareness: provider?.awareness,
|
|
1294
2083
|
peer: identity ? {
|
|
1295
2084
|
id: identity.identityKey.toHex(),
|
|
1296
2085
|
name: identity.profile?.displayName
|
|
1297
2086
|
} : void 0
|
|
1298
2087
|
};
|
|
1299
2088
|
};
|
|
1300
|
-
var createAutomergeModel = ({ identity,
|
|
1301
|
-
invariant(space && text?.doc && text?.content, void 0, {
|
|
1302
|
-
F: __dxlog_file2,
|
|
1303
|
-
L: 92,
|
|
1304
|
-
S: void 0,
|
|
1305
|
-
A: [
|
|
1306
|
-
"space && text?.doc && text?.content",
|
|
1307
|
-
""
|
|
1308
|
-
]
|
|
1309
|
-
});
|
|
2089
|
+
var createAutomergeModel = ({ identity, text }) => {
|
|
1310
2090
|
const obj = text;
|
|
1311
2091
|
const doc = getRawDoc(obj, [
|
|
1312
2092
|
obj.field
|
|
@@ -1334,19 +2114,26 @@ export {
|
|
|
1334
2114
|
YXmlFragment,
|
|
1335
2115
|
autocomplete,
|
|
1336
2116
|
basicBundle,
|
|
2117
|
+
blast,
|
|
1337
2118
|
codeTheme,
|
|
2119
|
+
comments,
|
|
1338
2120
|
cursorColor,
|
|
2121
|
+
defaultMarkdownSlots,
|
|
2122
|
+
defaultOptions,
|
|
1339
2123
|
defaultSlots,
|
|
1340
2124
|
defaultTextSlots,
|
|
1341
2125
|
defaultTheme,
|
|
2126
|
+
demo,
|
|
2127
|
+
image,
|
|
1342
2128
|
link,
|
|
1343
2129
|
listener,
|
|
1344
2130
|
markdownBundle,
|
|
1345
2131
|
markdownHighlightStyle,
|
|
1346
2132
|
markdownTags,
|
|
1347
2133
|
markdownTagsExtension,
|
|
1348
|
-
|
|
1349
|
-
|
|
2134
|
+
markdownTheme,
|
|
2135
|
+
mention,
|
|
2136
|
+
table,
|
|
1350
2137
|
tags2 as tags,
|
|
1351
2138
|
tasklist,
|
|
1352
2139
|
textTheme,
|