@opensite/ui 2.3.3 → 2.3.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.
@@ -1,17 +1,16 @@
1
1
  "use client";
2
2
  'use strict';
3
3
 
4
- var forms = require('@page-speed/forms');
4
+ var React = require('react');
5
5
  var clsx = require('clsx');
6
6
  var tailwindMerge = require('tailwind-merge');
7
7
  var img = require('@page-speed/img');
8
8
  var icon = require('@page-speed/icon');
9
9
  var jsxRuntime = require('react/jsx-runtime');
10
- var React = require('react');
11
10
  var classVarianceAuthority = require('class-variance-authority');
12
11
  var usePlatformFromUrl = require('@opensite/hooks/usePlatformFromUrl');
13
- var integration = require('@page-speed/forms/integration');
14
12
  var SeparatorPrimitive = require('@radix-ui/react-separator');
13
+ var integration = require('@page-speed/forms/integration');
15
14
 
16
15
  function _interopNamespace(e) {
17
16
  if (e && e.__esModule) return e;
@@ -1586,9 +1585,24 @@ var Section = React__namespace.default.forwardRef(
1586
1585
  }
1587
1586
  );
1588
1587
  Section.displayName = "Section";
1588
+ var DEFAULT_STYLE_RULES = {
1589
+ formContainer: "flex items-stretch w-full",
1590
+ fieldsContainer: "",
1591
+ fieldClassName: "",
1592
+ formClassName: ""
1593
+ };
1594
+ var DEFAULT_FORM_FIELDS = [
1595
+ {
1596
+ name: "email",
1597
+ type: "email",
1598
+ label: "Email Address",
1599
+ placeholder: "Enter your email",
1600
+ required: true,
1601
+ columnSpan: 12
1602
+ }
1603
+ ];
1589
1604
  function FooterSplitImageAccordion({
1590
1605
  newsletterTitle,
1591
- emailPlaceholder,
1592
1606
  footerLinks,
1593
1607
  socialLinks,
1594
1608
  paymentPlatforms,
@@ -1597,7 +1611,7 @@ function FooterSplitImageAccordion({
1597
1611
  copyright,
1598
1612
  background,
1599
1613
  containerClassName = "w-screen px-0 sm:px-0 lg:px-0 max-w-screen relative z-10",
1600
- spacing = "py-6 md:py-0",
1614
+ spacing = "none",
1601
1615
  pattern,
1602
1616
  patternOpacity,
1603
1617
  className,
@@ -1619,51 +1633,46 @@ function FooterSplitImageAccordion({
1619
1633
  copyrightClassName,
1620
1634
  submenuLinksClassName,
1621
1635
  optixFlowConfig,
1622
- formConfig,
1623
- onSubmit,
1624
- onSuccess,
1625
- onError
1636
+ formEngineSetup,
1637
+ buttonAction,
1638
+ formSlot
1626
1639
  }) {
1627
- const form = forms.useForm({
1628
- initialValues: {
1629
- email: ""
1630
- },
1631
- validationSchema: {
1632
- email: (value) => {
1633
- if (!value) return "Email is required";
1634
- if (!integration.isValidEmail(value)) return "Please enter a valid email address";
1635
- return void 0;
1636
- }
1637
- },
1638
- onSubmit: async (values, helpers) => {
1639
- const shouldAutoSubmit = Boolean(formConfig?.endpoint);
1640
- if (!shouldAutoSubmit && !onSubmit) {
1641
- return;
1642
- }
1643
- try {
1644
- let result;
1645
- if (shouldAutoSubmit) {
1646
- result = await integration.submitPageSpeedForm(values, formConfig);
1647
- }
1648
- if (onSubmit) {
1649
- await onSubmit(values.email);
1650
- }
1651
- if (shouldAutoSubmit || onSubmit) {
1652
- if (formConfig?.resetOnSuccess !== false) {
1653
- helpers.resetForm();
1640
+ const renderForm = React__namespace.useMemo(() => {
1641
+ if (formSlot) return formSlot;
1642
+ if (!formEngineSetup) return null;
1643
+ const defaultButtonAction = {
1644
+ label: "",
1645
+ variant: "default",
1646
+ icon: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1647
+ };
1648
+ const action = buttonAction || defaultButtonAction;
1649
+ return /* @__PURE__ */ jsxRuntime.jsx(
1650
+ integration.FormEngine,
1651
+ {
1652
+ formEngineSetup: {
1653
+ ...formEngineSetup,
1654
+ formLayoutSettings: {
1655
+ ...formEngineSetup.formLayoutSettings,
1656
+ formLayout: "button-group",
1657
+ buttonGroupSetup: {
1658
+ ...formEngineSetup.formLayoutSettings?.buttonGroupSetup,
1659
+ size: "default",
1660
+ submitLabel: action.icon || action.label,
1661
+ submitVariant: action.variant || "default"
1662
+ }
1654
1663
  }
1655
- onSuccess?.(result);
1656
- }
1657
- } catch (error) {
1658
- if (error instanceof integration.PageSpeedFormSubmissionError && error.formErrors) {
1659
- helpers.setErrors(error.formErrors);
1664
+ },
1665
+ defaultFields: DEFAULT_FORM_FIELDS,
1666
+ defaultStyleRules: {
1667
+ ...DEFAULT_STYLE_RULES,
1668
+ formContainer: cn(
1669
+ DEFAULT_STYLE_RULES.formContainer,
1670
+ newsletterFormClassName
1671
+ )
1660
1672
  }
1661
- onError?.(error);
1662
- throw error;
1663
1673
  }
1664
- }
1665
- });
1666
- const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
1674
+ );
1675
+ }, [formSlot, formEngineSetup, buttonAction, newsletterFormClassName]);
1667
1676
  return /* @__PURE__ */ jsxRuntime.jsx(
1668
1677
  Section,
1669
1678
  {
@@ -1704,40 +1713,7 @@ function FooterSplitImageAccordion({
1704
1713
  children: newsletterTitle
1705
1714
  }
1706
1715
  ),
1707
- /* @__PURE__ */ jsxRuntime.jsxs(
1708
- forms.Form,
1709
- {
1710
- form,
1711
- action: formConfig?.endpoint,
1712
- method: formMethod,
1713
- className: cn("flex items-stretch", newsletterFormClassName),
1714
- children: [
1715
- /* @__PURE__ */ jsxRuntime.jsx(forms.Field, { name: "email", className: "flex-1", children: ({ field }) => /* @__PURE__ */ jsxRuntime.jsx(
1716
- "input",
1717
- {
1718
- ...field,
1719
- type: "email",
1720
- placeholder: emailPlaceholder,
1721
- className: "flex h-10 w-full rounded-l-md rounded-r-none border border-r-0 border-input px-3 py-2 text-sm ring-offset-background placeholder:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1722
- "aria-label": emailPlaceholder
1723
- }
1724
- ) }),
1725
- /* @__PURE__ */ jsxRuntime.jsx(
1726
- Pressable,
1727
- {
1728
- componentType: "button",
1729
- type: "submit",
1730
- variant: "default",
1731
- size: "icon",
1732
- asButton: true,
1733
- className: "rounded-l-none rounded-r-md shrink-0 h-10",
1734
- disabled: form.isSubmitting,
1735
- children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1736
- }
1737
- )
1738
- ]
1739
- }
1740
- ),
1716
+ renderForm,
1741
1717
  socialLinks && socialLinks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1742
1718
  "ul",
1743
1719
  {
@@ -1762,19 +1738,31 @@ function FooterSplitImageAccordion({
1762
1738
  footerData.logo && /* @__PURE__ */ jsxRuntime.jsx(
1763
1739
  FooterLogo,
1764
1740
  {
1765
- logo: { ...footerData.logo, url: footerData.logoUrl },
1741
+ logo: { ...footerData.logo, url: footerData.logo.url || "/" },
1766
1742
  logoClassName: cn("inline-block max-w-60", logoClassName),
1767
1743
  optixFlowConfig
1768
1744
  }
1769
1745
  ),
1770
- footerData.title && /* @__PURE__ */ jsxRuntime.jsx(
1746
+ footerData.heading && /* @__PURE__ */ jsxRuntime.jsx(
1771
1747
  "h4",
1772
1748
  {
1773
- className: cn("text-xl font-semibold", brandTitleClassName),
1774
- children: footerData.title
1749
+ className: cn(
1750
+ "text-xl font-semibold text-pretty",
1751
+ brandTitleClassName
1752
+ ),
1753
+ children: footerData.heading
1775
1754
  }
1776
1755
  ),
1777
- footerData.description && /* @__PURE__ */ jsxRuntime.jsx("p", { className: cn("opacity-80", brandDescriptionClassName), children: footerData.description })
1756
+ footerData.description && /* @__PURE__ */ jsxRuntime.jsx(
1757
+ "p",
1758
+ {
1759
+ className: cn(
1760
+ "opacity-80 text-balance",
1761
+ brandDescriptionClassName
1762
+ ),
1763
+ children: footerData.description
1764
+ }
1765
+ )
1778
1766
  ] }),
1779
1767
  footerLinks && footerLinks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx(
1780
1768
  "div",
@@ -1,10 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { PaymentPlatformName } from './payment-platform-icon.cjs';
4
- import { PageSpeedFormConfig } from '@page-speed/forms/integration';
5
4
  import { f as SectionBackground, g as SectionSpacing, t as PatternName } from './community-initiatives-BFOWojwp.cjs';
6
- import { O as OptixFlowConfig } from './blocks-tmd_MRJv.cjs';
5
+ import { O as OptixFlowConfig, A as ActionConfig } from './blocks-tmd_MRJv.cjs';
7
6
  import { F as FooterSocialLink } from './types-Cs1jk79n.cjs';
7
+ import { FormEngineProps } from '@page-speed/forms/integration';
8
8
  import 'class-variance-authority';
9
9
  import './button-variants-8mtEHxev.cjs';
10
10
  import 'class-variance-authority/types';
@@ -40,29 +40,26 @@ interface FooterSplitImageAccordionData {
40
40
  /** Hero image configuration */
41
41
  image: {
42
42
  src: string;
43
- alt: string;
43
+ alt?: string;
44
44
  };
45
45
  /** Logo configuration with light/dark variants */
46
- logo: {
47
- light: string;
48
- dark: string;
46
+ logo?: {
47
+ src: string;
48
+ /** Logo link URL */
49
+ url?: string;
50
+ /** Brand title */
51
+ alt?: string;
49
52
  };
50
- /** Logo link URL */
51
- logoUrl: string;
52
- /** Brand title */
53
- title: string;
53
+ /** Footer heading */
54
+ heading?: string;
54
55
  /** Brand description */
55
- description: string;
56
+ description?: string;
56
57
  }
57
58
  interface FooterSplitImageAccordionProps {
58
59
  /**
59
60
  * Newsletter title
60
61
  */
61
62
  newsletterTitle?: React.ReactNode;
62
- /**
63
- * Email input placeholder text
64
- */
65
- emailPlaceholder?: string;
66
63
  /**
67
64
  * Footer link sections
68
65
  */
@@ -184,21 +181,17 @@ interface FooterSplitImageAccordionProps {
184
181
  */
185
182
  optixFlowConfig?: OptixFlowConfig;
186
183
  /**
187
- * Optional form submission configuration for newsletter signup.
184
+ * Full form engine setup and props
188
185
  */
189
- formConfig?: PageSpeedFormConfig;
186
+ formEngineSetup?: FormEngineProps;
190
187
  /**
191
- * Optional custom submission handler for newsletter signup.
188
+ * Submit button configuration
192
189
  */
193
- onSubmit?: (email: string) => void | Promise<void>;
190
+ buttonAction?: ActionConfig;
194
191
  /**
195
- * Optional success callback invoked after successful submission.
192
+ * Custom slot for the form (overrides form props)
196
193
  */
197
- onSuccess?: (data: unknown) => void;
198
- /**
199
- * Optional error callback invoked if submission fails.
200
- */
201
- onError?: (error: Error) => void;
194
+ formSlot?: React.ReactNode;
202
195
  }
203
196
  /**
204
197
  * Footer Split Image Accordion - A split-layout footer with large image,
@@ -208,10 +201,16 @@ interface FooterSplitImageAccordionProps {
208
201
  * Key features: Large hero image, organized link sections, payment icons.
209
202
  * Best for: E-commerce sites, fashion brands, lifestyle businesses.
210
203
  *
204
+ * The newsletter form is powered by `FormEngine` from `@page-speed/forms/integration`,
205
+ * which handles validation, submission, error handling, and success states.
206
+ *
211
207
  * @example
212
208
  * ```tsx
213
209
  * <FooterSplitImageAccordion
214
210
  * newsletterTitle="Get updates and save 20%"
211
+ * formEngineSetup={{
212
+ * formConfig: { endpoint: "/api/subscribe", format: "json" },
213
+ * }}
215
214
  * footerLinks={[
216
215
  * { title: "Collections", id: "collections", items: [...] },
217
216
  * ]}
@@ -223,6 +222,6 @@ interface FooterSplitImageAccordionProps {
223
222
  * />
224
223
  * ```
225
224
  */
226
- declare function FooterSplitImageAccordion({ newsletterTitle, emailPlaceholder, footerLinks, socialLinks, paymentPlatforms, submenuLinks, footerData, copyright, background, containerClassName, spacing, pattern, patternOpacity, className, gridClassName, imageColumnClassName, imageClassName, contentColumnClassName, newsletterSectionClassName, newsletterTitleClassName, newsletterFormClassName, socialLinksClassName, brandSectionClassName, logoClassName, brandTitleClassName, brandDescriptionClassName, linksGridClassName, paymentMethodsClassName, bottomClassName, copyrightClassName, submenuLinksClassName, optixFlowConfig, formConfig, onSubmit, onSuccess, onError, }: FooterSplitImageAccordionProps): react_jsx_runtime.JSX.Element;
225
+ declare function FooterSplitImageAccordion({ newsletterTitle, footerLinks, socialLinks, paymentPlatforms, submenuLinks, footerData, copyright, background, containerClassName, spacing, pattern, patternOpacity, className, gridClassName, imageColumnClassName, imageClassName, contentColumnClassName, newsletterSectionClassName, newsletterTitleClassName, newsletterFormClassName, socialLinksClassName, brandSectionClassName, logoClassName, brandTitleClassName, brandDescriptionClassName, linksGridClassName, paymentMethodsClassName, bottomClassName, copyrightClassName, submenuLinksClassName, optixFlowConfig, formEngineSetup, buttonAction, formSlot, }: FooterSplitImageAccordionProps): react_jsx_runtime.JSX.Element;
227
226
 
228
227
  export { FooterSocialLink, FooterSplitImageAccordion, type FooterSplitImageAccordionData, type FooterSplitImageAccordionLink, type FooterSplitImageAccordionProps, type FooterSplitImageAccordionSection, PaymentPlatformName };
@@ -1,10 +1,10 @@
1
1
  import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as React from 'react';
3
3
  import { PaymentPlatformName } from './payment-platform-icon.js';
4
- import { PageSpeedFormConfig } from '@page-speed/forms/integration';
5
4
  import { f as SectionBackground, g as SectionSpacing, t as PatternName } from './community-initiatives-CUqiRX_E.js';
6
- import { O as OptixFlowConfig } from './blocks-DRE-f6cS.js';
5
+ import { O as OptixFlowConfig, A as ActionConfig } from './blocks-DRE-f6cS.js';
7
6
  import { F as FooterSocialLink } from './types-Cs1jk79n.js';
7
+ import { FormEngineProps } from '@page-speed/forms/integration';
8
8
  import 'class-variance-authority';
9
9
  import './button-variants-8mtEHxev.js';
10
10
  import 'class-variance-authority/types';
@@ -40,29 +40,26 @@ interface FooterSplitImageAccordionData {
40
40
  /** Hero image configuration */
41
41
  image: {
42
42
  src: string;
43
- alt: string;
43
+ alt?: string;
44
44
  };
45
45
  /** Logo configuration with light/dark variants */
46
- logo: {
47
- light: string;
48
- dark: string;
46
+ logo?: {
47
+ src: string;
48
+ /** Logo link URL */
49
+ url?: string;
50
+ /** Brand title */
51
+ alt?: string;
49
52
  };
50
- /** Logo link URL */
51
- logoUrl: string;
52
- /** Brand title */
53
- title: string;
53
+ /** Footer heading */
54
+ heading?: string;
54
55
  /** Brand description */
55
- description: string;
56
+ description?: string;
56
57
  }
57
58
  interface FooterSplitImageAccordionProps {
58
59
  /**
59
60
  * Newsletter title
60
61
  */
61
62
  newsletterTitle?: React.ReactNode;
62
- /**
63
- * Email input placeholder text
64
- */
65
- emailPlaceholder?: string;
66
63
  /**
67
64
  * Footer link sections
68
65
  */
@@ -184,21 +181,17 @@ interface FooterSplitImageAccordionProps {
184
181
  */
185
182
  optixFlowConfig?: OptixFlowConfig;
186
183
  /**
187
- * Optional form submission configuration for newsletter signup.
184
+ * Full form engine setup and props
188
185
  */
189
- formConfig?: PageSpeedFormConfig;
186
+ formEngineSetup?: FormEngineProps;
190
187
  /**
191
- * Optional custom submission handler for newsletter signup.
188
+ * Submit button configuration
192
189
  */
193
- onSubmit?: (email: string) => void | Promise<void>;
190
+ buttonAction?: ActionConfig;
194
191
  /**
195
- * Optional success callback invoked after successful submission.
192
+ * Custom slot for the form (overrides form props)
196
193
  */
197
- onSuccess?: (data: unknown) => void;
198
- /**
199
- * Optional error callback invoked if submission fails.
200
- */
201
- onError?: (error: Error) => void;
194
+ formSlot?: React.ReactNode;
202
195
  }
203
196
  /**
204
197
  * Footer Split Image Accordion - A split-layout footer with large image,
@@ -208,10 +201,16 @@ interface FooterSplitImageAccordionProps {
208
201
  * Key features: Large hero image, organized link sections, payment icons.
209
202
  * Best for: E-commerce sites, fashion brands, lifestyle businesses.
210
203
  *
204
+ * The newsletter form is powered by `FormEngine` from `@page-speed/forms/integration`,
205
+ * which handles validation, submission, error handling, and success states.
206
+ *
211
207
  * @example
212
208
  * ```tsx
213
209
  * <FooterSplitImageAccordion
214
210
  * newsletterTitle="Get updates and save 20%"
211
+ * formEngineSetup={{
212
+ * formConfig: { endpoint: "/api/subscribe", format: "json" },
213
+ * }}
215
214
  * footerLinks={[
216
215
  * { title: "Collections", id: "collections", items: [...] },
217
216
  * ]}
@@ -223,6 +222,6 @@ interface FooterSplitImageAccordionProps {
223
222
  * />
224
223
  * ```
225
224
  */
226
- declare function FooterSplitImageAccordion({ newsletterTitle, emailPlaceholder, footerLinks, socialLinks, paymentPlatforms, submenuLinks, footerData, copyright, background, containerClassName, spacing, pattern, patternOpacity, className, gridClassName, imageColumnClassName, imageClassName, contentColumnClassName, newsletterSectionClassName, newsletterTitleClassName, newsletterFormClassName, socialLinksClassName, brandSectionClassName, logoClassName, brandTitleClassName, brandDescriptionClassName, linksGridClassName, paymentMethodsClassName, bottomClassName, copyrightClassName, submenuLinksClassName, optixFlowConfig, formConfig, onSubmit, onSuccess, onError, }: FooterSplitImageAccordionProps): react_jsx_runtime.JSX.Element;
225
+ declare function FooterSplitImageAccordion({ newsletterTitle, footerLinks, socialLinks, paymentPlatforms, submenuLinks, footerData, copyright, background, containerClassName, spacing, pattern, patternOpacity, className, gridClassName, imageColumnClassName, imageClassName, contentColumnClassName, newsletterSectionClassName, newsletterTitleClassName, newsletterFormClassName, socialLinksClassName, brandSectionClassName, logoClassName, brandTitleClassName, brandDescriptionClassName, linksGridClassName, paymentMethodsClassName, bottomClassName, copyrightClassName, submenuLinksClassName, optixFlowConfig, formEngineSetup, buttonAction, formSlot, }: FooterSplitImageAccordionProps): react_jsx_runtime.JSX.Element;
227
226
 
228
227
  export { FooterSocialLink, FooterSplitImageAccordion, type FooterSplitImageAccordionData, type FooterSplitImageAccordionLink, type FooterSplitImageAccordionProps, type FooterSplitImageAccordionSection, PaymentPlatformName };
@@ -1,16 +1,15 @@
1
1
  "use client";
2
- import { useForm, Form, Field } from '@page-speed/forms';
2
+ import * as React from 'react';
3
+ import React__default, { useMemo } from 'react';
3
4
  import { clsx } from 'clsx';
4
5
  import { twMerge } from 'tailwind-merge';
5
6
  import { Img } from '@page-speed/img';
6
7
  import { Icon } from '@page-speed/icon';
7
8
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
- import * as React from 'react';
9
- import React__default, { useMemo } from 'react';
10
9
  import { cva } from 'class-variance-authority';
11
10
  import { usePlatformFromUrl } from '@opensite/hooks/usePlatformFromUrl';
12
- import { submitPageSpeedForm, PageSpeedFormSubmissionError, isValidEmail } from '@page-speed/forms/integration';
13
11
  import * as SeparatorPrimitive from '@radix-ui/react-separator';
12
+ import { FormEngine } from '@page-speed/forms/integration';
14
13
 
15
14
  // components/blocks/footers/footer-split-image-accordion.tsx
16
15
  function cn(...inputs) {
@@ -1564,9 +1563,24 @@ var Section = React__default.forwardRef(
1564
1563
  }
1565
1564
  );
1566
1565
  Section.displayName = "Section";
1566
+ var DEFAULT_STYLE_RULES = {
1567
+ formContainer: "flex items-stretch w-full",
1568
+ fieldsContainer: "",
1569
+ fieldClassName: "",
1570
+ formClassName: ""
1571
+ };
1572
+ var DEFAULT_FORM_FIELDS = [
1573
+ {
1574
+ name: "email",
1575
+ type: "email",
1576
+ label: "Email Address",
1577
+ placeholder: "Enter your email",
1578
+ required: true,
1579
+ columnSpan: 12
1580
+ }
1581
+ ];
1567
1582
  function FooterSplitImageAccordion({
1568
1583
  newsletterTitle,
1569
- emailPlaceholder,
1570
1584
  footerLinks,
1571
1585
  socialLinks,
1572
1586
  paymentPlatforms,
@@ -1575,7 +1589,7 @@ function FooterSplitImageAccordion({
1575
1589
  copyright,
1576
1590
  background,
1577
1591
  containerClassName = "w-screen px-0 sm:px-0 lg:px-0 max-w-screen relative z-10",
1578
- spacing = "py-6 md:py-0",
1592
+ spacing = "none",
1579
1593
  pattern,
1580
1594
  patternOpacity,
1581
1595
  className,
@@ -1597,51 +1611,46 @@ function FooterSplitImageAccordion({
1597
1611
  copyrightClassName,
1598
1612
  submenuLinksClassName,
1599
1613
  optixFlowConfig,
1600
- formConfig,
1601
- onSubmit,
1602
- onSuccess,
1603
- onError
1614
+ formEngineSetup,
1615
+ buttonAction,
1616
+ formSlot
1604
1617
  }) {
1605
- const form = useForm({
1606
- initialValues: {
1607
- email: ""
1608
- },
1609
- validationSchema: {
1610
- email: (value) => {
1611
- if (!value) return "Email is required";
1612
- if (!isValidEmail(value)) return "Please enter a valid email address";
1613
- return void 0;
1614
- }
1615
- },
1616
- onSubmit: async (values, helpers) => {
1617
- const shouldAutoSubmit = Boolean(formConfig?.endpoint);
1618
- if (!shouldAutoSubmit && !onSubmit) {
1619
- return;
1620
- }
1621
- try {
1622
- let result;
1623
- if (shouldAutoSubmit) {
1624
- result = await submitPageSpeedForm(values, formConfig);
1625
- }
1626
- if (onSubmit) {
1627
- await onSubmit(values.email);
1628
- }
1629
- if (shouldAutoSubmit || onSubmit) {
1630
- if (formConfig?.resetOnSuccess !== false) {
1631
- helpers.resetForm();
1618
+ const renderForm = React.useMemo(() => {
1619
+ if (formSlot) return formSlot;
1620
+ if (!formEngineSetup) return null;
1621
+ const defaultButtonAction = {
1622
+ label: "",
1623
+ variant: "default",
1624
+ icon: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1625
+ };
1626
+ const action = buttonAction || defaultButtonAction;
1627
+ return /* @__PURE__ */ jsx(
1628
+ FormEngine,
1629
+ {
1630
+ formEngineSetup: {
1631
+ ...formEngineSetup,
1632
+ formLayoutSettings: {
1633
+ ...formEngineSetup.formLayoutSettings,
1634
+ formLayout: "button-group",
1635
+ buttonGroupSetup: {
1636
+ ...formEngineSetup.formLayoutSettings?.buttonGroupSetup,
1637
+ size: "default",
1638
+ submitLabel: action.icon || action.label,
1639
+ submitVariant: action.variant || "default"
1640
+ }
1632
1641
  }
1633
- onSuccess?.(result);
1634
- }
1635
- } catch (error) {
1636
- if (error instanceof PageSpeedFormSubmissionError && error.formErrors) {
1637
- helpers.setErrors(error.formErrors);
1642
+ },
1643
+ defaultFields: DEFAULT_FORM_FIELDS,
1644
+ defaultStyleRules: {
1645
+ ...DEFAULT_STYLE_RULES,
1646
+ formContainer: cn(
1647
+ DEFAULT_STYLE_RULES.formContainer,
1648
+ newsletterFormClassName
1649
+ )
1638
1650
  }
1639
- onError?.(error);
1640
- throw error;
1641
1651
  }
1642
- }
1643
- });
1644
- const formMethod = formConfig?.method?.toLowerCase() === "get" ? "get" : "post";
1652
+ );
1653
+ }, [formSlot, formEngineSetup, buttonAction, newsletterFormClassName]);
1645
1654
  return /* @__PURE__ */ jsx(
1646
1655
  Section,
1647
1656
  {
@@ -1682,40 +1691,7 @@ function FooterSplitImageAccordion({
1682
1691
  children: newsletterTitle
1683
1692
  }
1684
1693
  ),
1685
- /* @__PURE__ */ jsxs(
1686
- Form,
1687
- {
1688
- form,
1689
- action: formConfig?.endpoint,
1690
- method: formMethod,
1691
- className: cn("flex items-stretch", newsletterFormClassName),
1692
- children: [
1693
- /* @__PURE__ */ jsx(Field, { name: "email", className: "flex-1", children: ({ field }) => /* @__PURE__ */ jsx(
1694
- "input",
1695
- {
1696
- ...field,
1697
- type: "email",
1698
- placeholder: emailPlaceholder,
1699
- className: "flex h-10 w-full rounded-l-md rounded-r-none border border-r-0 border-input px-3 py-2 text-sm ring-offset-background placeholder:opacity-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50",
1700
- "aria-label": emailPlaceholder
1701
- }
1702
- ) }),
1703
- /* @__PURE__ */ jsx(
1704
- Pressable,
1705
- {
1706
- componentType: "button",
1707
- type: "submit",
1708
- variant: "default",
1709
- size: "icon",
1710
- asButton: true,
1711
- className: "rounded-l-none rounded-r-md shrink-0 h-10",
1712
- disabled: form.isSubmitting,
1713
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1714
- }
1715
- )
1716
- ]
1717
- }
1718
- ),
1694
+ renderForm,
1719
1695
  socialLinks && socialLinks.length > 0 && /* @__PURE__ */ jsx(
1720
1696
  "ul",
1721
1697
  {
@@ -1740,19 +1716,31 @@ function FooterSplitImageAccordion({
1740
1716
  footerData.logo && /* @__PURE__ */ jsx(
1741
1717
  FooterLogo,
1742
1718
  {
1743
- logo: { ...footerData.logo, url: footerData.logoUrl },
1719
+ logo: { ...footerData.logo, url: footerData.logo.url || "/" },
1744
1720
  logoClassName: cn("inline-block max-w-60", logoClassName),
1745
1721
  optixFlowConfig
1746
1722
  }
1747
1723
  ),
1748
- footerData.title && /* @__PURE__ */ jsx(
1724
+ footerData.heading && /* @__PURE__ */ jsx(
1749
1725
  "h4",
1750
1726
  {
1751
- className: cn("text-xl font-semibold", brandTitleClassName),
1752
- children: footerData.title
1727
+ className: cn(
1728
+ "text-xl font-semibold text-pretty",
1729
+ brandTitleClassName
1730
+ ),
1731
+ children: footerData.heading
1753
1732
  }
1754
1733
  ),
1755
- footerData.description && /* @__PURE__ */ jsx("p", { className: cn("opacity-80", brandDescriptionClassName), children: footerData.description })
1734
+ footerData.description && /* @__PURE__ */ jsx(
1735
+ "p",
1736
+ {
1737
+ className: cn(
1738
+ "opacity-80 text-balance",
1739
+ brandDescriptionClassName
1740
+ ),
1741
+ children: footerData.description
1742
+ }
1743
+ )
1756
1744
  ] }),
1757
1745
  footerLinks && footerLinks.length > 0 && /* @__PURE__ */ jsx(
1758
1746
  "div",