@dxos/react-ui-editor 0.3.11-main.c244d7e → 0.3.11-main.c865ffb

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 (168) hide show
  1. package/dist/lib/browser/index.mjs +1385 -929
  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 +7 -11
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts +3 -2
  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/automerge.stories.d.ts.map +1 -1
  10. package/dist/types/src/components/TextEditor/{yjs.stories.d.ts → hooks.stories.d.ts} +13 -2
  11. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
  12. package/dist/types/src/components/Toolbar/Toolbar.d.ts +25 -0
  13. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  14. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +23 -0
  15. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
  16. package/dist/types/src/components/Toolbar/index.d.ts +2 -0
  17. package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
  18. package/dist/types/src/components/index.d.ts +1 -0
  19. package/dist/types/src/components/index.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  21. package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
  22. package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
  23. package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
  24. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
  25. package/dist/types/src/extensions/automerge/defs.d.ts +5 -5
  26. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  27. package/dist/types/src/extensions/automerge/semaphore.d.ts +2 -1
  28. package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
  29. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  30. package/dist/types/src/extensions/awareness.d.ts +2 -4
  31. package/dist/types/src/extensions/awareness.d.ts.map +1 -1
  32. package/dist/types/src/extensions/basic.d.ts +2 -2
  33. package/dist/types/src/extensions/basic.d.ts.map +1 -1
  34. package/dist/types/src/extensions/comments.d.ts +9 -5
  35. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  36. package/dist/types/src/extensions/index.d.ts +0 -7
  37. package/dist/types/src/extensions/index.d.ts.map +1 -1
  38. package/dist/types/src/extensions/markdown/bundle.d.ts +2 -2
  39. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  40. package/dist/types/src/extensions/markdown/code.d.ts.map +1 -0
  41. package/dist/types/src/extensions/markdown/formatting.d.ts +13 -0
  42. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
  43. package/dist/types/src/extensions/markdown/heading.d.ts +6 -0
  44. package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -0
  45. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  46. package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -0
  47. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -0
  48. package/dist/types/src/extensions/markdown/index.d.ts +8 -0
  49. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  50. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -0
  51. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -0
  52. package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -0
  53. package/dist/types/src/extensions/mention.d.ts.map +1 -1
  54. package/dist/types/src/hooks/awareness-provider.d.ts +7 -4
  55. package/dist/types/src/hooks/awareness-provider.d.ts.map +1 -1
  56. package/dist/types/src/hooks/defs.d.ts +1 -4
  57. package/dist/types/src/hooks/defs.d.ts.map +1 -1
  58. package/dist/types/src/hooks/index.d.ts +3 -2
  59. package/dist/types/src/hooks/index.d.ts.map +1 -1
  60. package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
  61. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
  62. package/dist/types/src/hooks/useEditorView.d.ts +17 -0
  63. package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
  64. package/dist/types/src/hooks/useTextEditor.d.ts +39 -0
  65. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -0
  66. package/dist/types/src/hooks/useTextModel.d.ts +12 -0
  67. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  68. package/dist/types/src/index.d.ts +1 -1
  69. package/dist/types/src/index.d.ts.map +1 -1
  70. package/dist/types/src/styles/markdown.d.ts +2 -2
  71. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  72. package/dist/types/src/themes/default.d.ts.map +1 -1
  73. package/package.json +46 -36
  74. package/src/components/TextEditor/MarkdownEditor.stories.tsx +41 -46
  75. package/src/components/TextEditor/TextEditor.tsx +46 -27
  76. package/src/components/TextEditor/automerge.stories.tsx +1 -2
  77. package/src/components/TextEditor/hooks.stories.tsx +106 -0
  78. package/src/components/Toolbar/Toolbar.stories.tsx +90 -0
  79. package/src/components/Toolbar/Toolbar.tsx +166 -0
  80. package/src/components/Toolbar/index.ts +5 -0
  81. package/src/components/index.ts +1 -0
  82. package/src/extensions/automerge/automerge.spec.tsx +76 -0
  83. package/src/extensions/automerge/automerge.test.ts +13 -0
  84. package/src/extensions/automerge/automerge.ts +44 -11
  85. package/src/extensions/automerge/cursor.ts +3 -3
  86. package/src/extensions/automerge/defs.ts +9 -9
  87. package/src/extensions/automerge/semaphore.ts +18 -24
  88. package/src/extensions/automerge/update-automerge.ts +12 -6
  89. package/src/extensions/automerge/update-codemirror.ts +5 -5
  90. package/src/extensions/awareness.ts +21 -35
  91. package/src/extensions/basic.ts +17 -15
  92. package/src/extensions/blast.ts +4 -1
  93. package/src/extensions/comments.ts +126 -78
  94. package/src/extensions/index.ts +0 -7
  95. package/src/extensions/markdown/bundle.ts +9 -8
  96. package/src/extensions/markdown/code.ts +150 -0
  97. package/src/extensions/markdown/formatting.ts +188 -0
  98. package/src/extensions/markdown/heading.ts +59 -0
  99. package/src/extensions/markdown/highlight.ts +9 -15
  100. package/src/extensions/{hr.ts → markdown/hr.ts} +3 -4
  101. package/src/extensions/markdown/index.ts +8 -0
  102. package/src/extensions/{link.ts → markdown/link.ts} +13 -4
  103. package/src/extensions/{tasklist.ts → markdown/tasklist.ts} +2 -3
  104. package/src/extensions/mention.ts +6 -4
  105. package/src/hooks/awareness-provider.ts +24 -20
  106. package/src/hooks/defs.ts +1 -6
  107. package/src/hooks/index.ts +3 -2
  108. package/src/hooks/useActionHandler.ts +62 -0
  109. package/src/hooks/useEditorView.ts +29 -0
  110. package/src/hooks/useTextEditor.ts +153 -0
  111. package/src/hooks/useTextModel.ts +65 -12
  112. package/src/index.ts +1 -1
  113. package/src/styles/markdown.ts +9 -10
  114. package/src/themes/default.ts +9 -6
  115. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts +0 -12
  116. package/dist/types/src/components/TextEditor/codemirror.stories.d.ts.map +0 -1
  117. package/dist/types/src/components/TextEditor/comments.stories.d.ts +0 -26
  118. package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +0 -1
  119. package/dist/types/src/components/TextEditor/yjs.stories.d.ts.map +0 -1
  120. package/dist/types/src/extensions/code.d.ts.map +0 -1
  121. package/dist/types/src/extensions/hr.d.ts.map +0 -1
  122. package/dist/types/src/extensions/image.d.ts.map +0 -1
  123. package/dist/types/src/extensions/link.d.ts.map +0 -1
  124. package/dist/types/src/extensions/table.d.ts.map +0 -1
  125. package/dist/types/src/extensions/tasklist.d.ts.map +0 -1
  126. package/dist/types/src/extensions/yjs/cursor.d.ts +0 -4
  127. package/dist/types/src/extensions/yjs/cursor.d.ts.map +0 -1
  128. package/dist/types/src/extensions/yjs/index.d.ts +0 -2
  129. package/dist/types/src/extensions/yjs/index.d.ts.map +0 -1
  130. package/dist/types/src/extensions/yjs/yjs.d.ts +0 -4
  131. package/dist/types/src/extensions/yjs/yjs.d.ts.map +0 -1
  132. package/dist/types/src/extensions/yjs/yjs.test.d.ts +0 -2
  133. package/dist/types/src/extensions/yjs/yjs.test.d.ts.map +0 -1
  134. package/dist/types/src/hooks/automerge.d.ts +0 -4
  135. package/dist/types/src/hooks/automerge.d.ts.map +0 -1
  136. package/dist/types/src/hooks/yjs.d.ts +0 -28
  137. package/dist/types/src/hooks/yjs.d.ts.map +0 -1
  138. package/dist/types/src/testing/index.d.ts +0 -3
  139. package/dist/types/src/testing/index.d.ts.map +0 -1
  140. package/dist/types/src/testing/proto/gen/schema.d.ts +0 -15
  141. package/dist/types/src/testing/proto/gen/schema.d.ts.map +0 -1
  142. package/dist/types/src/testing/proto/index.d.ts +0 -2
  143. package/dist/types/src/testing/proto/index.d.ts.map +0 -1
  144. package/dist/types/src/testing/replicator.d.ts +0 -45
  145. package/dist/types/src/testing/replicator.d.ts.map +0 -1
  146. package/src/components/TextEditor/codemirror.stories.ts +0 -115
  147. package/src/components/TextEditor/comments.stories.tsx +0 -357
  148. package/src/components/TextEditor/yjs.stories.tsx +0 -56
  149. package/src/extensions/code.ts +0 -104
  150. package/src/extensions/yjs/cursor.ts +0 -22
  151. package/src/extensions/yjs/index.ts +0 -5
  152. package/src/extensions/yjs/yjs.test.ts +0 -35
  153. package/src/extensions/yjs/yjs.ts +0 -16
  154. package/src/hooks/automerge.ts +0 -53
  155. package/src/hooks/yjs.ts +0 -157
  156. package/src/testing/index.ts +0 -6
  157. package/src/testing/proto/gen/schema.ts +0 -49
  158. package/src/testing/proto/index.ts +0 -5
  159. package/src/testing/proto/schema.proto +0 -15
  160. package/src/testing/replicator.ts +0 -184
  161. /package/dist/types/src/extensions/{code.d.ts → markdown/code.d.ts} +0 -0
  162. /package/dist/types/src/extensions/{hr.d.ts → markdown/hr.d.ts} +0 -0
  163. /package/dist/types/src/extensions/{image.d.ts → markdown/image.d.ts} +0 -0
  164. /package/dist/types/src/extensions/{link.d.ts → markdown/link.d.ts} +0 -0
  165. /package/dist/types/src/extensions/{table.d.ts → markdown/table.d.ts} +0 -0
  166. /package/dist/types/src/extensions/{tasklist.d.ts → markdown/tasklist.d.ts} +0 -0
  167. /package/src/extensions/{image.ts → markdown/image.ts} +0 -0
  168. /package/src/extensions/{table.ts → markdown/table.ts} +0 -0
@@ -1,6 +1,7 @@
1
1
  // packages/ui/react-ui-editor/src/index.ts
2
2
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
3
3
  import { Doc, YText, YXmlFragment } from "@dxos/text-model";
4
+ import { keymap as keymap7 } from "@codemirror/view";
4
5
 
5
6
  // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
6
7
  import { tags as tags2 } from "@lezer/highlight";
@@ -8,13 +9,13 @@ import { tags as tags2 } from "@lezer/highlight";
8
9
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
9
10
  import { EditorState as EditorState2 } from "@codemirror/state";
10
11
  import { EditorView as EditorView13 } from "@codemirror/view";
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 as useEffect3, useImperativeHandle, useRef, useState } from "react";
14
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
15
15
  import { log as log2 } from "@dxos/log";
16
- import { useThemeContext as useThemeContext2 } from "@dxos/react-ui";
17
- import { inputSurface, mx as mx3 } from "@dxos/react-ui-theme";
16
+ import { useThemeContext } from "@dxos/react-ui";
17
+ import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
18
+ import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
18
19
 
19
20
  // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
20
21
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
@@ -53,13 +54,14 @@ var autocomplete = ({ onSearch }) => {
53
54
  };
54
55
 
55
56
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
57
+ import { invertedEffects } from "@codemirror/commands";
56
58
  import { StateField } from "@codemirror/state";
57
- import { EditorView } from "@codemirror/view";
58
- import { next as A } from "@dxos/automerge/automerge";
59
+ import { EditorView, ViewPlugin } from "@codemirror/view";
60
+ import { next as A4 } from "@dxos/automerge/automerge";
59
61
 
60
62
  // packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
61
63
  import get from "lodash.get";
62
- import { next as automerge } from "@dxos/automerge/automerge";
64
+ import { next as A } from "@dxos/automerge/automerge";
63
65
  var cursorConverter = (handle, path) => ({
64
66
  // TODO(burdon): Handle assoc to associate with a previous character.
65
67
  toCursor: (pos) => {
@@ -71,7 +73,7 @@ var cursorConverter = (handle, path) => ({
71
73
  if (typeof value === "string" && value.length <= pos) {
72
74
  return "end";
73
75
  }
74
- return automerge.getCursor(doc, path.slice(), pos);
76
+ return A.getCursor(doc, path.slice(), pos);
75
77
  },
76
78
  fromCursor: (cursor) => {
77
79
  if (cursor === "") {
@@ -89,26 +91,28 @@ var cursorConverter = (handle, path) => ({
89
91
  return 0;
90
92
  }
91
93
  }
92
- return automerge.getCursorPosition(doc, path.slice(), cursor);
94
+ return A.getCursorPosition(doc, path.slice(), cursor);
93
95
  }
94
96
  });
95
97
 
96
98
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
97
99
  import { Annotation, StateEffect } from "@codemirror/state";
98
- var effectType = StateEffect.define({});
99
- var reconcileAnnotationType = Annotation.define();
100
100
  var getPath = (state, field) => state.field(field).path;
101
101
  var getLastHeads = (state, field) => state.field(field).lastHeads;
102
- var updateHeads = (newHeads) => effectType.of({
102
+ var updateHeadsEffect = StateEffect.define({});
103
+ var updateHeads = (newHeads) => updateHeadsEffect.of({
103
104
  newHeads
104
105
  });
105
- var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
106
+ var reconcileAnnotation = Annotation.define();
107
+ var isReconcile = (tr) => {
108
+ return !!tr.annotation(reconcileAnnotation);
109
+ };
106
110
 
107
111
  // packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
108
- import { next as automerge2 } from "@dxos/automerge/automerge";
112
+ import { next as A3 } from "@dxos/automerge/automerge";
109
113
 
110
114
  // packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
111
- import { next as am } from "@dxos/automerge/automerge";
115
+ import { next as A2 } from "@dxos/automerge/automerge";
112
116
  var updateAutomerge = (field, handle, transactions, state) => {
113
117
  const { lastHeads, path } = state.field(field);
114
118
  let hasChanges = false;
@@ -121,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
121
125
  return void 0;
122
126
  }
123
127
  const newHeads = handle.changeAt(lastHeads, (doc) => {
128
+ const invertedTransactions = [];
124
129
  for (const tr of transactions) {
125
- tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
126
- am.splice(doc, path, fromA, toA - fromA, inserted.toString());
130
+ tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
131
+ invertedTransactions.push({
132
+ from: fromA,
133
+ del: toA - fromA,
134
+ insert
135
+ });
127
136
  });
128
137
  }
138
+ invertedTransactions.reverse().forEach(({ from, del, insert }) => {
139
+ A2.splice(doc, path.slice(), from, del, insert.toString());
140
+ });
129
141
  });
130
142
  return newHeads ?? void 0;
131
143
  };
@@ -140,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
140
152
  selection = selection.map(changeSet, 1);
141
153
  view.dispatch({
142
154
  changes: changeSet,
143
- annotations: reconcileAnnotationType.of({})
155
+ annotations: reconcileAnnotation.of(false)
144
156
  });
145
157
  }
146
158
  }
147
159
  view.dispatch({
148
160
  selection,
149
- annotations: reconcileAnnotationType.of({})
161
+ annotations: reconcileAnnotation.of(false)
150
162
  });
151
163
  };
152
164
  var handlePatch = (patch, target, state) => {
@@ -167,7 +179,7 @@ var handleInsert = (target, patch) => {
167
179
  if (index == null) {
168
180
  return [];
169
181
  }
170
- const text = patch.values.map((v) => v ? v.toString() : "").join("");
182
+ const text = patch.values.map((value) => value ? value.toString() : "").join("");
171
183
  return [
172
184
  {
173
185
  from: index,
@@ -245,36 +257,37 @@ var PatchSemaphore = class {
245
257
  this._state = _state;
246
258
  this._inReconcile = false;
247
259
  }
248
- // NOTE: Cannot destruct view.state.
249
260
  reconcile(view) {
250
- if (this._inReconcile) {
251
- return;
261
+ if (!this._inReconcile) {
262
+ this._inReconcile = true;
263
+ this.doReconcile(view);
264
+ this._inReconcile = false;
252
265
  }
253
- this._inReconcile = true;
266
+ }
267
+ doReconcile(view) {
254
268
  const path = getPath(view.state, this._state);
255
269
  const oldHeads = getLastHeads(view.state, this._state);
256
270
  let selection = view.state.selection;
257
- const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
271
+ const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
258
272
  const toInvert = transactions.slice().reverse();
259
- for (const tx of toInvert) {
260
- const inverted = tx.changes.invert(tx.startState.doc);
273
+ for (const tr of toInvert) {
274
+ const inverted = tr.changes.invert(tr.startState.doc);
261
275
  selection = selection.map(inverted);
262
276
  view.dispatch({
263
277
  changes: inverted,
264
- annotations: reconcileAnnotationType.of(true)
278
+ annotations: reconcileAnnotation.of(true)
265
279
  });
266
280
  }
267
281
  let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
268
282
  if (newHeads === null || newHeads === void 0) {
269
- newHeads = automerge2.getHeads(this._handle.docSync());
283
+ newHeads = A3.getHeads(this._handle.docSync());
270
284
  }
271
- const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
285
+ const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
272
286
  updateCodeMirror(view, selection, path, diff);
273
287
  view.dispatch({
274
288
  effects: updateHeads(newHeads),
275
- annotations: reconcileAnnotationType.of({})
289
+ annotations: reconcileAnnotation.of(false)
276
290
  });
277
- this._inReconcile = false;
278
291
  }
279
292
  };
280
293
 
@@ -292,9 +305,9 @@ var Cursor = class _Cursor {
292
305
  }
293
306
  static {
294
307
  this.getCursorFromRange = (state, range) => {
295
- const cursorConverter3 = state.facet(_Cursor.converter);
296
- const from = cursorConverter3.toCursor(range.from);
297
- const to = cursorConverter3.toCursor(range.to, -1);
308
+ const cursorConverter2 = state.facet(_Cursor.converter);
309
+ const from = cursorConverter2.toCursor(range.from);
310
+ const to = cursorConverter2.toCursor(range.to, -1);
298
311
  return [
299
312
  from,
300
313
  to
@@ -303,10 +316,10 @@ var Cursor = class _Cursor {
303
316
  }
304
317
  static {
305
318
  this.getRangeFromCursor = (state, cursor) => {
306
- const cursorConverter3 = state.facet(_Cursor.converter);
319
+ const cursorConverter2 = state.facet(_Cursor.converter);
307
320
  const parts = cursor.split(":");
308
- const from = cursorConverter3.fromCursor(parts[0]);
309
- const to = cursorConverter3.fromCursor(parts[1]);
321
+ const from = cursorConverter2.fromCursor(parts[0]);
322
+ const to = cursorConverter2.fromCursor(parts[1]);
310
323
  return from !== void 0 && to !== void 0 ? {
311
324
  from,
312
325
  to
@@ -316,11 +329,11 @@ var Cursor = class _Cursor {
316
329
  };
317
330
 
318
331
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
319
- var automerge3 = ({ handle, path }) => {
320
- const state = StateField.define({
332
+ var automerge = ({ handle, path }) => {
333
+ const syncState = StateField.define({
321
334
  create: () => ({
322
335
  path: path.slice(),
323
- lastHeads: A.getHeads(handle.docSync()),
336
+ lastHeads: A4.getHeads(handle.docSync()),
324
337
  unreconciledTransactions: []
325
338
  }),
326
339
  update: (value, tr) => {
@@ -331,7 +344,7 @@ var automerge3 = ({ handle, path }) => {
331
344
  };
332
345
  let clearUnreconciled = false;
333
346
  for (const effect of tr.effects) {
334
- if (effect.is(effectType)) {
347
+ if (effect.is(updateHeadsEffect)) {
335
348
  result.lastHeads = effect.value.newHeads;
336
349
  clearUnreconciled = true;
337
350
  }
@@ -339,80 +352,78 @@ var automerge3 = ({ handle, path }) => {
339
352
  if (clearUnreconciled) {
340
353
  result.unreconciledTransactions = [];
341
354
  } else {
342
- if (!isReconcileTx(tr)) {
355
+ if (!isReconcile(tr)) {
343
356
  result.unreconciledTransactions.push(tr);
344
357
  }
345
358
  }
346
359
  return result;
347
360
  }
348
361
  });
349
- const semaphore = new PatchSemaphore(handle, state);
362
+ const semaphore = new PatchSemaphore(handle, syncState);
350
363
  return [
351
364
  Cursor.converter.of(cursorConverter(handle, path)),
365
+ syncState,
366
+ // Reconcile external updates.
367
+ ViewPlugin.fromClass(class {
368
+ constructor(_view) {
369
+ this._view = _view;
370
+ handle.addListener("change", this._handleChange.bind(this));
371
+ }
372
+ destroy() {
373
+ handle.removeListener("change", this._handleChange.bind(this));
374
+ }
375
+ _handleChange() {
376
+ semaphore.reconcile(this._view);
377
+ }
378
+ }),
379
+ // Reconcile local updates.
352
380
  EditorView.updateListener.of(({ view, changes }) => {
353
381
  if (!changes.empty) {
354
382
  semaphore.reconcile(view);
355
383
  }
356
384
  }),
357
- state
385
+ // TODO(burdon): Record undo transactions.
386
+ // See https://github.com/yjs/y-codemirror.next/tree/main
387
+ // https://codemirror.net/examples/inverted-effect
388
+ invertedEffects.of((tr) => {
389
+ const effects = [];
390
+ if (!tr.changes.empty) {
391
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
392
+ });
393
+ }
394
+ return effects;
395
+ })
358
396
  ];
359
397
  };
360
398
 
361
399
  // packages/ui/react-ui-editor/src/extensions/awareness.ts
362
400
  import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
363
- import { Decoration, EditorView as EditorView2, ViewPlugin, WidgetType } from "@codemirror/view";
364
- import { useEffect } from "react";
401
+ import { Decoration, EditorView as EditorView2, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
365
402
  import { Event } from "@dxos/async";
366
403
  import { Context } from "@dxos/context";
367
- import { generateName } from "@dxos/display-name";
368
- import { useThemeContext } from "@dxos/react-ui";
369
- import { getColorForValue } from "@dxos/react-ui-theme";
370
404
  var dummyProvider = {
371
405
  remoteStateChange: new Event(),
372
406
  open: () => {
373
407
  },
374
408
  close: () => {
375
409
  },
410
+ getRemoteStates: () => [],
376
411
  update: () => {
377
- },
378
- getRemoteStates: () => []
412
+ }
379
413
  };
380
- var AwarenessProvider = Facet2.define({
414
+ var awarenessProvider = Facet2.define({
381
415
  combine: (providers) => providers[0] ?? dummyProvider
382
416
  });
383
417
  var RemoteSelectionChangedAnnotation = Annotation2.define();
384
418
  var awareness = (provider = dummyProvider) => {
385
419
  return [
386
- AwarenessProvider.of(provider),
387
- ViewPlugin.fromClass(RemoteSelectionsDecorator, {
420
+ awarenessProvider.of(provider),
421
+ ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
388
422
  decorations: (value) => value.decorations
389
423
  }),
390
424
  styles
391
425
  ];
392
426
  };
393
- var useAwareness = ({ awareness: awareness2, peer }) => {
394
- const { themeMode } = useThemeContext();
395
- useEffect(() => {
396
- if (awareness2 && peer) {
397
- awareness2.setLocalStateField("user", {
398
- name: peer.name ?? generateName(peer.id),
399
- color: getColorForValue({
400
- value: peer.id,
401
- type: "color"
402
- }),
403
- colorLight: getColorForValue({
404
- value: peer.id,
405
- themeMode,
406
- type: "highlight"
407
- })
408
- });
409
- }
410
- }, [
411
- awareness2,
412
- peer,
413
- themeMode
414
- ]);
415
- };
416
427
  var RemoteSelectionsDecorator = class {
417
428
  constructor(view) {
418
429
  this.decorations = RangeSet.of([]);
@@ -420,7 +431,7 @@ var RemoteSelectionsDecorator = class {
420
431
  this._lastAnchor = void 0;
421
432
  this._lastHead = void 0;
422
433
  this._cursorConverter = view.state.facet(Cursor.converter);
423
- this._provider = view.state.facet(AwarenessProvider);
434
+ this._provider = view.state.facet(awarenessProvider);
424
435
  this._provider.open();
425
436
  this._provider.remoteStateChange.on(this._ctx, () => {
426
437
  view.dispatch({
@@ -574,39 +585,41 @@ var styles = EditorView2.baseTheme({
574
585
  marginLeft: "-1px",
575
586
  marginRight: "-1px",
576
587
  boxSizing: "border-box",
577
- display: "inline"
588
+ display: "inline",
589
+ cursor: "pointer"
578
590
  },
579
591
  ".cm-collab-selectionCaretDot": {
580
592
  borderRadius: "50%",
581
593
  position: "absolute",
582
- width: ".4em",
583
- height: ".4em",
584
- top: "-.2em",
585
- left: "-.2em",
594
+ width: ".5em",
595
+ height: ".5em",
596
+ top: "-.25em",
597
+ left: "-.25em",
586
598
  backgroundColor: "inherit",
587
599
  transition: "transform .3s ease-in-out",
588
600
  boxSizing: "border-box"
589
601
  },
590
602
  ".cm-collab-selectionCaret:hover > .cm-collab-selectionCaretDot": {
591
- transformOrigin: "bottom center",
592
- transform: "scale(0)"
603
+ transform: "scale(0)",
604
+ transformOrigin: "center"
593
605
  },
594
606
  ".cm-collab-selectionInfo": {
595
607
  position: "absolute",
596
- top: "-1.05em",
597
- left: "-1px",
608
+ transform: "translate(-50%, 0)",
609
+ top: "-20px",
610
+ left: 0,
598
611
  fontSize: ".75em",
599
- fontFamily: "serif",
612
+ fontFamily: "sans-serif",
600
613
  fontStyle: "normal",
601
614
  fontWeight: "normal",
602
615
  lineHeight: "normal",
603
616
  userSelect: "none",
604
617
  color: "white",
605
- paddingLeft: "2px",
606
- paddingRight: "2px",
618
+ padding: "2px",
607
619
  zIndex: 101,
608
620
  transition: "opacity .3s ease-in-out",
609
621
  backgroundColor: "inherit",
622
+ borderRadius: "2px",
610
623
  // These should be separate.
611
624
  opacity: 0,
612
625
  transitionDelay: "0s",
@@ -624,18 +637,19 @@ import { history } from "@codemirror/commands";
624
637
  import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
625
638
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
626
639
  import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
627
- var basicBundle = ({ themeMode, placeholder: _placeholder, multiline = true }) => [
628
- multiline ? EditorView3.lineWrapping : [],
640
+ import { isNotFalsy } from "@dxos/util";
641
+ var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
642
+ lineWrapping && EditorView3.lineWrapping,
629
643
  // https://codemirror.net/docs/ref/#codemirror.minimalSetup
630
644
  bracketMatching(),
631
645
  closeBrackets(),
632
646
  drawSelection(),
633
647
  highlightActiveLine(),
634
648
  history(),
635
- _placeholder ? placeholder(_placeholder) : [],
649
+ _placeholder && placeholder(_placeholder),
636
650
  // https://github.com/codemirror/theme-one-dark
637
651
  themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
638
- ];
652
+ ].filter(isNotFalsy);
639
653
 
640
654
  // packages/ui/react-ui-editor/src/extensions/blast.ts
641
655
  import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
@@ -674,10 +688,10 @@ var blast = (options = defaultOptions) => {
674
688
  const getPoint = (view, pos) => {
675
689
  const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
676
690
  const element = document.elementFromPoint(x, y);
677
- const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
691
+ const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
678
692
  const point = {
679
693
  x: x - left,
680
- y: y - top
694
+ y: y - top2
681
695
  };
682
696
  return {
683
697
  element,
@@ -769,7 +783,7 @@ var Blaster = class {
769
783
  initialize() {
770
784
  invariant(!this._canvas && !this._ctx, void 0, {
771
785
  F: __dxlog_file,
772
- L: 138,
786
+ L: 141,
773
787
  S: this,
774
788
  A: [
775
789
  "!this._canvas && !this._ctx",
@@ -806,7 +820,7 @@ var Blaster = class {
806
820
  start() {
807
821
  invariant(this._canvas && this._ctx, void 0, {
808
822
  F: __dxlog_file,
809
- L: 177,
823
+ L: 180,
810
824
  S: this,
811
825
  A: [
812
826
  "this._canvas && this._ctx",
@@ -947,9 +961,14 @@ var random = (min, max) => {
947
961
  return min + ~~(Math.random() * (max - min + 1));
948
962
  };
949
963
 
950
- // packages/ui/react-ui-editor/src/extensions/code.ts
951
- import { ViewPlugin as ViewPlugin2, EditorView as EditorView5, Decoration as Decoration2 } from "@codemirror/view";
952
- import { mx as mx2 } from "@dxos/react-ui-theme";
964
+ // packages/ui/react-ui-editor/src/extensions/comments.ts
965
+ import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
966
+ import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
967
+ import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
968
+ import sortBy from "lodash.sortby";
969
+ import { useEffect } from "react";
970
+ import { debounce } from "@dxos/async";
971
+ import { nonNullable } from "@dxos/util";
953
972
 
954
973
  // packages/ui/react-ui-editor/src/styles/cursors.ts
955
974
  import * as random2 from "lib0/random";
@@ -992,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
992
1011
  // packages/ui/react-ui-editor/src/styles/markdown.ts
993
1012
  import { mx } from "@dxos/react-ui-theme";
994
1013
  var headings = {
995
- 1: [
996
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
997
- "-ml-[10px]"
998
- ],
999
- 2: [
1000
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
1001
- "-ml-[8px]"
1002
- ],
1003
- 3: [
1004
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
1005
- "-ml-[7px]"
1006
- ],
1007
- 4: [
1008
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
1009
- "-ml-[6px]"
1010
- ],
1011
- 5: [
1012
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
1013
- "-ml-[5px]"
1014
- ],
1015
- 6: [
1016
- "mbs-4 mbe-2 font-medium text-inherit no-underline",
1017
- "-ml-[4px]"
1018
- ]
1019
- };
1020
- var heading = (level, readonly) => {
1021
- const [style, offset] = headings[level];
1022
- return mx(style, readonly && offset);
1014
+ 1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
1015
+ 2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
1016
+ 3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
1017
+ 4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
1018
+ 5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
1019
+ 6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
1020
+ };
1021
+ var heading = (level) => {
1022
+ return headings[level];
1023
1023
  };
1024
1024
  var light = "text-neutral-200 dark:text-neutral-800";
1025
1025
  var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
@@ -1037,89 +1037,6 @@ import { tailwindConfig } from "@dxos/react-ui-theme";
1037
1037
  var tokens = tailwindConfig({}).theme;
1038
1038
  var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue);
1039
1039
 
1040
- // packages/ui/react-ui-editor/src/extensions/code.ts
1041
- var CODE_REGEX = /```[\s\S]*?```/gs;
1042
- var styles2 = EditorView5.baseTheme({
1043
- "& .cm-codeblock": {
1044
- fontFamily: getToken("fontFamily.mono", []).join(",")
1045
- },
1046
- '&light [aria-readonly="true"] .cm-codeblock': {
1047
- background: getToken("extend.colors.neutral.50")
1048
- },
1049
- '&dark [aria-readonly="true"] .cm-codeblock': {
1050
- background: getToken("extend.colors.neutral.850")
1051
- },
1052
- '& [aria-readonly="true"] .cm-codeblock': {
1053
- display: "block",
1054
- paddingInline: "4px !important"
1055
- },
1056
- '& [aria-readonly="true"] .cm-codeblock-first': {
1057
- paddingTop: "4px !important",
1058
- borderTopLeftRadius: "4px",
1059
- borderTopRightRadius: "4px"
1060
- },
1061
- '& [aria-readonly="true"] .cm-codeblock-last': {
1062
- paddingBottom: "4px !important",
1063
- borderBottomLeftRadius: "4px",
1064
- borderBottomRightRadius: "4px"
1065
- }
1066
- });
1067
- var getLineRange = (lines, from, to) => {
1068
- const start = lines.findIndex((line) => line.from >= from);
1069
- const end = lines.findIndex((line) => line.to >= to);
1070
- return [
1071
- start,
1072
- end
1073
- ];
1074
- };
1075
- var code2 = () => {
1076
- const buildDecorations5 = (view) => {
1077
- const decorations = [];
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));
1088
- }
1089
- }
1090
- return Decoration2.set(decorations);
1091
- };
1092
- return [
1093
- ViewPlugin2.fromClass(class {
1094
- constructor(view) {
1095
- this.hasFocus = false;
1096
- this.decorations = buildDecorations5(view);
1097
- }
1098
- update(update2) {
1099
- if (
1100
- // TODO(burdon): Generalize for other extensions.
1101
- this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1102
- ) {
1103
- this.hasFocus = update2.view.hasFocus;
1104
- this.decorations = buildDecorations5(update2.view);
1105
- }
1106
- }
1107
- }, {
1108
- decorations: (value) => value.decorations
1109
- }),
1110
- styles2
1111
- ];
1112
- };
1113
-
1114
- // packages/ui/react-ui-editor/src/extensions/comments.ts
1115
- import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1116
- import { hoverTooltip, keymap as keymap3, Decoration as Decoration3, EditorView as EditorView6 } from "@codemirror/view";
1117
- import sortBy from "lodash.sortby";
1118
- import { useEffect as useEffect2 } from "react";
1119
- import { debounce } from "@dxos/async";
1120
- import { invariant as invariant2 } from "@dxos/invariant";
1121
- import { nonNullable } from "@dxos/util";
1122
-
1123
1040
  // packages/ui/react-ui-editor/src/util.ts
1124
1041
  import { log } from "@dxos/log";
1125
1042
  var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
@@ -1156,24 +1073,21 @@ var logChanges = (trs) => {
1156
1073
  };
1157
1074
 
1158
1075
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1159
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1160
- var styles3 = EditorView6.baseTheme({
1076
+ var styles2 = EditorView5.baseTheme({
1161
1077
  "& .cm-comment": {
1162
1078
  backgroundColor: getToken("extend.colors.yellow.50")
1163
1079
  },
1164
- "& .cm-comment-active": {
1080
+ "& .cm-comment-current": {
1165
1081
  backgroundColor: getToken("extend.colors.yellow.100")
1166
1082
  }
1167
1083
  });
1168
- var marks = {
1169
- highlight: Decoration3.mark({
1170
- class: "cm-comment"
1171
- }),
1172
- highlightActive: Decoration3.mark({
1173
- class: "cm-comment-active"
1174
- })
1175
- };
1176
- var setFocus = (view, id, center = true) => {
1084
+ var commentMark = Decoration2.mark({
1085
+ class: "cm-comment"
1086
+ });
1087
+ var commentCurrentMark = Decoration2.mark({
1088
+ class: "cm-comment-current"
1089
+ });
1090
+ var focusComment = (view, id, center = true) => {
1177
1091
  const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
1178
1092
  if (!comment?.comment.cursor) {
1179
1093
  return;
@@ -1186,11 +1100,11 @@ var setFocus = (view, id, center = true) => {
1186
1100
  },
1187
1101
  effects: [
1188
1102
  //
1189
- EditorView6.scrollIntoView(range.from, center ? {
1103
+ EditorView5.scrollIntoView(range.from, center ? {
1190
1104
  y: "center"
1191
1105
  } : void 0),
1192
1106
  setSelection.of({
1193
- active: id
1107
+ current: id
1194
1108
  })
1195
1109
  ]
1196
1110
  });
@@ -1235,23 +1149,23 @@ var commentsState = StateField2.define({
1235
1149
  return value;
1236
1150
  }
1237
1151
  });
1238
- var highlightDecorations = EditorView6.decorations.compute([
1152
+ var commentsDecorations = EditorView5.decorations.compute([
1239
1153
  commentsState
1240
1154
  ], (state) => {
1241
- const { selection: { active }, comments: comments2 } = state.field(commentsState);
1155
+ const { selection: { current }, comments: comments2 } = state.field(commentsState);
1242
1156
  const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1243
1157
  const range = comment.range;
1244
1158
  if (!range || range.from === range.to) {
1245
1159
  console.warn("Invalid range:", range);
1246
1160
  return void 0;
1247
1161
  }
1248
- if (comment.comment.id === active) {
1249
- return marks.highlightActive.range(range.from, range.to);
1162
+ if (comment.comment.id === current) {
1163
+ return commentCurrentMark.range(range.from, range.to);
1250
1164
  } else {
1251
- return marks.highlight.range(range.from, range.to);
1165
+ return commentMark.range(range.from, range.to);
1252
1166
  }
1253
1167
  }).filter(nonNullable);
1254
- return Decoration3.set(decorations);
1168
+ return Decoration2.set(decorations);
1255
1169
  });
1256
1170
  var trackPastedComments = (onUpdate) => {
1257
1171
  let tracked = null;
@@ -1273,96 +1187,136 @@ var trackPastedComments = (onUpdate) => {
1273
1187
  }
1274
1188
  };
1275
1189
  return [
1276
- EditorView6.domEventHandlers({
1190
+ EditorView5.domEventHandlers({
1277
1191
  cut: handleTrack,
1278
1192
  copy: handleTrack
1279
1193
  }),
1280
- // Handle paste.
1281
- EditorView6.updateListener.of(({ view, state, transactions }) => {
1194
+ // Track deleted comments.
1195
+ invertedEffects2.of((tr) => {
1196
+ const { comments: comments2 } = tr.startState.field(commentsState);
1197
+ const effects = [];
1198
+ tr.changes.iterChangedRanges((fromA, toA) => {
1199
+ for (const { comment: { id }, range: { from, to } } of comments2) {
1200
+ if (from < to && from >= fromA && to <= toA) {
1201
+ effects.push(restoreCommentEffect.of({
1202
+ id,
1203
+ from,
1204
+ to
1205
+ }));
1206
+ }
1207
+ }
1208
+ });
1209
+ return effects;
1210
+ }),
1211
+ // Handle paste or the undo of comment deletion.
1212
+ EditorView5.updateListener.of((update2) => {
1213
+ const restore = [];
1214
+ for (let i = 0; i < update2.transactions.length; i++) {
1215
+ const tr = update2.transactions[i];
1216
+ for (let j = 0; j < restore.length; j++) {
1217
+ restore[j] = mapTrackedComment(restore[j], tr.changes);
1218
+ }
1219
+ for (const effect of tr.effects) {
1220
+ if (effect.is(restoreCommentEffect)) {
1221
+ restore.push(effect.value);
1222
+ }
1223
+ }
1224
+ }
1282
1225
  if (tracked) {
1283
- const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
1226
+ const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
1284
1227
  if (paste) {
1285
1228
  let found = -1;
1286
1229
  paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
1287
1230
  if (text.eq(tracked.text)) {
1288
- for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
1289
- fromB = transactions[i].changes.mapPos(fromB);
1231
+ for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
1232
+ fromB = update2.transactions[i].changes.mapPos(fromB);
1290
1233
  }
1291
1234
  found = fromB;
1292
1235
  }
1293
1236
  });
1294
1237
  if (found > -1) {
1295
1238
  for (const moved of tracked.comments) {
1296
- const range = {
1239
+ restore.push({
1240
+ id: moved.id,
1297
1241
  from: found + moved.from,
1298
1242
  to: found + moved.to
1299
- };
1300
- const cursor = Cursor.getCursorFromRange(state, range);
1301
- onUpdate(moved.id, cursor);
1243
+ });
1302
1244
  }
1303
1245
  }
1304
1246
  tracked = null;
1305
1247
  }
1306
1248
  }
1249
+ for (const comment of restore) {
1250
+ const { comments: comments2 } = update2.startState.field(commentsState);
1251
+ const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
1252
+ if (!exists) {
1253
+ const cursor = Cursor.getCursorFromRange(update2.state, comment);
1254
+ onUpdate(comment.id, cursor);
1255
+ }
1256
+ }
1307
1257
  })
1308
1258
  ];
1309
1259
  };
1310
- var comments = (options = {}) => {
1311
- const { key: shortcut = "meta-'" } = options;
1312
- const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1313
- const createCommentThread = (view) => {
1314
- invariant2(options.onCreate, void 0, {
1315
- F: __dxlog_file3,
1316
- L: 259,
1317
- S: void 0,
1318
- A: [
1319
- "options.onCreate",
1320
- ""
1321
- ]
1260
+ var mapTrackedComment = (comment, changes) => ({
1261
+ id: comment.id,
1262
+ from: changes.mapPos(comment.from, 1),
1263
+ to: changes.mapPos(comment.to, 1)
1264
+ });
1265
+ var restoreCommentEffect = StateEffect2.define({
1266
+ map: mapTrackedComment
1267
+ });
1268
+ var optionsFacet = Facet3.define({
1269
+ combine: (providers) => providers[0]
1270
+ });
1271
+ var createComment = (view) => {
1272
+ const options = view.state.facet(optionsFacet);
1273
+ const { from, to } = view.state.selection.main;
1274
+ if (from === to) {
1275
+ return false;
1276
+ }
1277
+ if (to === view.state.doc.length) {
1278
+ view.dispatch({
1279
+ changes: {
1280
+ from: to,
1281
+ insert: "\n"
1282
+ }
1322
1283
  });
1323
- const { from, to } = view.state.selection.main;
1324
- if (from === to) {
1325
- return false;
1326
- }
1327
- if (to === view.state.doc.length) {
1284
+ }
1285
+ const cursor = Cursor.getCursorFromRange(view.state, {
1286
+ from,
1287
+ to
1288
+ });
1289
+ if (cursor) {
1290
+ const id = options.onCreate?.(cursor, view.coordsAtPos(from));
1291
+ if (id) {
1328
1292
  view.dispatch({
1329
- changes: {
1330
- from: to,
1331
- insert: "\n"
1293
+ effects: setSelection.of({
1294
+ current: id
1295
+ }),
1296
+ selection: {
1297
+ anchor: to
1332
1298
  }
1333
1299
  });
1300
+ return true;
1334
1301
  }
1335
- const cursor = Cursor.getCursorFromRange(view.state, {
1336
- from,
1337
- to
1338
- });
1339
- if (cursor) {
1340
- const id = options.onCreate?.(cursor, view.coordsAtPos(from));
1341
- if (id) {
1342
- view.dispatch({
1343
- effects: setSelection.of({
1344
- active: id
1345
- }),
1346
- selection: {
1347
- anchor: from
1348
- }
1349
- });
1350
- return true;
1351
- }
1352
- }
1353
- return false;
1354
- };
1302
+ }
1303
+ return false;
1304
+ };
1305
+ var comments = (options = {}) => {
1306
+ const { key: shortcut = "meta-'" } = options;
1307
+ const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1355
1308
  return [
1309
+ optionsFacet.of(options),
1356
1310
  commentsState,
1357
- highlightDecorations,
1358
- styles3,
1311
+ commentsDecorations,
1312
+ styles2,
1359
1313
  //
1360
1314
  // Keymap.
1361
1315
  //
1362
1316
  options.onCreate ? keymap3.of([
1363
1317
  {
1364
1318
  key: shortcut,
1365
- run: callbackWrapper(createCommentThread)
1319
+ run: callbackWrapper(createComment)
1366
1320
  }
1367
1321
  ]) : [],
1368
1322
  //
@@ -1398,7 +1352,7 @@ var comments = (options = {}) => {
1398
1352
  //
1399
1353
  // Track deleted ranges and update ranges for decorations.
1400
1354
  //
1401
- EditorView6.updateListener.of(({ view, state, changes }) => {
1355
+ EditorView5.updateListener.of(({ view, state, changes }) => {
1402
1356
  let mod = false;
1403
1357
  const { comments: comments2, ...value } = state.field(commentsState);
1404
1358
  changes.iterChanges((from, to, from2, to2) => {
@@ -1428,17 +1382,17 @@ var comments = (options = {}) => {
1428
1382
  //
1429
1383
  // Track selection/proximity.
1430
1384
  //
1431
- EditorView6.updateListener.of(({ view, state, changes }) => {
1385
+ EditorView5.updateListener.of(({ view, state }) => {
1432
1386
  let min = Infinity;
1433
- const { selection: { active, closest }, comments: comments2 } = state.field(commentsState);
1387
+ const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1434
1388
  const { head } = state.selection.main;
1435
1389
  const selection = {};
1436
1390
  comments2.forEach(({ comment, range }) => {
1437
1391
  if (head >= range.from && head <= range.to) {
1438
- selection.active = comment.id;
1392
+ selection.current = comment.id;
1439
1393
  selection.closest = void 0;
1440
1394
  }
1441
- if (!selection.active) {
1395
+ if (!selection.current) {
1442
1396
  const d = Math.min(Math.abs(head - range.from), Math.abs(head - range.to));
1443
1397
  if (d < min) {
1444
1398
  selection.closest = comment.id;
@@ -1446,7 +1400,7 @@ var comments = (options = {}) => {
1446
1400
  }
1447
1401
  }
1448
1402
  });
1449
- if (selection.active !== active || selection.closest !== closest) {
1403
+ if (selection.current !== current || selection.closest !== closest) {
1450
1404
  view.dispatch({
1451
1405
  effects: setSelection.of(selection)
1452
1406
  });
@@ -1463,9 +1417,9 @@ var comments = (options = {}) => {
1463
1417
  options.onUpdate ? trackPastedComments(options.onUpdate) : []
1464
1418
  ];
1465
1419
  };
1466
- var useComments = (view, comments2) => {
1467
- useEffect2(() => {
1468
- if (view && comments2) {
1420
+ var useComments = (view, comments2 = []) => {
1421
+ useEffect(() => {
1422
+ if (view) {
1469
1423
  view.dispatch({
1470
1424
  effects: setComments.of(comments2)
1471
1425
  });
@@ -1476,314 +1430,51 @@ var useComments = (view, comments2) => {
1476
1430
  ]);
1477
1431
  };
1478
1432
 
1479
- // packages/ui/react-ui-editor/src/extensions/hr.ts
1480
- import { syntaxTree } from "@codemirror/language";
1481
- import { RangeSetBuilder } from "@codemirror/state";
1482
- import { Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
1483
- var styles4 = EditorView7.baseTheme({
1484
- "& .cm-hr": {
1485
- // Note that block-level decorations should not have vertical margins,
1486
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
1487
- }
1488
- });
1489
- var HorizontalRuleWidget = class extends WidgetType2 {
1490
- toDOM() {
1491
- const el = document.createElement("div");
1492
- el.className = "cm-hr";
1493
- return el;
1494
- }
1495
- };
1496
- var decoration = Decoration4.replace({
1497
- widget: new HorizontalRuleWidget()
1498
- });
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
- ViewPlugin3.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
1530
- })
1531
- ];
1433
+ // packages/ui/react-ui-editor/src/extensions/listener.ts
1434
+ import { EditorView as EditorView6 } from "@codemirror/view";
1435
+ var listener = ({ onFocus, onChange }) => {
1436
+ const extensions = [];
1437
+ onFocus && extensions.push(EditorView6.focusChangeEffect.of((_, focused) => {
1438
+ onFocus(focused);
1439
+ return null;
1440
+ }));
1441
+ onChange && extensions.push(EditorView6.updateListener.of((update2) => {
1442
+ onChange(update2.state.doc.toString());
1443
+ }));
1444
+ return extensions;
1532
1445
  };
1533
1446
 
1534
- // packages/ui/react-ui-editor/src/extensions/image.ts
1535
- import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1536
- import { StateField as StateField3 } from "@codemirror/state";
1537
- import { Decoration as Decoration5, EditorView as EditorView8, WidgetType as WidgetType3 } from "@codemirror/view";
1538
- var image = (options = {}) => {
1539
- return StateField3.define({
1540
- create: (state) => {
1541
- return Decoration5.set(buildDecorations2(0, state.doc.length, state));
1542
- },
1543
- update: (value, tr) => {
1544
- if (!tr.docChanged && !tr.selection) {
1545
- return value;
1546
- }
1547
- const cursor = tr.state.selection.main.head;
1548
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
1549
- let from = Math.min(cursor, oldCursor);
1550
- let to = Math.max(cursor, oldCursor);
1551
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
1552
- from = Math.min(from, fromB);
1553
- to = Math.max(to, toB);
1554
- });
1555
- from = tr.state.doc.lineAt(from).from;
1556
- to = tr.state.doc.lineAt(to).to;
1557
- return value.map(tr.changes).update({
1558
- filterFrom: from,
1559
- filterTo: to,
1560
- filter: () => false,
1561
- add: buildDecorations2(from, to, tr.state)
1562
- });
1563
- },
1564
- provide: (field) => EditorView8.decorations.from(field)
1565
- });
1566
- };
1567
- var buildDecorations2 = (from, to, state) => {
1568
- const decorations = [];
1569
- const cursor = state.selection.main.head;
1570
- syntaxTree2(state).iterate({
1571
- enter: (node) => {
1572
- if (node.name === "Image") {
1573
- const urlNode = node.node.getChild("URL");
1574
- if (urlNode) {
1575
- const hide = state.readOnly || cursor < node.from || cursor > node.to;
1576
- const url = state.sliceDoc(urlNode.from, urlNode.to);
1577
- decorations.push(Decoration5.replace({
1578
- block: true,
1579
- widget: new ImageWidget(url)
1580
- }).range(hide ? node.from : node.to, node.to));
1581
- }
1582
- }
1583
- },
1584
- from,
1585
- to
1586
- });
1587
- return decorations;
1588
- };
1589
- var ImageWidget = class extends WidgetType3 {
1590
- constructor(_url) {
1591
- super();
1592
- this._url = _url;
1593
- }
1594
- eq(other) {
1595
- return this._url === other._url;
1596
- }
1597
- toDOM(view) {
1598
- const img = document.createElement("img");
1599
- img.setAttribute("src", this._url);
1600
- img.setAttribute("class", "cm-image");
1601
- img.onload = () => img.classList.add("cm-loaded-image");
1602
- return img;
1603
- }
1604
- };
1605
-
1606
- // packages/ui/react-ui-editor/src/extensions/link.ts
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 ViewPlugin4, WidgetType as WidgetType4 } from "@codemirror/view";
1610
- import { tooltipContent } from "@dxos/react-ui-theme";
1611
- var link = (options = {}) => {
1612
- const extensions = [
1613
- ViewPlugin4.fromClass(class {
1614
- constructor(view) {
1615
- this.decorations = buildDecorations3(view, options);
1616
- }
1617
- update(update2) {
1618
- if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
1619
- this.decorations = buildDecorations3(update2.view, options);
1620
- }
1621
- }
1622
- }, {
1623
- decorations: (v) => v.decorations
1624
- })
1625
- ];
1626
- if (options.onHover) {
1627
- extensions.push(
1628
- // https://codemirror.net/examples/tooltip
1629
- // https://codemirror.net/docs/ref/#view.hoverTooltip
1630
- // https://github.com/codemirror/view/blob/main/src/tooltip.ts
1631
- hoverTooltip2((view, pos, side) => {
1632
- const syntax = syntaxTree3(view.state).resolveInner(pos, side);
1633
- let link2 = null;
1634
- for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
1635
- link2 = node.name === "Link" ? node : null;
1636
- }
1637
- const url = link2 && link2.getChild("URL");
1638
- if (!url || !link2) {
1639
- return null;
1640
- }
1641
- const urlText = view.state.sliceDoc(url.from, url.to);
1642
- return {
1643
- pos: link2.from,
1644
- end: link2.to,
1645
- above: true,
1646
- create: () => {
1647
- const el = document.createElement("div");
1648
- el.className = tooltipContent({}, "pli-2 plb-1");
1649
- options.onHover(el, urlText);
1650
- return {
1651
- dom: el,
1652
- offset: {
1653
- x: 0,
1654
- y: 4
1655
- }
1656
- };
1657
- }
1658
- };
1659
- })
1660
- );
1661
- }
1662
- return extensions;
1663
- };
1664
- var LinkButton = class extends WidgetType4 {
1665
- constructor(_url, _onAttach) {
1666
- super();
1667
- this._url = _url;
1668
- this._onAttach = _onAttach;
1669
- }
1670
- eq(other) {
1671
- return this._url === other._url;
1672
- }
1673
- toDOM(view) {
1674
- const el = document.createElement("span");
1675
- this._onAttach(el, this._url);
1676
- return el;
1677
- }
1678
- };
1679
- var LinkText = class extends WidgetType4 {
1680
- constructor(_text, _url) {
1681
- super();
1682
- this._text = _text;
1683
- this._url = _url;
1684
- }
1685
- eq(other) {
1686
- return this._url === other._url;
1687
- }
1688
- toDOM(view) {
1689
- const link2 = document.createElement("a");
1690
- link2.setAttribute("class", "cm-link");
1691
- link2.textContent = this._text;
1692
- if (this._url) {
1693
- link2.setAttribute("rel", "noreferrer");
1694
- link2.setAttribute("target", "_blank");
1695
- link2.href = this._url;
1696
- } else {
1697
- link2.onclick = () => {
1698
- view.dispatch({
1699
- selection: {
1700
- anchor: view.posAtDOM(link2)
1701
- }
1702
- });
1703
- };
1704
- }
1705
- return link2;
1706
- }
1707
- };
1708
- var buildDecorations3 = (view, options) => {
1709
- const builder = new RangeSetBuilder2();
1710
- const { state } = view;
1711
- const cursor = state.selection.main.head;
1712
- for (const { from, to } of view.visibleRanges) {
1713
- syntaxTree3(state).iterate({
1714
- enter: (node) => {
1715
- if (node.name === "Link") {
1716
- const marks2 = node.node.getChildren("LinkMark");
1717
- const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
1718
- const urlNode = node.node.getChild("URL");
1719
- const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
1720
- if (!url) {
1721
- return false;
1722
- }
1723
- if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
1724
- builder.add(node.from, node.to, Decoration6.replace({
1725
- widget: new LinkText(text, options.link ? url : void 0)
1726
- }));
1727
- }
1728
- if (options.onRender) {
1729
- builder.add(node.to, node.to, Decoration6.replace({
1730
- widget: new LinkButton(url, options.onRender)
1731
- }));
1732
- }
1733
- return false;
1734
- }
1735
- },
1736
- from,
1737
- to
1738
- });
1739
- }
1740
- return builder.finish();
1741
- };
1742
-
1743
- // packages/ui/react-ui-editor/src/extensions/listener.ts
1744
- import { EditorView as EditorView9 } from "@codemirror/view";
1745
- var listener = ({ onFocus, onChange }) => {
1746
- const extensions = [];
1747
- onFocus && extensions.push(EditorView9.focusChangeEffect.of((_, focused) => {
1748
- onFocus(focused);
1749
- return null;
1750
- }));
1751
- onChange && extensions.push(EditorView9.updateListener.of((update2) => {
1752
- onChange(update2.state.doc.toString());
1753
- }));
1754
- return extensions;
1755
- };
1756
-
1757
- // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1758
- import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1759
- import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1760
- import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1761
- import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1762
- import { languages } from "@codemirror/language-data";
1763
- import { searchKeymap } from "@codemirror/search";
1764
- import { EditorState } from "@codemirror/state";
1765
- import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1766
- import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView10, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1767
-
1768
- // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1769
- import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1770
- import { HighlightStyle } from "@codemirror/language";
1771
- import { tags, styleTags, Tag } from "@lezer/highlight";
1772
- import { Table } from "@lezer/markdown";
1773
- var markdownTags = {
1774
- Blockquote: Tag.define(),
1775
- CodeMark: Tag.define(),
1776
- CodeText: Tag.define(),
1777
- EmphasisMark: Tag.define(),
1778
- HeaderMark: Tag.define(),
1779
- InlineCode: Tag.define(),
1780
- LinkLabel: Tag.define(),
1781
- LinkReference: Tag.define(),
1782
- ListMark: Tag.define(),
1783
- QuoteMark: Tag.define(),
1784
- URL: Tag.define(),
1785
- // Custom.
1786
- TableCell: Tag.define()
1447
+ // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1448
+ import { closeBrackets as closeBrackets2, closeBracketsKeymap } from "@codemirror/autocomplete";
1449
+ import { history as history2, historyKeymap, indentWithTab, standardKeymap } from "@codemirror/commands";
1450
+ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lang-markdown";
1451
+ import { bracketMatching as bracketMatching2, defaultHighlightStyle as defaultHighlightStyle2, indentOnInput, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
1452
+ import { languages } from "@codemirror/language-data";
1453
+ import { searchKeymap } from "@codemirror/search";
1454
+ import { EditorState } from "@codemirror/state";
1455
+ import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1456
+ import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1457
+ import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1458
+
1459
+ // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1460
+ import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
1461
+ import { HighlightStyle } from "@codemirror/language";
1462
+ import { tags, styleTags, Tag } from "@lezer/highlight";
1463
+ import { Table } from "@lezer/markdown";
1464
+ var markdownTags = {
1465
+ Blockquote: Tag.define(),
1466
+ CodeMark: Tag.define(),
1467
+ CodeText: Tag.define(),
1468
+ EmphasisMark: Tag.define(),
1469
+ HeaderMark: Tag.define(),
1470
+ InlineCode: Tag.define(),
1471
+ LinkLabel: Tag.define(),
1472
+ LinkReference: Tag.define(),
1473
+ ListMark: Tag.define(),
1474
+ QuoteMark: Tag.define(),
1475
+ URL: Tag.define(),
1476
+ // Custom.
1477
+ TableCell: Tag.define()
1787
1478
  };
1788
1479
  Table.defineNodes?.forEach((node) => {
1789
1480
  switch (node?.name) {
@@ -1860,7 +1551,7 @@ var markdownHighlightStyle = (readonly) => {
1860
1551
  markdownTags.QuoteMark,
1861
1552
  markdownTags.EmphasisMark
1862
1553
  ],
1863
- class: readonly ? "hidden" : mark
1554
+ class: mark
1864
1555
  },
1865
1556
  // E.g., code block language (after ```).
1866
1557
  {
@@ -1868,7 +1559,7 @@ var markdownHighlightStyle = (readonly) => {
1868
1559
  tags.function(tags.variableName),
1869
1560
  tags.labelName
1870
1561
  ],
1871
- class: readonly ? "hidden" : codeMark
1562
+ class: codeMark
1872
1563
  },
1873
1564
  {
1874
1565
  tag: [
@@ -1879,27 +1570,27 @@ var markdownHighlightStyle = (readonly) => {
1879
1570
  // Headings.
1880
1571
  {
1881
1572
  tag: tags.heading1,
1882
- class: heading(1, readonly)
1573
+ class: heading(1)
1883
1574
  },
1884
1575
  {
1885
1576
  tag: tags.heading2,
1886
- class: heading(2, readonly)
1577
+ class: heading(2)
1887
1578
  },
1888
1579
  {
1889
1580
  tag: tags.heading3,
1890
- class: heading(3, readonly)
1581
+ class: heading(3)
1891
1582
  },
1892
1583
  {
1893
1584
  tag: tags.heading4,
1894
- class: heading(4, readonly)
1585
+ class: heading(4)
1895
1586
  },
1896
1587
  {
1897
1588
  tag: tags.heading5,
1898
- class: heading(5, readonly)
1589
+ class: heading(5)
1899
1590
  },
1900
1591
  {
1901
1592
  tag: tags.heading6,
1902
- class: heading(6, readonly)
1593
+ class: heading(6)
1903
1594
  },
1904
1595
  // Emphasis.
1905
1596
  {
@@ -1925,7 +1616,7 @@ var markdownHighlightStyle = (readonly) => {
1925
1616
  // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
1926
1617
  // when a language is specified. In this case, the syntax highlighting extensions will colorize
1927
1618
  // the code, but all other CSS properties will be inherited.
1928
- // IMPORTANT: Therefore, the fenced code block will use the base editor font.
1619
+ // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
1929
1620
  {
1930
1621
  tag: [
1931
1622
  markdownTags.CodeText,
@@ -1954,11 +1645,11 @@ var markdownHighlightStyle = (readonly) => {
1954
1645
  };
1955
1646
 
1956
1647
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1957
- var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1648
+ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
1958
1649
  return [
1650
+ lineWrapping && EditorView7.lineWrapping,
1959
1651
  EditorState.allowMultipleSelections.of(true),
1960
1652
  EditorState.tabSize.of(2),
1961
- EditorView10.lineWrapping,
1962
1653
  // https://github.com/codemirror/basic-setup
1963
1654
  bracketMatching2(),
1964
1655
  closeBrackets2(),
@@ -1968,7 +1659,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1968
1659
  highlightActiveLine2(),
1969
1660
  history2(),
1970
1661
  indentOnInput(),
1971
- _placeholder ? placeholder2(_placeholder) : [],
1662
+ _placeholder && placeholder2(_placeholder),
1972
1663
  // Main extension.
1973
1664
  // https://github.com/codemirror/lang-markdown
1974
1665
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -1990,7 +1681,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1990
1681
  // https://github.com/codemirror/theme-one-dark
1991
1682
  themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
1992
1683
  // Custom styles.
1993
- syntaxHighlighting2(markdownHighlightStyle(readonly)),
1684
+ syntaxHighlighting2(markdownHighlightStyle()),
1994
1685
  keymap4.of([
1995
1686
  // https://codemirror.net/docs/ref/#commands.indentWithTab
1996
1687
  indentWithTab,
@@ -2003,45 +1694,580 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
2003
1694
  // https://codemirror.net/docs/ref/#commands.standardKeymap
2004
1695
  ...standardKeymap
2005
1696
  ])
2006
- ];
1697
+ ].filter(isNotFalsy2);
2007
1698
  };
2008
1699
 
2009
- // packages/ui/react-ui-editor/src/extensions/mention.ts
2010
- import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
2011
- var mention = ({ onSearch }) => {
2012
- return autocompletion2({
2013
- activateOnTyping: true,
2014
- selectOnOpen: true,
2015
- closeOnBlur: true,
2016
- // defaultKeymap: false,
2017
- icons: false,
2018
- override: [
2019
- (context) => {
2020
- const match = context.matchBefore(/@(\w+)?/);
2021
- if (!match || match.from === match.to && !context.explicit) {
2022
- return null;
2023
- }
2024
- console.log(match);
2025
- return {
2026
- from: match.from,
2027
- options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
2028
- label: `@${value}`
2029
- }))
2030
- };
2031
- }
2032
- ]
2033
- });
1700
+ // packages/ui/react-ui-editor/src/extensions/markdown/code.ts
1701
+ import { syntaxTree } from "@codemirror/language";
1702
+ import { RangeSetBuilder } from "@codemirror/state";
1703
+ import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
1704
+ import { mx as mx2 } from "@dxos/react-ui-theme";
1705
+ var styles3 = EditorView8.baseTheme({
1706
+ "& .cm-code": {
1707
+ fontFamily: getToken("fontFamily.mono", []).join(",")
1708
+ },
1709
+ "& .cm-codeblock": {
1710
+ width: "100%",
1711
+ paddingInline: "1rem !important",
1712
+ position: "relative",
1713
+ "&::after": {
1714
+ content: '""',
1715
+ position: "absolute",
1716
+ inset: 0
1717
+ }
1718
+ },
1719
+ "&light .cm-codeblock": {
1720
+ "&::after": {
1721
+ background: getToken("extend.semanticColors.input.light"),
1722
+ mixBlendMode: "darken"
1723
+ }
1724
+ },
1725
+ "&dark .cm-codeblock": {
1726
+ "&::after": {
1727
+ background: getToken("extend.semanticColors.input.dark"),
1728
+ mixBlendMode: "lighten"
1729
+ }
1730
+ },
1731
+ "& .cm-codeblock-first": {
1732
+ display: "inline-block",
1733
+ "&::after": {
1734
+ borderTopLeftRadius: ".5rem",
1735
+ borderTopRightRadius: ".5rem"
1736
+ }
1737
+ },
1738
+ "& .cm-codeblock-last": {
1739
+ display: "inline-block",
1740
+ "&::after": {
1741
+ borderBottomLeftRadius: ".5rem",
1742
+ borderBottomRightRadius: ".5rem"
1743
+ }
1744
+ }
1745
+ });
1746
+ var getLineRange = (lines, from, to) => {
1747
+ const start = lines.findIndex((line) => line.from >= from);
1748
+ const end = lines.findIndex((line) => line.to >= to);
1749
+ return [
1750
+ start,
1751
+ end
1752
+ ];
2034
1753
  };
2035
-
2036
- // packages/ui/react-ui-editor/src/extensions/outliner.ts
2037
- var outliner = (options = {}) => {
2038
- return [];
1754
+ var LineWidget = class extends WidgetType2 {
1755
+ constructor(_className) {
1756
+ super();
1757
+ this._className = _className;
1758
+ }
1759
+ toDOM() {
1760
+ const el = document.createElement("span");
1761
+ el.innerHTML = "&nbsp;";
1762
+ el.className = mx2("cm-code cm-codeblock", this._className);
1763
+ return el;
1764
+ }
1765
+ };
1766
+ var top = new LineWidget("cm-codeblock-first");
1767
+ var bottom = new LineWidget("cm-codeblock-last");
1768
+ var buildDecorations = (view) => {
1769
+ const builder = new RangeSetBuilder();
1770
+ const { state } = view;
1771
+ const blocks = view.viewportLineBlocks;
1772
+ const cursor = state.selection.main.head;
1773
+ for (const { from, to } of view.visibleRanges) {
1774
+ syntaxTree(state).iterate({
1775
+ enter: (node) => {
1776
+ if (node.name === "FencedCode") {
1777
+ const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
1778
+ const range = getLineRange(blocks, node.from, node.to);
1779
+ for (let i = range[0]; i <= range[1]; i++) {
1780
+ const block = blocks[i];
1781
+ if (!edit && (i === range[0] || i === range[1])) {
1782
+ builder.add(block.from, block.to, Decoration3.replace({
1783
+ widget: i === range[0] ? top : bottom
1784
+ }));
1785
+ } else {
1786
+ builder.add(block.from, block.from, Decoration3.line({
1787
+ class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1788
+ }));
1789
+ }
1790
+ }
1791
+ }
1792
+ },
1793
+ from,
1794
+ to
1795
+ });
1796
+ }
1797
+ return builder.finish();
1798
+ };
1799
+ var code2 = () => {
1800
+ return [
1801
+ ViewPlugin3.fromClass(class {
1802
+ constructor(view) {
1803
+ this.decorations = buildDecorations(view);
1804
+ }
1805
+ update(update2) {
1806
+ this.decorations = buildDecorations(update2.view);
1807
+ }
1808
+ }, {
1809
+ decorations: (value) => value.decorations
1810
+ }),
1811
+ styles3
1812
+ ];
1813
+ };
1814
+
1815
+ // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
1816
+ import { snippet } from "@codemirror/autocomplete";
1817
+ import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1818
+ import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1819
+ import { Decoration as Decoration4, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1820
+ var setHeading = (level) => (view) => {
1821
+ const { selection: { ranges }, doc } = view.state;
1822
+ const changes = [];
1823
+ for (const range of ranges) {
1824
+ const { number } = doc.lineAt(range.anchor);
1825
+ const { from, to } = doc.line(number);
1826
+ const line = doc.sliceString(from, to);
1827
+ const [_, marks, spaces] = line.match(/(#+)(\s+)/) ?? [];
1828
+ const current = marks?.length ?? 0;
1829
+ if (level !== current) {
1830
+ changes.push({
1831
+ from,
1832
+ to: from + current + (spaces?.length ?? 0),
1833
+ insert: "#".repeat(level) + (level > 0 ? " " : "")
1834
+ });
1835
+ }
1836
+ }
1837
+ if (changes.length) {
1838
+ view.dispatch({
1839
+ changes
1840
+ });
1841
+ }
1842
+ return true;
1843
+ };
1844
+ var toggleStyle = (mark2) => (view) => {
1845
+ const { ranges } = view.state.selection;
1846
+ for (const range of ranges) {
1847
+ if (range.from === range.to) {
1848
+ return false;
1849
+ }
1850
+ view.dispatch({
1851
+ changes: [
1852
+ {
1853
+ from: range.from,
1854
+ insert: mark2
1855
+ },
1856
+ {
1857
+ from: range.to,
1858
+ insert: mark2
1859
+ }
1860
+ ]
1861
+ });
1862
+ }
1863
+ return true;
1864
+ };
1865
+ var snippets = {
1866
+ codeblock: snippet([
1867
+ "```#{lang}",
1868
+ " #{}",
1869
+ "```"
1870
+ ].join("\n")),
1871
+ table: snippet([
1872
+ "| #{col1} | #{col2} |",
1873
+ "| ---- | ---- |",
1874
+ "| #{val1} | #{val2} |",
1875
+ "| #{val3} | #{val4} |"
1876
+ ].join("\n"))
1877
+ };
1878
+ var insertCodeblock = (view) => {
1879
+ const { selection: { main }, doc } = view.state;
1880
+ const { number } = doc.lineAt(main.anchor);
1881
+ const { from } = doc.line(number);
1882
+ snippets.codeblock(view, null, from, from);
1883
+ };
1884
+ var insertTable = (view) => {
1885
+ const { selection: { main }, doc } = view.state;
1886
+ const { number } = doc.lineAt(main.anchor);
1887
+ const { from } = doc.line(number);
1888
+ snippets.table(view, null, from, from);
1889
+ };
1890
+ var toggleBold = toggleStyle("**");
1891
+ var toggleItalic = toggleStyle("_");
1892
+ var toggleStrikethrough = toggleStyle("~~");
1893
+ var toggleList = (view) => {
1894
+ };
1895
+ var formatting = (options = {}) => {
1896
+ return [
1897
+ keymap5.of([
1898
+ {
1899
+ key: "meta-b",
1900
+ run: toggleBold
1901
+ }
1902
+ ]),
1903
+ styling()
1904
+ ];
1905
+ };
1906
+ var styling = () => {
1907
+ const buildDecorations7 = (view) => {
1908
+ const builder = new RangeSetBuilder2();
1909
+ const { state } = view;
1910
+ const cursor = state.selection.main.head;
1911
+ const replace = (node, marks) => {
1912
+ if (cursor <= node.from || cursor >= node.to) {
1913
+ for (const mark2 of marks) {
1914
+ builder.add(mark2.from, mark2.to, Decoration4.replace({}));
1915
+ }
1916
+ }
1917
+ };
1918
+ for (const { from, to } of view.visibleRanges) {
1919
+ syntaxTree2(state).iterate({
1920
+ enter: (node) => {
1921
+ switch (node.name) {
1922
+ case "Emphasis":
1923
+ case "StrongEmphasis": {
1924
+ const marks = node.node.getChildren("EmphasisMark");
1925
+ replace(node, marks);
1926
+ break;
1927
+ }
1928
+ case "Strikethrough": {
1929
+ const marks = node.node.getChildren("StrikethroughMark");
1930
+ replace(node, marks);
1931
+ break;
1932
+ }
1933
+ }
1934
+ },
1935
+ from,
1936
+ to
1937
+ });
1938
+ }
1939
+ return builder.finish();
1940
+ };
1941
+ return [
1942
+ ViewPlugin4.fromClass(class {
1943
+ constructor(view) {
1944
+ this.decorations = buildDecorations7(view);
1945
+ }
1946
+ update(update2) {
1947
+ this.decorations = buildDecorations7(update2.view);
1948
+ }
1949
+ }, {
1950
+ decorations: (value) => value.decorations
1951
+ })
1952
+ ];
1953
+ };
1954
+
1955
+ // packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
1956
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1957
+ import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
1958
+ import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
1959
+ var buildDecorations2 = (view) => {
1960
+ const builder = new RangeSetBuilder3();
1961
+ const { state } = view;
1962
+ const cursor = state.selection.main.head;
1963
+ for (const { from, to } of view.visibleRanges) {
1964
+ syntaxTree3(state).iterate({
1965
+ enter: (node) => {
1966
+ switch (node.name) {
1967
+ case "ATXHeading1":
1968
+ case "ATXHeading2":
1969
+ case "ATXHeading3":
1970
+ case "ATXHeading4":
1971
+ case "ATXHeading5":
1972
+ case "ATXHeading6": {
1973
+ const mark2 = node.node.getChild("HeaderMark");
1974
+ if (mark2) {
1975
+ if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
1976
+ builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
1977
+ }
1978
+ }
1979
+ }
1980
+ }
1981
+ },
1982
+ from,
1983
+ to
1984
+ });
1985
+ }
1986
+ return builder.finish();
1987
+ };
1988
+ var heading2 = () => {
1989
+ return [
1990
+ ViewPlugin5.fromClass(class {
1991
+ constructor(view) {
1992
+ this.decorations = buildDecorations2(view);
1993
+ }
1994
+ update(update2) {
1995
+ this.decorations = buildDecorations2(update2.view);
1996
+ }
1997
+ }, {
1998
+ decorations: (value) => value.decorations
1999
+ })
2000
+ ];
2001
+ };
2002
+
2003
+ // packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
2004
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2005
+ import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
2006
+ import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
2007
+ var styles4 = EditorView9.baseTheme({
2008
+ "& .cm-hr": {
2009
+ // Note that block-level decorations should not have vertical margins,
2010
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2011
+ }
2012
+ });
2013
+ var HorizontalRuleWidget = class extends WidgetType3 {
2014
+ toDOM() {
2015
+ const el = document.createElement("div");
2016
+ el.className = "cm-hr";
2017
+ return el;
2018
+ }
2019
+ };
2020
+ var decoration = Decoration6.replace({
2021
+ widget: new HorizontalRuleWidget()
2022
+ });
2023
+ var buildDecorations3 = (view) => {
2024
+ const builder = new RangeSetBuilder4();
2025
+ const { state } = view;
2026
+ const cursor = state.selection.main.head;
2027
+ for (const { from, to } of view.visibleRanges) {
2028
+ syntaxTree4(state).iterate({
2029
+ enter: (node) => {
2030
+ if (node.name === "HorizontalRule") {
2031
+ if (cursor <= node.from || cursor >= node.to) {
2032
+ builder.add(node.from, node.to, decoration);
2033
+ }
2034
+ }
2035
+ },
2036
+ from,
2037
+ to
2038
+ });
2039
+ }
2040
+ return builder.finish();
2041
+ };
2042
+ var hr = () => {
2043
+ return [
2044
+ ViewPlugin6.fromClass(class {
2045
+ constructor(view) {
2046
+ this.decorations = buildDecorations3(view);
2047
+ }
2048
+ update(update2) {
2049
+ this.decorations = buildDecorations3(update2.view);
2050
+ }
2051
+ }, {
2052
+ decorations: (value) => value.decorations
2053
+ }),
2054
+ styles4
2055
+ ];
2056
+ };
2057
+
2058
+ // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
2059
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2060
+ import { StateField as StateField3 } from "@codemirror/state";
2061
+ import { Decoration as Decoration7, EditorView as EditorView10, WidgetType as WidgetType4 } from "@codemirror/view";
2062
+ var image = (options = {}) => {
2063
+ return StateField3.define({
2064
+ create: (state) => {
2065
+ return Decoration7.set(buildDecorations4(0, state.doc.length, state));
2066
+ },
2067
+ update: (value, tr) => {
2068
+ if (!tr.docChanged && !tr.selection) {
2069
+ return value;
2070
+ }
2071
+ const cursor = tr.state.selection.main.head;
2072
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
2073
+ let from = Math.min(cursor, oldCursor);
2074
+ let to = Math.max(cursor, oldCursor);
2075
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
2076
+ from = Math.min(from, fromB);
2077
+ to = Math.max(to, toB);
2078
+ });
2079
+ from = tr.state.doc.lineAt(from).from;
2080
+ to = tr.state.doc.lineAt(to).to;
2081
+ return value.map(tr.changes).update({
2082
+ filterFrom: from,
2083
+ filterTo: to,
2084
+ filter: () => false,
2085
+ add: buildDecorations4(from, to, tr.state)
2086
+ });
2087
+ },
2088
+ provide: (field) => EditorView10.decorations.from(field)
2089
+ });
2090
+ };
2091
+ var buildDecorations4 = (from, to, state) => {
2092
+ const decorations = [];
2093
+ const cursor = state.selection.main.head;
2094
+ syntaxTree5(state).iterate({
2095
+ enter: (node) => {
2096
+ if (node.name === "Image") {
2097
+ const urlNode = node.node.getChild("URL");
2098
+ if (urlNode) {
2099
+ const hide = state.readOnly || cursor < node.from || cursor > node.to;
2100
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
2101
+ decorations.push(Decoration7.replace({
2102
+ block: true,
2103
+ widget: new ImageWidget(url)
2104
+ }).range(hide ? node.from : node.to, node.to));
2105
+ }
2106
+ }
2107
+ },
2108
+ from,
2109
+ to
2110
+ });
2111
+ return decorations;
2112
+ };
2113
+ var ImageWidget = class extends WidgetType4 {
2114
+ constructor(_url) {
2115
+ super();
2116
+ this._url = _url;
2117
+ }
2118
+ eq(other) {
2119
+ return this._url === other._url;
2120
+ }
2121
+ toDOM(view) {
2122
+ const img = document.createElement("img");
2123
+ img.setAttribute("src", this._url);
2124
+ img.setAttribute("class", "cm-image");
2125
+ img.onload = () => img.classList.add("cm-loaded-image");
2126
+ return img;
2127
+ }
2128
+ };
2129
+
2130
+ // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
2131
+ import { syntaxTree as syntaxTree6 } from "@codemirror/language";
2132
+ import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
2133
+ import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
2134
+ import { tooltipContent } from "@dxos/react-ui-theme";
2135
+ var link = (options = {}) => {
2136
+ const extensions = [
2137
+ ViewPlugin7.fromClass(class {
2138
+ constructor(view) {
2139
+ this.decorations = buildDecorations5(view, options);
2140
+ }
2141
+ update(update2) {
2142
+ if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2143
+ this.decorations = buildDecorations5(update2.view, options);
2144
+ }
2145
+ }
2146
+ }, {
2147
+ decorations: (value) => value.decorations
2148
+ })
2149
+ ];
2150
+ if (options.onHover) {
2151
+ extensions.push(
2152
+ // https://codemirror.net/examples/tooltip
2153
+ // https://codemirror.net/docs/ref/#view.hoverTooltip
2154
+ // https://github.com/codemirror/view/blob/main/src/tooltip.ts
2155
+ hoverTooltip2((view, pos, side) => {
2156
+ const syntax = syntaxTree6(view.state).resolveInner(pos, side);
2157
+ let link2 = null;
2158
+ for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
2159
+ link2 = node.name === "Link" ? node : null;
2160
+ }
2161
+ const url = link2 && link2.getChild("URL");
2162
+ if (!url || !link2) {
2163
+ return null;
2164
+ }
2165
+ const urlText = view.state.sliceDoc(url.from, url.to);
2166
+ return {
2167
+ pos: link2.from,
2168
+ end: link2.to,
2169
+ above: true,
2170
+ create: () => {
2171
+ const el = document.createElement("div");
2172
+ el.className = tooltipContent({}, "pli-2 plb-1");
2173
+ options.onHover(el, urlText);
2174
+ return {
2175
+ dom: el,
2176
+ offset: {
2177
+ x: 0,
2178
+ y: 4
2179
+ }
2180
+ };
2181
+ }
2182
+ };
2183
+ })
2184
+ );
2185
+ }
2186
+ return extensions;
2187
+ };
2188
+ var LinkButton = class extends WidgetType5 {
2189
+ constructor(_url, _onAttach) {
2190
+ super();
2191
+ this._url = _url;
2192
+ this._onAttach = _onAttach;
2193
+ }
2194
+ eq(other) {
2195
+ return this._url === other._url;
2196
+ }
2197
+ toDOM(view) {
2198
+ const el = document.createElement("span");
2199
+ this._onAttach(el, this._url);
2200
+ return el;
2201
+ }
2202
+ };
2203
+ var LinkText = class extends WidgetType5 {
2204
+ constructor(_text, _url) {
2205
+ super();
2206
+ this._text = _text;
2207
+ this._url = _url;
2208
+ }
2209
+ eq(other) {
2210
+ return this._url === other._url;
2211
+ }
2212
+ toDOM(view) {
2213
+ const link2 = document.createElement("a");
2214
+ link2.setAttribute("class", "cm-link");
2215
+ link2.textContent = this._text;
2216
+ if (this._url) {
2217
+ link2.setAttribute("rel", "noreferrer");
2218
+ link2.setAttribute("target", "_blank");
2219
+ link2.href = this._url;
2220
+ } else {
2221
+ link2.onclick = () => {
2222
+ view.dispatch({
2223
+ selection: {
2224
+ anchor: view.posAtDOM(link2)
2225
+ }
2226
+ });
2227
+ };
2228
+ }
2229
+ return link2;
2230
+ }
2231
+ };
2232
+ var buildDecorations5 = (view, options) => {
2233
+ const builder = new RangeSetBuilder5();
2234
+ const { state } = view;
2235
+ const cursor = state.selection.main.head;
2236
+ for (const { from, to } of view.visibleRanges) {
2237
+ syntaxTree6(state).iterate({
2238
+ enter: (node) => {
2239
+ if (node.name === "Link") {
2240
+ const marks = node.node.getChildren("LinkMark");
2241
+ const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
2242
+ const urlNode = node.node.getChild("URL");
2243
+ const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
2244
+ if (!url) {
2245
+ return false;
2246
+ }
2247
+ if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
2248
+ builder.add(node.from, node.to, Decoration8.replace({
2249
+ widget: new LinkText(text, options.link ? url : void 0)
2250
+ }));
2251
+ }
2252
+ if (options.onRender) {
2253
+ builder.add(node.to, node.to, Decoration8.replace({
2254
+ widget: new LinkButton(url, options.onRender)
2255
+ }));
2256
+ }
2257
+ return false;
2258
+ }
2259
+ },
2260
+ from,
2261
+ to
2262
+ });
2263
+ }
2264
+ return builder.finish();
2039
2265
  };
2040
2266
 
2041
- // packages/ui/react-ui-editor/src/extensions/table.ts
2042
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2043
- import { RangeSetBuilder as RangeSetBuilder3, StateField as StateField4 } from "@codemirror/state";
2044
- import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
2267
+ // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
2268
+ import { syntaxTree as syntaxTree7 } from "@codemirror/language";
2269
+ import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
2270
+ import { Decoration as Decoration9, EditorView as EditorView11, WidgetType as WidgetType6 } from "@codemirror/view";
2045
2271
  var table = (options = {}) => {
2046
2272
  return StateField4.define({
2047
2273
  create: (state) => update(state, options),
@@ -2050,7 +2276,7 @@ var table = (options = {}) => {
2050
2276
  });
2051
2277
  };
2052
2278
  var update = (state, options) => {
2053
- const builder = new RangeSetBuilder3();
2279
+ const builder = new RangeSetBuilder6();
2054
2280
  const cursor = state.selection.main.head;
2055
2281
  const tables = [];
2056
2282
  const getTable = () => tables[tables.length - 1];
@@ -2058,7 +2284,7 @@ var update = (state, options) => {
2058
2284
  const table2 = getTable();
2059
2285
  return table2.rows?.[table2.rows.length - 1];
2060
2286
  };
2061
- syntaxTree4(state).iterate({
2287
+ syntaxTree7(state).iterate({
2062
2288
  enter: (node) => {
2063
2289
  switch (node.name) {
2064
2290
  case "Table": {
@@ -2090,16 +2316,16 @@ var update = (state, options) => {
2090
2316
  });
2091
2317
  tables.forEach((table2) => {
2092
2318
  const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
2093
- hide && builder.add(table2.from, table2.to, Decoration7.replace({
2319
+ hide && builder.add(table2.from, table2.to, Decoration9.replace({
2094
2320
  widget: new TableWidget(table2)
2095
2321
  }));
2096
- builder.add(table2.from, table2.to, Decoration7.mark({
2322
+ builder.add(table2.from, table2.to, Decoration9.mark({
2097
2323
  class: "cm-table"
2098
2324
  }));
2099
2325
  });
2100
2326
  return builder.finish();
2101
2327
  };
2102
- var TableWidget = class extends WidgetType5 {
2328
+ var TableWidget = class extends WidgetType6 {
2103
2329
  constructor(_table) {
2104
2330
  super();
2105
2331
  this._table = _table;
@@ -2136,10 +2362,10 @@ var TableWidget = class extends WidgetType5 {
2136
2362
  }
2137
2363
  };
2138
2364
 
2139
- // packages/ui/react-ui-editor/src/extensions/tasklist.ts
2140
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2141
- import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
2142
- import { EditorView as EditorView12, Decoration as Decoration8, WidgetType as WidgetType6, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
2365
+ // packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
2366
+ import { syntaxTree as syntaxTree8 } from "@codemirror/language";
2367
+ import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
2368
+ import { EditorView as EditorView12, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
2143
2369
  var styles5 = EditorView12.baseTheme({
2144
2370
  "& .cm-task": {
2145
2371
  color: getToken("extend.colors.blue.500")
@@ -2149,7 +2375,7 @@ var styles5 = EditorView12.baseTheme({
2149
2375
  marginRight: "4px"
2150
2376
  }
2151
2377
  });
2152
- var CheckboxWidget = class extends WidgetType6 {
2378
+ var CheckboxWidget = class extends WidgetType7 {
2153
2379
  constructor(_checked) {
2154
2380
  super();
2155
2381
  this._checked = _checked;
@@ -2186,23 +2412,23 @@ var CheckboxWidget = class extends WidgetType6 {
2186
2412
  return false;
2187
2413
  }
2188
2414
  };
2189
- var checkedDecoration = Decoration8.replace({
2415
+ var checkedDecoration = Decoration10.replace({
2190
2416
  widget: new CheckboxWidget(true)
2191
2417
  });
2192
- var uncheckedDecoration = Decoration8.replace({
2418
+ var uncheckedDecoration = Decoration10.replace({
2193
2419
  widget: new CheckboxWidget(false)
2194
2420
  });
2195
- var buildDecorations4 = (view) => {
2196
- const builder = new RangeSetBuilder4();
2421
+ var buildDecorations6 = (view) => {
2422
+ const builder = new RangeSetBuilder7();
2197
2423
  const { state } = view;
2198
2424
  const cursor = state.selection.main.head;
2199
2425
  for (const { from, to } of view.visibleRanges) {
2200
- syntaxTree5(state).iterate({
2426
+ syntaxTree8(state).iterate({
2201
2427
  enter: (node) => {
2202
2428
  if (node.name === "TaskMarker") {
2203
2429
  if (cursor < node.from || cursor > node.to) {
2204
2430
  const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2205
- builder.add(node.from - 2, node.from - 1, Decoration8.mark({
2431
+ builder.add(node.from - 2, node.from - 1, Decoration10.mark({
2206
2432
  class: "cm-task"
2207
2433
  }));
2208
2434
  builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
@@ -2217,24 +2443,58 @@ var buildDecorations4 = (view) => {
2217
2443
  };
2218
2444
  var tasklist = (options = {}) => {
2219
2445
  return [
2220
- ViewPlugin5.fromClass(class {
2446
+ ViewPlugin8.fromClass(class {
2221
2447
  constructor(view) {
2222
- this.decorations = buildDecorations4(view);
2448
+ this.decorations = buildDecorations6(view);
2223
2449
  }
2224
2450
  update(update2) {
2225
2451
  if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2226
- this.decorations = buildDecorations4(update2.view);
2452
+ this.decorations = buildDecorations6(update2.view);
2227
2453
  }
2228
2454
  }
2229
2455
  }, {
2230
- decorations: (v) => v.decorations
2456
+ decorations: (value) => value.decorations
2231
2457
  }),
2232
2458
  styles5
2233
2459
  ];
2234
2460
  };
2235
2461
 
2462
+ // packages/ui/react-ui-editor/src/extensions/mention.ts
2463
+ import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
2464
+ var mention = ({ onSearch }) => {
2465
+ return autocompletion2({
2466
+ // TODO(burdon): Not working.
2467
+ activateOnTyping: true,
2468
+ // activateOnTypingDelay: 100,
2469
+ // selectOnOpen: true,
2470
+ closeOnBlur: false,
2471
+ // defaultKeymap: false,
2472
+ icons: false,
2473
+ override: [
2474
+ (context) => {
2475
+ console.log(context);
2476
+ const match = context.matchBefore(/@(\w+)?/);
2477
+ if (!match || match.from === match.to && !context.explicit) {
2478
+ return null;
2479
+ }
2480
+ return {
2481
+ from: match.from,
2482
+ options: onSearch(match.text.slice(1).toLowerCase()).map((value) => ({
2483
+ label: `@${value}`
2484
+ }))
2485
+ };
2486
+ }
2487
+ ]
2488
+ });
2489
+ };
2490
+
2491
+ // packages/ui/react-ui-editor/src/extensions/outliner.ts
2492
+ var outliner = (options = {}) => {
2493
+ return [];
2494
+ };
2495
+
2236
2496
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
2237
- import { keymap as keymap5 } from "@codemirror/view";
2497
+ import { keymap as keymap6 } from "@codemirror/view";
2238
2498
  var defaultItems = [
2239
2499
  "hello world!",
2240
2500
  "this is a test.",
@@ -2244,7 +2504,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
2244
2504
  let t;
2245
2505
  let idx = 0;
2246
2506
  return [
2247
- keymap5.of([
2507
+ keymap6.of([
2248
2508
  {
2249
2509
  // Reset.
2250
2510
  key: "alt-meta-'",
@@ -2290,27 +2550,6 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
2290
2550
  ];
2291
2551
  };
2292
2552
 
2293
- // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2294
- import { yCollab } from "y-codemirror.next";
2295
-
2296
- // packages/ui/react-ui-editor/src/extensions/yjs/cursor.ts
2297
- import * as Y from "yjs";
2298
- import { arrayToString, stringToArray } from "@dxos/util";
2299
- var cursorConverter2 = (text) => ({
2300
- toCursor: (index, assoc) => {
2301
- return arrayToString(Y.encodeRelativePosition(Y.createRelativePositionFromTypeIndex(text, index, assoc)));
2302
- },
2303
- fromCursor: (cursor) => {
2304
- return Y.createAbsolutePositionFromRelativePosition(Y.decodeRelativePosition(stringToArray(cursor)), text.doc)?.index ?? 0;
2305
- }
2306
- });
2307
-
2308
- // packages/ui/react-ui-editor/src/extensions/yjs/yjs.ts
2309
- var yjs = (content, awareness2) => [
2310
- Cursor.converter.of(cursorConverter2(content)),
2311
- yCollab(content, awareness2)
2312
- ];
2313
-
2314
2553
  // packages/ui/react-ui-editor/src/themes/default.ts
2315
2554
  import get3 from "lodash.get";
2316
2555
  var defaultTheme = {
@@ -2342,8 +2581,9 @@ var defaultTheme = {
2342
2581
  outline: "none"
2343
2582
  },
2344
2583
  ".cm-scroller": {
2345
- overflow: "visible",
2346
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
2584
+ // overflow: 'visible',
2585
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
2586
+ lineHeight: 1.4
2347
2587
  },
2348
2588
  ".cm-content": {
2349
2589
  padding: 0,
@@ -2367,8 +2607,11 @@ var defaultTheme = {
2367
2607
  "&dark .cm-cursor, &dark .cm-dropCursor": {
2368
2608
  borderLeft: "2px solid white"
2369
2609
  },
2370
- ".cm-placeholder": {
2371
- fontWeight: 100
2610
+ "&light .cm-placeholder": {
2611
+ color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
2612
+ },
2613
+ "&dark .cm-placeholder": {
2614
+ color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
2372
2615
  },
2373
2616
  //
2374
2617
  // line
@@ -2377,7 +2620,7 @@ var defaultTheme = {
2377
2620
  paddingInline: 0
2378
2621
  },
2379
2622
  ".cm-activeLine": {
2380
- background: "inherit"
2623
+ background: "transparent"
2381
2624
  },
2382
2625
  //
2383
2626
  // Selection
@@ -2548,31 +2791,35 @@ var codeTheme = {
2548
2791
  };
2549
2792
 
2550
2793
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
2551
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
2794
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
2552
2795
  var EditorModes = [
2553
2796
  "default",
2554
2797
  "vim"
2555
2798
  ];
2556
- var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [] }, forwardedRef) => {
2557
- const tabsterDOMAttribute = useFocusableGroup({
2558
- tabBehavior: "limited"
2559
- });
2560
- const { themeMode } = useThemeContext2();
2799
+ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
2800
+ const { themeMode } = useThemeContext();
2561
2801
  const rootRef = useRef(null);
2562
2802
  const [view, setView] = useState(null);
2563
2803
  useImperativeHandle(forwardedRef, () => view, [
2564
2804
  view
2565
2805
  ]);
2566
- useEffect3(() => {
2567
- if (autofocus) {
2806
+ useEffect2(() => {
2807
+ if (autoFocus && !view?.hasFocus) {
2808
+ if (view?.state.selection.main?.from === 0) {
2809
+ const { to } = view.state.doc.lineAt(0);
2810
+ view?.dispatch({
2811
+ selection: {
2812
+ anchor: to
2813
+ }
2814
+ });
2815
+ }
2568
2816
  view?.focus();
2569
2817
  }
2570
2818
  }, [
2571
2819
  view,
2572
- autofocus
2820
+ autoFocus
2573
2821
  ]);
2574
- useAwareness(model);
2575
- useEffect3(() => {
2822
+ useEffect2(() => {
2576
2823
  if (!model || !rootRef.current) {
2577
2824
  return;
2578
2825
  }
@@ -2583,8 +2830,8 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2583
2830
  // TODO(burdon): Doesn't catch errors in keymap functions.
2584
2831
  EditorView13.exceptionSink.of((err) => {
2585
2832
  log2.catch(err, void 0, {
2586
- F: __dxlog_file4,
2587
- L: 114,
2833
+ F: __dxlog_file3,
2834
+ L: 134,
2588
2835
  S: void 0,
2589
2836
  C: (f, a) => f(...a)
2590
2837
  });
@@ -2601,15 +2848,16 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2601
2848
  class: slots.content?.className ?? ""
2602
2849
  }),
2603
2850
  // State.
2851
+ EditorView13.editable.of(!readonly),
2604
2852
  EditorState2.readOnly.of(!!readonly),
2605
2853
  // Storage and replication.
2606
2854
  // NOTE: This must come before user extensions.
2607
2855
  model.extension,
2608
- // TODO(burdon): Factor out (requires special handling for Escape/focus).
2856
+ // TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
2609
2857
  editorMode === "vim" && vim(),
2610
2858
  // Custom.
2611
2859
  ...extensions
2612
- ].filter(Boolean)
2860
+ ].filter(isNotFalsy3)
2613
2861
  });
2614
2862
  const newView = new EditorView13({
2615
2863
  state,
@@ -2618,11 +2866,10 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2618
2866
  // NOTE: Uncomment to debug/monitor all transactions.
2619
2867
  // https://codemirror.net/docs/ref/#view.EditorView.dispatch
2620
2868
  dispatchTransactions: (trs, view2) => {
2621
- view2.update(trs);
2622
- const debug = false;
2623
2869
  if (debug) {
2624
2870
  logChanges(trs);
2625
2871
  }
2872
+ view2.update(trs);
2626
2873
  }
2627
2874
  });
2628
2875
  view?.destroy();
@@ -2647,7 +2894,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2647
2894
  }
2648
2895
  case "Escape": {
2649
2896
  if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
2650
- rootRef.current?.focus();
2897
+ view?.focus();
2651
2898
  }
2652
2899
  break;
2653
2900
  }
@@ -2660,23 +2907,23 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autofocus, s
2660
2907
  key: model.id,
2661
2908
  role: "none",
2662
2909
  tabIndex: 0,
2663
- onKeyUp: handleKeyUp,
2664
2910
  ...slots.root,
2665
- ...editorMode !== "vim" && tabsterDOMAttribute,
2911
+ // {...(editorMode !== 'vim' && tabsterDOMAttribute)}
2912
+ onKeyUp: handleKeyUp,
2666
2913
  ref: rootRef
2667
2914
  });
2668
2915
  });
2669
- var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, multiline, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
2670
- const { themeMode } = useThemeContext2();
2916
+ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, lineWrapping, theme = textTheme, slots, extensions = [], ...props }, forwardedRef) => {
2917
+ const { themeMode } = useThemeContext();
2671
2918
  const updatedSlots = defaultsDeep2({}, slots, defaultTextSlots);
2672
2919
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2673
2920
  ref: forwardedRef,
2674
2921
  readonly,
2675
2922
  extensions: [
2676
- basicBundle({
2923
+ createBasicBundle({
2677
2924
  themeMode,
2678
2925
  placeholder: placeholder3,
2679
- multiline
2926
+ lineWrapping
2680
2927
  }),
2681
2928
  ...extensions
2682
2929
  ],
@@ -2686,15 +2933,14 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
2686
2933
  });
2687
2934
  });
2688
2935
  var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholder3, theme = markdownTheme, slots, extensions = [], ...props }, forwardedRef) => {
2689
- const { themeMode } = useThemeContext2();
2936
+ const { themeMode } = useThemeContext();
2690
2937
  const updatedSlots = defaultsDeep2({}, slots, defaultMarkdownSlots);
2691
2938
  return /* @__PURE__ */ React.createElement(BaseTextEditor, {
2692
2939
  ref: forwardedRef,
2693
2940
  readonly,
2694
2941
  extensions: [
2695
- markdownBundle({
2942
+ createMarkdownExtensions({
2696
2943
  themeMode,
2697
- readonly,
2698
2944
  placeholder: placeholder3
2699
2945
  }),
2700
2946
  ...extensions
@@ -2706,11 +2952,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
2706
2952
  });
2707
2953
  var defaultSlots = {
2708
2954
  root: {
2709
- // TODO(burdon): Add focusRing by default/as property?
2710
- className: mx3("flex flex-col grow overflow-y-auto", inputSurface)
2955
+ className: mx3("grow", focusRing)
2711
2956
  },
2712
2957
  editor: {
2713
- className: "h-full p-2"
2958
+ className: "bs-full"
2714
2959
  }
2715
2960
  };
2716
2961
  var defaultTextSlots = {
@@ -2720,22 +2965,178 @@ var defaultMarkdownSlots = {
2720
2965
  ...defaultSlots
2721
2966
  };
2722
2967
 
2723
- // packages/ui/react-ui-editor/src/hooks/automerge.ts
2724
- import get4 from "lodash.get";
2725
- import { getRawDoc } from "@dxos/echo-schema";
2726
- import { isNotNullOrUndefined } from "@dxos/util";
2968
+ // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
2969
+ import { At, CaretRight, ChatText, Code, Image, Link, ListBullets, ListChecks, ListNumbers, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
2970
+ import { createContext } from "@radix-ui/react-context";
2971
+ import React2 from "react";
2972
+ import { Button, DensityProvider, Select } from "@dxos/react-ui";
2973
+ import { getSize } from "@dxos/react-ui-theme";
2974
+ var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
2975
+ var ToolbarRoot = ({ children, onAction }) => {
2976
+ return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
2977
+ onAction
2978
+ }, /* @__PURE__ */ React2.createElement(DensityProvider, {
2979
+ density: "fine"
2980
+ }, /* @__PURE__ */ React2.createElement("div", {
2981
+ role: "toolbar",
2982
+ className: "flex w-full shrink-0 p-2 gap-4 items-center whitespace-nowrap overflow-hidden"
2983
+ }, children)));
2984
+ };
2985
+ var ToolbarButton = ({ Icon, onClick, title }) => {
2986
+ const { onAction } = useToolbarContext("ToolbarButton");
2987
+ const handleClick = () => {
2988
+ const action = onClick();
2989
+ if (action) {
2990
+ onAction?.(action);
2991
+ }
2992
+ };
2993
+ return /* @__PURE__ */ React2.createElement(Button, {
2994
+ variant: "ghost",
2995
+ classNames: "p-2",
2996
+ onClick: handleClick,
2997
+ title
2998
+ }, /* @__PURE__ */ React2.createElement(Icon, {
2999
+ className: getSize(5)
3000
+ }));
3001
+ };
3002
+ var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
3003
+ className: "grow"
3004
+ });
3005
+ var MarkdownHeading = () => {
3006
+ const { onAction } = useToolbarContext("MarkdownFormatting");
3007
+ return /* @__PURE__ */ React2.createElement(Select.Root, {
3008
+ defaultValue: "0",
3009
+ onValueChange: (value) => onAction?.({
3010
+ type: "heading",
3011
+ data: parseInt(value)
3012
+ })
3013
+ }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, {
3014
+ classNames: "w-[8rem]"
3015
+ }), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
3016
+ value: "0"
3017
+ }, "Paragraph"), [
3018
+ 1,
3019
+ 2,
3020
+ 3,
3021
+ 4,
3022
+ 5,
3023
+ 6
3024
+ ].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
3025
+ key: level,
3026
+ value: String(level)
3027
+ }, "Heading ", level))))));
3028
+ };
3029
+ var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
3030
+ role: "none"
3031
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3032
+ Icon: TextB,
3033
+ title: "Bold",
3034
+ onClick: () => ({
3035
+ type: "bold"
3036
+ })
3037
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3038
+ Icon: TextItalic,
3039
+ title: "Italic",
3040
+ onClick: () => ({
3041
+ type: "italic"
3042
+ })
3043
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3044
+ Icon: TextStrikethrough,
3045
+ title: "Strike-through",
3046
+ onClick: () => ({
3047
+ type: "strikethrough"
3048
+ })
3049
+ }));
3050
+ var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
3051
+ role: "none"
3052
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3053
+ Icon: ListBullets,
3054
+ title: "Bullet list",
3055
+ onClick: () => ({
3056
+ type: "list"
3057
+ })
3058
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3059
+ Icon: ListNumbers,
3060
+ title: "Numbered list",
3061
+ onClick: () => ({
3062
+ type: "list-ordered"
3063
+ })
3064
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3065
+ Icon: ListChecks,
3066
+ title: "Task list",
3067
+ onClick: () => ({
3068
+ type: "list-tasks"
3069
+ })
3070
+ }));
3071
+ var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
3072
+ role: "none"
3073
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3074
+ Icon: CaretRight,
3075
+ title: "Block quite",
3076
+ onClick: () => ({
3077
+ type: "blockquote"
3078
+ })
3079
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3080
+ Icon: Code,
3081
+ title: "Code block",
3082
+ onClick: () => ({
3083
+ type: "codeblock"
3084
+ })
3085
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3086
+ Icon: Table2,
3087
+ title: "Table",
3088
+ onClick: () => ({
3089
+ type: "table"
3090
+ })
3091
+ }));
3092
+ var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
3093
+ role: "none"
3094
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3095
+ Icon: Link,
3096
+ title: "Link",
3097
+ onClick: () => ({
3098
+ type: "link"
3099
+ })
3100
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3101
+ Icon: At,
3102
+ title: "Mention",
3103
+ onClick: () => ({
3104
+ type: "mention"
3105
+ })
3106
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3107
+ Icon: Image,
3108
+ title: "Image",
3109
+ onClick: () => ({
3110
+ type: "image"
3111
+ })
3112
+ }));
3113
+ var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
3114
+ var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
3115
+ Icon: ChatText,
3116
+ title: "Create comment",
3117
+ onClick: () => ({
3118
+ type: "comment"
3119
+ })
3120
+ });
3121
+ var Toolbar = {
3122
+ Root: ToolbarRoot,
3123
+ Button: ToolbarButton,
3124
+ Separator: ToolbarSeparator,
3125
+ Markdown: MarkdownStandard,
3126
+ Extended: MarkdownExtended
3127
+ };
2727
3128
 
2728
3129
  // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
2729
3130
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
2730
3131
  import { Context as Context2 } from "@dxos/context";
2731
- import { invariant as invariant3 } from "@dxos/invariant";
3132
+ import { invariant as invariant2 } from "@dxos/invariant";
2732
3133
  import { log as log3 } from "@dxos/log";
2733
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
3134
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
2734
3135
  var DEBOUNCE_INTERVAL = 100;
2735
3136
  var SpaceAwarenessProvider = class {
2736
3137
  constructor(params) {
2737
- this.remoteStateChange = new Event2();
2738
3138
  this._remoteStates = /* @__PURE__ */ new Map();
3139
+ this.remoteStateChange = new Event2();
2739
3140
  this._space = params.space;
2740
3141
  this._channel = params.channel;
2741
3142
  this._peerId = params.peerId;
@@ -2752,7 +3153,7 @@ var SpaceAwarenessProvider = class {
2752
3153
  await sleep(DEBOUNCE_INTERVAL);
2753
3154
  }
2754
3155
  });
2755
- const unsubscribe = this._space.listen(this._channel, (message) => {
3156
+ this._ctx.onDispose(this._space.listen(this._channel, (message) => {
2756
3157
  switch (message.payload.kind) {
2757
3158
  case "query": {
2758
3159
  this._handleQueryMessage();
@@ -2763,16 +3164,15 @@ var SpaceAwarenessProvider = class {
2763
3164
  break;
2764
3165
  }
2765
3166
  }
2766
- });
2767
- this._ctx.onDispose(unsubscribe);
3167
+ }));
2768
3168
  void this._space.postMessage(this._channel, {
2769
3169
  kind: "query"
2770
3170
  }).catch((err) => {
2771
3171
  log3.debug("failed to query awareness", {
2772
3172
  err
2773
3173
  }, {
2774
- F: __dxlog_file5,
2775
- L: 85,
3174
+ F: __dxlog_file4,
3175
+ L: 89,
2776
3176
  S: this,
2777
3177
  C: (f, a) => f(...a)
2778
3178
  });
@@ -2783,10 +3183,13 @@ var SpaceAwarenessProvider = class {
2783
3183
  this._ctx = void 0;
2784
3184
  this._postTask = void 0;
2785
3185
  }
3186
+ getRemoteStates() {
3187
+ return Array.from(this._remoteStates.values());
3188
+ }
2786
3189
  update(position) {
2787
- invariant3(this._postTask, void 0, {
2788
- F: __dxlog_file5,
2789
- L: 96,
3190
+ invariant2(this._postTask, void 0, {
3191
+ F: __dxlog_file4,
3192
+ L: 104,
2790
3193
  S: this,
2791
3194
  A: [
2792
3195
  "this._postTask",
@@ -2800,13 +3203,10 @@ var SpaceAwarenessProvider = class {
2800
3203
  };
2801
3204
  this._postTask.schedule();
2802
3205
  }
2803
- getRemoteStates() {
2804
- return Array.from(this._remoteStates.values());
2805
- }
2806
3206
  _handleQueryMessage() {
2807
- invariant3(this._postTask, void 0, {
2808
- F: __dxlog_file5,
2809
- L: 111,
3207
+ invariant2(this._postTask, void 0, {
3208
+ F: __dxlog_file4,
3209
+ L: 115,
2810
3210
  S: this,
2811
3211
  A: [
2812
3212
  "this._postTask",
@@ -2816,9 +3216,9 @@ var SpaceAwarenessProvider = class {
2816
3216
  this._postTask.schedule();
2817
3217
  }
2818
3218
  _handlePostMessage(message) {
2819
- invariant3(message.kind === "post", void 0, {
2820
- F: __dxlog_file5,
2821
- L: 116,
3219
+ invariant2(message.kind === "post", void 0, {
3220
+ F: __dxlog_file4,
3221
+ L: 120,
2822
3222
  S: this,
2823
3223
  A: [
2824
3224
  "message.kind === 'post'",
@@ -2837,182 +3237,177 @@ var modelState = StateField5.define({
2837
3237
  update: (model) => model
2838
3238
  });
2839
3239
 
2840
- // packages/ui/react-ui-editor/src/hooks/automerge.ts
2841
- var createAutomergeModel = ({ space, identity, text }) => {
2842
- const obj = text;
2843
- const doc = getRawDoc(obj, [
2844
- obj.field
2845
- ]);
2846
- const awarenessProvider = space && new SpaceAwarenessProvider({
2847
- space,
2848
- channel: `automerge.awareness.${obj.id}`,
2849
- info: {
2850
- displayName: identity?.profile?.displayName ?? "",
2851
- color: cursorColor.color,
2852
- lightColor: cursorColor.light
2853
- },
2854
- peerId: identity?.identityKey.toHex() ?? "Anonymous"
2855
- });
2856
- const model = {
2857
- id: obj.id,
2858
- content: doc,
2859
- text: () => get4(doc.handle.docSync(), doc.path),
2860
- // TODO(burdon): https://automerge.org/automerge/api-docs/js/functions/next.getCursor.html
2861
- extension: [
2862
- modelState.init(() => model),
2863
- automerge3({
2864
- handle: doc.handle,
2865
- path: doc.path
2866
- }),
2867
- awarenessProvider && AwarenessProvider.of(awarenessProvider),
2868
- awareness()
2869
- ].filter(isNotNullOrUndefined),
2870
- peer: identity ? {
2871
- id: identity.identityKey.toHex(),
2872
- name: identity.profile?.displayName
2873
- } : void 0
3240
+ // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
3241
+ var useActionHandler = (view) => {
3242
+ return (action) => {
3243
+ if (!view) {
3244
+ return;
3245
+ }
3246
+ switch (action.type) {
3247
+ case "heading":
3248
+ setHeading(parseInt(action.data))(view);
3249
+ break;
3250
+ case "bold":
3251
+ toggleBold(view);
3252
+ break;
3253
+ case "italic":
3254
+ toggleItalic(view);
3255
+ break;
3256
+ case "strikethrough":
3257
+ toggleStrikethrough(view);
3258
+ break;
3259
+ case "list":
3260
+ toggleList(view);
3261
+ break;
3262
+ case "codeblock":
3263
+ insertCodeblock(view);
3264
+ break;
3265
+ case "table":
3266
+ insertTable(view);
3267
+ break;
3268
+ case "comment":
3269
+ createComment(view);
3270
+ break;
3271
+ }
3272
+ setTimeout(() => {
3273
+ view.focus();
3274
+ view.dispatch({
3275
+ selection: view.state.selection
3276
+ });
3277
+ });
2874
3278
  };
2875
- return model;
2876
3279
  };
2877
3280
 
2878
- // packages/ui/react-ui-editor/src/hooks/yjs.ts
2879
- import * as decoding from "lib0/decoding";
2880
- import * as encoding from "lib0/encoding";
2881
- import { Observable } from "lib0/observable";
2882
- import * as YP from "y-protocols/awareness";
2883
- import { invariant as invariant4 } from "@dxos/invariant";
2884
- import { log as log4 } from "@dxos/log";
2885
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/yjs.ts";
2886
- var createYjsModel = ({ identity, space, text }) => {
2887
- invariant4(text?.doc && text?.content, void 0, {
2888
- F: __dxlog_file6,
2889
- L: 22,
2890
- S: void 0,
2891
- A: [
2892
- "text?.doc && text?.content",
2893
- ""
2894
- ]
2895
- });
2896
- const provider = space ? new YAwarenessProvider({
2897
- space,
2898
- doc: text.doc,
2899
- channel: `yjs.awareness.${text.id}`
2900
- }) : void 0;
2901
- const model = {
2902
- id: text.doc.guid,
2903
- content: text.content,
2904
- text: () => text.content.toString(),
2905
- extension: [
2906
- modelState.init(() => model),
2907
- yjs(text.content, provider?.awareness)
2908
- ],
2909
- awareness: provider?.awareness,
2910
- peer: identity ? {
2911
- id: identity.identityKey.toHex(),
2912
- name: identity.profile?.displayName
2913
- } : void 0
2914
- };
2915
- return model;
3281
+ // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
3282
+ import { useState as useState2 } from "react";
3283
+ var useEditorView = () => {
3284
+ const [view, setView] = useState2(null);
3285
+ return [
3286
+ (ref) => {
3287
+ setView(ref);
3288
+ },
3289
+ view
3290
+ ];
2916
3291
  };
2917
- var messageAwareness = 1;
2918
- var messageQueryAwareness = 3;
2919
- var YAwarenessProvider = class extends Observable {
2920
- constructor({ space, doc, channel, awareness: awareness2 }) {
2921
- super();
2922
- this._space = space;
2923
- this._awareness = awareness2 ?? new YP.Awareness(doc);
2924
- this._channel = channel;
2925
- this._clientId = doc.clientID;
2926
- this._awareness.on("update", this._handleAwarenessUpdate.bind(this));
2927
- this._space.listen(this._channel, this._handleSpaceMessage.bind(this));
2928
- if (typeof window !== "undefined") {
2929
- window.addEventListener("beforeunload", this._handleBeforeUnload.bind(this));
2930
- } else if (typeof process !== "undefined") {
2931
- process.on("exit", this._handleBeforeUnload.bind(this));
2932
- }
2933
- const encoderAwarenessQuery = encoding.createEncoder();
2934
- encoding.writeVarUint(encoderAwarenessQuery, messageQueryAwareness);
2935
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessQuery));
2936
- const encoderAwarenessState = encoding.createEncoder();
2937
- encoding.writeVarUint(encoderAwarenessState, messageAwareness);
2938
- encoding.writeVarUint8Array(encoderAwarenessState, YP.encodeAwarenessUpdate(this.awareness, [
2939
- this._clientId
2940
- ]));
2941
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwarenessState));
2942
- }
2943
- get awareness() {
2944
- return this._awareness;
2945
- }
2946
- _handleAwarenessUpdate({ added, updated, removed }, origin) {
2947
- log4("awareness update", {
2948
- added,
2949
- updated,
2950
- removed,
2951
- origin
2952
- }, {
2953
- F: __dxlog_file6,
2954
- L: 101,
2955
- S: this,
2956
- C: (f, a) => f(...a)
2957
- });
2958
- const changedClients = added.concat(updated).concat(removed);
2959
- const encoderAwareness = encoding.createEncoder();
2960
- encoding.writeVarUint(encoderAwareness, messageAwareness);
2961
- encoding.writeVarUint8Array(encoderAwareness, YP.encodeAwarenessUpdate(this._awareness, changedClients));
2962
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoderAwareness));
2963
- }
2964
- _handleSpaceMessage({ payload }) {
2965
- log4("space message", payload, {
2966
- F: __dxlog_file6,
2967
- L: 110,
2968
- S: this,
2969
- C: (f, a) => f(...a)
2970
- });
2971
- const data = new Uint8Array(Array.from(Object.values(payload)));
2972
- const encoder = this._readMessage(data);
2973
- if (encoder) {
2974
- void this._space.postMessage(this._channel, encoding.toUint8Array(encoder));
3292
+
3293
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
3294
+ import { EditorSelection, EditorState as EditorState3 } from "@codemirror/state";
3295
+ import { EditorView as EditorView14 } from "@codemirror/view";
3296
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState3 } from "react";
3297
+ import { log as log4 } from "@dxos/log";
3298
+ import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
3299
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
3300
+ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
3301
+ const onUpdate = useRef2();
3302
+ const [view, setView] = useState3();
3303
+ const parentRef = useRef2(null);
3304
+ useEffect3(() => {
3305
+ if (parentRef.current) {
3306
+ const state = EditorState3.create({
3307
+ doc,
3308
+ selection,
3309
+ extensions: [
3310
+ // TODO(burdon): Doesn't catch errors in keymap functions.
3311
+ EditorView14.exceptionSink.of((err) => {
3312
+ log4.catch(err, void 0, {
3313
+ F: __dxlog_file5,
3314
+ L: 57,
3315
+ S: void 0,
3316
+ C: (f, a) => f(...a)
3317
+ });
3318
+ }),
3319
+ extensions,
3320
+ EditorView14.updateListener.of(() => {
3321
+ onUpdate.current?.();
3322
+ })
3323
+ ].filter(isNotFalsy4)
3324
+ });
3325
+ const view2 = new EditorView14({
3326
+ parent: parentRef.current,
3327
+ scrollTo,
3328
+ state,
3329
+ // NOTE: Uncomment to debug/monitor all transactions.
3330
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
3331
+ dispatchTransactions: (trs, view3) => {
3332
+ if (debug) {
3333
+ logChanges(trs);
3334
+ }
3335
+ view3.update(trs);
3336
+ }
3337
+ });
3338
+ setView(view2);
2975
3339
  }
2976
- }
2977
- _readMessage(message) {
2978
- const decoder = decoding.createDecoder(message);
2979
- const encoder = encoding.createEncoder();
2980
- const messageType = decoding.readVarUint(decoder);
2981
- let sendReply = false;
2982
- switch (messageType) {
2983
- case messageAwareness: {
2984
- YP.applyAwarenessUpdate(this._awareness, decoding.readVarUint8Array(decoder), this);
2985
- break;
3340
+ return () => {
3341
+ view?.destroy();
3342
+ };
3343
+ }, [
3344
+ parentRef
3345
+ ]);
3346
+ useEffect3(() => {
3347
+ if (view) {
3348
+ if (!selection && !view.state.selection.main.anchor) {
3349
+ selection = EditorSelection.single(view.state.doc.line(1).to);
2986
3350
  }
2987
- case messageQueryAwareness: {
2988
- encoding.writeVarUint(encoder, messageAwareness);
2989
- encoding.writeVarUint8Array(encoder, YP.encodeAwarenessUpdate(this._awareness, Array.from(this._awareness.getStates().keys())));
2990
- sendReply = true;
2991
- break;
3351
+ if (selection || scrollTo) {
3352
+ onUpdate.current = () => {
3353
+ onUpdate.current = void 0;
3354
+ view.dispatch({
3355
+ selection,
3356
+ effects: scrollTo && [
3357
+ scrollTo
3358
+ ],
3359
+ scrollIntoView: !scrollTo
3360
+ });
3361
+ };
2992
3362
  }
2993
- default: {
2994
- console.error("Invalid message:", messageType);
2995
- return encoder;
3363
+ if (autoFocus) {
3364
+ view.focus();
2996
3365
  }
2997
3366
  }
2998
- if (!sendReply) {
2999
- return null;
3000
- }
3001
- return encoder;
3002
- }
3003
- _handleBeforeUnload() {
3004
- YP.removeAwarenessStates(this._awareness, [
3005
- this._clientId
3006
- ], "window unload");
3007
- }
3367
+ }, [
3368
+ view,
3369
+ autoFocus,
3370
+ selection,
3371
+ scrollTo
3372
+ ]);
3373
+ return {
3374
+ parentRef,
3375
+ view
3376
+ };
3377
+ };
3378
+ var createDataExtensions = ({ readonly = false } = {}) => {
3379
+ return [
3380
+ //
3381
+ EditorState3.readOnly.of(readonly),
3382
+ EditorView14.editable.of(!readonly)
3383
+ ];
3384
+ };
3385
+ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
3386
+ return [
3387
+ //
3388
+ EditorView14.baseTheme(defaultTheme),
3389
+ theme && EditorView14.theme(theme),
3390
+ EditorView14.darkTheme.of(themeMode === "dark"),
3391
+ EditorView14.editorAttributes.of({
3392
+ class: slots?.editor?.className ?? ""
3393
+ }),
3394
+ EditorView14.contentAttributes.of({
3395
+ class: slots?.content?.className ?? ""
3396
+ })
3397
+ ].filter(isNotFalsy4);
3008
3398
  };
3009
3399
 
3010
3400
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
3011
- import { useEffect as useEffect4, useState as useState2 } from "react";
3401
+ import get4 from "lodash.get";
3402
+ import { useEffect as useEffect4, useState as useState4 } from "react";
3403
+ import { generateName } from "@dxos/display-name";
3404
+ import { getRawDoc } from "@dxos/echo-schema";
3405
+ import { invariant as invariant3 } from "@dxos/invariant";
3012
3406
  import { isAutomergeObject } from "@dxos/react-client/echo";
3407
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
3013
3408
  var useTextModel = (props) => {
3014
3409
  const { identity, space, text } = props;
3015
- const [model, setModel] = useState2();
3410
+ const [model, setModel] = useState4();
3016
3411
  useEffect4(() => setModel(createModel(props)), [
3017
3412
  identity,
3018
3413
  space,
@@ -3020,18 +3415,63 @@ var useTextModel = (props) => {
3020
3415
  ]);
3021
3416
  return model;
3022
3417
  };
3023
- var createModel = (props) => {
3024
- const { text } = props;
3025
- if (isAutomergeObject(text)) {
3026
- return createAutomergeModel(props);
3027
- } else if (text?.doc) {
3028
- return createYjsModel(props);
3029
- } else {
3030
- return void 0;
3418
+ var useInMemoryTextModel = ({ id, defaultContent }) => {
3419
+ const [content, setContent] = useState4(defaultContent ?? "");
3420
+ return {
3421
+ id,
3422
+ content,
3423
+ setContent,
3424
+ text: () => content
3425
+ };
3426
+ };
3427
+ var createModel = ({ space, identity, text }) => {
3428
+ invariant3(isAutomergeObject(text), void 0, {
3429
+ F: __dxlog_file6,
3430
+ L: 50,
3431
+ S: void 0,
3432
+ A: [
3433
+ "isAutomergeObject(text)",
3434
+ ""
3435
+ ]
3436
+ });
3437
+ const obj = text;
3438
+ const doc = getRawDoc(obj, [
3439
+ obj.field
3440
+ ]);
3441
+ const awarenessProvider2 = space && new SpaceAwarenessProvider({
3442
+ space,
3443
+ channel: `automerge.awareness.${obj.id}`,
3444
+ info: {
3445
+ displayName: identity ? identity.profile?.displayName ?? generateName(identity.identityKey.toHex()) : void 0,
3446
+ color: cursorColor.color,
3447
+ lightColor: cursorColor.light
3448
+ },
3449
+ peerId: identity?.identityKey.toHex() ?? "Anonymous"
3450
+ });
3451
+ const extensions = [
3452
+ //
3453
+ modelState.init(() => model),
3454
+ automerge({
3455
+ handle: doc.handle,
3456
+ path: doc.path
3457
+ })
3458
+ ];
3459
+ if (awarenessProvider2) {
3460
+ extensions.push(awareness(awarenessProvider2));
3031
3461
  }
3462
+ const model = {
3463
+ id: obj.id,
3464
+ content: doc,
3465
+ text: () => get4(doc.handle.docSync(), doc.path),
3466
+ extension: extensions,
3467
+ peer: identity ? {
3468
+ id: identity.identityKey.toHex(),
3469
+ name: identity.profile?.displayName
3470
+ } : void 0
3471
+ };
3472
+ return model;
3032
3473
  };
3033
3474
  export {
3034
- AwarenessProvider,
3035
3475
  BaseTextEditor,
3036
3476
  Cursor,
3037
3477
  Doc,
@@ -3041,32 +3481,40 @@ export {
3041
3481
  SpaceAwarenessProvider,
3042
3482
  TextEditor,
3043
3483
  TextKind,
3044
- YAwarenessProvider,
3484
+ Toolbar,
3045
3485
  YText,
3046
3486
  YXmlFragment,
3047
3487
  autocomplete,
3048
- automerge3 as automerge,
3488
+ automerge,
3049
3489
  awareness,
3050
- basicBundle,
3490
+ awarenessProvider,
3051
3491
  blast,
3052
3492
  callbackWrapper,
3053
3493
  code2 as code,
3054
3494
  codeTheme,
3055
3495
  comments,
3056
- createAutomergeModel,
3057
- createYjsModel,
3496
+ createBasicBundle,
3497
+ createComment,
3498
+ createDataExtensions,
3499
+ createMarkdownExtensions,
3500
+ createThemeExtensions,
3058
3501
  defaultMarkdownSlots,
3059
3502
  defaultOptions,
3060
3503
  defaultSlots,
3061
3504
  defaultTextSlots,
3062
3505
  defaultTheme,
3506
+ focusComment,
3507
+ formatting,
3063
3508
  getToken,
3509
+ heading2 as heading,
3064
3510
  hr,
3065
3511
  image,
3512
+ insertCodeblock,
3513
+ insertTable,
3514
+ keymap7 as keymap,
3066
3515
  link,
3067
3516
  listener,
3068
3517
  logChanges,
3069
- markdownBundle,
3070
3518
  markdownHighlightStyle,
3071
3519
  markdownTags,
3072
3520
  markdownTagsExtensions,
@@ -3075,16 +3523,24 @@ export {
3075
3523
  modelState,
3076
3524
  outliner,
3077
3525
  setComments,
3078
- setFocus,
3526
+ setHeading,
3079
3527
  setSelection,
3080
3528
  table,
3081
3529
  tags2 as tags,
3082
3530
  tasklist,
3083
3531
  textTheme,
3532
+ toggleBold,
3533
+ toggleItalic,
3534
+ toggleList,
3535
+ toggleStrikethrough,
3536
+ toggleStyle,
3084
3537
  typewriter,
3085
- useAwareness,
3538
+ useActionHandler,
3086
3539
  useComments,
3540
+ useEditorView,
3541
+ useInMemoryTextModel,
3542
+ useTextEditor,
3087
3543
  useTextModel,
3088
- yjs
3544
+ useToolbarContext
3089
3545
  };
3090
3546
  //# sourceMappingURL=index.mjs.map