@vuehookform/core 0.1.2 → 0.2.7
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 +15 -13
- package/dist/core/formContext.d.ts +10 -1
- 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/vuehookform.cjs +432 -118
- package/dist/vuehookform.js +433 -120
- package/package.json +14 -2
package/dist/vuehookform.cjs
CHANGED
|
@@ -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,27 +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
|
-
|
|
81
|
-
|
|
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,
|
|
82
144
|
options
|
|
83
145
|
};
|
|
84
146
|
}
|
|
@@ -87,6 +149,17 @@ function clearFieldErrors(errors, fieldPath) {
|
|
|
87
149
|
for (const key of Object.keys(newErrors)) if (key === fieldPath || key.startsWith(`${fieldPath}.`)) delete newErrors[key];
|
|
88
150
|
return newErrors;
|
|
89
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
|
+
}
|
|
90
163
|
function groupErrorsByPath(issues) {
|
|
91
164
|
const grouped = /* @__PURE__ */ new Map();
|
|
92
165
|
for (const issue of issues) {
|
|
@@ -100,9 +173,10 @@ function groupErrorsByPath(issues) {
|
|
|
100
173
|
}
|
|
101
174
|
return grouped;
|
|
102
175
|
}
|
|
103
|
-
function createFieldError(errors) {
|
|
176
|
+
function createFieldError(errors, criteriaMode = "firstError") {
|
|
104
177
|
const firstError = errors[0];
|
|
105
178
|
if (!firstError) return "";
|
|
179
|
+
if (criteriaMode === "firstError") return firstError.message;
|
|
106
180
|
if (errors.length === 1) return firstError.message;
|
|
107
181
|
const types = {};
|
|
108
182
|
for (const err of errors) {
|
|
@@ -117,37 +191,89 @@ function createFieldError(errors) {
|
|
|
117
191
|
};
|
|
118
192
|
}
|
|
119
193
|
function createValidation(ctx) {
|
|
120
|
-
|
|
121
|
-
const
|
|
122
|
-
if (
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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;
|
|
126
201
|
}
|
|
127
|
-
const
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
if (
|
|
134
|
-
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
|
+
}
|
|
135
245
|
return true;
|
|
136
246
|
}
|
|
137
|
-
const
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
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));
|
|
141
266
|
return false;
|
|
267
|
+
} finally {
|
|
268
|
+
setValidating(ctx, validatingKey, false);
|
|
142
269
|
}
|
|
143
|
-
const newErrors = {};
|
|
144
|
-
const grouped = groupErrorsByPath(zodErrors);
|
|
145
|
-
for (const [path, errors] of grouped) set(newErrors, path, createFieldError(errors));
|
|
146
|
-
ctx.errors.value = newErrors;
|
|
147
|
-
return false;
|
|
148
270
|
}
|
|
149
|
-
return {
|
|
271
|
+
return {
|
|
272
|
+
validate,
|
|
273
|
+
clearAllPendingErrors
|
|
274
|
+
};
|
|
150
275
|
}
|
|
276
|
+
var validationRequestCounter = 0;
|
|
151
277
|
function createFieldRegistration(ctx, validate) {
|
|
152
278
|
function register(name, registerOptions) {
|
|
153
279
|
let fieldRef = ctx.fieldRefs.get(name);
|
|
@@ -162,11 +288,12 @@ function createFieldRegistration(ctx, validate) {
|
|
|
162
288
|
if (registerOptions) ctx.fieldOptions.set(name, registerOptions);
|
|
163
289
|
let handlers = ctx.fieldHandlers.get(name);
|
|
164
290
|
if (!handlers) {
|
|
165
|
-
const runCustomValidation = async (fieldName, value, requestId) => {
|
|
291
|
+
const runCustomValidation = async (fieldName, value, requestId, resetGenAtStart) => {
|
|
166
292
|
const fieldOpts = ctx.fieldOptions.get(fieldName);
|
|
167
293
|
if (!fieldOpts?.validate || fieldOpts.disabled) return;
|
|
168
294
|
const error = await fieldOpts.validate(value);
|
|
169
295
|
if (requestId !== ctx.validationRequestIds.get(fieldName)) return;
|
|
296
|
+
if (ctx.resetGeneration.value !== resetGenAtStart) return;
|
|
170
297
|
if (error) ctx.errors.value = {
|
|
171
298
|
...ctx.errors.value,
|
|
172
299
|
[fieldName]: error
|
|
@@ -185,21 +312,26 @@ function createFieldRegistration(ctx, validate) {
|
|
|
185
312
|
...ctx.dirtyFields.value,
|
|
186
313
|
[name]: true
|
|
187
314
|
};
|
|
188
|
-
if (ctx.options.mode === "onChange" || ctx.options.mode === "onTouched" && ctx.touchedFields.value[name] || ctx.touchedFields.value[name] && ctx.options.reValidateMode === "onChange")
|
|
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
|
+
}
|
|
189
320
|
const fieldOpts = ctx.fieldOptions.get(name);
|
|
190
321
|
if (fieldOpts?.validate && !fieldOpts.disabled) {
|
|
191
|
-
const requestId =
|
|
322
|
+
const requestId = ++validationRequestCounter;
|
|
192
323
|
ctx.validationRequestIds.set(name, requestId);
|
|
324
|
+
const resetGenAtStart = ctx.resetGeneration.value;
|
|
193
325
|
const debounceMs = fieldOpts.validateDebounce || 0;
|
|
194
326
|
if (debounceMs > 0) {
|
|
195
327
|
const existingTimer = ctx.debounceTimers.get(name);
|
|
196
328
|
if (existingTimer) clearTimeout(existingTimer);
|
|
197
329
|
const timer = setTimeout(() => {
|
|
198
330
|
ctx.debounceTimers.delete(name);
|
|
199
|
-
runCustomValidation(name, value, requestId);
|
|
331
|
+
runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
200
332
|
}, debounceMs);
|
|
201
333
|
ctx.debounceTimers.set(name, timer);
|
|
202
|
-
} else await runCustomValidation(name, value, requestId);
|
|
334
|
+
} else await runCustomValidation(name, value, requestId, resetGenAtStart);
|
|
203
335
|
}
|
|
204
336
|
};
|
|
205
337
|
const onBlur = async (_e) => {
|
|
@@ -207,12 +339,18 @@ function createFieldRegistration(ctx, validate) {
|
|
|
207
339
|
...ctx.touchedFields.value,
|
|
208
340
|
[name]: true
|
|
209
341
|
};
|
|
210
|
-
if (ctx.options.mode === "onBlur" || ctx.options.mode === "onTouched" || ctx.submitCount.value > 0 && ctx.options.reValidateMode === "onBlur")
|
|
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
|
+
}
|
|
211
347
|
};
|
|
212
348
|
const refCallback = (el) => {
|
|
213
349
|
const currentFieldRef = ctx.fieldRefs.get(name);
|
|
214
350
|
if (!currentFieldRef) return;
|
|
215
351
|
const previousEl = currentFieldRef.value;
|
|
352
|
+
if (previousEl === el) return;
|
|
353
|
+
if (previousEl && el) return;
|
|
216
354
|
currentFieldRef.value = el;
|
|
217
355
|
const opts = ctx.fieldOptions.get(name);
|
|
218
356
|
if (el && !opts?.controlled && el instanceof HTMLInputElement) {
|
|
@@ -221,6 +359,12 @@ function createFieldRegistration(ctx, validate) {
|
|
|
221
359
|
else el.value = value;
|
|
222
360
|
}
|
|
223
361
|
if (previousEl && !el) {
|
|
362
|
+
const timer = ctx.debounceTimers.get(name);
|
|
363
|
+
if (timer) {
|
|
364
|
+
clearTimeout(timer);
|
|
365
|
+
ctx.debounceTimers.delete(name);
|
|
366
|
+
}
|
|
367
|
+
ctx.validationRequestIds.delete(name);
|
|
224
368
|
if (opts?.shouldUnregister ?? ctx.options.shouldUnregister ?? false) {
|
|
225
369
|
unset(ctx.formData, name);
|
|
226
370
|
const newErrors = { ...ctx.errors.value };
|
|
@@ -235,12 +379,6 @@ function createFieldRegistration(ctx, validate) {
|
|
|
235
379
|
ctx.fieldRefs.delete(name);
|
|
236
380
|
ctx.fieldOptions.delete(name);
|
|
237
381
|
ctx.fieldHandlers.delete(name);
|
|
238
|
-
const timer = ctx.debounceTimers.get(name);
|
|
239
|
-
if (timer) {
|
|
240
|
-
clearTimeout(timer);
|
|
241
|
-
ctx.debounceTimers.delete(name);
|
|
242
|
-
}
|
|
243
|
-
ctx.validationRequestIds.delete(name);
|
|
244
382
|
}
|
|
245
383
|
}
|
|
246
384
|
};
|
|
@@ -268,7 +406,24 @@ function createFieldRegistration(ctx, validate) {
|
|
|
268
406
|
}) }
|
|
269
407
|
};
|
|
270
408
|
}
|
|
271
|
-
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
|
+
}
|
|
272
427
|
ctx.fieldRefs.delete(name);
|
|
273
428
|
ctx.fieldOptions.delete(name);
|
|
274
429
|
ctx.fieldHandlers.delete(name);
|
|
@@ -284,42 +439,89 @@ function createFieldRegistration(ctx, validate) {
|
|
|
284
439
|
unregister
|
|
285
440
|
};
|
|
286
441
|
}
|
|
287
|
-
function createFieldArrayManager(ctx, validate) {
|
|
288
|
-
function fields(name) {
|
|
442
|
+
function createFieldArrayManager(ctx, validate, setFocus) {
|
|
443
|
+
function fields(name, options) {
|
|
289
444
|
let fieldArray = ctx.fieldArrays.get(name);
|
|
290
445
|
if (!fieldArray) {
|
|
291
446
|
const existingValues = get(ctx.formData, name) || [];
|
|
292
447
|
fieldArray = {
|
|
293
448
|
items: (0, vue.ref)([]),
|
|
294
|
-
values: existingValues
|
|
449
|
+
values: existingValues,
|
|
450
|
+
indexCache: /* @__PURE__ */ new Map(),
|
|
451
|
+
rules: options?.rules
|
|
295
452
|
};
|
|
296
453
|
ctx.fieldArrays.set(name, fieldArray);
|
|
297
454
|
if (!get(ctx.formData, name)) set(ctx.formData, name, []);
|
|
298
|
-
}
|
|
455
|
+
} else if (options?.rules) fieldArray.rules = options.rules;
|
|
299
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
|
+
};
|
|
300
464
|
const createItem = (key) => ({
|
|
301
465
|
key,
|
|
302
466
|
get index() {
|
|
303
|
-
return
|
|
467
|
+
return indexCache.get(key) ?? -1;
|
|
304
468
|
},
|
|
305
469
|
remove() {
|
|
306
|
-
const currentIndex =
|
|
470
|
+
const currentIndex = indexCache.get(key) ?? -1;
|
|
307
471
|
if (currentIndex !== -1) removeAt(currentIndex);
|
|
308
472
|
}
|
|
309
473
|
});
|
|
310
|
-
if (fa.items.value.length === 0 && fa.values.length > 0)
|
|
311
|
-
|
|
312
|
-
|
|
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];
|
|
313
497
|
set(ctx.formData, name, newValues);
|
|
314
|
-
|
|
498
|
+
const newItems = values.map(() => createItem(generateId()));
|
|
499
|
+
fa.items.value = [...fa.items.value, ...newItems];
|
|
500
|
+
rebuildIndexCache();
|
|
315
501
|
ctx.dirtyFields.value = {
|
|
316
502
|
...ctx.dirtyFields.value,
|
|
317
503
|
[name]: true
|
|
318
504
|
};
|
|
319
505
|
if (ctx.options.mode === "onChange") validate(name);
|
|
506
|
+
handleFocus(insertIndex, values.length, focusOptions);
|
|
320
507
|
};
|
|
321
|
-
const prepend = (value) => {
|
|
322
|
-
|
|
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);
|
|
323
525
|
};
|
|
324
526
|
const update = (index, value) => {
|
|
325
527
|
const currentValues = get(ctx.formData, name) || [];
|
|
@@ -334,38 +536,52 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
334
536
|
if (ctx.options.mode === "onChange") validate(name);
|
|
335
537
|
};
|
|
336
538
|
const removeAt = (index) => {
|
|
337
|
-
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);
|
|
338
544
|
set(ctx.formData, name, newValues);
|
|
339
545
|
const keyToRemove = fa.items.value[index]?.key;
|
|
340
546
|
fa.items.value = fa.items.value.filter((item) => item.key !== keyToRemove);
|
|
547
|
+
rebuildIndexCache();
|
|
341
548
|
ctx.dirtyFields.value = {
|
|
342
549
|
...ctx.dirtyFields.value,
|
|
343
550
|
[name]: true
|
|
344
551
|
};
|
|
345
552
|
if (ctx.options.mode === "onChange") validate(name);
|
|
346
553
|
};
|
|
347
|
-
const insert = (index, value) => {
|
|
554
|
+
const insert = (index, value, focusOptions) => {
|
|
555
|
+
const values = normalizeToArray(value);
|
|
556
|
+
if (values.length === 0) return;
|
|
348
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));
|
|
349
561
|
const newValues = [
|
|
350
|
-
...currentValues.slice(0,
|
|
351
|
-
|
|
352
|
-
...currentValues.slice(
|
|
562
|
+
...currentValues.slice(0, clampedIndex),
|
|
563
|
+
...values,
|
|
564
|
+
...currentValues.slice(clampedIndex)
|
|
353
565
|
];
|
|
354
566
|
set(ctx.formData, name, newValues);
|
|
355
|
-
const
|
|
567
|
+
const newItems = values.map(() => createItem(generateId()));
|
|
356
568
|
fa.items.value = [
|
|
357
|
-
...fa.items.value.slice(0,
|
|
358
|
-
|
|
359
|
-
...fa.items.value.slice(
|
|
569
|
+
...fa.items.value.slice(0, clampedIndex),
|
|
570
|
+
...newItems,
|
|
571
|
+
...fa.items.value.slice(clampedIndex)
|
|
360
572
|
];
|
|
573
|
+
rebuildIndexCache();
|
|
361
574
|
ctx.dirtyFields.value = {
|
|
362
575
|
...ctx.dirtyFields.value,
|
|
363
576
|
[name]: true
|
|
364
577
|
};
|
|
365
578
|
if (ctx.options.mode === "onChange") validate(name);
|
|
579
|
+
handleFocus(clampedIndex, values.length, focusOptions);
|
|
366
580
|
};
|
|
367
581
|
const swap = (indexA, indexB) => {
|
|
368
|
-
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];
|
|
369
585
|
[newValues[indexA], newValues[indexB]] = [newValues[indexB], newValues[indexA]];
|
|
370
586
|
set(ctx.formData, name, newValues);
|
|
371
587
|
const newItems = [...fa.items.value];
|
|
@@ -375,6 +591,7 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
375
591
|
newItems[indexA] = itemB;
|
|
376
592
|
newItems[indexB] = itemA;
|
|
377
593
|
fa.items.value = newItems;
|
|
594
|
+
rebuildIndexCache();
|
|
378
595
|
}
|
|
379
596
|
ctx.dirtyFields.value = {
|
|
380
597
|
...ctx.dirtyFields.value,
|
|
@@ -383,17 +600,22 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
383
600
|
if (ctx.options.mode === "onChange") validate(name);
|
|
384
601
|
};
|
|
385
602
|
const move = (from, to) => {
|
|
386
|
-
const
|
|
603
|
+
const currentValues = get(ctx.formData, name) || [];
|
|
604
|
+
if (from < 0 || from >= currentValues.length || to < 0) return;
|
|
605
|
+
const newValues = [...currentValues];
|
|
387
606
|
const [removed] = newValues.splice(from, 1);
|
|
388
607
|
if (removed !== void 0) {
|
|
389
|
-
|
|
608
|
+
const clampedTo = Math.min(to, newValues.length);
|
|
609
|
+
newValues.splice(clampedTo, 0, removed);
|
|
390
610
|
set(ctx.formData, name, newValues);
|
|
391
611
|
}
|
|
392
612
|
const newItems = [...fa.items.value];
|
|
393
613
|
const [removedItem] = newItems.splice(from, 1);
|
|
394
614
|
if (removedItem) {
|
|
395
|
-
|
|
615
|
+
const clampedTo = Math.min(to, newItems.length);
|
|
616
|
+
newItems.splice(clampedTo, 0, removedItem);
|
|
396
617
|
fa.items.value = newItems;
|
|
618
|
+
rebuildIndexCache();
|
|
397
619
|
}
|
|
398
620
|
ctx.dirtyFields.value = {
|
|
399
621
|
...ctx.dirtyFields.value,
|
|
@@ -401,6 +623,17 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
401
623
|
};
|
|
402
624
|
if (ctx.options.mode === "onChange") validate(name);
|
|
403
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
|
+
};
|
|
404
637
|
return {
|
|
405
638
|
value: fa.items.value,
|
|
406
639
|
append,
|
|
@@ -409,31 +642,56 @@ function createFieldArrayManager(ctx, validate) {
|
|
|
409
642
|
insert,
|
|
410
643
|
swap,
|
|
411
644
|
move,
|
|
412
|
-
update
|
|
645
|
+
update,
|
|
646
|
+
replace
|
|
413
647
|
};
|
|
414
648
|
}
|
|
415
649
|
return { fields };
|
|
416
650
|
}
|
|
417
651
|
function useForm(options) {
|
|
418
652
|
const ctx = createFormContext(options);
|
|
419
|
-
const { validate } = createValidation(ctx);
|
|
653
|
+
const { validate, clearAllPendingErrors } = createValidation(ctx);
|
|
420
654
|
const { register, unregister } = createFieldRegistration(ctx, validate);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
})
|
|
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
|
+
});
|
|
432
688
|
function handleSubmit(onValid, onInvalid) {
|
|
433
689
|
return async (e) => {
|
|
434
690
|
e.preventDefault();
|
|
691
|
+
if (ctx.isSubmitting.value) return;
|
|
435
692
|
ctx.isSubmitting.value = true;
|
|
436
693
|
ctx.submitCount.value++;
|
|
694
|
+
ctx.isSubmitSuccessful.value = false;
|
|
437
695
|
try {
|
|
438
696
|
for (const [name, fieldRef] of ctx.fieldRefs.entries()) {
|
|
439
697
|
const el = fieldRef.value;
|
|
@@ -444,41 +702,60 @@ function useForm(options) {
|
|
|
444
702
|
}
|
|
445
703
|
}
|
|
446
704
|
}
|
|
447
|
-
if (await validate())
|
|
448
|
-
|
|
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
|
+
}
|
|
449
715
|
} finally {
|
|
450
716
|
ctx.isSubmitting.value = false;
|
|
451
717
|
}
|
|
452
718
|
};
|
|
453
719
|
}
|
|
454
|
-
function setValue(name, value) {
|
|
720
|
+
function setValue(name, value, setValueOptions) {
|
|
455
721
|
set(ctx.formData, name, value);
|
|
456
|
-
ctx.dirtyFields.value = {
|
|
722
|
+
if (setValueOptions?.shouldDirty !== false) ctx.dirtyFields.value = {
|
|
457
723
|
...ctx.dirtyFields.value,
|
|
458
724
|
[name]: true
|
|
459
725
|
};
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
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
|
+
}
|
|
465
737
|
}
|
|
466
|
-
if (
|
|
738
|
+
if (setValueOptions?.shouldValidate) validate(name);
|
|
467
739
|
}
|
|
468
740
|
function getValue(name) {
|
|
469
741
|
return get(ctx.formData, name);
|
|
470
742
|
}
|
|
471
743
|
function reset(values, resetOptions) {
|
|
472
744
|
const opts = resetOptions || {};
|
|
745
|
+
ctx.resetGeneration.value++;
|
|
746
|
+
clearAllPendingErrors();
|
|
747
|
+
ctx.validatingFields.value = {};
|
|
473
748
|
if (!opts.keepDefaultValues && values) Object.assign(ctx.defaultValues, values);
|
|
474
749
|
Object.keys(ctx.formData).forEach((key) => delete ctx.formData[key]);
|
|
475
|
-
const
|
|
750
|
+
const sourceValues = values || ctx.defaultValues;
|
|
751
|
+
const newValues = JSON.parse(JSON.stringify(sourceValues));
|
|
476
752
|
Object.assign(ctx.formData, newValues);
|
|
477
753
|
if (!opts.keepErrors) ctx.errors.value = {};
|
|
478
754
|
if (!opts.keepTouched) ctx.touchedFields.value = {};
|
|
479
755
|
if (!opts.keepDirty) ctx.dirtyFields.value = {};
|
|
480
756
|
if (!opts.keepSubmitCount) ctx.submitCount.value = 0;
|
|
481
757
|
if (!opts.keepIsSubmitting) ctx.isSubmitting.value = false;
|
|
758
|
+
if (!opts.keepIsSubmitSuccessful) ctx.isSubmitSuccessful.value = false;
|
|
482
759
|
ctx.fieldArrays.clear();
|
|
483
760
|
for (const [name, fieldRef] of ctx.fieldRefs.entries()) {
|
|
484
761
|
const el = fieldRef.value;
|
|
@@ -489,13 +766,54 @@ function useForm(options) {
|
|
|
489
766
|
}
|
|
490
767
|
}
|
|
491
768
|
}
|
|
492
|
-
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) {
|
|
493
810
|
return (0, vue.computed)(() => {
|
|
494
811
|
if (!name) return ctx.formData;
|
|
495
|
-
if (Array.isArray(name))
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
812
|
+
if (Array.isArray(name)) {
|
|
813
|
+
const result = {};
|
|
814
|
+
for (const n of name) result[n] = get(ctx.formData, n);
|
|
815
|
+
return result;
|
|
816
|
+
}
|
|
499
817
|
return get(ctx.formData, name);
|
|
500
818
|
});
|
|
501
819
|
}
|
|
@@ -553,15 +871,6 @@ function useForm(options) {
|
|
|
553
871
|
}
|
|
554
872
|
return await validate(name);
|
|
555
873
|
}
|
|
556
|
-
function setFocus(name, focusOptions) {
|
|
557
|
-
const fieldRef = ctx.fieldRefs.get(name);
|
|
558
|
-
if (!fieldRef?.value) return;
|
|
559
|
-
const el = fieldRef.value;
|
|
560
|
-
if (typeof el.focus === "function") {
|
|
561
|
-
el.focus();
|
|
562
|
-
if (focusOptions?.shouldSelect && el instanceof HTMLInputElement && typeof el.select === "function") el.select();
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
874
|
return {
|
|
566
875
|
register,
|
|
567
876
|
unregister,
|
|
@@ -571,7 +880,8 @@ function useForm(options) {
|
|
|
571
880
|
setValue,
|
|
572
881
|
getValue,
|
|
573
882
|
reset,
|
|
574
|
-
|
|
883
|
+
resetField,
|
|
884
|
+
watch: watch$1,
|
|
575
885
|
validate,
|
|
576
886
|
clearErrors,
|
|
577
887
|
setError,
|
|
@@ -653,7 +963,11 @@ function useFormState(options = {}) {
|
|
|
653
963
|
return { [name]: fullState[name] };
|
|
654
964
|
});
|
|
655
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
|
+
}
|
|
656
969
|
exports.FormContextKey = FormContextKey;
|
|
970
|
+
exports.isFieldError = isFieldError;
|
|
657
971
|
exports.provideForm = provideForm;
|
|
658
972
|
exports.useController = useController;
|
|
659
973
|
exports.useForm = useForm;
|