|
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); |
|
}, |
|
}; |
|
}; |
|
|