Files
fotospiel-app/resources/js/components/ui/carousel.tsx

141 lines
3.6 KiB
TypeScript

"use client"
import * as React from "react"
import { ArrowLeft, ArrowRight } from "lucide-react"
import { Button } from "@/components/ui/button"
import { cn } from "@/lib/utils"
import Autoplay from "embla-carousel-autoplay"
import useEmblaCarousel from "embla-carousel-react"
interface CarouselApi {
slideNodes(): HTMLElement[]
on(event: string, listener: (...args: any[]) => void): void
scrollPrev(): void
scrollNext(): void
reInit(): void
}
const CarouselContext = React.createContext<CarouselApi | null>(null)
interface CarouselProps {
opts?: {
align?: "start" | "center" | "end"
loop?: boolean
}
plugins?: any[]
setApi?: (api: CarouselApi) => void
[key: string]: any
}
const Carousel = React.forwardRef<HTMLDivElement, CarouselProps>(
({ opts, plugins = [Autoplay()], setApi, className, children, ...props }, ref) => {
const [api, setApiInternal] = React.useState<CarouselApi | null>(null)
const [emblaRef] = useEmblaCarousel(opts, plugins)
React.useEffect(() => {
if (!api) {
return
}
setApi?.(api)
}, [api, setApi])
return (
<CarouselContext.Provider value={api}>
<div
ref={ref}
className={cn(
"relative w-full",
className
)}
{...props}
>
<div
className="overflow-hidden"
ref={emblaRef}
style={{ touchAction: 'pan-y pinch-zoom' }}
>
<div className="flex">{children}</div>
</div>
</div>
</CarouselContext.Provider>
)
}
)
Carousel.displayName = "Carousel"
interface CarouselContentProps {
children: React.ReactNode
className?: string
}
const CarouselContent = React.forwardRef<HTMLDivElement, CarouselContentProps>(
({ children, className }, ref) => (
<div ref={ref} className={cn("flex", className)}>
{children}
</div>
)
)
CarouselContent.displayName = "CarouselContent"
interface CarouselItemProps {
children: React.ReactNode
className?: string
}
const CarouselItem = React.forwardRef<HTMLDivElement, CarouselItemProps>(
({ children, className }, ref) => (
<div
ref={ref}
className={cn("min-w-0 shrink-0 grow-0 basis-full pl-4 md:pl-6", className)}
>
{children}
</div>
)
)
CarouselItem.displayName = "CarouselItem"
const CarouselPrevious = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, ...props }, ref) => (
<Button
ref={ref}
variant="outline"
size="icon"
className={cn(
"absolute -left-1 top-1/2 -translate-y-1/2 rounded-full h-8 w-8 bg-background/80 backdrop-blur-sm hover:bg-background/90 disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
>
<ArrowLeft className="h-4 w-4" />
<span className="sr-only">Previous slide</span>
</Button>
))
CarouselPrevious.displayName = "CarouselPrevious"
const CarouselNext = React.forwardRef<
HTMLButtonElement,
React.ButtonHTMLAttributes<HTMLButtonElement>
>(({ className, ...props }, ref) => (
<Button
ref={ref}
variant="outline"
size="icon"
className={cn(
"absolute -right-1 top-1/2 -translate-y-1/2 rounded-full h-8 w-8 bg-background/80 backdrop-blur-sm hover:bg-background/90 disabled:pointer-events-none disabled:opacity-50",
className
)}
{...props}
>
<ArrowRight className="h-4 w-4" />
<span className="sr-only">Next slide</span>
</Button>
))
CarouselNext.displayName = "CarouselNext"
export { Carousel, CarouselContent, CarouselItem, CarouselPrevious, CarouselNext }