Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[material-ui][Autocomplete] Fix bug with child chip button events propagating to parent #43982

Merged
merged 8 commits into from
Oct 16, 2024
6 changes: 5 additions & 1 deletion packages/mui-material/src/Autocomplete/Autocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -737,7 +737,11 @@ const Autocomplete = React.forwardRef(function Autocomplete(inProps, ref) {
ref: setAnchorEl,
className: classes.inputRoot,
startAdornment,
onMouseDown: (event) => handleInputMouseDown(event),
onMouseDown: (event) => {
if (event.target === event.currentTarget) {
handleInputMouseDown(event);
}
},
...((hasClearIcon || hasPopupIcon) && {
endAdornment: (
<AutocompleteEndAdornment className={classes.endAdornment} ownerState={ownerState}>
Expand Down
77 changes: 44 additions & 33 deletions packages/mui-material/src/Autocomplete/Autocomplete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -414,39 +414,6 @@ describe('<Autocomplete />', () => {
expect(getAllByRole('button', { hidden: false })).to.have.lengthOf(5);
}
});

// Test for https://github.com/mui/material-ui/issues/42432
it('when the input box needs to expand downward, the listbox should remain open.', () => {
const options = [
'The Lord of the Rings: The Return of the King',
'The Good, the Bad and the Ugly',
'The Shawshank Redemption',
'Star Wars: Episode V - The Empire Strikes Back',
];
const defaultValue = [
'The Lord of the Rings: The Return of the King',
'The Good, the Bad and the Ugly',
'The Shawshank Redemption',
];

render(
<Autocomplete
multiple
limitTags={2}
options={options}
defaultValue={defaultValue}
renderInput={(params) => <TextField {...params} />}
sx={{ width: 500 }}
/>,
);

const textbox = screen.getByRole('combobox');

fireEvent.mouseDown(textbox);

const listbox = screen.getByRole('listbox');
expect(listbox).toBeVisible();
});
});

describe('prop: filterSelectedOptions', () => {
Expand Down Expand Up @@ -864,6 +831,50 @@ describe('<Autocomplete />', () => {
expect(handleSubmit.callCount).to.equal(4);
});

it('should not open the autocomplete popup when deleting chips', async () => {
const { queryByRole, queryByText, user } = render(
<Autocomplete
multiple
options={['one', 'two', 'three']}
defaultValue={['one']}
renderInput={(params) => <TextField {...params} autoFocus />}
/>,
);

expect(queryByRole('listbox')).to.equal(null);

const chip = queryByText('one').parentElement;
expect(chip).not.to.equal(null);

// Delete the chip
await user.click(chip.getElementsByClassName(chipClasses.deleteIcon)[0]);

expect(queryByText('one')).to.equal(null);
expect(queryByRole('listbox')).to.equal(null);
});

it('should toggle the autocomplete popup when clicking the popup indicator', async () => {
const { queryByRole, getByTestId, user } = render(
<Autocomplete
multiple
options={['one', 'two', 'three']}
renderInput={(params) => <TextField {...params} autoFocus />}
slotProps={{ popupIndicator: { 'data-testid': 'popup-indicator' } }}
/>,
);

expect(queryByRole('listbox')).to.equal(null);

const popupIndicator = getByTestId('popup-indicator');
DiegoAndai marked this conversation as resolved.
Show resolved Hide resolved
await user.click(popupIndicator);

expect(queryByRole('listbox')).not.to.equal(null);

await user.click(popupIndicator);

expect(queryByRole('listbox')).to.equal(null);
});

describe('prop: getOptionDisabled', () => {
it('should prevent the disabled option to trigger actions but allow focus with disabledItemsFocusable', () => {
const handleSubmit = spy();
Expand Down
2 changes: 0 additions & 2 deletions packages/mui-material/src/useAutocomplete/useAutocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -1020,7 +1020,6 @@ function useAutocomplete(props) {
const handleInputMouseDown = (event) => {
if (!disabledProp && (inputValue === '' || !open)) {
handlePopupIndicator(event);
event.stopPropagation();
}
};

Expand Down Expand Up @@ -1109,7 +1108,6 @@ function useAutocomplete(props) {
tabIndex: -1,
type: 'button',
onClick: handlePopupIndicator,
onMouseDown: (event) => event.stopPropagation(),
}),
getTagProps: ({ index }) => ({
key: index,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import * as React from 'react';
import TextField from '@mui/material/TextField';
import Autocomplete from '@mui/material/Autocomplete';

export default function StandardAutocomplete() {
return (
<div style={{ height: 220 }}>
<Autocomplete
multiple
limitTags={2}
options={['One', 'Two', 'Three']}
defaultValue={['One', 'Two', 'Three']}
renderInput={(params) => <TextField {...params} />}
sx={{ width: 300 }}
/>
</div>
);
}
14 changes: 14 additions & 0 deletions test/regressions/index.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,20 @@ async function main() {
await takeScreenshot({ testcase, route: '/regression-Rating/PreciseFocusVisibleRating3' });
});
});

describe('Autocomplete', () => {
it('should not close immediately when textbox expands', async () => {
const testcase = await renderFixture(
'/regression-Autocomplete/TextboxExpandsOnListboxOpen',
);
await page.getByRole('combobox').click();
await page.waitForTimeout(10);
await takeScreenshot({
testcase,
route: '/regression-Autocomplete/TextboxExpandsOnListboxOpen2',
});
});
});
});

run();
Expand Down