Skip to content

Commit

Permalink
[Autocomplete] Add ability to override key down events handlers
Browse files Browse the repository at this point in the history
  • Loading branch information
oliviertassinari committed Nov 14, 2020
1 parent 576cadd commit 226778e
Show file tree
Hide file tree
Showing 4 changed files with 69 additions and 20 deletions.
16 changes: 16 additions & 0 deletions docs/src/pages/components/autocomplete/autocomplete.md
Original file line number Diff line number Diff line change
Expand Up @@ -275,6 +275,22 @@ Search within 10,000 randomly generated options. The list is virtualized thanks

{{"demo": "pages/components/autocomplete/Virtualize.js"}}

## Events

If you would like to prevent the default key handler behavior, you can set the event's `defaultMuiPrevented` property to `true`:

```jsx
<Autocomplete
onKeyDown={(event) => {
if (event.key === 'Enter') {
// Prevent's default 'Enter' behavior.
event.defaultMuiPrevented = false;
// your handler code
}
}}
/>
```

## Limitations

### autocomplete/autofill
Expand Down
55 changes: 42 additions & 13 deletions packages/material-ui/src/Autocomplete/Autocomplete.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -533,17 +533,22 @@ describe('<Autocomplete />', () => {

it('should trigger a form expectedly', () => {
const handleSubmit = spy();
const { setProps } = render(
<Autocomplete
options={['one', 'two']}
const Test = (props) => (
<div
onKeyDown={(event) => {
if (!event.defaultPrevented && event.key === 'Enter') {
handleSubmit();
}
}}
renderInput={(props2) => <TextField {...props2} autoFocus />}
/>,
>
<Autocomplete
options={['one', 'two']}
renderInput={(props2) => <TextField {...props2} autoFocus />}
{...props}
/>
</div>
);
const { setProps } = render(<Test />);
let textbox = screen.getByRole('textbox');

fireEvent.keyDown(textbox, { key: 'Enter' });
Expand Down Expand Up @@ -580,19 +585,22 @@ describe('<Autocomplete />', () => {
const handleSubmit = spy();
const handleChange = spy();
const { getAllByRole } = render(
<Autocomplete
disabledItemsFocusable
getOptionDisabled={(option) => option === 'two'}
<div
onKeyDown={(event) => {
if (!event.defaultPrevented && event.key === 'Enter') {
handleSubmit();
}
}}
onChange={handleChange}
openOnFocus
options={['one', 'two', 'three']}
renderInput={(props2) => <TextField {...props2} autoFocus />}
/>,
>
<Autocomplete
disabledItemsFocusable
getOptionDisabled={(option) => option === 'two'}
onChange={handleChange}
openOnFocus
options={['one', 'two', 'three']}
renderInput={(props2) => <TextField {...props2} autoFocus />}
/>
</div>,
);

let options;
Expand Down Expand Up @@ -2099,4 +2107,25 @@ describe('<Autocomplete />', () => {

expect(getAllByRole('option')).to.have.length(1);
});

it('should prevent the default event handlers', () => {
const handleChange = spy();
render(
<Autocomplete
options={['one', 'two']}
onChange={handleChange}
onKeyDown={(event) => {
if (event.key === 'Enter') {
event.defaultMuiPrevented = true;
}
}}
renderInput={(params) => <TextField autoFocus {...params} />}
/>,
);
const textbox = screen.getByRole('textbox');
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
fireEvent.keyDown(textbox, { key: 'ArrowDown' });
fireEvent.keyDown(textbox, { key: 'Enter' });
expect(handleChange.callCount).to.equal(0);
});
});
4 changes: 2 additions & 2 deletions packages/material-ui/src/SwipeableDrawer/SwipeableDrawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,7 @@ const SwipeableDrawer = React.forwardRef(function SwipeableDrawer(inProps, ref)
}

// We can only have one node at the time claiming ownership for handling the swipe.
if (event.muiHandled) {
if (event.defaultMuiPrevented) {
return;
}

Expand Down Expand Up @@ -466,7 +466,7 @@ const SwipeableDrawer = React.forwardRef(function SwipeableDrawer(inProps, ref)
}
}

event.muiHandled = true;
event.defaultMuiPrevented = true;
nodeThatClaimedTheSwipe = null;
swipeInstance.current.startX = currentX;
swipeInstance.current.startY = currentY;
Expand Down
14 changes: 9 additions & 5 deletions packages/material-ui/src/useAutocomplete/useAutocomplete.js
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@ export default function useAutocomplete(props) {
const listboxAvailable = open && filteredOptions.length > 0;

if (process.env.NODE_ENV !== 'production') {
if (value !== null && !freeSolo && options?.length > 0) {
if (value !== null && !freeSolo && options.length > 0) {
const missingValue = (multiple ? value : [value]).filter(
(value2) => !options.some((option) => getOptionSelected(option, value2)),
);
Expand Down Expand Up @@ -657,6 +657,14 @@ export default function useAutocomplete(props) {
};

const handleKeyDown = (other) => (event) => {
if (other.onKeyDown) {
other.onKeyDown(event);
}

if (event.defaultMuiPrevented) {
return;
}

if (focusedTag !== -1 && ['ArrowLeft', 'ArrowRight'].indexOf(event.key) === -1) {
setFocusedTag(-1);
focusTag(-1);
Expand Down Expand Up @@ -776,10 +784,6 @@ export default function useAutocomplete(props) {
default:
}
}

if (other.onKeyDown) {
other.onKeyDown(event);
}
};

const handleFocus = (event) => {
Expand Down

0 comments on commit 226778e

Please sign in to comment.