@opensite/ui 2.0.6 → 2.0.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 (77) hide show
  1. package/dist/hero-adaptable-product-grid.cjs +1 -1
  2. package/dist/hero-adaptable-product-grid.js +1 -1
  3. package/dist/hero-agency-animated-images.cjs +795 -631
  4. package/dist/hero-agency-animated-images.d.cts +13 -9
  5. package/dist/hero-agency-animated-images.d.ts +13 -9
  6. package/dist/hero-agency-animated-images.js +794 -630
  7. package/dist/hero-business-carousel-dots.cjs +822 -911
  8. package/dist/hero-business-carousel-dots.d.cts +5 -1
  9. package/dist/hero-business-carousel-dots.d.ts +5 -1
  10. package/dist/hero-business-carousel-dots.js +824 -910
  11. package/dist/hero-coming-soon-countdown.cjs +267 -110
  12. package/dist/hero-coming-soon-countdown.d.cts +8 -11
  13. package/dist/hero-coming-soon-countdown.d.ts +8 -11
  14. package/dist/hero-coming-soon-countdown.js +268 -111
  15. package/dist/hero-conversation-intelligence.cjs +673 -639
  16. package/dist/hero-conversation-intelligence.js +663 -629
  17. package/dist/hero-creative-studio-stacked.cjs +899 -861
  18. package/dist/hero-creative-studio-stacked.d.cts +16 -15
  19. package/dist/hero-creative-studio-stacked.d.ts +16 -15
  20. package/dist/hero-creative-studio-stacked.js +897 -859
  21. package/dist/hero-customer-support-layered.cjs +89 -76
  22. package/dist/hero-customer-support-layered.js +89 -76
  23. package/dist/hero-developer-tools-code.cjs +721 -669
  24. package/dist/hero-developer-tools-code.d.cts +5 -1
  25. package/dist/hero-developer-tools-code.d.ts +5 -1
  26. package/dist/hero-developer-tools-code.js +719 -667
  27. package/dist/hero-digital-agency-fullscreen.cjs +722 -680
  28. package/dist/hero-digital-agency-fullscreen.d.cts +4 -20
  29. package/dist/hero-digital-agency-fullscreen.d.ts +4 -20
  30. package/dist/hero-digital-agency-fullscreen.js +722 -680
  31. package/dist/hero-ecommerce-product-showcase.cjs +892 -846
  32. package/dist/hero-ecommerce-product-showcase.js +889 -843
  33. package/dist/hero-enterprise-security.cjs +168 -132
  34. package/dist/hero-enterprise-security.d.cts +12 -19
  35. package/dist/hero-enterprise-security.d.ts +12 -19
  36. package/dist/hero-enterprise-security.js +168 -132
  37. package/dist/hero-event-registration.cjs +39 -39
  38. package/dist/hero-event-registration.js +39 -39
  39. package/dist/hero-fullscreen-background-image.cjs +3 -2
  40. package/dist/hero-fullscreen-background-image.js +3 -2
  41. package/dist/hero-fullscreen-logo-cta.cjs +4 -2
  42. package/dist/hero-fullscreen-logo-cta.js +4 -2
  43. package/dist/hero-innovation-image-grid.cjs +2 -2
  44. package/dist/hero-innovation-image-grid.js +2 -2
  45. package/dist/hero-mental-health-team.cjs +17 -17
  46. package/dist/hero-mental-health-team.d.cts +5 -5
  47. package/dist/hero-mental-health-team.d.ts +5 -5
  48. package/dist/hero-mental-health-team.js +17 -17
  49. package/dist/hero-mobile-app-download.cjs +2 -2
  50. package/dist/hero-mobile-app-download.js +2 -2
  51. package/dist/hero-newsletter-minimal.cjs +97 -57
  52. package/dist/hero-newsletter-minimal.d.cts +5 -1
  53. package/dist/hero-newsletter-minimal.d.ts +5 -1
  54. package/dist/hero-newsletter-minimal.js +97 -57
  55. package/dist/hero-shared-inbox-layered.cjs +522 -42
  56. package/dist/hero-shared-inbox-layered.d.cts +20 -4
  57. package/dist/hero-shared-inbox-layered.d.ts +20 -4
  58. package/dist/hero-shared-inbox-layered.js +505 -40
  59. package/dist/hero-startup-launch-cta.cjs +859 -816
  60. package/dist/hero-startup-launch-cta.d.cts +3 -2
  61. package/dist/hero-startup-launch-cta.d.ts +3 -2
  62. package/dist/hero-startup-launch-cta.js +858 -815
  63. package/dist/hero-therapy-testimonial-grid.cjs +1 -1
  64. package/dist/hero-therapy-testimonial-grid.js +1 -1
  65. package/dist/hero-video-dialog-gradient-BnCFFec0.d.ts +99 -0
  66. package/dist/hero-video-dialog-gradient-Dapebkzu.d.cts +99 -0
  67. package/dist/hero-video-dialog-gradient.cjs +24 -23
  68. package/dist/hero-video-dialog-gradient.d.cts +4 -94
  69. package/dist/hero-video-dialog-gradient.d.ts +4 -94
  70. package/dist/hero-video-dialog-gradient.js +24 -23
  71. package/dist/hero-welcome-asymmetric-images.cjs +652 -617
  72. package/dist/hero-welcome-asymmetric-images.d.cts +5 -1
  73. package/dist/hero-welcome-asymmetric-images.d.ts +5 -1
  74. package/dist/hero-welcome-asymmetric-images.js +651 -616
  75. package/dist/registry.cjs +1111 -848
  76. package/dist/registry.js +1111 -848
  77. package/package.json +1 -1
@@ -1,278 +1,455 @@
1
1
  "use client";
2
2
  import * as React3 from 'react';
3
- import React3__default, { useState, useEffect, useMemo } from 'react';
3
+ import React3__default, { useState, useRef, useCallback, useEffect } from 'react';
4
+ import { AnimatePresence, motion } from 'framer-motion';
4
5
  import { clsx } from 'clsx';
5
6
  import { twMerge } from 'tailwind-merge';
7
+ import { Slot } from '@radix-ui/react-slot';
6
8
  import { cva } from 'class-variance-authority';
7
9
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import { Slot } from '@radix-ui/react-slot';
9
10
  import { Img } from '@page-speed/img';
10
- import useEmblaCarousel from 'embla-carousel-react';
11
11
 
12
12
  // components/blocks/hero/hero-business-carousel-dots.tsx
13
13
  function cn(...inputs) {
14
14
  return twMerge(clsx(inputs));
15
15
  }
16
- function getNestedCardBg(parentBg, variant = "muted", options) {
17
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
18
- if (isDark) {
19
- switch (variant) {
20
- case "muted":
21
- return "bg-background";
22
- case "card":
23
- return "bg-card";
24
- case "accent":
25
- return "bg-accent";
26
- case "subtle":
27
- return "bg-background/50";
28
- }
29
- } else {
30
- switch (variant) {
31
- case "muted":
32
- return "bg-muted";
33
- case "card":
34
- return "bg-card";
35
- case "accent":
36
- return "bg-accent";
37
- case "subtle":
38
- return "bg-muted/50";
16
+ var badgeVariants = cva(
17
+ "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
18
+ {
19
+ variants: {
20
+ variant: {
21
+ default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
22
+ secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
23
+ destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
24
+ outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
25
+ }
26
+ },
27
+ defaultVariants: {
28
+ variant: "default"
39
29
  }
40
30
  }
41
- }
42
- function getTextColor(parentBg, variant = "default", options) {
43
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
44
- if (isDark) {
45
- switch (variant) {
46
- case "default":
47
- return "text-foreground";
48
- case "muted":
49
- return "text-foreground/80";
50
- case "subtle":
51
- return "text-foreground/60";
52
- case "accent":
53
- return "text-accent-foreground";
54
- }
55
- } else {
56
- switch (variant) {
57
- case "default":
58
- return "text-foreground";
59
- case "muted":
60
- return "text-muted-foreground";
61
- case "subtle":
62
- return "text-muted-foreground/70";
63
- case "accent":
64
- return "text-primary";
31
+ );
32
+ function Badge({
33
+ className,
34
+ variant,
35
+ asChild = false,
36
+ ...props
37
+ }) {
38
+ const Comp = asChild ? Slot : "span";
39
+ return /* @__PURE__ */ jsx(
40
+ Comp,
41
+ {
42
+ "data-slot": "badge",
43
+ className: cn(badgeVariants({ variant }), className),
44
+ ...props
65
45
  }
66
- }
67
- }
68
- function normalizePhoneNumber(input) {
69
- const trimmed = input.trim();
70
- if (trimmed.toLowerCase().startsWith("tel:")) {
71
- return trimmed;
72
- }
73
- const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
74
- if (match) {
75
- const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
76
- const extension = match[3];
77
- const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
78
- const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
79
- return `tel:${withExtension}`;
80
- }
81
- const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
82
- return `tel:${cleaned}`;
83
- }
84
- function normalizeEmail(input) {
85
- const trimmed = input.trim();
86
- if (trimmed.toLowerCase().startsWith("mailto:")) {
87
- return trimmed;
88
- }
89
- return `mailto:${trimmed}`;
90
- }
91
- function isEmail(input) {
92
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
93
- return emailRegex.test(input.trim());
94
- }
95
- function isPhoneNumber(input) {
96
- const trimmed = input.trim();
97
- if (trimmed.toLowerCase().startsWith("tel:")) {
98
- return true;
99
- }
100
- const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
101
- return phoneRegex.test(trimmed);
46
+ );
102
47
  }
103
- function isInternalUrl(href) {
104
- if (typeof window === "undefined") {
105
- return href.startsWith("/") && !href.startsWith("//");
106
- }
107
- const trimmed = href.trim();
108
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
109
- return true;
110
- }
111
- try {
112
- const url = new URL(trimmed, window.location.href);
113
- const currentOrigin = window.location.origin;
114
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
115
- return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
116
- } catch {
117
- return false;
48
+ var maxWidthStyles = {
49
+ sm: "max-w-screen-sm",
50
+ md: "max-w-screen-md",
51
+ lg: "max-w-screen-lg",
52
+ xl: "max-w-7xl",
53
+ "2xl": "max-w-screen-2xl",
54
+ "4xl": "max-w-[1536px]",
55
+ full: "max-w-full"
56
+ };
57
+ var Container = React3__default.forwardRef(
58
+ ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
59
+ const Component = as;
60
+ return /* @__PURE__ */ jsx(
61
+ Component,
62
+ {
63
+ ref,
64
+ className: cn(
65
+ "mx-auto w-full px-2 sm:px-4 lg:px-8",
66
+ maxWidthStyles[maxWidth],
67
+ className
68
+ ),
69
+ ...props,
70
+ children
71
+ }
72
+ );
118
73
  }
119
- }
120
- function toRelativePath(href) {
121
- if (typeof window === "undefined") {
122
- return href;
74
+ );
75
+ Container.displayName = "Container";
76
+
77
+ // lib/patternSvgs.ts
78
+ var patternSvgs = {
79
+ squareAltGrid: "https://cdn.ing/assets/files/record/286187/4gpn0yq2ptra8iwlvmwwv860ggwv",
80
+ grid1: "https://cdn.ing/assets/files/record/286186/nbdflpgp4ostrno079hygibsflp3",
81
+ noise: "https://cdn.ing/assets/i/r/286188/zrqcp9hynh3j7p2laihwzfbujgrl/noise.png",
82
+ dots: "https://cdn.ing/assets/files/record/286198/yfsjx9thvtxzhl2qtshxyhkrm524",
83
+ dotPattern: "https://cdn.ing/assets/files/record/286192/7ig0cku8aqbboiza8nuk6hw0nnsr",
84
+ dotPattern2: "https://cdn.ing/assets/files/record/286189/arez6gd2s7isn9i1o6c7sexdq7bl",
85
+ circles: "https://cdn.ing/assets/files/record/286190/gtmia3sncjtzetdshc20zf1d3c17",
86
+ waves: "https://cdn.ing/assets/files/record/286191/mqlb33fzxz9cdth1bx7if0wmpkp1",
87
+ crossPattern: "https://cdn.ing/assets/files/record/286193/9yfqwdbnqaipbp7fsb3wbzzmq472",
88
+ architect: "https://cdn.ing/assets/files/record/286194/vgs88ugpvyhxu13wqgy0acvae6re",
89
+ tinyCheckers: "https://cdn.ing/assets/files/record/286195/65efaknsw8kcpf9o3c2gybytsl5b",
90
+ p6: "https://cdn.ing/assets/i/r/286196/6kl0rqnd6mjk8j7e525fo8fo0vkc/p6.webp"
91
+ };
92
+ var maskTop = "radial-gradient(ellipse 70% 60% at 50% 0%, #000 60%, transparent 100%)";
93
+ var maskBottom = "radial-gradient(ellipse 100% 80% at 50% 100%, #000 50%, transparent 90%)";
94
+ var maskCenter = "radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)";
95
+ var maskTopLeft = "radial-gradient(ellipse 80% 80% at 0% 0%, #000 50%, transparent 90%)";
96
+ var maskTopRight = "radial-gradient(ellipse 80% 80% at 100% 0%, #000 50%, transparent 90%)";
97
+ var maskBottomLeft = "radial-gradient(ellipse 80% 80% at 0% 100%, #000 50%, transparent 90%)";
98
+ var maskBottomRight = "radial-gradient(ellipse 80% 80% at 100% 100%, #000 50%, transparent 90%)";
99
+ var circuitBoardPattern = (id, mask) => /* @__PURE__ */ jsxs(
100
+ "svg",
101
+ {
102
+ className: "h-full w-full",
103
+ xmlns: "http://www.w3.org/2000/svg",
104
+ style: mask ? {
105
+ maskImage: mask,
106
+ WebkitMaskImage: mask
107
+ } : void 0,
108
+ children: [
109
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
110
+ "pattern",
111
+ {
112
+ id,
113
+ x: "0",
114
+ y: "0",
115
+ width: "100",
116
+ height: "100",
117
+ patternUnits: "userSpaceOnUse",
118
+ children: [
119
+ /* @__PURE__ */ jsx(
120
+ "path",
121
+ {
122
+ d: "M0 50h40M60 50h40M50 0v40M50 60v40",
123
+ stroke: "hsl(var(--muted))",
124
+ strokeWidth: "1",
125
+ fill: "none"
126
+ }
127
+ ),
128
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "3", fill: "hsl(var(--muted))" }),
129
+ /* @__PURE__ */ jsx("circle", { cx: "0", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
130
+ /* @__PURE__ */ jsx("circle", { cx: "100", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
131
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "0", r: "2", fill: "hsl(var(--muted))" }),
132
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "100", r: "2", fill: "hsl(var(--muted))" })
133
+ ]
134
+ }
135
+ ) }),
136
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
137
+ ]
123
138
  }
124
- const trimmed = href.trim();
125
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
126
- return trimmed;
139
+ );
140
+ var gridDotsPattern = (id, mask) => /* @__PURE__ */ jsxs(
141
+ "svg",
142
+ {
143
+ className: "h-full w-full",
144
+ xmlns: "http://www.w3.org/2000/svg",
145
+ style: mask ? {
146
+ maskImage: mask,
147
+ WebkitMaskImage: mask
148
+ } : void 0,
149
+ children: [
150
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
151
+ "pattern",
152
+ {
153
+ id,
154
+ x: "0",
155
+ y: "0",
156
+ width: "40",
157
+ height: "40",
158
+ patternUnits: "userSpaceOnUse",
159
+ children: [
160
+ /* @__PURE__ */ jsx(
161
+ "path",
162
+ {
163
+ d: "M0 20h40M20 0v40",
164
+ stroke: "hsl(var(--muted))",
165
+ strokeWidth: "0.5",
166
+ fill: "none"
167
+ }
168
+ ),
169
+ /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "2", fill: "hsl(var(--muted))" })
170
+ ]
171
+ }
172
+ ) }),
173
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
174
+ ]
127
175
  }
128
- try {
129
- const url = new URL(trimmed, window.location.href);
130
- const currentOrigin = window.location.origin;
131
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
132
- if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
133
- return url.pathname + url.search + url.hash;
176
+ );
177
+ var gridPattern = (size, mask) => /* @__PURE__ */ jsx(
178
+ "div",
179
+ {
180
+ className: "h-full w-full bg-[linear-gradient(to_right,_hsl(var(--muted))_1px,_transparent_1px),linear-gradient(to_bottom,_hsl(var(--muted))_1px,_transparent_1px)]",
181
+ style: {
182
+ backgroundSize: `${size}px ${size}px`,
183
+ ...mask ? {
184
+ maskImage: mask,
185
+ WebkitMaskImage: mask
186
+ } : {}
134
187
  }
135
- } catch {
136
188
  }
137
- return trimmed;
138
- }
139
- function useNavigation({
140
- href,
141
- onClick
142
- } = {}) {
143
- const linkType = React3.useMemo(() => {
144
- if (!href || href.trim() === "") {
145
- return onClick ? "none" : "none";
189
+ );
190
+ var diagonalCrossPattern = (mask) => /* @__PURE__ */ jsx(
191
+ "div",
192
+ {
193
+ className: "h-full w-full",
194
+ style: {
195
+ backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px), repeating-linear-gradient(135deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px)",
196
+ ...mask ? {
197
+ maskImage: mask,
198
+ WebkitMaskImage: mask
199
+ } : {}
146
200
  }
147
- const trimmed = href.trim();
148
- if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
149
- return "mailto";
150
- }
151
- if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
152
- return "tel";
153
- }
154
- if (isInternalUrl(trimmed)) {
155
- return "internal";
156
- }
157
- try {
158
- new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
159
- return "external";
160
- } catch {
161
- return "internal";
162
- }
163
- }, [href, onClick]);
164
- const normalizedHref = React3.useMemo(() => {
165
- if (!href || href.trim() === "") {
166
- return void 0;
167
- }
168
- const trimmed = href.trim();
169
- switch (linkType) {
170
- case "tel":
171
- return normalizePhoneNumber(trimmed);
172
- case "mailto":
173
- return normalizeEmail(trimmed);
174
- case "internal":
175
- return toRelativePath(trimmed);
176
- case "external":
177
- return trimmed;
178
- default:
179
- return trimmed;
201
+ }
202
+ );
203
+ var dashedGridMaskBase = "repeating-linear-gradient(to right, black 0px, black 3px, transparent 3px, transparent 8px), repeating-linear-gradient(to bottom, black 0px, black 3px, transparent 3px, transparent 8px)";
204
+ var dashedGridPattern = (fadeMask) => {
205
+ const mask = fadeMask ? `${dashedGridMaskBase}, ${fadeMask}` : dashedGridMaskBase;
206
+ return /* @__PURE__ */ jsx(
207
+ "div",
208
+ {
209
+ className: "h-full w-full",
210
+ style: {
211
+ backgroundImage: "linear-gradient(to right, hsl(var(--muted)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--muted)) 1px, transparent 1px)",
212
+ backgroundSize: "20px 20px",
213
+ backgroundPosition: "0 0, 0 0",
214
+ maskImage: mask,
215
+ WebkitMaskImage: mask,
216
+ maskComposite: "intersect",
217
+ WebkitMaskComposite: "source-in"
218
+ }
180
219
  }
181
- }, [href, linkType]);
182
- const target = React3.useMemo(() => {
183
- switch (linkType) {
184
- case "external":
185
- return "_blank";
186
- case "internal":
187
- return "_self";
188
- case "mailto":
189
- case "tel":
190
- return void 0;
191
- default:
192
- return void 0;
220
+ );
221
+ };
222
+ var gradientGlow = (position) => /* @__PURE__ */ jsx(
223
+ "div",
224
+ {
225
+ className: cn(
226
+ "pointer-events-none absolute left-1/2 z-0 aspect-square w-3/4 -translate-x-1/2 rounded-full opacity-50 blur-3xl",
227
+ position === "top" ? "-top-1/4" : "-bottom-1/4"
228
+ ),
229
+ style: {
230
+ background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
193
231
  }
194
- }, [linkType]);
195
- const rel = React3.useMemo(() => {
196
- if (linkType === "external") {
197
- return "noopener noreferrer";
232
+ }
233
+ );
234
+ var spotlight = (position) => /* @__PURE__ */ jsx(
235
+ "div",
236
+ {
237
+ className: cn(
238
+ "pointer-events-none absolute top-1/2 z-0 aspect-square w-3/4 -translate-y-1/2 rounded-full opacity-40 blur-3xl",
239
+ position === "left" ? "-left-1/4" : "-right-1/4"
240
+ ),
241
+ style: {
242
+ background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
198
243
  }
199
- return void 0;
200
- }, [linkType]);
201
- const isExternal = linkType === "external";
202
- const isInternal = linkType === "internal";
203
- const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
204
- const handleClick = React3.useCallback(
205
- (event) => {
206
- if (onClick) {
207
- try {
208
- onClick(event);
209
- } catch (error) {
210
- console.error("Error in user onClick handler:", error);
211
- }
212
- }
213
- if (event.defaultPrevented) {
214
- return;
244
+ }
245
+ );
246
+ var patternOverlays = {
247
+ circuitBoardBasic: () => circuitBoardPattern("circuit-board-basic"),
248
+ circuitBoardFadeTop: () => circuitBoardPattern("circuit-board-fade-top", maskTop),
249
+ circuitBoardFadeBottom: () => circuitBoardPattern("circuit-board-fade-bottom", maskBottom),
250
+ circuitBoardFadeCenter: () => circuitBoardPattern("circuit-board-fade-center", maskCenter),
251
+ circuitBoardFadeTopLeft: () => circuitBoardPattern("circuit-board-fade-top-left", maskTopLeft),
252
+ circuitBoardFadeTopRight: () => circuitBoardPattern("circuit-board-fade-top-right", maskTopRight),
253
+ circuitBoardFadeBottomLeft: () => circuitBoardPattern("circuit-board-fade-bottom-left", maskBottomLeft),
254
+ circuitBoardFadeBottomRight: () => circuitBoardPattern("circuit-board-fade-bottom-right", maskBottomRight),
255
+ dashedGridBasic: () => dashedGridPattern(),
256
+ dashedGridFadeTop: () => dashedGridPattern(maskTop),
257
+ dashedGridFadeBottom: () => dashedGridPattern(maskBottom),
258
+ dashedGridFadeCenter: () => dashedGridPattern(maskCenter),
259
+ dashedGridFadeTopLeft: () => dashedGridPattern(maskTopLeft),
260
+ dashedGridFadeTopRight: () => dashedGridPattern(maskTopRight),
261
+ dashedGridFadeBottomLeft: () => dashedGridPattern(maskBottomLeft),
262
+ dashedGridFadeBottomRight: () => dashedGridPattern(maskBottomRight),
263
+ diagonalCrossBasic: () => diagonalCrossPattern(),
264
+ diagonalCrossFadeTop: () => diagonalCrossPattern(maskTop),
265
+ diagonalCrossFadeBottom: () => diagonalCrossPattern(maskBottom),
266
+ diagonalCrossFadeCenter: () => diagonalCrossPattern(maskCenter),
267
+ diagonalCrossFadeTopLeft: () => diagonalCrossPattern(maskTopLeft),
268
+ diagonalCrossFadeTopRight: () => diagonalCrossPattern(maskTopRight),
269
+ diagonalCrossFadeBottomLeft: () => diagonalCrossPattern(maskBottomLeft),
270
+ diagonalCrossFadeBottomRight: () => diagonalCrossPattern(maskBottomRight),
271
+ gridBasic: () => gridPattern(40),
272
+ gridFadeTop: () => gridPattern(32, maskTop),
273
+ gridFadeBottom: () => gridPattern(32, maskBottom),
274
+ gridFadeCenter: () => gridPattern(40, maskCenter),
275
+ gridFadeTopLeft: () => gridPattern(32, maskTopLeft),
276
+ gridFadeTopRight: () => gridPattern(32, maskTopRight),
277
+ gridFadeBottomLeft: () => gridPattern(32, maskBottomLeft),
278
+ gridFadeBottomRight: () => gridPattern(32, maskBottomRight),
279
+ gridDotsBasic: () => gridDotsPattern("grid-dots-basic"),
280
+ gridDotsFadeCenter: () => gridDotsPattern("grid-dots-fade-center", maskCenter),
281
+ gradientGlowTop: () => gradientGlow("top"),
282
+ gradientGlowBottom: () => gradientGlow("bottom"),
283
+ spotlightLeft: () => spotlight("left"),
284
+ spotlightRight: () => spotlight("right")
285
+ };
286
+ var inlinePatternStyles = {
287
+ radialGradientTop: {
288
+ background: "radial-gradient(125% 125% at 50% 10%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
289
+ },
290
+ radialGradientBottom: {
291
+ background: "radial-gradient(125% 125% at 50% 90%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
292
+ }
293
+ };
294
+ function PatternBackground({
295
+ pattern,
296
+ opacity = 0.08,
297
+ className,
298
+ style
299
+ }) {
300
+ if (!pattern) {
301
+ return null;
302
+ }
303
+ if (pattern in inlinePatternStyles) {
304
+ const inlineStyle = inlinePatternStyles[pattern];
305
+ return /* @__PURE__ */ jsx(
306
+ "div",
307
+ {
308
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
309
+ style: { ...inlineStyle, opacity, ...style },
310
+ "aria-hidden": "true"
215
311
  }
216
- if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
217
- !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
218
- if (typeof window !== "undefined") {
219
- const handler = window.__opensiteNavigationHandler;
220
- if (typeof handler === "function") {
221
- try {
222
- const handled = handler(normalizedHref, event.nativeEvent || event);
223
- if (handled !== false) {
224
- event.preventDefault();
225
- }
226
- } catch (error) {
227
- console.error("Error in navigation handler:", error);
228
- }
229
- }
230
- }
312
+ );
313
+ }
314
+ if (pattern in patternOverlays) {
315
+ const Overlay = patternOverlays[pattern];
316
+ return /* @__PURE__ */ jsx(
317
+ "div",
318
+ {
319
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
320
+ style: { opacity, ...style },
321
+ "aria-hidden": "true",
322
+ children: Overlay()
231
323
  }
232
- },
233
- [onClick, shouldUseRouter, normalizedHref]
324
+ );
325
+ }
326
+ const patternUrl = pattern in patternSvgs ? patternSvgs[pattern] : pattern;
327
+ return /* @__PURE__ */ jsx(
328
+ "div",
329
+ {
330
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
331
+ style: {
332
+ backgroundImage: `url(${patternUrl})`,
333
+ backgroundRepeat: "repeat",
334
+ backgroundSize: "auto",
335
+ opacity,
336
+ ...style
337
+ },
338
+ "aria-hidden": "true"
339
+ }
234
340
  );
235
- return {
236
- linkType,
237
- normalizedHref,
238
- target,
239
- rel,
240
- isExternal,
241
- isInternal,
242
- shouldUseRouter,
243
- handleClick
244
- };
245
341
  }
246
- var baseStyles = [
247
- // Layout
248
- "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
249
- // Typography - using CSS variables with sensible defaults
250
- "font-[var(--button-font-family,inherit)]",
251
- "font-[var(--button-font-weight,500)]",
252
- "tracking-[var(--button-letter-spacing,0)]",
253
- "leading-[var(--button-line-height,1.25)]",
254
- "[text-transform:var(--button-text-transform,none)]",
255
- "text-sm",
256
- // Border radius
257
- "rounded-[var(--button-radius,var(--radius,0.375rem))]",
258
- // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
259
- "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
260
- // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
261
- "[box-shadow:var(--button-shadow,none)]",
262
- "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
263
- // Disabled state
264
- "disabled:pointer-events-none disabled:opacity-50",
265
- // SVG handling
266
- "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
267
- // Focus styles
268
- "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
269
- // Invalid state
270
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
271
- ].join(" ");
272
- var buttonVariants = cva(baseStyles, {
273
- variants: {
274
- variant: {
275
- // Default (Primary) variant - full customization
342
+ var backgroundStyles = {
343
+ default: "bg-background text-foreground",
344
+ white: "bg-white text-dark",
345
+ gray: "bg-muted/30 text-foreground",
346
+ dark: "bg-foreground text-background",
347
+ transparent: "bg-transparent text-foreground",
348
+ gradient: "bg-linear-to-br from-primary via-primary/90 to-foreground text-primary-foreground",
349
+ primary: "bg-primary text-primary-foreground",
350
+ secondary: "bg-secondary text-secondary-foreground",
351
+ muted: "bg-muted text-muted-foreground"
352
+ };
353
+ var spacingStyles = {
354
+ none: "py-0 md:py-0",
355
+ sm: "py-12 md:py-16",
356
+ md: "py-16 md:py-24",
357
+ lg: "py-20 md:py-32",
358
+ xl: "py-24 md:py-40"
359
+ };
360
+ var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
361
+ var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
362
+ var Section = React3__default.forwardRef(
363
+ ({
364
+ id,
365
+ title,
366
+ subtitle,
367
+ children,
368
+ className,
369
+ style,
370
+ background = "default",
371
+ spacing = "lg",
372
+ pattern,
373
+ patternOpacity,
374
+ patternClassName,
375
+ containerClassName,
376
+ containerMaxWidth = "xl",
377
+ ...props
378
+ }, ref) => {
379
+ const effectivePatternOpacity = patternOpacity !== void 0 ? patternOpacity : pattern ? 1 : 0;
380
+ return /* @__PURE__ */ jsxs(
381
+ "section",
382
+ {
383
+ ref,
384
+ id,
385
+ className: cn(
386
+ "relative",
387
+ pattern ? "overflow-hidden" : null,
388
+ backgroundStyles[background],
389
+ isPredefinedSpacing(spacing) ? spacingStyles[spacing] : spacing,
390
+ className
391
+ ),
392
+ style,
393
+ ...props,
394
+ children: [
395
+ /* @__PURE__ */ jsx(
396
+ PatternBackground,
397
+ {
398
+ pattern,
399
+ opacity: effectivePatternOpacity,
400
+ className: patternClassName
401
+ }
402
+ ),
403
+ /* @__PURE__ */ jsxs(
404
+ Container,
405
+ {
406
+ maxWidth: containerMaxWidth,
407
+ className: cn("relative z-10", containerClassName),
408
+ children: [
409
+ (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-6 text-center md:mb-16", children: [
410
+ subtitle && /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-semibold uppercase tracking-wider", children: subtitle }),
411
+ title && /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl", children: title })
412
+ ] }),
413
+ children
414
+ ]
415
+ }
416
+ )
417
+ ]
418
+ }
419
+ );
420
+ }
421
+ );
422
+ Section.displayName = "Section";
423
+ var baseStyles = [
424
+ // Layout
425
+ "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
426
+ // Typography - using CSS variables with sensible defaults
427
+ "font-[var(--button-font-family,inherit)]",
428
+ "font-[var(--button-font-weight,500)]",
429
+ "tracking-[var(--button-letter-spacing,0)]",
430
+ "leading-[var(--button-line-height,1.25)]",
431
+ "[text-transform:var(--button-text-transform,none)]",
432
+ "text-sm",
433
+ // Border radius
434
+ "rounded-[var(--button-radius,var(--radius,0.375rem))]",
435
+ // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
436
+ "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
437
+ // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
438
+ "[box-shadow:var(--button-shadow,none)]",
439
+ "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
440
+ // Disabled state
441
+ "disabled:pointer-events-none disabled:opacity-50",
442
+ // SVG handling
443
+ "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
444
+ // Focus styles
445
+ "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
446
+ // Invalid state
447
+ "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
448
+ ].join(" ");
449
+ var buttonVariants = cva(baseStyles, {
450
+ variants: {
451
+ variant: {
452
+ // Default (Primary) variant - full customization
276
453
  default: [
277
454
  "bg-[var(--button-default-bg,hsl(var(--primary)))]",
278
455
  "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
@@ -385,643 +562,360 @@ var buttonVariants = cva(baseStyles, {
385
562
  size: "default"
386
563
  }
387
564
  });
388
- var Pressable = React3.forwardRef(
389
- ({
390
- children,
391
- className,
392
- href,
393
- onClick,
394
- variant,
395
- size,
396
- asButton = false,
397
- fallbackComponentType = "span",
398
- componentType,
399
- "aria-label": ariaLabel,
400
- "aria-describedby": ariaDescribedby,
401
- id,
402
- ...props
403
- }, ref) => {
404
- const navigation = useNavigation({ href, onClick });
405
- const {
406
- normalizedHref,
407
- target,
408
- rel,
409
- linkType,
410
- isInternal,
411
- handleClick
412
- } = navigation;
413
- const shouldRenderLink = normalizedHref && linkType !== "none";
414
- const shouldRenderButton = !shouldRenderLink && onClick;
415
- const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
416
- const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
417
- const shouldApplyButtonStyles = asButton || variant || size;
418
- const combinedClassName = cn(
419
- shouldApplyButtonStyles && buttonVariants({ variant, size }),
420
- className
421
- );
422
- const dataProps = Object.fromEntries(
423
- Object.entries(props).filter(([key]) => key.startsWith("data-"))
424
- );
425
- const buttonDataAttributes = shouldApplyButtonStyles ? {
426
- "data-slot": "button",
427
- "data-variant": variant ?? "default",
428
- "data-size": size ?? "default"
429
- } : {};
430
- const commonProps = {
431
- className: combinedClassName,
432
- onClick: handleClick,
433
- "aria-label": ariaLabel,
434
- "aria-describedby": ariaDescribedby,
435
- id,
436
- ...dataProps,
437
- ...buttonDataAttributes
438
- };
439
- if (finalComponentType === "a" && shouldRenderLink) {
440
- return /* @__PURE__ */ jsx(
441
- "a",
442
- {
443
- ref,
444
- href: normalizedHref,
445
- target,
446
- rel,
447
- ...commonProps,
448
- ...props,
449
- children
450
- }
451
- );
452
- }
453
- if (finalComponentType === "button") {
454
- return /* @__PURE__ */ jsx(
455
- "button",
456
- {
457
- ref,
458
- type: props.type || "button",
459
- ...commonProps,
460
- ...props,
461
- children
462
- }
463
- );
464
- }
465
- if (finalComponentType === "div") {
466
- return /* @__PURE__ */ jsx(
467
- "div",
468
- {
469
- ref,
470
- ...commonProps,
471
- children
472
- }
473
- );
474
- }
475
- return /* @__PURE__ */ jsx(
476
- "span",
477
- {
478
- ref,
479
- ...commonProps,
480
- children
481
- }
482
- );
565
+ function normalizePhoneNumber(input) {
566
+ const trimmed = input.trim();
567
+ if (trimmed.toLowerCase().startsWith("tel:")) {
568
+ return trimmed;
483
569
  }
484
- );
485
- Pressable.displayName = "Pressable";
486
- var badgeVariants = cva(
487
- "inline-flex items-center justify-center rounded-full border px-2 py-0.5 text-xs font-medium w-fit whitespace-nowrap shrink-0 [&>svg]:size-3 gap-1 [&>svg]:pointer-events-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px] aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive transition-[color,box-shadow] overflow-hidden",
488
- {
489
- variants: {
490
- variant: {
491
- default: "border-transparent bg-primary text-primary-foreground [a&]:hover:bg-primary/90",
492
- secondary: "border-transparent bg-secondary text-secondary-foreground [a&]:hover:bg-secondary/90",
493
- destructive: "border-transparent bg-destructive text-white [a&]:hover:bg-destructive/90 focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40 dark:bg-destructive/60",
494
- outline: "text-foreground [a&]:hover:bg-accent [a&]:hover:text-accent-foreground"
495
- }
496
- },
497
- defaultVariants: {
498
- variant: "default"
499
- }
570
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
571
+ if (match) {
572
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
573
+ const extension = match[3];
574
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
575
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
576
+ return `tel:${withExtension}`;
500
577
  }
501
- );
502
- function Badge({
503
- className,
504
- variant,
505
- asChild = false,
506
- ...props
507
- }) {
508
- const Comp = asChild ? Slot : "span";
509
- return /* @__PURE__ */ jsx(
510
- Comp,
511
- {
512
- "data-slot": "badge",
513
- className: cn(badgeVariants({ variant }), className),
514
- ...props
515
- }
516
- );
578
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
579
+ return `tel:${cleaned}`;
517
580
  }
518
- var CarouselContext = React3.createContext(null);
519
- function useCarousel() {
520
- const context = React3.useContext(CarouselContext);
521
- if (!context) {
522
- throw new Error("useCarousel must be used within a <Carousel />");
581
+ function normalizeEmail(input) {
582
+ const trimmed = input.trim();
583
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
584
+ return trimmed;
523
585
  }
524
- return context;
586
+ return `mailto:${trimmed}`;
525
587
  }
526
- function Carousel({
527
- orientation = "horizontal",
528
- opts,
529
- setApi,
530
- plugins,
531
- className,
532
- children,
533
- ...props
534
- }) {
535
- const [carouselRef, api] = useEmblaCarousel(
536
- {
537
- ...opts,
538
- axis: orientation === "horizontal" ? "x" : "y"
539
- },
540
- plugins
541
- );
542
- const [canScrollPrev, setCanScrollPrev] = React3.useState(false);
543
- const [canScrollNext, setCanScrollNext] = React3.useState(false);
544
- const onSelect = React3.useCallback((api2) => {
545
- if (!api2) return;
546
- setCanScrollPrev(api2.canScrollPrev());
547
- setCanScrollNext(api2.canScrollNext());
548
- }, []);
549
- const scrollPrev = React3.useCallback(() => {
550
- api?.scrollPrev();
551
- }, [api]);
552
- const scrollNext = React3.useCallback(() => {
553
- api?.scrollNext();
554
- }, [api]);
555
- const handleKeyDown = React3.useCallback(
556
- (event) => {
557
- if (event.key === "ArrowLeft") {
558
- event.preventDefault();
559
- scrollPrev();
560
- } else if (event.key === "ArrowRight") {
561
- event.preventDefault();
562
- scrollNext();
563
- }
564
- },
565
- [scrollPrev, scrollNext]
566
- );
567
- React3.useEffect(() => {
568
- if (!api || !setApi) return;
569
- setApi(api);
570
- }, [api, setApi]);
571
- React3.useEffect(() => {
572
- if (!api) return;
573
- onSelect(api);
574
- api.on("reInit", onSelect);
575
- api.on("select", onSelect);
576
- return () => {
577
- api?.off("select", onSelect);
578
- };
579
- }, [api, onSelect]);
580
- return /* @__PURE__ */ jsx(
581
- CarouselContext.Provider,
582
- {
583
- value: {
584
- carouselRef,
585
- api,
586
- opts,
587
- orientation: orientation || (opts?.axis === "y" ? "vertical" : "horizontal"),
588
- scrollPrev,
589
- scrollNext,
590
- canScrollPrev,
591
- canScrollNext
592
- },
593
- children: /* @__PURE__ */ jsx(
594
- "div",
595
- {
596
- onKeyDownCapture: handleKeyDown,
597
- className: cn("relative", className),
598
- role: "region",
599
- "aria-roledescription": "carousel",
600
- "data-slot": "carousel",
601
- ...props,
602
- children
603
- }
604
- )
605
- }
606
- );
607
- }
608
- function CarouselContent({ className, ...props }) {
609
- const { carouselRef, orientation } = useCarousel();
610
- return /* @__PURE__ */ jsx(
611
- "div",
612
- {
613
- ref: carouselRef,
614
- className: "overflow-hidden",
615
- "data-slot": "carousel-content",
616
- children: /* @__PURE__ */ jsx(
617
- "div",
618
- {
619
- className: cn(
620
- "flex",
621
- orientation === "horizontal" ? "-ml-4" : "-mt-4 flex-col",
622
- className
623
- ),
624
- ...props
625
- }
626
- )
627
- }
628
- );
588
+ function isEmail(input) {
589
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
590
+ return emailRegex.test(input.trim());
629
591
  }
630
- function CarouselItem({ className, ...props }) {
631
- const { orientation } = useCarousel();
632
- return /* @__PURE__ */ jsx(
633
- "div",
634
- {
635
- role: "group",
636
- "aria-roledescription": "slide",
637
- "data-slot": "carousel-item",
638
- className: cn(
639
- "min-w-0 shrink-0 grow-0 basis-full",
640
- orientation === "horizontal" ? "pl-4" : "pt-4",
641
- className
642
- ),
643
- ...props
644
- }
645
- );
592
+ function isPhoneNumber(input) {
593
+ const trimmed = input.trim();
594
+ if (trimmed.toLowerCase().startsWith("tel:")) {
595
+ return true;
596
+ }
597
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
598
+ return phoneRegex.test(trimmed);
646
599
  }
647
- var maxWidthStyles = {
648
- sm: "max-w-screen-sm",
649
- md: "max-w-screen-md",
650
- lg: "max-w-screen-lg",
651
- xl: "max-w-7xl",
652
- "2xl": "max-w-screen-2xl",
653
- "4xl": "max-w-[1536px]",
654
- full: "max-w-full"
655
- };
656
- var Container = React3__default.forwardRef(
657
- ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
658
- const Component = as;
659
- return /* @__PURE__ */ jsx(
660
- Component,
661
- {
662
- ref,
663
- className: cn(
664
- "mx-auto w-full px-2 sm:px-4 lg:px-8",
665
- maxWidthStyles[maxWidth],
666
- className
667
- ),
668
- ...props,
669
- children
670
- }
671
- );
600
+ function isInternalUrl(href) {
601
+ if (typeof window === "undefined") {
602
+ return href.startsWith("/") && !href.startsWith("//");
672
603
  }
673
- );
674
- Container.displayName = "Container";
675
-
676
- // lib/patternSvgs.ts
677
- var patternSvgs = {
678
- squareAltGrid: "https://cdn.ing/assets/files/record/286187/4gpn0yq2ptra8iwlvmwwv860ggwv",
679
- grid1: "https://cdn.ing/assets/files/record/286186/nbdflpgp4ostrno079hygibsflp3",
680
- noise: "https://cdn.ing/assets/i/r/286188/zrqcp9hynh3j7p2laihwzfbujgrl/noise.png",
681
- dots: "https://cdn.ing/assets/files/record/286198/yfsjx9thvtxzhl2qtshxyhkrm524",
682
- dotPattern: "https://cdn.ing/assets/files/record/286192/7ig0cku8aqbboiza8nuk6hw0nnsr",
683
- dotPattern2: "https://cdn.ing/assets/files/record/286189/arez6gd2s7isn9i1o6c7sexdq7bl",
684
- circles: "https://cdn.ing/assets/files/record/286190/gtmia3sncjtzetdshc20zf1d3c17",
685
- waves: "https://cdn.ing/assets/files/record/286191/mqlb33fzxz9cdth1bx7if0wmpkp1",
686
- crossPattern: "https://cdn.ing/assets/files/record/286193/9yfqwdbnqaipbp7fsb3wbzzmq472",
687
- architect: "https://cdn.ing/assets/files/record/286194/vgs88ugpvyhxu13wqgy0acvae6re",
688
- tinyCheckers: "https://cdn.ing/assets/files/record/286195/65efaknsw8kcpf9o3c2gybytsl5b",
689
- p6: "https://cdn.ing/assets/i/r/286196/6kl0rqnd6mjk8j7e525fo8fo0vkc/p6.webp"
690
- };
691
- var maskTop = "radial-gradient(ellipse 70% 60% at 50% 0%, #000 60%, transparent 100%)";
692
- var maskBottom = "radial-gradient(ellipse 100% 80% at 50% 100%, #000 50%, transparent 90%)";
693
- var maskCenter = "radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)";
694
- var maskTopLeft = "radial-gradient(ellipse 80% 80% at 0% 0%, #000 50%, transparent 90%)";
695
- var maskTopRight = "radial-gradient(ellipse 80% 80% at 100% 0%, #000 50%, transparent 90%)";
696
- var maskBottomLeft = "radial-gradient(ellipse 80% 80% at 0% 100%, #000 50%, transparent 90%)";
697
- var maskBottomRight = "radial-gradient(ellipse 80% 80% at 100% 100%, #000 50%, transparent 90%)";
698
- var circuitBoardPattern = (id, mask) => /* @__PURE__ */ jsxs(
699
- "svg",
700
- {
701
- className: "h-full w-full",
702
- xmlns: "http://www.w3.org/2000/svg",
703
- style: mask ? {
704
- maskImage: mask,
705
- WebkitMaskImage: mask
706
- } : void 0,
707
- children: [
708
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
709
- "pattern",
710
- {
711
- id,
712
- x: "0",
713
- y: "0",
714
- width: "100",
715
- height: "100",
716
- patternUnits: "userSpaceOnUse",
717
- children: [
718
- /* @__PURE__ */ jsx(
719
- "path",
720
- {
721
- d: "M0 50h40M60 50h40M50 0v40M50 60v40",
722
- stroke: "hsl(var(--muted))",
723
- strokeWidth: "1",
724
- fill: "none"
725
- }
726
- ),
727
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "3", fill: "hsl(var(--muted))" }),
728
- /* @__PURE__ */ jsx("circle", { cx: "0", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
729
- /* @__PURE__ */ jsx("circle", { cx: "100", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
730
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "0", r: "2", fill: "hsl(var(--muted))" }),
731
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "100", r: "2", fill: "hsl(var(--muted))" })
732
- ]
733
- }
734
- ) }),
735
- /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
736
- ]
604
+ const trimmed = href.trim();
605
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
606
+ return true;
737
607
  }
738
- );
739
- var gridDotsPattern = (id, mask) => /* @__PURE__ */ jsxs(
740
- "svg",
741
- {
742
- className: "h-full w-full",
743
- xmlns: "http://www.w3.org/2000/svg",
744
- style: mask ? {
745
- maskImage: mask,
746
- WebkitMaskImage: mask
747
- } : void 0,
748
- children: [
749
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
750
- "pattern",
751
- {
752
- id,
753
- x: "0",
754
- y: "0",
755
- width: "40",
756
- height: "40",
757
- patternUnits: "userSpaceOnUse",
758
- children: [
759
- /* @__PURE__ */ jsx(
760
- "path",
761
- {
762
- d: "M0 20h40M20 0v40",
763
- stroke: "hsl(var(--muted))",
764
- strokeWidth: "0.5",
765
- fill: "none"
766
- }
767
- ),
768
- /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "2", fill: "hsl(var(--muted))" })
769
- ]
770
- }
771
- ) }),
772
- /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
773
- ]
608
+ try {
609
+ const url = new URL(trimmed, window.location.href);
610
+ const currentOrigin = window.location.origin;
611
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
612
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
613
+ } catch {
614
+ return false;
774
615
  }
775
- );
776
- var gridPattern = (size, mask) => /* @__PURE__ */ jsx(
777
- "div",
778
- {
779
- className: "h-full w-full bg-[linear-gradient(to_right,_hsl(var(--muted))_1px,_transparent_1px),linear-gradient(to_bottom,_hsl(var(--muted))_1px,_transparent_1px)]",
780
- style: {
781
- backgroundSize: `${size}px ${size}px`,
782
- ...mask ? {
783
- maskImage: mask,
784
- WebkitMaskImage: mask
785
- } : {}
786
- }
616
+ }
617
+ function toRelativePath(href) {
618
+ if (typeof window === "undefined") {
619
+ return href;
787
620
  }
788
- );
789
- var diagonalCrossPattern = (mask) => /* @__PURE__ */ jsx(
790
- "div",
791
- {
792
- className: "h-full w-full",
793
- style: {
794
- backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px), repeating-linear-gradient(135deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px)",
795
- ...mask ? {
796
- maskImage: mask,
797
- WebkitMaskImage: mask
798
- } : {}
621
+ const trimmed = href.trim();
622
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
623
+ return trimmed;
624
+ }
625
+ try {
626
+ const url = new URL(trimmed, window.location.href);
627
+ const currentOrigin = window.location.origin;
628
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
629
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
630
+ return url.pathname + url.search + url.hash;
799
631
  }
632
+ } catch {
800
633
  }
801
- );
802
- var dashedGridMaskBase = "repeating-linear-gradient(to right, black 0px, black 3px, transparent 3px, transparent 8px), repeating-linear-gradient(to bottom, black 0px, black 3px, transparent 3px, transparent 8px)";
803
- var dashedGridPattern = (fadeMask) => {
804
- const mask = fadeMask ? `${dashedGridMaskBase}, ${fadeMask}` : dashedGridMaskBase;
805
- return /* @__PURE__ */ jsx(
806
- "div",
807
- {
808
- className: "h-full w-full",
809
- style: {
810
- backgroundImage: "linear-gradient(to right, hsl(var(--muted)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--muted)) 1px, transparent 1px)",
811
- backgroundSize: "20px 20px",
812
- backgroundPosition: "0 0, 0 0",
813
- maskImage: mask,
814
- WebkitMaskImage: mask,
815
- maskComposite: "intersect",
816
- WebkitMaskComposite: "source-in"
634
+ return trimmed;
635
+ }
636
+ function useNavigation({
637
+ href,
638
+ onClick
639
+ } = {}) {
640
+ const linkType = React3.useMemo(() => {
641
+ if (!href || href.trim() === "") {
642
+ return onClick ? "none" : "none";
643
+ }
644
+ const trimmed = href.trim();
645
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
646
+ return "mailto";
647
+ }
648
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
649
+ return "tel";
650
+ }
651
+ if (isInternalUrl(trimmed)) {
652
+ return "internal";
653
+ }
654
+ try {
655
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
656
+ return "external";
657
+ } catch {
658
+ return "internal";
659
+ }
660
+ }, [href, onClick]);
661
+ const normalizedHref = React3.useMemo(() => {
662
+ if (!href || href.trim() === "") {
663
+ return void 0;
664
+ }
665
+ const trimmed = href.trim();
666
+ switch (linkType) {
667
+ case "tel":
668
+ return normalizePhoneNumber(trimmed);
669
+ case "mailto":
670
+ return normalizeEmail(trimmed);
671
+ case "internal":
672
+ return toRelativePath(trimmed);
673
+ case "external":
674
+ return trimmed;
675
+ default:
676
+ return trimmed;
677
+ }
678
+ }, [href, linkType]);
679
+ const target = React3.useMemo(() => {
680
+ switch (linkType) {
681
+ case "external":
682
+ return "_blank";
683
+ case "internal":
684
+ return "_self";
685
+ case "mailto":
686
+ case "tel":
687
+ return void 0;
688
+ default:
689
+ return void 0;
690
+ }
691
+ }, [linkType]);
692
+ const rel = React3.useMemo(() => {
693
+ if (linkType === "external") {
694
+ return "noopener noreferrer";
695
+ }
696
+ return void 0;
697
+ }, [linkType]);
698
+ const isExternal = linkType === "external";
699
+ const isInternal = linkType === "internal";
700
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
701
+ const handleClick = React3.useCallback(
702
+ (event) => {
703
+ if (onClick) {
704
+ try {
705
+ onClick(event);
706
+ } catch (error) {
707
+ console.error("Error in user onClick handler:", error);
708
+ }
709
+ }
710
+ if (event.defaultPrevented) {
711
+ return;
712
+ }
713
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
714
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
715
+ if (typeof window !== "undefined") {
716
+ const handler = window.__opensiteNavigationHandler;
717
+ if (typeof handler === "function") {
718
+ try {
719
+ const handled = handler(normalizedHref, event.nativeEvent || event);
720
+ if (handled !== false) {
721
+ event.preventDefault();
722
+ }
723
+ } catch (error) {
724
+ console.error("Error in navigation handler:", error);
725
+ }
726
+ }
727
+ }
817
728
  }
729
+ },
730
+ [onClick, shouldUseRouter, normalizedHref]
731
+ );
732
+ return {
733
+ linkType,
734
+ normalizedHref,
735
+ target,
736
+ rel,
737
+ isExternal,
738
+ isInternal,
739
+ shouldUseRouter,
740
+ handleClick
741
+ };
742
+ }
743
+ var Pressable = React3.forwardRef(
744
+ ({
745
+ children,
746
+ className,
747
+ href,
748
+ onClick,
749
+ variant,
750
+ size,
751
+ asButton = false,
752
+ fallbackComponentType = "span",
753
+ componentType,
754
+ "aria-label": ariaLabel,
755
+ "aria-describedby": ariaDescribedby,
756
+ id,
757
+ ...props
758
+ }, ref) => {
759
+ const navigation = useNavigation({ href, onClick });
760
+ const {
761
+ normalizedHref,
762
+ target,
763
+ rel,
764
+ linkType,
765
+ isInternal,
766
+ handleClick
767
+ } = navigation;
768
+ const shouldRenderLink = normalizedHref && linkType !== "none";
769
+ const shouldRenderButton = !shouldRenderLink && onClick;
770
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
771
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
772
+ const shouldApplyButtonStyles = asButton || variant || size;
773
+ const combinedClassName = cn(
774
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
775
+ className
776
+ );
777
+ const dataProps = Object.fromEntries(
778
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
779
+ );
780
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
781
+ "data-slot": "button",
782
+ "data-variant": variant ?? "default",
783
+ "data-size": size ?? "default"
784
+ } : {};
785
+ const commonProps = {
786
+ className: combinedClassName,
787
+ onClick: handleClick,
788
+ "aria-label": ariaLabel,
789
+ "aria-describedby": ariaDescribedby,
790
+ id,
791
+ ...dataProps,
792
+ ...buttonDataAttributes
793
+ };
794
+ if (finalComponentType === "a" && shouldRenderLink) {
795
+ return /* @__PURE__ */ jsx(
796
+ "a",
797
+ {
798
+ ref,
799
+ href: normalizedHref,
800
+ target,
801
+ rel,
802
+ ...commonProps,
803
+ ...props,
804
+ children
805
+ }
806
+ );
818
807
  }
819
- );
820
- };
821
- var gradientGlow = (position) => /* @__PURE__ */ jsx(
822
- "div",
823
- {
824
- className: cn(
825
- "pointer-events-none absolute left-1/2 z-0 aspect-square w-3/4 -translate-x-1/2 rounded-full opacity-50 blur-3xl",
826
- position === "top" ? "-top-1/4" : "-bottom-1/4"
827
- ),
828
- style: {
829
- background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
808
+ if (finalComponentType === "button") {
809
+ return /* @__PURE__ */ jsx(
810
+ "button",
811
+ {
812
+ ref,
813
+ type: props.type || "button",
814
+ ...commonProps,
815
+ ...props,
816
+ children
817
+ }
818
+ );
830
819
  }
831
- }
832
- );
833
- var spotlight = (position) => /* @__PURE__ */ jsx(
834
- "div",
835
- {
836
- className: cn(
837
- "pointer-events-none absolute top-1/2 z-0 aspect-square w-3/4 -translate-y-1/2 rounded-full opacity-40 blur-3xl",
838
- position === "left" ? "-left-1/4" : "-right-1/4"
839
- ),
840
- style: {
841
- background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
820
+ if (finalComponentType === "div") {
821
+ return /* @__PURE__ */ jsx(
822
+ "div",
823
+ {
824
+ ref,
825
+ ...commonProps,
826
+ children
827
+ }
828
+ );
842
829
  }
843
- }
844
- );
845
- var patternOverlays = {
846
- circuitBoardBasic: () => circuitBoardPattern("circuit-board-basic"),
847
- circuitBoardFadeTop: () => circuitBoardPattern("circuit-board-fade-top", maskTop),
848
- circuitBoardFadeBottom: () => circuitBoardPattern("circuit-board-fade-bottom", maskBottom),
849
- circuitBoardFadeCenter: () => circuitBoardPattern("circuit-board-fade-center", maskCenter),
850
- circuitBoardFadeTopLeft: () => circuitBoardPattern("circuit-board-fade-top-left", maskTopLeft),
851
- circuitBoardFadeTopRight: () => circuitBoardPattern("circuit-board-fade-top-right", maskTopRight),
852
- circuitBoardFadeBottomLeft: () => circuitBoardPattern("circuit-board-fade-bottom-left", maskBottomLeft),
853
- circuitBoardFadeBottomRight: () => circuitBoardPattern("circuit-board-fade-bottom-right", maskBottomRight),
854
- dashedGridBasic: () => dashedGridPattern(),
855
- dashedGridFadeTop: () => dashedGridPattern(maskTop),
856
- dashedGridFadeBottom: () => dashedGridPattern(maskBottom),
857
- dashedGridFadeCenter: () => dashedGridPattern(maskCenter),
858
- dashedGridFadeTopLeft: () => dashedGridPattern(maskTopLeft),
859
- dashedGridFadeTopRight: () => dashedGridPattern(maskTopRight),
860
- dashedGridFadeBottomLeft: () => dashedGridPattern(maskBottomLeft),
861
- dashedGridFadeBottomRight: () => dashedGridPattern(maskBottomRight),
862
- diagonalCrossBasic: () => diagonalCrossPattern(),
863
- diagonalCrossFadeTop: () => diagonalCrossPattern(maskTop),
864
- diagonalCrossFadeBottom: () => diagonalCrossPattern(maskBottom),
865
- diagonalCrossFadeCenter: () => diagonalCrossPattern(maskCenter),
866
- diagonalCrossFadeTopLeft: () => diagonalCrossPattern(maskTopLeft),
867
- diagonalCrossFadeTopRight: () => diagonalCrossPattern(maskTopRight),
868
- diagonalCrossFadeBottomLeft: () => diagonalCrossPattern(maskBottomLeft),
869
- diagonalCrossFadeBottomRight: () => diagonalCrossPattern(maskBottomRight),
870
- gridBasic: () => gridPattern(40),
871
- gridFadeTop: () => gridPattern(32, maskTop),
872
- gridFadeBottom: () => gridPattern(32, maskBottom),
873
- gridFadeCenter: () => gridPattern(40, maskCenter),
874
- gridFadeTopLeft: () => gridPattern(32, maskTopLeft),
875
- gridFadeTopRight: () => gridPattern(32, maskTopRight),
876
- gridFadeBottomLeft: () => gridPattern(32, maskBottomLeft),
877
- gridFadeBottomRight: () => gridPattern(32, maskBottomRight),
878
- gridDotsBasic: () => gridDotsPattern("grid-dots-basic"),
879
- gridDotsFadeCenter: () => gridDotsPattern("grid-dots-fade-center", maskCenter),
880
- gradientGlowTop: () => gradientGlow("top"),
881
- gradientGlowBottom: () => gradientGlow("bottom"),
882
- spotlightLeft: () => spotlight("left"),
883
- spotlightRight: () => spotlight("right")
884
- };
885
- var inlinePatternStyles = {
886
- radialGradientTop: {
887
- background: "radial-gradient(125% 125% at 50% 10%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
888
- },
889
- radialGradientBottom: {
890
- background: "radial-gradient(125% 125% at 50% 90%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
891
- }
892
- };
893
- function PatternBackground({
894
- pattern,
895
- opacity = 0.08,
896
- className,
897
- style
898
- }) {
899
- if (!pattern) {
900
- return null;
901
- }
902
- if (pattern in inlinePatternStyles) {
903
- const inlineStyle = inlinePatternStyles[pattern];
904
830
  return /* @__PURE__ */ jsx(
905
- "div",
831
+ "span",
906
832
  {
907
- className: cn("pointer-events-none absolute inset-0 z-0", className),
908
- style: { ...inlineStyle, opacity, ...style },
909
- "aria-hidden": "true"
833
+ ref,
834
+ ...commonProps,
835
+ children
910
836
  }
911
837
  );
912
838
  }
913
- if (pattern in patternOverlays) {
914
- const Overlay = patternOverlays[pattern];
839
+ );
840
+ Pressable.displayName = "Pressable";
841
+ var MOBILE_CLASSES = {
842
+ "fit-left": "items-start md:items-center",
843
+ "fit-center": "items-center",
844
+ "fit-right": "items-end md:items-center",
845
+ "full-left": "items-stretch md:items-center",
846
+ "full-center": "items-stretch md:items-center",
847
+ "full-right": "items-stretch md:items-center"
848
+ };
849
+ function BlockActions({
850
+ mobileConfig,
851
+ actionsClassName,
852
+ verticalSpacing = "mt-4 md:mt-8",
853
+ actions,
854
+ actionsSlot
855
+ }) {
856
+ const width = mobileConfig?.width ?? "full";
857
+ const position = mobileConfig?.position ?? "center";
858
+ const mobileLayoutClass = MOBILE_CLASSES[`${width}-${position}`];
859
+ if (actionsSlot) {
860
+ return /* @__PURE__ */ jsx("div", { children: actionsSlot });
861
+ } else if (actions && actions?.length > 0) {
915
862
  return /* @__PURE__ */ jsx(
916
863
  "div",
917
864
  {
918
- className: cn("pointer-events-none absolute inset-0 z-0", className),
919
- style: { opacity, ...style },
920
- "aria-hidden": "true",
921
- children: Overlay()
865
+ className: cn(
866
+ "flex flex-col md:flex-row flex-wrap gap-4",
867
+ mobileLayoutClass,
868
+ actionsClassName,
869
+ verticalSpacing
870
+ ),
871
+ children: actions.map((action, index) => /* @__PURE__ */ jsx(ActionComponent, { action }, index))
922
872
  }
923
873
  );
874
+ } else {
875
+ return null;
924
876
  }
925
- const patternUrl = pattern in patternSvgs ? patternSvgs[pattern] : pattern;
877
+ }
878
+ function ActionComponent({ action }) {
879
+ const {
880
+ label,
881
+ icon,
882
+ iconAfter,
883
+ children,
884
+ href,
885
+ onClick,
886
+ className: actionClassName,
887
+ ...pressableProps
888
+ } = action;
926
889
  return /* @__PURE__ */ jsx(
927
- "div",
890
+ Pressable,
928
891
  {
929
- className: cn("pointer-events-none absolute inset-0 z-0", className),
930
- style: {
931
- backgroundImage: `url(${patternUrl})`,
932
- backgroundRepeat: "repeat",
933
- backgroundSize: "auto",
934
- opacity,
935
- ...style
936
- },
937
- "aria-hidden": "true"
892
+ href,
893
+ onClick,
894
+ asButton: action.asButton ?? true,
895
+ className: actionClassName,
896
+ ...pressableProps,
897
+ children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
898
+ icon,
899
+ label,
900
+ iconAfter
901
+ ] })
938
902
  }
939
903
  );
940
904
  }
941
- var backgroundStyles = {
942
- default: "bg-background text-foreground",
943
- white: "bg-white text-dark",
944
- gray: "bg-muted/30 text-foreground",
945
- dark: "bg-foreground text-background",
946
- transparent: "bg-transparent text-foreground",
947
- gradient: "bg-linear-to-br from-primary via-primary/90 to-foreground text-primary-foreground",
948
- primary: "bg-primary text-primary-foreground",
949
- secondary: "bg-secondary text-secondary-foreground",
950
- muted: "bg-muted text-muted-foreground"
951
- };
952
- var spacingStyles = {
953
- none: "py-0 md:py-0",
954
- sm: "py-12 md:py-16",
955
- md: "py-16 md:py-24",
956
- lg: "py-20 md:py-32",
957
- xl: "py-24 md:py-40"
958
- };
959
- var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
960
- var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
961
- var Section = React3__default.forwardRef(
962
- ({
963
- id,
964
- title,
965
- subtitle,
966
- children,
967
- className,
968
- style,
969
- background = "default",
970
- spacing = "lg",
971
- pattern,
972
- patternOpacity,
973
- patternClassName,
974
- containerClassName,
975
- containerMaxWidth = "xl",
976
- ...props
977
- }, ref) => {
978
- const effectivePatternOpacity = patternOpacity !== void 0 ? patternOpacity : pattern ? 1 : 0;
979
- return /* @__PURE__ */ jsxs(
980
- "section",
981
- {
982
- ref,
983
- id,
984
- className: cn(
985
- "relative",
986
- pattern ? "overflow-hidden" : null,
987
- backgroundStyles[background],
988
- isPredefinedSpacing(spacing) ? spacingStyles[spacing] : spacing,
989
- className
990
- ),
991
- style,
992
- ...props,
993
- children: [
994
- /* @__PURE__ */ jsx(
995
- PatternBackground,
996
- {
997
- pattern,
998
- opacity: effectivePatternOpacity,
999
- className: patternClassName
1000
- }
1001
- ),
1002
- /* @__PURE__ */ jsxs(
1003
- Container,
1004
- {
1005
- maxWidth: containerMaxWidth,
1006
- className: cn("relative z-10", containerClassName),
1007
- children: [
1008
- (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-6 text-center md:mb-16", children: [
1009
- subtitle && /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-semibold uppercase tracking-wider", children: subtitle }),
1010
- title && /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl", children: title })
1011
- ] }),
1012
- children
1013
- ]
1014
- }
1015
- )
1016
- ]
1017
- }
1018
- );
905
+ var fadeVariants = {
906
+ initial: { opacity: 0 },
907
+ animate: {
908
+ opacity: 1,
909
+ transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] }
910
+ },
911
+ exit: {
912
+ opacity: 0,
913
+ transition: { duration: 0.8, ease: [0.4, 0, 0.2, 1] }
1019
914
  }
1020
- );
1021
- Section.displayName = "Section";
915
+ };
1022
916
  function HeroBusinessCarouselDots({
1023
917
  badge,
1024
- badgeVariant = "outline",
918
+ badgeVariant,
1025
919
  heading,
1026
920
  description,
1027
921
  actions,
@@ -1032,6 +926,7 @@ function HeroBusinessCarouselDots({
1032
926
  spacing,
1033
927
  pattern,
1034
928
  patternOpacity,
929
+ patternClassName,
1035
930
  className,
1036
931
  containerClassName,
1037
932
  contentClassName,
@@ -1042,40 +937,22 @@ function HeroBusinessCarouselDots({
1042
937
  carouselClassName,
1043
938
  optixFlowConfig
1044
939
  }) {
1045
- const [api, setApi] = useState();
1046
- const [current, setCurrent] = useState(0);
940
+ const [currentIndex, setCurrentIndex] = useState(0);
941
+ const timerRef = useRef(null);
942
+ const imageCount = carouselImages?.length ?? 0;
943
+ const startTimer = useCallback(() => {
944
+ if (imageCount <= 1) return;
945
+ timerRef.current = setInterval(() => {
946
+ setCurrentIndex((prev) => (prev + 1) % imageCount);
947
+ }, 4e3);
948
+ }, [imageCount]);
1047
949
  useEffect(() => {
1048
- if (!api) return;
1049
- const updateCurrent = () => {
1050
- setCurrent(api.selectedScrollSnap() + 1);
1051
- };
1052
- updateCurrent();
1053
- api.on("select", updateCurrent);
950
+ startTimer();
1054
951
  return () => {
1055
- api.off("select", updateCurrent);
952
+ if (timerRef.current) clearInterval(timerRef.current);
1056
953
  };
1057
- }, [api]);
1058
- const renderActions = useMemo(() => {
1059
- if (actionsSlot) return actionsSlot;
1060
- if (!actions || actions.length === 0) return null;
1061
- return actions.map((action, index) => {
1062
- const { label, icon, iconAfter, children, className: actionClassName, ...pressableProps } = action;
1063
- return /* @__PURE__ */ jsx(
1064
- Pressable,
1065
- {
1066
- asButton: true,
1067
- className: actionClassName,
1068
- ...pressableProps,
1069
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
1070
- icon,
1071
- label,
1072
- iconAfter
1073
- ] })
1074
- },
1075
- index
1076
- );
1077
- });
1078
- }, [actionsSlot, actions]);
954
+ }, [startTimer]);
955
+ const activeImage = carouselImages && carouselImages.length > 0 ? carouselImages[currentIndex] : null;
1079
956
  return /* @__PURE__ */ jsx(
1080
957
  Section,
1081
958
  {
@@ -1083,42 +960,79 @@ function HeroBusinessCarouselDots({
1083
960
  spacing,
1084
961
  pattern,
1085
962
  patternOpacity,
963
+ patternClassName,
1086
964
  className: cn("overflow-hidden", className),
1087
- children: /* @__PURE__ */ jsxs("div", { className: cn("container", containerClassName), children: [
965
+ containerClassName,
966
+ children: /* @__PURE__ */ jsxs("div", { className: "pt-8 md:pt-0", children: [
1088
967
  /* @__PURE__ */ jsxs("div", { className: cn("mx-auto max-w-5xl text-center", contentClassName), children: [
1089
968
  badge && /* @__PURE__ */ jsx(Badge, { variant: badgeVariant, className: badgeClassName, children: badge }),
1090
- heading && (typeof heading === "string" ? /* @__PURE__ */ jsx("h1", { className: cn("mt-6 text-4xl font-bold md:text-6xl", headingClassName), children: heading }) : /* @__PURE__ */ jsx("div", { className: headingClassName, children: heading })),
1091
- description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn("mt-5 text-lg md:text-xl lg:px-32", getTextColor(background, "muted"), descriptionClassName), children: description }) : /* @__PURE__ */ jsx("div", { className: descriptionClassName, children: description })),
1092
- (actionsSlot || actions && actions.length > 0) && /* @__PURE__ */ jsx("div", { className: cn("mt-8 flex justify-center gap-2", actionsClassName), children: renderActions })
969
+ heading && (typeof heading === "string" ? /* @__PURE__ */ jsx(
970
+ "h1",
971
+ {
972
+ className: cn(
973
+ "mt-6 text-4xl font-bold md:text-6xl text-balance",
974
+ headingClassName
975
+ ),
976
+ children: heading
977
+ }
978
+ ) : heading),
979
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx(
980
+ "p",
981
+ {
982
+ className: cn(
983
+ "mt-5 text-lg md:text-xl lg:px-32 text-balance",
984
+ descriptionClassName
985
+ ),
986
+ children: description
987
+ }
988
+ ) : description),
989
+ /* @__PURE__ */ jsx(
990
+ BlockActions,
991
+ {
992
+ actions,
993
+ actionsSlot,
994
+ actionsClassName
995
+ }
996
+ )
1093
997
  ] }),
1094
- /* @__PURE__ */ jsxs("div", { className: cn("relative mx-10 mt-16 hidden md:block", carouselClassName), children: [
1095
- /* @__PURE__ */ jsx("div", { className: "absolute top-0 -right-20 -left-20 z-10 h-px bg-[linear-gradient(to_right,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)]" }),
1096
- /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 -right-20 -left-20 z-10 h-px bg-[linear-gradient(to_right,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)]" }),
1097
- /* @__PURE__ */ jsx("div", { className: "absolute -top-20 left-0 z-10 h-[calc(100%+160px)] w-px bg-[linear-gradient(to_bottom,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)]" }),
1098
- /* @__PURE__ */ jsx("div", { className: "absolute -top-20 right-0 z-10 h-[calc(100%+160px)] w-px bg-[linear-gradient(to_bottom,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)]" }),
1099
- carouselSlot ? carouselSlot : carouselImages && carouselImages.length > 0 ? /* @__PURE__ */ jsxs(Fragment, { children: [
1100
- /* @__PURE__ */ jsx(Carousel, { setApi, className: "w-full", children: /* @__PURE__ */ jsx(CarouselContent, { children: carouselImages.map((image, index) => /* @__PURE__ */ jsx(CarouselItem, { children: /* @__PURE__ */ jsx(
1101
- Img,
1102
- {
1103
- src: image.src,
1104
- alt: image.alt,
1105
- className: cn("aspect-video w-full rounded-lg object-cover", image.className),
1106
- optixFlowConfig
1107
- }
1108
- ) }, index)) }) }),
1109
- /* @__PURE__ */ jsx("div", { className: "mt-4 flex justify-center gap-2", children: carouselImages.map((_, index) => /* @__PURE__ */ jsx(
1110
- "button",
1111
- {
1112
- onClick: () => api?.scrollTo(index),
1113
- className: cn(
1114
- "h-2 w-2 rounded-full transition-colors",
1115
- current === index + 1 ? "bg-primary" : getNestedCardBg(background)
1116
- )
1117
- },
1118
- index
1119
- )) })
1120
- ] }) : null
1121
- ] })
998
+ /* @__PURE__ */ jsxs(
999
+ "div",
1000
+ {
1001
+ className: cn(
1002
+ "relative mx-4 mt-10 md:mx-10 md:mt-16",
1003
+ carouselClassName
1004
+ ),
1005
+ children: [
1006
+ /* @__PURE__ */ jsx("div", { className: "absolute top-0 -right-4 -left-4 z-10 h-px bg-[linear-gradient(to_right,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)] md:-right-20 md:-left-20" }),
1007
+ /* @__PURE__ */ jsx("div", { className: "absolute bottom-0 -right-4 -left-4 z-10 h-px bg-[linear-gradient(to_right,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)] md:-right-20 md:-left-20" }),
1008
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-10 left-0 z-10 h-[calc(100%+80px)] w-px bg-[linear-gradient(to_bottom,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)] md:-top-20 md:h-[calc(100%+160px)]" }),
1009
+ /* @__PURE__ */ jsx("div", { className: "absolute -top-10 right-0 z-10 h-[calc(100%+80px)] w-px bg-[linear-gradient(to_bottom,transparent,hsl(var(--border))_4%,hsl(var(--border))_96%,transparent)] md:-top-20 md:h-[calc(100%+160px)]" }),
1010
+ carouselSlot ? carouselSlot : activeImage ? /* @__PURE__ */ jsx("div", { className: "relative aspect-video w-full overflow-hidden", children: /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", initial: false, children: /* @__PURE__ */ jsx(
1011
+ motion.div,
1012
+ {
1013
+ variants: fadeVariants,
1014
+ initial: "initial",
1015
+ animate: "animate",
1016
+ exit: "exit",
1017
+ className: "absolute inset-0",
1018
+ children: /* @__PURE__ */ jsx(
1019
+ Img,
1020
+ {
1021
+ src: activeImage.src,
1022
+ alt: activeImage.alt,
1023
+ className: cn(
1024
+ "h-full w-full object-cover",
1025
+ activeImage.className
1026
+ ),
1027
+ optixFlowConfig
1028
+ }
1029
+ )
1030
+ },
1031
+ currentIndex
1032
+ ) }) }) : null
1033
+ ]
1034
+ }
1035
+ )
1122
1036
  ] })
1123
1037
  }
1124
1038
  );