Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions packages/@react-aria/tag/src/useTagGroup.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,11 @@ export interface TagGroupAria {
errorMessageProps: DOMAttributes
}

export interface AriaTagGroupProps<T> extends CollectionBase<T>, MultipleSelection, Pick<AriaGridListProps<T>, 'escapeKeyBehavior'>, DOMProps, LabelableProps, AriaLabelingProps, Omit<HelpTextProps, 'errorMessage'> {
/** How multiple selection should behave in the collection. */
export interface AriaTagGroupProps<T> extends CollectionBase<T>, MultipleSelection, Pick<AriaGridListProps<T>, 'escapeKeyBehavior' | 'onAction'>, DOMProps, LabelableProps, AriaLabelingProps, Omit<HelpTextProps, 'errorMessage'> {
/**
* How multiple selection should behave in the collection.
* @default 'toggle'
*/
selectionBehavior?: SelectionBehavior,
/** Whether selection should occur on press up instead of press down. */
shouldSelectOnPressUp?: boolean,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,11 +31,17 @@ function equalSets(setA, setB) {
}

export interface MultipleSelectionStateProps extends MultipleSelection {
/** How multiple selection should behave in the collection. */
/**
* How multiple selection should behave in the collection.
* @default 'toggle'
*/
selectionBehavior?: SelectionBehavior,
/** Whether onSelectionChange should fire even if the new set of keys is the same as the last. */
allowDuplicateSelectionEvents?: boolean,
/** Whether `disabledKeys` applies to all interactions, or only selection. */
/**
* Whether `disabledKeys` applies to all interactions, or only selection.
* @default 'all'
*/
disabledBehavior?: DisabledBehavior
}

Expand Down
117 changes: 116 additions & 1 deletion packages/react-aria-components/test/TagGroup.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -521,6 +521,121 @@ describe('TagGroup', () => {
expect(onRemove).toHaveBeenLastCalledWith(new Set(['dog']));
});

it('should support onAction', async () => {
let onAction = jest.fn();
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'none'});
let items = getAllByRole('row');

await user.click(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
onAction.mockReset();

await user.keyboard('{Enter}');
expect(onAction).toHaveBeenCalledTimes(1);
});

it('should support onAction with selectionMode = single, behaviour = replace', async () => {
let onAction = jest.fn();
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'single', selectionBehavior: 'replace'});
let items = getAllByRole('row');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
onAction.mockReset();

await user.click(items[1]);
expect(onAction).not.toHaveBeenCalled();
expect(items[1]).toHaveAttribute('aria-selected', 'true');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
expect(items[0]).toHaveAttribute('aria-selected', 'false'); // should be true?
expect(items[1]).toHaveAttribute('aria-selected', 'false');
onAction.mockReset();

await user.keyboard('{Enter}');
expect(onAction).toHaveBeenCalledTimes(1);
expect(items[0]).toHaveAttribute('aria-selected', 'false'); // should be true?
expect(items[1]).toHaveAttribute('aria-selected', 'false');
});

it('should support onAction with selectionMode = multiple, behaviour = replace', async () => {
let onAction = jest.fn();
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'multiple', selectionBehavior: 'replace'});
let items = getAllByRole('row');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
onAction.mockReset();

await user.click(items[1]);
expect(onAction).not.toHaveBeenCalled();
onAction.mockReset();
expect(items[1]).toHaveAttribute('aria-selected', 'true');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
expect(items[0]).toHaveAttribute('aria-selected', 'true');
expect(items[1]).toHaveAttribute('aria-selected', 'false');
onAction.mockReset();

await user.keyboard('{Enter}');
expect(onAction).toHaveBeenCalledTimes(1);
expect(items[0]).toHaveAttribute('aria-selected', 'true');
expect(items[1]).toHaveAttribute('aria-selected', 'false');
});

// TODO: What do we want to do for this behaviour? Should we warn that it's not a valid combination? Or should it react to double click?
// Replace selectionBehavior works with double click, but toggle doesn't.
it.skip('should support onAction with selectionMode = single, behaviour = toggle', async () => {
let onAction = jest.fn();
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'single'});
let items = getAllByRole('row');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
onAction.mockReset();

await user.click(items[1]);
expect(onAction).not.toHaveBeenCalled();
expect(items[1]).toHaveAttribute('aria-selected', 'true');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
expect(items[0]).not.toHaveAttribute('aria-selected');
onAction.mockReset();

await user.keyboard('{Enter}');
expect(onAction).not.toHaveBeenCalled();
expect(items[0]).toHaveAttribute('aria-selected', 'true');
expect(items[1]).not.toHaveAttribute('aria-selected');
});

it.skip('should support onAction with selectionMode = multiple, behaviour = toggle', async () => {
let onAction = jest.fn();
let {getAllByRole} = renderTagGroup({onAction, selectionMode: 'multiple'});
let items = getAllByRole('row');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
onAction.mockReset();

await user.click(items[1]);
expect(onAction).not.toHaveBeenCalled();
onAction.mockReset();
expect(items[1]).toHaveAttribute('aria-selected', 'true');

await user.dblClick(items[0]);
expect(onAction).toHaveBeenCalledTimes(1);
expect(items[0]).not.toHaveAttribute('aria-selected');
onAction.mockReset();

await user.keyboard('{Enter}');
expect(onAction).not.toHaveBeenCalled();
expect(items[0]).toHaveAttribute('aria-selected', 'true');
expect(items[1]).toHaveAttribute('aria-selected', 'true');
});

describe('shouldSelectOnPressUp', () => {
it('should select an item on pressing down when shouldSelectOnPressUp is not provided', async () => {
let onSelectionChange = jest.fn();
Expand Down Expand Up @@ -560,7 +675,7 @@ describe('TagGroup', () => {
});

describe('press events', () => {
it.only.each`
it.each`
interactionType
${'mouse'}
${'keyboard'}
Expand Down