iq-line-form-builder-renderer 1.0.13 → 1.0.15
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.
- package/README.md +2 -34
- package/dist/{fieldApiTransformer-DpvHi_69.mjs → fieldApiTransformer-Bx1Es8H0.mjs} +2 -2
- package/dist/{fieldApiTransformer-DpvHi_69.mjs.map → fieldApiTransformer-Bx1Es8H0.mjs.map} +1 -1
- package/dist/form-renderer.es.js +1 -1
- package/dist/form-renderer.umd.js +26 -26
- package/dist/form-renderer.umd.js.map +1 -1
- package/dist/{index-Clh0z6_i.mjs → index-lGTPtpcE.mjs} +3748 -3331
- package/dist/index-lGTPtpcE.mjs.map +1 -0
- package/dist/style.css +1 -1
- package/package.json +5 -12
- package/dist/index-Clh0z6_i.mjs.map +0 -1
package/README.md
CHANGED
|
@@ -260,26 +260,9 @@ axios.interceptors.request.use((config) => {
|
|
|
260
260
|
import 'iq-line-form-builder-renderer/styles';
|
|
261
261
|
```
|
|
262
262
|
|
|
263
|
-
###
|
|
263
|
+
### Custom Styling
|
|
264
264
|
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
#### CSS Scope
|
|
268
|
-
|
|
269
|
-
All styles are scoped to the `.iq-line-form-renderer` class. The FormRenderer component automatically wraps all content in this class, ensuring that:
|
|
270
|
-
|
|
271
|
-
- ✅ No global CSS conflicts with your application
|
|
272
|
-
- ✅ Works seamlessly with shadcn/ui components
|
|
273
|
-
- ✅ Compatible with other CSS frameworks
|
|
274
|
-
- ✅ Styles only apply within FormRenderer
|
|
275
|
-
|
|
276
|
-
#### CSS Variables
|
|
277
|
-
|
|
278
|
-
CSS variables (defined in `:root`) are kept global and won't conflict with your app's variables. The package uses its own variable namespace for theming.
|
|
279
|
-
|
|
280
|
-
#### Custom Styling
|
|
281
|
-
|
|
282
|
-
You can override styles by targeting the scoped class:
|
|
265
|
+
The renderer uses Tailwind CSS. You can override styles by:
|
|
283
266
|
|
|
284
267
|
1. **Using className prop**:
|
|
285
268
|
```tsx
|
|
@@ -292,11 +275,6 @@ You can override styles by targeting the scoped class:
|
|
|
292
275
|
2. **CSS Overrides**:
|
|
293
276
|
```css
|
|
294
277
|
/* Override form styles */
|
|
295
|
-
.iq-line-form-renderer input {
|
|
296
|
-
border-color: #your-color;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
/* Or use your custom class */
|
|
300
278
|
.custom-form-class input {
|
|
301
279
|
border-color: #your-color;
|
|
302
280
|
}
|
|
@@ -304,16 +282,6 @@ You can override styles by targeting the scoped class:
|
|
|
304
282
|
|
|
305
283
|
3. **Tailwind Configuration**: If your app uses Tailwind, ensure the renderer's Tailwind classes are included in your config.
|
|
306
284
|
|
|
307
|
-
#### Compatibility
|
|
308
|
-
|
|
309
|
-
This package is designed to work alongside:
|
|
310
|
-
- ✅ shadcn/ui components
|
|
311
|
-
- ✅ Tailwind CSS
|
|
312
|
-
- ✅ Other CSS frameworks
|
|
313
|
-
- ✅ Global CSS stylesheets
|
|
314
|
-
|
|
315
|
-
The scoped CSS ensures no conflicts with your application's global styles.
|
|
316
|
-
|
|
317
285
|
## Advanced Usage
|
|
318
286
|
|
|
319
287
|
### Using Form Schema Directly
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { g as O, a as P } from "./index-
|
|
1
|
+
import { g as O, a as P } from "./index-lGTPtpcE.mjs";
|
|
2
2
|
function S(e, u) {
|
|
3
3
|
const i = {};
|
|
4
4
|
let p = !1, o, t, s, c, d;
|
|
@@ -92,4 +92,4 @@ export {
|
|
|
92
92
|
S as transformFieldToBulkPayload,
|
|
93
93
|
E as transformFieldsToBulkPayload
|
|
94
94
|
};
|
|
95
|
-
//# sourceMappingURL=fieldApiTransformer-
|
|
95
|
+
//# sourceMappingURL=fieldApiTransformer-Bx1Es8H0.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fieldApiTransformer-DpvHi_69.mjs","sources":["../src/modules/formbuilder/utils/fieldApiTransformer.ts"],"sourcesContent":["// Purpose: Transform frontend FormField to API bulk create format\r\n// Scope: Converts FormField to the format expected by /api/form-builder/form-fields/bulk\r\n\r\nimport type { FormField } from '../types/field';\r\nimport { getApiDataFromProperties, getNonApiMetadata } from './apiDataHelpers';\r\n\r\nexport interface BulkFieldPayload {\r\n formDefinitionId: string;\r\n fieldKey: string;\r\n fieldType: string;\r\n label: string;\r\n placeholder?: string;\r\n defaultValue?: string;\r\n isRequired: boolean;\r\n \r\n // Position (both nested and flat for backend compatibility)\r\n position: {\r\n row: number;\r\n column: number;\r\n width: number;\r\n order: number;\r\n };\r\n positionRow: number;\r\n positionColumn: number;\r\n positionWidth: number;\r\n positionOrder: number;\r\n \r\n // Validation (both nested and flat for backend compatibility)\r\n validation?: Record<string, any>;\r\n validationRequired: boolean;\r\n validationMinLength?: number;\r\n validationMaxLength?: number;\r\n validationMin?: number;\r\n validationMax?: number;\r\n validationPattern?: string;\r\n \r\n // Field state\r\n disabled?: boolean;\r\n readOnly?: boolean;\r\n hidden?: boolean;\r\n \r\n // Appearance\r\n size?: string;\r\n labelPosition?: string;\r\n hideLabel?: boolean;\r\n customClass?: string;\r\n \r\n // Options for select/radio/checkbox fields (JSON string)\r\n options?: string;\r\n \r\n // Additional metadata (JSON string) - non-API fields only\r\n metadata?: string;\r\n \r\n // API data (new structure, preferred)\r\n apidata?: {\r\n apiKey?: string;\r\n valueSource?: string;\r\n apiEndpoint?: string;\r\n apiAutoDetect?: boolean;\r\n apiLabelField?: string;\r\n apiValueField?: string;\r\n apiMethod?: string;\r\n apiRealtime?: boolean;\r\n apiQueryParams?: {\r\n limit?: string;\r\n page?: string;\r\n sort?: string;\r\n orderBy?: string;\r\n custom?: Array<{ key: string; value: string }>;\r\n };\r\n apiClientFilter?: {\r\n filterField: string;\r\n matchField: string;\r\n };\r\n };\r\n \r\n // Help text\r\n helpText?: string;\r\n}\r\n\r\n/**\r\n * Transforms a frontend FormField to the API bulk create format\r\n */\r\nexport function transformFieldToBulkPayload(\r\n field: FormField,\r\n formDefinitionId: string\r\n): BulkFieldPayload {\r\n // Extract validation rules\r\n const validation: Record<string, any> = {};\r\n let isRequired = false;\r\n let validationMinLength: number | undefined;\r\n let validationMaxLength: number | undefined;\r\n let validationMin: number | undefined;\r\n let validationMax: number | undefined;\r\n let validationPattern: string | undefined;\r\n\r\n if (field.validation && Array.isArray(field.validation)) {\r\n field.validation.forEach((rule) => {\r\n if (rule.type === 'required') {\r\n isRequired = true;\r\n validation.required = true;\r\n } else if (rule.type === 'minLength' && typeof rule.value === 'number') {\r\n validationMinLength = rule.value;\r\n validation.minLength = rule.value;\r\n } else if (rule.type === 'maxLength' && typeof rule.value === 'number') {\r\n validationMaxLength = rule.value;\r\n validation.maxLength = rule.value;\r\n } else if (rule.type === 'min' && typeof rule.value === 'number') {\r\n validationMin = rule.value;\r\n validation.min = rule.value;\r\n } else if (rule.type === 'max' && typeof rule.value === 'number') {\r\n validationMax = rule.value;\r\n validation.max = rule.value;\r\n } else if (rule.type === 'pattern' && typeof rule.value === 'string') {\r\n validationPattern = rule.value;\r\n validation.pattern = rule.value;\r\n } else {\r\n // Store other validation rules (including character restrictions)\r\n validation[rule.type] = rule.value;\r\n }\r\n });\r\n }\r\n\r\n // Check if field is required from field properties\r\n if (field.properties && typeof field.properties === 'object') {\r\n const props = field.properties as any;\r\n if (props.required === true) {\r\n isRequired = true;\r\n validation.required = true;\r\n }\r\n }\r\n\r\n // Extract options for select/radio/checkbox fields\r\n let optionsString: string | undefined;\r\n if (field.properties && typeof field.properties === 'object') {\r\n const props = field.properties as any;\r\n if (props.options && Array.isArray(props.options)) {\r\n optionsString = JSON.stringify(props.options);\r\n }\r\n }\r\n\r\n // Extract appearance properties\r\n const appearance = field.appearance || {};\r\n const size = appearance.size || 'md';\r\n const labelPosition = appearance.labelPlacement || 'top';\r\n const hideLabel = appearance.hideLabel || false;\r\n const customClass = appearance.className || '';\r\n\r\n // Separate API fields from non-API metadata\r\n let apidata: any = undefined;\r\n let metadata: Record<string, any> = {};\r\n\r\n if (field.properties) {\r\n const props = field.properties as any;\r\n \r\n // Extract API data (new structure)\r\n const apiData = getApiDataFromProperties(props);\r\n if (apiData) {\r\n apidata = apiData;\r\n console.log(`[fieldApiTransformer] Field \"${field.name}\" (${field.type}) API config being saved in apidata:`, {\r\n apiEndpoint: apiData.apiEndpoint,\r\n apiMethod: apiData.apiMethod || 'GET',\r\n apiRealtime: apiData.apiRealtime ?? false,\r\n apiAutoDetect: apiData.apiAutoDetect ?? false,\r\n apiLabelField: apiData.apiLabelField,\r\n apiValueField: apiData.apiValueField,\r\n });\r\n }\r\n\r\n // Extract non-API metadata (searchable, clearable, etc.)\r\n metadata = getNonApiMetadata(props);\r\n }\r\n\r\n // Always include field state in metadata (also sent as top-level fields)\r\n metadata.disabled = field.disabled ?? false;\r\n metadata.readOnly = field.readOnly ?? false;\r\n metadata.hidden = field.hidden ?? false;\r\n \r\n // Include hideLabel in metadata if present (from appearance or properties)\r\n // This ensures it's available when loading from backend\r\n if (hideLabel !== undefined) {\r\n metadata.hideLabel = hideLabel;\r\n }\r\n // Also check properties.hideLabel for button fields\r\n if (field.properties && (field.properties as any).hideLabel !== undefined) {\r\n metadata.hideLabel = (field.properties as any).hideLabel;\r\n }\r\n \r\n const metadataString = JSON.stringify(metadata);\r\n\r\n // Position values\r\n const positionRow = field.position.order;\r\n const positionColumn = field.position.column || 1;\r\n const positionWidth = field.position.columnSpan || 1;\r\n const positionOrder = field.position.order;\r\n\r\n // Build payload, only including validation fields if they have values\r\n const payload: BulkFieldPayload = {\r\n formDefinitionId,\r\n fieldKey: field.name,\r\n fieldType: field.type,\r\n label: field.label,\r\n placeholder: field.placeholder,\r\n defaultValue: field.defaultValue ? String(field.defaultValue) : undefined,\r\n isRequired,\r\n \r\n // Position (both formats)\r\n position: {\r\n row: positionRow,\r\n column: positionColumn,\r\n width: positionWidth,\r\n order: positionOrder,\r\n },\r\n positionRow,\r\n positionColumn,\r\n positionWidth,\r\n positionOrder,\r\n \r\n // Validation (both formats)\r\n validation: Object.keys(validation).length > 0 ? validation : undefined,\r\n validationRequired: isRequired,\r\n \r\n // Field state (ensure boolean values, default to false)\r\n disabled: field.disabled ?? false,\r\n readOnly: field.readOnly ?? false,\r\n hidden: field.hidden ?? false,\r\n \r\n // Appearance\r\n size,\r\n labelPosition,\r\n hideLabel,\r\n customClass,\r\n \r\n // Options and metadata\r\n options: optionsString,\r\n metadata: metadataString,\r\n \r\n // API data (new structure, preferred)\r\n ...(apidata && { apidata }),\r\n \r\n // Help text\r\n helpText: field.description,\r\n };\r\n \r\n // Only include validation fields if they have actual values (not undefined/null)\r\n // Note: 0 is a valid value for minLength/maxLength, so we explicitly check for null/undefined\r\n if (validationMinLength !== undefined && validationMinLength !== null) {\r\n payload.validationMinLength = validationMinLength;\r\n }\r\n // Omit the field if undefined/null to let backend handle defaults\r\n if (validationMaxLength !== undefined && validationMaxLength !== null) {\r\n payload.validationMaxLength = validationMaxLength;\r\n }\r\n // Omit the field if undefined/null to let backend handle defaults\r\n if (validationMin !== undefined && validationMin !== null) {\r\n payload.validationMin = validationMin;\r\n }\r\n // Omit the field if undefined/null to let backend handle defaults\r\n if (validationMax !== undefined && validationMax !== null) {\r\n payload.validationMax = validationMax;\r\n }\r\n // Omit the field if undefined/null/empty to let backend handle defaults\r\n if (validationPattern !== undefined && validationPattern !== null && validationPattern !== '') {\r\n payload.validationPattern = validationPattern;\r\n }\r\n \r\n return payload;\r\n}\r\n\r\n/**\r\n * Transforms an array of FormFields to bulk create payload\r\n */\r\nexport function transformFieldsToBulkPayload(\r\n fields: FormField[],\r\n formDefinitionId: string\r\n): BulkFieldPayload[] {\r\n const filteredFields = fields.filter((field) => {\r\n // Filter out layout-only fields (section, divider, header, spacer)\r\n const layoutFields = ['section', 'divider', 'header', 'spacer'];\r\n return !layoutFields.includes(field.type);\r\n });\r\n\r\n const payloads = filteredFields.map((field) => transformFieldToBulkPayload(field, formDefinitionId));\r\n\r\n // Log summary of API configuration fields\r\n const apiFields = payloads.filter((p) => {\r\n try {\r\n const metadata = p.metadata ? JSON.parse(p.metadata) : {};\r\n return !!metadata.apiEndpoint;\r\n } catch {\r\n return false;\r\n }\r\n });\r\n\r\n if (apiFields.length > 0) {\r\n console.log(`[fieldApiTransformer] Summary: ${apiFields.length} field(s) with API configuration:`, \r\n apiFields.map((f) => ({\r\n fieldKey: f.fieldKey,\r\n fieldType: f.fieldType,\r\n apiEndpoint: f.metadata ? (() => {\r\n try {\r\n const meta = JSON.parse(f.metadata);\r\n return meta.apiEndpoint;\r\n } catch {\r\n return 'parse-error';\r\n }\r\n })() : 'no-metadata',\r\n }))\r\n );\r\n }\r\n\r\n return payloads;\r\n}\r\n\r\n/**\r\n * Utility to sync fields to localStorage.\r\n */\r\nexport function syncFieldsToLocalStorage(formId: string | undefined, fields: FormField[]) {\r\n if (!formId) return;\r\n try {\r\n localStorage.setItem(`formsmith_fields_${formId}`, JSON.stringify(fields));\r\n } catch (e) {\r\n console.error('Failed to save fields to localStorage:', e);\r\n }\r\n}\r\n\r\n/**\r\n * Utility to get fields from localStorage.\r\n */\r\nexport function getFieldsFromLocalStorage(formId: string | undefined): FormField[] | null {\r\n if (!formId) return null;\r\n try {\r\n const stored = localStorage.getItem(`formsmith_fields_${formId}`);\r\n if (stored) {\r\n return JSON.parse(stored);\r\n }\r\n return null;\r\n } catch (e) {\r\n console.error('Failed to load fields from localStorage:', e);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Utility to clear fields from localStorage.\r\n */\r\nexport function clearFieldsFromLocalStorage(formId: string | undefined) {\r\n if (!formId) return;\r\n try {\r\n localStorage.removeItem(`formsmith_fields_${formId}`);\r\n console.log(`[clearFieldsFromLocalStorage] Cleared fields for form ${formId}`);\r\n } catch (e) {\r\n console.error('Failed to clear fields from localStorage:', e);\r\n }\r\n}\r\n"],"names":["transformFieldToBulkPayload","field","formDefinitionId","validation","isRequired","validationMinLength","validationMaxLength","validationMin","validationMax","validationPattern","rule","optionsString","props","appearance","size","labelPosition","hideLabel","customClass","apidata","metadata","apiData","getApiDataFromProperties","getNonApiMetadata","metadataString","positionRow","positionColumn","positionWidth","positionOrder","payload","transformFieldsToBulkPayload","fields","payloads","apiFields","p","f"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fieldApiTransformer-Bx1Es8H0.mjs","sources":["../src/modules/formbuilder/utils/fieldApiTransformer.ts"],"sourcesContent":["// Purpose: Transform frontend FormField to API bulk create format\r\n// Scope: Converts FormField to the format expected by /api/form-builder/form-fields/bulk\r\n\r\nimport type { FormField } from '../types/field';\r\nimport { getApiDataFromProperties, getNonApiMetadata } from './apiDataHelpers';\r\n\r\nexport interface BulkFieldPayload {\r\n formDefinitionId: string;\r\n fieldKey: string;\r\n fieldType: string;\r\n label: string;\r\n placeholder?: string;\r\n defaultValue?: string;\r\n isRequired: boolean;\r\n \r\n // Position (both nested and flat for backend compatibility)\r\n position: {\r\n row: number;\r\n column: number;\r\n width: number;\r\n order: number;\r\n };\r\n positionRow: number;\r\n positionColumn: number;\r\n positionWidth: number;\r\n positionOrder: number;\r\n \r\n // Validation (both nested and flat for backend compatibility)\r\n validation?: Record<string, any>;\r\n validationRequired: boolean;\r\n validationMinLength?: number;\r\n validationMaxLength?: number;\r\n validationMin?: number;\r\n validationMax?: number;\r\n validationPattern?: string;\r\n \r\n // Field state\r\n disabled?: boolean;\r\n readOnly?: boolean;\r\n hidden?: boolean;\r\n \r\n // Appearance\r\n size?: string;\r\n labelPosition?: string;\r\n hideLabel?: boolean;\r\n customClass?: string;\r\n \r\n // Options for select/radio/checkbox fields (JSON string)\r\n options?: string;\r\n \r\n // Additional metadata (JSON string) - non-API fields only\r\n metadata?: string;\r\n \r\n // API data (new structure, preferred)\r\n apidata?: {\r\n apiKey?: string;\r\n valueSource?: string;\r\n apiEndpoint?: string;\r\n apiAutoDetect?: boolean;\r\n apiLabelField?: string;\r\n apiValueField?: string;\r\n apiMethod?: string;\r\n apiRealtime?: boolean;\r\n apiQueryParams?: {\r\n limit?: string;\r\n page?: string;\r\n sort?: string;\r\n orderBy?: string;\r\n custom?: Array<{ key: string; value: string }>;\r\n };\r\n apiClientFilter?: {\r\n filterField: string;\r\n matchField: string;\r\n };\r\n };\r\n \r\n // Help text\r\n helpText?: string;\r\n}\r\n\r\n/**\r\n * Transforms a frontend FormField to the API bulk create format\r\n */\r\nexport function transformFieldToBulkPayload(\r\n field: FormField,\r\n formDefinitionId: string\r\n): BulkFieldPayload {\r\n // Extract validation rules\r\n const validation: Record<string, any> = {};\r\n let isRequired = false;\r\n let validationMinLength: number | undefined;\r\n let validationMaxLength: number | undefined;\r\n let validationMin: number | undefined;\r\n let validationMax: number | undefined;\r\n let validationPattern: string | undefined;\r\n\r\n if (field.validation && Array.isArray(field.validation)) {\r\n field.validation.forEach((rule) => {\r\n if (rule.type === 'required') {\r\n isRequired = true;\r\n validation.required = true;\r\n } else if (rule.type === 'minLength' && typeof rule.value === 'number') {\r\n validationMinLength = rule.value;\r\n validation.minLength = rule.value;\r\n } else if (rule.type === 'maxLength' && typeof rule.value === 'number') {\r\n validationMaxLength = rule.value;\r\n validation.maxLength = rule.value;\r\n } else if (rule.type === 'min' && typeof rule.value === 'number') {\r\n validationMin = rule.value;\r\n validation.min = rule.value;\r\n } else if (rule.type === 'max' && typeof rule.value === 'number') {\r\n validationMax = rule.value;\r\n validation.max = rule.value;\r\n } else if (rule.type === 'pattern' && typeof rule.value === 'string') {\r\n validationPattern = rule.value;\r\n validation.pattern = rule.value;\r\n } else {\r\n // Store other validation rules (including character restrictions)\r\n validation[rule.type] = rule.value;\r\n }\r\n });\r\n }\r\n\r\n // Check if field is required from field properties\r\n if (field.properties && typeof field.properties === 'object') {\r\n const props = field.properties as any;\r\n if (props.required === true) {\r\n isRequired = true;\r\n validation.required = true;\r\n }\r\n }\r\n\r\n // Extract options for select/radio/checkbox fields\r\n let optionsString: string | undefined;\r\n if (field.properties && typeof field.properties === 'object') {\r\n const props = field.properties as any;\r\n if (props.options && Array.isArray(props.options)) {\r\n optionsString = JSON.stringify(props.options);\r\n }\r\n }\r\n\r\n // Extract appearance properties\r\n const appearance = field.appearance || {};\r\n const size = appearance.size || 'md';\r\n const labelPosition = appearance.labelPlacement || 'top';\r\n const hideLabel = appearance.hideLabel || false;\r\n const customClass = appearance.className || '';\r\n\r\n // Separate API fields from non-API metadata\r\n let apidata: any = undefined;\r\n let metadata: Record<string, any> = {};\r\n\r\n if (field.properties) {\r\n const props = field.properties as any;\r\n \r\n // Extract API data (new structure)\r\n const apiData = getApiDataFromProperties(props);\r\n if (apiData) {\r\n apidata = apiData;\r\n console.log(`[fieldApiTransformer] Field \"${field.name}\" (${field.type}) API config being saved in apidata:`, {\r\n apiEndpoint: apiData.apiEndpoint,\r\n apiMethod: apiData.apiMethod || 'GET',\r\n apiRealtime: apiData.apiRealtime ?? false,\r\n apiAutoDetect: apiData.apiAutoDetect ?? false,\r\n apiLabelField: apiData.apiLabelField,\r\n apiValueField: apiData.apiValueField,\r\n });\r\n }\r\n\r\n // Extract non-API metadata (searchable, clearable, etc.)\r\n metadata = getNonApiMetadata(props);\r\n }\r\n\r\n // Always include field state in metadata (also sent as top-level fields)\r\n metadata.disabled = field.disabled ?? false;\r\n metadata.readOnly = field.readOnly ?? false;\r\n metadata.hidden = field.hidden ?? false;\r\n \r\n // Include hideLabel in metadata if present (from appearance or properties)\r\n // This ensures it's available when loading from backend\r\n if (hideLabel !== undefined) {\r\n metadata.hideLabel = hideLabel;\r\n }\r\n // Also check properties.hideLabel for button fields\r\n if (field.properties && (field.properties as any).hideLabel !== undefined) {\r\n metadata.hideLabel = (field.properties as any).hideLabel;\r\n }\r\n \r\n const metadataString = JSON.stringify(metadata);\r\n\r\n // Position values\r\n const positionRow = field.position.order;\r\n const positionColumn = field.position.column || 1;\r\n const positionWidth = field.position.columnSpan || 1;\r\n const positionOrder = field.position.order;\r\n\r\n // Build payload, only including validation fields if they have values\r\n const payload: BulkFieldPayload = {\r\n formDefinitionId,\r\n fieldKey: field.name,\r\n fieldType: field.type,\r\n label: field.label,\r\n placeholder: field.placeholder,\r\n defaultValue: field.defaultValue ? String(field.defaultValue) : undefined,\r\n isRequired,\r\n \r\n // Position (both formats)\r\n position: {\r\n row: positionRow,\r\n column: positionColumn,\r\n width: positionWidth,\r\n order: positionOrder,\r\n },\r\n positionRow,\r\n positionColumn,\r\n positionWidth,\r\n positionOrder,\r\n \r\n // Validation (both formats)\r\n validation: Object.keys(validation).length > 0 ? validation : undefined,\r\n validationRequired: isRequired,\r\n \r\n // Field state (ensure boolean values, default to false)\r\n disabled: field.disabled ?? false,\r\n readOnly: field.readOnly ?? false,\r\n hidden: field.hidden ?? false,\r\n \r\n // Appearance\r\n size,\r\n labelPosition,\r\n hideLabel,\r\n customClass,\r\n \r\n // Options and metadata\r\n options: optionsString,\r\n metadata: metadataString,\r\n \r\n // API data (new structure, preferred)\r\n ...(apidata && { apidata }),\r\n \r\n // Help text\r\n helpText: field.description,\r\n };\r\n \r\n // Only include validation fields if they have actual values (not undefined/null)\r\n // Note: 0 is a valid value for minLength/maxLength, so we explicitly check for null/undefined\r\n if (validationMinLength !== undefined && validationMinLength !== null) {\r\n payload.validationMinLength = validationMinLength;\r\n }\r\n // Omit the field if undefined/null to let backend handle defaults\r\n if (validationMaxLength !== undefined && validationMaxLength !== null) {\r\n payload.validationMaxLength = validationMaxLength;\r\n }\r\n // Omit the field if undefined/null to let backend handle defaults\r\n if (validationMin !== undefined && validationMin !== null) {\r\n payload.validationMin = validationMin;\r\n }\r\n // Omit the field if undefined/null to let backend handle defaults\r\n if (validationMax !== undefined && validationMax !== null) {\r\n payload.validationMax = validationMax;\r\n }\r\n // Omit the field if undefined/null/empty to let backend handle defaults\r\n if (validationPattern !== undefined && validationPattern !== null && validationPattern !== '') {\r\n payload.validationPattern = validationPattern;\r\n }\r\n \r\n return payload;\r\n}\r\n\r\n/**\r\n * Transforms an array of FormFields to bulk create payload\r\n */\r\nexport function transformFieldsToBulkPayload(\r\n fields: FormField[],\r\n formDefinitionId: string\r\n): BulkFieldPayload[] {\r\n const filteredFields = fields.filter((field) => {\r\n // Filter out layout-only fields (section, divider, header, spacer)\r\n const layoutFields = ['section', 'divider', 'header', 'spacer'];\r\n return !layoutFields.includes(field.type);\r\n });\r\n\r\n const payloads = filteredFields.map((field) => transformFieldToBulkPayload(field, formDefinitionId));\r\n\r\n // Log summary of API configuration fields\r\n const apiFields = payloads.filter((p) => {\r\n try {\r\n const metadata = p.metadata ? JSON.parse(p.metadata) : {};\r\n return !!metadata.apiEndpoint;\r\n } catch {\r\n return false;\r\n }\r\n });\r\n\r\n if (apiFields.length > 0) {\r\n console.log(`[fieldApiTransformer] Summary: ${apiFields.length} field(s) with API configuration:`, \r\n apiFields.map((f) => ({\r\n fieldKey: f.fieldKey,\r\n fieldType: f.fieldType,\r\n apiEndpoint: f.metadata ? (() => {\r\n try {\r\n const meta = JSON.parse(f.metadata);\r\n return meta.apiEndpoint;\r\n } catch {\r\n return 'parse-error';\r\n }\r\n })() : 'no-metadata',\r\n }))\r\n );\r\n }\r\n\r\n return payloads;\r\n}\r\n\r\n/**\r\n * Utility to sync fields to localStorage.\r\n */\r\nexport function syncFieldsToLocalStorage(formId: string | undefined, fields: FormField[]) {\r\n if (!formId) return;\r\n try {\r\n localStorage.setItem(`formsmith_fields_${formId}`, JSON.stringify(fields));\r\n } catch (e) {\r\n console.error('Failed to save fields to localStorage:', e);\r\n }\r\n}\r\n\r\n/**\r\n * Utility to get fields from localStorage.\r\n */\r\nexport function getFieldsFromLocalStorage(formId: string | undefined): FormField[] | null {\r\n if (!formId) return null;\r\n try {\r\n const stored = localStorage.getItem(`formsmith_fields_${formId}`);\r\n if (stored) {\r\n return JSON.parse(stored);\r\n }\r\n return null;\r\n } catch (e) {\r\n console.error('Failed to load fields from localStorage:', e);\r\n return null;\r\n }\r\n}\r\n\r\n/**\r\n * Utility to clear fields from localStorage.\r\n */\r\nexport function clearFieldsFromLocalStorage(formId: string | undefined) {\r\n if (!formId) return;\r\n try {\r\n localStorage.removeItem(`formsmith_fields_${formId}`);\r\n console.log(`[clearFieldsFromLocalStorage] Cleared fields for form ${formId}`);\r\n } catch (e) {\r\n console.error('Failed to clear fields from localStorage:', e);\r\n }\r\n}\r\n"],"names":["transformFieldToBulkPayload","field","formDefinitionId","validation","isRequired","validationMinLength","validationMaxLength","validationMin","validationMax","validationPattern","rule","optionsString","props","appearance","size","labelPosition","hideLabel","customClass","apidata","metadata","apiData","getApiDataFromProperties","getNonApiMetadata","metadataString","positionRow","positionColumn","positionWidth","positionOrder","payload","transformFieldsToBulkPayload","fields","payloads","apiFields","p","f"],"mappings":"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"}
|
package/dist/form-renderer.es.js
CHANGED