kmod-cli 1.7.5 → 1.7.6
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.
|
@@ -100,6 +100,7 @@ export type ValidationRules<T> = Partial<{
|
|
|
100
100
|
type ValidationErrors<T> = {
|
|
101
101
|
[K in keyof T]?: string;
|
|
102
102
|
};
|
|
103
|
+
type Touched<T> = Partial<Record<keyof T, boolean>>;
|
|
103
104
|
|
|
104
105
|
export const useFormValidator = <T extends Record<string, any>>(
|
|
105
106
|
initialValues: T,
|
|
@@ -107,100 +108,125 @@ export const useFormValidator = <T extends Record<string, any>>(
|
|
|
107
108
|
) => {
|
|
108
109
|
const [values, setValues] = useState<T>(initialValues);
|
|
109
110
|
const [errors, setErrors] = useState<ValidationErrors<T>>({});
|
|
111
|
+
const [touched, setTouched] = useState<Touched<T>>({});
|
|
112
|
+
|
|
110
113
|
|
|
111
114
|
const validateField = <K extends keyof T>(
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
115
|
+
field: K,
|
|
116
|
+
value: T[K],
|
|
117
|
+
isTouched = false,
|
|
118
|
+
isSubmit = false
|
|
119
|
+
): string | undefined => {
|
|
120
|
+
const rules = validationRules[field];
|
|
121
|
+
if (!rules) return;
|
|
122
|
+
|
|
123
|
+
// Not touched & not submit → no validate
|
|
124
|
+
if (!isTouched && !isSubmit) return;
|
|
125
|
+
|
|
126
|
+
// Not submit & value equals initial → no error
|
|
127
|
+
if (!isSubmit && value === initialValues[field]) return;
|
|
128
|
+
|
|
129
|
+
// REQUIRED
|
|
130
|
+
if (rules.required) {
|
|
131
|
+
if (
|
|
132
|
+
value === '' ||
|
|
133
|
+
value === null ||
|
|
134
|
+
value === undefined
|
|
135
|
+
) {
|
|
136
|
+
return rules.errorMessage || 'This field is required.';
|
|
137
|
+
}
|
|
125
138
|
}
|
|
126
|
-
}
|
|
127
139
|
|
|
128
|
-
|
|
129
|
-
if (
|
|
130
|
-
|
|
140
|
+
// PATTERN
|
|
141
|
+
if (rules.pattern && typeof value === 'string' && value !== '') {
|
|
142
|
+
if (!rules.pattern.test(value)) {
|
|
143
|
+
return rules.errorMessage || 'Invalid format.';
|
|
144
|
+
}
|
|
131
145
|
}
|
|
132
|
-
}
|
|
133
146
|
|
|
134
|
-
|
|
135
|
-
if (
|
|
136
|
-
|
|
147
|
+
// MIN LENGTH
|
|
148
|
+
if (rules.minLength && typeof value === 'string' && value !== '') {
|
|
149
|
+
if (value.length < rules.minLength) {
|
|
150
|
+
return rules.errorMessage || `Minimum length is ${rules.minLength}.`;
|
|
151
|
+
}
|
|
137
152
|
}
|
|
138
|
-
}
|
|
139
153
|
|
|
140
|
-
|
|
141
|
-
if (
|
|
142
|
-
|
|
154
|
+
// MAX LENGTH
|
|
155
|
+
if (rules.maxLength && typeof value === 'string' && value !== '') {
|
|
156
|
+
if (value.length > rules.maxLength) {
|
|
157
|
+
return rules.errorMessage || `Maximum length is ${rules.maxLength}.`;
|
|
158
|
+
}
|
|
143
159
|
}
|
|
144
|
-
}
|
|
145
160
|
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
161
|
+
// CUSTOM
|
|
162
|
+
if (rules.custom && !rules.custom(value)) {
|
|
163
|
+
return rules.errorMessage || 'Invalid value.';
|
|
164
|
+
}
|
|
149
165
|
|
|
150
|
-
|
|
151
|
-
};
|
|
166
|
+
return;
|
|
167
|
+
};
|
|
152
168
|
|
|
153
169
|
|
|
154
170
|
const validateAllFields = (): boolean => {
|
|
155
|
-
const newErrors: ValidationErrors<T> = {};
|
|
156
171
|
let isValid = true;
|
|
172
|
+
const newErrors: ValidationErrors<T> = {};
|
|
157
173
|
|
|
158
|
-
|
|
159
|
-
const
|
|
160
|
-
const error = validateField(field, value);
|
|
174
|
+
(Object.keys(validationRules) as (keyof T)[]).forEach((field) => {
|
|
175
|
+
const error = validateField(field, values[field], true, true);
|
|
161
176
|
if (error) {
|
|
162
177
|
isValid = false;
|
|
163
178
|
newErrors[field] = error;
|
|
164
179
|
}
|
|
165
|
-
}
|
|
180
|
+
});
|
|
166
181
|
|
|
167
182
|
setErrors(newErrors);
|
|
168
183
|
return isValid;
|
|
169
184
|
};
|
|
170
185
|
|
|
186
|
+
|
|
171
187
|
// validate array of fields
|
|
172
188
|
const validateFields = (fields: readonly (keyof T)[]): boolean => {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
for (const field of fields) {
|
|
177
|
-
const value = values[field];
|
|
178
|
-
const error = validateField(field, value);
|
|
179
|
-
if (error) {
|
|
180
|
-
isValid = false;
|
|
181
|
-
newErrors[field] = error;
|
|
182
|
-
}
|
|
183
|
-
}
|
|
189
|
+
let isValid = true;
|
|
190
|
+
const newErrors: ValidationErrors<T> = {};
|
|
184
191
|
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
192
|
+
fields.forEach((field) => {
|
|
193
|
+
const error = validateField(field, values[field], true, true);
|
|
194
|
+
if (error) {
|
|
195
|
+
isValid = false;
|
|
196
|
+
newErrors[field] = error;
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
setErrors((prev) => ({ ...prev, ...newErrors }));
|
|
201
|
+
return isValid;
|
|
202
|
+
};
|
|
188
203
|
|
|
189
204
|
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
205
|
+
|
|
206
|
+
const handleChange = <K extends keyof T>(field: K, value: T[K]) => {
|
|
207
|
+
setValues((prev) => ({ ...prev, [field]: value }));
|
|
208
|
+
setTouched((prev) => ({ ...prev, [field]: true }));
|
|
209
|
+
|
|
210
|
+
const error = validateField(field, value, true, false);
|
|
211
|
+
setErrors((prev) => ({ ...prev, [field]: error }));
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const resetForm = (nextValues: T = initialValues) => {
|
|
215
|
+
setValues(nextValues);
|
|
216
|
+
setErrors({});
|
|
217
|
+
setTouched({});
|
|
218
|
+
};
|
|
195
219
|
|
|
196
220
|
|
|
197
221
|
return {
|
|
198
222
|
values,
|
|
199
223
|
errors,
|
|
224
|
+
touched,
|
|
200
225
|
handleChange,
|
|
226
|
+
validateFields,
|
|
201
227
|
validateAllFields,
|
|
202
228
|
setValues,
|
|
203
|
-
|
|
229
|
+
resetForm,
|
|
204
230
|
};
|
|
205
231
|
};
|
|
206
232
|
|