mobx-formly 0.0.1

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/dist/form.js ADDED
@@ -0,0 +1,569 @@
1
+ import { action, computed, makeObservable, observable, observe, runInAction } from 'mobx';
2
+ import { createRef } from 'yummies/mobx';
3
+ import { clone, deleteAtPath, extractValue, getAtPath, isEqual, setAtPath } from './utils.js';
4
+ export class Form {
5
+ /**
6
+ * Current form values.
7
+ *
8
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#values)
9
+ */
10
+ values;
11
+ /**
12
+ * Errors keyed by field path.
13
+ *
14
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#errors)
15
+ */
16
+ errors = {};
17
+ /**
18
+ * Field paths whose values differ from their defaults.
19
+ *
20
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#dirtyfields)
21
+ */
22
+ dirtyFields = {};
23
+ /**
24
+ * Field paths that have been touched.
25
+ *
26
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#touchedfields)
27
+ */
28
+ touchedFields = {};
29
+ /**
30
+ * Field paths that are currently being validated.
31
+ *
32
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#validatingfields)
33
+ */
34
+ validatingFields = {};
35
+ /**
36
+ * Observable state for each registered field.
37
+ *
38
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#fieldstate)
39
+ */
40
+ fieldState = {};
41
+ /**
42
+ * Whether a submission is currently running.
43
+ *
44
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#issubmitting)
45
+ */
46
+ isSubmitting = false;
47
+ /**
48
+ * Whether the form has been submitted at least once.
49
+ *
50
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#issubmitted)
51
+ */
52
+ isSubmitted = false;
53
+ /**
54
+ * Whether the latest submission succeeded.
55
+ *
56
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#issubmitsuccessful)
57
+ */
58
+ isSubmitSuccessful = false;
59
+ /**
60
+ * Number of submission attempts.
61
+ *
62
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#submitcount)
63
+ */
64
+ submitCount = 0;
65
+ /**
66
+ * Refs registered for fields.
67
+ *
68
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#refs)
69
+ */
70
+ refs = new Map();
71
+ defaultValues;
72
+ options;
73
+ fieldOptions = new Map();
74
+ valueObservers;
75
+ observerTimer;
76
+ changedPaths = new Set();
77
+ isMutating = false;
78
+ observerTreeChanged = false;
79
+ activeSubmissions = 0;
80
+ resetVersion = 0;
81
+ validationVersion = 0;
82
+ fieldValidationVersions = new Map();
83
+ constructor(options = {}) {
84
+ this.options = {
85
+ ...options,
86
+ mode: options.mode ?? 'onSubmit',
87
+ reValidateMode: options.reValidateMode ?? 'onChange',
88
+ disabled: options.disabled ?? false,
89
+ };
90
+ this.defaultValues = clone((options.defaultValues ?? {}));
91
+ this.values = clone((options.values ?? options.defaultValues ?? {}));
92
+ makeObservable(this, {
93
+ values: observable.deep,
94
+ errors: observable.shallow,
95
+ dirtyFields: observable.shallow,
96
+ touchedFields: observable.shallow,
97
+ validatingFields: observable.shallow,
98
+ isSubmitting: observable,
99
+ isSubmitted: observable,
100
+ isSubmitSuccessful: observable,
101
+ submitCount: observable,
102
+ disabled: computed,
103
+ fieldState: observable.deep,
104
+ isDirty: computed,
105
+ isValid: computed,
106
+ snapshot: computed,
107
+ register: action,
108
+ unregister: action,
109
+ setValue: action,
110
+ mutate: action,
111
+ setError: action,
112
+ clearErrors: action,
113
+ trigger: action,
114
+ handleSubmit: action,
115
+ reset: action,
116
+ resetField: action,
117
+ setFocus: action,
118
+ });
119
+ }
120
+ /**
121
+ * Whether registered event handlers ignore changes and blur events.
122
+ *
123
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#disabled)
124
+ */
125
+ get disabled() { return this.options.disabled; }
126
+ /**
127
+ * Whether any field is dirty.
128
+ *
129
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#isdirty)
130
+ */
131
+ get isDirty() { return Object.keys(this.dirtyFields).length > 0; }
132
+ /**
133
+ * Whether the form has no errors.
134
+ *
135
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#isvalid)
136
+ */
137
+ get isValid() { return Object.keys(this.errors).length === 0; }
138
+ /**
139
+ * Registers a field and returns its ref and event handlers.
140
+ *
141
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#registername-options)
142
+ */
143
+ register(name, options = {}) {
144
+ const path = name;
145
+ this.fieldOptions.set(path, options);
146
+ let ref = this.refs.get(path);
147
+ if (!ref) {
148
+ ref = createRef();
149
+ this.refs.set(path, ref);
150
+ }
151
+ this.ensureFieldState(path);
152
+ return {
153
+ name: path,
154
+ ref,
155
+ onChange: async (eventOrValue) => {
156
+ if (this.disabled)
157
+ return;
158
+ const value = this.transformValue(extractValue(eventOrValue), options);
159
+ const shouldValidate = this.shouldValidateOnChange(path);
160
+ this.setValue(path, value, { shouldDirty: true, shouldValidate: false });
161
+ if (shouldValidate)
162
+ await this.trigger(path);
163
+ },
164
+ onBlur: async () => {
165
+ if (this.disabled)
166
+ return;
167
+ this.markTouched(path);
168
+ if (this.options.mode === 'onBlur' || this.options.mode === 'all' || (path in this.errors && this.options.reValidateMode === 'onBlur'))
169
+ await this.trigger(path);
170
+ },
171
+ };
172
+ }
173
+ /**
174
+ * Removes a field, its value, and its associated state.
175
+ *
176
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#unregistername)
177
+ */
178
+ unregister(name) {
179
+ const path = name;
180
+ this.fieldValidationVersions.set(path, (this.fieldValidationVersions.get(path) ?? 0) + 1);
181
+ deleteAtPath(this.values, path);
182
+ delete this.errors[path];
183
+ delete this.dirtyFields[path];
184
+ delete this.touchedFields[path];
185
+ delete this.validatingFields[path];
186
+ delete this.fieldState[path];
187
+ this.fieldOptions.delete(path);
188
+ this.refs.delete(path);
189
+ }
190
+ /**
191
+ * Updates a field value and optionally changes its state or validates it.
192
+ *
193
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#setvaluename-value-config)
194
+ */
195
+ setValue(name, value, config = {}) {
196
+ const path = name;
197
+ setAtPath(this.values, path, value);
198
+ this.applyValueChange(path, config);
199
+ }
200
+ /**
201
+ * Groups direct value changes and processes their changed paths together.
202
+ *
203
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#mutatemutator-config)
204
+ */
205
+ mutate(mutator, config = {}) {
206
+ this.ensureValueObservers();
207
+ this.changedPaths.clear();
208
+ this.isMutating = true;
209
+ try {
210
+ mutator();
211
+ }
212
+ finally {
213
+ this.isMutating = false;
214
+ }
215
+ this.scheduleObserverCleanup();
216
+ const paths = [...this.changedPaths];
217
+ for (const path of paths)
218
+ this.applyValueChange(path, { ...config, shouldValidate: false });
219
+ if (paths.length && (config.shouldValidate ?? true)) {
220
+ void this.trigger(paths);
221
+ }
222
+ if (this.observerTreeChanged) {
223
+ this.disposeValueObservers();
224
+ this.observerTreeChanged = false;
225
+ this.ensureValueObservers();
226
+ }
227
+ }
228
+ applyValueChange(path, config) {
229
+ if (config.shouldDirty ?? true)
230
+ this.updateDirty(path);
231
+ if (config.shouldTouch)
232
+ this.markTouched(path);
233
+ if (config.shouldValidate)
234
+ void this.trigger(path);
235
+ }
236
+ ensureValueObservers() {
237
+ if (!this.valueObservers || this.observerTreeChanged) {
238
+ this.disposeValueObservers();
239
+ this.valueObservers = [];
240
+ this.observeValueTree(this.values, '', this.valueObservers);
241
+ this.observerTreeChanged = false;
242
+ }
243
+ this.scheduleObserverCleanup();
244
+ }
245
+ scheduleObserverCleanup() {
246
+ if (this.observerTimer)
247
+ clearTimeout(this.observerTimer);
248
+ this.observerTimer = setTimeout(() => this.disposeValueObservers(), 10 * 60 * 1000);
249
+ const timer = this.observerTimer;
250
+ timer.unref?.();
251
+ }
252
+ disposeValueObservers() {
253
+ for (const dispose of this.valueObservers ?? [])
254
+ dispose();
255
+ this.valueObservers = undefined;
256
+ this.observerTimer = undefined;
257
+ }
258
+ observeValueTree(value, basePath, disposers) {
259
+ if (!value || typeof value !== 'object')
260
+ return;
261
+ if (Array.isArray(value)) {
262
+ disposers.push(observe(value, (change) => {
263
+ if (change.type === 'splice')
264
+ this.observerTreeChanged = true;
265
+ if (this.isMutating && basePath)
266
+ this.changedPaths.add(basePath);
267
+ }));
268
+ }
269
+ else {
270
+ disposers.push(observe(value, (change) => {
271
+ if (change.type === 'update' && (typeof change.newValue === 'object' || typeof change.oldValue === 'object')) {
272
+ this.observerTreeChanged = true;
273
+ }
274
+ if (!this.isMutating)
275
+ return;
276
+ const path = basePath ? `${basePath}.${String(change.name)}` : String(change.name);
277
+ if (path)
278
+ this.changedPaths.add(path);
279
+ }));
280
+ }
281
+ for (const [key, child] of Object.entries(value)) {
282
+ this.observeValueTree(child, basePath ? `${basePath}.${key}` : key, disposers);
283
+ }
284
+ }
285
+ /**
286
+ * Sets an error for a field.
287
+ *
288
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#seterrorname-error)
289
+ */
290
+ setError(name, error) {
291
+ this.applyError(name, error);
292
+ }
293
+ /**
294
+ * Clears one, several, or all field errors.
295
+ *
296
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#clearerrorsname)
297
+ */
298
+ clearErrors(name) {
299
+ if (!name) {
300
+ this.errors = {};
301
+ for (const state of Object.values(this.fieldState))
302
+ if (state)
303
+ this.applyFieldState(state, undefined);
304
+ return;
305
+ }
306
+ for (const path of Array.isArray(name) ? name : [name])
307
+ this.applyError(path, undefined);
308
+ }
309
+ /**
310
+ * Validates one field, several fields, or the complete form.
311
+ *
312
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#triggername)
313
+ */
314
+ async trigger(name) {
315
+ const paths = name ? (Array.isArray(name) ? name : [name]).map(String) : undefined;
316
+ const run = ++this.validationVersion;
317
+ const fieldVersions = new Map();
318
+ for (const path of paths ?? this.fieldOptions.keys()) {
319
+ if (this.fieldOptions.has(path))
320
+ fieldVersions.set(path, this.fieldValidationVersions.get(path) ?? 0);
321
+ }
322
+ for (const path of paths ?? this.fieldOptions.keys()) {
323
+ this.validatingFields[path] = true;
324
+ this.ensureFieldState(path).isValidating = true;
325
+ }
326
+ try {
327
+ const schemaErrors = await this.validateSchema();
328
+ const validationPaths = paths ?? [...new Set([...this.fieldOptions.keys(), ...Object.keys(this.errors), ...Object.keys(schemaErrors)])];
329
+ runInAction(() => {
330
+ for (const path of validationPaths) {
331
+ if (schemaErrors[path] && this.isValidationCurrent(path, run, fieldVersions)) {
332
+ this.applyError(path, schemaErrors[path]);
333
+ }
334
+ }
335
+ });
336
+ for (const path of validationPaths) {
337
+ const ruleError = await this.validateRules(path);
338
+ runInAction(() => {
339
+ if (this.isValidationCurrent(path, run, fieldVersions)) {
340
+ if (ruleError)
341
+ this.applyError(path, ruleError);
342
+ else if (schemaErrors[path])
343
+ this.applyError(path, schemaErrors[path]);
344
+ else
345
+ this.applyError(path, undefined);
346
+ }
347
+ });
348
+ }
349
+ return (paths ?? Object.keys(this.errors)).every((path) => !this.errors[path]);
350
+ }
351
+ finally {
352
+ runInAction(() => {
353
+ if (this.validationVersion === run) {
354
+ for (const path of paths ?? this.fieldOptions.keys()) {
355
+ if (!this.isValidationCurrent(path, run, fieldVersions))
356
+ continue;
357
+ delete this.validatingFields[path];
358
+ this.ensureFieldState(path).isValidating = false;
359
+ }
360
+ }
361
+ });
362
+ }
363
+ }
364
+ /**
365
+ * Creates an asynchronous submit handler with validation and result callbacks.
366
+ *
367
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#handlesubmithandlers)
368
+ */
369
+ handleSubmit({ onValid, onInvalid }) {
370
+ return async () => {
371
+ this.activeSubmissions += 1;
372
+ this.isSubmitting = true;
373
+ this.isSubmitted = true;
374
+ this.submitCount += 1;
375
+ const submissionResetVersion = this.resetVersion;
376
+ try {
377
+ const valid = await this.trigger();
378
+ if (valid) {
379
+ await onValid(this.snapshot, this);
380
+ runInAction(() => {
381
+ if (this.resetVersion === submissionResetVersion)
382
+ this.isSubmitSuccessful = true;
383
+ });
384
+ }
385
+ else {
386
+ await onInvalid?.(this.errors, this);
387
+ runInAction(() => {
388
+ if (this.resetVersion === submissionResetVersion)
389
+ this.isSubmitSuccessful = false;
390
+ });
391
+ }
392
+ }
393
+ finally {
394
+ runInAction(() => {
395
+ this.activeSubmissions -= 1;
396
+ this.isSubmitting = this.activeSubmissions > 0;
397
+ });
398
+ }
399
+ };
400
+ }
401
+ /**
402
+ * Resets values and selected form state.
403
+ *
404
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#resetvalues-options)
405
+ */
406
+ reset(values, options = {}) {
407
+ this.disposeValueObservers();
408
+ this.resetVersion += 1;
409
+ this.validationVersion += 1;
410
+ for (const path of Object.keys(this.validatingFields)) {
411
+ delete this.validatingFields[path];
412
+ const state = this.fieldState[path];
413
+ if (state)
414
+ state.isValidating = false;
415
+ }
416
+ const next = clone((values ?? this.defaultValues));
417
+ this.values = next;
418
+ if (!options.keepDefaultValues && values)
419
+ Object.assign(this.defaultValues, clone(values));
420
+ if (!options.keepDirty)
421
+ this.dirtyFields = {};
422
+ if (!options.keepTouched)
423
+ this.touchedFields = {};
424
+ if (!options.keepErrors) {
425
+ this.errors = {};
426
+ for (const state of Object.values(this.fieldState))
427
+ if (state)
428
+ this.applyFieldState(state, undefined);
429
+ }
430
+ if (!options.keepIsSubmitted) {
431
+ this.isSubmitted = false;
432
+ this.isSubmitSuccessful = false;
433
+ }
434
+ if (!options.keepSubmitCount)
435
+ this.submitCount = 0;
436
+ for (const [path, state] of Object.entries(this.fieldState))
437
+ if (state) {
438
+ state.isDirty = !!this.dirtyFields[path];
439
+ state.isTouched = !!this.touchedFields[path];
440
+ }
441
+ }
442
+ /**
443
+ * Resets one field to its current default value and clears its state.
444
+ *
445
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#resetfieldname)
446
+ */
447
+ resetField(name) {
448
+ const path = name;
449
+ this.fieldValidationVersions.set(path, (this.fieldValidationVersions.get(path) ?? 0) + 1);
450
+ setAtPath(this.values, path, clone(getAtPath(this.defaultValues, path)));
451
+ delete this.errors[path];
452
+ delete this.dirtyFields[path];
453
+ delete this.touchedFields[path];
454
+ delete this.validatingFields[path];
455
+ const state = this.ensureFieldState(path);
456
+ this.applyFieldState(state, undefined);
457
+ state.isDirty = false;
458
+ state.isTouched = false;
459
+ state.isValidating = false;
460
+ }
461
+ /**
462
+ * Focuses a registered field when its ref points to a focusable element.
463
+ *
464
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#setfocusname)
465
+ */
466
+ setFocus(name) { this.refs.get(name)?.current?.focus(); }
467
+ /**
468
+ * Returns a plain copy of the current values.
469
+ *
470
+ * [**Documentation**](https://js2me.github.io/mobx-formly/api/form.html#snapshot)
471
+ */
472
+ get snapshot() { return clone(this.values); }
473
+ markTouched(path) {
474
+ this.touchedFields[path] = true;
475
+ this.ensureFieldState(path).isTouched = true;
476
+ }
477
+ updateDirty(path) {
478
+ if (isEqual(getAtPath(this.values, path), getAtPath(this.defaultValues, path)))
479
+ delete this.dirtyFields[path];
480
+ else
481
+ this.dirtyFields[path] = true;
482
+ this.ensureFieldState(path).isDirty = !!this.dirtyFields[path];
483
+ }
484
+ shouldValidateOnChange(path) { return this.options.mode === 'onChange' || this.options.mode === 'all' || (path in this.errors && this.options.reValidateMode === 'onChange'); }
485
+ isValidationCurrent(path, run, fieldVersions) {
486
+ if (this.validationVersion !== run)
487
+ return false;
488
+ const version = fieldVersions.get(path);
489
+ return version === undefined
490
+ || (this.fieldOptions.has(path) && (this.fieldValidationVersions.get(path) ?? 0) === version);
491
+ }
492
+ transformValue(value, options) {
493
+ if (options.setValueAs)
494
+ return options.setValueAs(value);
495
+ if (options.valueAsNumber)
496
+ return value === '' ? Number.NaN : Number(value);
497
+ if (options.valueAsDate)
498
+ return new Date(String(value));
499
+ return value;
500
+ }
501
+ async validateSchema() {
502
+ if (!this.options.schema)
503
+ return {};
504
+ const schema = this.options.schema;
505
+ if ('safeParseAsync' in schema) {
506
+ const result = await schema.safeParseAsync(this.snapshot);
507
+ if (result.success)
508
+ return {};
509
+ return this.normalizeSchemaErrors(result.error);
510
+ }
511
+ const result = await schema['~run']({ value: this.snapshot, typed: false }, {});
512
+ if (!result.issues?.length)
513
+ return {};
514
+ return this.normalizeSchemaErrors({ issues: result.issues });
515
+ }
516
+ normalizeSchemaErrors(error) {
517
+ return error.issues.reduce((errors, issue) => {
518
+ const path = (issue.path ?? []).map((part) => String(typeof part === 'object' ? part.key : part)).join('.') || 'root';
519
+ if (!errors[path])
520
+ errors[path] = { type: issue.code ?? issue.type ?? 'validation', message: issue.message };
521
+ return errors;
522
+ }, {});
523
+ }
524
+ async validateRules(path) {
525
+ const rules = this.fieldOptions.get(path);
526
+ if (!rules)
527
+ return undefined;
528
+ const value = getAtPath(this.values, path);
529
+ const fail = (type, rule) => typeof rule === 'string' ? { type, message: rule } : { type };
530
+ if (rules.required && (value === undefined || value === null || value === ''))
531
+ return fail('required', rules.required);
532
+ if (rules.minLength && String(value ?? '').length < rules.minLength.value)
533
+ return { type: 'minLength', message: rules.minLength.message };
534
+ if (rules.maxLength && String(value ?? '').length > rules.maxLength.value)
535
+ return { type: 'maxLength', message: rules.maxLength.message };
536
+ if (rules.min && Number(value) < rules.min.value)
537
+ return { type: 'min', message: rules.min.message };
538
+ if (rules.max && Number(value) > rules.max.value)
539
+ return { type: 'max', message: rules.max.message };
540
+ if (rules.pattern && !rules.pattern.value.test(String(value ?? '')))
541
+ return { type: 'pattern', message: rules.pattern.message };
542
+ if (rules.validate) {
543
+ let result;
544
+ try {
545
+ result = await rules.validate(value, this.snapshot);
546
+ }
547
+ catch {
548
+ return { type: 'validate', message: 'Validation failed' };
549
+ }
550
+ if (result !== true)
551
+ return { type: 'validate', message: typeof result === 'string' ? result : undefined };
552
+ }
553
+ return undefined;
554
+ }
555
+ ensureFieldState(path) {
556
+ return (this.fieldState[path] ??= { invalid: false, isDirty: false, isTouched: false, isValidating: false });
557
+ }
558
+ applyFieldState(state, error) {
559
+ state.error = error;
560
+ state.invalid = !!error;
561
+ }
562
+ applyError(path, error) {
563
+ if (error)
564
+ this.errors[path] = error;
565
+ else
566
+ delete this.errors[path];
567
+ this.applyFieldState(this.ensureFieldState(path), error);
568
+ }
569
+ }
@@ -0,0 +1,4 @@
1
+ export { Form } from './form.js';
2
+ export { createForm } from './create-form.js';
3
+ export type { InferredFormValues } from './create-form.js';
4
+ export type { FieldError, FieldErrors, FieldPath, FieldPathValue, FieldState, FieldStateTree, FieldValues, FormOptions, FormSchema, SafeParseFormSchema, SchemaIssue, SchemaOutput, SchemaResult, ValibotFormSchema, ValibotRunResult, RegisterOptions, RegisterReturn, ResetOptions, SetValueConfig, SubmitHandlers, } from './types.js';
package/dist/index.js ADDED
@@ -0,0 +1,2 @@
1
+ export { Form } from './form.js';
2
+ export { createForm } from './create-form.js';
@@ -0,0 +1,48 @@
1
+ import { type Ref } from 'yummies/mobx';
2
+ import type { FieldError, FieldErrors, FieldPath, FieldState, FieldValues, FormOptions, FormState, RegisterOptions, RegisterReturn, ResetOptions, SetValueConfig, SubmitHandlers } from './types.js';
3
+ export declare class Form<T extends FieldValues = FieldValues> {
4
+ values: T;
5
+ errors: FieldErrors<T>;
6
+ dirtyFields: Partial<Record<FieldPath<T>, true>>;
7
+ touchedFields: Partial<Record<FieldPath<T>, true>>;
8
+ validatingFields: Partial<Record<FieldPath<T>, true>>;
9
+ isSubmitting: boolean;
10
+ isSubmitted: boolean;
11
+ isSubmitSuccessful: boolean;
12
+ submitCount: number;
13
+ readonly refs: Map<string, Ref<HTMLElement | null, import("yummies/types").AnyObject>>;
14
+ private readonly defaultValues;
15
+ private readonly options;
16
+ private readonly fieldOptions;
17
+ private readonly listeners;
18
+ constructor(options?: FormOptions<T>);
19
+ get formState(): FormState<T>;
20
+ get isDirty(): boolean;
21
+ get isValid(): boolean;
22
+ register(name: FieldPath<T>, options?: RegisterOptions<T>): RegisterReturn;
23
+ unregister(name: FieldPath<T>): void;
24
+ getValues(): T;
25
+ getValues(name: FieldPath<T>): unknown;
26
+ setValue(name: FieldPath<T>, value: unknown, config?: SetValueConfig): void;
27
+ setError(name: FieldPath<T>, error: FieldError): void;
28
+ clearErrors(name?: FieldPath<T> | FieldPath<T>[]): void;
29
+ getFieldState(name: FieldPath<T>): FieldState;
30
+ trigger(name?: FieldPath<T> | FieldPath<T>[]): Promise<boolean>;
31
+ handleSubmit({ onValid, onInvalid }: SubmitHandlers<T>): () => Promise<void>;
32
+ reset(values?: Partial<T>, options?: ResetOptions): void;
33
+ resetField(name: FieldPath<T>): void;
34
+ setFocus(name: FieldPath<T>): void;
35
+ watch(): T;
36
+ watch(name: FieldPath<T>): unknown;
37
+ subscribe(listener: (values: T, info: {
38
+ name?: string;
39
+ }) => void): () => void;
40
+ private notify;
41
+ private markTouched;
42
+ private updateDirty;
43
+ private shouldValidateOnChange;
44
+ private transformValue;
45
+ private validateSchema;
46
+ private zodErrors;
47
+ private validateRules;
48
+ }