@dxos/ui-editor 0.8.4-main.abd8ff62ef → 0.8.4-main.bc2380dfbc

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 (41) hide show
  1. package/LICENSE +102 -5
  2. package/README.md +1 -1
  3. package/dist/lib/browser/index.mjs +503 -469
  4. package/dist/lib/browser/index.mjs.map +4 -4
  5. package/dist/lib/browser/meta.json +1 -1
  6. package/dist/lib/node-esm/index.mjs +503 -469
  7. package/dist/lib/node-esm/index.mjs.map +4 -4
  8. package/dist/lib/node-esm/meta.json +1 -1
  9. package/dist/types/src/extensions/autocomplete/placeholder.d.ts +5 -2
  10. package/dist/types/src/extensions/autocomplete/placeholder.d.ts.map +1 -1
  11. package/dist/types/src/extensions/index.d.ts +1 -3
  12. package/dist/types/src/extensions/index.d.ts.map +1 -1
  13. package/dist/types/src/extensions/scrolling/auto-scroll.d.ts.map +1 -0
  14. package/dist/types/src/extensions/{scroller.d.ts → scrolling/crawler.d.ts} +13 -6
  15. package/dist/types/src/extensions/scrolling/crawler.d.ts.map +1 -0
  16. package/dist/types/src/extensions/scrolling/index.d.ts +5 -0
  17. package/dist/types/src/extensions/scrolling/index.d.ts.map +1 -0
  18. package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts.map +1 -0
  19. package/dist/types/src/extensions/scrolling/scroller.d.ts +16 -0
  20. package/dist/types/src/extensions/scrolling/scroller.d.ts.map +1 -0
  21. package/dist/types/src/styles/theme.d.ts.map +1 -1
  22. package/dist/types/tsconfig.tsbuildinfo +1 -1
  23. package/package.json +32 -32
  24. package/src/extensions/autocomplete/placeholder.ts +37 -18
  25. package/src/extensions/automerge/automerge.test.tsx +8 -2
  26. package/src/extensions/factories.ts +1 -1
  27. package/src/extensions/index.ts +1 -3
  28. package/src/extensions/outliner/outliner.ts +1 -1
  29. package/src/extensions/{auto-scroll.ts → scrolling/auto-scroll.ts} +37 -25
  30. package/src/extensions/{scroller.ts → scrolling/crawler.ts} +20 -13
  31. package/src/extensions/scrolling/index.ts +8 -0
  32. package/src/extensions/{scroll-past-end.ts → scrolling/scroll-past-end.ts} +6 -6
  33. package/src/extensions/scrolling/scroller.ts +27 -0
  34. package/src/extensions/tags/xml-formatting.ts +1 -1
  35. package/src/extensions/tags/xml-tags.ts +4 -4
  36. package/src/styles/theme.ts +8 -7
  37. package/dist/types/src/extensions/auto-scroll.d.ts.map +0 -1
  38. package/dist/types/src/extensions/scroll-past-end.d.ts.map +0 -1
  39. package/dist/types/src/extensions/scroller.d.ts.map +0 -1
  40. /package/dist/types/src/extensions/{auto-scroll.d.ts → scrolling/auto-scroll.d.ts} +0 -0
  41. /package/dist/types/src/extensions/{scroll-past-end.d.ts → scrolling/scroll-past-end.d.ts} +0 -0
@@ -365,30 +365,37 @@ var insertAtLineStart = (view, from, insert) => {
365
365
  };
366
366
 
367
367
  // src/extensions/autocomplete/placeholder.ts
368
- var placeholder = ({ content, delay = 3e3 }) => {
368
+ var placeholder = ({ content, delay = 3e3, focusOnly = false }) => {
369
369
  const plugin = ViewPlugin3.fromClass(class {
370
370
  _timeout;
371
371
  _decorations = Decoration3.none;
372
372
  update(update2) {
373
+ if (!update2.docChanged && !update2.selectionSet && !update2.focusChanged) {
374
+ return;
375
+ }
373
376
  if (this._timeout) {
374
377
  window.clearTimeout(this._timeout);
375
378
  this._timeout = void 0;
376
379
  }
380
+ this._decorations = Decoration3.none;
381
+ if (focusOnly && !update2.view.hasFocus) {
382
+ return;
383
+ }
377
384
  const activeLine = update2.view.state.doc.lineAt(update2.view.state.selection.main.head);
378
- const isEmpty = activeLine.text.trim() === "";
379
- if (isEmpty) {
380
- const lineStart = activeLine.from;
381
- this._timeout = setTimeout(() => {
382
- this._decorations = Decoration3.set([
383
- Decoration3.widget({
384
- widget: new PlaceholderWidget(content),
385
- side: 1
386
- }).range(lineStart)
387
- ]);
388
- update2.view.update([]);
389
- }, delay);
385
+ if (activeLine.text.trim() !== "") {
386
+ return;
390
387
  }
391
- this._decorations = Decoration3.none;
388
+ const lineStart = activeLine.from;
389
+ const view = update2.view;
390
+ this._timeout = setTimeout(() => {
391
+ this._decorations = Decoration3.set([
392
+ Decoration3.widget({
393
+ widget: new PlaceholderWidget(content),
394
+ side: 1
395
+ }).range(lineStart)
396
+ ]);
397
+ view.update([]);
398
+ }, delay);
392
399
  }
393
400
  destroy() {
394
401
  if (this._timeout) {
@@ -506,341 +513,10 @@ var typeahead = ({ onComplete } = {}) => {
506
513
  ];
507
514
  };
508
515
 
509
- // src/extensions/auto-scroll.ts
510
- import { StateEffect as StateEffect2 } from "@codemirror/state";
511
- import { EditorView as EditorView5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
512
- import { addEventListener, combine, throttle } from "@dxos/async";
513
- import { Domino } from "@dxos/ui";
514
- import { getSize } from "@dxos/ui-theme";
515
-
516
- // src/extensions/scroller.ts
517
- import { StateEffect } from "@codemirror/state";
518
- import { EditorView as EditorView4, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
519
- import { log as log2 } from "@dxos/log";
520
- var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/scroller.ts";
521
- var scrollerLineEffect = StateEffect.define();
522
- var scrollerCrawlEffect = StateEffect.define();
523
- var scrollToLine = (view, options) => {
524
- view.dispatch({
525
- effects: scrollerLineEffect.of(options)
526
- });
527
- };
528
- var scroller = ({ overScroll = 0 } = {}) => {
529
- const scrollPlugin = ViewPlugin5.fromClass(class ScrollerPlugin {
530
- view;
531
- crawler;
532
- constructor(view) {
533
- this.view = view;
534
- this.crawler = createCrawler(this.view);
535
- }
536
- // No-op.
537
- destroy() {
538
- this.crawler.cancel();
539
- }
540
- cancel() {
541
- this.crawler.cancel();
542
- }
543
- crawl(start = false) {
544
- if (start) {
545
- this.crawler.scroll();
546
- } else {
547
- this.crawler.cancel();
548
- }
549
- }
550
- scroll({ line, offset = 0, position, behavior = "instant" }) {
551
- const { scrollTop, scrollHeight, clientHeight } = this.view.scrollDOM;
552
- const scrollerRect = this.view.scrollDOM.getBoundingClientRect();
553
- const doc = this.view.state.doc;
554
- let targetScrollTop = scrollHeight - clientHeight + offset;
555
- if (line >= 0 && line <= doc.lines - 1) {
556
- const lineStart = doc.line(line + 1).from;
557
- const coords = this.view.coordsAtPos(lineStart);
558
- if (coords) {
559
- const currentScrollTop = scrollTop;
560
- const maxScrollTop = scrollHeight - clientHeight;
561
- if (position === "end") {
562
- targetScrollTop = currentScrollTop + coords.bottom - scrollerRect.bottom + offset;
563
- } else {
564
- targetScrollTop = currentScrollTop + coords.top - scrollerRect.top + offset;
565
- }
566
- targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
567
- }
568
- }
569
- requestAnimationFrame(() => {
570
- this.view.scrollDOM.scrollTo({
571
- top: targetScrollTop
572
- });
573
- });
574
- }
575
- });
576
- return [
577
- scrollPlugin,
578
- // Listen for effect.s
579
- EditorView4.updateListener.of((update2) => {
580
- update2.transactions.forEach((transaction) => {
581
- try {
582
- const plugin = update2.view.plugin(scrollPlugin);
583
- if (plugin) {
584
- for (const effect of transaction.effects) {
585
- if (effect.is(scrollerCrawlEffect)) {
586
- plugin.crawl(effect.value);
587
- } else if (effect.is(scrollerLineEffect)) {
588
- plugin.scroll(effect.value);
589
- }
590
- }
591
- }
592
- } catch (err) {
593
- log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 91, S: void 0 });
594
- }
595
- });
596
- }),
597
- // Styles.
598
- EditorView4.theme({
599
- ".cm-scroller": {
600
- overflowY: "scroll",
601
- // Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks
602
- // expanding their TogglePanel), the browser picks a stable element near the viewport
603
- // top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning
604
- // logic still has the final word when pinned (forces scrollTop to scrollHeight).
605
- overflowAnchor: "auto"
606
- },
607
- ".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
608
- display: "none"
609
- },
610
- ".cm-scroller::-webkit-scrollbar-thumb": {
611
- background: "transparent",
612
- transition: "background 0.15s"
613
- },
614
- "&:hover .cm-scroller::-webkit-scrollbar-thumb": {
615
- background: "var(--color-scrollbar-thumb)"
616
- },
617
- // Spacer below the last text line. Implemented as a real block pseudo-element
618
- // (rather than `padding-bottom` on `.cm-content`) so it materializes in the
619
- // scroller's `scrollHeight` regardless of how `padding` is reset by the base
620
- // theme or downstream classes — this is what gives auto-scroll its head-room
621
- // so the last line stays `overScroll` px above the viewport bottom.
622
- ".cm-content::after": {
623
- content: '""',
624
- display: "block",
625
- height: `${overScroll}px`
626
- },
627
- ".cm-scroll-button": {
628
- position: "absolute",
629
- bottom: "0.5rem",
630
- right: "1rem"
631
- }
632
- })
633
- ];
634
- };
635
- function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
636
- const el = view.scrollDOM;
637
- let currentTop = 0;
638
- let velocity = 0;
639
- let rafId = null;
640
- let lastTime = 0;
641
- function frame(now) {
642
- const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1e3);
643
- lastTime = now;
644
- const targetTop = el.scrollHeight - el.clientHeight;
645
- const delta = targetTop - currentTop;
646
- if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
647
- el.scrollTop = targetTop;
648
- currentTop = targetTop;
649
- velocity = 0;
650
- rafId = null;
651
- lastTime = 0;
652
- return;
653
- }
654
- const accel = omega * omega * delta - 2 * omega * velocity;
655
- velocity += accel * dt;
656
- currentTop += velocity * dt;
657
- el.scrollTop = currentTop;
658
- rafId = requestAnimationFrame(frame);
659
- }
660
- return {
661
- scroll: () => {
662
- if (rafId === null) {
663
- currentTop = el.scrollTop;
664
- lastTime = 0;
665
- rafId = requestAnimationFrame(frame);
666
- }
667
- },
668
- cancel: () => {
669
- if (rafId !== null) {
670
- cancelAnimationFrame(rafId);
671
- velocity = 0;
672
- lastTime = 0;
673
- rafId = null;
674
- }
675
- }
676
- };
677
- }
678
-
679
- // src/extensions/auto-scroll.ts
680
- var autoScrollEffect = StateEffect2.define();
681
- var autoScroll = ({ scrollOnResize = true } = {}) => {
682
- let buttonContainer;
683
- let isPinned = true;
684
- let jumpPending = false;
685
- let enabled = true;
686
- let firstUpdate = true;
687
- const setPinned = (pinned) => {
688
- buttonContainer?.classList.toggle("opacity-0", pinned);
689
- isPinned = pinned;
690
- };
691
- return [
692
- // Update listener for scrolling when content changes.
693
- EditorView5.updateListener.of((update2) => {
694
- const { view, heightChanged, state, startState } = update2;
695
- for (const tr of update2.transactions) {
696
- for (const effect of tr.effects) {
697
- if (effect.is(autoScrollEffect)) {
698
- enabled = effect.value;
699
- if (enabled) {
700
- setPinned(true);
701
- view.dispatch({
702
- effects: scrollerCrawlEffect.of(true)
703
- });
704
- } else {
705
- view.dispatch({
706
- effects: scrollerCrawlEffect.of(false)
707
- });
708
- }
709
- }
710
- }
711
- }
712
- if (!enabled) {
713
- return;
714
- }
715
- if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
716
- firstUpdate = false;
717
- jumpPending = true;
718
- requestAnimationFrame(() => {
719
- view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
720
- jumpPending = false;
721
- });
722
- return;
723
- }
724
- firstUpdate = false;
725
- if (jumpPending) {
726
- return;
727
- }
728
- if (heightChanged) {
729
- if (isPinned) {
730
- const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
731
- const delta = scrollHeight - scrollTop - clientHeight;
732
- if (delta > 0) {
733
- setPinned(true);
734
- view.dispatch({
735
- effects: scrollerCrawlEffect.of(true)
736
- });
737
- } else if (delta < -1) {
738
- setPinned(false);
739
- }
740
- } else {
741
- if (state.doc.length === 0) {
742
- setPinned(true);
743
- }
744
- }
745
- }
746
- }),
747
- // Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
748
- // window resize). Doc-driven height changes are handled by the updateListener above; this
749
- // observer covers the case where the viewport changes while the doc length is unchanged.
750
- scrollOnResize ? ViewPlugin6.fromClass(class {
751
- observer;
752
- firstObservation = true;
753
- destroyed = false;
754
- constructor(view) {
755
- const onResize = throttle(() => {
756
- if (this.destroyed || !enabled) {
757
- return;
758
- }
759
- setPinned(true);
760
- requestAnimationFrame(() => {
761
- if (this.destroyed) {
762
- return;
763
- }
764
- view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
765
- view.dispatch({
766
- effects: scrollerCrawlEffect.of(true)
767
- });
768
- });
769
- }, 100);
770
- this.observer = new ResizeObserver(() => {
771
- if (this.firstObservation) {
772
- this.firstObservation = false;
773
- return;
774
- }
775
- onResize();
776
- });
777
- this.observer.observe(view.scrollDOM);
778
- }
779
- destroy() {
780
- this.destroyed = true;
781
- this.observer.disconnect();
782
- }
783
- }) : [],
784
- // Detect user scroll and unpin (or re-pin if scrolled to the bottom).
785
- ViewPlugin6.fromClass(class {
786
- cleanup;
787
- constructor(view) {
788
- this.cleanup = createUserScrollDetector(view.scrollDOM, throttle(() => {
789
- requestAnimationFrame(() => {
790
- const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
791
- const delta = scrollHeight - scrollTop - clientHeight;
792
- const pinned = delta === 0;
793
- setPinned(pinned);
794
- if (!pinned) {
795
- view.dispatch({
796
- effects: scrollerCrawlEffect.of(false)
797
- });
798
- }
799
- });
800
- }, 500));
801
- }
802
- destroy() {
803
- this.cleanup();
804
- }
805
- }),
806
- // Scroll button.
807
- ViewPlugin6.fromClass(class {
808
- constructor(view) {
809
- const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
810
- icon: "ph--arrow-down--regular"
811
- });
812
- const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
813
- "data-density": "fine"
814
- }).append(icon).on("click", () => {
815
- setPinned(true);
816
- view.dispatch({
817
- effects: scrollerLineEffect.of({
818
- line: -1,
819
- position: "end",
820
- behavior: "smooth"
821
- })
822
- });
823
- });
824
- buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
825
- view.scrollDOM.parentElement.appendChild(buttonContainer);
826
- }
827
- })
828
- ];
829
- };
830
- function createUserScrollDetector(element, onUserScroll) {
831
- return combine(addEventListener(element, "wheel", () => onUserScroll(), {
832
- passive: true
833
- }), addEventListener(element, "pointerdown", (event) => {
834
- if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {
835
- onUserScroll();
836
- }
837
- }));
838
- }
839
-
840
516
  // src/extensions/automerge/automerge.ts
841
517
  import { next as A3 } from "@automerge/automerge";
842
518
  import { StateField, Transaction as Transaction2 } from "@codemirror/state";
843
- import { EditorView as EditorView6, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
519
+ import { EditorView as EditorView4, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
844
520
  import { DocAccessor } from "@dxos/echo-db";
845
521
 
846
522
  // src/extensions/state.ts
@@ -849,14 +525,14 @@ var initialSync = Transaction.userEvent.of("initial.sync");
849
525
 
850
526
  // src/extensions/automerge/cursor.ts
851
527
  import { fromCursor, toCursor } from "@dxos/echo-db";
852
- import { log as log3 } from "@dxos/log";
853
- var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/cursor.ts";
528
+ import { log as log2 } from "@dxos/log";
529
+ var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/cursor.ts";
854
530
  var cursorConverter = (accessor) => ({
855
531
  toCursor: (pos, assoc) => {
856
532
  try {
857
533
  return toCursor(accessor, pos, assoc);
858
534
  } catch (err) {
859
- log3.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 11, S: void 0 });
535
+ log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 11, S: void 0 });
860
536
  return "";
861
537
  }
862
538
  },
@@ -864,17 +540,17 @@ var cursorConverter = (accessor) => ({
864
540
  try {
865
541
  return fromCursor(accessor, cursor);
866
542
  } catch (err) {
867
- log3.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 19, S: void 0 });
543
+ log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 19, S: void 0 });
868
544
  return 0;
869
545
  }
870
546
  }
871
547
  });
872
548
 
873
549
  // src/extensions/automerge/defs.ts
874
- import { Annotation, StateEffect as StateEffect3 } from "@codemirror/state";
550
+ import { Annotation, StateEffect } from "@codemirror/state";
875
551
  var getPath = (state, field) => state.field(field).path;
876
552
  var getLastHeads = (state, field) => state.field(field).lastHeads;
877
- var updateHeadsEffect = StateEffect3.define({});
553
+ var updateHeadsEffect = StateEffect.define({});
878
554
  var updateHeads = (newHeads) => updateHeadsEffect.of({
879
555
  newHeads
880
556
  });
@@ -885,7 +561,7 @@ var isReconcile = (tr) => {
885
561
 
886
562
  // src/extensions/automerge/sync.ts
887
563
  import { next as A2 } from "@automerge/automerge";
888
- import { log as log4 } from "@dxos/log";
564
+ import { log as log3 } from "@dxos/log";
889
565
 
890
566
  // src/extensions/automerge/update-automerge.ts
891
567
  import { next as A } from "@automerge/automerge";
@@ -1026,7 +702,7 @@ var charPath = (textPath, candidatePath) => {
1026
702
  };
1027
703
 
1028
704
  // src/extensions/automerge/sync.ts
1029
- var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/sync.ts";
705
+ var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/sync.ts";
1030
706
  var Syncer = class {
1031
707
  _handle;
1032
708
  _state;
@@ -1049,7 +725,7 @@ var Syncer = class {
1049
725
  this._pending = false;
1050
726
  }
1051
727
  onEditorChange(view) {
1052
- log4("onEditorChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 35, S: this });
728
+ log3("onEditorChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 35, S: this });
1053
729
  const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
1054
730
  const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
1055
731
  if (newHeads) {
@@ -1060,7 +736,7 @@ var Syncer = class {
1060
736
  }
1061
737
  }
1062
738
  onAutomergeChange(view) {
1063
- log4("onAutomergeChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 47, S: this });
739
+ log3("onAutomergeChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 47, S: this });
1064
740
  const oldHeads = getLastHeads(view.state, this._state);
1065
741
  const newHeads = A2.getHeads(this._handle.doc());
1066
742
  const diff = A2.equals(oldHeads, newHeads) ? [] : A2.diff(this._handle.doc(), oldHeads, newHeads);
@@ -1113,7 +789,7 @@ var automerge = (accessor) => {
1113
789
  // Track heads.
1114
790
  syncState,
1115
791
  // Reconcile external updates.
1116
- ViewPlugin7.fromClass(class {
792
+ ViewPlugin5.fromClass(class {
1117
793
  _view;
1118
794
  constructor(_view) {
1119
795
  this._view = _view;
@@ -1144,7 +820,7 @@ var automerge = (accessor) => {
1144
820
  };
1145
821
  }),
1146
822
  // Reconcile local updates.
1147
- EditorView6.updateListener.of(({ view, changes, transactions }) => {
823
+ EditorView4.updateListener.of(({ view, changes, transactions }) => {
1148
824
  if (!changes.empty) {
1149
825
  const isInitialSync = transactions.some((tr) => tr.annotation(Transaction2.userEvent) === initialSync.value);
1150
826
  if (!isInitialSync) {
@@ -1157,10 +833,10 @@ var automerge = (accessor) => {
1157
833
 
1158
834
  // src/extensions/awareness/awareness.ts
1159
835
  import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
1160
- import { Decoration as Decoration5, EditorView as EditorView7, ViewPlugin as ViewPlugin8, WidgetType as WidgetType3 } from "@codemirror/view";
836
+ import { Decoration as Decoration5, EditorView as EditorView5, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
1161
837
  import { Event } from "@dxos/async";
1162
838
  import { Context } from "@dxos/context";
1163
- var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness.ts";
839
+ var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness.ts";
1164
840
  var dummyProvider = {
1165
841
  remoteStateChange: new Event(),
1166
842
  open: () => {
@@ -1176,14 +852,14 @@ var RemoteSelectionChangedAnnotation = Annotation2.define();
1176
852
  var awareness = (provider = dummyProvider) => {
1177
853
  return [
1178
854
  awarenessProvider.of(provider),
1179
- ViewPlugin8.fromClass(RemoteSelectionsDecorator, {
855
+ ViewPlugin6.fromClass(RemoteSelectionsDecorator, {
1180
856
  decorations: (value) => value.decorations
1181
857
  }),
1182
858
  styles
1183
859
  ];
1184
860
  };
1185
861
  var RemoteSelectionsDecorator = class {
1186
- _ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 33 });
862
+ _ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 33 });
1187
863
  _cursorConverter;
1188
864
  _provider;
1189
865
  _lastAnchor;
@@ -1332,7 +1008,7 @@ var RemoteCaretWidget = class extends WidgetType3 {
1332
1008
  return true;
1333
1009
  }
1334
1010
  };
1335
- var styles = EditorView7.theme({
1011
+ var styles = EditorView5.theme({
1336
1012
  ".cm-collab-selection": {},
1337
1013
  ".cm-collab-selectionLine": {
1338
1014
  padding: 0,
@@ -1394,8 +1070,8 @@ var styles = EditorView7.theme({
1394
1070
  import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
1395
1071
  import { Context as Context2 } from "@dxos/context";
1396
1072
  import { invariant } from "@dxos/invariant";
1397
- import { log as log5 } from "@dxos/log";
1398
- var __dxlog_file6 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness-provider.ts";
1073
+ import { log as log4 } from "@dxos/log";
1074
+ var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness-provider.ts";
1399
1075
  var DEBOUNCE_INTERVAL = 100;
1400
1076
  var SpaceAwarenessProvider = class {
1401
1077
  _remoteStates = /* @__PURE__ */ new Map();
@@ -1414,7 +1090,7 @@ var SpaceAwarenessProvider = class {
1414
1090
  this._info = info;
1415
1091
  }
1416
1092
  open() {
1417
- this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 28 });
1093
+ this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 28 });
1418
1094
  this._postTask = new DeferredTask(this._ctx, async () => {
1419
1095
  if (this._localState) {
1420
1096
  await this._messenger.postMessage(this._channel, {
@@ -1439,9 +1115,9 @@ var SpaceAwarenessProvider = class {
1439
1115
  void this._messenger.postMessage(this._channel, {
1440
1116
  kind: "query"
1441
1117
  }).catch((err) => {
1442
- log5.debug("failed to query awareness", {
1118
+ log4.debug("failed to query awareness", {
1443
1119
  err
1444
- }, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 57, S: this });
1120
+ }, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 57, S: this });
1445
1121
  });
1446
1122
  }
1447
1123
  close() {
@@ -1453,7 +1129,7 @@ var SpaceAwarenessProvider = class {
1453
1129
  return Array.from(this._remoteStates.values());
1454
1130
  }
1455
1131
  update(position) {
1456
- invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 71, S: this, A: ["this._postTask", ""] });
1132
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 71, S: this, A: ["this._postTask", ""] });
1457
1133
  this._localState = {
1458
1134
  peerId: this._peerId,
1459
1135
  position,
@@ -1462,22 +1138,22 @@ var SpaceAwarenessProvider = class {
1462
1138
  this._postTask.schedule();
1463
1139
  }
1464
1140
  _handleQueryMessage() {
1465
- invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 80, S: this, A: ["this._postTask", ""] });
1141
+ invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 80, S: this, A: ["this._postTask", ""] });
1466
1142
  this._postTask.schedule();
1467
1143
  }
1468
1144
  _handlePostMessage(message) {
1469
- invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 84, S: this, A: ["message.kind === 'post'", ""] });
1145
+ invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 84, S: this, A: ["message.kind === 'post'", ""] });
1470
1146
  this._remoteStates.set(message.state.peerId, message.state);
1471
1147
  this.remoteStateChange.emit();
1472
1148
  }
1473
1149
  };
1474
1150
 
1475
1151
  // src/extensions/blast.ts
1476
- import { EditorView as EditorView8, keymap as keymap3 } from "@codemirror/view";
1152
+ import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
1477
1153
  import defaultsDeep from "lodash.defaultsdeep";
1478
- import { throttle as throttle2 } from "@dxos/async";
1154
+ import { throttle } from "@dxos/async";
1479
1155
  import { invariant as invariant2 } from "@dxos/invariant";
1480
- var __dxlog_file7 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/blast.ts";
1156
+ var __dxlog_file6 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/blast.ts";
1481
1157
  var defaultOptions = {
1482
1158
  effect: 2,
1483
1159
  maxParticles: 200,
@@ -1522,7 +1198,7 @@ var blast = (options = defaultOptions) => {
1522
1198
  };
1523
1199
  return [
1524
1200
  // Cursor moved.
1525
- EditorView8.updateListener.of((update2) => {
1201
+ EditorView6.updateListener.of((update2) => {
1526
1202
  if (blaster?.node !== update2.view.scrollDOM) {
1527
1203
  if (blaster) {
1528
1204
  blaster.destroy();
@@ -1595,7 +1271,7 @@ var Blaster = class {
1595
1271
  return this._node;
1596
1272
  }
1597
1273
  initialize() {
1598
- invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
1274
+ invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
1599
1275
  this._canvas = document.createElement("canvas");
1600
1276
  this._canvas.id = "code-blast-canvas";
1601
1277
  this._canvas.style.position = "absolute";
@@ -1624,7 +1300,7 @@ var Blaster = class {
1624
1300
  }
1625
1301
  }
1626
1302
  start() {
1627
- invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
1303
+ invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
1628
1304
  this._running = true;
1629
1305
  this.loop();
1630
1306
  }
@@ -1651,11 +1327,11 @@ var Blaster = class {
1651
1327
  this.drawParticles();
1652
1328
  requestAnimationFrame(this.loop.bind(this));
1653
1329
  }
1654
- shake = throttle2(({ time }) => {
1330
+ shake = throttle(({ time }) => {
1655
1331
  this._shakeTime = this._shakeTimeMax || time;
1656
1332
  this._shakeTimeMax = time;
1657
1333
  }, 100);
1658
- spawn = throttle2(({ element, point }) => {
1334
+ spawn = throttle(({ element, point }) => {
1659
1335
  const color = getRGBComponents(element, this._options.color);
1660
1336
  const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
1661
1337
  const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
@@ -1764,9 +1440,9 @@ var random = (min, max) => {
1764
1440
 
1765
1441
  // src/extensions/blocks.ts
1766
1442
  import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
1767
- import { Decoration as Decoration6, EditorView as EditorView9, ViewPlugin as ViewPlugin9 } from "@codemirror/view";
1443
+ import { Decoration as Decoration6, EditorView as EditorView7, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
1768
1444
  import { mx as mx2 } from "@dxos/ui-theme";
1769
- var paragraphBlockPlugin = ViewPlugin9.fromClass(class {
1445
+ var paragraphBlockPlugin = ViewPlugin7.fromClass(class {
1770
1446
  decorations;
1771
1447
  constructor(view) {
1772
1448
  this.decorations = this.build(view);
@@ -1825,7 +1501,7 @@ var paragraphBlockPlugin = ViewPlugin9.fromClass(class {
1825
1501
  });
1826
1502
  var blocks = () => [
1827
1503
  paragraphBlockPlugin,
1828
- EditorView9.baseTheme({
1504
+ EditorView7.baseTheme({
1829
1505
  ".cm-line.block-line": {
1830
1506
  paddingLeft: "0.75rem",
1831
1507
  paddingRight: "0.75rem",
@@ -1859,13 +1535,13 @@ var blocks = () => [
1859
1535
  ];
1860
1536
 
1861
1537
  // src/extensions/bookmarks.ts
1862
- import { Prec as Prec3, StateEffect as StateEffect4, StateField as StateField2 } from "@codemirror/state";
1538
+ import { Prec as Prec3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
1863
1539
  import { keymap as keymap4 } from "@codemirror/view";
1864
- import { log as log6 } from "@dxos/log";
1865
- var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
1866
- var addBookmark = StateEffect4.define();
1867
- var removeBookmark = StateEffect4.define();
1868
- var clearBookmarks = StateEffect4.define();
1540
+ import { log as log5 } from "@dxos/log";
1541
+ var __dxlog_file7 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
1542
+ var addBookmark = StateEffect2.define();
1543
+ var removeBookmark = StateEffect2.define();
1544
+ var clearBookmarks = StateEffect2.define();
1869
1545
  var bookmarks = () => {
1870
1546
  return [
1871
1547
  bookmarksField,
@@ -1874,7 +1550,7 @@ var bookmarks = () => {
1874
1550
  key: "Mod-ArrowUp",
1875
1551
  run: (view) => {
1876
1552
  const bookmarks2 = view.state.field(bookmarksField);
1877
- log6("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 18, S: void 0 });
1553
+ log5("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 18, S: void 0 });
1878
1554
  return true;
1879
1555
  }
1880
1556
  },
@@ -1882,7 +1558,7 @@ var bookmarks = () => {
1882
1558
  key: "Mod-ArrowDown",
1883
1559
  run: (view) => {
1884
1560
  const bookmarks2 = view.state.field(bookmarksField);
1885
- log6("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0 });
1561
+ log5("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 26, S: void 0 });
1886
1562
  return true;
1887
1563
  }
1888
1564
  }
@@ -1919,27 +1595,27 @@ var bookmarksField = StateField2.define({
1919
1595
 
1920
1596
  // src/extensions/comments.ts
1921
1597
  import { invertedEffects } from "@codemirror/commands";
1922
- import { StateEffect as StateEffect5, StateField as StateField3 } from "@codemirror/state";
1923
- import { Decoration as Decoration7, EditorView as EditorView11, ViewPlugin as ViewPlugin10, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
1598
+ import { StateEffect as StateEffect3, StateField as StateField3 } from "@codemirror/state";
1599
+ import { Decoration as Decoration7, EditorView as EditorView9, ViewPlugin as ViewPlugin8, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
1924
1600
  import sortBy from "lodash.sortby";
1925
1601
  import { debounce as debounce2 } from "@dxos/async";
1926
- import { log as log7 } from "@dxos/log";
1602
+ import { log as log6 } from "@dxos/log";
1927
1603
  import { isNonNullable } from "@dxos/util";
1928
1604
 
1929
1605
  // src/extensions/selection.ts
1930
1606
  import { Transaction as Transaction3 } from "@codemirror/state";
1931
- import { EditorView as EditorView10, keymap as keymap5 } from "@codemirror/view";
1607
+ import { EditorView as EditorView8, keymap as keymap5 } from "@codemirror/view";
1932
1608
  import { debounce } from "@dxos/async";
1933
1609
  import { invariant as invariant3 } from "@dxos/invariant";
1934
1610
  import { isTruthy } from "@dxos/util";
1935
- var __dxlog_file9 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/selection.ts";
1611
+ var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/selection.ts";
1936
1612
  var documentId = singleValueFacet();
1937
1613
  var stateRestoreAnnotation = "org.dxos.cm.state-restore";
1938
1614
  var createEditorStateTransaction = ({ scrollTo, selection }) => {
1939
1615
  return {
1940
1616
  selection,
1941
1617
  scrollIntoView: !scrollTo,
1942
- effects: scrollTo ? EditorView10.scrollIntoView(scrollTo, {
1618
+ effects: scrollTo ? EditorView8.scrollIntoView(scrollTo, {
1943
1619
  yMargin: 96
1944
1620
  }) : void 0,
1945
1621
  annotations: Transaction3.userEvent.of(stateRestoreAnnotation)
@@ -1947,12 +1623,12 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
1947
1623
  };
1948
1624
  var createEditorStateStore = (keyPrefix) => ({
1949
1625
  getState: (id) => {
1950
- invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 26, S: void 0, A: ["id", ""] });
1626
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0, A: ["id", ""] });
1951
1627
  const state = localStorage.getItem(`${keyPrefix}/${id}`);
1952
1628
  return state ? JSON.parse(state) : void 0;
1953
1629
  },
1954
1630
  setState: (id, state) => {
1955
- invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 31, S: void 0, A: ["id", ""] });
1631
+ invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 31, S: void 0, A: ["id", ""] });
1956
1632
  localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
1957
1633
  }
1958
1634
  });
@@ -1965,7 +1641,7 @@ var selectionState = ({ getState, setState } = {}) => {
1965
1641
  // setStateDebounced(id, {});
1966
1642
  // },
1967
1643
  // }),
1968
- EditorView10.updateListener.of(({ view, transactions }) => {
1644
+ EditorView8.updateListener.of(({ view, transactions }) => {
1969
1645
  const id = view.state.facet(documentId);
1970
1646
  if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
1971
1647
  return;
@@ -2004,10 +1680,10 @@ var selectionState = ({ getState, setState } = {}) => {
2004
1680
  };
2005
1681
 
2006
1682
  // src/extensions/comments.ts
2007
- var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
2008
- var setComments = StateEffect5.define();
2009
- var setSelection = StateEffect5.define();
2010
- var setCommentState = StateEffect5.define();
1683
+ var __dxlog_file9 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
1684
+ var setComments = StateEffect3.define();
1685
+ var setSelection = StateEffect3.define();
1686
+ var setCommentState = StateEffect3.define();
2011
1687
  var commentsState = StateField3.define({
2012
1688
  create: (state) => ({
2013
1689
  id: state.facet(documentId),
@@ -2046,7 +1722,7 @@ var commentsState = StateField3.define({
2046
1722
  return value;
2047
1723
  }
2048
1724
  });
2049
- var styles2 = EditorView11.theme({
1725
+ var styles2 = EditorView9.theme({
2050
1726
  ".cm-comment, .cm-comment-current": {
2051
1727
  padding: "3px 0",
2052
1728
  color: "var(--color-cm-comment-text)",
@@ -2067,14 +1743,14 @@ var createCommentMark = (id, isCurrent) => Decoration7.mark({
2067
1743
  "data-comment-id": id
2068
1744
  }
2069
1745
  });
2070
- var commentsDecorations = EditorView11.decorations.compute([
1746
+ var commentsDecorations = EditorView9.decorations.compute([
2071
1747
  commentsState
2072
1748
  ], (state) => {
2073
1749
  const { selection: { current }, comments: comments2 } = state.field(commentsState);
2074
1750
  const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
2075
1751
  const range = comment.range;
2076
1752
  if (!range) {
2077
- log7.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file10, L: 93, S: void 0 });
1753
+ log6.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 93, S: void 0 });
2078
1754
  return void 0;
2079
1755
  } else if (range.from === range.to) {
2080
1756
  return void 0;
@@ -2084,8 +1760,8 @@ var commentsDecorations = EditorView11.decorations.compute([
2084
1760
  }).filter(isNonNullable);
2085
1761
  return Decoration7.set(decorations2);
2086
1762
  });
2087
- var commentClickedEffect = StateEffect5.define();
2088
- var handleCommentClick = EditorView11.domEventHandlers({
1763
+ var commentClickedEffect = StateEffect3.define();
1764
+ var handleCommentClick = EditorView9.domEventHandlers({
2089
1765
  click: (event, view) => {
2090
1766
  let target = event.target;
2091
1767
  const editorRoot = view.dom;
@@ -2124,7 +1800,7 @@ var trackPastedComments = (onUpdate) => {
2124
1800
  }
2125
1801
  };
2126
1802
  return [
2127
- EditorView11.domEventHandlers({
1803
+ EditorView9.domEventHandlers({
2128
1804
  cut: handleTrack,
2129
1805
  copy: handleTrack
2130
1806
  }),
@@ -2146,7 +1822,7 @@ var trackPastedComments = (onUpdate) => {
2146
1822
  return effects;
2147
1823
  }),
2148
1824
  // Handle paste or the undo of comment deletion.
2149
- EditorView11.updateListener.of((update2) => {
1825
+ EditorView9.updateListener.of((update2) => {
2150
1826
  const restore = [];
2151
1827
  for (let i = 0; i < update2.transactions.length; i++) {
2152
1828
  const tr = update2.transactions[i];
@@ -2202,7 +1878,7 @@ var mapTrackedComment = (comment, changes) => ({
2202
1878
  from: changes.mapPos(comment.from, 1),
2203
1879
  to: changes.mapPos(comment.to, 1)
2204
1880
  });
2205
- var restoreCommentEffect = StateEffect5.define({
1881
+ var restoreCommentEffect = StateEffect3.define({
2206
1882
  map: mapTrackedComment
2207
1883
  });
2208
1884
  var createComment = (view) => {
@@ -2288,7 +1964,7 @@ var comments = (options = {}) => {
2288
1964
  //
2289
1965
  // Track deleted ranges and update ranges for decorations.
2290
1966
  //
2291
- EditorView11.updateListener.of(({ view, state, changes }) => {
1967
+ EditorView9.updateListener.of(({ view, state, changes }) => {
2292
1968
  let mod = false;
2293
1969
  const { comments: comments2, ...value } = state.field(commentsState);
2294
1970
  changes.iterChanges((from, to, from2, to2) => {
@@ -2320,7 +1996,7 @@ var comments = (options = {}) => {
2320
1996
  //
2321
1997
  // Track selection/proximity.
2322
1998
  //
2323
- EditorView11.updateListener.of(({ view, state }) => {
1999
+ EditorView9.updateListener.of(({ view, state }) => {
2324
2000
  let min = Infinity;
2325
2001
  const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
2326
2002
  const { head } = state.selection.main;
@@ -2374,7 +2050,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
2374
2050
  anchor: range.from
2375
2051
  } : void 0,
2376
2052
  effects: [
2377
- needsScroll ? EditorView11.scrollIntoView(range.from, center ? {
2053
+ needsScroll ? EditorView9.scrollIntoView(range.from, center ? {
2378
2054
  y: "center"
2379
2055
  } : void 0) : [],
2380
2056
  needsSelectionUpdate ? setSelection.of({
@@ -2405,7 +2081,7 @@ var ExternalCommentSync = class {
2405
2081
  this.unsubscribe();
2406
2082
  };
2407
2083
  };
2408
- var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin10.fromClass(class {
2084
+ var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin8.fromClass(class {
2409
2085
  constructor(view) {
2410
2086
  return new ExternalCommentSync(view, id, subscribe, getComments);
2411
2087
  }
@@ -2425,12 +2101,12 @@ var debugNodeLogger = (log12 = console.log) => {
2425
2101
  };
2426
2102
 
2427
2103
  // src/extensions/dnd.ts
2428
- import { EditorView as EditorView12, dropCursor } from "@codemirror/view";
2104
+ import { EditorView as EditorView10, dropCursor } from "@codemirror/view";
2429
2105
  var dropFile = (options = {}) => {
2430
2106
  return [
2431
2107
  styles3,
2432
2108
  dropCursor(),
2433
- EditorView12.domEventHandlers({
2109
+ EditorView10.domEventHandlers({
2434
2110
  drop: (event, view) => {
2435
2111
  event.preventDefault();
2436
2112
  const files = event.dataTransfer?.files;
@@ -2449,7 +2125,7 @@ var dropFile = (options = {}) => {
2449
2125
  })
2450
2126
  ];
2451
2127
  };
2452
- var styles3 = EditorView12.theme({
2128
+ var styles3 = EditorView10.theme({
2453
2129
  ".cm-dropCursor": {
2454
2130
  borderLeft: "2px solid var(--color-accent-text)",
2455
2131
  color: "var(--color-accent-text)",
@@ -2471,10 +2147,10 @@ import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode"
2471
2147
  import defaultsDeep2 from "lodash.defaultsdeep";
2472
2148
  import { generateName } from "@dxos/display-name";
2473
2149
  import { log as log8 } from "@dxos/log";
2474
- import { hexToHue, isTruthy as isTruthy2 } from "@dxos/util";
2150
+ import { hexToHue, isTruthy as isTruthy3 } from "@dxos/util";
2475
2151
 
2476
2152
  // src/styles/theme.ts
2477
- import { EditorView as EditorView13 } from "@codemirror/view";
2153
+ import { EditorView as EditorView11 } from "@codemirror/view";
2478
2154
  import { mx as mx3 } from "@dxos/ui-theme";
2479
2155
  var headings = {
2480
2156
  1: {
@@ -2522,7 +2198,7 @@ var markdownTheme = {
2522
2198
  fontWeight: "100 !important"
2523
2199
  })
2524
2200
  };
2525
- var baseTheme = EditorView13.baseTheme({
2201
+ var baseTheme = EditorView11.baseTheme({
2526
2202
  /**
2527
2203
  * Outer frame.
2528
2204
  */
@@ -2534,7 +2210,7 @@ var baseTheme = EditorView13.baseTheme({
2534
2210
  * Scroller
2535
2211
  */
2536
2212
  ".cm-scroller": {
2537
- // Browser scroll-anchoring: see comment in `scroller.ts`. `auto` lets the browser pin a
2213
+ // Browser scroll-anchoring: see comment in `scrolling/crawler.ts`. `auto` lets the browser pin a
2538
2214
  // stable element near the viewport top so widget resizes (e.g. tool-block TogglePanel
2539
2215
  // open/close) don't jump the user's view.
2540
2216
  overflowAnchor: "auto"
@@ -2645,7 +2321,8 @@ var baseTheme = EditorView13.baseTheme({
2645
2321
  textDecorationThickness: "1px",
2646
2322
  textDecorationColor: "var(--color-separator)",
2647
2323
  textUnderlineOffset: "2px",
2648
- borderRadius: ".125rem"
2324
+ borderRadius: ".125rem",
2325
+ cursor: "pointer"
2649
2326
  },
2650
2327
  ".cm-link > span": {
2651
2328
  color: "var(--color-accent-text)"
@@ -2683,12 +2360,12 @@ var baseTheme = EditorView13.baseTheme({
2683
2360
  padding: "4px"
2684
2361
  },
2685
2362
  ".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {
2686
- background: "var(--color-active-surface)",
2687
- color: "var(--color-base-surface-text)"
2363
+ background: "var(--color-current-surface)",
2364
+ color: "var(--color-base-foreground)"
2688
2365
  },
2689
2366
  ".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
2690
2367
  paddingLeft: "4px !important",
2691
- color: "var(--color-base-surface-text)"
2368
+ color: "var(--color-base-foreground)"
2692
2369
  },
2693
2370
  /**
2694
2371
  * Completion info.
@@ -2707,7 +2384,7 @@ var baseTheme = EditorView13.baseTheme({
2707
2384
  padding: "0 4px"
2708
2385
  },
2709
2386
  ".cm-completionMatchedText": {
2710
- color: "var(--color-base-surface-text)",
2387
+ color: "var(--color-base-foreground)",
2711
2388
  textDecoration: "none !important"
2712
2389
  },
2713
2390
  /**
@@ -2742,7 +2419,7 @@ var baseTheme = EditorView13.baseTheme({
2742
2419
  backgroundColor: "var(--color-input-surface)"
2743
2420
  },
2744
2421
  ".cm-panel input:focus, .cm-panel button:focus": {
2745
- outline: "1px solid var(--color-neutral-focus-indicator)"
2422
+ outline: "1px solid var(--color-focus-ring-subtle)"
2746
2423
  },
2747
2424
  ".cm-panel label": {
2748
2425
  display: "inline-flex",
@@ -2755,7 +2432,7 @@ var baseTheme = EditorView13.baseTheme({
2755
2432
  height: "8px",
2756
2433
  marginRight: "6px !important",
2757
2434
  padding: "2px !important",
2758
- color: "var(--color-neutral-focus-indicator)"
2435
+ color: "var(--color-focus-ring-subtle)"
2759
2436
  },
2760
2437
  ".cm-panel button": {
2761
2438
  "&:hover": {
@@ -2771,14 +2448,14 @@ var baseTheme = EditorView13.baseTheme({
2771
2448
  borderTop: "1px solid var(--color-separator)"
2772
2449
  }
2773
2450
  });
2774
- var editorGutter = EditorView13.theme({
2451
+ var editorGutter = EditorView11.theme({
2775
2452
  ".cm-gutters": {
2776
2453
  // NOTE: Non-transparent background required to cover content if scrolling horizontally.
2777
2454
  background: "var(--color-base-surface) !important",
2778
2455
  paddingRight: "1rem"
2779
2456
  }
2780
2457
  });
2781
- var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2458
+ var createFontTheme = ({ monospace } = {}) => EditorView11.theme({
2782
2459
  // Main content.
2783
2460
  ".cm-scroller": {
2784
2461
  fontFamily: monospace ? fontMono : fontBody
@@ -2791,9 +2468,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
2791
2468
  });
2792
2469
 
2793
2470
  // src/extensions/focus.ts
2794
- import { StateEffect as StateEffect6, StateField as StateField5 } from "@codemirror/state";
2795
- import { EditorView as EditorView14 } from "@codemirror/view";
2796
- var focusEffect = StateEffect6.define();
2471
+ import { StateEffect as StateEffect4, StateField as StateField5 } from "@codemirror/state";
2472
+ import { EditorView as EditorView12 } from "@codemirror/view";
2473
+ var focusEffect = StateEffect4.define();
2797
2474
  var focusField = StateField5.define({
2798
2475
  create: () => false,
2799
2476
  update: (value, tr) => {
@@ -2802,38 +2479,381 @@ var focusField = StateField5.define({
2802
2479
  return effect.value;
2803
2480
  }
2804
2481
  }
2805
- return value;
2482
+ return value;
2483
+ }
2484
+ });
2485
+ var focus = [
2486
+ focusField,
2487
+ EditorView12.domEventHandlers({
2488
+ focus: (_event, view) => {
2489
+ requestAnimationFrame(() => view.dispatch({
2490
+ effects: focusEffect.of(true)
2491
+ }));
2492
+ },
2493
+ blur: (_event, view) => {
2494
+ requestAnimationFrame(() => view.dispatch({
2495
+ effects: focusEffect.of(false)
2496
+ }));
2497
+ }
2498
+ })
2499
+ ];
2500
+
2501
+ // src/extensions/scrolling/auto-scroll.ts
2502
+ import { StateEffect as StateEffect6 } from "@codemirror/state";
2503
+ import { EditorView as EditorView14, ViewPlugin as ViewPlugin10 } from "@codemirror/view";
2504
+ import { addEventListener, combine, throttle as throttle2 } from "@dxos/async";
2505
+ import { Domino } from "@dxos/ui";
2506
+ import { getSize } from "@dxos/ui-theme";
2507
+
2508
+ // src/extensions/scrolling/crawler.ts
2509
+ import { StateEffect as StateEffect5 } from "@codemirror/state";
2510
+ import { EditorView as EditorView13, ViewPlugin as ViewPlugin9 } from "@codemirror/view";
2511
+ import { log as log7 } from "@dxos/log";
2512
+ var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/scrolling/crawler.ts";
2513
+ var crawlerLineEffect = StateEffect5.define();
2514
+ var crawlerActiveEffect = StateEffect5.define();
2515
+ var scrollToLine = (view, options) => {
2516
+ view.dispatch({
2517
+ effects: crawlerLineEffect.of(options)
2518
+ });
2519
+ };
2520
+ var crawler = ({ overScroll = 0 } = {}) => {
2521
+ const crawlerPlugin = ViewPlugin9.fromClass(class CrawlerPlugin {
2522
+ view;
2523
+ crawler;
2524
+ constructor(view) {
2525
+ this.view = view;
2526
+ this.crawler = createCrawler(this.view);
2527
+ }
2528
+ // No-op.
2529
+ destroy() {
2530
+ this.crawler.cancel();
2531
+ }
2532
+ cancel() {
2533
+ this.crawler.cancel();
2534
+ }
2535
+ crawl(start = false) {
2536
+ if (start) {
2537
+ this.crawler.scroll();
2538
+ } else {
2539
+ this.crawler.cancel();
2540
+ }
2541
+ }
2542
+ scroll({ line, offset = 0, position, behavior = "instant" }) {
2543
+ const { scrollTop, scrollHeight, clientHeight } = this.view.scrollDOM;
2544
+ const scrollerRect = this.view.scrollDOM.getBoundingClientRect();
2545
+ const doc = this.view.state.doc;
2546
+ let targetScrollTop = scrollHeight - clientHeight + offset;
2547
+ if (line >= 0 && line <= doc.lines - 1) {
2548
+ const lineStart = doc.line(line + 1).from;
2549
+ const coords = this.view.coordsAtPos(lineStart);
2550
+ if (coords) {
2551
+ const currentScrollTop = scrollTop;
2552
+ const maxScrollTop = scrollHeight - clientHeight;
2553
+ if (position === "end") {
2554
+ targetScrollTop = currentScrollTop + coords.bottom - scrollerRect.bottom + offset;
2555
+ } else {
2556
+ targetScrollTop = currentScrollTop + coords.top - scrollerRect.top + offset;
2557
+ }
2558
+ targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
2559
+ }
2560
+ }
2561
+ requestAnimationFrame(() => {
2562
+ this.view.scrollDOM.scrollTo({
2563
+ top: targetScrollTop
2564
+ });
2565
+ });
2566
+ }
2567
+ });
2568
+ return [
2569
+ crawlerPlugin,
2570
+ // Listen for effect.
2571
+ EditorView13.updateListener.of((update2) => {
2572
+ update2.transactions.forEach((transaction) => {
2573
+ try {
2574
+ const plugin = update2.view.plugin(crawlerPlugin);
2575
+ if (plugin) {
2576
+ for (const effect of transaction.effects) {
2577
+ if (effect.is(crawlerActiveEffect)) {
2578
+ plugin.crawl(effect.value);
2579
+ } else if (effect.is(crawlerLineEffect)) {
2580
+ plugin.scroll(effect.value);
2581
+ }
2582
+ }
2583
+ }
2584
+ } catch (err) {
2585
+ log7.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file10, L: 98, S: void 0 });
2586
+ }
2587
+ });
2588
+ }),
2589
+ // Styles.
2590
+ EditorView13.theme({
2591
+ ".cm-scroller": {
2592
+ overflowY: "scroll",
2593
+ // Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks
2594
+ // expanding their TogglePanel), the browser picks a stable element near the viewport
2595
+ // top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning
2596
+ // logic still has the final word when pinned (forces scrollTop to scrollHeight).
2597
+ overflowAnchor: "auto"
2598
+ },
2599
+ ".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
2600
+ display: "none"
2601
+ },
2602
+ ".cm-scroller::-webkit-scrollbar-thumb": {
2603
+ background: "transparent",
2604
+ transition: "background 0.15s"
2605
+ },
2606
+ "&:hover .cm-scroller::-webkit-scrollbar-thumb": {
2607
+ background: "var(--color-scrollbar-thumb)"
2608
+ },
2609
+ // Spacer below the last text line. Implemented as a real block pseudo-element
2610
+ // (rather than `padding-bottom` on `.cm-content`) so it materializes in the
2611
+ // scroller's `scrollHeight` regardless of how `padding` is reset by the base
2612
+ // theme or downstream classes — this is what gives auto-scroll its head-room
2613
+ // so the last line stays `overScroll` px above the viewport bottom.
2614
+ ".cm-content::after": {
2615
+ content: '""',
2616
+ display: "block",
2617
+ height: `${overScroll}px`
2618
+ },
2619
+ ".cm-scroll-button": {
2620
+ position: "absolute",
2621
+ bottom: "0.5rem",
2622
+ right: "1rem"
2623
+ }
2624
+ })
2625
+ ];
2626
+ };
2627
+ function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
2628
+ const el = view.scrollDOM;
2629
+ let currentTop = 0;
2630
+ let velocity = 0;
2631
+ let rafId = null;
2632
+ let lastTime = 0;
2633
+ function frame(now) {
2634
+ const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1e3);
2635
+ lastTime = now;
2636
+ const targetTop = el.scrollHeight - el.clientHeight;
2637
+ const delta = targetTop - currentTop;
2638
+ if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
2639
+ el.scrollTop = targetTop;
2640
+ currentTop = targetTop;
2641
+ velocity = 0;
2642
+ rafId = null;
2643
+ lastTime = 0;
2644
+ return;
2645
+ }
2646
+ const accel = omega * omega * delta - 2 * omega * velocity;
2647
+ velocity += accel * dt;
2648
+ currentTop += velocity * dt;
2649
+ el.scrollTop = currentTop;
2650
+ rafId = requestAnimationFrame(frame);
2806
2651
  }
2807
- });
2808
- var focus = [
2809
- focusField,
2810
- EditorView14.domEventHandlers({
2811
- focus: (_event, view) => {
2812
- requestAnimationFrame(() => view.dispatch({
2813
- effects: focusEffect.of(true)
2814
- }));
2652
+ return {
2653
+ scroll: () => {
2654
+ if (rafId === null) {
2655
+ currentTop = el.scrollTop;
2656
+ lastTime = 0;
2657
+ rafId = requestAnimationFrame(frame);
2658
+ }
2815
2659
  },
2816
- blur: (_event, view) => {
2817
- requestAnimationFrame(() => view.dispatch({
2818
- effects: focusEffect.of(false)
2819
- }));
2660
+ cancel: () => {
2661
+ if (rafId !== null) {
2662
+ cancelAnimationFrame(rafId);
2663
+ velocity = 0;
2664
+ lastTime = 0;
2665
+ rafId = null;
2666
+ }
2820
2667
  }
2821
- })
2822
- ];
2668
+ };
2669
+ }
2670
+
2671
+ // src/extensions/scrolling/auto-scroll.ts
2672
+ var autoScrollEffect = StateEffect6.define();
2673
+ var autoScroll = ({ scrollOnResize = true } = {}) => {
2674
+ let buttonContainer;
2675
+ let isPinned = true;
2676
+ let jumpPending = false;
2677
+ let enabled = true;
2678
+ let firstUpdate = true;
2679
+ const setPinned = (pinned) => {
2680
+ buttonContainer?.classList.toggle("opacity-0", pinned);
2681
+ isPinned = pinned;
2682
+ };
2683
+ return [
2684
+ // Update listener for scrolling when content changes.
2685
+ EditorView14.updateListener.of((update2) => {
2686
+ const { view, heightChanged, state, startState } = update2;
2687
+ for (const tr of update2.transactions) {
2688
+ for (const effect of tr.effects) {
2689
+ if (effect.is(autoScrollEffect)) {
2690
+ enabled = effect.value;
2691
+ if (enabled) {
2692
+ setPinned(true);
2693
+ view.dispatch({
2694
+ effects: crawlerActiveEffect.of(true)
2695
+ });
2696
+ } else {
2697
+ view.dispatch({
2698
+ effects: crawlerActiveEffect.of(false)
2699
+ });
2700
+ }
2701
+ }
2702
+ }
2703
+ }
2704
+ if (!enabled) {
2705
+ return;
2706
+ }
2707
+ if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
2708
+ firstUpdate = false;
2709
+ jumpPending = true;
2710
+ requestAnimationFrame(() => {
2711
+ view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
2712
+ jumpPending = false;
2713
+ });
2714
+ return;
2715
+ }
2716
+ firstUpdate = false;
2717
+ if (jumpPending) {
2718
+ return;
2719
+ }
2720
+ if (heightChanged) {
2721
+ if (isPinned) {
2722
+ const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
2723
+ const delta = scrollHeight - scrollTop - clientHeight;
2724
+ if (delta > 0) {
2725
+ setPinned(true);
2726
+ view.dispatch({
2727
+ effects: crawlerActiveEffect.of(true)
2728
+ });
2729
+ } else if (delta < -1) {
2730
+ setPinned(false);
2731
+ }
2732
+ } else {
2733
+ if (state.doc.length === 0) {
2734
+ setPinned(true);
2735
+ }
2736
+ }
2737
+ }
2738
+ }),
2739
+ // Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
2740
+ // window resize). Doc-driven height changes are handled by the updateListener above; this
2741
+ // observer covers the case where the viewport changes while the doc length is unchanged.
2742
+ scrollOnResize ? ViewPlugin10.fromClass(class {
2743
+ observer;
2744
+ firstObservation = true;
2745
+ destroyed = false;
2746
+ constructor(view) {
2747
+ const onResize = throttle2(() => {
2748
+ if (this.destroyed || !enabled) {
2749
+ return;
2750
+ }
2751
+ setPinned(true);
2752
+ requestAnimationFrame(() => {
2753
+ if (this.destroyed) {
2754
+ return;
2755
+ }
2756
+ view.scrollDOM.scrollTo({
2757
+ top: view.scrollDOM.scrollHeight,
2758
+ behavior: "instant"
2759
+ });
2760
+ view.dispatch({
2761
+ effects: crawlerActiveEffect.of(false)
2762
+ });
2763
+ });
2764
+ }, 50);
2765
+ this.observer = new ResizeObserver(() => {
2766
+ if (this.firstObservation) {
2767
+ this.firstObservation = false;
2768
+ return;
2769
+ }
2770
+ onResize();
2771
+ });
2772
+ this.observer.observe(view.scrollDOM);
2773
+ }
2774
+ destroy() {
2775
+ this.destroyed = true;
2776
+ this.observer.disconnect();
2777
+ }
2778
+ }) : [],
2779
+ // Detect user scroll and unpin (or re-pin if scrolled to the bottom).
2780
+ ViewPlugin10.fromClass(class {
2781
+ cleanup;
2782
+ constructor(view) {
2783
+ const onUserScroll = throttle2(() => {
2784
+ requestAnimationFrame(() => {
2785
+ const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
2786
+ const delta = scrollHeight - scrollTop - clientHeight;
2787
+ const pinned = Math.abs(delta) <= 1;
2788
+ setPinned(pinned);
2789
+ if (!pinned) {
2790
+ view.dispatch({
2791
+ effects: crawlerActiveEffect.of(false)
2792
+ });
2793
+ }
2794
+ });
2795
+ }, 500);
2796
+ this.cleanup = createUserScrollDetector(view.scrollDOM, () => {
2797
+ if (isPinned) {
2798
+ setPinned(false);
2799
+ view.dispatch({
2800
+ effects: crawlerActiveEffect.of(false)
2801
+ });
2802
+ }
2803
+ onUserScroll();
2804
+ });
2805
+ }
2806
+ destroy() {
2807
+ this.cleanup();
2808
+ }
2809
+ }),
2810
+ // Scroll button.
2811
+ ViewPlugin10.fromClass(class {
2812
+ constructor(view) {
2813
+ const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
2814
+ icon: "ph--arrow-down--regular"
2815
+ });
2816
+ const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
2817
+ "data-density": "fine"
2818
+ }).append(icon).on("click", () => {
2819
+ setPinned(true);
2820
+ view.dispatch({
2821
+ effects: crawlerLineEffect.of({
2822
+ line: -1,
2823
+ position: "end",
2824
+ behavior: "smooth"
2825
+ })
2826
+ });
2827
+ });
2828
+ buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
2829
+ view.scrollDOM.parentElement.appendChild(buttonContainer);
2830
+ }
2831
+ })
2832
+ ];
2833
+ };
2834
+ function createUserScrollDetector(element, onUserScroll) {
2835
+ return combine(addEventListener(element, "wheel", () => onUserScroll(), {
2836
+ passive: true
2837
+ }), addEventListener(element, "pointerdown", (event) => {
2838
+ if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {
2839
+ onUserScroll();
2840
+ }
2841
+ }));
2842
+ }
2823
2843
 
2824
- // src/extensions/scroll-past-end.ts
2844
+ // src/extensions/scrolling/scroll-past-end.ts
2825
2845
  import { EditorView as EditorView15, ViewPlugin as ViewPlugin11 } from "@codemirror/view";
2826
2846
  var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
2827
- height = 1e3;
2828
- attrs = {
2829
- style: "padding-bottom: 1000px"
2847
+ _height = 1e3;
2848
+ _attrs = {
2849
+ style: `padding-bottom: ${this._height}px`
2830
2850
  };
2831
2851
  update({ view }) {
2832
2852
  const lastLineBlock = view.lineBlockAt(view.state.doc.length);
2833
2853
  const height = view.dom.clientHeight - lastLineBlock.height - view.documentPadding.top - 0.5;
2834
- if (height >= 0 && height !== this.height) {
2835
- this.height = height;
2836
- this.attrs = {
2854
+ if (height >= 0 && height !== this._height) {
2855
+ this._height = height;
2856
+ this._attrs = {
2837
2857
  style: `padding-bottom: ${height}px`
2838
2858
  };
2839
2859
  }
@@ -2841,9 +2861,22 @@ var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
2841
2861
  });
2842
2862
  var scrollPastEnd = () => [
2843
2863
  scrollPastEndPlugin,
2844
- EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?.attrs ?? null)
2864
+ EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?._attrs ?? null)
2845
2865
  ];
2846
2866
 
2867
+ // src/extensions/scrolling/scroller.ts
2868
+ import { isTruthy as isTruthy2 } from "@dxos/util";
2869
+ var scroller = ({ overScroll, scrollOnResize, autoScroll: autoScroll2 = true } = {}) => {
2870
+ return [
2871
+ crawler({
2872
+ overScroll
2873
+ }),
2874
+ autoScroll2 && autoScroll({
2875
+ scrollOnResize
2876
+ })
2877
+ ].filter(isTruthy2);
2878
+ };
2879
+
2847
2880
  // src/extensions/factories.ts
2848
2881
  var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
2849
2882
  var tabbable = EditorView16.contentAttributes.of({
@@ -2951,8 +2984,8 @@ var createBasicExtensions = (propsProp) => {
2951
2984
  preventDefault: true,
2952
2985
  run: () => true
2953
2986
  }
2954
- ].filter(isTruthy2))
2955
- ].filter(isTruthy2);
2987
+ ].filter(isTruthy3))
2988
+ ].filter(isTruthy3);
2956
2989
  };
2957
2990
  var grow = {
2958
2991
  editor: {
@@ -2994,7 +3027,7 @@ var createThemeExtensions = ({ monospace, scrollbarThin, slots: slotsProp, synta
2994
3027
  }
2995
3028
  }
2996
3029
  })
2997
- ].filter(isTruthy2);
3030
+ ].filter(isTruthy3);
2998
3031
  };
2999
3032
  var createDataExtensions = ({ id, text, messenger, identity }) => {
3000
3033
  const extensions = [];
@@ -4318,7 +4351,7 @@ import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lan
4318
4351
  import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
4319
4352
  import { languages } from "@codemirror/language-data";
4320
4353
  import { keymap as keymap9 } from "@codemirror/view";
4321
- import { isTruthy as isTruthy3 } from "@dxos/util";
4354
+ import { isTruthy as isTruthy4 } from "@dxos/util";
4322
4355
 
4323
4356
  // src/extensions/markdown/highlight.ts
4324
4357
  import { markdownLanguage } from "@codemirror/lang-markdown";
@@ -4550,7 +4583,7 @@ var createMarkdownExtensions = (options = {}) => {
4550
4583
  ...defaultKeymap2,
4551
4584
  // TODO(burdon): Remove?
4552
4585
  ...completionKeymap
4553
- ].filter(isTruthy3))
4586
+ ].filter(isTruthy4))
4554
4587
  ];
4555
4588
  };
4556
4589
  var noFencedCodeFolding = {
@@ -6631,7 +6664,7 @@ var decorations = () => [
6631
6664
  marginBottom: "2px"
6632
6665
  },
6633
6666
  ".cm-list-item-focused": {
6634
- borderColor: "var(--color-neutral-focus-indicator)"
6667
+ borderColor: "var(--color-focus-ring-subtle)"
6635
6668
  },
6636
6669
  "&:focus-within .cm-list-item-selected": {
6637
6670
  borderColor: "var(--color-separator)"
@@ -7870,7 +7903,7 @@ var xmlFormatting = ({ skip } = {}) => {
7870
7903
  }),
7871
7904
  EditorView31.baseTheme({
7872
7905
  ".cm-xml-element": {
7873
- backgroundColor: "var(--color-active-surface)",
7906
+ backgroundColor: "var(--color-current-surface)",
7874
7907
  borderRadius: "0.25rem",
7875
7908
  padding: "0.25rem"
7876
7909
  },
@@ -8131,7 +8164,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
8131
8164
  anchor: line.from,
8132
8165
  head: line.from
8133
8166
  },
8134
- effects: scrollerLineEffect.of({
8167
+ effects: crawlerLineEffect.of({
8135
8168
  line: line.number - 1,
8136
8169
  offset: -16
8137
8170
  })
@@ -8164,7 +8197,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
8164
8197
  anchor: line.to,
8165
8198
  head: line.to
8166
8199
  },
8167
- effects: scrollerLineEffect.of({
8200
+ effects: crawlerLineEffect.of({
8168
8201
  line: line.number - 1,
8169
8202
  offset: -16
8170
8203
  })
@@ -8176,7 +8209,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
8176
8209
  anchor: line.to,
8177
8210
  head: line.to
8178
8211
  },
8179
- effects: scrollerLineEffect.of({
8212
+ effects: crawlerLineEffect.of({
8180
8213
  line: line.number - 1,
8181
8214
  position: "end"
8182
8215
  })
@@ -8495,6 +8528,9 @@ export {
8495
8528
  commentsState,
8496
8529
  compactSlots,
8497
8530
  convertTreeToJson,
8531
+ crawler,
8532
+ crawlerActiveEffect,
8533
+ crawlerLineEffect,
8498
8534
  createBasicExtensions,
8499
8535
  createComment,
8500
8536
  createCrawler,
@@ -8582,8 +8618,6 @@ export {
8582
8618
  scrollThreadIntoView,
8583
8619
  scrollToLine,
8584
8620
  scroller,
8585
- scrollerCrawlEffect,
8586
- scrollerLineEffect,
8587
8621
  selectionState,
8588
8622
  setBlockquote,
8589
8623
  setComments,