pdyform 2.1.0 → 2.2.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.
@@ -20,13 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
- applyFieldBlur: () => applyFieldBlur,
24
- applyFieldChange: () => applyFieldChange,
25
- createFormRuntimeState: () => createFormRuntimeState,
23
+ createFormStore: () => createFormStore,
24
+ defaultErrorMessages: () => defaultErrorMessages,
25
+ get: () => get,
26
26
  getDefaultValues: () => getDefaultValues,
27
27
  normalizeFieldValue: () => normalizeFieldValue,
28
- runSubmitValidation: () => runSubmitValidation,
29
- setSubmitting: () => setSubmitting,
28
+ set: () => set,
30
29
  validateField: () => validateField,
31
30
  validateFieldByName: () => validateFieldByName,
32
31
  validateForm: () => validateForm
@@ -40,85 +39,138 @@ function parseNumberish(value) {
40
39
  const parsed = Number(value);
41
40
  return Number.isNaN(parsed) ? null : parsed;
42
41
  }
42
+ var defaultErrorMessages = {
43
+ required: "{label} is required",
44
+ min: "{label} must be at least {value}",
45
+ max: "{label} must be at most {value}",
46
+ email: "Invalid email address",
47
+ pattern: "Invalid format",
48
+ custom: "Invalid value"
49
+ };
50
+ function formatMessage(template, field, rule) {
51
+ return template.replace("{label}", field.label).replace("{value}", String(rule.value || ""));
52
+ }
53
+ function get(obj, path, defaultValue) {
54
+ if (!path) return defaultValue;
55
+ const keys = path.split(/[.[\]]/).filter(Boolean);
56
+ let result = obj;
57
+ for (const key of keys) {
58
+ if (result === null || result === void 0) return defaultValue;
59
+ result = result[key];
60
+ }
61
+ return result === void 0 ? defaultValue : result;
62
+ }
63
+ function set(obj, path, value) {
64
+ if (Object(obj) !== obj) return obj;
65
+ const keys = path.split(/[.[\]]/).filter(Boolean);
66
+ const newObj = { ...obj };
67
+ let current = newObj;
68
+ for (let i = 0; i < keys.length - 1; i++) {
69
+ const key = keys[i];
70
+ const nextKey = keys[i + 1];
71
+ const isNextKeyIndex = /^\d+$/.test(nextKey);
72
+ if (!(key in current) || current[key] === null || typeof current[key] !== "object") {
73
+ current[key] = isNextKeyIndex ? [] : {};
74
+ } else {
75
+ current[key] = Array.isArray(current[key]) ? [...current[key]] : { ...current[key] };
76
+ }
77
+ current = current[key];
78
+ }
79
+ current[keys[keys.length - 1]] = value;
80
+ return newObj;
81
+ }
43
82
  function normalizeFieldValue(field, value) {
44
83
  if (field.type !== "number") return value;
45
84
  if (value === "" || value === void 0 || value === null) return "";
46
85
  const numericValue = parseNumberish(value);
47
86
  return numericValue === null ? value : numericValue;
48
87
  }
49
- function validateField(value, field) {
88
+ async function validateField(value, field, customMessages) {
50
89
  if (!field.validations) return null;
90
+ const messages = { ...defaultErrorMessages, ...customMessages };
51
91
  for (const rule of field.validations) {
52
92
  switch (rule.type) {
53
93
  case "required":
54
94
  if (value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0) {
55
- return rule.message || `${field.label} is required`;
95
+ return rule.message || formatMessage(messages.required, field, rule);
56
96
  }
57
97
  break;
58
98
  case "min":
59
99
  if (field.type === "number") {
60
100
  const numericValue = parseNumberish(value);
61
101
  if (numericValue !== null && numericValue < rule.value) {
62
- return rule.message || `${field.label} must be at least ${rule.value}`;
102
+ const template = field.type === "number" ? messages.min : typeof value === "string" ? "{label} must be at least {value} characters" : messages.min;
103
+ return rule.message || formatMessage(template, field, rule);
63
104
  }
64
105
  break;
65
106
  }
66
107
  if (typeof value === "number" && value < rule.value) {
67
- return rule.message || `${field.label} must be at least ${rule.value}`;
108
+ return rule.message || formatMessage(messages.min, field, rule);
68
109
  }
69
110
  if (typeof value === "string" && value.length < rule.value) {
70
- return rule.message || `${field.label} must be at least ${rule.value} characters`;
111
+ const template = "{label} must be at least {value} characters";
112
+ return rule.message || formatMessage(template, field, rule);
71
113
  }
72
114
  break;
73
115
  case "max":
74
116
  if (field.type === "number") {
75
117
  const numericValue = parseNumberish(value);
76
118
  if (numericValue !== null && numericValue > rule.value) {
77
- return rule.message || `${field.label} must be at most ${rule.value}`;
119
+ return rule.message || formatMessage(messages.max, field, rule);
78
120
  }
79
121
  break;
80
122
  }
81
123
  if (typeof value === "number" && value > rule.value) {
82
- return rule.message || `${field.label} must be at most ${rule.value}`;
124
+ return rule.message || formatMessage(messages.max, field, rule);
83
125
  }
84
126
  if (typeof value === "string" && value.length > rule.value) {
85
- return rule.message || `${field.label} must be at most ${rule.value} characters`;
127
+ const template = "{label} must be at most {value} characters";
128
+ return rule.message || formatMessage(template, field, rule);
86
129
  }
87
130
  break;
88
131
  case "email": {
89
132
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
90
133
  if (value && !emailRegex.test(value)) {
91
- return rule.message || "Invalid email address";
134
+ return rule.message || formatMessage(messages.email, field, rule);
92
135
  }
93
136
  break;
94
137
  }
95
138
  case "pattern":
96
139
  if (value && rule.value && !new RegExp(rule.value).test(value)) {
97
- return rule.message || "Invalid format";
140
+ return rule.message || formatMessage(messages.pattern, field, rule);
98
141
  }
99
142
  break;
100
143
  case "custom":
101
144
  if (rule.validator) {
102
- const result = rule.validator(value);
145
+ const result = await rule.validator(value);
103
146
  if (typeof result === "string") return result;
104
- if (!result) return rule.message || "Invalid value";
147
+ if (result === false) return rule.message || formatMessage(messages.custom, field, rule);
105
148
  }
106
149
  break;
107
150
  }
108
151
  }
109
152
  return null;
110
153
  }
111
- function validateFieldByName(fields, name, value) {
154
+ async function validateFieldByName(fields, name, value, resolver, allValues, customMessages) {
155
+ if (resolver && allValues) {
156
+ const resolverErrors = await resolver(allValues);
157
+ if (resolverErrors[name]) return resolverErrors[name];
158
+ }
112
159
  const field = fields.find((f) => f.name === name);
113
160
  if (!field) return null;
114
- return validateField(value, field);
161
+ return await validateField(value, field, customMessages);
115
162
  }
116
- function validateForm(fields, values) {
117
- const errors = {};
118
- for (const field of fields) {
119
- const error = validateField(values[field.name], field);
120
- if (error) errors[field.name] = error;
163
+ async function validateForm(fields, values, resolver, customMessages) {
164
+ let errors = {};
165
+ if (resolver) {
166
+ errors = await resolver(values);
121
167
  }
168
+ const validationPromises = fields.map(async (field) => {
169
+ if (errors[field.name]) return;
170
+ const error = await validateField(get(values, field.name), field, customMessages);
171
+ if (error) errors[field.name] = error;
172
+ });
173
+ await Promise.all(validationPromises);
122
174
  return errors;
123
175
  }
124
176
  function getDefaultValues(fields) {
@@ -129,68 +181,76 @@ function getDefaultValues(fields) {
129
181
  }
130
182
 
131
183
  // src/formState.ts
132
- function createFormRuntimeState(fields) {
133
- return {
184
+ var import_vanilla = require("zustand/vanilla");
185
+ function createFormStore(fields, resolver, errorMessages) {
186
+ return (0, import_vanilla.createStore)()((set2, getStore) => ({
134
187
  values: getDefaultValues(fields),
135
188
  errors: {},
136
- isSubmitting: false
137
- };
138
- }
139
- function setSubmitting(state, isSubmitting) {
140
- return {
141
- ...state,
142
- isSubmitting
143
- };
144
- }
145
- function applyFieldChange(fields, state, name, rawValue) {
146
- const field = fields.find((f) => f.name === name);
147
- const normalizedValue = field ? normalizeFieldValue(field, rawValue) : rawValue;
148
- const values = {
149
- ...state.values,
150
- [name]: normalizedValue
151
- };
152
- const error = validateFieldByName(fields, name, normalizedValue);
153
- const errors = {
154
- ...state.errors,
155
- [name]: error || ""
156
- };
157
- return {
158
- ...state,
159
- values,
160
- errors
161
- };
162
- }
163
- function applyFieldBlur(fields, state, name) {
164
- const error = validateFieldByName(fields, name, state.values[name]);
165
- return {
166
- ...state,
167
- errors: {
168
- ...state.errors,
169
- [name]: error || ""
170
- }
171
- };
172
- }
173
- function runSubmitValidation(fields, state) {
174
- const errors = validateForm(fields, state.values);
175
- const hasError = Object.keys(errors).length > 0;
176
- return {
177
- state: {
178
- ...state,
179
- errors,
180
- isSubmitting: false
189
+ validatingFields: [],
190
+ isSubmitting: false,
191
+ setFieldValue: async (name, rawValue) => {
192
+ const field = fields.find((f) => f.name === name);
193
+ const normalizedValue = field ? normalizeFieldValue(field, rawValue) : rawValue;
194
+ set2((state) => ({
195
+ values: set(state.values, name, normalizedValue),
196
+ validatingFields: [...state.validatingFields, name]
197
+ }));
198
+ try {
199
+ const currentValues = getStore().values;
200
+ const error = await validateFieldByName(fields, name, normalizedValue, resolver, currentValues, errorMessages);
201
+ set2((state) => ({
202
+ errors: { ...state.errors, [name]: error || "" },
203
+ validatingFields: state.validatingFields.filter((f) => f !== name)
204
+ }));
205
+ } catch (err) {
206
+ set2((state) => ({
207
+ validatingFields: state.validatingFields.filter((f) => f !== name)
208
+ }));
209
+ }
181
210
  },
182
- hasError
183
- };
211
+ setFieldBlur: async (name) => {
212
+ set2((state) => ({
213
+ validatingFields: [...state.validatingFields, name]
214
+ }));
215
+ try {
216
+ const currentValues = getStore().values;
217
+ const value = get(currentValues, name);
218
+ const error = await validateFieldByName(fields, name, value, resolver, currentValues, errorMessages);
219
+ set2((state) => ({
220
+ errors: { ...state.errors, [name]: error || "" },
221
+ validatingFields: state.validatingFields.filter((f) => f !== name)
222
+ }));
223
+ } catch (err) {
224
+ set2((state) => ({
225
+ validatingFields: state.validatingFields.filter((f) => f !== name)
226
+ }));
227
+ }
228
+ },
229
+ setSubmitting: (isSubmitting) => set2({ isSubmitting }),
230
+ runSubmitValidation: async () => {
231
+ set2({ isSubmitting: true });
232
+ const state = getStore();
233
+ const errors = await validateForm(fields, state.values, resolver, errorMessages);
234
+ const hasError = Object.keys(errors).length > 0;
235
+ set2({
236
+ errors,
237
+ isSubmitting: false
238
+ });
239
+ return {
240
+ state: getStore(),
241
+ hasError
242
+ };
243
+ }
244
+ }));
184
245
  }
185
246
  // Annotate the CommonJS export names for ESM import in node:
186
247
  0 && (module.exports = {
187
- applyFieldBlur,
188
- applyFieldChange,
189
- createFormRuntimeState,
248
+ createFormStore,
249
+ defaultErrorMessages,
250
+ get,
190
251
  getDefaultValues,
191
252
  normalizeFieldValue,
192
- runSubmitValidation,
193
- setSubmitting,
253
+ set,
194
254
  validateField,
195
255
  validateFieldByName,
196
256
  validateForm
@@ -1,3 +1,4 @@
1
- export { FieldType, FormField, FormSchema, FormState, Option, ValidationRule } from './types.cjs';
2
- export { getDefaultValues, normalizeFieldValue, validateField, validateFieldByName, validateForm } from './utils.cjs';
3
- export { FormRuntimeState, applyFieldBlur, applyFieldChange, createFormRuntimeState, runSubmitValidation, setSubmitting } from './formState.cjs';
1
+ export { ErrorMessageTemplates, FieldType, FormField, FormResolver, FormSchema, FormState, Option, ValidationRule } from './types.cjs';
2
+ export { defaultErrorMessages, get, getDefaultValues, normalizeFieldValue, set, validateField, validateFieldByName, validateForm } from './utils.cjs';
3
+ export { FormRuntimeState, FormStore, createFormStore } from './formState.cjs';
4
+ import 'zustand/vanilla';
@@ -1,3 +1,4 @@
1
- export { FieldType, FormField, FormSchema, FormState, Option, ValidationRule } from './types.js';
2
- export { getDefaultValues, normalizeFieldValue, validateField, validateFieldByName, validateForm } from './utils.js';
3
- export { FormRuntimeState, applyFieldBlur, applyFieldChange, createFormRuntimeState, runSubmitValidation, setSubmitting } from './formState.js';
1
+ export { ErrorMessageTemplates, FieldType, FormField, FormResolver, FormSchema, FormState, Option, ValidationRule } from './types.js';
2
+ export { defaultErrorMessages, get, getDefaultValues, normalizeFieldValue, set, validateField, validateFieldByName, validateForm } from './utils.js';
3
+ export { FormRuntimeState, FormStore, createFormStore } from './formState.js';
4
+ import 'zustand/vanilla';
@@ -1,25 +1,24 @@
1
1
  import {
2
- applyFieldBlur,
3
- applyFieldChange,
4
- createFormRuntimeState,
5
- runSubmitValidation,
6
- setSubmitting
7
- } from "./chunk-TP3IHKWV.js";
2
+ createFormStore
3
+ } from "./chunk-REHKL5VH.js";
4
+ import "./chunk-6F4PWJZI.js";
8
5
  import {
6
+ defaultErrorMessages,
7
+ get,
9
8
  getDefaultValues,
10
9
  normalizeFieldValue,
10
+ set,
11
11
  validateField,
12
12
  validateFieldByName,
13
13
  validateForm
14
- } from "./chunk-WEDHXOHH.js";
14
+ } from "./chunk-KA6QUMVR.js";
15
15
  export {
16
- applyFieldBlur,
17
- applyFieldChange,
18
- createFormRuntimeState,
16
+ createFormStore,
17
+ defaultErrorMessages,
18
+ get,
19
19
  getDefaultValues,
20
20
  normalizeFieldValue,
21
- runSubmitValidation,
22
- setSubmitting,
21
+ set,
23
22
  validateField,
24
23
  validateFieldByName,
25
24
  validateForm
@@ -1,9 +1,9 @@
1
- type FieldType = 'text' | 'number' | 'email' | 'password' | 'select' | 'checkbox' | 'radio' | 'textarea' | 'date';
1
+ type FieldType = 'text' | 'number' | 'email' | 'password' | 'select' | 'checkbox' | 'radio' | 'textarea' | 'date' | 'switch';
2
2
  interface ValidationRule {
3
3
  type: 'required' | 'min' | 'max' | 'pattern' | 'email' | 'custom';
4
4
  value?: any;
5
5
  message?: string;
6
- validator?: (value: any) => boolean | string;
6
+ validator?: (value: any) => boolean | string | Promise<boolean | string>;
7
7
  }
8
8
  interface Option {
9
9
  label: string;
@@ -19,21 +19,33 @@ interface FormField {
19
19
  defaultValue?: any;
20
20
  options?: Option[];
21
21
  validations?: ValidationRule[];
22
- hidden?: boolean;
23
- disabled?: boolean;
22
+ hidden?: boolean | ((values: any) => boolean);
23
+ disabled?: boolean | ((values: any) => boolean);
24
24
  className?: string;
25
25
  }
26
+ type FormResolver = (values: any) => Record<string, string> | Promise<Record<string, string>>;
27
+ type ErrorMessageTemplates = {
28
+ required?: string;
29
+ min?: string;
30
+ max?: string;
31
+ email?: string;
32
+ pattern?: string;
33
+ custom?: string;
34
+ };
26
35
  interface FormSchema {
27
36
  title?: string;
28
37
  description?: string;
29
38
  fields: FormField[];
30
39
  submitButtonText?: string;
40
+ resolver?: FormResolver;
41
+ errorMessages?: ErrorMessageTemplates;
31
42
  }
32
43
  interface FormState {
33
44
  values: Record<string, any>;
34
45
  errors: Record<string, string>;
46
+ validatingFields: string[];
35
47
  isSubmitting: boolean;
36
48
  isValid: boolean;
37
49
  }
38
50
 
39
- export type { FieldType, FormField, FormSchema, FormState, Option, ValidationRule };
51
+ export type { ErrorMessageTemplates, FieldType, FormField, FormResolver, FormSchema, FormState, Option, ValidationRule };
@@ -1,9 +1,9 @@
1
- type FieldType = 'text' | 'number' | 'email' | 'password' | 'select' | 'checkbox' | 'radio' | 'textarea' | 'date';
1
+ type FieldType = 'text' | 'number' | 'email' | 'password' | 'select' | 'checkbox' | 'radio' | 'textarea' | 'date' | 'switch';
2
2
  interface ValidationRule {
3
3
  type: 'required' | 'min' | 'max' | 'pattern' | 'email' | 'custom';
4
4
  value?: any;
5
5
  message?: string;
6
- validator?: (value: any) => boolean | string;
6
+ validator?: (value: any) => boolean | string | Promise<boolean | string>;
7
7
  }
8
8
  interface Option {
9
9
  label: string;
@@ -19,21 +19,33 @@ interface FormField {
19
19
  defaultValue?: any;
20
20
  options?: Option[];
21
21
  validations?: ValidationRule[];
22
- hidden?: boolean;
23
- disabled?: boolean;
22
+ hidden?: boolean | ((values: any) => boolean);
23
+ disabled?: boolean | ((values: any) => boolean);
24
24
  className?: string;
25
25
  }
26
+ type FormResolver = (values: any) => Record<string, string> | Promise<Record<string, string>>;
27
+ type ErrorMessageTemplates = {
28
+ required?: string;
29
+ min?: string;
30
+ max?: string;
31
+ email?: string;
32
+ pattern?: string;
33
+ custom?: string;
34
+ };
26
35
  interface FormSchema {
27
36
  title?: string;
28
37
  description?: string;
29
38
  fields: FormField[];
30
39
  submitButtonText?: string;
40
+ resolver?: FormResolver;
41
+ errorMessages?: ErrorMessageTemplates;
31
42
  }
32
43
  interface FormState {
33
44
  values: Record<string, any>;
34
45
  errors: Record<string, string>;
46
+ validatingFields: string[];
35
47
  isSubmitting: boolean;
36
48
  isValid: boolean;
37
49
  }
38
50
 
39
- export type { FieldType, FormField, FormSchema, FormState, Option, ValidationRule };
51
+ export type { ErrorMessageTemplates, FieldType, FormField, FormResolver, FormSchema, FormState, Option, ValidationRule };
@@ -0,0 +1 @@
1
+ import "./chunk-6F4PWJZI.js";
@@ -20,8 +20,11 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/utils.ts
21
21
  var utils_exports = {};
22
22
  __export(utils_exports, {
23
+ defaultErrorMessages: () => defaultErrorMessages,
24
+ get: () => get,
23
25
  getDefaultValues: () => getDefaultValues,
24
26
  normalizeFieldValue: () => normalizeFieldValue,
27
+ set: () => set,
25
28
  validateField: () => validateField,
26
29
  validateFieldByName: () => validateFieldByName,
27
30
  validateForm: () => validateForm
@@ -33,85 +36,138 @@ function parseNumberish(value) {
33
36
  const parsed = Number(value);
34
37
  return Number.isNaN(parsed) ? null : parsed;
35
38
  }
39
+ var defaultErrorMessages = {
40
+ required: "{label} is required",
41
+ min: "{label} must be at least {value}",
42
+ max: "{label} must be at most {value}",
43
+ email: "Invalid email address",
44
+ pattern: "Invalid format",
45
+ custom: "Invalid value"
46
+ };
47
+ function formatMessage(template, field, rule) {
48
+ return template.replace("{label}", field.label).replace("{value}", String(rule.value || ""));
49
+ }
50
+ function get(obj, path, defaultValue) {
51
+ if (!path) return defaultValue;
52
+ const keys = path.split(/[.[\]]/).filter(Boolean);
53
+ let result = obj;
54
+ for (const key of keys) {
55
+ if (result === null || result === void 0) return defaultValue;
56
+ result = result[key];
57
+ }
58
+ return result === void 0 ? defaultValue : result;
59
+ }
60
+ function set(obj, path, value) {
61
+ if (Object(obj) !== obj) return obj;
62
+ const keys = path.split(/[.[\]]/).filter(Boolean);
63
+ const newObj = { ...obj };
64
+ let current = newObj;
65
+ for (let i = 0; i < keys.length - 1; i++) {
66
+ const key = keys[i];
67
+ const nextKey = keys[i + 1];
68
+ const isNextKeyIndex = /^\d+$/.test(nextKey);
69
+ if (!(key in current) || current[key] === null || typeof current[key] !== "object") {
70
+ current[key] = isNextKeyIndex ? [] : {};
71
+ } else {
72
+ current[key] = Array.isArray(current[key]) ? [...current[key]] : { ...current[key] };
73
+ }
74
+ current = current[key];
75
+ }
76
+ current[keys[keys.length - 1]] = value;
77
+ return newObj;
78
+ }
36
79
  function normalizeFieldValue(field, value) {
37
80
  if (field.type !== "number") return value;
38
81
  if (value === "" || value === void 0 || value === null) return "";
39
82
  const numericValue = parseNumberish(value);
40
83
  return numericValue === null ? value : numericValue;
41
84
  }
42
- function validateField(value, field) {
85
+ async function validateField(value, field, customMessages) {
43
86
  if (!field.validations) return null;
87
+ const messages = { ...defaultErrorMessages, ...customMessages };
44
88
  for (const rule of field.validations) {
45
89
  switch (rule.type) {
46
90
  case "required":
47
91
  if (value === void 0 || value === null || value === "" || Array.isArray(value) && value.length === 0) {
48
- return rule.message || `${field.label} is required`;
92
+ return rule.message || formatMessage(messages.required, field, rule);
49
93
  }
50
94
  break;
51
95
  case "min":
52
96
  if (field.type === "number") {
53
97
  const numericValue = parseNumberish(value);
54
98
  if (numericValue !== null && numericValue < rule.value) {
55
- return rule.message || `${field.label} must be at least ${rule.value}`;
99
+ const template = field.type === "number" ? messages.min : typeof value === "string" ? "{label} must be at least {value} characters" : messages.min;
100
+ return rule.message || formatMessage(template, field, rule);
56
101
  }
57
102
  break;
58
103
  }
59
104
  if (typeof value === "number" && value < rule.value) {
60
- return rule.message || `${field.label} must be at least ${rule.value}`;
105
+ return rule.message || formatMessage(messages.min, field, rule);
61
106
  }
62
107
  if (typeof value === "string" && value.length < rule.value) {
63
- return rule.message || `${field.label} must be at least ${rule.value} characters`;
108
+ const template = "{label} must be at least {value} characters";
109
+ return rule.message || formatMessage(template, field, rule);
64
110
  }
65
111
  break;
66
112
  case "max":
67
113
  if (field.type === "number") {
68
114
  const numericValue = parseNumberish(value);
69
115
  if (numericValue !== null && numericValue > rule.value) {
70
- return rule.message || `${field.label} must be at most ${rule.value}`;
116
+ return rule.message || formatMessage(messages.max, field, rule);
71
117
  }
72
118
  break;
73
119
  }
74
120
  if (typeof value === "number" && value > rule.value) {
75
- return rule.message || `${field.label} must be at most ${rule.value}`;
121
+ return rule.message || formatMessage(messages.max, field, rule);
76
122
  }
77
123
  if (typeof value === "string" && value.length > rule.value) {
78
- return rule.message || `${field.label} must be at most ${rule.value} characters`;
124
+ const template = "{label} must be at most {value} characters";
125
+ return rule.message || formatMessage(template, field, rule);
79
126
  }
80
127
  break;
81
128
  case "email": {
82
129
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
83
130
  if (value && !emailRegex.test(value)) {
84
- return rule.message || "Invalid email address";
131
+ return rule.message || formatMessage(messages.email, field, rule);
85
132
  }
86
133
  break;
87
134
  }
88
135
  case "pattern":
89
136
  if (value && rule.value && !new RegExp(rule.value).test(value)) {
90
- return rule.message || "Invalid format";
137
+ return rule.message || formatMessage(messages.pattern, field, rule);
91
138
  }
92
139
  break;
93
140
  case "custom":
94
141
  if (rule.validator) {
95
- const result = rule.validator(value);
142
+ const result = await rule.validator(value);
96
143
  if (typeof result === "string") return result;
97
- if (!result) return rule.message || "Invalid value";
144
+ if (result === false) return rule.message || formatMessage(messages.custom, field, rule);
98
145
  }
99
146
  break;
100
147
  }
101
148
  }
102
149
  return null;
103
150
  }
104
- function validateFieldByName(fields, name, value) {
151
+ async function validateFieldByName(fields, name, value, resolver, allValues, customMessages) {
152
+ if (resolver && allValues) {
153
+ const resolverErrors = await resolver(allValues);
154
+ if (resolverErrors[name]) return resolverErrors[name];
155
+ }
105
156
  const field = fields.find((f) => f.name === name);
106
157
  if (!field) return null;
107
- return validateField(value, field);
158
+ return await validateField(value, field, customMessages);
108
159
  }
109
- function validateForm(fields, values) {
110
- const errors = {};
111
- for (const field of fields) {
112
- const error = validateField(values[field.name], field);
113
- if (error) errors[field.name] = error;
160
+ async function validateForm(fields, values, resolver, customMessages) {
161
+ let errors = {};
162
+ if (resolver) {
163
+ errors = await resolver(values);
114
164
  }
165
+ const validationPromises = fields.map(async (field) => {
166
+ if (errors[field.name]) return;
167
+ const error = await validateField(get(values, field.name), field, customMessages);
168
+ if (error) errors[field.name] = error;
169
+ });
170
+ await Promise.all(validationPromises);
115
171
  return errors;
116
172
  }
117
173
  function getDefaultValues(fields) {
@@ -122,8 +178,11 @@ function getDefaultValues(fields) {
122
178
  }
123
179
  // Annotate the CommonJS export names for ESM import in node:
124
180
  0 && (module.exports = {
181
+ defaultErrorMessages,
182
+ get,
125
183
  getDefaultValues,
126
184
  normalizeFieldValue,
185
+ set,
127
186
  validateField,
128
187
  validateFieldByName,
129
188
  validateForm