{
	"$schema": "https://ui.shadcn.com/schema/registry-item.json",
	"name": "AnimatedList-TS-CSS",
	"title": "AnimatedList",
	"description": "List items enter with staggered motion variants for polished reveals.",
	"type": "registry:component",
	"files": [
		{
			"type": "registry:component",
			"path": "AnimatedList/AnimatedList.css",
			"content": ".scroll-list-container {\n  position: relative;\n  width: 500px;\n}\n\n.scroll-list {\n  max-height: 400px;\n  overflow-y: auto;\n  padding: 16px;\n}\n\n.scroll-list::-webkit-scrollbar {\n  width: 8px;\n}\n\n.scroll-list::-webkit-scrollbar-track {\n  background: #060606;\n}\n\n.scroll-list::-webkit-scrollbar-thumb {\n  background: #222;\n  border-radius: 4px;\n}\n\n.no-scrollbar::-webkit-scrollbar {\n  display: none;\n}\n\n.no-scrollbar {\n  -ms-overflow-style: none;\n  scrollbar-width: none;\n}\n\n.item {\n  padding: 16px;\n  background-color: #111;\n  border-radius: 8px;\n  margin-bottom: 1rem;\n}\n\n.item.selected {\n  background-color: #222;\n}\n\n.item-text {\n  color: white;\n  margin: 0;\n}\n\n.top-gradient {\n  position: absolute;\n  top: 0;\n  left: 0;\n  right: 0;\n  height: 50px;\n  background: linear-gradient(to bottom, #120F17, transparent);\n  pointer-events: none;\n  transition: opacity 0.3s ease;\n}\n\n.bottom-gradient {\n  position: absolute;\n  bottom: 0;\n  left: 0;\n  right: 0;\n  height: 100px;\n  background: linear-gradient(to top, #120F17, transparent);\n  pointer-events: none;\n  transition: opacity 0.3s ease;\n}\n"
		},
		{
			"type": "registry:component",
			"path": "AnimatedList/AnimatedList.tsx",
			"content": "import React, { useRef, useState, useEffect, useCallback, ReactNode, MouseEventHandler, UIEvent } from 'react';\nimport { motion, useInView } from 'motion/react';\nimport './AnimatedList.css';\n\ninterface AnimatedItemProps {\n  children: ReactNode;\n  delay?: number;\n  index: number;\n  onMouseEnter?: MouseEventHandler<HTMLDivElement>;\n  onClick?: MouseEventHandler<HTMLDivElement>;\n}\n\nconst AnimatedItem: React.FC<AnimatedItemProps> = ({ children, delay = 0, index, onMouseEnter, onClick }) => {\n  const ref = useRef<HTMLDivElement>(null);\n  const inView = useInView(ref, { amount: 0.5, once: false });\n  return (\n    <motion.div\n      ref={ref}\n      data-index={index}\n      onMouseEnter={onMouseEnter}\n      onClick={onClick}\n      initial={{ scale: 0.7, opacity: 0 }}\n      animate={inView ? { scale: 1, opacity: 1 } : { scale: 0.7, opacity: 0 }}\n      transition={{ duration: 0.2, delay }}\n      style={{ marginBottom: '1rem', cursor: 'pointer' }}\n    >\n      {children}\n    </motion.div>\n  );\n};\n\ninterface AnimatedListProps {\n  items?: string[];\n  onItemSelect?: (item: string, index: number) => void;\n  showGradients?: boolean;\n  enableArrowNavigation?: boolean;\n  className?: string;\n  itemClassName?: string;\n  displayScrollbar?: boolean;\n  initialSelectedIndex?: number;\n}\n\nconst AnimatedList: React.FC<AnimatedListProps> = ({\n  items = [\n    'Item 1',\n    'Item 2',\n    'Item 3',\n    'Item 4',\n    'Item 5',\n    'Item 6',\n    'Item 7',\n    'Item 8',\n    'Item 9',\n    'Item 10',\n    'Item 11',\n    'Item 12',\n    'Item 13',\n    'Item 14',\n    'Item 15'\n  ],\n  onItemSelect,\n  showGradients = true,\n  enableArrowNavigation = true,\n  className = '',\n  itemClassName = '',\n  displayScrollbar = true,\n  initialSelectedIndex = -1\n}) => {\n  const listRef = useRef<HTMLDivElement>(null);\n  const [selectedIndex, setSelectedIndex] = useState<number>(initialSelectedIndex);\n  const [keyboardNav, setKeyboardNav] = useState<boolean>(false);\n  const [topGradientOpacity, setTopGradientOpacity] = useState<number>(0);\n  const [bottomGradientOpacity, setBottomGradientOpacity] = useState<number>(1);\n\n  const handleItemMouseEnter = useCallback((index: number) => {\n    setSelectedIndex(index);\n  }, []);\n\n  const handleItemClick = useCallback(\n    (item: string, index: number) => {\n      setSelectedIndex(index);\n      if (onItemSelect) {\n        onItemSelect(item, index);\n      }\n    },\n    [onItemSelect]\n  );\n\n  const handleScroll = useCallback((e: UIEvent<HTMLDivElement>) => {\n    const target = e.target as HTMLDivElement;\n    const { scrollTop, scrollHeight, clientHeight } = target;\n    setTopGradientOpacity(Math.min(scrollTop / 50, 1));\n    const bottomDistance = scrollHeight - (scrollTop + clientHeight);\n    setBottomGradientOpacity(scrollHeight <= clientHeight ? 0 : Math.min(bottomDistance / 50, 1));\n  }, []);\n\n  useEffect(() => {\n    if (!enableArrowNavigation) return;\n    const handleKeyDown = (e: KeyboardEvent) => {\n      if (e.key === 'ArrowDown' || (e.key === 'Tab' && !e.shiftKey)) {\n        e.preventDefault();\n        setKeyboardNav(true);\n        setSelectedIndex(prev => Math.min(prev + 1, items.length - 1));\n      } else if (e.key === 'ArrowUp' || (e.key === 'Tab' && e.shiftKey)) {\n        e.preventDefault();\n        setKeyboardNav(true);\n        setSelectedIndex(prev => Math.max(prev - 1, 0));\n      } else if (e.key === 'Enter') {\n        if (selectedIndex >= 0 && selectedIndex < items.length) {\n          e.preventDefault();\n          if (onItemSelect) {\n            onItemSelect(items[selectedIndex], selectedIndex);\n          }\n        }\n      }\n    };\n\n    window.addEventListener('keydown', handleKeyDown);\n    return () => window.removeEventListener('keydown', handleKeyDown);\n  }, [items, selectedIndex, onItemSelect, enableArrowNavigation]);\n\n  useEffect(() => {\n    if (!keyboardNav || selectedIndex < 0 || !listRef.current) return;\n    const container = listRef.current;\n    const selectedItem = container.querySelector(`[data-index=\"${selectedIndex}\"]`) as HTMLElement | null;\n    if (selectedItem) {\n      const extraMargin = 50;\n      const containerScrollTop = container.scrollTop;\n      const containerHeight = container.clientHeight;\n      const itemTop = selectedItem.offsetTop;\n      const itemBottom = itemTop + selectedItem.offsetHeight;\n      if (itemTop < containerScrollTop + extraMargin) {\n        container.scrollTo({ top: itemTop - extraMargin, behavior: 'smooth' });\n      } else if (itemBottom > containerScrollTop + containerHeight - extraMargin) {\n        container.scrollTo({\n          top: itemBottom - containerHeight + extraMargin,\n          behavior: 'smooth'\n        });\n      }\n    }\n    setKeyboardNav(false);\n  }, [selectedIndex, keyboardNav]);\n\n  return (\n    <div className={`scroll-list-container ${className}`}>\n      <div ref={listRef} className={`scroll-list ${!displayScrollbar ? 'no-scrollbar' : ''}`} onScroll={handleScroll}>\n        {items.map((item, index) => (\n          <AnimatedItem\n            key={index}\n            delay={0.1}\n            index={index}\n            onMouseEnter={() => handleItemMouseEnter(index)}\n            onClick={() => handleItemClick(item, index)}\n          >\n            <div className={`item ${selectedIndex === index ? 'selected' : ''} ${itemClassName}`}>\n              <p className=\"item-text\">{item}</p>\n            </div>\n          </AnimatedItem>\n        ))}\n      </div>\n      {showGradients && (\n        <>\n          <div className=\"top-gradient\" style={{ opacity: topGradientOpacity }}></div>\n          <div className=\"bottom-gradient\" style={{ opacity: bottomGradientOpacity }}></div>\n        </>\n      )}\n    </div>\n  );\n};\n\nexport default AnimatedList;\n"
		}
	],
	"registryDependencies": [],
	"dependencies": [
		"motion@^12.23.12"
	]
}