@bookinglab/booking-ui-react 1.1.0 → 1.2.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 +40 -0
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +35 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +35 -13
- package/dist/index.mjs.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -193,6 +193,7 @@ A reusable, accessible registration form component with built-in validation, cus
|
|
|
193
193
|
| Prop | Type | Default | Description |
|
|
194
194
|
|------|------|---------|-------------|
|
|
195
195
|
| `fields` | `FieldConfig[]` | Default fields | Custom field configuration |
|
|
196
|
+
| `additionalFields` | `FieldConfig[]` | `undefined` | Extra fields appended after default/custom fields |
|
|
196
197
|
| `onSubmit` | `(values: FormValues) => void` | required | Callback fired when form is submitted with valid values |
|
|
197
198
|
| `onChange` | `(values: FormValues, isValid: boolean) => void` | `undefined` | Callback fired on every field change |
|
|
198
199
|
| `validateOnBlur` | `boolean` | `true` | Whether to validate fields on blur |
|
|
@@ -238,6 +239,44 @@ const customFields: FieldConfig[] = [
|
|
|
238
239
|
<RegistrationForm fields={customFields} onSubmit={handleSubmit} />
|
|
239
240
|
```
|
|
240
241
|
|
|
242
|
+
### Additional Fields
|
|
243
|
+
|
|
244
|
+
Append extra fields after the defaults using `additionalFields`:
|
|
245
|
+
|
|
246
|
+
```tsx
|
|
247
|
+
import { RegistrationForm, FieldConfig } from '@bookinglab/booking-ui-react';
|
|
248
|
+
|
|
249
|
+
const extraFields: FieldConfig[] = [
|
|
250
|
+
{ name: 'company', label: 'Company Name', type: 'text' },
|
|
251
|
+
{
|
|
252
|
+
name: 'service',
|
|
253
|
+
label: 'Service Type',
|
|
254
|
+
type: 'select',
|
|
255
|
+
required: true,
|
|
256
|
+
options: [
|
|
257
|
+
{ id: 1, name: 'Consultation', price: 0, is_default: true },
|
|
258
|
+
{ id: 2, name: 'Premium Support', price: 50 },
|
|
259
|
+
{ id: 3, name: 'Enterprise', price: 200 },
|
|
260
|
+
],
|
|
261
|
+
},
|
|
262
|
+
];
|
|
263
|
+
|
|
264
|
+
<RegistrationForm additionalFields={extraFields} onSubmit={handleSubmit} />
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Select Field Options
|
|
268
|
+
|
|
269
|
+
Select fields accept an `options` array with the following structure:
|
|
270
|
+
|
|
271
|
+
```typescript
|
|
272
|
+
interface FieldOption {
|
|
273
|
+
id: number | string; // Unique identifier (submitted as the value)
|
|
274
|
+
name: string; // Display text
|
|
275
|
+
price?: number; // Optional price modifier (displayed as "+£X")
|
|
276
|
+
is_default?: boolean; // Pre-select this option
|
|
277
|
+
}
|
|
278
|
+
```
|
|
279
|
+
|
|
241
280
|
### Ref Methods
|
|
242
281
|
|
|
243
282
|
Access imperative methods via `ref`:
|
|
@@ -323,6 +362,7 @@ import type {
|
|
|
323
362
|
BookingFormProps,
|
|
324
363
|
BookingFormClassNames,
|
|
325
364
|
FieldConfig,
|
|
365
|
+
FieldOption,
|
|
326
366
|
RegistrationFormProps,
|
|
327
367
|
RegistrationFormRef,
|
|
328
368
|
RegistrationFormValues,
|
package/dist/index.d.cts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Option for select fields
|
|
6
|
+
*/
|
|
7
|
+
interface FieldOption {
|
|
8
|
+
/** Option display name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Option price (if applicable) */
|
|
11
|
+
price?: number;
|
|
12
|
+
/** Whether this is the default option */
|
|
13
|
+
is_default?: boolean;
|
|
14
|
+
/** Unique option ID */
|
|
15
|
+
id: number | string;
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* Configuration for a single form field
|
|
6
19
|
*/
|
|
@@ -10,13 +23,15 @@ interface FieldConfig {
|
|
|
10
23
|
/** Display label for the field */
|
|
11
24
|
label: string;
|
|
12
25
|
/** Input type */
|
|
13
|
-
type: 'text' | 'email' | 'tel';
|
|
26
|
+
type: 'text' | 'email' | 'tel' | 'select';
|
|
14
27
|
/** Whether the field is required */
|
|
15
28
|
required?: boolean;
|
|
16
29
|
/** Placeholder text */
|
|
17
30
|
placeholder?: string;
|
|
18
31
|
/** Custom validation function - returns error message or null */
|
|
19
32
|
validate?: (value: string) => string | null;
|
|
33
|
+
/** Options for select fields */
|
|
34
|
+
options?: FieldOption[];
|
|
20
35
|
}
|
|
21
36
|
/**
|
|
22
37
|
* Form values keyed by field name
|
|
@@ -51,6 +66,8 @@ interface RegistrationFormClassNames {
|
|
|
51
66
|
interface RegistrationFormProps {
|
|
52
67
|
/** Custom field configuration (overrides defaults) */
|
|
53
68
|
fields?: FieldConfig[];
|
|
69
|
+
/** Additional fields to append after default fields */
|
|
70
|
+
additionalFields?: FieldConfig[];
|
|
54
71
|
/** Callback fired when form is submitted with valid values */
|
|
55
72
|
onSubmit: (values: RegistrationFormValues) => void;
|
|
56
73
|
/** Callback fired on every field change */
|
|
@@ -225,4 +242,4 @@ declare function minLen(min: number): (value: string) => string | null;
|
|
|
225
242
|
*/
|
|
226
243
|
declare function compose(...validators: Array<(value: string) => string | null>): (value: string) => string | null;
|
|
227
244
|
|
|
228
|
-
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type FieldConfig, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, compose, email, minLen, phone, required, ukPostcode };
|
|
245
|
+
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type FieldConfig, type FieldOption, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, compose, email, minLen, phone, required, ukPostcode };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
2
|
import React from 'react';
|
|
3
3
|
|
|
4
|
+
/**
|
|
5
|
+
* Option for select fields
|
|
6
|
+
*/
|
|
7
|
+
interface FieldOption {
|
|
8
|
+
/** Option display name */
|
|
9
|
+
name: string;
|
|
10
|
+
/** Option price (if applicable) */
|
|
11
|
+
price?: number;
|
|
12
|
+
/** Whether this is the default option */
|
|
13
|
+
is_default?: boolean;
|
|
14
|
+
/** Unique option ID */
|
|
15
|
+
id: number | string;
|
|
16
|
+
}
|
|
4
17
|
/**
|
|
5
18
|
* Configuration for a single form field
|
|
6
19
|
*/
|
|
@@ -10,13 +23,15 @@ interface FieldConfig {
|
|
|
10
23
|
/** Display label for the field */
|
|
11
24
|
label: string;
|
|
12
25
|
/** Input type */
|
|
13
|
-
type: 'text' | 'email' | 'tel';
|
|
26
|
+
type: 'text' | 'email' | 'tel' | 'select';
|
|
14
27
|
/** Whether the field is required */
|
|
15
28
|
required?: boolean;
|
|
16
29
|
/** Placeholder text */
|
|
17
30
|
placeholder?: string;
|
|
18
31
|
/** Custom validation function - returns error message or null */
|
|
19
32
|
validate?: (value: string) => string | null;
|
|
33
|
+
/** Options for select fields */
|
|
34
|
+
options?: FieldOption[];
|
|
20
35
|
}
|
|
21
36
|
/**
|
|
22
37
|
* Form values keyed by field name
|
|
@@ -51,6 +66,8 @@ interface RegistrationFormClassNames {
|
|
|
51
66
|
interface RegistrationFormProps {
|
|
52
67
|
/** Custom field configuration (overrides defaults) */
|
|
53
68
|
fields?: FieldConfig[];
|
|
69
|
+
/** Additional fields to append after default fields */
|
|
70
|
+
additionalFields?: FieldConfig[];
|
|
54
71
|
/** Callback fired when form is submitted with valid values */
|
|
55
72
|
onSubmit: (values: RegistrationFormValues) => void;
|
|
56
73
|
/** Callback fired on every field change */
|
|
@@ -225,4 +242,4 @@ declare function minLen(min: number): (value: string) => string | null;
|
|
|
225
242
|
*/
|
|
226
243
|
declare function compose(...validators: Array<(value: string) => string | null>): (value: string) => string | null;
|
|
227
244
|
|
|
228
|
-
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type FieldConfig, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, compose, email, minLen, phone, required, ukPostcode };
|
|
245
|
+
export { BookingForm, type BookingFormClassNames, type BookingFormProps, type BookingUIConfig, type FieldConfig, type FieldOption, type FormErrors, type FormValues, type Question, type QuestionOption, type QuestionSettings, RegistrationForm, type RegistrationFormClassNames, type RegistrationFormErrors, type RegistrationFormProps, type RegistrationFormRef, type RegistrationFormValues, compose, email, minLen, phone, required, ukPostcode };
|
package/dist/index.js
CHANGED
|
@@ -465,6 +465,7 @@ var DEFAULT_FIELDS = [
|
|
|
465
465
|
var RegistrationForm = react.forwardRef(
|
|
466
466
|
({
|
|
467
467
|
fields = DEFAULT_FIELDS,
|
|
468
|
+
additionalFields,
|
|
468
469
|
onSubmit,
|
|
469
470
|
onChange,
|
|
470
471
|
validateOnBlur = true,
|
|
@@ -476,6 +477,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
476
477
|
const [values, setValues] = react.useState({});
|
|
477
478
|
const [errors, setErrors] = react.useState({});
|
|
478
479
|
const [touched, setTouched] = react.useState({});
|
|
480
|
+
const allFields = additionalFields ? [...fields, ...additionalFields] : fields;
|
|
479
481
|
const validateField = react.useCallback(
|
|
480
482
|
(field, value) => {
|
|
481
483
|
if (field.required && (!value || value.trim() === "")) {
|
|
@@ -491,7 +493,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
491
493
|
const validateAll = react.useCallback(() => {
|
|
492
494
|
const newErrors = {};
|
|
493
495
|
let isValid = true;
|
|
494
|
-
for (const field of
|
|
496
|
+
for (const field of allFields) {
|
|
495
497
|
const value = values[field.name] || "";
|
|
496
498
|
const error = validateField(field, value);
|
|
497
499
|
if (error) {
|
|
@@ -501,24 +503,24 @@ var RegistrationForm = react.forwardRef(
|
|
|
501
503
|
}
|
|
502
504
|
setErrors(newErrors);
|
|
503
505
|
return isValid;
|
|
504
|
-
}, [
|
|
506
|
+
}, [allFields, values, validateField]);
|
|
505
507
|
const checkIsValid = react.useCallback(
|
|
506
508
|
(currentValues) => {
|
|
507
|
-
for (const field of
|
|
509
|
+
for (const field of allFields) {
|
|
508
510
|
const value = currentValues[field.name] || "";
|
|
509
511
|
const error = validateField(field, value);
|
|
510
512
|
if (error) return false;
|
|
511
513
|
}
|
|
512
514
|
return true;
|
|
513
515
|
},
|
|
514
|
-
[
|
|
516
|
+
[allFields, validateField]
|
|
515
517
|
);
|
|
516
518
|
const handleChange = react.useCallback(
|
|
517
519
|
(fieldName, value) => {
|
|
518
520
|
const newValues = { ...values, [fieldName]: value };
|
|
519
521
|
setValues(newValues);
|
|
520
522
|
if (touched[fieldName]) {
|
|
521
|
-
const field =
|
|
523
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
522
524
|
if (field) {
|
|
523
525
|
const error = validateField(field, value);
|
|
524
526
|
if (!error) {
|
|
@@ -535,13 +537,13 @@ var RegistrationForm = react.forwardRef(
|
|
|
535
537
|
onChange(newValues, isValid);
|
|
536
538
|
}
|
|
537
539
|
},
|
|
538
|
-
[values, touched,
|
|
540
|
+
[values, touched, allFields, validateField, onChange, checkIsValid]
|
|
539
541
|
);
|
|
540
542
|
const handleBlur = react.useCallback(
|
|
541
543
|
(fieldName) => {
|
|
542
544
|
setTouched((prev) => ({ ...prev, [fieldName]: true }));
|
|
543
545
|
if (validateOnBlur) {
|
|
544
|
-
const field =
|
|
546
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
545
547
|
if (field) {
|
|
546
548
|
const value = values[fieldName] || "";
|
|
547
549
|
const error = validateField(field, value);
|
|
@@ -557,13 +559,13 @@ var RegistrationForm = react.forwardRef(
|
|
|
557
559
|
}
|
|
558
560
|
}
|
|
559
561
|
},
|
|
560
|
-
[validateOnBlur,
|
|
562
|
+
[validateOnBlur, allFields, values, validateField]
|
|
561
563
|
);
|
|
562
564
|
const handleSubmit = react.useCallback(
|
|
563
565
|
(e) => {
|
|
564
566
|
e.preventDefault();
|
|
565
567
|
const allTouched = {};
|
|
566
|
-
for (const field of
|
|
568
|
+
for (const field of allFields) {
|
|
567
569
|
allTouched[field.name] = true;
|
|
568
570
|
}
|
|
569
571
|
setTouched(allTouched);
|
|
@@ -571,7 +573,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
571
573
|
onSubmit(values);
|
|
572
574
|
}
|
|
573
575
|
},
|
|
574
|
-
[
|
|
576
|
+
[allFields, validateAll, onSubmit, values]
|
|
575
577
|
);
|
|
576
578
|
react.useImperativeHandle(
|
|
577
579
|
ref,
|
|
@@ -604,7 +606,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
604
606
|
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
607
|
};
|
|
606
608
|
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
607
|
-
|
|
609
|
+
allFields.map((field) => {
|
|
608
610
|
const fieldId = `${formId}-${field.name}`;
|
|
609
611
|
const errorId = `${fieldId}-error`;
|
|
610
612
|
const value = values[field.name] || "";
|
|
@@ -616,12 +618,32 @@ var RegistrationForm = react.forwardRef(
|
|
|
616
618
|
field.label,
|
|
617
619
|
field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
618
620
|
] }),
|
|
619
|
-
/* @__PURE__ */ jsxRuntime.
|
|
621
|
+
field.type === "select" && field.options ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
622
|
+
"select",
|
|
623
|
+
{
|
|
624
|
+
id: fieldId,
|
|
625
|
+
name: field.name,
|
|
626
|
+
value,
|
|
627
|
+
onChange: (e) => handleChange(field.name, e.target.value),
|
|
628
|
+
onBlur: () => handleBlur(field.name),
|
|
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
|
+
children: [
|
|
634
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: field.placeholder || "Select an option" }),
|
|
635
|
+
field.options.map((option) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: String(option.id), children: [
|
|
636
|
+
option.name,
|
|
637
|
+
option.price !== void 0 && option.price > 0 ? ` (+\xA3${option.price})` : ""
|
|
638
|
+
] }, option.id))
|
|
639
|
+
]
|
|
640
|
+
}
|
|
641
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
620
642
|
"input",
|
|
621
643
|
{
|
|
622
644
|
id: fieldId,
|
|
623
645
|
name: field.name,
|
|
624
|
-
type: field.type,
|
|
646
|
+
type: field.type === "select" ? "text" : field.type,
|
|
625
647
|
value,
|
|
626
648
|
onChange: (e) => handleChange(field.name, e.target.value),
|
|
627
649
|
onBlur: () => handleBlur(field.name),
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/BookingForm.tsx","../src/utils/validators.ts","../src/components/RegistrationForm.tsx"],"names":["jsxs","jsx","useState","useCallback","useEffect","forwardRef","useId","useImperativeHandle"],"mappings":"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","file":"index.js","sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport type { Question, FormValues, FormErrors, BookingFormProps, BookingFormClassNames } from '../types';\n\n/** Merge base classes with optional custom classes */\nconst cx = (...classes: (string | undefined)[]) => classes.filter(Boolean).join(' ');\n\n/**\n * Renders a single form field based on question type\n */\nfunction FormField({\n question,\n value,\n error,\n onChange,\n classNames,\n}: {\n question: Question;\n value: string | number | boolean | undefined;\n error?: string;\n onChange: (value: string | number | boolean) => void;\n classNames?: BookingFormClassNames;\n}) {\n const inputId = `question-${question.id}`;\n const errorId = `${inputId}-error`;\n const hasError = !!error;\n\n // Default classes (can be overridden via classNames prop)\n const defaultFieldWrapper = 'mb-4';\n const defaultLabel = 'block text-sm font-medium mb-1 text-gray-700';\n const defaultHeading = 'text-lg font-semibold text-gray-900 mt-4 mb-2 first:mt-0';\n const defaultInput = 'w-full px-3 py-2 border rounded-md text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1 border-gray-300 focus:ring-blue-500 focus:border-blue-500';\n const defaultInputError = 'border-red-500 focus:ring-red-500';\n const defaultCheckbox = 'mt-1 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500';\n const defaultHelpText = 'mt-1 text-xs text-gray-500';\n const defaultErrorText = 'mt-1 text-xs text-red-600';\n\n const inputClasses = hasError\n ? cx(classNames?.input ?? defaultInput, classNames?.inputError ?? defaultInputError)\n : cx(classNames?.input ?? defaultInput);\n\n const labelClasses = classNames?.label ?? defaultLabel;\n const checkboxLabelClasses = cx('text-sm', classNames?.label ?? 'text-gray-700');\n\n const renderLabel = () => {\n if (question.detail_type === 'heading') return null;\n return (\n <label htmlFor={inputId} className={labelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n );\n };\n\n const renderHelpText = () => {\n if (!question.help_text) return null;\n return <p className={classNames?.helpText ?? defaultHelpText}>{question.help_text}</p>;\n };\n\n const renderError = () => {\n if (!error) return null;\n return (\n <p id={errorId} className={classNames?.errorText ?? defaultErrorText} role=\"alert\">\n {error}\n </p>\n );\n };\n\n const ariaProps = {\n 'aria-invalid': hasError ? true : undefined,\n 'aria-describedby': hasError ? errorId : undefined,\n 'aria-required': question.required || undefined,\n };\n\n switch (question.detail_type) {\n case 'heading':\n return (\n <h3 className={classNames?.heading ?? defaultHeading}>\n {question.name}\n </h3>\n );\n\n case 'text_field':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'text_area':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <textarea\n id={inputId}\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n rows={4}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'select':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <select\n id={inputId}\n value={(value as string | number) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n className={inputClasses}\n {...ariaProps}\n >\n <option value=\"\">Select an option</option>\n {question.options?.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'date':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"date\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n min={question.settings?.min?.toString()}\n max={question.settings?.max?.toString()}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'number':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"number\"\n value={(value as number) ?? ''}\n onChange={(e) => onChange(e.target.value ? Number(e.target.value) : '')}\n min={question.settings?.min}\n max={question.settings?.max}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'check':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n <div className=\"flex items-start gap-2\">\n <input\n id={inputId}\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => onChange(e.target.checked)}\n className={classNames?.checkbox ?? defaultCheckbox}\n {...ariaProps}\n />\n <label htmlFor={inputId} className={checkboxLabelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n </div>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * BookingForm - A dynamic form component for booking questions\n *\n * @example\n * ```tsx\n * const questions: Question[] = [\n * { id: 1, name: 'Personal Details', detail_type: 'heading' },\n * { id: 2, name: 'Full Name', detail_type: 'text_field', required: true },\n * { id: 3, name: 'Email', detail_type: 'text_field', required: true },\n * ];\n *\n * <BookingForm\n * questions={questions}\n * onSubmit={(values) => console.log(values)}\n * />\n * ```\n */\nexport function BookingForm({\n questions,\n onSubmit,\n submitLabel = 'Submit',\n className = '',\n labelClassName,\n classNames: classNamesProp,\n}: BookingFormProps) {\n // Merge deprecated labelClassName into classNames for backwards compatibility\n const classNames: BookingFormClassNames = {\n ...classNamesProp,\n label: classNamesProp?.label ?? labelClassName,\n };\n const [values, setValues] = useState<FormValues>({});\n const [errors, setErrors] = useState<FormErrors>({});\n const [touched, setTouched] = useState<Record<number, boolean>>({});\n\n\n // Check if a question should be visible based on conditional settings\n const isQuestionVisible = useCallback(\n (question: Question): boolean => {\n const { settings } = question;\n if (!settings?.conditional_answers) {\n return true;\n }\n\n // Check all conditions in conditional_answers\n // Each entry is { questionId: expectedAnswerValue }\n const conditionEntries = Object.entries(settings.conditional_answers as Record<string, unknown>);\n if (conditionEntries.length === 0) {\n return true;\n }\n\n // Question is visible if ANY condition is met\n return conditionEntries.some(([questionIdStr, expectedAnswer]) => {\n const questionId = Number(questionIdStr);\n const currentValue = (values as Record<string, unknown>)[String(questionId)];\n\n if (currentValue === undefined || currentValue === '' || currentValue === null) {\n return false;\n }\n\n // Selects typically store the option id (as string), but allow `{ id, name }` objects too\n const normalizedCurrent =\n typeof currentValue === 'object' && currentValue !== null && 'id' in (currentValue as any)\n ? (currentValue as any)\n : currentValue;\n\n // Build a set of candidate strings for comparison.\n // For select questions we support matching by BOTH option id and option name.\n const candidates = new Set<string>();\n\n const addCandidate = (v: unknown) => {\n if (v === undefined || v === null) return;\n const s = String(v).trim();\n if (s) candidates.add(s);\n };\n\n const sourceQuestion = questions.find((q) => q.id === questionId);\n\n if (typeof normalizedCurrent === 'object' && normalizedCurrent !== null) {\n addCandidate((normalizedCurrent as any).id);\n addCandidate((normalizedCurrent as any).name);\n } else {\n addCandidate(normalizedCurrent);\n }\n\n if (sourceQuestion?.detail_type === 'select' && sourceQuestion.options?.length) {\n // Try to resolve the selected option via id or name.\n const currentStr = [...candidates][0] ?? '';\n const optionById = sourceQuestion.options.find((o) => String(o.id) === currentStr);\n const optionByName = sourceQuestion.options.find((o) => String(o.name).trim() === currentStr);\n const opt = optionById ?? optionByName;\n if (opt) {\n addCandidate(opt.id);\n addCandidate(opt.name);\n }\n }\n\n const matchesScalar = (expected: unknown) => {\n const expectedStr = String(expected).trim();\n return candidates.has(expectedStr);\n };\n\n // Support multiple expected formats:\n // - scalar: \"Consultation\" / \"1\" / 1 / true\n // - array: [\"Consultation\", \"Follow-up\"]\n // - map/object: { \"Consultation\": true }\n if (Array.isArray(expectedAnswer)) {\n return expectedAnswer.some((v) => matchesScalar(v));\n }\n\n if (expectedAnswer && typeof expectedAnswer === 'object') {\n const expectedMap = expectedAnswer as Record<string, unknown>;\n for (const c of candidates) {\n if (Object.prototype.hasOwnProperty.call(expectedMap, c)) {\n const flag = expectedMap[c];\n return flag === undefined ? true : !!flag;\n }\n }\n return false;\n }\n\n return matchesScalar(expectedAnswer);\n });\n },\n [values, questions]\n );\n\n // Get visible questions\n const visibleQuestions = questions.filter(isQuestionVisible);\n\n\n // Validate a single field\n const validateField = useCallback((question: Question, value: FormValues[number]): string | null => {\n if (question.detail_type === 'heading') return null;\n\n if (question.required) {\n if (value === undefined || value === '' || value === null) {\n return `${question.name} is required`;\n }\n if (question.detail_type === 'check' && !value) {\n return `${question.name} must be checked`;\n }\n }\n\n if (question.detail_type === 'number' && value !== '' && value !== undefined) {\n const numValue = Number(value);\n if (question.settings?.min !== undefined && numValue < question.settings.min) {\n return `Minimum value is ${question.settings.min}`;\n }\n if (question.settings?.max !== undefined && numValue > question.settings.max) {\n return `Maximum value is ${question.settings.max}`;\n }\n }\n\n return null;\n }, []);\n\n // Validate all visible fields\n const validateAll = useCallback((): boolean => {\n const newErrors: FormErrors = {};\n let isValid = true;\n\n visibleQuestions.forEach((question) => {\n const error = validateField(question, values[question.id]);\n if (error) {\n newErrors[question.id] = error;\n isValid = false;\n }\n });\n\n setErrors(newErrors);\n return isValid;\n }, [visibleQuestions, values, validateField]);\n\n // Clear errors for hidden questions\n useEffect(() => {\n const visibleIds = new Set(visibleQuestions.map((q) => q.id));\n\n setErrors((prev) => {\n let changed = false;\n const next = { ...prev };\n\n Object.keys(next).forEach((idStr) => {\n const id = Number(idStr);\n if (!visibleIds.has(id)) {\n delete next[id];\n changed = true;\n }\n });\n\n return changed ? next : prev;\n });\n }, [visibleQuestions]);\n\n const handleChange = (questionId: number, value: string | number | boolean) => {\n setValues((prev) => ({ ...prev, [questionId]: value }));\n setTouched((prev) => ({ ...prev, [questionId]: true }));\n\n // Clear error on change if touched\n if (touched[questionId]) {\n const question = questions.find((q) => q.id === questionId);\n if (question) {\n const error = validateField(question, value);\n setErrors((prev) => {\n if (error) {\n return { ...prev, [questionId]: error };\n }\n const { [questionId]: _, ...rest } = prev;\n return rest;\n });\n }\n }\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<number, boolean> = {};\n visibleQuestions.forEach((q) => {\n allTouched[q.id] = true;\n });\n setTouched(allTouched);\n\n if (validateAll()) {\n // Only include visible question values\n const visibleValues: FormValues = {};\n visibleQuestions.forEach((q) => {\n if (q.detail_type !== 'heading' && values[q.id] !== undefined) {\n visibleValues[q.id] = values[q.id];\n }\n });\n onSubmit(visibleValues);\n }\n };\n\n 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';\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {visibleQuestions.map((question) => (\n <FormField\n key={question.id}\n question={question}\n value={values[question.id]}\n error={touched[question.id] ? errors[question.id] : undefined}\n onChange={(value) => handleChange(question.id, value)}\n classNames={classNames}\n />\n ))}\n <button\n type=\"submit\"\n className={classNames?.button ?? defaultButton}\n >\n {submitLabel}\n </button>\n </form>\n );\n}\n\nexport default BookingForm;\n","/**\n * Validation helper functions for form fields\n * Each validator returns an error message string if invalid, or null if valid\n */\n\n/**\n * Validates that a value is not empty\n */\nexport function required(value: string): string | null {\n if (!value || value.trim() === '') {\n return 'This field is required';\n }\n return null;\n}\n\n/**\n * Validates email format (RFC 5322 compliant)\n */\nexport function email(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n 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])?)*$/;\n \n if (!emailRegex.test(value)) {\n return 'Please enter a valid email address';\n }\n return null;\n}\n\n/**\n * Validates phone number format (international)\n * Accepts formats like: +44 1234 567890, 01onal234 567890, +1-234-567-8900\n */\nexport function phone(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // Remove all spaces, dashes, and parentheses for validation\n const cleaned = value.replace(/[\\s\\-\\(\\)]/g, '');\n \n // Check for valid phone format: optional + followed by 7-15 digits\n const phoneRegex = /^\\+?[0-9]{7,15}$/;\n \n if (!phoneRegex.test(cleaned)) {\n return 'Please enter a valid phone number';\n }\n return null;\n}\n\n/**\n * Validates UK postcode format\n * Accepts formats like: SW1A 1AA, SW1A1AA, M1 1AA, B33 8TH\n */\nexport function ukPostcode(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // UK postcode regex - covers all valid formats\n const postcodeRegex = /^([A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2})$/i;\n \n if (!postcodeRegex.test(value.trim())) {\n return 'Please enter a valid UK postcode';\n }\n return null;\n}\n\n/**\n * Creates a minimum length validator\n * @param min - Minimum number of characters required\n */\nexport function minLen(min: number): (value: string) => string | null {\n return (value: string) => {\n if (!value) return null; // Let required handle empty values\n \n if (value.trim().length < min) {\n return `Must be at least ${min} character${min === 1 ? '' : 's'}`;\n }\n return null;\n };\n}\n\n/**\n * Combines multiple validators into one\n * Returns the first error encountered, or null if all pass\n */\nexport function compose(\n ...validators: Array<(value: string) => string | null>\n): (value: string) => string | null {\n return (value: string) => {\n for (const validator of validators) {\n const error = validator(value);\n if (error) return error;\n }\n return null;\n };\n}\n","import React, {\n useState,\n useCallback,\n useImperativeHandle,\n forwardRef,\n useId,\n} from 'react';\nimport type {\n FieldConfig,\n RegistrationFormProps,\n RegistrationFormRef,\n RegistrationFormValues,\n RegistrationFormErrors,\n} from '../types/registration';\nimport { required, email, phone, ukPostcode, compose } from '../utils/validators';\n\n/**\n * Default field configuration for the registration form\n */\nconst DEFAULT_FIELDS: FieldConfig[] = [\n {\n name: 'firstName',\n label: 'First name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'lastName',\n label: 'Last name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'email',\n label: 'Email address',\n type: 'email',\n required: true,\n validate: compose(required, email),\n },\n {\n name: 'phone',\n label: 'Contact number',\n type: 'tel',\n required: false,\n validate: phone,\n },\n {\n name: 'address1',\n label: 'Address 1',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'address2',\n label: 'Address 2',\n type: 'text',\n required: false,\n },\n {\n name: 'city',\n label: 'Town/City',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'postcode',\n label: 'Postcode',\n type: 'text',\n required: true,\n validate: compose(required, ukPostcode),\n },\n];\n\n/**\n * A reusable, accessible registration form component.\n * \n * Features:\n * - Customizable fields via props\n * - Built-in validation with blur and submit triggers\n * - Full accessibility support (ARIA attributes, keyboard navigation)\n * - Imperative handle for programmatic control (reset, setValues)\n * - Granular styling via classNames prop\n * \n * @example\n * ```tsx\n * const formRef = useRef<RegistrationFormRef>(null);\n * \n * <RegistrationForm\n * ref={formRef}\n * onSubmit={(values) => console.log(values)}\n * onChange={(values, isValid) => console.log(isValid)}\n * submitLabel=\"Register\"\n * />\n * \n * // Programmatic control\n * formRef.current?.reset();\n * formRef.current?.setValues({ email: 'test@example.com' });\n * ```\n */\nexport const RegistrationForm = forwardRef<RegistrationFormRef, RegistrationFormProps>(\n (\n {\n fields = DEFAULT_FIELDS,\n onSubmit,\n onChange,\n validateOnBlur = true,\n submitLabel = 'Submit',\n className = '',\n classNames = {},\n },\n ref\n ) => {\n const formId = useId();\n const [values, setValues] = useState<RegistrationFormValues>({});\n const [errors, setErrors] = useState<RegistrationFormErrors>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n /**\n * Validate a single field\n */\n const validateField = useCallback(\n (field: FieldConfig, value: string): string | null => {\n // Check required first\n if (field.required && (!value || value.trim() === '')) {\n return 'This field is required';\n }\n // Run custom validator if value is present\n if (field.validate && value) {\n return field.validate(value);\n }\n return null;\n },\n []\n );\n\n /**\n * Validate all fields and return whether form is valid\n */\n const validateAll = useCallback((): boolean => {\n const newErrors: RegistrationFormErrors = {};\n let isValid = true;\n\n for (const field of fields) {\n const value = values[field.name] || '';\n const error = validateField(field, value);\n if (error) {\n newErrors[field.name] = error;\n isValid = false;\n }\n }\n\n setErrors(newErrors);\n return isValid;\n }, [fields, values, validateField]);\n\n /**\n * Check if current form state is valid (without updating errors)\n */\n const checkIsValid = useCallback(\n (currentValues: RegistrationFormValues): boolean => {\n for (const field of fields) {\n const value = currentValues[field.name] || '';\n const error = validateField(field, value);\n if (error) return false;\n }\n return true;\n },\n [fields, validateField]\n );\n\n /**\n * Handle input change\n */\n const handleChange = useCallback(\n (fieldName: string, value: string) => {\n const newValues = { ...values, [fieldName]: value };\n setValues(newValues);\n\n // Clear error if field was touched and is now valid\n if (touched[fieldName]) {\n const field = fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(field, value);\n if (!error) {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n\n // Call onChange callback\n if (onChange) {\n const isValid = checkIsValid(newValues);\n onChange(newValues, isValid);\n }\n },\n [values, touched, fields, validateField, onChange, checkIsValid]\n );\n\n /**\n * Handle input blur\n */\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => ({ ...prev, [fieldName]: true }));\n\n if (validateOnBlur) {\n const field = fields.find((f) => f.name === fieldName);\n if (field) {\n const value = values[fieldName] || '';\n const error = validateField(field, value);\n if (error) {\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n },\n [validateOnBlur, fields, values, validateField]\n );\n\n /**\n * Handle form submission\n */\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<string, boolean> = {};\n for (const field of fields) {\n allTouched[field.name] = true;\n }\n setTouched(allTouched);\n\n // Validate all and submit if valid\n if (validateAll()) {\n onSubmit(values);\n }\n },\n [fields, validateAll, onSubmit, values]\n );\n\n /**\n * Expose imperative methods via ref\n */\n useImperativeHandle(\n ref,\n () => ({\n reset: () => {\n setValues({});\n setErrors({});\n setTouched({});\n },\n setValues: (newValues: Partial<RegistrationFormValues>) => {\n setValues((prev) => {\n const merged = { ...prev };\n for (const [key, value] of Object.entries(newValues)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n return merged;\n });\n },\n }),\n []\n );\n\n // Default styles\n const styles = {\n fieldWrapper: classNames.fieldWrapper || 'mb-4',\n label: classNames.label || 'block text-sm font-medium mb-1',\n input: classNames.input || 'w-full px-3 py-2 border rounded-md',\n inputError: classNames.inputError || 'border-red-500',\n errorText: classNames.errorText || 'mt-1 text-xs text-red-600',\n button:\n classNames.button ||\n 'w-full mt-4 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50',\n };\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {fields.map((field) => {\n const fieldId = `${formId}-${field.name}`;\n const errorId = `${fieldId}-error`;\n const value = values[field.name] || '';\n const error = errors[field.name];\n const isTouched = touched[field.name];\n const showError = isTouched && error;\n\n return (\n <div key={field.name} className={styles.fieldWrapper}>\n <label htmlFor={fieldId} className={styles.label}>\n {field.label}\n {field.required && (\n <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n <input\n id={fieldId}\n name={field.name}\n type={field.type}\n value={value}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n placeholder={field.placeholder}\n className={`${styles.input} ${showError ? styles.inputError : ''}`}\n aria-invalid={showError ? 'true' : 'false'}\n aria-describedby={showError ? errorId : undefined}\n aria-required={field.required ? 'true' : 'false'}\n />\n {showError && (\n <p id={errorId} className={styles.errorText} role=\"alert\">\n {error}\n </p>\n )}\n </div>\n );\n })}\n <button type=\"submit\" className={styles.button}>\n {submitLabel}\n </button>\n </form>\n );\n }\n);\n\nRegistrationForm.displayName = 'RegistrationForm';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/BookingForm.tsx","../src/utils/validators.ts","../src/components/RegistrationForm.tsx"],"names":["jsxs","jsx","useState","useCallback","useEffect","forwardRef","useId","useImperativeHandle"],"mappings":"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","file":"index.js","sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport type { Question, FormValues, FormErrors, BookingFormProps, BookingFormClassNames } from '../types';\n\n/** Merge base classes with optional custom classes */\nconst cx = (...classes: (string | undefined)[]) => classes.filter(Boolean).join(' ');\n\n/**\n * Renders a single form field based on question type\n */\nfunction FormField({\n question,\n value,\n error,\n onChange,\n classNames,\n}: {\n question: Question;\n value: string | number | boolean | undefined;\n error?: string;\n onChange: (value: string | number | boolean) => void;\n classNames?: BookingFormClassNames;\n}) {\n const inputId = `question-${question.id}`;\n const errorId = `${inputId}-error`;\n const hasError = !!error;\n\n // Default classes (can be overridden via classNames prop)\n const defaultFieldWrapper = 'mb-4';\n const defaultLabel = 'block text-sm font-medium mb-1 text-gray-700';\n const defaultHeading = 'text-lg font-semibold text-gray-900 mt-4 mb-2 first:mt-0';\n const defaultInput = 'w-full px-3 py-2 border rounded-md text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1 border-gray-300 focus:ring-blue-500 focus:border-blue-500';\n const defaultInputError = 'border-red-500 focus:ring-red-500';\n const defaultCheckbox = 'mt-1 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500';\n const defaultHelpText = 'mt-1 text-xs text-gray-500';\n const defaultErrorText = 'mt-1 text-xs text-red-600';\n\n const inputClasses = hasError\n ? cx(classNames?.input ?? defaultInput, classNames?.inputError ?? defaultInputError)\n : cx(classNames?.input ?? defaultInput);\n\n const labelClasses = classNames?.label ?? defaultLabel;\n const checkboxLabelClasses = cx('text-sm', classNames?.label ?? 'text-gray-700');\n\n const renderLabel = () => {\n if (question.detail_type === 'heading') return null;\n return (\n <label htmlFor={inputId} className={labelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n );\n };\n\n const renderHelpText = () => {\n if (!question.help_text) return null;\n return <p className={classNames?.helpText ?? defaultHelpText}>{question.help_text}</p>;\n };\n\n const renderError = () => {\n if (!error) return null;\n return (\n <p id={errorId} className={classNames?.errorText ?? defaultErrorText} role=\"alert\">\n {error}\n </p>\n );\n };\n\n const ariaProps = {\n 'aria-invalid': hasError ? true : undefined,\n 'aria-describedby': hasError ? errorId : undefined,\n 'aria-required': question.required || undefined,\n };\n\n switch (question.detail_type) {\n case 'heading':\n return (\n <h3 className={classNames?.heading ?? defaultHeading}>\n {question.name}\n </h3>\n );\n\n case 'text_field':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'text_area':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <textarea\n id={inputId}\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n rows={4}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'select':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <select\n id={inputId}\n value={(value as string | number) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n className={inputClasses}\n {...ariaProps}\n >\n <option value=\"\">Select an option</option>\n {question.options?.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'date':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"date\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n min={question.settings?.min?.toString()}\n max={question.settings?.max?.toString()}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'number':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"number\"\n value={(value as number) ?? ''}\n onChange={(e) => onChange(e.target.value ? Number(e.target.value) : '')}\n min={question.settings?.min}\n max={question.settings?.max}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'check':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n <div className=\"flex items-start gap-2\">\n <input\n id={inputId}\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => onChange(e.target.checked)}\n className={classNames?.checkbox ?? defaultCheckbox}\n {...ariaProps}\n />\n <label htmlFor={inputId} className={checkboxLabelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n </div>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * BookingForm - A dynamic form component for booking questions\n *\n * @example\n * ```tsx\n * const questions: Question[] = [\n * { id: 1, name: 'Personal Details', detail_type: 'heading' },\n * { id: 2, name: 'Full Name', detail_type: 'text_field', required: true },\n * { id: 3, name: 'Email', detail_type: 'text_field', required: true },\n * ];\n *\n * <BookingForm\n * questions={questions}\n * onSubmit={(values) => console.log(values)}\n * />\n * ```\n */\nexport function BookingForm({\n questions,\n onSubmit,\n submitLabel = 'Submit',\n className = '',\n labelClassName,\n classNames: classNamesProp,\n}: BookingFormProps) {\n // Merge deprecated labelClassName into classNames for backwards compatibility\n const classNames: BookingFormClassNames = {\n ...classNamesProp,\n label: classNamesProp?.label ?? labelClassName,\n };\n const [values, setValues] = useState<FormValues>({});\n const [errors, setErrors] = useState<FormErrors>({});\n const [touched, setTouched] = useState<Record<number, boolean>>({});\n\n\n // Check if a question should be visible based on conditional settings\n const isQuestionVisible = useCallback(\n (question: Question): boolean => {\n const { settings } = question;\n if (!settings?.conditional_answers) {\n return true;\n }\n\n // Check all conditions in conditional_answers\n // Each entry is { questionId: expectedAnswerValue }\n const conditionEntries = Object.entries(settings.conditional_answers as Record<string, unknown>);\n if (conditionEntries.length === 0) {\n return true;\n }\n\n // Question is visible if ANY condition is met\n return conditionEntries.some(([questionIdStr, expectedAnswer]) => {\n const questionId = Number(questionIdStr);\n const currentValue = (values as Record<string, unknown>)[String(questionId)];\n\n if (currentValue === undefined || currentValue === '' || currentValue === null) {\n return false;\n }\n\n // Selects typically store the option id (as string), but allow `{ id, name }` objects too\n const normalizedCurrent =\n typeof currentValue === 'object' && currentValue !== null && 'id' in (currentValue as any)\n ? (currentValue as any)\n : currentValue;\n\n // Build a set of candidate strings for comparison.\n // For select questions we support matching by BOTH option id and option name.\n const candidates = new Set<string>();\n\n const addCandidate = (v: unknown) => {\n if (v === undefined || v === null) return;\n const s = String(v).trim();\n if (s) candidates.add(s);\n };\n\n const sourceQuestion = questions.find((q) => q.id === questionId);\n\n if (typeof normalizedCurrent === 'object' && normalizedCurrent !== null) {\n addCandidate((normalizedCurrent as any).id);\n addCandidate((normalizedCurrent as any).name);\n } else {\n addCandidate(normalizedCurrent);\n }\n\n if (sourceQuestion?.detail_type === 'select' && sourceQuestion.options?.length) {\n // Try to resolve the selected option via id or name.\n const currentStr = [...candidates][0] ?? '';\n const optionById = sourceQuestion.options.find((o) => String(o.id) === currentStr);\n const optionByName = sourceQuestion.options.find((o) => String(o.name).trim() === currentStr);\n const opt = optionById ?? optionByName;\n if (opt) {\n addCandidate(opt.id);\n addCandidate(opt.name);\n }\n }\n\n const matchesScalar = (expected: unknown) => {\n const expectedStr = String(expected).trim();\n return candidates.has(expectedStr);\n };\n\n // Support multiple expected formats:\n // - scalar: \"Consultation\" / \"1\" / 1 / true\n // - array: [\"Consultation\", \"Follow-up\"]\n // - map/object: { \"Consultation\": true }\n if (Array.isArray(expectedAnswer)) {\n return expectedAnswer.some((v) => matchesScalar(v));\n }\n\n if (expectedAnswer && typeof expectedAnswer === 'object') {\n const expectedMap = expectedAnswer as Record<string, unknown>;\n for (const c of candidates) {\n if (Object.prototype.hasOwnProperty.call(expectedMap, c)) {\n const flag = expectedMap[c];\n return flag === undefined ? true : !!flag;\n }\n }\n return false;\n }\n\n return matchesScalar(expectedAnswer);\n });\n },\n [values, questions]\n );\n\n // Get visible questions\n const visibleQuestions = questions.filter(isQuestionVisible);\n\n\n // Validate a single field\n const validateField = useCallback((question: Question, value: FormValues[number]): string | null => {\n if (question.detail_type === 'heading') return null;\n\n if (question.required) {\n if (value === undefined || value === '' || value === null) {\n return `${question.name} is required`;\n }\n if (question.detail_type === 'check' && !value) {\n return `${question.name} must be checked`;\n }\n }\n\n if (question.detail_type === 'number' && value !== '' && value !== undefined) {\n const numValue = Number(value);\n if (question.settings?.min !== undefined && numValue < question.settings.min) {\n return `Minimum value is ${question.settings.min}`;\n }\n if (question.settings?.max !== undefined && numValue > question.settings.max) {\n return `Maximum value is ${question.settings.max}`;\n }\n }\n\n return null;\n }, []);\n\n // Validate all visible fields\n const validateAll = useCallback((): boolean => {\n const newErrors: FormErrors = {};\n let isValid = true;\n\n visibleQuestions.forEach((question) => {\n const error = validateField(question, values[question.id]);\n if (error) {\n newErrors[question.id] = error;\n isValid = false;\n }\n });\n\n setErrors(newErrors);\n return isValid;\n }, [visibleQuestions, values, validateField]);\n\n // Clear errors for hidden questions\n useEffect(() => {\n const visibleIds = new Set(visibleQuestions.map((q) => q.id));\n\n setErrors((prev) => {\n let changed = false;\n const next = { ...prev };\n\n Object.keys(next).forEach((idStr) => {\n const id = Number(idStr);\n if (!visibleIds.has(id)) {\n delete next[id];\n changed = true;\n }\n });\n\n return changed ? next : prev;\n });\n }, [visibleQuestions]);\n\n const handleChange = (questionId: number, value: string | number | boolean) => {\n setValues((prev) => ({ ...prev, [questionId]: value }));\n setTouched((prev) => ({ ...prev, [questionId]: true }));\n\n // Clear error on change if touched\n if (touched[questionId]) {\n const question = questions.find((q) => q.id === questionId);\n if (question) {\n const error = validateField(question, value);\n setErrors((prev) => {\n if (error) {\n return { ...prev, [questionId]: error };\n }\n const { [questionId]: _, ...rest } = prev;\n return rest;\n });\n }\n }\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<number, boolean> = {};\n visibleQuestions.forEach((q) => {\n allTouched[q.id] = true;\n });\n setTouched(allTouched);\n\n if (validateAll()) {\n // Only include visible question values\n const visibleValues: FormValues = {};\n visibleQuestions.forEach((q) => {\n if (q.detail_type !== 'heading' && values[q.id] !== undefined) {\n visibleValues[q.id] = values[q.id];\n }\n });\n onSubmit(visibleValues);\n }\n };\n\n 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';\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {visibleQuestions.map((question) => (\n <FormField\n key={question.id}\n question={question}\n value={values[question.id]}\n error={touched[question.id] ? errors[question.id] : undefined}\n onChange={(value) => handleChange(question.id, value)}\n classNames={classNames}\n />\n ))}\n <button\n type=\"submit\"\n className={classNames?.button ?? defaultButton}\n >\n {submitLabel}\n </button>\n </form>\n );\n}\n\nexport default BookingForm;\n","/**\n * Validation helper functions for form fields\n * Each validator returns an error message string if invalid, or null if valid\n */\n\n/**\n * Validates that a value is not empty\n */\nexport function required(value: string): string | null {\n if (!value || value.trim() === '') {\n return 'This field is required';\n }\n return null;\n}\n\n/**\n * Validates email format (RFC 5322 compliant)\n */\nexport function email(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n 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])?)*$/;\n \n if (!emailRegex.test(value)) {\n return 'Please enter a valid email address';\n }\n return null;\n}\n\n/**\n * Validates phone number format (international)\n * Accepts formats like: +44 1234 567890, 01onal234 567890, +1-234-567-8900\n */\nexport function phone(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // Remove all spaces, dashes, and parentheses for validation\n const cleaned = value.replace(/[\\s\\-\\(\\)]/g, '');\n \n // Check for valid phone format: optional + followed by 7-15 digits\n const phoneRegex = /^\\+?[0-9]{7,15}$/;\n \n if (!phoneRegex.test(cleaned)) {\n return 'Please enter a valid phone number';\n }\n return null;\n}\n\n/**\n * Validates UK postcode format\n * Accepts formats like: SW1A 1AA, SW1A1AA, M1 1AA, B33 8TH\n */\nexport function ukPostcode(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // UK postcode regex - covers all valid formats\n const postcodeRegex = /^([A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2})$/i;\n \n if (!postcodeRegex.test(value.trim())) {\n return 'Please enter a valid UK postcode';\n }\n return null;\n}\n\n/**\n * Creates a minimum length validator\n * @param min - Minimum number of characters required\n */\nexport function minLen(min: number): (value: string) => string | null {\n return (value: string) => {\n if (!value) return null; // Let required handle empty values\n \n if (value.trim().length < min) {\n return `Must be at least ${min} character${min === 1 ? '' : 's'}`;\n }\n return null;\n };\n}\n\n/**\n * Combines multiple validators into one\n * Returns the first error encountered, or null if all pass\n */\nexport function compose(\n ...validators: Array<(value: string) => string | null>\n): (value: string) => string | null {\n return (value: string) => {\n for (const validator of validators) {\n const error = validator(value);\n if (error) return error;\n }\n return null;\n };\n}\n","import React, {\n useState,\n useCallback,\n useImperativeHandle,\n forwardRef,\n useId,\n} from 'react';\nimport type {\n FieldConfig,\n RegistrationFormProps,\n RegistrationFormRef,\n RegistrationFormValues,\n RegistrationFormErrors,\n} from '../types/registration';\nimport { required, email, phone, ukPostcode, compose } from '../utils/validators';\n\n/**\n * Default field configuration for the registration form\n */\nconst DEFAULT_FIELDS: FieldConfig[] = [\n {\n name: 'firstName',\n label: 'First name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'lastName',\n label: 'Last name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'email',\n label: 'Email address',\n type: 'email',\n required: true,\n validate: compose(required, email),\n },\n {\n name: 'phone',\n label: 'Contact number',\n type: 'tel',\n required: false,\n validate: phone,\n },\n {\n name: 'address1',\n label: 'Address 1',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'address2',\n label: 'Address 2',\n type: 'text',\n required: false,\n },\n {\n name: 'city',\n label: 'Town/City',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'postcode',\n label: 'Postcode',\n type: 'text',\n required: true,\n validate: compose(required, ukPostcode),\n },\n];\n\n/**\n * A reusable, accessible registration form component.\n * \n * Features:\n * - Customizable fields via props\n * - Built-in validation with blur and submit triggers\n * - Full accessibility support (ARIA attributes, keyboard navigation)\n * - Imperative handle for programmatic control (reset, setValues)\n * - Granular styling via classNames prop\n * \n * @example\n * ```tsx\n * const formRef = useRef<RegistrationFormRef>(null);\n * \n * <RegistrationForm\n * ref={formRef}\n * onSubmit={(values) => console.log(values)}\n * onChange={(values, isValid) => console.log(isValid)}\n * submitLabel=\"Register\"\n * />\n * \n * // Programmatic control\n * formRef.current?.reset();\n * formRef.current?.setValues({ email: 'test@example.com' });\n * ```\n */\nexport const RegistrationForm = forwardRef<RegistrationFormRef, RegistrationFormProps>(\n (\n {\n fields = DEFAULT_FIELDS,\n additionalFields,\n onSubmit,\n onChange,\n validateOnBlur = true,\n submitLabel = 'Submit',\n className = '',\n classNames = {},\n },\n ref\n ) => {\n const formId = useId();\n const [values, setValues] = useState<RegistrationFormValues>({});\n const [errors, setErrors] = useState<RegistrationFormErrors>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n // Merge fields with additional fields\n const allFields = additionalFields ? [...fields, ...additionalFields] : fields;\n\n /**\n * Validate a single field\n */\n const validateField = useCallback(\n (field: FieldConfig, value: string): string | null => {\n // Check required first\n if (field.required && (!value || value.trim() === '')) {\n return 'This field is required';\n }\n // Run custom validator if value is present\n if (field.validate && value) {\n return field.validate(value);\n }\n return null;\n },\n []\n );\n\n /**\n * Validate all fields and return whether form is valid\n */\n const validateAll = useCallback((): boolean => {\n const newErrors: RegistrationFormErrors = {};\n let isValid = true;\n\n for (const field of allFields) {\n const value = values[field.name] || '';\n const error = validateField(field, value);\n if (error) {\n newErrors[field.name] = error;\n isValid = false;\n }\n }\n\n setErrors(newErrors);\n return isValid;\n }, [allFields, values, validateField]);\n\n /**\n * Check if current form state is valid (without updating errors)\n */\n const checkIsValid = useCallback(\n (currentValues: RegistrationFormValues): boolean => {\n for (const field of allFields) {\n const value = currentValues[field.name] || '';\n const error = validateField(field, value);\n if (error) return false;\n }\n return true;\n },\n [allFields, validateField]\n );\n\n /**\n * Handle input change\n */\n const handleChange = useCallback(\n (fieldName: string, value: string) => {\n const newValues = { ...values, [fieldName]: value };\n setValues(newValues);\n\n // Clear error if field was touched and is now valid\n if (touched[fieldName]) {\n const field = allFields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(field, value);\n if (!error) {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n\n // Call onChange callback\n if (onChange) {\n const isValid = checkIsValid(newValues);\n onChange(newValues, isValid);\n }\n },\n [values, touched, allFields, validateField, onChange, checkIsValid]\n );\n\n /**\n * Handle input blur\n */\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => ({ ...prev, [fieldName]: true }));\n\n if (validateOnBlur) {\n const field = allFields.find((f) => f.name === fieldName);\n if (field) {\n const value = values[fieldName] || '';\n const error = validateField(field, value);\n if (error) {\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n },\n [validateOnBlur, allFields, values, validateField]\n );\n\n /**\n * Handle form submission\n */\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<string, boolean> = {};\n for (const field of allFields) {\n allTouched[field.name] = true;\n }\n setTouched(allTouched);\n\n // Validate all and submit if valid\n if (validateAll()) {\n onSubmit(values);\n }\n },\n [allFields, validateAll, onSubmit, values]\n );\n\n /**\n * Expose imperative methods via ref\n */\n useImperativeHandle(\n ref,\n () => ({\n reset: () => {\n setValues({});\n setErrors({});\n setTouched({});\n },\n setValues: (newValues: Partial<RegistrationFormValues>) => {\n setValues((prev) => {\n const merged = { ...prev };\n for (const [key, value] of Object.entries(newValues)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n return merged;\n });\n },\n }),\n []\n );\n\n // Default styles\n const styles = {\n fieldWrapper: classNames.fieldWrapper || 'mb-4',\n label: classNames.label || 'block text-sm font-medium mb-1',\n input: classNames.input || 'w-full px-3 py-2 border rounded-md',\n inputError: classNames.inputError || 'border-red-500',\n errorText: classNames.errorText || 'mt-1 text-xs text-red-600',\n button:\n classNames.button ||\n 'w-full mt-4 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50',\n };\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {allFields.map((field) => {\n const fieldId = `${formId}-${field.name}`;\n const errorId = `${fieldId}-error`;\n const value = values[field.name] || '';\n const error = errors[field.name];\n const isTouched = touched[field.name];\n const showError = isTouched && error;\n\n return (\n <div key={field.name} className={styles.fieldWrapper}>\n <label htmlFor={fieldId} className={styles.label}>\n {field.label}\n {field.required && (\n <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n {field.type === 'select' && field.options ? (\n <select\n id={fieldId}\n name={field.name}\n value={value}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n className={`${styles.input} ${showError ? styles.inputError : ''}`}\n aria-invalid={showError ? 'true' : 'false'}\n aria-describedby={showError ? errorId : undefined}\n aria-required={field.required ? 'true' : 'false'}\n >\n <option value=\"\">{field.placeholder || 'Select an option'}</option>\n {field.options.map((option) => (\n <option key={option.id} value={String(option.id)}>\n {option.name}\n {option.price !== undefined && option.price > 0 ? ` (+£${option.price})` : ''}\n </option>\n ))}\n </select>\n ) : (\n <input\n id={fieldId}\n name={field.name}\n type={field.type === 'select' ? 'text' : field.type}\n value={value}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n placeholder={field.placeholder}\n className={`${styles.input} ${showError ? styles.inputError : ''}`}\n aria-invalid={showError ? 'true' : 'false'}\n aria-describedby={showError ? errorId : undefined}\n aria-required={field.required ? 'true' : 'false'}\n />\n )}\n {showError && (\n <p id={errorId} className={styles.errorText} role=\"alert\">\n {error}\n </p>\n )}\n </div>\n );\n })}\n <button type=\"submit\" className={styles.button}>\n {submitLabel}\n </button>\n </form>\n );\n }\n);\n\nRegistrationForm.displayName = 'RegistrationForm';\n"]}
|
package/dist/index.mjs
CHANGED
|
@@ -463,6 +463,7 @@ var DEFAULT_FIELDS = [
|
|
|
463
463
|
var RegistrationForm = forwardRef(
|
|
464
464
|
({
|
|
465
465
|
fields = DEFAULT_FIELDS,
|
|
466
|
+
additionalFields,
|
|
466
467
|
onSubmit,
|
|
467
468
|
onChange,
|
|
468
469
|
validateOnBlur = true,
|
|
@@ -474,6 +475,7 @@ var RegistrationForm = forwardRef(
|
|
|
474
475
|
const [values, setValues] = useState({});
|
|
475
476
|
const [errors, setErrors] = useState({});
|
|
476
477
|
const [touched, setTouched] = useState({});
|
|
478
|
+
const allFields = additionalFields ? [...fields, ...additionalFields] : fields;
|
|
477
479
|
const validateField = useCallback(
|
|
478
480
|
(field, value) => {
|
|
479
481
|
if (field.required && (!value || value.trim() === "")) {
|
|
@@ -489,7 +491,7 @@ var RegistrationForm = forwardRef(
|
|
|
489
491
|
const validateAll = useCallback(() => {
|
|
490
492
|
const newErrors = {};
|
|
491
493
|
let isValid = true;
|
|
492
|
-
for (const field of
|
|
494
|
+
for (const field of allFields) {
|
|
493
495
|
const value = values[field.name] || "";
|
|
494
496
|
const error = validateField(field, value);
|
|
495
497
|
if (error) {
|
|
@@ -499,24 +501,24 @@ var RegistrationForm = forwardRef(
|
|
|
499
501
|
}
|
|
500
502
|
setErrors(newErrors);
|
|
501
503
|
return isValid;
|
|
502
|
-
}, [
|
|
504
|
+
}, [allFields, values, validateField]);
|
|
503
505
|
const checkIsValid = useCallback(
|
|
504
506
|
(currentValues) => {
|
|
505
|
-
for (const field of
|
|
507
|
+
for (const field of allFields) {
|
|
506
508
|
const value = currentValues[field.name] || "";
|
|
507
509
|
const error = validateField(field, value);
|
|
508
510
|
if (error) return false;
|
|
509
511
|
}
|
|
510
512
|
return true;
|
|
511
513
|
},
|
|
512
|
-
[
|
|
514
|
+
[allFields, validateField]
|
|
513
515
|
);
|
|
514
516
|
const handleChange = useCallback(
|
|
515
517
|
(fieldName, value) => {
|
|
516
518
|
const newValues = { ...values, [fieldName]: value };
|
|
517
519
|
setValues(newValues);
|
|
518
520
|
if (touched[fieldName]) {
|
|
519
|
-
const field =
|
|
521
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
520
522
|
if (field) {
|
|
521
523
|
const error = validateField(field, value);
|
|
522
524
|
if (!error) {
|
|
@@ -533,13 +535,13 @@ var RegistrationForm = forwardRef(
|
|
|
533
535
|
onChange(newValues, isValid);
|
|
534
536
|
}
|
|
535
537
|
},
|
|
536
|
-
[values, touched,
|
|
538
|
+
[values, touched, allFields, validateField, onChange, checkIsValid]
|
|
537
539
|
);
|
|
538
540
|
const handleBlur = useCallback(
|
|
539
541
|
(fieldName) => {
|
|
540
542
|
setTouched((prev) => ({ ...prev, [fieldName]: true }));
|
|
541
543
|
if (validateOnBlur) {
|
|
542
|
-
const field =
|
|
544
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
543
545
|
if (field) {
|
|
544
546
|
const value = values[fieldName] || "";
|
|
545
547
|
const error = validateField(field, value);
|
|
@@ -555,13 +557,13 @@ var RegistrationForm = forwardRef(
|
|
|
555
557
|
}
|
|
556
558
|
}
|
|
557
559
|
},
|
|
558
|
-
[validateOnBlur,
|
|
560
|
+
[validateOnBlur, allFields, values, validateField]
|
|
559
561
|
);
|
|
560
562
|
const handleSubmit = useCallback(
|
|
561
563
|
(e) => {
|
|
562
564
|
e.preventDefault();
|
|
563
565
|
const allTouched = {};
|
|
564
|
-
for (const field of
|
|
566
|
+
for (const field of allFields) {
|
|
565
567
|
allTouched[field.name] = true;
|
|
566
568
|
}
|
|
567
569
|
setTouched(allTouched);
|
|
@@ -569,7 +571,7 @@ var RegistrationForm = forwardRef(
|
|
|
569
571
|
onSubmit(values);
|
|
570
572
|
}
|
|
571
573
|
},
|
|
572
|
-
[
|
|
574
|
+
[allFields, validateAll, onSubmit, values]
|
|
573
575
|
);
|
|
574
576
|
useImperativeHandle(
|
|
575
577
|
ref,
|
|
@@ -602,7 +604,7 @@ var RegistrationForm = forwardRef(
|
|
|
602
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"
|
|
603
605
|
};
|
|
604
606
|
return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
605
|
-
|
|
607
|
+
allFields.map((field) => {
|
|
606
608
|
const fieldId = `${formId}-${field.name}`;
|
|
607
609
|
const errorId = `${fieldId}-error`;
|
|
608
610
|
const value = values[field.name] || "";
|
|
@@ -614,12 +616,32 @@ var RegistrationForm = forwardRef(
|
|
|
614
616
|
field.label,
|
|
615
617
|
field.required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
616
618
|
] }),
|
|
617
|
-
/* @__PURE__ */
|
|
619
|
+
field.type === "select" && field.options ? /* @__PURE__ */ jsxs(
|
|
620
|
+
"select",
|
|
621
|
+
{
|
|
622
|
+
id: fieldId,
|
|
623
|
+
name: field.name,
|
|
624
|
+
value,
|
|
625
|
+
onChange: (e) => handleChange(field.name, e.target.value),
|
|
626
|
+
onBlur: () => handleBlur(field.name),
|
|
627
|
+
className: `${styles.input} ${showError ? styles.inputError : ""}`,
|
|
628
|
+
"aria-invalid": showError ? "true" : "false",
|
|
629
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
630
|
+
"aria-required": field.required ? "true" : "false",
|
|
631
|
+
children: [
|
|
632
|
+
/* @__PURE__ */ jsx("option", { value: "", children: field.placeholder || "Select an option" }),
|
|
633
|
+
field.options.map((option) => /* @__PURE__ */ jsxs("option", { value: String(option.id), children: [
|
|
634
|
+
option.name,
|
|
635
|
+
option.price !== void 0 && option.price > 0 ? ` (+\xA3${option.price})` : ""
|
|
636
|
+
] }, option.id))
|
|
637
|
+
]
|
|
638
|
+
}
|
|
639
|
+
) : /* @__PURE__ */ jsx(
|
|
618
640
|
"input",
|
|
619
641
|
{
|
|
620
642
|
id: fieldId,
|
|
621
643
|
name: field.name,
|
|
622
|
-
type: field.type,
|
|
644
|
+
type: field.type === "select" ? "text" : field.type,
|
|
623
645
|
value,
|
|
624
646
|
onChange: (e) => handleChange(field.name, e.target.value),
|
|
625
647
|
onBlur: () => handleBlur(field.name),
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/components/BookingForm.tsx","../src/utils/validators.ts","../src/components/RegistrationForm.tsx"],"names":["useState","useCallback","jsxs","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport type { Question, FormValues, FormErrors, BookingFormProps, BookingFormClassNames } from '../types';\n\n/** Merge base classes with optional custom classes */\nconst cx = (...classes: (string | undefined)[]) => classes.filter(Boolean).join(' ');\n\n/**\n * Renders a single form field based on question type\n */\nfunction FormField({\n question,\n value,\n error,\n onChange,\n classNames,\n}: {\n question: Question;\n value: string | number | boolean | undefined;\n error?: string;\n onChange: (value: string | number | boolean) => void;\n classNames?: BookingFormClassNames;\n}) {\n const inputId = `question-${question.id}`;\n const errorId = `${inputId}-error`;\n const hasError = !!error;\n\n // Default classes (can be overridden via classNames prop)\n const defaultFieldWrapper = 'mb-4';\n const defaultLabel = 'block text-sm font-medium mb-1 text-gray-700';\n const defaultHeading = 'text-lg font-semibold text-gray-900 mt-4 mb-2 first:mt-0';\n const defaultInput = 'w-full px-3 py-2 border rounded-md text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1 border-gray-300 focus:ring-blue-500 focus:border-blue-500';\n const defaultInputError = 'border-red-500 focus:ring-red-500';\n const defaultCheckbox = 'mt-1 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500';\n const defaultHelpText = 'mt-1 text-xs text-gray-500';\n const defaultErrorText = 'mt-1 text-xs text-red-600';\n\n const inputClasses = hasError\n ? cx(classNames?.input ?? defaultInput, classNames?.inputError ?? defaultInputError)\n : cx(classNames?.input ?? defaultInput);\n\n const labelClasses = classNames?.label ?? defaultLabel;\n const checkboxLabelClasses = cx('text-sm', classNames?.label ?? 'text-gray-700');\n\n const renderLabel = () => {\n if (question.detail_type === 'heading') return null;\n return (\n <label htmlFor={inputId} className={labelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n );\n };\n\n const renderHelpText = () => {\n if (!question.help_text) return null;\n return <p className={classNames?.helpText ?? defaultHelpText}>{question.help_text}</p>;\n };\n\n const renderError = () => {\n if (!error) return null;\n return (\n <p id={errorId} className={classNames?.errorText ?? defaultErrorText} role=\"alert\">\n {error}\n </p>\n );\n };\n\n const ariaProps = {\n 'aria-invalid': hasError ? true : undefined,\n 'aria-describedby': hasError ? errorId : undefined,\n 'aria-required': question.required || undefined,\n };\n\n switch (question.detail_type) {\n case 'heading':\n return (\n <h3 className={classNames?.heading ?? defaultHeading}>\n {question.name}\n </h3>\n );\n\n case 'text_field':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'text_area':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <textarea\n id={inputId}\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n rows={4}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'select':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <select\n id={inputId}\n value={(value as string | number) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n className={inputClasses}\n {...ariaProps}\n >\n <option value=\"\">Select an option</option>\n {question.options?.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'date':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"date\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n min={question.settings?.min?.toString()}\n max={question.settings?.max?.toString()}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'number':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"number\"\n value={(value as number) ?? ''}\n onChange={(e) => onChange(e.target.value ? Number(e.target.value) : '')}\n min={question.settings?.min}\n max={question.settings?.max}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'check':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n <div className=\"flex items-start gap-2\">\n <input\n id={inputId}\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => onChange(e.target.checked)}\n className={classNames?.checkbox ?? defaultCheckbox}\n {...ariaProps}\n />\n <label htmlFor={inputId} className={checkboxLabelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n </div>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * BookingForm - A dynamic form component for booking questions\n *\n * @example\n * ```tsx\n * const questions: Question[] = [\n * { id: 1, name: 'Personal Details', detail_type: 'heading' },\n * { id: 2, name: 'Full Name', detail_type: 'text_field', required: true },\n * { id: 3, name: 'Email', detail_type: 'text_field', required: true },\n * ];\n *\n * <BookingForm\n * questions={questions}\n * onSubmit={(values) => console.log(values)}\n * />\n * ```\n */\nexport function BookingForm({\n questions,\n onSubmit,\n submitLabel = 'Submit',\n className = '',\n labelClassName,\n classNames: classNamesProp,\n}: BookingFormProps) {\n // Merge deprecated labelClassName into classNames for backwards compatibility\n const classNames: BookingFormClassNames = {\n ...classNamesProp,\n label: classNamesProp?.label ?? labelClassName,\n };\n const [values, setValues] = useState<FormValues>({});\n const [errors, setErrors] = useState<FormErrors>({});\n const [touched, setTouched] = useState<Record<number, boolean>>({});\n\n\n // Check if a question should be visible based on conditional settings\n const isQuestionVisible = useCallback(\n (question: Question): boolean => {\n const { settings } = question;\n if (!settings?.conditional_answers) {\n return true;\n }\n\n // Check all conditions in conditional_answers\n // Each entry is { questionId: expectedAnswerValue }\n const conditionEntries = Object.entries(settings.conditional_answers as Record<string, unknown>);\n if (conditionEntries.length === 0) {\n return true;\n }\n\n // Question is visible if ANY condition is met\n return conditionEntries.some(([questionIdStr, expectedAnswer]) => {\n const questionId = Number(questionIdStr);\n const currentValue = (values as Record<string, unknown>)[String(questionId)];\n\n if (currentValue === undefined || currentValue === '' || currentValue === null) {\n return false;\n }\n\n // Selects typically store the option id (as string), but allow `{ id, name }` objects too\n const normalizedCurrent =\n typeof currentValue === 'object' && currentValue !== null && 'id' in (currentValue as any)\n ? (currentValue as any)\n : currentValue;\n\n // Build a set of candidate strings for comparison.\n // For select questions we support matching by BOTH option id and option name.\n const candidates = new Set<string>();\n\n const addCandidate = (v: unknown) => {\n if (v === undefined || v === null) return;\n const s = String(v).trim();\n if (s) candidates.add(s);\n };\n\n const sourceQuestion = questions.find((q) => q.id === questionId);\n\n if (typeof normalizedCurrent === 'object' && normalizedCurrent !== null) {\n addCandidate((normalizedCurrent as any).id);\n addCandidate((normalizedCurrent as any).name);\n } else {\n addCandidate(normalizedCurrent);\n }\n\n if (sourceQuestion?.detail_type === 'select' && sourceQuestion.options?.length) {\n // Try to resolve the selected option via id or name.\n const currentStr = [...candidates][0] ?? '';\n const optionById = sourceQuestion.options.find((o) => String(o.id) === currentStr);\n const optionByName = sourceQuestion.options.find((o) => String(o.name).trim() === currentStr);\n const opt = optionById ?? optionByName;\n if (opt) {\n addCandidate(opt.id);\n addCandidate(opt.name);\n }\n }\n\n const matchesScalar = (expected: unknown) => {\n const expectedStr = String(expected).trim();\n return candidates.has(expectedStr);\n };\n\n // Support multiple expected formats:\n // - scalar: \"Consultation\" / \"1\" / 1 / true\n // - array: [\"Consultation\", \"Follow-up\"]\n // - map/object: { \"Consultation\": true }\n if (Array.isArray(expectedAnswer)) {\n return expectedAnswer.some((v) => matchesScalar(v));\n }\n\n if (expectedAnswer && typeof expectedAnswer === 'object') {\n const expectedMap = expectedAnswer as Record<string, unknown>;\n for (const c of candidates) {\n if (Object.prototype.hasOwnProperty.call(expectedMap, c)) {\n const flag = expectedMap[c];\n return flag === undefined ? true : !!flag;\n }\n }\n return false;\n }\n\n return matchesScalar(expectedAnswer);\n });\n },\n [values, questions]\n );\n\n // Get visible questions\n const visibleQuestions = questions.filter(isQuestionVisible);\n\n\n // Validate a single field\n const validateField = useCallback((question: Question, value: FormValues[number]): string | null => {\n if (question.detail_type === 'heading') return null;\n\n if (question.required) {\n if (value === undefined || value === '' || value === null) {\n return `${question.name} is required`;\n }\n if (question.detail_type === 'check' && !value) {\n return `${question.name} must be checked`;\n }\n }\n\n if (question.detail_type === 'number' && value !== '' && value !== undefined) {\n const numValue = Number(value);\n if (question.settings?.min !== undefined && numValue < question.settings.min) {\n return `Minimum value is ${question.settings.min}`;\n }\n if (question.settings?.max !== undefined && numValue > question.settings.max) {\n return `Maximum value is ${question.settings.max}`;\n }\n }\n\n return null;\n }, []);\n\n // Validate all visible fields\n const validateAll = useCallback((): boolean => {\n const newErrors: FormErrors = {};\n let isValid = true;\n\n visibleQuestions.forEach((question) => {\n const error = validateField(question, values[question.id]);\n if (error) {\n newErrors[question.id] = error;\n isValid = false;\n }\n });\n\n setErrors(newErrors);\n return isValid;\n }, [visibleQuestions, values, validateField]);\n\n // Clear errors for hidden questions\n useEffect(() => {\n const visibleIds = new Set(visibleQuestions.map((q) => q.id));\n\n setErrors((prev) => {\n let changed = false;\n const next = { ...prev };\n\n Object.keys(next).forEach((idStr) => {\n const id = Number(idStr);\n if (!visibleIds.has(id)) {\n delete next[id];\n changed = true;\n }\n });\n\n return changed ? next : prev;\n });\n }, [visibleQuestions]);\n\n const handleChange = (questionId: number, value: string | number | boolean) => {\n setValues((prev) => ({ ...prev, [questionId]: value }));\n setTouched((prev) => ({ ...prev, [questionId]: true }));\n\n // Clear error on change if touched\n if (touched[questionId]) {\n const question = questions.find((q) => q.id === questionId);\n if (question) {\n const error = validateField(question, value);\n setErrors((prev) => {\n if (error) {\n return { ...prev, [questionId]: error };\n }\n const { [questionId]: _, ...rest } = prev;\n return rest;\n });\n }\n }\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<number, boolean> = {};\n visibleQuestions.forEach((q) => {\n allTouched[q.id] = true;\n });\n setTouched(allTouched);\n\n if (validateAll()) {\n // Only include visible question values\n const visibleValues: FormValues = {};\n visibleQuestions.forEach((q) => {\n if (q.detail_type !== 'heading' && values[q.id] !== undefined) {\n visibleValues[q.id] = values[q.id];\n }\n });\n onSubmit(visibleValues);\n }\n };\n\n 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';\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {visibleQuestions.map((question) => (\n <FormField\n key={question.id}\n question={question}\n value={values[question.id]}\n error={touched[question.id] ? errors[question.id] : undefined}\n onChange={(value) => handleChange(question.id, value)}\n classNames={classNames}\n />\n ))}\n <button\n type=\"submit\"\n className={classNames?.button ?? defaultButton}\n >\n {submitLabel}\n </button>\n </form>\n );\n}\n\nexport default BookingForm;\n","/**\n * Validation helper functions for form fields\n * Each validator returns an error message string if invalid, or null if valid\n */\n\n/**\n * Validates that a value is not empty\n */\nexport function required(value: string): string | null {\n if (!value || value.trim() === '') {\n return 'This field is required';\n }\n return null;\n}\n\n/**\n * Validates email format (RFC 5322 compliant)\n */\nexport function email(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n 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])?)*$/;\n \n if (!emailRegex.test(value)) {\n return 'Please enter a valid email address';\n }\n return null;\n}\n\n/**\n * Validates phone number format (international)\n * Accepts formats like: +44 1234 567890, 01onal234 567890, +1-234-567-8900\n */\nexport function phone(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // Remove all spaces, dashes, and parentheses for validation\n const cleaned = value.replace(/[\\s\\-\\(\\)]/g, '');\n \n // Check for valid phone format: optional + followed by 7-15 digits\n const phoneRegex = /^\\+?[0-9]{7,15}$/;\n \n if (!phoneRegex.test(cleaned)) {\n return 'Please enter a valid phone number';\n }\n return null;\n}\n\n/**\n * Validates UK postcode format\n * Accepts formats like: SW1A 1AA, SW1A1AA, M1 1AA, B33 8TH\n */\nexport function ukPostcode(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // UK postcode regex - covers all valid formats\n const postcodeRegex = /^([A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2})$/i;\n \n if (!postcodeRegex.test(value.trim())) {\n return 'Please enter a valid UK postcode';\n }\n return null;\n}\n\n/**\n * Creates a minimum length validator\n * @param min - Minimum number of characters required\n */\nexport function minLen(min: number): (value: string) => string | null {\n return (value: string) => {\n if (!value) return null; // Let required handle empty values\n \n if (value.trim().length < min) {\n return `Must be at least ${min} character${min === 1 ? '' : 's'}`;\n }\n return null;\n };\n}\n\n/**\n * Combines multiple validators into one\n * Returns the first error encountered, or null if all pass\n */\nexport function compose(\n ...validators: Array<(value: string) => string | null>\n): (value: string) => string | null {\n return (value: string) => {\n for (const validator of validators) {\n const error = validator(value);\n if (error) return error;\n }\n return null;\n };\n}\n","import React, {\n useState,\n useCallback,\n useImperativeHandle,\n forwardRef,\n useId,\n} from 'react';\nimport type {\n FieldConfig,\n RegistrationFormProps,\n RegistrationFormRef,\n RegistrationFormValues,\n RegistrationFormErrors,\n} from '../types/registration';\nimport { required, email, phone, ukPostcode, compose } from '../utils/validators';\n\n/**\n * Default field configuration for the registration form\n */\nconst DEFAULT_FIELDS: FieldConfig[] = [\n {\n name: 'firstName',\n label: 'First name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'lastName',\n label: 'Last name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'email',\n label: 'Email address',\n type: 'email',\n required: true,\n validate: compose(required, email),\n },\n {\n name: 'phone',\n label: 'Contact number',\n type: 'tel',\n required: false,\n validate: phone,\n },\n {\n name: 'address1',\n label: 'Address 1',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'address2',\n label: 'Address 2',\n type: 'text',\n required: false,\n },\n {\n name: 'city',\n label: 'Town/City',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'postcode',\n label: 'Postcode',\n type: 'text',\n required: true,\n validate: compose(required, ukPostcode),\n },\n];\n\n/**\n * A reusable, accessible registration form component.\n * \n * Features:\n * - Customizable fields via props\n * - Built-in validation with blur and submit triggers\n * - Full accessibility support (ARIA attributes, keyboard navigation)\n * - Imperative handle for programmatic control (reset, setValues)\n * - Granular styling via classNames prop\n * \n * @example\n * ```tsx\n * const formRef = useRef<RegistrationFormRef>(null);\n * \n * <RegistrationForm\n * ref={formRef}\n * onSubmit={(values) => console.log(values)}\n * onChange={(values, isValid) => console.log(isValid)}\n * submitLabel=\"Register\"\n * />\n * \n * // Programmatic control\n * formRef.current?.reset();\n * formRef.current?.setValues({ email: 'test@example.com' });\n * ```\n */\nexport const RegistrationForm = forwardRef<RegistrationFormRef, RegistrationFormProps>(\n (\n {\n fields = DEFAULT_FIELDS,\n onSubmit,\n onChange,\n validateOnBlur = true,\n submitLabel = 'Submit',\n className = '',\n classNames = {},\n },\n ref\n ) => {\n const formId = useId();\n const [values, setValues] = useState<RegistrationFormValues>({});\n const [errors, setErrors] = useState<RegistrationFormErrors>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n /**\n * Validate a single field\n */\n const validateField = useCallback(\n (field: FieldConfig, value: string): string | null => {\n // Check required first\n if (field.required && (!value || value.trim() === '')) {\n return 'This field is required';\n }\n // Run custom validator if value is present\n if (field.validate && value) {\n return field.validate(value);\n }\n return null;\n },\n []\n );\n\n /**\n * Validate all fields and return whether form is valid\n */\n const validateAll = useCallback((): boolean => {\n const newErrors: RegistrationFormErrors = {};\n let isValid = true;\n\n for (const field of fields) {\n const value = values[field.name] || '';\n const error = validateField(field, value);\n if (error) {\n newErrors[field.name] = error;\n isValid = false;\n }\n }\n\n setErrors(newErrors);\n return isValid;\n }, [fields, values, validateField]);\n\n /**\n * Check if current form state is valid (without updating errors)\n */\n const checkIsValid = useCallback(\n (currentValues: RegistrationFormValues): boolean => {\n for (const field of fields) {\n const value = currentValues[field.name] || '';\n const error = validateField(field, value);\n if (error) return false;\n }\n return true;\n },\n [fields, validateField]\n );\n\n /**\n * Handle input change\n */\n const handleChange = useCallback(\n (fieldName: string, value: string) => {\n const newValues = { ...values, [fieldName]: value };\n setValues(newValues);\n\n // Clear error if field was touched and is now valid\n if (touched[fieldName]) {\n const field = fields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(field, value);\n if (!error) {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n\n // Call onChange callback\n if (onChange) {\n const isValid = checkIsValid(newValues);\n onChange(newValues, isValid);\n }\n },\n [values, touched, fields, validateField, onChange, checkIsValid]\n );\n\n /**\n * Handle input blur\n */\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => ({ ...prev, [fieldName]: true }));\n\n if (validateOnBlur) {\n const field = fields.find((f) => f.name === fieldName);\n if (field) {\n const value = values[fieldName] || '';\n const error = validateField(field, value);\n if (error) {\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n },\n [validateOnBlur, fields, values, validateField]\n );\n\n /**\n * Handle form submission\n */\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<string, boolean> = {};\n for (const field of fields) {\n allTouched[field.name] = true;\n }\n setTouched(allTouched);\n\n // Validate all and submit if valid\n if (validateAll()) {\n onSubmit(values);\n }\n },\n [fields, validateAll, onSubmit, values]\n );\n\n /**\n * Expose imperative methods via ref\n */\n useImperativeHandle(\n ref,\n () => ({\n reset: () => {\n setValues({});\n setErrors({});\n setTouched({});\n },\n setValues: (newValues: Partial<RegistrationFormValues>) => {\n setValues((prev) => {\n const merged = { ...prev };\n for (const [key, value] of Object.entries(newValues)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n return merged;\n });\n },\n }),\n []\n );\n\n // Default styles\n const styles = {\n fieldWrapper: classNames.fieldWrapper || 'mb-4',\n label: classNames.label || 'block text-sm font-medium mb-1',\n input: classNames.input || 'w-full px-3 py-2 border rounded-md',\n inputError: classNames.inputError || 'border-red-500',\n errorText: classNames.errorText || 'mt-1 text-xs text-red-600',\n button:\n classNames.button ||\n 'w-full mt-4 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50',\n };\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {fields.map((field) => {\n const fieldId = `${formId}-${field.name}`;\n const errorId = `${fieldId}-error`;\n const value = values[field.name] || '';\n const error = errors[field.name];\n const isTouched = touched[field.name];\n const showError = isTouched && error;\n\n return (\n <div key={field.name} className={styles.fieldWrapper}>\n <label htmlFor={fieldId} className={styles.label}>\n {field.label}\n {field.required && (\n <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n <input\n id={fieldId}\n name={field.name}\n type={field.type}\n value={value}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n placeholder={field.placeholder}\n className={`${styles.input} ${showError ? styles.inputError : ''}`}\n aria-invalid={showError ? 'true' : 'false'}\n aria-describedby={showError ? errorId : undefined}\n aria-required={field.required ? 'true' : 'false'}\n />\n {showError && (\n <p id={errorId} className={styles.errorText} role=\"alert\">\n {error}\n </p>\n )}\n </div>\n );\n })}\n <button type=\"submit\" className={styles.button}>\n {submitLabel}\n </button>\n </form>\n );\n }\n);\n\nRegistrationForm.displayName = 'RegistrationForm';\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/components/BookingForm.tsx","../src/utils/validators.ts","../src/components/RegistrationForm.tsx"],"names":["useState","useCallback","jsxs","jsx"],"mappings":"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","file":"index.mjs","sourcesContent":["import React, { useState, useEffect, useCallback } from 'react';\nimport type { Question, FormValues, FormErrors, BookingFormProps, BookingFormClassNames } from '../types';\n\n/** Merge base classes with optional custom classes */\nconst cx = (...classes: (string | undefined)[]) => classes.filter(Boolean).join(' ');\n\n/**\n * Renders a single form field based on question type\n */\nfunction FormField({\n question,\n value,\n error,\n onChange,\n classNames,\n}: {\n question: Question;\n value: string | number | boolean | undefined;\n error?: string;\n onChange: (value: string | number | boolean) => void;\n classNames?: BookingFormClassNames;\n}) {\n const inputId = `question-${question.id}`;\n const errorId = `${inputId}-error`;\n const hasError = !!error;\n\n // Default classes (can be overridden via classNames prop)\n const defaultFieldWrapper = 'mb-4';\n const defaultLabel = 'block text-sm font-medium mb-1 text-gray-700';\n const defaultHeading = 'text-lg font-semibold text-gray-900 mt-4 mb-2 first:mt-0';\n const defaultInput = 'w-full px-3 py-2 border rounded-md text-sm transition-colors focus:outline-none focus:ring-2 focus:ring-offset-1 border-gray-300 focus:ring-blue-500 focus:border-blue-500';\n const defaultInputError = 'border-red-500 focus:ring-red-500';\n const defaultCheckbox = 'mt-1 h-4 w-4 rounded border-gray-300 text-blue-600 focus:ring-blue-500';\n const defaultHelpText = 'mt-1 text-xs text-gray-500';\n const defaultErrorText = 'mt-1 text-xs text-red-600';\n\n const inputClasses = hasError\n ? cx(classNames?.input ?? defaultInput, classNames?.inputError ?? defaultInputError)\n : cx(classNames?.input ?? defaultInput);\n\n const labelClasses = classNames?.label ?? defaultLabel;\n const checkboxLabelClasses = cx('text-sm', classNames?.label ?? 'text-gray-700');\n\n const renderLabel = () => {\n if (question.detail_type === 'heading') return null;\n return (\n <label htmlFor={inputId} className={labelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n );\n };\n\n const renderHelpText = () => {\n if (!question.help_text) return null;\n return <p className={classNames?.helpText ?? defaultHelpText}>{question.help_text}</p>;\n };\n\n const renderError = () => {\n if (!error) return null;\n return (\n <p id={errorId} className={classNames?.errorText ?? defaultErrorText} role=\"alert\">\n {error}\n </p>\n );\n };\n\n const ariaProps = {\n 'aria-invalid': hasError ? true : undefined,\n 'aria-describedby': hasError ? errorId : undefined,\n 'aria-required': question.required || undefined,\n };\n\n switch (question.detail_type) {\n case 'heading':\n return (\n <h3 className={classNames?.heading ?? defaultHeading}>\n {question.name}\n </h3>\n );\n\n case 'text_field':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"text\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'text_area':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <textarea\n id={inputId}\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n placeholder={question.settings?.placeholder}\n rows={4}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'select':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <select\n id={inputId}\n value={(value as string | number) ?? ''}\n onChange={(e) => onChange(e.target.value)}\n className={inputClasses}\n {...ariaProps}\n >\n <option value=\"\">Select an option</option>\n {question.options?.map((option) => (\n <option key={option.id} value={option.id}>\n {option.name}\n </option>\n ))}\n </select>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'date':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"date\"\n value={(value as string) || ''}\n onChange={(e) => onChange(e.target.value)}\n min={question.settings?.min?.toString()}\n max={question.settings?.max?.toString()}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'number':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n {renderLabel()}\n <input\n id={inputId}\n type=\"number\"\n value={(value as number) ?? ''}\n onChange={(e) => onChange(e.target.value ? Number(e.target.value) : '')}\n min={question.settings?.min}\n max={question.settings?.max}\n placeholder={question.settings?.placeholder}\n className={inputClasses}\n {...ariaProps}\n />\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n case 'check':\n return (\n <div className={classNames?.fieldWrapper ?? defaultFieldWrapper}>\n <div className=\"flex items-start gap-2\">\n <input\n id={inputId}\n type=\"checkbox\"\n checked={!!value}\n onChange={(e) => onChange(e.target.checked)}\n className={classNames?.checkbox ?? defaultCheckbox}\n {...ariaProps}\n />\n <label htmlFor={inputId} className={checkboxLabelClasses}>\n {question.name}\n {question.required && <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">*</span>}\n </label>\n </div>\n {renderHelpText()}\n {renderError()}\n </div>\n );\n\n default:\n return null;\n }\n}\n\n/**\n * BookingForm - A dynamic form component for booking questions\n *\n * @example\n * ```tsx\n * const questions: Question[] = [\n * { id: 1, name: 'Personal Details', detail_type: 'heading' },\n * { id: 2, name: 'Full Name', detail_type: 'text_field', required: true },\n * { id: 3, name: 'Email', detail_type: 'text_field', required: true },\n * ];\n *\n * <BookingForm\n * questions={questions}\n * onSubmit={(values) => console.log(values)}\n * />\n * ```\n */\nexport function BookingForm({\n questions,\n onSubmit,\n submitLabel = 'Submit',\n className = '',\n labelClassName,\n classNames: classNamesProp,\n}: BookingFormProps) {\n // Merge deprecated labelClassName into classNames for backwards compatibility\n const classNames: BookingFormClassNames = {\n ...classNamesProp,\n label: classNamesProp?.label ?? labelClassName,\n };\n const [values, setValues] = useState<FormValues>({});\n const [errors, setErrors] = useState<FormErrors>({});\n const [touched, setTouched] = useState<Record<number, boolean>>({});\n\n\n // Check if a question should be visible based on conditional settings\n const isQuestionVisible = useCallback(\n (question: Question): boolean => {\n const { settings } = question;\n if (!settings?.conditional_answers) {\n return true;\n }\n\n // Check all conditions in conditional_answers\n // Each entry is { questionId: expectedAnswerValue }\n const conditionEntries = Object.entries(settings.conditional_answers as Record<string, unknown>);\n if (conditionEntries.length === 0) {\n return true;\n }\n\n // Question is visible if ANY condition is met\n return conditionEntries.some(([questionIdStr, expectedAnswer]) => {\n const questionId = Number(questionIdStr);\n const currentValue = (values as Record<string, unknown>)[String(questionId)];\n\n if (currentValue === undefined || currentValue === '' || currentValue === null) {\n return false;\n }\n\n // Selects typically store the option id (as string), but allow `{ id, name }` objects too\n const normalizedCurrent =\n typeof currentValue === 'object' && currentValue !== null && 'id' in (currentValue as any)\n ? (currentValue as any)\n : currentValue;\n\n // Build a set of candidate strings for comparison.\n // For select questions we support matching by BOTH option id and option name.\n const candidates = new Set<string>();\n\n const addCandidate = (v: unknown) => {\n if (v === undefined || v === null) return;\n const s = String(v).trim();\n if (s) candidates.add(s);\n };\n\n const sourceQuestion = questions.find((q) => q.id === questionId);\n\n if (typeof normalizedCurrent === 'object' && normalizedCurrent !== null) {\n addCandidate((normalizedCurrent as any).id);\n addCandidate((normalizedCurrent as any).name);\n } else {\n addCandidate(normalizedCurrent);\n }\n\n if (sourceQuestion?.detail_type === 'select' && sourceQuestion.options?.length) {\n // Try to resolve the selected option via id or name.\n const currentStr = [...candidates][0] ?? '';\n const optionById = sourceQuestion.options.find((o) => String(o.id) === currentStr);\n const optionByName = sourceQuestion.options.find((o) => String(o.name).trim() === currentStr);\n const opt = optionById ?? optionByName;\n if (opt) {\n addCandidate(opt.id);\n addCandidate(opt.name);\n }\n }\n\n const matchesScalar = (expected: unknown) => {\n const expectedStr = String(expected).trim();\n return candidates.has(expectedStr);\n };\n\n // Support multiple expected formats:\n // - scalar: \"Consultation\" / \"1\" / 1 / true\n // - array: [\"Consultation\", \"Follow-up\"]\n // - map/object: { \"Consultation\": true }\n if (Array.isArray(expectedAnswer)) {\n return expectedAnswer.some((v) => matchesScalar(v));\n }\n\n if (expectedAnswer && typeof expectedAnswer === 'object') {\n const expectedMap = expectedAnswer as Record<string, unknown>;\n for (const c of candidates) {\n if (Object.prototype.hasOwnProperty.call(expectedMap, c)) {\n const flag = expectedMap[c];\n return flag === undefined ? true : !!flag;\n }\n }\n return false;\n }\n\n return matchesScalar(expectedAnswer);\n });\n },\n [values, questions]\n );\n\n // Get visible questions\n const visibleQuestions = questions.filter(isQuestionVisible);\n\n\n // Validate a single field\n const validateField = useCallback((question: Question, value: FormValues[number]): string | null => {\n if (question.detail_type === 'heading') return null;\n\n if (question.required) {\n if (value === undefined || value === '' || value === null) {\n return `${question.name} is required`;\n }\n if (question.detail_type === 'check' && !value) {\n return `${question.name} must be checked`;\n }\n }\n\n if (question.detail_type === 'number' && value !== '' && value !== undefined) {\n const numValue = Number(value);\n if (question.settings?.min !== undefined && numValue < question.settings.min) {\n return `Minimum value is ${question.settings.min}`;\n }\n if (question.settings?.max !== undefined && numValue > question.settings.max) {\n return `Maximum value is ${question.settings.max}`;\n }\n }\n\n return null;\n }, []);\n\n // Validate all visible fields\n const validateAll = useCallback((): boolean => {\n const newErrors: FormErrors = {};\n let isValid = true;\n\n visibleQuestions.forEach((question) => {\n const error = validateField(question, values[question.id]);\n if (error) {\n newErrors[question.id] = error;\n isValid = false;\n }\n });\n\n setErrors(newErrors);\n return isValid;\n }, [visibleQuestions, values, validateField]);\n\n // Clear errors for hidden questions\n useEffect(() => {\n const visibleIds = new Set(visibleQuestions.map((q) => q.id));\n\n setErrors((prev) => {\n let changed = false;\n const next = { ...prev };\n\n Object.keys(next).forEach((idStr) => {\n const id = Number(idStr);\n if (!visibleIds.has(id)) {\n delete next[id];\n changed = true;\n }\n });\n\n return changed ? next : prev;\n });\n }, [visibleQuestions]);\n\n const handleChange = (questionId: number, value: string | number | boolean) => {\n setValues((prev) => ({ ...prev, [questionId]: value }));\n setTouched((prev) => ({ ...prev, [questionId]: true }));\n\n // Clear error on change if touched\n if (touched[questionId]) {\n const question = questions.find((q) => q.id === questionId);\n if (question) {\n const error = validateField(question, value);\n setErrors((prev) => {\n if (error) {\n return { ...prev, [questionId]: error };\n }\n const { [questionId]: _, ...rest } = prev;\n return rest;\n });\n }\n }\n };\n\n const handleSubmit = (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<number, boolean> = {};\n visibleQuestions.forEach((q) => {\n allTouched[q.id] = true;\n });\n setTouched(allTouched);\n\n if (validateAll()) {\n // Only include visible question values\n const visibleValues: FormValues = {};\n visibleQuestions.forEach((q) => {\n if (q.detail_type !== 'heading' && values[q.id] !== undefined) {\n visibleValues[q.id] = values[q.id];\n }\n });\n onSubmit(visibleValues);\n }\n };\n\n 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';\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {visibleQuestions.map((question) => (\n <FormField\n key={question.id}\n question={question}\n value={values[question.id]}\n error={touched[question.id] ? errors[question.id] : undefined}\n onChange={(value) => handleChange(question.id, value)}\n classNames={classNames}\n />\n ))}\n <button\n type=\"submit\"\n className={classNames?.button ?? defaultButton}\n >\n {submitLabel}\n </button>\n </form>\n );\n}\n\nexport default BookingForm;\n","/**\n * Validation helper functions for form fields\n * Each validator returns an error message string if invalid, or null if valid\n */\n\n/**\n * Validates that a value is not empty\n */\nexport function required(value: string): string | null {\n if (!value || value.trim() === '') {\n return 'This field is required';\n }\n return null;\n}\n\n/**\n * Validates email format (RFC 5322 compliant)\n */\nexport function email(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n 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])?)*$/;\n \n if (!emailRegex.test(value)) {\n return 'Please enter a valid email address';\n }\n return null;\n}\n\n/**\n * Validates phone number format (international)\n * Accepts formats like: +44 1234 567890, 01onal234 567890, +1-234-567-8900\n */\nexport function phone(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // Remove all spaces, dashes, and parentheses for validation\n const cleaned = value.replace(/[\\s\\-\\(\\)]/g, '');\n \n // Check for valid phone format: optional + followed by 7-15 digits\n const phoneRegex = /^\\+?[0-9]{7,15}$/;\n \n if (!phoneRegex.test(cleaned)) {\n return 'Please enter a valid phone number';\n }\n return null;\n}\n\n/**\n * Validates UK postcode format\n * Accepts formats like: SW1A 1AA, SW1A1AA, M1 1AA, B33 8TH\n */\nexport function ukPostcode(value: string): string | null {\n if (!value) return null; // Let required handle empty values\n \n // UK postcode regex - covers all valid formats\n const postcodeRegex = /^([A-Z]{1,2}[0-9][A-Z0-9]? ?[0-9][A-Z]{2})$/i;\n \n if (!postcodeRegex.test(value.trim())) {\n return 'Please enter a valid UK postcode';\n }\n return null;\n}\n\n/**\n * Creates a minimum length validator\n * @param min - Minimum number of characters required\n */\nexport function minLen(min: number): (value: string) => string | null {\n return (value: string) => {\n if (!value) return null; // Let required handle empty values\n \n if (value.trim().length < min) {\n return `Must be at least ${min} character${min === 1 ? '' : 's'}`;\n }\n return null;\n };\n}\n\n/**\n * Combines multiple validators into one\n * Returns the first error encountered, or null if all pass\n */\nexport function compose(\n ...validators: Array<(value: string) => string | null>\n): (value: string) => string | null {\n return (value: string) => {\n for (const validator of validators) {\n const error = validator(value);\n if (error) return error;\n }\n return null;\n };\n}\n","import React, {\n useState,\n useCallback,\n useImperativeHandle,\n forwardRef,\n useId,\n} from 'react';\nimport type {\n FieldConfig,\n RegistrationFormProps,\n RegistrationFormRef,\n RegistrationFormValues,\n RegistrationFormErrors,\n} from '../types/registration';\nimport { required, email, phone, ukPostcode, compose } from '../utils/validators';\n\n/**\n * Default field configuration for the registration form\n */\nconst DEFAULT_FIELDS: FieldConfig[] = [\n {\n name: 'firstName',\n label: 'First name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'lastName',\n label: 'Last name',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'email',\n label: 'Email address',\n type: 'email',\n required: true,\n validate: compose(required, email),\n },\n {\n name: 'phone',\n label: 'Contact number',\n type: 'tel',\n required: false,\n validate: phone,\n },\n {\n name: 'address1',\n label: 'Address 1',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'address2',\n label: 'Address 2',\n type: 'text',\n required: false,\n },\n {\n name: 'city',\n label: 'Town/City',\n type: 'text',\n required: true,\n validate: required,\n },\n {\n name: 'postcode',\n label: 'Postcode',\n type: 'text',\n required: true,\n validate: compose(required, ukPostcode),\n },\n];\n\n/**\n * A reusable, accessible registration form component.\n * \n * Features:\n * - Customizable fields via props\n * - Built-in validation with blur and submit triggers\n * - Full accessibility support (ARIA attributes, keyboard navigation)\n * - Imperative handle for programmatic control (reset, setValues)\n * - Granular styling via classNames prop\n * \n * @example\n * ```tsx\n * const formRef = useRef<RegistrationFormRef>(null);\n * \n * <RegistrationForm\n * ref={formRef}\n * onSubmit={(values) => console.log(values)}\n * onChange={(values, isValid) => console.log(isValid)}\n * submitLabel=\"Register\"\n * />\n * \n * // Programmatic control\n * formRef.current?.reset();\n * formRef.current?.setValues({ email: 'test@example.com' });\n * ```\n */\nexport const RegistrationForm = forwardRef<RegistrationFormRef, RegistrationFormProps>(\n (\n {\n fields = DEFAULT_FIELDS,\n additionalFields,\n onSubmit,\n onChange,\n validateOnBlur = true,\n submitLabel = 'Submit',\n className = '',\n classNames = {},\n },\n ref\n ) => {\n const formId = useId();\n const [values, setValues] = useState<RegistrationFormValues>({});\n const [errors, setErrors] = useState<RegistrationFormErrors>({});\n const [touched, setTouched] = useState<Record<string, boolean>>({});\n\n // Merge fields with additional fields\n const allFields = additionalFields ? [...fields, ...additionalFields] : fields;\n\n /**\n * Validate a single field\n */\n const validateField = useCallback(\n (field: FieldConfig, value: string): string | null => {\n // Check required first\n if (field.required && (!value || value.trim() === '')) {\n return 'This field is required';\n }\n // Run custom validator if value is present\n if (field.validate && value) {\n return field.validate(value);\n }\n return null;\n },\n []\n );\n\n /**\n * Validate all fields and return whether form is valid\n */\n const validateAll = useCallback((): boolean => {\n const newErrors: RegistrationFormErrors = {};\n let isValid = true;\n\n for (const field of allFields) {\n const value = values[field.name] || '';\n const error = validateField(field, value);\n if (error) {\n newErrors[field.name] = error;\n isValid = false;\n }\n }\n\n setErrors(newErrors);\n return isValid;\n }, [allFields, values, validateField]);\n\n /**\n * Check if current form state is valid (without updating errors)\n */\n const checkIsValid = useCallback(\n (currentValues: RegistrationFormValues): boolean => {\n for (const field of allFields) {\n const value = currentValues[field.name] || '';\n const error = validateField(field, value);\n if (error) return false;\n }\n return true;\n },\n [allFields, validateField]\n );\n\n /**\n * Handle input change\n */\n const handleChange = useCallback(\n (fieldName: string, value: string) => {\n const newValues = { ...values, [fieldName]: value };\n setValues(newValues);\n\n // Clear error if field was touched and is now valid\n if (touched[fieldName]) {\n const field = allFields.find((f) => f.name === fieldName);\n if (field) {\n const error = validateField(field, value);\n if (!error) {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n\n // Call onChange callback\n if (onChange) {\n const isValid = checkIsValid(newValues);\n onChange(newValues, isValid);\n }\n },\n [values, touched, allFields, validateField, onChange, checkIsValid]\n );\n\n /**\n * Handle input blur\n */\n const handleBlur = useCallback(\n (fieldName: string) => {\n setTouched((prev) => ({ ...prev, [fieldName]: true }));\n\n if (validateOnBlur) {\n const field = allFields.find((f) => f.name === fieldName);\n if (field) {\n const value = values[fieldName] || '';\n const error = validateField(field, value);\n if (error) {\n setErrors((prev) => ({ ...prev, [fieldName]: error }));\n } else {\n setErrors((prev) => {\n const next = { ...prev };\n delete next[fieldName];\n return next;\n });\n }\n }\n }\n },\n [validateOnBlur, allFields, values, validateField]\n );\n\n /**\n * Handle form submission\n */\n const handleSubmit = useCallback(\n (e: React.FormEvent) => {\n e.preventDefault();\n\n // Mark all fields as touched\n const allTouched: Record<string, boolean> = {};\n for (const field of allFields) {\n allTouched[field.name] = true;\n }\n setTouched(allTouched);\n\n // Validate all and submit if valid\n if (validateAll()) {\n onSubmit(values);\n }\n },\n [allFields, validateAll, onSubmit, values]\n );\n\n /**\n * Expose imperative methods via ref\n */\n useImperativeHandle(\n ref,\n () => ({\n reset: () => {\n setValues({});\n setErrors({});\n setTouched({});\n },\n setValues: (newValues: Partial<RegistrationFormValues>) => {\n setValues((prev) => {\n const merged = { ...prev };\n for (const [key, value] of Object.entries(newValues)) {\n if (value !== undefined) {\n merged[key] = value;\n }\n }\n return merged;\n });\n },\n }),\n []\n );\n\n // Default styles\n const styles = {\n fieldWrapper: classNames.fieldWrapper || 'mb-4',\n label: classNames.label || 'block text-sm font-medium mb-1',\n input: classNames.input || 'w-full px-3 py-2 border rounded-md',\n inputError: classNames.inputError || 'border-red-500',\n errorText: classNames.errorText || 'mt-1 text-xs text-red-600',\n button:\n classNames.button ||\n 'w-full mt-4 px-4 py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50',\n };\n\n return (\n <form onSubmit={handleSubmit} className={className} noValidate>\n {allFields.map((field) => {\n const fieldId = `${formId}-${field.name}`;\n const errorId = `${fieldId}-error`;\n const value = values[field.name] || '';\n const error = errors[field.name];\n const isTouched = touched[field.name];\n const showError = isTouched && error;\n\n return (\n <div key={field.name} className={styles.fieldWrapper}>\n <label htmlFor={fieldId} className={styles.label}>\n {field.label}\n {field.required && (\n <span className=\"text-red-500 ml-1\" aria-hidden=\"true\">\n *\n </span>\n )}\n </label>\n {field.type === 'select' && field.options ? (\n <select\n id={fieldId}\n name={field.name}\n value={value}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n className={`${styles.input} ${showError ? styles.inputError : ''}`}\n aria-invalid={showError ? 'true' : 'false'}\n aria-describedby={showError ? errorId : undefined}\n aria-required={field.required ? 'true' : 'false'}\n >\n <option value=\"\">{field.placeholder || 'Select an option'}</option>\n {field.options.map((option) => (\n <option key={option.id} value={String(option.id)}>\n {option.name}\n {option.price !== undefined && option.price > 0 ? ` (+£${option.price})` : ''}\n </option>\n ))}\n </select>\n ) : (\n <input\n id={fieldId}\n name={field.name}\n type={field.type === 'select' ? 'text' : field.type}\n value={value}\n onChange={(e) => handleChange(field.name, e.target.value)}\n onBlur={() => handleBlur(field.name)}\n placeholder={field.placeholder}\n className={`${styles.input} ${showError ? styles.inputError : ''}`}\n aria-invalid={showError ? 'true' : 'false'}\n aria-describedby={showError ? errorId : undefined}\n aria-required={field.required ? 'true' : 'false'}\n />\n )}\n {showError && (\n <p id={errorId} className={styles.errorText} role=\"alert\">\n {error}\n </p>\n )}\n </div>\n );\n })}\n <button type=\"submit\" className={styles.button}>\n {submitLabel}\n </button>\n </form>\n );\n }\n);\n\nRegistrationForm.displayName = 'RegistrationForm';\n"]}
|