@opensite/ui 0.7.9 → 0.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/registry.js CHANGED
@@ -17950,192 +17950,49 @@ function CarouselAutoplayProgress({
17950
17950
  }
17951
17951
  );
17952
17952
  }
17953
- var CarouselContext = React52.createContext(null);
17954
- function useCarousel() {
17955
- const context = React52.useContext(CarouselContext);
17956
- if (!context) {
17957
- throw new Error("useCarousel must be used within a <Carousel />");
17958
- }
17959
- return context;
17960
- }
17961
- function Carousel({
17962
- orientation = "horizontal",
17963
- opts,
17964
- setApi,
17965
- plugins,
17953
+ function CarouselPagination({
17954
+ onPrevious,
17955
+ onNext,
17956
+ canScrollPrevious = true,
17957
+ canScrollNext = true,
17958
+ iconSize = 24,
17966
17959
  className,
17967
- children,
17968
- ...props
17960
+ buttonClassName,
17961
+ previousIcon = "lucide/arrow-left",
17962
+ nextIcon = "lucide/arrow-right",
17963
+ previousAriaLabel = "Previous",
17964
+ nextAriaLabel = "Next"
17969
17965
  }) {
17970
- const [carouselRef, api] = useEmblaCarousel(
17971
- {
17972
- ...opts,
17973
- axis: orientation === "horizontal" ? "x" : "y"
17974
- },
17975
- plugins
17976
- );
17977
- const [canScrollPrev, setCanScrollPrev] = React52.useState(false);
17978
- const [canScrollNext, setCanScrollNext] = React52.useState(false);
17979
- const onSelect = React52.useCallback((api2) => {
17980
- if (!api2) return;
17981
- setCanScrollPrev(api2.canScrollPrev());
17982
- setCanScrollNext(api2.canScrollNext());
17983
- }, []);
17984
- const scrollPrev = React52.useCallback(() => {
17985
- api?.scrollPrev();
17986
- }, [api]);
17987
- const scrollNext = React52.useCallback(() => {
17988
- api?.scrollNext();
17989
- }, [api]);
17990
- const handleKeyDown = React52.useCallback(
17991
- (event) => {
17992
- if (event.key === "ArrowLeft") {
17993
- event.preventDefault();
17994
- scrollPrev();
17995
- } else if (event.key === "ArrowRight") {
17996
- event.preventDefault();
17997
- scrollNext();
17966
+ return /* @__PURE__ */ jsxs("div", { className: cn("flex justify-end gap-2", className), children: [
17967
+ /* @__PURE__ */ jsx(
17968
+ Pressable,
17969
+ {
17970
+ onClick: onPrevious,
17971
+ disabled: !canScrollPrevious,
17972
+ "aria-label": previousAriaLabel,
17973
+ asButton: true,
17974
+ className: cn(
17975
+ "relative z-40 flex h-10 w-10 items-center justify-center rounded-full disabled:opacity-50",
17976
+ buttonClassName
17977
+ ),
17978
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: previousIcon, size: iconSize })
17998
17979
  }
17999
- },
18000
- [scrollPrev, scrollNext]
18001
- );
18002
- React52.useEffect(() => {
18003
- if (!api || !setApi) return;
18004
- setApi(api);
18005
- }, [api, setApi]);
18006
- React52.useEffect(() => {
18007
- if (!api) return;
18008
- onSelect(api);
18009
- api.on("reInit", onSelect);
18010
- api.on("select", onSelect);
18011
- return () => {
18012
- api?.off("select", onSelect);
18013
- };
18014
- }, [api, onSelect]);
18015
- return /* @__PURE__ */ jsx(
18016
- CarouselContext.Provider,
18017
- {
18018
- value: {
18019
- carouselRef,
18020
- api,
18021
- opts,
18022
- orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
18023
- scrollPrev,
18024
- scrollNext,
18025
- canScrollPrev,
18026
- canScrollNext
18027
- },
18028
- children: /* @__PURE__ */ jsx(
18029
- "div",
18030
- {
18031
- onKeyDownCapture: handleKeyDown,
18032
- className: cn("relative", className),
18033
- role: "region",
18034
- "aria-roledescription": "carousel",
18035
- "data-slot": "carousel",
18036
- ...props,
18037
- children
18038
- }
18039
- )
18040
- }
18041
- );
18042
- }
18043
- function CarouselContent({ className, ...props }) {
18044
- const { carouselRef, orientation } = useCarousel();
18045
- return /* @__PURE__ */ jsx(
18046
- "div",
18047
- {
18048
- ref: carouselRef,
18049
- className: "overflow-hidden",
18050
- "data-slot": "carousel-content",
18051
- children: /* @__PURE__ */ jsx(
18052
- "div",
18053
- {
18054
- className: cn(
18055
- "flex",
18056
- orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
18057
- className
18058
- ),
18059
- ...props
18060
- }
18061
- )
18062
- }
18063
- );
18064
- }
18065
- function CarouselItem({ className, ...props }) {
18066
- const { orientation } = useCarousel();
18067
- return /* @__PURE__ */ jsx(
18068
- "div",
18069
- {
18070
- role: "group",
18071
- "aria-roledescription": "slide",
18072
- "data-slot": "carousel-item",
18073
- className: cn(
18074
- "min-w-0 shrink-0 grow-0 basis-full",
18075
- orientation === "horizontal" ? "pl-4" : "pt-4",
18076
- className
18077
- ),
18078
- ...props
18079
- }
18080
- );
18081
- }
18082
- function CarouselPrevious({
18083
- className,
18084
- variant = "outline",
18085
- size = "icon",
18086
- ...props
18087
- }) {
18088
- const { orientation, scrollPrev, canScrollPrev } = useCarousel();
18089
- return /* @__PURE__ */ jsxs(
18090
- Pressable,
18091
- {
18092
- "data-slot": "carousel-previous",
18093
- variant,
18094
- size,
18095
- className: cn(
18096
- "absolute size-8 rounded-full",
18097
- orientation === "horizontal" ? "top-1/2 -left-12 -translate-y-1/2" : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
18098
- className
18099
- ),
18100
- disabled: !canScrollPrev,
18101
- onClick: scrollPrev,
18102
- asButton: true,
18103
- ...props,
18104
- children: [
18105
- /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-left" }),
18106
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Previous slide" })
18107
- ]
18108
- }
18109
- );
18110
- }
18111
- function CarouselNext({
18112
- className,
18113
- variant = "outline",
18114
- size = "icon",
18115
- ...props
18116
- }) {
18117
- const { orientation, scrollNext, canScrollNext } = useCarousel();
18118
- return /* @__PURE__ */ jsxs(
18119
- Pressable,
18120
- {
18121
- "data-slot": "carousel-next",
18122
- variant,
18123
- size,
18124
- className: cn(
18125
- "absolute size-8 rounded-full",
18126
- orientation === "horizontal" ? "top-1/2 -right-12 -translate-y-1/2" : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
18127
- className
18128
- ),
18129
- disabled: !canScrollNext,
18130
- onClick: scrollNext,
18131
- asButton: true,
18132
- ...props,
18133
- children: [
18134
- /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right" }),
18135
- /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Next slide" })
18136
- ]
18137
- }
18138
- );
17980
+ ),
17981
+ /* @__PURE__ */ jsx(
17982
+ Pressable,
17983
+ {
17984
+ onClick: onNext,
17985
+ disabled: !canScrollNext,
17986
+ "aria-label": nextAriaLabel,
17987
+ asButton: true,
17988
+ className: cn(
17989
+ "relative z-40 flex h-10 w-10 items-center justify-center rounded-full disabled:opacity-50",
17990
+ buttonClassName
17991
+ ),
17992
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: nextIcon, size: iconSize })
17993
+ }
17994
+ )
17995
+ ] });
18139
17996
  }
18140
17997
  var SLIDE_LAYOUT_ASPECT_MAP = {
18141
17998
  horizontal: "aspect-video",
@@ -18164,27 +18021,62 @@ function CarouselFeatureBadge({
18164
18021
  slideLayoutVariant = "square",
18165
18022
  containerMaxWidth = "2xl"
18166
18023
  }) {
18024
+ const [emblaRef, emblaApi] = useEmblaCarousel();
18025
+ const [canScrollPrev, setCanScrollPrev] = React52.useState(false);
18026
+ const [canScrollNext, setCanScrollNext] = React52.useState(false);
18027
+ const scrollPrev = React52.useCallback(() => {
18028
+ emblaApi?.scrollPrev();
18029
+ }, [emblaApi]);
18030
+ const scrollNext = React52.useCallback(() => {
18031
+ emblaApi?.scrollNext();
18032
+ }, [emblaApi]);
18033
+ const onSelect = React52.useCallback(() => {
18034
+ if (!emblaApi) return;
18035
+ setCanScrollPrev(emblaApi.canScrollPrev());
18036
+ setCanScrollNext(emblaApi.canScrollNext());
18037
+ }, [emblaApi]);
18038
+ React52.useEffect(() => {
18039
+ if (!emblaApi) return;
18040
+ onSelect();
18041
+ emblaApi.on("reInit", onSelect);
18042
+ emblaApi.on("select", onSelect);
18043
+ return () => {
18044
+ emblaApi?.off("select", onSelect);
18045
+ };
18046
+ }, [emblaApi, onSelect]);
18167
18047
  const renderCarouselItems = () => {
18168
18048
  if (itemsSlot) return itemsSlot;
18169
18049
  if (!items || items.length === 0) return null;
18170
- return items.map((item, index) => /* @__PURE__ */ jsx(CarouselItem, { className: carouselItemClassName, children: /* @__PURE__ */ jsx(
18050
+ return items.map((item, index) => /* @__PURE__ */ jsx(
18171
18051
  "div",
18172
18052
  {
18053
+ role: "group",
18054
+ "aria-roledescription": "slide",
18173
18055
  className: cn(
18174
- "flex items-center justify-center overflow-hidden rounded-2xl",
18175
- SLIDE_LAYOUT_ASPECT_MAP[slideLayoutVariant]
18056
+ "min-w-0 shrink-0 grow-0 basis-full pl-4",
18057
+ carouselItemClassName
18176
18058
  ),
18177
18059
  children: /* @__PURE__ */ jsx(
18178
- Img,
18060
+ "div",
18179
18061
  {
18180
- src: item.src,
18181
- alt: item.alt,
18182
- className: cn("h-full w-full object-cover", item.className),
18183
- optixFlowConfig
18062
+ className: cn(
18063
+ "flex items-center justify-center overflow-hidden rounded-2xl",
18064
+ SLIDE_LAYOUT_ASPECT_MAP[slideLayoutVariant]
18065
+ ),
18066
+ children: /* @__PURE__ */ jsx(
18067
+ Img,
18068
+ {
18069
+ src: item.src,
18070
+ alt: item.alt,
18071
+ className: cn("h-full w-full object-cover", item.className),
18072
+ optixFlowConfig
18073
+ }
18074
+ )
18184
18075
  }
18185
18076
  )
18186
- }
18187
- ) }, index));
18077
+ },
18078
+ index
18079
+ ));
18188
18080
  };
18189
18081
  return /* @__PURE__ */ jsx(
18190
18082
  Section,
@@ -18227,10 +18119,18 @@ function CarouselFeatureBadge({
18227
18119
  ]
18228
18120
  }
18229
18121
  ),
18230
- /* @__PURE__ */ jsx("div", { className: cn("w-full max-w-full px-6", carouselClassName), children: /* @__PURE__ */ jsxs(Carousel, { children: [
18231
- /* @__PURE__ */ jsx(CarouselContent, { children: renderCarouselItems() }),
18232
- /* @__PURE__ */ jsx(CarouselPrevious, {}),
18233
- /* @__PURE__ */ jsx(CarouselNext, {})
18122
+ /* @__PURE__ */ jsx("div", { className: cn("w-full max-w-full", carouselClassName), children: /* @__PURE__ */ jsxs("div", { className: "relative", children: [
18123
+ /* @__PURE__ */ jsx("div", { ref: emblaRef, className: "overflow-hidden", children: /* @__PURE__ */ jsx("div", { className: "flex -ml-4", children: renderCarouselItems() }) }),
18124
+ /* @__PURE__ */ jsx(
18125
+ CarouselPagination,
18126
+ {
18127
+ onPrevious: scrollPrev,
18128
+ onNext: scrollNext,
18129
+ canScrollPrevious: canScrollPrev,
18130
+ canScrollNext,
18131
+ className: "mt-4"
18132
+ }
18133
+ )
18234
18134
  ] }) })
18235
18135
  ] }) })
18236
18136
  }
@@ -18652,28 +18552,22 @@ function CarouselHorizontalCards({
18652
18552
  const carouselRef = React52.useRef(null);
18653
18553
  const [isAtStart, setIsAtStart] = React52.useState(true);
18654
18554
  const [isAtEnd, setIsAtEnd] = React52.useState(false);
18655
- const getCardWidth = React52.useCallback(() => {
18656
- if (typeof window === "undefined") return 320;
18657
- if (window.innerWidth >= 1024) return 400;
18658
- if (window.innerWidth >= 640) return 360;
18659
- return 320;
18660
- }, []);
18661
- const scroll = (direction) => {
18555
+ const scrollLeft = () => {
18662
18556
  if (carouselRef.current) {
18663
- const { scrollLeft } = carouselRef.current;
18664
- const cardWidth = getCardWidth();
18665
- const gap = 16;
18666
- const scrollAmount = cardWidth + gap;
18667
- const newScrollLeft = direction === "left" ? scrollLeft - scrollAmount : scrollLeft + scrollAmount;
18668
- carouselRef.current.scrollTo({ left: newScrollLeft, behavior: "smooth" });
18557
+ carouselRef.current.scrollBy({ left: -300, behavior: "smooth" });
18558
+ }
18559
+ };
18560
+ const scrollRight = () => {
18561
+ if (carouselRef.current) {
18562
+ carouselRef.current.scrollBy({ left: 300, behavior: "smooth" });
18669
18563
  }
18670
18564
  };
18671
18565
  React52.useEffect(() => {
18672
18566
  const checkScrollPosition = () => {
18673
18567
  if (carouselRef.current) {
18674
- const { scrollLeft, scrollWidth, clientWidth } = carouselRef.current;
18675
- setIsAtStart(scrollLeft < 10);
18676
- setIsAtEnd(scrollLeft + clientWidth >= scrollWidth - 10);
18568
+ const { scrollLeft: scrollLeft2, scrollWidth, clientWidth } = carouselRef.current;
18569
+ setIsAtStart(scrollLeft2 < 10);
18570
+ setIsAtEnd(scrollLeft2 + clientWidth >= scrollWidth - 10);
18677
18571
  }
18678
18572
  };
18679
18573
  const currentRef = carouselRef.current;
@@ -18689,41 +18583,6 @@ function CarouselHorizontalCards({
18689
18583
  window.removeEventListener("resize", checkScrollPosition);
18690
18584
  };
18691
18585
  }, [items]);
18692
- const renderItems = () => {
18693
- if (itemsSlot) return itemsSlot;
18694
- if (!items || items.length === 0) return null;
18695
- return items.map((item, index) => /* @__PURE__ */ jsx(
18696
- motion.div,
18697
- {
18698
- className: cn(
18699
- "group w-[320px] shrink-0 snap-start sm:w-[360px] lg:w-[400px]",
18700
- item.className
18701
- ),
18702
- initial: { opacity: 0, y: 20 },
18703
- animate: { opacity: 1, y: 0 },
18704
- transition: { duration: 0.5, delay: index * 0.1 },
18705
- children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-md", children: [
18706
- /* @__PURE__ */ jsx(
18707
- Img,
18708
- {
18709
- alt: typeof item.title === "string" ? item.title : `Card ${index + 1}`,
18710
- className: cn("aspect-video w-full object-cover transition-transform group-hover:scale-105", item.imageClassName),
18711
- src: item.imageSrc,
18712
- optixFlowConfig
18713
- }
18714
- ),
18715
- /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
18716
- item.title && (typeof item.title === "string" ? /* @__PURE__ */ jsx("h3", { className: "text-md font-semibold leading-tight text-card-foreground", children: item.title }) : /* @__PURE__ */ jsx("div", { children: item.title })),
18717
- (item.count !== void 0 || item.countLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
18718
- item.count !== void 0 && /* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children: item.count }),
18719
- item.countLabel && (typeof item.countLabel === "string" ? /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: item.countLabel }) : /* @__PURE__ */ jsx("div", { children: item.countLabel }))
18720
- ] })
18721
- ] })
18722
- ] })
18723
- },
18724
- item.id
18725
- ));
18726
- };
18727
18586
  return /* @__PURE__ */ jsx(
18728
18587
  Section,
18729
18588
  {
@@ -18734,74 +18593,143 @@ function CarouselHorizontalCards({
18734
18593
  patternOpacity,
18735
18594
  "aria-labelledby": "carousel-title",
18736
18595
  children: /* @__PURE__ */ jsxs("div", { className: cn("container mx-auto px-4 md:px-6", containerClassName), children: [
18737
- /* @__PURE__ */ jsx("div", { className: cn("mb-8 flex items-center justify-between gap-4", headerClassName), children: /* @__PURE__ */ jsxs("div", { children: [
18738
- heading && /* @__PURE__ */ jsxs("a", { href: headingHref, className: "group inline-flex items-center", children: [
18739
- typeof heading === "string" ? /* @__PURE__ */ jsx(
18740
- "h2",
18741
- {
18742
- id: "carousel-title",
18743
- className: cn("text-2xl font-bold tracking-tight text-card-foreground md:text-3xl", headingClassName),
18744
- children: heading
18745
- }
18746
- ) : /* @__PURE__ */ jsx("div", { className: headingClassName, children: heading }),
18747
- /* @__PURE__ */ jsx(
18748
- DynamicIcon,
18749
- {
18750
- name: "lucide/chevron-right",
18751
- size: 24,
18752
- className: "ml-2 flex-shrink-0 self-center transition-transform group-hover:translate-x-1"
18753
- }
18754
- )
18755
- ] }),
18756
- subtitle && (typeof subtitle === "string" ? /* @__PURE__ */ jsx("p", { className: cn("mt-1 text-muted-foreground", subtitleClassName), children: subtitle }) : /* @__PURE__ */ jsx("div", { className: subtitleClassName, children: subtitle }))
18757
- ] }) }),
18758
- /* @__PURE__ */ jsxs("div", { className: "relative", children: [
18596
+ /* @__PURE__ */ jsx(
18597
+ "div",
18598
+ {
18599
+ className: cn(
18600
+ "mb-8 flex items-center justify-between gap-4",
18601
+ headerClassName
18602
+ ),
18603
+ children: /* @__PURE__ */ jsxs("div", { children: [
18604
+ heading && /* @__PURE__ */ jsxs("a", { href: headingHref, className: "group inline-flex items-center", children: [
18605
+ typeof heading === "string" ? /* @__PURE__ */ jsx(
18606
+ "h2",
18607
+ {
18608
+ id: "carousel-title",
18609
+ className: cn(
18610
+ "text-2xl font-bold tracking-tight text-card-foreground md:text-3xl",
18611
+ headingClassName
18612
+ ),
18613
+ children: heading
18614
+ }
18615
+ ) : /* @__PURE__ */ jsx("div", { className: headingClassName, children: heading }),
18616
+ /* @__PURE__ */ jsx(
18617
+ DynamicIcon,
18618
+ {
18619
+ name: "lucide/chevron-right",
18620
+ size: 24,
18621
+ className: "ml-2 shrink-0 self-center transition-transform group-hover:translate-x-1"
18622
+ }
18623
+ )
18624
+ ] }),
18625
+ subtitle && (typeof subtitle === "string" ? /* @__PURE__ */ jsx(
18626
+ "p",
18627
+ {
18628
+ className: cn(
18629
+ "mt-1 text-muted-foreground",
18630
+ subtitleClassName
18631
+ ),
18632
+ children: subtitle
18633
+ }
18634
+ ) : /* @__PURE__ */ jsx("div", { className: subtitleClassName, children: subtitle }))
18635
+ ] })
18636
+ }
18637
+ ),
18638
+ /* @__PURE__ */ jsxs("div", { className: "relative w-full", children: [
18759
18639
  /* @__PURE__ */ jsx(
18760
18640
  "div",
18761
18641
  {
18642
+ className: "flex w-full overflow-x-scroll overscroll-x-auto scroll-smooth py-4 [scrollbar-width:none] md:py-6",
18762
18643
  ref: carouselRef,
18763
- className: cn(
18764
- "scrollbar-hide flex w-full space-x-4 overflow-x-auto pb-4",
18765
- "snap-x snap-mandatory scroll-pl-0",
18766
- carouselClassName
18767
- ),
18768
- children: renderItems()
18769
- }
18770
- ),
18771
- !isAtStart && /* @__PURE__ */ jsx(
18772
- Pressable,
18773
- {
18774
- onClick: () => scroll("left"),
18775
- className: cn(
18776
- "absolute left-4 top-1/2 z-10 -translate-y-1/2",
18777
- "flex h-12 w-12 items-center justify-center",
18778
- "rounded-full border border-border/50 bg-background shadow-lg",
18779
- "text-foreground transition-all duration-200",
18780
- "hover:bg-accent hover:shadow-xl hover:scale-105",
18781
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
18782
- navigationClassName
18783
- ),
18784
- "aria-label": "Scroll left",
18785
- asButton: true,
18786
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-left", size: 24 })
18644
+ children: /* @__PURE__ */ jsxs(
18645
+ "div",
18646
+ {
18647
+ className: cn(
18648
+ "flex flex-row justify-start gap-4 pl-4",
18649
+ carouselClassName
18650
+ ),
18651
+ children: [
18652
+ items?.map((item, index) => /* @__PURE__ */ jsx(
18653
+ motion.div,
18654
+ {
18655
+ className: cn(
18656
+ "rounded-lg last:pr-[5%] md:last:pr-[33%]"
18657
+ ),
18658
+ initial: { opacity: 0, y: 20 },
18659
+ animate: { opacity: 1, y: 0 },
18660
+ transition: { duration: 0.5, delay: 0.2 * index, ease: "easeOut" },
18661
+ children: /* @__PURE__ */ jsx(
18662
+ "div",
18663
+ {
18664
+ className: cn(
18665
+ "group w-56 shrink-0 md:w-96",
18666
+ item.className
18667
+ ),
18668
+ children: /* @__PURE__ */ jsxs("div", { className: "overflow-hidden rounded-lg border bg-card text-card-foreground shadow-sm transition-shadow hover:shadow-md", children: [
18669
+ /* @__PURE__ */ jsx(
18670
+ Img,
18671
+ {
18672
+ alt: typeof item.title === "string" ? item.title : `Card ${index + 1}`,
18673
+ className: cn(
18674
+ "aspect-video w-full object-cover transition-transform group-hover:scale-105",
18675
+ item.imageClassName
18676
+ ),
18677
+ src: item.imageSrc,
18678
+ optixFlowConfig
18679
+ }
18680
+ ),
18681
+ /* @__PURE__ */ jsxs("div", { className: "p-4", children: [
18682
+ item.title && (typeof item.title === "string" ? /* @__PURE__ */ jsx("h3", { className: "text-md font-semibold leading-tight text-card-foreground", children: item.title }) : /* @__PURE__ */ jsx("div", { children: item.title })),
18683
+ (item.count !== void 0 || item.countLabel) && /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
18684
+ item.count !== void 0 && /* @__PURE__ */ jsx("p", { className: "text-xl font-bold", children: item.count }),
18685
+ item.countLabel && (typeof item.countLabel === "string" ? /* @__PURE__ */ jsx("p", { className: "text-xs font-medium uppercase tracking-wider text-muted-foreground", children: item.countLabel }) : /* @__PURE__ */ jsx("div", { children: item.countLabel }))
18686
+ ] }),
18687
+ item.actions && item.actions.length > 0 && /* @__PURE__ */ jsx("div", { className: "mt-4 flex flex-wrap gap-2", children: item.actions.map((action, actionIndex) => {
18688
+ const {
18689
+ label,
18690
+ icon,
18691
+ iconAfter,
18692
+ children,
18693
+ className: actionClassName,
18694
+ asButton,
18695
+ ...pressableProps
18696
+ } = action;
18697
+ return /* @__PURE__ */ jsx(
18698
+ Pressable,
18699
+ {
18700
+ asButton,
18701
+ className: actionClassName,
18702
+ ...pressableProps,
18703
+ children: children ?? /* @__PURE__ */ jsxs(Fragment$1, { children: [
18704
+ icon,
18705
+ label,
18706
+ iconAfter
18707
+ ] })
18708
+ },
18709
+ actionIndex
18710
+ );
18711
+ }) })
18712
+ ] })
18713
+ ] })
18714
+ }
18715
+ )
18716
+ },
18717
+ item.id
18718
+ )),
18719
+ itemsSlot
18720
+ ]
18721
+ }
18722
+ )
18787
18723
  }
18788
18724
  ),
18789
- !isAtEnd && /* @__PURE__ */ jsx(
18790
- Pressable,
18725
+ /* @__PURE__ */ jsx(
18726
+ CarouselPagination,
18791
18727
  {
18792
- onClick: () => scroll("right"),
18793
- className: cn(
18794
- "absolute right-4 top-1/2 z-10 -translate-y-1/2",
18795
- "flex h-12 w-12 items-center justify-center",
18796
- "rounded-full border border-border/50 bg-background shadow-lg",
18797
- "text-foreground transition-all duration-200",
18798
- "hover:bg-accent hover:shadow-xl hover:scale-105",
18799
- "focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2",
18800
- navigationClassName
18801
- ),
18802
- "aria-label": "Scroll right",
18803
- asButton: true,
18804
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-right", size: 24 })
18728
+ onPrevious: scrollLeft,
18729
+ onNext: scrollRight,
18730
+ canScrollPrevious: !isAtStart,
18731
+ canScrollNext: !isAtEnd,
18732
+ className: cn("mr-0 md:mr-10", navigationClassName)
18805
18733
  }
18806
18734
  )
18807
18735
  ] })
@@ -19926,6 +19854,193 @@ function CarouselScrollingFeatureShowcase({
19926
19854
  }
19927
19855
  );
19928
19856
  }
19857
+ var CarouselContext = React52.createContext(null);
19858
+ function useCarousel() {
19859
+ const context = React52.useContext(CarouselContext);
19860
+ if (!context) {
19861
+ throw new Error("useCarousel must be used within a <Carousel />");
19862
+ }
19863
+ return context;
19864
+ }
19865
+ function Carousel({
19866
+ orientation = "horizontal",
19867
+ opts,
19868
+ setApi,
19869
+ plugins,
19870
+ className,
19871
+ children,
19872
+ ...props
19873
+ }) {
19874
+ const [carouselRef, api] = useEmblaCarousel(
19875
+ {
19876
+ ...opts,
19877
+ axis: orientation === "horizontal" ? "x" : "y"
19878
+ },
19879
+ plugins
19880
+ );
19881
+ const [canScrollPrev, setCanScrollPrev] = React52.useState(false);
19882
+ const [canScrollNext, setCanScrollNext] = React52.useState(false);
19883
+ const onSelect = React52.useCallback((api2) => {
19884
+ if (!api2) return;
19885
+ setCanScrollPrev(api2.canScrollPrev());
19886
+ setCanScrollNext(api2.canScrollNext());
19887
+ }, []);
19888
+ const scrollPrev = React52.useCallback(() => {
19889
+ api?.scrollPrev();
19890
+ }, [api]);
19891
+ const scrollNext = React52.useCallback(() => {
19892
+ api?.scrollNext();
19893
+ }, [api]);
19894
+ const handleKeyDown = React52.useCallback(
19895
+ (event) => {
19896
+ if (event.key === "ArrowLeft") {
19897
+ event.preventDefault();
19898
+ scrollPrev();
19899
+ } else if (event.key === "ArrowRight") {
19900
+ event.preventDefault();
19901
+ scrollNext();
19902
+ }
19903
+ },
19904
+ [scrollPrev, scrollNext]
19905
+ );
19906
+ React52.useEffect(() => {
19907
+ if (!api || !setApi) return;
19908
+ setApi(api);
19909
+ }, [api, setApi]);
19910
+ React52.useEffect(() => {
19911
+ if (!api) return;
19912
+ onSelect(api);
19913
+ api.on("reInit", onSelect);
19914
+ api.on("select", onSelect);
19915
+ return () => {
19916
+ api?.off("select", onSelect);
19917
+ };
19918
+ }, [api, onSelect]);
19919
+ return /* @__PURE__ */ jsx(
19920
+ CarouselContext.Provider,
19921
+ {
19922
+ value: {
19923
+ carouselRef,
19924
+ api,
19925
+ opts,
19926
+ orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
19927
+ scrollPrev,
19928
+ scrollNext,
19929
+ canScrollPrev,
19930
+ canScrollNext
19931
+ },
19932
+ children: /* @__PURE__ */ jsx(
19933
+ "div",
19934
+ {
19935
+ onKeyDownCapture: handleKeyDown,
19936
+ className: cn("relative", className),
19937
+ role: "region",
19938
+ "aria-roledescription": "carousel",
19939
+ "data-slot": "carousel",
19940
+ ...props,
19941
+ children
19942
+ }
19943
+ )
19944
+ }
19945
+ );
19946
+ }
19947
+ function CarouselContent({ className, ...props }) {
19948
+ const { carouselRef, orientation } = useCarousel();
19949
+ return /* @__PURE__ */ jsx(
19950
+ "div",
19951
+ {
19952
+ ref: carouselRef,
19953
+ className: "overflow-hidden",
19954
+ "data-slot": "carousel-content",
19955
+ children: /* @__PURE__ */ jsx(
19956
+ "div",
19957
+ {
19958
+ className: cn(
19959
+ "flex",
19960
+ orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
19961
+ className
19962
+ ),
19963
+ ...props
19964
+ }
19965
+ )
19966
+ }
19967
+ );
19968
+ }
19969
+ function CarouselItem({ className, ...props }) {
19970
+ const { orientation } = useCarousel();
19971
+ return /* @__PURE__ */ jsx(
19972
+ "div",
19973
+ {
19974
+ role: "group",
19975
+ "aria-roledescription": "slide",
19976
+ "data-slot": "carousel-item",
19977
+ className: cn(
19978
+ "min-w-0 shrink-0 grow-0 basis-full",
19979
+ orientation === "horizontal" ? "pl-4" : "pt-4",
19980
+ className
19981
+ ),
19982
+ ...props
19983
+ }
19984
+ );
19985
+ }
19986
+ function CarouselPrevious({
19987
+ className,
19988
+ variant = "outline",
19989
+ size = "icon",
19990
+ ...props
19991
+ }) {
19992
+ const { orientation, scrollPrev, canScrollPrev } = useCarousel();
19993
+ return /* @__PURE__ */ jsxs(
19994
+ Pressable,
19995
+ {
19996
+ "data-slot": "carousel-previous",
19997
+ variant,
19998
+ size,
19999
+ className: cn(
20000
+ "absolute size-8 rounded-full",
20001
+ orientation === "horizontal" ? "top-1/2 -left-12 -translate-y-1/2" : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
20002
+ className
20003
+ ),
20004
+ disabled: !canScrollPrev,
20005
+ onClick: scrollPrev,
20006
+ asButton: true,
20007
+ ...props,
20008
+ children: [
20009
+ /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-left" }),
20010
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Previous slide" })
20011
+ ]
20012
+ }
20013
+ );
20014
+ }
20015
+ function CarouselNext({
20016
+ className,
20017
+ variant = "outline",
20018
+ size = "icon",
20019
+ ...props
20020
+ }) {
20021
+ const { orientation, scrollNext, canScrollNext } = useCarousel();
20022
+ return /* @__PURE__ */ jsxs(
20023
+ Pressable,
20024
+ {
20025
+ "data-slot": "carousel-next",
20026
+ variant,
20027
+ size,
20028
+ className: cn(
20029
+ "absolute size-8 rounded-full",
20030
+ orientation === "horizontal" ? "top-1/2 -right-12 -translate-y-1/2" : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
20031
+ className
20032
+ ),
20033
+ disabled: !canScrollNext,
20034
+ onClick: scrollNext,
20035
+ asButton: true,
20036
+ ...props,
20037
+ children: [
20038
+ /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right" }),
20039
+ /* @__PURE__ */ jsx("span", { className: "sr-only", children: "Next slide" })
20040
+ ]
20041
+ }
20042
+ );
20043
+ }
19929
20044
  function FeatureShowcase({
19930
20045
  items,
19931
20046
  children,