CoolFace
Apppublic

huggingface/ai-deadlines

sourceHugging Faceupdated 3d agoView on Hugging Face
781likes
carousel.tsx261 linesDownload Raw Back to ui
1import * as React from "react"2import useEmblaCarousel, {3  type UseEmblaCarouselType,4} from "embla-carousel-react"5import { ArrowLeft, ArrowRight } from "lucide-react"6 7import { cn } from "@/lib/utils"8import { Button } from "@/components/ui/button"9 10type CarouselApi = UseEmblaCarouselType[1]11type UseCarouselParameters = Parameters<typeof useEmblaCarousel>12type CarouselOptions = UseCarouselParameters[0]13type CarouselPlugin = UseCarouselParameters[1]14 15type CarouselProps = {16  opts?: CarouselOptions17  plugins?: CarouselPlugin18  orientation?: "horizontal" | "vertical"19  setApi?: (api: CarouselApi) => void20}21 22type CarouselContextProps = {23  carouselRef: ReturnType<typeof useEmblaCarousel>[0]24  api: ReturnType<typeof useEmblaCarousel>[1]25  scrollPrev: () => void26  scrollNext: () => void27  canScrollPrev: boolean28  canScrollNext: boolean29} & CarouselProps30 31const CarouselContext = React.createContext<CarouselContextProps | null>(null)32 33function useCarousel() {34  const context = React.useContext(CarouselContext)35 36  if (!context) {37    throw new Error("useCarousel must be used within a <Carousel />")38  }39 40  return context41}42 43const Carousel = React.forwardRef<44  HTMLDivElement,45  React.HTMLAttributes<HTMLDivElement> & CarouselProps46>(47  (48    {49      orientation = "horizontal",50      opts,51      setApi,52      plugins,53      className,54      children,55      ...props56    },57    ref58  ) => {59    const [carouselRef, api] = useEmblaCarousel(60      {61        ...opts,62        axis: orientation === "horizontal" ? "x" : "y",63      },64      plugins65    )66    const [canScrollPrev, setCanScrollPrev] = React.useState(false)67    const [canScrollNext, setCanScrollNext] = React.useState(false)68 69    const onSelect = React.useCallback((api: CarouselApi) => {70      if (!api) {71        return72      }73 74      setCanScrollPrev(api.canScrollPrev())75      setCanScrollNext(api.canScrollNext())76    }, [])77 78    const scrollPrev = React.useCallback(() => {79      api?.scrollPrev()80    }, [api])81 82    const scrollNext = React.useCallback(() => {83      api?.scrollNext()84    }, [api])85 86    const handleKeyDown = React.useCallback(87      (event: React.KeyboardEvent<HTMLDivElement>) => {88        if (event.key === "ArrowLeft") {89          event.preventDefault()90          scrollPrev()91        } else if (event.key === "ArrowRight") {92          event.preventDefault()93          scrollNext()94        }95      },96      [scrollPrev, scrollNext]97    )98 99    React.useEffect(() => {100      if (!api || !setApi) {101        return102      }103 104      setApi(api)105    }, [api, setApi])106 107    React.useEffect(() => {108      if (!api) {109        return110      }111 112      onSelect(api)113      api.on("reInit", onSelect)114      api.on("select", onSelect)115 116      return () => {117        api?.off("select", onSelect)118      }119    }, [api, onSelect])120 121    return (122      <CarouselContext.Provider123        value={{124          carouselRef,125          api: api,126          opts,127          orientation:128            orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),129          scrollPrev,130          scrollNext,131          canScrollPrev,132          canScrollNext,133        }}134      >135        <div136          ref={ref}137          onKeyDownCapture={handleKeyDown}138          className={cn("relative", className)}139          role="region"140          aria-roledescription="carousel"141          {...props}142        >143          {children}144        </div>145      </CarouselContext.Provider>146    )147  }148)149Carousel.displayName = "Carousel"150 151const CarouselContent = React.forwardRef<152  HTMLDivElement,153  React.HTMLAttributes<HTMLDivElement>154>(({ className, ...props }, ref) => {155  const { carouselRef, orientation } = useCarousel()156 157  return (158    <div ref={carouselRef} className="overflow-hidden">159      <div160        ref={ref}161        className={cn(162          "flex",163          orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",164          className165        )}166        {...props}167      />168    </div>169  )170})171CarouselContent.displayName = "CarouselContent"172 173const CarouselItem = React.forwardRef<174  HTMLDivElement,175  React.HTMLAttributes<HTMLDivElement>176>(({ className, ...props }, ref) => {177  const { orientation } = useCarousel()178 179  return (180    <div181      ref={ref}182      role="group"183      aria-roledescription="slide"184      className={cn(185        "min-w-0 shrink-0 grow-0 basis-full",186        orientation === "horizontal" ? "pl-4" : "pt-4",187        className188      )}189      {...props}190    />191  )192})193CarouselItem.displayName = "CarouselItem"194 195const CarouselPrevious = React.forwardRef<196  HTMLButtonElement,197  React.ComponentProps<typeof Button>198>(({ className, variant = "outline", size = "icon", ...props }, ref) => {199  const { orientation, scrollPrev, canScrollPrev } = useCarousel()200 201  return (202    <Button203      ref={ref}204      variant={variant}205      size={size}206      className={cn(207        "absolute  h-8 w-8 rounded-full",208        orientation === "horizontal"209          ? "-left-12 top-1/2 -translate-y-1/2"210          : "-top-12 left-1/2 -translate-x-1/2 rotate-90",211        className212      )}213      disabled={!canScrollPrev}214      onClick={scrollPrev}215      {...props}216    >217      <ArrowLeft className="h-4 w-4" />218      <span className="sr-only">Previous slide</span>219    </Button>220  )221})222CarouselPrevious.displayName = "CarouselPrevious"223 224const CarouselNext = React.forwardRef<225  HTMLButtonElement,226  React.ComponentProps<typeof Button>227>(({ className, variant = "outline", size = "icon", ...props }, ref) => {228  const { orientation, scrollNext, canScrollNext } = useCarousel()229 230  return (231    <Button232      ref={ref}233      variant={variant}234      size={size}235      className={cn(236        "absolute h-8 w-8 rounded-full",237        orientation === "horizontal"238          ? "-right-12 top-1/2 -translate-y-1/2"239          : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",240        className241      )}242      disabled={!canScrollNext}243      onClick={scrollNext}244      {...props}245    >246      <ArrowRight className="h-4 w-4" />247      <span className="sr-only">Next slide</span>248    </Button>249  )250})251CarouselNext.displayName = "CarouselNext"252 253export {254  type CarouselApi,255  Carousel,256  CarouselContent,257  CarouselItem,258  CarouselPrevious,259  CarouselNext,260}261