@dxos/react-ui-editor 0.3.11-main.c01834e → 0.3.11-main.c8e9429

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 (81) hide show
  1. package/dist/lib/browser/index.mjs +347 -448
  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 +6 -2
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +12 -17
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +6 -6
  9. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
  11. package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
  12. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +1 -1
  13. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  14. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  15. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  16. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  17. package/dist/types/src/extensions/automerge/defs.d.ts +4 -4
  18. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/semaphore.d.ts +4 -9
  20. package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
  21. package/dist/types/src/extensions/code.d.ts.map +1 -1
  22. package/dist/types/src/extensions/comments.d.ts +14 -5
  23. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  24. package/dist/types/src/{util → extensions}/cursor.d.ts +9 -1
  25. package/dist/types/src/extensions/cursor.d.ts.map +1 -0
  26. package/dist/types/src/extensions/hr.d.ts.map +1 -1
  27. package/dist/types/src/extensions/index.d.ts +1 -0
  28. package/dist/types/src/extensions/index.d.ts.map +1 -1
  29. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  30. package/dist/types/src/extensions/tasklist.d.ts +5 -1
  31. package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
  32. package/dist/types/src/extensions/yjs/cursor.d.ts +1 -1
  33. package/dist/types/src/extensions/yjs/cursor.d.ts.map +1 -1
  34. package/dist/types/src/hooks/index.d.ts +1 -1
  35. package/dist/types/src/hooks/index.d.ts.map +1 -1
  36. package/dist/types/src/hooks/useTextModel.d.ts +0 -5
  37. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  38. package/dist/types/src/hooks/yjs.d.ts.map +1 -1
  39. package/dist/types/src/index.d.ts +2 -0
  40. package/dist/types/src/index.d.ts.map +1 -1
  41. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  42. package/dist/types/src/themes/default.d.ts.map +1 -1
  43. package/dist/types/src/util.d.ts.map +1 -0
  44. package/package.json +25 -24
  45. package/src/components/TextEditor/MarkdownEditor.stories.tsx +19 -16
  46. package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
  47. package/src/components/TextEditor/TextEditor.tsx +71 -67
  48. package/src/components/TextEditor/comments.stories.tsx +355 -0
  49. package/src/extensions/autocomplete.ts +18 -17
  50. package/src/extensions/automerge/automerge.ts +12 -14
  51. package/src/extensions/automerge/cursor.ts +2 -1
  52. package/src/extensions/automerge/defs.ts +13 -9
  53. package/src/extensions/automerge/semaphore.ts +10 -12
  54. package/src/extensions/awareness.ts +27 -33
  55. package/src/extensions/code.ts +24 -18
  56. package/src/extensions/comments.ts +128 -140
  57. package/src/extensions/cursor.ts +46 -0
  58. package/src/extensions/hr.ts +8 -9
  59. package/src/extensions/image.ts +2 -2
  60. package/src/extensions/index.ts +1 -0
  61. package/src/extensions/link.ts +7 -7
  62. package/src/extensions/markdown/highlight.ts +0 -8
  63. package/src/extensions/table.ts +2 -2
  64. package/src/extensions/tasklist.ts +54 -77
  65. package/src/extensions/yjs/cursor.ts +2 -1
  66. package/src/extensions/yjs/yjs.test.ts +1 -1
  67. package/src/extensions/yjs/yjs.ts +2 -2
  68. package/src/hooks/index.ts +2 -1
  69. package/src/hooks/useTextModel.ts +4 -7
  70. package/src/hooks/yjs.ts +1 -23
  71. package/src/index.ts +2 -0
  72. package/src/styles/markdown.ts +0 -2
  73. package/src/themes/default.ts +17 -50
  74. package/dist/types/src/util/cursor.d.ts.map +0 -1
  75. package/dist/types/src/util/index.d.ts +0 -3
  76. package/dist/types/src/util/index.d.ts.map +0 -1
  77. package/dist/types/src/util/util.d.ts.map +0 -1
  78. package/src/util/cursor.ts +0 -29
  79. package/src/util/index.ts +0 -6
  80. /package/dist/types/src/{util/util.d.ts → util.d.ts} +0 -0
  81. /package/src/{util/util.ts → util.ts} +0 -0
@@ -11,46 +11,47 @@ import { EditorView as EditorView12 } from "@codemirror/view";
11
11
  import { useFocusableGroup } from "@fluentui/react-tabster";
12
12
  import { vim } from "@replit/codemirror-vim";
13
13
  import defaultsDeep2 from "lodash.defaultsdeep";
14
- import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState } from "react";
14
+ import React, { forwardRef, useCallback, useEffect, useImperativeHandle, useState, useRef } from "react";
15
15
  import { generateName } from "@dxos/display-name";
16
16
  import { useThemeContext } from "@dxos/react-ui";
17
17
  import { getColorForValue, inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
18
18
 
19
19
  // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
20
20
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
21
+ import { markdownLanguage } from "@codemirror/lang-markdown";
21
22
  import { keymap } from "@codemirror/view";
22
23
  var autocomplete = ({ onSearch }) => {
23
24
  return [
24
25
  // https://codemirror.net/docs/ref/#view.keymap
25
26
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
27
+ // TODO(burdon): Set custom keymap.
26
28
  keymap.of(completionKeymap),
27
29
  // https://codemirror.net/examples/autocompletion
28
30
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
29
31
  autocompletion({
30
- // TODO(burdon): Set custom keymap.
31
- // defaultKeymap: false,
32
+ defaultKeymap: false,
32
33
  // Don't start unless key press.
33
- activateOnTyping: false,
34
- // TODO(burdon): Option to create new page?
35
- // TODO(burdon): Optional decoration via addToOptions
36
- override: [
37
- (context) => {
38
- const match = context.matchBefore(/\w*/);
39
- if (!match || match.from === match.to && !context.explicit) {
40
- return null;
41
- }
42
- return {
43
- from: match.from,
44
- options: onSearch(match.text.toLowerCase())
45
- };
34
+ activateOnTyping: false
35
+ }),
36
+ // TODO(burdon): Option to create new page?
37
+ // TODO(burdon): Optional decoration via addToOptions
38
+ markdownLanguage.data.of({
39
+ autocomplete: (context) => {
40
+ const match = context.matchBefore(/\w*/);
41
+ if (!match || match.from === match.to && !context.explicit) {
42
+ return null;
46
43
  }
47
- ]
44
+ return {
45
+ from: match.from,
46
+ options: onSearch(match.text.toLowerCase())
47
+ };
48
+ }
48
49
  })
49
50
  ];
50
51
  };
51
52
 
52
53
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
53
- import { Facet as Facet2, StateField } from "@codemirror/state";
54
+ import { StateField } from "@codemirror/state";
54
55
  import { ViewPlugin } from "@codemirror/view";
55
56
  import { next as A } from "@dxos/automerge/automerge";
56
57
 
@@ -91,7 +92,7 @@ var cursorConverter = (handle, path) => ({
91
92
  });
92
93
 
93
94
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
94
- import { Annotation, StateEffect } from "@codemirror/state";
95
+ import { Annotation, StateEffect, Facet } from "@codemirror/state";
95
96
  var effectType = StateEffect.define({});
96
97
  var updateHeads = (newHeads) => effectType.of({
97
98
  newHeads
@@ -100,6 +101,9 @@ var getLastHeads = (state, field) => state.field(field).lastHeads;
100
101
  var getPath = (state, field) => state.field(field).path;
101
102
  var reconcileAnnotationType = Annotation.define();
102
103
  var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
104
+ var semaphoreFacet = Facet.define({
105
+ combine: (values) => values.at(-1)
106
+ });
103
107
 
104
108
  // packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
105
109
  import { next as automerge2 } from "@dxos/automerge/automerge";
@@ -236,11 +240,11 @@ var charPath = (textPath, candidatePath) => {
236
240
 
237
241
  // packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
238
242
  var PatchSemaphore = class {
239
- constructor(_field) {
243
+ constructor(_handle, _field) {
244
+ this._handle = _handle;
240
245
  this._field = _field;
241
246
  this._inReconcile = false;
242
- this._queue = [];
243
- this.reconcile = (handle, view) => {
247
+ this.reconcile = (view) => {
244
248
  if (this._inReconcile) {
245
249
  return;
246
250
  }
@@ -258,11 +262,11 @@ var PatchSemaphore = class {
258
262
  annotations: reconcileAnnotationType.of(true)
259
263
  });
260
264
  }
261
- let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
265
+ let newHeads = updateAutomerge(this._field, this._handle, transactions, view.state);
262
266
  if (newHeads === null || newHeads === void 0) {
263
- newHeads = automerge2.getHeads(handle.docSync());
267
+ newHeads = automerge2.getHeads(this._handle.docSync());
264
268
  }
265
- const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
269
+ const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
266
270
  updateCodeMirror(view, selection, path, diff);
267
271
  view.dispatch({
268
272
  effects: updateHeads(newHeads),
@@ -273,36 +277,42 @@ var PatchSemaphore = class {
273
277
  }
274
278
  };
275
279
 
276
- // packages/ui/react-ui-editor/src/util/cursor.ts
277
- import { Facet } from "@codemirror/state";
278
- var DEFAULT_CURSOR_CONVERTER = {
280
+ // packages/ui/react-ui-editor/src/extensions/cursor.ts
281
+ import { Facet as Facet2 } from "@codemirror/state";
282
+ var defaultCursorConverter = {
279
283
  toCursor: (position) => position.toString(),
280
284
  fromCursor: (cursor) => parseInt(cursor)
281
285
  };
282
- var CursorConverter = Facet.define({
283
- combine: (providers) => providers[0] ?? DEFAULT_CURSOR_CONVERTER
284
- });
285
-
286
- // packages/ui/react-ui-editor/src/util/util.ts
287
- import { log } from "@dxos/log";
288
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
289
- var callbackWrapper = (fn) => (...args) => {
290
- try {
291
- return fn(...args);
292
- } catch (error) {
293
- log.catch(error, void 0, {
294
- F: __dxlog_file,
295
- L: 16,
296
- S: void 0,
297
- C: (f, a) => f(...a)
286
+ var Cursor = class {
287
+ static {
288
+ this.converter = Facet2.define({
289
+ combine: (providers) => providers[0] ?? defaultCursorConverter
298
290
  });
299
291
  }
292
+ static {
293
+ this.getCursorFromRange = (cursorConverter3, range) => {
294
+ const from = cursorConverter3.toCursor(range.from);
295
+ const to = cursorConverter3.toCursor(range.to, -1);
296
+ return [
297
+ from,
298
+ to
299
+ ].join(":");
300
+ };
301
+ }
302
+ static {
303
+ this.getRangeFromCursor = (cursorConverter3, cursor) => {
304
+ const parts = cursor.split(":");
305
+ const from = cursorConverter3.fromCursor(parts[0]);
306
+ const to = cursorConverter3.fromCursor(parts[1]);
307
+ return from !== void 0 && to !== void 0 ? {
308
+ from,
309
+ to
310
+ } : void 0;
311
+ };
312
+ }
300
313
  };
301
314
 
302
315
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
303
- var semaphoreFacet = Facet2.define({
304
- combine: (values) => values.at(-1)
305
- });
306
316
  var automerge3 = ({ handle, path }) => {
307
317
  const stateField = StateField.define({
308
318
  create: () => ({
@@ -333,19 +343,19 @@ var automerge3 = ({ handle, path }) => {
333
343
  return result;
334
344
  }
335
345
  });
336
- const semaphore = new PatchSemaphore(stateField);
337
- const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
346
+ const semaphore = new PatchSemaphore(handle, stateField);
347
+ const viewPlugin = ViewPlugin.fromClass(class AutomergeViewPlugin {
338
348
  constructor(_view) {
339
349
  this._view = _view;
340
350
  this._handleChange = () => {
341
- this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
351
+ this._view.state.facet(semaphoreFacet).reconcile(this._view);
342
352
  };
343
353
  handle.addListener("change", this._handleChange);
344
354
  }
345
355
  update(update2) {
346
356
  if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
347
357
  queueMicrotask(() => {
348
- this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
358
+ this._view.state.facet(semaphoreFacet).reconcile(this._view);
349
359
  });
350
360
  }
351
361
  }
@@ -355,7 +365,7 @@ var automerge3 = ({ handle, path }) => {
355
365
  });
356
366
  return {
357
367
  extension: [
358
- CursorConverter.of(cursorConverter(handle, path)),
368
+ Cursor.converter.of(cursorConverter(handle, path)),
359
369
  semaphoreFacet.of(semaphore),
360
370
  stateField,
361
371
  viewPlugin
@@ -397,7 +407,7 @@ var RemoteSelectionsDecorator = class {
397
407
  this._ctx = new Context();
398
408
  this._lastAnchor = void 0;
399
409
  this._lastHead = void 0;
400
- this._cursorConverter = view.state.facet(CursorConverter);
410
+ this._cursorConverter = view.state.facet(Cursor.converter);
401
411
  this._provider = view.state.facet(AwarenessProvider);
402
412
  this._provider.open();
403
413
  this._provider.remoteStateChange.on(this._ctx, () => {
@@ -452,7 +462,7 @@ var RemoteSelectionsDecorator = class {
452
462
  attributes: {
453
463
  style: `background-color: ${lightColor}`
454
464
  },
455
- class: "cm-ySelection"
465
+ class: "cm-collab-selection"
456
466
  })
457
467
  });
458
468
  } else {
@@ -463,7 +473,7 @@ var RemoteSelectionsDecorator = class {
463
473
  attributes: {
464
474
  style: `background-color: ${color}`
465
475
  },
466
- class: "cm-ySelection"
476
+ class: "cm-collab-selection"
467
477
  })
468
478
  });
469
479
  decorations.push({
@@ -473,7 +483,7 @@ var RemoteSelectionsDecorator = class {
473
483
  attributes: {
474
484
  style: `background-color: ${color}`
475
485
  },
476
- class: "cm-ySelection"
486
+ class: "cm-collab-selection"
477
487
  })
478
488
  });
479
489
  for (let i = startLine.number + 1; i < endLine.number; i++) {
@@ -484,7 +494,7 @@ var RemoteSelectionsDecorator = class {
484
494
  value: Decoration.line({
485
495
  attributes: {
486
496
  style: `background-color: ${color}`,
487
- class: "cm-yLineSelection"
497
+ class: "cm-collab-selectionLine"
488
498
  }
489
499
  })
490
500
  });
@@ -504,23 +514,21 @@ var RemoteSelectionsDecorator = class {
504
514
  }
505
515
  };
506
516
  var RemoteCaretWidget = class extends WidgetType {
507
- constructor(name, color) {
517
+ constructor(_name, _color) {
508
518
  super();
509
- this.name = name;
510
- this.color = color;
511
- this.name = name;
512
- this.color = color;
519
+ this._name = _name;
520
+ this._color = _color;
513
521
  }
514
522
  toDOM() {
515
523
  const span = document.createElement("span");
516
- span.className = "cm-ySelectionCaret";
517
- span.style.backgroundColor = this.color;
518
- span.style.borderColor = this.color;
524
+ span.className = "cm-collab-selectionCaret";
525
+ span.style.backgroundColor = this._color;
526
+ span.style.borderColor = this._color;
519
527
  const dot = document.createElement("div");
520
- dot.className = "cm-ySelectionCaretDot";
528
+ dot.className = "cm-collab-selectionCaretDot";
521
529
  const info = document.createElement("div");
522
- info.className = "cm-ySelectionInfo";
523
- info.innerText = this.name;
530
+ info.className = "cm-collab-selectionInfo";
531
+ info.innerText = this._name;
524
532
  span.appendChild(document.createTextNode("\u2060"));
525
533
  span.appendChild(dot);
526
534
  span.appendChild(document.createTextNode("\u2060"));
@@ -528,15 +536,12 @@ var RemoteCaretWidget = class extends WidgetType {
528
536
  span.appendChild(document.createTextNode("\u2060"));
529
537
  return span;
530
538
  }
531
- eq(widget) {
532
- return widget.color === this.color;
533
- }
534
- compare(widget) {
535
- return widget.color === this.color;
536
- }
537
539
  updateDOM() {
538
540
  return false;
539
541
  }
542
+ eq(widget) {
543
+ return widget._color === this._color;
544
+ }
540
545
  get estimatedHeight() {
541
546
  return -1;
542
547
  }
@@ -545,12 +550,12 @@ var RemoteCaretWidget = class extends WidgetType {
545
550
  }
546
551
  };
547
552
  var styles = EditorView.baseTheme({
548
- ".cm-ySelection": {},
549
- ".cm-yLineSelection": {
553
+ ".cm-collab-selection": {},
554
+ ".cm-collab-selectionLine": {
550
555
  padding: 0,
551
556
  margin: "0px 2px 0px 4px"
552
557
  },
553
- ".cm-ySelectionCaret": {
558
+ ".cm-collab-selectionCaret": {
554
559
  position: "relative",
555
560
  borderLeft: "1px solid black",
556
561
  borderRight: "1px solid black",
@@ -559,7 +564,7 @@ var styles = EditorView.baseTheme({
559
564
  boxSizing: "border-box",
560
565
  display: "inline"
561
566
  },
562
- ".cm-ySelectionCaretDot": {
567
+ ".cm-collab-selectionCaretDot": {
563
568
  borderRadius: "50%",
564
569
  position: "absolute",
565
570
  width: ".4em",
@@ -570,11 +575,11 @@ var styles = EditorView.baseTheme({
570
575
  transition: "transform .3s ease-in-out",
571
576
  boxSizing: "border-box"
572
577
  },
573
- ".cm-ySelectionCaret:hover > .cm-ySelectionCaretDot": {
578
+ ".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
574
579
  transformOrigin: "bottom center",
575
580
  transform: "scale(0)"
576
581
  },
577
- ".cm-ySelectionInfo": {
582
+ ".cm-collab-selectionInfo": {
578
583
  position: "absolute",
579
584
  top: "-1.05em",
580
585
  left: "-1px",
@@ -590,12 +595,12 @@ var styles = EditorView.baseTheme({
590
595
  zIndex: 101,
591
596
  transition: "opacity .3s ease-in-out",
592
597
  backgroundColor: "inherit",
593
- // these should be separate
598
+ // These should be separate.
594
599
  opacity: 0,
595
600
  transitionDelay: "0s",
596
601
  whiteSpace: "nowrap"
597
602
  },
598
- ".cm-ySelectionCaret:hover > .cm-ySelectionInfo": {
603
+ ".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
599
604
  opacity: 1,
600
605
  transitionDelay: "0s"
601
606
  }
@@ -622,7 +627,7 @@ var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
622
627
  import { EditorView as EditorView3, keymap as keymap2 } from "@codemirror/view";
623
628
  import defaultsDeep from "lodash.defaultsdeep";
624
629
  import { invariant } from "@dxos/invariant";
625
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
630
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
626
631
  var defaultOptions = {
627
632
  effect: 2,
628
633
  maxParticles: 200,
@@ -749,7 +754,7 @@ var Blaster = class {
749
754
  }
750
755
  initialize() {
751
756
  invariant(!this._canvas && !this._ctx, void 0, {
752
- F: __dxlog_file2,
757
+ F: __dxlog_file,
753
758
  L: 138,
754
759
  S: this,
755
760
  A: [
@@ -786,7 +791,7 @@ var Blaster = class {
786
791
  }
787
792
  start() {
788
793
  invariant(this._canvas && this._ctx, void 0, {
789
- F: __dxlog_file2,
794
+ F: __dxlog_file,
790
795
  L: 177,
791
796
  S: this,
792
797
  A: [
@@ -1054,20 +1059,18 @@ var getLineRange = (lines, from, to) => {
1054
1059
  ];
1055
1060
  };
1056
1061
  var code2 = () => {
1057
- const getDecorations = (view) => {
1062
+ const buildDecorations4 = (view) => {
1058
1063
  const decorations = [];
1059
- if (view.state.readOnly) {
1060
- const text = view.state.doc.sliceString(0);
1061
- const matches = text.matchAll(CODE_REGEX);
1062
- const blocks = view.viewportLineBlocks;
1063
- for (const match of matches) {
1064
- const range = getLineRange(blocks, match.index, match.index + match[0].length);
1065
- for (let i = range[0]; i <= range[1]; i++) {
1066
- const block = blocks[i];
1067
- decorations.push(Decoration2.line({
1068
- class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1069
- }).range(block.from));
1070
- }
1064
+ const text = view.state.doc.sliceString(0);
1065
+ const matches = text.matchAll(CODE_REGEX);
1066
+ const blocks = view.viewportLineBlocks;
1067
+ for (const match of matches) {
1068
+ const range = getLineRange(blocks, match.index, match.index + match[0].length);
1069
+ for (let i = range[0]; i <= range[1]; i++) {
1070
+ const block = blocks[i];
1071
+ decorations.push(Decoration2.line({
1072
+ class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1073
+ }).range(block.from));
1071
1074
  }
1072
1075
  }
1073
1076
  return Decoration2.set(decorations);
@@ -1075,11 +1078,16 @@ var code2 = () => {
1075
1078
  return [
1076
1079
  ViewPlugin3.fromClass(class {
1077
1080
  constructor(view) {
1078
- this.decorations = getDecorations(view);
1081
+ this.hasFocus = false;
1082
+ this.decorations = buildDecorations4(view);
1079
1083
  }
1080
1084
  update(update2) {
1081
- if (update2.docChanged || update2.viewportChanged) {
1082
- this.decorations = getDecorations(update2.view);
1085
+ if (
1086
+ // TODO(burdon): Generalize for other extensions.
1087
+ this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1088
+ ) {
1089
+ this.hasFocus = update2.view.hasFocus;
1090
+ this.decorations = buildDecorations4(update2.view);
1083
1091
  }
1084
1092
  }
1085
1093
  }, {
@@ -1091,23 +1099,31 @@ var code2 = () => {
1091
1099
 
1092
1100
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1093
1101
  import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1094
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1102
+ import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
1095
1103
  import sortBy from "lodash.sortby";
1096
1104
  import { debounce } from "@dxos/async";
1097
1105
  import { invariant as invariant2 } from "@dxos/invariant";
1098
- import { log as log2 } from "@dxos/log";
1099
1106
  import { nonNullable } from "@dxos/util";
1107
+
1108
+ // packages/ui/react-ui-editor/src/util.ts
1109
+ import { log } from "@dxos/log";
1110
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1111
+ var callbackWrapper = (fn) => (...args) => {
1112
+ try {
1113
+ return fn(...args);
1114
+ } catch (error) {
1115
+ log.catch(error, void 0, {
1116
+ F: __dxlog_file2,
1117
+ L: 16,
1118
+ S: void 0,
1119
+ C: (f, a) => f(...a)
1120
+ });
1121
+ }
1122
+ };
1123
+
1124
+ // packages/ui/react-ui-editor/src/extensions/comments.ts
1100
1125
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1101
1126
  var styles3 = EditorView5.baseTheme({
1102
- "& .cm-bookmark": {
1103
- cursor: "pointer",
1104
- margin: "4px",
1105
- padding: "4px",
1106
- backgroundColor: "yellow"
1107
- },
1108
- "& .cm-bookmark-selected": {
1109
- backgroundColor: "orange"
1110
- },
1111
1127
  "& .cm-comment": {
1112
1128
  backgroundColor: getToken("extend.colors.yellow.50")
1113
1129
  },
@@ -1146,7 +1162,7 @@ var commentsStateField = StateField2.define({
1146
1162
  ranges: []
1147
1163
  }),
1148
1164
  update: (value, tr) => {
1149
- const cursorConverter3 = tr.state.facet(CursorConverter);
1165
+ const cursorConverter3 = tr.state.facet(Cursor.converter);
1150
1166
  for (const effect of tr.effects) {
1151
1167
  if (effect.is(setSelection)) {
1152
1168
  return {
@@ -1157,7 +1173,7 @@ var commentsStateField = StateField2.define({
1157
1173
  if (effect.is(setCommentRange)) {
1158
1174
  const { comments: comments2 } = effect.value;
1159
1175
  const ranges = comments2.map((comment) => {
1160
- const range = getRangeFromCursor(cursorConverter3, comment.cursor);
1176
+ const range = Cursor.getRangeFromCursor(cursorConverter3, comment.cursor);
1161
1177
  return range && {
1162
1178
  ...comment,
1163
1179
  ...range
@@ -1195,58 +1211,89 @@ var highlightDecorations = EditorView5.decorations.compute([
1195
1211
  }).filter(nonNullable) ?? [];
1196
1212
  return Decoration3.set(decorations);
1197
1213
  });
1198
- var BookmarkWidget = class extends WidgetType2 {
1199
- constructor(_anchor, _id, _handleClick) {
1200
- super();
1201
- this._anchor = _anchor;
1202
- this._id = _id;
1203
- this._handleClick = _handleClick;
1204
- invariant2(this._id, void 0, {
1205
- F: __dxlog_file3,
1206
- L: 168,
1207
- S: this,
1208
- A: [
1209
- "this._id",
1210
- ""
1211
- ]
1212
- });
1213
- }
1214
- eq(other) {
1215
- return this._anchor === other._anchor && this._id === other._id;
1216
- }
1217
- toDOM() {
1218
- const span = document.createElement("span");
1219
- span.className = "cm-bookmark";
1220
- span.textContent = "\u203B";
1221
- if (this._handleClick) {
1222
- span.onclick = () => this._handleClick();
1214
+ var trackPastedComments = (onUpdate) => {
1215
+ let tracked = null;
1216
+ const handleTrack = (event, view) => {
1217
+ const comments2 = view.state.field(commentsStateField);
1218
+ const { main } = view.state.selection;
1219
+ const selectedRanges = comments2.ranges.filter((range) => range.from >= main.from && range.to <= main.to && range.from < range.to);
1220
+ if (!selectedRanges.length) {
1221
+ tracked = null;
1222
+ } else {
1223
+ tracked = {
1224
+ text: view.state.doc.slice(main.from, main.to),
1225
+ comments: selectedRanges.map((range) => ({
1226
+ id: range.id,
1227
+ from: range.from - main.from,
1228
+ to: range.to - main.from
1229
+ }))
1230
+ };
1223
1231
  }
1224
- return span;
1225
- }
1232
+ };
1233
+ return [
1234
+ EditorView5.domEventHandlers({
1235
+ cut: handleTrack,
1236
+ copy: handleTrack
1237
+ }),
1238
+ // Handle paste.
1239
+ EditorView5.updateListener.of(({ view, state, transactions }) => {
1240
+ if (tracked) {
1241
+ const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
1242
+ if (paste) {
1243
+ let found = -1;
1244
+ paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
1245
+ if (text.eq(tracked.text)) {
1246
+ for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
1247
+ fromB = transactions[i].changes.mapPos(fromB);
1248
+ }
1249
+ found = fromB;
1250
+ }
1251
+ });
1252
+ if (found > -1) {
1253
+ const comments2 = tracked.comments;
1254
+ view.state.facet(semaphoreFacet).reconcile(view);
1255
+ const active = state.field(commentsStateField).ranges;
1256
+ for (const moved of comments2) {
1257
+ if (active.some((range) => range.id === moved.id && range.from === range.to)) {
1258
+ const range = {
1259
+ from: found + moved.from,
1260
+ to: found + moved.to
1261
+ };
1262
+ const cursor = Cursor.getCursorFromRange(state.facet(Cursor.converter), range);
1263
+ onUpdate(moved.id, cursor);
1264
+ }
1265
+ }
1266
+ }
1267
+ tracked = null;
1268
+ }
1269
+ }
1270
+ })
1271
+ ];
1226
1272
  };
1227
1273
  var comments = (options = {}) => {
1274
+ const { key: shortcut = "meta-'" } = options;
1228
1275
  const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1229
1276
  const createCommentThread = (view) => {
1230
- const cursorConverter3 = view.state.facet(CursorConverter);
1277
+ const cursorConverter3 = view.state.facet(Cursor.converter);
1231
1278
  invariant2(options.onCreate, void 0, {
1232
1279
  F: __dxlog_file3,
1233
- L: 224,
1280
+ L: 264,
1234
1281
  S: void 0,
1235
1282
  A: [
1236
1283
  "options.onCreate",
1237
1284
  ""
1238
1285
  ]
1239
1286
  });
1240
- const { head, from, to } = view.state.selection.main;
1287
+ const { from, to } = view.state.selection.main;
1241
1288
  if (from === to) {
1242
1289
  return false;
1243
1290
  }
1244
- const relPos = getCursorFromRange(cursorConverter3, {
1291
+ const cursor = Cursor.getCursorFromRange(cursorConverter3, {
1245
1292
  from,
1246
1293
  to
1247
1294
  });
1248
- if (relPos) {
1249
- const id = callbackWrapper(options.onCreate)(relPos);
1295
+ if (cursor) {
1296
+ const id = callbackWrapper(options.onCreate)(cursor, view.coordsAtPos(from));
1250
1297
  if (id) {
1251
1298
  view.dispatch({
1252
1299
  effects: setSelection.of({
@@ -1256,52 +1303,12 @@ var comments = (options = {}) => {
1256
1303
  anchor: from
1257
1304
  }
1258
1305
  });
1259
- if (options.footnote) {
1260
- const tag = `[^${id}]`;
1261
- view.dispatch({
1262
- changes: {
1263
- from: head,
1264
- insert: tag
1265
- },
1266
- selection: {
1267
- anchor: head + tag.length
1268
- }
1269
- });
1270
- }
1271
1306
  return true;
1272
1307
  }
1273
1308
  }
1274
1309
  return false;
1275
1310
  };
1276
- const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
1277
- static {
1278
- // Match markdown footnotes (option).
1279
- // https://www.markdownguide.org/extended-syntax/#footnotes
1280
- this.bookmarkMatcher = new MatchDecorator({
1281
- regexp: /\[\^(\w+)\]/g,
1282
- decoration: (match, view, pos) => {
1283
- const id = match[1];
1284
- return Decoration3.replace({
1285
- id,
1286
- widget: new BookmarkWidget(pos, id)
1287
- });
1288
- }
1289
- });
1290
- }
1291
- constructor(view) {
1292
- this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
1293
- }
1294
- update(update2) {
1295
- this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update2, this.bookmarks);
1296
- }
1297
- }, {
1298
- decorations: (instance) => instance.bookmarks,
1299
- provide: (plugin) => EditorView5.atomicRanges.of((view) => {
1300
- return view.plugin(plugin)?.bookmarks || Decoration3.none;
1301
- })
1302
- });
1303
1311
  return [
1304
- bookmarksViewPlugin,
1305
1312
  commentsStateField,
1306
1313
  highlightDecorations,
1307
1314
  styles3,
@@ -1310,7 +1317,7 @@ var comments = (options = {}) => {
1310
1317
  //
1311
1318
  options.onCreate ? keymap3.of([
1312
1319
  {
1313
- key: options?.key ?? "meta-'",
1320
+ key: shortcut,
1314
1321
  run: callbackWrapper(createCommentThread)
1315
1322
  }
1316
1323
  ]) : [],
@@ -1327,7 +1334,7 @@ var comments = (options = {}) => {
1327
1334
  above: true,
1328
1335
  create: () => {
1329
1336
  const el = document.createElement("div");
1330
- options.onHover?.(el);
1337
+ options.onHover(el, shortcut);
1331
1338
  return {
1332
1339
  dom: el,
1333
1340
  offset: {
@@ -1340,7 +1347,8 @@ var comments = (options = {}) => {
1340
1347
  }
1341
1348
  return null;
1342
1349
  }, {
1343
- hideOnChange: true,
1350
+ // TODO(burdon): Hide on change triggered immediately?
1351
+ // hideOnChange: true,
1344
1352
  hoverTime: 1e3
1345
1353
  }) : [],
1346
1354
  //
@@ -1348,27 +1356,20 @@ var comments = (options = {}) => {
1348
1356
  // TODO(burdon): Is there a better (finer grained) way to do this?
1349
1357
  //
1350
1358
  EditorView5.updateListener.of(({ view, state, changes }) => {
1351
- const cursorConverter3 = view.state.facet(CursorConverter);
1359
+ const cursorConverter3 = view.state.facet(Cursor.converter);
1352
1360
  {
1353
1361
  let mod = false;
1354
1362
  const { active, ranges } = state.field(commentsStateField);
1355
1363
  changes.iterChanges((from, to, from2, to2) => {
1356
1364
  ranges.forEach((range) => {
1357
1365
  if (from2 === to2) {
1358
- const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
1366
+ const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1359
1367
  if (!newRange || newRange.to - newRange.from === 0) {
1360
- log2.info("deleted comment", {
1361
- thread: range.id
1362
- }, {
1363
- F: __dxlog_file3,
1364
- L: 358,
1365
- S: void 0,
1366
- C: (f, a) => f(...a)
1367
- });
1368
+ options.onDelete?.(range.id);
1368
1369
  }
1369
1370
  }
1370
1371
  if (from <= range.to) {
1371
- const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
1372
+ const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1372
1373
  Object.assign(range, newRange);
1373
1374
  mod = true;
1374
1375
  }
@@ -1414,29 +1415,13 @@ var comments = (options = {}) => {
1414
1415
  });
1415
1416
  }
1416
1417
  }
1417
- })
1418
+ }),
1419
+ options.onUpdate ? trackPastedComments(options.onUpdate) : []
1418
1420
  ];
1419
1421
  };
1420
- var getCursorFromRange = (cursorConverter3, range) => {
1421
- const from = cursorConverter3.toCursor(range.from);
1422
- const to = cursorConverter3.toCursor(range.to, -1);
1423
- return [
1424
- from,
1425
- to
1426
- ].join(":");
1427
- };
1428
- var getRangeFromCursor = (cursorConverter3, cursor) => {
1429
- const parts = cursor.split(":");
1430
- const from = cursorConverter3.fromCursor(parts[0]);
1431
- const to = cursorConverter3.fromCursor(parts[1]);
1432
- return from !== void 0 && to !== void 0 ? {
1433
- from,
1434
- to
1435
- } : void 0;
1436
- };
1437
1422
 
1438
1423
  // packages/ui/react-ui-editor/src/extensions/hr.ts
1439
- import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
1424
+ import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1440
1425
  var styles4 = EditorView6.baseTheme({
1441
1426
  "& .cm-hr": {
1442
1427
  // TODO(burdon): ???
@@ -1444,7 +1429,7 @@ var styles4 = EditorView6.baseTheme({
1444
1429
  borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
1445
1430
  }
1446
1431
  });
1447
- var HorizontalRuleWidget = class extends WidgetType3 {
1432
+ var HorizontalRuleWidget = class extends WidgetType2 {
1448
1433
  constructor(_pos) {
1449
1434
  super();
1450
1435
  this._pos = _pos;
@@ -1458,15 +1443,16 @@ var HorizontalRuleWidget = class extends WidgetType3 {
1458
1443
  return el;
1459
1444
  }
1460
1445
  };
1461
- var placeholderMatcher = new MatchDecorator2({
1462
- regexp: /^---$/g,
1446
+ var placeholderMatcher = new MatchDecorator({
1447
+ // regexp: /(?<=\n\n)---/gs,
1448
+ regexp: /^---$/gs,
1463
1449
  decoration: (match, view, pos) => Decoration4.replace({
1464
1450
  widget: new HorizontalRuleWidget(pos)
1465
1451
  })
1466
1452
  });
1467
1453
  var hr = () => [
1468
1454
  styles4,
1469
- ViewPlugin5.fromClass(class {
1455
+ ViewPlugin4.fromClass(class {
1470
1456
  constructor(view) {
1471
1457
  this.rules = placeholderMatcher.createDeco(view);
1472
1458
  }
@@ -1474,18 +1460,14 @@ var hr = () => [
1474
1460
  this.rules = placeholderMatcher.updateDeco(update2, this.rules);
1475
1461
  }
1476
1462
  }, {
1477
- decorations: (instance) => instance.rules,
1478
- // TODO(burdon): Is this really atomic (cursor can move into ---).
1479
- provide: (plugin) => EditorView6.atomicRanges.of((view) => {
1480
- return view.plugin(plugin)?.rules || Decoration4.none;
1481
- })
1463
+ decorations: (instance) => instance.rules
1482
1464
  })
1483
1465
  ];
1484
1466
 
1485
1467
  // packages/ui/react-ui-editor/src/extensions/image.ts
1486
1468
  import { syntaxTree } from "@codemirror/language";
1487
1469
  import { StateField as StateField3 } from "@codemirror/state";
1488
- import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
1470
+ import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
1489
1471
  var image = (options = {}) => {
1490
1472
  return StateField3.define({
1491
1473
  create: (state) => {
@@ -1537,7 +1519,7 @@ var buildDecorations = (from, to, state) => {
1537
1519
  });
1538
1520
  return decorations;
1539
1521
  };
1540
- var ImageWidget = class extends WidgetType4 {
1522
+ var ImageWidget = class extends WidgetType3 {
1541
1523
  constructor(_url) {
1542
1524
  super();
1543
1525
  this._url = _url;
@@ -1557,11 +1539,11 @@ var ImageWidget = class extends WidgetType4 {
1557
1539
  // packages/ui/react-ui-editor/src/extensions/link.ts
1558
1540
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1559
1541
  import { RangeSetBuilder } from "@codemirror/state";
1560
- import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
1542
+ import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
1561
1543
  import { tooltipContent } from "@dxos/react-ui-theme";
1562
1544
  var link = (options = {}) => {
1563
1545
  const extensions = [
1564
- ViewPlugin6.fromClass(class {
1546
+ ViewPlugin5.fromClass(class {
1565
1547
  constructor(view) {
1566
1548
  this.decorations = buildDecorations2(view, options);
1567
1549
  }
@@ -1612,7 +1594,7 @@ var link = (options = {}) => {
1612
1594
  }
1613
1595
  return extensions;
1614
1596
  };
1615
- var LinkButton = class extends WidgetType5 {
1597
+ var LinkButton = class extends WidgetType4 {
1616
1598
  constructor(_url, _onAttach) {
1617
1599
  super();
1618
1600
  this._url = _url;
@@ -1627,7 +1609,7 @@ var LinkButton = class extends WidgetType5 {
1627
1609
  return el;
1628
1610
  }
1629
1611
  };
1630
- var LinkText = class extends WidgetType5 {
1612
+ var LinkText = class extends WidgetType4 {
1631
1613
  constructor(_text, _url) {
1632
1614
  super();
1633
1615
  this._text = _text;
@@ -1708,7 +1690,7 @@ var listener = ({ onFocus, onChange }) => {
1708
1690
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1709
1691
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1710
1692
  import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1711
- import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
1693
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1712
1694
  import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1713
1695
  import { languages } from "@codemirror/language-data";
1714
1696
  import { searchKeymap } from "@codemirror/search";
@@ -1717,7 +1699,7 @@ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/the
1717
1699
  import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1718
1700
 
1719
1701
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1720
- import { markdownLanguage } from "@codemirror/lang-markdown";
1702
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1721
1703
  import { HighlightStyle } from "@codemirror/language";
1722
1704
  import { tags, styleTags, Tag } from "@lezer/highlight";
1723
1705
  import { Table } from "@lezer/markdown";
@@ -1727,7 +1709,6 @@ var markdownTags = {
1727
1709
  CodeText: Tag.define(),
1728
1710
  EmphasisMark: Tag.define(),
1729
1711
  HeaderMark: Tag.define(),
1730
- // HorizontalRule: Tag.define(),
1731
1712
  InlineCode: Tag.define(),
1732
1713
  LinkLabel: Tag.define(),
1733
1714
  LinkReference: Tag.define(),
@@ -1891,12 +1872,6 @@ var markdownHighlightStyle = (readonly) => {
1891
1872
  ],
1892
1873
  class: blockquote
1893
1874
  },
1894
- // TODO(burdon): Replace with extension.
1895
- // {
1896
- // tag: [markdownTags.HorizontalRule],
1897
- // class: mx(horizontalRule, readonly && '-indent-[100rem]'),
1898
- // },
1899
- // TODO(burdon): Only if being edited.
1900
1875
  {
1901
1876
  tag: [
1902
1877
  markdownTags.TableCell
@@ -1904,7 +1879,7 @@ var markdownHighlightStyle = (readonly) => {
1904
1879
  class: "font-mono"
1905
1880
  }
1906
1881
  ], {
1907
- scope: markdownLanguage,
1882
+ scope: markdownLanguage2,
1908
1883
  all: {
1909
1884
  fontFamily: getToken("fontFamily.body", []).join(",")
1910
1885
  }
@@ -1936,7 +1911,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1936
1911
  // NOTE: This extends the parser; it doesn't affect rendering.
1937
1912
  // https://github.github.com/gfm
1938
1913
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
1939
- base: markdownLanguage2,
1914
+ base: markdownLanguage3,
1940
1915
  // Languages for syntax highlighting fenced code blocks.
1941
1916
  codeLanguages: languages,
1942
1917
  // Parser extensions.
@@ -1990,7 +1965,7 @@ var mention = ({ onSearch }) => {
1990
1965
  // packages/ui/react-ui-editor/src/extensions/table.ts
1991
1966
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1992
1967
  import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
1993
- import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType6 } from "@codemirror/view";
1968
+ import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType5 } from "@codemirror/view";
1994
1969
  var table = (options = {}) => {
1995
1970
  return StateField4.define({
1996
1971
  create: (state) => update(state, options),
@@ -2048,7 +2023,7 @@ var update = (state, options) => {
2048
2023
  });
2049
2024
  return builder.finish();
2050
2025
  };
2051
- var TableWidget = class extends WidgetType6 {
2026
+ var TableWidget = class extends WidgetType5 {
2052
2027
  constructor(_table) {
2053
2028
  super();
2054
2029
  this._table = _table;
@@ -2086,87 +2061,86 @@ var TableWidget = class extends WidgetType6 {
2086
2061
  };
2087
2062
 
2088
2063
  // packages/ui/react-ui-editor/src/extensions/tasklist.ts
2089
- import { EditorView as EditorView11, Decoration as Decoration8, WidgetType as WidgetType7, MatchDecorator as MatchDecorator3, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
2090
- var styles5 = EditorView11.baseTheme({
2091
- "& .cm-task-item": {
2092
- paddingLeft: "4px",
2093
- paddingRight: "8px"
2094
- }
2095
- });
2096
- var CheckboxWidget = class extends WidgetType7 {
2097
- constructor(_checked, _indent, _onCheck) {
2064
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2065
+ import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
2066
+ import { EditorView as EditorView11, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
2067
+ var CheckboxWidget = class extends WidgetType6 {
2068
+ constructor(_checked) {
2098
2069
  super();
2099
2070
  this._checked = _checked;
2100
- this._indent = _indent;
2101
- this._onCheck = _onCheck;
2102
2071
  }
2103
2072
  eq(other) {
2104
- return this._checked === other._checked && this._indent === other._indent;
2073
+ return this._checked === other._checked;
2105
2074
  }
2106
2075
  toDOM(view) {
2107
- const wrap = document.createElement("span");
2108
- wrap.className = "cm-task-item";
2109
- wrap.setAttribute("aria-hidden", "true");
2110
- wrap.style.setProperty("margin-left", this._indent * 24 + "px");
2111
- const input = wrap.appendChild(document.createElement("input"));
2076
+ const input = document.createElement("input");
2112
2077
  input.type = "checkbox";
2113
2078
  input.checked = this._checked;
2114
- if (!this._onCheck) {
2079
+ if (view.state.readOnly) {
2115
2080
  input.setAttribute("disabled", "true");
2116
- }
2117
- if (this._onCheck) {
2118
- input.onchange = (event) => {
2119
- this._onCheck?.(event.target.checked);
2120
- return true;
2081
+ } else {
2082
+ input.onmousedown = (event) => {
2083
+ const pos = view.posAtDOM(input);
2084
+ const text = view.state.sliceDoc(pos, pos + 3);
2085
+ if (text === (this._checked ? "[x]" : "[ ]")) {
2086
+ view.dispatch({
2087
+ changes: {
2088
+ from: pos + 1,
2089
+ to: pos + 2,
2090
+ insert: this._checked ? " " : "x"
2091
+ }
2092
+ });
2093
+ event.preventDefault();
2094
+ }
2121
2095
  };
2122
2096
  }
2123
- return wrap;
2097
+ return input;
2124
2098
  }
2125
2099
  ignoreEvent() {
2126
2100
  return false;
2127
2101
  }
2128
2102
  };
2103
+ var checkedDeco = Decoration8.replace({
2104
+ widget: new CheckboxWidget(true)
2105
+ });
2106
+ var uncheckedDeco = Decoration8.replace({
2107
+ widget: new CheckboxWidget(false)
2108
+ });
2129
2109
  var tasklist = (options = {}) => {
2130
- const taskMatcher = new MatchDecorator3({
2131
- regexp: /^(\s*)- \[([ xX])\]\s/g,
2132
- decoration: (match, view, pos) => {
2133
- const indent = Math.floor(match[1].length / 2);
2134
- const checked = match[2] === "x" || match[2] === "X";
2135
- return Decoration8.replace({
2136
- widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
2137
- const idx = pos + match[0].indexOf("[") + 1;
2138
- view.dispatch({
2139
- changes: {
2140
- from: idx,
2141
- to: idx + 1,
2142
- insert: checked2 ? "x" : " "
2143
- },
2144
- // TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
2145
- selection: {
2146
- anchor: idx + 3
2147
- }
2148
- });
2149
- })
2150
- });
2151
- }
2152
- });
2153
- const tasks = ViewPlugin7.fromClass(class {
2110
+ return ViewPlugin6.fromClass(class {
2154
2111
  constructor(view) {
2155
- this.tasks = taskMatcher.createDeco(view);
2112
+ this.decorations = buildDecorations3(view);
2156
2113
  }
2157
2114
  update(update2) {
2158
- this.tasks = taskMatcher.updateDeco(update2, this.tasks);
2115
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2116
+ this.decorations = buildDecorations3(update2.view);
2117
+ }
2159
2118
  }
2160
2119
  }, {
2161
- decorations: (value) => value.tasks,
2120
+ decorations: (v) => v.decorations,
2121
+ // TODO(burdon): Is this still required?
2162
2122
  provide: (plugin) => EditorView11.atomicRanges.of((view) => {
2163
- return view.plugin(plugin)?.tasks || Decoration8.none;
2123
+ return view.plugin(plugin)?.decorations || Decoration8.none;
2164
2124
  })
2165
2125
  });
2166
- return [
2167
- tasks,
2168
- styles5
2169
- ];
2126
+ };
2127
+ var buildDecorations3 = (view) => {
2128
+ const builder = new RangeSetBuilder3();
2129
+ const { state } = view;
2130
+ const cursor = state.selection.main.head;
2131
+ for (const { from, to } of view.visibleRanges) {
2132
+ syntaxTree4(state).iterate({
2133
+ enter: (node) => {
2134
+ if (node.name === "TaskMarker" && (cursor < node.from || cursor > node.to)) {
2135
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2136
+ builder.add(node.from, node.to, checked ? checkedDeco : uncheckedDeco);
2137
+ }
2138
+ },
2139
+ from,
2140
+ to
2141
+ });
2142
+ }
2143
+ return builder.finish();
2170
2144
  };
2171
2145
 
2172
2146
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
@@ -2243,7 +2217,7 @@ var cursorConverter2 = (text) => ({
2243
2217
 
2244
2218
  // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2245
2219
  var yjs = (content, awareness2) => [
2246
- CursorConverter.of(cursorConverter2(content)),
2220
+ Cursor.converter.of(cursorConverter2(content)),
2247
2221
  yCollab(content, awareness2)
2248
2222
  ];
2249
2223
 
@@ -2340,33 +2314,6 @@ var defaultTheme = {
2340
2314
  backgroundColor: get3(tokens, "extend.colors.yellow.700")
2341
2315
  },
2342
2316
  //
2343
- // collaboration
2344
- // TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
2345
- //
2346
- "&light .cm-ySelection, &light .cm-yLineSelection": {
2347
- mixBlendMode: "multiply"
2348
- },
2349
- "&dark .cm-ySelection, &dark .cm-yLineSelection": {
2350
- mixBlendMode: "screen"
2351
- },
2352
- ".cm-ySelectionInfo": {
2353
- padding: "2px 4px",
2354
- marginBlockStart: "-4px"
2355
- },
2356
- ".cm-ySelection, & .cm-selectionMatch": {
2357
- paddingBlockStart: ".15em",
2358
- paddingBlockEnd: ".15em"
2359
- },
2360
- ".cm-ySelectionCaret": {
2361
- display: "inline-block",
2362
- insetBlockStart: ".1em",
2363
- blockSize: "1.4em",
2364
- verticalAlign: "top"
2365
- },
2366
- ".cm-yLineSelection": {
2367
- margin: 0
2368
- },
2369
- //
2370
2317
  // link
2371
2318
  //
2372
2319
  ".cm-link": {
@@ -2403,13 +2350,6 @@ var defaultTheme = {
2403
2350
  textDecoration: "none"
2404
2351
  },
2405
2352
  //
2406
- // widgets
2407
- //
2408
- ".cm-widgetBuffer": {
2409
- display: "none",
2410
- height: 0
2411
- },
2412
- //
2413
2353
  // table
2414
2354
  //
2415
2355
  ".cm-table *": {
@@ -2440,27 +2380,17 @@ var defaultTheme = {
2440
2380
  },
2441
2381
  //
2442
2382
  // font size
2443
- // 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.
2383
+ // TODO(thure): This appears to be the best or only way to set selection caret heights,
2384
+ // but it's far more verbose than it needs to be.
2444
2385
  //
2445
- ...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
2446
- const height = get3(tokens, [
2447
- "extend",
2448
- "fontSize",
2449
- fontSize,
2450
- 1,
2451
- "lineHeight"
2452
- ]);
2453
- acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
2454
- height
2455
- };
2456
- acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
2457
- height
2458
- };
2459
- acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
2460
- height
2461
- };
2462
- return acc;
2463
- }, {}),
2386
+ // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
2387
+ // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
2388
+ //
2389
+ // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
2390
+ // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
2391
+ // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
2392
+ // return acc;
2393
+ // }, {}),
2464
2394
  /**
2465
2395
  * Panels
2466
2396
  * TODO(burdon): Needs styling attention (esp. dark mode).
@@ -2511,7 +2441,9 @@ var textTheme = {
2511
2441
  }
2512
2442
  };
2513
2443
  var markdownTheme = {
2514
- // NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
2444
+ ".cm-scroller": {
2445
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2446
+ },
2515
2447
  ".cm-placeholder": {
2516
2448
  fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2517
2449
  }
@@ -2530,21 +2462,23 @@ var EditorModes = [
2530
2462
  "default",
2531
2463
  "vim"
2532
2464
  ];
2533
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: comments2, extensions = [], editorMode, slots = defaultSlots }, forwardedRef) => {
2534
- const { themeMode } = useThemeContext();
2465
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, autofocus, readonly, selection, comments: comments2, extensions = [], editorMode, theme, slots = defaultSlots }, forwardedRef) => {
2535
2466
  const tabsterDOMAttribute = useFocusableGroup({
2536
2467
  tabBehavior: "limited"
2537
2468
  });
2538
- const [root, setRoot] = useState(null);
2539
- const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
2540
- useImperativeHandle(forwardedRef, () => ({
2541
- root,
2542
- state,
2469
+ const { themeMode } = useThemeContext();
2470
+ const rootRef = useRef(null);
2471
+ const [view, setView] = useState(null);
2472
+ useImperativeHandle(forwardedRef, () => view, [
2473
+ view
2474
+ ]);
2475
+ useEffect(() => {
2476
+ if (autofocus) {
2477
+ view?.focus();
2478
+ }
2479
+ }, [
2480
+ autofocus,
2543
2481
  view
2544
- }), [
2545
- view,
2546
- state,
2547
- root
2548
2482
  ]);
2549
2483
  const { awareness: awareness2, peer } = model;
2550
2484
  useEffect(() => {
@@ -2568,7 +2502,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2568
2502
  themeMode
2569
2503
  ]);
2570
2504
  useEffect(() => {
2571
- if (view && comments2?.length) {
2505
+ if (view && comments2 !== void 0) {
2572
2506
  view.dispatch({
2573
2507
  effects: setCommentRange.of({
2574
2508
  model,
@@ -2581,11 +2515,13 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2581
2515
  comments2
2582
2516
  ]);
2583
2517
  useEffect(() => {
2584
- if (!root) {
2518
+ if (!model || !rootRef.current) {
2585
2519
  return;
2586
2520
  }
2587
- const state2 = EditorState2.create({
2521
+ const state = EditorState2.create({
2588
2522
  doc: model.text(),
2523
+ // TODO(burdon): Composer should store and set selection when switching documents.
2524
+ selection,
2589
2525
  extensions: [
2590
2526
  readonly && EditorState2.readOnly.of(readonly),
2591
2527
  // TODO(burdon): Factor out VIM mode? (manage via MarkdownPlugin).
@@ -2593,7 +2529,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2593
2529
  // Theme.
2594
2530
  // TODO(burdon): Make theme configurable.
2595
2531
  EditorView12.baseTheme(defaultTheme),
2596
- EditorView12.theme(slots?.editor?.theme ?? {}),
2532
+ EditorView12.theme(theme ?? {}),
2597
2533
  EditorView12.darkTheme.of(themeMode === "dark"),
2598
2534
  // Storage and replication.
2599
2535
  model.extension,
@@ -2602,19 +2538,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2602
2538
  ].filter(Boolean)
2603
2539
  });
2604
2540
  view?.destroy();
2605
- setEditor({
2606
- state: state2,
2607
- view: new EditorView12({
2608
- state: state2,
2609
- parent: root
2610
- })
2541
+ const newView = new EditorView12({
2542
+ parent: rootRef.current,
2543
+ state
2611
2544
  });
2545
+ setView(newView);
2612
2546
  return () => {
2613
- view?.destroy();
2614
- setEditor(void 0);
2547
+ newView?.destroy();
2548
+ setView(null);
2615
2549
  };
2616
2550
  }, [
2617
- root,
2551
+ rootRef,
2618
2552
  model,
2619
2553
  readonly,
2620
2554
  editorMode,
@@ -2623,12 +2557,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2623
2557
  const handleKeyUp = useCallback((event) => {
2624
2558
  const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
2625
2559
  switch (key) {
2626
- case "Enter": {
2627
- view?.contentDOM.focus();
2628
- break;
2629
- }
2630
2560
  case "Escape": {
2631
- editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
2561
+ editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && rootRef.current?.focus();
2632
2562
  break;
2633
2563
  }
2634
2564
  }
@@ -2638,16 +2568,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2638
2568
  ]);
2639
2569
  return /* @__PURE__ */ React.createElement("div", {
2640
2570
  key: model.id,
2641
- ref: setRoot,
2571
+ role: "none",
2642
2572
  tabIndex: 0,
2643
- ...slots?.root,
2573
+ onKeyUp: handleKeyUp,
2574
+ ...slots.root,
2644
2575
  ...editorMode !== "vim" && tabsterDOMAttribute,
2645
- onKeyUp: handleKeyUp
2576
+ ref: rootRef
2646
2577
  });
2647
2578
  });
2648
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
2579
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = textTheme, slots, ...props }, forwardedRef) => {
2649
2580
  const { themeMode } = useThemeContext();
2650
- const slots = defaultsDeep2({}, _slots, defaultTextSlots);
2581
+ const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2651
2582
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2652
2583
  ref: forwardedRef,
2653
2584
  readonly,
@@ -2655,17 +2586,18 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots:
2655
2586
  basicBundle({
2656
2587
  readonly,
2657
2588
  themeMode,
2658
- placeholder: slots?.editor?.placeholder
2589
+ placeholder: placeholder3
2659
2590
  }),
2660
2591
  ...extensions
2661
2592
  ],
2662
- slots,
2593
+ theme,
2594
+ slots: updatedSlots,
2663
2595
  ...props
2664
2596
  });
2665
2597
  });
2666
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
2598
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = markdownTheme, slots, ...props }, forwardedRef) => {
2667
2599
  const { themeMode } = useThemeContext();
2668
- const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
2600
+ const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2669
2601
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2670
2602
  ref: forwardedRef,
2671
2603
  readonly,
@@ -2673,30 +2605,25 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], sl
2673
2605
  markdownBundle({
2674
2606
  readonly,
2675
2607
  themeMode,
2676
- placeholder: slots?.editor?.placeholder
2608
+ placeholder: placeholder3
2677
2609
  }),
2678
2610
  ...extensions
2679
2611
  ],
2680
- slots,
2612
+ theme,
2613
+ slots: updatedSlots,
2681
2614
  ...props
2682
2615
  });
2683
2616
  });
2684
2617
  var defaultSlots = {
2685
2618
  root: {
2686
- className: mx3("p-2", inputSurface)
2619
+ className: mx3("w-full p-2 overflow-y-auto", inputSurface)
2687
2620
  }
2688
2621
  };
2689
2622
  var defaultTextSlots = {
2690
- ...defaultSlots,
2691
- editor: {
2692
- theme: textTheme
2693
- }
2623
+ ...defaultSlots
2694
2624
  };
2695
2625
  var defaultMarkdownSlots = {
2696
- ...defaultSlots,
2697
- editor: {
2698
- theme: markdownTheme
2699
- }
2626
+ ...defaultSlots
2700
2627
  };
2701
2628
 
2702
2629
  // packages/ui/react-ui-editor/src/hooks/automerge.ts
@@ -2708,7 +2635,7 @@ import { isNotNullOrUndefined } from "@dxos/util";
2708
2635
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
2709
2636
  import { Context as Context2 } from "@dxos/context";
2710
2637
  import { invariant as invariant3 } from "@dxos/invariant";
2711
- import { log as log3 } from "@dxos/log";
2638
+ import { log as log2 } from "@dxos/log";
2712
2639
  var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
2713
2640
  var DEBOUNCE_INTERVAL = 100;
2714
2641
  var SpaceAwarenessProvider = class {
@@ -2747,7 +2674,7 @@ var SpaceAwarenessProvider = class {
2747
2674
  void this._space.postMessage(this._channel, {
2748
2675
  kind: "query"
2749
2676
  }).catch((err) => {
2750
- log3.debug("failed to query awareness", {
2677
+ log2.debug("failed to query awareness", {
2751
2678
  err
2752
2679
  }, {
2753
2680
  F: __dxlog_file4,
@@ -2819,15 +2746,13 @@ import * as decoding from "lib0/decoding";
2819
2746
  import * as encoding from "lib0/encoding";
2820
2747
  import { Observable } from "lib0/observable";
2821
2748
  import * as YP from "y-protocols/awareness";
2822
- import * as Y2 from "yjs";
2823
2749
  import { invariant as invariant4 } from "@dxos/invariant";
2824
- import { log as log4 } from "@dxos/log";
2825
- import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
2750
+ import { log as log3 } from "@dxos/log";
2826
2751
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
2827
2752
  var createYjsModel = ({ identity, space, text }) => {
2828
2753
  invariant4(text?.doc && text?.content, void 0, {
2829
2754
  F: __dxlog_file5,
2830
- L: 23,
2755
+ L: 21,
2831
2756
  S: void 0,
2832
2757
  A: [
2833
2758
  "text?.doc && text?.content",
@@ -2843,34 +2768,6 @@ var createYjsModel = ({ identity, space, text }) => {
2843
2768
  id: text.doc.guid,
2844
2769
  content: text.content,
2845
2770
  text: () => text.content.toString(),
2846
- // https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
2847
- // TODO(dmaretskyi): Refactor as cursor-converter.
2848
- getCursorFromRange: (range) => {
2849
- const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
2850
- const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
2851
- return [
2852
- arrayToString2(from),
2853
- arrayToString2(to)
2854
- ].join(":");
2855
- },
2856
- getRangeFromCursor: (cursor) => {
2857
- invariant4(text.doc, void 0, {
2858
- F: __dxlog_file5,
2859
- L: 40,
2860
- S: void 0,
2861
- A: [
2862
- "text.doc",
2863
- ""
2864
- ]
2865
- });
2866
- const parts = cursor.split(":");
2867
- const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
2868
- const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
2869
- return from && to ? {
2870
- from: from.index,
2871
- to: to.index
2872
- } : void 0;
2873
- },
2874
2771
  extension: [
2875
2772
  modelState.init(() => model),
2876
2773
  yjs(text.content, provider?.awareness)
@@ -2913,14 +2810,14 @@ var YAwarenessProvider = class extends Observable {
2913
2810
  return this._awareness;
2914
2811
  }
2915
2812
  _handleAwarenessUpdate({ added, updated, removed }, origin) {
2916
- log4("awareness update", {
2813
+ log3("awareness update", {
2917
2814
  added,
2918
2815
  updated,
2919
2816
  removed,
2920
2817
  origin
2921
2818
  }, {
2922
2819
  F: __dxlog_file5,
2923
- L: 122,
2820
+ L: 100,
2924
2821
  S: this,
2925
2822
  C: (f, a) => f(...a)
2926
2823
  });
@@ -2931,9 +2828,9 @@ var YAwarenessProvider = class extends Observable {
2931
2828
  void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
2932
2829
  }
2933
2830
  _handleSpaceMessage({ payload }) {
2934
- log4("space message", payload, {
2831
+ log3("space message", payload, {
2935
2832
  F: __dxlog_file5,
2936
- L: 131,
2833
+ L: 109,
2937
2834
  S: this,
2938
2835
  C: (f, a) => f(...a)
2939
2836
  });
@@ -2983,7 +2880,7 @@ var modelState = StateField5.define({
2983
2880
  });
2984
2881
  var useTextModel = (props) => {
2985
2882
  const { identity, space, text } = props;
2986
- const [model, setModel] = useState2(() => createModel(props));
2883
+ const [model, setModel] = useState2();
2987
2884
  useEffect2(() => setModel(createModel(props)), [
2988
2885
  identity,
2989
2886
  space,
@@ -3042,6 +2939,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
3042
2939
  export {
3043
2940
  AwarenessProvider,
3044
2941
  BaseTextEditor,
2942
+ Cursor,
3045
2943
  Doc,
3046
2944
  EditorModes,
3047
2945
  MarkdownEditor,
@@ -3057,6 +2955,7 @@ export {
3057
2955
  awareness,
3058
2956
  basicBundle,
3059
2957
  blast,
2958
+ callbackWrapper,
3060
2959
  code2 as code,
3061
2960
  codeTheme,
3062
2961
  comments,