@bookinglab/booking-ui-react 1.0.2 → 1.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +128 -0
- package/dist/index.d.cts +136 -1
- package/dist/index.d.ts +136 -1
- package/dist/index.js +330 -35
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +644 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +6 -6
- package/dist/index.cjs +0 -360
- package/dist/index.cjs.map +0 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var react = require('react');
|
|
4
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
3
5
|
|
|
4
6
|
// src/components/BookingForm.tsx
|
|
5
7
|
var cx = (...classes) => classes.filter(Boolean).join(" ");
|
|
@@ -26,18 +28,18 @@ function FormField({
|
|
|
26
28
|
const checkboxLabelClasses = cx("text-sm", classNames?.label ?? "text-gray-700");
|
|
27
29
|
const renderLabel = () => {
|
|
28
30
|
if (question.detail_type === "heading") return null;
|
|
29
|
-
return /* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: labelClasses, children: [
|
|
31
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: labelClasses, children: [
|
|
30
32
|
question.name,
|
|
31
|
-
question.required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
33
|
+
question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
32
34
|
] });
|
|
33
35
|
};
|
|
34
36
|
const renderHelpText = () => {
|
|
35
37
|
if (!question.help_text) return null;
|
|
36
|
-
return /* @__PURE__ */ jsx("p", { className: classNames?.helpText ?? defaultHelpText, children: question.help_text });
|
|
38
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { className: classNames?.helpText ?? defaultHelpText, children: question.help_text });
|
|
37
39
|
};
|
|
38
40
|
const renderError = () => {
|
|
39
41
|
if (!error) return null;
|
|
40
|
-
return /* @__PURE__ */ jsx("p", { id: errorId, className: classNames?.errorText ?? defaultErrorText, role: "alert", children: error });
|
|
42
|
+
return /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: classNames?.errorText ?? defaultErrorText, role: "alert", children: error });
|
|
41
43
|
};
|
|
42
44
|
const ariaProps = {
|
|
43
45
|
"aria-invalid": hasError ? true : void 0,
|
|
@@ -46,11 +48,11 @@ function FormField({
|
|
|
46
48
|
};
|
|
47
49
|
switch (question.detail_type) {
|
|
48
50
|
case "heading":
|
|
49
|
-
return /* @__PURE__ */ jsx("h3", { className: classNames?.heading ?? defaultHeading, children: question.name });
|
|
51
|
+
return /* @__PURE__ */ jsxRuntime.jsx("h3", { className: classNames?.heading ?? defaultHeading, children: question.name });
|
|
50
52
|
case "text_field":
|
|
51
|
-
return /* @__PURE__ */ jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
53
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
52
54
|
renderLabel(),
|
|
53
|
-
/* @__PURE__ */ jsx(
|
|
55
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
54
56
|
"input",
|
|
55
57
|
{
|
|
56
58
|
id: inputId,
|
|
@@ -66,9 +68,9 @@ function FormField({
|
|
|
66
68
|
renderError()
|
|
67
69
|
] });
|
|
68
70
|
case "text_area":
|
|
69
|
-
return /* @__PURE__ */ jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
71
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
70
72
|
renderLabel(),
|
|
71
|
-
/* @__PURE__ */ jsx(
|
|
73
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
72
74
|
"textarea",
|
|
73
75
|
{
|
|
74
76
|
id: inputId,
|
|
@@ -84,9 +86,9 @@ function FormField({
|
|
|
84
86
|
renderError()
|
|
85
87
|
] });
|
|
86
88
|
case "select":
|
|
87
|
-
return /* @__PURE__ */ jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
89
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
88
90
|
renderLabel(),
|
|
89
|
-
/* @__PURE__ */ jsxs(
|
|
91
|
+
/* @__PURE__ */ jsxRuntime.jsxs(
|
|
90
92
|
"select",
|
|
91
93
|
{
|
|
92
94
|
id: inputId,
|
|
@@ -95,8 +97,8 @@ function FormField({
|
|
|
95
97
|
className: inputClasses,
|
|
96
98
|
...ariaProps,
|
|
97
99
|
children: [
|
|
98
|
-
/* @__PURE__ */ jsx("option", { value: "", children: "Select an option" }),
|
|
99
|
-
question.options?.map((option) => /* @__PURE__ */ jsx("option", { value: option.id, children: option.name }, option.id))
|
|
100
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: "Select an option" }),
|
|
101
|
+
question.options?.map((option) => /* @__PURE__ */ jsxRuntime.jsx("option", { value: option.id, children: option.name }, option.id))
|
|
100
102
|
]
|
|
101
103
|
}
|
|
102
104
|
),
|
|
@@ -104,9 +106,9 @@ function FormField({
|
|
|
104
106
|
renderError()
|
|
105
107
|
] });
|
|
106
108
|
case "date":
|
|
107
|
-
return /* @__PURE__ */ jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
109
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
108
110
|
renderLabel(),
|
|
109
|
-
/* @__PURE__ */ jsx(
|
|
111
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
110
112
|
"input",
|
|
111
113
|
{
|
|
112
114
|
id: inputId,
|
|
@@ -123,9 +125,9 @@ function FormField({
|
|
|
123
125
|
renderError()
|
|
124
126
|
] });
|
|
125
127
|
case "number":
|
|
126
|
-
return /* @__PURE__ */ jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
128
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
127
129
|
renderLabel(),
|
|
128
|
-
/* @__PURE__ */ jsx(
|
|
130
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
129
131
|
"input",
|
|
130
132
|
{
|
|
131
133
|
id: inputId,
|
|
@@ -143,9 +145,9 @@ function FormField({
|
|
|
143
145
|
renderError()
|
|
144
146
|
] });
|
|
145
147
|
case "check":
|
|
146
|
-
return /* @__PURE__ */ jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
147
|
-
/* @__PURE__ */ jsxs("div", { className: "flex items-start gap-2", children: [
|
|
148
|
-
/* @__PURE__ */ jsx(
|
|
148
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: classNames?.fieldWrapper ?? defaultFieldWrapper, children: [
|
|
149
|
+
/* @__PURE__ */ jsxRuntime.jsxs("div", { className: "flex items-start gap-2", children: [
|
|
150
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
149
151
|
"input",
|
|
150
152
|
{
|
|
151
153
|
id: inputId,
|
|
@@ -156,9 +158,9 @@ function FormField({
|
|
|
156
158
|
...ariaProps
|
|
157
159
|
}
|
|
158
160
|
),
|
|
159
|
-
/* @__PURE__ */ jsxs("label", { htmlFor: inputId, className: checkboxLabelClasses, children: [
|
|
161
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: inputId, className: checkboxLabelClasses, children: [
|
|
160
162
|
question.name,
|
|
161
|
-
question.required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
163
|
+
question.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
162
164
|
] })
|
|
163
165
|
] }),
|
|
164
166
|
renderHelpText(),
|
|
@@ -180,10 +182,10 @@ function BookingForm({
|
|
|
180
182
|
...classNamesProp,
|
|
181
183
|
label: classNamesProp?.label ?? labelClassName
|
|
182
184
|
};
|
|
183
|
-
const [values, setValues] = useState({});
|
|
184
|
-
const [errors, setErrors] = useState({});
|
|
185
|
-
const [touched, setTouched] = useState({});
|
|
186
|
-
const isQuestionVisible = useCallback(
|
|
185
|
+
const [values, setValues] = react.useState({});
|
|
186
|
+
const [errors, setErrors] = react.useState({});
|
|
187
|
+
const [touched, setTouched] = react.useState({});
|
|
188
|
+
const isQuestionVisible = react.useCallback(
|
|
187
189
|
(question) => {
|
|
188
190
|
const { settings } = question;
|
|
189
191
|
if (!settings?.conditional_answers) {
|
|
@@ -246,7 +248,7 @@ function BookingForm({
|
|
|
246
248
|
[values, questions]
|
|
247
249
|
);
|
|
248
250
|
const visibleQuestions = questions.filter(isQuestionVisible);
|
|
249
|
-
const validateField = useCallback((question, value) => {
|
|
251
|
+
const validateField = react.useCallback((question, value) => {
|
|
250
252
|
if (question.detail_type === "heading") return null;
|
|
251
253
|
if (question.required) {
|
|
252
254
|
if (value === void 0 || value === "" || value === null) {
|
|
@@ -267,7 +269,7 @@ function BookingForm({
|
|
|
267
269
|
}
|
|
268
270
|
return null;
|
|
269
271
|
}, []);
|
|
270
|
-
const validateAll = useCallback(() => {
|
|
272
|
+
const validateAll = react.useCallback(() => {
|
|
271
273
|
const newErrors = {};
|
|
272
274
|
let isValid = true;
|
|
273
275
|
visibleQuestions.forEach((question) => {
|
|
@@ -280,7 +282,7 @@ function BookingForm({
|
|
|
280
282
|
setErrors(newErrors);
|
|
281
283
|
return isValid;
|
|
282
284
|
}, [visibleQuestions, values, validateField]);
|
|
283
|
-
useEffect(() => {
|
|
285
|
+
react.useEffect(() => {
|
|
284
286
|
const visibleIds = new Set(visibleQuestions.map((q) => q.id));
|
|
285
287
|
setErrors((prev) => {
|
|
286
288
|
let changed = false;
|
|
@@ -330,8 +332,8 @@ function BookingForm({
|
|
|
330
332
|
}
|
|
331
333
|
};
|
|
332
334
|
const defaultButton = "w-full mt-4 px-4 py-2 bg-blue-600 text-white font-medium rounded-md hover:bg-blue-700 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2 transition-colors";
|
|
333
|
-
return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
334
|
-
visibleQuestions.map((question) => /* @__PURE__ */ jsx(
|
|
335
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
336
|
+
visibleQuestions.map((question) => /* @__PURE__ */ jsxRuntime.jsx(
|
|
335
337
|
FormField,
|
|
336
338
|
{
|
|
337
339
|
question,
|
|
@@ -342,7 +344,7 @@ function BookingForm({
|
|
|
342
344
|
},
|
|
343
345
|
question.id
|
|
344
346
|
)),
|
|
345
|
-
/* @__PURE__ */ jsx(
|
|
347
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
346
348
|
"button",
|
|
347
349
|
{
|
|
348
350
|
type: "submit",
|
|
@@ -353,6 +355,299 @@ function BookingForm({
|
|
|
353
355
|
] });
|
|
354
356
|
}
|
|
355
357
|
|
|
356
|
-
|
|
358
|
+
// src/utils/validators.ts
|
|
359
|
+
function required(value) {
|
|
360
|
+
if (!value || value.trim() === "") {
|
|
361
|
+
return "This field is required";
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
function email(value) {
|
|
366
|
+
if (!value) return null;
|
|
367
|
+
const emailRegex = /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$/;
|
|
368
|
+
if (!emailRegex.test(value)) {
|
|
369
|
+
return "Please enter a valid email address";
|
|
370
|
+
}
|
|
371
|
+
return null;
|
|
372
|
+
}
|
|
373
|
+
function phone(value) {
|
|
374
|
+
if (!value) return null;
|
|
375
|
+
const cleaned = value.replace(/[\s\-\(\)]/g, "");
|
|
376
|
+
const phoneRegex = /^\+?[0-9]{7,15}$/;
|
|
377
|
+
if (!phoneRegex.test(cleaned)) {
|
|
378
|
+
return "Please enter a valid phone number";
|
|
379
|
+
}
|
|
380
|
+
return null;
|
|
381
|
+
}
|
|
382
|
+
function ukPostcode(value) {
|
|
383
|
+
if (!value) return null;
|
|
384
|
+
const postcodeRegex = /^([A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2})$/i;
|
|
385
|
+
if (!postcodeRegex.test(value.trim())) {
|
|
386
|
+
return "Please enter a valid UK postcode";
|
|
387
|
+
}
|
|
388
|
+
return null;
|
|
389
|
+
}
|
|
390
|
+
function minLen(min) {
|
|
391
|
+
return (value) => {
|
|
392
|
+
if (!value) return null;
|
|
393
|
+
if (value.trim().length < min) {
|
|
394
|
+
return `Must be at least ${min} character${min === 1 ? "" : "s"}`;
|
|
395
|
+
}
|
|
396
|
+
return null;
|
|
397
|
+
};
|
|
398
|
+
}
|
|
399
|
+
function compose(...validators) {
|
|
400
|
+
return (value) => {
|
|
401
|
+
for (const validator of validators) {
|
|
402
|
+
const error = validator(value);
|
|
403
|
+
if (error) return error;
|
|
404
|
+
}
|
|
405
|
+
return null;
|
|
406
|
+
};
|
|
407
|
+
}
|
|
408
|
+
var DEFAULT_FIELDS = [
|
|
409
|
+
{
|
|
410
|
+
name: "firstName",
|
|
411
|
+
label: "First name",
|
|
412
|
+
type: "text",
|
|
413
|
+
required: true,
|
|
414
|
+
validate: required
|
|
415
|
+
},
|
|
416
|
+
{
|
|
417
|
+
name: "lastName",
|
|
418
|
+
label: "Last name",
|
|
419
|
+
type: "text",
|
|
420
|
+
required: true,
|
|
421
|
+
validate: required
|
|
422
|
+
},
|
|
423
|
+
{
|
|
424
|
+
name: "email",
|
|
425
|
+
label: "Email address",
|
|
426
|
+
type: "email",
|
|
427
|
+
required: true,
|
|
428
|
+
validate: compose(required, email)
|
|
429
|
+
},
|
|
430
|
+
{
|
|
431
|
+
name: "phone",
|
|
432
|
+
label: "Contact number",
|
|
433
|
+
type: "tel",
|
|
434
|
+
required: false,
|
|
435
|
+
validate: phone
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
name: "address1",
|
|
439
|
+
label: "Address 1",
|
|
440
|
+
type: "text",
|
|
441
|
+
required: true,
|
|
442
|
+
validate: required
|
|
443
|
+
},
|
|
444
|
+
{
|
|
445
|
+
name: "address2",
|
|
446
|
+
label: "Address 2",
|
|
447
|
+
type: "text",
|
|
448
|
+
required: false
|
|
449
|
+
},
|
|
450
|
+
{
|
|
451
|
+
name: "city",
|
|
452
|
+
label: "Town/City",
|
|
453
|
+
type: "text",
|
|
454
|
+
required: true,
|
|
455
|
+
validate: required
|
|
456
|
+
},
|
|
457
|
+
{
|
|
458
|
+
name: "postcode",
|
|
459
|
+
label: "Postcode",
|
|
460
|
+
type: "text",
|
|
461
|
+
required: true,
|
|
462
|
+
validate: compose(required, ukPostcode)
|
|
463
|
+
}
|
|
464
|
+
];
|
|
465
|
+
var RegistrationForm = react.forwardRef(
|
|
466
|
+
({
|
|
467
|
+
fields = DEFAULT_FIELDS,
|
|
468
|
+
onSubmit,
|
|
469
|
+
onChange,
|
|
470
|
+
validateOnBlur = true,
|
|
471
|
+
submitLabel = "Submit",
|
|
472
|
+
className = "",
|
|
473
|
+
classNames = {}
|
|
474
|
+
}, ref) => {
|
|
475
|
+
const formId = react.useId();
|
|
476
|
+
const [values, setValues] = react.useState({});
|
|
477
|
+
const [errors, setErrors] = react.useState({});
|
|
478
|
+
const [touched, setTouched] = react.useState({});
|
|
479
|
+
const validateField = react.useCallback(
|
|
480
|
+
(field, value) => {
|
|
481
|
+
if (field.required && (!value || value.trim() === "")) {
|
|
482
|
+
return "This field is required";
|
|
483
|
+
}
|
|
484
|
+
if (field.validate && value) {
|
|
485
|
+
return field.validate(value);
|
|
486
|
+
}
|
|
487
|
+
return null;
|
|
488
|
+
},
|
|
489
|
+
[]
|
|
490
|
+
);
|
|
491
|
+
const validateAll = react.useCallback(() => {
|
|
492
|
+
const newErrors = {};
|
|
493
|
+
let isValid = true;
|
|
494
|
+
for (const field of fields) {
|
|
495
|
+
const value = values[field.name] || "";
|
|
496
|
+
const error = validateField(field, value);
|
|
497
|
+
if (error) {
|
|
498
|
+
newErrors[field.name] = error;
|
|
499
|
+
isValid = false;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
setErrors(newErrors);
|
|
503
|
+
return isValid;
|
|
504
|
+
}, [fields, values, validateField]);
|
|
505
|
+
const checkIsValid = react.useCallback(
|
|
506
|
+
(currentValues) => {
|
|
507
|
+
for (const field of fields) {
|
|
508
|
+
const value = currentValues[field.name] || "";
|
|
509
|
+
const error = validateField(field, value);
|
|
510
|
+
if (error) return false;
|
|
511
|
+
}
|
|
512
|
+
return true;
|
|
513
|
+
},
|
|
514
|
+
[fields, validateField]
|
|
515
|
+
);
|
|
516
|
+
const handleChange = react.useCallback(
|
|
517
|
+
(fieldName, value) => {
|
|
518
|
+
const newValues = { ...values, [fieldName]: value };
|
|
519
|
+
setValues(newValues);
|
|
520
|
+
if (touched[fieldName]) {
|
|
521
|
+
const field = fields.find((f) => f.name === fieldName);
|
|
522
|
+
if (field) {
|
|
523
|
+
const error = validateField(field, value);
|
|
524
|
+
if (!error) {
|
|
525
|
+
setErrors((prev) => {
|
|
526
|
+
const next = { ...prev };
|
|
527
|
+
delete next[fieldName];
|
|
528
|
+
return next;
|
|
529
|
+
});
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
if (onChange) {
|
|
534
|
+
const isValid = checkIsValid(newValues);
|
|
535
|
+
onChange(newValues, isValid);
|
|
536
|
+
}
|
|
537
|
+
},
|
|
538
|
+
[values, touched, fields, validateField, onChange, checkIsValid]
|
|
539
|
+
);
|
|
540
|
+
const handleBlur = react.useCallback(
|
|
541
|
+
(fieldName) => {
|
|
542
|
+
setTouched((prev) => ({ ...prev, [fieldName]: true }));
|
|
543
|
+
if (validateOnBlur) {
|
|
544
|
+
const field = fields.find((f) => f.name === fieldName);
|
|
545
|
+
if (field) {
|
|
546
|
+
const value = values[fieldName] || "";
|
|
547
|
+
const error = validateField(field, value);
|
|
548
|
+
if (error) {
|
|
549
|
+
setErrors((prev) => ({ ...prev, [fieldName]: error }));
|
|
550
|
+
} else {
|
|
551
|
+
setErrors((prev) => {
|
|
552
|
+
const next = { ...prev };
|
|
553
|
+
delete next[fieldName];
|
|
554
|
+
return next;
|
|
555
|
+
});
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
}
|
|
559
|
+
},
|
|
560
|
+
[validateOnBlur, fields, values, validateField]
|
|
561
|
+
);
|
|
562
|
+
const handleSubmit = react.useCallback(
|
|
563
|
+
(e) => {
|
|
564
|
+
e.preventDefault();
|
|
565
|
+
const allTouched = {};
|
|
566
|
+
for (const field of fields) {
|
|
567
|
+
allTouched[field.name] = true;
|
|
568
|
+
}
|
|
569
|
+
setTouched(allTouched);
|
|
570
|
+
if (validateAll()) {
|
|
571
|
+
onSubmit(values);
|
|
572
|
+
}
|
|
573
|
+
},
|
|
574
|
+
[fields, validateAll, onSubmit, values]
|
|
575
|
+
);
|
|
576
|
+
react.useImperativeHandle(
|
|
577
|
+
ref,
|
|
578
|
+
() => ({
|
|
579
|
+
reset: () => {
|
|
580
|
+
setValues({});
|
|
581
|
+
setErrors({});
|
|
582
|
+
setTouched({});
|
|
583
|
+
},
|
|
584
|
+
setValues: (newValues) => {
|
|
585
|
+
setValues((prev) => {
|
|
586
|
+
const merged = { ...prev };
|
|
587
|
+
for (const [key, value] of Object.entries(newValues)) {
|
|
588
|
+
if (value !== void 0) {
|
|
589
|
+
merged[key] = value;
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
return merged;
|
|
593
|
+
});
|
|
594
|
+
}
|
|
595
|
+
}),
|
|
596
|
+
[]
|
|
597
|
+
);
|
|
598
|
+
const styles = {
|
|
599
|
+
fieldWrapper: classNames.fieldWrapper || "mb-4",
|
|
600
|
+
label: classNames.label || "block text-sm font-medium mb-1",
|
|
601
|
+
input: classNames.input || "w-full px-3 py-2 border rounded-md",
|
|
602
|
+
inputError: classNames.inputError || "border-red-500",
|
|
603
|
+
errorText: classNames.errorText || "mt-1 text-xs text-red-600",
|
|
604
|
+
button: classNames.button || "w-full mt-4 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50"
|
|
605
|
+
};
|
|
606
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
607
|
+
fields.map((field) => {
|
|
608
|
+
const fieldId = `${formId}-${field.name}`;
|
|
609
|
+
const errorId = `${fieldId}-error`;
|
|
610
|
+
const value = values[field.name] || "";
|
|
611
|
+
const error = errors[field.name];
|
|
612
|
+
const isTouched = touched[field.name];
|
|
613
|
+
const showError = isTouched && error;
|
|
614
|
+
return /* @__PURE__ */ jsxRuntime.jsxs("div", { className: styles.fieldWrapper, children: [
|
|
615
|
+
/* @__PURE__ */ jsxRuntime.jsxs("label", { htmlFor: fieldId, className: styles.label, children: [
|
|
616
|
+
field.label,
|
|
617
|
+
field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
618
|
+
] }),
|
|
619
|
+
/* @__PURE__ */ jsxRuntime.jsx(
|
|
620
|
+
"input",
|
|
621
|
+
{
|
|
622
|
+
id: fieldId,
|
|
623
|
+
name: field.name,
|
|
624
|
+
type: field.type,
|
|
625
|
+
value,
|
|
626
|
+
onChange: (e) => handleChange(field.name, e.target.value),
|
|
627
|
+
onBlur: () => handleBlur(field.name),
|
|
628
|
+
placeholder: field.placeholder,
|
|
629
|
+
className: `${styles.input} ${showError ? styles.inputError : ""}`,
|
|
630
|
+
"aria-invalid": showError ? "true" : "false",
|
|
631
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
632
|
+
"aria-required": field.required ? "true" : "false"
|
|
633
|
+
}
|
|
634
|
+
),
|
|
635
|
+
showError && /* @__PURE__ */ jsxRuntime.jsx("p", { id: errorId, className: styles.errorText, role: "alert", children: error })
|
|
636
|
+
] }, field.name);
|
|
637
|
+
}),
|
|
638
|
+
/* @__PURE__ */ jsxRuntime.jsx("button", { type: "submit", className: styles.button, children: submitLabel })
|
|
639
|
+
] });
|
|
640
|
+
}
|
|
641
|
+
);
|
|
642
|
+
RegistrationForm.displayName = "RegistrationForm";
|
|
643
|
+
|
|
644
|
+
exports.BookingForm = BookingForm;
|
|
645
|
+
exports.RegistrationForm = RegistrationForm;
|
|
646
|
+
exports.compose = compose;
|
|
647
|
+
exports.email = email;
|
|
648
|
+
exports.minLen = minLen;
|
|
649
|
+
exports.phone = phone;
|
|
650
|
+
exports.required = required;
|
|
651
|
+
exports.ukPostcode = ukPostcode;
|
|
357
652
|
//# sourceMappingURL=index.js.map
|
|
358
653
|
//# sourceMappingURL=index.js.map
|