Skip to content

Commit 49faf4a

Browse files
rbuzattorbuzattoLFDanLu
authored
feat: enhance listdata selection methods (#8656)
* add addSelectedKeys and removeSelectedKeys methods to useListData * create tests for new methods to useListData * keep same pattern for reassigning selection variable * rename methods * keep original selection value * remove validation for keys * adding some additional test cases --------- Co-authored-by: rbuzatto <[email protected]> Co-authored-by: Daniel Lu <[email protected]>
1 parent 0173413 commit 49faf4a

File tree

2 files changed

+122
-0
lines changed

2 files changed

+122
-0
lines changed

packages/@react-stately/data/src/useListData.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,12 @@ export interface ListData<T> {
3636
/** Sets the selected keys. */
3737
setSelectedKeys(keys: Selection): void,
3838

39+
/** Adds the given keys to the current selected keys. */
40+
addKeysToSelection(keys: Selection): void,
41+
42+
/** Removes the given keys from the current selected keys. */
43+
removeKeysFromSelection(keys: Selection): void,
44+
3945
/** The current filter text. */
4046
filterText: string,
4147

@@ -175,6 +181,43 @@ export function createListActions<T, C>(opts: CreateListOptions<T, C>, dispatch:
175181
selectedKeys
176182
}));
177183
},
184+
addKeysToSelection(selectedKeys: Selection) {
185+
dispatch(state => {
186+
if (state.selectedKeys === 'all') {
187+
return state;
188+
}
189+
if (selectedKeys === 'all') {
190+
return {
191+
...state,
192+
selectedKeys: 'all'
193+
};
194+
}
195+
196+
return {
197+
...state,
198+
selectedKeys: new Set([...state.selectedKeys, ...selectedKeys])
199+
};
200+
});
201+
},
202+
removeKeysFromSelection(selectedKeys: Selection) {
203+
dispatch(state => {
204+
if (selectedKeys === 'all') {
205+
return {
206+
...state,
207+
selectedKeys: new Set()
208+
};
209+
}
210+
211+
let selection: Selection = state.selectedKeys === 'all' ? new Set(state.items.map(getKey!)) : new Set(state.selectedKeys);
212+
for (let key of selectedKeys) {
213+
selection.delete(key);
214+
}
215+
return {
216+
...state,
217+
selectedKeys: selection
218+
};
219+
});
220+
},
178221
setFilterText(filterText: string) {
179222
dispatch(state => ({
180223
...state,

packages/@react-stately/data/test/useListData.test.js

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,85 @@ describe('useListData', function () {
4444
expect(result.current.selectedKeys).toEqual(new Set(['Sam', 'Julia']));
4545
});
4646

47+
describe('addKeysToSelection', function () {
48+
it('should add selected keys', function () {
49+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: ['Sam']}));
50+
let initialResult = result.current;
51+
52+
act(() => {
53+
result.current.addKeysToSelection(['Julia']);
54+
});
55+
expect(result.current.selectedKeys).not.toBe(initialResult.selectedKeys);
56+
expect(result.current.selectedKeys).toEqual(new Set(['Sam', 'Julia']));
57+
});
58+
59+
it('should support adding "all" to selected keys', function () {
60+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: ['Sam']}));
61+
let initialResult = result.current;
62+
63+
act(() => {
64+
result.current.addKeysToSelection('all');
65+
});
66+
expect(result.current.selectedKeys).not.toBe(initialResult.selectedKeys);
67+
expect(result.current.selectedKeys).toEqual('all');
68+
});
69+
70+
it('should still return "all" if selected keys was already "all"', function () {
71+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: 'all'}));
72+
73+
act(() => {
74+
result.current.addKeysToSelection(['Same']);
75+
});
76+
expect(result.current.selectedKeys).toEqual('all');
77+
});
78+
});
79+
80+
describe('removeKeysFromSelection', function () {
81+
it('should remove all keys', function () {
82+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: ['Sam', 'Julia']}));
83+
let initialResult = result.current;
84+
85+
act(() => {
86+
result.current.removeKeysFromSelection('all');
87+
});
88+
expect(result.current.selectedKeys).not.toBe(initialResult.selectedKeys);
89+
expect(result.current.selectedKeys).toEqual(new Set());
90+
});
91+
92+
it('should remove the selected keys', function () {
93+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: ['Sam', 'Julia']}));
94+
let initialResult = result.current;
95+
96+
act(() => {
97+
result.current.removeKeysFromSelection(['Sam']);
98+
});
99+
expect(result.current.selectedKeys).not.toBe(initialResult.selectedKeys);
100+
expect(result.current.selectedKeys).toEqual(new Set(['Julia']));
101+
});
102+
103+
it('should remove the selected keys from an "all" set', function () {
104+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: 'all'}));
105+
let initialResult = result.current;
106+
107+
act(() => {
108+
result.current.removeKeysFromSelection(['Sam', 'David']);
109+
});
110+
expect(result.current.selectedKeys).not.toBe(initialResult.selectedKeys);
111+
expect(result.current.selectedKeys).toEqual(new Set(['Julia']));
112+
});
113+
114+
it('should support removing "all"', function () {
115+
let {result} = renderHook(() => useListData({initialItems: initial, getKey, initialSelectedKeys: ['Sam', 'Julia']}));
116+
let initialResult = result.current;
117+
118+
act(() => {
119+
result.current.removeKeysFromSelection('all');
120+
});
121+
expect(result.current.selectedKeys).not.toBe(initialResult.selectedKeys);
122+
expect(result.current.selectedKeys).toEqual(new Set([]));
123+
});
124+
});
125+
47126
it('should get an item by key', function () {
48127
let {result} = renderHook(() => useListData({initialItems: initial, getKey}));
49128
expect(result.current.getItem('Sam')).toBe(initial[1]);

0 commit comments

Comments
 (0)