kmod-cli 1.7.1 → 1.7.3
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
|
@@ -38,69 +38,70 @@ npx kumod add --all # add all component
|
|
|
38
38
|
npx kumod add button # add button component
|
|
39
39
|
#...any other command
|
|
40
40
|
```
|
|
41
|
-
## Components
|
|
42
|
-
|
|
43
|
-
- access-denied
|
|
44
|
-
- api-service
|
|
45
|
-
- breadcumb
|
|
46
|
-
- button
|
|
47
|
-
- calculate
|
|
48
|
-
- calendar
|
|
49
|
-
- color-by-text
|
|
50
|
-
- column-table
|
|
51
|
-
- config
|
|
52
|
-
- count-down
|
|
53
|
-
- count-input
|
|
54
|
-
- data-table
|
|
55
|
-
- date-input
|
|
56
|
-
- date-range-picker
|
|
57
|
-
- datetime-picker
|
|
58
|
-
- fade-on-scroll
|
|
59
|
-
- feature-config
|
|
60
|
-
- feature-guard
|
|
61
|
-
- gradient-outline
|
|
62
|
-
- gradient-svg
|
|
63
|
-
- grid-layout
|
|
64
|
-
- hash-aes
|
|
65
|
-
- hydrate-guard
|
|
66
|
-
- idb
|
|
67
|
-
- image
|
|
68
|
-
- input
|
|
69
|
-
- keys
|
|
70
|
-
- kookies
|
|
71
|
-
- label
|
|
72
|
-
- lib
|
|
73
|
-
- list-map
|
|
74
|
-
- loader-slash-gradient
|
|
75
|
-
- masonry-gallery
|
|
76
|
-
- modal
|
|
77
|
-
- multi-select
|
|
78
|
-
- non-hydration
|
|
79
|
-
- period-input
|
|
80
|
-
- popover
|
|
81
|
-
- portal
|
|
82
|
-
- query
|
|
83
|
-
- rbac
|
|
84
|
-
- readme
|
|
85
|
-
- refine-provider
|
|
86
|
-
- safe-action
|
|
87
|
-
- segments-circle
|
|
88
|
-
- select
|
|
89
|
-
- simple-validate
|
|
90
|
-
- single-select
|
|
91
|
-
- spam-guard
|
|
92
|
-
- storage
|
|
93
|
-
- stripe-effect
|
|
94
|
-
- stroke-circle
|
|
95
|
-
- switch
|
|
96
|
-
- table
|
|
97
|
-
- text-hover-effect
|
|
98
|
-
- time-picker
|
|
99
|
-
- time-picker-input
|
|
100
|
-
- time-picker-utils
|
|
101
|
-
- timout-loader
|
|
102
|
-
- toast
|
|
103
|
-
- utils
|
|
41
|
+
## Components
|
|
42
|
+
|
|
43
|
+
- access-denied
|
|
44
|
+
- api-service
|
|
45
|
+
- breadcumb
|
|
46
|
+
- button
|
|
47
|
+
- calculate
|
|
48
|
+
- calendar
|
|
49
|
+
- color-by-text
|
|
50
|
+
- column-table
|
|
51
|
+
- config
|
|
52
|
+
- count-down
|
|
53
|
+
- count-input
|
|
54
|
+
- data-table
|
|
55
|
+
- date-input
|
|
56
|
+
- date-range-picker
|
|
57
|
+
- datetime-picker
|
|
58
|
+
- fade-on-scroll
|
|
59
|
+
- feature-config
|
|
60
|
+
- feature-guard
|
|
61
|
+
- gradient-outline
|
|
62
|
+
- gradient-svg
|
|
63
|
+
- grid-layout
|
|
64
|
+
- hash-aes
|
|
65
|
+
- hydrate-guard
|
|
66
|
+
- idb
|
|
67
|
+
- image
|
|
68
|
+
- input
|
|
69
|
+
- keys
|
|
70
|
+
- kookies
|
|
71
|
+
- label
|
|
72
|
+
- lib
|
|
73
|
+
- list-map
|
|
74
|
+
- loader-slash-gradient
|
|
75
|
+
- masonry-gallery
|
|
76
|
+
- modal
|
|
77
|
+
- multi-select
|
|
78
|
+
- non-hydration
|
|
79
|
+
- period-input
|
|
80
|
+
- popover
|
|
81
|
+
- portal
|
|
82
|
+
- query
|
|
83
|
+
- rbac
|
|
84
|
+
- readme
|
|
85
|
+
- refine-provider
|
|
86
|
+
- safe-action
|
|
87
|
+
- segments-circle
|
|
88
|
+
- select
|
|
89
|
+
- simple-validate
|
|
90
|
+
- single-select
|
|
91
|
+
- spam-guard
|
|
92
|
+
- storage
|
|
93
|
+
- stripe-effect
|
|
94
|
+
- stroke-circle
|
|
95
|
+
- switch
|
|
96
|
+
- table
|
|
97
|
+
- text-hover-effect
|
|
98
|
+
- time-picker
|
|
99
|
+
- time-picker-input
|
|
100
|
+
- time-picker-utils
|
|
101
|
+
- timout-loader
|
|
102
|
+
- toast
|
|
103
|
+
- utils
|
|
104
|
+
|
|
104
105
|
## Contributing
|
|
105
106
|
|
|
106
107
|
Contributions are welcome! Please open issues or pull requests.
|
|
@@ -67,7 +67,7 @@ export const REGEXS = {
|
|
|
67
67
|
*/
|
|
68
68
|
text: /^[a-zA-ZÀ-ỹ0-9\s]+$/,
|
|
69
69
|
/**
|
|
70
|
-
* /^[a-zA-
|
|
70
|
+
* /^[a-zA-ZÀ-ỹ0-9\s.,#\/-]+$/
|
|
71
71
|
* @example "123 Main St, Anytown, USA"
|
|
72
72
|
*/
|
|
73
73
|
address: /^[a-zA-ZÀ-ỹ0-9\s.,#\/-]+$/,
|
|
@@ -83,18 +83,19 @@ export const REGEXS = {
|
|
|
83
83
|
uuid: /[0-9a-fA-F]{8}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{4}\-[0-9a-fA-F]{12}/,
|
|
84
84
|
}
|
|
85
85
|
|
|
86
|
-
interface ValidationRule {
|
|
86
|
+
export interface ValidationRule<V = unknown> {
|
|
87
87
|
required?: boolean;
|
|
88
88
|
pattern?: RegExp;
|
|
89
|
-
custom?: (value: string) => boolean;
|
|
90
89
|
minLength?: number;
|
|
91
90
|
maxLength?: number;
|
|
92
91
|
errorMessage?: string;
|
|
92
|
+
custom?: (value: V) => boolean;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
export type ValidationRules<T> = {
|
|
96
|
-
[K in keyof T]: ValidationRule
|
|
97
|
-
}
|
|
95
|
+
export type ValidationRules<T> = Partial<{
|
|
96
|
+
[K in keyof T]: ValidationRule<T[K]>;
|
|
97
|
+
}>;
|
|
98
|
+
|
|
98
99
|
|
|
99
100
|
type ValidationErrors<T> = {
|
|
100
101
|
[K in keyof T]?: string;
|
|
@@ -107,32 +108,48 @@ export const useFormValidator = <T extends Record<string, any>>(
|
|
|
107
108
|
const [values, setValues] = useState<T>(initialValues);
|
|
108
109
|
const [errors, setErrors] = useState<ValidationErrors<T>>({});
|
|
109
110
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
111
|
+
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.';
|
|
116
125
|
}
|
|
126
|
+
}
|
|
117
127
|
|
|
118
|
-
|
|
119
|
-
|
|
128
|
+
if (rules.pattern && typeof value === 'string') {
|
|
129
|
+
if (!rules.pattern.test(value)) {
|
|
130
|
+
return rules.errorMessage || 'Invalid format.';
|
|
120
131
|
}
|
|
132
|
+
}
|
|
121
133
|
|
|
122
|
-
|
|
134
|
+
if (rules.minLength && typeof value === 'string') {
|
|
135
|
+
if (value.length < rules.minLength) {
|
|
123
136
|
return rules.errorMessage || `Minimum length is ${rules.minLength}.`;
|
|
124
137
|
}
|
|
138
|
+
}
|
|
125
139
|
|
|
126
|
-
|
|
140
|
+
if (rules.maxLength && typeof value === 'string') {
|
|
141
|
+
if (value.length > rules.maxLength) {
|
|
127
142
|
return rules.errorMessage || `Maximum length is ${rules.maxLength}.`;
|
|
128
143
|
}
|
|
144
|
+
}
|
|
129
145
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
146
|
+
if (rules.custom && !rules.custom(value)) {
|
|
147
|
+
return rules.errorMessage || 'Invalid value.';
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return undefined;
|
|
151
|
+
};
|
|
133
152
|
|
|
134
|
-
return undefined;
|
|
135
|
-
};
|
|
136
153
|
|
|
137
154
|
const validateAllFields = (): boolean => {
|
|
138
155
|
const newErrors: ValidationErrors<T> = {};
|
|
@@ -152,62 +169,37 @@ export const useFormValidator = <T extends Record<string, any>>(
|
|
|
152
169
|
};
|
|
153
170
|
|
|
154
171
|
// validate array of fields
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
172
|
+
const validateFields = (fields: readonly (keyof T)[]): boolean => {
|
|
173
|
+
const newErrors: ValidationErrors<T> = {};
|
|
174
|
+
let isValid = true;
|
|
158
175
|
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
}
|
|
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;
|
|
166
182
|
}
|
|
183
|
+
}
|
|
167
184
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
185
|
+
setErrors(prev => ({ ...prev, ...newErrors }));
|
|
186
|
+
return isValid;
|
|
187
|
+
};
|
|
188
|
+
|
|
189
|
+
|
|
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
|
+
};
|
|
171
195
|
|
|
172
|
-
const handleChange = <K extends keyof T>(field: K, value: T[K]) => {
|
|
173
|
-
setValues({...values, [field]: value});
|
|
174
|
-
const error = validateField(field, value);
|
|
175
|
-
setErrors({...errors, [field]: error});
|
|
176
|
-
};
|
|
177
196
|
|
|
178
197
|
return {
|
|
179
|
-
/**
|
|
180
|
-
* Form values
|
|
181
|
-
* - ex: values.email
|
|
182
|
-
*/
|
|
183
198
|
values,
|
|
184
|
-
/**
|
|
185
|
-
* Form errors
|
|
186
|
-
* - ex: errors.email
|
|
187
|
-
*/
|
|
188
199
|
errors,
|
|
189
|
-
/**
|
|
190
|
-
* Update the form values
|
|
191
|
-
* - ex: handleChange('email', 'a@example.com')
|
|
192
|
-
*/
|
|
193
200
|
handleChange,
|
|
194
|
-
/**
|
|
195
|
-
* Validate all form fields
|
|
196
|
-
* - ex: validateAllFields()
|
|
197
|
-
* @returns boolean
|
|
198
|
-
*/
|
|
199
201
|
validateAllFields,
|
|
200
|
-
/**
|
|
201
|
-
* Update entire the form values
|
|
202
|
-
* @param newValues
|
|
203
|
-
* - ex: setValues({ email: 'a@example.com', password: '123456' })
|
|
204
|
-
*/
|
|
205
202
|
setValues,
|
|
206
|
-
/**
|
|
207
|
-
* Validate array of fields
|
|
208
|
-
* - ex: validateFields(['email', 'password'])
|
|
209
|
-
* @returns boolean
|
|
210
|
-
*/
|
|
211
203
|
validateFields
|
|
212
204
|
};
|
|
213
205
|
};
|
|
@@ -231,4 +223,5 @@ export const useFormValidator = <T extends Record<string, any>>(
|
|
|
231
223
|
// if (validateAllFields()) {
|
|
232
224
|
// // proceed with form submission
|
|
233
225
|
// }
|
|
234
|
-
// };
|
|
226
|
+
// };
|
|
227
|
+
|