Skip to content

Commit 44b1dd0

Browse files
authored
Selection checkbox should always toggle regardless of selectionBehavior (#6526)
1 parent 38d9840 commit 44b1dd0

File tree

3 files changed

+55
-4
lines changed

3 files changed

+55
-4
lines changed

packages/@react-aria/grid/src/useGridSelectionCheckbox.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,8 @@ export function useGridSelectionCheckbox<T, C extends GridCollection<T>>(props:
3131
let isDisabled = !state.selectionManager.canSelectItem(key);
3232
let isSelected = state.selectionManager.isSelected(key);
3333

34-
let onChange = () => manager.select(key);
34+
// Checkbox should always toggle selection, regardless of selectionBehavior.
35+
let onChange = () => manager.toggleSelection(key);
3536

3637
const stringFormatter = useLocalizedStringFormatter(intlMessages, '@react-aria/grid');
3738

packages/react-aria-components/stories/GridList.stories.tsx

Lines changed: 35 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
* governing permissions and limitations under the License.
1111
*/
1212

13-
import {Button, GridList, GridListItem, GridListItemProps} from 'react-aria-components';
13+
import {Button, Checkbox, CheckboxProps, GridList, GridListItem, GridListItemProps} from 'react-aria-components';
1414
import {classNames} from '@react-spectrum/utils';
1515
import React from 'react';
1616
import styles from '../example/index.css';
@@ -47,12 +47,17 @@ const MyGridListItem = (props: GridListItemProps) => {
4747
return (
4848
<GridListItem
4949
{...props}
50-
style={{display: 'flex', alignItems: 'center', justifyContent: 'center'}}
50+
style={{display: 'flex', alignItems: 'center', gap: 8}}
5151
className={({isFocused, isSelected, isHovered}) => classNames(styles, 'item', {
5252
focused: isFocused,
5353
selected: isSelected,
5454
hovered: isHovered
55-
})} />
55+
})}>
56+
{({selectionMode}) => (<>
57+
{selectionMode !== 'none' ? <MyCheckbox slot="selection" /> : null}
58+
{props.children as any}
59+
</>)}
60+
</GridListItem>
5661
);
5762
};
5863

@@ -68,6 +73,33 @@ GridListExample.story = {
6873
keyboardNavigationBehavior: {
6974
control: 'radio',
7075
options: ['arrow', 'tab']
76+
},
77+
selectionMode: {
78+
control: 'radio',
79+
options: ['none', 'single', 'multiple']
80+
},
81+
selectionBehavior: {
82+
control: 'radio',
83+
options: ['toggle', 'replace']
7184
}
7285
}
7386
};
87+
88+
const MyCheckbox = ({children, ...props}: CheckboxProps) => {
89+
return (
90+
<Checkbox {...props}>
91+
{({isIndeterminate}) => (
92+
<>
93+
<div className="checkbox">
94+
<svg viewBox="0 0 18 18" aria-hidden="true">
95+
{isIndeterminate
96+
? <rect x={1} y={7.5} width={15} height={3} />
97+
: <polyline points="1 9 7 14 15 4" />}
98+
</svg>
99+
</div>
100+
{children}
101+
</>
102+
)}
103+
</Checkbox>
104+
);
105+
};

packages/react-aria-components/test/GridList.test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,24 @@ describe('GridList', () => {
334334
expect(document.activeElement).toBe(document.body);
335335
});
336336

337+
it('should support selectionMode="replace" with checkboxes', async () => {
338+
let {getAllByRole} = renderGridList({selectionMode: 'multiple', selectionBehavior: 'replace'});
339+
let items = getAllByRole('row');
340+
341+
await user.click(items[0]);
342+
await user.click(items[1]);
343+
344+
expect(items[0]).toHaveAttribute('aria-selected', 'false');
345+
expect(items[1]).toHaveAttribute('aria-selected', 'true');
346+
expect(items[2]).toHaveAttribute('aria-selected', 'false');
347+
348+
await user.click(within(items[2]).getByRole('checkbox'));
349+
350+
expect(items[0]).toHaveAttribute('aria-selected', 'false');
351+
expect(items[1]).toHaveAttribute('aria-selected', 'true');
352+
expect(items[2]).toHaveAttribute('aria-selected', 'true');
353+
});
354+
337355
describe('drag and drop', () => {
338356
it('should support drag button slot', () => {
339357
let {getAllByRole} = render(<DraggableGridList />);

0 commit comments

Comments
 (0)