import type React from 'react'; import type { JSX, Ref } from 'react'; import { useEffect, useState } from 'react'; import { LoadingSpinner } from '@growi/ui/dist/components'; import type { SWRInfiniteResponse } from 'swr/infinite'; type Props = { swrInifiniteResponse: SWRInfiniteResponse; children: React.ReactNode; loadingIndicator?: React.ReactNode; endingIndicator?: React.ReactNode; isReachingEnd?: boolean; offset?: number; }; const useIntersection = (): [boolean, Ref] => { const [intersecting, setIntersecting] = useState(false); const [element, setElement] = useState(); useEffect(() => { if (element != null) { const observer = new IntersectionObserver((entries) => { setIntersecting(entries[0]?.isIntersecting); }); observer.observe(element); return () => observer.unobserve(element); } return; }, [element]); return [ intersecting, (el) => { if (el != null) setElement(el); }, ]; }; const LoadingIndicator = (): JSX.Element => { return (
); }; const InfiniteScroll = (props: Props): React.ReactElement> => { const { swrInifiniteResponse: { setSize, isValidating }, children, loadingIndicator, endingIndicator, isReachingEnd, offset = 0, } = props; const [intersecting, ref] = useIntersection(); useEffect(() => { if (intersecting && !isValidating && !isReachingEnd) { setSize((size) => size + 1); } }, [setSize, intersecting, isValidating, isReachingEnd]); return ( <> {children}
{isReachingEnd ? endingIndicator : loadingIndicator || }
); }; export default InfiniteScroll;