Skip to content

Commit a7a2901

Browse files
[Alert] Add components and componentsProps props to allow close action overrides (mui#33582)
1 parent b7123a9 commit a7a2901

File tree

5 files changed

+129
-4
lines changed

5 files changed

+129
-4
lines changed

docs/pages/material-ui/api/alert.json

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@
1010
"description": "'error'<br>&#124;&nbsp;'info'<br>&#124;&nbsp;'success'<br>&#124;&nbsp;'warning'<br>&#124;&nbsp;string"
1111
}
1212
},
13+
"components": {
14+
"type": {
15+
"name": "shape",
16+
"description": "{ CloseButton?: elementType, CloseIcon?: elementType }"
17+
},
18+
"default": "{}"
19+
},
20+
"componentsProps": {
21+
"type": { "name": "shape", "description": "{ closeButton?: object, closeIcon?: object }" },
22+
"default": "{}"
23+
},
1324
"icon": { "type": { "name": "node" } },
1425
"iconMapping": {
1526
"type": {

docs/translations/api-docs/alert/alert.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66
"classes": "Override or extend the styles applied to the component. See <a href=\"#css\">CSS API</a> below for more details.",
77
"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>.",
88
"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>.",
9+
"components": "The components used for each slot inside the Alert. Either a string to use a HTML element or a component.",
10+
"componentsProps": "The props used for each slot inside.",
911
"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>.",
1012
"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.",
1113
"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.",

packages/mui-material/src/Alert/Alert.d.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import * as React from 'react';
22
import { OverridableStringUnion } from '@mui/types';
33
import { SxProps } from '@mui/system';
4-
import { InternalStandardProps as StandardProps, Theme } from '..';
4+
import { IconButtonProps, InternalStandardProps as StandardProps, SvgIconProps, Theme } from '..';
55
import { PaperProps } from '../Paper';
66
import { AlertClasses } from './alertClasses';
77

@@ -33,6 +33,23 @@ export interface AlertProps extends StandardProps<PaperProps, 'variant'> {
3333
* [palette customization guide](https://mui.com/material-ui/customization/palette/#adding-new-colors).
3434
*/
3535
color?: OverridableStringUnion<AlertColor, AlertPropsColorOverrides>;
36+
/**
37+
* The components used for each slot inside the Alert.
38+
* Either a string to use a HTML element or a component.
39+
* @default {}
40+
*/
41+
components?: {
42+
CloseButton?: React.ElementType;
43+
CloseIcon?: React.ElementType;
44+
};
45+
/**
46+
* The props used for each slot inside.
47+
* @default {}
48+
*/
49+
componentsProps?: {
50+
closeButton?: IconButtonProps;
51+
closeIcon?: SvgIconProps;
52+
};
3653
/**
3754
* The severity of the alert. This defines the color and icon used.
3855
* @default 'success'

packages/mui-material/src/Alert/Alert.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ const Alert = React.forwardRef(function Alert(inProps, ref) {
154154
className,
155155
closeText = 'Close',
156156
color,
157+
components = {},
158+
componentsProps = {},
157159
icon,
158160
iconMapping = defaultIconMapping,
159161
onClose,
@@ -172,6 +174,9 @@ const Alert = React.forwardRef(function Alert(inProps, ref) {
172174

173175
const classes = useUtilityClasses(ownerState);
174176

177+
const AlertCloseButton = components.CloseButton ?? IconButton;
178+
const AlertCloseIcon = components.CloseIcon ?? CloseIcon;
179+
175180
return (
176181
<AlertRoot
177182
role={role}
@@ -196,15 +201,16 @@ const Alert = React.forwardRef(function Alert(inProps, ref) {
196201
) : null}
197202
{action == null && onClose ? (
198203
<AlertAction ownerState={ownerState} className={classes.action}>
199-
<IconButton
204+
<AlertCloseButton
200205
size="small"
201206
aria-label={closeText}
202207
title={closeText}
203208
color="inherit"
204209
onClick={onClose}
210+
{...componentsProps.closeButton}
205211
>
206-
<CloseIcon fontSize="small" />
207-
</IconButton>
212+
<AlertCloseIcon fontSize="small" {...componentsProps.closeIcon} />
213+
</AlertCloseButton>
208214
</AlertAction>
209215
) : null}
210216
</AlertRoot>
@@ -248,6 +254,23 @@ Alert.propTypes /* remove-proptypes */ = {
248254
PropTypes.oneOf(['error', 'info', 'success', 'warning']),
249255
PropTypes.string,
250256
]),
257+
/**
258+
* The components used for each slot inside the Alert.
259+
* Either a string to use a HTML element or a component.
260+
* @default {}
261+
*/
262+
components: PropTypes.shape({
263+
CloseButton: PropTypes.elementType,
264+
CloseIcon: PropTypes.elementType,
265+
}),
266+
/**
267+
* The props used for each slot inside.
268+
* @default {}
269+
*/
270+
componentsProps: PropTypes.shape({
271+
closeButton: PropTypes.object,
272+
closeIcon: PropTypes.object,
273+
}),
251274
/**
252275
* Override the icon displayed before the children.
253276
* Unless provided, the icon is mapped to the value of the `severity` prop.

packages/mui-material/src/Alert/Alert.test.js

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ import { createRenderer, describeConformance, screen } from 'test/utils';
44
import { ThemeProvider, createTheme } from '@mui/material/styles';
55
import Alert, { alertClasses as classes } from '@mui/material/Alert';
66
import Paper, { paperClasses } from '@mui/material/Paper';
7+
import { iconButtonClasses } from '@mui/material/IconButton';
8+
import { svgIconClasses } from '@mui/material/SvgIcon';
79

810
describe('<Alert />', () => {
911
const { render } = createRenderer();
@@ -64,4 +66,74 @@ describe('<Alert />', () => {
6466
).not.to.throw();
6567
});
6668
});
69+
70+
describe('prop: components', () => {
71+
it('should override the default icon used in the close action', () => {
72+
const MyCloseIcon = () => <div data-testid="closeIcon">X</div>;
73+
74+
render(
75+
<Alert onClose={() => {}} components={{ CloseIcon: MyCloseIcon }}>
76+
Hello World
77+
</Alert>,
78+
);
79+
80+
expect(screen.getByTestId('closeIcon')).toBeVisible();
81+
});
82+
83+
it('should override the default button used in the close action', () => {
84+
const MyCloseButton = () => <button data-testid="closeButton">X</button>;
85+
86+
render(
87+
<Alert onClose={() => {}} components={{ CloseButton: MyCloseButton }}>
88+
Hello World
89+
</Alert>,
90+
);
91+
92+
expect(screen.getByTestId('closeButton')).toBeVisible();
93+
});
94+
});
95+
96+
describe('prop: componentsProps', () => {
97+
it('should apply the props on the close IconButton component', () => {
98+
render(
99+
<Alert
100+
onClose={() => {}}
101+
componentsProps={{
102+
closeButton: {
103+
'data-testid': 'closeButton',
104+
size: 'large',
105+
className: 'my-class',
106+
},
107+
}}
108+
>
109+
Hello World
110+
</Alert>,
111+
);
112+
113+
const closeIcon = screen.getByTestId('closeButton');
114+
expect(closeIcon).to.have.class(iconButtonClasses.sizeLarge);
115+
expect(closeIcon).to.have.class('my-class');
116+
});
117+
118+
it('should apply the props on the close SvgIcon component', () => {
119+
render(
120+
<Alert
121+
onClose={() => {}}
122+
componentsProps={{
123+
closeIcon: {
124+
'data-testid': 'closeIcon',
125+
fontSize: 'large',
126+
className: 'my-class',
127+
},
128+
}}
129+
>
130+
Hello World
131+
</Alert>,
132+
);
133+
134+
const closeIcon = screen.getByTestId('closeIcon');
135+
expect(closeIcon).to.have.class(svgIconClasses.fontSizeLarge);
136+
expect(closeIcon).to.have.class('my-class');
137+
});
138+
});
67139
});

0 commit comments

Comments
 (0)