{ "$schema": "https://ui.shadcn.com/schema/registry-item.json", "name": "carousel", "type": "registry:ui", "title": "Carousel", "description": "Snap-scrolling horizontal pager with optional arrows.", "registryDependencies": [ "https://raw.githubusercontent.com/truongnat/rnui/main/registry/dist/nativewind/utils.json", "https://raw.githubusercontent.com/truongnat/rnui/main/registry/dist/nativewind/theme.json" ], "dependencies": [ "lucide-react-native" ], "files": [ { "path": "registry/shared/ui/carousel.tsx", "type": "registry:ui", "target": "components/ui/carousel.tsx", "content": "import { useRef, useState, type ReactNode } from 'react';\nimport {\n FlatList,\n Pressable,\n useWindowDimensions,\n View,\n type ViewProps,\n} from 'react-native';\nimport { ChevronLeft, ChevronRight } from 'lucide-react-native';\nimport { cn, useIconColor } from '@/lib/utils';\n\nexport interface CarouselProps extends Omit {\n data: T[];\n renderItem: (item: T, index: number) => ReactNode;\n /** Item width in px — defaults to viewport width. */\n itemWidth?: number;\n className?: string;\n itemClassName?: string;\n showArrows?: boolean;\n /** Pagination dots under the carousel. */\n showDots?: boolean;\n onIndexChange?: (index: number) => void;\n}\n\nexport function Carousel({\n data,\n renderItem,\n itemWidth,\n className,\n itemClassName,\n showArrows = false,\n showDots = true,\n onIndexChange,\n ...props\n}: CarouselProps) {\n const { width: viewport } = useWindowDimensions();\n const w = itemWidth ?? viewport;\n const list = useRef>(null);\n const [index, setIndex] = useState(0);\n const iconColor = useIconColor('foreground');\n\n const scrollTo = (i: number) => {\n const next = Math.max(0, Math.min(data.length - 1, i));\n list.current?.scrollToOffset({ offset: next * w, animated: true });\n setIndex(next);\n onIndexChange?.(next);\n };\n\n return (\n \n String(i)}\n showsHorizontalScrollIndicator={false}\n snapToInterval={w}\n decelerationRate=\"fast\"\n onMomentumScrollEnd={(e) => {\n const i = Math.round(e.nativeEvent.contentOffset.x / w);\n setIndex(i);\n onIndexChange?.(i);\n }}\n renderItem={({ item, index: i }) => (\n \n {renderItem(item, i)}\n \n )}\n />\n {showArrows && (\n \n scrollTo(index - 1)}\n className=\"rounded-full border border-border bg-background p-2\"\n >\n \n \n scrollTo(index + 1)}\n className=\"rounded-full border border-border bg-background p-2\"\n >\n \n \n \n )}\n {showDots && data.length > 1 && (\n \n {data.map((_item, i) => (\n scrollTo(i)}\n className={cn(\n 'h-1.5 rounded-full',\n i === index ? 'w-5 bg-foreground' : 'w-1.5 bg-border'\n )}\n />\n ))}\n \n )}\n \n );\n}\n" } ] }