@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
|
@@ -513,344 +513,10 @@ var typeahead = ({ onComplete } = {}) => {
|
|
|
513
513
|
];
|
|
514
514
|
};
|
|
515
515
|
|
|
516
|
-
// src/extensions/auto-scroll.ts
|
|
517
|
-
import { StateEffect as StateEffect2 } from "@codemirror/state";
|
|
518
|
-
import { EditorView as EditorView5, ViewPlugin as ViewPlugin6 } from "@codemirror/view";
|
|
519
|
-
import { addEventListener, combine, throttle } from "@dxos/async";
|
|
520
|
-
import { Domino } from "@dxos/ui";
|
|
521
|
-
import { getSize } from "@dxos/ui-theme";
|
|
522
|
-
|
|
523
|
-
// src/extensions/scroller.ts
|
|
524
|
-
import { StateEffect } from "@codemirror/state";
|
|
525
|
-
import { EditorView as EditorView4, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
526
|
-
import { log as log2 } from "@dxos/log";
|
|
527
|
-
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/scroller.ts";
|
|
528
|
-
var scrollerLineEffect = StateEffect.define();
|
|
529
|
-
var scrollerCrawlEffect = StateEffect.define();
|
|
530
|
-
var scrollToLine = (view, options) => {
|
|
531
|
-
view.dispatch({
|
|
532
|
-
effects: scrollerLineEffect.of(options)
|
|
533
|
-
});
|
|
534
|
-
};
|
|
535
|
-
var scroller = ({ overScroll = 0 } = {}) => {
|
|
536
|
-
const scrollPlugin = ViewPlugin5.fromClass(class ScrollerPlugin {
|
|
537
|
-
view;
|
|
538
|
-
crawler;
|
|
539
|
-
constructor(view) {
|
|
540
|
-
this.view = view;
|
|
541
|
-
this.crawler = createCrawler(this.view);
|
|
542
|
-
}
|
|
543
|
-
// No-op.
|
|
544
|
-
destroy() {
|
|
545
|
-
this.crawler.cancel();
|
|
546
|
-
}
|
|
547
|
-
cancel() {
|
|
548
|
-
this.crawler.cancel();
|
|
549
|
-
}
|
|
550
|
-
crawl(start = false) {
|
|
551
|
-
if (start) {
|
|
552
|
-
this.crawler.scroll();
|
|
553
|
-
} else {
|
|
554
|
-
this.crawler.cancel();
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
scroll({ line, offset = 0, position, behavior = "instant" }) {
|
|
558
|
-
const { scrollTop, scrollHeight, clientHeight } = this.view.scrollDOM;
|
|
559
|
-
const scrollerRect = this.view.scrollDOM.getBoundingClientRect();
|
|
560
|
-
const doc = this.view.state.doc;
|
|
561
|
-
let targetScrollTop = scrollHeight - clientHeight + offset;
|
|
562
|
-
if (line >= 0 && line <= doc.lines - 1) {
|
|
563
|
-
const lineStart = doc.line(line + 1).from;
|
|
564
|
-
const coords = this.view.coordsAtPos(lineStart);
|
|
565
|
-
if (coords) {
|
|
566
|
-
const currentScrollTop = scrollTop;
|
|
567
|
-
const maxScrollTop = scrollHeight - clientHeight;
|
|
568
|
-
if (position === "end") {
|
|
569
|
-
targetScrollTop = currentScrollTop + coords.bottom - scrollerRect.bottom + offset;
|
|
570
|
-
} else {
|
|
571
|
-
targetScrollTop = currentScrollTop + coords.top - scrollerRect.top + offset;
|
|
572
|
-
}
|
|
573
|
-
targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
|
|
574
|
-
}
|
|
575
|
-
}
|
|
576
|
-
requestAnimationFrame(() => {
|
|
577
|
-
this.view.scrollDOM.scrollTo({
|
|
578
|
-
top: targetScrollTop
|
|
579
|
-
});
|
|
580
|
-
});
|
|
581
|
-
}
|
|
582
|
-
});
|
|
583
|
-
return [
|
|
584
|
-
scrollPlugin,
|
|
585
|
-
// Listen for effect.
|
|
586
|
-
EditorView4.updateListener.of((update2) => {
|
|
587
|
-
update2.transactions.forEach((transaction) => {
|
|
588
|
-
try {
|
|
589
|
-
const plugin = update2.view.plugin(scrollPlugin);
|
|
590
|
-
if (plugin) {
|
|
591
|
-
for (const effect of transaction.effects) {
|
|
592
|
-
if (effect.is(scrollerCrawlEffect)) {
|
|
593
|
-
plugin.crawl(effect.value);
|
|
594
|
-
} else if (effect.is(scrollerLineEffect)) {
|
|
595
|
-
plugin.scroll(effect.value);
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
}
|
|
599
|
-
} catch (err) {
|
|
600
|
-
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 91, S: void 0 });
|
|
601
|
-
}
|
|
602
|
-
});
|
|
603
|
-
}),
|
|
604
|
-
// Styles.
|
|
605
|
-
EditorView4.theme({
|
|
606
|
-
".cm-scroller": {
|
|
607
|
-
overflowY: "scroll",
|
|
608
|
-
// Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks
|
|
609
|
-
// expanding their TogglePanel), the browser picks a stable element near the viewport
|
|
610
|
-
// top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning
|
|
611
|
-
// logic still has the final word when pinned (forces scrollTop to scrollHeight).
|
|
612
|
-
overflowAnchor: "auto"
|
|
613
|
-
},
|
|
614
|
-
".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
|
|
615
|
-
display: "none"
|
|
616
|
-
},
|
|
617
|
-
".cm-scroller::-webkit-scrollbar-thumb": {
|
|
618
|
-
background: "transparent",
|
|
619
|
-
transition: "background 0.15s"
|
|
620
|
-
},
|
|
621
|
-
"&:hover .cm-scroller::-webkit-scrollbar-thumb": {
|
|
622
|
-
background: "var(--color-scrollbar-thumb)"
|
|
623
|
-
},
|
|
624
|
-
// Spacer below the last text line. Implemented as a real block pseudo-element
|
|
625
|
-
// (rather than `padding-bottom` on `.cm-content`) so it materializes in the
|
|
626
|
-
// scroller's `scrollHeight` regardless of how `padding` is reset by the base
|
|
627
|
-
// theme or downstream classes — this is what gives auto-scroll its head-room
|
|
628
|
-
// so the last line stays `overScroll` px above the viewport bottom.
|
|
629
|
-
".cm-content::after": {
|
|
630
|
-
content: '""',
|
|
631
|
-
display: "block",
|
|
632
|
-
height: `${overScroll}px`
|
|
633
|
-
},
|
|
634
|
-
".cm-scroll-button": {
|
|
635
|
-
position: "absolute",
|
|
636
|
-
bottom: "0.5rem",
|
|
637
|
-
right: "1rem"
|
|
638
|
-
}
|
|
639
|
-
})
|
|
640
|
-
];
|
|
641
|
-
};
|
|
642
|
-
function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
|
|
643
|
-
const el = view.scrollDOM;
|
|
644
|
-
let currentTop = 0;
|
|
645
|
-
let velocity = 0;
|
|
646
|
-
let rafId = null;
|
|
647
|
-
let lastTime = 0;
|
|
648
|
-
function frame(now) {
|
|
649
|
-
const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1e3);
|
|
650
|
-
lastTime = now;
|
|
651
|
-
const targetTop = el.scrollHeight - el.clientHeight;
|
|
652
|
-
const delta = targetTop - currentTop;
|
|
653
|
-
if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
|
|
654
|
-
el.scrollTop = targetTop;
|
|
655
|
-
currentTop = targetTop;
|
|
656
|
-
velocity = 0;
|
|
657
|
-
rafId = null;
|
|
658
|
-
lastTime = 0;
|
|
659
|
-
return;
|
|
660
|
-
}
|
|
661
|
-
const accel = omega * omega * delta - 2 * omega * velocity;
|
|
662
|
-
velocity += accel * dt;
|
|
663
|
-
currentTop += velocity * dt;
|
|
664
|
-
el.scrollTop = currentTop;
|
|
665
|
-
rafId = requestAnimationFrame(frame);
|
|
666
|
-
}
|
|
667
|
-
return {
|
|
668
|
-
scroll: () => {
|
|
669
|
-
if (rafId === null) {
|
|
670
|
-
currentTop = el.scrollTop;
|
|
671
|
-
lastTime = 0;
|
|
672
|
-
rafId = requestAnimationFrame(frame);
|
|
673
|
-
}
|
|
674
|
-
},
|
|
675
|
-
cancel: () => {
|
|
676
|
-
if (rafId !== null) {
|
|
677
|
-
cancelAnimationFrame(rafId);
|
|
678
|
-
velocity = 0;
|
|
679
|
-
lastTime = 0;
|
|
680
|
-
rafId = null;
|
|
681
|
-
}
|
|
682
|
-
}
|
|
683
|
-
};
|
|
684
|
-
}
|
|
685
|
-
|
|
686
|
-
// src/extensions/auto-scroll.ts
|
|
687
|
-
var autoScrollEffect = StateEffect2.define();
|
|
688
|
-
var autoScroll = ({ scrollOnResize = true } = {}) => {
|
|
689
|
-
let buttonContainer;
|
|
690
|
-
let isPinned = true;
|
|
691
|
-
let jumpPending = false;
|
|
692
|
-
let enabled = true;
|
|
693
|
-
let firstUpdate = true;
|
|
694
|
-
const setPinned = (pinned) => {
|
|
695
|
-
buttonContainer?.classList.toggle("opacity-0", pinned);
|
|
696
|
-
isPinned = pinned;
|
|
697
|
-
};
|
|
698
|
-
return [
|
|
699
|
-
// Update listener for scrolling when content changes.
|
|
700
|
-
EditorView5.updateListener.of((update2) => {
|
|
701
|
-
const { view, heightChanged, state, startState } = update2;
|
|
702
|
-
for (const tr of update2.transactions) {
|
|
703
|
-
for (const effect of tr.effects) {
|
|
704
|
-
if (effect.is(autoScrollEffect)) {
|
|
705
|
-
enabled = effect.value;
|
|
706
|
-
if (enabled) {
|
|
707
|
-
setPinned(true);
|
|
708
|
-
view.dispatch({
|
|
709
|
-
effects: scrollerCrawlEffect.of(true)
|
|
710
|
-
});
|
|
711
|
-
} else {
|
|
712
|
-
view.dispatch({
|
|
713
|
-
effects: scrollerCrawlEffect.of(false)
|
|
714
|
-
});
|
|
715
|
-
}
|
|
716
|
-
}
|
|
717
|
-
}
|
|
718
|
-
}
|
|
719
|
-
if (!enabled) {
|
|
720
|
-
return;
|
|
721
|
-
}
|
|
722
|
-
if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
|
|
723
|
-
firstUpdate = false;
|
|
724
|
-
jumpPending = true;
|
|
725
|
-
requestAnimationFrame(() => {
|
|
726
|
-
view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
|
|
727
|
-
jumpPending = false;
|
|
728
|
-
});
|
|
729
|
-
return;
|
|
730
|
-
}
|
|
731
|
-
firstUpdate = false;
|
|
732
|
-
if (jumpPending) {
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
if (heightChanged) {
|
|
736
|
-
if (isPinned) {
|
|
737
|
-
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
738
|
-
const delta = scrollHeight - scrollTop - clientHeight;
|
|
739
|
-
if (delta > 0) {
|
|
740
|
-
setPinned(true);
|
|
741
|
-
view.dispatch({
|
|
742
|
-
effects: scrollerCrawlEffect.of(true)
|
|
743
|
-
});
|
|
744
|
-
} else if (delta < -1) {
|
|
745
|
-
setPinned(false);
|
|
746
|
-
}
|
|
747
|
-
} else {
|
|
748
|
-
if (state.doc.length === 0) {
|
|
749
|
-
setPinned(true);
|
|
750
|
-
}
|
|
751
|
-
}
|
|
752
|
-
}
|
|
753
|
-
}),
|
|
754
|
-
// Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
|
|
755
|
-
// window resize). Doc-driven height changes are handled by the updateListener above; this
|
|
756
|
-
// observer covers the case where the viewport changes while the doc length is unchanged.
|
|
757
|
-
scrollOnResize ? ViewPlugin6.fromClass(class {
|
|
758
|
-
observer;
|
|
759
|
-
firstObservation = true;
|
|
760
|
-
destroyed = false;
|
|
761
|
-
constructor(view) {
|
|
762
|
-
const onResize = throttle(() => {
|
|
763
|
-
if (this.destroyed || !enabled) {
|
|
764
|
-
return;
|
|
765
|
-
}
|
|
766
|
-
setPinned(true);
|
|
767
|
-
requestAnimationFrame(() => {
|
|
768
|
-
if (this.destroyed) {
|
|
769
|
-
return;
|
|
770
|
-
}
|
|
771
|
-
view.scrollDOM.scrollTo({
|
|
772
|
-
top: view.scrollDOM.scrollHeight,
|
|
773
|
-
behavior: "instant"
|
|
774
|
-
});
|
|
775
|
-
view.dispatch({
|
|
776
|
-
effects: scrollerCrawlEffect.of(false)
|
|
777
|
-
});
|
|
778
|
-
});
|
|
779
|
-
}, 50);
|
|
780
|
-
this.observer = new ResizeObserver(() => {
|
|
781
|
-
if (this.firstObservation) {
|
|
782
|
-
this.firstObservation = false;
|
|
783
|
-
return;
|
|
784
|
-
}
|
|
785
|
-
onResize();
|
|
786
|
-
});
|
|
787
|
-
this.observer.observe(view.scrollDOM);
|
|
788
|
-
}
|
|
789
|
-
destroy() {
|
|
790
|
-
this.destroyed = true;
|
|
791
|
-
this.observer.disconnect();
|
|
792
|
-
}
|
|
793
|
-
}) : [],
|
|
794
|
-
// Detect user scroll and unpin (or re-pin if scrolled to the bottom).
|
|
795
|
-
ViewPlugin6.fromClass(class {
|
|
796
|
-
cleanup;
|
|
797
|
-
constructor(view) {
|
|
798
|
-
this.cleanup = createUserScrollDetector(view.scrollDOM, throttle(() => {
|
|
799
|
-
requestAnimationFrame(() => {
|
|
800
|
-
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
801
|
-
const delta = scrollHeight - scrollTop - clientHeight;
|
|
802
|
-
const pinned = delta === 0;
|
|
803
|
-
setPinned(pinned);
|
|
804
|
-
if (!pinned) {
|
|
805
|
-
view.dispatch({
|
|
806
|
-
effects: scrollerCrawlEffect.of(false)
|
|
807
|
-
});
|
|
808
|
-
}
|
|
809
|
-
});
|
|
810
|
-
}, 500));
|
|
811
|
-
}
|
|
812
|
-
destroy() {
|
|
813
|
-
this.cleanup();
|
|
814
|
-
}
|
|
815
|
-
}),
|
|
816
|
-
// Scroll button.
|
|
817
|
-
ViewPlugin6.fromClass(class {
|
|
818
|
-
constructor(view) {
|
|
819
|
-
const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
|
|
820
|
-
icon: "ph--arrow-down--regular"
|
|
821
|
-
});
|
|
822
|
-
const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
|
|
823
|
-
"data-density": "fine"
|
|
824
|
-
}).append(icon).on("click", () => {
|
|
825
|
-
setPinned(true);
|
|
826
|
-
view.dispatch({
|
|
827
|
-
effects: scrollerLineEffect.of({
|
|
828
|
-
line: -1,
|
|
829
|
-
position: "end",
|
|
830
|
-
behavior: "smooth"
|
|
831
|
-
})
|
|
832
|
-
});
|
|
833
|
-
});
|
|
834
|
-
buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
|
|
835
|
-
view.scrollDOM.parentElement.appendChild(buttonContainer);
|
|
836
|
-
}
|
|
837
|
-
})
|
|
838
|
-
];
|
|
839
|
-
};
|
|
840
|
-
function createUserScrollDetector(element, onUserScroll) {
|
|
841
|
-
return combine(addEventListener(element, "wheel", () => onUserScroll(), {
|
|
842
|
-
passive: true
|
|
843
|
-
}), addEventListener(element, "pointerdown", (event) => {
|
|
844
|
-
if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {
|
|
845
|
-
onUserScroll();
|
|
846
|
-
}
|
|
847
|
-
}));
|
|
848
|
-
}
|
|
849
|
-
|
|
850
516
|
// src/extensions/automerge/automerge.ts
|
|
851
517
|
import { next as A3 } from "@automerge/automerge";
|
|
852
518
|
import { StateField, Transaction as Transaction2 } from "@codemirror/state";
|
|
853
|
-
import { EditorView as
|
|
519
|
+
import { EditorView as EditorView4, ViewPlugin as ViewPlugin5 } from "@codemirror/view";
|
|
854
520
|
import { DocAccessor } from "@dxos/echo-db";
|
|
855
521
|
|
|
856
522
|
// src/extensions/state.ts
|
|
@@ -859,14 +525,14 @@ var initialSync = Transaction.userEvent.of("initial.sync");
|
|
|
859
525
|
|
|
860
526
|
// src/extensions/automerge/cursor.ts
|
|
861
527
|
import { fromCursor, toCursor } from "@dxos/echo-db";
|
|
862
|
-
import { log as
|
|
863
|
-
var
|
|
528
|
+
import { log as log2 } from "@dxos/log";
|
|
529
|
+
var __dxlog_file2 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/cursor.ts";
|
|
864
530
|
var cursorConverter = (accessor) => ({
|
|
865
531
|
toCursor: (pos, assoc) => {
|
|
866
532
|
try {
|
|
867
533
|
return toCursor(accessor, pos, assoc);
|
|
868
534
|
} catch (err) {
|
|
869
|
-
|
|
535
|
+
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 11, S: void 0 });
|
|
870
536
|
return "";
|
|
871
537
|
}
|
|
872
538
|
},
|
|
@@ -874,17 +540,17 @@ var cursorConverter = (accessor) => ({
|
|
|
874
540
|
try {
|
|
875
541
|
return fromCursor(accessor, cursor);
|
|
876
542
|
} catch (err) {
|
|
877
|
-
|
|
543
|
+
log2.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file2, L: 19, S: void 0 });
|
|
878
544
|
return 0;
|
|
879
545
|
}
|
|
880
546
|
}
|
|
881
547
|
});
|
|
882
548
|
|
|
883
549
|
// src/extensions/automerge/defs.ts
|
|
884
|
-
import { Annotation, StateEffect
|
|
550
|
+
import { Annotation, StateEffect } from "@codemirror/state";
|
|
885
551
|
var getPath = (state, field) => state.field(field).path;
|
|
886
552
|
var getLastHeads = (state, field) => state.field(field).lastHeads;
|
|
887
|
-
var updateHeadsEffect =
|
|
553
|
+
var updateHeadsEffect = StateEffect.define({});
|
|
888
554
|
var updateHeads = (newHeads) => updateHeadsEffect.of({
|
|
889
555
|
newHeads
|
|
890
556
|
});
|
|
@@ -895,7 +561,7 @@ var isReconcile = (tr) => {
|
|
|
895
561
|
|
|
896
562
|
// src/extensions/automerge/sync.ts
|
|
897
563
|
import { next as A2 } from "@automerge/automerge";
|
|
898
|
-
import { log as
|
|
564
|
+
import { log as log3 } from "@dxos/log";
|
|
899
565
|
|
|
900
566
|
// src/extensions/automerge/update-automerge.ts
|
|
901
567
|
import { next as A } from "@automerge/automerge";
|
|
@@ -1036,7 +702,7 @@ var charPath = (textPath, candidatePath) => {
|
|
|
1036
702
|
};
|
|
1037
703
|
|
|
1038
704
|
// src/extensions/automerge/sync.ts
|
|
1039
|
-
var
|
|
705
|
+
var __dxlog_file3 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/automerge/sync.ts";
|
|
1040
706
|
var Syncer = class {
|
|
1041
707
|
_handle;
|
|
1042
708
|
_state;
|
|
@@ -1059,7 +725,7 @@ var Syncer = class {
|
|
|
1059
725
|
this._pending = false;
|
|
1060
726
|
}
|
|
1061
727
|
onEditorChange(view) {
|
|
1062
|
-
|
|
728
|
+
log3("onEditorChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 35, S: this });
|
|
1063
729
|
const transactions = view.state.field(this._state).unreconciledTransactions.filter((tx) => !isReconcile(tx));
|
|
1064
730
|
const newHeads = updateAutomerge(this._state, this._handle, transactions, view.state);
|
|
1065
731
|
if (newHeads) {
|
|
@@ -1070,7 +736,7 @@ var Syncer = class {
|
|
|
1070
736
|
}
|
|
1071
737
|
}
|
|
1072
738
|
onAutomergeChange(view) {
|
|
1073
|
-
|
|
739
|
+
log3("onAutomergeChange", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file3, L: 47, S: this });
|
|
1074
740
|
const oldHeads = getLastHeads(view.state, this._state);
|
|
1075
741
|
const newHeads = A2.getHeads(this._handle.doc());
|
|
1076
742
|
const diff = A2.equals(oldHeads, newHeads) ? [] : A2.diff(this._handle.doc(), oldHeads, newHeads);
|
|
@@ -1123,7 +789,7 @@ var automerge = (accessor) => {
|
|
|
1123
789
|
// Track heads.
|
|
1124
790
|
syncState,
|
|
1125
791
|
// Reconcile external updates.
|
|
1126
|
-
|
|
792
|
+
ViewPlugin5.fromClass(class {
|
|
1127
793
|
_view;
|
|
1128
794
|
constructor(_view) {
|
|
1129
795
|
this._view = _view;
|
|
@@ -1154,7 +820,7 @@ var automerge = (accessor) => {
|
|
|
1154
820
|
};
|
|
1155
821
|
}),
|
|
1156
822
|
// Reconcile local updates.
|
|
1157
|
-
|
|
823
|
+
EditorView4.updateListener.of(({ view, changes, transactions }) => {
|
|
1158
824
|
if (!changes.empty) {
|
|
1159
825
|
const isInitialSync = transactions.some((tr) => tr.annotation(Transaction2.userEvent) === initialSync.value);
|
|
1160
826
|
if (!isInitialSync) {
|
|
@@ -1167,10 +833,10 @@ var automerge = (accessor) => {
|
|
|
1167
833
|
|
|
1168
834
|
// src/extensions/awareness/awareness.ts
|
|
1169
835
|
import { Annotation as Annotation2, RangeSet } from "@codemirror/state";
|
|
1170
|
-
import { Decoration as Decoration5, EditorView as
|
|
836
|
+
import { Decoration as Decoration5, EditorView as EditorView5, ViewPlugin as ViewPlugin6, WidgetType as WidgetType3 } from "@codemirror/view";
|
|
1171
837
|
import { Event } from "@dxos/async";
|
|
1172
838
|
import { Context } from "@dxos/context";
|
|
1173
|
-
var
|
|
839
|
+
var __dxlog_file4 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness.ts";
|
|
1174
840
|
var dummyProvider = {
|
|
1175
841
|
remoteStateChange: new Event(),
|
|
1176
842
|
open: () => {
|
|
@@ -1186,14 +852,14 @@ var RemoteSelectionChangedAnnotation = Annotation2.define();
|
|
|
1186
852
|
var awareness = (provider = dummyProvider) => {
|
|
1187
853
|
return [
|
|
1188
854
|
awarenessProvider.of(provider),
|
|
1189
|
-
|
|
855
|
+
ViewPlugin6.fromClass(RemoteSelectionsDecorator, {
|
|
1190
856
|
decorations: (value) => value.decorations
|
|
1191
857
|
}),
|
|
1192
858
|
styles
|
|
1193
859
|
];
|
|
1194
860
|
};
|
|
1195
861
|
var RemoteSelectionsDecorator = class {
|
|
1196
|
-
_ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F:
|
|
862
|
+
_ctx = new Context(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file4, L: 33 });
|
|
1197
863
|
_cursorConverter;
|
|
1198
864
|
_provider;
|
|
1199
865
|
_lastAnchor;
|
|
@@ -1342,7 +1008,7 @@ var RemoteCaretWidget = class extends WidgetType3 {
|
|
|
1342
1008
|
return true;
|
|
1343
1009
|
}
|
|
1344
1010
|
};
|
|
1345
|
-
var styles =
|
|
1011
|
+
var styles = EditorView5.theme({
|
|
1346
1012
|
".cm-collab-selection": {},
|
|
1347
1013
|
".cm-collab-selectionLine": {
|
|
1348
1014
|
padding: 0,
|
|
@@ -1404,8 +1070,8 @@ var styles = EditorView7.theme({
|
|
|
1404
1070
|
import { DeferredTask, Event as Event2, sleep } from "@dxos/async";
|
|
1405
1071
|
import { Context as Context2 } from "@dxos/context";
|
|
1406
1072
|
import { invariant } from "@dxos/invariant";
|
|
1407
|
-
import { log as
|
|
1408
|
-
var
|
|
1073
|
+
import { log as log4 } from "@dxos/log";
|
|
1074
|
+
var __dxlog_file5 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/awareness/awareness-provider.ts";
|
|
1409
1075
|
var DEBOUNCE_INTERVAL = 100;
|
|
1410
1076
|
var SpaceAwarenessProvider = class {
|
|
1411
1077
|
_remoteStates = /* @__PURE__ */ new Map();
|
|
@@ -1424,7 +1090,7 @@ var SpaceAwarenessProvider = class {
|
|
|
1424
1090
|
this._info = info;
|
|
1425
1091
|
}
|
|
1426
1092
|
open() {
|
|
1427
|
-
this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F:
|
|
1093
|
+
this._ctx = new Context2(void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 28 });
|
|
1428
1094
|
this._postTask = new DeferredTask(this._ctx, async () => {
|
|
1429
1095
|
if (this._localState) {
|
|
1430
1096
|
await this._messenger.postMessage(this._channel, {
|
|
@@ -1449,9 +1115,9 @@ var SpaceAwarenessProvider = class {
|
|
|
1449
1115
|
void this._messenger.postMessage(this._channel, {
|
|
1450
1116
|
kind: "query"
|
|
1451
1117
|
}).catch((err) => {
|
|
1452
|
-
|
|
1118
|
+
log4.debug("failed to query awareness", {
|
|
1453
1119
|
err
|
|
1454
|
-
}, { "~LogMeta": "~LogMeta", F:
|
|
1120
|
+
}, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 57, S: this });
|
|
1455
1121
|
});
|
|
1456
1122
|
}
|
|
1457
1123
|
close() {
|
|
@@ -1463,7 +1129,7 @@ var SpaceAwarenessProvider = class {
|
|
|
1463
1129
|
return Array.from(this._remoteStates.values());
|
|
1464
1130
|
}
|
|
1465
1131
|
update(position) {
|
|
1466
|
-
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1132
|
+
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 71, S: this, A: ["this._postTask", ""] });
|
|
1467
1133
|
this._localState = {
|
|
1468
1134
|
peerId: this._peerId,
|
|
1469
1135
|
position,
|
|
@@ -1472,22 +1138,22 @@ var SpaceAwarenessProvider = class {
|
|
|
1472
1138
|
this._postTask.schedule();
|
|
1473
1139
|
}
|
|
1474
1140
|
_handleQueryMessage() {
|
|
1475
|
-
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1141
|
+
invariant(this._postTask, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 80, S: this, A: ["this._postTask", ""] });
|
|
1476
1142
|
this._postTask.schedule();
|
|
1477
1143
|
}
|
|
1478
1144
|
_handlePostMessage(message) {
|
|
1479
|
-
invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F:
|
|
1145
|
+
invariant(message.kind === "post", void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file5, L: 84, S: this, A: ["message.kind === 'post'", ""] });
|
|
1480
1146
|
this._remoteStates.set(message.state.peerId, message.state);
|
|
1481
1147
|
this.remoteStateChange.emit();
|
|
1482
1148
|
}
|
|
1483
1149
|
};
|
|
1484
1150
|
|
|
1485
1151
|
// src/extensions/blast.ts
|
|
1486
|
-
import { EditorView as
|
|
1152
|
+
import { EditorView as EditorView6, keymap as keymap3 } from "@codemirror/view";
|
|
1487
1153
|
import defaultsDeep from "lodash.defaultsdeep";
|
|
1488
|
-
import { throttle
|
|
1154
|
+
import { throttle } from "@dxos/async";
|
|
1489
1155
|
import { invariant as invariant2 } from "@dxos/invariant";
|
|
1490
|
-
var
|
|
1156
|
+
var __dxlog_file6 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/blast.ts";
|
|
1491
1157
|
var defaultOptions = {
|
|
1492
1158
|
effect: 2,
|
|
1493
1159
|
maxParticles: 200,
|
|
@@ -1532,7 +1198,7 @@ var blast = (options = defaultOptions) => {
|
|
|
1532
1198
|
};
|
|
1533
1199
|
return [
|
|
1534
1200
|
// Cursor moved.
|
|
1535
|
-
|
|
1201
|
+
EditorView6.updateListener.of((update2) => {
|
|
1536
1202
|
if (blaster?.node !== update2.view.scrollDOM) {
|
|
1537
1203
|
if (blaster) {
|
|
1538
1204
|
blaster.destroy();
|
|
@@ -1605,7 +1271,7 @@ var Blaster = class {
|
|
|
1605
1271
|
return this._node;
|
|
1606
1272
|
}
|
|
1607
1273
|
initialize() {
|
|
1608
|
-
invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1274
|
+
invariant2(!this._canvas && !this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 134, S: this, A: ["!this._canvas && !this._ctx", ""] });
|
|
1609
1275
|
this._canvas = document.createElement("canvas");
|
|
1610
1276
|
this._canvas.id = "code-blast-canvas";
|
|
1611
1277
|
this._canvas.style.position = "absolute";
|
|
@@ -1634,7 +1300,7 @@ var Blaster = class {
|
|
|
1634
1300
|
}
|
|
1635
1301
|
}
|
|
1636
1302
|
start() {
|
|
1637
|
-
invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1303
|
+
invariant2(this._canvas && this._ctx, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file6, L: 166, S: this, A: ["this._canvas && this._ctx", ""] });
|
|
1638
1304
|
this._running = true;
|
|
1639
1305
|
this.loop();
|
|
1640
1306
|
}
|
|
@@ -1661,11 +1327,11 @@ var Blaster = class {
|
|
|
1661
1327
|
this.drawParticles();
|
|
1662
1328
|
requestAnimationFrame(this.loop.bind(this));
|
|
1663
1329
|
}
|
|
1664
|
-
shake =
|
|
1330
|
+
shake = throttle(({ time }) => {
|
|
1665
1331
|
this._shakeTime = this._shakeTimeMax || time;
|
|
1666
1332
|
this._shakeTimeMax = time;
|
|
1667
1333
|
}, 100);
|
|
1668
|
-
spawn =
|
|
1334
|
+
spawn = throttle(({ element, point }) => {
|
|
1669
1335
|
const color = getRGBComponents(element, this._options.color);
|
|
1670
1336
|
const numParticles = random(this._options.particleNumRange.min, this._options.particleNumRange.max);
|
|
1671
1337
|
const dir = this._lastPoint.x === point.x ? 0 : this._lastPoint.x < point.x ? 1 : -1;
|
|
@@ -1774,9 +1440,9 @@ var random = (min, max) => {
|
|
|
1774
1440
|
|
|
1775
1441
|
// src/extensions/blocks.ts
|
|
1776
1442
|
import { RangeSetBuilder as RangeSetBuilder3 } from "@codemirror/state";
|
|
1777
|
-
import { Decoration as Decoration6, EditorView as
|
|
1443
|
+
import { Decoration as Decoration6, EditorView as EditorView7, ViewPlugin as ViewPlugin7 } from "@codemirror/view";
|
|
1778
1444
|
import { mx as mx2 } from "@dxos/ui-theme";
|
|
1779
|
-
var paragraphBlockPlugin =
|
|
1445
|
+
var paragraphBlockPlugin = ViewPlugin7.fromClass(class {
|
|
1780
1446
|
decorations;
|
|
1781
1447
|
constructor(view) {
|
|
1782
1448
|
this.decorations = this.build(view);
|
|
@@ -1835,7 +1501,7 @@ var paragraphBlockPlugin = ViewPlugin9.fromClass(class {
|
|
|
1835
1501
|
});
|
|
1836
1502
|
var blocks = () => [
|
|
1837
1503
|
paragraphBlockPlugin,
|
|
1838
|
-
|
|
1504
|
+
EditorView7.baseTheme({
|
|
1839
1505
|
".cm-line.block-line": {
|
|
1840
1506
|
paddingLeft: "0.75rem",
|
|
1841
1507
|
paddingRight: "0.75rem",
|
|
@@ -1869,13 +1535,13 @@ var blocks = () => [
|
|
|
1869
1535
|
];
|
|
1870
1536
|
|
|
1871
1537
|
// src/extensions/bookmarks.ts
|
|
1872
|
-
import { Prec as Prec3, StateEffect as
|
|
1538
|
+
import { Prec as Prec3, StateEffect as StateEffect2, StateField as StateField2 } from "@codemirror/state";
|
|
1873
1539
|
import { keymap as keymap4 } from "@codemirror/view";
|
|
1874
|
-
import { log as
|
|
1875
|
-
var
|
|
1876
|
-
var addBookmark =
|
|
1877
|
-
var removeBookmark =
|
|
1878
|
-
var clearBookmarks =
|
|
1540
|
+
import { log as log5 } from "@dxos/log";
|
|
1541
|
+
var __dxlog_file7 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/bookmarks.ts";
|
|
1542
|
+
var addBookmark = StateEffect2.define();
|
|
1543
|
+
var removeBookmark = StateEffect2.define();
|
|
1544
|
+
var clearBookmarks = StateEffect2.define();
|
|
1879
1545
|
var bookmarks = () => {
|
|
1880
1546
|
return [
|
|
1881
1547
|
bookmarksField,
|
|
@@ -1884,7 +1550,7 @@ var bookmarks = () => {
|
|
|
1884
1550
|
key: "Mod-ArrowUp",
|
|
1885
1551
|
run: (view) => {
|
|
1886
1552
|
const bookmarks2 = view.state.field(bookmarksField);
|
|
1887
|
-
|
|
1553
|
+
log5("up", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 18, S: void 0 });
|
|
1888
1554
|
return true;
|
|
1889
1555
|
}
|
|
1890
1556
|
},
|
|
@@ -1892,7 +1558,7 @@ var bookmarks = () => {
|
|
|
1892
1558
|
key: "Mod-ArrowDown",
|
|
1893
1559
|
run: (view) => {
|
|
1894
1560
|
const bookmarks2 = view.state.field(bookmarksField);
|
|
1895
|
-
|
|
1561
|
+
log5("down", bookmarks2, { "~LogMeta": "~LogMeta", F: __dxlog_file7, L: 26, S: void 0 });
|
|
1896
1562
|
return true;
|
|
1897
1563
|
}
|
|
1898
1564
|
}
|
|
@@ -1929,27 +1595,27 @@ var bookmarksField = StateField2.define({
|
|
|
1929
1595
|
|
|
1930
1596
|
// src/extensions/comments.ts
|
|
1931
1597
|
import { invertedEffects } from "@codemirror/commands";
|
|
1932
|
-
import { StateEffect as
|
|
1933
|
-
import { Decoration as Decoration7, EditorView as
|
|
1598
|
+
import { StateEffect as StateEffect3, StateField as StateField3 } from "@codemirror/state";
|
|
1599
|
+
import { Decoration as Decoration7, EditorView as EditorView9, ViewPlugin as ViewPlugin8, hoverTooltip, keymap as keymap6 } from "@codemirror/view";
|
|
1934
1600
|
import sortBy from "lodash.sortby";
|
|
1935
1601
|
import { debounce as debounce2 } from "@dxos/async";
|
|
1936
|
-
import { log as
|
|
1602
|
+
import { log as log6 } from "@dxos/log";
|
|
1937
1603
|
import { isNonNullable } from "@dxos/util";
|
|
1938
1604
|
|
|
1939
1605
|
// src/extensions/selection.ts
|
|
1940
1606
|
import { Transaction as Transaction3 } from "@codemirror/state";
|
|
1941
|
-
import { EditorView as
|
|
1607
|
+
import { EditorView as EditorView8, keymap as keymap5 } from "@codemirror/view";
|
|
1942
1608
|
import { debounce } from "@dxos/async";
|
|
1943
1609
|
import { invariant as invariant3 } from "@dxos/invariant";
|
|
1944
1610
|
import { isTruthy } from "@dxos/util";
|
|
1945
|
-
var
|
|
1611
|
+
var __dxlog_file8 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/selection.ts";
|
|
1946
1612
|
var documentId = singleValueFacet();
|
|
1947
1613
|
var stateRestoreAnnotation = "org.dxos.cm.state-restore";
|
|
1948
1614
|
var createEditorStateTransaction = ({ scrollTo, selection }) => {
|
|
1949
1615
|
return {
|
|
1950
1616
|
selection,
|
|
1951
1617
|
scrollIntoView: !scrollTo,
|
|
1952
|
-
effects: scrollTo ?
|
|
1618
|
+
effects: scrollTo ? EditorView8.scrollIntoView(scrollTo, {
|
|
1953
1619
|
yMargin: 96
|
|
1954
1620
|
}) : void 0,
|
|
1955
1621
|
annotations: Transaction3.userEvent.of(stateRestoreAnnotation)
|
|
@@ -1957,12 +1623,12 @@ var createEditorStateTransaction = ({ scrollTo, selection }) => {
|
|
|
1957
1623
|
};
|
|
1958
1624
|
var createEditorStateStore = (keyPrefix) => ({
|
|
1959
1625
|
getState: (id) => {
|
|
1960
|
-
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1626
|
+
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 26, S: void 0, A: ["id", ""] });
|
|
1961
1627
|
const state = localStorage.getItem(`${keyPrefix}/${id}`);
|
|
1962
1628
|
return state ? JSON.parse(state) : void 0;
|
|
1963
1629
|
},
|
|
1964
1630
|
setState: (id, state) => {
|
|
1965
|
-
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F:
|
|
1631
|
+
invariant3(id, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file8, L: 31, S: void 0, A: ["id", ""] });
|
|
1966
1632
|
localStorage.setItem(`${keyPrefix}/${id}`, JSON.stringify(state));
|
|
1967
1633
|
}
|
|
1968
1634
|
});
|
|
@@ -1975,7 +1641,7 @@ var selectionState = ({ getState, setState } = {}) => {
|
|
|
1975
1641
|
// setStateDebounced(id, {});
|
|
1976
1642
|
// },
|
|
1977
1643
|
// }),
|
|
1978
|
-
|
|
1644
|
+
EditorView8.updateListener.of(({ view, transactions }) => {
|
|
1979
1645
|
const id = view.state.facet(documentId);
|
|
1980
1646
|
if (!id || transactions.some((tr) => tr.isUserEvent(stateRestoreAnnotation))) {
|
|
1981
1647
|
return;
|
|
@@ -2014,10 +1680,10 @@ var selectionState = ({ getState, setState } = {}) => {
|
|
|
2014
1680
|
};
|
|
2015
1681
|
|
|
2016
1682
|
// src/extensions/comments.ts
|
|
2017
|
-
var
|
|
2018
|
-
var setComments =
|
|
2019
|
-
var setSelection =
|
|
2020
|
-
var setCommentState =
|
|
1683
|
+
var __dxlog_file9 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/comments.ts";
|
|
1684
|
+
var setComments = StateEffect3.define();
|
|
1685
|
+
var setSelection = StateEffect3.define();
|
|
1686
|
+
var setCommentState = StateEffect3.define();
|
|
2021
1687
|
var commentsState = StateField3.define({
|
|
2022
1688
|
create: (state) => ({
|
|
2023
1689
|
id: state.facet(documentId),
|
|
@@ -2056,7 +1722,7 @@ var commentsState = StateField3.define({
|
|
|
2056
1722
|
return value;
|
|
2057
1723
|
}
|
|
2058
1724
|
});
|
|
2059
|
-
var styles2 =
|
|
1725
|
+
var styles2 = EditorView9.theme({
|
|
2060
1726
|
".cm-comment, .cm-comment-current": {
|
|
2061
1727
|
padding: "3px 0",
|
|
2062
1728
|
color: "var(--color-cm-comment-text)",
|
|
@@ -2077,14 +1743,14 @@ var createCommentMark = (id, isCurrent) => Decoration7.mark({
|
|
|
2077
1743
|
"data-comment-id": id
|
|
2078
1744
|
}
|
|
2079
1745
|
});
|
|
2080
|
-
var commentsDecorations =
|
|
1746
|
+
var commentsDecorations = EditorView9.decorations.compute([
|
|
2081
1747
|
commentsState
|
|
2082
1748
|
], (state) => {
|
|
2083
1749
|
const { selection: { current }, comments: comments2 } = state.field(commentsState);
|
|
2084
1750
|
const decorations2 = sortBy(comments2 ?? [], (range) => range.range.from)?.flatMap((comment) => {
|
|
2085
1751
|
const range = comment.range;
|
|
2086
1752
|
if (!range) {
|
|
2087
|
-
|
|
1753
|
+
log6.warn("Invalid range:", range, { "~LogMeta": "~LogMeta", F: __dxlog_file9, L: 93, S: void 0 });
|
|
2088
1754
|
return void 0;
|
|
2089
1755
|
} else if (range.from === range.to) {
|
|
2090
1756
|
return void 0;
|
|
@@ -2094,8 +1760,8 @@ var commentsDecorations = EditorView11.decorations.compute([
|
|
|
2094
1760
|
}).filter(isNonNullable);
|
|
2095
1761
|
return Decoration7.set(decorations2);
|
|
2096
1762
|
});
|
|
2097
|
-
var commentClickedEffect =
|
|
2098
|
-
var handleCommentClick =
|
|
1763
|
+
var commentClickedEffect = StateEffect3.define();
|
|
1764
|
+
var handleCommentClick = EditorView9.domEventHandlers({
|
|
2099
1765
|
click: (event, view) => {
|
|
2100
1766
|
let target = event.target;
|
|
2101
1767
|
const editorRoot = view.dom;
|
|
@@ -2134,7 +1800,7 @@ var trackPastedComments = (onUpdate) => {
|
|
|
2134
1800
|
}
|
|
2135
1801
|
};
|
|
2136
1802
|
return [
|
|
2137
|
-
|
|
1803
|
+
EditorView9.domEventHandlers({
|
|
2138
1804
|
cut: handleTrack,
|
|
2139
1805
|
copy: handleTrack
|
|
2140
1806
|
}),
|
|
@@ -2156,7 +1822,7 @@ var trackPastedComments = (onUpdate) => {
|
|
|
2156
1822
|
return effects;
|
|
2157
1823
|
}),
|
|
2158
1824
|
// Handle paste or the undo of comment deletion.
|
|
2159
|
-
|
|
1825
|
+
EditorView9.updateListener.of((update2) => {
|
|
2160
1826
|
const restore = [];
|
|
2161
1827
|
for (let i = 0; i < update2.transactions.length; i++) {
|
|
2162
1828
|
const tr = update2.transactions[i];
|
|
@@ -2212,7 +1878,7 @@ var mapTrackedComment = (comment, changes) => ({
|
|
|
2212
1878
|
from: changes.mapPos(comment.from, 1),
|
|
2213
1879
|
to: changes.mapPos(comment.to, 1)
|
|
2214
1880
|
});
|
|
2215
|
-
var restoreCommentEffect =
|
|
1881
|
+
var restoreCommentEffect = StateEffect3.define({
|
|
2216
1882
|
map: mapTrackedComment
|
|
2217
1883
|
});
|
|
2218
1884
|
var createComment = (view) => {
|
|
@@ -2298,7 +1964,7 @@ var comments = (options = {}) => {
|
|
|
2298
1964
|
//
|
|
2299
1965
|
// Track deleted ranges and update ranges for decorations.
|
|
2300
1966
|
//
|
|
2301
|
-
|
|
1967
|
+
EditorView9.updateListener.of(({ view, state, changes }) => {
|
|
2302
1968
|
let mod = false;
|
|
2303
1969
|
const { comments: comments2, ...value } = state.field(commentsState);
|
|
2304
1970
|
changes.iterChanges((from, to, from2, to2) => {
|
|
@@ -2330,7 +1996,7 @@ var comments = (options = {}) => {
|
|
|
2330
1996
|
//
|
|
2331
1997
|
// Track selection/proximity.
|
|
2332
1998
|
//
|
|
2333
|
-
|
|
1999
|
+
EditorView9.updateListener.of(({ view, state }) => {
|
|
2334
2000
|
let min = Infinity;
|
|
2335
2001
|
const { selection: { current, closest }, comments: comments2 } = state.field(commentsState);
|
|
2336
2002
|
const { head } = state.selection.main;
|
|
@@ -2384,7 +2050,7 @@ var scrollThreadIntoView = (view, id, center = true) => {
|
|
|
2384
2050
|
anchor: range.from
|
|
2385
2051
|
} : void 0,
|
|
2386
2052
|
effects: [
|
|
2387
|
-
needsScroll ?
|
|
2053
|
+
needsScroll ? EditorView9.scrollIntoView(range.from, center ? {
|
|
2388
2054
|
y: "center"
|
|
2389
2055
|
} : void 0) : [],
|
|
2390
2056
|
needsSelectionUpdate ? setSelection.of({
|
|
@@ -2415,7 +2081,7 @@ var ExternalCommentSync = class {
|
|
|
2415
2081
|
this.unsubscribe();
|
|
2416
2082
|
};
|
|
2417
2083
|
};
|
|
2418
|
-
var createExternalCommentSync = (id, subscribe, getComments) =>
|
|
2084
|
+
var createExternalCommentSync = (id, subscribe, getComments) => ViewPlugin8.fromClass(class {
|
|
2419
2085
|
constructor(view) {
|
|
2420
2086
|
return new ExternalCommentSync(view, id, subscribe, getComments);
|
|
2421
2087
|
}
|
|
@@ -2435,12 +2101,12 @@ var debugNodeLogger = (log12 = console.log) => {
|
|
|
2435
2101
|
};
|
|
2436
2102
|
|
|
2437
2103
|
// src/extensions/dnd.ts
|
|
2438
|
-
import { EditorView as
|
|
2104
|
+
import { EditorView as EditorView10, dropCursor } from "@codemirror/view";
|
|
2439
2105
|
var dropFile = (options = {}) => {
|
|
2440
2106
|
return [
|
|
2441
2107
|
styles3,
|
|
2442
2108
|
dropCursor(),
|
|
2443
|
-
|
|
2109
|
+
EditorView10.domEventHandlers({
|
|
2444
2110
|
drop: (event, view) => {
|
|
2445
2111
|
event.preventDefault();
|
|
2446
2112
|
const files = event.dataTransfer?.files;
|
|
@@ -2459,7 +2125,7 @@ var dropFile = (options = {}) => {
|
|
|
2459
2125
|
})
|
|
2460
2126
|
];
|
|
2461
2127
|
};
|
|
2462
|
-
var styles3 =
|
|
2128
|
+
var styles3 = EditorView10.theme({
|
|
2463
2129
|
".cm-dropCursor": {
|
|
2464
2130
|
borderLeft: "2px solid var(--color-accent-text)",
|
|
2465
2131
|
color: "var(--color-accent-text)",
|
|
@@ -2481,10 +2147,10 @@ import { vscodeDarkStyle, vscodeLightStyle } from "@uiw/codemirror-theme-vscode"
|
|
|
2481
2147
|
import defaultsDeep2 from "lodash.defaultsdeep";
|
|
2482
2148
|
import { generateName } from "@dxos/display-name";
|
|
2483
2149
|
import { log as log8 } from "@dxos/log";
|
|
2484
|
-
import { hexToHue, isTruthy as
|
|
2150
|
+
import { hexToHue, isTruthy as isTruthy3 } from "@dxos/util";
|
|
2485
2151
|
|
|
2486
2152
|
// src/styles/theme.ts
|
|
2487
|
-
import { EditorView as
|
|
2153
|
+
import { EditorView as EditorView11 } from "@codemirror/view";
|
|
2488
2154
|
import { mx as mx3 } from "@dxos/ui-theme";
|
|
2489
2155
|
var headings = {
|
|
2490
2156
|
1: {
|
|
@@ -2532,7 +2198,7 @@ var markdownTheme = {
|
|
|
2532
2198
|
fontWeight: "100 !important"
|
|
2533
2199
|
})
|
|
2534
2200
|
};
|
|
2535
|
-
var baseTheme =
|
|
2201
|
+
var baseTheme = EditorView11.baseTheme({
|
|
2536
2202
|
/**
|
|
2537
2203
|
* Outer frame.
|
|
2538
2204
|
*/
|
|
@@ -2544,7 +2210,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2544
2210
|
* Scroller
|
|
2545
2211
|
*/
|
|
2546
2212
|
".cm-scroller": {
|
|
2547
|
-
// Browser scroll-anchoring: see comment in `
|
|
2213
|
+
// Browser scroll-anchoring: see comment in `scrolling/crawler.ts`. `auto` lets the browser pin a
|
|
2548
2214
|
// stable element near the viewport top so widget resizes (e.g. tool-block TogglePanel
|
|
2549
2215
|
// open/close) don't jump the user's view.
|
|
2550
2216
|
overflowAnchor: "auto"
|
|
@@ -2655,7 +2321,8 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2655
2321
|
textDecorationThickness: "1px",
|
|
2656
2322
|
textDecorationColor: "var(--color-separator)",
|
|
2657
2323
|
textUnderlineOffset: "2px",
|
|
2658
|
-
borderRadius: ".125rem"
|
|
2324
|
+
borderRadius: ".125rem",
|
|
2325
|
+
cursor: "pointer"
|
|
2659
2326
|
},
|
|
2660
2327
|
".cm-link > span": {
|
|
2661
2328
|
color: "var(--color-accent-text)"
|
|
@@ -2693,12 +2360,12 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2693
2360
|
padding: "4px"
|
|
2694
2361
|
},
|
|
2695
2362
|
".cm-tooltip.cm-tooltip-autocomplete > ul > li[aria-selected]": {
|
|
2696
|
-
background: "var(--color-
|
|
2697
|
-
color: "var(--color-base-
|
|
2363
|
+
background: "var(--color-current-surface)",
|
|
2364
|
+
color: "var(--color-base-foreground)"
|
|
2698
2365
|
},
|
|
2699
2366
|
".cm-tooltip.cm-tooltip-autocomplete > ul > completion-section": {
|
|
2700
2367
|
paddingLeft: "4px !important",
|
|
2701
|
-
color: "var(--color-base-
|
|
2368
|
+
color: "var(--color-base-foreground)"
|
|
2702
2369
|
},
|
|
2703
2370
|
/**
|
|
2704
2371
|
* Completion info.
|
|
@@ -2717,7 +2384,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2717
2384
|
padding: "0 4px"
|
|
2718
2385
|
},
|
|
2719
2386
|
".cm-completionMatchedText": {
|
|
2720
|
-
color: "var(--color-base-
|
|
2387
|
+
color: "var(--color-base-foreground)",
|
|
2721
2388
|
textDecoration: "none !important"
|
|
2722
2389
|
},
|
|
2723
2390
|
/**
|
|
@@ -2752,7 +2419,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2752
2419
|
backgroundColor: "var(--color-input-surface)"
|
|
2753
2420
|
},
|
|
2754
2421
|
".cm-panel input:focus, .cm-panel button:focus": {
|
|
2755
|
-
outline: "1px solid var(--color-
|
|
2422
|
+
outline: "1px solid var(--color-focus-ring-subtle)"
|
|
2756
2423
|
},
|
|
2757
2424
|
".cm-panel label": {
|
|
2758
2425
|
display: "inline-flex",
|
|
@@ -2765,7 +2432,7 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2765
2432
|
height: "8px",
|
|
2766
2433
|
marginRight: "6px !important",
|
|
2767
2434
|
padding: "2px !important",
|
|
2768
|
-
color: "var(--color-
|
|
2435
|
+
color: "var(--color-focus-ring-subtle)"
|
|
2769
2436
|
},
|
|
2770
2437
|
".cm-panel button": {
|
|
2771
2438
|
"&:hover": {
|
|
@@ -2781,14 +2448,14 @@ var baseTheme = EditorView13.baseTheme({
|
|
|
2781
2448
|
borderTop: "1px solid var(--color-separator)"
|
|
2782
2449
|
}
|
|
2783
2450
|
});
|
|
2784
|
-
var editorGutter =
|
|
2451
|
+
var editorGutter = EditorView11.theme({
|
|
2785
2452
|
".cm-gutters": {
|
|
2786
2453
|
// NOTE: Non-transparent background required to cover content if scrolling horizontally.
|
|
2787
2454
|
background: "var(--color-base-surface) !important",
|
|
2788
2455
|
paddingRight: "1rem"
|
|
2789
2456
|
}
|
|
2790
2457
|
});
|
|
2791
|
-
var createFontTheme = ({ monospace } = {}) =>
|
|
2458
|
+
var createFontTheme = ({ monospace } = {}) => EditorView11.theme({
|
|
2792
2459
|
// Main content.
|
|
2793
2460
|
".cm-scroller": {
|
|
2794
2461
|
fontFamily: monospace ? fontMono : fontBody
|
|
@@ -2801,9 +2468,9 @@ var createFontTheme = ({ monospace } = {}) => EditorView13.theme({
|
|
|
2801
2468
|
});
|
|
2802
2469
|
|
|
2803
2470
|
// src/extensions/focus.ts
|
|
2804
|
-
import { StateEffect as
|
|
2805
|
-
import { EditorView as
|
|
2806
|
-
var focusEffect =
|
|
2471
|
+
import { StateEffect as StateEffect4, StateField as StateField5 } from "@codemirror/state";
|
|
2472
|
+
import { EditorView as EditorView12 } from "@codemirror/view";
|
|
2473
|
+
var focusEffect = StateEffect4.define();
|
|
2807
2474
|
var focusField = StateField5.define({
|
|
2808
2475
|
create: () => false,
|
|
2809
2476
|
update: (value, tr) => {
|
|
@@ -2812,38 +2479,381 @@ var focusField = StateField5.define({
|
|
|
2812
2479
|
return effect.value;
|
|
2813
2480
|
}
|
|
2814
2481
|
}
|
|
2815
|
-
return value;
|
|
2482
|
+
return value;
|
|
2483
|
+
}
|
|
2484
|
+
});
|
|
2485
|
+
var focus = [
|
|
2486
|
+
focusField,
|
|
2487
|
+
EditorView12.domEventHandlers({
|
|
2488
|
+
focus: (_event, view) => {
|
|
2489
|
+
requestAnimationFrame(() => view.dispatch({
|
|
2490
|
+
effects: focusEffect.of(true)
|
|
2491
|
+
}));
|
|
2492
|
+
},
|
|
2493
|
+
blur: (_event, view) => {
|
|
2494
|
+
requestAnimationFrame(() => view.dispatch({
|
|
2495
|
+
effects: focusEffect.of(false)
|
|
2496
|
+
}));
|
|
2497
|
+
}
|
|
2498
|
+
})
|
|
2499
|
+
];
|
|
2500
|
+
|
|
2501
|
+
// src/extensions/scrolling/auto-scroll.ts
|
|
2502
|
+
import { StateEffect as StateEffect6 } from "@codemirror/state";
|
|
2503
|
+
import { EditorView as EditorView14, ViewPlugin as ViewPlugin10 } from "@codemirror/view";
|
|
2504
|
+
import { addEventListener, combine, throttle as throttle2 } from "@dxos/async";
|
|
2505
|
+
import { Domino } from "@dxos/ui";
|
|
2506
|
+
import { getSize } from "@dxos/ui-theme";
|
|
2507
|
+
|
|
2508
|
+
// src/extensions/scrolling/crawler.ts
|
|
2509
|
+
import { StateEffect as StateEffect5 } from "@codemirror/state";
|
|
2510
|
+
import { EditorView as EditorView13, ViewPlugin as ViewPlugin9 } from "@codemirror/view";
|
|
2511
|
+
import { log as log7 } from "@dxos/log";
|
|
2512
|
+
var __dxlog_file10 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/scrolling/crawler.ts";
|
|
2513
|
+
var crawlerLineEffect = StateEffect5.define();
|
|
2514
|
+
var crawlerActiveEffect = StateEffect5.define();
|
|
2515
|
+
var scrollToLine = (view, options) => {
|
|
2516
|
+
view.dispatch({
|
|
2517
|
+
effects: crawlerLineEffect.of(options)
|
|
2518
|
+
});
|
|
2519
|
+
};
|
|
2520
|
+
var crawler = ({ overScroll = 0 } = {}) => {
|
|
2521
|
+
const crawlerPlugin = ViewPlugin9.fromClass(class CrawlerPlugin {
|
|
2522
|
+
view;
|
|
2523
|
+
crawler;
|
|
2524
|
+
constructor(view) {
|
|
2525
|
+
this.view = view;
|
|
2526
|
+
this.crawler = createCrawler(this.view);
|
|
2527
|
+
}
|
|
2528
|
+
// No-op.
|
|
2529
|
+
destroy() {
|
|
2530
|
+
this.crawler.cancel();
|
|
2531
|
+
}
|
|
2532
|
+
cancel() {
|
|
2533
|
+
this.crawler.cancel();
|
|
2534
|
+
}
|
|
2535
|
+
crawl(start = false) {
|
|
2536
|
+
if (start) {
|
|
2537
|
+
this.crawler.scroll();
|
|
2538
|
+
} else {
|
|
2539
|
+
this.crawler.cancel();
|
|
2540
|
+
}
|
|
2541
|
+
}
|
|
2542
|
+
scroll({ line, offset = 0, position, behavior = "instant" }) {
|
|
2543
|
+
const { scrollTop, scrollHeight, clientHeight } = this.view.scrollDOM;
|
|
2544
|
+
const scrollerRect = this.view.scrollDOM.getBoundingClientRect();
|
|
2545
|
+
const doc = this.view.state.doc;
|
|
2546
|
+
let targetScrollTop = scrollHeight - clientHeight + offset;
|
|
2547
|
+
if (line >= 0 && line <= doc.lines - 1) {
|
|
2548
|
+
const lineStart = doc.line(line + 1).from;
|
|
2549
|
+
const coords = this.view.coordsAtPos(lineStart);
|
|
2550
|
+
if (coords) {
|
|
2551
|
+
const currentScrollTop = scrollTop;
|
|
2552
|
+
const maxScrollTop = scrollHeight - clientHeight;
|
|
2553
|
+
if (position === "end") {
|
|
2554
|
+
targetScrollTop = currentScrollTop + coords.bottom - scrollerRect.bottom + offset;
|
|
2555
|
+
} else {
|
|
2556
|
+
targetScrollTop = currentScrollTop + coords.top - scrollerRect.top + offset;
|
|
2557
|
+
}
|
|
2558
|
+
targetScrollTop = Math.max(0, Math.min(targetScrollTop, maxScrollTop));
|
|
2559
|
+
}
|
|
2560
|
+
}
|
|
2561
|
+
requestAnimationFrame(() => {
|
|
2562
|
+
this.view.scrollDOM.scrollTo({
|
|
2563
|
+
top: targetScrollTop
|
|
2564
|
+
});
|
|
2565
|
+
});
|
|
2566
|
+
}
|
|
2567
|
+
});
|
|
2568
|
+
return [
|
|
2569
|
+
crawlerPlugin,
|
|
2570
|
+
// Listen for effect.
|
|
2571
|
+
EditorView13.updateListener.of((update2) => {
|
|
2572
|
+
update2.transactions.forEach((transaction) => {
|
|
2573
|
+
try {
|
|
2574
|
+
const plugin = update2.view.plugin(crawlerPlugin);
|
|
2575
|
+
if (plugin) {
|
|
2576
|
+
for (const effect of transaction.effects) {
|
|
2577
|
+
if (effect.is(crawlerActiveEffect)) {
|
|
2578
|
+
plugin.crawl(effect.value);
|
|
2579
|
+
} else if (effect.is(crawlerLineEffect)) {
|
|
2580
|
+
plugin.scroll(effect.value);
|
|
2581
|
+
}
|
|
2582
|
+
}
|
|
2583
|
+
}
|
|
2584
|
+
} catch (err) {
|
|
2585
|
+
log7.catch(err, void 0, { "~LogMeta": "~LogMeta", F: __dxlog_file10, L: 98, S: void 0 });
|
|
2586
|
+
}
|
|
2587
|
+
});
|
|
2588
|
+
}),
|
|
2589
|
+
// Styles.
|
|
2590
|
+
EditorView13.theme({
|
|
2591
|
+
".cm-scroller": {
|
|
2592
|
+
overflowY: "scroll",
|
|
2593
|
+
// Browser scroll-anchoring: when widgets above the viewport resize (e.g. tool blocks
|
|
2594
|
+
// expanding their TogglePanel), the browser picks a stable element near the viewport
|
|
2595
|
+
// top and adjusts `scrollTop` so the user's view doesn't jump. Auto-scroll's pinning
|
|
2596
|
+
// logic still has the final word when pinned (forces scrollTop to scrollHeight).
|
|
2597
|
+
overflowAnchor: "auto"
|
|
2598
|
+
},
|
|
2599
|
+
".cm-scroller.cm-hide-scrollbar::-webkit-scrollbar": {
|
|
2600
|
+
display: "none"
|
|
2601
|
+
},
|
|
2602
|
+
".cm-scroller::-webkit-scrollbar-thumb": {
|
|
2603
|
+
background: "transparent",
|
|
2604
|
+
transition: "background 0.15s"
|
|
2605
|
+
},
|
|
2606
|
+
"&:hover .cm-scroller::-webkit-scrollbar-thumb": {
|
|
2607
|
+
background: "var(--color-scrollbar-thumb)"
|
|
2608
|
+
},
|
|
2609
|
+
// Spacer below the last text line. Implemented as a real block pseudo-element
|
|
2610
|
+
// (rather than `padding-bottom` on `.cm-content`) so it materializes in the
|
|
2611
|
+
// scroller's `scrollHeight` regardless of how `padding` is reset by the base
|
|
2612
|
+
// theme or downstream classes — this is what gives auto-scroll its head-room
|
|
2613
|
+
// so the last line stays `overScroll` px above the viewport bottom.
|
|
2614
|
+
".cm-content::after": {
|
|
2615
|
+
content: '""',
|
|
2616
|
+
display: "block",
|
|
2617
|
+
height: `${overScroll}px`
|
|
2618
|
+
},
|
|
2619
|
+
".cm-scroll-button": {
|
|
2620
|
+
position: "absolute",
|
|
2621
|
+
bottom: "0.5rem",
|
|
2622
|
+
right: "1rem"
|
|
2623
|
+
}
|
|
2624
|
+
})
|
|
2625
|
+
];
|
|
2626
|
+
};
|
|
2627
|
+
function createCrawler(view, omega = 5, snapThreshold = 5, snapVelocity = 50) {
|
|
2628
|
+
const el = view.scrollDOM;
|
|
2629
|
+
let currentTop = 0;
|
|
2630
|
+
let velocity = 0;
|
|
2631
|
+
let rafId = null;
|
|
2632
|
+
let lastTime = 0;
|
|
2633
|
+
function frame(now) {
|
|
2634
|
+
const dt = lastTime === 0 ? 1 / 60 : Math.min(0.1, (now - lastTime) / 1e3);
|
|
2635
|
+
lastTime = now;
|
|
2636
|
+
const targetTop = el.scrollHeight - el.clientHeight;
|
|
2637
|
+
const delta = targetTop - currentTop;
|
|
2638
|
+
if (Math.abs(delta) < snapThreshold && Math.abs(velocity) < snapVelocity) {
|
|
2639
|
+
el.scrollTop = targetTop;
|
|
2640
|
+
currentTop = targetTop;
|
|
2641
|
+
velocity = 0;
|
|
2642
|
+
rafId = null;
|
|
2643
|
+
lastTime = 0;
|
|
2644
|
+
return;
|
|
2645
|
+
}
|
|
2646
|
+
const accel = omega * omega * delta - 2 * omega * velocity;
|
|
2647
|
+
velocity += accel * dt;
|
|
2648
|
+
currentTop += velocity * dt;
|
|
2649
|
+
el.scrollTop = currentTop;
|
|
2650
|
+
rafId = requestAnimationFrame(frame);
|
|
2816
2651
|
}
|
|
2817
|
-
|
|
2818
|
-
|
|
2819
|
-
|
|
2820
|
-
|
|
2821
|
-
|
|
2822
|
-
|
|
2823
|
-
|
|
2824
|
-
}));
|
|
2652
|
+
return {
|
|
2653
|
+
scroll: () => {
|
|
2654
|
+
if (rafId === null) {
|
|
2655
|
+
currentTop = el.scrollTop;
|
|
2656
|
+
lastTime = 0;
|
|
2657
|
+
rafId = requestAnimationFrame(frame);
|
|
2658
|
+
}
|
|
2825
2659
|
},
|
|
2826
|
-
|
|
2827
|
-
|
|
2828
|
-
|
|
2829
|
-
|
|
2660
|
+
cancel: () => {
|
|
2661
|
+
if (rafId !== null) {
|
|
2662
|
+
cancelAnimationFrame(rafId);
|
|
2663
|
+
velocity = 0;
|
|
2664
|
+
lastTime = 0;
|
|
2665
|
+
rafId = null;
|
|
2666
|
+
}
|
|
2830
2667
|
}
|
|
2831
|
-
}
|
|
2832
|
-
|
|
2668
|
+
};
|
|
2669
|
+
}
|
|
2670
|
+
|
|
2671
|
+
// src/extensions/scrolling/auto-scroll.ts
|
|
2672
|
+
var autoScrollEffect = StateEffect6.define();
|
|
2673
|
+
var autoScroll = ({ scrollOnResize = true } = {}) => {
|
|
2674
|
+
let buttonContainer;
|
|
2675
|
+
let isPinned = true;
|
|
2676
|
+
let jumpPending = false;
|
|
2677
|
+
let enabled = true;
|
|
2678
|
+
let firstUpdate = true;
|
|
2679
|
+
const setPinned = (pinned) => {
|
|
2680
|
+
buttonContainer?.classList.toggle("opacity-0", pinned);
|
|
2681
|
+
isPinned = pinned;
|
|
2682
|
+
};
|
|
2683
|
+
return [
|
|
2684
|
+
// Update listener for scrolling when content changes.
|
|
2685
|
+
EditorView14.updateListener.of((update2) => {
|
|
2686
|
+
const { view, heightChanged, state, startState } = update2;
|
|
2687
|
+
for (const tr of update2.transactions) {
|
|
2688
|
+
for (const effect of tr.effects) {
|
|
2689
|
+
if (effect.is(autoScrollEffect)) {
|
|
2690
|
+
enabled = effect.value;
|
|
2691
|
+
if (enabled) {
|
|
2692
|
+
setPinned(true);
|
|
2693
|
+
view.dispatch({
|
|
2694
|
+
effects: crawlerActiveEffect.of(true)
|
|
2695
|
+
});
|
|
2696
|
+
} else {
|
|
2697
|
+
view.dispatch({
|
|
2698
|
+
effects: crawlerActiveEffect.of(false)
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
}
|
|
2702
|
+
}
|
|
2703
|
+
}
|
|
2704
|
+
if (!enabled) {
|
|
2705
|
+
return;
|
|
2706
|
+
}
|
|
2707
|
+
if (isPinned && (firstUpdate || startState.doc.length === 0) && state.doc.length > 0) {
|
|
2708
|
+
firstUpdate = false;
|
|
2709
|
+
jumpPending = true;
|
|
2710
|
+
requestAnimationFrame(() => {
|
|
2711
|
+
view.scrollDOM.scrollTop = view.scrollDOM.scrollHeight;
|
|
2712
|
+
jumpPending = false;
|
|
2713
|
+
});
|
|
2714
|
+
return;
|
|
2715
|
+
}
|
|
2716
|
+
firstUpdate = false;
|
|
2717
|
+
if (jumpPending) {
|
|
2718
|
+
return;
|
|
2719
|
+
}
|
|
2720
|
+
if (heightChanged) {
|
|
2721
|
+
if (isPinned) {
|
|
2722
|
+
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
2723
|
+
const delta = scrollHeight - scrollTop - clientHeight;
|
|
2724
|
+
if (delta > 0) {
|
|
2725
|
+
setPinned(true);
|
|
2726
|
+
view.dispatch({
|
|
2727
|
+
effects: crawlerActiveEffect.of(true)
|
|
2728
|
+
});
|
|
2729
|
+
} else if (delta < -1) {
|
|
2730
|
+
setPinned(false);
|
|
2731
|
+
}
|
|
2732
|
+
} else {
|
|
2733
|
+
if (state.doc.length === 0) {
|
|
2734
|
+
setPinned(true);
|
|
2735
|
+
}
|
|
2736
|
+
}
|
|
2737
|
+
}
|
|
2738
|
+
}),
|
|
2739
|
+
// Re-pin and jump to bottom when the scroll container itself resizes (e.g. sidebar toggle,
|
|
2740
|
+
// window resize). Doc-driven height changes are handled by the updateListener above; this
|
|
2741
|
+
// observer covers the case where the viewport changes while the doc length is unchanged.
|
|
2742
|
+
scrollOnResize ? ViewPlugin10.fromClass(class {
|
|
2743
|
+
observer;
|
|
2744
|
+
firstObservation = true;
|
|
2745
|
+
destroyed = false;
|
|
2746
|
+
constructor(view) {
|
|
2747
|
+
const onResize = throttle2(() => {
|
|
2748
|
+
if (this.destroyed || !enabled) {
|
|
2749
|
+
return;
|
|
2750
|
+
}
|
|
2751
|
+
setPinned(true);
|
|
2752
|
+
requestAnimationFrame(() => {
|
|
2753
|
+
if (this.destroyed) {
|
|
2754
|
+
return;
|
|
2755
|
+
}
|
|
2756
|
+
view.scrollDOM.scrollTo({
|
|
2757
|
+
top: view.scrollDOM.scrollHeight,
|
|
2758
|
+
behavior: "instant"
|
|
2759
|
+
});
|
|
2760
|
+
view.dispatch({
|
|
2761
|
+
effects: crawlerActiveEffect.of(false)
|
|
2762
|
+
});
|
|
2763
|
+
});
|
|
2764
|
+
}, 50);
|
|
2765
|
+
this.observer = new ResizeObserver(() => {
|
|
2766
|
+
if (this.firstObservation) {
|
|
2767
|
+
this.firstObservation = false;
|
|
2768
|
+
return;
|
|
2769
|
+
}
|
|
2770
|
+
onResize();
|
|
2771
|
+
});
|
|
2772
|
+
this.observer.observe(view.scrollDOM);
|
|
2773
|
+
}
|
|
2774
|
+
destroy() {
|
|
2775
|
+
this.destroyed = true;
|
|
2776
|
+
this.observer.disconnect();
|
|
2777
|
+
}
|
|
2778
|
+
}) : [],
|
|
2779
|
+
// Detect user scroll and unpin (or re-pin if scrolled to the bottom).
|
|
2780
|
+
ViewPlugin10.fromClass(class {
|
|
2781
|
+
cleanup;
|
|
2782
|
+
constructor(view) {
|
|
2783
|
+
const onUserScroll = throttle2(() => {
|
|
2784
|
+
requestAnimationFrame(() => {
|
|
2785
|
+
const { scrollTop, scrollHeight, clientHeight } = view.scrollDOM;
|
|
2786
|
+
const delta = scrollHeight - scrollTop - clientHeight;
|
|
2787
|
+
const pinned = Math.abs(delta) <= 1;
|
|
2788
|
+
setPinned(pinned);
|
|
2789
|
+
if (!pinned) {
|
|
2790
|
+
view.dispatch({
|
|
2791
|
+
effects: crawlerActiveEffect.of(false)
|
|
2792
|
+
});
|
|
2793
|
+
}
|
|
2794
|
+
});
|
|
2795
|
+
}, 500);
|
|
2796
|
+
this.cleanup = createUserScrollDetector(view.scrollDOM, () => {
|
|
2797
|
+
if (isPinned) {
|
|
2798
|
+
setPinned(false);
|
|
2799
|
+
view.dispatch({
|
|
2800
|
+
effects: crawlerActiveEffect.of(false)
|
|
2801
|
+
});
|
|
2802
|
+
}
|
|
2803
|
+
onUserScroll();
|
|
2804
|
+
});
|
|
2805
|
+
}
|
|
2806
|
+
destroy() {
|
|
2807
|
+
this.cleanup();
|
|
2808
|
+
}
|
|
2809
|
+
}),
|
|
2810
|
+
// Scroll button.
|
|
2811
|
+
ViewPlugin10.fromClass(class {
|
|
2812
|
+
constructor(view) {
|
|
2813
|
+
const icon = Domino.of("dx-icon").classNames(getSize(4)).attributes({
|
|
2814
|
+
icon: "ph--arrow-down--regular"
|
|
2815
|
+
});
|
|
2816
|
+
const button = Domino.of("button").classNames("dx-button bg-accent-surface").attributes({
|
|
2817
|
+
"data-density": "fine"
|
|
2818
|
+
}).append(icon).on("click", () => {
|
|
2819
|
+
setPinned(true);
|
|
2820
|
+
view.dispatch({
|
|
2821
|
+
effects: crawlerLineEffect.of({
|
|
2822
|
+
line: -1,
|
|
2823
|
+
position: "end",
|
|
2824
|
+
behavior: "smooth"
|
|
2825
|
+
})
|
|
2826
|
+
});
|
|
2827
|
+
});
|
|
2828
|
+
buttonContainer = Domino.of("div").classNames("cm-scroll-button transition-opacity duration-300 opacity-0").append(button).root;
|
|
2829
|
+
view.scrollDOM.parentElement.appendChild(buttonContainer);
|
|
2830
|
+
}
|
|
2831
|
+
})
|
|
2832
|
+
];
|
|
2833
|
+
};
|
|
2834
|
+
function createUserScrollDetector(element, onUserScroll) {
|
|
2835
|
+
return combine(addEventListener(element, "wheel", () => onUserScroll(), {
|
|
2836
|
+
passive: true
|
|
2837
|
+
}), addEventListener(element, "pointerdown", (event) => {
|
|
2838
|
+
if (event.clientX > element.getBoundingClientRect().right - (element.offsetWidth - element.clientWidth)) {
|
|
2839
|
+
onUserScroll();
|
|
2840
|
+
}
|
|
2841
|
+
}));
|
|
2842
|
+
}
|
|
2833
2843
|
|
|
2834
|
-
// src/extensions/scroll-past-end.ts
|
|
2844
|
+
// src/extensions/scrolling/scroll-past-end.ts
|
|
2835
2845
|
import { EditorView as EditorView15, ViewPlugin as ViewPlugin11 } from "@codemirror/view";
|
|
2836
2846
|
var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
|
|
2837
|
-
|
|
2838
|
-
|
|
2839
|
-
style:
|
|
2847
|
+
_height = 1e3;
|
|
2848
|
+
_attrs = {
|
|
2849
|
+
style: `padding-bottom: ${this._height}px`
|
|
2840
2850
|
};
|
|
2841
2851
|
update({ view }) {
|
|
2842
2852
|
const lastLineBlock = view.lineBlockAt(view.state.doc.length);
|
|
2843
2853
|
const height = view.dom.clientHeight - lastLineBlock.height - view.documentPadding.top - 0.5;
|
|
2844
|
-
if (height >= 0 && height !== this.
|
|
2845
|
-
this.
|
|
2846
|
-
this.
|
|
2854
|
+
if (height >= 0 && height !== this._height) {
|
|
2855
|
+
this._height = height;
|
|
2856
|
+
this._attrs = {
|
|
2847
2857
|
style: `padding-bottom: ${height}px`
|
|
2848
2858
|
};
|
|
2849
2859
|
}
|
|
@@ -2851,9 +2861,22 @@ var scrollPastEndPlugin = ViewPlugin11.fromClass(class {
|
|
|
2851
2861
|
});
|
|
2852
2862
|
var scrollPastEnd = () => [
|
|
2853
2863
|
scrollPastEndPlugin,
|
|
2854
|
-
EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?.
|
|
2864
|
+
EditorView15.contentAttributes.of((view) => view.plugin(scrollPastEndPlugin)?._attrs ?? null)
|
|
2855
2865
|
];
|
|
2856
2866
|
|
|
2867
|
+
// src/extensions/scrolling/scroller.ts
|
|
2868
|
+
import { isTruthy as isTruthy2 } from "@dxos/util";
|
|
2869
|
+
var scroller = ({ overScroll, scrollOnResize, autoScroll: autoScroll2 = true } = {}) => {
|
|
2870
|
+
return [
|
|
2871
|
+
crawler({
|
|
2872
|
+
overScroll
|
|
2873
|
+
}),
|
|
2874
|
+
autoScroll2 && autoScroll({
|
|
2875
|
+
scrollOnResize
|
|
2876
|
+
})
|
|
2877
|
+
].filter(isTruthy2);
|
|
2878
|
+
};
|
|
2879
|
+
|
|
2857
2880
|
// src/extensions/factories.ts
|
|
2858
2881
|
var __dxlog_file11 = "/__w/dxos/dxos/packages/ui/ui-editor/src/extensions/factories.ts";
|
|
2859
2882
|
var tabbable = EditorView16.contentAttributes.of({
|
|
@@ -2961,8 +2984,8 @@ var createBasicExtensions = (propsProp) => {
|
|
|
2961
2984
|
preventDefault: true,
|
|
2962
2985
|
run: () => true
|
|
2963
2986
|
}
|
|
2964
|
-
].filter(
|
|
2965
|
-
].filter(
|
|
2987
|
+
].filter(isTruthy3))
|
|
2988
|
+
].filter(isTruthy3);
|
|
2966
2989
|
};
|
|
2967
2990
|
var grow = {
|
|
2968
2991
|
editor: {
|
|
@@ -3004,7 +3027,7 @@ var createThemeExtensions = ({ monospace, scrollbarThin, slots: slotsProp, synta
|
|
|
3004
3027
|
}
|
|
3005
3028
|
}
|
|
3006
3029
|
})
|
|
3007
|
-
].filter(
|
|
3030
|
+
].filter(isTruthy3);
|
|
3008
3031
|
};
|
|
3009
3032
|
var createDataExtensions = ({ id, text, messenger, identity }) => {
|
|
3010
3033
|
const extensions = [];
|
|
@@ -4328,7 +4351,7 @@ import { markdown, markdownLanguage as markdownLanguage2 } from "@codemirror/lan
|
|
|
4328
4351
|
import { foldNodeProp, syntaxHighlighting as syntaxHighlighting2 } from "@codemirror/language";
|
|
4329
4352
|
import { languages } from "@codemirror/language-data";
|
|
4330
4353
|
import { keymap as keymap9 } from "@codemirror/view";
|
|
4331
|
-
import { isTruthy as
|
|
4354
|
+
import { isTruthy as isTruthy4 } from "@dxos/util";
|
|
4332
4355
|
|
|
4333
4356
|
// src/extensions/markdown/highlight.ts
|
|
4334
4357
|
import { markdownLanguage } from "@codemirror/lang-markdown";
|
|
@@ -4560,7 +4583,7 @@ var createMarkdownExtensions = (options = {}) => {
|
|
|
4560
4583
|
...defaultKeymap2,
|
|
4561
4584
|
// TODO(burdon): Remove?
|
|
4562
4585
|
...completionKeymap
|
|
4563
|
-
].filter(
|
|
4586
|
+
].filter(isTruthy4))
|
|
4564
4587
|
];
|
|
4565
4588
|
};
|
|
4566
4589
|
var noFencedCodeFolding = {
|
|
@@ -6641,7 +6664,7 @@ var decorations = () => [
|
|
|
6641
6664
|
marginBottom: "2px"
|
|
6642
6665
|
},
|
|
6643
6666
|
".cm-list-item-focused": {
|
|
6644
|
-
borderColor: "var(--color-
|
|
6667
|
+
borderColor: "var(--color-focus-ring-subtle)"
|
|
6645
6668
|
},
|
|
6646
6669
|
"&:focus-within .cm-list-item-selected": {
|
|
6647
6670
|
borderColor: "var(--color-separator)"
|
|
@@ -7880,7 +7903,7 @@ var xmlFormatting = ({ skip } = {}) => {
|
|
|
7880
7903
|
}),
|
|
7881
7904
|
EditorView31.baseTheme({
|
|
7882
7905
|
".cm-xml-element": {
|
|
7883
|
-
backgroundColor: "var(--color-
|
|
7906
|
+
backgroundColor: "var(--color-current-surface)",
|
|
7884
7907
|
borderRadius: "0.25rem",
|
|
7885
7908
|
padding: "0.25rem"
|
|
7886
7909
|
},
|
|
@@ -8141,7 +8164,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
|
|
|
8141
8164
|
anchor: line.from,
|
|
8142
8165
|
head: line.from
|
|
8143
8166
|
},
|
|
8144
|
-
effects:
|
|
8167
|
+
effects: crawlerLineEffect.of({
|
|
8145
8168
|
line: line.number - 1,
|
|
8146
8169
|
offset: -16
|
|
8147
8170
|
})
|
|
@@ -8174,7 +8197,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
|
|
|
8174
8197
|
anchor: line.to,
|
|
8175
8198
|
head: line.to
|
|
8176
8199
|
},
|
|
8177
|
-
effects:
|
|
8200
|
+
effects: crawlerLineEffect.of({
|
|
8178
8201
|
line: line.number - 1,
|
|
8179
8202
|
offset: -16
|
|
8180
8203
|
})
|
|
@@ -8186,7 +8209,7 @@ var createNavigationEffectPlugin = (widgetDecorationsField, bookmarks2) => {
|
|
|
8186
8209
|
anchor: line.to,
|
|
8187
8210
|
head: line.to
|
|
8188
8211
|
},
|
|
8189
|
-
effects:
|
|
8212
|
+
effects: crawlerLineEffect.of({
|
|
8190
8213
|
line: line.number - 1,
|
|
8191
8214
|
position: "end"
|
|
8192
8215
|
})
|
|
@@ -8505,6 +8528,9 @@ export {
|
|
|
8505
8528
|
commentsState,
|
|
8506
8529
|
compactSlots,
|
|
8507
8530
|
convertTreeToJson,
|
|
8531
|
+
crawler,
|
|
8532
|
+
crawlerActiveEffect,
|
|
8533
|
+
crawlerLineEffect,
|
|
8508
8534
|
createBasicExtensions,
|
|
8509
8535
|
createComment,
|
|
8510
8536
|
createCrawler,
|
|
@@ -8592,8 +8618,6 @@ export {
|
|
|
8592
8618
|
scrollThreadIntoView,
|
|
8593
8619
|
scrollToLine,
|
|
8594
8620
|
scroller,
|
|
8595
|
-
scrollerCrawlEffect,
|
|
8596
|
-
scrollerLineEffect,
|
|
8597
8621
|
selectionState,
|
|
8598
8622
|
setBlockquote,
|
|
8599
8623
|
setComments,
|