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
9 changes: 9 additions & 0 deletions packages/react-aria/src/selection/useSelectableCollection.ts
Original file line number Diff line number Diff line change
Expand Up @@ -625,6 +625,15 @@ export function useSelectableCollection(
manager.setFocused(true);
manager.setFocusedKey(focusedKey);

if (
focusedKey != null &&
selectOnFocus &&
!selectedKeys.size &&
manager.canSelectItem(focusedKey)
) {
manager.replaceSelection(focusedKey);
}

// If no default focus key is selected, focus the collection itself.
if (focusedKey == null && !shouldUseVirtualFocus && ref.current) {
focusSafely(ref.current);
Expand Down
2 changes: 2 additions & 0 deletions packages/react-aria/stories/selection/List.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
AsyncLoadable,
CollectionBase,
FocusStrategy,
MultipleSelection,
Node,
SelectionBehavior
Expand Down Expand Up @@ -56,4 +57,5 @@ export function List<T extends object>(props: ListProps<T>): JSX.Element {

export interface ListProps<T> extends CollectionBase<T>, AsyncLoadable, MultipleSelection {
selectionBehavior?: SelectionBehavior;
autoFocus?: boolean | FocusStrategy;
}
33 changes: 33 additions & 0 deletions packages/react-aria/test/selection/useSelectableCollection.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,39 @@ describe('useSelectableCollection', () => {
expect(options[0]).toHaveAttribute('aria-selected', 'true');
});

it.each`
autoFocus | index
${'first'} | ${0}
${'last'} | ${2}
`(
'selects the autofocused item if selectOnFocus with autoFocus=$autoFocus',
({autoFocus, index}) => {
let {getAllByRole} = render(
<List selectionMode="single" autoFocus={autoFocus}>
<Item>Paco de Lucia</Item>
<Item>Vicente Amigo</Item>
<Item>Gerardo Nunez</Item>
</List>
);
let options = getAllByRole('option');
expect(document.activeElement).toBe(options[index]);
expect(options[index]).toHaveAttribute('aria-selected', 'true');
}
);

it('does not change the selection when autofocusing an already selected collection', () => {
let {getAllByRole} = render(
<List selectionMode="single" autoFocus="first" defaultSelectedKeys={['Gerardo Nunez']}>
<Item key="Paco de Lucia">Paco de Lucia</Item>
<Item key="Vicente Amigo">Vicente Amigo</Item>
<Item key="Gerardo Nunez">Gerardo Nunez</Item>
</List>
);
let options = getAllByRole('option');
expect(options[2]).toHaveAttribute('aria-selected', 'true');
expect(options[0]).not.toHaveAttribute('aria-selected');
});

it('can navigate without replacing the selection in multiple selection selectOnFocus', async () => {
let {getAllByRole} = render(
<List selectionMode="multiple" selectionBehavior="replace">
Expand Down