Skip to content

Commit 472cc72

Browse files
authored
[Autocomplete] Fix auto highlight when options change but not the length (#46489)
1 parent 83bfdd7 commit 472cc72

File tree

2 files changed

+75
-4
lines changed

2 files changed

+75
-4
lines changed

packages/mui-material/src/Autocomplete/Autocomplete.test.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,57 @@ describe('<Autocomplete />', () => {
369369
fireEvent.change(textbox, { target: { value: 'a' } });
370370
checkHighlightIs(getByRole('listbox'), 'Bar');
371371
});
372+
373+
// https://github.com/mui/material-ui/issues/45279
374+
it('should auto highlight first option after options order changes with autoHighlight', () => {
375+
const { setProps, getByRole } = render(
376+
<Autocomplete
377+
autoHighlight
378+
open
379+
options={['pediatric ent', 'pediatric flu', 'pediatrician', 'pediatric cough']}
380+
renderInput={(params) => <TextField {...params} autoFocus />}
381+
/>,
382+
);
383+
384+
checkHighlightIs(getByRole('listbox'), 'pediatric ent');
385+
setProps({
386+
options: ['pediatrician', 'pediatric ent', 'pediatric flu', 'pediatric cough'],
387+
});
388+
checkHighlightIs(getByRole('listbox'), 'pediatrician');
389+
});
390+
391+
it('should auto highlight first option when no match with input value with autoHighlight', () => {
392+
const { getByRole } = render(
393+
<Autocomplete
394+
open
395+
autoHighlight
396+
options={['1', '2', '3', '4']}
397+
value="5"
398+
renderInput={(params) => <TextField {...params} autoFocus />}
399+
/>,
400+
);
401+
402+
checkHighlightIs(getByRole('listbox'), '1');
403+
});
404+
405+
it('should auto highlight first option of rest after selecting an option with autoHighlight and filterSelectedOptions', () => {
406+
const { getByRole } = render(
407+
<Autocomplete
408+
open
409+
autoHighlight
410+
options={['1', '2', '3', '4']}
411+
renderInput={(params) => <TextField {...params} autoFocus />}
412+
filterSelectedOptions
413+
disableCloseOnSelect
414+
/>,
415+
);
416+
417+
const textbox = getByRole('combobox');
418+
419+
checkHighlightIs(getByRole('listbox'), '1');
420+
fireEvent.keyDown(textbox, { key: 'Enter' });
421+
checkHighlightIs(getByRole('listbox'), '2');
422+
});
372423
});
373424

374425
describe('highlight synchronisation', () => {

packages/mui-material/src/useAutocomplete/useAutocomplete.js

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,15 @@ import useControlled from '@mui/utils/useControlled';
77
import useId from '@mui/utils/useId';
88
import usePreviousProps from '@mui/utils/usePreviousProps';
99

10+
function areArraysSame({ array1, array2, parser = (value) => value }) {
11+
return (
12+
array1 &&
13+
array2 &&
14+
array1.length === array2.length &&
15+
array1.every((prevOption, index) => parser(prevOption) === parser(array2[index]))
16+
);
17+
}
18+
1019
// https://stackoverflow.com/questions/990904/remove-accents-diacritics-in-a-string-in-javascript
1120
function stripDiacritics(string) {
1221
return string.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
@@ -456,6 +465,12 @@ function useAutocomplete(props) {
456465
}
457466
});
458467

468+
const filteredOptionsChanged = !areArraysSame({
469+
array1: previousProps.filteredOptions,
470+
array2: filteredOptions,
471+
parser: getOptionLabel,
472+
});
473+
459474
const getPreviousHighlightedOptionIndex = () => {
460475
const isSameValue = (value1, value2) => {
461476
const label1 = value1 ? getOptionLabel(value1) : '';
@@ -465,8 +480,11 @@ function useAutocomplete(props) {
465480

466481
if (
467482
highlightedIndexRef.current !== -1 &&
468-
previousProps.filteredOptions &&
469-
previousProps.filteredOptions.length !== filteredOptions.length &&
483+
!areArraysSame({
484+
array1: previousProps.filteredOptions,
485+
array2: filteredOptions,
486+
parser: getOptionLabel,
487+
}) &&
470488
previousProps.inputValue === inputValue &&
471489
(multiple
472490
? value.length === previousProps.value.length &&
@@ -597,8 +615,10 @@ function useAutocomplete(props) {
597615
}
598616

599617
React.useEffect(() => {
600-
syncHighlightedIndex();
601-
}, [syncHighlightedIndex]);
618+
if (filteredOptionsChanged) {
619+
syncHighlightedIndex();
620+
}
621+
}, [syncHighlightedIndex, filteredOptionsChanged]);
602622

603623
const handleOpen = (event) => {
604624
if (open) {

0 commit comments

Comments
 (0)