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