cordis/archive/react-helper-partial.ts
2022-02-06 19:24:25 -06:00

67 lines
2.3 KiB
TypeScript

/** 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 ];
}