bonsaif-ui 0.1.19 → 0.1.20

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 CHANGED
@@ -32,12 +32,110 @@ The package includes reusable components migrated from `prime-auth` and new shar
32
32
 
33
33
  ### Forms
34
34
 
35
- - `InputField`, `TextInput`, `Textarea`: text inputs with Bonsaif styling.
35
+ - `InputField`, `EmailField`, `PhoneField`, `NumberField`, `TextInput`, `Textarea`: inputs with Bonsaif styling and inline validation for email and phone values.
36
36
  - `SearchableSelect`, `CompactFilterSelect`, `CompactSearchInput`: select and filter controls.
37
37
  - `CalendarPicker`, `DateRangePicker`: single-date and range selection.
38
38
  - `Checkbox`, `RadioGroup`, `Toggle`: boolean and option controls.
39
39
  - `FormField`: label, helper, error, and required wrapper for custom controls.
40
40
 
41
+ #### Form Validation
42
+
43
+ Use `validateForm` with reusable validators to validate complete forms before saving. Validators run in order and return the first error per field. Add `noValidate` to the form to avoid native browser validation, then pass each error to the field with `errorDisplay="tooltip"` when the message should appear in the compact validation tooltip.
44
+
45
+ ```tsx
46
+ import { useMemo, useState, type FormEvent } from "react";
47
+ import {
48
+ EmailField,
49
+ PhoneField,
50
+ emailFormat,
51
+ maxValue,
52
+ minLength,
53
+ minValue,
54
+ phoneFormat,
55
+ required,
56
+ validateForm,
57
+ type ValidationSchema,
58
+ } from "bonsaif-ui";
59
+
60
+ type AccountForm = {
61
+ contactName: string;
62
+ contactEmail: string;
63
+ contactCountryCode: string;
64
+ contactPhone: string;
65
+ seats: string;
66
+ discountCode: string;
67
+ };
68
+
69
+ const schema = {
70
+ contactName: [required("Escribe el nombre."), minLength(3)],
71
+ contactEmail: [required(), emailFormat()],
72
+ contactCountryCode: [required()],
73
+ contactPhone: (value, values) =>
74
+ phoneFormat()(`${values.contactCountryCode} ${value}`),
75
+ seats: [required(), minValue(1), maxValue(500)],
76
+ discountCode: (value, values) =>
77
+ Number(values.seats) > 100 && String(value).trim() === ""
78
+ ? "Solicita un codigo para cuentas de mas de 100 usuarios."
79
+ : undefined,
80
+ } satisfies ValidationSchema<AccountForm>;
81
+
82
+ function AccountFormExample() {
83
+ const [form, setForm] = useState<AccountForm>({
84
+ contactName: "",
85
+ contactEmail: "",
86
+ contactCountryCode: "+1",
87
+ contactPhone: "",
88
+ seats: "",
89
+ discountCode: "",
90
+ });
91
+ const validationResult = useMemo(
92
+ () => validateForm(form, schema),
93
+ [form],
94
+ );
95
+ const errors = validationResult.errors;
96
+
97
+ function submitForm(event: FormEvent<HTMLFormElement>) {
98
+ event.preventDefault();
99
+ if (!validationResult.valid) return;
100
+
101
+ saveAccount(form);
102
+ }
103
+
104
+ return (
105
+ <form noValidate onSubmit={submitForm}>
106
+ <EmailField
107
+ label="Correo"
108
+ value={form.contactEmail}
109
+ error={errors.contactEmail}
110
+ validate={false}
111
+ errorDisplay="tooltip"
112
+ />
113
+ <PhoneField
114
+ label="Telefono"
115
+ countryCode={form.contactCountryCode}
116
+ onCountryCodeChange={(countryCode) =>
117
+ setForm((current) => ({ ...current, contactCountryCode: countryCode }))
118
+ }
119
+ allowedCountryCodes={["+1", "+34", "+52", "+57", "+58"]}
120
+ value={form.contactPhone}
121
+ onChange={(event) =>
122
+ setForm((current) => ({
123
+ ...current,
124
+ contactPhone: event.currentTarget.value,
125
+ }))
126
+ }
127
+ error={errors.contactPhone}
128
+ validate={false}
129
+ errorDisplay="tooltip"
130
+ />
131
+ <button type="submit" disabled={!validationResult.valid}>
132
+ Guardar
133
+ </button>
134
+ </form>
135
+ );
136
+ }
137
+ ```
138
+
41
139
  ### Actions And Overlays
42
140
 
43
141
  - `Button`, `BonsaifButton`: action buttons.