@tanstack/form-core 0.0.9 → 0.0.12
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/build/lib/FieldApi.cjs +307 -0
- package/build/lib/FieldApi.cjs.map +1 -0
- package/build/lib/FieldApi.d.ts +112 -0
- package/build/lib/FieldApi.d.ts.map +1 -0
- package/build/lib/FieldApi.js +305 -0
- package/build/lib/FieldApi.js.map +1 -0
- package/build/lib/FieldApi.legacy.cjs +307 -0
- package/build/lib/FieldApi.legacy.cjs.map +1 -0
- package/build/lib/FieldApi.legacy.js +305 -0
- package/build/lib/FieldApi.legacy.js.map +1 -0
- package/build/lib/FormApi.cjs +248 -0
- package/build/lib/FormApi.cjs.map +1 -0
- package/build/{types → lib}/FormApi.d.ts +16 -11
- package/build/lib/FormApi.d.ts.map +1 -0
- package/build/lib/FormApi.js +246 -0
- package/build/lib/FormApi.js.map +1 -0
- package/build/lib/FormApi.legacy.cjs +248 -0
- package/build/lib/FormApi.legacy.cjs.map +1 -0
- package/build/lib/FormApi.legacy.js +246 -0
- package/build/lib/FormApi.legacy.js.map +1 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.cjs +65 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.cjs.map +1 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.js +56 -0
- package/build/{cjs → lib}/_virtual/_rollupPluginBabelHelpers.js.map +1 -1
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.cjs +65 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.cjs.map +1 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.js +56 -0
- package/build/lib/_virtual/_rollupPluginBabelHelpers.legacy.js.map +1 -0
- package/build/lib/index.cjs +14 -0
- package/build/lib/index.cjs.map +1 -0
- package/build/{types → lib}/index.d.ts +1 -0
- package/build/lib/index.d.ts.map +1 -0
- package/build/lib/index.js +4 -0
- package/build/{cjs → lib}/index.js.map +1 -1
- package/build/lib/index.legacy.cjs +14 -0
- package/build/lib/index.legacy.cjs.map +1 -0
- package/build/lib/index.legacy.js +4 -0
- package/build/lib/index.legacy.js.map +1 -0
- package/build/lib/tests/FieldApi.spec.d.ts +2 -0
- package/build/lib/tests/FieldApi.spec.d.ts.map +1 -0
- package/build/lib/tests/FieldApi.test-d.d.ts +2 -0
- package/build/lib/tests/FieldApi.test-d.d.ts.map +1 -0
- package/build/lib/tests/FormApi.spec.d.ts +2 -0
- package/build/lib/tests/FormApi.spec.d.ts.map +1 -0
- package/build/{cjs/utils.js → lib/utils.cjs} +18 -27
- package/build/lib/utils.cjs.map +1 -0
- package/build/{types → lib}/utils.d.ts +10 -0
- package/build/lib/utils.d.ts.map +1 -0
- package/build/lib/utils.js +77 -0
- package/build/lib/utils.js.map +1 -0
- package/build/lib/utils.legacy.cjs +81 -0
- package/build/lib/utils.legacy.cjs.map +1 -0
- package/build/lib/utils.legacy.js +77 -0
- package/build/lib/utils.legacy.js.map +1 -0
- package/package.json +23 -10
- package/src/FieldApi.ts +190 -138
- package/src/FormApi.ts +84 -118
- package/src/tests/FieldApi.spec.ts +143 -0
- package/src/tests/FieldApi.test-d.ts +41 -0
- package/src/tests/FormApi.spec.ts +216 -0
- package/src/utils.ts +10 -1
- package/build/cjs/FieldApi.js +0 -345
- package/build/cjs/FieldApi.js.map +0 -1
- package/build/cjs/FormApi.js +0 -317
- package/build/cjs/FormApi.js.map +0 -1
- package/build/cjs/_virtual/_rollupPluginBabelHelpers.js +0 -31
- package/build/cjs/index.js +0 -26
- package/build/cjs/utils.js.map +0 -1
- package/build/esm/index.js +0 -724
- package/build/esm/index.js.map +0 -1
- package/build/stats-html.html +0 -2689
- package/build/stats-react.json +0 -190
- package/build/types/FieldApi.d.ts +0 -79
- package/build/types/tests/test.test.d.ts +0 -0
- package/build/umd/index.development.js +0 -785
- package/build/umd/index.development.js.map +0 -1
- package/build/umd/index.production.js +0 -22
- package/build/umd/index.production.js.map +0 -1
- package/src/tests/test.test.tsx +0 -5
package/src/FormApi.ts
CHANGED
|
@@ -17,13 +17,27 @@ export type FormSubmitEvent = Register extends {
|
|
|
17
17
|
export type FormOptions<TData> = {
|
|
18
18
|
defaultValues?: TData
|
|
19
19
|
defaultState?: Partial<FormState<TData>>
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
20
|
+
asyncDebounceMs?: number
|
|
21
|
+
onMount?: (values: TData, formApi: FormApi<TData>) => ValidationError
|
|
22
|
+
onMountAsync?: (
|
|
23
|
+
values: TData,
|
|
24
|
+
formApi: FormApi<TData>,
|
|
25
|
+
) => ValidationError | Promise<ValidationError>
|
|
26
|
+
onMountAsyncDebounceMs?: number
|
|
27
|
+
onChange?: (values: TData, formApi: FormApi<TData>) => ValidationError
|
|
28
|
+
onChangeAsync?: (
|
|
29
|
+
values: TData,
|
|
30
|
+
formApi: FormApi<TData>,
|
|
31
|
+
) => ValidationError | Promise<ValidationError>
|
|
32
|
+
onChangeAsyncDebounceMs?: number
|
|
33
|
+
onBlur?: (values: TData, formApi: FormApi<TData>) => ValidationError
|
|
34
|
+
onBlurAsync?: (
|
|
35
|
+
values: TData,
|
|
36
|
+
formApi: FormApi<TData>,
|
|
37
|
+
) => ValidationError | Promise<ValidationError>
|
|
38
|
+
onBlurAsyncDebounceMs?: number
|
|
39
|
+
onSubmit?: (values: TData, formApi: FormApi<TData>) => any | Promise<any>
|
|
40
|
+
onSubmitInvalid?: (values: TData, formApi: FormApi<TData>) => void
|
|
27
41
|
}
|
|
28
42
|
|
|
29
43
|
export type FieldInfo<TFormData> = {
|
|
@@ -99,12 +113,13 @@ export class FormApi<TFormData> {
|
|
|
99
113
|
getDefaultFormState({
|
|
100
114
|
...opts?.defaultState,
|
|
101
115
|
values: opts?.defaultValues ?? opts?.defaultState?.values,
|
|
102
|
-
isFormValid:
|
|
116
|
+
isFormValid: true,
|
|
103
117
|
}),
|
|
104
118
|
{
|
|
105
|
-
onUpdate: (
|
|
119
|
+
onUpdate: () => {
|
|
120
|
+
let { state } = this.store
|
|
106
121
|
// Computed state
|
|
107
|
-
const fieldMetaValues = Object.values(
|
|
122
|
+
const fieldMetaValues = Object.values(state.fieldMeta) as (
|
|
108
123
|
| FieldMeta
|
|
109
124
|
| undefined
|
|
110
125
|
)[]
|
|
@@ -117,15 +132,15 @@ export class FormApi<TFormData> {
|
|
|
117
132
|
|
|
118
133
|
const isTouched = fieldMetaValues.some((field) => field?.isTouched)
|
|
119
134
|
|
|
120
|
-
const isValidating = isFieldsValidating ||
|
|
121
|
-
const isFormValid = !
|
|
135
|
+
const isValidating = isFieldsValidating || state.isFormValidating
|
|
136
|
+
const isFormValid = !state.formError
|
|
122
137
|
const isValid = isFieldsValid && isFormValid
|
|
123
138
|
const canSubmit =
|
|
124
|
-
(
|
|
125
|
-
(!isValidating && !
|
|
139
|
+
(state.submissionAttempts === 0 && !isTouched) ||
|
|
140
|
+
(!isValidating && !state.isSubmitting && isValid)
|
|
126
141
|
|
|
127
|
-
|
|
128
|
-
...
|
|
142
|
+
state = {
|
|
143
|
+
...state,
|
|
129
144
|
isFieldsValidating,
|
|
130
145
|
isFieldsValid,
|
|
131
146
|
isFormValid,
|
|
@@ -134,10 +149,8 @@ export class FormApi<TFormData> {
|
|
|
134
149
|
isTouched,
|
|
135
150
|
}
|
|
136
151
|
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
this.store.state = next
|
|
140
|
-
this.state = next
|
|
152
|
+
this.store.state = state
|
|
153
|
+
this.state = state
|
|
141
154
|
},
|
|
142
155
|
},
|
|
143
156
|
)
|
|
@@ -151,31 +164,47 @@ export class FormApi<TFormData> {
|
|
|
151
164
|
if (!options) return
|
|
152
165
|
|
|
153
166
|
this.store.batch(() => {
|
|
154
|
-
|
|
155
|
-
options.
|
|
167
|
+
const shouldUpdateValues =
|
|
168
|
+
options.defaultValues &&
|
|
169
|
+
options.defaultValues !== this.options.defaultValues
|
|
170
|
+
|
|
171
|
+
const shouldUpdateState =
|
|
156
172
|
options.defaultState !== this.options.defaultState
|
|
157
|
-
) {
|
|
158
|
-
this.store.setState((prev) => ({
|
|
159
|
-
...prev,
|
|
160
|
-
...options.defaultState,
|
|
161
|
-
}))
|
|
162
|
-
}
|
|
163
173
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
values: options.defaultValues as TFormData,
|
|
168
|
-
}))
|
|
174
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
175
|
+
if (!shouldUpdateValues || !shouldUpdateValues) {
|
|
176
|
+
return
|
|
169
177
|
}
|
|
178
|
+
|
|
179
|
+
this.store.setState(() =>
|
|
180
|
+
getDefaultFormState(
|
|
181
|
+
Object.assign(
|
|
182
|
+
{},
|
|
183
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
184
|
+
shouldUpdateState ? options.defaultState : {},
|
|
185
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
186
|
+
shouldUpdateValues
|
|
187
|
+
? {
|
|
188
|
+
values: options.defaultValues,
|
|
189
|
+
}
|
|
190
|
+
: {},
|
|
191
|
+
),
|
|
192
|
+
),
|
|
193
|
+
)
|
|
170
194
|
})
|
|
171
195
|
|
|
172
196
|
this.options = options
|
|
173
197
|
}
|
|
174
198
|
|
|
175
199
|
reset = () =>
|
|
176
|
-
this.store.setState(() =>
|
|
200
|
+
this.store.setState(() =>
|
|
201
|
+
getDefaultFormState({
|
|
202
|
+
...this.options.defaultState,
|
|
203
|
+
values: this.options.defaultValues ?? this.options.defaultState?.values,
|
|
204
|
+
}),
|
|
205
|
+
)
|
|
177
206
|
|
|
178
|
-
validateAllFields = async () => {
|
|
207
|
+
validateAllFields = async (cause: ValidationCause) => {
|
|
179
208
|
const fieldValidationPromises: Promise<ValidationError>[] = [] as any
|
|
180
209
|
|
|
181
210
|
this.store.batch(() => {
|
|
@@ -187,9 +216,9 @@ export class FormApi<TFormData> {
|
|
|
187
216
|
// Mark them as touched
|
|
188
217
|
instance.setMeta((prev) => ({ ...prev, isTouched: true }))
|
|
189
218
|
// Validate the field
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
219
|
+
fieldValidationPromises.push(
|
|
220
|
+
Promise.resolve().then(() => instance.validate(cause)),
|
|
221
|
+
)
|
|
193
222
|
}
|
|
194
223
|
})
|
|
195
224
|
},
|
|
@@ -199,63 +228,7 @@ export class FormApi<TFormData> {
|
|
|
199
228
|
return Promise.all(fieldValidationPromises)
|
|
200
229
|
}
|
|
201
230
|
|
|
202
|
-
validateForm = async () => {
|
|
203
|
-
const { validate } = this.options
|
|
204
|
-
|
|
205
|
-
if (!validate) {
|
|
206
|
-
return
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
// Use the formValidationCount for all field instances to
|
|
210
|
-
// track freshness of the validation
|
|
211
|
-
this.store.setState((prev) => ({
|
|
212
|
-
...prev,
|
|
213
|
-
isValidating: true,
|
|
214
|
-
formValidationCount: prev.formValidationCount + 1,
|
|
215
|
-
}))
|
|
216
|
-
|
|
217
|
-
const formValidationCount = this.state.formValidationCount
|
|
218
|
-
|
|
219
|
-
const checkLatest = () =>
|
|
220
|
-
formValidationCount === this.state.formValidationCount
|
|
221
|
-
|
|
222
|
-
if (!this.validationMeta.validationPromise) {
|
|
223
|
-
this.validationMeta.validationPromise = new Promise((resolve, reject) => {
|
|
224
|
-
this.validationMeta.validationResolve = resolve
|
|
225
|
-
this.validationMeta.validationReject = reject
|
|
226
|
-
})
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
const doValidation = async () => {
|
|
230
|
-
try {
|
|
231
|
-
const error = await validate(this.state.values, this)
|
|
232
|
-
|
|
233
|
-
if (checkLatest()) {
|
|
234
|
-
this.store.setState((prev) => ({
|
|
235
|
-
...prev,
|
|
236
|
-
isValidating: false,
|
|
237
|
-
error: error
|
|
238
|
-
? typeof error === 'string'
|
|
239
|
-
? error
|
|
240
|
-
: 'Invalid Form Values'
|
|
241
|
-
: null,
|
|
242
|
-
}))
|
|
243
|
-
|
|
244
|
-
this.validationMeta.validationResolve?.(error)
|
|
245
|
-
}
|
|
246
|
-
} catch (err) {
|
|
247
|
-
if (checkLatest()) {
|
|
248
|
-
this.validationMeta.validationReject?.(err)
|
|
249
|
-
}
|
|
250
|
-
} finally {
|
|
251
|
-
delete this.validationMeta.validationPromise
|
|
252
|
-
}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
doValidation()
|
|
256
|
-
|
|
257
|
-
return this.validationMeta.validationPromise
|
|
258
|
-
}
|
|
231
|
+
// validateForm = async () => {}
|
|
259
232
|
|
|
260
233
|
handleSubmit = async (e: FormSubmitEvent) => {
|
|
261
234
|
e.preventDefault()
|
|
@@ -284,21 +257,21 @@ export class FormApi<TFormData> {
|
|
|
284
257
|
}
|
|
285
258
|
|
|
286
259
|
// Validate all fields
|
|
287
|
-
await this.validateAllFields()
|
|
260
|
+
await this.validateAllFields('submit')
|
|
288
261
|
|
|
289
262
|
// Fields are invalid, do not submit
|
|
290
263
|
if (!this.state.isFieldsValid) {
|
|
291
264
|
done()
|
|
292
|
-
this.options.
|
|
265
|
+
this.options.onSubmitInvalid?.(this.state.values, this)
|
|
293
266
|
return
|
|
294
267
|
}
|
|
295
268
|
|
|
296
269
|
// Run validation for the form
|
|
297
|
-
await this.validateForm()
|
|
270
|
+
// await this.validateForm()
|
|
298
271
|
|
|
299
272
|
if (!this.state.isValid) {
|
|
300
273
|
done()
|
|
301
|
-
this.options.
|
|
274
|
+
this.options.onSubmitInvalid?.(this.state.values, this)
|
|
302
275
|
return
|
|
303
276
|
}
|
|
304
277
|
|
|
@@ -327,6 +300,7 @@ export class FormApi<TFormData> {
|
|
|
327
300
|
}
|
|
328
301
|
|
|
329
302
|
getFieldInfo = <TField extends DeepKeys<TFormData>>(field: TField) => {
|
|
303
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
330
304
|
return (this.fieldInfo[field] ||= {
|
|
331
305
|
instances: {},
|
|
332
306
|
})
|
|
@@ -352,28 +326,28 @@ export class FormApi<TFormData> {
|
|
|
352
326
|
updater: Updater<DeepValue<TFormData, TField>>,
|
|
353
327
|
opts?: { touch?: boolean },
|
|
354
328
|
) => {
|
|
355
|
-
const touch = opts?.touch
|
|
329
|
+
const touch = opts?.touch
|
|
356
330
|
|
|
357
331
|
this.store.batch(() => {
|
|
358
|
-
this.store.setState((prev) => {
|
|
359
|
-
return {
|
|
360
|
-
...prev,
|
|
361
|
-
values: setBy(prev.values, field, updater),
|
|
362
|
-
}
|
|
363
|
-
})
|
|
364
|
-
|
|
365
332
|
if (touch) {
|
|
366
333
|
this.setFieldMeta(field, (prev) => ({
|
|
367
334
|
...prev,
|
|
368
335
|
isTouched: true,
|
|
369
336
|
}))
|
|
370
337
|
}
|
|
338
|
+
|
|
339
|
+
this.store.setState((prev) => {
|
|
340
|
+
return {
|
|
341
|
+
...prev,
|
|
342
|
+
values: setBy(prev.values, field, updater),
|
|
343
|
+
}
|
|
344
|
+
})
|
|
371
345
|
})
|
|
372
346
|
}
|
|
373
347
|
|
|
374
348
|
pushFieldValue = <TField extends DeepKeys<TFormData>>(
|
|
375
349
|
field: TField,
|
|
376
|
-
value: DeepValue<TFormData, TField
|
|
350
|
+
value: DeepValue<TFormData, TField>[number],
|
|
377
351
|
opts?: { touch?: boolean },
|
|
378
352
|
) => {
|
|
379
353
|
return this.setFieldValue(
|
|
@@ -386,16 +360,12 @@ export class FormApi<TFormData> {
|
|
|
386
360
|
insertFieldValue = <TField extends DeepKeys<TFormData>>(
|
|
387
361
|
field: TField,
|
|
388
362
|
index: number,
|
|
389
|
-
value: DeepValue<TFormData, TField
|
|
363
|
+
value: DeepValue<TFormData, TField>[number],
|
|
390
364
|
opts?: { touch?: boolean },
|
|
391
365
|
) => {
|
|
392
366
|
this.setFieldValue(
|
|
393
367
|
field,
|
|
394
368
|
(prev) => {
|
|
395
|
-
// invariant( // TODO: bring in invariant
|
|
396
|
-
// Array.isArray(prev),
|
|
397
|
-
// `Cannot insert a field value into a non-array field. Check that this field's existing value is an array: ${field}.`
|
|
398
|
-
// )
|
|
399
369
|
return (prev as DeepValue<TFormData, TField>[]).map((d, i) =>
|
|
400
370
|
i === index ? value : d,
|
|
401
371
|
) as any
|
|
@@ -412,10 +382,6 @@ export class FormApi<TFormData> {
|
|
|
412
382
|
this.setFieldValue(
|
|
413
383
|
field,
|
|
414
384
|
(prev) => {
|
|
415
|
-
// invariant( // TODO: bring in invariant
|
|
416
|
-
// Array.isArray(prev),
|
|
417
|
-
// `Cannot insert a field value into a non-array field. Check that this field's existing value is an array: ${field}.`
|
|
418
|
-
// )
|
|
419
385
|
return (prev as DeepValue<TFormData, TField>[]).filter(
|
|
420
386
|
(_d, i) => i !== index,
|
|
421
387
|
) as any
|
|
@@ -432,7 +398,7 @@ export class FormApi<TFormData> {
|
|
|
432
398
|
this.setFieldValue(field, (prev: any) => {
|
|
433
399
|
const prev1 = prev[index1]!
|
|
434
400
|
const prev2 = prev[index2]!
|
|
435
|
-
return setBy(setBy(prev,
|
|
401
|
+
return setBy(setBy(prev, `${index1}`, prev2), `${index2}`, prev1)
|
|
436
402
|
})
|
|
437
403
|
}
|
|
438
404
|
}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
import { expect } from 'vitest'
|
|
2
|
+
|
|
3
|
+
import { FormApi } from '../FormApi'
|
|
4
|
+
import { FieldApi } from '../FieldApi'
|
|
5
|
+
|
|
6
|
+
describe('field api', () => {
|
|
7
|
+
it('should have an initial value', () => {
|
|
8
|
+
const form = new FormApi({
|
|
9
|
+
defaultValues: {
|
|
10
|
+
name: 'test',
|
|
11
|
+
},
|
|
12
|
+
})
|
|
13
|
+
|
|
14
|
+
const field = new FieldApi({
|
|
15
|
+
form,
|
|
16
|
+
name: 'name',
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
expect(field.getValue()).toBe('test')
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
it('should set a value correctly', () => {
|
|
23
|
+
const form = new FormApi({
|
|
24
|
+
defaultValues: {
|
|
25
|
+
name: 'test',
|
|
26
|
+
},
|
|
27
|
+
})
|
|
28
|
+
|
|
29
|
+
const field = new FieldApi({
|
|
30
|
+
form,
|
|
31
|
+
name: 'name',
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
field.setValue('other')
|
|
35
|
+
|
|
36
|
+
expect(field.getValue()).toBe('other')
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
it('should set a value correctly', () => {
|
|
40
|
+
const form = new FormApi({
|
|
41
|
+
defaultValues: {
|
|
42
|
+
name: 'test',
|
|
43
|
+
},
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
const field = new FieldApi({
|
|
47
|
+
form,
|
|
48
|
+
name: 'name',
|
|
49
|
+
})
|
|
50
|
+
|
|
51
|
+
field.setValue('other')
|
|
52
|
+
|
|
53
|
+
expect(field.getValue()).toBe('other')
|
|
54
|
+
})
|
|
55
|
+
|
|
56
|
+
it('should push an array value correctly', () => {
|
|
57
|
+
const form = new FormApi({
|
|
58
|
+
defaultValues: {
|
|
59
|
+
names: ['one'],
|
|
60
|
+
},
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const field = new FieldApi({
|
|
64
|
+
form,
|
|
65
|
+
name: 'names',
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
field.pushValue('other')
|
|
69
|
+
|
|
70
|
+
expect(field.getValue()).toStrictEqual(['one', 'other'])
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
it('should insert a value into an array value correctly', () => {
|
|
74
|
+
const form = new FormApi({
|
|
75
|
+
defaultValues: {
|
|
76
|
+
names: ['one', 'two'],
|
|
77
|
+
},
|
|
78
|
+
})
|
|
79
|
+
|
|
80
|
+
const field = new FieldApi({
|
|
81
|
+
form,
|
|
82
|
+
name: 'names',
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
field.insertValue(1, 'other')
|
|
86
|
+
|
|
87
|
+
expect(field.getValue()).toStrictEqual(['one', 'other'])
|
|
88
|
+
})
|
|
89
|
+
|
|
90
|
+
it('should remove a value from an array value correctly', () => {
|
|
91
|
+
const form = new FormApi({
|
|
92
|
+
defaultValues: {
|
|
93
|
+
names: ['one', 'two'],
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
|
|
97
|
+
const field = new FieldApi({
|
|
98
|
+
form,
|
|
99
|
+
name: 'names',
|
|
100
|
+
})
|
|
101
|
+
|
|
102
|
+
field.removeValue(1)
|
|
103
|
+
|
|
104
|
+
expect(field.getValue()).toStrictEqual(['one'])
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
it('should swap a value from an array value correctly', () => {
|
|
108
|
+
const form = new FormApi({
|
|
109
|
+
defaultValues: {
|
|
110
|
+
names: ['one', 'two'],
|
|
111
|
+
},
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
const field = new FieldApi({
|
|
115
|
+
form,
|
|
116
|
+
name: 'names',
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
field.swapValues(0, 1)
|
|
120
|
+
|
|
121
|
+
expect(field.getValue()).toStrictEqual(['two', 'one'])
|
|
122
|
+
})
|
|
123
|
+
|
|
124
|
+
it('should get a subfield properly', () => {
|
|
125
|
+
const form = new FormApi({
|
|
126
|
+
defaultValues: {
|
|
127
|
+
names: {
|
|
128
|
+
first: 'one',
|
|
129
|
+
second: 'two',
|
|
130
|
+
},
|
|
131
|
+
},
|
|
132
|
+
})
|
|
133
|
+
|
|
134
|
+
const field = new FieldApi({
|
|
135
|
+
form,
|
|
136
|
+
name: 'names',
|
|
137
|
+
})
|
|
138
|
+
|
|
139
|
+
const subfield = field.getSubField('first')
|
|
140
|
+
|
|
141
|
+
expect(subfield.getValue()).toBe('one')
|
|
142
|
+
})
|
|
143
|
+
})
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { assertType } from 'vitest'
|
|
2
|
+
import { FormApi } from '../FormApi'
|
|
3
|
+
import { FieldApi } from '../FieldApi'
|
|
4
|
+
|
|
5
|
+
it('should type a subfield properly', () => {
|
|
6
|
+
const form = new FormApi({
|
|
7
|
+
defaultValues: {
|
|
8
|
+
names: {
|
|
9
|
+
first: 'one',
|
|
10
|
+
second: 'two',
|
|
11
|
+
},
|
|
12
|
+
} as const,
|
|
13
|
+
})
|
|
14
|
+
|
|
15
|
+
const field = new FieldApi({
|
|
16
|
+
form,
|
|
17
|
+
name: 'names',
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const subfield = field.getSubField('first')
|
|
21
|
+
|
|
22
|
+
assertType<'one'>(subfield.getValue())
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
it('should type onChange properly', () => {
|
|
26
|
+
const form = new FormApi({
|
|
27
|
+
defaultValues: {
|
|
28
|
+
name: 'test',
|
|
29
|
+
},
|
|
30
|
+
} as const)
|
|
31
|
+
|
|
32
|
+
const field = new FieldApi({
|
|
33
|
+
form,
|
|
34
|
+
name: 'name',
|
|
35
|
+
onChange: (value) => {
|
|
36
|
+
assertType<'test'>(value)
|
|
37
|
+
|
|
38
|
+
return undefined
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
})
|