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