Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

[material-ui][Button] Add loading feature to Button #42987

Merged
merged 68 commits into from
Nov 14, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
68 commits
Select commit Hold shift + click to select a range
7f2f33a
Loading props added to button
Jul 18, 2024
aa09045
ran pnpm deduplicate
Jul 18, 2024
7369f21
Imports reformated and eslint failure fixed
Jul 18, 2024
4459f08
missing files added
Jul 18, 2024
451a3a1
More ci/circle issues resolved
Jul 18, 2024
4ddca3f
Review suggestions implemented
Aug 22, 2024
a9cac91
Docs updated and loading button depreciated
Aug 22, 2024
f045e16
Updates to API, Button, and LoadingButton
Aug 23, 2024
e77cc6f
Resolving dependency issues
Aug 23, 2024
6379283
Resolving dependency issues again
Aug 23, 2024
6402d77
Deduplicating pnpm-lock file
Aug 23, 2024
56449f4
Restoring old pnpm-lock file
Aug 23, 2024
5186aa9
Resolving dependency issues
Gavin-10 Aug 25, 2024
293ecdc
Manually changed pnpm-lock.yaml file
Gavin-10 Aug 25, 2024
a3f279c
Button Group Docs Updated
Gavin-10 Aug 28, 2024
5b429c6
Child alignment issues fixed
Gavin-10 Aug 28, 2024
8b968cf
Added suggestions from review
Gavin-10 Oct 2, 2024
0de62ae
Formatted demos
Gavin-10 Oct 3, 2024
ae5befd
merge master branch and resolve conflicts
ZeeshanTamboli Oct 30, 2024
15c0396
Merge branch 'master' into loading-button
ZeeshanTamboli Oct 30, 2024
1d6b23f
pnpm dedupe
ZeeshanTamboli Oct 30, 2024
9c1394d
pnpm docs:api
ZeeshanTamboli Oct 30, 2024
54acce4
pnpm dedupe
ZeeshanTamboli Oct 30, 2024
840c0a8
Remove LodingButton spec file and move the test to Button spec
ZeeshanTamboli Oct 30, 2024
64f6e6f
rename
ZeeshanTamboli Oct 30, 2024
a837207
fix unit test
ZeeshanTamboli Oct 30, 2024
e9d2f9d
fix full width loading button regression
ZeeshanTamboli Oct 30, 2024
eea3660
remove loading button classes
ZeeshanTamboli Oct 31, 2024
c983657
update demo
ZeeshanTamboli Oct 31, 2024
1793b93
remove loading-button links
ZeeshanTamboli Oct 31, 2024
cf13fb0
add label
ZeeshanTamboli Oct 31, 2024
0a368a4
add missing styles
ZeeshanTamboli Oct 31, 2024
3bc8275
Merge branch 'master' into loading-button
ZeeshanTamboli Oct 31, 2024
110316c
remove redundant tests
ZeeshanTamboli Oct 31, 2024
a3821e0
remove redundant tests
ZeeshanTamboli Oct 31, 2024
f09c729
add missing ownerState
ZeeshanTamboli Nov 1, 2024
4099c08
update docs code review
ZeeshanTamboli Nov 2, 2024
91c8f50
update rendering logic
ZeeshanTamboli Nov 2, 2024
1563d53
pnpm docs:link-check
ZeeshanTamboli Nov 2, 2024
d0d914a
Merge branch 'master' into loading-button
ZeeshanTamboli Nov 4, 2024
6b0ce5d
update loading-button links
ZeeshanTamboli Nov 4, 2024
eceba5d
Merge branch 'master' of https://github.com/mui/material-ui into load…
siriwatknp Nov 5, 2024
18ef354
remove label slot and simplify code
siriwatknp Nov 6, 2024
839d9c7
restore unwanted change
siriwatknp Nov 6, 2024
b52d663
fix link
siriwatknp Nov 6, 2024
65f25fd
preserve the same demo
siriwatknp Nov 6, 2024
b2dc46e
fix test
siriwatknp Nov 6, 2024
2864248
run proptypes
siriwatknp Nov 6, 2024
75f35f9
run docs:ts:format
siriwatknp Nov 6, 2024
23d8200
test fix gg translate
siriwatknp Nov 7, 2024
ae62a4d
render indicator only when loading
siriwatknp Nov 7, 2024
d0f92dd
use order and simplify styles
siriwatknp Nov 7, 2024
a354fd5
remove Button label slot
ZeeshanTamboli Nov 9, 2024
497b8ad
Merge branch 'master' into loading-button
ZeeshanTamboli Nov 9, 2024
c24da44
update warning text
ZeeshanTamboli Nov 9, 2024
d160f4c
update migration guide on Button with loading state
ZeeshanTamboli Nov 9, 2024
10c8fd8
use non-breaking space for Material UI
ZeeshanTamboli Nov 9, 2024
d7b67b5
fix vale
ZeeshanTamboli Nov 9, 2024
158a325
Merge branch 'master' into loading-button
Gavin-10 Nov 12, 2024
3f800e0
Merge branch 'master' of https://github.com/mui/material-ui into load…
siriwatknp Nov 13, 2024
d0ce7f3
add loading to IconButton
siriwatknp Nov 13, 2024
ad5e9c7
run proptypes
siriwatknp Nov 13, 2024
739299b
run docs:ts:format
siriwatknp Nov 13, 2024
e6ad5c1
separate badge from loading demo
siriwatknp Nov 14, 2024
723d36d
add tests for IconButton loading
siriwatknp Nov 14, 2024
0de27c4
fix link
ZeeshanTamboli Nov 14, 2024
b472bb9
add loading style for styleOverrides
ZeeshanTamboli Nov 14, 2024
579e331
Merge branch 'master' into loading-button
ZeeshanTamboli Nov 14, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -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 (
<ButtonGroup variant="outlined" aria-label="Loading button group">
<Button>Submit</Button>
<LoadingButton>Fetch data</LoadingButton>
<LoadingButton loading loadingPosition="start" startIcon={<SaveIcon />}>
<Button>Fetch data</Button>
<Button loading loadingPosition="start" startIcon={<SaveIcon />}>
Save
</LoadingButton>
</Button>
</ButtonGroup>
);
}
Original file line number Diff line number Diff line change
@@ -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 (
<ButtonGroup variant="outlined" aria-label="Loading button group">
<Button>Submit</Button>
<LoadingButton>Fetch data</LoadingButton>
<LoadingButton loading loadingPosition="start" startIcon={<SaveIcon />}>
<Button>Fetch data</Button>
ZeeshanTamboli marked this conversation as resolved.
Show resolved Hide resolved
<Button loading loadingPosition="start" startIcon={<SaveIcon />}>
Save
</LoadingButton>
</Button>
</ButtonGroup>
);
}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<ButtonGroup variant="outlined" aria-label="Loading button group">
<Button>Submit</Button>
<LoadingButton>Fetch data</LoadingButton>
<LoadingButton loading loadingPosition="start" startIcon={<SaveIcon />}>
<Button>Fetch data</Button>
<Button loading loadingPosition="start" startIcon={<SaveIcon />}>
Save
</LoadingButton>
</Button>
</ButtonGroup>
8 changes: 3 additions & 5 deletions docs/data/material/components/button-group/button-group.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
productId: material-ui
title: React Button Group component
components: Button, ButtonGroup, LoadingButton
components: Button, ButtonGroup
githubLabel: 'component: ButtonGroup'
---

Expand Down Expand Up @@ -48,10 +48,8 @@ You can remove the elevation with the `disableElevation` prop.

{{"demo": "DisableElevation.js"}}

## Experimental APIs
## Loading button
ZeeshanTamboli marked this conversation as resolved.
Show resolved Hide resolved

### Loading button

You can use the [`<LoadingButton />`](/material-ui/react-button/#loading-button) from [`@mui/lab`](/material-ui/about-the-lab/) in the button group.
You can use the `loading` prop to create loading buttons in button groups
ZeeshanTamboli marked this conversation as resolved.
Show resolved Hide resolved

{{"demo": "LoadingButtonGroup.js"}}
14 changes: 7 additions & 7 deletions docs/data/material/components/buttons/LoadingButtons.js
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
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 (
<Stack direction="row" spacing={2}>
<LoadingButton loading variant="outlined">
<Button loading variant="outlined">
Submit
</LoadingButton>
<LoadingButton loading loadingIndicator="Loading…" variant="outlined">
</Button>
<Button loading loadingIndicator="Loading…" variant="outlined">
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
loading
loadingPosition="start"
startIcon={<SaveIcon />}
variant="outlined"
>
Save
</LoadingButton>
</Button>
</Stack>
);
}
14 changes: 7 additions & 7 deletions docs/data/material/components/buttons/LoadingButtons.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,25 @@
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 (
<Stack direction="row" spacing={2}>
<LoadingButton loading variant="outlined">
<Button loading variant="outlined">
Submit
</LoadingButton>
<LoadingButton loading loadingIndicator="Loading…" variant="outlined">
</Button>
<Button loading loadingIndicator="Loading…" variant="outlined">
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
loading
loadingPosition="start"
startIcon={<SaveIcon />}
variant="outlined"
>
Save
</LoadingButton>
</Button>
</Stack>
);
}
12 changes: 6 additions & 6 deletions docs/data/material/components/buttons/LoadingButtons.tsx.preview
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
<LoadingButton loading variant="outlined">
<Button loading variant="outlined">
Submit
</LoadingButton>
<LoadingButton loading loadingIndicator="Loading…" variant="outlined">
</Button>
<Button loading loadingIndicator="Loading…" variant="outlined">
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
loading
loadingPosition="start"
startIcon={<SaveIcon />}
variant="outlined"
>
Save
</LoadingButton>
</Button>
39 changes: 17 additions & 22 deletions docs/data/material/components/buttons/LoadingButtonsTransition.js
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -27,25 +27,25 @@ export default function LoadingButtonsTransition() {
label="Loading"
/>
<Box sx={{ '& > button': { m: 1 } }}>
<LoadingButton
<Button
size="small"
onClick={handleClick}
loading={loading}
variant="outlined"
disabled
>
Disabled
</LoadingButton>
<LoadingButton
</Button>
<Button
size="small"
onClick={handleClick}
loading={loading}
loadingIndicator="Loading…"
variant="outlined"
>
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
size="small"
onClick={handleClick}
endIcon={<SendIcon />}
Expand All @@ -54,8 +54,8 @@ export default function LoadingButtonsTransition() {
variant="contained"
>
Send
</LoadingButton>
<LoadingButton
</Button>
<Button
size="small"
color="secondary"
onClick={handleClick}
Expand All @@ -65,35 +65,30 @@ export default function LoadingButtonsTransition() {
variant="contained"
>
Save
</LoadingButton>
</Button>
</Box>
<Box sx={{ '& > button': { m: 1 } }}>
<LoadingButton
onClick={handleClick}
loading={loading}
variant="outlined"
disabled
>
<Button onClick={handleClick} loading={loading} variant="outlined" disabled>
Disabled
</LoadingButton>
<LoadingButton
</Button>
<Button
onClick={handleClick}
loading={loading}
loadingIndicator="Loading…"
variant="outlined"
>
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
onClick={handleClick}
endIcon={<SendIcon />}
loading={loading}
loadingPosition="end"
variant="contained"
>
Send
</LoadingButton>
<LoadingButton
</Button>
<Button
color="secondary"
onClick={handleClick}
loading={loading}
Expand All @@ -102,7 +97,7 @@ export default function LoadingButtonsTransition() {
variant="contained"
>
Save
</LoadingButton>
</Button>
</Box>
</div>
);
Expand Down
39 changes: 17 additions & 22 deletions docs/data/material/components/buttons/LoadingButtonsTransition.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as React from 'react';
import LoadingButton from '@mui/lab/LoadingButton';
import Button from '@mui/material/Button';
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change goes in opposition to the initial API design decision, no? #21389. We used import LoadingButton from '@mui/lab/LoadingButton';, we didn't use:

import Button from '@mui/material/Button';

<Button unstable_loading={true}>

The reason was in this dangerbot message:
SCR-20241115-pacn

Personally, as a user, I wouldn't want to use the Material UI Button if it loads a progress component that is different from the one that I want to use because it's bundle size bloat.

Was this change discussed? How do we feel about it?

Happy to move forward with a loading prop though.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a <Button loading> is better than having <Button> and <LoadingButton>. I guess 9/10 projects would need a loading button so it's fine to bundle CircularProgress to the Button.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this was discussed. Having a loading prop in Button is universally established and I think it's preferable to merge LoadingButton and Button to reduce API surface and confusion (why having 2 components with almost the same exact API?), even if it means an increase in the bundle size.

Q: Is there a way we could dynamically import the progress component that would be compatible with all bundlers? Are dynamic imports universally supported?

Personally, as a user, I wouldn't want to use the Material UI Button if it loads a progress component that is different from the one that I want to use because it's bundle size bloat.

This also happens with component styles. Users load our components, which have all styles built-in and are included in the bundle, to later override them.

Copy link
Member

@oliviertassinari oliviertassinari Nov 19, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Q: Is there a way we could dynamically import the progress component that would be compatible with all bundlers? Are dynamic imports universally supported?

@aarongarciah MUI X does this https://github.com/mui/mui-x/blob/a4481b6a661849d1a33b41aad86970a1e212ca69/packages/x-data-grid-premium/src/hooks/features/export/serializer/excelSerializer.ts#L24. It seems to work for them:

Screen.Recording.2024-11-19.at.16.34.51.mov

In the CJS the output is https://unpkg.com/browse/@mui/x-data-grid-premium@7.22.2/hooks/features/export/serializer/excelSerializer.js so it only works for ESM.

This wouldn't work for us here, since we would also need an async component, not React 18 friendly.


This also happens with component styles. Users load our components, which have all styles built-in and are included in the bundle, to later override them.

Yeah. Ok, so maybe it's fine. As long as we move to have the source to be clean to copy and paste from the npm package to a project codebase, then, a developer (e.g. me) would eject, and remove all the stuff unneeded, once it truly becomes a problem.

I have checked a couple of design system, they seem to all go with the loading prop pattern. e.g. https://polaris.shopify.com/components/actions/button. So yeah, assuming that we don't expect most people to wrap the MUI component to create their own system, but to either

  • use it as is with theme customization
  • or to decompose + recompose with a wrapper, this makes sense.

import Box from '@mui/material/Box';
import FormControlLabel from '@mui/material/FormControlLabel';
import Switch from '@mui/material/Switch';
Expand Down Expand Up @@ -27,25 +27,25 @@ export default function LoadingButtonsTransition() {
label="Loading"
/>
<Box sx={{ '& > button': { m: 1 } }}>
<LoadingButton
<Button
size="small"
onClick={handleClick}
loading={loading}
variant="outlined"
disabled
>
Disabled
</LoadingButton>
<LoadingButton
</Button>
<Button
size="small"
onClick={handleClick}
loading={loading}
loadingIndicator="Loading…"
variant="outlined"
>
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
size="small"
onClick={handleClick}
endIcon={<SendIcon />}
Expand All @@ -54,8 +54,8 @@ export default function LoadingButtonsTransition() {
variant="contained"
>
Send
</LoadingButton>
<LoadingButton
</Button>
<Button
size="small"
color="secondary"
onClick={handleClick}
Expand All @@ -65,35 +65,30 @@ export default function LoadingButtonsTransition() {
variant="contained"
>
Save
</LoadingButton>
</Button>
</Box>
<Box sx={{ '& > button': { m: 1 } }}>
<LoadingButton
onClick={handleClick}
loading={loading}
variant="outlined"
disabled
>
<Button onClick={handleClick} loading={loading} variant="outlined" disabled>
Disabled
</LoadingButton>
<LoadingButton
</Button>
<Button
onClick={handleClick}
loading={loading}
loadingIndicator="Loading…"
variant="outlined"
>
Fetch data
</LoadingButton>
<LoadingButton
</Button>
<Button
onClick={handleClick}
endIcon={<SendIcon />}
loading={loading}
loadingPosition="end"
variant="contained"
>
Send
</LoadingButton>
<LoadingButton
</Button>
<Button
color="secondary"
onClick={handleClick}
loading={loading}
Expand All @@ -102,7 +97,7 @@ export default function LoadingButtonsTransition() {
variant="contained"
>
Save
</LoadingButton>
</Button>
</Box>
</div>
);
Expand Down
Loading