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