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