@dxos/react-ui-editor 0.3.11-main.53a52d9 → 0.3.11-main.56ff0ac

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 (116) hide show
  1. package/dist/lib/browser/index.mjs +656 -680
  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 +13 -14
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +14 -6
  7. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  8. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
  9. package/dist/types/src/components/TextEditor/comments.stories.d.ts +1 -1
  10. package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +1 -1
  11. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  12. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  13. package/dist/types/src/extensions/automerge/defs.d.ts +7 -9
  14. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  15. package/dist/types/src/extensions/automerge/index.d.ts +0 -1
  16. package/dist/types/src/extensions/automerge/index.d.ts.map +1 -1
  17. package/dist/types/src/extensions/automerge/semaphore.d.ts +7 -12
  18. package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/update-automerge.d.ts +2 -2
  20. package/dist/types/src/extensions/awareness.d.ts +1 -1
  21. package/dist/types/src/extensions/awareness.d.ts.map +1 -1
  22. package/dist/types/src/extensions/basic.d.ts +4 -5
  23. package/dist/types/src/extensions/basic.d.ts.map +1 -1
  24. package/dist/types/src/extensions/code.d.ts.map +1 -1
  25. package/dist/types/src/extensions/comments.d.ts +30 -17
  26. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  27. package/dist/types/src/extensions/cursor.d.ts +3 -3
  28. package/dist/types/src/extensions/cursor.d.ts.map +1 -1
  29. package/dist/types/src/extensions/hr.d.ts.map +1 -1
  30. package/dist/types/src/extensions/index.d.ts +1 -1
  31. package/dist/types/src/extensions/index.d.ts.map +1 -1
  32. package/dist/types/src/extensions/markdown/bundle.d.ts +2 -5
  33. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  34. package/dist/types/src/extensions/mention.d.ts.map +1 -1
  35. package/dist/types/src/extensions/outliner.d.ts +4 -0
  36. package/dist/types/src/extensions/outliner.d.ts.map +1 -0
  37. package/dist/types/src/extensions/tasklist.d.ts.map +1 -1
  38. package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
  39. package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
  40. package/dist/types/src/hooks/defs.d.ts +25 -0
  41. package/dist/types/src/hooks/defs.d.ts.map +1 -0
  42. package/dist/types/src/hooks/index.d.ts +2 -2
  43. package/dist/types/src/hooks/index.d.ts.map +1 -1
  44. package/dist/types/src/hooks/useTextEditor.d.ts +17 -0
  45. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
  46. package/dist/types/src/hooks/useTextModel.d.ts +2 -27
  47. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  48. package/dist/types/src/themes/default.d.ts.map +1 -1
  49. package/dist/types/src/util.d.ts +2 -0
  50. package/dist/types/src/util.d.ts.map +1 -1
  51. package/package.json +33 -36
  52. package/src/components/TextEditor/MarkdownEditor.stories.tsx +64 -69
  53. package/src/components/TextEditor/TextEditor.tsx +95 -70
  54. package/src/components/TextEditor/comments.stories.tsx +113 -71
  55. package/src/extensions/autocomplete.ts +6 -3
  56. package/src/extensions/automerge/automerge.ts +39 -45
  57. package/src/extensions/automerge/defs.ts +10 -31
  58. package/src/extensions/automerge/index.ts +0 -1
  59. package/src/extensions/automerge/semaphore.ts +23 -20
  60. package/src/extensions/automerge/update-automerge.ts +2 -2
  61. package/src/extensions/awareness.ts +15 -14
  62. package/src/extensions/basic.ts +22 -17
  63. package/src/extensions/code.ts +15 -17
  64. package/src/extensions/comments.ts +239 -136
  65. package/src/extensions/cursor.ts +7 -3
  66. package/src/extensions/hr.ts +49 -50
  67. package/src/extensions/index.ts +1 -1
  68. package/src/extensions/link.ts +3 -3
  69. package/src/extensions/markdown/bundle.ts +18 -24
  70. package/src/extensions/mention.ts +9 -2
  71. package/src/extensions/outliner.ts +12 -0
  72. package/src/extensions/tasklist.ts +76 -84
  73. package/src/hooks/awareness-provider.ts +24 -20
  74. package/src/hooks/defs.ts +42 -0
  75. package/src/hooks/index.ts +3 -2
  76. package/src/hooks/useTextEditor.ts +29 -0
  77. package/src/hooks/useTextModel.ts +47 -56
  78. package/src/themes/default.ts +0 -8
  79. package/src/util.ts +26 -3
  80. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
  81. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
  82. package/dist/types/src/components/TextEditor/yjs.stories.d.ts +0 -12
  83. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  84. package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
  85. package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
  86. package/dist/types/src/extensions/yjs/index.d.ts +0 -2
  87. package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
  88. package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
  89. package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
  90. package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
  91. package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
  92. package/dist/types/src/hooks/automerge.d.ts +0 -3
  93. package/dist/types/src/hooks/automerge.d.ts.map +0 -1
  94. package/dist/types/src/hooks/yjs.d.ts +0 -27
  95. package/dist/types/src/hooks/yjs.d.ts.map +0 -1
  96. package/dist/types/src/testing/index.d.ts +0 -3
  97. package/dist/types/src/testing/index.d.ts.map +0 -1
  98. package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
  99. package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
  100. package/dist/types/src/testing/proto/index.d.ts +0 -2
  101. package/dist/types/src/testing/proto/index.d.ts.map +0 -1
  102. package/dist/types/src/testing/replicator.d.ts +0 -45
  103. package/dist/types/src/testing/replicator.d.ts.map +0 -1
  104. package/src/components/TextEditor/codemirror.stories.ts +0 -115
  105. package/src/components/TextEditor/yjs.stories.tsx +0 -56
  106. package/src/extensions/yjs/cursor.ts +0 -22
  107. package/src/extensions/yjs/index.ts +0 -5
  108. package/src/extensions/yjs/yjs.test.ts +0 -35
  109. package/src/extensions/yjs/yjs.ts +0 -16
  110. package/src/hooks/automerge.ts +0 -52
  111. package/src/hooks/yjs.ts +0 -156
  112. package/src/testing/index.ts +0 -6
  113. package/src/testing/proto/gen/schema.ts +0 -49
  114. package/src/testing/proto/index.ts +0 -5
  115. package/src/testing/proto/schema.proto +0 -15
  116. package/src/testing/replicator.ts +0 -184
@@ -7,14 +7,14 @@ 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 EditorView12 } from "@codemirror/view";
10
+ import { EditorView as EditorView13 } 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, useRef } from "react";
15
- import { generateName } from "@dxos/display-name";
14
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
15
+ import { log as log2 } from "@dxos/log";
16
16
  import { useThemeContext } from "@dxos/react-ui";
17
- import { getColorForValue, inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
17
+ import { attentionSurface, 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";
@@ -29,9 +29,11 @@ var autocomplete = ({ onSearch }) => {
29
29
  // https://codemirror.net/examples/autocompletion
30
30
  // https://codemirror.net/docs/ref/#autocomplete.autocompletion
31
31
  autocompletion({
32
- defaultKeymap: false,
33
- // Don't start unless key press.
34
- activateOnTyping: false
32
+ activateOnTyping: true,
33
+ // closeOnBlur: false,
34
+ // defaultKeymap: false,
35
+ // TODO(burdon): Styles/fragments.
36
+ tooltipClass: () => "shadow rounded"
35
37
  }),
36
38
  // TODO(burdon): Option to create new page?
37
39
  // TODO(burdon): Optional decoration via addToOptions
@@ -51,9 +53,10 @@ var autocomplete = ({ onSearch }) => {
51
53
  };
52
54
 
53
55
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
54
- import { Facet as Facet2, StateField } from "@codemirror/state";
55
- import { ViewPlugin } from "@codemirror/view";
56
+ import { StateField } from "@codemirror/state";
57
+ import { EditorView, ViewPlugin } from "@codemirror/view";
56
58
  import { next as A } from "@dxos/automerge/automerge";
59
+ import { invariant } from "@dxos/invariant";
57
60
 
58
61
  // packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
59
62
  import get from "lodash.get";
@@ -94,12 +97,12 @@ var cursorConverter = (handle, path) => ({
94
97
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
95
98
  import { Annotation, StateEffect } from "@codemirror/state";
96
99
  var effectType = StateEffect.define({});
100
+ var reconcileAnnotationType = Annotation.define();
101
+ var getPath = (state, field) => state.field(field).path;
102
+ var getLastHeads = (state, field) => state.field(field).lastHeads;
97
103
  var updateHeads = (newHeads) => effectType.of({
98
104
  newHeads
99
105
  });
100
- var getLastHeads = (state, field) => state.field(field).lastHeads;
101
- var getPath = (state, field) => state.field(field).path;
102
- var reconcileAnnotationType = Annotation.define();
103
106
  var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
104
107
 
105
108
  // packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
@@ -237,40 +240,42 @@ var charPath = (textPath, candidatePath) => {
237
240
 
238
241
  // packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
239
242
  var PatchSemaphore = class {
240
- constructor(_field) {
241
- this._field = _field;
243
+ // prettier-ignore
244
+ constructor(_handle, _state) {
245
+ this._handle = _handle;
246
+ this._state = _state;
242
247
  this._inReconcile = false;
243
- this._queue = [];
244
- this.reconcile = (handle, view) => {
245
- if (this._inReconcile) {
246
- return;
247
- }
248
- this._inReconcile = true;
249
- const path = getPath(view.state, this._field);
250
- const oldHeads = getLastHeads(view.state, this._field);
251
- let selection = view.state.selection;
252
- const transactions = view.state.field(this._field).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
253
- const toInvert = transactions.slice().reverse();
254
- for (const tx of toInvert) {
255
- const inverted = tx.changes.invert(tx.startState.doc);
256
- selection = selection.map(inverted);
257
- view.dispatch({
258
- changes: inverted,
259
- annotations: reconcileAnnotationType.of(true)
260
- });
261
- }
262
- let newHeads = updateAutomerge(this._field, handle, transactions, view.state);
263
- if (newHeads === null || newHeads === void 0) {
264
- newHeads = automerge2.getHeads(handle.docSync());
265
- }
266
- const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(handle.docSync(), oldHeads, newHeads);
267
- updateCodeMirror(view, selection, path, diff);
248
+ }
249
+ // NOTE: Cannot destruct view.state.
250
+ reconcile(view) {
251
+ if (this._inReconcile) {
252
+ return;
253
+ }
254
+ this._inReconcile = true;
255
+ const path = getPath(view.state, this._state);
256
+ const oldHeads = getLastHeads(view.state, this._state);
257
+ let selection = view.state.selection;
258
+ const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
259
+ const toInvert = transactions.slice().reverse();
260
+ for (const tx of toInvert) {
261
+ const inverted = tx.changes.invert(tx.startState.doc);
262
+ selection = selection.map(inverted);
268
263
  view.dispatch({
269
- effects: updateHeads(newHeads),
270
- annotations: reconcileAnnotationType.of({})
264
+ changes: inverted,
265
+ annotations: reconcileAnnotationType.of(true)
271
266
  });
272
- this._inReconcile = false;
273
- };
267
+ }
268
+ let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
269
+ if (newHeads === null || newHeads === void 0) {
270
+ newHeads = automerge2.getHeads(this._handle.docSync());
271
+ }
272
+ const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
273
+ updateCodeMirror(view, selection, path, diff);
274
+ view.dispatch({
275
+ effects: updateHeads(newHeads),
276
+ annotations: reconcileAnnotationType.of({})
277
+ });
278
+ this._inReconcile = false;
274
279
  }
275
280
  };
276
281
 
@@ -280,16 +285,17 @@ var defaultCursorConverter = {
280
285
  toCursor: (position) => position.toString(),
281
286
  fromCursor: (cursor) => parseInt(cursor)
282
287
  };
283
- var Cursor = class {
288
+ var Cursor = class _Cursor {
284
289
  static {
285
290
  this.converter = Facet.define({
286
291
  combine: (providers) => providers[0] ?? defaultCursorConverter
287
292
  });
288
293
  }
289
294
  static {
290
- this.getCursorFromRange = (cursorConverter3, range) => {
291
- const from = cursorConverter3.toCursor(range.from);
292
- const to = cursorConverter3.toCursor(range.to, -1);
295
+ this.getCursorFromRange = (state, range) => {
296
+ const cursorConverter2 = state.facet(_Cursor.converter);
297
+ const from = cursorConverter2.toCursor(range.from);
298
+ const to = cursorConverter2.toCursor(range.to, -1);
293
299
  return [
294
300
  from,
295
301
  to
@@ -297,10 +303,11 @@ var Cursor = class {
297
303
  };
298
304
  }
299
305
  static {
300
- this.getRangeFromCursor = (cursorConverter3, cursor) => {
306
+ this.getRangeFromCursor = (state, cursor) => {
307
+ const cursorConverter2 = state.facet(_Cursor.converter);
301
308
  const parts = cursor.split(":");
302
- const from = cursorConverter3.fromCursor(parts[0]);
303
- const to = cursorConverter3.fromCursor(parts[1]);
309
+ const from = cursorConverter2.fromCursor(parts[0]);
310
+ const to = cursorConverter2.fromCursor(parts[1]);
304
311
  return from !== void 0 && to !== void 0 ? {
305
312
  from,
306
313
  to
@@ -310,21 +317,19 @@ var Cursor = class {
310
317
  };
311
318
 
312
319
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
313
- var semaphoreFacet = Facet2.define({
314
- combine: (values) => values.at(-1)
315
- });
320
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts";
316
321
  var automerge3 = ({ handle, path }) => {
317
- const stateField = StateField.define({
322
+ const state = StateField.define({
318
323
  create: () => ({
324
+ path: path.slice(),
319
325
  lastHeads: A.getHeads(handle.docSync()),
320
- unreconciledTransactions: [],
321
- path: path.slice()
326
+ unreconciledTransactions: []
322
327
  }),
323
328
  update: (value, tr) => {
324
329
  const result = {
330
+ path: path.slice(),
325
331
  lastHeads: value.lastHeads,
326
- unreconciledTransactions: value.unreconciledTransactions.slice(),
327
- path: path.slice()
332
+ unreconciledTransactions: value.unreconciledTransactions.slice()
328
333
  };
329
334
  let clearUnreconciled = false;
330
335
  for (const effect of tr.effects) {
@@ -343,39 +348,44 @@ var automerge3 = ({ handle, path }) => {
343
348
  return result;
344
349
  }
345
350
  });
346
- const semaphore = new PatchSemaphore(stateField);
347
- const viewPlugin = ViewPlugin.fromClass(class AutomergeCodemirrorViewPlugin {
348
- constructor(_view) {
349
- this._view = _view;
350
- this._handleChange = () => {
351
- this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
352
- };
353
- handle.addListener("change", this._handleChange);
354
- }
355
- update(update2) {
356
- if (update2.transactions.length > 0 && update2.transactions.some((tr) => !isReconcileTx(tr))) {
357
- queueMicrotask(() => {
358
- this._view.state.facet(semaphoreFacet).reconcile(handle, this._view);
351
+ const semaphore = new PatchSemaphore(handle, state);
352
+ return [
353
+ Cursor.converter.of(cursorConverter(handle, path)),
354
+ // Reconcile external updates.
355
+ ViewPlugin.fromClass(class {
356
+ constructor(_view) {
357
+ this._view = _view;
358
+ invariant(this._view, void 0, {
359
+ F: __dxlog_file,
360
+ L: 66,
361
+ S: this,
362
+ A: [
363
+ "this._view",
364
+ ""
365
+ ]
359
366
  });
367
+ handle.addListener("change", this._handleChange.bind(this));
360
368
  }
361
- }
362
- destroy() {
363
- handle.addListener("change", this._handleChange);
364
- }
365
- });
366
- return {
367
- extension: [
368
- Cursor.converter.of(cursorConverter(handle, path)),
369
- semaphoreFacet.of(semaphore),
370
- stateField,
371
- viewPlugin
372
- ]
373
- };
369
+ destroy() {
370
+ handle.removeListener("change", this._handleChange.bind(this));
371
+ }
372
+ _handleChange() {
373
+ semaphore.reconcile(this._view);
374
+ }
375
+ }),
376
+ // Reconcile local updates.
377
+ EditorView.updateListener.of(({ view, changes }) => {
378
+ if (!changes.empty) {
379
+ semaphore.reconcile(view);
380
+ }
381
+ }),
382
+ state
383
+ ];
374
384
  };
375
385
 
376
386
  // packages/ui/react-ui-editor/src/extensions/awareness.ts
377
- import { Annotation as Annotation2, Facet as Facet3, RangeSet } from "@codemirror/state";
378
- import { Decoration, EditorView, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
387
+ import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
388
+ import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
379
389
  import { Event } from "@dxos/async";
380
390
  import { Context } from "@dxos/context";
381
391
  var dummyProvider = {
@@ -384,11 +394,11 @@ var dummyProvider = {
384
394
  },
385
395
  close: () => {
386
396
  },
397
+ getRemoteStates: () => [],
387
398
  update: () => {
388
- },
389
- getRemoteStates: () => []
399
+ }
390
400
  };
391
- var AwarenessProvider = Facet3.define({
401
+ var AwarenessProvider = Facet2.define({
392
402
  combine: (providers) => providers[0] ?? dummyProvider
393
403
  });
394
404
  var RemoteSelectionChangedAnnotation = Annotation2.define();
@@ -549,7 +559,7 @@ var RemoteCaretWidget = class extends WidgetType {
549
559
  return true;
550
560
  }
551
561
  };
552
- var styles = EditorView.baseTheme({
562
+ var styles = EditorView2.baseTheme({
553
563
  ".cm-collab-selection": {},
554
564
  ".cm-collab-selectionLine": {
555
565
  padding: 0,
@@ -562,40 +572,42 @@ var styles = EditorView.baseTheme({
562
572
  marginLeft: "-1px",
563
573
  marginRight: "-1px",
564
574
  boxSizing: "border-box",
565
- display: "inline"
575
+ display: "inline",
576
+ cursor: "pointer"
566
577
  },
567
578
  ".cm-collab-selectionCaretDot": {
568
579
  borderRadius: "50%",
569
580
  position: "absolute",
570
- width: ".4em",
571
- height: ".4em",
572
- top: "-.2em",
573
- left: "-.2em",
581
+ width: ".5em",
582
+ height: ".5em",
583
+ top: "-.25em",
584
+ left: "-.25em",
574
585
  backgroundColor: "inherit",
575
586
  transition: "transform .3s ease-in-out",
576
587
  boxSizing: "border-box"
577
588
  },
578
589
  ".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
579
- transformOrigin: "bottom center",
580
- transform: "scale(0)"
590
+ transform: "scale(0)",
591
+ transformOrigin: "center"
581
592
  },
582
593
  ".cm-collab-selectionInfo": {
583
594
  position: "absolute",
584
- top: "-1.05em",
585
- left: "-1px",
595
+ transform: "translate(-50%, 0)",
596
+ top: "-20px",
597
+ left: 0,
586
598
  fontSize: ".75em",
587
- fontFamily: "serif",
599
+ fontFamily: "sans-serif",
588
600
  fontStyle: "normal",
589
601
  fontWeight: "normal",
590
602
  lineHeight: "normal",
591
603
  userSelect: "none",
592
604
  color: "white",
593
- paddingLeft: "2px",
594
- paddingRight: "2px",
605
+ padding: "2px",
595
606
  zIndex: 101,
596
607
  transition: "opacity .3s ease-in-out",
597
608
  backgroundColor: "inherit",
598
- // these should be separate
609
+ borderRadius: "2px",
610
+ // These should be separate.
599
611
  opacity: 0,
600
612
  transitionDelay: "0s",
601
613
  whiteSpace: "nowrap"
@@ -608,26 +620,28 @@ var styles = EditorView.baseTheme({
608
620
 
609
621
  // packages/ui/react-ui-editor/src/extensions/basic.ts
610
622
  import { closeBrackets } from "@codemirror/autocomplete";
623
+ import { history } from "@codemirror/commands";
611
624
  import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
612
625
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
613
- import { drawSelection, EditorView as EditorView2, placeholder } from "@codemirror/view";
614
- var basicBundle = ({ readonly, themeMode, placeholder: _placeholder }) => [
615
- EditorView2.lineWrapping,
616
- // TODO(burdon): Compare with minimalSetup.
626
+ import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
627
+ var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
628
+ lineWrapping ? EditorView3.lineWrapping : [],
617
629
  // https://codemirror.net/docs/ref/#codemirror.minimalSetup
618
630
  bracketMatching(),
619
631
  closeBrackets(),
620
632
  drawSelection(),
621
- _placeholder && placeholder(_placeholder),
622
- // TODO(burdon): Is this required?
633
+ highlightActiveLine(),
634
+ history(),
635
+ _placeholder ? placeholder(_placeholder) : [],
636
+ // https://github.com/codemirror/theme-one-dark
623
637
  themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
624
- ].filter(Boolean);
638
+ ];
625
639
 
626
640
  // packages/ui/react-ui-editor/src/extensions/blast.ts
627
- import { EditorView as EditorView3, keymap as keymap2 } from "@codemirror/view";
641
+ import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
628
642
  import defaultsDeep from "lodash.defaultsdeep";
629
- import { invariant } from "@dxos/invariant";
630
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
643
+ import { invariant as invariant2 } from "@dxos/invariant";
644
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
631
645
  var defaultOptions = {
632
646
  effect: 2,
633
647
  maxParticles: 200,
@@ -672,7 +686,7 @@ var blast = (options = defaultOptions) => {
672
686
  };
673
687
  return [
674
688
  // Cursor moved.
675
- EditorView3.updateListener.of((update2) => {
689
+ EditorView4.updateListener.of((update2) => {
676
690
  if (blaster?.node !== update2.view.scrollDOM) {
677
691
  if (blaster) {
678
692
  blaster.destroy();
@@ -753,8 +767,8 @@ var Blaster = class {
753
767
  return this._node;
754
768
  }
755
769
  initialize() {
756
- invariant(!this._canvas && !this._ctx, void 0, {
757
- F: __dxlog_file,
770
+ invariant2(!this._canvas && !this._ctx, void 0, {
771
+ F: __dxlog_file2,
758
772
  L: 138,
759
773
  S: this,
760
774
  A: [
@@ -790,8 +804,8 @@ var Blaster = class {
790
804
  }
791
805
  }
792
806
  start() {
793
- invariant(this._canvas && this._ctx, void 0, {
794
- F: __dxlog_file,
807
+ invariant2(this._canvas && this._ctx, void 0, {
808
+ F: __dxlog_file2,
795
809
  L: 177,
796
810
  S: this,
797
811
  A: [
@@ -934,7 +948,7 @@ var random = (min, max) => {
934
948
  };
935
949
 
936
950
  // packages/ui/react-ui-editor/src/extensions/code.ts
937
- import { ViewPlugin as ViewPlugin3, EditorView as EditorView4, Decoration as Decoration2 } from "@codemirror/view";
951
+ import { ViewPlugin as ViewPlugin3, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
938
952
  import { mx as mx2 } from "@dxos/react-ui-theme";
939
953
 
940
954
  // packages/ui/react-ui-editor/src/styles/cursors.ts
@@ -1025,7 +1039,7 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
1025
1039
 
1026
1040
  // packages/ui/react-ui-editor/src/extensions/code.ts
1027
1041
  var CODE_REGEX = /```[\s\S]*?```/gs;
1028
- var styles2 = EditorView4.baseTheme({
1042
+ var styles2 = EditorView5.baseTheme({
1029
1043
  "& .cm-codeblock": {
1030
1044
  fontFamily: getToken("fontFamily.mono", []).join(",")
1031
1045
  },
@@ -1059,20 +1073,18 @@ var getLineRange = (lines, from, to) => {
1059
1073
  ];
1060
1074
  };
1061
1075
  var code2 = () => {
1062
- const getDecorations = (view) => {
1076
+ const buildDecorations5 = (view) => {
1063
1077
  const decorations = [];
1064
- if (!view.hasFocus || view.state.readOnly) {
1065
- const text = view.state.doc.sliceString(0);
1066
- const matches = text.matchAll(CODE_REGEX);
1067
- const blocks = view.viewportLineBlocks;
1068
- for (const match of matches) {
1069
- const range = getLineRange(blocks, match.index, match.index + match[0].length);
1070
- for (let i = range[0]; i <= range[1]; i++) {
1071
- const block = blocks[i];
1072
- decorations.push(Decoration2.line({
1073
- class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1074
- }).range(block.from));
1075
- }
1078
+ const text = view.state.doc.sliceString(0);
1079
+ const matches = text.matchAll(CODE_REGEX);
1080
+ const blocks = view.viewportLineBlocks;
1081
+ for (const match of matches) {
1082
+ const range = getLineRange(blocks, match.index, match.index + match[0].length);
1083
+ for (let i = range[0]; i <= range[1]; i++) {
1084
+ const block = blocks[i];
1085
+ decorations.push(Decoration2.line({
1086
+ class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1087
+ }).range(block.from));
1076
1088
  }
1077
1089
  }
1078
1090
  return Decoration2.set(decorations);
@@ -1081,7 +1093,7 @@ var code2 = () => {
1081
1093
  ViewPlugin3.fromClass(class {
1082
1094
  constructor(view) {
1083
1095
  this.hasFocus = false;
1084
- this.decorations = getDecorations(view);
1096
+ this.decorations = buildDecorations5(view);
1085
1097
  }
1086
1098
  update(update2) {
1087
1099
  if (
@@ -1089,7 +1101,7 @@ var code2 = () => {
1089
1101
  this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1090
1102
  ) {
1091
1103
  this.hasFocus = update2.view.hasFocus;
1092
- this.decorations = getDecorations(update2.view);
1104
+ this.decorations = buildDecorations5(update2.view);
1093
1105
  }
1094
1106
  }
1095
1107
  }, {
@@ -1101,36 +1113,55 @@ var code2 = () => {
1101
1113
 
1102
1114
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1103
1115
  import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1104
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView5 } from "@codemirror/view";
1116
+ import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
1105
1117
  import sortBy from "lodash.sortby";
1118
+ import { useEffect } from "react";
1106
1119
  import { debounce } from "@dxos/async";
1107
- import { invariant as invariant2 } from "@dxos/invariant";
1108
- import { log as log2 } from "@dxos/log";
1120
+ import { invariant as invariant3 } from "@dxos/invariant";
1109
1121
  import { nonNullable } from "@dxos/util";
1110
1122
 
1111
1123
  // packages/ui/react-ui-editor/src/util.ts
1112
1124
  import { log } from "@dxos/log";
1113
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1125
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1114
1126
  var callbackWrapper = (fn) => (...args) => {
1115
1127
  try {
1116
1128
  return fn(...args);
1117
- } catch (error) {
1118
- log.catch(error, void 0, {
1119
- F: __dxlog_file2,
1120
- L: 16,
1129
+ } catch (err) {
1130
+ log.catch(err, void 0, {
1131
+ F: __dxlog_file3,
1132
+ L: 18,
1121
1133
  S: void 0,
1122
1134
  C: (f, a) => f(...a)
1123
1135
  });
1124
1136
  }
1125
1137
  };
1138
+ var logChanges = (trs) => {
1139
+ const changes = trs.flatMap((tr) => {
1140
+ if (tr.changes.empty) {
1141
+ return void 0;
1142
+ }
1143
+ const changes2 = [];
1144
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
1145
+ fromA,
1146
+ toA,
1147
+ fromB,
1148
+ toB,
1149
+ inserted: inserted.toString()
1150
+ })));
1151
+ return changes2;
1152
+ }).filter(Boolean);
1153
+ if (changes.length) {
1154
+ console.log("changes", changes);
1155
+ }
1156
+ };
1126
1157
 
1127
1158
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1128
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1129
- var styles3 = EditorView5.baseTheme({
1159
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1160
+ var styles3 = EditorView6.baseTheme({
1130
1161
  "& .cm-comment": {
1131
1162
  backgroundColor: getToken("extend.colors.yellow.50")
1132
1163
  },
1133
- "& .cm-comment-active": {
1164
+ "& .cm-comment-current": {
1134
1165
  backgroundColor: getToken("extend.colors.yellow.100")
1135
1166
  }
1136
1167
  });
@@ -1139,52 +1170,62 @@ var marks = {
1139
1170
  class: "cm-comment"
1140
1171
  }),
1141
1172
  highlightActive: Decoration3.mark({
1142
- class: "cm-comment-active"
1173
+ class: "cm-comment-current"
1143
1174
  })
1144
1175
  };
1145
- var setFocus = (view, thread) => {
1146
- const range = view.state.field(commentsStateField).ranges.find((range2) => range2.id === thread);
1147
- if (!range) {
1176
+ var setFocus = (view, id, center = true) => {
1177
+ const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
1178
+ if (!comment?.comment.cursor) {
1148
1179
  return;
1149
1180
  }
1150
- view.dispatch({
1151
- effects: setSelection.of({
1152
- active: thread
1153
- }),
1154
- selection: {
1155
- anchor: range.from
1156
- },
1157
- scrollIntoView: true
1158
- });
1181
+ const range = Cursor.getRangeFromCursor(view.state, comment.comment.cursor);
1182
+ if (range) {
1183
+ view.dispatch({
1184
+ selection: {
1185
+ anchor: range.from
1186
+ },
1187
+ effects: [
1188
+ //
1189
+ EditorView6.scrollIntoView(range.from, center ? {
1190
+ y: "center"
1191
+ } : void 0),
1192
+ setSelection.of({
1193
+ current: id
1194
+ })
1195
+ ]
1196
+ });
1197
+ }
1159
1198
  };
1160
- var setCommentRange = StateEffect2.define();
1199
+ var setComments = StateEffect2.define();
1161
1200
  var setSelection = StateEffect2.define();
1162
1201
  var setCommentState = StateEffect2.define();
1163
- var commentsStateField = StateField2.define({
1202
+ var commentsState = StateField2.define({
1164
1203
  create: () => ({
1165
- ranges: []
1204
+ comments: [],
1205
+ selection: {}
1166
1206
  }),
1167
1207
  update: (value, tr) => {
1168
- const cursorConverter3 = tr.state.facet(Cursor.converter);
1169
1208
  for (const effect of tr.effects) {
1170
1209
  if (effect.is(setSelection)) {
1171
1210
  return {
1172
1211
  ...value,
1173
- ...effect.value
1212
+ selection: effect.value
1174
1213
  };
1175
1214
  }
1176
- if (effect.is(setCommentRange)) {
1177
- const { comments: comments2 } = effect.value;
1178
- const ranges = comments2.map((comment) => {
1179
- const range = Cursor.getRangeFromCursor(cursorConverter3, comment.cursor);
1215
+ if (effect.is(setComments)) {
1216
+ const comments2 = effect.value.map((comment) => {
1217
+ if (!comment.cursor) {
1218
+ return void 0;
1219
+ }
1220
+ const range = Cursor.getRangeFromCursor(tr.state, comment.cursor);
1180
1221
  return range && {
1181
- ...comment,
1182
- ...range
1222
+ comment,
1223
+ range
1183
1224
  };
1184
1225
  }).filter(nonNullable);
1185
1226
  return {
1186
1227
  ...value,
1187
- ranges
1228
+ comments: comments2
1188
1229
  };
1189
1230
  }
1190
1231
  if (effect.is(setCommentState)) {
@@ -1194,78 +1235,125 @@ var commentsStateField = StateField2.define({
1194
1235
  return value;
1195
1236
  }
1196
1237
  });
1197
- var highlightDecorations = EditorView5.decorations.compute([
1198
- commentsStateField
1238
+ var highlightDecorations = EditorView6.decorations.compute([
1239
+ commentsState
1199
1240
  ], (state) => {
1200
- const { active, ranges } = state.field(commentsStateField);
1201
- const decorations = sortBy(ranges ?? [], (range) => range.from)?.flatMap((selection) => {
1202
- if (selection.from === selection.to) {
1241
+ const { selection: { current }, comments: comments2 } = state.field(commentsState);
1242
+ const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1243
+ const range = comment.range;
1244
+ if (!range || range.from === range.to) {
1245
+ console.warn("Invalid range:", range);
1203
1246
  return void 0;
1204
1247
  }
1205
- const range = {
1206
- from: selection.from,
1207
- to: selection.to
1208
- };
1209
- if (selection.id === active) {
1248
+ if (comment.comment.id === current) {
1210
1249
  return marks.highlightActive.range(range.from, range.to);
1211
1250
  } else {
1212
1251
  return marks.highlight.range(range.from, range.to);
1213
1252
  }
1214
- }).filter(nonNullable) ?? [];
1253
+ }).filter(nonNullable);
1215
1254
  return Decoration3.set(decorations);
1216
1255
  });
1256
+ var trackPastedComments = (onUpdate) => {
1257
+ let tracked = null;
1258
+ const handleTrack = (event, view) => {
1259
+ const comments2 = view.state.field(commentsState);
1260
+ const { main } = view.state.selection;
1261
+ const selectedRanges = comments2.comments.filter(({ range }) => range.from >= main.from && range.to <= main.to && range.from < range.to);
1262
+ if (!selectedRanges.length) {
1263
+ tracked = null;
1264
+ } else {
1265
+ tracked = {
1266
+ text: view.state.doc.slice(main.from, main.to),
1267
+ comments: selectedRanges.map(({ comment, range }) => ({
1268
+ id: comment.id,
1269
+ from: range.from - main.from,
1270
+ to: range.to - main.from
1271
+ }))
1272
+ };
1273
+ }
1274
+ };
1275
+ return [
1276
+ EditorView6.domEventHandlers({
1277
+ cut: handleTrack,
1278
+ copy: handleTrack
1279
+ }),
1280
+ // Handle paste.
1281
+ EditorView6.updateListener.of(({ view, state, transactions }) => {
1282
+ if (tracked) {
1283
+ const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
1284
+ if (paste) {
1285
+ let found = -1;
1286
+ paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
1287
+ if (text.eq(tracked.text)) {
1288
+ for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
1289
+ fromB = transactions[i].changes.mapPos(fromB);
1290
+ }
1291
+ found = fromB;
1292
+ }
1293
+ });
1294
+ if (found > -1) {
1295
+ for (const moved of tracked.comments) {
1296
+ const range = {
1297
+ from: found + moved.from,
1298
+ to: found + moved.to
1299
+ };
1300
+ const cursor = Cursor.getCursorFromRange(state, range);
1301
+ onUpdate(moved.id, cursor);
1302
+ }
1303
+ }
1304
+ tracked = null;
1305
+ }
1306
+ }
1307
+ })
1308
+ ];
1309
+ };
1217
1310
  var comments = (options = {}) => {
1218
1311
  const { key: shortcut = "meta-'" } = options;
1219
1312
  const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1220
1313
  const createCommentThread = (view) => {
1221
- const cursorConverter3 = view.state.facet(Cursor.converter);
1222
- invariant2(options.onCreate, void 0, {
1223
- F: __dxlog_file3,
1224
- L: 177,
1314
+ invariant3(options.onCreate, void 0, {
1315
+ F: __dxlog_file4,
1316
+ L: 259,
1225
1317
  S: void 0,
1226
1318
  A: [
1227
1319
  "options.onCreate",
1228
1320
  ""
1229
1321
  ]
1230
1322
  });
1231
- const { head, from, to } = view.state.selection.main;
1323
+ const { from, to } = view.state.selection.main;
1232
1324
  if (from === to) {
1233
1325
  return false;
1234
1326
  }
1235
- const cursor = Cursor.getCursorFromRange(cursorConverter3, {
1327
+ if (to === view.state.doc.length) {
1328
+ view.dispatch({
1329
+ changes: {
1330
+ from: to,
1331
+ insert: "\n"
1332
+ }
1333
+ });
1334
+ }
1335
+ const cursor = Cursor.getCursorFromRange(view.state, {
1236
1336
  from,
1237
1337
  to
1238
1338
  });
1239
1339
  if (cursor) {
1240
- const id = callbackWrapper(options.onCreate)(cursor, view.coordsAtPos(from));
1340
+ const id = options.onCreate?.(cursor, view.coordsAtPos(from));
1241
1341
  if (id) {
1242
1342
  view.dispatch({
1243
1343
  effects: setSelection.of({
1244
- active: id
1344
+ current: id
1245
1345
  }),
1246
1346
  selection: {
1247
1347
  anchor: from
1248
1348
  }
1249
1349
  });
1250
- if (options.footnote) {
1251
- const tag = `[^${id}]`;
1252
- view.dispatch({
1253
- changes: {
1254
- from: head,
1255
- insert: tag
1256
- },
1257
- selection: {
1258
- anchor: head + tag.length
1259
- }
1260
- });
1261
- }
1262
1350
  return true;
1263
1351
  }
1264
1352
  }
1265
1353
  return false;
1266
1354
  };
1267
1355
  return [
1268
- commentsStateField,
1356
+ commentsState,
1269
1357
  highlightDecorations,
1270
1358
  styles3,
1271
1359
  //
@@ -1290,7 +1378,7 @@ var comments = (options = {}) => {
1290
1378
  above: true,
1291
1379
  create: () => {
1292
1380
  const el = document.createElement("div");
1293
- options.onHover?.(el, shortcut);
1381
+ options.onHover(el, shortcut);
1294
1382
  return {
1295
1383
  dom: el,
1296
1384
  offset: {
@@ -1303,139 +1391,154 @@ var comments = (options = {}) => {
1303
1391
  }
1304
1392
  return null;
1305
1393
  }, {
1306
- hideOnChange: true,
1394
+ // TODO(burdon): Hide on change triggered immediately?
1395
+ // hideOnChange: true,
1307
1396
  hoverTime: 1e3
1308
1397
  }) : [],
1309
1398
  //
1310
- // Monitor cursor movement and text updates.
1311
- // TODO(burdon): Is there a better (finer grained) way to do this?
1399
+ // Track deleted ranges and update ranges for decorations.
1312
1400
  //
1313
- EditorView5.updateListener.of(({ view, state, changes }) => {
1314
- const cursorConverter3 = view.state.facet(Cursor.converter);
1315
- {
1316
- let mod = false;
1317
- const { active, ranges } = state.field(commentsStateField);
1318
- changes.iterChanges((from, to, from2, to2) => {
1319
- ranges.forEach((range) => {
1320
- if (from2 === to2) {
1321
- const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1322
- if (!newRange || newRange.to - newRange.from === 0) {
1323
- log2.info("deleted comment", {
1324
- thread: range.id
1325
- }, {
1326
- F: __dxlog_file3,
1327
- L: 274,
1328
- S: void 0,
1329
- C: (f, a) => f(...a)
1330
- });
1331
- }
1332
- }
1333
- if (from <= range.to) {
1334
- const newRange = Cursor.getRangeFromCursor(cursorConverter3, range.cursor);
1335
- Object.assign(range, newRange);
1336
- mod = true;
1401
+ EditorView6.updateListener.of(({ view, state, changes }) => {
1402
+ let mod = false;
1403
+ const { comments: comments2, ...value } = state.field(commentsState);
1404
+ changes.iterChanges((from, to, from2, to2) => {
1405
+ comments2.forEach(({ comment, range }) => {
1406
+ if (from2 === to2) {
1407
+ const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
1408
+ if (!newRange || newRange.to - newRange.from === 0) {
1409
+ options.onDelete?.(comment.id);
1337
1410
  }
1338
- });
1411
+ }
1412
+ if (from <= range.to) {
1413
+ const newRange = Cursor.getRangeFromCursor(view.state, comment.cursor);
1414
+ Object.assign(range, newRange);
1415
+ mod = true;
1416
+ }
1417
+ });
1418
+ });
1419
+ if (mod) {
1420
+ view.dispatch({
1421
+ effects: setCommentState.of({
1422
+ comments: comments2,
1423
+ ...value
1424
+ })
1339
1425
  });
1340
- if (mod) {
1341
- view.dispatch({
1342
- effects: setCommentState.of({
1343
- active,
1344
- ranges
1345
- })
1346
- });
1347
- }
1348
1426
  }
1349
- {
1350
- const { head } = state.selection.main;
1351
- let min = Infinity;
1352
- const { active, closest, ranges } = state.field(commentsStateField);
1353
- const selected = {
1354
- active: void 0,
1355
- closest: void 0
1356
- };
1357
- ranges.forEach((comment) => {
1358
- const d = Math.min(Math.abs(head - comment.from), Math.abs(head - comment.to));
1359
- if (head >= comment.from && head <= comment.to) {
1360
- selected.active = comment.id;
1361
- }
1427
+ }),
1428
+ //
1429
+ // Track selection/proximity.
1430
+ //
1431
+ EditorView6.updateListener.of(({ view, state }) => {
1432
+ let min = Infinity;
1433
+ const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1434
+ const { head } = state.selection.main;
1435
+ const selection = {};
1436
+ comments2.forEach(({ comment, range }) => {
1437
+ if (head >= range.from && head <= range.to) {
1438
+ selection.current = comment.id;
1439
+ selection.closest = void 0;
1440
+ }
1441
+ if (!selection.current) {
1442
+ const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
1362
1443
  if (d < min) {
1363
- selected.closest = comment.id;
1444
+ selection.closest = comment.id;
1364
1445
  min = d;
1365
1446
  }
1366
- });
1367
- if (selected.active !== active || selected.closest !== closest) {
1368
- view.dispatch({
1369
- effects: setSelection.of(selected)
1370
- });
1371
- handleSelect({
1372
- ...selected,
1373
- ranges: ranges.map((range) => ({
1374
- ...range,
1375
- location: view.coordsAtPos(range.from)
1376
- }))
1377
- });
1378
1447
  }
1448
+ });
1449
+ if (selection.current !== current || selection.closest !== closest) {
1450
+ view.dispatch({
1451
+ effects: setSelection.of(selection)
1452
+ });
1453
+ handleSelect({
1454
+ selection,
1455
+ comments: comments2.map(({ comment, range }) => ({
1456
+ comment,
1457
+ range,
1458
+ location: view.coordsAtPos(range.from)
1459
+ }))
1460
+ });
1379
1461
  }
1380
- })
1462
+ }),
1463
+ options.onUpdate ? trackPastedComments(options.onUpdate) : []
1381
1464
  ];
1382
1465
  };
1466
+ var useComments = (view, comments2 = []) => {
1467
+ useEffect(() => {
1468
+ if (view) {
1469
+ view.dispatch({
1470
+ effects: setComments.of(comments2)
1471
+ });
1472
+ }
1473
+ }, [
1474
+ view,
1475
+ comments2
1476
+ ]);
1477
+ };
1383
1478
 
1384
1479
  // packages/ui/react-ui-editor/src/extensions/hr.ts
1385
- import { Decoration as Decoration4, EditorView as EditorView6, MatchDecorator, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1386
- var styles4 = EditorView6.baseTheme({
1480
+ import { syntaxTree } from "@codemirror/language";
1481
+ import { RangeSetBuilder } from "@codemirror/state";
1482
+ import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin4, WidgetType as WidgetType2 } from "@codemirror/view";
1483
+ var styles4 = EditorView7.baseTheme({
1387
1484
  "& .cm-hr": {
1388
- // TODO(burdon): ???
1389
1485
  // Note that block-level decorations should not have vertical margins,
1390
- borderBottom: `1px solid ${getToken("extend.colors.neutral.200")}`
1486
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
1391
1487
  }
1392
1488
  });
1393
1489
  var HorizontalRuleWidget = class extends WidgetType2 {
1394
- constructor(_pos) {
1395
- super();
1396
- this._pos = _pos;
1397
- }
1398
- eq(other) {
1399
- return this._pos === other._pos;
1400
- }
1401
- toDOM(view) {
1490
+ toDOM() {
1402
1491
  const el = document.createElement("div");
1403
1492
  el.className = "cm-hr";
1404
1493
  return el;
1405
1494
  }
1406
1495
  };
1407
- var placeholderMatcher = new MatchDecorator({
1408
- regexp: /^---$/g,
1409
- decoration: (match, view, pos) => Decoration4.replace({
1410
- widget: new HorizontalRuleWidget(pos)
1411
- })
1496
+ var decoration = Decoration4.replace({
1497
+ widget: new HorizontalRuleWidget()
1412
1498
  });
1413
- var hr = () => [
1414
- styles4,
1415
- ViewPlugin4.fromClass(class {
1416
- constructor(view) {
1417
- this.rules = placeholderMatcher.createDeco(view);
1418
- }
1419
- update(update2) {
1420
- this.rules = placeholderMatcher.updateDeco(update2, this.rules);
1421
- }
1422
- }, {
1423
- decorations: (instance) => instance.rules,
1424
- // TODO(burdon): Is this really atomic (cursor can move into ---).
1425
- provide: (plugin) => EditorView6.atomicRanges.of((view) => {
1426
- return view.plugin(plugin)?.rules || Decoration4.none;
1499
+ var buildDecorations = (view) => {
1500
+ const builder = new RangeSetBuilder();
1501
+ const { state } = view;
1502
+ const cursor = state.selection.main.head;
1503
+ for (const { from, to } of view.visibleRanges) {
1504
+ syntaxTree(state).iterate({
1505
+ enter: (node) => {
1506
+ if (node.name === "HorizontalRule") {
1507
+ if (cursor <= node.from || cursor >= node.to) {
1508
+ builder.add(node.from, node.to, decoration);
1509
+ }
1510
+ }
1511
+ },
1512
+ from,
1513
+ to
1514
+ });
1515
+ }
1516
+ return builder.finish();
1517
+ };
1518
+ var hr = () => {
1519
+ return [
1520
+ styles4,
1521
+ ViewPlugin4.fromClass(class {
1522
+ constructor(view) {
1523
+ this.decorations = buildDecorations(view);
1524
+ }
1525
+ update(update2) {
1526
+ this.decorations = buildDecorations(update2.view);
1527
+ }
1528
+ }, {
1529
+ decorations: (v) => v.decorations
1427
1530
  })
1428
- })
1429
- ];
1531
+ ];
1532
+ };
1430
1533
 
1431
1534
  // packages/ui/react-ui-editor/src/extensions/image.ts
1432
- import { syntaxTree } from "@codemirror/language";
1535
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1433
1536
  import { StateField as StateField3 } from "@codemirror/state";
1434
- import { Decoration as Decoration5, EditorView as EditorView7, WidgetType as WidgetType3 } from "@codemirror/view";
1537
+ import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
1435
1538
  var image = (options = {}) => {
1436
1539
  return StateField3.define({
1437
1540
  create: (state) => {
1438
- return Decoration5.set(buildDecorations(0, state.doc.length, state));
1541
+ return Decoration5.set(buildDecorations2(0, state.doc.length, state));
1439
1542
  },
1440
1543
  update: (value, tr) => {
1441
1544
  if (!tr.docChanged && !tr.selection) {
@@ -1455,16 +1558,16 @@ var image = (options = {}) => {
1455
1558
  filterFrom: from,
1456
1559
  filterTo: to,
1457
1560
  filter: () => false,
1458
- add: buildDecorations(from, to, tr.state)
1561
+ add: buildDecorations2(from, to, tr.state)
1459
1562
  });
1460
1563
  },
1461
- provide: (field) => EditorView7.decorations.from(field)
1564
+ provide: (field) => EditorView8.decorations.from(field)
1462
1565
  });
1463
1566
  };
1464
- var buildDecorations = (from, to, state) => {
1567
+ var buildDecorations2 = (from, to, state) => {
1465
1568
  const decorations = [];
1466
1569
  const cursor = state.selection.main.head;
1467
- syntaxTree(state).iterate({
1570
+ syntaxTree2(state).iterate({
1468
1571
  enter: (node) => {
1469
1572
  if (node.name === "Image") {
1470
1573
  const urlNode = node.node.getChild("URL");
@@ -1501,19 +1604,19 @@ var ImageWidget = class extends WidgetType3 {
1501
1604
  };
1502
1605
 
1503
1606
  // packages/ui/react-ui-editor/src/extensions/link.ts
1504
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1505
- import { RangeSetBuilder } from "@codemirror/state";
1506
- import { Decoration as Decoration6, WidgetType as WidgetType4, hoverTooltip as hoverTooltip2, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
1607
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1608
+ import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1609
+ import { hoverTooltip as hoverTooltip2, Decoration as Decoration6, ViewPlugin as ViewPlugin5, WidgetType as WidgetType4 } from "@codemirror/view";
1507
1610
  import { tooltipContent } from "@dxos/react-ui-theme";
1508
1611
  var link = (options = {}) => {
1509
1612
  const extensions = [
1510
1613
  ViewPlugin5.fromClass(class {
1511
1614
  constructor(view) {
1512
- this.decorations = buildDecorations2(view, options);
1615
+ this.decorations = buildDecorations3(view, options);
1513
1616
  }
1514
1617
  update(update2) {
1515
1618
  if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
1516
- this.decorations = buildDecorations2(update2.view, options);
1619
+ this.decorations = buildDecorations3(update2.view, options);
1517
1620
  }
1518
1621
  }
1519
1622
  }, {
@@ -1526,7 +1629,7 @@ var link = (options = {}) => {
1526
1629
  // https://codemirror.net/docs/ref/#view.hoverTooltip
1527
1630
  // https://github.com/codemirror/view/blob/main/src/tooltip.ts
1528
1631
  hoverTooltip2((view, pos, side) => {
1529
- const syntax = syntaxTree2(view.state).resolveInner(pos, side);
1632
+ const syntax = syntaxTree3(view.state).resolveInner(pos, side);
1530
1633
  let link2 = null;
1531
1634
  for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
1532
1635
  link2 = node.name === "Link" ? node : null;
@@ -1602,12 +1705,12 @@ var LinkText = class extends WidgetType4 {
1602
1705
  return link2;
1603
1706
  }
1604
1707
  };
1605
- var buildDecorations2 = (view, options) => {
1606
- const builder = new RangeSetBuilder();
1708
+ var buildDecorations3 = (view, options) => {
1709
+ const builder = new RangeSetBuilder2();
1607
1710
  const { state } = view;
1608
1711
  const cursor = state.selection.main.head;
1609
1712
  for (const { from, to } of view.visibleRanges) {
1610
- syntaxTree2(state).iterate({
1713
+ syntaxTree3(state).iterate({
1611
1714
  enter: (node) => {
1612
1715
  if (node.name === "Link") {
1613
1716
  const marks2 = node.node.getChildren("LinkMark");
@@ -1638,14 +1741,14 @@ var buildDecorations2 = (view, options) => {
1638
1741
  };
1639
1742
 
1640
1743
  // packages/ui/react-ui-editor/src/extensions/listener.ts
1641
- import { EditorView as EditorView8 } from "@codemirror/view";
1744
+ import { EditorView as EditorView9 } from "@codemirror/view";
1642
1745
  var listener = ({ onFocus, onChange }) => {
1643
1746
  const extensions = [];
1644
- onFocus && extensions.push(EditorView8.focusChangeEffect.of((_, focused) => {
1747
+ onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
1645
1748
  onFocus(focused);
1646
1749
  return null;
1647
1750
  }));
1648
- onChange && extensions.push(EditorView8.updateListener.of((update2) => {
1751
+ onChange && extensions.push(EditorView9.updateListener.of((update2) => {
1649
1752
  onChange(update2.state.doc.toString());
1650
1753
  }));
1651
1754
  return extensions;
@@ -1653,14 +1756,14 @@ var listener = ({ onFocus, onChange }) => {
1653
1756
 
1654
1757
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1655
1758
  import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1656
- import { history, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1759
+ import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1657
1760
  import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1658
1761
  import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1659
1762
  import { languages } from "@codemirror/language-data";
1660
1763
  import { searchKeymap } from "@codemirror/search";
1661
1764
  import { EditorState } from "@codemirror/state";
1662
1765
  import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1663
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView9, highlightActiveLine, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1766
+ import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1664
1767
 
1665
1768
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1666
1769
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -1855,17 +1958,17 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1855
1958
  return [
1856
1959
  EditorState.allowMultipleSelections.of(true),
1857
1960
  EditorState.tabSize.of(2),
1858
- EditorView9.lineWrapping,
1859
- customKeymap(),
1961
+ EditorView10.lineWrapping,
1962
+ // https://github.com/codemirror/basic-setup
1860
1963
  bracketMatching2(),
1861
1964
  closeBrackets2(),
1862
1965
  crosshairCursor(),
1863
1966
  dropCursor(),
1864
1967
  drawSelection2(),
1865
- highlightActiveLine(),
1866
- history(),
1968
+ highlightActiveLine2(),
1969
+ history2(),
1867
1970
  indentOnInput(),
1868
- _placeholder && placeholder2(_placeholder),
1971
+ _placeholder ? placeholder2(_placeholder) : [],
1869
1972
  // Main extension.
1870
1973
  // https://github.com/codemirror/lang-markdown
1871
1974
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -1887,34 +1990,40 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1887
1990
  // https://github.com/codemirror/theme-one-dark
1888
1991
  themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
1889
1992
  // Custom styles.
1890
- syntaxHighlighting2(markdownHighlightStyle(readonly))
1891
- ].filter(Boolean);
1892
- };
1893
- var customKeymap = () => keymap4.of([
1894
- // https://codemirror.net/docs/ref/#commands.indentWithTab
1895
- indentWithTab,
1896
- // https://codemirror.net/docs/ref/#commands.standardKeymap
1897
- ...standardKeymap,
1898
- // https://codemirror.net/docs/ref/#commands.historyKeymap
1899
- ...historyKeymap,
1900
- // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
1901
- ...closeBracketsKeymap,
1902
- // https://codemirror.net/docs/ref/#search.searchKeymap
1903
- ...searchKeymap
1904
- ]);
1993
+ syntaxHighlighting2(markdownHighlightStyle(readonly)),
1994
+ keymap4.of([
1995
+ // https://codemirror.net/docs/ref/#commands.indentWithTab
1996
+ indentWithTab,
1997
+ // https://codemirror.net/docs/ref/#autocomplete.closeBracketsKeymap
1998
+ ...closeBracketsKeymap,
1999
+ // https://codemirror.net/docs/ref/#commands.historyKeymap
2000
+ ...historyKeymap,
2001
+ // https://codemirror.net/docs/ref/#search.searchKeymap
2002
+ ...searchKeymap,
2003
+ // https://codemirror.net/docs/ref/#commands.standardKeymap
2004
+ ...standardKeymap
2005
+ ])
2006
+ ];
2007
+ };
1905
2008
 
1906
2009
  // packages/ui/react-ui-editor/src/extensions/mention.ts
1907
2010
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
1908
2011
  var mention = ({ onSearch }) => {
1909
2012
  return autocompletion2({
2013
+ // TODO(burdon): Not working.
2014
+ activateOnTyping: true,
2015
+ // activateOnTypingDelay: 100,
2016
+ // selectOnOpen: true,
1910
2017
  closeOnBlur: false,
2018
+ // defaultKeymap: false,
2019
+ icons: false,
1911
2020
  override: [
1912
2021
  (context) => {
2022
+ console.log(context);
1913
2023
  const match = context.matchBefore(/@(\w+)?/);
1914
2024
  if (!match || match.from === match.to && !context.explicit) {
1915
2025
  return null;
1916
2026
  }
1917
- console.log(match);
1918
2027
  return {
1919
2028
  from: match.from,
1920
2029
  options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
@@ -1926,19 +2035,24 @@ var mention = ({ onSearch }) => {
1926
2035
  });
1927
2036
  };
1928
2037
 
2038
+ // packages/ui/react-ui-editor/src/extensions/outliner.ts
2039
+ var outliner = (options = {}) => {
2040
+ return [];
2041
+ };
2042
+
1929
2043
  // packages/ui/react-ui-editor/src/extensions/table.ts
1930
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1931
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField4 } from "@codemirror/state";
1932
- import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType5 } from "@codemirror/view";
2044
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2045
+ import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
2046
+ import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
1933
2047
  var table = (options = {}) => {
1934
2048
  return StateField4.define({
1935
2049
  create: (state) => update(state, options),
1936
2050
  update: (_, tr) => update(tr.state, options),
1937
- provide: (field) => EditorView10.decorations.from(field)
2051
+ provide: (field) => EditorView11.decorations.from(field)
1938
2052
  });
1939
2053
  };
1940
2054
  var update = (state, options) => {
1941
- const builder = new RangeSetBuilder2();
2055
+ const builder = new RangeSetBuilder3();
1942
2056
  const cursor = state.selection.main.head;
1943
2057
  const tables = [];
1944
2058
  const getTable = () => tables[tables.length - 1];
@@ -1946,7 +2060,7 @@ var update = (state, options) => {
1946
2060
  const table2 = getTable();
1947
2061
  return table2.rows?.[table2.rows.length - 1];
1948
2062
  };
1949
- syntaxTree3(state).iterate({
2063
+ syntaxTree4(state).iterate({
1950
2064
  enter: (node) => {
1951
2065
  switch (node.name) {
1952
2066
  case "Table": {
@@ -2025,85 +2139,98 @@ var TableWidget = class extends WidgetType5 {
2025
2139
  };
2026
2140
 
2027
2141
  // packages/ui/react-ui-editor/src/extensions/tasklist.ts
2028
- import { EditorView as EditorView11, Decoration as Decoration8, WidgetType as WidgetType6, MatchDecorator as MatchDecorator2, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
2029
- var styles5 = EditorView11.baseTheme({
2030
- "& .cm-task-item": {
2031
- paddingLeft: "4px",
2032
- paddingRight: "8px"
2142
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2143
+ import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
2144
+ import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
2145
+ var styles5 = EditorView12.baseTheme({
2146
+ "& .cm-task": {
2147
+ color: getToken("extend.colors.blue.500")
2148
+ },
2149
+ "& .cm-task-checkbox": {
2150
+ marginLeft: "4px",
2151
+ marginRight: "4px"
2033
2152
  }
2034
2153
  });
2035
2154
  var CheckboxWidget = class extends WidgetType6 {
2036
- constructor(_checked, _indent, _onCheck) {
2155
+ constructor(_checked) {
2037
2156
  super();
2038
2157
  this._checked = _checked;
2039
- this._indent = _indent;
2040
- this._onCheck = _onCheck;
2041
2158
  }
2042
2159
  eq(other) {
2043
- return this._checked === other._checked && this._indent === other._indent;
2160
+ return this._checked === other._checked;
2044
2161
  }
2045
2162
  toDOM(view) {
2046
- const wrap = document.createElement("span");
2047
- wrap.className = "cm-task-item";
2048
- wrap.setAttribute("aria-hidden", "true");
2049
- wrap.style.setProperty("margin-left", this._indent * 24 + "px");
2050
- const input = wrap.appendChild(document.createElement("input"));
2163
+ const input = document.createElement("input");
2164
+ input.className = "cm-task-checkbox";
2051
2165
  input.type = "checkbox";
2052
2166
  input.checked = this._checked;
2053
- if (!this._onCheck) {
2167
+ if (view.state.readOnly) {
2054
2168
  input.setAttribute("disabled", "true");
2055
- }
2056
- if (this._onCheck) {
2057
- input.onchange = (event) => {
2058
- this._onCheck?.(event.target.checked);
2059
- return true;
2169
+ } else {
2170
+ input.onmousedown = (event) => {
2171
+ const pos = view.posAtDOM(input);
2172
+ const text = view.state.sliceDoc(pos, pos + 3);
2173
+ if (text === (this._checked ? "[x]" : "[ ]")) {
2174
+ view.dispatch({
2175
+ changes: {
2176
+ from: pos + 1,
2177
+ to: pos + 2,
2178
+ insert: this._checked ? " " : "x"
2179
+ }
2180
+ });
2181
+ event.preventDefault();
2182
+ }
2060
2183
  };
2061
2184
  }
2062
- return wrap;
2185
+ return input;
2063
2186
  }
2064
2187
  ignoreEvent() {
2065
2188
  return false;
2066
2189
  }
2067
2190
  };
2191
+ var checkedDecoration = Decoration8.replace({
2192
+ widget: new CheckboxWidget(true)
2193
+ });
2194
+ var uncheckedDecoration = Decoration8.replace({
2195
+ widget: new CheckboxWidget(false)
2196
+ });
2197
+ var buildDecorations4 = (view) => {
2198
+ const builder = new RangeSetBuilder4();
2199
+ const { state } = view;
2200
+ const cursor = state.selection.main.head;
2201
+ for (const { from, to } of view.visibleRanges) {
2202
+ syntaxTree5(state).iterate({
2203
+ enter: (node) => {
2204
+ if (node.name === "TaskMarker") {
2205
+ if (cursor < node.from || cursor > node.to) {
2206
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2207
+ builder.add(node.from - 2, node.from - 1, Decoration8.mark({
2208
+ class: "cm-task"
2209
+ }));
2210
+ builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
2211
+ }
2212
+ }
2213
+ },
2214
+ from,
2215
+ to
2216
+ });
2217
+ }
2218
+ return builder.finish();
2219
+ };
2068
2220
  var tasklist = (options = {}) => {
2069
- const taskMatcher = new MatchDecorator2({
2070
- regexp: /^(\s*)- \[([ xX])\]\s/g,
2071
- decoration: (match, view, pos) => {
2072
- const indent = Math.floor(match[1].length / 2);
2073
- const checked = match[2] === "x" || match[2] === "X";
2074
- return Decoration8.replace({
2075
- widget: new CheckboxWidget(checked, indent, view.state.readOnly ? void 0 : (checked2) => {
2076
- const idx = pos + match[0].indexOf("[") + 1;
2077
- view.dispatch({
2078
- changes: {
2079
- from: idx,
2080
- to: idx + 1,
2081
- insert: checked2 ? "x" : " "
2082
- },
2083
- // TODO(burdon): Restore cursor position? More useful to move to end of line (can indent).
2084
- selection: {
2085
- anchor: idx + 3
2086
- }
2087
- });
2088
- })
2089
- });
2090
- }
2091
- });
2092
- const tasks = ViewPlugin6.fromClass(class {
2093
- constructor(view) {
2094
- this.tasks = taskMatcher.createDeco(view);
2095
- }
2096
- update(update2) {
2097
- this.tasks = taskMatcher.updateDeco(update2, this.tasks);
2098
- }
2099
- }, {
2100
- decorations: (value) => value.tasks,
2101
- provide: (plugin) => EditorView11.atomicRanges.of((view) => {
2102
- return view.plugin(plugin)?.tasks || Decoration8.none;
2103
- })
2104
- });
2105
2221
  return [
2106
- tasks,
2222
+ ViewPlugin6.fromClass(class {
2223
+ constructor(view) {
2224
+ this.decorations = buildDecorations4(view);
2225
+ }
2226
+ update(update2) {
2227
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2228
+ this.decorations = buildDecorations4(update2.view);
2229
+ }
2230
+ }
2231
+ }, {
2232
+ decorations: (v) => v.decorations
2233
+ }),
2107
2234
  styles5
2108
2235
  ];
2109
2236
  };
@@ -2165,27 +2292,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
2165
2292
  ];
2166
2293
  };
2167
2294
 
2168
- // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2169
- import { yCollab } from "y-codemirror.next";
2170
-
2171
- // packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
2172
- import * as Y from "yjs";
2173
- import { arrayToString, stringToArray } from "@dxos/util";
2174
- var cursorConverter2 = (text) => ({
2175
- toCursor: (index, assoc) => {
2176
- return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
2177
- },
2178
- fromCursor: (cursor) => {
2179
- return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
2180
- }
2181
- });
2182
-
2183
- // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2184
- var yjs = (content, awareness2) => [
2185
- Cursor.converter.of(cursorConverter2(content)),
2186
- yCollab(content, awareness2)
2187
- ];
2188
-
2189
2295
  // packages/ui/react-ui-editor/src/themes/default.ts
2190
2296
  import get3 from "lodash.get";
2191
2297
  var defaultTheme = {
@@ -2315,13 +2421,6 @@ var defaultTheme = {
2315
2421
  textDecoration: "none"
2316
2422
  },
2317
2423
  //
2318
- // widgets
2319
- //
2320
- ".cm-widgetBuffer": {
2321
- display: "none",
2322
- height: 0
2323
- },
2324
- //
2325
2424
  // table
2326
2425
  //
2327
2426
  ".cm-table *": {
@@ -2430,11 +2529,12 @@ var codeTheme = {
2430
2529
  };
2431
2530
 
2432
2531
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
2532
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
2433
2533
  var EditorModes = [
2434
2534
  "default",
2435
2535
  "vim"
2436
2536
  ];
2437
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, readonly, comments: comments2, extensions = [], editorMode, theme, slots = defaultSlots }, forwardedRef) => {
2537
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
2438
2538
  const tabsterDOMAttribute = useFocusableGroup({
2439
2539
  tabBehavior: "limited"
2440
2540
  });
@@ -2444,76 +2544,67 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2444
2544
  useImperativeHandle(forwardedRef, () => view, [
2445
2545
  view
2446
2546
  ]);
2447
- useEffect(() => {
2448
- if (view && focus) {
2449
- view.focus();
2450
- }
2451
- }, [
2452
- view,
2453
- focus
2454
- ]);
2455
- const { awareness: awareness2, peer } = model;
2456
- useEffect(() => {
2457
- if (awareness2 && peer) {
2458
- awareness2.setLocalStateField("user", {
2459
- name: peer.name ?? generateName(peer.id),
2460
- color: getColorForValue({
2461
- value: peer.id,
2462
- type: "color"
2463
- }),
2464
- colorLight: getColorForValue({
2465
- value: peer.id,
2466
- themeMode,
2467
- type: "highlight"
2468
- })
2469
- });
2470
- }
2471
- }, [
2472
- awareness2,
2473
- peer,
2474
- themeMode
2475
- ]);
2476
- useEffect(() => {
2477
- if (view && comments2 !== void 0) {
2478
- view.dispatch({
2479
- effects: setCommentRange.of({
2480
- model,
2481
- comments: comments2
2482
- })
2483
- });
2547
+ useEffect2(() => {
2548
+ if (autoFocus) {
2549
+ view?.focus();
2484
2550
  }
2485
2551
  }, [
2486
2552
  view,
2487
- comments2
2553
+ autoFocus
2488
2554
  ]);
2489
- useEffect(() => {
2555
+ useEffect2(() => {
2490
2556
  if (!model || !rootRef.current) {
2491
2557
  return;
2492
2558
  }
2493
2559
  const state = EditorState2.create({
2494
2560
  doc: model.text(),
2495
- // TODO(burdon): Composer should store and set selection when switching documents.
2496
2561
  selection,
2497
2562
  extensions: [
2498
- readonly && EditorState2.readOnly.of(readonly),
2499
- // TODO(burdon): Factor out VIM mode? (manage via MarkdownPlugin).
2500
- editorMode === "vim" && vim(),
2563
+ // TODO(burdon): Doesn't catch errors in keymap functions.
2564
+ EditorView13.exceptionSink.of((err) => {
2565
+ log2.catch(err, void 0, {
2566
+ F: __dxlog_file5,
2567
+ L: 123,
2568
+ S: void 0,
2569
+ C: (f, a) => f(...a)
2570
+ });
2571
+ }),
2501
2572
  // Theme.
2502
- // TODO(burdon): Make theme configurable.
2503
- EditorView12.baseTheme(defaultTheme),
2504
- EditorView12.theme(theme ?? {}),
2505
- EditorView12.darkTheme.of(themeMode === "dark"),
2573
+ // TODO(burdon): Make configurable.
2574
+ EditorView13.baseTheme(defaultTheme),
2575
+ EditorView13.theme(theme ?? {}),
2576
+ EditorView13.darkTheme.of(themeMode === "dark"),
2577
+ EditorView13.editorAttributes.of({
2578
+ class: slots.editor?.className ?? ""
2579
+ }),
2580
+ EditorView13.contentAttributes.of({
2581
+ class: slots.content?.className ?? ""
2582
+ }),
2583
+ // State.
2584
+ EditorState2.readOnly.of(!!readonly),
2506
2585
  // Storage and replication.
2586
+ // NOTE: This must come before user extensions.
2507
2587
  model.extension,
2588
+ // TODO(burdon): Factor out (requires special handling for Escape/focus).
2589
+ editorMode === "vim" && vim(),
2508
2590
  // Custom.
2509
2591
  ...extensions
2510
2592
  ].filter(Boolean)
2511
2593
  });
2512
- view?.destroy();
2513
- const newView = new EditorView12({
2594
+ const newView = new EditorView13({
2595
+ state,
2514
2596
  parent: rootRef.current,
2515
- state
2597
+ scrollTo,
2598
+ // NOTE: Uncomment to debug/monitor all transactions.
2599
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
2600
+ dispatchTransactions: (trs, view2) => {
2601
+ if (debug) {
2602
+ logChanges(trs);
2603
+ }
2604
+ view2.update(trs);
2605
+ }
2516
2606
  });
2607
+ view?.destroy();
2517
2608
  setView(newView);
2518
2609
  return () => {
2519
2610
  newView?.destroy();
@@ -2529,8 +2620,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2529
2620
  const handleKeyUp = useCallback((event) => {
2530
2621
  const { key, altKey, shiftKey, metaKey, ctrlKey } = event;
2531
2622
  switch (key) {
2623
+ case "Enter": {
2624
+ view?.focus();
2625
+ break;
2626
+ }
2532
2627
  case "Escape": {
2533
- editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey) && rootRef.current?.focus();
2628
+ if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
2629
+ rootRef.current?.focus();
2630
+ }
2534
2631
  break;
2535
2632
  }
2536
2633
  }
@@ -2541,14 +2638,14 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, focus, selection, read
2541
2638
  return /* @__PURE__ */ React.createElement("div", {
2542
2639
  key: model.id,
2543
2640
  role: "none",
2544
- ref: rootRef,
2545
2641
  tabIndex: 0,
2546
2642
  onKeyUp: handleKeyUp,
2547
2643
  ...slots.root,
2548
- ...editorMode !== "vim" && tabsterDOMAttribute
2644
+ ...editorMode !== "vim" && tabsterDOMAttribute,
2645
+ ref: rootRef
2549
2646
  });
2550
2647
  });
2551
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = textTheme, slots, ...props }, forwardedRef) => {
2648
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
2552
2649
  const { themeMode } = useThemeContext();
2553
2650
  const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2554
2651
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
@@ -2556,9 +2653,9 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
2556
2653
  readonly,
2557
2654
  extensions: [
2558
2655
  basicBundle({
2559
- readonly,
2560
2656
  themeMode,
2561
- placeholder: placeholder3
2657
+ placeholder: placeholder3,
2658
+ lineWrapping
2562
2659
  }),
2563
2660
  ...extensions
2564
2661
  ],
@@ -2567,7 +2664,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
2567
2664
  ...props
2568
2665
  });
2569
2666
  });
2570
- var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, extensions = [], theme = markdownTheme, slots, ...props }, forwardedRef) => {
2667
+ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
2571
2668
  const { themeMode } = useThemeContext();
2572
2669
  const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2573
2670
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
@@ -2575,8 +2672,8 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
2575
2672
  readonly,
2576
2673
  extensions: [
2577
2674
  markdownBundle({
2578
- readonly,
2579
2675
  themeMode,
2676
+ readonly,
2580
2677
  placeholder: placeholder3
2581
2678
  }),
2582
2679
  ...extensions
@@ -2588,7 +2685,11 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
2588
2685
  });
2589
2686
  var defaultSlots = {
2590
2687
  root: {
2591
- className: mx3("p-2 overflow-y-auto", inputSurface)
2688
+ // TODO(burdon): Add focusRing by default/as property?
2689
+ className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
2690
+ },
2691
+ editor: {
2692
+ className: "h-full p-2"
2592
2693
  }
2593
2694
  };
2594
2695
  var defaultTextSlots = {
@@ -2598,22 +2699,17 @@ var defaultMarkdownSlots = {
2598
2699
  ...defaultSlots
2599
2700
  };
2600
2701
 
2601
- // packages/ui/react-ui-editor/src/hooks/automerge.ts
2602
- import get4 from "lodash.get";
2603
- import { getRawDoc } from "@dxos/echo-schema";
2604
- import { isNotNullOrUndefined } from "@dxos/util";
2605
-
2606
2702
  // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
2607
2703
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
2608
2704
  import { Context as Context2 } from "@dxos/context";
2609
- import { invariant as invariant3 } from "@dxos/invariant";
2705
+ import { invariant as invariant4 } from "@dxos/invariant";
2610
2706
  import { log as log3 } from "@dxos/log";
2611
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
2707
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
2612
2708
  var DEBOUNCE_INTERVAL = 100;
2613
2709
  var SpaceAwarenessProvider = class {
2614
2710
  constructor(params) {
2615
- this.remoteStateChange = new Event2();
2616
2711
  this._remoteStates = /* @__PURE__ */ new Map();
2712
+ this.remoteStateChange = new Event2();
2617
2713
  this._space = params.space;
2618
2714
  this._channel = params.channel;
2619
2715
  this._peerId = params.peerId;
@@ -2630,7 +2726,7 @@ var SpaceAwarenessProvider = class {
2630
2726
  await sleep(DEBOUNCE_INTERVAL);
2631
2727
  }
2632
2728
  });
2633
- const unsubscribe = this._space.listen(this._channel, (message) => {
2729
+ this._ctx.onDispose(this._space.listen(this._channel, (message) => {
2634
2730
  switch (message.payload.kind) {
2635
2731
  case "query": {
2636
2732
  this._handleQueryMessage();
@@ -2641,16 +2737,15 @@ var SpaceAwarenessProvider = class {
2641
2737
  break;
2642
2738
  }
2643
2739
  }
2644
- });
2645
- this._ctx.onDispose(unsubscribe);
2740
+ }));
2646
2741
  void this._space.postMessage(this._channel, {
2647
2742
  kind: "query"
2648
2743
  }).catch((err) => {
2649
2744
  log3.debug("failed to query awareness", {
2650
2745
  err
2651
2746
  }, {
2652
- F: __dxlog_file4,
2653
- L: 85,
2747
+ F: __dxlog_file6,
2748
+ L: 89,
2654
2749
  S: this,
2655
2750
  C: (f, a) => f(...a)
2656
2751
  });
@@ -2661,10 +2756,13 @@ var SpaceAwarenessProvider = class {
2661
2756
  this._ctx = void 0;
2662
2757
  this._postTask = void 0;
2663
2758
  }
2759
+ getRemoteStates() {
2760
+ return Array.from(this._remoteStates.values());
2761
+ }
2664
2762
  update(position) {
2665
- invariant3(this._postTask, void 0, {
2666
- F: __dxlog_file4,
2667
- L: 96,
2763
+ invariant4(this._postTask, void 0, {
2764
+ F: __dxlog_file6,
2765
+ L: 104,
2668
2766
  S: this,
2669
2767
  A: [
2670
2768
  "this._postTask",
@@ -2678,13 +2776,10 @@ var SpaceAwarenessProvider = class {
2678
2776
  };
2679
2777
  this._postTask.schedule();
2680
2778
  }
2681
- getRemoteStates() {
2682
- return Array.from(this._remoteStates.values());
2683
- }
2684
2779
  _handleQueryMessage() {
2685
- invariant3(this._postTask, void 0, {
2686
- F: __dxlog_file4,
2687
- L: 111,
2780
+ invariant4(this._postTask, void 0, {
2781
+ F: __dxlog_file6,
2782
+ L: 115,
2688
2783
  S: this,
2689
2784
  A: [
2690
2785
  "this._postTask",
@@ -2694,9 +2789,9 @@ var SpaceAwarenessProvider = class {
2694
2789
  this._postTask.schedule();
2695
2790
  }
2696
2791
  _handlePostMessage(message) {
2697
- invariant3(message.kind === "post", void 0, {
2698
- F: __dxlog_file4,
2699
- L: 116,
2792
+ invariant4(message.kind === "post", void 0, {
2793
+ F: __dxlog_file6,
2794
+ L: 120,
2700
2795
  S: this,
2701
2796
  A: [
2702
2797
  "message.kind === 'post'",
@@ -2708,171 +2803,54 @@ var SpaceAwarenessProvider = class {
2708
2803
  }
2709
2804
  };
2710
2805
 
2711
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2806
+ // packages/ui/react-ui-editor/src/hooks/defs.ts
2712
2807
  import { StateField as StateField5 } from "@codemirror/state";
2713
- import { useEffect as useEffect2, useState as useState2 } from "react";
2714
- import { isAutomergeObject } from "@dxos/react-client/echo";
2715
-
2716
- // packages/ui/react-ui-editor/src/hooks/yjs.ts
2717
- import * as decoding from "lib0/decoding";
2718
- import * as encoding from "lib0/encoding";
2719
- import { Observable } from "lib0/observable";
2720
- import * as YP from "y-protocols/awareness";
2721
- import { invariant as invariant4 } from "@dxos/invariant";
2722
- import { log as log4 } from "@dxos/log";
2723
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
2724
- var createYjsModel = ({ identity, space, text }) => {
2725
- invariant4(text?.doc && text?.content, void 0, {
2726
- F: __dxlog_file5,
2727
- L: 21,
2728
- S: void 0,
2729
- A: [
2730
- "text?.doc && text?.content",
2731
- ""
2732
- ]
2733
- });
2734
- const provider = space ? new YAwarenessProvider({
2735
- space,
2736
- doc: text.doc,
2737
- channel: `yjs.awareness.${text.id}`
2738
- }) : void 0;
2739
- const model = {
2740
- id: text.doc.guid,
2741
- content: text.content,
2742
- text: () => text.content.toString(),
2743
- extension: [
2744
- modelState.init(() => model),
2745
- yjs(text.content, provider?.awareness)
2746
- ],
2747
- awareness: provider?.awareness,
2748
- peer: identity ? {
2749
- id: identity.identityKey.toHex(),
2750
- name: identity.profile?.displayName
2751
- } : void 0
2752
- };
2753
- return model;
2754
- };
2755
- var messageAwareness = 1;
2756
- var messageQueryAwareness = 3;
2757
- var YAwarenessProvider = class extends Observable {
2758
- constructor({ space, doc, channel, awareness: awareness2 }) {
2759
- super();
2760
- this._space = space;
2761
- this._awareness = awareness2 ?? new YP.Awareness(doc);
2762
- this._channel = channel;
2763
- this._clientId = doc.clientID;
2764
- this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
2765
- this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
2766
- if (typeof window !== "undefined") {
2767
- window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
2768
- } else if (typeof process !== "undefined") {
2769
- process.on("exit", this._handleBeforeUnload.bind(this));
2770
- }
2771
- const encoderAwarenessQuery = encoding.createEncoder();
2772
- encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
2773
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
2774
- const encoderAwarenessState = encoding.createEncoder();
2775
- encoding.writeVarUint(encoderAwarenessState, messageAwareness);
2776
- encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
2777
- this._clientId
2778
- ]));
2779
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
2780
- }
2781
- get awareness() {
2782
- return this._awareness;
2783
- }
2784
- _handleAwarenessUpdate({ added, updated, removed }, origin) {
2785
- log4("awareness update", {
2786
- added,
2787
- updated,
2788
- removed,
2789
- origin
2790
- }, {
2791
- F: __dxlog_file5,
2792
- L: 100,
2793
- S: this,
2794
- C: (f, a) => f(...a)
2795
- });
2796
- const changedClients = added.concat(updated).concat(removed);
2797
- const encoderAwareness = encoding.createEncoder();
2798
- encoding.writeVarUint(encoderAwareness, messageAwareness);
2799
- encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
2800
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
2801
- }
2802
- _handleSpaceMessage({ payload }) {
2803
- log4("space message", payload, {
2804
- F: __dxlog_file5,
2805
- L: 109,
2806
- S: this,
2807
- C: (f, a) => f(...a)
2808
- });
2809
- const data = new Uint8Array(Array.from(Object.values(payload)));
2810
- const encoder = this._readMessage(data);
2811
- if (encoder) {
2812
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
2813
- }
2814
- }
2815
- _readMessage(message) {
2816
- const decoder = decoding.createDecoder(message);
2817
- const encoder = encoding.createEncoder();
2818
- const messageType = decoding.readVarUint(decoder);
2819
- let sendReply = false;
2820
- switch (messageType) {
2821
- case messageAwareness: {
2822
- YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
2823
- break;
2824
- }
2825
- case messageQueryAwareness: {
2826
- encoding.writeVarUint(encoder, messageAwareness);
2827
- encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
2828
- sendReply = true;
2829
- break;
2830
- }
2831
- default: {
2832
- console.error("Invalid message:", messageType);
2833
- return encoder;
2834
- }
2835
- }
2836
- if (!sendReply) {
2837
- return null;
2838
- }
2839
- return encoder;
2840
- }
2841
- _handleBeforeUnload() {
2842
- YP.removeAwarenessStates(this._awareness, [
2843
- this._clientId
2844
- ], "window unload");
2845
- }
2846
- };
2847
-
2848
- // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2849
2808
  var modelState = StateField5.define({
2850
2809
  create: () => void 0,
2851
2810
  update: (model) => model
2852
2811
  });
2812
+
2813
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
2814
+ import { useState as useState2 } from "react";
2815
+ var useTextEditor = () => {
2816
+ const [view, setView] = useState2(null);
2817
+ return [
2818
+ (ref) => {
2819
+ setView(ref);
2820
+ },
2821
+ view
2822
+ ];
2823
+ };
2824
+
2825
+ // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2826
+ import get4 from "lodash.get";
2827
+ import { useEffect as useEffect3, useState as useState3 } from "react";
2828
+ import { generateName } from "@dxos/display-name";
2829
+ import { getRawDoc } from "@dxos/echo-schema";
2830
+ import { invariant as invariant5 } from "@dxos/invariant";
2831
+ import { isAutomergeObject } from "@dxos/react-client/echo";
2832
+ import { isNotNullOrUndefined } from "@dxos/util";
2833
+ var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
2853
2834
  var useTextModel = (props) => {
2854
2835
  const { identity, space, text } = props;
2855
- const [model, setModel] = useState2();
2856
- useEffect2(() => setModel(createModel(props)), [
2836
+ const [model, setModel] = useState3();
2837
+ useEffect3(() => setModel(createModel(props)), [
2857
2838
  identity,
2858
2839
  space,
2859
2840
  text
2860
2841
  ]);
2861
2842
  return model;
2862
2843
  };
2863
- var createModel = (props) => {
2864
- const { text } = props;
2865
- if (isAutomergeObject(text)) {
2866
- return createAutomergeModel(props);
2867
- } else if (text?.doc) {
2868
- return createYjsModel(props);
2869
- } else {
2870
- return void 0;
2871
- }
2872
- };
2873
-
2874
- // packages/ui/react-ui-editor/src/hooks/automerge.ts
2875
- var createAutomergeModel = ({ space, identity, text }) => {
2844
+ var createModel = ({ space, identity, text }) => {
2845
+ invariant5(isAutomergeObject(text), void 0, {
2846
+ F: __dxlog_file7,
2847
+ L: 35,
2848
+ S: void 0,
2849
+ A: [
2850
+ "isAutomergeObject(text)",
2851
+ ""
2852
+ ]
2853
+ });
2876
2854
  const obj = text;
2877
2855
  const doc = getRawDoc(obj, [
2878
2856
  obj.field
@@ -2881,7 +2859,7 @@ var createAutomergeModel = ({ space, identity, text }) => {
2881
2859
  space,
2882
2860
  channel: `automerge.awareness.${obj.id}`,
2883
2861
  info: {
2884
- displayName: identity?.profile?.displayName ?? "",
2862
+ displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
2885
2863
  color: cursorColor.color,
2886
2864
  lightColor: cursorColor.light
2887
2865
  },
@@ -2891,7 +2869,6 @@ var createAutomergeModel = ({ space, identity, text }) => {
2891
2869
  id: obj.id,
2892
2870
  content: doc,
2893
2871
  text: () => get4(doc.handle.docSync(), doc.path),
2894
- // TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
2895
2872
  extension: [
2896
2873
  modelState.init(() => model),
2897
2874
  automerge3({
@@ -2919,7 +2896,6 @@ export {
2919
2896
  SpaceAwarenessProvider,
2920
2897
  TextEditor,
2921
2898
  TextKind,
2922
- YAwarenessProvider,
2923
2899
  YText,
2924
2900
  YXmlFragment,
2925
2901
  autocomplete,
@@ -2931,9 +2907,6 @@ export {
2931
2907
  code2 as code,
2932
2908
  codeTheme,
2933
2909
  comments,
2934
- createAutomergeModel,
2935
- createYjsModel,
2936
- cursorConverter,
2937
2910
  defaultMarkdownSlots,
2938
2911
  defaultOptions,
2939
2912
  defaultSlots,
@@ -2944,6 +2917,7 @@ export {
2944
2917
  image,
2945
2918
  link,
2946
2919
  listener,
2920
+ logChanges,
2947
2921
  markdownBundle,
2948
2922
  markdownHighlightStyle,
2949
2923
  markdownTags,
@@ -2951,7 +2925,8 @@ export {
2951
2925
  markdownTheme,
2952
2926
  mention,
2953
2927
  modelState,
2954
- setCommentRange,
2928
+ outliner,
2929
+ setComments,
2955
2930
  setFocus,
2956
2931
  setSelection,
2957
2932
  table,
@@ -2959,7 +2934,8 @@ export {
2959
2934
  tasklist,
2960
2935
  textTheme,
2961
2936
  typewriter,
2962
- useTextModel,
2963
- yjs
2937
+ useComments,
2938
+ useTextEditor,
2939
+ useTextModel
2964
2940
  };
2965
2941
  //# sourceMappingURL=index.mjs.map