{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "virtual-list",
  "title": "Virtual List",
  "type": "registry:ui",
  "files": [
    {
      "path": "packages/registry-react/components/virtual-list/virtual-list.tsx",
      "content": "'use client'\n\nimport * as React from 'react'\nimport { useVirtualizer } from '@tanstack/react-virtual'\nimport { cn } from '@/lib/utils'\n\nexport interface VirtualListHandle {\n  scrollToOffset: (px: number) => void\n  scrollToIndex: (index: number, options?: { align?: 'start' | 'center' | 'end' }) => void\n  getVisibleRange: () => [number, number]\n}\n\nexport interface VirtualListProps<T> {\n  items: T[]\n  /** Fixed pixel size, or a measurer called per item/index. */\n  itemSize: number | ((item: T, index: number) => number)\n  height: number | string\n  overscan?: number\n  keyField?: keyof T | string\n  direction?: 'vertical' | 'horizontal'\n  className?: string\n  /** Render-prop for each row. */\n  children: (item: T, index: number) => React.ReactNode\n  onScroll?: (event: React.UIEvent<HTMLDivElement>) => void\n  onRangeChange?: (range: [number, number]) => void\n}\n\nfunction VirtualListInner<T extends Record<string, any>>(\n  {\n    items,\n    itemSize,\n    height,\n    overscan = 3,\n    keyField = 'id',\n    direction = 'vertical',\n    className,\n    children,\n    onScroll,\n    onRangeChange,\n  }: VirtualListProps<T>,\n  ref: React.Ref<VirtualListHandle>,\n) {\n  const scrollRef = React.useRef<HTMLDivElement | null>(null)\n  const isVertical = direction === 'vertical'\n\n  const virtualizer = useVirtualizer({\n    count: items.length,\n    horizontal: !isVertical,\n    getScrollElement: () => scrollRef.current,\n    estimateSize: (index) =>\n      typeof itemSize === 'function' ? itemSize(items[index]!, index) : itemSize,\n    overscan,\n    getItemKey: (index) => {\n      const item = items[index]\n      const k = item?.[keyField as keyof T]\n      return (k ?? index) as string | number\n    },\n  })\n\n  const virtualItems = virtualizer.getVirtualItems()\n  const totalSize = virtualizer.getTotalSize()\n\n  React.useEffect(() => {\n    if (!onRangeChange || virtualItems.length === 0) return\n    onRangeChange([virtualItems[0]!.index, virtualItems[virtualItems.length - 1]!.index + 1])\n  }, [virtualItems, onRangeChange])\n\n  React.useImperativeHandle(\n    ref,\n    () => ({\n      scrollToOffset: (px) => virtualizer.scrollToOffset(px),\n      scrollToIndex: (index, options) =>\n        virtualizer.scrollToIndex(index, { align: options?.align ?? 'start' }),\n      getVisibleRange: () => {\n        const v = virtualizer.getVirtualItems()\n        if (v.length === 0) return [0, 0]\n        return [v[0]!.index, v[v.length - 1]!.index + 1]\n      },\n    }),\n    [virtualizer],\n  )\n\n  const h = typeof height === 'number' ? `${height}px` : height\n  const containerStyle: React.CSSProperties = isVertical\n    ? { height: h, overflowY: 'auto' }\n    : { width: h, overflowX: 'auto' }\n\n  const innerStyle: React.CSSProperties = isVertical\n    ? { height: `${totalSize}px`, position: 'relative', width: '100%' }\n    : { width: `${totalSize}px`, position: 'relative', height: '100%' }\n\n  return (\n    <div\n      ref={scrollRef}\n      data-uipkge=\"\"\n      data-slot=\"virtual-list\"\n      className={cn('w-full', className)}\n      style={containerStyle}\n      onScroll={onScroll}\n    >\n      <div style={innerStyle}>\n        {virtualItems.map((virtualItem) => {\n          const item = items[virtualItem.index]!\n          const rowStyle: React.CSSProperties = isVertical\n            ? {\n                position: 'absolute',\n                top: 0,\n                left: 0,\n                width: '100%',\n                height: `${virtualItem.size}px`,\n                transform: `translateY(${virtualItem.start}px)`,\n              }\n            : {\n                position: 'absolute',\n                top: 0,\n                left: 0,\n                height: '100%',\n                width: `${virtualItem.size}px`,\n                transform: `translateX(${virtualItem.start}px)`,\n              }\n          return (\n            <div key={virtualItem.key} style={rowStyle}>\n              {children(item, virtualItem.index)}\n            </div>\n          )\n        })}\n      </div>\n    </div>\n  )\n}\n\nconst VirtualList = React.forwardRef(VirtualListInner) as <T extends Record<string, any>>(\n  props: VirtualListProps<T> & { ref?: React.Ref<VirtualListHandle> },\n) => React.ReactElement\n\nexport { VirtualList }\n",
      "type": "registry:ui",
      "target": "~/components/ui/virtual-list/virtual-list.tsx"
    },
    {
      "path": "packages/registry-react/components/virtual-list/index.ts",
      "content": "export { VirtualList, type VirtualListProps, type VirtualListHandle } from './virtual-list'\n",
      "type": "registry:ui",
      "target": "~/components/ui/virtual-list/index.ts"
    }
  ],
  "dependencies": [
    "@tanstack/react-virtual"
  ],
  "devDependencies": [],
  "registryDependencies": [],
  "description": "Generic windowed scroller. Renders only visible items plus a small overscan, with fixed or dynamic item sizes. Use for long lists where most rows are off-screen.",
  "categories": [
    "data-display"
  ]
}