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