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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/lib/browser/index.mjs +1523 -750
  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 +1522 -748
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/lib/node-esm/types/index.mjs +27 -6
  10. package/dist/lib/node-esm/types/index.mjs.map +4 -4
  11. package/dist/types/src/defaults.d.ts +4 -10
  12. package/dist/types/src/defaults.d.ts.map +1 -1
  13. package/dist/types/src/extensions/annotations.d.ts.map +1 -1
  14. package/dist/types/src/extensions/auto-scroll.d.ts +14 -2
  15. package/dist/types/src/extensions/auto-scroll.d.ts.map +1 -1
  16. package/dist/types/src/extensions/autocomplete/autocomplete.d.ts.map +1 -1
  17. package/dist/types/src/extensions/autocomplete/match.d.ts.map +1 -1
  18. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -1
  19. package/dist/types/src/extensions/autocomplete/typeahead.d.ts.map +1 -1
  20. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  21. package/dist/types/src/extensions/automerge/cursor.d.ts.map +1 -1
  22. package/dist/types/src/extensions/automerge/defs.d.ts.map +1 -1
  23. package/dist/types/src/extensions/automerge/sync.d.ts.map +1 -1
  24. package/dist/types/src/extensions/automerge/update-automerge.d.ts.map +1 -1
  25. package/dist/types/src/extensions/automerge/update-codemirror.d.ts.map +1 -1
  26. package/dist/types/src/extensions/awareness/awareness-provider.d.ts.map +1 -1
  27. package/dist/types/src/extensions/awareness/awareness.d.ts.map +1 -1
  28. package/dist/types/src/extensions/blast.d.ts.map +1 -1
  29. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  30. package/dist/types/src/extensions/debug.d.ts.map +1 -1
  31. package/dist/types/src/extensions/dnd.d.ts.map +1 -1
  32. package/dist/types/src/extensions/factories.d.ts +4 -3
  33. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  34. package/dist/types/src/extensions/factories.test.d.ts +2 -0
  35. package/dist/types/src/extensions/factories.test.d.ts.map +1 -0
  36. package/dist/types/src/extensions/focus.d.ts +1 -1
  37. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  38. package/dist/types/src/extensions/index.d.ts +2 -1
  39. package/dist/types/src/extensions/index.d.ts.map +1 -1
  40. package/dist/types/src/extensions/json.d.ts.map +1 -1
  41. package/dist/types/src/extensions/listener.d.ts.map +1 -1
  42. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  43. package/dist/types/src/extensions/markdown/bundle.d.ts +3 -0
  44. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  45. package/dist/types/src/extensions/markdown/changes.d.ts.map +1 -1
  46. package/dist/types/src/extensions/markdown/debug.d.ts.map +1 -1
  47. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  48. package/dist/types/src/extensions/markdown/formatting.d.ts.map +1 -1
  49. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  50. package/dist/types/src/extensions/markdown/image.d.ts.map +1 -1
  51. package/dist/types/src/extensions/markdown/link.d.ts.map +1 -1
  52. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  53. package/dist/types/src/extensions/markdown/table.d.ts.map +1 -1
  54. package/dist/types/src/extensions/mention.d.ts.map +1 -1
  55. package/dist/types/src/extensions/outliner/menu.d.ts.map +1 -1
  56. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  57. package/dist/types/src/extensions/outliner/selection.d.ts.map +1 -1
  58. package/dist/types/src/extensions/outliner/tree.d.ts.map +1 -1
  59. package/dist/types/src/extensions/preview/preview.d.ts +2 -0
  60. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  61. package/dist/types/src/extensions/replacer.d.ts.map +1 -1
  62. package/dist/types/src/extensions/scroll-past-end.d.ts +3 -0
  63. package/dist/types/src/extensions/scroll-past-end.d.ts.map +1 -0
  64. package/dist/types/src/extensions/scroller.d.ts +12 -10
  65. package/dist/types/src/extensions/scroller.d.ts.map +1 -1
  66. package/dist/types/src/extensions/selection.d.ts.map +1 -1
  67. package/dist/types/src/extensions/snippets.d.ts +10 -0
  68. package/dist/types/src/extensions/snippets.d.ts.map +1 -0
  69. package/dist/types/src/extensions/submit.d.ts.map +1 -1
  70. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -1
  71. package/dist/types/src/extensions/tags/fader.d.ts +12 -0
  72. package/dist/types/src/extensions/tags/fader.d.ts.map +1 -0
  73. package/dist/types/src/extensions/tags/index.d.ts +4 -1
  74. package/dist/types/src/extensions/tags/index.d.ts.map +1 -1
  75. package/dist/types/src/extensions/tags/typewriter.d.ts +43 -0
  76. package/dist/types/src/extensions/tags/typewriter.d.ts.map +1 -0
  77. package/dist/types/src/extensions/tags/typewriter.test.d.ts +2 -0
  78. package/dist/types/src/extensions/tags/typewriter.test.d.ts.map +1 -0
  79. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts +31 -0
  80. package/dist/types/src/extensions/tags/xml-block-decoration.d.ts.map +1 -0
  81. package/dist/types/src/extensions/tags/xml-formatting.d.ts +24 -0
  82. package/dist/types/src/extensions/tags/xml-formatting.d.ts.map +1 -0
  83. package/dist/types/src/extensions/tags/xml-tags.d.ts +28 -8
  84. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
  85. package/dist/types/src/extensions/tags/xml-util.d.ts.map +1 -1
  86. package/dist/types/src/index.d.ts +0 -1
  87. package/dist/types/src/index.d.ts.map +1 -1
  88. package/dist/types/src/styles/theme.d.ts +2 -2
  89. package/dist/types/src/styles/theme.d.ts.map +1 -1
  90. package/dist/types/src/types/types.d.ts +4 -4
  91. package/dist/types/src/types/types.d.ts.map +1 -1
  92. package/dist/types/src/util/cursor.d.ts.map +1 -1
  93. package/dist/types/src/util/debug.d.ts.map +1 -1
  94. package/dist/types/src/util/decorations.d.ts.map +1 -1
  95. package/dist/types/src/util/dom.d.ts.map +1 -1
  96. package/dist/types/src/util/facet.d.ts.map +1 -1
  97. package/dist/types/src/util/util.d.ts.map +1 -1
  98. package/dist/types/tsconfig.tsbuildinfo +1 -1
  99. package/package.json +33 -36
  100. package/src/defaults.ts +33 -17
  101. package/src/extensions/auto-scroll.ts +115 -9
  102. package/src/extensions/automerge/automerge.test.tsx +35 -9
  103. package/src/extensions/automerge/automerge.ts +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 +46 -23
  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,26 +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 = {
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 = {
18
36
  content: {
19
- className: editorWidth
37
+ className: "mx-2!"
20
38
  }
21
39
  };
22
- var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
23
- 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");
24
40
 
25
41
  // src/extensions/annotations.ts
26
42
  import { RangeSetBuilder } from "@codemirror/state";
@@ -204,7 +220,7 @@ var singleValueFacet = (defaultValue) => Facet.define({
204
220
  var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
205
221
  var defaultCursorConverter = {
206
222
  toCursor: (position) => position.toString(),
207
- fromCursor: (cursor2) => parseInt(cursor2)
223
+ fromCursor: (cursor) => parseInt(cursor)
208
224
  };
209
225
  var Cursor = class _Cursor {
210
226
  static converter = singleValueFacet(defaultCursorConverter);
@@ -217,9 +233,9 @@ var Cursor = class _Cursor {
217
233
  to
218
234
  ].join(":");
219
235
  };
220
- static getRangeFromCursor = (state, cursor2) => {
236
+ static getRangeFromCursor = (state, cursor) => {
221
237
  const cursorConverter2 = state.facet(_Cursor.converter);
222
- const parts = cursor2.split(":");
238
+ const parts = cursor.split(":");
223
239
  const from = cursorConverter2.fromCursor(parts[0]);
224
240
  const to = cursorConverter2.fromCursor(parts[1]);
225
241
  return from !== void 0 && to !== void 0 ? {
@@ -255,12 +271,7 @@ var wrapWithCatch = (fn, label) => {
255
271
  } catch (err) {
256
272
  log.catch(err, {
257
273
  label
258
- }, {
259
- F: __dxlog_file,
260
- L: 20,
261
- S: void 0,
262
- C: (f, a) => f(...a)
263
- });
274
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 13, S: void 0 });
264
275
  }
265
276
  };
266
277
  };
@@ -286,12 +297,7 @@ var logChanges = (trs) => {
286
297
  if (changes.length) {
287
298
  log("changes", {
288
299
  changes
289
- }, {
290
- F: __dxlog_file,
291
- L: 54,
292
- S: void 0,
293
- C: (f, a) => f(...a)
294
- });
300
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file, L: 44, S: void 0 });
295
301
  }
296
302
  };
297
303
 
@@ -499,9 +505,11 @@ var typeahead = ({ onComplete } = {}) => {
499
505
  };
500
506
 
501
507
  // src/extensions/auto-scroll.ts
508
+ import { StateEffect as StateEffect2 } from "@codemirror/state";
502
509
  import { EditorView as EditorView5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
503
510
  import { addEventListener, combine, throttle } from "@dxos/async";
504
511
  import { Domino } from "@dxos/ui";
512
+ import { getSize } from "@dxos/ui-theme";
505
513
 
506
514
  // src/extensions/scroller.ts
507
515
  import { StateEffect } from "@codemirror/state";
@@ -580,23 +588,19 @@ var scroller = ({ overScroll = 0 } = {}) => {
580
588
  }
581
589
  }
582
590
  } catch (err) {
583
- log2.catch(err, void 0, {
584
- F: __dxlog_file2,
585
- L: 146,
586
- S: void 0,
587
- C: (f, a) => f(...a)
588
- });
591
+ log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 91, S: void 0 });
589
592
  }
590
593
  });
591
594
  }),
592
595
  // Styles.
593
596
  EditorView4.theme({
594
- ".cm-content": {
595
- paddingBottom: `${overScroll}px`
596
- },
597
597
  ".cm-scroller": {
598
- overflowAnchor: "none",
599
- 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"
600
604
  },
601
605
  ".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
602
606
  display: "none"
@@ -608,6 +612,16 @@ var scroller = ({ overScroll = 0 } = {}) => {
608
612
  "&:hover .cm-scroller::-webkit-scrollbar-thumb": {
609
613
  background: "var(--color-scrollbar-thumb)"
610
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
+ },
611
625
  ".cm-scroll-button": {
612
626
  position: "absolute",
613
627
  bottom: "0.5rem",
@@ -616,22 +630,28 @@ var scroller = ({ overScroll = 0 } = {}) => {
616
630
  })
617
631
  ];
618
632
  };
619
- function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
633
+ function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
620
634
  const el = view.scrollDOM;
621
635
  let currentTop = 0;
636
+ let velocity = 0;
622
637
  let rafId = null;
623
- 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;
624
642
  const targetTop = el.scrollHeight - el.clientHeight;
625
643
  const delta = targetTop - currentTop;
626
- const absDelta = Math.abs(delta);
627
- if (absDelta < targetDelta) {
644
+ if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
628
645
  el.scrollTop = targetTop;
629
646
  currentTop = targetTop;
647
+ velocity = 0;
630
648
  rafId = null;
649
+ lastTime = 0;
631
650
  return;
632
651
  }
633
- const step = Math.sign(delta) * Math.min(absDelta, Math.max(1, Math.min(absDelta * k, maxStep)));
634
- currentTop += step;
652
+ const accel = omega * omega * delta - 2 * omega * velocity;
653
+ velocity += accel * dt;
654
+ currentTop += velocity * dt;
635
655
  el.scrollTop = currentTop;
636
656
  rafId = requestAnimationFrame(frame);
637
657
  }
@@ -639,12 +659,15 @@ function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
639
659
  scroll: () => {
640
660
  if (rafId === null) {
641
661
  currentTop = el.scrollTop;
662
+ lastTime = 0;
642
663
  rafId = requestAnimationFrame(frame);
643
664
  }
644
665
  },
645
666
  cancel: () => {
646
667
  if (rafId !== null) {
647
668
  cancelAnimationFrame(rafId);
669
+ velocity = 0;
670
+ lastTime = 0;
648
671
  rafId = null;
649
672
  }
650
673
  }
@@ -652,26 +675,64 @@ function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
652
675
  }
653
676
 
654
677
  // src/extensions/auto-scroll.ts
655
- var autoScroll = (_ = {}) => {
678
+ var autoScrollEffect = StateEffect2.define();
679
+ var autoScroll = ({ scrollOnResize = true } = {}) => {
656
680
  let buttonContainer;
657
681
  let isPinned = true;
682
+ let jumpPending = false;
683
+ let enabled = true;
684
+ let firstUpdate = true;
658
685
  const setPinned = (pinned) => {
659
686
  buttonContainer?.classList.toggle("opacity-0", pinned);
660
687
  isPinned = pinned;
661
688
  };
662
689
  return [
663
- // Update listener for logging when scrolling is needed.
664
- 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
+ }
665
726
  if (heightChanged) {
666
727
  if (isPinned) {
667
728
  const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
668
729
  const delta = scrollHeight - scrollTop - clientHeight;
669
- if (delta > 0 && scrollTop > 0) {
730
+ if (delta > 0) {
670
731
  setPinned(true);
671
732
  view.dispatch({
672
733
  effects: scrollerCrawlEffect.of(true)
673
734
  });
674
- } else if (delta < 0) {
735
+ } else if (delta < -1) {
675
736
  setPinned(false);
676
737
  }
677
738
  } else {
@@ -681,6 +742,43 @@ var autoScroll = (_ = {}) => {
681
742
  }
682
743
  }
683
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
+ }) : [],
684
782
  // Detect user scroll and unpin (or re-pin if scrolled to the bottom).
685
783
  ViewPlugin6.fromClass(class {
686
784
  cleanup;
@@ -706,12 +804,12 @@ var autoScroll = (_ = {}) => {
706
804
  // Scroll button.
707
805
  ViewPlugin6.fromClass(class {
708
806
  constructor(view) {
709
- const icon = Domino.of("dx-icon").attributes({
807
+ const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
710
808
  icon: "ph--arrow-down--regular"
711
809
  });
712
810
  const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
713
811
  "data-density": "fine"
714
- }).children(icon).on("click", () => {
812
+ }).append(icon).on("click", () => {
715
813
  setPinned(true);
716
814
  view.dispatch({
717
815
  effects: scrollerLineEffect.of({
@@ -721,7 +819,7 @@ var autoScroll = (_ = {}) => {
721
819
  })
722
820
  });
723
821
  });
724
- 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;
725
823
  view.scrollDOM.parentElement.appendChild(buttonContainer);
726
824
  }
727
825
  })
@@ -756,35 +854,25 @@ var cursorConverter = (accessor) => ({
756
854
  try {
757
855
  return toCursor(accessor, pos, assoc);
758
856
  } catch (err) {
759
- log3.catch(err, void 0, {
760
- F: __dxlog_file3,
761
- L: 15,
762
- S: void 0,
763
- C: (f, a) => f(...a)
764
- });
857
+ log3.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 11, S: void 0 });
765
858
  return "";
766
859
  }
767
860
  },
768
- fromCursor: (cursor2) => {
861
+ fromCursor: (cursor) => {
769
862
  try {
770
- return fromCursor(accessor, cursor2);
863
+ return fromCursor(accessor, cursor);
771
864
  } catch (err) {
772
- log3.catch(err, void 0, {
773
- F: __dxlog_file3,
774
- L: 24,
775
- S: void 0,
776
- C: (f, a) => f(...a)
777
- });
865
+ log3.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 19, S: void 0 });
778
866
  return 0;
779
867
  }
780
868
  }
781
869
  });
782
870
 
783
871
  // src/extensions/automerge/defs.ts
784
- import { Annotation, StateEffect as StateEffect2 } from "@codemirror/state";
872
+ import { Annotation, StateEffect as StateEffect3 } from "@codemirror/state";
785
873
  var getPath = (state, field) => state.field(field).path;
786
874
  var getLastHeads = (state, field) => state.field(field).lastHeads;
787
- var updateHeadsEffect = StateEffect2.define({});
875
+ var updateHeadsEffect = StateEffect3.define({});
788
876
  var updateHeads = (newHeads) => updateHeadsEffect.of({
789
877
  newHeads
790
878
  });
@@ -959,12 +1047,7 @@ var Syncer = class {
959
1047
  this._pending = false;
960
1048
  }
961
1049
  onEditorChange(view) {
962
- log4("onEditorChange", void 0, {
963
- F: __dxlog_file4,
964
- L: 45,
965
- S: this,
966
- C: (f, a) => f(...a)
967
- });
1050
+ log4("onEditorChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 35, S: this });
968
1051
  const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
969
1052
  const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
970
1053
  if (newHeads) {
@@ -975,12 +1058,7 @@ var Syncer = class {
975
1058
  }
976
1059
  }
977
1060
  onAutomergeChange(view) {
978
- log4("onAutomergeChange", void 0, {
979
- F: __dxlog_file4,
980
- L: 60,
981
- S: this,
982
- C: (f, a) => f(...a)
983
- });
1061
+ log4("onAutomergeChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 47, S: this });
984
1062
  const oldHeads = getLastHeads(view.state, this._state);
985
1063
  const newHeads = A2.getHeads(this._handle.doc());
986
1064
  const diff = A2.equals(oldHeads, newHeads) ? [] : A2.diff(this._handle.doc(), oldHeads, newHeads);
@@ -1042,14 +1120,16 @@ var automerge = (accessor) => {
1042
1120
  const value = DocAccessor.getValue(accessor);
1043
1121
  const current = this._view.state.doc.toString();
1044
1122
  if (value !== current) {
1045
- console.warn("ENABLING INITIAL SYNC -- THIS MAY BE A REGRESSION");
1046
1123
  this._view.dispatch({
1047
1124
  changes: {
1048
1125
  from: 0,
1049
1126
  to: this._view.state.doc.length,
1050
1127
  insert: value
1051
1128
  },
1052
- annotations: initialSync
1129
+ annotations: [
1130
+ initialSync,
1131
+ reconcileAnnotation.of(true)
1132
+ ]
1053
1133
  });
1054
1134
  }
1055
1135
  });
@@ -1101,10 +1181,7 @@ var awareness = (provider = dummyProvider) => {
1101
1181
  ];
1102
1182
  };
1103
1183
  var RemoteSelectionsDecorator = class {
1104
- _ctx = new Context(void 0, {
1105
- F: __dxlog_file5,
1106
- L: 80
1107
- });
1184
+ _ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 33 });
1108
1185
  _cursorConverter;
1109
1186
  _provider;
1110
1187
  _lastAnchor;
@@ -1335,10 +1412,7 @@ var SpaceAwarenessProvider = class {
1335
1412
  this._info = info;
1336
1413
  }
1337
1414
  open() {
1338
- this._ctx = new Context2(void 0, {
1339
- F: __dxlog_file6,
1340
- L: 57
1341
- });
1415
+ this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 28 });
1342
1416
  this._postTask = new DeferredTask(this._ctx, async () => {
1343
1417
  if (this._localState) {
1344
1418
  await this._messenger.postMessage(this._channel, {
@@ -1365,12 +1439,7 @@ var SpaceAwarenessProvider = class {
1365
1439
  }).catch((err) => {
1366
1440
  log5.debug("failed to query awareness", {
1367
1441
  err
1368
- }, {
1369
- F: __dxlog_file6,
1370
- L: 91,
1371
- S: this,
1372
- C: (f, a) => f(...a)
1373
- });
1442
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 57, S: this });
1374
1443
  });
1375
1444
  }
1376
1445
  close() {
@@ -1382,15 +1451,7 @@ var SpaceAwarenessProvider = class {
1382
1451
  return Array.from(this._remoteStates.values());
1383
1452
  }
1384
1453
  update(position) {
1385
- invariant(this._postTask, void 0, {
1386
- F: __dxlog_file6,
1387
- L: 106,
1388
- S: this,
1389
- A: [
1390
- "this._postTask",
1391
- ""
1392
- ]
1393
- });
1454
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 71, S: this, A: ["this._postTask", ""] });
1394
1455
  this._localState = {
1395
1456
  peerId: this._peerId,
1396
1457
  position,
@@ -1399,27 +1460,11 @@ var SpaceAwarenessProvider = class {
1399
1460
  this._postTask.schedule();
1400
1461
  }
1401
1462
  _handleQueryMessage() {
1402
- invariant(this._postTask, void 0, {
1403
- F: __dxlog_file6,
1404
- L: 117,
1405
- S: this,
1406
- A: [
1407
- "this._postTask",
1408
- ""
1409
- ]
1410
- });
1463
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 80, S: this, A: ["this._postTask", ""] });
1411
1464
  this._postTask.schedule();
1412
1465
  }
1413
1466
  _handlePostMessage(message) {
1414
- invariant(message.kind === "post", void 0, {
1415
- F: __dxlog_file6,
1416
- L: 122,
1417
- S: this,
1418
- A: [
1419
- "message.kind === 'post'",
1420
- ""
1421
- ]
1422
- });
1467
+ invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 84, S: this, A: ["message.kind === 'post'", ""] });
1423
1468
  this._remoteStates.set(message.state.peerId, message.state);
1424
1469
  this.remoteStateChange.emit();
1425
1470
  }
@@ -1548,15 +1593,7 @@ var Blaster = class {
1548
1593
  return this._node;
1549
1594
  }
1550
1595
  initialize() {
1551
- invariant2(!this._canvas && !this._ctx, void 0, {
1552
- F: __dxlog_file7,
1553
- L: 142,
1554
- S: this,
1555
- A: [
1556
- "!this._canvas && !this._ctx",
1557
- ""
1558
- ]
1559
- });
1596
+ invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
1560
1597
  this._canvas = document.createElement("canvas");
1561
1598
  this._canvas.id = "code-blast-canvas";
1562
1599
  this._canvas.style.position = "absolute";
@@ -1585,15 +1622,7 @@ var Blaster = class {
1585
1622
  }
1586
1623
  }
1587
1624
  start() {
1588
- invariant2(this._canvas && this._ctx, void 0, {
1589
- F: __dxlog_file7,
1590
- L: 181,
1591
- S: this,
1592
- A: [
1593
- "this._canvas && this._ctx",
1594
- ""
1595
- ]
1596
- });
1625
+ invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
1597
1626
  this._running = true;
1598
1627
  this.loop();
1599
1628
  }
@@ -1828,13 +1857,13 @@ var blocks = () => [
1828
1857
  ];
1829
1858
 
1830
1859
  // src/extensions/bookmarks.ts
1831
- 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";
1832
1861
  import { keymap as keymap4 } from "@codemirror/view";
1833
1862
  import { log as log6 } from "@dxos/log";
1834
1863
  var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
1835
- var addBookmark = StateEffect3.define();
1836
- var removeBookmark = StateEffect3.define();
1837
- var clearBookmarks = StateEffect3.define();
1864
+ var addBookmark = StateEffect4.define();
1865
+ var removeBookmark = StateEffect4.define();
1866
+ var clearBookmarks = StateEffect4.define();
1838
1867
  var bookmarks = () => {
1839
1868
  return [
1840
1869
  bookmarksField,
@@ -1843,12 +1872,7 @@ var bookmarks = () => {
1843
1872
  key: "Mod-ArrowUp",
1844
1873
  run: (view) => {
1845
1874
  const bookmarks2 = view.state.field(bookmarksField);
1846
- log6("up", bookmarks2, {
1847
- F: __dxlog_file8,
1848
- L: 29,
1849
- S: void 0,
1850
- C: (f, a) => f(...a)
1851
- });
1875
+ log6("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 18, S: void 0 });
1852
1876
  return true;
1853
1877
  }
1854
1878
  },
@@ -1856,12 +1880,7 @@ var bookmarks = () => {
1856
1880
  key: "Mod-ArrowDown",
1857
1881
  run: (view) => {
1858
1882
  const bookmarks2 = view.state.field(bookmarksField);
1859
- log6("down", bookmarks2, {
1860
- F: __dxlog_file8,
1861
- L: 37,
1862
- S: void 0,
1863
- C: (f, a) => f(...a)
1864
- });
1883
+ log6("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0 });
1865
1884
  return true;
1866
1885
  }
1867
1886
  }
@@ -1898,7 +1917,7 @@ var bookmarksField = StateField2.define({
1898
1917
 
1899
1918
  // src/extensions/comments.ts
1900
1919
  import { invertedEffects } from "@codemirror/commands";
1901
- import { StateEffect as StateEffect4, StateField as StateField3 } from "@codemirror/state";
1920
+ import { StateEffect as StateEffect5, StateField as StateField3 } from "@codemirror/state";
1902
1921
  import { Decoration as Decoration7, EditorView as EditorView11, ViewPlugin as ViewPlugin10, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
1903
1922
  import sortBy from "lodash.sortby";
1904
1923
  import { debounce as debounce2 } from "@dxos/async";
@@ -1926,28 +1945,12 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1926
1945
  };
1927
1946
  var createEditorStateStore = (keyPrefix) => ({
1928
1947
  getState: (id) => {
1929
- invariant3(id, void 0, {
1930
- F: __dxlog_file9,
1931
- L: 47,
1932
- S: void 0,
1933
- A: [
1934
- "id",
1935
- ""
1936
- ]
1937
- });
1948
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 26, S: void 0, A: ["id", ""] });
1938
1949
  const state = localStorage.getItem(`${keyPrefix}/${id}`);
1939
1950
  return state ? JSON.parse(state) : void 0;
1940
1951
  },
1941
1952
  setState: (id, state) => {
1942
- invariant3(id, void 0, {
1943
- F: __dxlog_file9,
1944
- L: 53,
1945
- S: void 0,
1946
- A: [
1947
- "id",
1948
- ""
1949
- ]
1950
- });
1953
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 31, S: void 0, A: ["id", ""] });
1951
1954
  localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
1952
1955
  }
1953
1956
  });
@@ -2000,9 +2003,9 @@ var selectionState = ({ getState, setState } = {}) => {
2000
2003
 
2001
2004
  // src/extensions/comments.ts
2002
2005
  var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
2003
- var setComments = StateEffect4.define();
2004
- var setSelection = StateEffect4.define();
2005
- var setCommentState = StateEffect4.define();
2006
+ var setComments = StateEffect5.define();
2007
+ var setSelection = StateEffect5.define();
2008
+ var setCommentState = StateEffect5.define();
2006
2009
  var commentsState = StateField3.define({
2007
2010
  create: (state) => ({
2008
2011
  id: state.facet(documentId),
@@ -2069,12 +2072,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2069
2072
  const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
2070
2073
  const range = comment.range;
2071
2074
  if (!range) {
2072
- log7.warn("Invalid range:", range, {
2073
- F: __dxlog_file10,
2074
- L: 140,
2075
- S: void 0,
2076
- C: (f, a) => f(...a)
2077
- });
2075
+ log7.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file10, L: 93, S: void 0 });
2078
2076
  return void 0;
2079
2077
  } else if (range.from === range.to) {
2080
2078
  return void 0;
@@ -2084,7 +2082,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2084
2082
  }).filter(isNonNullable);
2085
2083
  return Decoration7.set(decorations2);
2086
2084
  });
2087
- var commentClickedEffect = StateEffect4.define();
2085
+ var commentClickedEffect = StateEffect5.define();
2088
2086
  var handleCommentClick = EditorView11.domEventHandlers({
2089
2087
  click: (event, view) => {
2090
2088
  let target = event.target;
@@ -2187,10 +2185,10 @@ var trackPastedComments = (onUpdate) => {
2187
2185
  const { comments: comments2 } = update2.startState.field(commentsState);
2188
2186
  const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
2189
2187
  if (!exists) {
2190
- const cursor2 = Cursor.getCursorFromRange(update2.state, comment);
2188
+ const cursor = Cursor.getCursorFromRange(update2.state, comment);
2191
2189
  onUpdate({
2192
2190
  id: comment.id,
2193
- cursor: cursor2
2191
+ cursor
2194
2192
  });
2195
2193
  }
2196
2194
  }
@@ -2202,7 +2200,7 @@ var mapTrackedComment = (comment, changes) => ({
2202
2200
  from: changes.mapPos(comment.from, 1),
2203
2201
  to: changes.mapPos(comment.to, 1)
2204
2202
  });
2205
- var restoreCommentEffect = StateEffect4.define({
2203
+ var restoreCommentEffect = StateEffect5.define({
2206
2204
  map: mapTrackedComment
2207
2205
  });
2208
2206
  var createComment = (view) => {
@@ -2219,13 +2217,13 @@ var createComment = (view) => {
2219
2217
  }
2220
2218
  });
2221
2219
  }
2222
- const cursor2 = Cursor.getCursorFromRange(view.state, {
2220
+ const cursor = Cursor.getCursorFromRange(view.state, {
2223
2221
  from,
2224
2222
  to
2225
2223
  });
2226
- if (cursor2) {
2224
+ if (cursor) {
2227
2225
  options.onCreate?.({
2228
- cursor: cursor2,
2226
+ cursor,
2229
2227
  from,
2230
2228
  location: view.coordsAtPos(from)
2231
2229
  });
@@ -2466,7 +2464,7 @@ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap }
2466
2464
  import { HighlightStyle, bracketMatching, syntaxHighlighting } from "@codemirror/language";
2467
2465
  import { searchKeymap } from "@codemirror/search";
2468
2466
  import { EditorState } from "@codemirror/state";
2469
- 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";
2470
2468
  import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode";
2471
2469
  import defaultsDeep2 from "lodash.defaultsdeep";
2472
2470
  import { generateName } from "@dxos/display-name";
@@ -2478,28 +2476,28 @@ import { EditorView as EditorView13 } from "@codemirror/view";
2478
2476
  import { mx as mx3 } from "@dxos/ui-theme";
2479
2477
  var headings = {
2480
2478
  1: {
2481
- className: "text-4xl",
2482
- fontSize: "var(--text-4xl)",
2479
+ className: "text-3xl",
2480
+ fontSize: "var(--text-3xl)",
2483
2481
  lineHeight: "var(--text-4xl--line-height)"
2484
2482
  },
2485
2483
  2: {
2486
- className: "text-3xl",
2487
- fontSize: "var(--text-3xl)",
2484
+ className: "text-2xl",
2485
+ fontSize: "var(--text-2xl)",
2488
2486
  lineHeight: "var(--text-3xl--line-height)"
2489
2487
  },
2490
2488
  3: {
2491
- className: "text-2xl",
2492
- fontSize: "var(--text-2xl)",
2489
+ className: "text-xl",
2490
+ fontSize: "var(--text-xl)",
2493
2491
  lineHeight: "var(--text-2xl--line-height)"
2494
2492
  },
2495
2493
  4: {
2496
- className: "text-xl",
2497
- fontSize: "var(--text-xl)",
2494
+ className: "text-lg",
2495
+ fontSize: "var(--text-lg)",
2498
2496
  lineHeight: "var(--text-xl--line-height)"
2499
2497
  },
2500
2498
  5: {
2501
- className: "text-lg",
2502
- fontSize: "var(--text-lg)",
2499
+ className: "text-base",
2500
+ fontSize: "var(--text-base)",
2503
2501
  lineHeight: "var(--text-lg--line-height)"
2504
2502
  },
2505
2503
  6: {
@@ -2508,20 +2506,20 @@ var headings = {
2508
2506
  lineHeight: "var(--text-base--line-height)"
2509
2507
  }
2510
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';
2511
2511
  var markdownTheme = {
2512
- code: "font-mono no-underline! text-cm-code",
2513
- codeMark: "font-mono text-cm-code-mark",
2514
- mark: "opacity-50",
2512
+ code: "font-mono! cm-code-inline",
2513
+ codeMark: "font-mono! cm-code-mark",
2514
+ mark: "font-mono!",
2515
2515
  heading: (level) => ({
2516
- className: mx3(headings[level].className, "font-light text-cm-heading"),
2516
+ className: mx3(headings[level].className, "font-light text-(--color-cm-heading-number)"),
2517
2517
  color: "var(--color-cm-heading) !important",
2518
2518
  lineHeight: headings[level].lineHeight,
2519
2519
  fontSize: headings[level].fontSize,
2520
2520
  fontWeight: "100 !important"
2521
2521
  })
2522
2522
  };
2523
- var fontBody = "Inter Variable, ui-sans-serif, system-ui, sans-serif";
2524
- var fontMono = "JetBrains Mono Variable, ui-monospace, Cascadia Code, Source Code Pro, monospace";
2525
2523
  var baseTheme = EditorView13.baseTheme({
2526
2524
  /**
2527
2525
  * Outer frame.
@@ -2534,12 +2532,21 @@ var baseTheme = EditorView13.baseTheme({
2534
2532
  * Scroller
2535
2533
  */
2536
2534
  ".cm-scroller": {
2537
- 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"
2538
2539
  },
2539
2540
  ".cm-scroller::-webkit-scrollbar": {
2540
- 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"
2541
2549
  },
2542
- ".cm-scroller::-webkit-scrollbar-track": {},
2543
2550
  ".cm-scroller::-webkit-scrollbar-thumb": {
2544
2551
  background: "transparent",
2545
2552
  transition: "background 0.15s"
@@ -2553,7 +2560,6 @@ var baseTheme = EditorView13.baseTheme({
2553
2560
  */
2554
2561
  ".cm-content": {
2555
2562
  padding: "unset",
2556
- lineHeight: "24px",
2557
2563
  color: "unset"
2558
2564
  },
2559
2565
  /**
@@ -2584,9 +2590,16 @@ var baseTheme = EditorView13.baseTheme({
2584
2590
  * Line.
2585
2591
  */
2586
2592
  ".cm-line": {
2587
- lineHeight: "24px",
2593
+ lineHeight: 1.5,
2588
2594
  paddingInline: 0
2589
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
+ },
2590
2603
  ".cm-activeLine": {
2591
2604
  background: "var(--color-cm-active-line)"
2592
2605
  },
@@ -2764,10 +2777,9 @@ var editorGutter = EditorView13.theme({
2764
2777
  }
2765
2778
  });
2766
2779
  var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2767
- // Set metrics on the scroller (this is often what CM uses for layout).
2780
+ // Main content.
2768
2781
  ".cm-scroller": {
2769
- fontFamily: monospace ? fontMono : fontBody,
2770
- fontSize: "16px"
2782
+ fontFamily: monospace ? fontMono : fontBody
2771
2783
  },
2772
2784
  // Maintain defaults for UI components.
2773
2785
  ".cm-content, .cm-gutters, .cm-panel": {
@@ -2777,9 +2789,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2777
2789
  });
2778
2790
 
2779
2791
  // src/extensions/focus.ts
2780
- import { StateEffect as StateEffect5, StateField as StateField5 } from "@codemirror/state";
2792
+ import { StateEffect as StateEffect6, StateField as StateField5 } from "@codemirror/state";
2781
2793
  import { EditorView as EditorView14 } from "@codemirror/view";
2782
- var focusEffect = StateEffect5.define();
2794
+ var focusEffect = StateEffect6.define();
2783
2795
  var focusField = StateField5.define({
2784
2796
  create: () => false,
2785
2797
  update: (value, tr) => {
@@ -2807,9 +2819,32 @@ var focus = [
2807
2819
  })
2808
2820
  ];
2809
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
+
2810
2845
  // src/extensions/factories.ts
2811
2846
  var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
2812
- var tabbable = EditorView15.contentAttributes.of({
2847
+ var tabbable = EditorView16.contentAttributes.of({
2813
2848
  tabindex: "0"
2814
2849
  });
2815
2850
  var filterChars = (chars) => {
@@ -2862,13 +2897,8 @@ var createBasicExtensions = (propsProp) => {
2862
2897
  const props = defaultsDeep2({}, propsProp, defaultBasicOptions);
2863
2898
  return [
2864
2899
  // NOTE: Doesn't catch errors in keymap functions.
2865
- EditorView15.exceptionSink.of((err) => {
2866
- log8.catch(err, void 0, {
2867
- F: __dxlog_file11,
2868
- L: 131,
2869
- S: void 0,
2870
- C: (f, a) => f(...a)
2871
- });
2900
+ EditorView16.exceptionSink.of((err) => {
2901
+ log8.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file11, L: 79, S: void 0 });
2872
2902
  }),
2873
2903
  props.allowMultipleSelections && EditorState.allowMultipleSelections.of(true),
2874
2904
  props.bracketMatching && bracketMatching(),
@@ -2877,7 +2907,7 @@ var createBasicExtensions = (propsProp) => {
2877
2907
  props.drawSelection && drawSelection({
2878
2908
  cursorBlinkRate: 1200
2879
2909
  }),
2880
- props.editable !== void 0 && EditorView15.editable.of(props.editable),
2910
+ props.editable !== void 0 && EditorView16.editable.of(props.editable),
2881
2911
  props.focus && focus,
2882
2912
  props.highlightActiveLine && highlightActiveLine(),
2883
2913
  props.history && history(),
@@ -2885,9 +2915,16 @@ var createBasicExtensions = (propsProp) => {
2885
2915
  lineNumbers(),
2886
2916
  editorGutter
2887
2917
  ],
2888
- props.lineWrapping && EditorView15.lineWrapping,
2918
+ props.lineWrapping && EditorView16.lineWrapping,
2889
2919
  props.placeholder && placeholder2(props.placeholder),
2890
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),
2891
2928
  props.scrollPastEnd && scrollPastEnd(),
2892
2929
  props.tabbable && tabbable,
2893
2930
  props.tabSize && EditorState.tabSize.of(props.tabSize),
@@ -2930,24 +2967,29 @@ var defaultStyles = {
2930
2967
  dark: vscodeDarkStyle,
2931
2968
  light: vscodeLightStyle
2932
2969
  };
2933
- var createThemeExtensions = ({ monospace, themeMode, slots: slotsProp, syntaxHighlighting: syntaxHighlightingProp } = {}) => {
2970
+ var createThemeExtensions = ({ monospace, scrollbarThin, slots: slotsProp, syntaxHighlighting: syntaxHighlightingProp, themeMode } = {}) => {
2934
2971
  const slots = defaultsDeep2({}, slotsProp, defaultThemeSlots);
2935
2972
  return [
2936
2973
  baseTheme,
2937
- EditorView15.darkTheme.of(themeMode === "dark"),
2974
+ EditorView16.darkTheme.of(themeMode === "dark"),
2938
2975
  createFontTheme({
2939
2976
  monospace
2940
2977
  }),
2941
2978
  syntaxHighlightingProp && syntaxHighlighting(HighlightStyle.define(themeMode === "dark" ? defaultStyles.dark : defaultStyles.light)),
2942
- slots.editor?.className && EditorView15.editorAttributes.of({
2979
+ slots.editor?.className && EditorView16.editorAttributes.of({
2943
2980
  class: slots.editor.className
2944
2981
  }),
2945
- slots.content?.className && EditorView15.contentAttributes.of({
2982
+ slots.content?.className && EditorView16.contentAttributes.of({
2946
2983
  class: slots.content.className
2947
2984
  }),
2948
- slots.scroll?.className && ViewPlugin11.fromClass(class {
2985
+ (slots.scroller?.className || scrollbarThin) && ViewPlugin12.fromClass(class {
2949
2986
  constructor(view) {
2950
- 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
+ }
2951
2993
  }
2952
2994
  })
2953
2995
  ].filter(isTruthy2);
@@ -2976,7 +3018,7 @@ var createDataExtensions = ({ id, text, messenger, identity }) => {
2976
3018
 
2977
3019
  // src/extensions/folding.ts
2978
3020
  import { codeFolding, foldGutter } from "@codemirror/language";
2979
- import { EditorView as EditorView16 } from "@codemirror/view";
3021
+ import { EditorView as EditorView17 } from "@codemirror/view";
2980
3022
  import { Domino as Domino2, mx as mx4 } from "@dxos/ui";
2981
3023
  var folding = () => {
2982
3024
  return [
@@ -2984,13 +3026,14 @@ var folding = () => {
2984
3026
  placeholderDOM: () => Domino2.of("span").root
2985
3027
  }),
2986
3028
  foldGutter({
3029
+ // NOTE: We can't animate since the element is remounted on state change.
2987
3030
  markerDOM: (open) => {
2988
- 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({
2989
3032
  href: Domino2.icon("ph--caret-right--regular")
2990
3033
  }))).root;
2991
3034
  }
2992
3035
  }),
2993
- EditorView16.theme({
3036
+ EditorView17.theme({
2994
3037
  ".cm-foldGutter": {
2995
3038
  opacity: 0.3,
2996
3039
  transition: "opacity 0.3s",
@@ -3004,7 +3047,7 @@ var folding = () => {
3004
3047
  };
3005
3048
 
3006
3049
  // src/extensions/hashtag.ts
3007
- 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";
3008
3051
  import { getHashStyles, mx as mx5 } from "@dxos/ui-theme";
3009
3052
  var TagWidget = class extends WidgetType4 {
3010
3053
  _text;
@@ -3025,7 +3068,7 @@ var tagMatcher = new MatchDecorator({
3025
3068
  })
3026
3069
  });
3027
3070
  var hashtag = () => [
3028
- ViewPlugin12.fromClass(class {
3071
+ ViewPlugin13.fromClass(class {
3029
3072
  tags;
3030
3073
  constructor(view) {
3031
3074
  this.tags = tagMatcher.createDeco(view);
@@ -3035,11 +3078,11 @@ var hashtag = () => [
3035
3078
  }
3036
3079
  }, {
3037
3080
  decorations: (instance) => instance.tags,
3038
- provide: (plugin) => EditorView17.atomicRanges.of((view) => {
3081
+ provide: (plugin) => EditorView18.atomicRanges.of((view) => {
3039
3082
  return view.plugin(plugin)?.tags || Decoration8.none;
3040
3083
  })
3041
3084
  }),
3042
- EditorView17.theme({
3085
+ EditorView18.theme({
3043
3086
  ".cm-tag": {
3044
3087
  borderRadius: "4px",
3045
3088
  marginRight: "6px",
@@ -3094,18 +3137,18 @@ var schemaLinter = (validate) => (view) => {
3094
3137
  };
3095
3138
 
3096
3139
  // src/extensions/listener.ts
3097
- import { EditorView as EditorView18 } from "@codemirror/view";
3140
+ import { EditorView as EditorView19 } from "@codemirror/view";
3098
3141
  import { isNonNullable as isNonNullable2 } from "@dxos/util";
3099
3142
  var listener = ({ onFocus, onChange }) => {
3100
3143
  return [
3101
- onFocus && EditorView18.focusChangeEffect.of((state, focusing) => {
3144
+ onFocus && EditorView19.focusChangeEffect.of((state, focusing) => {
3102
3145
  onFocus({
3103
3146
  id: state.facet(documentId),
3104
3147
  focusing
3105
3148
  });
3106
3149
  return null;
3107
3150
  }),
3108
- onChange && EditorView18.updateListener.of(({ state, docChanged }) => {
3151
+ onChange && EditorView19.updateListener.of(({ state, docChanged }) => {
3109
3152
  if (docChanged) {
3110
3153
  onChange({
3111
3154
  id: state.facet(documentId),
@@ -3120,7 +3163,7 @@ var listener = ({ onFocus, onChange }) => {
3120
3163
  import { snippet } from "@codemirror/autocomplete";
3121
3164
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3122
3165
  import { EditorSelection as EditorSelection2 } from "@codemirror/state";
3123
- import { EditorView as EditorView19, keymap as keymap8 } from "@codemirror/view";
3166
+ import { EditorView as EditorView20, keymap as keymap8 } from "@codemirror/view";
3124
3167
  import { debounceAndThrottle } from "@dxos/async";
3125
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;
3126
3169
  var Inline = /* @__PURE__ */ (function(Inline2) {
@@ -4209,7 +4252,7 @@ var getFormatting = (state) => {
4209
4252
  };
4210
4253
  };
4211
4254
  var formattingListener = (onStateChange, delay = 100) => {
4212
- return EditorView19.updateListener.of(debounceAndThrottle((update2) => {
4255
+ return EditorView20.updateListener.of(debounceAndThrottle((update2) => {
4213
4256
  if (update2.docChanged || update2.selectionSet) {
4214
4257
  onStateChange(getFormatting(update2.state));
4215
4258
  }
@@ -4270,8 +4313,7 @@ import { completionKeymap } from "@codemirror/autocomplete";
4270
4313
  import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
4271
4314
  import { jsonLanguage } from "@codemirror/lang-json";
4272
4315
  import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
4273
- import { xml } from "@codemirror/lang-xml";
4274
- import { LanguageDescription, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4316
+ import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4275
4317
  import { languages } from "@codemirror/language-data";
4276
4318
  import { keymap as keymap9 } from "@codemirror/view";
4277
4319
  import { isTruthy as isTruthy3 } from "@dxos/util";
@@ -4281,11 +4323,6 @@ import { markdownLanguage } from "@codemirror/lang-markdown";
4281
4323
  import { HighlightStyle as HighlightStyle2 } from "@codemirror/language";
4282
4324
  import { Tag, styleTags, tags } from "@lezer/highlight";
4283
4325
  import { Table } from "@lezer/markdown";
4284
- var styles4 = {
4285
- code: "font-mono no-underline! text-cm-code",
4286
- codeMark: "font-mono text-cm-code-mark",
4287
- mark: "opacity-50"
4288
- };
4289
4326
  var markdownTags = {
4290
4327
  Blockquote: Tag.define(),
4291
4328
  CodeMark: Tag.define(),
@@ -4367,7 +4404,7 @@ var markdownHighlightStyle = (_options = {}) => {
4367
4404
  markdownTags.LinkReference,
4368
4405
  markdownTags.ListMark
4369
4406
  ],
4370
- class: styles4.mark
4407
+ class: markdownTheme.mark
4371
4408
  },
4372
4409
  // Markdown marks.
4373
4410
  {
@@ -4378,7 +4415,7 @@ var markdownHighlightStyle = (_options = {}) => {
4378
4415
  markdownTags.QuoteMark,
4379
4416
  markdownTags.EmphasisMark
4380
4417
  ],
4381
- class: styles4.mark
4418
+ class: markdownTheme.mark
4382
4419
  },
4383
4420
  // E.g., code block language (after ```).
4384
4421
  {
@@ -4387,7 +4424,7 @@ var markdownHighlightStyle = (_options = {}) => {
4387
4424
  tags.function(tags.variableName),
4388
4425
  tags.labelName
4389
4426
  ],
4390
- class: styles4.codeMark
4427
+ class: markdownTheme.codeMark
4391
4428
  },
4392
4429
  // Fonts.
4393
4430
  {
@@ -4453,7 +4490,7 @@ var markdownHighlightStyle = (_options = {}) => {
4453
4490
  markdownTags.CodeText,
4454
4491
  markdownTags.InlineCode
4455
4492
  ],
4456
- class: styles4.code
4493
+ class: markdownTheme.code
4457
4494
  },
4458
4495
  {
4459
4496
  tag: [
@@ -4483,15 +4520,23 @@ var createMarkdownExtensions = (options = {}) => {
4483
4520
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
4484
4521
  base: markdownLanguage2,
4485
4522
  // Languages for syntax highlighting fenced code blocks.
4523
+ // Caller-supplied languages are checked first so they can override defaults.
4486
4524
  defaultCodeLanguage: jsonLanguage,
4487
- codeLanguages: languages,
4525
+ codeLanguages: [
4526
+ ...options.codeLanguages ?? [],
4527
+ ...languages
4528
+ ],
4488
4529
  // Don't complete HTML tags.
4489
4530
  completeHTMLTags: false,
4490
4531
  // Parser extensions.
4491
4532
  extensions: [
4492
4533
  // GFM provided by default.
4493
4534
  markdownTagsExtensions,
4494
- ...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
4495
4540
  ]
4496
4541
  }),
4497
4542
  // Custom styles.
@@ -4506,18 +4551,13 @@ var createMarkdownExtensions = (options = {}) => {
4506
4551
  ].filter(isTruthy3))
4507
4552
  ];
4508
4553
  };
4509
- var xmlLanguageDesc = LanguageDescription.of({
4510
- name: "xml",
4511
- alias: [
4512
- "html",
4513
- "xhtml"
4514
- ],
4515
- extensions: [
4516
- "xml",
4517
- "xhtml"
4518
- ],
4519
- load: async () => xml()
4520
- });
4554
+ var noFencedCodeFolding = {
4555
+ props: [
4556
+ foldNodeProp.add({
4557
+ FencedCode: () => null
4558
+ })
4559
+ ]
4560
+ };
4521
4561
  var defaultExtensions = () => [
4522
4562
  noSetExtHeading,
4523
4563
  noHtml
@@ -4537,19 +4577,19 @@ var debugTree = (cb) => StateField6.define({
4537
4577
  update: (value, tr) => cb(convertTreeToJson(tr.state))
4538
4578
  });
4539
4579
  var convertTreeToJson = (state) => {
4540
- const treeToJson = (cursor2) => {
4580
+ const treeToJson = (cursor) => {
4541
4581
  const node = {
4542
- type: cursor2.type.name,
4543
- from: cursor2.from,
4544
- to: cursor2.to,
4545
- 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(),
4546
4586
  children: []
4547
4587
  };
4548
- if (cursor2.firstChild()) {
4588
+ if (cursor.firstChild()) {
4549
4589
  do {
4550
- node.children.push(treeToJson(cursor2));
4551
- } while (cursor2.nextSibling());
4552
- cursor2.parent();
4590
+ node.children.push(treeToJson(cursor));
4591
+ } while (cursor.nextSibling());
4592
+ cursor.parent();
4553
4593
  }
4554
4594
  return node;
4555
4595
  };
@@ -4558,17 +4598,16 @@ var convertTreeToJson = (state) => {
4558
4598
 
4559
4599
  // src/extensions/markdown/decorate.ts
4560
4600
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4561
- import { Prec as Prec4, RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect6 } from "@codemirror/state";
4562
- 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";
4563
4603
  import { invariant as invariant4 } from "@dxos/invariant";
4564
- import { mx as mx6 } from "@dxos/ui-theme";
4565
4604
 
4566
4605
  // src/extensions/markdown/changes.ts
4567
4606
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
4568
4607
  import { Transaction as Transaction4 } from "@codemirror/state";
4569
- import { ViewPlugin as ViewPlugin13 } from "@codemirror/view";
4608
+ import { ViewPlugin as ViewPlugin14 } from "@codemirror/view";
4570
4609
  var adjustChanges = () => {
4571
- return ViewPlugin13.fromClass(class {
4610
+ return ViewPlugin14.fromClass(class {
4572
4611
  update(update2) {
4573
4612
  const tree = syntaxTree4(update2.state);
4574
4613
  const adjustments = [];
@@ -4710,7 +4749,7 @@ var getValidUrl = (str) => {
4710
4749
  // src/extensions/markdown/image.ts
4711
4750
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4712
4751
  import { StateField as StateField7 } from "@codemirror/state";
4713
- 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";
4714
4753
  var image = (_options = {}) => {
4715
4754
  return [
4716
4755
  StateField7.define({
@@ -4721,10 +4760,10 @@ var image = (_options = {}) => {
4721
4760
  if (!tr.docChanged && !tr.selection) {
4722
4761
  return value;
4723
4762
  }
4724
- const cursor2 = tr.state.selection.main.head;
4763
+ const cursor = tr.state.selection.main.head;
4725
4764
  const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
4726
- let from = Math.min(cursor2, oldCursor);
4727
- let to = Math.max(cursor2, oldCursor);
4765
+ let from = Math.min(cursor, oldCursor);
4766
+ let to = Math.max(cursor, oldCursor);
4728
4767
  tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
4729
4768
  from = Math.min(from, fromB);
4730
4769
  to = Math.max(to, toB);
@@ -4738,19 +4777,19 @@ var image = (_options = {}) => {
4738
4777
  add: buildDecorations(tr.state, from, to)
4739
4778
  });
4740
4779
  },
4741
- provide: (field) => EditorView20.decorations.from(field)
4780
+ provide: (field) => EditorView21.decorations.from(field)
4742
4781
  })
4743
4782
  ];
4744
4783
  };
4745
4784
  var buildDecorations = (state, from, to) => {
4746
4785
  const decorations2 = [];
4747
- const cursor2 = state.selection.main.head;
4786
+ const cursor = state.selection.main.head;
4748
4787
  syntaxTree5(state).iterate({
4749
4788
  enter: (node) => {
4750
4789
  if (node.name === "Image") {
4751
4790
  const urlNode = node.node.getChild("URL");
4752
4791
  if (urlNode) {
4753
- 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);
4754
4793
  const url = state.sliceDoc(urlNode.from, urlNode.to);
4755
4794
  if (url.match(/^https?:\/\//) === null && url.match(/^file?:\/\//) === null) {
4756
4795
  return;
@@ -4798,10 +4837,10 @@ var ImageWidget = class extends WidgetType5 {
4798
4837
  };
4799
4838
 
4800
4839
  // src/extensions/markdown/styles.ts
4801
- import { EditorView as EditorView21 } from "@codemirror/view";
4840
+ import { EditorView as EditorView22 } from "@codemirror/view";
4802
4841
  var bulletListIndentationWidth = 24;
4803
4842
  var orderedListIndentationWidth = 36;
4804
- var formattingStyles = EditorView21.theme({
4843
+ var formattingStyles = EditorView22.theme({
4805
4844
  /**
4806
4845
  * Horizontal rule.
4807
4846
  */
@@ -4836,13 +4875,38 @@ var formattingStyles = EditorView21.theme({
4836
4875
  background: "var(--color-cm-codeblock)",
4837
4876
  borderLeft: "2px solid var(--color-cm-separator)",
4838
4877
  paddingLeft: "1rem",
4839
- margin: "0"
4878
+ margin: 0
4840
4879
  },
4841
4880
  /**
4842
4881
  * Code and codeblocks.
4843
4882
  */
4883
+ "& code": {
4884
+ fontFamily: fontMono,
4885
+ color: "var(--color-cm-code)",
4886
+ whiteSpace: "nowrap"
4887
+ },
4844
4888
  "& .cm-code": {
4845
- 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"
4846
4910
  },
4847
4911
  "& .cm-codeblock-line": {
4848
4912
  background: "var(--color-cm-codeblock)",
@@ -4874,16 +4938,24 @@ var formattingStyles = EditorView21.theme({
4874
4938
  */
4875
4939
  ".cm-table *": {
4876
4940
  fontFamily: fontMono,
4941
+ lineHeight: 1.5,
4877
4942
  textDecoration: "none !important"
4878
4943
  },
4879
4944
  ".cm-table-head": {
4880
4945
  padding: "2px 16px 2px 0px",
4946
+ overflowWrap: "break-word",
4947
+ whiteSpace: "pre-wrap",
4948
+ wordBreak: "keep-all",
4881
4949
  textAlign: "left",
4882
- borderBottom: "1px solid var(--color-cm-separator)",
4883
- color: "var(--color-subdued)"
4950
+ color: "var(--color-subdued)",
4951
+ borderBottom: "1px solid var(--color-cm-separator)"
4884
4952
  },
4885
4953
  ".cm-table-cell": {
4886
- 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"
4887
4959
  },
4888
4960
  /**
4889
4961
  * Image.
@@ -4899,12 +4971,12 @@ var formattingStyles = EditorView21.theme({
4899
4971
  },
4900
4972
  ".cm-image-with-loader": {
4901
4973
  display: "block",
4902
- opacity: "0",
4974
+ opacity: 0,
4903
4975
  transitionDuration: "350ms",
4904
4976
  transitionProperty: "opacity"
4905
4977
  },
4906
4978
  ".cm-image-with-loader.cm-loaded-image": {
4907
- opacity: "1"
4979
+ opacity: 1
4908
4980
  },
4909
4981
  ".cm-image-wrapper": {
4910
4982
  "grid-template-columns": "1fr",
@@ -4923,17 +4995,17 @@ var formattingStyles = EditorView21.theme({
4923
4995
  // src/extensions/markdown/table.ts
4924
4996
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4925
4997
  import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField8 } from "@codemirror/state";
4926
- 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";
4927
4999
  var table = (options = {}) => {
4928
5000
  return StateField8.define({
4929
5001
  create: (state) => update(state, options),
4930
5002
  update: (_, tr) => update(tr.state, options),
4931
- provide: (field) => EditorView22.decorations.from(field)
5003
+ provide: (field) => EditorView23.decorations.from(field)
4932
5004
  });
4933
5005
  };
4934
5006
  var update = (state, _options) => {
4935
5007
  const builder = new RangeSetBuilder4();
4936
- const cursor2 = state.selection.main.head;
5008
+ const cursor = state.selection.main.head;
4937
5009
  const tables = [];
4938
5010
  const getTable = () => tables[tables.length - 1];
4939
5011
  const getRow = () => {
@@ -4971,7 +5043,7 @@ var update = (state, _options) => {
4971
5043
  }
4972
5044
  });
4973
5045
  tables.forEach((table2) => {
4974
- const replace = state.readOnly || cursor2 < table2.from || cursor2 > table2.to;
5046
+ const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4975
5047
  if (replace) {
4976
5048
  builder.add(table2.from, table2.to, Decoration10.replace({
4977
5049
  block: true,
@@ -4985,6 +5057,26 @@ var update = (state, _options) => {
4985
5057
  });
4986
5058
  return builder.finish();
4987
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
+ };
4988
5080
  var TableWidget = class extends WidgetType6 {
4989
5081
  _table;
4990
5082
  constructor(_table) {
@@ -5004,7 +5096,7 @@ var TableWidget = class extends WidgetType6 {
5004
5096
  this._table.header?.forEach((cell) => {
5005
5097
  const th = document.createElement("th");
5006
5098
  th.setAttribute("class", "cm-table-head");
5007
- tr.appendChild(th).textContent = cell;
5099
+ renderCellContent(tr.appendChild(th), cell);
5008
5100
  });
5009
5101
  const body = table2.appendChild(document.createElement("tbody"));
5010
5102
  this._table.rows?.forEach((row) => {
@@ -5012,7 +5104,7 @@ var TableWidget = class extends WidgetType6 {
5012
5104
  row.forEach((cell) => {
5013
5105
  const td = document.createElement("td");
5014
5106
  td.setAttribute("class", "cm-table-cell");
5015
- tr2.appendChild(td).textContent = cell;
5107
+ renderCellContent(tr2.appendChild(td), cell);
5016
5108
  });
5017
5109
  });
5018
5110
  return div;
@@ -5119,10 +5211,10 @@ var fencedCodeLine = Decoration11.line({
5119
5211
  class: "cm-code cm-codeblock-line"
5120
5212
  });
5121
5213
  var fencedCodeLineFirst = Decoration11.line({
5122
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-start")
5214
+ class: "cm-code cm-codeblock-line cm-codeblock-start"
5123
5215
  });
5124
5216
  var fencedCodeLineLast = Decoration11.line({
5125
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-end")
5217
+ class: "cm-code cm-codeblock-line cm-codeblock-end"
5126
5218
  });
5127
5219
  var commentBlockLine = fencedCodeLine;
5128
5220
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -5154,15 +5246,7 @@ var buildDecorations2 = (view, options, focus2) => {
5154
5246
  const { state } = view;
5155
5247
  const headerLevels = [];
5156
5248
  const getHeaderLevels = (node, level) => {
5157
- invariant4(level > 0, void 0, {
5158
- F: __dxlog_file12,
5159
- L: 179,
5160
- S: void 0,
5161
- A: [
5162
- "level > 0",
5163
- ""
5164
- ]
5165
- });
5249
+ invariant4(level > 0, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file12, L: 160, S: void 0, A: ["level > 0", ""] });
5166
5250
  if (level > headerLevels.length) {
5167
5251
  const len = headerLevels.length;
5168
5252
  headerLevels.length = level;
@@ -5193,15 +5277,7 @@ var buildDecorations2 = (view, options, focus2) => {
5193
5277
  listLevels.pop();
5194
5278
  };
5195
5279
  const getCurrentListLevel = () => {
5196
- invariant4(listLevels.length, void 0, {
5197
- F: __dxlog_file12,
5198
- L: 201,
5199
- S: void 0,
5200
- A: [
5201
- "listLevels.length",
5202
- ""
5203
- ]
5204
- });
5280
+ invariant4(listLevels.length, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file12, L: 192, S: void 0, A: ["listLevels.length", ""] });
5205
5281
  return listLevels[listLevels.length - 1];
5206
5282
  };
5207
5283
  const enterNode = (node) => {
@@ -5239,7 +5315,7 @@ var buildDecorations2 = (view, options, focus2) => {
5239
5315
  deco: hide
5240
5316
  });
5241
5317
  } else {
5242
- 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(".") + "). ";
5243
5319
  if (num.length) {
5244
5320
  atomicDecoRanges.push({
5245
5321
  from: mark.from,
@@ -5422,11 +5498,11 @@ var buildDecorations2 = (view, options, focus2) => {
5422
5498
  }
5423
5499
  decoRanges.push({
5424
5500
  from: marks[0].to,
5425
- to: marks[1].from,
5501
+ to: !editing && options.renderLinkButton ? node.to : marks[1].from,
5426
5502
  deco: Decoration11.mark({
5427
5503
  tagName: "a",
5428
5504
  attributes: {
5429
- class: "cm-link",
5505
+ class: options.renderLinkButton ? "cm-link cm-link-with-button" : "cm-link",
5430
5506
  href: url,
5431
5507
  rel: "noreferrer",
5432
5508
  target: "_blank"
@@ -5504,18 +5580,21 @@ var buildDecorations2 = (view, options, focus2) => {
5504
5580
  deco.add(from, to, d);
5505
5581
  }
5506
5582
  const atomicDeco = new RangeSetBuilder5();
5507
- for (const { from, to, deco: d } of atomicDecoRanges) {
5508
- 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);
5509
5588
  }
5510
5589
  return {
5511
5590
  deco: deco.finish(),
5512
5591
  atomicDeco: atomicDeco.finish()
5513
5592
  };
5514
5593
  };
5515
- var forceUpdate = StateEffect6.define();
5594
+ var forceUpdate = StateEffect7.define();
5516
5595
  var decorateMarkdown = (options = {}) => {
5517
5596
  return [
5518
- ViewPlugin14.fromClass(class {
5597
+ ViewPlugin15.fromClass(class {
5519
5598
  deco;
5520
5599
  atomicDeco;
5521
5600
  pendingUpdate;
@@ -5550,9 +5629,9 @@ var decorateMarkdown = (options = {}) => {
5550
5629
  }
5551
5630
  }, {
5552
5631
  provide: (plugin) => [
5553
- Prec4.low(EditorView23.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration11.none)),
5554
- EditorView23.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none),
5555
- 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)
5556
5635
  ]
5557
5636
  }),
5558
5637
  image(),
@@ -5620,12 +5699,7 @@ var mention = ({ debug, onSearch }) => {
5620
5699
  (context) => {
5621
5700
  log9.info("completion context", {
5622
5701
  context
5623
- }, {
5624
- F: __dxlog_file13,
5625
- L: 27,
5626
- S: void 0,
5627
- C: (f, a) => f(...a)
5628
- });
5702
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file13, L: 18, S: void 0 });
5629
5703
  const match = context.matchBefore(/@(\w+)?/);
5630
5704
  if (!match || match.from === match.to && !context.explicit) {
5631
5705
  return null;
@@ -5642,8 +5716,8 @@ var mention = ({ debug, onSearch }) => {
5642
5716
  };
5643
5717
 
5644
5718
  // src/extensions/modal.ts
5645
- import { StateEffect as StateEffect7, StateField as StateField9 } from "@codemirror/state";
5646
- var modalStateEffect = StateEffect7.define();
5719
+ import { StateEffect as StateEffect8, StateField as StateField9 } from "@codemirror/state";
5720
+ var modalStateEffect = StateEffect8.define();
5647
5721
  var modalStateField = StateField9.define({
5648
5722
  create: () => false,
5649
5723
  update: (value, tr) => {
@@ -5858,15 +5932,7 @@ var outlinerTree = (_options = {}) => {
5858
5932
  break;
5859
5933
  }
5860
5934
  case "BulletList": {
5861
- invariant5(current, void 0, {
5862
- F: __dxlog_file14,
5863
- L: 219,
5864
- S: void 0,
5865
- A: [
5866
- "current",
5867
- ""
5868
- ]
5869
- });
5935
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 169, S: void 0, A: ["current", ""] });
5870
5936
  parent = current;
5871
5937
  if (current) {
5872
5938
  current.lineRange.to = current.node.from;
@@ -5875,15 +5941,7 @@ var outlinerTree = (_options = {}) => {
5875
5941
  break;
5876
5942
  }
5877
5943
  case "ListItem": {
5878
- invariant5(parent, void 0, {
5879
- F: __dxlog_file14,
5880
- L: 228,
5881
- S: void 0,
5882
- A: [
5883
- "parent",
5884
- ""
5885
- ]
5886
- });
5944
+ invariant5(parent, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 179, S: void 0, A: ["parent", ""] });
5887
5945
  const nextSibling = node.node.nextSibling ?? node.node.parent?.nextSibling;
5888
5946
  const docRange = {
5889
5947
  from: state.doc.lineAt(node.from).from,
@@ -5917,42 +5975,18 @@ var outlinerTree = (_options = {}) => {
5917
5975
  break;
5918
5976
  }
5919
5977
  case "ListMark": {
5920
- invariant5(current, void 0, {
5921
- F: __dxlog_file14,
5922
- L: 272,
5923
- S: void 0,
5924
- A: [
5925
- "current",
5926
- ""
5927
- ]
5928
- });
5978
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 219, S: void 0, A: ["current", ""] });
5929
5979
  current.type = "bullet";
5930
5980
  current.contentRange.from = node.from + "- ".length;
5931
5981
  break;
5932
5982
  }
5933
5983
  case "Task": {
5934
- invariant5(current, void 0, {
5935
- F: __dxlog_file14,
5936
- L: 278,
5937
- S: void 0,
5938
- A: [
5939
- "current",
5940
- ""
5941
- ]
5942
- });
5984
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 226, S: void 0, A: ["current", ""] });
5943
5985
  current.type = "task";
5944
5986
  break;
5945
5987
  }
5946
5988
  case "TaskMarker": {
5947
- invariant5(current, void 0, {
5948
- F: __dxlog_file14,
5949
- L: 283,
5950
- S: void 0,
5951
- A: [
5952
- "current",
5953
- ""
5954
- ]
5955
- });
5989
+ invariant5(current, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 232, S: void 0, A: ["current", ""] });
5956
5990
  current.contentRange.from = node.from + "[ ] ".length;
5957
5991
  break;
5958
5992
  }
@@ -5960,29 +5994,13 @@ var outlinerTree = (_options = {}) => {
5960
5994
  },
5961
5995
  leave: (node) => {
5962
5996
  if (node.name === "BulletList") {
5963
- invariant5(parent, void 0, {
5964
- F: __dxlog_file14,
5965
- L: 291,
5966
- S: void 0,
5967
- A: [
5968
- "parent",
5969
- ""
5970
- ]
5971
- });
5997
+ invariant5(parent, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 240, S: void 0, A: ["parent", ""] });
5972
5998
  prevSiblings[level--] = void 0;
5973
5999
  parent = parent.parent;
5974
6000
  }
5975
6001
  }
5976
6002
  });
5977
- invariant5(tree, void 0, {
5978
- F: __dxlog_file14,
5979
- L: 298,
5980
- S: void 0,
5981
- A: [
5982
- "tree",
5983
- ""
5984
- ]
5985
- });
6003
+ invariant5(tree, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file14, L: 246, S: void 0, A: ["tree", ""] });
5986
6004
  return tree;
5987
6005
  };
5988
6006
  return [
@@ -6267,17 +6285,17 @@ var commands = () => keymap11.of([
6267
6285
 
6268
6286
  // src/extensions/outliner/outliner.ts
6269
6287
  import { Prec as Prec5 } from "@codemirror/state";
6270
- import { Decoration as Decoration12, EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6271
- 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";
6272
6290
 
6273
6291
  // src/extensions/outliner/editor.ts
6274
6292
  import { EditorSelection as EditorSelection4, EditorState as EditorState2 } from "@codemirror/state";
6275
- import { ViewPlugin as ViewPlugin15 } from "@codemirror/view";
6293
+ import { ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6276
6294
  import { log as log10 } from "@dxos/log";
6277
6295
  var __dxlog_file15 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/outliner/editor.ts";
6278
6296
  var LIST_ITEM_REGEX = /^\s*- (\[ \]|\[x\])? /;
6279
6297
  var initialize = () => {
6280
- return ViewPlugin15.fromClass(class {
6298
+ return ViewPlugin16.fromClass(class {
6281
6299
  constructor(view) {
6282
6300
  const first = view.state.doc.lineAt(0);
6283
6301
  const text = view.state.sliceDoc(first.from, first.to);
@@ -6424,35 +6442,20 @@ var editor = () => [
6424
6442
  text: insert.toString(),
6425
6443
  length: insert.length
6426
6444
  }
6427
- }, {
6428
- F: __dxlog_file15,
6429
- L: 164,
6430
- S: void 0,
6431
- C: (f, a) => f(...a)
6432
- });
6445
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 174, S: void 0 });
6433
6446
  }
6434
6447
  });
6435
6448
  if (changes.length > 0) {
6436
6449
  log10("modified,", {
6437
6450
  changes
6438
- }, {
6439
- F: __dxlog_file15,
6440
- L: 175,
6441
- S: void 0,
6442
- C: (f, a) => f(...a)
6443
- });
6451
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 196, S: void 0 });
6444
6452
  return [
6445
6453
  {
6446
6454
  changes
6447
6455
  }
6448
6456
  ];
6449
6457
  } else if (cancel) {
6450
- log10("cancel", void 0, {
6451
- F: __dxlog_file15,
6452
- L: 178,
6453
- S: void 0,
6454
- C: (f, a) => f(...a)
6455
- });
6458
+ log10("cancel", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file15, L: 205, S: void 0 });
6456
6459
  return [];
6457
6460
  }
6458
6461
  return tr;
@@ -6460,10 +6463,10 @@ var editor = () => [
6460
6463
  ];
6461
6464
 
6462
6465
  // src/extensions/outliner/menu.ts
6463
- import { EditorView as EditorView24, ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6466
+ import { EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6464
6467
  import { addEventListener as addEventListener2 } from "@dxos/async";
6465
6468
  var menu = (options = {}) => [
6466
- ViewPlugin16.fromClass(class {
6469
+ ViewPlugin17.fromClass(class {
6467
6470
  view;
6468
6471
  tag;
6469
6472
  rafId;
@@ -6525,7 +6528,7 @@ var menu = (options = {}) => [
6525
6528
  this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
6526
6529
  }
6527
6530
  }),
6528
- EditorView24.theme({
6531
+ EditorView25.theme({
6529
6532
  ".cm-popover-trigger": {
6530
6533
  position: "fixed",
6531
6534
  padding: "0",
@@ -6561,12 +6564,12 @@ var outliner = (_options = {}) => [
6561
6564
  listPaddingLeft: 8
6562
6565
  }),
6563
6566
  // Researve space for menu.
6564
- EditorView25.contentAttributes.of({
6567
+ EditorView26.contentAttributes.of({
6565
6568
  class: "w-full !mr-[3rem]"
6566
6569
  })
6567
6570
  ];
6568
6571
  var decorations = () => [
6569
- ViewPlugin17.fromClass(class {
6572
+ ViewPlugin18.fromClass(class {
6570
6573
  decorations = Decoration12.none;
6571
6574
  constructor(view) {
6572
6575
  this.updateDecorations(view.state, view);
@@ -6591,7 +6594,7 @@ var decorations = () => [
6591
6594
  const lineTo = doc.lineAt(item.contentRange.to);
6592
6595
  const isSelected = selection.includes(item.index) || item === current;
6593
6596
  decorations2.push(Decoration12.line({
6594
- 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"))
6595
6598
  }).range(line.from, line.from));
6596
6599
  }
6597
6600
  }
@@ -6601,7 +6604,7 @@ var decorations = () => [
6601
6604
  decorations: (v) => v.decorations
6602
6605
  }),
6603
6606
  // Theme.
6604
- EditorView25.theme(Object.assign({
6607
+ EditorView26.theme(Object.assign({
6605
6608
  ".cm-list-item": {
6606
6609
  borderLeftWidth: "1px",
6607
6610
  borderRightWidth: "1px",
@@ -6636,28 +6639,57 @@ var decorations = () => [
6636
6639
 
6637
6640
  // src/extensions/preview/preview.ts
6638
6641
  import { syntaxTree as syntaxTree10 } from "@codemirror/language";
6639
- import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField11 } from "@codemirror/state";
6640
- 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();
6641
6646
  var preview = (options = {}) => {
6647
+ const viewRef = {
6648
+ current: void 0
6649
+ };
6642
6650
  return [
6643
6651
  // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
6644
6652
  // "Block decorations may not be specified via plugins".
6645
6653
  StateField11.define({
6646
- create: (state) => buildDecorations3(state, options),
6654
+ create: (state) => buildDecorations3(state, options, viewRef),
6647
6655
  update: (decorations2, tr) => {
6648
- if (tr.docChanged) {
6649
- return buildDecorations3(tr.state, options);
6656
+ if (tr.docChanged || tr.effects.some((effect) => effect.is(labelResolvedEffect))) {
6657
+ return buildDecorations3(tr.state, options, viewRef);
6650
6658
  }
6651
6659
  return decorations2.map(tr.changes);
6652
6660
  },
6653
6661
  provide: (field) => [
6654
- EditorView26.decorations.from(field),
6655
- EditorView26.atomicRanges.of((view) => view.state.field(field))
6662
+ EditorView27.decorations.from(field),
6663
+ EditorView27.atomicRanges.of((view) => view.state.field(field))
6656
6664
  ]
6665
+ }),
6666
+ ViewPlugin19.define((view) => {
6667
+ viewRef.current = view;
6668
+ return {
6669
+ destroy() {
6670
+ viewRef.current = void 0;
6671
+ }
6672
+ };
6657
6673
  })
6658
6674
  ];
6659
6675
  };
6660
- 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) => {
6661
6693
  const builder = new RangeSetBuilder6();
6662
6694
  syntaxTree10(state).iterate({
6663
6695
  enter: (node) => {
@@ -6669,8 +6701,13 @@ var buildDecorations3 = (state, options) => {
6669
6701
  case "Link": {
6670
6702
  const link = getLinkRef(state, node.node);
6671
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;
6672
6709
  builder.add(node.from, node.to, Decoration13.replace({
6673
- widget: new PreviewInlineWidget(options, link),
6710
+ widget: new PreviewInlineWidget(options, displayLink),
6674
6711
  side: 1
6675
6712
  }));
6676
6713
  }
@@ -6762,7 +6799,7 @@ var PreviewBlockWidget = class extends WidgetType8 {
6762
6799
  };
6763
6800
 
6764
6801
  // src/extensions/replacer.ts
6765
- import { EditorView as EditorView27 } from "@codemirror/view";
6802
+ import { EditorView as EditorView28 } from "@codemirror/view";
6766
6803
  var defaultReplacements = [
6767
6804
  {
6768
6805
  input: "--",
@@ -6825,7 +6862,7 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6825
6862
  const sortedReplacements = [
6826
6863
  ...replacements
6827
6864
  ].sort((a, b) => b.input.length - a.input.length);
6828
- return EditorView27.inputHandler.of((view, from, to, insert) => {
6865
+ return EditorView28.inputHandler.of((view, from, to, insert) => {
6829
6866
  if (insert.length !== 1) {
6830
6867
  return false;
6831
6868
  }
@@ -6859,12 +6896,69 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6859
6896
  });
6860
6897
  };
6861
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
+
6862
6956
  // src/extensions/submit.ts
6863
6957
  import { Prec as Prec6 } from "@codemirror/state";
6864
- import { keymap as keymap12 } from "@codemirror/view";
6958
+ import { keymap as keymap13 } from "@codemirror/view";
6865
6959
  var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6866
6960
  return [
6867
- Prec6.highest(keymap12.of([
6961
+ Prec6.highest(keymap13.of([
6868
6962
  {
6869
6963
  key: "Enter",
6870
6964
  preventDefault: true,
@@ -6909,6 +7003,7 @@ var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6909
7003
  // src/extensions/tags/extended-markdown.ts
6910
7004
  import { xmlLanguage } from "@codemirror/lang-xml";
6911
7005
  import { parseMixed } from "@lezer/common";
7006
+ var escapeRegExpSource = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6912
7007
  var extendedMarkdown = ({ registry } = {}) => {
6913
7008
  return [
6914
7009
  createMarkdownExtensions({
@@ -6920,13 +7015,65 @@ var extendedMarkdown = ({ registry } = {}) => {
6920
7015
  {
6921
7016
  name: "SetextHeading",
6922
7017
  parse: () => false
6923
- }
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)
6924
7022
  ]
6925
7023
  }
6926
7024
  ]
6927
7025
  })
6928
7026
  ];
6929
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
+ };
6930
7077
  var mixedParser = (registry) => {
6931
7078
  const customTags = Object.keys(registry ?? {});
6932
7079
  const tagPattern = new RegExp(`<(${customTags.join("|")})`);
@@ -6960,219 +7107,793 @@ var mixedParser = (registry) => {
6960
7107
  });
6961
7108
  };
6962
7109
 
6963
- // src/extensions/tags/streamer.ts
6964
- import { StateEffect as StateEffect8, StateField as StateField12 } from "@codemirror/state";
6965
- import { Decoration as Decoration14, EditorView as EditorView28, ViewPlugin as ViewPlugin18, WidgetType as WidgetType9 } from "@codemirror/view";
6966
- import { Domino as Domino3 } from "@dxos/ui";
6967
- import { isTruthy as isTruthy4 } from "@dxos/util";
6968
- var BLINK_RATE = 2e3;
6969
- var streamer = (options = {}) => {
6970
- return [
6971
- options.cursor && cursor(),
6972
- options.fadeIn && fadeIn(typeof options.fadeIn === "object" ? options.fadeIn : {})
6973
- ].filter(isTruthy4);
6974
- };
6975
- var cursor = () => {
6976
- const hideCursor = StateEffect8.define();
6977
- const showCursor = StateField12.define({
6978
- create: () => true,
6979
- 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) => {
6980
7133
  for (const effect of tr.effects) {
6981
- if (effect.is(hideCursor)) {
6982
- 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
+ }
6983
7153
  }
6984
7154
  }
6985
- if (tr.docChanged) {
6986
- return true;
6987
- }
6988
- 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
+ };
6989
7354
  }
6990
7355
  });
6991
- 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 {
6992
7388
  view;
6993
- timer;
7389
+ _raf;
7390
+ _activeStreamTag = null;
6994
7391
  constructor(view) {
6995
7392
  this.view = view;
6996
7393
  }
6997
7394
  update(update2) {
6998
- if (update2.docChanged) {
6999
- clearTimeout(this.timer);
7000
- this.timer = setTimeout(() => {
7001
- this.view.dispatch({
7002
- effects: hideCursor.of(null)
7003
- });
7004
- }, 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();
7005
7402
  }
7006
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
+ };
7007
7478
  destroy() {
7008
- clearTimeout(this.timer);
7479
+ if (this._raf !== void 0) {
7480
+ cancelAnimationFrame(this._raf);
7481
+ }
7009
7482
  }
7010
7483
  });
7011
- const cursorDecoration = StateField12.define({
7012
- create: () => Decoration14.none,
7013
- update: (_decorations, tr) => {
7014
- const show = tr.state.field(showCursor);
7015
- if (!show) {
7016
- 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
+ }
7017
7525
  }
7018
- const endPos = tr.state.doc.length;
7019
- return Decoration14.set([
7020
- 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({
7021
7541
  widget: new CursorWidget(),
7022
7542
  side: 1
7023
- }).range(endPos)
7543
+ }).range(pos)
7024
7544
  ]);
7025
7545
  },
7026
- 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
+ }
7027
7573
  });
7028
7574
  return [
7029
- showCursor,
7030
- timerPlugin,
7031
- cursorDecoration
7575
+ visibilityField,
7576
+ decorationField,
7577
+ timerPlugin
7032
7578
  ];
7033
7579
  };
7034
- 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
+ }
7035
7586
  toDOM() {
7036
- const inner = Domino3.of("span").text("\u258F").style({
7037
- animation: "blink 2s infinite"
7587
+ const inner = Domino3.of("span").text("\u2217").style({
7588
+ animation: "blink 1s infinite",
7589
+ animationDelay: "250ms"
7038
7590
  });
7039
7591
  return Domino3.of("span").style({
7040
7592
  opacity: "0.8"
7041
- }).children(inner).root;
7593
+ }).append(inner).root;
7042
7594
  }
7043
7595
  };
7044
- var fadeIn = (options = {}) => {
7045
- const FADE_IN_DURATION = 1e3;
7046
- const DEFAULT_REMOVAL_DELAY = 3e3;
7047
- const removalDelay = options.removalDelay ?? DEFAULT_REMOVAL_DELAY;
7048
- const removeDecoration = StateEffect8.define();
7049
- const fadeField = StateField12.define({
7050
- create: () => Decoration14.none,
7051
- update: (decorations2, tr) => {
7052
- let next = decorations2;
7053
- for (const effect of tr.effects) {
7054
- if (effect.is(removeDecoration)) {
7055
- const target = effect.value;
7056
- next = next.update({
7057
- filter: (from, to) => !(from === target.from && to === target.to)
7058
- });
7059
- }
7060
- }
7061
- if (!tr.docChanged) {
7062
- 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
+ };
7063
7632
  }
7064
- let isReset = tr.state.doc.length === 0;
7065
- if (!isReset) {
7066
- tr.changes.iterChanges((fromA, toA) => {
7067
- if (fromA === 0 && toA === tr.startState.doc.length) {
7068
- isReset = true;
7069
- }
7070
- });
7633
+ if (buffer[close - 1] === "/") {
7634
+ return {
7635
+ count: close + 1 - start
7636
+ };
7071
7637
  }
7072
- if (isReset) {
7073
- 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;
7074
7693
  }
7075
- const add = [];
7076
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7077
- 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") {
7078
7739
  return;
7079
7740
  }
7080
- if (toA === tr.startState.doc.length && inserted.length > 0) {
7081
- add.push(Decoration14.mark({
7082
- class: "cm-fade-in"
7083
- }).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;
7084
7746
  }
7085
- });
7086
- return next.update({
7087
- add
7088
- });
7089
- },
7090
- provide: (f) => EditorView28.decorations.from(f)
7091
- });
7092
- const timerPlugin = ViewPlugin18.fromClass(class {
7093
- view;
7094
- // Map a simple key "from-to" to timer id.
7095
- _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;
7096
7778
  constructor(view) {
7097
- this.view = view;
7779
+ this.decorations = buildDecorations5(view);
7098
7780
  }
7099
7781
  update(update2) {
7100
- if (!update2.docChanged) {
7101
- return;
7782
+ if (update2.docChanged) {
7783
+ this.decorations = buildDecorations5(update2.view);
7102
7784
  }
7103
- update2.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7104
- 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));
7105
7831
  return;
7106
7832
  }
7107
- const key = `${fromB}-${toB}`;
7108
- if (this._timers.has(key)) {
7109
- 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
+ }
7110
7850
  }
7111
- const totalDelay = FADE_IN_DURATION + removalDelay;
7112
- const id = setTimeout(() => {
7113
- this.view.dispatch({
7114
- effects: removeDecoration.of({
7115
- from: fromB,
7116
- to: toB
7117
- })
7118
- });
7119
- this._timers.delete(key);
7120
- }, totalDelay);
7121
- this._timers.set(key, id);
7122
- });
7123
- }
7124
- destroy() {
7125
- for (const id of this._timers.values()) {
7126
- clearTimeout(id);
7127
7851
  }
7128
- this._timers.clear();
7129
- }
7130
- });
7852
+ });
7853
+ return Decoration17.set(ranges, true);
7854
+ };
7131
7855
  return [
7132
- fadeField,
7133
- timerPlugin,
7134
- EditorView28.theme({
7135
- ".cm-line > span": {
7136
- opacity: "0.8"
7137
- },
7138
- ".cm-fade-in": {
7139
- animation: "fade-in 3s ease-out forwards"
7140
- },
7141
- "@keyframes fade-in": {
7142
- "0%": {
7143
- opacity: "0"
7144
- },
7145
- "80%": {
7146
- opacity: "1"
7147
- },
7148
- "100%": {
7149
- 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);
7150
7864
  }
7151
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": {}
7152
7880
  })
7153
7881
  ];
7154
7882
  };
7155
7883
 
7156
7884
  // src/extensions/tags/xml-tags.ts
7157
7885
  import { syntaxTree as syntaxTree11 } from "@codemirror/language";
7158
- import { Prec as Prec7, RangeSetBuilder as RangeSetBuilder7, StateEffect as StateEffect9, StateField as StateField13 } from "@codemirror/state";
7159
- 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";
7160
7888
  import { invariant as invariant7 } from "@dxos/invariant";
7161
7889
  import { log as log11 } from "@dxos/log";
7890
+ import { Domino as Domino4 } from "@dxos/ui";
7162
7891
 
7163
7892
  // src/extensions/tags/xml-util.ts
7164
7893
  import { invariant as invariant6 } from "@dxos/invariant";
7165
7894
  var __dxlog_file16 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-util.ts";
7166
7895
  var nodeToJson = (state, node) => {
7167
- invariant6(node.type.name === "Element", "Node is not an Element", {
7168
- F: __dxlog_file16,
7169
- L: 18,
7170
- S: void 0,
7171
- A: [
7172
- "node.type.name === 'Element'",
7173
- "'Node is not an Element'"
7174
- ]
7175
- });
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'"] });
7176
7897
  const openTag = node.node.getChild("OpenTag") || node.node.getChild("SelfClosingTag");
7177
7898
  if (openTag) {
7178
7899
  const tagName = openTag.getChild("TagName");
@@ -7204,13 +7925,23 @@ var nodeToJson = (state, node) => {
7204
7925
  if (node.type.name === "Element" && openTag.type.name !== "SelfClosingTag") {
7205
7926
  const children = [];
7206
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
+ };
7207
7939
  while (child) {
7208
7940
  if (child.type.name !== "OpenTag" && child.type.name !== "CloseTag") {
7209
7941
  if (child.type.name === "Text") {
7210
- const text = state.doc.sliceString(child.from, child.to).trim();
7211
- if (text) {
7212
- children.push(text);
7213
- }
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)));
7214
7945
  } else if (child.type.name === "Element") {
7215
7946
  const data = nodeToJson(state, child);
7216
7947
  if (data) {
@@ -7220,26 +7951,63 @@ var nodeToJson = (state, node) => {
7220
7951
  }
7221
7952
  child = child.nextSibling;
7222
7953
  }
7954
+ if (children.length > 0 && typeof children[0] === "string") {
7955
+ children[0] = children[0].trimStart();
7956
+ }
7223
7957
  if (children.length > 0) {
7224
- 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;
7225
7967
  }
7226
7968
  }
7227
7969
  return tag;
7228
7970
  }
7229
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
+ };
7230
7996
 
7231
7997
  // src/extensions/tags/xml-tags.ts
7232
7998
  var __dxlog_file17 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-tags.ts";
7233
- var navigatePreviousEffect = StateEffect9.define();
7234
- var navigateNextEffect = StateEffect9.define();
7999
+ var navigatePreviousEffect = StateEffect12.define();
8000
+ var navigateNextEffect = StateEffect12.define();
7235
8001
  var getXmlTextChild = (children) => {
7236
8002
  const child = children?.[0];
7237
8003
  return typeof child === "string" ? child : null;
7238
8004
  };
7239
- var xmlTagContextEffect = StateEffect9.define();
7240
- var xmlTagResetEffect = StateEffect9.define();
7241
- var xmlTagUpdateEffect = StateEffect9.define();
7242
- 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({
7243
8011
  create: () => void 0,
7244
8012
  update: (value, tr) => {
7245
8013
  for (const effect of tr.effects) {
@@ -7250,7 +8018,7 @@ var widgetContextStateField = StateField13.define({
7250
8018
  return value;
7251
8019
  }
7252
8020
  });
7253
- var widgetStateMapStateField = StateField13.define({
8021
+ var widgetStateMapStateField = StateField14.define({
7254
8022
  create: () => ({}),
7255
8023
  update: (map, tr) => {
7256
8024
  for (const effect of tr.effects) {
@@ -7262,12 +8030,7 @@ var widgetStateMapStateField = StateField13.define({
7262
8030
  log11("widget updated", {
7263
8031
  id,
7264
8032
  value
7265
- }, {
7266
- F: __dxlog_file17,
7267
- L: 153,
7268
- S: void 0,
7269
- C: (f, a) => f(...a)
7270
- });
8033
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 59, S: void 0 });
7271
8034
  const state = typeof value === "function" ? value(map[id]) : value;
7272
8035
  return {
7273
8036
  ...map,
@@ -7297,12 +8060,7 @@ var createWidgetMap = (setWidgets) => {
7297
8060
  log11("widget mounted", {
7298
8061
  id: state.id,
7299
8062
  tag: state.props._tag
7300
- }, {
7301
- F: __dxlog_file17,
7302
- L: 206,
7303
- S: void 0,
7304
- C: (f, a) => f(...a)
7305
- });
8063
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 101, S: void 0 });
7306
8064
  widgets.set(state.id, state);
7307
8065
  setWidgets?.([
7308
8066
  ...widgets.values()
@@ -7313,12 +8071,7 @@ var createWidgetMap = (setWidgets) => {
7313
8071
  log11("widget unmounted", {
7314
8072
  id,
7315
8073
  tag: state?.props._tag
7316
- }, {
7317
- F: __dxlog_file17,
7318
- L: 212,
7319
- S: void 0,
7320
- C: (f, a) => f(...a)
7321
- });
8074
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 112, S: void 0 });
7322
8075
  widgets.delete(id);
7323
8076
  setWidgets?.([
7324
8077
  ...widgets.values()
@@ -7327,7 +8080,7 @@ var createWidgetMap = (setWidgets) => {
7327
8080
  };
7328
8081
  return notifier;
7329
8082
  };
7330
- var keyHandlers = keymap13.of([
8083
+ var keyHandlers = keymap14.of([
7331
8084
  {
7332
8085
  key: "Mod-ArrowUp",
7333
8086
  run: (view) => {
@@ -7348,7 +8101,7 @@ var keyHandlers = keymap13.of([
7348
8101
  }
7349
8102
  ]);
7350
8103
  var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7351
- return EditorView29.updateListener.of((update2) => {
8104
+ return EditorView32.updateListener.of((update2) => {
7352
8105
  update2.transactions.forEach((transaction) => {
7353
8106
  for (const effect of transaction.effects) {
7354
8107
  if (effect.is(navigatePreviousEffect)) {
@@ -7433,7 +8186,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7433
8186
  });
7434
8187
  });
7435
8188
  };
7436
- var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin19.fromClass(class {
8189
+ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin24.fromClass(class {
7437
8190
  update(update2) {
7438
8191
  const widgetStateMap = update2.state.field(widgetStateMapStateField);
7439
8192
  const { decorations: decorations2 } = update2.state.field(widgetDecorationsField);
@@ -7460,14 +8213,14 @@ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin1
7460
8213
  }
7461
8214
  }
7462
8215
  });
7463
- var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.define({
8216
+ var createWidgetDecorationsField = (registry = {}, notifier) => StateField14.define({
7464
8217
  create: (state) => {
7465
8218
  return buildDecorations4(state, {
7466
8219
  from: 0,
7467
8220
  to: state.doc.length
7468
8221
  }, registry, notifier);
7469
8222
  },
7470
- update: ({ from, decorations: decorations2 }, tr) => {
8223
+ update: ({ from, streamingFrom, decorations: decorations2 }, tr) => {
7471
8224
  for (const effect of tr.effects) {
7472
8225
  if (effect.is(xmlTagResetEffect)) {
7473
8226
  if (tr.docChanged) {
@@ -7478,7 +8231,7 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7478
8231
  }
7479
8232
  return {
7480
8233
  from: 0,
7481
- decorations: Decoration15.none
8234
+ decorations: Decoration18.none
7482
8235
  };
7483
8236
  }
7484
8237
  }
@@ -7489,24 +8242,23 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7489
8242
  log11("document reset", {
7490
8243
  from,
7491
8244
  to: state.doc.length
7492
- }, {
7493
- F: __dxlog_file17,
7494
- L: 374,
7495
- S: void 0,
7496
- C: (f, a) => f(...a)
7497
- });
8245
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 298, S: void 0 });
7498
8246
  return buildDecorations4(state, {
7499
8247
  from: 0,
7500
8248
  to: state.doc.length
7501
8249
  }, registry, notifier);
7502
8250
  } else {
8251
+ const rebuildFrom = streamingFrom ?? from;
7503
8252
  const result = buildDecorations4(state, {
7504
- from,
8253
+ from: rebuildFrom,
7505
8254
  to: state.doc.length
7506
8255
  }, registry, notifier);
7507
8256
  return {
7508
8257
  from: result.from,
8258
+ streamingFrom: result.streamingFrom,
7509
8259
  decorations: decorations2.update({
8260
+ // Remove old streaming decorations — they are rebuilt each tick.
8261
+ filter: (_f, _t, deco) => !deco.spec.streaming,
7510
8262
  add: decorationSetToArray(result.decorations)
7511
8263
  })
7512
8264
  };
@@ -7514,12 +8266,13 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7514
8266
  }
7515
8267
  return {
7516
8268
  from,
8269
+ streamingFrom,
7517
8270
  decorations: decorations2
7518
8271
  };
7519
8272
  },
7520
8273
  provide: (field) => [
7521
- EditorView29.decorations.from(field, (v) => v.decorations),
7522
- 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)
7523
8276
  ]
7524
8277
  });
7525
8278
  var buildDecorations4 = (state, range, registry, notifier) => {
@@ -7530,10 +8283,11 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7530
8283
  if (!tree || tree.type.name === "Program" && tree.length === 0) {
7531
8284
  return {
7532
8285
  from: range.from,
7533
- decorations: Decoration15.none
8286
+ decorations: Decoration18.none
7534
8287
  };
7535
8288
  }
7536
8289
  let last = range.from;
8290
+ let streamingFrom;
7537
8291
  tree.iterate({
7538
8292
  from: range.from,
7539
8293
  to: range.to,
@@ -7546,21 +8300,26 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7546
8300
  if (args) {
7547
8301
  const def = registry[args._tag];
7548
8302
  if (def) {
8303
+ if (def.streaming && !node.node.getChild("CloseTag")) {
8304
+ return false;
8305
+ }
7549
8306
  const { block, factory, Component } = def;
7550
- const widgetState = args.id ? widgetStateMap[args.id] : void 0;
7551
8307
  const nodeRange = {
7552
8308
  from: node.node.from,
7553
8309
  to: node.node.to
7554
8310
  };
8311
+ const widgetId = xmlWidgetId(args.id, def.streaming ? `cm-xml-${nodeRange.from}` : `cm-xml-${nodeRange.from}-${nodeRange.to}`);
8312
+ const widgetState = widgetStateMap[widgetId];
7555
8313
  const props = {
7556
- context,
8314
+ id: widgetId,
7557
8315
  range: nodeRange,
8316
+ context,
7558
8317
  ...args,
7559
8318
  ...widgetState
7560
8319
  };
7561
- 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;
7562
8321
  if (widget) {
7563
- builder.add(nodeRange.from, nodeRange.to, Decoration15.replace({
8322
+ builder.add(nodeRange.from, nodeRange.to, Decoration18.replace({
7564
8323
  widget,
7565
8324
  block,
7566
8325
  atomic: true,
@@ -7572,20 +8331,72 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7572
8331
  }
7573
8332
  }
7574
8333
  } catch (err) {
7575
- log11.catch(err, void 0, {
7576
- F: __dxlog_file17,
7577
- L: 459,
7578
- S: void 0,
7579
- C: (f, a) => f(...a)
7580
- });
8334
+ log11.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file17, L: 401, S: void 0 });
7581
8335
  }
7582
8336
  return false;
7583
8337
  }
7584
8338
  }
7585
8339
  }
7586
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
+ }
7587
8397
  return {
7588
8398
  from: last,
8399
+ streamingFrom,
7589
8400
  decorations: builder.finish()
7590
8401
  };
7591
8402
  };
@@ -7594,108 +8405,62 @@ var PlaceholderWidget2 = class extends WidgetType10 {
7594
8405
  Component;
7595
8406
  props;
7596
8407
  notifier;
7597
- _root = null;
7598
- constructor(id, Component, props, notifier) {
7599
- super(), this.id = id, this.Component = Component, this.props = props, this.notifier = notifier;
7600
- invariant7(id, void 0, {
7601
- F: __dxlog_file17,
7602
- L: 485,
7603
- S: this,
7604
- A: [
7605
- "id",
7606
- ""
7607
- ]
7608
- });
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", ""] });
7609
8414
  }
7610
8415
  get root() {
7611
- return this._root;
8416
+ return this.#root;
7612
8417
  }
7613
8418
  eq(other) {
8419
+ if (this.streaming) {
8420
+ return false;
8421
+ }
7614
8422
  return this.id === other.id;
7615
8423
  }
7616
8424
  ignoreEvent() {
7617
8425
  return true;
7618
8426
  }
7619
- toDOM(_view) {
7620
- 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
+ });
7621
8446
  this.notifier.mounted({
7622
8447
  id: this.id,
7623
- root: this._root,
7624
- props: this.props,
8448
+ root: this.#root,
8449
+ props,
7625
8450
  Component: this.Component
7626
8451
  });
7627
- return this._root;
8452
+ return true;
7628
8453
  }
7629
8454
  destroy(_dom) {
7630
8455
  this.notifier.unmounted(this.id);
7631
- this._root = null;
8456
+ this.#root = null;
8457
+ this.#view = void 0;
7632
8458
  }
7633
8459
  };
7634
-
7635
- // src/extensions/typewriter.ts
7636
- import { keymap as keymap14 } from "@codemirror/view";
7637
- var defaultItems = [
7638
- "hello world!",
7639
- "this is a test.",
7640
- "this is [DXOS](https://dxos.org)"
7641
- ];
7642
- var typewriter = ({ delay = 75, items = defaultItems } = {}) => {
7643
- let t;
7644
- let idx = 0;
7645
- return [
7646
- keymap14.of([
7647
- {
7648
- // Reset.
7649
- key: "alt-meta-'",
7650
- run: () => {
7651
- clearTimeout(t);
7652
- idx = 0;
7653
- return true;
7654
- }
7655
- },
7656
- {
7657
- // Next prompt.
7658
- // TODO(burdon): Press 1-9 to select prompt?
7659
- key: "Shift-Meta-'",
7660
- run: (view) => {
7661
- clearTimeout(t);
7662
- const text = items[idx++];
7663
- if (idx === items?.length) {
7664
- idx = 0;
7665
- }
7666
- let i = 0;
7667
- const insert = (d = 0) => {
7668
- t = setTimeout(() => {
7669
- const pos = view.state.selection.main.head;
7670
- view.dispatch({
7671
- changes: {
7672
- from: pos,
7673
- insert: text[i++]
7674
- },
7675
- selection: {
7676
- anchor: pos + 1
7677
- }
7678
- });
7679
- if (i < text.length) {
7680
- insert(Math.random() * delay * (text[i] === " " ? 2 : 1));
7681
- }
7682
- }, d);
7683
- };
7684
- insert();
7685
- return true;
7686
- }
7687
- }
7688
- ])
7689
- ];
7690
- };
7691
8460
  export {
7692
8461
  Cursor,
7693
- EditorInputMode,
7694
- EditorInputModes,
7695
- EditorState3 as EditorState,
7696
- EditorView30 as EditorView,
7697
- EditorViewMode,
7698
- EditorViewModes,
8462
+ EditorState4 as EditorState,
8463
+ EditorView33 as EditorView,
7699
8464
  Inline,
7700
8465
  InputModeExtensions,
7701
8466
  List,
@@ -7712,6 +8477,7 @@ export {
7712
8477
  addStyle,
7713
8478
  annotations,
7714
8479
  autoScroll,
8480
+ autoScrollEffect,
7715
8481
  autocomplete,
7716
8482
  automerge,
7717
8483
  awareness,
@@ -7725,6 +8491,7 @@ export {
7725
8491
  commentClickedEffect,
7726
8492
  comments,
7727
8493
  commentsState,
8494
+ compactSlots,
7728
8495
  convertTreeToJson,
7729
8496
  createBasicExtensions,
7730
8497
  createComment,
@@ -7748,12 +8515,12 @@ export {
7748
8515
  defaultThemeSlots,
7749
8516
  deleteItem,
7750
8517
  documentId,
8518
+ documentSlots,
7751
8519
  dropFile,
8520
+ editorClassNames,
7752
8521
  editorInputMode,
7753
- editorSlots,
7754
- editorWidth,
7755
- editorWithToolbarLayout,
7756
8522
  extendedMarkdown,
8523
+ fader,
7757
8524
  filterChars,
7758
8525
  flattenRect,
7759
8526
  focus,
@@ -7789,6 +8556,7 @@ export {
7789
8556
  markdownTagsExtensions,
7790
8557
  matchCompletion,
7791
8558
  mention,
8559
+ mobileSlots,
7792
8560
  modalStateEffect,
7793
8561
  modalStateField,
7794
8562
  moveItemDown,
@@ -7808,6 +8576,7 @@ export {
7808
8576
  removeList,
7809
8577
  removeStyle,
7810
8578
  replacer,
8579
+ scrollPastEnd,
7811
8580
  scrollThreadIntoView,
7812
8581
  scrollToLine,
7813
8582
  scroller,
@@ -7820,9 +8589,8 @@ export {
7820
8589
  setSelection,
7821
8590
  setStyle,
7822
8591
  singleValueFacet,
7823
- stackItemContentEditorClassNames,
8592
+ snippets2 as snippets,
7824
8593
  staticCompletion,
7825
- streamer,
7826
8594
  submit,
7827
8595
  tabbable,
7828
8596
  table,
@@ -7841,7 +8609,12 @@ export {
7841
8609
  treeFacet,
7842
8610
  typeahead,
7843
8611
  typewriter,
8612
+ typewriterBypass,
8613
+ typewriterDrainingEffect,
7844
8614
  wrapWithCatch,
8615
+ xmlBlockDecoration,
8616
+ xmlElementLength,
8617
+ xmlFormatting,
7845
8618
  xmlTagContextEffect,
7846
8619
  xmlTagResetEffect,
7847
8620
  xmlTagUpdateEffect,