@opensite/ui 2.8.7 → 2.8.9

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 (163) hide show
  1. package/dist/about-culture-tabs.cjs +174 -174
  2. package/dist/about-culture-tabs.js +174 -174
  3. package/dist/about-developer-profile.cjs +200 -200
  4. package/dist/about-developer-profile.js +198 -198
  5. package/dist/about-developer-story.cjs +142 -142
  6. package/dist/about-developer-story.js +142 -142
  7. package/dist/about-mission-dual-image.cjs +142 -142
  8. package/dist/about-mission-dual-image.js +142 -142
  9. package/dist/about-mission-features.cjs +142 -142
  10. package/dist/about-mission-features.js +142 -142
  11. package/dist/about-network-spotlight.cjs +142 -142
  12. package/dist/about-network-spotlight.js +142 -142
  13. package/dist/about-story-expertise.cjs +142 -142
  14. package/dist/about-story-expertise.js +142 -142
  15. package/dist/about-streamline-team.cjs +142 -142
  16. package/dist/about-streamline-team.js +142 -142
  17. package/dist/carousel-icon-sidebar.cjs +5 -4
  18. package/dist/carousel-icon-sidebar.js +5 -4
  19. package/dist/community-initiatives.cjs +142 -142
  20. package/dist/community-initiatives.js +142 -142
  21. package/dist/components.cjs +723 -1364
  22. package/dist/components.d.cts +0 -2
  23. package/dist/components.d.ts +0 -2
  24. package/dist/components.js +633 -1273
  25. package/dist/contact-map.cjs +14 -1069
  26. package/dist/contact-map.d.cts +13 -3
  27. package/dist/contact-map.d.ts +13 -3
  28. package/dist/contact-map.js +14 -1069
  29. package/dist/cta-feature-checklist.cjs +142 -142
  30. package/dist/cta-feature-checklist.js +142 -142
  31. package/dist/faq-numbered-grid.cjs +142 -142
  32. package/dist/faq-numbered-grid.js +142 -142
  33. package/dist/feature-animated-carousel.cjs +142 -142
  34. package/dist/feature-animated-carousel.js +142 -142
  35. package/dist/feature-bento-utilities.cjs +142 -142
  36. package/dist/feature-bento-utilities.js +142 -142
  37. package/dist/feature-capabilities-grid.cjs +142 -142
  38. package/dist/feature-capabilities-grid.js +142 -142
  39. package/dist/feature-category-image-cards.cjs +142 -142
  40. package/dist/feature-category-image-cards.js +142 -142
  41. package/dist/feature-icon-grid-bordered.cjs +142 -142
  42. package/dist/feature-icon-grid-bordered.js +142 -142
  43. package/dist/feature-icon-grid-muted.cjs +142 -142
  44. package/dist/feature-icon-grid-muted.js +142 -142
  45. package/dist/feature-numbered-cards.cjs +142 -142
  46. package/dist/feature-numbered-cards.js +142 -142
  47. package/dist/feature-three-column-values.cjs +142 -142
  48. package/dist/feature-three-column-values.js +142 -142
  49. package/dist/hero-ad-campaign-expert.cjs +142 -142
  50. package/dist/hero-ad-campaign-expert.js +142 -142
  51. package/dist/hero-adaptable-product-grid.cjs +142 -142
  52. package/dist/hero-adaptable-product-grid.js +142 -142
  53. package/dist/hero-agency-animated-images.cjs +142 -142
  54. package/dist/hero-agency-animated-images.js +142 -142
  55. package/dist/hero-announcement-badge.cjs +142 -142
  56. package/dist/hero-announcement-badge.js +142 -142
  57. package/dist/hero-badge-image-split.cjs +142 -142
  58. package/dist/hero-badge-image-split.js +142 -142
  59. package/dist/hero-business-carousel-dots.cjs +142 -142
  60. package/dist/hero-business-carousel-dots.js +142 -142
  61. package/dist/hero-business-operations-mosaic.cjs +142 -142
  62. package/dist/hero-business-operations-mosaic.js +142 -142
  63. package/dist/hero-conversation-intelligence.cjs +142 -142
  64. package/dist/hero-conversation-intelligence.js +142 -142
  65. package/dist/hero-creative-studio-stacked.cjs +142 -142
  66. package/dist/hero-creative-studio-stacked.js +142 -142
  67. package/dist/hero-crm-streamlined.cjs +142 -142
  68. package/dist/hero-crm-streamlined.js +142 -142
  69. package/dist/hero-customer-support-layered.cjs +142 -142
  70. package/dist/hero-customer-support-layered.js +142 -142
  71. package/dist/hero-design-showcase-logos.cjs +142 -142
  72. package/dist/hero-design-showcase-logos.js +142 -142
  73. package/dist/hero-design-system-3d.cjs +142 -142
  74. package/dist/hero-design-system-3d.js +142 -142
  75. package/dist/hero-developer-tools-code.cjs +142 -142
  76. package/dist/hero-developer-tools-code.js +142 -142
  77. package/dist/hero-digital-agency-fullscreen.cjs +142 -142
  78. package/dist/hero-digital-agency-fullscreen.js +142 -142
  79. package/dist/hero-ecommerce-product-showcase.cjs +174 -174
  80. package/dist/hero-ecommerce-product-showcase.js +174 -174
  81. package/dist/hero-event-registration.cjs +142 -142
  82. package/dist/hero-event-registration.js +142 -142
  83. package/dist/hero-fullscreen-background-image.cjs +142 -142
  84. package/dist/hero-fullscreen-background-image.js +142 -142
  85. package/dist/hero-gradient-avatars-rating.cjs +142 -142
  86. package/dist/hero-gradient-avatars-rating.js +142 -142
  87. package/dist/hero-gradient-client-focused.cjs +142 -142
  88. package/dist/hero-gradient-client-focused.js +142 -142
  89. package/dist/hero-hiring-animated-text.cjs +142 -142
  90. package/dist/hero-hiring-animated-text.js +142 -142
  91. package/dist/hero-image-left-content.cjs +142 -142
  92. package/dist/hero-image-left-content.js +142 -142
  93. package/dist/hero-innovation-image-grid.cjs +142 -142
  94. package/dist/hero-innovation-image-grid.js +142 -142
  95. package/dist/hero-mental-health-team.cjs +142 -142
  96. package/dist/hero-mental-health-team.js +142 -142
  97. package/dist/hero-minimal-centered-dark.cjs +174 -174
  98. package/dist/hero-minimal-centered-dark.js +174 -174
  99. package/dist/hero-presentation-platform-video.cjs +142 -142
  100. package/dist/hero-presentation-platform-video.js +142 -142
  101. package/dist/hero-product-showcase-floating.cjs +174 -174
  102. package/dist/hero-product-showcase-floating.js +174 -174
  103. package/dist/hero-shared-inbox-layered.cjs +142 -142
  104. package/dist/hero-shared-inbox-layered.js +142 -142
  105. package/dist/hero-software-growth-video-dialog.cjs +142 -142
  106. package/dist/hero-software-growth-video-dialog.js +142 -142
  107. package/dist/hero-spiral-pattern-cards.cjs +174 -174
  108. package/dist/hero-spiral-pattern-cards.js +174 -174
  109. package/dist/hero-split-geometric-shapes.cjs +142 -142
  110. package/dist/hero-split-geometric-shapes.js +142 -142
  111. package/dist/hero-startup-launch-cta.cjs +174 -174
  112. package/dist/hero-startup-launch-cta.js +174 -174
  113. package/dist/hero-stats-social-proof.cjs +174 -174
  114. package/dist/hero-stats-social-proof.js +174 -174
  115. package/dist/hero-task-timer-animated.cjs +142 -142
  116. package/dist/hero-task-timer-animated.js +142 -142
  117. package/dist/hero-testimonial-image-grid.cjs +142 -142
  118. package/dist/hero-testimonial-image-grid.js +142 -142
  119. package/dist/hero-therapy-testimonial-grid.cjs +142 -142
  120. package/dist/hero-therapy-testimonial-grid.js +142 -142
  121. package/dist/hero-ui-library-showcase.cjs +142 -142
  122. package/dist/hero-ui-library-showcase.js +142 -142
  123. package/dist/hero-video-background-dark.cjs +174 -174
  124. package/dist/hero-video-background-dark.js +174 -174
  125. package/dist/hero-video-dialog-gradient.cjs +142 -142
  126. package/dist/hero-video-dialog-gradient.js +142 -142
  127. package/dist/hero-video-overlay-stars.cjs +142 -142
  128. package/dist/hero-video-overlay-stars.js +142 -142
  129. package/dist/hero-welcome-asymmetric-images.cjs +142 -142
  130. package/dist/hero-welcome-asymmetric-images.js +142 -142
  131. package/dist/index.cjs +725 -1366
  132. package/dist/index.d.cts +0 -2
  133. package/dist/index.d.ts +0 -2
  134. package/dist/index.js +634 -1274
  135. package/dist/registry.cjs +2371 -2915
  136. package/dist/registry.js +1120 -1664
  137. package/dist/testimonials-large-quote.cjs +74 -43
  138. package/dist/testimonials-large-quote.d.cts +5 -1
  139. package/dist/testimonials-large-quote.d.ts +5 -1
  140. package/dist/testimonials-large-quote.js +74 -43
  141. package/dist/testimonials-logo-cards.cjs +8 -2
  142. package/dist/testimonials-logo-cards.js +8 -2
  143. package/dist/testimonials-masonry-grid.cjs +486 -69
  144. package/dist/testimonials-masonry-grid.d.cts +5 -1
  145. package/dist/testimonials-masonry-grid.d.ts +5 -1
  146. package/dist/testimonials-masonry-grid.js +483 -63
  147. package/dist/testimonials-mini-dividers.cjs +2 -3
  148. package/dist/testimonials-mini-dividers.js +2 -3
  149. package/dist/testimonials-minimal-numbered.cjs +5 -4
  150. package/dist/testimonials-minimal-numbered.js +5 -4
  151. package/dist/testimonials-parallax-number.cjs +5 -4
  152. package/dist/testimonials-parallax-number.js +5 -4
  153. package/dist/testimonials-scrolling-columns.cjs +7 -12
  154. package/dist/testimonials-scrolling-columns.js +7 -12
  155. package/dist/testimonials-stats-header.cjs +528 -87
  156. package/dist/testimonials-stats-header.d.cts +39 -3
  157. package/dist/testimonials-stats-header.d.ts +39 -3
  158. package/dist/testimonials-stats-header.js +523 -82
  159. package/package.json +4 -7
  160. package/dist/geo-map.cjs +0 -1103
  161. package/dist/geo-map.d.cts +0 -92
  162. package/dist/geo-map.d.ts +0 -92
  163. package/dist/geo-map.js +0 -1081
@@ -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
+ var baseStyles = [
458
+ // Layout
459
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
460
+ // Typography - using CSS variables with sensible defaults
461
+ "font-[var(--button-font-family,inherit)]",
462
+ "font-[var(--button-font-weight,500)]",
463
+ "tracking-[var(--button-letter-spacing,0)]",
464
+ "leading-[var(--button-line-height,1.25)]",
465
+ "[text-transform:var(--button-text-transform,none)]",
466
+ "text-sm",
467
+ // Border radius
468
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
469
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
470
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
471
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
472
+ "[box-shadow:var(--button-shadow,none)]",
473
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
474
+ // Disabled state
475
+ "disabled:pointer-events-none disabled:opacity-50",
476
+ // SVG handling
477
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
478
+ // Focus styles
479
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
480
+ // Invalid state
481
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
482
+ ].join(" ");
483
+ var buttonVariants = classVarianceAuthority.cva(baseStyles, {
484
+ variants: {
485
+ variant: {
486
+ // Default (Primary) variant - full customization
487
+ default: [
488
+ "bg-[var(--button-default-bg,hsl(var(--primary)))]",
489
+ "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
490
+ "border-[length:var(--button-default-border-width,0px)]",
491
+ "border-[color:var(--button-default-border,transparent)]",
492
+ "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
493
+ "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
494
+ "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
495
+ "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
496
+ "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
497
+ ].join(" "),
498
+ // Destructive variant - full customization
499
+ destructive: [
500
+ "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
501
+ "text-[var(--button-destructive-fg,white)]",
502
+ "border-[length:var(--button-destructive-border-width,0px)]",
503
+ "border-[color:var(--button-destructive-border,transparent)]",
504
+ "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
505
+ "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
506
+ "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
507
+ "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
508
+ "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
509
+ "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
510
+ "dark:bg-destructive/60"
511
+ ].join(" "),
512
+ // Outline variant - full customization with proper border handling
513
+ outline: [
514
+ "bg-[var(--button-outline-bg,hsl(var(--background)))]",
515
+ "text-[var(--button-outline-fg,inherit)]",
516
+ "border-[length:var(--button-outline-border-width,1px)]",
517
+ "border-[color:var(--button-outline-border,hsl(var(--border)))]",
518
+ "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
519
+ "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
520
+ "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
521
+ "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
522
+ "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
523
+ "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
524
+ ].join(" "),
525
+ // Secondary variant - full customization
526
+ secondary: [
527
+ "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
528
+ "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
529
+ "border-[length:var(--button-secondary-border-width,0px)]",
530
+ "border-[color:var(--button-secondary-border,transparent)]",
531
+ "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
532
+ "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
533
+ "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
534
+ "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
535
+ "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
536
+ ].join(" "),
537
+ // Ghost variant - full customization
538
+ ghost: [
539
+ "bg-[var(--button-ghost-bg,transparent)]",
540
+ "text-[var(--button-ghost-fg,inherit)]",
541
+ "border-[length:var(--button-ghost-border-width,0px)]",
542
+ "border-[color:var(--button-ghost-border,transparent)]",
543
+ "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
544
+ "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
545
+ "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
546
+ "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
547
+ "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
548
+ "dark:hover:bg-accent/50"
549
+ ].join(" "),
550
+ // Link variant - full customization
551
+ link: [
552
+ "bg-[var(--button-link-bg,transparent)]",
553
+ "text-[var(--button-link-fg,hsl(var(--primary)))]",
554
+ "border-[length:var(--button-link-border-width,0px)]",
555
+ "border-[color:var(--button-link-border,transparent)]",
556
+ "[box-shadow:var(--button-link-shadow,none)]",
557
+ "hover:bg-[var(--button-link-hover-bg,transparent)]",
558
+ "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
559
+ "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
560
+ "underline-offset-4 hover:underline"
561
+ ].join(" ")
562
+ },
563
+ size: {
564
+ default: [
565
+ "h-[var(--button-height-md,2.25rem)]",
566
+ "px-[var(--button-padding-x-md,1rem)]",
567
+ "py-[var(--button-padding-y-md,0.5rem)]",
568
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
569
+ ].join(" "),
570
+ sm: [
571
+ "h-[var(--button-height-sm,2rem)]",
572
+ "px-[var(--button-padding-x-sm,0.75rem)]",
573
+ "py-[var(--button-padding-y-sm,0.25rem)]",
574
+ "gap-1.5",
575
+ "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
576
+ ].join(" "),
577
+ md: [
578
+ "h-[var(--button-height-md,2.25rem)]",
579
+ "px-[var(--button-padding-x-md,1rem)]",
580
+ "py-[var(--button-padding-y-md,0.5rem)]",
581
+ "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
582
+ ].join(" "),
583
+ lg: [
584
+ "h-[var(--button-height-lg,2.5rem)]",
585
+ "px-[var(--button-padding-x-lg,1.5rem)]",
586
+ "py-[var(--button-padding-y-lg,0.5rem)]",
587
+ "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
588
+ ].join(" "),
589
+ icon: "size-[var(--button-height-md,2.25rem)]",
590
+ "icon-sm": "size-[var(--button-height-sm,2rem)]",
591
+ "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
592
+ }
593
+ },
594
+ defaultVariants: {
595
+ variant: "default",
596
+ size: "default"
597
+ }
598
+ });
599
+ function normalizePhoneNumber(input) {
600
+ const trimmed = input.trim();
601
+ if (trimmed.toLowerCase().startsWith("tel:")) {
602
+ return trimmed;
603
+ }
604
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
605
+ if (match) {
606
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
607
+ const extension = match[3];
608
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
609
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
610
+ return `tel:${withExtension}`;
611
+ }
612
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
613
+ return `tel:${cleaned}`;
614
+ }
615
+ function normalizeEmail(input) {
616
+ const trimmed = input.trim();
617
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
618
+ return trimmed;
619
+ }
620
+ return `mailto:${trimmed}`;
621
+ }
622
+ function isEmail(input) {
623
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
624
+ return emailRegex.test(input.trim());
625
+ }
626
+ function isPhoneNumber(input) {
627
+ const trimmed = input.trim();
628
+ if (trimmed.toLowerCase().startsWith("tel:")) {
629
+ return true;
630
+ }
631
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
632
+ return phoneRegex.test(trimmed);
633
+ }
634
+ function isInternalUrl(href) {
635
+ if (typeof window === "undefined") {
636
+ return href.startsWith("/") && !href.startsWith("//");
637
+ }
638
+ const trimmed = href.trim();
639
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
640
+ return true;
641
+ }
642
+ try {
643
+ const url = new URL(trimmed, window.location.href);
644
+ const currentOrigin = window.location.origin;
645
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
646
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
647
+ } catch {
648
+ return false;
649
+ }
650
+ }
651
+ function toRelativePath(href) {
652
+ if (typeof window === "undefined") {
653
+ return href;
654
+ }
655
+ const trimmed = href.trim();
656
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
657
+ return trimmed;
658
+ }
659
+ try {
660
+ const url = new URL(trimmed, window.location.href);
661
+ const currentOrigin = window.location.origin;
662
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
663
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
664
+ return url.pathname + url.search + url.hash;
665
+ }
666
+ } catch {
667
+ }
668
+ return trimmed;
669
+ }
670
+ function useNavigation({
671
+ href,
672
+ onClick
673
+ } = {}) {
674
+ const linkType = React3__namespace.useMemo(() => {
675
+ if (!href || href.trim() === "") {
676
+ return onClick ? "none" : "none";
677
+ }
678
+ const trimmed = href.trim();
679
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
680
+ return "mailto";
681
+ }
682
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
683
+ return "tel";
684
+ }
685
+ if (isInternalUrl(trimmed)) {
686
+ return "internal";
687
+ }
688
+ try {
689
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
690
+ return "external";
691
+ } catch {
692
+ return "internal";
693
+ }
694
+ }, [href, onClick]);
695
+ const normalizedHref = React3__namespace.useMemo(() => {
696
+ if (!href || href.trim() === "") {
697
+ return void 0;
698
+ }
699
+ const trimmed = href.trim();
700
+ switch (linkType) {
701
+ case "tel":
702
+ return normalizePhoneNumber(trimmed);
703
+ case "mailto":
704
+ return normalizeEmail(trimmed);
705
+ case "internal":
706
+ return toRelativePath(trimmed);
707
+ case "external":
708
+ return trimmed;
709
+ default:
710
+ return trimmed;
711
+ }
712
+ }, [href, linkType]);
713
+ const target = React3__namespace.useMemo(() => {
714
+ switch (linkType) {
715
+ case "external":
716
+ return "_blank";
717
+ case "internal":
718
+ return "_self";
719
+ case "mailto":
720
+ case "tel":
721
+ return void 0;
722
+ default:
723
+ return void 0;
724
+ }
725
+ }, [linkType]);
726
+ const rel = React3__namespace.useMemo(() => {
727
+ if (linkType === "external") {
728
+ return "noopener noreferrer";
729
+ }
730
+ return void 0;
731
+ }, [linkType]);
732
+ const isExternal = linkType === "external";
733
+ const isInternal = linkType === "internal";
734
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
735
+ const handleClick = React3__namespace.useCallback(
736
+ (event) => {
737
+ if (onClick) {
738
+ try {
739
+ onClick(event);
740
+ } catch (error) {
741
+ console.error("Error in user onClick handler:", error);
742
+ }
743
+ }
744
+ if (event.defaultPrevented) {
745
+ return;
746
+ }
747
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
748
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
749
+ if (typeof window !== "undefined") {
750
+ const handler = window.__opensiteNavigationHandler;
751
+ if (typeof handler === "function") {
752
+ try {
753
+ const handled = handler(normalizedHref, event.nativeEvent || event);
754
+ if (handled !== false) {
755
+ event.preventDefault();
756
+ }
757
+ } catch (error) {
758
+ console.error("Error in navigation handler:", error);
759
+ }
760
+ }
761
+ }
762
+ }
763
+ },
764
+ [onClick, shouldUseRouter, normalizedHref]
765
+ );
766
+ return {
767
+ linkType,
768
+ normalizedHref,
769
+ target,
770
+ rel,
771
+ isExternal,
772
+ isInternal,
773
+ shouldUseRouter,
774
+ handleClick
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 };