@dxos/ui-editor 0.8.4-main.6fa680abb7 → 0.8.4-main.74a063c4e0

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 (77) hide show
  1. package/dist/lib/browser/index.mjs +1055 -386
  2. package/dist/lib/browser/index.mjs.map +4 -4
  3. package/dist/lib/browser/meta.json +1 -1
  4. package/dist/lib/node-esm/index.mjs +1055 -386
  5. package/dist/lib/node-esm/index.mjs.map +4 -4
  6. package/dist/lib/node-esm/meta.json +1 -1
  7. package/dist/types/src/defaults.d.ts +3 -10
  8. package/dist/types/src/defaults.d.ts.map +1 -1
  9. package/dist/types/src/extensions/auto-scroll.d.ts +4 -2
  10. package/dist/types/src/extensions/auto-scroll.d.ts.map +1 -1
  11. package/dist/types/src/extensions/automerge/automerge.d.ts.map +1 -1
  12. package/dist/types/src/extensions/comments.d.ts.map +1 -1
  13. package/dist/types/src/extensions/factories.d.ts.map +1 -1
  14. package/dist/types/src/extensions/folding.d.ts.map +1 -1
  15. package/dist/types/src/extensions/index.d.ts +1 -0
  16. package/dist/types/src/extensions/index.d.ts.map +1 -1
  17. package/dist/types/src/extensions/markdown/action.d.ts.map +1 -1
  18. package/dist/types/src/extensions/markdown/bundle.d.ts +3 -0
  19. package/dist/types/src/extensions/markdown/bundle.d.ts.map +1 -1
  20. package/dist/types/src/extensions/markdown/decorate.d.ts.map +1 -1
  21. package/dist/types/src/extensions/markdown/highlight.d.ts.map +1 -1
  22. package/dist/types/src/extensions/markdown/styles.d.ts.map +1 -1
  23. package/dist/types/src/extensions/outliner/outliner.d.ts.map +1 -1
  24. package/dist/types/src/extensions/preview/preview.d.ts +2 -0
  25. package/dist/types/src/extensions/preview/preview.d.ts.map +1 -1
  26. package/dist/types/src/extensions/scroll-past-end.d.ts +3 -0
  27. package/dist/types/src/extensions/scroll-past-end.d.ts.map +1 -0
  28. package/dist/types/src/extensions/scroller.d.ts +8 -11
  29. package/dist/types/src/extensions/scroller.d.ts.map +1 -1
  30. package/dist/types/src/extensions/tags/extended-markdown.d.ts.map +1 -1
  31. package/dist/types/src/extensions/tags/fader.d.ts +12 -0
  32. package/dist/types/src/extensions/tags/fader.d.ts.map +1 -0
  33. package/dist/types/src/extensions/tags/index.d.ts +2 -1
  34. package/dist/types/src/extensions/tags/index.d.ts.map +1 -1
  35. package/dist/types/src/extensions/tags/wire.d.ts +23 -0
  36. package/dist/types/src/extensions/tags/wire.d.ts.map +1 -0
  37. package/dist/types/src/extensions/tags/wire.test.d.ts +2 -0
  38. package/dist/types/src/extensions/tags/wire.test.d.ts.map +1 -0
  39. package/dist/types/src/extensions/tags/xml-tags.d.ts +28 -8
  40. package/dist/types/src/extensions/tags/xml-tags.d.ts.map +1 -1
  41. package/dist/types/src/styles/theme.d.ts +2 -2
  42. package/dist/types/src/styles/theme.d.ts.map +1 -1
  43. package/dist/types/src/util/cursor.d.ts.map +1 -1
  44. package/dist/types/tsconfig.tsbuildinfo +1 -1
  45. package/package.json +27 -27
  46. package/src/defaults.ts +22 -20
  47. package/src/extensions/auto-scroll.ts +62 -9
  48. package/src/extensions/automerge/automerge.ts +0 -1
  49. package/src/extensions/comments.ts +0 -1
  50. package/src/extensions/factories.ts +1 -2
  51. package/src/extensions/folding.ts +3 -20
  52. package/src/extensions/index.ts +1 -0
  53. package/src/extensions/markdown/action.ts +0 -1
  54. package/src/extensions/markdown/bundle.ts +23 -9
  55. package/src/extensions/markdown/decorate.ts +11 -9
  56. package/src/extensions/markdown/highlight.ts +4 -10
  57. package/src/extensions/markdown/parser.test.ts +0 -1
  58. package/src/extensions/markdown/styles.ts +37 -4
  59. package/src/extensions/markdown/table.ts +24 -2
  60. package/src/extensions/outliner/outliner.test.ts +0 -1
  61. package/src/extensions/outliner/outliner.ts +0 -1
  62. package/src/extensions/outliner/tree.test.ts +0 -1
  63. package/src/extensions/preview/preview.ts +54 -7
  64. package/src/extensions/scroll-past-end.ts +32 -0
  65. package/src/extensions/scroller.ts +31 -18
  66. package/src/extensions/tags/extended-markdown.ts +73 -1
  67. package/src/extensions/tags/fader.ts +195 -0
  68. package/src/extensions/tags/index.ts +2 -1
  69. package/src/extensions/tags/wire.test.ts +65 -0
  70. package/src/extensions/tags/wire.ts +459 -0
  71. package/src/extensions/tags/xml-tags.ts +178 -30
  72. package/src/extensions/tags/xml-util.test.ts +111 -23
  73. package/src/styles/theme.ts +28 -23
  74. package/src/util/cursor.ts +0 -1
  75. package/dist/types/src/extensions/tags/streamer.d.ts +0 -12
  76. package/dist/types/src/extensions/tags/streamer.d.ts.map +0 -1
  77. package/src/extensions/tags/streamer.ts +0 -243
@@ -6,24 +6,34 @@ import {
6
6
  } from "./chunk-HL3YF6WC.mjs";
7
7
 
8
8
  // src/index.ts
9
- import { EditorState as EditorState3 } from "@codemirror/state";
10
- import { EditorView as EditorView30, keymap as keymap15 } from "@codemirror/view";
9
+ import { EditorState as EditorState4 } from "@codemirror/state";
10
+ import { EditorView as EditorView32, keymap as keymap15 } from "@codemirror/view";
11
11
  import { tags as tags2 } from "@lezer/highlight";
12
12
  import { TextKind } from "@dxos/protocols/proto/dxos/echo/model/text";
13
13
 
14
14
  // src/defaults.ts
15
15
  import { mx } from "@dxos/ui-theme";
16
- var editorWidth = "!mx-auto w-full max-w-[min(50rem,100%-4rem)]";
17
- var editorSlots = {
18
- scroll: {
19
- className: "pt-2"
16
+ 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");
17
+ var documentSlots = {
18
+ content: {
19
+ /**
20
+ * CodeMirror content width.
21
+ * 40rem = 640px. Corresponds to initial plank width (Google docs, Stashpad, etc.)
22
+ * 50rem = 800px. Maximum content width for solo mode.
23
+ * NOTE: Max width - 4rem = 2rem left/right margin (or 2rem gutter plus 1rem left/right margin).
24
+ */
25
+ className: "mx-auto! w-full pointer-fine:max-w-[min(50rem,100%-4rem)] pointer-coarse:max-w-[min(50rem,100%-2rem)]"
20
26
  },
27
+ scroll: {
28
+ // NOTE: Child widgets must have `max-w-[100cqi]`.
29
+ className: "dx-size-container"
30
+ }
31
+ };
32
+ var compactSlots = {
21
33
  content: {
22
- className: editorWidth
34
+ className: "mx-2! w-full"
23
35
  }
24
36
  };
25
- var editorWithToolbarLayout = "grid grid-cols-1 grid-rows-[min-content_1fr] data-[toolbar=disabled]:grid-rows-[1fr] justify-center content-start overflow-hidden";
26
- var stackItemContentEditorClassNames = (role) => mx("dx-attention-surface p-0.5 dx-focus-ring-inset data-[toolbar=disabled]:pt-2", role === "section" ? "[&_.cm-scroller]:overflow-hidden [&_.cm-scroller]:min-h-24" : "dx-container overflow-hidden");
27
37
 
28
38
  // src/extensions/annotations.ts
29
39
  import { RangeSetBuilder } from "@codemirror/state";
@@ -207,7 +217,7 @@ var singleValueFacet = (defaultValue) => Facet.define({
207
217
  var overlap = (a, b) => a.from <= b.to && a.to >= b.from;
208
218
  var defaultCursorConverter = {
209
219
  toCursor: (position) => position.toString(),
210
- fromCursor: (cursor2) => parseInt(cursor2)
220
+ fromCursor: (cursor) => parseInt(cursor)
211
221
  };
212
222
  var Cursor = class _Cursor {
213
223
  static converter = singleValueFacet(defaultCursorConverter);
@@ -220,9 +230,9 @@ var Cursor = class _Cursor {
220
230
  to
221
231
  ].join(":");
222
232
  };
223
- static getRangeFromCursor = (state, cursor2) => {
233
+ static getRangeFromCursor = (state, cursor) => {
224
234
  const cursorConverter2 = state.facet(_Cursor.converter);
225
- const parts = cursor2.split(":");
235
+ const parts = cursor.split(":");
226
236
  const from = cursorConverter2.fromCursor(parts[0]);
227
237
  const to = cursorConverter2.fromCursor(parts[1]);
228
238
  return from !== void 0 && to !== void 0 ? {
@@ -502,9 +512,11 @@ var typeahead = ({ onComplete } = {}) => {
502
512
  };
503
513
 
504
514
  // src/extensions/auto-scroll.ts
515
+ import { StateEffect as StateEffect2 } from "@codemirror/state";
505
516
  import { EditorView as EditorView5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
506
517
  import { addEventListener, combine, throttle } from "@dxos/async";
507
518
  import { Domino } from "@dxos/ui";
519
+ import { getSize } from "@dxos/ui-theme";
508
520
 
509
521
  // src/extensions/scroller.ts
510
522
  import { StateEffect } from "@codemirror/state";
@@ -561,8 +573,7 @@ var scroller = ({ overScroll = 0 } = {}) => {
561
573
  }
562
574
  requestAnimationFrame(() => {
563
575
  this.view.scrollDOM.scrollTo({
564
- top: targetScrollTop,
565
- behavior
576
+ top: targetScrollTop
566
577
  });
567
578
  });
568
579
  }
@@ -586,7 +597,7 @@ var scroller = ({ overScroll = 0 } = {}) => {
586
597
  } catch (err) {
587
598
  log2.catch(err, void 0, {
588
599
  F: __dxlog_file2,
589
- L: 145,
600
+ L: 146,
590
601
  S: void 0,
591
602
  C: (f, a) => f(...a)
592
603
  });
@@ -599,6 +610,7 @@ var scroller = ({ overScroll = 0 } = {}) => {
599
610
  paddingBottom: `${overScroll}px`
600
611
  },
601
612
  ".cm-scroller": {
613
+ overflowY: "scroll",
602
614
  overflowAnchor: "none",
603
615
  paddingBottom: "0"
604
616
  },
@@ -620,22 +632,31 @@ var scroller = ({ overScroll = 0 } = {}) => {
620
632
  })
621
633
  ];
622
634
  };
623
- function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
635
+ function createCrawler(view, accel = 0.15, maxVelocity = 1, snapThreshold = 0.5) {
624
636
  const el = view.scrollDOM;
625
637
  let currentTop = 0;
638
+ let velocity = 0;
626
639
  let rafId = null;
627
640
  function frame() {
628
641
  const targetTop = el.scrollHeight - el.clientHeight;
629
642
  const delta = targetTop - currentTop;
630
643
  const absDelta = Math.abs(delta);
631
- if (absDelta < targetDelta) {
644
+ if (absDelta < snapThreshold && Math.abs(velocity) < snapThreshold) {
632
645
  el.scrollTop = targetTop;
633
646
  currentTop = targetTop;
647
+ velocity = 0;
634
648
  rafId = null;
635
649
  return;
636
650
  }
637
- const step = Math.sign(delta) * Math.min(absDelta, Math.max(1, Math.min(absDelta * k, maxStep)));
638
- currentTop += step;
651
+ const stoppingDistance = velocity * velocity / (2 * accel);
652
+ const direction = Math.sign(delta);
653
+ if (velocity !== 0 && (absDelta <= stoppingDistance || direction !== Math.sign(velocity))) {
654
+ velocity -= Math.sign(velocity) * Math.min(accel, Math.abs(velocity));
655
+ } else {
656
+ velocity += direction * accel;
657
+ velocity = Math.sign(velocity) * Math.min(Math.abs(velocity), maxVelocity);
658
+ }
659
+ currentTop += velocity;
639
660
  el.scrollTop = currentTop;
640
661
  rafId = requestAnimationFrame(frame);
641
662
  }
@@ -650,32 +671,71 @@ function createCrawler(view, k = 0.3, maxStep = 2, targetDelta = 0.5) {
650
671
  if (rafId !== null) {
651
672
  cancelAnimationFrame(rafId);
652
673
  rafId = null;
674
+ velocity = 0;
653
675
  }
654
676
  }
655
677
  };
656
678
  }
657
679
 
658
680
  // src/extensions/auto-scroll.ts
681
+ var autoScrollEffect = StateEffect2.define();
659
682
  var autoScroll = (_ = {}) => {
660
683
  let buttonContainer;
661
684
  let isPinned = true;
685
+ let jumpPending = false;
686
+ let enabled = true;
687
+ let firstUpdate = true;
662
688
  const setPinned = (pinned) => {
663
689
  buttonContainer?.classList.toggle("opacity-0", pinned);
664
690
  isPinned = pinned;
665
691
  };
666
692
  return [
667
- // Update listener for logging when scrolling is needed.
668
- EditorView5.updateListener.of(({ view, heightChanged, state }) => {
693
+ // Update listener for scrolling when content changes.
694
+ EditorView5.updateListener.of((update2) => {
695
+ const { view, heightChanged, state, startState } = update2;
696
+ for (const tr of update2.transactions) {
697
+ for (const effect of tr.effects) {
698
+ if (effect.is(autoScrollEffect)) {
699
+ enabled = effect.value;
700
+ if (enabled) {
701
+ setPinned(true);
702
+ view.dispatch({
703
+ effects: scrollerCrawlEffect.of(true)
704
+ });
705
+ } else {
706
+ view.dispatch({
707
+ effects: scrollerCrawlEffect.of(false)
708
+ });
709
+ }
710
+ }
711
+ }
712
+ }
713
+ if (!enabled) {
714
+ return;
715
+ }
716
+ if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
717
+ firstUpdate = false;
718
+ jumpPending = true;
719
+ requestAnimationFrame(() => {
720
+ view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
721
+ jumpPending = false;
722
+ });
723
+ return;
724
+ }
725
+ firstUpdate = false;
726
+ if (jumpPending) {
727
+ return;
728
+ }
669
729
  if (heightChanged) {
670
730
  if (isPinned) {
671
731
  const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
672
732
  const delta = scrollHeight - scrollTop - clientHeight;
673
- if (delta > 0 && scrollTop > 0) {
733
+ if (delta > 0) {
674
734
  setPinned(true);
675
735
  view.dispatch({
676
736
  effects: scrollerCrawlEffect.of(true)
677
737
  });
678
- } else if (delta < 0) {
738
+ } else if (delta < -1) {
679
739
  setPinned(false);
680
740
  }
681
741
  } else {
@@ -710,12 +770,12 @@ var autoScroll = (_ = {}) => {
710
770
  // Scroll button.
711
771
  ViewPlugin6.fromClass(class {
712
772
  constructor(view) {
713
- const icon = Domino.of("dx-icon").attributes({
773
+ const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
714
774
  icon: "ph--arrow-down--regular"
715
775
  });
716
776
  const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
717
777
  "data-density": "fine"
718
- }).children(icon).on("click", () => {
778
+ }).append(icon).on("click", () => {
719
779
  setPinned(true);
720
780
  view.dispatch({
721
781
  effects: scrollerLineEffect.of({
@@ -725,7 +785,7 @@ var autoScroll = (_ = {}) => {
725
785
  })
726
786
  });
727
787
  });
728
- buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").children(button).root;
788
+ buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
729
789
  view.scrollDOM.parentElement.appendChild(buttonContainer);
730
790
  }
731
791
  })
@@ -769,9 +829,9 @@ var cursorConverter = (accessor) => ({
769
829
  return "";
770
830
  }
771
831
  },
772
- fromCursor: (cursor2) => {
832
+ fromCursor: (cursor) => {
773
833
  try {
774
- return fromCursor(accessor, cursor2);
834
+ return fromCursor(accessor, cursor);
775
835
  } catch (err) {
776
836
  log3.catch(err, void 0, {
777
837
  F: __dxlog_file3,
@@ -785,10 +845,10 @@ var cursorConverter = (accessor) => ({
785
845
  });
786
846
 
787
847
  // src/extensions/automerge/defs.ts
788
- import { Annotation, StateEffect as StateEffect2 } from "@codemirror/state";
848
+ import { Annotation, StateEffect as StateEffect3 } from "@codemirror/state";
789
849
  var getPath = (state, field) => state.field(field).path;
790
850
  var getLastHeads = (state, field) => state.field(field).lastHeads;
791
- var updateHeadsEffect = StateEffect2.define({});
851
+ var updateHeadsEffect = StateEffect3.define({});
792
852
  var updateHeads = (newHeads) => updateHeadsEffect.of({
793
853
  newHeads
794
854
  });
@@ -1832,13 +1892,13 @@ var blocks = () => [
1832
1892
  ];
1833
1893
 
1834
1894
  // src/extensions/bookmarks.ts
1835
- import { Prec as Prec3, StateEffect as StateEffect3, StateField as StateField2 } from "@codemirror/state";
1895
+ import { Prec as Prec3, StateEffect as StateEffect4, StateField as StateField2 } from "@codemirror/state";
1836
1896
  import { keymap as keymap4 } from "@codemirror/view";
1837
1897
  import { log as log6 } from "@dxos/log";
1838
1898
  var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
1839
- var addBookmark = StateEffect3.define();
1840
- var removeBookmark = StateEffect3.define();
1841
- var clearBookmarks = StateEffect3.define();
1899
+ var addBookmark = StateEffect4.define();
1900
+ var removeBookmark = StateEffect4.define();
1901
+ var clearBookmarks = StateEffect4.define();
1842
1902
  var bookmarks = () => {
1843
1903
  return [
1844
1904
  bookmarksField,
@@ -1902,7 +1962,7 @@ var bookmarksField = StateField2.define({
1902
1962
 
1903
1963
  // src/extensions/comments.ts
1904
1964
  import { invertedEffects } from "@codemirror/commands";
1905
- import { StateEffect as StateEffect4, StateField as StateField3 } from "@codemirror/state";
1965
+ import { StateEffect as StateEffect5, StateField as StateField3 } from "@codemirror/state";
1906
1966
  import { Decoration as Decoration7, EditorView as EditorView11, ViewPlugin as ViewPlugin10, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
1907
1967
  import sortBy from "lodash.sortby";
1908
1968
  import { debounce as debounce2 } from "@dxos/async";
@@ -2004,9 +2064,9 @@ var selectionState = ({ getState, setState } = {}) => {
2004
2064
 
2005
2065
  // src/extensions/comments.ts
2006
2066
  var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
2007
- var setComments = StateEffect4.define();
2008
- var setSelection = StateEffect4.define();
2009
- var setCommentState = StateEffect4.define();
2067
+ var setComments = StateEffect5.define();
2068
+ var setSelection = StateEffect5.define();
2069
+ var setCommentState = StateEffect5.define();
2010
2070
  var commentsState = StateField3.define({
2011
2071
  create: (state) => ({
2012
2072
  id: state.facet(documentId),
@@ -2075,7 +2135,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2075
2135
  if (!range) {
2076
2136
  log7.warn("Invalid range:", range, {
2077
2137
  F: __dxlog_file10,
2078
- L: 140,
2138
+ L: 139,
2079
2139
  S: void 0,
2080
2140
  C: (f, a) => f(...a)
2081
2141
  });
@@ -2088,7 +2148,7 @@ var commentsDecorations = EditorView11.decorations.compute([
2088
2148
  }).filter(isNonNullable);
2089
2149
  return Decoration7.set(decorations2);
2090
2150
  });
2091
- var commentClickedEffect = StateEffect4.define();
2151
+ var commentClickedEffect = StateEffect5.define();
2092
2152
  var handleCommentClick = EditorView11.domEventHandlers({
2093
2153
  click: (event, view) => {
2094
2154
  let target = event.target;
@@ -2191,10 +2251,10 @@ var trackPastedComments = (onUpdate) => {
2191
2251
  const { comments: comments2 } = update2.startState.field(commentsState);
2192
2252
  const exists = comments2.some((c) => c.comment.id === comment.id && c.range.from < c.range.to);
2193
2253
  if (!exists) {
2194
- const cursor2 = Cursor.getCursorFromRange(update2.state, comment);
2254
+ const cursor = Cursor.getCursorFromRange(update2.state, comment);
2195
2255
  onUpdate({
2196
2256
  id: comment.id,
2197
- cursor: cursor2
2257
+ cursor
2198
2258
  });
2199
2259
  }
2200
2260
  }
@@ -2206,7 +2266,7 @@ var mapTrackedComment = (comment, changes) => ({
2206
2266
  from: changes.mapPos(comment.from, 1),
2207
2267
  to: changes.mapPos(comment.to, 1)
2208
2268
  });
2209
- var restoreCommentEffect = StateEffect4.define({
2269
+ var restoreCommentEffect = StateEffect5.define({
2210
2270
  map: mapTrackedComment
2211
2271
  });
2212
2272
  var createComment = (view) => {
@@ -2223,13 +2283,13 @@ var createComment = (view) => {
2223
2283
  }
2224
2284
  });
2225
2285
  }
2226
- const cursor2 = Cursor.getCursorFromRange(view.state, {
2286
+ const cursor = Cursor.getCursorFromRange(view.state, {
2227
2287
  from,
2228
2288
  to
2229
2289
  });
2230
- if (cursor2) {
2290
+ if (cursor) {
2231
2291
  options.onCreate?.({
2232
- cursor: cursor2,
2292
+ cursor,
2233
2293
  from,
2234
2294
  location: view.coordsAtPos(from)
2235
2295
  });
@@ -2470,7 +2530,7 @@ import { defaultKeymap, history, historyKeymap, indentWithTab, standardKeymap }
2470
2530
  import { HighlightStyle, bracketMatching, syntaxHighlighting } from "@codemirror/language";
2471
2531
  import { searchKeymap } from "@codemirror/search";
2472
2532
  import { EditorState } from "@codemirror/state";
2473
- import { EditorView as EditorView15, ViewPlugin as ViewPlugin11, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap7, lineNumbers, placeholder as placeholder2, scrollPastEnd } from "@codemirror/view";
2533
+ import { EditorView as EditorView16, ViewPlugin as ViewPlugin12, drawSelection, dropCursor as dropCursor2, highlightActiveLine, keymap as keymap7, lineNumbers, placeholder as placeholder2 } from "@codemirror/view";
2474
2534
  import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode";
2475
2535
  import defaultsDeep2 from "lodash.defaultsdeep";
2476
2536
  import { generateName } from "@dxos/display-name";
@@ -2482,28 +2542,28 @@ import { EditorView as EditorView13 } from "@codemirror/view";
2482
2542
  import { mx as mx3 } from "@dxos/ui-theme";
2483
2543
  var headings = {
2484
2544
  1: {
2485
- className: "text-4xl",
2486
- fontSize: "var(--text-4xl)",
2545
+ className: "text-3xl",
2546
+ fontSize: "var(--text-3xl)",
2487
2547
  lineHeight: "var(--text-4xl--line-height)"
2488
2548
  },
2489
2549
  2: {
2490
- className: "text-3xl",
2491
- fontSize: "var(--text-3xl)",
2550
+ className: "text-2xl",
2551
+ fontSize: "var(--text-2xl)",
2492
2552
  lineHeight: "var(--text-3xl--line-height)"
2493
2553
  },
2494
2554
  3: {
2495
- className: "text-2xl",
2496
- fontSize: "var(--text-2xl)",
2555
+ className: "text-xl",
2556
+ fontSize: "var(--text-xl)",
2497
2557
  lineHeight: "var(--text-2xl--line-height)"
2498
2558
  },
2499
2559
  4: {
2500
- className: "text-xl",
2501
- fontSize: "var(--text-xl)",
2560
+ className: "text-lg",
2561
+ fontSize: "var(--text-lg)",
2502
2562
  lineHeight: "var(--text-xl--line-height)"
2503
2563
  },
2504
2564
  5: {
2505
- className: "text-lg",
2506
- fontSize: "var(--text-lg)",
2565
+ className: "text-base",
2566
+ fontSize: "var(--text-base)",
2507
2567
  lineHeight: "var(--text-lg--line-height)"
2508
2568
  },
2509
2569
  6: {
@@ -2512,20 +2572,20 @@ var headings = {
2512
2572
  lineHeight: "var(--text-base--line-height)"
2513
2573
  }
2514
2574
  };
2575
+ var fontBody = '"Inter Variable", ui-sans-serif, system-ui, sans-serif';
2576
+ var fontMono = '"JetBrains Mono Variable", ui-monospace, "Cascadia Code", "Source Code Pro", monospace';
2515
2577
  var markdownTheme = {
2516
- code: "font-mono no-underline! text-cm-code",
2517
- codeMark: "font-mono text-cm-code-mark",
2518
- mark: "opacity-50",
2578
+ code: "font-mono! cm-code-inline",
2579
+ codeMark: "font-mono! cm-code-mark",
2580
+ mark: "font-mono!",
2519
2581
  heading: (level) => ({
2520
- className: mx3(headings[level].className, "font-light text-cm-heading"),
2582
+ className: mx3(headings[level].className, "font-light text-(--color-cm-heading-number)"),
2521
2583
  color: "var(--color-cm-heading) !important",
2522
2584
  lineHeight: headings[level].lineHeight,
2523
2585
  fontSize: headings[level].fontSize,
2524
2586
  fontWeight: "100 !important"
2525
2587
  })
2526
2588
  };
2527
- var fontBody = "Inter Variable, ui-sans-serif, system-ui, sans-serif";
2528
- var fontMono = "JetBrains Mono Variable, ui-monospace, Cascadia Code, Source Code Pro, monospace";
2529
2589
  var baseTheme = EditorView13.baseTheme({
2530
2590
  /**
2531
2591
  * Outer frame.
@@ -2557,7 +2617,6 @@ var baseTheme = EditorView13.baseTheme({
2557
2617
  */
2558
2618
  ".cm-content": {
2559
2619
  padding: "unset",
2560
- lineHeight: "24px",
2561
2620
  color: "unset"
2562
2621
  },
2563
2622
  /**
@@ -2581,16 +2640,23 @@ var baseTheme = EditorView13.baseTheme({
2581
2640
  * Height is set to match the corresponding line (which may have wrapped).
2582
2641
  */
2583
2642
  ".cm-gutterElement": {
2584
- lineHeight: "24px",
2643
+ lineHeight: 1.5,
2585
2644
  fontSize: "12px"
2586
2645
  },
2587
2646
  /**
2588
2647
  * Line.
2589
2648
  */
2590
2649
  ".cm-line": {
2591
- lineHeight: "24px",
2650
+ lineHeight: 1.5,
2592
2651
  paddingInline: 0
2593
2652
  },
2653
+ /**
2654
+ * Force all inline children to inherit line-height to prevent monospace font metrics
2655
+ * (JetBrains Mono ascent/descent) from inflating the line box beyond 24px.
2656
+ */
2657
+ ".cm-line *": {
2658
+ lineHeight: "inherit"
2659
+ },
2594
2660
  ".cm-activeLine": {
2595
2661
  background: "var(--color-cm-active-line)"
2596
2662
  },
@@ -2768,10 +2834,9 @@ var editorGutter = EditorView13.theme({
2768
2834
  }
2769
2835
  });
2770
2836
  var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2771
- // Set metrics on the scroller (this is often what CM uses for layout).
2837
+ // Main content.
2772
2838
  ".cm-scroller": {
2773
- fontFamily: monospace ? fontMono : fontBody,
2774
- fontSize: "16px"
2839
+ fontFamily: monospace ? fontMono : fontBody
2775
2840
  },
2776
2841
  // Maintain defaults for UI components.
2777
2842
  ".cm-content, .cm-gutters, .cm-panel": {
@@ -2781,9 +2846,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2781
2846
  });
2782
2847
 
2783
2848
  // src/extensions/focus.ts
2784
- import { StateEffect as StateEffect5, StateField as StateField5 } from "@codemirror/state";
2849
+ import { StateEffect as StateEffect6, StateField as StateField5 } from "@codemirror/state";
2785
2850
  import { EditorView as EditorView14 } from "@codemirror/view";
2786
- var focusEffect = StateEffect5.define();
2851
+ var focusEffect = StateEffect6.define();
2787
2852
  var focusField = StateField5.define({
2788
2853
  create: () => false,
2789
2854
  update: (value, tr) => {
@@ -2811,9 +2876,32 @@ var focus = [
2811
2876
  })
2812
2877
  ];
2813
2878
 
2879
+ // src/extensions/scroll-past-end.ts
2880
+ import { EditorView as EditorView15, ViewPlugin as ViewPlugin11 } from "@codemirror/view";
2881
+ var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
2882
+ height = 1e3;
2883
+ attrs = {
2884
+ style: "padding-bottom: 1000px"
2885
+ };
2886
+ update({ view }) {
2887
+ const lastLineBlock = view.lineBlockAt(view.state.doc.length);
2888
+ const height = view.dom.clientHeight - lastLineBlock.height - view.documentPadding.top - 0.5;
2889
+ if (height >= 0 && height !== this.height) {
2890
+ this.height = height;
2891
+ this.attrs = {
2892
+ style: `padding-bottom: ${height}px`
2893
+ };
2894
+ }
2895
+ }
2896
+ });
2897
+ var scrollPastEnd = () => [
2898
+ scrollPastEndPlugin,
2899
+ EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?.attrs ?? null)
2900
+ ];
2901
+
2814
2902
  // src/extensions/factories.ts
2815
2903
  var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
2816
- var tabbable = EditorView15.contentAttributes.of({
2904
+ var tabbable = EditorView16.contentAttributes.of({
2817
2905
  tabindex: "0"
2818
2906
  });
2819
2907
  var filterChars = (chars) => {
@@ -2866,10 +2954,10 @@ var createBasicExtensions = (propsProp) => {
2866
2954
  const props = defaultsDeep2({}, propsProp, defaultBasicOptions);
2867
2955
  return [
2868
2956
  // NOTE: Doesn't catch errors in keymap functions.
2869
- EditorView15.exceptionSink.of((err) => {
2957
+ EditorView16.exceptionSink.of((err) => {
2870
2958
  log8.catch(err, void 0, {
2871
2959
  F: __dxlog_file11,
2872
- L: 131,
2960
+ L: 130,
2873
2961
  S: void 0,
2874
2962
  C: (f, a) => f(...a)
2875
2963
  });
@@ -2881,7 +2969,7 @@ var createBasicExtensions = (propsProp) => {
2881
2969
  props.drawSelection && drawSelection({
2882
2970
  cursorBlinkRate: 1200
2883
2971
  }),
2884
- props.editable !== void 0 && EditorView15.editable.of(props.editable),
2972
+ props.editable !== void 0 && EditorView16.editable.of(props.editable),
2885
2973
  props.focus && focus,
2886
2974
  props.highlightActiveLine && highlightActiveLine(),
2887
2975
  props.history && history(),
@@ -2889,7 +2977,7 @@ var createBasicExtensions = (propsProp) => {
2889
2977
  lineNumbers(),
2890
2978
  editorGutter
2891
2979
  ],
2892
- props.lineWrapping && EditorView15.lineWrapping,
2980
+ props.lineWrapping && EditorView16.lineWrapping,
2893
2981
  props.placeholder && placeholder2(props.placeholder),
2894
2982
  props.readOnly !== void 0 && EditorState.readOnly.of(props.readOnly),
2895
2983
  props.scrollPastEnd && scrollPastEnd(),
@@ -2938,18 +3026,18 @@ var createThemeExtensions = ({ monospace, themeMode, slots: slotsProp, syntaxHig
2938
3026
  const slots = defaultsDeep2({}, slotsProp, defaultThemeSlots);
2939
3027
  return [
2940
3028
  baseTheme,
2941
- EditorView15.darkTheme.of(themeMode === "dark"),
3029
+ EditorView16.darkTheme.of(themeMode === "dark"),
2942
3030
  createFontTheme({
2943
3031
  monospace
2944
3032
  }),
2945
3033
  syntaxHighlightingProp && syntaxHighlighting(HighlightStyle.define(themeMode === "dark" ? defaultStyles.dark : defaultStyles.light)),
2946
- slots.editor?.className && EditorView15.editorAttributes.of({
3034
+ slots.editor?.className && EditorView16.editorAttributes.of({
2947
3035
  class: slots.editor.className
2948
3036
  }),
2949
- slots.content?.className && EditorView15.contentAttributes.of({
3037
+ slots.content?.className && EditorView16.contentAttributes.of({
2950
3038
  class: slots.content.className
2951
3039
  }),
2952
- slots.scroll?.className && ViewPlugin11.fromClass(class {
3040
+ slots.scroll?.className && ViewPlugin12.fromClass(class {
2953
3041
  constructor(view) {
2954
3042
  view.scrollDOM.classList.add(...slots.scroll.className.split(/\s+/));
2955
3043
  }
@@ -2980,7 +3068,7 @@ var createDataExtensions = ({ id, text, messenger, identity }) => {
2980
3068
 
2981
3069
  // src/extensions/folding.ts
2982
3070
  import { codeFolding, foldGutter } from "@codemirror/language";
2983
- import { EditorView as EditorView16 } from "@codemirror/view";
3071
+ import { EditorView as EditorView17 } from "@codemirror/view";
2984
3072
  import { Domino as Domino2, mx as mx4 } from "@dxos/ui";
2985
3073
  var folding = () => {
2986
3074
  return [
@@ -2988,13 +3076,14 @@ var folding = () => {
2988
3076
  placeholderDOM: () => Domino2.of("span").root
2989
3077
  }),
2990
3078
  foldGutter({
3079
+ // NOTE: We can't animate since the element is remounted on state change.
2991
3080
  markerDOM: (open) => {
2992
- return Domino2.of("div").classNames("flex h-full justify-center items-center").children(Domino2.of("svg", Domino2.SVG).classNames(mx4("w-4 h-4 cursor-pointer", open && "rotate-90")).children(Domino2.of("use", Domino2.SVG).attributes({
3081
+ return Domino2.of("div").classNames("flex h-full justify-center items-center").append(Domino2.of("svg", Domino2.SVG).classNames(mx4("w-4 h-4 cursor-pointer", open && "rotate-90")).append(Domino2.of("use", Domino2.SVG).attributes({
2993
3082
  href: Domino2.icon("ph--caret-right--regular")
2994
3083
  }))).root;
2995
3084
  }
2996
3085
  }),
2997
- EditorView16.theme({
3086
+ EditorView17.theme({
2998
3087
  ".cm-foldGutter": {
2999
3088
  opacity: 0.3,
3000
3089
  transition: "opacity 0.3s",
@@ -3008,7 +3097,7 @@ var folding = () => {
3008
3097
  };
3009
3098
 
3010
3099
  // src/extensions/hashtag.ts
3011
- import { Decoration as Decoration8, EditorView as EditorView17, MatchDecorator, ViewPlugin as ViewPlugin12, WidgetType as WidgetType4 } from "@codemirror/view";
3100
+ import { Decoration as Decoration8, EditorView as EditorView18, MatchDecorator, ViewPlugin as ViewPlugin13, WidgetType as WidgetType4 } from "@codemirror/view";
3012
3101
  import { getHashStyles, mx as mx5 } from "@dxos/ui-theme";
3013
3102
  var TagWidget = class extends WidgetType4 {
3014
3103
  _text;
@@ -3029,7 +3118,7 @@ var tagMatcher = new MatchDecorator({
3029
3118
  })
3030
3119
  });
3031
3120
  var hashtag = () => [
3032
- ViewPlugin12.fromClass(class {
3121
+ ViewPlugin13.fromClass(class {
3033
3122
  tags;
3034
3123
  constructor(view) {
3035
3124
  this.tags = tagMatcher.createDeco(view);
@@ -3039,11 +3128,11 @@ var hashtag = () => [
3039
3128
  }
3040
3129
  }, {
3041
3130
  decorations: (instance) => instance.tags,
3042
- provide: (plugin) => EditorView17.atomicRanges.of((view) => {
3131
+ provide: (plugin) => EditorView18.atomicRanges.of((view) => {
3043
3132
  return view.plugin(plugin)?.tags || Decoration8.none;
3044
3133
  })
3045
3134
  }),
3046
- EditorView17.theme({
3135
+ EditorView18.theme({
3047
3136
  ".cm-tag": {
3048
3137
  borderRadius: "4px",
3049
3138
  marginRight: "6px",
@@ -3098,18 +3187,18 @@ var schemaLinter = (validate) => (view) => {
3098
3187
  };
3099
3188
 
3100
3189
  // src/extensions/listener.ts
3101
- import { EditorView as EditorView18 } from "@codemirror/view";
3190
+ import { EditorView as EditorView19 } from "@codemirror/view";
3102
3191
  import { isNonNullable as isNonNullable2 } from "@dxos/util";
3103
3192
  var listener = ({ onFocus, onChange }) => {
3104
3193
  return [
3105
- onFocus && EditorView18.focusChangeEffect.of((state, focusing) => {
3194
+ onFocus && EditorView19.focusChangeEffect.of((state, focusing) => {
3106
3195
  onFocus({
3107
3196
  id: state.facet(documentId),
3108
3197
  focusing
3109
3198
  });
3110
3199
  return null;
3111
3200
  }),
3112
- onChange && EditorView18.updateListener.of(({ state, docChanged }) => {
3201
+ onChange && EditorView19.updateListener.of(({ state, docChanged }) => {
3113
3202
  if (docChanged) {
3114
3203
  onChange({
3115
3204
  id: state.facet(documentId),
@@ -3124,7 +3213,7 @@ var listener = ({ onFocus, onChange }) => {
3124
3213
  import { snippet } from "@codemirror/autocomplete";
3125
3214
  import { syntaxTree as syntaxTree2 } from "@codemirror/language";
3126
3215
  import { EditorSelection as EditorSelection2 } from "@codemirror/state";
3127
- import { EditorView as EditorView19, keymap as keymap8 } from "@codemirror/view";
3216
+ import { EditorView as EditorView20, keymap as keymap8 } from "@codemirror/view";
3128
3217
  import { debounceAndThrottle } from "@dxos/async";
3129
3218
  var formattingEquals = (a, b) => a.blockType === b.blockType && a.strong === b.strong && a.emphasis === b.emphasis && a.strikethrough === b.strikethrough && a.code === b.code && a.link === b.link && a.listStyle === b.listStyle && a.blockQuote === b.blockQuote;
3130
3219
  var Inline = /* @__PURE__ */ (function(Inline2) {
@@ -4213,7 +4302,7 @@ var getFormatting = (state) => {
4213
4302
  };
4214
4303
  };
4215
4304
  var formattingListener = (onStateChange, delay = 100) => {
4216
- return EditorView19.updateListener.of(debounceAndThrottle((update2) => {
4305
+ return EditorView20.updateListener.of(debounceAndThrottle((update2) => {
4217
4306
  if (update2.docChanged || update2.selectionSet) {
4218
4307
  onStateChange(getFormatting(update2.state));
4219
4308
  }
@@ -4274,8 +4363,7 @@ import { completionKeymap } from "@codemirror/autocomplete";
4274
4363
  import { defaultKeymap as defaultKeymap2, indentWithTab as indentWithTab2 } from "@codemirror/commands";
4275
4364
  import { jsonLanguage } from "@codemirror/lang-json";
4276
4365
  import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lang-markdown";
4277
- import { xml } from "@codemirror/lang-xml";
4278
- import { LanguageDescription, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4366
+ import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4279
4367
  import { languages } from "@codemirror/language-data";
4280
4368
  import { keymap as keymap9 } from "@codemirror/view";
4281
4369
  import { isTruthy as isTruthy3 } from "@dxos/util";
@@ -4285,11 +4373,6 @@ import { markdownLanguage } from "@codemirror/lang-markdown";
4285
4373
  import { HighlightStyle as HighlightStyle2 } from "@codemirror/language";
4286
4374
  import { Tag, styleTags, tags } from "@lezer/highlight";
4287
4375
  import { Table } from "@lezer/markdown";
4288
- var styles4 = {
4289
- code: "font-mono no-underline! text-cm-code",
4290
- codeMark: "font-mono text-cm-code-mark",
4291
- mark: "opacity-50"
4292
- };
4293
4376
  var markdownTags = {
4294
4377
  Blockquote: Tag.define(),
4295
4378
  CodeMark: Tag.define(),
@@ -4371,7 +4454,7 @@ var markdownHighlightStyle = (_options = {}) => {
4371
4454
  markdownTags.LinkReference,
4372
4455
  markdownTags.ListMark
4373
4456
  ],
4374
- class: styles4.mark
4457
+ class: markdownTheme.mark
4375
4458
  },
4376
4459
  // Markdown marks.
4377
4460
  {
@@ -4382,7 +4465,7 @@ var markdownHighlightStyle = (_options = {}) => {
4382
4465
  markdownTags.QuoteMark,
4383
4466
  markdownTags.EmphasisMark
4384
4467
  ],
4385
- class: styles4.mark
4468
+ class: markdownTheme.mark
4386
4469
  },
4387
4470
  // E.g., code block language (after ```).
4388
4471
  {
@@ -4391,7 +4474,7 @@ var markdownHighlightStyle = (_options = {}) => {
4391
4474
  tags.function(tags.variableName),
4392
4475
  tags.labelName
4393
4476
  ],
4394
- class: styles4.codeMark
4477
+ class: markdownTheme.codeMark
4395
4478
  },
4396
4479
  // Fonts.
4397
4480
  {
@@ -4457,7 +4540,7 @@ var markdownHighlightStyle = (_options = {}) => {
4457
4540
  markdownTags.CodeText,
4458
4541
  markdownTags.InlineCode
4459
4542
  ],
4460
- class: styles4.code
4543
+ class: markdownTheme.code
4461
4544
  },
4462
4545
  {
4463
4546
  tag: [
@@ -4487,15 +4570,23 @@ var createMarkdownExtensions = (options = {}) => {
4487
4570
  // https://github.com/lezer-parser/markdown?tab=readme-ov-file#github-flavored-markdown
4488
4571
  base: markdownLanguage2,
4489
4572
  // Languages for syntax highlighting fenced code blocks.
4573
+ // Caller-supplied languages are checked first so they can override defaults.
4490
4574
  defaultCodeLanguage: jsonLanguage,
4491
- codeLanguages: languages,
4575
+ codeLanguages: [
4576
+ ...options.codeLanguages ?? [],
4577
+ ...languages
4578
+ ],
4492
4579
  // Don't complete HTML tags.
4493
4580
  completeHTMLTags: false,
4494
4581
  // Parser extensions.
4495
4582
  extensions: [
4496
4583
  // GFM provided by default.
4497
4584
  markdownTagsExtensions,
4498
- ...options.extensions ?? defaultExtensions()
4585
+ ...options.extensions ?? defaultExtensions(),
4586
+ // Disable folding for fenced code blocks by overriding foldNodeProp.
4587
+ // Note: returning null from foldService does not prevent syntaxFolding fallback,
4588
+ // so we must override the node prop directly on the FencedCode node type.
4589
+ noFencedCodeFolding
4499
4590
  ]
4500
4591
  }),
4501
4592
  // Custom styles.
@@ -4510,18 +4601,13 @@ var createMarkdownExtensions = (options = {}) => {
4510
4601
  ].filter(isTruthy3))
4511
4602
  ];
4512
4603
  };
4513
- var xmlLanguageDesc = LanguageDescription.of({
4514
- name: "xml",
4515
- alias: [
4516
- "html",
4517
- "xhtml"
4518
- ],
4519
- extensions: [
4520
- "xml",
4521
- "xhtml"
4522
- ],
4523
- load: async () => xml()
4524
- });
4604
+ var noFencedCodeFolding = {
4605
+ props: [
4606
+ foldNodeProp.add({
4607
+ FencedCode: () => null
4608
+ })
4609
+ ]
4610
+ };
4525
4611
  var defaultExtensions = () => [
4526
4612
  noSetExtHeading,
4527
4613
  noHtml
@@ -4541,19 +4627,19 @@ var debugTree = (cb) => StateField6.define({
4541
4627
  update: (value, tr) => cb(convertTreeToJson(tr.state))
4542
4628
  });
4543
4629
  var convertTreeToJson = (state) => {
4544
- const treeToJson = (cursor2) => {
4630
+ const treeToJson = (cursor) => {
4545
4631
  const node = {
4546
- type: cursor2.type.name,
4547
- from: cursor2.from,
4548
- to: cursor2.to,
4549
- text: state.doc.slice(cursor2.from, cursor2.to).toString(),
4632
+ type: cursor.type.name,
4633
+ from: cursor.from,
4634
+ to: cursor.to,
4635
+ text: state.doc.slice(cursor.from, cursor.to).toString(),
4550
4636
  children: []
4551
4637
  };
4552
- if (cursor2.firstChild()) {
4638
+ if (cursor.firstChild()) {
4553
4639
  do {
4554
- node.children.push(treeToJson(cursor2));
4555
- } while (cursor2.nextSibling());
4556
- cursor2.parent();
4640
+ node.children.push(treeToJson(cursor));
4641
+ } while (cursor.nextSibling());
4642
+ cursor.parent();
4557
4643
  }
4558
4644
  return node;
4559
4645
  };
@@ -4562,17 +4648,16 @@ var convertTreeToJson = (state) => {
4562
4648
 
4563
4649
  // src/extensions/markdown/decorate.ts
4564
4650
  import { syntaxTree as syntaxTree7 } from "@codemirror/language";
4565
- import { Prec as Prec4, RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect6 } from "@codemirror/state";
4566
- import { Decoration as Decoration11, EditorView as EditorView23, ViewPlugin as ViewPlugin14, WidgetType as WidgetType7 } from "@codemirror/view";
4651
+ import { Prec as Prec4, RangeSetBuilder as RangeSetBuilder5, StateEffect as StateEffect7 } from "@codemirror/state";
4652
+ import { Decoration as Decoration11, EditorView as EditorView24, ViewPlugin as ViewPlugin15, WidgetType as WidgetType7 } from "@codemirror/view";
4567
4653
  import { invariant as invariant4 } from "@dxos/invariant";
4568
- import { mx as mx6 } from "@dxos/ui-theme";
4569
4654
 
4570
4655
  // src/extensions/markdown/changes.ts
4571
4656
  import { syntaxTree as syntaxTree4 } from "@codemirror/language";
4572
4657
  import { Transaction as Transaction4 } from "@codemirror/state";
4573
- import { ViewPlugin as ViewPlugin13 } from "@codemirror/view";
4658
+ import { ViewPlugin as ViewPlugin14 } from "@codemirror/view";
4574
4659
  var adjustChanges = () => {
4575
- return ViewPlugin13.fromClass(class {
4660
+ return ViewPlugin14.fromClass(class {
4576
4661
  update(update2) {
4577
4662
  const tree = syntaxTree4(update2.state);
4578
4663
  const adjustments = [];
@@ -4714,7 +4799,7 @@ var getValidUrl = (str) => {
4714
4799
  // src/extensions/markdown/image.ts
4715
4800
  import { syntaxTree as syntaxTree5 } from "@codemirror/language";
4716
4801
  import { StateField as StateField7 } from "@codemirror/state";
4717
- import { Decoration as Decoration9, EditorView as EditorView20, WidgetType as WidgetType5 } from "@codemirror/view";
4802
+ import { Decoration as Decoration9, EditorView as EditorView21, WidgetType as WidgetType5 } from "@codemirror/view";
4718
4803
  var image = (_options = {}) => {
4719
4804
  return [
4720
4805
  StateField7.define({
@@ -4725,10 +4810,10 @@ var image = (_options = {}) => {
4725
4810
  if (!tr.docChanged && !tr.selection) {
4726
4811
  return value;
4727
4812
  }
4728
- const cursor2 = tr.state.selection.main.head;
4813
+ const cursor = tr.state.selection.main.head;
4729
4814
  const oldCursor = tr.changes.mapPos(tr.startState.selection.main.head);
4730
- let from = Math.min(cursor2, oldCursor);
4731
- let to = Math.max(cursor2, oldCursor);
4815
+ let from = Math.min(cursor, oldCursor);
4816
+ let to = Math.max(cursor, oldCursor);
4732
4817
  tr.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
4733
4818
  from = Math.min(from, fromB);
4734
4819
  to = Math.max(to, toB);
@@ -4742,19 +4827,19 @@ var image = (_options = {}) => {
4742
4827
  add: buildDecorations(tr.state, from, to)
4743
4828
  });
4744
4829
  },
4745
- provide: (field) => EditorView20.decorations.from(field)
4830
+ provide: (field) => EditorView21.decorations.from(field)
4746
4831
  })
4747
4832
  ];
4748
4833
  };
4749
4834
  var buildDecorations = (state, from, to) => {
4750
4835
  const decorations2 = [];
4751
- const cursor2 = state.selection.main.head;
4836
+ const cursor = state.selection.main.head;
4752
4837
  syntaxTree5(state).iterate({
4753
4838
  enter: (node) => {
4754
4839
  if (node.name === "Image") {
4755
4840
  const urlNode = node.node.getChild("URL");
4756
4841
  if (urlNode) {
4757
- const hide2 = state.readOnly || cursor2 < node.from || cursor2 > node.to || !state.field(focusField);
4842
+ const hide2 = state.readOnly || cursor < node.from || cursor > node.to || !state.field(focusField);
4758
4843
  const url = state.sliceDoc(urlNode.from, urlNode.to);
4759
4844
  if (url.match(/^https?:\/\//) === null && url.match(/^file?:\/\//) === null) {
4760
4845
  return;
@@ -4802,10 +4887,10 @@ var ImageWidget = class extends WidgetType5 {
4802
4887
  };
4803
4888
 
4804
4889
  // src/extensions/markdown/styles.ts
4805
- import { EditorView as EditorView21 } from "@codemirror/view";
4890
+ import { EditorView as EditorView22 } from "@codemirror/view";
4806
4891
  var bulletListIndentationWidth = 24;
4807
4892
  var orderedListIndentationWidth = 36;
4808
- var formattingStyles = EditorView21.theme({
4893
+ var formattingStyles = EditorView22.theme({
4809
4894
  /**
4810
4895
  * Horizontal rule.
4811
4896
  */
@@ -4840,13 +4925,38 @@ var formattingStyles = EditorView21.theme({
4840
4925
  background: "var(--color-cm-codeblock)",
4841
4926
  borderLeft: "2px solid var(--color-cm-separator)",
4842
4927
  paddingLeft: "1rem",
4843
- margin: "0"
4928
+ margin: 0
4844
4929
  },
4845
4930
  /**
4846
4931
  * Code and codeblocks.
4847
4932
  */
4933
+ "& code": {
4934
+ fontFamily: fontMono,
4935
+ color: "var(--color-cm-code)",
4936
+ whiteSpace: "nowrap"
4937
+ },
4848
4938
  "& .cm-code": {
4849
- fontFamily: fontMono
4939
+ fontFamily: fontMono,
4940
+ color: "var(--color-cm-code)"
4941
+ },
4942
+ // Inline code spans (triggered by backticks) use `cm-code-inline` + `font-mono`.
4943
+ // Different monospace font metrics can slightly overflow the fixed CodeMirror line box,
4944
+ // so constrain them to the target 24px height.
4945
+ "& .cm-code-inline": {
4946
+ fontFamily: fontMono,
4947
+ height: "24px",
4948
+ // display: 'inline-flex',
4949
+ alignItems: "center",
4950
+ overflow: "hidden",
4951
+ whiteSpace: "nowrap",
4952
+ color: "var(--color-cm-code-inline)"
4953
+ },
4954
+ "& .cm-code-mark": {
4955
+ fontFamily: fontMono,
4956
+ height: "24px",
4957
+ display: "inline-flex",
4958
+ alignItems: "center",
4959
+ overflow: "hidden"
4850
4960
  },
4851
4961
  "& .cm-codeblock-line": {
4852
4962
  background: "var(--color-cm-codeblock)",
@@ -4878,16 +4988,24 @@ var formattingStyles = EditorView21.theme({
4878
4988
  */
4879
4989
  ".cm-table *": {
4880
4990
  fontFamily: fontMono,
4991
+ lineHeight: 1.5,
4881
4992
  textDecoration: "none !important"
4882
4993
  },
4883
4994
  ".cm-table-head": {
4884
4995
  padding: "2px 16px 2px 0px",
4996
+ overflowWrap: "break-word",
4997
+ whiteSpace: "pre-wrap",
4998
+ wordBreak: "keep-all",
4885
4999
  textAlign: "left",
4886
- borderBottom: "1px solid var(--color-cm-separator)",
4887
- color: "var(--color-subdued)"
5000
+ color: "var(--color-subdued)",
5001
+ borderBottom: "1px solid var(--color-cm-separator)"
4888
5002
  },
4889
5003
  ".cm-table-cell": {
4890
- padding: "2px 16px 2px 0px"
5004
+ padding: "2px 16px 2px 0px",
5005
+ overflowWrap: "break-word",
5006
+ whiteSpace: "pre-wrap",
5007
+ wordBreak: "keep-all",
5008
+ verticalAlign: "top"
4891
5009
  },
4892
5010
  /**
4893
5011
  * Image.
@@ -4903,12 +5021,12 @@ var formattingStyles = EditorView21.theme({
4903
5021
  },
4904
5022
  ".cm-image-with-loader": {
4905
5023
  display: "block",
4906
- opacity: "0",
5024
+ opacity: 0,
4907
5025
  transitionDuration: "350ms",
4908
5026
  transitionProperty: "opacity"
4909
5027
  },
4910
5028
  ".cm-image-with-loader.cm-loaded-image": {
4911
- opacity: "1"
5029
+ opacity: 1
4912
5030
  },
4913
5031
  ".cm-image-wrapper": {
4914
5032
  "grid-template-columns": "1fr",
@@ -4927,17 +5045,17 @@ var formattingStyles = EditorView21.theme({
4927
5045
  // src/extensions/markdown/table.ts
4928
5046
  import { syntaxTree as syntaxTree6 } from "@codemirror/language";
4929
5047
  import { RangeSetBuilder as RangeSetBuilder4, StateField as StateField8 } from "@codemirror/state";
4930
- import { Decoration as Decoration10, EditorView as EditorView22, WidgetType as WidgetType6 } from "@codemirror/view";
5048
+ import { Decoration as Decoration10, EditorView as EditorView23, WidgetType as WidgetType6 } from "@codemirror/view";
4931
5049
  var table = (options = {}) => {
4932
5050
  return StateField8.define({
4933
5051
  create: (state) => update(state, options),
4934
5052
  update: (_, tr) => update(tr.state, options),
4935
- provide: (field) => EditorView22.decorations.from(field)
5053
+ provide: (field) => EditorView23.decorations.from(field)
4936
5054
  });
4937
5055
  };
4938
5056
  var update = (state, _options) => {
4939
5057
  const builder = new RangeSetBuilder4();
4940
- const cursor2 = state.selection.main.head;
5058
+ const cursor = state.selection.main.head;
4941
5059
  const tables = [];
4942
5060
  const getTable = () => tables[tables.length - 1];
4943
5061
  const getRow = () => {
@@ -4975,7 +5093,7 @@ var update = (state, _options) => {
4975
5093
  }
4976
5094
  });
4977
5095
  tables.forEach((table2) => {
4978
- const replace = state.readOnly || cursor2 < table2.from || cursor2 > table2.to;
5096
+ const replace = state.readOnly || cursor < table2.from || cursor > table2.to;
4979
5097
  if (replace) {
4980
5098
  builder.add(table2.from, table2.to, Decoration10.replace({
4981
5099
  block: true,
@@ -4989,6 +5107,26 @@ var update = (state, _options) => {
4989
5107
  });
4990
5108
  return builder.finish();
4991
5109
  };
5110
+ var renderCellContent = (el, text) => {
5111
+ const parts = text.split(/(`[^`\n]+`|\*\*[^*\n]+\*\*|__[^_\n]+__|\*[^*\n]+\*|_[^_\n]+_)/);
5112
+ for (const part of parts) {
5113
+ if (part.length > 2 && part.startsWith("`") && part.endsWith("`")) {
5114
+ const code = document.createElement("code");
5115
+ code.textContent = part.slice(1, -1);
5116
+ el.appendChild(code);
5117
+ } else if (part.startsWith("**") && part.endsWith("**") || part.startsWith("__") && part.endsWith("__")) {
5118
+ const strong = document.createElement("strong");
5119
+ strong.textContent = part.slice(2, -2);
5120
+ el.appendChild(strong);
5121
+ } else if (part.startsWith("*") && part.endsWith("*") || part.startsWith("_") && part.endsWith("_")) {
5122
+ const em = document.createElement("em");
5123
+ em.textContent = part.slice(1, -1);
5124
+ el.appendChild(em);
5125
+ } else {
5126
+ el.appendChild(document.createTextNode(part));
5127
+ }
5128
+ }
5129
+ };
4992
5130
  var TableWidget = class extends WidgetType6 {
4993
5131
  _table;
4994
5132
  constructor(_table) {
@@ -5008,7 +5146,7 @@ var TableWidget = class extends WidgetType6 {
5008
5146
  this._table.header?.forEach((cell) => {
5009
5147
  const th = document.createElement("th");
5010
5148
  th.setAttribute("class", "cm-table-head");
5011
- tr.appendChild(th).textContent = cell;
5149
+ renderCellContent(tr.appendChild(th), cell);
5012
5150
  });
5013
5151
  const body = table2.appendChild(document.createElement("tbody"));
5014
5152
  this._table.rows?.forEach((row) => {
@@ -5016,7 +5154,7 @@ var TableWidget = class extends WidgetType6 {
5016
5154
  row.forEach((cell) => {
5017
5155
  const td = document.createElement("td");
5018
5156
  td.setAttribute("class", "cm-table-cell");
5019
- tr2.appendChild(td).textContent = cell;
5157
+ renderCellContent(tr2.appendChild(td), cell);
5020
5158
  });
5021
5159
  });
5022
5160
  return div;
@@ -5123,10 +5261,10 @@ var fencedCodeLine = Decoration11.line({
5123
5261
  class: "cm-code cm-codeblock-line"
5124
5262
  });
5125
5263
  var fencedCodeLineFirst = Decoration11.line({
5126
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-start")
5264
+ class: "cm-code cm-codeblock-line cm-codeblock-start"
5127
5265
  });
5128
5266
  var fencedCodeLineLast = Decoration11.line({
5129
- class: mx6("cm-code cm-codeblock-line", "cm-codeblock-end")
5267
+ class: "cm-code cm-codeblock-line cm-codeblock-end"
5130
5268
  });
5131
5269
  var commentBlockLine = fencedCodeLine;
5132
5270
  var commentBlockLineFirst = fencedCodeLineFirst;
@@ -5160,7 +5298,7 @@ var buildDecorations2 = (view, options, focus2) => {
5160
5298
  const getHeaderLevels = (node, level) => {
5161
5299
  invariant4(level > 0, void 0, {
5162
5300
  F: __dxlog_file12,
5163
- L: 179,
5301
+ L: 177,
5164
5302
  S: void 0,
5165
5303
  A: [
5166
5304
  "level > 0",
@@ -5199,7 +5337,7 @@ var buildDecorations2 = (view, options, focus2) => {
5199
5337
  const getCurrentListLevel = () => {
5200
5338
  invariant4(listLevels.length, void 0, {
5201
5339
  F: __dxlog_file12,
5202
- L: 201,
5340
+ L: 199,
5203
5341
  S: void 0,
5204
5342
  A: [
5205
5343
  "listLevels.length",
@@ -5243,7 +5381,7 @@ var buildDecorations2 = (view, options, focus2) => {
5243
5381
  deco: hide
5244
5382
  });
5245
5383
  } else {
5246
- const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + " ";
5384
+ const num = headers.slice(from - 1).map((level2) => level2?.number ?? 0).join(".") + "). ";
5247
5385
  if (num.length) {
5248
5386
  atomicDecoRanges.push({
5249
5387
  from: mark.from,
@@ -5426,11 +5564,11 @@ var buildDecorations2 = (view, options, focus2) => {
5426
5564
  }
5427
5565
  decoRanges.push({
5428
5566
  from: marks[0].to,
5429
- to: marks[1].from,
5567
+ to: !editing && options.renderLinkButton ? node.to : marks[1].from,
5430
5568
  deco: Decoration11.mark({
5431
5569
  tagName: "a",
5432
5570
  attributes: {
5433
- class: "cm-link",
5571
+ class: options.renderLinkButton ? "cm-link cm-link-with-button" : "cm-link",
5434
5572
  href: url,
5435
5573
  rel: "noreferrer",
5436
5574
  target: "_blank"
@@ -5508,18 +5646,21 @@ var buildDecorations2 = (view, options, focus2) => {
5508
5646
  deco.add(from, to, d);
5509
5647
  }
5510
5648
  const atomicDeco = new RangeSetBuilder5();
5511
- for (const { from, to, deco: d } of atomicDecoRanges) {
5512
- atomicDeco.add(from, to, d);
5649
+ for (const { from, to, deco: deco2 } of atomicDecoRanges) {
5650
+ if (from < to && state.doc.lineAt(from).number !== state.doc.lineAt(to).number) {
5651
+ continue;
5652
+ }
5653
+ atomicDeco.add(from, to, deco2);
5513
5654
  }
5514
5655
  return {
5515
5656
  deco: deco.finish(),
5516
5657
  atomicDeco: atomicDeco.finish()
5517
5658
  };
5518
5659
  };
5519
- var forceUpdate = StateEffect6.define();
5660
+ var forceUpdate = StateEffect7.define();
5520
5661
  var decorateMarkdown = (options = {}) => {
5521
5662
  return [
5522
- ViewPlugin14.fromClass(class {
5663
+ ViewPlugin15.fromClass(class {
5523
5664
  deco;
5524
5665
  atomicDeco;
5525
5666
  pendingUpdate;
@@ -5554,9 +5695,9 @@ var decorateMarkdown = (options = {}) => {
5554
5695
  }
5555
5696
  }, {
5556
5697
  provide: (plugin) => [
5557
- Prec4.low(EditorView23.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration11.none)),
5558
- EditorView23.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none),
5559
- EditorView23.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none)
5698
+ Prec4.low(EditorView24.decorations.of((view) => view.plugin(plugin)?.deco ?? Decoration11.none)),
5699
+ EditorView24.decorations.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none),
5700
+ EditorView24.atomicRanges.of((view) => view.plugin(plugin)?.atomicDeco ?? Decoration11.none)
5560
5701
  ]
5561
5702
  }),
5562
5703
  image(),
@@ -5646,8 +5787,8 @@ var mention = ({ debug, onSearch }) => {
5646
5787
  };
5647
5788
 
5648
5789
  // src/extensions/modal.ts
5649
- import { StateEffect as StateEffect7, StateField as StateField9 } from "@codemirror/state";
5650
- var modalStateEffect = StateEffect7.define();
5790
+ import { StateEffect as StateEffect8, StateField as StateField9 } from "@codemirror/state";
5791
+ var modalStateEffect = StateEffect8.define();
5651
5792
  var modalStateField = StateField9.define({
5652
5793
  create: () => false,
5653
5794
  update: (value, tr) => {
@@ -6271,17 +6412,17 @@ var commands = () => keymap11.of([
6271
6412
 
6272
6413
  // src/extensions/outliner/outliner.ts
6273
6414
  import { Prec as Prec5 } from "@codemirror/state";
6274
- import { Decoration as Decoration12, EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6275
- import { mx as mx7 } from "@dxos/ui-theme";
6415
+ import { Decoration as Decoration12, EditorView as EditorView26, ViewPlugin as ViewPlugin18 } from "@codemirror/view";
6416
+ import { mx as mx6 } from "@dxos/ui-theme";
6276
6417
 
6277
6418
  // src/extensions/outliner/editor.ts
6278
6419
  import { EditorSelection as EditorSelection4, EditorState as EditorState2 } from "@codemirror/state";
6279
- import { ViewPlugin as ViewPlugin15 } from "@codemirror/view";
6420
+ import { ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6280
6421
  import { log as log10 } from "@dxos/log";
6281
6422
  var __dxlog_file15 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/outliner/editor.ts";
6282
6423
  var LIST_ITEM_REGEX = /^\s*- (\[ \]|\[x\])? /;
6283
6424
  var initialize = () => {
6284
- return ViewPlugin15.fromClass(class {
6425
+ return ViewPlugin16.fromClass(class {
6285
6426
  constructor(view) {
6286
6427
  const first = view.state.doc.lineAt(0);
6287
6428
  const text = view.state.sliceDoc(first.from, first.to);
@@ -6464,10 +6605,10 @@ var editor = () => [
6464
6605
  ];
6465
6606
 
6466
6607
  // src/extensions/outliner/menu.ts
6467
- import { EditorView as EditorView24, ViewPlugin as ViewPlugin16 } from "@codemirror/view";
6608
+ import { EditorView as EditorView25, ViewPlugin as ViewPlugin17 } from "@codemirror/view";
6468
6609
  import { addEventListener as addEventListener2 } from "@dxos/async";
6469
6610
  var menu = (options = {}) => [
6470
- ViewPlugin16.fromClass(class {
6611
+ ViewPlugin17.fromClass(class {
6471
6612
  view;
6472
6613
  tag;
6473
6614
  rafId;
@@ -6529,7 +6670,7 @@ var menu = (options = {}) => [
6529
6670
  this.rafId = requestAnimationFrame(this.updateButtonPosition.bind(this));
6530
6671
  }
6531
6672
  }),
6532
- EditorView24.theme({
6673
+ EditorView25.theme({
6533
6674
  ".cm-popover-trigger": {
6534
6675
  position: "fixed",
6535
6676
  padding: "0",
@@ -6565,12 +6706,12 @@ var outliner = (_options = {}) => [
6565
6706
  listPaddingLeft: 8
6566
6707
  }),
6567
6708
  // Researve space for menu.
6568
- EditorView25.contentAttributes.of({
6709
+ EditorView26.contentAttributes.of({
6569
6710
  class: "w-full !mr-[3rem]"
6570
6711
  })
6571
6712
  ];
6572
6713
  var decorations = () => [
6573
- ViewPlugin17.fromClass(class {
6714
+ ViewPlugin18.fromClass(class {
6574
6715
  decorations = Decoration12.none;
6575
6716
  constructor(view) {
6576
6717
  this.updateDecorations(view.state, view);
@@ -6595,7 +6736,7 @@ var decorations = () => [
6595
6736
  const lineTo = doc.lineAt(item.contentRange.to);
6596
6737
  const isSelected = selection.includes(item.index) || item === current;
6597
6738
  decorations2.push(Decoration12.line({
6598
- class: mx7("cm-list-item", lineFrom.number === line.number && "cm-list-item-start", lineTo.number === line.number && "cm-list-item-end", isSelected && (hasFocus ? "cm-list-item-focused" : "cm-list-item-selected"))
6739
+ class: mx6("cm-list-item", lineFrom.number === line.number && "cm-list-item-start", lineTo.number === line.number && "cm-list-item-end", isSelected && (hasFocus ? "cm-list-item-focused" : "cm-list-item-selected"))
6599
6740
  }).range(line.from, line.from));
6600
6741
  }
6601
6742
  }
@@ -6605,7 +6746,7 @@ var decorations = () => [
6605
6746
  decorations: (v) => v.decorations
6606
6747
  }),
6607
6748
  // Theme.
6608
- EditorView25.theme(Object.assign({
6749
+ EditorView26.theme(Object.assign({
6609
6750
  ".cm-list-item": {
6610
6751
  borderLeftWidth: "1px",
6611
6752
  borderRightWidth: "1px",
@@ -6640,28 +6781,57 @@ var decorations = () => [
6640
6781
 
6641
6782
  // src/extensions/preview/preview.ts
6642
6783
  import { syntaxTree as syntaxTree10 } from "@codemirror/language";
6643
- import { RangeSetBuilder as RangeSetBuilder6, StateField as StateField11 } from "@codemirror/state";
6644
- import { Decoration as Decoration13, EditorView as EditorView26, WidgetType as WidgetType8 } from "@codemirror/view";
6784
+ import { RangeSetBuilder as RangeSetBuilder6, StateEffect as StateEffect9, StateField as StateField11 } from "@codemirror/state";
6785
+ import { Decoration as Decoration13, EditorView as EditorView27, ViewPlugin as ViewPlugin19, WidgetType as WidgetType8 } from "@codemirror/view";
6786
+ import { DXN, Entity } from "@dxos/echo";
6787
+ var labelResolvedEffect = StateEffect9.define();
6645
6788
  var preview = (options = {}) => {
6789
+ const viewRef = {
6790
+ current: void 0
6791
+ };
6646
6792
  return [
6647
6793
  // NOTE: Atomic block decorations must be created from a state field, now a widget, otherwise it results in the following error:
6648
6794
  // "Block decorations may not be specified via plugins".
6649
6795
  StateField11.define({
6650
- create: (state) => buildDecorations3(state, options),
6796
+ create: (state) => buildDecorations3(state, options, viewRef),
6651
6797
  update: (decorations2, tr) => {
6652
- if (tr.docChanged) {
6653
- return buildDecorations3(tr.state, options);
6798
+ if (tr.docChanged || tr.effects.some((effect) => effect.is(labelResolvedEffect))) {
6799
+ return buildDecorations3(tr.state, options, viewRef);
6654
6800
  }
6655
6801
  return decorations2.map(tr.changes);
6656
6802
  },
6657
6803
  provide: (field) => [
6658
- EditorView26.decorations.from(field),
6659
- EditorView26.atomicRanges.of((view) => view.state.field(field))
6804
+ EditorView27.decorations.from(field),
6805
+ EditorView27.atomicRanges.of((view) => view.state.field(field))
6660
6806
  ]
6807
+ }),
6808
+ ViewPlugin19.define((view) => {
6809
+ viewRef.current = view;
6810
+ return {
6811
+ destroy() {
6812
+ viewRef.current = void 0;
6813
+ }
6814
+ };
6661
6815
  })
6662
6816
  ];
6663
6817
  };
6664
- var buildDecorations3 = (state, options) => {
6818
+ var resolveLabel = (db, dxnStr, viewRef) => {
6819
+ const dxn = DXN.tryParse(dxnStr);
6820
+ if (!dxn) {
6821
+ return;
6822
+ }
6823
+ const ref = db.makeRef(dxn);
6824
+ const target = ref.target;
6825
+ if (target) {
6826
+ return Entity.getLabel(target);
6827
+ }
6828
+ void ref.tryLoad().then(() => {
6829
+ viewRef.current?.dispatch({
6830
+ effects: labelResolvedEffect.of(void 0)
6831
+ });
6832
+ });
6833
+ };
6834
+ var buildDecorations3 = (state, options, viewRef) => {
6665
6835
  const builder = new RangeSetBuilder6();
6666
6836
  syntaxTree10(state).iterate({
6667
6837
  enter: (node) => {
@@ -6673,8 +6843,13 @@ var buildDecorations3 = (state, options) => {
6673
6843
  case "Link": {
6674
6844
  const link = getLinkRef(state, node.node);
6675
6845
  if (link) {
6846
+ const resolved = options.db ? resolveLabel(options.db, link.dxn, viewRef) : void 0;
6847
+ const displayLink = resolved ? {
6848
+ ...link,
6849
+ label: resolved
6850
+ } : link;
6676
6851
  builder.add(node.from, node.to, Decoration13.replace({
6677
- widget: new PreviewInlineWidget(options, link),
6852
+ widget: new PreviewInlineWidget(options, displayLink),
6678
6853
  side: 1
6679
6854
  }));
6680
6855
  }
@@ -6766,7 +6941,7 @@ var PreviewBlockWidget = class extends WidgetType8 {
6766
6941
  };
6767
6942
 
6768
6943
  // src/extensions/replacer.ts
6769
- import { EditorView as EditorView27 } from "@codemirror/view";
6944
+ import { EditorView as EditorView28 } from "@codemirror/view";
6770
6945
  var defaultReplacements = [
6771
6946
  {
6772
6947
  input: "--",
@@ -6829,7 +7004,7 @@ var replacer = ({ replacements = defaultReplacements } = {}) => {
6829
7004
  const sortedReplacements = [
6830
7005
  ...replacements
6831
7006
  ].sort((a, b) => b.input.length - a.input.length);
6832
- return EditorView27.inputHandler.of((view, from, to, insert) => {
7007
+ return EditorView28.inputHandler.of((view, from, to, insert) => {
6833
7008
  if (insert.length !== 1) {
6834
7009
  return false;
6835
7010
  }
@@ -6913,6 +7088,7 @@ var submit = ({ fireIfEmpty = false, onSubmit } = {}) => {
6913
7088
  // src/extensions/tags/extended-markdown.ts
6914
7089
  import { xmlLanguage } from "@codemirror/lang-xml";
6915
7090
  import { parseMixed } from "@lezer/common";
7091
+ var escapeRegExpSource = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
6916
7092
  var extendedMarkdown = ({ registry } = {}) => {
6917
7093
  return [
6918
7094
  createMarkdownExtensions({
@@ -6924,13 +7100,61 @@ var extendedMarkdown = ({ registry } = {}) => {
6924
7100
  {
6925
7101
  name: "SetextHeading",
6926
7102
  parse: () => false
6927
- }
7103
+ },
7104
+ // Custom XML block parser that keeps registered tags as a single HTMLBlock
7105
+ // even when their content contains blank lines.
7106
+ ...xmlBlockParsers(registry)
6928
7107
  ]
6929
7108
  }
6930
7109
  ]
6931
7110
  })
6932
7111
  ];
6933
7112
  };
7113
+ var xmlBlockParsers = (registry) => {
7114
+ const customTags = Object.keys(registry ?? {});
7115
+ if (customTags.length === 0) {
7116
+ return [];
7117
+ }
7118
+ const tagPattern = customTags.map(escapeRegExpSource).join("|");
7119
+ const openPattern = new RegExp(`^\\s*<(${tagPattern})(\\s[^>]*)?>|^\\s*<(${tagPattern})\\s*/>`);
7120
+ return [
7121
+ {
7122
+ name: "XMLBlock",
7123
+ before: "HTMLBlock",
7124
+ parse: (cx, line) => {
7125
+ const match = openPattern.exec(line.text);
7126
+ if (!match) {
7127
+ return false;
7128
+ }
7129
+ if (match[3]) {
7130
+ const end2 = cx.lineStart + line.text.length;
7131
+ cx.addElement(cx.elt("HTMLBlock", cx.lineStart, end2));
7132
+ cx.nextLine();
7133
+ return true;
7134
+ }
7135
+ const tagName = match[1];
7136
+ const closeTag = `</${tagName}>`;
7137
+ const start = cx.lineStart;
7138
+ if (line.text.includes(closeTag)) {
7139
+ cx.addElement(cx.elt("HTMLBlock", start, start + line.text.length));
7140
+ cx.nextLine();
7141
+ return true;
7142
+ }
7143
+ let end = cx.lineStart + line.text.length;
7144
+ while (cx.nextLine()) {
7145
+ end = cx.lineStart + line.text.length;
7146
+ if (line.text.includes(closeTag)) {
7147
+ cx.addElement(cx.elt("HTMLBlock", start, end));
7148
+ cx.nextLine();
7149
+ return true;
7150
+ }
7151
+ }
7152
+ cx.addElement(cx.elt("HTMLBlock", start, end));
7153
+ return true;
7154
+ }
7155
+ }
7156
+ ];
7157
+ };
6934
7158
  var mixedParser = (registry) => {
6935
7159
  const customTags = Object.keys(registry ?? {});
6936
7160
  const tagPattern = new RegExp(`<(${customTags.join("|")})`);
@@ -6964,205 +7188,553 @@ var mixedParser = (registry) => {
6964
7188
  });
6965
7189
  };
6966
7190
 
6967
- // src/extensions/tags/streamer.ts
6968
- import { StateEffect as StateEffect8, StateField as StateField12 } from "@codemirror/state";
6969
- import { Decoration as Decoration14, EditorView as EditorView28, ViewPlugin as ViewPlugin18, WidgetType as WidgetType9 } from "@codemirror/view";
6970
- import { Domino as Domino3 } from "@dxos/ui";
6971
- import { isTruthy as isTruthy4 } from "@dxos/util";
6972
- var BLINK_RATE = 2e3;
6973
- var streamer = (options = {}) => {
6974
- return [
6975
- options.cursor && cursor(),
6976
- options.fadeIn && fadeIn(typeof options.fadeIn === "object" ? options.fadeIn : {})
6977
- ].filter(isTruthy4);
6978
- };
6979
- var cursor = () => {
6980
- const hideCursor = StateEffect8.define();
6981
- const showCursor = StateField12.define({
6982
- create: () => true,
6983
- update: (value, tr) => {
7191
+ // src/extensions/tags/fader.ts
7192
+ import { StateEffect as StateEffect10, StateField as StateField12 } from "@codemirror/state";
7193
+ import { Decoration as Decoration14, EditorView as EditorView29, ViewPlugin as ViewPlugin20 } from "@codemirror/view";
7194
+ var DEFAULT_REMOVAL_DELAY = 5e3;
7195
+ var DEFAULT_COALESCE_WINDOW = 100;
7196
+ var CLEANUP_INTERVAL = 1e3;
7197
+ var fader = (options = {}) => {
7198
+ const removalDelay = DEFAULT_REMOVAL_DELAY;
7199
+ const coalesceWindow = options.coalesce ?? DEFAULT_COALESCE_WINDOW;
7200
+ let lastCount = -1;
7201
+ const log12 = (expiries) => {
7202
+ if (expiries.length !== lastCount) {
7203
+ lastCount = expiries.length;
7204
+ }
7205
+ };
7206
+ const dequeue = StateEffect10.define();
7207
+ const fadeField = StateField12.define({
7208
+ create: () => ({
7209
+ decorations: Decoration14.none,
7210
+ expiries: [],
7211
+ batchStart: 0
7212
+ }),
7213
+ update: ({ decorations: decorations2, expiries, batchStart }, tr) => {
6984
7214
  for (const effect of tr.effects) {
6985
- if (effect.is(hideCursor)) {
6986
- return false;
7215
+ if (effect.is(dequeue)) {
7216
+ const now2 = effect.value;
7217
+ let removeCount = 0;
7218
+ while (removeCount < expiries.length && expiries[removeCount] <= now2) {
7219
+ removeCount++;
7220
+ }
7221
+ if (removeCount > 0) {
7222
+ expiries = expiries.slice(removeCount);
7223
+ let skipped = 0;
7224
+ decorations2 = decorations2.update({
7225
+ filter: () => {
7226
+ if (skipped < removeCount) {
7227
+ skipped++;
7228
+ return false;
7229
+ }
7230
+ return true;
7231
+ }
7232
+ });
7233
+ }
6987
7234
  }
6988
7235
  }
6989
- if (tr.docChanged) {
6990
- return true;
7236
+ if (!tr.docChanged) {
7237
+ log12(expiries);
7238
+ return {
7239
+ decorations: decorations2,
7240
+ expiries,
7241
+ batchStart
7242
+ };
6991
7243
  }
6992
- return value;
6993
- }
7244
+ let isReset = tr.state.doc.length === 0;
7245
+ if (!isReset && tr.startState.doc.length > 0) {
7246
+ tr.changes.iterChanges((fromA, toA) => {
7247
+ if (fromA === 0 && toA === tr.startState.doc.length) {
7248
+ isReset = true;
7249
+ }
7250
+ });
7251
+ }
7252
+ if (isReset) {
7253
+ log12([]);
7254
+ return {
7255
+ decorations: Decoration14.none,
7256
+ expiries: [],
7257
+ batchStart: 0
7258
+ };
7259
+ }
7260
+ const now = Date.now();
7261
+ const add = [];
7262
+ tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7263
+ if (toA === tr.startState.doc.length && inserted.length > 0) {
7264
+ add.push({
7265
+ from: fromB,
7266
+ to: toB
7267
+ });
7268
+ }
7269
+ });
7270
+ if (add.length > 0) {
7271
+ const canCoalesce = expiries.length > 0 && batchStart > 0 && now - batchStart < coalesceWindow;
7272
+ if (canCoalesce) {
7273
+ let lastFrom = -1;
7274
+ let lastTo = -1;
7275
+ decorations2.between(0, tr.state.doc.length, (from, to) => {
7276
+ lastFrom = from;
7277
+ lastTo = to;
7278
+ });
7279
+ if (lastFrom >= 0) {
7280
+ decorations2 = decorations2.update({
7281
+ filter: (from, to) => !(from === lastFrom && to === lastTo)
7282
+ });
7283
+ const mergedFrom = Math.min(lastFrom, add[0].from);
7284
+ const mergedTo = add[add.length - 1].to;
7285
+ decorations2 = decorations2.update({
7286
+ add: [
7287
+ Decoration14.mark({
7288
+ class: "cm-fader"
7289
+ }).range(mergedFrom, mergedTo)
7290
+ ]
7291
+ });
7292
+ expiries = [
7293
+ ...expiries.slice(0, -1),
7294
+ now + removalDelay
7295
+ ];
7296
+ }
7297
+ } else {
7298
+ batchStart = now;
7299
+ expiries = [
7300
+ ...expiries,
7301
+ now + removalDelay
7302
+ ];
7303
+ decorations2 = decorations2.update({
7304
+ add: add.map(({ from, to }) => Decoration14.mark({
7305
+ class: "cm-fader"
7306
+ }).range(from, to))
7307
+ });
7308
+ }
7309
+ }
7310
+ log12(expiries);
7311
+ return {
7312
+ decorations: decorations2,
7313
+ expiries,
7314
+ batchStart
7315
+ };
7316
+ },
7317
+ provide: (f) => EditorView29.decorations.from(f, (value) => value.decorations)
6994
7318
  });
6995
- const timerPlugin = ViewPlugin18.fromClass(class {
7319
+ const cleanup = ViewPlugin20.fromClass(class {
6996
7320
  view;
6997
- timer;
7321
+ #timer;
6998
7322
  constructor(view) {
6999
7323
  this.view = view;
7324
+ this.#schedule();
7000
7325
  }
7001
- update(update2) {
7002
- if (update2.docChanged) {
7003
- clearTimeout(this.timer);
7004
- this.timer = setTimeout(() => {
7005
- this.view.dispatch({
7006
- effects: hideCursor.of(null)
7007
- });
7008
- }, BLINK_RATE);
7326
+ update() {
7327
+ this.#schedule();
7328
+ }
7329
+ #schedule() {
7330
+ const { expiries } = this.view.state.field(fadeField);
7331
+ if (expiries.length === 0) {
7332
+ clearTimeout(this.#timer);
7333
+ this.#timer = void 0;
7334
+ return;
7335
+ }
7336
+ if (this.#timer !== void 0) {
7337
+ return;
7009
7338
  }
7339
+ const delay = Math.max(CLEANUP_INTERVAL, expiries[0] - Date.now());
7340
+ this.#timer = setTimeout(() => {
7341
+ this.#timer = void 0;
7342
+ this.view.dispatch({
7343
+ effects: dequeue.of(Date.now())
7344
+ });
7345
+ }, delay);
7010
7346
  }
7011
7347
  destroy() {
7012
- clearTimeout(this.timer);
7348
+ clearTimeout(this.#timer);
7013
7349
  }
7014
7350
  });
7015
- const cursorDecoration = StateField12.define({
7016
- create: () => Decoration14.none,
7017
- update: (_decorations, tr) => {
7018
- const show = tr.state.field(showCursor);
7019
- if (!show) {
7020
- return Decoration14.none;
7021
- }
7022
- const endPos = tr.state.doc.length;
7023
- return Decoration14.set([
7024
- Decoration14.widget({
7025
- widget: new CursorWidget(),
7026
- side: 1
7027
- }).range(endPos)
7028
- ]);
7029
- },
7030
- provide: (f) => EditorView28.decorations.from(f)
7031
- });
7032
7351
  return [
7033
- showCursor,
7034
- timerPlugin,
7035
- cursorDecoration
7352
+ fadeField,
7353
+ cleanup,
7354
+ EditorView29.theme({
7355
+ ".cm-fader": {
7356
+ animation: "fader 1s ease-out forwards"
7357
+ },
7358
+ "@keyframes fader": {
7359
+ "0%": {
7360
+ textShadow: "0 0 16px rgba(100, 200, 255, 1), 0 0 32px rgba(100, 200, 255, 0.6)"
7361
+ },
7362
+ "100%": {}
7363
+ }
7364
+ })
7036
7365
  ];
7037
7366
  };
7038
- var CursorWidget = class extends WidgetType9 {
7039
- toDOM() {
7040
- const inner = Domino3.of("span").text("\u258F").style({
7041
- animation: "blink 2s infinite"
7042
- });
7043
- return Domino3.of("span").style({
7044
- opacity: "0.8"
7045
- }).children(inner).root;
7046
- }
7047
- };
7048
- var fadeIn = (options = {}) => {
7049
- const FADE_IN_DURATION = 1e3;
7050
- const DEFAULT_REMOVAL_DELAY = 3e3;
7051
- const removalDelay = options.removalDelay ?? DEFAULT_REMOVAL_DELAY;
7052
- const removeDecoration = StateEffect8.define();
7053
- const fadeField = StateField12.define({
7054
- create: () => Decoration14.none,
7055
- update: (decorations2, tr) => {
7056
- let next = decorations2;
7367
+
7368
+ // src/extensions/tags/wire.ts
7369
+ import { Annotation as Annotation3, ChangeSet as ChangeSet2, EditorState as EditorState3, StateEffect as StateEffect11, StateField as StateField13 } from "@codemirror/state";
7370
+ import { Decoration as Decoration15, EditorView as EditorView30, ViewPlugin as ViewPlugin21, WidgetType as WidgetType9 } from "@codemirror/view";
7371
+ import { Domino as Domino3 } from "@dxos/ui";
7372
+ var wireBypass = Annotation3.define();
7373
+ var DEFAULT_RATE = 200;
7374
+ var CURSOR_LINGER = 3e3;
7375
+ var wire = (options = {}) => {
7376
+ const rate = options.rate ?? DEFAULT_RATE;
7377
+ const interval = 1e3 / rate;
7378
+ const streamingTags = options.streamingTags ?? /* @__PURE__ */ new Set();
7379
+ const suppressAppend = StateEffect11.define();
7380
+ const insertChunk = StateEffect11.define();
7381
+ const bufferField = StateField13.define({
7382
+ create: () => ({
7383
+ text: "",
7384
+ insertAt: 0
7385
+ }),
7386
+ update: (value, tr) => {
7387
+ let { text, insertAt } = value;
7057
7388
  for (const effect of tr.effects) {
7058
- if (effect.is(removeDecoration)) {
7059
- const target = effect.value;
7060
- next = next.update({
7061
- filter: (from, to) => !(from === target.from && to === target.to)
7389
+ if (effect.is(suppressAppend)) {
7390
+ text += effect.value.text;
7391
+ if (text.length === effect.value.text.length) {
7392
+ insertAt = effect.value.from;
7393
+ }
7394
+ }
7395
+ if (effect.is(insertChunk)) {
7396
+ text = text.slice(effect.value.text.length);
7397
+ insertAt = effect.value.from + effect.value.text.length;
7398
+ }
7399
+ }
7400
+ if (tr.docChanged) {
7401
+ let isReset = tr.state.doc.length === 0;
7402
+ if (!isReset && tr.startState.doc.length > 0) {
7403
+ tr.changes.iterChanges((fromA, toA) => {
7404
+ if (fromA === 0 && toA === tr.startState.doc.length) {
7405
+ isReset = true;
7406
+ }
7062
7407
  });
7063
7408
  }
7409
+ if (isReset) {
7410
+ return {
7411
+ text: "",
7412
+ insertAt: 0
7413
+ };
7414
+ }
7415
+ if (!tr.effects.some((effect) => effect.is(insertChunk))) {
7416
+ insertAt = tr.changes.mapPos(Math.min(insertAt, tr.startState.doc.length));
7417
+ }
7064
7418
  }
7065
- if (!tr.docChanged) {
7066
- return next;
7419
+ return {
7420
+ text,
7421
+ insertAt
7422
+ };
7423
+ }
7424
+ });
7425
+ const filter = EditorState3.transactionFilter.of((tr) => {
7426
+ if (!tr.docChanged) {
7427
+ return tr;
7428
+ }
7429
+ if (tr.annotation(wireBypass) || tr.effects.some((effect) => effect.is(insertChunk))) {
7430
+ return tr;
7431
+ }
7432
+ let appendedText = "";
7433
+ let appendFrom = -1;
7434
+ let isAppendOnly = true;
7435
+ tr.changes.iterChanges((fromA, toA, _fromB, _toB, inserted) => {
7436
+ if (toA === tr.startState.doc.length && fromA === toA && inserted.length > 0) {
7437
+ appendedText += inserted.sliceString(0);
7438
+ if (appendFrom === -1) {
7439
+ appendFrom = fromA;
7440
+ }
7441
+ } else {
7442
+ isAppendOnly = false;
7067
7443
  }
7068
- let isReset = tr.state.doc.length === 0;
7069
- if (!isReset) {
7070
- tr.changes.iterChanges((fromA, toA) => {
7071
- if (fromA === 0 && toA === tr.startState.doc.length) {
7072
- isReset = true;
7073
- }
7074
- });
7444
+ });
7445
+ if (!isAppendOnly || appendedText.length === 0) {
7446
+ return tr;
7447
+ }
7448
+ return {
7449
+ changes: ChangeSet2.empty(tr.startState.doc.length),
7450
+ effects: suppressAppend.of({
7451
+ from: appendFrom,
7452
+ text: appendedText
7453
+ })
7454
+ };
7455
+ });
7456
+ const drainPlugin = ViewPlugin21.fromClass(class {
7457
+ view;
7458
+ #timer;
7459
+ #activeStreamTag = null;
7460
+ constructor(view) {
7461
+ this.view = view;
7462
+ this.#start();
7463
+ }
7464
+ update(update2) {
7465
+ const buffer = update2.state.field(bufferField);
7466
+ if (buffer.text.length === 0) {
7467
+ this.#activeStreamTag = null;
7075
7468
  }
7076
- if (isReset) {
7077
- return Decoration14.none;
7469
+ if (buffer.text.length > 0 && this.#timer === void 0) {
7470
+ this.#start();
7078
7471
  }
7079
- const add = [];
7080
- tr.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7081
- if (fromB === 0 && toB === inserted.length) {
7472
+ }
7473
+ #start() {
7474
+ this.#timer = setInterval(() => {
7475
+ const { text, insertAt } = this.view.state.field(bufferField);
7476
+ if (text.length === 0) {
7477
+ clearInterval(this.#timer);
7478
+ this.#timer = void 0;
7082
7479
  return;
7083
7480
  }
7084
- if (toA === tr.startState.doc.length && inserted.length > 0) {
7085
- add.push(Decoration14.mark({
7086
- class: "cm-fade-in"
7087
- }).range(fromB, toB));
7481
+ const result = flushable(text, streamingTags, this.#activeStreamTag);
7482
+ if (result.count === 0) {
7483
+ return;
7088
7484
  }
7089
- });
7090
- return next.update({
7091
- add
7092
- });
7485
+ if (result.enterTag) {
7486
+ this.#activeStreamTag = result.enterTag;
7487
+ }
7488
+ if (result.exitTag) {
7489
+ this.#activeStreamTag = null;
7490
+ }
7491
+ const chunk = text.slice(0, result.count);
7492
+ this.view.dispatch({
7493
+ changes: {
7494
+ from: insertAt,
7495
+ insert: chunk
7496
+ },
7497
+ effects: insertChunk.of({
7498
+ from: insertAt,
7499
+ text: chunk
7500
+ })
7501
+ });
7502
+ }, interval);
7503
+ }
7504
+ destroy() {
7505
+ clearInterval(this.#timer);
7506
+ }
7507
+ });
7508
+ return [
7509
+ bufferField,
7510
+ filter,
7511
+ drainPlugin,
7512
+ options.cursor && wireCursor(bufferField)
7513
+ ].filter(Boolean);
7514
+ };
7515
+ var wireCursor = (bufferField) => {
7516
+ const hideCursor = StateEffect11.define();
7517
+ const visibilityField = StateField13.define({
7518
+ create: () => ({
7519
+ visible: false,
7520
+ insertAt: 0,
7521
+ lastNonWsAt: 0
7522
+ }),
7523
+ update: (value, tr) => {
7524
+ const { text, insertAt } = tr.state.field(bufferField);
7525
+ if (text.length > 0) {
7526
+ let lastNonWsAt = tr.changes.mapPos(Math.min(value.lastNonWsAt, tr.startState.doc.length));
7527
+ if (tr.docChanged) {
7528
+ tr.changes.iterChanges((_fromA, _toA, _fromB, _toB, inserted) => {
7529
+ const chunk = inserted.sliceString(0);
7530
+ if (chunk.trim().length > 0) {
7531
+ lastNonWsAt = _fromB + chunk.length;
7532
+ }
7533
+ });
7534
+ }
7535
+ return {
7536
+ visible: true,
7537
+ insertAt,
7538
+ lastNonWsAt
7539
+ };
7540
+ }
7541
+ for (const effect of tr.effects) {
7542
+ if (effect.is(hideCursor)) {
7543
+ return {
7544
+ ...value,
7545
+ visible: false
7546
+ };
7547
+ }
7548
+ }
7549
+ return value;
7550
+ }
7551
+ });
7552
+ const decorationField = StateField13.define({
7553
+ create: () => Decoration15.none,
7554
+ update: (_decorations, tr) => {
7555
+ const { visible, insertAt, lastNonWsAt } = tr.state.field(visibilityField);
7556
+ if (!visible) {
7557
+ return Decoration15.none;
7558
+ }
7559
+ const { text } = tr.state.field(bufferField);
7560
+ const cursorAt = text.length > 0 ? insertAt : lastNonWsAt;
7561
+ const pos = Math.min(cursorAt, tr.state.doc.length);
7562
+ return Decoration15.set([
7563
+ Decoration15.widget({
7564
+ widget: new CursorWidget(),
7565
+ side: 1
7566
+ }).range(pos)
7567
+ ]);
7093
7568
  },
7094
- provide: (f) => EditorView28.decorations.from(f)
7569
+ provide: (field) => EditorView30.decorations.from(field)
7095
7570
  });
7096
- const timerPlugin = ViewPlugin18.fromClass(class {
7571
+ const timerPlugin = ViewPlugin21.fromClass(class {
7097
7572
  view;
7098
- // Map a simple key "from-to" to timer id.
7099
- _timers = /* @__PURE__ */ new Map();
7573
+ #timer;
7100
7574
  constructor(view) {
7101
7575
  this.view = view;
7102
7576
  }
7103
7577
  update(update2) {
7104
- if (!update2.docChanged) {
7105
- return;
7106
- }
7107
- update2.changes.iterChanges((fromA, toA, fromB, toB, inserted) => {
7108
- if (toA !== update2.startState.doc.length || inserted.length === 0) {
7109
- return;
7110
- }
7111
- const key = `${fromB}-${toB}`;
7112
- if (this._timers.has(key)) {
7113
- clearTimeout(this._timers.get(key));
7114
- }
7115
- const totalDelay = FADE_IN_DURATION + removalDelay;
7116
- const id = setTimeout(() => {
7578
+ const { text } = update2.state.field(bufferField);
7579
+ const { visible } = update2.state.field(visibilityField);
7580
+ if (text.length > 0) {
7581
+ clearTimeout(this.#timer);
7582
+ this.#timer = void 0;
7583
+ } else if (visible && this.#timer === void 0) {
7584
+ this.#timer = setTimeout(() => {
7117
7585
  this.view.dispatch({
7118
- effects: removeDecoration.of({
7119
- from: fromB,
7120
- to: toB
7121
- })
7586
+ effects: hideCursor.of(null)
7122
7587
  });
7123
- this._timers.delete(key);
7124
- }, totalDelay);
7125
- this._timers.set(key, id);
7126
- });
7588
+ this.#timer = void 0;
7589
+ }, CURSOR_LINGER);
7590
+ }
7127
7591
  }
7128
7592
  destroy() {
7129
- for (const id of this._timers.values()) {
7130
- clearTimeout(id);
7131
- }
7132
- this._timers.clear();
7593
+ clearTimeout(this.#timer);
7133
7594
  }
7134
7595
  });
7135
7596
  return [
7136
- fadeField,
7137
- timerPlugin,
7138
- EditorView28.theme({
7139
- ".cm-line > span": {
7140
- opacity: "0.8"
7141
- },
7142
- ".cm-fade-in": {
7143
- animation: "fade-in 3s ease-out forwards"
7144
- },
7145
- "@keyframes fade-in": {
7146
- "0%": {
7147
- opacity: "0"
7148
- },
7149
- "80%": {
7150
- opacity: "1"
7151
- },
7152
- "100%": {
7153
- opacity: "0.8"
7154
- }
7155
- }
7156
- })
7597
+ visibilityField,
7598
+ decorationField,
7599
+ timerPlugin
7157
7600
  ];
7158
7601
  };
7602
+ var CursorWidget = class extends WidgetType9 {
7603
+ toDOM() {
7604
+ const inner = Domino3.of("span").text("\u2217").style({
7605
+ animation: "blink 1s infinite",
7606
+ animationDelay: "250ms"
7607
+ });
7608
+ return Domino3.of("span").style({
7609
+ opacity: "0.8"
7610
+ }).append(inner).root;
7611
+ }
7612
+ };
7613
+ var OPENING_TAG_NAME = /^<([a-zA-Z][\w-]*)/;
7614
+ var escapeRegExpSource2 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7615
+ var flushable = (buffer, streamingTags, activeStreamTag) => {
7616
+ if (buffer.length === 0) {
7617
+ return {
7618
+ count: 0
7619
+ };
7620
+ }
7621
+ if (activeStreamTag) {
7622
+ const closeTag = `</${activeStreamTag}>`;
7623
+ if (buffer.startsWith(closeTag)) {
7624
+ return {
7625
+ count: closeTag.length,
7626
+ exitTag: true
7627
+ };
7628
+ }
7629
+ if (buffer[0] === "<") {
7630
+ return {
7631
+ count: xmlElementLength(buffer)
7632
+ };
7633
+ }
7634
+ return {
7635
+ count: 1
7636
+ };
7637
+ }
7638
+ const ch = buffer[0];
7639
+ if (ch === "<") {
7640
+ const nameMatch = buffer.match(OPENING_TAG_NAME);
7641
+ if (nameMatch && streamingTags.has(nameMatch[1])) {
7642
+ const close = buffer.indexOf(">");
7643
+ if (close === -1) {
7644
+ return {
7645
+ count: 0
7646
+ };
7647
+ }
7648
+ if (buffer[close - 1] === "/") {
7649
+ return {
7650
+ count: close + 1
7651
+ };
7652
+ }
7653
+ return {
7654
+ count: close + 1,
7655
+ enterTag: nameMatch[1]
7656
+ };
7657
+ }
7658
+ return {
7659
+ count: xmlElementLength(buffer)
7660
+ };
7661
+ }
7662
+ if (ch === "!" && buffer.length > 1 && buffer[1] === "[") {
7663
+ return {
7664
+ count: linkLength(buffer, 1)
7665
+ };
7666
+ }
7667
+ if (ch === "[") {
7668
+ return {
7669
+ count: linkLength(buffer, 0)
7670
+ };
7671
+ }
7672
+ return {
7673
+ count: 1
7674
+ };
7675
+ };
7676
+ var xmlElementLength = (buffer) => {
7677
+ const close = buffer.indexOf(">");
7678
+ if (close === -1) {
7679
+ return 0;
7680
+ }
7681
+ if (buffer[close - 1] === "/") {
7682
+ return close + 1;
7683
+ }
7684
+ if (buffer[1] === "/") {
7685
+ return close + 1;
7686
+ }
7687
+ const nameMatch = buffer.match(OPENING_TAG_NAME);
7688
+ if (!nameMatch) {
7689
+ return 1;
7690
+ }
7691
+ const tagName = nameMatch[1];
7692
+ let depth = 0;
7693
+ const tagPattern = new RegExp(`<(/?)${escapeRegExpSource2(tagName)}(\\s[^>]*)?>`, "g");
7694
+ let match;
7695
+ while ((match = tagPattern.exec(buffer)) !== null) {
7696
+ const isSelfClosing = match[0].endsWith("/>");
7697
+ const isClosing = match[1] === "/";
7698
+ if (isSelfClosing) {
7699
+ if (depth === 0) {
7700
+ return match.index + match[0].length;
7701
+ }
7702
+ } else if (isClosing) {
7703
+ depth--;
7704
+ if (depth === 0) {
7705
+ return match.index + match[0].length;
7706
+ }
7707
+ } else {
7708
+ depth++;
7709
+ }
7710
+ }
7711
+ return 0;
7712
+ };
7713
+ var linkLength = (buffer, offset) => {
7714
+ const bracketClose = buffer.indexOf("]", offset + 1);
7715
+ if (bracketClose === -1) {
7716
+ return 0;
7717
+ }
7718
+ if (bracketClose + 1 >= buffer.length) {
7719
+ return 0;
7720
+ }
7721
+ if (buffer[bracketClose + 1] !== "(") {
7722
+ return 1;
7723
+ }
7724
+ const parenClose = buffer.indexOf(")", bracketClose + 2);
7725
+ if (parenClose === -1) {
7726
+ return 0;
7727
+ }
7728
+ return parenClose + 1;
7729
+ };
7159
7730
 
7160
7731
  // src/extensions/tags/xml-tags.ts
7161
7732
  import { syntaxTree as syntaxTree11 } from "@codemirror/language";
7162
- import { Prec as Prec7, RangeSetBuilder as RangeSetBuilder7, StateEffect as StateEffect9, StateField as StateField13 } from "@codemirror/state";
7163
- import { Decoration as Decoration15, EditorView as EditorView29, ViewPlugin as ViewPlugin19, WidgetType as WidgetType10, keymap as keymap13 } from "@codemirror/view";
7733
+ import { Prec as Prec7, RangeSetBuilder as RangeSetBuilder7, StateEffect as StateEffect12, StateField as StateField14 } from "@codemirror/state";
7734
+ import { Decoration as Decoration16, EditorView as EditorView31, ViewPlugin as ViewPlugin22, WidgetType as WidgetType10, keymap as keymap13 } from "@codemirror/view";
7164
7735
  import { invariant as invariant7 } from "@dxos/invariant";
7165
7736
  import { log as log11 } from "@dxos/log";
7737
+ import { Domino as Domino4 } from "@dxos/ui";
7166
7738
 
7167
7739
  // src/extensions/tags/xml-util.ts
7168
7740
  import { invariant as invariant6 } from "@dxos/invariant";
@@ -7234,16 +7806,18 @@ var nodeToJson = (state, node) => {
7234
7806
 
7235
7807
  // src/extensions/tags/xml-tags.ts
7236
7808
  var __dxlog_file17 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/tags/xml-tags.ts";
7237
- var navigatePreviousEffect = StateEffect9.define();
7238
- var navigateNextEffect = StateEffect9.define();
7809
+ var navigatePreviousEffect = StateEffect12.define();
7810
+ var navigateNextEffect = StateEffect12.define();
7239
7811
  var getXmlTextChild = (children) => {
7240
7812
  const child = children?.[0];
7241
7813
  return typeof child === "string" ? child : null;
7242
7814
  };
7243
- var xmlTagContextEffect = StateEffect9.define();
7244
- var xmlTagResetEffect = StateEffect9.define();
7245
- var xmlTagUpdateEffect = StateEffect9.define();
7246
- var widgetContextStateField = StateField13.define({
7815
+ var xmlWidgetId = (explicit, fallback) => typeof explicit === "string" && explicit.length > 0 ? explicit : fallback;
7816
+ var escapeRegExpSource3 = (value) => value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
7817
+ var xmlTagContextEffect = StateEffect12.define();
7818
+ var xmlTagResetEffect = StateEffect12.define();
7819
+ var xmlTagUpdateEffect = StateEffect12.define();
7820
+ var widgetContextStateField = StateField14.define({
7247
7821
  create: () => void 0,
7248
7822
  update: (value, tr) => {
7249
7823
  for (const effect of tr.effects) {
@@ -7254,7 +7828,7 @@ var widgetContextStateField = StateField13.define({
7254
7828
  return value;
7255
7829
  }
7256
7830
  });
7257
- var widgetStateMapStateField = StateField13.define({
7831
+ var widgetStateMapStateField = StateField14.define({
7258
7832
  create: () => ({}),
7259
7833
  update: (map, tr) => {
7260
7834
  for (const effect of tr.effects) {
@@ -7268,7 +7842,7 @@ var widgetStateMapStateField = StateField13.define({
7268
7842
  value
7269
7843
  }, {
7270
7844
  F: __dxlog_file17,
7271
- L: 153,
7845
+ L: 184,
7272
7846
  S: void 0,
7273
7847
  C: (f, a) => f(...a)
7274
7848
  });
@@ -7303,7 +7877,7 @@ var createWidgetMap = (setWidgets) => {
7303
7877
  tag: state.props._tag
7304
7878
  }, {
7305
7879
  F: __dxlog_file17,
7306
- L: 206,
7880
+ L: 237,
7307
7881
  S: void 0,
7308
7882
  C: (f, a) => f(...a)
7309
7883
  });
@@ -7319,7 +7893,7 @@ var createWidgetMap = (setWidgets) => {
7319
7893
  tag: state?.props._tag
7320
7894
  }, {
7321
7895
  F: __dxlog_file17,
7322
- L: 212,
7896
+ L: 243,
7323
7897
  S: void 0,
7324
7898
  C: (f, a) => f(...a)
7325
7899
  });
@@ -7352,7 +7926,7 @@ var keyHandlers = keymap13.of([
7352
7926
  }
7353
7927
  ]);
7354
7928
  var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7355
- return EditorView29.updateListener.of((update2) => {
7929
+ return EditorView31.updateListener.of((update2) => {
7356
7930
  update2.transactions.forEach((transaction) => {
7357
7931
  for (const effect of transaction.effects) {
7358
7932
  if (effect.is(navigatePreviousEffect)) {
@@ -7437,7 +8011,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
7437
8011
  });
7438
8012
  });
7439
8013
  };
7440
- var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin19.fromClass(class {
8014
+ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin22.fromClass(class {
7441
8015
  update(update2) {
7442
8016
  const widgetStateMap = update2.state.field(widgetStateMapStateField);
7443
8017
  const { decorations: decorations2 } = update2.state.field(widgetDecorationsField);
@@ -7464,14 +8038,14 @@ var createWidgetUpdatePlugin = (widgetDecorationsField, notifier) => ViewPlugin1
7464
8038
  }
7465
8039
  }
7466
8040
  });
7467
- var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.define({
8041
+ var createWidgetDecorationsField = (registry = {}, notifier) => StateField14.define({
7468
8042
  create: (state) => {
7469
8043
  return buildDecorations4(state, {
7470
8044
  from: 0,
7471
8045
  to: state.doc.length
7472
8046
  }, registry, notifier);
7473
8047
  },
7474
- update: ({ from, decorations: decorations2 }, tr) => {
8048
+ update: ({ from, streamingFrom, decorations: decorations2 }, tr) => {
7475
8049
  for (const effect of tr.effects) {
7476
8050
  if (effect.is(xmlTagResetEffect)) {
7477
8051
  if (tr.docChanged) {
@@ -7482,7 +8056,7 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7482
8056
  }
7483
8057
  return {
7484
8058
  from: 0,
7485
- decorations: Decoration15.none
8059
+ decorations: Decoration16.none
7486
8060
  };
7487
8061
  }
7488
8062
  }
@@ -7495,7 +8069,7 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7495
8069
  to: state.doc.length
7496
8070
  }, {
7497
8071
  F: __dxlog_file17,
7498
- L: 374,
8072
+ L: 405,
7499
8073
  S: void 0,
7500
8074
  C: (f, a) => f(...a)
7501
8075
  });
@@ -7504,13 +8078,17 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7504
8078
  to: state.doc.length
7505
8079
  }, registry, notifier);
7506
8080
  } else {
8081
+ const rebuildFrom = streamingFrom ?? from;
7507
8082
  const result = buildDecorations4(state, {
7508
- from,
8083
+ from: rebuildFrom,
7509
8084
  to: state.doc.length
7510
8085
  }, registry, notifier);
7511
8086
  return {
7512
8087
  from: result.from,
8088
+ streamingFrom: result.streamingFrom,
7513
8089
  decorations: decorations2.update({
8090
+ // Remove old streaming decorations — they are rebuilt each tick.
8091
+ filter: (_f, _t, deco) => !deco.spec.streaming,
7514
8092
  add: decorationSetToArray(result.decorations)
7515
8093
  })
7516
8094
  };
@@ -7518,12 +8096,13 @@ var createWidgetDecorationsField = (registry = {}, notifier) => StateField13.def
7518
8096
  }
7519
8097
  return {
7520
8098
  from,
8099
+ streamingFrom,
7521
8100
  decorations: decorations2
7522
8101
  };
7523
8102
  },
7524
8103
  provide: (field) => [
7525
- EditorView29.decorations.from(field, (v) => v.decorations),
7526
- EditorView29.atomicRanges.of((view) => view.state.field(field).decorations || Decoration15.none)
8104
+ EditorView31.decorations.from(field, (v) => v.decorations),
8105
+ EditorView31.atomicRanges.of((view) => view.state.field(field).decorations || Decoration16.none)
7527
8106
  ]
7528
8107
  });
7529
8108
  var buildDecorations4 = (state, range, registry, notifier) => {
@@ -7534,10 +8113,11 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7534
8113
  if (!tree || tree.type.name === "Program" && tree.length === 0) {
7535
8114
  return {
7536
8115
  from: range.from,
7537
- decorations: Decoration15.none
8116
+ decorations: Decoration16.none
7538
8117
  };
7539
8118
  }
7540
8119
  let last = range.from;
8120
+ let streamingFrom;
7541
8121
  tree.iterate({
7542
8122
  from: range.from,
7543
8123
  to: range.to,
@@ -7550,21 +8130,26 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7550
8130
  if (args) {
7551
8131
  const def = registry[args._tag];
7552
8132
  if (def) {
8133
+ if (def.streaming && !node.node.getChild("CloseTag")) {
8134
+ return false;
8135
+ }
7553
8136
  const { block, factory, Component } = def;
7554
- const widgetState = args.id ? widgetStateMap[args.id] : void 0;
7555
8137
  const nodeRange = {
7556
8138
  from: node.node.from,
7557
8139
  to: node.node.to
7558
8140
  };
8141
+ const widgetId = xmlWidgetId(args.id, def.streaming ? `cm-xml-${nodeRange.from}` : `cm-xml-${nodeRange.from}-${nodeRange.to}`);
8142
+ const widgetState = widgetStateMap[widgetId];
7559
8143
  const props = {
7560
- context,
8144
+ id: widgetId,
7561
8145
  range: nodeRange,
8146
+ context,
7562
8147
  ...args,
7563
8148
  ...widgetState
7564
8149
  };
7565
- const widget = factory ? factory(props) : Component ? args.id && new PlaceholderWidget2(args.id, Component, props, notifier) : void 0;
8150
+ const widget = factory ? factory(props) ?? void 0 : Component ? new PlaceholderWidget2(widgetId, Component, props, notifier) : void 0;
7566
8151
  if (widget) {
7567
- builder.add(nodeRange.from, nodeRange.to, Decoration15.replace({
8152
+ builder.add(nodeRange.from, nodeRange.to, Decoration16.replace({
7568
8153
  widget,
7569
8154
  block,
7570
8155
  atomic: true,
@@ -7578,7 +8163,7 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7578
8163
  } catch (err) {
7579
8164
  log11.catch(err, void 0, {
7580
8165
  F: __dxlog_file17,
7581
- L: 459,
8166
+ L: 514,
7582
8167
  S: void 0,
7583
8168
  C: (f, a) => f(...a)
7584
8169
  });
@@ -7588,8 +8173,65 @@ var buildDecorations4 = (state, range, registry, notifier) => {
7588
8173
  }
7589
8174
  }
7590
8175
  });
8176
+ const streamingTagNames = Object.entries(registry).filter(([, def]) => def.streaming).map(([name]) => name).sort((a, b) => b.length - a.length);
8177
+ if (streamingTagNames.length > 0) {
8178
+ const tailText = state.sliceDoc(range.from, range.to);
8179
+ const streamingPattern = streamingTagNames.map(escapeRegExpSource3).join("|");
8180
+ const tagPattern = new RegExp(`<(${streamingPattern})(\\s[^>]*)?>`, "g");
8181
+ let match;
8182
+ while ((match = tagPattern.exec(tailText)) !== null) {
8183
+ const tagName = match[1];
8184
+ const closeTag = `</${tagName}>`;
8185
+ const afterOpen = match.index + match[0].length;
8186
+ if (tailText.indexOf(closeTag, afterOpen) === -1) {
8187
+ const absoluteFrom = range.from + match.index;
8188
+ const contentFrom = range.from + afterOpen;
8189
+ const innerText = state.sliceDoc(contentFrom, range.to).trim();
8190
+ const def = registry[tagName];
8191
+ const props = {
8192
+ _tag: tagName,
8193
+ context,
8194
+ range: {
8195
+ from: absoluteFrom,
8196
+ to: range.to
8197
+ },
8198
+ children: innerText ? [
8199
+ innerText
8200
+ ] : void 0
8201
+ };
8202
+ const attrPattern = /(\w+)="([^"]*)"/g;
8203
+ let attrMatch;
8204
+ while ((attrMatch = attrPattern.exec(match[0])) !== null) {
8205
+ props[attrMatch[1]] = attrMatch[2];
8206
+ }
8207
+ const widgetId = xmlWidgetId(props.id, `cm-xml-${absoluteFrom}`);
8208
+ const widgetState = widgetStateMap[widgetId];
8209
+ const mergedProps = {
8210
+ ...props,
8211
+ id: widgetId,
8212
+ ...widgetState
8213
+ };
8214
+ const widget = def.factory ? def.factory(mergedProps) ?? void 0 : def.Component ? new PlaceholderWidget2(widgetId, def.Component, mergedProps, notifier, true) : void 0;
8215
+ if (widget) {
8216
+ builder.add(absoluteFrom, range.to, Decoration16.replace({
8217
+ widget,
8218
+ block: def.block,
8219
+ atomic: true,
8220
+ inclusive: true,
8221
+ tag: tagName,
8222
+ streaming: true,
8223
+ contentFrom
8224
+ }));
8225
+ streamingFrom = absoluteFrom;
8226
+ last = absoluteFrom;
8227
+ }
8228
+ break;
8229
+ }
8230
+ }
8231
+ }
7591
8232
  return {
7592
8233
  from: last,
8234
+ streamingFrom,
7593
8235
  decorations: builder.finish()
7594
8236
  };
7595
8237
  };
@@ -7598,12 +8240,14 @@ var PlaceholderWidget2 = class extends WidgetType10 {
7598
8240
  Component;
7599
8241
  props;
7600
8242
  notifier;
7601
- _root = null;
7602
- constructor(id, Component, props, notifier) {
7603
- super(), this.id = id, this.Component = Component, this.props = props, this.notifier = notifier;
8243
+ streaming;
8244
+ #root = null;
8245
+ #view;
8246
+ constructor(id, Component, props, notifier, streaming) {
8247
+ super(), this.id = id, this.Component = Component, this.props = props, this.notifier = notifier, this.streaming = streaming;
7604
8248
  invariant7(id, void 0, {
7605
8249
  F: __dxlog_file17,
7606
- L: 485,
8250
+ L: 617,
7607
8251
  S: this,
7608
8252
  A: [
7609
8253
  "id",
@@ -7612,27 +8256,48 @@ var PlaceholderWidget2 = class extends WidgetType10 {
7612
8256
  });
7613
8257
  }
7614
8258
  get root() {
7615
- return this._root;
8259
+ return this.#root;
7616
8260
  }
7617
8261
  eq(other) {
8262
+ if (this.streaming) {
8263
+ return false;
8264
+ }
7618
8265
  return this.id === other.id;
7619
8266
  }
7620
8267
  ignoreEvent() {
7621
8268
  return true;
7622
8269
  }
7623
- toDOM(_view) {
7624
- this._root = document.createElement("span");
8270
+ toDOM(view) {
8271
+ this.#view = view;
8272
+ this.#root = Domino4.of("div").classNames("min-h-[24px]").root;
8273
+ const props = Object.assign({}, this.props, {
8274
+ view
8275
+ });
7625
8276
  this.notifier.mounted({
7626
8277
  id: this.id,
7627
- root: this._root,
7628
- props: this.props,
8278
+ root: this.#root,
8279
+ props,
7629
8280
  Component: this.Component
7630
8281
  });
7631
- return this._root;
8282
+ return this.#root;
8283
+ }
8284
+ updateDOM(dom) {
8285
+ this.#root = dom;
8286
+ const props = Object.assign({}, this.props, {
8287
+ view: this.#view
8288
+ });
8289
+ this.notifier.mounted({
8290
+ id: this.id,
8291
+ root: this.#root,
8292
+ props,
8293
+ Component: this.Component
8294
+ });
8295
+ return true;
7632
8296
  }
7633
8297
  destroy(_dom) {
7634
8298
  this.notifier.unmounted(this.id);
7635
- this._root = null;
8299
+ this.#root = null;
8300
+ this.#view = void 0;
7636
8301
  }
7637
8302
  };
7638
8303
 
@@ -7696,8 +8361,8 @@ export {
7696
8361
  Cursor,
7697
8362
  EditorInputMode,
7698
8363
  EditorInputModes,
7699
- EditorState3 as EditorState,
7700
- EditorView30 as EditorView,
8364
+ EditorState4 as EditorState,
8365
+ EditorView32 as EditorView,
7701
8366
  EditorViewMode,
7702
8367
  EditorViewModes,
7703
8368
  Inline,
@@ -7716,6 +8381,7 @@ export {
7716
8381
  addStyle,
7717
8382
  annotations,
7718
8383
  autoScroll,
8384
+ autoScrollEffect,
7719
8385
  autocomplete,
7720
8386
  automerge,
7721
8387
  awareness,
@@ -7729,6 +8395,7 @@ export {
7729
8395
  commentClickedEffect,
7730
8396
  comments,
7731
8397
  commentsState,
8398
+ compactSlots,
7732
8399
  convertTreeToJson,
7733
8400
  createBasicExtensions,
7734
8401
  createComment,
@@ -7752,12 +8419,12 @@ export {
7752
8419
  defaultThemeSlots,
7753
8420
  deleteItem,
7754
8421
  documentId,
8422
+ documentSlots,
7755
8423
  dropFile,
8424
+ editorClassNames,
7756
8425
  editorInputMode,
7757
- editorSlots,
7758
- editorWidth,
7759
- editorWithToolbarLayout,
7760
8426
  extendedMarkdown,
8427
+ fader,
7761
8428
  filterChars,
7762
8429
  flattenRect,
7763
8430
  focus,
@@ -7812,6 +8479,7 @@ export {
7812
8479
  removeList,
7813
8480
  removeStyle,
7814
8481
  replacer,
8482
+ scrollPastEnd,
7815
8483
  scrollThreadIntoView,
7816
8484
  scrollToLine,
7817
8485
  scroller,
@@ -7824,9 +8492,7 @@ export {
7824
8492
  setSelection,
7825
8493
  setStyle,
7826
8494
  singleValueFacet,
7827
- stackItemContentEditorClassNames,
7828
8495
  staticCompletion,
7829
- streamer,
7830
8496
  submit,
7831
8497
  tabbable,
7832
8498
  table,
@@ -7845,7 +8511,10 @@ export {
7845
8511
  treeFacet,
7846
8512
  typeahead,
7847
8513
  typewriter,
8514
+ wire,
8515
+ wireBypass,
7848
8516
  wrapWithCatch,
8517
+ xmlElementLength,
7849
8518
  xmlTagContextEffect,
7850
8519
  xmlTagResetEffect,
7851
8520
  xmlTagUpdateEffect,