@dxos/react-ui-editor 0.3.10-main.cb1d9e2 → 0.3.10-main.cbe7692

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 (80) hide show
  1. package/dist/lib/browser/index.mjs +704 -135
  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 +19 -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 +2 -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.map +1 -1
  9. package/dist/types/src/components/TextEditor/extensions/basic.d.ts +2 -1
  10. package/dist/types/src/components/TextEditor/extensions/basic.d.ts.map +1 -1
  11. package/dist/types/src/components/TextEditor/extensions/blast.d.ts +25 -0
  12. package/dist/types/src/components/TextEditor/extensions/blast.d.ts.map +1 -0
  13. package/dist/types/src/components/TextEditor/extensions/demo.d.ts +2 -1
  14. package/dist/types/src/components/TextEditor/extensions/demo.d.ts.map +1 -1
  15. package/dist/types/src/components/TextEditor/extensions/image.d.ts +4 -0
  16. package/dist/types/src/components/TextEditor/extensions/image.d.ts.map +1 -0
  17. package/dist/types/src/components/TextEditor/extensions/index.d.ts +4 -0
  18. package/dist/types/src/components/TextEditor/extensions/index.d.ts.map +1 -1
  19. package/dist/types/src/components/TextEditor/extensions/link.d.ts.map +1 -1
  20. package/dist/types/src/components/TextEditor/extensions/listener.d.ts.map +1 -1
  21. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts +2 -1
  22. package/dist/types/src/components/TextEditor/extensions/markdown/bundle.d.ts.map +1 -1
  23. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts +6 -2
  24. package/dist/types/src/components/TextEditor/extensions/markdown/highlight.d.ts.map +1 -1
  25. package/dist/types/src/components/TextEditor/extensions/mention.d.ts +6 -0
  26. package/dist/types/src/components/TextEditor/extensions/mention.d.ts.map +1 -0
  27. package/dist/types/src/components/TextEditor/extensions/table.d.ts +8 -0
  28. package/dist/types/src/components/TextEditor/extensions/table.d.ts.map +1 -0
  29. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts +2 -1
  30. package/dist/types/src/components/TextEditor/extensions/tasklist.d.ts.map +1 -1
  31. package/dist/types/src/components/TextEditor/themes/default.d.ts +5 -0
  32. package/dist/types/src/components/TextEditor/themes/default.d.ts.map +1 -1
  33. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts +3 -0
  34. package/dist/types/src/hooks/automerge/PatchSemaphore.d.ts.map +1 -1
  35. package/dist/types/src/hooks/automerge/automerge.stories.d.ts +8 -1
  36. package/dist/types/src/hooks/automerge/automerge.stories.d.ts.map +1 -1
  37. package/dist/types/src/hooks/automerge/index.d.ts +1 -1
  38. package/dist/types/src/hooks/automerge/index.d.ts.map +1 -1
  39. package/dist/types/src/hooks/automerge/plugin.d.ts.map +1 -1
  40. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts +5 -0
  41. package/dist/types/src/hooks/automerge/translation/automerge-to-codemirror.d.ts.map +1 -0
  42. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts +6 -0
  43. package/dist/types/src/hooks/automerge/translation/codemirror-to-automerge.d.ts.map +1 -0
  44. package/dist/types/src/hooks/automerge/translation/index.d.ts +3 -0
  45. package/dist/types/src/hooks/automerge/translation/index.d.ts.map +1 -0
  46. package/dist/types/src/{components/TextEditor → hooks/yjs}/yjs.stories.d.ts +1 -1
  47. package/dist/types/src/hooks/yjs/yjs.stories.d.ts.map +1 -0
  48. package/dist/types/src/styles/markdown.d.ts +3 -2
  49. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  50. package/package.json +20 -20
  51. package/src/components/TextEditor/MarkdownEditor.stories.tsx +98 -25
  52. package/src/components/TextEditor/TextEditor.tsx +16 -7
  53. package/src/components/TextEditor/extensions/autocomplete.ts +5 -20
  54. package/src/components/TextEditor/extensions/basic.ts +2 -1
  55. package/src/components/TextEditor/extensions/blast.ts +375 -0
  56. package/src/components/TextEditor/extensions/demo.ts +4 -1
  57. package/src/components/TextEditor/extensions/image.ts +68 -0
  58. package/src/components/TextEditor/extensions/index.ts +4 -0
  59. package/src/components/TextEditor/extensions/link.ts +15 -23
  60. package/src/components/TextEditor/extensions/listener.ts +3 -3
  61. package/src/components/TextEditor/extensions/markdown/bundle.ts +19 -11
  62. package/src/components/TextEditor/extensions/markdown/highlight.ts +118 -104
  63. package/src/components/TextEditor/extensions/mention.ts +31 -0
  64. package/src/components/TextEditor/extensions/table.ts +123 -0
  65. package/src/components/TextEditor/extensions/tasklist.ts +34 -20
  66. package/src/components/TextEditor/themes/default.ts +54 -2
  67. package/src/hooks/automerge/PatchSemaphore.ts +12 -9
  68. package/src/hooks/automerge/automerge.stories.tsx +3 -2
  69. package/src/hooks/automerge/index.ts +1 -1
  70. package/src/hooks/automerge/plugin.ts +1 -0
  71. package/src/hooks/automerge/{amToCodemirror.ts → translation/automerge-to-codemirror.ts} +10 -2
  72. package/src/hooks/automerge/{codeMirrorToAm.ts → translation/codemirror-to-automerge.ts} +7 -4
  73. package/src/hooks/automerge/translation/index.ts +6 -0
  74. package/src/{components/TextEditor → hooks/yjs}/yjs.stories.tsx +1 -1
  75. package/src/styles/markdown.ts +14 -8
  76. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  77. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts +0 -6
  78. package/dist/types/src/hooks/automerge/amToCodemirror.d.ts.map +0 -1
  79. package/dist/types/src/hooks/automerge/codeMirrorToAm.d.ts +0 -7
  80. 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
  ]
@@ -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,8 +54,324 @@ 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/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
+ maxParticles: 200,
65
+ particleGravity: 0.08,
66
+ particleAlphaFadeout: 0.996,
67
+ particleSize: {
68
+ min: 2,
69
+ max: 8
70
+ },
71
+ particleNumRange: {
72
+ min: 5,
73
+ max: 10
74
+ },
75
+ particleVelocityRange: {
76
+ x: [
77
+ -1,
78
+ 1
79
+ ],
80
+ y: [
81
+ -3.5,
82
+ -1.5
83
+ ]
84
+ },
85
+ particleShrinkRate: 0.95,
86
+ shakeIntensity: 5
87
+ };
88
+ var blast = (options) => {
89
+ let blaster;
90
+ let last = 0;
91
+ const getPoint = (view, pos) => {
92
+ const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
93
+ const element = document.elementFromPoint(x, y);
94
+ const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
95
+ const point = {
96
+ x: x - left,
97
+ y: y - top
98
+ };
99
+ return {
100
+ element,
101
+ point
102
+ };
103
+ };
104
+ return [
105
+ // Cursor moved.
106
+ EditorView2.updateListener.of((update4) => {
107
+ if (blaster?.node !== update4.view.scrollDOM) {
108
+ if (blaster) {
109
+ blaster.destroy();
110
+ }
111
+ blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({}, options, defaultOptions));
112
+ blaster.initialize();
113
+ blaster.start();
114
+ } else {
115
+ blaster.resize();
116
+ }
117
+ const current = update4.view.state.selection.main.head;
118
+ if (current !== last) {
119
+ last = current;
120
+ const { element, point } = getPoint(update4.view, current);
121
+ if (element && point) {
122
+ blaster.spawn({
123
+ element,
124
+ point
125
+ });
126
+ }
127
+ }
128
+ }),
129
+ // Document changed.
130
+ StateField.define({
131
+ create: () => null,
132
+ update: (_value, transaction) => {
133
+ if (blaster && transaction.docChanged) {
134
+ const view = EditorView2.findFromDOM(blaster.node);
135
+ const { element, point } = getPoint(view, transaction.selection.main.head);
136
+ if (element && point) {
137
+ blaster.spawn({
138
+ element,
139
+ point
140
+ });
141
+ }
142
+ }
143
+ return null;
144
+ }
145
+ }),
146
+ keymap2.of([
147
+ {
148
+ any: (view, event) => {
149
+ if (blaster && event.key === "Enter" && event.shiftKey) {
150
+ blaster.shake({
151
+ time: 0.4
152
+ });
153
+ }
154
+ return false;
155
+ }
156
+ }
157
+ ])
158
+ ];
159
+ };
160
+ var Blaster = class {
161
+ constructor(_node, _options) {
162
+ this._node = _node;
163
+ this._options = _options;
164
+ this._running = false;
165
+ this._shakeTime = 0;
166
+ this._shakeTimeMax = 0;
167
+ this._particles = [];
168
+ this._particlePointer = 0;
169
+ this._lastPoint = {
170
+ x: 0,
171
+ y: 0
172
+ };
173
+ this.shake = throttle(({ time }) => {
174
+ this._shakeTime = this._shakeTimeMax;
175
+ this._shakeTimeMax = time;
176
+ }, 100);
177
+ this.spawn = throttle(({ element, point }) => {
178
+ const color = getRGBComponents(element, this._options.color);
179
+ const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
180
+ const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
181
+ this._lastPoint = point;
182
+ for (let i = numParticles; i--; i > 0) {
183
+ this._particles[this._particlePointer] = this._effect.create(point.x - dir * 16, point.y, color);
184
+ this._particlePointer = (this._particlePointer + 1) % this._options.maxParticles;
185
+ }
186
+ }, 100);
187
+ this._effect = this._options.effect === 1 ? new Effect1(_options) : new Effect2(_options);
188
+ }
189
+ get node() {
190
+ return this._node;
191
+ }
192
+ initialize() {
193
+ invariant(!this._canvas && !this._ctx, void 0, {
194
+ F: __dxlog_file,
195
+ L: 140,
196
+ S: this,
197
+ A: [
198
+ "!this._canvas && !this._ctx",
199
+ ""
200
+ ]
201
+ });
202
+ this._canvas = document.createElement("canvas");
203
+ this._canvas.id = "code-blast-canvas";
204
+ this._canvas.style.position = "absolute";
205
+ this._canvas.style.zIndex = "0";
206
+ this._canvas.style.pointerEvents = "none";
207
+ this._ctx = this._canvas.getContext("2d");
208
+ const parent = this._node.parentElement?.parentElement;
209
+ parent?.appendChild(this._canvas);
210
+ this.resize();
211
+ }
212
+ destroy() {
213
+ this.stop();
214
+ if (this._canvas) {
215
+ this._canvas.remove();
216
+ this._canvas = void 0;
217
+ this._ctx = void 0;
218
+ }
219
+ }
220
+ resize() {
221
+ if (this._node.parentElement && this._canvas) {
222
+ const { offsetLeft: x, offsetTop: y, offsetWidth: width, offsetHeight: height } = this._node.parentElement;
223
+ this._canvas.style.top = `${y}px`;
224
+ this._canvas.style.left = `${x}px`;
225
+ this._canvas.width = width;
226
+ this._canvas.height = height;
227
+ }
228
+ }
229
+ start() {
230
+ invariant(this._canvas && this._ctx, void 0, {
231
+ F: __dxlog_file,
232
+ L: 179,
233
+ S: this,
234
+ A: [
235
+ "this._canvas && this._ctx",
236
+ ""
237
+ ]
238
+ });
239
+ this._running = true;
240
+ this.loop();
241
+ }
242
+ stop() {
243
+ this._running = false;
244
+ this._node.style.transform = "translate(0px, 0px)";
245
+ }
246
+ loop() {
247
+ if (!this._running || !this._canvas || !this._ctx) {
248
+ return;
249
+ }
250
+ this._ctx.clearRect(0, 0, this._canvas.width ?? 0, this._canvas.height ?? 0);
251
+ const now = (/* @__PURE__ */ new Date()).getTime();
252
+ this._lastTime ??= now;
253
+ const dt = (now - this._lastTime) / 1e3;
254
+ this._lastTime = now;
255
+ if (this._shakeTime > 0) {
256
+ this._shakeTime -= dt;
257
+ const magnitude = this._shakeTime / this._shakeTimeMax * this._options.shakeIntensity;
258
+ const shakeX = random(-magnitude, magnitude);
259
+ const shakeY = random(-magnitude, magnitude);
260
+ this._node.style.transform = `translate(${shakeX}px,${shakeY}px)`;
261
+ }
262
+ this.drawParticles();
263
+ requestAnimationFrame(this.loop.bind(this));
264
+ }
265
+ drawParticles() {
266
+ for (let i = this._particles.length; i--; i > 0) {
267
+ const particle = this._particles[i];
268
+ if (!particle) {
269
+ continue;
270
+ }
271
+ if (particle.alpha < 0.01 || particle.size <= 0.5) {
272
+ continue;
273
+ }
274
+ this._effect.update(this._ctx, particle);
275
+ }
276
+ }
277
+ };
278
+ var Effect = class {
279
+ constructor(_options) {
280
+ this._options = _options;
281
+ }
282
+ };
283
+ var Effect1 = class extends Effect {
284
+ create(x, y, color) {
285
+ return {
286
+ x,
287
+ y: y + 10,
288
+ vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
289
+ vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
290
+ size: random(this._options.particleSize.min, this._options.particleSize.max),
291
+ color,
292
+ alpha: 1
293
+ };
294
+ }
295
+ update(ctx, particle) {
296
+ particle.vy += this._options.particleGravity;
297
+ particle.x += particle.vx;
298
+ particle.y += particle.vy;
299
+ particle.alpha *= this._options.particleAlphaFadeout;
300
+ ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
301
+ ctx.fillRect(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, particle.size);
302
+ }
303
+ };
304
+ var Effect2 = class extends Effect {
305
+ create(x, y, color) {
306
+ return {
307
+ x,
308
+ y: y + 10,
309
+ vx: random(this._options.particleVelocityRange.x[0], this._options.particleVelocityRange.x[1]),
310
+ vy: random(this._options.particleVelocityRange.y[0], this._options.particleVelocityRange.y[1]),
311
+ size: random(this._options.particleSize.min, this._options.particleSize.max),
312
+ color,
313
+ alpha: 1,
314
+ theta: random(0, 360) * Math.PI / 180,
315
+ drag: 0.92,
316
+ wander: 0.15
317
+ };
318
+ }
319
+ update(ctx, particle) {
320
+ particle.vy += this._options.particleGravity;
321
+ particle.x += particle.vx;
322
+ particle.y += particle.vy;
323
+ particle.vx *= particle.drag;
324
+ particle.vy *= particle.drag;
325
+ particle.theta += random(-0.5, 0.5);
326
+ particle.vx += Math.sin(particle.theta) * 0.1;
327
+ particle.vy += Math.cos(particle.theta) * 0.1;
328
+ particle.size *= this._options.particleShrinkRate;
329
+ particle.alpha *= this._options.particleAlphaFadeout;
330
+ ctx.fillStyle = `rgba(${particle.color[0]},${particle.color[1]},${particle.color[2]},${particle.alpha})`;
331
+ ctx.beginPath();
332
+ ctx.arc(Math.round(particle.x - 1), Math.round(particle.y - 1), particle.size, 0, 2 * Math.PI);
333
+ ctx.fill();
334
+ }
335
+ };
336
+ function throttle(callback, limit) {
337
+ let wait = false;
338
+ return function(...args) {
339
+ if (!wait) {
340
+ callback.apply(this, args);
341
+ wait = true;
342
+ setTimeout(() => {
343
+ wait = false;
344
+ }, limit);
345
+ }
346
+ };
347
+ }
348
+ var getRGBComponents = (node, color) => {
349
+ if (typeof color === "function") {
350
+ return color();
351
+ }
352
+ const bgColor = getComputedStyle(node).color;
353
+ if (bgColor) {
354
+ const x = bgColor.match(/(\d+), (\d+), (\d+)/)?.slice(1);
355
+ if (x) {
356
+ return x;
357
+ }
358
+ }
359
+ return [
360
+ 50,
361
+ 50,
362
+ 50
363
+ ];
364
+ };
365
+ var random = (min, max) => {
366
+ if (!max) {
367
+ max = min;
368
+ min = 0;
369
+ }
370
+ return min + ~~(Math.random() * (max - min + 1));
371
+ };
372
+
57
373
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/demo.ts
58
- import { keymap as keymap2 } from "@codemirror/view";
374
+ import { keymap as keymap3 } from "@codemirror/view";
59
375
  var defaultItems = [
60
376
  "hello world!",
61
377
  "this is a test.",
@@ -65,7 +381,7 @@ var demo = ({ delay = 75, items = defaultItems } = {}) => {
65
381
  let t;
66
382
  let idx = 0;
67
383
  return [
68
- keymap2.of([
384
+ keymap3.of([
69
385
  {
70
386
  // Reset.
71
387
  key: "alt-meta-'",
@@ -112,17 +428,17 @@ var demo = ({ delay = 75, items = defaultItems } = {}) => {
112
428
  };
113
429
 
114
430
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts
115
- import { keymap as keymap3, Decoration, EditorView as EditorView2, MatchDecorator, ViewPlugin, WidgetType } from "@codemirror/view";
431
+ import { keymap as keymap4, Decoration, EditorView as EditorView3, MatchDecorator, ViewPlugin, WidgetType } from "@codemirror/view";
116
432
  import { debounce } from "@dxos/async";
117
- import { invariant } from "@dxos/invariant";
118
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
433
+ import { invariant as invariant2 } from "@dxos/invariant";
434
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/extensions/comments.ts";
119
435
  var BookmarkWidget = class extends WidgetType {
120
436
  constructor(_pos, _id) {
121
437
  super();
122
438
  this._pos = _pos;
123
439
  this._id = _id;
124
- invariant(this._id, void 0, {
125
- F: __dxlog_file,
440
+ invariant2(this._id, void 0, {
441
+ F: __dxlog_file2,
126
442
  L: 41,
127
443
  S: this,
128
444
  A: [
@@ -141,7 +457,7 @@ var BookmarkWidget = class extends WidgetType {
141
457
  return span;
142
458
  }
143
459
  };
144
- var styles = EditorView2.baseTheme({
460
+ var styles = EditorView3.baseTheme({
145
461
  "& .cm-bookmark": {
146
462
  cursor: "pointer",
147
463
  margin: "4px",
@@ -168,12 +484,12 @@ var comments = (options = {}) => {
168
484
  constructor(view) {
169
485
  this.bookmarks = bookmarkMatcher.createDeco(view);
170
486
  }
171
- update(update2) {
172
- this.bookmarks = bookmarkMatcher.updateDeco(update2, this.bookmarks);
487
+ update(update4) {
488
+ this.bookmarks = bookmarkMatcher.updateDeco(update4, this.bookmarks);
173
489
  }
174
490
  }, {
175
491
  decorations: (instance) => instance.bookmarks,
176
- provide: (plugin) => EditorView2.atomicRanges.of((view) => {
492
+ provide: (plugin) => EditorView3.atomicRanges.of((view) => {
177
493
  return view.plugin(plugin)?.bookmarks || Decoration.none;
178
494
  })
179
495
  });
@@ -181,7 +497,7 @@ var comments = (options = {}) => {
181
497
  options.onUpdate?.(data);
182
498
  }, 200);
183
499
  return [
184
- keymap3.of([
500
+ keymap4.of([
185
501
  {
186
502
  key: options?.key ?? "shift-meta-c",
187
503
  run: (view) => {
@@ -206,12 +522,12 @@ var comments = (options = {}) => {
206
522
  ]),
207
523
  bookmarks,
208
524
  // Monitor cursor movement.
209
- EditorView2.updateListener.of((update2) => {
525
+ EditorView3.updateListener.of((update4) => {
210
526
  active = void 0;
211
527
  if (!options.onUpdate) {
212
528
  return;
213
529
  }
214
- const view = update2.view;
530
+ const view = update4.view;
215
531
  const pos = view.state.selection.main.head;
216
532
  const decorations = [];
217
533
  const rangeSet = view.plugin(bookmarks)?.bookmarks;
@@ -247,11 +563,62 @@ var comments = (options = {}) => {
247
563
  ];
248
564
  };
249
565
 
250
- // packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
566
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/image.ts
251
567
  import { syntaxTree } from "@codemirror/language";
252
- import { RangeSetBuilder, StateField } from "@codemirror/state";
253
- import { Decoration as Decoration2, EditorView as EditorView3, WidgetType as WidgetType2 } from "@codemirror/view";
254
- var LinkButton = class extends WidgetType2 {
568
+ import { RangeSetBuilder, StateField as StateField2 } from "@codemirror/state";
569
+ import { Decoration as Decoration2, EditorView as EditorView4, WidgetType as WidgetType2 } from "@codemirror/view";
570
+ var image = (options = {}) => {
571
+ return StateField2.define({
572
+ create: (state) => update(state, options),
573
+ update: (_, tr) => update(tr.state, options),
574
+ provide: (field) => EditorView4.decorations.from(field)
575
+ });
576
+ };
577
+ var update = (state, options) => {
578
+ const builder = new RangeSetBuilder();
579
+ syntaxTree(state).iterate({
580
+ enter: (node) => {
581
+ if (node.name === "Image") {
582
+ const urlNode = node.node.getChild("URL");
583
+ if (urlNode) {
584
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
585
+ builder.add(state.readOnly ? node.from : node.to, node.to, Decoration2.widget({
586
+ widget: new ImageWidget(url)
587
+ }));
588
+ }
589
+ }
590
+ }
591
+ });
592
+ return builder.finish();
593
+ };
594
+ var ImageWidget = class extends WidgetType2 {
595
+ constructor(_url) {
596
+ super();
597
+ this._url = _url;
598
+ }
599
+ eq(other) {
600
+ return this._url === other?._url;
601
+ }
602
+ toDOM(view) {
603
+ const img = document.createElement("img");
604
+ img.setAttribute("src", this._url);
605
+ img.setAttribute("class", "cm-image");
606
+ return img;
607
+ }
608
+ };
609
+
610
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/link.ts
611
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
612
+ import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField3 } from "@codemirror/state";
613
+ import { Decoration as Decoration3, EditorView as EditorView5, WidgetType as WidgetType3 } from "@codemirror/view";
614
+ var link = (options = {}) => {
615
+ return StateField3.define({
616
+ create: (state) => update2(state, options),
617
+ update: (_, tr) => update2(tr.state, options),
618
+ provide: (field) => EditorView5.decorations.from(field)
619
+ });
620
+ };
621
+ var LinkButton = class extends WidgetType3 {
255
622
  constructor(_pos, _url, _onAttach) {
256
623
  super();
257
624
  this._pos = _pos;
@@ -267,7 +634,7 @@ var LinkButton = class extends WidgetType2 {
267
634
  return el;
268
635
  }
269
636
  };
270
- var LinkText = class extends WidgetType2 {
637
+ var LinkText = class extends WidgetType3 {
271
638
  constructor(_pos, _text, _url) {
272
639
  super();
273
640
  this._pos = _pos;
@@ -297,10 +664,10 @@ var LinkText = class extends WidgetType2 {
297
664
  return link2;
298
665
  }
299
666
  };
300
- var update = (state, options) => {
301
- const builder = new RangeSetBuilder();
667
+ var update2 = (state, options) => {
668
+ const builder = new RangeSetBuilder2();
302
669
  const cursor = state.selection.main.head;
303
- syntaxTree(state).iterate({
670
+ syntaxTree2(state).iterate({
304
671
  enter: (node) => {
305
672
  if (node.name === "Link") {
306
673
  const marks = node.node.getChildren("LinkMark");
@@ -311,12 +678,12 @@ var update = (state, options) => {
311
678
  return false;
312
679
  }
313
680
  if (cursor < node.from || cursor > node.to) {
314
- builder.add(node.from, node.to, Decoration2.replace({
681
+ builder.add(node.from, node.to, Decoration3.replace({
315
682
  widget: new LinkText(node.from, text, options.link ? url : void 0)
316
683
  }));
317
684
  }
318
685
  if (options.onRender) {
319
- builder.add(node.to, node.to, Decoration2.replace({
686
+ builder.add(node.to, node.to, Decoration3.replace({
320
687
  widget: new LinkButton(node.from, url, options.onRender)
321
688
  }));
322
689
  }
@@ -326,52 +693,70 @@ var update = (state, options) => {
326
693
  });
327
694
  return builder.finish();
328
695
  };
329
- var link = (options = {}) => {
330
- return StateField.define({
331
- create: (state) => update(state, options),
332
- update: (_, tr) => update(tr.state, options),
333
- provide: (field) => EditorView3.decorations.from(field)
334
- });
335
- };
336
696
 
337
697
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/listener.ts
338
- import { StateField as StateField2 } from "@codemirror/state";
339
- var listener = ({ onChange }) => StateField2.define({
340
- create: () => null,
341
- update: (_value, transaction) => {
342
- if (transaction.docChanged && onChange) {
343
- onChange(transaction.newDoc.toString());
698
+ import { StateField as StateField4 } from "@codemirror/state";
699
+ var listener = ({ onChange }) => {
700
+ return StateField4.define({
701
+ create: () => null,
702
+ update: (_value, transaction) => {
703
+ if (transaction.docChanged && onChange) {
704
+ onChange(transaction.newDoc.toString());
705
+ }
706
+ return null;
344
707
  }
345
- return null;
346
- }
347
- });
708
+ });
709
+ };
348
710
 
349
711
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
350
712
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
351
- import { defaultKeymap, history, indentWithTab } from "@codemirror/commands";
713
+ import { defaultKeymap, history, historyKeymap, indentWithTab } from "@codemirror/commands";
352
714
  import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
353
715
  import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
354
716
  import { languages } from "@codemirror/language-data";
355
717
  import { highlightSelectionMatches, searchKeymap } from "@codemirror/search";
356
718
  import { EditorState } from "@codemirror/state";
357
719
  import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
358
- import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView4, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap4, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
720
+ import { crosshairCursor, drawSelection, dropCursor, EditorView as EditorView6, highlightActiveLine, highlightActiveLineGutter, highlightSpecialChars, keymap as keymap5, placeholder as placeholder2, rectangularSelection } from "@codemirror/view";
359
721
 
360
722
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/highlight.ts
361
723
  import { markdownLanguage } from "@codemirror/lang-markdown";
362
724
  import { HighlightStyle } from "@codemirror/language";
363
725
  import { tags, styleTags, Tag } from "@lezer/highlight";
364
726
  import get from "lodash.get";
727
+ import { mx as mx2 } from "@dxos/react-ui-theme";
365
728
 
366
729
  // packages/ui/react-ui-editor/src/styles/markdown.ts
367
730
  import { mx } from "@dxos/react-ui-theme";
368
- var heading = {
369
- 1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
370
- 2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
371
- 3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
372
- 4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
373
- 5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
374
- 6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
731
+ var headings = {
732
+ 1: [
733
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
734
+ "-ml-1.5"
735
+ ],
736
+ 2: [
737
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
738
+ "-ml-1.5"
739
+ ],
740
+ 3: [
741
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
742
+ "-ml-1.5"
743
+ ],
744
+ 4: [
745
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
746
+ "-ml-[5px]"
747
+ ],
748
+ 5: [
749
+ "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
750
+ "-ml-[5px]"
751
+ ],
752
+ 6: [
753
+ "mbs-4 mbe-2 font-medium text-inherit no-underline",
754
+ "-ml-[4px]"
755
+ ]
756
+ };
757
+ var heading = (level, readonly) => {
758
+ const [style, offset] = headings[level];
759
+ return mx(style, readonly && offset);
375
760
  };
376
761
  var light = "text-neutral-200 dark:text-neutral-800";
377
762
  var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
@@ -382,7 +767,7 @@ var code = "font-mono !no-underline text-neutral-700 dark:text-neutral-300";
382
767
  var codeMark = "font-mono text-primary-500";
383
768
  var inlineUrl = mx(code, "px-1");
384
769
  var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
385
- var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-500/50";
770
+ var horizontalRule = "flex mlb-4 border-b text-neutral-100 dark:text-neutral-900 border-neutral-200 dark:border-neutral-800";
386
771
 
387
772
  // packages/ui/react-ui-editor/src/styles/tokens.ts
388
773
  import { tailwindConfig } from "@dxos/react-ui-theme";
@@ -408,7 +793,7 @@ var markdownTagsExtension = {
408
793
  styleTags(markdownTags)
409
794
  ]
410
795
  };
411
- var markdownHighlightStyle = HighlightStyle.define([
796
+ var markdownHighlightStyle = (readonly) => HighlightStyle.define([
412
797
  {
413
798
  tag: [
414
799
  tags.keyword,
@@ -452,40 +837,54 @@ var markdownHighlightStyle = HighlightStyle.define([
452
837
  tag: [
453
838
  tags.meta,
454
839
  tags.processingInstruction,
455
- markdownTags.CodeMark,
456
- markdownTags.EmphasisMark,
457
- markdownTags.HeaderMark,
458
840
  markdownTags.LinkLabel,
459
841
  markdownTags.LinkReference,
460
- markdownTags.ListMark,
461
- markdownTags.QuoteMark
842
+ markdownTags.ListMark
462
843
  ],
463
844
  class: mark
464
845
  },
846
+ // Markdown marks.
847
+ {
848
+ tag: [
849
+ markdownTags.CodeMark,
850
+ markdownTags.HeaderMark,
851
+ markdownTags.QuoteMark,
852
+ markdownTags.EmphasisMark
853
+ ],
854
+ class: readonly ? "hidden" : mark
855
+ },
856
+ // E.g., code block language (after ```).
857
+ {
858
+ tag: [
859
+ tags.function(tags.variableName),
860
+ tags.labelName
861
+ ],
862
+ class: readonly ? "hidden" : codeMark
863
+ },
465
864
  // Headings.
466
865
  {
467
866
  tag: tags.heading1,
468
- class: heading[1]
867
+ class: heading(1, readonly)
469
868
  },
470
869
  {
471
870
  tag: tags.heading2,
472
- class: heading[2]
871
+ class: heading(2, readonly)
473
872
  },
474
873
  {
475
874
  tag: tags.heading3,
476
- class: heading[3]
875
+ class: heading(3, readonly)
477
876
  },
478
877
  {
479
878
  tag: tags.heading4,
480
- class: heading[4]
879
+ class: heading(4, readonly)
481
880
  },
482
881
  {
483
882
  tag: tags.heading5,
484
- class: heading[5]
883
+ class: heading(5, readonly)
485
884
  },
486
885
  {
487
886
  tag: tags.heading6,
488
- class: heading[6]
887
+ class: heading(6, readonly)
489
888
  },
490
889
  // Emphasis.
491
890
  {
@@ -507,14 +906,6 @@ var markdownHighlightStyle = HighlightStyle.define([
507
906
  ],
508
907
  class: inlineUrl
509
908
  },
510
- // E.g., code block language (after ```).
511
- {
512
- tag: [
513
- tags.function(tags.variableName),
514
- tags.labelName
515
- ],
516
- class: codeMark
517
- },
518
909
  // NOTE: The `markdown` extension configures extensions for `lezer` to parse markdown tokens (incl. below).
519
910
  // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
520
911
  // when a language is specified. In this case, the syntax highlighting extensions will colorize
@@ -537,7 +928,7 @@ var markdownHighlightStyle = HighlightStyle.define([
537
928
  tag: [
538
929
  markdownTags.HorizontalRule
539
930
  ],
540
- class: horizontalRule
931
+ class: mx2(horizontalRule, readonly && "-indent-[100rem]")
541
932
  }
542
933
  ], {
543
934
  scope: markdownLanguage,
@@ -547,13 +938,13 @@ var markdownHighlightStyle = HighlightStyle.define([
547
938
  });
548
939
 
549
940
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/markdown/bundle.ts
550
- var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
941
+ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
551
942
  return [
552
943
  bracketMatching2(),
553
944
  closeBrackets2(),
554
945
  _placeholder && placeholder2(_placeholder),
555
946
  EditorState.allowMultipleSelections.of(true),
556
- EditorView4.lineWrapping,
947
+ EditorView6.lineWrapping,
557
948
  crosshairCursor(),
558
949
  dropCursor(),
559
950
  drawSelection(),
@@ -564,14 +955,17 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
564
955
  history(),
565
956
  indentOnInput(),
566
957
  rectangularSelection(),
567
- // TODO(burdon): Review.
568
- keymap4.of([
569
- ...closeBracketsKeymap,
958
+ // https://codemirror.net/docs/ref/#view.keymap
959
+ keymap5.of([
960
+ // https://codemirror.net/docs/ref/#commands.defaultKeymap
570
961
  ...defaultKeymap,
571
- // ...foldKeymap,
572
- // ...historyKeymap,
573
- // ...lintKeymap,
962
+ // https://codemirror.net/docs/ref/#commands.historyKeymap
963
+ ...historyKeymap,
964
+ // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
965
+ ...closeBracketsKeymap,
966
+ // https://codemirror.net/docs/ref/#search.searchKeymap
574
967
  ...searchKeymap,
968
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
575
969
  indentWithTab
576
970
  ]),
577
971
  // Main extension.
@@ -592,16 +986,132 @@ var markdownBundle = ({ themeMode, placeholder: _placeholder }) => {
592
986
  markdownTagsExtension
593
987
  ]
594
988
  }),
989
+ // https://github.com/codemirror/theme-one-dark
990
+ themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
595
991
  // Custom styles.
596
- syntaxHighlighting2(markdownHighlightStyle),
597
- // TODO(thure): All but one rule here apply to both themes; rename or refactor.
598
- themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2)
992
+ syntaxHighlighting2(markdownHighlightStyle(readonly))
599
993
  ].filter(Boolean);
600
994
  };
601
995
 
996
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/mention.ts
997
+ import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
998
+ var mention = ({ onSearch }) => {
999
+ return autocompletion2({
1000
+ closeOnBlur: false,
1001
+ override: [
1002
+ (context) => {
1003
+ const match = context.matchBefore(/@(\w+)?/);
1004
+ if (!match || match.from === match.to && !context.explicit) {
1005
+ return null;
1006
+ }
1007
+ console.log(match);
1008
+ return {
1009
+ from: match.from,
1010
+ options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
1011
+ label: `@${value}`
1012
+ }))
1013
+ };
1014
+ }
1015
+ ]
1016
+ });
1017
+ };
1018
+
1019
+ // packages/ui/react-ui-editor/src/components/TextEditor/extensions/table.ts
1020
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1021
+ import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
1022
+ import { Decoration as Decoration4, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
1023
+ var table = (options = {}) => {
1024
+ return StateField5.define({
1025
+ create: (state) => update3(state, options),
1026
+ update: (_, tr) => update3(tr.state, options),
1027
+ provide: (field) => EditorView7.decorations.from(field)
1028
+ });
1029
+ };
1030
+ var update3 = (state, options) => {
1031
+ const builder = new RangeSetBuilder3();
1032
+ if (state.readOnly) {
1033
+ const tables = [];
1034
+ const getTable = () => tables[tables.length - 1];
1035
+ const getRow = () => {
1036
+ const table2 = getTable();
1037
+ return table2.rows?.[table2.rows.length - 1];
1038
+ };
1039
+ syntaxTree3(state).iterate({
1040
+ enter: (node) => {
1041
+ switch (node.name) {
1042
+ case "Table": {
1043
+ tables.push({
1044
+ from: node.from
1045
+ });
1046
+ break;
1047
+ }
1048
+ case "TableHeader": {
1049
+ getTable().header = [];
1050
+ break;
1051
+ }
1052
+ case "TableRow": {
1053
+ (getTable().rows ??= []).push([]);
1054
+ break;
1055
+ }
1056
+ case "TableCell": {
1057
+ const row = getRow();
1058
+ if (row) {
1059
+ row.push(state.sliceDoc(node.from, node.to));
1060
+ } else {
1061
+ getTable().header?.push(state.sliceDoc(node.from, node.to));
1062
+ }
1063
+ break;
1064
+ }
1065
+ case "TableDelimiter": {
1066
+ getTable().to = node.to;
1067
+ break;
1068
+ }
1069
+ }
1070
+ }
1071
+ });
1072
+ tables.forEach((table2) => builder.add(table2.from, table2.to, Decoration4.replace({
1073
+ widget: new TableWidget(table2)
1074
+ })));
1075
+ }
1076
+ return builder.finish();
1077
+ };
1078
+ var TableWidget = class extends WidgetType4 {
1079
+ constructor(_table) {
1080
+ super();
1081
+ this._table = _table;
1082
+ }
1083
+ eq(other) {
1084
+ return this._table.from === other?._table?.from;
1085
+ }
1086
+ toDOM(view) {
1087
+ const table2 = document.createElement("table");
1088
+ {
1089
+ const header = table2.appendChild(document.createElement("thead"));
1090
+ const row = header.appendChild(document.createElement("tr"));
1091
+ this._table.header?.forEach((cell) => {
1092
+ const th = document.createElement("th");
1093
+ th.setAttribute("class", "cm-table-head");
1094
+ row.appendChild(th).textContent = cell;
1095
+ });
1096
+ }
1097
+ {
1098
+ const body = table2.appendChild(document.createElement("tbody"));
1099
+ this._table.rows?.forEach((row) => {
1100
+ const tr = body.appendChild(document.createElement("tr"));
1101
+ row.forEach((cell) => {
1102
+ const td = document.createElement("td");
1103
+ td.setAttribute("class", "cm-table-cell");
1104
+ tr.appendChild(td).textContent = cell;
1105
+ });
1106
+ });
1107
+ }
1108
+ return table2;
1109
+ }
1110
+ };
1111
+
602
1112
  // packages/ui/react-ui-editor/src/components/TextEditor/extensions/tasklist.ts
603
- import { EditorView as EditorView5, Decoration as Decoration3, WidgetType as WidgetType3, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
604
- var CheckboxWidget = class extends WidgetType3 {
1113
+ import { EditorView as EditorView8, Decoration as Decoration5, WidgetType as WidgetType5, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin2 } from "@codemirror/view";
1114
+ var CheckboxWidget = class extends WidgetType5 {
605
1115
  constructor(_pos, _checked, _indent, _onCheck) {
606
1116
  super();
607
1117
  this._pos = _pos;
@@ -620,30 +1130,35 @@ var CheckboxWidget = class extends WidgetType3 {
620
1130
  const input = wrap.appendChild(document.createElement("input"));
621
1131
  input.type = "checkbox";
622
1132
  input.checked = this._checked;
623
- input.onchange = (event) => {
624
- this._onCheck(event.target.checked);
625
- return true;
626
- };
1133
+ if (!this._onCheck) {
1134
+ input.setAttribute("disabled", "true");
1135
+ }
1136
+ if (this._onCheck) {
1137
+ input.onchange = (event) => {
1138
+ this._onCheck?.(event.target.checked);
1139
+ return true;
1140
+ };
1141
+ }
627
1142
  return wrap;
628
1143
  }
629
1144
  ignoreEvent() {
630
1145
  return false;
631
1146
  }
632
1147
  };
633
- var styles2 = EditorView5.baseTheme({
1148
+ var styles2 = EditorView8.baseTheme({
634
1149
  "& .cm-task-item": {
635
1150
  paddingLeft: "4px",
636
1151
  paddingRight: "8px"
637
1152
  }
638
1153
  });
639
- var tasklist = () => {
1154
+ var tasklist = (options = {}) => {
640
1155
  const taskMatcher = new MatchDecorator2({
641
1156
  regexp: /^(\s*)- \[([ xX])\]\s/g,
642
1157
  decoration: (match, view, pos) => {
643
1158
  const indent = Math.floor(match[1].length / 2);
644
1159
  const checked = match[2] === "x" || match[2] === "X";
645
- return Decoration3.replace({
646
- widget: new CheckboxWidget(pos, checked, indent, (checked2) => {
1160
+ return Decoration5.replace({
1161
+ widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
647
1162
  const idx = pos + match[0].indexOf("[") + 1;
648
1163
  view.dispatch({
649
1164
  changes: {
@@ -664,13 +1179,13 @@ var tasklist = () => {
664
1179
  constructor(view) {
665
1180
  this.tasks = taskMatcher.createDeco(view);
666
1181
  }
667
- update(update2) {
668
- this.tasks = taskMatcher.updateDeco(update2, this.tasks);
1182
+ update(update4) {
1183
+ this.tasks = taskMatcher.updateDeco(update4, this.tasks);
669
1184
  }
670
1185
  }, {
671
1186
  decorations: (instance) => instance.tasks,
672
- provide: (plugin) => EditorView5.atomicRanges.of((view) => {
673
- return view.plugin(plugin)?.tasks || Decoration3.none;
1187
+ provide: (plugin) => EditorView8.atomicRanges.of((view) => {
1188
+ return view.plugin(plugin)?.tasks || Decoration5.none;
674
1189
  })
675
1190
  });
676
1191
  return [
@@ -837,8 +1352,51 @@ var defaultTheme = {
837
1352
  "& .cm-tooltip": {
838
1353
  border: "none"
839
1354
  },
840
- // '& .cm-tooltip-below': {},
841
- // '& .cm-tooltip-autocomplete': {},
1355
+ "& .cm-tooltip-below": {},
1356
+ //
1357
+ // autocomplete
1358
+ //
1359
+ "& .cm-tooltip-autocomplete": {
1360
+ marginTop: "4px",
1361
+ marginLeft: "-3px"
1362
+ },
1363
+ "& .cm-tooltip-autocomplete ul li": {},
1364
+ "& .cm-tooltip-autocomplete ul li[aria-selected]": {},
1365
+ "& .cm-completionIcon": {
1366
+ display: "none"
1367
+ },
1368
+ "& .cm-completionLabel": {
1369
+ fontFamily: get2(tokens, "fontFamily.body", []).join(",")
1370
+ },
1371
+ "& .cm-completionMatchedText": {
1372
+ textDecoration: "none"
1373
+ },
1374
+ //
1375
+ // widgets
1376
+ //
1377
+ "& .cm-widgetBuffer": {
1378
+ display: "none",
1379
+ height: 0
1380
+ },
1381
+ //
1382
+ // table
1383
+ //
1384
+ "& .cm-table-head": {
1385
+ padding: "2px 16px 2px 0px",
1386
+ borderBottom: `1px solid ${get2(tokens, "extend.colors.neutral.500")}`,
1387
+ fontWeight: 100,
1388
+ textAlign: "left",
1389
+ color: get2(tokens, "extend.colors.neutral.500")
1390
+ },
1391
+ "& .cm-table-cell": {
1392
+ padding: "2px 16px 2px 0px"
1393
+ },
1394
+ //
1395
+ // image
1396
+ //
1397
+ "& .cm-image": {
1398
+ margin: "0.5rem 0"
1399
+ },
842
1400
  //
843
1401
  // font size
844
1402
  // 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.
@@ -888,19 +1446,19 @@ var codeTheme = {
888
1446
 
889
1447
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
890
1448
  import { EditorState as EditorState2 } from "@codemirror/state";
891
- import { EditorView as EditorView6 } from "@codemirror/view";
1449
+ import { EditorView as EditorView9 } from "@codemirror/view";
892
1450
  import { useFocusableGroup } from "@fluentui/react-tabster";
893
1451
  import { vim } from "@replit/codemirror-vim";
894
- import defaultsDeep from "lodash.defaultsdeep";
1452
+ import defaultsDeep2 from "lodash.defaultsdeep";
895
1453
  import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
896
1454
  import { generateName } from "@dxos/display-name";
897
1455
  import { useThemeContext } from "@dxos/react-ui";
898
- import { getColorForValue, inputSurface, mx as mx2 } from "@dxos/react-ui-theme";
1456
+ import { getColorForValue, inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
899
1457
  var EditorModes = [
900
1458
  "default",
901
1459
  "vim"
902
1460
  ];
903
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots = defaultSlots, editorMode }, forwardedRef) => {
1461
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, editorMode, extensions = [], slots = defaultSlots }, forwardedRef) => {
904
1462
  const { themeMode } = useThemeContext();
905
1463
  const tabsterDOMAttribute = useFocusableGroup({
906
1464
  tabBehavior: "limited"
@@ -945,13 +1503,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
945
1503
  const state2 = EditorState2.create({
946
1504
  doc: model.text(),
947
1505
  extensions: [
1506
+ readonly && EditorState2.readOnly.of(readonly),
948
1507
  // TODO(burdon): Factor out VIM mode?
949
1508
  editorMode === "vim" && vim(),
950
1509
  // Theme.
951
- EditorView6.baseTheme(defaultTheme),
952
- EditorView6.theme(slots?.editor?.theme ?? {}),
1510
+ EditorView9.baseTheme(defaultTheme),
1511
+ EditorView9.theme(slots?.editor?.theme ?? {}),
953
1512
  // TODO(burdon): themeMode doesn't change in storybooks.
954
- EditorView6.darkTheme.of(themeMode === "dark"),
1513
+ EditorView9.darkTheme.of(themeMode === "dark"),
955
1514
  // Storage and replication.
956
1515
  model.extension,
957
1516
  // Custom.
@@ -959,7 +1518,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
959
1518
  ].filter(Boolean)
960
1519
  });
961
1520
  view?.destroy();
962
- setView(new EditorView6({
1521
+ setView(new EditorView9({
963
1522
  state: state2,
964
1523
  parent: root
965
1524
  }));
@@ -973,6 +1532,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, extensions = [], slots
973
1532
  root,
974
1533
  model,
975
1534
  themeMode,
1535
+ readonly,
976
1536
  editorMode
977
1537
  ]);
978
1538
  const handleKeyUp = useCallback((event) => {
@@ -1009,13 +1569,15 @@ var maybeDebug = () => {
1009
1569
  }
1010
1570
  return [];
1011
1571
  };
1012
- var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
1572
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
1013
1573
  const { themeMode } = useThemeContext();
1014
- const slots = defaultsDeep({}, _slots, defaultTextSlots);
1574
+ const slots = defaultsDeep2({}, _slots, defaultTextSlots);
1015
1575
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
1016
1576
  ref: forwardedRef,
1577
+ readonly,
1017
1578
  extensions: [
1018
1579
  basicBundle({
1580
+ readonly,
1019
1581
  themeMode,
1020
1582
  placeholder: slots?.editor?.placeholder
1021
1583
  }),
@@ -1026,13 +1588,15 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, .
1026
1588
  ...props
1027
1589
  });
1028
1590
  });
1029
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slots, ...props }, forwardedRef) => {
1591
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
1030
1592
  const { themeMode } = useThemeContext();
1031
- const slots = defaultsDeep({}, _slots, defaultMarkdownSlots);
1593
+ const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
1032
1594
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
1033
1595
  ref: forwardedRef,
1596
+ readonly,
1034
1597
  extensions: [
1035
1598
  markdownBundle({
1599
+ readonly,
1036
1600
  themeMode,
1037
1601
  placeholder: slots?.editor?.placeholder
1038
1602
  }),
@@ -1045,7 +1609,7 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ extensions = [], slots: _slot
1045
1609
  });
1046
1610
  var defaultSlots = {
1047
1611
  root: {
1048
- className: mx2("p-2", inputSurface)
1612
+ className: mx3("p-2", inputSurface)
1049
1613
  }
1050
1614
  };
1051
1615
  var defaultTextSlots = {
@@ -1065,20 +1629,20 @@ var defaultMarkdownSlots = {
1065
1629
  import get3 from "lodash.get";
1066
1630
  import { useEffect as useEffect2, useState as useState2 } from "react";
1067
1631
  import { yCollab } from "y-codemirror.next";
1068
- import { invariant as invariant2 } from "@dxos/invariant";
1632
+ import { invariant as invariant3 } from "@dxos/invariant";
1069
1633
  import { getRawDoc, isActualAutomergeObject } from "@dxos/react-client/echo";
1070
1634
 
1071
1635
  // packages/ui/react-ui-editor/src/hooks/automerge/plugin.ts
1072
- import { Annotation, Facet, StateEffect, StateField as StateField3 } from "@codemirror/state";
1636
+ import { Annotation, Facet, StateEffect, StateField as StateField6 } from "@codemirror/state";
1073
1637
  import { ViewPlugin as ViewPlugin3 } from "@codemirror/view";
1074
1638
  import * as automerge2 from "@dxos/automerge/automerge";
1075
1639
 
1076
1640
  // packages/ui/react-ui-editor/src/hooks/automerge/PatchSemaphore.ts
1077
1641
  import { next as automerge } from "@dxos/automerge/automerge";
1078
1642
 
1079
- // packages/ui/react-ui-editor/src/hooks/automerge/amToCodemirror.ts
1643
+ // packages/ui/react-ui-editor/src/hooks/automerge/translation/automerge-to-codemirror.ts
1080
1644
  import { ChangeSet } from "@codemirror/state";
1081
- var amToCodemirror_default = (view, selection, target, patches) => {
1645
+ var automergeToCodemirror = (view, selection, target, patches) => {
1082
1646
  for (const patch of patches) {
1083
1647
  const changeSpec = handlePatch(patch, target, view.state);
1084
1648
  if (changeSpec != null) {
@@ -1183,9 +1747,9 @@ var charPath = (textPath, candidatePath) => {
1183
1747
  return null;
1184
1748
  };
1185
1749
 
1186
- // packages/ui/react-ui-editor/src/hooks/automerge/codeMirrorToAm.ts
1750
+ // packages/ui/react-ui-editor/src/hooks/automerge/translation/codemirror-to-automerge.ts
1187
1751
  import { next as am } from "@dxos/automerge/automerge";
1188
- var codeMirrorToAm_default = (field, handle, transactions, state) => {
1752
+ var codemirrorToAutomerge = (field, handle, transactions, state) => {
1189
1753
  const { lastHeads, path } = state.field(field);
1190
1754
  let hasChanges = false;
1191
1755
  for (const tr of transactions) {
@@ -1229,12 +1793,12 @@ var PatchSemaphore = class {
1229
1793
  annotations: reconcileAnnotationType.of(true)
1230
1794
  });
1231
1795
  }
1232
- let newHeads = codeMirrorToAm_default(this._field, handle, transactions, view.state);
1796
+ let newHeads = codemirrorToAutomerge(this._field, handle, transactions, view.state);
1233
1797
  if (newHeads === null || newHeads === void 0) {
1234
1798
  newHeads = automerge.getHeads(handle.docSync());
1235
1799
  }
1236
1800
  const diff = automerge.equals(oldHeads, newHeads) ? [] : automerge.diff(handle.docSync(), oldHeads, newHeads);
1237
- amToCodemirror_default(view, selection, path, diff);
1801
+ automergeToCodemirror(view, selection, path, diff);
1238
1802
  view.dispatch({
1239
1803
  effects: updateHeads(newHeads),
1240
1804
  annotations: reconcileAnnotationType.of({})
@@ -1258,7 +1822,7 @@ var semaphoreFacet = Facet.define({
1258
1822
  combine: (values) => values.at(-1)
1259
1823
  });
1260
1824
  var automergePlugin = (handle, path) => {
1261
- const stateField = StateField3.define({
1825
+ const stateField = StateField6.define({
1262
1826
  create: () => ({
1263
1827
  lastHeads: automerge2.getHeads(handle.docSync()),
1264
1828
  unreconciledTransactions: [],
@@ -1296,8 +1860,8 @@ var automergePlugin = (handle, path) => {
1296
1860
  this._view = view;
1297
1861
  handle.addListener("change", this._handleChange);
1298
1862
  }
1299
- update(update2) {
1300
- if (update2.transactions.length > 0 && update2.transactions.some((t) => !isReconcileTx(t))) {
1863
+ update(update4) {
1864
+ if (update4.transactions.length > 0 && update4.transactions.some((t) => !isReconcileTx(t))) {
1301
1865
  queueMicrotask(() => {
1302
1866
  this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
1303
1867
  });
@@ -1319,7 +1883,7 @@ var reconcileAnnotationType = Annotation.define();
1319
1883
  var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
1320
1884
 
1321
1885
  // packages/ui/react-ui-editor/src/hooks/yjs/cursors.ts
1322
- import * as random from "lib0/random";
1886
+ import * as random2 from "lib0/random";
1323
1887
  var cursorColors = [
1324
1888
  {
1325
1889
  color: "#30bced",
@@ -1354,7 +1918,7 @@ var cursorColors = [
1354
1918
  light: "#1be7ff33"
1355
1919
  }
1356
1920
  ];
1357
- var cursorColor = cursorColors[random.uint32() % cursorColors.length];
1921
+ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
1358
1922
 
1359
1923
  // packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts
1360
1924
  import * as decoding from "lib0/decoding";
@@ -1362,7 +1926,7 @@ import * as encoding from "lib0/encoding";
1362
1926
  import { Observable } from "lib0/observable";
1363
1927
  import * as awarenessProtocol from "y-protocols/awareness";
1364
1928
  import { log } from "@dxos/log";
1365
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
1929
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs/space-provider.ts";
1366
1930
  var messageAwareness = 1;
1367
1931
  var messageQueryAwareness = 3;
1368
1932
  var SpaceAwarenessProvider = class extends Observable {
@@ -1399,7 +1963,7 @@ var SpaceAwarenessProvider = class extends Observable {
1399
1963
  removed,
1400
1964
  origin
1401
1965
  }, {
1402
- F: __dxlog_file2,
1966
+ F: __dxlog_file3,
1403
1967
  L: 67,
1404
1968
  S: this,
1405
1969
  C: (f, a) => f(...a)
@@ -1412,7 +1976,7 @@ var SpaceAwarenessProvider = class extends Observable {
1412
1976
  }
1413
1977
  _handleSpaceMessage({ payload }) {
1414
1978
  log("space message", payload, {
1415
- F: __dxlog_file2,
1979
+ F: __dxlog_file3,
1416
1980
  L: 79,
1417
1981
  S: this,
1418
1982
  C: (f, a) => f(...a)
@@ -1457,7 +2021,7 @@ var SpaceAwarenessProvider = class extends Observable {
1457
2021
  };
1458
2022
 
1459
2023
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
1460
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
2024
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
1461
2025
  var useTextModel = ({ identity, space, text }) => {
1462
2026
  const [model, setModel] = useState2(() => createModel({
1463
2027
  identity,
@@ -1489,8 +2053,8 @@ var createModel = (options) => {
1489
2053
  }
1490
2054
  };
1491
2055
  var createYjsModel = ({ identity, space, text }) => {
1492
- invariant2(text?.doc && text?.content, void 0, {
1493
- F: __dxlog_file3,
2056
+ invariant3(text?.doc && text?.content, void 0, {
2057
+ F: __dxlog_file4,
1494
2058
  L: 74,
1495
2059
  S: void 0,
1496
2060
  A: [
@@ -1543,14 +2107,17 @@ export {
1543
2107
  YXmlFragment,
1544
2108
  autocomplete,
1545
2109
  basicBundle,
2110
+ blast,
1546
2111
  codeTheme,
1547
2112
  comments,
1548
2113
  cursorColor,
1549
2114
  defaultMarkdownSlots,
2115
+ defaultOptions,
1550
2116
  defaultSlots,
1551
2117
  defaultTextSlots,
1552
2118
  defaultTheme,
1553
2119
  demo,
2120
+ image,
1554
2121
  link,
1555
2122
  listener,
1556
2123
  markdownBundle,
@@ -1558,6 +2125,8 @@ export {
1558
2125
  markdownTags,
1559
2126
  markdownTagsExtension,
1560
2127
  markdownTheme,
2128
+ mention,
2129
+ table,
1561
2130
  tags2 as tags,
1562
2131
  tasklist,
1563
2132
  textTheme,