feat(SW-1542): Carousel component * feat(SW-1542): add Embla Carousel component and use in CarouselCards * fix(SW-1542): remove max-width constraint for card on ipad * fix(SW-1542): Add padding to start page content container * refactor(SW-1542): Improve Embla Carousel type imports * refactor(SW-1542): Remove unnecessary carousel wrapper div * refactor(SW-1542): Modularize Carousel component structure * refactor(SW-1542): Remove carousel dots display * feat(SW-1542): Add carousel dots navigation * refactor(SW-1542): Update Carousel component styling and types * refactor(SW-1542): Remove uneeded useCallback from Carousel navigation methods * refactor(SW-1542): Modify CarouselContextProps type to exclude className * refactor(SW-1542): Optimize React imports in Carousel components * refactor(SW-1542): Consolidate Carousel component and remove CarouselRoot * refactor(SW-1542): Update Carousel navigation methods to use function-based scroll checks * refactor(SW-1542): Add explicit children prop support to CarouselContent component * refactor(SW-1542): Add children prop support to CarouselItem component Approved-by: Christian Andolf
46 lines
1.1 KiB
TypeScript
46 lines
1.1 KiB
TypeScript
"use client"
|
|
|
|
import { cx } from "class-variance-authority"
|
|
import { useEffect, useState } from "react"
|
|
|
|
import { useCarousel } from "./CarouselContext"
|
|
|
|
import styles from "./carousel.module.css"
|
|
|
|
export function CarouselDots({ className }: { className?: string }) {
|
|
const { selectedIndex, api } = useCarousel()
|
|
const [scrollSnaps, setScrollSnaps] = useState<number[]>([])
|
|
|
|
// Update scroll snaps when the carousel is initialized or viewport changes
|
|
useEffect(() => {
|
|
if (!api) return
|
|
|
|
const onInit = () => {
|
|
setScrollSnaps(api.scrollSnapList())
|
|
}
|
|
|
|
onInit()
|
|
api.on("reInit", onInit)
|
|
|
|
return () => {
|
|
api.off("reInit", onInit)
|
|
}
|
|
}, [api])
|
|
|
|
// Don't render dots if we have 1 or fewer scroll positions
|
|
if (scrollSnaps.length <= 1) return null
|
|
|
|
return (
|
|
<div className={cx(styles.dots, className)}>
|
|
{scrollSnaps.map((_, index) => (
|
|
<div
|
|
key={index}
|
|
className={styles.dot}
|
|
data-active={index === selectedIndex}
|
|
aria-hidden="true"
|
|
/>
|
|
))}
|
|
</div>
|
|
)
|
|
}
|