@opensite/ui 1.5.4 → 1.5.5

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.
@@ -3,171 +3,14 @@ import * as React from 'react';
3
3
  import React__default, { useCallback, useMemo } from 'react';
4
4
  import { clsx } from 'clsx';
5
5
  import { twMerge } from 'tailwind-merge';
6
- import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
7
6
  import { cva } from 'class-variance-authority';
7
+ import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
8
8
  import { Img } from '@page-speed/img';
9
9
 
10
10
  // components/blocks/features/feature-integration-cards.tsx
11
11
  function cn(...inputs) {
12
12
  return twMerge(clsx(inputs));
13
13
  }
14
- function getTextColor(parentBg, variant = "default", options) {
15
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
16
- if (isDark) {
17
- switch (variant) {
18
- case "default":
19
- return "text-foreground";
20
- case "muted":
21
- return "text-foreground/80";
22
- case "subtle":
23
- return "text-foreground/60";
24
- case "accent":
25
- return "text-accent-foreground";
26
- }
27
- } else {
28
- switch (variant) {
29
- case "default":
30
- return "text-foreground";
31
- case "muted":
32
- return "text-muted-foreground";
33
- case "subtle":
34
- return "text-muted-foreground/70";
35
- case "accent":
36
- return "text-primary";
37
- }
38
- }
39
- }
40
- function getAccentColor(parentBg, options) {
41
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
42
- return isDark ? "text-accent-foreground" : "text-primary";
43
- }
44
- function getBorderColor(parentBg, variant = "default", options) {
45
- const isDark = parentBg === "dark" || parentBg === "secondary" || parentBg === "primary";
46
- if (isDark) {
47
- switch (variant) {
48
- case "default":
49
- return "border-foreground/20";
50
- case "muted":
51
- return "border-foreground/10";
52
- case "accent":
53
- return "border-accent-foreground";
54
- }
55
- } else {
56
- switch (variant) {
57
- case "default":
58
- return "border-border";
59
- case "muted":
60
- return "border-muted";
61
- case "accent":
62
- return "border-primary";
63
- }
64
- }
65
- }
66
- var svgCache = /* @__PURE__ */ new Map();
67
- function DynamicIcon({
68
- name,
69
- size = 28,
70
- color,
71
- className,
72
- alt
73
- }) {
74
- const [svgContent, setSvgContent] = React.useState(null);
75
- const [isLoading, setIsLoading] = React.useState(true);
76
- const [error, setError] = React.useState(null);
77
- const { url, iconName } = React.useMemo(() => {
78
- const separator = name.includes("/") ? "/" : ":";
79
- const [prefix, iconName2] = name.split(separator);
80
- const baseUrl = `https://icons.opensite.ai/api/icon/${prefix}/${iconName2}?format=svg&width=${size}&height=${size}&key=au382bi7fsh96w9h9xlrnat2jglx`;
81
- return {
82
- url: baseUrl,
83
- iconName: iconName2
84
- };
85
- }, [name, size]);
86
- React.useEffect(() => {
87
- let isMounted = true;
88
- const fetchSvg = async () => {
89
- const cached = svgCache.get(url);
90
- if (cached) {
91
- if (isMounted) {
92
- setSvgContent(cached);
93
- setIsLoading(false);
94
- }
95
- return;
96
- }
97
- try {
98
- setIsLoading(true);
99
- setError(null);
100
- const response = await fetch(url);
101
- if (!response.ok) {
102
- throw new Error(`Failed to fetch icon: ${response.status}`);
103
- }
104
- let svg = await response.text();
105
- svg = processSvgForCurrentColor(svg);
106
- svgCache.set(url, svg);
107
- if (isMounted) {
108
- setSvgContent(svg);
109
- setIsLoading(false);
110
- }
111
- } catch (err) {
112
- if (isMounted) {
113
- setError(err instanceof Error ? err.message : "Failed to load icon");
114
- setIsLoading(false);
115
- }
116
- }
117
- };
118
- fetchSvg();
119
- return () => {
120
- isMounted = false;
121
- };
122
- }, [url]);
123
- if (isLoading) {
124
- return /* @__PURE__ */ jsx(
125
- "span",
126
- {
127
- className: cn("inline-block", className),
128
- style: { width: size, height: size },
129
- "aria-hidden": "true"
130
- }
131
- );
132
- }
133
- if (error || !svgContent) {
134
- return /* @__PURE__ */ jsx(
135
- "span",
136
- {
137
- className: cn("inline-block", className),
138
- style: { width: size, height: size },
139
- role: "img",
140
- "aria-label": alt || iconName
141
- }
142
- );
143
- }
144
- return /* @__PURE__ */ jsx(
145
- "span",
146
- {
147
- className: cn("inline-flex items-center justify-center", className),
148
- style: {
149
- width: size,
150
- height: size,
151
- color: color || "inherit"
152
- },
153
- role: "img",
154
- "aria-label": alt || iconName,
155
- dangerouslySetInnerHTML: { __html: svgContent }
156
- }
157
- );
158
- }
159
- function processSvgForCurrentColor(svg) {
160
- let processed = svg;
161
- processed = processed.replace(
162
- /stroke=["'](#000000|#000|black)["']/gi,
163
- 'stroke="currentColor"'
164
- );
165
- processed = processed.replace(
166
- /fill=["'](#000000|#000|black)["']/gi,
167
- 'fill="currentColor"'
168
- );
169
- return processed;
170
- }
171
14
  function normalizePhoneNumber(input) {
172
15
  const trimmed = input.trim();
173
16
  if (trimmed.toLowerCase().startsWith("tel:")) {
@@ -980,66 +823,39 @@ function FeatureIntegrationCards({
980
823
  patternOpacity,
981
824
  patternClassName
982
825
  }) {
983
- const renderIntegrationIcon = useCallback((integration) => {
984
- if (integration.iconSlot) return integration.iconSlot;
985
- if (!integration.icon) return null;
986
- return /* @__PURE__ */ jsx(
987
- Img,
988
- {
989
- src: integration.icon,
990
- alt: integration.iconAlt || (typeof integration.title === "string" ? integration.title : "Integration icon"),
991
- className: cn("h-auto w-7", integration.iconClassName),
992
- loading: "lazy",
993
- optixFlowConfig
994
- }
995
- );
996
- }, [optixFlowConfig]);
997
- const renderLinkLabel = useCallback((integration) => {
998
- if (integration.linkLabelSlot) return integration.linkLabelSlot;
999
- if (!integration.linkLabel) return null;
1000
- return /* @__PURE__ */ jsxs(
1001
- "span",
1002
- {
1003
- className: cn(
1004
- "flex items-center gap-1.5 rounded-full border px-3 py-2 text-sm font-medium transition-colors",
1005
- getBorderColor(background),
1006
- getAccentColor(background),
1007
- integration.linkLabelClassName
1008
- ),
1009
- children: [
1010
- integration.linkLabel,
1011
- /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right", size: 14 })
1012
- ]
1013
- }
1014
- );
1015
- }, [background]);
826
+ const renderIntegrationIcon = useCallback(
827
+ (integration) => {
828
+ if (integration.iconSlot) return integration.iconSlot;
829
+ if (!integration.icon) return null;
830
+ return /* @__PURE__ */ jsx(
831
+ Img,
832
+ {
833
+ src: integration.icon,
834
+ alt: integration.iconAlt || (typeof integration.title === "string" ? integration.title : "Integration icon"),
835
+ className: cn(
836
+ "min-h-12 h-auto w-auto object-contain",
837
+ integration.iconClassName
838
+ ),
839
+ loading: "lazy",
840
+ optixFlowConfig
841
+ }
842
+ );
843
+ },
844
+ [optixFlowConfig]
845
+ );
1016
846
  const integrationsContent = useMemo(() => {
1017
847
  if (integrationsSlot) return integrationsSlot;
1018
848
  if (!integrations || integrations.length === 0) return null;
1019
849
  return integrations.map((integration, index) => {
1020
850
  const iconContent = renderIntegrationIcon(integration);
1021
- const linkLabelContent = renderLinkLabel(integration);
1022
851
  const cardContent = /* @__PURE__ */ jsxs(Fragment, { children: [
1023
- /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between", children: [
1024
- iconContent && /* @__PURE__ */ jsx(
1025
- "span",
1026
- {
1027
- className: cn(
1028
- "grid size-12 shrink-0 place-content-center rounded-lg border bg-background/50",
1029
- getBorderColor(background)
1030
- ),
1031
- children: iconContent
1032
- }
1033
- ),
1034
- linkLabelContent
1035
- ] }),
852
+ /* @__PURE__ */ jsx("div", { className: "flex items-start gap-2 justify-between", children: iconContent && /* @__PURE__ */ jsx("div", { className: cn("flex"), children: iconContent }) }),
1036
853
  /* @__PURE__ */ jsxs("div", { className: "space-y-1", children: [
1037
854
  integration.title && (typeof integration.title === "string" ? /* @__PURE__ */ jsx(
1038
855
  "h3",
1039
856
  {
1040
857
  className: cn(
1041
858
  "font-semibold md:text-lg",
1042
- getTextColor(background),
1043
859
  integration.titleClassName
1044
860
  ),
1045
861
  children: integration.title
@@ -1049,7 +865,6 @@ function FeatureIntegrationCards({
1049
865
  {
1050
866
  className: cn(
1051
867
  "font-semibold md:text-lg",
1052
- getTextColor(background),
1053
868
  integration.titleClassName
1054
869
  ),
1055
870
  children: integration.title
@@ -1060,7 +875,6 @@ function FeatureIntegrationCards({
1060
875
  {
1061
876
  className: cn(
1062
877
  "text-sm leading-relaxed md:text-base",
1063
- getTextColor(background, "muted"),
1064
878
  integration.descriptionClassName
1065
879
  ),
1066
880
  children: integration.description
@@ -1070,7 +884,6 @@ function FeatureIntegrationCards({
1070
884
  {
1071
885
  className: cn(
1072
886
  "text-sm leading-relaxed md:text-base",
1073
- getTextColor(background, "muted"),
1074
887
  integration.descriptionClassName
1075
888
  ),
1076
889
  children: integration.description
@@ -1079,8 +892,7 @@ function FeatureIntegrationCards({
1079
892
  ] })
1080
893
  ] });
1081
894
  const cardClasses = cn(
1082
- "flex flex-col gap-5 rounded-xl border p-6 transition-all duration-300",
1083
- getBorderColor(background),
895
+ "flex flex-col gap-5 rounded-xl border p-6 transition-all duration-300 bg-card card-text-foreground",
1084
896
  "hover:shadow-lg",
1085
897
  cardClassName,
1086
898
  integration.className
@@ -1098,7 +910,7 @@ function FeatureIntegrationCards({
1098
910
  }
1099
911
  return /* @__PURE__ */ jsx("div", { className: cardClasses, children: cardContent }, index);
1100
912
  });
1101
- }, [integrationsSlot, integrations, cardClassName, renderIntegrationIcon, renderLinkLabel, background]);
913
+ }, [integrationsSlot, integrations, cardClassName, renderIntegrationIcon]);
1102
914
  return /* @__PURE__ */ jsxs(
1103
915
  Section,
1104
916
  {
@@ -1110,11 +922,47 @@ function FeatureIntegrationCards({
1110
922
  className,
1111
923
  containerClassName,
1112
924
  children: [
1113
- /* @__PURE__ */ jsxs("div", { className: cn("mx-auto mb-12 flex max-w-3xl flex-col items-center gap-4 text-center", headerClassName), children: [
1114
- title && (typeof title === "string" ? /* @__PURE__ */ jsx("h2", { className: cn("text-3xl font-semibold md:text-4xl", titleClassName), children: title }) : /* @__PURE__ */ jsx("div", { className: cn("text-3xl font-semibold md:text-4xl", titleClassName), children: title })),
1115
- description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn(getTextColor(background, "muted"), descriptionClassName), children: description }) : /* @__PURE__ */ jsx("div", { className: cn(getTextColor(background, "muted"), descriptionClassName), children: description }))
1116
- ] }),
1117
- /* @__PURE__ */ jsx("div", { className: cn("grid gap-6 sm:grid-cols-2 lg:grid-cols-4", gridClassName), children: integrationsContent })
925
+ /* @__PURE__ */ jsxs(
926
+ "div",
927
+ {
928
+ className: cn(
929
+ "mx-auto mb-12 flex max-w-3xl flex-col items-center gap-4 text-center",
930
+ headerClassName
931
+ ),
932
+ children: [
933
+ title && (typeof title === "string" ? /* @__PURE__ */ jsx(
934
+ "h2",
935
+ {
936
+ className: cn(
937
+ "text-3xl font-semibold md:text-4xl",
938
+ titleClassName
939
+ ),
940
+ children: title
941
+ }
942
+ ) : /* @__PURE__ */ jsx(
943
+ "div",
944
+ {
945
+ className: cn(
946
+ "text-3xl font-semibold md:text-4xl",
947
+ titleClassName
948
+ ),
949
+ children: title
950
+ }
951
+ )),
952
+ description && (typeof description === "string" ? /* @__PURE__ */ jsx("p", { className: cn(descriptionClassName), children: description }) : /* @__PURE__ */ jsx("div", { className: cn(descriptionClassName), children: description }))
953
+ ]
954
+ }
955
+ ),
956
+ /* @__PURE__ */ jsx(
957
+ "div",
958
+ {
959
+ className: cn(
960
+ "grid gap-6 sm:grid-cols-2 lg:grid-cols-4",
961
+ gridClassName
962
+ ),
963
+ children: integrationsContent
964
+ }
965
+ )
1118
966
  ]
1119
967
  }
1120
968
  );
@@ -1817,43 +1817,45 @@ function FooterAccordionSocial({
1817
1817
  optixFlowConfig
1818
1818
  }
1819
1819
  ),
1820
- /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
1821
- /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl font-semibold", children: newsletterTitle }),
1822
- /* @__PURE__ */ jsxRuntime.jsx("p", { className: "opacity-80", children: newsletterDescription })
1823
- ] }),
1824
- /* @__PURE__ */ jsxRuntime.jsxs(
1825
- forms.Form,
1826
- {
1827
- form,
1828
- action: formConfig?.endpoint,
1829
- method: formMethod,
1830
- className: "flex gap-2",
1831
- children: [
1832
- /* @__PURE__ */ jsxRuntime.jsx(forms.Field, { name: "email", className: "flex-1", children: ({ field, meta }) => /* @__PURE__ */ jsxRuntime.jsx(
1833
- TextInput,
1834
- {
1835
- ...field,
1836
- type: "email",
1837
- placeholder: "Email Address",
1838
- error: meta.touched && !!meta.error,
1839
- className: "flex h-10 w-full rounded-md border 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",
1840
- "aria-label": "Email Address"
1841
- }
1842
- ) }),
1843
- /* @__PURE__ */ jsxRuntime.jsx(
1844
- Pressable,
1845
- {
1846
- componentType: "button",
1847
- type: "submit",
1848
- className: "inline-flex h-10 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90",
1849
- asButton: false,
1850
- disabled: form.isSubmitting,
1851
- children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1852
- }
1853
- )
1854
- ]
1855
- }
1856
- )
1820
+ formConfig?.token && /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1821
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-4", children: [
1822
+ /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-2xl font-semibold", children: newsletterTitle }),
1823
+ /* @__PURE__ */ jsxRuntime.jsx("p", { className: "opacity-80", children: newsletterDescription })
1824
+ ] }),
1825
+ /* @__PURE__ */ jsxRuntime.jsxs(
1826
+ forms.Form,
1827
+ {
1828
+ form,
1829
+ action: formConfig?.endpoint,
1830
+ method: formMethod,
1831
+ className: "flex gap-2",
1832
+ children: [
1833
+ /* @__PURE__ */ jsxRuntime.jsx(forms.Field, { name: "email", className: "flex-1", children: ({ field, meta }) => /* @__PURE__ */ jsxRuntime.jsx(
1834
+ TextInput,
1835
+ {
1836
+ ...field,
1837
+ type: "email",
1838
+ placeholder: "Email Address",
1839
+ error: meta.touched && !!meta.error,
1840
+ className: "flex h-10 w-full rounded-md border 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",
1841
+ "aria-label": "Email Address"
1842
+ }
1843
+ ) }),
1844
+ /* @__PURE__ */ jsxRuntime.jsx(
1845
+ Pressable,
1846
+ {
1847
+ componentType: "button",
1848
+ type: "submit",
1849
+ className: "inline-flex h-10 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90",
1850
+ asButton: false,
1851
+ disabled: form.isSubmitting,
1852
+ children: /* @__PURE__ */ jsxRuntime.jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1853
+ }
1854
+ )
1855
+ ]
1856
+ }
1857
+ )
1858
+ ] })
1857
1859
  ] }),
1858
1860
  footerLinks && footerLinks.length > 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "grid grid-cols-2 gap-x-16 gap-y-8 lg:grid-cols-3", children: footerLinks.map((section) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1859
1861
  /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "mb-4 text-lg font-bold", children: section.title }),
@@ -74,8 +74,11 @@ interface FooterAccordionSocialProps {
74
74
  };
75
75
  /**
76
76
  * Optional form submission configuration for newsletter signup.
77
+ * Requires `token` to render the newsletter UI.
77
78
  */
78
- formConfig?: PageSpeedFormConfig;
79
+ formConfig?: PageSpeedFormConfig & {
80
+ token: string;
81
+ };
79
82
  /**
80
83
  * Optional custom submission handler for newsletter signup.
81
84
  */
@@ -74,8 +74,11 @@ interface FooterAccordionSocialProps {
74
74
  };
75
75
  /**
76
76
  * Optional form submission configuration for newsletter signup.
77
+ * Requires `token` to render the newsletter UI.
77
78
  */
78
- formConfig?: PageSpeedFormConfig;
79
+ formConfig?: PageSpeedFormConfig & {
80
+ token: string;
81
+ };
79
82
  /**
80
83
  * Optional custom submission handler for newsletter signup.
81
84
  */
@@ -1796,43 +1796,45 @@ function FooterAccordionSocial({
1796
1796
  optixFlowConfig
1797
1797
  }
1798
1798
  ),
1799
- /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1800
- /* @__PURE__ */ jsx("h3", { className: "text-2xl font-semibold", children: newsletterTitle }),
1801
- /* @__PURE__ */ jsx("p", { className: "opacity-80", children: newsletterDescription })
1802
- ] }),
1803
- /* @__PURE__ */ jsxs(
1804
- Form,
1805
- {
1806
- form,
1807
- action: formConfig?.endpoint,
1808
- method: formMethod,
1809
- className: "flex gap-2",
1810
- children: [
1811
- /* @__PURE__ */ jsx(Field, { name: "email", className: "flex-1", children: ({ field, meta }) => /* @__PURE__ */ jsx(
1812
- TextInput,
1813
- {
1814
- ...field,
1815
- type: "email",
1816
- placeholder: "Email Address",
1817
- error: meta.touched && !!meta.error,
1818
- className: "flex h-10 w-full rounded-md border 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",
1819
- "aria-label": "Email Address"
1820
- }
1821
- ) }),
1822
- /* @__PURE__ */ jsx(
1823
- Pressable,
1824
- {
1825
- componentType: "button",
1826
- type: "submit",
1827
- className: "inline-flex h-10 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90",
1828
- asButton: false,
1829
- disabled: form.isSubmitting,
1830
- children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1831
- }
1832
- )
1833
- ]
1834
- }
1835
- )
1799
+ formConfig?.token && /* @__PURE__ */ jsxs(Fragment, { children: [
1800
+ /* @__PURE__ */ jsxs("div", { className: "space-y-4", children: [
1801
+ /* @__PURE__ */ jsx("h3", { className: "text-2xl font-semibold", children: newsletterTitle }),
1802
+ /* @__PURE__ */ jsx("p", { className: "opacity-80", children: newsletterDescription })
1803
+ ] }),
1804
+ /* @__PURE__ */ jsxs(
1805
+ Form,
1806
+ {
1807
+ form,
1808
+ action: formConfig?.endpoint,
1809
+ method: formMethod,
1810
+ className: "flex gap-2",
1811
+ children: [
1812
+ /* @__PURE__ */ jsx(Field, { name: "email", className: "flex-1", children: ({ field, meta }) => /* @__PURE__ */ jsx(
1813
+ TextInput,
1814
+ {
1815
+ ...field,
1816
+ type: "email",
1817
+ placeholder: "Email Address",
1818
+ error: meta.touched && !!meta.error,
1819
+ className: "flex h-10 w-full rounded-md border 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",
1820
+ "aria-label": "Email Address"
1821
+ }
1822
+ ) }),
1823
+ /* @__PURE__ */ jsx(
1824
+ Pressable,
1825
+ {
1826
+ componentType: "button",
1827
+ type: "submit",
1828
+ className: "inline-flex h-10 items-center justify-center rounded-md bg-primary px-4 text-sm font-medium text-primary-foreground hover:bg-primary/90",
1829
+ asButton: false,
1830
+ disabled: form.isSubmitting,
1831
+ children: /* @__PURE__ */ jsx(DynamicIcon, { name: "lucide/arrow-right", size: 16 })
1832
+ }
1833
+ )
1834
+ ]
1835
+ }
1836
+ )
1837
+ ] })
1836
1838
  ] }),
1837
1839
  footerLinks && footerLinks.length > 0 && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-x-16 gap-y-8 lg:grid-cols-3", children: footerLinks.map((section) => /* @__PURE__ */ jsxs("div", { children: [
1838
1840
  /* @__PURE__ */ jsx("h3", { className: "mb-4 text-lg font-bold", children: section.title }),
@@ -1873,7 +1873,7 @@ function FooterNewsletterContact({
1873
1873
  className: cn(className),
1874
1874
  children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-10", children: [
1875
1875
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "grid grid-cols-1 gap-x-16 gap-y-8 md:grid-cols-2 xl:grid-cols-4", children: [
1876
- (newsletterTitle || newsletterDescription || newsletterButtonText) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
1876
+ formConfig?.token && (newsletterTitle || newsletterDescription || newsletterButtonText) && /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-6", children: [
1877
1877
  newsletterTitle && /* @__PURE__ */ jsxRuntime.jsx("h3", { className: "text-3xl font-medium font-serif leading-none", children: newsletterTitle }),
1878
1878
  newsletterDescription && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "font-light leading-normal", children: newsletterDescription }),
1879
1879
  /* @__PURE__ */ jsxRuntime.jsxs(
@@ -108,8 +108,11 @@ interface FooterNewsletterContactProps {
108
108
  };
109
109
  /**
110
110
  * Optional form submission configuration for newsletter signup.
111
+ * Requires `token` to render the newsletter UI.
111
112
  */
112
- formConfig?: PageSpeedFormConfig;
113
+ formConfig?: PageSpeedFormConfig & {
114
+ token: string;
115
+ };
113
116
  /**
114
117
  * Optional custom submission handler for newsletter signup.
115
118
  */
@@ -108,8 +108,11 @@ interface FooterNewsletterContactProps {
108
108
  };
109
109
  /**
110
110
  * Optional form submission configuration for newsletter signup.
111
+ * Requires `token` to render the newsletter UI.
111
112
  */
112
- formConfig?: PageSpeedFormConfig;
113
+ formConfig?: PageSpeedFormConfig & {
114
+ token: string;
115
+ };
113
116
  /**
114
117
  * Optional custom submission handler for newsletter signup.
115
118
  */
@@ -1851,7 +1851,7 @@ function FooterNewsletterContact({
1851
1851
  className: cn(className),
1852
1852
  children: /* @__PURE__ */ jsxs("div", { className: "space-y-10", children: [
1853
1853
  /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-1 gap-x-16 gap-y-8 md:grid-cols-2 xl:grid-cols-4", children: [
1854
- (newsletterTitle || newsletterDescription || newsletterButtonText) && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
1854
+ formConfig?.token && (newsletterTitle || newsletterDescription || newsletterButtonText) && /* @__PURE__ */ jsxs("div", { className: "space-y-6", children: [
1855
1855
  newsletterTitle && /* @__PURE__ */ jsx("h3", { className: "text-3xl font-medium font-serif leading-none", children: newsletterTitle }),
1856
1856
  newsletterDescription && /* @__PURE__ */ jsx("p", { className: "font-light leading-normal", children: newsletterDescription }),
1857
1857
  /* @__PURE__ */ jsxs(
@@ -1807,7 +1807,7 @@ function FooterNewsletterMinimal({
1807
1807
  ] })
1808
1808
  ] }),
1809
1809
  /* @__PURE__ */ jsxRuntime.jsxs("div", { className: cn("mt-20 flex flex-col justify-between gap-15 lg:flex-row", newsletterSectionClassName), children: [
1810
- /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full max-w-md flex-col gap-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-sm font-light tracking-tight lg:text-base", children: [
1810
+ formConfig?.token && /* @__PURE__ */ jsxRuntime.jsx("div", { className: "flex w-full max-w-md flex-col gap-10", children: /* @__PURE__ */ jsxRuntime.jsxs("div", { className: "space-y-1 text-sm font-light tracking-tight lg:text-base", children: [
1811
1811
  newsletterLabel && /* @__PURE__ */ jsxRuntime.jsx("p", { children: newsletterLabel }),
1812
1812
  /* @__PURE__ */ jsxRuntime.jsxs(
1813
1813
  forms.Form,
@@ -95,6 +95,7 @@ interface FooterNewsletterMinimalProps {
95
95
  patternOpacity?: number;
96
96
  /**
97
97
  * Optional form submission configuration.
98
+ * Requires `token` to render the newsletter UI.
98
99
  *
99
100
  * **Universal Usage**: Works with ANY REST API endpoint. Simply provide an `endpoint` URL
100
101
  * and the form will submit to it in JSON format.
@@ -116,7 +117,9 @@ interface FooterNewsletterMinimalProps {
116
117
  *
117
118
  * See `FORMS_INTEGRATION_GUIDE.md` for complete examples with Next.js, React, and more.
118
119
  */
119
- formConfig?: PageSpeedFormConfig;
120
+ formConfig?: PageSpeedFormConfig & {
121
+ token: string;
122
+ };
120
123
  /**
121
124
  * Optional custom submission handler for maximum flexibility.
122
125
  *
@@ -95,6 +95,7 @@ interface FooterNewsletterMinimalProps {
95
95
  patternOpacity?: number;
96
96
  /**
97
97
  * Optional form submission configuration.
98
+ * Requires `token` to render the newsletter UI.
98
99
  *
99
100
  * **Universal Usage**: Works with ANY REST API endpoint. Simply provide an `endpoint` URL
100
101
  * and the form will submit to it in JSON format.
@@ -116,7 +117,9 @@ interface FooterNewsletterMinimalProps {
116
117
  *
117
118
  * See `FORMS_INTEGRATION_GUIDE.md` for complete examples with Next.js, React, and more.
118
119
  */
119
- formConfig?: PageSpeedFormConfig;
120
+ formConfig?: PageSpeedFormConfig & {
121
+ token: string;
122
+ };
120
123
  /**
121
124
  * Optional custom submission handler for maximum flexibility.
122
125
  *