@opensite/ui 1.2.4 → 1.2.5

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,11 +1,12 @@
1
1
  "use client";
2
- import * as React4 from 'react';
3
- import React4__default, { useMemo, useCallback } from 'react';
2
+ import * as React6 from 'react';
3
+ import React6__default, { useMemo, useCallback } from 'react';
4
4
  import { AnimatePresence, motion } from 'framer-motion';
5
5
  import { clsx } from 'clsx';
6
6
  import { twMerge } from 'tailwind-merge';
7
7
  import { Img } from '@page-speed/img';
8
8
  import { jsx, jsxs } from 'react/jsx-runtime';
9
+ import { cva } from 'class-variance-authority';
9
10
 
10
11
  // components/blocks/features/feature-animated-carousel.tsx
11
12
  function cn(...inputs) {
@@ -49,10 +50,10 @@ function DynamicIcon({
49
50
  className,
50
51
  alt
51
52
  }) {
52
- const [svgContent, setSvgContent] = React4.useState(null);
53
- const [isLoading, setIsLoading] = React4.useState(true);
54
- const [error, setError] = React4.useState(null);
55
- const { url, iconName } = React4.useMemo(() => {
53
+ const [svgContent, setSvgContent] = React6.useState(null);
54
+ const [isLoading, setIsLoading] = React6.useState(true);
55
+ const [error, setError] = React6.useState(null);
56
+ const { url, iconName } = React6.useMemo(() => {
56
57
  const separator = name.includes("/") ? "/" : ":";
57
58
  const [prefix, iconName2] = name.split(separator);
58
59
  const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}`;
@@ -61,7 +62,7 @@ function DynamicIcon({
61
62
  iconName: iconName2
62
63
  };
63
64
  }, [name, size]);
64
- React4.useEffect(() => {
65
+ React6.useEffect(() => {
65
66
  let isMounted = true;
66
67
  const fetchSvg = async () => {
67
68
  const cached = svgCache.get(url);
@@ -155,7 +156,7 @@ var maxWidthStyles = {
155
156
  "4xl": "max-w-[1536px]",
156
157
  full: "max-w-full"
157
158
  };
158
- var Container = React4__default.forwardRef(
159
+ var Container = React6__default.forwardRef(
159
160
  ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
160
161
  const Component = as;
161
162
  return /* @__PURE__ */ jsx(
@@ -460,7 +461,7 @@ var spacingStyles = {
460
461
  };
461
462
  var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
462
463
  var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
463
- var Section = React4__default.forwardRef(
464
+ var Section = React6__default.forwardRef(
464
465
  ({
465
466
  id,
466
467
  title,
@@ -521,239 +522,689 @@ var Section = React4__default.forwardRef(
521
522
  }
522
523
  );
523
524
  Section.displayName = "Section";
524
- var Controls = React4.memo(({
525
- handleNext,
526
- handlePrevious,
527
- isPreviousDisabled,
528
- isNextDisabled
529
- }) => {
530
- return /* @__PURE__ */ jsxs("div", { className: "hidden flex-col items-start gap-8 lg:flex", children: [
531
- /* @__PURE__ */ jsx(
532
- "button",
533
- {
534
- className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
535
- onClick: handlePrevious,
536
- disabled: isPreviousDisabled,
537
- type: "button",
538
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-up", size: 24 })
525
+ var baseStyles = [
526
+ // Layout
527
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
528
+ // Typography - using CSS variables with sensible defaults
529
+ "font-[var(--button-font-family,inherit)]",
530
+ "font-[var(--button-font-weight,500)]",
531
+ "tracking-[var(--button-letter-spacing,0)]",
532
+ "leading-[var(--button-line-height,1.25)]",
533
+ "[text-transform:var(--button-text-transform,none)]",
534
+ "text-sm",
535
+ // Border radius
536
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
537
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
538
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
539
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
540
+ "[box-shadow:var(--button-shadow,none)]",
541
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
542
+ // Disabled state
543
+ "disabled:pointer-events-none disabled:opacity-50",
544
+ // SVG handling
545
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
546
+ // Focus styles
547
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
548
+ // Invalid state
549
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
550
+ ].join(" ");
551
+ var buttonVariants = cva(baseStyles, {
552
+ variants: {
553
+ variant: {
554
+ // Default (Primary) variant - full customization
555
+ default: [
556
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
557
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
558
+ "border-[length:var(--button-default-border-width,0px)]",
559
+ "border-[color:var(--button-default-border,transparent)]",
560
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
561
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
562
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
563
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
564
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
565
+ ].join(" "),
566
+ // Destructive variant - full customization
567
+ destructive: [
568
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
569
+ "text-[var(--button-destructive-fg,white)]",
570
+ "border-[length:var(--button-destructive-border-width,0px)]",
571
+ "border-[color:var(--button-destructive-border,transparent)]",
572
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
573
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
574
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
575
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
576
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
577
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
578
+ "dark:bg-destructive/60"
579
+ ].join(" "),
580
+ // Outline variant - full customization with proper border handling
581
+ outline: [
582
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
583
+ "text-[var(--button-outline-fg,inherit)]",
584
+ "border-[length:var(--button-outline-border-width,1px)]",
585
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
586
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
587
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
588
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
589
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
590
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
591
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
592
+ ].join(" "),
593
+ // Secondary variant - full customization
594
+ secondary: [
595
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
596
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
597
+ "border-[length:var(--button-secondary-border-width,0px)]",
598
+ "border-[color:var(--button-secondary-border,transparent)]",
599
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
600
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
601
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
602
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
603
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
604
+ ].join(" "),
605
+ // Ghost variant - full customization
606
+ ghost: [
607
+ "bg-[var(--button-ghost-bg,transparent)]",
608
+ "text-[var(--button-ghost-fg,inherit)]",
609
+ "border-[length:var(--button-ghost-border-width,0px)]",
610
+ "border-[color:var(--button-ghost-border,transparent)]",
611
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
612
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
613
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
614
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
615
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
616
+ "dark:hover:bg-accent/50"
617
+ ].join(" "),
618
+ // Link variant - full customization
619
+ link: [
620
+ "bg-[var(--button-link-bg,transparent)]",
621
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
622
+ "border-[length:var(--button-link-border-width,0px)]",
623
+ "border-[color:var(--button-link-border,transparent)]",
624
+ "[box-shadow:var(--button-link-shadow,none)]",
625
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
626
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
627
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
628
+ "underline-offset-4 hover:underline"
629
+ ].join(" ")
630
+ },
631
+ size: {
632
+ default: [
633
+ "h-[var(--button-height-md,2.25rem)]",
634
+ "px-[var(--button-padding-x-md,1rem)]",
635
+ "py-[var(--button-padding-y-md,0.5rem)]",
636
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
637
+ ].join(" "),
638
+ sm: [
639
+ "h-[var(--button-height-sm,2rem)]",
640
+ "px-[var(--button-padding-x-sm,0.75rem)]",
641
+ "py-[var(--button-padding-y-sm,0.25rem)]",
642
+ "gap-1.5",
643
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
644
+ ].join(" "),
645
+ md: [
646
+ "h-[var(--button-height-md,2.25rem)]",
647
+ "px-[var(--button-padding-x-md,1rem)]",
648
+ "py-[var(--button-padding-y-md,0.5rem)]",
649
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
650
+ ].join(" "),
651
+ lg: [
652
+ "h-[var(--button-height-lg,2.5rem)]",
653
+ "px-[var(--button-padding-x-lg,1.5rem)]",
654
+ "py-[var(--button-padding-y-lg,0.5rem)]",
655
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
656
+ ].join(" "),
657
+ icon: "size-[var(--button-height-md,2.25rem)]",
658
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
659
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
660
+ }
661
+ },
662
+ defaultVariants: {
663
+ variant: "default",
664
+ size: "default"
665
+ }
666
+ });
667
+ function normalizePhoneNumber(input) {
668
+ const trimmed = input.trim();
669
+ if (trimmed.toLowerCase().startsWith("tel:")) {
670
+ return trimmed;
671
+ }
672
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
673
+ if (match) {
674
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
675
+ const extension = match[3];
676
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
677
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
678
+ return `tel:${withExtension}`;
679
+ }
680
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
681
+ return `tel:${cleaned}`;
682
+ }
683
+ function normalizeEmail(input) {
684
+ const trimmed = input.trim();
685
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
686
+ return trimmed;
687
+ }
688
+ return `mailto:${trimmed}`;
689
+ }
690
+ function isEmail(input) {
691
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
692
+ return emailRegex.test(input.trim());
693
+ }
694
+ function isPhoneNumber(input) {
695
+ const trimmed = input.trim();
696
+ if (trimmed.toLowerCase().startsWith("tel:")) {
697
+ return true;
698
+ }
699
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
700
+ return phoneRegex.test(trimmed);
701
+ }
702
+ function isInternalUrl(href) {
703
+ if (typeof window === "undefined") {
704
+ return href.startsWith("/") && !href.startsWith("//");
705
+ }
706
+ const trimmed = href.trim();
707
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
708
+ return true;
709
+ }
710
+ try {
711
+ const url = new URL(trimmed, window.location.href);
712
+ const currentOrigin = window.location.origin;
713
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
714
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
715
+ } catch {
716
+ return false;
717
+ }
718
+ }
719
+ function toRelativePath(href) {
720
+ if (typeof window === "undefined") {
721
+ return href;
722
+ }
723
+ const trimmed = href.trim();
724
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
725
+ return trimmed;
726
+ }
727
+ try {
728
+ const url = new URL(trimmed, window.location.href);
729
+ const currentOrigin = window.location.origin;
730
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
731
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
732
+ return url.pathname + url.search + url.hash;
733
+ }
734
+ } catch {
735
+ }
736
+ return trimmed;
737
+ }
738
+ function useNavigation({
739
+ href,
740
+ onClick
741
+ } = {}) {
742
+ const linkType = React6.useMemo(() => {
743
+ if (!href || href.trim() === "") {
744
+ return onClick ? "none" : "none";
745
+ }
746
+ const trimmed = href.trim();
747
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
748
+ return "mailto";
749
+ }
750
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
751
+ return "tel";
752
+ }
753
+ if (isInternalUrl(trimmed)) {
754
+ return "internal";
755
+ }
756
+ try {
757
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
758
+ return "external";
759
+ } catch {
760
+ return "internal";
761
+ }
762
+ }, [href, onClick]);
763
+ const normalizedHref = React6.useMemo(() => {
764
+ if (!href || href.trim() === "") {
765
+ return void 0;
766
+ }
767
+ const trimmed = href.trim();
768
+ switch (linkType) {
769
+ case "tel":
770
+ return normalizePhoneNumber(trimmed);
771
+ case "mailto":
772
+ return normalizeEmail(trimmed);
773
+ case "internal":
774
+ return toRelativePath(trimmed);
775
+ case "external":
776
+ return trimmed;
777
+ default:
778
+ return trimmed;
779
+ }
780
+ }, [href, linkType]);
781
+ const target = React6.useMemo(() => {
782
+ switch (linkType) {
783
+ case "external":
784
+ return "_blank";
785
+ case "internal":
786
+ return "_self";
787
+ case "mailto":
788
+ case "tel":
789
+ return void 0;
790
+ default:
791
+ return void 0;
792
+ }
793
+ }, [linkType]);
794
+ const rel = React6.useMemo(() => {
795
+ if (linkType === "external") {
796
+ return "noopener noreferrer";
797
+ }
798
+ return void 0;
799
+ }, [linkType]);
800
+ const isExternal = linkType === "external";
801
+ const isInternal = linkType === "internal";
802
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
803
+ const handleClick = React6.useCallback(
804
+ (event) => {
805
+ if (onClick) {
806
+ try {
807
+ onClick(event);
808
+ } catch (error) {
809
+ console.error("Error in user onClick handler:", error);
810
+ }
539
811
  }
540
- ),
541
- /* @__PURE__ */ jsx(
542
- "button",
543
- {
544
- className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
545
- onClick: handleNext,
546
- disabled: isNextDisabled,
547
- type: "button",
548
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-down", size: 24 })
812
+ if (event.defaultPrevented) {
813
+ return;
814
+ }
815
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
816
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
817
+ if (typeof window !== "undefined") {
818
+ const handler = window.__opensiteNavigationHandler;
819
+ if (typeof handler === "function") {
820
+ try {
821
+ const handled = handler(normalizedHref, event.nativeEvent || event);
822
+ if (handled !== false) {
823
+ event.preventDefault();
824
+ }
825
+ } catch (error) {
826
+ console.error("Error in navigation handler:", error);
827
+ }
828
+ }
829
+ }
549
830
  }
550
- )
551
- ] });
552
- });
553
- var FeatureCard = React4.memo(({ feature, isActive, onClick }) => {
554
- const variants = useMemo(() => ({
555
- initial: {
556
- opacity: 0
557
- },
558
- animate: {
559
- opacity: 1
560
831
  },
561
- exit: {
562
- opacity: 0
832
+ [onClick, shouldUseRouter, normalizedHref]
833
+ );
834
+ return {
835
+ linkType,
836
+ normalizedHref,
837
+ target,
838
+ rel,
839
+ isExternal,
840
+ isInternal,
841
+ shouldUseRouter,
842
+ handleClick
843
+ };
844
+ }
845
+ var Pressable = React6.forwardRef(
846
+ ({
847
+ children,
848
+ className,
849
+ href,
850
+ onClick,
851
+ variant,
852
+ size,
853
+ asButton = false,
854
+ fallbackComponentType = "span",
855
+ componentType,
856
+ "aria-label": ariaLabel,
857
+ "aria-describedby": ariaDescribedby,
858
+ id,
859
+ ...props
860
+ }, ref) => {
861
+ const navigation = useNavigation({ href, onClick });
862
+ const {
863
+ normalizedHref,
864
+ target,
865
+ rel,
866
+ linkType,
867
+ isInternal,
868
+ handleClick
869
+ } = navigation;
870
+ const shouldRenderLink = normalizedHref && linkType !== "none";
871
+ const shouldRenderButton = !shouldRenderLink && onClick;
872
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
873
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
874
+ const shouldApplyButtonStyles = asButton || variant || size;
875
+ const combinedClassName = cn(
876
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
877
+ className
878
+ );
879
+ const dataProps = Object.fromEntries(
880
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
881
+ );
882
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
883
+ "data-slot": "button",
884
+ "data-variant": variant ?? "default",
885
+ "data-size": size ?? "default"
886
+ } : {};
887
+ const commonProps = {
888
+ className: combinedClassName,
889
+ onClick: handleClick,
890
+ "aria-label": ariaLabel,
891
+ "aria-describedby": ariaDescribedby,
892
+ id,
893
+ ...dataProps,
894
+ ...buttonDataAttributes
895
+ };
896
+ if (finalComponentType === "a" && shouldRenderLink) {
897
+ return /* @__PURE__ */ jsx(
898
+ "a",
899
+ {
900
+ ref,
901
+ href: normalizedHref,
902
+ target,
903
+ rel,
904
+ ...commonProps,
905
+ ...props,
906
+ children
907
+ }
908
+ );
563
909
  }
564
- }), []);
565
- return /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsx(
566
- motion.div,
567
- {
568
- layout: true,
569
- transition: {
570
- layout: {
571
- duration: 0.4,
572
- ease: "easeOut"
910
+ if (finalComponentType === "button") {
911
+ return /* @__PURE__ */ jsx(
912
+ "button",
913
+ {
914
+ ref,
915
+ type: props.type || "button",
916
+ ...commonProps,
917
+ ...props,
918
+ children
573
919
  }
574
- },
575
- style: {
576
- borderRadius: "24px"
577
- },
578
- className: "flex cursor-pointer items-start gap-4 overflow-hidden bg-background md:w-fit md:max-w-sm",
579
- onClick,
580
- children: isActive ? /* @__PURE__ */ jsx(
581
- motion.div,
920
+ );
921
+ }
922
+ if (finalComponentType === "div") {
923
+ return /* @__PURE__ */ jsx(
924
+ "div",
582
925
  {
583
- layout: true,
584
- variants,
585
- initial: "initial",
586
- animate: "animate",
587
- exit: "exit",
588
- transition: {
926
+ ref,
927
+ ...commonProps,
928
+ children
929
+ }
930
+ );
931
+ }
932
+ return /* @__PURE__ */ jsx(
933
+ "span",
934
+ {
935
+ ref,
936
+ ...commonProps,
937
+ children
938
+ }
939
+ );
940
+ }
941
+ );
942
+ Pressable.displayName = "Pressable";
943
+ var Controls = React6.memo(
944
+ ({
945
+ handleNext,
946
+ handlePrevious,
947
+ isPreviousDisabled,
948
+ isNextDisabled
949
+ }) => {
950
+ return /* @__PURE__ */ jsxs("div", { className: "hidden flex-col items-start gap-8 lg:flex", children: [
951
+ /* @__PURE__ */ jsx(
952
+ "button",
953
+ {
954
+ className: "rounded-full border p-2 flex items-center justify-center disabled:opacity-50 h-fit w-fit bg-card text-card-foreground",
955
+ onClick: handlePrevious,
956
+ disabled: isPreviousDisabled,
957
+ type: "button",
958
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-up", size: 24 })
959
+ }
960
+ ),
961
+ /* @__PURE__ */ jsx(
962
+ "button",
963
+ {
964
+ className: "rounded-full border p-2 flex items-center justify-center disabled:opacity-50 h-fit w-fit bg-card text-card-foreground",
965
+ onClick: handleNext,
966
+ disabled: isNextDisabled,
967
+ type: "button",
968
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-down", size: 24 })
969
+ }
970
+ )
971
+ ] });
972
+ }
973
+ );
974
+ var FeatureCard = React6.memo(
975
+ ({ feature, isActive, onClick }) => {
976
+ const variants = useMemo(
977
+ () => ({
978
+ initial: {
979
+ opacity: 0
980
+ },
981
+ animate: {
982
+ opacity: 1
983
+ },
984
+ exit: {
985
+ opacity: 0
986
+ }
987
+ }),
988
+ []
989
+ );
990
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "popLayout", children: /* @__PURE__ */ jsxs(
991
+ motion.div,
992
+ {
993
+ layout: true,
994
+ transition: {
995
+ layout: {
589
996
  duration: 0.4,
590
- delay: 0.3,
591
997
  ease: "easeOut"
998
+ }
999
+ },
1000
+ style: {
1001
+ borderRadius: "24px"
1002
+ },
1003
+ className: cn(
1004
+ "relative flex items-start gap-4 overflow-hidden bg-background text-foreground md:w-fit md:max-w-sm",
1005
+ isActive ? "shadow-xl" : "cursor-pointer shadow-none"
1006
+ ),
1007
+ onClick,
1008
+ children: [
1009
+ isActive && feature.href && /* @__PURE__ */ jsx("div", { className: "absolute bottom-4 right-4 bg-background rounded-full h-fit w-fit p-2 flex items-center justify-center", children: /* @__PURE__ */ jsx(
1010
+ Pressable,
1011
+ {
1012
+ href: feature.href,
1013
+ size: "icon-lg",
1014
+ className: "text-foreground",
1015
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-up-right" })
1016
+ }
1017
+ ) }),
1018
+ isActive ? /* @__PURE__ */ jsx(
1019
+ motion.div,
1020
+ {
1021
+ layout: true,
1022
+ variants,
1023
+ initial: "initial",
1024
+ animate: "animate",
1025
+ exit: "exit",
1026
+ transition: {
1027
+ duration: 0.4,
1028
+ delay: 0.3,
1029
+ ease: "easeOut"
1030
+ },
1031
+ className: "p-6 text-sm md:p-8 md:text-base",
1032
+ children: (feature.title || feature.description) && /* @__PURE__ */ jsxs("p", { children: [
1033
+ feature.title && /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
1034
+ feature.title,
1035
+ "."
1036
+ ] }),
1037
+ feature.title && feature.description && " ",
1038
+ feature.description && /* @__PURE__ */ jsx("span", { children: feature.description })
1039
+ ] })
1040
+ },
1041
+ `feature-description-active-${feature.title}`
1042
+ ) : /* @__PURE__ */ jsxs(
1043
+ motion.div,
1044
+ {
1045
+ layout: true,
1046
+ variants,
1047
+ initial: "initial",
1048
+ animate: "animate",
1049
+ exit: "exit",
1050
+ transition: {
1051
+ duration: 0.4,
1052
+ delay: 0.2,
1053
+ ease: "easeOut"
1054
+ },
1055
+ className: cn(
1056
+ "flex h-fit shrink-0 items-center gap-4 text-sm md:py-3.5 md:pr-6 md:pl-3 md:text-base",
1057
+ !isActive && "h-0 w-0 md:h-auto md:w-auto"
1058
+ ),
1059
+ style: {
1060
+ height: "auto",
1061
+ lineHeight: "normal"
1062
+ },
1063
+ children: [
1064
+ /* @__PURE__ */ jsx(
1065
+ DynamicIcon,
1066
+ {
1067
+ name: "lucide/plus-circle",
1068
+ size: 24,
1069
+ className: "shrink-0"
1070
+ }
1071
+ ),
1072
+ feature.title && /* @__PURE__ */ jsx("p", { className: "shrink-0 font-semibold", children: feature.title })
1073
+ ]
1074
+ },
1075
+ `feature-description-inactive-${feature.title}`
1076
+ )
1077
+ ]
1078
+ }
1079
+ ) });
1080
+ }
1081
+ );
1082
+ var FeaturesDesktop = React6.memo(
1083
+ ({
1084
+ features,
1085
+ handleNext,
1086
+ handlePrevious,
1087
+ activeIndex,
1088
+ handleFeatureClick,
1089
+ isPreviousDisabled,
1090
+ isNextDisabled
1091
+ }) => {
1092
+ return /* @__PURE__ */ jsxs("div", { className: "relative z-10 hidden items-center gap-8 md:flex", children: [
1093
+ /* @__PURE__ */ jsx(
1094
+ Controls,
1095
+ {
1096
+ handleNext,
1097
+ handlePrevious,
1098
+ isPreviousDisabled,
1099
+ isNextDisabled
1100
+ }
1101
+ ),
1102
+ /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: features.map((feature, index) => {
1103
+ return /* @__PURE__ */ jsx(
1104
+ FeatureCard,
1105
+ {
1106
+ feature,
1107
+ isActive: index === activeIndex,
1108
+ onClick: () => handleFeatureClick(index)
592
1109
  },
593
- className: "p-6 text-sm md:p-8 md:text-base",
594
- children: (feature.title || feature.description) && /* @__PURE__ */ jsxs("p", { children: [
595
- feature.title && /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
596
- feature.title,
597
- "."
598
- ] }),
599
- feature.title && feature.description && " ",
600
- feature.description && /* @__PURE__ */ jsx("span", { children: feature.description })
601
- ] })
1110
+ `feature-card-${index}`
1111
+ );
1112
+ }) })
1113
+ ] });
1114
+ }
1115
+ );
1116
+ var FeaturesMobile = React6.memo(
1117
+ ({
1118
+ features,
1119
+ handleNext,
1120
+ handlePrevious,
1121
+ activeIndex,
1122
+ direction,
1123
+ isPreviousDisabled,
1124
+ isNextDisabled
1125
+ }) => {
1126
+ const variants = useMemo(
1127
+ () => ({
1128
+ enter: (direction2) => ({
1129
+ x: direction2 > 0 ? 100 : -100,
1130
+ opacity: 0
1131
+ }),
1132
+ center: {
1133
+ x: 0,
1134
+ opacity: 1
602
1135
  },
603
- `feature-description-active-${feature.title}`
604
- ) : /* @__PURE__ */ jsxs(
1136
+ exit: (direction2) => ({
1137
+ x: direction2 < 0 ? 100 : -100,
1138
+ opacity: 0
1139
+ })
1140
+ }),
1141
+ []
1142
+ );
1143
+ const currentFeature = features[activeIndex];
1144
+ return /* @__PURE__ */ jsx("div", { className: "relative z-10 flex flex-col gap-4 md:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full items-stretch gap-4", children: [
1145
+ /* @__PURE__ */ jsx("div", { className: "flex-1 overflow-hidden", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsx(
605
1146
  motion.div,
606
1147
  {
607
- layout: true,
1148
+ custom: direction,
608
1149
  variants,
609
- initial: "initial",
610
- animate: "animate",
1150
+ initial: "enter",
1151
+ animate: "center",
611
1152
  exit: "exit",
612
1153
  transition: {
613
- duration: 0.4,
614
- delay: 0.2,
615
- ease: "easeOut"
616
- },
617
- className: cn(
618
- "flex h-fit shrink-0 items-center gap-4 text-sm md:py-3.5 md:pr-6 md:pl-3 md:text-base",
619
- !isActive && "h-0 w-0 md:h-auto md:w-auto"
620
- ),
621
- style: {
622
- height: "auto",
623
- lineHeight: "normal"
1154
+ x: { type: "spring", stiffness: 300, damping: 30 },
1155
+ opacity: { duration: 0.2 }
624
1156
  },
625
- children: [
626
- /* @__PURE__ */ jsx(
627
- DynamicIcon,
628
- {
629
- name: "lucide/plus-circle",
630
- size: 24,
631
- className: "shrink-0"
632
- }
633
- ),
634
- feature.title && /* @__PURE__ */ jsx("p", { className: "shrink-0 font-semibold", children: feature.title })
635
- ]
636
- },
637
- `feature-description-inactive-${feature.title}`
638
- )
639
- }
640
- ) });
641
- });
642
- var FeaturesDesktop = React4.memo(({
643
- features,
644
- handleNext,
645
- handlePrevious,
646
- activeIndex,
647
- handleFeatureClick,
648
- isPreviousDisabled,
649
- isNextDisabled
650
- }) => {
651
- return /* @__PURE__ */ jsxs("div", { className: "relative z-10 hidden items-center gap-8 md:flex", children: [
652
- /* @__PURE__ */ jsx(
653
- Controls,
654
- {
655
- handleNext,
656
- handlePrevious,
657
- isPreviousDisabled,
658
- isNextDisabled
659
- }
660
- ),
661
- /* @__PURE__ */ jsx("div", { className: "flex flex-col gap-4", children: features.map((feature, index) => {
662
- return /* @__PURE__ */ jsx(
663
- FeatureCard,
664
- {
665
- feature,
666
- isActive: index === activeIndex,
667
- onClick: () => handleFeatureClick(index)
668
- },
669
- `feature-card-${index}`
670
- );
671
- }) })
672
- ] });
673
- });
674
- var FeaturesMobile = React4.memo(({
675
- features,
676
- handleNext,
677
- handlePrevious,
678
- activeIndex,
679
- direction,
680
- isPreviousDisabled,
681
- isNextDisabled
682
- }) => {
683
- const variants = useMemo(() => ({
684
- enter: (direction2) => ({
685
- x: direction2 > 0 ? 100 : -100,
686
- opacity: 0
687
- }),
688
- center: {
689
- x: 0,
690
- opacity: 1
691
- },
692
- exit: (direction2) => ({
693
- x: direction2 < 0 ? 100 : -100,
694
- opacity: 0
695
- })
696
- }), []);
697
- const currentFeature = features[activeIndex];
698
- return /* @__PURE__ */ jsx("div", { className: "relative z-10 flex flex-col items-center gap-6 md:hidden", children: /* @__PURE__ */ jsxs("div", { className: "flex w-full items-center justify-between gap-4", children: [
699
- /* @__PURE__ */ jsx(
700
- "button",
701
- {
702
- className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
703
- onClick: handlePrevious,
704
- disabled: isPreviousDisabled,
705
- type: "button",
706
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-left", size: 24 })
707
- }
708
- ),
709
- /* @__PURE__ */ jsx("div", { className: "relative h-24 w-full overflow-hidden", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsx(
710
- motion.div,
711
- {
712
- custom: direction,
713
- variants,
714
- initial: "enter",
715
- animate: "center",
716
- exit: "exit",
717
- transition: {
718
- x: { type: "spring", stiffness: 300, damping: 30 },
719
- opacity: { duration: 0.2 }
1157
+ className: "rounded-3xl bg-background p-4 text-left",
1158
+ children: (currentFeature?.title || currentFeature?.description) && /* @__PURE__ */ jsxs("div", { className: "text-sm", children: [
1159
+ currentFeature.title && /* @__PURE__ */ jsx("p", { className: "font-semibold", children: currentFeature.title }),
1160
+ currentFeature.description && /* @__PURE__ */ jsx("p", { className: "mt-1", children: currentFeature.description })
1161
+ ] })
720
1162
  },
721
- className: "absolute inset-0 flex items-center justify-center rounded-3xl bg-background p-4",
722
- children: (currentFeature?.title || currentFeature?.description) && /* @__PURE__ */ jsxs("p", { className: "text-center text-sm", children: [
723
- currentFeature.title && /* @__PURE__ */ jsxs("span", { className: "font-semibold", children: [
724
- currentFeature.title,
725
- "."
726
- ] }),
727
- currentFeature.title && currentFeature.description && " ",
728
- currentFeature.description && /* @__PURE__ */ jsx("span", { children: currentFeature.description })
729
- ] })
730
- },
731
- activeIndex
732
- ) }) }),
733
- /* @__PURE__ */ jsx(
734
- "button",
735
- {
736
- className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
737
- onClick: handleNext,
738
- disabled: isNextDisabled,
739
- type: "button",
740
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-right", size: 24 })
741
- }
742
- )
743
- ] }) });
744
- });
1163
+ activeIndex
1164
+ ) }) }),
1165
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col justify-center gap-2", children: [
1166
+ /* @__PURE__ */ jsx(
1167
+ "button",
1168
+ {
1169
+ className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
1170
+ onClick: handlePrevious,
1171
+ disabled: isPreviousDisabled,
1172
+ type: "button",
1173
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-up", size: 20 })
1174
+ }
1175
+ ),
1176
+ /* @__PURE__ */ jsx(
1177
+ "button",
1178
+ {
1179
+ className: "rounded-full border bg-background/50 p-2 hover:bg-background disabled:opacity-50",
1180
+ onClick: handleNext,
1181
+ disabled: isNextDisabled,
1182
+ type: "button",
1183
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/chevron-down", size: 20 })
1184
+ }
1185
+ )
1186
+ ] })
1187
+ ] }) });
1188
+ }
1189
+ );
745
1190
  function FeatureAnimatedCarousel({
1191
+ title,
1192
+ description,
1193
+ titleClassName,
1194
+ descriptionClassName,
746
1195
  features,
747
1196
  className,
748
1197
  optixFlowConfig,
749
1198
  background,
750
- spacing,
751
1199
  pattern,
752
1200
  patternOpacity,
753
- patternClassName
1201
+ patternClassName,
1202
+ headerClassName,
1203
+ spacing = "py-12 md:py-32",
1204
+ containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8"
754
1205
  }) {
755
- const [activeIndex, setActiveIndex] = React4.useState(0);
756
- const [direction, setDirection] = React4.useState(1);
1206
+ const [activeIndex, setActiveIndex] = React6.useState(0);
1207
+ const [direction, setDirection] = React6.useState(1);
757
1208
  const handleNext = useCallback(() => {
758
1209
  if (features && activeIndex < features.length - 1) {
759
1210
  setDirection(1);
@@ -766,26 +1217,32 @@ function FeatureAnimatedCarousel({
766
1217
  setActiveIndex(activeIndex - 1);
767
1218
  }
768
1219
  }, [activeIndex]);
769
- const handleFeatureClick = useCallback((index) => {
770
- setDirection(index > activeIndex ? 1 : -1);
771
- setActiveIndex(index);
772
- }, [activeIndex]);
1220
+ const handleFeatureClick = useCallback(
1221
+ (index) => {
1222
+ setDirection(index > activeIndex ? 1 : -1);
1223
+ setActiveIndex(index);
1224
+ },
1225
+ [activeIndex]
1226
+ );
773
1227
  const isPreviousDisabled = activeIndex === 0;
774
1228
  const isNextDisabled = !features || activeIndex === features.length - 1;
775
- const imageVariants = useMemo(() => ({
776
- enter: (direction2) => ({
777
- x: direction2 > 0 ? 300 : -300,
778
- opacity: 0
1229
+ const imageVariants = useMemo(
1230
+ () => ({
1231
+ enter: (direction2) => ({
1232
+ x: direction2 > 0 ? 300 : -300,
1233
+ opacity: 0
1234
+ }),
1235
+ center: {
1236
+ x: 0,
1237
+ opacity: 1
1238
+ },
1239
+ exit: (direction2) => ({
1240
+ x: direction2 < 0 ? 300 : -300,
1241
+ opacity: 0
1242
+ })
779
1243
  }),
780
- center: {
781
- x: 0,
782
- opacity: 1
783
- },
784
- exit: (direction2) => ({
785
- x: direction2 < 0 ? 300 : -300,
786
- opacity: 0
787
- })
788
- }), []);
1244
+ []
1245
+ );
789
1246
  if (!features || features.length === 0) {
790
1247
  return /* @__PURE__ */ jsx(
791
1248
  Section,
@@ -796,11 +1253,17 @@ function FeatureAnimatedCarousel({
796
1253
  patternOpacity,
797
1254
  patternClassName,
798
1255
  className,
799
- children: /* @__PURE__ */ jsx("div", { className: cn(
800
- "relative flex min-h-[500px] flex-col-reverse gap-8 overflow-hidden rounded-3xl p-6 md:flex-row md:items-center md:p-12 lg:min-h-[600px]",
801
- getNestedCardBg(background),
802
- getNestedCardTextColor(background)
803
- ) })
1256
+ containerClassName,
1257
+ children: /* @__PURE__ */ jsx(
1258
+ "div",
1259
+ {
1260
+ className: cn(
1261
+ "relative flex min-h-[500px] flex-col-reverse gap-8 overflow-hidden rounded-3xl p-6 md:flex-row md:items-center md:p-12 lg:min-h-[600px]",
1262
+ getNestedCardBg(background),
1263
+ getNestedCardTextColor(background)
1264
+ )
1265
+ }
1266
+ )
804
1267
  }
805
1268
  );
806
1269
  }
@@ -814,60 +1277,105 @@ function FeatureAnimatedCarousel({
814
1277
  patternOpacity,
815
1278
  patternClassName,
816
1279
  className,
817
- children: /* @__PURE__ */ jsxs("div", { className: cn(
818
- "relative flex min-h-[500px] flex-col-reverse gap-8 overflow-hidden rounded-3xl p-6 md:flex-row md:items-center md:p-12 lg:min-h-[600px]",
819
- getNestedCardBg(background),
820
- getNestedCardTextColor(background)
821
- ), children: [
822
- /* @__PURE__ */ jsx(
823
- FeaturesDesktop,
824
- {
825
- features,
826
- handleNext,
827
- handlePrevious,
828
- activeIndex,
829
- handleFeatureClick,
830
- isPreviousDisabled,
831
- isNextDisabled
832
- }
833
- ),
834
- /* @__PURE__ */ jsx(
835
- FeaturesMobile,
1280
+ children: /* @__PURE__ */ jsxs("div", { className: "flex flex-col space-y-6 md:space-y-16", children: [
1281
+ title || description ? /* @__PURE__ */ jsxs("div", { className: cn("flex flex-col gap-6 text-left", headerClassName), children: [
1282
+ title && (typeof title === "string" ? /* @__PURE__ */ jsx(
1283
+ "h2",
1284
+ {
1285
+ className: cn(
1286
+ "text-xl font-semibold text-balance md:text-2xl lg:text-3xl max-w-lg md:max-w-md",
1287
+ titleClassName
1288
+ ),
1289
+ children: title
1290
+ }
1291
+ ) : /* @__PURE__ */ jsx(
1292
+ "div",
1293
+ {
1294
+ className: cn(
1295
+ "text-xl font-semibold text-balance md:text-2xl lg:text-3xl max-w-lg md:max-w-md",
1296
+ titleClassName
1297
+ ),
1298
+ children: title
1299
+ }
1300
+ )),
1301
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn("max-w-lg md:max-w-md", descriptionClassName), children: description }) : /* @__PURE__ */ jsx(
1302
+ "div",
1303
+ {
1304
+ className: cn("max-w-lg md:max-w-md", descriptionClassName),
1305
+ children: description
1306
+ }
1307
+ ))
1308
+ ] }) : null,
1309
+ /* @__PURE__ */ jsxs(
1310
+ "div",
836
1311
  {
837
- features,
838
- handleNext,
839
- handlePrevious,
840
- activeIndex,
841
- direction,
842
- isPreviousDisabled,
843
- isNextDisabled
1312
+ className: cn(
1313
+ "relative flex min-h-[500px] flex-col-reverse gap-8 overflow-hidden rounded-3xl p-6 md:flex-row md:items-center md:p-12 lg:min-h-[600px]"
1314
+ ),
1315
+ children: [
1316
+ /* @__PURE__ */ jsx(
1317
+ FeaturesDesktop,
1318
+ {
1319
+ features,
1320
+ handleNext,
1321
+ handlePrevious,
1322
+ activeIndex,
1323
+ handleFeatureClick,
1324
+ isPreviousDisabled,
1325
+ isNextDisabled
1326
+ }
1327
+ ),
1328
+ /* @__PURE__ */ jsx(
1329
+ FeaturesMobile,
1330
+ {
1331
+ features,
1332
+ handleNext,
1333
+ handlePrevious,
1334
+ activeIndex,
1335
+ direction,
1336
+ isPreviousDisabled,
1337
+ isNextDisabled
1338
+ }
1339
+ ),
1340
+ currentFeature?.image && /* @__PURE__ */ jsxs("div", { className: "relative w-full h-[250px] md:h-auto overflow-hidden rounded-2xl md:absolute md:right-8 md:top-8 md:bottom-8 md:w-1/2 shadow-xl", children: [
1341
+ currentFeature.href && /* @__PURE__ */ jsx("div", { className: "absolute top-4 right-4 z-10 bg-background rounded-full h-fit w-fit p-2 flex items-center justify-center md:hidden", children: /* @__PURE__ */ jsx(
1342
+ Pressable,
1343
+ {
1344
+ href: currentFeature.href,
1345
+ size: "icon-lg",
1346
+ className: "text-foreground",
1347
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-up-right" })
1348
+ }
1349
+ ) }),
1350
+ /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsx(
1351
+ motion.div,
1352
+ {
1353
+ custom: direction,
1354
+ variants: imageVariants,
1355
+ initial: "enter",
1356
+ animate: "center",
1357
+ exit: "exit",
1358
+ transition: {
1359
+ x: { type: "spring", stiffness: 300, damping: 30 },
1360
+ opacity: { duration: 0.2 }
1361
+ },
1362
+ className: "h-full w-full",
1363
+ children: /* @__PURE__ */ jsx(
1364
+ Img,
1365
+ {
1366
+ src: currentFeature.image,
1367
+ alt: currentFeature.imageAlt || (typeof currentFeature.title === "string" ? currentFeature.title : "Feature image"),
1368
+ className: "h-full w-full object-cover",
1369
+ optixFlowConfig
1370
+ }
1371
+ )
1372
+ },
1373
+ activeIndex
1374
+ ) })
1375
+ ] })
1376
+ ]
844
1377
  }
845
- ),
846
- currentFeature?.image && /* @__PURE__ */ jsx("div", { className: "relative flex-1 overflow-hidden rounded-2xl md:absolute md:right-8 md:top-8 md:bottom-8 md:w-1/2", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", custom: direction, children: /* @__PURE__ */ jsx(
847
- motion.div,
848
- {
849
- custom: direction,
850
- variants: imageVariants,
851
- initial: "enter",
852
- animate: "center",
853
- exit: "exit",
854
- transition: {
855
- x: { type: "spring", stiffness: 300, damping: 30 },
856
- opacity: { duration: 0.2 }
857
- },
858
- className: "h-full w-full",
859
- children: /* @__PURE__ */ jsx(
860
- Img,
861
- {
862
- src: currentFeature.image,
863
- alt: currentFeature.imageAlt || (typeof currentFeature.title === "string" ? currentFeature.title : "Feature image"),
864
- className: "h-full w-full object-cover",
865
- optixFlowConfig
866
- }
867
- )
868
- },
869
- activeIndex
870
- ) }) })
1378
+ )
871
1379
  ] })
872
1380
  }
873
1381
  );