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
- field: K,
113
- value: T[K]
114
- ): string | undefined => {
115
- const rules = validationRules[field];
116
- if (!rules) return undefined;
117
-
118
- if (rules.required) {
119
- if (
120
- value === '' ||
121
- value === null ||
122
- value === undefined
123
- ) {
124
- return rules.errorMessage || 'This field is required.';
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
- if (rules.pattern && typeof value === 'string') {
129
- if (!rules.pattern.test(value)) {
130
- return rules.errorMessage || 'Invalid format.';
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
- if (rules.minLength && typeof value === 'string') {
135
- if (value.length < rules.minLength) {
136
- return rules.errorMessage || `Minimum length is ${rules.minLength}.`;
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
- if (rules.maxLength && typeof value === 'string') {
141
- if (value.length > rules.maxLength) {
142
- return rules.errorMessage || `Maximum length is ${rules.maxLength}.`;
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
- if (rules.custom && !rules.custom(value)) {
147
- return rules.errorMessage || 'Invalid value.';
148
- }
161
+ // CUSTOM
162
+ if (rules.custom && !rules.custom(value)) {
163
+ return rules.errorMessage || 'Invalid value.';
164
+ }
149
165
 
150
- return undefined;
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
- for (const field in validationRules) {
159
- const value = values[field];
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
- const newErrors: ValidationErrors<T> = {};
174
- let isValid = true;
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
- setErrors(prev => ({ ...prev, ...newErrors }));
186
- return isValid;
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
- const handleChange = <K extends keyof T>(field: K, value: T[K]) => {
191
- setValues(prev => ({ ...prev, [field]: value }));
192
- const error = validateField(field, value);
193
- setErrors(prev => ({ ...prev, [field]: error }));
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
- validateFields
229
+ resetForm,
204
230
  };
205
231
  };
206
232
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kmod-cli",
3
- "version": "1.7.5",
3
+ "version": "1.7.6",
4
4
  "description": "Stack components utilities fast setup in projects",
5
5
  "author": "kumo_d",
6
6
  "license": "MIT",