@dxos/ui-editor 0.8.4-main.dfabb4ec29 → 0.8.4-main.f466a3d56e
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.
- package/LICENSE +102 -5
- package/README.md +1 -1
- package/dist/lib/browser/index.mjs +482 -458
- package/dist/lib/browser/index.mjs.map +4 -4
- package/dist/lib/browser/meta.json +1 -1
- package/dist/lib/node-esm/index.mjs +482 -458
- package/dist/lib/node-esm/index.mjs.map +4 -4
- package/dist/lib/node-esm/meta.json +1 -1
- package/dist/types/src/extensions/index.d.ts +1 -3
- package/dist/types/src/extensions/index.d.ts.map +1 -1
- package/dist/types/src/extensions/scrolling/auto-scroll.d.ts.map +1 -0
- package/dist/types/src/extensions/{scroller.d.ts → scrolling/crawler.d.ts} +13 -6
- package/dist/types/src/extensions/scrolling/crawler.d.ts.map +1 -0
- package/dist/types/src/extensions/scrolling/index.d.ts +5 -0
- package/dist/types/src/extensions/scrolling/index.d.ts.map +1 -0
- package/dist/types/src/extensions/scrolling/scroll-past-end.d.ts.map +1 -0
- package/dist/types/src/extensions/scrolling/scroller.d.ts +16 -0
- package/dist/types/src/extensions/scrolling/scroller.d.ts.map +1 -0
- package/dist/types/src/styles/theme.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/package.json +29 -29
- package/src/extensions/factories.ts +1 -1
- package/src/extensions/index.ts +1 -3
- package/src/extensions/outliner/outliner.ts +1 -1
- package/src/extensions/{auto-scroll.ts → scrolling/auto-scroll.ts} +30 -20
- package/src/extensions/{scroller.ts → scrolling/crawler.ts} +19 -12
- package/src/extensions/scrolling/index.ts +8 -0
- package/src/extensions/{scroll-past-end.ts → scrolling/scroll-past-end.ts} +6 -6
- package/src/extensions/scrolling/scroller.ts +27 -0
- package/src/extensions/tags/xml-formatting.ts +1 -1
- package/src/extensions/tags/xml-tags.ts +4 -4
- package/src/styles/theme.ts +8 -7
- package/dist/types/src/extensions/auto-scroll.d.ts.map +0 -1
- package/dist/types/src/extensions/scroll-past-end.d.ts.map +0 -1
- package/dist/types/src/extensions/scroller.d.ts.map +0 -1
- /package/dist/types/src/extensions/{auto-scroll.d.ts → scrolling/auto-scroll.d.ts} +0 -0
- /package/dist/types/src/extensions/{scroll-past-end.d.ts → scrolling/scroll-past-end.d.ts} +0 -0
|
@@ -511,344 +511,10 @@ var typeahead = ({ onComplete } = {}) => {
|
|
|
511
511
|
];
|
|
512
512
|
};
|
|
513
513
|
|
|
514
|
-
// src/extensions/auto-scroll.ts
|
|
515
|
-
import { StateEffect as StateEffect2 } from "@codemirror/state";
|
|
516
|
-
import { EditorView as EditorView5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
517
|
-
import { addEventListener, combine, throttle } from "@dxos/async";
|
|
518
|
-
import { Domino } from "@dxos/ui";
|
|
519
|
-
import { getSize } from "@dxos/ui-theme";
|
|
520
|
-
|
|
521
|
-
// src/extensions/scroller.ts
|
|
522
|
-
import { StateEffect } from "@codemirror/state";
|
|
523
|
-
import { EditorView as EditorView4, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
524
|
-
import { log as log2 } from "@dxos/log";
|
|
525
|
-
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/scroller.ts";
|
|
526
|
-
var scrollerLineEffect = StateEffect.define();
|
|
527
|
-
var scrollerCrawlEffect = StateEffect.define();
|
|
528
|
-
var scrollToLine = (view, options) => {
|
|
529
|
-
view.dispatch({
|
|
530
|
-
effects: scrollerLineEffect.of(options)
|
|
531
|
-
});
|
|
532
|
-
};
|
|
533
|
-
var scroller = ({ overScroll = 0 } = {}) => {
|
|
534
|
-
const scrollPlugin = ViewPlugin5.fromClass(class ScrollerPlugin {
|
|
535
|
-
view;
|
|
536
|
-
crawler;
|
|
537
|
-
constructor(view) {
|
|
538
|
-
this.view = view;
|
|
539
|
-
this.crawler = createCrawler(this.view);
|
|
540
|
-
}
|
|
541
|
-
// No-op.
|
|
542
|
-
destroy() {
|
|
543
|
-
this.crawler.cancel();
|
|
544
|
-
}
|
|
545
|
-
cancel() {
|
|
546
|
-
this.crawler.cancel();
|
|
547
|
-
}
|
|
548
|
-
crawl(start = false) {
|
|
549
|
-
if (start) {
|
|
550
|
-
this.crawler.scroll();
|
|
551
|
-
} else {
|
|
552
|
-
this.crawler.cancel();
|
|
553
|
-
}
|
|
554
|
-
}
|
|
555
|
-
scroll({ line, offset = 0, position, behavior = "instant" }) {
|
|
556
|
-
const { scrollTop, scrollHeight, clientHeight } = this.view.scrollDOM;
|
|
557
|
-
const scrollerRect = this.view.scrollDOM.getBoundingClientRect();
|
|
558
|
-
const doc = this.view.state.doc;
|
|
559
|
-
let targetScrollTop = scrollHeight - clientHeight + offset;
|
|
560
|
-
if (line >= 0 && line <= doc.lines - 1) {
|
|
561
|
-
const lineStart = doc.line(line + 1).from;
|
|
562
|
-
const coords = this.view.coordsAtPos(lineStart);
|
|
563
|
-
if (coords) {
|
|
564
|
-
const currentScrollTop = scrollTop;
|
|
565
|
-
const maxScrollTop = scrollHeight - clientHeight;
|
|
566
|
-
if (position === "end") {
|
|
567
|
-
targetScrollTop = currentScrollTop + coords.bottom - scrollerRect.bottom + offset;
|
|
568
|
-
} else {
|
|
569
|
-
targetScrollTop = currentScrollTop + coords.top - scrollerRect.top + offset;
|
|
570
|
-
}
|
|
571
|
-
targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
|
|
572
|
-
}
|
|
573
|
-
}
|
|
574
|
-
requestAnimationFrame(() => {
|
|
575
|
-
this.view.scrollDOM.scrollTo({
|
|
576
|
-
top: targetScrollTop
|
|
577
|
-
});
|
|
578
|
-
});
|
|
579
|
-
}
|
|
580
|
-
});
|
|
581
|
-
return [
|
|
582
|
-
scrollPlugin,
|
|
583
|
-
// Listen for effect.
|
|
584
|
-
EditorView4.updateListener.of((update2) => {
|
|
585
|
-
update2.transactions.forEach((transaction) => {
|
|
586
|
-
try {
|
|
587
|
-
const plugin = update2.view.plugin(scrollPlugin);
|
|
588
|
-
if (plugin) {
|
|
589
|
-
for (const effect of transaction.effects) {
|
|
590
|
-
if (effect.is(scrollerCrawlEffect)) {
|
|
591
|
-
plugin.crawl(effect.value);
|
|
592
|
-
} else if (effect.is(scrollerLineEffect)) {
|
|
593
|
-
plugin.scroll(effect.value);
|
|
594
|
-
}
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
} catch (err) {
|
|
598
|
-
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 91, S: void 0 });
|
|
599
|
-
}
|
|
600
|
-
});
|
|
601
|
-
}),
|
|
602
|
-
// Styles.
|
|
603
|
-
EditorView4.theme({
|
|
604
|
-
".cm-scroller": {
|
|
605
|
-
overflowY: "scroll",
|
|
606
|
-
// Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks
|
|
607
|
-
// expanding their TogglePanel), the browser picks a stable element near the viewport
|
|
608
|
-
// top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning
|
|
609
|
-
// logic still has the final word when pinned (forces scrollTop to scrollHeight).
|
|
610
|
-
overflowAnchor: "auto"
|
|
611
|
-
},
|
|
612
|
-
".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
|
|
613
|
-
display: "none"
|
|
614
|
-
},
|
|
615
|
-
".cm-scroller::-webkit-scrollbar-thumb": {
|
|
616
|
-
background: "transparent",
|
|
617
|
-
transition: "background 0.15s"
|
|
618
|
-
},
|
|
619
|
-
"&:hover .cm-scroller::-webkit-scrollbar-thumb": {
|
|
620
|
-
background: "var(--color-scrollbar-thumb)"
|
|
621
|
-
},
|
|
622
|
-
// Spacer below the last text line. Implemented as a real block pseudo-element
|
|
623
|
-
// (rather than `padding-bottom` on `.cm-content`) so it materializes in the
|
|
624
|
-
// scroller's `scrollHeight` regardless of how `padding` is reset by the base
|
|
625
|
-
// theme or downstream classes — this is what gives auto-scroll its head-room
|
|
626
|
-
// so the last line stays `overScroll` px above the viewport bottom.
|
|
627
|
-
".cm-content::after": {
|
|
628
|
-
content: '""',
|
|
629
|
-
display: "block",
|
|
630
|
-
height: `${overScroll}px`
|
|
631
|
-
},
|
|
632
|
-
".cm-scroll-button": {
|
|
633
|
-
position: "absolute",
|
|
634
|
-
bottom: "0.5rem",
|
|
635
|
-
right: "1rem"
|
|
636
|
-
}
|
|
637
|
-
})
|
|
638
|
-
];
|
|
639
|
-
};
|
|
640
|
-
function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
|
|
641
|
-
const el = view.scrollDOM;
|
|
642
|
-
let currentTop = 0;
|
|
643
|
-
let velocity = 0;
|
|
644
|
-
let rafId = null;
|
|
645
|
-
let lastTime = 0;
|
|
646
|
-
function frame(now) {
|
|
647
|
-
const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1e3);
|
|
648
|
-
lastTime = now;
|
|
649
|
-
const targetTop = el.scrollHeight - el.clientHeight;
|
|
650
|
-
const delta = targetTop - currentTop;
|
|
651
|
-
if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
|
|
652
|
-
el.scrollTop = targetTop;
|
|
653
|
-
currentTop = targetTop;
|
|
654
|
-
velocity = 0;
|
|
655
|
-
rafId = null;
|
|
656
|
-
lastTime = 0;
|
|
657
|
-
return;
|
|
658
|
-
}
|
|
659
|
-
const accel = omega * omega * delta - 2 * omega * velocity;
|
|
660
|
-
velocity += accel * dt;
|
|
661
|
-
currentTop += velocity * dt;
|
|
662
|
-
el.scrollTop = currentTop;
|
|
663
|
-
rafId = requestAnimationFrame(frame);
|
|
664
|
-
}
|
|
665
|
-
return {
|
|
666
|
-
scroll: () => {
|
|
667
|
-
if (rafId === null) {
|
|
668
|
-
currentTop = el.scrollTop;
|
|
669
|
-
lastTime = 0;
|
|
670
|
-
rafId = requestAnimationFrame(frame);
|
|
671
|
-
}
|
|
672
|
-
},
|
|
673
|
-
cancel: () => {
|
|
674
|
-
if (rafId !== null) {
|
|
675
|
-
cancelAnimationFrame(rafId);
|
|
676
|
-
velocity = 0;
|
|
677
|
-
lastTime = 0;
|
|
678
|
-
rafId = null;
|
|
679
|
-
}
|
|
680
|
-
}
|
|
681
|
-
};
|
|
682
|
-
}
|
|
683
|
-
|
|
684
|
-
// src/extensions/auto-scroll.ts
|
|
685
|
-
var autoScrollEffect = StateEffect2.define();
|
|
686
|
-
var autoScroll = ({ scrollOnResize = true } = {}) => {
|
|
687
|
-
let buttonContainer;
|
|
688
|
-
let isPinned = true;
|
|
689
|
-
let jumpPending = false;
|
|
690
|
-
let enabled = true;
|
|
691
|
-
let firstUpdate = true;
|
|
692
|
-
const setPinned = (pinned) => {
|
|
693
|
-
buttonContainer?.classList.toggle("opacity-0", pinned);
|
|
694
|
-
isPinned = pinned;
|
|
695
|
-
};
|
|
696
|
-
return [
|
|
697
|
-
// Update listener for scrolling when content changes.
|
|
698
|
-
EditorView5.updateListener.of((update2) => {
|
|
699
|
-
const { view, heightChanged, state, startState } = update2;
|
|
700
|
-
for (const tr of update2.transactions) {
|
|
701
|
-
for (const effect of tr.effects) {
|
|
702
|
-
if (effect.is(autoScrollEffect)) {
|
|
703
|
-
enabled = effect.value;
|
|
704
|
-
if (enabled) {
|
|
705
|
-
setPinned(true);
|
|
706
|
-
view.dispatch({
|
|
707
|
-
effects: scrollerCrawlEffect.of(true)
|
|
708
|
-
});
|
|
709
|
-
} else {
|
|
710
|
-
view.dispatch({
|
|
711
|
-
effects: scrollerCrawlEffect.of(false)
|
|
712
|
-
});
|
|
713
|
-
}
|
|
714
|
-
}
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
if (!enabled) {
|
|
718
|
-
return;
|
|
719
|
-
}
|
|
720
|
-
if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
|
|
721
|
-
firstUpdate = false;
|
|
722
|
-
jumpPending = true;
|
|
723
|
-
requestAnimationFrame(() => {
|
|
724
|
-
view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
|
|
725
|
-
jumpPending = false;
|
|
726
|
-
});
|
|
727
|
-
return;
|
|
728
|
-
}
|
|
729
|
-
firstUpdate = false;
|
|
730
|
-
if (jumpPending) {
|
|
731
|
-
return;
|
|
732
|
-
}
|
|
733
|
-
if (heightChanged) {
|
|
734
|
-
if (isPinned) {
|
|
735
|
-
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
736
|
-
const delta = scrollHeight - scrollTop - clientHeight;
|
|
737
|
-
if (delta > 0) {
|
|
738
|
-
setPinned(true);
|
|
739
|
-
view.dispatch({
|
|
740
|
-
effects: scrollerCrawlEffect.of(true)
|
|
741
|
-
});
|
|
742
|
-
} else if (delta < -1) {
|
|
743
|
-
setPinned(false);
|
|
744
|
-
}
|
|
745
|
-
} else {
|
|
746
|
-
if (state.doc.length === 0) {
|
|
747
|
-
setPinned(true);
|
|
748
|
-
}
|
|
749
|
-
}
|
|
750
|
-
}
|
|
751
|
-
}),
|
|
752
|
-
// Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
|
|
753
|
-
// window resize). Doc-driven height changes are handled by the updateListener above; this
|
|
754
|
-
// observer covers the case where the viewport changes while the doc length is unchanged.
|
|
755
|
-
scrollOnResize ? ViewPlugin6.fromClass(class {
|
|
756
|
-
observer;
|
|
757
|
-
firstObservation = true;
|
|
758
|
-
destroyed = false;
|
|
759
|
-
constructor(view) {
|
|
760
|
-
const onResize = throttle(() => {
|
|
761
|
-
if (this.destroyed || !enabled) {
|
|
762
|
-
return;
|
|
763
|
-
}
|
|
764
|
-
setPinned(true);
|
|
765
|
-
requestAnimationFrame(() => {
|
|
766
|
-
if (this.destroyed) {
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
view.scrollDOM.scrollTo({
|
|
770
|
-
top: view.scrollDOM.scrollHeight,
|
|
771
|
-
behavior: "instant"
|
|
772
|
-
});
|
|
773
|
-
view.dispatch({
|
|
774
|
-
effects: scrollerCrawlEffect.of(false)
|
|
775
|
-
});
|
|
776
|
-
});
|
|
777
|
-
}, 50);
|
|
778
|
-
this.observer = new ResizeObserver(() => {
|
|
779
|
-
if (this.firstObservation) {
|
|
780
|
-
this.firstObservation = false;
|
|
781
|
-
return;
|
|
782
|
-
}
|
|
783
|
-
onResize();
|
|
784
|
-
});
|
|
785
|
-
this.observer.observe(view.scrollDOM);
|
|
786
|
-
}
|
|
787
|
-
destroy() {
|
|
788
|
-
this.destroyed = true;
|
|
789
|
-
this.observer.disconnect();
|
|
790
|
-
}
|
|
791
|
-
}) : [],
|
|
792
|
-
// Detect user scroll and unpin (or re-pin if scrolled to the bottom).
|
|
793
|
-
ViewPlugin6.fromClass(class {
|
|
794
|
-
cleanup;
|
|
795
|
-
constructor(view) {
|
|
796
|
-
this.cleanup = createUserScrollDetector(view.scrollDOM, throttle(() => {
|
|
797
|
-
requestAnimationFrame(() => {
|
|
798
|
-
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
799
|
-
const delta = scrollHeight - scrollTop - clientHeight;
|
|
800
|
-
const pinned = delta === 0;
|
|
801
|
-
setPinned(pinned);
|
|
802
|
-
if (!pinned) {
|
|
803
|
-
view.dispatch({
|
|
804
|
-
effects: scrollerCrawlEffect.of(false)
|
|
805
|
-
});
|
|
806
|
-
}
|
|
807
|
-
});
|
|
808
|
-
}, 500));
|
|
809
|
-
}
|
|
810
|
-
destroy() {
|
|
811
|
-
this.cleanup();
|
|
812
|
-
}
|
|
813
|
-
}),
|
|
814
|
-
// Scroll button.
|
|
815
|
-
ViewPlugin6.fromClass(class {
|
|
816
|
-
constructor(view) {
|
|
817
|
-
const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
|
|
818
|
-
icon: "ph--arrow-down--regular"
|
|
819
|
-
});
|
|
820
|
-
const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
|
|
821
|
-
"data-density": "fine"
|
|
822
|
-
}).append(icon).on("click", () => {
|
|
823
|
-
setPinned(true);
|
|
824
|
-
view.dispatch({
|
|
825
|
-
effects: scrollerLineEffect.of({
|
|
826
|
-
line: -1,
|
|
827
|
-
position: "end",
|
|
828
|
-
behavior: "smooth"
|
|
829
|
-
})
|
|
830
|
-
});
|
|
831
|
-
});
|
|
832
|
-
buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
|
|
833
|
-
view.scrollDOM.parentElement.appendChild(buttonContainer);
|
|
834
|
-
}
|
|
835
|
-
})
|
|
836
|
-
];
|
|
837
|
-
};
|
|
838
|
-
function createUserScrollDetector(element, onUserScroll) {
|
|
839
|
-
return combine(addEventListener(element, "wheel", () => onUserScroll(), {
|
|
840
|
-
passive: true
|
|
841
|
-
}), addEventListener(element, "pointerdown", (event) => {
|
|
842
|
-
if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {
|
|
843
|
-
onUserScroll();
|
|
844
|
-
}
|
|
845
|
-
}));
|
|
846
|
-
}
|
|
847
|
-
|
|
848
514
|
// src/extensions/automerge/automerge.ts
|
|
849
515
|
import { next as A3 } from "@automerge/automerge";
|
|
850
516
|
import { StateField, Transaction as Transaction2 } from "@codemirror/state";
|
|
851
|
-
import { EditorView as
|
|
517
|
+
import { EditorView as EditorView4, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
852
518
|
import { DocAccessor } from "@dxos/echo-db";
|
|
853
519
|
|
|
854
520
|
// src/extensions/state.ts
|
|
@@ -857,14 +523,14 @@ var initialSync = Transaction.userEvent.of("initial.sync");
|
|
|
857
523
|
|
|
858
524
|
// src/extensions/automerge/cursor.ts
|
|
859
525
|
import { fromCursor, toCursor } from "@dxos/echo-db";
|
|
860
|
-
import { log as
|
|
861
|
-
var
|
|
526
|
+
import { log as log2 } from "@dxos/log";
|
|
527
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/cursor.ts";
|
|
862
528
|
var cursorConverter = (accessor) => ({
|
|
863
529
|
toCursor: (pos, assoc) => {
|
|
864
530
|
try {
|
|
865
531
|
return toCursor(accessor, pos, assoc);
|
|
866
532
|
} catch (err) {
|
|
867
|
-
|
|
533
|
+
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 11, S: void 0 });
|
|
868
534
|
return "";
|
|
869
535
|
}
|
|
870
536
|
},
|
|
@@ -872,17 +538,17 @@ var cursorConverter = (accessor) => ({
|
|
|
872
538
|
try {
|
|
873
539
|
return fromCursor(accessor, cursor);
|
|
874
540
|
} catch (err) {
|
|
875
|
-
|
|
541
|
+
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 19, S: void 0 });
|
|
876
542
|
return 0;
|
|
877
543
|
}
|
|
878
544
|
}
|
|
879
545
|
});
|
|
880
546
|
|
|
881
547
|
// src/extensions/automerge/defs.ts
|
|
882
|
-
import { Annotation, StateEffect
|
|
548
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
883
549
|
var getPath = (state, field) => state.field(field).path;
|
|
884
550
|
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
885
|
-
var updateHeadsEffect =
|
|
551
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
886
552
|
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
887
553
|
newHeads
|
|
888
554
|
});
|
|
@@ -893,7 +559,7 @@ var isReconcile = (tr) => {
|
|
|
893
559
|
|
|
894
560
|
// src/extensions/automerge/sync.ts
|
|
895
561
|
import { next as A2 } from "@automerge/automerge";
|
|
896
|
-
import { log as
|
|
562
|
+
import { log as log3 } from "@dxos/log";
|
|
897
563
|
|
|
898
564
|
// src/extensions/automerge/update-automerge.ts
|
|
899
565
|
import { next as A } from "@automerge/automerge";
|
|
@@ -1034,7 +700,7 @@ var charPath = (textPath, candidatePath) => {
|
|
|
1034
700
|
};
|
|
1035
701
|
|
|
1036
702
|
// src/extensions/automerge/sync.ts
|
|
1037
|
-
var
|
|
703
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/sync.ts";
|
|
1038
704
|
var Syncer = class {
|
|
1039
705
|
_handle;
|
|
1040
706
|
_state;
|
|
@@ -1057,7 +723,7 @@ var Syncer = class {
|
|
|
1057
723
|
this._pending = false;
|
|
1058
724
|
}
|
|
1059
725
|
onEditorChange(view) {
|
|
1060
|
-
|
|
726
|
+
log3("onEditorChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 35, S: this });
|
|
1061
727
|
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
1062
728
|
const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
1063
729
|
if (newHeads) {
|
|
@@ -1068,7 +734,7 @@ var Syncer = class {
|
|
|
1068
734
|
}
|
|
1069
735
|
}
|
|
1070
736
|
onAutomergeChange(view) {
|
|
1071
|
-
|
|
737
|
+
log3("onAutomergeChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 47, S: this });
|
|
1072
738
|
const oldHeads = getLastHeads(view.state, this._state);
|
|
1073
739
|
const newHeads = A2.getHeads(this._handle.doc());
|
|
1074
740
|
const diff = A2.equals(oldHeads, newHeads) ? [] : A2.diff(this._handle.doc(), oldHeads, newHeads);
|
|
@@ -1121,7 +787,7 @@ var automerge = (accessor) => {
|
|
|
1121
787
|
// Track heads.
|
|
1122
788
|
syncState,
|
|
1123
789
|
// Reconcile external updates.
|
|
1124
|
-
|
|
790
|
+
ViewPlugin5.fromClass(class {
|
|
1125
791
|
_view;
|
|
1126
792
|
constructor(_view) {
|
|
1127
793
|
this._view = _view;
|
|
@@ -1152,7 +818,7 @@ var automerge = (accessor) => {
|
|
|
1152
818
|
};
|
|
1153
819
|
}),
|
|
1154
820
|
// Reconcile local updates.
|
|
1155
|
-
|
|
821
|
+
EditorView4.updateListener.of(({ view, changes, transactions }) => {
|
|
1156
822
|
if (!changes.empty) {
|
|
1157
823
|
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction2.userEvent) === initialSync.value);
|
|
1158
824
|
if (!isInitialSync) {
|
|
@@ -1165,10 +831,10 @@ var automerge = (accessor) => {
|
|
|
1165
831
|
|
|
1166
832
|
// src/extensions/awareness/awareness.ts
|
|
1167
833
|
import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
|
|
1168
|
-
import { Decoration as Decoration5, EditorView as
|
|
834
|
+
import { Decoration as Decoration5, EditorView as EditorView5, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1169
835
|
import { Event } from "@dxos/async";
|
|
1170
836
|
import { Context } from "@dxos/context";
|
|
1171
|
-
var
|
|
837
|
+
var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness.ts";
|
|
1172
838
|
var dummyProvider = {
|
|
1173
839
|
remoteStateChange: new Event(),
|
|
1174
840
|
open: () => {
|
|
@@ -1184,14 +850,14 @@ var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
|
1184
850
|
var awareness = (provider = dummyProvider) => {
|
|
1185
851
|
return [
|
|
1186
852
|
awarenessProvider.of(provider),
|
|
1187
|
-
|
|
853
|
+
ViewPlugin6.fromClass(RemoteSelectionsDecorator, {
|
|
1188
854
|
decorations: (value) => value.decorations
|
|
1189
855
|
}),
|
|
1190
856
|
styles
|
|
1191
857
|
];
|
|
1192
858
|
};
|
|
1193
859
|
var RemoteSelectionsDecorator = class {
|
|
1194
|
-
_ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F:
|
|
860
|
+
_ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 33 });
|
|
1195
861
|
_cursorConverter;
|
|
1196
862
|
_provider;
|
|
1197
863
|
_lastAnchor;
|
|
@@ -1340,7 +1006,7 @@ var RemoteCaretWidget = class extends WidgetType3 {
|
|
|
1340
1006
|
return true;
|
|
1341
1007
|
}
|
|
1342
1008
|
};
|
|
1343
|
-
var styles =
|
|
1009
|
+
var styles = EditorView5.theme({
|
|
1344
1010
|
".cm-collab-selection": {},
|
|
1345
1011
|
".cm-collab-selectionLine": {
|
|
1346
1012
|
padding: 0,
|
|
@@ -1402,8 +1068,8 @@ var styles = EditorView7.theme({
|
|
|
1402
1068
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
1403
1069
|
import { Context as Context2 } from "@dxos/context";
|
|
1404
1070
|
import { invariant } from "@dxos/invariant";
|
|
1405
|
-
import { log as
|
|
1406
|
-
var
|
|
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";
|
|
1407
1073
|
var DEBOUNCE_INTERVAL = 100;
|
|
1408
1074
|
var SpaceAwarenessProvider = class {
|
|
1409
1075
|
_remoteStates = /* @__PURE__ */ new Map();
|
|
@@ -1422,7 +1088,7 @@ var SpaceAwarenessProvider = class {
|
|
|
1422
1088
|
this._info = info;
|
|
1423
1089
|
}
|
|
1424
1090
|
open() {
|
|
1425
|
-
this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F:
|
|
1091
|
+
this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 28 });
|
|
1426
1092
|
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
1427
1093
|
if (this._localState) {
|
|
1428
1094
|
await this._messenger.postMessage(this._channel, {
|
|
@@ -1447,9 +1113,9 @@ var SpaceAwarenessProvider = class {
|
|
|
1447
1113
|
void this._messenger.postMessage(this._channel, {
|
|
1448
1114
|
kind: "query"
|
|
1449
1115
|
}).catch((err) => {
|
|
1450
|
-
|
|
1116
|
+
log4.debug("failed to query awareness", {
|
|
1451
1117
|
err
|
|
1452
|
-
}, { "~LogMeta": "~LogMeta", F:
|
|
1118
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 57, S: this });
|
|
1453
1119
|
});
|
|
1454
1120
|
}
|
|
1455
1121
|
close() {
|
|
@@ -1461,7 +1127,7 @@ var SpaceAwarenessProvider = class {
|
|
|
1461
1127
|
return Array.from(this._remoteStates.values());
|
|
1462
1128
|
}
|
|
1463
1129
|
update(position) {
|
|
1464
|
-
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1130
|
+
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 71, S: this, A: ["this._postTask", ""] });
|
|
1465
1131
|
this._localState = {
|
|
1466
1132
|
peerId: this._peerId,
|
|
1467
1133
|
position,
|
|
@@ -1470,22 +1136,22 @@ var SpaceAwarenessProvider = class {
|
|
|
1470
1136
|
this._postTask.schedule();
|
|
1471
1137
|
}
|
|
1472
1138
|
_handleQueryMessage() {
|
|
1473
|
-
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1139
|
+
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 80, S: this, A: ["this._postTask", ""] });
|
|
1474
1140
|
this._postTask.schedule();
|
|
1475
1141
|
}
|
|
1476
1142
|
_handlePostMessage(message) {
|
|
1477
|
-
invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F:
|
|
1143
|
+
invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 84, S: this, A: ["message.kind === 'post'", ""] });
|
|
1478
1144
|
this._remoteStates.set(message.state.peerId, message.state);
|
|
1479
1145
|
this.remoteStateChange.emit();
|
|
1480
1146
|
}
|
|
1481
1147
|
};
|
|
1482
1148
|
|
|
1483
1149
|
// src/extensions/blast.ts
|
|
1484
|
-
import { EditorView as
|
|
1150
|
+
import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
|
|
1485
1151
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
1486
|
-
import { throttle
|
|
1152
|
+
import { throttle } from "@dxos/async";
|
|
1487
1153
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1488
|
-
var
|
|
1154
|
+
var __dxlog_file6 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/blast.ts";
|
|
1489
1155
|
var defaultOptions = {
|
|
1490
1156
|
effect: 2,
|
|
1491
1157
|
maxParticles: 200,
|
|
@@ -1530,7 +1196,7 @@ var blast = (options = defaultOptions) => {
|
|
|
1530
1196
|
};
|
|
1531
1197
|
return [
|
|
1532
1198
|
// Cursor moved.
|
|
1533
|
-
|
|
1199
|
+
EditorView6.updateListener.of((update2) => {
|
|
1534
1200
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
1535
1201
|
if (blaster) {
|
|
1536
1202
|
blaster.destroy();
|
|
@@ -1603,7 +1269,7 @@ var Blaster = class {
|
|
|
1603
1269
|
return this._node;
|
|
1604
1270
|
}
|
|
1605
1271
|
initialize() {
|
|
1606
|
-
invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1272
|
+
invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
|
|
1607
1273
|
this._canvas = document.createElement("canvas");
|
|
1608
1274
|
this._canvas.id = "code-blast-canvas";
|
|
1609
1275
|
this._canvas.style.position = "absolute";
|
|
@@ -1632,7 +1298,7 @@ var Blaster = class {
|
|
|
1632
1298
|
}
|
|
1633
1299
|
}
|
|
1634
1300
|
start() {
|
|
1635
|
-
invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1301
|
+
invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
|
|
1636
1302
|
this._running = true;
|
|
1637
1303
|
this.loop();
|
|
1638
1304
|
}
|
|
@@ -1659,11 +1325,11 @@ var Blaster = class {
|
|
|
1659
1325
|
this.drawParticles();
|
|
1660
1326
|
requestAnimationFrame(this.loop.bind(this));
|
|
1661
1327
|
}
|
|
1662
|
-
shake =
|
|
1328
|
+
shake = throttle(({ time }) => {
|
|
1663
1329
|
this._shakeTime = this._shakeTimeMax || time;
|
|
1664
1330
|
this._shakeTimeMax = time;
|
|
1665
1331
|
}, 100);
|
|
1666
|
-
spawn =
|
|
1332
|
+
spawn = throttle(({ element, point }) => {
|
|
1667
1333
|
const color = getRGBComponents(element, this._options.color);
|
|
1668
1334
|
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
1669
1335
|
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
@@ -1772,9 +1438,9 @@ var random = (min, max) => {
|
|
|
1772
1438
|
|
|
1773
1439
|
// src/extensions/blocks.ts
|
|
1774
1440
|
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1775
|
-
import { Decoration as Decoration6, EditorView as
|
|
1441
|
+
import { Decoration as Decoration6, EditorView as EditorView7, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
|
|
1776
1442
|
import { mx as mx2 } from "@dxos/ui-theme";
|
|
1777
|
-
var paragraphBlockPlugin =
|
|
1443
|
+
var paragraphBlockPlugin = ViewPlugin7.fromClass(class {
|
|
1778
1444
|
decorations;
|
|
1779
1445
|
constructor(view) {
|
|
1780
1446
|
this.decorations = this.build(view);
|
|
@@ -1833,7 +1499,7 @@ var paragraphBlockPlugin = ViewPlugin9.fromClass(class {
|
|
|
1833
1499
|
});
|
|
1834
1500
|
var blocks = () => [
|
|
1835
1501
|
paragraphBlockPlugin,
|
|
1836
|
-
|
|
1502
|
+
EditorView7.baseTheme({
|
|
1837
1503
|
".cm-line.block-line": {
|
|
1838
1504
|
paddingLeft: "0.75rem",
|
|
1839
1505
|
paddingRight: "0.75rem",
|
|
@@ -1867,13 +1533,13 @@ var blocks = () => [
|
|
|
1867
1533
|
];
|
|
1868
1534
|
|
|
1869
1535
|
// src/extensions/bookmarks.ts
|
|
1870
|
-
import { Prec as Prec3, StateEffect as
|
|
1536
|
+
import { Prec as Prec3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1871
1537
|
import { keymap as keymap4 } from "@codemirror/view";
|
|
1872
|
-
import { log as
|
|
1873
|
-
var
|
|
1874
|
-
var addBookmark =
|
|
1875
|
-
var removeBookmark =
|
|
1876
|
-
var clearBookmarks =
|
|
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();
|
|
1877
1543
|
var bookmarks = () => {
|
|
1878
1544
|
return [
|
|
1879
1545
|
bookmarksField,
|
|
@@ -1882,7 +1548,7 @@ var bookmarks = () => {
|
|
|
1882
1548
|
key: "Mod-ArrowUp",
|
|
1883
1549
|
run: (view) => {
|
|
1884
1550
|
const bookmarks2 = view.state.field(bookmarksField);
|
|
1885
|
-
|
|
1551
|
+
log5("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 18, S: void 0 });
|
|
1886
1552
|
return true;
|
|
1887
1553
|
}
|
|
1888
1554
|
},
|
|
@@ -1890,7 +1556,7 @@ var bookmarks = () => {
|
|
|
1890
1556
|
key: "Mod-ArrowDown",
|
|
1891
1557
|
run: (view) => {
|
|
1892
1558
|
const bookmarks2 = view.state.field(bookmarksField);
|
|
1893
|
-
|
|
1559
|
+
log5("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 26, S: void 0 });
|
|
1894
1560
|
return true;
|
|
1895
1561
|
}
|
|
1896
1562
|
}
|
|
@@ -1927,27 +1593,27 @@ var bookmarksField = StateField2.define({
|
|
|
1927
1593
|
|
|
1928
1594
|
// src/extensions/comments.ts
|
|
1929
1595
|
import { invertedEffects } from "@codemirror/commands";
|
|
1930
|
-
import { StateEffect as
|
|
1931
|
-
import { Decoration as Decoration7, EditorView as
|
|
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";
|
|
1932
1598
|
import sortBy from "lodash.sortby";
|
|
1933
1599
|
import { debounce as debounce2 } from "@dxos/async";
|
|
1934
|
-
import { log as
|
|
1600
|
+
import { log as log6 } from "@dxos/log";
|
|
1935
1601
|
import { isNonNullable } from "@dxos/util";
|
|
1936
1602
|
|
|
1937
1603
|
// src/extensions/selection.ts
|
|
1938
1604
|
import { Transaction as Transaction3 } from "@codemirror/state";
|
|
1939
|
-
import { EditorView as
|
|
1605
|
+
import { EditorView as EditorView8, keymap as keymap5 } from "@codemirror/view";
|
|
1940
1606
|
import { debounce } from "@dxos/async";
|
|
1941
1607
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1942
1608
|
import { isTruthy } from "@dxos/util";
|
|
1943
|
-
var
|
|
1609
|
+
var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/selection.ts";
|
|
1944
1610
|
var documentId = singleValueFacet();
|
|
1945
1611
|
var stateRestoreAnnotation = "org.dxos.cm.state-restore";
|
|
1946
1612
|
var createEditorStateTransaction = ({ scrollTo, selection }) => {
|
|
1947
1613
|
return {
|
|
1948
1614
|
selection,
|
|
1949
1615
|
scrollIntoView: !scrollTo,
|
|
1950
|
-
effects: scrollTo ?
|
|
1616
|
+
effects: scrollTo ? EditorView8.scrollIntoView(scrollTo, {
|
|
1951
1617
|
yMargin: 96
|
|
1952
1618
|
}) : void 0,
|
|
1953
1619
|
annotations: Transaction3.userEvent.of(stateRestoreAnnotation)
|
|
@@ -1955,12 +1621,12 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
|
|
|
1955
1621
|
};
|
|
1956
1622
|
var createEditorStateStore = (keyPrefix) => ({
|
|
1957
1623
|
getState: (id) => {
|
|
1958
|
-
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1624
|
+
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0, A: ["id", ""] });
|
|
1959
1625
|
const state = localStorage.getItem(`${keyPrefix}/${id}`);
|
|
1960
1626
|
return state ? JSON.parse(state) : void 0;
|
|
1961
1627
|
},
|
|
1962
1628
|
setState: (id, state) => {
|
|
1963
|
-
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1629
|
+
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 31, S: void 0, A: ["id", ""] });
|
|
1964
1630
|
localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
|
|
1965
1631
|
}
|
|
1966
1632
|
});
|
|
@@ -1973,7 +1639,7 @@ var selectionState = ({ getState, setState } = {}) => {
|
|
|
1973
1639
|
// setStateDebounced(id, {});
|
|
1974
1640
|
// },
|
|
1975
1641
|
// }),
|
|
1976
|
-
|
|
1642
|
+
EditorView8.updateListener.of(({ view, transactions }) => {
|
|
1977
1643
|
const id = view.state.facet(documentId);
|
|
1978
1644
|
if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
|
|
1979
1645
|
return;
|
|
@@ -2012,10 +1678,10 @@ var selectionState = ({ getState, setState } = {}) => {
|
|
|
2012
1678
|
};
|
|
2013
1679
|
|
|
2014
1680
|
// src/extensions/comments.ts
|
|
2015
|
-
var
|
|
2016
|
-
var setComments =
|
|
2017
|
-
var setSelection =
|
|
2018
|
-
var setCommentState =
|
|
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();
|
|
2019
1685
|
var commentsState = StateField3.define({
|
|
2020
1686
|
create: (state) => ({
|
|
2021
1687
|
id: state.facet(documentId),
|
|
@@ -2054,7 +1720,7 @@ var commentsState = StateField3.define({
|
|
|
2054
1720
|
return value;
|
|
2055
1721
|
}
|
|
2056
1722
|
});
|
|
2057
|
-
var styles2 =
|
|
1723
|
+
var styles2 = EditorView9.theme({
|
|
2058
1724
|
".cm-comment, .cm-comment-current": {
|
|
2059
1725
|
padding: "3px 0",
|
|
2060
1726
|
color: "var(--color-cm-comment-text)",
|
|
@@ -2075,14 +1741,14 @@ var createCommentMark = (id, isCurrent) => Decoration7.mark({
|
|
|
2075
1741
|
"data-comment-id": id
|
|
2076
1742
|
}
|
|
2077
1743
|
});
|
|
2078
|
-
var commentsDecorations =
|
|
1744
|
+
var commentsDecorations = EditorView9.decorations.compute([
|
|
2079
1745
|
commentsState
|
|
2080
1746
|
], (state) => {
|
|
2081
1747
|
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
2082
1748
|
const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
2083
1749
|
const range = comment.range;
|
|
2084
1750
|
if (!range) {
|
|
2085
|
-
|
|
1751
|
+
log6.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 93, S: void 0 });
|
|
2086
1752
|
return void 0;
|
|
2087
1753
|
} else if (range.from === range.to) {
|
|
2088
1754
|
return void 0;
|
|
@@ -2092,8 +1758,8 @@ var commentsDecorations = EditorView11.decorations.compute([
|
|
|
2092
1758
|
}).filter(isNonNullable);
|
|
2093
1759
|
return Decoration7.set(decorations2);
|
|
2094
1760
|
});
|
|
2095
|
-
var commentClickedEffect =
|
|
2096
|
-
var handleCommentClick =
|
|
1761
|
+
var commentClickedEffect = StateEffect3.define();
|
|
1762
|
+
var handleCommentClick = EditorView9.domEventHandlers({
|
|
2097
1763
|
click: (event, view) => {
|
|
2098
1764
|
let target = event.target;
|
|
2099
1765
|
const editorRoot = view.dom;
|
|
@@ -2132,7 +1798,7 @@ var trackPastedComments = (onUpdate) => {
|
|
|
2132
1798
|
}
|
|
2133
1799
|
};
|
|
2134
1800
|
return [
|
|
2135
|
-
|
|
1801
|
+
EditorView9.domEventHandlers({
|
|
2136
1802
|
cut: handleTrack,
|
|
2137
1803
|
copy: handleTrack
|
|
2138
1804
|
}),
|
|
@@ -2154,7 +1820,7 @@ var trackPastedComments = (onUpdate) => {
|
|
|
2154
1820
|
return effects;
|
|
2155
1821
|
}),
|
|
2156
1822
|
// Handle paste or the undo of comment deletion.
|
|
2157
|
-
|
|
1823
|
+
EditorView9.updateListener.of((update2) => {
|
|
2158
1824
|
const restore = [];
|
|
2159
1825
|
for (let i = 0; i < update2.transactions.length; i++) {
|
|
2160
1826
|
const tr = update2.transactions[i];
|
|
@@ -2210,7 +1876,7 @@ var mapTrackedComment = (comment, changes) => ({
|
|
|
2210
1876
|
from: changes.mapPos(comment.from, 1),
|
|
2211
1877
|
to: changes.mapPos(comment.to, 1)
|
|
2212
1878
|
});
|
|
2213
|
-
var restoreCommentEffect =
|
|
1879
|
+
var restoreCommentEffect = StateEffect3.define({
|
|
2214
1880
|
map: mapTrackedComment
|
|
2215
1881
|
});
|
|
2216
1882
|
var createComment = (view) => {
|
|
@@ -2296,7 +1962,7 @@ var comments = (options = {}) => {
|
|
|
2296
1962
|
//
|
|
2297
1963
|
// Track deleted ranges and update ranges for decorations.
|
|
2298
1964
|
//
|
|
2299
|
-
|
|
1965
|
+
EditorView9.updateListener.of(({ view, state, changes }) => {
|
|
2300
1966
|
let mod = false;
|
|
2301
1967
|
const { comments: comments2, ...value } = state.field(commentsState);
|
|
2302
1968
|
changes.iterChanges((from, to, from2, to2) => {
|
|
@@ -2328,7 +1994,7 @@ var comments = (options = {}) => {
|
|
|
2328
1994
|
//
|
|
2329
1995
|
// Track selection/proximity.
|
|
2330
1996
|
//
|
|
2331
|
-
|
|
1997
|
+
EditorView9.updateListener.of(({ view, state }) => {
|
|
2332
1998
|
let min = Infinity;
|
|
2333
1999
|
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
2334
2000
|
const { head } = state.selection.main;
|
|
@@ -2382,7 +2048,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
|
|
|
2382
2048
|
anchor: range.from
|
|
2383
2049
|
} : void 0,
|
|
2384
2050
|
effects: [
|
|
2385
|
-
needsScroll ?
|
|
2051
|
+
needsScroll ? EditorView9.scrollIntoView(range.from, center ? {
|
|
2386
2052
|
y: "center"
|
|
2387
2053
|
} : void 0) : [],
|
|
2388
2054
|
needsSelectionUpdate ? setSelection.of({
|
|
@@ -2413,7 +2079,7 @@ var ExternalCommentSync = class {
|
|
|
2413
2079
|
this.unsubscribe();
|
|
2414
2080
|
};
|
|
2415
2081
|
};
|
|
2416
|
-
var createExternalCommentSync = (id, subscribe, getComments) =>
|
|
2082
|
+
var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin8.fromClass(class {
|
|
2417
2083
|
constructor(view) {
|
|
2418
2084
|
return new ExternalCommentSync(view, id, subscribe, getComments);
|
|
2419
2085
|
}
|
|
@@ -2433,12 +2099,12 @@ var debugNodeLogger = (log12 = console.log) => {
|
|
|
2433
2099
|
};
|
|
2434
2100
|
|
|
2435
2101
|
// src/extensions/dnd.ts
|
|
2436
|
-
import { EditorView as
|
|
2102
|
+
import { EditorView as EditorView10, dropCursor } from "@codemirror/view";
|
|
2437
2103
|
var dropFile = (options = {}) => {
|
|
2438
2104
|
return [
|
|
2439
2105
|
styles3,
|
|
2440
2106
|
dropCursor(),
|
|
2441
|
-
|
|
2107
|
+
EditorView10.domEventHandlers({
|
|
2442
2108
|
drop: (event, view) => {
|
|
2443
2109
|
event.preventDefault();
|
|
2444
2110
|
const files = event.dataTransfer?.files;
|
|
@@ -2457,7 +2123,7 @@ var dropFile = (options = {}) => {
|
|
|
2457
2123
|
})
|
|
2458
2124
|
];
|
|
2459
2125
|
};
|
|
2460
|
-
var styles3 =
|
|
2126
|
+
var styles3 = EditorView10.theme({
|
|
2461
2127
|
".cm-dropCursor": {
|
|
2462
2128
|
borderLeft: "2px solid var(--color-accent-text)",
|
|
2463
2129
|
color: "var(--color-accent-text)",
|
|
@@ -2479,10 +2145,10 @@ import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode"
|
|
|
2479
2145
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
2480
2146
|
import { generateName } from "@dxos/display-name";
|
|
2481
2147
|
import { log as log8 } from "@dxos/log";
|
|
2482
|
-
import { hexToHue, isTruthy as
|
|
2148
|
+
import { hexToHue, isTruthy as isTruthy3 } from "@dxos/util";
|
|
2483
2149
|
|
|
2484
2150
|
// src/styles/theme.ts
|
|
2485
|
-
import { EditorView as
|
|
2151
|
+
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
2486
2152
|
import { mx as mx3 } from "@dxos/ui-theme";
|
|
2487
2153
|
var headings = {
|
|
2488
2154
|
1: {
|
|
@@ -2530,7 +2196,7 @@ var markdownTheme = {
|
|
|
2530
2196
|
fontWeight: "100 !important"
|
|
2531
2197
|
})
|
|
2532
2198
|
};
|
|
2533
|
-
var baseTheme =
|
|
2199
|
+
var baseTheme = EditorView11.baseTheme({
|
|
2534
2200
|
/**
|
|
2535
2201
|
* Outer frame.
|
|
2536
2202
|
*/
|
|
@@ -2542,7 +2208,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2542
2208
|
* Scroller
|
|
2543
2209
|
*/
|
|
2544
2210
|
".cm-scroller": {
|
|
2545
|
-
// Browser scroll-anchoring: see comment in `
|
|
2211
|
+
// Browser scroll-anchoring: see comment in `scrolling/crawler.ts`. `auto` lets the browser pin a
|
|
2546
2212
|
// stable element near the viewport top so widget resizes (e.g. tool-block TogglePanel
|
|
2547
2213
|
// open/close) don't jump the user's view.
|
|
2548
2214
|
overflowAnchor: "auto"
|
|
@@ -2653,7 +2319,8 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2653
2319
|
textDecorationThickness: "1px",
|
|
2654
2320
|
textDecorationColor: "var(--color-separator)",
|
|
2655
2321
|
textUnderlineOffset: "2px",
|
|
2656
|
-
borderRadius: ".125rem"
|
|
2322
|
+
borderRadius: ".125rem",
|
|
2323
|
+
cursor: "pointer"
|
|
2657
2324
|
},
|
|
2658
2325
|
".cm-link > span": {
|
|
2659
2326
|
color: "var(--color-accent-text)"
|
|
@@ -2691,12 +2358,12 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2691
2358
|
padding: "4px"
|
|
2692
2359
|
},
|
|
2693
2360
|
".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {
|
|
2694
|
-
background: "var(--color-
|
|
2695
|
-
color: "var(--color-base-
|
|
2361
|
+
background: "var(--color-current-surface)",
|
|
2362
|
+
color: "var(--color-base-foreground)"
|
|
2696
2363
|
},
|
|
2697
2364
|
".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
|
|
2698
2365
|
paddingLeft: "4px !important",
|
|
2699
|
-
color: "var(--color-base-
|
|
2366
|
+
color: "var(--color-base-foreground)"
|
|
2700
2367
|
},
|
|
2701
2368
|
/**
|
|
2702
2369
|
* Completion info.
|
|
@@ -2715,7 +2382,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2715
2382
|
padding: "0 4px"
|
|
2716
2383
|
},
|
|
2717
2384
|
".cm-completionMatchedText": {
|
|
2718
|
-
color: "var(--color-base-
|
|
2385
|
+
color: "var(--color-base-foreground)",
|
|
2719
2386
|
textDecoration: "none !important"
|
|
2720
2387
|
},
|
|
2721
2388
|
/**
|
|
@@ -2750,7 +2417,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2750
2417
|
backgroundColor: "var(--color-input-surface)"
|
|
2751
2418
|
},
|
|
2752
2419
|
".cm-panel input:focus, .cm-panel button:focus": {
|
|
2753
|
-
outline: "1px solid var(--color-
|
|
2420
|
+
outline: "1px solid var(--color-focus-ring-subtle)"
|
|
2754
2421
|
},
|
|
2755
2422
|
".cm-panel label": {
|
|
2756
2423
|
display: "inline-flex",
|
|
@@ -2763,7 +2430,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2763
2430
|
height: "8px",
|
|
2764
2431
|
marginRight: "6px !important",
|
|
2765
2432
|
padding: "2px !important",
|
|
2766
|
-
color: "var(--color-
|
|
2433
|
+
color: "var(--color-focus-ring-subtle)"
|
|
2767
2434
|
},
|
|
2768
2435
|
".cm-panel button": {
|
|
2769
2436
|
"&:hover": {
|
|
@@ -2779,14 +2446,14 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2779
2446
|
borderTop: "1px solid var(--color-separator)"
|
|
2780
2447
|
}
|
|
2781
2448
|
});
|
|
2782
|
-
var editorGutter =
|
|
2449
|
+
var editorGutter = EditorView11.theme({
|
|
2783
2450
|
".cm-gutters": {
|
|
2784
2451
|
// NOTE: Non-transparent background required to cover content if scrolling horizontally.
|
|
2785
2452
|
background: "var(--color-base-surface) !important",
|
|
2786
2453
|
paddingRight: "1rem"
|
|
2787
2454
|
}
|
|
2788
2455
|
});
|
|
2789
|
-
var createFontTheme = ({ monospace } = {}) =>
|
|
2456
|
+
var createFontTheme = ({ monospace } = {}) => EditorView11.theme({
|
|
2790
2457
|
// Main content.
|
|
2791
2458
|
".cm-scroller": {
|
|
2792
2459
|
fontFamily: monospace ? fontMono : fontBody
|
|
@@ -2799,9 +2466,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
|
|
|
2799
2466
|
});
|
|
2800
2467
|
|
|
2801
2468
|
// src/extensions/focus.ts
|
|
2802
|
-
import { StateEffect as
|
|
2803
|
-
import { EditorView as
|
|
2804
|
-
var focusEffect =
|
|
2469
|
+
import { StateEffect as StateEffect4, StateField as StateField5 } from "@codemirror/state";
|
|
2470
|
+
import { EditorView as EditorView12 } from "@codemirror/view";
|
|
2471
|
+
var focusEffect = StateEffect4.define();
|
|
2805
2472
|
var focusField = StateField5.define({
|
|
2806
2473
|
create: () => false,
|
|
2807
2474
|
update: (value, tr) => {
|
|
@@ -2810,38 +2477,381 @@ var focusField = StateField5.define({
|
|
|
2810
2477
|
return effect.value;
|
|
2811
2478
|
}
|
|
2812
2479
|
}
|
|
2813
|
-
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);
|
|
2814
2649
|
}
|
|
2815
|
-
|
|
2816
|
-
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
}));
|
|
2650
|
+
return {
|
|
2651
|
+
scroll: () => {
|
|
2652
|
+
if (rafId === null) {
|
|
2653
|
+
currentTop = el.scrollTop;
|
|
2654
|
+
lastTime = 0;
|
|
2655
|
+
rafId = requestAnimationFrame(frame);
|
|
2656
|
+
}
|
|
2823
2657
|
},
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2827
|
-
|
|
2658
|
+
cancel: () => {
|
|
2659
|
+
if (rafId !== null) {
|
|
2660
|
+
cancelAnimationFrame(rafId);
|
|
2661
|
+
velocity = 0;
|
|
2662
|
+
lastTime = 0;
|
|
2663
|
+
rafId = null;
|
|
2664
|
+
}
|
|
2828
2665
|
}
|
|
2829
|
-
}
|
|
2830
|
-
|
|
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
|
+
}
|
|
2831
2841
|
|
|
2832
|
-
// src/extensions/scroll-past-end.ts
|
|
2842
|
+
// src/extensions/scrolling/scroll-past-end.ts
|
|
2833
2843
|
import { EditorView as EditorView15, ViewPlugin as ViewPlugin11 } from "@codemirror/view";
|
|
2834
2844
|
var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
|
|
2835
|
-
|
|
2836
|
-
|
|
2837
|
-
style:
|
|
2845
|
+
_height = 1e3;
|
|
2846
|
+
_attrs = {
|
|
2847
|
+
style: `padding-bottom: ${this._height}px`
|
|
2838
2848
|
};
|
|
2839
2849
|
update({ view }) {
|
|
2840
2850
|
const lastLineBlock = view.lineBlockAt(view.state.doc.length);
|
|
2841
2851
|
const height = view.dom.clientHeight - lastLineBlock.height - view.documentPadding.top - 0.5;
|
|
2842
|
-
if (height >= 0 && height !== this.
|
|
2843
|
-
this.
|
|
2844
|
-
this.
|
|
2852
|
+
if (height >= 0 && height !== this._height) {
|
|
2853
|
+
this._height = height;
|
|
2854
|
+
this._attrs = {
|
|
2845
2855
|
style: `padding-bottom: ${height}px`
|
|
2846
2856
|
};
|
|
2847
2857
|
}
|
|
@@ -2849,9 +2859,22 @@ var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
|
|
|
2849
2859
|
});
|
|
2850
2860
|
var scrollPastEnd = () => [
|
|
2851
2861
|
scrollPastEndPlugin,
|
|
2852
|
-
EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?.
|
|
2862
|
+
EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?._attrs ?? null)
|
|
2853
2863
|
];
|
|
2854
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
|
+
|
|
2855
2878
|
// src/extensions/factories.ts
|
|
2856
2879
|
var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
|
|
2857
2880
|
var tabbable = EditorView16.contentAttributes.of({
|
|
@@ -2959,8 +2982,8 @@ var createBasicExtensions = (propsProp) => {
|
|
|
2959
2982
|
preventDefault: true,
|
|
2960
2983
|
run: () => true
|
|
2961
2984
|
}
|
|
2962
|
-
].filter(
|
|
2963
|
-
].filter(
|
|
2985
|
+
].filter(isTruthy3))
|
|
2986
|
+
].filter(isTruthy3);
|
|
2964
2987
|
};
|
|
2965
2988
|
var grow = {
|
|
2966
2989
|
editor: {
|
|
@@ -3002,7 +3025,7 @@ var createThemeExtensions = ({ monospace, scrollbarThin, slots: slotsProp, synta
|
|
|
3002
3025
|
}
|
|
3003
3026
|
}
|
|
3004
3027
|
})
|
|
3005
|
-
].filter(
|
|
3028
|
+
].filter(isTruthy3);
|
|
3006
3029
|
};
|
|
3007
3030
|
var createDataExtensions = ({ id, text, messenger, identity }) => {
|
|
3008
3031
|
const extensions = [];
|
|
@@ -4326,7 +4349,7 @@ import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lan
|
|
|
4326
4349
|
import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
4327
4350
|
import { languages } from "@codemirror/language-data";
|
|
4328
4351
|
import { keymap as keymap9 } from "@codemirror/view";
|
|
4329
|
-
import { isTruthy as
|
|
4352
|
+
import { isTruthy as isTruthy4 } from "@dxos/util";
|
|
4330
4353
|
|
|
4331
4354
|
// src/extensions/markdown/highlight.ts
|
|
4332
4355
|
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
@@ -4558,7 +4581,7 @@ var createMarkdownExtensions = (options = {}) => {
|
|
|
4558
4581
|
...defaultKeymap2,
|
|
4559
4582
|
// TODO(burdon): Remove?
|
|
4560
4583
|
...completionKeymap
|
|
4561
|
-
].filter(
|
|
4584
|
+
].filter(isTruthy4))
|
|
4562
4585
|
];
|
|
4563
4586
|
};
|
|
4564
4587
|
var noFencedCodeFolding = {
|
|
@@ -6639,7 +6662,7 @@ var decorations = () => [
|
|
|
6639
6662
|
marginBottom: "2px"
|
|
6640
6663
|
},
|
|
6641
6664
|
".cm-list-item-focused": {
|
|
6642
|
-
borderColor: "var(--color-
|
|
6665
|
+
borderColor: "var(--color-focus-ring-subtle)"
|
|
6643
6666
|
},
|
|
6644
6667
|
"&:focus-within .cm-list-item-selected": {
|
|
6645
6668
|
borderColor: "var(--color-separator)"
|
|
@@ -7878,7 +7901,7 @@ var xmlFormatting = ({ skip } = {}) => {
|
|
|
7878
7901
|
}),
|
|
7879
7902
|
EditorView31.baseTheme({
|
|
7880
7903
|
".cm-xml-element": {
|
|
7881
|
-
backgroundColor: "var(--color-
|
|
7904
|
+
backgroundColor: "var(--color-current-surface)",
|
|
7882
7905
|
borderRadius: "0.25rem",
|
|
7883
7906
|
padding: "0.25rem"
|
|
7884
7907
|
},
|
|
@@ -8139,7 +8162,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
|
|
|
8139
8162
|
anchor: line.from,
|
|
8140
8163
|
head: line.from
|
|
8141
8164
|
},
|
|
8142
|
-
effects:
|
|
8165
|
+
effects: crawlerLineEffect.of({
|
|
8143
8166
|
line: line.number - 1,
|
|
8144
8167
|
offset: -16
|
|
8145
8168
|
})
|
|
@@ -8172,7 +8195,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
|
|
|
8172
8195
|
anchor: line.to,
|
|
8173
8196
|
head: line.to
|
|
8174
8197
|
},
|
|
8175
|
-
effects:
|
|
8198
|
+
effects: crawlerLineEffect.of({
|
|
8176
8199
|
line: line.number - 1,
|
|
8177
8200
|
offset: -16
|
|
8178
8201
|
})
|
|
@@ -8184,7 +8207,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
|
|
|
8184
8207
|
anchor: line.to,
|
|
8185
8208
|
head: line.to
|
|
8186
8209
|
},
|
|
8187
|
-
effects:
|
|
8210
|
+
effects: crawlerLineEffect.of({
|
|
8188
8211
|
line: line.number - 1,
|
|
8189
8212
|
position: "end"
|
|
8190
8213
|
})
|
|
@@ -8503,6 +8526,9 @@ export {
|
|
|
8503
8526
|
commentsState,
|
|
8504
8527
|
compactSlots,
|
|
8505
8528
|
convertTreeToJson,
|
|
8529
|
+
crawler,
|
|
8530
|
+
crawlerActiveEffect,
|
|
8531
|
+
crawlerLineEffect,
|
|
8506
8532
|
createBasicExtensions,
|
|
8507
8533
|
createComment,
|
|
8508
8534
|
createCrawler,
|
|
@@ -8590,8 +8616,6 @@ export {
|
|
|
8590
8616
|
scrollThreadIntoView,
|
|
8591
8617
|
scrollToLine,
|
|
8592
8618
|
scroller,
|
|
8593
|
-
scrollerCrawlEffect,
|
|
8594
|
-
scrollerLineEffect,
|
|
8595
8619
|
selectionState,
|
|
8596
8620
|
setBlockquote,
|
|
8597
8621
|
setComments,
|