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