UNPKG

@yamada-ui/react

Version:

React UI components of the Yamada, by the Yamada, for the Yamada built with React and Emotion

187 lines (183 loc) 4.96 kB
"use client"; import { assignRef, useCallbackRef } from "../../utils/ref.js"; import { useEnvironment } from "../../core/system/environment-provider.js"; import { useCallback, useEffect, useMemo, useRef, useState } from "react"; //#region src/components/infinite-scroll-area/use-infinite-scroll.ts const isScrollable = (el, vertical) => { const style = getComputedStyle(el); if ([ "auto", "overlay", "scroll" ].includes(style.overflow)) return true; if (vertical) return [ "auto", "overlay", "scroll" ].includes(style.overflowY); else return [ "auto", "overlay", "scroll" ].includes(style.overflowX); }; /** * `useInfiniteScroll` is a custom hook for providing infinite scroll functionality. * * @see https://yamada-ui.com/docs/hooks/use-infinite-scroll */ const useInfiniteScroll = ({ behavior, disabled = false, indexRef: indexRefProp, initialLoad = false, orientation = "vertical", resetRef, reverse = false, rootMargin, rootRef, startIndex = initialLoad ? 0 : 1, threshold, onLoad: onLoadProp } = {}) => { const ref = useRef(null); const { getDocument, getWindow } = useEnvironment(); const indexRef = useRef(startIndex); const processingRef = useRef(false); const observerRef = useRef(void 0); const [finish, setFinish] = useState(false); const onLoad = useCallbackRef(onLoadProp); const vertical = orientation === "vertical"; const direction = vertical ? "top" : "left"; const options = useMemo(() => { return { root: rootRef?.current, rootMargin, threshold }; }, [ rootMargin, rootRef, threshold ]); const onReset = useCallback((index = 1, runScroll = true) => { indexRef.current = index; setFinish(false); if (runScroll) { const root = rootRef?.current; const body = getDocument()?.body; const el = root && isScrollable(root, vertical) ? root : body; if (el) { const target = el === body ? getWindow() : el; const position = reverse ? vertical ? el.scrollHeight : el.scrollWidth : 0; target?.scrollTo({ behavior, [direction]: position }); } } if (disabled) return; setTimeout(() => { const observer = observerRef.current; const el = ref.current; if (el) observer?.observe(el); }); }, [ disabled, rootRef, getDocument, vertical, getWindow, reverse, behavior, direction ]); const onFinish = useCallback(() => { const observer = observerRef.current; const el = ref.current; if (el) observer?.unobserve(el); setFinish(true); }, []); const createObserver = useCallback(() => { return new IntersectionObserver(async ([entry]) => { const root = rootRef?.current; const body = getDocument()?.body; const el = root && isScrollable(root, vertical) ? root : body; if (!entry?.isIntersecting || processingRef.current || !el) return; const props = { entry, finish: onFinish, index: indexRef.current }; processingRef.current = true; if (root) root.ariaBusy = "true"; let prevScrollPosition = 0; if (reverse) prevScrollPosition = vertical ? el.scrollHeight : el.scrollWidth; await onLoad(props); if (reverse) setTimeout(() => { const target = el === body ? getWindow() : el; const position = (vertical ? el.scrollHeight : el.scrollWidth) - prevScrollPosition; target?.scrollTo({ [direction]: position }); }); indexRef.current += 1; processingRef.current = false; if (root) root.ariaBusy = "false"; }, options); }, [ options, rootRef, getDocument, vertical, onFinish, reverse, onLoad, getWindow, direction ]); useEffect(() => { const setupObserver = async () => { const el = ref.current; const index = indexRef.current; const root = rootRef?.current; if (initialLoad) { processingRef.current = true; if (root) root.ariaBusy = "true"; await onLoad({ finish: onFinish, index }); indexRef.current += 1; processingRef.current = false; if (root) root.ariaBusy = "false"; } if (disabled) return; observerRef.current = createObserver(); const observer = observerRef.current; if (reverse) { const root$1 = rootRef?.current; const body = getDocument()?.body; const el$1 = root$1 && isScrollable(root$1, vertical) ? root$1 : body; if (el$1) { const target = el$1 === body ? getWindow() : el$1; const position = vertical ? el$1.scrollHeight : el$1.scrollWidth; target?.scrollTo({ [direction]: position }); } } setTimeout(() => { if (el) observer.observe(el); }); return () => { if (el) observer.unobserve(el); }; }; setupObserver(); }, [ createObserver, initialLoad, disabled, reverse, vertical, onFinish, onLoad, rootRef, getDocument, getWindow, direction ]); assignRef(resetRef, onReset); assignRef(indexRefProp, (index) => indexRef.current = index); return { ref, finish }; }; //#endregion export { useInfiniteScroll }; //# sourceMappingURL=use-infinite-scroll.js.map