@dxos/ui-editor 0.8.4-main.c85a9c8dae → 0.8.4-main.cb12b3f963

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 (151) hide show
  1. package/dist/lib/browser/index.mjs +1530 -752
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/browser/types/index.mjs +26 -6
  5. package/dist/lib/browser/types/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/index.mjs +1531 -752
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/types/index.mjs +27 -6
  10. package/dist/lib/node-esm/types/index.mjs.map +4 -4
  11. package/dist/types/src/defaults.d.ts +4 -10
  12. package/dist/types/src/defaults.d.ts.map +1 -1
  13. package/dist/types/src/extensions/annotations.d.ts.map +1 -1
  14. package/dist/types/src/extensions/auto-scroll.d.ts +14 -2
  15. package/dist/types/src/extensions/auto-scroll.d.ts.map +1 -1
  16. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -1
  17. package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -1
  18. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -1
  19. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  21. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  22. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  23. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  24. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  25. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -1
  26. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -1
  27. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  28. package/dist/types/src/extensions/blast.d.ts.map +1 -1
  29. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  30. package/dist/types/src/extensions/debug.d.ts.map +1 -1
  31. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  32. package/dist/types/src/extensions/factories.d.ts +4 -3
  33. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  34. package/dist/types/src/extensions/factories.test.d.ts +2 -0
  35. package/dist/types/src/extensions/factories.test.d.ts.map +1 -0
  36. package/dist/types/src/extensions/focus.d.ts +1 -1
  37. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  38. package/dist/types/src/extensions/index.d.ts +2 -1
  39. package/dist/types/src/extensions/index.d.ts.map +1 -1
  40. package/dist/types/src/extensions/json.d.ts.map +1 -1
  41. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  42. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/bundle.d.ts +3 -0
  44. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  45. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  46. package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -1
  47. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  48. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  49. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  50. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  51. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  52. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  53. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
  54. package/dist/types/src/extensions/mention.d.ts.map +1 -1
  55. package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -1
  56. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  57. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -1
  58. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -1
  59. package/dist/types/src/extensions/preview/preview.d.ts +2 -0
  60. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  61. package/dist/types/src/extensions/replacer.d.ts.map +1 -1
  62. package/dist/types/src/extensions/scroll-past-end.d.ts +3 -0
  63. package/dist/types/src/extensions/scroll-past-end.d.ts.map +1 -0
  64. package/dist/types/src/extensions/scroller.d.ts +12 -10
  65. package/dist/types/src/extensions/scroller.d.ts.map +1 -1
  66. package/dist/types/src/extensions/selection.d.ts.map +1 -1
  67. package/dist/types/src/extensions/snippets.d.ts +10 -0
  68. package/dist/types/src/extensions/snippets.d.ts.map +1 -0
  69. package/dist/types/src/extensions/submit.d.ts.map +1 -1
  70. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -1
  71. package/dist/types/src/extensions/tags/fader.d.ts +12 -0
  72. package/dist/types/src/extensions/tags/fader.d.ts.map +1 -0
  73. package/dist/types/src/extensions/tags/index.d.ts +4 -1
  74. package/dist/types/src/extensions/tags/index.d.ts.map +1 -1
  75. package/dist/types/src/extensions/tags/typewriter.d.ts +43 -0
  76. package/dist/types/src/extensions/tags/typewriter.d.ts.map +1 -0
  77. package/dist/types/src/extensions/tags/typewriter.test.d.ts +2 -0
  78. package/dist/types/src/extensions/tags/typewriter.test.d.ts.map +1 -0
  79. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +31 -0
  80. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +1 -0
  81. package/dist/types/src/extensions/tags/xml-formatting.d.ts +24 -0
  82. package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +1 -0
  83. package/dist/types/src/extensions/tags/xml-tags.d.ts +28 -8
  84. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
  85. package/dist/types/src/extensions/tags/xml-util.d.ts.map +1 -1
  86. package/dist/types/src/index.d.ts +0 -1
  87. package/dist/types/src/index.d.ts.map +1 -1
  88. package/dist/types/src/styles/theme.d.ts +2 -2
  89. package/dist/types/src/styles/theme.d.ts.map +1 -1
  90. package/dist/types/src/types/types.d.ts +4 -4
  91. package/dist/types/src/types/types.d.ts.map +1 -1
  92. package/dist/types/src/util/cursor.d.ts.map +1 -1
  93. package/dist/types/src/util/debug.d.ts.map +1 -1
  94. package/dist/types/src/util/decorations.d.ts.map +1 -1
  95. package/dist/types/src/util/dom.d.ts.map +1 -1
  96. package/dist/types/src/util/facet.d.ts.map +1 -1
  97. package/dist/types/src/util/util.d.ts.map +1 -1
  98. package/dist/types/tsconfig.tsbuildinfo +1 -1
  99. package/package.json +33 -36
  100. package/src/defaults.ts +33 -20
  101. package/src/extensions/auto-scroll.ts +115 -9
  102. package/src/extensions/automerge/automerge.test.tsx +35 -9
  103. package/src/extensions/automerge/automerge.ts +5 -7
  104. package/src/extensions/comments.ts +0 -1
  105. package/src/extensions/factories.test.ts +88 -0
  106. package/src/extensions/factories.ts +26 -8
  107. package/src/extensions/folding.ts +3 -20
  108. package/src/extensions/index.ts +2 -1
  109. package/src/extensions/markdown/action.ts +0 -1
  110. package/src/extensions/markdown/bundle.ts +23 -9
  111. package/src/extensions/markdown/decorate.ts +11 -9
  112. package/src/extensions/markdown/highlight.ts +4 -10
  113. package/src/extensions/markdown/parser.test.ts +0 -1
  114. package/src/extensions/markdown/styles.ts +37 -4
  115. package/src/extensions/markdown/table.ts +24 -2
  116. package/src/extensions/outliner/outliner.test.ts +0 -1
  117. package/src/extensions/outliner/outliner.ts +0 -1
  118. package/src/extensions/outliner/tree.test.ts +0 -1
  119. package/src/extensions/preview/preview.ts +54 -7
  120. package/src/extensions/scroll-past-end.ts +32 -0
  121. package/src/extensions/scroller.ts +48 -24
  122. package/src/extensions/selection.ts +1 -1
  123. package/src/extensions/snippets.ts +67 -0
  124. package/src/extensions/tags/extended-markdown.test.ts +120 -2
  125. package/src/extensions/tags/extended-markdown.ts +80 -1
  126. package/src/extensions/tags/fader.ts +195 -0
  127. package/src/extensions/tags/index.ts +4 -1
  128. package/src/extensions/tags/testing/text.md +36 -0
  129. package/src/extensions/tags/testing/text.txt +35 -0
  130. package/src/extensions/tags/typewriter.test.ts +65 -0
  131. package/src/extensions/tags/typewriter.ts +594 -0
  132. package/src/extensions/tags/xml-block-decoration.ts +123 -0
  133. package/src/extensions/tags/xml-formatting.ts +125 -0
  134. package/src/extensions/tags/xml-tags.ts +179 -31
  135. package/src/extensions/tags/xml-util.test.ts +199 -24
  136. package/src/extensions/tags/xml-util.ts +62 -5
  137. package/src/index.ts +0 -1
  138. package/src/styles/theme.ts +39 -25
  139. package/src/types/types.ts +10 -2
  140. package/src/typings.d.ts +8 -0
  141. package/src/util/cursor.ts +0 -1
  142. package/dist/lib/browser/chunk-HL3YF6WC.mjs +0 -22
  143. package/dist/lib/browser/chunk-HL3YF6WC.mjs.map +0 -7
  144. package/dist/lib/node-esm/chunk-YJZGD3LY.mjs +0 -24
  145. package/dist/lib/node-esm/chunk-YJZGD3LY.mjs.map +0 -7
  146. package/dist/types/src/extensions/tags/streamer.d.ts +0 -12
  147. package/dist/types/src/extensions/tags/streamer.d.ts.map +0 -1
  148. package/dist/types/src/extensions/typewriter.d.ts +0 -10
  149. package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
  150. package/src/extensions/tags/streamer.ts +0 -243
  151. package/src/extensions/typewriter.ts +0 -68
@@ -1,29 +1,42 @@
1
- import {
2
- EditorInputMode,
3
- EditorInputModes,
4
- EditorViewMode,
5
- EditorViewModes
6
- } from "./chunk-HL3YF6WC.mjs";
7
-
8
1
  // src/index.ts
9
- import { EditorState as EditorState3 } from "@codemirror/state";
10
- import { EditorView as EditorView30, keymap as keymap15 } from "@codemirror/view";
2
+ import { EditorState as EditorState4 } from "@codemirror/state";
3
+ import { EditorView as EditorView33, keymap as keymap15 } from "@codemirror/view";
11
4
  import { tags as tags2 } from "@lezer/highlight";
12
5
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
13
6
 
14
7
  // src/defaults.ts
15
8
  import { mx } from "@dxos/ui-theme";
16
- var editorWidth = "!mx-auto w-full max-w-[min(50rem,100%-4rem)]";
17
- var editorSlots = {
18
- scroll: {
19
- className: "pt-2"
20
- },
9
+ var editorClassNames = (role) => mx("dx-attention-surface p-0.5 data-[toolbar=disabled]:pt-2 dx-focus-ring-inset", role === "section" ? "[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-h-24" : "dx-container overflow-hidden");
10
+ var documentSlots = {
11
+ content: {
12
+ /**
13
+ * CodeMirror content width.
14
+ * 40rem = 640px. Corresponds to initial plank width (Google docs, Stashpad, etc.)
15
+ * 50rem = 800px. Maximum content width for solo mode.
16
+ * NOTE: Max width - 4rem = 2rem left/right margin (or 2rem gutter plus 1rem left/right margin).
17
+ */
18
+ className: mx(
19
+ // Inline-size container for widget sizing (children use `max-w-[100cqi]`).
20
+ // NOTE: Use inline-size, not full size containment — `container-type: size` on the
21
+ // editor content breaks CodeMirror's viewport measurement, leaving blank gaps during
22
+ // scroll until a click forces a re-measure.
23
+ "dx-inline-size-container",
24
+ // Wider margin for web (vs. mobile).
25
+ "pointer-fine:max-w-[min(50rem,100%-4rem)] pointer-coarse:max-w-[min(50rem,100%-2rem)]",
26
+ "mx-auto! w-full"
27
+ )
28
+ }
29
+ };
30
+ var compactSlots = {
31
+ content: {
32
+ className: "mx-2!"
33
+ }
34
+ };
35
+ var mobileSlots = {
21
36
  content: {
22
- className: editorWidth
37
+ className: "mx-2!"
23
38
  }
24
39
  };
25
- var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
26
- var stackItemContentEditorClassNames = (role) => mx("dx-attention-surface p-0.5 dx-focus-ring-inset data-[toolbar=disabled]:pt-2", role === "section" ? "[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-h-24" : "dx-container overflow-hidden");
27
40
 
28
41
  // src/extensions/annotations.ts
29
42
  import { RangeSetBuilder } from "@codemirror/state";
@@ -207,7 +220,7 @@ var singleValueFacet = (defaultValue) => Facet.define({
207
220
  var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
208
221
  var defaultCursorConverter = {
209
222
  toCursor: (position) => position.toString(),
210
- fromCursor: (cursor2) => parseInt(cursor2)
223
+ fromCursor: (cursor) => parseInt(cursor)
211
224
  };
212
225
  var Cursor = class _Cursor {
213
226
  static converter = singleValueFacet(defaultCursorConverter);
@@ -220,9 +233,9 @@ var Cursor = class _Cursor {
220
233
  to
221
234
  ].join(":");
222
235
  };
223
- static getRangeFromCursor = (state, cursor2) => {
236
+ static getRangeFromCursor = (state, cursor) => {
224
237
  const cursorConverter2 = state.facet(_Cursor.converter);
225
- const parts = cursor2.split(":");
238
+ const parts = cursor.split(":");
226
239
  const from = cursorConverter2.fromCursor(parts[0]);
227
240
  const to = cursorConverter2.fromCursor(parts[1]);
228
241
  return from !== void 0 && to !== void 0 ? {
@@ -258,12 +271,7 @@ var wrapWithCatch = (fn, label) => {
258
271
  } catch (err) {
259
272
  log.catch(err, {
260
273
  label
261
- }, {
262
- F: __dxlog_file,
263
- L: 20,
264
- S: void 0,
265
- C: (f, a) => f(...a)
266
- });
274
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 13, S: void 0 });
267
275
  }
268
276
  };
269
277
  };
@@ -289,12 +297,7 @@ var logChanges = (trs) => {
289
297
  if (changes.length) {
290
298
  log("changes", {
291
299
  changes
292
- }, {
293
- F: __dxlog_file,
294
- L: 54,
295
- S: void 0,
296
- C: (f, a) => f(...a)
297
- });
300
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 44, S: void 0 });
298
301
  }
299
302
  };
300
303
 
@@ -502,9 +505,11 @@ var typeahead = ({ onComplete } = {}) => {
502
505
  };
503
506
 
504
507
  // src/extensions/auto-scroll.ts
508
+ import { StateEffect as StateEffect2 } from "@codemirror/state";
505
509
  import { EditorView as EditorView5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
506
510
  import { addEventListener, combine, throttle } from "@dxos/async";
507
511
  import { Domino } from "@dxos/ui";
512
+ import { getSize } from "@dxos/ui-theme";
508
513
 
509
514
  // src/extensions/scroller.ts
510
515
  import { StateEffect } from "@codemirror/state";
@@ -561,8 +566,7 @@ var scroller = ({ overScroll = 0 } = {}) => {
561
566
  }
562
567
  requestAnimationFrame(() => {
563
568
  this.view.scrollDOM.scrollTo({
564
- top: targetScrollTop,
565
- behavior
569
+ top: targetScrollTop
566
570
  });
567
571
  });
568
572
  }
@@ -584,23 +588,19 @@ var scroller = ({ overScroll = 0 } = {}) => {
584
588
  }
585
589
  }
586
590
  } catch (err) {
587
- log2.catch(err, void 0, {
588
- F: __dxlog_file2,
589
- L: 145,
590
- S: void 0,
591
- C: (f, a) => f(...a)
592
- });
591
+ log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 91, S: void 0 });
593
592
  }
594
593
  });
595
594
  }),
596
595
  // Styles.
597
596
  EditorView4.theme({
598
- ".cm-content": {
599
- paddingBottom: `${overScroll}px`
600
- },
601
597
  ".cm-scroller": {
602
- overflowAnchor: "none",
603
- paddingBottom: "0"
598
+ overflowY: "scroll",
599
+ // Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks
600
+ // expanding their TogglePanel), the browser picks a stable element near the viewport
601
+ // top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning
602
+ // logic still has the final word when pinned (forces scrollTop to scrollHeight).
603
+ overflowAnchor: "auto"
604
604
  },
605
605
  ".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
606
606
  display: "none"
@@ -612,6 +612,16 @@ var scroller = ({ overScroll = 0 } = {}) => {
612
612
  "&:hover .cm-scroller::-webkit-scrollbar-thumb": {
613
613
  background: "var(--color-scrollbar-thumb)"
614
614
  },
615
+ // Spacer below the last text line. Implemented as a real block pseudo-element
616
+ // (rather than `padding-bottom` on `.cm-content`) so it materializes in the
617
+ // scroller's `scrollHeight` regardless of how `padding` is reset by the base
618
+ // theme or downstream classes — this is what gives auto-scroll its head-room
619
+ // so the last line stays `overScroll` px above the viewport bottom.
620
+ ".cm-content::after": {
621
+ content: '""',
622
+ display: "block",
623
+ height: `${overScroll}px`
624
+ },
615
625
  ".cm-scroll-button": {
616
626
  position: "absolute",
617
627
  bottom: "0.5rem",
@@ -620,22 +630,28 @@ var scroller = ({ overScroll = 0 } = {}) => {
620
630
  })
621
631
  ];
622
632
  };
623
- function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
633
+ function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
624
634
  const el = view.scrollDOM;
625
635
  let currentTop = 0;
636
+ let velocity = 0;
626
637
  let rafId = null;
627
- function frame() {
638
+ let lastTime = 0;
639
+ function frame(now) {
640
+ const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1e3);
641
+ lastTime = now;
628
642
  const targetTop = el.scrollHeight - el.clientHeight;
629
643
  const delta = targetTop - currentTop;
630
- const absDelta = Math.abs(delta);
631
- if (absDelta < targetDelta) {
644
+ if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
632
645
  el.scrollTop = targetTop;
633
646
  currentTop = targetTop;
647
+ velocity = 0;
634
648
  rafId = null;
649
+ lastTime = 0;
635
650
  return;
636
651
  }
637
- const step = Math.sign(delta) * Math.min(absDelta, Math.max(1, Math.min(absDelta * k, maxStep)));
638
- currentTop += step;
652
+ const accel = omega * omega * delta - 2 * omega * velocity;
653
+ velocity += accel * dt;
654
+ currentTop += velocity * dt;
639
655
  el.scrollTop = currentTop;
640
656
  rafId = requestAnimationFrame(frame);
641
657
  }
@@ -643,12 +659,15 @@ function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
643
659
  scroll: () => {
644
660
  if (rafId === null) {
645
661
  currentTop = el.scrollTop;
662
+ lastTime = 0;
646
663
  rafId = requestAnimationFrame(frame);
647
664
  }
648
665
  },
649
666
  cancel: () => {
650
667
  if (rafId !== null) {
651
668
  cancelAnimationFrame(rafId);
669
+ velocity = 0;
670
+ lastTime = 0;
652
671
  rafId = null;
653
672
  }
654
673
  }
@@ -656,26 +675,64 @@ function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
656
675
  }
657
676
 
658
677
  // src/extensions/auto-scroll.ts
659
- var autoScroll = (_ = {}) => {
678
+ var autoScrollEffect = StateEffect2.define();
679
+ var autoScroll = ({ scrollOnResize = true } = {}) => {
660
680
  let buttonContainer;
661
681
  let isPinned = true;
682
+ let jumpPending = false;
683
+ let enabled = true;
684
+ let firstUpdate = true;
662
685
  const setPinned = (pinned) => {
663
686
  buttonContainer?.classList.toggle("opacity-0", pinned);
664
687
  isPinned = pinned;
665
688
  };
666
689
  return [
667
- // Update listener for logging when scrolling is needed.
668
- EditorView5.updateListener.of(({ view, heightChanged, state }) => {
690
+ // Update listener for scrolling when content changes.
691
+ EditorView5.updateListener.of((update2) => {
692
+ const { view, heightChanged, state, startState } = update2;
693
+ for (const tr of update2.transactions) {
694
+ for (const effect of tr.effects) {
695
+ if (effect.is(autoScrollEffect)) {
696
+ enabled = effect.value;
697
+ if (enabled) {
698
+ setPinned(true);
699
+ view.dispatch({
700
+ effects: scrollerCrawlEffect.of(true)
701
+ });
702
+ } else {
703
+ view.dispatch({
704
+ effects: scrollerCrawlEffect.of(false)
705
+ });
706
+ }
707
+ }
708
+ }
709
+ }
710
+ if (!enabled) {
711
+ return;
712
+ }
713
+ if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
714
+ firstUpdate = false;
715
+ jumpPending = true;
716
+ requestAnimationFrame(() => {
717
+ view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
718
+ jumpPending = false;
719
+ });
720
+ return;
721
+ }
722
+ firstUpdate = false;
723
+ if (jumpPending) {
724
+ return;
725
+ }
669
726
  if (heightChanged) {
670
727
  if (isPinned) {
671
728
  const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
672
729
  const delta = scrollHeight - scrollTop - clientHeight;
673
- if (delta > 0 && scrollTop > 0) {
730
+ if (delta > 0) {
674
731
  setPinned(true);
675
732
  view.dispatch({
676
733
  effects: scrollerCrawlEffect.of(true)
677
734
  });
678
- } else if (delta < 0) {
735
+ } else if (delta < -1) {
679
736
  setPinned(false);
680
737
  }
681
738
  } else {
@@ -685,6 +742,43 @@ var autoScroll = (_ = {}) => {
685
742
  }
686
743
  }
687
744
  }),
745
+ // Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
746
+ // window resize). Doc-driven height changes are handled by the updateListener above; this
747
+ // observer covers the case where the viewport changes while the doc length is unchanged.
748
+ scrollOnResize ? ViewPlugin6.fromClass(class {
749
+ observer;
750
+ firstObservation = true;
751
+ destroyed = false;
752
+ constructor(view) {
753
+ const onResize = throttle(() => {
754
+ if (this.destroyed || !enabled) {
755
+ return;
756
+ }
757
+ setPinned(true);
758
+ requestAnimationFrame(() => {
759
+ if (this.destroyed) {
760
+ return;
761
+ }
762
+ view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
763
+ view.dispatch({
764
+ effects: scrollerCrawlEffect.of(true)
765
+ });
766
+ });
767
+ }, 100);
768
+ this.observer = new ResizeObserver(() => {
769
+ if (this.firstObservation) {
770
+ this.firstObservation = false;
771
+ return;
772
+ }
773
+ onResize();
774
+ });
775
+ this.observer.observe(view.scrollDOM);
776
+ }
777
+ destroy() {
778
+ this.destroyed = true;
779
+ this.observer.disconnect();
780
+ }
781
+ }) : [],
688
782
  // Detect user scroll and unpin (or re-pin if scrolled to the bottom).
689
783
  ViewPlugin6.fromClass(class {
690
784
  cleanup;
@@ -710,12 +804,12 @@ var autoScroll = (_ = {}) => {
710
804
  // Scroll button.
711
805
  ViewPlugin6.fromClass(class {
712
806
  constructor(view) {
713
- const icon = Domino.of("dx-icon").attributes({
807
+ const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
714
808
  icon: "ph--arrow-down--regular"
715
809
  });
716
810
  const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
717
811
  "data-density": "fine"
718
- }).children(icon).on("click", () => {
812
+ }).append(icon).on("click", () => {
719
813
  setPinned(true);
720
814
  view.dispatch({
721
815
  effects: scrollerLineEffect.of({
@@ -725,7 +819,7 @@ var autoScroll = (_ = {}) => {
725
819
  })
726
820
  });
727
821
  });
728
- buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").children(button).root;
822
+ buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
729
823
  view.scrollDOM.parentElement.appendChild(buttonContainer);
730
824
  }
731
825
  })
@@ -760,35 +854,25 @@ var cursorConverter = (accessor) => ({
760
854
  try {
761
855
  return toCursor(accessor, pos, assoc);
762
856
  } catch (err) {
763
- log3.catch(err, void 0, {
764
- F: __dxlog_file3,
765
- L: 15,
766
- S: void 0,
767
- C: (f, a) => f(...a)
768
- });
857
+ log3.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 11, S: void 0 });
769
858
  return "";
770
859
  }
771
860
  },
772
- fromCursor: (cursor2) => {
861
+ fromCursor: (cursor) => {
773
862
  try {
774
- return fromCursor(accessor, cursor2);
863
+ return fromCursor(accessor, cursor);
775
864
  } catch (err) {
776
- log3.catch(err, void 0, {
777
- F: __dxlog_file3,
778
- L: 24,
779
- S: void 0,
780
- C: (f, a) => f(...a)
781
- });
865
+ log3.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 19, S: void 0 });
782
866
  return 0;
783
867
  }
784
868
  }
785
869
  });
786
870
 
787
871
  // src/extensions/automerge/defs.ts
788
- import { Annotation, StateEffect as StateEffect2 } from "@codemirror/state";
872
+ import { Annotation, StateEffect as StateEffect3 } from "@codemirror/state";
789
873
  var getPath = (state, field) => state.field(field).path;
790
874
  var getLastHeads = (state, field) => state.field(field).lastHeads;
791
- var updateHeadsEffect = StateEffect2.define({});
875
+ var updateHeadsEffect = StateEffect3.define({});
792
876
  var updateHeads = (newHeads) => updateHeadsEffect.of({
793
877
  newHeads
794
878
  });
@@ -963,12 +1047,7 @@ var Syncer = class {
963
1047
  this._pending = false;
964
1048
  }
965
1049
  onEditorChange(view) {
966
- log4("onEditorChange", void 0, {
967
- F: __dxlog_file4,
968
- L: 45,
969
- S: this,
970
- C: (f, a) => f(...a)
971
- });
1050
+ log4("onEditorChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 35, S: this });
972
1051
  const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
973
1052
  const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
974
1053
  if (newHeads) {
@@ -979,12 +1058,7 @@ var Syncer = class {
979
1058
  }
980
1059
  }
981
1060
  onAutomergeChange(view) {
982
- log4("onAutomergeChange", void 0, {
983
- F: __dxlog_file4,
984
- L: 60,
985
- S: this,
986
- C: (f, a) => f(...a)
987
- });
1061
+ log4("onAutomergeChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 47, S: this });
988
1062
  const oldHeads = getLastHeads(view.state, this._state);
989
1063
  const newHeads = A2.getHeads(this._handle.doc());
990
1064
  const diff = A2.equals(oldHeads, newHeads) ? [] : A2.diff(this._handle.doc(), oldHeads, newHeads);
@@ -1046,6 +1120,17 @@ var automerge = (accessor) => {
1046
1120
  const value = DocAccessor.getValue(accessor);
1047
1121
  const current = this._view.state.doc.toString();
1048
1122
  if (value !== current) {
1123
+ this._view.dispatch({
1124
+ changes: {
1125
+ from: 0,
1126
+ to: this._view.state.doc.length,
1127
+ insert: value
1128
+ },
1129
+ annotations: [
1130
+ initialSync,
1131
+ reconcileAnnotation.of(true)
1132
+ ]
1133
+ });
1049
1134
  }
1050
1135
  });
1051
1136
  }
@@ -1096,10 +1181,7 @@ var awareness = (provider = dummyProvider) => {
1096
1181
  ];
1097
1182
  };
1098
1183
  var RemoteSelectionsDecorator = class {
1099
- _ctx = new Context(void 0, {
1100
- F: __dxlog_file5,
1101
- L: 80
1102
- });
1184
+ _ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 33 });
1103
1185
  _cursorConverter;
1104
1186
  _provider;
1105
1187
  _lastAnchor;
@@ -1330,10 +1412,7 @@ var SpaceAwarenessProvider = class {
1330
1412
  this._info = info;
1331
1413
  }
1332
1414
  open() {
1333
- this._ctx = new Context2(void 0, {
1334
- F: __dxlog_file6,
1335
- L: 57
1336
- });
1415
+ this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 28 });
1337
1416
  this._postTask = new DeferredTask(this._ctx, async () => {
1338
1417
  if (this._localState) {
1339
1418
  await this._messenger.postMessage(this._channel, {
@@ -1360,12 +1439,7 @@ var SpaceAwarenessProvider = class {
1360
1439
  }).catch((err) => {
1361
1440
  log5.debug("failed to query awareness", {
1362
1441
  err
1363
- }, {
1364
- F: __dxlog_file6,
1365
- L: 91,
1366
- S: this,
1367
- C: (f, a) => f(...a)
1368
- });
1442
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 57, S: this });
1369
1443
  });
1370
1444
  }
1371
1445
  close() {
@@ -1377,15 +1451,7 @@ var SpaceAwarenessProvider = class {
1377
1451
  return Array.from(this._remoteStates.values());
1378
1452
  }
1379
1453
  update(position) {
1380
- invariant(this._postTask, void 0, {
1381
- F: __dxlog_file6,
1382
- L: 106,
1383
- S: this,
1384
- A: [
1385
- "this._postTask",
1386
- ""
1387
- ]
1388
- });
1454
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 71, S: this, A: ["this._postTask", ""] });
1389
1455
  this._localState = {
1390
1456
  peerId: this._peerId,
1391
1457
  position,
@@ -1394,27 +1460,11 @@ var SpaceAwarenessProvider = class {
1394
1460
  this._postTask.schedule();
1395
1461
  }
1396
1462
  _handleQueryMessage() {
1397
- invariant(this._postTask, void 0, {
1398
- F: __dxlog_file6,
1399
- L: 117,
1400
- S: this,
1401
- A: [
1402
- "this._postTask",
1403
- ""
1404
- ]
1405
- });
1463
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 80, S: this, A: ["this._postTask", ""] });
1406
1464
  this._postTask.schedule();
1407
1465
  }
1408
1466
  _handlePostMessage(message) {
1409
- invariant(message.kind === "post", void 0, {
1410
- F: __dxlog_file6,
1411
- L: 122,
1412
- S: this,
1413
- A: [
1414
- "message.kind === 'post'",
1415
- ""
1416
- ]
1417
- });
1467
+ invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 84, S: this, A: ["message.kind === 'post'", ""] });
1418
1468
  this._remoteStates.set(message.state.peerId, message.state);
1419
1469
  this.remoteStateChange.emit();
1420
1470
  }
@@ -1543,15 +1593,7 @@ var Blaster = class {
1543
1593
  return this._node;
1544
1594
  }
1545
1595
  initialize() {
1546
- invariant2(!this._canvas && !this._ctx, void 0, {
1547
- F: __dxlog_file7,
1548
- L: 142,
1549
- S: this,
1550
- A: [
1551
- "!this._canvas && !this._ctx",
1552
- ""
1553
- ]
1554
- });
1596
+ invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
1555
1597
  this._canvas = document.createElement("canvas");
1556
1598
  this._canvas.id = "code-blast-canvas";
1557
1599
  this._canvas.style.position = "absolute";
@@ -1580,15 +1622,7 @@ var Blaster = class {
1580
1622
  }
1581
1623
  }
1582
1624
  start() {
1583
- invariant2(this._canvas && this._ctx, void 0, {
1584
- F: __dxlog_file7,
1585
- L: 181,
1586
- S: this,
1587
- A: [
1588
- "this._canvas && this._ctx",
1589
- ""
1590
- ]
1591
- });
1625
+ invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
1592
1626
  this._running = true;
1593
1627
  this.loop();
1594
1628
  }
@@ -1823,13 +1857,13 @@ var blocks = () => [
1823
1857
  ];
1824
1858
 
1825
1859
  // src/extensions/bookmarks.ts
1826
- import { Prec as Prec3, StateEffect as StateEffect3, StateField as StateField2 } from "@codemirror/state";
1860
+ import { Prec as Prec3, StateEffect as StateEffect4, StateField as StateField2 } from "@codemirror/state";
1827
1861
  import { keymap as keymap4 } from "@codemirror/view";
1828
1862
  import { log as log6 } from "@dxos/log";
1829
1863
  var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
1830
- var addBookmark = StateEffect3.define();
1831
- var removeBookmark = StateEffect3.define();
1832
- var clearBookmarks = StateEffect3.define();
1864
+ var addBookmark = StateEffect4.define();
1865
+ var removeBookmark = StateEffect4.define();
1866
+ var clearBookmarks = StateEffect4.define();
1833
1867
  var bookmarks = () => {
1834
1868
  return [
1835
1869
  bookmarksField,
@@ -1838,12 +1872,7 @@ var bookmarks = () => {
1838
1872
  key: "Mod-ArrowUp",
1839
1873
  run: (view) => {
1840
1874
  const bookmarks2 = view.state.field(bookmarksField);
1841
- log6("up", bookmarks2, {
1842
- F: __dxlog_file8,
1843
- L: 29,
1844
- S: void 0,
1845
- C: (f, a) => f(...a)
1846
- });
1875
+ log6("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 18, S: void 0 });
1847
1876
  return true;
1848
1877
  }
1849
1878
  },
@@ -1851,12 +1880,7 @@ var bookmarks = () => {
1851
1880
  key: "Mod-ArrowDown",
1852
1881
  run: (view) => {
1853
1882
  const bookmarks2 = view.state.field(bookmarksField);
1854
- log6("down", bookmarks2, {
1855
- F: __dxlog_file8,
1856
- L: 37,
1857
- S: void 0,
1858
- C: (f, a) => f(...a)
1859
- });
1883
+ log6("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0 });
1860
1884
  return true;
1861
1885
  }
1862
1886
  }
@@ -1893,7 +1917,7 @@ var bookmarksField = StateField2.define({
1893
1917
 
1894
1918
  // src/extensions/comments.ts
1895
1919
  import { invertedEffects } from "@codemirror/commands";
1896
- import { StateEffect as StateEffect4, StateField as StateField3 } from "@codemirror/state";
1920
+ import { StateEffect as StateEffect5, StateField as StateField3 } from "@codemirror/state";
1897
1921
  import { Decoration as Decoration7, EditorView as EditorView11, ViewPlugin as ViewPlugin10, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
1898
1922
  import sortBy from "lodash.sortby";
1899
1923
  import { debounce as debounce2 } from "@dxos/async";
@@ -1908,7 +1932,7 @@ import { invariant as invariant3 } from "@dxos/invariant";
1908
1932
  import { isTruthy } from "@dxos/util";
1909
1933
  var __dxlog_file9 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/selection.ts";
1910
1934
  var documentId = singleValueFacet();
1911
- var stateRestoreAnnotation = "dxos.org/cm/state-restore";
1935
+ var stateRestoreAnnotation = "org.dxos.cm.state-restore";
1912
1936
  var createEditorStateTransaction = ({ scrollTo, selection }) => {
1913
1937
  return {
1914
1938
  selection,
@@ -1921,28 +1945,12 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1921
1945
  };
1922
1946
  var createEditorStateStore = (keyPrefix) => ({
1923
1947
  getState: (id) => {
1924
- invariant3(id, void 0, {
1925
- F: __dxlog_file9,
1926
- L: 47,
1927
- S: void 0,
1928
- A: [
1929
- "id",
1930
- ""
1931
- ]
1932
- });
1948
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 26, S: void 0, A: ["id", ""] });
1933
1949
  const state = localStorage.getItem(`${keyPrefix}/${id}`);
1934
1950
  return state ? JSON.parse(state) : void 0;
1935
1951
  },
1936
1952
  setState: (id, state) => {
1937
- invariant3(id, void 0, {
1938
- F: __dxlog_file9,
1939
- L: 53,
1940
- S: void 0,
1941
- A: [
1942
- "id",
1943
- ""
1944
- ]
1945
- });
1953
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 31, S: void 0, A: ["id", ""] });
1946
1954
  localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
1947
1955
  }
1948
1956
  });
@@ -1995,9 +2003,9 @@ var selectionState = ({ getState, setState } = {}) => {
1995
2003
 
1996
2004
  // src/extensions/comments.ts
1997
2005
  var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
1998
- var setComments = StateEffect4.define();
1999
- var setSelection = StateEffect4.define();
2000
- var setCommentState = StateEffect4.define();
2006
+ var setComments = StateEffect5.define();
2007
+ var setSelection = StateEffect5.define();
2008
+ var setCommentState = StateEffect5.define();
2001
2009
  var commentsState = StateField3.define({
2002
2010
  create: (state) => ({
2003
2011
  id: state.facet(documentId),
@@ -2064,12 +2072,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2064
2072
  const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
2065
2073
  const range = comment.range;
2066
2074
  if (!range) {
2067
- log7.warn("Invalid range:", range, {
2068
- F: __dxlog_file10,
2069
- L: 140,
2070
- S: void 0,
2071
- C: (f, a) => f(...a)
2072
- });
2075
+ log7.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file10, L: 93, S: void 0 });
2073
2076
  return void 0;
2074
2077
  } else if (range.from === range.to) {
2075
2078
  return void 0;
@@ -2079,7 +2082,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2079
2082
  }).filter(isNonNullable);
2080
2083
  return Decoration7.set(decorations2);
2081
2084
  });
2082
- var commentClickedEffect = StateEffect4.define();
2085
+ var commentClickedEffect = StateEffect5.define();
2083
2086
  var handleCommentClick = EditorView11.domEventHandlers({
2084
2087
  click: (event, view) => {
2085
2088
  let target = event.target;
@@ -2182,10 +2185,10 @@ var trackPastedComments = (onUpdate) => {
2182
2185
  const { comments: comments2 } = update2.startState.field(commentsState);
2183
2186
  const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
2184
2187
  if (!exists) {
2185
- const cursor2 = Cursor.getCursorFromRange(update2.state, comment);
2188
+ const cursor = Cursor.getCursorFromRange(update2.state, comment);
2186
2189
  onUpdate({
2187
2190
  id: comment.id,
2188
- cursor: cursor2
2191
+ cursor
2189
2192
  });
2190
2193
  }
2191
2194
  }
@@ -2197,7 +2200,7 @@ var mapTrackedComment = (comment, changes) => ({
2197
2200
  from: changes.mapPos(comment.from, 1),
2198
2201
  to: changes.mapPos(comment.to, 1)
2199
2202
  });
2200
- var restoreCommentEffect = StateEffect4.define({
2203
+ var restoreCommentEffect = StateEffect5.define({
2201
2204
  map: mapTrackedComment
2202
2205
  });
2203
2206
  var createComment = (view) => {
@@ -2214,13 +2217,13 @@ var createComment = (view) => {
2214
2217
  }
2215
2218
  });
2216
2219
  }
2217
- const cursor2 = Cursor.getCursorFromRange(view.state, {
2220
+ const cursor = Cursor.getCursorFromRange(view.state, {
2218
2221
  from,
2219
2222
  to
2220
2223
  });
2221
- if (cursor2) {
2224
+ if (cursor) {
2222
2225
  options.onCreate?.({
2223
- cursor: cursor2,
2226
+ cursor,
2224
2227
  from,
2225
2228
  location: view.coordsAtPos(from)
2226
2229
  });
@@ -2461,7 +2464,7 @@ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap }
2461
2464
  import { HighlightStyle, bracketMatching, syntaxHighlighting } from "@codemirror/language";
2462
2465
  import { searchKeymap } from "@codemirror/search";
2463
2466
  import { EditorState } from "@codemirror/state";
2464
- import { EditorView as EditorView15, ViewPlugin as ViewPlugin11, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap7, lineNumbers, placeholder as placeholder2, scrollPastEnd } from "@codemirror/view";
2467
+ import { EditorView as EditorView16, ViewPlugin as ViewPlugin12, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap7, lineNumbers, placeholder as placeholder2 } from "@codemirror/view";
2465
2468
  import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode";
2466
2469
  import defaultsDeep2 from "lodash.defaultsdeep";
2467
2470
  import { generateName } from "@dxos/display-name";
@@ -2473,28 +2476,28 @@ import { EditorView as EditorView13 } from "@codemirror/view";
2473
2476
  import { mx as mx3 } from "@dxos/ui-theme";
2474
2477
  var headings = {
2475
2478
  1: {
2476
- className: "text-4xl",
2477
- fontSize: "var(--text-4xl)",
2479
+ className: "text-3xl",
2480
+ fontSize: "var(--text-3xl)",
2478
2481
  lineHeight: "var(--text-4xl--line-height)"
2479
2482
  },
2480
2483
  2: {
2481
- className: "text-3xl",
2482
- fontSize: "var(--text-3xl)",
2484
+ className: "text-2xl",
2485
+ fontSize: "var(--text-2xl)",
2483
2486
  lineHeight: "var(--text-3xl--line-height)"
2484
2487
  },
2485
2488
  3: {
2486
- className: "text-2xl",
2487
- fontSize: "var(--text-2xl)",
2489
+ className: "text-xl",
2490
+ fontSize: "var(--text-xl)",
2488
2491
  lineHeight: "var(--text-2xl--line-height)"
2489
2492
  },
2490
2493
  4: {
2491
- className: "text-xl",
2492
- fontSize: "var(--text-xl)",
2494
+ className: "text-lg",
2495
+ fontSize: "var(--text-lg)",
2493
2496
  lineHeight: "var(--text-xl--line-height)"
2494
2497
  },
2495
2498
  5: {
2496
- className: "text-lg",
2497
- fontSize: "var(--text-lg)",
2499
+ className: "text-base",
2500
+ fontSize: "var(--text-base)",
2498
2501
  lineHeight: "var(--text-lg--line-height)"
2499
2502
  },
2500
2503
  6: {
@@ -2503,20 +2506,20 @@ var headings = {
2503
2506
  lineHeight: "var(--text-base--line-height)"
2504
2507
  }
2505
2508
  };
2509
+ var fontBody = '"Inter Variable", ui-sans-serif, system-ui, sans-serif';
2510
+ var fontMono = '"JetBrains Mono Variable", ui-monospace, "Cascadia Code", "Source Code Pro", monospace';
2506
2511
  var markdownTheme = {
2507
- code: "font-mono no-underline! text-cm-code",
2508
- codeMark: "font-mono text-cm-code-mark",
2509
- mark: "opacity-50",
2512
+ code: "font-mono! cm-code-inline",
2513
+ codeMark: "font-mono! cm-code-mark",
2514
+ mark: "font-mono!",
2510
2515
  heading: (level) => ({
2511
- className: mx3(headings[level].className, "font-light text-cm-heading"),
2516
+ className: mx3(headings[level].className, "font-light text-(--color-cm-heading-number)"),
2512
2517
  color: "var(--color-cm-heading) !important",
2513
2518
  lineHeight: headings[level].lineHeight,
2514
2519
  fontSize: headings[level].fontSize,
2515
2520
  fontWeight: "100 !important"
2516
2521
  })
2517
2522
  };
2518
- var fontBody = "Inter Variable, ui-sans-serif, system-ui, sans-serif";
2519
- var fontMono = "JetBrains Mono Variable, ui-monospace, Cascadia Code, Source Code Pro, monospace";
2520
2523
  var baseTheme = EditorView13.baseTheme({
2521
2524
  /**
2522
2525
  * Outer frame.
@@ -2529,12 +2532,21 @@ var baseTheme = EditorView13.baseTheme({
2529
2532
  * Scroller
2530
2533
  */
2531
2534
  ".cm-scroller": {
2532
- overflowAnchor: "none"
2535
+ // Browser scroll-anchoring: see comment in `scroller.ts`. `auto` lets the browser pin a
2536
+ // stable element near the viewport top so widget resizes (e.g. tool-block TogglePanel
2537
+ // open/close) don't jump the user's view.
2538
+ overflowAnchor: "auto"
2533
2539
  },
2534
2540
  ".cm-scroller::-webkit-scrollbar": {
2535
- width: "8px"
2541
+ width: "var(--scrollbar-size,8px)",
2542
+ height: "var(--scrollbar-size,8px)"
2543
+ },
2544
+ ".cm-scroller::-webkit-scrollbar-corner": {
2545
+ background: "transparent"
2546
+ },
2547
+ ".cm-scroller::-webkit-scrollbar-track": {
2548
+ background: "transparent"
2536
2549
  },
2537
- ".cm-scroller::-webkit-scrollbar-track": {},
2538
2550
  ".cm-scroller::-webkit-scrollbar-thumb": {
2539
2551
  background: "transparent",
2540
2552
  transition: "background 0.15s"
@@ -2548,7 +2560,6 @@ var baseTheme = EditorView13.baseTheme({
2548
2560
  */
2549
2561
  ".cm-content": {
2550
2562
  padding: "unset",
2551
- lineHeight: "24px",
2552
2563
  color: "unset"
2553
2564
  },
2554
2565
  /**
@@ -2579,9 +2590,16 @@ var baseTheme = EditorView13.baseTheme({
2579
2590
  * Line.
2580
2591
  */
2581
2592
  ".cm-line": {
2582
- lineHeight: "24px",
2593
+ lineHeight: 1.5,
2583
2594
  paddingInline: 0
2584
2595
  },
2596
+ /**
2597
+ * Force all inline children to inherit line-height to prevent monospace font metrics
2598
+ * (JetBrains Mono ascent/descent) from inflating the line box beyond 24px.
2599
+ */
2600
+ ".cm-line *": {
2601
+ lineHeight: "inherit"
2602
+ },
2585
2603
  ".cm-activeLine": {
2586
2604
  background: "var(--color-cm-active-line)"
2587
2605
  },
@@ -2759,10 +2777,9 @@ var editorGutter = EditorView13.theme({
2759
2777
  }
2760
2778
  });
2761
2779
  var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2762
- // Set metrics on the scroller (this is often what CM uses for layout).
2780
+ // Main content.
2763
2781
  ".cm-scroller": {
2764
- fontFamily: monospace ? fontMono : fontBody,
2765
- fontSize: "16px"
2782
+ fontFamily: monospace ? fontMono : fontBody
2766
2783
  },
2767
2784
  // Maintain defaults for UI components.
2768
2785
  ".cm-content, .cm-gutters, .cm-panel": {
@@ -2772,9 +2789,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2772
2789
  });
2773
2790
 
2774
2791
  // src/extensions/focus.ts
2775
- import { StateEffect as StateEffect5, StateField as StateField5 } from "@codemirror/state";
2792
+ import { StateEffect as StateEffect6, StateField as StateField5 } from "@codemirror/state";
2776
2793
  import { EditorView as EditorView14 } from "@codemirror/view";
2777
- var focusEffect = StateEffect5.define();
2794
+ var focusEffect = StateEffect6.define();
2778
2795
  var focusField = StateField5.define({
2779
2796
  create: () => false,
2780
2797
  update: (value, tr) => {
@@ -2802,9 +2819,32 @@ var focus = [
2802
2819
  })
2803
2820
  ];
2804
2821
 
2822
+ // src/extensions/scroll-past-end.ts
2823
+ import { EditorView as EditorView15, ViewPlugin as ViewPlugin11 } from "@codemirror/view";
2824
+ var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
2825
+ height = 1e3;
2826
+ attrs = {
2827
+ style: "padding-bottom: 1000px"
2828
+ };
2829
+ update({ view }) {
2830
+ const lastLineBlock = view.lineBlockAt(view.state.doc.length);
2831
+ const height = view.dom.clientHeight - lastLineBlock.height - view.documentPadding.top - 0.5;
2832
+ if (height >= 0 && height !== this.height) {
2833
+ this.height = height;
2834
+ this.attrs = {
2835
+ style: `padding-bottom: ${height}px`
2836
+ };
2837
+ }
2838
+ }
2839
+ });
2840
+ var scrollPastEnd = () => [
2841
+ scrollPastEndPlugin,
2842
+ EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?.attrs ?? null)
2843
+ ];
2844
+
2805
2845
  // src/extensions/factories.ts
2806
2846
  var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
2807
- var tabbable = EditorView15.contentAttributes.of({
2847
+ var tabbable = EditorView16.contentAttributes.of({
2808
2848
  tabindex: "0"
2809
2849
  });
2810
2850
  var filterChars = (chars) => {
@@ -2857,13 +2897,8 @@ var createBasicExtensions = (propsProp) => {
2857
2897
  const props = defaultsDeep2({}, propsProp, defaultBasicOptions);
2858
2898
  return [
2859
2899
  // NOTE: Doesn't catch errors in keymap functions.
2860
- EditorView15.exceptionSink.of((err) => {
2861
- log8.catch(err, void 0, {
2862
- F: __dxlog_file11,
2863
- L: 131,
2864
- S: void 0,
2865
- C: (f, a) => f(...a)
2866
- });
2900
+ EditorView16.exceptionSink.of((err) => {
2901
+ log8.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file11, L: 79, S: void 0 });
2867
2902
  }),
2868
2903
  props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2869
2904
  props.bracketMatching && bracketMatching(),
@@ -2872,7 +2907,7 @@ var createBasicExtensions = (propsProp) => {
2872
2907
  props.drawSelection && drawSelection({
2873
2908
  cursorBlinkRate: 1200
2874
2909
  }),
2875
- props.editable !== void 0 && EditorView15.editable.of(props.editable),
2910
+ props.editable !== void 0 && EditorView16.editable.of(props.editable),
2876
2911
  props.focus && focus,
2877
2912
  props.highlightActiveLine && highlightActiveLine(),
2878
2913
  props.history && history(),
@@ -2880,9 +2915,16 @@ var createBasicExtensions = (propsProp) => {
2880
2915
  lineNumbers(),
2881
2916
  editorGutter
2882
2917
  ],
2883
- props.lineWrapping && EditorView15.lineWrapping,
2918
+ props.lineWrapping && EditorView16.lineWrapping,
2884
2919
  props.placeholder && placeholder2(props.placeholder),
2885
2920
  props.readOnly !== void 0 && EditorState.readOnly.of(props.readOnly),
2921
+ // `EditorState.readOnly` is advisory — CodeMirror doesn't auto-reject doc-changing
2922
+ // transactions. Some extensions (e.g. `@codemirror/lang-markdown`'s Enter handler that
2923
+ // continues a list) dispatch programmatic edits regardless. Drop user-initiated edits
2924
+ // (`input` / `delete` keymap dispatches plus `undo` / `redo` from the history extension)
2925
+ // but pass programmatic dispatches — streaming `MarkdownStream` and similar consumers
2926
+ // depend on being able to populate the doc themselves.
2927
+ props.readOnly && EditorState.transactionFilter.of((tr) => tr.docChanged && (tr.isUserEvent("input") || tr.isUserEvent("delete") || tr.isUserEvent("undo") || tr.isUserEvent("redo")) ? [] : tr),
2886
2928
  props.scrollPastEnd && scrollPastEnd(),
2887
2929
  props.tabbable && tabbable,
2888
2930
  props.tabSize && EditorState.tabSize.of(props.tabSize),
@@ -2925,24 +2967,29 @@ var defaultStyles = {
2925
2967
  dark: vscodeDarkStyle,
2926
2968
  light: vscodeLightStyle
2927
2969
  };
2928
- var createThemeExtensions = ({ monospace, themeMode, slots: slotsProp, syntaxHighlighting: syntaxHighlightingProp } = {}) => {
2970
+ var createThemeExtensions = ({ monospace, scrollbarThin, slots: slotsProp, syntaxHighlighting: syntaxHighlightingProp, themeMode } = {}) => {
2929
2971
  const slots = defaultsDeep2({}, slotsProp, defaultThemeSlots);
2930
2972
  return [
2931
2973
  baseTheme,
2932
- EditorView15.darkTheme.of(themeMode === "dark"),
2974
+ EditorView16.darkTheme.of(themeMode === "dark"),
2933
2975
  createFontTheme({
2934
2976
  monospace
2935
2977
  }),
2936
2978
  syntaxHighlightingProp && syntaxHighlighting(HighlightStyle.define(themeMode === "dark" ? defaultStyles.dark : defaultStyles.light)),
2937
- slots.editor?.className && EditorView15.editorAttributes.of({
2979
+ slots.editor?.className && EditorView16.editorAttributes.of({
2938
2980
  class: slots.editor.className
2939
2981
  }),
2940
- slots.content?.className && EditorView15.contentAttributes.of({
2982
+ slots.content?.className && EditorView16.contentAttributes.of({
2941
2983
  class: slots.content.className
2942
2984
  }),
2943
- slots.scroll?.className && ViewPlugin11.fromClass(class {
2985
+ (slots.scroller?.className || scrollbarThin) && ViewPlugin12.fromClass(class {
2944
2986
  constructor(view) {
2945
- view.scrollDOM.classList.add(...slots.scroll.className.split(/\s+/));
2987
+ if (slots.scroller?.className) {
2988
+ view.scrollDOM.classList.add(...slots.scroller.className.split(/\s+/));
2989
+ }
2990
+ if (scrollbarThin) {
2991
+ view.scrollDOM.style.setProperty("--scrollbar-size", "4px");
2992
+ }
2946
2993
  }
2947
2994
  })
2948
2995
  ].filter(isTruthy2);
@@ -2971,7 +3018,7 @@ var createDataExtensions = ({ id, text, messenger, identity }) => {
2971
3018
 
2972
3019
  // src/extensions/folding.ts
2973
3020
  import { codeFolding, foldGutter } from "@codemirror/language";
2974
- import { EditorView as EditorView16 } from "@codemirror/view";
3021
+ import { EditorView as EditorView17 } from "@codemirror/view";
2975
3022
  import { Domino as Domino2, mx as mx4 } from "@dxos/ui";
2976
3023
  var folding = () => {
2977
3024
  return [
@@ -2979,13 +3026,14 @@ var folding = () => {
2979
3026
  placeholderDOM: () => Domino2.of("span").root
2980
3027
  }),
2981
3028
  foldGutter({
3029
+ // NOTE: We can't animate since the element is remounted on state change.
2982
3030
  markerDOM: (open) => {
2983
- return Domino2.of("div").classNames("flex h-full justify-center items-center").children(Domino2.of("svg", Domino2.SVG).classNames(mx4("w-4 h-4 cursor-pointer", open && "rotate-90")).children(Domino2.of("use", Domino2.SVG).attributes({
3031
+ return Domino2.of("div").classNames("flex h-full justify-center items-center").append(Domino2.of("svg", Domino2.SVG).classNames(mx4("w-4 h-4 cursor-pointer", open && "rotate-90")).append(Domino2.of("use", Domino2.SVG).attributes({
2984
3032
  href: Domino2.icon("ph--caret-right--regular")
2985
3033
  }))).root;
2986
3034
  }
2987
3035
  }),
2988
- EditorView16.theme({
3036
+ EditorView17.theme({
2989
3037
  ".cm-foldGutter": {
2990
3038
  opacity: 0.3,
2991
3039
  transition: "opacity 0.3s",
@@ -2999,7 +3047,7 @@ var folding = () => {
2999
3047
  };
3000
3048
 
3001
3049
  // src/extensions/hashtag.ts
3002
- import { Decoration as Decoration8, EditorView as EditorView17, MatchDecorator, ViewPlugin as ViewPlugin12, WidgetType as WidgetType4 } from "@codemirror/view";
3050
+ import { Decoration as Decoration8, EditorView as EditorView18, MatchDecorator, ViewPlugin as ViewPlugin13, WidgetType as WidgetType4 } from "@codemirror/view";
3003
3051
  import { getHashStyles, mx as mx5 } from "@dxos/ui-theme";
3004
3052
  var TagWidget = class extends WidgetType4 {
3005
3053
  _text;
@@ -3020,7 +3068,7 @@ var tagMatcher = new MatchDecorator({
3020
3068
  })
3021
3069
  });
3022
3070
  var hashtag = () => [
3023
- ViewPlugin12.fromClass(class {
3071
+ ViewPlugin13.fromClass(class {
3024
3072
  tags;
3025
3073
  constructor(view) {
3026
3074
  this.tags = tagMatcher.createDeco(view);
@@ -3030,11 +3078,11 @@ var hashtag = () => [
3030
3078
  }
3031
3079
  }, {
3032
3080
  decorations: (instance) => instance.tags,
3033
- provide: (plugin) => EditorView17.atomicRanges.of((view) => {
3081
+ provide: (plugin) => EditorView18.atomicRanges.of((view) => {
3034
3082
  return view.plugin(plugin)?.tags || Decoration8.none;
3035
3083
  })
3036
3084
  }),
3037
- EditorView17.theme({
3085
+ EditorView18.theme({
3038
3086
  ".cm-tag": {
3039
3087
  borderRadius: "4px",
3040
3088
  marginRight: "6px",
@@ -3089,18 +3137,18 @@ var schemaLinter = (validate) => (view) => {
3089
3137
  };
3090
3138
 
3091
3139
  // src/extensions/listener.ts
3092
- import { EditorView as EditorView18 } from "@codemirror/view";
3140
+ import { EditorView as EditorView19 } from "@codemirror/view";
3093
3141
  import { isNonNullable as isNonNullable2 } from "@dxos/util";
3094
3142
  var listener = ({ onFocus, onChange }) => {
3095
3143
  return [
3096
- onFocus && EditorView18.focusChangeEffect.of((state, focusing) => {
3144
+ onFocus && EditorView19.focusChangeEffect.of((state, focusing) => {
3097
3145
  onFocus({
3098
3146
  id: state.facet(documentId),
3099
3147
  focusing
3100
3148
  });
3101
3149
  return null;
3102
3150
  }),
3103
- onChange && EditorView18.updateListener.of(({ state, docChanged }) => {
3151
+ onChange && EditorView19.updateListener.of(({ state, docChanged }) => {
3104
3152
  if (docChanged) {
3105
3153
  onChange({
3106
3154
  id: state.facet(documentId),
@@ -3115,7 +3163,7 @@ var listener = ({ onFocus, onChange }) => {
3115
3163
  import { snippet } from "@codemirror/autocomplete";
3116
3164
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3117
3165
  import { EditorSelection as EditorSelection2 } from "@codemirror/state";
3118
- import { EditorView as EditorView19, keymap as keymap8 } from "@codemirror/view";
3166
+ import { EditorView as EditorView20, keymap as keymap8 } from "@codemirror/view";
3119
3167
  import { debounceAndThrottle } from "@dxos/async";
3120
3168
  var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
3121
3169
  var Inline = /* @__PURE__ */ (function(Inline2) {
@@ -4204,7 +4252,7 @@ var getFormatting = (state) => {
4204
4252
  };
4205
4253
  };
4206
4254
  var formattingListener = (onStateChange, delay = 100) => {
4207
- return EditorView19.updateListener.of(debounceAndThrottle((update2) => {
4255
+ return EditorView20.updateListener.of(debounceAndThrottle((update2) => {
4208
4256
  if (update2.docChanged || update2.selectionSet) {
4209
4257
  onStateChange(getFormatting(update2.state));
4210
4258
  }
@@ -4265,8 +4313,7 @@ import { completionKeymap } from "@codemirror/autocomplete";
4265
4313
  import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
4266
4314
  import { jsonLanguage } from "@codemirror/lang-json";
4267
4315
  import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
4268
- import { xml } from "@codemirror/lang-xml";
4269
- import { LanguageDescription, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4316
+ import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4270
4317
  import { languages } from "@codemirror/language-data";
4271
4318
  import { keymap as keymap9 } from "@codemirror/view";
4272
4319
  import { isTruthy as isTruthy3 } from "@dxos/util";
@@ -4276,11 +4323,6 @@ import { markdownLanguage } from "@codemirror/lang-markdown";
4276
4323
  import { HighlightStyle as HighlightStyle2 } from "@codemirror/language";
4277
4324
  import { Tag, styleTags, tags } from "@lezer/highlight";
4278
4325
  import { Table } from "@lezer/markdown";
4279
- var styles4 = {
4280
- code: "font-mono no-underline! text-cm-code",
4281
- codeMark: "font-mono text-cm-code-mark",
4282
- mark: "opacity-50"
4283
- };
4284
4326
  var markdownTags = {
4285
4327
  Blockquote: Tag.define(),
4286
4328
  CodeMark: Tag.define(),
@@ -4362,7 +4404,7 @@ var markdownHighlightStyle = (_options = {}) => {
4362
4404
  markdownTags.LinkReference,
4363
4405
  markdownTags.ListMark
4364
4406
  ],
4365
- class: styles4.mark
4407
+ class: markdownTheme.mark
4366
4408
  },
4367
4409
  // Markdown marks.
4368
4410
  {
@@ -4373,7 +4415,7 @@ var markdownHighlightStyle = (_options = {}) => {
4373
4415
  markdownTags.QuoteMark,
4374
4416
  markdownTags.EmphasisMark
4375
4417
  ],
4376
- class: styles4.mark
4418
+ class: markdownTheme.mark
4377
4419
  },
4378
4420
  // E.g., code block language (after ```).
4379
4421
  {
@@ -4382,7 +4424,7 @@ var markdownHighlightStyle = (_options = {}) => {
4382
4424
  tags.function(tags.variableName),
4383
4425
  tags.labelName
4384
4426
  ],
4385
- class: styles4.codeMark
4427
+ class: markdownTheme.codeMark
4386
4428
  },
4387
4429
  // Fonts.
4388
4430
  {
@@ -4448,7 +4490,7 @@ var markdownHighlightStyle = (_options = {}) => {
4448
4490
  markdownTags.CodeText,
4449
4491
  markdownTags.InlineCode
4450
4492
  ],
4451
- class: styles4.code
4493
+ class: markdownTheme.code
4452
4494
  },
4453
4495
  {
4454
4496
  tag: [
@@ -4478,15 +4520,23 @@ var createMarkdownExtensions = (options = {}) => {
4478
4520
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
4479
4521
  base: markdownLanguage2,
4480
4522
  // Languages for syntax highlighting fenced code blocks.
4523
+ // Caller-supplied languages are checked first so they can override defaults.
4481
4524
  defaultCodeLanguage: jsonLanguage,
4482
- codeLanguages: languages,
4525
+ codeLanguages: [
4526
+ ...options.codeLanguages ?? [],
4527
+ ...languages
4528
+ ],
4483
4529
  // Don't complete HTML tags.
4484
4530
  completeHTMLTags: false,
4485
4531
  // Parser extensions.
4486
4532
  extensions: [
4487
4533
  // GFM provided by default.
4488
4534
  markdownTagsExtensions,
4489
- ...options.extensions ?? defaultExtensions()
4535
+ ...options.extensions ?? defaultExtensions(),
4536
+ // Disable folding for fenced code blocks by overriding foldNodeProp.
4537
+ // Note: returning null from foldService does not prevent syntaxFolding fallback,
4538
+ // so we must override the node prop directly on the FencedCode node type.
4539
+ noFencedCodeFolding
4490
4540
  ]
4491
4541
  }),
4492
4542
  // Custom styles.
@@ -4501,18 +4551,13 @@ var createMarkdownExtensions = (options = {}) => {
4501
4551
  ].filter(isTruthy3))
4502
4552
  ];
4503
4553
  };
4504
- var xmlLanguageDesc = LanguageDescription.of({
4505
- name: "xml",
4506
- alias: [
4507
- "html",
4508
- "xhtml"
4509
- ],
4510
- extensions: [
4511
- "xml",
4512
- "xhtml"
4513
- ],
4514
- load: async () => xml()
4515
- });
4554
+ var noFencedCodeFolding = {
4555
+ props: [
4556
+ foldNodeProp.add({
4557
+ FencedCode: () => null
4558
+ })
4559
+ ]
4560
+ };
4516
4561
  var defaultExtensions = () => [
4517
4562
  noSetExtHeading,
4518
4563
  noHtml
@@ -4532,19 +4577,19 @@ var debugTree = (cb) => StateField6.define({
4532
4577
  update: (value, tr) => cb(convertTreeToJson(tr.state))
4533
4578
  });
4534
4579
  var convertTreeToJson = (state) => {
4535
- const treeToJson = (cursor2) => {
4580
+ const treeToJson = (cursor) => {
4536
4581
  const node = {
4537
- type: cursor2.type.name,
4538
- from: cursor2.from,
4539
- to: cursor2.to,
4540
- text: state.doc.slice(cursor2.from, cursor2.to).toString(),
4582
+ type: cursor.type.name,
4583
+ from: cursor.from,
4584
+ to: cursor.to,
4585
+ text: state.doc.slice(cursor.from, cursor.to).toString(),
4541
4586
  children: []
4542
4587
  };
4543
- if (cursor2.firstChild()) {
4588
+ if (cursor.firstChild()) {
4544
4589
  do {
4545
- node.children.push(treeToJson(cursor2));
4546
- } while (cursor2.nextSibling());
4547
- cursor2.parent();
4590
+ node.children.push(treeToJson(cursor));
4591
+ } while (cursor.nextSibling());
4592
+ cursor.parent();
4548
4593
  }
4549
4594
  return node;
4550
4595
  };
@@ -4553,17 +4598,16 @@ var convertTreeToJson = (state) => {
4553
4598
 
4554
4599
  // src/extensions/markdown/decorate.ts
4555
4600
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4556
- import { Prec as Prec4, RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect6 } from "@codemirror/state";
4557
- import { Decoration as Decoration11, EditorView as EditorView23, ViewPlugin as ViewPlugin14, WidgetType as WidgetType7 } from "@codemirror/view";
4601
+ import { Prec as Prec4, RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect7 } from "@codemirror/state";
4602
+ import { Decoration as Decoration11, EditorView as EditorView24, ViewPlugin as ViewPlugin15, WidgetType as WidgetType7 } from "@codemirror/view";
4558
4603
  import { invariant as invariant4 } from "@dxos/invariant";
4559
- import { mx as mx6 } from "@dxos/ui-theme";
4560
4604
 
4561
4605
  // src/extensions/markdown/changes.ts
4562
4606
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
4563
4607
  import { Transaction as Transaction4 } from "@codemirror/state";
4564
- import { ViewPlugin as ViewPlugin13 } from "@codemirror/view";
4608
+ import { ViewPlugin as ViewPlugin14 } from "@codemirror/view";
4565
4609
  var adjustChanges = () => {
4566
- return ViewPlugin13.fromClass(class {
4610
+ return ViewPlugin14.fromClass(class {
4567
4611
  update(update2) {
4568
4612
  const tree = syntaxTree4(update2.state);
4569
4613
  const adjustments = [];
@@ -4705,7 +4749,7 @@ var getValidUrl = (str) => {
4705
4749
  // src/extensions/markdown/image.ts
4706
4750
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4707
4751
  import { StateField as StateField7 } from "@codemirror/state";
4708
- import { Decoration as Decoration9, EditorView as EditorView20, WidgetType as WidgetType5 } from "@codemirror/view";
4752
+ import { Decoration as Decoration9, EditorView as EditorView21, WidgetType as WidgetType5 } from "@codemirror/view";
4709
4753
  var image = (_options = {}) => {
4710
4754
  return [
4711
4755
  StateField7.define({
@@ -4716,10 +4760,10 @@ var image = (_options = {}) => {
4716
4760
  if (!tr.docChanged && !tr.selection) {
4717
4761
  return value;
4718
4762
  }
4719
- const cursor2 = tr.state.selection.main.head;
4763
+ const cursor = tr.state.selection.main.head;
4720
4764
  const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
4721
- let from = Math.min(cursor2, oldCursor);
4722
- let to = Math.max(cursor2, oldCursor);
4765
+ let from = Math.min(cursor, oldCursor);
4766
+ let to = Math.max(cursor, oldCursor);
4723
4767
  tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
4724
4768
  from = Math.min(from, fromB);
4725
4769
  to = Math.max(to, toB);
@@ -4733,19 +4777,19 @@ var image = (_options = {}) => {
4733
4777
  add: buildDecorations(tr.state, from, to)
4734
4778
  });
4735
4779
  },
4736
- provide: (field) => EditorView20.decorations.from(field)
4780
+ provide: (field) => EditorView21.decorations.from(field)
4737
4781
  })
4738
4782
  ];
4739
4783
  };
4740
4784
  var buildDecorations = (state, from, to) => {
4741
4785
  const decorations2 = [];
4742
- const cursor2 = state.selection.main.head;
4786
+ const cursor = state.selection.main.head;
4743
4787
  syntaxTree5(state).iterate({
4744
4788
  enter: (node) => {
4745
4789
  if (node.name === "Image") {
4746
4790
  const urlNode = node.node.getChild("URL");
4747
4791
  if (urlNode) {
4748
- const hide2 = state.readOnly || cursor2 < node.from || cursor2 > node.to || !state.field(focusField);
4792
+ const hide2 = state.readOnly || cursor < node.from || cursor > node.to || !state.field(focusField);
4749
4793
  const url = state.sliceDoc(urlNode.from, urlNode.to);
4750
4794
  if (url.match(/^https?:\/\//) === null && url.match(/^file?:\/\//) === null) {
4751
4795
  return;
@@ -4793,10 +4837,10 @@ var ImageWidget = class extends WidgetType5 {
4793
4837
  };
4794
4838
 
4795
4839
  // src/extensions/markdown/styles.ts
4796
- import { EditorView as EditorView21 } from "@codemirror/view";
4840
+ import { EditorView as EditorView22 } from "@codemirror/view";
4797
4841
  var bulletListIndentationWidth = 24;
4798
4842
  var orderedListIndentationWidth = 36;
4799
- var formattingStyles = EditorView21.theme({
4843
+ var formattingStyles = EditorView22.theme({
4800
4844
  /**
4801
4845
  * Horizontal rule.
4802
4846
  */
@@ -4831,13 +4875,38 @@ var formattingStyles = EditorView21.theme({
4831
4875
  background: "var(--color-cm-codeblock)",
4832
4876
  borderLeft: "2px solid var(--color-cm-separator)",
4833
4877
  paddingLeft: "1rem",
4834
- margin: "0"
4878
+ margin: 0
4835
4879
  },
4836
4880
  /**
4837
4881
  * Code and codeblocks.
4838
4882
  */
4883
+ "& code": {
4884
+ fontFamily: fontMono,
4885
+ color: "var(--color-cm-code)",
4886
+ whiteSpace: "nowrap"
4887
+ },
4839
4888
  "& .cm-code": {
4840
- fontFamily: fontMono
4889
+ fontFamily: fontMono,
4890
+ color: "var(--color-cm-code)"
4891
+ },
4892
+ // Inline code spans (triggered by backticks) use `cm-code-inline` + `font-mono`.
4893
+ // Different monospace font metrics can slightly overflow the fixed CodeMirror line box,
4894
+ // so constrain them to the target 24px height.
4895
+ "& .cm-code-inline": {
4896
+ fontFamily: fontMono,
4897
+ height: "24px",
4898
+ // display: 'inline-flex',
4899
+ alignItems: "center",
4900
+ overflow: "hidden",
4901
+ whiteSpace: "nowrap",
4902
+ color: "var(--color-cm-code-inline)"
4903
+ },
4904
+ "& .cm-code-mark": {
4905
+ fontFamily: fontMono,
4906
+ height: "24px",
4907
+ display: "inline-flex",
4908
+ alignItems: "center",
4909
+ overflow: "hidden"
4841
4910
  },
4842
4911
  "& .cm-codeblock-line": {
4843
4912
  background: "var(--color-cm-codeblock)",
@@ -4869,16 +4938,24 @@ var formattingStyles = EditorView21.theme({
4869
4938
  */
4870
4939
  ".cm-table *": {
4871
4940
  fontFamily: fontMono,
4941
+ lineHeight: 1.5,
4872
4942
  textDecoration: "none !important"
4873
4943
  },
4874
4944
  ".cm-table-head": {
4875
4945
  padding: "2px 16px 2px 0px",
4946
+ overflowWrap: "break-word",
4947
+ whiteSpace: "pre-wrap",
4948
+ wordBreak: "keep-all",
4876
4949
  textAlign: "left",
4877
- borderBottom: "1px solid var(--color-cm-separator)",
4878
- color: "var(--color-subdued)"
4950
+ color: "var(--color-subdued)",
4951
+ borderBottom: "1px solid var(--color-cm-separator)"
4879
4952
  },
4880
4953
  ".cm-table-cell": {
4881
- padding: "2px 16px 2px 0px"
4954
+ padding: "2px 16px 2px 0px",
4955
+ overflowWrap: "break-word",
4956
+ whiteSpace: "pre-wrap",
4957
+ wordBreak: "keep-all",
4958
+ verticalAlign: "top"
4882
4959
  },
4883
4960
  /**
4884
4961
  * Image.
@@ -4894,12 +4971,12 @@ var formattingStyles = EditorView21.theme({
4894
4971
  },
4895
4972
  ".cm-image-with-loader": {
4896
4973
  display: "block",
4897
- opacity: "0",
4974
+ opacity: 0,
4898
4975
  transitionDuration: "350ms",
4899
4976
  transitionProperty: "opacity"
4900
4977
  },
4901
4978
  ".cm-image-with-loader.cm-loaded-image": {
4902
- opacity: "1"
4979
+ opacity: 1
4903
4980
  },
4904
4981
  ".cm-image-wrapper": {
4905
4982
  "grid-template-columns": "1fr",
@@ -4918,17 +4995,17 @@ var formattingStyles = EditorView21.theme({
4918
4995
  // src/extensions/markdown/table.ts
4919
4996
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4920
4997
  import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField8 } from "@codemirror/state";
4921
- import { Decoration as Decoration10, EditorView as EditorView22, WidgetType as WidgetType6 } from "@codemirror/view";
4998
+ import { Decoration as Decoration10, EditorView as EditorView23, WidgetType as WidgetType6 } from "@codemirror/view";
4922
4999
  var table = (options = {}) => {
4923
5000
  return StateField8.define({
4924
5001
  create: (state) => update(state, options),
4925
5002
  update: (_, tr) => update(tr.state, options),
4926
- provide: (field) => EditorView22.decorations.from(field)
5003
+ provide: (field) => EditorView23.decorations.from(field)
4927
5004
  });
4928
5005
  };
4929
5006
  var update = (state, _options) => {
4930
5007
  const builder = new RangeSetBuilder4();
4931
- const cursor2 = state.selection.main.head;
5008
+ const cursor = state.selection.main.head;
4932
5009
  const tables = [];
4933
5010
  const getTable = () => tables[tables.length - 1];
4934
5011
  const getRow = () => {
@@ -4966,7 +5043,7 @@ var update = (state, _options) => {
4966
5043
  }
4967
5044
  });
4968
5045
  tables.forEach((table2) => {
4969
- const replace = state.readOnly || cursor2 < table2.from || cursor2 > table2.to;
5046
+ const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4970
5047
  if (replace) {
4971
5048
  builder.add(table2.from, table2.to, Decoration10.replace({
4972
5049
  block: true,
@@ -4980,6 +5057,26 @@ var update = (state, _options) => {
4980
5057
  });
4981
5058
  return builder.finish();
4982
5059
  };
5060
+ var renderCellContent = (el, text) => {
5061
+ const parts = text.split(/(`[^`\n]+`|\*\*[^*\n]+\*\*|__[^_\n]+__|\*[^*\n]+\*|_[^_\n]+_)/);
5062
+ for (const part of parts) {
5063
+ if (part.length > 2 && part.startsWith("`") && part.endsWith("`")) {
5064
+ const code = document.createElement("code");
5065
+ code.textContent = part.slice(1, -1);
5066
+ el.appendChild(code);
5067
+ } else if (part.startsWith("**") && part.endsWith("**") || part.startsWith("__") && part.endsWith("__")) {
5068
+ const strong = document.createElement("strong");
5069
+ strong.textContent = part.slice(2, -2);
5070
+ el.appendChild(strong);
5071
+ } else if (part.startsWith("*") && part.endsWith("*") || part.startsWith("_") && part.endsWith("_")) {
5072
+ const em = document.createElement("em");
5073
+ em.textContent = part.slice(1, -1);
5074
+ el.appendChild(em);
5075
+ } else {
5076
+ el.appendChild(document.createTextNode(part));
5077
+ }
5078
+ }
5079
+ };
4983
5080
  var TableWidget = class extends WidgetType6 {
4984
5081
  _table;
4985
5082
  constructor(_table) {
@@ -4999,7 +5096,7 @@ var TableWidget = class extends WidgetType6 {
4999
5096
  this._table.header?.forEach((cell) => {
5000
5097
  const th = document.createElement("th");
5001
5098
  th.setAttribute("class", "cm-table-head");
5002
- tr.appendChild(th).textContent = cell;
5099
+ renderCellContent(tr.appendChild(th), cell);
5003
5100
  });
5004
5101
  const body = table2.appendChild(document.createElement("tbody"));
5005
5102
  this._table.rows?.forEach((row) => {
@@ -5007,7 +5104,7 @@ var TableWidget = class extends WidgetType6 {
5007
5104
  row.forEach((cell) => {
5008
5105
  const td = document.createElement("td");
5009
5106
  td.setAttribute("class", "cm-table-cell");
5010
- tr2.appendChild(td).textContent = cell;
5107
+ renderCellContent(tr2.appendChild(td), cell);
5011
5108
  });
5012
5109
  });
5013
5110
  return div;
@@ -5114,10 +5211,10 @@ var fencedCodeLine = Decoration11.line({
5114
5211
  class: "cm-code cm-codeblock-line"
5115
5212
  });
5116
5213
  var fencedCodeLineFirst = Decoration11.line({
5117
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-start")
5214
+ class: "cm-code cm-codeblock-line cm-codeblock-start"
5118
5215
  });
5119
5216
  var fencedCodeLineLast = Decoration11.line({
5120
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-end")
5217
+ class: "cm-code cm-codeblock-line cm-codeblock-end"
5121
5218
  });
5122
5219
  var commentBlockLine = fencedCodeLine;
5123
5220
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -5149,15 +5246,7 @@ var buildDecorations2 = (view, options, focus2) => {
5149
5246
  const { state } = view;
5150
5247
  const headerLevels = [];
5151
5248
  const getHeaderLevels = (node, level) => {
5152
- invariant4(level > 0, void 0, {
5153
- F: __dxlog_file12,
5154
- L: 179,
5155
- S: void 0,
5156
- A: [
5157
- "level > 0",
5158
- ""
5159
- ]
5160
- });
5249
+ invariant4(level > 0, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file12, L: 160, S: void 0, A: ["level > 0", ""] });
5161
5250
  if (level > headerLevels.length) {
5162
5251
  const len = headerLevels.length;
5163
5252
  headerLevels.length = level;
@@ -5188,15 +5277,7 @@ var buildDecorations2 = (view, options, focus2) => {
5188
5277
  listLevels.pop();
5189
5278
  };
5190
5279
  const getCurrentListLevel = () => {
5191
- invariant4(listLevels.length, void 0, {
5192
- F: __dxlog_file12,
5193
- L: 201,
5194
- S: void 0,
5195
- A: [
5196
- "listLevels.length",
5197
- ""
5198
- ]
5199
- });
5280
+ invariant4(listLevels.length, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file12, L: 192, S: void 0, A: ["listLevels.length", ""] });
5200
5281
  return listLevels[listLevels.length - 1];
5201
5282
  };
5202
5283
  const enterNode = (node) => {
@@ -5234,7 +5315,7 @@ var buildDecorations2 = (view, options, focus2) => {
5234
5315
  deco: hide
5235
5316
  });
5236
5317
  } else {
5237
- const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + " ";
5318
+ const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + "). ";
5238
5319
  if (num.length) {
5239
5320
  atomicDecoRanges.push({
5240
5321
  from: mark.from,
@@ -5417,11 +5498,11 @@ var buildDecorations2 = (view, options, focus2) => {
5417
5498
  }
5418
5499
  decoRanges.push({
5419
5500
  from: marks[0].to,
5420
- to: marks[1].from,
5501
+ to: !editing && options.renderLinkButton ? node.to : marks[1].from,
5421
5502
  deco: Decoration11.mark({
5422
5503
  tagName: "a",
5423
5504
  attributes: {
5424
- class: "cm-link",
5505
+ class: options.renderLinkButton ? "cm-link cm-link-with-button" : "cm-link",
5425
5506
  href: url,
5426
5507
  rel: "noreferrer",
5427
5508
  target: "_blank"
@@ -5499,18 +5580,21 @@ var buildDecorations2 = (view, options, focus2) => {
5499
5580
  deco.add(from, to, d);
5500
5581
  }
5501
5582
  const atomicDeco = new RangeSetBuilder5();
5502
- for (const { from, to, deco: d } of atomicDecoRanges) {
5503
- atomicDeco.add(from, to, d);
5583
+ for (const { from, to, deco: deco2 } of atomicDecoRanges) {
5584
+ if (from < to && state.doc.lineAt(from).number !== state.doc.lineAt(to).number) {
5585
+ continue;
5586
+ }
5587
+ atomicDeco.add(from, to, deco2);
5504
5588
  }
5505
5589
  return {
5506
5590
  deco: deco.finish(),
5507
5591
  atomicDeco: atomicDeco.finish()
5508
5592
  };
5509
5593
  };
5510
- var forceUpdate = StateEffect6.define();
5594
+ var forceUpdate = StateEffect7.define();
5511
5595
  var decorateMarkdown = (options = {}) => {
5512
5596
  return [
5513
- ViewPlugin14.fromClass(class {
5597
+ ViewPlugin15.fromClass(class {
5514
5598
  deco;
5515
5599
  atomicDeco;
5516
5600
  pendingUpdate;
@@ -5545,9 +5629,9 @@ var decorateMarkdown = (options = {}) => {
5545
5629
  }
5546
5630
  }, {
5547
5631
  provide: (plugin) => [
5548
- Prec4.low(EditorView23.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration11.none)),
5549
- EditorView23.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none),
5550
- EditorView23.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none)
5632
+ Prec4.low(EditorView24.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration11.none)),
5633
+ EditorView24.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none),
5634
+ EditorView24.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none)
5551
5635
  ]
5552
5636
  }),
5553
5637
  image(),
@@ -5615,12 +5699,7 @@ var mention = ({ debug, onSearch }) => {
5615
5699
  (context) => {
5616
5700
  log9.info("completion context", {
5617
5701
  context
5618
- }, {
5619
- F: __dxlog_file13,
5620
- L: 27,
5621
- S: void 0,
5622
- C: (f, a) => f(...a)
5623
- });
5702
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file13, L: 18, S: void 0 });
5624
5703
  const match = context.matchBefore(/@(\w+)?/);
5625
5704
  if (!match || match.from === match.to && !context.explicit) {
5626
5705
  return null;
@@ -5637,8 +5716,8 @@ var mention = ({ debug, onSearch }) => {
5637
5716
  };
5638
5717
 
5639
5718
  // src/extensions/modal.ts
5640
- import { StateEffect as StateEffect7, StateField as StateField9 } from "@codemirror/state";
5641
- var modalStateEffect = StateEffect7.define();
5719
+ import { StateEffect as StateEffect8, StateField as StateField9 } from "@codemirror/state";
5720
+ var modalStateEffect = StateEffect8.define();
5642
5721
  var modalStateField = StateField9.define({
5643
5722
  create: () => false,
5644
5723
  update: (value, tr) => {
@@ -5853,15 +5932,7 @@ var outlinerTree = (_options = {}) => {
5853
5932
  break;
5854
5933
  }
5855
5934
  case "BulletList": {
5856
- invariant5(current, void 0, {
5857
- F: __dxlog_file14,
5858
- L: 219,
5859
- S: void 0,
5860
- A: [
5861
- "current",
5862
- ""
5863
- ]
5864
- });
5935
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 169, S: void 0, A: ["current", ""] });
5865
5936
  parent = current;
5866
5937
  if (current) {
5867
5938
  current.lineRange.to = current.node.from;
@@ -5870,15 +5941,7 @@ var outlinerTree = (_options = {}) => {
5870
5941
  break;
5871
5942
  }
5872
5943
  case "ListItem": {
5873
- invariant5(parent, void 0, {
5874
- F: __dxlog_file14,
5875
- L: 228,
5876
- S: void 0,
5877
- A: [
5878
- "parent",
5879
- ""
5880
- ]
5881
- });
5944
+ invariant5(parent, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 179, S: void 0, A: ["parent", ""] });
5882
5945
  const nextSibling = node.node.nextSibling ?? node.node.parent?.nextSibling;
5883
5946
  const docRange = {
5884
5947
  from: state.doc.lineAt(node.from).from,
@@ -5912,42 +5975,18 @@ var outlinerTree = (_options = {}) => {
5912
5975
  break;
5913
5976
  }
5914
5977
  case "ListMark": {
5915
- invariant5(current, void 0, {
5916
- F: __dxlog_file14,
5917
- L: 272,
5918
- S: void 0,
5919
- A: [
5920
- "current",
5921
- ""
5922
- ]
5923
- });
5978
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 219, S: void 0, A: ["current", ""] });
5924
5979
  current.type = "bullet";
5925
5980
  current.contentRange.from = node.from + "- ".length;
5926
5981
  break;
5927
5982
  }
5928
5983
  case "Task": {
5929
- invariant5(current, void 0, {
5930
- F: __dxlog_file14,
5931
- L: 278,
5932
- S: void 0,
5933
- A: [
5934
- "current",
5935
- ""
5936
- ]
5937
- });
5984
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 226, S: void 0, A: ["current", ""] });
5938
5985
  current.type = "task";
5939
5986
  break;
5940
5987
  }
5941
5988
  case "TaskMarker": {
5942
- invariant5(current, void 0, {
5943
- F: __dxlog_file14,
5944
- L: 283,
5945
- S: void 0,
5946
- A: [
5947
- "current",
5948
- ""
5949
- ]
5950
- });
5989
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 232, S: void 0, A: ["current", ""] });
5951
5990
  current.contentRange.from = node.from + "[ ] ".length;
5952
5991
  break;
5953
5992
  }
@@ -5955,29 +5994,13 @@ var outlinerTree = (_options = {}) => {
5955
5994
  },
5956
5995
  leave: (node) => {
5957
5996
  if (node.name === "BulletList") {
5958
- invariant5(parent, void 0, {
5959
- F: __dxlog_file14,
5960
- L: 291,
5961
- S: void 0,
5962
- A: [
5963
- "parent",
5964
- ""
5965
- ]
5966
- });
5997
+ invariant5(parent, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 240, S: void 0, A: ["parent", ""] });
5967
5998
  prevSiblings[level--] = void 0;
5968
5999
  parent = parent.parent;
5969
6000
  }
5970
6001
  }
5971
6002
  });
5972
- invariant5(tree, void 0, {
5973
- F: __dxlog_file14,
5974
- L: 298,
5975
- S: void 0,
5976
- A: [
5977
- "tree",
5978
- ""
5979
- ]
5980
- });
6003
+ invariant5(tree, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 246, S: void 0, A: ["tree", ""] });
5981
6004
  return tree;
5982
6005
  };
5983
6006
  return [
@@ -6262,17 +6285,17 @@ var commands = () => keymap11.of([
6262
6285
 
6263
6286
  // src/extensions/outliner/outliner.ts
6264
6287
  import { Prec as Prec5 } from "@codemirror/state";
6265
- import { Decoration as Decoration12, EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6266
- import { mx as mx7 } from "@dxos/ui-theme";
6288
+ import { Decoration as Decoration12, EditorView as EditorView26, ViewPlugin as ViewPlugin18 } from "@codemirror/view";
6289
+ import { mx as mx6 } from "@dxos/ui-theme";
6267
6290
 
6268
6291
  // src/extensions/outliner/editor.ts
6269
6292
  import { EditorSelection as EditorSelection4, EditorState as EditorState2 } from "@codemirror/state";
6270
- import { ViewPlugin as ViewPlugin15 } from "@codemirror/view";
6293
+ import { ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6271
6294
  import { log as log10 } from "@dxos/log";
6272
6295
  var __dxlog_file15 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/outliner/editor.ts";
6273
6296
  var LIST_ITEM_REGEX = /^\s*- (\[ \]|\[x\])? /;
6274
6297
  var initialize = () => {
6275
- return ViewPlugin15.fromClass(class {
6298
+ return ViewPlugin16.fromClass(class {
6276
6299
  constructor(view) {
6277
6300
  const first = view.state.doc.lineAt(0);
6278
6301
  const text = view.state.sliceDoc(first.from, first.to);
@@ -6419,35 +6442,20 @@ var editor = () => [
6419
6442
  text: insert.toString(),
6420
6443
  length: insert.length
6421
6444
  }
6422
- }, {
6423
- F: __dxlog_file15,
6424
- L: 164,
6425
- S: void 0,
6426
- C: (f, a) => f(...a)
6427
- });
6445
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 174, S: void 0 });
6428
6446
  }
6429
6447
  });
6430
6448
  if (changes.length > 0) {
6431
6449
  log10("modified,", {
6432
6450
  changes
6433
- }, {
6434
- F: __dxlog_file15,
6435
- L: 175,
6436
- S: void 0,
6437
- C: (f, a) => f(...a)
6438
- });
6451
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 196, S: void 0 });
6439
6452
  return [
6440
6453
  {
6441
6454
  changes
6442
6455
  }
6443
6456
  ];
6444
6457
  } else if (cancel) {
6445
- log10("cancel", void 0, {
6446
- F: __dxlog_file15,
6447
- L: 178,
6448
- S: void 0,
6449
- C: (f, a) => f(...a)
6450
- });
6458
+ log10("cancel", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 205, S: void 0 });
6451
6459
  return [];
6452
6460
  }
6453
6461
  return tr;
@@ -6455,10 +6463,10 @@ var editor = () => [
6455
6463
  ];
6456
6464
 
6457
6465
  // src/extensions/outliner/menu.ts
6458
- import { EditorView as EditorView24, ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6466
+ import { EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6459
6467
  import { addEventListener as addEventListener2 } from "@dxos/async";
6460
6468
  var menu = (options = {}) => [
6461
- ViewPlugin16.fromClass(class {
6469
+ ViewPlugin17.fromClass(class {
6462
6470
  view;
6463
6471
  tag;
6464
6472
  rafId;
@@ -6520,7 +6528,7 @@ var menu = (options = {}) => [
6520
6528
  this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
6521
6529
  }
6522
6530
  }),
6523
- EditorView24.theme({
6531
+ EditorView25.theme({
6524
6532
  ".cm-popover-trigger": {
6525
6533
  position: "fixed",
6526
6534
  padding: "0",
@@ -6556,12 +6564,12 @@ var outliner = (_options = {}) => [
6556
6564
  listPaddingLeft: 8
6557
6565
  }),
6558
6566
  // Researve space for menu.
6559
- EditorView25.contentAttributes.of({
6567
+ EditorView26.contentAttributes.of({
6560
6568
  class: "w-full !mr-[3rem]"
6561
6569
  })
6562
6570
  ];
6563
6571
  var decorations = () => [
6564
- ViewPlugin17.fromClass(class {
6572
+ ViewPlugin18.fromClass(class {
6565
6573
  decorations = Decoration12.none;
6566
6574
  constructor(view) {
6567
6575
  this.updateDecorations(view.state, view);
@@ -6586,7 +6594,7 @@ var decorations = () => [
6586
6594
  const lineTo = doc.lineAt(item.contentRange.to);
6587
6595
  const isSelected = selection.includes(item.index) || item === current;
6588
6596
  decorations2.push(Decoration12.line({
6589
- class: mx7("cm-list-item", lineFrom.number === line.number && "cm-list-item-start", lineTo.number === line.number && "cm-list-item-end", isSelected && (hasFocus ? "cm-list-item-focused" : "cm-list-item-selected"))
6597
+ class: mx6("cm-list-item", lineFrom.number === line.number && "cm-list-item-start", lineTo.number === line.number && "cm-list-item-end", isSelected && (hasFocus ? "cm-list-item-focused" : "cm-list-item-selected"))
6590
6598
  }).range(line.from, line.from));
6591
6599
  }
6592
6600
  }
@@ -6596,7 +6604,7 @@ var decorations = () => [
6596
6604
  decorations: (v) => v.decorations
6597
6605
  }),
6598
6606
  // Theme.
6599
- EditorView25.theme(Object.assign({
6607
+ EditorView26.theme(Object.assign({
6600
6608
  ".cm-list-item": {
6601
6609
  borderLeftWidth: "1px",
6602
6610
  borderRightWidth: "1px",
@@ -6631,28 +6639,57 @@ var decorations = () => [
6631
6639
 
6632
6640
  // src/extensions/preview/preview.ts
6633
6641
  import { syntaxTree as syntaxTree10 } from "@codemirror/language";
6634
- import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField11 } from "@codemirror/state";
6635
- import { Decoration as Decoration13, EditorView as EditorView26, WidgetType as WidgetType8 } from "@codemirror/view";
6642
+ import { RangeSetBuilder as RangeSetBuilder6, StateEffect as StateEffect9, StateField as StateField11 } from "@codemirror/state";
6643
+ import { Decoration as Decoration13, EditorView as EditorView27, ViewPlugin as ViewPlugin19, WidgetType as WidgetType8 } from "@codemirror/view";
6644
+ import { DXN, Entity } from "@dxos/echo";
6645
+ var labelResolvedEffect = StateEffect9.define();
6636
6646
  var preview = (options = {}) => {
6647
+ const viewRef = {
6648
+ current: void 0
6649
+ };
6637
6650
  return [
6638
6651
  // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
6639
6652
  // "Block decorations may not be specified via plugins".
6640
6653
  StateField11.define({
6641
- create: (state) => buildDecorations3(state, options),
6654
+ create: (state) => buildDecorations3(state, options, viewRef),
6642
6655
  update: (decorations2, tr) => {
6643
- if (tr.docChanged) {
6644
- return buildDecorations3(tr.state, options);
6656
+ if (tr.docChanged || tr.effects.some((effect) => effect.is(labelResolvedEffect))) {
6657
+ return buildDecorations3(tr.state, options, viewRef);
6645
6658
  }
6646
6659
  return decorations2.map(tr.changes);
6647
6660
  },
6648
6661
  provide: (field) => [
6649
- EditorView26.decorations.from(field),
6650
- EditorView26.atomicRanges.of((view) => view.state.field(field))
6662
+ EditorView27.decorations.from(field),
6663
+ EditorView27.atomicRanges.of((view) => view.state.field(field))
6651
6664
  ]
6665
+ }),
6666
+ ViewPlugin19.define((view) => {
6667
+ viewRef.current = view;
6668
+ return {
6669
+ destroy() {
6670
+ viewRef.current = void 0;
6671
+ }
6672
+ };
6652
6673
  })
6653
6674
  ];
6654
6675
  };
6655
- var buildDecorations3 = (state, options) => {
6676
+ var resolveLabel = (db, dxnStr, viewRef) => {
6677
+ const dxn = DXN.tryParse(dxnStr);
6678
+ if (!dxn) {
6679
+ return;
6680
+ }
6681
+ const ref = db.makeRef(dxn);
6682
+ const target = ref.target;
6683
+ if (target) {
6684
+ return Entity.getLabel(target);
6685
+ }
6686
+ void ref.tryLoad().then(() => {
6687
+ viewRef.current?.dispatch({
6688
+ effects: labelResolvedEffect.of(void 0)
6689
+ });
6690
+ });
6691
+ };
6692
+ var buildDecorations3 = (state, options, viewRef) => {
6656
6693
  const builder = new RangeSetBuilder6();
6657
6694
  syntaxTree10(state).iterate({
6658
6695
  enter: (node) => {
@@ -6664,8 +6701,13 @@ var buildDecorations3 = (state, options) => {
6664
6701
  case "Link": {
6665
6702
  const link = getLinkRef(state, node.node);
6666
6703
  if (link) {
6704
+ const resolved = options.db ? resolveLabel(options.db, link.dxn, viewRef) : void 0;
6705
+ const displayLink = resolved ? {
6706
+ ...link,
6707
+ label: resolved
6708
+ } : link;
6667
6709
  builder.add(node.from, node.to, Decoration13.replace({
6668
- widget: new PreviewInlineWidget(options, link),
6710
+ widget: new PreviewInlineWidget(options, displayLink),
6669
6711
  side: 1
6670
6712
  }));
6671
6713
  }
@@ -6757,7 +6799,7 @@ var PreviewBlockWidget = class extends WidgetType8 {
6757
6799
  };
6758
6800
 
6759
6801
  // src/extensions/replacer.ts
6760
- import { EditorView as EditorView27 } from "@codemirror/view";
6802
+ import { EditorView as EditorView28 } from "@codemirror/view";
6761
6803
  var defaultReplacements = [
6762
6804
  {
6763
6805
  input: "--",
@@ -6820,7 +6862,7 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6820
6862
  const sortedReplacements = [
6821
6863
  ...replacements
6822
6864
  ].sort((a, b) => b.input.length - a.input.length);
6823
- return EditorView27.inputHandler.of((view, from, to, insert) => {
6865
+ return EditorView28.inputHandler.of((view, from, to, insert) => {
6824
6866
  if (insert.length !== 1) {
6825
6867
  return false;
6826
6868
  }
@@ -6854,12 +6896,69 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6854
6896
  });
6855
6897
  };
6856
6898
 
6899
+ // src/extensions/snippets.ts
6900
+ import { keymap as keymap12 } from "@codemirror/view";
6901
+ var defaultItems = [
6902
+ "hello world!",
6903
+ "this is a test.",
6904
+ "this is [DXOS](https://dxos.org)"
6905
+ ];
6906
+ var snippets2 = ({ delay = 75, items = defaultItems } = {}) => {
6907
+ let timer;
6908
+ let index = 0;
6909
+ return [
6910
+ keymap12.of([
6911
+ {
6912
+ // Reset.
6913
+ key: "alt-meta-'",
6914
+ run: () => {
6915
+ clearTimeout(timer);
6916
+ index = 0;
6917
+ return true;
6918
+ }
6919
+ },
6920
+ {
6921
+ // Next snippet.
6922
+ // TODO(burdon): Press 1-9 to select snippet?
6923
+ key: "Shift-Meta-'",
6924
+ run: (view) => {
6925
+ clearTimeout(timer);
6926
+ const text = items[index++];
6927
+ if (index === items?.length) {
6928
+ index = 0;
6929
+ }
6930
+ let offset = 0;
6931
+ const insert = (delayMs = 0) => {
6932
+ timer = setTimeout(() => {
6933
+ const pos = view.state.selection.main.head;
6934
+ view.dispatch({
6935
+ changes: {
6936
+ from: pos,
6937
+ insert: text[offset++]
6938
+ },
6939
+ selection: {
6940
+ anchor: pos + 1
6941
+ }
6942
+ });
6943
+ if (offset < text.length) {
6944
+ insert(Math.random() * delay * (text[offset] === " " ? 2 : 1));
6945
+ }
6946
+ }, delayMs);
6947
+ };
6948
+ insert();
6949
+ return true;
6950
+ }
6951
+ }
6952
+ ])
6953
+ ];
6954
+ };
6955
+
6857
6956
  // src/extensions/submit.ts
6858
6957
  import { Prec as Prec6 } from "@codemirror/state";
6859
- import { keymap as keymap12 } from "@codemirror/view";
6958
+ import { keymap as keymap13 } from "@codemirror/view";
6860
6959
  var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6861
6960
  return [
6862
- Prec6.highest(keymap12.of([
6961
+ Prec6.highest(keymap13.of([
6863
6962
  {
6864
6963
  key: "Enter",
6865
6964
  preventDefault: true,
@@ -6904,6 +7003,7 @@ var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6904
7003
  // src/extensions/tags/extended-markdown.ts
6905
7004
  import { xmlLanguage } from "@codemirror/lang-xml";
6906
7005
  import { parseMixed } from "@lezer/common";
7006
+ var escapeRegExpSource = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6907
7007
  var extendedMarkdown = ({ registry } = {}) => {
6908
7008
  return [
6909
7009
  createMarkdownExtensions({
@@ -6915,13 +7015,65 @@ var extendedMarkdown = ({ registry } = {}) => {
6915
7015
  {
6916
7016
  name: "SetextHeading",
6917
7017
  parse: () => false
6918
- }
7018
+ },
7019
+ // Custom XML block parser that keeps registered tags as a single HTMLBlock
7020
+ // even when their content contains blank lines.
7021
+ ...xmlBlockParsers(registry)
6919
7022
  ]
6920
7023
  }
6921
7024
  ]
6922
7025
  })
6923
7026
  ];
6924
7027
  };
7028
+ var xmlBlockParsers = (registry) => {
7029
+ const customTags = Object.keys(registry ?? {});
7030
+ if (customTags.length === 0) {
7031
+ return [];
7032
+ }
7033
+ const tagPattern = customTags.map(escapeRegExpSource).join("|");
7034
+ const selfClosePattern = new RegExp(`^\\s*<(${tagPattern})(\\s[^>]*)?\\/>\\s*$`);
7035
+ const openPattern = new RegExp(`^\\s*<(${tagPattern})(\\s[^>]*)?\\/?>`);
7036
+ return [
7037
+ {
7038
+ name: "XMLBlock",
7039
+ before: "HTMLBlock",
7040
+ parse: (cx, line) => {
7041
+ const match = openPattern.exec(line.text);
7042
+ if (!match) {
7043
+ return false;
7044
+ }
7045
+ if (selfClosePattern.test(line.text)) {
7046
+ const end2 = cx.lineStart + line.text.length;
7047
+ cx.addElement(cx.elt("HTMLBlock", cx.lineStart, end2));
7048
+ cx.nextLine();
7049
+ return true;
7050
+ }
7051
+ if (match[0].trimEnd().endsWith("/>")) {
7052
+ return false;
7053
+ }
7054
+ const tagName = match[1];
7055
+ const closeTag = `</${tagName}>`;
7056
+ const start = cx.lineStart;
7057
+ if (line.text.includes(closeTag)) {
7058
+ cx.addElement(cx.elt("HTMLBlock", start, start + line.text.length));
7059
+ cx.nextLine();
7060
+ return true;
7061
+ }
7062
+ let end = cx.lineStart + line.text.length;
7063
+ while (cx.nextLine()) {
7064
+ end = cx.lineStart + line.text.length;
7065
+ if (line.text.includes(closeTag)) {
7066
+ cx.addElement(cx.elt("HTMLBlock", start, end));
7067
+ cx.nextLine();
7068
+ return true;
7069
+ }
7070
+ }
7071
+ cx.addElement(cx.elt("HTMLBlock", start, end));
7072
+ return true;
7073
+ }
7074
+ }
7075
+ ];
7076
+ };
6925
7077
  var mixedParser = (registry) => {
6926
7078
  const customTags = Object.keys(registry ?? {});
6927
7079
  const tagPattern = new RegExp(`<(${customTags.join("|")})`);
@@ -6955,219 +7107,793 @@ var mixedParser = (registry) => {
6955
7107
  });
6956
7108
  };
6957
7109
 
6958
- // src/extensions/tags/streamer.ts
6959
- import { StateEffect as StateEffect8, StateField as StateField12 } from "@codemirror/state";
6960
- import { Decoration as Decoration14, EditorView as EditorView28, ViewPlugin as ViewPlugin18, WidgetType as WidgetType9 } from "@codemirror/view";
6961
- import { Domino as Domino3 } from "@dxos/ui";
6962
- import { isTruthy as isTruthy4 } from "@dxos/util";
6963
- var BLINK_RATE = 2e3;
6964
- var streamer = (options = {}) => {
6965
- return [
6966
- options.cursor && cursor(),
6967
- options.fadeIn && fadeIn(typeof options.fadeIn === "object" ? options.fadeIn : {})
6968
- ].filter(isTruthy4);
6969
- };
6970
- var cursor = () => {
6971
- const hideCursor = StateEffect8.define();
6972
- const showCursor = StateField12.define({
6973
- create: () => true,
6974
- update: (value, tr) => {
7110
+ // src/extensions/tags/fader.ts
7111
+ import { StateEffect as StateEffect10, StateField as StateField12 } from "@codemirror/state";
7112
+ import { Decoration as Decoration14, EditorView as EditorView29, ViewPlugin as ViewPlugin20 } from "@codemirror/view";
7113
+ var DEFAULT_REMOVAL_DELAY = 5e3;
7114
+ var DEFAULT_COALESCE_WINDOW = 100;
7115
+ var CLEANUP_INTERVAL = 1e3;
7116
+ var fader = (options = {}) => {
7117
+ const removalDelay = DEFAULT_REMOVAL_DELAY;
7118
+ const coalesceWindow = options.coalesce ?? DEFAULT_COALESCE_WINDOW;
7119
+ let lastCount = -1;
7120
+ const log12 = (expiries) => {
7121
+ if (expiries.length !== lastCount) {
7122
+ lastCount = expiries.length;
7123
+ }
7124
+ };
7125
+ const dequeue = StateEffect10.define();
7126
+ const fadeField = StateField12.define({
7127
+ create: () => ({
7128
+ decorations: Decoration14.none,
7129
+ expiries: [],
7130
+ batchStart: 0
7131
+ }),
7132
+ update: ({ decorations: decorations2, expiries, batchStart }, tr) => {
6975
7133
  for (const effect of tr.effects) {
6976
- if (effect.is(hideCursor)) {
6977
- return false;
7134
+ if (effect.is(dequeue)) {
7135
+ const now2 = effect.value;
7136
+ let removeCount = 0;
7137
+ while (removeCount < expiries.length && expiries[removeCount] <= now2) {
7138
+ removeCount++;
7139
+ }
7140
+ if (removeCount > 0) {
7141
+ expiries = expiries.slice(removeCount);
7142
+ let skipped = 0;
7143
+ decorations2 = decorations2.update({
7144
+ filter: () => {
7145
+ if (skipped < removeCount) {
7146
+ skipped++;
7147
+ return false;
7148
+ }
7149
+ return true;
7150
+ }
7151
+ });
7152
+ }
7153
+ }
7154
+ }
7155
+ if (!tr.docChanged) {
7156
+ log12(expiries);
7157
+ return {
7158
+ decorations: decorations2,
7159
+ expiries,
7160
+ batchStart
7161
+ };
7162
+ }
7163
+ let isReset = tr.state.doc.length === 0;
7164
+ if (!isReset && tr.startState.doc.length > 0) {
7165
+ tr.changes.iterChanges((fromA, toA) => {
7166
+ if (fromA === 0 && toA === tr.startState.doc.length) {
7167
+ isReset = true;
7168
+ }
7169
+ });
7170
+ }
7171
+ if (isReset) {
7172
+ log12([]);
7173
+ return {
7174
+ decorations: Decoration14.none,
7175
+ expiries: [],
7176
+ batchStart: 0
7177
+ };
7178
+ }
7179
+ const now = Date.now();
7180
+ const add = [];
7181
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7182
+ if (toA === tr.startState.doc.length && inserted.length > 0) {
7183
+ add.push({
7184
+ from: fromB,
7185
+ to: toB
7186
+ });
7187
+ }
7188
+ });
7189
+ if (add.length > 0) {
7190
+ const canCoalesce = expiries.length > 0 && batchStart > 0 && now - batchStart < coalesceWindow;
7191
+ if (canCoalesce) {
7192
+ let lastFrom = -1;
7193
+ let lastTo = -1;
7194
+ decorations2.between(0, tr.state.doc.length, (from, to) => {
7195
+ lastFrom = from;
7196
+ lastTo = to;
7197
+ });
7198
+ if (lastFrom >= 0) {
7199
+ decorations2 = decorations2.update({
7200
+ filter: (from, to) => !(from === lastFrom && to === lastTo)
7201
+ });
7202
+ const mergedFrom = Math.min(lastFrom, add[0].from);
7203
+ const mergedTo = add[add.length - 1].to;
7204
+ decorations2 = decorations2.update({
7205
+ add: [
7206
+ Decoration14.mark({
7207
+ class: "cm-fader"
7208
+ }).range(mergedFrom, mergedTo)
7209
+ ]
7210
+ });
7211
+ expiries = [
7212
+ ...expiries.slice(0, -1),
7213
+ now + removalDelay
7214
+ ];
7215
+ }
7216
+ } else {
7217
+ batchStart = now;
7218
+ expiries = [
7219
+ ...expiries,
7220
+ now + removalDelay
7221
+ ];
7222
+ decorations2 = decorations2.update({
7223
+ add: add.map(({ from, to }) => Decoration14.mark({
7224
+ class: "cm-fader"
7225
+ }).range(from, to))
7226
+ });
7227
+ }
7228
+ }
7229
+ log12(expiries);
7230
+ return {
7231
+ decorations: decorations2,
7232
+ expiries,
7233
+ batchStart
7234
+ };
7235
+ },
7236
+ provide: (f) => EditorView29.decorations.from(f, (value) => value.decorations)
7237
+ });
7238
+ const cleanup = ViewPlugin20.fromClass(class {
7239
+ view;
7240
+ #timer;
7241
+ constructor(view) {
7242
+ this.view = view;
7243
+ this.#schedule();
7244
+ }
7245
+ update() {
7246
+ this.#schedule();
7247
+ }
7248
+ #schedule() {
7249
+ const { expiries } = this.view.state.field(fadeField);
7250
+ if (expiries.length === 0) {
7251
+ clearTimeout(this.#timer);
7252
+ this.#timer = void 0;
7253
+ return;
7254
+ }
7255
+ if (this.#timer !== void 0) {
7256
+ return;
7257
+ }
7258
+ const delay = Math.max(CLEANUP_INTERVAL, expiries[0] - Date.now());
7259
+ this.#timer = setTimeout(() => {
7260
+ this.#timer = void 0;
7261
+ this.view.dispatch({
7262
+ effects: dequeue.of(Date.now())
7263
+ });
7264
+ }, delay);
7265
+ }
7266
+ destroy() {
7267
+ clearTimeout(this.#timer);
7268
+ }
7269
+ });
7270
+ return [
7271
+ fadeField,
7272
+ cleanup,
7273
+ EditorView29.theme({
7274
+ ".cm-fader": {
7275
+ animation: "fader 1s ease-out forwards"
7276
+ },
7277
+ "@keyframes fader": {
7278
+ "0%": {
7279
+ textShadow: "0 0 16px rgba(100, 200, 255, 1), 0 0 32px rgba(100, 200, 255, 0.6)"
7280
+ },
7281
+ "100%": {}
7282
+ }
7283
+ })
7284
+ ];
7285
+ };
7286
+
7287
+ // src/extensions/tags/typewriter.ts
7288
+ import { Annotation as Annotation3, ChangeSet as ChangeSet2, EditorState as EditorState3, StateEffect as StateEffect11, StateField as StateField13 } from "@codemirror/state";
7289
+ import { Decoration as Decoration15, EditorView as EditorView30, ViewPlugin as ViewPlugin21, WidgetType as WidgetType9 } from "@codemirror/view";
7290
+ import { Domino as Domino3 } from "@dxos/ui";
7291
+ var typewriterBypass = Annotation3.define();
7292
+ var typewriterDrainingEffect = StateEffect11.define();
7293
+ var CURSOR_LINGER = 3e3;
7294
+ var FRAME_BUDGET_MS = 4;
7295
+ var CHARS_PER_FRAME = 5;
7296
+ var FLUSH_THRESHOLD = 2e3;
7297
+ var COMPACT_HEAD_THRESHOLD = 4096;
7298
+ var typewriter = (options = {}) => {
7299
+ const streamingTags = options.streamingTags ?? /* @__PURE__ */ new Set();
7300
+ const flushThreshold = options.flushThreshold ?? FLUSH_THRESHOLD;
7301
+ const frameBudgetMs = options.frameBudgetMs ?? FRAME_BUDGET_MS;
7302
+ const charsPerFrame = options.charsPerFrame ?? CHARS_PER_FRAME;
7303
+ const suppressAppend = StateEffect11.define();
7304
+ const insertChunk = StateEffect11.define();
7305
+ const bufferField = StateField13.define({
7306
+ create: () => ({
7307
+ text: "",
7308
+ head: 0,
7309
+ insertAt: 0
7310
+ }),
7311
+ update: (value, tr) => {
7312
+ let { text, head, insertAt } = value;
7313
+ for (const effect of tr.effects) {
7314
+ if (effect.is(suppressAppend)) {
7315
+ if (text.length === head) {
7316
+ insertAt = effect.value.from;
7317
+ }
7318
+ text += effect.value.text;
7319
+ }
7320
+ if (effect.is(insertChunk)) {
7321
+ head += effect.value.text.length;
7322
+ insertAt = effect.value.from + effect.value.text.length;
7323
+ if (head >= COMPACT_HEAD_THRESHOLD || head > 0 && head * 2 >= text.length) {
7324
+ text = text.slice(head);
7325
+ head = 0;
7326
+ }
6978
7327
  }
6979
7328
  }
6980
7329
  if (tr.docChanged) {
6981
- return true;
7330
+ let isReset = tr.state.doc.length === 0;
7331
+ if (!isReset && tr.startState.doc.length > 0) {
7332
+ tr.changes.iterChanges((fromA, toA) => {
7333
+ if (fromA === 0 && toA === tr.startState.doc.length) {
7334
+ isReset = true;
7335
+ }
7336
+ });
7337
+ }
7338
+ if (isReset) {
7339
+ return {
7340
+ text: "",
7341
+ head: 0,
7342
+ insertAt: 0
7343
+ };
7344
+ }
7345
+ if (!tr.effects.some((effect) => effect.is(insertChunk))) {
7346
+ insertAt = tr.changes.mapPos(Math.min(insertAt, tr.startState.doc.length));
7347
+ }
6982
7348
  }
6983
- return value;
7349
+ return {
7350
+ text,
7351
+ head,
7352
+ insertAt
7353
+ };
6984
7354
  }
6985
7355
  });
6986
- const timerPlugin = ViewPlugin18.fromClass(class {
7356
+ const filter = EditorState3.transactionFilter.of((tr) => {
7357
+ if (!tr.docChanged) {
7358
+ return tr;
7359
+ }
7360
+ if (tr.annotation(typewriterBypass) || tr.effects.some((effect) => effect.is(insertChunk))) {
7361
+ return tr;
7362
+ }
7363
+ let appendedText = "";
7364
+ let appendFrom = -1;
7365
+ let isAppendOnly = true;
7366
+ tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
7367
+ if (toA === tr.startState.doc.length && fromA === toA && inserted.length > 0) {
7368
+ appendedText += inserted.sliceString(0);
7369
+ if (appendFrom === -1) {
7370
+ appendFrom = fromA;
7371
+ }
7372
+ } else {
7373
+ isAppendOnly = false;
7374
+ }
7375
+ });
7376
+ if (!isAppendOnly || appendedText.length === 0) {
7377
+ return tr;
7378
+ }
7379
+ return {
7380
+ changes: ChangeSet2.empty(tr.startState.doc.length),
7381
+ effects: suppressAppend.of({
7382
+ from: appendFrom,
7383
+ text: appendedText
7384
+ })
7385
+ };
7386
+ });
7387
+ const drainPlugin = ViewPlugin21.fromClass(class {
6987
7388
  view;
6988
- timer;
7389
+ _raf;
7390
+ _activeStreamTag = null;
6989
7391
  constructor(view) {
6990
7392
  this.view = view;
6991
7393
  }
6992
7394
  update(update2) {
6993
- if (update2.docChanged) {
6994
- clearTimeout(this.timer);
6995
- this.timer = setTimeout(() => {
6996
- this.view.dispatch({
6997
- effects: hideCursor.of(null)
6998
- });
6999
- }, BLINK_RATE);
7395
+ const { text, head } = update2.state.field(bufferField);
7396
+ const pending = text.length - head;
7397
+ if (pending === 0) {
7398
+ this._activeStreamTag = null;
7399
+ }
7400
+ if (pending > 0 && this._raf === void 0) {
7401
+ this._start();
7000
7402
  }
7001
7403
  }
7404
+ _start() {
7405
+ queueMicrotask(() => {
7406
+ this.view.dispatch({
7407
+ effects: typewriterDrainingEffect.of(true),
7408
+ annotations: typewriterBypass.of(true)
7409
+ });
7410
+ });
7411
+ this._raf = requestAnimationFrame(this._tick);
7412
+ }
7413
+ _tick = () => {
7414
+ const { text, head, insertAt } = this.view.state.field(bufferField);
7415
+ const pending = text.length - head;
7416
+ if (pending === 0) {
7417
+ this.view.dispatch({
7418
+ effects: typewriterDrainingEffect.of(false),
7419
+ annotations: typewriterBypass.of(true)
7420
+ });
7421
+ this._raf = void 0;
7422
+ return;
7423
+ }
7424
+ if (pending > flushThreshold) {
7425
+ const chunk = text.slice(head);
7426
+ this._activeStreamTag = null;
7427
+ this.view.dispatch({
7428
+ changes: {
7429
+ from: insertAt,
7430
+ insert: chunk
7431
+ },
7432
+ effects: insertChunk.of({
7433
+ from: insertAt,
7434
+ text: chunk
7435
+ })
7436
+ });
7437
+ this._raf = requestAnimationFrame(this._tick);
7438
+ return;
7439
+ }
7440
+ const startTime = performance.now();
7441
+ let pos = head;
7442
+ let activeTag = this._activeStreamTag;
7443
+ let charsEmitted = 0;
7444
+ while (pos < text.length && performance.now() - startTime < frameBudgetMs) {
7445
+ const result = flushable(text, pos, streamingTags, activeTag);
7446
+ if (result.count === 0) {
7447
+ break;
7448
+ }
7449
+ if (charsEmitted > 0 && charsEmitted + result.count > charsPerFrame) {
7450
+ break;
7451
+ }
7452
+ if (result.enterTag) {
7453
+ activeTag = result.enterTag;
7454
+ }
7455
+ if (result.exitTag) {
7456
+ activeTag = null;
7457
+ }
7458
+ pos += result.count;
7459
+ charsEmitted += result.count;
7460
+ }
7461
+ const totalCount = pos - head;
7462
+ if (totalCount > 0) {
7463
+ const chunk = text.slice(head, head + totalCount);
7464
+ this._activeStreamTag = activeTag;
7465
+ this.view.dispatch({
7466
+ changes: {
7467
+ from: insertAt,
7468
+ insert: chunk
7469
+ },
7470
+ effects: insertChunk.of({
7471
+ from: insertAt,
7472
+ text: chunk
7473
+ })
7474
+ });
7475
+ }
7476
+ this._raf = requestAnimationFrame(this._tick);
7477
+ };
7002
7478
  destroy() {
7003
- clearTimeout(this.timer);
7479
+ if (this._raf !== void 0) {
7480
+ cancelAnimationFrame(this._raf);
7481
+ }
7004
7482
  }
7005
7483
  });
7006
- const cursorDecoration = StateField12.define({
7007
- create: () => Decoration14.none,
7008
- update: (_decorations, tr) => {
7009
- const show = tr.state.field(showCursor);
7010
- if (!show) {
7011
- return Decoration14.none;
7484
+ return [
7485
+ bufferField,
7486
+ filter,
7487
+ drainPlugin,
7488
+ options.cursor && typewriterCursor(bufferField)
7489
+ ].filter(Boolean);
7490
+ };
7491
+ var typewriterCursor = (bufferField) => {
7492
+ const hideCursor = StateEffect11.define();
7493
+ const visibilityField = StateField13.define({
7494
+ create: () => ({
7495
+ visible: false,
7496
+ insertAt: 0,
7497
+ lastNonWsAt: 0
7498
+ }),
7499
+ update: (value, tr) => {
7500
+ const { text, head, insertAt } = tr.state.field(bufferField);
7501
+ const pending = text.length - head;
7502
+ if (pending > 0) {
7503
+ let lastNonWsAt = tr.changes.mapPos(Math.min(value.lastNonWsAt, tr.startState.doc.length));
7504
+ if (tr.docChanged) {
7505
+ tr.changes.iterChanges((_fromA, _toA, _fromB, _toB, inserted) => {
7506
+ const chunk = inserted.sliceString(0);
7507
+ if (chunk.trim().length > 0) {
7508
+ lastNonWsAt = _fromB + chunk.length;
7509
+ }
7510
+ });
7511
+ }
7512
+ return {
7513
+ visible: true,
7514
+ insertAt,
7515
+ lastNonWsAt
7516
+ };
7517
+ }
7518
+ for (const effect of tr.effects) {
7519
+ if (effect.is(hideCursor)) {
7520
+ return {
7521
+ ...value,
7522
+ visible: false
7523
+ };
7524
+ }
7012
7525
  }
7013
- const endPos = tr.state.doc.length;
7014
- return Decoration14.set([
7015
- Decoration14.widget({
7526
+ return value;
7527
+ }
7528
+ });
7529
+ const decorationField = StateField13.define({
7530
+ create: () => Decoration15.none,
7531
+ update: (_decorations, tr) => {
7532
+ const { visible, insertAt, lastNonWsAt } = tr.state.field(visibilityField);
7533
+ if (!visible) {
7534
+ return Decoration15.none;
7535
+ }
7536
+ const { text, head } = tr.state.field(bufferField);
7537
+ const cursorAt = text.length > head ? insertAt : lastNonWsAt;
7538
+ const pos = Math.min(cursorAt, tr.state.doc.length);
7539
+ return Decoration15.set([
7540
+ Decoration15.widget({
7016
7541
  widget: new CursorWidget(),
7017
7542
  side: 1
7018
- }).range(endPos)
7543
+ }).range(pos)
7019
7544
  ]);
7020
7545
  },
7021
- provide: (f) => EditorView28.decorations.from(f)
7546
+ provide: (field) => EditorView30.decorations.from(field)
7547
+ });
7548
+ const timerPlugin = ViewPlugin21.fromClass(class {
7549
+ view;
7550
+ _timer;
7551
+ constructor(view) {
7552
+ this.view = view;
7553
+ }
7554
+ update(update2) {
7555
+ const { text, head } = update2.state.field(bufferField);
7556
+ const { visible } = update2.state.field(visibilityField);
7557
+ const pending = text.length - head;
7558
+ if (pending > 0) {
7559
+ clearTimeout(this._timer);
7560
+ this._timer = void 0;
7561
+ } else if (visible && this._timer === void 0) {
7562
+ this._timer = setTimeout(() => {
7563
+ this.view.dispatch({
7564
+ effects: hideCursor.of(null)
7565
+ });
7566
+ this._timer = void 0;
7567
+ }, CURSOR_LINGER);
7568
+ }
7569
+ }
7570
+ destroy() {
7571
+ clearTimeout(this._timer);
7572
+ }
7022
7573
  });
7023
7574
  return [
7024
- showCursor,
7025
- timerPlugin,
7026
- cursorDecoration
7575
+ visibilityField,
7576
+ decorationField,
7577
+ timerPlugin
7027
7578
  ];
7028
7579
  };
7029
- var CursorWidget = class extends WidgetType9 {
7580
+ var CursorWidget = class _CursorWidget extends WidgetType9 {
7581
+ // All instances are interchangeable — let CM reuse the existing DOM across drips so
7582
+ // the blink animation isn't restarted on every transaction.
7583
+ eq(other) {
7584
+ return other instanceof _CursorWidget;
7585
+ }
7030
7586
  toDOM() {
7031
- const inner = Domino3.of("span").text("\u258F").style({
7032
- animation: "blink 2s infinite"
7587
+ const inner = Domino3.of("span").text("\u2217").style({
7588
+ animation: "blink 1s infinite",
7589
+ animationDelay: "250ms"
7033
7590
  });
7034
7591
  return Domino3.of("span").style({
7035
7592
  opacity: "0.8"
7036
- }).children(inner).root;
7593
+ }).append(inner).root;
7037
7594
  }
7038
7595
  };
7039
- var fadeIn = (options = {}) => {
7040
- const FADE_IN_DURATION = 1e3;
7041
- const DEFAULT_REMOVAL_DELAY = 3e3;
7042
- const removalDelay = options.removalDelay ?? DEFAULT_REMOVAL_DELAY;
7043
- const removeDecoration = StateEffect8.define();
7044
- const fadeField = StateField12.define({
7045
- create: () => Decoration14.none,
7046
- update: (decorations2, tr) => {
7047
- let next = decorations2;
7048
- for (const effect of tr.effects) {
7049
- if (effect.is(removeDecoration)) {
7050
- const target = effect.value;
7051
- next = next.update({
7052
- filter: (from, to) => !(from === target.from && to === target.to)
7053
- });
7054
- }
7055
- }
7056
- if (!tr.docChanged) {
7057
- return next;
7596
+ var OPENING_TAG_NAME = /^<([a-zA-Z][\w-]*)/;
7597
+ var TAG_NAME_PROBE = 64;
7598
+ var escapeRegExpSource2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7599
+ var flushable = (buffer, start, streamingTags, activeStreamTag) => {
7600
+ if (start >= buffer.length) {
7601
+ return {
7602
+ count: 0
7603
+ };
7604
+ }
7605
+ if (activeStreamTag) {
7606
+ const closeTag = `</${activeStreamTag}>`;
7607
+ if (buffer.startsWith(closeTag, start)) {
7608
+ return {
7609
+ count: closeTag.length,
7610
+ exitTag: true
7611
+ };
7612
+ }
7613
+ if (buffer[start] === "<") {
7614
+ return {
7615
+ count: xmlElementLength(buffer, start)
7616
+ };
7617
+ }
7618
+ return {
7619
+ count: 1
7620
+ };
7621
+ }
7622
+ const ch = buffer[start];
7623
+ if (ch === "<") {
7624
+ const probe = buffer.slice(start, start + TAG_NAME_PROBE);
7625
+ const nameMatch = probe.match(OPENING_TAG_NAME);
7626
+ if (nameMatch && streamingTags.has(nameMatch[1])) {
7627
+ const close = buffer.indexOf(">", start);
7628
+ if (close === -1) {
7629
+ return {
7630
+ count: 0
7631
+ };
7058
7632
  }
7059
- let isReset = tr.state.doc.length === 0;
7060
- if (!isReset) {
7061
- tr.changes.iterChanges((fromA, toA) => {
7062
- if (fromA === 0 && toA === tr.startState.doc.length) {
7063
- isReset = true;
7064
- }
7065
- });
7633
+ if (buffer[close - 1] === "/") {
7634
+ return {
7635
+ count: close + 1 - start
7636
+ };
7066
7637
  }
7067
- if (isReset) {
7068
- return Decoration14.none;
7638
+ return {
7639
+ count: close + 1 - start,
7640
+ enterTag: nameMatch[1]
7641
+ };
7642
+ }
7643
+ return {
7644
+ count: xmlElementLength(buffer, start)
7645
+ };
7646
+ }
7647
+ if (ch === "!" && buffer.length > start + 1 && buffer[start + 1] === "[") {
7648
+ return {
7649
+ count: linkLength(buffer, start, start + 1)
7650
+ };
7651
+ }
7652
+ if (ch === "[") {
7653
+ return {
7654
+ count: linkLength(buffer, start, start)
7655
+ };
7656
+ }
7657
+ return {
7658
+ count: 1
7659
+ };
7660
+ };
7661
+ var xmlElementLength = (buffer, start = 0) => {
7662
+ const close = buffer.indexOf(">", start);
7663
+ if (close === -1) {
7664
+ return 0;
7665
+ }
7666
+ if (buffer[close - 1] === "/") {
7667
+ return close + 1 - start;
7668
+ }
7669
+ if (buffer[start + 1] === "/") {
7670
+ return close + 1 - start;
7671
+ }
7672
+ const probe = buffer.slice(start, start + TAG_NAME_PROBE);
7673
+ const nameMatch = probe.match(OPENING_TAG_NAME);
7674
+ if (!nameMatch) {
7675
+ return 1;
7676
+ }
7677
+ const tagName = nameMatch[1];
7678
+ let depth = 0;
7679
+ const tagPattern = new RegExp(`<(/?)${escapeRegExpSource2(tagName)}(\\s[^>]*)?>`, "g");
7680
+ tagPattern.lastIndex = start;
7681
+ let match;
7682
+ while ((match = tagPattern.exec(buffer)) !== null) {
7683
+ const isSelfClosing = match[0].endsWith("/>");
7684
+ const isClosing = match[1] === "/";
7685
+ if (isSelfClosing) {
7686
+ if (depth === 0) {
7687
+ return match.index + match[0].length - start;
7688
+ }
7689
+ } else if (isClosing) {
7690
+ depth--;
7691
+ if (depth === 0) {
7692
+ return match.index + match[0].length - start;
7069
7693
  }
7070
- const add = [];
7071
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7072
- if (fromB === 0 && toB === inserted.length) {
7694
+ } else {
7695
+ depth++;
7696
+ }
7697
+ }
7698
+ return 0;
7699
+ };
7700
+ var linkLength = (buffer, start, bracketAt) => {
7701
+ const bracketClose = buffer.indexOf("]", bracketAt + 1);
7702
+ if (bracketClose === -1) {
7703
+ return 0;
7704
+ }
7705
+ if (bracketClose + 1 >= buffer.length) {
7706
+ return 0;
7707
+ }
7708
+ if (buffer[bracketClose + 1] !== "(") {
7709
+ return 1;
7710
+ }
7711
+ const parenClose = buffer.indexOf(")", bracketClose + 2);
7712
+ if (parenClose === -1) {
7713
+ return 0;
7714
+ }
7715
+ return parenClose + 1 - start;
7716
+ };
7717
+
7718
+ // src/extensions/tags/xml-block-decoration.ts
7719
+ import { xmlLanguage as xmlLanguage2 } from "@codemirror/lang-xml";
7720
+ import { Decoration as Decoration16, ViewPlugin as ViewPlugin22 } from "@codemirror/view";
7721
+ var xmlBlockDecoration = ({ tag, lineClass, contentClass, hideTags }) => {
7722
+ const lineDecoration = lineClass ? Decoration16.line({
7723
+ class: lineClass
7724
+ }) : void 0;
7725
+ const contentDecoration = contentClass ? Decoration16.mark({
7726
+ class: contentClass
7727
+ }) : void 0;
7728
+ const hideDecoration = hideTags ? Decoration16.replace({}) : void 0;
7729
+ const buildDecorations5 = (view) => {
7730
+ const text = view.state.sliceDoc(0, view.state.doc.length);
7731
+ if (!text.includes(`<${tag}`)) {
7732
+ return Decoration16.none;
7733
+ }
7734
+ const tree = xmlLanguage2.parser.parse(text);
7735
+ const ranges = [];
7736
+ tree.iterate({
7737
+ enter: (node) => {
7738
+ if (node.type.name !== "Element") {
7073
7739
  return;
7074
7740
  }
7075
- if (toA === tr.startState.doc.length && inserted.length > 0) {
7076
- add.push(Decoration14.mark({
7077
- class: "cm-fade-in"
7078
- }).range(fromB, toB));
7741
+ const openTag = node.node.getChild("OpenTag");
7742
+ const closeTag = node.node.getChild("CloseTag") ?? node.node.getChild("MismatchedCloseTag");
7743
+ const tagNameNode = openTag?.getChild("TagName");
7744
+ if (!openTag || !tagNameNode) {
7745
+ return;
7079
7746
  }
7080
- });
7081
- return next.update({
7082
- add
7083
- });
7084
- },
7085
- provide: (f) => EditorView28.decorations.from(f)
7086
- });
7087
- const timerPlugin = ViewPlugin18.fromClass(class {
7088
- view;
7089
- // Map a simple key "from-to" to timer id.
7090
- _timers = /* @__PURE__ */ new Map();
7747
+ if (text.slice(tagNameNode.from, tagNameNode.to) !== tag) {
7748
+ return;
7749
+ }
7750
+ const contentFrom = openTag.to;
7751
+ const contentTo = closeTag?.from ?? node.node.to;
7752
+ if (hideDecoration) {
7753
+ ranges.push(hideDecoration.range(openTag.from, openTag.to));
7754
+ if (closeTag) {
7755
+ ranges.push(hideDecoration.range(closeTag.from, closeTag.to));
7756
+ }
7757
+ }
7758
+ if (contentDecoration && contentFrom < contentTo) {
7759
+ ranges.push(contentDecoration.range(contentFrom, contentTo));
7760
+ }
7761
+ if (lineDecoration && contentFrom <= view.state.doc.length) {
7762
+ let pos = contentFrom;
7763
+ while (pos <= contentTo && pos <= view.state.doc.length) {
7764
+ const line = view.state.doc.lineAt(pos);
7765
+ ranges.push(lineDecoration.range(line.from));
7766
+ if (line.to >= contentTo) {
7767
+ break;
7768
+ }
7769
+ pos = line.to + 1;
7770
+ }
7771
+ }
7772
+ }
7773
+ });
7774
+ return Decoration16.set(ranges, true);
7775
+ };
7776
+ return ViewPlugin22.fromClass(class {
7777
+ decorations;
7091
7778
  constructor(view) {
7092
- this.view = view;
7779
+ this.decorations = buildDecorations5(view);
7093
7780
  }
7094
7781
  update(update2) {
7095
- if (!update2.docChanged) {
7096
- return;
7782
+ if (update2.docChanged) {
7783
+ this.decorations = buildDecorations5(update2.view);
7097
7784
  }
7098
- update2.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7099
- if (toA !== update2.startState.doc.length || inserted.length === 0) {
7785
+ }
7786
+ }, {
7787
+ decorations: (instance) => instance.decorations
7788
+ });
7789
+ };
7790
+
7791
+ // src/extensions/tags/xml-formatting.ts
7792
+ import { xmlLanguage as xmlLanguage3 } from "@codemirror/lang-xml";
7793
+ import { Decoration as Decoration17, EditorView as EditorView31, ViewPlugin as ViewPlugin23 } from "@codemirror/view";
7794
+ var XML_TAG_NODES = /* @__PURE__ */ new Set([
7795
+ "OpenTag",
7796
+ "CloseTag",
7797
+ "SelfClosingTag",
7798
+ "MismatchedCloseTag"
7799
+ ]);
7800
+ var xmlElementMark = Decoration17.mark({
7801
+ class: "cm-xml-element"
7802
+ });
7803
+ var xmlTagMark = Decoration17.mark({
7804
+ class: "cm-xml-tag"
7805
+ });
7806
+ var xmlContentMark = Decoration17.mark({
7807
+ class: "cm-xml-content"
7808
+ });
7809
+ var xmlFormatting = ({ skip } = {}) => {
7810
+ const skipSet = skip && skip.length > 0 ? new Set(skip) : void 0;
7811
+ const buildDecorations5 = (view) => {
7812
+ const text = view.state.sliceDoc(0, view.state.doc.length);
7813
+ if (!text.includes("<")) {
7814
+ return Decoration17.none;
7815
+ }
7816
+ const tagNameAt = (node) => text.slice(node.from, node.to);
7817
+ const tree = xmlLanguage3.parser.parse(text);
7818
+ const ranges = [];
7819
+ tree.iterate({
7820
+ enter: (node) => {
7821
+ const name = node.type.name;
7822
+ if (name === "SelfClosingTag" && node.from < node.to) {
7823
+ if (skipSet) {
7824
+ const tagNameNode = node.node.getChild("TagName");
7825
+ if (tagNameNode && skipSet.has(tagNameAt(tagNameNode))) {
7826
+ return false;
7827
+ }
7828
+ }
7829
+ ranges.push(xmlElementMark.range(node.from, node.to));
7830
+ ranges.push(xmlTagMark.range(node.from, node.to));
7100
7831
  return;
7101
7832
  }
7102
- const key = `${fromB}-${toB}`;
7103
- if (this._timers.has(key)) {
7104
- clearTimeout(this._timers.get(key));
7833
+ if (XML_TAG_NODES.has(name) && node.from < node.to) {
7834
+ ranges.push(xmlTagMark.range(node.from, node.to));
7835
+ return;
7836
+ }
7837
+ if (name === "Element" && node.from < node.to) {
7838
+ const openTag = node.node.getChild("OpenTag");
7839
+ if (openTag && skipSet) {
7840
+ const tagNameNode = openTag.getChild("TagName");
7841
+ if (tagNameNode && skipSet.has(tagNameAt(tagNameNode))) {
7842
+ return false;
7843
+ }
7844
+ }
7845
+ const closeTag = node.node.getChild("CloseTag") ?? node.node.getChild("MismatchedCloseTag");
7846
+ ranges.push(xmlElementMark.range(node.from, node.to));
7847
+ if (openTag && closeTag && openTag.to < closeTag.from) {
7848
+ ranges.push(xmlContentMark.range(openTag.to, closeTag.from));
7849
+ }
7105
7850
  }
7106
- const totalDelay = FADE_IN_DURATION + removalDelay;
7107
- const id = setTimeout(() => {
7108
- this.view.dispatch({
7109
- effects: removeDecoration.of({
7110
- from: fromB,
7111
- to: toB
7112
- })
7113
- });
7114
- this._timers.delete(key);
7115
- }, totalDelay);
7116
- this._timers.set(key, id);
7117
- });
7118
- }
7119
- destroy() {
7120
- for (const id of this._timers.values()) {
7121
- clearTimeout(id);
7122
7851
  }
7123
- this._timers.clear();
7124
- }
7125
- });
7852
+ });
7853
+ return Decoration17.set(ranges, true);
7854
+ };
7126
7855
  return [
7127
- fadeField,
7128
- timerPlugin,
7129
- EditorView28.theme({
7130
- ".cm-line > span": {
7131
- opacity: "0.8"
7132
- },
7133
- ".cm-fade-in": {
7134
- animation: "fade-in 3s ease-out forwards"
7135
- },
7136
- "@keyframes fade-in": {
7137
- "0%": {
7138
- opacity: "0"
7139
- },
7140
- "80%": {
7141
- opacity: "1"
7142
- },
7143
- "100%": {
7144
- opacity: "0.8"
7856
+ ViewPlugin23.fromClass(class {
7857
+ decorations;
7858
+ constructor(view) {
7859
+ this.decorations = buildDecorations5(view);
7860
+ }
7861
+ update(update2) {
7862
+ if (update2.docChanged) {
7863
+ this.decorations = buildDecorations5(update2.view);
7145
7864
  }
7146
7865
  }
7866
+ }, {
7867
+ decorations: (instance) => instance.decorations
7868
+ }),
7869
+ EditorView31.baseTheme({
7870
+ ".cm-xml-element": {
7871
+ backgroundColor: "var(--color-active-surface)",
7872
+ borderRadius: "0.25rem",
7873
+ padding: "0.25rem"
7874
+ },
7875
+ ".cm-xml-tag": {
7876
+ color: "var(--color-blue-500)",
7877
+ fontFamily: "var(--font-mono)"
7878
+ },
7879
+ ".cm-xml-content": {}
7147
7880
  })
7148
7881
  ];
7149
7882
  };
7150
7883
 
7151
7884
  // src/extensions/tags/xml-tags.ts
7152
7885
  import { syntaxTree as syntaxTree11 } from "@codemirror/language";
7153
- import { Prec as Prec7, RangeSetBuilder as RangeSetBuilder7, StateEffect as StateEffect9, StateField as StateField13 } from "@codemirror/state";
7154
- import { Decoration as Decoration15, EditorView as EditorView29, ViewPlugin as ViewPlugin19, WidgetType as WidgetType10, keymap as keymap13 } from "@codemirror/view";
7886
+ import { Prec as Prec7, RangeSetBuilder as RangeSetBuilder7, StateEffect as StateEffect12, StateField as StateField14 } from "@codemirror/state";
7887
+ import { Decoration as Decoration18, EditorView as EditorView32, ViewPlugin as ViewPlugin24, WidgetType as WidgetType10, keymap as keymap14 } from "@codemirror/view";
7155
7888
  import { invariant as invariant7 } from "@dxos/invariant";
7156
7889
  import { log as log11 } from "@dxos/log";
7890
+ import { Domino as Domino4 } from "@dxos/ui";
7157
7891
 
7158
7892
  // src/extensions/tags/xml-util.ts
7159
7893
  import { invariant as invariant6 } from "@dxos/invariant";
7160
7894
  var __dxlog_file16 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-util.ts";
7161
7895
  var nodeToJson = (state, node) => {
7162
- invariant6(node.type.name === "Element", "Node is not an Element", {
7163
- F: __dxlog_file16,
7164
- L: 18,
7165
- S: void 0,
7166
- A: [
7167
- "node.type.name === 'Element'",
7168
- "'Node is not an Element'"
7169
- ]
7170
- });
7896
+ invariant6(node.type.name === "Element", "Node is not an Element", { "~LogMeta": "~LogMeta", F: __dxlog_file16, L: 8, S: void 0, A: ["node.type.name === 'Element'", "'Node is not an Element'"] });
7171
7897
  const openTag = node.node.getChild("OpenTag") || node.node.getChild("SelfClosingTag");
7172
7898
  if (openTag) {
7173
7899
  const tagName = openTag.getChild("TagName");
@@ -7199,13 +7925,23 @@ var nodeToJson = (state, node) => {
7199
7925
  if (node.type.name === "Element" && openTag.type.name !== "SelfClosingTag") {
7200
7926
  const children = [];
7201
7927
  let child = node.node.firstChild;
7928
+ const appendText = (raw) => {
7929
+ if (raw.length === 0) {
7930
+ return;
7931
+ }
7932
+ const last = children[children.length - 1];
7933
+ if (typeof last === "string") {
7934
+ children[children.length - 1] = last + raw;
7935
+ } else {
7936
+ children.push(raw);
7937
+ }
7938
+ };
7202
7939
  while (child) {
7203
7940
  if (child.type.name !== "OpenTag" && child.type.name !== "CloseTag") {
7204
7941
  if (child.type.name === "Text") {
7205
- const text = state.doc.sliceString(child.from, child.to).trim();
7206
- if (text) {
7207
- children.push(text);
7208
- }
7942
+ appendText(state.doc.sliceString(child.from, child.to));
7943
+ } else if (child.type.name === "EntityReference" || child.type.name === "CharacterReference") {
7944
+ appendText(decodeXmlEntity(state.doc.sliceString(child.from, child.to)));
7209
7945
  } else if (child.type.name === "Element") {
7210
7946
  const data = nodeToJson(state, child);
7211
7947
  if (data) {
@@ -7215,26 +7951,63 @@ var nodeToJson = (state, node) => {
7215
7951
  }
7216
7952
  child = child.nextSibling;
7217
7953
  }
7954
+ if (children.length > 0 && typeof children[0] === "string") {
7955
+ children[0] = children[0].trimStart();
7956
+ }
7218
7957
  if (children.length > 0) {
7219
- tag.children = children;
7958
+ const lastIndex = children.length - 1;
7959
+ const last = children[lastIndex];
7960
+ if (typeof last === "string") {
7961
+ children[lastIndex] = last.trimEnd();
7962
+ }
7963
+ }
7964
+ const trimmed = children.filter((value) => typeof value !== "string" || value.length > 0);
7965
+ if (trimmed.length > 0) {
7966
+ tag.children = trimmed;
7220
7967
  }
7221
7968
  }
7222
7969
  return tag;
7223
7970
  }
7224
7971
  };
7972
+ var XML_NAMED_ENTITIES = {
7973
+ "&lt;": "<",
7974
+ "&gt;": ">",
7975
+ "&amp;": "&",
7976
+ "&quot;": '"',
7977
+ "&apos;": "'"
7978
+ };
7979
+ var decodeXmlEntity = (raw) => {
7980
+ const named = XML_NAMED_ENTITIES[raw];
7981
+ if (named !== void 0) {
7982
+ return named;
7983
+ }
7984
+ const numeric = /^&#(x?)([0-9a-fA-F]+);$/.exec(raw);
7985
+ if (numeric) {
7986
+ const code = parseInt(numeric[2], numeric[1] ? 16 : 10);
7987
+ if (Number.isFinite(code)) {
7988
+ try {
7989
+ return String.fromCodePoint(code);
7990
+ } catch {
7991
+ }
7992
+ }
7993
+ }
7994
+ return raw;
7995
+ };
7225
7996
 
7226
7997
  // src/extensions/tags/xml-tags.ts
7227
7998
  var __dxlog_file17 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-tags.ts";
7228
- var navigatePreviousEffect = StateEffect9.define();
7229
- var navigateNextEffect = StateEffect9.define();
7999
+ var navigatePreviousEffect = StateEffect12.define();
8000
+ var navigateNextEffect = StateEffect12.define();
7230
8001
  var getXmlTextChild = (children) => {
7231
8002
  const child = children?.[0];
7232
8003
  return typeof child === "string" ? child : null;
7233
8004
  };
7234
- var xmlTagContextEffect = StateEffect9.define();
7235
- var xmlTagResetEffect = StateEffect9.define();
7236
- var xmlTagUpdateEffect = StateEffect9.define();
7237
- var widgetContextStateField = StateField13.define({
8005
+ var xmlWidgetId = (explicit, fallback) => typeof explicit === "string" && explicit.length > 0 ? explicit : fallback;
8006
+ var escapeRegExpSource3 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
8007
+ var xmlTagContextEffect = StateEffect12.define();
8008
+ var xmlTagResetEffect = StateEffect12.define();
8009
+ var xmlTagUpdateEffect = StateEffect12.define();
8010
+ var widgetContextStateField = StateField14.define({
7238
8011
  create: () => void 0,
7239
8012
  update: (value, tr) => {
7240
8013
  for (const effect of tr.effects) {
@@ -7245,7 +8018,7 @@ var widgetContextStateField = StateField13.define({
7245
8018
  return value;
7246
8019
  }
7247
8020
  });
7248
- var widgetStateMapStateField = StateField13.define({
8021
+ var widgetStateMapStateField = StateField14.define({
7249
8022
  create: () => ({}),
7250
8023
  update: (map, tr) => {
7251
8024
  for (const effect of tr.effects) {
@@ -7257,12 +8030,7 @@ var widgetStateMapStateField = StateField13.define({
7257
8030
  log11("widget updated", {
7258
8031
  id,
7259
8032
  value
7260
- }, {
7261
- F: __dxlog_file17,
7262
- L: 153,
7263
- S: void 0,
7264
- C: (f, a) => f(...a)
7265
- });
8033
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 59, S: void 0 });
7266
8034
  const state = typeof value === "function" ? value(map[id]) : value;
7267
8035
  return {
7268
8036
  ...map,
@@ -7292,12 +8060,7 @@ var createWidgetMap = (setWidgets) => {
7292
8060
  log11("widget mounted", {
7293
8061
  id: state.id,
7294
8062
  tag: state.props._tag
7295
- }, {
7296
- F: __dxlog_file17,
7297
- L: 206,
7298
- S: void 0,
7299
- C: (f, a) => f(...a)
7300
- });
8063
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 101, S: void 0 });
7301
8064
  widgets.set(state.id, state);
7302
8065
  setWidgets?.([
7303
8066
  ...widgets.values()
@@ -7308,12 +8071,7 @@ var createWidgetMap = (setWidgets) => {
7308
8071
  log11("widget unmounted", {
7309
8072
  id,
7310
8073
  tag: state?.props._tag
7311
- }, {
7312
- F: __dxlog_file17,
7313
- L: 212,
7314
- S: void 0,
7315
- C: (f, a) => f(...a)
7316
- });
8074
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 112, S: void 0 });
7317
8075
  widgets.delete(id);
7318
8076
  setWidgets?.([
7319
8077
  ...widgets.values()
@@ -7322,7 +8080,7 @@ var createWidgetMap = (setWidgets) => {
7322
8080
  };
7323
8081
  return notifier;
7324
8082
  };
7325
- var keyHandlers = keymap13.of([
8083
+ var keyHandlers = keymap14.of([
7326
8084
  {
7327
8085
  key: "Mod-ArrowUp",
7328
8086
  run: (view) => {
@@ -7343,7 +8101,7 @@ var keyHandlers = keymap13.of([
7343
8101
  }
7344
8102
  ]);
7345
8103
  var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7346
- return EditorView29.updateListener.of((update2) => {
8104
+ return EditorView32.updateListener.of((update2) => {
7347
8105
  update2.transactions.forEach((transaction) => {
7348
8106
  for (const effect of transaction.effects) {
7349
8107
  if (effect.is(navigatePreviousEffect)) {
@@ -7428,7 +8186,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7428
8186
  });
7429
8187
  });
7430
8188
  };
7431
- var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin19.fromClass(class {
8189
+ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin24.fromClass(class {
7432
8190
  update(update2) {
7433
8191
  const widgetStateMap = update2.state.field(widgetStateMapStateField);
7434
8192
  const { decorations: decorations2 } = update2.state.field(widgetDecorationsField);
@@ -7455,14 +8213,14 @@ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin1
7455
8213
  }
7456
8214
  }
7457
8215
  });
7458
- var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.define({
8216
+ var createWidgetDecorationsField = (registry = {}, notifier) => StateField14.define({
7459
8217
  create: (state) => {
7460
8218
  return buildDecorations4(state, {
7461
8219
  from: 0,
7462
8220
  to: state.doc.length
7463
8221
  }, registry, notifier);
7464
8222
  },
7465
- update: ({ from, decorations: decorations2 }, tr) => {
8223
+ update: ({ from, streamingFrom, decorations: decorations2 }, tr) => {
7466
8224
  for (const effect of tr.effects) {
7467
8225
  if (effect.is(xmlTagResetEffect)) {
7468
8226
  if (tr.docChanged) {
@@ -7473,7 +8231,7 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7473
8231
  }
7474
8232
  return {
7475
8233
  from: 0,
7476
- decorations: Decoration15.none
8234
+ decorations: Decoration18.none
7477
8235
  };
7478
8236
  }
7479
8237
  }
@@ -7484,24 +8242,23 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7484
8242
  log11("document reset", {
7485
8243
  from,
7486
8244
  to: state.doc.length
7487
- }, {
7488
- F: __dxlog_file17,
7489
- L: 374,
7490
- S: void 0,
7491
- C: (f, a) => f(...a)
7492
- });
8245
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 298, S: void 0 });
7493
8246
  return buildDecorations4(state, {
7494
8247
  from: 0,
7495
8248
  to: state.doc.length
7496
8249
  }, registry, notifier);
7497
8250
  } else {
8251
+ const rebuildFrom = streamingFrom ?? from;
7498
8252
  const result = buildDecorations4(state, {
7499
- from,
8253
+ from: rebuildFrom,
7500
8254
  to: state.doc.length
7501
8255
  }, registry, notifier);
7502
8256
  return {
7503
8257
  from: result.from,
8258
+ streamingFrom: result.streamingFrom,
7504
8259
  decorations: decorations2.update({
8260
+ // Remove old streaming decorations — they are rebuilt each tick.
8261
+ filter: (_f, _t, deco) => !deco.spec.streaming,
7505
8262
  add: decorationSetToArray(result.decorations)
7506
8263
  })
7507
8264
  };
@@ -7509,12 +8266,13 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7509
8266
  }
7510
8267
  return {
7511
8268
  from,
8269
+ streamingFrom,
7512
8270
  decorations: decorations2
7513
8271
  };
7514
8272
  },
7515
8273
  provide: (field) => [
7516
- EditorView29.decorations.from(field, (v) => v.decorations),
7517
- EditorView29.atomicRanges.of((view) => view.state.field(field).decorations || Decoration15.none)
8274
+ EditorView32.decorations.from(field, (v) => v.decorations),
8275
+ EditorView32.atomicRanges.of((view) => view.state.field(field).decorations || Decoration18.none)
7518
8276
  ]
7519
8277
  });
7520
8278
  var buildDecorations4 = (state, range, registry, notifier) => {
@@ -7525,10 +8283,11 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7525
8283
  if (!tree || tree.type.name === "Program" && tree.length === 0) {
7526
8284
  return {
7527
8285
  from: range.from,
7528
- decorations: Decoration15.none
8286
+ decorations: Decoration18.none
7529
8287
  };
7530
8288
  }
7531
8289
  let last = range.from;
8290
+ let streamingFrom;
7532
8291
  tree.iterate({
7533
8292
  from: range.from,
7534
8293
  to: range.to,
@@ -7541,21 +8300,26 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7541
8300
  if (args) {
7542
8301
  const def = registry[args._tag];
7543
8302
  if (def) {
8303
+ if (def.streaming && !node.node.getChild("CloseTag")) {
8304
+ return false;
8305
+ }
7544
8306
  const { block, factory, Component } = def;
7545
- const widgetState = args.id ? widgetStateMap[args.id] : void 0;
7546
8307
  const nodeRange = {
7547
8308
  from: node.node.from,
7548
8309
  to: node.node.to
7549
8310
  };
8311
+ const widgetId = xmlWidgetId(args.id, def.streaming ? `cm-xml-${nodeRange.from}` : `cm-xml-${nodeRange.from}-${nodeRange.to}`);
8312
+ const widgetState = widgetStateMap[widgetId];
7550
8313
  const props = {
7551
- context,
8314
+ id: widgetId,
7552
8315
  range: nodeRange,
8316
+ context,
7553
8317
  ...args,
7554
8318
  ...widgetState
7555
8319
  };
7556
- const widget = factory ? factory(props) : Component ? args.id && new PlaceholderWidget2(args.id, Component, props, notifier) : void 0;
8320
+ const widget = factory ? factory(props) ?? void 0 : Component ? new PlaceholderWidget2(widgetId, Component, props, notifier) : void 0;
7557
8321
  if (widget) {
7558
- builder.add(nodeRange.from, nodeRange.to, Decoration15.replace({
8322
+ builder.add(nodeRange.from, nodeRange.to, Decoration18.replace({
7559
8323
  widget,
7560
8324
  block,
7561
8325
  atomic: true,
@@ -7567,20 +8331,72 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7567
8331
  }
7568
8332
  }
7569
8333
  } catch (err) {
7570
- log11.catch(err, void 0, {
7571
- F: __dxlog_file17,
7572
- L: 459,
7573
- S: void 0,
7574
- C: (f, a) => f(...a)
7575
- });
8334
+ log11.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 401, S: void 0 });
7576
8335
  }
7577
8336
  return false;
7578
8337
  }
7579
8338
  }
7580
8339
  }
7581
8340
  });
8341
+ const streamingTagNames = Object.entries(registry).filter(([, def]) => def.streaming).map(([name]) => name).sort((a, b) => b.length - a.length);
8342
+ if (streamingTagNames.length > 0) {
8343
+ const tailText = state.sliceDoc(range.from, range.to);
8344
+ const streamingPattern = streamingTagNames.map(escapeRegExpSource3).join("|");
8345
+ const tagPattern = new RegExp(`<(${streamingPattern})(\\s[^>]*)?>`, "g");
8346
+ let match;
8347
+ while ((match = tagPattern.exec(tailText)) !== null) {
8348
+ const tagName = match[1];
8349
+ const closeTag = `</${tagName}>`;
8350
+ const afterOpen = match.index + match[0].length;
8351
+ if (tailText.indexOf(closeTag, afterOpen) === -1) {
8352
+ const absoluteFrom = range.from + match.index;
8353
+ const contentFrom = range.from + afterOpen;
8354
+ const innerText = state.sliceDoc(contentFrom, range.to).trim();
8355
+ const def = registry[tagName];
8356
+ const props = {
8357
+ _tag: tagName,
8358
+ context,
8359
+ range: {
8360
+ from: absoluteFrom,
8361
+ to: range.to
8362
+ },
8363
+ children: innerText ? [
8364
+ innerText
8365
+ ] : void 0
8366
+ };
8367
+ const attrPattern = /(\w+)="([^"]*)"/g;
8368
+ let attrMatch;
8369
+ while ((attrMatch = attrPattern.exec(match[0])) !== null) {
8370
+ props[attrMatch[1]] = attrMatch[2];
8371
+ }
8372
+ const widgetId = xmlWidgetId(props.id, `cm-xml-${absoluteFrom}`);
8373
+ const widgetState = widgetStateMap[widgetId];
8374
+ const mergedProps = {
8375
+ ...props,
8376
+ id: widgetId,
8377
+ ...widgetState
8378
+ };
8379
+ const widget = def.factory ? def.factory(mergedProps) ?? void 0 : def.Component ? new PlaceholderWidget2(widgetId, def.Component, mergedProps, notifier, true) : void 0;
8380
+ if (widget) {
8381
+ builder.add(absoluteFrom, range.to, Decoration18.replace({
8382
+ widget,
8383
+ block: def.block,
8384
+ atomic: true,
8385
+ inclusive: true,
8386
+ tag: tagName,
8387
+ streaming: true,
8388
+ contentFrom
8389
+ }));
8390
+ streamingFrom = absoluteFrom;
8391
+ last = absoluteFrom;
8392
+ }
8393
+ break;
8394
+ }
8395
+ }
8396
+ }
7582
8397
  return {
7583
8398
  from: last,
8399
+ streamingFrom,
7584
8400
  decorations: builder.finish()
7585
8401
  };
7586
8402
  };
@@ -7589,108 +8405,62 @@ var PlaceholderWidget2 = class extends WidgetType10 {
7589
8405
  Component;
7590
8406
  props;
7591
8407
  notifier;
7592
- _root = null;
7593
- constructor(id, Component, props, notifier) {
7594
- super(), this.id = id, this.Component = Component, this.props = props, this.notifier = notifier;
7595
- invariant7(id, void 0, {
7596
- F: __dxlog_file17,
7597
- L: 485,
7598
- S: this,
7599
- A: [
7600
- "id",
7601
- ""
7602
- ]
7603
- });
8408
+ streaming;
8409
+ #root = null;
8410
+ #view;
8411
+ constructor(id, Component, props, notifier, streaming) {
8412
+ super(), this.id = id, this.Component = Component, this.props = props, this.notifier = notifier, this.streaming = streaming;
8413
+ invariant7(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 488, S: this, A: ["id", ""] });
7604
8414
  }
7605
8415
  get root() {
7606
- return this._root;
8416
+ return this.#root;
7607
8417
  }
7608
8418
  eq(other) {
8419
+ if (this.streaming) {
8420
+ return false;
8421
+ }
7609
8422
  return this.id === other.id;
7610
8423
  }
7611
8424
  ignoreEvent() {
7612
8425
  return true;
7613
8426
  }
7614
- toDOM(_view) {
7615
- this._root = document.createElement("span");
8427
+ toDOM(view) {
8428
+ this.#view = view;
8429
+ this.#root = Domino4.of("div").classNames("min-h-[24px]").root;
8430
+ const props = Object.assign({}, this.props, {
8431
+ view
8432
+ });
8433
+ this.notifier.mounted({
8434
+ id: this.id,
8435
+ root: this.#root,
8436
+ props,
8437
+ Component: this.Component
8438
+ });
8439
+ return this.#root;
8440
+ }
8441
+ updateDOM(dom) {
8442
+ this.#root = dom;
8443
+ const props = Object.assign({}, this.props, {
8444
+ view: this.#view
8445
+ });
7616
8446
  this.notifier.mounted({
7617
8447
  id: this.id,
7618
- root: this._root,
7619
- props: this.props,
8448
+ root: this.#root,
8449
+ props,
7620
8450
  Component: this.Component
7621
8451
  });
7622
- return this._root;
8452
+ return true;
7623
8453
  }
7624
8454
  destroy(_dom) {
7625
8455
  this.notifier.unmounted(this.id);
7626
- this._root = null;
8456
+ this.#root = null;
8457
+ this.#view = void 0;
7627
8458
  }
7628
8459
  };
7629
-
7630
- // src/extensions/typewriter.ts
7631
- import { keymap as keymap14 } from "@codemirror/view";
7632
- var defaultItems = [
7633
- "hello world!",
7634
- "this is a test.",
7635
- "this is [DXOS](https://dxos.org)"
7636
- ];
7637
- var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
7638
- let t;
7639
- let idx = 0;
7640
- return [
7641
- keymap14.of([
7642
- {
7643
- // Reset.
7644
- key: "alt-meta-'",
7645
- run: () => {
7646
- clearTimeout(t);
7647
- idx = 0;
7648
- return true;
7649
- }
7650
- },
7651
- {
7652
- // Next prompt.
7653
- // TODO(burdon): Press 1-9 to select prompt?
7654
- key: "Shift-Meta-'",
7655
- run: (view) => {
7656
- clearTimeout(t);
7657
- const text = items[idx++];
7658
- if (idx === items?.length) {
7659
- idx = 0;
7660
- }
7661
- let i = 0;
7662
- const insert = (d = 0) => {
7663
- t = setTimeout(() => {
7664
- const pos = view.state.selection.main.head;
7665
- view.dispatch({
7666
- changes: {
7667
- from: pos,
7668
- insert: text[i++]
7669
- },
7670
- selection: {
7671
- anchor: pos + 1
7672
- }
7673
- });
7674
- if (i < text.length) {
7675
- insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
7676
- }
7677
- }, d);
7678
- };
7679
- insert();
7680
- return true;
7681
- }
7682
- }
7683
- ])
7684
- ];
7685
- };
7686
8460
  export {
7687
8461
  Cursor,
7688
- EditorInputMode,
7689
- EditorInputModes,
7690
- EditorState3 as EditorState,
7691
- EditorView30 as EditorView,
7692
- EditorViewMode,
7693
- EditorViewModes,
8462
+ EditorState4 as EditorState,
8463
+ EditorView33 as EditorView,
7694
8464
  Inline,
7695
8465
  InputModeExtensions,
7696
8466
  List,
@@ -7707,6 +8477,7 @@ export {
7707
8477
  addStyle,
7708
8478
  annotations,
7709
8479
  autoScroll,
8480
+ autoScrollEffect,
7710
8481
  autocomplete,
7711
8482
  automerge,
7712
8483
  awareness,
@@ -7720,6 +8491,7 @@ export {
7720
8491
  commentClickedEffect,
7721
8492
  comments,
7722
8493
  commentsState,
8494
+ compactSlots,
7723
8495
  convertTreeToJson,
7724
8496
  createBasicExtensions,
7725
8497
  createComment,
@@ -7743,12 +8515,12 @@ export {
7743
8515
  defaultThemeSlots,
7744
8516
  deleteItem,
7745
8517
  documentId,
8518
+ documentSlots,
7746
8519
  dropFile,
8520
+ editorClassNames,
7747
8521
  editorInputMode,
7748
- editorSlots,
7749
- editorWidth,
7750
- editorWithToolbarLayout,
7751
8522
  extendedMarkdown,
8523
+ fader,
7752
8524
  filterChars,
7753
8525
  flattenRect,
7754
8526
  focus,
@@ -7784,6 +8556,7 @@ export {
7784
8556
  markdownTagsExtensions,
7785
8557
  matchCompletion,
7786
8558
  mention,
8559
+ mobileSlots,
7787
8560
  modalStateEffect,
7788
8561
  modalStateField,
7789
8562
  moveItemDown,
@@ -7803,6 +8576,7 @@ export {
7803
8576
  removeList,
7804
8577
  removeStyle,
7805
8578
  replacer,
8579
+ scrollPastEnd,
7806
8580
  scrollThreadIntoView,
7807
8581
  scrollToLine,
7808
8582
  scroller,
@@ -7815,9 +8589,8 @@ export {
7815
8589
  setSelection,
7816
8590
  setStyle,
7817
8591
  singleValueFacet,
7818
- stackItemContentEditorClassNames,
8592
+ snippets2 as snippets,
7819
8593
  staticCompletion,
7820
- streamer,
7821
8594
  submit,
7822
8595
  tabbable,
7823
8596
  table,
@@ -7836,7 +8609,12 @@ export {
7836
8609
  treeFacet,
7837
8610
  typeahead,
7838
8611
  typewriter,
8612
+ typewriterBypass,
8613
+ typewriterDrainingEffect,
7839
8614
  wrapWithCatch,
8615
+ xmlBlockDecoration,
8616
+ xmlElementLength,
8617
+ xmlFormatting,
7840
8618
  xmlTagContextEffect,
7841
8619
  xmlTagResetEffect,
7842
8620
  xmlTagUpdateEffect,