@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.
@@ -1,14 +1,14 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
+ var React6 = require('react');
4
5
  var clsx = require('clsx');
5
6
  var tailwindMerge = require('tailwind-merge');
6
7
  var reactSlot = require('@radix-ui/react-slot');
7
8
  var classVarianceAuthority = require('class-variance-authority');
8
9
  var jsxRuntime = require('react/jsx-runtime');
9
- var React4 = require('react');
10
- var useEmblaCarousel = require('embla-carousel-react');
11
10
  var img = require('@page-speed/img');
11
+ var useEmblaCarousel = require('embla-carousel-react');
12
12
 
13
13
  function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
14
14
 
@@ -30,10 +30,10 @@ function _interopNamespace(e) {
30
30
  return Object.freeze(n);
31
31
  }
32
32
 
33
- var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
33
+ var React6__namespace = /*#__PURE__*/_interopNamespace(React6);
34
34
  var useEmblaCarousel__default = /*#__PURE__*/_interopDefault(useEmblaCarousel);
35
35
 
36
- // lib/utils.ts
36
+ // components/blocks/carousel/carousel-feature-badge.tsx
37
37
  function cn(...inputs) {
38
38
  return tailwindMerge.twMerge(clsx.clsx(inputs));
39
39
  }
@@ -144,7 +144,7 @@ function useNavigation({
144
144
  href,
145
145
  onClick
146
146
  } = {}) {
147
- const linkType = React4__namespace.useMemo(() => {
147
+ const linkType = React6__namespace.useMemo(() => {
148
148
  if (!href || href.trim() === "") {
149
149
  return onClick ? "none" : "none";
150
150
  }
@@ -165,7 +165,7 @@ function useNavigation({
165
165
  return "internal";
166
166
  }
167
167
  }, [href, onClick]);
168
- const normalizedHref = React4__namespace.useMemo(() => {
168
+ const normalizedHref = React6__namespace.useMemo(() => {
169
169
  if (!href || href.trim() === "") {
170
170
  return void 0;
171
171
  }
@@ -183,7 +183,7 @@ function useNavigation({
183
183
  return trimmed;
184
184
  }
185
185
  }, [href, linkType]);
186
- const target = React4__namespace.useMemo(() => {
186
+ const target = React6__namespace.useMemo(() => {
187
187
  switch (linkType) {
188
188
  case "external":
189
189
  return "_blank";
@@ -196,7 +196,7 @@ function useNavigation({
196
196
  return void 0;
197
197
  }
198
198
  }, [linkType]);
199
- const rel = React4__namespace.useMemo(() => {
199
+ const rel = React6__namespace.useMemo(() => {
200
200
  if (linkType === "external") {
201
201
  return "noopener noreferrer";
202
202
  }
@@ -205,7 +205,7 @@ function useNavigation({
205
205
  const isExternal = linkType === "external";
206
206
  const isInternal = linkType === "internal";
207
207
  const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
208
- const handleClick = React4__namespace.useCallback(
208
+ const handleClick = React6__namespace.useCallback(
209
209
  (event) => {
210
210
  if (onClick) {
211
211
  try {
@@ -389,7 +389,7 @@ var buttonVariants = classVarianceAuthority.cva(baseStyles, {
389
389
  size: "default"
390
390
  }
391
391
  });
392
- var Pressable = React4__namespace.forwardRef(
392
+ var Pressable = React6__namespace.forwardRef(
393
393
  ({
394
394
  children,
395
395
  className,
@@ -495,10 +495,10 @@ function DynamicIcon({
495
495
  className,
496
496
  alt
497
497
  }) {
498
- const [svgContent, setSvgContent] = React4__namespace.useState(null);
499
- const [isLoading, setIsLoading] = React4__namespace.useState(true);
500
- const [error, setError] = React4__namespace.useState(null);
501
- const { url, iconName } = React4__namespace.useMemo(() => {
498
+ const [svgContent, setSvgContent] = React6__namespace.useState(null);
499
+ const [isLoading, setIsLoading] = React6__namespace.useState(true);
500
+ const [error, setError] = React6__namespace.useState(null);
501
+ const { url, iconName } = React6__namespace.useMemo(() => {
502
502
  const separator = name.includes("/") ? "/" : ":";
503
503
  const [prefix, iconName2] = name.split(separator);
504
504
  const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}`;
@@ -507,7 +507,7 @@ function DynamicIcon({
507
507
  iconName: iconName2
508
508
  };
509
509
  }, [name, size]);
510
- React4__namespace.useEffect(() => {
510
+ React6__namespace.useEffect(() => {
511
511
  let isMounted = true;
512
512
  const fetchSvg = async () => {
513
513
  const cached = svgCache.get(url);
@@ -592,192 +592,49 @@ function processSvgForCurrentColor(svg) {
592
592
  );
593
593
  return processed;
594
594
  }
595
- var CarouselContext = React4__namespace.createContext(null);
596
- function useCarousel() {
597
- const context = React4__namespace.useContext(CarouselContext);
598
- if (!context) {
599
- throw new Error("useCarousel must be used within a <Carousel />");
600
- }
601
- return context;
602
- }
603
- function Carousel({
604
- orientation = "horizontal",
605
- opts,
606
- setApi,
607
- plugins,
595
+ function CarouselPagination({
596
+ onPrevious,
597
+ onNext,
598
+ canScrollPrevious = true,
599
+ canScrollNext = true,
600
+ iconSize = 24,
608
601
  className,
609
- children,
610
- ...props
602
+ buttonClassName,
603
+ previousIcon = "lucide/arrow-left",
604
+ nextIcon = "lucide/arrow-right",
605
+ previousAriaLabel = "Previous",
606
+ nextAriaLabel = "Next"
611
607
  }) {
612
- const [carouselRef, api] = useEmblaCarousel__default.default(
613
- {
614
- ...opts,
615
- axis: orientation === "horizontal" ? "x" : "y"
616
- },
617
- plugins
618
- );
619
- const [canScrollPrev, setCanScrollPrev] = React4__namespace.useState(false);
620
- const [canScrollNext, setCanScrollNext] = React4__namespace.useState(false);
621
- const onSelect = React4__namespace.useCallback((api2) => {
622
- if (!api2) return;
623
- setCanScrollPrev(api2.canScrollPrev());
624
- setCanScrollNext(api2.canScrollNext());
625
- }, []);
626
- const scrollPrev = React4__namespace.useCallback(() => {
627
- api?.scrollPrev();
628
- }, [api]);
629
- const scrollNext = React4__namespace.useCallback(() => {
630
- api?.scrollNext();
631
- }, [api]);
632
- const handleKeyDown = React4__namespace.useCallback(
633
- (event) => {
634
- if (event.key === "ArrowLeft") {
635
- event.preventDefault();
636
- scrollPrev();
637
- } else if (event.key === "ArrowRight") {
638
- event.preventDefault();
639
- scrollNext();
608
+ return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex justify-end gap-2", className), children: [
609
+ /* @__PURE__ */ jsxRuntime.jsx(
610
+ Pressable,
611
+ {
612
+ onClick: onPrevious,
613
+ disabled: !canScrollPrevious,
614
+ "aria-label": previousAriaLabel,
615
+ asButton: true,
616
+ className: cn(
617
+ "relative z-40 flex h-10 w-10 items-center justify-center rounded-full disabled:opacity-50",
618
+ buttonClassName
619
+ ),
620
+ children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: previousIcon, size: iconSize })
640
621
  }
641
- },
642
- [scrollPrev, scrollNext]
643
- );
644
- React4__namespace.useEffect(() => {
645
- if (!api || !setApi) return;
646
- setApi(api);
647
- }, [api, setApi]);
648
- React4__namespace.useEffect(() => {
649
- if (!api) return;
650
- onSelect(api);
651
- api.on("reInit", onSelect);
652
- api.on("select", onSelect);
653
- return () => {
654
- api?.off("select", onSelect);
655
- };
656
- }, [api, onSelect]);
657
- return /* @__PURE__ */ jsxRuntime.jsx(
658
- CarouselContext.Provider,
659
- {
660
- value: {
661
- carouselRef,
662
- api,
663
- opts,
664
- orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
665
- scrollPrev,
666
- scrollNext,
667
- canScrollPrev,
668
- canScrollNext
669
- },
670
- children: /* @__PURE__ */ jsxRuntime.jsx(
671
- "div",
672
- {
673
- onKeyDownCapture: handleKeyDown,
674
- className: cn("relative", className),
675
- role: "region",
676
- "aria-roledescription": "carousel",
677
- "data-slot": "carousel",
678
- ...props,
679
- children
680
- }
681
- )
682
- }
683
- );
684
- }
685
- function CarouselContent({ className, ...props }) {
686
- const { carouselRef, orientation } = useCarousel();
687
- return /* @__PURE__ */ jsxRuntime.jsx(
688
- "div",
689
- {
690
- ref: carouselRef,
691
- className: "overflow-hidden",
692
- "data-slot": "carousel-content",
693
- children: /* @__PURE__ */ jsxRuntime.jsx(
694
- "div",
695
- {
696
- className: cn(
697
- "flex",
698
- orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
699
- className
700
- ),
701
- ...props
702
- }
703
- )
704
- }
705
- );
706
- }
707
- function CarouselItem({ className, ...props }) {
708
- const { orientation } = useCarousel();
709
- return /* @__PURE__ */ jsxRuntime.jsx(
710
- "div",
711
- {
712
- role: "group",
713
- "aria-roledescription": "slide",
714
- "data-slot": "carousel-item",
715
- className: cn(
716
- "min-w-0 shrink-0 grow-0 basis-full",
717
- orientation === "horizontal" ? "pl-4" : "pt-4",
718
- className
719
- ),
720
- ...props
721
- }
722
- );
723
- }
724
- function CarouselPrevious({
725
- className,
726
- variant = "outline",
727
- size = "icon",
728
- ...props
729
- }) {
730
- const { orientation, scrollPrev, canScrollPrev } = useCarousel();
731
- return /* @__PURE__ */ jsxRuntime.jsxs(
732
- Pressable,
733
- {
734
- "data-slot": "carousel-previous",
735
- variant,
736
- size,
737
- className: cn(
738
- "absolute size-8 rounded-full",
739
- orientation === "horizontal" ? "top-1/2 -left-12 -translate-y-1/2" : "-top-12 left-1/2 -translate-x-1/2 rotate-90",
740
- className
741
- ),
742
- disabled: !canScrollPrev,
743
- onClick: scrollPrev,
744
- asButton: true,
745
- ...props,
746
- children: [
747
- /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-left" }),
748
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Previous slide" })
749
- ]
750
- }
751
- );
752
- }
753
- function CarouselNext({
754
- className,
755
- variant = "outline",
756
- size = "icon",
757
- ...props
758
- }) {
759
- const { orientation, scrollNext, canScrollNext } = useCarousel();
760
- return /* @__PURE__ */ jsxRuntime.jsxs(
761
- Pressable,
762
- {
763
- "data-slot": "carousel-next",
764
- variant,
765
- size,
766
- className: cn(
767
- "absolute size-8 rounded-full",
768
- orientation === "horizontal" ? "top-1/2 -right-12 -translate-y-1/2" : "-bottom-12 left-1/2 -translate-x-1/2 rotate-90",
769
- className
770
- ),
771
- disabled: !canScrollNext,
772
- onClick: scrollNext,
773
- asButton: true,
774
- ...props,
775
- children: [
776
- /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-right" }),
777
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: "sr-only", children: "Next slide" })
778
- ]
779
- }
780
- );
622
+ ),
623
+ /* @__PURE__ */ jsxRuntime.jsx(
624
+ Pressable,
625
+ {
626
+ onClick: onNext,
627
+ disabled: !canScrollNext,
628
+ "aria-label": nextAriaLabel,
629
+ asButton: true,
630
+ className: cn(
631
+ "relative z-40 flex h-10 w-10 items-center justify-center rounded-full disabled:opacity-50",
632
+ buttonClassName
633
+ ),
634
+ children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: nextIcon, size: iconSize })
635
+ }
636
+ )
637
+ ] });
781
638
  }
782
639
  var maxWidthStyles = {
783
640
  sm: "max-w-screen-sm",
@@ -788,7 +645,7 @@ var maxWidthStyles = {
788
645
  "4xl": "max-w-[1536px]",
789
646
  full: "max-w-full"
790
647
  };
791
- var Container = React4__namespace.default.forwardRef(
648
+ var Container = React6__namespace.default.forwardRef(
792
649
  ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
793
650
  const Component = as;
794
651
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -1093,7 +950,7 @@ var spacingStyles = {
1093
950
  };
1094
951
  var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
1095
952
  var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
1096
- var Section = React4__namespace.default.forwardRef(
953
+ var Section = React6__namespace.default.forwardRef(
1097
954
  ({
1098
955
  id,
1099
956
  title,
@@ -1181,27 +1038,62 @@ function CarouselFeatureBadge({
1181
1038
  slideLayoutVariant = "square",
1182
1039
  containerMaxWidth = "2xl"
1183
1040
  }) {
1041
+ const [emblaRef, emblaApi] = useEmblaCarousel__default.default();
1042
+ const [canScrollPrev, setCanScrollPrev] = React6__namespace.useState(false);
1043
+ const [canScrollNext, setCanScrollNext] = React6__namespace.useState(false);
1044
+ const scrollPrev = React6__namespace.useCallback(() => {
1045
+ emblaApi?.scrollPrev();
1046
+ }, [emblaApi]);
1047
+ const scrollNext = React6__namespace.useCallback(() => {
1048
+ emblaApi?.scrollNext();
1049
+ }, [emblaApi]);
1050
+ const onSelect = React6__namespace.useCallback(() => {
1051
+ if (!emblaApi) return;
1052
+ setCanScrollPrev(emblaApi.canScrollPrev());
1053
+ setCanScrollNext(emblaApi.canScrollNext());
1054
+ }, [emblaApi]);
1055
+ React6__namespace.useEffect(() => {
1056
+ if (!emblaApi) return;
1057
+ onSelect();
1058
+ emblaApi.on("reInit", onSelect);
1059
+ emblaApi.on("select", onSelect);
1060
+ return () => {
1061
+ emblaApi?.off("select", onSelect);
1062
+ };
1063
+ }, [emblaApi, onSelect]);
1184
1064
  const renderCarouselItems = () => {
1185
1065
  if (itemsSlot) return itemsSlot;
1186
1066
  if (!items || items.length === 0) return null;
1187
- return items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(CarouselItem, { className: carouselItemClassName, children: /* @__PURE__ */ jsxRuntime.jsx(
1067
+ return items.map((item, index) => /* @__PURE__ */ jsxRuntime.jsx(
1188
1068
  "div",
1189
1069
  {
1070
+ role: "group",
1071
+ "aria-roledescription": "slide",
1190
1072
  className: cn(
1191
- "flex items-center justify-center overflow-hidden rounded-2xl",
1192
- SLIDE_LAYOUT_ASPECT_MAP[slideLayoutVariant]
1073
+ "min-w-0 shrink-0 grow-0 basis-full pl-4",
1074
+ carouselItemClassName
1193
1075
  ),
1194
1076
  children: /* @__PURE__ */ jsxRuntime.jsx(
1195
- img.Img,
1077
+ "div",
1196
1078
  {
1197
- src: item.src,
1198
- alt: item.alt,
1199
- className: cn("h-full w-full object-cover", item.className),
1200
- optixFlowConfig
1079
+ className: cn(
1080
+ "flex items-center justify-center overflow-hidden rounded-2xl",
1081
+ SLIDE_LAYOUT_ASPECT_MAP[slideLayoutVariant]
1082
+ ),
1083
+ children: /* @__PURE__ */ jsxRuntime.jsx(
1084
+ img.Img,
1085
+ {
1086
+ src: item.src,
1087
+ alt: item.alt,
1088
+ className: cn("h-full w-full object-cover", item.className),
1089
+ optixFlowConfig
1090
+ }
1091
+ )
1201
1092
  }
1202
1093
  )
1203
- }
1204
- ) }, index));
1094
+ },
1095
+ index
1096
+ ));
1205
1097
  };
1206
1098
  return /* @__PURE__ */ jsxRuntime.jsx(
1207
1099
  Section,
@@ -1244,10 +1136,18 @@ function CarouselFeatureBadge({
1244
1136
  ]
1245
1137
  }
1246
1138
  ),
1247
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full max-w-full px-6", carouselClassName), children: /* @__PURE__ */ jsxRuntime.jsxs(Carousel, { children: [
1248
- /* @__PURE__ */ jsxRuntime.jsx(CarouselContent, { children: renderCarouselItems() }),
1249
- /* @__PURE__ */ jsxRuntime.jsx(CarouselPrevious, {}),
1250
- /* @__PURE__ */ jsxRuntime.jsx(CarouselNext, {})
1139
+ /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("w-full max-w-full", carouselClassName), children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "relative", children: [
1140
+ /* @__PURE__ */ jsxRuntime.jsx("div", { ref: emblaRef, className: "overflow-hidden", children: /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex -ml-4", children: renderCarouselItems() }) }),
1141
+ /* @__PURE__ */ jsxRuntime.jsx(
1142
+ CarouselPagination,
1143
+ {
1144
+ onPrevious: scrollPrev,
1145
+ onNext: scrollNext,
1146
+ canScrollPrevious: canScrollPrev,
1147
+ canScrollNext,
1148
+ className: "mt-4"
1149
+ }
1150
+ )
1251
1151
  ] }) })
1252
1152
  ] }) })
1253
1153
  }