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