@opensite/ui 2.8.6 → 2.8.8

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 (143) hide show
  1. package/dist/about-developer-profile.cjs +17 -10
  2. package/dist/about-developer-profile.js +17 -10
  3. package/dist/article-chapters-author.cjs +17 -10
  4. package/dist/article-chapters-author.js +17 -10
  5. package/dist/carousel-animated-sections.cjs +79 -25
  6. package/dist/carousel-animated-sections.d.cts +7 -2
  7. package/dist/carousel-animated-sections.d.ts +7 -2
  8. package/dist/carousel-animated-sections.js +79 -25
  9. package/dist/carousel-gallery-thumbnails.cjs +79 -25
  10. package/dist/carousel-gallery-thumbnails.d.cts +7 -2
  11. package/dist/carousel-gallery-thumbnails.d.ts +7 -2
  12. package/dist/carousel-gallery-thumbnails.js +79 -25
  13. package/dist/carousel-icon-sidebar.cjs +5 -4
  14. package/dist/carousel-icon-sidebar.js +5 -4
  15. package/dist/carousel-portfolio-hero.cjs +79 -25
  16. package/dist/carousel-portfolio-hero.d.cts +7 -2
  17. package/dist/carousel-portfolio-hero.d.ts +7 -2
  18. package/dist/carousel-portfolio-hero.js +79 -25
  19. package/dist/components.cjs +81 -42
  20. package/dist/components.d.cts +29 -2
  21. package/dist/components.d.ts +29 -2
  22. package/dist/components.js +81 -43
  23. package/dist/contact-map.cjs +46 -32
  24. package/dist/contact-map.js +46 -32
  25. package/dist/footer-accordion-social.cjs +17 -10
  26. package/dist/footer-accordion-social.js +17 -10
  27. package/dist/footer-animated-social.cjs +17 -10
  28. package/dist/footer-animated-social.js +17 -10
  29. package/dist/footer-brand-description.cjs +17 -10
  30. package/dist/footer-brand-description.js +17 -10
  31. package/dist/footer-brand-links-contact.cjs +17 -10
  32. package/dist/footer-brand-links-contact.js +17 -10
  33. package/dist/footer-comprehensive-links.cjs +17 -10
  34. package/dist/footer-comprehensive-links.js +17 -10
  35. package/dist/footer-contact-card.cjs +17 -10
  36. package/dist/footer-contact-card.js +17 -10
  37. package/dist/footer-cta-banner.cjs +17 -10
  38. package/dist/footer-cta-banner.js +17 -10
  39. package/dist/footer-cta-social.cjs +17 -10
  40. package/dist/footer-cta-social.js +17 -10
  41. package/dist/footer-info-cards-accordion.cjs +17 -10
  42. package/dist/footer-info-cards-accordion.js +17 -10
  43. package/dist/footer-nav-social.cjs +17 -10
  44. package/dist/footer-nav-social.js +17 -10
  45. package/dist/footer-newsletter-contact.cjs +17 -10
  46. package/dist/footer-newsletter-contact.js +17 -10
  47. package/dist/footer-newsletter-grid.cjs +17 -10
  48. package/dist/footer-newsletter-grid.js +17 -10
  49. package/dist/footer-newsletter-minimal.cjs +17 -10
  50. package/dist/footer-newsletter-minimal.js +17 -10
  51. package/dist/footer-social-apps.cjs +17 -10
  52. package/dist/footer-social-apps.js +17 -10
  53. package/dist/footer-social-newsletter.cjs +17 -10
  54. package/dist/footer-social-newsletter.js +17 -10
  55. package/dist/footer-split-image-accordion.cjs +17 -10
  56. package/dist/footer-split-image-accordion.js +17 -10
  57. package/dist/geo-map.cjs +46 -32
  58. package/dist/geo-map.js +46 -32
  59. package/dist/hero-coming-soon-countdown.cjs +17 -10
  60. package/dist/hero-coming-soon-countdown.js +17 -10
  61. package/dist/hero-video-background-dark.cjs +78 -16
  62. package/dist/hero-video-background-dark.d.cts +7 -2
  63. package/dist/hero-video-background-dark.d.ts +7 -2
  64. package/dist/hero-video-background-dark.js +78 -16
  65. package/dist/index.cjs +81 -42
  66. package/dist/index.d.cts +1 -0
  67. package/dist/index.d.ts +1 -0
  68. package/dist/index.js +81 -43
  69. package/dist/link-page-bento-layout.cjs +17 -10
  70. package/dist/link-page-bento-layout.js +17 -10
  71. package/dist/link-page-grid-cards.cjs +17 -10
  72. package/dist/link-page-grid-cards.js +17 -10
  73. package/dist/link-page-minimal-profile.cjs +17 -10
  74. package/dist/link-page-minimal-profile.js +17 -10
  75. package/dist/link-page-newsletter-social.cjs +17 -10
  76. package/dist/link-page-newsletter-social.js +17 -10
  77. package/dist/link-tree-block.cjs +17 -10
  78. package/dist/link-tree-block.js +17 -10
  79. package/dist/navbar-fullscreen-menu.cjs +17 -10
  80. package/dist/navbar-fullscreen-menu.js +17 -10
  81. package/dist/navbar-transparent-overlay.cjs +17 -10
  82. package/dist/navbar-transparent-overlay.js +17 -10
  83. package/dist/registry.cjs +967 -620
  84. package/dist/registry.js +967 -620
  85. package/dist/social-link-icon.cjs +17 -10
  86. package/dist/social-link-icon.d.cts +5 -0
  87. package/dist/social-link-icon.d.ts +5 -0
  88. package/dist/social-link-icon.js +17 -10
  89. package/dist/testimonials-bento-grid.cjs +1 -1
  90. package/dist/testimonials-bento-grid.js +1 -1
  91. package/dist/testimonials-carousel-image.cjs +16 -2
  92. package/dist/testimonials-carousel-image.d.cts +5 -1
  93. package/dist/testimonials-carousel-image.d.ts +5 -1
  94. package/dist/testimonials-carousel-image.js +16 -2
  95. package/dist/testimonials-centered-avatars.cjs +1 -1
  96. package/dist/testimonials-centered-avatars.js +1 -1
  97. package/dist/testimonials-grid-add-review.cjs +51 -29
  98. package/dist/testimonials-grid-add-review.js +51 -29
  99. package/dist/testimonials-images-helpful.cjs +181 -160
  100. package/dist/testimonials-images-helpful.d.cts +9 -1
  101. package/dist/testimonials-images-helpful.d.ts +9 -1
  102. package/dist/testimonials-images-helpful.js +181 -159
  103. package/dist/testimonials-large-quote.cjs +74 -43
  104. package/dist/testimonials-large-quote.d.cts +5 -1
  105. package/dist/testimonials-large-quote.d.ts +5 -1
  106. package/dist/testimonials-large-quote.js +74 -43
  107. package/dist/testimonials-list-verified.cjs +63 -44
  108. package/dist/testimonials-list-verified.d.cts +5 -1
  109. package/dist/testimonials-list-verified.d.ts +5 -1
  110. package/dist/testimonials-list-verified.js +64 -45
  111. package/dist/testimonials-logo-cards.cjs +55 -25
  112. package/dist/testimonials-logo-cards.d.cts +5 -1
  113. package/dist/testimonials-logo-cards.d.ts +5 -1
  114. package/dist/testimonials-logo-cards.js +55 -25
  115. package/dist/testimonials-marquee.cjs +440 -28
  116. package/dist/testimonials-marquee.js +441 -26
  117. package/dist/testimonials-masonry-grid.cjs +486 -69
  118. package/dist/testimonials-masonry-grid.d.cts +5 -1
  119. package/dist/testimonials-masonry-grid.d.ts +5 -1
  120. package/dist/testimonials-masonry-grid.js +483 -63
  121. package/dist/testimonials-mini-dividers.cjs +119 -83
  122. package/dist/testimonials-mini-dividers.d.cts +10 -6
  123. package/dist/testimonials-mini-dividers.d.ts +10 -6
  124. package/dist/testimonials-mini-dividers.js +119 -83
  125. package/dist/testimonials-minimal-numbered.cjs +9 -7
  126. package/dist/testimonials-minimal-numbered.d.cts +5 -1
  127. package/dist/testimonials-minimal-numbered.d.ts +5 -1
  128. package/dist/testimonials-minimal-numbered.js +9 -7
  129. package/dist/testimonials-parallax-number.cjs +14 -9
  130. package/dist/testimonials-parallax-number.js +14 -9
  131. package/dist/testimonials-scrolling-columns.cjs +100 -21
  132. package/dist/testimonials-scrolling-columns.js +100 -21
  133. package/dist/testimonials-simple-grid.cjs +22 -5
  134. package/dist/testimonials-simple-grid.js +22 -5
  135. package/dist/testimonials-slider-minimal.cjs +1 -1
  136. package/dist/testimonials-slider-minimal.js +1 -1
  137. package/dist/testimonials-stats-header.cjs +528 -87
  138. package/dist/testimonials-stats-header.d.cts +39 -3
  139. package/dist/testimonials-stats-header.d.ts +39 -3
  140. package/dist/testimonials-stats-header.js +523 -82
  141. package/dist/testimonials-twitter-cards.cjs +20 -12
  142. package/dist/testimonials-twitter-cards.js +20 -12
  143. package/package.json +11 -1
@@ -1,12 +1,13 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var React = require('react');
4
+ var React4 = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
7
  var icon = require('@page-speed/icon');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
9
  var AvatarPrimitive = require('@radix-ui/react-avatar');
10
+ var classVarianceAuthority = require('class-variance-authority');
10
11
 
11
12
  function _interopNamespace(e) {
12
13
  if (e && e.__esModule) return e;
@@ -26,45 +27,15 @@ function _interopNamespace(e) {
26
27
  return Object.freeze(n);
27
28
  }
28
29
 
29
- var React__namespace = /*#__PURE__*/_interopNamespace(React);
30
+ var React4__namespace = /*#__PURE__*/_interopNamespace(React4);
30
31
  var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
31
32
 
32
33
  // components/blocks/testimonials/testimonials-stats-header.tsx
33
34
  function cn(...inputs) {
34
35
  return tailwindMerge.twMerge(clsx.clsx(inputs));
35
36
  }
36
- function getNestedCardBg(parentBg, variant = "muted", options) {
37
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
38
- if (isDark) {
39
- switch (variant) {
40
- case "muted":
41
- return "bg-background";
42
- case "card":
43
- return "bg-card";
44
- case "accent":
45
- return "bg-accent";
46
- case "subtle":
47
- return "bg-background/50";
48
- }
49
- } else {
50
- switch (variant) {
51
- case "muted":
52
- return "bg-muted";
53
- case "card":
54
- return "bg-card";
55
- case "accent":
56
- return "bg-accent";
57
- case "subtle":
58
- return "bg-muted/50";
59
- }
60
- }
61
- }
62
- function getNestedCardTextColor(parentBg, options) {
63
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
64
- return isDark ? "text-foreground" : "";
65
- }
66
37
  var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
67
- var DynamicIcon = React__namespace.memo(function DynamicIcon2({
38
+ var DynamicIcon = React4__namespace.memo(function DynamicIcon2({
68
39
  apiKey,
69
40
  ...props
70
41
  }) {
@@ -148,7 +119,7 @@ var maxWidthStyles = {
148
119
  "4xl": "max-w-[1536px]",
149
120
  full: "max-w-full"
150
121
  };
151
- var Container = React__namespace.default.forwardRef(
122
+ var Container = React4__namespace.default.forwardRef(
152
123
  ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
153
124
  const Component = as;
154
125
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -454,7 +425,7 @@ var spacingStyles = {
454
425
  };
455
426
  var predefinedSpacings = ["none", "sm", "md", "lg", "xl", "hero"];
456
427
  var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
457
- var Section = React__namespace.default.forwardRef(
428
+ var Section = React4__namespace.default.forwardRef(
458
429
  ({
459
430
  id,
460
431
  title,
@@ -515,6 +486,441 @@ var Section = React__namespace.default.forwardRef(
515
486
  }
516
487
  );
517
488
  Section.displayName = "Section";
489
+ function normalizePhoneNumber(input) {
490
+ const trimmed = input.trim();
491
+ if (trimmed.toLowerCase().startsWith("tel:")) {
492
+ return trimmed;
493
+ }
494
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
495
+ if (match) {
496
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
497
+ const extension = match[3];
498
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
499
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
500
+ return `tel:${withExtension}`;
501
+ }
502
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
503
+ return `tel:${cleaned}`;
504
+ }
505
+ function normalizeEmail(input) {
506
+ const trimmed = input.trim();
507
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
508
+ return trimmed;
509
+ }
510
+ return `mailto:${trimmed}`;
511
+ }
512
+ function isEmail(input) {
513
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
514
+ return emailRegex.test(input.trim());
515
+ }
516
+ function isPhoneNumber(input) {
517
+ const trimmed = input.trim();
518
+ if (trimmed.toLowerCase().startsWith("tel:")) {
519
+ return true;
520
+ }
521
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
522
+ return phoneRegex.test(trimmed);
523
+ }
524
+ function isInternalUrl(href) {
525
+ if (typeof window === "undefined") {
526
+ return href.startsWith("/") && !href.startsWith("//");
527
+ }
528
+ const trimmed = href.trim();
529
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
530
+ return true;
531
+ }
532
+ try {
533
+ const url = new URL(trimmed, window.location.href);
534
+ const currentOrigin = window.location.origin;
535
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
536
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
537
+ } catch {
538
+ return false;
539
+ }
540
+ }
541
+ function toRelativePath(href) {
542
+ if (typeof window === "undefined") {
543
+ return href;
544
+ }
545
+ const trimmed = href.trim();
546
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
547
+ return trimmed;
548
+ }
549
+ try {
550
+ const url = new URL(trimmed, window.location.href);
551
+ const currentOrigin = window.location.origin;
552
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
553
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
554
+ return url.pathname + url.search + url.hash;
555
+ }
556
+ } catch {
557
+ }
558
+ return trimmed;
559
+ }
560
+ function useNavigation({
561
+ href,
562
+ onClick
563
+ } = {}) {
564
+ const linkType = React4__namespace.useMemo(() => {
565
+ if (!href || href.trim() === "") {
566
+ return onClick ? "none" : "none";
567
+ }
568
+ const trimmed = href.trim();
569
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
570
+ return "mailto";
571
+ }
572
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
573
+ return "tel";
574
+ }
575
+ if (isInternalUrl(trimmed)) {
576
+ return "internal";
577
+ }
578
+ try {
579
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
580
+ return "external";
581
+ } catch {
582
+ return "internal";
583
+ }
584
+ }, [href, onClick]);
585
+ const normalizedHref = React4__namespace.useMemo(() => {
586
+ if (!href || href.trim() === "") {
587
+ return void 0;
588
+ }
589
+ const trimmed = href.trim();
590
+ switch (linkType) {
591
+ case "tel":
592
+ return normalizePhoneNumber(trimmed);
593
+ case "mailto":
594
+ return normalizeEmail(trimmed);
595
+ case "internal":
596
+ return toRelativePath(trimmed);
597
+ case "external":
598
+ return trimmed;
599
+ default:
600
+ return trimmed;
601
+ }
602
+ }, [href, linkType]);
603
+ const target = React4__namespace.useMemo(() => {
604
+ switch (linkType) {
605
+ case "external":
606
+ return "_blank";
607
+ case "internal":
608
+ return "_self";
609
+ case "mailto":
610
+ case "tel":
611
+ return void 0;
612
+ default:
613
+ return void 0;
614
+ }
615
+ }, [linkType]);
616
+ const rel = React4__namespace.useMemo(() => {
617
+ if (linkType === "external") {
618
+ return "noopener noreferrer";
619
+ }
620
+ return void 0;
621
+ }, [linkType]);
622
+ const isExternal = linkType === "external";
623
+ const isInternal = linkType === "internal";
624
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
625
+ const handleClick = React4__namespace.useCallback(
626
+ (event) => {
627
+ if (onClick) {
628
+ try {
629
+ onClick(event);
630
+ } catch (error) {
631
+ console.error("Error in user onClick handler:", error);
632
+ }
633
+ }
634
+ if (event.defaultPrevented) {
635
+ return;
636
+ }
637
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
638
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
639
+ if (typeof window !== "undefined") {
640
+ const handler = window.__opensiteNavigationHandler;
641
+ if (typeof handler === "function") {
642
+ try {
643
+ const handled = handler(normalizedHref, event.nativeEvent || event);
644
+ if (handled !== false) {
645
+ event.preventDefault();
646
+ }
647
+ } catch (error) {
648
+ console.error("Error in navigation handler:", error);
649
+ }
650
+ }
651
+ }
652
+ }
653
+ },
654
+ [onClick, shouldUseRouter, normalizedHref]
655
+ );
656
+ return {
657
+ linkType,
658
+ normalizedHref,
659
+ target,
660
+ rel,
661
+ isExternal,
662
+ isInternal,
663
+ shouldUseRouter,
664
+ handleClick
665
+ };
666
+ }
667
+ var baseStyles = [
668
+ // Layout
669
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
670
+ // Typography - using CSS variables with sensible defaults
671
+ "font-[var(--button-font-family,inherit)]",
672
+ "font-[var(--button-font-weight,500)]",
673
+ "tracking-[var(--button-letter-spacing,0)]",
674
+ "leading-[var(--button-line-height,1.25)]",
675
+ "[text-transform:var(--button-text-transform,none)]",
676
+ "text-sm",
677
+ // Border radius
678
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
679
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
680
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
681
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
682
+ "[box-shadow:var(--button-shadow,none)]",
683
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
684
+ // Disabled state
685
+ "disabled:pointer-events-none disabled:opacity-50",
686
+ // SVG handling
687
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
688
+ // Focus styles
689
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
690
+ // Invalid state
691
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
692
+ ].join(" ");
693
+ var buttonVariants = classVarianceAuthority.cva(baseStyles, {
694
+ variants: {
695
+ variant: {
696
+ // Default (Primary) variant - full customization
697
+ default: [
698
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
699
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
700
+ "border-[length:var(--button-default-border-width,0px)]",
701
+ "border-[color:var(--button-default-border,transparent)]",
702
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
703
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
704
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
705
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
706
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
707
+ ].join(" "),
708
+ // Destructive variant - full customization
709
+ destructive: [
710
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
711
+ "text-[var(--button-destructive-fg,white)]",
712
+ "border-[length:var(--button-destructive-border-width,0px)]",
713
+ "border-[color:var(--button-destructive-border,transparent)]",
714
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
715
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
716
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
717
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
718
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
719
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
720
+ "dark:bg-destructive/60"
721
+ ].join(" "),
722
+ // Outline variant - full customization with proper border handling
723
+ outline: [
724
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
725
+ "text-[var(--button-outline-fg,inherit)]",
726
+ "border-[length:var(--button-outline-border-width,1px)]",
727
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
728
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
729
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
730
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
731
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
732
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
733
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
734
+ ].join(" "),
735
+ // Secondary variant - full customization
736
+ secondary: [
737
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
738
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
739
+ "border-[length:var(--button-secondary-border-width,0px)]",
740
+ "border-[color:var(--button-secondary-border,transparent)]",
741
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
742
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
743
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
744
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
745
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
746
+ ].join(" "),
747
+ // Ghost variant - full customization
748
+ ghost: [
749
+ "bg-[var(--button-ghost-bg,transparent)]",
750
+ "text-[var(--button-ghost-fg,inherit)]",
751
+ "border-[length:var(--button-ghost-border-width,0px)]",
752
+ "border-[color:var(--button-ghost-border,transparent)]",
753
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
754
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
755
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
756
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
757
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
758
+ "dark:hover:bg-accent/50"
759
+ ].join(" "),
760
+ // Link variant - full customization
761
+ link: [
762
+ "bg-[var(--button-link-bg,transparent)]",
763
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
764
+ "border-[length:var(--button-link-border-width,0px)]",
765
+ "border-[color:var(--button-link-border,transparent)]",
766
+ "[box-shadow:var(--button-link-shadow,none)]",
767
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
768
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
769
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
770
+ "underline-offset-4 hover:underline"
771
+ ].join(" ")
772
+ },
773
+ size: {
774
+ default: [
775
+ "h-[var(--button-height-md,2.25rem)]",
776
+ "px-[var(--button-padding-x-md,1rem)]",
777
+ "py-[var(--button-padding-y-md,0.5rem)]",
778
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
779
+ ].join(" "),
780
+ sm: [
781
+ "h-[var(--button-height-sm,2rem)]",
782
+ "px-[var(--button-padding-x-sm,0.75rem)]",
783
+ "py-[var(--button-padding-y-sm,0.25rem)]",
784
+ "gap-1.5",
785
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
786
+ ].join(" "),
787
+ md: [
788
+ "h-[var(--button-height-md,2.25rem)]",
789
+ "px-[var(--button-padding-x-md,1rem)]",
790
+ "py-[var(--button-padding-y-md,0.5rem)]",
791
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
792
+ ].join(" "),
793
+ lg: [
794
+ "h-[var(--button-height-lg,2.5rem)]",
795
+ "px-[var(--button-padding-x-lg,1.5rem)]",
796
+ "py-[var(--button-padding-y-lg,0.5rem)]",
797
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
798
+ ].join(" "),
799
+ icon: "size-[var(--button-height-md,2.25rem)]",
800
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
801
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
802
+ }
803
+ },
804
+ defaultVariants: {
805
+ variant: "default",
806
+ size: "default"
807
+ }
808
+ });
809
+ var Pressable = React4__namespace.forwardRef(
810
+ ({
811
+ children,
812
+ className,
813
+ href,
814
+ onClick,
815
+ variant,
816
+ size,
817
+ asButton = false,
818
+ fallbackComponentType = "span",
819
+ componentType,
820
+ "aria-label": ariaLabel,
821
+ "aria-describedby": ariaDescribedby,
822
+ id,
823
+ ...props
824
+ }, ref) => {
825
+ const navigation = useNavigation({ href, onClick });
826
+ const {
827
+ normalizedHref,
828
+ target,
829
+ rel,
830
+ linkType,
831
+ isInternal,
832
+ handleClick
833
+ } = navigation;
834
+ const shouldRenderLink = normalizedHref && linkType !== "none";
835
+ const shouldRenderButton = !shouldRenderLink && onClick;
836
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
837
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
838
+ const shouldApplyButtonStyles = asButton || variant || size;
839
+ const combinedClassName = cn(
840
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
841
+ className
842
+ );
843
+ const dataProps = Object.fromEntries(
844
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
845
+ );
846
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
847
+ "data-slot": "button",
848
+ "data-variant": variant ?? "default",
849
+ "data-size": size ?? "default"
850
+ } : {};
851
+ const commonProps = {
852
+ className: combinedClassName,
853
+ onClick: handleClick,
854
+ "aria-label": ariaLabel,
855
+ "aria-describedby": ariaDescribedby,
856
+ id,
857
+ ...dataProps,
858
+ ...buttonDataAttributes
859
+ };
860
+ if (finalComponentType === "a" && shouldRenderLink) {
861
+ return /* @__PURE__ */ jsxRuntime.jsx(
862
+ "a",
863
+ {
864
+ ref,
865
+ href: normalizedHref,
866
+ target,
867
+ rel,
868
+ ...commonProps,
869
+ ...props,
870
+ children
871
+ }
872
+ );
873
+ }
874
+ if (finalComponentType === "button") {
875
+ return /* @__PURE__ */ jsxRuntime.jsx(
876
+ "button",
877
+ {
878
+ ref,
879
+ type: props.type || "button",
880
+ ...commonProps,
881
+ ...props,
882
+ children
883
+ }
884
+ );
885
+ }
886
+ if (finalComponentType === "div") {
887
+ return /* @__PURE__ */ jsxRuntime.jsx(
888
+ "div",
889
+ {
890
+ ref,
891
+ ...commonProps,
892
+ children
893
+ }
894
+ );
895
+ }
896
+ return /* @__PURE__ */ jsxRuntime.jsx(
897
+ "span",
898
+ {
899
+ ref,
900
+ ...commonProps,
901
+ children
902
+ }
903
+ );
904
+ }
905
+ );
906
+ Pressable.displayName = "Pressable";
907
+ function StarRating({
908
+ rating,
909
+ size = 18,
910
+ className
911
+ }) {
912
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("flex items-center gap-0.5", className), children: [1, 2, 3, 4, 5].map((star) => /* @__PURE__ */ jsxRuntime.jsx(
913
+ DynamicIcon,
914
+ {
915
+ name: "icon-park-solid/star",
916
+ size,
917
+ className: cn(
918
+ star <= rating ? "fill-primary text-primary" : "fill-muted text-muted"
919
+ )
920
+ },
921
+ star
922
+ )) });
923
+ }
518
924
  function TestimonialsStatsHeader({
519
925
  stats,
520
926
  statsSlot,
@@ -530,6 +936,7 @@ function TestimonialsStatsHeader({
530
936
  statItemClassName,
531
937
  testimonialsGridClassName,
532
938
  cardClassName,
939
+ statCardClassName,
533
940
  quoteClassName,
534
941
  authorClassName,
535
942
  background,
@@ -538,49 +945,59 @@ function TestimonialsStatsHeader({
538
945
  pattern,
539
946
  patternOpacity
540
947
  }) {
541
- const getAuthorName = React.useCallback((testimonial) => {
948
+ const getAuthorName = React4.useCallback((testimonial) => {
542
949
  if (typeof testimonial.author === "string") return testimonial.author;
543
950
  return "";
544
951
  }, []);
545
- const getAvatarSrc = React.useCallback(
952
+ const getAvatarSrc = React4.useCallback(
546
953
  (testimonial) => {
547
954
  return testimonial.avatarSrc || testimonial.avatar?.src;
548
955
  },
549
956
  []
550
957
  );
551
- const getInitials = React.useCallback((name) => {
958
+ const renderStatIcon = React4.useCallback((stat) => {
959
+ if (stat.iconSlot) return stat.iconSlot;
960
+ if (!stat.icon) return null;
961
+ return /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-6", children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: stat.icon, size: 32, className: stat.iconColor }) });
962
+ }, []);
963
+ const getInitials = React4.useCallback((name) => {
552
964
  return name.split(" ").map((n) => n[0]).join("");
553
965
  }, []);
554
- const renderedStats = React.useMemo(() => {
966
+ const renderedStats = React4.useMemo(() => {
555
967
  if (statsSlot) return statsSlot;
556
968
  if (!stats || stats.length === 0) return null;
557
969
  return /* @__PURE__ */ jsxRuntime.jsx(
558
970
  "div",
559
971
  {
560
972
  className: cn(
561
- "mb-12 grid grid-cols-2 gap-4 md:grid-cols-4",
973
+ "mb-12 grid gap-6 md:grid-cols-2 lg:grid-cols-3",
562
974
  statsGridClassName
563
975
  ),
564
- children: stats.map((stat, index) => /* @__PURE__ */ jsxRuntime.jsxs(
565
- "div",
976
+ children: stats.map((stat) => /* @__PURE__ */ jsxRuntime.jsx(
977
+ Card,
566
978
  {
567
979
  className: cn(
568
- "rounded-lg p-6 text-center",
569
- getNestedCardBg(background),
570
- getNestedCardTextColor(background),
571
- statItemClassName
980
+ "overflow-hidden border p-0",
981
+ stat.className,
982
+ statCardClassName
572
983
  ),
573
- children: [
574
- typeof stat.value === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-3xl font-bold text-primary md:text-4xl", children: stat.value }) : stat.value,
575
- typeof stat.label === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "mt-1 text-sm text-muted-foreground", children: stat.label }) : stat.label
576
- ]
984
+ children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-6 md:p-8", children: [
985
+ renderStatIcon(stat),
986
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mb-2 flex items-end", children: [
987
+ stat.prefix && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 mr-1 text-2xl font-bold", children: stat.prefix }),
988
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-4xl font-bold tracking-tight leading-tight md:text-5xl", children: stat.value }),
989
+ stat.suffix && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "mb-1 ml-1 text-2xl font-bold", children: stat.suffix })
990
+ ] }),
991
+ stat.label && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 text-xl font-semibold", children: stat.label }),
992
+ stat.description && (typeof stat.description === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "opacity-75", children: stat.description }) : stat.description)
993
+ ] })
577
994
  },
578
- index
995
+ stat.id
579
996
  ))
580
997
  }
581
998
  );
582
999
  }, [statsSlot, stats, statsGridClassName, statItemClassName]);
583
- const renderedTestimonials = React.useMemo(() => {
1000
+ const renderedTestimonials = React4.useMemo(() => {
584
1001
  if (testimonialsSlot) return testimonialsSlot;
585
1002
  if (!testimonials || testimonials.length === 0) return null;
586
1003
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -590,41 +1007,65 @@ function TestimonialsStatsHeader({
590
1007
  children: testimonials.map((testimonial, index) => {
591
1008
  const authorName = getAuthorName(testimonial);
592
1009
  const avatarSrc = getAvatarSrc(testimonial);
593
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cardClassName, children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-6", children: [
594
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "mb-4 flex gap-1", children: [...Array(5)].map((_, i) => /* @__PURE__ */ jsxRuntime.jsx(
595
- DynamicIcon,
596
- {
597
- name: "lucide/star",
598
- size: 16,
599
- className: "fill-primary text-primary"
600
- },
601
- i
602
- )) }),
603
- testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsxRuntime.jsxs(
604
- "p",
605
- {
606
- className: cn(
607
- "mb-6 text-sm leading-relaxed",
608
- quoteClassName
609
- ),
610
- children: [
611
- "\u201C",
612
- testimonial.quote,
613
- "\u201D"
614
- ]
615
- }
616
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-6", quoteClassName), children: testimonial.quote })),
617
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("flex items-center gap-3", authorClassName), children: [
618
- /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-10", children: [
619
- /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: avatarSrc, alt: authorName }),
620
- /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { children: getInitials(authorName) })
621
- ] }),
622
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
623
- testimonial.author && (typeof testimonial.author === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: testimonial.author }) : testimonial.author),
624
- testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: testimonial.role }) : testimonial.role)
625
- ] })
626
- ] })
627
- ] }) }, index);
1010
+ return /* @__PURE__ */ jsxRuntime.jsx(
1011
+ "div",
1012
+ {
1013
+ className: cn(
1014
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-2xl border py-0 shadow-xl",
1015
+ cardClassName
1016
+ ),
1017
+ children: /* @__PURE__ */ jsxRuntime.jsx(CardContent, { className: "p-6", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-12 justify-between", children: [
1018
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex flex-col items-start gap-4", children: [
1019
+ /* @__PURE__ */ jsxRuntime.jsx(StarRating, { rating: 5, size: 20 }),
1020
+ testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsxRuntime.jsxs(
1021
+ "p",
1022
+ {
1023
+ className: cn(
1024
+ "mb-6 text-sm leading-relaxed",
1025
+ quoteClassName
1026
+ ),
1027
+ children: [
1028
+ "\u201C",
1029
+ testimonial.quote,
1030
+ "\u201D"
1031
+ ]
1032
+ }
1033
+ ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-6", quoteClassName), children: testimonial.quote }))
1034
+ ] }),
1035
+ /* @__PURE__ */ jsxRuntime.jsxs(
1036
+ "div",
1037
+ {
1038
+ className: cn("flex items-center gap-3", authorClassName),
1039
+ children: [
1040
+ /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-10", children: [
1041
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: avatarSrc, alt: authorName }),
1042
+ /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { children: getInitials(authorName) })
1043
+ ] }),
1044
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-2", children: [
1045
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1046
+ testimonial.author && (typeof testimonial.author === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base font-medium", children: testimonial.author }) : testimonial.author),
1047
+ testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm opacity-75", children: testimonial.role }) : testimonial.role)
1048
+ ] }),
1049
+ testimonial.linkConfig?.href && /* @__PURE__ */ jsxRuntime.jsx(
1050
+ Pressable,
1051
+ {
1052
+ href: testimonial.linkConfig.href,
1053
+ className: cn(
1054
+ "text-sm transition-all duration-300",
1055
+ "hover:underline hover:underline-offset-4",
1056
+ testimonial.linkConfig.className
1057
+ ),
1058
+ children: testimonial.linkConfig.label
1059
+ }
1060
+ )
1061
+ ] })
1062
+ ]
1063
+ }
1064
+ )
1065
+ ] }) })
1066
+ },
1067
+ index
1068
+ );
628
1069
  })
629
1070
  }
630
1071
  );