UNPKG

@ariakit/react-core

Version:

Ariakit React core

129 lines (126 loc) 3.77 kB
"use client"; import { Role } from "./HIN2NSI2.js"; import { CollectionItem } from "./DTXGDDAC.js"; import { forwardRef } from "./ILRXHV7V.js"; import { useForceUpdate, useId, useMergeRefs } from "./K2XTQB3X.js"; // src/collection/collection-item-offscreen.tsx import { invariant } from "@ariakit/core/utils/misc"; import { useCallback, useRef, useState } from "react"; import { jsx } from "react/jsx-runtime"; var TagName = "div"; function requestIdleCallback(callback) { if (typeof window.requestIdleCallback === "function") { return window.requestIdleCallback(callback); } callback(); return 0; } function cancelIdleCallback(id) { if (typeof window.cancelIdleCallback === "function") { window.cancelIdleCallback(id); } } function useCollectionItemOffscreen({ offscreenBehavior = "active", offscreenRoot, ...props }) { const id = useId(props.id); const [updated, forceUpdate] = useForceUpdate(); const forcedUpdatesCountRef = useRef(0); const [_active, setActive] = useState(offscreenBehavior === "active"); const active = _active || offscreenBehavior === "active"; const observerRef = useRef(null); const idleCallbackIdRef = useRef(0); const ref = useCallback( (element) => { var _a; if (!element || offscreenBehavior === "active") { cancelIdleCallback(idleCallbackIdRef.current); (_a = observerRef.current) == null ? void 0 : _a.disconnect(); return; } invariant( offscreenRoot !== void 0, process.env.NODE_ENV !== "production" && "The offscreenRoot prop must provided." ); const getOffscreenRoot = () => { if (!offscreenRoot) return null; if (typeof offscreenRoot === "function") { return offscreenRoot(element); } if ("current" in offscreenRoot) { return offscreenRoot.current; } return offscreenRoot; }; const root = getOffscreenRoot(); if (!root) { forcedUpdatesCountRef.current++; if (forcedUpdatesCountRef.current > 3) { throw new Error( "The offscreenRoot is not available. Please make sure the root element is mounted." ); } forceUpdate(); return; } if (!observerRef.current || observerRef.current.root !== root) { observerRef.current = new IntersectionObserver( ([entry]) => { cancelIdleCallback(idleCallbackIdRef.current); const isIntersecting = !!(entry == null ? void 0 : entry.isIntersecting); idleCallbackIdRef.current = requestIdleCallback(() => { if (!isIntersecting && offscreenBehavior === "lazy") return; setActive(isIntersecting); }); }, { root, rootMargin: "40%" } ); } observerRef.current.observe(element); }, [updated, offscreenBehavior, offscreenRoot] ); return { id, active, ref, "data-offscreen": !active || void 0 }; } var CollectionItem2 = forwardRef(function CollectionItem3({ offscreenBehavior, offscreenRoot, ...props }) { const { active, ref, ...rest } = useCollectionItemOffscreen({ offscreenBehavior, offscreenRoot, ...props }); const allProps = { ...rest, ...props, ref: useMergeRefs(ref, props.ref) }; if (active) { return /* @__PURE__ */ jsx(CollectionItem, { ...allProps }); } const { store, shouldRegisterItem, getItem, // @ts-expect-error This prop may come from a collection renderer. element, ...htmlProps } = allProps; const Component = Role[TagName]; return /* @__PURE__ */ jsx(Component, { ...htmlProps }); }); export { useCollectionItemOffscreen, CollectionItem2 as CollectionItem };