Skip to content

Commit daf32c0

Browse files
committed
[SnackbarContent][Material You] copy SnackbarContent files to the material-next
1 parent 64c48b5 commit daf32c0

File tree

7 files changed

+278
-0
lines changed

7 files changed

+278
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import * as React from 'react';
2+
import { SxProps } from '@mui/system';
3+
import { InternalStandardProps as StandardProps, PaperProps, Theme } from '@mui/material';
4+
import { SnackbarContentClasses } from './snackbarContentClasses';
5+
6+
export interface SnackbarContentProps extends StandardProps<PaperProps, 'children'> {
7+
/**
8+
* The action to display. It renders after the message, at the end of the snackbar.
9+
*/
10+
action?: React.ReactNode;
11+
/**
12+
* Override or extend the styles applied to the component.
13+
*/
14+
classes?: Partial<SnackbarContentClasses>;
15+
/**
16+
* The message to display.
17+
*/
18+
message?: React.ReactNode;
19+
/**
20+
* The ARIA role attribute of the element.
21+
* @default 'alert'
22+
*/
23+
role?: PaperProps['role'];
24+
/**
25+
* The system prop that allows defining system overrides as well as additional CSS styles.
26+
*/
27+
sx?: SxProps<Theme>;
28+
}
29+
30+
/**
31+
*
32+
* Demos:
33+
*
34+
* - [Snackbar](https://mui.com/material-ui/react-snackbar/)
35+
*
36+
* API:
37+
*
38+
* - [SnackbarContent API](https://mui.com/material-ui/api/snackbar-content/)
39+
* - inherits [Paper API](https://mui.com/material-ui/api/paper/)
40+
*/
41+
export default function SnackbarContent(props: SnackbarContentProps): JSX.Element;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
'use client';
2+
import * as React from 'react';
3+
import PropTypes from 'prop-types';
4+
import clsx from 'clsx';
5+
import { unstable_composeClasses as composeClasses } from '@mui/base/composeClasses';
6+
import { emphasize } from '@mui/system';
7+
import styled from '@mui/material/styles/styled';
8+
import useThemeProps from '@mui/material/styles/useThemeProps';
9+
import Paper from '@mui/material/Paper';
10+
import { getSnackbarContentUtilityClass } from './snackbarContentClasses';
11+
12+
const useUtilityClasses = (ownerState) => {
13+
const { classes } = ownerState;
14+
15+
const slots = {
16+
root: ['root'],
17+
action: ['action'],
18+
message: ['message'],
19+
};
20+
21+
return composeClasses(slots, getSnackbarContentUtilityClass, classes);
22+
};
23+
24+
const SnackbarContentRoot = styled(Paper, {
25+
name: 'MuiSnackbarContent',
26+
slot: 'Root',
27+
overridesResolver: (props, styles) => styles.root,
28+
})(({ theme }) => {
29+
const emphasis = theme.palette.mode === 'light' ? 0.8 : 0.98;
30+
const backgroundColor = emphasize(theme.palette.background.default, emphasis);
31+
32+
return {
33+
...theme.typography.body2,
34+
color: theme.vars
35+
? theme.vars.palette.SnackbarContent.color
36+
: theme.palette.getContrastText(backgroundColor),
37+
backgroundColor: theme.vars ? theme.vars.palette.SnackbarContent.bg : backgroundColor,
38+
display: 'flex',
39+
alignItems: 'center',
40+
flexWrap: 'wrap',
41+
padding: '6px 16px',
42+
borderRadius: (theme.vars || theme).shape.borderRadius,
43+
flexGrow: 1,
44+
[theme.breakpoints.up('sm')]: {
45+
flexGrow: 'initial',
46+
minWidth: 288,
47+
},
48+
};
49+
});
50+
51+
const SnackbarContentMessage = styled('div', {
52+
name: 'MuiSnackbarContent',
53+
slot: 'Message',
54+
overridesResolver: (props, styles) => styles.message,
55+
})({
56+
padding: '8px 0',
57+
});
58+
59+
const SnackbarContentAction = styled('div', {
60+
name: 'MuiSnackbarContent',
61+
slot: 'Action',
62+
overridesResolver: (props, styles) => styles.action,
63+
})({
64+
display: 'flex',
65+
alignItems: 'center',
66+
marginLeft: 'auto',
67+
paddingLeft: 16,
68+
marginRight: -8,
69+
});
70+
71+
const SnackbarContent = React.forwardRef(function SnackbarContent(inProps, ref) {
72+
const props = useThemeProps({ props: inProps, name: 'MuiSnackbarContent' });
73+
const { action, className, message, role = 'alert', ...other } = props;
74+
const ownerState = props;
75+
const classes = useUtilityClasses(ownerState);
76+
77+
return (
78+
<SnackbarContentRoot
79+
role={role}
80+
square
81+
elevation={6}
82+
className={clsx(classes.root, className)}
83+
ownerState={ownerState}
84+
ref={ref}
85+
{...other}
86+
>
87+
<SnackbarContentMessage className={classes.message} ownerState={ownerState}>
88+
{message}
89+
</SnackbarContentMessage>
90+
{action ? (
91+
<SnackbarContentAction className={classes.action} ownerState={ownerState}>
92+
{action}
93+
</SnackbarContentAction>
94+
) : null}
95+
</SnackbarContentRoot>
96+
);
97+
});
98+
99+
SnackbarContent.propTypes /* remove-proptypes */ = {
100+
// ----------------------------- Warning --------------------------------
101+
// | These PropTypes are generated from the TypeScript type definitions |
102+
// | To update them edit the d.ts file and run "yarn proptypes" |
103+
// ----------------------------------------------------------------------
104+
/**
105+
* The action to display. It renders after the message, at the end of the snackbar.
106+
*/
107+
action: PropTypes.node,
108+
/**
109+
* Override or extend the styles applied to the component.
110+
*/
111+
classes: PropTypes.object,
112+
/**
113+
* @ignore
114+
*/
115+
className: PropTypes.string,
116+
/**
117+
* The message to display.
118+
*/
119+
message: PropTypes.node,
120+
/**
121+
* The ARIA role attribute of the element.
122+
* @default 'alert'
123+
*/
124+
role: PropTypes /* @typescript-to-proptypes-ignore */.string,
125+
/**
126+
* The system prop that allows defining system overrides as well as additional CSS styles.
127+
*/
128+
sx: PropTypes.oneOfType([
129+
PropTypes.arrayOf(PropTypes.oneOfType([PropTypes.func, PropTypes.object, PropTypes.bool])),
130+
PropTypes.func,
131+
PropTypes.object,
132+
]),
133+
};
134+
135+
export default SnackbarContent;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
import * as React from 'react';
2+
import { expect } from 'chai';
3+
import { createRenderer, describeConformance } from '@mui-internal/test-utils';
4+
import Paper from '@mui/material/Paper';
5+
import SnackbarContent, {
6+
snackbarContentClasses as classes,
7+
} from '@mui/material-next/SnackbarContent';
8+
9+
describe('<SnackbarContent />', () => {
10+
const { render } = createRenderer();
11+
12+
describeConformance(<SnackbarContent message="conform?" />, () => ({
13+
classes,
14+
inheritComponent: Paper,
15+
render,
16+
muiName: 'MuiSnackbarContent',
17+
refInstanceof: window.HTMLDivElement,
18+
skip: ['componentProp', 'componentsProp', 'themeVariants'],
19+
}));
20+
21+
describe('prop: action', () => {
22+
it('should render the action', () => {
23+
const action = <span>action</span>;
24+
const { container } = render(
25+
<SnackbarContent message="message" data-testid="action" action={action} />,
26+
);
27+
expect(container.querySelector(`.${classes.action}`)).to.have.class(classes.action);
28+
expect(container.querySelector(`.${classes.action}`)).to.contain('span');
29+
});
30+
31+
it('should render an array of elements', () => {
32+
const action0 = <span key={0}>action0</span>;
33+
const action1 = <span key={1}>action1</span>;
34+
const { getByText } = render(
35+
<SnackbarContent message="message" action={[action0, action1]} />,
36+
);
37+
expect(getByText('action0')).not.to.equal(null);
38+
expect(getByText('action1')).not.to.equal(null);
39+
});
40+
});
41+
42+
describe('prop: message', () => {
43+
it('should render the message', () => {
44+
const message = 'message prop text';
45+
const { getByRole } = render(<SnackbarContent message={<span>{message}</span>} />);
46+
expect(getByRole('alert')).to.have.text(message);
47+
});
48+
});
49+
50+
describe('prop: role', () => {
51+
it('renders the default role', () => {
52+
const { getByRole } = render(<SnackbarContent message="alert message" />);
53+
expect(getByRole('alert')).to.have.text('alert message');
54+
});
55+
56+
it('can override the role', () => {
57+
const { queryByRole } = render(
58+
<SnackbarContent message="alertdialog message" role="alertdialog" />,
59+
);
60+
expect(queryByRole('alertdialog')).to.have.text('alertdialog message');
61+
});
62+
});
63+
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export { default } from './SnackbarContent';
2+
export * from './SnackbarContent';
3+
4+
export { default as snackbarContentClasses } from './snackbarContentClasses';
5+
export * from './snackbarContentClasses';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
'use client';
2+
export { default } from './SnackbarContent';
3+
4+
export { default as snackbarContentClasses } from './snackbarContentClasses';
5+
export * from './snackbarContentClasses';
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import {
2+
unstable_generateUtilityClasses as generateUtilityClasses,
3+
unstable_generateUtilityClass as generateUtilityClass,
4+
} from '@mui/utils';
5+
6+
export interface SnackbarContentClasses {
7+
/** Styles applied to the root element. */
8+
root: string;
9+
/** Styles applied to the message wrapper element. */
10+
message: string;
11+
/** Styles applied to the action wrapper element if `action` is provided. */
12+
action: string;
13+
}
14+
15+
export type SnackbarContentClassKey = keyof SnackbarContentClasses;
16+
17+
export function getSnackbarContentUtilityClass(slot: string): string {
18+
return generateUtilityClass('MuiSnackbarContent', slot);
19+
}
20+
21+
const snackbarContentClasses: SnackbarContentClasses = generateUtilityClasses(
22+
'MuiSnackbarContent',
23+
['root', 'message', 'action'],
24+
);
25+
26+
export default snackbarContentClasses;

packages/mui-material-next/src/index.ts

+3
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,9 @@ export * from './Select';
4747
export { default as Slider } from './Slider';
4848
export * from './Slider';
4949

50+
export { default as SnackbarContent } from './SnackbarContent';
51+
export * from './SnackbarContent';
52+
5053
export { default as Divider } from './Divider';
5154
export * from './Divider';
5255

0 commit comments

Comments
 (0)