stream-chat-react
Version:
React components to create chat conversations or livestream style chat
75 lines (74 loc) • 3.02 kB
JavaScript
import clsx from 'clsx';
import debounce from 'lodash.debounce';
import React, { useEffect, useMemo, useRef } from 'react';
import { DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD } from '../../constants/limits';
/**
* Prevents Chrome hangups
* See: https://stackoverflow.com/questions/47524205/random-high-content-download-time-in-chrome/47684257#47684257
*/
const mousewheelListener = (event) => {
if (event instanceof WheelEvent && event.deltaY === 1) {
event.preventDefault();
}
};
export const InfiniteScrollPaginator = (props) => {
const { children, className, listenToScroll, loadNextDebounceMs = 500, loadNextOnScrollToBottom, loadNextOnScrollToTop, threshold = DEFAULT_LOAD_PAGE_SCROLL_THRESHOLD, useCapture = false, ...componentProps } = props;
const rootRef = useRef(null);
const childRef = useRef(null);
const scrollListener = useMemo(() => debounce(() => {
const root = rootRef.current;
const child = childRef.current;
if (!root || root.offsetParent === null || !child) {
return;
}
const distanceFromBottom = child.scrollHeight - root.scrollTop - root.clientHeight;
const distanceFromTop = root.scrollTop;
if (listenToScroll) {
listenToScroll(distanceFromBottom, distanceFromTop, threshold);
}
if (distanceFromTop < Number(threshold)) {
loadNextOnScrollToTop?.();
}
if (distanceFromBottom < Number(threshold)) {
loadNextOnScrollToBottom?.();
}
}, loadNextDebounceMs), [
listenToScroll,
loadNextDebounceMs,
loadNextOnScrollToBottom,
loadNextOnScrollToTop,
threshold,
]);
useEffect(() => {
const scrollElement = rootRef.current;
if (!scrollElement)
return;
scrollElement.addEventListener('scroll', scrollListener, useCapture);
return () => {
scrollElement.removeEventListener('scroll', scrollListener, useCapture);
};
}, [scrollListener, useCapture]);
useEffect(() => {
const root = rootRef.current;
if (!root || typeof ResizeObserver === 'undefined' || !scrollListener)
return;
const observer = new ResizeObserver(scrollListener);
observer.observe(root);
return () => {
observer.disconnect();
};
}, [scrollListener]);
useEffect(() => {
const root = rootRef.current;
if (root) {
root.addEventListener('wheel', mousewheelListener, { passive: false });
}
return () => {
if (root) {
root.removeEventListener('wheel', mousewheelListener, useCapture);
}
};
}, [useCapture]);
return (React.createElement("div", { ...componentProps, className: clsx('str-chat__infinite-scroll-paginator', className), ref: rootRef },
React.createElement("div", { className: 'str-chat__infinite-scroll-paginator__content', ref: childRef }, children)));
};