@dxos/react-ui-editor 0.3.11-main.674a7f9 → 0.3.11-main.6901f09

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 (103) hide show
  1. package/dist/lib/browser/index.mjs +1994 -433
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts +1 -2
  5. package/dist/types/src/components/TextEditor/MarkdownEditor.stories.d.ts.map +1 -1
  6. package/dist/types/src/components/TextEditor/TextEditor.d.ts.map +1 -1
  7. package/dist/types/src/components/TextEditor/TextEditor.stories.d.ts +1 -1
  8. package/dist/types/src/components/TextEditor/automerge.stories.d.ts.map +1 -1
  9. package/dist/types/src/components/TextEditor/{comments.stories.d.ts → hooks.stories.d.ts} +9 -12
  10. package/dist/types/src/components/TextEditor/hooks.stories.d.ts.map +1 -0
  11. package/dist/types/src/components/Toolbar/Toolbar.d.ts +29 -0
  12. package/dist/types/src/components/Toolbar/Toolbar.d.ts.map +1 -0
  13. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts +25 -0
  14. package/dist/types/src/components/Toolbar/Toolbar.stories.d.ts.map +1 -0
  15. package/dist/types/src/components/Toolbar/index.d.ts +2 -0
  16. package/dist/types/src/components/Toolbar/index.d.ts.map +1 -0
  17. package/dist/types/src/components/index.d.ts +1 -0
  18. package/dist/types/src/components/index.d.ts.map +1 -1
  19. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/automerge.spec.d.ts +2 -0
  21. package/dist/types/src/extensions/automerge/automerge.spec.d.ts.map +1 -0
  22. package/dist/types/src/extensions/automerge/automerge.test.d.ts +2 -0
  23. package/dist/types/src/extensions/automerge/automerge.test.d.ts.map +1 -0
  24. package/dist/types/src/extensions/automerge/defs.d.ts +5 -5
  25. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  26. package/dist/types/src/extensions/automerge/semaphore.d.ts +2 -1
  27. package/dist/types/src/extensions/automerge/semaphore.d.ts.map +1 -1
  28. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  29. package/dist/types/src/extensions/awareness.d.ts +1 -1
  30. package/dist/types/src/extensions/basic.d.ts +1 -1
  31. package/dist/types/src/extensions/basic.d.ts.map +1 -1
  32. package/dist/types/src/extensions/comments.d.ts +11 -3
  33. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  34. package/dist/types/src/extensions/markdown/bundle.d.ts +2 -2
  35. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  36. package/dist/types/src/extensions/markdown/code.d.ts.map +1 -1
  37. package/dist/types/src/extensions/markdown/formatting.d.ts +57 -0
  38. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -0
  39. package/dist/types/src/extensions/markdown/formatting.test.d.ts +3 -0
  40. package/dist/types/src/extensions/markdown/formatting.test.d.ts.map +1 -0
  41. package/dist/types/src/extensions/markdown/heading.d.ts.map +1 -1
  42. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/hr.d.ts.map +1 -1
  44. package/dist/types/src/extensions/markdown/index.d.ts +1 -0
  45. package/dist/types/src/extensions/markdown/index.d.ts.map +1 -1
  46. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  47. package/dist/types/src/extensions/markdown/tasklist.d.ts.map +1 -1
  48. package/dist/types/src/hooks/index.d.ts +2 -0
  49. package/dist/types/src/hooks/index.d.ts.map +1 -1
  50. package/dist/types/src/hooks/useActionHandler.d.ts +4 -0
  51. package/dist/types/src/hooks/useActionHandler.d.ts.map +1 -0
  52. package/dist/types/src/hooks/useEditorView.d.ts +17 -0
  53. package/dist/types/src/hooks/useEditorView.d.ts.map +1 -0
  54. package/dist/types/src/hooks/useTextEditor.d.ts +36 -14
  55. package/dist/types/src/hooks/useTextEditor.d.ts.map +1 -1
  56. package/dist/types/src/hooks/useTextModel.d.ts +12 -0
  57. package/dist/types/src/hooks/useTextModel.d.ts.map +1 -1
  58. package/dist/types/src/index.d.ts +1 -1
  59. package/dist/types/src/index.d.ts.map +1 -1
  60. package/dist/types/src/styles/markdown.d.ts +2 -2
  61. package/dist/types/src/styles/markdown.d.ts.map +1 -1
  62. package/dist/types/src/themes/default.d.ts.map +1 -1
  63. package/package.json +40 -27
  64. package/src/components/TextEditor/MarkdownEditor.stories.tsx +15 -21
  65. package/src/components/TextEditor/TextEditor.tsx +27 -16
  66. package/src/components/TextEditor/automerge.stories.tsx +1 -2
  67. package/src/components/TextEditor/hooks.stories.tsx +111 -0
  68. package/src/components/Toolbar/Toolbar.stories.tsx +102 -0
  69. package/src/components/Toolbar/Toolbar.tsx +245 -0
  70. package/src/components/Toolbar/index.ts +5 -0
  71. package/src/components/index.ts +1 -0
  72. package/src/extensions/automerge/automerge.spec.tsx +76 -0
  73. package/src/extensions/automerge/automerge.test.ts +13 -0
  74. package/src/extensions/automerge/automerge.ts +26 -11
  75. package/src/extensions/automerge/cursor.ts +3 -3
  76. package/src/extensions/automerge/defs.ts +9 -9
  77. package/src/extensions/automerge/semaphore.ts +17 -19
  78. package/src/extensions/automerge/update-automerge.ts +12 -6
  79. package/src/extensions/automerge/update-codemirror.ts +5 -5
  80. package/src/extensions/awareness.ts +7 -4
  81. package/src/extensions/basic.ts +15 -13
  82. package/src/extensions/blast.ts +4 -1
  83. package/src/extensions/comments.ts +126 -68
  84. package/src/extensions/markdown/bundle.ts +9 -8
  85. package/src/extensions/markdown/code.ts +95 -49
  86. package/src/extensions/markdown/formatting.test.ts +481 -0
  87. package/src/extensions/markdown/formatting.ts +1198 -0
  88. package/src/extensions/markdown/heading.ts +5 -6
  89. package/src/extensions/markdown/highlight.ts +9 -15
  90. package/src/extensions/markdown/hr.ts +2 -3
  91. package/src/extensions/markdown/index.ts +1 -0
  92. package/src/extensions/markdown/link.ts +13 -4
  93. package/src/extensions/markdown/tasklist.ts +1 -2
  94. package/src/hooks/index.ts +2 -0
  95. package/src/hooks/useActionHandler.ts +93 -0
  96. package/src/hooks/useEditorView.ts +29 -0
  97. package/src/hooks/useTextEditor.ts +143 -19
  98. package/src/hooks/useTextModel.ts +28 -9
  99. package/src/index.ts +1 -1
  100. package/src/styles/markdown.ts +9 -10
  101. package/src/themes/default.ts +11 -8
  102. package/dist/types/src/components/TextEditor/comments.stories.d.ts.map +0 -1
  103. package/src/components/TextEditor/comments.stories.tsx +0 -357
@@ -1,20 +1,21 @@
1
1
  // packages/ui/react-ui-editor/src/index.ts
2
2
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
3
3
  import { Doc, YText, YXmlFragment } from "@dxos/text-model";
4
+ import { keymap as keymap7 } from "@codemirror/view";
4
5
 
5
6
  // packages/ui/react-ui-editor/src/components/TextEditor/index.ts
6
7
  import { tags as tags2 } from "@lezer/highlight";
7
8
 
8
9
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
9
10
  import { EditorState as EditorState2 } from "@codemirror/state";
10
- import { EditorView as EditorView13 } from "@codemirror/view";
11
- import { useFocusableGroup } from "@fluentui/react-tabster";
11
+ import { EditorView as EditorView14 } from "@codemirror/view";
12
12
  import { vim } from "@replit/codemirror-vim";
13
13
  import defaultsDeep2 from "lodash.defaultsdeep";
14
- import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState } from "react";
14
+ import React, { forwardRef, useCallback, useEffect as useEffect2, useImperativeHandle, useRef, useState as useState2 } from "react";
15
15
  import { log as log2 } from "@dxos/log";
16
16
  import { useThemeContext } from "@dxos/react-ui";
17
- import { attentionSurface, mx as mx3 } from "@dxos/react-ui-theme";
17
+ import { focusRing, mx as mx3 } from "@dxos/react-ui-theme";
18
+ import { isNotFalsy as isNotFalsy3 } from "@dxos/util";
18
19
 
19
20
  // packages/ui/react-ui-editor/src/extensions/autocomplete.ts
20
21
  import { autocompletion, completionKeymap } from "@codemirror/autocomplete";
@@ -53,14 +54,14 @@ var autocomplete = ({ onSearch }) => {
53
54
  };
54
55
 
55
56
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
57
+ import { invertedEffects } from "@codemirror/commands";
56
58
  import { StateField } from "@codemirror/state";
57
59
  import { EditorView, ViewPlugin } from "@codemirror/view";
58
- import { next as A } from "@dxos/automerge/automerge";
59
- import { invariant } from "@dxos/invariant";
60
+ import { next as A4 } from "@dxos/automerge/automerge";
60
61
 
61
62
  // packages/ui/react-ui-editor/src/extensions/automerge/cursor.ts
62
63
  import get from "lodash.get";
63
- import { next as automerge } from "@dxos/automerge/automerge";
64
+ import { next as A } from "@dxos/automerge/automerge";
64
65
  var cursorConverter = (handle, path) => ({
65
66
  // TODO(burdon): Handle assoc to associate with a previous character.
66
67
  toCursor: (pos) => {
@@ -72,7 +73,7 @@ var cursorConverter = (handle, path) => ({
72
73
  if (typeof value === "string" && value.length <= pos) {
73
74
  return "end";
74
75
  }
75
- return automerge.getCursor(doc, path.slice(), pos);
76
+ return A.getCursor(doc, path.slice(), pos);
76
77
  },
77
78
  fromCursor: (cursor) => {
78
79
  if (cursor === "") {
@@ -90,26 +91,28 @@ var cursorConverter = (handle, path) => ({
90
91
  return 0;
91
92
  }
92
93
  }
93
- return automerge.getCursorPosition(doc, path.slice(), cursor);
94
+ return A.getCursorPosition(doc, path.slice(), cursor);
94
95
  }
95
96
  });
96
97
 
97
98
  // packages/ui/react-ui-editor/src/extensions/automerge/defs.ts
98
99
  import { Annotation, StateEffect } from "@codemirror/state";
99
- var effectType = StateEffect.define({});
100
- var reconcileAnnotationType = Annotation.define();
101
100
  var getPath = (state, field) => state.field(field).path;
102
101
  var getLastHeads = (state, field) => state.field(field).lastHeads;
103
- var updateHeads = (newHeads) => effectType.of({
102
+ var updateHeadsEffect = StateEffect.define({});
103
+ var updateHeads = (newHeads) => updateHeadsEffect.of({
104
104
  newHeads
105
105
  });
106
- var isReconcileTx = (tr) => !!tr.annotation(reconcileAnnotationType);
106
+ var reconcileAnnotation = Annotation.define();
107
+ var isReconcile = (tr) => {
108
+ return !!tr.annotation(reconcileAnnotation);
109
+ };
107
110
 
108
111
  // packages/ui/react-ui-editor/src/extensions/automerge/semaphore.ts
109
- import { next as automerge2 } from "@dxos/automerge/automerge";
112
+ import { next as A3 } from "@dxos/automerge/automerge";
110
113
 
111
114
  // packages/ui/react-ui-editor/src/extensions/automerge/update-automerge.ts
112
- import { next as am } from "@dxos/automerge/automerge";
115
+ import { next as A2 } from "@dxos/automerge/automerge";
113
116
  var updateAutomerge = (field, handle, transactions, state) => {
114
117
  const { lastHeads, path } = state.field(field);
115
118
  let hasChanges = false;
@@ -122,11 +125,19 @@ var updateAutomerge = (field, handle, transactions, state) => {
122
125
  return void 0;
123
126
  }
124
127
  const newHeads = handle.changeAt(lastHeads, (doc) => {
128
+ const invertedTransactions = [];
125
129
  for (const tr of transactions) {
126
- tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
127
- am.splice(doc, path, fromA, toA - fromA, inserted.toString());
130
+ tr.changes.iterChanges((fromA, toA, _fromB, _toB, insert) => {
131
+ invertedTransactions.push({
132
+ from: fromA,
133
+ del: toA - fromA,
134
+ insert
135
+ });
128
136
  });
129
137
  }
138
+ invertedTransactions.reverse().forEach(({ from, del, insert }) => {
139
+ A2.splice(doc, path.slice(), from, del, insert.toString());
140
+ });
130
141
  });
131
142
  return newHeads ?? void 0;
132
143
  };
@@ -141,13 +152,13 @@ var updateCodeMirror = (view, selection, target, patches) => {
141
152
  selection = selection.map(changeSet, 1);
142
153
  view.dispatch({
143
154
  changes: changeSet,
144
- annotations: reconcileAnnotationType.of({})
155
+ annotations: reconcileAnnotation.of(false)
145
156
  });
146
157
  }
147
158
  }
148
159
  view.dispatch({
149
160
  selection,
150
- annotations: reconcileAnnotationType.of({})
161
+ annotations: reconcileAnnotation.of(false)
151
162
  });
152
163
  };
153
164
  var handlePatch = (patch, target, state) => {
@@ -168,7 +179,7 @@ var handleInsert = (target, patch) => {
168
179
  if (index == null) {
169
180
  return [];
170
181
  }
171
- const text = patch.values.map((v) => v ? v.toString() : "").join("");
182
+ const text = patch.values.map((value) => value ? value.toString() : "").join("");
172
183
  return [
173
184
  {
174
185
  from: index,
@@ -246,36 +257,37 @@ var PatchSemaphore = class {
246
257
  this._state = _state;
247
258
  this._inReconcile = false;
248
259
  }
249
- // NOTE: Cannot destruct view.state.
250
260
  reconcile(view) {
251
- if (this._inReconcile) {
252
- return;
261
+ if (!this._inReconcile) {
262
+ this._inReconcile = true;
263
+ this.doReconcile(view);
264
+ this._inReconcile = false;
253
265
  }
254
- this._inReconcile = true;
266
+ }
267
+ doReconcile(view) {
255
268
  const path = getPath(view.state, this._state);
256
269
  const oldHeads = getLastHeads(view.state, this._state);
257
270
  let selection = view.state.selection;
258
- const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcileTx(tx));
271
+ const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
259
272
  const toInvert = transactions.slice().reverse();
260
- for (const tx of toInvert) {
261
- const inverted = tx.changes.invert(tx.startState.doc);
273
+ for (const tr of toInvert) {
274
+ const inverted = tr.changes.invert(tr.startState.doc);
262
275
  selection = selection.map(inverted);
263
276
  view.dispatch({
264
277
  changes: inverted,
265
- annotations: reconcileAnnotationType.of(true)
278
+ annotations: reconcileAnnotation.of(true)
266
279
  });
267
280
  }
268
281
  let newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
269
282
  if (newHeads === null || newHeads === void 0) {
270
- newHeads = automerge2.getHeads(this._handle.docSync());
283
+ newHeads = A3.getHeads(this._handle.docSync());
271
284
  }
272
- const diff = automerge2.equals(oldHeads, newHeads) ? [] : automerge2.diff(this._handle.docSync(), oldHeads, newHeads);
285
+ const diff = A3.equals(oldHeads, newHeads) ? [] : A3.diff(this._handle.docSync(), oldHeads, newHeads);
273
286
  updateCodeMirror(view, selection, path, diff);
274
287
  view.dispatch({
275
288
  effects: updateHeads(newHeads),
276
- annotations: reconcileAnnotationType.of({})
289
+ annotations: reconcileAnnotation.of(false)
277
290
  });
278
- this._inReconcile = false;
279
291
  }
280
292
  };
281
293
 
@@ -317,12 +329,11 @@ var Cursor = class _Cursor {
317
329
  };
318
330
 
319
331
  // packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts
320
- var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/automerge/automerge.ts";
321
- var automerge3 = ({ handle, path }) => {
322
- const state = StateField.define({
332
+ var automerge = ({ handle, path }) => {
333
+ const syncState = StateField.define({
323
334
  create: () => ({
324
335
  path: path.slice(),
325
- lastHeads: A.getHeads(handle.docSync()),
336
+ lastHeads: A4.getHeads(handle.docSync()),
326
337
  unreconciledTransactions: []
327
338
  }),
328
339
  update: (value, tr) => {
@@ -333,7 +344,7 @@ var automerge3 = ({ handle, path }) => {
333
344
  };
334
345
  let clearUnreconciled = false;
335
346
  for (const effect of tr.effects) {
336
- if (effect.is(effectType)) {
347
+ if (effect.is(updateHeadsEffect)) {
337
348
  result.lastHeads = effect.value.newHeads;
338
349
  clearUnreconciled = true;
339
350
  }
@@ -341,29 +352,21 @@ var automerge3 = ({ handle, path }) => {
341
352
  if (clearUnreconciled) {
342
353
  result.unreconciledTransactions = [];
343
354
  } else {
344
- if (!isReconcileTx(tr)) {
355
+ if (!isReconcile(tr)) {
345
356
  result.unreconciledTransactions.push(tr);
346
357
  }
347
358
  }
348
359
  return result;
349
360
  }
350
361
  });
351
- const semaphore = new PatchSemaphore(handle, state);
362
+ const semaphore = new PatchSemaphore(handle, syncState);
352
363
  return [
353
364
  Cursor.converter.of(cursorConverter(handle, path)),
365
+ syncState,
354
366
  // Reconcile external updates.
355
367
  ViewPlugin.fromClass(class {
356
368
  constructor(_view) {
357
369
  this._view = _view;
358
- invariant(this._view, void 0, {
359
- F: __dxlog_file,
360
- L: 66,
361
- S: this,
362
- A: [
363
- "this._view",
364
- ""
365
- ]
366
- });
367
370
  handle.addListener("change", this._handleChange.bind(this));
368
371
  }
369
372
  destroy() {
@@ -379,7 +382,17 @@ var automerge3 = ({ handle, path }) => {
379
382
  semaphore.reconcile(view);
380
383
  }
381
384
  }),
382
- state
385
+ // TODO(burdon): Record undo transactions.
386
+ // See https://github.com/yjs/y-codemirror.next/tree/main
387
+ // https://codemirror.net/examples/inverted-effect
388
+ invertedEffects.of((tr) => {
389
+ const effects = [];
390
+ if (!tr.changes.empty) {
391
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
392
+ });
393
+ }
394
+ return effects;
395
+ })
383
396
  ];
384
397
  };
385
398
 
@@ -398,13 +411,13 @@ var dummyProvider = {
398
411
  update: () => {
399
412
  }
400
413
  };
401
- var AwarenessProvider = Facet2.define({
414
+ var awarenessProvider = Facet2.define({
402
415
  combine: (providers) => providers[0] ?? dummyProvider
403
416
  });
404
417
  var RemoteSelectionChangedAnnotation = Annotation2.define();
405
418
  var awareness = (provider = dummyProvider) => {
406
419
  return [
407
- AwarenessProvider.of(provider),
420
+ awarenessProvider.of(provider),
408
421
  ViewPlugin2.fromClass(RemoteSelectionsDecorator, {
409
422
  decorations: (value) => value.decorations
410
423
  }),
@@ -418,7 +431,7 @@ var RemoteSelectionsDecorator = class {
418
431
  this._lastAnchor = void 0;
419
432
  this._lastHead = void 0;
420
433
  this._cursorConverter = view.state.facet(Cursor.converter);
421
- this._provider = view.state.facet(AwarenessProvider);
434
+ this._provider = view.state.facet(awarenessProvider);
422
435
  this._provider.open();
423
436
  this._provider.remoteStateChange.on(this._ctx, () => {
424
437
  view.dispatch({
@@ -624,24 +637,25 @@ import { history } from "@codemirror/commands";
624
637
  import { bracketMatching, defaultHighlightStyle, syntaxHighlighting } from "@codemirror/language";
625
638
  import { oneDarkHighlightStyle } from "@codemirror/theme-one-dark";
626
639
  import { drawSelection, EditorView as EditorView3, highlightActiveLine, placeholder } from "@codemirror/view";
627
- var basicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true }) => [
628
- lineWrapping ? EditorView3.lineWrapping : [],
640
+ import { isNotFalsy } from "@dxos/util";
641
+ var createBasicBundle = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => [
642
+ lineWrapping && EditorView3.lineWrapping,
629
643
  // https://codemirror.net/docs/ref/#codemirror.minimalSetup
630
644
  bracketMatching(),
631
645
  closeBrackets(),
632
646
  drawSelection(),
633
647
  highlightActiveLine(),
634
648
  history(),
635
- _placeholder ? placeholder(_placeholder) : [],
649
+ _placeholder && placeholder(_placeholder),
636
650
  // https://github.com/codemirror/theme-one-dark
637
651
  themeMode === "dark" ? syntaxHighlighting(oneDarkHighlightStyle) : syntaxHighlighting(defaultHighlightStyle)
638
- ];
652
+ ].filter(isNotFalsy);
639
653
 
640
654
  // packages/ui/react-ui-editor/src/extensions/blast.ts
641
655
  import { EditorView as EditorView4, keymap as keymap2 } from "@codemirror/view";
642
656
  import defaultsDeep from "lodash.defaultsdeep";
643
- import { invariant as invariant2 } from "@dxos/invariant";
644
- var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
657
+ import { invariant } from "@dxos/invariant";
658
+ var __dxlog_file = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/blast.ts";
645
659
  var defaultOptions = {
646
660
  effect: 2,
647
661
  maxParticles: 200,
@@ -674,10 +688,10 @@ var blast = (options = defaultOptions) => {
674
688
  const getPoint = (view, pos) => {
675
689
  const { left: x = 0, top: y = 0 } = view.coordsForChar(pos) ?? {};
676
690
  const element = document.elementFromPoint(x, y);
677
- const { offsetLeft: left = 0, offsetTop: top = 0 } = view.scrollDOM.parentElement ?? {};
691
+ const { offsetLeft: left = 0, offsetTop: top2 = 0 } = view.scrollDOM.parentElement ?? {};
678
692
  const point = {
679
693
  x: x - left,
680
- y: y - top
694
+ y: y - top2
681
695
  };
682
696
  return {
683
697
  element,
@@ -767,9 +781,9 @@ var Blaster = class {
767
781
  return this._node;
768
782
  }
769
783
  initialize() {
770
- invariant2(!this._canvas && !this._ctx, void 0, {
771
- F: __dxlog_file2,
772
- L: 138,
784
+ invariant(!this._canvas && !this._ctx, void 0, {
785
+ F: __dxlog_file,
786
+ L: 141,
773
787
  S: this,
774
788
  A: [
775
789
  "!this._canvas && !this._ctx",
@@ -804,9 +818,9 @@ var Blaster = class {
804
818
  }
805
819
  }
806
820
  start() {
807
- invariant2(this._canvas && this._ctx, void 0, {
808
- F: __dxlog_file2,
809
- L: 177,
821
+ invariant(this._canvas && this._ctx, void 0, {
822
+ F: __dxlog_file,
823
+ L: 180,
810
824
  S: this,
811
825
  A: [
812
826
  "this._canvas && this._ctx",
@@ -948,12 +962,12 @@ var random = (min, max) => {
948
962
  };
949
963
 
950
964
  // packages/ui/react-ui-editor/src/extensions/comments.ts
951
- import { StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
965
+ import { invertedEffects as invertedEffects2 } from "@codemirror/commands";
966
+ import { Facet as Facet3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
952
967
  import { hoverTooltip, keymap as keymap3, Decoration as Decoration2, EditorView as EditorView5 } from "@codemirror/view";
953
968
  import sortBy from "lodash.sortby";
954
969
  import { useEffect } from "react";
955
970
  import { debounce } from "@dxos/async";
956
- import { invariant as invariant3 } from "@dxos/invariant";
957
971
  import { nonNullable } from "@dxos/util";
958
972
 
959
973
  // packages/ui/react-ui-editor/src/styles/cursors.ts
@@ -997,34 +1011,15 @@ var cursorColor = cursorColors[random2.uint32() % cursorColors.length];
997
1011
  // packages/ui/react-ui-editor/src/styles/markdown.ts
998
1012
  import { mx } from "@dxos/react-ui-theme";
999
1013
  var headings = {
1000
- 1: [
1001
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
1002
- "-ml-[10px]"
1003
- ],
1004
- 2: [
1005
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
1006
- "-ml-[8px]"
1007
- ],
1008
- 3: [
1009
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
1010
- "-ml-[7px]"
1011
- ],
1012
- 4: [
1013
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
1014
- "-ml-[6px]"
1015
- ],
1016
- 5: [
1017
- "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
1018
- "-ml-[5px]"
1019
- ],
1020
- 6: [
1021
- "mbs-4 mbe-2 font-medium text-inherit no-underline",
1022
- "-ml-[4px]"
1023
- ]
1024
- };
1025
- var heading = (level, readonly) => {
1026
- const [style, offset] = headings[level];
1027
- return mx(style, readonly && offset);
1014
+ 1: "mbs-4 mbe-2 font-medium text-inherit no-underline text-4xl",
1015
+ 2: "mbs-4 mbe-2 font-medium text-inherit no-underline text-3xl",
1016
+ 3: "mbs-4 mbe-2 font-medium text-inherit no-underline text-2xl",
1017
+ 4: "mbs-4 mbe-2 font-medium text-inherit no-underline text-xl",
1018
+ 5: "mbs-4 mbe-2 font-medium text-inherit no-underline text-lg",
1019
+ 6: "mbs-4 mbe-2 font-medium text-inherit no-underline"
1020
+ };
1021
+ var heading = (level) => {
1022
+ return headings[level];
1028
1023
  };
1029
1024
  var light = "text-neutral-200 dark:text-neutral-800";
1030
1025
  var mark = mx("!font-normal !no-underline !text-inherit opacity-40", light);
@@ -1044,13 +1039,13 @@ var getToken = (path, defaultValue = void 0) => get2(tokens, path, defaultValue)
1044
1039
 
1045
1040
  // packages/ui/react-ui-editor/src/util.ts
1046
1041
  import { log } from "@dxos/log";
1047
- var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1042
+ var __dxlog_file2 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/util.ts";
1048
1043
  var callbackWrapper = (fn) => (...args) => {
1049
1044
  try {
1050
1045
  return fn(...args);
1051
1046
  } catch (err) {
1052
1047
  log.catch(err, void 0, {
1053
- F: __dxlog_file3,
1048
+ F: __dxlog_file2,
1054
1049
  L: 18,
1055
1050
  S: void 0,
1056
1051
  C: (f, a) => f(...a)
@@ -1078,24 +1073,35 @@ var logChanges = (trs) => {
1078
1073
  };
1079
1074
 
1080
1075
  // packages/ui/react-ui-editor/src/extensions/comments.ts
1081
- var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/extensions/comments.ts";
1082
1076
  var styles2 = EditorView5.baseTheme({
1083
- "& .cm-comment": {
1077
+ "&light .cm-comment, &light .cm-comment-current": {
1078
+ mixBlendMode: "darken"
1079
+ },
1080
+ "&dark .cm-comment, &dark .cm-comment-current": {
1081
+ mixBlendMode: "plus-lighter"
1082
+ },
1083
+ "&light .cm-comment": {
1084
1084
  backgroundColor: getToken("extend.colors.yellow.50")
1085
1085
  },
1086
- "& .cm-comment-current": {
1086
+ "&light .cm-comment-current": {
1087
1087
  backgroundColor: getToken("extend.colors.yellow.100")
1088
+ },
1089
+ "&dark .cm-comment": {
1090
+ color: getToken("extend.colors.yellow.50"),
1091
+ backgroundColor: getToken("extend.colors.yellow.900")
1092
+ },
1093
+ "&dark .cm-comment-current": {
1094
+ color: getToken("extend.colors.yellow.100"),
1095
+ backgroundColor: getToken("extend.colors.yellow.950")
1088
1096
  }
1089
1097
  });
1090
- var marks = {
1091
- highlight: Decoration2.mark({
1092
- class: "cm-comment"
1093
- }),
1094
- highlightActive: Decoration2.mark({
1095
- class: "cm-comment-current"
1096
- })
1097
- };
1098
- var setFocus = (view, id, center = true) => {
1098
+ var commentMark = Decoration2.mark({
1099
+ class: "cm-comment"
1100
+ });
1101
+ var commentCurrentMark = Decoration2.mark({
1102
+ class: "cm-comment-current"
1103
+ });
1104
+ var focusComment = (view, id, center = true) => {
1099
1105
  const comment = view.state.field(commentsState).comments.find((range2) => range2.comment.id === id);
1100
1106
  if (!comment?.comment.cursor) {
1101
1107
  return;
@@ -1157,7 +1163,7 @@ var commentsState = StateField2.define({
1157
1163
  return value;
1158
1164
  }
1159
1165
  });
1160
- var highlightDecorations = EditorView5.decorations.compute([
1166
+ var commentsDecorations = EditorView5.decorations.compute([
1161
1167
  commentsState
1162
1168
  ], (state) => {
1163
1169
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
@@ -1168,9 +1174,9 @@ var highlightDecorations = EditorView5.decorations.compute([
1168
1174
  return void 0;
1169
1175
  }
1170
1176
  if (comment.comment.id === current) {
1171
- return marks.highlightActive.range(range.from, range.to);
1177
+ return commentCurrentMark.range(range.from, range.to);
1172
1178
  } else {
1173
- return marks.highlight.range(range.from, range.to);
1179
+ return commentMark.range(range.from, range.to);
1174
1180
  }
1175
1181
  }).filter(nonNullable);
1176
1182
  return Decoration2.set(decorations);
@@ -1199,84 +1205,128 @@ var trackPastedComments = (onUpdate) => {
1199
1205
  cut: handleTrack,
1200
1206
  copy: handleTrack
1201
1207
  }),
1202
- // Handle paste.
1203
- EditorView5.updateListener.of(({ view, state, transactions }) => {
1208
+ // Track deleted comments.
1209
+ invertedEffects2.of((tr) => {
1210
+ const { comments: comments2 } = tr.startState.field(commentsState);
1211
+ const effects = [];
1212
+ tr.changes.iterChangedRanges((fromA, toA) => {
1213
+ for (const { comment: { id }, range: { from, to } } of comments2) {
1214
+ if (from < to && from >= fromA && to <= toA) {
1215
+ effects.push(restoreCommentEffect.of({
1216
+ id,
1217
+ from,
1218
+ to
1219
+ }));
1220
+ }
1221
+ }
1222
+ });
1223
+ return effects;
1224
+ }),
1225
+ // Handle paste or the undo of comment deletion.
1226
+ EditorView5.updateListener.of((update2) => {
1227
+ const restore = [];
1228
+ for (let i = 0; i < update2.transactions.length; i++) {
1229
+ const tr = update2.transactions[i];
1230
+ for (let j = 0; j < restore.length; j++) {
1231
+ restore[j] = mapTrackedComment(restore[j], tr.changes);
1232
+ }
1233
+ for (const effect of tr.effects) {
1234
+ if (effect.is(restoreCommentEffect)) {
1235
+ restore.push(effect.value);
1236
+ }
1237
+ }
1238
+ }
1204
1239
  if (tracked) {
1205
- const paste = transactions.find((tr) => tr.isUserEvent("input.paste"));
1240
+ const paste = update2.transactions.find((tr) => tr.isUserEvent("input.paste"));
1206
1241
  if (paste) {
1207
1242
  let found = -1;
1208
1243
  paste.changes.iterChanges((fromA, toA, fromB, toB, text) => {
1209
1244
  if (text.eq(tracked.text)) {
1210
- for (let i = transactions.indexOf(paste) + 1; i < transactions.length; i++) {
1211
- fromB = transactions[i].changes.mapPos(fromB);
1245
+ for (let i = update2.transactions.indexOf(paste) + 1; i < update2.transactions.length; i++) {
1246
+ fromB = update2.transactions[i].changes.mapPos(fromB);
1212
1247
  }
1213
1248
  found = fromB;
1214
1249
  }
1215
1250
  });
1216
1251
  if (found > -1) {
1217
1252
  for (const moved of tracked.comments) {
1218
- const range = {
1253
+ restore.push({
1254
+ id: moved.id,
1219
1255
  from: found + moved.from,
1220
1256
  to: found + moved.to
1221
- };
1222
- const cursor = Cursor.getCursorFromRange(state, range);
1223
- onUpdate(moved.id, cursor);
1257
+ });
1224
1258
  }
1225
1259
  }
1226
1260
  tracked = null;
1227
1261
  }
1228
1262
  }
1263
+ for (const comment of restore) {
1264
+ const { comments: comments2 } = update2.startState.field(commentsState);
1265
+ const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
1266
+ if (!exists) {
1267
+ const cursor = Cursor.getCursorFromRange(update2.state, comment);
1268
+ onUpdate(comment.id, cursor);
1269
+ }
1270
+ }
1229
1271
  })
1230
1272
  ];
1231
1273
  };
1232
- var comments = (options = {}) => {
1233
- const { key: shortcut = "meta-'" } = options;
1234
- const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1235
- const createCommentThread = (view) => {
1236
- invariant3(options.onCreate, void 0, {
1237
- F: __dxlog_file4,
1238
- L: 259,
1239
- S: void 0,
1240
- A: [
1241
- "options.onCreate",
1242
- ""
1243
- ]
1274
+ var mapTrackedComment = (comment, changes) => ({
1275
+ id: comment.id,
1276
+ from: changes.mapPos(comment.from, 1),
1277
+ to: changes.mapPos(comment.to, 1)
1278
+ });
1279
+ var restoreCommentEffect = StateEffect2.define({
1280
+ map: mapTrackedComment
1281
+ });
1282
+ var optionsFacet = Facet3.define({
1283
+ combine: (providers) => providers[0]
1284
+ });
1285
+ var createComment = (view) => {
1286
+ const options = view.state.facet(optionsFacet);
1287
+ const { from, to } = view.state.selection.main;
1288
+ if (from === to) {
1289
+ return false;
1290
+ }
1291
+ if (to === view.state.doc.length) {
1292
+ view.dispatch({
1293
+ changes: {
1294
+ from: to,
1295
+ insert: "\n"
1296
+ }
1244
1297
  });
1245
- const { from, to } = view.state.selection.main;
1246
- if (from === to) {
1247
- return false;
1248
- }
1249
- if (to === view.state.doc.length) {
1298
+ }
1299
+ const cursor = Cursor.getCursorFromRange(view.state, {
1300
+ from,
1301
+ to
1302
+ });
1303
+ if (cursor) {
1304
+ const id = options.onCreate?.({
1305
+ cursor,
1306
+ from,
1307
+ location: view.coordsAtPos(from)
1308
+ });
1309
+ if (id) {
1250
1310
  view.dispatch({
1251
- changes: {
1252
- from: to,
1253
- insert: "\n"
1311
+ effects: setSelection.of({
1312
+ current: id
1313
+ }),
1314
+ selection: {
1315
+ anchor: to
1254
1316
  }
1255
1317
  });
1318
+ return true;
1256
1319
  }
1257
- const cursor = Cursor.getCursorFromRange(view.state, {
1258
- from,
1259
- to
1260
- });
1261
- if (cursor) {
1262
- const id = options.onCreate?.(cursor, view.coordsAtPos(from));
1263
- if (id) {
1264
- view.dispatch({
1265
- effects: setSelection.of({
1266
- current: id
1267
- }),
1268
- selection: {
1269
- anchor: from
1270
- }
1271
- });
1272
- return true;
1273
- }
1274
- }
1275
- return false;
1276
- };
1320
+ }
1321
+ return false;
1322
+ };
1323
+ var comments = (options = {}) => {
1324
+ const { key: shortcut = "meta-'" } = options;
1325
+ const handleSelect = debounce((state) => options.onSelect?.(state), 200);
1277
1326
  return [
1327
+ optionsFacet.of(options),
1278
1328
  commentsState,
1279
- highlightDecorations,
1329
+ commentsDecorations,
1280
1330
  styles2,
1281
1331
  //
1282
1332
  // Keymap.
@@ -1284,7 +1334,7 @@ var comments = (options = {}) => {
1284
1334
  options.onCreate ? keymap3.of([
1285
1335
  {
1286
1336
  key: shortcut,
1287
- run: callbackWrapper(createCommentThread)
1337
+ run: callbackWrapper(createComment)
1288
1338
  }
1289
1339
  ]) : [],
1290
1340
  //
@@ -1422,6 +1472,7 @@ import { searchKeymap } from "@codemirror/search";
1422
1472
  import { EditorState } from "@codemirror/state";
1423
1473
  import { oneDarkHighlightStyle as oneDarkHighlightStyle2 } from "@codemirror/theme-one-dark";
1424
1474
  import { crosshairCursor, drawSelection as drawSelection2, dropCursor, EditorView as EditorView7, highlightActiveLine as highlightActiveLine2, keymap as keymap4, placeholder as placeholder2 } from "@codemirror/view";
1475
+ import { isNotFalsy as isNotFalsy2 } from "@dxos/util";
1425
1476
 
1426
1477
  // packages/ui/react-ui-editor/src/extensions/markdown/highlight.ts
1427
1478
  import { markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
@@ -1518,7 +1569,7 @@ var markdownHighlightStyle = (readonly) => {
1518
1569
  markdownTags.QuoteMark,
1519
1570
  markdownTags.EmphasisMark
1520
1571
  ],
1521
- class: readonly ? "hidden" : mark
1572
+ class: mark
1522
1573
  },
1523
1574
  // E.g., code block language (after ```).
1524
1575
  {
@@ -1526,7 +1577,7 @@ var markdownHighlightStyle = (readonly) => {
1526
1577
  tags.function(tags.variableName),
1527
1578
  tags.labelName
1528
1579
  ],
1529
- class: readonly ? "hidden" : codeMark
1580
+ class: codeMark
1530
1581
  },
1531
1582
  {
1532
1583
  tag: [
@@ -1537,27 +1588,27 @@ var markdownHighlightStyle = (readonly) => {
1537
1588
  // Headings.
1538
1589
  {
1539
1590
  tag: tags.heading1,
1540
- class: heading(1, readonly)
1591
+ class: heading(1)
1541
1592
  },
1542
1593
  {
1543
1594
  tag: tags.heading2,
1544
- class: heading(2, readonly)
1595
+ class: heading(2)
1545
1596
  },
1546
1597
  {
1547
1598
  tag: tags.heading3,
1548
- class: heading(3, readonly)
1599
+ class: heading(3)
1549
1600
  },
1550
1601
  {
1551
1602
  tag: tags.heading4,
1552
- class: heading(4, readonly)
1603
+ class: heading(4)
1553
1604
  },
1554
1605
  {
1555
1606
  tag: tags.heading5,
1556
- class: heading(5, readonly)
1607
+ class: heading(5)
1557
1608
  },
1558
1609
  {
1559
1610
  tag: tags.heading6,
1560
- class: heading(6, readonly)
1611
+ class: heading(6)
1561
1612
  },
1562
1613
  // Emphasis.
1563
1614
  {
@@ -1583,7 +1634,7 @@ var markdownHighlightStyle = (readonly) => {
1583
1634
  // However, since `codeLanguages` is also defined, the `lezer` will not parse fenced code blocks,
1584
1635
  // when a language is specified. In this case, the syntax highlighting extensions will colorize
1585
1636
  // the code, but all other CSS properties will be inherited.
1586
- // IMPORTANT: Therefore, the fenced code block will use the base editor font.
1637
+ // IMPORTANT: Therefore, the fenced code block will use the base editor font unless changed by an extension.
1587
1638
  {
1588
1639
  tag: [
1589
1640
  markdownTags.CodeText,
@@ -1612,11 +1663,11 @@ var markdownHighlightStyle = (readonly) => {
1612
1663
  };
1613
1664
 
1614
1665
  // packages/ui/react-ui-editor/src/extensions/markdown/bundle.ts
1615
- var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1666
+ var createMarkdownExtensions = ({ themeMode, placeholder: _placeholder, lineWrapping = true } = {}) => {
1616
1667
  return [
1668
+ lineWrapping && EditorView7.lineWrapping,
1617
1669
  EditorState.allowMultipleSelections.of(true),
1618
1670
  EditorState.tabSize.of(2),
1619
- EditorView7.lineWrapping,
1620
1671
  // https://github.com/codemirror/basic-setup
1621
1672
  bracketMatching2(),
1622
1673
  closeBrackets2(),
@@ -1626,7 +1677,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1626
1677
  highlightActiveLine2(),
1627
1678
  history2(),
1628
1679
  indentOnInput(),
1629
- _placeholder ? placeholder2(_placeholder) : [],
1680
+ _placeholder && placeholder2(_placeholder),
1630
1681
  // Main extension.
1631
1682
  // https://github.com/codemirror/lang-markdown
1632
1683
  // https://codemirror.net/5/mode/markdown/index.html (demo).
@@ -1648,7 +1699,7 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1648
1699
  // https://github.com/codemirror/theme-one-dark
1649
1700
  themeMode === "dark" ? syntaxHighlighting2(oneDarkHighlightStyle2) : syntaxHighlighting2(defaultHighlightStyle2),
1650
1701
  // Custom styles.
1651
- syntaxHighlighting2(markdownHighlightStyle(readonly)),
1702
+ syntaxHighlighting2(markdownHighlightStyle()),
1652
1703
  keymap4.of([
1653
1704
  // https://codemirror.net/docs/ref/#commands.indentWithTab
1654
1705
  indentWithTab,
@@ -1661,36 +1712,53 @@ var markdownBundle = ({ readonly, themeMode, placeholder: _placeholder }) => {
1661
1712
  // https://codemirror.net/docs/ref/#commands.standardKeymap
1662
1713
  ...standardKeymap
1663
1714
  ])
1664
- ];
1715
+ ].filter(isNotFalsy2);
1665
1716
  };
1666
1717
 
1667
1718
  // packages/ui/react-ui-editor/src/extensions/markdown/code.ts
1668
- import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3 } from "@codemirror/view";
1719
+ import { syntaxTree } from "@codemirror/language";
1720
+ import { RangeSetBuilder } from "@codemirror/state";
1721
+ import { ViewPlugin as ViewPlugin3, EditorView as EditorView8, Decoration as Decoration3, WidgetType as WidgetType2 } from "@codemirror/view";
1669
1722
  import { mx as mx2 } from "@dxos/react-ui-theme";
1670
- var CODE_REGEX = /```[\s\S]*?```/gs;
1671
1723
  var styles3 = EditorView8.baseTheme({
1672
- "& .cm-codeblock": {
1724
+ "& .cm-code": {
1673
1725
  fontFamily: getToken("fontFamily.mono", []).join(",")
1674
1726
  },
1675
- '&light [aria-readonly="true"] .cm-codeblock': {
1676
- background: getToken("extend.colors.neutral.50")
1727
+ "& .cm-codeblock": {
1728
+ width: "100%",
1729
+ paddingInline: "1rem !important",
1730
+ position: "relative",
1731
+ "&::after": {
1732
+ content: '""',
1733
+ position: "absolute",
1734
+ inset: 0
1735
+ }
1677
1736
  },
1678
- '&dark [aria-readonly="true"] .cm-codeblock': {
1679
- background: getToken("extend.colors.neutral.850")
1737
+ "&light .cm-codeblock": {
1738
+ "&::after": {
1739
+ background: getToken("extend.semanticColors.input.light"),
1740
+ mixBlendMode: "darken"
1741
+ }
1680
1742
  },
1681
- '& [aria-readonly="true"] .cm-codeblock': {
1682
- display: "block",
1683
- paddingInline: "4px !important"
1743
+ "&dark .cm-codeblock": {
1744
+ "&::after": {
1745
+ background: getToken("extend.semanticColors.input.dark"),
1746
+ mixBlendMode: "lighten"
1747
+ }
1684
1748
  },
1685
- '& [aria-readonly="true"] .cm-codeblock-first': {
1686
- paddingTop: "4px !important",
1687
- borderTopLeftRadius: "4px",
1688
- borderTopRightRadius: "4px"
1749
+ "& .cm-codeblock-first": {
1750
+ display: "inline-block",
1751
+ "&::after": {
1752
+ borderTopLeftRadius: ".5rem",
1753
+ borderTopRightRadius: ".5rem"
1754
+ }
1689
1755
  },
1690
- '& [aria-readonly="true"] .cm-codeblock-last': {
1691
- paddingBottom: "4px !important",
1692
- borderBottomLeftRadius: "4px",
1693
- borderBottomRightRadius: "4px"
1756
+ "& .cm-codeblock-last": {
1757
+ display: "inline-block",
1758
+ "&::after": {
1759
+ borderBottomLeftRadius: ".5rem",
1760
+ borderBottomRightRadius: ".5rem"
1761
+ }
1694
1762
  }
1695
1763
  });
1696
1764
  var getLineRange = (lines, from, to) => {
@@ -1701,66 +1769,41 @@ var getLineRange = (lines, from, to) => {
1701
1769
  end
1702
1770
  ];
1703
1771
  };
1704
- var code2 = () => {
1705
- const buildDecorations6 = (view) => {
1706
- const decorations = [];
1707
- const text = view.state.doc.sliceString(0);
1708
- const matches = text.matchAll(CODE_REGEX);
1709
- const blocks = view.viewportLineBlocks;
1710
- for (const match of matches) {
1711
- const range = getLineRange(blocks, match.index, match.index + match[0].length);
1712
- for (let i = range[0]; i <= range[1]; i++) {
1713
- const block = blocks[i];
1714
- decorations.push(Decoration3.line({
1715
- class: mx2("cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1716
- }).range(block.from));
1717
- }
1718
- }
1719
- return Decoration3.set(decorations);
1720
- };
1721
- return [
1722
- ViewPlugin3.fromClass(class {
1723
- constructor(view) {
1724
- this.hasFocus = false;
1725
- this.decorations = buildDecorations6(view);
1726
- }
1727
- update(update2) {
1728
- if (
1729
- // TODO(burdon): Generalize for other extensions.
1730
- this.hasFocus !== update2.view.hasFocus || update2.startState.readOnly !== update2.view.state.readOnly || update2.docChanged || update2.viewportChanged
1731
- ) {
1732
- this.hasFocus = update2.view.hasFocus;
1733
- this.decorations = buildDecorations6(update2.view);
1734
- }
1735
- }
1736
- }, {
1737
- decorations: (value) => value.decorations
1738
- }),
1739
- styles3
1740
- ];
1772
+ var LineWidget = class extends WidgetType2 {
1773
+ constructor(_className) {
1774
+ super();
1775
+ this._className = _className;
1776
+ }
1777
+ toDOM() {
1778
+ const el = document.createElement("span");
1779
+ el.innerHTML = "&nbsp;";
1780
+ el.className = mx2("cm-code cm-codeblock", this._className);
1781
+ return el;
1782
+ }
1741
1783
  };
1742
-
1743
- // packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
1744
- import { syntaxTree } from "@codemirror/language";
1745
- import { RangeSetBuilder } from "@codemirror/state";
1746
- import { Decoration as Decoration4, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1784
+ var top = new LineWidget("cm-codeblock-first");
1785
+ var bottom = new LineWidget("cm-codeblock-last");
1747
1786
  var buildDecorations = (view) => {
1748
1787
  const builder = new RangeSetBuilder();
1749
1788
  const { state } = view;
1789
+ const blocks = view.viewportLineBlocks;
1750
1790
  const cursor = state.selection.main.head;
1751
1791
  for (const { from, to } of view.visibleRanges) {
1752
1792
  syntaxTree(state).iterate({
1753
1793
  enter: (node) => {
1754
- switch (node.name) {
1755
- case "ATXHeading1":
1756
- case "ATXHeading2":
1757
- case "ATXHeading3":
1758
- case "ATXHeading4":
1759
- case "ATXHeading5":
1760
- case "ATXHeading6": {
1761
- const mark2 = node.node.getChild("HeaderMark");
1762
- if (mark2 && (cursor < node.from || cursor > node.to)) {
1763
- builder.add(mark2.from, mark2.to + 1, Decoration4.replace({}));
1794
+ if (node.name === "FencedCode") {
1795
+ const edit = !view.state.readOnly && cursor >= node.from && cursor <= node.to;
1796
+ const range = getLineRange(blocks, node.from, node.to);
1797
+ for (let i = range[0]; i <= range[1]; i++) {
1798
+ const block = blocks[i];
1799
+ if (!edit && (i === range[0] || i === range[1])) {
1800
+ builder.add(block.from, block.to, Decoration3.replace({
1801
+ widget: i === range[0] ? top : bottom
1802
+ }));
1803
+ } else {
1804
+ builder.add(block.from, block.from, Decoration3.line({
1805
+ class: mx2("cm-code cm-codeblock", i === range[0] && "cm-codeblock-first", i === range[1] && "cm-codeblock-last")
1806
+ }));
1764
1807
  }
1765
1808
  }
1766
1809
  }
@@ -1771,9 +1814,9 @@ var buildDecorations = (view) => {
1771
1814
  }
1772
1815
  return builder.finish();
1773
1816
  };
1774
- var heading2 = () => {
1817
+ var code2 = () => {
1775
1818
  return [
1776
- ViewPlugin4.fromClass(class {
1819
+ ViewPlugin3.fromClass(class {
1777
1820
  constructor(view) {
1778
1821
  this.decorations = buildDecorations(view);
1779
1822
  }
@@ -1781,86 +1824,1205 @@ var heading2 = () => {
1781
1824
  this.decorations = buildDecorations(update2.view);
1782
1825
  }
1783
1826
  }, {
1784
- decorations: (v) => v.decorations
1785
- })
1827
+ decorations: (value) => value.decorations
1828
+ }),
1829
+ styles3
1786
1830
  ];
1787
1831
  };
1788
1832
 
1789
- // packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
1833
+ // packages/ui/react-ui-editor/src/extensions/markdown/formatting.ts
1834
+ import { snippet } from "@codemirror/autocomplete";
1790
1835
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
1791
- import { RangeSetBuilder as RangeSetBuilder2 } from "@codemirror/state";
1792
- import { Decoration as Decoration5, EditorView as EditorView9, ViewPlugin as ViewPlugin5, WidgetType as WidgetType2 } from "@codemirror/view";
1793
- var styles4 = EditorView9.baseTheme({
1794
- "& .cm-hr": {
1795
- // Note that block-level decorations should not have vertical margins,
1796
- borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
1836
+ import { RangeSetBuilder as RangeSetBuilder2, EditorSelection } from "@codemirror/state";
1837
+ import { Decoration as Decoration4, EditorView as EditorView9, keymap as keymap5, ViewPlugin as ViewPlugin4 } from "@codemirror/view";
1838
+ import { useState, useMemo } from "react";
1839
+ var compareFormatting = (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;
1840
+ var Inline;
1841
+ (function(Inline2) {
1842
+ Inline2[Inline2["Strong"] = 0] = "Strong";
1843
+ Inline2[Inline2["Emphasis"] = 1] = "Emphasis";
1844
+ Inline2[Inline2["Strikethrough"] = 2] = "Strikethrough";
1845
+ Inline2[Inline2["Code"] = 3] = "Code";
1846
+ })(Inline || (Inline = {}));
1847
+ var List;
1848
+ (function(List2) {
1849
+ List2[List2["Ordered"] = 0] = "Ordered";
1850
+ List2[List2["Bullet"] = 1] = "Bullet";
1851
+ List2[List2["Task"] = 2] = "Task";
1852
+ })(List || (List = {}));
1853
+ var setHeading = (level) => ({ state, dispatch }) => {
1854
+ const { selection: { ranges }, doc } = state;
1855
+ const changes = [];
1856
+ let prevBlock = -1;
1857
+ for (const range of ranges) {
1858
+ syntaxTree2(state).iterate({
1859
+ from: range.from,
1860
+ to: range.to,
1861
+ enter: (node) => {
1862
+ if (!Object.hasOwn(Textblocks, node.name) || prevBlock === node.from) {
1863
+ return;
1864
+ }
1865
+ prevBlock = node.from;
1866
+ const blockType = Textblocks[node.name];
1867
+ const isHeading = /heading(\d)/.exec(blockType);
1868
+ const curLevel = isHeading ? +isHeading[1] : node.name === "Paragraph" ? 0 : -1;
1869
+ if (curLevel < 0 || curLevel === level) {
1870
+ return;
1871
+ }
1872
+ if (curLevel === 0) {
1873
+ changes.push({
1874
+ from: node.from,
1875
+ insert: "#".repeat(level) + " "
1876
+ });
1877
+ } else if (node.name === "SetextHeading1" || node.name === "SetextHeading2") {
1878
+ const nextLine = doc.lineAt(node.to);
1879
+ if (level) {
1880
+ changes.push({
1881
+ from: node.from,
1882
+ insert: "#".repeat(level) + " "
1883
+ });
1884
+ }
1885
+ changes.push({
1886
+ from: nextLine.from - 1,
1887
+ to: nextLine.to
1888
+ });
1889
+ } else {
1890
+ if (level === 0) {
1891
+ changes.push({
1892
+ from: node.from,
1893
+ to: Math.min(node.to, node.from + curLevel + 1)
1894
+ });
1895
+ } else if (level < curLevel) {
1896
+ changes.push({
1897
+ from: node.from,
1898
+ to: node.from + (curLevel - level)
1899
+ });
1900
+ } else {
1901
+ changes.push({
1902
+ from: node.from,
1903
+ insert: "#".repeat(level - curLevel)
1904
+ });
1905
+ }
1906
+ }
1907
+ }
1908
+ });
1797
1909
  }
1798
- });
1799
- var HorizontalRuleWidget = class extends WidgetType2 {
1800
- toDOM() {
1801
- const el = document.createElement("div");
1802
- el.className = "cm-hr";
1803
- return el;
1910
+ if (!changes.length) {
1911
+ return false;
1804
1912
  }
1913
+ dispatch(state.update({
1914
+ changes,
1915
+ userEvent: "format.setHeading",
1916
+ scrollIntoView: true
1917
+ }));
1918
+ return true;
1805
1919
  };
1806
- var decoration = Decoration5.replace({
1807
- widget: new HorizontalRuleWidget()
1808
- });
1809
- var buildDecorations2 = (view) => {
1810
- const builder = new RangeSetBuilder2();
1811
- const { state } = view;
1812
- const cursor = state.selection.main.head;
1813
- for (const { from, to } of view.visibleRanges) {
1920
+ var setStyle = (type, enable) => ({ state, dispatch }) => {
1921
+ const marker = inlineMarkerText(type);
1922
+ const changes = state.changeByRange((range) => {
1923
+ if (!enable && range.empty) {
1924
+ const after = state.doc.sliceString(range.head, range.head + 6);
1925
+ const found = after.indexOf(marker);
1926
+ if (found >= 0 && /^[*~`]*$/.test(after.slice(0, found))) {
1927
+ const before = state.doc.sliceString(range.head - 6, range.head);
1928
+ if (before.slice(before.length - found - marker.length, before.length - found) === marker && [
1929
+ ...before.slice(before.length - found)
1930
+ ].reverse().join("") === after.slice(0, found)) {
1931
+ return {
1932
+ changes: [
1933
+ {
1934
+ from: range.head - marker.length - found,
1935
+ to: range.head - found
1936
+ },
1937
+ {
1938
+ from: range.head + found,
1939
+ to: range.head + found + marker.length
1940
+ }
1941
+ ],
1942
+ range: EditorSelection.cursor(range.from - marker.length)
1943
+ };
1944
+ }
1945
+ }
1946
+ }
1947
+ const changes2 = [];
1948
+ const changesAtEnd = [];
1949
+ let blockStart = -1;
1950
+ let blockEnd = -1;
1951
+ let startCovered = false;
1952
+ let endCovered = false;
1953
+ let { from, to } = range;
1814
1954
  syntaxTree2(state).iterate({
1955
+ from,
1956
+ to,
1815
1957
  enter: (node) => {
1816
- if (node.name === "HorizontalRule") {
1817
- if (cursor <= node.from || cursor >= node.to) {
1818
- builder.add(node.from, node.to, decoration);
1958
+ const { name } = node;
1959
+ if (Object.hasOwn(Textblocks, name) && Textblocks[name] !== "codeblock") {
1960
+ blockStart = blockContentStart(node);
1961
+ blockEnd = blockContentEnd(node, state.doc);
1962
+ startCovered = endCovered = false;
1963
+ } else if (name === "Link" || name === "Image" && enable) {
1964
+ if (from < node.from && to > node.from && to <= node.to) {
1965
+ to = node.to;
1966
+ } else if (to > node.to && from >= node.from && from < node.to) {
1967
+ from = node.from;
1968
+ }
1969
+ } else if (IgnoreInline.has(name) && enable) {
1970
+ if (node.from < from && node.to > from) {
1971
+ if (to === from) {
1972
+ to = node.to;
1973
+ }
1974
+ from = node.to;
1975
+ }
1976
+ if (node.from < to && node.to > to) {
1977
+ to = node.from;
1978
+ }
1979
+ } else if (Object.hasOwn(InlineMarker, name)) {
1980
+ const markType = InlineMarker[name];
1981
+ const size = inlineMarkerText(markType).length;
1982
+ const openEnd = node.from + size;
1983
+ const closeStart = node.to - size;
1984
+ if (markType === type) {
1985
+ if (openEnd <= from && closeStart >= from) {
1986
+ startCovered = openEnd === from ? "adjacent" : true;
1987
+ }
1988
+ if (openEnd <= to && closeStart >= to) {
1989
+ endCovered = closeStart === to ? "adjacent" : true;
1990
+ }
1991
+ }
1992
+ if (markType === type || type === 3 && enable) {
1993
+ if (node.from >= from && openEnd <= to) {
1994
+ changes2.push({
1995
+ from: node.from,
1996
+ to: openEnd
1997
+ });
1998
+ if (markType !== type && closeStart >= to) {
1999
+ changesAtEnd.push({
2000
+ from: skipSpaces(Math.min(to, blockEnd), state.doc, 1, blockEnd),
2001
+ insert: inlineMarkerText(markType)
2002
+ });
2003
+ }
2004
+ }
2005
+ if (closeStart >= from && node.to <= to) {
2006
+ changes2.push({
2007
+ from: closeStart,
2008
+ to: node.to
2009
+ });
2010
+ if (markType !== type && openEnd <= from) {
2011
+ changes2.push({
2012
+ from: skipSpaces(Math.max(from, blockStart), state.doc, -1, blockStart),
2013
+ insert: inlineMarkerText(markType)
2014
+ });
2015
+ }
2016
+ }
1819
2017
  }
1820
2018
  }
1821
2019
  },
1822
- from,
1823
- to
2020
+ leave: (node) => {
2021
+ if (Object.hasOwn(Textblocks, node.name) && Textblocks[node.name] !== "codeblock") {
2022
+ const rangeStart = Math.max(from, blockStart);
2023
+ const rangeEnd = Math.min(to, blockEnd);
2024
+ if (enable) {
2025
+ if (!startCovered) {
2026
+ changes2.push({
2027
+ from: rangeStart,
2028
+ insert: marker
2029
+ });
2030
+ }
2031
+ if (!endCovered) {
2032
+ changes2.push({
2033
+ from: rangeEnd,
2034
+ insert: marker
2035
+ });
2036
+ }
2037
+ } else {
2038
+ if (startCovered === "adjacent") {
2039
+ changes2.push({
2040
+ from: from - marker.length,
2041
+ to: from
2042
+ });
2043
+ } else if (startCovered) {
2044
+ changes2.push({
2045
+ from: skipSpaces(rangeStart, state.doc, -1, blockStart),
2046
+ insert: marker
2047
+ });
2048
+ }
2049
+ if (endCovered === "adjacent") {
2050
+ changes2.push({
2051
+ from: to,
2052
+ to: to + marker.length
2053
+ });
2054
+ } else if (endCovered) {
2055
+ changes2.push({
2056
+ from: skipSpaces(rangeEnd, state.doc, 1, blockEnd),
2057
+ insert: marker
2058
+ });
2059
+ }
2060
+ }
2061
+ }
2062
+ }
1824
2063
  });
2064
+ const changeSet = state.changes(changes2.concat(changesAtEnd));
2065
+ return {
2066
+ changes: changeSet,
2067
+ range: range.empty && !changeSet.empty ? EditorSelection.cursor(range.head + marker.length) : EditorSelection.range(changeSet.mapPos(range.from, 1), changeSet.mapPos(range.to, -1))
2068
+ };
2069
+ });
2070
+ dispatch(state.update(changes, {
2071
+ userEvent: enable ? "format.style.add" : "format.style.remove",
2072
+ scrollIntoView: true
2073
+ }));
2074
+ return true;
2075
+ };
2076
+ var addStyle = (style) => setStyle(style, true);
2077
+ var removeStyle = (style) => setStyle(style, false);
2078
+ var toggleStyle = (style) => (arg) => {
2079
+ const form = getFormatting(arg.state);
2080
+ return setStyle(style, style === 0 ? !form.strong : style === 1 ? !form.emphasis : style === 2 ? !form.strikethrough : !form.code)(arg);
2081
+ };
2082
+ var toggleStrong = toggleStyle(0);
2083
+ var toggleEmphasis = toggleStyle(1);
2084
+ var toggleStrikethrough = toggleStyle(2);
2085
+ var toggleInlineCode = toggleStyle(3);
2086
+ var inlineMarkerText = (type) => type === 0 ? "**" : type === 2 ? "~~" : type === 1 ? "*" : "`";
2087
+ var blockContentStart = (node) => {
2088
+ const atx = /^ATXHeading(\d)/.exec(node.name);
2089
+ if (atx) {
2090
+ return Math.min(node.to, node.from + +atx[1] + 1);
1825
2091
  }
1826
- return builder.finish();
2092
+ return node.from;
1827
2093
  };
1828
- var hr = () => {
1829
- return [
1830
- styles4,
1831
- ViewPlugin5.fromClass(class {
1832
- constructor(view) {
1833
- this.decorations = buildDecorations2(view);
1834
- }
1835
- update(update2) {
1836
- this.decorations = buildDecorations2(update2.view);
1837
- }
1838
- }, {
1839
- decorations: (v) => v.decorations
1840
- })
1841
- ];
2094
+ var blockContentEnd = (node, doc) => {
2095
+ const setext = /^SetextHeading(\d)/.exec(node.name);
2096
+ const lastLine = doc.lineAt(node.to);
2097
+ if (setext || /^[\s>]*$/.exec(lastLine.text)) {
2098
+ return lastLine.from - 1;
2099
+ }
2100
+ return node.to;
1842
2101
  };
1843
-
1844
- // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
1845
- import { syntaxTree as syntaxTree3 } from "@codemirror/language";
1846
- import { StateField as StateField3 } from "@codemirror/state";
1847
- import { Decoration as Decoration6, EditorView as EditorView10, WidgetType as WidgetType3 } from "@codemirror/view";
1848
- var image = (options = {}) => {
1849
- return StateField3.define({
1850
- create: (state) => {
1851
- return Decoration6.set(buildDecorations3(0, state.doc.length, state));
1852
- },
1853
- update: (value, tr) => {
1854
- if (!tr.docChanged && !tr.selection) {
1855
- return value;
2102
+ var skipSpaces = (pos, doc, dir, limit) => {
2103
+ const line = doc.lineAt(pos);
2104
+ while (pos !== limit && line.text[pos - line.from - (dir < 0 ? 1 : 0)] === " ") {
2105
+ pos += dir;
2106
+ }
2107
+ return pos;
2108
+ };
2109
+ var snippets = {
2110
+ codeblock: snippet([
2111
+ "```#{lang}",
2112
+ "#{}",
2113
+ "```"
2114
+ ].join("\n")),
2115
+ table: snippet([
2116
+ "| #{col1} | #{col2} |",
2117
+ "| ---- | ---- |",
2118
+ "| #{val1} | #{val2} |",
2119
+ "| #{val3} | #{val4} |"
2120
+ ].join("\n"))
2121
+ };
2122
+ var insertTable = (view) => {
2123
+ const { selection: { main }, doc } = view.state;
2124
+ const { number } = doc.lineAt(main.anchor);
2125
+ const { from } = doc.line(number);
2126
+ snippets.table(view, null, from, from);
2127
+ };
2128
+ var removeLinkInner = (from, to, changes, state) => {
2129
+ syntaxTree2(state).iterate({
2130
+ from,
2131
+ to,
2132
+ enter: (node) => {
2133
+ if (node.name === "Link" && node.from < to && node.to > from) {
2134
+ node.node.cursor().iterate((node2) => {
2135
+ const { name } = node2;
2136
+ if (name === "LinkMark" || name === "LinkLabel") {
2137
+ changes.push({
2138
+ from: node2.from,
2139
+ to: node2.to
2140
+ });
2141
+ } else if (name === "LinkTitle" || name === "URL") {
2142
+ changes.push({
2143
+ from: skipSpaces(node2.from, state.doc, -1),
2144
+ to: skipSpaces(node2.to, state.doc, 1)
2145
+ });
2146
+ }
2147
+ });
2148
+ return false;
1856
2149
  }
1857
- const cursor = tr.state.selection.main.head;
1858
- const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
1859
- let from = Math.min(cursor, oldCursor);
1860
- let to = Math.max(cursor, oldCursor);
1861
- tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
1862
- from = Math.min(from, fromB);
1863
- to = Math.max(to, toB);
2150
+ }
2151
+ });
2152
+ };
2153
+ var removeLink = ({ state, dispatch }) => {
2154
+ const changes = [];
2155
+ for (const { from, to } of state.selection.ranges) {
2156
+ removeLinkInner(from, to, changes, state);
2157
+ }
2158
+ if (!changes) {
2159
+ return false;
2160
+ }
2161
+ dispatch(state.update({
2162
+ changes,
2163
+ userEvent: "format.link.remove",
2164
+ scrollIntoView: true
2165
+ }));
2166
+ return true;
2167
+ };
2168
+ var addLink = ({ state, dispatch }) => {
2169
+ const changes = state.changeByRange((range) => {
2170
+ let { from, to } = range;
2171
+ const cutStyles = [];
2172
+ let okay = null;
2173
+ syntaxTree2(state).iterate({
2174
+ from,
2175
+ to,
2176
+ enter: (node) => {
2177
+ if (Object.hasOwn(Textblocks, node.name)) {
2178
+ okay = Textblocks[node.name] !== "codeblock" && from >= blockContentStart(node) && to <= blockContentEnd(node, state.doc);
2179
+ } else if (Object.hasOwn(InlineMarker, node.name)) {
2180
+ const sNode = node.node;
2181
+ if (node.from < from && node.to <= to) {
2182
+ if (sNode.firstChild.to === from) {
2183
+ from = node.from;
2184
+ } else {
2185
+ cutStyles.push(sNode);
2186
+ }
2187
+ } else if (node.from >= from && node.to > to) {
2188
+ if (sNode.lastChild.from === to) {
2189
+ to = node.to;
2190
+ } else {
2191
+ cutStyles.push(sNode);
2192
+ }
2193
+ }
2194
+ }
2195
+ }
2196
+ });
2197
+ if (okay === null) {
2198
+ const line = state.doc.lineAt(from);
2199
+ okay = to <= line.to && !/\S/.test(line.text.slice(from - line.from));
2200
+ }
2201
+ if (!okay) {
2202
+ return {
2203
+ range
2204
+ };
2205
+ }
2206
+ const changes2 = [];
2207
+ const changesAfter = [];
2208
+ removeLinkInner(from, to, changesAfter, state);
2209
+ let cursorOffset = 1;
2210
+ for (const style of cutStyles) {
2211
+ const type = InlineMarker[style.name];
2212
+ const mark2 = inlineMarkerText(type);
2213
+ if (style.from < from) {
2214
+ changes2.push({
2215
+ from: skipSpaces(from, state.doc, -1),
2216
+ insert: mark2
2217
+ });
2218
+ changesAfter.push({
2219
+ from: skipSpaces(from, state.doc, 1, to),
2220
+ insert: mark2
2221
+ });
2222
+ } else {
2223
+ changes2.push({
2224
+ from: skipSpaces(to, state.doc, -1, from),
2225
+ insert: mark2
2226
+ });
2227
+ const after = skipSpaces(to, state.doc, 1);
2228
+ if (after === to) {
2229
+ cursorOffset += mark2.length;
2230
+ }
2231
+ changesAfter.push({
2232
+ from: after,
2233
+ insert: mark2
2234
+ });
2235
+ }
2236
+ }
2237
+ changes2.push({
2238
+ from,
2239
+ insert: "["
2240
+ }, {
2241
+ from: to,
2242
+ insert: "]()"
2243
+ });
2244
+ const changeSet = state.changes(changes2.concat(changesAfter));
2245
+ return {
2246
+ changes: changeSet,
2247
+ range: EditorSelection.cursor(changeSet.mapPos(to, 1) - cursorOffset)
2248
+ };
2249
+ });
2250
+ if (changes.changes.empty) {
2251
+ return false;
2252
+ }
2253
+ dispatch(state.update(changes, {
2254
+ userEvent: "format.link.add",
2255
+ scrollIntoView: true
2256
+ }));
2257
+ return true;
2258
+ };
2259
+ var addList = (type) => ({ state, dispatch }) => {
2260
+ let lastBlock = -1;
2261
+ let counter = 1;
2262
+ let first = true;
2263
+ let parentColumn = null;
2264
+ const blocks = [];
2265
+ for (const { from, to } of state.selection.ranges) {
2266
+ syntaxTree2(state).iterate({
2267
+ from,
2268
+ to,
2269
+ enter: (node) => {
2270
+ if (Object.hasOwn(Textblocks, node.name) && node.name !== "TableCell" || node.name === "Table") {
2271
+ if (first) {
2272
+ let before = node.node.prevSibling;
2273
+ while (before && /Mark$/.test(before.name)) {
2274
+ before = before.prevSibling;
2275
+ }
2276
+ if (before?.name === (type === 0 ? "OrderedList" : "BulletList")) {
2277
+ const item = before.lastChild;
2278
+ const itemLine = state.doc.lineAt(item.from);
2279
+ const itemText = itemLine.text.slice(item.from - itemLine.from);
2280
+ parentColumn = item.from - itemLine.from + /^\s*/.exec(itemText)[0].length;
2281
+ if (type === 0) {
2282
+ const mark2 = /^\s*(\d+)[.)]/.exec(itemText);
2283
+ if (mark2) {
2284
+ parentColumn += mark2[1].length;
2285
+ counter = +mark2[1] + 1;
2286
+ }
2287
+ }
2288
+ }
2289
+ first = false;
2290
+ }
2291
+ if (node.from === lastBlock) {
2292
+ return;
2293
+ }
2294
+ lastBlock = node.from;
2295
+ blocks.push({
2296
+ node: node.node,
2297
+ counter,
2298
+ parentColumn
2299
+ });
2300
+ counter++;
2301
+ return false;
2302
+ }
2303
+ },
2304
+ leave: (node) => {
2305
+ if (node.name === "BulletList" || node.name === "OrderedList" || node.name === "Blockquote") {
2306
+ counter = 1;
2307
+ parentColumn = null;
2308
+ }
2309
+ }
2310
+ });
2311
+ }
2312
+ if (!blocks.length) {
2313
+ return false;
2314
+ }
2315
+ const changes = [];
2316
+ for (let i = 0; i < blocks.length; i++) {
2317
+ const { node, counter: counter2, parentColumn: parentColumn2 } = blocks[i];
2318
+ const nodeFrom = node.name === "CodeBlock" ? node.from - 4 : node.from;
2319
+ let padding = nodeFrom > 0 && !/\s/.test(state.doc.sliceString(nodeFrom - 1, nodeFrom)) ? 1 : 0;
2320
+ if (type === 0) {
2321
+ padding += String(counter2).length;
2322
+ }
2323
+ let line = state.doc.lineAt(nodeFrom);
2324
+ const column = nodeFrom - line.from;
2325
+ if (parentColumn2 !== null && parentColumn2 > column) {
2326
+ padding = Math.max(padding, parentColumn2 - column);
2327
+ }
2328
+ let mark2;
2329
+ if (type === 0) {
2330
+ let max = counter2;
2331
+ for (let j = i + 1; j < blocks.length; j++) {
2332
+ if (blocks[j].counter !== max + 1) {
2333
+ break;
2334
+ }
2335
+ max++;
2336
+ }
2337
+ const num = String(counter2);
2338
+ padding = Math.max(String(max).length, padding);
2339
+ mark2 = " ".repeat(Math.max(0, padding - num.length)) + num + ". ";
2340
+ } else {
2341
+ mark2 = " ".repeat(padding) + "- " + (type === 2 ? "[ ] " : "");
2342
+ }
2343
+ changes.push({
2344
+ from: nodeFrom,
2345
+ insert: mark2
2346
+ });
2347
+ while (line.to < node.to) {
2348
+ line = state.doc.lineAt(line.to + 1);
2349
+ const open = /^[\s>]*/.exec(line.text)[0].length;
2350
+ changes.push({
2351
+ from: line.from + Math.min(open, column),
2352
+ insert: " ".repeat(mark2.length)
2353
+ });
2354
+ }
2355
+ }
2356
+ if (type === 0) {
2357
+ const last = blocks[blocks.length - 1];
2358
+ let next = last.node.nextSibling;
2359
+ while (next && /Mark$/.test(next.name)) {
2360
+ next = next.nextSibling;
2361
+ }
2362
+ if (next?.name === "OrderedList") {
2363
+ renumberListItems(next.firstChild, last.counter + 1, changes, state.doc);
2364
+ }
2365
+ }
2366
+ dispatch(state.update({
2367
+ changes,
2368
+ userEvent: "format.list.add",
2369
+ scrollIntoView: true
2370
+ }));
2371
+ return true;
2372
+ };
2373
+ var removeList = (type) => ({ state, dispatch }) => {
2374
+ let lastBlock = -1;
2375
+ const changes = [];
2376
+ const stack = [];
2377
+ const targetNodeType = type === 0 ? "OrderedList" : type === 1 ? "BulletList" : "TaskList";
2378
+ for (const { from, to } of state.selection.ranges) {
2379
+ syntaxTree2(state).iterate({
2380
+ from,
2381
+ to,
2382
+ enter: (node) => {
2383
+ const { name } = node;
2384
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2385
+ stack.push(name);
2386
+ } else if (name === "Task" && stack[stack.length - 1] === "BulletList") {
2387
+ stack[stack.length - 1] = "TaskList";
2388
+ }
2389
+ },
2390
+ leave: (node) => {
2391
+ const { name } = node;
2392
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2393
+ stack.pop();
2394
+ } else if (name === "ListItem" && stack[stack.length - 1] === targetNodeType && node.from !== lastBlock) {
2395
+ lastBlock = node.from;
2396
+ let line = state.doc.lineAt(node.from);
2397
+ const mark2 = /^\s*(\d+[.)] |[-*+] (\[[ x]\] )?)/.exec(line.text.slice(node.from - line.from));
2398
+ if (!mark2) {
2399
+ return false;
2400
+ }
2401
+ const column = node.from - line.from;
2402
+ changes.push({
2403
+ from: node.from,
2404
+ to: node.from + mark2[0].length
2405
+ });
2406
+ while (line.to < node.to) {
2407
+ line = state.doc.lineAt(line.to + 1);
2408
+ const open = /^[\s>]*/.exec(line.text)[0].length;
2409
+ if (open > column) {
2410
+ changes.push({
2411
+ from: line.from + column,
2412
+ to: line.from + Math.min(column + mark2[0].length, open)
2413
+ });
2414
+ }
2415
+ }
2416
+ if (node.to >= to) {
2417
+ renumberListItems(node.node.nextSibling, 1, changes, state.doc);
2418
+ }
2419
+ return false;
2420
+ }
2421
+ }
2422
+ });
2423
+ }
2424
+ if (!changes.length) {
2425
+ return false;
2426
+ }
2427
+ dispatch(state.update({
2428
+ changes,
2429
+ userEvent: "format.list.remove",
2430
+ scrollIntoView: true
2431
+ }));
2432
+ return true;
2433
+ };
2434
+ var toggleList = (type) => (target) => {
2435
+ const formatting2 = getFormatting(target.state);
2436
+ const active = formatting2.listStyle === (type === 1 ? "bullet" : type === 0 ? "ordered" : "task");
2437
+ return (active ? removeList(type) : addList(type))(target);
2438
+ };
2439
+ var renumberListItems = (item, counter, changes, doc) => {
2440
+ for (; item; item = item.nextSibling) {
2441
+ if (item.name === "ListItem") {
2442
+ const number = /(\s*)(\d+)[.)]/.exec(doc.sliceString(item.from, item.from + 10));
2443
+ if (!number || +number[2] === counter) {
2444
+ break;
2445
+ }
2446
+ const size = number[1].length + number[2].length;
2447
+ const newNum = String(counter);
2448
+ changes.push({
2449
+ from: item.from + Math.max(0, size - newNum.length),
2450
+ to: item.from + size,
2451
+ insert: newNum
2452
+ });
2453
+ counter++;
2454
+ }
2455
+ }
2456
+ };
2457
+ var setBlockquote = (enable) => ({ state, dispatch }) => {
2458
+ const lines = [];
2459
+ let lastBlock = -1;
2460
+ for (const { from, to } of state.selection.ranges) {
2461
+ syntaxTree2(state).iterate({
2462
+ from,
2463
+ to,
2464
+ enter: (node) => {
2465
+ if (Object.hasOwn(Textblocks, node.name) || node.name === "Table") {
2466
+ if (node.from === lastBlock) {
2467
+ return false;
2468
+ }
2469
+ lastBlock = node.from;
2470
+ let line = state.doc.lineAt(node.from);
2471
+ if (line.number > 1) {
2472
+ const prevLine = state.doc.line(line.number - 1);
2473
+ if (/^[>\s]*$/.test(prevLine.text)) {
2474
+ if (!enable || lines.length && lines[lines.length - 1].number === prevLine.number - 1) {
2475
+ lines.push(prevLine);
2476
+ }
2477
+ }
2478
+ }
2479
+ for (; ; ) {
2480
+ lines.push(line);
2481
+ if (line.to >= node.to) {
2482
+ break;
2483
+ }
2484
+ line = state.doc.line(line.number + 1);
2485
+ }
2486
+ if (!enable && line.number < state.doc.lines) {
2487
+ const nextLine = state.doc.line(line.number + 1);
2488
+ if (/^[>\s]*$/.test(nextLine.text)) {
2489
+ lines.push(nextLine);
2490
+ }
2491
+ }
2492
+ return false;
2493
+ }
2494
+ }
2495
+ });
2496
+ }
2497
+ const changes = [];
2498
+ for (const line of lines) {
2499
+ if (enable) {
2500
+ changes.push({
2501
+ from: line.from,
2502
+ insert: /\S/.test(line.text) ? "> " : ">"
2503
+ });
2504
+ } else {
2505
+ const quote = /((?:[\s>\-+*]|\d+[.)])*?)> ?/.exec(line.text);
2506
+ if (quote) {
2507
+ changes.push({
2508
+ from: line.from + quote[1].length,
2509
+ to: line.from + quote[0].length
2510
+ });
2511
+ }
2512
+ }
2513
+ }
2514
+ if (!changes.length) {
2515
+ return false;
2516
+ }
2517
+ dispatch(state.update({
2518
+ changes,
2519
+ userEvent: enable ? "format.blockquote.add" : "format.blockquote.remove",
2520
+ scrollIntoView: true
2521
+ }));
2522
+ return true;
2523
+ };
2524
+ var addBlockquote = setBlockquote(true);
2525
+ var removeBlockquote = setBlockquote(false);
2526
+ var toggleBlockquote = (target) => {
2527
+ return (getFormatting(target.state).blockquote ? removeBlockquote : addBlockquote)(target);
2528
+ };
2529
+ var addCodeblock = (target) => {
2530
+ const { state, dispatch } = target;
2531
+ const { selection } = state;
2532
+ if (selection.ranges.length === 1 && selection.main.empty) {
2533
+ const { head } = selection.main;
2534
+ const line = state.doc.lineAt(head);
2535
+ if (!/\S/.test(line.text) && head === line.from) {
2536
+ snippets.codeblock(target, null, line.from, line.to);
2537
+ return true;
2538
+ }
2539
+ }
2540
+ const ranges = [];
2541
+ for (const { from, to } of selection.ranges) {
2542
+ let blockFrom = from;
2543
+ let blockTo = to;
2544
+ syntaxTree2(state).iterate({
2545
+ from,
2546
+ to,
2547
+ enter: (node) => {
2548
+ if (Object.hasOwn(Textblocks, node.name)) {
2549
+ if (from >= node.from && to <= node.to) {
2550
+ blockFrom = node.from;
2551
+ blockTo = node.to;
2552
+ } else {
2553
+ blockFrom = Math.min(blockFrom, state.doc.lineAt(node.from).from);
2554
+ blockTo = Math.max(blockTo, state.doc.lineAt(node.to).to);
2555
+ }
2556
+ }
2557
+ }
2558
+ });
2559
+ if (ranges.length && ranges[ranges.length - 1].to >= blockFrom - 1) {
2560
+ ranges[ranges.length - 1].to = blockTo;
2561
+ } else {
2562
+ ranges.push({
2563
+ from: blockFrom,
2564
+ to: blockTo
2565
+ });
2566
+ }
2567
+ }
2568
+ if (!ranges.length) {
2569
+ return false;
2570
+ }
2571
+ const changes = ranges.map(({ from, to }) => {
2572
+ const column = from - state.doc.lineAt(from).from;
2573
+ return [
2574
+ {
2575
+ from,
2576
+ insert: "```\n" + " ".repeat(column)
2577
+ },
2578
+ {
2579
+ from: to,
2580
+ insert: "\n" + " ".repeat(column) + "```"
2581
+ }
2582
+ ];
2583
+ });
2584
+ dispatch(state.update({
2585
+ changes,
2586
+ userEvent: "format.codeblock.add",
2587
+ scrollIntoView: true
2588
+ }));
2589
+ return true;
2590
+ };
2591
+ var removeCodeblock = ({ state, dispatch }) => {
2592
+ const changes = [];
2593
+ let lastBlock = -1;
2594
+ for (const { from, to } of state.selection.ranges) {
2595
+ syntaxTree2(state).iterate({
2596
+ from,
2597
+ to,
2598
+ enter: (node) => {
2599
+ if (Textblocks[node.name] === "codeblock" && lastBlock !== node.from) {
2600
+ lastBlock = node.from;
2601
+ const firstLine = state.doc.lineAt(node.from);
2602
+ if (node.name === "FencedCode") {
2603
+ changes.push({
2604
+ from: node.from,
2605
+ to: firstLine.to + 1 + node.from - firstLine.from
2606
+ });
2607
+ const lastLine = state.doc.lineAt(node.to);
2608
+ if (/^([\s>]|[-*+] |\d+[).])*`+$/.test(lastLine.text)) {
2609
+ changes.push({
2610
+ from: lastLine.from - (lastLine.number === firstLine.number + 1 ? 0 : 1),
2611
+ to: lastLine.to
2612
+ });
2613
+ }
2614
+ } else {
2615
+ const column = node.from - firstLine.from;
2616
+ for (let line = firstLine; ; line = state.doc.line(line.number + 1)) {
2617
+ changes.push({
2618
+ from: line.from + column - 4,
2619
+ to: line.from + column
2620
+ });
2621
+ if (line.to >= node.to) {
2622
+ break;
2623
+ }
2624
+ }
2625
+ }
2626
+ }
2627
+ }
2628
+ });
2629
+ }
2630
+ if (!changes.length) {
2631
+ return false;
2632
+ }
2633
+ dispatch(state.update({
2634
+ changes,
2635
+ userEvent: "format.codeblock.remove",
2636
+ scrollIntoView: true
2637
+ }));
2638
+ return true;
2639
+ };
2640
+ var toggleCodeblock = (target) => {
2641
+ return (getFormatting(target.state).blockType === "codeblock" ? removeCodeblock : addCodeblock)(target);
2642
+ };
2643
+ var formatting = (options = {}) => {
2644
+ return [
2645
+ keymap5.of([
2646
+ {
2647
+ key: "meta-b",
2648
+ run: toggleStrong
2649
+ }
2650
+ ]),
2651
+ styling()
2652
+ ];
2653
+ };
2654
+ var styling = () => {
2655
+ const buildDecorations7 = (view) => {
2656
+ const builder = new RangeSetBuilder2();
2657
+ const { state } = view;
2658
+ const cursor = state.selection.main.head;
2659
+ const replace = (node, marks) => {
2660
+ if (cursor <= node.from || cursor >= node.to) {
2661
+ for (const mark2 of marks) {
2662
+ builder.add(mark2.from, mark2.to, Decoration4.replace({}));
2663
+ }
2664
+ }
2665
+ };
2666
+ for (const { from, to } of view.visibleRanges) {
2667
+ syntaxTree2(state).iterate({
2668
+ enter: (node) => {
2669
+ switch (node.name) {
2670
+ case "Emphasis":
2671
+ case "StrongEmphasis": {
2672
+ const marks = node.node.getChildren("EmphasisMark");
2673
+ replace(node, marks);
2674
+ break;
2675
+ }
2676
+ case "Strikethrough": {
2677
+ const marks = node.node.getChildren("StrikethroughMark");
2678
+ replace(node, marks);
2679
+ break;
2680
+ }
2681
+ }
2682
+ },
2683
+ from,
2684
+ to
2685
+ });
2686
+ }
2687
+ return builder.finish();
2688
+ };
2689
+ return [
2690
+ ViewPlugin4.fromClass(class {
2691
+ constructor(view) {
2692
+ this.decorations = buildDecorations7(view);
2693
+ }
2694
+ update(update2) {
2695
+ this.decorations = buildDecorations7(update2.view);
2696
+ }
2697
+ }, {
2698
+ decorations: (value) => value.decorations
2699
+ })
2700
+ ];
2701
+ };
2702
+ var InlineMarker = {
2703
+ Emphasis: 1,
2704
+ StrongEmphasis: 0,
2705
+ InlineCode: 3,
2706
+ Strikethrough: 2
2707
+ };
2708
+ var IgnoreInline = /* @__PURE__ */ new Set([
2709
+ "Hardbreak",
2710
+ "HTMLTag",
2711
+ "Comment",
2712
+ "ProcessingInstruction",
2713
+ "Autolink",
2714
+ "HeaderMark",
2715
+ "QuoteMark",
2716
+ "ListMark",
2717
+ "LinkMark",
2718
+ "EmphasisMark",
2719
+ "CodeMark",
2720
+ "CodeText",
2721
+ "StrikethroughMark",
2722
+ "TaskMarker",
2723
+ "SuperscriptMark",
2724
+ "SubscriptMark"
2725
+ ]);
2726
+ var Textblocks = {
2727
+ Paragraph: "paragraph",
2728
+ Task: "paragraph",
2729
+ CodeBlock: "codeblock",
2730
+ FencedCode: "codeblock",
2731
+ ATXHeading1: "heading1",
2732
+ ATXHeading2: "heading2",
2733
+ ATXHeading3: "heading3",
2734
+ ATXHeading4: "heading4",
2735
+ ATXHeading5: "heading5",
2736
+ ATXHeading6: "heading6",
2737
+ SetextHeading1: "heading1",
2738
+ SetextHeading2: "heading2",
2739
+ TableCell: "tablecell"
2740
+ };
2741
+ var getFormatting = (state) => {
2742
+ let blockType = null;
2743
+ const inline = [
2744
+ null,
2745
+ null,
2746
+ null,
2747
+ null
2748
+ ];
2749
+ let link2 = false;
2750
+ let blockquote2 = null;
2751
+ let listStyle = null;
2752
+ const stack = [];
2753
+ let currentBlock = null;
2754
+ const advanceInline = (upto) => {
2755
+ if (!currentBlock) {
2756
+ return;
2757
+ }
2758
+ upto = Math.min(upto, currentBlock.end);
2759
+ if (upto <= currentBlock.pos) {
2760
+ return;
2761
+ }
2762
+ for (let i = 0; i < currentBlock.active.length; i++) {
2763
+ if (inline[i] === false) {
2764
+ continue;
2765
+ } else if (currentBlock.active[i]) {
2766
+ inline[i] = true;
2767
+ } else if (/\S/.test(state.doc.sliceString(currentBlock.pos, upto))) {
2768
+ inline[i] = false;
2769
+ }
2770
+ }
2771
+ currentBlock.pos = upto;
2772
+ };
2773
+ const skipInline = (upto) => {
2774
+ if (currentBlock && upto > currentBlock.pos) {
2775
+ currentBlock.pos = Math.min(upto, currentBlock.end);
2776
+ }
2777
+ };
2778
+ const { selection } = state;
2779
+ for (const range of selection.ranges) {
2780
+ if (range.empty && inline.some((v) => v === null)) {
2781
+ const contextSize = Math.min(range.head, 6);
2782
+ const contextBefore = state.doc.sliceString(range.head - contextSize, range.head);
2783
+ let contextAfter = state.doc.sliceString(range.head, range.head + contextSize);
2784
+ for (let i = 0; i < contextSize; i++) {
2785
+ const ch = contextAfter[i];
2786
+ if (ch !== contextBefore[contextBefore.length - 1 - i] || !/[~`*]/.test(ch)) {
2787
+ contextAfter = contextAfter.slice(0, i);
2788
+ break;
2789
+ }
2790
+ }
2791
+ for (let i = 0; i < inline.length; i++) {
2792
+ const mark2 = inlineMarkerText(i);
2793
+ const found = contextAfter.indexOf(mark2);
2794
+ if (found > -1) {
2795
+ contextAfter = contextAfter.slice(0, found) + contextAfter.slice(found + mark2.length);
2796
+ if (inline[i] === null) {
2797
+ inline[i] = true;
2798
+ }
2799
+ }
2800
+ }
2801
+ }
2802
+ syntaxTree2(state).iterate({
2803
+ from: range.from,
2804
+ to: range.to,
2805
+ enter: (node) => {
2806
+ advanceInline(node.from);
2807
+ const { name } = node;
2808
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2809
+ stack.push(name);
2810
+ } else if (name === "Link") {
2811
+ link2 = true;
2812
+ } else if (Object.hasOwn(Textblocks, name) && (range.empty || node.to > range.from || node.from < range.to)) {
2813
+ if (name === "Task" && stack[stack.length - 1] === "BulletList") {
2814
+ stack[stack.length - 1] = "TaskList";
2815
+ }
2816
+ const blockCode = Textblocks[name];
2817
+ if (blockType === null) {
2818
+ blockType = blockCode;
2819
+ } else if (blockType !== blockCode) {
2820
+ blockType = false;
2821
+ }
2822
+ if (blockCode !== "codeblock" && inline.some((i) => i !== false)) {
2823
+ currentBlock = {
2824
+ pos: Math.max(range.from, node.from),
2825
+ end: Math.min(range.to, node.to),
2826
+ active: [
2827
+ false,
2828
+ false,
2829
+ false,
2830
+ false
2831
+ ]
2832
+ };
2833
+ }
2834
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
2835
+ const index = InlineMarker[name];
2836
+ if (range.empty && inline[index] === null) {
2837
+ inline[index] = true;
2838
+ }
2839
+ currentBlock.active[index] = true;
2840
+ } else if (IgnoreInline.has(name)) {
2841
+ skipInline(node.to);
2842
+ }
2843
+ },
2844
+ leave: (node) => {
2845
+ advanceInline(node.to);
2846
+ const { name } = node;
2847
+ if (name === "BulletList" || name === "OrderedList" || name === "Blockquote") {
2848
+ stack.pop();
2849
+ } else if (Object.hasOwn(Textblocks, name)) {
2850
+ let hasList = false;
2851
+ let hasQuote = false;
2852
+ for (let i = stack.length - 1; i >= 0; i--) {
2853
+ if (stack[i] === "Blockquote") {
2854
+ hasQuote = true;
2855
+ } else if (!hasList) {
2856
+ hasList = stack[i] === "TaskList" ? "task" : stack[i] === "BulletList" ? "bullet" : "ordered";
2857
+ }
2858
+ }
2859
+ if (blockquote2 === null) {
2860
+ blockquote2 = hasQuote;
2861
+ } else if (!hasQuote && blockquote2) {
2862
+ blockquote2 = false;
2863
+ }
2864
+ if (listStyle === null) {
2865
+ listStyle = hasList;
2866
+ } else if (listStyle !== hasList) {
2867
+ listStyle = false;
2868
+ }
2869
+ currentBlock = null;
2870
+ } else if (Object.hasOwn(InlineMarker, name) && currentBlock) {
2871
+ currentBlock.active[InlineMarker[name]] = false;
2872
+ }
2873
+ }
2874
+ });
2875
+ }
2876
+ return {
2877
+ blockType: blockType || null,
2878
+ strong: inline[0] ?? false,
2879
+ emphasis: inline[1] ?? false,
2880
+ code: inline[3] ?? false,
2881
+ strikethrough: inline[2] ?? false,
2882
+ link: link2,
2883
+ blockquote: blockquote2 ?? false,
2884
+ listStyle: listStyle || null
2885
+ };
2886
+ };
2887
+ var useFormattingState = () => {
2888
+ const [state, setState] = useState(null);
2889
+ const observer = useMemo(() => EditorView9.updateListener.of((update2) => {
2890
+ if (update2.docChanged || update2.selectionSet) {
2891
+ const newState = getFormatting(update2.state);
2892
+ if (!state || !compareFormatting(state, newState)) {
2893
+ setState(newState);
2894
+ }
2895
+ }
2896
+ }), []);
2897
+ return [
2898
+ state,
2899
+ observer
2900
+ ];
2901
+ };
2902
+
2903
+ // packages/ui/react-ui-editor/src/extensions/markdown/heading.ts
2904
+ import { syntaxTree as syntaxTree3 } from "@codemirror/language";
2905
+ import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
2906
+ import { Decoration as Decoration5, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
2907
+ var buildDecorations2 = (view) => {
2908
+ const builder = new RangeSetBuilder3();
2909
+ const { state } = view;
2910
+ const cursor = state.selection.main.head;
2911
+ for (const { from, to } of view.visibleRanges) {
2912
+ syntaxTree3(state).iterate({
2913
+ enter: (node) => {
2914
+ switch (node.name) {
2915
+ case "ATXHeading1":
2916
+ case "ATXHeading2":
2917
+ case "ATXHeading3":
2918
+ case "ATXHeading4":
2919
+ case "ATXHeading5":
2920
+ case "ATXHeading6": {
2921
+ const mark2 = node.node.getChild("HeaderMark");
2922
+ if (mark2) {
2923
+ if (!view.hasFocus || view.state.readOnly || cursor < node.from || cursor > node.to) {
2924
+ builder.add(mark2.from, mark2.to + 1, Decoration5.replace({}));
2925
+ }
2926
+ }
2927
+ }
2928
+ }
2929
+ },
2930
+ from,
2931
+ to
2932
+ });
2933
+ }
2934
+ return builder.finish();
2935
+ };
2936
+ var heading2 = () => {
2937
+ return [
2938
+ ViewPlugin5.fromClass(class {
2939
+ constructor(view) {
2940
+ this.decorations = buildDecorations2(view);
2941
+ }
2942
+ update(update2) {
2943
+ this.decorations = buildDecorations2(update2.view);
2944
+ }
2945
+ }, {
2946
+ decorations: (value) => value.decorations
2947
+ })
2948
+ ];
2949
+ };
2950
+
2951
+ // packages/ui/react-ui-editor/src/extensions/markdown/hr.ts
2952
+ import { syntaxTree as syntaxTree4 } from "@codemirror/language";
2953
+ import { RangeSetBuilder as RangeSetBuilder4 } from "@codemirror/state";
2954
+ import { Decoration as Decoration6, EditorView as EditorView10, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
2955
+ var styles4 = EditorView10.baseTheme({
2956
+ "& .cm-hr": {
2957
+ // Note that block-level decorations should not have vertical margins,
2958
+ borderTop: `1px solid ${getToken("extend.colors.neutral.200")}`
2959
+ }
2960
+ });
2961
+ var HorizontalRuleWidget = class extends WidgetType3 {
2962
+ toDOM() {
2963
+ const el = document.createElement("div");
2964
+ el.className = "cm-hr";
2965
+ return el;
2966
+ }
2967
+ };
2968
+ var decoration = Decoration6.replace({
2969
+ widget: new HorizontalRuleWidget()
2970
+ });
2971
+ var buildDecorations3 = (view) => {
2972
+ const builder = new RangeSetBuilder4();
2973
+ const { state } = view;
2974
+ const cursor = state.selection.main.head;
2975
+ for (const { from, to } of view.visibleRanges) {
2976
+ syntaxTree4(state).iterate({
2977
+ enter: (node) => {
2978
+ if (node.name === "HorizontalRule") {
2979
+ if (cursor <= node.from || cursor >= node.to) {
2980
+ builder.add(node.from, node.to, decoration);
2981
+ }
2982
+ }
2983
+ },
2984
+ from,
2985
+ to
2986
+ });
2987
+ }
2988
+ return builder.finish();
2989
+ };
2990
+ var hr = () => {
2991
+ return [
2992
+ ViewPlugin6.fromClass(class {
2993
+ constructor(view) {
2994
+ this.decorations = buildDecorations3(view);
2995
+ }
2996
+ update(update2) {
2997
+ this.decorations = buildDecorations3(update2.view);
2998
+ }
2999
+ }, {
3000
+ decorations: (value) => value.decorations
3001
+ }),
3002
+ styles4
3003
+ ];
3004
+ };
3005
+
3006
+ // packages/ui/react-ui-editor/src/extensions/markdown/image.ts
3007
+ import { syntaxTree as syntaxTree5 } from "@codemirror/language";
3008
+ import { StateField as StateField3 } from "@codemirror/state";
3009
+ import { Decoration as Decoration7, EditorView as EditorView11, WidgetType as WidgetType4 } from "@codemirror/view";
3010
+ var image = (options = {}) => {
3011
+ return StateField3.define({
3012
+ create: (state) => {
3013
+ return Decoration7.set(buildDecorations4(0, state.doc.length, state));
3014
+ },
3015
+ update: (value, tr) => {
3016
+ if (!tr.docChanged && !tr.selection) {
3017
+ return value;
3018
+ }
3019
+ const cursor = tr.state.selection.main.head;
3020
+ const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
3021
+ let from = Math.min(cursor, oldCursor);
3022
+ let to = Math.max(cursor, oldCursor);
3023
+ tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
3024
+ from = Math.min(from, fromB);
3025
+ to = Math.max(to, toB);
1864
3026
  });
1865
3027
  from = tr.state.doc.lineAt(from).from;
1866
3028
  to = tr.state.doc.lineAt(to).to;
@@ -1868,23 +3030,23 @@ var image = (options = {}) => {
1868
3030
  filterFrom: from,
1869
3031
  filterTo: to,
1870
3032
  filter: () => false,
1871
- add: buildDecorations3(from, to, tr.state)
3033
+ add: buildDecorations4(from, to, tr.state)
1872
3034
  });
1873
3035
  },
1874
- provide: (field) => EditorView10.decorations.from(field)
3036
+ provide: (field) => EditorView11.decorations.from(field)
1875
3037
  });
1876
3038
  };
1877
- var buildDecorations3 = (from, to, state) => {
3039
+ var buildDecorations4 = (from, to, state) => {
1878
3040
  const decorations = [];
1879
3041
  const cursor = state.selection.main.head;
1880
- syntaxTree3(state).iterate({
3042
+ syntaxTree5(state).iterate({
1881
3043
  enter: (node) => {
1882
3044
  if (node.name === "Image") {
1883
3045
  const urlNode = node.node.getChild("URL");
1884
3046
  if (urlNode) {
1885
3047
  const hide = state.readOnly || cursor < node.from || cursor > node.to;
1886
3048
  const url = state.sliceDoc(urlNode.from, urlNode.to);
1887
- decorations.push(Decoration6.replace({
3049
+ decorations.push(Decoration7.replace({
1888
3050
  block: true,
1889
3051
  widget: new ImageWidget(url)
1890
3052
  }).range(hide ? node.from : node.to, node.to));
@@ -1896,7 +3058,7 @@ var buildDecorations3 = (from, to, state) => {
1896
3058
  });
1897
3059
  return decorations;
1898
3060
  };
1899
- var ImageWidget = class extends WidgetType3 {
3061
+ var ImageWidget = class extends WidgetType4 {
1900
3062
  constructor(_url) {
1901
3063
  super();
1902
3064
  this._url = _url;
@@ -1914,23 +3076,23 @@ var ImageWidget = class extends WidgetType3 {
1914
3076
  };
1915
3077
 
1916
3078
  // packages/ui/react-ui-editor/src/extensions/markdown/link.ts
1917
- import { syntaxTree as syntaxTree4 } from "@codemirror/language";
1918
- import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
1919
- import { hoverTooltip as hoverTooltip2, Decoration as Decoration7, ViewPlugin as ViewPlugin6, WidgetType as WidgetType4 } from "@codemirror/view";
3079
+ import { syntaxTree as syntaxTree6 } from "@codemirror/language";
3080
+ import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
3081
+ import { hoverTooltip as hoverTooltip2, Decoration as Decoration8, ViewPlugin as ViewPlugin7, WidgetType as WidgetType5 } from "@codemirror/view";
1920
3082
  import { tooltipContent } from "@dxos/react-ui-theme";
1921
3083
  var link = (options = {}) => {
1922
3084
  const extensions = [
1923
- ViewPlugin6.fromClass(class {
3085
+ ViewPlugin7.fromClass(class {
1924
3086
  constructor(view) {
1925
- this.decorations = buildDecorations4(view, options);
3087
+ this.decorations = buildDecorations5(view, options);
1926
3088
  }
1927
3089
  update(update2) {
1928
3090
  if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
1929
- this.decorations = buildDecorations4(update2.view, options);
3091
+ this.decorations = buildDecorations5(update2.view, options);
1930
3092
  }
1931
3093
  }
1932
3094
  }, {
1933
- decorations: (v) => v.decorations
3095
+ decorations: (value) => value.decorations
1934
3096
  })
1935
3097
  ];
1936
3098
  if (options.onHover) {
@@ -1939,7 +3101,7 @@ var link = (options = {}) => {
1939
3101
  // https://codemirror.net/docs/ref/#view.hoverTooltip
1940
3102
  // https://github.com/codemirror/view/blob/main/src/tooltip.ts
1941
3103
  hoverTooltip2((view, pos, side) => {
1942
- const syntax = syntaxTree4(view.state).resolveInner(pos, side);
3104
+ const syntax = syntaxTree6(view.state).resolveInner(pos, side);
1943
3105
  let link2 = null;
1944
3106
  for (let i = 0, node = syntax; !link2 && node && i < 5; node = node.parent, i++) {
1945
3107
  link2 = node.name === "Link" ? node : null;
@@ -1971,7 +3133,7 @@ var link = (options = {}) => {
1971
3133
  }
1972
3134
  return extensions;
1973
3135
  };
1974
- var LinkButton = class extends WidgetType4 {
3136
+ var LinkButton = class extends WidgetType5 {
1975
3137
  constructor(_url, _onAttach) {
1976
3138
  super();
1977
3139
  this._url = _url;
@@ -1986,7 +3148,7 @@ var LinkButton = class extends WidgetType4 {
1986
3148
  return el;
1987
3149
  }
1988
3150
  };
1989
- var LinkText = class extends WidgetType4 {
3151
+ var LinkText = class extends WidgetType5 {
1990
3152
  constructor(_text, _url) {
1991
3153
  super();
1992
3154
  this._text = _text;
@@ -2015,28 +3177,28 @@ var LinkText = class extends WidgetType4 {
2015
3177
  return link2;
2016
3178
  }
2017
3179
  };
2018
- var buildDecorations4 = (view, options) => {
2019
- const builder = new RangeSetBuilder3();
3180
+ var buildDecorations5 = (view, options) => {
3181
+ const builder = new RangeSetBuilder5();
2020
3182
  const { state } = view;
2021
3183
  const cursor = state.selection.main.head;
2022
3184
  for (const { from, to } of view.visibleRanges) {
2023
- syntaxTree4(state).iterate({
3185
+ syntaxTree6(state).iterate({
2024
3186
  enter: (node) => {
2025
3187
  if (node.name === "Link") {
2026
- const marks2 = node.node.getChildren("LinkMark");
2027
- const text = marks2.length >= 2 ? state.sliceDoc(marks2[0].to, marks2[1].from) : "";
3188
+ const marks = node.node.getChildren("LinkMark");
3189
+ const text = marks.length >= 2 ? state.sliceDoc(marks[0].to, marks[1].from) : "";
2028
3190
  const urlNode = node.node.getChild("URL");
2029
3191
  const url = urlNode ? state.sliceDoc(urlNode.from, urlNode.to) : "";
2030
3192
  if (!url) {
2031
3193
  return false;
2032
3194
  }
2033
3195
  if (!view.hasFocus || state.readOnly || cursor < node.from || cursor > node.to) {
2034
- builder.add(node.from, node.to, Decoration7.replace({
3196
+ builder.add(node.from, node.to, Decoration8.replace({
2035
3197
  widget: new LinkText(text, options.link ? url : void 0)
2036
3198
  }));
2037
3199
  }
2038
3200
  if (options.onRender) {
2039
- builder.add(node.to, node.to, Decoration7.replace({
3201
+ builder.add(node.to, node.to, Decoration8.replace({
2040
3202
  widget: new LinkButton(url, options.onRender)
2041
3203
  }));
2042
3204
  }
@@ -2051,18 +3213,18 @@ var buildDecorations4 = (view, options) => {
2051
3213
  };
2052
3214
 
2053
3215
  // packages/ui/react-ui-editor/src/extensions/markdown/table.ts
2054
- import { syntaxTree as syntaxTree5 } from "@codemirror/language";
2055
- import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField4 } from "@codemirror/state";
2056
- import { Decoration as Decoration8, EditorView as EditorView11, WidgetType as WidgetType5 } from "@codemirror/view";
3216
+ import { syntaxTree as syntaxTree7 } from "@codemirror/language";
3217
+ import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField4 } from "@codemirror/state";
3218
+ import { Decoration as Decoration9, EditorView as EditorView12, WidgetType as WidgetType6 } from "@codemirror/view";
2057
3219
  var table = (options = {}) => {
2058
3220
  return StateField4.define({
2059
3221
  create: (state) => update(state, options),
2060
3222
  update: (_, tr) => update(tr.state, options),
2061
- provide: (field) => EditorView11.decorations.from(field)
3223
+ provide: (field) => EditorView12.decorations.from(field)
2062
3224
  });
2063
3225
  };
2064
3226
  var update = (state, options) => {
2065
- const builder = new RangeSetBuilder4();
3227
+ const builder = new RangeSetBuilder6();
2066
3228
  const cursor = state.selection.main.head;
2067
3229
  const tables = [];
2068
3230
  const getTable = () => tables[tables.length - 1];
@@ -2070,7 +3232,7 @@ var update = (state, options) => {
2070
3232
  const table2 = getTable();
2071
3233
  return table2.rows?.[table2.rows.length - 1];
2072
3234
  };
2073
- syntaxTree5(state).iterate({
3235
+ syntaxTree7(state).iterate({
2074
3236
  enter: (node) => {
2075
3237
  switch (node.name) {
2076
3238
  case "Table": {
@@ -2102,16 +3264,16 @@ var update = (state, options) => {
2102
3264
  });
2103
3265
  tables.forEach((table2) => {
2104
3266
  const hide = state.readOnly || cursor < table2.from || cursor > table2.to;
2105
- hide && builder.add(table2.from, table2.to, Decoration8.replace({
3267
+ hide && builder.add(table2.from, table2.to, Decoration9.replace({
2106
3268
  widget: new TableWidget(table2)
2107
3269
  }));
2108
- builder.add(table2.from, table2.to, Decoration8.mark({
3270
+ builder.add(table2.from, table2.to, Decoration9.mark({
2109
3271
  class: "cm-table"
2110
3272
  }));
2111
3273
  });
2112
3274
  return builder.finish();
2113
3275
  };
2114
- var TableWidget = class extends WidgetType5 {
3276
+ var TableWidget = class extends WidgetType6 {
2115
3277
  constructor(_table) {
2116
3278
  super();
2117
3279
  this._table = _table;
@@ -2149,10 +3311,10 @@ var TableWidget = class extends WidgetType5 {
2149
3311
  };
2150
3312
 
2151
3313
  // packages/ui/react-ui-editor/src/extensions/markdown/tasklist.ts
2152
- import { syntaxTree as syntaxTree6 } from "@codemirror/language";
2153
- import { RangeSetBuilder as RangeSetBuilder5 } from "@codemirror/state";
2154
- import { EditorView as EditorView12, Decoration as Decoration9, WidgetType as WidgetType6, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
2155
- var styles5 = EditorView12.baseTheme({
3314
+ import { syntaxTree as syntaxTree8 } from "@codemirror/language";
3315
+ import { RangeSetBuilder as RangeSetBuilder7 } from "@codemirror/state";
3316
+ import { EditorView as EditorView13, Decoration as Decoration10, WidgetType as WidgetType7, ViewPlugin as ViewPlugin8 } from "@codemirror/view";
3317
+ var styles5 = EditorView13.baseTheme({
2156
3318
  "& .cm-task": {
2157
3319
  color: getToken("extend.colors.blue.500")
2158
3320
  },
@@ -2161,7 +3323,7 @@ var styles5 = EditorView12.baseTheme({
2161
3323
  marginRight: "4px"
2162
3324
  }
2163
3325
  });
2164
- var CheckboxWidget = class extends WidgetType6 {
3326
+ var CheckboxWidget = class extends WidgetType7 {
2165
3327
  constructor(_checked) {
2166
3328
  super();
2167
3329
  this._checked = _checked;
@@ -2198,23 +3360,23 @@ var CheckboxWidget = class extends WidgetType6 {
2198
3360
  return false;
2199
3361
  }
2200
3362
  };
2201
- var checkedDecoration = Decoration9.replace({
3363
+ var checkedDecoration = Decoration10.replace({
2202
3364
  widget: new CheckboxWidget(true)
2203
3365
  });
2204
- var uncheckedDecoration = Decoration9.replace({
3366
+ var uncheckedDecoration = Decoration10.replace({
2205
3367
  widget: new CheckboxWidget(false)
2206
3368
  });
2207
- var buildDecorations5 = (view) => {
2208
- const builder = new RangeSetBuilder5();
3369
+ var buildDecorations6 = (view) => {
3370
+ const builder = new RangeSetBuilder7();
2209
3371
  const { state } = view;
2210
3372
  const cursor = state.selection.main.head;
2211
3373
  for (const { from, to } of view.visibleRanges) {
2212
- syntaxTree6(state).iterate({
3374
+ syntaxTree8(state).iterate({
2213
3375
  enter: (node) => {
2214
3376
  if (node.name === "TaskMarker") {
2215
3377
  if (cursor < node.from || cursor > node.to) {
2216
3378
  const checked = state.doc.sliceString(node.from + 1, node.to - 1) === "x";
2217
- builder.add(node.from - 2, node.from - 1, Decoration9.mark({
3379
+ builder.add(node.from - 2, node.from - 1, Decoration10.mark({
2218
3380
  class: "cm-task"
2219
3381
  }));
2220
3382
  builder.add(node.from, node.to, checked ? checkedDecoration : uncheckedDecoration);
@@ -2229,17 +3391,17 @@ var buildDecorations5 = (view) => {
2229
3391
  };
2230
3392
  var tasklist = (options = {}) => {
2231
3393
  return [
2232
- ViewPlugin7.fromClass(class {
3394
+ ViewPlugin8.fromClass(class {
2233
3395
  constructor(view) {
2234
- this.decorations = buildDecorations5(view);
3396
+ this.decorations = buildDecorations6(view);
2235
3397
  }
2236
3398
  update(update2) {
2237
3399
  if (update2.docChanged || update2.viewportChanged || update2.selectionSet) {
2238
- this.decorations = buildDecorations5(update2.view);
3400
+ this.decorations = buildDecorations6(update2.view);
2239
3401
  }
2240
3402
  }
2241
3403
  }, {
2242
- decorations: (v) => v.decorations
3404
+ decorations: (value) => value.decorations
2243
3405
  }),
2244
3406
  styles5
2245
3407
  ];
@@ -2280,7 +3442,7 @@ var outliner = (options = {}) => {
2280
3442
  };
2281
3443
 
2282
3444
  // packages/ui/react-ui-editor/src/extensions/typewriter.ts
2283
- import { keymap as keymap5 } from "@codemirror/view";
3445
+ import { keymap as keymap6 } from "@codemirror/view";
2284
3446
  var defaultItems = [
2285
3447
  "hello world!",
2286
3448
  "this is a test.",
@@ -2290,7 +3452,7 @@ var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
2290
3452
  let t;
2291
3453
  let idx = 0;
2292
3454
  return [
2293
- keymap5.of([
3455
+ keymap6.of([
2294
3456
  {
2295
3457
  // Reset.
2296
3458
  key: "alt-meta-'",
@@ -2367,8 +3529,9 @@ var defaultTheme = {
2367
3529
  outline: "none"
2368
3530
  },
2369
3531
  ".cm-scroller": {
2370
- overflow: "visible",
2371
- fontFamily: get3(tokens, "fontFamily.mono", []).join(",")
3532
+ // overflow: 'visible',
3533
+ fontFamily: get3(tokens, "fontFamily.mono", []).join(","),
3534
+ lineHeight: 1.4
2372
3535
  },
2373
3536
  ".cm-content": {
2374
3537
  padding: 0,
@@ -2376,11 +3539,11 @@ var defaultTheme = {
2376
3539
  fontSize: "16px"
2377
3540
  },
2378
3541
  "&light .cm-content": {
2379
- color: get3(tokens, "extend.colors.neutral.900", "black"),
3542
+ color: get3(tokens, "extend.semanticColors.base.fg.light", "black"),
2380
3543
  caretColor: "black"
2381
3544
  },
2382
3545
  "&dark .cm-content": {
2383
- color: get3(tokens, "extend.colors.neutral.100", "white"),
3546
+ color: get3(tokens, "extend.semanticColors.base.fg.dark", "white"),
2384
3547
  caretColor: "white"
2385
3548
  },
2386
3549
  //
@@ -2392,8 +3555,11 @@ var defaultTheme = {
2392
3555
  "&dark .cm-cursor, &dark .cm-dropCursor": {
2393
3556
  borderLeft: "2px solid white"
2394
3557
  },
2395
- ".cm-placeholder": {
2396
- fontWeight: 100
3558
+ "&light .cm-placeholder": {
3559
+ color: get3(tokens, "extend.semanticColors.description.light", "rgba(0,0,0,.2)")
3560
+ },
3561
+ "&dark .cm-placeholder": {
3562
+ color: get3(tokens, "extend.semanticColors.description.dark", "rgba(255,255,255,.2)")
2397
3563
  },
2398
3564
  //
2399
3565
  // line
@@ -2402,7 +3568,7 @@ var defaultTheme = {
2402
3568
  paddingInline: 0
2403
3569
  },
2404
3570
  ".cm-activeLine": {
2405
- background: "inherit"
3571
+ background: "transparent"
2406
3572
  },
2407
3573
  //
2408
3574
  // Selection
@@ -2573,23 +3739,28 @@ var codeTheme = {
2573
3739
  };
2574
3740
 
2575
3741
  // packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx
2576
- var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
3742
+ var __dxlog_file3 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/components/TextEditor/TextEditor.tsx";
2577
3743
  var EditorModes = [
2578
3744
  "default",
2579
3745
  "vim"
2580
3746
  ];
2581
3747
  var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, scrollTo, selection, editorMode, theme, slots = defaultSlots, extensions = [], debug }, forwardedRef) => {
2582
- const tabsterDOMAttribute = useFocusableGroup({
2583
- tabBehavior: "limited"
2584
- });
2585
3748
  const { themeMode } = useThemeContext();
2586
3749
  const rootRef = useRef(null);
2587
- const [view, setView] = useState(null);
3750
+ const [view, setView] = useState2(null);
2588
3751
  useImperativeHandle(forwardedRef, () => view, [
2589
3752
  view
2590
3753
  ]);
2591
3754
  useEffect2(() => {
2592
- if (autoFocus) {
3755
+ if (autoFocus && !view?.hasFocus) {
3756
+ if (view?.state.selection.main?.from === 0) {
3757
+ const { to } = view.state.doc.lineAt(0);
3758
+ view?.dispatch({
3759
+ selection: {
3760
+ anchor: to
3761
+ }
3762
+ });
3763
+ }
2593
3764
  view?.focus();
2594
3765
  }
2595
3766
  }, [
@@ -2605,37 +3776,38 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
2605
3776
  selection,
2606
3777
  extensions: [
2607
3778
  // TODO(burdon): Doesn't catch errors in keymap functions.
2608
- EditorView13.exceptionSink.of((err) => {
3779
+ EditorView14.exceptionSink.of((err) => {
2609
3780
  log2.catch(err, void 0, {
2610
- F: __dxlog_file5,
2611
- L: 123,
3781
+ F: __dxlog_file3,
3782
+ L: 134,
2612
3783
  S: void 0,
2613
3784
  C: (f, a) => f(...a)
2614
3785
  });
2615
3786
  }),
2616
3787
  // Theme.
2617
3788
  // TODO(burdon): Make configurable.
2618
- EditorView13.baseTheme(defaultTheme),
2619
- EditorView13.theme(theme ?? {}),
2620
- EditorView13.darkTheme.of(themeMode === "dark"),
2621
- EditorView13.editorAttributes.of({
3789
+ EditorView14.baseTheme(defaultTheme),
3790
+ EditorView14.theme(theme ?? {}),
3791
+ EditorView14.darkTheme.of(themeMode === "dark"),
3792
+ EditorView14.editorAttributes.of({
2622
3793
  class: slots.editor?.className ?? ""
2623
3794
  }),
2624
- EditorView13.contentAttributes.of({
3795
+ EditorView14.contentAttributes.of({
2625
3796
  class: slots.content?.className ?? ""
2626
3797
  }),
2627
3798
  // State.
3799
+ EditorView14.editable.of(!readonly),
2628
3800
  EditorState2.readOnly.of(!!readonly),
2629
3801
  // Storage and replication.
2630
3802
  // NOTE: This must come before user extensions.
2631
3803
  model.extension,
2632
- // TODO(burdon): Factor out (requires special handling for Escape/focus).
3804
+ // TODO(burdon): Factor out? (Requires special handling for Escape/Enter below).
2633
3805
  editorMode === "vim" && vim(),
2634
3806
  // Custom.
2635
3807
  ...extensions
2636
- ].filter(Boolean)
3808
+ ].filter(isNotFalsy3)
2637
3809
  });
2638
- const newView = new EditorView13({
3810
+ const newView = new EditorView14({
2639
3811
  state,
2640
3812
  parent: rootRef.current,
2641
3813
  scrollTo,
@@ -2670,7 +3842,7 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
2670
3842
  }
2671
3843
  case "Escape": {
2672
3844
  if (editorMode === "vim" && (altKey || shiftKey || metaKey || ctrlKey)) {
2673
- rootRef.current?.focus();
3845
+ view?.focus();
2674
3846
  }
2675
3847
  break;
2676
3848
  }
@@ -2683,9 +3855,9 @@ var BaseTextEditor = /* @__PURE__ */ forwardRef(({ model, readonly, autoFocus, s
2683
3855
  key: model.id,
2684
3856
  role: "none",
2685
3857
  tabIndex: 0,
2686
- onKeyUp: handleKeyUp,
2687
3858
  ...slots.root,
2688
- ...editorMode !== "vim" && tabsterDOMAttribute,
3859
+ // {...(editorMode !== 'vim' && tabsterDOMAttribute)}
3860
+ onKeyUp: handleKeyUp,
2689
3861
  ref: rootRef
2690
3862
  });
2691
3863
  });
@@ -2696,7 +3868,7 @@ var TextEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeholde
2696
3868
  ref: forwardedRef,
2697
3869
  readonly,
2698
3870
  extensions: [
2699
- basicBundle({
3871
+ createBasicBundle({
2700
3872
  themeMode,
2701
3873
  placeholder: placeholder3,
2702
3874
  lineWrapping
@@ -2715,9 +3887,8 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
2715
3887
  ref: forwardedRef,
2716
3888
  readonly,
2717
3889
  extensions: [
2718
- markdownBundle({
3890
+ createMarkdownExtensions({
2719
3891
  themeMode,
2720
- readonly,
2721
3892
  placeholder: placeholder3
2722
3893
  }),
2723
3894
  ...extensions
@@ -2729,11 +3900,10 @@ var MarkdownEditor = /* @__PURE__ */ forwardRef(({ readonly, placeholder: placeh
2729
3900
  });
2730
3901
  var defaultSlots = {
2731
3902
  root: {
2732
- // TODO(burdon): Add focusRing by default/as property?
2733
- className: mx3("flex flex-col grow overflow-y-auto", attentionSurface)
3903
+ className: mx3("grow", focusRing)
2734
3904
  },
2735
3905
  editor: {
2736
- className: "h-full p-2"
3906
+ className: "bs-full"
2737
3907
  }
2738
3908
  };
2739
3909
  var defaultTextSlots = {
@@ -2743,12 +3913,200 @@ var defaultMarkdownSlots = {
2743
3913
  ...defaultSlots
2744
3914
  };
2745
3915
 
3916
+ // packages/ui/react-ui-editor/src/components/Toolbar/Toolbar.tsx
3917
+ import { CaretRight, ChatText, Code, Link, ListBullets, ListChecks, ListNumbers, Paragraph, TextStrikethrough, Table as Table2, TextB, TextItalic } from "@phosphor-icons/react";
3918
+ import { createContext } from "@radix-ui/react-context";
3919
+ import React2 from "react";
3920
+ import { Button, DensityProvider, Select } from "@dxos/react-ui";
3921
+ import { getSize, mx as mx4 } from "@dxos/react-ui-theme";
3922
+ var [ToolbarContextProvider, useToolbarContext] = createContext("Toolbar");
3923
+ var ToolbarRoot = ({ children, onAction, state }) => {
3924
+ return /* @__PURE__ */ React2.createElement(ToolbarContextProvider, {
3925
+ onAction,
3926
+ state
3927
+ }, /* @__PURE__ */ React2.createElement(DensityProvider, {
3928
+ density: "fine"
3929
+ }, /* @__PURE__ */ React2.createElement("div", {
3930
+ role: "toolbar",
3931
+ className: "flex w-full shrink-0 p-1 gap-2 items-center whitespace-nowrap overflow-hidden"
3932
+ }, children)));
3933
+ };
3934
+ var ToolbarButton = ({ Icon, onClick, title, getState, disable }) => {
3935
+ const { onAction, state } = useToolbarContext("ToolbarButton");
3936
+ const active = getState && state ? getState(state) : false;
3937
+ const disabled = disable && state ? disable(state) : false;
3938
+ const handleClick = (event) => {
3939
+ const action = onClick(state);
3940
+ if (action) {
3941
+ onAction?.(action);
3942
+ event.preventDefault();
3943
+ }
3944
+ };
3945
+ return /* @__PURE__ */ React2.createElement(Button, {
3946
+ variant: "ghost",
3947
+ classNames: mx4("p-2", active && "ring-[1px]"),
3948
+ onMouseDown: handleClick,
3949
+ title,
3950
+ disabled
3951
+ }, /* @__PURE__ */ React2.createElement(Icon, {
3952
+ className: getSize(5)
3953
+ }));
3954
+ };
3955
+ var ToolbarSeparator = () => /* @__PURE__ */ React2.createElement("div", {
3956
+ className: "grow"
3957
+ });
3958
+ var MarkdownHeading = () => {
3959
+ const { onAction, state } = useToolbarContext("MarkdownFormatting");
3960
+ const blockType = state ? state.blockType : "paragraph";
3961
+ const header = blockType && /heading(\d)/.exec(blockType);
3962
+ const value = header ? header[1] : blockType === "paragraph" || !blockType ? "0" : null;
3963
+ return /* @__PURE__ */ React2.createElement(Select.Root, {
3964
+ disabled: value === null,
3965
+ value: value ?? "0",
3966
+ onValueChange: (value2) => onAction?.({
3967
+ type: "heading",
3968
+ data: parseInt(value2)
3969
+ })
3970
+ }, /* @__PURE__ */ React2.createElement(Select.TriggerButton, null, /* @__PURE__ */ React2.createElement(Paragraph, {
3971
+ className: getSize(5)
3972
+ })), /* @__PURE__ */ React2.createElement(Select.Portal, null, /* @__PURE__ */ React2.createElement(Select.Content, null, /* @__PURE__ */ React2.createElement(Select.Viewport, null, /* @__PURE__ */ React2.createElement(Select.Option, {
3973
+ value: "0"
3974
+ }, "Paragraph"), [
3975
+ 1,
3976
+ 2,
3977
+ 3,
3978
+ 4,
3979
+ 5,
3980
+ 6
3981
+ ].map((level) => /* @__PURE__ */ React2.createElement(Select.Option, {
3982
+ key: level,
3983
+ value: String(level)
3984
+ }, "Heading ", level))))));
3985
+ };
3986
+ var MarkdownStyles = () => /* @__PURE__ */ React2.createElement("div", {
3987
+ role: "none"
3988
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
3989
+ Icon: TextB,
3990
+ title: "String",
3991
+ disable: (s) => s.blockType === "codeblock",
3992
+ getState: (s) => s.strong,
3993
+ onClick: (s) => ({
3994
+ type: "strong",
3995
+ data: s ? !s.strong : null
3996
+ })
3997
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
3998
+ Icon: TextItalic,
3999
+ title: "Emphasis",
4000
+ disable: (s) => s.blockType === "codeblock",
4001
+ getState: (s) => s.emphasis,
4002
+ onClick: (s) => ({
4003
+ type: "emphasis",
4004
+ data: s ? !s.emphasis : null
4005
+ })
4006
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4007
+ Icon: TextStrikethrough,
4008
+ title: "Strike-through",
4009
+ disable: (s) => s.blockType === "codeblock",
4010
+ getState: (s) => s.strikethrough,
4011
+ onClick: (s) => ({
4012
+ type: "strikethrough",
4013
+ data: s ? !s.strikethrough : null
4014
+ })
4015
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4016
+ Icon: Code,
4017
+ title: "Inline code",
4018
+ disable: (s) => s.blockType === "codeblock",
4019
+ getState: (s) => s.code,
4020
+ onClick: (s) => ({
4021
+ type: "code",
4022
+ data: s ? !s.code : null
4023
+ })
4024
+ }));
4025
+ var MarkdownLists = () => /* @__PURE__ */ React2.createElement("div", {
4026
+ role: "none"
4027
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
4028
+ Icon: ListBullets,
4029
+ title: "Bullet list",
4030
+ getState: (s) => s.listStyle === "bullet",
4031
+ onClick: (s) => ({
4032
+ type: "list-bullet",
4033
+ data: s ? s.listStyle !== "bullet" : null
4034
+ })
4035
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4036
+ Icon: ListNumbers,
4037
+ title: "Numbered list",
4038
+ getState: (s) => s.listStyle === "ordered",
4039
+ onClick: (s) => ({
4040
+ type: "list-ordered",
4041
+ data: s ? s.listStyle !== "ordered" : null
4042
+ })
4043
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4044
+ Icon: ListChecks,
4045
+ title: "Task list",
4046
+ getState: (s) => s.listStyle === "task",
4047
+ onClick: (s) => ({
4048
+ type: "list-tasks",
4049
+ data: s ? s.listStyle !== "task" : null
4050
+ })
4051
+ }));
4052
+ var MarkdownBlocks = () => /* @__PURE__ */ React2.createElement("div", {
4053
+ role: "none"
4054
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
4055
+ Icon: CaretRight,
4056
+ title: "Block quote",
4057
+ getState: (s) => s.blockquote,
4058
+ onClick: (s) => ({
4059
+ type: "blockquote",
4060
+ data: s ? !s.blockquote : null
4061
+ })
4062
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4063
+ Icon: Code,
4064
+ title: "Code block",
4065
+ getState: (s) => s.blockType === "codeblock",
4066
+ onClick: (s) => ({
4067
+ type: "codeblock",
4068
+ data: s ? s.blockType !== "codeblock" : null
4069
+ })
4070
+ }), /* @__PURE__ */ React2.createElement(ToolbarButton, {
4071
+ Icon: Table2,
4072
+ title: "Table",
4073
+ onClick: () => ({
4074
+ type: "table"
4075
+ })
4076
+ }));
4077
+ var MarkdownLinks = () => /* @__PURE__ */ React2.createElement("div", {
4078
+ role: "none"
4079
+ }, /* @__PURE__ */ React2.createElement(ToolbarButton, {
4080
+ Icon: Link,
4081
+ title: "Link",
4082
+ getState: (s) => s.link,
4083
+ onClick: (s) => ({
4084
+ type: "link",
4085
+ data: s ? !s.link : null
4086
+ })
4087
+ }));
4088
+ var MarkdownStandard = () => /* @__PURE__ */ React2.createElement(React2.Fragment, null, /* @__PURE__ */ React2.createElement(MarkdownHeading, null), /* @__PURE__ */ React2.createElement(MarkdownStyles, null), /* @__PURE__ */ React2.createElement(MarkdownLists, null), /* @__PURE__ */ React2.createElement(MarkdownBlocks, null), /* @__PURE__ */ React2.createElement(MarkdownLinks, null));
4089
+ var MarkdownExtended = () => /* @__PURE__ */ React2.createElement(Toolbar.Button, {
4090
+ Icon: ChatText,
4091
+ title: "Create comment",
4092
+ onClick: () => ({
4093
+ type: "comment"
4094
+ })
4095
+ });
4096
+ var Toolbar = {
4097
+ Root: ToolbarRoot,
4098
+ Button: ToolbarButton,
4099
+ Separator: ToolbarSeparator,
4100
+ Markdown: MarkdownStandard,
4101
+ Extended: MarkdownExtended
4102
+ };
4103
+
2746
4104
  // packages/ui/react-ui-editor/src/hooks/awareness-provider.ts
2747
4105
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
2748
4106
  import { Context as Context2 } from "@dxos/context";
2749
- import { invariant as invariant4 } from "@dxos/invariant";
4107
+ import { invariant as invariant2 } from "@dxos/invariant";
2750
4108
  import { log as log3 } from "@dxos/log";
2751
- var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
4109
+ var __dxlog_file4 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/awareness-provider.ts";
2752
4110
  var DEBOUNCE_INTERVAL = 100;
2753
4111
  var SpaceAwarenessProvider = class {
2754
4112
  constructor(params) {
@@ -2788,7 +4146,7 @@ var SpaceAwarenessProvider = class {
2788
4146
  log3.debug("failed to query awareness", {
2789
4147
  err
2790
4148
  }, {
2791
- F: __dxlog_file6,
4149
+ F: __dxlog_file4,
2792
4150
  L: 89,
2793
4151
  S: this,
2794
4152
  C: (f, a) => f(...a)
@@ -2804,8 +4162,8 @@ var SpaceAwarenessProvider = class {
2804
4162
  return Array.from(this._remoteStates.values());
2805
4163
  }
2806
4164
  update(position) {
2807
- invariant4(this._postTask, void 0, {
2808
- F: __dxlog_file6,
4165
+ invariant2(this._postTask, void 0, {
4166
+ F: __dxlog_file4,
2809
4167
  L: 104,
2810
4168
  S: this,
2811
4169
  A: [
@@ -2821,8 +4179,8 @@ var SpaceAwarenessProvider = class {
2821
4179
  this._postTask.schedule();
2822
4180
  }
2823
4181
  _handleQueryMessage() {
2824
- invariant4(this._postTask, void 0, {
2825
- F: __dxlog_file6,
4182
+ invariant2(this._postTask, void 0, {
4183
+ F: __dxlog_file4,
2826
4184
  L: 115,
2827
4185
  S: this,
2828
4186
  A: [
@@ -2833,8 +4191,8 @@ var SpaceAwarenessProvider = class {
2833
4191
  this._postTask.schedule();
2834
4192
  }
2835
4193
  _handlePostMessage(message) {
2836
- invariant4(message.kind === "post", void 0, {
2837
- F: __dxlog_file6,
4194
+ invariant2(message.kind === "post", void 0, {
4195
+ F: __dxlog_file4,
2838
4196
  L: 120,
2839
4197
  S: this,
2840
4198
  A: [
@@ -2854,10 +4212,58 @@ var modelState = StateField5.define({
2854
4212
  update: (model) => model
2855
4213
  });
2856
4214
 
2857
- // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
2858
- import { useState as useState2 } from "react";
2859
- var useTextEditor = () => {
2860
- const [view, setView] = useState2(null);
4215
+ // packages/ui/react-ui-editor/src/hooks/useActionHandler.ts
4216
+ var useActionHandler = (view) => {
4217
+ return (action) => {
4218
+ if (!view) {
4219
+ return;
4220
+ }
4221
+ let inlineType, listType;
4222
+ switch (action.type) {
4223
+ case "heading":
4224
+ setHeading(parseInt(action.data))(view);
4225
+ break;
4226
+ case "strong":
4227
+ case "emphasis":
4228
+ case "strikethrough":
4229
+ case "code":
4230
+ inlineType = action.type === "strong" ? Inline.Strong : action.type === "emphasis" ? Inline.Emphasis : action.type === "strikethrough" ? Inline.Strikethrough : Inline.Code;
4231
+ (typeof action.data === "boolean" ? setStyle(inlineType, action.data) : toggleStyle(inlineType))(view);
4232
+ break;
4233
+ case "list-ordered":
4234
+ case "list-bullet":
4235
+ case "list-tasks":
4236
+ listType = action.type === "list-ordered" ? List.Ordered : action.type === "list-bullet" ? List.Bullet : List.Task;
4237
+ (action.data === false ? removeList(listType) : action.data === true ? addList(listType) : toggleList(listType))(view);
4238
+ break;
4239
+ case "blockquote":
4240
+ (action.data === false ? removeBlockquote : action.data === true ? addBlockquote : toggleBlockquote)(view);
4241
+ break;
4242
+ case "codeblock":
4243
+ (action.data === false ? removeCodeblock : addCodeblock)(view);
4244
+ break;
4245
+ case "table":
4246
+ insertTable(view);
4247
+ break;
4248
+ case "link":
4249
+ (action.data === false ? removeLink : addLink)(view);
4250
+ break;
4251
+ case "comment":
4252
+ createComment(view);
4253
+ break;
4254
+ }
4255
+ setTimeout(() => {
4256
+ if (!view.hasFocus) {
4257
+ view.focus();
4258
+ }
4259
+ });
4260
+ };
4261
+ };
4262
+
4263
+ // packages/ui/react-ui-editor/src/hooks/useEditorView.ts
4264
+ import { useState as useState3 } from "react";
4265
+ var useEditorView = () => {
4266
+ const [view, setView] = useState3(null);
2861
4267
  return [
2862
4268
  (ref) => {
2863
4269
  setView(ref);
@@ -2866,29 +4272,144 @@ var useTextEditor = () => {
2866
4272
  ];
2867
4273
  };
2868
4274
 
4275
+ // packages/ui/react-ui-editor/src/hooks/useTextEditor.ts
4276
+ import { EditorSelection as EditorSelection2, EditorState as EditorState3 } from "@codemirror/state";
4277
+ import { EditorView as EditorView15 } from "@codemirror/view";
4278
+ import { useEffect as useEffect3, useRef as useRef2, useState as useState4 } from "react";
4279
+ import { log as log4 } from "@dxos/log";
4280
+ import { isNotFalsy as isNotFalsy4 } from "@dxos/util";
4281
+ var __dxlog_file5 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextEditor.ts";
4282
+ var useTextEditor = ({ autoFocus, scrollTo, debug, doc, selection, extensions } = {}) => {
4283
+ const onUpdate = useRef2();
4284
+ const [view, setView] = useState4();
4285
+ const parentRef = useRef2(null);
4286
+ useEffect3(() => {
4287
+ if (parentRef.current) {
4288
+ const state = EditorState3.create({
4289
+ doc,
4290
+ selection,
4291
+ extensions: [
4292
+ // TODO(burdon): Doesn't catch errors in keymap functions.
4293
+ EditorView15.exceptionSink.of((err) => {
4294
+ log4.catch(err, void 0, {
4295
+ F: __dxlog_file5,
4296
+ L: 57,
4297
+ S: void 0,
4298
+ C: (f, a) => f(...a)
4299
+ });
4300
+ }),
4301
+ extensions,
4302
+ EditorView15.updateListener.of(() => {
4303
+ onUpdate.current?.();
4304
+ })
4305
+ ].filter(isNotFalsy4)
4306
+ });
4307
+ const view2 = new EditorView15({
4308
+ parent: parentRef.current,
4309
+ scrollTo,
4310
+ state,
4311
+ // NOTE: Uncomment to debug/monitor all transactions.
4312
+ // https://codemirror.net/docs/ref/#view.EditorView.dispatch
4313
+ dispatchTransactions: (trs, view3) => {
4314
+ if (debug) {
4315
+ logChanges(trs);
4316
+ }
4317
+ view3.update(trs);
4318
+ }
4319
+ });
4320
+ setView(view2);
4321
+ }
4322
+ return () => {
4323
+ view?.destroy();
4324
+ };
4325
+ }, [
4326
+ parentRef
4327
+ ]);
4328
+ useEffect3(() => {
4329
+ if (view) {
4330
+ if (!selection && !view.state.selection.main.anchor) {
4331
+ selection = EditorSelection2.single(view.state.doc.line(1).to);
4332
+ }
4333
+ if (selection || scrollTo) {
4334
+ onUpdate.current = () => {
4335
+ onUpdate.current = void 0;
4336
+ view.dispatch({
4337
+ selection,
4338
+ effects: scrollTo && [
4339
+ scrollTo
4340
+ ],
4341
+ scrollIntoView: !scrollTo
4342
+ });
4343
+ };
4344
+ }
4345
+ if (autoFocus) {
4346
+ view.focus();
4347
+ }
4348
+ }
4349
+ }, [
4350
+ view,
4351
+ autoFocus,
4352
+ selection,
4353
+ scrollTo
4354
+ ]);
4355
+ return {
4356
+ parentRef,
4357
+ view
4358
+ };
4359
+ };
4360
+ var createDataExtensions = ({ readonly = false } = {}) => {
4361
+ return [
4362
+ //
4363
+ EditorState3.readOnly.of(readonly),
4364
+ EditorView15.editable.of(!readonly)
4365
+ ];
4366
+ };
4367
+ var createThemeExtensions = ({ theme, themeMode, slots } = {}) => {
4368
+ return [
4369
+ //
4370
+ EditorView15.baseTheme(defaultTheme),
4371
+ theme && EditorView15.theme(theme),
4372
+ EditorView15.darkTheme.of(themeMode === "dark"),
4373
+ EditorView15.editorAttributes.of({
4374
+ class: slots?.editor?.className ?? ""
4375
+ }),
4376
+ EditorView15.contentAttributes.of({
4377
+ class: slots?.content?.className ?? ""
4378
+ })
4379
+ ].filter(isNotFalsy4);
4380
+ };
4381
+
2869
4382
  // packages/ui/react-ui-editor/src/hooks/useTextModel.ts
2870
4383
  import get4 from "lodash.get";
2871
- import { useEffect as useEffect3, useState as useState3 } from "react";
4384
+ import { useEffect as useEffect4, useState as useState5 } from "react";
2872
4385
  import { generateName } from "@dxos/display-name";
2873
4386
  import { getRawDoc } from "@dxos/echo-schema";
2874
- import { invariant as invariant5 } from "@dxos/invariant";
4387
+ import { invariant as invariant3 } from "@dxos/invariant";
2875
4388
  import { isAutomergeObject } from "@dxos/react-client/echo";
2876
- import { isNotNullOrUndefined } from "@dxos/util";
2877
- var __dxlog_file7 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
4389
+ var __dxlog_file6 = "/home/runner/work/dxos/dxos/packages/ui/react-ui-editor/src/hooks/useTextModel.ts";
2878
4390
  var useTextModel = (props) => {
2879
4391
  const { identity, space, text } = props;
2880
- const [model, setModel] = useState3();
2881
- useEffect3(() => setModel(createModel(props)), [
4392
+ const [model, setModel] = useState5();
4393
+ useEffect4(() => setModel(createModel(props)), [
2882
4394
  identity,
2883
4395
  space,
2884
4396
  text
2885
4397
  ]);
2886
4398
  return model;
2887
4399
  };
4400
+ var useInMemoryTextModel = ({ id, defaultContent }) => {
4401
+ const [content, setContent] = useState5(defaultContent ?? "");
4402
+ return {
4403
+ id,
4404
+ content,
4405
+ setContent,
4406
+ text: () => content
4407
+ };
4408
+ };
2888
4409
  var createModel = ({ space, identity, text }) => {
2889
- invariant5(isAutomergeObject(text), void 0, {
2890
- F: __dxlog_file7,
2891
- L: 35,
4410
+ invariant3(isAutomergeObject(text), void 0, {
4411
+ F: __dxlog_file6,
4412
+ L: 50,
2892
4413
  S: void 0,
2893
4414
  A: [
2894
4415
  "isAutomergeObject(text)",
@@ -2899,7 +4420,7 @@ var createModel = ({ space, identity, text }) => {
2899
4420
  const doc = getRawDoc(obj, [
2900
4421
  obj.field
2901
4422
  ]);
2902
- const awarenessProvider = space && new SpaceAwarenessProvider({
4423
+ const awarenessProvider2 = space && new SpaceAwarenessProvider({
2903
4424
  space,
2904
4425
  channel: `automerge.awareness.${obj.id}`,
2905
4426
  info: {
@@ -2909,19 +4430,22 @@ var createModel = ({ space, identity, text }) => {
2909
4430
  },
2910
4431
  peerId: identity?.identityKey.toHex() ?? "Anonymous"
2911
4432
  });
4433
+ const extensions = [
4434
+ //
4435
+ modelState.init(() => model),
4436
+ automerge({
4437
+ handle: doc.handle,
4438
+ path: doc.path
4439
+ })
4440
+ ];
4441
+ if (awarenessProvider2) {
4442
+ extensions.push(awareness(awarenessProvider2));
4443
+ }
2912
4444
  const model = {
2913
4445
  id: obj.id,
2914
4446
  content: doc,
2915
4447
  text: () => get4(doc.handle.docSync(), doc.path),
2916
- extension: [
2917
- modelState.init(() => model),
2918
- automerge3({
2919
- handle: doc.handle,
2920
- path: doc.path
2921
- }),
2922
- awarenessProvider && AwarenessProvider.of(awarenessProvider),
2923
- awareness()
2924
- ].filter(isNotNullOrUndefined),
4448
+ extension: extensions,
2925
4449
  peer: identity ? {
2926
4450
  id: identity.identityKey.toHex(),
2927
4451
  name: identity.profile?.displayName
@@ -2930,40 +4454,57 @@ var createModel = ({ space, identity, text }) => {
2930
4454
  return model;
2931
4455
  };
2932
4456
  export {
2933
- AwarenessProvider,
2934
4457
  BaseTextEditor,
2935
4458
  Cursor,
2936
4459
  Doc,
2937
4460
  EditorModes,
4461
+ Inline,
4462
+ List,
2938
4463
  MarkdownEditor,
2939
4464
  RemoteSelectionsDecorator,
2940
4465
  SpaceAwarenessProvider,
2941
4466
  TextEditor,
2942
4467
  TextKind,
4468
+ Toolbar,
2943
4469
  YText,
2944
4470
  YXmlFragment,
4471
+ addBlockquote,
4472
+ addCodeblock,
4473
+ addLink,
4474
+ addList,
4475
+ addStyle,
2945
4476
  autocomplete,
2946
- automerge3 as automerge,
4477
+ automerge,
2947
4478
  awareness,
2948
- basicBundle,
4479
+ awarenessProvider,
2949
4480
  blast,
2950
4481
  callbackWrapper,
2951
4482
  code2 as code,
2952
4483
  codeTheme,
2953
4484
  comments,
4485
+ compareFormatting,
4486
+ createBasicBundle,
4487
+ createComment,
4488
+ createDataExtensions,
4489
+ createMarkdownExtensions,
4490
+ createThemeExtensions,
2954
4491
  defaultMarkdownSlots,
2955
4492
  defaultOptions,
2956
4493
  defaultSlots,
2957
4494
  defaultTextSlots,
2958
4495
  defaultTheme,
4496
+ focusComment,
4497
+ formatting,
4498
+ getFormatting,
2959
4499
  getToken,
2960
4500
  heading2 as heading,
2961
4501
  hr,
2962
4502
  image,
4503
+ insertTable,
4504
+ keymap7 as keymap,
2963
4505
  link,
2964
4506
  listener,
2965
4507
  logChanges,
2966
- markdownBundle,
2967
4508
  markdownHighlightStyle,
2968
4509
  markdownTags,
2969
4510
  markdownTagsExtensions,
@@ -2971,16 +4512,36 @@ export {
2971
4512
  mention,
2972
4513
  modelState,
2973
4514
  outliner,
4515
+ removeBlockquote,
4516
+ removeCodeblock,
4517
+ removeLink,
4518
+ removeList,
4519
+ removeStyle,
4520
+ setBlockquote,
2974
4521
  setComments,
2975
- setFocus,
4522
+ setHeading,
2976
4523
  setSelection,
4524
+ setStyle,
2977
4525
  table,
2978
4526
  tags2 as tags,
2979
4527
  tasklist,
2980
4528
  textTheme,
4529
+ toggleBlockquote,
4530
+ toggleCodeblock,
4531
+ toggleEmphasis,
4532
+ toggleInlineCode,
4533
+ toggleList,
4534
+ toggleStrikethrough,
4535
+ toggleStrong,
4536
+ toggleStyle,
2981
4537
  typewriter,
4538
+ useActionHandler,
2982
4539
  useComments,
4540
+ useEditorView,
4541
+ useFormattingState,
4542
+ useInMemoryTextModel,
2983
4543
  useTextEditor,
2984
- useTextModel
4544
+ useTextModel,
4545
+ useToolbarContext
2985
4546
  };
2986
4547
  //# sourceMappingURL=index.mjs.map