@dxos/react-ui-editor 0.6.13 → 0.6.14-main.1366248

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 (133) hide show
  1. package/dist/lib/browser/index.mjs +772 -712
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node/index.cjs +5667 -0
  5. package/dist/lib/node/index.cjs.map +7 -0
  6. package/dist/lib/node/meta.json +1 -0
  7. package/dist/lib/node-esm/index.mjs +5650 -0
  8. package/dist/lib/node-esm/index.mjs.map +7 -0
  9. package/dist/lib/node-esm/meta.json +1 -0
  10. package/dist/types/src/InputMode.stories.d.ts +11 -11
  11. package/dist/types/src/InputMode.stories.d.ts.map +1 -1
  12. package/dist/types/src/TextEditor.stories.d.ts +4 -1
  13. package/dist/types/src/TextEditor.stories.d.ts.map +1 -1
  14. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -1
  15. package/dist/types/src/defaults.d.ts.map +1 -1
  16. package/dist/types/src/extensions/autocomplete.d.ts +2 -1
  17. package/dist/types/src/extensions/autocomplete.d.ts.map +1 -1
  18. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/cursor.d.ts +1 -1
  20. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  21. package/dist/types/src/extensions/awareness/awareness.d.ts +2 -2
  22. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  23. package/dist/types/src/extensions/command/state.d.ts +2 -2
  24. package/dist/types/src/extensions/command/state.d.ts.map +1 -1
  25. package/dist/types/src/extensions/comments.d.ts +1 -1
  26. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  27. package/dist/types/src/extensions/debug.d.ts +2 -2
  28. package/dist/types/src/extensions/debug.d.ts.map +1 -1
  29. package/dist/types/src/extensions/factories.d.ts +1 -0
  30. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  31. package/dist/types/src/extensions/focus.d.ts +7 -0
  32. package/dist/types/src/extensions/focus.d.ts.map +1 -0
  33. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  34. package/dist/types/src/extensions/index.d.ts +2 -4
  35. package/dist/types/src/extensions/index.d.ts.map +1 -1
  36. package/dist/types/src/extensions/listener.d.ts +2 -1
  37. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  38. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  39. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -1
  40. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  41. package/dist/types/src/extensions/markdown/image.d.ts +3 -6
  42. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/link.d.ts +1 -1
  44. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  45. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  46. package/dist/types/src/extensions/modes.d.ts +3 -4
  47. package/dist/types/src/extensions/modes.d.ts.map +1 -1
  48. package/dist/types/src/extensions/{state.d.ts → selection.d.ts} +8 -4
  49. package/dist/types/src/extensions/selection.d.ts.map +1 -0
  50. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  51. package/dist/types/src/index.d.ts +1 -0
  52. package/dist/types/src/index.d.ts.map +1 -1
  53. package/dist/types/src/styles/markdown.d.ts +1 -2
  54. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  55. package/dist/types/src/styles/theme.d.ts.map +1 -1
  56. package/dist/types/src/types.d.ts.map +1 -0
  57. package/dist/types/src/{extensions → util}/cursor.d.ts +9 -3
  58. package/dist/types/src/util/cursor.d.ts.map +1 -0
  59. package/dist/types/src/util/debug.d.ts +17 -0
  60. package/dist/types/src/util/debug.d.ts.map +1 -0
  61. package/dist/types/src/util/dom.d.ts.map +1 -0
  62. package/dist/types/src/util/facet.d.ts +3 -0
  63. package/dist/types/src/util/facet.d.ts.map +1 -0
  64. package/dist/types/src/util/index.d.ts +6 -0
  65. package/dist/types/src/util/index.d.ts.map +1 -0
  66. package/dist/types/src/{extensions/util → util}/react.d.ts +1 -1
  67. package/dist/types/src/util/react.d.ts.map +1 -0
  68. package/package.json +46 -41
  69. package/src/InputMode.stories.tsx +8 -8
  70. package/src/TextEditor.stories.tsx +100 -75
  71. package/src/components/Toolbar/Toolbar.tsx +8 -11
  72. package/src/defaults.ts +0 -2
  73. package/src/extensions/annotations.ts +1 -1
  74. package/src/extensions/autocomplete.ts +9 -8
  75. package/src/extensions/automerge/automerge.stories.tsx +2 -2
  76. package/src/extensions/automerge/{automerge.spec.tsx → automerge.test.tsx} +1 -0
  77. package/src/extensions/automerge/automerge.ts +2 -2
  78. package/src/extensions/automerge/cursor.ts +1 -1
  79. package/src/extensions/awareness/awareness.ts +3 -5
  80. package/src/extensions/command/hint.ts +1 -1
  81. package/src/extensions/command/state.ts +3 -4
  82. package/src/extensions/comments.ts +45 -47
  83. package/src/extensions/debug.ts +2 -2
  84. package/src/extensions/factories.ts +5 -1
  85. package/src/extensions/focus.ts +35 -0
  86. package/src/extensions/folding.tsx +7 -5
  87. package/src/extensions/index.ts +2 -4
  88. package/src/extensions/listener.ts +5 -2
  89. package/src/extensions/markdown/changes.test.ts +1 -3
  90. package/src/extensions/markdown/decorate.ts +50 -7
  91. package/src/extensions/markdown/formatting.test.ts +1 -3
  92. package/src/extensions/markdown/highlight.ts +0 -5
  93. package/src/extensions/markdown/image.ts +53 -42
  94. package/src/extensions/markdown/link.ts +3 -2
  95. package/src/extensions/markdown/parser.test.ts +1 -2
  96. package/src/extensions/markdown/styles.ts +10 -0
  97. package/src/extensions/markdown/table.ts +3 -3
  98. package/src/extensions/modes.ts +6 -7
  99. package/src/extensions/{state.ts → selection.ts} +20 -16
  100. package/src/hooks/useTextEditor.ts +36 -35
  101. package/src/index.ts +1 -0
  102. package/src/styles/markdown.ts +1 -3
  103. package/src/styles/theme.ts +3 -1
  104. package/src/{extensions → util}/cursor.ts +11 -8
  105. package/src/{util.ts → util/debug.ts} +25 -2
  106. package/src/util/facet.ts +13 -0
  107. package/src/{extensions/util → util}/index.ts +3 -2
  108. package/src/{extensions/util → util}/react.tsx +6 -1
  109. package/dist/types/src/extensions/automerge/automerge.spec.d.ts +0 -2
  110. package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +0 -1
  111. package/dist/types/src/extensions/cursor.d.ts.map +0 -1
  112. package/dist/types/src/extensions/doc.d.ts +0 -6
  113. package/dist/types/src/extensions/doc.d.ts.map +0 -1
  114. package/dist/types/src/extensions/state.d.ts.map +0 -1
  115. package/dist/types/src/extensions/types.d.ts.map +0 -1
  116. package/dist/types/src/extensions/util/dom.d.ts.map +0 -1
  117. package/dist/types/src/extensions/util/error.d.ts +0 -2
  118. package/dist/types/src/extensions/util/error.d.ts.map +0 -1
  119. package/dist/types/src/extensions/util/index.d.ts +0 -5
  120. package/dist/types/src/extensions/util/index.d.ts.map +0 -1
  121. package/dist/types/src/extensions/util/overlap.d.ts +0 -8
  122. package/dist/types/src/extensions/util/overlap.d.ts.map +0 -1
  123. package/dist/types/src/extensions/util/react.d.ts.map +0 -1
  124. package/dist/types/src/util.d.ts +0 -7
  125. package/dist/types/src/util.d.ts.map +0 -1
  126. package/src/extensions/automerge/automerge.test.ts +0 -13
  127. package/src/extensions/doc.ts +0 -17
  128. package/src/extensions/util/error.ts +0 -15
  129. package/src/extensions/util/overlap.ts +0 -12
  130. /package/dist/types/src/{extensions/types.d.ts → types.d.ts} +0 -0
  131. /package/dist/types/src/{extensions/util → util}/dom.d.ts +0 -0
  132. /package/src/{extensions/types.ts → types.ts} +0 -0
  133. /package/src/{extensions/util → util}/dom.ts +0 -0
@@ -43,31 +43,36 @@ import { ChatText, Code, CodeBlock, Image, Link, ListBullets, ListChecks, ListNu
43
43
  import { createContext } from "@radix-ui/react-context";
44
44
  import React3, { useEffect as useEffect2, useRef, useState as useState3 } from "react";
45
45
  import { useDropzone } from "react-dropzone";
46
- import { Button, DensityProvider, DropdownMenu, ElevationProvider, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
47
- import { getSize as getSize2 } from "@dxos/react-ui-theme";
46
+ import { Button, DropdownMenu, ElevationProvider, Toolbar as NaturalToolbar, Tooltip, useTranslation } from "@dxos/react-ui";
47
+ import { getSize } from "@dxos/react-ui-theme";
48
48
 
49
49
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
50
50
  import { StateField } from "@codemirror/state";
51
51
  import { Decoration, EditorView } from "@codemirror/view";
52
52
  import { isNotFalsy } from "@dxos/util";
53
53
 
54
- // packages/ui/react-ui-editor/src/extensions/cursor.ts
54
+ // packages/ui/react-ui-editor/src/util/facet.ts
55
55
  import { Facet } from "@codemirror/state";
56
+ var singleValueFacet = (defaultValue) => Facet.define({
57
+ // Called immediately.
58
+ combine: (providers) => {
59
+ return providers[0] ?? defaultValue;
60
+ }
61
+ });
62
+
63
+ // packages/ui/react-ui-editor/src/util/cursor.ts
64
+ var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
56
65
  var defaultCursorConverter = {
57
66
  toCursor: (position) => position.toString(),
58
67
  fromCursor: (cursor) => parseInt(cursor)
59
68
  };
60
69
  var Cursor = class _Cursor {
61
70
  static {
62
- this.converter = Facet.define({
63
- combine: (providers) => {
64
- return providers[0] ?? defaultCursorConverter;
65
- }
66
- });
71
+ this.converter = singleValueFacet(defaultCursorConverter);
67
72
  }
68
73
  static {
69
- this.getCursorFromRange = (state2, range) => {
70
- const cursorConverter2 = state2.facet(_Cursor.converter);
74
+ this.getCursorFromRange = (state, range) => {
75
+ const cursorConverter2 = state.facet(_Cursor.converter);
71
76
  const from = cursorConverter2.toCursor(range.from);
72
77
  const to = cursorConverter2.toCursor(range.to, -1);
73
78
  return [
@@ -77,8 +82,8 @@ var Cursor = class _Cursor {
77
82
  };
78
83
  }
79
84
  static {
80
- this.getRangeFromCursor = (state2, cursor) => {
81
- const cursorConverter2 = state2.facet(_Cursor.converter);
85
+ this.getRangeFromCursor = (state, cursor) => {
86
+ const cursorConverter2 = state.facet(_Cursor.converter);
82
87
  const parts = cursor.split(":");
83
88
  const from = cursorConverter2.fromCursor(parts[0]);
84
89
  const to = cursorConverter2.fromCursor(parts[1]);
@@ -90,20 +95,131 @@ var Cursor = class _Cursor {
90
95
  }
91
96
  };
92
97
 
98
+ // packages/ui/react-ui-editor/src/util/debug.ts
99
+ import { log } from "@dxos/log";
100
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util/debug.ts";
101
+ var wrapWithCatch = (fn) => {
102
+ return (...args) => {
103
+ try {
104
+ return fn(...args);
105
+ } catch (err) {
106
+ log.catch(err, void 0, {
107
+ F: __dxlog_file,
108
+ L: 15,
109
+ S: void 0,
110
+ C: (f, a) => f(...a)
111
+ });
112
+ }
113
+ };
114
+ };
115
+ var callbackWrapper = (fn) => (...args) => {
116
+ try {
117
+ return fn(...args);
118
+ } catch (err) {
119
+ log.catch(err, void 0, {
120
+ F: __dxlog_file,
121
+ L: 29,
122
+ S: void 0,
123
+ C: (f, a) => f(...a)
124
+ });
125
+ }
126
+ };
127
+ var debugDispatcher = (trs, view) => {
128
+ logChanges(trs);
129
+ view.update(trs);
130
+ };
131
+ var logChanges = (trs) => {
132
+ const changes = trs.flatMap((tr) => {
133
+ if (tr.changes.empty) {
134
+ return void 0;
135
+ }
136
+ const changes2 = [];
137
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
138
+ fromA,
139
+ toA,
140
+ fromB,
141
+ toB,
142
+ inserted: inserted.toString()
143
+ })));
144
+ return changes2;
145
+ }).filter(Boolean);
146
+ if (changes.length) {
147
+ log.info("changes", {
148
+ changes
149
+ }, {
150
+ F: __dxlog_file,
151
+ L: 62,
152
+ S: void 0,
153
+ C: (f, a) => f(...a)
154
+ });
155
+ }
156
+ };
157
+
158
+ // packages/ui/react-ui-editor/src/util/dom.ts
159
+ var flattenRect = (rect, left) => {
160
+ const x = left ? rect.left : rect.right;
161
+ return {
162
+ left: x,
163
+ right: x,
164
+ top: rect.top,
165
+ bottom: rect.bottom
166
+ };
167
+ };
168
+ var scratchRange;
169
+ var textRange = (node, from, to = from) => {
170
+ const range = scratchRange || (scratchRange = document.createRange());
171
+ range.setEnd(node, to);
172
+ range.setStart(node, from);
173
+ return range;
174
+ };
175
+ var clientRectsFor = (dom) => {
176
+ if (dom.nodeType === 3) {
177
+ return textRange(dom, 0, dom.nodeValue.length).getClientRects();
178
+ } else if (dom.nodeType === 1) {
179
+ return dom.getClientRects();
180
+ } else {
181
+ return [];
182
+ }
183
+ };
184
+
185
+ // packages/ui/react-ui-editor/src/util/react.tsx
186
+ import React from "react";
187
+ import { createRoot } from "react-dom/client";
188
+ import { ThemeProvider } from "@dxos/react-ui";
189
+ import { defaultTx } from "@dxos/react-ui-theme";
190
+ var createElement = (tag, options, children) => {
191
+ const el = document.createElement(tag);
192
+ if (options?.className) {
193
+ el.className = options.className;
194
+ }
195
+ if (children) {
196
+ el.append(...Array.isArray(children) ? children : [
197
+ children
198
+ ]);
199
+ }
200
+ return el;
201
+ };
202
+ var renderRoot = (root, node) => {
203
+ createRoot(root).render(/* @__PURE__ */ React.createElement(ThemeProvider, {
204
+ tx: defaultTx
205
+ }, node));
206
+ return root;
207
+ };
208
+
93
209
  // packages/ui/react-ui-editor/src/extensions/annotations.ts
94
210
  var annotationMark = Decoration.mark({
95
211
  class: "cm-annotation"
96
212
  });
97
213
  var annotations = (options = {}) => {
98
- const match = (state2) => {
214
+ const match = (state) => {
99
215
  const annotations2 = [];
100
- const text = state2.doc.toString();
216
+ const text = state.doc.toString();
101
217
  if (options.match) {
102
218
  const matches = text.matchAll(options.match);
103
219
  for (const match2 of matches) {
104
220
  const from = match2.index;
105
221
  const to = from + match2[0].length;
106
- const cursor = Cursor.getCursorFromRange(state2, {
222
+ const cursor = Cursor.getCursorFromRange(state, {
107
223
  from,
108
224
  to
109
225
  });
@@ -115,8 +231,8 @@ var annotations = (options = {}) => {
115
231
  return annotations2;
116
232
  };
117
233
  const annotationsState = StateField.define({
118
- create: (state2) => {
119
- return match(state2);
234
+ create: (state) => {
235
+ return match(state);
120
236
  },
121
237
  update: (value, tr) => {
122
238
  if (!tr.changes.empty) {
@@ -129,10 +245,10 @@ var annotations = (options = {}) => {
129
245
  annotationsState,
130
246
  EditorView.decorations.compute([
131
247
  annotationsState
132
- ], (state2) => {
133
- const annotations2 = state2.field(annotationsState);
248
+ ], (state) => {
249
+ const annotations2 = state.field(annotationsState);
134
250
  const decorations = annotations2.map((annotation) => {
135
- const range = Cursor.getRangeFromCursor(state2, annotation.cursor);
251
+ const range = Cursor.getRangeFromCursor(state, annotation.cursor);
136
252
  return range && annotationMark.range(range.from, range.to);
137
253
  }).filter(isNotFalsy);
138
254
  return Decoration.set(decorations);
@@ -153,7 +269,7 @@ import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
153
269
  import { markdownLanguage } from "@codemirror/lang-markdown";
154
270
  import { keymap } from "@codemirror/view";
155
271
  var autocomplete = ({ activateOnTyping, override, onSearch } = {}) => {
156
- const extentions = [
272
+ const extensions = [
157
273
  // https://codemirror.net/docs/ref/#view.keymap
158
274
  // https://discuss.codemirror.net/t/how-can-i-replace-the-default-autocompletion-keymap-v6/3322
159
275
  // TODO(burdon): Set custom keymap.
@@ -170,7 +286,7 @@ var autocomplete = ({ activateOnTyping, override, onSearch } = {}) => {
170
286
  })
171
287
  ];
172
288
  if (onSearch) {
173
- extentions.push(
289
+ extensions.push(
174
290
  // TODO(burdon): Optional decoration via addToOptions
175
291
  markdownLanguage.data.of({
176
292
  autocomplete: (context) => {
@@ -186,7 +302,7 @@ var autocomplete = ({ activateOnTyping, override, onSearch } = {}) => {
186
302
  })
187
303
  );
188
304
  }
189
- return extentions;
305
+ return extensions;
190
306
  };
191
307
 
192
308
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
@@ -195,16 +311,16 @@ import { EditorView as EditorView2, ViewPlugin } from "@codemirror/view";
195
311
  import { next as A3 } from "@dxos/automerge/automerge";
196
312
 
197
313
  // packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
198
- import { log } from "@dxos/log";
314
+ import { log as log2 } from "@dxos/log";
199
315
  import { fromCursor, toCursor } from "@dxos/react-client/echo";
200
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
316
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts";
201
317
  var cursorConverter = (accessor) => ({
202
318
  toCursor: (pos, assoc) => {
203
319
  try {
204
320
  return toCursor(accessor, pos, assoc);
205
321
  } catch (err) {
206
- log.catch(err, void 0, {
207
- F: __dxlog_file,
322
+ log2.catch(err, void 0, {
323
+ F: __dxlog_file2,
208
324
  L: 15,
209
325
  S: void 0,
210
326
  C: (f, a) => f(...a)
@@ -216,8 +332,8 @@ var cursorConverter = (accessor) => ({
216
332
  try {
217
333
  return fromCursor(accessor, cursor);
218
334
  } catch (err) {
219
- log.catch(err, void 0, {
220
- F: __dxlog_file,
335
+ log2.catch(err, void 0, {
336
+ F: __dxlog_file2,
221
337
  L: 24,
222
338
  S: void 0,
223
339
  C: (f, a) => f(...a)
@@ -229,8 +345,8 @@ var cursorConverter = (accessor) => ({
229
345
 
230
346
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
231
347
  import { Annotation, StateEffect } from "@codemirror/state";
232
- var getPath = (state2, field) => state2.field(field).path;
233
- var getLastHeads = (state2, field) => state2.field(field).lastHeads;
348
+ var getPath = (state, field) => state.field(field).path;
349
+ var getLastHeads = (state, field) => state.field(field).lastHeads;
234
350
  var updateHeadsEffect = StateEffect.define({});
235
351
  var updateHeads = (newHeads) => updateHeadsEffect.of({
236
352
  newHeads
@@ -245,8 +361,8 @@ import { next as A2 } from "@dxos/automerge/automerge";
245
361
 
246
362
  // packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
247
363
  import { next as A } from "@dxos/automerge/automerge";
248
- var updateAutomerge = (field, handle, transactions, state2) => {
249
- const { lastHeads, path } = state2.field(field);
364
+ var updateAutomerge = (field, handle, transactions, state) => {
365
+ const { lastHeads, path } = state.field(field);
250
366
  let hasChanges = false;
251
367
  for (const tr of transactions) {
252
368
  tr.changes.iterChanges(() => {
@@ -293,7 +409,7 @@ var updateCodeMirror = (view, selection, target, patches) => {
293
409
  annotations: reconcileAnnotation.of(false)
294
410
  });
295
411
  };
296
- var handlePatch = (patch, target, state2) => {
412
+ var handlePatch = (patch, target, state) => {
297
413
  if (patch.action === "insert") {
298
414
  return handleInsert(target, patch);
299
415
  } else if (patch.action === "splice") {
@@ -301,7 +417,7 @@ var handlePatch = (patch, target, state2) => {
301
417
  } else if (patch.action === "del") {
302
418
  return handleDel(target, patch);
303
419
  } else if (patch.action === "put") {
304
- return handlePut(target, patch, state2);
420
+ return handlePut(target, patch, state);
305
421
  } else {
306
422
  return null;
307
423
  }
@@ -345,7 +461,7 @@ var handleDel = (target, patch) => {
345
461
  }
346
462
  ];
347
463
  };
348
- var handlePut = (target, patch, state2) => {
464
+ var handlePut = (target, patch, state) => {
349
465
  const index = charPath(target, [
350
466
  ...patch.path,
351
467
  0
@@ -353,7 +469,7 @@ var handlePut = (target, patch, state2) => {
353
469
  if (index == null) {
354
470
  return [];
355
471
  }
356
- const length = state2.doc.length;
472
+ const length = state.doc.length;
357
473
  if (typeof patch.value !== "string") {
358
474
  return [];
359
475
  }
@@ -484,11 +600,11 @@ var automerge = (accessor) => {
484
600
  };
485
601
 
486
602
  // packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts
487
- import { Annotation as Annotation2, Facet as Facet2, RangeSet } from "@codemirror/state";
603
+ import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
488
604
  import { Decoration as Decoration2, EditorView as EditorView3, ViewPlugin as ViewPlugin2, WidgetType } from "@codemirror/view";
489
605
  import { Event } from "@dxos/async";
490
606
  import { Context } from "@dxos/context";
491
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts";
607
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness.ts";
492
608
  var dummyProvider = {
493
609
  remoteStateChange: new Event(),
494
610
  open: () => {
@@ -499,9 +615,7 @@ var dummyProvider = {
499
615
  update: () => {
500
616
  }
501
617
  };
502
- var awarenessProvider = Facet2.define({
503
- combine: (providers) => providers[0] ?? dummyProvider
504
- });
618
+ var awarenessProvider = singleValueFacet(dummyProvider);
505
619
  var RemoteSelectionChangedAnnotation = Annotation2.define();
506
620
  var awareness = (provider = dummyProvider) => {
507
621
  return [
@@ -515,8 +629,8 @@ var awareness = (provider = dummyProvider) => {
515
629
  var RemoteSelectionsDecorator = class {
516
630
  constructor(view) {
517
631
  this._ctx = new Context(void 0, {
518
- F: __dxlog_file2,
519
- L: 82
632
+ F: __dxlog_file3,
633
+ L: 80
520
634
  });
521
635
  this.decorations = RangeSet.of([]);
522
636
  this._cursorConverter = view.state.facet(Cursor.converter);
@@ -554,9 +668,9 @@ var RemoteSelectionsDecorator = class {
554
668
  _updateRemoteSelections(view) {
555
669
  const decorations = [];
556
670
  const awarenessStates = this._provider.getRemoteStates();
557
- for (const state2 of awarenessStates) {
558
- const anchor = state2.position?.anchor ? this._cursorConverter.fromCursor(state2.position.anchor) : null;
559
- const head = state2.position?.head ? this._cursorConverter.fromCursor(state2.position.head) : null;
671
+ for (const state of awarenessStates) {
672
+ const anchor = state.position?.anchor ? this._cursorConverter.fromCursor(state.position.anchor) : null;
673
+ const head = state.position?.head ? this._cursorConverter.fromCursor(state.position.head) : null;
560
674
  if (anchor == null || head == null) {
561
675
  continue;
562
676
  }
@@ -564,8 +678,8 @@ var RemoteSelectionsDecorator = class {
564
678
  const end = Math.min(Math.max(anchor, head), view.state.doc.length);
565
679
  const startLine = view.state.doc.lineAt(start);
566
680
  const endLine = view.state.doc.lineAt(end);
567
- const darkColor = state2.info.darkColor;
568
- const lightColor = state2.info.lightColor;
681
+ const darkColor = state.info.darkColor;
682
+ const lightColor = state.info.lightColor;
569
683
  if (startLine.number === endLine.number) {
570
684
  decorations.push({
571
685
  from: start,
@@ -618,7 +732,7 @@ var RemoteSelectionsDecorator = class {
618
732
  value: Decoration2.widget({
619
733
  side: head - anchor > 0 ? -1 : 1,
620
734
  block: false,
621
- widget: new RemoteCaretWidget(state2.info.displayName ?? "Anonymous", darkColor)
735
+ widget: new RemoteCaretWidget(state.info.displayName ?? "Anonymous", darkColor)
622
736
  })
623
737
  });
624
738
  }
@@ -723,8 +837,8 @@ var styles2 = EditorView3.theme({
723
837
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
724
838
  import { Context as Context2 } from "@dxos/context";
725
839
  import { invariant } from "@dxos/invariant";
726
- import { log as log2 } from "@dxos/log";
727
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness-provider.ts";
840
+ import { log as log3 } from "@dxos/log";
841
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/awareness/awareness-provider.ts";
728
842
  var DEBOUNCE_INTERVAL = 100;
729
843
  var SpaceAwarenessProvider = class {
730
844
  constructor(params) {
@@ -737,7 +851,7 @@ var SpaceAwarenessProvider = class {
737
851
  }
738
852
  open() {
739
853
  this._ctx = new Context2(void 0, {
740
- F: __dxlog_file3,
854
+ F: __dxlog_file4,
741
855
  L: 57
742
856
  });
743
857
  this._postTask = new DeferredTask(this._ctx, async () => {
@@ -764,10 +878,10 @@ var SpaceAwarenessProvider = class {
764
878
  void this._space.postMessage(this._channel, {
765
879
  kind: "query"
766
880
  }).catch((err) => {
767
- log2.debug("failed to query awareness", {
881
+ log3.debug("failed to query awareness", {
768
882
  err
769
883
  }, {
770
- F: __dxlog_file3,
884
+ F: __dxlog_file4,
771
885
  L: 91,
772
886
  S: this,
773
887
  C: (f, a) => f(...a)
@@ -784,7 +898,7 @@ var SpaceAwarenessProvider = class {
784
898
  }
785
899
  update(position) {
786
900
  invariant(this._postTask, void 0, {
787
- F: __dxlog_file3,
901
+ F: __dxlog_file4,
788
902
  L: 106,
789
903
  S: this,
790
904
  A: [
@@ -801,7 +915,7 @@ var SpaceAwarenessProvider = class {
801
915
  }
802
916
  _handleQueryMessage() {
803
917
  invariant(this._postTask, void 0, {
804
- F: __dxlog_file3,
918
+ F: __dxlog_file4,
805
919
  L: 117,
806
920
  S: this,
807
921
  A: [
@@ -813,7 +927,7 @@ var SpaceAwarenessProvider = class {
813
927
  }
814
928
  _handlePostMessage(message) {
815
929
  invariant(message.kind === "post", void 0, {
816
- F: __dxlog_file3,
930
+ F: __dxlog_file4,
817
931
  L: 122,
818
932
  S: this,
819
933
  A: [
@@ -830,7 +944,7 @@ var SpaceAwarenessProvider = class {
830
944
  import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
831
945
  import defaultsDeep from "lodash.defaultsdeep";
832
946
  import { invariant as invariant2 } from "@dxos/invariant";
833
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
947
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
834
948
  var defaultOptions = {
835
949
  effect: 2,
836
950
  maxParticles: 200,
@@ -957,7 +1071,7 @@ var Blaster = class {
957
1071
  }
958
1072
  initialize() {
959
1073
  invariant2(!this._canvas && !this._ctx, void 0, {
960
- F: __dxlog_file4,
1074
+ F: __dxlog_file5,
961
1075
  L: 141,
962
1076
  S: this,
963
1077
  A: [
@@ -994,7 +1108,7 @@ var Blaster = class {
994
1108
  }
995
1109
  start() {
996
1110
  invariant2(this._canvas && this._ctx, void 0, {
997
- F: __dxlog_file4,
1111
+ F: __dxlog_file5,
998
1112
  L: 180,
999
1113
  S: this,
1000
1114
  A: [
@@ -1144,14 +1258,12 @@ import { RangeSetBuilder } from "@codemirror/state";
1144
1258
  import { Decoration as Decoration3, EditorView as EditorView5, ViewPlugin as ViewPlugin3, WidgetType as WidgetType2 } from "@codemirror/view";
1145
1259
 
1146
1260
  // packages/ui/react-ui-editor/src/extensions/command/state.ts
1147
- import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
1261
+ import { StateEffect as StateEffect2, StateField as StateField3 } from "@codemirror/state";
1148
1262
  import { showTooltip } from "@codemirror/view";
1149
- var commandConfig = Facet3.define({
1150
- combine: (providers) => providers[0]
1151
- });
1263
+ var commandConfig = singleValueFacet();
1152
1264
  var commandState = StateField3.define({
1153
1265
  create: () => ({}),
1154
- update: (state2, tr) => {
1266
+ update: (state, tr) => {
1155
1267
  for (const effect of tr.effects) {
1156
1268
  if (effect.is(closeEffect)) {
1157
1269
  return {};
@@ -1202,7 +1314,7 @@ var commandState = StateField3.define({
1202
1314
  };
1203
1315
  }
1204
1316
  }
1205
- return state2;
1317
+ return state;
1206
1318
  },
1207
1319
  provide: (field) => [
1208
1320
  showTooltip.from(field, (value) => value.tooltip ?? null)
@@ -1246,33 +1358,6 @@ var commandKeyBindings = [
1246
1358
  }
1247
1359
  ];
1248
1360
 
1249
- // packages/ui/react-ui-editor/src/extensions/util/dom.ts
1250
- var flattenRect = (rect, left) => {
1251
- const x = left ? rect.left : rect.right;
1252
- return {
1253
- left: x,
1254
- right: x,
1255
- top: rect.top,
1256
- bottom: rect.bottom
1257
- };
1258
- };
1259
- var scratchRange;
1260
- var textRange = (node, from, to = from) => {
1261
- const range = scratchRange || (scratchRange = document.createRange());
1262
- range.setEnd(node, to);
1263
- range.setStart(node, from);
1264
- return range;
1265
- };
1266
- var clientRectsFor = (dom) => {
1267
- if (dom.nodeType === 3) {
1268
- return textRange(dom, 0, dom.nodeValue.length).getClientRects();
1269
- } else if (dom.nodeType === 1) {
1270
- return dom.getClientRects();
1271
- } else {
1272
- return [];
1273
- }
1274
- };
1275
-
1276
1361
  // packages/ui/react-ui-editor/src/extensions/command/hint.ts
1277
1362
  var CommandHint = class extends WidgetType2 {
1278
1363
  constructor(content) {
@@ -1355,112 +1440,115 @@ var command = (options) => {
1355
1440
 
1356
1441
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1357
1442
  import { invertedEffects } from "@codemirror/commands";
1358
- import { Facet as Facet4, StateEffect as StateEffect3, StateField as StateField4 } from "@codemirror/state";
1359
- import { hoverTooltip, keymap as keymap4, Decoration as Decoration4, EditorView as EditorView7, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1443
+ import { StateEffect as StateEffect3, StateField as StateField4 } from "@codemirror/state";
1444
+ import { hoverTooltip, keymap as keymap5, Decoration as Decoration4, EditorView as EditorView8, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1360
1445
  import sortBy from "lodash.sortby";
1361
1446
  import { useEffect, useMemo, useState } from "react";
1362
- import { debounce } from "@dxos/async";
1363
- import { log as log5 } from "@dxos/log";
1447
+ import { debounce as debounce2 } from "@dxos/async";
1448
+ import { log as log4 } from "@dxos/log";
1364
1449
  import { nonNullable } from "@dxos/util";
1365
1450
 
1366
- // packages/ui/react-ui-editor/src/extensions/util/error.ts
1367
- import { log as log3 } from "@dxos/log";
1368
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/util/error.ts";
1369
- var wrapWithCatch = (fn) => {
1370
- return (...args) => {
1371
- try {
1372
- return fn(...args);
1373
- } catch (err) {
1374
- log3.catch(err, void 0, {
1375
- F: __dxlog_file5,
1376
- L: 12,
1377
- S: void 0,
1378
- C: (f, a) => f(...a)
1379
- });
1380
- }
1451
+ // packages/ui/react-ui-editor/src/extensions/selection.ts
1452
+ import { Transaction } from "@codemirror/state";
1453
+ import { EditorView as EditorView7, keymap as keymap4 } from "@codemirror/view";
1454
+ import { debounce } from "@dxos/async";
1455
+ import { invariant as invariant3 } from "@dxos/invariant";
1456
+ import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1457
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/selection.ts";
1458
+ var documentId = singleValueFacet();
1459
+ var stateRestoreAnnotation = "dxos.org/cm/state-restore";
1460
+ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1461
+ return {
1462
+ selection,
1463
+ scrollIntoView: !scrollTo,
1464
+ effects: scrollTo ? EditorView7.scrollIntoView(scrollTo, {
1465
+ yMargin: 96
1466
+ }) : void 0,
1467
+ annotations: Transaction.userEvent.of(stateRestoreAnnotation)
1381
1468
  };
1382
1469
  };
1383
-
1384
- // packages/ui/react-ui-editor/src/extensions/util/overlap.ts
1385
- var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
1386
-
1387
- // packages/ui/react-ui-editor/src/extensions/util/react.tsx
1388
- import React from "react";
1389
- import { createRoot } from "react-dom/client";
1390
- import { ThemeProvider } from "@dxos/react-ui";
1391
- import { defaultTx } from "@dxos/react-ui-theme";
1392
- var createElement = (tag, options, children) => {
1393
- const el = document.createElement(tag);
1394
- if (options?.className) {
1395
- el.className = options.className;
1396
- }
1397
- if (children) {
1398
- el.append(...Array.isArray(children) ? children : [
1399
- children
1400
- ]);
1401
- }
1402
- return el;
1403
- };
1404
- var renderRoot = (root, node) => {
1405
- createRoot(root).render(/* @__PURE__ */ React.createElement(ThemeProvider, {
1406
- tx: defaultTx
1407
- }, node));
1408
- return root;
1409
- };
1410
-
1411
- // packages/ui/react-ui-editor/src/util.ts
1412
- import { log as log4 } from "@dxos/log";
1413
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1414
- var callbackWrapper = (fn) => (...args) => {
1415
- try {
1416
- return fn(...args);
1417
- } catch (err) {
1418
- log4.catch(err, void 0, {
1470
+ var createEditorStateStore = (keyPrefix) => ({
1471
+ getState: (id) => {
1472
+ invariant3(id, void 0, {
1419
1473
  F: __dxlog_file6,
1420
- L: 18,
1474
+ L: 47,
1421
1475
  S: void 0,
1422
- C: (f, a) => f(...a)
1476
+ A: [
1477
+ "id",
1478
+ ""
1479
+ ]
1423
1480
  });
1424
- }
1425
- };
1426
- var logChanges = (trs) => {
1427
- const changes = trs.flatMap((tr) => {
1428
- if (tr.changes.empty) {
1429
- return void 0;
1430
- }
1431
- const changes2 = [];
1432
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => changes2.push(JSON.stringify({
1433
- fromA,
1434
- toA,
1435
- fromB,
1436
- toB,
1437
- inserted: inserted.toString()
1438
- })));
1439
- return changes2;
1440
- }).filter(Boolean);
1441
- if (changes.length) {
1442
- log4.info("changes", {
1443
- changes
1444
- }, {
1481
+ const state = localStorage.getItem(`${keyPrefix}/${id}`);
1482
+ return state ? JSON.parse(state) : void 0;
1483
+ },
1484
+ setState: (id, state) => {
1485
+ invariant3(id, void 0, {
1445
1486
  F: __dxlog_file6,
1446
- L: 39,
1487
+ L: 53,
1447
1488
  S: void 0,
1448
- C: (f, a) => f(...a)
1489
+ A: [
1490
+ "id",
1491
+ ""
1492
+ ]
1449
1493
  });
1494
+ localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
1450
1495
  }
1496
+ });
1497
+ var selectionState = ({ getState, setState } = {}) => {
1498
+ const setStateDebounced = debounce(setState, 1e3);
1499
+ return [
1500
+ // TODO(burdon): Track scrolling (currently only updates when cursor moves).
1501
+ // EditorView.domEventHandlers({
1502
+ // scroll: (event) => {
1503
+ // setStateDebounced(id, {});
1504
+ // },
1505
+ // }),
1506
+ EditorView7.updateListener.of(({ view, transactions }) => {
1507
+ const id = view.state.facet(documentId);
1508
+ if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
1509
+ return;
1510
+ }
1511
+ if (setState) {
1512
+ const { scrollTop } = view.scrollDOM;
1513
+ const pos = view.posAtCoords({
1514
+ x: 0,
1515
+ y: scrollTop
1516
+ });
1517
+ if (pos !== null) {
1518
+ const { anchor, head } = view.state.selection.main;
1519
+ setStateDebounced(id, {
1520
+ scrollTo: pos,
1521
+ selection: {
1522
+ anchor,
1523
+ head
1524
+ }
1525
+ });
1526
+ }
1527
+ }
1528
+ }),
1529
+ getState && keymap4.of([
1530
+ {
1531
+ key: "ctrl-r",
1532
+ run: (view) => {
1533
+ const state = getState(view.state.facet(documentId));
1534
+ if (state) {
1535
+ view.dispatch(createEditorStateTransaction(state));
1536
+ }
1537
+ return true;
1538
+ }
1539
+ }
1540
+ ])
1541
+ ].filter(isNotFalsy2);
1451
1542
  };
1452
1543
 
1453
1544
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1454
1545
  var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1455
- var documentId = Facet4.define({
1456
- combine: (values) => values[0]
1457
- });
1458
1546
  var setComments = StateEffect3.define();
1459
1547
  var setSelection = StateEffect3.define();
1460
1548
  var setCommentState = StateEffect3.define();
1461
1549
  var commentsState = StateField4.define({
1462
- create: (state2) => ({
1463
- id: state2.facet(documentId),
1550
+ create: (state) => ({
1551
+ id: state.facet(documentId),
1464
1552
  comments: [],
1465
1553
  selection: {}
1466
1554
  }),
@@ -1496,7 +1584,7 @@ var commentsState = StateField4.define({
1496
1584
  return value;
1497
1585
  }
1498
1586
  });
1499
- var styles3 = EditorView7.theme({
1587
+ var styles3 = EditorView8.theme({
1500
1588
  ".cm-comment, .cm-comment-current": {
1501
1589
  margin: "0 -3px",
1502
1590
  padding: "3px",
@@ -1516,16 +1604,16 @@ var createCommentMark = (id, isCurrent) => Decoration4.mark({
1516
1604
  "data-comment-id": id
1517
1605
  }
1518
1606
  });
1519
- var commentsDecorations = EditorView7.decorations.compute([
1607
+ var commentsDecorations = EditorView8.decorations.compute([
1520
1608
  commentsState
1521
- ], (state2) => {
1522
- const { selection: { current }, comments: comments2 } = state2.field(commentsState);
1609
+ ], (state) => {
1610
+ const { selection: { current }, comments: comments2 } = state.field(commentsState);
1523
1611
  const decorations = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
1524
1612
  const range = comment.range;
1525
1613
  if (!range) {
1526
- log5.warn("Invalid range:", range, {
1614
+ log4.warn("Invalid range:", range, {
1527
1615
  F: __dxlog_file7,
1528
- L: 147,
1616
+ L: 142,
1529
1617
  S: void 0,
1530
1618
  C: (f, a) => f(...a)
1531
1619
  });
@@ -1539,7 +1627,7 @@ var commentsDecorations = EditorView7.decorations.compute([
1539
1627
  return Decoration4.set(decorations);
1540
1628
  });
1541
1629
  var commentClickedEffect = StateEffect3.define();
1542
- var handleCommentClick = EditorView7.domEventHandlers({
1630
+ var handleCommentClick = EditorView8.domEventHandlers({
1543
1631
  click: (event, view) => {
1544
1632
  let target = event.target;
1545
1633
  const editorRoot = view.dom;
@@ -1578,7 +1666,7 @@ var trackPastedComments = (onUpdate) => {
1578
1666
  }
1579
1667
  };
1580
1668
  return [
1581
- EditorView7.domEventHandlers({
1669
+ EditorView8.domEventHandlers({
1582
1670
  cut: handleTrack,
1583
1671
  copy: handleTrack
1584
1672
  }),
@@ -1600,7 +1688,7 @@ var trackPastedComments = (onUpdate) => {
1600
1688
  return effects;
1601
1689
  }),
1602
1690
  // Handle paste or the undo of comment deletion.
1603
- EditorView7.updateListener.of((update2) => {
1691
+ EditorView8.updateListener.of((update2) => {
1604
1692
  const restore = [];
1605
1693
  for (let i = 0; i < update2.transactions.length; i++) {
1606
1694
  const tr = update2.transactions[i];
@@ -1687,15 +1775,13 @@ var createComment = (view) => {
1687
1775
  }
1688
1776
  return false;
1689
1777
  };
1690
- var optionsFacet = Facet4.define({
1691
- combine: (providers) => providers[0]
1692
- });
1778
+ var optionsFacet = singleValueFacet();
1693
1779
  var comments = (options = {}) => {
1694
1780
  const { key: shortcut = "meta-'" } = options;
1695
- const handleSelect = debounce((state2) => options.onSelect?.(state2), 200);
1781
+ const handleSelect = debounce2((state) => options.onSelect?.(state), 200);
1696
1782
  return [
1697
1783
  optionsFacet.of(options),
1698
- documentId.of(options.id),
1784
+ options.id ? documentId.of(options.id) : void 0,
1699
1785
  commentsState,
1700
1786
  commentsDecorations,
1701
1787
  handleCommentClick,
@@ -1703,17 +1789,17 @@ var comments = (options = {}) => {
1703
1789
  //
1704
1790
  // Keymap.
1705
1791
  //
1706
- options.onCreate ? keymap4.of([
1792
+ options.onCreate && keymap5.of([
1707
1793
  {
1708
1794
  key: shortcut,
1709
1795
  run: callbackWrapper(createComment)
1710
1796
  }
1711
- ]) : [],
1797
+ ]),
1712
1798
  //
1713
1799
  // Hover tooltip (for key shortcut hints, etc.)
1714
1800
  // TODO(burdon): Factor out to generic hints extension for current selection/line.
1715
1801
  //
1716
- options.onHover ? hoverTooltip((view, pos) => {
1802
+ options.onHover && hoverTooltip((view, pos) => {
1717
1803
  const selection = view.state.selection.main;
1718
1804
  if (selection && pos >= selection.from && pos <= selection.to) {
1719
1805
  return {
@@ -1738,13 +1824,13 @@ var comments = (options = {}) => {
1738
1824
  // TODO(burdon): Hide on change triggered immediately?
1739
1825
  // hideOnChange: true,
1740
1826
  hoverTime: 1e3
1741
- }) : [],
1827
+ }),
1742
1828
  //
1743
1829
  // Track deleted ranges and update ranges for decorations.
1744
1830
  //
1745
- EditorView7.updateListener.of(({ view, state: state2, changes }) => {
1831
+ EditorView8.updateListener.of(({ view, state, changes }) => {
1746
1832
  let mod = false;
1747
- const { comments: comments2, ...value } = state2.field(commentsState);
1833
+ const { comments: comments2, ...value } = state.field(commentsState);
1748
1834
  changes.iterChanges((from, to, from2, to2) => {
1749
1835
  comments2.forEach(({ comment, range }) => {
1750
1836
  if (from2 === to2) {
@@ -1774,10 +1860,10 @@ var comments = (options = {}) => {
1774
1860
  //
1775
1861
  // Track selection/proximity.
1776
1862
  //
1777
- EditorView7.updateListener.of(({ view, state: state2 }) => {
1863
+ EditorView8.updateListener.of(({ view, state }) => {
1778
1864
  let min = Infinity;
1779
- const { selection: { current, closest }, comments: comments2 } = state2.field(commentsState);
1780
- const { head } = state2.selection.main;
1865
+ const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
1866
+ const { head } = state.selection.main;
1781
1867
  const selection = {};
1782
1868
  comments2.forEach(({ comment, range }) => {
1783
1869
  if (head >= range.from && head <= range.to) {
@@ -1798,7 +1884,7 @@ var comments = (options = {}) => {
1798
1884
  });
1799
1885
  handleSelect({
1800
1886
  selection,
1801
- id: state2.facet(documentId),
1887
+ id: state.facet(documentId),
1802
1888
  comments: comments2.map(({ comment, range }) => ({
1803
1889
  comment,
1804
1890
  range,
@@ -1807,8 +1893,8 @@ var comments = (options = {}) => {
1807
1893
  });
1808
1894
  }
1809
1895
  }),
1810
- options.onUpdate ? trackPastedComments(options.onUpdate) : []
1811
- ];
1896
+ options.onUpdate && trackPastedComments(options.onUpdate)
1897
+ ].filter(nonNullable);
1812
1898
  };
1813
1899
  var scrollThreadIntoView = (view, id, center = true) => {
1814
1900
  const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
@@ -1828,7 +1914,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
1828
1914
  anchor: range.from
1829
1915
  } : void 0,
1830
1916
  effects: [
1831
- needsScroll ? EditorView7.scrollIntoView(range.from, center ? {
1917
+ needsScroll ? EditorView8.scrollIntoView(range.from, center ? {
1832
1918
  y: "center"
1833
1919
  } : void 0) : [],
1834
1920
  needsSelectionUpdate ? setSelection.of({
@@ -1839,9 +1925,12 @@ var scrollThreadIntoView = (view, id, center = true) => {
1839
1925
  }
1840
1926
  }
1841
1927
  };
1842
- var selectionOverlapsComment = (state2) => {
1843
- const { selection } = state2;
1844
- const commentState = state2.field(commentsState);
1928
+ var selectionOverlapsComment = (state) => {
1929
+ const commentState = state.field(commentsState, false);
1930
+ if (commentState === void 0) {
1931
+ return false;
1932
+ }
1933
+ const { selection } = state;
1845
1934
  for (const range of selection.ranges) {
1846
1935
  if (commentState.comments.some(({ range: commentRange }) => overlap(commentRange, range))) {
1847
1936
  return true;
@@ -1849,8 +1938,8 @@ var selectionOverlapsComment = (state2) => {
1849
1938
  }
1850
1939
  return false;
1851
1940
  };
1852
- var hasActiveSelection = (state2) => {
1853
- return state2.selection.ranges.some((range) => !range.empty);
1941
+ var hasActiveSelection = (state) => {
1942
+ return state.selection.ranges.some((range) => !range.empty);
1854
1943
  };
1855
1944
  var ExternalCommentSync = class {
1856
1945
  constructor(view, id, subscribe, getComments) {
@@ -1877,11 +1966,11 @@ var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin4.from
1877
1966
  }
1878
1967
  });
1879
1968
  var useCommentState = () => {
1880
- const [state2, setState] = useState({
1969
+ const [state, setState] = useState({
1881
1970
  comment: false,
1882
1971
  selection: false
1883
1972
  });
1884
- const observer = useMemo(() => EditorView7.updateListener.of((update2) => {
1973
+ const observer = useMemo(() => EditorView8.updateListener.of((update2) => {
1885
1974
  if (update2.docChanged || update2.selectionSet) {
1886
1975
  setState({
1887
1976
  comment: selectionOverlapsComment(update2.state),
@@ -1890,7 +1979,7 @@ var useCommentState = () => {
1890
1979
  }
1891
1980
  }), []);
1892
1981
  return [
1893
- state2,
1982
+ state,
1894
1983
  observer
1895
1984
  ];
1896
1985
  };
@@ -1909,7 +1998,7 @@ var useComments = (view, id, comments2) => {
1909
1998
  });
1910
1999
  };
1911
2000
  var useCommentClickListener = (onCommentClick) => {
1912
- return useMemo(() => EditorView7.updateListener.of((update2) => {
2001
+ return useMemo(() => EditorView8.updateListener.of((update2) => {
1913
2002
  update2.transactions.forEach((transaction) => {
1914
2003
  transaction.effects.forEach((effect) => {
1915
2004
  if (effect.is(commentClickedEffect)) {
@@ -1925,38 +2014,19 @@ var useCommentClickListener = (onCommentClick) => {
1925
2014
  // packages/ui/react-ui-editor/src/extensions/debug.ts
1926
2015
  import { syntaxTree } from "@codemirror/language";
1927
2016
  import { StateField as StateField5 } from "@codemirror/state";
1928
- var debugNodeLogger = (log9 = console.log) => {
1929
- const logTokens = (state2) => syntaxTree(state2).iterate({
1930
- enter: (node) => log9(node.type)
2017
+ var debugNodeLogger = (log8 = console.log) => {
2018
+ const logTokens = (state) => syntaxTree(state).iterate({
2019
+ enter: (node) => log8(node.type)
1931
2020
  });
1932
2021
  return StateField5.define({
1933
- create: (state2) => logTokens(state2),
2022
+ create: (state) => logTokens(state),
1934
2023
  update: (_, tr) => logTokens(tr.state)
1935
2024
  });
1936
2025
  };
1937
2026
 
1938
- // packages/ui/react-ui-editor/src/extensions/doc.ts
1939
- import { Facet as Facet5 } from "@codemirror/state";
1940
- import { invariant as invariant3 } from "@dxos/invariant";
1941
- var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/doc.ts";
1942
- var documentId2 = Facet5.define({
1943
- combine: (providers) => {
1944
- invariant3(providers.length <= 1, void 0, {
1945
- F: __dxlog_file8,
1946
- L: 14,
1947
- S: void 0,
1948
- A: [
1949
- "providers.length <= 1",
1950
- ""
1951
- ]
1952
- });
1953
- return providers[0];
1954
- }
1955
- });
1956
-
1957
2027
  // packages/ui/react-ui-editor/src/extensions/dnd.ts
1958
- import { dropCursor, EditorView as EditorView8 } from "@codemirror/view";
1959
- var styles4 = EditorView8.theme({
2028
+ import { dropCursor, EditorView as EditorView9 } from "@codemirror/view";
2029
+ var styles4 = EditorView9.theme({
1960
2030
  ".cm-dropCursor": {
1961
2031
  borderLeft: "2px solid var(--dx-accentText)",
1962
2032
  color: "var(--dx-accentText)",
@@ -1970,7 +2040,7 @@ var dropFile = (options = {}) => {
1970
2040
  return [
1971
2041
  styles4,
1972
2042
  dropCursor(),
1973
- EditorView8.domEventHandlers({
2043
+ EditorView9.domEventHandlers({
1974
2044
  drop: (event, view) => {
1975
2045
  event.preventDefault();
1976
2046
  const files = event.dataTransfer?.files;
@@ -1997,13 +2067,44 @@ import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@cod
1997
2067
  import { searchKeymap } from "@codemirror/search";
1998
2068
  import { EditorState } from "@codemirror/state";
1999
2069
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
2000
- import { EditorView as EditorView9, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap5, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2070
+ import { EditorView as EditorView11, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap6, lineNumbers, placeholder, scrollPastEnd } from "@codemirror/view";
2001
2071
  import defaultsDeep2 from "lodash.defaultsdeep";
2002
2072
  import merge from "lodash.merge";
2003
2073
  import { generateName } from "@dxos/display-name";
2004
- import { log as log6 } from "@dxos/log";
2074
+ import { log as log5 } from "@dxos/log";
2005
2075
  import { hueTokens } from "@dxos/react-ui-theme";
2006
- import { hexToHue, isNotFalsy as isNotFalsy2 } from "@dxos/util";
2076
+ import { hexToHue, isNotFalsy as isNotFalsy3 } from "@dxos/util";
2077
+
2078
+ // packages/ui/react-ui-editor/src/extensions/focus.ts
2079
+ import { StateEffect as StateEffect4, StateField as StateField6 } from "@codemirror/state";
2080
+ import { EditorView as EditorView10 } from "@codemirror/view";
2081
+ var focusEffect = StateEffect4.define();
2082
+ var focusField = StateField6.define({
2083
+ create: () => false,
2084
+ update: (value, tr) => {
2085
+ for (const effect of tr.effects) {
2086
+ if (effect.is(focusEffect)) {
2087
+ return effect.value;
2088
+ }
2089
+ }
2090
+ return value;
2091
+ }
2092
+ });
2093
+ var focus = [
2094
+ focusField,
2095
+ EditorView10.domEventHandlers({
2096
+ focus: (event, view) => {
2097
+ setTimeout(() => view.dispatch({
2098
+ effects: focusEffect.of(true)
2099
+ }));
2100
+ },
2101
+ blur: (event, view) => {
2102
+ setTimeout(() => view.dispatch({
2103
+ effects: focusEffect.of(false)
2104
+ }));
2105
+ }
2106
+ })
2107
+ ];
2007
2108
 
2008
2109
  // packages/ui/react-ui-editor/src/styles/markdown.ts
2009
2110
  import { mx } from "@dxos/react-ui-theme";
@@ -2016,11 +2117,9 @@ var headings = {
2016
2117
  6: "text-md"
2017
2118
  };
2018
2119
  var theme = {
2019
- mark: "opacity-50",
2020
2120
  code: "font-mono !no-underline text-neutral-700 dark:text-neutral-300",
2021
2121
  codeMark: "font-mono text-primary-500",
2022
- // TODO(burdon): Replace with widget.
2023
- blockquote: "pl-1 mr-1 border-is-4 border-orange-500 dark:border-orange-500 dark:text-neutral-500",
2122
+ mark: "opacity-50",
2024
2123
  heading: (level) => {
2025
2124
  return mx(headings[level], "dark:text-primary-400");
2026
2125
  }
@@ -2063,9 +2162,11 @@ var defaultTheme = {
2063
2162
  /**
2064
2163
  * Gutters
2065
2164
  * NOTE: Gutters should have the same top margin as the content.
2165
+ * NOTE: They can't be transparent since the content needs to scroll below.
2066
2166
  */
2067
2167
  ".cm-gutters": {
2068
- background: "var(--surface-bg)"
2168
+ background: "var(--surface-bg)",
2169
+ borderRight: "none"
2069
2170
  },
2070
2171
  ".cm-gutter": {},
2071
2172
  ".cm-gutter.cm-lineNumbers .cm-gutterElement": {
@@ -2086,7 +2187,7 @@ var defaultTheme = {
2086
2187
  paddingInline: 0
2087
2188
  },
2088
2189
  ".cm-activeLine": {
2089
- background: "var(--dx-hoverSurface)"
2190
+ background: "var(--dx-cmActiveLine)"
2090
2191
  },
2091
2192
  /**
2092
2193
  * Cursor (layer).
@@ -2234,7 +2335,7 @@ var defaultTheme = {
2234
2335
  };
2235
2336
 
2236
2337
  // packages/ui/react-ui-editor/src/extensions/factories.ts
2237
- var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2338
+ var __dxlog_file8 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/factories.ts";
2238
2339
  var preventNewline = EditorState.transactionFilter.of((tr) => tr.newDoc.lines > 1 ? [] : tr);
2239
2340
  var defaultBasicOptions = {
2240
2341
  allowMultipleSelections: true,
@@ -2242,6 +2343,7 @@ var defaultBasicOptions = {
2242
2343
  closeBrackets: true,
2243
2344
  drawSelection: true,
2244
2345
  editable: true,
2346
+ focus: true,
2245
2347
  history: true,
2246
2348
  keymap: "standard",
2247
2349
  lineWrapping: true,
@@ -2257,10 +2359,10 @@ var createBasicExtensions = (_props) => {
2257
2359
  const props = defaultsDeep2({}, _props, defaultBasicOptions);
2258
2360
  return [
2259
2361
  // NOTE: Doesn't catch errors in keymap functions.
2260
- EditorView9.exceptionSink.of((err) => {
2261
- log6.catch(err, void 0, {
2262
- F: __dxlog_file9,
2263
- L: 93,
2362
+ EditorView11.exceptionSink.of((err) => {
2363
+ log5.catch(err, void 0, {
2364
+ F: __dxlog_file8,
2365
+ L: 96,
2264
2366
  S: void 0,
2265
2367
  C: (f, a) => f(...a)
2266
2368
  });
@@ -2272,19 +2374,20 @@ var createBasicExtensions = (_props) => {
2272
2374
  props.drawSelection && drawSelection({
2273
2375
  cursorBlinkRate: 1200
2274
2376
  }),
2377
+ props.focus && focus,
2275
2378
  props.highlightActiveLine && highlightActiveLine(),
2276
2379
  props.history && history(),
2277
2380
  props.lineNumbers && lineNumbers(),
2278
- props.lineWrapping && EditorView9.lineWrapping,
2381
+ props.lineWrapping && EditorView11.lineWrapping,
2279
2382
  props.placeholder && placeholder(props.placeholder),
2280
2383
  props.readonly && [
2281
2384
  EditorState.readOnly.of(true),
2282
- EditorView9.editable.of(false)
2385
+ EditorView11.editable.of(false)
2283
2386
  ],
2284
2387
  props.scrollPastEnd && scrollPastEnd(),
2285
2388
  props.tabSize && EditorState.tabSize.of(props.tabSize),
2286
2389
  // https://codemirror.net/docs/ref/#view.KeyBinding
2287
- keymap5.of([
2390
+ keymap6.of([
2288
2391
  ...(props.keymap && keymaps[props.keymap]) ?? [],
2289
2392
  // NOTE: Tabs are also configured by markdown extension.
2290
2393
  // https://codemirror.net/docs/ref/#commands.indentWithTab
@@ -2297,8 +2400,8 @@ var createBasicExtensions = (_props) => {
2297
2400
  ...props.history ? historyKeymap : [],
2298
2401
  // https://codemirror.net/docs/ref/#search.searchKeymap
2299
2402
  ...props.search ? searchKeymap : []
2300
- ].filter(isNotFalsy2))
2301
- ].filter(isNotFalsy2);
2403
+ ].filter(isNotFalsy3))
2404
+ ].filter(isNotFalsy3);
2302
2405
  };
2303
2406
  var defaultThemeSlots = {
2304
2407
  editor: {
@@ -2308,17 +2411,17 @@ var defaultThemeSlots = {
2308
2411
  var createThemeExtensions = ({ themeMode, styles: styles5, syntaxHighlighting: _syntaxHighlighting, slots: _slots } = {}) => {
2309
2412
  const slots = defaultsDeep2({}, _slots, defaultThemeSlots);
2310
2413
  return [
2311
- EditorView9.darkTheme.of(themeMode === "dark"),
2312
- EditorView9.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2414
+ EditorView11.darkTheme.of(themeMode === "dark"),
2415
+ EditorView11.baseTheme(styles5 ? merge({}, defaultTheme, styles5) : defaultTheme),
2313
2416
  // https://github.com/codemirror/theme-one-dark
2314
2417
  _syntaxHighlighting && (themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)),
2315
- slots.editor?.className && EditorView9.editorAttributes.of({
2418
+ slots.editor?.className && EditorView11.editorAttributes.of({
2316
2419
  class: slots.editor.className
2317
2420
  }),
2318
- slots.content?.className && EditorView9.contentAttributes.of({
2421
+ slots.content?.className && EditorView11.contentAttributes.of({
2319
2422
  class: slots.content.className
2320
2423
  })
2321
- ].filter(isNotFalsy2);
2424
+ ].filter(isNotFalsy3);
2322
2425
  };
2323
2426
  var createDataExtensions = ({ id, text, space, identity }) => {
2324
2427
  const extensions = [];
@@ -2344,10 +2447,9 @@ var createDataExtensions = ({ id, text, space, identity }) => {
2344
2447
 
2345
2448
  // packages/ui/react-ui-editor/src/extensions/folding.tsx
2346
2449
  import { codeFolding, foldGutter } from "@codemirror/language";
2347
- import { EditorView as EditorView10 } from "@codemirror/view";
2450
+ import { EditorView as EditorView12 } from "@codemirror/view";
2348
2451
  import React2 from "react";
2349
2452
  import { Icon } from "@dxos/react-ui";
2350
- import { getSize } from "@dxos/react-ui-theme";
2351
2453
  var folding = (_props = {}) => [
2352
2454
  codeFolding({
2353
2455
  placeholderDOM: () => {
@@ -2356,22 +2458,24 @@ var folding = (_props = {}) => [
2356
2458
  }),
2357
2459
  foldGutter({
2358
2460
  markerDOM: (open) => {
2359
- return renderRoot(createElement("div", {
2461
+ const el = createElement("div", {
2360
2462
  className: "flex h-full items-center"
2361
- }), /* @__PURE__ */ React2.createElement(Icon, {
2463
+ });
2464
+ return renderRoot(el, /* @__PURE__ */ React2.createElement(Icon, {
2362
2465
  icon: "ph--caret-right--regular",
2466
+ size: 3,
2363
2467
  classNames: [
2364
- getSize(3),
2365
2468
  "mx-3 cursor-pointer",
2366
2469
  open && "rotate-90"
2367
2470
  ]
2368
2471
  }));
2369
2472
  }
2370
2473
  }),
2371
- EditorView10.theme({
2474
+ EditorView12.theme({
2372
2475
  ".cm-foldGutter": {
2373
2476
  opacity: 0.3,
2374
- transition: "opacity 0.3s"
2477
+ transition: "opacity 0.3s",
2478
+ width: "32px"
2375
2479
  },
2376
2480
  ".cm-foldGutter:hover": {
2377
2481
  opacity: 1
@@ -2380,15 +2484,15 @@ var folding = (_props = {}) => [
2380
2484
  ];
2381
2485
 
2382
2486
  // packages/ui/react-ui-editor/src/extensions/listener.ts
2383
- import { EditorView as EditorView11 } from "@codemirror/view";
2487
+ import { EditorView as EditorView13 } from "@codemirror/view";
2384
2488
  var listener = ({ onFocus, onChange }) => {
2385
2489
  const extensions = [];
2386
- onFocus && extensions.push(EditorView11.focusChangeEffect.of((_, focusing) => {
2490
+ onFocus && extensions.push(EditorView13.focusChangeEffect.of((_, focusing) => {
2387
2491
  onFocus(focusing);
2388
2492
  return null;
2389
2493
  }));
2390
- onChange && extensions.push(EditorView11.updateListener.of((update2) => {
2391
- onChange(update2.state.doc.toString());
2494
+ onChange && extensions.push(EditorView13.updateListener.of((update2) => {
2495
+ onChange(update2.state.doc.toString(), update2.state.facet(documentId));
2392
2496
  }));
2393
2497
  return extensions;
2394
2498
  };
@@ -2397,7 +2501,7 @@ var listener = ({ onFocus, onChange }) => {
2397
2501
  import { snippet } from "@codemirror/autocomplete";
2398
2502
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
2399
2503
  import { EditorSelection } from "@codemirror/state";
2400
- import { EditorView as EditorView12, keymap as keymap6 } from "@codemirror/view";
2504
+ import { EditorView as EditorView14, keymap as keymap7 } from "@codemirror/view";
2401
2505
  import { useMemo as useMemo2, useState as useState2 } from "react";
2402
2506
  var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
2403
2507
  var Inline;
@@ -2414,13 +2518,13 @@ var List;
2414
2518
  List2[List2["Task"] = 2] = "Task";
2415
2519
  })(List || (List = {}));
2416
2520
  var setHeading = (level) => {
2417
- return ({ state: state2, dispatch }) => {
2418
- const { selection: { ranges }, doc } = state2;
2521
+ return ({ state, dispatch }) => {
2522
+ const { selection: { ranges }, doc } = state;
2419
2523
  const changes = [];
2420
2524
  let prevBlock = -1;
2421
2525
  for (const range of ranges) {
2422
2526
  let sawBlock = false;
2423
- syntaxTree2(state2).iterate({
2527
+ syntaxTree2(state).iterate({
2424
2528
  from: range.from,
2425
2529
  to: range.to,
2426
2530
  enter: (node) => {
@@ -2473,7 +2577,7 @@ var setHeading = (level) => {
2473
2577
  }
2474
2578
  });
2475
2579
  let line;
2476
- if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state2.doc.lineAt(range.from)).text)) {
2580
+ if (!sawBlock && range.empty && level > 0 && !/\S/.test((line = state.doc.lineAt(range.from)).text)) {
2477
2581
  changes.push({
2478
2582
  from: line.from,
2479
2583
  to: line.to,
@@ -2484,10 +2588,10 @@ var setHeading = (level) => {
2484
2588
  if (!changes.length) {
2485
2589
  return false;
2486
2590
  }
2487
- const changeSet = state2.changes(changes);
2488
- dispatch(state2.update({
2591
+ const changeSet = state.changes(changes);
2592
+ dispatch(state.update({
2489
2593
  changes: changeSet,
2490
- selection: state2.selection.map(changeSet, 1),
2594
+ selection: state.selection.map(changeSet, 1),
2491
2595
  userEvent: "format.setHeading",
2492
2596
  scrollIntoView: true
2493
2597
  }));
@@ -2495,14 +2599,14 @@ var setHeading = (level) => {
2495
2599
  };
2496
2600
  };
2497
2601
  var setStyle = (type, enable) => {
2498
- return ({ state: state2, dispatch }) => {
2602
+ return ({ state, dispatch }) => {
2499
2603
  const marker = inlineMarkerText(type);
2500
- const changes = state2.changeByRange((range) => {
2604
+ const changes = state.changeByRange((range) => {
2501
2605
  if (!enable && range.empty) {
2502
- const after = state2.doc.sliceString(range.head, range.head + 6);
2606
+ const after = state.doc.sliceString(range.head, range.head + 6);
2503
2607
  const found = after.indexOf(marker);
2504
2608
  if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
2505
- const before = state2.doc.sliceString(range.head - 6, range.head);
2609
+ const before = state.doc.sliceString(range.head - 6, range.head);
2506
2610
  if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
2507
2611
  ...before.slice(before.length - found)
2508
2612
  ].reverse().join("") === after.slice(0, found)) {
@@ -2529,14 +2633,14 @@ var setStyle = (type, enable) => {
2529
2633
  let startCovered = false;
2530
2634
  let endCovered = false;
2531
2635
  let { from, to } = range;
2532
- syntaxTree2(state2).iterate({
2636
+ syntaxTree2(state).iterate({
2533
2637
  from,
2534
2638
  to,
2535
2639
  enter: (node) => {
2536
2640
  const { name } = node;
2537
2641
  if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
2538
2642
  blockStart = blockContentStart(node);
2539
- blockEnd = blockContentEnd(node, state2.doc);
2643
+ blockEnd = blockContentEnd(node, state.doc);
2540
2644
  startCovered = endCovered = false;
2541
2645
  } else if (name === "Link" || name === "Image" && enable) {
2542
2646
  if (from < node.from && to > node.from && to <= node.to) {
@@ -2581,7 +2685,7 @@ var setStyle = (type, enable) => {
2581
2685
  });
2582
2686
  if (markType !== type && closeStart >= to) {
2583
2687
  changesAtEnd.push({
2584
- from: skipSpaces(Math.min(to, blockEnd), state2.doc, 1, blockEnd),
2688
+ from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
2585
2689
  insert: inlineMarkerText(markType)
2586
2690
  });
2587
2691
  }
@@ -2593,7 +2697,7 @@ var setStyle = (type, enable) => {
2593
2697
  });
2594
2698
  if (markType !== type && openEnd <= from) {
2595
2699
  changes2.push({
2596
- from: skipSpaces(Math.max(from, blockStart), state2.doc, -1, blockStart),
2700
+ from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
2597
2701
  insert: inlineMarkerText(markType)
2598
2702
  });
2599
2703
  }
@@ -2623,7 +2727,7 @@ var setStyle = (type, enable) => {
2623
2727
  changes2.push(startCovered);
2624
2728
  } else if (startCovered) {
2625
2729
  changes2.push({
2626
- from: skipSpaces(rangeStart, state2.doc, -1, blockStart),
2730
+ from: skipSpaces(rangeStart, state.doc, -1, blockStart),
2627
2731
  insert: marker
2628
2732
  });
2629
2733
  }
@@ -2631,7 +2735,7 @@ var setStyle = (type, enable) => {
2631
2735
  changes2.push(endCovered);
2632
2736
  } else if (endCovered) {
2633
2737
  changes2.push({
2634
- from: skipSpaces(rangeEnd, state2.doc, 1, blockEnd),
2738
+ from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
2635
2739
  insert: marker
2636
2740
  });
2637
2741
  }
@@ -2639,7 +2743,7 @@ var setStyle = (type, enable) => {
2639
2743
  }
2640
2744
  }
2641
2745
  });
2642
- if (blockStart < 0 && range.empty && enable && !/\S/.test(state2.doc.lineAt(range.from).text)) {
2746
+ if (blockStart < 0 && range.empty && enable && !/\S/.test(state.doc.lineAt(range.from).text)) {
2643
2747
  return {
2644
2748
  changes: {
2645
2749
  from: range.head,
@@ -2648,13 +2752,13 @@ var setStyle = (type, enable) => {
2648
2752
  range: EditorSelection.cursor(range.head + marker.length)
2649
2753
  };
2650
2754
  }
2651
- const changeSet = state2.changes(changes2.concat(changesAtEnd));
2755
+ const changeSet = state.changes(changes2.concat(changesAtEnd));
2652
2756
  return {
2653
2757
  changes: changeSet,
2654
2758
  range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
2655
2759
  };
2656
2760
  });
2657
- dispatch(state2.update(changes, {
2761
+ dispatch(state.update(changes, {
2658
2762
  userEvent: enable ? "format.style.add" : "format.style.remove",
2659
2763
  scrollIntoView: true
2660
2764
  }));
@@ -2731,8 +2835,8 @@ var insertTable = (view) => {
2731
2835
  const { from } = doc.line(number);
2732
2836
  snippets.table(view, null, from, from);
2733
2837
  };
2734
- var removeLinkInner = (from, to, changes, state2) => {
2735
- syntaxTree2(state2).iterate({
2838
+ var removeLinkInner = (from, to, changes, state) => {
2839
+ syntaxTree2(state).iterate({
2736
2840
  from,
2737
2841
  to,
2738
2842
  enter: (node) => {
@@ -2746,8 +2850,8 @@ var removeLinkInner = (from, to, changes, state2) => {
2746
2850
  });
2747
2851
  } else if (name === "LinkTitle" || name === "URL") {
2748
2852
  changes.push({
2749
- from: skipSpaces(node2.from, state2.doc, -1),
2750
- to: skipSpaces(node2.to, state2.doc, 1)
2853
+ from: skipSpaces(node2.from, state.doc, -1),
2854
+ to: skipSpaces(node2.to, state.doc, 1)
2751
2855
  });
2752
2856
  }
2753
2857
  });
@@ -2756,15 +2860,15 @@ var removeLinkInner = (from, to, changes, state2) => {
2756
2860
  }
2757
2861
  });
2758
2862
  };
2759
- var removeLink = ({ state: state2, dispatch }) => {
2863
+ var removeLink = ({ state, dispatch }) => {
2760
2864
  const changes = [];
2761
- for (const { from, to } of state2.selection.ranges) {
2762
- removeLinkInner(from, to, changes, state2);
2865
+ for (const { from, to } of state.selection.ranges) {
2866
+ removeLinkInner(from, to, changes, state);
2763
2867
  }
2764
2868
  if (!changes) {
2765
2869
  return false;
2766
2870
  }
2767
- dispatch(state2.update({
2871
+ dispatch(state.update({
2768
2872
  changes,
2769
2873
  userEvent: "format.link.remove",
2770
2874
  scrollIntoView: true
@@ -2772,17 +2876,17 @@ var removeLink = ({ state: state2, dispatch }) => {
2772
2876
  return true;
2773
2877
  };
2774
2878
  var addLink = ({ url, image: image2 } = {}) => {
2775
- return ({ state: state2, dispatch }) => {
2776
- const changes = state2.changeByRange((range) => {
2879
+ return ({ state, dispatch }) => {
2880
+ const changes = state.changeByRange((range) => {
2777
2881
  let { from, to } = range;
2778
2882
  const cutStyles = [];
2779
2883
  let okay = null;
2780
- syntaxTree2(state2).iterate({
2884
+ syntaxTree2(state).iterate({
2781
2885
  from,
2782
2886
  to,
2783
2887
  enter: (node) => {
2784
2888
  if (Object.hasOwn(Textblocks, node.name)) {
2785
- okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state2.doc);
2889
+ okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
2786
2890
  } else if (Object.hasOwn(InlineMarker, node.name)) {
2787
2891
  const sNode = node.node;
2788
2892
  if (node.from < from && node.to <= to) {
@@ -2802,7 +2906,7 @@ var addLink = ({ url, image: image2 } = {}) => {
2802
2906
  }
2803
2907
  });
2804
2908
  if (okay === null) {
2805
- const line = state2.doc.lineAt(from);
2909
+ const line = state.doc.lineAt(from);
2806
2910
  okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
2807
2911
  }
2808
2912
  if (!okay) {
@@ -2812,26 +2916,26 @@ var addLink = ({ url, image: image2 } = {}) => {
2812
2916
  }
2813
2917
  const changes2 = [];
2814
2918
  const changesAfter = [];
2815
- removeLinkInner(from, to, changesAfter, state2);
2919
+ removeLinkInner(from, to, changesAfter, state);
2816
2920
  let cursorOffset = 1;
2817
2921
  for (const style of cutStyles) {
2818
2922
  const type = InlineMarker[style.name];
2819
2923
  const mark = inlineMarkerText(type);
2820
2924
  if (style.from < from) {
2821
2925
  changes2.push({
2822
- from: skipSpaces(from, state2.doc, -1),
2926
+ from: skipSpaces(from, state.doc, -1),
2823
2927
  insert: mark
2824
2928
  });
2825
2929
  changesAfter.push({
2826
- from: skipSpaces(from, state2.doc, 1, to),
2930
+ from: skipSpaces(from, state.doc, 1, to),
2827
2931
  insert: mark
2828
2932
  });
2829
2933
  } else {
2830
2934
  changes2.push({
2831
- from: skipSpaces(to, state2.doc, -1, from),
2935
+ from: skipSpaces(to, state.doc, -1, from),
2832
2936
  insert: mark
2833
2937
  });
2834
- const after = skipSpaces(to, state2.doc, 1);
2938
+ const after = skipSpaces(to, state.doc, 1);
2835
2939
  if (after === to) {
2836
2940
  cursorOffset += mark.length;
2837
2941
  }
@@ -2848,7 +2952,7 @@ var addLink = ({ url, image: image2 } = {}) => {
2848
2952
  from: to,
2849
2953
  insert: `](${url ?? ""})`
2850
2954
  });
2851
- const changeSet = state2.changes(changes2.concat(changesAfter));
2955
+ const changeSet = state.changes(changes2.concat(changesAfter));
2852
2956
  return {
2853
2957
  changes: changeSet,
2854
2958
  range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset - (url ? url.length + 2 : 0))
@@ -2857,7 +2961,7 @@ var addLink = ({ url, image: image2 } = {}) => {
2857
2961
  if (changes.changes.empty) {
2858
2962
  return false;
2859
2963
  }
2860
- dispatch(state2.update(changes, {
2964
+ dispatch(state.update(changes, {
2861
2965
  userEvent: "format.link.add",
2862
2966
  scrollIntoView: true
2863
2967
  }));
@@ -2865,14 +2969,14 @@ var addLink = ({ url, image: image2 } = {}) => {
2865
2969
  };
2866
2970
  };
2867
2971
  var addList = (type) => {
2868
- return ({ state: state2, dispatch }) => {
2972
+ return ({ state, dispatch }) => {
2869
2973
  let lastBlock = -1;
2870
2974
  let counter = 1;
2871
2975
  let first = true;
2872
2976
  let parentColumn = null;
2873
2977
  const blocks = [];
2874
- for (const { from, to } of state2.selection.ranges) {
2875
- syntaxTree2(state2).iterate({
2978
+ for (const { from, to } of state.selection.ranges) {
2979
+ syntaxTree2(state).iterate({
2876
2980
  from,
2877
2981
  to,
2878
2982
  enter: (node) => {
@@ -2884,7 +2988,7 @@ var addList = (type) => {
2884
2988
  }
2885
2989
  if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
2886
2990
  const item = before.lastChild;
2887
- const itemLine = state2.doc.lineAt(item.from);
2991
+ const itemLine = state.doc.lineAt(item.from);
2888
2992
  const itemText = itemLine.text.slice(item.from - itemLine.from);
2889
2993
  parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
2890
2994
  if (type === 0) {
@@ -2919,10 +3023,10 @@ var addList = (type) => {
2919
3023
  });
2920
3024
  }
2921
3025
  if (!blocks.length) {
2922
- const { from, to } = state2.doc.lineAt(state2.selection.main.anchor);
3026
+ const { from, to } = state.doc.lineAt(state.selection.main.anchor);
2923
3027
  if (from === to) {
2924
3028
  const insert = type === 1 ? "- " : type === 0 ? "1. " : "- [ ] ";
2925
- dispatch(state2.update({
3029
+ dispatch(state.update({
2926
3030
  changes: [
2927
3031
  {
2928
3032
  from,
@@ -2943,11 +3047,11 @@ var addList = (type) => {
2943
3047
  for (let i = 0; i < blocks.length; i++) {
2944
3048
  const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
2945
3049
  const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
2946
- let padding = nodeFrom > 0 && !/\s/.test(state2.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
3050
+ let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
2947
3051
  if (type === 0) {
2948
3052
  padding += String(counter2).length;
2949
3053
  }
2950
- let line = state2.doc.lineAt(nodeFrom);
3054
+ let line = state.doc.lineAt(nodeFrom);
2951
3055
  const column = nodeFrom - line.from;
2952
3056
  if (parentColumn2 !== null && parentColumn2 > column) {
2953
3057
  padding = Math.max(padding, parentColumn2 - column);
@@ -2972,7 +3076,7 @@ var addList = (type) => {
2972
3076
  insert: mark
2973
3077
  });
2974
3078
  while (line.to < node.to) {
2975
- line = state2.doc.lineAt(line.to + 1);
3079
+ line = state.doc.lineAt(line.to + 1);
2976
3080
  const open = /^[\s>]*/.exec(line.text)[0].length;
2977
3081
  changes.push({
2978
3082
  from: line.from + Math.min(open, column),
@@ -2987,13 +3091,13 @@ var addList = (type) => {
2987
3091
  next = next.nextSibling;
2988
3092
  }
2989
3093
  if (next?.name === "OrderedList") {
2990
- renumberListItems(next.firstChild, last.counter + 1, changes, state2.doc);
3094
+ renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
2991
3095
  }
2992
3096
  }
2993
- const changeSet = state2.changes(changes);
2994
- dispatch(state2.update({
3097
+ const changeSet = state.changes(changes);
3098
+ dispatch(state.update({
2995
3099
  changes: changeSet,
2996
- selection: state2.selection.map(changeSet, 1),
3100
+ selection: state.selection.map(changeSet, 1),
2997
3101
  userEvent: "format.list.add",
2998
3102
  scrollIntoView: true
2999
3103
  }));
@@ -3001,13 +3105,13 @@ var addList = (type) => {
3001
3105
  };
3002
3106
  };
3003
3107
  var removeList = (type) => {
3004
- return ({ state: state2, dispatch }) => {
3108
+ return ({ state, dispatch }) => {
3005
3109
  let lastBlock = -1;
3006
3110
  const changes = [];
3007
3111
  const stack = [];
3008
3112
  const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
3009
- for (const { from, to } of state2.selection.ranges) {
3010
- syntaxTree2(state2).iterate({
3113
+ for (const { from, to } of state.selection.ranges) {
3114
+ syntaxTree2(state).iterate({
3011
3115
  from,
3012
3116
  to,
3013
3117
  enter: (node) => {
@@ -3024,7 +3128,7 @@ var removeList = (type) => {
3024
3128
  stack.pop();
3025
3129
  } else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
3026
3130
  lastBlock = node.from;
3027
- let line = state2.doc.lineAt(node.from);
3131
+ let line = state.doc.lineAt(node.from);
3028
3132
  const mark = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
3029
3133
  if (!mark) {
3030
3134
  return false;
@@ -3035,7 +3139,7 @@ var removeList = (type) => {
3035
3139
  to: node.from + mark[0].length
3036
3140
  });
3037
3141
  while (line.to < node.to) {
3038
- line = state2.doc.lineAt(line.to + 1);
3142
+ line = state.doc.lineAt(line.to + 1);
3039
3143
  const open = /^[\s>]*/.exec(line.text)[0].length;
3040
3144
  if (open > column) {
3041
3145
  changes.push({
@@ -3045,7 +3149,7 @@ var removeList = (type) => {
3045
3149
  }
3046
3150
  }
3047
3151
  if (node.to >= to) {
3048
- renumberListItems(node.node.nextSibling, 1, changes, state2.doc);
3152
+ renumberListItems(node.node.nextSibling, 1, changes, state.doc);
3049
3153
  }
3050
3154
  return false;
3051
3155
  }
@@ -3055,7 +3159,7 @@ var removeList = (type) => {
3055
3159
  if (!changes.length) {
3056
3160
  return false;
3057
3161
  }
3058
- dispatch(state2.update({
3162
+ dispatch(state.update({
3059
3163
  changes,
3060
3164
  userEvent: "format.list.remove",
3061
3165
  scrollIntoView: true
@@ -3089,12 +3193,12 @@ var renumberListItems = (item, counter, changes, doc) => {
3089
3193
  }
3090
3194
  };
3091
3195
  var setBlockquote = (enable) => {
3092
- return ({ state: state2, dispatch }) => {
3196
+ return ({ state, dispatch }) => {
3093
3197
  const lines = [];
3094
3198
  let lastBlock = -1;
3095
- for (const { from, to } of state2.selection.ranges) {
3199
+ for (const { from, to } of state.selection.ranges) {
3096
3200
  const sawBlock = false;
3097
- syntaxTree2(state2).iterate({
3201
+ syntaxTree2(state).iterate({
3098
3202
  from,
3099
3203
  to,
3100
3204
  enter: (node) => {
@@ -3103,9 +3207,9 @@ var setBlockquote = (enable) => {
3103
3207
  return false;
3104
3208
  }
3105
3209
  lastBlock = node.from;
3106
- let line2 = state2.doc.lineAt(node.from);
3210
+ let line2 = state.doc.lineAt(node.from);
3107
3211
  if (line2.number > 1) {
3108
- const prevLine = state2.doc.line(line2.number - 1);
3212
+ const prevLine = state.doc.line(line2.number - 1);
3109
3213
  if (/^[>\s]*$/.test(prevLine.text)) {
3110
3214
  if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
3111
3215
  lines.push(prevLine);
@@ -3117,10 +3221,10 @@ var setBlockquote = (enable) => {
3117
3221
  if (line2.to >= node.to) {
3118
3222
  break;
3119
3223
  }
3120
- line2 = state2.doc.line(line2.number + 1);
3224
+ line2 = state.doc.line(line2.number + 1);
3121
3225
  }
3122
- if (!enable && line2.number < state2.doc.lines) {
3123
- const nextLine = state2.doc.line(line2.number + 1);
3226
+ if (!enable && line2.number < state.doc.lines) {
3227
+ const nextLine = state.doc.line(line2.number + 1);
3124
3228
  if (/^[>\s]*$/.test(nextLine.text)) {
3125
3229
  lines.push(nextLine);
3126
3230
  }
@@ -3130,7 +3234,7 @@ var setBlockquote = (enable) => {
3130
3234
  }
3131
3235
  });
3132
3236
  let line;
3133
- if (!sawBlock && enable && from === to && !/\S/.test((line = state2.doc.lineAt(from)).text)) {
3237
+ if (!sawBlock && enable && from === to && !/\S/.test((line = state.doc.lineAt(from)).text)) {
3134
3238
  lines.push(line);
3135
3239
  }
3136
3240
  }
@@ -3154,10 +3258,10 @@ var setBlockquote = (enable) => {
3154
3258
  if (!changes.length) {
3155
3259
  return false;
3156
3260
  }
3157
- const changeSet = state2.changes(changes);
3158
- dispatch(state2.update({
3261
+ const changeSet = state.changes(changes);
3262
+ dispatch(state.update({
3159
3263
  changes: changeSet,
3160
- selection: state2.selection.map(changeSet, 1),
3264
+ selection: state.selection.map(changeSet, 1),
3161
3265
  userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
3162
3266
  scrollIntoView: true
3163
3267
  }));
@@ -3170,11 +3274,11 @@ var toggleBlockquote = (target) => {
3170
3274
  return (getFormatting(target.state).blockQuote ? removeBlockquote : addBlockquote)(target);
3171
3275
  };
3172
3276
  var addCodeblock = (target) => {
3173
- const { state: state2, dispatch } = target;
3174
- const { selection } = state2;
3277
+ const { state, dispatch } = target;
3278
+ const { selection } = state;
3175
3279
  if (selection.ranges.length === 1 && selection.main.empty) {
3176
3280
  const { head } = selection.main;
3177
- const line = state2.doc.lineAt(head);
3281
+ const line = state.doc.lineAt(head);
3178
3282
  if (!/\S/.test(line.text) && head === line.from) {
3179
3283
  snippets.codeblock(target, null, line.from, line.to);
3180
3284
  return true;
@@ -3184,7 +3288,7 @@ var addCodeblock = (target) => {
3184
3288
  for (const { from, to } of selection.ranges) {
3185
3289
  let blockFrom = from;
3186
3290
  let blockTo = to;
3187
- syntaxTree2(state2).iterate({
3291
+ syntaxTree2(state).iterate({
3188
3292
  from,
3189
3293
  to,
3190
3294
  enter: (node) => {
@@ -3193,8 +3297,8 @@ var addCodeblock = (target) => {
3193
3297
  blockFrom = node.from;
3194
3298
  blockTo = node.to;
3195
3299
  } else {
3196
- blockFrom = Math.min(blockFrom, state2.doc.lineAt(node.from).from);
3197
- blockTo = Math.max(blockTo, state2.doc.lineAt(node.to).to);
3300
+ blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
3301
+ blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
3198
3302
  }
3199
3303
  }
3200
3304
  }
@@ -3212,7 +3316,7 @@ var addCodeblock = (target) => {
3212
3316
  return false;
3213
3317
  }
3214
3318
  const changes = ranges.map(({ from, to }) => {
3215
- const column = from - state2.doc.lineAt(from).from;
3319
+ const column = from - state.doc.lineAt(from).from;
3216
3320
  return [
3217
3321
  {
3218
3322
  from,
@@ -3224,30 +3328,30 @@ var addCodeblock = (target) => {
3224
3328
  }
3225
3329
  ];
3226
3330
  });
3227
- dispatch(state2.update({
3331
+ dispatch(state.update({
3228
3332
  changes,
3229
3333
  userEvent: "format.codeblock.add",
3230
3334
  scrollIntoView: true
3231
3335
  }));
3232
3336
  return true;
3233
3337
  };
3234
- var removeCodeblock = ({ state: state2, dispatch }) => {
3338
+ var removeCodeblock = ({ state, dispatch }) => {
3235
3339
  let lastBlock = -1;
3236
3340
  const changes = [];
3237
- for (const { from, to } of state2.selection.ranges) {
3238
- syntaxTree2(state2).iterate({
3341
+ for (const { from, to } of state.selection.ranges) {
3342
+ syntaxTree2(state).iterate({
3239
3343
  from,
3240
3344
  to,
3241
3345
  enter: (node) => {
3242
3346
  if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
3243
3347
  lastBlock = node.from;
3244
- const firstLine = state2.doc.lineAt(node.from);
3348
+ const firstLine = state.doc.lineAt(node.from);
3245
3349
  if (node.name === "FencedCode") {
3246
3350
  changes.push({
3247
3351
  from: node.from,
3248
3352
  to: firstLine.to + 1 + node.from - firstLine.from
3249
3353
  });
3250
- const lastLine = state2.doc.lineAt(node.to);
3354
+ const lastLine = state.doc.lineAt(node.to);
3251
3355
  if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
3252
3356
  changes.push({
3253
3357
  from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
@@ -3256,7 +3360,7 @@ var removeCodeblock = ({ state: state2, dispatch }) => {
3256
3360
  }
3257
3361
  } else {
3258
3362
  const column = node.from - firstLine.from;
3259
- for (let line = firstLine; ; line = state2.doc.line(line.number + 1)) {
3363
+ for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
3260
3364
  changes.push({
3261
3365
  from: line.from + column - 4,
3262
3366
  to: line.from + column
@@ -3273,7 +3377,7 @@ var removeCodeblock = ({ state: state2, dispatch }) => {
3273
3377
  if (!changes.length) {
3274
3378
  return false;
3275
3379
  }
3276
- dispatch(state2.update({
3380
+ dispatch(state.update({
3277
3381
  changes,
3278
3382
  userEvent: "format.codeblock.remove",
3279
3383
  scrollIntoView: true
@@ -3285,7 +3389,7 @@ var toggleCodeblock = (target) => {
3285
3389
  };
3286
3390
  var formattingKeymap = (_options = {}) => {
3287
3391
  return [
3288
- keymap6.of([
3392
+ keymap7.of([
3289
3393
  {
3290
3394
  key: "meta-b",
3291
3395
  run: toggleStrong
@@ -3336,7 +3440,7 @@ var Textblocks = {
3336
3440
  TableCell: "tablecell",
3337
3441
  Task: "paragraph"
3338
3442
  };
3339
- var getFormatting = (state2) => {
3443
+ var getFormatting = (state) => {
3340
3444
  let blockType = null;
3341
3445
  const inline = [
3342
3446
  null,
@@ -3345,7 +3449,7 @@ var getFormatting = (state2) => {
3345
3449
  null
3346
3450
  ];
3347
3451
  let link = false;
3348
- let blockQuote = null;
3452
+ let blockQuote2 = null;
3349
3453
  let listStyle = null;
3350
3454
  const stack = [];
3351
3455
  let currentBlock = null;
@@ -3362,7 +3466,7 @@ var getFormatting = (state2) => {
3362
3466
  continue;
3363
3467
  } else if (currentBlock.active[i]) {
3364
3468
  inline[i] = true;
3365
- } else if (/\S/.test(state2.doc.sliceString(currentBlock.pos, upto))) {
3469
+ } else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
3366
3470
  inline[i] = false;
3367
3471
  }
3368
3472
  }
@@ -3373,12 +3477,12 @@ var getFormatting = (state2) => {
3373
3477
  currentBlock.pos = Math.min(upto, currentBlock.end);
3374
3478
  }
3375
3479
  };
3376
- const { selection } = state2;
3480
+ const { selection } = state;
3377
3481
  for (const range of selection.ranges) {
3378
3482
  if (range.empty && inline.some((v) => v === null)) {
3379
3483
  const contextSize = Math.min(range.head, 6);
3380
- const contextBefore = state2.doc.sliceString(range.head - contextSize, range.head);
3381
- let contextAfter = state2.doc.sliceString(range.head, range.head + contextSize);
3484
+ const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
3485
+ let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
3382
3486
  for (let i = 0; i < contextSize; i++) {
3383
3487
  const ch = contextAfter[i];
3384
3488
  if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
@@ -3397,7 +3501,7 @@ var getFormatting = (state2) => {
3397
3501
  }
3398
3502
  }
3399
3503
  }
3400
- syntaxTree2(state2).iterate({
3504
+ syntaxTree2(state).iterate({
3401
3505
  from: range.from,
3402
3506
  to: range.to,
3403
3507
  enter: (node) => {
@@ -3454,10 +3558,10 @@ var getFormatting = (state2) => {
3454
3558
  hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
3455
3559
  }
3456
3560
  }
3457
- if (blockQuote === null) {
3458
- blockQuote = hasQuote;
3459
- } else if (!hasQuote && blockQuote) {
3460
- blockQuote = false;
3561
+ if (blockQuote2 === null) {
3562
+ blockQuote2 = hasQuote;
3563
+ } else if (!hasQuote && blockQuote2) {
3564
+ blockQuote2 = false;
3461
3565
  }
3462
3566
  if (listStyle === null) {
3463
3567
  listStyle = hasList;
@@ -3471,12 +3575,12 @@ var getFormatting = (state2) => {
3471
3575
  }
3472
3576
  });
3473
3577
  }
3474
- const { from, to } = state2.doc.lineAt(selection.main.anchor);
3578
+ const { from, to } = state.doc.lineAt(selection.main.anchor);
3475
3579
  const blankLine = from === to;
3476
3580
  return {
3477
3581
  blankLine,
3478
3582
  blockType: blockType || null,
3479
- blockQuote: blockQuote ?? false,
3583
+ blockQuote: blockQuote2 ?? false,
3480
3584
  code: inline[3] ?? false,
3481
3585
  emphasis: inline[1] ?? false,
3482
3586
  strong: inline[0] ?? false,
@@ -3486,8 +3590,8 @@ var getFormatting = (state2) => {
3486
3590
  };
3487
3591
  };
3488
3592
  var useFormattingState = () => {
3489
- const [state2, setState] = useState2();
3490
- const observer = useMemo2(() => EditorView12.updateListener.of((update2) => {
3593
+ const [state, setState] = useState2();
3594
+ const observer = useMemo2(() => EditorView14.updateListener.of((update2) => {
3491
3595
  if (update2.docChanged || update2.selectionSet) {
3492
3596
  setState((prevState) => {
3493
3597
  const newState = getFormatting(update2.state);
@@ -3499,7 +3603,7 @@ var useFormattingState = () => {
3499
3603
  }
3500
3604
  }), []);
3501
3605
  return [
3502
- state2,
3606
+ state,
3503
3607
  observer
3504
3608
  ];
3505
3609
  };
@@ -3560,7 +3664,7 @@ import { markdownLanguage as markdownLanguage3, markdown } from "@codemirror/lan
3560
3664
  import { syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
3561
3665
  import { languages } from "@codemirror/language-data";
3562
3666
  import { lintKeymap } from "@codemirror/lint";
3563
- import { keymap as keymap7 } from "@codemirror/view";
3667
+ import { keymap as keymap8 } from "@codemirror/view";
3564
3668
 
3565
3669
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
3566
3670
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -3727,12 +3831,6 @@ var markdownHighlightStyle = (_options = {}) => {
3727
3831
  ],
3728
3832
  class: theme.code
3729
3833
  },
3730
- {
3731
- tag: [
3732
- markdownTags.QuoteMark
3733
- ],
3734
- class: theme.blockquote
3735
- },
3736
3834
  {
3737
3835
  tag: [
3738
3836
  markdownTags.TableCell
@@ -3772,7 +3870,7 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3772
3870
  }),
3773
3871
  // Custom styles.
3774
3872
  syntaxHighlighting2(markdownHighlightStyle()),
3775
- keymap7.of([
3873
+ keymap8.of([
3776
3874
  // https://codemirror.net/docs/ref/#commands.indentWithTab
3777
3875
  indentWithTab2,
3778
3876
  // https://codemirror.net/docs/ref/#commands.defaultKeymap
@@ -3785,18 +3883,18 @@ var createMarkdownExtensions = ({ themeMode } = {}) => {
3785
3883
 
3786
3884
  // packages/ui/react-ui-editor/src/extensions/markdown/debug.ts
3787
3885
  import { syntaxTree as syntaxTree3 } from "@codemirror/language";
3788
- import { StateField as StateField6 } from "@codemirror/state";
3789
- var debugTree = (cb) => StateField6.define({
3790
- create: (state2) => cb(convertTreeToJson(state2)),
3886
+ import { StateField as StateField7 } from "@codemirror/state";
3887
+ var debugTree = (cb) => StateField7.define({
3888
+ create: (state) => cb(convertTreeToJson(state)),
3791
3889
  update: (value, tr) => cb(convertTreeToJson(tr.state))
3792
3890
  });
3793
- var convertTreeToJson = (state2) => {
3891
+ var convertTreeToJson = (state) => {
3794
3892
  const treeToJson = (cursor) => {
3795
3893
  const node = {
3796
3894
  type: cursor.type.name,
3797
3895
  from: cursor.from,
3798
3896
  to: cursor.to,
3799
- text: state2.doc.slice(cursor.from, cursor.to).toString(),
3897
+ text: state.doc.slice(cursor.from, cursor.to).toString(),
3800
3898
  children: []
3801
3899
  };
3802
3900
  if (cursor.firstChild()) {
@@ -3807,19 +3905,19 @@ var convertTreeToJson = (state2) => {
3807
3905
  }
3808
3906
  return node;
3809
3907
  };
3810
- return treeToJson(syntaxTree3(state2).cursor());
3908
+ return treeToJson(syntaxTree3(state).cursor());
3811
3909
  };
3812
3910
 
3813
3911
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
3814
3912
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3815
- import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect4 } from "@codemirror/state";
3816
- import { EditorView as EditorView16, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
3913
+ import { RangeSetBuilder as RangeSetBuilder3, StateEffect as StateEffect5 } from "@codemirror/state";
3914
+ import { EditorView as EditorView18, Decoration as Decoration7, WidgetType as WidgetType5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
3817
3915
  import { invariant as invariant4 } from "@dxos/invariant";
3818
3916
  import { mx as mx2 } from "@dxos/react-ui-theme";
3819
3917
 
3820
3918
  // packages/ui/react-ui-editor/src/extensions/markdown/changes.ts
3821
3919
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
3822
- import { Transaction } from "@codemirror/state";
3920
+ import { Transaction as Transaction2 } from "@codemirror/state";
3823
3921
  import { ViewPlugin as ViewPlugin5 } from "@codemirror/view";
3824
3922
  var adjustChanges = () => {
3825
3923
  return ViewPlugin5.fromClass(class {
@@ -3827,7 +3925,7 @@ var adjustChanges = () => {
3827
3925
  const tree = syntaxTree4(update2.state);
3828
3926
  const adjustments = [];
3829
3927
  for (const tr of update2.transactions) {
3830
- const event = tr.annotation(Transaction.userEvent);
3928
+ const event = tr.annotation(Transaction2.userEvent);
3831
3929
  switch (event) {
3832
3930
  //
3833
3931
  // Enter
@@ -3963,36 +4061,38 @@ var getValidUrl = (str) => {
3963
4061
 
3964
4062
  // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3965
4063
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3966
- import { StateField as StateField7 } from "@codemirror/state";
3967
- import { Decoration as Decoration5, EditorView as EditorView13, WidgetType as WidgetType3 } from "@codemirror/view";
4064
+ import { StateField as StateField8 } from "@codemirror/state";
4065
+ import { Decoration as Decoration5, EditorView as EditorView15, WidgetType as WidgetType3 } from "@codemirror/view";
3968
4066
  var image = (_options = {}) => {
3969
- return StateField7.define({
3970
- create: (state2) => {
3971
- return Decoration5.set(buildDecorations(0, state2.doc.length, state2));
3972
- },
3973
- update: (value, tr) => {
3974
- if (!tr.docChanged && !tr.selection) {
3975
- return value;
3976
- }
3977
- const cursor = tr.state.selection.main.head;
3978
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3979
- let from = Math.min(cursor, oldCursor);
3980
- let to = Math.max(cursor, oldCursor);
3981
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3982
- from = Math.min(from, fromB);
3983
- to = Math.max(to, toB);
3984
- });
3985
- from = tr.state.doc.lineAt(from).from;
3986
- to = tr.state.doc.lineAt(to).to;
3987
- return value.map(tr.changes).update({
3988
- filterFrom: from,
3989
- filterTo: to,
3990
- filter: () => false,
3991
- add: buildDecorations(from, to, tr.state)
3992
- });
3993
- },
3994
- provide: (field) => EditorView13.decorations.from(field)
3995
- });
4067
+ return [
4068
+ StateField8.define({
4069
+ create: (state) => {
4070
+ return Decoration5.set(buildDecorations(0, state.doc.length, state));
4071
+ },
4072
+ update: (value, tr) => {
4073
+ if (!tr.docChanged && !tr.selection) {
4074
+ return value;
4075
+ }
4076
+ const cursor = tr.state.selection.main.head;
4077
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
4078
+ let from = Math.min(cursor, oldCursor);
4079
+ let to = Math.max(cursor, oldCursor);
4080
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
4081
+ from = Math.min(from, fromB);
4082
+ to = Math.max(to, toB);
4083
+ });
4084
+ from = tr.state.doc.lineAt(from).from;
4085
+ to = tr.state.doc.lineAt(to).to;
4086
+ return value.map(tr.changes).update({
4087
+ filterFrom: from,
4088
+ filterTo: to,
4089
+ filter: () => false,
4090
+ add: buildDecorations(from, to, tr.state)
4091
+ });
4092
+ },
4093
+ provide: (field) => EditorView15.decorations.from(field)
4094
+ })
4095
+ ];
3996
4096
  };
3997
4097
  var preloaded = /* @__PURE__ */ new Set();
3998
4098
  var preloadImage = (url) => {
@@ -4002,16 +4102,19 @@ var preloadImage = (url) => {
4002
4102
  preloaded.add(url);
4003
4103
  }
4004
4104
  };
4005
- var buildDecorations = (from, to, state2) => {
4105
+ var buildDecorations = (from, to, state) => {
4006
4106
  const decorations = [];
4007
- const cursor = state2.selection.main.head;
4008
- syntaxTree5(state2).iterate({
4107
+ const cursor = state.selection.main.head;
4108
+ syntaxTree5(state).iterate({
4009
4109
  enter: (node) => {
4010
4110
  if (node.name === "Image") {
4011
4111
  const urlNode = node.node.getChild("URL");
4012
4112
  if (urlNode) {
4013
- const hide2 = state2.readOnly || cursor < node.from || cursor > node.to;
4014
- const url = state2.sliceDoc(urlNode.from, urlNode.to);
4113
+ const hide2 = state.readOnly || cursor < node.from || cursor > node.to || !state.field(focusField);
4114
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
4115
+ if (url.match(/^https?:\/\//) === null && url.match(/^file?:\/\//) === null) {
4116
+ return;
4117
+ }
4015
4118
  preloadImage(url);
4016
4119
  decorations.push(Decoration5.replace({
4017
4120
  block: true,
@@ -4037,18 +4140,20 @@ var ImageWidget = class extends WidgetType3 {
4037
4140
  const img = document.createElement("img");
4038
4141
  img.setAttribute("src", this._url);
4039
4142
  img.setAttribute("class", "cm-image");
4040
- img.onload = () => img.classList.add("cm-loaded-image");
4143
+ if (view.state.field(focusField)) {
4144
+ img.onload = () => img.classList.add("cm-loaded-image");
4145
+ } else {
4146
+ img.classList.add("cm-loaded-image");
4147
+ }
4041
4148
  return img;
4042
4149
  }
4043
4150
  };
4044
- var imageUpload = (options = {}) => {
4045
- };
4046
4151
 
4047
4152
  // packages/ui/react-ui-editor/src/extensions/markdown/styles.ts
4048
- import { EditorView as EditorView14 } from "@codemirror/view";
4153
+ import { EditorView as EditorView16 } from "@codemirror/view";
4049
4154
  var bulletListIndentationWidth = 24;
4050
4155
  var orderedListIndentationWidth = 36;
4051
- var formattingStyles = EditorView14.theme({
4156
+ var formattingStyles = EditorView16.theme({
4052
4157
  /**
4053
4158
  * Horizontal rule.
4054
4159
  */
@@ -4077,6 +4182,15 @@ var formattingStyles = EditorView14.theme({
4077
4182
  width: `${orderedListIndentationWidth}px`
4078
4183
  },
4079
4184
  /**
4185
+ * Blockquote.
4186
+ */
4187
+ "& .cm-blockquote": {
4188
+ background: "var(--dx-cmCodeblock)",
4189
+ borderLeft: "2px solid var(--dx-cmSeparator)",
4190
+ paddingLeft: "1rem",
4191
+ margin: "0"
4192
+ },
4193
+ /**
4080
4194
  * Code and codeblocks.
4081
4195
  */
4082
4196
  "& .cm-code": {
@@ -4138,25 +4252,25 @@ var formattingStyles = EditorView14.theme({
4138
4252
 
4139
4253
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
4140
4254
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4141
- import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField8 } from "@codemirror/state";
4142
- import { Decoration as Decoration6, EditorView as EditorView15, WidgetType as WidgetType4 } from "@codemirror/view";
4255
+ import { RangeSetBuilder as RangeSetBuilder2, StateField as StateField9 } from "@codemirror/state";
4256
+ import { Decoration as Decoration6, EditorView as EditorView17, WidgetType as WidgetType4 } from "@codemirror/view";
4143
4257
  var table = (options = {}) => {
4144
- return StateField8.define({
4145
- create: (state2) => update(state2, options),
4258
+ return StateField9.define({
4259
+ create: (state) => update(state, options),
4146
4260
  update: (_, tr) => update(tr.state, options),
4147
- provide: (field) => EditorView15.decorations.from(field)
4261
+ provide: (field) => EditorView17.decorations.from(field)
4148
4262
  });
4149
4263
  };
4150
- var update = (state2, _options) => {
4264
+ var update = (state, _options) => {
4151
4265
  const builder = new RangeSetBuilder2();
4152
- const cursor = state2.selection.main.head;
4266
+ const cursor = state.selection.main.head;
4153
4267
  const tables = [];
4154
4268
  const getTable = () => tables[tables.length - 1];
4155
4269
  const getRow = () => {
4156
4270
  const table2 = getTable();
4157
4271
  return table2.rows?.[table2.rows.length - 1];
4158
4272
  };
4159
- syntaxTree6(state2).iterate({
4273
+ syntaxTree6(state).iterate({
4160
4274
  enter: (node) => {
4161
4275
  switch (node.name) {
4162
4276
  case "Table": {
@@ -4177,9 +4291,9 @@ var update = (state2, _options) => {
4177
4291
  case "TableCell": {
4178
4292
  const row = getRow();
4179
4293
  if (row) {
4180
- row.push(state2.sliceDoc(node.from, node.to));
4294
+ row.push(state.sliceDoc(node.from, node.to));
4181
4295
  } else {
4182
- getTable().header?.push(state2.sliceDoc(node.from, node.to));
4296
+ getTable().header?.push(state.sliceDoc(node.from, node.to));
4183
4297
  }
4184
4298
  break;
4185
4299
  }
@@ -4187,7 +4301,7 @@ var update = (state2, _options) => {
4187
4301
  }
4188
4302
  });
4189
4303
  tables.forEach((table2) => {
4190
- const replace = state2.readOnly || cursor < table2.from || cursor > table2.to;
4304
+ const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4191
4305
  if (replace) {
4192
4306
  builder.add(table2.from, table2.to, Decoration6.replace({
4193
4307
  block: true,
@@ -4236,7 +4350,7 @@ var TableWidget = class extends WidgetType4 {
4236
4350
  };
4237
4351
 
4238
4352
  // packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts
4239
- var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts";
4353
+ var __dxlog_file9 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/markdown/decorate.ts";
4240
4354
  var Unicode = {
4241
4355
  emDash: "\u2014",
4242
4356
  bullet: "\u2022",
@@ -4259,6 +4373,7 @@ var LinkButton = class extends WidgetType5 {
4259
4373
  eq(other) {
4260
4374
  return this.url === other.url;
4261
4375
  }
4376
+ // TODO(burdon): Create icon and link directly without react?
4262
4377
  toDOM(view) {
4263
4378
  const el = document.createElement("span");
4264
4379
  this.render(el, this.url);
@@ -4326,6 +4441,9 @@ var TextWidget = class extends WidgetType5 {
4326
4441
  }
4327
4442
  };
4328
4443
  var hide = Decoration7.replace({});
4444
+ var blockQuote = Decoration7.line({
4445
+ class: mx2("cm-blockquote")
4446
+ });
4329
4447
  var fencedCodeLine = Decoration7.line({
4330
4448
  class: mx2("cm-code cm-codeblock-line")
4331
4449
  });
@@ -4347,9 +4465,9 @@ var checkedTask = Decoration7.replace({
4347
4465
  var uncheckedTask = Decoration7.replace({
4348
4466
  widget: new CheckboxWidget(false)
4349
4467
  });
4350
- var editingRange = (state2, range, focus) => {
4351
- const { readOnly, selection: { main: { head } } } = state2;
4352
- return focus && !readOnly && head >= range.from && head <= range.to;
4468
+ var editingRange = (state, range, focus2) => {
4469
+ const { readOnly, selection: { main: { head } } } = state;
4470
+ return focus2 && !readOnly && head >= range.from && head <= range.to;
4353
4471
  };
4354
4472
  var autoHideTags = /* @__PURE__ */ new Set([
4355
4473
  "CodeMark",
@@ -4359,15 +4477,15 @@ var autoHideTags = /* @__PURE__ */ new Set([
4359
4477
  "SubscriptMark",
4360
4478
  "SuperscriptMark"
4361
4479
  ]);
4362
- var buildDecorations2 = (view, options, focus) => {
4480
+ var buildDecorations2 = (view, options, focus2) => {
4363
4481
  const deco = new RangeSetBuilder3();
4364
4482
  const atomicDeco = new RangeSetBuilder3();
4365
- const { state: state2 } = view;
4483
+ const { state } = view;
4366
4484
  const headerLevels = [];
4367
4485
  const getHeaderLevels = (node, level) => {
4368
4486
  invariant4(level > 0, void 0, {
4369
- F: __dxlog_file10,
4370
- L: 176,
4487
+ F: __dxlog_file9,
4488
+ L: 178,
4371
4489
  S: void 0,
4372
4490
  A: [
4373
4491
  "level > 0",
@@ -4405,8 +4523,8 @@ var buildDecorations2 = (view, options, focus) => {
4405
4523
  };
4406
4524
  const getCurrentListLevel = () => {
4407
4525
  invariant4(listLevels.length, void 0, {
4408
- F: __dxlog_file10,
4409
- L: 198,
4526
+ F: __dxlog_file9,
4527
+ L: 200,
4410
4528
  S: void 0,
4411
4529
  A: [
4412
4530
  "listLevels.length",
@@ -4431,7 +4549,7 @@ var buildDecorations2 = (view, options, focus) => {
4431
4549
  if (options.numberedHeadings?.from !== void 0) {
4432
4550
  headers[level - 1].number++;
4433
4551
  }
4434
- const editing = editingRange(state2, node, focus);
4552
+ const editing = editingRange(state, node, focus2);
4435
4553
  if (editing) {
4436
4554
  break;
4437
4555
  }
@@ -4463,7 +4581,7 @@ var buildDecorations2 = (view, options, focus) => {
4463
4581
  break;
4464
4582
  }
4465
4583
  case "ListItem": {
4466
- const line = state2.doc.lineAt(node.from);
4584
+ const line = state.doc.lineAt(node.from);
4467
4585
  const list = getCurrentListLevel();
4468
4586
  const width = list.type === "OrderedList" ? orderedListIndentationWidth : bulletListIndentationWidth;
4469
4587
  const offset = ((list.level ?? 0) + 1) * width;
@@ -4485,23 +4603,46 @@ var buildDecorations2 = (view, options, focus) => {
4485
4603
  break;
4486
4604
  }
4487
4605
  const label = list.type === "OrderedList" ? `${++list.number}.` : Unicode.bulletSmall;
4488
- const line = state2.doc.lineAt(node.from);
4489
- const to = state2.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4606
+ const line = state.doc.lineAt(node.from);
4607
+ const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4490
4608
  atomicDeco.add(line.from, to, Decoration7.replace({
4491
4609
  widget: new TextWidget(label, list.type === "OrderedList" ? "cm-list-mark cm-list-mark-ordered" : "cm-list-mark cm-list-mark-bullet")
4492
4610
  }));
4493
4611
  break;
4494
4612
  }
4495
4613
  case "TaskMarker": {
4496
- const checked = state2.doc.sliceString(node.from + 1, node.to - 1) === "x";
4497
- const line = state2.doc.lineAt(node.from);
4498
- const to = state2.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4614
+ const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
4615
+ const line = state.doc.lineAt(node.from);
4616
+ const to = state.doc.sliceString(node.to, node.to + 1) === " " ? node.to + 1 : node.to;
4499
4617
  atomicDeco.add(line.from, to, checked ? checkedTask : uncheckedTask);
4500
4618
  break;
4501
4619
  }
4620
+ //
4621
+ // Blockquote > QuoteMark > Paragraph
4622
+ //
4623
+ case "Blockquote": {
4624
+ const editing = editingRange(state, node, focus2);
4625
+ const quoteMark = node.node.getChild("QuoteMark");
4626
+ const paragraph = node.node.getChild("Paragraph");
4627
+ if (!editing && quoteMark && paragraph) {
4628
+ atomicDeco.add(quoteMark.from, paragraph.from, hide);
4629
+ }
4630
+ for (const block of view.viewportLineBlocks) {
4631
+ if (block.to < node.from) {
4632
+ continue;
4633
+ }
4634
+ if (block.from > node.to) {
4635
+ break;
4636
+ }
4637
+ deco.add(block.from, block.from, blockQuote);
4638
+ }
4639
+ break;
4640
+ }
4641
+ //
4502
4642
  // CommentBlock
4643
+ //
4503
4644
  case "CommentBlock": {
4504
- const editing = editingRange(state2, node, focus);
4645
+ const editing = editingRange(state, node, focus2);
4505
4646
  for (const block of view.viewportLineBlocks) {
4506
4647
  if (block.to < node.from) {
4507
4648
  continue;
@@ -4509,16 +4650,18 @@ var buildDecorations2 = (view, options, focus) => {
4509
4650
  if (block.from > node.to) {
4510
4651
  break;
4511
4652
  }
4512
- const first = block.from <= node.from;
4513
- const last = block.to >= node.to && /^(\s>)*-->$/.test(state2.doc.sliceString(block.from, block.to));
4514
- deco.add(block.from, block.from, first ? commentBlockLineFirst : last ? commentBlockLineLast : commentBlockLine);
4515
- if (!editing && (first || last)) {
4653
+ const isFirst = block.from <= node.from;
4654
+ const isLast = block.to >= node.to && /^(\s>)*-->$/.test(state.doc.sliceString(block.from, block.to));
4655
+ deco.add(block.from, block.from, isFirst ? commentBlockLineFirst : isLast ? commentBlockLineLast : commentBlockLine);
4656
+ if (!editing && (isFirst || isLast)) {
4516
4657
  atomicDeco.add(block.from, block.to, hide);
4517
4658
  }
4518
4659
  }
4519
4660
  break;
4520
4661
  }
4662
+ //
4521
4663
  // FencedCode > CodeMark > [CodeInfo] > CodeText > CodeMark
4664
+ //
4522
4665
  case "FencedCode": {
4523
4666
  for (const block of view.viewportLineBlocks) {
4524
4667
  if (block.to < node.from) {
@@ -4528,22 +4671,24 @@ var buildDecorations2 = (view, options, focus) => {
4528
4671
  break;
4529
4672
  }
4530
4673
  const first = block.from <= node.from;
4531
- const last = block.to >= node.to && /^(\s>)*```$/.test(state2.doc.sliceString(block.from, block.to));
4674
+ const last = block.to >= node.to && /^(\s>)*```$/.test(state.doc.sliceString(block.from, block.to));
4532
4675
  deco.add(block.from, block.from, first ? fencedCodeLineFirst : last ? fencedCodeLineLast : fencedCodeLine);
4533
- const editing = editingRange(state2, node, focus);
4676
+ const editing = editingRange(state, node, focus2);
4534
4677
  if (!editing && (first || last)) {
4535
4678
  atomicDeco.add(block.from, block.to, hide);
4536
4679
  }
4537
4680
  }
4538
4681
  return false;
4539
4682
  }
4683
+ //
4540
4684
  // Link > [LinkMark, URL]
4685
+ //
4541
4686
  case "Link": {
4542
4687
  const marks = node.node.getChildren("LinkMark");
4543
4688
  const urlNode = node.node.getChild("URL");
4544
- const editing = editingRange(state2, node, focus);
4689
+ const editing = editingRange(state, node, focus2);
4545
4690
  if (urlNode && marks.length >= 2) {
4546
- const url = state2.sliceDoc(urlNode.from, urlNode.to);
4691
+ const url = state.sliceDoc(urlNode.from, urlNode.to);
4547
4692
  if (!editing) {
4548
4693
  atomicDeco.add(node.from, marks[0].to, hide);
4549
4694
  }
@@ -4564,16 +4709,18 @@ var buildDecorations2 = (view, options, focus) => {
4564
4709
  }
4565
4710
  break;
4566
4711
  }
4712
+ //
4567
4713
  // HR
4714
+ //
4568
4715
  case "HorizontalRule": {
4569
- if (!editingRange(state2, node, focus)) {
4716
+ if (!editingRange(state, node, focus2)) {
4570
4717
  deco.add(node.from, node.to, horizontalRule);
4571
4718
  }
4572
4719
  break;
4573
4720
  }
4574
4721
  default: {
4575
4722
  if (autoHideTags.has(node.name)) {
4576
- if (!editingRange(state2, node.node.parent, focus)) {
4723
+ if (!editingRange(state, node.node.parent, focus2)) {
4577
4724
  atomicDeco.add(node.from, node.to, hide);
4578
4725
  }
4579
4726
  }
@@ -4589,7 +4736,7 @@ var buildDecorations2 = (view, options, focus) => {
4589
4736
  }
4590
4737
  }
4591
4738
  };
4592
- const tree = syntaxTree7(state2);
4739
+ const tree = syntaxTree7(state);
4593
4740
  if (options.numberedHeadings?.from === void 0) {
4594
4741
  for (const { from, to } of view.visibleRanges) {
4595
4742
  tree.iterate({
@@ -4610,7 +4757,7 @@ var buildDecorations2 = (view, options, focus) => {
4610
4757
  atomicDeco: atomicDeco.finish()
4611
4758
  };
4612
4759
  };
4613
- var forceUpdate = StateEffect4.define();
4760
+ var forceUpdate = StateEffect5.define();
4614
4761
  var decorateMarkdown = (options = {}) => {
4615
4762
  return [
4616
4763
  ViewPlugin6.fromClass(class {
@@ -4645,9 +4792,9 @@ var decorateMarkdown = (options = {}) => {
4645
4792
  }
4646
4793
  }, {
4647
4794
  provide: (plugin) => [
4648
- EditorView16.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4649
- EditorView16.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4650
- EditorView16.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
4795
+ EditorView18.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4796
+ EditorView18.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration7.none),
4797
+ EditorView18.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration7.none)
4651
4798
  ]
4652
4799
  }),
4653
4800
  image(),
@@ -4661,40 +4808,42 @@ var decorateMarkdown = (options = {}) => {
4661
4808
  import { syntaxTree as syntaxTree8 } from "@codemirror/language";
4662
4809
  import { hoverTooltip as hoverTooltip2 } from "@codemirror/view";
4663
4810
  import { tooltipContent } from "@dxos/react-ui-theme";
4664
- var linkTooltip = (render) => hoverTooltip2((view, pos, side) => {
4665
- const syntax = syntaxTree8(view.state).resolveInner(pos, side);
4666
- let link = null;
4667
- for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
4668
- link = node.name === "Link" ? node : null;
4669
- }
4670
- const url = link && link.getChild("URL");
4671
- if (!url || !link) {
4672
- return null;
4673
- }
4674
- const urlText = view.state.sliceDoc(url.from, url.to);
4675
- return {
4676
- pos: link.from,
4677
- end: link.to,
4678
- above: true,
4679
- create: () => {
4680
- const el = document.createElement("div");
4681
- el.className = tooltipContent({}, "pli-2 plb-1");
4682
- render(el, urlText);
4683
- return {
4684
- dom: el,
4685
- offset: {
4686
- x: 0,
4687
- y: 4
4688
- }
4689
- };
4811
+ var linkTooltip = (render) => {
4812
+ return hoverTooltip2((view, pos, side) => {
4813
+ const syntax = syntaxTree8(view.state).resolveInner(pos, side);
4814
+ let link = null;
4815
+ for (let i = 0, node = syntax; !link && node && i < 5; node = node.parent, i++) {
4816
+ link = node.name === "Link" ? node : null;
4690
4817
  }
4691
- };
4692
- });
4818
+ const url = link && link.getChild("URL");
4819
+ if (!url || !link) {
4820
+ return null;
4821
+ }
4822
+ const urlText = view.state.sliceDoc(url.from, url.to);
4823
+ return {
4824
+ pos: link.from,
4825
+ end: link.to,
4826
+ above: true,
4827
+ create: () => {
4828
+ const el = document.createElement("div");
4829
+ el.className = tooltipContent({}, "pli-2 plb-1");
4830
+ render(el, urlText);
4831
+ return {
4832
+ dom: el,
4833
+ offset: {
4834
+ x: 0,
4835
+ y: 4
4836
+ }
4837
+ };
4838
+ }
4839
+ };
4840
+ });
4841
+ };
4693
4842
 
4694
4843
  // packages/ui/react-ui-editor/src/extensions/mention.ts
4695
4844
  import { autocompletion as autocompletion2 } from "@codemirror/autocomplete";
4696
- import { log as log7 } from "@dxos/log";
4697
- var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4845
+ import { log as log6 } from "@dxos/log";
4846
+ var __dxlog_file10 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/mention.ts";
4698
4847
  var mention = ({ onSearch }) => {
4699
4848
  return autocompletion2({
4700
4849
  // TODO(burdon): Not working.
@@ -4706,10 +4855,10 @@ var mention = ({ onSearch }) => {
4706
4855
  icons: false,
4707
4856
  override: [
4708
4857
  (context) => {
4709
- log7.info("completion context", {
4858
+ log6.info("completion context", {
4710
4859
  context
4711
4860
  }, {
4712
- F: __dxlog_file11,
4861
+ F: __dxlog_file10,
4713
4862
  L: 26,
4714
4863
  S: void 0,
4715
4864
  C: (f, a) => f(...a)
@@ -4730,11 +4879,9 @@ var mention = ({ onSearch }) => {
4730
4879
  };
4731
4880
 
4732
4881
  // packages/ui/react-ui-editor/src/extensions/modes.ts
4733
- import { Facet as Facet6 } from "@codemirror/state";
4734
- import { keymap as keymap8 } from "@codemirror/view";
4882
+ import { keymap as keymap9 } from "@codemirror/view";
4735
4883
  import { vim } from "@replit/codemirror-vim";
4736
4884
  import { vscodeKeymap } from "@replit/codemirror-vscode-keymap";
4737
- var focusEvent = "focus.container";
4738
4885
  var EditorViewModes = [
4739
4886
  "preview",
4740
4887
  "readonly",
@@ -4745,9 +4892,7 @@ var EditorInputModes = [
4745
4892
  "vim",
4746
4893
  "vscode"
4747
4894
  ];
4748
- var editorInputMode = Facet6.define({
4749
- combine: (modes) => modes[0] ?? {}
4750
- });
4895
+ var editorInputMode = singleValueFacet({});
4751
4896
  var InputModeExtensions = {
4752
4897
  default: [],
4753
4898
  vscode: [
@@ -4755,7 +4900,7 @@ var InputModeExtensions = {
4755
4900
  editorInputMode.of({
4756
4901
  type: "vscode"
4757
4902
  }),
4758
- keymap8.of(vscodeKeymap)
4903
+ keymap9.of(vscodeKeymap)
4759
4904
  ],
4760
4905
  vim: [
4761
4906
  // https://github.com/replit/codemirror-vim
@@ -4764,13 +4909,11 @@ var InputModeExtensions = {
4764
4909
  type: "vim",
4765
4910
  noTabster: true
4766
4911
  }),
4767
- keymap8.of([
4912
+ keymap9.of([
4768
4913
  {
4769
4914
  key: "Alt-Escape",
4770
4915
  run: (view) => {
4771
- view.dispatch({
4772
- userEvent: focusEvent
4773
- });
4916
+ view.dom.parentElement?.focus();
4774
4917
  return true;
4775
4918
  }
4776
4919
  }
@@ -4778,99 +4921,6 @@ var InputModeExtensions = {
4778
4921
  ]
4779
4922
  };
4780
4923
 
4781
- // packages/ui/react-ui-editor/src/extensions/state.ts
4782
- import { Transaction as Transaction2 } from "@codemirror/state";
4783
- import { EditorView as EditorView17, keymap as keymap9 } from "@codemirror/view";
4784
- import { debounce as debounce2 } from "@dxos/async";
4785
- import { invariant as invariant5 } from "@dxos/invariant";
4786
- import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
4787
- var __dxlog_file12 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/state.ts";
4788
- var stateRestoreAnnotation = "dxos.org/cm/state-restore";
4789
- var keyPrefix = "dxos.org/react-ui-editor/state";
4790
- var localStorageStateStoreAdapter = {
4791
- getState: (id) => {
4792
- invariant5(id, void 0, {
4793
- F: __dxlog_file12,
4794
- L: 34,
4795
- S: void 0,
4796
- A: [
4797
- "id",
4798
- ""
4799
- ]
4800
- });
4801
- const state2 = localStorage.getItem(`${keyPrefix}/${id}`);
4802
- return state2 ? JSON.parse(state2) : void 0;
4803
- },
4804
- setState: (id, state2) => {
4805
- invariant5(id, void 0, {
4806
- F: __dxlog_file12,
4807
- L: 40,
4808
- S: void 0,
4809
- A: [
4810
- "id",
4811
- ""
4812
- ]
4813
- });
4814
- localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state2));
4815
- }
4816
- };
4817
- var createEditorStateTransaction = ({ scrollTo, selection }) => {
4818
- return {
4819
- selection,
4820
- scrollIntoView: !scrollTo,
4821
- effects: scrollTo ? EditorView17.scrollIntoView(scrollTo, {
4822
- yMargin: 96
4823
- }) : void 0,
4824
- annotations: Transaction2.userEvent.of(stateRestoreAnnotation)
4825
- };
4826
- };
4827
- var state = ({ getState, setState } = {}) => {
4828
- const setStateDebounced = debounce2(setState, 1e3);
4829
- return [
4830
- // TODO(burdon): Track scrolling (currently only updates when cursor moves).
4831
- // EditorView.domEventHandlers({
4832
- // scroll: (event) => {
4833
- // setStateDebounced(id, {});
4834
- // },
4835
- // }),
4836
- EditorView17.updateListener.of(({ view, transactions }) => {
4837
- const id = view.state.facet(documentId2);
4838
- if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
4839
- return;
4840
- }
4841
- if (setState) {
4842
- const { scrollTop } = view.scrollDOM;
4843
- const pos = view.posAtCoords({
4844
- x: 0,
4845
- y: scrollTop
4846
- });
4847
- if (pos !== null) {
4848
- const { anchor, head } = view.state.selection.main;
4849
- setStateDebounced(id, {
4850
- scrollTo: pos,
4851
- selection: {
4852
- anchor,
4853
- head
4854
- }
4855
- });
4856
- }
4857
- }
4858
- }),
4859
- getState && keymap9.of([
4860
- {
4861
- key: "ctrl-r",
4862
- run: (view) => {
4863
- const state2 = getState(view.state.facet(documentId2));
4864
- if (state2) {
4865
- view.dispatch(createEditorStateTransaction(state2));
4866
- }
4867
- return true;
4868
- }
4869
- }
4870
- ])
4871
- ].filter(isNotFalsy3);
4872
- };
4873
-
4874
4924
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
4875
4925
  import { keymap as keymap10 } from "@codemirror/view";
4876
4926
  var defaultItems = [
@@ -4929,7 +4979,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
4929
4979
  };
4930
4980
 
4931
4981
  // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
4932
- var iconStyles = getSize2(5);
4982
+ var iconStyles = getSize(5);
4933
4983
  var buttonStyles = "min-bs-0 p-2";
4934
4984
  var tooltipProps = {
4935
4985
  side: "top",
@@ -4940,12 +4990,10 @@ var ToolbarSeparator = () => /* @__PURE__ */ React3.createElement("div", {
4940
4990
  className: "grow"
4941
4991
  });
4942
4992
  var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
4943
- var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
4993
+ var ToolbarRoot = ({ children, onAction, classNames, state }) => {
4944
4994
  return /* @__PURE__ */ React3.createElement(ToolbarContextProvider, {
4945
4995
  onAction,
4946
- state: state2
4947
- }, /* @__PURE__ */ React3.createElement(DensityProvider, {
4948
- density: "fine"
4996
+ state
4949
4997
  }, /* @__PURE__ */ React3.createElement(ElevationProvider, {
4950
4998
  elevation: "chrome"
4951
4999
  }, /* @__PURE__ */ React3.createElement(NaturalToolbar.Root, {
@@ -4956,7 +5004,7 @@ var ToolbarRoot = ({ children, onAction, classNames, state: state2 }) => {
4956
5004
  style: {
4957
5005
  contain: "layout"
4958
5006
  }
4959
- }, children))));
5007
+ }, children)));
4960
5008
  };
4961
5009
  var ToolbarToggleButton = ({ Icon: Icon2, children, ...props }) => {
4962
5010
  return /* @__PURE__ */ React3.createElement(Tooltip.Root, null, /* @__PURE__ */ React3.createElement(Tooltip.Trigger, {
@@ -4995,8 +5043,8 @@ var HeadingIcons = {
4995
5043
  };
4996
5044
  var MarkdownHeading = () => {
4997
5045
  const { t } = useTranslation(translationKey);
4998
- const { onAction, state: state2 } = useToolbarContext("MarkdownFormatting");
4999
- const blockType = state2 ? state2.blockType : "paragraph";
5046
+ const { onAction, state } = useToolbarContext("MarkdownFormatting");
5047
+ const blockType = state ? state.blockType : "paragraph";
5000
5048
  const header = blockType && /heading(\d)/.exec(blockType);
5001
5049
  const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : void 0;
5002
5050
  const HeadingIcon = HeadingIcons[value ?? "0"];
@@ -5060,43 +5108,43 @@ var markdownStyles = [
5060
5108
  {
5061
5109
  type: "strong",
5062
5110
  Icon: TextB,
5063
- getState: (state2) => !!state2?.strong
5111
+ getState: (state) => !!state?.strong
5064
5112
  },
5065
5113
  {
5066
5114
  type: "emphasis",
5067
5115
  Icon: TextItalic,
5068
- getState: (state2) => !!state2?.emphasis
5116
+ getState: (state) => !!state?.emphasis
5069
5117
  },
5070
5118
  {
5071
5119
  type: "strikethrough",
5072
5120
  Icon: TextStrikethrough,
5073
- getState: (state2) => !!state2?.strikethrough
5121
+ getState: (state) => !!state?.strikethrough
5074
5122
  },
5075
5123
  {
5076
5124
  type: "code",
5077
5125
  Icon: Code,
5078
- getState: (state2) => !!state2?.code
5126
+ getState: (state) => !!state?.code
5079
5127
  },
5080
5128
  {
5081
5129
  type: "link",
5082
5130
  Icon: Link,
5083
- getState: (state2) => !!state2?.link
5131
+ getState: (state) => !!state?.link
5084
5132
  }
5085
5133
  ];
5086
5134
  var MarkdownStyles = () => {
5087
- const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
5135
+ const { onAction, state } = useToolbarContext("MarkdownStyles");
5088
5136
  const { t } = useTranslation(translationKey);
5089
5137
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5090
5138
  type: "multiple",
5091
- value: markdownStyles.filter(({ getState }) => state2 && getState(state2)).map(({ type }) => type)
5139
+ value: markdownStyles.filter(({ getState }) => state && getState(state)).map(({ type }) => type)
5092
5140
  }, markdownStyles.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5093
5141
  key: type,
5094
5142
  value: type,
5095
5143
  Icon: Icon2,
5096
- disabled: state2?.blockType === "codeblock",
5097
- onClick: state2 ? () => onAction?.({
5144
+ disabled: state?.blockType === "codeblock",
5145
+ onClick: state ? () => onAction?.({
5098
5146
  type,
5099
- data: !getState(state2)
5147
+ data: !getState(state)
5100
5148
  }) : void 0
5101
5149
  }, t(`${type} label`))));
5102
5150
  };
@@ -5104,32 +5152,32 @@ var markdownLists = [
5104
5152
  {
5105
5153
  type: "list-bullet",
5106
5154
  Icon: ListBullets,
5107
- getState: (state2) => state2.listStyle === "bullet"
5155
+ getState: (state) => state.listStyle === "bullet"
5108
5156
  },
5109
5157
  {
5110
5158
  type: "list-ordered",
5111
5159
  Icon: ListNumbers,
5112
- getState: (state2) => state2.listStyle === "ordered"
5160
+ getState: (state) => state.listStyle === "ordered"
5113
5161
  },
5114
5162
  {
5115
5163
  type: "list-task",
5116
5164
  Icon: ListChecks,
5117
- getState: (state2) => state2.listStyle === "task"
5165
+ getState: (state) => state.listStyle === "task"
5118
5166
  }
5119
5167
  ];
5120
5168
  var MarkdownLists = () => {
5121
- const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
5169
+ const { onAction, state } = useToolbarContext("MarkdownStyles");
5122
5170
  const { t } = useTranslation(translationKey);
5123
5171
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5124
5172
  type: "single",
5125
- value: state2?.listStyle ? `list-${state2.listStyle}` : ""
5173
+ value: state?.listStyle ? `list-${state.listStyle}` : ""
5126
5174
  }, markdownLists.map(({ type, getState, Icon: Icon2 }) => /* @__PURE__ */ React3.createElement(ToolbarToggleButton, {
5127
5175
  key: type,
5128
5176
  value: type,
5129
5177
  Icon: Icon2,
5130
- onClick: state2 ? () => onAction?.({
5178
+ onClick: state ? () => onAction?.({
5131
5179
  type,
5132
- data: !getState(state2)
5180
+ data: !getState(state)
5133
5181
  }) : void 0
5134
5182
  }, t(`${type} label`))));
5135
5183
  };
@@ -5137,24 +5185,24 @@ var markdownBlocks = [
5137
5185
  {
5138
5186
  type: "blockquote",
5139
5187
  Icon: Quotes,
5140
- getState: (state2) => !!state2?.blockQuote
5188
+ getState: (state) => !!state?.blockQuote
5141
5189
  },
5142
5190
  {
5143
5191
  type: "codeblock",
5144
5192
  Icon: CodeBlock,
5145
- getState: (state2) => state2.blockType === "codeblock"
5193
+ getState: (state) => state.blockType === "codeblock"
5146
5194
  },
5147
5195
  {
5148
5196
  type: "table",
5149
5197
  Icon: Table2,
5150
- getState: (state2) => state2.blockType === "tablecell",
5151
- disabled: (state2) => !state2.blankLine
5198
+ getState: (state) => state.blockType === "tablecell",
5199
+ disabled: (state) => !state.blankLine
5152
5200
  }
5153
5201
  ];
5154
5202
  var MarkdownBlocks = () => {
5155
- const { onAction, state: state2 } = useToolbarContext("MarkdownStyles");
5203
+ const { onAction, state } = useToolbarContext("MarkdownStyles");
5156
5204
  const { t } = useTranslation(translationKey);
5157
- const value = markdownBlocks.find(({ getState }) => state2 && getState(state2));
5205
+ const value = markdownBlocks.find(({ getState }) => state && getState(state));
5158
5206
  return /* @__PURE__ */ React3.createElement(NaturalToolbar.ToggleGroup, {
5159
5207
  type: "single",
5160
5208
  value: value?.type ?? ""
@@ -5162,10 +5210,10 @@ var MarkdownBlocks = () => {
5162
5210
  key: type,
5163
5211
  value: type,
5164
5212
  Icon: Icon2,
5165
- disabled: !state2 || disabled?.(state2),
5166
- onClick: state2 ? () => onAction?.({
5213
+ disabled: !state || disabled?.(state),
5214
+ onClick: state ? () => onAction?.({
5167
5215
  type,
5168
- data: !getState(state2)
5216
+ data: !getState(state)
5169
5217
  }) : void 0
5170
5218
  }, t(`${type} label`))));
5171
5219
  };
@@ -5278,12 +5326,12 @@ var MarkdownView = ({ mode }) => {
5278
5326
  })), /* @__PURE__ */ React3.createElement(DropdownMenu.Arrow, null)))), /* @__PURE__ */ React3.createElement(Tooltip.Portal, null, /* @__PURE__ */ React3.createElement(Tooltip.Content, tooltipProps, t("view mode label"), /* @__PURE__ */ React3.createElement(Tooltip.Arrow, null))));
5279
5327
  };
5280
5328
  var MarkdownActions = () => {
5281
- const { onAction, state: state2 } = useToolbarContext("MarkdownActions");
5329
+ const { onAction, state } = useToolbarContext("MarkdownActions");
5282
5330
  const { t } = useTranslation(translationKey);
5283
5331
  let commentToolTipKey = "comment label";
5284
- if (state2?.comment) {
5332
+ if (state?.comment) {
5285
5333
  commentToolTipKey = "selection overlaps existing comment label";
5286
- } else if (state2?.selection === false) {
5334
+ } else if (state?.selection === false) {
5287
5335
  commentToolTipKey = "select text to comment label";
5288
5336
  }
5289
5337
  return /* @__PURE__ */ React3.createElement(React3.Fragment, null, /* @__PURE__ */ React3.createElement(ToolbarButton, {
@@ -5299,7 +5347,7 @@ var MarkdownActions = () => {
5299
5347
  onClick: () => onAction?.({
5300
5348
  type: "comment"
5301
5349
  }),
5302
- disabled: !state2 || state2.comment || !state2.selection
5350
+ disabled: !state || state.comment || !state.selection
5303
5351
  }, t(commentToolTipKey)));
5304
5352
  };
5305
5353
  var Toolbar = {
@@ -5313,20 +5361,20 @@ var Toolbar = {
5313
5361
  };
5314
5362
 
5315
5363
  // packages/ui/react-ui-editor/src/defaults.ts
5316
- import { EditorView as EditorView18 } from "@codemirror/view";
5364
+ import { EditorView as EditorView19 } from "@codemirror/view";
5317
5365
  import { mx as mx3 } from "@dxos/react-ui-theme";
5318
5366
  var margin = "!mt-[1rem]";
5319
5367
  var editorContent = mx3(margin, "!mli-auto w-full max-w-[min(50rem,100%-2rem)]");
5320
5368
  var editorFullWidth = mx3(margin);
5321
5369
  var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
5322
- var editorGutter = EditorView18.theme({
5370
+ var editorGutter = EditorView19.theme({
5323
5371
  // Match margin from content.
5324
5372
  ".cm-gutters": {
5325
5373
  marginTop: "16px",
5326
5374
  paddingRight: "1rem"
5327
5375
  }
5328
5376
  });
5329
- var editorMonospace = EditorView18.theme({
5377
+ var editorMonospace = EditorView19.theme({
5330
5378
  ".cm-content": {
5331
5379
  fontFamily: fontMono
5332
5380
  }
@@ -5339,29 +5387,28 @@ var useActionHandler = (view) => {
5339
5387
 
5340
5388
  // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
5341
5389
  import { EditorState as EditorState2 } from "@codemirror/state";
5342
- import { EditorView as EditorView19 } from "@codemirror/view";
5390
+ import { EditorView as EditorView20 } from "@codemirror/view";
5343
5391
  import { useFocusableGroup } from "@fluentui/react-tabster";
5344
5392
  import { useCallback, useEffect as useEffect3, useMemo as useMemo3, useRef as useRef2, useState as useState4 } from "react";
5345
- import { log as log8 } from "@dxos/log";
5393
+ import { log as log7 } from "@dxos/log";
5346
5394
  import { getProviderValue, isNotFalsy as isNotFalsy4 } from "@dxos/util";
5347
- var __dxlog_file13 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5395
+ var __dxlog_file11 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
5348
5396
  var instanceCount = 0;
5349
5397
  var useTextEditor = (props = {}, deps = []) => {
5350
5398
  const { id, initialValue, extensions, autoFocus, scrollTo, selection, moveToEndOfLine, debug } = useMemo3(() => getProviderValue(props), deps ?? []);
5351
5399
  const [instanceId] = useState4(() => `text-editor-${++instanceCount}`);
5352
- const onUpdate = useRef2();
5353
5400
  const [view, setView] = useState4();
5354
5401
  const parentRef = useRef2(null);
5355
5402
  useEffect3(() => {
5356
5403
  let view2;
5357
5404
  if (parentRef.current) {
5358
- log8("create", {
5405
+ log7("create", {
5359
5406
  id,
5360
5407
  instanceId,
5361
5408
  doc: initialValue?.length ?? 0
5362
5409
  }, {
5363
- F: __dxlog_file13,
5364
- L: 76,
5410
+ F: __dxlog_file11,
5411
+ L: 75,
5365
5412
  S: void 0,
5366
5413
  C: (f, a) => f(...a)
5367
5414
  });
@@ -5377,56 +5424,48 @@ var useTextEditor = (props = {}, deps = []) => {
5377
5424
  anchor
5378
5425
  };
5379
5426
  }
5380
- const state2 = EditorState2.create({
5427
+ const state = EditorState2.create({
5381
5428
  doc: initialValue,
5382
- selection: initialSelection,
5429
+ // selection: initialSelection,
5383
5430
  extensions: [
5384
- id && documentId2.of(id),
5385
- // NOTE: Doesn't catch errors in keymap functions.
5386
- EditorView19.exceptionSink.of((err) => {
5387
- log8.catch(err, void 0, {
5388
- F: __dxlog_file13,
5389
- L: 98,
5431
+ id && documentId.of(id),
5432
+ extensions,
5433
+ // NOTE: This doesn't catch errors in keymap functions.
5434
+ EditorView20.exceptionSink.of((err) => {
5435
+ log7.catch(err, void 0, {
5436
+ F: __dxlog_file11,
5437
+ L: 97,
5390
5438
  S: void 0,
5391
5439
  C: (f, a) => f(...a)
5392
5440
  });
5393
- }),
5394
- extensions,
5395
- EditorView19.updateListener.of(() => {
5396
- setTimeout(() => {
5397
- onUpdate.current?.();
5398
- });
5399
5441
  })
5400
5442
  ].filter(isNotFalsy4)
5401
5443
  });
5402
- view2 = new EditorView19({
5444
+ view2 = new EditorView20({
5403
5445
  parent: parentRef.current,
5404
- selection: initialSelection,
5405
- state: state2,
5406
- // NOTE: Uncomment to debug/monitor all transactions.
5407
- // https://codemirror.net/docs/ref/#view.EditorView.dispatch
5408
- dispatchTransactions: (trs, view3) => {
5409
- if (debug) {
5410
- logChanges(trs);
5411
- }
5412
- view3.update(trs);
5413
- }
5446
+ state,
5447
+ scrollTo: scrollTo ? EditorView20.scrollIntoView(scrollTo, {
5448
+ yMargin: 96
5449
+ }) : void 0,
5450
+ dispatchTransactions: debug ? debugDispatcher : void 0
5414
5451
  });
5415
- if (!initialValue && moveToEndOfLine) {
5452
+ if (moveToEndOfLine && !initialSelection) {
5416
5453
  const { to } = view2.state.doc.lineAt(0);
5417
- view2.dispatch({
5418
- selection: {
5419
- anchor: to
5420
- }
5421
- });
5454
+ if (to) {
5455
+ view2.dispatch({
5456
+ selection: {
5457
+ anchor: to
5458
+ }
5459
+ });
5460
+ }
5422
5461
  }
5423
5462
  setView(view2);
5424
5463
  }
5425
5464
  return () => {
5426
- log8("destroy", {
5465
+ log7("destroy", {
5427
5466
  id
5428
5467
  }, {
5429
- F: __dxlog_file13,
5468
+ F: __dxlog_file11,
5430
5469
  L: 134,
5431
5470
  S: void 0,
5432
5471
  C: (f, a) => f(...a)
@@ -5436,21 +5475,30 @@ var useTextEditor = (props = {}, deps = []) => {
5436
5475
  }, deps);
5437
5476
  useEffect3(() => {
5438
5477
  if (view) {
5439
- onUpdate.current = () => {
5440
- onUpdate.current = void 0;
5478
+ if (scrollTo || selection) {
5479
+ if (selection && selection.anchor > view.state.doc.length) {
5480
+ log7.warn("invalid selection", {
5481
+ length: view.state.doc.length,
5482
+ scrollTo,
5483
+ selection
5484
+ }, {
5485
+ F: __dxlog_file11,
5486
+ L: 143,
5487
+ S: void 0,
5488
+ C: (f, a) => f(...a)
5489
+ });
5490
+ return;
5491
+ }
5441
5492
  view.dispatch(createEditorStateTransaction({
5442
5493
  scrollTo,
5443
5494
  selection
5444
5495
  }));
5445
- };
5446
- if (view.state.facet(editorInputMode).noTabster) {
5447
- parentRef.current?.removeAttribute("data-tabster");
5448
5496
  }
5449
5497
  }
5450
5498
  }, [
5451
5499
  view,
5452
- selection,
5453
- scrollTo
5500
+ scrollTo,
5501
+ selection
5454
5502
  ]);
5455
5503
  useEffect3(() => {
5456
5504
  if (view && autoFocus) {
@@ -5461,7 +5509,10 @@ var useTextEditor = (props = {}, deps = []) => {
5461
5509
  view
5462
5510
  ]);
5463
5511
  const focusableGroup = useFocusableGroup({
5464
- tabBehavior: "limited"
5512
+ tabBehavior: "limited",
5513
+ ignoreDefaultKeydown: {
5514
+ Escape: view?.state.facet(editorInputMode).noTabster
5515
+ }
5465
5516
  });
5466
5517
  const handleKeyUp = useCallback((event) => {
5467
5518
  const { key, target, currentTarget } = event;
@@ -5510,6 +5561,7 @@ export {
5510
5561
  awarenessProvider,
5511
5562
  blast,
5512
5563
  callbackWrapper,
5564
+ clientRectsFor,
5513
5565
  command,
5514
5566
  comments,
5515
5567
  commentsState,
@@ -5517,15 +5569,18 @@ export {
5517
5569
  createBasicExtensions,
5518
5570
  createComment,
5519
5571
  createDataExtensions,
5572
+ createEditorStateStore,
5520
5573
  createEditorStateTransaction,
5574
+ createElement,
5521
5575
  createExternalCommentSync,
5522
5576
  createMarkdownExtensions,
5523
5577
  createThemeExtensions,
5578
+ debugDispatcher,
5524
5579
  debugNodeLogger,
5525
5580
  debugTree,
5526
5581
  decorateMarkdown,
5527
5582
  defaultOptions,
5528
- documentId2 as documentId,
5583
+ documentId,
5529
5584
  dropFile,
5530
5585
  editorContent,
5531
5586
  editorFullWidth,
@@ -5533,23 +5588,24 @@ export {
5533
5588
  editorInputMode,
5534
5589
  editorMonospace,
5535
5590
  editorWithToolbarLayout,
5536
- focusEvent,
5591
+ flattenRect,
5592
+ focus,
5593
+ focusField,
5537
5594
  folding,
5538
5595
  formattingEquals,
5539
5596
  formattingKeymap,
5540
5597
  getFormatting,
5541
5598
  image,
5542
- imageUpload,
5543
5599
  insertTable,
5544
5600
  keymap11 as keymap,
5545
5601
  linkTooltip,
5546
5602
  listener,
5547
- localStorageStateStoreAdapter,
5548
5603
  logChanges,
5549
5604
  markdownHighlightStyle,
5550
5605
  markdownTags,
5551
5606
  markdownTagsExtensions,
5552
5607
  mention,
5608
+ overlap,
5553
5609
  preventNewline,
5554
5610
  processAction,
5555
5611
  removeBlockquote,
@@ -5557,16 +5613,19 @@ export {
5557
5613
  removeLink,
5558
5614
  removeList,
5559
5615
  removeStyle,
5616
+ renderRoot,
5560
5617
  scrollThreadIntoView,
5561
5618
  selectionOverlapsComment,
5619
+ selectionState,
5562
5620
  setBlockquote,
5563
5621
  setComments,
5564
5622
  setHeading,
5565
5623
  setSelection,
5566
5624
  setStyle,
5567
- state,
5625
+ singleValueFacet,
5568
5626
  table,
5569
5627
  tags2 as tags,
5628
+ textRange,
5570
5629
  toggleBlockquote,
5571
5630
  toggleCodeblock,
5572
5631
  toggleEmphasis,
@@ -5583,6 +5642,7 @@ export {
5583
5642
  useComments,
5584
5643
  useFormattingState,
5585
5644
  useTextEditor,
5586
- useToolbarContext
5645
+ useToolbarContext,
5646
+ wrapWithCatch
5587
5647
  };
5588
5648
  //# sourceMappingURL=index.mjs.map