Merged in feat/SW-1542-carousel-functionality (pull request #1311)
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
This commit is contained in:
108
components/Carousel/index.tsx
Normal file
108
components/Carousel/index.tsx
Normal file
@@ -0,0 +1,108 @@
|
||||
"use client"
|
||||
|
||||
import { cx } from "class-variance-authority"
|
||||
import useEmblaCarousel from "embla-carousel-react"
|
||||
import { useCallback, useEffect, useState } from "react"
|
||||
|
||||
import { CarouselContent } from "./CarouselContent"
|
||||
import { CarouselContext } from "./CarouselContext"
|
||||
import { CarouselDots } from "./CarouselDots"
|
||||
import { CarouselItem } from "./CarouselItem"
|
||||
import { CarouselNext, CarouselPrevious } from "./CarouselNavigation"
|
||||
|
||||
import styles from "./carousel.module.css"
|
||||
|
||||
import type { CarouselApi, CarouselProps } from "./types"
|
||||
|
||||
function Carousel({
|
||||
opts,
|
||||
setApi,
|
||||
plugins,
|
||||
className,
|
||||
children,
|
||||
}: CarouselProps) {
|
||||
const [carouselRef, api] = useEmblaCarousel(
|
||||
{
|
||||
...opts,
|
||||
axis: "x",
|
||||
},
|
||||
plugins
|
||||
)
|
||||
const [selectedIndex, setSelectedIndex] = useState(0)
|
||||
|
||||
const onSelect = useCallback((api: CarouselApi) => {
|
||||
if (!api) return
|
||||
setSelectedIndex(api.selectedScrollSnap())
|
||||
}, [])
|
||||
|
||||
function scrollPrev() {
|
||||
api?.scrollPrev()
|
||||
}
|
||||
|
||||
function scrollNext() {
|
||||
api?.scrollNext()
|
||||
}
|
||||
|
||||
function handleKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
|
||||
if (event.key === "ArrowLeft") {
|
||||
event.preventDefault()
|
||||
scrollPrev()
|
||||
} else if (event.key === "ArrowRight") {
|
||||
event.preventDefault()
|
||||
scrollNext()
|
||||
}
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
if (!api || !setApi) return
|
||||
setApi(api)
|
||||
}, [api, setApi])
|
||||
|
||||
useEffect(() => {
|
||||
if (!api) return
|
||||
|
||||
onSelect(api)
|
||||
api.on("reInit", onSelect)
|
||||
api.on("select", onSelect)
|
||||
|
||||
return () => {
|
||||
api.off("select", onSelect)
|
||||
}
|
||||
}, [api, onSelect])
|
||||
|
||||
return (
|
||||
<CarouselContext.Provider
|
||||
value={{
|
||||
carouselRef,
|
||||
api,
|
||||
opts,
|
||||
plugins,
|
||||
setApi,
|
||||
children,
|
||||
scrollPrev,
|
||||
scrollNext,
|
||||
canScrollPrev: api?.canScrollPrev.bind(api) ?? (() => false),
|
||||
canScrollNext: api?.canScrollNext.bind(api) ?? (() => false),
|
||||
selectedIndex,
|
||||
}}
|
||||
>
|
||||
<div
|
||||
onKeyDownCapture={handleKeyDown}
|
||||
className={cx(styles.root, className)}
|
||||
role="region"
|
||||
aria-roledescription="carousel"
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</CarouselContext.Provider>
|
||||
)
|
||||
}
|
||||
|
||||
Carousel.Content = CarouselContent
|
||||
Carousel.Item = CarouselItem
|
||||
Carousel.Next = CarouselNext
|
||||
Carousel.Previous = CarouselPrevious
|
||||
Carousel.Dots = CarouselDots
|
||||
|
||||
export { Carousel }
|
||||
export type { CarouselApi }
|
||||
Reference in New Issue
Block a user