'use client'; import { forwardRef, HTMLAttributes, ReactNode, useState, useRef, useCallback, Children } from 'react'; export interface CircularGalleryProps extends HTMLAttributes { children: ReactNode; radius?: number; autoRotate?: boolean; rotateSpeed?: number; itemSize?: number; onItemClick?: (index: number) => void; activeIndex?: number; } export const CircularGallery = forwardRef( ( { children, radius = 200, autoRotate = true, rotateSpeed = 30, itemSize = 80, onItemClick, activeIndex: controlledActiveIndex, className = '', style, ...props }, ref ) => { const [internalActiveIndex, setInternalActiveIndex] = useState(0); const [isPaused, setIsPaused] = useState(false); const containerRef = useRef(null); const activeIndex = controlledActiveIndex ?? internalActiveIndex; const items = Children.toArray(children); const itemCount = items.length; const handleItemClick = useCallback( (index: number) => { setInternalActiveIndex(index); onItemClick?.(index); }, [onItemClick] ); const handleMouseEnter = useCallback(() => { if (autoRotate) setIsPaused(true); }, [autoRotate]); const handleMouseLeave = useCallback(() => { if (autoRotate) setIsPaused(false); }, [autoRotate]); const getItemStyle = (index: number) => { const angle = (index / itemCount) * 360; return { '--item-angle': `${angle}deg`, } as React.CSSProperties; }; return ( { (containerRef as React.MutableRefObject).current = node; if (typeof ref === 'function') ref(node); else if (ref) ref.current = node; }} className={`relative flex items-center justify-center w-full ${className}`} style={{ minHeight: `${radius * 2 + itemSize * 2}px`, padding: '2rem', ...style, }} onMouseEnter={handleMouseEnter} onMouseLeave={handleMouseLeave} {...props} > {/* Inner circle decoration */} {/* Outer ring with segments */} {items.map((item, index) => { const isActive = index === activeIndex; return ( handleItemClick(index)} > {item} {isActive && ( <> > )} ); })} {/* Center display for active item */} {items[activeIndex]} ); } ); CircularGallery.displayName = 'CircularGallery'; export default CircularGallery;