streaming, markdown, model selecting, and lots more
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { ref, watch, onUnmounted, type Ref } from 'vue';
|
||||
|
||||
export function useAutoScroll(elementRef: Ref<HTMLElement | null>) {
|
||||
const userIsScrollingUp = ref(false);
|
||||
const THRESHOLD = 50;
|
||||
|
||||
const isAtBottom = () => {
|
||||
const el = elementRef.value;
|
||||
if (!el) return false;
|
||||
const distanceToBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
|
||||
return distanceToBottom <= THRESHOLD;
|
||||
};
|
||||
|
||||
const scrollToBottom = (behavior: ScrollBehavior = 'auto') => {
|
||||
const el = elementRef.value;
|
||||
if (!el) return;
|
||||
el.scrollTo({
|
||||
top: el.scrollHeight,
|
||||
behavior,
|
||||
});
|
||||
};
|
||||
|
||||
const handleScroll = () => {
|
||||
const el = elementRef.value;
|
||||
if (!el) return;
|
||||
|
||||
userIsScrollingUp.value = !isAtBottom();
|
||||
};
|
||||
|
||||
let observer: MutationObserver | null = null;
|
||||
|
||||
watch(elementRef, (newEl, oldEl) => {
|
||||
if (oldEl) {
|
||||
oldEl.removeEventListener('scroll', handleScroll);
|
||||
observer?.disconnect();
|
||||
}
|
||||
|
||||
if (newEl) {
|
||||
newEl.addEventListener('scroll', handleScroll, { passive: true });
|
||||
|
||||
observer = new MutationObserver(() => {
|
||||
if (!userIsScrollingUp.value) {
|
||||
scrollToBottom();
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe(newEl, {
|
||||
childList: true,
|
||||
subtree: true,
|
||||
characterData: true
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
onUnmounted(() => {
|
||||
elementRef.value?.removeEventListener('scroll', handleScroll);
|
||||
observer?.disconnect();
|
||||
});
|
||||
|
||||
return {
|
||||
userIsScrollingUp,
|
||||
scrollToBottom,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user