@opensite/ui 1.2.4 → 1.2.6

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