Skip to content
Merged
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
45 changes: 44 additions & 1 deletion packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,50 @@ describe('<Autocomplete />', () => {
fireEvent.change(document.activeElement, { target: { value: 'o' } });
checkHighlightIs('one');
});

it('should set the focus on selected item when dropdown is expanded', () => {
const { getByRole, setProps } = render(
<Autocomplete
{...defaultProps}
value="one"
options={['one', 'two', 'three']}
renderInput={params => <TextField autoFocus {...params} />}
/>,
);

function checkHighlightIs(expected) {
expect(getByRole('listbox').querySelector('li[data-focus]')).to.have.text(expected);
}

checkHighlightIs('one');
setProps({ value: 'two' });
checkHighlightIs('two');
});
});

describe('prop: filterSelectedOptions', () => {
it('when the last item is selected, highlights the new last item', () => {
const { getByRole } = render(
<Autocomplete
{...defaultProps}
filterSelectedOptions
options={['one', 'two', 'three']}
renderInput={params => <TextField {...params} autoFocus />}
/>,
);

function checkHighlightIs(expected) {
expect(getByRole('listbox').querySelector('li[data-focus]')).to.have.text(expected);
}

fireEvent.keyDown(document.activeElement, { key: 'ArrowUp' });
checkHighlightIs('three');
fireEvent.keyDown(document.activeElement, { key: 'Enter' }); // selects the last option
const input = getByRole('textbox');
input.blur();
input.focus(); // opens the listbox again
checkHighlightIs('two');
});
});

describe('prop: autoSelect', () => {
Expand Down Expand Up @@ -758,7 +802,6 @@ describe('<Autocomplete />', () => {
/>,
);

fireEvent.keyDown(document.activeElement, { key: 'ArrowDown' });
fireEvent.keyDown(document.activeElement, { key: 'ArrowDown' });
fireEvent.keyDown(document.activeElement, { key: 'Enter' });

Expand Down
48 changes: 42 additions & 6 deletions packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ export default function useAutocomplete(props) {
const defaultHighlighted = autoHighlight ? 0 : -1;
const highlightedIndexRef = React.useRef(defaultHighlighted);

function setHighlightedIndex(index, mouse = false) {
const setHighlightedIndex = useEventCallback((index, mouse = false) => {
highlightedIndexRef.current = index;
// does the index exist?
if (index === -1) {
Expand Down Expand Up @@ -190,7 +190,7 @@ export default function useAutocomplete(props) {
listboxNode.scrollTop = element.offsetTop - element.offsetHeight * (groupBy ? 1.3 : 0);
}
}
}
});

const [value, setValue] = useControlled({
controlled: valueProp,
Expand Down Expand Up @@ -323,7 +323,7 @@ export default function useAutocomplete(props) {
}
}

const changeHighlightedIndex = (diff, direction) => {
const changeHighlightedIndex = useEventCallback((diff, direction) => {
if (!popupOpen) {
return;
}
Expand Down Expand Up @@ -390,11 +390,47 @@ export default function useAutocomplete(props) {
}
}
}
};
});

React.useEffect(() => {
changeHighlightedIndex('reset', 'next');
}, [inputValue]); // eslint-disable-line react-hooks/exhaustive-deps
if (!open) {
return;
}

const valueItem = multiple ? value[0] : value;

// The popup is empty
if (filteredOptions.length === 0 || valueItem == null) {
changeHighlightedIndex('reset', 'next');
return;
}

// Synchronize the value with the highlighted index
if (!filterSelectedOptions && valueItem != null) {
const itemIndex = findIndex(filteredOptions, optionItem =>
getOptionSelected(optionItem, valueItem),
);

setHighlightedIndex(itemIndex);
return;
}

// Keep the index in the boundaries
if (highlightedIndexRef.current >= filteredOptions.length - 1) {
setHighlightedIndex(filteredOptions.length - 1);
}

// Ignore filterOptions => options, getOptionSelected, getOptionLabel)
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [
value,
open,
filterSelectedOptions,
changeHighlightedIndex,
setHighlightedIndex,
inputValue,
multiple,
]);

const handleOpen = event => {
if (open) {
Expand Down