@dxos/react-ui-editor 0.3.11-main.8d54a30 → 0.3.11-main.8feb6a5

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 (82) hide show
  1. package/dist/lib/browser/index.mjs +511 -569
  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 +9 -5
  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/cursor.d.ts +1 -1
  15. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  16. package/dist/types/src/extensions/automerge/index.d.ts +1 -0
  17. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  18. package/dist/types/src/extensions/code.d.ts.map +1 -1
  19. package/dist/types/src/extensions/comments.d.ts +6 -2
  20. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  21. package/dist/types/src/{util → extensions}/cursor.d.ts +9 -1
  22. package/dist/types/src/extensions/cursor.d.ts.map +1 -0
  23. package/dist/types/src/extensions/hr.d.ts.map +1 -1
  24. package/dist/types/src/extensions/image.d.ts.map +1 -1
  25. package/dist/types/src/extensions/index.d.ts +1 -1
  26. package/dist/types/src/extensions/index.d.ts.map +1 -1
  27. package/dist/types/src/extensions/link.d.ts.map +1 -1
  28. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  29. package/dist/types/src/extensions/tasklist.d.ts +5 -1
  30. package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
  31. package/dist/types/src/extensions/yjs/cursor.d.ts +1 -1
  32. package/dist/types/src/extensions/yjs/cursor.d.ts.map +1 -1
  33. package/dist/types/src/hooks/useTextModel.d.ts +0 -5
  34. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  35. package/dist/types/src/hooks/yjs.d.ts.map +1 -1
  36. package/dist/types/src/index.d.ts +3 -0
  37. package/dist/types/src/index.d.ts.map +1 -1
  38. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  39. package/dist/types/src/styles/tokens.d.ts +1 -0
  40. package/dist/types/src/styles/tokens.d.ts.map +1 -1
  41. package/dist/types/src/themes/default.d.ts.map +1 -1
  42. package/dist/types/src/util.d.ts.map +1 -0
  43. package/package.json +24 -23
  44. package/src/components/TextEditor/MarkdownEditor.stories.tsx +25 -23
  45. package/src/components/TextEditor/TextEditor.stories.tsx +12 -46
  46. package/src/components/TextEditor/TextEditor.tsx +68 -64
  47. package/src/components/TextEditor/comments.stories.tsx +329 -0
  48. package/src/extensions/autocomplete.ts +18 -17
  49. package/src/extensions/automerge/automerge.ts +2 -2
  50. package/src/extensions/automerge/cursor.ts +2 -1
  51. package/src/extensions/automerge/index.ts +1 -0
  52. package/src/extensions/awareness.ts +25 -32
  53. package/src/extensions/code.ts +14 -7
  54. package/src/extensions/comments.ts +89 -120
  55. package/src/extensions/cursor.ts +46 -0
  56. package/src/extensions/hr.ts +4 -5
  57. package/src/extensions/image.ts +40 -22
  58. package/src/extensions/index.ts +1 -1
  59. package/src/extensions/link.ts +86 -88
  60. package/src/extensions/markdown/highlight.ts +3 -12
  61. package/src/extensions/table.ts +10 -4
  62. package/src/extensions/tasklist.ts +53 -79
  63. package/src/extensions/yjs/cursor.ts +2 -1
  64. package/src/extensions/yjs/yjs.test.ts +1 -1
  65. package/src/extensions/yjs/yjs.ts +2 -2
  66. package/src/hooks/useTextModel.ts +4 -7
  67. package/src/hooks/yjs.ts +1 -23
  68. package/src/index.ts +3 -0
  69. package/src/styles/markdown.ts +0 -2
  70. package/src/styles/tokens.ts +3 -0
  71. package/src/themes/default.ts +51 -78
  72. package/dist/types/src/extensions/mermaid.d.ts +0 -3
  73. package/dist/types/src/extensions/mermaid.d.ts.map +0 -1
  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/extensions/mermaid.ts +0 -11
  79. package/src/util/cursor.ts +0 -29
  80. package/src/util/index.ts +0 -6
  81. /package/dist/types/src/{util/util.d.ts → util.d.ts} +0 -0
  82. /package/src/{util/util.ts → util.ts} +0 -0
@@ -7,44 +7,45 @@ import { tags as tags2 } from "@lezer/highlight";
7
7
 
8
8
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
9
9
  import { EditorState as EditorState2 } from "@codemirror/state";
10
- import { EditorView as EditorView13 } from "@codemirror/view";
10
+ 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
  };
@@ -273,30 +274,39 @@ var PatchSemaphore = class {
273
274
  }
274
275
  };
275
276
 
276
- // packages/ui/react-ui-editor/src/util/cursor.ts
277
+ // packages/ui/react-ui-editor/src/extensions/cursor.ts
277
278
  import { Facet } from "@codemirror/state";
278
- var DEFAULT_CURSOR_CONVERTER = {
279
+ var defaultCursorConverter = {
279
280
  toCursor: (position) => position.toString(),
280
281
  fromCursor: (cursor) => parseInt(cursor)
281
282
  };
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)
283
+ var Cursor = class {
284
+ static {
285
+ this.converter = Facet.define({
286
+ combine: (providers) => providers[0] ?? defaultCursorConverter
298
287
  });
299
288
  }
289
+ static {
290
+ this.getCursorFromRange = (cursorConverter3, range) => {
291
+ const from = cursorConverter3.toCursor(range.from);
292
+ const to = cursorConverter3.toCursor(range.to, -1);
293
+ return [
294
+ from,
295
+ to
296
+ ].join(":");
297
+ };
298
+ }
299
+ static {
300
+ this.getRangeFromCursor = (cursorConverter3, cursor) => {
301
+ const parts = cursor.split(":");
302
+ const from = cursorConverter3.fromCursor(parts[0]);
303
+ const to = cursorConverter3.fromCursor(parts[1]);
304
+ return from !== void 0 && to !== void 0 ? {
305
+ from,
306
+ to
307
+ } : void 0;
308
+ };
309
+ }
300
310
  };
301
311
 
302
312
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
@@ -342,8 +352,8 @@ var automerge3 = ({ handle, path }) => {
342
352
  };
343
353
  handle.addListener("change", this._handleChange);
344
354
  }
345
- update(update4) {
346
- if (update4.transactions.length > 0 && update4.transactions.some((tr) => !isReconcileTx(tr))) {
355
+ update(update2) {
356
+ if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
347
357
  queueMicrotask(() => {
348
358
  this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
349
359
  });
@@ -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, () => {
@@ -412,13 +422,13 @@ var RemoteSelectionsDecorator = class {
412
422
  void this._ctx.dispose();
413
423
  this._provider.close();
414
424
  }
415
- update(update4) {
416
- this._updateLocalSelection(update4);
417
- this._updateRemoteSelections(update4);
425
+ update(update2) {
426
+ this._updateLocalSelection(update2);
427
+ this._updateRemoteSelections(update2);
418
428
  }
419
- _updateLocalSelection(update4) {
420
- const hasFocus = update4.view.hasFocus && update4.view.dom.ownerDocument.hasFocus();
421
- const { anchor = void 0, head = void 0 } = hasFocus ? update4.state.selection.main : {};
429
+ _updateLocalSelection(update2) {
430
+ const hasFocus = update2.view.hasFocus && update2.view.dom.ownerDocument.hasFocus();
431
+ const { anchor = void 0, head = void 0 } = hasFocus ? update2.state.selection.main : {};
422
432
  if (this._lastAnchor === anchor && this._lastHead === head) {
423
433
  return;
424
434
  }
@@ -429,7 +439,7 @@ var RemoteSelectionsDecorator = class {
429
439
  head: this._cursorConverter.toCursor(head)
430
440
  } : void 0);
431
441
  }
432
- _updateRemoteSelections(update4) {
442
+ _updateRemoteSelections(update2) {
433
443
  const decorations = [];
434
444
  const awarenessStates = this._provider.getRemoteStates();
435
445
  for (const state of awarenessStates) {
@@ -438,10 +448,10 @@ var RemoteSelectionsDecorator = class {
438
448
  if (anchor == null || head == null) {
439
449
  continue;
440
450
  }
441
- const start = Math.min(Math.min(anchor, head), update4.view.state.doc.length);
442
- const end = Math.min(Math.max(anchor, head), update4.view.state.doc.length);
443
- const startLine = update4.view.state.doc.lineAt(start);
444
- const endLine = update4.view.state.doc.lineAt(end);
451
+ const start = Math.min(Math.min(anchor, head), update2.view.state.doc.length);
452
+ const end = Math.min(Math.max(anchor, head), update2.view.state.doc.length);
453
+ const startLine = update2.view.state.doc.lineAt(start);
454
+ const endLine = update2.view.state.doc.lineAt(end);
445
455
  const color = state.info.color ?? "#30bced";
446
456
  const lightColor = state.info.lightColor ?? color + "33";
447
457
  if (startLine.number === endLine.number) {
@@ -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,18 +483,18 @@ 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++) {
480
- const linePos = update4.view.state.doc.line(i).from;
490
+ const linePos = update2.view.state.doc.line(i).from;
481
491
  decorations.push({
482
492
  from: linePos,
483
493
  to: linePos,
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",
@@ -595,7 +600,7 @@ var styles = EditorView.baseTheme({
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,
@@ -667,12 +672,12 @@ var blast = (options = defaultOptions) => {
667
672
  };
668
673
  return [
669
674
  // Cursor moved.
670
- EditorView3.updateListener.of((update4) => {
671
- if (blaster?.node !== update4.view.scrollDOM) {
675
+ EditorView3.updateListener.of((update2) => {
676
+ if (blaster?.node !== update2.view.scrollDOM) {
672
677
  if (blaster) {
673
678
  blaster.destroy();
674
679
  }
675
- blaster = new Blaster(update4.view.scrollDOM, defaultsDeep({
680
+ blaster = new Blaster(update2.view.scrollDOM, defaultsDeep({
676
681
  particleGravity: 0.2,
677
682
  particleShrinkRate: 0.995,
678
683
  color: () => [
@@ -686,10 +691,10 @@ var blast = (options = defaultOptions) => {
686
691
  } else {
687
692
  blaster.resize();
688
693
  }
689
- const current = update4.state.selection.main.head;
694
+ const current = update2.state.selection.main.head;
690
695
  if (current !== last) {
691
696
  last = current;
692
- const { element, point } = getPoint(update4.view, current - 1);
697
+ const { element, point } = getPoint(update2.view, current - 1);
693
698
  if (element && point) {
694
699
  blaster.spawn({
695
700
  element,
@@ -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: [
@@ -930,7 +935,6 @@ var random = (min, max) => {
930
935
 
931
936
  // packages/ui/react-ui-editor/src/extensions/code.ts
932
937
  import { ViewPlugin as ViewPlugin3, EditorView as EditorView4, Decoration as Decoration2 } from "@codemirror/view";
933
- import get2 from "lodash.get";
934
938
  import { mx as mx2 } from "@dxos/react-ui-theme";
935
939
 
936
940
  // packages/ui/react-ui-editor/src/styles/cursors.ts
@@ -1014,20 +1018,22 @@ var inlineUrl = mx(code, "px-1");
1014
1018
  var blockquote = mx("pl-1 mr-1 border-is-4 border-primary-500/70 dark:border-primary-500/30", light);
1015
1019
 
1016
1020
  // packages/ui/react-ui-editor/src/styles/tokens.ts
1021
+ import get2 from "lodash.get";
1017
1022
  import { tailwindConfig } from "@dxos/react-ui-theme";
1018
1023
  var tokens = tailwindConfig({}).theme;
1024
+ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1019
1025
 
1020
1026
  // packages/ui/react-ui-editor/src/extensions/code.ts
1021
1027
  var CODE_REGEX = /```[\s\S]*?```/gs;
1022
1028
  var styles2 = EditorView4.baseTheme({
1023
1029
  "& .cm-codeblock": {
1024
- fontFamily: get2(tokens, "fontFamily.mono", []).join(",")
1030
+ fontFamily: getToken("fontFamily.mono", []).join(",")
1025
1031
  },
1026
1032
  '&light [aria-readonly="true"] .cm-codeblock': {
1027
- background: get2(tokens, "extend.colors.neutral.50")
1033
+ background: getToken("extend.colors.neutral.50")
1028
1034
  },
1029
1035
  '&dark [aria-readonly="true"] .cm-codeblock': {
1030
- background: get2(tokens, "extend.colors.neutral.850")
1036
+ background: getToken("extend.colors.neutral.850")
1031
1037
  },
1032
1038
  '& [aria-readonly="true"] .cm-codeblock': {
1033
1039
  display: "block",
@@ -1055,7 +1061,7 @@ var getLineRange = (lines, from, to) => {
1055
1061
  var code2 = () => {
1056
1062
  const getDecorations = (view) => {
1057
1063
  const decorations = [];
1058
- if (view.state.readOnly) {
1064
+ if (!view.hasFocus || view.state.readOnly) {
1059
1065
  const text = view.state.doc.sliceString(0);
1060
1066
  const matches = text.matchAll(CODE_REGEX);
1061
1067
  const blocks = view.viewportLineBlocks;
@@ -1074,11 +1080,16 @@ var code2 = () => {
1074
1080
  return [
1075
1081
  ViewPlugin3.fromClass(class {
1076
1082
  constructor(view) {
1083
+ this.hasFocus = false;
1077
1084
  this.decorations = getDecorations(view);
1078
1085
  }
1079
- update(update4) {
1080
- if (update4.docChanged || update4.viewportChanged) {
1081
- this.decorations = getDecorations(update4.view);
1086
+ update(update2) {
1087
+ if (
1088
+ // TODO(burdon): Generalize for other extensions.
1089
+ this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1090
+ ) {
1091
+ this.hasFocus = update2.view.hasFocus;
1092
+ this.decorations = getDecorations(update2.view);
1082
1093
  }
1083
1094
  }
1084
1095
  }, {
@@ -1090,29 +1101,37 @@ var code2 = () => {
1090
1101
 
1091
1102
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1092
1103
  import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1093
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1094
- import get3 from "lodash.get";
1104
+ import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
1095
1105
  import sortBy from "lodash.sortby";
1096
1106
  import { debounce } from "@dxos/async";
1097
1107
  import { invariant as invariant2 } from "@dxos/invariant";
1098
1108
  import { log as log2 } from "@dxos/log";
1099
1109
  import { nonNullable } from "@dxos/util";
1110
+
1111
+ // packages/ui/react-ui-editor/src/util.ts
1112
+ import { log } from "@dxos/log";
1113
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1114
+ var callbackWrapper = (fn) => (...args) => {
1115
+ try {
1116
+ return fn(...args);
1117
+ } catch (error) {
1118
+ log.catch(error, void 0, {
1119
+ F: __dxlog_file2,
1120
+ L: 16,
1121
+ S: void 0,
1122
+ C: (f, a) => f(...a)
1123
+ });
1124
+ }
1125
+ };
1126
+
1127
+ // packages/ui/react-ui-editor/src/extensions/comments.ts
1100
1128
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1101
1129
  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
1130
  "& .cm-comment": {
1112
- backgroundColor: get3(tokens, "extend.colors.yellow.50")
1131
+ backgroundColor: getToken("extend.colors.yellow.50")
1113
1132
  },
1114
1133
  "& .cm-comment-active": {
1115
- backgroundColor: get3(tokens, "extend.colors.yellow.100")
1134
+ backgroundColor: getToken("extend.colors.yellow.100")
1116
1135
  }
1117
1136
  });
1118
1137
  var marks = {
@@ -1146,7 +1165,7 @@ var commentsStateField = StateField2.define({
1146
1165
  ranges: []
1147
1166
  }),
1148
1167
  update: (value, tr) => {
1149
- const cursorConverter3 = tr.state.facet(CursorConverter);
1168
+ const cursorConverter3 = tr.state.facet(Cursor.converter);
1150
1169
  for (const effect of tr.effects) {
1151
1170
  if (effect.is(setSelection)) {
1152
1171
  return {
@@ -1157,7 +1176,7 @@ var commentsStateField = StateField2.define({
1157
1176
  if (effect.is(setCommentRange)) {
1158
1177
  const { comments: comments2 } = effect.value;
1159
1178
  const ranges = comments2.map((comment) => {
1160
- const range = getRangeFromCursor(cursorConverter3, comment.cursor);
1179
+ const range = Cursor.getRangeFromCursor(cursorConverter3, comment.cursor);
1161
1180
  return range && {
1162
1181
  ...comment,
1163
1182
  ...range
@@ -1195,42 +1214,68 @@ var highlightDecorations = EditorView5.decorations.compute([
1195
1214
  }).filter(nonNullable) ?? [];
1196
1215
  return Decoration3.set(decorations);
1197
1216
  });
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: 169,
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();
1217
+ var trackPastedComments = (onMove) => {
1218
+ let tracked = null;
1219
+ const registerCopy = (event, view) => {
1220
+ const comments2 = view.state.field(commentsStateField);
1221
+ const { main } = view.state.selection;
1222
+ const inSel = comments2.ranges.filter((range) => range.from >= main.from && range.to <= main.to && range.from < range.to);
1223
+ if (!inSel.length) {
1224
+ tracked = null;
1225
+ } else {
1226
+ tracked = {
1227
+ text: view.state.doc.slice(main.from, main.to),
1228
+ comments: inSel.map((range) => ({
1229
+ from: range.from - main.from,
1230
+ to: range.to - main.from,
1231
+ id: range.id
1232
+ }))
1233
+ };
1223
1234
  }
1224
- return span;
1225
- }
1235
+ };
1236
+ return [
1237
+ EditorView5.domEventHandlers({
1238
+ cut: registerCopy,
1239
+ copy: registerCopy
1240
+ }),
1241
+ EditorView5.updateListener.of((update2) => {
1242
+ if (tracked) {
1243
+ const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
1244
+ if (paste) {
1245
+ let found = -1;
1246
+ paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
1247
+ if (text.eq(tracked.text)) {
1248
+ for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
1249
+ fromB = update2.transactions[i].changes.mapPos(fromB);
1250
+ }
1251
+ found = fromB;
1252
+ }
1253
+ });
1254
+ if (found > -1) {
1255
+ const active = update2.view.state.field(commentsStateField).ranges;
1256
+ for (const moved of tracked.comments) {
1257
+ if (active.some((range) => range.id === moved.id && range.from === range.to)) {
1258
+ onMove(moved.id, Cursor.getCursorFromRange(update2.view.state.facet(Cursor.converter), {
1259
+ from: found + moved.from,
1260
+ to: found + moved.to
1261
+ }));
1262
+ }
1263
+ }
1264
+ }
1265
+ tracked = null;
1266
+ }
1267
+ }
1268
+ })
1269
+ ];
1226
1270
  };
1227
1271
  var comments = (options = {}) => {
1272
+ const { key: shortcut = "meta-'" } = options;
1228
1273
  const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1229
1274
  const createCommentThread = (view) => {
1230
- const cursorConverter3 = view.state.facet(CursorConverter);
1275
+ const cursorConverter3 = view.state.facet(Cursor.converter);
1231
1276
  invariant2(options.onCreate, void 0, {
1232
1277
  F: __dxlog_file3,
1233
- L: 225,
1278
+ L: 240,
1234
1279
  S: void 0,
1235
1280
  A: [
1236
1281
  "options.onCreate",
@@ -1241,12 +1286,12 @@ var comments = (options = {}) => {
1241
1286
  if (from === to) {
1242
1287
  return false;
1243
1288
  }
1244
- const relPos = getCursorFromRange(cursorConverter3, {
1289
+ const cursor = Cursor.getCursorFromRange(cursorConverter3, {
1245
1290
  from,
1246
1291
  to
1247
1292
  });
1248
- if (relPos) {
1249
- const id = callbackWrapper(options.onCreate)(relPos);
1293
+ if (cursor) {
1294
+ const id = callbackWrapper(options.onCreate)(cursor, view.coordsAtPos(from));
1250
1295
  if (id) {
1251
1296
  view.dispatch({
1252
1297
  effects: setSelection.of({
@@ -1273,35 +1318,7 @@ var comments = (options = {}) => {
1273
1318
  }
1274
1319
  return false;
1275
1320
  };
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(update4) {
1295
- this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update4, 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
1321
  return [
1304
- bookmarksViewPlugin,
1305
1322
  commentsStateField,
1306
1323
  highlightDecorations,
1307
1324
  styles3,
@@ -1310,7 +1327,7 @@ var comments = (options = {}) => {
1310
1327
  //
1311
1328
  options.onCreate ? keymap3.of([
1312
1329
  {
1313
- key: options?.key ?? "meta-'",
1330
+ key: shortcut,
1314
1331
  run: callbackWrapper(createCommentThread)
1315
1332
  }
1316
1333
  ]) : [],
@@ -1327,7 +1344,7 @@ var comments = (options = {}) => {
1327
1344
  above: true,
1328
1345
  create: () => {
1329
1346
  const el = document.createElement("div");
1330
- options.onHover?.(el);
1347
+ options.onHover?.(el, shortcut);
1331
1348
  return {
1332
1349
  dom: el,
1333
1350
  offset: {
@@ -1348,27 +1365,27 @@ var comments = (options = {}) => {
1348
1365
  // TODO(burdon): Is there a better (finer grained) way to do this?
1349
1366
  //
1350
1367
  EditorView5.updateListener.of(({ view, state, changes }) => {
1351
- const cursorConverter3 = view.state.facet(CursorConverter);
1368
+ const cursorConverter3 = view.state.facet(Cursor.converter);
1352
1369
  {
1353
1370
  let mod = false;
1354
1371
  const { active, ranges } = state.field(commentsStateField);
1355
1372
  changes.iterChanges((from, to, from2, to2) => {
1356
1373
  ranges.forEach((range) => {
1357
1374
  if (from2 === to2) {
1358
- const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
1375
+ const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1359
1376
  if (!newRange || newRange.to - newRange.from === 0) {
1360
1377
  log2.info("deleted comment", {
1361
1378
  thread: range.id
1362
1379
  }, {
1363
1380
  F: __dxlog_file3,
1364
- L: 359,
1381
+ L: 337,
1365
1382
  S: void 0,
1366
1383
  C: (f, a) => f(...a)
1367
1384
  });
1368
1385
  }
1369
1386
  }
1370
1387
  if (from <= range.to) {
1371
- const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
1388
+ const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1372
1389
  Object.assign(range, newRange);
1373
1390
  mod = true;
1374
1391
  }
@@ -1414,38 +1431,21 @@ var comments = (options = {}) => {
1414
1431
  });
1415
1432
  }
1416
1433
  }
1417
- })
1434
+ }),
1435
+ options.onMove ? trackPastedComments(options.onMove) : []
1418
1436
  ];
1419
1437
  };
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 && to ? {
1433
- from,
1434
- to
1435
- } : void 0;
1436
- };
1437
1438
 
1438
1439
  // 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";
1440
- import get4 from "lodash.get";
1440
+ import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1441
1441
  var styles4 = EditorView6.baseTheme({
1442
1442
  "& .cm-hr": {
1443
1443
  // TODO(burdon): ???
1444
1444
  // Note that block-level decorations should not have vertical margins,
1445
- borderBottom: `1px solid ${get4(tokens, "extend.colors.neutral.200")}`
1445
+ borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
1446
1446
  }
1447
1447
  });
1448
- var HorizontalRuleWidget = class extends WidgetType3 {
1448
+ var HorizontalRuleWidget = class extends WidgetType2 {
1449
1449
  constructor(_pos) {
1450
1450
  super();
1451
1451
  this._pos = _pos;
@@ -1459,7 +1459,7 @@ var HorizontalRuleWidget = class extends WidgetType3 {
1459
1459
  return el;
1460
1460
  }
1461
1461
  };
1462
- var placeholderMatcher = new MatchDecorator2({
1462
+ var placeholderMatcher = new MatchDecorator({
1463
1463
  regexp: /^---$/g,
1464
1464
  decoration: (match, view, pos) => Decoration4.replace({
1465
1465
  widget: new HorizontalRuleWidget(pos)
@@ -1467,12 +1467,12 @@ var placeholderMatcher = new MatchDecorator2({
1467
1467
  });
1468
1468
  var hr = () => [
1469
1469
  styles4,
1470
- ViewPlugin5.fromClass(class {
1470
+ ViewPlugin4.fromClass(class {
1471
1471
  constructor(view) {
1472
1472
  this.rules = placeholderMatcher.createDeco(view);
1473
1473
  }
1474
- update(update4) {
1475
- this.rules = placeholderMatcher.updateDeco(update4, this.rules);
1474
+ update(update2) {
1475
+ this.rules = placeholderMatcher.updateDeco(update2, this.rules);
1476
1476
  }
1477
1477
  }, {
1478
1478
  decorations: (instance) => instance.rules,
@@ -1485,17 +1485,39 @@ var hr = () => [
1485
1485
 
1486
1486
  // packages/ui/react-ui-editor/src/extensions/image.ts
1487
1487
  import { syntaxTree } from "@codemirror/language";
1488
- import { RangeSetBuilder, StateField as StateField3 } from "@codemirror/state";
1489
- import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
1488
+ import { StateField as StateField3 } from "@codemirror/state";
1489
+ import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
1490
1490
  var image = (options = {}) => {
1491
1491
  return StateField3.define({
1492
- create: (state) => update(state, options),
1493
- update: (_, tr) => update(tr.state, options),
1492
+ create: (state) => {
1493
+ return Decoration5.set(buildDecorations(0, state.doc.length, state));
1494
+ },
1495
+ update: (value, tr) => {
1496
+ if (!tr.docChanged && !tr.selection) {
1497
+ return value;
1498
+ }
1499
+ const cursor = tr.state.selection.main.head;
1500
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
1501
+ let from = Math.min(cursor, oldCursor);
1502
+ let to = Math.max(cursor, oldCursor);
1503
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
1504
+ from = Math.min(from, fromB);
1505
+ to = Math.max(to, toB);
1506
+ });
1507
+ from = tr.state.doc.lineAt(from).from;
1508
+ to = tr.state.doc.lineAt(to).to;
1509
+ return value.map(tr.changes).update({
1510
+ filterFrom: from,
1511
+ filterTo: to,
1512
+ filter: () => false,
1513
+ add: buildDecorations(from, to, tr.state)
1514
+ });
1515
+ },
1494
1516
  provide: (field) => EditorView7.decorations.from(field)
1495
1517
  });
1496
1518
  };
1497
- var update = (state, options) => {
1498
- const builder = new RangeSetBuilder();
1519
+ var buildDecorations = (from, to, state) => {
1520
+ const decorations = [];
1499
1521
  const cursor = state.selection.main.head;
1500
1522
  syntaxTree(state).iterate({
1501
1523
  enter: (node) => {
@@ -1504,22 +1526,23 @@ var update = (state, options) => {
1504
1526
  if (urlNode) {
1505
1527
  const hide = state.readOnly || cursor < node.from || cursor > node.to;
1506
1528
  const url = state.sliceDoc(urlNode.from, urlNode.to);
1507
- builder.add(hide ? node.from : node.to, node.to, Decoration5.replace({
1529
+ decorations.push(Decoration5.replace({
1508
1530
  block: true,
1509
1531
  widget: new ImageWidget(url)
1510
- }));
1532
+ }).range(hide ? node.from : node.to, node.to));
1511
1533
  }
1512
1534
  }
1513
- }
1535
+ },
1536
+ from,
1537
+ to
1514
1538
  });
1515
- return builder.finish();
1539
+ return decorations;
1516
1540
  };
1517
- var ImageWidget = class extends WidgetType4 {
1541
+ var ImageWidget = class extends WidgetType3 {
1518
1542
  constructor(_url) {
1519
1543
  super();
1520
1544
  this._url = _url;
1521
1545
  }
1522
- // TODO(burdon): Does this need to be unique for each position?
1523
1546
  eq(other) {
1524
1547
  return this._url === other._url;
1525
1548
  }
@@ -1527,22 +1550,29 @@ var ImageWidget = class extends WidgetType4 {
1527
1550
  const img = document.createElement("img");
1528
1551
  img.setAttribute("src", this._url);
1529
1552
  img.setAttribute("class", "cm-image");
1553
+ img.onload = () => img.classList.add("cm-loaded-image");
1530
1554
  return img;
1531
1555
  }
1532
1556
  };
1533
1557
 
1534
1558
  // packages/ui/react-ui-editor/src/extensions/link.ts
1535
1559
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1536
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
1537
- import { Decoration as Decoration6, EditorView as EditorView8, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2 } from "@codemirror/view";
1560
+ import { RangeSetBuilder } from "@codemirror/state";
1561
+ import { Decoration as Decoration6, WidgetType as WidgetType4, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
1538
1562
  import { tooltipContent } from "@dxos/react-ui-theme";
1539
- var markdownLinkRegexp = /\[([^\]]+)]\(([^)]+)\)/;
1540
1563
  var link = (options = {}) => {
1541
1564
  const extensions = [
1542
- StateField4.define({
1543
- create: (state) => update2(state, options),
1544
- update: (_, tr) => update2(tr.state, options),
1545
- provide: (field) => EditorView8.decorations.from(field)
1565
+ ViewPlugin5.fromClass(class {
1566
+ constructor(view) {
1567
+ this.decorations = buildDecorations2(view, options);
1568
+ }
1569
+ update(update2) {
1570
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
1571
+ this.decorations = buildDecorations2(update2.view, options);
1572
+ }
1573
+ }
1574
+ }, {
1575
+ decorations: (v) => v.decorations
1546
1576
  })
1547
1577
  ];
1548
1578
  if (options.onHover) {
@@ -1550,35 +1580,25 @@ var link = (options = {}) => {
1550
1580
  // https://codemirror.net/examples/tooltip
1551
1581
  // https://codemirror.net/docs/ref/#view.hoverTooltip
1552
1582
  // https://github.com/codemirror/view/blob/main/src/tooltip.ts
1553
- hoverTooltip2((view, pos) => {
1554
- const { from, text } = view.state.doc.lineAt(pos);
1555
- const p = pos - from;
1556
- let idx = 0;
1557
- let match;
1558
- do {
1559
- match = text.substring(idx).match(markdownLinkRegexp);
1560
- if (!match) {
1561
- match = void 0;
1562
- break;
1563
- }
1564
- idx = text.indexOf(match[0]);
1565
- if (p >= idx && p < idx + match[0].length) {
1566
- break;
1567
- }
1568
- idx += match[0].length;
1569
- } while (true);
1570
- if (!match) {
1583
+ hoverTooltip2((view, pos, side) => {
1584
+ const syntax = syntaxTree2(view.state).resolveInner(pos, side);
1585
+ let link2 = null;
1586
+ for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
1587
+ link2 = node.name === "Link" ? node : null;
1588
+ }
1589
+ const url = link2 && link2.getChild("URL");
1590
+ if (!url || !link2) {
1571
1591
  return null;
1572
1592
  }
1573
- const [, , url] = match ?? [];
1593
+ const urlText = view.state.sliceDoc(url.from, url.to);
1574
1594
  return {
1575
- pos: idx + from,
1576
- end: idx + from + match[0].length,
1595
+ pos: link2.from,
1596
+ end: link2.to,
1577
1597
  above: true,
1578
1598
  create: () => {
1579
1599
  const el = document.createElement("div");
1580
1600
  el.className = tooltipContent({}, "pli-2 plb-1");
1581
- options.onHover(el, url);
1601
+ options.onHover(el, urlText);
1582
1602
  return {
1583
1603
  dom: el,
1584
1604
  offset: {
@@ -1593,15 +1613,14 @@ var link = (options = {}) => {
1593
1613
  }
1594
1614
  return extensions;
1595
1615
  };
1596
- var LinkButton = class extends WidgetType5 {
1597
- constructor(_pos, _url, _onAttach) {
1616
+ var LinkButton = class extends WidgetType4 {
1617
+ constructor(_url, _onAttach) {
1598
1618
  super();
1599
- this._pos = _pos;
1600
1619
  this._url = _url;
1601
1620
  this._onAttach = _onAttach;
1602
1621
  }
1603
1622
  eq(other) {
1604
- return this._pos === other._pos && this._url === other._url;
1623
+ return this._url === other._url;
1605
1624
  }
1606
1625
  toDOM(view) {
1607
1626
  const el = document.createElement("span");
@@ -1609,7 +1628,7 @@ var LinkButton = class extends WidgetType5 {
1609
1628
  return el;
1610
1629
  }
1611
1630
  };
1612
- var LinkText = class extends WidgetType5 {
1631
+ var LinkText = class extends WidgetType4 {
1613
1632
  constructor(_text, _url) {
1614
1633
  super();
1615
1634
  this._text = _text;
@@ -1638,46 +1657,51 @@ var LinkText = class extends WidgetType5 {
1638
1657
  return link2;
1639
1658
  }
1640
1659
  };
1641
- var update2 = (state, options) => {
1642
- const builder = new RangeSetBuilder2();
1660
+ var buildDecorations2 = (view, options) => {
1661
+ const builder = new RangeSetBuilder();
1662
+ const { state } = view;
1643
1663
  const cursor = state.selection.main.head;
1644
- syntaxTree2(state).iterate({
1645
- enter: (node) => {
1646
- if (node.name === "Link") {
1647
- const marks2 = node.node.getChildren("LinkMark");
1648
- const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
1649
- const urlNode = node.node.getChild("URL");
1650
- const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
1651
- if (!url) {
1664
+ for (const { from, to } of view.visibleRanges) {
1665
+ syntaxTree2(state).iterate({
1666
+ enter: (node) => {
1667
+ if (node.name === "Link") {
1668
+ const marks2 = node.node.getChildren("LinkMark");
1669
+ const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
1670
+ const urlNode = node.node.getChild("URL");
1671
+ const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
1672
+ if (!url) {
1673
+ return false;
1674
+ }
1675
+ if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
1676
+ builder.add(node.from, node.to, Decoration6.replace({
1677
+ widget: new LinkText(text, options.link ? url : void 0)
1678
+ }));
1679
+ }
1680
+ if (options.onRender) {
1681
+ builder.add(node.to, node.to, Decoration6.replace({
1682
+ widget: new LinkButton(url, options.onRender)
1683
+ }));
1684
+ }
1652
1685
  return false;
1653
1686
  }
1654
- if (state.readOnly || cursor < node.from || cursor > node.to) {
1655
- builder.add(node.from, node.to, Decoration6.replace({
1656
- widget: new LinkText(text, options.link ? url : void 0)
1657
- }));
1658
- }
1659
- if (options.onRender) {
1660
- builder.add(node.to, node.to, Decoration6.replace({
1661
- widget: new LinkButton(node.from, url, options.onRender)
1662
- }));
1663
- }
1664
- return false;
1665
- }
1666
- }
1667
- });
1687
+ },
1688
+ from,
1689
+ to
1690
+ });
1691
+ }
1668
1692
  return builder.finish();
1669
1693
  };
1670
1694
 
1671
1695
  // packages/ui/react-ui-editor/src/extensions/listener.ts
1672
- import { EditorView as EditorView9 } from "@codemirror/view";
1696
+ import { EditorView as EditorView8 } from "@codemirror/view";
1673
1697
  var listener = ({ onFocus, onChange }) => {
1674
1698
  const extensions = [];
1675
- onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
1699
+ onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
1676
1700
  onFocus(focused);
1677
1701
  return null;
1678
1702
  }));
1679
- onChange && extensions.push(EditorView9.updateListener.of((update4) => {
1680
- onChange(update4.state.doc.toString());
1703
+ onChange && extensions.push(EditorView8.updateListener.of((update2) => {
1704
+ onChange(update2.state.doc.toString());
1681
1705
  }));
1682
1706
  return extensions;
1683
1707
  };
@@ -1685,27 +1709,25 @@ var listener = ({ onFocus, onChange }) => {
1685
1709
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1686
1710
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1687
1711
  import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1688
- import { markdownLanguage as markdownLanguage2, markdown } from "@codemirror/lang-markdown";
1712
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1689
1713
  import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1690
1714
  import { languages } from "@codemirror/language-data";
1691
1715
  import { searchKeymap } from "@codemirror/search";
1692
1716
  import { EditorState } from "@codemirror/state";
1693
1717
  import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1694
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1718
+ import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1695
1719
 
1696
1720
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1697
- import { markdownLanguage } from "@codemirror/lang-markdown";
1721
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1698
1722
  import { HighlightStyle } from "@codemirror/language";
1699
1723
  import { tags, styleTags, Tag } from "@lezer/highlight";
1700
1724
  import { Table } from "@lezer/markdown";
1701
- import get5 from "lodash.get";
1702
1725
  var markdownTags = {
1703
1726
  Blockquote: Tag.define(),
1704
1727
  CodeMark: Tag.define(),
1705
1728
  CodeText: Tag.define(),
1706
1729
  EmphasisMark: Tag.define(),
1707
1730
  HeaderMark: Tag.define(),
1708
- // HorizontalRule: Tag.define(),
1709
1731
  InlineCode: Tag.define(),
1710
1732
  LinkLabel: Tag.define(),
1711
1733
  LinkReference: Tag.define(),
@@ -1869,12 +1891,6 @@ var markdownHighlightStyle = (readonly) => {
1869
1891
  ],
1870
1892
  class: blockquote
1871
1893
  },
1872
- // TODO(burdon): Replace with extension.
1873
- // {
1874
- // tag: [markdownTags.HorizontalRule],
1875
- // class: mx(horizontalRule, readonly && '-indent-[100rem]'),
1876
- // },
1877
- // TODO(burdon): Only if being edited.
1878
1894
  {
1879
1895
  tag: [
1880
1896
  markdownTags.TableCell
@@ -1882,9 +1898,9 @@ var markdownHighlightStyle = (readonly) => {
1882
1898
  class: "font-mono"
1883
1899
  }
1884
1900
  ], {
1885
- scope: markdownLanguage,
1901
+ scope: markdownLanguage2,
1886
1902
  all: {
1887
- fontFamily: get5(tokens, "fontFamily.body", []).join(",")
1903
+ fontFamily: getToken("fontFamily.body", []).join(",")
1888
1904
  }
1889
1905
  });
1890
1906
  };
@@ -1894,7 +1910,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1894
1910
  return [
1895
1911
  EditorState.allowMultipleSelections.of(true),
1896
1912
  EditorState.tabSize.of(2),
1897
- EditorView10.lineWrapping,
1913
+ EditorView9.lineWrapping,
1898
1914
  customKeymap(),
1899
1915
  bracketMatching2(),
1900
1916
  closeBrackets2(),
@@ -1914,7 +1930,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1914
1930
  // NOTE: This extends the parser; it doesn't affect rendering.
1915
1931
  // https://github.github.com/gfm
1916
1932
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
1917
- base: markdownLanguage2,
1933
+ base: markdownLanguage3,
1918
1934
  // Languages for syntax highlighting fenced code blocks.
1919
1935
  codeLanguages: languages,
1920
1936
  // Parser extensions.
@@ -1965,24 +1981,19 @@ var mention = ({ onSearch }) => {
1965
1981
  });
1966
1982
  };
1967
1983
 
1968
- // packages/ui/react-ui-editor/src/extensions/mermaid.ts
1969
- var mermaid = () => {
1970
- return [];
1971
- };
1972
-
1973
1984
  // packages/ui/react-ui-editor/src/extensions/table.ts
1974
1985
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1975
- import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField5 } from "@codemirror/state";
1976
- import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
1986
+ import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
1987
+ import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType5 } from "@codemirror/view";
1977
1988
  var table = (options = {}) => {
1978
- return StateField5.define({
1979
- create: (state) => update3(state, options),
1980
- update: (_, tr) => update3(tr.state, options),
1981
- provide: (field) => EditorView11.decorations.from(field)
1989
+ return StateField4.define({
1990
+ create: (state) => update(state, options),
1991
+ update: (_, tr) => update(tr.state, options),
1992
+ provide: (field) => EditorView10.decorations.from(field)
1982
1993
  });
1983
1994
  };
1984
- var update3 = (state, options) => {
1985
- const builder = new RangeSetBuilder3();
1995
+ var update = (state, options) => {
1996
+ const builder = new RangeSetBuilder2();
1986
1997
  const cursor = state.selection.main.head;
1987
1998
  const tables = [];
1988
1999
  const getTable = () => tables[tables.length - 1];
@@ -2023,7 +2034,6 @@ var update3 = (state, options) => {
2023
2034
  tables.forEach((table2) => {
2024
2035
  const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
2025
2036
  hide && builder.add(table2.from, table2.to, Decoration7.replace({
2026
- block: true,
2027
2037
  widget: new TableWidget(table2)
2028
2038
  }));
2029
2039
  builder.add(table2.from, table2.to, Decoration7.mark({
@@ -2032,13 +2042,13 @@ var update3 = (state, options) => {
2032
2042
  });
2033
2043
  return builder.finish();
2034
2044
  };
2035
- var TableWidget = class extends WidgetType6 {
2045
+ var TableWidget = class extends WidgetType5 {
2036
2046
  constructor(_table) {
2037
2047
  super();
2038
2048
  this._table = _table;
2039
2049
  }
2040
2050
  eq(other) {
2041
- return this._table.from === other?._table?.from;
2051
+ return this._table.header?.join() === other._table.header?.join() && this._table.rows?.join() === other._table.rows?.join();
2042
2052
  }
2043
2053
  toDOM(view) {
2044
2054
  const table2 = document.createElement("table");
@@ -2064,91 +2074,91 @@ var TableWidget = class extends WidgetType6 {
2064
2074
  }
2065
2075
  return table2;
2066
2076
  }
2077
+ ignoreEvent(e) {
2078
+ return !/^mouse/.test(e.type);
2079
+ }
2067
2080
  };
2068
2081
 
2069
2082
  // packages/ui/react-ui-editor/src/extensions/tasklist.ts
2070
- import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType7, MatchDecorator as MatchDecorator3, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
2071
- var styles5 = EditorView12.baseTheme({
2072
- "& .cm-task-item": {
2073
- paddingLeft: "4px",
2074
- paddingRight: "8px"
2075
- }
2076
- });
2077
- var CheckboxWidget = class extends WidgetType7 {
2078
- constructor(_pos, _checked, _indent, _onCheck) {
2083
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2084
+ import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
2085
+ import { EditorView as EditorView11, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
2086
+ var CheckboxWidget = class extends WidgetType6 {
2087
+ constructor(_checked) {
2079
2088
  super();
2080
- this._pos = _pos;
2081
2089
  this._checked = _checked;
2082
- this._indent = _indent;
2083
- this._onCheck = _onCheck;
2084
2090
  }
2085
2091
  eq(other) {
2086
- return this._pos === other._pos && this._checked === other._checked && this._indent === other._indent;
2092
+ return this._checked === other._checked;
2087
2093
  }
2088
2094
  toDOM(view) {
2089
- const wrap = document.createElement("span");
2090
- wrap.className = "cm-task-item";
2091
- wrap.setAttribute("aria-hidden", "true");
2092
- wrap.style.setProperty("margin-left", this._indent * 24 + "px");
2093
- const input = wrap.appendChild(document.createElement("input"));
2095
+ const input = document.createElement("input");
2094
2096
  input.type = "checkbox";
2095
2097
  input.checked = this._checked;
2096
- if (!this._onCheck) {
2098
+ if (view.state.readOnly) {
2097
2099
  input.setAttribute("disabled", "true");
2098
- }
2099
- if (this._onCheck) {
2100
- input.onchange = (event) => {
2101
- this._onCheck?.(event.target.checked);
2102
- return true;
2100
+ } else {
2101
+ input.onmousedown = (event) => {
2102
+ const pos = view.posAtDOM(input);
2103
+ const text = view.state.sliceDoc(pos, pos + 3);
2104
+ if (text === (this._checked ? "[x]" : "[ ]")) {
2105
+ view.dispatch({
2106
+ changes: {
2107
+ from: pos + 1,
2108
+ to: pos + 2,
2109
+ insert: this._checked ? " " : "x"
2110
+ }
2111
+ });
2112
+ event.preventDefault();
2113
+ }
2103
2114
  };
2104
2115
  }
2105
- return wrap;
2116
+ return input;
2106
2117
  }
2107
2118
  ignoreEvent() {
2108
2119
  return false;
2109
2120
  }
2110
2121
  };
2122
+ var checkedDeco = Decoration8.replace({
2123
+ widget: new CheckboxWidget(true)
2124
+ });
2125
+ var uncheckedDeco = Decoration8.replace({
2126
+ widget: new CheckboxWidget(false)
2127
+ });
2111
2128
  var tasklist = (options = {}) => {
2112
- const taskMatcher = new MatchDecorator3({
2113
- regexp: /^(\s*)- \[([ xX])\]\s/g,
2114
- decoration: (match, view, pos) => {
2115
- const indent = Math.floor(match[1].length / 2);
2116
- const checked = match[2] === "x" || match[2] === "X";
2117
- return Decoration8.replace({
2118
- widget: new CheckboxWidget(pos, checked, indent, view.state.readOnly ? void 0 : (checked2) => {
2119
- const idx = pos + match[0].indexOf("[") + 1;
2120
- view.dispatch({
2121
- changes: {
2122
- from: idx,
2123
- to: idx + 1,
2124
- insert: checked2 ? "x" : " "
2125
- },
2126
- // TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
2127
- selection: {
2128
- anchor: idx + 3
2129
- }
2130
- });
2131
- })
2132
- });
2133
- }
2134
- });
2135
- const tasks = ViewPlugin6.fromClass(class {
2129
+ return ViewPlugin6.fromClass(class {
2136
2130
  constructor(view) {
2137
- this.tasks = taskMatcher.createDeco(view);
2131
+ this.decorations = buildDecorations3(view);
2138
2132
  }
2139
- update(update4) {
2140
- this.tasks = taskMatcher.updateDeco(update4, this.tasks);
2133
+ update(update2) {
2134
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2135
+ this.decorations = buildDecorations3(update2.view);
2136
+ }
2141
2137
  }
2142
2138
  }, {
2143
- decorations: (value) => value.tasks,
2144
- provide: (plugin) => EditorView12.atomicRanges.of((view) => {
2145
- return view.plugin(plugin)?.tasks || Decoration8.none;
2139
+ decorations: (v) => v.decorations,
2140
+ provide: (plugin) => EditorView11.atomicRanges.of((view) => {
2141
+ return view.plugin(plugin)?.decorations || Decoration8.none;
2146
2142
  })
2147
2143
  });
2148
- return [
2149
- tasks,
2150
- styles5
2151
- ];
2144
+ };
2145
+ var buildDecorations3 = (view) => {
2146
+ const builder = new RangeSetBuilder3();
2147
+ const { state } = view;
2148
+ const cursor = state.selection.main.head;
2149
+ for (const { from, to } of view.visibleRanges) {
2150
+ syntaxTree4(state).iterate({
2151
+ enter: (node) => {
2152
+ if (node.name === "TaskMarker" && (cursor < node.from || cursor > node.to)) {
2153
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2154
+ builder.add(node.from, node.to, checked ? checkedDeco : uncheckedDeco);
2155
+ }
2156
+ },
2157
+ from,
2158
+ to
2159
+ });
2160
+ }
2161
+ return builder.finish();
2152
2162
  };
2153
2163
 
2154
2164
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
@@ -2225,12 +2235,12 @@ var cursorConverter2 = (text) => ({
2225
2235
 
2226
2236
  // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2227
2237
  var yjs = (content, awareness2) => [
2228
- CursorConverter.of(cursorConverter2(content)),
2238
+ Cursor.converter.of(cursorConverter2(content)),
2229
2239
  yCollab(content, awareness2)
2230
2240
  ];
2231
2241
 
2232
2242
  // packages/ui/react-ui-editor/src/themes/default.ts
2233
- import get6 from "lodash.get";
2243
+ import get3 from "lodash.get";
2234
2244
  var defaultTheme = {
2235
2245
  //
2236
2246
  // Main layout:
@@ -2259,21 +2269,21 @@ var defaultTheme = {
2259
2269
  "&.cm-focused": {
2260
2270
  outline: "none"
2261
2271
  },
2262
- "& .cm-scroller": {
2272
+ ".cm-scroller": {
2263
2273
  overflow: "visible",
2264
- fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
2274
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2265
2275
  },
2266
- "& .cm-content": {
2276
+ ".cm-content": {
2267
2277
  padding: 0,
2268
2278
  // NOTE: Base font size (otherwise defined by HTML tag, which might be different for storybook).
2269
2279
  fontSize: "16px"
2270
2280
  },
2271
2281
  "&light .cm-content": {
2272
- color: get6(tokens, "extend.colors.neutral.900", "black"),
2282
+ color: get3(tokens, "extend.colors.neutral.900", "black"),
2273
2283
  caretColor: "black"
2274
2284
  },
2275
2285
  "&dark .cm-content": {
2276
- color: get6(tokens, "extend.colors.neutral.100", "white"),
2286
+ color: get3(tokens, "extend.colors.neutral.100", "white"),
2277
2287
  caretColor: "white"
2278
2288
  },
2279
2289
  //
@@ -2285,158 +2295,120 @@ var defaultTheme = {
2285
2295
  "&dark .cm-cursor, &dark .cm-dropCursor": {
2286
2296
  borderLeft: "2px solid white"
2287
2297
  },
2288
- "& .cm-placeholder": {
2298
+ ".cm-placeholder": {
2289
2299
  fontWeight: 100
2290
2300
  },
2291
2301
  //
2292
2302
  // line
2293
2303
  //
2294
- "& .cm-line": {
2304
+ ".cm-line": {
2295
2305
  paddingInline: 0
2296
2306
  },
2297
- "& .cm-activeLine": {
2307
+ ".cm-activeLine": {
2298
2308
  background: "inherit"
2299
2309
  },
2300
2310
  //
2301
2311
  // Selection
2302
2312
  //
2303
2313
  "&light .cm-selectionBackground": {
2304
- background: get6(tokens, "extend.colors.primary.100")
2314
+ background: get3(tokens, "extend.colors.primary.100")
2305
2315
  },
2306
2316
  "&light.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2307
- background: get6(tokens, "extend.colors.primary.200")
2317
+ background: get3(tokens, "extend.colors.primary.200")
2308
2318
  },
2309
2319
  "&dark .cm-selectionBackground": {
2310
- background: get6(tokens, "extend.colors.primary.700")
2320
+ background: get3(tokens, "extend.colors.primary.700")
2311
2321
  },
2312
2322
  "&dark.cm-focused > .cm-scroller > .cm-selectionLayer .cm-selectionBackground": {
2313
- background: get6(tokens, "extend.colors.primary.600")
2323
+ background: get3(tokens, "extend.colors.primary.600")
2314
2324
  },
2315
2325
  //
2316
2326
  // Search
2317
2327
  //
2318
2328
  "&light .cm-searchMatch": {
2319
- backgroundColor: get6(tokens, "extend.colors.yellow.100")
2329
+ backgroundColor: get3(tokens, "extend.colors.yellow.100")
2320
2330
  },
2321
2331
  "&dark .cm-searchMatch": {
2322
- backgroundColor: get6(tokens, "extend.colors.yellow.700")
2323
- },
2324
- //
2325
- // collaboration
2326
- // TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
2327
- //
2328
- "&light .cm-ySelection, &light .cm-yLineSelection": {
2329
- mixBlendMode: "multiply"
2330
- },
2331
- "&dark .cm-ySelection, &dark .cm-yLineSelection": {
2332
- mixBlendMode: "screen"
2333
- },
2334
- "& .cm-ySelectionInfo": {
2335
- padding: "2px 4px",
2336
- marginBlockStart: "-4px"
2337
- },
2338
- "& .cm-ySelection, & .cm-selectionMatch": {
2339
- paddingBlockStart: ".15em",
2340
- paddingBlockEnd: ".15em"
2341
- },
2342
- "& .cm-ySelectionCaret": {
2343
- display: "inline-block",
2344
- insetBlockStart: ".1em",
2345
- blockSize: "1.4em",
2346
- verticalAlign: "top"
2347
- },
2348
- "& .cm-yLineSelection": {
2349
- margin: 0
2332
+ backgroundColor: get3(tokens, "extend.colors.yellow.700")
2350
2333
  },
2351
2334
  //
2352
2335
  // link
2353
2336
  //
2354
- "& .cm-link": {
2355
- color: get6(tokens, "extend.colors.primary.500"),
2337
+ ".cm-link": {
2338
+ color: get3(tokens, "extend.colors.primary.500"),
2356
2339
  textDecorationLine: "underline",
2357
2340
  textDecorationThickness: "1px",
2358
2341
  textUnderlineOffset: "2px",
2359
2342
  borderRadius: ".125rem",
2360
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2343
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2361
2344
  },
2362
2345
  //
2363
2346
  // tooltip
2364
2347
  //
2365
- "& .cm-tooltip": {
2348
+ ".cm-tooltip": {
2366
2349
  border: "none"
2367
2350
  },
2368
- "& .cm-tooltip-below": {},
2351
+ ".cm-tooltip-below": {},
2369
2352
  //
2370
2353
  // autocomplete
2371
2354
  //
2372
- "& .cm-tooltip-autocomplete": {
2355
+ ".cm-tooltip-autocomplete": {
2373
2356
  marginTop: "4px",
2374
2357
  marginLeft: "-3px"
2375
2358
  },
2376
- "& .cm-tooltip-autocomplete ul li": {},
2377
- "& .cm-tooltip-autocomplete ul li[aria-selected]": {},
2378
- "& .cm-completionIcon": {
2359
+ ".cm-tooltip-autocomplete ul li": {},
2360
+ ".cm-tooltip-autocomplete ul li[aria-selected]": {},
2361
+ ".cm-completionIcon": {
2379
2362
  display: "none"
2380
2363
  },
2381
- "& .cm-completionLabel": {
2382
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2364
+ ".cm-completionLabel": {
2365
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2383
2366
  },
2384
- "& .cm-completionMatchedText": {
2367
+ ".cm-completionMatchedText": {
2385
2368
  textDecoration: "none"
2386
2369
  },
2387
2370
  //
2388
- // widgets
2389
- //
2390
- "& .cm-widgetBuffer": {
2391
- display: "none",
2392
- height: 0
2393
- },
2394
- //
2395
2371
  // table
2396
2372
  //
2397
- "& .cm-table *": {
2398
- fontFamily: `${get6(tokens, "fontFamily.mono", []).join(",")} !important`,
2373
+ ".cm-table *": {
2374
+ fontFamily: `${get3(tokens, "fontFamily.mono", []).join(",")} !important`,
2399
2375
  textDecoration: "none !important"
2400
2376
  },
2401
- "& .cm-table-head": {
2377
+ ".cm-table-head": {
2402
2378
  padding: "2px 16px 2px 0px",
2403
- borderBottom: `1px solid ${get6(tokens, "extend.colors.neutral.500")}`,
2379
+ borderBottom: `1px solid ${get3(tokens, "extend.colors.neutral.500")}`,
2404
2380
  fontWeight: 100,
2405
2381
  textAlign: "left",
2406
- color: get6(tokens, "extend.colors.neutral.500")
2382
+ color: get3(tokens, "extend.colors.neutral.500")
2407
2383
  },
2408
- "& .cm-table-cell": {
2384
+ ".cm-table-cell": {
2409
2385
  padding: "2px 16px 2px 0px"
2410
2386
  },
2411
2387
  //
2412
2388
  // image
2413
2389
  //
2414
- "& .cm-image": {
2415
- margin: "0.5rem 0"
2390
+ ".cm-image": {
2391
+ display: "block",
2392
+ height: "0"
2393
+ },
2394
+ ".cm-image.cm-loaded-image": {
2395
+ height: "auto",
2396
+ borderTop: "0.5rem solid transparent",
2397
+ borderBottom: "0.5rem solid transparent"
2416
2398
  },
2417
2399
  //
2418
2400
  // font size
2419
- // 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.
2401
+ // TODO(thure): This appears to be the best or only way to set selection caret heights,
2402
+ // but it's far more verbose than it needs to be.
2420
2403
  //
2421
- ...Object.keys(get6(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
2422
- const height = get6(tokens, [
2423
- "extend",
2424
- "fontSize",
2425
- fontSize,
2426
- 1,
2427
- "lineHeight"
2428
- ]);
2429
- acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
2430
- height
2431
- };
2432
- acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
2433
- height
2434
- };
2435
- acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
2436
- height
2437
- };
2438
- return acc;
2439
- }, {}),
2404
+ // ...Object.keys(get(tokens, 'extend.fontSize', {})).reduce((acc: Record<string, any>, fontSize) => {
2405
+ // const height = get(tokens, ['extend', 'fontSize', fontSize, 1, 'lineHeight']);
2406
+ //
2407
+ // acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = { height };
2408
+ // acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = { height };
2409
+ // acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = { height };
2410
+ // return acc;
2411
+ // }, {}),
2440
2412
  /**
2441
2413
  * Panels
2442
2414
  * TODO(burdon): Needs styling attention (esp. dark mode).
@@ -2453,51 +2425,53 @@ var defaultTheme = {
2453
2425
  * </div>
2454
2426
  * </div
2455
2427
  */
2456
- "& .cm-panels": {
2457
- border: `1px solid ${get6(tokens, "extend.colors.neutral.200")}`
2428
+ ".cm-panels": {
2429
+ border: `1px solid ${get3(tokens, "extend.colors.neutral.200")}`
2458
2430
  },
2459
- "& .cm-panel": {
2460
- background: get6(tokens, "extend.colors.neutral.50"),
2461
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2431
+ ".cm-panel": {
2432
+ background: get3(tokens, "extend.colors.neutral.50"),
2433
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2462
2434
  },
2463
- "& .cm-button": {
2435
+ ".cm-button": {
2464
2436
  margin: "4px",
2465
- fontFamily: get6(tokens, "fontFamily.body", []).join(","),
2466
- background: get6(tokens, "extend.colors.neutral.100"),
2437
+ fontFamily: get3(tokens, "fontFamily.body", []).join(","),
2438
+ background: get3(tokens, "extend.colors.neutral.100"),
2467
2439
  backgroundImage: "none",
2468
2440
  border: "none",
2469
2441
  "&:hover": {
2470
- background: get6(tokens, "extend.colors.neutral.200")
2442
+ background: get3(tokens, "extend.colors.neutral.200")
2471
2443
  },
2472
2444
  "&:active": {
2473
- background: get6(tokens, "extend.colors.neutral.300"),
2445
+ background: get3(tokens, "extend.colors.neutral.300"),
2474
2446
  backgroundImage: "none"
2475
2447
  }
2476
2448
  },
2477
- "& .cm-panel input[type=checkbox]": {
2449
+ ".cm-panel input[type=checkbox]": {
2478
2450
  marginRight: "0.4rem !important"
2479
2451
  }
2480
2452
  };
2481
2453
  var textTheme = {
2482
- "& .cm-scroller": {
2483
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2454
+ ".cm-scroller": {
2455
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2484
2456
  },
2485
- "& .cm-placeholder": {
2486
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2457
+ ".cm-placeholder": {
2458
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2487
2459
  }
2488
2460
  };
2489
2461
  var markdownTheme = {
2490
- // NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
2491
- "& .cm-placeholder": {
2492
- fontFamily: get6(tokens, "fontFamily.body", []).join(",")
2462
+ ".cm-scroller": {
2463
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2464
+ },
2465
+ ".cm-placeholder": {
2466
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2493
2467
  }
2494
2468
  };
2495
2469
  var codeTheme = {
2496
- "& .cm-scroller": {
2497
- fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
2470
+ ".cm-scroller": {
2471
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2498
2472
  },
2499
- "& .cm-placeholder": {
2500
- fontFamily: get6(tokens, "fontFamily.mono", []).join(",")
2473
+ ".cm-placeholder": {
2474
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2501
2475
  }
2502
2476
  };
2503
2477
 
@@ -2506,21 +2480,23 @@ var EditorModes = [
2506
2480
  "default",
2507
2481
  "vim"
2508
2482
  ];
2509
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: comments2, extensions = [], editorMode, slots = defaultSlots }, forwardedRef) => {
2510
- const { themeMode } = useThemeContext();
2483
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, readonly, comments: comments2, extensions = [], editorMode, theme, slots = defaultSlots }, forwardedRef) => {
2511
2484
  const tabsterDOMAttribute = useFocusableGroup({
2512
2485
  tabBehavior: "limited"
2513
2486
  });
2514
- const [root, setRoot] = useState(null);
2515
- const [{ state = void 0, view = void 0 } = {}, setEditor] = useState();
2516
- useImperativeHandle(forwardedRef, () => ({
2517
- root,
2518
- state,
2487
+ const { themeMode } = useThemeContext();
2488
+ const rootRef = useRef(null);
2489
+ const [view, setView] = useState(null);
2490
+ useImperativeHandle(forwardedRef, () => view, [
2519
2491
  view
2520
- }), [
2492
+ ]);
2493
+ useEffect(() => {
2494
+ if (view && focus) {
2495
+ view.focus();
2496
+ }
2497
+ }, [
2521
2498
  view,
2522
- state,
2523
- root
2499
+ focus
2524
2500
  ]);
2525
2501
  const { awareness: awareness2, peer } = model;
2526
2502
  useEffect(() => {
@@ -2544,7 +2520,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2544
2520
  themeMode
2545
2521
  ]);
2546
2522
  useEffect(() => {
2547
- if (view && comments2?.length) {
2523
+ if (view && comments2 !== void 0) {
2548
2524
  view.dispatch({
2549
2525
  effects: setCommentRange.of({
2550
2526
  model,
@@ -2557,20 +2533,22 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2557
2533
  comments2
2558
2534
  ]);
2559
2535
  useEffect(() => {
2560
- if (!root) {
2536
+ if (!model || !rootRef.current) {
2561
2537
  return;
2562
2538
  }
2563
- const state2 = EditorState2.create({
2539
+ const state = EditorState2.create({
2564
2540
  doc: model.text(),
2541
+ // TODO(burdon): Composer should store and set selection when switching documents.
2542
+ selection,
2565
2543
  extensions: [
2566
2544
  readonly && EditorState2.readOnly.of(readonly),
2567
2545
  // TODO(burdon): Factor out VIM mode? (manage via MarkdownPlugin).
2568
2546
  editorMode === "vim" && vim(),
2569
2547
  // Theme.
2570
2548
  // TODO(burdon): Make theme configurable.
2571
- EditorView13.baseTheme(defaultTheme),
2572
- EditorView13.theme(slots?.editor?.theme ?? {}),
2573
- EditorView13.darkTheme.of(themeMode === "dark"),
2549
+ EditorView12.baseTheme(defaultTheme),
2550
+ EditorView12.theme(theme ?? {}),
2551
+ EditorView12.darkTheme.of(themeMode === "dark"),
2574
2552
  // Storage and replication.
2575
2553
  model.extension,
2576
2554
  // Custom.
@@ -2578,19 +2556,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2578
2556
  ].filter(Boolean)
2579
2557
  });
2580
2558
  view?.destroy();
2581
- setEditor({
2582
- state: state2,
2583
- view: new EditorView13({
2584
- state: state2,
2585
- parent: root
2586
- })
2559
+ const newView = new EditorView12({
2560
+ parent: rootRef.current,
2561
+ state
2587
2562
  });
2563
+ setView(newView);
2588
2564
  return () => {
2589
- view?.destroy();
2590
- setEditor(void 0);
2565
+ newView?.destroy();
2566
+ setView(null);
2591
2567
  };
2592
2568
  }, [
2593
- root,
2569
+ rootRef,
2594
2570
  model,
2595
2571
  readonly,
2596
2572
  editorMode,
@@ -2599,12 +2575,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2599
2575
  const handleKeyUp = useCallback((event) => {
2600
2576
  const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
2601
2577
  switch (key) {
2602
- case "Enter": {
2603
- view?.contentDOM.focus();
2604
- break;
2605
- }
2606
2578
  case "Escape": {
2607
- editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && root?.focus();
2579
+ editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && rootRef.current?.focus();
2608
2580
  break;
2609
2581
  }
2610
2582
  }
@@ -2614,16 +2586,17 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, comments: co
2614
2586
  ]);
2615
2587
  return /* @__PURE__ */ React.createElement("div", {
2616
2588
  key: model.id,
2617
- ref: setRoot,
2589
+ role: "none",
2590
+ ref: rootRef,
2618
2591
  tabIndex: 0,
2619
- ...slots?.root,
2620
- ...editorMode !== "vim" && tabsterDOMAttribute,
2621
- onKeyUp: handleKeyUp
2592
+ onKeyUp: handleKeyUp,
2593
+ ...slots.root,
2594
+ ...editorMode !== "vim" && tabsterDOMAttribute
2622
2595
  });
2623
2596
  });
2624
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
2597
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = textTheme, slots, ...props }, forwardedRef) => {
2625
2598
  const { themeMode } = useThemeContext();
2626
- const slots = defaultsDeep2({}, _slots, defaultTextSlots);
2599
+ const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2627
2600
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2628
2601
  ref: forwardedRef,
2629
2602
  readonly,
@@ -2631,17 +2604,18 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots:
2631
2604
  basicBundle({
2632
2605
  readonly,
2633
2606
  themeMode,
2634
- placeholder: slots?.editor?.placeholder
2607
+ placeholder: placeholder3
2635
2608
  }),
2636
2609
  ...extensions
2637
2610
  ],
2638
- slots,
2611
+ theme,
2612
+ slots: updatedSlots,
2639
2613
  ...props
2640
2614
  });
2641
2615
  });
2642
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots: _slots, ...props }, forwardedRef) => {
2616
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = markdownTheme, slots, ...props }, forwardedRef) => {
2643
2617
  const { themeMode } = useThemeContext();
2644
- const slots = defaultsDeep2({}, _slots, defaultMarkdownSlots);
2618
+ const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2645
2619
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2646
2620
  ref: forwardedRef,
2647
2621
  readonly,
@@ -2649,34 +2623,29 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], sl
2649
2623
  markdownBundle({
2650
2624
  readonly,
2651
2625
  themeMode,
2652
- placeholder: slots?.editor?.placeholder
2626
+ placeholder: placeholder3
2653
2627
  }),
2654
2628
  ...extensions
2655
2629
  ],
2656
- slots,
2630
+ theme,
2631
+ slots: updatedSlots,
2657
2632
  ...props
2658
2633
  });
2659
2634
  });
2660
2635
  var defaultSlots = {
2661
2636
  root: {
2662
- className: mx3("p-2", inputSurface)
2637
+ className: mx3("p-2 overflow-y-auto", inputSurface)
2663
2638
  }
2664
2639
  };
2665
2640
  var defaultTextSlots = {
2666
- ...defaultSlots,
2667
- editor: {
2668
- theme: textTheme
2669
- }
2641
+ ...defaultSlots
2670
2642
  };
2671
2643
  var defaultMarkdownSlots = {
2672
- ...defaultSlots,
2673
- editor: {
2674
- theme: markdownTheme
2675
- }
2644
+ ...defaultSlots
2676
2645
  };
2677
2646
 
2678
2647
  // packages/ui/react-ui-editor/src/hooks/automerge.ts
2679
- import get7 from "lodash.get";
2648
+ import get4 from "lodash.get";
2680
2649
  import { getRawDoc } from "@dxos/echo-schema";
2681
2650
  import { isNotNullOrUndefined } from "@dxos/util";
2682
2651
 
@@ -2786,7 +2755,7 @@ var SpaceAwarenessProvider = class {
2786
2755
  };
2787
2756
 
2788
2757
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2789
- import { StateField as StateField6 } from "@codemirror/state";
2758
+ import { StateField as StateField5 } from "@codemirror/state";
2790
2759
  import { useEffect as useEffect2, useState as useState2 } from "react";
2791
2760
  import { isAutomergeObject } from "@dxos/react-client/echo";
2792
2761
 
@@ -2795,15 +2764,13 @@ import * as decoding from "lib0/decoding";
2795
2764
  import * as encoding from "lib0/encoding";
2796
2765
  import { Observable } from "lib0/observable";
2797
2766
  import * as YP from "y-protocols/awareness";
2798
- import * as Y2 from "yjs";
2799
2767
  import { invariant as invariant4 } from "@dxos/invariant";
2800
2768
  import { log as log4 } from "@dxos/log";
2801
- import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
2802
2769
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
2803
2770
  var createYjsModel = ({ identity, space, text }) => {
2804
2771
  invariant4(text?.doc && text?.content, void 0, {
2805
2772
  F: __dxlog_file5,
2806
- L: 23,
2773
+ L: 21,
2807
2774
  S: void 0,
2808
2775
  A: [
2809
2776
  "text?.doc && text?.content",
@@ -2819,34 +2786,6 @@ var createYjsModel = ({ identity, space, text }) => {
2819
2786
  id: text.doc.guid,
2820
2787
  content: text.content,
2821
2788
  text: () => text.content.toString(),
2822
- // https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
2823
- // TODO(dmaretskyi): Refactor as cursor-converter.
2824
- getCursorFromRange: (range) => {
2825
- const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
2826
- const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
2827
- return [
2828
- arrayToString2(from),
2829
- arrayToString2(to)
2830
- ].join(":");
2831
- },
2832
- getRangeFromCursor: (cursor) => {
2833
- invariant4(text.doc, void 0, {
2834
- F: __dxlog_file5,
2835
- L: 40,
2836
- S: void 0,
2837
- A: [
2838
- "text.doc",
2839
- ""
2840
- ]
2841
- });
2842
- const parts = cursor.split(":");
2843
- const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
2844
- const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
2845
- return from && to ? {
2846
- from: from.index,
2847
- to: to.index
2848
- } : void 0;
2849
- },
2850
2789
  extension: [
2851
2790
  modelState.init(() => model),
2852
2791
  yjs(text.content, provider?.awareness)
@@ -2896,7 +2835,7 @@ var YAwarenessProvider = class extends Observable {
2896
2835
  origin
2897
2836
  }, {
2898
2837
  F: __dxlog_file5,
2899
- L: 122,
2838
+ L: 100,
2900
2839
  S: this,
2901
2840
  C: (f, a) => f(...a)
2902
2841
  });
@@ -2909,7 +2848,7 @@ var YAwarenessProvider = class extends Observable {
2909
2848
  _handleSpaceMessage({ payload }) {
2910
2849
  log4("space message", payload, {
2911
2850
  F: __dxlog_file5,
2912
- L: 131,
2851
+ L: 109,
2913
2852
  S: this,
2914
2853
  C: (f, a) => f(...a)
2915
2854
  });
@@ -2953,13 +2892,13 @@ var YAwarenessProvider = class extends Observable {
2953
2892
  };
2954
2893
 
2955
2894
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2956
- var modelState = StateField6.define({
2895
+ var modelState = StateField5.define({
2957
2896
  create: () => void 0,
2958
2897
  update: (model) => model
2959
2898
  });
2960
2899
  var useTextModel = (props) => {
2961
2900
  const { identity, space, text } = props;
2962
- const [model, setModel] = useState2(() => createModel(props));
2901
+ const [model, setModel] = useState2();
2963
2902
  useEffect2(() => setModel(createModel(props)), [
2964
2903
  identity,
2965
2904
  space,
@@ -2997,7 +2936,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
2997
2936
  const model = {
2998
2937
  id: obj.id,
2999
2938
  content: doc,
3000
- text: () => get7(doc.handle.docSync(), doc.path),
2939
+ text: () => get4(doc.handle.docSync(), doc.path),
3001
2940
  // TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
3002
2941
  extension: [
3003
2942
  modelState.init(() => model),
@@ -3018,6 +2957,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
3018
2957
  export {
3019
2958
  AwarenessProvider,
3020
2959
  BaseTextEditor,
2960
+ Cursor,
3021
2961
  Doc,
3022
2962
  EditorModes,
3023
2963
  MarkdownEditor,
@@ -3033,16 +2973,19 @@ export {
3033
2973
  awareness,
3034
2974
  basicBundle,
3035
2975
  blast,
2976
+ callbackWrapper,
3036
2977
  code2 as code,
3037
2978
  codeTheme,
3038
2979
  comments,
3039
2980
  createAutomergeModel,
3040
2981
  createYjsModel,
2982
+ cursorConverter,
3041
2983
  defaultMarkdownSlots,
3042
2984
  defaultOptions,
3043
2985
  defaultSlots,
3044
2986
  defaultTextSlots,
3045
2987
  defaultTheme,
2988
+ getToken,
3046
2989
  hr,
3047
2990
  image,
3048
2991
  link,
@@ -3053,7 +2996,6 @@ export {
3053
2996
  markdownTagsExtensions,
3054
2997
  markdownTheme,
3055
2998
  mention,
3056
- mermaid,
3057
2999
  modelState,
3058
3000
  setCommentRange,
3059
3001
  setFocus,