-
-
- Overlap
-
- } label="Rectangle" />
- } label="Circle" />
-
-
-
-
+
+
+ {rectangle}
+
+
+ {rectangle}
+
+
+ {circle}
+
+
+ {circle}
+
);
}
diff --git a/docs/src/pages/components/badges/CustomizedBadges.js b/docs/src/pages/components/badges/CustomizedBadges.js
index f781d09a53152a..6071cca81b3589 100644
--- a/docs/src/pages/components/badges/CustomizedBadges.js
+++ b/docs/src/pages/components/badges/CustomizedBadges.js
@@ -1,89 +1,24 @@
import React from 'react';
import Badge from '@material-ui/core/Badge';
-import Box from '@material-ui/core/Box';
-import Avatar from '@material-ui/core/Avatar';
import { withStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
-const StyledBadge1 = withStyles(theme => ({
+const StyledBadge = withStyles(theme => ({
badge: {
right: -3,
+ top: 13,
border: `2px solid ${theme.palette.background.paper}`,
padding: '0 4px',
},
}))(Badge);
-const StyledBadge2 = withStyles(theme => ({
- badge: {
- backgroundColor: '#44b700',
- boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
- '&::after': {
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- borderRadius: '50%',
- animation: '$ripple 1.2s infinite ease-in-out',
- border: '1px solid #44b700',
- content: '""',
- },
- },
- '@keyframes ripple': {
- '0%': {
- transform: 'scale(.8)',
- opacity: 1,
- },
- '100%': {
- transform: 'scale(2.4)',
- opacity: 0,
- },
- },
-}))(Badge);
-
-const SmallAvatar = withStyles(theme => ({
- root: {
- width: 22,
- height: 22,
- border: `2px solid ${theme.palette.background.paper}`,
- },
-}))(Avatar);
-
export default function CustomizedBadges() {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- >
-
-
-
-
+
+
+
+
+
);
}
diff --git a/docs/src/pages/components/badges/CustomizedBadges.tsx b/docs/src/pages/components/badges/CustomizedBadges.tsx
index c28abe5d17e8ae..7da7ffe40155e5 100644
--- a/docs/src/pages/components/badges/CustomizedBadges.tsx
+++ b/docs/src/pages/components/badges/CustomizedBadges.tsx
@@ -1,95 +1,26 @@
import React from 'react';
import Badge from '@material-ui/core/Badge';
-import Box from '@material-ui/core/Box';
-import Avatar from '@material-ui/core/Avatar';
import { Theme, withStyles, createStyles } from '@material-ui/core/styles';
import IconButton from '@material-ui/core/IconButton';
import ShoppingCartIcon from '@material-ui/icons/ShoppingCart';
-const StyledBadge1 = withStyles((theme: Theme) =>
+const StyledBadge = withStyles((theme: Theme) =>
createStyles({
badge: {
right: -3,
+ top: 13,
border: `2px solid ${theme.palette.background.paper}`,
padding: '0 4px',
},
}),
)(Badge);
-const StyledBadge2 = withStyles((theme: Theme) =>
- createStyles({
- badge: {
- backgroundColor: '#44b700',
- boxShadow: `0 0 0 2px ${theme.palette.background.paper}`,
- '&::after': {
- position: 'absolute',
- top: 0,
- left: 0,
- width: '100%',
- height: '100%',
- borderRadius: '50%',
- animation: '$ripple 1.2s infinite ease-in-out',
- border: '1px solid #44b700',
- content: '""',
- },
- },
- '@keyframes ripple': {
- '0%': {
- transform: 'scale(.8)',
- opacity: 1,
- },
- '100%': {
- transform: 'scale(2.4)',
- opacity: 0,
- },
- },
- }),
-)(Badge);
-
-const SmallAvatar = withStyles((theme: Theme) =>
- createStyles({
- root: {
- width: 22,
- height: 22,
- border: `2px solid ${theme.palette.background.paper}`,
- },
- }),
-)(Avatar);
-
export default function CustomizedBadges() {
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
- >
-
-
-
-
+
+
+
+
+
);
}
diff --git a/docs/src/pages/components/badges/DotBadge.js b/docs/src/pages/components/badges/DotBadge.js
index 16558e3b2eec00..bcc6604b2ed4a5 100644
--- a/docs/src/pages/components/badges/DotBadge.js
+++ b/docs/src/pages/components/badges/DotBadge.js
@@ -1,27 +1,31 @@
import React from 'react';
-import Box from '@material-ui/core/Box';
+import { makeStyles } from '@material-ui/core/styles';
import Badge from '@material-ui/core/Badge';
import MailIcon from '@material-ui/icons/Mail';
import Typography from '@material-ui/core/Typography';
+const useStyles = makeStyles(theme => ({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+}));
+
export default function DotBadge() {
+ const classes = useStyles();
+
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- Typography
-
-
-
+
+
+
+
+
+
+
+
+ Typography
+
+
);
}
diff --git a/docs/src/pages/components/badges/DotBadge.tsx b/docs/src/pages/components/badges/DotBadge.tsx
index 16558e3b2eec00..dcc4d242435622 100644
--- a/docs/src/pages/components/badges/DotBadge.tsx
+++ b/docs/src/pages/components/badges/DotBadge.tsx
@@ -1,27 +1,33 @@
import React from 'react';
-import Box from '@material-ui/core/Box';
+import { makeStyles, createStyles, Theme } from '@material-ui/core/styles';
import Badge from '@material-ui/core/Badge';
import MailIcon from '@material-ui/icons/Mail';
import Typography from '@material-ui/core/Typography';
+const useStyles = makeStyles((theme: Theme) =>
+ createStyles({
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
+ },
+ }),
+);
+
export default function DotBadge() {
+ const classes = useStyles();
+
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
- Typography
-
-
-
+
+
+
+
+
+
+
+
+ Typography
+
+
);
}
diff --git a/docs/src/pages/components/badges/SimpleBadge.js b/docs/src/pages/components/badges/SimpleBadge.js
index 58476cb4012075..d0dfad7cd61b9c 100644
--- a/docs/src/pages/components/badges/SimpleBadge.js
+++ b/docs/src/pages/components/badges/SimpleBadge.js
@@ -3,18 +3,12 @@ import { makeStyles } from '@material-ui/core/styles';
import Badge from '@material-ui/core/Badge';
import IconButton from '@material-ui/core/IconButton';
import MailIcon from '@material-ui/icons/Mail';
-import AppBar from '@material-ui/core/AppBar';
-import Tabs from '@material-ui/core/Tabs';
-import Tab from '@material-ui/core/Tab';
-import Typography from '@material-ui/core/Typography';
-import Button from '@material-ui/core/Button';
const useStyles = makeStyles(theme => ({
- margin: {
- margin: theme.spacing(2),
- },
- padding: {
- padding: theme.spacing(0, 2),
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
},
}));
@@ -22,39 +16,18 @@ export default function SimpleBadge() {
const classes = useStyles();
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Item One
-
- }
- />
-
-
-
-
-
- Typography
+
+
+
-
- Button
+
+
+
+
+
+
+
);
}
diff --git a/docs/src/pages/components/badges/SimpleBadge.tsx b/docs/src/pages/components/badges/SimpleBadge.tsx
index 9a47471350eea1..3ed7f2aed2596f 100644
--- a/docs/src/pages/components/badges/SimpleBadge.tsx
+++ b/docs/src/pages/components/badges/SimpleBadge.tsx
@@ -3,19 +3,13 @@ import { makeStyles, Theme, createStyles } from '@material-ui/core/styles';
import Badge from '@material-ui/core/Badge';
import IconButton from '@material-ui/core/IconButton';
import MailIcon from '@material-ui/icons/Mail';
-import AppBar from '@material-ui/core/AppBar';
-import Tabs from '@material-ui/core/Tabs';
-import Tab from '@material-ui/core/Tab';
-import Typography from '@material-ui/core/Typography';
-import Button from '@material-ui/core/Button';
const useStyles = makeStyles((theme: Theme) =>
createStyles({
- margin: {
- margin: theme.spacing(2),
- },
- padding: {
- padding: theme.spacing(0, 2),
+ root: {
+ '& > *': {
+ margin: theme.spacing(1),
+ },
},
}),
);
@@ -24,39 +18,18 @@ export default function SimpleBadge() {
const classes = useStyles();
return (
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Item One
-
- }
- />
-
-
-
-
-
- Typography
+
+
+
-
- Button
+
+
+
+
+
+
+
);
}
diff --git a/docs/src/pages/components/badges/badges.md b/docs/src/pages/components/badges/badges.md
index fa68eec06546c7..69a1c6e50712e6 100644
--- a/docs/src/pages/components/badges/badges.md
+++ b/docs/src/pages/components/badges/badges.md
@@ -15,7 +15,7 @@ Examples of badges containing text, using primary and secondary colors. The badg
## Customized badges
-Here are some examples of customizing the component. You can learn more about this in the [overrides documentation page](/customization/components/).
+Here is an example of customizing the component. You can learn more about this in the [overrides documentation page](/customization/components/).
{{"demo": "pages/components/badges/CustomizedBadges.js"}}
@@ -49,4 +49,4 @@ You can use the `overlap` property to place the badge relative to the corner of
You can use the `horizontalAlignment` and `verticalAlignment` properties to move the badge to any corner of the wrapped element.
-{{"demo": "pages/components/badges/BadgeAlignment.js"}}
+{{"demo": "pages/components/badges/BadgeAlignment.js", "hideHeader": true}}
diff --git a/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.d.ts b/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.d.ts
new file mode 100644
index 00000000000000..2d2e7065d971e1
--- /dev/null
+++ b/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.d.ts
@@ -0,0 +1,14 @@
+import * as React from 'react';
+import { StandardProps } from '@material-ui/core';
+
+export interface AvatarGroupProps
+ extends StandardProps, AvatarGroupClassKey> {
+ /**
+ * The avatars to stack.
+ */
+ children: React.ReactNode;
+}
+
+export type AvatarGroupClassKey = 'root' | 'avatar';
+
+export default function AvatarGroup(props: AvatarGroupProps): JSX.Element | null;
diff --git a/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.js b/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.js
new file mode 100644
index 00000000000000..016441e475b9ed
--- /dev/null
+++ b/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.js
@@ -0,0 +1,72 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { isFragment } from 'react-is';
+import clsx from 'clsx';
+import { withStyles } from '@material-ui/core/styles';
+
+export const styles = theme => ({
+ /* Styles applied to the root element. */
+ root: {
+ display: 'flex',
+ },
+ /* Styles applied to the avatar elements. */
+ avatar: {
+ border: `2px solid ${theme.palette.background.default}`,
+ marginLeft: -8,
+ },
+});
+
+const AvatarGroup = React.forwardRef(function AvatarGroup(props, ref) {
+ const { children: childrenProp, classes, className, ...other } = props;
+
+ const children = React.Children.toArray(childrenProp).filter(child => {
+ if (process.env.NODE_ENV !== 'production') {
+ if (isFragment(child)) {
+ console.error(
+ [
+ "Material-UI: the AvatarGroup component doesn't accept a Fragment as a child.",
+ 'Consider providing an array instead.',
+ ].join('\n'),
+ );
+ }
+ }
+
+ return React.isValidElement(child);
+ });
+
+ return (
+
+ {children.map((child, index) => {
+ return React.cloneElement(child, {
+ className: clsx(child.props.className, classes.avatar),
+ style: {
+ zIndex: children.length - index,
+ ...child.props.style,
+ },
+ });
+ })}
+
+ );
+});
+
+AvatarGroup.propTypes = {
+ // ----------------------------- Warning --------------------------------
+ // | These PropTypes are generated from the TypeScript type definitions |
+ // | To update them edit the d.ts file and run "yarn proptypes" |
+ // ----------------------------------------------------------------------
+ /**
+ * The avatars to stack.
+ */
+ children: PropTypes.node,
+ /**
+ * Override or extend the styles applied to the component.
+ * See [CSS API](#css) below for more details.
+ */
+ classes: PropTypes.object,
+ /**
+ * @ignore
+ */
+ className: PropTypes.string,
+};
+
+export default withStyles(styles, { name: 'MuiAvatarGroup' })(AvatarGroup);
diff --git a/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.test.js b/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.test.js
new file mode 100644
index 00000000000000..135ed703ad6962
--- /dev/null
+++ b/packages/material-ui-lab/src/AvatarGroup/AvatarGroup.test.js
@@ -0,0 +1,26 @@
+import React from 'react';
+import { createMount, getClasses } from '@material-ui/core/test-utils';
+import describeConformance from '@material-ui/core/test-utils/describeConformance';
+import AvatarGroup from './AvatarGroup';
+
+describe(' ', () => {
+ let mount;
+ let classes;
+
+ before(() => {
+ mount = createMount({ strict: true });
+ classes = getClasses( );
+ });
+
+ after(() => {
+ mount.cleanUp();
+ });
+
+ describeConformance( , () => ({
+ classes,
+ inheritComponent: 'div',
+ mount,
+ refInstanceof: window.HTMLDivElement,
+ skip: ['componentProp'],
+ }));
+});
diff --git a/packages/material-ui-lab/src/AvatarGroup/index.d.ts b/packages/material-ui-lab/src/AvatarGroup/index.d.ts
new file mode 100644
index 00000000000000..a691e2cb2eff92
--- /dev/null
+++ b/packages/material-ui-lab/src/AvatarGroup/index.d.ts
@@ -0,0 +1,2 @@
+export { default } from './AvatarGroup';
+export * from './AvatarGroup';
diff --git a/packages/material-ui-lab/src/AvatarGroup/index.js b/packages/material-ui-lab/src/AvatarGroup/index.js
new file mode 100644
index 00000000000000..20c5443b297112
--- /dev/null
+++ b/packages/material-ui-lab/src/AvatarGroup/index.js
@@ -0,0 +1 @@
+export { default } from './AvatarGroup';
diff --git a/packages/material-ui-lab/src/index.d.ts b/packages/material-ui-lab/src/index.d.ts
index 8016e0cc3c094f..c39dc2b6a1545b 100644
--- a/packages/material-ui-lab/src/index.d.ts
+++ b/packages/material-ui-lab/src/index.d.ts
@@ -1,6 +1,9 @@
export { default as Autocomplete } from './Autocomplete';
export * from './Autocomplete';
+export { default as AvatarGroup } from './AvatarGroup';
+export * from './AvatarGroup';
+
export { default as Rating } from './Rating';
export * from './Rating';
diff --git a/packages/material-ui-lab/src/index.js b/packages/material-ui-lab/src/index.js
index 42ffe2284d6874..4014dcac7ca134 100644
--- a/packages/material-ui-lab/src/index.js
+++ b/packages/material-ui-lab/src/index.js
@@ -2,6 +2,9 @@
export { default as Autocomplete } from './Autocomplete';
export * from './Autocomplete';
+export { default as AvatarGroup } from './AvatarGroup';
+export * from './AvatarGroup';
+
export { default as Rating } from './Rating';
export * from './Rating';
diff --git a/packages/material-ui/src/Badge/Badge.js b/packages/material-ui/src/Badge/Badge.js
index 0027b6602c29a4..cf1fcef48e5a8e 100644
--- a/packages/material-ui/src/Badge/Badge.js
+++ b/packages/material-ui/src/Badge/Badge.js
@@ -5,7 +5,7 @@ import withStyles from '../styles/withStyles';
import capitalize from '../utils/capitalize';
const RADIUS_STANDARD = 10;
-const RADIUS_DOT = 3;
+const RADIUS_DOT = 4;
export const styles = theme => ({
/* Styles applied to the root element. */
@@ -34,8 +34,6 @@ export const styles = theme => ({
padding: '0 6px',
height: RADIUS_STANDARD * 2,
borderRadius: RADIUS_STANDARD,
- backgroundColor: theme.palette.color,
- color: theme.palette.textColor,
zIndex: 1, // Render the badge on top of potential ripples.
transition: theme.transitions.create('transform', {
easing: theme.transitions.easing.easeInOut,
@@ -59,6 +57,7 @@ export const styles = theme => ({
},
/* Styles applied to the root element if `variant="dot"`. */
dot: {
+ borderRadius: RADIUS_DOT,
height: RADIUS_DOT * 2,
minWidth: RADIUS_DOT * 2,
padding: 0,
diff --git a/test/regressions/index.js b/test/regressions/index.js
index cb5cdc818bac05..9b5559e544b5d4 100644
--- a/test/regressions/index.js
+++ b/test/regressions/index.js
@@ -82,6 +82,7 @@ const blacklistFilename = [
'docs-components-tree-view/CustomizedTreeView.png',
// Redux isolation
+ 'docs-components-badges/BadgeAlignment.png',
'docs-components-chips/ChipsPlayground.png',
'docs-components-popover/AnchorPlayground.png',
'docs-components-popper/ScrollPlayground.png',