| import { navigating } from "$app/stores"; |
| import { tick } from "svelte"; |
| import { get } from "svelte/store"; |
|
|
| const detachedOffset = 10; |
|
|
| |
| |
| |
| |
| export const snapScrollToBottom = (node: HTMLElement, dependency: unknown) => { |
| let prevScrollValue = node.scrollTop; |
| let isDetached = false; |
|
|
| const handleScroll = () => { |
| |
| if (node.scrollTop < prevScrollValue) { |
| isDetached = true; |
| } |
|
|
| |
| if (node.scrollTop - (node.scrollHeight - node.clientHeight) >= -detachedOffset) { |
| isDetached = false; |
| } |
|
|
| prevScrollValue = node.scrollTop; |
| }; |
|
|
| const updateScroll = async (_options: { force?: boolean } = {}) => { |
| const defaultOptions = { force: false }; |
| const options = { ...defaultOptions, ..._options }; |
| const { force } = options; |
|
|
| if (!force && isDetached && !get(navigating)) return; |
|
|
| |
| await tick(); |
|
|
| node.scrollTo({ top: node.scrollHeight }); |
| }; |
|
|
| node.addEventListener("scroll", handleScroll); |
|
|
| if (dependency) { |
| updateScroll({ force: true }); |
| } |
|
|
| return { |
| update: updateScroll, |
| destroy: () => { |
| node.removeEventListener("scroll", handleScroll); |
| }, |
| }; |
| }; |
|
|