Skip to content

Commit

Permalink
[Alert] Add components and componentsProps props to allow close a…
Browse files Browse the repository at this point in the history
…ction overrides (mui#33582)
  • Loading branch information
jake-collibra authored and felipe.richter committed Dec 6, 2022
1 parent 2602593 commit 7c4aeff
Show file tree
Hide file tree
Showing 5 changed files with 129 additions and 4 deletions.
11 changes: 11 additions & 0 deletions docs/pages/material-ui/api/alert.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,17 @@
"description": "'error'<br>&#124;&nbsp;'info'<br>&#124;&nbsp;'success'<br>&#124;&nbsp;'warning'<br>&#124;&nbsp;string"
}
},
"components": {
"type": {
"name": "shape",
"description": "{ CloseButton?: elementType, CloseIcon?: elementType }"
},
"default": "{}"
},
"componentsProps": {
"type": { "name": "shape", "description": "{ closeButton?: object, closeIcon?: object }" },
"default": "{}"
},
"icon": { "type": { "name": "node" } },
"iconMapping": {
"type": {
Expand Down
2 changes: 2 additions & 0 deletions docs/translations/api-docs/alert/alert.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
"classes": "Override or extend the styles applied to the component. See <a href=\"#css\">CSS API</a> below for more details.",
"closeText": "Override the default label for the <em>close popup</em> icon button.<br>For localization purposes, you can use the provided <a href=\"/material-ui/guides/localization/\">translations</a>.",
"color": "The color of the component. Unless provided, the value is taken from the <code>severity</code> prop. It supports both default and custom theme colors, which can be added as shown in the <a href=\"https://mui.com/material-ui/customization/palette/#adding-new-colors\">palette customization guide</a>.",
"components": "The components used for each slot inside the Alert. Either a string to use a HTML element or a component.",
"componentsProps": "The props used for each slot inside.",
"icon": "Override the icon displayed before the children. Unless provided, the icon is mapped to the value of the <code>severity</code> prop. Set to <code>false</code> to remove the <code>icon</code>.",
"iconMapping": "The component maps the <code>severity</code> prop to a range of different icons, for instance success to <code>&lt;SuccessOutlined&gt;</code>. If you wish to change this mapping, you can provide your own. Alternatively, you can use the <code>icon</code> prop to override the icon displayed.",
"onClose": "Callback fired when the component requests to be closed. When provided and no <code>action</code> prop is set, a close icon button is displayed that triggers the callback when clicked.<br><br><strong>Signature:</strong><br><code>function(event: React.SyntheticEvent) =&gt; void</code><br><em>event:</em> The event source of the callback.",
Expand Down
19 changes: 18 additions & 1 deletion packages/mui-material/src/Alert/Alert.d.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import { OverridableStringUnion } from '@mui/types';
import { SxProps } from '@mui/system';
import { InternalStandardProps as StandardProps, Theme } from '..';
import { IconButtonProps, InternalStandardProps as StandardProps, SvgIconProps, Theme } from '..';
import { PaperProps } from '../Paper';
import { AlertClasses } from './alertClasses';

Expand Down Expand Up @@ -33,6 +33,23 @@ export interface AlertProps extends StandardProps<PaperProps, 'variant'> {
* [palette customization guide](https://mui.com/material-ui/customization/palette/#adding-new-colors).
*/
color?: OverridableStringUnion<AlertColor, AlertPropsColorOverrides>;
/**
* The components used for each slot inside the Alert.
* Either a string to use a HTML element or a component.
* @default {}
*/
components?: {
CloseButton?: React.ElementType;
CloseIcon?: React.ElementType;
};
/**
* The props used for each slot inside.
* @default {}
*/
componentsProps?: {
closeButton?: IconButtonProps;
closeIcon?: SvgIconProps;
};
/**
* The severity of the alert. This defines the color and icon used.
* @default 'success'
Expand Down
29 changes: 26 additions & 3 deletions packages/mui-material/src/Alert/Alert.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,8 @@ const Alert = React.forwardRef(function Alert(inProps, ref) {
className,
closeText = 'Close',
color,
components = {},
componentsProps = {},
icon,
iconMapping = defaultIconMapping,
onClose,
Expand All @@ -172,6 +174,9 @@ const Alert = React.forwardRef(function Alert(inProps, ref) {

const classes = useUtilityClasses(ownerState);

const AlertCloseButton = components.CloseButton ?? IconButton;
const AlertCloseIcon = components.CloseIcon ?? CloseIcon;

return (
<AlertRoot
role={role}
Expand All @@ -196,15 +201,16 @@ const Alert = React.forwardRef(function Alert(inProps, ref) {
) : null}
{action == null && onClose ? (
<AlertAction ownerState={ownerState} className={classes.action}>
<IconButton
<AlertCloseButton
size="small"
aria-label={closeText}
title={closeText}
color="inherit"
onClick={onClose}
{...componentsProps.closeButton}
>
<CloseIcon fontSize="small" />
</IconButton>
<AlertCloseIcon fontSize="small" {...componentsProps.closeIcon} />
</AlertCloseButton>
</AlertAction>
) : null}
</AlertRoot>
Expand Down Expand Up @@ -248,6 +254,23 @@ Alert.propTypes /* remove-proptypes */ = {
PropTypes.oneOf(['error', 'info', 'success', 'warning']),
PropTypes.string,
]),
/**
* The components used for each slot inside the Alert.
* Either a string to use a HTML element or a component.
* @default {}
*/
components: PropTypes.shape({
CloseButton: PropTypes.elementType,
CloseIcon: PropTypes.elementType,
}),
/**
* The props used for each slot inside.
* @default {}
*/
componentsProps: PropTypes.shape({
closeButton: PropTypes.object,
closeIcon: PropTypes.object,
}),
/**
* Override the icon displayed before the children.
* Unless provided, the icon is mapped to the value of the `severity` prop.
Expand Down
72 changes: 72 additions & 0 deletions packages/mui-material/src/Alert/Alert.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ import { createRenderer, describeConformance, screen } from 'test/utils';
import { ThemeProvider, createTheme } from '@mui/material/styles';
import Alert, { alertClasses as classes } from '@mui/material/Alert';
import Paper, { paperClasses } from '@mui/material/Paper';
import { iconButtonClasses } from '@mui/material/IconButton';
import { svgIconClasses } from '@mui/material/SvgIcon';

describe('<Alert />', () => {
const { render } = createRenderer();
Expand Down Expand Up @@ -64,4 +66,74 @@ describe('<Alert />', () => {
).not.to.throw();
});
});

describe('prop: components', () => {
it('should override the default icon used in the close action', () => {
const MyCloseIcon = () => <div data-testid="closeIcon">X</div>;

render(
<Alert onClose={() => {}} components={{ CloseIcon: MyCloseIcon }}>
Hello World
</Alert>,
);

expect(screen.getByTestId('closeIcon')).toBeVisible();
});

it('should override the default button used in the close action', () => {
const MyCloseButton = () => <button data-testid="closeButton">X</button>;

render(
<Alert onClose={() => {}} components={{ CloseButton: MyCloseButton }}>
Hello World
</Alert>,
);

expect(screen.getByTestId('closeButton')).toBeVisible();
});
});

describe('prop: componentsProps', () => {
it('should apply the props on the close IconButton component', () => {
render(
<Alert
onClose={() => {}}
componentsProps={{
closeButton: {
'data-testid': 'closeButton',
size: 'large',
className: 'my-class',
},
}}
>
Hello World
</Alert>,
);

const closeIcon = screen.getByTestId('closeButton');
expect(closeIcon).to.have.class(iconButtonClasses.sizeLarge);
expect(closeIcon).to.have.class('my-class');
});

it('should apply the props on the close SvgIcon component', () => {
render(
<Alert
onClose={() => {}}
componentsProps={{
closeIcon: {
'data-testid': 'closeIcon',
fontSize: 'large',
className: 'my-class',
},
}}
>
Hello World
</Alert>,
);

const closeIcon = screen.getByTestId('closeIcon');
expect(closeIcon).to.have.class(svgIconClasses.fontSizeLarge);
expect(closeIcon).to.have.class('my-class');
});
});
});

0 comments on commit 7c4aeff

Please sign in to comment.