@dxos/react-ui-editor 0.3.11-main.8be6c8a → 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 (63) hide show
  1. package/dist/lib/browser/index.mjs +250 -333
  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.map +1 -1
  5. package/dist/types/src/components/TextEditor/TextEditor.d.ts +2 -7
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  7. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +4 -4
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/TextEditor/comments.stories.d.ts +26 -0
  10. package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -0
  11. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  12. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  13. package/dist/types/src/extensions/code.d.ts.map +1 -1
  14. package/dist/types/src/extensions/comments.d.ts +6 -2
  15. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  16. package/dist/types/src/{util → extensions}/cursor.d.ts +9 -1
  17. package/dist/types/src/extensions/cursor.d.ts.map +1 -0
  18. package/dist/types/src/extensions/index.d.ts +1 -0
  19. package/dist/types/src/extensions/index.d.ts.map +1 -1
  20. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  21. package/dist/types/src/extensions/tasklist.d.ts +5 -1
  22. package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
  23. package/dist/types/src/extensions/yjs/cursor.d.ts +1 -1
  24. package/dist/types/src/extensions/yjs/cursor.d.ts.map +1 -1
  25. package/dist/types/src/hooks/useTextModel.d.ts +0 -5
  26. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  27. package/dist/types/src/hooks/yjs.d.ts.map +1 -1
  28. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  29. package/dist/types/src/themes/default.d.ts.map +1 -1
  30. package/dist/types/src/util.d.ts.map +1 -0
  31. package/package.json +24 -23
  32. package/src/components/TextEditor/MarkdownEditor.stories.tsx +12 -12
  33. package/src/components/TextEditor/TextEditor.stories.tsx +10 -43
  34. package/src/components/TextEditor/TextEditor.tsx +21 -31
  35. package/src/components/TextEditor/comments.stories.tsx +329 -0
  36. package/src/extensions/automerge/automerge.ts +2 -2
  37. package/src/extensions/automerge/cursor.ts +2 -1
  38. package/src/extensions/awareness.ts +25 -32
  39. package/src/extensions/code.ts +10 -2
  40. package/src/extensions/comments.ts +86 -116
  41. package/src/extensions/cursor.ts +46 -0
  42. package/src/extensions/hr.ts +2 -2
  43. package/src/extensions/image.ts +2 -2
  44. package/src/extensions/index.ts +1 -0
  45. package/src/extensions/link.ts +4 -4
  46. package/src/extensions/markdown/highlight.ts +0 -8
  47. package/src/extensions/table.ts +2 -2
  48. package/src/extensions/tasklist.ts +53 -77
  49. package/src/extensions/yjs/cursor.ts +2 -1
  50. package/src/extensions/yjs/yjs.test.ts +1 -1
  51. package/src/extensions/yjs/yjs.ts +2 -2
  52. package/src/hooks/useTextModel.ts +3 -6
  53. package/src/hooks/yjs.ts +1 -23
  54. package/src/styles/markdown.ts +0 -2
  55. package/src/themes/default.ts +17 -50
  56. package/dist/types/src/util/cursor.d.ts.map +0 -1
  57. package/dist/types/src/util/index.d.ts +0 -3
  58. package/dist/types/src/util/index.d.ts.map +0 -1
  59. package/dist/types/src/util/util.d.ts.map +0 -1
  60. package/src/util/cursor.ts +0 -29
  61. package/src/util/index.ts +0 -6
  62. /package/dist/types/src/{util/util.d.ts → util.d.ts} +0 -0
  63. /package/src/{util/util.ts → util.ts} +0 -0
@@ -274,30 +274,39 @@ var PatchSemaphore = class {
274
274
  }
275
275
  };
276
276
 
277
- // packages/ui/react-ui-editor/src/util/cursor.ts
277
+ // packages/ui/react-ui-editor/src/extensions/cursor.ts
278
278
  import { Facet } from "@codemirror/state";
279
- var DEFAULT_CURSOR_CONVERTER = {
279
+ var defaultCursorConverter = {
280
280
  toCursor: (position) => position.toString(),
281
281
  fromCursor: (cursor) => parseInt(cursor)
282
282
  };
283
- var CursorConverter = Facet.define({
284
- combine: (providers) => providers[0] ?? DEFAULT_CURSOR_CONVERTER
285
- });
286
-
287
- // packages/ui/react-ui-editor/src/util/util.ts
288
- import { log } from "@dxos/log";
289
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/util.ts";
290
- var callbackWrapper = (fn) => (...args) => {
291
- try {
292
- return fn(...args);
293
- } catch (error) {
294
- log.catch(error, void 0, {
295
- F: __dxlog_file,
296
- L: 16,
297
- S: void 0,
298
- C: (f, a) => f(...a)
283
+ var Cursor = class {
284
+ static {
285
+ this.converter = Facet.define({
286
+ combine: (providers) => providers[0] ?? defaultCursorConverter
299
287
  });
300
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
+ }
301
310
  };
302
311
 
303
312
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
@@ -356,7 +365,7 @@ var automerge3 = ({ handle, path }) => {
356
365
  });
357
366
  return {
358
367
  extension: [
359
- CursorConverter.of(cursorConverter(handle, path)),
368
+ Cursor.converter.of(cursorConverter(handle, path)),
360
369
  semaphoreFacet.of(semaphore),
361
370
  stateField,
362
371
  viewPlugin
@@ -398,7 +407,7 @@ var RemoteSelectionsDecorator = class {
398
407
  this._ctx = new Context();
399
408
  this._lastAnchor = void 0;
400
409
  this._lastHead = void 0;
401
- this._cursorConverter = view.state.facet(CursorConverter);
410
+ this._cursorConverter = view.state.facet(Cursor.converter);
402
411
  this._provider = view.state.facet(AwarenessProvider);
403
412
  this._provider.open();
404
413
  this._provider.remoteStateChange.on(this._ctx, () => {
@@ -453,7 +462,7 @@ var RemoteSelectionsDecorator = class {
453
462
  attributes: {
454
463
  style: `background-color: ${lightColor}`
455
464
  },
456
- class: "cm-ySelection"
465
+ class: "cm-collab-selection"
457
466
  })
458
467
  });
459
468
  } else {
@@ -464,7 +473,7 @@ var RemoteSelectionsDecorator = class {
464
473
  attributes: {
465
474
  style: `background-color: ${color}`
466
475
  },
467
- class: "cm-ySelection"
476
+ class: "cm-collab-selection"
468
477
  })
469
478
  });
470
479
  decorations.push({
@@ -474,7 +483,7 @@ var RemoteSelectionsDecorator = class {
474
483
  attributes: {
475
484
  style: `background-color: ${color}`
476
485
  },
477
- class: "cm-ySelection"
486
+ class: "cm-collab-selection"
478
487
  })
479
488
  });
480
489
  for (let i = startLine.number + 1; i < endLine.number; i++) {
@@ -485,7 +494,7 @@ var RemoteSelectionsDecorator = class {
485
494
  value: Decoration.line({
486
495
  attributes: {
487
496
  style: `background-color: ${color}`,
488
- class: "cm-yLineSelection"
497
+ class: "cm-collab-selectionLine"
489
498
  }
490
499
  })
491
500
  });
@@ -505,23 +514,21 @@ var RemoteSelectionsDecorator = class {
505
514
  }
506
515
  };
507
516
  var RemoteCaretWidget = class extends WidgetType {
508
- constructor(name, color) {
517
+ constructor(_name, _color) {
509
518
  super();
510
- this.name = name;
511
- this.color = color;
512
- this.name = name;
513
- this.color = color;
519
+ this._name = _name;
520
+ this._color = _color;
514
521
  }
515
522
  toDOM() {
516
523
  const span = document.createElement("span");
517
- span.className = "cm-ySelectionCaret";
518
- span.style.backgroundColor = this.color;
519
- span.style.borderColor = this.color;
524
+ span.className = "cm-collab-selectionCaret";
525
+ span.style.backgroundColor = this._color;
526
+ span.style.borderColor = this._color;
520
527
  const dot = document.createElement("div");
521
- dot.className = "cm-ySelectionCaretDot";
528
+ dot.className = "cm-collab-selectionCaretDot";
522
529
  const info = document.createElement("div");
523
- info.className = "cm-ySelectionInfo";
524
- info.innerText = this.name;
530
+ info.className = "cm-collab-selectionInfo";
531
+ info.innerText = this._name;
525
532
  span.appendChild(document.createTextNode("\u2060"));
526
533
  span.appendChild(dot);
527
534
  span.appendChild(document.createTextNode("\u2060"));
@@ -529,15 +536,12 @@ var RemoteCaretWidget = class extends WidgetType {
529
536
  span.appendChild(document.createTextNode("\u2060"));
530
537
  return span;
531
538
  }
532
- eq(widget) {
533
- return widget.color === this.color;
534
- }
535
- compare(widget) {
536
- return widget.color === this.color;
537
- }
538
539
  updateDOM() {
539
540
  return false;
540
541
  }
542
+ eq(widget) {
543
+ return widget._color === this._color;
544
+ }
541
545
  get estimatedHeight() {
542
546
  return -1;
543
547
  }
@@ -546,12 +550,12 @@ var RemoteCaretWidget = class extends WidgetType {
546
550
  }
547
551
  };
548
552
  var styles = EditorView.baseTheme({
549
- ".cm-ySelection": {},
550
- ".cm-yLineSelection": {
553
+ ".cm-collab-selection": {},
554
+ ".cm-collab-selectionLine": {
551
555
  padding: 0,
552
556
  margin: "0px 2px 0px 4px"
553
557
  },
554
- ".cm-ySelectionCaret": {
558
+ ".cm-collab-selectionCaret": {
555
559
  position: "relative",
556
560
  borderLeft: "1px solid black",
557
561
  borderRight: "1px solid black",
@@ -560,7 +564,7 @@ var styles = EditorView.baseTheme({
560
564
  boxSizing: "border-box",
561
565
  display: "inline"
562
566
  },
563
- ".cm-ySelectionCaretDot": {
567
+ ".cm-collab-selectionCaretDot": {
564
568
  borderRadius: "50%",
565
569
  position: "absolute",
566
570
  width: ".4em",
@@ -571,11 +575,11 @@ var styles = EditorView.baseTheme({
571
575
  transition: "transform .3s ease-in-out",
572
576
  boxSizing: "border-box"
573
577
  },
574
- ".cm-ySelectionCaret:hover > .cm-ySelectionCaretDot": {
578
+ ".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
575
579
  transformOrigin: "bottom center",
576
580
  transform: "scale(0)"
577
581
  },
578
- ".cm-ySelectionInfo": {
582
+ ".cm-collab-selectionInfo": {
579
583
  position: "absolute",
580
584
  top: "-1.05em",
581
585
  left: "-1px",
@@ -596,7 +600,7 @@ var styles = EditorView.baseTheme({
596
600
  transitionDelay: "0s",
597
601
  whiteSpace: "nowrap"
598
602
  },
599
- ".cm-ySelectionCaret:hover > .cm-ySelectionInfo": {
603
+ ".cm-collab-selectionCaret:hover > .cm-collab-selectionInfo": {
600
604
  opacity: 1,
601
605
  transitionDelay: "0s"
602
606
  }
@@ -623,7 +627,7 @@ var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
623
627
  import { EditorView as EditorView3, keymap as keymap2 } from "@codemirror/view";
624
628
  import defaultsDeep from "lodash.defaultsdeep";
625
629
  import { invariant } from "@dxos/invariant";
626
- 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";
627
631
  var defaultOptions = {
628
632
  effect: 2,
629
633
  maxParticles: 200,
@@ -750,7 +754,7 @@ var Blaster = class {
750
754
  }
751
755
  initialize() {
752
756
  invariant(!this._canvas && !this._ctx, void 0, {
753
- F: __dxlog_file2,
757
+ F: __dxlog_file,
754
758
  L: 138,
755
759
  S: this,
756
760
  A: [
@@ -787,7 +791,7 @@ var Blaster = class {
787
791
  }
788
792
  start() {
789
793
  invariant(this._canvas && this._ctx, void 0, {
790
- F: __dxlog_file2,
794
+ F: __dxlog_file,
791
795
  L: 177,
792
796
  S: this,
793
797
  A: [
@@ -1057,7 +1061,7 @@ var getLineRange = (lines, from, to) => {
1057
1061
  var code2 = () => {
1058
1062
  const getDecorations = (view) => {
1059
1063
  const decorations = [];
1060
- if (view.state.readOnly) {
1064
+ if (!view.hasFocus || view.state.readOnly) {
1061
1065
  const text = view.state.doc.sliceString(0);
1062
1066
  const matches = text.matchAll(CODE_REGEX);
1063
1067
  const blocks = view.viewportLineBlocks;
@@ -1076,10 +1080,15 @@ var code2 = () => {
1076
1080
  return [
1077
1081
  ViewPlugin3.fromClass(class {
1078
1082
  constructor(view) {
1083
+ this.hasFocus = false;
1079
1084
  this.decorations = getDecorations(view);
1080
1085
  }
1081
1086
  update(update2) {
1082
- if (update2.docChanged || update2.viewportChanged) {
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;
1083
1092
  this.decorations = getDecorations(update2.view);
1084
1093
  }
1085
1094
  }
@@ -1092,23 +1101,32 @@ var code2 = () => {
1092
1101
 
1093
1102
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1094
1103
  import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1095
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1104
+ import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
1096
1105
  import sortBy from "lodash.sortby";
1097
1106
  import { debounce } from "@dxos/async";
1098
1107
  import { invariant as invariant2 } from "@dxos/invariant";
1099
1108
  import { log as log2 } from "@dxos/log";
1100
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
1101
1128
  var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1102
1129
  var styles3 = EditorView5.baseTheme({
1103
- "& .cm-bookmark": {
1104
- cursor: "pointer",
1105
- margin: "4px",
1106
- padding: "4px",
1107
- backgroundColor: "yellow"
1108
- },
1109
- "& .cm-bookmark-selected": {
1110
- backgroundColor: "orange"
1111
- },
1112
1130
  "& .cm-comment": {
1113
1131
  backgroundColor: getToken("extend.colors.yellow.50")
1114
1132
  },
@@ -1147,7 +1165,7 @@ var commentsStateField = StateField2.define({
1147
1165
  ranges: []
1148
1166
  }),
1149
1167
  update: (value, tr) => {
1150
- const cursorConverter3 = tr.state.facet(CursorConverter);
1168
+ const cursorConverter3 = tr.state.facet(Cursor.converter);
1151
1169
  for (const effect of tr.effects) {
1152
1170
  if (effect.is(setSelection)) {
1153
1171
  return {
@@ -1158,7 +1176,7 @@ var commentsStateField = StateField2.define({
1158
1176
  if (effect.is(setCommentRange)) {
1159
1177
  const { comments: comments2 } = effect.value;
1160
1178
  const ranges = comments2.map((comment) => {
1161
- const range = getRangeFromCursor(cursorConverter3, comment.cursor);
1179
+ const range = Cursor.getRangeFromCursor(cursorConverter3, comment.cursor);
1162
1180
  return range && {
1163
1181
  ...comment,
1164
1182
  ...range
@@ -1196,42 +1214,68 @@ var highlightDecorations = EditorView5.decorations.compute([
1196
1214
  }).filter(nonNullable) ?? [];
1197
1215
  return Decoration3.set(decorations);
1198
1216
  });
1199
- var BookmarkWidget = class extends WidgetType2 {
1200
- constructor(_anchor, _id, _handleClick) {
1201
- super();
1202
- this._anchor = _anchor;
1203
- this._id = _id;
1204
- this._handleClick = _handleClick;
1205
- invariant2(this._id, void 0, {
1206
- F: __dxlog_file3,
1207
- L: 168,
1208
- S: this,
1209
- A: [
1210
- "this._id",
1211
- ""
1212
- ]
1213
- });
1214
- }
1215
- eq(other) {
1216
- return this._anchor === other._anchor && this._id === other._id;
1217
- }
1218
- toDOM() {
1219
- const span = document.createElement("span");
1220
- span.className = "cm-bookmark";
1221
- span.textContent = "\u203B";
1222
- if (this._handleClick) {
1223
- 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
+ };
1224
1234
  }
1225
- return span;
1226
- }
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
+ ];
1227
1270
  };
1228
1271
  var comments = (options = {}) => {
1272
+ const { key: shortcut = "meta-'" } = options;
1229
1273
  const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1230
1274
  const createCommentThread = (view) => {
1231
- const cursorConverter3 = view.state.facet(CursorConverter);
1275
+ const cursorConverter3 = view.state.facet(Cursor.converter);
1232
1276
  invariant2(options.onCreate, void 0, {
1233
1277
  F: __dxlog_file3,
1234
- L: 224,
1278
+ L: 240,
1235
1279
  S: void 0,
1236
1280
  A: [
1237
1281
  "options.onCreate",
@@ -1242,12 +1286,12 @@ var comments = (options = {}) => {
1242
1286
  if (from === to) {
1243
1287
  return false;
1244
1288
  }
1245
- const relPos = getCursorFromRange(cursorConverter3, {
1289
+ const cursor = Cursor.getCursorFromRange(cursorConverter3, {
1246
1290
  from,
1247
1291
  to
1248
1292
  });
1249
- if (relPos) {
1250
- const id = callbackWrapper(options.onCreate)(relPos);
1293
+ if (cursor) {
1294
+ const id = callbackWrapper(options.onCreate)(cursor, view.coordsAtPos(from));
1251
1295
  if (id) {
1252
1296
  view.dispatch({
1253
1297
  effects: setSelection.of({
@@ -1274,35 +1318,7 @@ var comments = (options = {}) => {
1274
1318
  }
1275
1319
  return false;
1276
1320
  };
1277
- const bookmarksViewPlugin = ViewPlugin4.fromClass(class BookmarkViewPlugin {
1278
- static {
1279
- // Match markdown footnotes (option).
1280
- // https://www.markdownguide.org/extended-syntax/#footnotes
1281
- this.bookmarkMatcher = new MatchDecorator({
1282
- regexp: /\[\^(\w+)\]/g,
1283
- decoration: (match, view, pos) => {
1284
- const id = match[1];
1285
- return Decoration3.replace({
1286
- id,
1287
- widget: new BookmarkWidget(pos, id)
1288
- });
1289
- }
1290
- });
1291
- }
1292
- constructor(view) {
1293
- this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.createDeco(view);
1294
- }
1295
- update(update2) {
1296
- this.bookmarks = BookmarkViewPlugin.bookmarkMatcher.updateDeco(update2, this.bookmarks);
1297
- }
1298
- }, {
1299
- decorations: (instance) => instance.bookmarks,
1300
- provide: (plugin) => EditorView5.atomicRanges.of((view) => {
1301
- return view.plugin(plugin)?.bookmarks || Decoration3.none;
1302
- })
1303
- });
1304
1321
  return [
1305
- bookmarksViewPlugin,
1306
1322
  commentsStateField,
1307
1323
  highlightDecorations,
1308
1324
  styles3,
@@ -1311,7 +1327,7 @@ var comments = (options = {}) => {
1311
1327
  //
1312
1328
  options.onCreate ? keymap3.of([
1313
1329
  {
1314
- key: options?.key ?? "meta-'",
1330
+ key: shortcut,
1315
1331
  run: callbackWrapper(createCommentThread)
1316
1332
  }
1317
1333
  ]) : [],
@@ -1328,7 +1344,7 @@ var comments = (options = {}) => {
1328
1344
  above: true,
1329
1345
  create: () => {
1330
1346
  const el = document.createElement("div");
1331
- options.onHover?.(el);
1347
+ options.onHover?.(el, shortcut);
1332
1348
  return {
1333
1349
  dom: el,
1334
1350
  offset: {
@@ -1349,27 +1365,27 @@ var comments = (options = {}) => {
1349
1365
  // TODO(burdon): Is there a better (finer grained) way to do this?
1350
1366
  //
1351
1367
  EditorView5.updateListener.of(({ view, state, changes }) => {
1352
- const cursorConverter3 = view.state.facet(CursorConverter);
1368
+ const cursorConverter3 = view.state.facet(Cursor.converter);
1353
1369
  {
1354
1370
  let mod = false;
1355
1371
  const { active, ranges } = state.field(commentsStateField);
1356
1372
  changes.iterChanges((from, to, from2, to2) => {
1357
1373
  ranges.forEach((range) => {
1358
1374
  if (from2 === to2) {
1359
- const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
1375
+ const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1360
1376
  if (!newRange || newRange.to - newRange.from === 0) {
1361
1377
  log2.info("deleted comment", {
1362
1378
  thread: range.id
1363
1379
  }, {
1364
1380
  F: __dxlog_file3,
1365
- L: 358,
1381
+ L: 337,
1366
1382
  S: void 0,
1367
1383
  C: (f, a) => f(...a)
1368
1384
  });
1369
1385
  }
1370
1386
  }
1371
1387
  if (from <= range.to) {
1372
- const newRange = getRangeFromCursor(cursorConverter3, range.cursor);
1388
+ const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1373
1389
  Object.assign(range, newRange);
1374
1390
  mod = true;
1375
1391
  }
@@ -1415,29 +1431,13 @@ var comments = (options = {}) => {
1415
1431
  });
1416
1432
  }
1417
1433
  }
1418
- })
1434
+ }),
1435
+ options.onMove ? trackPastedComments(options.onMove) : []
1419
1436
  ];
1420
1437
  };
1421
- var getCursorFromRange = (cursorConverter3, range) => {
1422
- const from = cursorConverter3.toCursor(range.from);
1423
- const to = cursorConverter3.toCursor(range.to, -1);
1424
- return [
1425
- from,
1426
- to
1427
- ].join(":");
1428
- };
1429
- var getRangeFromCursor = (cursorConverter3, cursor) => {
1430
- const parts = cursor.split(":");
1431
- const from = cursorConverter3.fromCursor(parts[0]);
1432
- const to = cursorConverter3.fromCursor(parts[1]);
1433
- return from !== void 0 && to !== void 0 ? {
1434
- from,
1435
- to
1436
- } : void 0;
1437
- };
1438
1438
 
1439
1439
  // packages/ui/react-ui-editor/src/extensions/hr.ts
1440
- import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin5, WidgetType as WidgetType3 } from "@codemirror/view";
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): ???
@@ -1445,7 +1445,7 @@ var styles4 = EditorView6.baseTheme({
1445
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,7 +1467,7 @@ 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
  }
@@ -1486,7 +1486,7 @@ var hr = () => [
1486
1486
  // packages/ui/react-ui-editor/src/extensions/image.ts
1487
1487
  import { syntaxTree } from "@codemirror/language";
1488
1488
  import { StateField as StateField3 } from "@codemirror/state";
1489
- import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType4 } from "@codemirror/view";
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
1492
  create: (state) => {
@@ -1538,7 +1538,7 @@ var buildDecorations = (from, to, state) => {
1538
1538
  });
1539
1539
  return decorations;
1540
1540
  };
1541
- var ImageWidget = class extends WidgetType4 {
1541
+ var ImageWidget = class extends WidgetType3 {
1542
1542
  constructor(_url) {
1543
1543
  super();
1544
1544
  this._url = _url;
@@ -1558,11 +1558,11 @@ var ImageWidget = class extends WidgetType4 {
1558
1558
  // packages/ui/react-ui-editor/src/extensions/link.ts
1559
1559
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1560
1560
  import { RangeSetBuilder } from "@codemirror/state";
1561
- import { Decoration as Decoration6, WidgetType as WidgetType5, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
1561
+ import { Decoration as Decoration6, WidgetType as WidgetType4, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
1562
1562
  import { tooltipContent } from "@dxos/react-ui-theme";
1563
1563
  var link = (options = {}) => {
1564
1564
  const extensions = [
1565
- ViewPlugin6.fromClass(class {
1565
+ ViewPlugin5.fromClass(class {
1566
1566
  constructor(view) {
1567
1567
  this.decorations = buildDecorations2(view, options);
1568
1568
  }
@@ -1613,7 +1613,7 @@ var link = (options = {}) => {
1613
1613
  }
1614
1614
  return extensions;
1615
1615
  };
1616
- var LinkButton = class extends WidgetType5 {
1616
+ var LinkButton = class extends WidgetType4 {
1617
1617
  constructor(_url, _onAttach) {
1618
1618
  super();
1619
1619
  this._url = _url;
@@ -1628,7 +1628,7 @@ var LinkButton = class extends WidgetType5 {
1628
1628
  return el;
1629
1629
  }
1630
1630
  };
1631
- var LinkText = class extends WidgetType5 {
1631
+ var LinkText = class extends WidgetType4 {
1632
1632
  constructor(_text, _url) {
1633
1633
  super();
1634
1634
  this._text = _text;
@@ -1728,7 +1728,6 @@ var markdownTags = {
1728
1728
  CodeText: Tag.define(),
1729
1729
  EmphasisMark: Tag.define(),
1730
1730
  HeaderMark: Tag.define(),
1731
- // HorizontalRule: Tag.define(),
1732
1731
  InlineCode: Tag.define(),
1733
1732
  LinkLabel: Tag.define(),
1734
1733
  LinkReference: Tag.define(),
@@ -1892,12 +1891,6 @@ var markdownHighlightStyle = (readonly) => {
1892
1891
  ],
1893
1892
  class: blockquote
1894
1893
  },
1895
- // TODO(burdon): Replace with extension.
1896
- // {
1897
- // tag: [markdownTags.HorizontalRule],
1898
- // class: mx(horizontalRule, readonly && '-indent-[100rem]'),
1899
- // },
1900
- // TODO(burdon): Only if being edited.
1901
1894
  {
1902
1895
  tag: [
1903
1896
  markdownTags.TableCell
@@ -1991,7 +1984,7 @@ var mention = ({ onSearch }) => {
1991
1984
  // packages/ui/react-ui-editor/src/extensions/table.ts
1992
1985
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1993
1986
  import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
1994
- import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType6 } from "@codemirror/view";
1987
+ import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType5 } from "@codemirror/view";
1995
1988
  var table = (options = {}) => {
1996
1989
  return StateField4.define({
1997
1990
  create: (state) => update(state, options),
@@ -2049,7 +2042,7 @@ var update = (state, options) => {
2049
2042
  });
2050
2043
  return builder.finish();
2051
2044
  };
2052
- var TableWidget = class extends WidgetType6 {
2045
+ var TableWidget = class extends WidgetType5 {
2053
2046
  constructor(_table) {
2054
2047
  super();
2055
2048
  this._table = _table;
@@ -2087,87 +2080,85 @@ var TableWidget = class extends WidgetType6 {
2087
2080
  };
2088
2081
 
2089
2082
  // packages/ui/react-ui-editor/src/extensions/tasklist.ts
2090
- import { EditorView as EditorView11, Decoration as Decoration8, WidgetType as WidgetType7, MatchDecorator as MatchDecorator3, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
2091
- var styles5 = EditorView11.baseTheme({
2092
- "& .cm-task-item": {
2093
- paddingLeft: "4px",
2094
- paddingRight: "8px"
2095
- }
2096
- });
2097
- var CheckboxWidget = class extends WidgetType7 {
2098
- constructor(_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) {
2099
2088
  super();
2100
2089
  this._checked = _checked;
2101
- this._indent = _indent;
2102
- this._onCheck = _onCheck;
2103
2090
  }
2104
2091
  eq(other) {
2105
- return this._checked === other._checked && this._indent === other._indent;
2092
+ return this._checked === other._checked;
2106
2093
  }
2107
2094
  toDOM(view) {
2108
- const wrap = document.createElement("span");
2109
- wrap.className = "cm-task-item";
2110
- wrap.setAttribute("aria-hidden", "true");
2111
- wrap.style.setProperty("margin-left", this._indent * 24 + "px");
2112
- const input = wrap.appendChild(document.createElement("input"));
2095
+ const input = document.createElement("input");
2113
2096
  input.type = "checkbox";
2114
2097
  input.checked = this._checked;
2115
- if (!this._onCheck) {
2098
+ if (view.state.readOnly) {
2116
2099
  input.setAttribute("disabled", "true");
2117
- }
2118
- if (this._onCheck) {
2119
- input.onchange = (event) => {
2120
- this._onCheck?.(event.target.checked);
2121
- 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
+ }
2122
2114
  };
2123
2115
  }
2124
- return wrap;
2116
+ return input;
2125
2117
  }
2126
2118
  ignoreEvent() {
2127
2119
  return false;
2128
2120
  }
2129
2121
  };
2122
+ var checkedDeco = Decoration8.replace({
2123
+ widget: new CheckboxWidget(true)
2124
+ });
2125
+ var uncheckedDeco = Decoration8.replace({
2126
+ widget: new CheckboxWidget(false)
2127
+ });
2130
2128
  var tasklist = (options = {}) => {
2131
- const taskMatcher = new MatchDecorator3({
2132
- regexp: /^(\s*)- \[([ xX])\]\s/g,
2133
- decoration: (match, view, pos) => {
2134
- const indent = Math.floor(match[1].length / 2);
2135
- const checked = match[2] === "x" || match[2] === "X";
2136
- return Decoration8.replace({
2137
- widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
2138
- const idx = pos + match[0].indexOf("[") + 1;
2139
- view.dispatch({
2140
- changes: {
2141
- from: idx,
2142
- to: idx + 1,
2143
- insert: checked2 ? "x" : " "
2144
- },
2145
- // TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
2146
- selection: {
2147
- anchor: idx + 3
2148
- }
2149
- });
2150
- })
2151
- });
2152
- }
2153
- });
2154
- const tasks = ViewPlugin7.fromClass(class {
2129
+ return ViewPlugin6.fromClass(class {
2155
2130
  constructor(view) {
2156
- this.tasks = taskMatcher.createDeco(view);
2131
+ this.decorations = buildDecorations3(view);
2157
2132
  }
2158
2133
  update(update2) {
2159
- this.tasks = taskMatcher.updateDeco(update2, this.tasks);
2134
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2135
+ this.decorations = buildDecorations3(update2.view);
2136
+ }
2160
2137
  }
2161
2138
  }, {
2162
- decorations: (value) => value.tasks,
2139
+ decorations: (v) => v.decorations,
2163
2140
  provide: (plugin) => EditorView11.atomicRanges.of((view) => {
2164
- return view.plugin(plugin)?.tasks || Decoration8.none;
2141
+ return view.plugin(plugin)?.decorations || Decoration8.none;
2165
2142
  })
2166
2143
  });
2167
- return [
2168
- tasks,
2169
- styles5
2170
- ];
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();
2171
2162
  };
2172
2163
 
2173
2164
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
@@ -2244,7 +2235,7 @@ var cursorConverter2 = (text) => ({
2244
2235
 
2245
2236
  // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2246
2237
  var yjs = (content, awareness2) => [
2247
- CursorConverter.of(cursorConverter2(content)),
2238
+ Cursor.converter.of(cursorConverter2(content)),
2248
2239
  yCollab(content, awareness2)
2249
2240
  ];
2250
2241
 
@@ -2341,33 +2332,6 @@ var defaultTheme = {
2341
2332
  backgroundColor: get3(tokens, "extend.colors.yellow.700")
2342
2333
  },
2343
2334
  //
2344
- // collaboration
2345
- // TODO(burdon): Review classnames (YJS dependent?) Note: e2e tests depend on this class.
2346
- //
2347
- "&light .cm-ySelection, &light .cm-yLineSelection": {
2348
- mixBlendMode: "multiply"
2349
- },
2350
- "&dark .cm-ySelection, &dark .cm-yLineSelection": {
2351
- mixBlendMode: "screen"
2352
- },
2353
- ".cm-ySelectionInfo": {
2354
- padding: "2px 4px",
2355
- marginBlockStart: "-4px"
2356
- },
2357
- ".cm-ySelection, & .cm-selectionMatch": {
2358
- paddingBlockStart: ".15em",
2359
- paddingBlockEnd: ".15em"
2360
- },
2361
- ".cm-ySelectionCaret": {
2362
- display: "inline-block",
2363
- insetBlockStart: ".1em",
2364
- blockSize: "1.4em",
2365
- verticalAlign: "top"
2366
- },
2367
- ".cm-yLineSelection": {
2368
- margin: 0
2369
- },
2370
- //
2371
2335
  // link
2372
2336
  //
2373
2337
  ".cm-link": {
@@ -2404,13 +2368,6 @@ var defaultTheme = {
2404
2368
  textDecoration: "none"
2405
2369
  },
2406
2370
  //
2407
- // widgets
2408
- //
2409
- ".cm-widgetBuffer": {
2410
- display: "none",
2411
- height: 0
2412
- },
2413
- //
2414
2371
  // table
2415
2372
  //
2416
2373
  ".cm-table *": {
@@ -2441,27 +2398,17 @@ var defaultTheme = {
2441
2398
  },
2442
2399
  //
2443
2400
  // font size
2444
- // 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.
2445
2403
  //
2446
- ...Object.keys(get3(tokens, "extend.fontSize", {})).reduce((acc, fontSize) => {
2447
- const height = get3(tokens, [
2448
- "extend",
2449
- "fontSize",
2450
- fontSize,
2451
- 1,
2452
- "lineHeight"
2453
- ]);
2454
- acc[`& .text-${fontSize} + .cm-ySelectionCaret`] = {
2455
- height
2456
- };
2457
- acc[`& .text-${fontSize} + .cm-ySelection + .cm-ySelectionCaret`] = {
2458
- height
2459
- };
2460
- acc[`& .text-${fontSize} + .cm-widgetBuffer + .cm-ySelectionCaret`] = {
2461
- height
2462
- };
2463
- return acc;
2464
- }, {}),
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
+ // }, {}),
2465
2412
  /**
2466
2413
  * Panels
2467
2414
  * TODO(burdon): Needs styling attention (esp. dark mode).
@@ -2512,7 +2459,9 @@ var textTheme = {
2512
2459
  }
2513
2460
  };
2514
2461
  var markdownTheme = {
2515
- // NOTE: Must leave base font family as is (i.e., monospace) due to fenced code blocks.
2462
+ ".cm-scroller": {
2463
+ fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2464
+ },
2516
2465
  ".cm-placeholder": {
2517
2466
  fontFamily: get3(tokens, "fontFamily.body", []).join(",")
2518
2467
  }
@@ -2531,7 +2480,7 @@ var EditorModes = [
2531
2480
  "default",
2532
2481
  "vim"
2533
2482
  ];
2534
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, readonly, comments: comments2, extensions = [], editorMode, slots = defaultSlots }, forwardedRef) => {
2483
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, readonly, comments: comments2, extensions = [], editorMode, theme, slots = defaultSlots }, forwardedRef) => {
2535
2484
  const tabsterDOMAttribute = useFocusableGroup({
2536
2485
  tabBehavior: "limited"
2537
2486
  });
@@ -2571,7 +2520,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2571
2520
  themeMode
2572
2521
  ]);
2573
2522
  useEffect(() => {
2574
- if (view && comments2?.length) {
2523
+ if (view && comments2 !== void 0) {
2575
2524
  view.dispatch({
2576
2525
  effects: setCommentRange.of({
2577
2526
  model,
@@ -2589,6 +2538,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2589
2538
  }
2590
2539
  const state = EditorState2.create({
2591
2540
  doc: model.text(),
2541
+ // TODO(burdon): Composer should store and set selection when switching documents.
2592
2542
  selection,
2593
2543
  extensions: [
2594
2544
  readonly && EditorState2.readOnly.of(readonly),
@@ -2597,7 +2547,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2597
2547
  // Theme.
2598
2548
  // TODO(burdon): Make theme configurable.
2599
2549
  EditorView12.baseTheme(defaultTheme),
2600
- EditorView12.theme(slots?.editor?.theme ?? {}),
2550
+ EditorView12.theme(theme ?? {}),
2601
2551
  EditorView12.darkTheme.of(themeMode === "dark"),
2602
2552
  // Storage and replication.
2603
2553
  model.extension,
@@ -2636,14 +2586,15 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2636
2586
  ]);
2637
2587
  return /* @__PURE__ */ React.createElement("div", {
2638
2588
  key: model.id,
2589
+ role: "none",
2639
2590
  ref: rootRef,
2640
2591
  tabIndex: 0,
2641
- ...slots?.root,
2642
- ...editorMode !== "vim" && tabsterDOMAttribute,
2643
- onKeyUp: handleKeyUp
2592
+ onKeyUp: handleKeyUp,
2593
+ ...slots.root,
2594
+ ...editorMode !== "vim" && tabsterDOMAttribute
2644
2595
  });
2645
2596
  });
2646
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots, ...props }, forwardedRef) => {
2597
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = textTheme, slots, ...props }, forwardedRef) => {
2647
2598
  const { themeMode } = useThemeContext();
2648
2599
  const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2649
2600
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
@@ -2653,15 +2604,16 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots,
2653
2604
  basicBundle({
2654
2605
  readonly,
2655
2606
  themeMode,
2656
- placeholder: updatedSlots?.editor?.placeholder
2607
+ placeholder: placeholder3
2657
2608
  }),
2658
2609
  ...extensions
2659
2610
  ],
2611
+ theme,
2660
2612
  slots: updatedSlots,
2661
2613
  ...props
2662
2614
  });
2663
2615
  });
2664
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], slots, ...props }, forwardedRef) => {
2616
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = markdownTheme, slots, ...props }, forwardedRef) => {
2665
2617
  const { themeMode } = useThemeContext();
2666
2618
  const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2667
2619
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
@@ -2671,30 +2623,25 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, extensions = [], sl
2671
2623
  markdownBundle({
2672
2624
  readonly,
2673
2625
  themeMode,
2674
- placeholder: updatedSlots?.editor?.placeholder
2626
+ placeholder: placeholder3
2675
2627
  }),
2676
2628
  ...extensions
2677
2629
  ],
2630
+ theme,
2678
2631
  slots: updatedSlots,
2679
2632
  ...props
2680
2633
  });
2681
2634
  });
2682
2635
  var defaultSlots = {
2683
2636
  root: {
2684
- className: mx3("p-2", inputSurface)
2637
+ className: mx3("p-2 overflow-y-auto", inputSurface)
2685
2638
  }
2686
2639
  };
2687
2640
  var defaultTextSlots = {
2688
- ...defaultSlots,
2689
- editor: {
2690
- theme: textTheme
2691
- }
2641
+ ...defaultSlots
2692
2642
  };
2693
2643
  var defaultMarkdownSlots = {
2694
- ...defaultSlots,
2695
- editor: {
2696
- theme: markdownTheme
2697
- }
2644
+ ...defaultSlots
2698
2645
  };
2699
2646
 
2700
2647
  // packages/ui/react-ui-editor/src/hooks/automerge.ts
@@ -2817,15 +2764,13 @@ import * as decoding from "lib0/decoding";
2817
2764
  import * as encoding from "lib0/encoding";
2818
2765
  import { Observable } from "lib0/observable";
2819
2766
  import * as YP from "y-protocols/awareness";
2820
- import * as Y2 from "yjs";
2821
2767
  import { invariant as invariant4 } from "@dxos/invariant";
2822
2768
  import { log as log4 } from "@dxos/log";
2823
- import { arrayToString as arrayToString2, stringToArray as stringToArray2 } from "@dxos/util";
2824
2769
  var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
2825
2770
  var createYjsModel = ({ identity, space, text }) => {
2826
2771
  invariant4(text?.doc && text?.content, void 0, {
2827
2772
  F: __dxlog_file5,
2828
- L: 23,
2773
+ L: 21,
2829
2774
  S: void 0,
2830
2775
  A: [
2831
2776
  "text?.doc && text?.content",
@@ -2841,34 +2786,6 @@ var createYjsModel = ({ identity, space, text }) => {
2841
2786
  id: text.doc.guid,
2842
2787
  content: text.content,
2843
2788
  text: () => text.content.toString(),
2844
- // https://github.com/yjs/yjs?tab=readme-ov-file#relative-positions
2845
- // TODO(dmaretskyi): Refactor as cursor-converter.
2846
- getCursorFromRange: (range) => {
2847
- const from = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.from));
2848
- const to = Y2.encodeRelativePosition(Y2.createRelativePositionFromTypeIndex(text.content, range.to, -1));
2849
- return [
2850
- arrayToString2(from),
2851
- arrayToString2(to)
2852
- ].join(":");
2853
- },
2854
- getRangeFromCursor: (cursor) => {
2855
- invariant4(text.doc, void 0, {
2856
- F: __dxlog_file5,
2857
- L: 40,
2858
- S: void 0,
2859
- A: [
2860
- "text.doc",
2861
- ""
2862
- ]
2863
- });
2864
- const parts = cursor.split(":");
2865
- const from = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[0])), text.doc);
2866
- const to = Y2.createAbsolutePositionFromRelativePosition(Y2.decodeRelativePosition(stringToArray2(parts[1])), text.doc);
2867
- return from && to ? {
2868
- from: from.index,
2869
- to: to.index
2870
- } : void 0;
2871
- },
2872
2789
  extension: [
2873
2790
  modelState.init(() => model),
2874
2791
  yjs(text.content, provider?.awareness)
@@ -2918,7 +2835,7 @@ var YAwarenessProvider = class extends Observable {
2918
2835
  origin
2919
2836
  }, {
2920
2837
  F: __dxlog_file5,
2921
- L: 122,
2838
+ L: 100,
2922
2839
  S: this,
2923
2840
  C: (f, a) => f(...a)
2924
2841
  });
@@ -2931,7 +2848,7 @@ var YAwarenessProvider = class extends Observable {
2931
2848
  _handleSpaceMessage({ payload }) {
2932
2849
  log4("space message", payload, {
2933
2850
  F: __dxlog_file5,
2934
- L: 131,
2851
+ L: 109,
2935
2852
  S: this,
2936
2853
  C: (f, a) => f(...a)
2937
2854
  });
@@ -3040,7 +2957,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
3040
2957
  export {
3041
2958
  AwarenessProvider,
3042
2959
  BaseTextEditor,
3043
- CursorConverter,
2960
+ Cursor,
3044
2961
  Doc,
3045
2962
  EditorModes,
3046
2963
  MarkdownEditor,