@pixelated-tech/components 3.2.14 → 3.3.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 (160) hide show
  1. package/README.COMPONENTS.md +289 -30
  2. package/README.md +36 -28
  3. package/dist/components/general/tab.css +105 -0
  4. package/dist/components/general/tab.js +26 -0
  5. package/dist/components/seo/metadata.components.js +0 -19
  6. package/dist/components/seo/metadata.functions.js +111 -0
  7. package/dist/components/seo/schema-blogposting.functions.js +42 -0
  8. package/dist/components/seo/schema-blogposting.js +0 -46
  9. package/dist/components/seo/sitemap.js +1 -1
  10. package/dist/components/shoppingcart/shoppingcart.components.js +4 -4
  11. package/dist/components/sitebuilder/config/ConfigBuilder.css +266 -0
  12. package/dist/components/sitebuilder/config/ConfigBuilder.js +221 -0
  13. package/dist/components/{pagebuilder → sitebuilder}/form/form.css +55 -34
  14. package/dist/components/sitebuilder/form/formbuilder.js +106 -0
  15. package/dist/components/sitebuilder/form/formcomponents.js +356 -0
  16. package/dist/components/sitebuilder/form/formengine.js +82 -0
  17. package/dist/components/{pagebuilder/form/form.js → sitebuilder/form/formextractor.js} +10 -211
  18. package/dist/components/sitebuilder/form/formutils.js +206 -0
  19. package/dist/components/sitebuilder/form/formvalidator.js +123 -0
  20. package/dist/components/{pagebuilder → sitebuilder/page}/components/ComponentPropertiesForm.js +1 -1
  21. package/dist/components/{pagebuilder → sitebuilder/page}/components/PageBuilderUI.js +2 -2
  22. package/dist/components/{pagebuilder → sitebuilder/page}/components/PageEngine.js +1 -1
  23. package/dist/components/sitebuilder/page/documentation/api-examples/save-route-example.js +37 -0
  24. package/dist/components/{pagebuilder → sitebuilder/page}/lib/componentMap.js +3 -3
  25. package/dist/components/{pagebuilder → sitebuilder/page}/lib/componentMetadata.js +2 -2
  26. package/dist/components/{pagebuilder → sitebuilder/page}/lib/pageStorageContentful.js +2 -2
  27. package/dist/components/sitebuilder/page/lib/pageStorageTypes.js +1 -0
  28. package/dist/data/form.json +18 -18
  29. package/dist/data/shipping.to.json +9 -9
  30. package/dist/data/siteinfo-form.json +200 -0
  31. package/dist/index.js +29 -21
  32. package/dist/index.server.js +24 -17
  33. package/dist/types/components/general/semantic.d.ts +3 -3
  34. package/dist/types/components/general/tab.d.ts +18 -0
  35. package/dist/types/components/general/tab.d.ts.map +1 -0
  36. package/dist/types/components/seo/metadata.components.d.ts +0 -17
  37. package/dist/types/components/seo/metadata.components.d.ts.map +1 -1
  38. package/dist/types/components/seo/{metadata.d.ts → metadata.functions.d.ts} +15 -1
  39. package/dist/types/components/seo/metadata.functions.d.ts.map +1 -0
  40. package/dist/types/components/seo/schema-blogposting.d.ts +1 -25
  41. package/dist/types/components/seo/schema-blogposting.d.ts.map +1 -1
  42. package/dist/types/components/seo/schema-blogposting.functions.d.ts +26 -0
  43. package/dist/types/components/seo/schema-blogposting.functions.d.ts.map +1 -0
  44. package/dist/types/components/seo/sitemap.d.ts.map +1 -1
  45. package/dist/types/components/shoppingcart/shoppingcart.components.d.ts +1 -1
  46. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts +86 -0
  47. package/dist/types/components/sitebuilder/config/ConfigBuilder.d.ts.map +1 -0
  48. package/dist/types/components/sitebuilder/form/formbuilder.d.ts +11 -0
  49. package/dist/types/components/sitebuilder/form/formbuilder.d.ts.map +1 -0
  50. package/dist/types/components/{pagebuilder → sitebuilder}/form/formcomponents.d.ts +12 -16
  51. package/dist/types/components/sitebuilder/form/formcomponents.d.ts.map +1 -0
  52. package/dist/types/components/{pagebuilder/form/form.submit.d.ts → sitebuilder/form/formemailer.d.ts} +1 -1
  53. package/dist/types/components/sitebuilder/form/formemailer.d.ts.map +1 -0
  54. package/dist/types/components/sitebuilder/form/formengine.d.ts +14 -0
  55. package/dist/types/components/sitebuilder/form/formengine.d.ts.map +1 -0
  56. package/dist/types/components/sitebuilder/form/formextractor.d.ts +25 -0
  57. package/dist/types/components/sitebuilder/form/formextractor.d.ts.map +1 -0
  58. package/dist/types/components/{pagebuilder/form/formvalidations.d.ts → sitebuilder/form/formfieldvalidations.d.ts} +1 -1
  59. package/dist/types/components/sitebuilder/form/formfieldvalidations.d.ts.map +1 -0
  60. package/dist/types/components/sitebuilder/form/formtypes.d.ts +66 -0
  61. package/dist/types/components/sitebuilder/form/formtypes.d.ts.map +1 -0
  62. package/dist/types/components/sitebuilder/form/formutils.d.ts +20 -0
  63. package/dist/types/components/sitebuilder/form/formutils.d.ts.map +1 -0
  64. package/dist/types/components/sitebuilder/form/formvalidator.d.ts +20 -0
  65. package/dist/types/components/sitebuilder/form/formvalidator.d.ts.map +1 -0
  66. package/dist/types/components/sitebuilder/page/components/ComponentPropertiesForm.d.ts.map +1 -0
  67. package/dist/types/components/sitebuilder/page/components/ComponentSelector.d.ts.map +1 -0
  68. package/dist/types/components/sitebuilder/page/components/ComponentTree.d.ts.map +1 -0
  69. package/dist/types/components/{pagebuilder → sitebuilder/page}/components/PageBuilderUI.d.ts +1 -1
  70. package/dist/types/components/sitebuilder/page/components/PageBuilderUI.d.ts.map +1 -0
  71. package/dist/types/components/sitebuilder/page/components/PageEngine.d.ts.map +1 -0
  72. package/dist/types/components/sitebuilder/page/components/SaveLoadSection.d.ts.map +1 -0
  73. package/dist/types/components/sitebuilder/page/documentation/api-examples/save-route-example.d.ts +6 -0
  74. package/dist/types/components/sitebuilder/page/documentation/api-examples/save-route-example.d.ts.map +1 -0
  75. package/dist/types/components/sitebuilder/page/lib/componentGeneration.d.ts.map +1 -0
  76. package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/componentMap.d.ts +3 -3
  77. package/dist/types/components/sitebuilder/page/lib/componentMap.d.ts.map +1 -0
  78. package/dist/types/components/sitebuilder/page/lib/componentMetadata.d.ts.map +1 -0
  79. package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/pageStorageContentful.d.ts +1 -1
  80. package/dist/types/components/sitebuilder/page/lib/pageStorageContentful.d.ts.map +1 -0
  81. package/dist/types/components/sitebuilder/page/lib/pageStorageLocal.d.ts.map +1 -0
  82. package/dist/types/components/sitebuilder/page/lib/pageStorageTypes.d.ts.map +1 -0
  83. package/dist/types/components/sitebuilder/page/lib/propTypeIntrospection.d.ts.map +1 -0
  84. package/dist/types/components/sitebuilder/page/lib/types.d.ts.map +1 -0
  85. package/dist/types/components/sitebuilder/page/lib/usePageBuilder.d.ts.map +1 -0
  86. package/dist/types/index.d.ts +29 -20
  87. package/dist/types/index.server.d.ts +23 -16
  88. package/dist/types/stories/general/tab.stories.d.ts +45 -0
  89. package/dist/types/stories/general/tab.stories.d.ts.map +1 -0
  90. package/dist/types/stories/seo/seo.metadata.stories.d.ts +1 -1
  91. package/dist/types/stories/seo/seo.metadata.stories.d.ts.map +1 -1
  92. package/dist/types/stories/sitebuilder/configbuilder.stories.d.ts +48 -0
  93. package/dist/types/stories/sitebuilder/configbuilder.stories.d.ts.map +1 -0
  94. package/dist/types/stories/{pagebuilder → sitebuilder}/form-builder.stories.d.ts +1 -1
  95. package/dist/types/stories/sitebuilder/form-builder.stories.d.ts.map +1 -0
  96. package/dist/types/stories/{pagebuilder → sitebuilder}/form-engine.stories.d.ts +1 -1
  97. package/dist/types/stories/sitebuilder/form-engine.stories.d.ts.map +1 -0
  98. package/dist/types/stories/{pagebuilder → sitebuilder}/form-extractor.stories.d.ts +1 -1
  99. package/dist/types/stories/sitebuilder/form-extractor.stories.d.ts.map +1 -0
  100. package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.stories.d.ts +1 -1
  101. package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.stories.d.ts.map +1 -1
  102. package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.usageguide.stories.d.ts +1 -1
  103. package/dist/types/stories/{pagebuilder → sitebuilder}/pagebuilder.usageguide.stories.d.ts.map +1 -1
  104. package/dist/types/stories/{pagebuilder → sitebuilder}/pageengine.stories.d.ts +1 -1
  105. package/dist/types/stories/{pagebuilder → sitebuilder}/pageengine.stories.d.ts.map +1 -1
  106. package/dist/types/tests/configbuilder.test.d.ts +2 -0
  107. package/dist/types/tests/configbuilder.test.d.ts.map +1 -0
  108. package/dist/types/tests/tab.test.d.ts +2 -0
  109. package/dist/types/tests/tab.test.d.ts.map +1 -0
  110. package/package.json +5 -4
  111. package/dist/components/pagebuilder/form/formcomponents.js +0 -359
  112. package/dist/components/seo/metadata.js +0 -108
  113. package/dist/types/components/pagebuilder/components/ComponentPropertiesForm.d.ts.map +0 -1
  114. package/dist/types/components/pagebuilder/components/ComponentSelector.d.ts.map +0 -1
  115. package/dist/types/components/pagebuilder/components/ComponentTree.d.ts.map +0 -1
  116. package/dist/types/components/pagebuilder/components/PageBuilderUI.d.ts.map +0 -1
  117. package/dist/types/components/pagebuilder/components/PageEngine.d.ts.map +0 -1
  118. package/dist/types/components/pagebuilder/components/SaveLoadSection.d.ts.map +0 -1
  119. package/dist/types/components/pagebuilder/form/form.d.ts +0 -46
  120. package/dist/types/components/pagebuilder/form/form.d.ts.map +0 -1
  121. package/dist/types/components/pagebuilder/form/form.submit.d.ts.map +0 -1
  122. package/dist/types/components/pagebuilder/form/formcomponents.d.ts.map +0 -1
  123. package/dist/types/components/pagebuilder/form/formvalidations.d.ts.map +0 -1
  124. package/dist/types/components/pagebuilder/lib/componentGeneration.d.ts.map +0 -1
  125. package/dist/types/components/pagebuilder/lib/componentMap.d.ts.map +0 -1
  126. package/dist/types/components/pagebuilder/lib/componentMetadata.d.ts.map +0 -1
  127. package/dist/types/components/pagebuilder/lib/pageStorageContentful.d.ts.map +0 -1
  128. package/dist/types/components/pagebuilder/lib/pageStorageLocal.d.ts.map +0 -1
  129. package/dist/types/components/pagebuilder/lib/pageStorageTypes.d.ts.map +0 -1
  130. package/dist/types/components/pagebuilder/lib/propTypeIntrospection.d.ts.map +0 -1
  131. package/dist/types/components/pagebuilder/lib/types.d.ts.map +0 -1
  132. package/dist/types/components/pagebuilder/lib/usePageBuilder.d.ts.map +0 -1
  133. package/dist/types/components/seo/metadata.d.ts.map +0 -1
  134. package/dist/types/stories/pagebuilder/form-builder.stories.d.ts.map +0 -1
  135. package/dist/types/stories/pagebuilder/form-engine.stories.d.ts.map +0 -1
  136. package/dist/types/stories/pagebuilder/form-extractor.stories.d.ts.map +0 -1
  137. /package/dist/components/{pagebuilder/form/form.submit.js → sitebuilder/form/formemailer.js} +0 -0
  138. /package/dist/components/{pagebuilder/form/formvalidations.js → sitebuilder/form/formfieldvalidations.js} +0 -0
  139. /package/dist/components/{pagebuilder/lib/pageStorageTypes.js → sitebuilder/form/formtypes.js} +0 -0
  140. /package/dist/components/{pagebuilder → sitebuilder/page}/components/ComponentSelector.js +0 -0
  141. /package/dist/components/{pagebuilder → sitebuilder/page}/components/ComponentTree.js +0 -0
  142. /package/dist/components/{pagebuilder → sitebuilder/page}/components/SaveLoadSection.js +0 -0
  143. /package/dist/components/{pagebuilder → sitebuilder/page}/components/pagebuilder.scss +0 -0
  144. /package/dist/components/{pagebuilder → sitebuilder/page}/lib/componentGeneration.js +0 -0
  145. /package/dist/components/{pagebuilder → sitebuilder/page}/lib/pageStorageLocal.js +0 -0
  146. /package/dist/components/{pagebuilder → sitebuilder/page}/lib/propTypeIntrospection.js +0 -0
  147. /package/dist/components/{pagebuilder → sitebuilder/page}/lib/types.js +0 -0
  148. /package/dist/components/{pagebuilder → sitebuilder/page}/lib/usePageBuilder.js +0 -0
  149. /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/ComponentPropertiesForm.d.ts +0 -0
  150. /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/ComponentSelector.d.ts +0 -0
  151. /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/ComponentTree.d.ts +0 -0
  152. /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/PageEngine.d.ts +0 -0
  153. /package/dist/types/components/{pagebuilder → sitebuilder/page}/components/SaveLoadSection.d.ts +0 -0
  154. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/componentGeneration.d.ts +0 -0
  155. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/componentMetadata.d.ts +0 -0
  156. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/pageStorageLocal.d.ts +0 -0
  157. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/pageStorageTypes.d.ts +0 -0
  158. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/propTypeIntrospection.d.ts +0 -0
  159. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/types.d.ts +0 -0
  160. /package/dist/types/components/{pagebuilder → sitebuilder/page}/lib/usePageBuilder.d.ts +0 -0
@@ -0,0 +1,206 @@
1
+ // Shared utility functions for form components
2
+ import { generateKey, capitalize, attributeMap } from '../../utilities/functions';
3
+ export const debug = false;
4
+ /**
5
+ * Maps input type to form component name
6
+ */
7
+ export function mapTypeToComponent(myType) {
8
+ if (debug)
9
+ console.log("Mapping Type Field to Component");
10
+ let myComponent = (["button"].includes(myType)) ? 'FormButton' :
11
+ (["checkbox"].includes(myType)) ? 'FormCheckbox' :
12
+ (["datalist"].includes(myType)) ? 'FormDataList' :
13
+ (["radio"].includes(myType)) ? 'FormRadio' :
14
+ (["select"].includes(myType)) ? 'FormSelect' :
15
+ (["textarea"].includes(myType)) ? 'FormTextarea' :
16
+ "FormInput";
17
+ return myComponent;
18
+ }
19
+ /**
20
+ * Generates field JSON for form building
21
+ */
22
+ export function generateFieldJSON(component, type) {
23
+ const form = {};
24
+ form.fields = [];
25
+ // Common fields for all components
26
+ const commonFields = [
27
+ {
28
+ component: 'FormInput',
29
+ props: {
30
+ label: 'ID : ',
31
+ name: 'id',
32
+ id: 'id',
33
+ type: 'text',
34
+ required: true
35
+ }
36
+ },
37
+ {
38
+ component: 'FormInput',
39
+ props: {
40
+ label: 'Label : ',
41
+ name: 'label',
42
+ id: 'label',
43
+ type: 'text'
44
+ }
45
+ }
46
+ ];
47
+ // Type-specific fields
48
+ let typeSpecificFields = [];
49
+ if (component === 'FormSelect') {
50
+ typeSpecificFields = [
51
+ {
52
+ component: 'FormTextarea',
53
+ props: {
54
+ label: 'Options (JSON) : ',
55
+ name: 'options',
56
+ id: 'options',
57
+ rows: 5,
58
+ placeholder: '[{"value": "option1", "text": "Option 1"}, {"value": "option2", "text": "Option 2"}]'
59
+ }
60
+ }
61
+ ];
62
+ }
63
+ else if (component === 'FormRadio' || component === 'FormCheckbox') {
64
+ typeSpecificFields = [
65
+ {
66
+ component: 'FormInput',
67
+ props: {
68
+ label: 'Value : ',
69
+ name: 'value',
70
+ id: 'value',
71
+ type: 'text'
72
+ }
73
+ },
74
+ {
75
+ component: 'FormTextarea',
76
+ props: {
77
+ label: 'Options (JSON) : ',
78
+ name: 'options',
79
+ id: 'options',
80
+ rows: 5,
81
+ placeholder: '[{"value": "option1", "text": "Option 1"}, {"value": "option2", "text": "Option 2"}]'
82
+ }
83
+ }
84
+ ];
85
+ }
86
+ else {
87
+ typeSpecificFields = [
88
+ {
89
+ component: 'FormInput',
90
+ props: {
91
+ label: 'Type : ',
92
+ name: 'type',
93
+ id: 'type',
94
+ type: 'text',
95
+ value: type,
96
+ list: 'inputTypes'
97
+ }
98
+ },
99
+ {
100
+ component: 'FormInput',
101
+ props: {
102
+ label: 'Placeholder : ',
103
+ name: 'placeholder',
104
+ id: 'placeholder',
105
+ type: 'text'
106
+ }
107
+ },
108
+ {
109
+ component: 'FormInput',
110
+ props: {
111
+ label: 'Value : ',
112
+ name: 'value',
113
+ id: 'value',
114
+ type: 'text'
115
+ }
116
+ }
117
+ ];
118
+ }
119
+ // Add required field
120
+ const requiredField = {
121
+ component: 'FormCheckbox',
122
+ props: {
123
+ label: 'Required : ',
124
+ name: 'required',
125
+ id: 'required',
126
+ value: 'required'
127
+ }
128
+ };
129
+ // Add validation field
130
+ const validationField = {
131
+ component: 'FormInput',
132
+ props: {
133
+ label: 'Validate : ',
134
+ name: 'validate',
135
+ id: 'validate',
136
+ type: 'text',
137
+ list: 'validationTypes',
138
+ placeholder: 'isValidEmailAddress, isValidUrl, etc.'
139
+ }
140
+ };
141
+ // Combine all fields
142
+ let i = 0;
143
+ [...commonFields, ...typeSpecificFields, requiredField, validationField].forEach(field => {
144
+ form.fields[i] = field;
145
+ i++;
146
+ });
147
+ // Add submit button
148
+ const addButton = {
149
+ component: 'FormButton',
150
+ props: {
151
+ label: 'Add ' + component,
152
+ type: 'submit',
153
+ id: 'Add ' + component,
154
+ text: 'Add ' + component
155
+ }
156
+ };
157
+ form.fields[i] = addButton;
158
+ return form;
159
+ }
160
+ /**
161
+ * Generates type selection field for form builder
162
+ */
163
+ export function generateTypeField() {
164
+ const form = {};
165
+ const typeField = {
166
+ component: 'FormInput',
167
+ props: {
168
+ label: 'Type : ',
169
+ name: 'type',
170
+ id: 'type',
171
+ type: 'text',
172
+ list: 'inputTypes'
173
+ }
174
+ };
175
+ const addButton = {
176
+ component: 'FormButton',
177
+ props: {
178
+ label: 'Build',
179
+ type: 'submit',
180
+ id: 'build',
181
+ text: '=== Build ==='
182
+ }
183
+ };
184
+ form.fields = [typeField, addButton];
185
+ return form;
186
+ }
187
+ /**
188
+ * Converts numeric string props to numbers
189
+ */
190
+ export function convertNumericProps(props) {
191
+ const numericProps = ['maxLength', 'minLength', 'rows', 'cols', 'size', 'step'];
192
+ numericProps.forEach(prop => {
193
+ if (props[prop] !== undefined &&
194
+ props[prop] !== null &&
195
+ props[prop] !== '') {
196
+ if (typeof props[prop] === 'string') {
197
+ const num = Number(props[prop]);
198
+ if (!isNaN(num)) {
199
+ props[prop] = num;
200
+ }
201
+ }
202
+ }
203
+ });
204
+ }
205
+ // Re-export utilities from main utilities file for convenience
206
+ export { generateKey, capitalize, attributeMap };
@@ -0,0 +1,123 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext, useState, useCallback } from 'react';
3
+ import * as FVF from './formfieldvalidations';
4
+ /**
5
+ * Centralized field validation service
6
+ */
7
+ export async function validateField(fieldProps, event) {
8
+ const errors = [];
9
+ let isValid = true;
10
+ // 1. Field-specific validation (e.g., isValidEmailAddress, isValidUrl, etc.)
11
+ if (fieldProps.validate && typeof fieldProps.validate === "string" && fieldProps.validate in FVF) {
12
+ const fieldValid = FVF[fieldProps.validate](event.target);
13
+ if (!fieldValid) {
14
+ isValid = false;
15
+ errors.push(`${fieldProps.validate} validation failed`);
16
+ }
17
+ }
18
+ // 2. Parent validation (for grouped/nested fields)
19
+ if (fieldProps.parent?.validate && typeof fieldProps.parent.validate === "string" && fieldProps.parent.validate in FVF) {
20
+ const parentValid = FVF[fieldProps.parent.validate](event.target);
21
+ if (!parentValid) {
22
+ isValid = false;
23
+ errors.push(`Parent ${fieldProps.parent.validate} validation failed`);
24
+ }
25
+ }
26
+ // 3. HTML5 required validation
27
+ if (fieldProps.required) {
28
+ const requiredValid = event.target.checkValidity();
29
+ if (!requiredValid) {
30
+ isValid = false;
31
+ errors.push('Required field validation failed');
32
+ }
33
+ }
34
+ // 4. Required not empty check
35
+ if (fieldProps.required && !event.target.value) {
36
+ isValid = false;
37
+ errors.push('Field cannot be empty');
38
+ }
39
+ // 5. Custom validation rules can be added here
40
+ // Example: minimum length, maximum length, pattern matching, etc.
41
+ return { isValid, errors };
42
+ }
43
+ /**
44
+ * Form validation context for managing form-wide validation state
45
+ */
46
+ const FormValidationContext = createContext(null);
47
+ export function useFormValidation() {
48
+ const context = useContext(FormValidationContext);
49
+ if (!context) {
50
+ throw new Error('useFormValidation must be used within FormValidationProvider');
51
+ }
52
+ return context;
53
+ }
54
+ export function FormValidationProvider({ children }) {
55
+ const [fieldValidity, setFieldValidity] = useState({});
56
+ const [fieldErrors, setFieldErrors] = useState({});
57
+ const validateField = useCallback((fieldId, isValid, errors) => {
58
+ setFieldValidity(prev => ({ ...prev, [fieldId]: isValid }));
59
+ setFieldErrors(prev => ({ ...prev, [fieldId]: errors }));
60
+ }, []);
61
+ const validateAllFields = useCallback(() => {
62
+ return Object.values(fieldValidity).every(valid => valid === true);
63
+ }, [fieldValidity]);
64
+ const resetValidation = useCallback(() => {
65
+ setFieldValidity({});
66
+ setFieldErrors({});
67
+ }, []);
68
+ const isFormValid = Object.values(fieldValidity).every(valid => valid === true);
69
+ const value = {
70
+ fieldValidity,
71
+ fieldErrors,
72
+ isFormValid,
73
+ validateField,
74
+ validateAllFields,
75
+ resetValidation
76
+ };
77
+ return (_jsx(FormValidationContext.Provider, { value: value, children: children }));
78
+ }
79
+ /**
80
+ * Cross-field validation functions
81
+ */
82
+ export function validatePasswordMatch(formData) {
83
+ const password = formData.password?.value;
84
+ const confirm = formData.passwordConfirm?.value;
85
+ if (!password || !confirm) {
86
+ return { isValid: true, errors: [] }; // Not required fields
87
+ }
88
+ const isValid = password === confirm;
89
+ return {
90
+ isValid,
91
+ errors: isValid ? [] : ['Passwords do not match']
92
+ };
93
+ }
94
+ export function validateAgeRestriction(formData) {
95
+ const age = parseInt(formData.age?.value);
96
+ const hasParentalConsent = formData.parentalConsent?.value === 'yes';
97
+ if (isNaN(age) || age >= 13) {
98
+ return { isValid: true, errors: [] };
99
+ }
100
+ const isValid = hasParentalConsent;
101
+ return {
102
+ isValid,
103
+ errors: isValid ? [] : ['Parental consent required for users under 13']
104
+ };
105
+ }
106
+ /**
107
+ * Form-level validation orchestrator
108
+ */
109
+ export function validateFormLevel(formData, customValidators = []) {
110
+ const allErrors = [];
111
+ let isValid = true;
112
+ // Run custom cross-field validations
113
+ const defaultValidators = [validatePasswordMatch, validateAgeRestriction];
114
+ const allValidators = [...defaultValidators, ...customValidators];
115
+ for (const validator of allValidators) {
116
+ const result = validator(formData);
117
+ if (!result.isValid) {
118
+ isValid = false;
119
+ allErrors.push(...result.errors);
120
+ }
121
+ }
122
+ return { isValid, errors: allErrors };
123
+ }
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import PropTypes from 'prop-types';
3
3
  // import { PageSectionHeader } from '../../general/pixelated.headers';
4
- import { FormEngine } from '../form/form';
4
+ import { FormEngine } from '../../form/formengine';
5
5
  /**
6
6
  * ComponentPropertiesForm - Displays the component properties form
7
7
  * Shows FormEngine when component is selected, placeholder otherwise
@@ -1,13 +1,13 @@
1
1
  "use client";
2
2
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
3
  import React from 'react';
4
- import { PageSectionHeader } from '../../general/semantic';
4
+ import { PageSectionHeader } from '../../../general/semantic';
5
5
  import { usePageBuilder } from '../lib/usePageBuilder';
6
6
  import { ComponentSelector } from '../components/ComponentSelector';
7
7
  import { ComponentPropertiesForm } from '../components/ComponentPropertiesForm';
8
8
  import { PageEngine } from '../components/PageEngine';
9
9
  import { SaveLoadSection } from '../components/SaveLoadSection';
10
- import "../../../css/pixelated.global.css";
10
+ import "../../../../css/pixelated.global.css";
11
11
  import './pagebuilder.scss';
12
12
  /**
13
13
  * PageBuilderUI - Main orchestrator component
@@ -1,7 +1,7 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx, Fragment as _Fragment } from "react/jsx-runtime";
2
2
  import React from 'react';
3
3
  import PropTypes from 'prop-types';
4
- import { generateKey } from '../../utilities/functions';
4
+ import { generateKey } from '../../../utilities/functions';
5
5
  import { componentMap, layoutComponents } from '../lib/componentMap';
6
6
  import './pagebuilder.scss';
7
7
  /**
@@ -0,0 +1,37 @@
1
+ import { NextResponse } from 'next/server';
2
+ // Choose ONE of these imports:
3
+ // Option 1: File-based storage
4
+ import { savePage } from '../../lib/pageStorageLocal';
5
+ // Option 2: Contentful storage
6
+ // import { savePage } from '@pixelated-tech/components/server';
7
+ // import type { ContentfulConfig } from '@pixelated-tech/components/server';
8
+ export async function POST(request) {
9
+ try {
10
+ const body = await request.json();
11
+ const { name, data } = body;
12
+ if (!name || !data) {
13
+ return NextResponse.json({
14
+ success: false,
15
+ message: 'Name and data are required'
16
+ }, { status: 400 });
17
+ }
18
+ // ===== OPTION 1: File-based storage =====
19
+ const result = await savePage(name, data);
20
+ // ===== OPTION 2: Contentful storage =====
21
+ // ===== OPTION 2: Contentful storage (recommended when using the unified PIXELATED config blob) =====
22
+ // The app reads the unified config on the server via `getFullPixelatedConfig()` which
23
+ // sources values from `PIXELATED_CONFIG_JSON` or `PIXELATED_CONFIG_B64`.
24
+ // Example (server-side):
25
+ // import { getFullPixelatedConfig } from '@pixelated-tech/components/server';
26
+ // const cfg = getFullPixelatedConfig();
27
+ // const contentfulConfig = cfg.contentful;
28
+ // const result = await savePage(name, data, contentfulConfig);
29
+ return NextResponse.json(result);
30
+ }
31
+ catch (error) {
32
+ return NextResponse.json({
33
+ success: false,
34
+ message: `Invalid request: ${error}`
35
+ }, { status: 400 });
36
+ }
37
+ }
@@ -1,6 +1,6 @@
1
- import { PageTitleHeader, PageSectionHeader } from "../../general/semantic";
2
- import { Callout } from "../../callout/callout";
3
- import { PageSection, PageGridItem, PageFlexItem } from "../../general/semantic";
1
+ import { PageTitleHeader, PageSectionHeader } from "../../../general/semantic";
2
+ import { Callout } from "../../../callout/callout";
3
+ import { PageSection, PageGridItem, PageFlexItem } from "../../../general/semantic";
4
4
  /**
5
5
  * Component registry and constants
6
6
  */
@@ -6,8 +6,8 @@
6
6
  * used in PropTypes, generate TypeScript types via InferProps, and provide
7
7
  * runtime values for form generation.
8
8
  */
9
- import { variants, shapes, layouts, directions } from "../../callout/callout";
10
- import { layoutTypes, autoFlowValues, flexDirections, flexWraps, justifyContentValues, alignItemsValues } from "../../general/semantic";
9
+ import { variants, shapes, layouts, directions } from "../../../callout/callout";
10
+ import { layoutTypes, autoFlowValues, flexDirections, flexWraps, justifyContentValues, alignItemsValues } from "../../../general/semantic";
11
11
  export const componentMetadata = {
12
12
  'Callout': {
13
13
  variant: {
@@ -3,8 +3,8 @@
3
3
  *
4
4
  * Uses generic Contentful management functions with PageBuilder-specific logic
5
5
  */
6
- import { createEntry, updateEntry, deleteEntry, searchEntriesByField } from '../../cms/contentful.management';
7
- import { getContentfulEntriesByType } from '../../cms/contentful.delivery';
6
+ import { createEntry, updateEntry, deleteEntry, searchEntriesByField } from '../../../cms/contentful.management';
7
+ import { getContentfulEntriesByType } from '../../../cms/contentful.delivery';
8
8
  const CONTENT_TYPE = 'page';
9
9
  /**
10
10
  * Validate page name format
@@ -8,7 +8,7 @@
8
8
  "defaultValue": "",
9
9
  "autoComplete": "honorific-prefix",
10
10
  "multiple": null,
11
- "required": "required",
11
+ "required": true,
12
12
  "display": "horizontal",
13
13
  "label": "Title : ",
14
14
  "options": [
@@ -31,7 +31,7 @@
31
31
  "autoComplete": "given-name",
32
32
  "size": "40",
33
33
  "display": "horizontal",
34
- "required": "required",
34
+ "required": true,
35
35
  "label": "First Name : ",
36
36
  "tooltip": "Please type in your First Name"
37
37
  }
@@ -46,7 +46,7 @@
46
46
  "autoComplete": "family-name",
47
47
  "size": "40",
48
48
  "display": "horizontal",
49
- "required": "required",
49
+ "required": true,
50
50
  "label": "Last Name : "
51
51
  }
52
52
  },
@@ -60,7 +60,7 @@
60
60
  "autoComplete": "street-address",
61
61
  "size": "40",
62
62
  "display": "horizontal",
63
- "required": "required",
63
+ "required": true,
64
64
  "label": "Street Address : "
65
65
  }
66
66
  },
@@ -74,7 +74,7 @@
74
74
  "autoComplete": "address-level2",
75
75
  "size": "40",
76
76
  "display": "horizontal",
77
- "required": "required",
77
+ "required": true,
78
78
  "label": "City : "
79
79
  }
80
80
  },
@@ -87,7 +87,7 @@
87
87
  "defaultValue": ["NJ", "SC"],
88
88
  "autoComplete": "address-level1",
89
89
  "multiple": "multiple",
90
- "required": "required",
90
+ "required": true,
91
91
  "display": "horizontal",
92
92
  "label": "State : ",
93
93
  "tooltip": "Please select your State",
@@ -156,7 +156,7 @@
156
156
  "autoComplete": "postal-code",
157
157
  "size": "40",
158
158
  "display": "horizontal",
159
- "required": "required",
159
+ "required": true,
160
160
  "label": "Zip Code : ",
161
161
  "validate": "isValidUSZipCode"
162
162
  }
@@ -171,7 +171,7 @@
171
171
  "autoComplete": "tel",
172
172
  "size": "40",
173
173
  "display": "horizontal",
174
- "required": "required",
174
+ "required": true,
175
175
  "label": "Phone Number : ",
176
176
  "validate": "isValidUSPhoneNumber"
177
177
  }
@@ -186,7 +186,7 @@
186
186
  "autoComplete": "bday",
187
187
  "size": "40",
188
188
  "display": "horizontal",
189
- "required": "required",
189
+ "required": true,
190
190
  "label": "Birthday : ",
191
191
  "validate": "isValidDate"
192
192
  }
@@ -198,7 +198,7 @@
198
198
  "name": "age",
199
199
  "defaultValue": "",
200
200
  "multiple": null,
201
- "required": "required",
201
+ "required": true,
202
202
  "display": "horizontal",
203
203
  "label": "Age : ",
204
204
  "options": [
@@ -223,7 +223,7 @@
223
223
  "name": "generation",
224
224
  "defaultValue": null,
225
225
  "multiple": null,
226
- "required": "required",
226
+ "required": true,
227
227
  "display": "horizontal",
228
228
  "label": "Generation : ",
229
229
  "options": [
@@ -248,7 +248,7 @@
248
248
  "autoComplete": "email",
249
249
  "size": "40",
250
250
  "display": "horizontal",
251
- "required": "required",
251
+ "required": true,
252
252
  "label": "Email Address : ",
253
253
  "validate": "isValidEmailAddress"
254
254
  }
@@ -261,7 +261,7 @@
261
261
  "autoComplete": "sex",
262
262
  "label": "Gender : ",
263
263
  "display": "horizontal",
264
- "required": "required",
264
+ "required": true,
265
265
  "validate": "isOneRadioSelected",
266
266
  "tooltip": "Please select your gender",
267
267
  "options": [
@@ -296,7 +296,7 @@
296
296
  "autoComplete": "organization-title",
297
297
  "size": "40",
298
298
  "display": "horizontal",
299
- "required": "required",
299
+ "required": true,
300
300
  "label": "Job Title : "
301
301
  }
302
302
  },
@@ -310,7 +310,7 @@
310
310
  "autoComplete": "organization",
311
311
  "size": "40",
312
312
  "display": "horizontal",
313
- "required": "required",
313
+ "required": true,
314
314
  "label": "Company : "
315
315
  }
316
316
  },
@@ -326,7 +326,7 @@
326
326
  "min": "10000",
327
327
  "max": "1000000",
328
328
  "step": "1000",
329
- "required": "required",
329
+ "required": true,
330
330
  "label": "Salary : "
331
331
  }
332
332
  },
@@ -339,7 +339,7 @@
339
339
  "defaultValue": null,
340
340
  "size": "40",
341
341
  "display": "horizontal",
342
- "required": "required",
342
+ "required": true,
343
343
  "label": "LinkedIn URL : ",
344
344
  "validate": "isValidUrl"
345
345
  }
@@ -353,7 +353,7 @@
353
353
  "cols": "40",
354
354
  "defaultValue": null,
355
355
  "display": "horizontal",
356
- "required": "required",
356
+ "required": true,
357
357
  "label": "Comments : ",
358
358
  "tooltip": "Please enter your comments"
359
359
  }
@@ -11,7 +11,7 @@
11
11
  "autoComplete": "name",
12
12
  "size": "40",
13
13
  "display": "horizontal",
14
- "required": "required",
14
+ "required": true,
15
15
  "label": "Name : ",
16
16
  "tooltip": "Please enter your First and Last Name"
17
17
  }
@@ -26,7 +26,7 @@
26
26
  "autoComplete": "street-address",
27
27
  "size": "40",
28
28
  "display": "horizontal",
29
- "required": "required",
29
+ "required": true,
30
30
  "label": "Street Address : ",
31
31
  "tooltip": "Please enter your Street Address"
32
32
  }
@@ -41,7 +41,7 @@
41
41
  "autoComplete": "address-level2",
42
42
  "size": "40",
43
43
  "display": "horizontal",
44
- "required": "required",
44
+ "required": true,
45
45
  "label": "City : ",
46
46
  "tooltip": "Please enter your City"
47
47
  }
@@ -55,7 +55,7 @@
55
55
  "placeholder": "State",
56
56
  "autoComplete": "address-level1",
57
57
  "multiple": null,
58
- "required": "required",
58
+ "required": true,
59
59
  "display": "horizontal",
60
60
  "label": "State : ",
61
61
  "tooltip": "Please select your State",
@@ -124,7 +124,7 @@
124
124
  "autoComplete": "postal-code",
125
125
  "size": "40",
126
126
  "display": "horizontal",
127
- "required": "required",
127
+ "required": true,
128
128
  "label": "Zip Code : ",
129
129
  "tooltip": "Please enter your Zip Code",
130
130
  "validate": "isValidUSZipCode"
@@ -139,7 +139,7 @@
139
139
  "placeholder": "Country",
140
140
  "autoComplete": "country",
141
141
  "multiple": null,
142
- "required": "required",
142
+ "required": true,
143
143
  "display": "horizontal",
144
144
  "label": "Country : ",
145
145
  "tooltip": "Please select your Country",
@@ -353,7 +353,7 @@
353
353
  "autoComplete": "tel",
354
354
  "size": "40",
355
355
  "display": "horizontal",
356
- "required": "required",
356
+ "required": true,
357
357
  "label": "Phone Number : ",
358
358
  "tooltip": "Please enter your Phone Number",
359
359
  "validate": "isValidUSPhoneNumber"
@@ -369,7 +369,7 @@
369
369
  "autoComplete": "email",
370
370
  "size": "40",
371
371
  "display": "horizontal",
372
- "required": "required",
372
+ "required": true,
373
373
  "label": "Email Address : ",
374
374
  "tooltip": "Please enter your Email Address",
375
375
  "validate": "isValidEmailAddress"
@@ -397,7 +397,7 @@
397
397
  "name": "shippingMethod",
398
398
  "label": "Shipping Method : ",
399
399
  "display": "vertical",
400
- "required": "required",
400
+ "required": true,
401
401
  "validate": "isOneRadioSelected",
402
402
  "tooltip": "Please select your Shipping Method",
403
403
  "options": [