funuicss 3.8.6 → 3.8.8
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/css/fun.css +393 -89
- package/index.d.ts +1 -0
- package/index.js +3 -1
- package/package.json +1 -1
- package/ui/accordion/Accordion.js +3 -1
- package/ui/button/Button.d.ts +2 -1
- package/ui/button/Button.js +8 -7
- package/ui/div/Div.d.ts +3 -1
- package/ui/div/Div.js +2 -2
- package/ui/form/Form.d.ts +68 -0
- package/ui/form/Form.js +658 -0
- package/ui/input/FileUpload.js +370 -21
- package/ui/input/Input.d.ts +35 -1
- package/ui/input/Input.js +1041 -41
- package/ui/products/CartModal.d.ts +0 -2
- package/ui/products/CartModal.js +59 -39
- package/ui/products/ProductCard.js +9 -22
- package/ui/products/ProductDetail.js +111 -80
- package/ui/products/ProductLoader.d.ts +3 -0
- package/ui/products/ProductLoader.js +22 -0
- package/ui/products/Store.d.ts +32 -7
- package/ui/products/Store.js +393 -94
- package/ui/progress/Bar.js +2 -2
- package/ui/theme/theme.d.ts +4 -0
- package/ui/theme/theme.js +336 -133
package/ui/form/Form.js
ADDED
|
@@ -0,0 +1,658 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
'use client';
|
|
3
|
+
var __assign = (this && this.__assign) || function () {
|
|
4
|
+
__assign = Object.assign || function(t) {
|
|
5
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
6
|
+
s = arguments[i];
|
|
7
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
8
|
+
t[p] = s[p];
|
|
9
|
+
}
|
|
10
|
+
return t;
|
|
11
|
+
};
|
|
12
|
+
return __assign.apply(this, arguments);
|
|
13
|
+
};
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
26
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
27
|
+
}) : function(o, v) {
|
|
28
|
+
o["default"] = v;
|
|
29
|
+
});
|
|
30
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
31
|
+
var ownKeys = function(o) {
|
|
32
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
33
|
+
var ar = [];
|
|
34
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
35
|
+
return ar;
|
|
36
|
+
};
|
|
37
|
+
return ownKeys(o);
|
|
38
|
+
};
|
|
39
|
+
return function (mod) {
|
|
40
|
+
if (mod && mod.__esModule) return mod;
|
|
41
|
+
var result = {};
|
|
42
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
43
|
+
__setModuleDefault(result, mod);
|
|
44
|
+
return result;
|
|
45
|
+
};
|
|
46
|
+
})();
|
|
47
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
48
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
49
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
50
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
51
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
52
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
53
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
54
|
+
});
|
|
55
|
+
};
|
|
56
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
57
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
58
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
59
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
60
|
+
function step(op) {
|
|
61
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
62
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
63
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
64
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
65
|
+
switch (op[0]) {
|
|
66
|
+
case 0: case 1: t = op; break;
|
|
67
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
68
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
69
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
70
|
+
default:
|
|
71
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
72
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
73
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
74
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
75
|
+
if (t[2]) _.ops.pop();
|
|
76
|
+
_.trys.pop(); continue;
|
|
77
|
+
}
|
|
78
|
+
op = body.call(thisArg, _);
|
|
79
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
80
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
84
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
85
|
+
if (ar || !(i in from)) {
|
|
86
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
87
|
+
ar[i] = from[i];
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
91
|
+
};
|
|
92
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
93
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
94
|
+
};
|
|
95
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
96
|
+
var react_1 = __importStar(require("react"));
|
|
97
|
+
var Button_1 = __importDefault(require("../button/Button"));
|
|
98
|
+
var Input_1 = __importDefault(require("../input/Input"));
|
|
99
|
+
var Flex_1 = __importDefault(require("../flex/Flex"));
|
|
100
|
+
var Div_1 = __importDefault(require("../div/Div"));
|
|
101
|
+
var Text_1 = __importDefault(require("../text/Text"));
|
|
102
|
+
var pi_1 = require("react-icons/pi");
|
|
103
|
+
// Custom Checkbox Component
|
|
104
|
+
var FormCheckbox = function (_a) {
|
|
105
|
+
var label = _a.label, checked = _a.checked, onChange = _a.onChange, disabled = _a.disabled, required = _a.required, value = _a.value, id = _a.id;
|
|
106
|
+
return (react_1.default.createElement("label", { className: "funui_form-checkbox", style: {
|
|
107
|
+
display: 'flex',
|
|
108
|
+
alignItems: 'center',
|
|
109
|
+
gap: '0.5rem',
|
|
110
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
111
|
+
userSelect: 'none',
|
|
112
|
+
width: 'fit-content',
|
|
113
|
+
} },
|
|
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' } }),
|
|
115
|
+
react_1.default.createElement("div", { className: "funui_form-checkbox-box", style: {
|
|
116
|
+
width: '1.25rem',
|
|
117
|
+
height: '1.25rem',
|
|
118
|
+
border: checked ? '2px solid var(--primary)' : '2px solid var(--border)',
|
|
119
|
+
borderRadius: '0.25rem',
|
|
120
|
+
backgroundColor: checked ? 'var(--primary)' : 'transparent',
|
|
121
|
+
position: 'relative',
|
|
122
|
+
transition: 'all 0.2s ease',
|
|
123
|
+
display: 'flex',
|
|
124
|
+
alignItems: 'center',
|
|
125
|
+
justifyContent: 'center',
|
|
126
|
+
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' } },
|
|
134
|
+
label,
|
|
135
|
+
required && ' *'))));
|
|
136
|
+
};
|
|
137
|
+
// Custom Radio Component
|
|
138
|
+
var FormRadio = function (_a) {
|
|
139
|
+
var label = _a.label, checked = _a.checked, onChange = _a.onChange, disabled = _a.disabled, required = _a.required, value = _a.value, id = _a.id;
|
|
140
|
+
return (react_1.default.createElement("label", { className: "funui_form-radio", style: {
|
|
141
|
+
display: 'flex',
|
|
142
|
+
alignItems: 'center',
|
|
143
|
+
gap: '0.5rem',
|
|
144
|
+
cursor: disabled ? 'not-allowed' : 'pointer',
|
|
145
|
+
userSelect: 'none',
|
|
146
|
+
width: 'fit-content',
|
|
147
|
+
} },
|
|
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' } }),
|
|
149
|
+
react_1.default.createElement("div", { className: "funui_form-radio-circle", style: {
|
|
150
|
+
width: '1.25rem',
|
|
151
|
+
height: '1.25rem',
|
|
152
|
+
border: checked ? '2px solid var(--primary)' : '2px solid var(--border)',
|
|
153
|
+
borderRadius: '50%',
|
|
154
|
+
backgroundColor: 'transparent',
|
|
155
|
+
position: 'relative',
|
|
156
|
+
transition: 'all 0.2s ease',
|
|
157
|
+
display: 'flex',
|
|
158
|
+
alignItems: 'center',
|
|
159
|
+
justifyContent: 'center',
|
|
160
|
+
flexShrink: 0,
|
|
161
|
+
} }, checked && (react_1.default.createElement("div", { style: {
|
|
162
|
+
width: '0.75rem',
|
|
163
|
+
height: '0.75rem',
|
|
164
|
+
backgroundColor: 'var(--primary)',
|
|
165
|
+
borderRadius: '50%',
|
|
166
|
+
} }))),
|
|
167
|
+
label && (react_1.default.createElement("span", { className: "funui_form-radio-label", style: { fontSize: '0.875rem' } },
|
|
168
|
+
label,
|
|
169
|
+
required && ' *'))));
|
|
170
|
+
};
|
|
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) {
|
|
195
|
+
var value = values[field.name];
|
|
196
|
+
var displayValue = value;
|
|
197
|
+
// Format array values (for multiple checkboxes)
|
|
198
|
+
if (Array.isArray(value)) {
|
|
199
|
+
displayValue = value.join(', ');
|
|
200
|
+
}
|
|
201
|
+
// Format checkbox values
|
|
202
|
+
if (field.type === 'checkbox' && !field.multiple) {
|
|
203
|
+
displayValue = value ? 'Yes' : 'No';
|
|
204
|
+
}
|
|
205
|
+
// Format select/radio values
|
|
206
|
+
if ((field.type === 'select' || field.type === 'radio') && field.options) {
|
|
207
|
+
var option = field.options.find(function (opt) { return opt.value === value; });
|
|
208
|
+
displayValue = option ? option.label : value;
|
|
209
|
+
}
|
|
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);
|
|
220
|
+
}
|
|
221
|
+
return encodeURIComponent(message);
|
|
222
|
+
};
|
|
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;
|
|
226
|
+
// 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 () {
|
|
235
|
+
var initialValues = {};
|
|
236
|
+
fields.forEach(function (field) {
|
|
237
|
+
var _a, _b;
|
|
238
|
+
// Priority: field.value > defaultValues > default based on type
|
|
239
|
+
if (field.value !== undefined) {
|
|
240
|
+
initialValues[field.name] = field.value;
|
|
241
|
+
}
|
|
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] = '';
|
|
253
|
+
}
|
|
254
|
+
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
|
+
});
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
setFormValues(initialValues);
|
|
266
|
+
}, [fields, defaultValues]);
|
|
267
|
+
// Initialize WhatsApp phone number
|
|
268
|
+
(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);
|
|
273
|
+
}
|
|
274
|
+
}, [whatsappIntegration]);
|
|
275
|
+
// Validate a single field
|
|
276
|
+
var validateField = (0, react_1.useCallback)(function (field, value) {
|
|
277
|
+
var _a, _b, _c, _d, _e;
|
|
278
|
+
// Required validation
|
|
279
|
+
if (field.required) {
|
|
280
|
+
if (value === undefined || value === null || value === '') {
|
|
281
|
+
return "".concat(field.label || field.name, " is required");
|
|
282
|
+
}
|
|
283
|
+
if (field.type === 'checkbox' && field.multiple && Array.isArray(value) && value.length === 0) {
|
|
284
|
+
return "".concat(field.label || field.name, " is required");
|
|
285
|
+
}
|
|
286
|
+
if (field.type === 'checkbox' && !field.multiple && value === false) {
|
|
287
|
+
return "".concat(field.label || field.name, " is required");
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
// Type-specific validations
|
|
291
|
+
if (value && value !== '') {
|
|
292
|
+
// Email validation
|
|
293
|
+
if (field.type === 'email') {
|
|
294
|
+
var emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
295
|
+
if (!emailRegex.test(value)) {
|
|
296
|
+
return 'Please enter a valid email address';
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
// Number validation
|
|
300
|
+
if (field.type === 'number') {
|
|
301
|
+
var numValue = parseFloat(value);
|
|
302
|
+
if (isNaN(numValue)) {
|
|
303
|
+
return 'Please enter a valid number';
|
|
304
|
+
}
|
|
305
|
+
var min = (_a = field.inputProps) === null || _a === void 0 ? void 0 : _a.min;
|
|
306
|
+
var max = (_b = field.inputProps) === null || _b === void 0 ? void 0 : _b.max;
|
|
307
|
+
if (min !== undefined && numValue < parseFloat(min.toString())) {
|
|
308
|
+
return "Minimum value is ".concat(min);
|
|
309
|
+
}
|
|
310
|
+
if (max !== undefined && numValue > parseFloat(max.toString())) {
|
|
311
|
+
return "Maximum value is ".concat(max);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
// Phone validation (basic)
|
|
315
|
+
if (field.type === 'tel') {
|
|
316
|
+
var phoneRegex = /^[\+]?[1-9][\d]{0,17}$/;
|
|
317
|
+
if (!phoneRegex.test(value.replace(/[\s+\-()]/g, ''))) {
|
|
318
|
+
return 'Please enter a valid phone number';
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
// Length validation
|
|
322
|
+
if (typeof value === 'string') {
|
|
323
|
+
var minLength = (_c = field.inputProps) === null || _c === void 0 ? void 0 : _c.minLength;
|
|
324
|
+
var maxLength = (_d = field.inputProps) === null || _d === void 0 ? void 0 : _d.maxLength;
|
|
325
|
+
if (minLength && value.length < minLength) {
|
|
326
|
+
return "Minimum ".concat(minLength, " characters required");
|
|
327
|
+
}
|
|
328
|
+
if (maxLength && value.length > maxLength) {
|
|
329
|
+
return "Maximum ".concat(maxLength, " characters allowed");
|
|
330
|
+
}
|
|
331
|
+
}
|
|
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';
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
return null;
|
|
341
|
+
}, []);
|
|
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;
|
|
347
|
+
setFormValues(function (prev) {
|
|
348
|
+
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;
|
|
366
|
+
});
|
|
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; });
|
|
371
|
+
if (!field)
|
|
372
|
+
return;
|
|
373
|
+
setTouched(function (prev) {
|
|
374
|
+
var _a;
|
|
375
|
+
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = true, _a)));
|
|
376
|
+
});
|
|
377
|
+
// Validate on blur
|
|
378
|
+
var value = formValues[fieldName];
|
|
379
|
+
var error = validateField(field, value);
|
|
380
|
+
setErrors(function (prev) {
|
|
381
|
+
var _a;
|
|
382
|
+
if (error) {
|
|
383
|
+
return __assign(__assign({}, prev), (_a = {}, _a[fieldName] = error, _a));
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
var newErrors = __assign({}, prev);
|
|
387
|
+
delete newErrors[fieldName];
|
|
388
|
+
return newErrors;
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
}, [fields, formValues, validateField]);
|
|
392
|
+
// Toggle password visibility
|
|
393
|
+
var togglePasswordVisibility = (0, react_1.useCallback)(function (fieldName) {
|
|
394
|
+
setShowPassword(function (prev) {
|
|
395
|
+
var _a;
|
|
396
|
+
return (__assign(__assign({}, prev), (_a = {}, _a[fieldName] = !prev[fieldName], _a)));
|
|
397
|
+
});
|
|
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');
|
|
403
|
+
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);
|
|
411
|
+
if (error) {
|
|
412
|
+
newErrors[field.name] = error;
|
|
413
|
+
hasErrors = true;
|
|
414
|
+
}
|
|
415
|
+
});
|
|
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]);
|
|
433
|
+
// Handle form submission
|
|
434
|
+
var handleSubmit = (0, react_1.useCallback)(function (e) { return __awaiter(void 0, void 0, void 0, function () {
|
|
435
|
+
var allTouched, newErrors, hasErrors, error_2;
|
|
436
|
+
return __generator(this, function (_a) {
|
|
437
|
+
switch (_a.label) {
|
|
438
|
+
case 0:
|
|
439
|
+
e.preventDefault();
|
|
440
|
+
allTouched = {};
|
|
441
|
+
fields.forEach(function (field) {
|
|
442
|
+
allTouched[field.name] = true;
|
|
443
|
+
});
|
|
444
|
+
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;
|
|
453
|
+
}
|
|
454
|
+
});
|
|
455
|
+
setErrors(newErrors);
|
|
456
|
+
if (hasErrors)
|
|
457
|
+
return [2 /*return*/];
|
|
458
|
+
// Submit
|
|
459
|
+
setIsSubmitting(true);
|
|
460
|
+
_a.label = 1;
|
|
461
|
+
case 1:
|
|
462
|
+
_a.trys.push([1, 3, 4, 5]);
|
|
463
|
+
return [4 /*yield*/, onSubmit(formValues)];
|
|
464
|
+
case 2:
|
|
465
|
+
_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];
|
|
472
|
+
case 4:
|
|
473
|
+
setIsSubmitting(false);
|
|
474
|
+
return [7 /*endfinally*/];
|
|
475
|
+
case 5: return [2 /*return*/];
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
}); }, [fields, formValues, validateField, onSubmit]);
|
|
479
|
+
// Handle form reset
|
|
480
|
+
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] = '';
|
|
489
|
+
}
|
|
490
|
+
else if (field.type === 'select' && ((_b = field.options) === null || _b === void 0 ? void 0 : _b.length)) {
|
|
491
|
+
resetValues[field.name] = '';
|
|
492
|
+
}
|
|
493
|
+
else {
|
|
494
|
+
resetValues[field.name] = '';
|
|
495
|
+
}
|
|
496
|
+
});
|
|
497
|
+
setFormValues(resetValues);
|
|
498
|
+
setErrors({});
|
|
499
|
+
setTouched({});
|
|
500
|
+
setShowPassword({});
|
|
501
|
+
}, [fields]);
|
|
502
|
+
// Get field status for Input component
|
|
503
|
+
var getFieldStatus = (0, react_1.useCallback)(function (fieldName) {
|
|
504
|
+
var error = errors[fieldName];
|
|
505
|
+
var isTouched = touched[fieldName];
|
|
506
|
+
var value = formValues[fieldName];
|
|
507
|
+
if (error)
|
|
508
|
+
return 'error';
|
|
509
|
+
if (isTouched && !error && value && value !== '' && !(Array.isArray(value) && value.length === 0)) {
|
|
510
|
+
return 'success';
|
|
511
|
+
}
|
|
512
|
+
return 'default';
|
|
513
|
+
}, [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';
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return '';
|
|
526
|
+
}, [layout]);
|
|
527
|
+
// Render field based on type
|
|
528
|
+
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 : '';
|
|
531
|
+
var status = getFieldStatus(field.name);
|
|
532
|
+
var error = errors[field.name];
|
|
533
|
+
var isTouched = touched[field.name];
|
|
534
|
+
var showError = error && isTouched;
|
|
535
|
+
// Field wrapper classes
|
|
536
|
+
var wrapperClass = "funui_form-field ".concat(getColumnClass(field), " ").concat(showError ? 'funui_form-field-error' : '').trim();
|
|
537
|
+
// Helper text (error takes priority)
|
|
538
|
+
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;
|
|
540
|
+
// 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);
|
|
542
|
+
// Render based on field type
|
|
543
|
+
switch (field.type) {
|
|
544
|
+
case 'checkbox':
|
|
545
|
+
if ((_c = field.options) === null || _c === void 0 ? void 0 : _c.length) {
|
|
546
|
+
// 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' } },
|
|
549
|
+
react_1.default.createElement(Text_1.default, { text: field.label + (field.required ? ' *' : ''), size: "sm", color: "text", bold: true }))),
|
|
550
|
+
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
|
+
}
|
|
563
|
+
}
|
|
564
|
+
else {
|
|
565
|
+
handleFieldChange(field.name, checked ? option.value : false);
|
|
566
|
+
}
|
|
567
|
+
}, disabled: field.disabled || option.disabled || isLoading, required: field.required && index === 0, value: option.value }));
|
|
568
|
+
}))));
|
|
569
|
+
}
|
|
570
|
+
else {
|
|
571
|
+
// 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 })));
|
|
574
|
+
}
|
|
575
|
+
case 'radio':
|
|
576
|
+
if (!((_d = field.options) === null || _d === void 0 ? void 0 : _d.length))
|
|
577
|
+
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' } },
|
|
580
|
+
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 })); }))));
|
|
582
|
+
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); } })));
|
|
585
|
+
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 }) })));
|
|
591
|
+
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); } })));
|
|
595
|
+
}
|
|
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" })))));
|
|
657
|
+
};
|
|
658
|
+
exports.default = Form;
|