{"version":3,"file":"Carousel.cjs","names":[],"sources":["../../../src/components/Carousel/Carousel.tsx"],"sourcesContent":["/**\n * @tempest-limits function-lines — the body owns the scroll snap position, the\n * swipe, the autoplay timer that must pause on interaction and the dot indicators\n * that read the same index.\n */\nimport { useCallback, useState } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"@/utils/cn\";\nimport styles from \"./Carousel.module.css\";\n\nexport interface CarouselProps extends Omit<HTMLAttributes<HTMLDivElement>, \"children\"> {\n    /** Slides — one rendered at a time. */\n    children: ReactNode[];\n    /** Wrap around at the ends instead of stopping. Default `false`. */\n    loop?: boolean;\n    /** Show prev/next arrow buttons. Default `true`. */\n    showArrows?: boolean;\n    /** Show dot indicators. Default `true`. */\n    showDots?: boolean;\n    /** Controlled active index. */\n    index?: number;\n    /** Initial index for uncontrolled use. Default `0`. */\n    defaultIndex?: number;\n    /** Called whenever the active index changes. */\n    onIndexChange?: (index: number) => void;\n}\n\n/**\n * Horizontal content slider showing one slide at a time.\n *\n * - Track translates by the active index (`translateX(-index * 100%)`).\n * - Prev/next arrows (disabled at the ends unless `loop`); dot indicators jump.\n * - Controlled (`index`) or uncontrolled (`defaultIndex`).\n * - Arrow Left/Right on the focused region navigates.\n *\n * @example\n * <Carousel loop>\n *     <img src=\"/1.jpg\" alt=\"\" />\n *     <img src=\"/2.jpg\" alt=\"\" />\n *     <img src=\"/3.jpg\" alt=\"\" />\n * </Carousel>\n */\nexport function Carousel({\n    children,\n    loop = false,\n    showArrows = true,\n    showDots = true,\n    index,\n    defaultIndex = 0,\n    onIndexChange,\n    className,\n    ...props\n}: CarouselProps) {\n    const count = children.length;\n    const isControlled = index !== undefined;\n    const [internalIndex, setInternalIndex] = useState<number>(defaultIndex);\n    const current = isControlled ? index : internalIndex;\n\n    const goTo = useCallback(\n        (next: number): void => {\n            let target = next;\n            if (target < 0) target = loop ? count - 1 : 0;\n            else if (target >= count) target = loop ? 0 : count - 1;\n            if (target === current) return;\n            if (!isControlled) setInternalIndex(target);\n            onIndexChange?.(target);\n        },\n        [count, loop, current, isControlled, onIndexChange],\n    );\n\n    const atStart = current <= 0;\n    const atEnd = current >= count - 1;\n\n    const handleKeyDown = (event: React.KeyboardEvent<HTMLDivElement>): void => {\n        if (event.key === \"ArrowRight\") {\n            event.preventDefault();\n            goTo(current + 1);\n        } else if (event.key === \"ArrowLeft\") {\n            event.preventDefault();\n            goTo(current - 1);\n        }\n    };\n\n    return (\n        <div\n            role=\"region\"\n            aria-roledescription=\"carousel\"\n            tabIndex={0}\n            className={cn(styles.root, className)}\n            onKeyDown={handleKeyDown}\n            {...props}\n        >\n            <div className={styles.viewport}>\n                <div\n                    className={styles.track}\n                    style={{ transform: `translateX(-${current * 100}%)` }}\n                >\n                    {children.map((slide, slideIndex) => (\n                        <div\n                            key={slideIndex}\n                            role=\"group\"\n                            aria-roledescription=\"slide\"\n                            aria-label={`${slideIndex + 1} of ${count}`}\n                            aria-hidden={slideIndex !== current}\n                            className={styles.slide}\n                        >\n                            {slide}\n                        </div>\n                    ))}\n                </div>\n            </div>\n\n            {showArrows && count > 1 && (\n                <>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.arrow, styles.prev)}\n                        aria-label=\"Previous slide\"\n                        disabled={!loop && atStart}\n                        onClick={() => goTo(current - 1)}\n                    >\n                        ‹\n                    </button>\n                    <button\n                        type=\"button\"\n                        className={cn(styles.arrow, styles.next)}\n                        aria-label=\"Next slide\"\n                        disabled={!loop && atEnd}\n                        onClick={() => goTo(current + 1)}\n                    >\n                        ›\n                    </button>\n                </>\n            )}\n\n            {showDots && count > 1 && (\n                <div className={styles.dots} role=\"tablist\" aria-label=\"Slides\">\n                    {children.map((_, dotIndex) => (\n                        <button\n                            key={dotIndex}\n                            type=\"button\"\n                            role=\"tab\"\n                            aria-label={`Go to slide ${dotIndex + 1}`}\n                            aria-selected={dotIndex === current}\n                            className={cn(styles.dot, dotIndex === current && styles.dotActive)}\n                            onClick={() => goTo(dotIndex)}\n                        />\n                    ))}\n                </div>\n            )}\n        </div>\n    );\n}\n"],"mappings":"+HA0CA,SAAgB,EAAS,CACrB,WACA,OAAO,GACP,aAAa,GACb,WAAW,GACX,QACA,eAAe,EACf,gBACA,YACA,GAAG,GACW,CACd,IAAM,EAAQ,EAAS,OACjB,EAAe,IAAU,IAAA,GACzB,CAAC,EAAe,IAAA,EAAoB,EAAA,SAAA,CAAiB,CAAY,EACjE,EAAU,EAAe,EAAQ,EAEjC,GAAA,EAAO,EAAA,YAAA,CACR,GAAuB,CACpB,IAAI,EAAS,EACT,EAAS,EAAG,EAAS,EAAO,EAAQ,EAAI,EACnC,GAAU,IAAO,EAAS,EAAO,EAAI,EAAQ,GAClD,IAAW,IACV,GAAc,EAAiB,CAAM,EAC1C,IAAgB,CAAM,EAC1B,EACA,CAAC,EAAO,EAAM,EAAS,EAAc,CAAa,CACtD,EAEM,EAAU,GAAW,EACrB,EAAQ,GAAW,EAAQ,EAYjC,OACI,EAAA,EAAA,KAAA,CAAC,MAAD,CACI,KAAK,SACL,uBAAqB,WACrB,SAAU,EACV,UAAW,EAAA,GAAG,EAAA,QAAO,KAAM,CAAS,EACpC,UAhBe,GAAqD,CACpE,EAAM,MAAQ,cACd,EAAM,eAAe,EACrB,EAAK,EAAU,CAAC,GACT,EAAM,MAAQ,cACrB,EAAM,eAAe,EACrB,EAAK,EAAU,CAAC,EAExB,EASQ,GAAI,EANR,SAAA,EAQI,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,SACnB,UAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CACI,UAAW,EAAA,QAAO,MAClB,MAAO,CAAE,UAAW,eAAe,EAAU,IAAI,GAAI,EAEpD,SAAA,EAAS,KAAK,EAAO,KAClB,EAAA,EAAA,IAAA,CAAC,MAAD,CAEI,KAAK,QACL,uBAAqB,QACrB,aAAY,GAAG,EAAa,EAAE,MAAM,IACpC,cAAa,IAAe,EAC5B,UAAW,EAAA,QAAO,MAEjB,SAAA,CACA,EARI,CAQJ,CACR,CACA,CAAA,CACJ,CAAA,EAEJ,GAAc,EAAQ,IACnB,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACI,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,IAAI,EACvC,aAAW,iBACX,SAAU,CAAC,GAAQ,EACnB,YAAe,EAAK,EAAU,CAAC,EAClC,SAAA,GAEO,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,SAAD,CACI,KAAK,SACL,UAAW,EAAA,GAAG,EAAA,QAAO,MAAO,EAAA,QAAO,IAAI,EACvC,aAAW,aACX,SAAU,CAAC,GAAQ,EACnB,YAAe,EAAK,EAAU,CAAC,EAClC,SAAA,GAEO,CAAA,CACV,CAAA,CAAA,EAGL,GAAY,EAAQ,IACjB,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAA,QAAO,KAAM,KAAK,UAAU,aAAW,SAClD,SAAA,EAAS,KAAK,EAAG,KACd,EAAA,EAAA,IAAA,CAAC,SAAD,CAEI,KAAK,SACL,KAAK,MACL,aAAY,eAAe,EAAW,IACtC,gBAAe,IAAa,EAC5B,UAAW,EAAA,GAAG,EAAA,QAAO,IAAK,IAAa,GAAW,EAAA,QAAO,SAAS,EAClE,YAAe,EAAK,CAAQ,CAC/B,EAPQ,CAOR,CACJ,CACA,CAAA,CAER,GAEb"}