@bookinglab/booking-ui-react 1.1.0 → 1.3.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 +41 -0
- package/dist/index.d.cts +19 -2
- package/dist/index.d.ts +19 -2
- package/dist/index.js +41 -13
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +41 -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 |
|
|
@@ -207,6 +208,7 @@ A reusable, accessible registration form component with built-in validation, cus
|
|
|
207
208
|
| `firstName` | First name | text | Yes | required |
|
|
208
209
|
| `lastName` | Last name | text | Yes | required |
|
|
209
210
|
| `email` | Email address | email | Yes | required, email format |
|
|
211
|
+
| `password` | Password | password | No | none |
|
|
210
212
|
| `phone` | Contact number | tel | No | phone format (if provided) |
|
|
211
213
|
| `address1` | Address 1 | text | Yes | required |
|
|
212
214
|
| `address2` | Address 2 | text | No | none |
|
|
@@ -238,6 +240,44 @@ const customFields: FieldConfig[] = [
|
|
|
238
240
|
<RegistrationForm fields={customFields} onSubmit={handleSubmit} />
|
|
239
241
|
```
|
|
240
242
|
|
|
243
|
+
### Additional Fields
|
|
244
|
+
|
|
245
|
+
Append extra fields after the defaults using `additionalFields`:
|
|
246
|
+
|
|
247
|
+
```tsx
|
|
248
|
+
import { RegistrationForm, FieldConfig } from '@bookinglab/booking-ui-react';
|
|
249
|
+
|
|
250
|
+
const extraFields: FieldConfig[] = [
|
|
251
|
+
{ name: 'company', label: 'Company Name', type: 'text' },
|
|
252
|
+
{
|
|
253
|
+
name: 'service',
|
|
254
|
+
label: 'Service Type',
|
|
255
|
+
type: 'select',
|
|
256
|
+
required: true,
|
|
257
|
+
options: [
|
|
258
|
+
{ id: 1, name: 'Consultation', price: 0, is_default: true },
|
|
259
|
+
{ id: 2, name: 'Premium Support', price: 50 },
|
|
260
|
+
{ id: 3, name: 'Enterprise', price: 200 },
|
|
261
|
+
],
|
|
262
|
+
},
|
|
263
|
+
];
|
|
264
|
+
|
|
265
|
+
<RegistrationForm additionalFields={extraFields} onSubmit={handleSubmit} />
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
### Select Field Options
|
|
269
|
+
|
|
270
|
+
Select fields accept an `options` array with the following structure:
|
|
271
|
+
|
|
272
|
+
```typescript
|
|
273
|
+
interface FieldOption {
|
|
274
|
+
id: number | string; // Unique identifier (submitted as the value)
|
|
275
|
+
name: string; // Display text
|
|
276
|
+
price?: number; // Optional price modifier (displayed as "+£X")
|
|
277
|
+
is_default?: boolean; // Pre-select this option
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
241
281
|
### Ref Methods
|
|
242
282
|
|
|
243
283
|
Access imperative methods via `ref`:
|
|
@@ -323,6 +363,7 @@ import type {
|
|
|
323
363
|
BookingFormProps,
|
|
324
364
|
BookingFormClassNames,
|
|
325
365
|
FieldConfig,
|
|
366
|
+
FieldOption,
|
|
326
367
|
RegistrationFormProps,
|
|
327
368
|
RegistrationFormRef,
|
|
328
369
|
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' | 'password' | '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' | 'password' | '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
|
@@ -427,6 +427,12 @@ var DEFAULT_FIELDS = [
|
|
|
427
427
|
required: true,
|
|
428
428
|
validate: compose(required, email)
|
|
429
429
|
},
|
|
430
|
+
{
|
|
431
|
+
name: "password",
|
|
432
|
+
label: "Password",
|
|
433
|
+
type: "password",
|
|
434
|
+
required: false
|
|
435
|
+
},
|
|
430
436
|
{
|
|
431
437
|
name: "phone",
|
|
432
438
|
label: "Contact number",
|
|
@@ -465,6 +471,7 @@ var DEFAULT_FIELDS = [
|
|
|
465
471
|
var RegistrationForm = react.forwardRef(
|
|
466
472
|
({
|
|
467
473
|
fields = DEFAULT_FIELDS,
|
|
474
|
+
additionalFields,
|
|
468
475
|
onSubmit,
|
|
469
476
|
onChange,
|
|
470
477
|
validateOnBlur = true,
|
|
@@ -476,6 +483,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
476
483
|
const [values, setValues] = react.useState({});
|
|
477
484
|
const [errors, setErrors] = react.useState({});
|
|
478
485
|
const [touched, setTouched] = react.useState({});
|
|
486
|
+
const allFields = additionalFields ? [...fields, ...additionalFields] : fields;
|
|
479
487
|
const validateField = react.useCallback(
|
|
480
488
|
(field, value) => {
|
|
481
489
|
if (field.required && (!value || value.trim() === "")) {
|
|
@@ -491,7 +499,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
491
499
|
const validateAll = react.useCallback(() => {
|
|
492
500
|
const newErrors = {};
|
|
493
501
|
let isValid = true;
|
|
494
|
-
for (const field of
|
|
502
|
+
for (const field of allFields) {
|
|
495
503
|
const value = values[field.name] || "";
|
|
496
504
|
const error = validateField(field, value);
|
|
497
505
|
if (error) {
|
|
@@ -501,24 +509,24 @@ var RegistrationForm = react.forwardRef(
|
|
|
501
509
|
}
|
|
502
510
|
setErrors(newErrors);
|
|
503
511
|
return isValid;
|
|
504
|
-
}, [
|
|
512
|
+
}, [allFields, values, validateField]);
|
|
505
513
|
const checkIsValid = react.useCallback(
|
|
506
514
|
(currentValues) => {
|
|
507
|
-
for (const field of
|
|
515
|
+
for (const field of allFields) {
|
|
508
516
|
const value = currentValues[field.name] || "";
|
|
509
517
|
const error = validateField(field, value);
|
|
510
518
|
if (error) return false;
|
|
511
519
|
}
|
|
512
520
|
return true;
|
|
513
521
|
},
|
|
514
|
-
[
|
|
522
|
+
[allFields, validateField]
|
|
515
523
|
);
|
|
516
524
|
const handleChange = react.useCallback(
|
|
517
525
|
(fieldName, value) => {
|
|
518
526
|
const newValues = { ...values, [fieldName]: value };
|
|
519
527
|
setValues(newValues);
|
|
520
528
|
if (touched[fieldName]) {
|
|
521
|
-
const field =
|
|
529
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
522
530
|
if (field) {
|
|
523
531
|
const error = validateField(field, value);
|
|
524
532
|
if (!error) {
|
|
@@ -535,13 +543,13 @@ var RegistrationForm = react.forwardRef(
|
|
|
535
543
|
onChange(newValues, isValid);
|
|
536
544
|
}
|
|
537
545
|
},
|
|
538
|
-
[values, touched,
|
|
546
|
+
[values, touched, allFields, validateField, onChange, checkIsValid]
|
|
539
547
|
);
|
|
540
548
|
const handleBlur = react.useCallback(
|
|
541
549
|
(fieldName) => {
|
|
542
550
|
setTouched((prev) => ({ ...prev, [fieldName]: true }));
|
|
543
551
|
if (validateOnBlur) {
|
|
544
|
-
const field =
|
|
552
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
545
553
|
if (field) {
|
|
546
554
|
const value = values[fieldName] || "";
|
|
547
555
|
const error = validateField(field, value);
|
|
@@ -557,13 +565,13 @@ var RegistrationForm = react.forwardRef(
|
|
|
557
565
|
}
|
|
558
566
|
}
|
|
559
567
|
},
|
|
560
|
-
[validateOnBlur,
|
|
568
|
+
[validateOnBlur, allFields, values, validateField]
|
|
561
569
|
);
|
|
562
570
|
const handleSubmit = react.useCallback(
|
|
563
571
|
(e) => {
|
|
564
572
|
e.preventDefault();
|
|
565
573
|
const allTouched = {};
|
|
566
|
-
for (const field of
|
|
574
|
+
for (const field of allFields) {
|
|
567
575
|
allTouched[field.name] = true;
|
|
568
576
|
}
|
|
569
577
|
setTouched(allTouched);
|
|
@@ -571,7 +579,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
571
579
|
onSubmit(values);
|
|
572
580
|
}
|
|
573
581
|
},
|
|
574
|
-
[
|
|
582
|
+
[allFields, validateAll, onSubmit, values]
|
|
575
583
|
);
|
|
576
584
|
react.useImperativeHandle(
|
|
577
585
|
ref,
|
|
@@ -604,7 +612,7 @@ var RegistrationForm = react.forwardRef(
|
|
|
604
612
|
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
613
|
};
|
|
606
614
|
return /* @__PURE__ */ jsxRuntime.jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
607
|
-
|
|
615
|
+
allFields.map((field) => {
|
|
608
616
|
const fieldId = `${formId}-${field.name}`;
|
|
609
617
|
const errorId = `${fieldId}-error`;
|
|
610
618
|
const value = values[field.name] || "";
|
|
@@ -616,12 +624,32 @@ var RegistrationForm = react.forwardRef(
|
|
|
616
624
|
field.label,
|
|
617
625
|
field.required && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
618
626
|
] }),
|
|
619
|
-
/* @__PURE__ */ jsxRuntime.
|
|
627
|
+
field.type === "select" && field.options ? /* @__PURE__ */ jsxRuntime.jsxs(
|
|
628
|
+
"select",
|
|
629
|
+
{
|
|
630
|
+
id: fieldId,
|
|
631
|
+
name: field.name,
|
|
632
|
+
value,
|
|
633
|
+
onChange: (e) => handleChange(field.name, e.target.value),
|
|
634
|
+
onBlur: () => handleBlur(field.name),
|
|
635
|
+
className: `${styles.input} ${showError ? styles.inputError : ""}`,
|
|
636
|
+
"aria-invalid": showError ? "true" : "false",
|
|
637
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
638
|
+
"aria-required": field.required ? "true" : "false",
|
|
639
|
+
children: [
|
|
640
|
+
/* @__PURE__ */ jsxRuntime.jsx("option", { value: "", children: field.placeholder || "Select an option" }),
|
|
641
|
+
field.options.map((option) => /* @__PURE__ */ jsxRuntime.jsxs("option", { value: String(option.id), children: [
|
|
642
|
+
option.name,
|
|
643
|
+
option.price !== void 0 && option.price > 0 ? ` (+\xA3${option.price})` : ""
|
|
644
|
+
] }, option.id))
|
|
645
|
+
]
|
|
646
|
+
}
|
|
647
|
+
) : /* @__PURE__ */ jsxRuntime.jsx(
|
|
620
648
|
"input",
|
|
621
649
|
{
|
|
622
650
|
id: fieldId,
|
|
623
651
|
name: field.name,
|
|
624
|
-
type: field.type,
|
|
652
|
+
type: field.type === "select" ? "text" : field.type,
|
|
625
653
|
value,
|
|
626
654
|
onChange: (e) => handleChange(field.name, e.target.value),
|
|
627
655
|
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: 'password',\n label: 'Password',\n type: 'password',\n required: false,\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
|
@@ -425,6 +425,12 @@ var DEFAULT_FIELDS = [
|
|
|
425
425
|
required: true,
|
|
426
426
|
validate: compose(required, email)
|
|
427
427
|
},
|
|
428
|
+
{
|
|
429
|
+
name: "password",
|
|
430
|
+
label: "Password",
|
|
431
|
+
type: "password",
|
|
432
|
+
required: false
|
|
433
|
+
},
|
|
428
434
|
{
|
|
429
435
|
name: "phone",
|
|
430
436
|
label: "Contact number",
|
|
@@ -463,6 +469,7 @@ var DEFAULT_FIELDS = [
|
|
|
463
469
|
var RegistrationForm = forwardRef(
|
|
464
470
|
({
|
|
465
471
|
fields = DEFAULT_FIELDS,
|
|
472
|
+
additionalFields,
|
|
466
473
|
onSubmit,
|
|
467
474
|
onChange,
|
|
468
475
|
validateOnBlur = true,
|
|
@@ -474,6 +481,7 @@ var RegistrationForm = forwardRef(
|
|
|
474
481
|
const [values, setValues] = useState({});
|
|
475
482
|
const [errors, setErrors] = useState({});
|
|
476
483
|
const [touched, setTouched] = useState({});
|
|
484
|
+
const allFields = additionalFields ? [...fields, ...additionalFields] : fields;
|
|
477
485
|
const validateField = useCallback(
|
|
478
486
|
(field, value) => {
|
|
479
487
|
if (field.required && (!value || value.trim() === "")) {
|
|
@@ -489,7 +497,7 @@ var RegistrationForm = forwardRef(
|
|
|
489
497
|
const validateAll = useCallback(() => {
|
|
490
498
|
const newErrors = {};
|
|
491
499
|
let isValid = true;
|
|
492
|
-
for (const field of
|
|
500
|
+
for (const field of allFields) {
|
|
493
501
|
const value = values[field.name] || "";
|
|
494
502
|
const error = validateField(field, value);
|
|
495
503
|
if (error) {
|
|
@@ -499,24 +507,24 @@ var RegistrationForm = forwardRef(
|
|
|
499
507
|
}
|
|
500
508
|
setErrors(newErrors);
|
|
501
509
|
return isValid;
|
|
502
|
-
}, [
|
|
510
|
+
}, [allFields, values, validateField]);
|
|
503
511
|
const checkIsValid = useCallback(
|
|
504
512
|
(currentValues) => {
|
|
505
|
-
for (const field of
|
|
513
|
+
for (const field of allFields) {
|
|
506
514
|
const value = currentValues[field.name] || "";
|
|
507
515
|
const error = validateField(field, value);
|
|
508
516
|
if (error) return false;
|
|
509
517
|
}
|
|
510
518
|
return true;
|
|
511
519
|
},
|
|
512
|
-
[
|
|
520
|
+
[allFields, validateField]
|
|
513
521
|
);
|
|
514
522
|
const handleChange = useCallback(
|
|
515
523
|
(fieldName, value) => {
|
|
516
524
|
const newValues = { ...values, [fieldName]: value };
|
|
517
525
|
setValues(newValues);
|
|
518
526
|
if (touched[fieldName]) {
|
|
519
|
-
const field =
|
|
527
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
520
528
|
if (field) {
|
|
521
529
|
const error = validateField(field, value);
|
|
522
530
|
if (!error) {
|
|
@@ -533,13 +541,13 @@ var RegistrationForm = forwardRef(
|
|
|
533
541
|
onChange(newValues, isValid);
|
|
534
542
|
}
|
|
535
543
|
},
|
|
536
|
-
[values, touched,
|
|
544
|
+
[values, touched, allFields, validateField, onChange, checkIsValid]
|
|
537
545
|
);
|
|
538
546
|
const handleBlur = useCallback(
|
|
539
547
|
(fieldName) => {
|
|
540
548
|
setTouched((prev) => ({ ...prev, [fieldName]: true }));
|
|
541
549
|
if (validateOnBlur) {
|
|
542
|
-
const field =
|
|
550
|
+
const field = allFields.find((f) => f.name === fieldName);
|
|
543
551
|
if (field) {
|
|
544
552
|
const value = values[fieldName] || "";
|
|
545
553
|
const error = validateField(field, value);
|
|
@@ -555,13 +563,13 @@ var RegistrationForm = forwardRef(
|
|
|
555
563
|
}
|
|
556
564
|
}
|
|
557
565
|
},
|
|
558
|
-
[validateOnBlur,
|
|
566
|
+
[validateOnBlur, allFields, values, validateField]
|
|
559
567
|
);
|
|
560
568
|
const handleSubmit = useCallback(
|
|
561
569
|
(e) => {
|
|
562
570
|
e.preventDefault();
|
|
563
571
|
const allTouched = {};
|
|
564
|
-
for (const field of
|
|
572
|
+
for (const field of allFields) {
|
|
565
573
|
allTouched[field.name] = true;
|
|
566
574
|
}
|
|
567
575
|
setTouched(allTouched);
|
|
@@ -569,7 +577,7 @@ var RegistrationForm = forwardRef(
|
|
|
569
577
|
onSubmit(values);
|
|
570
578
|
}
|
|
571
579
|
},
|
|
572
|
-
[
|
|
580
|
+
[allFields, validateAll, onSubmit, values]
|
|
573
581
|
);
|
|
574
582
|
useImperativeHandle(
|
|
575
583
|
ref,
|
|
@@ -602,7 +610,7 @@ var RegistrationForm = forwardRef(
|
|
|
602
610
|
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
611
|
};
|
|
604
612
|
return /* @__PURE__ */ jsxs("form", { onSubmit: handleSubmit, className, noValidate: true, children: [
|
|
605
|
-
|
|
613
|
+
allFields.map((field) => {
|
|
606
614
|
const fieldId = `${formId}-${field.name}`;
|
|
607
615
|
const errorId = `${fieldId}-error`;
|
|
608
616
|
const value = values[field.name] || "";
|
|
@@ -614,12 +622,32 @@ var RegistrationForm = forwardRef(
|
|
|
614
622
|
field.label,
|
|
615
623
|
field.required && /* @__PURE__ */ jsx("span", { className: "text-red-500 ml-1", "aria-hidden": "true", children: "*" })
|
|
616
624
|
] }),
|
|
617
|
-
/* @__PURE__ */
|
|
625
|
+
field.type === "select" && field.options ? /* @__PURE__ */ jsxs(
|
|
626
|
+
"select",
|
|
627
|
+
{
|
|
628
|
+
id: fieldId,
|
|
629
|
+
name: field.name,
|
|
630
|
+
value,
|
|
631
|
+
onChange: (e) => handleChange(field.name, e.target.value),
|
|
632
|
+
onBlur: () => handleBlur(field.name),
|
|
633
|
+
className: `${styles.input} ${showError ? styles.inputError : ""}`,
|
|
634
|
+
"aria-invalid": showError ? "true" : "false",
|
|
635
|
+
"aria-describedby": showError ? errorId : void 0,
|
|
636
|
+
"aria-required": field.required ? "true" : "false",
|
|
637
|
+
children: [
|
|
638
|
+
/* @__PURE__ */ jsx("option", { value: "", children: field.placeholder || "Select an option" }),
|
|
639
|
+
field.options.map((option) => /* @__PURE__ */ jsxs("option", { value: String(option.id), children: [
|
|
640
|
+
option.name,
|
|
641
|
+
option.price !== void 0 && option.price > 0 ? ` (+\xA3${option.price})` : ""
|
|
642
|
+
] }, option.id))
|
|
643
|
+
]
|
|
644
|
+
}
|
|
645
|
+
) : /* @__PURE__ */ jsx(
|
|
618
646
|
"input",
|
|
619
647
|
{
|
|
620
648
|
id: fieldId,
|
|
621
649
|
name: field.name,
|
|
622
|
-
type: field.type,
|
|
650
|
+
type: field.type === "select" ? "text" : field.type,
|
|
623
651
|
value,
|
|
624
652
|
onChange: (e) => handleChange(field.name, e.target.value),
|
|
625
653
|
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: 'password',\n label: 'Password',\n type: 'password',\n required: false,\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"]}
|