@dxos/react-ui-editor 0.3.10-main.a21ec31 → 0.3.10-main.c5193cc

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