@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
@@ -5,6 +5,7 @@ var React = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
7
  var jsxRuntime = require('react/jsx-runtime');
8
+ var classVarianceAuthority = require('class-variance-authority');
8
9
 
9
10
  function _interopNamespace(e) {
10
11
  if (e && e.__esModule) return e;
@@ -514,19 +515,437 @@ var Section = React__namespace.default.forwardRef(
514
515
  }
515
516
  );
516
517
  Section.displayName = "Section";
518
+ var baseStyles = [
519
+ // Layout
520
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
521
+ // Typography - using CSS variables with sensible defaults
522
+ "font-[var(--button-font-family,inherit)]",
523
+ "font-[var(--button-font-weight,500)]",
524
+ "tracking-[var(--button-letter-spacing,0)]",
525
+ "leading-[var(--button-line-height,1.25)]",
526
+ "[text-transform:var(--button-text-transform,none)]",
527
+ "text-sm",
528
+ // Border radius
529
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
530
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
531
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
532
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
533
+ "[box-shadow:var(--button-shadow,none)]",
534
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
535
+ // Disabled state
536
+ "disabled:pointer-events-none disabled:opacity-50",
537
+ // SVG handling
538
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
539
+ // Focus styles
540
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
541
+ // Invalid state
542
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
543
+ ].join(" ");
544
+ var buttonVariants = classVarianceAuthority.cva(baseStyles, {
545
+ variants: {
546
+ variant: {
547
+ // Default (Primary) variant - full customization
548
+ default: [
549
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
550
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
551
+ "border-[length:var(--button-default-border-width,0px)]",
552
+ "border-[color:var(--button-default-border,transparent)]",
553
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
554
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
555
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
556
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
557
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
558
+ ].join(" "),
559
+ // Destructive variant - full customization
560
+ destructive: [
561
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
562
+ "text-[var(--button-destructive-fg,white)]",
563
+ "border-[length:var(--button-destructive-border-width,0px)]",
564
+ "border-[color:var(--button-destructive-border,transparent)]",
565
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
566
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
567
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
568
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
569
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
570
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
571
+ "dark:bg-destructive/60"
572
+ ].join(" "),
573
+ // Outline variant - full customization with proper border handling
574
+ outline: [
575
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
576
+ "text-[var(--button-outline-fg,inherit)]",
577
+ "border-[length:var(--button-outline-border-width,1px)]",
578
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
579
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
580
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
581
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
582
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
583
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
584
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
585
+ ].join(" "),
586
+ // Secondary variant - full customization
587
+ secondary: [
588
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
589
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
590
+ "border-[length:var(--button-secondary-border-width,0px)]",
591
+ "border-[color:var(--button-secondary-border,transparent)]",
592
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
593
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
594
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
595
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
596
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
597
+ ].join(" "),
598
+ // Ghost variant - full customization
599
+ ghost: [
600
+ "bg-[var(--button-ghost-bg,transparent)]",
601
+ "text-[var(--button-ghost-fg,inherit)]",
602
+ "border-[length:var(--button-ghost-border-width,0px)]",
603
+ "border-[color:var(--button-ghost-border,transparent)]",
604
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
605
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
606
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
607
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
608
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
609
+ "dark:hover:bg-accent/50"
610
+ ].join(" "),
611
+ // Link variant - full customization
612
+ link: [
613
+ "bg-[var(--button-link-bg,transparent)]",
614
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
615
+ "border-[length:var(--button-link-border-width,0px)]",
616
+ "border-[color:var(--button-link-border,transparent)]",
617
+ "[box-shadow:var(--button-link-shadow,none)]",
618
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
619
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
620
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
621
+ "underline-offset-4 hover:underline"
622
+ ].join(" ")
623
+ },
624
+ size: {
625
+ default: [
626
+ "h-[var(--button-height-md,2.25rem)]",
627
+ "px-[var(--button-padding-x-md,1rem)]",
628
+ "py-[var(--button-padding-y-md,0.5rem)]",
629
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
630
+ ].join(" "),
631
+ sm: [
632
+ "h-[var(--button-height-sm,2rem)]",
633
+ "px-[var(--button-padding-x-sm,0.75rem)]",
634
+ "py-[var(--button-padding-y-sm,0.25rem)]",
635
+ "gap-1.5",
636
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
637
+ ].join(" "),
638
+ md: [
639
+ "h-[var(--button-height-md,2.25rem)]",
640
+ "px-[var(--button-padding-x-md,1rem)]",
641
+ "py-[var(--button-padding-y-md,0.5rem)]",
642
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
643
+ ].join(" "),
644
+ lg: [
645
+ "h-[var(--button-height-lg,2.5rem)]",
646
+ "px-[var(--button-padding-x-lg,1.5rem)]",
647
+ "py-[var(--button-padding-y-lg,0.5rem)]",
648
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
649
+ ].join(" "),
650
+ icon: "size-[var(--button-height-md,2.25rem)]",
651
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
652
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
653
+ }
654
+ },
655
+ defaultVariants: {
656
+ variant: "default",
657
+ size: "default"
658
+ }
659
+ });
660
+ function normalizePhoneNumber(input) {
661
+ const trimmed = input.trim();
662
+ if (trimmed.toLowerCase().startsWith("tel:")) {
663
+ return trimmed;
664
+ }
665
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
666
+ if (match) {
667
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
668
+ const extension = match[3];
669
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
670
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
671
+ return `tel:${withExtension}`;
672
+ }
673
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
674
+ return `tel:${cleaned}`;
675
+ }
676
+ function normalizeEmail(input) {
677
+ const trimmed = input.trim();
678
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
679
+ return trimmed;
680
+ }
681
+ return `mailto:${trimmed}`;
682
+ }
683
+ function isEmail(input) {
684
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
685
+ return emailRegex.test(input.trim());
686
+ }
687
+ function isPhoneNumber(input) {
688
+ const trimmed = input.trim();
689
+ if (trimmed.toLowerCase().startsWith("tel:")) {
690
+ return true;
691
+ }
692
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
693
+ return phoneRegex.test(trimmed);
694
+ }
695
+ function isInternalUrl(href) {
696
+ if (typeof window === "undefined") {
697
+ return href.startsWith("/") && !href.startsWith("//");
698
+ }
699
+ const trimmed = href.trim();
700
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
701
+ return true;
702
+ }
703
+ try {
704
+ const url = new URL(trimmed, window.location.href);
705
+ const currentOrigin = window.location.origin;
706
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
707
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
708
+ } catch {
709
+ return false;
710
+ }
711
+ }
712
+ function toRelativePath(href) {
713
+ if (typeof window === "undefined") {
714
+ return href;
715
+ }
716
+ const trimmed = href.trim();
717
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
718
+ return trimmed;
719
+ }
720
+ try {
721
+ const url = new URL(trimmed, window.location.href);
722
+ const currentOrigin = window.location.origin;
723
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
724
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
725
+ return url.pathname + url.search + url.hash;
726
+ }
727
+ } catch {
728
+ }
729
+ return trimmed;
730
+ }
731
+ function useNavigation({
732
+ href,
733
+ onClick
734
+ } = {}) {
735
+ const linkType = React__namespace.useMemo(() => {
736
+ if (!href || href.trim() === "") {
737
+ return onClick ? "none" : "none";
738
+ }
739
+ const trimmed = href.trim();
740
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
741
+ return "mailto";
742
+ }
743
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
744
+ return "tel";
745
+ }
746
+ if (isInternalUrl(trimmed)) {
747
+ return "internal";
748
+ }
749
+ try {
750
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
751
+ return "external";
752
+ } catch {
753
+ return "internal";
754
+ }
755
+ }, [href, onClick]);
756
+ const normalizedHref = React__namespace.useMemo(() => {
757
+ if (!href || href.trim() === "") {
758
+ return void 0;
759
+ }
760
+ const trimmed = href.trim();
761
+ switch (linkType) {
762
+ case "tel":
763
+ return normalizePhoneNumber(trimmed);
764
+ case "mailto":
765
+ return normalizeEmail(trimmed);
766
+ case "internal":
767
+ return toRelativePath(trimmed);
768
+ case "external":
769
+ return trimmed;
770
+ default:
771
+ return trimmed;
772
+ }
773
+ }, [href, linkType]);
774
+ const target = React__namespace.useMemo(() => {
775
+ switch (linkType) {
776
+ case "external":
777
+ return "_blank";
778
+ case "internal":
779
+ return "_self";
780
+ case "mailto":
781
+ case "tel":
782
+ return void 0;
783
+ default:
784
+ return void 0;
785
+ }
786
+ }, [linkType]);
787
+ const rel = React__namespace.useMemo(() => {
788
+ if (linkType === "external") {
789
+ return "noopener noreferrer";
790
+ }
791
+ return void 0;
792
+ }, [linkType]);
793
+ const isExternal = linkType === "external";
794
+ const isInternal = linkType === "internal";
795
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
796
+ const handleClick = React__namespace.useCallback(
797
+ (event) => {
798
+ if (onClick) {
799
+ try {
800
+ onClick(event);
801
+ } catch (error) {
802
+ console.error("Error in user onClick handler:", error);
803
+ }
804
+ }
805
+ if (event.defaultPrevented) {
806
+ return;
807
+ }
808
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
809
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
810
+ if (typeof window !== "undefined") {
811
+ const handler = window.__opensiteNavigationHandler;
812
+ if (typeof handler === "function") {
813
+ try {
814
+ const handled = handler(normalizedHref, event.nativeEvent || event);
815
+ if (handled !== false) {
816
+ event.preventDefault();
817
+ }
818
+ } catch (error) {
819
+ console.error("Error in navigation handler:", error);
820
+ }
821
+ }
822
+ }
823
+ }
824
+ },
825
+ [onClick, shouldUseRouter, normalizedHref]
826
+ );
827
+ return {
828
+ linkType,
829
+ normalizedHref,
830
+ target,
831
+ rel,
832
+ isExternal,
833
+ isInternal,
834
+ shouldUseRouter,
835
+ handleClick
836
+ };
837
+ }
838
+ var Pressable = React__namespace.forwardRef(
839
+ ({
840
+ children,
841
+ className,
842
+ href,
843
+ onClick,
844
+ variant,
845
+ size,
846
+ asButton = false,
847
+ fallbackComponentType = "span",
848
+ componentType,
849
+ "aria-label": ariaLabel,
850
+ "aria-describedby": ariaDescribedby,
851
+ id,
852
+ ...props
853
+ }, ref) => {
854
+ const navigation = useNavigation({ href, onClick });
855
+ const {
856
+ normalizedHref,
857
+ target,
858
+ rel,
859
+ linkType,
860
+ isInternal,
861
+ handleClick
862
+ } = navigation;
863
+ const shouldRenderLink = normalizedHref && linkType !== "none";
864
+ const shouldRenderButton = !shouldRenderLink && onClick;
865
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
866
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
867
+ const shouldApplyButtonStyles = asButton || variant || size;
868
+ const combinedClassName = cn(
869
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
870
+ className
871
+ );
872
+ const dataProps = Object.fromEntries(
873
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
874
+ );
875
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
876
+ "data-slot": "button",
877
+ "data-variant": variant ?? "default",
878
+ "data-size": size ?? "default"
879
+ } : {};
880
+ const commonProps = {
881
+ className: combinedClassName,
882
+ onClick: handleClick,
883
+ "aria-label": ariaLabel,
884
+ "aria-describedby": ariaDescribedby,
885
+ id,
886
+ ...dataProps,
887
+ ...buttonDataAttributes
888
+ };
889
+ if (finalComponentType === "a" && shouldRenderLink) {
890
+ return /* @__PURE__ */ jsxRuntime.jsx(
891
+ "a",
892
+ {
893
+ ref,
894
+ href: normalizedHref,
895
+ target,
896
+ rel,
897
+ ...commonProps,
898
+ ...props,
899
+ children
900
+ }
901
+ );
902
+ }
903
+ if (finalComponentType === "button") {
904
+ return /* @__PURE__ */ jsxRuntime.jsx(
905
+ "button",
906
+ {
907
+ ref,
908
+ type: props.type || "button",
909
+ ...commonProps,
910
+ ...props,
911
+ children
912
+ }
913
+ );
914
+ }
915
+ if (finalComponentType === "div") {
916
+ return /* @__PURE__ */ jsxRuntime.jsx(
917
+ "div",
918
+ {
919
+ ref,
920
+ ...commonProps,
921
+ children
922
+ }
923
+ );
924
+ }
925
+ return /* @__PURE__ */ jsxRuntime.jsx(
926
+ "span",
927
+ {
928
+ ref,
929
+ ...commonProps,
930
+ children
931
+ }
932
+ );
933
+ }
934
+ );
935
+ Pressable.displayName = "Pressable";
517
936
  function FeatureIconGridBordered({
518
937
  label,
519
938
  title,
520
939
  features,
521
940
  featuresSlot,
522
941
  className,
523
- containerClassName,
942
+ containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
524
943
  labelClassName,
525
944
  titleClassName,
526
945
  gridClassName,
527
946
  cardClassName,
528
947
  background,
529
- spacing = "py-6 md:py-32",
948
+ spacing = "py-12 md:py-32",
530
949
  pattern,
531
950
  patternOpacity,
532
951
  patternClassName
@@ -545,7 +964,7 @@ function FeatureIconGridBordered({
545
964
  "div",
546
965
  {
547
966
  className: cn(
548
- "relative flex gap-3 rounded-lg border-dashed md:block md:border-l md:p-5",
967
+ "relative flex gap-3 rounded-none border-dashed md:block md:border-l md:p-5",
549
968
  cardClassName,
550
969
  feature.className
551
970
  ),
@@ -554,7 +973,7 @@ function FeatureIconGridBordered({
554
973
  "span",
555
974
  {
556
975
  className: cn(
557
- "mb-8 flex size-10 shrink-0 items-center justify-center rounded-full text-primary-foreground md:size-12",
976
+ "mb-8 flex size-10 shrink-0 items-center justify-center rounded-full text-primary-foreground md:size-16",
558
977
  getAccentColor(background),
559
978
  feature.iconClassName
560
979
  ),
@@ -562,29 +981,24 @@ function FeatureIconGridBordered({
562
981
  }
563
982
  ),
564
983
  /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
565
- feature.title && (typeof feature.title === "string" ? /* @__PURE__ */ jsxRuntime.jsxs(
566
- "h3",
984
+ feature.title && (typeof feature.title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
985
+ Pressable,
567
986
  {
987
+ href: feature.href,
568
988
  className: cn(
569
- "font-medium md:mb-2 md:text-xl",
989
+ "font-medium md:mb-2 text-xl",
570
990
  feature.titleClassName
571
991
  ),
572
- children: [
573
- feature.title,
574
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("absolute -left-px hidden h-6 w-px md:inline-block", getAccentColor(background)) })
575
- ]
992
+ children: feature.title
576
993
  }
577
- ) : /* @__PURE__ */ jsxRuntime.jsxs(
994
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
578
995
  "div",
579
996
  {
580
997
  className: cn(
581
- "font-medium md:mb-2 md:text-xl",
998
+ "font-medium md:mb-2 text-xl",
582
999
  feature.titleClassName
583
1000
  ),
584
- children: [
585
- feature.title,
586
- /* @__PURE__ */ jsxRuntime.jsx("span", { className: cn("absolute -left-px hidden h-6 w-px md:inline-block", getAccentColor(background)) })
587
- ]
1001
+ children: feature.title
588
1002
  }
589
1003
  )),
590
1004
  feature.description && (typeof feature.description === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
@@ -612,7 +1026,7 @@ function FeatureIconGridBordered({
612
1026
  index
613
1027
  ));
614
1028
  }, [featuresSlot, features, cardClassName, renderIcon, background]);
615
- return /* @__PURE__ */ jsxRuntime.jsxs(
1029
+ return /* @__PURE__ */ jsxRuntime.jsx(
616
1030
  Section,
617
1031
  {
618
1032
  background,
@@ -622,32 +1036,40 @@ function FeatureIconGridBordered({
622
1036
  patternClassName,
623
1037
  className,
624
1038
  containerClassName,
625
- children: [
626
- label && (typeof label === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mb-4 text-xs ", labelClassName), children: label }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-4 text-xs ", labelClassName), children: label })),
627
- title && (typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
628
- "h2",
629
- {
630
- className: cn("text-3xl font-medium lg:text-4xl", titleClassName),
631
- children: title
632
- }
633
- ) : /* @__PURE__ */ jsxRuntime.jsx(
634
- "div",
635
- {
636
- className: cn("text-3xl font-medium lg:text-4xl", titleClassName),
637
- children: title
638
- }
639
- )),
1039
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col space-y-6 md:space-y-16", children: [
1040
+ label || title ? /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col", children: [
1041
+ label && (typeof label === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("mb-4 text-sm", labelClassName), children: label }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-4 text-sm", labelClassName), children: label })),
1042
+ title && (typeof title === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
1043
+ "h2",
1044
+ {
1045
+ className: cn(
1046
+ "text-3xl font-medium lg:text-4xl",
1047
+ titleClassName
1048
+ ),
1049
+ children: title
1050
+ }
1051
+ ) : /* @__PURE__ */ jsxRuntime.jsx(
1052
+ "div",
1053
+ {
1054
+ className: cn(
1055
+ "text-3xl font-medium lg:text-4xl",
1056
+ titleClassName
1057
+ ),
1058
+ children: title
1059
+ }
1060
+ ))
1061
+ ] }) : null,
640
1062
  (featuresSlot || features && features.length > 0) && /* @__PURE__ */ jsxRuntime.jsx(
641
1063
  "div",
642
1064
  {
643
1065
  className: cn(
644
- "mt-14 grid gap-6 md:grid-cols-2 lg:mt-20 lg:grid-cols-4",
1066
+ "grid gap-6 md:grid-cols-2 lg:grid-cols-4",
645
1067
  gridClassName
646
1068
  ),
647
1069
  children: featuresContent
648
1070
  }
649
1071
  )
650
- ]
1072
+ ] })
651
1073
  }
652
1074
  );
653
1075
  }
@@ -39,6 +39,10 @@ interface FeatureIconGridBorderedItem {
39
39
  * Additional CSS classes for the description
40
40
  */
41
41
  descriptionClassName?: string;
42
+ /**
43
+ * Optional href for the item
44
+ */
45
+ href?: string;
42
46
  }
43
47
  interface FeatureIconGridBorderedProps {
44
48
  /**
@@ -39,6 +39,10 @@ interface FeatureIconGridBorderedItem {
39
39
  * Additional CSS classes for the description
40
40
  */
41
41
  descriptionClassName?: string;
42
+ /**
43
+ * Optional href for the item
44
+ */
45
+ href?: string;
42
46
  }
43
47
  interface FeatureIconGridBorderedProps {
44
48
  /**