2022-02-07 01:24:25 +00:00
|
|
|
/** Creates useful state for an infinite scroll subscription */
|
|
|
|
export function useColumnReverseInfiniteScroll(
|
|
|
|
threshold: number,
|
|
|
|
ends: { hasMoreBelow: boolean, hasMoreAbove: boolean } | null,
|
|
|
|
loadMoreAbove: () => Promise<void>,
|
|
|
|
loadMoreBelow: () => Promise<void>,
|
|
|
|
setScrollRatio: Dispatch<SetStateAction<number>>
|
|
|
|
): [
|
|
|
|
updateCallable: (event: UIEvent<HTMLElement>) => void,
|
|
|
|
loadAboveRetry: () => Promise<void>,
|
|
|
|
loadBelowRetry: () => Promise<void>
|
|
|
|
] {
|
|
|
|
const isMounted = useIsMountedRef();
|
|
|
|
|
|
|
|
const [ loadingAbove, setLoadingAbove ] = useState<boolean>(false);
|
|
|
|
const [ loadingBelow, setLoadingBelow ] = useState<boolean>(false);
|
|
|
|
|
|
|
|
const loadAbove = useCallback(async () => {
|
|
|
|
if (loadingAbove) return;
|
|
|
|
if (!ends || !ends.hasMoreAbove) return;
|
|
|
|
setLoadingAbove(true);
|
|
|
|
await loadMoreAbove();
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
setLoadingAbove(false);
|
|
|
|
}, [ loadingAbove, loadMoreAbove, ends ]);
|
|
|
|
|
|
|
|
const loadBelow = useCallback(async () => {
|
|
|
|
if (loadingBelow) return;
|
|
|
|
if (!ends || !ends.hasMoreBelow) return;
|
|
|
|
setLoadingBelow(true);
|
|
|
|
await loadMoreBelow();
|
|
|
|
if (!isMounted.current) return;
|
|
|
|
setLoadingBelow(false);
|
|
|
|
}, [ loadingBelow, loadMoreBelow, ends ]);
|
|
|
|
|
|
|
|
const onScrollCallable = useCallback(async (event: UIEvent<HTMLElement>) => {
|
|
|
|
const scrollTop = event.currentTarget.scrollTop;
|
|
|
|
const scrollHeight = event.currentTarget.scrollHeight;
|
|
|
|
const clientHeight = event.currentTarget.clientHeight;
|
|
|
|
|
|
|
|
// WARNING
|
|
|
|
// There's likely an inconsistency between browsers on this so have fun when you're working
|
|
|
|
// on the cross-platform implementation of this
|
|
|
|
// scrollTop apparantly is negative for column-reverse divs (this actually kindof makes sense if you flip your head upside down)
|
|
|
|
// have to reverse this
|
|
|
|
// I expect this was a change with some version of chromium.
|
|
|
|
// MDN documentation issue: https://github.com/mdn/content/issues/10968
|
|
|
|
|
|
|
|
setScrollRatio(Math.abs(scrollTop / scrollHeight));
|
|
|
|
|
|
|
|
const distToTop = -(clientHeight - scrollHeight - scrollTop); // keep in mind scrollTop is negative >:]
|
|
|
|
const distToBottom = -scrollTop;
|
|
|
|
|
|
|
|
//LOG.debug(`scroll callable update. to top: ${distToTop}, to bottom: ${distToBottom}`)
|
|
|
|
|
|
|
|
if (distToTop < threshold) {
|
|
|
|
await loadAbove();
|
|
|
|
}
|
|
|
|
|
|
|
|
if (distToBottom < threshold) {
|
|
|
|
await loadBelow();
|
|
|
|
}
|
|
|
|
}, [ setScrollRatio, loadAbove, loadBelow, threshold ]);
|
|
|
|
|
|
|
|
return [ onScrollCallable, loadAbove, loadBelow ];
|
|
|
|
}
|