@pixelated-tech/components 3.4.3 → 3.5.0

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 (228) hide show
  1. package/README.md +12 -191
  2. package/dist/components/admin/componentusage/componentAnalysis.js +12 -4
  3. package/dist/components/admin/componentusage/componentDiscovery.js +20 -6
  4. package/dist/components/admin/site-health/site-health-accessibility.js +5 -1
  5. package/dist/components/admin/site-health/site-health-axe-core.js +4 -0
  6. package/dist/components/admin/site-health/site-health-cloudwatch.integration.js +0 -5
  7. package/dist/components/admin/site-health/site-health-cloudwatch.js +7 -1
  8. package/dist/components/admin/site-health/site-health-dependency-vulnerabilities.js +4 -0
  9. package/dist/components/admin/site-health/site-health-github.js +6 -0
  10. package/dist/components/admin/site-health/site-health-google-analytics.js +6 -0
  11. package/dist/components/admin/site-health/site-health-google-search-console.js +6 -0
  12. package/dist/components/admin/site-health/site-health-on-site-seo.integration.js +128 -55
  13. package/dist/components/admin/site-health/site-health-on-site-seo.js +4 -0
  14. package/dist/components/admin/site-health/site-health-overview.js +11 -4
  15. package/dist/components/admin/site-health/site-health-performance.js +4 -0
  16. package/dist/components/admin/site-health/site-health-security.js +5 -1
  17. package/dist/components/admin/site-health/site-health-seo.js +5 -1
  18. package/dist/components/admin/site-health/site-health-template.js +19 -9
  19. package/dist/components/admin/site-health/site-health-uptime.js +4 -0
  20. package/dist/components/callout/callout.js +0 -10
  21. package/dist/components/carousel/carousel.js +15 -4
  22. package/dist/components/carousel/tiles.js +1 -1
  23. package/dist/components/cms/contentful.items.components.js +3 -4
  24. package/dist/components/cms/flickr.js +1 -1
  25. package/dist/components/cms/google.reviews.components.js +3 -3
  26. package/dist/components/cms/instagram.components.js +15 -5
  27. package/dist/components/cms/smartimage.js +2 -2
  28. package/dist/components/cms/wordpress.components.js +32 -6
  29. package/dist/components/cms/yelp.js +5 -0
  30. package/dist/components/config/config.server.js +7 -1
  31. package/dist/components/general/css.js +0 -1
  32. package/dist/components/general/image.js +0 -1
  33. package/dist/components/general/loading.js +2 -1
  34. package/dist/components/general/microinteractions.js +0 -1
  35. package/dist/components/general/modal.css +2 -4
  36. package/dist/components/general/modal.js +72 -30
  37. package/dist/components/general/sidepanel.js +16 -0
  38. package/dist/components/general/tab.js +1 -0
  39. package/dist/components/menu/menu-accordion.css +1 -1
  40. package/dist/components/menu/menu-accordion.js +15 -4
  41. package/dist/components/menu/menu-expando.js +21 -19
  42. package/dist/components/menu/menu-simple.js +14 -14
  43. package/dist/components/nerdjoke/nerdjoke.js +1 -1
  44. package/dist/components/seo/googlesearch.js +0 -1
  45. package/dist/components/seo/schema-blogposting.js +6 -1
  46. package/dist/components/seo/schema-recipe.js +34 -1
  47. package/dist/components/seo/schema-services.js +20 -2
  48. package/dist/components/shoppingcart/ebay.components.js +3 -3
  49. package/dist/components/shoppingcart/shoppingcart.components.js +76 -28
  50. package/dist/components/shoppingcart/shoppingcart.functions.js +4 -4
  51. package/dist/components/sitebuilder/config/CompoundFontSelector.js +13 -4
  52. package/dist/components/sitebuilder/config/ConfigBuilder.css +194 -5
  53. package/dist/components/sitebuilder/config/ConfigBuilder.js +183 -17
  54. package/dist/components/sitebuilder/config/FontSelector.js +13 -2
  55. package/dist/components/sitebuilder/config/routes-form.json +67 -0
  56. package/dist/components/sitebuilder/config/siteinfo-form.json +28 -14
  57. package/dist/components/sitebuilder/config/visualdesignform.json +4 -4
  58. package/dist/components/sitebuilder/form/formbuilder.js +1 -0
  59. package/dist/components/sitebuilder/form/formcomponents.js +2 -3
  60. package/dist/components/sitebuilder/form/formengine.js +6 -5
  61. package/dist/components/sitebuilder/form/formvalidator.js +5 -0
  62. package/dist/components/sitebuilder/page/components/PageBuilderUI.js +5 -1
  63. package/dist/components/structured/buzzwordbingo.css +0 -1
  64. package/dist/components/structured/recipe.js +1 -1
  65. package/dist/components/structured/socialcard.js +2 -2
  66. package/dist/components/utilities/functions.js +82 -1
  67. package/dist/components/utilities/gemini-api.client.js +76 -0
  68. package/dist/components/utilities/gemini-api.server.js +185 -0
  69. package/dist/data/routes.json +5 -5
  70. package/dist/index.adminclient.js +30 -0
  71. package/dist/index.adminserver.js +21 -0
  72. package/dist/index.js +4 -18
  73. package/dist/index.server.js +15 -28
  74. package/dist/types/components/admin/componentusage/componentAnalysis.d.ts.map +1 -1
  75. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts +1 -1
  76. package/dist/types/components/admin/componentusage/componentDiscovery.d.ts.map +1 -1
  77. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts +7 -4
  78. package/dist/types/components/admin/site-health/site-health-accessibility.d.ts.map +1 -1
  79. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts +7 -4
  80. package/dist/types/components/admin/site-health/site-health-axe-core.d.ts.map +1 -1
  81. package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts +9 -6
  82. package/dist/types/components/admin/site-health/site-health-cloudwatch.d.ts.map +1 -1
  83. package/dist/types/components/admin/site-health/site-health-cloudwatch.integration.d.ts.map +1 -1
  84. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts +7 -4
  85. package/dist/types/components/admin/site-health/site-health-dependency-vulnerabilities.d.ts.map +1 -1
  86. package/dist/types/components/admin/site-health/site-health-github.d.ts +9 -6
  87. package/dist/types/components/admin/site-health/site-health-github.d.ts.map +1 -1
  88. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts +9 -6
  89. package/dist/types/components/admin/site-health/site-health-google-analytics.d.ts.map +1 -1
  90. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts +9 -6
  91. package/dist/types/components/admin/site-health/site-health-google-search-console.d.ts.map +1 -1
  92. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts +8 -3
  93. package/dist/types/components/admin/site-health/site-health-on-site-seo.d.ts.map +1 -1
  94. package/dist/types/components/admin/site-health/site-health-on-site-seo.integration.d.ts.map +1 -1
  95. package/dist/types/components/admin/site-health/site-health-overview.d.ts +7 -4
  96. package/dist/types/components/admin/site-health/site-health-overview.d.ts.map +1 -1
  97. package/dist/types/components/admin/site-health/site-health-performance.d.ts +7 -4
  98. package/dist/types/components/admin/site-health/site-health-performance.d.ts.map +1 -1
  99. package/dist/types/components/admin/site-health/site-health-security.d.ts +7 -4
  100. package/dist/types/components/admin/site-health/site-health-security.d.ts.map +1 -1
  101. package/dist/types/components/admin/site-health/site-health-seo.d.ts +7 -4
  102. package/dist/types/components/admin/site-health/site-health-seo.d.ts.map +1 -1
  103. package/dist/types/components/admin/site-health/site-health-template.d.ts +12 -10
  104. package/dist/types/components/admin/site-health/site-health-template.d.ts.map +1 -1
  105. package/dist/types/components/admin/site-health/site-health-uptime.d.ts +7 -4
  106. package/dist/types/components/admin/site-health/site-health-uptime.d.ts.map +1 -1
  107. package/dist/types/components/callout/callout.d.ts +3 -3
  108. package/dist/types/components/callout/callout.d.ts.map +1 -1
  109. package/dist/types/components/carousel/carousel.d.ts +16 -7
  110. package/dist/types/components/carousel/carousel.d.ts.map +1 -1
  111. package/dist/types/components/carousel/tiles.d.ts +3 -6
  112. package/dist/types/components/carousel/tiles.d.ts.map +1 -1
  113. package/dist/types/components/cms/flickr.d.ts +3 -6
  114. package/dist/types/components/cms/flickr.d.ts.map +1 -1
  115. package/dist/types/components/cms/google.reviews.components.d.ts +1 -7
  116. package/dist/types/components/cms/google.reviews.components.d.ts.map +1 -1
  117. package/dist/types/components/cms/hubspot.components.d.ts +1 -2
  118. package/dist/types/components/cms/hubspot.components.d.ts.map +1 -1
  119. package/dist/types/components/cms/instagram.components.d.ts +14 -9
  120. package/dist/types/components/cms/instagram.components.d.ts.map +1 -1
  121. package/dist/types/components/cms/smartimage.d.ts +2 -28
  122. package/dist/types/components/cms/smartimage.d.ts.map +1 -1
  123. package/dist/types/components/cms/wordpress.components.d.ts +33 -14
  124. package/dist/types/components/cms/wordpress.components.d.ts.map +1 -1
  125. package/dist/types/components/cms/yelp.d.ts +9 -4
  126. package/dist/types/components/cms/yelp.d.ts.map +1 -1
  127. package/dist/types/components/config/config.server.d.ts +9 -6
  128. package/dist/types/components/config/config.server.d.ts.map +1 -1
  129. package/dist/types/components/general/loading.d.ts +5 -1
  130. package/dist/types/components/general/loading.d.ts.map +1 -1
  131. package/dist/types/components/general/microinteractions.d.ts +1 -3
  132. package/dist/types/components/general/microinteractions.d.ts.map +1 -1
  133. package/dist/types/components/general/modal.d.ts +11 -5
  134. package/dist/types/components/general/modal.d.ts.map +1 -1
  135. package/dist/types/components/general/semantic.d.ts +3 -3
  136. package/dist/types/components/general/sidepanel.d.ts +20 -13
  137. package/dist/types/components/general/sidepanel.d.ts.map +1 -1
  138. package/dist/types/components/general/tab.d.ts +1 -2
  139. package/dist/types/components/general/tab.d.ts.map +1 -1
  140. package/dist/types/components/menu/menu-accordion.d.ts +22 -9
  141. package/dist/types/components/menu/menu-accordion.d.ts.map +1 -1
  142. package/dist/types/components/menu/menu-expando.d.ts +14 -5
  143. package/dist/types/components/menu/menu-expando.d.ts.map +1 -1
  144. package/dist/types/components/menu/menu-simple.d.ts +4 -5
  145. package/dist/types/components/menu/menu-simple.d.ts.map +1 -1
  146. package/dist/types/components/nerdjoke/nerdjoke.d.ts +1 -1
  147. package/dist/types/components/nerdjoke/nerdjoke.d.ts.map +1 -1
  148. package/dist/types/components/seo/googleanalytics.d.ts.map +1 -1
  149. package/dist/types/components/seo/metadata.components.d.ts +2 -2
  150. package/dist/types/components/seo/metadata.components.d.ts.map +1 -1
  151. package/dist/types/components/seo/schema-blogposting.d.ts +7 -4
  152. package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -1
  153. package/dist/types/components/seo/schema-recipe.d.ts +29 -30
  154. package/dist/types/components/seo/schema-recipe.d.ts.map +1 -1
  155. package/dist/types/components/seo/schema-services.d.ts +19 -9
  156. package/dist/types/components/seo/schema-services.d.ts.map +1 -1
  157. package/dist/types/components/shoppingcart/paypal.d.ts +1 -1
  158. package/dist/types/components/shoppingcart/paypal.d.ts.map +1 -1
  159. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +77 -28
  160. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts.map +1 -1
  161. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts +4 -23
  162. package/dist/types/components/shoppingcart/shoppingcart.functions.d.ts.map +1 -1
  163. package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts +10 -11
  164. package/dist/types/components/sitebuilder/config/CompoundFontSelector.d.ts.map +1 -1
  165. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +41 -174
  166. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -1
  167. package/dist/types/components/sitebuilder/config/FontSelector.d.ts +12 -13
  168. package/dist/types/components/sitebuilder/config/FontSelector.d.ts.map +1 -1
  169. package/dist/types/components/sitebuilder/form/formbuilder.d.ts +7 -3
  170. package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -1
  171. package/dist/types/components/sitebuilder/form/formcomponents.d.ts +1 -1
  172. package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -1
  173. package/dist/types/components/sitebuilder/form/formengine.d.ts +1 -2
  174. package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -1
  175. package/dist/types/components/sitebuilder/form/formextractor.d.ts +5 -4
  176. package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -1
  177. package/dist/types/components/sitebuilder/form/formtypes.d.ts +3 -3
  178. package/dist/types/components/sitebuilder/form/formtypes.d.ts.map +1 -1
  179. package/dist/types/components/sitebuilder/form/formvalidator.d.ts +8 -3
  180. package/dist/types/components/sitebuilder/form/formvalidator.d.ts.map +1 -1
  181. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts +2 -3
  182. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts.map +1 -1
  183. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts +2 -3
  184. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts.map +1 -1
  185. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts +2 -3
  186. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts.map +1 -1
  187. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts +8 -7
  188. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts.map +1 -1
  189. package/dist/types/components/sitebuilder/page/components/PageEngine.d.ts.map +1 -1
  190. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts +2 -3
  191. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -1
  192. package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts +1 -1
  193. package/dist/types/components/structured/markdown.d.ts +1 -3
  194. package/dist/types/components/structured/markdown.d.ts.map +1 -1
  195. package/dist/types/components/structured/recipe.d.ts +5 -32
  196. package/dist/types/components/structured/recipe.d.ts.map +1 -1
  197. package/dist/types/components/structured/socialcard.d.ts +4 -0
  198. package/dist/types/components/structured/socialcard.d.ts.map +1 -1
  199. package/dist/types/components/structured/timeline.d.ts +1 -3
  200. package/dist/types/components/structured/timeline.d.ts.map +1 -1
  201. package/dist/types/components/utilities/functions.d.ts +20 -0
  202. package/dist/types/components/utilities/functions.d.ts.map +1 -1
  203. package/dist/types/components/utilities/gemini-api.client.d.ts +38 -0
  204. package/dist/types/components/utilities/gemini-api.client.d.ts.map +1 -0
  205. package/dist/types/components/utilities/gemini-api.server.d.ts +17 -0
  206. package/dist/types/components/utilities/gemini-api.server.d.ts.map +1 -0
  207. package/dist/types/index.adminclient.d.ts +27 -0
  208. package/dist/types/index.adminclient.d.ts.map +1 -0
  209. package/dist/types/index.adminserver.d.ts +19 -0
  210. package/dist/types/index.adminserver.d.ts.map +1 -0
  211. package/dist/types/index.d.ts +4 -18
  212. package/dist/types/index.server.d.ts +5 -28
  213. package/dist/types/stories/general/sidepanel.stories.d.ts.map +1 -1
  214. package/dist/types/stories/general/smartimage.stories.d.ts +74 -2
  215. package/dist/types/stories/general/smartimage.stories.d.ts.map +1 -1
  216. package/package.json +19 -9
  217. package/README.COMPONENTS.md +0 -2310
  218. package/dist/components/cms/pixelated.linkedin.js +0 -180
  219. package/dist/components/cms/pixelated.linkedin1.js +0 -84
  220. package/dist/components/cms/pixelated.linkedin2.js +0 -92
  221. package/dist/types/components/cms/pixelated.linkedin.d.ts +0 -2
  222. package/dist/types/components/cms/pixelated.linkedin.d.ts.map +0 -1
  223. package/dist/types/components/cms/pixelated.linkedin1.d.ts +0 -2
  224. package/dist/types/components/cms/pixelated.linkedin1.d.ts.map +0 -1
  225. package/dist/types/components/cms/pixelated.linkedin2.d.ts +0 -2
  226. package/dist/types/components/cms/pixelated.linkedin2.d.ts.map +0 -1
  227. package/dist/types/tests/pixelated.menu-expando.test.d.ts +0 -2
  228. package/dist/types/tests/pixelated.menu-expando.test.d.ts.map +0 -1
@@ -2,18 +2,25 @@
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import { useState, useEffect } from 'react';
4
4
  import PropTypes from 'prop-types';
5
+ import { Modal } from '../../general/modal';
5
6
  import { Tab } from '../../general/tab';
6
7
  import { Accordion } from '../../general/accordion';
8
+ import { createGeminiApiService } from '../../utilities/gemini-api.client';
7
9
  import { FormEngine } from '../form/formengine';
10
+ import { FormValidationProvider } from '../form/formvalidator';
11
+ import * as FC from '../form/formcomponents';
8
12
  import siteInfoForm from './siteinfo-form.json';
9
13
  import visualDesignForm from './visualdesignform.json';
14
+ import routesForm from './routes-form.json';
10
15
  import defaultConfigData from '../../../data/routes.json';
11
16
  import './ConfigBuilder.css';
12
17
  const RoutePropTypes = {
18
+ name: PropTypes.string,
13
19
  path: PropTypes.string.isRequired,
14
- component: PropTypes.string.isRequired,
15
20
  title: PropTypes.string,
16
21
  description: PropTypes.string,
22
+ keywords: PropTypes.arrayOf(PropTypes.string),
23
+ hidden: PropTypes.bool,
17
24
  };
18
25
  const SiteInfoPropTypes = {
19
26
  name: PropTypes.string.isRequired,
@@ -78,7 +85,7 @@ const SiteConfigPropTypes = {
78
85
  routes: PropTypes.arrayOf(PropTypes.shape(RoutePropTypes).isRequired).isRequired,
79
86
  visualdesign: PropTypes.shape(VisualDesignPropTypes).isRequired,
80
87
  };
81
- const ConfigBuilderPropTypes = {
88
+ ConfigBuilder.propTypes = {
82
89
  initialConfig: PropTypes.shape(SiteConfigPropTypes),
83
90
  onSave: PropTypes.func,
84
91
  };
@@ -98,18 +105,38 @@ export function ConfigBuilder(props) {
98
105
  });
99
106
  const [socialLinks, setSocialLinks] = useState(initialConfig?.siteInfo?.sameAs || ['']);
100
107
  const [isFormValid, setIsFormValid] = useState(false);
108
+ // AI Recommendations state
109
+ const [aiModalOpen, setAiModalOpen] = useState(false);
110
+ const [currentRouteIndex, setCurrentRouteIndex] = useState(null);
111
+ const [aiRecommendations, setAiRecommendations] = useState(null);
112
+ const [aiLoading, setAiLoading] = useState(false);
113
+ const [acceptTitle, setAcceptTitle] = useState(false);
114
+ const [acceptKeywords, setAcceptKeywords] = useState(false);
115
+ const [acceptDescription, setAcceptDescription] = useState(false);
101
116
  // Validate form whenever config changes
102
117
  useEffect(() => {
103
118
  const siteInfo = config.siteInfo || {};
104
- const isValid = (siteInfo.name || '').trim() !== '' &&
105
- (siteInfo.author || '').trim() !== '' &&
106
- (siteInfo.description || '').trim() !== '' &&
107
- (siteInfo.url || '').trim() !== '' &&
108
- (siteInfo.email || '').trim() !== '' &&
119
+ const isValid = String(siteInfo.name || '').trim() !== '' &&
120
+ String(siteInfo.author || '').trim() !== '' &&
121
+ String(siteInfo.description || '').trim() !== '' &&
122
+ String(siteInfo.url || '').trim() !== '' &&
123
+ String(siteInfo.email || '').trim() !== '' &&
109
124
  // Basic email validation
110
125
  /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(siteInfo.email || '');
111
126
  setIsFormValid(isValid);
112
127
  }, [config]);
128
+ // Handle AI modal visibility - now handled by Modal component isOpen prop
129
+ // useEffect(() => {
130
+ // console.log('AI modal effect running, aiModalOpen:', aiModalOpen);
131
+ // if (aiModalOpen) {
132
+ // const modal = document.getElementById('myModalai-recommendations');
133
+ // console.log('Modal element found:', modal);
134
+ // if (modal) {
135
+ // modal.style.display = 'block';
136
+ // console.log('Set modal display to block');
137
+ // }
138
+ // }
139
+ // }, [aiModalOpen]);
113
140
  const handleFileUpload = (event) => {
114
141
  const file = event.target.files?.[0];
115
142
  if (!file)
@@ -121,7 +148,19 @@ export function ConfigBuilder(props) {
121
148
  const parsedConfig = JSON.parse(jsonContent);
122
149
  // Validate the structure
123
150
  if (parsedConfig.siteInfo && parsedConfig.routes) {
124
- setConfig(parsedConfig);
151
+ // Ensure keywords are arrays for all routes
152
+ const normalizedRoutes = parsedConfig.routes.map((route) => ({
153
+ ...route,
154
+ keywords: Array.isArray(route.keywords)
155
+ ? route.keywords
156
+ : (typeof route.keywords === 'string'
157
+ ? route.keywords.split(',').map((k) => k.trim()).filter((k) => k.length > 0)
158
+ : [])
159
+ }));
160
+ setConfig({
161
+ ...parsedConfig,
162
+ routes: normalizedRoutes
163
+ });
125
164
  setSocialLinks(parsedConfig.siteInfo.sameAs || ['']);
126
165
  }
127
166
  else {
@@ -138,9 +177,18 @@ export function ConfigBuilder(props) {
138
177
  };
139
178
  useEffect(() => {
140
179
  if (initialConfig) {
180
+ // Ensure keywords are arrays for all routes
181
+ const normalizedRoutes = (initialConfig.routes || []).map((route) => ({
182
+ ...route,
183
+ keywords: Array.isArray(route.keywords)
184
+ ? route.keywords
185
+ : (typeof route.keywords === 'string'
186
+ ? route.keywords.split(',').map((k) => k.trim()).filter((k) => k.length > 0)
187
+ : [])
188
+ }));
141
189
  setConfig((prev) => ({
142
190
  siteInfo: { ...prev.siteInfo, ...initialConfig.siteInfo },
143
- routes: initialConfig.routes || [],
191
+ routes: normalizedRoutes,
144
192
  visualdesign: initialConfig.visualdesign || prev.visualdesign || {}
145
193
  }));
146
194
  setSocialLinks(initialConfig.siteInfo?.sameAs || ['']);
@@ -155,11 +203,18 @@ export function ConfigBuilder(props) {
155
203
  value: config.siteInfo[field.props.name] || '',
156
204
  defaultValue: config.siteInfo[field.props.name] || field.props.defaultValue || '',
157
205
  onChange: (value) => {
206
+ // Handle both direct values and event objects
207
+ let actualValue = value;
208
+ if (value && typeof value === 'object' && value.target) {
209
+ // It's an event object, extract the value
210
+ const target = value.target;
211
+ actualValue = target.type === 'checkbox' ? (target.checked ? target.value : '') : target.value;
212
+ }
158
213
  setConfig((prev) => ({
159
214
  ...prev,
160
215
  siteInfo: {
161
216
  ...prev.siteInfo,
162
- [field.props.name]: value
217
+ [field.props.name]: actualValue
163
218
  }
164
219
  }));
165
220
  }
@@ -174,7 +229,8 @@ export function ConfigBuilder(props) {
174
229
  ...field.props,
175
230
  value: (config.visualdesign && config.visualdesign[field.props.name]) ? (config.visualdesign[field.props.name].value ?? config.visualdesign[field.props.name]) : '',
176
231
  defaultValue: (config.visualdesign && config.visualdesign[field.props.name]) ? (config.visualdesign[field.props.name].value ?? config.visualdesign[field.props.name]) : field.props.defaultValue || '',
177
- onChange: (value) => {
232
+ onChange: (event) => {
233
+ const value = event.target.value;
178
234
  setConfig((prev) => ({
179
235
  ...prev,
180
236
  visualdesign: {
@@ -228,13 +284,18 @@ export function ConfigBuilder(props) {
228
284
  const addRoute = () => {
229
285
  setConfig(prev => ({
230
286
  ...prev,
231
- routes: [...prev.routes, { path: '', component: '', title: '', description: '' }]
287
+ routes: [...prev.routes, { name: '', path: '', title: '', description: '', keywords: [], hidden: false }]
232
288
  }));
233
289
  };
234
290
  const updateRoute = (index, field, value) => {
291
+ // Special handling for keywords field - convert comma-separated string to array
292
+ let processedValue = value;
293
+ if (field === 'keywords' && typeof value === 'string') {
294
+ processedValue = value.split(',').map((k) => k.trim()).filter((k) => k.length > 0);
295
+ }
235
296
  setConfig(prev => ({
236
297
  ...prev,
237
- routes: prev.routes.map((route, i) => i === index ? { ...route, [field]: value } : route)
298
+ routes: prev.routes.map((route, i) => i === index ? { ...route, [field]: processedValue } : route)
238
299
  }));
239
300
  };
240
301
  const removeRoute = (index) => {
@@ -250,6 +311,60 @@ export function ConfigBuilder(props) {
250
311
  }
251
312
  onSave?.(config);
252
313
  };
314
+ const handleAiRecommendations = async (routeIndex) => {
315
+ console.log('handleAiRecommendations called with routeIndex:', routeIndex);
316
+ setCurrentRouteIndex(routeIndex);
317
+ setAiLoading(true);
318
+ setAiModalOpen(true);
319
+ setAcceptTitle(false);
320
+ setAcceptKeywords(false);
321
+ setAcceptDescription(false);
322
+ try {
323
+ const geminiService = createGeminiApiService('dummy-key'); // API key handled server-side
324
+ const route = config.routes[routeIndex];
325
+ const result = await geminiService.generateRouteRecommendations({
326
+ route,
327
+ siteInfo: config.siteInfo,
328
+ baseUrl: config.siteInfo.url
329
+ });
330
+ if (result.success && result.data) {
331
+ setAiRecommendations(result.data);
332
+ }
333
+ else {
334
+ setAiRecommendations({ error: result.error || 'Failed to generate recommendations' });
335
+ }
336
+ }
337
+ catch (error) {
338
+ console.error('AI recommendation error:', error);
339
+ setAiRecommendations({ error: 'Failed to generate AI recommendations' });
340
+ }
341
+ finally {
342
+ setAiLoading(false);
343
+ }
344
+ };
345
+ const handleAcceptAiRecommendations = () => {
346
+ if (currentRouteIndex === null || !aiRecommendations)
347
+ return;
348
+ const updates = {};
349
+ if (acceptTitle && aiRecommendations.title) {
350
+ updates.title = aiRecommendations.title;
351
+ }
352
+ if (acceptKeywords && aiRecommendations.keywords) {
353
+ updates.keywords = aiRecommendations.keywords;
354
+ }
355
+ if (acceptDescription && aiRecommendations.description) {
356
+ updates.description = aiRecommendations.description;
357
+ }
358
+ if (Object.keys(updates).length > 0) {
359
+ setConfig(prev => ({
360
+ ...prev,
361
+ routes: prev.routes.map((route, i) => i === currentRouteIndex ? { ...route, ...updates } : route)
362
+ }));
363
+ }
364
+ setAiModalOpen(false);
365
+ setAiRecommendations(null);
366
+ setCurrentRouteIndex(null);
367
+ };
253
368
  return (_jsxs("div", { className: "config-builder", children: [_jsx("h2", { children: "Config Builder" }), _jsxs("div", { className: "file-upload-section", children: [_jsx("label", { htmlFor: "config-file-upload", className: "file-upload-label", children: "Load Configuration File:" }), _jsx("input", { id: "config-file-upload", type: "file", accept: ".json", onChange: handleFileUpload, className: "file-upload-input" })] }), _jsx(Tab, { tabs: [
254
369
  {
255
370
  id: 'siteinfo',
@@ -259,7 +374,41 @@ export function ConfigBuilder(props) {
259
374
  {
260
375
  id: 'routes',
261
376
  label: 'Routes',
262
- content: (_jsxs("div", { className: "routes-section", children: [_jsxs("div", { className: "routes-list", children: [_jsxs("div", { className: "route-headers", children: [_jsx("span", { children: "Path" }), _jsx("span", { children: "Component" }), _jsx("span", { children: "Title" }), _jsx("span", { children: "Description" }), _jsx("span", { children: "Actions" })] }), config.routes.map((route, index) => (_jsxs("div", { className: "route-item", children: [_jsx("input", { type: "text", placeholder: "Path", value: route.path, onChange: (e) => updateRoute(index, 'path', e.target.value) }), _jsx("input", { type: "text", placeholder: "Component", value: route.component, onChange: (e) => updateRoute(index, 'component', e.target.value) }), _jsx("input", { type: "text", placeholder: "Title", value: route.title || '', onChange: (e) => updateRoute(index, 'title', e.target.value) }), _jsx("input", { type: "text", placeholder: "Description", value: route.description || '', onChange: (e) => updateRoute(index, 'description', e.target.value) }), _jsx("button", { onClick: () => removeRoute(index), children: "Remove" })] }, index)))] }), _jsx("button", { onClick: addRoute, children: "Add Route" })] }))
377
+ content: (_jsx(FormValidationProvider, { children: _jsxs("div", { className: "routes-section", children: [_jsx("div", { className: "routes-list", children: config.routes.map((route, index) => (_jsxs("div", { className: "route-item", children: [routesForm.fields.map((field) => {
378
+ const Component = FC[field.component];
379
+ if (!Component)
380
+ return null;
381
+ let fieldValue = route[field.props.name];
382
+ if (field.props.name === 'keywords' && Array.isArray(fieldValue)) {
383
+ fieldValue = fieldValue.join(', ');
384
+ }
385
+ const fieldProps = {
386
+ ...field.props,
387
+ id: `${field.props.id}-${index}`,
388
+ ...(field.component === 'FormTextarea'
389
+ ? { defaultValue: fieldValue || '' }
390
+ : field.props.type === 'checkbox'
391
+ ? { checked: fieldValue || false }
392
+ : { value: fieldValue || '' }),
393
+ onChange: (e) => {
394
+ let value;
395
+ if (field.props.type === 'checkbox') {
396
+ value = e.target.checked;
397
+ }
398
+ else if (field.props.name === 'keywords') {
399
+ value = e.target.value.split(',').map((s) => s.trim()).filter((s) => s);
400
+ }
401
+ else {
402
+ value = e.target.value;
403
+ }
404
+ updateRoute(index, field.props.name, value);
405
+ }
406
+ };
407
+ return _jsx(Component, { ...fieldProps }, fieldProps.id);
408
+ }), _jsxs("div", { className: "route-buttons", children: [_jsxs("button", { onClick: () => {
409
+ console.log('AI Recommend button clicked for route:', index);
410
+ handleAiRecommendations(index);
411
+ }, className: "route-button ai-recommend", children: [_jsx("span", { className: "ai-icon", children: "\u2728" }), " Recommend"] }), _jsx("button", { onClick: () => removeRoute(index), className: "route-button remove", children: "Remove" })] })] }, index))) }), _jsx("button", { onClick: addRoute, children: "Add Route" })] }) }))
263
412
  },
264
413
  {
265
414
  id: 'visualdesign',
@@ -269,8 +418,25 @@ export function ConfigBuilder(props) {
269
418
  ], orientation: "top" }), _jsx("button", { onClick: handleSave, disabled: !isFormValid, className: isFormValid ? 'save-button-valid' : 'save-button-invalid', children: "Save Config" }), !isFormValid && (_jsx("div", { className: "validation-message", children: "Please fill in all required fields (marked with *) before saving." })), _jsx(Accordion, { items: [
270
419
  {
271
420
  title: 'Configuration Preview',
272
- content: _jsx("pre", { children: JSON.stringify(config, null, 2) })
421
+ content: _jsx("pre", { children: (() => {
422
+ try {
423
+ return JSON.stringify(config, null, 2);
424
+ }
425
+ catch (e) {
426
+ // Simple fallback that doesn't try to analyze the object deeply
427
+ const errorMessage = e instanceof Error ? e.message : String(e);
428
+ return `Configuration contains non-serializable data (functions, circular references, or DOM elements).\n\nError: ${errorMessage}\n\nTo debug, check the config object in browser dev tools for functions or complex objects.`;
429
+ }
430
+ })() })
273
431
  }
274
- ] })] }));
432
+ ] }), _jsx(Modal, { modalID: "ai-recommendations", isOpen: aiModalOpen, handleCloseEvent: () => setAiModalOpen(false), modalContent: _jsxs("div", { className: "ai-recommendations-modal", children: [_jsx("h3", { children: "AI SEO Recommendations" }), currentRouteIndex !== null && (_jsxs("p", { children: [_jsx("strong", { children: "Route:" }), " ", config.routes[currentRouteIndex].name || config.routes[currentRouteIndex].path] })), aiLoading ? (_jsxs("div", { className: "ai-loading", children: [_jsx("p", { children: "Generating AI recommendations..." }), _jsx("div", { className: "loading-spinner" })] })) : aiRecommendations?.error ? (_jsx("div", { className: "ai-error", children: _jsxs("p", { children: ["Error: ", aiRecommendations.error] }) })) : aiRecommendations ? (_jsxs("div", { className: "ai-recommendations", children: [_jsxs("div", { className: "recommendation-item", children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: acceptTitle, onChange: (e) => setAcceptTitle(e.target.checked) }), _jsx("strong", { children: "Title:" })] }), _jsxs("div", { className: "recommendation-content", children: [_jsx("div", { className: "current-value", children: _jsxs("small", { children: ["Current: ", config.routes[currentRouteIndex]?.title || 'None'] }) }), _jsx("div", { className: "suggested-value", children: aiRecommendations.title })] })] }), _jsxs("div", { className: "recommendation-item", children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: acceptKeywords, onChange: (e) => setAcceptKeywords(e.target.checked) }), _jsx("strong", { children: "Keywords:" })] }), _jsxs("div", { className: "recommendation-content", children: [_jsx("div", { className: "current-value", children: _jsxs("small", { children: ["Current: ", (() => {
433
+ const keywords = config.routes[currentRouteIndex]?.keywords;
434
+ if (Array.isArray(keywords)) {
435
+ return keywords.join(', ') || 'None';
436
+ }
437
+ else if (typeof keywords === 'string') {
438
+ return keywords || 'None';
439
+ }
440
+ return 'None';
441
+ })()] }) }), _jsx("div", { className: "suggested-value", children: aiRecommendations.keywords?.join(', ') })] })] }), _jsxs("div", { className: "recommendation-item", children: [_jsxs("label", { children: [_jsx("input", { type: "checkbox", checked: acceptDescription, onChange: (e) => setAcceptDescription(e.target.checked) }), _jsx("strong", { children: "Description:" })] }), _jsxs("div", { className: "recommendation-content", children: [_jsx("div", { className: "current-value", children: _jsxs("small", { children: ["Current: ", config.routes[currentRouteIndex]?.description || 'None'] }) }), _jsx("div", { className: "suggested-value", children: aiRecommendations.description })] })] })] })) : null, _jsxs("div", { className: "modal-actions", children: [_jsx("button", { onClick: () => setAiModalOpen(false), children: "Cancel" }), _jsx("button", { onClick: handleAcceptAiRecommendations, disabled: !acceptTitle && !acceptKeywords && !acceptDescription, className: "accept-button", children: "Accept Selected" })] })] }) })] }));
275
442
  }
276
- ConfigBuilder.propTypes = ConfigBuilderPropTypes;
@@ -4,7 +4,18 @@ import PropTypes from 'prop-types';
4
4
  import { getFontOptions } from './google-fonts';
5
5
  import { WEB_SAFE_FONTS, GENERIC_FAMILIES } from './fonts';
6
6
  import './FontSelector.css';
7
- export function FontSelector({ id, name, label, fontType, required = false, placeholder, value = '', onChange }) {
7
+ FontSelector.propTypes = {
8
+ id: PropTypes.string.isRequired,
9
+ name: PropTypes.string.isRequired,
10
+ label: PropTypes.string.isRequired,
11
+ fontType: PropTypes.oneOf(['google', 'websafe', 'generic']).isRequired,
12
+ required: PropTypes.bool,
13
+ placeholder: PropTypes.string,
14
+ value: PropTypes.string,
15
+ onChange: PropTypes.func,
16
+ };
17
+ export function FontSelector(props) {
18
+ const { id, name, label, fontType, required = false, placeholder, value = '', onChange } = props;
8
19
  const [inputValue, setInputValue] = useState(value);
9
20
  const [googleFonts, setGoogleFonts] = useState([]);
10
21
  const [isLoading, setIsLoading] = useState(false);
@@ -67,7 +78,7 @@ export function FontSelector({ id, name, label, fontType, required = false, plac
67
78
  }
68
79
  return null;
69
80
  };
70
- return (_jsxs("div", { className: "font-selector-container", children: [_jsxs("label", { htmlFor: id, className: "font-selector-label", children: [label, required && _jsx("span", { className: "font-selector-required", children: "*" }), getTooltip() && (_jsx("span", { className: "font-selector-tooltip", title: getTooltip().replace(/\[([^\]]+)\]\([^)]+\)/, '$1'), children: "\uD83D\uDC41\uFE0F" }))] }), _jsxs("div", { className: "font-selector-input-container", children: [_jsx("input", { type: "text", id: id, name: name, value: inputValue, onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder, required: required, autoComplete: "off", className: "font-selector-input" }), showDropdown && filteredOptions.length > 0 && (_jsx("div", { className: "font-selector-dropdown", children: isLoading ? (_jsx("div", { className: "font-selector-loading", children: "Loading fonts..." })) : (filteredOptions.map((option) => (_jsxs("div", { className: "font-selector-option", onClick: () => handleOptionSelect(option), onKeyDown: (e) => {
81
+ return (_jsxs("div", { className: "font-selector-container", children: [_jsxs("label", { htmlFor: id, className: "font-selector-label", children: [label, required && _jsx("span", { className: "font-selector-required", children: "*" }), getTooltip() && (_jsx("span", { className: "font-selector-tooltip", title: getTooltip().replace(/\[([^\]]+)\]\([^)]+\)/, '$1'), children: "\uD83D\uDC41\uFE0F" }))] }), _jsxs("div", { className: "font-selector-input-container", children: [_jsx("input", { type: "text", id: id, name: name, value: inputValue ?? '', onChange: handleInputChange, onFocus: handleFocus, onBlur: handleBlur, placeholder: placeholder ?? undefined, required: required ?? false, autoComplete: "off", className: "font-selector-input" }), showDropdown && filteredOptions.length > 0 && (_jsx("div", { className: "font-selector-dropdown", children: isLoading ? (_jsx("div", { className: "font-selector-loading", children: "Loading fonts..." })) : (filteredOptions.map((option) => (_jsxs("div", { className: "font-selector-option", onClick: () => handleOptionSelect(option), onKeyDown: (e) => {
71
82
  if (e.key === 'Enter' || e.key === ' ') {
72
83
  e.preventDefault();
73
84
  handleOptionSelect(option);
@@ -0,0 +1,67 @@
1
+ {
2
+ "fields": [
3
+ {
4
+ "component": "FormInput",
5
+ "props": {
6
+ "type": "text",
7
+ "id": "name",
8
+ "name": "name",
9
+ "label": "Route Name",
10
+ "required": true,
11
+ "placeholder": "e.g., Home Page",
12
+ "size": "40"
13
+ }
14
+ },
15
+ {
16
+ "component": "FormInput",
17
+ "props": {
18
+ "type": "text",
19
+ "id": "path",
20
+ "name": "path",
21
+ "label": "Path",
22
+ "required": true,
23
+ "placeholder": "e.g., /",
24
+ "size": "40"
25
+ }
26
+ },
27
+ {
28
+ "component": "FormInput",
29
+ "props": {
30
+ "type": "text",
31
+ "id": "title",
32
+ "name": "title",
33
+ "label": "Title",
34
+ "placeholder": "Page title for SEO",
35
+ "size": "40"
36
+ }
37
+ },
38
+ {
39
+ "component": "FormTextarea",
40
+ "props": {
41
+ "id": "description",
42
+ "name": "description",
43
+ "label": "Description",
44
+ "placeholder": "Meta description for SEO"
45
+ }
46
+ },
47
+ {
48
+ "component": "FormTextarea",
49
+ "props": {
50
+ "id": "keywords",
51
+ "name": "keywords",
52
+ "label": "Keywords",
53
+ "placeholder": "Comma-separated keywords for SEO",
54
+ "cols": "40"
55
+ }
56
+ },
57
+ {
58
+ "component": "FormInput",
59
+ "props": {
60
+ "type": "checkbox",
61
+ "id": "hidden",
62
+ "name": "hidden",
63
+ "label": "Hidden Route"
64
+ }
65
+ }
66
+ ]
67
+ }
@@ -8,7 +8,8 @@
8
8
  "name": "name",
9
9
  "label": "Site Name",
10
10
  "required": true,
11
- "placeholder": "Enter site name"
11
+ "placeholder": "Enter site name",
12
+ "size": "40"
12
13
  }
13
14
  },
14
15
  {
@@ -19,7 +20,8 @@
19
20
  "name": "author",
20
21
  "label": "Author",
21
22
  "required": true,
22
- "placeholder": "Enter author name"
23
+ "placeholder": "Enter author name",
24
+ "size": "40"
23
25
  }
24
26
  },
25
27
  {
@@ -41,7 +43,8 @@
41
43
  "name": "url",
42
44
  "label": "Site URL",
43
45
  "required": true,
44
- "placeholder": "https://example.com"
46
+ "placeholder": "https://example.com",
47
+ "size": "40"
45
48
  }
46
49
  },
47
50
  {
@@ -52,7 +55,8 @@
52
55
  "name": "email",
53
56
  "label": "Email",
54
57
  "required": true,
55
- "placeholder": "contact@example.com"
58
+ "placeholder": "contact@example.com",
59
+ "size": "40"
56
60
  }
57
61
  },
58
62
  {
@@ -63,7 +67,8 @@
63
67
  "name": "favicon",
64
68
  "label": "Favicon",
65
69
  "required": true,
66
- "placeholder": "/favicon.ico"
70
+ "placeholder": "/favicon.ico",
71
+ "size": "40"
67
72
  }
68
73
  },
69
74
  {
@@ -74,7 +79,8 @@
74
79
  "name": "favicon_sizes",
75
80
  "label": "Favicon Sizes",
76
81
  "required": true,
77
- "placeholder": "64x64 32x32 24x24 16x16"
82
+ "placeholder": "64x64 32x32 24x24 16x16",
83
+ "size": "40"
78
84
  }
79
85
  },
80
86
  {
@@ -85,7 +91,8 @@
85
91
  "name": "favicon_type",
86
92
  "label": "Favicon Type",
87
93
  "required": true,
88
- "placeholder": "image/x-icon"
94
+ "placeholder": "image/x-icon",
95
+ "size": "40"
89
96
  }
90
97
  },
91
98
  {
@@ -118,7 +125,8 @@
118
125
  "name": "default_locale",
119
126
  "label": "Default Locale",
120
127
  "required": true,
121
- "placeholder": "en"
128
+ "placeholder": "en",
129
+ "size": "40"
122
130
  }
123
131
  },
124
132
  {
@@ -143,7 +151,8 @@
143
151
  "id": "image",
144
152
  "name": "image",
145
153
  "label": "Site Image",
146
- "placeholder": "/images/site-image.jpg"
154
+ "placeholder": "/images/site-image.jpg",
155
+ "size": "40"
147
156
  }
148
157
  },
149
158
  {
@@ -153,7 +162,8 @@
153
162
  "id": "image_height",
154
163
  "name": "image_height",
155
164
  "label": "Image Height",
156
- "placeholder": "512"
165
+ "placeholder": "512",
166
+ "size": "40"
157
167
  }
158
168
  },
159
169
  {
@@ -163,7 +173,8 @@
163
173
  "id": "image_width",
164
174
  "name": "image_width",
165
175
  "label": "Image Width",
166
- "placeholder": "512"
176
+ "placeholder": "512",
177
+ "size": "40"
167
178
  }
168
179
  },
169
180
  {
@@ -173,7 +184,8 @@
173
184
  "id": "telephone",
174
185
  "name": "telephone",
175
186
  "label": "Telephone",
176
- "placeholder": "+1-555-123-4567"
187
+ "placeholder": "+1-555-123-4567",
188
+ "size": "40"
177
189
  }
178
190
  },
179
191
  {
@@ -183,7 +195,8 @@
183
195
  "id": "priceRange",
184
196
  "name": "priceRange",
185
197
  "label": "Price Range",
186
- "placeholder": "$$"
198
+ "placeholder": "$$",
199
+ "size": "40"
187
200
  }
188
201
  },
189
202
  {
@@ -193,7 +206,8 @@
193
206
  "id": "keywords",
194
207
  "name": "keywords",
195
208
  "label": "Keywords",
196
- "placeholder": "web development, design, services"
209
+ "placeholder": "web development, design, services",
210
+ "size": "40"
197
211
  }
198
212
  }
199
213
  ]
@@ -8,7 +8,7 @@
8
8
  "name": "primary-color",
9
9
  "label": "Primary color",
10
10
  "required": true,
11
- "placeholder": "#369"
11
+ "placeholder": "#336699"
12
12
  }
13
13
  },
14
14
  {
@@ -19,7 +19,7 @@
19
19
  "name": "secondary-color",
20
20
  "label": "Secondary color",
21
21
  "required": true,
22
- "placeholder": "#BCD"
22
+ "placeholder": "#BBCCDD"
23
23
  }
24
24
  },
25
25
  {
@@ -30,7 +30,7 @@
30
30
  "name": "accent1-color",
31
31
  "label": "Accent color 1",
32
32
  "required": true,
33
- "placeholder": "#CCC"
33
+ "placeholder": "#CCCCCC"
34
34
  }
35
35
  },
36
36
  {
@@ -41,7 +41,7 @@
41
41
  "name": "accent2-color",
42
42
  "label": "Accent color 2",
43
43
  "required": true,
44
- "placeholder": "#EEE"
44
+ "placeholder": "#EEEEEE"
45
45
  }
46
46
  },
47
47
  {
@@ -8,6 +8,7 @@ import { FormEngine } from './formengine';
8
8
  /* ===== FORM BUILDER =====
9
9
  Display all the components for a Form Builder -
10
10
  Element Buttons, Element Details, and the Form */
11
+ FormBuilder.propTypes = {};
11
12
  export function FormBuilder() {
12
13
  const [formData, setFormData] = useState({ fields: [] });
13
14
  const [fieldFormData, setFieldFormData] = useState({ fields: [] });
@@ -53,7 +53,7 @@ const useFormComponent = (props) => {
53
53
  const customOnChange = props.onChange || (props.parent && props.parent.onChange);
54
54
  if (customOnChange) {
55
55
  try {
56
- customOnChange(value);
56
+ customOnChange(event);
57
57
  }
58
58
  catch {
59
59
  // swallow handler errors to avoid breaking validation flow
@@ -293,7 +293,6 @@ FormRadioOption.propTypes = {
293
293
  function FormRadioOption(props) {
294
294
  const inputProps = setupInputProps(props);
295
295
  const isChecked = props.parent.checked === props.value;
296
- // eslint-disable-next-line @typescript-eslint/no-unused-vars
297
296
  const handleChange = (e) => {
298
297
  if (props.parent.onChange) {
299
298
  props.parent.onChange(props.value);
@@ -374,7 +373,7 @@ export function FormDataList(props) {
374
373
  return (_jsx("datalist", { id: props.id, children: options }));
375
374
  }
376
375
  FormFieldset.propTypes = {};
377
- export function FormFieldset() {
376
+ export function FormFieldset(props) {
378
377
  return (_jsx(_Fragment, {}));
379
378
  }
380
379
  // Re-export FontSelector for use in forms
@@ -1,3 +1,4 @@
1
+ "use client";
1
2
  import { jsx as _jsx } from "react/jsx-runtime";
2
3
  import React from 'react';
3
4
  import PropTypes from 'prop-types';
@@ -14,14 +15,17 @@ FormEngine.propTypes = {
14
15
  onSubmitHandler: PropTypes.func,
15
16
  formData: PropTypes.object.isRequired
16
17
  };
18
+ export function FormEngine(props) {
19
+ return (_jsx(FormValidationProvider, { children: _jsx(FormEngineInner, { ...props }) }));
20
+ }
17
21
  function FormEngineInner(props) {
18
22
  const { validateAllFields } = useFormValidation();
19
23
  function generateFormProps(props) {
20
24
  // GENERATE PROPS TO RENDER THE FORM CONTAINER, INTERNAL FUNCTION
21
25
  if (debug)
22
26
  console.log("Generating Form Props");
23
- const formProps = JSON.parse(JSON.stringify(props));
24
- ['formData', 'onSubmitHandler'].forEach(e => delete formProps[e]);
27
+ // Create a clean copy without non-serializable properties
28
+ const { formData, onSubmitHandler, ...formProps } = props;
25
29
  return formProps;
26
30
  }
27
31
  generateNewFields.propTypes = {
@@ -77,6 +81,3 @@ function FormEngineInner(props) {
77
81
  }
78
82
  return (_jsx("form", { ...generateFormProps(props), onSubmit: (event) => { handleSubmit(event); }, suppressHydrationWarning: true, children: generateNewFields(props) }));
79
83
  }
80
- export function FormEngine(props) {
81
- return (_jsx(FormValidationProvider, { children: _jsx(FormEngineInner, { ...props }) }));
82
- }