@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
JavaScript
"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