@opensite/ui 2.9.0 → 2.9.2
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.
- package/dist/carousel-feature-badge.cjs +4 -3
- package/dist/carousel-feature-badge.d.cts +1 -1
- package/dist/carousel-feature-badge.d.ts +1 -1
- package/dist/carousel-feature-badge.js +4 -3
- package/dist/carousel-scrolling-feature-showcase.cjs +47 -38
- package/dist/carousel-scrolling-feature-showcase.js +47 -38
- package/dist/registry.cjs +454 -265
- package/dist/registry.js +454 -265
- package/dist/testimonials-grid-add-review.cjs +578 -39
- package/dist/testimonials-grid-add-review.d.cts +26 -26
- package/dist/testimonials-grid-add-review.d.ts +26 -26
- package/dist/testimonials-grid-add-review.js +577 -38
- package/dist/testimonials-images-helpful.cjs +85 -74
- package/dist/testimonials-images-helpful.js +85 -74
- package/dist/testimonials-list-verified.cjs +1 -0
- package/dist/testimonials-list-verified.js +1 -0
- package/dist/testimonials-logo-cards.cjs +8 -5
- package/dist/testimonials-logo-cards.js +8 -5
- package/dist/testimonials-masonry-grid.cjs +87 -11
- package/dist/testimonials-masonry-grid.d.cts +14 -1
- package/dist/testimonials-masonry-grid.d.ts +14 -1
- package/dist/testimonials-masonry-grid.js +88 -12
- package/dist/testimonials-mini-dividers.cjs +438 -26
- package/dist/testimonials-mini-dividers.js +434 -22
- package/dist/testimonials-minimal-numbered.cjs +1 -1
- package/dist/testimonials-minimal-numbered.js +1 -1
- package/dist/testimonials-parallax-number.cjs +1 -1
- package/dist/testimonials-parallax-number.js +1 -1
- package/dist/testimonials-quote-carousel.cjs +39 -37
- package/dist/testimonials-quote-carousel.d.cts +5 -1
- package/dist/testimonials-quote-carousel.d.ts +5 -1
- package/dist/testimonials-quote-carousel.js +39 -37
- package/dist/testimonials-scrolling-columns.cjs +438 -8
- package/dist/testimonials-scrolling-columns.js +436 -6
- package/dist/testimonials-simple-grid.cjs +82 -6
- package/dist/testimonials-simple-grid.d.cts +14 -1
- package/dist/testimonials-simple-grid.d.ts +14 -1
- package/dist/testimonials-simple-grid.js +83 -7
- package/dist/testimonials-stats-header.cjs +88 -8
- package/dist/testimonials-stats-header.d.cts +14 -1
- package/dist/testimonials-stats-header.d.ts +14 -1
- package/dist/testimonials-stats-header.js +89 -9
- package/dist/testimonials-twitter-cards.cjs +150 -25
- package/dist/testimonials-twitter-cards.d.cts +14 -1
- package/dist/testimonials-twitter-cards.d.ts +14 -1
- package/dist/testimonials-twitter-cards.js +151 -26
- package/dist/testimonials-wall-compact.cjs +529 -50
- package/dist/testimonials-wall-compact.d.cts +14 -1
- package/dist/testimonials-wall-compact.d.ts +14 -1
- package/dist/testimonials-wall-compact.js +526 -44
- package/package.json +1 -1
|
@@ -1,19 +1,20 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import * as
|
|
3
|
-
import
|
|
2
|
+
import * as React4 from 'react';
|
|
3
|
+
import React4__default, { useCallback, useMemo } from 'react';
|
|
4
4
|
import { motion } from 'framer-motion';
|
|
5
5
|
import { clsx } from 'clsx';
|
|
6
6
|
import { twMerge } from 'tailwind-merge';
|
|
7
7
|
import { Icon } from '@page-speed/icon';
|
|
8
8
|
import { jsx, jsxs } from 'react/jsx-runtime';
|
|
9
9
|
import { Img } from '@page-speed/img';
|
|
10
|
+
import { cva } from 'class-variance-authority';
|
|
10
11
|
|
|
11
12
|
// components/blocks/testimonials/testimonials-scrolling-columns.tsx
|
|
12
13
|
function cn(...inputs) {
|
|
13
14
|
return twMerge(clsx(inputs));
|
|
14
15
|
}
|
|
15
16
|
var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
|
|
16
|
-
var DynamicIcon =
|
|
17
|
+
var DynamicIcon = React4.memo(function DynamicIcon2({
|
|
17
18
|
apiKey,
|
|
18
19
|
...props
|
|
19
20
|
}) {
|
|
@@ -90,7 +91,7 @@ var maxWidthStyles = {
|
|
|
90
91
|
"4xl": "max-w-[1536px]",
|
|
91
92
|
full: "max-w-full"
|
|
92
93
|
};
|
|
93
|
-
var Container =
|
|
94
|
+
var Container = React4__default.forwardRef(
|
|
94
95
|
({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
|
|
95
96
|
const Component = as;
|
|
96
97
|
return /* @__PURE__ */ jsx(
|
|
@@ -396,7 +397,7 @@ var spacingStyles = {
|
|
|
396
397
|
};
|
|
397
398
|
var predefinedSpacings = ["none", "sm", "md", "lg", "xl", "hero"];
|
|
398
399
|
var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
|
|
399
|
-
var Section =
|
|
400
|
+
var Section = React4__default.forwardRef(
|
|
400
401
|
({
|
|
401
402
|
id,
|
|
402
403
|
title,
|
|
@@ -457,6 +458,424 @@ var Section = React__default.forwardRef(
|
|
|
457
458
|
}
|
|
458
459
|
);
|
|
459
460
|
Section.displayName = "Section";
|
|
461
|
+
var baseStyles = [
|
|
462
|
+
// Layout
|
|
463
|
+
"inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
|
|
464
|
+
// Typography - using CSS variables with sensible defaults
|
|
465
|
+
"font-[var(--button-font-family,inherit)]",
|
|
466
|
+
"font-[var(--button-font-weight,500)]",
|
|
467
|
+
"tracking-[var(--button-letter-spacing,0)]",
|
|
468
|
+
"leading-[var(--button-line-height,1.25)]",
|
|
469
|
+
"[text-transform:var(--button-text-transform,none)]",
|
|
470
|
+
"text-sm",
|
|
471
|
+
// Border radius
|
|
472
|
+
"rounded-[var(--button-radius,var(--radius,0.375rem))]",
|
|
473
|
+
// Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
|
|
474
|
+
"[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
|
|
475
|
+
// Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
|
|
476
|
+
"[box-shadow:var(--button-shadow,none)]",
|
|
477
|
+
"hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
|
|
478
|
+
// Disabled state
|
|
479
|
+
"disabled:pointer-events-none disabled:opacity-50",
|
|
480
|
+
// SVG handling
|
|
481
|
+
"[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
|
|
482
|
+
// Focus styles
|
|
483
|
+
"outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
|
|
484
|
+
// Invalid state
|
|
485
|
+
"aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
|
|
486
|
+
].join(" ");
|
|
487
|
+
var buttonVariants = cva(baseStyles, {
|
|
488
|
+
variants: {
|
|
489
|
+
variant: {
|
|
490
|
+
// Default (Primary) variant - full customization
|
|
491
|
+
default: [
|
|
492
|
+
"bg-[var(--button-default-bg,hsl(var(--primary)))]",
|
|
493
|
+
"text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
|
|
494
|
+
"border-[length:var(--button-default-border-width,0px)]",
|
|
495
|
+
"border-[color:var(--button-default-border,transparent)]",
|
|
496
|
+
"[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
|
|
497
|
+
"hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
|
|
498
|
+
"hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
|
|
499
|
+
"hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
|
|
500
|
+
"hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
|
|
501
|
+
].join(" "),
|
|
502
|
+
// Destructive variant - full customization
|
|
503
|
+
destructive: [
|
|
504
|
+
"bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
|
|
505
|
+
"text-[var(--button-destructive-fg,white)]",
|
|
506
|
+
"border-[length:var(--button-destructive-border-width,0px)]",
|
|
507
|
+
"border-[color:var(--button-destructive-border,transparent)]",
|
|
508
|
+
"[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
|
|
509
|
+
"hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
|
|
510
|
+
"hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
|
|
511
|
+
"hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
|
|
512
|
+
"hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
|
|
513
|
+
"focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
|
|
514
|
+
"dark:bg-destructive/60"
|
|
515
|
+
].join(" "),
|
|
516
|
+
// Outline variant - full customization with proper border handling
|
|
517
|
+
outline: [
|
|
518
|
+
"bg-[var(--button-outline-bg,hsl(var(--background)))]",
|
|
519
|
+
"text-[var(--button-outline-fg,inherit)]",
|
|
520
|
+
"border-[length:var(--button-outline-border-width,1px)]",
|
|
521
|
+
"border-[color:var(--button-outline-border,hsl(var(--border)))]",
|
|
522
|
+
"[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
|
|
523
|
+
"hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
|
|
524
|
+
"hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
|
|
525
|
+
"hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
|
|
526
|
+
"hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
|
|
527
|
+
"dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
|
|
528
|
+
].join(" "),
|
|
529
|
+
// Secondary variant - full customization
|
|
530
|
+
secondary: [
|
|
531
|
+
"bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
|
|
532
|
+
"text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
|
|
533
|
+
"border-[length:var(--button-secondary-border-width,0px)]",
|
|
534
|
+
"border-[color:var(--button-secondary-border,transparent)]",
|
|
535
|
+
"[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
|
|
536
|
+
"hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
|
|
537
|
+
"hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
|
|
538
|
+
"hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
|
|
539
|
+
"hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
|
|
540
|
+
].join(" "),
|
|
541
|
+
// Ghost variant - full customization
|
|
542
|
+
ghost: [
|
|
543
|
+
"bg-[var(--button-ghost-bg,transparent)]",
|
|
544
|
+
"text-[var(--button-ghost-fg,inherit)]",
|
|
545
|
+
"border-[length:var(--button-ghost-border-width,0px)]",
|
|
546
|
+
"border-[color:var(--button-ghost-border,transparent)]",
|
|
547
|
+
"[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
|
|
548
|
+
"hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
|
|
549
|
+
"hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
|
|
550
|
+
"hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
|
|
551
|
+
"hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
|
|
552
|
+
"dark:hover:bg-accent/50"
|
|
553
|
+
].join(" "),
|
|
554
|
+
// Link variant - full customization
|
|
555
|
+
link: [
|
|
556
|
+
"bg-[var(--button-link-bg,transparent)]",
|
|
557
|
+
"text-[var(--button-link-fg,hsl(var(--primary)))]",
|
|
558
|
+
"border-[length:var(--button-link-border-width,0px)]",
|
|
559
|
+
"border-[color:var(--button-link-border,transparent)]",
|
|
560
|
+
"[box-shadow:var(--button-link-shadow,none)]",
|
|
561
|
+
"hover:bg-[var(--button-link-hover-bg,transparent)]",
|
|
562
|
+
"hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
|
|
563
|
+
"hover:[box-shadow:var(--button-link-shadow-hover,none)]",
|
|
564
|
+
"underline-offset-4 hover:underline"
|
|
565
|
+
].join(" ")
|
|
566
|
+
},
|
|
567
|
+
size: {
|
|
568
|
+
default: [
|
|
569
|
+
"h-[var(--button-height-md,2.25rem)]",
|
|
570
|
+
"px-[var(--button-padding-x-md,1rem)]",
|
|
571
|
+
"py-[var(--button-padding-y-md,0.5rem)]",
|
|
572
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
|
|
573
|
+
].join(" "),
|
|
574
|
+
sm: [
|
|
575
|
+
"h-[var(--button-height-sm,2rem)]",
|
|
576
|
+
"px-[var(--button-padding-x-sm,0.75rem)]",
|
|
577
|
+
"py-[var(--button-padding-y-sm,0.25rem)]",
|
|
578
|
+
"gap-1.5",
|
|
579
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
|
|
580
|
+
].join(" "),
|
|
581
|
+
md: [
|
|
582
|
+
"h-[var(--button-height-md,2.25rem)]",
|
|
583
|
+
"px-[var(--button-padding-x-md,1rem)]",
|
|
584
|
+
"py-[var(--button-padding-y-md,0.5rem)]",
|
|
585
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
|
|
586
|
+
].join(" "),
|
|
587
|
+
lg: [
|
|
588
|
+
"h-[var(--button-height-lg,2.5rem)]",
|
|
589
|
+
"px-[var(--button-padding-x-lg,1.5rem)]",
|
|
590
|
+
"py-[var(--button-padding-y-lg,0.5rem)]",
|
|
591
|
+
"has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
|
|
592
|
+
].join(" "),
|
|
593
|
+
icon: "size-[var(--button-height-md,2.25rem)]",
|
|
594
|
+
"icon-sm": "size-[var(--button-height-sm,2rem)]",
|
|
595
|
+
"icon-lg": "size-[var(--button-height-lg,2.5rem)]"
|
|
596
|
+
}
|
|
597
|
+
},
|
|
598
|
+
defaultVariants: {
|
|
599
|
+
variant: "default",
|
|
600
|
+
size: "default"
|
|
601
|
+
}
|
|
602
|
+
});
|
|
603
|
+
function normalizePhoneNumber(input) {
|
|
604
|
+
const trimmed = input.trim();
|
|
605
|
+
if (trimmed.toLowerCase().startsWith("tel:")) {
|
|
606
|
+
return trimmed;
|
|
607
|
+
}
|
|
608
|
+
const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
|
|
609
|
+
if (match) {
|
|
610
|
+
const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
|
|
611
|
+
const extension = match[3];
|
|
612
|
+
const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
|
|
613
|
+
const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
|
|
614
|
+
return `tel:${withExtension}`;
|
|
615
|
+
}
|
|
616
|
+
const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
|
|
617
|
+
return `tel:${cleaned}`;
|
|
618
|
+
}
|
|
619
|
+
function normalizeEmail(input) {
|
|
620
|
+
const trimmed = input.trim();
|
|
621
|
+
if (trimmed.toLowerCase().startsWith("mailto:")) {
|
|
622
|
+
return trimmed;
|
|
623
|
+
}
|
|
624
|
+
return `mailto:${trimmed}`;
|
|
625
|
+
}
|
|
626
|
+
function isEmail(input) {
|
|
627
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
628
|
+
return emailRegex.test(input.trim());
|
|
629
|
+
}
|
|
630
|
+
function isPhoneNumber(input) {
|
|
631
|
+
const trimmed = input.trim();
|
|
632
|
+
if (trimmed.toLowerCase().startsWith("tel:")) {
|
|
633
|
+
return true;
|
|
634
|
+
}
|
|
635
|
+
const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
|
|
636
|
+
return phoneRegex.test(trimmed);
|
|
637
|
+
}
|
|
638
|
+
function isInternalUrl(href) {
|
|
639
|
+
if (typeof window === "undefined") {
|
|
640
|
+
return href.startsWith("/") && !href.startsWith("//");
|
|
641
|
+
}
|
|
642
|
+
const trimmed = href.trim();
|
|
643
|
+
if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
|
|
644
|
+
return true;
|
|
645
|
+
}
|
|
646
|
+
try {
|
|
647
|
+
const url = new URL(trimmed, window.location.href);
|
|
648
|
+
const currentOrigin = window.location.origin;
|
|
649
|
+
const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
|
|
650
|
+
return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
|
|
651
|
+
} catch {
|
|
652
|
+
return false;
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
function toRelativePath(href) {
|
|
656
|
+
if (typeof window === "undefined") {
|
|
657
|
+
return href;
|
|
658
|
+
}
|
|
659
|
+
const trimmed = href.trim();
|
|
660
|
+
if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
|
|
661
|
+
return trimmed;
|
|
662
|
+
}
|
|
663
|
+
try {
|
|
664
|
+
const url = new URL(trimmed, window.location.href);
|
|
665
|
+
const currentOrigin = window.location.origin;
|
|
666
|
+
const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
|
|
667
|
+
if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
|
|
668
|
+
return url.pathname + url.search + url.hash;
|
|
669
|
+
}
|
|
670
|
+
} catch {
|
|
671
|
+
}
|
|
672
|
+
return trimmed;
|
|
673
|
+
}
|
|
674
|
+
function useNavigation({
|
|
675
|
+
href,
|
|
676
|
+
onClick
|
|
677
|
+
} = {}) {
|
|
678
|
+
const linkType = React4.useMemo(() => {
|
|
679
|
+
if (!href || href.trim() === "") {
|
|
680
|
+
return onClick ? "none" : "none";
|
|
681
|
+
}
|
|
682
|
+
const trimmed = href.trim();
|
|
683
|
+
if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
|
|
684
|
+
return "mailto";
|
|
685
|
+
}
|
|
686
|
+
if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
|
|
687
|
+
return "tel";
|
|
688
|
+
}
|
|
689
|
+
if (isInternalUrl(trimmed)) {
|
|
690
|
+
return "internal";
|
|
691
|
+
}
|
|
692
|
+
try {
|
|
693
|
+
new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
|
|
694
|
+
return "external";
|
|
695
|
+
} catch {
|
|
696
|
+
return "internal";
|
|
697
|
+
}
|
|
698
|
+
}, [href, onClick]);
|
|
699
|
+
const normalizedHref = React4.useMemo(() => {
|
|
700
|
+
if (!href || href.trim() === "") {
|
|
701
|
+
return void 0;
|
|
702
|
+
}
|
|
703
|
+
const trimmed = href.trim();
|
|
704
|
+
switch (linkType) {
|
|
705
|
+
case "tel":
|
|
706
|
+
return normalizePhoneNumber(trimmed);
|
|
707
|
+
case "mailto":
|
|
708
|
+
return normalizeEmail(trimmed);
|
|
709
|
+
case "internal":
|
|
710
|
+
return toRelativePath(trimmed);
|
|
711
|
+
case "external":
|
|
712
|
+
return trimmed;
|
|
713
|
+
default:
|
|
714
|
+
return trimmed;
|
|
715
|
+
}
|
|
716
|
+
}, [href, linkType]);
|
|
717
|
+
const target = React4.useMemo(() => {
|
|
718
|
+
switch (linkType) {
|
|
719
|
+
case "external":
|
|
720
|
+
return "_blank";
|
|
721
|
+
case "internal":
|
|
722
|
+
return "_self";
|
|
723
|
+
case "mailto":
|
|
724
|
+
case "tel":
|
|
725
|
+
return void 0;
|
|
726
|
+
default:
|
|
727
|
+
return void 0;
|
|
728
|
+
}
|
|
729
|
+
}, [linkType]);
|
|
730
|
+
const rel = React4.useMemo(() => {
|
|
731
|
+
if (linkType === "external") {
|
|
732
|
+
return "noopener noreferrer";
|
|
733
|
+
}
|
|
734
|
+
return void 0;
|
|
735
|
+
}, [linkType]);
|
|
736
|
+
const isExternal = linkType === "external";
|
|
737
|
+
const isInternal = linkType === "internal";
|
|
738
|
+
const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
|
|
739
|
+
const handleClick = React4.useCallback(
|
|
740
|
+
(event) => {
|
|
741
|
+
if (onClick) {
|
|
742
|
+
try {
|
|
743
|
+
onClick(event);
|
|
744
|
+
} catch (error) {
|
|
745
|
+
console.error("Error in user onClick handler:", error);
|
|
746
|
+
}
|
|
747
|
+
}
|
|
748
|
+
if (event.defaultPrevented) {
|
|
749
|
+
return;
|
|
750
|
+
}
|
|
751
|
+
if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
|
|
752
|
+
!event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
|
|
753
|
+
if (typeof window !== "undefined") {
|
|
754
|
+
const handler = window.__opensiteNavigationHandler;
|
|
755
|
+
if (typeof handler === "function") {
|
|
756
|
+
try {
|
|
757
|
+
const handled = handler(normalizedHref, event.nativeEvent || event);
|
|
758
|
+
if (handled !== false) {
|
|
759
|
+
event.preventDefault();
|
|
760
|
+
}
|
|
761
|
+
} catch (error) {
|
|
762
|
+
console.error("Error in navigation handler:", error);
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
}
|
|
767
|
+
},
|
|
768
|
+
[onClick, shouldUseRouter, normalizedHref]
|
|
769
|
+
);
|
|
770
|
+
return {
|
|
771
|
+
linkType,
|
|
772
|
+
normalizedHref,
|
|
773
|
+
target,
|
|
774
|
+
rel,
|
|
775
|
+
isExternal,
|
|
776
|
+
isInternal,
|
|
777
|
+
shouldUseRouter,
|
|
778
|
+
handleClick
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
var Pressable = React4.forwardRef(
|
|
782
|
+
({
|
|
783
|
+
children,
|
|
784
|
+
className,
|
|
785
|
+
href,
|
|
786
|
+
onClick,
|
|
787
|
+
variant,
|
|
788
|
+
size,
|
|
789
|
+
asButton = false,
|
|
790
|
+
fallbackComponentType = "span",
|
|
791
|
+
componentType,
|
|
792
|
+
"aria-label": ariaLabel,
|
|
793
|
+
"aria-describedby": ariaDescribedby,
|
|
794
|
+
id,
|
|
795
|
+
...props
|
|
796
|
+
}, ref) => {
|
|
797
|
+
const navigation = useNavigation({ href, onClick });
|
|
798
|
+
const {
|
|
799
|
+
normalizedHref,
|
|
800
|
+
target,
|
|
801
|
+
rel,
|
|
802
|
+
linkType,
|
|
803
|
+
isInternal,
|
|
804
|
+
handleClick
|
|
805
|
+
} = navigation;
|
|
806
|
+
const shouldRenderLink = normalizedHref && linkType !== "none";
|
|
807
|
+
const shouldRenderButton = !shouldRenderLink && onClick;
|
|
808
|
+
const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
|
|
809
|
+
const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
|
|
810
|
+
const shouldApplyButtonStyles = asButton || variant || size;
|
|
811
|
+
const combinedClassName = cn(
|
|
812
|
+
shouldApplyButtonStyles && buttonVariants({ variant, size }),
|
|
813
|
+
className
|
|
814
|
+
);
|
|
815
|
+
const dataProps = Object.fromEntries(
|
|
816
|
+
Object.entries(props).filter(([key]) => key.startsWith("data-"))
|
|
817
|
+
);
|
|
818
|
+
const buttonDataAttributes = shouldApplyButtonStyles ? {
|
|
819
|
+
"data-slot": "button",
|
|
820
|
+
"data-variant": variant ?? "default",
|
|
821
|
+
"data-size": size ?? "default"
|
|
822
|
+
} : {};
|
|
823
|
+
const commonProps = {
|
|
824
|
+
className: combinedClassName,
|
|
825
|
+
onClick: handleClick,
|
|
826
|
+
"aria-label": ariaLabel,
|
|
827
|
+
"aria-describedby": ariaDescribedby,
|
|
828
|
+
id,
|
|
829
|
+
...dataProps,
|
|
830
|
+
...buttonDataAttributes
|
|
831
|
+
};
|
|
832
|
+
if (finalComponentType === "a" && shouldRenderLink) {
|
|
833
|
+
return /* @__PURE__ */ jsx(
|
|
834
|
+
"a",
|
|
835
|
+
{
|
|
836
|
+
ref,
|
|
837
|
+
href: normalizedHref,
|
|
838
|
+
target,
|
|
839
|
+
rel,
|
|
840
|
+
...commonProps,
|
|
841
|
+
...props,
|
|
842
|
+
children
|
|
843
|
+
}
|
|
844
|
+
);
|
|
845
|
+
}
|
|
846
|
+
if (finalComponentType === "button") {
|
|
847
|
+
return /* @__PURE__ */ jsx(
|
|
848
|
+
"button",
|
|
849
|
+
{
|
|
850
|
+
ref,
|
|
851
|
+
type: props.type || "button",
|
|
852
|
+
...commonProps,
|
|
853
|
+
...props,
|
|
854
|
+
children
|
|
855
|
+
}
|
|
856
|
+
);
|
|
857
|
+
}
|
|
858
|
+
if (finalComponentType === "div") {
|
|
859
|
+
return /* @__PURE__ */ jsx(
|
|
860
|
+
"div",
|
|
861
|
+
{
|
|
862
|
+
ref,
|
|
863
|
+
...commonProps,
|
|
864
|
+
children
|
|
865
|
+
}
|
|
866
|
+
);
|
|
867
|
+
}
|
|
868
|
+
return /* @__PURE__ */ jsx(
|
|
869
|
+
"span",
|
|
870
|
+
{
|
|
871
|
+
ref,
|
|
872
|
+
...commonProps,
|
|
873
|
+
children
|
|
874
|
+
}
|
|
875
|
+
);
|
|
876
|
+
}
|
|
877
|
+
);
|
|
878
|
+
Pressable.displayName = "Pressable";
|
|
460
879
|
var containerVariants = {
|
|
461
880
|
hidden: {},
|
|
462
881
|
visible: {
|
|
@@ -571,7 +990,18 @@ function TestimonialsScrollingColumns({
|
|
|
571
990
|
) : testimonial.quote),
|
|
572
991
|
/* @__PURE__ */ jsx("figcaption", { className: cn("mt-4", authorClassName), children: /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
|
|
573
992
|
testimonial.author && (typeof testimonial.author === "string" ? /* @__PURE__ */ jsx("div", { className: "uppercase text-base font-semibold", children: testimonial.author }) : null),
|
|
574
|
-
testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsx("div", { className: "text-sm font-thin", children: testimonial.role }) : null)
|
|
993
|
+
testimonial.role && (typeof testimonial.role === "string" ? /* @__PURE__ */ jsx("div", { className: "text-sm font-thin opacity-75", children: testimonial.role }) : null),
|
|
994
|
+
testimonial.linkConfig?.href ? /* @__PURE__ */ jsx(
|
|
995
|
+
Pressable,
|
|
996
|
+
{
|
|
997
|
+
href: testimonial.linkConfig.href,
|
|
998
|
+
className: cn(
|
|
999
|
+
"text-base font-bold",
|
|
1000
|
+
testimonial.linkConfig.className
|
|
1001
|
+
),
|
|
1002
|
+
children: testimonial.linkConfig.label || "Full Review"
|
|
1003
|
+
}
|
|
1004
|
+
) : null
|
|
575
1005
|
] }) })
|
|
576
1006
|
] })
|
|
577
1007
|
]
|
|
@@ -882,6 +882,70 @@ var Pressable = React3__namespace.forwardRef(
|
|
|
882
882
|
}
|
|
883
883
|
);
|
|
884
884
|
Pressable.displayName = "Pressable";
|
|
885
|
+
var MOBILE_CLASSES = {
|
|
886
|
+
"fit-left": "items-start md:items-center",
|
|
887
|
+
"fit-center": "items-center",
|
|
888
|
+
"fit-right": "items-end md:items-center",
|
|
889
|
+
"full-left": "items-stretch md:items-center",
|
|
890
|
+
"full-center": "items-stretch md:items-center",
|
|
891
|
+
"full-right": "items-stretch md:items-center"
|
|
892
|
+
};
|
|
893
|
+
function BlockActions({
|
|
894
|
+
mobileConfig,
|
|
895
|
+
actionsClassName,
|
|
896
|
+
verticalSpacing = "mt-4 md:mt-8",
|
|
897
|
+
actions,
|
|
898
|
+
actionsSlot
|
|
899
|
+
}) {
|
|
900
|
+
const width = mobileConfig?.width ?? "full";
|
|
901
|
+
const position = mobileConfig?.position ?? "center";
|
|
902
|
+
const mobileLayoutClass = MOBILE_CLASSES[`${width}-${position}`];
|
|
903
|
+
if (actionsSlot) {
|
|
904
|
+
return /* @__PURE__ */ jsxRuntime.jsx("div", { children: actionsSlot });
|
|
905
|
+
} else if (actions && actions?.length > 0) {
|
|
906
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
907
|
+
"div",
|
|
908
|
+
{
|
|
909
|
+
className: cn(
|
|
910
|
+
"flex flex-col md:flex-row flex-wrap gap-4",
|
|
911
|
+
mobileLayoutClass,
|
|
912
|
+
actionsClassName,
|
|
913
|
+
verticalSpacing
|
|
914
|
+
),
|
|
915
|
+
children: actions.map((action, index) => /* @__PURE__ */ jsxRuntime.jsx(ActionComponent, { action }, index))
|
|
916
|
+
}
|
|
917
|
+
);
|
|
918
|
+
} else {
|
|
919
|
+
return null;
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
function ActionComponent({ action }) {
|
|
923
|
+
const {
|
|
924
|
+
label,
|
|
925
|
+
icon,
|
|
926
|
+
iconAfter,
|
|
927
|
+
children,
|
|
928
|
+
href,
|
|
929
|
+
onClick,
|
|
930
|
+
className: actionClassName,
|
|
931
|
+
...pressableProps
|
|
932
|
+
} = action;
|
|
933
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
934
|
+
Pressable,
|
|
935
|
+
{
|
|
936
|
+
href,
|
|
937
|
+
onClick,
|
|
938
|
+
asButton: action.asButton ?? true,
|
|
939
|
+
className: actionClassName,
|
|
940
|
+
...pressableProps,
|
|
941
|
+
children: children ?? /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
|
|
942
|
+
icon,
|
|
943
|
+
label,
|
|
944
|
+
iconAfter
|
|
945
|
+
] })
|
|
946
|
+
}
|
|
947
|
+
);
|
|
948
|
+
}
|
|
885
949
|
function TestimonialsSimpleGrid({
|
|
886
950
|
testimonials,
|
|
887
951
|
testimonialsSlot,
|
|
@@ -901,7 +965,10 @@ function TestimonialsSimpleGrid({
|
|
|
901
965
|
containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
|
|
902
966
|
spacing = "xl",
|
|
903
967
|
pattern,
|
|
904
|
-
patternOpacity
|
|
968
|
+
patternOpacity,
|
|
969
|
+
actions,
|
|
970
|
+
actionsSlot,
|
|
971
|
+
actionsClassName
|
|
905
972
|
}) {
|
|
906
973
|
const getAuthorName = React3.useCallback((testimonial) => {
|
|
907
974
|
if (typeof testimonial.author === "string") return testimonial.author;
|
|
@@ -923,7 +990,7 @@ function TestimonialsSimpleGrid({
|
|
|
923
990
|
"div",
|
|
924
991
|
{
|
|
925
992
|
className: cn(
|
|
926
|
-
"grid gap-
|
|
993
|
+
"grid gap-8 md:gap-6 lg:gap-8 grid-cols-1 md:grid-cols-2 lg:grid-cols-3",
|
|
927
994
|
gridClassName
|
|
928
995
|
),
|
|
929
996
|
children: testimonials.map((testimonial, index) => {
|
|
@@ -935,8 +1002,8 @@ function TestimonialsSimpleGrid({
|
|
|
935
1002
|
className: cn(
|
|
936
1003
|
"bg-card text-card-foreground",
|
|
937
1004
|
"flex flex-col gap-6",
|
|
938
|
-
testimonial.linkConfig?.href ? "cursor-pointer hover:
|
|
939
|
-
"rounded-2xl py-0 shadow-xl group",
|
|
1005
|
+
testimonial.linkConfig?.href ? "cursor-pointer hover:opacity-75 transition-all duration-500" : "opacity-100",
|
|
1006
|
+
"rounded-2xl py-0 shadow-xl group overflow-hidden",
|
|
940
1007
|
"ring-4 ring-ring",
|
|
941
1008
|
cardClassName
|
|
942
1009
|
),
|
|
@@ -987,7 +1054,7 @@ function TestimonialsSimpleGrid({
|
|
|
987
1054
|
] })
|
|
988
1055
|
}
|
|
989
1056
|
),
|
|
990
|
-
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-6 md:
|
|
1057
|
+
/* @__PURE__ */ jsxRuntime.jsx("div", { className: "pt-6 md:pt-8 px-6 md:px-8", children: testimonial.quote && (typeof testimonial.quote === "string" ? /* @__PURE__ */ jsxRuntime.jsx("p", { className: "text-base leading-relaxed", children: testimonial.quote }) : testimonial.quote) })
|
|
991
1058
|
]
|
|
992
1059
|
}
|
|
993
1060
|
)
|
|
@@ -1046,7 +1113,16 @@ function TestimonialsSimpleGrid({
|
|
|
1046
1113
|
]
|
|
1047
1114
|
}
|
|
1048
1115
|
),
|
|
1049
|
-
renderedTestimonials
|
|
1116
|
+
renderedTestimonials,
|
|
1117
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
1118
|
+
BlockActions,
|
|
1119
|
+
{
|
|
1120
|
+
actions,
|
|
1121
|
+
actionsSlot,
|
|
1122
|
+
actionsClassName: cn("mt-8 md:mt-12 justify-center", actionsClassName),
|
|
1123
|
+
mobileConfig: { width: "full", position: "center" }
|
|
1124
|
+
}
|
|
1125
|
+
)
|
|
1050
1126
|
]
|
|
1051
1127
|
}
|
|
1052
1128
|
);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { S as SectionBackground, s as SectionSpacing, t as PatternName } from './community-initiatives-B8KCpwXH.cjs';
|
|
3
|
+
import { ActionConfig } from '@page-speed/maps/components/geo-map';
|
|
3
4
|
import { T as TestimonialItem } from './blocks-BtDAbw8d.cjs';
|
|
4
5
|
import 'react/jsx-runtime';
|
|
5
6
|
import 'class-variance-authority';
|
|
@@ -84,6 +85,18 @@ interface TestimonialsSimpleGridProps {
|
|
|
84
85
|
* Additional CSS classes for the card content
|
|
85
86
|
*/
|
|
86
87
|
cardContentClassName?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Array of action configurations for CTA buttons
|
|
90
|
+
*/
|
|
91
|
+
actions?: ActionConfig[];
|
|
92
|
+
/**
|
|
93
|
+
* Custom slot for rendering actions (overrides actions array)
|
|
94
|
+
*/
|
|
95
|
+
actionsSlot?: React.ReactNode;
|
|
96
|
+
/**
|
|
97
|
+
* Additional CSS classes for the actions container
|
|
98
|
+
*/
|
|
99
|
+
actionsClassName?: string;
|
|
87
100
|
}
|
|
88
101
|
/**
|
|
89
102
|
* TestimonialsSimpleGrid - A clean, straightforward grid of testimonial cards with
|
|
@@ -112,6 +125,6 @@ interface TestimonialsSimpleGridProps {
|
|
|
112
125
|
* />
|
|
113
126
|
* ```
|
|
114
127
|
*/
|
|
115
|
-
declare function TestimonialsSimpleGrid({ testimonials, testimonialsSlot, heading, description, columns, className, headerClassName, headingClassName, descriptionClassName, cardContentClassName, gridClassName, cardClassName, quoteClassName, authorClassName, background, containerClassName, spacing, pattern, patternOpacity, }: TestimonialsSimpleGridProps): React.JSX.Element;
|
|
128
|
+
declare function TestimonialsSimpleGrid({ testimonials, testimonialsSlot, heading, description, columns, className, headerClassName, headingClassName, descriptionClassName, cardContentClassName, gridClassName, cardClassName, quoteClassName, authorClassName, background, containerClassName, spacing, pattern, patternOpacity, actions, actionsSlot, actionsClassName, }: TestimonialsSimpleGridProps): React.JSX.Element;
|
|
116
129
|
|
|
117
130
|
export { TestimonialsSimpleGrid, type TestimonialsSimpleGridProps };
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as React from 'react';
|
|
2
2
|
import { S as SectionBackground, s as SectionSpacing, t as PatternName } from './community-initiatives-rTRuDt0r.js';
|
|
3
|
+
import { ActionConfig } from '@page-speed/maps/components/geo-map';
|
|
3
4
|
import { T as TestimonialItem } from './blocks-BlWXj9GI.js';
|
|
4
5
|
import 'react/jsx-runtime';
|
|
5
6
|
import 'class-variance-authority';
|
|
@@ -84,6 +85,18 @@ interface TestimonialsSimpleGridProps {
|
|
|
84
85
|
* Additional CSS classes for the card content
|
|
85
86
|
*/
|
|
86
87
|
cardContentClassName?: string;
|
|
88
|
+
/**
|
|
89
|
+
* Array of action configurations for CTA buttons
|
|
90
|
+
*/
|
|
91
|
+
actions?: ActionConfig[];
|
|
92
|
+
/**
|
|
93
|
+
* Custom slot for rendering actions (overrides actions array)
|
|
94
|
+
*/
|
|
95
|
+
actionsSlot?: React.ReactNode;
|
|
96
|
+
/**
|
|
97
|
+
* Additional CSS classes for the actions container
|
|
98
|
+
*/
|
|
99
|
+
actionsClassName?: string;
|
|
87
100
|
}
|
|
88
101
|
/**
|
|
89
102
|
* TestimonialsSimpleGrid - A clean, straightforward grid of testimonial cards with
|
|
@@ -112,6 +125,6 @@ interface TestimonialsSimpleGridProps {
|
|
|
112
125
|
* />
|
|
113
126
|
* ```
|
|
114
127
|
*/
|
|
115
|
-
declare function TestimonialsSimpleGrid({ testimonials, testimonialsSlot, heading, description, columns, className, headerClassName, headingClassName, descriptionClassName, cardContentClassName, gridClassName, cardClassName, quoteClassName, authorClassName, background, containerClassName, spacing, pattern, patternOpacity, }: TestimonialsSimpleGridProps): React.JSX.Element;
|
|
128
|
+
declare function TestimonialsSimpleGrid({ testimonials, testimonialsSlot, heading, description, columns, className, headerClassName, headingClassName, descriptionClassName, cardContentClassName, gridClassName, cardClassName, quoteClassName, authorClassName, background, containerClassName, spacing, pattern, patternOpacity, actions, actionsSlot, actionsClassName, }: TestimonialsSimpleGridProps): React.JSX.Element;
|
|
116
129
|
|
|
117
130
|
export { TestimonialsSimpleGrid, type TestimonialsSimpleGridProps };
|