@dxos/react-ui-editor 0.3.10-main.dcfebef → 0.3.10-main.e948ee0
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 +1179 -372
- 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 +23 -2
- package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -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.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 +2 -2
- package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/extensions/demo.d.ts +2 -1
- package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -1
- 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 +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.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 -1
- package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
- package/dist/types/src/components/TextEditor/themes/default.d.ts +5 -0
- package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
- package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -1
- package/dist/types/src/hooks/useTextModel.d.ts +6 -0
- 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 -20
- package/src/components/TextEditor/MarkdownEditor.stories.tsx +124 -32
- package/src/components/TextEditor/TextEditor.stories.tsx +12 -1
- package/src/components/TextEditor/TextEditor.tsx +31 -24
- package/src/components/TextEditor/extensions/autocomplete.ts +5 -20
- 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 +29 -46
- package/src/components/TextEditor/extensions/demo.ts +4 -1
- package/src/components/TextEditor/extensions/experimental.tsx +15 -36
- 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 +6 -0
- package/src/components/TextEditor/extensions/link.ts +17 -25
- package/src/components/TextEditor/extensions/listener.ts +3 -3
- package/src/components/TextEditor/extensions/markdown/bundle.ts +46 -47
- package/src/components/TextEditor/extensions/markdown/highlight.ts +148 -108
- 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 +42 -28
- package/src/components/TextEditor/themes/default.ts +97 -4
- package/src/hooks/automerge/automerge.stories.tsx +1 -0
- package/src/hooks/useTextModel.ts +9 -0
- package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +2 -2
- package/src/styles/markdown.ts +15 -8
- package/src/testing/replicator.ts +1 -0
- package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
|
@@ -24,13 +24,13 @@ var autocomplete = ({ onSearch }) => {
|
|
|
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: onSearch(
|
|
32
|
+
from: match.from,
|
|
33
|
+
options: onSearch(match.text.toLowerCase())
|
|
34
34
|
};
|
|
35
35
|
}
|
|
36
36
|
]
|
|
@@ -42,20 +42,451 @@ var autocomplete = ({ onSearch }) => {
|
|
|
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
|
|
|
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
|
+
|
|
57
488
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
|
|
58
|
-
import { keymap as
|
|
489
|
+
import { keymap as keymap3 } from "@codemirror/view";
|
|
59
490
|
var defaultItems = [
|
|
60
491
|
"hello world!",
|
|
61
492
|
"this is a test.",
|
|
@@ -65,7 +496,7 @@ var demo = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
65
496
|
let t;
|
|
66
497
|
let idx = 0;
|
|
67
498
|
return [
|
|
68
|
-
|
|
499
|
+
keymap3.of([
|
|
69
500
|
{
|
|
70
501
|
// Reset.
|
|
71
502
|
key: "alt-meta-'",
|
|
@@ -112,18 +543,30 @@ var demo = ({ delay = 75, items = defaultItems } = {}) => {
|
|
|
112
543
|
};
|
|
113
544
|
|
|
114
545
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
|
|
115
|
-
import { keymap as
|
|
546
|
+
import { keymap as keymap4, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
|
|
116
547
|
import { debounce } from "@dxos/async";
|
|
117
|
-
import { invariant } from "@dxos/invariant";
|
|
118
|
-
var
|
|
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
|
+
});
|
|
119
561
|
var BookmarkWidget = class extends WidgetType {
|
|
120
|
-
constructor(_pos, _id) {
|
|
562
|
+
constructor(_pos, _id, _handleClick) {
|
|
121
563
|
super();
|
|
122
564
|
this._pos = _pos;
|
|
123
565
|
this._id = _id;
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
566
|
+
this._handleClick = _handleClick;
|
|
567
|
+
invariant2(this._id, void 0, {
|
|
568
|
+
F: __dxlog_file2,
|
|
569
|
+
L: 37,
|
|
127
570
|
S: this,
|
|
128
571
|
A: [
|
|
129
572
|
"this._id",
|
|
@@ -137,65 +580,57 @@ var BookmarkWidget = class extends WidgetType {
|
|
|
137
580
|
toDOM() {
|
|
138
581
|
const span = document.createElement("span");
|
|
139
582
|
span.className = "cm-bookmark";
|
|
140
|
-
span.textContent = "\
|
|
583
|
+
span.textContent = "\xA7";
|
|
584
|
+
span.onclick = () => this._handleClick();
|
|
141
585
|
return span;
|
|
142
586
|
}
|
|
143
587
|
};
|
|
144
|
-
var styles = EditorView2.baseTheme({
|
|
145
|
-
"& .cm-bookmark": {
|
|
146
|
-
cursor: "pointer",
|
|
147
|
-
margin: "4px",
|
|
148
|
-
padding: "4px",
|
|
149
|
-
backgroundColor: "yellow"
|
|
150
|
-
},
|
|
151
|
-
"& .cm-bookmark-selected": {
|
|
152
|
-
backgroundColor: "orange"
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
588
|
var comments = (options = {}) => {
|
|
156
589
|
let active;
|
|
157
590
|
const bookmarkMatcher = new MatchDecorator({
|
|
158
591
|
regexp: /\[\^(\w+)\]/g,
|
|
159
592
|
decoration: (match, view, pos) => {
|
|
160
593
|
const id = match[1];
|
|
161
|
-
return
|
|
594
|
+
return Decoration2.replace({
|
|
162
595
|
id,
|
|
163
|
-
widget: new BookmarkWidget(pos, id)
|
|
596
|
+
widget: new BookmarkWidget(pos, id, () => handleUpdate({
|
|
597
|
+
active: id
|
|
598
|
+
}))
|
|
164
599
|
});
|
|
165
600
|
}
|
|
166
601
|
});
|
|
167
|
-
const bookmarks =
|
|
602
|
+
const bookmarks = ViewPlugin2.fromClass(class {
|
|
168
603
|
constructor(view) {
|
|
169
604
|
this.bookmarks = bookmarkMatcher.createDeco(view);
|
|
170
605
|
}
|
|
171
|
-
update(
|
|
172
|
-
this.bookmarks = bookmarkMatcher.updateDeco(
|
|
606
|
+
update(update4) {
|
|
607
|
+
this.bookmarks = bookmarkMatcher.updateDeco(update4, this.bookmarks);
|
|
173
608
|
}
|
|
174
609
|
}, {
|
|
175
610
|
decorations: (instance) => instance.bookmarks,
|
|
176
|
-
provide: (plugin) =>
|
|
177
|
-
return view.plugin(plugin)?.bookmarks ||
|
|
611
|
+
provide: (plugin) => EditorView4.atomicRanges.of((view) => {
|
|
612
|
+
return view.plugin(plugin)?.bookmarks || Decoration2.none;
|
|
178
613
|
})
|
|
179
614
|
});
|
|
180
|
-
const
|
|
615
|
+
const handleUpdate = debounce((data) => {
|
|
181
616
|
options.onUpdate?.(data);
|
|
182
617
|
}, 200);
|
|
183
618
|
return [
|
|
184
|
-
|
|
619
|
+
keymap4.of([
|
|
185
620
|
{
|
|
186
621
|
key: options?.key ?? "shift-meta-c",
|
|
187
622
|
run: (view) => {
|
|
188
|
-
const
|
|
623
|
+
const { from, to, head } = view.state.selection.main;
|
|
624
|
+
const id = options.onCreate?.(from, to);
|
|
189
625
|
if (id) {
|
|
190
|
-
const pos = view.state.selection.main.head;
|
|
191
626
|
const tag = `[^${id}]`;
|
|
192
627
|
view.dispatch({
|
|
193
628
|
changes: {
|
|
194
|
-
from:
|
|
629
|
+
from: head,
|
|
195
630
|
insert: tag
|
|
196
631
|
},
|
|
197
632
|
selection: {
|
|
198
|
-
anchor:
|
|
633
|
+
anchor: head + tag.length
|
|
199
634
|
}
|
|
200
635
|
});
|
|
201
636
|
return true;
|
|
@@ -206,20 +641,23 @@ var comments = (options = {}) => {
|
|
|
206
641
|
]),
|
|
207
642
|
bookmarks,
|
|
208
643
|
// Monitor cursor movement.
|
|
209
|
-
|
|
644
|
+
EditorView4.updateListener.of((update4) => {
|
|
210
645
|
active = void 0;
|
|
211
646
|
if (!options.onUpdate) {
|
|
212
647
|
return;
|
|
213
648
|
}
|
|
214
|
-
const view =
|
|
215
|
-
const pos =
|
|
649
|
+
const { view, state } = update4;
|
|
650
|
+
const pos = state.selection.main.head;
|
|
216
651
|
const decorations = [];
|
|
217
652
|
const rangeSet = view.plugin(bookmarks)?.bookmarks;
|
|
218
653
|
let closest = Infinity;
|
|
219
|
-
const { from, to } =
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
654
|
+
const { from, to } = (
|
|
655
|
+
/* view.visibleRanges?.[0] ?? */
|
|
656
|
+
{
|
|
657
|
+
from: 0,
|
|
658
|
+
to: state.doc.length
|
|
659
|
+
}
|
|
660
|
+
);
|
|
223
661
|
rangeSet?.between(from, to, (from2, to2, value) => {
|
|
224
662
|
decorations.push({
|
|
225
663
|
from: from2,
|
|
@@ -233,7 +671,7 @@ var comments = (options = {}) => {
|
|
|
233
671
|
}
|
|
234
672
|
});
|
|
235
673
|
if (decorations.length) {
|
|
236
|
-
|
|
674
|
+
handleUpdate({
|
|
237
675
|
active,
|
|
238
676
|
items: decorations.map(({ from: from2, value: { spec: { id } } }) => ({
|
|
239
677
|
id,
|
|
@@ -243,15 +681,170 @@ var comments = (options = {}) => {
|
|
|
243
681
|
});
|
|
244
682
|
}
|
|
245
683
|
}),
|
|
246
|
-
|
|
684
|
+
styles2
|
|
247
685
|
];
|
|
248
686
|
};
|
|
249
687
|
|
|
250
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/
|
|
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
|
|
251
791
|
import { syntaxTree } from "@codemirror/language";
|
|
252
|
-
import { RangeSetBuilder, StateField } from "@codemirror/state";
|
|
253
|
-
import { Decoration as
|
|
254
|
-
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 {
|
|
255
848
|
constructor(_pos, _url, _onAttach) {
|
|
256
849
|
super();
|
|
257
850
|
this._pos = _pos;
|
|
@@ -267,7 +860,7 @@ var LinkButton = class extends WidgetType2 {
|
|
|
267
860
|
return el;
|
|
268
861
|
}
|
|
269
862
|
};
|
|
270
|
-
var LinkText = class extends
|
|
863
|
+
var LinkText = class extends WidgetType3 {
|
|
271
864
|
constructor(_pos, _text, _url) {
|
|
272
865
|
super();
|
|
273
866
|
this._pos = _pos;
|
|
@@ -297,26 +890,26 @@ var LinkText = class extends WidgetType2 {
|
|
|
297
890
|
return link2;
|
|
298
891
|
}
|
|
299
892
|
};
|
|
300
|
-
var
|
|
301
|
-
const builder = new
|
|
893
|
+
var update2 = (state, options) => {
|
|
894
|
+
const builder = new RangeSetBuilder2();
|
|
302
895
|
const cursor = state.selection.main.head;
|
|
303
|
-
|
|
896
|
+
syntaxTree2(state).iterate({
|
|
304
897
|
enter: (node) => {
|
|
305
898
|
if (node.name === "Link") {
|
|
306
|
-
const
|
|
307
|
-
const text =
|
|
899
|
+
const marks2 = node.node.getChildren("LinkMark");
|
|
900
|
+
const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
|
|
308
901
|
const urlNode = node.node.getChild("URL");
|
|
309
902
|
const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
|
|
310
903
|
if (!url) {
|
|
311
904
|
return false;
|
|
312
905
|
}
|
|
313
|
-
if (cursor < node.from || cursor > node.to) {
|
|
314
|
-
builder.add(node.from, node.to,
|
|
906
|
+
if (state.readOnly || cursor < node.from || cursor > node.to) {
|
|
907
|
+
builder.add(node.from, node.to, Decoration5.replace({
|
|
315
908
|
widget: new LinkText(node.from, text, options.link ? url : void 0)
|
|
316
909
|
}));
|
|
317
910
|
}
|
|
318
911
|
if (options.onRender) {
|
|
319
|
-
builder.add(node.to, node.to,
|
|
912
|
+
builder.add(node.to, node.to, Decoration5.replace({
|
|
320
913
|
widget: new LinkButton(node.from, url, options.onRender)
|
|
321
914
|
}));
|
|
322
915
|
}
|
|
@@ -326,69 +919,39 @@ var update = (state, options) => {
|
|
|
326
919
|
});
|
|
327
920
|
return builder.finish();
|
|
328
921
|
};
|
|
329
|
-
var link = (options = {}) => {
|
|
330
|
-
return StateField.define({
|
|
331
|
-
create: (state) => update(state, options),
|
|
332
|
-
update: (_, tr) => update(tr.state, options),
|
|
333
|
-
provide: (field) => EditorView3.decorations.from(field)
|
|
334
|
-
});
|
|
335
|
-
};
|
|
336
922
|
|
|
337
923
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
|
|
338
|
-
import { StateField as
|
|
339
|
-
var
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
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;
|
|
344
933
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
});
|
|
934
|
+
});
|
|
935
|
+
};
|
|
348
936
|
|
|
349
937
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
350
938
|
import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
|
|
351
|
-
import {
|
|
939
|
+
import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
|
|
352
940
|
import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
|
|
353
941
|
import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
354
942
|
import { languages } from "@codemirror/language-data";
|
|
355
|
-
import {
|
|
943
|
+
import { searchKeymap } from "@codemirror/search";
|
|
356
944
|
import { EditorState } from "@codemirror/state";
|
|
357
945
|
import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
|
|
358
|
-
import { crosshairCursor, drawSelection, dropCursor, EditorView as
|
|
946
|
+
import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView8, keymap as keymap5, placeholder as placeholder2 } from "@codemirror/view";
|
|
359
947
|
|
|
360
948
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
361
949
|
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
362
950
|
import { HighlightStyle } from "@codemirror/language";
|
|
363
951
|
import { tags, styleTags, Tag } from "@lezer/highlight";
|
|
364
|
-
import
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
import { mx } from "@dxos/react-ui-theme";
|
|
368
|
-
var heading = {
|
|
369
|
-
1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
|
|
370
|
-
2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
|
|
371
|
-
3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
|
|
372
|
-
4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
|
|
373
|
-
5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
|
|
374
|
-
6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
|
|
375
|
-
};
|
|
376
|
-
var light = "text-neutral-200 dark:text-neutral-800";
|
|
377
|
-
var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
|
|
378
|
-
var bold = "font-bold";
|
|
379
|
-
var italic = "italic";
|
|
380
|
-
var strikethrough = "line-through";
|
|
381
|
-
var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
|
|
382
|
-
var codeMark = "font-mono text-primary-500";
|
|
383
|
-
var inlineUrl = mx(code, "px-1");
|
|
384
|
-
var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
|
|
385
|
-
var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
|
|
386
|
-
|
|
387
|
-
// packages/ui/react-ui-editor/src/styles/tokens.ts
|
|
388
|
-
import { tailwindConfig } from "@dxos/react-ui-theme";
|
|
389
|
-
var tokens = tailwindConfig({}).theme;
|
|
390
|
-
|
|
391
|
-
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
|
|
952
|
+
import { Table } from "@lezer/markdown";
|
|
953
|
+
import get2 from "lodash.get";
|
|
954
|
+
import { mx as mx3 } from "@dxos/react-ui-theme";
|
|
392
955
|
var markdownTags = {
|
|
393
956
|
Blockquote: Tag.define(),
|
|
394
957
|
CodeMark: Tag.define(),
|
|
@@ -401,182 +964,201 @@ var markdownTags = {
|
|
|
401
964
|
LinkReference: Tag.define(),
|
|
402
965
|
ListMark: Tag.define(),
|
|
403
966
|
QuoteMark: Tag.define(),
|
|
404
|
-
URL: Tag.define()
|
|
967
|
+
URL: Tag.define(),
|
|
968
|
+
// Custom.
|
|
969
|
+
TableCell: Tag.define()
|
|
405
970
|
};
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
{
|
|
413
|
-
tag: [
|
|
414
|
-
tags.keyword,
|
|
415
|
-
tags.name,
|
|
416
|
-
tags.deleted,
|
|
417
|
-
tags.character,
|
|
418
|
-
tags.propertyName,
|
|
419
|
-
tags.macroName,
|
|
420
|
-
tags.color,
|
|
421
|
-
tags.constant(tags.name),
|
|
422
|
-
tags.standard(tags.name),
|
|
423
|
-
tags.definition(tags.name),
|
|
424
|
-
tags.separator,
|
|
425
|
-
tags.typeName,
|
|
426
|
-
tags.className,
|
|
427
|
-
tags.number,
|
|
428
|
-
tags.changed,
|
|
429
|
-
tags.annotation,
|
|
430
|
-
tags.modifier,
|
|
431
|
-
tags.self,
|
|
432
|
-
tags.namespace,
|
|
433
|
-
tags.operator,
|
|
434
|
-
tags.operatorKeyword,
|
|
435
|
-
tags.escape,
|
|
436
|
-
tags.regexp,
|
|
437
|
-
tags.special(tags.string),
|
|
438
|
-
tags.meta,
|
|
439
|
-
tags.comment,
|
|
440
|
-
tags.atom,
|
|
441
|
-
tags.bool,
|
|
442
|
-
tags.special(tags.variableName),
|
|
443
|
-
tags.processingInstruction,
|
|
444
|
-
tags.string,
|
|
445
|
-
tags.inserted,
|
|
446
|
-
tags.invalid
|
|
447
|
-
],
|
|
448
|
-
color: "inherit !important"
|
|
449
|
-
},
|
|
450
|
-
// Markdown marks.
|
|
451
|
-
{
|
|
452
|
-
tag: [
|
|
453
|
-
tags.meta,
|
|
454
|
-
tags.processingInstruction,
|
|
455
|
-
markdownTags.CodeMark,
|
|
456
|
-
markdownTags.EmphasisMark,
|
|
457
|
-
markdownTags.HeaderMark,
|
|
458
|
-
markdownTags.LinkLabel,
|
|
459
|
-
markdownTags.LinkReference,
|
|
460
|
-
markdownTags.ListMark,
|
|
461
|
-
markdownTags.QuoteMark
|
|
462
|
-
],
|
|
463
|
-
class: mark
|
|
464
|
-
},
|
|
465
|
-
// Headings.
|
|
466
|
-
{
|
|
467
|
-
tag: tags.heading1,
|
|
468
|
-
class: heading[1]
|
|
469
|
-
},
|
|
470
|
-
{
|
|
471
|
-
tag: tags.heading2,
|
|
472
|
-
class: heading[2]
|
|
473
|
-
},
|
|
474
|
-
{
|
|
475
|
-
tag: tags.heading3,
|
|
476
|
-
class: heading[3]
|
|
477
|
-
},
|
|
478
|
-
{
|
|
479
|
-
tag: tags.heading4,
|
|
480
|
-
class: heading[4]
|
|
481
|
-
},
|
|
482
|
-
{
|
|
483
|
-
tag: tags.heading5,
|
|
484
|
-
class: heading[5]
|
|
485
|
-
},
|
|
486
|
-
{
|
|
487
|
-
tag: tags.heading6,
|
|
488
|
-
class: heading[6]
|
|
489
|
-
},
|
|
490
|
-
// Emphasis.
|
|
491
|
-
{
|
|
492
|
-
tag: tags.emphasis,
|
|
493
|
-
class: italic
|
|
494
|
-
},
|
|
495
|
-
{
|
|
496
|
-
tag: tags.strong,
|
|
497
|
-
class: bold
|
|
498
|
-
},
|
|
499
|
-
{
|
|
500
|
-
tag: tags.strikethrough,
|
|
501
|
-
class: strikethrough
|
|
502
|
-
},
|
|
503
|
-
// Naked URLs.
|
|
504
|
-
{
|
|
505
|
-
tag: [
|
|
506
|
-
markdownTags.URL
|
|
507
|
-
],
|
|
508
|
-
class: inlineUrl
|
|
509
|
-
},
|
|
510
|
-
// E.g., code block language (after ```).
|
|
511
|
-
{
|
|
512
|
-
tag: [
|
|
513
|
-
tags.function(tags.variableName),
|
|
514
|
-
tags.labelName
|
|
515
|
-
],
|
|
516
|
-
class: codeMark
|
|
517
|
-
},
|
|
518
|
-
// NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
|
|
519
|
-
// However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
|
|
520
|
-
// when a language is specified. In this case, the syntax highlighting extensions will colorize
|
|
521
|
-
// the code, but all other CSS properties will be inherited.
|
|
522
|
-
// IMPORTANT: Therefore, the fenced code block will use the base editor font.
|
|
523
|
-
{
|
|
524
|
-
tag: [
|
|
525
|
-
markdownTags.CodeText,
|
|
526
|
-
markdownTags.InlineCode
|
|
527
|
-
],
|
|
528
|
-
class: code
|
|
529
|
-
},
|
|
530
|
-
{
|
|
531
|
-
tag: [
|
|
532
|
-
markdownTags.QuoteMark
|
|
533
|
-
],
|
|
534
|
-
class: blockquote
|
|
535
|
-
},
|
|
536
|
-
{
|
|
537
|
-
tag: [
|
|
538
|
-
markdownTags.HorizontalRule
|
|
539
|
-
],
|
|
540
|
-
class: horizontalRule
|
|
541
|
-
}
|
|
542
|
-
], {
|
|
543
|
-
scope: markdownLanguage,
|
|
544
|
-
all: {
|
|
545
|
-
fontFamily: get(tokens, "fontFamily.body", []).join(",")
|
|
971
|
+
Table.defineNodes?.forEach((node) => {
|
|
972
|
+
switch (node?.name) {
|
|
973
|
+
case "TableCell": {
|
|
974
|
+
node.style = markdownTags.TableCell;
|
|
975
|
+
break;
|
|
976
|
+
}
|
|
546
977
|
}
|
|
547
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
|
+
};
|
|
548
1146
|
|
|
549
1147
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
|
|
550
|
-
var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
1148
|
+
var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
|
|
551
1149
|
return [
|
|
1150
|
+
EditorState.allowMultipleSelections.of(true),
|
|
1151
|
+
EditorState.tabSize.of(2),
|
|
1152
|
+
EditorView8.lineWrapping,
|
|
1153
|
+
customKeymap(),
|
|
552
1154
|
bracketMatching2(),
|
|
553
1155
|
closeBrackets2(),
|
|
554
|
-
_placeholder && placeholder2(_placeholder),
|
|
555
|
-
EditorState.allowMultipleSelections.of(true),
|
|
556
|
-
EditorView4.lineWrapping,
|
|
557
1156
|
crosshairCursor(),
|
|
558
1157
|
dropCursor(),
|
|
559
|
-
|
|
560
|
-
highlightActiveLine(),
|
|
561
|
-
highlightActiveLineGutter(),
|
|
562
|
-
highlightSelectionMatches(),
|
|
563
|
-
highlightSpecialChars(),
|
|
1158
|
+
drawSelection2(),
|
|
564
1159
|
history(),
|
|
565
1160
|
indentOnInput(),
|
|
566
|
-
|
|
567
|
-
// https://codemirror.net/docs/ref/#view.keymap
|
|
568
|
-
keymap4.of([
|
|
569
|
-
// https://codemirror.net/docs/ref/#commands.defaultKeymap
|
|
570
|
-
...defaultKeymap,
|
|
571
|
-
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
572
|
-
...historyKeymap,
|
|
573
|
-
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
574
|
-
...closeBracketsKeymap,
|
|
575
|
-
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
576
|
-
...searchKeymap,
|
|
577
|
-
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
578
|
-
indentWithTab
|
|
579
|
-
]),
|
|
1161
|
+
_placeholder && placeholder2(_placeholder),
|
|
580
1162
|
// Main extension.
|
|
581
1163
|
// https://github.com/codemirror/lang-markdown
|
|
582
1164
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -591,20 +1173,156 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
591
1173
|
codeLanguages: languages,
|
|
592
1174
|
// Parser extensions.
|
|
593
1175
|
extensions: [
|
|
594
|
-
// GFM
|
|
595
|
-
|
|
1176
|
+
// GFM provided by default.
|
|
1177
|
+
markdownTagsExtensions
|
|
596
1178
|
]
|
|
597
1179
|
}),
|
|
1180
|
+
// https://github.com/codemirror/theme-one-dark
|
|
1181
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
598
1182
|
// Custom styles.
|
|
599
|
-
syntaxHighlighting2(markdownHighlightStyle)
|
|
600
|
-
// TODO(thure): All but one rule here apply to both themes; rename or refactor.
|
|
601
|
-
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
|
|
1183
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
602
1184
|
].filter(Boolean);
|
|
603
1185
|
};
|
|
1186
|
+
var customKeymap = () => keymap5.of([
|
|
1187
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1188
|
+
indentWithTab,
|
|
1189
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1190
|
+
...standardKeymap,
|
|
1191
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1192
|
+
...historyKeymap,
|
|
1193
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1194
|
+
...closeBracketsKeymap,
|
|
1195
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1196
|
+
...searchKeymap
|
|
1197
|
+
]);
|
|
1198
|
+
|
|
1199
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
|
|
1200
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1201
|
+
var mention = ({ onSearch }) => {
|
|
1202
|
+
return autocompletion2({
|
|
1203
|
+
closeOnBlur: false,
|
|
1204
|
+
override: [
|
|
1205
|
+
(context) => {
|
|
1206
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
1207
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
1208
|
+
return null;
|
|
1209
|
+
}
|
|
1210
|
+
console.log(match);
|
|
1211
|
+
return {
|
|
1212
|
+
from: match.from,
|
|
1213
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1214
|
+
label: `@${value}`
|
|
1215
|
+
}))
|
|
1216
|
+
};
|
|
1217
|
+
}
|
|
1218
|
+
]
|
|
1219
|
+
});
|
|
1220
|
+
};
|
|
1221
|
+
|
|
1222
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/table.ts
|
|
1223
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1224
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
|
|
1225
|
+
import { Decoration as Decoration6, EditorView as EditorView9, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1226
|
+
var table = (options = {}) => {
|
|
1227
|
+
return StateField5.define({
|
|
1228
|
+
create: (state) => update3(state, options),
|
|
1229
|
+
update: (_, tr) => update3(tr.state, options),
|
|
1230
|
+
provide: (field) => EditorView9.decorations.from(field)
|
|
1231
|
+
});
|
|
1232
|
+
};
|
|
1233
|
+
var update3 = (state, options) => {
|
|
1234
|
+
const builder = new RangeSetBuilder3();
|
|
1235
|
+
const cursor = state.selection.main.head;
|
|
1236
|
+
const tables = [];
|
|
1237
|
+
const getTable = () => tables[tables.length - 1];
|
|
1238
|
+
const getRow = () => {
|
|
1239
|
+
const table2 = getTable();
|
|
1240
|
+
return table2.rows?.[table2.rows.length - 1];
|
|
1241
|
+
};
|
|
1242
|
+
syntaxTree3(state).iterate({
|
|
1243
|
+
enter: (node) => {
|
|
1244
|
+
switch (node.name) {
|
|
1245
|
+
case "Table": {
|
|
1246
|
+
tables.push({
|
|
1247
|
+
from: node.from,
|
|
1248
|
+
to: node.to
|
|
1249
|
+
});
|
|
1250
|
+
break;
|
|
1251
|
+
}
|
|
1252
|
+
case "TableHeader": {
|
|
1253
|
+
getTable().header = [];
|
|
1254
|
+
break;
|
|
1255
|
+
}
|
|
1256
|
+
case "TableRow": {
|
|
1257
|
+
(getTable().rows ??= []).push([]);
|
|
1258
|
+
break;
|
|
1259
|
+
}
|
|
1260
|
+
case "TableCell": {
|
|
1261
|
+
const row = getRow();
|
|
1262
|
+
if (row) {
|
|
1263
|
+
row.push(state.sliceDoc(node.from, node.to));
|
|
1264
|
+
} else {
|
|
1265
|
+
getTable().header?.push(state.sliceDoc(node.from, node.to));
|
|
1266
|
+
}
|
|
1267
|
+
break;
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
});
|
|
1272
|
+
tables.forEach((table2) => {
|
|
1273
|
+
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1274
|
+
hide && builder.add(table2.from, table2.to, Decoration6.replace({
|
|
1275
|
+
widget: new TableWidget(table2)
|
|
1276
|
+
}));
|
|
1277
|
+
builder.add(table2.from, table2.to, Decoration6.mark({
|
|
1278
|
+
class: "cm-table"
|
|
1279
|
+
}));
|
|
1280
|
+
});
|
|
1281
|
+
return builder.finish();
|
|
1282
|
+
};
|
|
1283
|
+
var TableWidget = class extends WidgetType4 {
|
|
1284
|
+
constructor(_table) {
|
|
1285
|
+
super();
|
|
1286
|
+
this._table = _table;
|
|
1287
|
+
}
|
|
1288
|
+
eq(other) {
|
|
1289
|
+
return this._table.from === other?._table?.from;
|
|
1290
|
+
}
|
|
1291
|
+
toDOM(view) {
|
|
1292
|
+
const table2 = document.createElement("table");
|
|
1293
|
+
{
|
|
1294
|
+
const header = table2.appendChild(document.createElement("thead"));
|
|
1295
|
+
const tr = header.appendChild(document.createElement("tr"));
|
|
1296
|
+
this._table.header?.forEach((cell) => {
|
|
1297
|
+
const th = document.createElement("th");
|
|
1298
|
+
th.setAttribute("class", "cm-table-head");
|
|
1299
|
+
tr.appendChild(th).textContent = cell;
|
|
1300
|
+
});
|
|
1301
|
+
}
|
|
1302
|
+
{
|
|
1303
|
+
const body = table2.appendChild(document.createElement("tbody"));
|
|
1304
|
+
this._table.rows?.forEach((row) => {
|
|
1305
|
+
const tr = body.appendChild(document.createElement("tr"));
|
|
1306
|
+
row.forEach((cell) => {
|
|
1307
|
+
const td = document.createElement("td");
|
|
1308
|
+
td.setAttribute("class", "cm-table-cell");
|
|
1309
|
+
tr.appendChild(td).textContent = cell;
|
|
1310
|
+
});
|
|
1311
|
+
});
|
|
1312
|
+
}
|
|
1313
|
+
return table2;
|
|
1314
|
+
}
|
|
1315
|
+
};
|
|
604
1316
|
|
|
605
1317
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
606
|
-
import { EditorView as
|
|
607
|
-
var
|
|
1318
|
+
import { EditorView as EditorView10, Decoration as Decoration7, WidgetType as WidgetType5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
1319
|
+
var styles4 = EditorView10.baseTheme({
|
|
1320
|
+
"& .cm-task-item": {
|
|
1321
|
+
paddingLeft: "4px",
|
|
1322
|
+
paddingRight: "8px"
|
|
1323
|
+
}
|
|
1324
|
+
});
|
|
1325
|
+
var CheckboxWidget = class extends WidgetType5 {
|
|
608
1326
|
constructor(_pos, _checked, _indent, _onCheck) {
|
|
609
1327
|
super();
|
|
610
1328
|
this._pos = _pos;
|
|
@@ -623,30 +1341,29 @@ var CheckboxWidget = class extends WidgetType3 {
|
|
|
623
1341
|
const input = wrap.appendChild(document.createElement("input"));
|
|
624
1342
|
input.type = "checkbox";
|
|
625
1343
|
input.checked = this._checked;
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
1344
|
+
if (!this._onCheck) {
|
|
1345
|
+
input.setAttribute("disabled", "true");
|
|
1346
|
+
}
|
|
1347
|
+
if (this._onCheck) {
|
|
1348
|
+
input.onchange = (event) => {
|
|
1349
|
+
this._onCheck?.(event.target.checked);
|
|
1350
|
+
return true;
|
|
1351
|
+
};
|
|
1352
|
+
}
|
|
630
1353
|
return wrap;
|
|
631
1354
|
}
|
|
632
1355
|
ignoreEvent() {
|
|
633
1356
|
return false;
|
|
634
1357
|
}
|
|
635
1358
|
};
|
|
636
|
-
var
|
|
637
|
-
"& .cm-task-item": {
|
|
638
|
-
paddingLeft: "4px",
|
|
639
|
-
paddingRight: "8px"
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
var tasklist = () => {
|
|
1359
|
+
var tasklist = (options = {}) => {
|
|
643
1360
|
const taskMatcher = new MatchDecorator2({
|
|
644
1361
|
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
645
1362
|
decoration: (match, view, pos) => {
|
|
646
1363
|
const indent = Math.floor(match[1].length / 2);
|
|
647
1364
|
const checked = match[2] === "x" || match[2] === "X";
|
|
648
|
-
return
|
|
649
|
-
widget: new CheckboxWidget(pos, checked, indent, (checked2) => {
|
|
1365
|
+
return Decoration7.replace({
|
|
1366
|
+
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
650
1367
|
const idx = pos + match[0].indexOf("[") + 1;
|
|
651
1368
|
view.dispatch({
|
|
652
1369
|
changes: {
|
|
@@ -663,22 +1380,22 @@ var tasklist = () => {
|
|
|
663
1380
|
});
|
|
664
1381
|
}
|
|
665
1382
|
});
|
|
666
|
-
const tasks =
|
|
1383
|
+
const tasks = ViewPlugin3.fromClass(class {
|
|
667
1384
|
constructor(view) {
|
|
668
1385
|
this.tasks = taskMatcher.createDeco(view);
|
|
669
1386
|
}
|
|
670
|
-
update(
|
|
671
|
-
this.tasks = taskMatcher.updateDeco(
|
|
1387
|
+
update(update4) {
|
|
1388
|
+
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
672
1389
|
}
|
|
673
1390
|
}, {
|
|
674
|
-
decorations: (
|
|
675
|
-
provide: (plugin) =>
|
|
676
|
-
return view.plugin(plugin)?.tasks ||
|
|
1391
|
+
decorations: (value) => value.tasks,
|
|
1392
|
+
provide: (plugin) => EditorView10.atomicRanges.of((view) => {
|
|
1393
|
+
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
677
1394
|
})
|
|
678
1395
|
});
|
|
679
1396
|
return [
|
|
680
1397
|
tasks,
|
|
681
|
-
|
|
1398
|
+
styles4
|
|
682
1399
|
];
|
|
683
1400
|
};
|
|
684
1401
|
|
|
@@ -727,7 +1444,7 @@ var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view,
|
|
|
727
1444
|
});
|
|
728
1445
|
|
|
729
1446
|
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
730
|
-
import
|
|
1447
|
+
import get3 from "lodash.get";
|
|
731
1448
|
var defaultTheme = {
|
|
732
1449
|
//
|
|
733
1450
|
// Main layout:
|
|
@@ -752,20 +1469,20 @@ var defaultTheme = {
|
|
|
752
1469
|
fontSize: "16px"
|
|
753
1470
|
},
|
|
754
1471
|
"&light .cm-content": {
|
|
755
|
-
color:
|
|
1472
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
756
1473
|
caretColor: "black"
|
|
757
1474
|
},
|
|
758
1475
|
"&dark .cm-content": {
|
|
759
|
-
color:
|
|
1476
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
760
1477
|
caretColor: "white"
|
|
761
1478
|
},
|
|
762
1479
|
//
|
|
763
1480
|
// Cursor
|
|
764
1481
|
//
|
|
765
|
-
"&light .cm-cursor": {
|
|
1482
|
+
"&light .cm-cursor, &light .cm-dropCursor": {
|
|
766
1483
|
borderLeft: "2px solid black"
|
|
767
1484
|
},
|
|
768
|
-
"&dark .cm-cursor": {
|
|
1485
|
+
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
769
1486
|
borderLeft: "2px solid white"
|
|
770
1487
|
},
|
|
771
1488
|
"& .cm-placeholder": {
|
|
@@ -785,16 +1502,16 @@ var defaultTheme = {
|
|
|
785
1502
|
// selection
|
|
786
1503
|
//
|
|
787
1504
|
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
788
|
-
background:
|
|
1505
|
+
background: get3(tokens, "extend.colors.primary.150", "#00ffff")
|
|
789
1506
|
},
|
|
790
1507
|
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
791
|
-
background:
|
|
1508
|
+
background: get3(tokens, "extend.colors.primary.850", "#00ffff")
|
|
792
1509
|
},
|
|
793
1510
|
"&light .cm-selectionMatch": {
|
|
794
|
-
background:
|
|
1511
|
+
background: get3(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
795
1512
|
},
|
|
796
1513
|
"&dark .cm-selectionMatch": {
|
|
797
|
-
background:
|
|
1514
|
+
background: get3(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
798
1515
|
},
|
|
799
1516
|
//
|
|
800
1517
|
// collaboration
|
|
@@ -827,12 +1544,12 @@ var defaultTheme = {
|
|
|
827
1544
|
// link
|
|
828
1545
|
//
|
|
829
1546
|
"& .cm-link": {
|
|
830
|
-
color:
|
|
1547
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
831
1548
|
textDecorationLine: "underline",
|
|
832
1549
|
textDecorationThickness: "1px",
|
|
833
1550
|
textUnderlineOffset: "2px",
|
|
834
1551
|
borderRadius: ".125rem",
|
|
835
|
-
fontFamily:
|
|
1552
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
836
1553
|
},
|
|
837
1554
|
//
|
|
838
1555
|
// tooltip
|
|
@@ -840,14 +1557,61 @@ var defaultTheme = {
|
|
|
840
1557
|
"& .cm-tooltip": {
|
|
841
1558
|
border: "none"
|
|
842
1559
|
},
|
|
843
|
-
|
|
844
|
-
//
|
|
1560
|
+
"& .cm-tooltip-below": {},
|
|
1561
|
+
//
|
|
1562
|
+
// autocomplete
|
|
1563
|
+
//
|
|
1564
|
+
"& .cm-tooltip-autocomplete": {
|
|
1565
|
+
marginTop: "4px",
|
|
1566
|
+
marginLeft: "-3px"
|
|
1567
|
+
},
|
|
1568
|
+
"& .cm-tooltip-autocomplete ul li": {},
|
|
1569
|
+
"& .cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
1570
|
+
"& .cm-completionIcon": {
|
|
1571
|
+
display: "none"
|
|
1572
|
+
},
|
|
1573
|
+
"& .cm-completionLabel": {
|
|
1574
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1575
|
+
},
|
|
1576
|
+
"& .cm-completionMatchedText": {
|
|
1577
|
+
textDecoration: "none"
|
|
1578
|
+
},
|
|
1579
|
+
//
|
|
1580
|
+
// widgets
|
|
1581
|
+
//
|
|
1582
|
+
"& .cm-widgetBuffer": {
|
|
1583
|
+
display: "none",
|
|
1584
|
+
height: 0
|
|
1585
|
+
},
|
|
1586
|
+
//
|
|
1587
|
+
// table
|
|
1588
|
+
//
|
|
1589
|
+
"& .cm-table *": {
|
|
1590
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
1591
|
+
textDecoration: "none !important"
|
|
1592
|
+
},
|
|
1593
|
+
"& .cm-table-head": {
|
|
1594
|
+
padding: "2px 16px 2px 0px",
|
|
1595
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
1596
|
+
fontWeight: 100,
|
|
1597
|
+
textAlign: "left",
|
|
1598
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
1599
|
+
},
|
|
1600
|
+
"& .cm-table-cell": {
|
|
1601
|
+
padding: "2px 16px 2px 0px"
|
|
1602
|
+
},
|
|
1603
|
+
//
|
|
1604
|
+
// image
|
|
1605
|
+
//
|
|
1606
|
+
"& .cm-image": {
|
|
1607
|
+
margin: "0.5rem 0"
|
|
1608
|
+
},
|
|
845
1609
|
//
|
|
846
1610
|
// font size
|
|
847
1611
|
// 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.
|
|
848
1612
|
//
|
|
849
|
-
...Object.keys(
|
|
850
|
-
const height =
|
|
1613
|
+
...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
1614
|
+
const height = get3(tokens, [
|
|
851
1615
|
"extend",
|
|
852
1616
|
"fontSize",
|
|
853
1617
|
fontSize,
|
|
@@ -864,46 +1628,81 @@ var defaultTheme = {
|
|
|
864
1628
|
height
|
|
865
1629
|
};
|
|
866
1630
|
return acc;
|
|
867
|
-
}, {})
|
|
1631
|
+
}, {}),
|
|
1632
|
+
/**
|
|
1633
|
+
* Panels
|
|
1634
|
+
* https://github.com/codemirror/search/blob/main/src/search.ts#L745
|
|
1635
|
+
*
|
|
1636
|
+
* Find/replace panel.
|
|
1637
|
+
* <div class="cm-announced">...</div>
|
|
1638
|
+
* <div class="cm-scroller">...</div>
|
|
1639
|
+
* <div class="cm-panels cm-panels-bottom">
|
|
1640
|
+
* <div class="cm-search cm-panel">
|
|
1641
|
+
* <input class="cm-textfield" />
|
|
1642
|
+
* <button class="cm-button">...</button>
|
|
1643
|
+
* <label><input type="checkbox" />...</label>
|
|
1644
|
+
* </div>
|
|
1645
|
+
* </div
|
|
1646
|
+
*/
|
|
1647
|
+
"& .cm-panels": {
|
|
1648
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`,
|
|
1649
|
+
borderBottom: "none"
|
|
1650
|
+
},
|
|
1651
|
+
"& .cm-panel": {
|
|
1652
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
1653
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1654
|
+
},
|
|
1655
|
+
"& .cm-button": {
|
|
1656
|
+
margin: "4px",
|
|
1657
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
1658
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
1659
|
+
border: "none"
|
|
1660
|
+
},
|
|
1661
|
+
"& .cm-searchMatch": {
|
|
1662
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
1663
|
+
},
|
|
1664
|
+
"& .cm-searchMatch.cm-searchMatch-selected": {
|
|
1665
|
+
backgroundColor: get3(tokens, "extend.colors.primary.100")
|
|
1666
|
+
}
|
|
868
1667
|
};
|
|
869
1668
|
var textTheme = {
|
|
870
1669
|
"& .cm-scroller": {
|
|
871
|
-
fontFamily:
|
|
1670
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
872
1671
|
},
|
|
873
1672
|
"& .cm-placeholder": {
|
|
874
|
-
fontFamily:
|
|
1673
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
875
1674
|
}
|
|
876
1675
|
};
|
|
877
1676
|
var markdownTheme = {
|
|
878
1677
|
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
879
1678
|
"& .cm-placeholder": {
|
|
880
|
-
fontFamily:
|
|
1679
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
881
1680
|
}
|
|
882
1681
|
};
|
|
883
1682
|
var codeTheme = {
|
|
884
1683
|
"& .cm-scroller": {
|
|
885
|
-
fontFamily:
|
|
1684
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
886
1685
|
},
|
|
887
1686
|
"& .cm-placeholder": {
|
|
888
|
-
fontFamily:
|
|
1687
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
889
1688
|
}
|
|
890
1689
|
};
|
|
891
1690
|
|
|
892
1691
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
893
1692
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
894
|
-
import { EditorView as
|
|
1693
|
+
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
895
1694
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
896
1695
|
import { vim } from "@replit/codemirror-vim";
|
|
897
|
-
import
|
|
898
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
1696
|
+
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
1697
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
|
|
899
1698
|
import { generateName } from "@dxos/display-name";
|
|
900
1699
|
import { useThemeContext } from "@dxos/react-ui";
|
|
901
|
-
import { getColorForValue, inputSurface, mx as
|
|
1700
|
+
import { getColorForValue, inputSurface, mx as mx4 } from "@dxos/react-ui-theme";
|
|
902
1701
|
var EditorModes = [
|
|
903
1702
|
"default",
|
|
904
1703
|
"vim"
|
|
905
1704
|
];
|
|
906
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots
|
|
1705
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
|
|
907
1706
|
const { themeMode } = useThemeContext();
|
|
908
1707
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
909
1708
|
tabBehavior: "limited"
|
|
@@ -921,7 +1720,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
921
1720
|
root
|
|
922
1721
|
]);
|
|
923
1722
|
const { awareness, peer } = model;
|
|
924
|
-
|
|
1723
|
+
useEffect2(() => {
|
|
925
1724
|
if (awareness && peer) {
|
|
926
1725
|
awareness.setLocalStateField("user", {
|
|
927
1726
|
name: peer.name ?? generateName(peer.id),
|
|
@@ -941,20 +1740,22 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
941
1740
|
peer,
|
|
942
1741
|
themeMode
|
|
943
1742
|
]);
|
|
944
|
-
|
|
1743
|
+
useEffect2(() => {
|
|
945
1744
|
if (!root) {
|
|
946
1745
|
return;
|
|
947
1746
|
}
|
|
948
1747
|
const state2 = EditorState2.create({
|
|
949
1748
|
doc: model.text(),
|
|
950
1749
|
extensions: [
|
|
1750
|
+
readonly && EditorState2.readOnly.of(readonly),
|
|
951
1751
|
// TODO(burdon): Factor out VIM mode?
|
|
952
1752
|
editorMode === "vim" && vim(),
|
|
953
1753
|
// Theme.
|
|
954
|
-
|
|
955
|
-
|
|
1754
|
+
// TODO(burdon): Make optional.
|
|
1755
|
+
EditorView11.baseTheme(defaultTheme),
|
|
1756
|
+
EditorView11.theme(slots?.editor?.theme ?? {}),
|
|
956
1757
|
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
957
|
-
|
|
1758
|
+
EditorView11.darkTheme.of(themeMode === "dark"),
|
|
958
1759
|
// Storage and replication.
|
|
959
1760
|
model.extension,
|
|
960
1761
|
// Custom.
|
|
@@ -962,7 +1763,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
962
1763
|
].filter(Boolean)
|
|
963
1764
|
});
|
|
964
1765
|
view?.destroy();
|
|
965
|
-
setView(new
|
|
1766
|
+
setView(new EditorView11({
|
|
966
1767
|
state: state2,
|
|
967
1768
|
parent: root
|
|
968
1769
|
}));
|
|
@@ -976,6 +1777,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
976
1777
|
root,
|
|
977
1778
|
model,
|
|
978
1779
|
themeMode,
|
|
1780
|
+
readonly,
|
|
979
1781
|
editorMode
|
|
980
1782
|
]);
|
|
981
1783
|
const handleKeyUp = useCallback((event) => {
|
|
@@ -1003,43 +1805,36 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
1003
1805
|
onKeyUp: handleKeyUp
|
|
1004
1806
|
});
|
|
1005
1807
|
});
|
|
1006
|
-
var
|
|
1007
|
-
const items = localStorage.getItem("dxos.composer.demo");
|
|
1008
|
-
if (items) {
|
|
1009
|
-
return demo({
|
|
1010
|
-
items: items.split(",")
|
|
1011
|
-
});
|
|
1012
|
-
}
|
|
1013
|
-
return [];
|
|
1014
|
-
};
|
|
1015
|
-
var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1808
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1016
1809
|
const { themeMode } = useThemeContext();
|
|
1017
|
-
const slots =
|
|
1810
|
+
const slots = defaultsDeep2({}, _slots, defaultTextSlots);
|
|
1018
1811
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1019
1812
|
ref: forwardedRef,
|
|
1813
|
+
readonly,
|
|
1020
1814
|
extensions: [
|
|
1021
1815
|
basicBundle({
|
|
1816
|
+
readonly,
|
|
1022
1817
|
themeMode,
|
|
1023
1818
|
placeholder: slots?.editor?.placeholder
|
|
1024
1819
|
}),
|
|
1025
|
-
maybeDebug(),
|
|
1026
1820
|
...extensions
|
|
1027
1821
|
],
|
|
1028
1822
|
slots,
|
|
1029
1823
|
...props
|
|
1030
1824
|
});
|
|
1031
1825
|
});
|
|
1032
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1826
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1033
1827
|
const { themeMode } = useThemeContext();
|
|
1034
|
-
const slots =
|
|
1828
|
+
const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
|
|
1035
1829
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1036
1830
|
ref: forwardedRef,
|
|
1831
|
+
readonly,
|
|
1037
1832
|
extensions: [
|
|
1038
1833
|
markdownBundle({
|
|
1834
|
+
readonly,
|
|
1039
1835
|
themeMode,
|
|
1040
1836
|
placeholder: slots?.editor?.placeholder
|
|
1041
1837
|
}),
|
|
1042
|
-
maybeDebug(),
|
|
1043
1838
|
...extensions
|
|
1044
1839
|
],
|
|
1045
1840
|
slots,
|
|
@@ -1048,7 +1843,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slot
|
|
|
1048
1843
|
});
|
|
1049
1844
|
var defaultSlots = {
|
|
1050
1845
|
root: {
|
|
1051
|
-
className:
|
|
1846
|
+
className: mx4("p-2", inputSurface)
|
|
1052
1847
|
}
|
|
1053
1848
|
};
|
|
1054
1849
|
var defaultTextSlots = {
|
|
@@ -1065,15 +1860,15 @@ var defaultMarkdownSlots = {
|
|
|
1065
1860
|
};
|
|
1066
1861
|
|
|
1067
1862
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1068
|
-
import
|
|
1069
|
-
import { useEffect as
|
|
1863
|
+
import get4 from "lodash.get";
|
|
1864
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
1070
1865
|
import { yCollab } from "y-codemirror.next";
|
|
1071
|
-
import { invariant as
|
|
1866
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1072
1867
|
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
1073
1868
|
|
|
1074
1869
|
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
1075
|
-
import { Annotation, Facet, StateEffect, StateField as
|
|
1076
|
-
import { ViewPlugin as
|
|
1870
|
+
import { Annotation, Facet, StateEffect as StateEffect2, StateField as StateField6 } from "@codemirror/state";
|
|
1871
|
+
import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1077
1872
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
1078
1873
|
|
|
1079
1874
|
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
@@ -1251,7 +2046,7 @@ var PatchSemaphore = class {
|
|
|
1251
2046
|
};
|
|
1252
2047
|
|
|
1253
2048
|
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
1254
|
-
var effectType =
|
|
2049
|
+
var effectType = StateEffect2.define({});
|
|
1255
2050
|
var updateHeads = (newHeads) => effectType.of({
|
|
1256
2051
|
newHeads
|
|
1257
2052
|
});
|
|
@@ -1261,7 +2056,7 @@ var semaphoreFacet = Facet.define({
|
|
|
1261
2056
|
combine: (values) => values.at(-1)
|
|
1262
2057
|
});
|
|
1263
2058
|
var automergePlugin = (handle, path) => {
|
|
1264
|
-
const stateField =
|
|
2059
|
+
const stateField = StateField6.define({
|
|
1265
2060
|
create: () => ({
|
|
1266
2061
|
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
1267
2062
|
unreconciledTransactions: [],
|
|
@@ -1291,7 +2086,7 @@ var automergePlugin = (handle, path) => {
|
|
|
1291
2086
|
}
|
|
1292
2087
|
});
|
|
1293
2088
|
const semaphore = new PatchSemaphore(stateField);
|
|
1294
|
-
const viewPlugin =
|
|
2089
|
+
const viewPlugin = ViewPlugin4.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
1295
2090
|
constructor(view) {
|
|
1296
2091
|
this._handleChange = () => {
|
|
1297
2092
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -1299,8 +2094,8 @@ var automergePlugin = (handle, path) => {
|
|
|
1299
2094
|
this._view = view;
|
|
1300
2095
|
handle.addListener("change", this._handleChange);
|
|
1301
2096
|
}
|
|
1302
|
-
update(
|
|
1303
|
-
if (
|
|
2097
|
+
update(update4) {
|
|
2098
|
+
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
1304
2099
|
queueMicrotask(() => {
|
|
1305
2100
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
1306
2101
|
});
|
|
@@ -1322,7 +2117,7 @@ var reconcileAnnotationType = Annotation.define();
|
|
|
1322
2117
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
1323
2118
|
|
|
1324
2119
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
1325
|
-
import * as
|
|
2120
|
+
import * as random2 from "lib0/random";
|
|
1326
2121
|
var cursorColors = [
|
|
1327
2122
|
{
|
|
1328
2123
|
color: "#30bced",
|
|
@@ -1357,7 +2152,7 @@ var cursorColors = [
|
|
|
1357
2152
|
light: "#1be7ff33"
|
|
1358
2153
|
}
|
|
1359
2154
|
];
|
|
1360
|
-
var cursorColor = cursorColors[
|
|
2155
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
1361
2156
|
|
|
1362
2157
|
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
1363
2158
|
import * as decoding from "lib0/decoding";
|
|
@@ -1365,7 +2160,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1365
2160
|
import { Observable } from "lib0/observable";
|
|
1366
2161
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1367
2162
|
import { log } from "@dxos/log";
|
|
1368
|
-
var
|
|
2163
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1369
2164
|
var messageAwareness = 1;
|
|
1370
2165
|
var messageQueryAwareness = 3;
|
|
1371
2166
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1402,7 +2197,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1402
2197
|
removed,
|
|
1403
2198
|
origin
|
|
1404
2199
|
}, {
|
|
1405
|
-
F:
|
|
2200
|
+
F: __dxlog_file3,
|
|
1406
2201
|
L: 67,
|
|
1407
2202
|
S: this,
|
|
1408
2203
|
C: (f, a) => f(...a)
|
|
@@ -1415,7 +2210,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1415
2210
|
}
|
|
1416
2211
|
_handleSpaceMessage({ payload }) {
|
|
1417
2212
|
log("space message", payload, {
|
|
1418
|
-
F:
|
|
2213
|
+
F: __dxlog_file3,
|
|
1419
2214
|
L: 79,
|
|
1420
2215
|
S: this,
|
|
1421
2216
|
C: (f, a) => f(...a)
|
|
@@ -1460,14 +2255,14 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1460
2255
|
};
|
|
1461
2256
|
|
|
1462
2257
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1463
|
-
var
|
|
2258
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1464
2259
|
var useTextModel = ({ identity, space, text }) => {
|
|
1465
2260
|
const [model, setModel] = useState2(() => createModel({
|
|
1466
2261
|
identity,
|
|
1467
2262
|
space,
|
|
1468
2263
|
text
|
|
1469
2264
|
}));
|
|
1470
|
-
|
|
2265
|
+
useEffect3(() => {
|
|
1471
2266
|
setModel(createModel({
|
|
1472
2267
|
identity,
|
|
1473
2268
|
space,
|
|
@@ -1492,9 +2287,9 @@ var createModel = (options) => {
|
|
|
1492
2287
|
}
|
|
1493
2288
|
};
|
|
1494
2289
|
var createYjsModel = ({ identity, space, text }) => {
|
|
1495
|
-
|
|
1496
|
-
F:
|
|
1497
|
-
L:
|
|
2290
|
+
invariant3(text?.doc && text?.content, void 0, {
|
|
2291
|
+
F: __dxlog_file4,
|
|
2292
|
+
L: 81,
|
|
1498
2293
|
S: void 0,
|
|
1499
2294
|
A: [
|
|
1500
2295
|
"text?.doc && text?.content",
|
|
@@ -1510,6 +2305,7 @@ var createYjsModel = ({ identity, space, text }) => {
|
|
|
1510
2305
|
id: text.doc.guid,
|
|
1511
2306
|
content: text.content,
|
|
1512
2307
|
text: () => text.content.toString(),
|
|
2308
|
+
ranges: [],
|
|
1513
2309
|
extension: yCollab(text.content, provider?.awareness),
|
|
1514
2310
|
awareness: provider?.awareness,
|
|
1515
2311
|
peer: identity ? {
|
|
@@ -1526,7 +2322,8 @@ var createAutomergeModel = ({ identity, text }) => {
|
|
|
1526
2322
|
return {
|
|
1527
2323
|
id: obj.id,
|
|
1528
2324
|
content: doc,
|
|
1529
|
-
text: () =>
|
|
2325
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2326
|
+
ranges: [],
|
|
1530
2327
|
extension: automergePlugin(doc.handle, doc.path),
|
|
1531
2328
|
peer: identity ? {
|
|
1532
2329
|
id: identity.identityKey.toHex(),
|
|
@@ -1546,25 +2343,35 @@ export {
|
|
|
1546
2343
|
YXmlFragment,
|
|
1547
2344
|
autocomplete,
|
|
1548
2345
|
basicBundle,
|
|
2346
|
+
blast,
|
|
2347
|
+
code2 as code,
|
|
1549
2348
|
codeTheme,
|
|
1550
2349
|
comments,
|
|
1551
2350
|
cursorColor,
|
|
1552
2351
|
defaultMarkdownSlots,
|
|
2352
|
+
defaultOptions,
|
|
1553
2353
|
defaultSlots,
|
|
1554
2354
|
defaultTextSlots,
|
|
1555
2355
|
defaultTheme,
|
|
1556
2356
|
demo,
|
|
2357
|
+
highlight,
|
|
2358
|
+
highlightDecorations,
|
|
2359
|
+
highlightStateField,
|
|
2360
|
+
image,
|
|
1557
2361
|
link,
|
|
1558
|
-
listener,
|
|
2362
|
+
listener2 as listener,
|
|
1559
2363
|
markdownBundle,
|
|
1560
2364
|
markdownHighlightStyle,
|
|
1561
2365
|
markdownTags,
|
|
1562
|
-
|
|
2366
|
+
markdownTagsExtensions,
|
|
1563
2367
|
markdownTheme,
|
|
2368
|
+
mention,
|
|
2369
|
+
table,
|
|
1564
2370
|
tags2 as tags,
|
|
1565
2371
|
tasklist,
|
|
1566
2372
|
textTheme,
|
|
1567
2373
|
tooltip,
|
|
2374
|
+
useHighlights,
|
|
1568
2375
|
useTextModel
|
|
1569
2376
|
};
|
|
1570
2377
|
//# sourceMappingURL=index.mjs.map
|