diff --git a/docs/pages/api/autocomplete.md b/docs/pages/api/autocomplete.md
index 9b5440408754c3..75a59b5914a098 100644
--- a/docs/pages/api/autocomplete.md
+++ b/docs/pages/api/autocomplete.md
@@ -60,7 +60,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| noOptionsText | node | 'No options' | Text to display when there are no options.
For localization purposes, you can use the provided [translations](/guides/localization/). |
| onChange | func | | Callback fired when the value changes.
**Signature:**
`function(event: object, value: any) => void`
*event:* The event source of the callback
*value:* null |
| onClose | func | | Callback fired when the popup requests to be closed. Use in controlled mode (see open).
**Signature:**
`function(event: object) => void`
*event:* The event source of the callback. |
-| onInputChange | func | | Callback fired when the input value changes.
**Signature:**
`function(event: object, value: string, reason: string) => void`
*event:* The event source of the callback.
*value:* The new value of the text input
*reason:* One of "input" (user input) or "reset" (programmatic change) |
+| onInputChange | func | | Callback fired when the input value changes.
**Signature:**
`function(event: object, value: string, reason: string) => void`
*event:* The event source of the callback.
*value:* The new value of the text input
*reason:* Can be: "input" (user input), "reset" (programmatic change), `"clear"`. |
| onOpen | func | | Callback fired when the popup requests to be opened. Use in controlled mode (see open).
**Signature:**
`function(event: object) => void`
*event:* The event source of the callback. |
| open | bool | | Control the popup` open state. |
| openText | string | 'Open' | Override the default text for the *open popup* icon button.
For localization purposes, you can use the provided [translations](/guides/localization/). |
diff --git a/docs/pages/api/dialog.md b/docs/pages/api/dialog.md
index def06e885f715a..9861764aa0e827 100644
--- a/docs/pages/api/dialog.md
+++ b/docs/pages/api/dialog.md
@@ -34,7 +34,7 @@ Dialogs are overlaid modal paper based components with a backdrop.
| fullWidth | bool | false | If `true`, the dialog stretches to `maxWidth`.
Notice that the dialog width grow is limited by the default margin. |
| maxWidth | 'xs'
| 'sm'
| 'md'
| 'lg'
| 'xl'
| false | 'sm' | Determine the max-width of the dialog. The dialog width grows with the size of the screen. Set to `false` to disable `maxWidth`. |
| onBackdropClick | func | | Callback fired when the backdrop is clicked. |
-| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"escapeKeyDown"`, `"backdropClick"`. |
+| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"escapeKeyDown"`, `"backdropClick"`. |
| onEnter | func | | Callback fired before the dialog enters. |
| onEntered | func | | Callback fired when the dialog has entered. |
| onEntering | func | | Callback fired when the dialog is entering. |
diff --git a/docs/pages/api/menu.md b/docs/pages/api/menu.md
index ee661c0b2a9105..5abae1f0a9ce7c 100644
--- a/docs/pages/api/menu.md
+++ b/docs/pages/api/menu.md
@@ -30,7 +30,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| classes | object | | Override or extend the styles applied to the component. See [CSS API](#css) below for more details. |
| disableAutoFocusItem | bool | false | When opening the menu will not focus the active item but the `[role="menu"]` unless `autoFocus` is also set to `false`. Not using the default means not following WAI-ARIA authoring practices. Please be considerate about possible accessibility implications. |
| MenuListProps | object | {} | Props applied to the [`MenuList`](/api/menu-list/) element. |
-| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"escapeKeyDown"`, `"backdropClick"`, `"tabKeyDown"`. |
+| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"escapeKeyDown"`, `"backdropClick"`, `"tabKeyDown"`. |
| onEnter | func | | Callback fired before the Menu enters. |
| onEntered | func | | Callback fired when the Menu has entered. |
| onEntering | func | | Callback fired when the Menu is entering. |
diff --git a/docs/pages/api/modal.md b/docs/pages/api/modal.md
index f5da20e5ce8043..72710eb78bf08d 100644
--- a/docs/pages/api/modal.md
+++ b/docs/pages/api/modal.md
@@ -49,7 +49,7 @@ This component shares many concepts with [react-overlays](https://react-bootstra
| hideBackdrop | bool | false | If `true`, the backdrop is not rendered. |
| keepMounted | bool | false | Always keep the children in the DOM. This prop can be useful in SEO situation or when you want to maximize the responsiveness of the Modal. |
| onBackdropClick | func | | Callback fired when the backdrop is clicked. |
-| onClose | func | | Callback fired when the component requests to be closed. The `reason` parameter can optionally be used to control the response to `onClose`.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"escapeKeyDown"`, `"backdropClick"`. |
+| onClose | func | | Callback fired when the component requests to be closed. The `reason` parameter can optionally be used to control the response to `onClose`.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"escapeKeyDown"`, `"backdropClick"`. |
| onEscapeKeyDown | func | | Callback fired when the escape key is pressed, `disableEscapeKeyDown` is false and the modal is in focus. |
| onRendered | func | | Callback fired once the children has been mounted into the `container`. It signals that the `open={true}` prop took effect.
This prop will be deprecated and removed in v5, the ref can be used instead. |
| open * | bool | | If `true`, the modal is open. |
diff --git a/docs/pages/api/popover.md b/docs/pages/api/popover.md
index bcb742822b7c81..49bd300d585df5 100644
--- a/docs/pages/api/popover.md
+++ b/docs/pages/api/popover.md
@@ -35,7 +35,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| elevation | number | 8 | The elevation of the popover. |
| getContentAnchorEl | func | | This function is called in order to retrieve the content anchor element. It's the opposite of the `anchorEl` prop. The content anchor element should be an element inside the popover. It's used to correctly scroll and set the position of the popover. The positioning strategy tries to make the content anchor element just above the anchor element. |
| marginThreshold | number | 16 | Specifies how close to the edge of the window the popover can appear. |
-| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"escapeKeyDown"`, `"backdropClick"` |
+| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"escapeKeyDown"`, `"backdropClick"`. |
| onEnter | func | | Callback fired before the component is entering. |
| onEntered | func | | Callback fired when the component has entered. |
| onEntering | func | | Callback fired when the component is entering. |
diff --git a/docs/pages/api/snackbar.md b/docs/pages/api/snackbar.md
index aeb93bae57da72..4384127502c3da 100644
--- a/docs/pages/api/snackbar.md
+++ b/docs/pages/api/snackbar.md
@@ -34,7 +34,7 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| disableWindowBlurListener | bool | false | If `true`, the `autoHideDuration` timer will expire even if the window is not focused. |
| key | any | | When displaying multiple consecutive Snackbars from a parent rendering a single <Snackbar/>, add the key prop to ensure independent treatment of each message. e.g. <Snackbar key={message} />, otherwise, the message may update-in-place and features such as autoHideDuration may be canceled. |
| message | node | | The message to display. |
-| onClose | func | | Callback fired when the component requests to be closed. Typically `onClose` is used to set state in the parent component, which is used to control the `Snackbar` `open` prop. The `reason` parameter can optionally be used to control the response to `onClose`, for example ignoring `clickaway`.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"timeout"` (`autoHideDuration` expired) or: `"clickaway"`. |
+| onClose | func | | Callback fired when the component requests to be closed. Typically `onClose` is used to set state in the parent component, which is used to control the `Snackbar` `open` prop. The `reason` parameter can optionally be used to control the response to `onClose`, for example ignoring `clickaway`.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"timeout"` (`autoHideDuration` expired), `"clickaway"`. |
| onEnter | func | | Callback fired before the transition is entering. |
| onEntered | func | | Callback fired when the transition has entered. |
| onEntering | func | | Callback fired when the transition is entering. |
diff --git a/docs/pages/api/speed-dial.md b/docs/pages/api/speed-dial.md
index 8ea77bff16f88f..aa6096e6628eb3 100644
--- a/docs/pages/api/speed-dial.md
+++ b/docs/pages/api/speed-dial.md
@@ -31,8 +31,8 @@ You can learn more about the difference by [reading this guide](/guides/minimizi
| FabProps | object | {} | Props applied to the [`Fab`](/api/fab/) element. |
| hidden | bool | false | If `true`, the SpeedDial will be hidden. |
| icon | node | | The icon to display in the SpeedDial Fab. The `SpeedDialIcon` component provides a default Icon with animation. |
-| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"toggle"`, `"blur"`, `"mouseLeave"`, `"escapeKeyDown"`. |
-| onOpen | func | | Callback fired when the component requests to be open.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be:`"toggle"`, `"focus"`, `"mouseEnter"`. |
+| onClose | func | | Callback fired when the component requests to be closed.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"toggle"`, `"blur"`, `"mouseLeave"`, `"escapeKeyDown"`. |
+| onOpen | func | | Callback fired when the component requests to be open.
**Signature:**
`function(event: object, reason: string) => void`
*event:* The event source of the callback.
*reason:* Can be: `"toggle"`, `"focus"`, `"mouseEnter"`. |
| open * | bool | | If `true`, the SpeedDial is open. |
| openIcon | node | | The icon to display in the SpeedDial Fab when the SpeedDial is open. |
| TransitionComponent | elementType | Zoom | The component used for the transition. |
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
index cc88d60041d29f..b68510b98c1004 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.js
@@ -637,7 +637,7 @@ Autocomplete.propTypes = {
*
* @param {object} event The event source of the callback.
* @param {string} value The new value of the text input
- * @param {string} reason One of "input" (user input) or "reset" (programmatic change)
+ * @param {string} reason Can be: "input" (user input), "reset" (programmatic change), `"clear"`.
*/
onInputChange: PropTypes.func,
/**
diff --git a/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js b/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
index 01dc865ed01fe4..f472bbc8dd1557 100644
--- a/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
+++ b/packages/material-ui-lab/src/Autocomplete/Autocomplete.test.js
@@ -682,7 +682,7 @@ describe('', () => {
});
});
- describe('controlled input', () => {
+ describe('controlled', () => {
it('controls the input value', () => {
const handleChange = spy();
function MyComponent() {
@@ -708,6 +708,22 @@ describe('', () => {
expect(handleChange.args[0][0]).to.equal('a');
expect(document.activeElement.value).to.equal('');
});
+
+ it('should fire the input change event before the change event', () => {
+ const handleChange = spy();
+ const handleInputChange = spy();
+ render(
+ }
+ />,
+ );
+ fireEvent.keyDown(document.activeElement, { key: 'ArrowDown' });
+ fireEvent.keyDown(document.activeElement, { key: 'Enter' });
+ expect(handleInputChange.calledBefore(handleChange)).to.equal(true);
+ });
});
describe('prop: filterOptions', () => {
diff --git a/packages/material-ui-lab/src/SpeedDial/SpeedDial.d.ts b/packages/material-ui-lab/src/SpeedDial/SpeedDial.d.ts
index 4db46ee9f97a27..c508218b2bb500 100644
--- a/packages/material-ui-lab/src/SpeedDial/SpeedDial.d.ts
+++ b/packages/material-ui-lab/src/SpeedDial/SpeedDial.d.ts
@@ -43,14 +43,14 @@ export interface SpeedDialProps
* Callback fired when the component requests to be closed.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"toggle"`, `"blur"`, `"mouseLeave"`, `"escapeKeyDown"`.
+ * @param {string} reason Can be: `"toggle"`, `"blur"`, `"mouseLeave"`, `"escapeKeyDown"`.
*/
onClose?: (event: React.SyntheticEvent<{}>, reason: CloseReason) => void;
/**
* Callback fired when the component requests to be open.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"toggle"`, `"focus"`, `"mouseEnter"`.
+ * @param {string} reason Can be: `"toggle"`, `"focus"`, `"mouseEnter"`.
*/
onOpen?: (event: React.SyntheticEvent<{}>, reason: OpenReason) => void;
/**
diff --git a/packages/material-ui-lab/src/SpeedDial/SpeedDial.js b/packages/material-ui-lab/src/SpeedDial/SpeedDial.js
index e2cd10f514d9b2..8988d44cda7c5d 100644
--- a/packages/material-ui-lab/src/SpeedDial/SpeedDial.js
+++ b/packages/material-ui-lab/src/SpeedDial/SpeedDial.js
@@ -402,7 +402,7 @@ SpeedDial.propTypes = {
* Callback fired when the component requests to be closed.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"toggle"`, `"blur"`, `"mouseLeave"`, `"escapeKeyDown"`.
+ * @param {string} reason Can be: `"toggle"`, `"blur"`, `"mouseLeave"`, `"escapeKeyDown"`.
*/
onClose: PropTypes.func,
/**
@@ -425,7 +425,7 @@ SpeedDial.propTypes = {
* Callback fired when the component requests to be open.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"toggle"`, `"focus"`, `"mouseEnter"`.
+ * @param {string} reason Can be: `"toggle"`, `"focus"`, `"mouseEnter"`.
*/
onOpen: PropTypes.func,
/**
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
index 250312f748a3d1..4d0e062c9011b0 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.d.ts
@@ -148,7 +148,7 @@ export interface UseAutocompleteProps {
*
* @param {object} event The event source of the callback.
* @param {string} value The new value of the text input
- * @param {string} reason One of "input" (user input) or "reset" (programmatic change)
+ * @param {string} reason Can be: "input" (user input), "reset" (programmatic change), `"clear"`.
*/
onInputChange?: (event: React.ChangeEvent<{}>, value: any, reason: 'input' | 'reset') => void;
/**
diff --git a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
index 85636b90ab2cce..7a799b1b81dbce 100644
--- a/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
+++ b/packages/material-ui-lab/src/useAutocomplete/useAutocomplete.js
@@ -436,13 +436,14 @@ export default function useAutocomplete(props) {
newValue.splice(itemIndex, 1);
}
}
+
+ resetInputValue(event, newValue);
+
handleValue(event, newValue);
if (!disableCloseOnSelect) {
handleClose(event);
}
- resetInputValue(event, newValue);
-
selectedIndexRef.current = -1;
};
@@ -511,8 +512,13 @@ export default function useAutocomplete(props) {
const handleClear = event => {
ignoreFocus.current = true;
- handleValue(event, multiple ? [] : null);
setInputValue('');
+
+ if (onInputChange) {
+ onInputChange(event, '', 'clear');
+ }
+
+ handleValue(event, multiple ? [] : null);
};
const handleKeyDown = event => {
@@ -639,6 +645,14 @@ export default function useAutocomplete(props) {
const handleInputChange = event => {
const newValue = event.target.value;
+ if (inputValue !== newValue) {
+ setInputValue(newValue);
+
+ if (onInputChange) {
+ onInputChange(event, newValue, 'input');
+ }
+ }
+
if (newValue === '') {
if (disableOpenOnFocus) {
handleClose(event);
@@ -650,16 +664,6 @@ export default function useAutocomplete(props) {
} else {
handleOpen(event);
}
-
- if (inputValue === newValue) {
- return;
- }
-
- setInputValue(newValue);
-
- if (onInputChange) {
- onInputChange(event, newValue, 'input');
- }
};
const handleOptionMouseOver = event => {
diff --git a/packages/material-ui/src/Dialog/Dialog.js b/packages/material-ui/src/Dialog/Dialog.js
index aaa7c022c0496f..6c8eefaf4637f6 100644
--- a/packages/material-ui/src/Dialog/Dialog.js
+++ b/packages/material-ui/src/Dialog/Dialog.js
@@ -321,7 +321,7 @@ Dialog.propTypes = {
* Callback fired when the component requests to be closed.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"escapeKeyDown"`, `"backdropClick"`.
+ * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
*/
onClose: PropTypes.func,
/**
diff --git a/packages/material-ui/src/Menu/Menu.js b/packages/material-ui/src/Menu/Menu.js
index 628674ceb2a2b8..2001eb36c6e8f2 100644
--- a/packages/material-ui/src/Menu/Menu.js
+++ b/packages/material-ui/src/Menu/Menu.js
@@ -201,7 +201,7 @@ Menu.propTypes = {
* Callback fired when the component requests to be closed.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"escapeKeyDown"`, `"backdropClick"`, `"tabKeyDown"`.
+ * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`, `"tabKeyDown"`.
*/
onClose: PropTypes.func,
/**
diff --git a/packages/material-ui/src/Modal/Modal.js b/packages/material-ui/src/Modal/Modal.js
index 2cc22810702d71..5b8d8be6d9d159 100644
--- a/packages/material-ui/src/Modal/Modal.js
+++ b/packages/material-ui/src/Modal/Modal.js
@@ -338,7 +338,7 @@ Modal.propTypes = {
* The `reason` parameter can optionally be used to control the response to `onClose`.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"escapeKeyDown"`, `"backdropClick"`.
+ * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
*/
onClose: PropTypes.func,
/**
diff --git a/packages/material-ui/src/Popover/Popover.js b/packages/material-ui/src/Popover/Popover.js
index 9f23c25e2ab817..86a64c32315e60 100644
--- a/packages/material-ui/src/Popover/Popover.js
+++ b/packages/material-ui/src/Popover/Popover.js
@@ -527,7 +527,7 @@ Popover.propTypes = {
* Callback fired when the component requests to be closed.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"escapeKeyDown"`, `"backdropClick"`
+ * @param {string} reason Can be: `"escapeKeyDown"`, `"backdropClick"`.
*/
onClose: PropTypes.func,
/**
diff --git a/packages/material-ui/src/Snackbar/Snackbar.js b/packages/material-ui/src/Snackbar/Snackbar.js
index 424543c9147fd8..100f8e62218e6a 100644
--- a/packages/material-ui/src/Snackbar/Snackbar.js
+++ b/packages/material-ui/src/Snackbar/Snackbar.js
@@ -314,7 +314,7 @@ Snackbar.propTypes = {
* for example ignoring `clickaway`.
*
* @param {object} event The event source of the callback.
- * @param {string} reason Can be:`"timeout"` (`autoHideDuration` expired) or: `"clickaway"`.
+ * @param {string} reason Can be: `"timeout"` (`autoHideDuration` expired), `"clickaway"`.
*/
onClose: PropTypes.func,
/**