@opensite/ui 1.2.2 → 1.2.4

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.
Files changed (51) hide show
  1. package/dist/auto-scroll-carousel.cjs +2 -2
  2. package/dist/auto-scroll-carousel.js +2 -2
  3. package/dist/blur-vignette-grid.cjs +13 -17
  4. package/dist/blur-vignette-grid.d.cts +2 -2
  5. package/dist/blur-vignette-grid.d.ts +2 -2
  6. package/dist/blur-vignette-grid.js +13 -17
  7. package/dist/carousel-gradient-text.cjs +8 -10
  8. package/dist/carousel-gradient-text.js +8 -10
  9. package/dist/carousel-icon-sidebar.cjs +48 -29
  10. package/dist/carousel-icon-sidebar.js +48 -29
  11. package/dist/carousel-scale-focus.cjs +27 -1
  12. package/dist/carousel-scale-focus.js +27 -1
  13. package/dist/carousel-tabs-content.cjs +46 -36
  14. package/dist/carousel-tabs-content.js +46 -36
  15. package/dist/expandable-case-study-cards.cjs +1 -0
  16. package/dist/expandable-case-study-cards.js +1 -0
  17. package/dist/feature-capabilities-grid.cjs +525 -54
  18. package/dist/feature-capabilities-grid.d.cts +4 -0
  19. package/dist/feature-capabilities-grid.d.ts +4 -0
  20. package/dist/feature-capabilities-grid.js +525 -54
  21. package/dist/feature-card-grid-linked.cjs +40 -35
  22. package/dist/feature-card-grid-linked.d.cts +9 -1
  23. package/dist/feature-card-grid-linked.d.ts +9 -1
  24. package/dist/feature-card-grid-linked.js +40 -35
  25. package/dist/feature-carousel-progress.cjs +129 -56
  26. package/dist/feature-carousel-progress.d.cts +13 -1
  27. package/dist/feature-carousel-progress.d.ts +13 -1
  28. package/dist/feature-carousel-progress.js +129 -56
  29. package/dist/feature-checklist-image.cjs +61 -105
  30. package/dist/feature-checklist-image.d.cts +1 -1
  31. package/dist/feature-checklist-image.d.ts +1 -1
  32. package/dist/feature-checklist-image.js +61 -105
  33. package/dist/feature-icon-grid-bordered.cjs +457 -35
  34. package/dist/feature-icon-grid-bordered.d.cts +4 -0
  35. package/dist/feature-icon-grid-bordered.d.ts +4 -0
  36. package/dist/feature-icon-grid-bordered.js +457 -35
  37. package/dist/feature-numbered-cards.cjs +519 -35
  38. package/dist/feature-numbered-cards.d.cts +18 -2
  39. package/dist/feature-numbered-cards.d.ts +18 -2
  40. package/dist/feature-numbered-cards.js +520 -36
  41. package/dist/feature-split-image.cjs +1 -1
  42. package/dist/feature-split-image.js +1 -1
  43. package/dist/masonry-motion-grid.cjs +2 -2
  44. package/dist/masonry-motion-grid.js +2 -2
  45. package/dist/registry.cjs +10264 -9952
  46. package/dist/registry.js +10262 -9950
  47. package/dist/testimonial-carousel-cards.cjs +28 -8
  48. package/dist/testimonial-carousel-cards.d.cts +8 -0
  49. package/dist/testimonial-carousel-cards.d.ts +8 -0
  50. package/dist/testimonial-carousel-cards.js +28 -8
  51. package/package.json +1 -1
@@ -6,6 +6,7 @@ var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
8
  var img = require('@page-speed/img');
9
+ var classVarianceAuthority = require('class-variance-authority');
9
10
 
10
11
  function _interopNamespace(e) {
11
12
  if (e && e.__esModule) return e;
@@ -511,11 +512,431 @@ var Section = React__namespace.default.forwardRef(
511
512
  }
512
513
  );
513
514
  Section.displayName = "Section";
515
+ var baseStyles = [
516
+ // Layout
517
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
518
+ // Typography - using CSS variables with sensible defaults
519
+ "font-[var(--button-font-family,inherit)]",
520
+ "font-[var(--button-font-weight,500)]",
521
+ "tracking-[var(--button-letter-spacing,0)]",
522
+ "leading-[var(--button-line-height,1.25)]",
523
+ "[text-transform:var(--button-text-transform,none)]",
524
+ "text-sm",
525
+ // Border radius
526
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
527
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
528
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
529
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
530
+ "[box-shadow:var(--button-shadow,none)]",
531
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
532
+ // Disabled state
533
+ "disabled:pointer-events-none disabled:opacity-50",
534
+ // SVG handling
535
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
536
+ // Focus styles
537
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
538
+ // Invalid state
539
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
540
+ ].join(" ");
541
+ var buttonVariants = classVarianceAuthority.cva(baseStyles, {
542
+ variants: {
543
+ variant: {
544
+ // Default (Primary) variant - full customization
545
+ default: [
546
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
547
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
548
+ "border-[length:var(--button-default-border-width,0px)]",
549
+ "border-[color:var(--button-default-border,transparent)]",
550
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
551
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
552
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
553
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
554
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
555
+ ].join(" "),
556
+ // Destructive variant - full customization
557
+ destructive: [
558
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
559
+ "text-[var(--button-destructive-fg,white)]",
560
+ "border-[length:var(--button-destructive-border-width,0px)]",
561
+ "border-[color:var(--button-destructive-border,transparent)]",
562
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
563
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
564
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
565
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
566
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
567
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
568
+ "dark:bg-destructive/60"
569
+ ].join(" "),
570
+ // Outline variant - full customization with proper border handling
571
+ outline: [
572
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
573
+ "text-[var(--button-outline-fg,inherit)]",
574
+ "border-[length:var(--button-outline-border-width,1px)]",
575
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
576
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
577
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
578
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
579
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
580
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
581
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
582
+ ].join(" "),
583
+ // Secondary variant - full customization
584
+ secondary: [
585
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
586
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
587
+ "border-[length:var(--button-secondary-border-width,0px)]",
588
+ "border-[color:var(--button-secondary-border,transparent)]",
589
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
590
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
591
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
592
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
593
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
594
+ ].join(" "),
595
+ // Ghost variant - full customization
596
+ ghost: [
597
+ "bg-[var(--button-ghost-bg,transparent)]",
598
+ "text-[var(--button-ghost-fg,inherit)]",
599
+ "border-[length:var(--button-ghost-border-width,0px)]",
600
+ "border-[color:var(--button-ghost-border,transparent)]",
601
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
602
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
603
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
604
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
605
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
606
+ "dark:hover:bg-accent/50"
607
+ ].join(" "),
608
+ // Link variant - full customization
609
+ link: [
610
+ "bg-[var(--button-link-bg,transparent)]",
611
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
612
+ "border-[length:var(--button-link-border-width,0px)]",
613
+ "border-[color:var(--button-link-border,transparent)]",
614
+ "[box-shadow:var(--button-link-shadow,none)]",
615
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
616
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
617
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
618
+ "underline-offset-4 hover:underline"
619
+ ].join(" ")
620
+ },
621
+ size: {
622
+ default: [
623
+ "h-[var(--button-height-md,2.25rem)]",
624
+ "px-[var(--button-padding-x-md,1rem)]",
625
+ "py-[var(--button-padding-y-md,0.5rem)]",
626
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
627
+ ].join(" "),
628
+ sm: [
629
+ "h-[var(--button-height-sm,2rem)]",
630
+ "px-[var(--button-padding-x-sm,0.75rem)]",
631
+ "py-[var(--button-padding-y-sm,0.25rem)]",
632
+ "gap-1.5",
633
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
634
+ ].join(" "),
635
+ md: [
636
+ "h-[var(--button-height-md,2.25rem)]",
637
+ "px-[var(--button-padding-x-md,1rem)]",
638
+ "py-[var(--button-padding-y-md,0.5rem)]",
639
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
640
+ ].join(" "),
641
+ lg: [
642
+ "h-[var(--button-height-lg,2.5rem)]",
643
+ "px-[var(--button-padding-x-lg,1.5rem)]",
644
+ "py-[var(--button-padding-y-lg,0.5rem)]",
645
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
646
+ ].join(" "),
647
+ icon: "size-[var(--button-height-md,2.25rem)]",
648
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
649
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
650
+ }
651
+ },
652
+ defaultVariants: {
653
+ variant: "default",
654
+ size: "default"
655
+ }
656
+ });
657
+ function normalizePhoneNumber(input) {
658
+ const trimmed = input.trim();
659
+ if (trimmed.toLowerCase().startsWith("tel:")) {
660
+ return trimmed;
661
+ }
662
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
663
+ if (match) {
664
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
665
+ const extension = match[3];
666
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
667
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
668
+ return `tel:${withExtension}`;
669
+ }
670
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
671
+ return `tel:${cleaned}`;
672
+ }
673
+ function normalizeEmail(input) {
674
+ const trimmed = input.trim();
675
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
676
+ return trimmed;
677
+ }
678
+ return `mailto:${trimmed}`;
679
+ }
680
+ function isEmail(input) {
681
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
682
+ return emailRegex.test(input.trim());
683
+ }
684
+ function isPhoneNumber(input) {
685
+ const trimmed = input.trim();
686
+ if (trimmed.toLowerCase().startsWith("tel:")) {
687
+ return true;
688
+ }
689
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
690
+ return phoneRegex.test(trimmed);
691
+ }
692
+ function isInternalUrl(href) {
693
+ if (typeof window === "undefined") {
694
+ return href.startsWith("/") && !href.startsWith("//");
695
+ }
696
+ const trimmed = href.trim();
697
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
698
+ return true;
699
+ }
700
+ try {
701
+ const url = new URL(trimmed, window.location.href);
702
+ const currentOrigin = window.location.origin;
703
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
704
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
705
+ } catch {
706
+ return false;
707
+ }
708
+ }
709
+ function toRelativePath(href) {
710
+ if (typeof window === "undefined") {
711
+ return href;
712
+ }
713
+ const trimmed = href.trim();
714
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
715
+ return trimmed;
716
+ }
717
+ try {
718
+ const url = new URL(trimmed, window.location.href);
719
+ const currentOrigin = window.location.origin;
720
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
721
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
722
+ return url.pathname + url.search + url.hash;
723
+ }
724
+ } catch {
725
+ }
726
+ return trimmed;
727
+ }
728
+ function useNavigation({
729
+ href,
730
+ onClick
731
+ } = {}) {
732
+ const linkType = React__namespace.useMemo(() => {
733
+ if (!href || href.trim() === "") {
734
+ return onClick ? "none" : "none";
735
+ }
736
+ const trimmed = href.trim();
737
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
738
+ return "mailto";
739
+ }
740
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
741
+ return "tel";
742
+ }
743
+ if (isInternalUrl(trimmed)) {
744
+ return "internal";
745
+ }
746
+ try {
747
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
748
+ return "external";
749
+ } catch {
750
+ return "internal";
751
+ }
752
+ }, [href, onClick]);
753
+ const normalizedHref = React__namespace.useMemo(() => {
754
+ if (!href || href.trim() === "") {
755
+ return void 0;
756
+ }
757
+ const trimmed = href.trim();
758
+ switch (linkType) {
759
+ case "tel":
760
+ return normalizePhoneNumber(trimmed);
761
+ case "mailto":
762
+ return normalizeEmail(trimmed);
763
+ case "internal":
764
+ return toRelativePath(trimmed);
765
+ case "external":
766
+ return trimmed;
767
+ default:
768
+ return trimmed;
769
+ }
770
+ }, [href, linkType]);
771
+ const target = React__namespace.useMemo(() => {
772
+ switch (linkType) {
773
+ case "external":
774
+ return "_blank";
775
+ case "internal":
776
+ return "_self";
777
+ case "mailto":
778
+ case "tel":
779
+ return void 0;
780
+ default:
781
+ return void 0;
782
+ }
783
+ }, [linkType]);
784
+ const rel = React__namespace.useMemo(() => {
785
+ if (linkType === "external") {
786
+ return "noopener noreferrer";
787
+ }
788
+ return void 0;
789
+ }, [linkType]);
790
+ const isExternal = linkType === "external";
791
+ const isInternal = linkType === "internal";
792
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
793
+ const handleClick = React__namespace.useCallback(
794
+ (event) => {
795
+ if (onClick) {
796
+ try {
797
+ onClick(event);
798
+ } catch (error) {
799
+ console.error("Error in user onClick handler:", error);
800
+ }
801
+ }
802
+ if (event.defaultPrevented) {
803
+ return;
804
+ }
805
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
806
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
807
+ if (typeof window !== "undefined") {
808
+ const handler = window.__opensiteNavigationHandler;
809
+ if (typeof handler === "function") {
810
+ try {
811
+ const handled = handler(normalizedHref, event.nativeEvent || event);
812
+ if (handled !== false) {
813
+ event.preventDefault();
814
+ }
815
+ } catch (error) {
816
+ console.error("Error in navigation handler:", error);
817
+ }
818
+ }
819
+ }
820
+ }
821
+ },
822
+ [onClick, shouldUseRouter, normalizedHref]
823
+ );
824
+ return {
825
+ linkType,
826
+ normalizedHref,
827
+ target,
828
+ rel,
829
+ isExternal,
830
+ isInternal,
831
+ shouldUseRouter,
832
+ handleClick
833
+ };
834
+ }
835
+ var Pressable = React__namespace.forwardRef(
836
+ ({
837
+ children,
838
+ className,
839
+ href,
840
+ onClick,
841
+ variant,
842
+ size,
843
+ asButton = false,
844
+ fallbackComponentType = "span",
845
+ componentType,
846
+ "aria-label": ariaLabel,
847
+ "aria-describedby": ariaDescribedby,
848
+ id,
849
+ ...props
850
+ }, ref) => {
851
+ const navigation = useNavigation({ href, onClick });
852
+ const {
853
+ normalizedHref,
854
+ target,
855
+ rel,
856
+ linkType,
857
+ isInternal,
858
+ handleClick
859
+ } = navigation;
860
+ const shouldRenderLink = normalizedHref && linkType !== "none";
861
+ const shouldRenderButton = !shouldRenderLink && onClick;
862
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
863
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
864
+ const shouldApplyButtonStyles = asButton || variant || size;
865
+ const combinedClassName = cn(
866
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
867
+ className
868
+ );
869
+ const dataProps = Object.fromEntries(
870
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
871
+ );
872
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
873
+ "data-slot": "button",
874
+ "data-variant": variant ?? "default",
875
+ "data-size": size ?? "default"
876
+ } : {};
877
+ const commonProps = {
878
+ className: combinedClassName,
879
+ onClick: handleClick,
880
+ "aria-label": ariaLabel,
881
+ "aria-describedby": ariaDescribedby,
882
+ id,
883
+ ...dataProps,
884
+ ...buttonDataAttributes
885
+ };
886
+ if (finalComponentType === "a" && shouldRenderLink) {
887
+ return /* @__PURE__ */ jsxRuntime.jsx(
888
+ "a",
889
+ {
890
+ ref,
891
+ href: normalizedHref,
892
+ target,
893
+ rel,
894
+ ...commonProps,
895
+ ...props,
896
+ children
897
+ }
898
+ );
899
+ }
900
+ if (finalComponentType === "button") {
901
+ return /* @__PURE__ */ jsxRuntime.jsx(
902
+ "button",
903
+ {
904
+ ref,
905
+ type: props.type || "button",
906
+ ...commonProps,
907
+ ...props,
908
+ children
909
+ }
910
+ );
911
+ }
912
+ if (finalComponentType === "div") {
913
+ return /* @__PURE__ */ jsxRuntime.jsx(
914
+ "div",
915
+ {
916
+ ref,
917
+ ...commonProps,
918
+ children
919
+ }
920
+ );
921
+ }
922
+ return /* @__PURE__ */ jsxRuntime.jsx(
923
+ "span",
924
+ {
925
+ ref,
926
+ ...commonProps,
927
+ children
928
+ }
929
+ );
930
+ }
931
+ );
932
+ Pressable.displayName = "Pressable";
514
933
  function FeatureNumberedCards({
934
+ title,
935
+ description,
515
936
  features,
516
937
  featuresSlot,
517
938
  className,
518
- containerClassName,
939
+ containerClassName = "px-6 sm:px-6 md:mx-6 lg:px-8",
519
940
  cardsWrapperClassName,
520
941
  cardClassName,
521
942
  titleClassName,
@@ -524,7 +945,7 @@ function FeatureNumberedCards({
524
945
  badgeClassName,
525
946
  optixFlowConfig,
526
947
  background,
527
- spacing,
948
+ spacing = "py-6 md:py-32",
528
949
  pattern,
529
950
  patternOpacity,
530
951
  patternClassName
@@ -568,32 +989,61 @@ function FeatureNumberedCards({
568
989
  },
569
990
  []
570
991
  );
992
+ const actionsContent = React.useCallback(
993
+ (args) => {
994
+ if (args?.actionsSlot) return args.actionsSlot;
995
+ if (!args?.actions || args.actions.length === 0) return null;
996
+ return args.actions.map((action, index) => {
997
+ const {
998
+ label,
999
+ icon,
1000
+ iconAfter,
1001
+ children,
1002
+ className: actionClassName,
1003
+ ...pressableProps
1004
+ } = action;
1005
+ return /* @__PURE__ */ jsxRuntime.jsx(
1006
+ Pressable,
1007
+ {
1008
+ asButton: true,
1009
+ className: actionClassName,
1010
+ ...pressableProps,
1011
+ children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1012
+ icon,
1013
+ label,
1014
+ iconAfter
1015
+ ] })
1016
+ },
1017
+ index
1018
+ );
1019
+ });
1020
+ },
1021
+ []
1022
+ );
1023
+ const cardImg = React.useCallback((feature) => {
1024
+ if (!feature.image || !feature.imageSlot) return null;
1025
+ if (feature.imageSlot) return feature.imageSlot;
1026
+ const imageAlt = feature.imageAlt || (typeof feature.title === "string" ? feature.title : "Feature image");
1027
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "overflow-hidden h-full w-full rounded-t-lg rounded-b-none md:rounded-t-none md:rounded-l-none md:rounded-r-lg", children: /* @__PURE__ */ jsxRuntime.jsx(
1028
+ img.Img,
1029
+ {
1030
+ src: feature.image,
1031
+ alt: imageAlt,
1032
+ className: "h-full w-full object-cover",
1033
+ loading: "lazy",
1034
+ optixFlowConfig
1035
+ }
1036
+ ) });
1037
+ }, []);
571
1038
  const featuresContent = React.useMemo(() => {
572
1039
  if (featuresSlot) return featuresSlot;
573
1040
  if (!features || features.length === 0) return null;
574
1041
  return features.map((feature, index) => {
575
- const imageAlt = feature.imageAlt || (typeof feature.title === "string" ? feature.title : "Feature image");
576
- const renderImage = () => {
577
- if (feature.imageSlot) return feature.imageSlot;
578
- if (feature.image) {
579
- return /* @__PURE__ */ jsxRuntime.jsx(
580
- img.Img,
581
- {
582
- src: feature.image,
583
- alt: imageAlt,
584
- className: "h-full w-full object-cover rounded-tr-lg rounded-tl-lg md:rounded-tl-0 rounded-br-0 md:rounded-br-lg",
585
- loading: "lazy",
586
- optixFlowConfig
587
- }
588
- );
589
- }
590
- return null;
591
- };
592
1042
  return /* @__PURE__ */ jsxRuntime.jsxs(
593
1043
  "div",
594
1044
  {
595
1045
  className: cn(
596
- "grid rounded-lg border md:grid-cols-2",
1046
+ "grid rounded-lg border md:grid-cols-2 bg-background text-foreground",
597
1047
  cardClassName,
598
1048
  feature.className
599
1049
  ),
@@ -602,7 +1052,7 @@ function FeatureNumberedCards({
602
1052
  "div",
603
1053
  {
604
1054
  className: cn(
605
- "flex flex-col px-6 py-8 lg:px-8 lg:py-12 xl:px-12 xl:py-20",
1055
+ "flex flex-col px-4 py-4 lg:px-8 lg:py-12 xl:px-12 xl:py-20",
606
1056
  feature.contentClassName
607
1057
  ),
608
1058
  children: [
@@ -610,7 +1060,7 @@ function FeatureNumberedCards({
610
1060
  "h3",
611
1061
  {
612
1062
  className: cn(
613
- "mb-3 text-2xl font-medium sm:mb-5 md:text-3xl lg:text-4xl",
1063
+ "mb-3 text-lg font-medium sm:mb-5 md:text-xl lg:text-2xl",
614
1064
  titleClassName
615
1065
  ),
616
1066
  children: feature.title
@@ -619,7 +1069,7 @@ function FeatureNumberedCards({
619
1069
  "div",
620
1070
  {
621
1071
  className: cn(
622
- "mb-3 text-2xl font-medium sm:mb-5 md:text-3xl lg:text-4xl",
1072
+ "mb-3 text-lg font-medium sm:mb-5 md:text-xl lg:text-2xl",
623
1073
  titleClassName
624
1074
  ),
625
1075
  children: feature.title
@@ -653,7 +1103,14 @@ function FeatureNumberedCards({
653
1103
  ),
654
1104
  children: renderChecklistItems(feature)
655
1105
  }
656
- ) : null
1106
+ ) : null,
1107
+ actionsContent({
1108
+ actions: feature.actions,
1109
+ actionsSlot: feature.actionsSlot
1110
+ }) && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex items-center flex-wrap gap-4 md:gap-2", children: actionsContent({
1111
+ actions: feature.actions,
1112
+ actionsSlot: feature.actionsSlot
1113
+ }) })
657
1114
  ]
658
1115
  }
659
1116
  ),
@@ -665,7 +1122,7 @@ function FeatureNumberedCards({
665
1122
  feature.imageWrapperClassName
666
1123
  ),
667
1124
  children: [
668
- renderImage(),
1125
+ cardImg(feature),
669
1126
  /* @__PURE__ */ jsxRuntime.jsx(
670
1127
  "span",
671
1128
  {
@@ -704,16 +1161,43 @@ function FeatureNumberedCards({
704
1161
  patternClassName,
705
1162
  className,
706
1163
  containerClassName,
707
- children: /* @__PURE__ */ jsxRuntime.jsx(
708
- "div",
709
- {
710
- className: cn(
711
- "space-y-4 md:space-y-10 rounded-lg border-none md:border p-0 md:p-10",
712
- cardsWrapperClassName
713
- ),
714
- children: featuresContent
715
- }
716
- )
1164
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-6 md:space-y-16", children: [
1165
+ title || description ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col gap-4", children: [
1166
+ title && (typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1167
+ "h2",
1168
+ {
1169
+ className: cn(
1170
+ "text-xl font-medium tracking-tight md:text-2xl lg:text-3xl text-balance",
1171
+ titleClassName
1172
+ ),
1173
+ children: title
1174
+ }
1175
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: titleClassName, children: title })),
1176
+ description && (typeof description === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1177
+ "p",
1178
+ {
1179
+ className: cn("max-w-lg text-balance", descriptionClassName),
1180
+ children: description
1181
+ }
1182
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1183
+ "div",
1184
+ {
1185
+ className: cn("max-w-lg text-balance", descriptionClassName),
1186
+ children: description
1187
+ }
1188
+ ))
1189
+ ] }) : null,
1190
+ /* @__PURE__ */ jsxRuntime.jsx(
1191
+ "div",
1192
+ {
1193
+ className: cn(
1194
+ "space-y-4 md:space-y-10 rounded-lg border-none md:border p-0 md:p-10",
1195
+ cardsWrapperClassName
1196
+ ),
1197
+ children: featuresContent
1198
+ }
1199
+ )
1200
+ ] })
717
1201
  }
718
1202
  );
719
1203
  }
@@ -1,6 +1,6 @@
1
1
  import * as React from 'react';
2
2
  import { f as SectionBackground, g as SectionSpacing, t as PatternName } from './community-initiatives-Bz_A5vLU.cjs';
3
- import { O as OptixFlowConfig } from './blocks-Cohq4eio.cjs';
3
+ import { A as ActionConfig, O as OptixFlowConfig } from './blocks-Cohq4eio.cjs';
4
4
  import 'react/jsx-runtime';
5
5
  import 'class-variance-authority';
6
6
  import './button-variants-lRElsmTc.cjs';
@@ -65,8 +65,24 @@ interface FeatureNumberedCardsItem {
65
65
  * Additional CSS classes for the image wrapper
66
66
  */
67
67
  imageWrapperClassName?: string;
68
+ /**
69
+ * Array of action configurations for CTA buttons
70
+ */
71
+ actions?: ActionConfig[];
72
+ /**
73
+ * Custom slot for rendering actions (overrides actions array)
74
+ */
75
+ actionsSlot?: React.ReactNode;
68
76
  }
69
77
  interface FeatureNumberedCardsProps {
78
+ /**
79
+ * Feature title content
80
+ */
81
+ title?: React.ReactNode;
82
+ /**
83
+ * Feature description content
84
+ */
85
+ description?: React.ReactNode;
70
86
  /**
71
87
  * Array of numbered feature cards
72
88
  */
@@ -154,6 +170,6 @@ interface FeatureNumberedCardsProps {
154
170
  * />
155
171
  * ```
156
172
  */
157
- declare function FeatureNumberedCards({ features, featuresSlot, className, containerClassName, cardsWrapperClassName, cardClassName, titleClassName, descriptionClassName, checklistClassName, badgeClassName, optixFlowConfig, background, spacing, pattern, patternOpacity, patternClassName, }: FeatureNumberedCardsProps): React.JSX.Element;
173
+ declare function FeatureNumberedCards({ title, description, features, featuresSlot, className, containerClassName, cardsWrapperClassName, cardClassName, titleClassName, descriptionClassName, checklistClassName, badgeClassName, optixFlowConfig, background, spacing, pattern, patternOpacity, patternClassName, }: FeatureNumberedCardsProps): React.JSX.Element;
158
174
 
159
175
  export { FeatureNumberedCards, type FeatureNumberedCardsProps };