Skip to content

Commit f8bb8ae

Browse files
onx2snowystinger
andauthored
fix: add onAction type to RAC TagGroup (adobe#9222)
* add onAction to type pick * add tests * confirm selection happened * add keyboard tests * fix defaults and split tests on selection behaviour * verified against ListBox --------- Co-authored-by: Robert Snow <rsnow@adobe.com> Co-authored-by: Robert Snow <snowystinger@gmail.com>
1 parent 76931bf commit f8bb8ae

File tree

4 files changed

+81
-8
lines changed

4 files changed

+81
-8
lines changed

packages/@react-aria/tag/src/useTagGroup.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,11 @@ export interface TagGroupAria {
3131
errorMessageProps: DOMAttributes
3232
}
3333

34-
export interface AriaTagGroupProps<T> extends CollectionBase<T>, MultipleSelection, Pick<AriaGridListProps<T>, 'escapeKeyBehavior'>, DOMProps, LabelableProps, AriaLabelingProps, Omit<HelpTextProps, 'errorMessage'> {
35-
/** How multiple selection should behave in the collection. */
34+
export interface AriaTagGroupProps<T> extends CollectionBase<T>, MultipleSelection, Pick<AriaGridListProps<T>, 'escapeKeyBehavior' | 'onAction'>, DOMProps, LabelableProps, AriaLabelingProps, Omit<HelpTextProps, 'errorMessage'> {
35+
/**
36+
* How multiple selection should behave in the collection.
37+
* @default 'toggle'
38+
*/
3639
selectionBehavior?: SelectionBehavior,
3740
/** Whether selection should occur on press up instead of press down. */
3841
shouldSelectOnPressUp?: boolean,

packages/@react-stately/selection/src/useMultipleSelectionState.ts

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,17 @@ function equalSets(setA, setB) {
3131
}
3232

3333
export interface MultipleSelectionStateProps extends MultipleSelection {
34-
/** How multiple selection should behave in the collection. */
34+
/**
35+
* How multiple selection should behave in the collection.
36+
* @default 'toggle'
37+
*/
3538
selectionBehavior?: SelectionBehavior,
3639
/** Whether onSelectionChange should fire even if the new set of keys is the same as the last. */
3740
allowDuplicateSelectionEvents?: boolean,
38-
/** Whether `disabledKeys` applies to all interactions, or only selection. */
41+
/**
42+
* Whether `disabledKeys` applies to all interactions, or only selection.
43+
* @default 'all'
44+
*/
3945
disabledBehavior?: DisabledBehavior
4046
}
4147

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

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1199,7 +1199,7 @@ describe('ListBox', () => {
11991199
it('should support dropping into an empty ListBox with a ListBoxLoadMoreItem', () => {
12001200
let onRootDrop = jest.fn();
12011201
let onLoadMore = jest.fn();
1202-
1202+
12031203
let EmptyListBoxWithLoader = (props) => {
12041204
let {dragAndDropHooks} = useDragAndDrop({
12051205
getItems: (keys) => [...keys].map((key) => ({'text/plain': key})),
@@ -1210,7 +1210,7 @@ describe('ListBox', () => {
12101210
<ListBox aria-label="Empty ListBox" dragAndDropHooks={dragAndDropHooks} {...props}>
12111211
<Collection items={[]}>
12121212
{(item) => <ListBoxItem id={item.id}>{item.name}</ListBoxItem>}
1213-
</Collection>
1213+
</Collection>
12141214
<ListBoxLoadMoreItem isLoading onLoadMore={onLoadMore} />
12151215
</ListBox>
12161216
);
@@ -1235,7 +1235,7 @@ describe('ListBox', () => {
12351235

12361236
let listboxes = getAllByRole('listbox');
12371237
let options = getAllByRole('option');
1238-
1238+
12391239
// Start dragging from first listbox
12401240
let dataTransfer = new DataTransfer();
12411241
fireEvent(options[0], new DragEvent('dragstart', {dataTransfer, clientX: 5, clientY: 5}));
@@ -1244,7 +1244,7 @@ describe('ListBox', () => {
12441244
// Drag over the empty listbox (which only has a loader)
12451245
fireEvent(listboxes[1], new DragEvent('dragenter', {dataTransfer, clientX: 50, clientY: 50}));
12461246
fireEvent(listboxes[1], new DragEvent('dragover', {dataTransfer, clientX: 50, clientY: 50}));
1247-
1247+
12481248
expect(listboxes[1]).toHaveAttribute('data-drop-target', 'true');
12491249

12501250
// Drop on the empty listbox

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

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -572,6 +572,70 @@ describe('TagGroup', () => {
572572
expect(onRemove).toHaveBeenLastCalledWith(new Set(['dog']));
573573
});
574574

575+
it('should support onAction', async () => {
576+
let onAction = jest.fn();
577+
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'none'});
578+
let items = getAllByRole('row');
579+
580+
await user.click(items[0]);
581+
expect(onAction).toHaveBeenCalledTimes(1);
582+
onAction.mockReset();
583+
584+
await user.keyboard('{Enter}');
585+
expect(onAction).toHaveBeenCalledTimes(1);
586+
});
587+
588+
it('should support onAction with selectionMode = single, behaviour = replace', async () => {
589+
let onAction = jest.fn();
590+
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'single', selectionBehavior: 'replace'});
591+
let items = getAllByRole('row');
592+
593+
await user.dblClick(items[0]);
594+
expect(onAction).toHaveBeenCalledTimes(1);
595+
onAction.mockReset();
596+
597+
await user.click(items[1]);
598+
expect(onAction).not.toHaveBeenCalled();
599+
expect(items[1]).toHaveAttribute('aria-selected', 'true');
600+
601+
await user.dblClick(items[0]);
602+
expect(onAction).toHaveBeenCalledTimes(1);
603+
expect(items[0]).toHaveAttribute('aria-selected', 'false');
604+
expect(items[1]).toHaveAttribute('aria-selected', 'false');
605+
onAction.mockReset();
606+
607+
await user.keyboard('{Enter}');
608+
expect(onAction).toHaveBeenCalledTimes(1);
609+
expect(items[0]).toHaveAttribute('aria-selected', 'false');
610+
expect(items[1]).toHaveAttribute('aria-selected', 'false');
611+
});
612+
613+
it('should support onAction with selectionMode = multiple, behaviour = replace', async () => {
614+
let onAction = jest.fn();
615+
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'multiple', selectionBehavior: 'replace'});
616+
let items = getAllByRole('row');
617+
618+
await user.dblClick(items[0]);
619+
expect(onAction).toHaveBeenCalledTimes(1);
620+
onAction.mockReset();
621+
622+
await user.click(items[1]);
623+
expect(onAction).not.toHaveBeenCalled();
624+
onAction.mockReset();
625+
expect(items[1]).toHaveAttribute('aria-selected', 'true');
626+
627+
await user.dblClick(items[0]);
628+
expect(onAction).toHaveBeenCalledTimes(1);
629+
expect(items[0]).toHaveAttribute('aria-selected', 'true');
630+
expect(items[1]).toHaveAttribute('aria-selected', 'false');
631+
onAction.mockReset();
632+
633+
await user.keyboard('{Enter}');
634+
expect(onAction).toHaveBeenCalledTimes(1);
635+
expect(items[0]).toHaveAttribute('aria-selected', 'true');
636+
expect(items[1]).toHaveAttribute('aria-selected', 'false');
637+
});
638+
575639
describe('shouldSelectOnPressUp', () => {
576640
it('should select an item on pressing down when shouldSelectOnPressUp is not provided', async () => {
577641
let onSelectionChange = jest.fn();

0 commit comments

Comments
 (0)