@dxos/react-ui-editor 0.3.10-main.dcfebef → 0.3.10-main.e38869c
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 +1181 -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 +23 -21
- 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 +45 -37
- 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 +98 -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, highlightActiveLine, 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,202 @@ 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
|
-
|
|
1158
|
+
drawSelection2(),
|
|
560
1159
|
highlightActiveLine(),
|
|
561
|
-
highlightActiveLineGutter(),
|
|
562
|
-
highlightSelectionMatches(),
|
|
563
|
-
highlightSpecialChars(),
|
|
564
1160
|
history(),
|
|
565
1161
|
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
|
-
]),
|
|
1162
|
+
_placeholder && placeholder2(_placeholder),
|
|
580
1163
|
// Main extension.
|
|
581
1164
|
// https://github.com/codemirror/lang-markdown
|
|
582
1165
|
// https://codemirror.net/5/mode/markdown/index.html (demo).
|
|
@@ -591,20 +1174,156 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
|
|
|
591
1174
|
codeLanguages: languages,
|
|
592
1175
|
// Parser extensions.
|
|
593
1176
|
extensions: [
|
|
594
|
-
// GFM
|
|
595
|
-
|
|
1177
|
+
// GFM provided by default.
|
|
1178
|
+
markdownTagsExtensions
|
|
596
1179
|
]
|
|
597
1180
|
}),
|
|
1181
|
+
// https://github.com/codemirror/theme-one-dark
|
|
1182
|
+
themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
|
|
598
1183
|
// 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)
|
|
1184
|
+
syntaxHighlighting2(markdownHighlightStyle(readonly))
|
|
602
1185
|
].filter(Boolean);
|
|
603
1186
|
};
|
|
1187
|
+
var customKeymap = () => keymap5.of([
|
|
1188
|
+
// https://codemirror.net/docs/ref/#commands.indentWithTab
|
|
1189
|
+
indentWithTab,
|
|
1190
|
+
// https://codemirror.net/docs/ref/#commands.standardKeymap
|
|
1191
|
+
...standardKeymap,
|
|
1192
|
+
// https://codemirror.net/docs/ref/#commands.historyKeymap
|
|
1193
|
+
...historyKeymap,
|
|
1194
|
+
// https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
|
|
1195
|
+
...closeBracketsKeymap,
|
|
1196
|
+
// https://codemirror.net/docs/ref/#search.searchKeymap
|
|
1197
|
+
...searchKeymap
|
|
1198
|
+
]);
|
|
1199
|
+
|
|
1200
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
|
|
1201
|
+
import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
|
|
1202
|
+
var mention = ({ onSearch }) => {
|
|
1203
|
+
return autocompletion2({
|
|
1204
|
+
closeOnBlur: false,
|
|
1205
|
+
override: [
|
|
1206
|
+
(context) => {
|
|
1207
|
+
const match = context.matchBefore(/@(\w+)?/);
|
|
1208
|
+
if (!match || match.from === match.to && !context.explicit) {
|
|
1209
|
+
return null;
|
|
1210
|
+
}
|
|
1211
|
+
console.log(match);
|
|
1212
|
+
return {
|
|
1213
|
+
from: match.from,
|
|
1214
|
+
options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
|
|
1215
|
+
label: `@${value}`
|
|
1216
|
+
}))
|
|
1217
|
+
};
|
|
1218
|
+
}
|
|
1219
|
+
]
|
|
1220
|
+
});
|
|
1221
|
+
};
|
|
1222
|
+
|
|
1223
|
+
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/table.ts
|
|
1224
|
+
import { syntaxTree as syntaxTree3 } from "@codemirror/language";
|
|
1225
|
+
import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
|
|
1226
|
+
import { Decoration as Decoration6, EditorView as EditorView9, WidgetType as WidgetType4 } from "@codemirror/view";
|
|
1227
|
+
var table = (options = {}) => {
|
|
1228
|
+
return StateField5.define({
|
|
1229
|
+
create: (state) => update3(state, options),
|
|
1230
|
+
update: (_, tr) => update3(tr.state, options),
|
|
1231
|
+
provide: (field) => EditorView9.decorations.from(field)
|
|
1232
|
+
});
|
|
1233
|
+
};
|
|
1234
|
+
var update3 = (state, options) => {
|
|
1235
|
+
const builder = new RangeSetBuilder3();
|
|
1236
|
+
const cursor = state.selection.main.head;
|
|
1237
|
+
const tables = [];
|
|
1238
|
+
const getTable = () => tables[tables.length - 1];
|
|
1239
|
+
const getRow = () => {
|
|
1240
|
+
const table2 = getTable();
|
|
1241
|
+
return table2.rows?.[table2.rows.length - 1];
|
|
1242
|
+
};
|
|
1243
|
+
syntaxTree3(state).iterate({
|
|
1244
|
+
enter: (node) => {
|
|
1245
|
+
switch (node.name) {
|
|
1246
|
+
case "Table": {
|
|
1247
|
+
tables.push({
|
|
1248
|
+
from: node.from,
|
|
1249
|
+
to: node.to
|
|
1250
|
+
});
|
|
1251
|
+
break;
|
|
1252
|
+
}
|
|
1253
|
+
case "TableHeader": {
|
|
1254
|
+
getTable().header = [];
|
|
1255
|
+
break;
|
|
1256
|
+
}
|
|
1257
|
+
case "TableRow": {
|
|
1258
|
+
(getTable().rows ??= []).push([]);
|
|
1259
|
+
break;
|
|
1260
|
+
}
|
|
1261
|
+
case "TableCell": {
|
|
1262
|
+
const row = getRow();
|
|
1263
|
+
if (row) {
|
|
1264
|
+
row.push(state.sliceDoc(node.from, node.to));
|
|
1265
|
+
} else {
|
|
1266
|
+
getTable().header?.push(state.sliceDoc(node.from, node.to));
|
|
1267
|
+
}
|
|
1268
|
+
break;
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
});
|
|
1273
|
+
tables.forEach((table2) => {
|
|
1274
|
+
const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
|
|
1275
|
+
hide && builder.add(table2.from, table2.to, Decoration6.replace({
|
|
1276
|
+
widget: new TableWidget(table2)
|
|
1277
|
+
}));
|
|
1278
|
+
builder.add(table2.from, table2.to, Decoration6.mark({
|
|
1279
|
+
class: "cm-table"
|
|
1280
|
+
}));
|
|
1281
|
+
});
|
|
1282
|
+
return builder.finish();
|
|
1283
|
+
};
|
|
1284
|
+
var TableWidget = class extends WidgetType4 {
|
|
1285
|
+
constructor(_table) {
|
|
1286
|
+
super();
|
|
1287
|
+
this._table = _table;
|
|
1288
|
+
}
|
|
1289
|
+
eq(other) {
|
|
1290
|
+
return this._table.from === other?._table?.from;
|
|
1291
|
+
}
|
|
1292
|
+
toDOM(view) {
|
|
1293
|
+
const table2 = document.createElement("table");
|
|
1294
|
+
{
|
|
1295
|
+
const header = table2.appendChild(document.createElement("thead"));
|
|
1296
|
+
const tr = header.appendChild(document.createElement("tr"));
|
|
1297
|
+
this._table.header?.forEach((cell) => {
|
|
1298
|
+
const th = document.createElement("th");
|
|
1299
|
+
th.setAttribute("class", "cm-table-head");
|
|
1300
|
+
tr.appendChild(th).textContent = cell;
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1303
|
+
{
|
|
1304
|
+
const body = table2.appendChild(document.createElement("tbody"));
|
|
1305
|
+
this._table.rows?.forEach((row) => {
|
|
1306
|
+
const tr = body.appendChild(document.createElement("tr"));
|
|
1307
|
+
row.forEach((cell) => {
|
|
1308
|
+
const td = document.createElement("td");
|
|
1309
|
+
td.setAttribute("class", "cm-table-cell");
|
|
1310
|
+
tr.appendChild(td).textContent = cell;
|
|
1311
|
+
});
|
|
1312
|
+
});
|
|
1313
|
+
}
|
|
1314
|
+
return table2;
|
|
1315
|
+
}
|
|
1316
|
+
};
|
|
604
1317
|
|
|
605
1318
|
// packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
|
|
606
|
-
import { EditorView as
|
|
607
|
-
var
|
|
1319
|
+
import { EditorView as EditorView10, Decoration as Decoration7, WidgetType as WidgetType5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin3 } from "@codemirror/view";
|
|
1320
|
+
var styles4 = EditorView10.baseTheme({
|
|
1321
|
+
"& .cm-task-item": {
|
|
1322
|
+
paddingLeft: "4px",
|
|
1323
|
+
paddingRight: "8px"
|
|
1324
|
+
}
|
|
1325
|
+
});
|
|
1326
|
+
var CheckboxWidget = class extends WidgetType5 {
|
|
608
1327
|
constructor(_pos, _checked, _indent, _onCheck) {
|
|
609
1328
|
super();
|
|
610
1329
|
this._pos = _pos;
|
|
@@ -623,30 +1342,29 @@ var CheckboxWidget = class extends WidgetType3 {
|
|
|
623
1342
|
const input = wrap.appendChild(document.createElement("input"));
|
|
624
1343
|
input.type = "checkbox";
|
|
625
1344
|
input.checked = this._checked;
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
1345
|
+
if (!this._onCheck) {
|
|
1346
|
+
input.setAttribute("disabled", "true");
|
|
1347
|
+
}
|
|
1348
|
+
if (this._onCheck) {
|
|
1349
|
+
input.onchange = (event) => {
|
|
1350
|
+
this._onCheck?.(event.target.checked);
|
|
1351
|
+
return true;
|
|
1352
|
+
};
|
|
1353
|
+
}
|
|
630
1354
|
return wrap;
|
|
631
1355
|
}
|
|
632
1356
|
ignoreEvent() {
|
|
633
1357
|
return false;
|
|
634
1358
|
}
|
|
635
1359
|
};
|
|
636
|
-
var
|
|
637
|
-
"& .cm-task-item": {
|
|
638
|
-
paddingLeft: "4px",
|
|
639
|
-
paddingRight: "8px"
|
|
640
|
-
}
|
|
641
|
-
});
|
|
642
|
-
var tasklist = () => {
|
|
1360
|
+
var tasklist = (options = {}) => {
|
|
643
1361
|
const taskMatcher = new MatchDecorator2({
|
|
644
1362
|
regexp: /^(\s*)- \[([ xX])\]\s/g,
|
|
645
1363
|
decoration: (match, view, pos) => {
|
|
646
1364
|
const indent = Math.floor(match[1].length / 2);
|
|
647
1365
|
const checked = match[2] === "x" || match[2] === "X";
|
|
648
|
-
return
|
|
649
|
-
widget: new CheckboxWidget(pos, checked, indent, (checked2) => {
|
|
1366
|
+
return Decoration7.replace({
|
|
1367
|
+
widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
|
|
650
1368
|
const idx = pos + match[0].indexOf("[") + 1;
|
|
651
1369
|
view.dispatch({
|
|
652
1370
|
changes: {
|
|
@@ -663,22 +1381,22 @@ var tasklist = () => {
|
|
|
663
1381
|
});
|
|
664
1382
|
}
|
|
665
1383
|
});
|
|
666
|
-
const tasks =
|
|
1384
|
+
const tasks = ViewPlugin3.fromClass(class {
|
|
667
1385
|
constructor(view) {
|
|
668
1386
|
this.tasks = taskMatcher.createDeco(view);
|
|
669
1387
|
}
|
|
670
|
-
update(
|
|
671
|
-
this.tasks = taskMatcher.updateDeco(
|
|
1388
|
+
update(update4) {
|
|
1389
|
+
this.tasks = taskMatcher.updateDeco(update4, this.tasks);
|
|
672
1390
|
}
|
|
673
1391
|
}, {
|
|
674
|
-
decorations: (
|
|
675
|
-
provide: (plugin) =>
|
|
676
|
-
return view.plugin(plugin)?.tasks ||
|
|
1392
|
+
decorations: (value) => value.tasks,
|
|
1393
|
+
provide: (plugin) => EditorView10.atomicRanges.of((view) => {
|
|
1394
|
+
return view.plugin(plugin)?.tasks || Decoration7.none;
|
|
677
1395
|
})
|
|
678
1396
|
});
|
|
679
1397
|
return [
|
|
680
1398
|
tasks,
|
|
681
|
-
|
|
1399
|
+
styles4
|
|
682
1400
|
];
|
|
683
1401
|
};
|
|
684
1402
|
|
|
@@ -727,7 +1445,7 @@ var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view,
|
|
|
727
1445
|
});
|
|
728
1446
|
|
|
729
1447
|
// packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
|
|
730
|
-
import
|
|
1448
|
+
import get3 from "lodash.get";
|
|
731
1449
|
var defaultTheme = {
|
|
732
1450
|
//
|
|
733
1451
|
// Main layout:
|
|
@@ -744,7 +1462,8 @@ var defaultTheme = {
|
|
|
744
1462
|
outline: "none"
|
|
745
1463
|
},
|
|
746
1464
|
"& .cm-scroller": {
|
|
747
|
-
overflow: "visible"
|
|
1465
|
+
overflow: "visible",
|
|
1466
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
748
1467
|
},
|
|
749
1468
|
"& .cm-content": {
|
|
750
1469
|
padding: 0,
|
|
@@ -752,20 +1471,20 @@ var defaultTheme = {
|
|
|
752
1471
|
fontSize: "16px"
|
|
753
1472
|
},
|
|
754
1473
|
"&light .cm-content": {
|
|
755
|
-
color:
|
|
1474
|
+
color: get3(tokens, "extend.colors.neutral.900", "black"),
|
|
756
1475
|
caretColor: "black"
|
|
757
1476
|
},
|
|
758
1477
|
"&dark .cm-content": {
|
|
759
|
-
color:
|
|
1478
|
+
color: get3(tokens, "extend.colors.neutral.100", "white"),
|
|
760
1479
|
caretColor: "white"
|
|
761
1480
|
},
|
|
762
1481
|
//
|
|
763
1482
|
// Cursor
|
|
764
1483
|
//
|
|
765
|
-
"&light .cm-cursor": {
|
|
1484
|
+
"&light .cm-cursor, &light .cm-dropCursor": {
|
|
766
1485
|
borderLeft: "2px solid black"
|
|
767
1486
|
},
|
|
768
|
-
"&dark .cm-cursor": {
|
|
1487
|
+
"&dark .cm-cursor, &dark .cm-dropCursor": {
|
|
769
1488
|
borderLeft: "2px solid white"
|
|
770
1489
|
},
|
|
771
1490
|
"& .cm-placeholder": {
|
|
@@ -785,16 +1504,16 @@ var defaultTheme = {
|
|
|
785
1504
|
// selection
|
|
786
1505
|
//
|
|
787
1506
|
"&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
|
|
788
|
-
background:
|
|
1507
|
+
background: get3(tokens, "extend.colors.primary.150", "#00ffff")
|
|
789
1508
|
},
|
|
790
1509
|
"&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
|
|
791
|
-
background:
|
|
1510
|
+
background: get3(tokens, "extend.colors.primary.850", "#00ffff")
|
|
792
1511
|
},
|
|
793
1512
|
"&light .cm-selectionMatch": {
|
|
794
|
-
background:
|
|
1513
|
+
background: get3(tokens, "extend.colors.primary.250", "#00ffff") + "44"
|
|
795
1514
|
},
|
|
796
1515
|
"&dark .cm-selectionMatch": {
|
|
797
|
-
background:
|
|
1516
|
+
background: get3(tokens, "extend.colors.primary.600", "#00ffff") + "44"
|
|
798
1517
|
},
|
|
799
1518
|
//
|
|
800
1519
|
// collaboration
|
|
@@ -827,12 +1546,12 @@ var defaultTheme = {
|
|
|
827
1546
|
// link
|
|
828
1547
|
//
|
|
829
1548
|
"& .cm-link": {
|
|
830
|
-
color:
|
|
1549
|
+
color: get3(tokens, "extend.colors.primary.500"),
|
|
831
1550
|
textDecorationLine: "underline",
|
|
832
1551
|
textDecorationThickness: "1px",
|
|
833
1552
|
textUnderlineOffset: "2px",
|
|
834
1553
|
borderRadius: ".125rem",
|
|
835
|
-
fontFamily:
|
|
1554
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
836
1555
|
},
|
|
837
1556
|
//
|
|
838
1557
|
// tooltip
|
|
@@ -840,14 +1559,61 @@ var defaultTheme = {
|
|
|
840
1559
|
"& .cm-tooltip": {
|
|
841
1560
|
border: "none"
|
|
842
1561
|
},
|
|
843
|
-
|
|
844
|
-
//
|
|
1562
|
+
"& .cm-tooltip-below": {},
|
|
1563
|
+
//
|
|
1564
|
+
// autocomplete
|
|
1565
|
+
//
|
|
1566
|
+
"& .cm-tooltip-autocomplete": {
|
|
1567
|
+
marginTop: "4px",
|
|
1568
|
+
marginLeft: "-3px"
|
|
1569
|
+
},
|
|
1570
|
+
"& .cm-tooltip-autocomplete ul li": {},
|
|
1571
|
+
"& .cm-tooltip-autocomplete ul li[aria-selected]": {},
|
|
1572
|
+
"& .cm-completionIcon": {
|
|
1573
|
+
display: "none"
|
|
1574
|
+
},
|
|
1575
|
+
"& .cm-completionLabel": {
|
|
1576
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1577
|
+
},
|
|
1578
|
+
"& .cm-completionMatchedText": {
|
|
1579
|
+
textDecoration: "none"
|
|
1580
|
+
},
|
|
1581
|
+
//
|
|
1582
|
+
// widgets
|
|
1583
|
+
//
|
|
1584
|
+
"& .cm-widgetBuffer": {
|
|
1585
|
+
display: "none",
|
|
1586
|
+
height: 0
|
|
1587
|
+
},
|
|
1588
|
+
//
|
|
1589
|
+
// table
|
|
1590
|
+
//
|
|
1591
|
+
"& .cm-table *": {
|
|
1592
|
+
fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
|
|
1593
|
+
textDecoration: "none !important"
|
|
1594
|
+
},
|
|
1595
|
+
"& .cm-table-head": {
|
|
1596
|
+
padding: "2px 16px 2px 0px",
|
|
1597
|
+
borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
|
|
1598
|
+
fontWeight: 100,
|
|
1599
|
+
textAlign: "left",
|
|
1600
|
+
color: get3(tokens, "extend.colors.neutral.500")
|
|
1601
|
+
},
|
|
1602
|
+
"& .cm-table-cell": {
|
|
1603
|
+
padding: "2px 16px 2px 0px"
|
|
1604
|
+
},
|
|
1605
|
+
//
|
|
1606
|
+
// image
|
|
1607
|
+
//
|
|
1608
|
+
"& .cm-image": {
|
|
1609
|
+
margin: "0.5rem 0"
|
|
1610
|
+
},
|
|
845
1611
|
//
|
|
846
1612
|
// font size
|
|
847
1613
|
// 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
1614
|
//
|
|
849
|
-
...Object.keys(
|
|
850
|
-
const height =
|
|
1615
|
+
...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
|
|
1616
|
+
const height = get3(tokens, [
|
|
851
1617
|
"extend",
|
|
852
1618
|
"fontSize",
|
|
853
1619
|
fontSize,
|
|
@@ -864,46 +1630,81 @@ var defaultTheme = {
|
|
|
864
1630
|
height
|
|
865
1631
|
};
|
|
866
1632
|
return acc;
|
|
867
|
-
}, {})
|
|
1633
|
+
}, {}),
|
|
1634
|
+
/**
|
|
1635
|
+
* Panels
|
|
1636
|
+
* https://github.com/codemirror/search/blob/main/src/search.ts#L745
|
|
1637
|
+
*
|
|
1638
|
+
* Find/replace panel.
|
|
1639
|
+
* <div class="cm-announced">...</div>
|
|
1640
|
+
* <div class="cm-scroller">...</div>
|
|
1641
|
+
* <div class="cm-panels cm-panels-bottom">
|
|
1642
|
+
* <div class="cm-search cm-panel">
|
|
1643
|
+
* <input class="cm-textfield" />
|
|
1644
|
+
* <button class="cm-button">...</button>
|
|
1645
|
+
* <label><input type="checkbox" />...</label>
|
|
1646
|
+
* </div>
|
|
1647
|
+
* </div
|
|
1648
|
+
*/
|
|
1649
|
+
"& .cm-panels": {
|
|
1650
|
+
border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`,
|
|
1651
|
+
borderBottom: "none"
|
|
1652
|
+
},
|
|
1653
|
+
"& .cm-panel": {
|
|
1654
|
+
background: get3(tokens, "extend.colors.neutral.50"),
|
|
1655
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
1656
|
+
},
|
|
1657
|
+
"& .cm-button": {
|
|
1658
|
+
margin: "4px",
|
|
1659
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(","),
|
|
1660
|
+
background: get3(tokens, "extend.colors.neutral.100"),
|
|
1661
|
+
border: "none"
|
|
1662
|
+
},
|
|
1663
|
+
"& .cm-searchMatch": {
|
|
1664
|
+
backgroundColor: get3(tokens, "extend.colors.yellow.100")
|
|
1665
|
+
},
|
|
1666
|
+
"& .cm-searchMatch.cm-searchMatch-selected": {
|
|
1667
|
+
backgroundColor: get3(tokens, "extend.colors.primary.100")
|
|
1668
|
+
}
|
|
868
1669
|
};
|
|
869
1670
|
var textTheme = {
|
|
870
1671
|
"& .cm-scroller": {
|
|
871
|
-
fontFamily:
|
|
1672
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
872
1673
|
},
|
|
873
1674
|
"& .cm-placeholder": {
|
|
874
|
-
fontFamily:
|
|
1675
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
875
1676
|
}
|
|
876
1677
|
};
|
|
877
1678
|
var markdownTheme = {
|
|
878
1679
|
// NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
|
|
879
1680
|
"& .cm-placeholder": {
|
|
880
|
-
fontFamily:
|
|
1681
|
+
fontFamily: get3(tokens, "fontFamily.body", []).join(",")
|
|
881
1682
|
}
|
|
882
1683
|
};
|
|
883
1684
|
var codeTheme = {
|
|
884
1685
|
"& .cm-scroller": {
|
|
885
|
-
fontFamily:
|
|
1686
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
886
1687
|
},
|
|
887
1688
|
"& .cm-placeholder": {
|
|
888
|
-
fontFamily:
|
|
1689
|
+
fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
|
|
889
1690
|
}
|
|
890
1691
|
};
|
|
891
1692
|
|
|
892
1693
|
// packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
|
|
893
1694
|
import { EditorState as EditorState2 } from "@codemirror/state";
|
|
894
|
-
import { EditorView as
|
|
1695
|
+
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
895
1696
|
import { useFocusableGroup } from "@fluentui/react-tabster";
|
|
896
1697
|
import { vim } from "@replit/codemirror-vim";
|
|
897
|
-
import
|
|
898
|
-
import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
|
|
1698
|
+
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
1699
|
+
import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useState } from "react";
|
|
899
1700
|
import { generateName } from "@dxos/display-name";
|
|
900
1701
|
import { useThemeContext } from "@dxos/react-ui";
|
|
901
|
-
import { getColorForValue, inputSurface, mx as
|
|
1702
|
+
import { getColorForValue, inputSurface, mx as mx4 } from "@dxos/react-ui-theme";
|
|
902
1703
|
var EditorModes = [
|
|
903
1704
|
"default",
|
|
904
1705
|
"vim"
|
|
905
1706
|
];
|
|
906
|
-
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots
|
|
1707
|
+
var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
|
|
907
1708
|
const { themeMode } = useThemeContext();
|
|
908
1709
|
const tabsterDOMAttribute = useFocusableGroup({
|
|
909
1710
|
tabBehavior: "limited"
|
|
@@ -921,7 +1722,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
921
1722
|
root
|
|
922
1723
|
]);
|
|
923
1724
|
const { awareness, peer } = model;
|
|
924
|
-
|
|
1725
|
+
useEffect2(() => {
|
|
925
1726
|
if (awareness && peer) {
|
|
926
1727
|
awareness.setLocalStateField("user", {
|
|
927
1728
|
name: peer.name ?? generateName(peer.id),
|
|
@@ -941,20 +1742,22 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
941
1742
|
peer,
|
|
942
1743
|
themeMode
|
|
943
1744
|
]);
|
|
944
|
-
|
|
1745
|
+
useEffect2(() => {
|
|
945
1746
|
if (!root) {
|
|
946
1747
|
return;
|
|
947
1748
|
}
|
|
948
1749
|
const state2 = EditorState2.create({
|
|
949
1750
|
doc: model.text(),
|
|
950
1751
|
extensions: [
|
|
1752
|
+
readonly && EditorState2.readOnly.of(readonly),
|
|
951
1753
|
// TODO(burdon): Factor out VIM mode?
|
|
952
1754
|
editorMode === "vim" && vim(),
|
|
953
1755
|
// Theme.
|
|
954
|
-
|
|
955
|
-
|
|
1756
|
+
// TODO(burdon): Make optional.
|
|
1757
|
+
EditorView11.baseTheme(defaultTheme),
|
|
1758
|
+
EditorView11.theme(slots?.editor?.theme ?? {}),
|
|
956
1759
|
// TODO(burdon): themeMode doesn't change in storybooks.
|
|
957
|
-
|
|
1760
|
+
EditorView11.darkTheme.of(themeMode === "dark"),
|
|
958
1761
|
// Storage and replication.
|
|
959
1762
|
model.extension,
|
|
960
1763
|
// Custom.
|
|
@@ -962,7 +1765,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
962
1765
|
].filter(Boolean)
|
|
963
1766
|
});
|
|
964
1767
|
view?.destroy();
|
|
965
|
-
setView(new
|
|
1768
|
+
setView(new EditorView11({
|
|
966
1769
|
state: state2,
|
|
967
1770
|
parent: root
|
|
968
1771
|
}));
|
|
@@ -976,6 +1779,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
976
1779
|
root,
|
|
977
1780
|
model,
|
|
978
1781
|
themeMode,
|
|
1782
|
+
readonly,
|
|
979
1783
|
editorMode
|
|
980
1784
|
]);
|
|
981
1785
|
const handleKeyUp = useCallback((event) => {
|
|
@@ -1003,43 +1807,36 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
|
|
|
1003
1807
|
onKeyUp: handleKeyUp
|
|
1004
1808
|
});
|
|
1005
1809
|
});
|
|
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) => {
|
|
1810
|
+
var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1016
1811
|
const { themeMode } = useThemeContext();
|
|
1017
|
-
const slots =
|
|
1812
|
+
const slots = defaultsDeep2({}, _slots, defaultTextSlots);
|
|
1018
1813
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1019
1814
|
ref: forwardedRef,
|
|
1815
|
+
readonly,
|
|
1020
1816
|
extensions: [
|
|
1021
1817
|
basicBundle({
|
|
1818
|
+
readonly,
|
|
1022
1819
|
themeMode,
|
|
1023
1820
|
placeholder: slots?.editor?.placeholder
|
|
1024
1821
|
}),
|
|
1025
|
-
maybeDebug(),
|
|
1026
1822
|
...extensions
|
|
1027
1823
|
],
|
|
1028
1824
|
slots,
|
|
1029
1825
|
...props
|
|
1030
1826
|
});
|
|
1031
1827
|
});
|
|
1032
|
-
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1828
|
+
var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
|
|
1033
1829
|
const { themeMode } = useThemeContext();
|
|
1034
|
-
const slots =
|
|
1830
|
+
const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
|
|
1035
1831
|
return /* @__PURE__ */ React.createElement(BaseTextEditor, {
|
|
1036
1832
|
ref: forwardedRef,
|
|
1833
|
+
readonly,
|
|
1037
1834
|
extensions: [
|
|
1038
1835
|
markdownBundle({
|
|
1836
|
+
readonly,
|
|
1039
1837
|
themeMode,
|
|
1040
1838
|
placeholder: slots?.editor?.placeholder
|
|
1041
1839
|
}),
|
|
1042
|
-
maybeDebug(),
|
|
1043
1840
|
...extensions
|
|
1044
1841
|
],
|
|
1045
1842
|
slots,
|
|
@@ -1048,7 +1845,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slot
|
|
|
1048
1845
|
});
|
|
1049
1846
|
var defaultSlots = {
|
|
1050
1847
|
root: {
|
|
1051
|
-
className:
|
|
1848
|
+
className: mx4("p-2", inputSurface)
|
|
1052
1849
|
}
|
|
1053
1850
|
};
|
|
1054
1851
|
var defaultTextSlots = {
|
|
@@ -1065,15 +1862,15 @@ var defaultMarkdownSlots = {
|
|
|
1065
1862
|
};
|
|
1066
1863
|
|
|
1067
1864
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1068
|
-
import
|
|
1069
|
-
import { useEffect as
|
|
1865
|
+
import get4 from "lodash.get";
|
|
1866
|
+
import { useEffect as useEffect3, useState as useState2 } from "react";
|
|
1070
1867
|
import { yCollab } from "y-codemirror.next";
|
|
1071
|
-
import { invariant as
|
|
1868
|
+
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1072
1869
|
import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
|
|
1073
1870
|
|
|
1074
1871
|
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
1075
|
-
import { Annotation, Facet, StateEffect, StateField as
|
|
1076
|
-
import { ViewPlugin as
|
|
1872
|
+
import { Annotation, Facet, StateEffect as StateEffect2, StateField as StateField6 } from "@codemirror/state";
|
|
1873
|
+
import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
|
|
1077
1874
|
import * as automerge2 from "@dxos/automerge/automerge";
|
|
1078
1875
|
|
|
1079
1876
|
// packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
|
|
@@ -1251,7 +2048,7 @@ var PatchSemaphore = class {
|
|
|
1251
2048
|
};
|
|
1252
2049
|
|
|
1253
2050
|
// packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
|
|
1254
|
-
var effectType =
|
|
2051
|
+
var effectType = StateEffect2.define({});
|
|
1255
2052
|
var updateHeads = (newHeads) => effectType.of({
|
|
1256
2053
|
newHeads
|
|
1257
2054
|
});
|
|
@@ -1261,7 +2058,7 @@ var semaphoreFacet = Facet.define({
|
|
|
1261
2058
|
combine: (values) => values.at(-1)
|
|
1262
2059
|
});
|
|
1263
2060
|
var automergePlugin = (handle, path) => {
|
|
1264
|
-
const stateField =
|
|
2061
|
+
const stateField = StateField6.define({
|
|
1265
2062
|
create: () => ({
|
|
1266
2063
|
lastHeads: automerge2.getHeads(handle.docSync()),
|
|
1267
2064
|
unreconciledTransactions: [],
|
|
@@ -1291,7 +2088,7 @@ var automergePlugin = (handle, path) => {
|
|
|
1291
2088
|
}
|
|
1292
2089
|
});
|
|
1293
2090
|
const semaphore = new PatchSemaphore(stateField);
|
|
1294
|
-
const viewPlugin =
|
|
2091
|
+
const viewPlugin = ViewPlugin4.fromClass(class AutomergeCodemirrorViewPlugin {
|
|
1295
2092
|
constructor(view) {
|
|
1296
2093
|
this._handleChange = () => {
|
|
1297
2094
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
@@ -1299,8 +2096,8 @@ var automergePlugin = (handle, path) => {
|
|
|
1299
2096
|
this._view = view;
|
|
1300
2097
|
handle.addListener("change", this._handleChange);
|
|
1301
2098
|
}
|
|
1302
|
-
update(
|
|
1303
|
-
if (
|
|
2099
|
+
update(update4) {
|
|
2100
|
+
if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
|
|
1304
2101
|
queueMicrotask(() => {
|
|
1305
2102
|
this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
|
|
1306
2103
|
});
|
|
@@ -1322,7 +2119,7 @@ var reconcileAnnotationType = Annotation.define();
|
|
|
1322
2119
|
var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
|
|
1323
2120
|
|
|
1324
2121
|
// packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
|
|
1325
|
-
import * as
|
|
2122
|
+
import * as random2 from "lib0/random";
|
|
1326
2123
|
var cursorColors = [
|
|
1327
2124
|
{
|
|
1328
2125
|
color: "#30bced",
|
|
@@ -1357,7 +2154,7 @@ var cursorColors = [
|
|
|
1357
2154
|
light: "#1be7ff33"
|
|
1358
2155
|
}
|
|
1359
2156
|
];
|
|
1360
|
-
var cursorColor = cursorColors[
|
|
2157
|
+
var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
|
|
1361
2158
|
|
|
1362
2159
|
// packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
|
|
1363
2160
|
import * as decoding from "lib0/decoding";
|
|
@@ -1365,7 +2162,7 @@ import * as encoding from "lib0/encoding";
|
|
|
1365
2162
|
import { Observable } from "lib0/observable";
|
|
1366
2163
|
import * as awarenessProtocol from "y-protocols/awareness";
|
|
1367
2164
|
import { log } from "@dxos/log";
|
|
1368
|
-
var
|
|
2165
|
+
var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
|
|
1369
2166
|
var messageAwareness = 1;
|
|
1370
2167
|
var messageQueryAwareness = 3;
|
|
1371
2168
|
var SpaceAwarenessProvider = class extends Observable {
|
|
@@ -1402,7 +2199,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1402
2199
|
removed,
|
|
1403
2200
|
origin
|
|
1404
2201
|
}, {
|
|
1405
|
-
F:
|
|
2202
|
+
F: __dxlog_file3,
|
|
1406
2203
|
L: 67,
|
|
1407
2204
|
S: this,
|
|
1408
2205
|
C: (f, a) => f(...a)
|
|
@@ -1415,7 +2212,7 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1415
2212
|
}
|
|
1416
2213
|
_handleSpaceMessage({ payload }) {
|
|
1417
2214
|
log("space message", payload, {
|
|
1418
|
-
F:
|
|
2215
|
+
F: __dxlog_file3,
|
|
1419
2216
|
L: 79,
|
|
1420
2217
|
S: this,
|
|
1421
2218
|
C: (f, a) => f(...a)
|
|
@@ -1460,14 +2257,14 @@ var SpaceAwarenessProvider = class extends Observable {
|
|
|
1460
2257
|
};
|
|
1461
2258
|
|
|
1462
2259
|
// packages/ui/react-ui-editor/src/hooks/useTextModel.ts
|
|
1463
|
-
var
|
|
2260
|
+
var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
|
|
1464
2261
|
var useTextModel = ({ identity, space, text }) => {
|
|
1465
2262
|
const [model, setModel] = useState2(() => createModel({
|
|
1466
2263
|
identity,
|
|
1467
2264
|
space,
|
|
1468
2265
|
text
|
|
1469
2266
|
}));
|
|
1470
|
-
|
|
2267
|
+
useEffect3(() => {
|
|
1471
2268
|
setModel(createModel({
|
|
1472
2269
|
identity,
|
|
1473
2270
|
space,
|
|
@@ -1492,9 +2289,9 @@ var createModel = (options) => {
|
|
|
1492
2289
|
}
|
|
1493
2290
|
};
|
|
1494
2291
|
var createYjsModel = ({ identity, space, text }) => {
|
|
1495
|
-
|
|
1496
|
-
F:
|
|
1497
|
-
L:
|
|
2292
|
+
invariant3(text?.doc && text?.content, void 0, {
|
|
2293
|
+
F: __dxlog_file4,
|
|
2294
|
+
L: 81,
|
|
1498
2295
|
S: void 0,
|
|
1499
2296
|
A: [
|
|
1500
2297
|
"text?.doc && text?.content",
|
|
@@ -1510,6 +2307,7 @@ var createYjsModel = ({ identity, space, text }) => {
|
|
|
1510
2307
|
id: text.doc.guid,
|
|
1511
2308
|
content: text.content,
|
|
1512
2309
|
text: () => text.content.toString(),
|
|
2310
|
+
ranges: [],
|
|
1513
2311
|
extension: yCollab(text.content, provider?.awareness),
|
|
1514
2312
|
awareness: provider?.awareness,
|
|
1515
2313
|
peer: identity ? {
|
|
@@ -1526,7 +2324,8 @@ var createAutomergeModel = ({ identity, text }) => {
|
|
|
1526
2324
|
return {
|
|
1527
2325
|
id: obj.id,
|
|
1528
2326
|
content: doc,
|
|
1529
|
-
text: () =>
|
|
2327
|
+
text: () => get4(doc.handle.docSync(), doc.path),
|
|
2328
|
+
ranges: [],
|
|
1530
2329
|
extension: automergePlugin(doc.handle, doc.path),
|
|
1531
2330
|
peer: identity ? {
|
|
1532
2331
|
id: identity.identityKey.toHex(),
|
|
@@ -1546,25 +2345,35 @@ export {
|
|
|
1546
2345
|
YXmlFragment,
|
|
1547
2346
|
autocomplete,
|
|
1548
2347
|
basicBundle,
|
|
2348
|
+
blast,
|
|
2349
|
+
code2 as code,
|
|
1549
2350
|
codeTheme,
|
|
1550
2351
|
comments,
|
|
1551
2352
|
cursorColor,
|
|
1552
2353
|
defaultMarkdownSlots,
|
|
2354
|
+
defaultOptions,
|
|
1553
2355
|
defaultSlots,
|
|
1554
2356
|
defaultTextSlots,
|
|
1555
2357
|
defaultTheme,
|
|
1556
2358
|
demo,
|
|
2359
|
+
highlight,
|
|
2360
|
+
highlightDecorations,
|
|
2361
|
+
highlightStateField,
|
|
2362
|
+
image,
|
|
1557
2363
|
link,
|
|
1558
|
-
listener,
|
|
2364
|
+
listener2 as listener,
|
|
1559
2365
|
markdownBundle,
|
|
1560
2366
|
markdownHighlightStyle,
|
|
1561
2367
|
markdownTags,
|
|
1562
|
-
|
|
2368
|
+
markdownTagsExtensions,
|
|
1563
2369
|
markdownTheme,
|
|
2370
|
+
mention,
|
|
2371
|
+
table,
|
|
1564
2372
|
tags2 as tags,
|
|
1565
2373
|
tasklist,
|
|
1566
2374
|
textTheme,
|
|
1567
2375
|
tooltip,
|
|
2376
|
+
useHighlights,
|
|
1568
2377
|
useTextModel
|
|
1569
2378
|
};
|
|
1570
2379
|
//# sourceMappingURL=index.mjs.map
|