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

Conversation

Gavin-10
Copy link
Contributor

@Gavin-10 Gavin-10 commented Jul 18, 2024

All functionality from loadingButton has been moved to Button in mui-material

closes #42684

Closes #31235 (removes the wrong warning)

Preview: https://deploy-preview-42987--material-ui.netlify.app/material-ui/react-button/

Gavin McGuinness added 2 commits July 17, 2024 21:27
All functionality from loadingButton has been moved to Button in
mui-material
@Gavin-10 Gavin-10 marked this pull request as draft July 18, 2024 01:49
@github-actions github-actions bot added the PR: out-of-date The pull request has merge conflicts and can't be merged label Jul 18, 2024
@mui-bot
Copy link

mui-bot commented Jul 18, 2024

Netlify deploy preview

IconButton: parsed: +4.61% , gzip: +3.47%
Alert: parsed: +3.99% , gzip: +3.08%
Autocomplete: parsed: +2.44% , gzip: +1.83%
@material-ui/core: parsed: +0.58% , gzip: +0.40%
LoadingButton: parsed: -1.09% 😍, gzip: -0.46% 😍
@material-ui/lab: parsed: -0.14% 😍, gzip: +0.02%

Bundle size report

Details of bundle changes (Toolpad)
Details of bundle changes

Generated by 🚫 dangerJS against 579e331

Gavin McGuinness added 3 commits July 17, 2024 23:18
added Icon class to start and end icons, ran prettier, updated
loadingButton tests to test Button. LoadingButton tests not to be merged
@aarongarciah aarongarciah self-requested a review July 20, 2024 20:10
@ZeeshanTamboli ZeeshanTamboli added component: button This is the name of the generic UI component, not the React module! package: material-ui Specific to @mui/material labels Jul 21, 2024
Copy link
Member

@aarongarciah aarongarciah left a comment

Choose a reason for hiding this comment

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

Thanks for working on this @Gavin-10! I did a first pass and left some inline comments. Apart from that, two more things:

  • The LoadingButton component implementation in mui-lab needs to be updated to just use the newly updated Button from mui-material. The Alert component in mui-lab is a good example of how to do this.
  • The Button usage docs must be updated:
    • The examples under the "Loading button" section must be updated to use Button and this section should be moved before the "File upload" section.
    • The "Experimental APIs" heading can be removed.
    • LoadingButton shouldn't be listed in the API section at the end of the page.

Let me know if you have any doubts or if you need help.

packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
test/test-results/.last-run.json Outdated Show resolved Hide resolved
pnpm-lock.yaml Outdated Show resolved Hide resolved
packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
packages/mui-material/src/Button/Button.js Outdated Show resolved Hide resolved
packages/mui-lab/src/LoadingButton/LoadingButton.test.js Outdated Show resolved Hide resolved
@aarongarciah aarongarciah self-assigned this Aug 21, 2024
Button.js variable names changed, extra classes deleted,
loading button tests moved to button.test.js, pnpm-lock restored,
last-run.json removed (hopefully)
@Gavin-10
Copy link
Contributor Author

Thank you so much @aarongarciah for the review! I have implemented all the suggested changes and almost ready to push again. I just have two quick questions. To remove the loading button from the API list do I need to just delete the .json and .js file from the API folder or are there more steps I need to do? Last, all of those extra props were generated when I ran pnpm proptypes and I'm just wondering why they need to be removed so I can have a better understanding for future contributions? Thank you so much.

@aarongarciah
Copy link
Member

To remove the loading button from the API list do I need to just delete the .json and .js file from the API folder or are there more steps I need to do?

To remove LoadingButton from the API list, you just need to remove LoadingButton from the front matter in the corresponding docs markdown file. See

components: Button, IconButton, ButtonBase, LoadingButton

Last, all of those extra props were generated when I ran pnpm proptypes

I should have left the comment in the .d.ts file instead of the .js file. pnpm proptypes generates proptypes based on the types defined in the .d.ts file. So if you remove the unwanted props from the .d.ts file, running pnpm proptypes again will remove the proptypes from the .js file.

Every time you make a proptypes change (add, remove, or modify comments) you'll need to run pnpm docs:api so the corresponding .json files consumed by the docs are updated.

Another common script is pnpm docs:typescript, which we run after modifying any demo file: we work on .tsx files and this script generates the corresponding .js file.

Take a look at https://github.com/mui/material-ui/blob/next/CONTRIBUTING.md#sending-a-pull-request if you have doubts and feel free to ping me anytime you get stuck.

Happy coding!

@Gavin-10 Gavin-10 marked this pull request as ready for review August 25, 2024 20:52
@Gavin-10
Copy link
Contributor Author

Everything should be about wrapped up now. I fixed the dependency issues and some minor styling issues with child elements. The test_unit and test_browser tests failing is expected and caused by the CircularProgress not having accessibility labels. I however do not know why test_e2e_website is failing. Once that is resolved though, I believe everything should be ready.

Copy link
Member

@aarongarciah aarongarciah left a comment

Choose a reason for hiding this comment

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

I did another quick pass. We're currently focused on supporting the v6 release, but I'll get back to this PR once all feedback is tackled. Thanks for working on this!

docs/data/material/components/button-group/button-group.md Outdated Show resolved Hide resolved
docs/data/material/components/buttons/buttons.md Outdated Show resolved Hide resolved
docs/data/material/pagesApi.js Show resolved Hide resolved
packages/mui-lab/src/LoadingButton/LoadingButton.js Outdated Show resolved Hide resolved
docs/data/material/components/buttons/buttons.md Outdated Show resolved Hide resolved
@siriwatknp
Copy link
Member

Copy link
Member

@ZeeshanTamboli ZeeshanTamboli left a comment

Choose a reason for hiding this comment

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

Can we add tests for IconButton with loading state?

@siriwatknp
Copy link
Member

Can we add tests for IconButton with loading state?

Added, thanks.

Copy link
Member

@siriwatknp siriwatknp left a comment

Choose a reason for hiding this comment

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

👍 I'm pumped. It has been 4 years since LoadingButton was introduced!

Copy link
Member

@ZeeshanTamboli ZeeshanTamboli left a comment

Choose a reason for hiding this comment

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

Pushed two commits recently. Looks good to me!

@siriwatknp siriwatknp merged commit 7ad8893 into mui:master Nov 14, 2024
22 checks passed
@Gavin-10 Gavin-10 deleted the loading-button branch November 14, 2024 15:39
import ShoppingCartIcon from '@mui/icons-material/ShoppingCartOutlined';

const CartBadge = styled(Badge)`
.${badgeClasses.badge} {
Copy link
Member

@oliviertassinari oliviertassinari Nov 15, 2024

Choose a reason for hiding this comment

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

Missing selector per convention

Suggested change
.${badgeClasses.badge} {
&.${badgeClasses.badge} {

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/[email protected]/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.

packages/mui-material/src/Button/Button.d.ts Show resolved Hide resolved
packages/mui-material/src/Button/Button.d.ts Show resolved Hide resolved
packages/mui-material/src/Button/Button.js Show resolved Hide resolved
@aarongarciah aarongarciah added the component: icon button This is the name of the generic UI component, not the React module! label Nov 19, 2024
Comment on lines +572 to +576
const loader = (
<ButtonLoadingIndicator className={classes.loadingIndicator} ownerState={ownerState}>
{loading && loadingIndicator}
</ButtonLoadingIndicator>
);
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.

Can we make this conditional? I don't think this can work to render an empty DOM node when loading={false}:
SCR-20241119-ortp

https://deploy-preview-42987--material-ui.netlify.app/material-ui/react-button/#basic-button. DOM size has an impact on performance, buttons that are likely to be rendered in the x100 in a list. Same applies with emotion, another styled() mounting point is more slowness to the page. The most important might be that this can communicate a feeling of "bloat" to developers.

At the very minimum, I think we need a comment to explain why it's here. As a developer looking at the dev tools then the source to try to understand this, I would be: "What?! Let's delete that" I wouldn't know the context around Google translate #35198.

Copy link
Member

Choose a reason for hiding this comment

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

If it's conditional, it won't fix #35198.

Copy link
Member

Choose a reason for hiding this comment

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

I don't think this can fly

May I ask why? what's the issue of it?

Copy link
Member

@oliviertassinari oliviertassinari Nov 20, 2024

Choose a reason for hiding this comment

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

If it's conditional, it won't fix

@siriwatknp I mean, what I don't understand is why are we not using the same fix that we used in #35198? Why are we always rendering an extra styled() element even when loading={false}?

May I ask why? what's the issue of it?

I have tried to cover the problem with the initial comment: "DOM size has an impact on performance, buttons that are likely to be rendered in the x100 in a list. Same applies with emotion, another styled() mounting point is more slowness to the page. The most important might be that this can communicate a feeling of "bloat" to developers."

What do you think about those?

siriwatknp added a commit to siriwatknp/material-ui that referenced this pull request Nov 20, 2024
@oliviertassinari
Copy link
Member

PR was reverted in #44478.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
component: button This is the name of the generic UI component, not the React module! component: icon button This is the name of the generic UI component, not the React module! new feature New feature or request package: material-ui Specific to @mui/material
Projects
Status: Done
Development

Successfully merging this pull request may close these issues.

[material-ui][Button] Button doesn't have the loading props [LoadingButton] Displaying incorrect warning
7 participants