@dxos/react-ui-editor 0.3.10-next.e7dbe51 → 0.3.10

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.
Files changed (101) hide show
  1. package/dist/lib/browser/index.mjs +1270 -372
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +23 -2
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -1
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +3 -0
  9. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/extensions/autocomplete.d.ts.map +1 -1
  11. package/dist/types/src/components/TextEditor/extensions/basic.d.ts +2 -1
  12. package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +1 -1
  13. package/dist/types/src/components/TextEditor/extensions/blast.d.ts +25 -0
  14. package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +1 -0
  15. package/dist/types/src/components/TextEditor/extensions/code.d.ts +2 -0
  16. package/dist/types/src/components/TextEditor/extensions/code.d.ts.map +1 -0
  17. package/dist/types/src/components/TextEditor/extensions/comments.d.ts +11 -7
  18. package/dist/types/src/components/TextEditor/extensions/comments.d.ts.map +1 -1
  19. package/dist/types/src/components/TextEditor/extensions/demo.d.ts +11 -0
  20. package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -0
  21. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts +1 -1
  22. package/dist/types/src/components/TextEditor/extensions/experimental.d.ts.map +1 -1
  23. package/dist/types/src/components/TextEditor/extensions/highlight.d.ts +24 -0
  24. package/dist/types/src/components/TextEditor/extensions/highlight.d.ts.map +1 -0
  25. package/dist/types/src/components/TextEditor/extensions/image.d.ts +4 -0
  26. package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +1 -0
  27. package/dist/types/src/components/TextEditor/extensions/index.d.ts +7 -0
  28. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  29. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -1
  30. package/dist/types/src/components/TextEditor/extensions/listener.d.ts +4 -2
  31. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -1
  32. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +10 -1
  33. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
  34. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +9 -3
  35. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -1
  36. package/dist/types/src/components/TextEditor/extensions/mention.d.ts +6 -0
  37. package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +1 -0
  38. package/dist/types/src/components/TextEditor/extensions/table.d.ts +8 -0
  39. package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +1 -0
  40. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +2 -1
  41. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
  42. package/dist/types/src/components/TextEditor/themes/default.d.ts +5 -0
  43. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
  44. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts +3 -0
  45. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -1
  46. package/dist/types/src/hooks/automerge/automerge.stories.d.ts +8 -1
  47. package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -1
  48. package/dist/types/src/hooks/automerge/index.d.ts +1 -1
  49. package/dist/types/src/hooks/automerge/index.d.ts.map +1 -1
  50. package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -1
  51. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts +5 -0
  52. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts.map +1 -0
  53. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts +6 -0
  54. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts.map +1 -0
  55. package/dist/types/src/hooks/automerge/translation/index.d.ts +3 -0
  56. package/dist/types/src/hooks/automerge/translation/index.d.ts.map +1 -0
  57. package/dist/types/src/hooks/useTextModel.d.ts +6 -0
  58. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  59. package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +2 -2
  60. package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +1 -0
  61. package/dist/types/src/styles/markdown.d.ts +3 -2
  62. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  63. package/dist/types/src/testing/replicator.d.ts.map +1 -1
  64. package/package.json +23 -20
  65. package/src/components/TextEditor/MarkdownEditor.stories.tsx +128 -34
  66. package/src/components/TextEditor/TextEditor.stories.tsx +12 -1
  67. package/src/components/TextEditor/TextEditor.tsx +30 -9
  68. package/src/components/TextEditor/extensions/autocomplete.ts +5 -20
  69. package/src/components/TextEditor/extensions/basic.ts +6 -4
  70. package/src/components/TextEditor/extensions/blast.ts +373 -0
  71. package/src/components/TextEditor/extensions/code.ts +99 -0
  72. package/src/components/TextEditor/extensions/comments.ts +67 -67
  73. package/src/components/TextEditor/extensions/demo.ts +69 -0
  74. package/src/components/TextEditor/extensions/experimental.tsx +15 -36
  75. package/src/components/TextEditor/extensions/highlight.ts +128 -0
  76. package/src/components/TextEditor/extensions/image.ts +67 -0
  77. package/src/components/TextEditor/extensions/index.ts +7 -0
  78. package/src/components/TextEditor/extensions/link.ts +17 -25
  79. package/src/components/TextEditor/extensions/listener.ts +4 -4
  80. package/src/components/TextEditor/extensions/markdown/bundle.ts +45 -34
  81. package/src/components/TextEditor/extensions/markdown/highlight.ts +148 -108
  82. package/src/components/TextEditor/extensions/mention.ts +31 -0
  83. package/src/components/TextEditor/extensions/table.ts +119 -0
  84. package/src/components/TextEditor/extensions/tasklist.ts +42 -28
  85. package/src/components/TextEditor/themes/default.ts +98 -4
  86. package/src/hooks/automerge/PatchSemaphore.ts +12 -9
  87. package/src/hooks/automerge/automerge.stories.tsx +4 -2
  88. package/src/hooks/automerge/index.ts +1 -1
  89. package/src/hooks/automerge/plugin.ts +1 -0
  90. package/src/hooks/automerge/{amToCodemirror.ts → translation/automerge-to-codemirror.ts} +10 -2
  91. package/src/hooks/automerge/{codeMirrorToAm.ts → translation/codemirror-to-automerge.ts} +7 -4
  92. package/src/hooks/automerge/translation/index.ts +6 -0
  93. package/src/hooks/useTextModel.ts +9 -0
  94. package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +2 -2
  95. package/src/styles/markdown.ts +15 -8
  96. package/src/testing/replicator.ts +1 -0
  97. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  98. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts +0 -6
  99. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts.map +0 -1
  100. package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts +0 -7
  101. package/dist/types/src/hooks/automerge/codeMirrorToAm.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 word = context.matchBefore(/\w*/);
28
- if (!word || word.from === word.to && !context.explicit) {
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: word.from,
33
- options: onSearch(word.text.toLowerCase())
32
+ from: match.from,
33
+ options: onSearch(match.text.toLowerCase())
34
34
  };
35
35
  }
36
36
  ]
@@ -42,30 +42,531 @@ 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
- EditorView.lineWrapping,
52
+ drawSelection(),
52
53
  _placeholder && placeholder(_placeholder),
53
54
  // TODO(burdon): Is this required?
54
55
  themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
55
56
  ].filter(Boolean);
56
57
 
57
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
58
- import { Decoration, EditorView as EditorView2, keymap as keymap2, MatchDecorator, ViewPlugin, WidgetType } from "@codemirror/view";
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";
59
61
  import { invariant } from "@dxos/invariant";
60
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
62
+ var __dxlog_file = "/home/circleci/project/packages/ui/react-ui-editor/src/components/TextEditor/extensions/blast.ts";
63
+ var defaultOptions = {
64
+ effect: 2,
65
+ maxParticles: 200,
66
+ particleGravity: 0.08,
67
+ particleAlphaFadeout: 0.996,
68
+ particleSize: {
69
+ min: 2,
70
+ max: 8
71
+ },
72
+ particleNumRange: {
73
+ min: 5,
74
+ max: 10
75
+ },
76
+ particleVelocityRange: {
77
+ x: [
78
+ -1,
79
+ 1
80
+ ],
81
+ y: [
82
+ -3.5,
83
+ -1.5
84
+ ]
85
+ },
86
+ particleShrinkRate: 0.95,
87
+ shakeIntensity: 5
88
+ };
89
+ var blast = (options = defaultOptions) => {
90
+ let blaster;
91
+ let last = 0;
92
+ const getPoint = (view, pos) => {
93
+ const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
94
+ const element = document.elementFromPoint(x, y);
95
+ const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
96
+ const point = {
97
+ x: x - left,
98
+ y: y - top
99
+ };
100
+ return {
101
+ element,
102
+ point
103
+ };
104
+ };
105
+ return [
106
+ // Cursor moved.
107
+ EditorView2.updateListener.of((update4) => {
108
+ if (blaster?.node !== update4.view.scrollDOM) {
109
+ if (blaster) {
110
+ blaster.destroy();
111
+ }
112
+ blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({
113
+ particleGravity: 0.2,
114
+ particleShrinkRate: 0.995,
115
+ color: () => [
116
+ 100 + Math.random() * 100,
117
+ 0,
118
+ 0
119
+ ]
120
+ }, options, defaultOptions));
121
+ blaster.initialize();
122
+ blaster.start();
123
+ } else {
124
+ blaster.resize();
125
+ }
126
+ const current = update4.state.selection.main.head;
127
+ if (current !== last) {
128
+ last = current;
129
+ const { element, point } = getPoint(update4.view, current - 1);
130
+ if (element && point) {
131
+ blaster.spawn({
132
+ element,
133
+ point
134
+ });
135
+ }
136
+ }
137
+ }),
138
+ keymap2.of([
139
+ {
140
+ any: (_, event) => {
141
+ if (blaster) {
142
+ if (event.key === "Enter" && event.shiftKey) {
143
+ blaster.shake({
144
+ time: 0.8
145
+ });
146
+ return true;
147
+ }
148
+ }
149
+ return false;
150
+ }
151
+ }
152
+ ])
153
+ ];
154
+ };
155
+ var Blaster = class {
156
+ constructor(_node, _options) {
157
+ this._node = _node;
158
+ this._options = _options;
159
+ this._running = false;
160
+ this._shakeTime = 0;
161
+ this._shakeTimeMax = 0;
162
+ this._particles = [];
163
+ this._particlePointer = 0;
164
+ this._lastPoint = {
165
+ x: 0,
166
+ y: 0
167
+ };
168
+ this.shake = throttle(({ time }) => {
169
+ this._shakeTime = this._shakeTimeMax || time;
170
+ this._shakeTimeMax = time;
171
+ }, 100);
172
+ this.spawn = throttle(({ element, point }) => {
173
+ const color = getRGBComponents(element, this._options.color);
174
+ const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
175
+ const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
176
+ this._lastPoint = point;
177
+ for (let i = numParticles; i--; i > 0) {
178
+ this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
179
+ this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
180
+ }
181
+ }, 100);
182
+ this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
183
+ }
184
+ get node() {
185
+ return this._node;
186
+ }
187
+ initialize() {
188
+ invariant(!this._canvas && !this._ctx, void 0, {
189
+ F: __dxlog_file,
190
+ L: 138,
191
+ S: this,
192
+ A: [
193
+ "!this._canvas && !this._ctx",
194
+ ""
195
+ ]
196
+ });
197
+ this._canvas = document.createElement("canvas");
198
+ this._canvas.id = "code-blast-canvas";
199
+ this._canvas.style.position = "absolute";
200
+ this._canvas.style.zIndex = "0";
201
+ this._canvas.style.pointerEvents = "none";
202
+ this._ctx = this._canvas.getContext("2d");
203
+ const parent = this._node.parentElement?.parentElement;
204
+ parent?.appendChild(this._canvas);
205
+ this.resize();
206
+ }
207
+ destroy() {
208
+ this.stop();
209
+ if (this._canvas) {
210
+ this._canvas.remove();
211
+ this._canvas = void 0;
212
+ this._ctx = void 0;
213
+ }
214
+ }
215
+ resize() {
216
+ if (this._node.parentElement && this._canvas) {
217
+ const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
218
+ this._canvas.style.top = `${y}px`;
219
+ this._canvas.style.left = `${x}px`;
220
+ this._canvas.width = width;
221
+ this._canvas.height = height;
222
+ }
223
+ }
224
+ start() {
225
+ invariant(this._canvas && this._ctx, void 0, {
226
+ F: __dxlog_file,
227
+ L: 177,
228
+ S: this,
229
+ A: [
230
+ "this._canvas && this._ctx",
231
+ ""
232
+ ]
233
+ });
234
+ this._running = true;
235
+ this.loop();
236
+ }
237
+ stop() {
238
+ this._running = false;
239
+ this._node.style.transform = "translate(0px, 0px)";
240
+ }
241
+ loop() {
242
+ if (!this._running || !this._canvas || !this._ctx) {
243
+ return;
244
+ }
245
+ this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
246
+ const now = (/* @__PURE__ */ new Date()).getTime();
247
+ this._lastTime ??= now;
248
+ const dt = (now - this._lastTime) / 1e3;
249
+ this._lastTime = now;
250
+ if (this._shakeTime > 0) {
251
+ this._shakeTime -= dt;
252
+ const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
253
+ const shakeX = random(-magnitude, magnitude);
254
+ const shakeY = random(-magnitude, magnitude);
255
+ this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
256
+ }
257
+ this.drawParticles();
258
+ requestAnimationFrame(this.loop.bind(this));
259
+ }
260
+ drawParticles() {
261
+ for (let i = this._particles.length; i--; i > 0) {
262
+ const particle = this._particles[i];
263
+ if (!particle) {
264
+ continue;
265
+ }
266
+ if (particle.alpha < 0.01 || particle.size <= 0.5) {
267
+ continue;
268
+ }
269
+ this._effect.update(this._ctx, particle);
270
+ }
271
+ }
272
+ };
273
+ var Effect = class {
274
+ constructor(_options) {
275
+ this._options = _options;
276
+ }
277
+ };
278
+ var Effect1 = class extends Effect {
279
+ create(x, y, color) {
280
+ return {
281
+ x,
282
+ y: y + 10,
283
+ vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
284
+ vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
285
+ size: random(this._options.particleSize.min, this._options.particleSize.max),
286
+ color,
287
+ alpha: 1
288
+ };
289
+ }
290
+ update(ctx, particle) {
291
+ particle.vy += this._options.particleGravity;
292
+ particle.x += particle.vx;
293
+ particle.y += particle.vy;
294
+ particle.alpha *= this._options.particleAlphaFadeout;
295
+ ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
296
+ ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
297
+ }
298
+ };
299
+ var Effect2 = class extends Effect {
300
+ create(x, y, color) {
301
+ return {
302
+ x,
303
+ y: y + 10,
304
+ vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
305
+ vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
306
+ size: random(this._options.particleSize.min, this._options.particleSize.max),
307
+ color,
308
+ alpha: 1,
309
+ theta: random(0, 360) * Math.PI / 180,
310
+ drag: 0.92,
311
+ wander: 0.15
312
+ };
313
+ }
314
+ update(ctx, particle) {
315
+ particle.vy += this._options.particleGravity;
316
+ particle.x += particle.vx;
317
+ particle.y += particle.vy;
318
+ particle.vx *= particle.drag;
319
+ particle.vy *= particle.drag;
320
+ particle.theta += random(-0.5, 0.5);
321
+ particle.vx += Math.sin(particle.theta) * 0.1;
322
+ particle.vy += Math.cos(particle.theta) * 0.1;
323
+ particle.size *= this._options.particleShrinkRate;
324
+ particle.alpha *= this._options.particleAlphaFadeout;
325
+ ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
326
+ ctx.beginPath();
327
+ ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
328
+ ctx.fill();
329
+ }
330
+ };
331
+ function throttle(callback, limit) {
332
+ let wait = false;
333
+ return function(...args) {
334
+ if (!wait) {
335
+ callback.apply(this, args);
336
+ wait = true;
337
+ setTimeout(() => {
338
+ wait = false;
339
+ }, limit);
340
+ }
341
+ };
342
+ }
343
+ var getRGBComponents = (node, color) => {
344
+ if (typeof color === "function") {
345
+ return color();
346
+ }
347
+ const bgColor = getComputedStyle(node).color;
348
+ if (bgColor) {
349
+ const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
350
+ if (x) {
351
+ return x;
352
+ }
353
+ }
354
+ return [
355
+ 50,
356
+ 50,
357
+ 50
358
+ ];
359
+ };
360
+ var random = (min, max) => {
361
+ if (!max) {
362
+ max = min;
363
+ min = 0;
364
+ }
365
+ return min + ~~(Math.random() * (max - min + 1));
366
+ };
367
+
368
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
369
+ import { ViewPlugin, EditorView as EditorView3, Decoration } from "@codemirror/view";
370
+ import get from "lodash.get";
371
+ import { mx as mx2 } from "@dxos/react-ui-theme";
372
+
373
+ // packages/ui/react-ui-editor/src/styles/markdown.ts
374
+ import { mx } from "@dxos/react-ui-theme";
375
+ var headings = {
376
+ 1: [
377
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
378
+ "-ml-[10px]"
379
+ ],
380
+ 2: [
381
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
382
+ "-ml-[8px]"
383
+ ],
384
+ 3: [
385
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
386
+ "-ml-[7px]"
387
+ ],
388
+ 4: [
389
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
390
+ "-ml-[6px]"
391
+ ],
392
+ 5: [
393
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
394
+ "-ml-[5px]"
395
+ ],
396
+ 6: [
397
+ "mbs-4 mbe-2 font-medium text-inherit no-underline",
398
+ "-ml-[4px]"
399
+ ]
400
+ };
401
+ var heading = (level, readonly) => {
402
+ const [style, offset] = headings[level];
403
+ return mx(style, readonly && offset);
404
+ };
405
+ var light = "text-neutral-200 dark:text-neutral-800";
406
+ var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
407
+ var bold = "font-bold";
408
+ var italic = "italic";
409
+ var strikethrough = "line-through";
410
+ var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
411
+ var codeMark = "font-mono text-primary-500";
412
+ var inlineUrl = mx(code, "px-1");
413
+ var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
414
+ var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
415
+
416
+ // packages/ui/react-ui-editor/src/styles/tokens.ts
417
+ import { tailwindConfig } from "@dxos/react-ui-theme";
418
+ var tokens = tailwindConfig({}).theme;
419
+
420
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/code.ts
421
+ var CODE_REGEX = /```[\s\S]*?```/gs;
422
+ var styles = EditorView3.baseTheme({
423
+ "& .cm-code-block": {
424
+ display: "block",
425
+ paddingInline: "4px !important"
426
+ },
427
+ "&light .cm-code-block": {
428
+ background: get(tokens, "extend.colors.neutral.50")
429
+ },
430
+ "&dark .cm-code-block": {
431
+ background: get(tokens, "extend.colors.neutral.850")
432
+ },
433
+ "& .cm-code-block-first": {
434
+ paddingTop: "4px !important",
435
+ borderTopLeftRadius: "4px",
436
+ borderTopRightRadius: "4px"
437
+ },
438
+ "& .cm-code-block-last": {
439
+ paddingBottom: "4px !important",
440
+ borderBottomLeftRadius: "4px",
441
+ borderBottomRightRadius: "4px"
442
+ }
443
+ });
444
+ var getLineRange = (lines, from, to) => {
445
+ const start = lines.findIndex((line) => line.from >= from);
446
+ const end = lines.findIndex((line) => line.to >= to);
447
+ return [
448
+ start,
449
+ end
450
+ ];
451
+ };
452
+ var code2 = () => {
453
+ const getDecorations = (view) => {
454
+ const decorations = [];
455
+ if (view.state.readOnly) {
456
+ const text = view.state.doc.sliceString(0);
457
+ const matches = text.matchAll(CODE_REGEX);
458
+ const blocks = view.viewportLineBlocks;
459
+ for (const match of matches) {
460
+ const range = getLineRange(blocks, match.index, match.index + match[0].length);
461
+ for (let i = range[0]; i <= range[1]; i++) {
462
+ const block = blocks[i];
463
+ decorations.push(Decoration.line({
464
+ class: mx2("cm-code-block", i === range[0] && "cm-code-block-first", i === range[1] && "cm-code-block-last")
465
+ }).range(block.from));
466
+ }
467
+ }
468
+ }
469
+ return Decoration.set(decorations);
470
+ };
471
+ return [
472
+ ViewPlugin.fromClass(class {
473
+ constructor(view) {
474
+ this.decorations = getDecorations(view);
475
+ }
476
+ update(update4) {
477
+ if (update4.docChanged || update4.viewportChanged) {
478
+ this.decorations = getDecorations(update4.view);
479
+ }
480
+ }
481
+ }, {
482
+ decorations: (value) => value.decorations
483
+ }),
484
+ styles
485
+ ];
486
+ };
487
+
488
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
489
+ import { keymap as keymap3 } from "@codemirror/view";
490
+ var defaultItems = [
491
+ "hello world!",
492
+ "this is a test.",
493
+ "this is [DXOS](https://dxos.org)"
494
+ ];
495
+ var demo = ({ delay = 75, items = defaultItems } = {}) => {
496
+ let t;
497
+ let idx = 0;
498
+ return [
499
+ keymap3.of([
500
+ {
501
+ // Reset.
502
+ key: "alt-meta-'",
503
+ run: (view) => {
504
+ clearTimeout(t);
505
+ idx = 0;
506
+ return true;
507
+ }
508
+ },
509
+ {
510
+ // Next prompt.
511
+ // TODO(burdon): Press 1-9 to select prompt?
512
+ key: "shift-meta-'",
513
+ run: (view) => {
514
+ clearTimeout(t);
515
+ const text = items[idx++];
516
+ if (idx === items?.length) {
517
+ idx = 0;
518
+ }
519
+ let i = 0;
520
+ const insert = (d = 0) => {
521
+ t = setTimeout(() => {
522
+ const pos = view.state.selection.main.head;
523
+ view.dispatch({
524
+ changes: {
525
+ from: pos,
526
+ insert: text[i++]
527
+ },
528
+ selection: {
529
+ anchor: pos + 1
530
+ }
531
+ });
532
+ if (i < text.length) {
533
+ insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
534
+ }
535
+ }, d);
536
+ };
537
+ insert();
538
+ return true;
539
+ }
540
+ }
541
+ ])
542
+ ];
543
+ };
544
+
545
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
546
+ import { keymap as keymap4, Decoration as Decoration2, EditorView as EditorView4, MatchDecorator, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
547
+ import { debounce } from "@dxos/async";
548
+ import { invariant as invariant2 } from "@dxos/invariant";
549
+ var __dxlog_file2 = "/home/circleci/project/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
+ });
61
561
  var BookmarkWidget = class extends WidgetType {
62
- constructor(_pos, _id) {
562
+ constructor(_pos, _id, _handleClick) {
63
563
  super();
64
564
  this._pos = _pos;
65
565
  this._id = _id;
66
- invariant(this._id, void 0, {
67
- F: __dxlog_file,
68
- L: 40,
566
+ this._handleClick = _handleClick;
567
+ invariant2(this._id, void 0, {
568
+ F: __dxlog_file2,
569
+ L: 37,
69
570
  S: this,
70
571
  A: [
71
572
  "this._id",
@@ -76,62 +577,60 @@ var BookmarkWidget = class extends WidgetType {
76
577
  eq(other) {
77
578
  return this._id === other._id;
78
579
  }
79
- // TODO(burdon): Click to select.
80
580
  toDOM() {
81
581
  const span = document.createElement("span");
82
582
  span.className = "cm-bookmark";
83
- span.textContent = "\u{1F4AC}";
583
+ span.textContent = "\xA7";
584
+ span.onclick = () => this._handleClick();
84
585
  return span;
85
586
  }
86
587
  };
87
- var styles = EditorView2.baseTheme({
88
- "& .cm-bookmark": {
89
- cursor: "pointer",
90
- margin: "4px",
91
- padding: "4px",
92
- backgroundColor: "yellow"
93
- }
94
- });
95
588
  var comments = (options = {}) => {
589
+ let active;
96
590
  const bookmarkMatcher = new MatchDecorator({
97
591
  regexp: /\[\^(\w+)\]/g,
98
592
  decoration: (match, view, pos) => {
99
593
  const id = match[1];
100
- return Decoration.replace({
594
+ return Decoration2.replace({
101
595
  id,
102
- widget: new BookmarkWidget(pos, id)
596
+ widget: new BookmarkWidget(pos, id, () => handleUpdate({
597
+ active: id
598
+ }))
103
599
  });
104
600
  }
105
601
  });
106
- const bookmarks = ViewPlugin.fromClass(class {
602
+ const bookmarks = ViewPlugin2.fromClass(class {
107
603
  constructor(view) {
108
604
  this.bookmarks = bookmarkMatcher.createDeco(view);
109
605
  }
110
- update(update2) {
111
- this.bookmarks = bookmarkMatcher.updateDeco(update2, this.bookmarks);
606
+ update(update4) {
607
+ this.bookmarks = bookmarkMatcher.updateDeco(update4, this.bookmarks);
112
608
  }
113
609
  }, {
114
610
  decorations: (instance) => instance.bookmarks,
115
- provide: (plugin) => EditorView2.atomicRanges.of((view) => {
116
- return view.plugin(plugin)?.bookmarks || Decoration.none;
611
+ provide: (plugin) => EditorView4.atomicRanges.of((view) => {
612
+ return view.plugin(plugin)?.bookmarks || Decoration2.none;
117
613
  })
118
614
  });
615
+ const handleUpdate = debounce((data) => {
616
+ options.onUpdate?.(data);
617
+ }, 200);
119
618
  return [
120
- keymap2.of([
619
+ keymap4.of([
121
620
  {
122
- key: options?.key ?? "alt-meta-c",
621
+ key: options?.key ?? "shift-meta-c",
123
622
  run: (view) => {
124
- const id = options.onCreate?.();
623
+ const { from, to, head } = view.state.selection.main;
624
+ const id = options.onCreate?.(from, to);
125
625
  if (id) {
126
- const pos = view.state.selection.main.head;
127
626
  const tag = `[^${id}]`;
128
627
  view.dispatch({
129
628
  changes: {
130
- from: pos,
629
+ from: head,
131
630
  insert: tag
132
631
  },
133
632
  selection: {
134
- anchor: pos + tag.length
633
+ anchor: head + tag.length
135
634
  }
136
635
  });
137
636
  return true;
@@ -142,42 +641,210 @@ var comments = (options = {}) => {
142
641
  ]),
143
642
  bookmarks,
144
643
  // Monitor cursor movement.
145
- EditorView2.updateListener.of((update2) => {
146
- const view = update2.view;
147
- const pos = view.state.selection.main.head;
644
+ EditorView4.updateListener.of((update4) => {
645
+ active = void 0;
646
+ if (!options.onUpdate) {
647
+ return;
648
+ }
649
+ const { view, state } = update4;
650
+ const pos = state.selection.main.head;
148
651
  const decorations = [];
149
652
  const rangeSet = view.plugin(bookmarks)?.bookmarks;
150
- rangeSet?.between(pos, pos + 1, (from, to, value) => {
151
- if (value.spec.widget) {
152
- decorations.push({
153
- from,
154
- to,
155
- value
156
- });
653
+ let closest = Infinity;
654
+ const { from, to } = (
655
+ /* view.visibleRanges?.[0] ?? */
656
+ {
657
+ from: 0,
658
+ to: state.doc.length
659
+ }
660
+ );
661
+ rangeSet?.between(from, to, (from2, to2, value) => {
662
+ decorations.push({
663
+ from: from2,
664
+ to: to2,
665
+ value
666
+ });
667
+ const d = Math.min(Math.abs(pos - from2), Math.abs(pos - to2));
668
+ if (d < closest) {
669
+ active = value.spec.id;
670
+ closest = d;
157
671
  }
158
672
  });
159
673
  if (decorations.length) {
160
- const { from, value: { spec: { id } } } = decorations[0];
161
- const location = view.coordsAtPos(from);
162
- if (location) {
163
- options.onUpdate?.({
164
- items: decorations.map(({ value: { spec: { id: id2 } } }) => id2),
165
- active: id,
166
- pos,
167
- location
168
- });
169
- }
674
+ handleUpdate({
675
+ active,
676
+ items: decorations.map(({ from: from2, value: { spec: { id } } }) => ({
677
+ id,
678
+ pos: from2,
679
+ location: view.coordsAtPos(from2)
680
+ }))
681
+ });
170
682
  }
171
683
  }),
172
- styles
684
+ styles2
173
685
  ];
174
686
  };
175
687
 
176
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
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
177
791
  import { syntaxTree } from "@codemirror/language";
178
- import { RangeSetBuilder, StateField } from "@codemirror/state";
179
- import { Decoration as Decoration2, EditorView as EditorView3, WidgetType as WidgetType2 } from "@codemirror/view";
180
- var LinkButton = class extends WidgetType2 {
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 {
181
848
  constructor(_pos, _url, _onAttach) {
182
849
  super();
183
850
  this._pos = _pos;
@@ -193,7 +860,7 @@ var LinkButton = class extends WidgetType2 {
193
860
  return el;
194
861
  }
195
862
  };
196
- var LinkText = class extends WidgetType2 {
863
+ var LinkText = class extends WidgetType3 {
197
864
  constructor(_pos, _text, _url) {
198
865
  super();
199
866
  this._pos = _pos;
@@ -223,26 +890,26 @@ var LinkText = class extends WidgetType2 {
223
890
  return link2;
224
891
  }
225
892
  };
226
- var update = (state, options) => {
227
- const builder = new RangeSetBuilder();
893
+ var update2 = (state, options) => {
894
+ const builder = new RangeSetBuilder2();
228
895
  const cursor = state.selection.main.head;
229
- syntaxTree(state).iterate({
896
+ syntaxTree2(state).iterate({
230
897
  enter: (node) => {
231
898
  if (node.name === "Link") {
232
- const marks = node.node.getChildren("LinkMark");
233
- const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
899
+ const marks2 = node.node.getChildren("LinkMark");
900
+ const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
234
901
  const urlNode = node.node.getChild("URL");
235
902
  const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
236
903
  if (!url) {
237
904
  return false;
238
905
  }
239
- if (cursor < node.from || cursor > node.to) {
240
- builder.add(node.from, node.to, Decoration2.replace({
906
+ if (state.readOnly || cursor < node.from || cursor > node.to) {
907
+ builder.add(node.from, node.to, Decoration5.replace({
241
908
  widget: new LinkText(node.from, text, options.link ? url : void 0)
242
909
  }));
243
910
  }
244
911
  if (options.onRender) {
245
- builder.add(node.to, node.to, Decoration2.replace({
912
+ builder.add(node.to, node.to, Decoration5.replace({
246
913
  widget: new LinkButton(node.from, url, options.onRender)
247
914
  }));
248
915
  }
@@ -252,69 +919,39 @@ var update = (state, options) => {
252
919
  });
253
920
  return builder.finish();
254
921
  };
255
- var link = (options = {}) => {
256
- return StateField.define({
257
- create: (state) => update(state, options),
258
- update: (_, tr) => update(tr.state, options),
259
- provide: (field) => EditorView3.decorations.from(field)
260
- });
261
- };
262
922
 
263
923
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
264
- import { StateField as StateField2 } from "@codemirror/state";
265
- var listener = (onChange) => StateField2.define({
266
- create: () => null,
267
- update: (_value, transaction) => {
268
- if (transaction.docChanged && onChange) {
269
- onChange(transaction.newDoc.toString());
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;
270
933
  }
271
- return null;
272
- }
273
- });
934
+ });
935
+ };
274
936
 
275
937
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
276
938
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
277
- import { defaultKeymap, history, indentWithTab } from "@codemirror/commands";
939
+ import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
278
940
  import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
279
941
  import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
280
942
  import { languages } from "@codemirror/language-data";
281
- import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
943
+ import { searchKeymap } from "@codemirror/search";
282
944
  import { EditorState } from "@codemirror/state";
283
945
  import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
284
- import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView4, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap3, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
946
+ import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView8, highlightActiveLine, keymap as keymap5, placeholder as placeholder2 } from "@codemirror/view";
285
947
 
286
948
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
287
949
  import { markdownLanguage } from "@codemirror/lang-markdown";
288
950
  import { HighlightStyle } from "@codemirror/language";
289
951
  import { tags, styleTags, Tag } from "@lezer/highlight";
290
- import get from "lodash.get";
291
-
292
- // packages/ui/react-ui-editor/src/styles/markdown.ts
293
- import { mx } from "@dxos/react-ui-theme";
294
- var heading = {
295
- 1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
296
- 2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
297
- 3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
298
- 4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
299
- 5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
300
- 6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
301
- };
302
- var light = "text-neutral-200 dark:text-neutral-800";
303
- var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
304
- var bold = "font-bold";
305
- var italic = "italic";
306
- var strikethrough = "line-through";
307
- var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
308
- var codeMark = "font-mono text-primary-500";
309
- var inlineUrl = mx(code, "px-1");
310
- var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
311
- var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
312
-
313
- // packages/ui/react-ui-editor/src/styles/tokens.ts
314
- import { tailwindConfig } from "@dxos/react-ui-theme";
315
- var tokens = tailwindConfig({}).theme;
316
-
317
- // 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";
318
955
  var markdownTags = {
319
956
  Blockquote: Tag.define(),
320
957
  CodeMark: Tag.define(),
@@ -327,179 +964,202 @@ var markdownTags = {
327
964
  LinkReference: Tag.define(),
328
965
  ListMark: Tag.define(),
329
966
  QuoteMark: Tag.define(),
330
- URL: Tag.define()
331
- };
332
- var markdownTagsExtension = {
333
- props: [
334
- styleTags(markdownTags)
335
- ]
967
+ URL: Tag.define(),
968
+ // Custom.
969
+ TableCell: Tag.define()
336
970
  };
337
- var markdownHighlightStyle = HighlightStyle.define([
338
- {
339
- tag: [
340
- tags.keyword,
341
- tags.name,
342
- tags.deleted,
343
- tags.character,
344
- tags.propertyName,
345
- tags.macroName,
346
- tags.color,
347
- tags.constant(tags.name),
348
- tags.standard(tags.name),
349
- tags.definition(tags.name),
350
- tags.separator,
351
- tags.typeName,
352
- tags.className,
353
- tags.number,
354
- tags.changed,
355
- tags.annotation,
356
- tags.modifier,
357
- tags.self,
358
- tags.namespace,
359
- tags.operator,
360
- tags.operatorKeyword,
361
- tags.escape,
362
- tags.regexp,
363
- tags.special(tags.string),
364
- tags.meta,
365
- tags.comment,
366
- tags.atom,
367
- tags.bool,
368
- tags.special(tags.variableName),
369
- tags.processingInstruction,
370
- tags.string,
371
- tags.inserted,
372
- tags.invalid
373
- ],
374
- color: "inherit !important"
375
- },
376
- // Markdown marks.
377
- {
378
- tag: [
379
- tags.meta,
380
- tags.processingInstruction,
381
- markdownTags.CodeMark,
382
- markdownTags.EmphasisMark,
383
- markdownTags.HeaderMark,
384
- markdownTags.LinkLabel,
385
- markdownTags.LinkReference,
386
- markdownTags.ListMark,
387
- markdownTags.QuoteMark
388
- ],
389
- class: mark
390
- },
391
- // Headings.
392
- {
393
- tag: tags.heading1,
394
- class: heading[1]
395
- },
396
- {
397
- tag: tags.heading2,
398
- class: heading[2]
399
- },
400
- {
401
- tag: tags.heading3,
402
- class: heading[3]
403
- },
404
- {
405
- tag: tags.heading4,
406
- class: heading[4]
407
- },
408
- {
409
- tag: tags.heading5,
410
- class: heading[5]
411
- },
412
- {
413
- tag: tags.heading6,
414
- class: heading[6]
415
- },
416
- // Emphasis.
417
- {
418
- tag: tags.emphasis,
419
- class: italic
420
- },
421
- {
422
- tag: tags.strong,
423
- class: bold
424
- },
425
- {
426
- tag: tags.strikethrough,
427
- class: strikethrough
428
- },
429
- // Naked URLs.
430
- {
431
- tag: [
432
- markdownTags.URL
433
- ],
434
- class: inlineUrl
435
- },
436
- // E.g., code block language (after ```).
437
- {
438
- tag: [
439
- tags.function(tags.variableName),
440
- tags.labelName
441
- ],
442
- class: codeMark
443
- },
444
- // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
445
- // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
446
- // when a language is specified. In this case, the syntax highlighting extensions will colorize
447
- // the code, but all other CSS properties will be inherited.
448
- // IMPORTANT: Therefore, the fenced code block will use the base editor font.
449
- {
450
- tag: [
451
- markdownTags.CodeText,
452
- markdownTags.InlineCode
453
- ],
454
- class: code
455
- },
456
- {
457
- tag: [
458
- markdownTags.QuoteMark
459
- ],
460
- class: blockquote
461
- },
462
- {
463
- tag: [
464
- markdownTags.HorizontalRule
465
- ],
466
- class: horizontalRule
467
- }
468
- ], {
469
- scope: markdownLanguage,
470
- all: {
471
- 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
+ }
472
977
  }
473
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
+ };
474
1146
 
475
1147
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
476
- var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
1148
+ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
477
1149
  return [
1150
+ EditorState.allowMultipleSelections.of(true),
1151
+ EditorState.tabSize.of(2),
1152
+ EditorView8.lineWrapping,
1153
+ customKeymap(),
478
1154
  bracketMatching2(),
479
1155
  closeBrackets2(),
480
- _placeholder && placeholder2(_placeholder),
481
- EditorState.allowMultipleSelections.of(true),
482
- EditorView4.lineWrapping,
483
1156
  crosshairCursor(),
484
1157
  dropCursor(),
485
- drawSelection(),
1158
+ drawSelection2(),
486
1159
  highlightActiveLine(),
487
- highlightActiveLineGutter(),
488
- highlightSelectionMatches(),
489
- highlightSpecialChars(),
490
1160
  history(),
491
1161
  indentOnInput(),
492
- rectangularSelection(),
493
- // TODO(burdon): Review.
494
- keymap3.of([
495
- ...closeBracketsKeymap,
496
- ...defaultKeymap,
497
- // ...foldKeymap,
498
- // ...historyKeymap,
499
- // ...lintKeymap,
500
- ...searchKeymap,
501
- indentWithTab
502
- ]),
1162
+ _placeholder && placeholder2(_placeholder),
503
1163
  // Main extension.
504
1164
  // https://github.com/codemirror/lang-markdown
505
1165
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -514,20 +1174,156 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
514
1174
  codeLanguages: languages,
515
1175
  // Parser extensions.
516
1176
  extensions: [
517
- // GFM, // TODO(burdon): Provided by default?
518
- markdownTagsExtension
1177
+ // GFM provided by default.
1178
+ markdownTagsExtensions
519
1179
  ]
520
1180
  }),
1181
+ // https://github.com/codemirror/theme-one-dark
1182
+ themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
521
1183
  // Custom styles.
522
- syntaxHighlighting2(markdownHighlightStyle),
523
- // TODO(thure): All but one rule here apply to both themes; rename or refactor.
524
- themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
1184
+ syntaxHighlighting2(markdownHighlightStyle(readonly))
525
1185
  ].filter(Boolean);
526
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
+ };
527
1317
 
528
1318
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
529
- import { EditorView as EditorView5, Decoration as Decoration3, WidgetType as WidgetType3, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
530
- var CheckboxWidget = class extends WidgetType3 {
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 {
531
1327
  constructor(_pos, _checked, _indent, _onCheck) {
532
1328
  super();
533
1329
  this._pos = _pos;
@@ -546,30 +1342,29 @@ var CheckboxWidget = class extends WidgetType3 {
546
1342
  const input = wrap.appendChild(document.createElement("input"));
547
1343
  input.type = "checkbox";
548
1344
  input.checked = this._checked;
549
- input.onchange = (event) => {
550
- this._onCheck(event.target.checked);
551
- return true;
552
- };
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
+ }
553
1354
  return wrap;
554
1355
  }
555
1356
  ignoreEvent() {
556
1357
  return false;
557
1358
  }
558
1359
  };
559
- var styles2 = EditorView5.baseTheme({
560
- "& .cm-task-item": {
561
- paddingLeft: "4px",
562
- paddingRight: "8px"
563
- }
564
- });
565
- var tasklist = () => {
1360
+ var tasklist = (options = {}) => {
566
1361
  const taskMatcher = new MatchDecorator2({
567
1362
  regexp: /^(\s*)- \[([ xX])\]\s/g,
568
1363
  decoration: (match, view, pos) => {
569
1364
  const indent = Math.floor(match[1].length / 2);
570
1365
  const checked = match[2] === "x" || match[2] === "X";
571
- return Decoration3.replace({
572
- widget: new CheckboxWidget(pos, checked, indent, (checked2) => {
1366
+ return Decoration7.replace({
1367
+ widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
573
1368
  const idx = pos + match[0].indexOf("[") + 1;
574
1369
  view.dispatch({
575
1370
  changes: {
@@ -586,22 +1381,22 @@ var tasklist = () => {
586
1381
  });
587
1382
  }
588
1383
  });
589
- const tasks = ViewPlugin2.fromClass(class {
1384
+ const tasks = ViewPlugin3.fromClass(class {
590
1385
  constructor(view) {
591
1386
  this.tasks = taskMatcher.createDeco(view);
592
1387
  }
593
- update(update2) {
594
- this.tasks = taskMatcher.updateDeco(update2, this.tasks);
1388
+ update(update4) {
1389
+ this.tasks = taskMatcher.updateDeco(update4, this.tasks);
595
1390
  }
596
1391
  }, {
597
- decorations: (instance) => instance.tasks,
598
- provide: (plugin) => EditorView5.atomicRanges.of((view) => {
599
- return view.plugin(plugin)?.tasks || Decoration3.none;
1392
+ decorations: (value) => value.tasks,
1393
+ provide: (plugin) => EditorView10.atomicRanges.of((view) => {
1394
+ return view.plugin(plugin)?.tasks || Decoration7.none;
600
1395
  })
601
1396
  });
602
1397
  return [
603
1398
  tasks,
604
- styles2
1399
+ styles4
605
1400
  ];
606
1401
  };
607
1402
 
@@ -650,7 +1445,7 @@ var tooltip = ({ onHover, regexp = markdownLinkRegexp }) => hoverTooltip((view,
650
1445
  });
651
1446
 
652
1447
  // packages/ui/react-ui-editor/src/components/TextEditor/themes/default.ts
653
- import get2 from "lodash.get";
1448
+ import get3 from "lodash.get";
654
1449
  var defaultTheme = {
655
1450
  //
656
1451
  // Main layout:
@@ -667,7 +1462,8 @@ var defaultTheme = {
667
1462
  outline: "none"
668
1463
  },
669
1464
  "& .cm-scroller": {
670
- overflow: "visible"
1465
+ overflow: "visible",
1466
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
671
1467
  },
672
1468
  "& .cm-content": {
673
1469
  padding: 0,
@@ -675,20 +1471,20 @@ var defaultTheme = {
675
1471
  fontSize: "16px"
676
1472
  },
677
1473
  "&light .cm-content": {
678
- color: get2(tokens, "extend.colors.neutral.900", "black"),
1474
+ color: get3(tokens, "extend.colors.neutral.900", "black"),
679
1475
  caretColor: "black"
680
1476
  },
681
1477
  "&dark .cm-content": {
682
- color: get2(tokens, "extend.colors.neutral.100", "white"),
1478
+ color: get3(tokens, "extend.colors.neutral.100", "white"),
683
1479
  caretColor: "white"
684
1480
  },
685
1481
  //
686
1482
  // Cursor
687
1483
  //
688
- "&light .cm-cursor": {
1484
+ "&light .cm-cursor, &light .cm-dropCursor": {
689
1485
  borderLeft: "2px solid black"
690
1486
  },
691
- "&dark .cm-cursor": {
1487
+ "&dark .cm-cursor, &dark .cm-dropCursor": {
692
1488
  borderLeft: "2px solid white"
693
1489
  },
694
1490
  "& .cm-placeholder": {
@@ -708,16 +1504,16 @@ var defaultTheme = {
708
1504
  // selection
709
1505
  //
710
1506
  "&light .cm-selectionBackground, &light.cm-focused .cm-selectionBackground": {
711
- background: get2(tokens, "extend.colors.primary.150", "#00ffff")
1507
+ background: get3(tokens, "extend.colors.primary.150", "#00ffff")
712
1508
  },
713
1509
  "&dark .cm-selectionBackground, &dark.cm-focused .cm-selectionBackground": {
714
- background: get2(tokens, "extend.colors.primary.850", "#00ffff")
1510
+ background: get3(tokens, "extend.colors.primary.850", "#00ffff")
715
1511
  },
716
1512
  "&light .cm-selectionMatch": {
717
- background: get2(tokens, "extend.colors.primary.250", "#00ffff") + "44"
1513
+ background: get3(tokens, "extend.colors.primary.250", "#00ffff") + "44"
718
1514
  },
719
1515
  "&dark .cm-selectionMatch": {
720
- background: get2(tokens, "extend.colors.primary.600", "#00ffff") + "44"
1516
+ background: get3(tokens, "extend.colors.primary.600", "#00ffff") + "44"
721
1517
  },
722
1518
  //
723
1519
  // collaboration
@@ -750,12 +1546,12 @@ var defaultTheme = {
750
1546
  // link
751
1547
  //
752
1548
  "& .cm-link": {
753
- color: get2(tokens, "extend.colors.primary.500"),
1549
+ color: get3(tokens, "extend.colors.primary.500"),
754
1550
  textDecorationLine: "underline",
755
1551
  textDecorationThickness: "1px",
756
1552
  textUnderlineOffset: "2px",
757
1553
  borderRadius: ".125rem",
758
- fontFamily: get2(tokens, "fontFamily.body", []).join(",")
1554
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
759
1555
  },
760
1556
  //
761
1557
  // tooltip
@@ -763,14 +1559,61 @@ var defaultTheme = {
763
1559
  "& .cm-tooltip": {
764
1560
  border: "none"
765
1561
  },
766
- // '& .cm-tooltip-below': {},
767
- // '& .cm-tooltip-autocomplete': {},
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
+ },
768
1611
  //
769
1612
  // font size
770
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.
771
1614
  //
772
- ...Object.keys(get2(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
773
- const height = get2(tokens, [
1615
+ ...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
1616
+ const height = get3(tokens, [
774
1617
  "extend",
775
1618
  "fontSize",
776
1619
  fontSize,
@@ -787,46 +1630,81 @@ var defaultTheme = {
787
1630
  height
788
1631
  };
789
1632
  return acc;
790
- }, {})
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
+ }
791
1669
  };
792
1670
  var textTheme = {
793
1671
  "& .cm-scroller": {
794
- fontFamily: get2(tokens, "fontFamily.body", []).join(",")
1672
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
795
1673
  },
796
1674
  "& .cm-placeholder": {
797
- fontFamily: get2(tokens, "fontFamily.body", []).join(",")
1675
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
798
1676
  }
799
1677
  };
800
1678
  var markdownTheme = {
801
1679
  // NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
802
1680
  "& .cm-placeholder": {
803
- fontFamily: get2(tokens, "fontFamily.body", []).join(",")
1681
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
804
1682
  }
805
1683
  };
806
1684
  var codeTheme = {
807
1685
  "& .cm-scroller": {
808
- fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
1686
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
809
1687
  },
810
1688
  "& .cm-placeholder": {
811
- fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
1689
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
812
1690
  }
813
1691
  };
814
1692
 
815
1693
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
816
1694
  import { EditorState as EditorState2 } from "@codemirror/state";
817
- import { EditorView as EditorView6 } from "@codemirror/view";
1695
+ import { EditorView as EditorView11 } from "@codemirror/view";
818
1696
  import { useFocusableGroup } from "@fluentui/react-tabster";
819
1697
  import { vim } from "@replit/codemirror-vim";
820
- import defaultsDeep from "lodash.defaultsdeep";
821
- 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";
822
1700
  import { generateName } from "@dxos/display-name";
823
1701
  import { useThemeContext } from "@dxos/react-ui";
824
- import { getColorForValue, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
1702
+ import { getColorForValue, inputSurface, mx as mx4 } from "@dxos/react-ui-theme";
825
1703
  var EditorModes = [
826
1704
  "default",
827
1705
  "vim"
828
1706
  ];
829
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
1707
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
830
1708
  const { themeMode } = useThemeContext();
831
1709
  const tabsterDOMAttribute = useFocusableGroup({
832
1710
  tabBehavior: "limited"
@@ -844,7 +1722,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
844
1722
  root
845
1723
  ]);
846
1724
  const { awareness, peer } = model;
847
- useEffect(() => {
1725
+ useEffect2(() => {
848
1726
  if (awareness && peer) {
849
1727
  awareness.setLocalStateField("user", {
850
1728
  name: peer.name ?? generateName(peer.id),
@@ -864,20 +1742,22 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
864
1742
  peer,
865
1743
  themeMode
866
1744
  ]);
867
- useEffect(() => {
1745
+ useEffect2(() => {
868
1746
  if (!root) {
869
1747
  return;
870
1748
  }
871
1749
  const state2 = EditorState2.create({
872
1750
  doc: model.text(),
873
1751
  extensions: [
1752
+ readonly && EditorState2.readOnly.of(readonly),
874
1753
  // TODO(burdon): Factor out VIM mode?
875
1754
  editorMode === "vim" && vim(),
876
1755
  // Theme.
877
- EditorView6.baseTheme(defaultTheme),
878
- EditorView6.theme(slots?.editor?.theme ?? {}),
1756
+ // TODO(burdon): Make optional.
1757
+ EditorView11.baseTheme(defaultTheme),
1758
+ EditorView11.theme(slots?.editor?.theme ?? {}),
879
1759
  // TODO(burdon): themeMode doesn't change in storybooks.
880
- EditorView6.darkTheme.of(themeMode === "dark"),
1760
+ EditorView11.darkTheme.of(themeMode === "dark"),
881
1761
  // Storage and replication.
882
1762
  model.extension,
883
1763
  // Custom.
@@ -885,7 +1765,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
885
1765
  ].filter(Boolean)
886
1766
  });
887
1767
  view?.destroy();
888
- setView(new EditorView6({
1768
+ setView(new EditorView11({
889
1769
  state: state2,
890
1770
  parent: root
891
1771
  }));
@@ -899,6 +1779,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
899
1779
  root,
900
1780
  model,
901
1781
  themeMode,
1782
+ readonly,
902
1783
  editorMode
903
1784
  ]);
904
1785
  const handleKeyUp = useCallback((event) => {
@@ -926,13 +1807,15 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
926
1807
  onKeyUp: handleKeyUp
927
1808
  });
928
1809
  });
929
- var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
1810
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
930
1811
  const { themeMode } = useThemeContext();
931
- const slots = defaultsDeep({}, _slots, defaultTextSlots);
1812
+ const slots = defaultsDeep2({}, _slots, defaultTextSlots);
932
1813
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
933
1814
  ref: forwardedRef,
1815
+ readonly,
934
1816
  extensions: [
935
1817
  basicBundle({
1818
+ readonly,
936
1819
  themeMode,
937
1820
  placeholder: slots?.editor?.placeholder
938
1821
  }),
@@ -942,13 +1825,15 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, .
942
1825
  ...props
943
1826
  });
944
1827
  });
945
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
1828
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
946
1829
  const { themeMode } = useThemeContext();
947
- const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
1830
+ const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
948
1831
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
949
1832
  ref: forwardedRef,
1833
+ readonly,
950
1834
  extensions: [
951
1835
  markdownBundle({
1836
+ readonly,
952
1837
  themeMode,
953
1838
  placeholder: slots?.editor?.placeholder
954
1839
  }),
@@ -960,7 +1845,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slot
960
1845
  });
961
1846
  var defaultSlots = {
962
1847
  root: {
963
- className: mx2("p-2", inputSurface)
1848
+ className: mx4("p-2", inputSurface)
964
1849
  }
965
1850
  };
966
1851
  var defaultTextSlots = {
@@ -977,23 +1862,23 @@ var defaultMarkdownSlots = {
977
1862
  };
978
1863
 
979
1864
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
980
- import get3 from "lodash.get";
981
- import { useEffect as useEffect2, useState as useState2 } from "react";
1865
+ import get4 from "lodash.get";
1866
+ import { useEffect as useEffect3, useState as useState2 } from "react";
982
1867
  import { yCollab } from "y-codemirror.next";
983
- import { invariant as invariant2 } from "@dxos/invariant";
1868
+ import { invariant as invariant3 } from "@dxos/invariant";
984
1869
  import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
985
1870
 
986
1871
  // packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
987
- import { Annotation, Facet, StateEffect, StateField as StateField3 } from "@codemirror/state";
988
- import { ViewPlugin as ViewPlugin3 } from "@codemirror/view";
1872
+ import { Annotation, Facet, StateEffect as StateEffect2, StateField as StateField6 } from "@codemirror/state";
1873
+ import { ViewPlugin as ViewPlugin4 } from "@codemirror/view";
989
1874
  import * as automerge2 from "@dxos/automerge/automerge";
990
1875
 
991
1876
  // packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
992
1877
  import { next as automerge } from "@dxos/automerge/automerge";
993
1878
 
994
- // packages/ui/react-ui-editor/src/hooks/automerge/amToCodemirror.ts
1879
+ // packages/ui/react-ui-editor/src/hooks/automerge/translation/automerge-to-codemirror.ts
995
1880
  import { ChangeSet } from "@codemirror/state";
996
- var amToCodemirror_default = (view, selection, target, patches) => {
1881
+ var automergeToCodemirror = (view, selection, target, patches) => {
997
1882
  for (const patch of patches) {
998
1883
  const changeSpec = handlePatch(patch, target, view.state);
999
1884
  if (changeSpec != null) {
@@ -1098,9 +1983,9 @@ var charPath = (textPath, candidatePath) => {
1098
1983
  return null;
1099
1984
  };
1100
1985
 
1101
- // packages/ui/react-ui-editor/src/hooks/automerge/codeMirrorToAm.ts
1986
+ // packages/ui/react-ui-editor/src/hooks/automerge/translation/codemirror-to-automerge.ts
1102
1987
  import { next as am } from "@dxos/automerge/automerge";
1103
- var codeMirrorToAm_default = (field, handle, transactions, state) => {
1988
+ var codemirrorToAutomerge = (field, handle, transactions, state) => {
1104
1989
  const { lastHeads, path } = state.field(field);
1105
1990
  let hasChanges = false;
1106
1991
  for (const tr of transactions) {
@@ -1144,12 +2029,12 @@ var PatchSemaphore = class {
1144
2029
  annotations: reconcileAnnotationType.of(true)
1145
2030
  });
1146
2031
  }
1147
- let newHeads = codeMirrorToAm_default(this._field, handle, transactions, view.state);
2032
+ let newHeads = codemirrorToAutomerge(this._field, handle, transactions, view.state);
1148
2033
  if (newHeads === null || newHeads === void 0) {
1149
2034
  newHeads = automerge.getHeads(handle.docSync());
1150
2035
  }
1151
2036
  const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
1152
- amToCodemirror_default(view, selection, path, diff);
2037
+ automergeToCodemirror(view, selection, path, diff);
1153
2038
  view.dispatch({
1154
2039
  effects: updateHeads(newHeads),
1155
2040
  annotations: reconcileAnnotationType.of({})
@@ -1163,7 +2048,7 @@ var PatchSemaphore = class {
1163
2048
  };
1164
2049
 
1165
2050
  // packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
1166
- var effectType = StateEffect.define({});
2051
+ var effectType = StateEffect2.define({});
1167
2052
  var updateHeads = (newHeads) => effectType.of({
1168
2053
  newHeads
1169
2054
  });
@@ -1173,7 +2058,7 @@ var semaphoreFacet = Facet.define({
1173
2058
  combine: (values) => values.at(-1)
1174
2059
  });
1175
2060
  var automergePlugin = (handle, path) => {
1176
- const stateField = StateField3.define({
2061
+ const stateField = StateField6.define({
1177
2062
  create: () => ({
1178
2063
  lastHeads: automerge2.getHeads(handle.docSync()),
1179
2064
  unreconciledTransactions: [],
@@ -1203,7 +2088,7 @@ var automergePlugin = (handle, path) => {
1203
2088
  }
1204
2089
  });
1205
2090
  const semaphore = new PatchSemaphore(stateField);
1206
- const viewPlugin = ViewPlugin3.fromClass(class AutomergeCodemirrorViewPlugin {
2091
+ const viewPlugin = ViewPlugin4.fromClass(class AutomergeCodemirrorViewPlugin {
1207
2092
  constructor(view) {
1208
2093
  this._handleChange = () => {
1209
2094
  this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
@@ -1211,8 +2096,8 @@ var automergePlugin = (handle, path) => {
1211
2096
  this._view = view;
1212
2097
  handle.addListener("change", this._handleChange);
1213
2098
  }
1214
- update(update2) {
1215
- if (update2.transactions.length > 0 && update2.transactions.some((t) => !isReconcileTx(t))) {
2099
+ update(update4) {
2100
+ if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
1216
2101
  queueMicrotask(() => {
1217
2102
  this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
1218
2103
  });
@@ -1234,7 +2119,7 @@ var reconcileAnnotationType = Annotation.define();
1234
2119
  var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
1235
2120
 
1236
2121
  // packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
1237
- import * as random from "lib0/random";
2122
+ import * as random2 from "lib0/random";
1238
2123
  var cursorColors = [
1239
2124
  {
1240
2125
  color: "#30bced",
@@ -1269,7 +2154,7 @@ var cursorColors = [
1269
2154
  light: "#1be7ff33"
1270
2155
  }
1271
2156
  ];
1272
- var cursorColor = cursorColors[random.uint32() % cursorColors.length];
2157
+ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
1273
2158
 
1274
2159
  // packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
1275
2160
  import * as decoding from "lib0/decoding";
@@ -1277,7 +2162,7 @@ import * as encoding from "lib0/encoding";
1277
2162
  import { Observable } from "lib0/observable";
1278
2163
  import * as awarenessProtocol from "y-protocols/awareness";
1279
2164
  import { log } from "@dxos/log";
1280
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
2165
+ var __dxlog_file3 = "/home/circleci/project/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
1281
2166
  var messageAwareness = 1;
1282
2167
  var messageQueryAwareness = 3;
1283
2168
  var SpaceAwarenessProvider = class extends Observable {
@@ -1314,7 +2199,7 @@ var SpaceAwarenessProvider = class extends Observable {
1314
2199
  removed,
1315
2200
  origin
1316
2201
  }, {
1317
- F: __dxlog_file2,
2202
+ F: __dxlog_file3,
1318
2203
  L: 67,
1319
2204
  S: this,
1320
2205
  C: (f, a) => f(...a)
@@ -1327,7 +2212,7 @@ var SpaceAwarenessProvider = class extends Observable {
1327
2212
  }
1328
2213
  _handleSpaceMessage({ payload }) {
1329
2214
  log("space message", payload, {
1330
- F: __dxlog_file2,
2215
+ F: __dxlog_file3,
1331
2216
  L: 79,
1332
2217
  S: this,
1333
2218
  C: (f, a) => f(...a)
@@ -1372,14 +2257,14 @@ var SpaceAwarenessProvider = class extends Observable {
1372
2257
  };
1373
2258
 
1374
2259
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
1375
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
2260
+ var __dxlog_file4 = "/home/circleci/project/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
1376
2261
  var useTextModel = ({ identity, space, text }) => {
1377
2262
  const [model, setModel] = useState2(() => createModel({
1378
2263
  identity,
1379
2264
  space,
1380
2265
  text
1381
2266
  }));
1382
- useEffect2(() => {
2267
+ useEffect3(() => {
1383
2268
  setModel(createModel({
1384
2269
  identity,
1385
2270
  space,
@@ -1404,9 +2289,9 @@ var createModel = (options) => {
1404
2289
  }
1405
2290
  };
1406
2291
  var createYjsModel = ({ identity, space, text }) => {
1407
- invariant2(text?.doc && text?.content, void 0, {
1408
- F: __dxlog_file3,
1409
- L: 74,
2292
+ invariant3(text?.doc && text?.content, void 0, {
2293
+ F: __dxlog_file4,
2294
+ L: 81,
1410
2295
  S: void 0,
1411
2296
  A: [
1412
2297
  "text?.doc && text?.content",
@@ -1422,6 +2307,7 @@ var createYjsModel = ({ identity, space, text }) => {
1422
2307
  id: text.doc.guid,
1423
2308
  content: text.content,
1424
2309
  text: () => text.content.toString(),
2310
+ ranges: [],
1425
2311
  extension: yCollab(text.content, provider?.awareness),
1426
2312
  awareness: provider?.awareness,
1427
2313
  peer: identity ? {
@@ -1438,7 +2324,8 @@ var createAutomergeModel = ({ identity, text }) => {
1438
2324
  return {
1439
2325
  id: obj.id,
1440
2326
  content: doc,
1441
- text: () => get3(doc.handle.docSync(), doc.path),
2327
+ text: () => get4(doc.handle.docSync(), doc.path),
2328
+ ranges: [],
1442
2329
  extension: automergePlugin(doc.handle, doc.path),
1443
2330
  peer: identity ? {
1444
2331
  id: identity.identityKey.toHex(),
@@ -1458,24 +2345,35 @@ export {
1458
2345
  YXmlFragment,
1459
2346
  autocomplete,
1460
2347
  basicBundle,
2348
+ blast,
2349
+ code2 as code,
1461
2350
  codeTheme,
1462
2351
  comments,
1463
2352
  cursorColor,
1464
2353
  defaultMarkdownSlots,
2354
+ defaultOptions,
1465
2355
  defaultSlots,
1466
2356
  defaultTextSlots,
1467
2357
  defaultTheme,
2358
+ demo,
2359
+ highlight,
2360
+ highlightDecorations,
2361
+ highlightStateField,
2362
+ image,
1468
2363
  link,
1469
- listener,
2364
+ listener2 as listener,
1470
2365
  markdownBundle,
1471
2366
  markdownHighlightStyle,
1472
2367
  markdownTags,
1473
- markdownTagsExtension,
2368
+ markdownTagsExtensions,
1474
2369
  markdownTheme,
2370
+ mention,
2371
+ table,
1475
2372
  tags2 as tags,
1476
2373
  tasklist,
1477
2374
  textTheme,
1478
2375
  tooltip,
2376
+ useHighlights,
1479
2377
  useTextModel
1480
2378
  };
1481
2379
  //# sourceMappingURL=index.mjs.map