From 52f690eeb334ac2f5687c96a5094b3bacf432501 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 3 Dec 2024 13:40:36 +0700 Subject: [PATCH 1/9] Revert "[material-ui][Button] Revert Button loading (#44478)" This reverts commit 232555b5cabafdaed4bb2ee857d41f37bb1009d2. --- .../button-group/LoadingButtonGroup.js | 7 +- .../button-group/LoadingButtonGroup.tsx | 7 +- .../LoadingButtonGroup.tsx.preview | 6 +- .../components/button-group/button-group.md | 8 +- .../components/buttons/IconButtonWithBadge.js | 37 ++ .../buttons/IconButtonWithBadge.tsx | 37 ++ .../buttons/IconButtonWithBadge.tsx.preview | 9 + .../components/buttons/LoadingButtons.js | 42 +- .../components/buttons/LoadingButtons.tsx | 42 +- .../buttons/LoadingButtons.tsx.preview | 14 - .../buttons/LoadingButtonsTransition.js | 39 +- .../buttons/LoadingButtonsTransition.tsx | 39 +- .../components/buttons/LoadingIconButton.js | 21 + .../components/buttons/LoadingIconButton.tsx | 21 + .../buttons/LoadingIconButton.tsx.preview | 5 + .../material/components/buttons/buttons.md | 36 +- .../dialogs/ToolpadDialogsNoSnap.js | 9 +- .../dialogs/ToolpadDialogsNoSnap.tsx | 9 +- .../migration/upgrade-to-v6/upgrade-to-v6.md | 16 +- docs/data/material/pagesApi.js | 1 - docs/pages/blog/2020-q2-update.md | 2 +- docs/pages/blog/mui-core-v5.md | 2 +- docs/pages/material-ui/api/button.json | 54 +++ docs/pages/material-ui/api/icon-button.json | 17 + docs/pages/material-ui/api/loading-button.js | 23 - .../pages/material-ui/api/loading-button.json | 453 ------------------ docs/src/pagesApi.js | 1 - docs/translations/api-docs/button/button.json | 43 ++ .../api-docs/icon-button/icon-button.json | 15 + .../loading-button/loading-button.json | 356 -------------- .../src/LoadingButton/LoadingButton.d.ts | 82 +--- .../src/LoadingButton/LoadingButton.js | 363 +------------- .../src/LoadingButton/LoadingButton.spec.tsx | 16 - .../src/LoadingButton/LoadingButton.test.js | 117 ----- packages/mui-lab/src/LoadingButton/index.d.ts | 3 - packages/mui-lab/src/LoadingButton/index.js | 3 - .../src/LoadingButton/loadingButtonClasses.ts | 43 -- packages/mui-material/src/Button/Button.d.ts | 17 + packages/mui-material/src/Button/Button.js | 222 ++++++++- .../mui-material/src/Button/Button.spec.tsx | 14 + .../mui-material/src/Button/Button.test.js | 44 +- .../mui-material/src/Button/buttonClasses.ts | 21 + .../src/IconButton/IconButton.d.ts | 12 + .../mui-material/src/IconButton/IconButton.js | 57 ++- .../src/IconButton/IconButton.test.js | 44 +- .../src/IconButton/iconButtonClasses.ts | 6 + .../Button/FullWidthLoadingButtons.js | 14 +- 47 files changed, 862 insertions(+), 1587 deletions(-) create mode 100644 docs/data/material/components/buttons/IconButtonWithBadge.js create mode 100644 docs/data/material/components/buttons/IconButtonWithBadge.tsx create mode 100644 docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview delete mode 100644 docs/data/material/components/buttons/LoadingButtons.tsx.preview create mode 100644 docs/data/material/components/buttons/LoadingIconButton.js create mode 100644 docs/data/material/components/buttons/LoadingIconButton.tsx create mode 100644 docs/data/material/components/buttons/LoadingIconButton.tsx.preview delete mode 100644 docs/pages/material-ui/api/loading-button.js delete mode 100644 docs/pages/material-ui/api/loading-button.json delete mode 100644 docs/translations/api-docs/loading-button/loading-button.json delete mode 100644 packages/mui-lab/src/LoadingButton/LoadingButton.spec.tsx delete mode 100644 packages/mui-lab/src/LoadingButton/LoadingButton.test.js delete mode 100644 packages/mui-lab/src/LoadingButton/loadingButtonClasses.ts diff --git a/docs/data/material/components/button-group/LoadingButtonGroup.js b/docs/data/material/components/button-group/LoadingButtonGroup.js index 989f028daf7a56..fd146a90620d10 100644 --- a/docs/data/material/components/button-group/LoadingButtonGroup.js +++ b/docs/data/material/components/button-group/LoadingButtonGroup.js @@ -1,17 +1,16 @@ import * as React from 'react'; import ButtonGroup from '@mui/material/ButtonGroup'; import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; import SaveIcon from '@mui/icons-material/Save'; export default function LoadingButtonGroup() { return ( - Fetch data - }> + + ); } diff --git a/docs/data/material/components/button-group/LoadingButtonGroup.tsx b/docs/data/material/components/button-group/LoadingButtonGroup.tsx index 989f028daf7a56..fd146a90620d10 100644 --- a/docs/data/material/components/button-group/LoadingButtonGroup.tsx +++ b/docs/data/material/components/button-group/LoadingButtonGroup.tsx @@ -1,17 +1,16 @@ import * as React from 'react'; import ButtonGroup from '@mui/material/ButtonGroup'; import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; import SaveIcon from '@mui/icons-material/Save'; export default function LoadingButtonGroup() { return ( - Fetch data - }> + + ); } diff --git a/docs/data/material/components/button-group/LoadingButtonGroup.tsx.preview b/docs/data/material/components/button-group/LoadingButtonGroup.tsx.preview index 51360c91557385..a69903f1fca35c 100644 --- a/docs/data/material/components/button-group/LoadingButtonGroup.tsx.preview +++ b/docs/data/material/components/button-group/LoadingButtonGroup.tsx.preview @@ -1,7 +1,7 @@ - Fetch data - }> + + \ No newline at end of file diff --git a/docs/data/material/components/button-group/button-group.md b/docs/data/material/components/button-group/button-group.md index 6cc23f74925aec..5bceb0b6ab282b 100644 --- a/docs/data/material/components/button-group/button-group.md +++ b/docs/data/material/components/button-group/button-group.md @@ -1,7 +1,7 @@ --- productId: material-ui title: React Button Group component -components: Button, ButtonGroup, LoadingButton +components: Button, ButtonGroup githubLabel: 'component: ButtonGroup' githubSource: packages/mui-material/src/ButtonGroup --- @@ -49,10 +49,8 @@ You can remove the elevation with the `disableElevation` prop. {{"demo": "DisableElevation.js"}} -## Experimental APIs +## Loading -### Loading button - -You can use the [``](/material-ui/react-button/#loading-button) from [`@mui/lab`](/material-ui/about-the-lab/) in the button group. +Use the `loading` prop from `Button` to set buttons in a loading state and disable interactions. {{"demo": "LoadingButtonGroup.js"}} diff --git a/docs/data/material/components/buttons/IconButtonWithBadge.js b/docs/data/material/components/buttons/IconButtonWithBadge.js new file mode 100644 index 00000000000000..6a00cbd44b6180 --- /dev/null +++ b/docs/data/material/components/buttons/IconButtonWithBadge.js @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { styled } from '@mui/material/styles'; +import IconButton from '@mui/material/IconButton'; +import Badge, { badgeClasses } from '@mui/material/Badge'; +import Stack from '@mui/material/Stack'; +import SaveIcon from '@mui/icons-material/Save'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCartOutlined'; + +const CartBadge = styled(Badge)` + .${badgeClasses.badge} { + top: -12px; + right: -6px; + } +`; + +export default function IconButtonWithBadge() { + const [loading, setLoading] = React.useState(false); + React.useEffect(() => { + const timeout = setTimeout(() => { + setLoading(false); + }, 2000); + return () => clearTimeout(timeout); + }); + return ( + + + + + + + setLoading(true)}> + + + + + ); +} diff --git a/docs/data/material/components/buttons/IconButtonWithBadge.tsx b/docs/data/material/components/buttons/IconButtonWithBadge.tsx new file mode 100644 index 00000000000000..6a00cbd44b6180 --- /dev/null +++ b/docs/data/material/components/buttons/IconButtonWithBadge.tsx @@ -0,0 +1,37 @@ +import * as React from 'react'; +import { styled } from '@mui/material/styles'; +import IconButton from '@mui/material/IconButton'; +import Badge, { badgeClasses } from '@mui/material/Badge'; +import Stack from '@mui/material/Stack'; +import SaveIcon from '@mui/icons-material/Save'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCartOutlined'; + +const CartBadge = styled(Badge)` + .${badgeClasses.badge} { + top: -12px; + right: -6px; + } +`; + +export default function IconButtonWithBadge() { + const [loading, setLoading] = React.useState(false); + React.useEffect(() => { + const timeout = setTimeout(() => { + setLoading(false); + }, 2000); + return () => clearTimeout(timeout); + }); + return ( + + + + + + + setLoading(true)}> + + + + + ); +} diff --git a/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview b/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview new file mode 100644 index 00000000000000..cfe404e63cb83d --- /dev/null +++ b/docs/data/material/components/buttons/IconButtonWithBadge.tsx.preview @@ -0,0 +1,9 @@ + + + + + + setLoading(true)}> + + + \ No newline at end of file diff --git a/docs/data/material/components/buttons/LoadingButtons.js b/docs/data/material/components/buttons/LoadingButtons.js index f2d71b178ab98d..09d568b124c92d 100644 --- a/docs/data/material/components/buttons/LoadingButtons.js +++ b/docs/data/material/components/buttons/LoadingButtons.js @@ -1,25 +1,45 @@ import * as React from 'react'; -import LoadingButton from '@mui/lab/LoadingButton'; +import Button from '@mui/material/Button'; import SaveIcon from '@mui/icons-material/Save'; import Stack from '@mui/material/Stack'; export default function LoadingButtons() { return ( - - - Submit - - - Fetch data - - + + + + + + + ); } diff --git a/docs/data/material/components/buttons/LoadingButtons.tsx b/docs/data/material/components/buttons/LoadingButtons.tsx index f2d71b178ab98d..09d568b124c92d 100644 --- a/docs/data/material/components/buttons/LoadingButtons.tsx +++ b/docs/data/material/components/buttons/LoadingButtons.tsx @@ -1,25 +1,45 @@ import * as React from 'react'; -import LoadingButton from '@mui/lab/LoadingButton'; +import Button from '@mui/material/Button'; import SaveIcon from '@mui/icons-material/Save'; import Stack from '@mui/material/Stack'; export default function LoadingButtons() { return ( - - - Submit - - - Fetch data - - + + + + + + + ); } diff --git a/docs/data/material/components/buttons/LoadingButtons.tsx.preview b/docs/data/material/components/buttons/LoadingButtons.tsx.preview deleted file mode 100644 index 9578d91a245686..00000000000000 --- a/docs/data/material/components/buttons/LoadingButtons.tsx.preview +++ /dev/null @@ -1,14 +0,0 @@ - - Submit - - - Fetch data - -} - variant="outlined" -> - Save - \ No newline at end of file diff --git a/docs/data/material/components/buttons/LoadingButtonsTransition.js b/docs/data/material/components/buttons/LoadingButtonsTransition.js index 21b0f2bd331d26..2278b2684fe7b5 100644 --- a/docs/data/material/components/buttons/LoadingButtonsTransition.js +++ b/docs/data/material/components/buttons/LoadingButtonsTransition.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import LoadingButton from '@mui/lab/LoadingButton'; +import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import FormControlLabel from '@mui/material/FormControlLabel'; import Switch from '@mui/material/Switch'; @@ -27,7 +27,7 @@ export default function LoadingButtonsTransition() { label="Loading" /> button': { m: 1 } }}> - Disabled - - + button': { m: 1 } }}> - + ); diff --git a/docs/data/material/components/buttons/LoadingButtonsTransition.tsx b/docs/data/material/components/buttons/LoadingButtonsTransition.tsx index 21b0f2bd331d26..2278b2684fe7b5 100644 --- a/docs/data/material/components/buttons/LoadingButtonsTransition.tsx +++ b/docs/data/material/components/buttons/LoadingButtonsTransition.tsx @@ -1,5 +1,5 @@ import * as React from 'react'; -import LoadingButton from '@mui/lab/LoadingButton'; +import Button from '@mui/material/Button'; import Box from '@mui/material/Box'; import FormControlLabel from '@mui/material/FormControlLabel'; import Switch from '@mui/material/Switch'; @@ -27,7 +27,7 @@ export default function LoadingButtonsTransition() { label="Loading" /> button': { m: 1 } }}> - Disabled - - + button': { m: 1 } }}> - + ); diff --git a/docs/data/material/components/buttons/LoadingIconButton.js b/docs/data/material/components/buttons/LoadingIconButton.js new file mode 100644 index 00000000000000..6778d7281d47d7 --- /dev/null +++ b/docs/data/material/components/buttons/LoadingIconButton.js @@ -0,0 +1,21 @@ +import * as React from 'react'; +import Tooltip from '@mui/material/Tooltip'; +import IconButton from '@mui/material/IconButton'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; + +export default function LoadingIconButton() { + const [loading, setLoading] = React.useState(false); + React.useEffect(() => { + const timeout = setTimeout(() => { + setLoading(false); + }, 2000); + return () => clearTimeout(timeout); + }); + return ( + + setLoading(true)} loading={loading}> + + + + ); +} diff --git a/docs/data/material/components/buttons/LoadingIconButton.tsx b/docs/data/material/components/buttons/LoadingIconButton.tsx new file mode 100644 index 00000000000000..6778d7281d47d7 --- /dev/null +++ b/docs/data/material/components/buttons/LoadingIconButton.tsx @@ -0,0 +1,21 @@ +import * as React from 'react'; +import Tooltip from '@mui/material/Tooltip'; +import IconButton from '@mui/material/IconButton'; +import ShoppingCartIcon from '@mui/icons-material/ShoppingCart'; + +export default function LoadingIconButton() { + const [loading, setLoading] = React.useState(false); + React.useEffect(() => { + const timeout = setTimeout(() => { + setLoading(false); + }, 2000); + return () => clearTimeout(timeout); + }); + return ( + + setLoading(true)} loading={loading}> + + + + ); +} diff --git a/docs/data/material/components/buttons/LoadingIconButton.tsx.preview b/docs/data/material/components/buttons/LoadingIconButton.tsx.preview new file mode 100644 index 00000000000000..9c9a8b0cbf868a --- /dev/null +++ b/docs/data/material/components/buttons/LoadingIconButton.tsx.preview @@ -0,0 +1,5 @@ + + setLoading(true)} loading={loading}> + + + \ No newline at end of file diff --git a/docs/data/material/components/buttons/buttons.md b/docs/data/material/components/buttons/buttons.md index 4da25aa7e55f5f..660f4233fa93aa 100644 --- a/docs/data/material/components/buttons/buttons.md +++ b/docs/data/material/components/buttons/buttons.md @@ -1,7 +1,7 @@ --- productId: material-ui title: React Button component -components: Button, IconButton, ButtonBase, LoadingButton +components: Button, IconButton, ButtonBase materialDesign: https://m2.material.io/components/buttons githubLabel: 'component: button' waiAria: https://www.w3.org/WAI/ARIA/apg/patterns/button/ @@ -113,12 +113,34 @@ Use `color` prop to apply theme color palette to component. {{"demo": "IconButtonColors.js"}} +### Loading + +Starting from [`v6.2.0`](https://github.com/mui/material-ui/releases/tag/v6.2.0), use `loading` prop to set icon buttons in a loading state and disable interactions. + +{{"demo": "LoadingIconButton.js"}} + +### Badge + +You can use the [`Badge`](/material-ui/react-badge/) component to add a badge to an `IconButton`. + +{{"demo": "IconButtonWithBadge.js"}} + ## File upload To create a file upload button, turn the button into a label using `component="label"` and then create a visually-hidden input with type `file`. {{"demo": "InputFileUpload.js"}} +## Loading + +Starting from [`v6.2.0`](https://github.com/mui/material-ui/releases/tag/v6.2.0), use the `loading` prop to set buttons in a loading state and disable interactions. + +{{"demo": "LoadingButtons.js"}} + +Toggle the loading switch to see the transition between the different states. + +{{"demo": "LoadingButtonsTransition.js"}} + ## Customization Here are some examples of customizing the component. @@ -174,15 +196,3 @@ However: ``` This has the advantage of supporting any element, for instance, a link `` element. - -## Experimental APIs - -### Loading button - -[`@mui/lab`](/material-ui/about-the-lab/) offers loading buttons that can show loading state and disable interactions. - -{{"demo": "LoadingButtons.js"}} - -Toggle the loading switch to see the transition between the different states. - -{{"demo": "LoadingButtonsTransition.js"}} diff --git a/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.js b/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.js index c51820532be8de..45c5878821cf2a 100644 --- a/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.js +++ b/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.js @@ -2,7 +2,6 @@ import * as React from 'react'; import PropTypes from 'prop-types'; import { DialogsProvider, useDialogs } from '@toolpad/core/useDialogs'; import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; import Dialog from '@mui/material/Dialog'; import Alert from '@mui/material/Alert'; import DialogTitle from '@mui/material/DialogTitle'; @@ -99,13 +98,9 @@ function DemoContent() { return (
- +
); diff --git a/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.tsx b/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.tsx index 1fd85d043d9c2f..1d6aa7dacc434f 100644 --- a/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.tsx +++ b/docs/data/material/components/dialogs/ToolpadDialogsNoSnap.tsx @@ -1,7 +1,6 @@ import * as React from 'react'; import { DialogsProvider, useDialogs, DialogProps } from '@toolpad/core/useDialogs'; import Button from '@mui/material/Button'; -import LoadingButton from '@mui/lab/LoadingButton'; import Dialog from '@mui/material/Dialog'; import Alert from '@mui/material/Alert'; import DialogTitle from '@mui/material/DialogTitle'; @@ -80,13 +79,9 @@ function DemoContent() { return (
- +
); diff --git a/docs/data/material/migration/upgrade-to-v6/upgrade-to-v6.md b/docs/data/material/migration/upgrade-to-v6/upgrade-to-v6.md index 00559f268f5d28..c4fcc9af9dd1e4 100644 --- a/docs/data/material/migration/upgrade-to-v6/upgrade-to-v6.md +++ b/docs/data/material/migration/upgrade-to-v6/upgrade-to-v6.md @@ -356,9 +356,21 @@ As the `ListItem` no longer supports these props, the class names related to the +listItemButtonClasses.selected ``` -### Loading Button +### Button with Loading State -In v6, the `children` prop passed to the Loading Button component is now wrapped in a `` tag to avoid [issues](https://github.com/mui/material-ui/issues/27853) when using tools to translate websites. +As of `@mui/material` **v6.2.0**, the `LoadingButton` from Lab has been removed. Loading functionality is now part of the standard `Button` component. Update your import as follows: + +```diff +-import { LoadingButton } from '@mui/lab'; ++import { Button } from '@mui/material'; +``` + +```diff +-import LoadingButton from '@mui/lab/LoadingButton'; ++import Button from '@mui/material/Button'; +``` + +For more details, see the [Loading section](/material-ui/react-button/#loading-2) in the [Material UI `Button` documentation](/material-ui/react-button/). ### Typography diff --git a/docs/data/material/pagesApi.js b/docs/data/material/pagesApi.js index 2c6f1e2aca5155..7c0e8e172b7b08 100644 --- a/docs/data/material/pagesApi.js +++ b/docs/data/material/pagesApi.js @@ -70,7 +70,6 @@ module.exports = [ { pathname: '/material-ui/api/list-item-secondary-action' }, { pathname: '/material-ui/api/list-item-text' }, { pathname: '/material-ui/api/list-subheader' }, - { pathname: '/material-ui/api/loading-button' }, { pathname: '/material-ui/api/masonry' }, { pathname: '/material-ui/api/menu' }, { pathname: '/material-ui/api/menu-item' }, diff --git a/docs/pages/blog/2020-q2-update.md b/docs/pages/blog/2020-q2-update.md index 6d34a639194694..29f38b8eee2ea2 100644 --- a/docs/pages/blog/2020-q2-update.md +++ b/docs/pages/blog/2020-q2-update.md @@ -27,7 +27,7 @@ Here are the most significant improvements since March 2020: Adobe XD and Framer support are also up for consideration if they attract a significant audience, but not until we've polished the Sketch and Figma assets. -- 🔄 `LoadingButton` – [a new component in the lab](https://mui.com/material-ui/react-button/#loading-button). This work is influenced by the [concurrent UI patterns](https://17.reactjs.org/docs/concurrent-mode-patterns.html) presented by the React team. +- 🔄 `LoadingButton` – [a new component in the lab](https://v5.mui.com/material-ui/react-button/#loading-button). This work is influenced by the [concurrent UI patterns](https://17.reactjs.org/docs/concurrent-mode-patterns.html) presented by the React team. loading diff --git a/docs/pages/blog/mui-core-v5.md b/docs/pages/blog/mui-core-v5.md index 08bca2d4844f2a..4a2e55c467a95c 100644 --- a/docs/pages/blog/mui-core-v5.md +++ b/docs/pages/blog/mui-core-v5.md @@ -602,7 +602,7 @@ Having a separate lab package allows us to release breaking changes when necessa The following components are now available in the lab: -- [LoadingButton](/material-ui/react-button/#loading-button). It does what you would expect. It renders the `Button` with a configurable loading/pending state. +- [LoadingButton](https://v5.mui.com/material-ui/react-button/#loading-button). It does what you would expect. It renders the `Button` with a configurable loading/pending state. - [FocusTrap](/base-ui/react-focus-trap/). This component traps the keyboard focus within a DOM node. For example, it's used by the Modal to prevent tabbing out of the component for accessibility reasons. - [Masonry](/material-ui/react-masonry/). One great use case for this component is when using the `Grid` component leads to wasted space. It's frequently used in dashboards. diff --git a/docs/pages/material-ui/api/button.json b/docs/pages/material-ui/api/button.json index 04a03e76d983d5..996ab60f6e6a63 100644 --- a/docs/pages/material-ui/api/button.json +++ b/docs/pages/material-ui/api/button.json @@ -17,6 +17,18 @@ "endIcon": { "type": { "name": "node" } }, "fullWidth": { "type": { "name": "bool" }, "default": "false" }, "href": { "type": { "name": "string" } }, + "loading": { "type": { "name": "bool" }, "default": "false" }, + "loadingIndicator": { + "type": { "name": "node" }, + "default": "" + }, + "loadingPosition": { + "type": { + "name": "enum", + "description": "'center'
| 'end'
| 'start'" + }, + "default": "'center'" + }, "size": { "type": { "name": "union", @@ -182,6 +194,12 @@ "description": "Styles applied to the endIcon element if supplied.", "isGlobal": false }, + { + "key": "endIconLoadingEnd", + "className": "MuiButton-endIconLoadingEnd", + "description": "Styles applied to the endIcon element if `loading={true}` and `loadingPosition=\"end\"`.", + "isGlobal": false + }, { "key": "focusVisible", "className": "Mui-focusVisible", @@ -221,6 +239,36 @@ "isGlobal": false, "isDeprecated": true }, + { + "key": "loading", + "className": "MuiButton-loading", + "description": "Styles applied to the root element if `loading={true}`.", + "isGlobal": false + }, + { + "key": "loadingIndicator", + "className": "MuiButton-loadingIndicator", + "description": "Styles applied to the loadingIndicator element.", + "isGlobal": false + }, + { + "key": "loadingIndicatorCenter", + "className": "MuiButton-loadingIndicatorCenter", + "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"center\"`.", + "isGlobal": false + }, + { + "key": "loadingIndicatorEnd", + "className": "MuiButton-loadingIndicatorEnd", + "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"end\"`.", + "isGlobal": false + }, + { + "key": "loadingIndicatorStart", + "className": "MuiButton-loadingIndicatorStart", + "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"start\"`.", + "isGlobal": false + }, { "key": "outlined", "className": "MuiButton-outlined", @@ -327,6 +375,12 @@ "description": "Styles applied to the startIcon element if supplied.", "isGlobal": false }, + { + "key": "startIconLoadingStart", + "className": "MuiButton-startIconLoadingStart", + "description": "Styles applied to the startIcon element if `loading={true}` and `loadingPosition=\"start\"`.", + "isGlobal": false + }, { "key": "text", "className": "MuiButton-text", diff --git a/docs/pages/material-ui/api/icon-button.json b/docs/pages/material-ui/api/icon-button.json index 752030e32dcce9..09cb6b9e7dc49e 100644 --- a/docs/pages/material-ui/api/icon-button.json +++ b/docs/pages/material-ui/api/icon-button.json @@ -19,6 +19,11 @@ }, "default": "false" }, + "loading": { "type": { "name": "bool" }, "default": "false" }, + "loadingIndicator": { + "type": { "name": "node" }, + "default": "" + }, "size": { "type": { "name": "union", @@ -100,6 +105,18 @@ "description": "Styles applied to the root element if `edge=\"start\"`.", "isGlobal": false }, + { + "key": "loading", + "className": "MuiIconButton-loading", + "description": "Styles applied to the root element if `loading={true}`.", + "isGlobal": false + }, + { + "key": "loadingIndicator", + "className": "MuiIconButton-loadingIndicator", + "description": "Styles applied to the loadingIndicator element.", + "isGlobal": false + }, { "key": "root", "className": "MuiIconButton-root", diff --git a/docs/pages/material-ui/api/loading-button.js b/docs/pages/material-ui/api/loading-button.js deleted file mode 100644 index cab581691ab572..00000000000000 --- a/docs/pages/material-ui/api/loading-button.js +++ /dev/null @@ -1,23 +0,0 @@ -import * as React from 'react'; -import ApiPage from 'docs/src/modules/components/ApiPage'; -import mapApiPageTranslations from 'docs/src/modules/utils/mapApiPageTranslations'; -import jsonPageContent from './loading-button.json'; - -export default function Page(props) { - const { descriptions, pageContent } = props; - return ; -} - -Page.getInitialProps = () => { - const req = require.context( - 'docs/translations/api-docs/loading-button', - false, - /\.\/loading-button.*.json$/, - ); - const descriptions = mapApiPageTranslations(req); - - return { - descriptions, - pageContent: jsonPageContent, - }; -}; diff --git a/docs/pages/material-ui/api/loading-button.json b/docs/pages/material-ui/api/loading-button.json deleted file mode 100644 index 8155927a65f266..00000000000000 --- a/docs/pages/material-ui/api/loading-button.json +++ /dev/null @@ -1,453 +0,0 @@ -{ - "props": { - "children": { "type": { "name": "node" } }, - "classes": { "type": { "name": "object" }, "additionalInfo": { "cssApi": true } }, - "disabled": { "type": { "name": "bool" }, "default": "false" }, - "loading": { "type": { "name": "bool" }, "default": "false" }, - "loadingIndicator": { - "type": { "name": "node" }, - "default": "" - }, - "loadingPosition": { - "type": { - "name": "custom", - "description": "'start'
| 'end'
| 'center'" - }, - "default": "'center'" - }, - "sx": { - "type": { - "name": "union", - "description": "Array<func
| object
| bool>
| func
| object" - }, - "additionalInfo": { "sx": true } - }, - "variant": { - "type": { - "name": "union", - "description": "'contained'
| 'outlined'
| 'text'
| string" - }, - "default": "'text'" - } - }, - "name": "LoadingButton", - "imports": [ - "import LoadingButton from '@mui/lab/LoadingButton';", - "import { LoadingButton } from '@mui/lab';" - ], - "classes": [ - { - "key": "colorError", - "className": "MuiLoadingButton-colorError", - "description": "Styles applied to the root element if `color=\"error\"`.", - "isGlobal": false - }, - { - "key": "colorInfo", - "className": "MuiLoadingButton-colorInfo", - "description": "Styles applied to the root element if `color=\"info\"`.", - "isGlobal": false - }, - { - "key": "colorInherit", - "className": "MuiLoadingButton-colorInherit", - "description": "Styles applied to the root element if `color=\"inherit\"`.", - "isGlobal": false - }, - { - "key": "colorPrimary", - "className": "MuiLoadingButton-colorPrimary", - "description": "Styles applied to the root element if `color=\"primary\"`.", - "isGlobal": false - }, - { - "key": "colorSecondary", - "className": "MuiLoadingButton-colorSecondary", - "description": "Styles applied to the root element if `color=\"secondary\"`.", - "isGlobal": false - }, - { - "key": "colorSuccess", - "className": "MuiLoadingButton-colorSuccess", - "description": "Styles applied to the root element if `color=\"success\"`.", - "isGlobal": false - }, - { - "key": "colorWarning", - "className": "MuiLoadingButton-colorWarning", - "description": "Styles applied to the root element if `color=\"warning\"`.", - "isGlobal": false - }, - { - "key": "contained", - "className": "MuiLoadingButton-contained", - "description": "Styles applied to the root element if `variant=\"contained\"`.", - "isGlobal": false - }, - { - "key": "containedError", - "className": "MuiLoadingButton-containedError", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"error\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedInfo", - "className": "MuiLoadingButton-containedInfo", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"info\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedInherit", - "className": "MuiLoadingButton-containedInherit", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"inherit\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedPrimary", - "className": "MuiLoadingButton-containedPrimary", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"primary\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedSecondary", - "className": "MuiLoadingButton-containedSecondary", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"secondary\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedSizeLarge", - "className": "MuiLoadingButton-containedSizeLarge", - "description": "Styles applied to the root element if `size=\"large\"` and `variant=\"contained\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedSizeMedium", - "className": "MuiLoadingButton-containedSizeMedium", - "description": "Styles applied to the root element if `size=\"medium\"` and `variant=\"contained\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedSizeSmall", - "className": "MuiLoadingButton-containedSizeSmall", - "description": "Styles applied to the root element if `size=\"small\"` and `variant=\"contained\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedSuccess", - "className": "MuiLoadingButton-containedSuccess", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"success\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "containedWarning", - "className": "MuiLoadingButton-containedWarning", - "description": "Styles applied to the root element if `variant=\"contained\"` and `color=\"warning\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "disabled", - "className": "Mui-disabled", - "description": "State class applied to the root element if `disabled={true}`.", - "isGlobal": true - }, - { - "key": "disableElevation", - "className": "MuiLoadingButton-disableElevation", - "description": "Styles applied to the root element if `disableElevation={true}`.", - "isGlobal": false - }, - { - "key": "endIcon", - "className": "MuiLoadingButton-endIcon", - "description": "Styles applied to the endIcon element if supplied.", - "isGlobal": false - }, - { - "key": "endIconLoadingEnd", - "className": "MuiLoadingButton-endIconLoadingEnd", - "description": "Styles applied to the endIcon element if `loading={true}` and `loadingPosition=\"end\"`.", - "isGlobal": false - }, - { - "key": "focusVisible", - "className": "Mui-focusVisible", - "description": "State class applied to the ButtonBase root element if the button is keyboard focused.", - "isGlobal": true - }, - { - "key": "fullWidth", - "className": "MuiLoadingButton-fullWidth", - "description": "Styles applied to the root element if `fullWidth={true}`.", - "isGlobal": false - }, - { - "key": "icon", - "className": "MuiLoadingButton-icon", - "description": "Styles applied to the icon element if supplied", - "isGlobal": false - }, - { - "key": "iconSizeLarge", - "className": "MuiLoadingButton-iconSizeLarge", - "description": "Styles applied to the icon element if supplied and `size=\"large\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "iconSizeMedium", - "className": "MuiLoadingButton-iconSizeMedium", - "description": "Styles applied to the icon element if supplied and `size=\"medium\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "iconSizeSmall", - "className": "MuiLoadingButton-iconSizeSmall", - "description": "Styles applied to the icon element if supplied and `size=\"small\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "label", - "className": "MuiLoadingButton-label", - "description": "Styles applied to the span element that wraps the children.", - "isGlobal": false - }, - { - "key": "loading", - "className": "MuiLoadingButton-loading", - "description": "Styles applied to the root element if `loading={true}`.", - "isGlobal": false - }, - { - "key": "loadingIndicator", - "className": "MuiLoadingButton-loadingIndicator", - "description": "Styles applied to the loadingIndicator element.", - "isGlobal": false - }, - { - "key": "loadingIndicatorCenter", - "className": "MuiLoadingButton-loadingIndicatorCenter", - "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"center\"`.", - "isGlobal": false - }, - { - "key": "loadingIndicatorEnd", - "className": "MuiLoadingButton-loadingIndicatorEnd", - "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"end\"`.", - "isGlobal": false - }, - { - "key": "loadingIndicatorStart", - "className": "MuiLoadingButton-loadingIndicatorStart", - "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"start\"`.", - "isGlobal": false - }, - { - "key": "outlined", - "className": "MuiLoadingButton-outlined", - "description": "Styles applied to the root element if `variant=\"outlined\"`.", - "isGlobal": false - }, - { - "key": "outlinedError", - "className": "MuiLoadingButton-outlinedError", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"error\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedInfo", - "className": "MuiLoadingButton-outlinedInfo", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"info\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedInherit", - "className": "MuiLoadingButton-outlinedInherit", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"inherit\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedPrimary", - "className": "MuiLoadingButton-outlinedPrimary", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"primary\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedSecondary", - "className": "MuiLoadingButton-outlinedSecondary", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"secondary\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedSizeLarge", - "className": "MuiLoadingButton-outlinedSizeLarge", - "description": "Styles applied to the root element if `size=\"large\"` and `variant=\"outlined\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedSizeMedium", - "className": "MuiLoadingButton-outlinedSizeMedium", - "description": "Styles applied to the root element if `size=\"medium\"` and `variant=\"outlined\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedSizeSmall", - "className": "MuiLoadingButton-outlinedSizeSmall", - "description": "Styles applied to the root element if `size=\"small\"` and `variant=\"outlined\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedSuccess", - "className": "MuiLoadingButton-outlinedSuccess", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"success\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "outlinedWarning", - "className": "MuiLoadingButton-outlinedWarning", - "description": "Styles applied to the root element if `variant=\"outlined\"` and `color=\"warning\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "root", - "className": "MuiLoadingButton-root", - "description": "Styles applied to the root element.", - "isGlobal": false - }, - { - "key": "sizeLarge", - "className": "MuiLoadingButton-sizeLarge", - "description": "Styles applied to the root element if `size=\"large\"`.", - "isGlobal": false - }, - { - "key": "sizeMedium", - "className": "MuiLoadingButton-sizeMedium", - "description": "Styles applied to the root element if `size=\"medium\"`.", - "isGlobal": false - }, - { - "key": "sizeSmall", - "className": "MuiLoadingButton-sizeSmall", - "description": "Styles applied to the root element if `size=\"small\"`.", - "isGlobal": false - }, - { - "key": "startIcon", - "className": "MuiLoadingButton-startIcon", - "description": "Styles applied to the startIcon element if supplied.", - "isGlobal": false - }, - { - "key": "startIconLoadingStart", - "className": "MuiLoadingButton-startIconLoadingStart", - "description": "Styles applied to the startIcon element if `loading={true}` and `loadingPosition=\"start\"`.", - "isGlobal": false - }, - { - "key": "text", - "className": "MuiLoadingButton-text", - "description": "Styles applied to the root element if `variant=\"text\"`.", - "isGlobal": false - }, - { - "key": "textError", - "className": "MuiLoadingButton-textError", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"error\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textInfo", - "className": "MuiLoadingButton-textInfo", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"info\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textInherit", - "className": "MuiLoadingButton-textInherit", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"inherit\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textPrimary", - "className": "MuiLoadingButton-textPrimary", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"primary\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textSecondary", - "className": "MuiLoadingButton-textSecondary", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"secondary\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textSizeLarge", - "className": "MuiLoadingButton-textSizeLarge", - "description": "Styles applied to the root element if `size=\"large\"` and `variant=\"text\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textSizeMedium", - "className": "MuiLoadingButton-textSizeMedium", - "description": "Styles applied to the root element if `size=\"medium\"` and `variant=\"text\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textSizeSmall", - "className": "MuiLoadingButton-textSizeSmall", - "description": "Styles applied to the root element if `size=\"small\"` and `variant=\"text\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textSuccess", - "className": "MuiLoadingButton-textSuccess", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"success\"`.", - "isGlobal": false, - "isDeprecated": true - }, - { - "key": "textWarning", - "className": "MuiLoadingButton-textWarning", - "description": "Styles applied to the root element if `variant=\"text\"` and `color=\"warning\"`.", - "isGlobal": false, - "isDeprecated": true - } - ], - "spread": true, - "themeDefaultProps": true, - "muiName": "MuiLoadingButton", - "forwardsRefTo": "HTMLButtonElement", - "filename": "/packages/mui-lab/src/LoadingButton/LoadingButton.js", - "inheritance": { "component": "Button", "pathname": "/material-ui/api/button/" }, - "demos": "
", - "cssComponent": false -} diff --git a/docs/src/pagesApi.js b/docs/src/pagesApi.js index c9829209aec475..8c040f448a4d23 100644 --- a/docs/src/pagesApi.js +++ b/docs/src/pagesApi.js @@ -67,7 +67,6 @@ module.exports = [ { pathname: '/api-docs/list-item-secondary-action' }, { pathname: '/api-docs/list-item-text' }, { pathname: '/api-docs/list-subheader' }, - { pathname: '/api-docs/loading-button' }, { pathname: '/api-docs/masonry' }, { pathname: '/api-docs/menu' }, { pathname: '/api-docs/menu-item' }, diff --git a/docs/translations/api-docs/button/button.json b/docs/translations/api-docs/button/button.json index 1e9426f65ac3de..14a7ad2f58db52 100644 --- a/docs/translations/api-docs/button/button.json +++ b/docs/translations/api-docs/button/button.json @@ -24,6 +24,15 @@ "href": { "description": "The URL to link to when the button is clicked. If defined, an a element will be used as the root node." }, + "loading": { + "description": "If true, the loading indicator is visible and the button is disabled." + }, + "loadingIndicator": { + "description": "Element placed before the children if the button is in loading state. The node should contain an element with role="progressbar" with an accessible name. By default, it renders a CircularProgress that is labeled by the button itself." + }, + "loadingPosition": { + "description": "The loading indicator can be positioned on the start, end, or the center of the button." + }, "size": { "description": "The size of the component. small is equivalent to the dense button styling." }, @@ -149,6 +158,11 @@ "nodeName": "the endIcon element", "conditions": "supplied" }, + "endIconLoadingEnd": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the endIcon element", + "conditions": "loading={true} and loadingPosition=\"end\"" + }, "focusVisible": { "description": "State class applied to {{nodeName}} if {{conditions}}.", "nodeName": "the ButtonBase root element", @@ -178,6 +192,30 @@ "conditions": "supplied and size=\"small\"", "deprecationInfo": "Combine the .MuiButton-icon and .MuiButtonSizeSmall classes instead. See Migrating from deprecated APIs for more details." }, + "loading": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "loading={true}" + }, + "loadingIndicator": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the loadingIndicator element" + }, + "loadingIndicatorCenter": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the loadingIndicator element", + "conditions": "loadingPosition=\"center\"" + }, + "loadingIndicatorEnd": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the loadingIndicator element", + "conditions": "loadingPosition=\"end\"" + }, + "loadingIndicatorStart": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the loadingIndicator element", + "conditions": "loadingPosition=\"start\"" + }, "outlined": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", @@ -264,6 +302,11 @@ "nodeName": "the startIcon element", "conditions": "supplied" }, + "startIconLoadingStart": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the startIcon element", + "conditions": "loading={true} and loadingPosition=\"start\"" + }, "text": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", diff --git a/docs/translations/api-docs/icon-button/icon-button.json b/docs/translations/api-docs/icon-button/icon-button.json index 76558bfba72680..a54834e31d136a 100644 --- a/docs/translations/api-docs/icon-button/icon-button.json +++ b/docs/translations/api-docs/icon-button/icon-button.json @@ -16,6 +16,12 @@ "edge": { "description": "If given, uses a negative margin to counteract the padding on one side (this is often helpful for aligning the left or right side of the icon with content above or below, without ruining the border size and shape)." }, + "loading": { + "description": "If true, the loading indicator is visible and the button is disabled." + }, + "loadingIndicator": { + "description": "Element placed before the children if the button is in loading state. The node should contain an element with role="progressbar" with an accessible name. By default, it renders a CircularProgress that is labeled by the button itself." + }, "size": { "description": "The size of the component. small is equivalent to the dense button styling." }, @@ -74,6 +80,15 @@ "nodeName": "the root element", "conditions": "edge=\"start\"" }, + "loading": { + "description": "Styles applied to {{nodeName}} if {{conditions}}.", + "nodeName": "the root element", + "conditions": "loading={true}" + }, + "loadingIndicator": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the loadingIndicator element" + }, "root": { "description": "Styles applied to the root element." }, "sizeLarge": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", diff --git a/docs/translations/api-docs/loading-button/loading-button.json b/docs/translations/api-docs/loading-button/loading-button.json deleted file mode 100644 index 9babb1623d14c9..00000000000000 --- a/docs/translations/api-docs/loading-button/loading-button.json +++ /dev/null @@ -1,356 +0,0 @@ -{ - "componentDescription": "", - "propDescriptions": { - "children": { "description": "The content of the component." }, - "classes": { "description": "Override or extend the styles applied to the component." }, - "disabled": { "description": "If true, the component is disabled." }, - "loading": { - "description": "If true, the loading indicator is shown and the button becomes disabled." - }, - "loadingIndicator": { - "description": "Element placed before the children if the button is in loading state. The node should contain an element with role="progressbar" with an accessible name. By default we render a CircularProgress that is labelled by the button itself." - }, - "loadingPosition": { - "description": "The loading indicator can be positioned on the start, end, or the center of the button." - }, - "sx": { - "description": "The system prop that allows defining system overrides as well as additional CSS styles." - }, - "variant": { "description": "The variant to use." } - }, - "classDescriptions": { - "colorError": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"error\"" - }, - "colorInfo": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"info\"" - }, - "colorInherit": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"inherit\"" - }, - "colorPrimary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"primary\"" - }, - "colorSecondary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"secondary\"" - }, - "colorSuccess": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"success\"" - }, - "colorWarning": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "color=\"warning\"" - }, - "contained": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\"" - }, - "containedError": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"error\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorError classes instead. See Migrating from deprecated APIs for more details." - }, - "containedInfo": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"info\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorInfo classes instead. See Migrating from deprecated APIs for more details." - }, - "containedInherit": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"inherit\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorInherit classes instead. See Migrating from deprecated APIs for more details." - }, - "containedPrimary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"primary\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorPrimary classes instead. See Migrating from deprecated APIs for more details." - }, - "containedSecondary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"secondary\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorSecondary classes instead. See Migrating from deprecated APIs for more details." - }, - "containedSizeLarge": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"large\" and variant=\"contained\"", - "deprecationInfo": "Combine the .MuiButton-sizeLarge and .MuiButton-contained classes instead. See Migrating from deprecated APIs for more details." - }, - "containedSizeMedium": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"medium\" and variant=\"contained\"", - "deprecationInfo": "Combine the .MuiButton-sizeMedium and .MuiButton-contained classes instead. See Migrating from deprecated APIs for more details." - }, - "containedSizeSmall": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"small\" and variant=\"contained\"", - "deprecationInfo": "Combine the .MuiButton-sizeSmall and .MuiButton-contained classes instead. See Migrating from deprecated APIs for more details." - }, - "containedSuccess": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"success\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorSuccess classes instead. See Migrating from deprecated APIs for more details." - }, - "containedWarning": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"contained\" and color=\"warning\"", - "deprecationInfo": "Combine the .MuiButton-contained and .MuiButton-colorWarning classes instead. See Migrating from deprecated APIs for more details." - }, - "disabled": { - "description": "State class applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "disabled={true}" - }, - "disableElevation": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "disableElevation={true}" - }, - "endIcon": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the endIcon element", - "conditions": "supplied" - }, - "endIconLoadingEnd": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the endIcon element", - "conditions": "loading={true} and loadingPosition=\"end\"" - }, - "focusVisible": { - "description": "State class applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the ButtonBase root element", - "conditions": "the button is keyboard focused" - }, - "fullWidth": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "fullWidth={true}" - }, - "icon": { "description": "Styles applied to the icon element if supplied" }, - "iconSizeLarge": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the icon element", - "conditions": "supplied and size=\"large\"", - "deprecationInfo": "Combine the .MuiButton-icon and .MuiButtonSizeLarge classes instead. See Migrating from deprecated APIs for more details." - }, - "iconSizeMedium": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the icon element", - "conditions": "supplied and size=\"medium\"", - "deprecationInfo": "Combine the .MuiButton-icon and .MuiButtonSizeMedium classes instead. See Migrating from deprecated APIs for more details." - }, - "iconSizeSmall": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the icon element", - "conditions": "supplied and size=\"small\"", - "deprecationInfo": "Combine the .MuiButton-icon and .MuiButtonSizeSmall classes instead. See Migrating from deprecated APIs for more details." - }, - "label": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the span element that wraps the children" - }, - "loading": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "loading={true}" - }, - "loadingIndicator": { - "description": "Styles applied to {{nodeName}}.", - "nodeName": "the loadingIndicator element" - }, - "loadingIndicatorCenter": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the loadingIndicator element", - "conditions": "loadingPosition=\"center\"" - }, - "loadingIndicatorEnd": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the loadingIndicator element", - "conditions": "loadingPosition=\"end\"" - }, - "loadingIndicatorStart": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the loadingIndicator element", - "conditions": "loadingPosition=\"start\"" - }, - "outlined": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\"" - }, - "outlinedError": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"error\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorError classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedInfo": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"info\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorInfo classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedInherit": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"inherit\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorInherit classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedPrimary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"primary\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorPrimary classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedSecondary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"secondary\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorSecondary classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedSizeLarge": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"large\" and variant=\"outlined\"", - "deprecationInfo": "Combine the .MuiButton-sizeLarge and .MuiButton-outlined classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedSizeMedium": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"medium\" and variant=\"outlined\"", - "deprecationInfo": "Combine the .MuiButton-sizeMedium and .MuiButton-outlined classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedSizeSmall": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"small\" and variant=\"outlined\"", - "deprecationInfo": "Combine the .MuiButton-sizeSmall and .MuiButton-outlined classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedSuccess": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"success\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorSuccess classes instead. See Migrating from deprecated APIs for more details." - }, - "outlinedWarning": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"outlined\" and color=\"warning\"", - "deprecationInfo": "Combine the .MuiButton-outlined and .MuiButton-colorWarning classes instead. See Migrating from deprecated APIs for more details." - }, - "root": { "description": "Styles applied to the root element." }, - "sizeLarge": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"large\"" - }, - "sizeMedium": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"medium\"" - }, - "sizeSmall": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"small\"" - }, - "startIcon": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the startIcon element", - "conditions": "supplied" - }, - "startIconLoadingStart": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the startIcon element", - "conditions": "loading={true} and loadingPosition=\"start\"" - }, - "text": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\"" - }, - "textError": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"error\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorError classes instead. See Migrating from deprecated APIs for more details." - }, - "textInfo": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"info\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorInfo classes instead. See Migrating from deprecated APIs for more details." - }, - "textInherit": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"inherit\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorInherit classes instead. See Migrating from deprecated APIs for more details." - }, - "textPrimary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"primary\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorPrimary classes instead. See Migrating from deprecated APIs for more details." - }, - "textSecondary": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"secondary\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorSecondary classes instead. See Migrating from deprecated APIs for more details." - }, - "textSizeLarge": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"large\" and variant=\"text\"", - "deprecationInfo": "Combine the .MuiButton-sizeLarge and .MuiButton-text classes instead. See Migrating from deprecated APIs for more details." - }, - "textSizeMedium": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"medium\" and variant=\"text\"", - "deprecationInfo": "Combine the .MuiButton-sizeMedium and .MuiButton-text classes instead. See Migrating from deprecated APIs for more details." - }, - "textSizeSmall": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "size=\"small\" and variant=\"text\"", - "deprecationInfo": "Combine the .MuiButton-sizeSmall and .MuiButton-text classes instead. See Migrating from deprecated APIs for more details." - }, - "textSuccess": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"success\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorSuccess classes instead. See Migrating from deprecated APIs for more details." - }, - "textWarning": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the root element", - "conditions": "variant=\"text\" and color=\"warning\"", - "deprecationInfo": "Combine the .MuiButton-text and .MuiButton-colorWarning classes instead. See Migrating from deprecated APIs for more details." - } - } -} diff --git a/packages/mui-lab/src/LoadingButton/LoadingButton.d.ts b/packages/mui-lab/src/LoadingButton/LoadingButton.d.ts index 193b192ddf029d..da2a708e023be3 100644 --- a/packages/mui-lab/src/LoadingButton/LoadingButton.d.ts +++ b/packages/mui-lab/src/LoadingButton/LoadingButton.d.ts @@ -1,80 +1,2 @@ -import { ExtendButton, ExtendButtonTypeMap, ButtonClasses } from '@mui/material/Button'; -import { OverrideProps } from '@mui/material/OverridableComponent'; -import { Theme } from '@mui/material/styles'; -import { SxProps } from '@mui/system'; - -export interface LoadingButtonOwnProps { - /** - * Override or extend the styles applied to the component. - */ - classes?: Partial & { - /** Styles applied to the root element. */ - root?: string; - /** Styles applied to the span element that wraps the children. */ - label?: string; - /** Styles applied to the root element if `loading={true}`. */ - loading?: string; - /** Styles applied to the loadingIndicator element. */ - loadingIndicator?: string; - /** Styles applied to the loadingIndicator element if `loadingPosition="center"`. */ - loadingIndicatorCenter?: string; - /** Styles applied to the loadingIndicator element if `loadingPosition="start"`. */ - loadingIndicatorStart?: string; - /** Styles applied to the loadingIndicator element if `loadingPosition="end"`. */ - loadingIndicatorEnd?: string; - /** Styles applied to the endIcon element if `loading={true}` and `loadingPosition="end"`. */ - endIconLoadingEnd?: string; - /** Styles applied to the startIcon element if `loading={true}` and `loadingPosition="start"`. */ - startIconLoadingStart?: string; - }; - /** - * If `true`, the loading indicator is shown and the button becomes disabled. - * @default false - */ - loading?: boolean; - /** - * Element placed before the children if the button is in loading state. - * The node should contain an element with `role="progressbar"` with an accessible name. - * By default we render a `CircularProgress` that is labelled by the button itself. - * @default - */ - loadingIndicator?: React.ReactNode; - /** - * The loading indicator can be positioned on the start, end, or the center of the button. - * @default 'center' - */ - loadingPosition?: 'start' | 'end' | 'center'; - /** - * The system prop that allows defining system overrides as well as additional CSS styles. - */ - sx?: SxProps; -} - -export type LoadingButtonTypeMap< - AdditionalProps = {}, - RootComponent extends React.ElementType = 'button', -> = ExtendButtonTypeMap<{ - props: AdditionalProps & LoadingButtonOwnProps; - defaultComponent: RootComponent; -}>; - -/** - * - * Demos: - * - * - [Button Group](https://mui.com/material-ui/react-button-group/) - * - [Button](https://mui.com/material-ui/react-button/) - * - * API: - * - * - [LoadingButton API](https://mui.com/material-ui/api/loading-button/) - * - inherits [Button API](https://mui.com/material-ui/api/button/) - */ -declare const LoadingButton: ExtendButton; - -export type LoadingButtonProps< - RootComponent extends React.ElementType = LoadingButtonTypeMap['defaultComponent'], - AdditionalProps = {}, -> = OverrideProps, RootComponent>; - -export default LoadingButton; +export { default } from '@mui/material/Button'; +export * from '@mui/material/Button'; diff --git a/packages/mui-lab/src/LoadingButton/LoadingButton.js b/packages/mui-lab/src/LoadingButton/LoadingButton.js index 12f0997a888d09..091f9c9f388846 100644 --- a/packages/mui-lab/src/LoadingButton/LoadingButton.js +++ b/packages/mui-lab/src/LoadingButton/LoadingButton.js @@ -1,350 +1,29 @@ 'use client'; import * as React from 'react'; -import PropTypes from 'prop-types'; -import { chainPropTypes } from '@mui/utils'; -import { - capitalize, - unstable_useId as useId, - unstable_memoTheme as memoTheme, -} from '@mui/material/utils'; -import { unstable_composeClasses as composeClasses } from '@mui/base'; -import { useDefaultProps } from '@mui/material/DefaultPropsProvider'; import Button from '@mui/material/Button'; -import { ButtonGroupContext } from '@mui/material/ButtonGroup'; -import CircularProgress from '@mui/material/CircularProgress'; -import resolveProps from '@mui/utils/resolveProps'; -import { styled } from '../zero-styled'; -import loadingButtonClasses, { getLoadingButtonUtilityClass } from './loadingButtonClasses'; -const useUtilityClasses = (ownerState) => { - const { loading, loadingPosition, classes } = ownerState; - - const slots = { - root: ['root', loading && 'loading'], - label: ['label'], - startIcon: [loading && `startIconLoading${capitalize(loadingPosition)}`], - endIcon: [loading && `endIconLoading${capitalize(loadingPosition)}`], - loadingIndicator: [ - 'loadingIndicator', - loading && `loadingIndicator${capitalize(loadingPosition)}`, - ], - }; - - const composedClasses = composeClasses(slots, getLoadingButtonUtilityClass, classes); - - return { - ...classes, // forward the outlined, color, etc. classes to Button - ...composedClasses, - }; +let warnedOnce = false; + +const warn = () => { + if (!warnedOnce) { + console.warn( + [ + 'MUI: The LoadingButton component functionality is now part of the Button component from Material UI.', + '', + "You should use `import Button from '@mui/material/Button'`", + "or `import { Button } from '@mui/material'`", + ].join('\n'), + ); + + warnedOnce = true; + } }; -// TODO use `import rootShouldForwardProp from '../styles/rootShouldForwardProp';` once move to core -const rootShouldForwardProp = (prop) => - prop !== 'ownerState' && prop !== 'theme' && prop !== 'sx' && prop !== 'as' && prop !== 'classes'; -const LoadingButtonRoot = styled(Button, { - shouldForwardProp: (prop) => rootShouldForwardProp(prop) || prop === 'classes', - name: 'MuiLoadingButton', - slot: 'Root', - overridesResolver: (props, styles) => { - return [ - styles.root, - styles.startIconLoadingStart && { - [`& .${loadingButtonClasses.startIconLoadingStart}`]: styles.startIconLoadingStart, - }, - styles.endIconLoadingEnd && { - [`& .${loadingButtonClasses.endIconLoadingEnd}`]: styles.endIconLoadingEnd, - }, - ]; - }, -})( - memoTheme(({ theme }) => ({ - display: 'inline-flex', - [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: - { - transition: theme.transitions.create(['opacity'], { - duration: theme.transitions.duration.short, - }), - opacity: 0, - }, - variants: [ - { - props: { - loadingPosition: 'center', - }, - style: { - transition: theme.transitions.create(['background-color', 'box-shadow', 'border-color'], { - duration: theme.transitions.duration.short, - }), - [`&.${loadingButtonClasses.loading}`]: { - color: 'transparent', - }, - }, - }, - { - props: ({ ownerState }) => ownerState.loadingPosition === 'start' && ownerState.fullWidth, - style: { - [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: - { - transition: theme.transitions.create(['opacity'], { - duration: theme.transitions.duration.short, - }), - opacity: 0, - marginRight: -8, - }, - }, - }, - { - props: ({ ownerState }) => ownerState.loadingPosition === 'end' && ownerState.fullWidth, - style: { - [`& .${loadingButtonClasses.startIconLoadingStart}, & .${loadingButtonClasses.endIconLoadingEnd}`]: - { - transition: theme.transitions.create(['opacity'], { - duration: theme.transitions.duration.short, - }), - opacity: 0, - marginLeft: -8, - }, - }, - }, - ], - })), -); - -const LoadingButtonLoadingIndicator = styled('span', { - name: 'MuiLoadingButton', - slot: 'LoadingIndicator', - overridesResolver: (props, styles) => { - const { ownerState } = props; - return [ - styles.loadingIndicator, - styles[`loadingIndicator${capitalize(ownerState.loadingPosition)}`], - ]; - }, -})( - memoTheme(({ theme }) => ({ - position: 'absolute', - visibility: 'visible', - display: 'flex', - variants: [ - { - props: { - loadingPosition: 'start', - size: 'small', - }, - style: { - left: 10, - }, - }, - { - props: ({ loadingPosition, ownerState }) => - loadingPosition === 'start' && ownerState.size !== 'small', - style: { - left: 14, - }, - }, - { - props: { - variant: 'text', - loadingPosition: 'start', - }, - style: { - left: 6, - }, - }, - { - props: { - loadingPosition: 'center', - }, - style: { - left: '50%', - transform: 'translate(-50%)', - color: (theme.vars || theme).palette.action.disabled, - }, - }, - { - props: { - loadingPosition: 'end', - size: 'small', - }, - style: { - right: 10, - }, - }, - { - props: ({ loadingPosition, ownerState }) => - loadingPosition === 'end' && ownerState.size !== 'small', - style: { - right: 14, - }, - }, - { - props: { - variant: 'text', - loadingPosition: 'end', - }, - style: { - right: 6, - }, - }, - { - props: ({ ownerState }) => ownerState.loadingPosition === 'start' && ownerState.fullWidth, - style: { - position: 'relative', - left: -10, - }, - }, - { - props: ({ ownerState }) => ownerState.loadingPosition === 'end' && ownerState.fullWidth, - style: { - position: 'relative', - right: -10, - }, - }, - ], - })), -); +/** + * @ignore - do not document. + */ +export default React.forwardRef(function DeprecatedLoadingButton(props, ref) { + warn(); -const LoadingButtonLabel = styled('span', { - name: 'MuiLoadingButton', - slot: 'Label', - overridesResolver: (props, styles) => { - return [styles.label]; - }, -})({ - display: 'inherit', - alignItems: 'inherit', - justifyContent: 'inherit', + return ); }; + +function ClassesTest() { + return ( + + ); +} diff --git a/packages/mui-material/src/Button/Button.test.js b/packages/mui-material/src/Button/Button.test.js index 5d57fa23d002a0..7d3c1033a2f376 100644 --- a/packages/mui-material/src/Button/Button.test.js +++ b/packages/mui-material/src/Button/Button.test.js @@ -1,6 +1,6 @@ import * as React from 'react'; import { expect } from 'chai'; -import { createRenderer, screen, simulateKeyboardDevice } from '@mui/internal-test-utils'; +import { createRenderer, screen, simulateKeyboardDevice, within } from '@mui/internal-test-utils'; import { ClassNames } from '@emotion/react'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import Button, { buttonClasses as classes } from '@mui/material/Button'; @@ -753,4 +753,46 @@ describe('); + + const button = screen.getByRole('button'); + const progressbar = within(button).getByRole('progressbar'); + expect(progressbar).toHaveAccessibleName('Submit'); + }); + }); + + describe('prop: loadingIndicator', () => { + it('is not rendered by default', () => { + render(); + + expect(screen.getByRole('button')).to.have.text('Test'); + }); + + it('is rendered before the children when `loading`', () => { + render( + , + ); + + expect(screen.getByRole('button')).to.have.text('loading…Test'); + }); + }); }); diff --git a/packages/mui-material/src/Button/buttonClasses.ts b/packages/mui-material/src/Button/buttonClasses.ts index e6abe7643e4736..3dd6b4ea750fb1 100644 --- a/packages/mui-material/src/Button/buttonClasses.ts +++ b/packages/mui-material/src/Button/buttonClasses.ts @@ -176,6 +176,20 @@ export interface ButtonClasses { colorInfo: string; /** Styles applied to the root element if `color="warning"`. */ colorWarning: string; + /** Styles applied to the root element if `loading={true}`. */ + loading: string; + /** Styles applied to the loadingIndicator element. */ + loadingIndicator: string; + /** Styles applied to the loadingIndicator element if `loadingPosition="center"`. */ + loadingIndicatorCenter: string; + /** Styles applied to the loadingIndicator element if `loadingPosition="start"`. */ + loadingIndicatorStart: string; + /** Styles applied to the loadingIndicator element if `loadingPosition="end"`. */ + loadingIndicatorEnd: string; + /** Styles applied to the endIcon element if `loading={true}` and `loadingPosition="end"`. */ + endIconLoadingEnd: string; + /** Styles applied to the startIcon element if `loading={true}` and `loadingPosition="start"`. */ + startIconLoadingStart: string; } export type ButtonClassKey = keyof ButtonClasses; @@ -239,6 +253,13 @@ const buttonClasses: ButtonClasses = generateUtilityClasses('MuiButton', [ 'iconSizeSmall', 'iconSizeMedium', 'iconSizeLarge', + 'loading', + 'loadingIndicator', + 'loadingIndicatorCenter', + 'loadingIndicatorStart', + 'loadingIndicatorEnd', + 'endIconLoadingEnd', + 'startIconLoadingStart', ]); export default buttonClasses; diff --git a/packages/mui-material/src/IconButton/IconButton.d.ts b/packages/mui-material/src/IconButton/IconButton.d.ts index 108d72d09ac0c3..775df23cc68f8c 100644 --- a/packages/mui-material/src/IconButton/IconButton.d.ts +++ b/packages/mui-material/src/IconButton/IconButton.d.ts @@ -47,6 +47,18 @@ export interface IconButtonOwnProps { * @default false */ edge?: 'start' | 'end' | false; + /** + * If `true`, the loading indicator is visible and the button is disabled. + * @default false + */ + loading?: boolean; + /** + * Element placed before the children if the button is in loading state. + * The node should contain an element with `role="progressbar"` with an accessible name. + * By default, it renders a `CircularProgress` that is labeled by the button itself. + * @default + */ + loadingIndicator?: React.ReactNode; /** * The size of the component. * `small` is equivalent to the dense button styling. diff --git a/packages/mui-material/src/IconButton/IconButton.js b/packages/mui-material/src/IconButton/IconButton.js index 780a3ff72d3d19..ac2776275f0aa1 100644 --- a/packages/mui-material/src/IconButton/IconButton.js +++ b/packages/mui-material/src/IconButton/IconButton.js @@ -4,26 +4,30 @@ import PropTypes from 'prop-types'; import clsx from 'clsx'; import chainPropTypes from '@mui/utils/chainPropTypes'; import composeClasses from '@mui/utils/composeClasses'; +import { unstable_useId as useId } from '@mui/material/utils'; import { alpha } from '@mui/system/colorManipulator'; import { styled } from '../zero-styled'; import memoTheme from '../utils/memoTheme'; import createSimplePaletteValueFilter from '../utils/createSimplePaletteValueFilter'; import { useDefaultProps } from '../DefaultPropsProvider'; import ButtonBase from '../ButtonBase'; +import CircularProgress from '../CircularProgress'; import capitalize from '../utils/capitalize'; import iconButtonClasses, { getIconButtonUtilityClass } from './iconButtonClasses'; const useUtilityClasses = (ownerState) => { - const { classes, disabled, color, edge, size } = ownerState; + const { classes, disabled, color, edge, size, loading } = ownerState; const slots = { root: [ 'root', + loading && 'loading', disabled && 'disabled', color !== 'default' && `color${capitalize(color)}`, edge && `edge${capitalize(edge)}`, `size${capitalize(size)}`, ], + loadingIndicator: ['loadingIndicator'], }; return composeClasses(slots, getIconButtonUtilityClass, classes); @@ -37,6 +41,7 @@ const IconButtonRoot = styled(ButtonBase, { return [ styles.root, + ownerState.loading && styles.loading, ownerState.color !== 'default' && styles[`color${capitalize(ownerState.color)}`], ownerState.edge && styles[`edge${capitalize(ownerState.edge)}`], styles[`size${capitalize(ownerState.size)}`], @@ -140,9 +145,27 @@ const IconButtonRoot = styled(ButtonBase, { backgroundColor: 'transparent', color: (theme.vars || theme).palette.action.disabled, }, + [`&.${iconButtonClasses.loading}`]: { + color: 'transparent', + }, })), ); +const IconButtonLoadingIndicator = styled('span', { + name: 'MuiIconButton', + slot: 'LoadingIndicator', + overridesResolver: (props, styles) => styles.loadingIndicator, +})(({ theme }) => ({ + display: 'none', + position: 'absolute', + visibility: 'visible', + top: '50%', + left: '50%', + transform: 'translate(-50%, -50%)', + color: (theme.vars || theme).palette.action.disabled, + variants: [{ props: { loading: true }, style: { display: 'flex' } }], +})); + /** * Refer to the [Icons](/material-ui/icons/) section of the documentation * regarding the available icon options. @@ -157,15 +180,25 @@ const IconButton = React.forwardRef(function IconButton(inProps, ref) { disabled = false, disableFocusRipple = false, size = 'medium', + id: idProp, + loading = false, + loadingIndicator: loadingIndicatorProp, ...other } = props; + const id = useId(idProp); + const loadingIndicator = loadingIndicatorProp ?? ( + + ); + const ownerState = { ...props, edge, color, disabled, disableFocusRipple, + loading, + loadingIndicator, size, }; @@ -173,14 +206,18 @@ const IconButton = React.forwardRef(function IconButton(inProps, ref) { return ( + + {loading && loadingIndicator} + {children} ); @@ -264,6 +301,22 @@ IconButton.propTypes /* remove-proptypes */ = { * @default false */ edge: PropTypes.oneOf(['end', 'start', false]), + /** + * @ignore + */ + id: PropTypes.string, + /** + * If `true`, the loading indicator is visible and the button is disabled. + * @default false + */ + loading: PropTypes.bool, + /** + * Element placed before the children if the button is in loading state. + * The node should contain an element with `role="progressbar"` with an accessible name. + * By default, it renders a `CircularProgress` that is labeled by the button itself. + * @default + */ + loadingIndicator: PropTypes.node, /** * The size of the component. * `small` is equivalent to the dense button styling. diff --git a/packages/mui-material/src/IconButton/IconButton.test.js b/packages/mui-material/src/IconButton/IconButton.test.js index 827d2c91fb560d..e72515a6b0b309 100644 --- a/packages/mui-material/src/IconButton/IconButton.test.js +++ b/packages/mui-material/src/IconButton/IconButton.test.js @@ -1,7 +1,7 @@ import * as React from 'react'; import { expect } from 'chai'; import PropTypes from 'prop-types'; -import { createRenderer, reactMajor } from '@mui/internal-test-utils'; +import { createRenderer, reactMajor, screen, within } from '@mui/internal-test-utils'; import capitalize from '@mui/utils/capitalize'; import { ThemeProvider, createTheme } from '@mui/material/styles'; import IconButton, { iconButtonClasses as classes } from '@mui/material/IconButton'; @@ -161,4 +161,46 @@ describe('', () => { await ripple.startTouch(getByRole('button')); expect(container.querySelector('.touch-ripple')).to.equal(null); }); + + describe('prop: loading', () => { + it('disables the button', () => { + render(); + + const button = screen.getByRole('button'); + expect(button).to.have.property('tabIndex', -1); + expect(button).to.have.property('disabled', true); + }); + + it('cannot be enabled while `loading`', () => { + render(); + + expect(screen.getByRole('button')).to.have.property('disabled', true); + }); + + it('renders a progressbar that is labelled by the button', () => { + render(Submit); + + const button = screen.getByRole('button'); + const progressbar = within(button).getByRole('progressbar'); + expect(progressbar).toHaveAccessibleName('Submit'); + }); + }); + + describe('prop: loadingIndicator', () => { + it('is not rendered by default', () => { + render(Test); + + expect(screen.getByRole('button')).to.have.text('Test'); + }); + + it('is rendered before the children when `loading`', () => { + render( + + Test + , + ); + + expect(screen.getByRole('button')).to.have.text('loading…Test'); + }); + }); }); diff --git a/packages/mui-material/src/IconButton/iconButtonClasses.ts b/packages/mui-material/src/IconButton/iconButtonClasses.ts index 72eb0e109c497f..b65ac3b0d85264 100644 --- a/packages/mui-material/src/IconButton/iconButtonClasses.ts +++ b/packages/mui-material/src/IconButton/iconButtonClasses.ts @@ -30,6 +30,10 @@ export interface IconButtonClasses { sizeMedium: string; /** Styles applied to the root element if `size="large"`. */ sizeLarge: string; + /** Styles applied to the root element if `loading={true}`. */ + loading: string; + /** Styles applied to the loadingIndicator element. */ + loadingIndicator: string; } export type IconButtonClassKey = keyof IconButtonClasses; @@ -53,6 +57,8 @@ const iconButtonClasses: IconButtonClasses = generateUtilityClasses('MuiIconButt 'sizeSmall', 'sizeMedium', 'sizeLarge', + 'loading', + 'loadingIndicator', ]); export default iconButtonClasses; diff --git a/test/regressions/fixtures/Button/FullWidthLoadingButtons.js b/test/regressions/fixtures/Button/FullWidthLoadingButtons.js index e9f544630ef187..038f027e6b4b6a 100644 --- a/test/regressions/fixtures/Button/FullWidthLoadingButtons.js +++ b/test/regressions/fixtures/Button/FullWidthLoadingButtons.js @@ -1,5 +1,5 @@ import * as React from 'react'; -import LoadingButton from '@mui/lab/LoadingButton'; +import Button from '@mui/material/Button'; import FormControlLabel from '@mui/material/FormControlLabel'; import Switch from '@mui/material/Switch'; import SaveIcon from '@mui/icons-material/Save'; @@ -27,10 +27,10 @@ export default function FullWidthLoadingButtonsTransition() { } label="Loading" /> - + ); } From f317e696f04eda6b27f30734c16d32223f7f7c69 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Tue, 3 Dec 2024 14:25:18 +0700 Subject: [PATCH 2/9] add enableLoadingWrapper --- .../buttons/LoadingButtonsTransition.js | 15 +++++++++++- .../buttons/LoadingButtonsTransition.tsx | 15 +++++++++++- .../material/components/buttons/buttons.md | 4 ++++ docs/pages/material-ui/api/button.json | 7 ++++++ docs/translations/api-docs/button/button.json | 7 ++++++ packages/mui-material/src/Button/Button.d.ts | 6 +++++ packages/mui-material/src/Button/Button.js | 19 +++++++++++++-- .../mui-material/src/Button/Button.spec.tsx | 14 +++++++++++ .../mui-material/src/Button/Button.test.js | 24 ++++++++++++++++++- .../mui-material/src/Button/buttonClasses.ts | 3 +++ 10 files changed, 109 insertions(+), 5 deletions(-) diff --git a/docs/data/material/components/buttons/LoadingButtonsTransition.js b/docs/data/material/components/buttons/LoadingButtonsTransition.js index 2278b2684fe7b5..80bcde0475c2b3 100644 --- a/docs/data/material/components/buttons/LoadingButtonsTransition.js +++ b/docs/data/material/components/buttons/LoadingButtonsTransition.js @@ -30,6 +30,7 @@ export default function LoadingButtonsTransition() { button': { m: 1 } }}> - button': { m: 1 } }}> - + + + + + + ); diff --git a/packages/mui-material/src/Button/Button.test.js b/packages/mui-material/src/Button/Button.test.js index 7d3c1033a2f376..c15d900fb8be2a 100644 --- a/packages/mui-material/src/Button/Button.test.js +++ b/packages/mui-material/src/Button/Button.test.js @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { createRenderer, screen, simulateKeyboardDevice, within } from '@mui/internal-test-utils'; import { ClassNames } from '@emotion/react'; import { ThemeProvider, createTheme } from '@mui/material/styles'; -import Button, { buttonClasses as classes } from '@mui/material/Button'; +import Button, { buttonClasses, buttonClasses as classes } from '@mui/material/Button'; import ButtonBase, { touchRippleClasses } from '@mui/material/ButtonBase'; import describeConformance from '../../test/describeConformance'; import * as ripple from '../../test/ripple'; @@ -795,4 +795,26 @@ describe('); + + expect(container.querySelector(`.${buttonClasses.loadingWrapper}`)).to.equal(null); + }); + + it('is always rendered before the children', () => { + const { container, rerender } = render(); + + expect(container.querySelector(`.${buttonClasses.loadingWrapper}`)).not.to.equal(null); + + rerender( + , + ); + + expect(container.querySelector(`.${buttonClasses.loadingWrapper}`)).not.to.equal(null); + }); + }); }); diff --git a/packages/mui-material/src/Button/buttonClasses.ts b/packages/mui-material/src/Button/buttonClasses.ts index 3dd6b4ea750fb1..0fbb2484338f0f 100644 --- a/packages/mui-material/src/Button/buttonClasses.ts +++ b/packages/mui-material/src/Button/buttonClasses.ts @@ -178,6 +178,8 @@ export interface ButtonClasses { colorWarning: string; /** Styles applied to the root element if `loading={true}`. */ loading: string; + /** Styles applied to the loadingWrapper element. */ + loadingWrapper: string; /** Styles applied to the loadingIndicator element. */ loadingIndicator: string; /** Styles applied to the loadingIndicator element if `loadingPosition="center"`. */ @@ -254,6 +256,7 @@ const buttonClasses: ButtonClasses = generateUtilityClasses('MuiButton', [ 'iconSizeMedium', 'iconSizeLarge', 'loading', + 'loadingWrapper', 'loadingIndicator', 'loadingIndicatorCenter', 'loadingIndicatorStart', From baf6709f4096290fba3ef5a5506d5015351bcdb9 Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 6 Dec 2024 09:46:21 +0700 Subject: [PATCH 3/9] Revert "add enableLoadingWrapper" This reverts commit f317e696f04eda6b27f30734c16d32223f7f7c69. --- .../buttons/LoadingButtonsTransition.js | 15 +----------- .../buttons/LoadingButtonsTransition.tsx | 15 +----------- .../material/components/buttons/buttons.md | 4 ---- docs/pages/material-ui/api/button.json | 7 ------ docs/translations/api-docs/button/button.json | 7 ------ packages/mui-material/src/Button/Button.d.ts | 6 ----- packages/mui-material/src/Button/Button.js | 19 ++------------- .../mui-material/src/Button/Button.spec.tsx | 14 ----------- .../mui-material/src/Button/Button.test.js | 24 +------------------ .../mui-material/src/Button/buttonClasses.ts | 3 --- 10 files changed, 5 insertions(+), 109 deletions(-) diff --git a/docs/data/material/components/buttons/LoadingButtonsTransition.js b/docs/data/material/components/buttons/LoadingButtonsTransition.js index 80bcde0475c2b3..2278b2684fe7b5 100644 --- a/docs/data/material/components/buttons/LoadingButtonsTransition.js +++ b/docs/data/material/components/buttons/LoadingButtonsTransition.js @@ -30,7 +30,6 @@ export default function LoadingButtonsTransition() { button': { m: 1 } }}> - button': { m: 1 } }}> - - - - - - - ); diff --git a/packages/mui-material/src/Button/Button.test.js b/packages/mui-material/src/Button/Button.test.js index c15d900fb8be2a..7d3c1033a2f376 100644 --- a/packages/mui-material/src/Button/Button.test.js +++ b/packages/mui-material/src/Button/Button.test.js @@ -3,7 +3,7 @@ import { expect } from 'chai'; import { createRenderer, screen, simulateKeyboardDevice, within } from '@mui/internal-test-utils'; import { ClassNames } from '@emotion/react'; import { ThemeProvider, createTheme } from '@mui/material/styles'; -import Button, { buttonClasses, buttonClasses as classes } from '@mui/material/Button'; +import Button, { buttonClasses as classes } from '@mui/material/Button'; import ButtonBase, { touchRippleClasses } from '@mui/material/ButtonBase'; import describeConformance from '../../test/describeConformance'; import * as ripple from '../../test/ripple'; @@ -795,26 +795,4 @@ describe('); - - expect(container.querySelector(`.${buttonClasses.loadingWrapper}`)).to.equal(null); - }); - - it('is always rendered before the children', () => { - const { container, rerender } = render(); - - expect(container.querySelector(`.${buttonClasses.loadingWrapper}`)).not.to.equal(null); - - rerender( - , - ); - - expect(container.querySelector(`.${buttonClasses.loadingWrapper}`)).not.to.equal(null); - }); - }); }); diff --git a/packages/mui-material/src/Button/buttonClasses.ts b/packages/mui-material/src/Button/buttonClasses.ts index 0fbb2484338f0f..3dd6b4ea750fb1 100644 --- a/packages/mui-material/src/Button/buttonClasses.ts +++ b/packages/mui-material/src/Button/buttonClasses.ts @@ -178,8 +178,6 @@ export interface ButtonClasses { colorWarning: string; /** Styles applied to the root element if `loading={true}`. */ loading: string; - /** Styles applied to the loadingWrapper element. */ - loadingWrapper: string; /** Styles applied to the loadingIndicator element. */ loadingIndicator: string; /** Styles applied to the loadingIndicator element if `loadingPosition="center"`. */ @@ -256,7 +254,6 @@ const buttonClasses: ButtonClasses = generateUtilityClasses('MuiButton', [ 'iconSizeMedium', 'iconSizeLarge', 'loading', - 'loadingWrapper', 'loadingIndicator', 'loadingIndicatorCenter', 'loadingIndicatorStart', From ce1206a4ed6ddd0e0540b7e192c9851814f8988c Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Fri, 6 Dec 2024 10:01:01 +0700 Subject: [PATCH 4/9] set loading default to null --- docs/pages/material-ui/api/button.json | 8 ++++++- docs/translations/api-docs/button/button.json | 6 ++++- packages/mui-material/src/Button/Button.d.ts | 5 ++-- packages/mui-material/src/Button/Button.js | 23 +++++++++++-------- .../mui-material/src/Button/Button.test.js | 16 +++++++++++++ .../mui-material/src/Button/buttonClasses.ts | 3 +++ 6 files changed, 48 insertions(+), 13 deletions(-) diff --git a/docs/pages/material-ui/api/button.json b/docs/pages/material-ui/api/button.json index 996ab60f6e6a63..51843e8735fca9 100644 --- a/docs/pages/material-ui/api/button.json +++ b/docs/pages/material-ui/api/button.json @@ -17,7 +17,7 @@ "endIcon": { "type": { "name": "node" } }, "fullWidth": { "type": { "name": "bool" }, "default": "false" }, "href": { "type": { "name": "string" } }, - "loading": { "type": { "name": "bool" }, "default": "false" }, + "loading": { "type": { "name": "bool" }, "default": "null" }, "loadingIndicator": { "type": { "name": "node" }, "default": "" @@ -269,6 +269,12 @@ "description": "Styles applied to the loadingIndicator element if `loadingPosition=\"start\"`.", "isGlobal": false }, + { + "key": "loadingWrapper", + "className": "MuiButton-loadingWrapper", + "description": "Styles applied to the loadingWrapper element.", + "isGlobal": false + }, { "key": "outlined", "className": "MuiButton-outlined", diff --git a/docs/translations/api-docs/button/button.json b/docs/translations/api-docs/button/button.json index 14a7ad2f58db52..bc57f9537a060f 100644 --- a/docs/translations/api-docs/button/button.json +++ b/docs/translations/api-docs/button/button.json @@ -25,7 +25,7 @@ "description": "The URL to link to when the button is clicked. If defined, an a element will be used as the root node." }, "loading": { - "description": "If true, the loading indicator is visible and the button is disabled." + "description": "If true, the loading indicator is visible and the button is disabled. If true \\| false, the loading wrapper is always rendered before the children to prevent Google Translation Crash." }, "loadingIndicator": { "description": "Element placed before the children if the button is in loading state. The node should contain an element with role="progressbar" with an accessible name. By default, it renders a CircularProgress that is labeled by the button itself." @@ -216,6 +216,10 @@ "nodeName": "the loadingIndicator element", "conditions": "loadingPosition=\"start\"" }, + "loadingWrapper": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the loadingWrapper element" + }, "outlined": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element", diff --git a/packages/mui-material/src/Button/Button.d.ts b/packages/mui-material/src/Button/Button.d.ts index 03df55d186736f..0e32a0b6ab459e 100644 --- a/packages/mui-material/src/Button/Button.d.ts +++ b/packages/mui-material/src/Button/Button.d.ts @@ -62,9 +62,10 @@ export interface ButtonOwnProps { href?: string; /** * If `true`, the loading indicator is visible and the button is disabled. - * @default false + * If `true | false`, the loading wrapper is always rendered before the children to prevent [Google Translation Crash](https://github.com/mui/material-ui/issues/27853). + * @default null */ - loading?: boolean; + loading?: boolean | null; /** * Element placed before the children if the button is in loading state. * The node should contain an element with `role="progressbar"` with an accessible name. diff --git a/packages/mui-material/src/Button/Button.js b/packages/mui-material/src/Button/Button.js index d418248451036d..6a989793d476c3 100644 --- a/packages/mui-material/src/Button/Button.js +++ b/packages/mui-material/src/Button/Button.js @@ -50,6 +50,7 @@ const useUtilityClasses = (ownerState) => { 'loadingIndicator', loading && `loadingIndicator${capitalize(loadingPosition)}`, ], + loadingWrapper: ['loadingWrapper'], }; const composedClasses = composeClasses(slots, getButtonUtilityClass, classes); @@ -524,7 +525,7 @@ const Button = React.forwardRef(function Button(inProps, ref) { focusVisibleClassName, fullWidth = false, id: idProp, - loading = false, + loading = null, loadingIndicator: loadingIndicatorProp, loadingPosition = 'center', size = 'medium', @@ -569,12 +570,6 @@ const Button = React.forwardRef(function Button(inProps, ref) { ); - const loader = ( - - {loading && loadingIndicator} - - ); - const positionClassName = buttonGroupButtonContextPositionClassName || ''; return ( @@ -592,7 +587,16 @@ const Button = React.forwardRef(function Button(inProps, ref) { classes={classes} > {startIcon} - {loader} + {typeof loading === 'boolean' && ( + // use plain HTML span to minimize the runtime overhead + + {loading && ( + + {loadingIndicator} + + )} + + )} {children} {endIcon} @@ -678,7 +682,8 @@ Button.propTypes /* remove-proptypes */ = { id: PropTypes.string, /** * If `true`, the loading indicator is visible and the button is disabled. - * @default false + * If `true | false`, the loading wrapper is always rendered before the children to prevent [Google Translation Crash](https://github.com/mui/material-ui/issues/27853). + * @default null */ loading: PropTypes.bool, /** diff --git a/packages/mui-material/src/Button/Button.test.js b/packages/mui-material/src/Button/Button.test.js index 7d3c1033a2f376..80b9dc94b01b54 100644 --- a/packages/mui-material/src/Button/Button.test.js +++ b/packages/mui-material/src/Button/Button.test.js @@ -755,6 +755,22 @@ describe('); + + expect(container.querySelector(`.${classes.loadingWrapper}`)).to.equal(null); + }); + + it('should have a loading wrapper when loading is boolean', () => { + const { container, rerender } = render(); + + expect(container.querySelector(`.${classes.loadingWrapper}`)).not.to.equal(null); + + rerender(); + + expect(container.querySelector(`.${classes.loadingWrapper}`)).not.to.equal(null); + }); + it('disables the button', () => { render( + + + + + ); } diff --git a/docs/data/material/components/buttons/LoadingButtons.tsx b/docs/data/material/components/buttons/LoadingButtons.tsx index 09d568b124c92d..33bdada801bbb2 100644 --- a/docs/data/material/components/buttons/LoadingButtons.tsx +++ b/docs/data/material/components/buttons/LoadingButtons.tsx @@ -40,6 +40,22 @@ export default function LoadingButtons() { > Full width + + + + + ); } diff --git a/packages/mui-material/src/Button/Button.js b/packages/mui-material/src/Button/Button.js index eb0a8d3afb6ae7..682af07ce66b2a 100644 --- a/packages/mui-material/src/Button/Button.js +++ b/packages/mui-material/src/Button/Button.js @@ -497,6 +497,16 @@ const ButtonLoadingIndicator = styled('span', { ], })); +const ButtonLoadingIconPlaceholder = styled('span', { + name: 'MuiButton', + slot: 'LoadingIconPlaceholder', + overridesResolver: (props, styles) => styles.loadingIconPlaceholder, +})({ + display: 'inline-block', + width: '1em', + height: '1em', +}); + const Button = React.forwardRef(function Button(inProps, ref) { // props priority: `inProps` > `contextProps` > `themeDefaultProps` const contextProps = React.useContext(ButtonGroupContext); @@ -548,15 +558,25 @@ const Button = React.forwardRef(function Button(inProps, ref) { const classes = useUtilityClasses(ownerState); - const startIcon = startIconProp && ( + const startIcon = (startIconProp || (loading && loadingPosition === 'start')) && ( - {startIconProp} + {startIconProp || ( + + )} ); - const endIcon = endIconProp && ( + const endIcon = (endIconProp || (loading && loadingPosition === 'end')) && ( - {endIconProp} + {endIconProp || ( + + )} ); diff --git a/packages/mui-material/src/Button/buttonClasses.ts b/packages/mui-material/src/Button/buttonClasses.ts index 27c6279247dd1c..7a15757d65e071 100644 --- a/packages/mui-material/src/Button/buttonClasses.ts +++ b/packages/mui-material/src/Button/buttonClasses.ts @@ -180,6 +180,8 @@ export interface ButtonClasses { loading: string; /** Styles applied to the loadingWrapper element. */ loadingWrapper: string; + /** Styles applied to the loadingIconPlaceholder element. */ + loadingIconPlaceholder: string; /** Styles applied to the loadingIndicator element. */ loadingIndicator: string; /** Styles applied to the loadingIndicator element if `loadingPosition="center"`. */ @@ -253,6 +255,7 @@ const buttonClasses: ButtonClasses = generateUtilityClasses('MuiButton', [ 'iconSizeLarge', 'loading', 'loadingWrapper', + 'loadingIconPlaceholder', 'loadingIndicator', 'loadingIndicatorCenter', 'loadingIndicatorStart', From 978a40e26935ac48200b5b3371481a29891f6afa Mon Sep 17 00:00:00 2001 From: siriwatknp Date: Wed, 11 Dec 2024 10:48:42 +0700 Subject: [PATCH 9/9] run docs:api --- docs/pages/material-ui/api/button.json | 18 ++++++------------ docs/translations/api-docs/button/button.json | 14 ++++---------- 2 files changed, 10 insertions(+), 22 deletions(-) diff --git a/docs/pages/material-ui/api/button.json b/docs/pages/material-ui/api/button.json index 51843e8735fca9..2b94b2de4c3152 100644 --- a/docs/pages/material-ui/api/button.json +++ b/docs/pages/material-ui/api/button.json @@ -194,12 +194,6 @@ "description": "Styles applied to the endIcon element if supplied.", "isGlobal": false }, - { - "key": "endIconLoadingEnd", - "className": "MuiButton-endIconLoadingEnd", - "description": "Styles applied to the endIcon element if `loading={true}` and `loadingPosition=\"end\"`.", - "isGlobal": false - }, { "key": "focusVisible", "className": "Mui-focusVisible", @@ -245,6 +239,12 @@ "description": "Styles applied to the root element if `loading={true}`.", "isGlobal": false }, + { + "key": "loadingIconPlaceholder", + "className": "MuiButton-loadingIconPlaceholder", + "description": "Styles applied to the loadingIconPlaceholder element.", + "isGlobal": false + }, { "key": "loadingIndicator", "className": "MuiButton-loadingIndicator", @@ -381,12 +381,6 @@ "description": "Styles applied to the startIcon element if supplied.", "isGlobal": false }, - { - "key": "startIconLoadingStart", - "className": "MuiButton-startIconLoadingStart", - "description": "Styles applied to the startIcon element if `loading={true}` and `loadingPosition=\"start\"`.", - "isGlobal": false - }, { "key": "text", "className": "MuiButton-text", diff --git a/docs/translations/api-docs/button/button.json b/docs/translations/api-docs/button/button.json index bc57f9537a060f..bfe40130293341 100644 --- a/docs/translations/api-docs/button/button.json +++ b/docs/translations/api-docs/button/button.json @@ -158,11 +158,6 @@ "nodeName": "the endIcon element", "conditions": "supplied" }, - "endIconLoadingEnd": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the endIcon element", - "conditions": "loading={true} and loadingPosition=\"end\"" - }, "focusVisible": { "description": "State class applied to {{nodeName}} if {{conditions}}.", "nodeName": "the ButtonBase root element", @@ -197,6 +192,10 @@ "nodeName": "the root element", "conditions": "loading={true}" }, + "loadingIconPlaceholder": { + "description": "Styles applied to {{nodeName}}.", + "nodeName": "the loadingIconPlaceholder element" + }, "loadingIndicator": { "description": "Styles applied to {{nodeName}}.", "nodeName": "the loadingIndicator element" @@ -306,11 +305,6 @@ "nodeName": "the startIcon element", "conditions": "supplied" }, - "startIconLoadingStart": { - "description": "Styles applied to {{nodeName}} if {{conditions}}.", - "nodeName": "the startIcon element", - "conditions": "loading={true} and loadingPosition=\"start\"" - }, "text": { "description": "Styles applied to {{nodeName}} if {{conditions}}.", "nodeName": "the root element",