"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.TailwindCarousel = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const cn_js_1 = require("../utils/cn.js");
/**
 * Carousel component built with Tailwind CSS
 *
 * A feature-rich carousel/slideshow with various transition effects,
 * navigation controls, and indicator types.
 *
 * @example
 * // Basic usage
 * <TailwindCarousel
 *   slides={[
 *     { id: 1, content: <img src="/image1.jpg" alt="Slide 1" />, caption: "Caption 1" },
 *     { id: 2, content: <img src="/image2.jpg" alt="Slide 2" />, caption: "Caption 2" },
 *     { id: 3, content: <img src="/image3.jpg" alt="Slide 3" />, caption: "Caption 3" },
 *   ]}
 * />
 *
 * @example
 * // With custom options
 * <TailwindCarousel
 *   slides={slides}
 *   autoPlay={true}
 *   interval={3000}
 *   effect="fade"
 *   indicators="thumbnails"
 *   controls="sides"
 *   aspectRatio="16:9"
 * />
 */
exports.TailwindCarousel = (0, react_1.forwardRef)(({ slides, initialSlide = 0, autoPlay = false, interval = 5000, pauseOnHover = true, infinite = true, effect = 'slide', indicators = 'dots', controls = 'arrows', showCaptions = true, transitionDuration = 300, swipeable = true, onChange, fullWidth = true, aspectRatio, slideClassName, indicatorsClassName, controlsClassName, captionClassName, className, ...props }, ref) => {
    // State for current slide index
    const [currentSlide, setCurrentSlide] = (0, react_1.useState)(initialSlide);
    const [isHovering, setIsHovering] = (0, react_1.useState)(false);
    const [touchStart, setTouchStart] = (0, react_1.useState)(null);
    const [touchEnd, setTouchEnd] = (0, react_1.useState)(null);
    // Refs
    const carouselRef = (0, react_1.useRef)(null);
    const intervalRef = (0, react_1.useRef)(null);
    // Calculate aspect ratio padding if provided
    const getAspectRatioPadding = () => {
        if (!aspectRatio)
            return undefined;
        const [width, height] = aspectRatio.split(':').map(Number);
        if (!width || !height)
            return undefined;
        const paddingTop = `${(height / width) * 100}%`;
        return paddingTop;
    };
    // Handle slide navigation
    const goToSlide = (index) => {
        let newIndex = index;
        // Handle infinite looping
        if (infinite) {
            if (index < 0) {
                newIndex = slides.length - 1;
            }
            else if (index >= slides.length) {
                newIndex = 0;
            }
        }
        else {
            // Clamp to valid range without looping
            newIndex = Math.max(0, Math.min(index, slides.length - 1));
        }
        if (newIndex !== currentSlide) {
            setCurrentSlide(newIndex);
            onChange?.(newIndex);
        }
    };
    // Navigate to next/previous slide
    const goToNextSlide = () => goToSlide(currentSlide + 1);
    const goToPrevSlide = () => goToSlide(currentSlide - 1);
    // Auto-play functionality
    (0, react_1.useEffect)(() => {
        if (autoPlay && !isHovering) {
            intervalRef.current = setInterval(goToNextSlide, interval);
        }
        return () => {
            if (intervalRef.current) {
                clearInterval(intervalRef.current);
            }
        };
    }, [autoPlay, interval, currentSlide, isHovering, infinite]);
    // Mouse enter/leave handlers
    const handleMouseEnter = () => {
        if (pauseOnHover) {
            setIsHovering(true);
        }
    };
    const handleMouseLeave = () => {
        if (pauseOnHover) {
            setIsHovering(false);
        }
    };
    // Touch event handlers for swipe gesture
    const handleTouchStart = (e) => {
        if (!swipeable)
            return;
        setTouchStart(e.targetTouches[0].clientX);
    };
    const handleTouchMove = (e) => {
        if (!swipeable || touchStart === null)
            return;
        setTouchEnd(e.targetTouches[0].clientX);
    };
    const handleTouchEnd = () => {
        if (!swipeable || touchStart === null || touchEnd === null)
            return;
        const distance = touchStart - touchEnd;
        const isSignificantSwipe = Math.abs(distance) > 50;
        if (isSignificantSwipe) {
            if (distance > 0) {
                // Swipe left, go to next slide
                goToNextSlide();
            }
            else {
                // Swipe right, go to previous slide
                goToPrevSlide();
            }
        }
        // Reset touch values
        setTouchStart(null);
        setTouchEnd(null);
    };
    // Keyboard navigation
    (0, react_1.useEffect)(() => {
        const handleKeyDown = (e) => {
            if (e.key === 'ArrowLeft') {
                goToPrevSlide();
            }
            else if (e.key === 'ArrowRight') {
                goToNextSlide();
            }
        };
        if (carouselRef.current) {
            carouselRef.current.addEventListener('keydown', handleKeyDown);
        }
        return () => {
            if (carouselRef.current) {
                carouselRef.current.removeEventListener('keydown', handleKeyDown);
            }
        };
    }, [currentSlide]);
    // Class names and styles
    // Container classes
    const containerClasses = (0, cn_js_1.cn)('relative overflow-hidden focus:outline-none', fullWidth && 'w-full', className);
    // Container style for aspect ratio
    const containerStyle = {
        paddingTop: getAspectRatioPadding(),
    };
    // Slides container classes based on effect
    const slidesContainerClasses = (0, cn_js_1.cn)('flex h-full w-full', effect === 'slide' && 'transition-transform duration-300 ease-in-out', effect !== 'slide' && 'relative');
    // Individual slide classes based on effect
    const getSlideClasses = (index) => {
        return (0, cn_js_1.cn)('flex-shrink-0 w-full h-full flex items-center justify-center overflow-hidden', effect === 'slide' && 'relative', effect === 'fade' && (0, cn_js_1.cn)('absolute inset-0 transition-opacity duration-300 ease-in-out', index === currentSlide ? 'opacity-100 z-10' : 'opacity-0 z-0'), effect === 'zoom' && (0, cn_js_1.cn)('absolute inset-0 transition-all duration-300 ease-in-out', index === currentSlide
            ? 'opacity-100 scale-100 z-10'
            : 'opacity-0 scale-90 z-0'), effect === 'flip' && (0, cn_js_1.cn)('absolute inset-0 transition-all duration-300 ease-in-out backface-visibility-hidden', index === currentSlide
            ? 'opacity-100 rotateY-0 z-10'
            : 'opacity-0 rotateY-180 z-0'), slideClassName);
    };
    // Caption classes
    const captionClasses = (0, cn_js_1.cn)('absolute bottom-0 left-0 right-0 bg-black bg-opacity-50 text-white p-3', 'transition-opacity duration-300 ease-in-out', captionClassName);
    // Indicators container classes
    const indicatorsContainerClasses = (0, cn_js_1.cn)('absolute bottom-4 left-0 right-0 flex justify-center z-20', indicators === 'thumbnails' && 'bottom-10', indicatorsClassName);
    // Individual indicator classes
    const getIndicatorClasses = (index) => {
        return (0, cn_js_1.cn)('transition-all duration-300 mx-1 cursor-pointer', indicators === 'dots' && (0, cn_js_1.cn)('w-3 h-3 rounded-full', index === currentSlide
            ? 'bg-white scale-125'
            : 'bg-white bg-opacity-50 hover:bg-opacity-75'), indicators === 'bars' && (0, cn_js_1.cn)('h-1 w-8', index === currentSlide
            ? 'bg-white'
            : 'bg-white bg-opacity-50 hover:bg-opacity-75'), indicators === 'numbers' && (0, cn_js_1.cn)('w-6 h-6 rounded-full flex items-center justify-center text-xs', index === currentSlide
            ? 'bg-white text-black'
            : 'bg-black bg-opacity-50 text-white hover:bg-opacity-75'), indicators === 'thumbnails' && (0, cn_js_1.cn)('w-12 h-8 border-2 overflow-hidden', index === currentSlide
            ? 'border-white scale-110'
            : 'border-transparent opacity-70 hover:opacity-100'));
    };
    // Navigation control classes
    const controlClasses = (0, cn_js_1.cn)('absolute top-1/2 transform -translate-y-1/2 z-20', 'bg-black bg-opacity-50 hover:bg-opacity-75 text-white', 'w-10 h-10 flex items-center justify-center rounded-full', 'transition-all duration-200 cursor-pointer', 'focus:outline-none focus:ring-2 focus:ring-white', controls === 'arrows' && 'mx-4', controls === 'sides' && 'w-12 h-full rounded-none m-0 opacity-0 hover:opacity-30', controlsClassName);
    return ((0, jsx_runtime_1.jsxs)("div", { ref: (node) => {
            // Forward ref to parent component
            if (typeof ref === 'function') {
                ref(node);
            }
            else if (ref) {
                ref.current = node;
            }
            // Also set our internal ref
            if (node) {
                carouselRef.current = node;
            }
        }, className: containerClasses, style: aspectRatio ? containerStyle : undefined, onMouseEnter: handleMouseEnter, onMouseLeave: handleMouseLeave, tabIndex: 0, role: "region", "aria-roledescription": "carousel", "aria-label": "Image carousel", ...props, children: [(0, jsx_runtime_1.jsx)("div", { className: slidesContainerClasses, style: effect === 'slide'
                    ? { transform: `translateX(-${currentSlide * 100}%)` }
                    : undefined, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, children: slides.map((slide, index) => ((0, jsx_runtime_1.jsxs)("div", { className: getSlideClasses(index), style: effect === 'slide' ? { width: '100%' } : undefined, role: "group", "aria-roledescription": "slide", "aria-label": `Slide ${index + 1} of ${slides.length}`, "aria-hidden": index !== currentSlide, children: [slide.content, showCaptions && slide.caption && ((0, jsx_runtime_1.jsx)("div", { className: captionClasses, children: slide.caption }))] }, slide.id))) }), indicators !== 'none' && ((0, jsx_runtime_1.jsx)("div", { className: indicatorsContainerClasses, children: slides.map((slide, index) => ((0, jsx_runtime_1.jsxs)("div", { className: getIndicatorClasses(index), onClick: () => goToSlide(index), role: "button", tabIndex: 0, "aria-label": `Go to slide ${index + 1}`, "aria-current": index === currentSlide, children: [indicators === 'numbers' && (index + 1), indicators === 'thumbnails' && slide.thumbnail && ((0, jsx_runtime_1.jsx)("img", { src: slide.thumbnail, alt: `Thumbnail for slide ${index + 1}`, className: "w-full h-full object-cover" }))] }, `indicator-${slide.id}`))) })), controls !== 'none' && ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("button", { className: (0, cn_js_1.cn)(controlClasses, 'left-0', (!infinite && currentSlide === 0) && 'opacity-50 cursor-not-allowed'), onClick: goToPrevSlide, disabled: !infinite && currentSlide === 0, "aria-label": "Previous slide", type: "button", children: (0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: controls === 'sides' ? 'w-8 h-8' : 'w-6 h-6', children: (0, jsx_runtime_1.jsx)("polyline", { points: "15 18 9 12 15 6" }) }) }), (0, jsx_runtime_1.jsx)("button", { className: (0, cn_js_1.cn)(controlClasses, 'right-0', (!infinite && currentSlide === slides.length - 1) && 'opacity-50 cursor-not-allowed'), onClick: goToNextSlide, disabled: !infinite && currentSlide === slides.length - 1, "aria-label": "Next slide", type: "button", children: (0, jsx_runtime_1.jsx)("svg", { xmlns: "http://www.w3.org/2000/svg", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", className: controls === 'sides' ? 'w-8 h-8' : 'w-6 h-6', children: (0, jsx_runtime_1.jsx)("polyline", { points: "9 18 15 12 9 6" }) }) })] }))] }));
});
exports.TailwindCarousel.displayName = 'TailwindCarousel';
exports.default = exports.TailwindCarousel;
//# sourceMappingURL=TailwindCarousel.js.map