{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "carousel",
  "title": "Carousel",
  "description": "A carousel with motion and swipe built using Embla.",
  "dependencies": [
    "embla-carousel-react",
    "lucide-react",
    "clsx",
    "tailwind-merge"
  ],
  "registryDependencies": [
    "https://optics.agusmayol.com.ar/r/button.json",
    "https://optics.agusmayol.com.ar/r/utils.json"
  ],
  "files": [
    {
      "path": "registry/optics/carousel.jsx",
      "content": "\"use client\";\nimport * as React from \"react\";\nimport useEmblaCarousel from \"embla-carousel-react\";\n\nimport { cn } from \"@/lib/utils\";\nimport { Button } from \"@/registry/optics/button\";\nimport { ChevronLeftIcon, ChevronRightIcon } from \"lucide-react\";\n\nconst CarouselContext = React.createContext(null);\n\nfunction useCarousel() {\n\tconst context = React.useContext(CarouselContext);\n\n\tif (!context) {\n\t\tthrow new Error(\"useCarousel must be used within a <Carousel />\");\n\t}\n\n\treturn context;\n}\n\nfunction Carousel({\n\torientation = \"horizontal\",\n\topts = {},\n\tsetApi = undefined,\n\tplugins = [],\n\tclassName = \"\",\n\tchildren = null,\n\t...props\n}) {\n\tconst [carouselRef, api] = useEmblaCarousel(\n\t\t{\n\t\t\t...opts,\n\t\t\taxis: orientation === \"horizontal\" ? \"x\" : \"y\",\n\t\t},\n\t\tplugins,\n\t);\n\tconst [canScrollPrev, setCanScrollPrev] = React.useState(false);\n\tconst [canScrollNext, setCanScrollNext] = React.useState(false);\n\n\tconst onSelect = React.useCallback((api) => {\n\t\tif (!api) return;\n\t\tsetCanScrollPrev(api.canScrollPrev());\n\t\tsetCanScrollNext(api.canScrollNext());\n\t}, []);\n\n\tconst scrollPrev = React.useCallback(() => {\n\t\tapi?.scrollPrev();\n\t}, [api]);\n\n\tconst scrollNext = React.useCallback(() => {\n\t\tapi?.scrollNext();\n\t}, [api]);\n\n\tconst handleKeyDown = React.useCallback(\n\t\t(event) => {\n\t\t\tif (event.key === \"ArrowLeft\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tscrollPrev();\n\t\t\t} else if (event.key === \"ArrowRight\") {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tscrollNext();\n\t\t\t}\n\t\t},\n\t\t[scrollPrev, scrollNext],\n\t);\n\n\tReact.useEffect(() => {\n\t\tif (!api || !setApi) return;\n\t\tsetApi(api);\n\t}, [api, setApi]);\n\n\tReact.useEffect(() => {\n\t\tif (!api) return;\n\t\tonSelect(api);\n\t\tapi.on(\"reInit\", onSelect);\n\t\tapi.on(\"select\", onSelect);\n\n\t\treturn () => {\n\t\t\tapi?.off(\"select\", onSelect);\n\t\t};\n\t}, [api, onSelect]);\n\n\treturn (\n\t\t<CarouselContext.Provider\n\t\t\tvalue={{\n\t\t\t\tcarouselRef,\n\t\t\t\tapi: api,\n\t\t\t\topts,\n\t\t\t\torientation:\n\t\t\t\t\torientation || (opts?.axis === \"y\" ? \"vertical\" : \"horizontal\"),\n\t\t\t\tscrollPrev,\n\t\t\t\tscrollNext,\n\t\t\t\tcanScrollPrev,\n\t\t\t\tcanScrollNext,\n\t\t\t}}\n\t\t>\n\t\t\t<div\n\t\t\t\tonKeyDownCapture={handleKeyDown}\n\t\t\t\tclassName={cn(\"relative\", className)}\n\t\t\t\trole=\"region\"\n\t\t\t\taria-roledescription=\"carousel\"\n\t\t\t\tdata-slot=\"carousel\"\n\t\t\t\t{...props}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</div>\n\t\t</CarouselContext.Provider>\n\t);\n}\n\nfunction CarouselContent({ className = \"\", ...props }) {\n\tconst { carouselRef, orientation } = useCarousel();\n\n\treturn (\n\t\t<div\n\t\t\tref={carouselRef}\n\t\t\tclassName=\"overflow-hidden\"\n\t\t\tdata-slot=\"carousel-content\"\n\t\t>\n\t\t\t<div\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"flex\",\n\t\t\t\t\torientation === \"horizontal\" ? \"-ml-4\" : \"-mt-4 flex-col\",\n\t\t\t\t\tclassName,\n\t\t\t\t)}\n\t\t\t\t{...props}\n\t\t\t/>\n\t\t</div>\n\t);\n}\n\nfunction CarouselItem({ className = \"\", ...props }) {\n\tconst { orientation } = useCarousel();\n\n\treturn (\n\t\t<div\n\t\t\trole=\"group\"\n\t\t\taria-roledescription=\"slide\"\n\t\t\tdata-slot=\"carousel-item\"\n\t\t\tclassName={cn(\n\t\t\t\t\"min-w-0 shrink-0 grow-0 basis-full\",\n\t\t\t\torientation === \"horizontal\" ? \"pl-4\" : \"pt-4\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nfunction CarouselPrevious({\n\tclassName = \"\",\n\tvariant = \"outline\",\n\tsize = \"icon-sm\",\n\t...props\n}) {\n\tconst { orientation, scrollPrev, canScrollPrev } = useCarousel();\n\n\treturn (\n\t\t<Button\n\t\t\tdata-slot=\"carousel-previous\"\n\t\t\tvariant={variant}\n\t\t\tsize={size}\n\t\t\tclassName={cn(\n\t\t\t\t\"rounded-full squircle-none absolute touch-manipulation\",\n\t\t\t\torientation === \"horizontal\"\n\t\t\t\t\t? \"top-1/2 -left-12 -translate-y-1/2\"\n\t\t\t\t\t: \"-top-12 left-1/2 -translate-x-1/2 rotate-90\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tdisabled={!canScrollPrev}\n\t\t\tonClick={scrollPrev}\n\t\t\t{...props}\n\t\t>\n\t\t\t<ChevronLeftIcon />\n\t\t\t<span className=\"sr-only\">Previous slide</span>\n\t\t</Button>\n\t);\n}\n\nfunction CarouselNext({\n\tclassName = \"\",\n\tvariant = \"outline\",\n\tsize = \"icon-sm\",\n\t...props\n}) {\n\tconst { orientation, scrollNext, canScrollNext } = useCarousel();\n\n\treturn (\n\t\t<Button\n\t\t\tdata-slot=\"carousel-next\"\n\t\t\tvariant={variant}\n\t\t\tsize={size}\n\t\t\tclassName={cn(\n\t\t\t\t\"rounded-full squircle-none absolute touch-manipulation\",\n\t\t\t\torientation === \"horizontal\"\n\t\t\t\t\t? \"top-1/2 -right-12 -translate-y-1/2\"\n\t\t\t\t\t: \"-bottom-12 left-1/2 -translate-x-1/2 rotate-90\",\n\t\t\t\tclassName,\n\t\t\t)}\n\t\t\tdisabled={!canScrollNext}\n\t\t\tonClick={scrollNext}\n\t\t\t{...props}\n\t\t>\n\t\t\t<ChevronRightIcon />\n\t\t\t<span className=\"sr-only\">Next slide</span>\n\t\t</Button>\n\t);\n}\n\nCarousel.displayName = \"Carousel\";\nCarouselContent.displayName = \"CarouselContent\";\nCarouselItem.displayName = \"CarouselItem\";\nCarouselPrevious.displayName = \"CarouselPrevious\";\nCarouselNext.displayName = \"CarouselNext\";\n\nexport {\n\tCarousel,\n\tCarouselContent,\n\tCarouselItem,\n\tCarouselPrevious,\n\tCarouselNext,\n\tuseCarousel,\n};\n",
      "type": "registry:component",
      "target": "components/optics/carousel.jsx"
    }
  ],
  "type": "registry:component"
}