@tanstack/form-core 0.10.0 → 0.10.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/build/legacy/FormApi.cjs +1 -1
- package/build/legacy/FormApi.cjs.map +1 -1
- package/build/legacy/FormApi.js +8 -2
- package/build/legacy/FormApi.js.map +1 -1
- package/build/legacy/index.d.cts +1 -1
- package/build/legacy/index.d.ts +1 -1
- package/build/legacy/utils.cjs +35 -6
- package/build/legacy/utils.cjs.map +1 -1
- package/build/legacy/utils.d.cts +5 -1
- package/build/legacy/utils.d.ts +5 -1
- package/build/legacy/utils.js +34 -6
- package/build/legacy/utils.js.map +1 -1
- package/build/modern/FormApi.cjs +1 -1
- package/build/modern/FormApi.cjs.map +1 -1
- package/build/modern/FormApi.js +8 -2
- package/build/modern/FormApi.js.map +1 -1
- package/build/modern/index.d.cts +1 -1
- package/build/modern/index.d.ts +1 -1
- package/build/modern/utils.cjs +35 -6
- package/build/modern/utils.cjs.map +1 -1
- package/build/modern/utils.d.cts +5 -1
- package/build/modern/utils.d.ts +5 -1
- package/build/modern/utils.js +34 -6
- package/build/modern/utils.js.map +1 -1
- package/package.json +1 -1
- package/src/FormApi.ts +9 -2
- package/src/tests/FormApi.spec.ts +57 -1
- package/src/tests/utils.spec.ts +73 -0
- package/src/utils.ts +42 -6
|
@@ -226,6 +226,63 @@ describe('form api', () => {
|
|
|
226
226
|
expect(form.getFieldValue('names')).toStrictEqual(['one', 'three', 'two'])
|
|
227
227
|
})
|
|
228
228
|
|
|
229
|
+
it('should handle fields inside an array', async () => {
|
|
230
|
+
interface Employee {
|
|
231
|
+
firstName: string
|
|
232
|
+
}
|
|
233
|
+
interface Form {
|
|
234
|
+
employees: Partial<Employee>[]
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
const form = new FormApi<Form, unknown>()
|
|
238
|
+
|
|
239
|
+
const field = new FieldApi({
|
|
240
|
+
form,
|
|
241
|
+
name: 'employees',
|
|
242
|
+
defaultValue: [],
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
field.mount()
|
|
246
|
+
|
|
247
|
+
const fieldInArray = new FieldApi({
|
|
248
|
+
form,
|
|
249
|
+
name: `employees.${0}.firstName`,
|
|
250
|
+
defaultValue: 'Darcy',
|
|
251
|
+
})
|
|
252
|
+
fieldInArray.mount()
|
|
253
|
+
expect(field.state.value.length).toBe(1)
|
|
254
|
+
expect(fieldInArray.getValue()).toBe('Darcy')
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('should handle deleting fields in an array', async () => {
|
|
258
|
+
interface Employee {
|
|
259
|
+
firstName: string
|
|
260
|
+
}
|
|
261
|
+
interface Form {
|
|
262
|
+
employees: Partial<Employee>[]
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
const form = new FormApi<Form, unknown>()
|
|
266
|
+
|
|
267
|
+
const field = new FieldApi({
|
|
268
|
+
form,
|
|
269
|
+
name: 'employees',
|
|
270
|
+
defaultValue: [],
|
|
271
|
+
})
|
|
272
|
+
|
|
273
|
+
field.mount()
|
|
274
|
+
|
|
275
|
+
const fieldInArray = new FieldApi({
|
|
276
|
+
form,
|
|
277
|
+
name: `employees.${0}.firstName`,
|
|
278
|
+
defaultValue: 'Darcy',
|
|
279
|
+
})
|
|
280
|
+
fieldInArray.mount()
|
|
281
|
+
form.deleteField(`employees.${0}.firstName`)
|
|
282
|
+
expect(field.state.value.length).toBe(1)
|
|
283
|
+
expect(Object.keys(field.state.value[0]!).length).toBe(0)
|
|
284
|
+
})
|
|
285
|
+
|
|
229
286
|
it('should not wipe values when updating', () => {
|
|
230
287
|
const form = new FormApi({
|
|
231
288
|
defaultValues: {
|
|
@@ -500,7 +557,6 @@ describe('form api', () => {
|
|
|
500
557
|
|
|
501
558
|
form.mount()
|
|
502
559
|
field.mount()
|
|
503
|
-
|
|
504
560
|
expect(form.state.errors.length).toBe(0)
|
|
505
561
|
field.setValue('other', { touch: true })
|
|
506
562
|
field.validate('blur')
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest'
|
|
2
|
+
import { deleteBy, getBy, setBy } from '../utils'
|
|
3
|
+
|
|
4
|
+
describe('getBy', () => {
|
|
5
|
+
const structure = {
|
|
6
|
+
name: 'Marc',
|
|
7
|
+
kids: [
|
|
8
|
+
{ name: 'Stephen', age: 10 },
|
|
9
|
+
{ name: 'Taylor', age: 15 },
|
|
10
|
+
],
|
|
11
|
+
mother: {
|
|
12
|
+
name: 'Lisa',
|
|
13
|
+
},
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
it('should get subfields by path', () => {
|
|
17
|
+
expect(getBy(structure, 'name')).toBe(structure.name)
|
|
18
|
+
expect(getBy(structure, 'mother.name')).toBe(structure.mother.name)
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it('should get array subfields by path', () => {
|
|
22
|
+
expect(getBy(structure, 'kids.0.name')).toBe(structure.kids[0]!.name)
|
|
23
|
+
expect(getBy(structure, 'kids.0.age')).toBe(structure.kids[0]!.age)
|
|
24
|
+
})
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
describe('setBy', () => {
|
|
28
|
+
const structure = {
|
|
29
|
+
name: 'Marc',
|
|
30
|
+
kids: [
|
|
31
|
+
{ name: 'Stephen', age: 10 },
|
|
32
|
+
{ name: 'Taylor', age: 15 },
|
|
33
|
+
],
|
|
34
|
+
mother: {
|
|
35
|
+
name: 'Lisa',
|
|
36
|
+
},
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
it('should set subfields by path', () => {
|
|
40
|
+
expect(setBy(structure, 'name', 'Lisa').name).toBe('Lisa')
|
|
41
|
+
expect(setBy(structure, 'mother.name', 'Tina').mother.name).toBe('Tina')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
it('should set array subfields by path', () => {
|
|
45
|
+
expect(setBy(structure, 'kids.0.name', 'Taylor').kids[0].name).toBe(
|
|
46
|
+
'Taylor',
|
|
47
|
+
)
|
|
48
|
+
expect(setBy(structure, 'kids.0.age', 20).kids[0].age).toBe(20)
|
|
49
|
+
})
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
describe('deleteBy', () => {
|
|
53
|
+
const structure = {
|
|
54
|
+
name: 'Marc',
|
|
55
|
+
kids: [
|
|
56
|
+
{ name: 'Stephen', age: 10 },
|
|
57
|
+
{ name: 'Taylor', age: 15 },
|
|
58
|
+
],
|
|
59
|
+
mother: {
|
|
60
|
+
name: 'Lisa',
|
|
61
|
+
},
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
it('should delete subfields by path', () => {
|
|
65
|
+
expect(deleteBy(structure, 'name').name).not.toBeDefined()
|
|
66
|
+
expect(deleteBy(structure, 'mother.name').mother.name).not.toBeDefined()
|
|
67
|
+
})
|
|
68
|
+
|
|
69
|
+
it('should delete array subfields by path', () => {
|
|
70
|
+
expect(deleteBy(structure, 'kids.0.name').kids[0].name).not.toBeDefined()
|
|
71
|
+
expect(deleteBy(structure, 'kids.0.age').kids[0].age).not.toBeDefined()
|
|
72
|
+
})
|
|
73
|
+
})
|
package/src/utils.ts
CHANGED
|
@@ -17,8 +17,7 @@ export function functionalUpdate<TInput, TOutput = TInput>(
|
|
|
17
17
|
* Get a value from an object using a path, including dot notation.
|
|
18
18
|
*/
|
|
19
19
|
export function getBy(obj: any, path: any) {
|
|
20
|
-
const
|
|
21
|
-
const pathObj = pathArray
|
|
20
|
+
const pathObj = makePathArray(path)
|
|
22
21
|
return pathObj.reduce((current: any, pathPart: any) => {
|
|
23
22
|
if (typeof current !== 'undefined') {
|
|
24
23
|
return current[pathPart]
|
|
@@ -52,22 +51,59 @@ export function setBy(obj: any, _path: any, updater: Updater<any>) {
|
|
|
52
51
|
}
|
|
53
52
|
}
|
|
54
53
|
|
|
54
|
+
if (Array.isArray(parent) && key !== undefined) {
|
|
55
|
+
const prefix = parent.slice(0, key)
|
|
56
|
+
return [
|
|
57
|
+
...(prefix.length ? prefix : new Array(key)),
|
|
58
|
+
doSet(parent[key]),
|
|
59
|
+
...parent.slice(key + 1),
|
|
60
|
+
]
|
|
61
|
+
}
|
|
62
|
+
return [...new Array(key), doSet()]
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return doSet(obj)
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Delete a field on an object using a path, including dot notation.
|
|
70
|
+
*/
|
|
71
|
+
export function deleteBy(obj: any, _path: any) {
|
|
72
|
+
const path = makePathArray(_path)
|
|
73
|
+
|
|
74
|
+
function doDelete(parent: any): any {
|
|
75
|
+
if (path.length === 1) {
|
|
76
|
+
const finalPath = path[0]!
|
|
77
|
+
const { [finalPath]: remove, ...rest } = parent
|
|
78
|
+
return rest
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
const key = path.shift()
|
|
82
|
+
|
|
83
|
+
if (typeof key === 'string') {
|
|
84
|
+
if (typeof parent === 'object') {
|
|
85
|
+
return {
|
|
86
|
+
...parent,
|
|
87
|
+
[key]: doDelete(parent[key]),
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
|
|
55
92
|
if (typeof key === 'number') {
|
|
56
93
|
if (Array.isArray(parent)) {
|
|
57
94
|
const prefix = parent.slice(0, key)
|
|
58
95
|
return [
|
|
59
96
|
...(prefix.length ? prefix : new Array(key)),
|
|
60
|
-
|
|
97
|
+
doDelete(parent[key]),
|
|
61
98
|
...parent.slice(key + 1),
|
|
62
99
|
]
|
|
63
100
|
}
|
|
64
|
-
return [...new Array(key), doSet()]
|
|
65
101
|
}
|
|
66
102
|
|
|
67
|
-
throw new Error('
|
|
103
|
+
throw new Error('It seems we have created an infinite loop in deleteBy. ')
|
|
68
104
|
}
|
|
69
105
|
|
|
70
|
-
return
|
|
106
|
+
return doDelete(obj)
|
|
71
107
|
}
|
|
72
108
|
|
|
73
109
|
const reFindNumbers0 = /^(\d*)$/gm
|