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

[ButtonGroup] Add disableElevation prop #20747

Merged
merged 3 commits into from Apr 25, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 2 additions & 0 deletions docs/pages/api-docs/button-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ The `MuiButtonGroup` name can be used for providing [default props](/customizati
| <span class="prop-name">color</span> | <span class="prop-type">'default'<br>&#124;&nbsp;'inherit'<br>&#124;&nbsp;'primary'<br>&#124;&nbsp;'secondary'</span> | <span class="prop-default">'default'</span> | The color of the component. It supports those theme colors that make sense for this component. |
| <span class="prop-name">component</span> | <span class="prop-type">elementType</span> | <span class="prop-default">'div'</span> | The component used for the root node. Either a string to use a HTML element or a component. |
| <span class="prop-name">disabled</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the buttons will be disabled. |
| <span class="prop-name">disableElevation</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, no elevation is used. |
| <span class="prop-name">disableFocusRipple</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the button keyboard focus ripple will be disabled. `disableRipple` must also be true. |
| <span class="prop-name">disableRipple</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the button ripple effect will be disabled. |
| <span class="prop-name">fullWidth</span> | <span class="prop-type">bool</span> | <span class="prop-default">false</span> | If `true`, the buttons will take up the full width of its container. |
Expand All @@ -50,6 +51,7 @@ Any other props supplied will be provided to the root element (native element).
|:-----|:-------------|:------------|
| <span class="prop-name">root</span> | <span class="prop-name">.MuiButtonGroup-root</span> | Styles applied to the root element.
| <span class="prop-name">contained</span> | <span class="prop-name">.MuiButtonGroup-contained</span> | Styles applied to the root element if `variant="contained"`.
| <span class="prop-name">disableElevation</span> | <span class="prop-name">.MuiButtonGroup-disableElevation</span> | Styles applied to the root element if `disableElevation={true}`.
| <span class="prop-name">disabled</span> | <span class="prop-name">.Mui-disabled</span> | Pseudo-class applied to child elements if `disabled={true}`.
| <span class="prop-name">fullWidth</span> | <span class="prop-name">.MuiButtonGroup-fullWidth</span> | Styles applied to the root element if `fullWidth={true}`.
| <span class="prop-name">vertical</span> | <span class="prop-name">.MuiButtonGroup-vertical</span> | Styles applied to the root element if `orientation="vertical"`.
Expand Down
12 changes: 12 additions & 0 deletions docs/src/pages/components/button-group/DisableElevation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import ButtonGroup from '@material-ui/core/ButtonGroup';
import Button from '@material-ui/core/Button';

export default function DisableElevation() {
return (
<ButtonGroup disableElevation variant="contained" color="primary">
<Button>One</Button>
<Button>Two</Button>
</ButtonGroup>
);
}
12 changes: 12 additions & 0 deletions docs/src/pages/components/button-group/DisableElevation.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import React from 'react';
import ButtonGroup from '@material-ui/core/ButtonGroup';
import Button from '@material-ui/core/Button';

export default function DisableElevation() {
return (
<ButtonGroup disableElevation variant="contained" color="primary">
<Button>One</Button>
<Button>Two</Button>
</ButtonGroup>
);
}
14 changes: 10 additions & 4 deletions docs/src/pages/components/button-group/button-group.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,22 @@ components: Button, ButtonGroup

{{"demo": "pages/components/button-group/BasicButtonGroup.js"}}

### Group sizes and colors
## Sizes and colors

{{"demo": "pages/components/button-group/GroupSizesColors.js"}}

### Group orientation
## Vertical group

{{"demo": "pages/components/button-group/GroupOrientation.js"}}

### Split Button
## Split button

ButtonGroup can also be used to create a split button. The dropdown can change the button action (as in this example), or be used to immediately trigger a related action.
`ButtonGroup` can also be used to create a split button. The dropdown can change the button action (as in this example), or be used to immediately trigger a related action.

{{"demo": "pages/components/button-group/SplitButton.js"}}

## Disabled elevation

You can remove the elevation with the `disableElevation` prop.

{{"demo": "pages/components/button-group/DisableElevation.js"}}
2 changes: 2 additions & 0 deletions packages/material-ui/src/ButtonGroup/ButtonGroup.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export interface ButtonGroupTypeMap<P = {}, D extends React.ElementType = 'div'>
props: P & {
color?: PropTypes.Color;
disabled?: boolean;
disableElevation?: boolean;
disableFocusRipple?: boolean;
disableRipple?: boolean;
fullWidth?: boolean;
Expand Down Expand Up @@ -33,6 +34,7 @@ export type ButtonGroupClassKey =
| 'root'
| 'contained'
| 'disabled'
| 'disableElevation'
| 'fullWidth'
| 'vertical'
| 'grouped'
Expand Down
11 changes: 11 additions & 0 deletions packages/material-ui/src/ButtonGroup/ButtonGroup.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ export const styles = (theme) => ({
contained: {
boxShadow: theme.shadows[2],
},
/* Styles applied to the root element if `disableElevation={true}`. */
disableElevation: {
boxShadow: 'none',
},
/* Pseudo-class applied to child elements if `disabled={true}`. */
disabled: {},
/* Styles applied to the root element if `fullWidth={true}`. */
Expand Down Expand Up @@ -164,6 +168,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(props, ref) {
color = 'default',
component: Component = 'div',
disabled = false,
disableElevation = false,
disableFocusRipple = false,
disableRipple = false,
fullWidth = false,
Expand Down Expand Up @@ -193,6 +198,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(props, ref) {
[classes.contained]: variant === 'contained',
[classes.vertical]: orientation === 'vertical',
[classes.fullWidth]: fullWidth,
[classes.disableElevation]: disableElevation,
},
className,
)}
Expand Down Expand Up @@ -224,6 +230,7 @@ const ButtonGroup = React.forwardRef(function ButtonGroup(props, ref) {
fullWidth,
size: child.props.size || size,
variant: child.props.variant || variant,
disableElevation: child.props.disableElevation || disableElevation,
});
})}
</Component>
Expand Down Expand Up @@ -257,6 +264,10 @@ ButtonGroup.propTypes = {
* If `true`, the buttons will be disabled.
*/
disabled: PropTypes.bool,
/**
* If `true`, no elevation is used.
*/
disableElevation: PropTypes.bool,
/**
* If `true`, the button keyboard focus ripple will be disabled.
* `disableRipple` must also be true.
Expand Down
147 changes: 59 additions & 88 deletions packages/material-ui/src/ButtonGroup/ButtonGroup.test.js
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import * as React from 'react';
import { assert } from 'chai';
import { expect } from 'chai';
import { createMount, getClasses } from '@material-ui/core/test-utils';
import { createClientRender } from 'test/utils/createClientRender';
import describeConformance from '@material-ui/core/test-utils/describeConformance';
import Button from '../Button';
import ButtonGroup from './ButtonGroup';

describe('<ButtonGroup />', () => {
const render = createClientRender();
let mount;
let classes;

Expand Down Expand Up @@ -36,159 +38,128 @@ describe('<ButtonGroup />', () => {
);

it('should render with the root class but no others', () => {
const wrapper = mount(
const { container } = render(
<ButtonGroup>
<Button>Hello World</Button>
</ButtonGroup>,
);
const buttonGroup = wrapper.find('div');
assert.strictEqual(buttonGroup.hasClass(classes.root), true);
assert.strictEqual(buttonGroup.hasClass(classes.contained), false);
assert.strictEqual(buttonGroup.hasClass(classes.fullWidth), false);
const buttonGroup = container.firstChild;
expect(buttonGroup).to.have.class(classes.root);
expect(buttonGroup).to.not.have.class(classes.contained);
expect(buttonGroup).to.not.have.class(classes.fullWidth);
});

it('should render an outlined button', () => {
const wrapper = mount(
const { getByRole } = render(
<ButtonGroup>
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-outlined'), true);
assert.strictEqual(button.hasClass(classes.grouped), true);
assert.strictEqual(button.hasClass(classes.groupedOutlined), true);
assert.strictEqual(button.hasClass(classes.groupedOutlinedPrimary), false);
assert.strictEqual(button.hasClass(classes.groupedOutlinedSecondary), false);
const button = getByRole('button');
expect(button).to.have.class('MuiButton-outlined');
expect(button).to.have.class(classes.grouped);
expect(button).to.have.class(classes.groupedOutlined);
expect(button).to.not.have.class(classes.groupedOutlinedPrimary);
expect(button).to.not.have.class(classes.groupedOutlinedSecondary);
});

it('can render an outlined primary button', () => {
const wrapper = mount(
const { getByRole } = render(
<ButtonGroup color="primary">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('div').find('button');
assert.strictEqual(button.hasClass('MuiButton-outlinedPrimary'), true);
assert.strictEqual(button.hasClass(classes.grouped), true);
assert.strictEqual(button.hasClass(classes.groupedOutlined), true);
assert.strictEqual(button.hasClass(classes.groupedOutlinedPrimary), true);
assert.strictEqual(button.hasClass(classes.groupedOutlinedSecondary), false);
});

it('can render an outlined secondary button', () => {
const wrapper = mount(
<ButtonGroup color="secondary">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-outlinedSecondary'), true);
assert.strictEqual(button.hasClass(classes.grouped), true);
assert.strictEqual(button.hasClass(classes.groupedOutlined), true);
assert.strictEqual(button.hasClass(classes.groupedOutlinedPrimary), false);
assert.strictEqual(button.hasClass(classes.groupedOutlinedSecondary), true);
const button = getByRole('button');
expect(button).to.have.class('MuiButton-outlinedPrimary');
expect(button).to.have.class(classes.grouped);
expect(button).to.have.class(classes.groupedOutlined);
expect(button).to.have.class(classes.groupedOutlinedPrimary);
expect(button).to.not.have.class(classes.groupedOutlinedSecondary);
});

it('can render a contained button', () => {
const wrapper = mount(
const { getByRole } = render(
<ButtonGroup variant="contained">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-contained'), true);
assert.strictEqual(button.hasClass(classes.grouped), true);
assert.strictEqual(button.hasClass(classes.groupedContained), true);
assert.strictEqual(button.hasClass(classes.groupedContainedPrimary), false);
assert.strictEqual(button.hasClass(classes.groupedContainedSecondary), false);
});

it('can render a contained primary button', () => {
const wrapper = mount(
<ButtonGroup variant="contained" color="primary">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-containedPrimary'), true);
assert.strictEqual(button.hasClass(classes.grouped), true);
assert.strictEqual(button.hasClass(classes.groupedContained), true);
assert.strictEqual(button.hasClass(classes.groupedContainedPrimary), true);
assert.strictEqual(button.hasClass(classes.groupedContainedSecondary), false);
});

it('can render a contained secondary button', () => {
const wrapper = mount(
<ButtonGroup variant="contained" color="secondary">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-containedSecondary'), true);
assert.strictEqual(button.hasClass(classes.grouped), true);
assert.strictEqual(button.hasClass(classes.groupedContained), true);
assert.strictEqual(button.hasClass(classes.groupedContainedPrimary), false);
assert.strictEqual(button.hasClass(classes.groupedContainedSecondary), true);
const button = getByRole('button');
expect(button).to.have.class('MuiButton-contained');
expect(button).to.have.class(classes.grouped);
expect(button).to.have.class(classes.groupedContained);
expect(button).to.not.have.class(classes.groupedContainedPrimary);
expect(button).to.not.have.class(classes.groupedContainedSecondary);
});

it('can render a small button', () => {
const wrapper = mount(
const { getByRole } = render(
<ButtonGroup size="small">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-outlinedSizeSmall'), true);
const button = getByRole('button');
expect(button).to.have.class('MuiButton-outlinedSizeSmall');
});

it('can render a large button', () => {
const wrapper = mount(
const { getByRole } = render(
<ButtonGroup size="large">
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(button.hasClass('MuiButton-outlinedSizeLarge'), true);
const button = getByRole('button');
expect(button).to.have.class('MuiButton-outlinedSizeLarge');
});

it('should have a ripple by default', () => {
const wrapper = mount(
const { container } = render(
<ButtonGroup>
<Button TouchRippleProps={{ classes: { root: 'touchRipple' } }}>Hello World</Button>
</ButtonGroup>,
);
assert.strictEqual(wrapper.find('.touchRipple').exists(), true);
expect(container.querySelector('.touchRipple')).to.not.equal(null);
});

it('can disable the elevation', () => {
const { getByRole } = render(
<ButtonGroup disableElevation>
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = getByRole('button');
expect(button).to.have.class('MuiButton-disableElevation');
});

it('can disable the ripple', () => {
const wrapper = mount(
const { container } = render(
<ButtonGroup disableRipple>
<Button TouchRippleProps={{ classes: { root: 'touchRipple' } }}>Hello World</Button>
</ButtonGroup>,
);
assert.strictEqual(wrapper.find('.touchRipple').exists(), false);
expect(container.querySelector('.touchRipple')).to.equal(null);
});

it('should not be fullWidth by default', () => {
const wrapper = mount(
const { container, getByRole } = render(
<ButtonGroup>
<Button>Hello World</Button>
</ButtonGroup>,
);
const button = wrapper.find('button');
assert.strictEqual(wrapper.hasClass(classes.fullWidth), false);
assert.strictEqual(button.hasClass('MuiButton-fullWidth'), false);
const button = getByRole('button');
const buttonGroup = container.firstChild;
expect(buttonGroup).to.not.have.class(classes.fullWidth);
expect(button).to.not.have.class('MuiButton-fullWidth');
});

it('can pass fullWidth to Button', () => {
const wrapper = mount(
const { container, getByRole } = render(
<ButtonGroup fullWidth>
<Button>Hello World</Button>
</ButtonGroup>,
);
const buttonGroup = wrapper.find('div');
const button = wrapper.find('button');
assert.strictEqual(buttonGroup.hasClass(classes.fullWidth), true);
assert.strictEqual(button.hasClass('MuiButton-fullWidth'), true);
const buttonGroup = container.firstChild;
const button = getByRole('button');
expect(buttonGroup).to.have.class(classes.fullWidth);
expect(button).to.have.class('MuiButton-fullWidth');
});
});