@dxos/ui-editor 0.8.4-main.d05673bc65 → 0.8.4-main.fcc0d83b33

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 (150) hide show
  1. package/dist/lib/browser/index.mjs +1524 -755
  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 +1524 -754
  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 +29 -32
  100. package/src/defaults.ts +33 -20
  101. package/src/extensions/auto-scroll.ts +115 -9
  102. package/src/extensions/automerge/automerge.test.tsx +28 -8
  103. package/src/extensions/automerge/automerge.ts +2 -5
  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/snippets.ts +67 -0
  123. package/src/extensions/tags/extended-markdown.test.ts +120 -2
  124. package/src/extensions/tags/extended-markdown.ts +80 -1
  125. package/src/extensions/tags/fader.ts +195 -0
  126. package/src/extensions/tags/index.ts +4 -1
  127. package/src/extensions/tags/testing/text.md +36 -0
  128. package/src/extensions/tags/testing/text.txt +35 -0
  129. package/src/extensions/tags/typewriter.test.ts +65 -0
  130. package/src/extensions/tags/typewriter.ts +594 -0
  131. package/src/extensions/tags/xml-block-decoration.ts +123 -0
  132. package/src/extensions/tags/xml-formatting.ts +125 -0
  133. package/src/extensions/tags/xml-tags.ts +179 -31
  134. package/src/extensions/tags/xml-util.test.ts +199 -24
  135. package/src/extensions/tags/xml-util.ts +62 -5
  136. package/src/index.ts +0 -1
  137. package/src/styles/theme.ts +39 -25
  138. package/src/types/types.ts +10 -2
  139. package/src/typings.d.ts +8 -0
  140. package/src/util/cursor.ts +0 -1
  141. package/dist/lib/browser/chunk-HL3YF6WC.mjs +0 -22
  142. package/dist/lib/browser/chunk-HL3YF6WC.mjs.map +0 -7
  143. package/dist/lib/node-esm/chunk-YJZGD3LY.mjs +0 -24
  144. package/dist/lib/node-esm/chunk-YJZGD3LY.mjs.map +0 -7
  145. package/dist/types/src/extensions/tags/streamer.d.ts +0 -12
  146. package/dist/types/src/extensions/tags/streamer.d.ts.map +0 -1
  147. package/dist/types/src/extensions/typewriter.d.ts +0 -10
  148. package/dist/types/src/extensions/typewriter.d.ts.map +0 -1
  149. package/src/extensions/tags/streamer.ts +0 -243
  150. 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,14 +1120,16 @@ var automerge = (accessor) => {
1046
1120
  const value = DocAccessor.getValue(accessor);
1047
1121
  const current = this._view.state.doc.toString();
1048
1122
  if (value !== current) {
1049
- console.warn("ENABLING INITIAL SYNC -- THIS MAY BE A REGRESSION");
1050
1123
  this._view.dispatch({
1051
1124
  changes: {
1052
1125
  from: 0,
1053
1126
  to: this._view.state.doc.length,
1054
1127
  insert: value
1055
1128
  },
1056
- annotations: initialSync
1129
+ annotations: [
1130
+ initialSync,
1131
+ reconcileAnnotation.of(true)
1132
+ ]
1057
1133
  });
1058
1134
  }
1059
1135
  });
@@ -1105,10 +1181,7 @@ var awareness = (provider = dummyProvider) => {
1105
1181
  ];
1106
1182
  };
1107
1183
  var RemoteSelectionsDecorator = class {
1108
- _ctx = new Context(void 0, {
1109
- F: __dxlog_file5,
1110
- L: 80
1111
- });
1184
+ _ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 33 });
1112
1185
  _cursorConverter;
1113
1186
  _provider;
1114
1187
  _lastAnchor;
@@ -1339,10 +1412,7 @@ var SpaceAwarenessProvider = class {
1339
1412
  this._info = info;
1340
1413
  }
1341
1414
  open() {
1342
- this._ctx = new Context2(void 0, {
1343
- F: __dxlog_file6,
1344
- L: 57
1345
- });
1415
+ this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 28 });
1346
1416
  this._postTask = new DeferredTask(this._ctx, async () => {
1347
1417
  if (this._localState) {
1348
1418
  await this._messenger.postMessage(this._channel, {
@@ -1369,12 +1439,7 @@ var SpaceAwarenessProvider = class {
1369
1439
  }).catch((err) => {
1370
1440
  log5.debug("failed to query awareness", {
1371
1441
  err
1372
- }, {
1373
- F: __dxlog_file6,
1374
- L: 91,
1375
- S: this,
1376
- C: (f, a) => f(...a)
1377
- });
1442
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 57, S: this });
1378
1443
  });
1379
1444
  }
1380
1445
  close() {
@@ -1386,15 +1451,7 @@ var SpaceAwarenessProvider = class {
1386
1451
  return Array.from(this._remoteStates.values());
1387
1452
  }
1388
1453
  update(position) {
1389
- invariant(this._postTask, void 0, {
1390
- F: __dxlog_file6,
1391
- L: 106,
1392
- S: this,
1393
- A: [
1394
- "this._postTask",
1395
- ""
1396
- ]
1397
- });
1454
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 71, S: this, A: ["this._postTask", ""] });
1398
1455
  this._localState = {
1399
1456
  peerId: this._peerId,
1400
1457
  position,
@@ -1403,27 +1460,11 @@ var SpaceAwarenessProvider = class {
1403
1460
  this._postTask.schedule();
1404
1461
  }
1405
1462
  _handleQueryMessage() {
1406
- invariant(this._postTask, void 0, {
1407
- F: __dxlog_file6,
1408
- L: 117,
1409
- S: this,
1410
- A: [
1411
- "this._postTask",
1412
- ""
1413
- ]
1414
- });
1463
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 80, S: this, A: ["this._postTask", ""] });
1415
1464
  this._postTask.schedule();
1416
1465
  }
1417
1466
  _handlePostMessage(message) {
1418
- invariant(message.kind === "post", void 0, {
1419
- F: __dxlog_file6,
1420
- L: 122,
1421
- S: this,
1422
- A: [
1423
- "message.kind === 'post'",
1424
- ""
1425
- ]
1426
- });
1467
+ invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 84, S: this, A: ["message.kind === 'post'", ""] });
1427
1468
  this._remoteStates.set(message.state.peerId, message.state);
1428
1469
  this.remoteStateChange.emit();
1429
1470
  }
@@ -1552,15 +1593,7 @@ var Blaster = class {
1552
1593
  return this._node;
1553
1594
  }
1554
1595
  initialize() {
1555
- invariant2(!this._canvas && !this._ctx, void 0, {
1556
- F: __dxlog_file7,
1557
- L: 142,
1558
- S: this,
1559
- A: [
1560
- "!this._canvas && !this._ctx",
1561
- ""
1562
- ]
1563
- });
1596
+ invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
1564
1597
  this._canvas = document.createElement("canvas");
1565
1598
  this._canvas.id = "code-blast-canvas";
1566
1599
  this._canvas.style.position = "absolute";
@@ -1589,15 +1622,7 @@ var Blaster = class {
1589
1622
  }
1590
1623
  }
1591
1624
  start() {
1592
- invariant2(this._canvas && this._ctx, void 0, {
1593
- F: __dxlog_file7,
1594
- L: 181,
1595
- S: this,
1596
- A: [
1597
- "this._canvas && this._ctx",
1598
- ""
1599
- ]
1600
- });
1625
+ invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
1601
1626
  this._running = true;
1602
1627
  this.loop();
1603
1628
  }
@@ -1832,13 +1857,13 @@ var blocks = () => [
1832
1857
  ];
1833
1858
 
1834
1859
  // src/extensions/bookmarks.ts
1835
- 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";
1836
1861
  import { keymap as keymap4 } from "@codemirror/view";
1837
1862
  import { log as log6 } from "@dxos/log";
1838
1863
  var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
1839
- var addBookmark = StateEffect3.define();
1840
- var removeBookmark = StateEffect3.define();
1841
- var clearBookmarks = StateEffect3.define();
1864
+ var addBookmark = StateEffect4.define();
1865
+ var removeBookmark = StateEffect4.define();
1866
+ var clearBookmarks = StateEffect4.define();
1842
1867
  var bookmarks = () => {
1843
1868
  return [
1844
1869
  bookmarksField,
@@ -1847,12 +1872,7 @@ var bookmarks = () => {
1847
1872
  key: "Mod-ArrowUp",
1848
1873
  run: (view) => {
1849
1874
  const bookmarks2 = view.state.field(bookmarksField);
1850
- log6("up", bookmarks2, {
1851
- F: __dxlog_file8,
1852
- L: 29,
1853
- S: void 0,
1854
- C: (f, a) => f(...a)
1855
- });
1875
+ log6("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 18, S: void 0 });
1856
1876
  return true;
1857
1877
  }
1858
1878
  },
@@ -1860,12 +1880,7 @@ var bookmarks = () => {
1860
1880
  key: "Mod-ArrowDown",
1861
1881
  run: (view) => {
1862
1882
  const bookmarks2 = view.state.field(bookmarksField);
1863
- log6("down", bookmarks2, {
1864
- F: __dxlog_file8,
1865
- L: 37,
1866
- S: void 0,
1867
- C: (f, a) => f(...a)
1868
- });
1883
+ log6("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0 });
1869
1884
  return true;
1870
1885
  }
1871
1886
  }
@@ -1902,7 +1917,7 @@ var bookmarksField = StateField2.define({
1902
1917
 
1903
1918
  // src/extensions/comments.ts
1904
1919
  import { invertedEffects } from "@codemirror/commands";
1905
- import { StateEffect as StateEffect4, StateField as StateField3 } from "@codemirror/state";
1920
+ import { StateEffect as StateEffect5, StateField as StateField3 } from "@codemirror/state";
1906
1921
  import { Decoration as Decoration7, EditorView as EditorView11, ViewPlugin as ViewPlugin10, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
1907
1922
  import sortBy from "lodash.sortby";
1908
1923
  import { debounce as debounce2 } from "@dxos/async";
@@ -1930,28 +1945,12 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1930
1945
  };
1931
1946
  var createEditorStateStore = (keyPrefix) => ({
1932
1947
  getState: (id) => {
1933
- invariant3(id, void 0, {
1934
- F: __dxlog_file9,
1935
- L: 47,
1936
- S: void 0,
1937
- A: [
1938
- "id",
1939
- ""
1940
- ]
1941
- });
1948
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 26, S: void 0, A: ["id", ""] });
1942
1949
  const state = localStorage.getItem(`${keyPrefix}/${id}`);
1943
1950
  return state ? JSON.parse(state) : void 0;
1944
1951
  },
1945
1952
  setState: (id, state) => {
1946
- invariant3(id, void 0, {
1947
- F: __dxlog_file9,
1948
- L: 53,
1949
- S: void 0,
1950
- A: [
1951
- "id",
1952
- ""
1953
- ]
1954
- });
1953
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 31, S: void 0, A: ["id", ""] });
1955
1954
  localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
1956
1955
  }
1957
1956
  });
@@ -2004,9 +2003,9 @@ var selectionState = ({ getState, setState } = {}) => {
2004
2003
 
2005
2004
  // src/extensions/comments.ts
2006
2005
  var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
2007
- var setComments = StateEffect4.define();
2008
- var setSelection = StateEffect4.define();
2009
- var setCommentState = StateEffect4.define();
2006
+ var setComments = StateEffect5.define();
2007
+ var setSelection = StateEffect5.define();
2008
+ var setCommentState = StateEffect5.define();
2010
2009
  var commentsState = StateField3.define({
2011
2010
  create: (state) => ({
2012
2011
  id: state.facet(documentId),
@@ -2073,12 +2072,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2073
2072
  const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
2074
2073
  const range = comment.range;
2075
2074
  if (!range) {
2076
- log7.warn("Invalid range:", range, {
2077
- F: __dxlog_file10,
2078
- L: 140,
2079
- S: void 0,
2080
- C: (f, a) => f(...a)
2081
- });
2075
+ log7.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file10, L: 93, S: void 0 });
2082
2076
  return void 0;
2083
2077
  } else if (range.from === range.to) {
2084
2078
  return void 0;
@@ -2088,7 +2082,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2088
2082
  }).filter(isNonNullable);
2089
2083
  return Decoration7.set(decorations2);
2090
2084
  });
2091
- var commentClickedEffect = StateEffect4.define();
2085
+ var commentClickedEffect = StateEffect5.define();
2092
2086
  var handleCommentClick = EditorView11.domEventHandlers({
2093
2087
  click: (event, view) => {
2094
2088
  let target = event.target;
@@ -2191,10 +2185,10 @@ var trackPastedComments = (onUpdate) => {
2191
2185
  const { comments: comments2 } = update2.startState.field(commentsState);
2192
2186
  const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
2193
2187
  if (!exists) {
2194
- const cursor2 = Cursor.getCursorFromRange(update2.state, comment);
2188
+ const cursor = Cursor.getCursorFromRange(update2.state, comment);
2195
2189
  onUpdate({
2196
2190
  id: comment.id,
2197
- cursor: cursor2
2191
+ cursor
2198
2192
  });
2199
2193
  }
2200
2194
  }
@@ -2206,7 +2200,7 @@ var mapTrackedComment = (comment, changes) => ({
2206
2200
  from: changes.mapPos(comment.from, 1),
2207
2201
  to: changes.mapPos(comment.to, 1)
2208
2202
  });
2209
- var restoreCommentEffect = StateEffect4.define({
2203
+ var restoreCommentEffect = StateEffect5.define({
2210
2204
  map: mapTrackedComment
2211
2205
  });
2212
2206
  var createComment = (view) => {
@@ -2223,13 +2217,13 @@ var createComment = (view) => {
2223
2217
  }
2224
2218
  });
2225
2219
  }
2226
- const cursor2 = Cursor.getCursorFromRange(view.state, {
2220
+ const cursor = Cursor.getCursorFromRange(view.state, {
2227
2221
  from,
2228
2222
  to
2229
2223
  });
2230
- if (cursor2) {
2224
+ if (cursor) {
2231
2225
  options.onCreate?.({
2232
- cursor: cursor2,
2226
+ cursor,
2233
2227
  from,
2234
2228
  location: view.coordsAtPos(from)
2235
2229
  });
@@ -2470,7 +2464,7 @@ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap }
2470
2464
  import { HighlightStyle, bracketMatching, syntaxHighlighting } from "@codemirror/language";
2471
2465
  import { searchKeymap } from "@codemirror/search";
2472
2466
  import { EditorState } from "@codemirror/state";
2473
- 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";
2474
2468
  import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode";
2475
2469
  import defaultsDeep2 from "lodash.defaultsdeep";
2476
2470
  import { generateName } from "@dxos/display-name";
@@ -2482,28 +2476,28 @@ import { EditorView as EditorView13 } from "@codemirror/view";
2482
2476
  import { mx as mx3 } from "@dxos/ui-theme";
2483
2477
  var headings = {
2484
2478
  1: {
2485
- className: "text-4xl",
2486
- fontSize: "var(--text-4xl)",
2479
+ className: "text-3xl",
2480
+ fontSize: "var(--text-3xl)",
2487
2481
  lineHeight: "var(--text-4xl--line-height)"
2488
2482
  },
2489
2483
  2: {
2490
- className: "text-3xl",
2491
- fontSize: "var(--text-3xl)",
2484
+ className: "text-2xl",
2485
+ fontSize: "var(--text-2xl)",
2492
2486
  lineHeight: "var(--text-3xl--line-height)"
2493
2487
  },
2494
2488
  3: {
2495
- className: "text-2xl",
2496
- fontSize: "var(--text-2xl)",
2489
+ className: "text-xl",
2490
+ fontSize: "var(--text-xl)",
2497
2491
  lineHeight: "var(--text-2xl--line-height)"
2498
2492
  },
2499
2493
  4: {
2500
- className: "text-xl",
2501
- fontSize: "var(--text-xl)",
2494
+ className: "text-lg",
2495
+ fontSize: "var(--text-lg)",
2502
2496
  lineHeight: "var(--text-xl--line-height)"
2503
2497
  },
2504
2498
  5: {
2505
- className: "text-lg",
2506
- fontSize: "var(--text-lg)",
2499
+ className: "text-base",
2500
+ fontSize: "var(--text-base)",
2507
2501
  lineHeight: "var(--text-lg--line-height)"
2508
2502
  },
2509
2503
  6: {
@@ -2512,20 +2506,20 @@ var headings = {
2512
2506
  lineHeight: "var(--text-base--line-height)"
2513
2507
  }
2514
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';
2515
2511
  var markdownTheme = {
2516
- code: "font-mono no-underline! text-cm-code",
2517
- codeMark: "font-mono text-cm-code-mark",
2518
- mark: "opacity-50",
2512
+ code: "font-mono! cm-code-inline",
2513
+ codeMark: "font-mono! cm-code-mark",
2514
+ mark: "font-mono!",
2519
2515
  heading: (level) => ({
2520
- className: mx3(headings[level].className, "font-light text-cm-heading"),
2516
+ className: mx3(headings[level].className, "font-light text-(--color-cm-heading-number)"),
2521
2517
  color: "var(--color-cm-heading) !important",
2522
2518
  lineHeight: headings[level].lineHeight,
2523
2519
  fontSize: headings[level].fontSize,
2524
2520
  fontWeight: "100 !important"
2525
2521
  })
2526
2522
  };
2527
- var fontBody = "Inter Variable, ui-sans-serif, system-ui, sans-serif";
2528
- var fontMono = "JetBrains Mono Variable, ui-monospace, Cascadia Code, Source Code Pro, monospace";
2529
2523
  var baseTheme = EditorView13.baseTheme({
2530
2524
  /**
2531
2525
  * Outer frame.
@@ -2538,12 +2532,21 @@ var baseTheme = EditorView13.baseTheme({
2538
2532
  * Scroller
2539
2533
  */
2540
2534
  ".cm-scroller": {
2541
- 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"
2542
2539
  },
2543
2540
  ".cm-scroller::-webkit-scrollbar": {
2544
- 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"
2545
2549
  },
2546
- ".cm-scroller::-webkit-scrollbar-track": {},
2547
2550
  ".cm-scroller::-webkit-scrollbar-thumb": {
2548
2551
  background: "transparent",
2549
2552
  transition: "background 0.15s"
@@ -2557,7 +2560,6 @@ var baseTheme = EditorView13.baseTheme({
2557
2560
  */
2558
2561
  ".cm-content": {
2559
2562
  padding: "unset",
2560
- lineHeight: "24px",
2561
2563
  color: "unset"
2562
2564
  },
2563
2565
  /**
@@ -2588,9 +2590,16 @@ var baseTheme = EditorView13.baseTheme({
2588
2590
  * Line.
2589
2591
  */
2590
2592
  ".cm-line": {
2591
- lineHeight: "24px",
2593
+ lineHeight: 1.5,
2592
2594
  paddingInline: 0
2593
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
+ },
2594
2603
  ".cm-activeLine": {
2595
2604
  background: "var(--color-cm-active-line)"
2596
2605
  },
@@ -2768,10 +2777,9 @@ var editorGutter = EditorView13.theme({
2768
2777
  }
2769
2778
  });
2770
2779
  var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2771
- // Set metrics on the scroller (this is often what CM uses for layout).
2780
+ // Main content.
2772
2781
  ".cm-scroller": {
2773
- fontFamily: monospace ? fontMono : fontBody,
2774
- fontSize: "16px"
2782
+ fontFamily: monospace ? fontMono : fontBody
2775
2783
  },
2776
2784
  // Maintain defaults for UI components.
2777
2785
  ".cm-content, .cm-gutters, .cm-panel": {
@@ -2781,9 +2789,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2781
2789
  });
2782
2790
 
2783
2791
  // src/extensions/focus.ts
2784
- import { StateEffect as StateEffect5, StateField as StateField5 } from "@codemirror/state";
2792
+ import { StateEffect as StateEffect6, StateField as StateField5 } from "@codemirror/state";
2785
2793
  import { EditorView as EditorView14 } from "@codemirror/view";
2786
- var focusEffect = StateEffect5.define();
2794
+ var focusEffect = StateEffect6.define();
2787
2795
  var focusField = StateField5.define({
2788
2796
  create: () => false,
2789
2797
  update: (value, tr) => {
@@ -2811,9 +2819,32 @@ var focus = [
2811
2819
  })
2812
2820
  ];
2813
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
+
2814
2845
  // src/extensions/factories.ts
2815
2846
  var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
2816
- var tabbable = EditorView15.contentAttributes.of({
2847
+ var tabbable = EditorView16.contentAttributes.of({
2817
2848
  tabindex: "0"
2818
2849
  });
2819
2850
  var filterChars = (chars) => {
@@ -2866,13 +2897,8 @@ var createBasicExtensions = (propsProp) => {
2866
2897
  const props = defaultsDeep2({}, propsProp, defaultBasicOptions);
2867
2898
  return [
2868
2899
  // NOTE: Doesn't catch errors in keymap functions.
2869
- EditorView15.exceptionSink.of((err) => {
2870
- log8.catch(err, void 0, {
2871
- F: __dxlog_file11,
2872
- L: 131,
2873
- S: void 0,
2874
- C: (f, a) => f(...a)
2875
- });
2900
+ EditorView16.exceptionSink.of((err) => {
2901
+ log8.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file11, L: 79, S: void 0 });
2876
2902
  }),
2877
2903
  props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2878
2904
  props.bracketMatching && bracketMatching(),
@@ -2881,7 +2907,7 @@ var createBasicExtensions = (propsProp) => {
2881
2907
  props.drawSelection && drawSelection({
2882
2908
  cursorBlinkRate: 1200
2883
2909
  }),
2884
- props.editable !== void 0 && EditorView15.editable.of(props.editable),
2910
+ props.editable !== void 0 && EditorView16.editable.of(props.editable),
2885
2911
  props.focus && focus,
2886
2912
  props.highlightActiveLine && highlightActiveLine(),
2887
2913
  props.history && history(),
@@ -2889,9 +2915,16 @@ var createBasicExtensions = (propsProp) => {
2889
2915
  lineNumbers(),
2890
2916
  editorGutter
2891
2917
  ],
2892
- props.lineWrapping && EditorView15.lineWrapping,
2918
+ props.lineWrapping && EditorView16.lineWrapping,
2893
2919
  props.placeholder && placeholder2(props.placeholder),
2894
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),
2895
2928
  props.scrollPastEnd && scrollPastEnd(),
2896
2929
  props.tabbable && tabbable,
2897
2930
  props.tabSize && EditorState.tabSize.of(props.tabSize),
@@ -2934,24 +2967,29 @@ var defaultStyles = {
2934
2967
  dark: vscodeDarkStyle,
2935
2968
  light: vscodeLightStyle
2936
2969
  };
2937
- var createThemeExtensions = ({ monospace, themeMode, slots: slotsProp, syntaxHighlighting: syntaxHighlightingProp } = {}) => {
2970
+ var createThemeExtensions = ({ monospace, scrollbarThin, slots: slotsProp, syntaxHighlighting: syntaxHighlightingProp, themeMode } = {}) => {
2938
2971
  const slots = defaultsDeep2({}, slotsProp, defaultThemeSlots);
2939
2972
  return [
2940
2973
  baseTheme,
2941
- EditorView15.darkTheme.of(themeMode === "dark"),
2974
+ EditorView16.darkTheme.of(themeMode === "dark"),
2942
2975
  createFontTheme({
2943
2976
  monospace
2944
2977
  }),
2945
2978
  syntaxHighlightingProp && syntaxHighlighting(HighlightStyle.define(themeMode === "dark" ? defaultStyles.dark : defaultStyles.light)),
2946
- slots.editor?.className && EditorView15.editorAttributes.of({
2979
+ slots.editor?.className && EditorView16.editorAttributes.of({
2947
2980
  class: slots.editor.className
2948
2981
  }),
2949
- slots.content?.className && EditorView15.contentAttributes.of({
2982
+ slots.content?.className && EditorView16.contentAttributes.of({
2950
2983
  class: slots.content.className
2951
2984
  }),
2952
- slots.scroll?.className && ViewPlugin11.fromClass(class {
2985
+ (slots.scroller?.className || scrollbarThin) && ViewPlugin12.fromClass(class {
2953
2986
  constructor(view) {
2954
- 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
+ }
2955
2993
  }
2956
2994
  })
2957
2995
  ].filter(isTruthy2);
@@ -2980,7 +3018,7 @@ var createDataExtensions = ({ id, text, messenger, identity }) => {
2980
3018
 
2981
3019
  // src/extensions/folding.ts
2982
3020
  import { codeFolding, foldGutter } from "@codemirror/language";
2983
- import { EditorView as EditorView16 } from "@codemirror/view";
3021
+ import { EditorView as EditorView17 } from "@codemirror/view";
2984
3022
  import { Domino as Domino2, mx as mx4 } from "@dxos/ui";
2985
3023
  var folding = () => {
2986
3024
  return [
@@ -2988,13 +3026,14 @@ var folding = () => {
2988
3026
  placeholderDOM: () => Domino2.of("span").root
2989
3027
  }),
2990
3028
  foldGutter({
3029
+ // NOTE: We can't animate since the element is remounted on state change.
2991
3030
  markerDOM: (open) => {
2992
- 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({
2993
3032
  href: Domino2.icon("ph--caret-right--regular")
2994
3033
  }))).root;
2995
3034
  }
2996
3035
  }),
2997
- EditorView16.theme({
3036
+ EditorView17.theme({
2998
3037
  ".cm-foldGutter": {
2999
3038
  opacity: 0.3,
3000
3039
  transition: "opacity 0.3s",
@@ -3008,7 +3047,7 @@ var folding = () => {
3008
3047
  };
3009
3048
 
3010
3049
  // src/extensions/hashtag.ts
3011
- 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";
3012
3051
  import { getHashStyles, mx as mx5 } from "@dxos/ui-theme";
3013
3052
  var TagWidget = class extends WidgetType4 {
3014
3053
  _text;
@@ -3029,7 +3068,7 @@ var tagMatcher = new MatchDecorator({
3029
3068
  })
3030
3069
  });
3031
3070
  var hashtag = () => [
3032
- ViewPlugin12.fromClass(class {
3071
+ ViewPlugin13.fromClass(class {
3033
3072
  tags;
3034
3073
  constructor(view) {
3035
3074
  this.tags = tagMatcher.createDeco(view);
@@ -3039,11 +3078,11 @@ var hashtag = () => [
3039
3078
  }
3040
3079
  }, {
3041
3080
  decorations: (instance) => instance.tags,
3042
- provide: (plugin) => EditorView17.atomicRanges.of((view) => {
3081
+ provide: (plugin) => EditorView18.atomicRanges.of((view) => {
3043
3082
  return view.plugin(plugin)?.tags || Decoration8.none;
3044
3083
  })
3045
3084
  }),
3046
- EditorView17.theme({
3085
+ EditorView18.theme({
3047
3086
  ".cm-tag": {
3048
3087
  borderRadius: "4px",
3049
3088
  marginRight: "6px",
@@ -3098,18 +3137,18 @@ var schemaLinter = (validate) => (view) => {
3098
3137
  };
3099
3138
 
3100
3139
  // src/extensions/listener.ts
3101
- import { EditorView as EditorView18 } from "@codemirror/view";
3140
+ import { EditorView as EditorView19 } from "@codemirror/view";
3102
3141
  import { isNonNullable as isNonNullable2 } from "@dxos/util";
3103
3142
  var listener = ({ onFocus, onChange }) => {
3104
3143
  return [
3105
- onFocus && EditorView18.focusChangeEffect.of((state, focusing) => {
3144
+ onFocus && EditorView19.focusChangeEffect.of((state, focusing) => {
3106
3145
  onFocus({
3107
3146
  id: state.facet(documentId),
3108
3147
  focusing
3109
3148
  });
3110
3149
  return null;
3111
3150
  }),
3112
- onChange && EditorView18.updateListener.of(({ state, docChanged }) => {
3151
+ onChange && EditorView19.updateListener.of(({ state, docChanged }) => {
3113
3152
  if (docChanged) {
3114
3153
  onChange({
3115
3154
  id: state.facet(documentId),
@@ -3124,7 +3163,7 @@ var listener = ({ onFocus, onChange }) => {
3124
3163
  import { snippet } from "@codemirror/autocomplete";
3125
3164
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3126
3165
  import { EditorSelection as EditorSelection2 } from "@codemirror/state";
3127
- import { EditorView as EditorView19, keymap as keymap8 } from "@codemirror/view";
3166
+ import { EditorView as EditorView20, keymap as keymap8 } from "@codemirror/view";
3128
3167
  import { debounceAndThrottle } from "@dxos/async";
3129
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;
3130
3169
  var Inline = /* @__PURE__ */ (function(Inline2) {
@@ -4213,7 +4252,7 @@ var getFormatting = (state) => {
4213
4252
  };
4214
4253
  };
4215
4254
  var formattingListener = (onStateChange, delay = 100) => {
4216
- return EditorView19.updateListener.of(debounceAndThrottle((update2) => {
4255
+ return EditorView20.updateListener.of(debounceAndThrottle((update2) => {
4217
4256
  if (update2.docChanged || update2.selectionSet) {
4218
4257
  onStateChange(getFormatting(update2.state));
4219
4258
  }
@@ -4274,8 +4313,7 @@ import { completionKeymap } from "@codemirror/autocomplete";
4274
4313
  import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
4275
4314
  import { jsonLanguage } from "@codemirror/lang-json";
4276
4315
  import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
4277
- import { xml } from "@codemirror/lang-xml";
4278
- import { LanguageDescription, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4316
+ import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4279
4317
  import { languages } from "@codemirror/language-data";
4280
4318
  import { keymap as keymap9 } from "@codemirror/view";
4281
4319
  import { isTruthy as isTruthy3 } from "@dxos/util";
@@ -4285,11 +4323,6 @@ import { markdownLanguage } from "@codemirror/lang-markdown";
4285
4323
  import { HighlightStyle as HighlightStyle2 } from "@codemirror/language";
4286
4324
  import { Tag, styleTags, tags } from "@lezer/highlight";
4287
4325
  import { Table } from "@lezer/markdown";
4288
- var styles4 = {
4289
- code: "font-mono no-underline! text-cm-code",
4290
- codeMark: "font-mono text-cm-code-mark",
4291
- mark: "opacity-50"
4292
- };
4293
4326
  var markdownTags = {
4294
4327
  Blockquote: Tag.define(),
4295
4328
  CodeMark: Tag.define(),
@@ -4371,7 +4404,7 @@ var markdownHighlightStyle = (_options = {}) => {
4371
4404
  markdownTags.LinkReference,
4372
4405
  markdownTags.ListMark
4373
4406
  ],
4374
- class: styles4.mark
4407
+ class: markdownTheme.mark
4375
4408
  },
4376
4409
  // Markdown marks.
4377
4410
  {
@@ -4382,7 +4415,7 @@ var markdownHighlightStyle = (_options = {}) => {
4382
4415
  markdownTags.QuoteMark,
4383
4416
  markdownTags.EmphasisMark
4384
4417
  ],
4385
- class: styles4.mark
4418
+ class: markdownTheme.mark
4386
4419
  },
4387
4420
  // E.g., code block language (after ```).
4388
4421
  {
@@ -4391,7 +4424,7 @@ var markdownHighlightStyle = (_options = {}) => {
4391
4424
  tags.function(tags.variableName),
4392
4425
  tags.labelName
4393
4426
  ],
4394
- class: styles4.codeMark
4427
+ class: markdownTheme.codeMark
4395
4428
  },
4396
4429
  // Fonts.
4397
4430
  {
@@ -4457,7 +4490,7 @@ var markdownHighlightStyle = (_options = {}) => {
4457
4490
  markdownTags.CodeText,
4458
4491
  markdownTags.InlineCode
4459
4492
  ],
4460
- class: styles4.code
4493
+ class: markdownTheme.code
4461
4494
  },
4462
4495
  {
4463
4496
  tag: [
@@ -4487,15 +4520,23 @@ var createMarkdownExtensions = (options = {}) => {
4487
4520
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
4488
4521
  base: markdownLanguage2,
4489
4522
  // Languages for syntax highlighting fenced code blocks.
4523
+ // Caller-supplied languages are checked first so they can override defaults.
4490
4524
  defaultCodeLanguage: jsonLanguage,
4491
- codeLanguages: languages,
4525
+ codeLanguages: [
4526
+ ...options.codeLanguages ?? [],
4527
+ ...languages
4528
+ ],
4492
4529
  // Don't complete HTML tags.
4493
4530
  completeHTMLTags: false,
4494
4531
  // Parser extensions.
4495
4532
  extensions: [
4496
4533
  // GFM provided by default.
4497
4534
  markdownTagsExtensions,
4498
- ...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
4499
4540
  ]
4500
4541
  }),
4501
4542
  // Custom styles.
@@ -4510,18 +4551,13 @@ var createMarkdownExtensions = (options = {}) => {
4510
4551
  ].filter(isTruthy3))
4511
4552
  ];
4512
4553
  };
4513
- var xmlLanguageDesc = LanguageDescription.of({
4514
- name: "xml",
4515
- alias: [
4516
- "html",
4517
- "xhtml"
4518
- ],
4519
- extensions: [
4520
- "xml",
4521
- "xhtml"
4522
- ],
4523
- load: async () => xml()
4524
- });
4554
+ var noFencedCodeFolding = {
4555
+ props: [
4556
+ foldNodeProp.add({
4557
+ FencedCode: () => null
4558
+ })
4559
+ ]
4560
+ };
4525
4561
  var defaultExtensions = () => [
4526
4562
  noSetExtHeading,
4527
4563
  noHtml
@@ -4541,19 +4577,19 @@ var debugTree = (cb) => StateField6.define({
4541
4577
  update: (value, tr) => cb(convertTreeToJson(tr.state))
4542
4578
  });
4543
4579
  var convertTreeToJson = (state) => {
4544
- const treeToJson = (cursor2) => {
4580
+ const treeToJson = (cursor) => {
4545
4581
  const node = {
4546
- type: cursor2.type.name,
4547
- from: cursor2.from,
4548
- to: cursor2.to,
4549
- 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(),
4550
4586
  children: []
4551
4587
  };
4552
- if (cursor2.firstChild()) {
4588
+ if (cursor.firstChild()) {
4553
4589
  do {
4554
- node.children.push(treeToJson(cursor2));
4555
- } while (cursor2.nextSibling());
4556
- cursor2.parent();
4590
+ node.children.push(treeToJson(cursor));
4591
+ } while (cursor.nextSibling());
4592
+ cursor.parent();
4557
4593
  }
4558
4594
  return node;
4559
4595
  };
@@ -4562,17 +4598,16 @@ var convertTreeToJson = (state) => {
4562
4598
 
4563
4599
  // src/extensions/markdown/decorate.ts
4564
4600
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4565
- import { Prec as Prec4, RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect6 } from "@codemirror/state";
4566
- 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";
4567
4603
  import { invariant as invariant4 } from "@dxos/invariant";
4568
- import { mx as mx6 } from "@dxos/ui-theme";
4569
4604
 
4570
4605
  // src/extensions/markdown/changes.ts
4571
4606
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
4572
4607
  import { Transaction as Transaction4 } from "@codemirror/state";
4573
- import { ViewPlugin as ViewPlugin13 } from "@codemirror/view";
4608
+ import { ViewPlugin as ViewPlugin14 } from "@codemirror/view";
4574
4609
  var adjustChanges = () => {
4575
- return ViewPlugin13.fromClass(class {
4610
+ return ViewPlugin14.fromClass(class {
4576
4611
  update(update2) {
4577
4612
  const tree = syntaxTree4(update2.state);
4578
4613
  const adjustments = [];
@@ -4714,7 +4749,7 @@ var getValidUrl = (str) => {
4714
4749
  // src/extensions/markdown/image.ts
4715
4750
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4716
4751
  import { StateField as StateField7 } from "@codemirror/state";
4717
- 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";
4718
4753
  var image = (_options = {}) => {
4719
4754
  return [
4720
4755
  StateField7.define({
@@ -4725,10 +4760,10 @@ var image = (_options = {}) => {
4725
4760
  if (!tr.docChanged && !tr.selection) {
4726
4761
  return value;
4727
4762
  }
4728
- const cursor2 = tr.state.selection.main.head;
4763
+ const cursor = tr.state.selection.main.head;
4729
4764
  const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
4730
- let from = Math.min(cursor2, oldCursor);
4731
- let to = Math.max(cursor2, oldCursor);
4765
+ let from = Math.min(cursor, oldCursor);
4766
+ let to = Math.max(cursor, oldCursor);
4732
4767
  tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
4733
4768
  from = Math.min(from, fromB);
4734
4769
  to = Math.max(to, toB);
@@ -4742,19 +4777,19 @@ var image = (_options = {}) => {
4742
4777
  add: buildDecorations(tr.state, from, to)
4743
4778
  });
4744
4779
  },
4745
- provide: (field) => EditorView20.decorations.from(field)
4780
+ provide: (field) => EditorView21.decorations.from(field)
4746
4781
  })
4747
4782
  ];
4748
4783
  };
4749
4784
  var buildDecorations = (state, from, to) => {
4750
4785
  const decorations2 = [];
4751
- const cursor2 = state.selection.main.head;
4786
+ const cursor = state.selection.main.head;
4752
4787
  syntaxTree5(state).iterate({
4753
4788
  enter: (node) => {
4754
4789
  if (node.name === "Image") {
4755
4790
  const urlNode = node.node.getChild("URL");
4756
4791
  if (urlNode) {
4757
- 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);
4758
4793
  const url = state.sliceDoc(urlNode.from, urlNode.to);
4759
4794
  if (url.match(/^https?:\/\//) === null && url.match(/^file?:\/\//) === null) {
4760
4795
  return;
@@ -4802,10 +4837,10 @@ var ImageWidget = class extends WidgetType5 {
4802
4837
  };
4803
4838
 
4804
4839
  // src/extensions/markdown/styles.ts
4805
- import { EditorView as EditorView21 } from "@codemirror/view";
4840
+ import { EditorView as EditorView22 } from "@codemirror/view";
4806
4841
  var bulletListIndentationWidth = 24;
4807
4842
  var orderedListIndentationWidth = 36;
4808
- var formattingStyles = EditorView21.theme({
4843
+ var formattingStyles = EditorView22.theme({
4809
4844
  /**
4810
4845
  * Horizontal rule.
4811
4846
  */
@@ -4840,13 +4875,38 @@ var formattingStyles = EditorView21.theme({
4840
4875
  background: "var(--color-cm-codeblock)",
4841
4876
  borderLeft: "2px solid var(--color-cm-separator)",
4842
4877
  paddingLeft: "1rem",
4843
- margin: "0"
4878
+ margin: 0
4844
4879
  },
4845
4880
  /**
4846
4881
  * Code and codeblocks.
4847
4882
  */
4883
+ "& code": {
4884
+ fontFamily: fontMono,
4885
+ color: "var(--color-cm-code)",
4886
+ whiteSpace: "nowrap"
4887
+ },
4848
4888
  "& .cm-code": {
4849
- 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"
4850
4910
  },
4851
4911
  "& .cm-codeblock-line": {
4852
4912
  background: "var(--color-cm-codeblock)",
@@ -4878,16 +4938,24 @@ var formattingStyles = EditorView21.theme({
4878
4938
  */
4879
4939
  ".cm-table *": {
4880
4940
  fontFamily: fontMono,
4941
+ lineHeight: 1.5,
4881
4942
  textDecoration: "none !important"
4882
4943
  },
4883
4944
  ".cm-table-head": {
4884
4945
  padding: "2px 16px 2px 0px",
4946
+ overflowWrap: "break-word",
4947
+ whiteSpace: "pre-wrap",
4948
+ wordBreak: "keep-all",
4885
4949
  textAlign: "left",
4886
- borderBottom: "1px solid var(--color-cm-separator)",
4887
- color: "var(--color-subdued)"
4950
+ color: "var(--color-subdued)",
4951
+ borderBottom: "1px solid var(--color-cm-separator)"
4888
4952
  },
4889
4953
  ".cm-table-cell": {
4890
- 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"
4891
4959
  },
4892
4960
  /**
4893
4961
  * Image.
@@ -4903,12 +4971,12 @@ var formattingStyles = EditorView21.theme({
4903
4971
  },
4904
4972
  ".cm-image-with-loader": {
4905
4973
  display: "block",
4906
- opacity: "0",
4974
+ opacity: 0,
4907
4975
  transitionDuration: "350ms",
4908
4976
  transitionProperty: "opacity"
4909
4977
  },
4910
4978
  ".cm-image-with-loader.cm-loaded-image": {
4911
- opacity: "1"
4979
+ opacity: 1
4912
4980
  },
4913
4981
  ".cm-image-wrapper": {
4914
4982
  "grid-template-columns": "1fr",
@@ -4927,17 +4995,17 @@ var formattingStyles = EditorView21.theme({
4927
4995
  // src/extensions/markdown/table.ts
4928
4996
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4929
4997
  import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField8 } from "@codemirror/state";
4930
- 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";
4931
4999
  var table = (options = {}) => {
4932
5000
  return StateField8.define({
4933
5001
  create: (state) => update(state, options),
4934
5002
  update: (_, tr) => update(tr.state, options),
4935
- provide: (field) => EditorView22.decorations.from(field)
5003
+ provide: (field) => EditorView23.decorations.from(field)
4936
5004
  });
4937
5005
  };
4938
5006
  var update = (state, _options) => {
4939
5007
  const builder = new RangeSetBuilder4();
4940
- const cursor2 = state.selection.main.head;
5008
+ const cursor = state.selection.main.head;
4941
5009
  const tables = [];
4942
5010
  const getTable = () => tables[tables.length - 1];
4943
5011
  const getRow = () => {
@@ -4975,7 +5043,7 @@ var update = (state, _options) => {
4975
5043
  }
4976
5044
  });
4977
5045
  tables.forEach((table2) => {
4978
- const replace = state.readOnly || cursor2 < table2.from || cursor2 > table2.to;
5046
+ const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4979
5047
  if (replace) {
4980
5048
  builder.add(table2.from, table2.to, Decoration10.replace({
4981
5049
  block: true,
@@ -4989,6 +5057,26 @@ var update = (state, _options) => {
4989
5057
  });
4990
5058
  return builder.finish();
4991
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
+ };
4992
5080
  var TableWidget = class extends WidgetType6 {
4993
5081
  _table;
4994
5082
  constructor(_table) {
@@ -5008,7 +5096,7 @@ var TableWidget = class extends WidgetType6 {
5008
5096
  this._table.header?.forEach((cell) => {
5009
5097
  const th = document.createElement("th");
5010
5098
  th.setAttribute("class", "cm-table-head");
5011
- tr.appendChild(th).textContent = cell;
5099
+ renderCellContent(tr.appendChild(th), cell);
5012
5100
  });
5013
5101
  const body = table2.appendChild(document.createElement("tbody"));
5014
5102
  this._table.rows?.forEach((row) => {
@@ -5016,7 +5104,7 @@ var TableWidget = class extends WidgetType6 {
5016
5104
  row.forEach((cell) => {
5017
5105
  const td = document.createElement("td");
5018
5106
  td.setAttribute("class", "cm-table-cell");
5019
- tr2.appendChild(td).textContent = cell;
5107
+ renderCellContent(tr2.appendChild(td), cell);
5020
5108
  });
5021
5109
  });
5022
5110
  return div;
@@ -5123,10 +5211,10 @@ var fencedCodeLine = Decoration11.line({
5123
5211
  class: "cm-code cm-codeblock-line"
5124
5212
  });
5125
5213
  var fencedCodeLineFirst = Decoration11.line({
5126
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-start")
5214
+ class: "cm-code cm-codeblock-line cm-codeblock-start"
5127
5215
  });
5128
5216
  var fencedCodeLineLast = Decoration11.line({
5129
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-end")
5217
+ class: "cm-code cm-codeblock-line cm-codeblock-end"
5130
5218
  });
5131
5219
  var commentBlockLine = fencedCodeLine;
5132
5220
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -5158,15 +5246,7 @@ var buildDecorations2 = (view, options, focus2) => {
5158
5246
  const { state } = view;
5159
5247
  const headerLevels = [];
5160
5248
  const getHeaderLevels = (node, level) => {
5161
- invariant4(level > 0, void 0, {
5162
- F: __dxlog_file12,
5163
- L: 179,
5164
- S: void 0,
5165
- A: [
5166
- "level > 0",
5167
- ""
5168
- ]
5169
- });
5249
+ invariant4(level > 0, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file12, L: 160, S: void 0, A: ["level > 0", ""] });
5170
5250
  if (level > headerLevels.length) {
5171
5251
  const len = headerLevels.length;
5172
5252
  headerLevels.length = level;
@@ -5197,15 +5277,7 @@ var buildDecorations2 = (view, options, focus2) => {
5197
5277
  listLevels.pop();
5198
5278
  };
5199
5279
  const getCurrentListLevel = () => {
5200
- invariant4(listLevels.length, void 0, {
5201
- F: __dxlog_file12,
5202
- L: 201,
5203
- S: void 0,
5204
- A: [
5205
- "listLevels.length",
5206
- ""
5207
- ]
5208
- });
5280
+ invariant4(listLevels.length, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file12, L: 192, S: void 0, A: ["listLevels.length", ""] });
5209
5281
  return listLevels[listLevels.length - 1];
5210
5282
  };
5211
5283
  const enterNode = (node) => {
@@ -5243,7 +5315,7 @@ var buildDecorations2 = (view, options, focus2) => {
5243
5315
  deco: hide
5244
5316
  });
5245
5317
  } else {
5246
- 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(".") + "). ";
5247
5319
  if (num.length) {
5248
5320
  atomicDecoRanges.push({
5249
5321
  from: mark.from,
@@ -5426,11 +5498,11 @@ var buildDecorations2 = (view, options, focus2) => {
5426
5498
  }
5427
5499
  decoRanges.push({
5428
5500
  from: marks[0].to,
5429
- to: marks[1].from,
5501
+ to: !editing && options.renderLinkButton ? node.to : marks[1].from,
5430
5502
  deco: Decoration11.mark({
5431
5503
  tagName: "a",
5432
5504
  attributes: {
5433
- class: "cm-link",
5505
+ class: options.renderLinkButton ? "cm-link cm-link-with-button" : "cm-link",
5434
5506
  href: url,
5435
5507
  rel: "noreferrer",
5436
5508
  target: "_blank"
@@ -5508,18 +5580,21 @@ var buildDecorations2 = (view, options, focus2) => {
5508
5580
  deco.add(from, to, d);
5509
5581
  }
5510
5582
  const atomicDeco = new RangeSetBuilder5();
5511
- for (const { from, to, deco: d } of atomicDecoRanges) {
5512
- 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);
5513
5588
  }
5514
5589
  return {
5515
5590
  deco: deco.finish(),
5516
5591
  atomicDeco: atomicDeco.finish()
5517
5592
  };
5518
5593
  };
5519
- var forceUpdate = StateEffect6.define();
5594
+ var forceUpdate = StateEffect7.define();
5520
5595
  var decorateMarkdown = (options = {}) => {
5521
5596
  return [
5522
- ViewPlugin14.fromClass(class {
5597
+ ViewPlugin15.fromClass(class {
5523
5598
  deco;
5524
5599
  atomicDeco;
5525
5600
  pendingUpdate;
@@ -5554,9 +5629,9 @@ var decorateMarkdown = (options = {}) => {
5554
5629
  }
5555
5630
  }, {
5556
5631
  provide: (plugin) => [
5557
- Prec4.low(EditorView23.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration11.none)),
5558
- EditorView23.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none),
5559
- 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)
5560
5635
  ]
5561
5636
  }),
5562
5637
  image(),
@@ -5624,12 +5699,7 @@ var mention = ({ debug, onSearch }) => {
5624
5699
  (context) => {
5625
5700
  log9.info("completion context", {
5626
5701
  context
5627
- }, {
5628
- F: __dxlog_file13,
5629
- L: 27,
5630
- S: void 0,
5631
- C: (f, a) => f(...a)
5632
- });
5702
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file13, L: 18, S: void 0 });
5633
5703
  const match = context.matchBefore(/@(\w+)?/);
5634
5704
  if (!match || match.from === match.to && !context.explicit) {
5635
5705
  return null;
@@ -5646,8 +5716,8 @@ var mention = ({ debug, onSearch }) => {
5646
5716
  };
5647
5717
 
5648
5718
  // src/extensions/modal.ts
5649
- import { StateEffect as StateEffect7, StateField as StateField9 } from "@codemirror/state";
5650
- var modalStateEffect = StateEffect7.define();
5719
+ import { StateEffect as StateEffect8, StateField as StateField9 } from "@codemirror/state";
5720
+ var modalStateEffect = StateEffect8.define();
5651
5721
  var modalStateField = StateField9.define({
5652
5722
  create: () => false,
5653
5723
  update: (value, tr) => {
@@ -5862,15 +5932,7 @@ var outlinerTree = (_options = {}) => {
5862
5932
  break;
5863
5933
  }
5864
5934
  case "BulletList": {
5865
- invariant5(current, void 0, {
5866
- F: __dxlog_file14,
5867
- L: 219,
5868
- S: void 0,
5869
- A: [
5870
- "current",
5871
- ""
5872
- ]
5873
- });
5935
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 169, S: void 0, A: ["current", ""] });
5874
5936
  parent = current;
5875
5937
  if (current) {
5876
5938
  current.lineRange.to = current.node.from;
@@ -5879,15 +5941,7 @@ var outlinerTree = (_options = {}) => {
5879
5941
  break;
5880
5942
  }
5881
5943
  case "ListItem": {
5882
- invariant5(parent, void 0, {
5883
- F: __dxlog_file14,
5884
- L: 228,
5885
- S: void 0,
5886
- A: [
5887
- "parent",
5888
- ""
5889
- ]
5890
- });
5944
+ invariant5(parent, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 179, S: void 0, A: ["parent", ""] });
5891
5945
  const nextSibling = node.node.nextSibling ?? node.node.parent?.nextSibling;
5892
5946
  const docRange = {
5893
5947
  from: state.doc.lineAt(node.from).from,
@@ -5921,42 +5975,18 @@ var outlinerTree = (_options = {}) => {
5921
5975
  break;
5922
5976
  }
5923
5977
  case "ListMark": {
5924
- invariant5(current, void 0, {
5925
- F: __dxlog_file14,
5926
- L: 272,
5927
- S: void 0,
5928
- A: [
5929
- "current",
5930
- ""
5931
- ]
5932
- });
5978
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 219, S: void 0, A: ["current", ""] });
5933
5979
  current.type = "bullet";
5934
5980
  current.contentRange.from = node.from + "- ".length;
5935
5981
  break;
5936
5982
  }
5937
5983
  case "Task": {
5938
- invariant5(current, void 0, {
5939
- F: __dxlog_file14,
5940
- L: 278,
5941
- S: void 0,
5942
- A: [
5943
- "current",
5944
- ""
5945
- ]
5946
- });
5984
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 226, S: void 0, A: ["current", ""] });
5947
5985
  current.type = "task";
5948
5986
  break;
5949
5987
  }
5950
5988
  case "TaskMarker": {
5951
- invariant5(current, void 0, {
5952
- F: __dxlog_file14,
5953
- L: 283,
5954
- S: void 0,
5955
- A: [
5956
- "current",
5957
- ""
5958
- ]
5959
- });
5989
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 232, S: void 0, A: ["current", ""] });
5960
5990
  current.contentRange.from = node.from + "[ ] ".length;
5961
5991
  break;
5962
5992
  }
@@ -5964,29 +5994,13 @@ var outlinerTree = (_options = {}) => {
5964
5994
  },
5965
5995
  leave: (node) => {
5966
5996
  if (node.name === "BulletList") {
5967
- invariant5(parent, void 0, {
5968
- F: __dxlog_file14,
5969
- L: 291,
5970
- S: void 0,
5971
- A: [
5972
- "parent",
5973
- ""
5974
- ]
5975
- });
5997
+ invariant5(parent, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 240, S: void 0, A: ["parent", ""] });
5976
5998
  prevSiblings[level--] = void 0;
5977
5999
  parent = parent.parent;
5978
6000
  }
5979
6001
  }
5980
6002
  });
5981
- invariant5(tree, void 0, {
5982
- F: __dxlog_file14,
5983
- L: 298,
5984
- S: void 0,
5985
- A: [
5986
- "tree",
5987
- ""
5988
- ]
5989
- });
6003
+ invariant5(tree, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 246, S: void 0, A: ["tree", ""] });
5990
6004
  return tree;
5991
6005
  };
5992
6006
  return [
@@ -6271,17 +6285,17 @@ var commands = () => keymap11.of([
6271
6285
 
6272
6286
  // src/extensions/outliner/outliner.ts
6273
6287
  import { Prec as Prec5 } from "@codemirror/state";
6274
- import { Decoration as Decoration12, EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6275
- 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";
6276
6290
 
6277
6291
  // src/extensions/outliner/editor.ts
6278
6292
  import { EditorSelection as EditorSelection4, EditorState as EditorState2 } from "@codemirror/state";
6279
- import { ViewPlugin as ViewPlugin15 } from "@codemirror/view";
6293
+ import { ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6280
6294
  import { log as log10 } from "@dxos/log";
6281
6295
  var __dxlog_file15 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/outliner/editor.ts";
6282
6296
  var LIST_ITEM_REGEX = /^\s*- (\[ \]|\[x\])? /;
6283
6297
  var initialize = () => {
6284
- return ViewPlugin15.fromClass(class {
6298
+ return ViewPlugin16.fromClass(class {
6285
6299
  constructor(view) {
6286
6300
  const first = view.state.doc.lineAt(0);
6287
6301
  const text = view.state.sliceDoc(first.from, first.to);
@@ -6428,35 +6442,20 @@ var editor = () => [
6428
6442
  text: insert.toString(),
6429
6443
  length: insert.length
6430
6444
  }
6431
- }, {
6432
- F: __dxlog_file15,
6433
- L: 164,
6434
- S: void 0,
6435
- C: (f, a) => f(...a)
6436
- });
6445
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 174, S: void 0 });
6437
6446
  }
6438
6447
  });
6439
6448
  if (changes.length > 0) {
6440
6449
  log10("modified,", {
6441
6450
  changes
6442
- }, {
6443
- F: __dxlog_file15,
6444
- L: 175,
6445
- S: void 0,
6446
- C: (f, a) => f(...a)
6447
- });
6451
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 196, S: void 0 });
6448
6452
  return [
6449
6453
  {
6450
6454
  changes
6451
6455
  }
6452
6456
  ];
6453
6457
  } else if (cancel) {
6454
- log10("cancel", void 0, {
6455
- F: __dxlog_file15,
6456
- L: 178,
6457
- S: void 0,
6458
- C: (f, a) => f(...a)
6459
- });
6458
+ log10("cancel", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 205, S: void 0 });
6460
6459
  return [];
6461
6460
  }
6462
6461
  return tr;
@@ -6464,10 +6463,10 @@ var editor = () => [
6464
6463
  ];
6465
6464
 
6466
6465
  // src/extensions/outliner/menu.ts
6467
- import { EditorView as EditorView24, ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6466
+ import { EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6468
6467
  import { addEventListener as addEventListener2 } from "@dxos/async";
6469
6468
  var menu = (options = {}) => [
6470
- ViewPlugin16.fromClass(class {
6469
+ ViewPlugin17.fromClass(class {
6471
6470
  view;
6472
6471
  tag;
6473
6472
  rafId;
@@ -6529,7 +6528,7 @@ var menu = (options = {}) => [
6529
6528
  this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
6530
6529
  }
6531
6530
  }),
6532
- EditorView24.theme({
6531
+ EditorView25.theme({
6533
6532
  ".cm-popover-trigger": {
6534
6533
  position: "fixed",
6535
6534
  padding: "0",
@@ -6565,12 +6564,12 @@ var outliner = (_options = {}) => [
6565
6564
  listPaddingLeft: 8
6566
6565
  }),
6567
6566
  // Researve space for menu.
6568
- EditorView25.contentAttributes.of({
6567
+ EditorView26.contentAttributes.of({
6569
6568
  class: "w-full !mr-[3rem]"
6570
6569
  })
6571
6570
  ];
6572
6571
  var decorations = () => [
6573
- ViewPlugin17.fromClass(class {
6572
+ ViewPlugin18.fromClass(class {
6574
6573
  decorations = Decoration12.none;
6575
6574
  constructor(view) {
6576
6575
  this.updateDecorations(view.state, view);
@@ -6595,7 +6594,7 @@ var decorations = () => [
6595
6594
  const lineTo = doc.lineAt(item.contentRange.to);
6596
6595
  const isSelected = selection.includes(item.index) || item === current;
6597
6596
  decorations2.push(Decoration12.line({
6598
- 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"))
6599
6598
  }).range(line.from, line.from));
6600
6599
  }
6601
6600
  }
@@ -6605,7 +6604,7 @@ var decorations = () => [
6605
6604
  decorations: (v) => v.decorations
6606
6605
  }),
6607
6606
  // Theme.
6608
- EditorView25.theme(Object.assign({
6607
+ EditorView26.theme(Object.assign({
6609
6608
  ".cm-list-item": {
6610
6609
  borderLeftWidth: "1px",
6611
6610
  borderRightWidth: "1px",
@@ -6640,28 +6639,57 @@ var decorations = () => [
6640
6639
 
6641
6640
  // src/extensions/preview/preview.ts
6642
6641
  import { syntaxTree as syntaxTree10 } from "@codemirror/language";
6643
- import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField11 } from "@codemirror/state";
6644
- 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();
6645
6646
  var preview = (options = {}) => {
6647
+ const viewRef = {
6648
+ current: void 0
6649
+ };
6646
6650
  return [
6647
6651
  // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
6648
6652
  // "Block decorations may not be specified via plugins".
6649
6653
  StateField11.define({
6650
- create: (state) => buildDecorations3(state, options),
6654
+ create: (state) => buildDecorations3(state, options, viewRef),
6651
6655
  update: (decorations2, tr) => {
6652
- if (tr.docChanged) {
6653
- return buildDecorations3(tr.state, options);
6656
+ if (tr.docChanged || tr.effects.some((effect) => effect.is(labelResolvedEffect))) {
6657
+ return buildDecorations3(tr.state, options, viewRef);
6654
6658
  }
6655
6659
  return decorations2.map(tr.changes);
6656
6660
  },
6657
6661
  provide: (field) => [
6658
- EditorView26.decorations.from(field),
6659
- EditorView26.atomicRanges.of((view) => view.state.field(field))
6662
+ EditorView27.decorations.from(field),
6663
+ EditorView27.atomicRanges.of((view) => view.state.field(field))
6660
6664
  ]
6665
+ }),
6666
+ ViewPlugin19.define((view) => {
6667
+ viewRef.current = view;
6668
+ return {
6669
+ destroy() {
6670
+ viewRef.current = void 0;
6671
+ }
6672
+ };
6661
6673
  })
6662
6674
  ];
6663
6675
  };
6664
- 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) => {
6665
6693
  const builder = new RangeSetBuilder6();
6666
6694
  syntaxTree10(state).iterate({
6667
6695
  enter: (node) => {
@@ -6673,8 +6701,13 @@ var buildDecorations3 = (state, options) => {
6673
6701
  case "Link": {
6674
6702
  const link = getLinkRef(state, node.node);
6675
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;
6676
6709
  builder.add(node.from, node.to, Decoration13.replace({
6677
- widget: new PreviewInlineWidget(options, link),
6710
+ widget: new PreviewInlineWidget(options, displayLink),
6678
6711
  side: 1
6679
6712
  }));
6680
6713
  }
@@ -6766,7 +6799,7 @@ var PreviewBlockWidget = class extends WidgetType8 {
6766
6799
  };
6767
6800
 
6768
6801
  // src/extensions/replacer.ts
6769
- import { EditorView as EditorView27 } from "@codemirror/view";
6802
+ import { EditorView as EditorView28 } from "@codemirror/view";
6770
6803
  var defaultReplacements = [
6771
6804
  {
6772
6805
  input: "--",
@@ -6829,7 +6862,7 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6829
6862
  const sortedReplacements = [
6830
6863
  ...replacements
6831
6864
  ].sort((a, b) => b.input.length - a.input.length);
6832
- return EditorView27.inputHandler.of((view, from, to, insert) => {
6865
+ return EditorView28.inputHandler.of((view, from, to, insert) => {
6833
6866
  if (insert.length !== 1) {
6834
6867
  return false;
6835
6868
  }
@@ -6863,12 +6896,69 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6863
6896
  });
6864
6897
  };
6865
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
+
6866
6956
  // src/extensions/submit.ts
6867
6957
  import { Prec as Prec6 } from "@codemirror/state";
6868
- import { keymap as keymap12 } from "@codemirror/view";
6958
+ import { keymap as keymap13 } from "@codemirror/view";
6869
6959
  var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6870
6960
  return [
6871
- Prec6.highest(keymap12.of([
6961
+ Prec6.highest(keymap13.of([
6872
6962
  {
6873
6963
  key: "Enter",
6874
6964
  preventDefault: true,
@@ -6913,6 +7003,7 @@ var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6913
7003
  // src/extensions/tags/extended-markdown.ts
6914
7004
  import { xmlLanguage } from "@codemirror/lang-xml";
6915
7005
  import { parseMixed } from "@lezer/common";
7006
+ var escapeRegExpSource = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6916
7007
  var extendedMarkdown = ({ registry } = {}) => {
6917
7008
  return [
6918
7009
  createMarkdownExtensions({
@@ -6924,13 +7015,65 @@ var extendedMarkdown = ({ registry } = {}) => {
6924
7015
  {
6925
7016
  name: "SetextHeading",
6926
7017
  parse: () => false
6927
- }
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)
6928
7022
  ]
6929
7023
  }
6930
7024
  ]
6931
7025
  })
6932
7026
  ];
6933
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
+ };
6934
7077
  var mixedParser = (registry) => {
6935
7078
  const customTags = Object.keys(registry ?? {});
6936
7079
  const tagPattern = new RegExp(`<(${customTags.join("|")})`);
@@ -6964,219 +7107,793 @@ var mixedParser = (registry) => {
6964
7107
  });
6965
7108
  };
6966
7109
 
6967
- // src/extensions/tags/streamer.ts
6968
- import { StateEffect as StateEffect8, StateField as StateField12 } from "@codemirror/state";
6969
- import { Decoration as Decoration14, EditorView as EditorView28, ViewPlugin as ViewPlugin18, WidgetType as WidgetType9 } from "@codemirror/view";
6970
- import { Domino as Domino3 } from "@dxos/ui";
6971
- import { isTruthy as isTruthy4 } from "@dxos/util";
6972
- var BLINK_RATE = 2e3;
6973
- var streamer = (options = {}) => {
6974
- return [
6975
- options.cursor && cursor(),
6976
- options.fadeIn && fadeIn(typeof options.fadeIn === "object" ? options.fadeIn : {})
6977
- ].filter(isTruthy4);
6978
- };
6979
- var cursor = () => {
6980
- const hideCursor = StateEffect8.define();
6981
- const showCursor = StateField12.define({
6982
- create: () => true,
6983
- 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) => {
6984
7133
  for (const effect of tr.effects) {
6985
- if (effect.is(hideCursor)) {
6986
- 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
+ }
6987
7153
  }
6988
7154
  }
6989
- if (tr.docChanged) {
6990
- return true;
6991
- }
6992
- return value;
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
+ }
7327
+ }
7328
+ }
7329
+ if (tr.docChanged) {
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
+ }
7348
+ }
7349
+ return {
7350
+ text,
7351
+ head,
7352
+ insertAt
7353
+ };
6993
7354
  }
6994
7355
  });
6995
- 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 {
6996
7388
  view;
6997
- timer;
7389
+ _raf;
7390
+ _activeStreamTag = null;
6998
7391
  constructor(view) {
6999
7392
  this.view = view;
7000
7393
  }
7001
7394
  update(update2) {
7002
- if (update2.docChanged) {
7003
- clearTimeout(this.timer);
7004
- this.timer = setTimeout(() => {
7005
- this.view.dispatch({
7006
- effects: hideCursor.of(null)
7007
- });
7008
- }, 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();
7009
7402
  }
7010
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
+ };
7011
7478
  destroy() {
7012
- clearTimeout(this.timer);
7479
+ if (this._raf !== void 0) {
7480
+ cancelAnimationFrame(this._raf);
7481
+ }
7013
7482
  }
7014
7483
  });
7015
- const cursorDecoration = StateField12.define({
7016
- create: () => Decoration14.none,
7017
- update: (_decorations, tr) => {
7018
- const show = tr.state.field(showCursor);
7019
- if (!show) {
7020
- 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
+ }
7021
7525
  }
7022
- const endPos = tr.state.doc.length;
7023
- return Decoration14.set([
7024
- 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({
7025
7541
  widget: new CursorWidget(),
7026
7542
  side: 1
7027
- }).range(endPos)
7543
+ }).range(pos)
7028
7544
  ]);
7029
7545
  },
7030
- 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
+ }
7031
7573
  });
7032
7574
  return [
7033
- showCursor,
7034
- timerPlugin,
7035
- cursorDecoration
7575
+ visibilityField,
7576
+ decorationField,
7577
+ timerPlugin
7036
7578
  ];
7037
7579
  };
7038
- 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
+ }
7039
7586
  toDOM() {
7040
- const inner = Domino3.of("span").text("\u258F").style({
7041
- animation: "blink 2s infinite"
7587
+ const inner = Domino3.of("span").text("\u2217").style({
7588
+ animation: "blink 1s infinite",
7589
+ animationDelay: "250ms"
7042
7590
  });
7043
7591
  return Domino3.of("span").style({
7044
7592
  opacity: "0.8"
7045
- }).children(inner).root;
7593
+ }).append(inner).root;
7046
7594
  }
7047
7595
  };
7048
- var fadeIn = (options = {}) => {
7049
- const FADE_IN_DURATION = 1e3;
7050
- const DEFAULT_REMOVAL_DELAY = 3e3;
7051
- const removalDelay = options.removalDelay ?? DEFAULT_REMOVAL_DELAY;
7052
- const removeDecoration = StateEffect8.define();
7053
- const fadeField = StateField12.define({
7054
- create: () => Decoration14.none,
7055
- update: (decorations2, tr) => {
7056
- let next = decorations2;
7057
- for (const effect of tr.effects) {
7058
- if (effect.is(removeDecoration)) {
7059
- const target = effect.value;
7060
- next = next.update({
7061
- filter: (from, to) => !(from === target.from && to === target.to)
7062
- });
7063
- }
7064
- }
7065
- if (!tr.docChanged) {
7066
- 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
+ };
7067
7632
  }
7068
- let isReset = tr.state.doc.length === 0;
7069
- if (!isReset) {
7070
- tr.changes.iterChanges((fromA, toA) => {
7071
- if (fromA === 0 && toA === tr.startState.doc.length) {
7072
- isReset = true;
7073
- }
7074
- });
7633
+ if (buffer[close - 1] === "/") {
7634
+ return {
7635
+ count: close + 1 - start
7636
+ };
7075
7637
  }
7076
- if (isReset) {
7077
- 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;
7078
7693
  }
7079
- const add = [];
7080
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7081
- 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") {
7082
7739
  return;
7083
7740
  }
7084
- if (toA === tr.startState.doc.length && inserted.length > 0) {
7085
- add.push(Decoration14.mark({
7086
- class: "cm-fade-in"
7087
- }).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;
7088
7746
  }
7089
- });
7090
- return next.update({
7091
- add
7092
- });
7093
- },
7094
- provide: (f) => EditorView28.decorations.from(f)
7095
- });
7096
- const timerPlugin = ViewPlugin18.fromClass(class {
7097
- view;
7098
- // Map a simple key "from-to" to timer id.
7099
- _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;
7100
7778
  constructor(view) {
7101
- this.view = view;
7779
+ this.decorations = buildDecorations5(view);
7102
7780
  }
7103
7781
  update(update2) {
7104
- if (!update2.docChanged) {
7105
- return;
7782
+ if (update2.docChanged) {
7783
+ this.decorations = buildDecorations5(update2.view);
7106
7784
  }
7107
- update2.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7108
- 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));
7109
7831
  return;
7110
7832
  }
7111
- const key = `${fromB}-${toB}`;
7112
- if (this._timers.has(key)) {
7113
- 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
+ }
7114
7850
  }
7115
- const totalDelay = FADE_IN_DURATION + removalDelay;
7116
- const id = setTimeout(() => {
7117
- this.view.dispatch({
7118
- effects: removeDecoration.of({
7119
- from: fromB,
7120
- to: toB
7121
- })
7122
- });
7123
- this._timers.delete(key);
7124
- }, totalDelay);
7125
- this._timers.set(key, id);
7126
- });
7127
- }
7128
- destroy() {
7129
- for (const id of this._timers.values()) {
7130
- clearTimeout(id);
7131
7851
  }
7132
- this._timers.clear();
7133
- }
7134
- });
7852
+ });
7853
+ return Decoration17.set(ranges, true);
7854
+ };
7135
7855
  return [
7136
- fadeField,
7137
- timerPlugin,
7138
- EditorView28.theme({
7139
- ".cm-line > span": {
7140
- opacity: "0.8"
7141
- },
7142
- ".cm-fade-in": {
7143
- animation: "fade-in 3s ease-out forwards"
7144
- },
7145
- "@keyframes fade-in": {
7146
- "0%": {
7147
- opacity: "0"
7148
- },
7149
- "80%": {
7150
- opacity: "1"
7151
- },
7152
- "100%": {
7153
- 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);
7154
7864
  }
7155
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": {}
7156
7880
  })
7157
7881
  ];
7158
7882
  };
7159
7883
 
7160
7884
  // src/extensions/tags/xml-tags.ts
7161
7885
  import { syntaxTree as syntaxTree11 } from "@codemirror/language";
7162
- import { Prec as Prec7, RangeSetBuilder as RangeSetBuilder7, StateEffect as StateEffect9, StateField as StateField13 } from "@codemirror/state";
7163
- 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";
7164
7888
  import { invariant as invariant7 } from "@dxos/invariant";
7165
7889
  import { log as log11 } from "@dxos/log";
7890
+ import { Domino as Domino4 } from "@dxos/ui";
7166
7891
 
7167
7892
  // src/extensions/tags/xml-util.ts
7168
7893
  import { invariant as invariant6 } from "@dxos/invariant";
7169
7894
  var __dxlog_file16 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-util.ts";
7170
7895
  var nodeToJson = (state, node) => {
7171
- invariant6(node.type.name === "Element", "Node is not an Element", {
7172
- F: __dxlog_file16,
7173
- L: 18,
7174
- S: void 0,
7175
- A: [
7176
- "node.type.name === 'Element'",
7177
- "'Node is not an Element'"
7178
- ]
7179
- });
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'"] });
7180
7897
  const openTag = node.node.getChild("OpenTag") || node.node.getChild("SelfClosingTag");
7181
7898
  if (openTag) {
7182
7899
  const tagName = openTag.getChild("TagName");
@@ -7208,13 +7925,23 @@ var nodeToJson = (state, node) => {
7208
7925
  if (node.type.name === "Element" && openTag.type.name !== "SelfClosingTag") {
7209
7926
  const children = [];
7210
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
+ };
7211
7939
  while (child) {
7212
7940
  if (child.type.name !== "OpenTag" && child.type.name !== "CloseTag") {
7213
7941
  if (child.type.name === "Text") {
7214
- const text = state.doc.sliceString(child.from, child.to).trim();
7215
- if (text) {
7216
- children.push(text);
7217
- }
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)));
7218
7945
  } else if (child.type.name === "Element") {
7219
7946
  const data = nodeToJson(state, child);
7220
7947
  if (data) {
@@ -7224,26 +7951,63 @@ var nodeToJson = (state, node) => {
7224
7951
  }
7225
7952
  child = child.nextSibling;
7226
7953
  }
7954
+ if (children.length > 0 && typeof children[0] === "string") {
7955
+ children[0] = children[0].trimStart();
7956
+ }
7227
7957
  if (children.length > 0) {
7228
- 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;
7229
7967
  }
7230
7968
  }
7231
7969
  return tag;
7232
7970
  }
7233
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
+ };
7234
7996
 
7235
7997
  // src/extensions/tags/xml-tags.ts
7236
7998
  var __dxlog_file17 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-tags.ts";
7237
- var navigatePreviousEffect = StateEffect9.define();
7238
- var navigateNextEffect = StateEffect9.define();
7999
+ var navigatePreviousEffect = StateEffect12.define();
8000
+ var navigateNextEffect = StateEffect12.define();
7239
8001
  var getXmlTextChild = (children) => {
7240
8002
  const child = children?.[0];
7241
8003
  return typeof child === "string" ? child : null;
7242
8004
  };
7243
- var xmlTagContextEffect = StateEffect9.define();
7244
- var xmlTagResetEffect = StateEffect9.define();
7245
- var xmlTagUpdateEffect = StateEffect9.define();
7246
- 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({
7247
8011
  create: () => void 0,
7248
8012
  update: (value, tr) => {
7249
8013
  for (const effect of tr.effects) {
@@ -7254,7 +8018,7 @@ var widgetContextStateField = StateField13.define({
7254
8018
  return value;
7255
8019
  }
7256
8020
  });
7257
- var widgetStateMapStateField = StateField13.define({
8021
+ var widgetStateMapStateField = StateField14.define({
7258
8022
  create: () => ({}),
7259
8023
  update: (map, tr) => {
7260
8024
  for (const effect of tr.effects) {
@@ -7266,12 +8030,7 @@ var widgetStateMapStateField = StateField13.define({
7266
8030
  log11("widget updated", {
7267
8031
  id,
7268
8032
  value
7269
- }, {
7270
- F: __dxlog_file17,
7271
- L: 153,
7272
- S: void 0,
7273
- C: (f, a) => f(...a)
7274
- });
8033
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 59, S: void 0 });
7275
8034
  const state = typeof value === "function" ? value(map[id]) : value;
7276
8035
  return {
7277
8036
  ...map,
@@ -7301,12 +8060,7 @@ var createWidgetMap = (setWidgets) => {
7301
8060
  log11("widget mounted", {
7302
8061
  id: state.id,
7303
8062
  tag: state.props._tag
7304
- }, {
7305
- F: __dxlog_file17,
7306
- L: 206,
7307
- S: void 0,
7308
- C: (f, a) => f(...a)
7309
- });
8063
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 101, S: void 0 });
7310
8064
  widgets.set(state.id, state);
7311
8065
  setWidgets?.([
7312
8066
  ...widgets.values()
@@ -7317,12 +8071,7 @@ var createWidgetMap = (setWidgets) => {
7317
8071
  log11("widget unmounted", {
7318
8072
  id,
7319
8073
  tag: state?.props._tag
7320
- }, {
7321
- F: __dxlog_file17,
7322
- L: 212,
7323
- S: void 0,
7324
- C: (f, a) => f(...a)
7325
- });
8074
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 112, S: void 0 });
7326
8075
  widgets.delete(id);
7327
8076
  setWidgets?.([
7328
8077
  ...widgets.values()
@@ -7331,7 +8080,7 @@ var createWidgetMap = (setWidgets) => {
7331
8080
  };
7332
8081
  return notifier;
7333
8082
  };
7334
- var keyHandlers = keymap13.of([
8083
+ var keyHandlers = keymap14.of([
7335
8084
  {
7336
8085
  key: "Mod-ArrowUp",
7337
8086
  run: (view) => {
@@ -7352,7 +8101,7 @@ var keyHandlers = keymap13.of([
7352
8101
  }
7353
8102
  ]);
7354
8103
  var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7355
- return EditorView29.updateListener.of((update2) => {
8104
+ return EditorView32.updateListener.of((update2) => {
7356
8105
  update2.transactions.forEach((transaction) => {
7357
8106
  for (const effect of transaction.effects) {
7358
8107
  if (effect.is(navigatePreviousEffect)) {
@@ -7437,7 +8186,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7437
8186
  });
7438
8187
  });
7439
8188
  };
7440
- var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin19.fromClass(class {
8189
+ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin24.fromClass(class {
7441
8190
  update(update2) {
7442
8191
  const widgetStateMap = update2.state.field(widgetStateMapStateField);
7443
8192
  const { decorations: decorations2 } = update2.state.field(widgetDecorationsField);
@@ -7464,14 +8213,14 @@ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin1
7464
8213
  }
7465
8214
  }
7466
8215
  });
7467
- var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.define({
8216
+ var createWidgetDecorationsField = (registry = {}, notifier) => StateField14.define({
7468
8217
  create: (state) => {
7469
8218
  return buildDecorations4(state, {
7470
8219
  from: 0,
7471
8220
  to: state.doc.length
7472
8221
  }, registry, notifier);
7473
8222
  },
7474
- update: ({ from, decorations: decorations2 }, tr) => {
8223
+ update: ({ from, streamingFrom, decorations: decorations2 }, tr) => {
7475
8224
  for (const effect of tr.effects) {
7476
8225
  if (effect.is(xmlTagResetEffect)) {
7477
8226
  if (tr.docChanged) {
@@ -7482,7 +8231,7 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7482
8231
  }
7483
8232
  return {
7484
8233
  from: 0,
7485
- decorations: Decoration15.none
8234
+ decorations: Decoration18.none
7486
8235
  };
7487
8236
  }
7488
8237
  }
@@ -7493,24 +8242,23 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7493
8242
  log11("document reset", {
7494
8243
  from,
7495
8244
  to: state.doc.length
7496
- }, {
7497
- F: __dxlog_file17,
7498
- L: 374,
7499
- S: void 0,
7500
- C: (f, a) => f(...a)
7501
- });
8245
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 298, S: void 0 });
7502
8246
  return buildDecorations4(state, {
7503
8247
  from: 0,
7504
8248
  to: state.doc.length
7505
8249
  }, registry, notifier);
7506
8250
  } else {
8251
+ const rebuildFrom = streamingFrom ?? from;
7507
8252
  const result = buildDecorations4(state, {
7508
- from,
8253
+ from: rebuildFrom,
7509
8254
  to: state.doc.length
7510
8255
  }, registry, notifier);
7511
8256
  return {
7512
8257
  from: result.from,
8258
+ streamingFrom: result.streamingFrom,
7513
8259
  decorations: decorations2.update({
8260
+ // Remove old streaming decorations — they are rebuilt each tick.
8261
+ filter: (_f, _t, deco) => !deco.spec.streaming,
7514
8262
  add: decorationSetToArray(result.decorations)
7515
8263
  })
7516
8264
  };
@@ -7518,12 +8266,13 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7518
8266
  }
7519
8267
  return {
7520
8268
  from,
8269
+ streamingFrom,
7521
8270
  decorations: decorations2
7522
8271
  };
7523
8272
  },
7524
8273
  provide: (field) => [
7525
- EditorView29.decorations.from(field, (v) => v.decorations),
7526
- 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)
7527
8276
  ]
7528
8277
  });
7529
8278
  var buildDecorations4 = (state, range, registry, notifier) => {
@@ -7534,10 +8283,11 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7534
8283
  if (!tree || tree.type.name === "Program" && tree.length === 0) {
7535
8284
  return {
7536
8285
  from: range.from,
7537
- decorations: Decoration15.none
8286
+ decorations: Decoration18.none
7538
8287
  };
7539
8288
  }
7540
8289
  let last = range.from;
8290
+ let streamingFrom;
7541
8291
  tree.iterate({
7542
8292
  from: range.from,
7543
8293
  to: range.to,
@@ -7550,21 +8300,26 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7550
8300
  if (args) {
7551
8301
  const def = registry[args._tag];
7552
8302
  if (def) {
8303
+ if (def.streaming && !node.node.getChild("CloseTag")) {
8304
+ return false;
8305
+ }
7553
8306
  const { block, factory, Component } = def;
7554
- const widgetState = args.id ? widgetStateMap[args.id] : void 0;
7555
8307
  const nodeRange = {
7556
8308
  from: node.node.from,
7557
8309
  to: node.node.to
7558
8310
  };
8311
+ const widgetId = xmlWidgetId(args.id, def.streaming ? `cm-xml-${nodeRange.from}` : `cm-xml-${nodeRange.from}-${nodeRange.to}`);
8312
+ const widgetState = widgetStateMap[widgetId];
7559
8313
  const props = {
7560
- context,
8314
+ id: widgetId,
7561
8315
  range: nodeRange,
8316
+ context,
7562
8317
  ...args,
7563
8318
  ...widgetState
7564
8319
  };
7565
- 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;
7566
8321
  if (widget) {
7567
- builder.add(nodeRange.from, nodeRange.to, Decoration15.replace({
8322
+ builder.add(nodeRange.from, nodeRange.to, Decoration18.replace({
7568
8323
  widget,
7569
8324
  block,
7570
8325
  atomic: true,
@@ -7576,20 +8331,72 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7576
8331
  }
7577
8332
  }
7578
8333
  } catch (err) {
7579
- log11.catch(err, void 0, {
7580
- F: __dxlog_file17,
7581
- L: 459,
7582
- S: void 0,
7583
- C: (f, a) => f(...a)
7584
- });
8334
+ log11.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 401, S: void 0 });
7585
8335
  }
7586
8336
  return false;
7587
8337
  }
7588
8338
  }
7589
8339
  }
7590
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
+ }
7591
8397
  return {
7592
8398
  from: last,
8399
+ streamingFrom,
7593
8400
  decorations: builder.finish()
7594
8401
  };
7595
8402
  };
@@ -7598,108 +8405,62 @@ var PlaceholderWidget2 = class extends WidgetType10 {
7598
8405
  Component;
7599
8406
  props;
7600
8407
  notifier;
7601
- _root = null;
7602
- constructor(id, Component, props, notifier) {
7603
- super(), this.id = id, this.Component = Component, this.props = props, this.notifier = notifier;
7604
- invariant7(id, void 0, {
7605
- F: __dxlog_file17,
7606
- L: 485,
7607
- S: this,
7608
- A: [
7609
- "id",
7610
- ""
7611
- ]
7612
- });
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", ""] });
7613
8414
  }
7614
8415
  get root() {
7615
- return this._root;
8416
+ return this.#root;
7616
8417
  }
7617
8418
  eq(other) {
8419
+ if (this.streaming) {
8420
+ return false;
8421
+ }
7618
8422
  return this.id === other.id;
7619
8423
  }
7620
8424
  ignoreEvent() {
7621
8425
  return true;
7622
8426
  }
7623
- toDOM(_view) {
7624
- 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
+ });
7625
8446
  this.notifier.mounted({
7626
8447
  id: this.id,
7627
- root: this._root,
7628
- props: this.props,
8448
+ root: this.#root,
8449
+ props,
7629
8450
  Component: this.Component
7630
8451
  });
7631
- return this._root;
8452
+ return true;
7632
8453
  }
7633
8454
  destroy(_dom) {
7634
8455
  this.notifier.unmounted(this.id);
7635
- this._root = null;
8456
+ this.#root = null;
8457
+ this.#view = void 0;
7636
8458
  }
7637
8459
  };
7638
-
7639
- // src/extensions/typewriter.ts
7640
- import { keymap as keymap14 } from "@codemirror/view";
7641
- var defaultItems = [
7642
- "hello world!",
7643
- "this is a test.",
7644
- "this is [DXOS](https://dxos.org)"
7645
- ];
7646
- var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
7647
- let t;
7648
- let idx = 0;
7649
- return [
7650
- keymap14.of([
7651
- {
7652
- // Reset.
7653
- key: "alt-meta-'",
7654
- run: () => {
7655
- clearTimeout(t);
7656
- idx = 0;
7657
- return true;
7658
- }
7659
- },
7660
- {
7661
- // Next prompt.
7662
- // TODO(burdon): Press 1-9 to select prompt?
7663
- key: "Shift-Meta-'",
7664
- run: (view) => {
7665
- clearTimeout(t);
7666
- const text = items[idx++];
7667
- if (idx === items?.length) {
7668
- idx = 0;
7669
- }
7670
- let i = 0;
7671
- const insert = (d = 0) => {
7672
- t = setTimeout(() => {
7673
- const pos = view.state.selection.main.head;
7674
- view.dispatch({
7675
- changes: {
7676
- from: pos,
7677
- insert: text[i++]
7678
- },
7679
- selection: {
7680
- anchor: pos + 1
7681
- }
7682
- });
7683
- if (i < text.length) {
7684
- insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
7685
- }
7686
- }, d);
7687
- };
7688
- insert();
7689
- return true;
7690
- }
7691
- }
7692
- ])
7693
- ];
7694
- };
7695
8460
  export {
7696
8461
  Cursor,
7697
- EditorInputMode,
7698
- EditorInputModes,
7699
- EditorState3 as EditorState,
7700
- EditorView30 as EditorView,
7701
- EditorViewMode,
7702
- EditorViewModes,
8462
+ EditorState4 as EditorState,
8463
+ EditorView33 as EditorView,
7703
8464
  Inline,
7704
8465
  InputModeExtensions,
7705
8466
  List,
@@ -7716,6 +8477,7 @@ export {
7716
8477
  addStyle,
7717
8478
  annotations,
7718
8479
  autoScroll,
8480
+ autoScrollEffect,
7719
8481
  autocomplete,
7720
8482
  automerge,
7721
8483
  awareness,
@@ -7729,6 +8491,7 @@ export {
7729
8491
  commentClickedEffect,
7730
8492
  comments,
7731
8493
  commentsState,
8494
+ compactSlots,
7732
8495
  convertTreeToJson,
7733
8496
  createBasicExtensions,
7734
8497
  createComment,
@@ -7752,12 +8515,12 @@ export {
7752
8515
  defaultThemeSlots,
7753
8516
  deleteItem,
7754
8517
  documentId,
8518
+ documentSlots,
7755
8519
  dropFile,
8520
+ editorClassNames,
7756
8521
  editorInputMode,
7757
- editorSlots,
7758
- editorWidth,
7759
- editorWithToolbarLayout,
7760
8522
  extendedMarkdown,
8523
+ fader,
7761
8524
  filterChars,
7762
8525
  flattenRect,
7763
8526
  focus,
@@ -7793,6 +8556,7 @@ export {
7793
8556
  markdownTagsExtensions,
7794
8557
  matchCompletion,
7795
8558
  mention,
8559
+ mobileSlots,
7796
8560
  modalStateEffect,
7797
8561
  modalStateField,
7798
8562
  moveItemDown,
@@ -7812,6 +8576,7 @@ export {
7812
8576
  removeList,
7813
8577
  removeStyle,
7814
8578
  replacer,
8579
+ scrollPastEnd,
7815
8580
  scrollThreadIntoView,
7816
8581
  scrollToLine,
7817
8582
  scroller,
@@ -7824,9 +8589,8 @@ export {
7824
8589
  setSelection,
7825
8590
  setStyle,
7826
8591
  singleValueFacet,
7827
- stackItemContentEditorClassNames,
8592
+ snippets2 as snippets,
7828
8593
  staticCompletion,
7829
- streamer,
7830
8594
  submit,
7831
8595
  tabbable,
7832
8596
  table,
@@ -7845,7 +8609,12 @@ export {
7845
8609
  treeFacet,
7846
8610
  typeahead,
7847
8611
  typewriter,
8612
+ typewriterBypass,
8613
+ typewriterDrainingEffect,
7848
8614
  wrapWithCatch,
8615
+ xmlBlockDecoration,
8616
+ xmlElementLength,
8617
+ xmlFormatting,
7849
8618
  xmlTagContextEffect,
7850
8619
  xmlTagResetEffect,
7851
8620
  xmlTagUpdateEffect,