@opensite/ui 2.1.9 → 2.2.1

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.
@@ -1,458 +1,21 @@
1
1
  "use client";
2
- import * as React from 'react';
3
- import React__default, { useMemo } from 'react';
4
- import { Form } from '@page-speed/forms';
5
- import { useFileUpload, useContactForm, getColumnSpanClass, DynamicFormField } from '@page-speed/forms/integration';
2
+ import * as React3 from 'react';
3
+ import React3__default from 'react';
4
+ import { motion } from 'framer-motion';
5
+ import { FormEngine } from '@page-speed/forms/integration';
6
6
  import { clsx } from 'clsx';
7
7
  import { twMerge } from 'tailwind-merge';
8
- import { cva } from 'class-variance-authority';
9
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
10
8
  import { Img } from '@page-speed/img';
9
+ import { Icon } from '@page-speed/icon';
10
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
11
11
 
12
12
  // components/blocks/contact/contact-image.tsx
13
13
  function cn(...inputs) {
14
14
  return twMerge(clsx(inputs));
15
15
  }
16
- function normalizePhoneNumber(input) {
17
- const trimmed = input.trim();
18
- if (trimmed.toLowerCase().startsWith("tel:")) {
19
- return trimmed;
20
- }
21
- const match = trimmed.match(/^[\s\+\-\(\)]*(\d[\d\s\-\(\)\.]*\d)[\s\-]*(x|ext\.?|extension)?[\s\-]*(\d+)?$/i);
22
- if (match) {
23
- const mainNumber = match[1].replace(/[\s\-\(\)\.]/g, "");
24
- const extension = match[3];
25
- const normalized = mainNumber.length >= 10 && !trimmed.startsWith("+") ? `+${mainNumber}` : mainNumber;
26
- const withExtension = extension ? `${normalized};ext=${extension}` : normalized;
27
- return `tel:${withExtension}`;
28
- }
29
- const cleaned = trimmed.replace(/[\s\-\(\)\.]/g, "");
30
- return `tel:${cleaned}`;
31
- }
32
- function normalizeEmail(input) {
33
- const trimmed = input.trim();
34
- if (trimmed.toLowerCase().startsWith("mailto:")) {
35
- return trimmed;
36
- }
37
- return `mailto:${trimmed}`;
38
- }
39
- function isEmail(input) {
40
- const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
41
- return emailRegex.test(input.trim());
42
- }
43
- function isPhoneNumber(input) {
44
- const trimmed = input.trim();
45
- if (trimmed.toLowerCase().startsWith("tel:")) {
46
- return true;
47
- }
48
- const phoneRegex = /^[\s\+\-\(\)]*\d[\d\s\-\(\)\.]*\d[\s\-]*(x|ext\.?|extension)?[\s\-]*\d*$/i;
49
- return phoneRegex.test(trimmed);
50
- }
51
- function isInternalUrl(href) {
52
- if (typeof window === "undefined") {
53
- return href.startsWith("/") && !href.startsWith("//");
54
- }
55
- const trimmed = href.trim();
56
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
57
- return true;
58
- }
59
- try {
60
- const url = new URL(trimmed, window.location.href);
61
- const currentOrigin = window.location.origin;
62
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
63
- return normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin);
64
- } catch {
65
- return false;
66
- }
67
- }
68
- function toRelativePath(href) {
69
- if (typeof window === "undefined") {
70
- return href;
71
- }
72
- const trimmed = href.trim();
73
- if (trimmed.startsWith("/") && !trimmed.startsWith("//")) {
74
- return trimmed;
75
- }
76
- try {
77
- const url = new URL(trimmed, window.location.href);
78
- const currentOrigin = window.location.origin;
79
- const normalizeOrigin = (origin) => origin.replace(/^(https?:\/\/)(www\.)?/, "$1");
80
- if (normalizeOrigin(url.origin) === normalizeOrigin(currentOrigin)) {
81
- return url.pathname + url.search + url.hash;
82
- }
83
- } catch {
84
- }
85
- return trimmed;
86
- }
87
- function useNavigation({
88
- href,
89
- onClick
90
- } = {}) {
91
- const linkType = React.useMemo(() => {
92
- if (!href || href.trim() === "") {
93
- return onClick ? "none" : "none";
94
- }
95
- const trimmed = href.trim();
96
- if (trimmed.toLowerCase().startsWith("mailto:") || isEmail(trimmed)) {
97
- return "mailto";
98
- }
99
- if (trimmed.toLowerCase().startsWith("tel:") || isPhoneNumber(trimmed)) {
100
- return "tel";
101
- }
102
- if (isInternalUrl(trimmed)) {
103
- return "internal";
104
- }
105
- try {
106
- new URL(trimmed, typeof window !== "undefined" ? window.location.href : "http://localhost");
107
- return "external";
108
- } catch {
109
- return "internal";
110
- }
111
- }, [href, onClick]);
112
- const normalizedHref = React.useMemo(() => {
113
- if (!href || href.trim() === "") {
114
- return void 0;
115
- }
116
- const trimmed = href.trim();
117
- switch (linkType) {
118
- case "tel":
119
- return normalizePhoneNumber(trimmed);
120
- case "mailto":
121
- return normalizeEmail(trimmed);
122
- case "internal":
123
- return toRelativePath(trimmed);
124
- case "external":
125
- return trimmed;
126
- default:
127
- return trimmed;
128
- }
129
- }, [href, linkType]);
130
- const target = React.useMemo(() => {
131
- switch (linkType) {
132
- case "external":
133
- return "_blank";
134
- case "internal":
135
- return "_self";
136
- case "mailto":
137
- case "tel":
138
- return void 0;
139
- default:
140
- return void 0;
141
- }
142
- }, [linkType]);
143
- const rel = React.useMemo(() => {
144
- if (linkType === "external") {
145
- return "noopener noreferrer";
146
- }
147
- return void 0;
148
- }, [linkType]);
149
- const isExternal = linkType === "external";
150
- const isInternal = linkType === "internal";
151
- const shouldUseRouter = isInternal && typeof normalizedHref === "string" && normalizedHref.startsWith("/");
152
- const handleClick = React.useCallback(
153
- (event) => {
154
- if (onClick) {
155
- try {
156
- onClick(event);
157
- } catch (error) {
158
- console.error("Error in user onClick handler:", error);
159
- }
160
- }
161
- if (event.defaultPrevented) {
162
- return;
163
- }
164
- if (shouldUseRouter && normalizedHref && event.button === 0 && // left-click only
165
- !event.metaKey && !event.altKey && !event.ctrlKey && !event.shiftKey) {
166
- if (typeof window !== "undefined") {
167
- const handler = window.__opensiteNavigationHandler;
168
- if (typeof handler === "function") {
169
- try {
170
- const handled = handler(normalizedHref, event.nativeEvent || event);
171
- if (handled !== false) {
172
- event.preventDefault();
173
- }
174
- } catch (error) {
175
- console.error("Error in navigation handler:", error);
176
- }
177
- }
178
- }
179
- }
180
- },
181
- [onClick, shouldUseRouter, normalizedHref]
182
- );
183
- return {
184
- linkType,
185
- normalizedHref,
186
- target,
187
- rel,
188
- isExternal,
189
- isInternal,
190
- shouldUseRouter,
191
- handleClick
192
- };
193
- }
194
- var baseStyles = [
195
- // Layout
196
- "inline-flex items-center justify-center gap-2 whitespace-nowrap shrink-0",
197
- // Typography - using CSS variables with sensible defaults
198
- "font-[var(--button-font-family,inherit)]",
199
- "font-[var(--button-font-weight,500)]",
200
- "tracking-[var(--button-letter-spacing,0)]",
201
- "leading-[var(--button-line-height,1.25)]",
202
- "[text-transform:var(--button-text-transform,none)]",
203
- "text-sm",
204
- // Border radius
205
- "rounded-[var(--button-radius,var(--radius,0.375rem))]",
206
- // Smooth transition - using [transition:...] to set full shorthand property (not just transition-property)
207
- "[transition:var(--button-transition,all_250ms_cubic-bezier(0.4,0,0.2,1))]",
208
- // Box shadow (master level) - using [box-shadow:...] for complex multi-value shadows
209
- "[box-shadow:var(--button-shadow,none)]",
210
- "hover:[box-shadow:var(--button-shadow-hover,var(--button-shadow,none))]",
211
- // Disabled state
212
- "disabled:pointer-events-none disabled:opacity-50",
213
- // SVG handling
214
- "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0",
215
- // Focus styles
216
- "outline-none focus-visible:border-ring focus-visible:ring-ring/50 focus-visible:ring-[3px]",
217
- // Invalid state
218
- "aria-invalid:ring-destructive/20 dark:aria-invalid:ring-destructive/40 aria-invalid:border-destructive"
219
- ].join(" ");
220
- var buttonVariants = cva(baseStyles, {
221
- variants: {
222
- variant: {
223
- // Default (Primary) variant - full customization
224
- default: [
225
- "bg-[var(--button-default-bg,hsl(var(--primary)))]",
226
- "text-[var(--button-default-fg,hsl(var(--primary-foreground)))]",
227
- "border-[length:var(--button-default-border-width,0px)]",
228
- "border-[color:var(--button-default-border,transparent)]",
229
- "[box-shadow:var(--button-default-shadow,var(--button-shadow,none))]",
230
- "hover:bg-[var(--button-default-hover-bg,hsl(var(--primary)/0.9))]",
231
- "hover:text-[var(--button-default-hover-fg,var(--button-default-fg,hsl(var(--primary-foreground))))]",
232
- "hover:border-[color:var(--button-default-hover-border,var(--button-default-border,transparent))]",
233
- "hover:[box-shadow:var(--button-default-shadow-hover,var(--button-shadow-hover,var(--button-default-shadow,var(--button-shadow,none))))]"
234
- ].join(" "),
235
- // Destructive variant - full customization
236
- destructive: [
237
- "bg-[var(--button-destructive-bg,hsl(var(--destructive)))]",
238
- "text-[var(--button-destructive-fg,white)]",
239
- "border-[length:var(--button-destructive-border-width,0px)]",
240
- "border-[color:var(--button-destructive-border,transparent)]",
241
- "[box-shadow:var(--button-destructive-shadow,var(--button-shadow,none))]",
242
- "hover:bg-[var(--button-destructive-hover-bg,hsl(var(--destructive)/0.9))]",
243
- "hover:text-[var(--button-destructive-hover-fg,var(--button-destructive-fg,white))]",
244
- "hover:border-[color:var(--button-destructive-hover-border,var(--button-destructive-border,transparent))]",
245
- "hover:[box-shadow:var(--button-destructive-shadow-hover,var(--button-shadow-hover,var(--button-destructive-shadow,var(--button-shadow,none))))]",
246
- "focus-visible:ring-destructive/20 dark:focus-visible:ring-destructive/40",
247
- "dark:bg-destructive/60"
248
- ].join(" "),
249
- // Outline variant - full customization with proper border handling
250
- outline: [
251
- "bg-[var(--button-outline-bg,hsl(var(--background)))]",
252
- "text-[var(--button-outline-fg,inherit)]",
253
- "border-[length:var(--button-outline-border-width,1px)]",
254
- "border-[color:var(--button-outline-border,hsl(var(--border)))]",
255
- "[box-shadow:var(--button-outline-shadow,var(--button-shadow,0_1px_2px_0_rgb(0_0_0/0.05)))]",
256
- "hover:bg-[var(--button-outline-hover-bg,hsl(var(--accent)))]",
257
- "hover:text-[var(--button-outline-hover-fg,hsl(var(--accent-foreground)))]",
258
- "hover:border-[color:var(--button-outline-hover-border,var(--button-outline-border,hsl(var(--border))))]",
259
- "hover:[box-shadow:var(--button-outline-shadow-hover,var(--button-shadow-hover,var(--button-outline-shadow,var(--button-shadow,none))))]",
260
- "dark:bg-input/30 dark:border-input dark:hover:bg-input/50"
261
- ].join(" "),
262
- // Secondary variant - full customization
263
- secondary: [
264
- "bg-[var(--button-secondary-bg,hsl(var(--secondary)))]",
265
- "text-[var(--button-secondary-fg,hsl(var(--secondary-foreground)))]",
266
- "border-[length:var(--button-secondary-border-width,0px)]",
267
- "border-[color:var(--button-secondary-border,transparent)]",
268
- "[box-shadow:var(--button-secondary-shadow,var(--button-shadow,none))]",
269
- "hover:bg-[var(--button-secondary-hover-bg,hsl(var(--secondary)/0.8))]",
270
- "hover:text-[var(--button-secondary-hover-fg,var(--button-secondary-fg,hsl(var(--secondary-foreground))))]",
271
- "hover:border-[color:var(--button-secondary-hover-border,var(--button-secondary-border,transparent))]",
272
- "hover:[box-shadow:var(--button-secondary-shadow-hover,var(--button-shadow-hover,var(--button-secondary-shadow,var(--button-shadow,none))))]"
273
- ].join(" "),
274
- // Ghost variant - full customization
275
- ghost: [
276
- "bg-[var(--button-ghost-bg,transparent)]",
277
- "text-[var(--button-ghost-fg,inherit)]",
278
- "border-[length:var(--button-ghost-border-width,0px)]",
279
- "border-[color:var(--button-ghost-border,transparent)]",
280
- "[box-shadow:var(--button-ghost-shadow,var(--button-shadow,none))]",
281
- "hover:bg-[var(--button-ghost-hover-bg,hsl(var(--accent)))]",
282
- "hover:text-[var(--button-ghost-hover-fg,hsl(var(--accent-foreground)))]",
283
- "hover:border-[color:var(--button-ghost-hover-border,var(--button-ghost-border,transparent))]",
284
- "hover:[box-shadow:var(--button-ghost-shadow-hover,var(--button-shadow-hover,var(--button-ghost-shadow,var(--button-shadow,none))))]",
285
- "dark:hover:bg-accent/50"
286
- ].join(" "),
287
- // Link variant - full customization
288
- link: [
289
- "bg-[var(--button-link-bg,transparent)]",
290
- "text-[var(--button-link-fg,hsl(var(--primary)))]",
291
- "border-[length:var(--button-link-border-width,0px)]",
292
- "border-[color:var(--button-link-border,transparent)]",
293
- "[box-shadow:var(--button-link-shadow,none)]",
294
- "hover:bg-[var(--button-link-hover-bg,transparent)]",
295
- "hover:text-[var(--button-link-hover-fg,var(--button-link-fg,hsl(var(--primary))))]",
296
- "hover:[box-shadow:var(--button-link-shadow-hover,none)]",
297
- "underline-offset-4 hover:underline"
298
- ].join(" ")
299
- },
300
- size: {
301
- default: [
302
- "h-[var(--button-height-md,2.25rem)]",
303
- "px-[var(--button-padding-x-md,1rem)]",
304
- "py-[var(--button-padding-y-md,0.5rem)]",
305
- "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
306
- ].join(" "),
307
- sm: [
308
- "h-[var(--button-height-sm,2rem)]",
309
- "px-[var(--button-padding-x-sm,0.75rem)]",
310
- "py-[var(--button-padding-y-sm,0.25rem)]",
311
- "gap-1.5",
312
- "has-[>svg]:px-[calc(var(--button-padding-x-sm,0.75rem)*0.83)]"
313
- ].join(" "),
314
- md: [
315
- "h-[var(--button-height-md,2.25rem)]",
316
- "px-[var(--button-padding-x-md,1rem)]",
317
- "py-[var(--button-padding-y-md,0.5rem)]",
318
- "has-[>svg]:px-[calc(var(--button-padding-x-md,1rem)*0.75)]"
319
- ].join(" "),
320
- lg: [
321
- "h-[var(--button-height-lg,2.5rem)]",
322
- "px-[var(--button-padding-x-lg,1.5rem)]",
323
- "py-[var(--button-padding-y-lg,0.5rem)]",
324
- "has-[>svg]:px-[calc(var(--button-padding-x-lg,1.5rem)*0.67)]"
325
- ].join(" "),
326
- icon: "size-[var(--button-height-md,2.25rem)]",
327
- "icon-sm": "size-[var(--button-height-sm,2rem)]",
328
- "icon-lg": "size-[var(--button-height-lg,2.5rem)]"
329
- }
330
- },
331
- defaultVariants: {
332
- variant: "default",
333
- size: "default"
334
- }
335
- });
336
- var Pressable = React.forwardRef(
337
- ({
338
- children,
339
- className,
340
- href,
341
- onClick,
342
- variant,
343
- size,
344
- asButton = false,
345
- fallbackComponentType = "span",
346
- componentType,
347
- "aria-label": ariaLabel,
348
- "aria-describedby": ariaDescribedby,
349
- id,
350
- ...props
351
- }, ref) => {
352
- const navigation = useNavigation({ href, onClick });
353
- const {
354
- normalizedHref,
355
- target,
356
- rel,
357
- linkType,
358
- isInternal,
359
- handleClick
360
- } = navigation;
361
- const shouldRenderLink = normalizedHref && linkType !== "none";
362
- const shouldRenderButton = !shouldRenderLink && onClick;
363
- const effectiveComponentType = componentType || (shouldRenderLink ? "a" : shouldRenderButton ? "button" : fallbackComponentType);
364
- const finalComponentType = isInternal && shouldRenderLink ? "a" : effectiveComponentType;
365
- const shouldApplyButtonStyles = asButton || variant || size;
366
- const combinedClassName = cn(
367
- shouldApplyButtonStyles && buttonVariants({ variant, size }),
368
- className
369
- );
370
- const dataProps = Object.fromEntries(
371
- Object.entries(props).filter(([key]) => key.startsWith("data-"))
372
- );
373
- const buttonDataAttributes = shouldApplyButtonStyles ? {
374
- "data-slot": "button",
375
- "data-variant": variant ?? "default",
376
- "data-size": size ?? "default"
377
- } : {};
378
- const commonProps = {
379
- className: combinedClassName,
380
- onClick: handleClick,
381
- "aria-label": ariaLabel,
382
- "aria-describedby": ariaDescribedby,
383
- id,
384
- ...dataProps,
385
- ...buttonDataAttributes
386
- };
387
- if (finalComponentType === "a" && shouldRenderLink) {
388
- return /* @__PURE__ */ jsx(
389
- "a",
390
- {
391
- ref,
392
- href: normalizedHref,
393
- target,
394
- rel,
395
- ...commonProps,
396
- ...props,
397
- children
398
- }
399
- );
400
- }
401
- if (finalComponentType === "button") {
402
- return /* @__PURE__ */ jsx(
403
- "button",
404
- {
405
- ref,
406
- type: props.type || "button",
407
- ...commonProps,
408
- ...props,
409
- children
410
- }
411
- );
412
- }
413
- if (finalComponentType === "div") {
414
- return /* @__PURE__ */ jsx(
415
- "div",
416
- {
417
- ref,
418
- ...commonProps,
419
- children
420
- }
421
- );
422
- }
423
- return /* @__PURE__ */ jsx(
424
- "span",
425
- {
426
- ref,
427
- ...commonProps,
428
- children
429
- }
430
- );
431
- }
432
- );
433
- Pressable.displayName = "Pressable";
434
- function Card({ className, ...props }) {
435
- return /* @__PURE__ */ jsx(
436
- "div",
437
- {
438
- "data-slot": "card",
439
- className: cn(
440
- "bg-card text-card-foreground flex flex-col gap-6 rounded-xl border py-6 shadow-sm",
441
- className
442
- ),
443
- ...props
444
- }
445
- );
446
- }
447
- function CardContent({ className, ...props }) {
448
- return /* @__PURE__ */ jsx(
449
- "div",
450
- {
451
- "data-slot": "card-content",
452
- className: cn("px-6", className),
453
- ...props
454
- }
455
- );
16
+ var DEFAULT_ICON_API_KEY = "au382bi7fsh96w9h9xlrnat2jglx";
17
+ function DynamicIcon({ apiKey, ...props }) {
18
+ return /* @__PURE__ */ jsx(Icon, { ...props, apiKey: apiKey ?? DEFAULT_ICON_API_KEY });
456
19
  }
457
20
  var maxWidthStyles = {
458
21
  sm: "max-w-screen-sm",
@@ -463,7 +26,7 @@ var maxWidthStyles = {
463
26
  "4xl": "max-w-[1536px]",
464
27
  full: "max-w-full"
465
28
  };
466
- var Container = React__default.forwardRef(
29
+ var Container = React3__default.forwardRef(
467
30
  ({ children, maxWidth = "xl", className, as = "div", ...props }, ref) => {
468
31
  const Component = as;
469
32
  return /* @__PURE__ */ jsx(
@@ -768,7 +331,7 @@ var spacingStyles = {
768
331
  };
769
332
  var predefinedSpacings = ["none", "sm", "md", "lg", "xl"];
770
333
  var isPredefinedSpacing = (spacing) => predefinedSpacings.includes(spacing);
771
- var Section = React__default.forwardRef(
334
+ var Section = React3__default.forwardRef(
772
335
  ({
773
336
  id,
774
337
  title,
@@ -829,6 +392,12 @@ var Section = React__default.forwardRef(
829
392
  }
830
393
  );
831
394
  Section.displayName = "Section";
395
+ var DEFAULT_STYLE_RULES = {
396
+ formContainer: "",
397
+ fieldsContainer: "",
398
+ fieldClassName: "",
399
+ formClassName: "space-y-4"
400
+ };
832
401
  var DEFAULT_FORM_FIELDS = [
833
402
  {
834
403
  name: "first_name",
@@ -873,207 +442,186 @@ var DEFAULT_FORM_FIELDS = [
873
442
  }
874
443
  ];
875
444
  function ContactImage({
445
+ eyebrow,
876
446
  heading,
877
447
  description,
878
- buttonText = "Submit",
448
+ buttonText = "Send Message",
879
449
  buttonIcon,
880
- actions,
881
- actionsSlot,
882
- formFields = DEFAULT_FORM_FIELDS,
883
- successMessage = "Thank you! Your message has been sent successfully.",
450
+ image,
451
+ contactOverlays,
452
+ contactOverlaysSlot,
453
+ formEngineSetup,
454
+ className,
455
+ containerClassName = "px-6 sm:px-6 md:px-8 lg:px-8",
456
+ contentClassName,
457
+ eyebrowClassName,
884
458
  headingClassName,
885
459
  descriptionClassName,
886
- cardClassName,
887
- cardContentClassName,
888
- formClassName,
889
- submitClassName,
890
- successMessageClassName,
891
- errorMessageClassName,
892
- backgroundImage,
460
+ imageClassName,
461
+ contactOverlaysClassName,
893
462
  background,
894
- optixFlowConfig,
895
- spacing = "none",
896
- className,
897
- containerClassName = "px-0 sm:px-0 lg:px-0 max-w-full relative z-10 h-screen w-screen flex justify-center items-center",
898
- contentClassName = "",
463
+ spacing = "py-16 md:py-32",
899
464
  pattern,
900
- patternOpacity = 0.1,
901
- formConfig,
902
- onSubmit,
903
- onSuccess,
904
- onError
465
+ patternOpacity,
466
+ optixFlowConfig
905
467
  }) {
906
- const {
907
- uploadTokens,
908
- uploadProgress,
909
- isUploading,
910
- uploadFiles,
911
- removeFile,
912
- resetUpload
913
- } = useFileUpload({ onError });
914
- const { form, submissionError, formMethod, resetSubmissionState } = useContactForm({
915
- formFields,
916
- formConfig,
917
- onSubmit,
918
- onSuccess: (data) => {
919
- resetUpload();
920
- onSuccess?.(data);
921
- },
922
- onError,
923
- resetOnSuccess: formConfig?.resetOnSuccess !== false,
924
- uploadTokens
925
- });
926
- const actionsContent = useMemo(() => {
927
- if (actionsSlot) return actionsSlot;
928
- if (actions && actions.length > 0) {
929
- return actions.map((action, index) => {
930
- const {
931
- label,
932
- icon,
933
- iconAfter,
934
- children,
935
- className: actionClassName,
936
- ...pressableProps
937
- } = action;
468
+ const formStyleRules = React3.useMemo(() => {
469
+ return {
470
+ formContainer: formEngineSetup?.formLayoutSettings?.styleRules?.formContainer ?? DEFAULT_STYLE_RULES.formContainer,
471
+ fieldsContainer: formEngineSetup?.formLayoutSettings?.styleRules?.fieldsContainer ?? DEFAULT_STYLE_RULES.fieldsContainer,
472
+ fieldClassName: formEngineSetup?.formLayoutSettings?.styleRules?.fieldClassName ?? DEFAULT_STYLE_RULES.fieldClassName,
473
+ formClassName: formEngineSetup?.formLayoutSettings?.styleRules?.formClassName ?? DEFAULT_STYLE_RULES.formClassName,
474
+ successMessageClassName: formEngineSetup?.formLayoutSettings?.styleRules?.successMessageClassName ?? DEFAULT_STYLE_RULES.successMessageClassName,
475
+ errorMessageClassName: formEngineSetup?.formLayoutSettings?.styleRules?.errorMessageClassName ?? DEFAULT_STYLE_RULES.errorMessageClassName
476
+ };
477
+ }, [formEngineSetup?.formLayoutSettings?.styleRules]);
478
+ const formFields = React3.useMemo(() => {
479
+ if (formEngineSetup?.fields && formEngineSetup.fields.length > 0) {
480
+ return formEngineSetup.fields;
481
+ }
482
+ return DEFAULT_FORM_FIELDS;
483
+ }, [formEngineSetup?.fields]);
484
+ const contactOverlaysContent = React3.useMemo(() => {
485
+ if (contactOverlaysSlot) return contactOverlaysSlot;
486
+ if (!contactOverlays || contactOverlays.length === 0) return null;
487
+ return /* @__PURE__ */ jsx("div", { className: cn("flex flex-col gap-3", contactOverlaysClassName), children: contactOverlays.map((item, index) => {
488
+ const content = /* @__PURE__ */ jsxs(
489
+ "div",
490
+ {
491
+ className: cn(
492
+ "rounded-2xl border border-white/10 bg-foreground/80 p-4 backdrop-blur-sm",
493
+ item.className
494
+ ),
495
+ children: [
496
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center gap-3", children: [
497
+ /* @__PURE__ */ jsx("div", { className: "flex size-fit p-2 items-center justify-center rounded-full bg-primary text-primary-foreground", children: /* @__PURE__ */ jsx(DynamicIcon, { name: item.icon, size: 18 }) }),
498
+ /* @__PURE__ */ jsxs("div", { children: [
499
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-bold uppercase tracking-[0.15em] text-background/70", children: item.label }),
500
+ /* @__PURE__ */ jsx("p", { className: "font-semibold text-background", children: item.title })
501
+ ] })
502
+ ] }),
503
+ item.description && /* @__PURE__ */ jsx("p", { className: "mt-2 text-sm text-background/80", children: item.description })
504
+ ]
505
+ }
506
+ );
507
+ if (item.href) {
938
508
  return /* @__PURE__ */ jsx(
939
- Pressable,
509
+ "a",
940
510
  {
941
- asButton: true,
942
- className: actionClassName,
943
- ...pressableProps,
944
- children: children ?? /* @__PURE__ */ jsxs(Fragment, { children: [
945
- icon,
946
- label,
947
- iconAfter
948
- ] })
511
+ href: item.href,
512
+ className: "block transition-transform hover:scale-[1.02]",
513
+ children: content
949
514
  },
950
515
  index
951
516
  );
952
- });
953
- }
954
- return null;
955
- }, [actionsSlot, actions]);
956
- const renderBackground = useMemo(() => {
957
- if (!backgroundImage) return null;
958
- return /* @__PURE__ */ jsxs("div", { className: "absolute inset-0", children: [
959
- /* @__PURE__ */ jsx(
960
- Img,
961
- {
962
- src: backgroundImage,
963
- alt: "Full screen background image",
964
- className: "h-full w-full object-cover",
965
- loading: "eager",
966
- optixFlowConfig
967
- }
968
- ),
969
- /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-b from-black/80 via-black/65 to-black/20" })
970
- ] });
971
- }, [backgroundImage, optixFlowConfig]);
972
- return /* @__PURE__ */ jsxs(
517
+ }
518
+ return /* @__PURE__ */ jsx("div", { children: content }, index);
519
+ }) });
520
+ }, [contactOverlaysSlot, contactOverlays, contactOverlaysClassName]);
521
+ return /* @__PURE__ */ jsx(
973
522
  Section,
974
523
  {
975
524
  background,
976
525
  spacing,
526
+ className,
527
+ containerClassName,
977
528
  pattern,
978
529
  patternOpacity,
979
- className: cn(
980
- "relative flex h-full min-h-screen w-screen items-center justify-center overflow-hidden bg-black pb-0 pt-0 md:pt-0 px-0",
981
- className
982
- ),
983
- containerClassName,
984
- children: [
985
- renderBackground,
986
- /* @__PURE__ */ jsx(
987
- "div",
988
- {
989
- className: cn(
990
- "flex flex-col gap-4 md:gap-6 px-6 pt-28 pb-6 md:pt-0 md:pb-0",
991
- "relative z-30 m-auto max-w-full md:max-w-md flex-col items-center justify-center text-center",
992
- contentClassName
993
- ),
994
- children: /* @__PURE__ */ jsx(Card, { className: cn("mx-auto max-w-xl", cardClassName), children: /* @__PURE__ */ jsxs(CardContent, { className: cn("p-6 lg:p-8", cardContentClassName), children: [
995
- heading && (typeof heading === "string" ? /* @__PURE__ */ jsx(
996
- "h2",
997
- {
998
- className: cn(
999
- "text-5xl md:text-6xl lg:text-7xl text-card-foreground text-shadow-2xl font-semibold",
1000
- headingClassName
1001
- ),
1002
- children: heading
1003
- }
1004
- ) : heading),
1005
- description && (typeof description === "string" ? /* @__PURE__ */ jsx(
1006
- "p",
1007
- {
1008
- className: cn(
1009
- "text-center text-base text-balance text-card-foreground text-shadow-2xl",
1010
- descriptionClassName
530
+ children: /* @__PURE__ */ jsxs(
531
+ "div",
532
+ {
533
+ className: cn(
534
+ "grid grid-cols-1 items-center gap-12 lg:grid-cols-2",
535
+ contentClassName
536
+ ),
537
+ children: [
538
+ image && /* @__PURE__ */ jsx(
539
+ motion.div,
540
+ {
541
+ initial: { opacity: 0, x: -20 },
542
+ whileInView: { opacity: 1, x: 0 },
543
+ viewport: { once: true, margin: "-50px" },
544
+ transition: { duration: 0.5 },
545
+ className: "order-2 lg:order-1",
546
+ children: /* @__PURE__ */ jsxs("div", { className: "relative overflow-hidden rounded-3xl border border-white/10 shadow-2xl", children: [
547
+ /* @__PURE__ */ jsx(
548
+ Img,
549
+ {
550
+ src: image.src,
551
+ alt: image.alt,
552
+ className: cn("h-full w-full object-cover", imageClassName),
553
+ optixFlowConfig
554
+ }
1011
555
  ),
1012
- children: description
1013
- }
1014
- ) : description),
1015
- /* @__PURE__ */ jsxs(
1016
- Form,
1017
- {
1018
- form,
1019
- notificationConfig: {
1020
- submissionError,
1021
- successMessage
1022
- },
1023
- styleConfig: {
1024
- formClassName: cn("space-y-4", formClassName),
1025
- successMessageClassName,
1026
- errorMessageClassName
1027
- },
1028
- formConfig: {
1029
- endpoint: formConfig?.endpoint,
1030
- method: formMethod,
1031
- submissionConfig: formConfig?.submissionConfig
1032
- },
1033
- onNewSubmission: () => {
1034
- resetUpload();
1035
- resetSubmissionState();
1036
- },
1037
- children: [
1038
- /* @__PURE__ */ jsx("div", { className: "grid grid-cols-12 gap-6", children: formFields.map((field) => /* @__PURE__ */ jsx(
1039
- "div",
1040
- {
1041
- className: getColumnSpanClass(field.columnSpan),
1042
- children: /* @__PURE__ */ jsx(
1043
- DynamicFormField,
1044
- {
1045
- field,
1046
- uploadProgress,
1047
- onFileUpload: uploadFiles,
1048
- onFileRemove: removeFile,
1049
- isUploading
1050
- }
1051
- )
556
+ /* @__PURE__ */ jsx("div", { className: "absolute inset-0 bg-linear-to-tr from-black/70 via-transparent to-transparent" }),
557
+ contactOverlaysContent && /* @__PURE__ */ jsx("div", { className: "absolute bottom-6 left-6 right-6", children: contactOverlaysContent })
558
+ ] })
559
+ }
560
+ ),
561
+ /* @__PURE__ */ jsxs(
562
+ motion.div,
563
+ {
564
+ initial: { opacity: 0, x: 20 },
565
+ whileInView: { opacity: 1, x: 0 },
566
+ viewport: { once: true, margin: "-50px" },
567
+ transition: { duration: 0.5 },
568
+ className: "order-1 lg:order-2",
569
+ children: [
570
+ eyebrow && (typeof eyebrow === "string" ? /* @__PURE__ */ jsx(
571
+ "p",
572
+ {
573
+ className: cn(
574
+ "text-sm font-semibold uppercase tracking-[0.2em] text-muted-foreground",
575
+ eyebrowClassName
576
+ ),
577
+ children: eyebrow
578
+ }
579
+ ) : /* @__PURE__ */ jsx("div", { className: eyebrowClassName, children: eyebrow })),
580
+ heading && (typeof heading === "string" ? /* @__PURE__ */ jsx(
581
+ "h2",
582
+ {
583
+ className: cn(
584
+ "mt-2 text-3xl font-bold md:text-4xl lg:text-5xl",
585
+ headingClassName
586
+ ),
587
+ children: heading
588
+ }
589
+ ) : /* @__PURE__ */ jsx("div", { className: cn("mt-2", headingClassName), children: heading })),
590
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx(
591
+ "p",
592
+ {
593
+ className: cn(
594
+ "mt-4 text-lg text-muted-foreground",
595
+ descriptionClassName
596
+ ),
597
+ children: description
598
+ }
599
+ ) : /* @__PURE__ */ jsx("div", { className: cn("mt-4", descriptionClassName), children: description })),
600
+ /* @__PURE__ */ jsx("div", { className: "mt-8", children: formEngineSetup ? /* @__PURE__ */ jsx(
601
+ FormEngine,
602
+ {
603
+ ...formEngineSetup,
604
+ formLayoutSettings: {
605
+ ...formEngineSetup.formLayoutSettings,
606
+ formLayout: "standard",
607
+ submitButtonSetup: {
608
+ ...formEngineSetup.formLayoutSettings?.submitButtonSetup,
609
+ submitLabel: /* @__PURE__ */ jsxs(Fragment, { children: [
610
+ buttonIcon,
611
+ buttonText
612
+ ] })
613
+ },
614
+ styleRules: formStyleRules
1052
615
  },
1053
- field.name
1054
- )) }),
1055
- actionsSlot || actions && actions.length > 0 ? actionsContent : /* @__PURE__ */ jsxs(
1056
- Pressable,
1057
- {
1058
- componentType: "button",
1059
- type: "submit",
1060
- className: cn("w-full", submitClassName),
1061
- size: "lg",
1062
- asButton: true,
1063
- disabled: form.isSubmitting,
1064
- children: [
1065
- buttonIcon,
1066
- buttonText
1067
- ]
1068
- }
1069
- )
1070
- ]
1071
- }
1072
- )
1073
- ] }) })
1074
- }
1075
- )
1076
- ]
616
+ fields: formFields
617
+ }
618
+ ) : null })
619
+ ]
620
+ }
621
+ )
622
+ ]
623
+ }
624
+ )
1077
625
  }
1078
626
  );
1079
627
  }