@opensite/ui 2.0.2 → 2.0.4

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 (75) hide show
  1. package/dist/hero-ai-powered-carousel.cjs +152 -77
  2. package/dist/hero-ai-powered-carousel.d.cts +5 -13
  3. package/dist/hero-ai-powered-carousel.d.ts +5 -13
  4. package/dist/hero-ai-powered-carousel.js +152 -77
  5. package/dist/hero-announcement-badge.cjs +679 -665
  6. package/dist/hero-announcement-badge.d.cts +1 -1
  7. package/dist/hero-announcement-badge.d.ts +1 -1
  8. package/dist/hero-announcement-badge.js +689 -675
  9. package/dist/hero-badge-shadow-overlay.cjs +79 -32
  10. package/dist/hero-badge-shadow-overlay.js +80 -33
  11. package/dist/hero-centered-image-grid.cjs +106 -95
  12. package/dist/hero-centered-image-grid.d.cts +2 -14
  13. package/dist/hero-centered-image-grid.d.ts +2 -14
  14. package/dist/hero-centered-image-grid.js +106 -95
  15. package/dist/hero-community-survey-cta.cjs +149 -58
  16. package/dist/hero-community-survey-cta.d.cts +1 -1
  17. package/dist/hero-community-survey-cta.d.ts +1 -1
  18. package/dist/hero-community-survey-cta.js +149 -58
  19. package/dist/hero-design-carousel-portfolio.cjs +158 -66
  20. package/dist/hero-design-carousel-portfolio.d.cts +7 -11
  21. package/dist/hero-design-carousel-portfolio.d.ts +7 -11
  22. package/dist/hero-design-carousel-portfolio.js +158 -66
  23. package/dist/hero-event-registration.cjs +765 -718
  24. package/dist/hero-event-registration.js +761 -714
  25. package/dist/hero-fullscreen-background-image.cjs +746 -649
  26. package/dist/hero-fullscreen-background-image.d.cts +12 -4
  27. package/dist/hero-fullscreen-background-image.d.ts +12 -4
  28. package/dist/hero-fullscreen-background-image.js +746 -649
  29. package/dist/hero-fullscreen-logo-cta.cjs +89 -31
  30. package/dist/hero-fullscreen-logo-cta.js +89 -31
  31. package/dist/hero-gradient-avatars-rating.cjs +847 -816
  32. package/dist/hero-gradient-avatars-rating.d.cts +1 -13
  33. package/dist/hero-gradient-avatars-rating.d.ts +1 -13
  34. package/dist/hero-gradient-avatars-rating.js +844 -813
  35. package/dist/hero-gradient-client-focused.cjs +690 -629
  36. package/dist/hero-gradient-client-focused.d.cts +1 -1
  37. package/dist/hero-gradient-client-focused.d.ts +1 -1
  38. package/dist/hero-gradient-client-focused.js +689 -628
  39. package/dist/hero-grid-pattern-efficiency.cjs +59 -47
  40. package/dist/hero-grid-pattern-efficiency.d.cts +1 -8
  41. package/dist/hero-grid-pattern-efficiency.d.ts +1 -8
  42. package/dist/hero-grid-pattern-efficiency.js +59 -47
  43. package/dist/hero-logo-centered-screenshot.cjs +1 -1
  44. package/dist/hero-logo-centered-screenshot.js +1 -1
  45. package/dist/hero-marketplace-scattered-images.cjs +2 -6
  46. package/dist/hero-marketplace-scattered-images.d.cts +1 -4
  47. package/dist/hero-marketplace-scattered-images.d.ts +1 -4
  48. package/dist/hero-marketplace-scattered-images.js +2 -6
  49. package/dist/hero-pattern-logo-tech-stack.cjs +1 -1
  50. package/dist/hero-pattern-logo-tech-stack.js +1 -1
  51. package/dist/hero-platform-features-grid.cjs +5 -5
  52. package/dist/hero-platform-features-grid.js +5 -5
  53. package/dist/hero-simple-centered-image.cjs +140 -44
  54. package/dist/hero-simple-centered-image.d.cts +1 -1
  55. package/dist/hero-simple-centered-image.d.ts +1 -1
  56. package/dist/hero-simple-centered-image.js +140 -44
  57. package/dist/hero-spiral-pattern-cards.cjs +857 -809
  58. package/dist/hero-spiral-pattern-cards.d.cts +5 -1
  59. package/dist/hero-spiral-pattern-cards.d.ts +5 -1
  60. package/dist/hero-spiral-pattern-cards.js +856 -808
  61. package/dist/hero-split-geometric-shapes.cjs +754 -723
  62. package/dist/hero-split-geometric-shapes.d.cts +5 -1
  63. package/dist/hero-split-geometric-shapes.d.ts +5 -1
  64. package/dist/hero-split-geometric-shapes.js +748 -717
  65. package/dist/hero-task-timer-animated.cjs +698 -650
  66. package/dist/hero-task-timer-animated.d.cts +5 -1
  67. package/dist/hero-task-timer-animated.d.ts +5 -1
  68. package/dist/hero-task-timer-animated.js +697 -649
  69. package/dist/hero-ui-library-showcase.cjs +734 -719
  70. package/dist/hero-ui-library-showcase.d.cts +5 -1
  71. package/dist/hero-ui-library-showcase.d.ts +5 -1
  72. package/dist/hero-ui-library-showcase.js +732 -717
  73. package/dist/registry.cjs +1035 -788
  74. package/dist/registry.js +1035 -788
  75. package/package.json +1 -1
@@ -1,195 +1,397 @@
1
1
  "use client";
2
- import * as React from 'react';
3
- import React__default, { useMemo } from 'react';
2
+ import * as React3 from 'react';
3
+ import React3__default, { useMemo } 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
6
  import { Img } from '@page-speed/img';
9
7
  import * as AspectRatioPrimitive from '@radix-ui/react-aspect-ratio';
8
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
9
+ import { cva } from 'class-variance-authority';
10
10
 
11
11
  // components/blocks/hero/hero-task-timer-animated.tsx
12
12
  function cn(...inputs) {
13
13
  return twMerge(clsx(inputs));
14
14
  }
15
- function normalizePhoneNumber(input) {
16
- const trimmed = input.trim();
17
- if (trimmed.toLowerCase().startsWith("tel:")) {
18
- return trimmed;
19
- }
20
- const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
21
- if (match) {
22
- const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
23
- const extension = match[3];
24
- const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
25
- const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
26
- return `tel:${withExtension}`;
27
- }
28
- const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
29
- return `tel:${cleaned}`;
30
- }
31
- function normalizeEmail(input) {
32
- const trimmed = input.trim();
33
- if (trimmed.toLowerCase().startsWith("mailto:")) {
34
- return trimmed;
35
- }
36
- return `mailto:${trimmed}`;
37
- }
38
- function isEmail(input) {
39
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
40
- return emailRegex.test(input.trim());
41
- }
42
- function isPhoneNumber(input) {
43
- const trimmed = input.trim();
44
- if (trimmed.toLowerCase().startsWith("tel:")) {
45
- return true;
46
- }
47
- const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
48
- return phoneRegex.test(trimmed);
15
+ function AspectRatio({
16
+ ...props
17
+ }) {
18
+ return /* @__PURE__ */ jsx(AspectRatioPrimitive.Root, { "data-slot": "aspect-ratio", ...props });
49
19
  }
50
- function isInternalUrl(href) {
51
- if (typeof window === "undefined") {
52
- return href.startsWith("/") && !href.startsWith("//");
53
- }
54
- const trimmed = href.trim();
55
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
56
- return true;
20
+ var maxWidthStyles = {
21
+ sm: "max-w-screen-sm",
22
+ md: "max-w-screen-md",
23
+ lg: "max-w-screen-lg",
24
+ xl: "max-w-7xl",
25
+ "2xl": "max-w-screen-2xl",
26
+ "4xl": "max-w-[1536px]",
27
+ full: "max-w-full"
28
+ };
29
+ var Container = React3__default.forwardRef(
30
+ ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
31
+ const Component = as;
32
+ return /* @__PURE__ */ jsx(
33
+ Component,
34
+ {
35
+ ref,
36
+ className: cn(
37
+ "mx-auto w-full px-2 sm:px-4 lg:px-8",
38
+ maxWidthStyles[maxWidth],
39
+ className
40
+ ),
41
+ ...props,
42
+ children
43
+ }
44
+ );
57
45
  }
58
- try {
59
- const url = new URL(trimmed, window.location.href);
60
- const currentOrigin = window.location.origin;
61
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
62
- return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
63
- } catch {
64
- return false;
46
+ );
47
+ Container.displayName = "Container";
48
+
49
+ // lib/patternSvgs.ts
50
+ var patternSvgs = {
51
+ squareAltGrid: "https://cdn.ing/assets/files/record/286187/4gpn0yq2ptra8iwlvmwwv860ggwv",
52
+ grid1: "https://cdn.ing/assets/files/record/286186/nbdflpgp4ostrno079hygibsflp3",
53
+ noise: "https://cdn.ing/assets/i/r/286188/zrqcp9hynh3j7p2laihwzfbujgrl/noise.png",
54
+ dots: "https://cdn.ing/assets/files/record/286198/yfsjx9thvtxzhl2qtshxyhkrm524",
55
+ dotPattern: "https://cdn.ing/assets/files/record/286192/7ig0cku8aqbboiza8nuk6hw0nnsr",
56
+ dotPattern2: "https://cdn.ing/assets/files/record/286189/arez6gd2s7isn9i1o6c7sexdq7bl",
57
+ circles: "https://cdn.ing/assets/files/record/286190/gtmia3sncjtzetdshc20zf1d3c17",
58
+ waves: "https://cdn.ing/assets/files/record/286191/mqlb33fzxz9cdth1bx7if0wmpkp1",
59
+ crossPattern: "https://cdn.ing/assets/files/record/286193/9yfqwdbnqaipbp7fsb3wbzzmq472",
60
+ architect: "https://cdn.ing/assets/files/record/286194/vgs88ugpvyhxu13wqgy0acvae6re",
61
+ tinyCheckers: "https://cdn.ing/assets/files/record/286195/65efaknsw8kcpf9o3c2gybytsl5b",
62
+ p6: "https://cdn.ing/assets/i/r/286196/6kl0rqnd6mjk8j7e525fo8fo0vkc/p6.webp"
63
+ };
64
+ var maskTop = "radial-gradient(ellipse 70% 60% at 50% 0%, #000 60%, transparent 100%)";
65
+ var maskBottom = "radial-gradient(ellipse 100% 80% at 50% 100%, #000 50%, transparent 90%)";
66
+ var maskCenter = "radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)";
67
+ var maskTopLeft = "radial-gradient(ellipse 80% 80% at 0% 0%, #000 50%, transparent 90%)";
68
+ var maskTopRight = "radial-gradient(ellipse 80% 80% at 100% 0%, #000 50%, transparent 90%)";
69
+ var maskBottomLeft = "radial-gradient(ellipse 80% 80% at 0% 100%, #000 50%, transparent 90%)";
70
+ var maskBottomRight = "radial-gradient(ellipse 80% 80% at 100% 100%, #000 50%, transparent 90%)";
71
+ var circuitBoardPattern = (id, mask) => /* @__PURE__ */ jsxs(
72
+ "svg",
73
+ {
74
+ className: "h-full w-full",
75
+ xmlns: "http://www.w3.org/2000/svg",
76
+ style: mask ? {
77
+ maskImage: mask,
78
+ WebkitMaskImage: mask
79
+ } : void 0,
80
+ children: [
81
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
82
+ "pattern",
83
+ {
84
+ id,
85
+ x: "0",
86
+ y: "0",
87
+ width: "100",
88
+ height: "100",
89
+ patternUnits: "userSpaceOnUse",
90
+ children: [
91
+ /* @__PURE__ */ jsx(
92
+ "path",
93
+ {
94
+ d: "M0 50h40M60 50h40M50 0v40M50 60v40",
95
+ stroke: "hsl(var(--muted))",
96
+ strokeWidth: "1",
97
+ fill: "none"
98
+ }
99
+ ),
100
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "3", fill: "hsl(var(--muted))" }),
101
+ /* @__PURE__ */ jsx("circle", { cx: "0", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
102
+ /* @__PURE__ */ jsx("circle", { cx: "100", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
103
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "0", r: "2", fill: "hsl(var(--muted))" }),
104
+ /* @__PURE__ */ jsx("circle", { cx: "50", cy: "100", r: "2", fill: "hsl(var(--muted))" })
105
+ ]
106
+ }
107
+ ) }),
108
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
109
+ ]
65
110
  }
66
- }
67
- function toRelativePath(href) {
68
- if (typeof window === "undefined") {
69
- return href;
111
+ );
112
+ var gridDotsPattern = (id, mask) => /* @__PURE__ */ jsxs(
113
+ "svg",
114
+ {
115
+ className: "h-full w-full",
116
+ xmlns: "http://www.w3.org/2000/svg",
117
+ style: mask ? {
118
+ maskImage: mask,
119
+ WebkitMaskImage: mask
120
+ } : void 0,
121
+ children: [
122
+ /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
123
+ "pattern",
124
+ {
125
+ id,
126
+ x: "0",
127
+ y: "0",
128
+ width: "40",
129
+ height: "40",
130
+ patternUnits: "userSpaceOnUse",
131
+ children: [
132
+ /* @__PURE__ */ jsx(
133
+ "path",
134
+ {
135
+ d: "M0 20h40M20 0v40",
136
+ stroke: "hsl(var(--muted))",
137
+ strokeWidth: "0.5",
138
+ fill: "none"
139
+ }
140
+ ),
141
+ /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "2", fill: "hsl(var(--muted))" })
142
+ ]
143
+ }
144
+ ) }),
145
+ /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
146
+ ]
70
147
  }
71
- const trimmed = href.trim();
72
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
73
- return trimmed;
148
+ );
149
+ var gridPattern = (size, mask) => /* @__PURE__ */ jsx(
150
+ "div",
151
+ {
152
+ className: "h-full w-full bg-[linear-gradient(to_right,_hsl(var(--muted))_1px,_transparent_1px),linear-gradient(to_bottom,_hsl(var(--muted))_1px,_transparent_1px)]",
153
+ style: {
154
+ backgroundSize: `${size}px ${size}px`,
155
+ ...mask ? {
156
+ maskImage: mask,
157
+ WebkitMaskImage: mask
158
+ } : {}
159
+ }
74
160
  }
75
- try {
76
- const url = new URL(trimmed, window.location.href);
77
- const currentOrigin = window.location.origin;
78
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
79
- if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
80
- return url.pathname + url.search + url.hash;
161
+ );
162
+ var diagonalCrossPattern = (mask) => /* @__PURE__ */ jsx(
163
+ "div",
164
+ {
165
+ className: "h-full w-full",
166
+ style: {
167
+ backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px), repeating-linear-gradient(135deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px)",
168
+ ...mask ? {
169
+ maskImage: mask,
170
+ WebkitMaskImage: mask
171
+ } : {}
81
172
  }
82
- } catch {
83
173
  }
84
- return trimmed;
85
- }
86
- function useNavigation({
87
- href,
88
- onClick
89
- } = {}) {
90
- const linkType = React.useMemo(() => {
91
- if (!href || href.trim() === "") {
92
- return onClick ? "none" : "none";
174
+ );
175
+ 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)";
176
+ var dashedGridPattern = (fadeMask) => {
177
+ const mask = fadeMask ? `${dashedGridMaskBase}, ${fadeMask}` : dashedGridMaskBase;
178
+ return /* @__PURE__ */ jsx(
179
+ "div",
180
+ {
181
+ className: "h-full w-full",
182
+ style: {
183
+ backgroundImage: "linear-gradient(to right, hsl(var(--muted)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--muted)) 1px, transparent 1px)",
184
+ backgroundSize: "20px 20px",
185
+ backgroundPosition: "0 0, 0 0",
186
+ maskImage: mask,
187
+ WebkitMaskImage: mask,
188
+ maskComposite: "intersect",
189
+ WebkitMaskComposite: "source-in"
190
+ }
93
191
  }
94
- const trimmed = href.trim();
95
- if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
96
- return "mailto";
192
+ );
193
+ };
194
+ var gradientGlow = (position) => /* @__PURE__ */ jsx(
195
+ "div",
196
+ {
197
+ className: cn(
198
+ "pointer-events-none absolute left-1/2 z-0 aspect-square w-3/4 -translate-x-1/2 rounded-full opacity-50 blur-3xl",
199
+ position === "top" ? "-top-1/4" : "-bottom-1/4"
200
+ ),
201
+ style: {
202
+ background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
97
203
  }
98
- if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
99
- return "tel";
100
- }
101
- if (isInternalUrl(trimmed)) {
102
- return "internal";
103
- }
104
- try {
105
- new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
106
- return "external";
107
- } catch {
108
- return "internal";
109
- }
110
- }, [href, onClick]);
111
- const normalizedHref = React.useMemo(() => {
112
- if (!href || href.trim() === "") {
113
- return void 0;
114
- }
115
- const trimmed = href.trim();
116
- switch (linkType) {
117
- case "tel":
118
- return normalizePhoneNumber(trimmed);
119
- case "mailto":
120
- return normalizeEmail(trimmed);
121
- case "internal":
122
- return toRelativePath(trimmed);
123
- case "external":
124
- return trimmed;
125
- default:
126
- return trimmed;
127
- }
128
- }, [href, linkType]);
129
- const target = React.useMemo(() => {
130
- switch (linkType) {
131
- case "external":
132
- return "_blank";
133
- case "internal":
134
- return "_self";
135
- case "mailto":
136
- case "tel":
137
- return void 0;
138
- default:
139
- return void 0;
140
- }
141
- }, [linkType]);
142
- const rel = React.useMemo(() => {
143
- if (linkType === "external") {
144
- return "noopener noreferrer";
204
+ }
205
+ );
206
+ var spotlight = (position) => /* @__PURE__ */ jsx(
207
+ "div",
208
+ {
209
+ className: cn(
210
+ "pointer-events-none absolute top-1/2 z-0 aspect-square w-3/4 -translate-y-1/2 rounded-full opacity-40 blur-3xl",
211
+ position === "left" ? "-left-1/4" : "-right-1/4"
212
+ ),
213
+ style: {
214
+ background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
145
215
  }
146
- return void 0;
147
- }, [linkType]);
148
- const isExternal = linkType === "external";
149
- const isInternal = linkType === "internal";
150
- const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
151
- const handleClick = React.useCallback(
152
- (event) => {
153
- if (onClick) {
154
- try {
155
- onClick(event);
156
- } catch (error) {
157
- console.error("Error in user onClick handler:", error);
158
- }
159
- }
160
- if (event.defaultPrevented) {
161
- return;
216
+ }
217
+ );
218
+ var patternOverlays = {
219
+ circuitBoardBasic: () => circuitBoardPattern("circuit-board-basic"),
220
+ circuitBoardFadeTop: () => circuitBoardPattern("circuit-board-fade-top", maskTop),
221
+ circuitBoardFadeBottom: () => circuitBoardPattern("circuit-board-fade-bottom", maskBottom),
222
+ circuitBoardFadeCenter: () => circuitBoardPattern("circuit-board-fade-center", maskCenter),
223
+ circuitBoardFadeTopLeft: () => circuitBoardPattern("circuit-board-fade-top-left", maskTopLeft),
224
+ circuitBoardFadeTopRight: () => circuitBoardPattern("circuit-board-fade-top-right", maskTopRight),
225
+ circuitBoardFadeBottomLeft: () => circuitBoardPattern("circuit-board-fade-bottom-left", maskBottomLeft),
226
+ circuitBoardFadeBottomRight: () => circuitBoardPattern("circuit-board-fade-bottom-right", maskBottomRight),
227
+ dashedGridBasic: () => dashedGridPattern(),
228
+ dashedGridFadeTop: () => dashedGridPattern(maskTop),
229
+ dashedGridFadeBottom: () => dashedGridPattern(maskBottom),
230
+ dashedGridFadeCenter: () => dashedGridPattern(maskCenter),
231
+ dashedGridFadeTopLeft: () => dashedGridPattern(maskTopLeft),
232
+ dashedGridFadeTopRight: () => dashedGridPattern(maskTopRight),
233
+ dashedGridFadeBottomLeft: () => dashedGridPattern(maskBottomLeft),
234
+ dashedGridFadeBottomRight: () => dashedGridPattern(maskBottomRight),
235
+ diagonalCrossBasic: () => diagonalCrossPattern(),
236
+ diagonalCrossFadeTop: () => diagonalCrossPattern(maskTop),
237
+ diagonalCrossFadeBottom: () => diagonalCrossPattern(maskBottom),
238
+ diagonalCrossFadeCenter: () => diagonalCrossPattern(maskCenter),
239
+ diagonalCrossFadeTopLeft: () => diagonalCrossPattern(maskTopLeft),
240
+ diagonalCrossFadeTopRight: () => diagonalCrossPattern(maskTopRight),
241
+ diagonalCrossFadeBottomLeft: () => diagonalCrossPattern(maskBottomLeft),
242
+ diagonalCrossFadeBottomRight: () => diagonalCrossPattern(maskBottomRight),
243
+ gridBasic: () => gridPattern(40),
244
+ gridFadeTop: () => gridPattern(32, maskTop),
245
+ gridFadeBottom: () => gridPattern(32, maskBottom),
246
+ gridFadeCenter: () => gridPattern(40, maskCenter),
247
+ gridFadeTopLeft: () => gridPattern(32, maskTopLeft),
248
+ gridFadeTopRight: () => gridPattern(32, maskTopRight),
249
+ gridFadeBottomLeft: () => gridPattern(32, maskBottomLeft),
250
+ gridFadeBottomRight: () => gridPattern(32, maskBottomRight),
251
+ gridDotsBasic: () => gridDotsPattern("grid-dots-basic"),
252
+ gridDotsFadeCenter: () => gridDotsPattern("grid-dots-fade-center", maskCenter),
253
+ gradientGlowTop: () => gradientGlow("top"),
254
+ gradientGlowBottom: () => gradientGlow("bottom"),
255
+ spotlightLeft: () => spotlight("left"),
256
+ spotlightRight: () => spotlight("right")
257
+ };
258
+ var inlinePatternStyles = {
259
+ radialGradientTop: {
260
+ background: "radial-gradient(125% 125% at 50% 10%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
261
+ },
262
+ radialGradientBottom: {
263
+ background: "radial-gradient(125% 125% at 50% 90%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
264
+ }
265
+ };
266
+ function PatternBackground({
267
+ pattern,
268
+ opacity = 0.08,
269
+ className,
270
+ style
271
+ }) {
272
+ if (!pattern) {
273
+ return null;
274
+ }
275
+ if (pattern in inlinePatternStyles) {
276
+ const inlineStyle = inlinePatternStyles[pattern];
277
+ return /* @__PURE__ */ jsx(
278
+ "div",
279
+ {
280
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
281
+ style: { ...inlineStyle, opacity, ...style },
282
+ "aria-hidden": "true"
162
283
  }
163
- if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
164
- !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
165
- if (typeof window !== "undefined") {
166
- const handler = window.__opensiteNavigationHandler;
167
- if (typeof handler === "function") {
168
- try {
169
- const handled = handler(normalizedHref, event.nativeEvent || event);
170
- if (handled !== false) {
171
- event.preventDefault();
172
- }
173
- } catch (error) {
174
- console.error("Error in navigation handler:", error);
175
- }
176
- }
177
- }
284
+ );
285
+ }
286
+ if (pattern in patternOverlays) {
287
+ const Overlay = patternOverlays[pattern];
288
+ return /* @__PURE__ */ jsx(
289
+ "div",
290
+ {
291
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
292
+ style: { opacity, ...style },
293
+ "aria-hidden": "true",
294
+ children: Overlay()
178
295
  }
179
- },
180
- [onClick, shouldUseRouter, normalizedHref]
296
+ );
297
+ }
298
+ const patternUrl = pattern in patternSvgs ? patternSvgs[pattern] : pattern;
299
+ return /* @__PURE__ */ jsx(
300
+ "div",
301
+ {
302
+ className: cn("pointer-events-none absolute inset-0 z-0", className),
303
+ style: {
304
+ backgroundImage: `url(${patternUrl})`,
305
+ backgroundRepeat: "repeat",
306
+ backgroundSize: "auto",
307
+ opacity,
308
+ ...style
309
+ },
310
+ "aria-hidden": "true"
311
+ }
181
312
  );
182
- return {
183
- linkType,
184
- normalizedHref,
185
- target,
186
- rel,
187
- isExternal,
188
- isInternal,
189
- shouldUseRouter,
190
- handleClick
191
- };
192
313
  }
314
+ var backgroundStyles = {
315
+ default: "bg-background text-foreground",
316
+ white: "bg-white text-dark",
317
+ gray: "bg-muted/30 text-foreground",
318
+ dark: "bg-foreground text-background",
319
+ transparent: "bg-transparent text-foreground",
320
+ gradient: "bg-linear-to-br from-primary via-primary/90 to-foreground text-primary-foreground",
321
+ primary: "bg-primary text-primary-foreground",
322
+ secondary: "bg-secondary text-secondary-foreground",
323
+ muted: "bg-muted text-muted-foreground"
324
+ };
325
+ var spacingStyles = {
326
+ none: "py-0 md:py-0",
327
+ sm: "py-12 md:py-16",
328
+ md: "py-16 md:py-24",
329
+ lg: "py-20 md:py-32",
330
+ xl: "py-24 md:py-40"
331
+ };
332
+ var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
333
+ var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
334
+ var Section = React3__default.forwardRef(
335
+ ({
336
+ id,
337
+ title,
338
+ subtitle,
339
+ children,
340
+ className,
341
+ style,
342
+ background = "default",
343
+ spacing = "lg",
344
+ pattern,
345
+ patternOpacity,
346
+ patternClassName,
347
+ containerClassName,
348
+ containerMaxWidth = "xl",
349
+ ...props
350
+ }, ref) => {
351
+ const effectivePatternOpacity = patternOpacity !== void 0 ? patternOpacity : pattern ? 1 : 0;
352
+ return /* @__PURE__ */ jsxs(
353
+ "section",
354
+ {
355
+ ref,
356
+ id,
357
+ className: cn(
358
+ "relative",
359
+ pattern ? "overflow-hidden" : null,
360
+ backgroundStyles[background],
361
+ isPredefinedSpacing(spacing) ? spacingStyles[spacing] : spacing,
362
+ className
363
+ ),
364
+ style,
365
+ ...props,
366
+ children: [
367
+ /* @__PURE__ */ jsx(
368
+ PatternBackground,
369
+ {
370
+ pattern,
371
+ opacity: effectivePatternOpacity,
372
+ className: patternClassName
373
+ }
374
+ ),
375
+ /* @__PURE__ */ jsxs(
376
+ Container,
377
+ {
378
+ maxWidth: containerMaxWidth,
379
+ className: cn("relative z-10", containerClassName),
380
+ children: [
381
+ (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-6 text-center md:mb-16", children: [
382
+ subtitle && /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-semibold uppercase tracking-wider", children: subtitle }),
383
+ title && /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl", children: title })
384
+ ] }),
385
+ children
386
+ ]
387
+ }
388
+ )
389
+ ]
390
+ }
391
+ );
392
+ }
393
+ );
394
+ Section.displayName = "Section";
193
395
  var baseStyles = [
194
396
  // Layout
195
397
  "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
@@ -332,531 +534,370 @@ var buttonVariants = cva(baseStyles, {
332
534
  size: "default"
333
535
  }
334
536
  });
335
- var Pressable = React.forwardRef(
336
- ({
337
- children,
338
- className,
339
- href,
340
- onClick,
341
- variant,
342
- size,
343
- asButton = false,
344
- fallbackComponentType = "span",
345
- componentType,
346
- "aria-label": ariaLabel,
347
- "aria-describedby": ariaDescribedby,
348
- id,
349
- ...props
350
- }, ref) => {
351
- const navigation = useNavigation({ href, onClick });
352
- const {
353
- normalizedHref,
354
- target,
355
- rel,
356
- linkType,
357
- isInternal,
358
- handleClick
359
- } = navigation;
360
- const shouldRenderLink = normalizedHref && linkType !== "none";
361
- const shouldRenderButton = !shouldRenderLink && onClick;
362
- const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
363
- const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
364
- const shouldApplyButtonStyles = asButton || variant || size;
365
- const combinedClassName = cn(
366
- shouldApplyButtonStyles && buttonVariants({ variant, size }),
367
- className
368
- );
369
- const dataProps = Object.fromEntries(
370
- Object.entries(props).filter(([key]) => key.startsWith("data-"))
371
- );
372
- const buttonDataAttributes = shouldApplyButtonStyles ? {
373
- "data-slot": "button",
374
- "data-variant": variant ?? "default",
375
- "data-size": size ?? "default"
376
- } : {};
377
- const commonProps = {
378
- className: combinedClassName,
379
- onClick: handleClick,
380
- "aria-label": ariaLabel,
381
- "aria-describedby": ariaDescribedby,
382
- id,
383
- ...dataProps,
384
- ...buttonDataAttributes
385
- };
386
- if (finalComponentType === "a" && shouldRenderLink) {
387
- return /* @__PURE__ */ jsx(
388
- "a",
389
- {
390
- ref,
391
- href: normalizedHref,
392
- target,
393
- rel,
394
- ...commonProps,
395
- ...props,
396
- children
397
- }
398
- );
399
- }
400
- if (finalComponentType === "button") {
401
- return /* @__PURE__ */ jsx(
402
- "button",
403
- {
404
- ref,
405
- type: props.type || "button",
406
- ...commonProps,
407
- ...props,
408
- children
409
- }
410
- );
411
- }
412
- if (finalComponentType === "div") {
413
- return /* @__PURE__ */ jsx(
414
- "div",
415
- {
416
- ref,
417
- ...commonProps,
418
- children
419
- }
420
- );
421
- }
422
- return /* @__PURE__ */ jsx(
423
- "span",
424
- {
425
- ref,
426
- ...commonProps,
427
- children
428
- }
429
- );
430
- }
431
- );
432
- Pressable.displayName = "Pressable";
433
- function AspectRatio({
434
- ...props
435
- }) {
436
- return /* @__PURE__ */ jsx(AspectRatioPrimitive.Root, { "data-slot": "aspect-ratio", ...props });
437
- }
438
- var maxWidthStyles = {
439
- sm: "max-w-screen-sm",
440
- md: "max-w-screen-md",
441
- lg: "max-w-screen-lg",
442
- xl: "max-w-7xl",
443
- "2xl": "max-w-screen-2xl",
444
- "4xl": "max-w-[1536px]",
445
- full: "max-w-full"
446
- };
447
- var Container = React__default.forwardRef(
448
- ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
449
- const Component = as;
450
- return /* @__PURE__ */ jsx(
451
- Component,
452
- {
453
- ref,
454
- className: cn(
455
- "mx-auto w-full px-2 sm:px-4 lg:px-8",
456
- maxWidthStyles[maxWidth],
457
- className
458
- ),
459
- ...props,
460
- children
461
- }
462
- );
463
- }
464
- );
465
- Container.displayName = "Container";
466
-
467
- // lib/patternSvgs.ts
468
- var patternSvgs = {
469
- squareAltGrid: "https://cdn.ing/assets/files/record/286187/4gpn0yq2ptra8iwlvmwwv860ggwv",
470
- grid1: "https://cdn.ing/assets/files/record/286186/nbdflpgp4ostrno079hygibsflp3",
471
- noise: "https://cdn.ing/assets/i/r/286188/zrqcp9hynh3j7p2laihwzfbujgrl/noise.png",
472
- dots: "https://cdn.ing/assets/files/record/286198/yfsjx9thvtxzhl2qtshxyhkrm524",
473
- dotPattern: "https://cdn.ing/assets/files/record/286192/7ig0cku8aqbboiza8nuk6hw0nnsr",
474
- dotPattern2: "https://cdn.ing/assets/files/record/286189/arez6gd2s7isn9i1o6c7sexdq7bl",
475
- circles: "https://cdn.ing/assets/files/record/286190/gtmia3sncjtzetdshc20zf1d3c17",
476
- waves: "https://cdn.ing/assets/files/record/286191/mqlb33fzxz9cdth1bx7if0wmpkp1",
477
- crossPattern: "https://cdn.ing/assets/files/record/286193/9yfqwdbnqaipbp7fsb3wbzzmq472",
478
- architect: "https://cdn.ing/assets/files/record/286194/vgs88ugpvyhxu13wqgy0acvae6re",
479
- tinyCheckers: "https://cdn.ing/assets/files/record/286195/65efaknsw8kcpf9o3c2gybytsl5b",
480
- p6: "https://cdn.ing/assets/i/r/286196/6kl0rqnd6mjk8j7e525fo8fo0vkc/p6.webp"
481
- };
482
- var maskTop = "radial-gradient(ellipse 70% 60% at 50% 0%, #000 60%, transparent 100%)";
483
- var maskBottom = "radial-gradient(ellipse 100% 80% at 50% 100%, #000 50%, transparent 90%)";
484
- var maskCenter = "radial-gradient(ellipse 60% 60% at 50% 50%, #000 30%, transparent 70%)";
485
- var maskTopLeft = "radial-gradient(ellipse 80% 80% at 0% 0%, #000 50%, transparent 90%)";
486
- var maskTopRight = "radial-gradient(ellipse 80% 80% at 100% 0%, #000 50%, transparent 90%)";
487
- var maskBottomLeft = "radial-gradient(ellipse 80% 80% at 0% 100%, #000 50%, transparent 90%)";
488
- var maskBottomRight = "radial-gradient(ellipse 80% 80% at 100% 100%, #000 50%, transparent 90%)";
489
- var circuitBoardPattern = (id, mask) => /* @__PURE__ */ jsxs(
490
- "svg",
491
- {
492
- className: "h-full w-full",
493
- xmlns: "http://www.w3.org/2000/svg",
494
- style: mask ? {
495
- maskImage: mask,
496
- WebkitMaskImage: mask
497
- } : void 0,
498
- children: [
499
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
500
- "pattern",
501
- {
502
- id,
503
- x: "0",
504
- y: "0",
505
- width: "100",
506
- height: "100",
507
- patternUnits: "userSpaceOnUse",
508
- children: [
509
- /* @__PURE__ */ jsx(
510
- "path",
511
- {
512
- d: "M0 50h40M60 50h40M50 0v40M50 60v40",
513
- stroke: "hsl(var(--muted))",
514
- strokeWidth: "1",
515
- fill: "none"
516
- }
517
- ),
518
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "50", r: "3", fill: "hsl(var(--muted))" }),
519
- /* @__PURE__ */ jsx("circle", { cx: "0", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
520
- /* @__PURE__ */ jsx("circle", { cx: "100", cy: "50", r: "2", fill: "hsl(var(--muted))" }),
521
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "0", r: "2", fill: "hsl(var(--muted))" }),
522
- /* @__PURE__ */ jsx("circle", { cx: "50", cy: "100", r: "2", fill: "hsl(var(--muted))" })
523
- ]
524
- }
525
- ) }),
526
- /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
527
- ]
537
+ function normalizePhoneNumber(input) {
538
+ const trimmed = input.trim();
539
+ if (trimmed.toLowerCase().startsWith("tel:")) {
540
+ return trimmed;
528
541
  }
529
- );
530
- var gridDotsPattern = (id, mask) => /* @__PURE__ */ jsxs(
531
- "svg",
532
- {
533
- className: "h-full w-full",
534
- xmlns: "http://www.w3.org/2000/svg",
535
- style: mask ? {
536
- maskImage: mask,
537
- WebkitMaskImage: mask
538
- } : void 0,
539
- children: [
540
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsxs(
541
- "pattern",
542
- {
543
- id,
544
- x: "0",
545
- y: "0",
546
- width: "40",
547
- height: "40",
548
- patternUnits: "userSpaceOnUse",
549
- children: [
550
- /* @__PURE__ */ jsx(
551
- "path",
552
- {
553
- d: "M0 20h40M20 0v40",
554
- stroke: "hsl(var(--muted))",
555
- strokeWidth: "0.5",
556
- fill: "none"
557
- }
558
- ),
559
- /* @__PURE__ */ jsx("circle", { cx: "20", cy: "20", r: "2", fill: "hsl(var(--muted))" })
560
- ]
561
- }
562
- ) }),
563
- /* @__PURE__ */ jsx("rect", { width: "100%", height: "100%", fill: `url(#${id})` })
564
- ]
542
+ const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
543
+ if (match) {
544
+ const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
545
+ const extension = match[3];
546
+ const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
547
+ const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
548
+ return `tel:${withExtension}`;
565
549
  }
566
- );
567
- var gridPattern = (size, mask) => /* @__PURE__ */ jsx(
568
- "div",
569
- {
570
- className: "h-full w-full bg-[linear-gradient(to_right,_hsl(var(--muted))_1px,_transparent_1px),linear-gradient(to_bottom,_hsl(var(--muted))_1px,_transparent_1px)]",
571
- style: {
572
- backgroundSize: `${size}px ${size}px`,
573
- ...mask ? {
574
- maskImage: mask,
575
- WebkitMaskImage: mask
576
- } : {}
577
- }
550
+ const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
551
+ return `tel:${cleaned}`;
552
+ }
553
+ function normalizeEmail(input) {
554
+ const trimmed = input.trim();
555
+ if (trimmed.toLowerCase().startsWith("mailto:")) {
556
+ return trimmed;
578
557
  }
579
- );
580
- var diagonalCrossPattern = (mask) => /* @__PURE__ */ jsx(
581
- "div",
582
- {
583
- className: "h-full w-full",
584
- style: {
585
- backgroundImage: "repeating-linear-gradient(45deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px), repeating-linear-gradient(135deg, transparent, transparent 32px, hsl(var(--muted)) 32px, hsl(var(--muted)) 33px)",
586
- ...mask ? {
587
- maskImage: mask,
588
- WebkitMaskImage: mask
589
- } : {}
590
- }
558
+ return `mailto:${trimmed}`;
559
+ }
560
+ function isEmail(input) {
561
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
562
+ return emailRegex.test(input.trim());
563
+ }
564
+ function isPhoneNumber(input) {
565
+ const trimmed = input.trim();
566
+ if (trimmed.toLowerCase().startsWith("tel:")) {
567
+ return true;
591
568
  }
592
- );
593
- 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)";
594
- var dashedGridPattern = (fadeMask) => {
595
- const mask = fadeMask ? `${dashedGridMaskBase}, ${fadeMask}` : dashedGridMaskBase;
596
- return /* @__PURE__ */ jsx(
597
- "div",
598
- {
599
- className: "h-full w-full",
600
- style: {
601
- backgroundImage: "linear-gradient(to right, hsl(var(--muted)) 1px, transparent 1px), linear-gradient(to bottom, hsl(var(--muted)) 1px, transparent 1px)",
602
- backgroundSize: "20px 20px",
603
- backgroundPosition: "0 0, 0 0",
604
- maskImage: mask,
605
- WebkitMaskImage: mask,
606
- maskComposite: "intersect",
607
- WebkitMaskComposite: "source-in"
608
- }
609
- }
610
- );
611
- };
612
- var gradientGlow = (position) => /* @__PURE__ */ jsx(
613
- "div",
614
- {
615
- className: cn(
616
- "pointer-events-none absolute left-1/2 z-0 aspect-square w-3/4 -translate-x-1/2 rounded-full opacity-50 blur-3xl",
617
- position === "top" ? "-top-1/4" : "-bottom-1/4"
618
- ),
619
- style: {
620
- background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
621
- }
569
+ const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
570
+ return phoneRegex.test(trimmed);
571
+ }
572
+ function isInternalUrl(href) {
573
+ if (typeof window === "undefined") {
574
+ return href.startsWith("/") && !href.startsWith("//");
622
575
  }
623
- );
624
- var spotlight = (position) => /* @__PURE__ */ jsx(
625
- "div",
626
- {
627
- className: cn(
628
- "pointer-events-none absolute top-1/2 z-0 aspect-square w-3/4 -translate-y-1/2 rounded-full opacity-40 blur-3xl",
629
- position === "left" ? "-left-1/4" : "-right-1/4"
630
- ),
631
- style: {
632
- background: "radial-gradient(circle, hsl(var(--primary)) 0%, transparent 70%)"
633
- }
576
+ const trimmed = href.trim();
577
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
578
+ return true;
634
579
  }
635
- );
636
- var patternOverlays = {
637
- circuitBoardBasic: () => circuitBoardPattern("circuit-board-basic"),
638
- circuitBoardFadeTop: () => circuitBoardPattern("circuit-board-fade-top", maskTop),
639
- circuitBoardFadeBottom: () => circuitBoardPattern("circuit-board-fade-bottom", maskBottom),
640
- circuitBoardFadeCenter: () => circuitBoardPattern("circuit-board-fade-center", maskCenter),
641
- circuitBoardFadeTopLeft: () => circuitBoardPattern("circuit-board-fade-top-left", maskTopLeft),
642
- circuitBoardFadeTopRight: () => circuitBoardPattern("circuit-board-fade-top-right", maskTopRight),
643
- circuitBoardFadeBottomLeft: () => circuitBoardPattern("circuit-board-fade-bottom-left", maskBottomLeft),
644
- circuitBoardFadeBottomRight: () => circuitBoardPattern("circuit-board-fade-bottom-right", maskBottomRight),
645
- dashedGridBasic: () => dashedGridPattern(),
646
- dashedGridFadeTop: () => dashedGridPattern(maskTop),
647
- dashedGridFadeBottom: () => dashedGridPattern(maskBottom),
648
- dashedGridFadeCenter: () => dashedGridPattern(maskCenter),
649
- dashedGridFadeTopLeft: () => dashedGridPattern(maskTopLeft),
650
- dashedGridFadeTopRight: () => dashedGridPattern(maskTopRight),
651
- dashedGridFadeBottomLeft: () => dashedGridPattern(maskBottomLeft),
652
- dashedGridFadeBottomRight: () => dashedGridPattern(maskBottomRight),
653
- diagonalCrossBasic: () => diagonalCrossPattern(),
654
- diagonalCrossFadeTop: () => diagonalCrossPattern(maskTop),
655
- diagonalCrossFadeBottom: () => diagonalCrossPattern(maskBottom),
656
- diagonalCrossFadeCenter: () => diagonalCrossPattern(maskCenter),
657
- diagonalCrossFadeTopLeft: () => diagonalCrossPattern(maskTopLeft),
658
- diagonalCrossFadeTopRight: () => diagonalCrossPattern(maskTopRight),
659
- diagonalCrossFadeBottomLeft: () => diagonalCrossPattern(maskBottomLeft),
660
- diagonalCrossFadeBottomRight: () => diagonalCrossPattern(maskBottomRight),
661
- gridBasic: () => gridPattern(40),
662
- gridFadeTop: () => gridPattern(32, maskTop),
663
- gridFadeBottom: () => gridPattern(32, maskBottom),
664
- gridFadeCenter: () => gridPattern(40, maskCenter),
665
- gridFadeTopLeft: () => gridPattern(32, maskTopLeft),
666
- gridFadeTopRight: () => gridPattern(32, maskTopRight),
667
- gridFadeBottomLeft: () => gridPattern(32, maskBottomLeft),
668
- gridFadeBottomRight: () => gridPattern(32, maskBottomRight),
669
- gridDotsBasic: () => gridDotsPattern("grid-dots-basic"),
670
- gridDotsFadeCenter: () => gridDotsPattern("grid-dots-fade-center", maskCenter),
671
- gradientGlowTop: () => gradientGlow("top"),
672
- gradientGlowBottom: () => gradientGlow("bottom"),
673
- spotlightLeft: () => spotlight("left"),
674
- spotlightRight: () => spotlight("right")
675
- };
676
- var inlinePatternStyles = {
677
- radialGradientTop: {
678
- background: "radial-gradient(125% 125% at 50% 10%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
679
- },
680
- radialGradientBottom: {
681
- background: "radial-gradient(125% 125% at 50% 90%, hsl(var(--background)) 40%, hsl(var(--primary)) 100%)"
580
+ try {
581
+ const url = new URL(trimmed, window.location.href);
582
+ const currentOrigin = window.location.origin;
583
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
584
+ return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
585
+ } catch {
586
+ return false;
682
587
  }
683
- };
684
- function PatternBackground({
685
- pattern,
686
- opacity = 0.08,
687
- className,
688
- style
689
- }) {
690
- if (!pattern) {
691
- return null;
588
+ }
589
+ function toRelativePath(href) {
590
+ if (typeof window === "undefined") {
591
+ return href;
692
592
  }
693
- if (pattern in inlinePatternStyles) {
694
- const inlineStyle = inlinePatternStyles[pattern];
695
- return /* @__PURE__ */ jsx(
696
- "div",
697
- {
698
- className: cn("pointer-events-none absolute inset-0 z-0", className),
699
- style: { ...inlineStyle, opacity, ...style },
700
- "aria-hidden": "true"
701
- }
702
- );
593
+ const trimmed = href.trim();
594
+ if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
595
+ return trimmed;
703
596
  }
704
- if (pattern in patternOverlays) {
705
- const Overlay = patternOverlays[pattern];
706
- return /* @__PURE__ */ jsx(
707
- "div",
708
- {
709
- className: cn("pointer-events-none absolute inset-0 z-0", className),
710
- style: { opacity, ...style },
711
- "aria-hidden": "true",
712
- children: Overlay()
713
- }
714
- );
597
+ try {
598
+ const url = new URL(trimmed, window.location.href);
599
+ const currentOrigin = window.location.origin;
600
+ const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
601
+ if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
602
+ return url.pathname + url.search + url.hash;
603
+ }
604
+ } catch {
715
605
  }
716
- const patternUrl = pattern in patternSvgs ? patternSvgs[pattern] : pattern;
717
- return /* @__PURE__ */ jsx(
718
- "div",
719
- {
720
- className: cn("pointer-events-none absolute inset-0 z-0", className),
721
- style: {
722
- backgroundImage: `url(${patternUrl})`,
723
- backgroundRepeat: "repeat",
724
- backgroundSize: "auto",
725
- opacity,
726
- ...style
727
- },
728
- "aria-hidden": "true"
606
+ return trimmed;
607
+ }
608
+ function useNavigation({
609
+ href,
610
+ onClick
611
+ } = {}) {
612
+ const linkType = React3.useMemo(() => {
613
+ if (!href || href.trim() === "") {
614
+ return onClick ? "none" : "none";
615
+ }
616
+ const trimmed = href.trim();
617
+ if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
618
+ return "mailto";
619
+ }
620
+ if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
621
+ return "tel";
622
+ }
623
+ if (isInternalUrl(trimmed)) {
624
+ return "internal";
625
+ }
626
+ try {
627
+ new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
628
+ return "external";
629
+ } catch {
630
+ return "internal";
631
+ }
632
+ }, [href, onClick]);
633
+ const normalizedHref = React3.useMemo(() => {
634
+ if (!href || href.trim() === "") {
635
+ return void 0;
636
+ }
637
+ const trimmed = href.trim();
638
+ switch (linkType) {
639
+ case "tel":
640
+ return normalizePhoneNumber(trimmed);
641
+ case "mailto":
642
+ return normalizeEmail(trimmed);
643
+ case "internal":
644
+ return toRelativePath(trimmed);
645
+ case "external":
646
+ return trimmed;
647
+ default:
648
+ return trimmed;
649
+ }
650
+ }, [href, linkType]);
651
+ const target = React3.useMemo(() => {
652
+ switch (linkType) {
653
+ case "external":
654
+ return "_blank";
655
+ case "internal":
656
+ return "_self";
657
+ case "mailto":
658
+ case "tel":
659
+ return void 0;
660
+ default:
661
+ return void 0;
662
+ }
663
+ }, [linkType]);
664
+ const rel = React3.useMemo(() => {
665
+ if (linkType === "external") {
666
+ return "noopener noreferrer";
729
667
  }
668
+ return void 0;
669
+ }, [linkType]);
670
+ const isExternal = linkType === "external";
671
+ const isInternal = linkType === "internal";
672
+ const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
673
+ const handleClick = React3.useCallback(
674
+ (event) => {
675
+ if (onClick) {
676
+ try {
677
+ onClick(event);
678
+ } catch (error) {
679
+ console.error("Error in user onClick handler:", error);
680
+ }
681
+ }
682
+ if (event.defaultPrevented) {
683
+ return;
684
+ }
685
+ if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
686
+ !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
687
+ if (typeof window !== "undefined") {
688
+ const handler = window.__opensiteNavigationHandler;
689
+ if (typeof handler === "function") {
690
+ try {
691
+ const handled = handler(normalizedHref, event.nativeEvent || event);
692
+ if (handled !== false) {
693
+ event.preventDefault();
694
+ }
695
+ } catch (error) {
696
+ console.error("Error in navigation handler:", error);
697
+ }
698
+ }
699
+ }
700
+ }
701
+ },
702
+ [onClick, shouldUseRouter, normalizedHref]
730
703
  );
704
+ return {
705
+ linkType,
706
+ normalizedHref,
707
+ target,
708
+ rel,
709
+ isExternal,
710
+ isInternal,
711
+ shouldUseRouter,
712
+ handleClick
713
+ };
731
714
  }
732
- var backgroundStyles = {
733
- default: "bg-background text-foreground",
734
- white: "bg-white text-dark",
735
- gray: "bg-muted/30 text-foreground",
736
- dark: "bg-foreground text-background",
737
- transparent: "bg-transparent text-foreground",
738
- gradient: "bg-linear-to-br from-primary via-primary/90 to-foreground text-primary-foreground",
739
- primary: "bg-primary text-primary-foreground",
740
- secondary: "bg-secondary text-secondary-foreground",
741
- muted: "bg-muted text-muted-foreground"
742
- };
743
- var spacingStyles = {
744
- none: "py-0 md:py-0",
745
- sm: "py-12 md:py-16",
746
- md: "py-16 md:py-24",
747
- lg: "py-20 md:py-32",
748
- xl: "py-24 md:py-40"
749
- };
750
- var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
751
- var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
752
- var Section = React__default.forwardRef(
715
+ var Pressable = React3.forwardRef(
753
716
  ({
754
- id,
755
- title,
756
- subtitle,
757
717
  children,
758
718
  className,
759
- style,
760
- background = "default",
761
- spacing = "lg",
762
- pattern,
763
- patternOpacity,
764
- patternClassName,
765
- containerClassName,
766
- containerMaxWidth = "xl",
719
+ href,
720
+ onClick,
721
+ variant,
722
+ size,
723
+ asButton = false,
724
+ fallbackComponentType = "span",
725
+ componentType,
726
+ "aria-label": ariaLabel,
727
+ "aria-describedby": ariaDescribedby,
728
+ id,
767
729
  ...props
768
730
  }, ref) => {
769
- const effectivePatternOpacity = patternOpacity !== void 0 ? patternOpacity : pattern ? 1 : 0;
770
- return /* @__PURE__ */ jsxs(
771
- "section",
731
+ const navigation = useNavigation({ href, onClick });
732
+ const {
733
+ normalizedHref,
734
+ target,
735
+ rel,
736
+ linkType,
737
+ isInternal,
738
+ handleClick
739
+ } = navigation;
740
+ const shouldRenderLink = normalizedHref && linkType !== "none";
741
+ const shouldRenderButton = !shouldRenderLink && onClick;
742
+ const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
743
+ const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
744
+ const shouldApplyButtonStyles = asButton || variant || size;
745
+ const combinedClassName = cn(
746
+ shouldApplyButtonStyles && buttonVariants({ variant, size }),
747
+ className
748
+ );
749
+ const dataProps = Object.fromEntries(
750
+ Object.entries(props).filter(([key]) => key.startsWith("data-"))
751
+ );
752
+ const buttonDataAttributes = shouldApplyButtonStyles ? {
753
+ "data-slot": "button",
754
+ "data-variant": variant ?? "default",
755
+ "data-size": size ?? "default"
756
+ } : {};
757
+ const commonProps = {
758
+ className: combinedClassName,
759
+ onClick: handleClick,
760
+ "aria-label": ariaLabel,
761
+ "aria-describedby": ariaDescribedby,
762
+ id,
763
+ ...dataProps,
764
+ ...buttonDataAttributes
765
+ };
766
+ if (finalComponentType === "a" && shouldRenderLink) {
767
+ return /* @__PURE__ */ jsx(
768
+ "a",
769
+ {
770
+ ref,
771
+ href: normalizedHref,
772
+ target,
773
+ rel,
774
+ ...commonProps,
775
+ ...props,
776
+ children
777
+ }
778
+ );
779
+ }
780
+ if (finalComponentType === "button") {
781
+ return /* @__PURE__ */ jsx(
782
+ "button",
783
+ {
784
+ ref,
785
+ type: props.type || "button",
786
+ ...commonProps,
787
+ ...props,
788
+ children
789
+ }
790
+ );
791
+ }
792
+ if (finalComponentType === "div") {
793
+ return /* @__PURE__ */ jsx(
794
+ "div",
795
+ {
796
+ ref,
797
+ ...commonProps,
798
+ children
799
+ }
800
+ );
801
+ }
802
+ return /* @__PURE__ */ jsx(
803
+ "span",
772
804
  {
773
805
  ref,
774
- id,
775
- className: cn(
776
- "relative",
777
- pattern ? "overflow-hidden" : null,
778
- backgroundStyles[background],
779
- isPredefinedSpacing(spacing) ? spacingStyles[spacing] : spacing,
780
- className
781
- ),
782
- style,
783
- ...props,
784
- children: [
785
- /* @__PURE__ */ jsx(
786
- PatternBackground,
787
- {
788
- pattern,
789
- opacity: effectivePatternOpacity,
790
- className: patternClassName
791
- }
792
- ),
793
- /* @__PURE__ */ jsxs(
794
- Container,
795
- {
796
- maxWidth: containerMaxWidth,
797
- className: cn("relative z-10", containerClassName),
798
- children: [
799
- (title || subtitle) && /* @__PURE__ */ jsxs("div", { className: "mb-6 text-center md:mb-16", children: [
800
- subtitle && /* @__PURE__ */ jsx("p", { className: "mb-2 text-sm font-semibold uppercase tracking-wider", children: subtitle }),
801
- title && /* @__PURE__ */ jsx("h2", { className: "text-3xl font-bold tracking-tight md:text-4xl lg:text-5xl", children: title })
802
- ] }),
803
- children
804
- ]
805
- }
806
- )
807
- ]
806
+ ...commonProps,
807
+ children
808
808
  }
809
809
  );
810
810
  }
811
811
  );
812
- Section.displayName = "Section";
813
- function HeroTaskTimerAnimated({
814
- heading,
815
- description,
816
- descriptionClassName,
812
+ Pressable.displayName = "Pressable";
813
+ var MOBILE_CLASSES = {
814
+ "fit-left": "items-start md:items-center",
815
+ "fit-center": "items-center",
816
+ "fit-right": "items-end md:items-center",
817
+ "full-left": "items-stretch md:items-center",
818
+ "full-center": "items-stretch md:items-center",
819
+ "full-right": "items-stretch md:items-center"
820
+ };
821
+ function BlockActions({
822
+ mobileConfig,
823
+ actionsClassName,
824
+ verticalSpacing = "mt-4 md:mt-8",
817
825
  actions,
818
- actionsSlot,
819
- images,
820
- imagesSlot,
821
- background,
822
- spacing = "pt-28 pb-8 md:pt-32 md:pb-32",
823
- pattern,
824
- patternOpacity,
825
- className,
826
- containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
827
- headerClassName,
828
- headingClassName,
829
- imagesClassName,
830
- optixFlowConfig
826
+ actionsSlot
831
827
  }) {
832
- const renderActions = useMemo(() => {
833
- if (actionsSlot) return actionsSlot;
834
- if (!actions || actions.length === 0) return null;
835
- return /* @__PURE__ */ jsx("div", { className: "flex flex-col items-start mt-6 md:mt-8 gap-4 sm:flex-row sm:items-center", children: actions.map((action, index) => {
828
+ const renderAction = React3.useCallback(
829
+ (action, idx) => {
836
830
  const {
837
831
  label,
838
832
  icon,
839
833
  iconAfter,
840
834
  children,
835
+ href,
836
+ onClick,
841
837
  className: actionClassName,
842
838
  ...pressableProps
843
839
  } = action;
844
840
  return /* @__PURE__ */ jsx(
845
841
  Pressable,
846
842
  {
847
- asButton: true,
843
+ href,
844
+ onClick,
845
+ asButton: action.asButton || true,
848
846
  className: actionClassName,
849
847
  ...pressableProps,
850
848
  children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
851
849
  icon,
852
- /* @__PURE__ */ jsx("span", { children: label }),
850
+ label,
853
851
  iconAfter
854
852
  ] })
855
853
  },
856
- index
854
+ idx
857
855
  );
858
- }) });
859
- }, [actionsSlot, actions]);
856
+ },
857
+ []
858
+ );
859
+ const width = mobileConfig?.width ?? "full";
860
+ const position = mobileConfig?.position ?? "center";
861
+ const mobileLayoutClass = MOBILE_CLASSES[`${width}-${position}`];
862
+ if (actionsSlot) {
863
+ return /* @__PURE__ */ jsx("div", { children: actionsSlot });
864
+ } else if (actions && actions?.length > 0) {
865
+ return /* @__PURE__ */ jsx(
866
+ "div",
867
+ {
868
+ className: cn(
869
+ "flex flex-col md:flex-row flex-wrap gap-4",
870
+ mobileLayoutClass,
871
+ actionsClassName,
872
+ verticalSpacing
873
+ ),
874
+ children: actions.map((action, index) => renderAction(action, index))
875
+ }
876
+ );
877
+ } else {
878
+ return null;
879
+ }
880
+ }
881
+ function HeroTaskTimerAnimated({
882
+ heading,
883
+ description,
884
+ descriptionClassName,
885
+ actions,
886
+ actionsSlot,
887
+ actionsClassName,
888
+ images,
889
+ imagesSlot,
890
+ background,
891
+ pattern,
892
+ patternOpacity,
893
+ className,
894
+ spacing = "xl",
895
+ containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
896
+ headerClassName,
897
+ headingClassName,
898
+ imagesClassName,
899
+ optixFlowConfig
900
+ }) {
860
901
  const renderImages = useMemo(() => {
861
902
  if (imagesSlot) return imagesSlot;
862
903
  if (!images || images.length < 2) return null;
@@ -927,7 +968,14 @@ function HeroTaskTimerAnimated({
927
968
  }
928
969
  )),
929
970
  description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn("text-lg text-balance", descriptionClassName), children: description }) : /* @__PURE__ */ jsx("div", { className: descriptionClassName, children: description })),
930
- renderActions
971
+ /* @__PURE__ */ jsx(
972
+ BlockActions,
973
+ {
974
+ actions,
975
+ actionsSlot,
976
+ actionsClassName
977
+ }
978
+ )
931
979
  ] }),
932
980
  renderImages
933
981
  ] })