@vuehookform/core 0.1.1 → 0.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/LICENSE +21 -0
- package/README.md +15 -13
- package/dist/core/formContext.d.ts +21 -3
- package/dist/core/useFieldArray.d.ts +3 -3
- package/dist/core/useFieldRegistration.d.ts +2 -2
- package/dist/core/useValidation.d.ts +1 -0
- package/dist/index.d.ts +2 -1
- package/dist/types.d.ts +301 -33
- package/dist/utils/paths.d.ts +1 -1
- package/dist/vuehookform.cjs +520 -186
- package/dist/vuehookform.js +521 -188
- package/package.json +11 -3
package/dist/vuehookform.cjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let vue = require("vue");
|
|
3
3
|
function get(obj, path) {
|
|
4
|
-
if (!path) return obj;
|
|
4
|
+
if (!path || obj === null || obj === void 0) return obj;
|
|
5
5
|
const keys = path.split(".");
|
|
6
6
|
let result = obj;
|
|
7
7
|
for (const key of keys) {
|
|
@@ -21,9 +21,14 @@ function set(obj, path, value) {
|
|
|
21
21
|
if (keys.some((k) => UNSAFE_KEYS.includes(k))) return;
|
|
22
22
|
const lastKey = keys.pop();
|
|
23
23
|
let current = obj;
|
|
24
|
-
for (
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
for (let i = 0; i < keys.length; i++) {
|
|
25
|
+
const key = keys[i];
|
|
26
|
+
const existing = current[key];
|
|
27
|
+
if (existing !== void 0 && existing !== null && typeof existing !== "object") try {
|
|
28
|
+
if (globalThis.process?.env?.NODE_ENV !== "production") console.warn(`[vue-hook-form] set(): Overwriting primitive value at path "${keys.slice(0, i + 1).join(".")}" with an object. Previous value: ${JSON.stringify(existing)}`);
|
|
29
|
+
} catch {}
|
|
30
|
+
if (!(key in current) || typeof current[key] !== "object" || current[key] === null) {
|
|
31
|
+
const nextKey = keys[i + 1];
|
|
27
32
|
current[key] = nextKey && /^\d+$/.test(nextKey) ? [] : {};
|
|
28
33
|
}
|
|
29
34
|
current = current[key];
|
|
@@ -37,13 +42,16 @@ function unset(obj, path) {
|
|
|
37
42
|
let current = obj;
|
|
38
43
|
for (const key of keys) {
|
|
39
44
|
if (!(key in current)) return;
|
|
40
|
-
|
|
45
|
+
const next = current[key];
|
|
46
|
+
if (next === null || typeof next !== "object") return;
|
|
47
|
+
current = next;
|
|
41
48
|
}
|
|
42
49
|
delete current[lastKey];
|
|
43
50
|
}
|
|
44
51
|
var idCounter = 0;
|
|
45
52
|
function generateId() {
|
|
46
|
-
|
|
53
|
+
const random = Math.random().toString(36).substring(2, 11);
|
|
54
|
+
return `field_${Date.now()}_${idCounter++}_${random}`;
|
|
47
55
|
}
|
|
48
56
|
function createFormContext(options) {
|
|
49
57
|
const formData = (0, vue.reactive)({});
|
|
@@ -58,26 +66,81 @@ function createFormContext(options) {
|
|
|
58
66
|
isLoading.value = false;
|
|
59
67
|
}).catch((error) => {
|
|
60
68
|
console.error("Failed to load async default values:", error);
|
|
69
|
+
defaultValuesError.value = error;
|
|
61
70
|
isLoading.value = false;
|
|
71
|
+
options.onDefaultValuesError?.(error);
|
|
62
72
|
});
|
|
63
73
|
} else if (options.defaultValues) {
|
|
64
74
|
Object.assign(defaultValues, options.defaultValues);
|
|
65
75
|
Object.assign(formData, defaultValues);
|
|
66
76
|
}
|
|
77
|
+
const errors = (0, vue.shallowRef)({});
|
|
78
|
+
const touchedFields = (0, vue.shallowRef)({});
|
|
79
|
+
const dirtyFields = (0, vue.shallowRef)({});
|
|
80
|
+
const isSubmitting = (0, vue.ref)(false);
|
|
81
|
+
const submitCount = (0, vue.ref)(0);
|
|
82
|
+
const defaultValuesError = (0, vue.ref)(null);
|
|
83
|
+
const isSubmitSuccessful = (0, vue.ref)(false);
|
|
84
|
+
const validatingFields = (0, vue.shallowRef)({});
|
|
85
|
+
const externalErrors = (0, vue.shallowRef)({});
|
|
86
|
+
const errorDelayTimers = /* @__PURE__ */ new Map();
|
|
87
|
+
const pendingErrors = /* @__PURE__ */ new Map();
|
|
88
|
+
const fieldRefs = /* @__PURE__ */ new Map();
|
|
89
|
+
const fieldOptions = /* @__PURE__ */ new Map();
|
|
90
|
+
const fieldArrays = /* @__PURE__ */ new Map();
|
|
91
|
+
const fieldHandlers = /* @__PURE__ */ new Map();
|
|
92
|
+
const debounceTimers = /* @__PURE__ */ new Map();
|
|
93
|
+
const validationRequestIds = /* @__PURE__ */ new Map();
|
|
94
|
+
const resetGeneration = (0, vue.ref)(0);
|
|
95
|
+
if (options.values !== void 0) {
|
|
96
|
+
const initialValues = (0, vue.toValue)(options.values);
|
|
97
|
+
if (initialValues && !isAsyncDefaults) {
|
|
98
|
+
for (const [key, value] of Object.entries(initialValues)) if (value !== void 0) set(formData, key, value);
|
|
99
|
+
}
|
|
100
|
+
(0, vue.watch)(() => (0, vue.toValue)(options.values), (newValues) => {
|
|
101
|
+
if (newValues) {
|
|
102
|
+
for (const [key, value] of Object.entries(newValues)) if (value !== void 0) {
|
|
103
|
+
set(formData, key, value);
|
|
104
|
+
const fieldRef = fieldRefs.get(key);
|
|
105
|
+
const opts = fieldOptions.get(key);
|
|
106
|
+
if (fieldRef?.value && !opts?.controlled) {
|
|
107
|
+
const el = fieldRef.value;
|
|
108
|
+
if (el.type === "checkbox") el.checked = value;
|
|
109
|
+
else el.value = value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}, { deep: true });
|
|
114
|
+
}
|
|
115
|
+
if (options.errors !== void 0) {
|
|
116
|
+
const initialErrors = (0, vue.toValue)(options.errors);
|
|
117
|
+
if (initialErrors) externalErrors.value = initialErrors;
|
|
118
|
+
(0, vue.watch)(() => (0, vue.toValue)(options.errors), (newErrors) => {
|
|
119
|
+
externalErrors.value = newErrors || {};
|
|
120
|
+
}, { deep: true });
|
|
121
|
+
}
|
|
67
122
|
return {
|
|
68
123
|
formData,
|
|
69
124
|
defaultValues,
|
|
70
|
-
errors
|
|
71
|
-
touchedFields
|
|
72
|
-
dirtyFields
|
|
73
|
-
isSubmitting
|
|
125
|
+
errors,
|
|
126
|
+
touchedFields,
|
|
127
|
+
dirtyFields,
|
|
128
|
+
isSubmitting,
|
|
74
129
|
isLoading,
|
|
75
|
-
submitCount
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
130
|
+
submitCount,
|
|
131
|
+
defaultValuesError,
|
|
132
|
+
isSubmitSuccessful,
|
|
133
|
+
validatingFields,
|
|
134
|
+
externalErrors,
|
|
135
|
+
errorDelayTimers,
|
|
136
|
+
pendingErrors,
|
|
137
|
+
fieldRefs,
|
|
138
|
+
fieldOptions,
|
|
139
|
+
fieldArrays,
|
|
140
|
+
fieldHandlers,
|
|
141
|
+
debounceTimers,
|
|
142
|
+
validationRequestIds,
|
|
143
|
+
resetGeneration,
|
|
81
144
|
options
|
|
82
145
|
};
|
|
83
146
|
}
|
|
@@ -86,6 +149,17 @@ function clearFieldErrors(errors, fieldPath) {
|
|
|
86
149
|
for (const key of Object.keys(newErrors)) if (key === fieldPath || key.startsWith(`${fieldPath}.`)) delete newErrors[key];
|
|
87
150
|
return newErrors;
|
|
88
151
|
}
|
|
152
|
+
function setValidating(ctx, fieldPath, isValidating) {
|
|
153
|
+
if (isValidating) ctx.validatingFields.value = {
|
|
154
|
+
...ctx.validatingFields.value,
|
|
155
|
+
[fieldPath]: true
|
|
156
|
+
};
|
|
157
|
+
else {
|
|
158
|
+
const newValidating = { ...ctx.validatingFields.value };
|
|
159
|
+
delete newValidating[fieldPath];
|
|
160
|
+
ctx.validatingFields.value = newValidating;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
89
163
|
function groupErrorsByPath(issues) {
|
|
90
164
|
const grouped = /* @__PURE__ */ new Map();
|
|
91
165
|
for (const issue of issues) {
|
|
@@ -99,8 +173,11 @@ function groupErrorsByPath(issues) {
|
|
|
99
173
|
}
|
|
100
174
|
return grouped;
|
|
101
175
|
}
|
|
102
|
-
function createFieldError(errors) {
|
|
103
|
-
|
|
176
|
+
function createFieldError(errors, criteriaMode = "firstError") {
|
|
177
|
+
const firstError = errors[0];
|
|
178
|
+
if (!firstError) return "";
|
|
179
|
+
if (criteriaMode === "firstError") return firstError.message;
|
|
180
|
+
if (errors.length === 1) return firstError.message;
|
|
104
181
|
const types = {};
|
|
105
182
|
for (const err of errors) {
|
|
106
183
|
const existing = types[err.type];
|
|
@@ -108,135 +185,215 @@ function createFieldError(errors) {
|
|
|
108
185
|
else types[err.type] = err.message;
|
|
109
186
|
}
|
|
110
187
|
return {
|
|
111
|
-
type:
|
|
112
|
-
message:
|
|
188
|
+
type: firstError.type,
|
|
189
|
+
message: firstError.message,
|
|
113
190
|
types
|
|
114
191
|
};
|
|
115
192
|
}
|
|
116
193
|
function createValidation(ctx) {
|
|
117
|
-
|
|
118
|
-
const
|
|
119
|
-
if (
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
194
|
+
function scheduleError(fieldPath, error) {
|
|
195
|
+
const delayMs = ctx.options.delayError || 0;
|
|
196
|
+
if (delayMs <= 0) {
|
|
197
|
+
const newErrors = { ...ctx.errors.value };
|
|
198
|
+
set(newErrors, fieldPath, error);
|
|
199
|
+
ctx.errors.value = newErrors;
|
|
200
|
+
return;
|
|
123
201
|
}
|
|
124
|
-
const
|
|
125
|
-
if (
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
if (
|
|
131
|
-
ctx.
|
|
202
|
+
const existingTimer = ctx.errorDelayTimers.get(fieldPath);
|
|
203
|
+
if (existingTimer) clearTimeout(existingTimer);
|
|
204
|
+
ctx.pendingErrors.set(fieldPath, error);
|
|
205
|
+
const timer = setTimeout(() => {
|
|
206
|
+
ctx.errorDelayTimers.delete(fieldPath);
|
|
207
|
+
const pendingError = ctx.pendingErrors.get(fieldPath);
|
|
208
|
+
if (pendingError !== void 0) {
|
|
209
|
+
ctx.pendingErrors.delete(fieldPath);
|
|
210
|
+
const newErrors = { ...ctx.errors.value };
|
|
211
|
+
set(newErrors, fieldPath, pendingError);
|
|
212
|
+
ctx.errors.value = newErrors;
|
|
213
|
+
}
|
|
214
|
+
}, delayMs);
|
|
215
|
+
ctx.errorDelayTimers.set(fieldPath, timer);
|
|
216
|
+
}
|
|
217
|
+
function cancelError(fieldPath) {
|
|
218
|
+
const timer = ctx.errorDelayTimers.get(fieldPath);
|
|
219
|
+
if (timer) {
|
|
220
|
+
clearTimeout(timer);
|
|
221
|
+
ctx.errorDelayTimers.delete(fieldPath);
|
|
222
|
+
}
|
|
223
|
+
ctx.pendingErrors.delete(fieldPath);
|
|
224
|
+
return clearFieldErrors(ctx.errors.value, fieldPath);
|
|
225
|
+
}
|
|
226
|
+
function clearAllPendingErrors() {
|
|
227
|
+
for (const timer of ctx.errorDelayTimers.values()) clearTimeout(timer);
|
|
228
|
+
ctx.errorDelayTimers.clear();
|
|
229
|
+
ctx.pendingErrors.clear();
|
|
230
|
+
}
|
|
231
|
+
async function validate(fieldPath) {
|
|
232
|
+
const generationAtStart = ctx.resetGeneration.value;
|
|
233
|
+
const criteriaMode = ctx.options.criteriaMode || "firstError";
|
|
234
|
+
const validatingKey = fieldPath || "_form";
|
|
235
|
+
setValidating(ctx, validatingKey, true);
|
|
236
|
+
try {
|
|
237
|
+
const result = await ctx.options.schema.safeParseAsync(ctx.formData);
|
|
238
|
+
if (ctx.resetGeneration.value !== generationAtStart) return true;
|
|
239
|
+
if (result.success) {
|
|
240
|
+
if (fieldPath) ctx.errors.value = cancelError(fieldPath);
|
|
241
|
+
else {
|
|
242
|
+
clearAllPendingErrors();
|
|
243
|
+
ctx.errors.value = {};
|
|
244
|
+
}
|
|
132
245
|
return true;
|
|
133
246
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
247
|
+
const zodErrors = result.error.issues;
|
|
248
|
+
if (fieldPath) {
|
|
249
|
+
const fieldErrors = zodErrors.filter((issue) => {
|
|
250
|
+
const path = issue.path.join(".");
|
|
251
|
+
return path === fieldPath || path.startsWith(`${fieldPath}.`);
|
|
252
|
+
});
|
|
253
|
+
if (fieldErrors.length === 0) {
|
|
254
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
255
|
+
return true;
|
|
256
|
+
}
|
|
257
|
+
ctx.errors.value = cancelError(fieldPath);
|
|
258
|
+
const grouped$1 = groupErrorsByPath(fieldErrors);
|
|
259
|
+
for (const [path, errors] of grouped$1) scheduleError(path, createFieldError(errors, criteriaMode));
|
|
260
|
+
return false;
|
|
261
|
+
}
|
|
262
|
+
clearAllPendingErrors();
|
|
263
|
+
ctx.errors.value = {};
|
|
264
|
+
const grouped = groupErrorsByPath(zodErrors);
|
|
265
|
+
for (const [path, errors] of grouped) scheduleError(path, createFieldError(errors, criteriaMode));
|
|
138
266
|
return false;
|
|
267
|
+
} finally {
|
|
268
|
+
setValidating(ctx, validatingKey, false);
|
|
139
269
|
}
|
|
140
|
-
const newErrors = {};
|
|
141
|
-
const grouped = groupErrorsByPath(zodErrors);
|
|
142
|
-
for (const [path, errors] of grouped) set(newErrors, path, createFieldError(errors));
|
|
143
|
-
ctx.errors.value = newErrors;
|
|
144
|
-
return false;
|
|
145
270
|
}
|
|
146
|
-
return {
|
|
271
|
+
return {
|
|
272
|
+
validate,
|
|
273
|
+
clearAllPendingErrors
|
|
274
|
+
};
|
|
147
275
|
}
|
|
276
|
+
var validationRequestCounter = 0;
|
|
148
277
|
function createFieldRegistration(ctx, validate) {
|
|
149
278
|
function register(name, registerOptions) {
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
279
|
+
let fieldRef = ctx.fieldRefs.get(name);
|
|
280
|
+
if (!fieldRef) {
|
|
281
|
+
fieldRef = (0, vue.ref)(null);
|
|
282
|
+
ctx.fieldRefs.set(name, fieldRef);
|
|
283
|
+
if (get(ctx.formData, name) === void 0) {
|
|
284
|
+
const defaultValue = get(ctx.defaultValues, name);
|
|
285
|
+
if (defaultValue !== void 0) set(ctx.formData, name, defaultValue);
|
|
286
|
+
}
|
|
156
287
|
}
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
const
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
288
|
+
if (registerOptions) ctx.fieldOptions.set(name, registerOptions);
|
|
289
|
+
let handlers = ctx.fieldHandlers.get(name);
|
|
290
|
+
if (!handlers) {
|
|
291
|
+
const runCustomValidation = async (fieldName, value, requestId, resetGenAtStart) => {
|
|
292
|
+
const fieldOpts = ctx.fieldOptions.get(fieldName);
|
|
293
|
+
if (!fieldOpts?.validate || fieldOpts.disabled) return;
|
|
294
|
+
const error = await fieldOpts.validate(value);
|
|
295
|
+
if (requestId !== ctx.validationRequestIds.get(fieldName)) return;
|
|
296
|
+
if (ctx.resetGeneration.value !== resetGenAtStart) return;
|
|
297
|
+
if (error) ctx.errors.value = {
|
|
298
|
+
...ctx.errors.value,
|
|
299
|
+
[fieldName]: error
|
|
300
|
+
};
|
|
301
|
+
else {
|
|
302
|
+
const newErrors = { ...ctx.errors.value };
|
|
303
|
+
delete newErrors[fieldName];
|
|
304
|
+
ctx.errors.value = newErrors;
|
|
305
|
+
}
|
|
165
306
|
};
|
|
166
|
-
|
|
167
|
-
const
|
|
168
|
-
|
|
169
|
-
ctx.
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
307
|
+
const onInput = async (e) => {
|
|
308
|
+
const target = e.target;
|
|
309
|
+
const value = target.type === "checkbox" ? target.checked : target.value;
|
|
310
|
+
set(ctx.formData, name, value);
|
|
311
|
+
ctx.dirtyFields.value = {
|
|
312
|
+
...ctx.dirtyFields.value,
|
|
313
|
+
[name]: true
|
|
314
|
+
};
|
|
315
|
+
if (ctx.options.mode === "onChange" || ctx.options.mode === "onTouched" && ctx.touchedFields.value[name] || ctx.touchedFields.value[name] && ctx.options.reValidateMode === "onChange") {
|
|
316
|
+
await validate(name);
|
|
317
|
+
const fieldOpts$1 = ctx.fieldOptions.get(name);
|
|
318
|
+
if (fieldOpts$1?.deps && fieldOpts$1.deps.length > 0) for (const depField of fieldOpts$1.deps) validate(depField);
|
|
319
|
+
}
|
|
320
|
+
const fieldOpts = ctx.fieldOptions.get(name);
|
|
321
|
+
if (fieldOpts?.validate && !fieldOpts.disabled) {
|
|
322
|
+
const requestId = ++validationRequestCounter;
|
|
323
|
+
ctx.validationRequestIds.set(name, requestId);
|
|
324
|
+
const resetGenAtStart = ctx.resetGeneration.value;
|
|
325
|
+
const debounceMs = fieldOpts.validateDebounce || 0;
|
|
326
|
+
if (debounceMs > 0) {
|
|
327
|
+
const existingTimer = ctx.debounceTimers.get(name);
|
|
328
|
+
if (existingTimer) clearTimeout(existingTimer);
|
|
329
|
+
const timer = setTimeout(() => {
|
|
330
|
+
ctx.debounceTimers.delete(name);
|
|
331
|
+
runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
332
|
+
}, debounceMs);
|
|
333
|
+
ctx.debounceTimers.set(name, timer);
|
|
334
|
+
} else await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
335
|
+
}
|
|
179
336
|
};
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const
|
|
188
|
-
if (
|
|
189
|
-
|
|
190
|
-
ctx.debounceTimers.delete(name);
|
|
191
|
-
runCustomValidation(name, value, requestId);
|
|
192
|
-
}, debounceMs);
|
|
193
|
-
ctx.debounceTimers.set(name, timer);
|
|
194
|
-
} else await runCustomValidation(name, value, requestId);
|
|
195
|
-
}
|
|
196
|
-
};
|
|
197
|
-
const onBlur = async (_e) => {
|
|
198
|
-
ctx.touchedFields.value = {
|
|
199
|
-
...ctx.touchedFields.value,
|
|
200
|
-
[name]: true
|
|
337
|
+
const onBlur = async (_e) => {
|
|
338
|
+
ctx.touchedFields.value = {
|
|
339
|
+
...ctx.touchedFields.value,
|
|
340
|
+
[name]: true
|
|
341
|
+
};
|
|
342
|
+
if (ctx.options.mode === "onBlur" || ctx.options.mode === "onTouched" || ctx.submitCount.value > 0 && ctx.options.reValidateMode === "onBlur") {
|
|
343
|
+
await validate(name);
|
|
344
|
+
const fieldOpts = ctx.fieldOptions.get(name);
|
|
345
|
+
if (fieldOpts?.deps && fieldOpts.deps.length > 0) for (const depField of fieldOpts.deps) validate(depField);
|
|
346
|
+
}
|
|
201
347
|
};
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
delete newErrors[name];
|
|
217
|
-
ctx.errors.value = newErrors;
|
|
218
|
-
const newTouched = { ...ctx.touchedFields.value };
|
|
219
|
-
delete newTouched[name];
|
|
220
|
-
ctx.touchedFields.value = newTouched;
|
|
221
|
-
const newDirty = { ...ctx.dirtyFields.value };
|
|
222
|
-
delete newDirty[name];
|
|
223
|
-
ctx.dirtyFields.value = newDirty;
|
|
224
|
-
ctx.fieldRefs.delete(name);
|
|
225
|
-
ctx.fieldOptions.delete(name);
|
|
348
|
+
const refCallback = (el) => {
|
|
349
|
+
const currentFieldRef = ctx.fieldRefs.get(name);
|
|
350
|
+
if (!currentFieldRef) return;
|
|
351
|
+
const previousEl = currentFieldRef.value;
|
|
352
|
+
if (previousEl === el) return;
|
|
353
|
+
if (previousEl && el) return;
|
|
354
|
+
currentFieldRef.value = el;
|
|
355
|
+
const opts = ctx.fieldOptions.get(name);
|
|
356
|
+
if (el && !opts?.controlled && el instanceof HTMLInputElement) {
|
|
357
|
+
const value = get(ctx.formData, name);
|
|
358
|
+
if (value !== void 0) if (el.type === "checkbox") el.checked = value;
|
|
359
|
+
else el.value = value;
|
|
360
|
+
}
|
|
361
|
+
if (previousEl && !el) {
|
|
226
362
|
const timer = ctx.debounceTimers.get(name);
|
|
227
363
|
if (timer) {
|
|
228
364
|
clearTimeout(timer);
|
|
229
365
|
ctx.debounceTimers.delete(name);
|
|
230
366
|
}
|
|
231
367
|
ctx.validationRequestIds.delete(name);
|
|
368
|
+
if (opts?.shouldUnregister ?? ctx.options.shouldUnregister ?? false) {
|
|
369
|
+
unset(ctx.formData, name);
|
|
370
|
+
const newErrors = { ...ctx.errors.value };
|
|
371
|
+
delete newErrors[name];
|
|
372
|
+
ctx.errors.value = newErrors;
|
|
373
|
+
const newTouched = { ...ctx.touchedFields.value };
|
|
374
|
+
delete newTouched[name];
|
|
375
|
+
ctx.touchedFields.value = newTouched;
|
|
376
|
+
const newDirty = { ...ctx.dirtyFields.value };
|
|
377
|
+
delete newDirty[name];
|
|
378
|
+
ctx.dirtyFields.value = newDirty;
|
|
379
|
+
ctx.fieldRefs.delete(name);
|
|
380
|
+
ctx.fieldOptions.delete(name);
|
|
381
|
+
ctx.fieldHandlers.delete(name);
|
|
382
|
+
}
|
|
232
383
|
}
|
|
233
|
-
}
|
|
234
|
-
|
|
384
|
+
};
|
|
385
|
+
handlers = {
|
|
386
|
+
onInput,
|
|
387
|
+
onBlur,
|
|
388
|
+
refCallback
|
|
389
|
+
};
|
|
390
|
+
ctx.fieldHandlers.set(name, handlers);
|
|
391
|
+
}
|
|
235
392
|
return {
|
|
236
393
|
name,
|
|
237
|
-
ref: refCallback,
|
|
238
|
-
onInput,
|
|
239
|
-
onBlur,
|
|
394
|
+
ref: handlers.refCallback,
|
|
395
|
+
onInput: handlers.onInput,
|
|
396
|
+
onBlur: handlers.onBlur,
|
|
240
397
|
...registerOptions?.controlled && { value: (0, vue.computed)({
|
|
241
398
|
get: () => get(ctx.formData, name),
|
|
242
399
|
set: (val) => {
|
|
@@ -249,9 +406,27 @@ function createFieldRegistration(ctx, validate) {
|
|
|
249
406
|
}) }
|
|
250
407
|
};
|
|
251
408
|
}
|
|
252
|
-
function unregister(name) {
|
|
409
|
+
function unregister(name, options) {
|
|
410
|
+
const opts = options || {};
|
|
411
|
+
if (!opts.keepValue) unset(ctx.formData, name);
|
|
412
|
+
if (!opts.keepError) {
|
|
413
|
+
const newErrors = { ...ctx.errors.value };
|
|
414
|
+
delete newErrors[name];
|
|
415
|
+
ctx.errors.value = newErrors;
|
|
416
|
+
}
|
|
417
|
+
if (!opts.keepTouched) {
|
|
418
|
+
const newTouched = { ...ctx.touchedFields.value };
|
|
419
|
+
delete newTouched[name];
|
|
420
|
+
ctx.touchedFields.value = newTouched;
|
|
421
|
+
}
|
|
422
|
+
if (!opts.keepDirty) {
|
|
423
|
+
const newDirty = { ...ctx.dirtyFields.value };
|
|
424
|
+
delete newDirty[name];
|
|
425
|
+
ctx.dirtyFields.value = newDirty;
|
|
426
|
+
}
|
|
253
427
|
ctx.fieldRefs.delete(name);
|
|
254
428
|
ctx.fieldOptions.delete(name);
|
|
429
|
+
ctx.fieldHandlers.delete(name);
|
|
255
430
|
const timer = ctx.debounceTimers.get(name);
|
|
256
431
|
if (timer) {
|
|
257
432
|
clearTimeout(timer);
|
|
@@ -264,42 +439,89 @@ function createFieldRegistration(ctx, validate) {
|
|
|
264
439
|
unregister
|
|
265
440
|
};
|
|
266
441
|
}
|
|
267
|
-
function createFieldArrayManager(ctx, validate) {
|
|
268
|
-
function fields(name) {
|
|
442
|
+
function createFieldArrayManager(ctx, validate, setFocus) {
|
|
443
|
+
function fields(name, options) {
|
|
269
444
|
let fieldArray = ctx.fieldArrays.get(name);
|
|
270
445
|
if (!fieldArray) {
|
|
271
446
|
const existingValues = get(ctx.formData, name) || [];
|
|
272
447
|
fieldArray = {
|
|
273
448
|
items: (0, vue.ref)([]),
|
|
274
|
-
values: existingValues
|
|
449
|
+
values: existingValues,
|
|
450
|
+
indexCache: /* @__PURE__ */ new Map(),
|
|
451
|
+
rules: options?.rules
|
|
275
452
|
};
|
|
276
453
|
ctx.fieldArrays.set(name, fieldArray);
|
|
277
454
|
if (!get(ctx.formData, name)) set(ctx.formData, name, []);
|
|
278
|
-
}
|
|
455
|
+
} else if (options?.rules) fieldArray.rules = options.rules;
|
|
279
456
|
const fa = fieldArray;
|
|
457
|
+
const indexCache = fa.indexCache;
|
|
458
|
+
const rebuildIndexCache = () => {
|
|
459
|
+
indexCache.clear();
|
|
460
|
+
fa.items.value.forEach((item, idx) => {
|
|
461
|
+
indexCache.set(item.key, idx);
|
|
462
|
+
});
|
|
463
|
+
};
|
|
280
464
|
const createItem = (key) => ({
|
|
281
465
|
key,
|
|
282
466
|
get index() {
|
|
283
|
-
return
|
|
467
|
+
return indexCache.get(key) ?? -1;
|
|
284
468
|
},
|
|
285
469
|
remove() {
|
|
286
|
-
const currentIndex =
|
|
470
|
+
const currentIndex = indexCache.get(key) ?? -1;
|
|
287
471
|
if (currentIndex !== -1) removeAt(currentIndex);
|
|
288
472
|
}
|
|
289
473
|
});
|
|
290
|
-
if (fa.items.value.length === 0 && fa.values.length > 0)
|
|
291
|
-
|
|
292
|
-
|
|
474
|
+
if (fa.items.value.length === 0 && fa.values.length > 0) {
|
|
475
|
+
fa.items.value = fa.values.map(() => createItem(generateId()));
|
|
476
|
+
rebuildIndexCache();
|
|
477
|
+
}
|
|
478
|
+
const handleFocus = async (baseIndex, addedCount, focusOptions) => {
|
|
479
|
+
if (!focusOptions?.shouldFocus) return;
|
|
480
|
+
await (0, vue.nextTick)();
|
|
481
|
+
const focusItemOffset = focusOptions?.focusIndex ?? 0;
|
|
482
|
+
let fieldPath = `${name}.${baseIndex + Math.min(focusItemOffset, addedCount - 1)}`;
|
|
483
|
+
if (focusOptions?.focusName) fieldPath = `${fieldPath}.${focusOptions.focusName}`;
|
|
484
|
+
setFocus(fieldPath);
|
|
485
|
+
};
|
|
486
|
+
const normalizeToArray = (value) => {
|
|
487
|
+
return Array.isArray(value) ? value : [value];
|
|
488
|
+
};
|
|
489
|
+
const append = (value, focusOptions) => {
|
|
490
|
+
const values = normalizeToArray(value);
|
|
491
|
+
if (values.length === 0) return;
|
|
492
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
493
|
+
const insertIndex = currentValues.length;
|
|
494
|
+
const rules = fa.rules;
|
|
495
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return;
|
|
496
|
+
const newValues = [...currentValues, ...values];
|
|
293
497
|
set(ctx.formData, name, newValues);
|
|
294
|
-
|
|
498
|
+
const newItems = values.map(() => createItem(generateId()));
|
|
499
|
+
fa.items.value = [...fa.items.value, ...newItems];
|
|
500
|
+
rebuildIndexCache();
|
|
295
501
|
ctx.dirtyFields.value = {
|
|
296
502
|
...ctx.dirtyFields.value,
|
|
297
503
|
[name]: true
|
|
298
504
|
};
|
|
299
505
|
if (ctx.options.mode === "onChange") validate(name);
|
|
506
|
+
handleFocus(insertIndex, values.length, focusOptions);
|
|
300
507
|
};
|
|
301
|
-
const prepend = (value) => {
|
|
302
|
-
|
|
508
|
+
const prepend = (value, focusOptions) => {
|
|
509
|
+
const values = normalizeToArray(value);
|
|
510
|
+
if (values.length === 0) return;
|
|
511
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
512
|
+
const rules = fa.rules;
|
|
513
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return;
|
|
514
|
+
const newValues = [...values, ...currentValues];
|
|
515
|
+
set(ctx.formData, name, newValues);
|
|
516
|
+
const newItems = values.map(() => createItem(generateId()));
|
|
517
|
+
fa.items.value = [...newItems, ...fa.items.value];
|
|
518
|
+
rebuildIndexCache();
|
|
519
|
+
ctx.dirtyFields.value = {
|
|
520
|
+
...ctx.dirtyFields.value,
|
|
521
|
+
[name]: true
|
|
522
|
+
};
|
|
523
|
+
if (ctx.options.mode === "onChange") validate(name);
|
|
524
|
+
handleFocus(0, values.length, focusOptions);
|
|
303
525
|
};
|
|
304
526
|
const update = (index, value) => {
|
|
305
527
|
const currentValues = get(ctx.formData, name) || [];
|
|
@@ -314,38 +536,52 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
314
536
|
if (ctx.options.mode === "onChange") validate(name);
|
|
315
537
|
};
|
|
316
538
|
const removeAt = (index) => {
|
|
317
|
-
const
|
|
539
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
540
|
+
if (index < 0 || index >= currentValues.length) return;
|
|
541
|
+
const rules = fa.rules;
|
|
542
|
+
if (rules?.minLength && currentValues.length - 1 < rules.minLength.value) return;
|
|
543
|
+
const newValues = currentValues.filter((_, i) => i !== index);
|
|
318
544
|
set(ctx.formData, name, newValues);
|
|
319
545
|
const keyToRemove = fa.items.value[index]?.key;
|
|
320
546
|
fa.items.value = fa.items.value.filter((item) => item.key !== keyToRemove);
|
|
547
|
+
rebuildIndexCache();
|
|
321
548
|
ctx.dirtyFields.value = {
|
|
322
549
|
...ctx.dirtyFields.value,
|
|
323
550
|
[name]: true
|
|
324
551
|
};
|
|
325
552
|
if (ctx.options.mode === "onChange") validate(name);
|
|
326
553
|
};
|
|
327
|
-
const insert = (index, value) => {
|
|
554
|
+
const insert = (index, value, focusOptions) => {
|
|
555
|
+
const values = normalizeToArray(value);
|
|
556
|
+
if (values.length === 0) return;
|
|
328
557
|
const currentValues = get(ctx.formData, name) || [];
|
|
558
|
+
const rules = fa.rules;
|
|
559
|
+
if (rules?.maxLength && currentValues.length + values.length > rules.maxLength.value) return;
|
|
560
|
+
const clampedIndex = Math.max(0, Math.min(index, currentValues.length));
|
|
329
561
|
const newValues = [
|
|
330
|
-
...currentValues.slice(0,
|
|
331
|
-
|
|
332
|
-
...currentValues.slice(
|
|
562
|
+
...currentValues.slice(0, clampedIndex),
|
|
563
|
+
...values,
|
|
564
|
+
...currentValues.slice(clampedIndex)
|
|
333
565
|
];
|
|
334
566
|
set(ctx.formData, name, newValues);
|
|
335
|
-
const
|
|
567
|
+
const newItems = values.map(() => createItem(generateId()));
|
|
336
568
|
fa.items.value = [
|
|
337
|
-
...fa.items.value.slice(0,
|
|
338
|
-
|
|
339
|
-
...fa.items.value.slice(
|
|
569
|
+
...fa.items.value.slice(0, clampedIndex),
|
|
570
|
+
...newItems,
|
|
571
|
+
...fa.items.value.slice(clampedIndex)
|
|
340
572
|
];
|
|
573
|
+
rebuildIndexCache();
|
|
341
574
|
ctx.dirtyFields.value = {
|
|
342
575
|
...ctx.dirtyFields.value,
|
|
343
576
|
[name]: true
|
|
344
577
|
};
|
|
345
578
|
if (ctx.options.mode === "onChange") validate(name);
|
|
579
|
+
handleFocus(clampedIndex, values.length, focusOptions);
|
|
346
580
|
};
|
|
347
581
|
const swap = (indexA, indexB) => {
|
|
348
|
-
const
|
|
582
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
583
|
+
if (indexA < 0 || indexB < 0 || indexA >= currentValues.length || indexB >= currentValues.length) return;
|
|
584
|
+
const newValues = [...currentValues];
|
|
349
585
|
[newValues[indexA], newValues[indexB]] = [newValues[indexB], newValues[indexA]];
|
|
350
586
|
set(ctx.formData, name, newValues);
|
|
351
587
|
const newItems = [...fa.items.value];
|
|
@@ -355,6 +591,7 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
355
591
|
newItems[indexA] = itemB;
|
|
356
592
|
newItems[indexB] = itemA;
|
|
357
593
|
fa.items.value = newItems;
|
|
594
|
+
rebuildIndexCache();
|
|
358
595
|
}
|
|
359
596
|
ctx.dirtyFields.value = {
|
|
360
597
|
...ctx.dirtyFields.value,
|
|
@@ -363,17 +600,22 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
363
600
|
if (ctx.options.mode === "onChange") validate(name);
|
|
364
601
|
};
|
|
365
602
|
const move = (from, to) => {
|
|
366
|
-
const
|
|
603
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
604
|
+
if (from < 0 || from >= currentValues.length || to < 0) return;
|
|
605
|
+
const newValues = [...currentValues];
|
|
367
606
|
const [removed] = newValues.splice(from, 1);
|
|
368
607
|
if (removed !== void 0) {
|
|
369
|
-
|
|
608
|
+
const clampedTo = Math.min(to, newValues.length);
|
|
609
|
+
newValues.splice(clampedTo, 0, removed);
|
|
370
610
|
set(ctx.formData, name, newValues);
|
|
371
611
|
}
|
|
372
612
|
const newItems = [...fa.items.value];
|
|
373
613
|
const [removedItem] = newItems.splice(from, 1);
|
|
374
614
|
if (removedItem) {
|
|
375
|
-
|
|
615
|
+
const clampedTo = Math.min(to, newItems.length);
|
|
616
|
+
newItems.splice(clampedTo, 0, removedItem);
|
|
376
617
|
fa.items.value = newItems;
|
|
618
|
+
rebuildIndexCache();
|
|
377
619
|
}
|
|
378
620
|
ctx.dirtyFields.value = {
|
|
379
621
|
...ctx.dirtyFields.value,
|
|
@@ -381,6 +623,17 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
381
623
|
};
|
|
382
624
|
if (ctx.options.mode === "onChange") validate(name);
|
|
383
625
|
};
|
|
626
|
+
const replace = (newValues) => {
|
|
627
|
+
if (!Array.isArray(newValues)) return;
|
|
628
|
+
set(ctx.formData, name, newValues);
|
|
629
|
+
fa.items.value = newValues.map(() => createItem(generateId()));
|
|
630
|
+
rebuildIndexCache();
|
|
631
|
+
ctx.dirtyFields.value = {
|
|
632
|
+
...ctx.dirtyFields.value,
|
|
633
|
+
[name]: true
|
|
634
|
+
};
|
|
635
|
+
if (ctx.options.mode === "onChange") validate(name);
|
|
636
|
+
};
|
|
384
637
|
return {
|
|
385
638
|
value: fa.items.value,
|
|
386
639
|
append,
|
|
@@ -389,31 +642,56 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
389
642
|
insert,
|
|
390
643
|
swap,
|
|
391
644
|
move,
|
|
392
|
-
update
|
|
645
|
+
update,
|
|
646
|
+
replace
|
|
393
647
|
};
|
|
394
648
|
}
|
|
395
649
|
return { fields };
|
|
396
650
|
}
|
|
397
651
|
function useForm(options) {
|
|
398
652
|
const ctx = createFormContext(options);
|
|
399
|
-
const { validate } = createValidation(ctx);
|
|
653
|
+
const { validate, clearAllPendingErrors } = createValidation(ctx);
|
|
400
654
|
const { register, unregister } = createFieldRegistration(ctx, validate);
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
})
|
|
655
|
+
function setFocus(name, focusOptions) {
|
|
656
|
+
const fieldRef = ctx.fieldRefs.get(name);
|
|
657
|
+
if (!fieldRef?.value) return;
|
|
658
|
+
const el = fieldRef.value;
|
|
659
|
+
if (typeof el.focus === "function") {
|
|
660
|
+
el.focus();
|
|
661
|
+
if (focusOptions?.shouldSelect && el instanceof HTMLInputElement && typeof el.select === "function") el.select();
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
const setFocusWrapper = (name) => setFocus(name);
|
|
665
|
+
const { fields } = createFieldArrayManager(ctx, validate, setFocusWrapper);
|
|
666
|
+
const formState = (0, vue.computed)(() => {
|
|
667
|
+
const mergedErrors = {
|
|
668
|
+
...ctx.errors.value,
|
|
669
|
+
...ctx.externalErrors.value
|
|
670
|
+
};
|
|
671
|
+
return {
|
|
672
|
+
errors: mergedErrors,
|
|
673
|
+
isDirty: Object.keys(ctx.dirtyFields.value).some((k) => ctx.dirtyFields.value[k]),
|
|
674
|
+
dirtyFields: ctx.dirtyFields.value,
|
|
675
|
+
isValid: (ctx.submitCount.value > 0 || Object.keys(ctx.touchedFields.value).length > 0) && Object.keys(mergedErrors).length === 0,
|
|
676
|
+
isSubmitting: ctx.isSubmitting.value,
|
|
677
|
+
isLoading: ctx.isLoading.value,
|
|
678
|
+
isReady: !ctx.isLoading.value,
|
|
679
|
+
isValidating: Object.keys(ctx.validatingFields.value).some((k) => ctx.validatingFields.value[k]),
|
|
680
|
+
validatingFields: ctx.validatingFields.value,
|
|
681
|
+
touchedFields: ctx.touchedFields.value,
|
|
682
|
+
submitCount: ctx.submitCount.value,
|
|
683
|
+
defaultValuesError: ctx.defaultValuesError.value,
|
|
684
|
+
isSubmitted: ctx.submitCount.value > 0,
|
|
685
|
+
isSubmitSuccessful: ctx.isSubmitSuccessful.value
|
|
686
|
+
};
|
|
687
|
+
});
|
|
412
688
|
function handleSubmit(onValid, onInvalid) {
|
|
413
689
|
return async (e) => {
|
|
414
690
|
e.preventDefault();
|
|
691
|
+
if (ctx.isSubmitting.value) return;
|
|
415
692
|
ctx.isSubmitting.value = true;
|
|
416
693
|
ctx.submitCount.value++;
|
|
694
|
+
ctx.isSubmitSuccessful.value = false;
|
|
417
695
|
try {
|
|
418
696
|
for (const [name, fieldRef] of ctx.fieldRefs.entries()) {
|
|
419
697
|
const el = fieldRef.value;
|
|
@@ -424,41 +702,60 @@ function useForm(options) {
|
|
|
424
702
|
}
|
|
425
703
|
}
|
|
426
704
|
}
|
|
427
|
-
if (await validate())
|
|
428
|
-
|
|
705
|
+
if (await validate()) {
|
|
706
|
+
await onValid(ctx.formData);
|
|
707
|
+
ctx.isSubmitSuccessful.value = true;
|
|
708
|
+
} else {
|
|
709
|
+
onInvalid?.(formState.value.errors);
|
|
710
|
+
if (options.shouldFocusError !== false) {
|
|
711
|
+
const firstErrorField = Object.keys(formState.value.errors)[0];
|
|
712
|
+
if (firstErrorField) setFocus(firstErrorField);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
429
715
|
} finally {
|
|
430
716
|
ctx.isSubmitting.value = false;
|
|
431
717
|
}
|
|
432
718
|
};
|
|
433
719
|
}
|
|
434
|
-
function setValue(name, value) {
|
|
720
|
+
function setValue(name, value, setValueOptions) {
|
|
435
721
|
set(ctx.formData, name, value);
|
|
436
|
-
ctx.dirtyFields.value = {
|
|
722
|
+
if (setValueOptions?.shouldDirty !== false) ctx.dirtyFields.value = {
|
|
437
723
|
...ctx.dirtyFields.value,
|
|
438
724
|
[name]: true
|
|
439
725
|
};
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
726
|
+
if (setValueOptions?.shouldTouch) ctx.touchedFields.value = {
|
|
727
|
+
...ctx.touchedFields.value,
|
|
728
|
+
[name]: true
|
|
729
|
+
};
|
|
730
|
+
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
731
|
+
const fieldRef = ctx.fieldRefs.get(name);
|
|
732
|
+
if (fieldRef?.value) {
|
|
733
|
+
const el = fieldRef.value;
|
|
734
|
+
if (el.type === "checkbox") el.checked = value;
|
|
735
|
+
else el.value = value;
|
|
736
|
+
}
|
|
445
737
|
}
|
|
446
|
-
if (
|
|
738
|
+
if (setValueOptions?.shouldValidate) validate(name);
|
|
447
739
|
}
|
|
448
740
|
function getValue(name) {
|
|
449
741
|
return get(ctx.formData, name);
|
|
450
742
|
}
|
|
451
743
|
function reset(values, resetOptions) {
|
|
452
744
|
const opts = resetOptions || {};
|
|
745
|
+
ctx.resetGeneration.value++;
|
|
746
|
+
clearAllPendingErrors();
|
|
747
|
+
ctx.validatingFields.value = {};
|
|
453
748
|
if (!opts.keepDefaultValues && values) Object.assign(ctx.defaultValues, values);
|
|
454
749
|
Object.keys(ctx.formData).forEach((key) => delete ctx.formData[key]);
|
|
455
|
-
const
|
|
750
|
+
const sourceValues = values || ctx.defaultValues;
|
|
751
|
+
const newValues = JSON.parse(JSON.stringify(sourceValues));
|
|
456
752
|
Object.assign(ctx.formData, newValues);
|
|
457
753
|
if (!opts.keepErrors) ctx.errors.value = {};
|
|
458
754
|
if (!opts.keepTouched) ctx.touchedFields.value = {};
|
|
459
755
|
if (!opts.keepDirty) ctx.dirtyFields.value = {};
|
|
460
756
|
if (!opts.keepSubmitCount) ctx.submitCount.value = 0;
|
|
461
757
|
if (!opts.keepIsSubmitting) ctx.isSubmitting.value = false;
|
|
758
|
+
if (!opts.keepIsSubmitSuccessful) ctx.isSubmitSuccessful.value = false;
|
|
462
759
|
ctx.fieldArrays.clear();
|
|
463
760
|
for (const [name, fieldRef] of ctx.fieldRefs.entries()) {
|
|
464
761
|
const el = fieldRef.value;
|
|
@@ -469,13 +766,54 @@ function useForm(options) {
|
|
|
469
766
|
}
|
|
470
767
|
}
|
|
471
768
|
}
|
|
472
|
-
function
|
|
769
|
+
function resetField(name, resetFieldOptions) {
|
|
770
|
+
const opts = resetFieldOptions || {};
|
|
771
|
+
ctx.resetGeneration.value++;
|
|
772
|
+
const errorTimer = ctx.errorDelayTimers.get(name);
|
|
773
|
+
if (errorTimer) {
|
|
774
|
+
clearTimeout(errorTimer);
|
|
775
|
+
ctx.errorDelayTimers.delete(name);
|
|
776
|
+
}
|
|
777
|
+
ctx.pendingErrors.delete(name);
|
|
778
|
+
let defaultValue = opts.defaultValue;
|
|
779
|
+
if (defaultValue === void 0) defaultValue = get(ctx.defaultValues, name);
|
|
780
|
+
else set(ctx.defaultValues, name, defaultValue);
|
|
781
|
+
const clonedValue = defaultValue !== void 0 ? JSON.parse(JSON.stringify(defaultValue)) : void 0;
|
|
782
|
+
set(ctx.formData, name, clonedValue);
|
|
783
|
+
if (!opts.keepError) {
|
|
784
|
+
const newErrors = { ...ctx.errors.value };
|
|
785
|
+
for (const key of Object.keys(newErrors)) if (key === name || key.startsWith(`${name}.`)) delete newErrors[key];
|
|
786
|
+
ctx.errors.value = newErrors;
|
|
787
|
+
}
|
|
788
|
+
if (!opts.keepDirty) {
|
|
789
|
+
const newDirty = { ...ctx.dirtyFields.value };
|
|
790
|
+
delete newDirty[name];
|
|
791
|
+
ctx.dirtyFields.value = newDirty;
|
|
792
|
+
}
|
|
793
|
+
if (!opts.keepTouched) {
|
|
794
|
+
const newTouched = { ...ctx.touchedFields.value };
|
|
795
|
+
delete newTouched[name];
|
|
796
|
+
ctx.touchedFields.value = newTouched;
|
|
797
|
+
}
|
|
798
|
+
if (!ctx.fieldOptions.get(name)?.controlled) {
|
|
799
|
+
const fieldRef = ctx.fieldRefs.get(name);
|
|
800
|
+
if (fieldRef?.value) {
|
|
801
|
+
const el = fieldRef.value;
|
|
802
|
+
if (clonedValue !== void 0) if (el.type === "checkbox") el.checked = clonedValue;
|
|
803
|
+
else el.value = clonedValue;
|
|
804
|
+
else if (el.type === "checkbox") el.checked = false;
|
|
805
|
+
else el.value = "";
|
|
806
|
+
}
|
|
807
|
+
}
|
|
808
|
+
}
|
|
809
|
+
function watch$1(name) {
|
|
473
810
|
return (0, vue.computed)(() => {
|
|
474
811
|
if (!name) return ctx.formData;
|
|
475
|
-
if (Array.isArray(name))
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
812
|
+
if (Array.isArray(name)) {
|
|
813
|
+
const result = {};
|
|
814
|
+
for (const n of name) result[n] = get(ctx.formData, n);
|
|
815
|
+
return result;
|
|
816
|
+
}
|
|
479
817
|
return get(ctx.formData, name);
|
|
480
818
|
});
|
|
481
819
|
}
|
|
@@ -533,15 +871,6 @@ function useForm(options) {
|
|
|
533
871
|
}
|
|
534
872
|
return await validate(name);
|
|
535
873
|
}
|
|
536
|
-
function setFocus(name, focusOptions) {
|
|
537
|
-
const fieldRef = ctx.fieldRefs.get(name);
|
|
538
|
-
if (!fieldRef?.value) return;
|
|
539
|
-
const el = fieldRef.value;
|
|
540
|
-
if (typeof el.focus === "function") {
|
|
541
|
-
el.focus();
|
|
542
|
-
if (focusOptions?.shouldSelect && el instanceof HTMLInputElement && typeof el.select === "function") el.select();
|
|
543
|
-
}
|
|
544
|
-
}
|
|
545
874
|
return {
|
|
546
875
|
register,
|
|
547
876
|
unregister,
|
|
@@ -551,7 +880,8 @@ function useForm(options) {
|
|
|
551
880
|
setValue,
|
|
552
881
|
getValue,
|
|
553
882
|
reset,
|
|
554
|
-
|
|
883
|
+
resetField,
|
|
884
|
+
watch: watch$1,
|
|
555
885
|
validate,
|
|
556
886
|
clearErrors,
|
|
557
887
|
setError,
|
|
@@ -633,7 +963,11 @@ function useFormState(options = {}) {
|
|
|
633
963
|
return { [name]: fullState[name] };
|
|
634
964
|
});
|
|
635
965
|
}
|
|
966
|
+
function isFieldError(error) {
|
|
967
|
+
return typeof error === "object" && error !== null && "type" in error && "message" in error && typeof error.type === "string" && typeof error.message === "string";
|
|
968
|
+
}
|
|
636
969
|
exports.FormContextKey = FormContextKey;
|
|
970
|
+
exports.isFieldError = isFieldError;
|
|
637
971
|
exports.provideForm = provideForm;
|
|
638
972
|
exports.useController = useController;
|
|
639
973
|
exports.useForm = useForm;
|