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