refactor(style): update chat layout and scrolling
This commit is contained in:
43
frontend/src/utils/autoScroll.ts
Normal file
43
frontend/src/utils/autoScroll.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
// Pin-to-bottom controller for the document scroll.
|
||||
//
|
||||
// Tracks whether the user is "near" the bottom of the page. While pinned, new
|
||||
// content (e.g. streaming tokens) scrolls the viewport to keep up. Once the
|
||||
// user scrolls up, pinning releases and updates stop forcing scroll until the
|
||||
// user returns to the bottom.
|
||||
|
||||
const PIN_THRESHOLD_PX = 80;
|
||||
|
||||
export interface AutoScroll {
|
||||
isPinned(): boolean;
|
||||
scrollToBottom(behavior?: ScrollBehavior): void;
|
||||
maybeScrollToBottom(): void;
|
||||
}
|
||||
|
||||
export function createAutoScroll(): AutoScroll {
|
||||
let pinned = true;
|
||||
|
||||
const scrollEl = () => document.scrollingElement || document.documentElement;
|
||||
const distanceFromBottom = () => {
|
||||
const el = scrollEl();
|
||||
return el.scrollHeight - el.scrollTop - el.clientHeight;
|
||||
};
|
||||
|
||||
const onScroll = () => {
|
||||
pinned = distanceFromBottom() < PIN_THRESHOLD_PX;
|
||||
};
|
||||
window.addEventListener('scroll', onScroll, { passive: true });
|
||||
|
||||
return {
|
||||
isPinned: () => pinned,
|
||||
scrollToBottom(behavior: ScrollBehavior = 'auto') {
|
||||
window.scrollTo({ top: scrollEl().scrollHeight, behavior });
|
||||
pinned = true;
|
||||
},
|
||||
maybeScrollToBottom() {
|
||||
if (!pinned) return;
|
||||
requestAnimationFrame(() => {
|
||||
window.scrollTo({ top: scrollEl().scrollHeight });
|
||||
});
|
||||
},
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user