{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "infinite-scroll",
  "title": "Infinite Scroll",
  "description": "infinite scroll container instead of pagination, for large lists and fetching data.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://systaliko-ui.vercel.app/r/shadcn/spinner"
  ],
  "files": [
    {
      "path": "registry/ecommerce/infinite-scroll/index.tsx",
      "content": "'use client';\nimport { Spinner } from '@/components/systaliko-ui/shadcn/spinner';\nimport {\n  AnimatePresence,\n  motion,\n  useInView,\n  UseInViewOptions,\n} from 'motion/react';\nimport React from 'react';\n\ninterface InfiniteScrollProps extends React.ComponentPropsWithRef<'div'> {\n  isPending: boolean;\n  currentItemsLength: number;\n  allItemsCount: number | null | undefined;\n  loadMore: () => void;\n}\ninterface InfiniteScrollCellProps extends React.ComponentPropsWithRef<'div'> {\n  skelton?: React.ReactNode;\n  amount?: UseInViewOptions['amount'];\n}\n\nexport function InfiniteScrollCell({\n  skelton,\n  amount,\n  children,\n  ...props\n}: InfiniteScrollCellProps) {\n  const ref = React.useRef<HTMLDivElement>(null);\n  const isInView = useInView(ref, {\n    once: true,\n    amount,\n  });\n\n  return (\n    <div ref={ref} {...props}>\n      <AnimatePresence mode=\"wait\">\n        {!isInView ? (\n          <motion.div\n            key=\"skeleton\"\n            initial={{ opacity: 1 }}\n            exit={{ opacity: 0 }}\n          >\n            {skelton}\n          </motion.div>\n        ) : (\n          <motion.div\n            key=\"content\"\n            initial={{ opacity: 0, y: 5 }}\n            animate={{ opacity: 1, y: 0 }}\n            transition={{\n              ease: 'easeOut',\n            }}\n          >\n            {children}\n          </motion.div>\n        )}\n      </AnimatePresence>\n    </div>\n  );\n}\n\nexport function InfiniteScroll({\n  currentItemsLength,\n  isPending,\n  allItemsCount,\n  loadMore,\n  children,\n  ...props\n}: InfiniteScrollProps) {\n  const ref = React.useRef<HTMLDivElement | null>(null);\n  const allLoaded = currentItemsLength === allItemsCount;\n  const hasMore = !allLoaded && currentItemsLength > 0;\n\n  React.useEffect(() => {\n    const { current } = ref;\n\n    if (isPending || allLoaded || !current) {\n      return;\n    }\n\n    const observer = new IntersectionObserver(\n      (entries) => {\n        if (entries[0].isIntersecting && !isPending && !allLoaded) {\n          loadMore();\n        }\n      },\n      { rootMargin: '0px 0px', threshold: 0 },\n    );\n\n    observer.observe(current);\n\n    return () => {\n      observer.disconnect();\n    };\n  }, [isPending, allLoaded, currentItemsLength, loadMore]);\n\n  return (\n    <div {...props}>\n      {children}\n      {isPending && hasMore && (\n        <div className=\"flex justify-center py-4\">\n          <Spinner />\n        </div>\n      )}\n      {hasMore && <div ref={ref} />}\n    </div>\n  );\n}\n",
      "type": "registry:block",
      "target": "components/systaliko-ui/infinite-scroll.tsx"
    }
  ],
  "type": "registry:block"
}