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