Skip to content

Commit 9345846

Browse files
lucasveigaferikras
authored andcommitted
Add the merge and removeBatch mutators (#27)
* Add the merge mutator * Add the removeBatch mutator
1 parent 23afa71 commit 9345846

File tree

9 files changed

+152
-0
lines changed

9 files changed

+152
-0
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,10 +50,12 @@ const customer = form.mutators.pop('customers')
5050

5151
- [Mutators](#mutators)
5252
- [`form.mutators.insert(name: string, index: number, value: any) => undefined`](#formmutatorsinsertname-string-index-number-value-any--undefined)
53+
- [`form.mutators.merge(name: string, value: Array<any>) => void`](#formmutatorsmergename-string-value-arrayany--void)
5354
- [`form.mutators.move(name: string, from: number, to: number) => undefined`](#formmutatorsmovename-string-from-number-to-number--undefined)
5455
- [`form.mutators.pop(name: string) => any`](#formmutatorspopname-string--any)
5556
- [`form.mutators.push(name: string, value: any) => void`](#formmutatorspushname-string-value-any--void)
5657
- [`form.mutators.remove(name: string, index: number) => any`](#formmutatorsremovename-string-index-number--any)
58+
- [`form.mutators.removeBatch(name: string, indexes: Array<number>) => undefined`](#formmutatorsremovebatchname-string-indexes-arraynumber--undefined)
5759
- [`form.mutators.shift(name: string) => any`](#formmutatorsshiftname-string--any)
5860
- [`form.mutators.swap(name: string, indexA: number, indexB: number) => void`](#formmutatorsswapname-string-indexa-number-indexb-number--void)
5961
- [`form.mutators.update(name: string, index: number, value: any) => void`](#formmutatorsupdatename-string-index-number-value-any--void)
@@ -67,6 +69,10 @@ const customer = form.mutators.pop('customers')
6769

6870
Inserts a value into the specified index of the array field.
6971

72+
### `form.mutators.merge(name: string, value: Array<any>) => void`
73+
74+
Merges an array at the end of the array field.
75+
7076
### `form.mutators.move(name: string, from: number, to: number) => undefined`
7177

7278
Moves a value from one index to another index in the array field.
@@ -84,6 +90,10 @@ Pushes a value onto the end of an array field.
8490
Removes a value from the specified index of the array field. Returns the removed
8591
value.
8692

93+
### `form.mutators.removeBatch(name: string, indexes: Array<number>) => undefined`
94+
95+
Removes the values at the specified indexes of the array field.
96+
8797
### `form.mutators.shift(name: string) => any`
8898

8999
Removes a value from the beginning of the array field. Returns the value.

src/index.d.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@ const form = createForm({
1515
const mutators: Mutators = (form.mutators as any) as Mutators
1616

1717
mutators.insert('customers', 0, { firstName: '', lastName: '' })
18+
mutators.merge('customers', [{ firstName: '', lastName: '' }, { firstName: '', lastName: '' }])
1819
mutators.move('customers', 0, 1)
1920
const customer = mutators.pop('customers')
2021
mutators.push('customers', { firstName: '', lastName: '' })
22+
mutators.removeBatch('customers', [0])
2123
const removed = mutators.remove('customers', 0)
2224
const shifted = mutators.shift('customers')
2325
mutators.swap('customers', 0, 1)

src/index.d.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import { Mutator } from 'final-form'
22

33
export const insert: Mutator
4+
export const merge: Mutator
45
export const move: Mutator
56
export const pop: Mutator
67
export const push: Mutator
8+
export const removeBatch: Mutator
79
export const remove: Mutator
810
export const shift: Mutator
911
export const swap: Mutator
@@ -12,9 +14,11 @@ export const unshift: Mutator
1214

1315
export interface DefaultType {
1416
insert: Mutator
17+
merge: Mutator
1518
move: Mutator
1619
pop: Mutator
1720
push: Mutator
21+
removeBatch: Mutator
1822
remove: Mutator
1923
shift: Mutator
2024
swap: Mutator
@@ -28,10 +32,12 @@ export default d
2832
/** The shape of the mutators once final-form has bound them to state */
2933
export interface Mutators {
3034
insert: (name: string, index: number, value: any) => void
35+
merge: (name: string, value: Array<any>) => void,
3136
move: (name: string, from: number, to: number) => void
3237
pop: (name: string) => any
3338
push: (name: string, value: any) => void
3439
remove: (name: string, index: number) => any
40+
removeBatch: (name: string, indexes: Array<number>) => any
3541
shift: (name: string) => any
3642
swap: (name: string, indexA: number, indexB: number) => void
3743
update: (name: string, index: number, value: any) => void

src/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,25 @@
11
// @flow
22
import type { Mutator } from 'final-form'
33
import insert from './insert'
4+
import merge from './merge'
45
import move from './move'
56
import pop from './pop'
67
import push from './push'
78
import remove from './remove'
9+
import removeBatch from './removeBatch'
810
import shift from './shift'
911
import swap from './swap'
1012
import unshift from './unshift'
1113
import update from './update'
1214

1315
const mutators: { [string]: Mutator } = {
1416
insert,
17+
merge,
1518
move,
1619
pop,
1720
push,
1821
remove,
22+
removeBatch,
1923
shift,
2024
swap,
2125
unshift,

src/index.js.flow

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,12 @@ declare export default DefaultType
88
/** The shape of the mutators once final-form has bound them to state */
99
export type Mutators = {
1010
insert: (name: string, index: number, value: any) => void,
11+
merge: (name: string, value: Array<any>) => void,
1112
move: (name: string, from: number, to: number) => void,
1213
pop: (name: string) => any,
1314
push: (name: string, value: any) => void,
1415
remove: (name: string, index: number) => any,
16+
removeBatch: (name: string, indexes: Array<number>) => any,
1517
shift: (name: string) => any,
1618
swap: (name: string, indexA: number, indexB: number) => void,
1719
update: (name: string, index: number, value: any) => void,

src/merge.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// @flow
2+
import type { MutableState, Mutator, Tools } from 'final-form'
3+
4+
const merge: Mutator = (
5+
[name, value]: any[],
6+
state: MutableState,
7+
{ changeValue }: Tools
8+
) => {
9+
changeValue(
10+
state,
11+
name,
12+
(array: ?(any[])): any[] => (array ? [...array, ...value] : value)
13+
)
14+
}
15+
16+
export default merge

src/merge.test.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
import merge from './merge'
2+
3+
describe('merge', () => {
4+
const getOp = value => {
5+
const changeValue = jest.fn()
6+
merge(['foo', value], {}, { changeValue })
7+
return changeValue.mock.calls[0][2]
8+
}
9+
10+
it('should call changeValue once', () => {
11+
const changeValue = jest.fn()
12+
const state = {}
13+
const result = merge(['foo', ['bar', 'baz']], state, { changeValue })
14+
expect(result).toBeUndefined()
15+
expect(changeValue).toHaveBeenCalled()
16+
expect(changeValue).toHaveBeenCalledTimes(1)
17+
expect(changeValue.mock.calls[0][0]).toBe(state)
18+
expect(changeValue.mock.calls[0][1]).toBe('foo')
19+
expect(typeof changeValue.mock.calls[0][2]).toBe('function')
20+
})
21+
22+
it('should turn undefined into an array with two values', () => {
23+
const op = getOp(['bar', 'baz'])
24+
const result = op(undefined)
25+
expect(Array.isArray(result)).toBe(true)
26+
expect(result).toEqual(['bar', 'baz'])
27+
})
28+
29+
it('should merge the array at the end of the original array', () => {
30+
const op = getOp(['d', 'e'])
31+
const result = op(['a', 'b', 'c'])
32+
expect(Array.isArray(result)).toBe(true)
33+
expect(result).toEqual(['a', 'b', 'c', 'd', 'e'])
34+
})
35+
})

src/removeBatch.js

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
// @flow
2+
import type { MutableState, Mutator, Tools } from 'final-form'
3+
4+
const removeBatch: Mutator = (
5+
[name, indexes]: any[],
6+
state: MutableState,
7+
{ changeValue }: Tools
8+
) => {
9+
changeValue(
10+
state,
11+
name,
12+
(array: ?(any[])): ?(any[]) => {
13+
if (!array || !indexes) {
14+
return array
15+
}
16+
17+
let mask = new Array(indexes.length)
18+
for (let i = 0; i < indexes.length; i++) {
19+
mask[indexes[i]] = true
20+
}
21+
22+
let offset = 0
23+
for (let i = 0; i < array.length; i++) {
24+
if (mask[i] === undefined) {
25+
array[offset] = array[i]
26+
offset++
27+
}
28+
}
29+
30+
array.length = offset
31+
return array
32+
}
33+
)
34+
}
35+
36+
export default removeBatch

src/removeBatch.test.js

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import removeBatch from './removeBatch'
2+
3+
describe('merge', () => {
4+
const getOp = value => {
5+
const changeValue = jest.fn()
6+
removeBatch(['foo', value], {}, { changeValue })
7+
return changeValue.mock.calls[0][2]
8+
}
9+
10+
it('should call changeValue once', () => {
11+
const changeValue = jest.fn()
12+
const state = {}
13+
const result = removeBatch(['foo', [1, 2]], state, { changeValue })
14+
expect(result).toBeUndefined()
15+
expect(changeValue).toHaveBeenCalled()
16+
expect(changeValue).toHaveBeenCalledTimes(1)
17+
expect(changeValue.mock.calls[0][0]).toBe(state)
18+
expect(changeValue.mock.calls[0][1]).toBe('foo')
19+
expect(typeof changeValue.mock.calls[0][2]).toBe('function')
20+
})
21+
22+
it('should return undefined if array is undefined', () => {
23+
const op = getOp([0, 1])
24+
const result = op(undefined)
25+
expect(result).toBeUndefined()
26+
})
27+
28+
it('should return the original array if no indexes are specified to be removed', () => {
29+
const op = getOp([])
30+
const result = op(['a', 'b', 'c', 'd', 'e'])
31+
expect(Array.isArray(result)).toBe(true)
32+
expect(result).toEqual(['a', 'b', 'c', 'd', 'e'])
33+
})
34+
35+
it('should remove the values at the specified indexes', () => {
36+
const op = getOp([1, 3])
37+
const result = op(['a', 'b', 'c', 'd', 'e'])
38+
expect(Array.isArray(result)).toBe(true)
39+
expect(result).toEqual(['a', 'c', 'e'])
40+
})
41+
})

0 commit comments

Comments
 (0)