@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,13 +1,12 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var React = require('react');
4
+ var React3 = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
7
  var AvatarPrimitive = require('@radix-ui/react-avatar');
8
8
  var jsxRuntime = require('react/jsx-runtime');
9
-
10
- function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
9
+ var classVarianceAuthority = require('class-variance-authority');
11
10
 
12
11
  function _interopNamespace(e) {
13
12
  if (e && e.__esModule) return e;
@@ -27,7 +26,7 @@ function _interopNamespace(e) {
27
26
  return Object.freeze(n);
28
27
  }
29
28
 
30
- var React__default = /*#__PURE__*/_interopDefault(React);
29
+ var React3__namespace = /*#__PURE__*/_interopNamespace(React3);
31
30
  var AvatarPrimitive__namespace = /*#__PURE__*/_interopNamespace(AvatarPrimitive);
32
31
 
33
32
  // components/blocks/testimonials/testimonials-masonry-grid.tsx
@@ -79,29 +78,6 @@ function AvatarFallback({
79
78
  }
80
79
  );
81
80
  }
82
- function Card({ className, ...props }) {
83
- return /* @__PURE__ */ jsxRuntime.jsx(
84
- "div",
85
- {
86
- "data-slot": "card",
87
- className: cn(
88
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
89
- className
90
- ),
91
- ...props
92
- }
93
- );
94
- }
95
- function CardContent({ className, ...props }) {
96
- return /* @__PURE__ */ jsxRuntime.jsx(
97
- "div",
98
- {
99
- "data-slot": "card-content",
100
- className: cn("px-6", className),
101
- ...props
102
- }
103
- );
104
- }
105
81
  var maxWidthStyles = {
106
82
  sm: "max-w-screen-sm",
107
83
  md: "max-w-screen-md",
@@ -111,7 +87,7 @@ var maxWidthStyles = {
111
87
  "4xl": "max-w-[1536px]",
112
88
  full: "max-w-full"
113
89
  };
114
- var Container = React__default.default.forwardRef(
90
+ var Container = React3__namespace.default.forwardRef(
115
91
  ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
116
92
  const Component = as;
117
93
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -417,7 +393,7 @@ var spacingStyles = {
417
393
  };
418
394
  var predefinedSpacings = ["none", "sm", "md", "lg", "xl", "hero"];
419
395
  var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
420
- var Section = React__default.default.forwardRef(
396
+ var Section = React3__namespace.default.forwardRef(
421
397
  ({
422
398
  id,
423
399
  title,
@@ -478,6 +454,424 @@ var Section = React__default.default.forwardRef(
478
454
  }
479
455
  );
480
456
  Section.displayName = "Section";
457
+ function normalizePhoneNumber(input) {
458
+ const trimmed = input.trim();
459
+ if (trimmed.toLowerCase().startsWith("tel:")) {
460
+ return trimmed;
461
+ }
462
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
463
+ if (match) {
464
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
465
+ const extension = match[3];
466
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
467
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
468
+ return `tel:${withExtension}`;
469
+ }
470
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
471
+ return `tel:${cleaned}`;
472
+ }
473
+ function normalizeEmail(input) {
474
+ const trimmed = input.trim();
475
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
476
+ return trimmed;
477
+ }
478
+ return `mailto:${trimmed}`;
479
+ }
480
+ function isEmail(input) {
481
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
482
+ return emailRegex.test(input.trim());
483
+ }
484
+ function isPhoneNumber(input) {
485
+ const trimmed = input.trim();
486
+ if (trimmed.toLowerCase().startsWith("tel:")) {
487
+ return true;
488
+ }
489
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
490
+ return phoneRegex.test(trimmed);
491
+ }
492
+ function isInternalUrl(href) {
493
+ if (typeof window === "undefined") {
494
+ return href.startsWith("/") && !href.startsWith("//");
495
+ }
496
+ const trimmed = href.trim();
497
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
498
+ return true;
499
+ }
500
+ try {
501
+ const url = new URL(trimmed, window.location.href);
502
+ const currentOrigin = window.location.origin;
503
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
504
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
505
+ } catch {
506
+ return false;
507
+ }
508
+ }
509
+ function toRelativePath(href) {
510
+ if (typeof window === "undefined") {
511
+ return href;
512
+ }
513
+ const trimmed = href.trim();
514
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
515
+ return trimmed;
516
+ }
517
+ try {
518
+ const url = new URL(trimmed, window.location.href);
519
+ const currentOrigin = window.location.origin;
520
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
521
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
522
+ return url.pathname + url.search + url.hash;
523
+ }
524
+ } catch {
525
+ }
526
+ return trimmed;
527
+ }
528
+ function useNavigation({
529
+ href,
530
+ onClick
531
+ } = {}) {
532
+ const linkType = React3__namespace.useMemo(() => {
533
+ if (!href || href.trim() === "") {
534
+ return onClick ? "none" : "none";
535
+ }
536
+ const trimmed = href.trim();
537
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
538
+ return "mailto";
539
+ }
540
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
541
+ return "tel";
542
+ }
543
+ if (isInternalUrl(trimmed)) {
544
+ return "internal";
545
+ }
546
+ try {
547
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
548
+ return "external";
549
+ } catch {
550
+ return "internal";
551
+ }
552
+ }, [href, onClick]);
553
+ const normalizedHref = React3__namespace.useMemo(() => {
554
+ if (!href || href.trim() === "") {
555
+ return void 0;
556
+ }
557
+ const trimmed = href.trim();
558
+ switch (linkType) {
559
+ case "tel":
560
+ return normalizePhoneNumber(trimmed);
561
+ case "mailto":
562
+ return normalizeEmail(trimmed);
563
+ case "internal":
564
+ return toRelativePath(trimmed);
565
+ case "external":
566
+ return trimmed;
567
+ default:
568
+ return trimmed;
569
+ }
570
+ }, [href, linkType]);
571
+ const target = React3__namespace.useMemo(() => {
572
+ switch (linkType) {
573
+ case "external":
574
+ return "_blank";
575
+ case "internal":
576
+ return "_self";
577
+ case "mailto":
578
+ case "tel":
579
+ return void 0;
580
+ default:
581
+ return void 0;
582
+ }
583
+ }, [linkType]);
584
+ const rel = React3__namespace.useMemo(() => {
585
+ if (linkType === "external") {
586
+ return "noopener noreferrer";
587
+ }
588
+ return void 0;
589
+ }, [linkType]);
590
+ const isExternal = linkType === "external";
591
+ const isInternal = linkType === "internal";
592
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
593
+ const handleClick = React3__namespace.useCallback(
594
+ (event) => {
595
+ if (onClick) {
596
+ try {
597
+ onClick(event);
598
+ } catch (error) {
599
+ console.error("Error in user onClick handler:", error);
600
+ }
601
+ }
602
+ if (event.defaultPrevented) {
603
+ return;
604
+ }
605
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
606
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
607
+ if (typeof window !== "undefined") {
608
+ const handler = window.__opensiteNavigationHandler;
609
+ if (typeof handler === "function") {
610
+ try {
611
+ const handled = handler(normalizedHref, event.nativeEvent || event);
612
+ if (handled !== false) {
613
+ event.preventDefault();
614
+ }
615
+ } catch (error) {
616
+ console.error("Error in navigation handler:", error);
617
+ }
618
+ }
619
+ }
620
+ }
621
+ },
622
+ [onClick, shouldUseRouter, normalizedHref]
623
+ );
624
+ return {
625
+ linkType,
626
+ normalizedHref,
627
+ target,
628
+ rel,
629
+ isExternal,
630
+ isInternal,
631
+ shouldUseRouter,
632
+ handleClick
633
+ };
634
+ }
635
+ var baseStyles = [
636
+ // Layout
637
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
638
+ // Typography - using CSS variables with sensible defaults
639
+ "font-[var(--button-font-family,inherit)]",
640
+ "font-[var(--button-font-weight,500)]",
641
+ "tracking-[var(--button-letter-spacing,0)]",
642
+ "leading-[var(--button-line-height,1.25)]",
643
+ "[text-transform:var(--button-text-transform,none)]",
644
+ "text-sm",
645
+ // Border radius
646
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
647
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
648
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
649
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
650
+ "[box-shadow:var(--button-shadow,none)]",
651
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
652
+ // Disabled state
653
+ "disabled:pointer-events-none disabled:opacity-50",
654
+ // SVG handling
655
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
656
+ // Focus styles
657
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
658
+ // Invalid state
659
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
660
+ ].join(" ");
661
+ var buttonVariants = classVarianceAuthority.cva(baseStyles, {
662
+ variants: {
663
+ variant: {
664
+ // Default (Primary) variant - full customization
665
+ default: [
666
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
667
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
668
+ "border-[length:var(--button-default-border-width,0px)]",
669
+ "border-[color:var(--button-default-border,transparent)]",
670
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
671
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
672
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
673
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
674
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
675
+ ].join(" "),
676
+ // Destructive variant - full customization
677
+ destructive: [
678
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
679
+ "text-[var(--button-destructive-fg,white)]",
680
+ "border-[length:var(--button-destructive-border-width,0px)]",
681
+ "border-[color:var(--button-destructive-border,transparent)]",
682
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
683
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
684
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
685
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
686
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
687
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
688
+ "dark:bg-destructive/60"
689
+ ].join(" "),
690
+ // Outline variant - full customization with proper border handling
691
+ outline: [
692
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
693
+ "text-[var(--button-outline-fg,inherit)]",
694
+ "border-[length:var(--button-outline-border-width,1px)]",
695
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
696
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
697
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
698
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
699
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
700
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
701
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
702
+ ].join(" "),
703
+ // Secondary variant - full customization
704
+ secondary: [
705
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
706
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
707
+ "border-[length:var(--button-secondary-border-width,0px)]",
708
+ "border-[color:var(--button-secondary-border,transparent)]",
709
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
710
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
711
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
712
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
713
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
714
+ ].join(" "),
715
+ // Ghost variant - full customization
716
+ ghost: [
717
+ "bg-[var(--button-ghost-bg,transparent)]",
718
+ "text-[var(--button-ghost-fg,inherit)]",
719
+ "border-[length:var(--button-ghost-border-width,0px)]",
720
+ "border-[color:var(--button-ghost-border,transparent)]",
721
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
722
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
723
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
724
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
725
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
726
+ "dark:hover:bg-accent/50"
727
+ ].join(" "),
728
+ // Link variant - full customization
729
+ link: [
730
+ "bg-[var(--button-link-bg,transparent)]",
731
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
732
+ "border-[length:var(--button-link-border-width,0px)]",
733
+ "border-[color:var(--button-link-border,transparent)]",
734
+ "[box-shadow:var(--button-link-shadow,none)]",
735
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
736
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
737
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
738
+ "underline-offset-4 hover:underline"
739
+ ].join(" ")
740
+ },
741
+ size: {
742
+ default: [
743
+ "h-[var(--button-height-md,2.25rem)]",
744
+ "px-[var(--button-padding-x-md,1rem)]",
745
+ "py-[var(--button-padding-y-md,0.5rem)]",
746
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
747
+ ].join(" "),
748
+ sm: [
749
+ "h-[var(--button-height-sm,2rem)]",
750
+ "px-[var(--button-padding-x-sm,0.75rem)]",
751
+ "py-[var(--button-padding-y-sm,0.25rem)]",
752
+ "gap-1.5",
753
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
754
+ ].join(" "),
755
+ md: [
756
+ "h-[var(--button-height-md,2.25rem)]",
757
+ "px-[var(--button-padding-x-md,1rem)]",
758
+ "py-[var(--button-padding-y-md,0.5rem)]",
759
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
760
+ ].join(" "),
761
+ lg: [
762
+ "h-[var(--button-height-lg,2.5rem)]",
763
+ "px-[var(--button-padding-x-lg,1.5rem)]",
764
+ "py-[var(--button-padding-y-lg,0.5rem)]",
765
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
766
+ ].join(" "),
767
+ icon: "size-[var(--button-height-md,2.25rem)]",
768
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
769
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
770
+ }
771
+ },
772
+ defaultVariants: {
773
+ variant: "default",
774
+ size: "default"
775
+ }
776
+ });
777
+ var Pressable = React3__namespace.forwardRef(
778
+ ({
779
+ children,
780
+ className,
781
+ href,
782
+ onClick,
783
+ variant,
784
+ size,
785
+ asButton = false,
786
+ fallbackComponentType = "span",
787
+ componentType,
788
+ "aria-label": ariaLabel,
789
+ "aria-describedby": ariaDescribedby,
790
+ id,
791
+ ...props
792
+ }, ref) => {
793
+ const navigation = useNavigation({ href, onClick });
794
+ const {
795
+ normalizedHref,
796
+ target,
797
+ rel,
798
+ linkType,
799
+ isInternal,
800
+ handleClick
801
+ } = navigation;
802
+ const shouldRenderLink = normalizedHref && linkType !== "none";
803
+ const shouldRenderButton = !shouldRenderLink && onClick;
804
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
805
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
806
+ const shouldApplyButtonStyles = asButton || variant || size;
807
+ const combinedClassName = cn(
808
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
809
+ className
810
+ );
811
+ const dataProps = Object.fromEntries(
812
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
813
+ );
814
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
815
+ "data-slot": "button",
816
+ "data-variant": variant ?? "default",
817
+ "data-size": size ?? "default"
818
+ } : {};
819
+ const commonProps = {
820
+ className: combinedClassName,
821
+ onClick: handleClick,
822
+ "aria-label": ariaLabel,
823
+ "aria-describedby": ariaDescribedby,
824
+ id,
825
+ ...dataProps,
826
+ ...buttonDataAttributes
827
+ };
828
+ if (finalComponentType === "a" && shouldRenderLink) {
829
+ return /* @__PURE__ */ jsxRuntime.jsx(
830
+ "a",
831
+ {
832
+ ref,
833
+ href: normalizedHref,
834
+ target,
835
+ rel,
836
+ ...commonProps,
837
+ ...props,
838
+ children
839
+ }
840
+ );
841
+ }
842
+ if (finalComponentType === "button") {
843
+ return /* @__PURE__ */ jsxRuntime.jsx(
844
+ "button",
845
+ {
846
+ ref,
847
+ type: props.type || "button",
848
+ ...commonProps,
849
+ ...props,
850
+ children
851
+ }
852
+ );
853
+ }
854
+ if (finalComponentType === "div") {
855
+ return /* @__PURE__ */ jsxRuntime.jsx(
856
+ "div",
857
+ {
858
+ ref,
859
+ ...commonProps,
860
+ children
861
+ }
862
+ );
863
+ }
864
+ return /* @__PURE__ */ jsxRuntime.jsx(
865
+ "span",
866
+ {
867
+ ref,
868
+ ...commonProps,
869
+ children
870
+ }
871
+ );
872
+ }
873
+ );
874
+ Pressable.displayName = "Pressable";
481
875
  function TestimonialsMasonryGrid({
482
876
  testimonials,
483
877
  testimonialsSlot,
@@ -492,7 +886,8 @@ function TestimonialsMasonryGrid({
492
886
  quoteClassName,
493
887
  authorClassName,
494
888
  background,
495
- spacing,
889
+ containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
890
+ spacing = "xl",
496
891
  pattern,
497
892
  patternOpacity
498
893
  }) {
@@ -501,17 +896,20 @@ function TestimonialsMasonryGrid({
501
896
  testimonials.filter((_, i) => i % 3 === 1),
502
897
  testimonials.filter((_, i) => i % 3 === 2)
503
898
  ] : [];
504
- const getAuthorName = React.useCallback((testimonial) => {
899
+ const getAuthorName = React3.useCallback((testimonial) => {
505
900
  if (typeof testimonial.author === "string") return testimonial.author;
506
901
  return "";
507
902
  }, []);
508
- const getAvatarSrc = React.useCallback((testimonial) => {
509
- return testimonial.avatarSrc || testimonial.avatar?.src;
510
- }, []);
511
- const getInitials = React.useCallback((name) => {
903
+ const getAvatarSrc = React3.useCallback(
904
+ (testimonial) => {
905
+ return testimonial.avatarSrc || testimonial.avatar?.src;
906
+ },
907
+ []
908
+ );
909
+ const getInitials = React3.useCallback((name) => {
512
910
  return name.split(" ").map((n) => n[0]).join("");
513
911
  }, []);
514
- const renderedTestimonials = React.useMemo(() => {
912
+ const renderedTestimonials = React3.useMemo(() => {
515
913
  if (testimonialsSlot) return testimonialsSlot;
516
914
  if (!testimonials || testimonials.length === 0) return null;
517
915
  return /* @__PURE__ */ jsxRuntime.jsx(
@@ -524,42 +922,60 @@ function TestimonialsMasonryGrid({
524
922
  children: columns.map((column, columnIndex) => /* @__PURE__ */ jsxRuntime.jsx("div", { className: "space-y-4", children: column.map((testimonial, index) => {
525
923
  const authorName = getAuthorName(testimonial);
526
924
  const avatarSrc = getAvatarSrc(testimonial);
527
- return /* @__PURE__ */ jsxRuntime.jsx(Card, { className: cardClassName, children: /* @__PURE__ */ jsxRuntime.jsxs(CardContent, { className: "p-6", children: [
528
- testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsxRuntime.jsxs(
529
- "p",
530
- {
531
- className: cn(
532
- "mb-4 text-sm leading-relaxed",
533
- quoteClassName
534
- ),
535
- children: [
925
+ return /* @__PURE__ */ jsxRuntime.jsx(
926
+ "div",
927
+ {
928
+ className: cn(
929
+ cardClassName,
930
+ "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border shadow-sm"
931
+ ),
932
+ children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex h-full flex-col justify-between p-6 gap-8", children: [
933
+ testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsxRuntime.jsxs("blockquote", { className: "text-sm leading-relaxed line-clamp-3", children: [
536
934
  "\u201C",
537
935
  testimonial.quote,
538
936
  "\u201D"
539
- ]
540
- }
541
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mb-4", quoteClassName), children: testimonial.quote })),
542
- /* @__PURE__ */ jsxRuntime.jsxs(
543
- "div",
544
- {
545
- className: cn("flex items-center gap-3", authorClassName),
546
- children: [
547
- /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "size-9", children: [
937
+ ] }) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: "line-clamp-3", children: testimonial.quote })),
938
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "mt-4 flex items-center gap-3", children: [
939
+ /* @__PURE__ */ jsxRuntime.jsxs(Avatar, { className: "relative flex shrink-0 overflow-hidden rounded-full size-12 ring-4 ring-primary shadow-lg", children: [
548
940
  /* @__PURE__ */ jsxRuntime.jsx(AvatarImage, { src: avatarSrc, alt: authorName }),
549
941
  /* @__PURE__ */ jsxRuntime.jsx(AvatarFallback, { className: "text-xs", children: getInitials(authorName) })
550
942
  ] }),
551
- /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
943
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-0 leading-tight", children: [
552
944
  testimonial.author && (typeof testimonial.author === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-sm font-medium", children: testimonial.author }) : testimonial.author),
553
- testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs text-muted-foreground", children: testimonial.role }) : testimonial.role)
945
+ testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-xs", children: testimonial.role }) : testimonial.role),
946
+ testimonial.linkConfig?.href && /* @__PURE__ */ jsxRuntime.jsx(
947
+ Pressable,
948
+ {
949
+ href: testimonial.linkConfig.href,
950
+ className: cn(
951
+ "text-sm transition-all duration-300",
952
+ "underline underline-offset-4",
953
+ testimonial.linkConfig.className
954
+ ),
955
+ children: testimonial.linkConfig.label
956
+ }
957
+ )
554
958
  ] })
555
- ]
556
- }
557
- )
558
- ] }) }, index);
959
+ ] })
960
+ ] })
961
+ },
962
+ index
963
+ );
559
964
  }) }, columnIndex))
560
965
  }
561
966
  );
562
- }, [testimonialsSlot, gridClassName, columns, cardClassName, quoteClassName, authorClassName, testimonials, getAuthorName, getAvatarSrc, getInitials]);
967
+ }, [
968
+ testimonialsSlot,
969
+ gridClassName,
970
+ columns,
971
+ cardClassName,
972
+ quoteClassName,
973
+ authorClassName,
974
+ testimonials,
975
+ getAuthorName,
976
+ getAvatarSrc,
977
+ getInitials
978
+ ]);
563
979
  return /* @__PURE__ */ jsxRuntime.jsxs(
564
980
  Section,
565
981
  {
@@ -568,32 +984,33 @@ function TestimonialsMasonryGrid({
568
984
  pattern,
569
985
  patternOpacity,
570
986
  className,
987
+ containerClassName,
571
988
  children: [
572
989
  /* @__PURE__ */ jsxRuntime.jsxs(
573
990
  "div",
574
991
  {
575
- className: cn("mx-auto mb-12 max-w-2xl text-center", headerClassName),
992
+ className: cn(
993
+ "mx-auto mb-12 max-w-full md:max-w-2xl text-center",
994
+ headerClassName
995
+ ),
576
996
  children: [
577
997
  heading && (typeof heading === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
578
998
  "h2",
579
999
  {
580
1000
  className: cn(
581
- "text-3xl font-semibold tracking-tight md:text-4xl",
1001
+ "text-3xl font-semibold tracking-tight md:text-4xl lg:text-6xl text-balance",
582
1002
  headingClassName
583
1003
  ),
584
1004
  children: heading
585
1005
  }
586
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: headingClassName, children: heading })),
1006
+ ) : heading),
587
1007
  description && (typeof description === "string" ? /* @__PURE__ */ jsxRuntime.jsx(
588
1008
  "p",
589
1009
  {
590
- className: cn(
591
- "mt-4 text-lg text-muted-foreground",
592
- descriptionClassName
593
- ),
1010
+ className: cn("mt-4 text-lg text-balance", descriptionClassName),
594
1011
  children: description
595
1012
  }
596
- ) : /* @__PURE__ */ jsxRuntime.jsx("div", { className: cn("mt-4", descriptionClassName), children: description }))
1013
+ ) : description)
597
1014
  ]
598
1015
  }
599
1016
  ),
@@ -72,6 +72,10 @@ interface TestimonialsMasonryGridProps {
72
72
  * Pattern overlay opacity (0-1)
73
73
  */
74
74
  patternOpacity?: number;
75
+ /**
76
+ * Additional CSS classes for the container
77
+ */
78
+ containerClassName?: string;
75
79
  }
76
80
  /**
77
81
  * TestimonialsMasonryGrid - A masonry-style grid layout for testimonials with varying
@@ -98,6 +102,6 @@ interface TestimonialsMasonryGridProps {
98
102
  * />
99
103
  * ```
100
104
  */
101
- declare function TestimonialsMasonryGrid({ testimonials, testimonialsSlot, heading, description, className, headerClassName, headingClassName, descriptionClassName, gridClassName, cardClassName, quoteClassName, authorClassName, background, spacing, pattern, patternOpacity, }: TestimonialsMasonryGridProps): React.JSX.Element;
105
+ declare function TestimonialsMasonryGrid({ testimonials, testimonialsSlot, heading, description, className, headerClassName, headingClassName, descriptionClassName, gridClassName, cardClassName, quoteClassName, authorClassName, background, containerClassName, spacing, pattern, patternOpacity, }: TestimonialsMasonryGridProps): React.JSX.Element;
102
106
 
103
107
  export { TestimonialsMasonryGrid, type TestimonialsMasonryGridProps };