funuicss 3.8.8 → 3.8.10

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/ui/form/Form.js CHANGED
@@ -97,10 +97,43 @@ var react_1 = __importStar(require("react"));
97
97
  var Button_1 = __importDefault(require("../button/Button"));
98
98
  var Input_1 = __importDefault(require("../input/Input"));
99
99
  var Flex_1 = __importDefault(require("../flex/Flex"));
100
- var Div_1 = __importDefault(require("../div/Div"));
101
100
  var Text_1 = __importDefault(require("../text/Text"));
102
101
  var pi_1 = require("react-icons/pi");
103
- // Custom Checkbox Component
102
+ var componentUtils_1 = require("../../utils/componentUtils");
103
+ // Helper function to parse JSON input
104
+ var parseJsonInput = function (input, defaultValue) {
105
+ if (input === undefined || input === null) {
106
+ return defaultValue;
107
+ }
108
+ // If it's already the correct type, return as is
109
+ if (typeof input !== 'string') {
110
+ return input;
111
+ }
112
+ try {
113
+ // Try to parse as JSON
114
+ var parsed = JSON.parse(input);
115
+ return parsed;
116
+ }
117
+ catch (error) {
118
+ console.warn('Failed to parse JSON input:', input, error);
119
+ // If parsing fails, try to interpret as a string that might be valid
120
+ try {
121
+ // Try to handle common cases like arrays or objects without quotes
122
+ var trimmed = input.trim();
123
+ if (trimmed.startsWith('[') && trimmed.endsWith(']')) {
124
+ return JSON.parse(trimmed);
125
+ }
126
+ else if (trimmed.startsWith('{') && trimmed.endsWith('}')) {
127
+ return JSON.parse(trimmed);
128
+ }
129
+ }
130
+ catch (e) {
131
+ // If still fails, return default
132
+ }
133
+ return defaultValue;
134
+ }
135
+ };
136
+ // Custom Checkbox Component (unchanged)
104
137
  var FormCheckbox = function (_a) {
105
138
  var label = _a.label, checked = _a.checked, onChange = _a.onChange, disabled = _a.disabled, required = _a.required, value = _a.value, id = _a.id;
106
139
  return (react_1.default.createElement("label", { className: "funui_form-checkbox", style: {
@@ -110,12 +143,19 @@ var FormCheckbox = function (_a) {
110
143
  cursor: disabled ? 'not-allowed' : 'pointer',
111
144
  userSelect: 'none',
112
145
  width: 'fit-content',
146
+ padding: '0.25rem 0',
113
147
  } },
114
- react_1.default.createElement("input", { type: "checkbox", id: id, checked: checked, onChange: function (e) { return !disabled && onChange(e.target.checked); }, disabled: disabled, required: required, value: value, style: { display: 'none' } }),
148
+ react_1.default.createElement("input", { type: "checkbox", id: id, checked: checked, onChange: function (e) { return !disabled && onChange(e.target.checked); }, disabled: disabled, required: required, value: value, style: {
149
+ position: 'absolute',
150
+ opacity: 0,
151
+ width: 0,
152
+ height: 0,
153
+ pointerEvents: 'none'
154
+ } }),
115
155
  react_1.default.createElement("div", { className: "funui_form-checkbox-box", style: {
116
156
  width: '1.25rem',
117
157
  height: '1.25rem',
118
- border: checked ? '2px solid var(--primary)' : '2px solid var(--border)',
158
+ border: checked ? '2px solid var(--primary)' : '2px solid var(--borderColor)',
119
159
  borderRadius: '0.25rem',
120
160
  backgroundColor: checked ? 'var(--primary)' : 'transparent',
121
161
  position: 'relative',
@@ -124,17 +164,22 @@ var FormCheckbox = function (_a) {
124
164
  alignItems: 'center',
125
165
  justifyContent: 'center',
126
166
  flexShrink: 0,
127
- } }, checked && (react_1.default.createElement("div", { style: {
128
- width: '0.75rem',
129
- height: '0.75rem',
130
- backgroundColor: 'white',
131
- borderRadius: '0.125rem',
132
- } }))),
133
- label && (react_1.default.createElement("span", { className: "funui_form-checkbox-label", style: { fontSize: '0.875rem' } },
167
+ } }, checked && (react_1.default.createElement("svg", { width: "14", height: "14", viewBox: "0 0 14 14", fill: "none", xmlns: "http://www.w3.org2000/svg", style: {
168
+ stroke: 'white',
169
+ strokeWidth: '2',
170
+ strokeLinecap: 'round',
171
+ strokeLinejoin: 'round',
172
+ } },
173
+ react_1.default.createElement("path", { d: "M3 7L6 10L11 4" })))),
174
+ label && (react_1.default.createElement("span", { className: "funui_form-checkbox-label", style: {
175
+ fontSize: '0.875rem',
176
+ color: disabled ? 'var(--text-muted)' : 'var(--text)',
177
+ fontWeight: checked ? '500' : '400',
178
+ } },
134
179
  label,
135
180
  required && ' *'))));
136
181
  };
137
- // Custom Radio Component
182
+ // Custom Radio Component (unchanged)
138
183
  var FormRadio = function (_a) {
139
184
  var label = _a.label, checked = _a.checked, onChange = _a.onChange, disabled = _a.disabled, required = _a.required, value = _a.value, id = _a.id;
140
185
  return (react_1.default.createElement("label", { className: "funui_form-radio", style: {
@@ -144,12 +189,19 @@ var FormRadio = function (_a) {
144
189
  cursor: disabled ? 'not-allowed' : 'pointer',
145
190
  userSelect: 'none',
146
191
  width: 'fit-content',
192
+ padding: '0.25rem 0',
147
193
  } },
148
- react_1.default.createElement("input", { type: "radio", id: id, checked: checked, onChange: function (e) { return !disabled && onChange(e.target.checked); }, disabled: disabled, required: required, value: value, style: { display: 'none' } }),
194
+ react_1.default.createElement("input", { type: "radio", id: id, checked: checked, onChange: function (e) { return !disabled && onChange(e.target.checked); }, disabled: disabled, required: required, value: value, style: {
195
+ position: 'absolute',
196
+ opacity: 0,
197
+ width: 0,
198
+ height: 0,
199
+ pointerEvents: 'none'
200
+ } }),
149
201
  react_1.default.createElement("div", { className: "funui_form-radio-circle", style: {
150
202
  width: '1.25rem',
151
203
  height: '1.25rem',
152
- border: checked ? '2px solid var(--primary)' : '2px solid var(--border)',
204
+ border: checked ? '2px solid var(--primary)' : '2px solid var(--borderColor)',
153
205
  borderRadius: '50%',
154
206
  backgroundColor: 'transparent',
155
207
  position: 'relative',
@@ -164,34 +216,41 @@ var FormRadio = function (_a) {
164
216
  backgroundColor: 'var(--primary)',
165
217
  borderRadius: '50%',
166
218
  } }))),
167
- label && (react_1.default.createElement("span", { className: "funui_form-radio-label", style: { fontSize: '0.875rem' } },
219
+ label && (react_1.default.createElement("span", { className: "funui_form-radio-label", style: {
220
+ fontSize: '0.875rem',
221
+ color: disabled ? 'var(--text-muted)' : 'var(--text)',
222
+ fontWeight: checked ? '500' : '400',
223
+ } },
168
224
  label,
169
225
  required && ' *'))));
170
226
  };
171
- // Password Toggle
172
- var PasswordToggle = function (_a) {
173
- var isVisible = _a.isVisible, onToggle = _a.onToggle, disabled = _a.disabled;
174
- return (react_1.default.createElement("button", { type: "button", onClick: onToggle, disabled: disabled, className: "funui_form-password-toggle", style: {
175
- background: 'none',
176
- border: 'none',
177
- padding: '0.5rem',
178
- cursor: disabled ? 'not-allowed' : 'pointer',
179
- opacity: disabled ? 0.5 : 1,
180
- display: 'flex',
181
- alignItems: 'center',
182
- justifyContent: 'center',
183
- }, "aria-label": isVisible ? 'Hide password' : 'Show password' }, isVisible ? react_1.default.createElement(pi_1.PiEyeSlash, { size: 18 }) : react_1.default.createElement(pi_1.PiEye, { size: 18 })));
184
- };
185
- // WhatsApp Button Component
186
- var WhatsAppButton = function (_a) {
187
- var onClick = _a.onClick, disabled = _a.disabled, _b = _a.text, text = _b === void 0 ? 'Send via WhatsApp' : _b;
188
- return (react_1.default.createElement(Button_1.default, { type: "button", text: text, bg: "#25D366", color: "white", raised: true, startIcon: react_1.default.createElement(pi_1.PiWhatsappLogo, null), disabled: disabled, onClick: onClick, funcss: "funui_form-whatsapp-button" }));
189
- };
190
- // Function to format WhatsApp message
191
- var formatWhatsAppMessage = function (values, fields, headerMessage, footerMessage) {
192
- var fieldLines = fields
193
- .filter(function (field) { return values[field.name] !== undefined && values[field.name] !== null && values[field.name] !== ''; })
194
- .map(function (field) {
227
+ // Function to format WhatsApp message - UPDATED with proper formatting
228
+ var formatWhatsAppMessage = function (values, fields, header, footer) {
229
+ // Build message lines
230
+ var message = '';
231
+ // Add header if provided
232
+ if (header) {
233
+ message += "".concat(header, "\n\n");
234
+ }
235
+ // Filter out empty/null/undefined values
236
+ var nonEmptyFields = fields.filter(function (field) {
237
+ var value = values[field.name];
238
+ // Skip if value is undefined, null, or empty string
239
+ if (value === undefined || value === null || value === '') {
240
+ return false;
241
+ }
242
+ // Skip if array is empty
243
+ if (Array.isArray(value) && value.length === 0) {
244
+ return false;
245
+ }
246
+ // Skip if checkbox is false
247
+ if (field.type === 'checkbox' && !field.multiple && value === false) {
248
+ return false;
249
+ }
250
+ return true;
251
+ });
252
+ // Format each field
253
+ var fieldLines = nonEmptyFields.map(function (field) {
195
254
  var value = values[field.name];
196
255
  var displayValue = value;
197
256
  // Format array values (for multiple checkboxes)
@@ -207,71 +266,122 @@ var formatWhatsAppMessage = function (values, fields, headerMessage, footerMessa
207
266
  var option = field.options.find(function (opt) { return opt.value === value; });
208
267
  displayValue = option ? option.label : value;
209
268
  }
210
- return "*".concat(field.label || field.name, ":* ").concat(displayValue);
211
- })
212
- .join('\n');
213
- var message = '';
214
- if (headerMessage) {
215
- message += "".concat(headerMessage, "\n\n");
216
- }
217
- message += fieldLines;
218
- if (footerMessage) {
219
- message += "\n\n".concat(footerMessage);
269
+ // Ensure displayValue is a string and preserve spaces/newlines
270
+ displayValue = String(displayValue);
271
+ // WhatsApp formatting:
272
+ // - Field label on its own line
273
+ // - Value on next line wrapped in backticks
274
+ // - Double newline between fields for readability
275
+ return "".concat(field.label || field.name, "\n`").concat(displayValue, "`");
276
+ });
277
+ // Join with double newline for spacing
278
+ message += fieldLines.join('\n\n');
279
+ // Add footer if provided
280
+ if (footer) {
281
+ message += "\n\n".concat(footer);
220
282
  }
221
283
  return encodeURIComponent(message);
222
284
  };
223
- // Main Form Component
224
- var Form = function (_a) {
225
- var fields = _a.fields, onSubmit = _a.onSubmit, _b = _a.defaultValues, defaultValues = _b === void 0 ? {} : _b, _c = _a.submitText, submitText = _c === void 0 ? 'Submit' : _c, _d = _a.resetText, resetText = _d === void 0 ? 'Reset' : _d, _e = _a.showReset, showReset = _e === void 0 ? true : _e, _f = _a.isLoading, isLoading = _f === void 0 ? false : _f, _g = _a.className, className = _g === void 0 ? '' : _g, _h = _a.layout, layout = _h === void 0 ? 'vertical' : _h, _j = _a.gap, gap = _j === void 0 ? '1.5rem' : _j, whatsappIntegration = _a.whatsappIntegration;
285
+ // Main Form Component - FIXED
286
+ var Form = function (props) {
287
+ var fieldsProp = props.fields, onSubmitProp = props.onSubmit, _a = props.defaultValues, defaultValuesProp = _a === void 0 ? {} : _a, _b = props.submitText, submitTextProp = _b === void 0 ? 'Submit' : _b, _c = props.submitBg, submitBgProp = _c === void 0 ? 'primary' : _c, submitPrefixProp = props.submitPrefix, submitSuffixProp = props.submitSuffix, _d = props.resetText, resetTextProp = _d === void 0 ? 'Reset' : _d, _e = props.showReset, showResetProp = _e === void 0 ? true : _e, _f = props.isLoading, isLoadingProp = _f === void 0 ? false : _f, _g = props.className, classNameProp = _g === void 0 ? '' : _g, _h = props.layout, layoutProp = _h === void 0 ? 'vertical' : _h, _j = props.gap, gapProp = _j === void 0 ? '1.5rem' : _j, titleProp = props.title, titleSizeProp = props.titleSize, titleColorProp = props.titleColor, descriptionProp = props.description, descriptionSizeProp = props.descriptionSize, descriptionColorProp = props.descriptionColor, whatsappContactProp = props.whatsappContact, widthProp = props.width, centeredProp = props.centered, whatsappHeaderProp = props.whatsappHeader, whatsappFooterProp = props.whatsappFooter, _k = props.fullWidth, fullWidthProp = _k === void 0 ? true : _k, _l = props.variant, variant = _l === void 0 ? '' : _l;
288
+ // Use component configuration with variant
289
+ var mergeWithLocal = (0, componentUtils_1.useComponentConfiguration)('Form', variant).mergeWithLocal;
290
+ // Create local props object
291
+ var localProps = {
292
+ fields: fieldsProp,
293
+ onSubmit: onSubmitProp,
294
+ defaultValues: defaultValuesProp,
295
+ submitText: submitTextProp,
296
+ submitBg: submitBgProp,
297
+ submitPrefix: submitPrefixProp,
298
+ submitSuffix: submitSuffixProp,
299
+ resetText: resetTextProp,
300
+ showReset: showResetProp,
301
+ isLoading: isLoadingProp,
302
+ className: classNameProp,
303
+ layout: layoutProp,
304
+ gap: gapProp,
305
+ title: titleProp,
306
+ titleSize: titleSizeProp,
307
+ titleColor: titleColorProp,
308
+ description: descriptionProp,
309
+ descriptionSize: descriptionSizeProp,
310
+ descriptionColor: descriptionColorProp,
311
+ whatsappContact: whatsappContactProp,
312
+ width: widthProp,
313
+ centered: centeredProp,
314
+ whatsappHeader: whatsappHeaderProp,
315
+ whatsappFooter: whatsappFooterProp,
316
+ fullWidth: fullWidthProp,
317
+ variant: variant,
318
+ };
319
+ // Merge with theme configuration
320
+ var mergedProps = mergeWithLocal(localProps).props;
321
+ // Destructure with proper priority: local props override config props
322
+ var fields = fieldsProp !== undefined ? fieldsProp : mergedProps.fields;
323
+ var onSubmit = onSubmitProp !== undefined ? onSubmitProp : mergedProps.onSubmit;
324
+ var defaultValues = defaultValuesProp !== undefined ? defaultValuesProp : mergedProps.defaultValues;
325
+ var submitText = submitTextProp !== undefined ? submitTextProp : mergedProps.submitText;
326
+ var submitBg = submitBgProp !== undefined ? submitBgProp : mergedProps.submitBg;
327
+ var submitPrefix = submitPrefixProp !== undefined ? submitPrefixProp : mergedProps.submitPrefix;
328
+ var submitSuffix = submitSuffixProp !== undefined ? submitSuffixProp : mergedProps.submitSuffix;
329
+ var resetText = resetTextProp !== undefined ? resetTextProp : mergedProps.resetText;
330
+ var showReset = showResetProp !== undefined ? showResetProp : mergedProps.showReset;
331
+ var isLoading = isLoadingProp !== undefined ? isLoadingProp : mergedProps.isLoading;
332
+ var className = classNameProp !== undefined ? classNameProp : mergedProps.className;
333
+ var layout = layoutProp !== undefined ? layoutProp : mergedProps.layout;
334
+ var gap = gapProp !== undefined ? gapProp : mergedProps.gap;
335
+ var title = titleProp !== undefined ? titleProp : mergedProps.title;
336
+ var titleSize = titleSizeProp !== undefined ? titleSizeProp : mergedProps.titleSize;
337
+ var titleColor = titleColorProp !== undefined ? titleColorProp : mergedProps.titleColor;
338
+ var description = descriptionProp !== undefined ? descriptionProp : mergedProps.description;
339
+ var descriptionSize = descriptionSizeProp !== undefined ? descriptionSizeProp : mergedProps.descriptionSize;
340
+ var descriptionColor = descriptionColorProp !== undefined ? descriptionColorProp : mergedProps.descriptionColor;
341
+ var whatsappContact = whatsappContactProp !== undefined ? whatsappContactProp : mergedProps.whatsappContact;
342
+ var width = widthProp !== undefined ? widthProp : mergedProps.width;
343
+ var centered = centeredProp !== undefined ? centeredProp : mergedProps.centered;
344
+ var whatsappHeader = whatsappHeaderProp !== undefined ? whatsappHeaderProp : mergedProps.whatsappHeader;
345
+ var whatsappFooter = whatsappFooterProp !== undefined ? whatsappFooterProp : mergedProps.whatsappFooter;
346
+ var fullWidth = fullWidthProp !== undefined ? fullWidthProp : mergedProps.fullWidth;
347
+ // Parse JSON inputs
348
+ var parsedFields = (0, react_1.useMemo)(function () { return parseJsonInput(fields, []); }, [fields]);
349
+ var parsedDefaultValues = (0, react_1.useMemo)(function () { return parseJsonInput(defaultValues, {}); }, [defaultValues]);
226
350
  // State management
227
- var _k = (0, react_1.useState)({}), formValues = _k[0], setFormValues = _k[1];
228
- var _l = (0, react_1.useState)({}), errors = _l[0], setErrors = _l[1];
229
- var _m = (0, react_1.useState)({}), touched = _m[0], setTouched = _m[1];
230
- var _o = (0, react_1.useState)({}), showPassword = _o[0], setShowPassword = _o[1];
231
- var _p = (0, react_1.useState)(false), isSubmitting = _p[0], setIsSubmitting = _p[1];
232
- var _q = (0, react_1.useState)(''), whatsappPhone = _q[0], setWhatsappPhone = _q[1];
233
- // Initialize form values
234
- (0, react_1.useEffect)(function () {
351
+ var _m = (0, react_1.useState)({}), errors = _m[0], setErrors = _m[1];
352
+ var _o = (0, react_1.useState)({}), touched = _o[0], setTouched = _o[1];
353
+ var _p = (0, react_1.useState)(function () {
354
+ // Initialize form values from defaultValues and field values
235
355
  var initialValues = {};
236
- fields.forEach(function (field) {
237
- var _a, _b;
238
- // Priority: field.value > defaultValues > default based on type
356
+ parsedFields.forEach(function (field) {
239
357
  if (field.value !== undefined) {
240
358
  initialValues[field.name] = field.value;
241
359
  }
242
- else if (defaultValues[field.name] !== undefined) {
243
- initialValues[field.name] = defaultValues[field.name];
244
- }
245
- else if (field.type === 'checkbox') {
246
- initialValues[field.name] = field.multiple ? [] : false;
247
- }
248
- else if (field.type === 'radio' && ((_a = field.options) === null || _a === void 0 ? void 0 : _a.length)) {
249
- initialValues[field.name] = '';
250
- }
251
- else if (field.type === 'select' && ((_b = field.options) === null || _b === void 0 ? void 0 : _b.length)) {
252
- initialValues[field.name] = '';
360
+ else if (parsedDefaultValues[field.name] !== undefined) {
361
+ initialValues[field.name] = parsedDefaultValues[field.name];
253
362
  }
254
363
  else {
255
- initialValues[field.name] = '';
256
- }
257
- // Initialize password visibility
258
- if (field.type === 'password') {
259
- setShowPassword(function (prev) {
260
- var _a;
261
- return (__assign(__assign({}, prev), (_a = {}, _a[field.name] = false, _a)));
262
- });
364
+ // Set default empty values
365
+ if (field.type === 'checkbox' && field.multiple) {
366
+ initialValues[field.name] = [];
367
+ }
368
+ else if (field.type === 'checkbox') {
369
+ initialValues[field.name] = false;
370
+ }
371
+ else {
372
+ initialValues[field.name] = '';
373
+ }
263
374
  }
264
375
  });
265
- setFormValues(initialValues);
266
- }, [fields, defaultValues]);
267
- // Initialize WhatsApp phone number
376
+ return initialValues;
377
+ }), formValues = _p[0], setFormValues = _p[1];
378
+ var _q = (0, react_1.useState)(false), isSubmitting = _q[0], setIsSubmitting = _q[1];
379
+ // Update form values when defaultValues prop changes
268
380
  (0, react_1.useEffect)(function () {
269
- if (whatsappIntegration === null || whatsappIntegration === void 0 ? void 0 : whatsappIntegration.phoneNumber) {
270
- // Clean the phone number (remove +, spaces, etc.)
271
- var cleanPhone = whatsappIntegration.phoneNumber.replace(/[\s+\-()]/g, '');
272
- setWhatsappPhone(cleanPhone);
381
+ if (Object.keys(parsedDefaultValues).length > 0) {
382
+ setFormValues(function (prev) { return (__assign(__assign({}, prev), parsedDefaultValues)); });
273
383
  }
274
- }, [whatsappIntegration]);
384
+ }, [parsedDefaultValues]);
275
385
  // Validate a single field
276
386
  var validateField = (0, react_1.useCallback)(function (field, value) {
277
387
  var _a, _b, _c, _d, _e;
@@ -287,10 +397,10 @@ var Form = function (_a) {
287
397
  return "".concat(field.label || field.name, " is required");
288
398
  }
289
399
  }
290
- // Type-specific validations
291
- if (value && value !== '') {
400
+ // Type-specific validations (only for non-empty values)
401
+ if (value && (typeof value !== 'string' || value !== '')) {
292
402
  // Email validation
293
- if (field.type === 'email') {
403
+ if (field.type === 'email' && typeof value === 'string') {
294
404
  var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
295
405
  if (!emailRegex.test(value)) {
296
406
  return 'Please enter a valid email address';
@@ -298,7 +408,16 @@ var Form = function (_a) {
298
408
  }
299
409
  // Number validation
300
410
  if (field.type === 'number') {
301
- var numValue = parseFloat(value);
411
+ var numValue = void 0;
412
+ if (typeof value === 'string') {
413
+ numValue = parseFloat(value);
414
+ }
415
+ else if (typeof value === 'number') {
416
+ numValue = value;
417
+ }
418
+ else {
419
+ return 'Please enter a valid number';
420
+ }
302
421
  if (isNaN(numValue)) {
303
422
  return 'Please enter a valid number';
304
423
  }
@@ -311,14 +430,14 @@ var Form = function (_a) {
311
430
  return "Maximum value is ".concat(max);
312
431
  }
313
432
  }
314
- // Phone validation (basic)
315
- if (field.type === 'tel') {
433
+ // Phone validation (basic) - only for strings
434
+ if (field.type === 'tel' && typeof value === 'string') {
316
435
  var phoneRegex = /^[\+]?[1-9][\d]{0,17}$/;
317
436
  if (!phoneRegex.test(value.replace(/[\s+\-()]/g, ''))) {
318
437
  return 'Please enter a valid phone number';
319
438
  }
320
439
  }
321
- // Length validation
440
+ // Length validation for strings
322
441
  if (typeof value === 'string') {
323
442
  var minLength = (_c = field.inputProps) === null || _c === void 0 ? void 0 : _c.minLength;
324
443
  var maxLength = (_d = field.inputProps) === null || _d === void 0 ? void 0 : _d.maxLength;
@@ -329,53 +448,83 @@ var Form = function (_a) {
329
448
  return "Maximum ".concat(maxLength, " characters allowed");
330
449
  }
331
450
  }
332
- // Pattern validation if provided
333
- if ((_e = field.inputProps) === null || _e === void 0 ? void 0 : _e.pattern) {
334
- var regex = new RegExp(field.inputProps.pattern);
335
- if (!regex.test(value)) {
336
- return 'Invalid format';
451
+ // Pattern validation if provided - only for strings
452
+ if (((_e = field.inputProps) === null || _e === void 0 ? void 0 : _e.pattern) && typeof value === 'string') {
453
+ try {
454
+ var regex = new RegExp(field.inputProps.pattern);
455
+ if (!regex.test(value)) {
456
+ return 'Invalid format';
457
+ }
458
+ }
459
+ catch (error) {
460
+ console.warn('Invalid regex pattern:', field.inputProps.pattern);
337
461
  }
338
462
  }
339
463
  }
340
464
  return null;
341
465
  }, []);
342
- // Handle field change
343
- var handleFieldChange = (0, react_1.useCallback)(function (fieldName, value) {
344
- var field = fields.find(function (f) { return f.name === fieldName; });
345
- if (!field)
346
- return;
466
+ // Validate form
467
+ var validateForm = (0, react_1.useCallback)(function () {
468
+ var newErrors = {};
469
+ var hasErrors = false;
470
+ parsedFields.forEach(function (field) {
471
+ var value = formValues[field.name];
472
+ var error = validateField(field, value);
473
+ if (error) {
474
+ newErrors[field.name] = error;
475
+ hasErrors = true;
476
+ }
477
+ });
478
+ setErrors(newErrors);
479
+ return !hasErrors;
480
+ }, [parsedFields, validateField, formValues]);
481
+ // Handle field change for checkboxes and radios
482
+ var handleFieldChange = (0, react_1.useCallback)(function (fieldName, newValue) {
483
+ // Update form values
347
484
  setFormValues(function (prev) {
348
485
  var _a;
349
- var newValues = __assign(__assign({}, prev), (_a = {}, _a[fieldName] = value, _a));
350
- // Validate on change if field has been touched
351
- if (touched[fieldName]) {
352
- var error_1 = validateField(field, value);
353
- setErrors(function (prevErrors) {
354
- var _a;
355
- if (error_1) {
356
- return __assign(__assign({}, prevErrors), (_a = {}, _a[fieldName] = error_1, _a));
357
- }
358
- else {
359
- var newErrors = __assign({}, prevErrors);
360
- delete newErrors[fieldName];
361
- return newErrors;
362
- }
363
- });
364
- }
365
- return newValues;
486
+ return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = newValue, _a)));
487
+ });
488
+ // Update touched state
489
+ setTouched(function (prev) {
490
+ var _a;
491
+ return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
366
492
  });
367
- }, [fields, touched, validateField]);
368
- // Handle field blur
369
- var handleFieldBlur = (0, react_1.useCallback)(function (fieldName) {
370
- var field = fields.find(function (f) { return f.name === fieldName; });
493
+ // Validate the changed field
494
+ var field = parsedFields.find(function (f) { return f.name === fieldName; });
371
495
  if (!field)
372
496
  return;
497
+ var error = validateField(field, newValue);
498
+ setErrors(function (prev) {
499
+ var _a;
500
+ if (error) {
501
+ return __assign(__assign({}, prev), (_a = {}, _a[fieldName] = error, _a));
502
+ }
503
+ else {
504
+ var newErrors = __assign({}, prev);
505
+ delete newErrors[fieldName];
506
+ return newErrors;
507
+ }
508
+ });
509
+ }, [parsedFields, validateField]);
510
+ // FIXED: Handle input change - pass event directly to Input component
511
+ var handleInputEventChange = (0, react_1.useCallback)(function (e) {
512
+ var fieldName = e.target.name;
513
+ var value = e.target.value;
514
+ // Update form values - PASS VALUE AS-IS (preserves spaces)
515
+ setFormValues(function (prev) {
516
+ var _a;
517
+ return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = value, _a)));
518
+ });
519
+ // Update touched state
373
520
  setTouched(function (prev) {
374
521
  var _a;
375
522
  return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
376
523
  });
377
- // Validate on blur
378
- var value = formValues[fieldName];
524
+ // Validate the changed field
525
+ var field = parsedFields.find(function (f) { return f.name === fieldName; });
526
+ if (!field)
527
+ return;
379
528
  var error = validateField(field, value);
380
529
  setErrors(function (prev) {
381
530
  var _a;
@@ -388,271 +537,231 @@ var Form = function (_a) {
388
537
  return newErrors;
389
538
  }
390
539
  });
391
- }, [fields, formValues, validateField]);
392
- // Toggle password visibility
393
- var togglePasswordVisibility = (0, react_1.useCallback)(function (fieldName) {
394
- setShowPassword(function (prev) {
540
+ }, [parsedFields, validateField]);
541
+ // FIXED: Handle blur event - pass event directly to Input component
542
+ var handleInputEventBlur = (0, react_1.useCallback)(function (e) {
543
+ var fieldName = e.target.name;
544
+ setTouched(function (prev) {
395
545
  var _a;
396
- return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = !prev[fieldName], _a)));
546
+ return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
397
547
  });
398
- }, []);
399
- // Handle WhatsApp submission
400
- var handleWhatsAppSubmit = (0, react_1.useCallback)(function () {
401
- if (!(whatsappIntegration === null || whatsappIntegration === void 0 ? void 0 : whatsappIntegration.enabled) || !whatsappPhone) {
402
- console.error('WhatsApp integration not properly configured');
548
+ // Validate the field
549
+ var field = parsedFields.find(function (f) { return f.name === fieldName; });
550
+ if (!field)
403
551
  return;
404
- }
405
- // Validate form before sending
406
- var newErrors = {};
407
- var hasErrors = false;
408
- fields.forEach(function (field) {
409
- var value = formValues[field.name];
410
- var error = validateField(field, value);
552
+ var value = formValues[fieldName];
553
+ var error = validateField(field, value);
554
+ setErrors(function (prev) {
555
+ var _a;
411
556
  if (error) {
412
- newErrors[field.name] = error;
413
- hasErrors = true;
557
+ return __assign(__assign({}, prev), (_a = {}, _a[fieldName] = error, _a));
558
+ }
559
+ else {
560
+ var newErrors = __assign({}, prev);
561
+ delete newErrors[fieldName];
562
+ return newErrors;
414
563
  }
415
564
  });
416
- setErrors(newErrors);
417
- if (hasErrors) {
418
- // Mark all fields as touched to show errors
419
- var allTouched_1 = {};
420
- fields.forEach(function (field) {
421
- allTouched_1[field.name] = true;
422
- });
423
- setTouched(allTouched_1);
424
- return;
425
- }
426
- // Format the message
427
- var message = formatWhatsAppMessage(formValues, fields, whatsappIntegration.headerMessage, whatsappIntegration.footerMessage);
428
- // Create WhatsApp URL
429
- var whatsappUrl = "https://wa.me/".concat(whatsappPhone, "?text=").concat(message);
430
- // Open WhatsApp in new tab
431
- window.open(whatsappUrl, '_blank');
432
- }, [whatsappIntegration, whatsappPhone, fields, formValues, validateField]);
565
+ }, [parsedFields, validateField, formValues]);
433
566
  // Handle form submission
434
567
  var handleSubmit = (0, react_1.useCallback)(function (e) { return __awaiter(void 0, void 0, void 0, function () {
435
- var allTouched, newErrors, hasErrors, error_2;
568
+ var allTouched, isValid, firstErrorField, element, message, cleanPhone, whatsappUrl, error_1;
436
569
  return __generator(this, function (_a) {
437
570
  switch (_a.label) {
438
571
  case 0:
439
572
  e.preventDefault();
440
573
  allTouched = {};
441
- fields.forEach(function (field) {
574
+ parsedFields.forEach(function (field) {
442
575
  allTouched[field.name] = true;
443
576
  });
444
577
  setTouched(allTouched);
445
- newErrors = {};
446
- hasErrors = false;
447
- fields.forEach(function (field) {
448
- var value = formValues[field.name];
449
- var error = validateField(field, value);
450
- if (error) {
451
- newErrors[field.name] = error;
452
- hasErrors = true;
578
+ isValid = validateForm();
579
+ if (!isValid) {
580
+ firstErrorField = Object.keys(errors)[0];
581
+ if (firstErrorField) {
582
+ element = document.getElementById("form-field-".concat(firstErrorField));
583
+ element === null || element === void 0 ? void 0 : element.scrollIntoView({ behavior: 'smooth', block: 'center' });
453
584
  }
454
- });
455
- setErrors(newErrors);
456
- if (hasErrors)
457
585
  return [2 /*return*/];
458
- // Submit
586
+ }
587
+ // Get form data and submit
459
588
  setIsSubmitting(true);
460
589
  _a.label = 1;
461
590
  case 1:
462
- _a.trys.push([1, 3, 4, 5]);
463
- return [4 /*yield*/, onSubmit(formValues)];
591
+ _a.trys.push([1, 7, 8, 9]);
592
+ if (!whatsappContact) return [3 /*break*/, 4];
593
+ message = formatWhatsAppMessage(formValues, parsedFields, whatsappHeader, whatsappFooter);
594
+ cleanPhone = whatsappContact.replace(/[\s+\-()]/g, '');
595
+ whatsappUrl = "https://wa.me/".concat(cleanPhone, "?text=").concat(message);
596
+ window.open(whatsappUrl, '_blank');
597
+ if (!onSubmit) return [3 /*break*/, 3];
598
+ return [4 /*yield*/, onSubmit(formValues, true)];
464
599
  case 2:
465
600
  _a.sent();
466
- return [3 /*break*/, 5];
467
- case 3:
468
- error_2 = _a.sent();
469
- console.error('Form submission error:', error_2);
470
- setErrors(function (prev) { return (__assign(__assign({}, prev), { _form: 'There was an error submitting the form. Please try again.' })); });
471
- return [3 /*break*/, 5];
601
+ _a.label = 3;
602
+ case 3: return [3 /*break*/, 6];
472
603
  case 4:
604
+ if (!onSubmit) return [3 /*break*/, 6];
605
+ return [4 /*yield*/, onSubmit(formValues, false)];
606
+ case 5:
607
+ _a.sent();
608
+ _a.label = 6;
609
+ case 6: return [3 /*break*/, 9];
610
+ case 7:
611
+ error_1 = _a.sent();
612
+ console.error('Form submission error:', error_1);
613
+ setErrors(function (prev) { return (__assign(__assign({}, prev), { _form: 'There was an error submitting the form. Please try again.' })); });
614
+ return [3 /*break*/, 9];
615
+ case 8:
473
616
  setIsSubmitting(false);
474
617
  return [7 /*endfinally*/];
475
- case 5: return [2 /*return*/];
618
+ case 9: return [2 /*return*/];
476
619
  }
477
620
  });
478
- }); }, [fields, formValues, validateField, onSubmit]);
621
+ }); }, [parsedFields, validateForm, formValues, whatsappContact, whatsappHeader, whatsappFooter, onSubmit, errors]);
479
622
  // Handle form reset
480
623
  var handleReset = (0, react_1.useCallback)(function () {
481
- var resetValues = {};
482
- fields.forEach(function (field) {
483
- var _a, _b;
484
- if (field.type === 'checkbox') {
485
- resetValues[field.name] = field.multiple ? [] : false;
486
- }
487
- else if (field.type === 'radio' && ((_a = field.options) === null || _a === void 0 ? void 0 : _a.length)) {
488
- resetValues[field.name] = '';
624
+ // Reset to initial values
625
+ var initialValues = {};
626
+ parsedFields.forEach(function (field) {
627
+ if (field.value !== undefined) {
628
+ initialValues[field.name] = field.value;
489
629
  }
490
- else if (field.type === 'select' && ((_b = field.options) === null || _b === void 0 ? void 0 : _b.length)) {
491
- resetValues[field.name] = '';
630
+ else if (parsedDefaultValues[field.name] !== undefined) {
631
+ initialValues[field.name] = parsedDefaultValues[field.name];
492
632
  }
493
633
  else {
494
- resetValues[field.name] = '';
634
+ if (field.type === 'checkbox' && field.multiple) {
635
+ initialValues[field.name] = [];
636
+ }
637
+ else if (field.type === 'checkbox') {
638
+ initialValues[field.name] = false;
639
+ }
640
+ else {
641
+ initialValues[field.name] = '';
642
+ }
495
643
  }
496
644
  });
497
- setFormValues(resetValues);
645
+ setFormValues(initialValues);
498
646
  setErrors({});
499
647
  setTouched({});
500
- setShowPassword({});
501
- }, [fields]);
648
+ }, [parsedFields, parsedDefaultValues]);
502
649
  // Get field status for Input component
503
650
  var getFieldStatus = (0, react_1.useCallback)(function (fieldName) {
504
651
  var error = errors[fieldName];
505
652
  var isTouched = touched[fieldName];
506
- var value = formValues[fieldName];
507
653
  if (error)
508
- return 'error';
509
- if (isTouched && !error && value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
654
+ return 'danger';
655
+ if (isTouched && !error && formValues[fieldName] !== '') {
510
656
  return 'success';
511
657
  }
512
- return 'default';
658
+ return undefined;
513
659
  }, [errors, touched, formValues]);
514
- // Get column class based on layout and column setting
515
- var getColumnClass = (0, react_1.useCallback)(function (field) {
516
- if (layout === 'grid') {
517
- switch (field.column) {
518
- case 'half': return 'funui_form-col-half';
519
- case 'third': return 'funui_form-col-third';
520
- case 'quarter': return 'funui_form-col-quarter';
521
- case 'full':
522
- default: return 'funui_form-col-full';
660
+ // Check if form is valid for submission
661
+ var isFormValid = (0, react_1.useMemo)(function () {
662
+ // Check if any required fields are empty
663
+ var hasEmptyRequiredFields = parsedFields.some(function (field) {
664
+ if (!field.required)
665
+ return false;
666
+ var value = formValues[field.name];
667
+ if (field.type === 'checkbox' && field.multiple) {
668
+ return !Array.isArray(value) || value.length === 0;
523
669
  }
524
- }
525
- return '';
526
- }, [layout]);
527
- // Render field based on type
670
+ if (field.type === 'checkbox') {
671
+ return value === false;
672
+ }
673
+ return !value || value === '';
674
+ });
675
+ // Check if there are any validation errors
676
+ var hasValidationErrors = Object.keys(errors).length > 0;
677
+ return !hasEmptyRequiredFields && !hasValidationErrors;
678
+ }, [parsedFields, formValues, errors]);
679
+ // Submit button disabled state
680
+ var isSubmitDisabled = isSubmitting || isLoading || !isFormValid;
681
+ // Check if WhatsApp is configured
682
+ var hasWhatsApp = !!whatsappContact;
683
+ // Render field based on type - FIXED
528
684
  var renderField = (0, react_1.useCallback)(function (field) {
529
- var _a, _b, _c, _d, _e, _f;
530
- var value = (_a = formValues[field.name]) !== null && _a !== void 0 ? _a : '';
685
+ var _a, _b, _c, _d, _e;
531
686
  var status = getFieldStatus(field.name);
532
687
  var error = errors[field.name];
533
688
  var isTouched = touched[field.name];
534
689
  var showError = error && isTouched;
690
+ var value = formValues[field.name];
535
691
  // Field wrapper classes
536
- var wrapperClass = "funui_form-field ".concat(getColumnClass(field), " ").concat(showError ? 'funui_form-field-error' : '').trim();
692
+ var wrapperClass = "col min-w-200 field ".concat(showError ? 'field-error' : '').trim();
537
693
  // Helper text (error takes priority)
538
694
  var helperText = showError ? error : field.helperText;
539
- var helperIcon = showError ? react_1.default.createElement(pi_1.PiWarningCircle, null) : status === 'success' ? react_1.default.createElement(pi_1.PiCheckCircle, null) : undefined;
695
+ // Generate unique ID for the input
696
+ var inputId = ((_a = field.inputProps) === null || _a === void 0 ? void 0 : _a.id) || "form-field-".concat(field.name);
540
697
  // Base props for Input component
541
- var baseProps = __assign({ id: ((_b = field.inputProps) === null || _b === void 0 ? void 0 : _b.id) || field.name, name: field.name, label: field.label, placeholder: field.placeholder, helperText: helperText, status: status, disabled: field.disabled || isLoading, fullWidth: true }, field.inputProps);
698
+ var baseProps = __assign({ id: inputId, name: field.name, label: field.label, placeholder: field.placeholder, helperText: helperText, disabled: field.disabled || isLoading, fullWidth: fullWidth }, field.inputProps);
699
+ // Only add status if it's not undefined
700
+ if (status !== undefined) {
701
+ baseProps.status = status;
702
+ }
542
703
  // Render based on field type
543
704
  switch (field.type) {
544
705
  case 'checkbox':
545
- if ((_c = field.options) === null || _c === void 0 ? void 0 : _c.length) {
706
+ if ((_b = field.options) === null || _b === void 0 ? void 0 : _b.length) {
546
707
  // Multiple checkboxes (checkbox group)
547
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
548
- field.label && (react_1.default.createElement("div", { className: "funui_form-label", style: { marginBottom: '0.5rem' } },
708
+ var checkedValues_1 = Array.isArray(value) ? value : [];
709
+ return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
710
+ field.label && (react_1.default.createElement("div", { className: "form-label", style: { marginBottom: '0.5rem' } },
549
711
  react_1.default.createElement(Text_1.default, { text: field.label + (field.required ? ' *' : ''), size: "sm", color: "text", bold: true }))),
550
712
  react_1.default.createElement(Flex_1.default, { direction: "column", gap: "0.5rem" }, field.options.map(function (option, index) {
551
- var isChecked = field.multiple
552
- ? Array.isArray(value) && value.includes(option.value)
553
- : value === option.value;
554
- return (react_1.default.createElement(FormCheckbox, { key: "".concat(field.name, "_").concat(index), id: "".concat(field.name, "_").concat(index), label: option.label, checked: !!isChecked, onChange: function (checked) {
555
- if (field.multiple) {
556
- var currentValues = Array.isArray(value) ? value : [];
557
- if (checked) {
558
- handleFieldChange(field.name, __spreadArray(__spreadArray([], currentValues, true), [option.value], false));
559
- }
560
- else {
561
- handleFieldChange(field.name, currentValues.filter(function (v) { return v !== option.value; }));
562
- }
713
+ var isChecked = checkedValues_1.includes(option.value);
714
+ return (react_1.default.createElement(FormCheckbox, { key: "".concat(field.name, "_").concat(index), id: "".concat(inputId, "_").concat(index), label: option.label, checked: isChecked, onChange: function (checked) {
715
+ if (checked) {
716
+ // Add value to array
717
+ var newValues = __spreadArray(__spreadArray([], checkedValues_1, true), [option.value], false);
718
+ handleFieldChange(field.name, newValues);
563
719
  }
564
720
  else {
565
- handleFieldChange(field.name, checked ? option.value : false);
721
+ // Remove value from array
722
+ var newValues = checkedValues_1.filter(function (v) { return v !== option.value; });
723
+ handleFieldChange(field.name, newValues);
566
724
  }
567
725
  }, disabled: field.disabled || option.disabled || isLoading, required: field.required && index === 0, value: option.value }));
568
726
  }))));
569
727
  }
570
728
  else {
571
729
  // Single checkbox (boolean)
572
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
573
- react_1.default.createElement(FormCheckbox, { label: field.label, checked: !!value, onChange: function (checked) { return handleFieldChange(field.name, checked); }, disabled: field.disabled || isLoading, required: field.required, id: field.name })));
730
+ return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
731
+ react_1.default.createElement(FormCheckbox, { label: field.label, checked: !!value, onChange: function (checked) { return handleFieldChange(field.name, checked); }, disabled: field.disabled || isLoading, required: field.required, id: inputId })));
574
732
  }
575
733
  case 'radio':
576
- if (!((_d = field.options) === null || _d === void 0 ? void 0 : _d.length))
734
+ if (!((_c = field.options) === null || _c === void 0 ? void 0 : _c.length))
577
735
  return null;
578
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
579
- field.label && (react_1.default.createElement("div", { className: "funui_form-label", style: { marginBottom: '0.5rem' } },
736
+ return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
737
+ field.label && (react_1.default.createElement("div", { className: "form-label", style: { marginBottom: '0.5rem' } },
580
738
  react_1.default.createElement(Text_1.default, { text: field.label + (field.required ? ' *' : ''), size: "sm", color: "text", bold: true }))),
581
- react_1.default.createElement(Flex_1.default, { direction: "column", gap: "0.5rem" }, field.options.map(function (option, index) { return (react_1.default.createElement(FormRadio, { key: "".concat(field.name, "_").concat(index), id: "".concat(field.name, "_").concat(index), label: option.label, checked: value === option.value, onChange: function () { return handleFieldChange(field.name, option.value); }, disabled: field.disabled || option.disabled || isLoading, required: field.required && index === 0, value: option.value })); }))));
739
+ react_1.default.createElement(Flex_1.default, { direction: "column", gap: "0.5rem" }, field.options.map(function (option, index) { return (react_1.default.createElement(FormRadio, { key: "".concat(field.name, "_").concat(index), id: "".concat(inputId, "_").concat(index), label: option.label, checked: value === option.value, onChange: function () { return handleFieldChange(field.name, option.value); }, disabled: field.disabled || option.disabled || isLoading, required: field.required && index === 0, value: option.value })); }))));
582
740
  case 'textarea':
583
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
584
- react_1.default.createElement(Input_1.default, { multiline: true, rows: ((_e = field.inputProps) === null || _e === void 0 ? void 0 : _e.rows) || 4, value: value, onChange: function (e) { return handleFieldChange(field.name, e.target.value); }, onBlur: function () { return handleFieldBlur(field.name); } })));
741
+ return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
742
+ react_1.default.createElement(Input_1.default, __assign({ multiline: true, rows: ((_d = field.inputProps) === null || _d === void 0 ? void 0 : _d.rows) || 4, value: value || '', onChange: handleInputEventChange, onBlur: handleInputEventBlur }, baseProps))));
585
743
  case 'select':
586
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
587
- react_1.default.createElement(Input_1.default, { select: true, options: ((_f = field.options) === null || _f === void 0 ? void 0 : _f.map(function (opt) { return ({ text: opt.label, value: opt.value }); })) || [], value: value, onChange: function (e) { return handleFieldChange(field.name, e.target.value); }, onBlur: function () { return handleFieldBlur(field.name); } })));
588
- case 'password':
589
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
590
- react_1.default.createElement(Input_1.default, { type: showPassword[field.name] ? 'text' : 'password', value: value, onChange: function (e) { return handleFieldChange(field.name, e.target.value); }, onBlur: function () { return handleFieldBlur(field.name); }, endIcon: react_1.default.createElement(PasswordToggle, { isVisible: !!showPassword[field.name], onToggle: function () { return togglePasswordVisibility(field.name); }, disabled: field.disabled || isLoading }) })));
744
+ return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
745
+ react_1.default.createElement(Input_1.default, __assign({ select: true, options: ((_e = field.options) === null || _e === void 0 ? void 0 : _e.map(function (opt) { return ({ text: opt.label, value: opt.value }); })) || [], value: value || '', onChange: handleInputEventChange, onBlur: handleInputEventBlur }, baseProps))));
591
746
  default:
592
- // text, email, number, tel, date, file
593
- return (react_1.default.createElement(Div_1.default, { key: field.name, className: wrapperClass },
594
- react_1.default.createElement(Input_1.default, { type: field.type, value: value, onChange: function (e) { return handleFieldChange(field.name, e.target.value); }, onBlur: function () { return handleFieldBlur(field.name); } })));
747
+ // text, email, number, tel, date, file, password
748
+ return (react_1.default.createElement("div", { key: field.name, className: wrapperClass },
749
+ react_1.default.createElement(Input_1.default, __assign({ type: field.type, value: value || '', onChange: handleInputEventChange, onBlur: handleInputEventBlur }, baseProps))));
595
750
  }
596
- }, [formValues, errors, touched, showPassword, isLoading, getFieldStatus, getColumnClass, handleFieldChange, handleFieldBlur, togglePasswordVisibility]);
597
- // Check if form is valid
598
- var isFormValid = (0, react_1.useMemo)(function () {
599
- return Object.keys(errors).length === 0;
600
- }, [errors]);
601
- // Check if form has empty required fields
602
- var hasEmptyRequiredFields = (0, react_1.useMemo)(function () {
603
- return fields.some(function (field) {
604
- if (!field.required)
605
- return false;
606
- var value = formValues[field.name];
607
- if (field.type === 'checkbox' && field.multiple) {
608
- return !Array.isArray(value) || value.length === 0;
609
- }
610
- if (field.type === 'checkbox' && !field.multiple) {
611
- return value === false;
612
- }
613
- return value === undefined || value === null || value === '';
614
- });
615
- }, [fields, formValues]);
616
- // Submit button disabled state
617
- var isSubmitDisabled = isSubmitting || isLoading || (!isFormValid && hasEmptyRequiredFields);
618
- // WhatsApp button disabled state
619
- var isWhatsAppDisabled = isSubmitDisabled || !whatsappPhone;
620
- // Layout container
621
- var LayoutContainer = (0, react_1.useMemo)(function () {
622
- if (layout === 'grid') {
623
- return function (_a) {
624
- var children = _a.children;
625
- return (react_1.default.createElement("div", { className: "funui_form-grid", style: { display: 'grid', gap: gap, gridTemplateColumns: 'repeat(auto-fit, minmax(250px, 1fr))' } }, children));
626
- };
627
- }
628
- else if (layout === 'horizontal') {
629
- return function (_a) {
630
- var children = _a.children;
631
- return (react_1.default.createElement(Flex_1.default, { gap: gap, wrap: "wrap" }, children));
632
- };
633
- }
634
- else {
635
- // vertical layout (default)
636
- return function (_a) {
637
- var children = _a.children;
638
- return (react_1.default.createElement(Flex_1.default, { direction: "column", gap: gap }, children));
639
- };
640
- }
641
- }, [layout, gap]);
642
- return (react_1.default.createElement("form", { className: "funui_form ".concat(className), onSubmit: handleSubmit, onReset: handleReset, style: { width: '100%' } },
643
- errors._form && (react_1.default.createElement(Div_1.default, { className: "funui_form-error", style: { marginBottom: '1rem' } },
644
- react_1.default.createElement(Flex_1.default, { gap: "0.5rem", alignItems: "center" },
645
- react_1.default.createElement(pi_1.PiWarningCircle, { className: "text-error", size: 20 }),
646
- react_1.default.createElement(Text_1.default, { text: errors._form, size: "sm", color: "error", bold: true })))),
647
- (whatsappIntegration === null || whatsappIntegration === void 0 ? void 0 : whatsappIntegration.enabled) && !whatsappPhone && (react_1.default.createElement(Div_1.default, { className: "funui_form-warning", style: { marginBottom: '1rem', padding: '0.75rem', backgroundColor: 'var(--warning-light)', borderRadius: '0.375rem' } },
648
- react_1.default.createElement(Flex_1.default, { gap: "0.5rem", alignItems: "center" },
649
- react_1.default.createElement(pi_1.PiWarningCircle, { className: "text-warning", size: 20 }),
650
- react_1.default.createElement(Text_1.default, { text: "WhatsApp phone number is not configured. Please provide a valid phone number.", size: "sm", color: "warning" })))),
651
- react_1.default.createElement(LayoutContainer, null, fields.map(renderField)),
652
- react_1.default.createElement(Flex_1.default, { direction: "column", gap: "1rem", style: { marginTop: '2rem' } },
653
- react_1.default.createElement(Flex_1.default, { gap: "1rem", alignItems: "center", justify: "space-between", wrap: "wrap" },
654
- showReset && (react_1.default.createElement(Button_1.default, { type: "reset", text: resetText, bg: "light", color: "text", disabled: isSubmitting || isLoading, funcss: "funui_form-reset-btn" })),
655
- react_1.default.createElement(Button_1.default, { type: "submit", text: submitText, bg: "primary", color: "white", raised: true, startIcon: react_1.default.createElement(pi_1.PiPaperPlaneTilt, null), disabled: isSubmitDisabled, isLoading: isSubmitting || isLoading, funcss: "funui_form-submit-btn" })),
656
- (whatsappIntegration === null || whatsappIntegration === void 0 ? void 0 : whatsappIntegration.enabled) && whatsappPhone && (react_1.default.createElement(WhatsAppButton, { onClick: handleWhatsAppSubmit, disabled: isWhatsAppDisabled, text: "Send via WhatsApp" })))));
751
+ }, [errors, touched, formValues, isLoading, getFieldStatus, handleFieldChange, handleInputEventChange, handleInputEventBlur, fullWidth]);
752
+ // Don't render if no fields are configured
753
+ if (parsedFields.length === 0) {
754
+ console.warn('Form: No fields configured. Please provide fields prop or configure via theme.');
755
+ return null;
756
+ }
757
+ return (react_1.default.createElement("div", { className: "form-wrapper ".concat(centered ? 'center' : '', " ").concat(className), style: { width: "100%", maxWidth: width || "450px" } },
758
+ title && (react_1.default.createElement("div", { className: "form-header", style: { marginBottom: '2rem' } },
759
+ react_1.default.createElement(Text_1.default, { text: title, size: titleSize || "3xl", color: titleColor || "", block: true }),
760
+ description && (react_1.default.createElement(Text_1.default, { article: true, size: descriptionSize || "sm", color: descriptionColor || "" },
761
+ react_1.default.createElement("div", { className: "article text-sm", dangerouslySetInnerHTML: { __html: description } }))))),
762
+ react_1.default.createElement("form", { className: "form", onSubmit: handleSubmit, style: { width: '100%' } },
763
+ react_1.default.createElement(Flex_1.default, { direction: layout === 'horizontal' ? 'row' : 'column', gap: gap, width: '100%' }, parsedFields.map(renderField)),
764
+ react_1.default.createElement(Flex_1.default, { direction: "column", gap: "1rem", style: { marginTop: '2rem', width: fullWidth ? '100%' : undefined } },
765
+ react_1.default.createElement(Button_1.default, { type: "submit", text: hasWhatsApp ? "Send via WhatsApp" : submitText, bg: submitBg || "primary", raised: true, prefix: submitPrefix || hasWhatsApp ? react_1.default.createElement(pi_1.PiWhatsappLogo, null) : react_1.default.createElement(pi_1.PiPaperPlaneTilt, null), suffix: submitSuffix, disabled: isSubmitDisabled, isLoading: isSubmitting || isLoading, fullWidth: fullWidth })))));
657
766
  };
658
767
  exports.default = Form;