@tanstack/form-core 0.23.2 → 0.24.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/src/FieldApi.ts CHANGED
@@ -10,6 +10,9 @@ import type {
10
10
  import type { AsyncValidator, SyncValidator, Updater } from './utils'
11
11
  import type { DeepKeys, DeepValue, NoInfer } from './util-types'
12
12
 
13
+ /**
14
+ * @private
15
+ */
13
16
  export type FieldValidateFn<
14
17
  TParentData,
15
18
  TName extends DeepKeys<TParentData>,
@@ -25,6 +28,9 @@ export type FieldValidateFn<
25
28
  fieldApi: FieldApi<TParentData, TName, TFieldValidator, TFormValidator, TData>
26
29
  }) => ValidationError
27
30
 
31
+ /**
32
+ * @private
33
+ */
28
34
  export type FieldValidateOrFn<
29
35
  TParentData,
30
36
  TName extends DeepKeys<TParentData>,
@@ -63,6 +69,9 @@ export type FieldValidateOrFn<
63
69
  TData
64
70
  >
65
71
 
72
+ /**
73
+ * @private
74
+ */
66
75
  export type FieldValidateAsyncFn<
67
76
  TParentData,
68
77
  TName extends DeepKeys<TParentData>,
@@ -79,6 +88,9 @@ export type FieldValidateAsyncFn<
79
88
  signal: AbortSignal
80
89
  }) => ValidationError | Promise<ValidationError>
81
90
 
91
+ /**
92
+ * @private
93
+ */
82
94
  export type FieldAsyncValidateOrFn<
83
95
  TParentData,
84
96
  TName extends DeepKeys<TParentData>,
@@ -128,6 +140,9 @@ export interface FieldValidators<
128
140
  | undefined = undefined,
129
141
  TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
130
142
  > {
143
+ /**
144
+ * An optional function that takes a param of `formApi` which is a generic type of `TData` and `TParentData`
145
+ */
131
146
  onMount?: FieldValidateOrFn<
132
147
  TParentData,
133
148
  TName,
@@ -135,6 +150,12 @@ export interface FieldValidators<
135
150
  TFormValidator,
136
151
  TData
137
152
  >
153
+ /**
154
+ * An optional property that takes a `ValidateFn` which is a generic of `TData` and `TParentData`.
155
+ * If `validatorAdapter` is passed, this may also accept a property from the respective adapter
156
+ *
157
+ * @example `z.string().min(1)` if `zodAdapter` is passed
158
+ */
138
159
  onChange?: FieldValidateOrFn<
139
160
  TParentData,
140
161
  TName,
@@ -142,6 +163,12 @@ export interface FieldValidators<
142
163
  TFormValidator,
143
164
  TData
144
165
  >
166
+ /**
167
+ * An optional property similar to `onChange` but async validation. If `validatorAdapter`
168
+ * is passed, this may also accept a property from the respective adapter
169
+ *
170
+ * @example `z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' })` if `zodAdapter` is passed
171
+ */
145
172
  onChangeAsync?: FieldAsyncValidateOrFn<
146
173
  TParentData,
147
174
  TName,
@@ -149,8 +176,22 @@ export interface FieldValidators<
149
176
  TFormValidator,
150
177
  TData
151
178
  >
179
+ /**
180
+ * An optional number to represent how long the `onChangeAsync` should wait before running
181
+ *
182
+ * If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds
183
+ */
152
184
  onChangeAsyncDebounceMs?: number
185
+ /**
186
+ * An optional list of field names that should trigger this field's `onChange` and `onChangeAsync` events when its value changes
187
+ */
153
188
  onChangeListenTo?: DeepKeys<TParentData>[]
189
+ /**
190
+ * An optional function, that when run when subscribing to blur event of input.
191
+ * If `validatorAdapter` is passed, this may also accept a property from the respective adapter
192
+ *
193
+ * @example `z.string().min(1)` if `zodAdapter` is passed
194
+ */
154
195
  onBlur?: FieldValidateOrFn<
155
196
  TParentData,
156
197
  TName,
@@ -158,6 +199,12 @@ export interface FieldValidators<
158
199
  TFormValidator,
159
200
  TData
160
201
  >
202
+ /**
203
+ * An optional property similar to `onBlur` but async validation. If `validatorAdapter`
204
+ * is passed, this may also accept a property from the respective adapter
205
+ *
206
+ * @example `z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' })` if `zodAdapter` is passed
207
+ */
161
208
  onBlurAsync?: FieldAsyncValidateOrFn<
162
209
  TParentData,
163
210
  TName,
@@ -165,8 +212,23 @@ export interface FieldValidators<
165
212
  TFormValidator,
166
213
  TData
167
214
  >
215
+
216
+ /**
217
+ * An optional number to represent how long the `onBlurAsync` should wait before running
218
+ *
219
+ * If set to a number larger than 0, will debounce the async validation event by this length of time in milliseconds
220
+ */
168
221
  onBlurAsyncDebounceMs?: number
222
+ /**
223
+ * An optional list of field names that should trigger this field's `onBlur` and `onBlurAsync` events when its value changes
224
+ */
169
225
  onBlurListenTo?: DeepKeys<TParentData>[]
226
+ /**
227
+ * An optional function, that when run when subscribing to submit event of input.
228
+ * If `validatorAdapter` is passed, this may also accept a property from the respective adapter
229
+ *
230
+ * @example `z.string().min(1)` if `zodAdapter` is passed
231
+ */
170
232
  onSubmit?: FieldValidateOrFn<
171
233
  TParentData,
172
234
  TName,
@@ -174,6 +236,12 @@ export interface FieldValidators<
174
236
  TFormValidator,
175
237
  TData
176
238
  >
239
+ /**
240
+ * An optional property similar to `onSubmit` but async validation. If `validatorAdapter`
241
+ * is passed, this may also accept a property from the respective adapter
242
+ *
243
+ * @example `z.string().refine(async (val) => val.length > 3, { message: 'Testing 123' })` if `zodAdapter` is passed
244
+ */
177
245
  onSubmitAsync?: FieldAsyncValidateOrFn<
178
246
  TParentData,
179
247
  TName,
@@ -183,6 +251,9 @@ export interface FieldValidators<
183
251
  >
184
252
  }
185
253
 
254
+ /**
255
+ * An object type representing the options for a field in a form.
256
+ */
186
257
  export interface FieldOptions<
187
258
  TParentData,
188
259
  TName extends DeepKeys<TParentData>,
@@ -194,12 +265,29 @@ export interface FieldOptions<
194
265
  | undefined = undefined,
195
266
  TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
196
267
  > {
268
+ /**
269
+ * The field name. The type will be `DeepKeys<TParentData>` to ensure your name is a deep key of the parent dataset.
270
+ */
197
271
  name: TName
272
+ /**
273
+ * An optional default value for the field.
274
+ */
198
275
  defaultValue?: NoInfer<TData>
276
+ /**
277
+ * The default time to debounce async validation if there is not a more specific debounce time passed.
278
+ */
199
279
  asyncDebounceMs?: number
280
+ /**
281
+ * If `true`, always run async validation, even if there are errors emitted during synchronous validation.
282
+ */
200
283
  asyncAlways?: boolean
201
- preserveValue?: boolean
284
+ /**
285
+ * A validator provided by an extension, like `yupValidator` from `@tanstack/yup-form-adapter`
286
+ */
202
287
  validatorAdapter?: TFieldValidator
288
+ /**
289
+ * A list of validators to pass to the field
290
+ */
203
291
  validators?: FieldValidators<
204
292
  TParentData,
205
293
  TName,
@@ -207,9 +295,15 @@ export interface FieldOptions<
207
295
  TFormValidator,
208
296
  TData
209
297
  >
298
+ /**
299
+ * An optional object with default metadata for the field.
300
+ */
210
301
  defaultMeta?: Partial<FieldMeta>
211
302
  }
212
303
 
304
+ /**
305
+ * An object type representing the required options for the FieldApi class.
306
+ */
213
307
  export interface FieldApiOptions<
214
308
  TParentData,
215
309
  TName extends DeepKeys<TParentData>,
@@ -230,25 +324,63 @@ export interface FieldApiOptions<
230
324
  form: FormApi<TParentData, TFormValidator>
231
325
  }
232
326
 
327
+ /**
328
+ * An object type representing the metadata of a field in a form.
329
+ */
233
330
  export type FieldMeta = {
331
+ /**
332
+ * A flag indicating whether the field has been touched.
333
+ */
234
334
  isTouched: boolean
335
+ /**
336
+ * A flag that is `true` if the field's value has not been modified by the user. Opposite of `isDirty`.
337
+ */
235
338
  isPristine: boolean
339
+ /**
340
+ * A flag that is `true` if the field's value has been modified by the user. Opposite of `isPristine`.
341
+ */
236
342
  isDirty: boolean
343
+ /**
344
+ * An array of errors related to the touched state of the field.
345
+ */
237
346
  touchedErrors: ValidationError[]
347
+ /**
348
+ * An array of errors related to the field value.
349
+ */
238
350
  errors: ValidationError[]
351
+ /**
352
+ * A map of errors related to the field value.
353
+ */
239
354
  errorMap: ValidationErrorMap
355
+ /**
356
+ * A flag indicating whether the field is currently being validated.
357
+ */
240
358
  isValidating: boolean
241
359
  }
242
360
 
361
+ /**
362
+ * An object type representing the state of a field.
363
+ */
243
364
  export type FieldState<TData> = {
365
+ /**
366
+ * The current value of the field.
367
+ */
244
368
  value: TData
369
+ /**
370
+ * The current metadata of the field.
371
+ */
245
372
  meta: FieldMeta
246
373
  }
247
374
 
248
- export type ResolveName<TParentData> = unknown extends TParentData
249
- ? string
250
- : DeepKeys<TParentData>
251
-
375
+ /**
376
+ * A class representing the API for managing a form field.
377
+ *
378
+ * Normally, you will not need to create a new `FieldApi` instance directly.
379
+ * Instead, you will use a framework hook/function like `useField` or `createField`
380
+ * to create a new instance for you that uses your framework's reactivity model.
381
+ * However, if you need to create a new instance manually, you can do so by calling
382
+ * the `new FieldApi` constructor.
383
+ */
252
384
  export class FieldApi<
253
385
  TParentData,
254
386
  TName extends DeepKeys<TParentData>,
@@ -260,6 +392,9 @@ export class FieldApi<
260
392
  | undefined = undefined,
261
393
  TData extends DeepValue<TParentData, TName> = DeepValue<TParentData, TName>,
262
394
  > {
395
+ /**
396
+ * A reference to the form API instance.
397
+ */
263
398
  form: FieldApiOptions<
264
399
  TParentData,
265
400
  TName,
@@ -267,7 +402,13 @@ export class FieldApi<
267
402
  TFormValidator,
268
403
  TData
269
404
  >['form']
405
+ /**
406
+ * The field name.
407
+ */
270
408
  name!: DeepKeys<TParentData>
409
+ /**
410
+ * The field options.
411
+ */
271
412
  options: FieldApiOptions<
272
413
  TParentData,
273
414
  TName,
@@ -275,10 +416,22 @@ export class FieldApi<
275
416
  TFormValidator,
276
417
  TData
277
418
  > = {} as any
419
+ /**
420
+ * The field state store.
421
+ */
278
422
  store!: Store<FieldState<TData>>
423
+ /**
424
+ * The current field state.
425
+ */
279
426
  state!: FieldState<TData>
427
+ /**
428
+ * @private
429
+ */
280
430
  prevState!: FieldState<TData>
281
431
 
432
+ /**
433
+ * Initializes a new `FieldApi` instance.
434
+ */
282
435
  constructor(
283
436
  opts: FieldApiOptions<
284
437
  TParentData,
@@ -335,6 +488,9 @@ export class FieldApi<
335
488
  this.options = opts as never
336
489
  }
337
490
 
491
+ /**
492
+ * @private
493
+ */
338
494
  runValidator<
339
495
  TValue extends { value: TData; fieldApi: FieldApi<any, any, any, any> },
340
496
  TType extends 'validate' | 'validateAsync',
@@ -361,6 +517,9 @@ export class FieldApi<
361
517
  return (props.validate as FieldValidateFn<any, any>)(props.value) as never
362
518
  }
363
519
 
520
+ /**
521
+ * Mounts the field instance to the form.
522
+ */
364
523
  mount = () => {
365
524
  const info = this.getInfo()
366
525
  info.instance = this as never
@@ -401,14 +560,13 @@ export class FieldApi<
401
560
  }
402
561
 
403
562
  return () => {
404
- const preserveValue = this.options.preserveValue
405
563
  unsubscribe()
406
- if (!preserveValue) {
407
- this.form.deleteField(this.name)
408
- }
409
564
  }
410
565
  }
411
566
 
567
+ /**
568
+ * Updates the field instance with new options.
569
+ */
412
570
  update = (
413
571
  opts: FieldApiOptions<
414
572
  TParentData,
@@ -438,10 +596,16 @@ export class FieldApi<
438
596
  this.options = opts as never
439
597
  }
440
598
 
599
+ /**
600
+ * Gets the current field value.
601
+ */
441
602
  getValue = (): TData => {
442
603
  return this.form.getFieldValue(this.name) as TData
443
604
  }
444
605
 
606
+ /**
607
+ * Sets the field value and run the `change` validator.
608
+ */
445
609
  setValue = (
446
610
  updater: Updater<TData>,
447
611
  options?: { touch?: boolean; notify?: boolean },
@@ -450,7 +614,14 @@ export class FieldApi<
450
614
  this.validate('change')
451
615
  }
452
616
 
617
+ /**
618
+ * @private
619
+ */
453
620
  _getMeta = () => this.form.getFieldMeta(this.name)
621
+
622
+ /**
623
+ * Gets the current field metadata.
624
+ */
454
625
  getMeta = () =>
455
626
  this._getMeta() ??
456
627
  ({
@@ -464,37 +635,64 @@ export class FieldApi<
464
635
  ...this.options.defaultMeta,
465
636
  } as FieldMeta)
466
637
 
638
+ /**
639
+ * Sets the field metadata.
640
+ */
467
641
  setMeta = (updater: Updater<FieldMeta>) =>
468
642
  this.form.setFieldMeta(this.name, updater)
469
643
 
644
+ /**
645
+ * Gets the field information object.
646
+ */
470
647
  getInfo = () => this.form.getFieldInfo(this.name)
471
648
 
649
+ /**
650
+ * Pushes a new value to the field.
651
+ */
472
652
  pushValue = (
473
653
  value: TData extends any[] ? TData[number] : never,
474
654
  opts?: { touch?: boolean },
475
655
  ) => this.form.pushFieldValue(this.name, value as any, opts)
476
656
 
657
+ /**
658
+ * Inserts a value at the specified index, shifting the subsequent values to the right.
659
+ */
477
660
  insertValue = (
478
661
  index: number,
479
662
  value: TData extends any[] ? TData[number] : never,
480
663
  opts?: { touch?: boolean },
481
664
  ) => this.form.insertFieldValue(this.name, index, value as any, opts)
482
665
 
666
+ /**
667
+ * Replaces a value at the specified index.
668
+ */
483
669
  replaceValue = (
484
670
  index: number,
485
671
  value: TData extends any[] ? TData[number] : never,
486
672
  opts?: { touch?: boolean },
487
673
  ) => this.form.replaceFieldValue(this.name, index, value as any, opts)
488
674
 
675
+ /**
676
+ * Removes a value at the specified index.
677
+ */
489
678
  removeValue = (index: number, opts?: { touch: boolean }) =>
490
679
  this.form.removeFieldValue(this.name, index, opts)
491
680
 
681
+ /**
682
+ * Swaps the values at the specified indices.
683
+ */
492
684
  swapValues = (aIndex: number, bIndex: number, opts?: { touch?: boolean }) =>
493
685
  this.form.swapFieldValues(this.name, aIndex, bIndex, opts)
494
686
 
687
+ /**
688
+ * Moves the value at the first specified index to the second specified index.
689
+ */
495
690
  moveValue = (aIndex: number, bIndex: number, opts?: { touch?: boolean }) =>
496
691
  this.form.moveFieldValues(this.name, aIndex, bIndex, opts)
497
692
 
693
+ /**
694
+ * @private
695
+ */
498
696
  getLinkedFields = (cause: ValidationCause) => {
499
697
  const fields = Object.values(this.form.fieldInfo) as FieldInfo<
500
698
  any,
@@ -520,6 +718,9 @@ export class FieldApi<
520
718
  return linkedFields
521
719
  }
522
720
 
721
+ /**
722
+ * @private
723
+ */
523
724
  validateSync = (cause: ValidationCause) => {
524
725
  const validates = getSyncValidatorArray(cause, this.options)
525
726
 
@@ -597,6 +798,9 @@ export class FieldApi<
597
798
  return { hasErrored }
598
799
  }
599
800
 
801
+ /**
802
+ * @private
803
+ */
600
804
  validateAsync = async (cause: ValidationCause) => {
601
805
  const validates = getAsyncValidatorArray(cause, this.options)
602
806
 
@@ -717,6 +921,9 @@ export class FieldApi<
717
921
  return results.filter(Boolean)
718
922
  }
719
923
 
924
+ /**
925
+ * Validates the field value.
926
+ */
720
927
  validate = (
721
928
  cause: ValidationCause,
722
929
  ): ValidationError[] | Promise<ValidationError[]> => {
@@ -737,10 +944,16 @@ export class FieldApi<
737
944
  return this.validateAsync(cause)
738
945
  }
739
946
 
947
+ /**
948
+ * Handles the change event.
949
+ */
740
950
  handleChange = (updater: Updater<TData>) => {
741
951
  this.setValue(updater, { touch: true })
742
952
  }
743
953
 
954
+ /**
955
+ * Handles the blur event.
956
+ */
744
957
  handleBlur = () => {
745
958
  const prevTouched = this.state.meta.isTouched
746
959
  if (!prevTouched) {