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 5 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
59 changes: 59 additions & 0 deletions docs/pages/material-ui/api/button.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,24 @@
"disableFocusRipple": { "type": { "name": "bool" }, "default": "false" },
"disableRipple": { "type": { "name": "bool" }, "default": "false" },
"endIcon": { "type": { "name": "node" } },
"endIconLoadingEnd": { "type": { "name": "string" } },
"fullWidth": { "type": { "name": "bool" }, "default": "false" },
"href": { "type": { "name": "string" } },
"loading": { "type": { "name": "bool" }, "default": "false" },
"loadingIndicator": {
"type": { "name": "node" },
"default": "<CircularProgress color=\"inherit\" size={16} />"
},
"loadingIndicatorCenter": { "type": { "name": "string" } },
"loadingIndicatorEnd": { "type": { "name": "string" } },
"loadingIndicatorStart": { "type": { "name": "string" } },
"loadingPosition": {
"type": {
"name": "enum",
"description": "'center'<br>&#124;&nbsp;'end'<br>&#124;&nbsp;'start'"
},
"default": "'center'"
},
"size": {
"type": {
"name": "union",
Expand All @@ -25,6 +41,7 @@
"default": "'medium'"
},
"startIcon": { "type": { "name": "node" } },
"startIconLoadingStart": { "type": { "name": "string" } },
"sx": {
"type": {
"name": "union",
Expand Down Expand Up @@ -182,6 +199,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",
Expand Down Expand Up @@ -221,6 +244,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",
Expand Down Expand Up @@ -327,6 +380,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",
Expand Down
58 changes: 58 additions & 0 deletions docs/translations/api-docs/button/button.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,40 @@
"description": "If <code>true</code>, the ripple effect is disabled.<br>⚠️ Without a ripple there is no styling for :focus-visible by default. Be sure to highlight the element by applying separate styles with the <code>.Mui-focusVisible</code> class."
},
"endIcon": { "description": "Element placed after the children." },
"endIconLoadingEnd": {
"description": "Styles applied to the endIcon element if <code>loading={true}</code> and <code>loadingPosition=&quot;end&quot;</code>."
},
"fullWidth": {
"description": "If <code>true</code>, the button will take up the full width of its container."
},
"href": {
"description": "The URL to link to when the button is clicked. If defined, an <code>a</code> element will be used as the root node."
},
"loading": {
"description": "If <code>true</code>, 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 <code>role=&quot;progressbar&quot;</code> with an accessible name. By default we render a <code>CircularProgress</code> that is labelled by the button itself."
},
"loadingIndicatorCenter": {
"description": "Styles applied to the loadingIndicator element if <code>loadingPosition=&quot;center&quot;</code>."
},
"loadingIndicatorEnd": {
"description": "Styles applied to the loadingIndicator element if <code>loadingPosition=&quot;end&quot;</code>."
},
"loadingIndicatorStart": {
"description": "Styles applied to the loadingIndicator element if <code>loadingPosition=&quot;start&quot;</code>."
},
"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. <code>small</code> is equivalent to the dense button styling."
},
"startIcon": { "description": "Element placed before the children." },
"startIconLoadingStart": {
"description": "Styles applied to the startIcon element if <code>loading={true}</code> and <code>loadingPosition=&quot;start&quot;</code>."
},
"sx": {
"description": "The system prop that allows defining system overrides as well as additional CSS styles."
},
Expand Down Expand Up @@ -149,6 +173,11 @@
"nodeName": "the endIcon element",
"conditions": "supplied"
},
"endIconLoadingEnd": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the endIcon element",
"conditions": "<code>loading={true}</code> and <code>loadingPosition=\"end\"</code>"
},
"focusVisible": {
"description": "State class applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the ButtonBase root element",
Expand Down Expand Up @@ -178,6 +207,30 @@
"conditions": "supplied and <code>size=\"small\"</code>",
"deprecationInfo": "Combine the <a href=\"/material-ui/api/button/#button-classes-icon\">.MuiButton-icon</a> and <a href=\"/material-ui/api/button/#button-classes-sizeSmall\">.MuiButtonSizeSmall</a> classes instead. See <a href=\"/material-ui/migration/migrating-from-deprecated-apis/\">Migrating from deprecated APIs</a> for more details."
},
"loading": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the root element",
"conditions": "<code>loading={true}</code>"
},
"loadingIndicator": {
"description": "Styles applied to {{nodeName}}.",
"nodeName": "the loadingIndicator element"
},
"loadingIndicatorCenter": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the loadingIndicator element",
"conditions": "<code>loadingPosition=\"center\"</code>"
},
"loadingIndicatorEnd": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the loadingIndicator element",
"conditions": "<code>loadingPosition=\"end\"</code>"
},
"loadingIndicatorStart": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the loadingIndicator element",
"conditions": "<code>loadingPosition=\"start\"</code>"
},
"outlined": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the root element",
Expand Down Expand Up @@ -264,6 +317,11 @@
"nodeName": "the startIcon element",
"conditions": "supplied"
},
"startIconLoadingStart": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the startIcon element",
"conditions": "<code>loading={true}</code> and <code>loadingPosition=\"start\"</code>"
},
"text": {
"description": "Styles applied to {{nodeName}} if {{conditions}}.",
"nodeName": "the root element",
Expand Down
24 changes: 12 additions & 12 deletions packages/mui-lab/src/LoadingButton/LoadingButton.test.js
aarongarciah marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,13 @@ describe('<LoadingButton />', () => {
}));

it('is in tab-order by default', () => {
render(<LoadingButton />);
render(<Button />);

expect(screen.getByRole('button')).to.have.property('tabIndex', 0);
});

it('prop: classes can be appended to MuiButton', () => {
render(<LoadingButton variant="outlined" classes={{ outlined: 'loading-button-outlined' }} />);
render(<Button variant="outlined" classes={{ outlined: 'loading-button-outlined' }} />);
const button = screen.getByRole('button');

expect(button).to.have.class('MuiButton-outlined');
Expand All @@ -35,21 +35,21 @@ describe('<LoadingButton />', () => {

describe('prop: loading', () => {
it('disables the button', () => {
render(<LoadingButton loading />);
render(<Button loading />);

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(<LoadingButton disabled={false} loading />);
render(<Button disabled={false} loading />);

expect(screen.getByRole('button')).to.have.property('disabled', true);
});

it('renders a progressbar that is labelled by the button', () => {
render(<LoadingButton loading>Submit</LoadingButton>);
render(<Button loading>Submit</Button>);

const button = screen.getByRole('button');
const progressbar = within(button).getByRole('progressbar');
Expand All @@ -59,16 +59,16 @@ describe('<LoadingButton />', () => {

describe('prop: loadingIndicator', () => {
it('is not rendered by default', () => {
render(<LoadingButton loadingIndicator="loading">Test</LoadingButton>);
render(<Button loadingIndicator="loading">Test</Button>);

expect(screen.getByRole('button')).to.have.text('Test');
});

it('is rendered before the children when `loading`', () => {
render(
<LoadingButton loadingIndicator="loading…" loading>
<Button loadingIndicator="loading…" loading>
Test
</LoadingButton>,
</Button>,
);

expect(screen.getByRole('button')).to.have.text('loading…Test');
Expand All @@ -79,7 +79,7 @@ describe('<LoadingButton />', () => {
it('correctly passes props to children', () => {
const { getByRole } = render(
<ButtonGroup variant="contained" size="large" color="secondary">
<LoadingButton />
<Button />
</ButtonGroup>,
);
const button = getByRole('button');
Expand All @@ -91,9 +91,9 @@ describe('<LoadingButton />', () => {
it('correctly applies position classes to loading buttons', () => {
render(
<ButtonGroup>
<LoadingButton>Button 1</LoadingButton>
<LoadingButton>Button 2</LoadingButton>
<LoadingButton>Button 3</LoadingButton>
<Button>Button 1</Button>
<Button>Button 2</Button>
<Button>Button 3</Button>
</ButtonGroup>,
);

Expand Down
27 changes: 27 additions & 0 deletions packages/mui-material/src/Button/Button.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,33 @@ export interface ButtonOwnProps {
* If defined, an `a` element will be used as the root node.
*/
href?: string;
/**
* If `true`, the loading indicator is shown and the button becomes disabled.
aarongarciah marked this conversation as resolved.
Show resolved Hide resolved
* @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.
aarongarciah marked this conversation as resolved.
Show resolved Hide resolved
* @default <CircularProgress color="inherit" size={16} />
*/
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';
/** 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;
/**
* The size of the component.
* `small` is equivalent to the dense button styling.
Expand Down
Loading