diff --git a/docs/api/Badge/Badge.md b/docs/api/Badge/Badge.md new file mode 100644 index 00000000000000..f0cf3808cec141 --- /dev/null +++ b/docs/api/Badge/Badge.md @@ -0,0 +1,18 @@ +Badge +====== + + + +Props +----- + +| Name | Type | Default | Description | +|:-----|:-----|:--------|:------------| +| accent | bool | false | If true, the badge will use the accent badge colors. | +| badgeClassName | string | | The CSS class name of the badge element. | +| badgeContent * | node | | This is the content rendered within the badge. | +| children * | node | | The node that the badge will be applied to. | +| className | string | | The CSS class name of the root element. | +| primary | bool | false | If true, the badge will use the primary badge colors. | + +Any other properties supplied will be spread to the root element. diff --git a/docs/site/src/demos/badges/SimpleBadge.js b/docs/site/src/demos/badges/SimpleBadge.js new file mode 100644 index 00000000000000..696f9fbb91022a --- /dev/null +++ b/docs/site/src/demos/badges/SimpleBadge.js @@ -0,0 +1,39 @@ +// @flow weak + +import React from 'react'; +import { createStyleSheet } from 'jss-theme-reactor'; +import Badge from 'material-ui/Badge'; +import customPropTypes from 'material-ui/utils/customPropTypes'; +import Icon from 'material-ui/Icon'; + +const styleSheet = createStyleSheet('SimpleBadge', () => ({ + badge: { + margin: '0 20px', + }, +})); + +export default function SimpleBadge(props, context) { + const classes = context.styleManager.render(styleSheet); + return ( +
+ + mail + + + folder + +
+ ); +} + +SimpleBadge.contextTypes = { + styleManager: customPropTypes.muiRequired, +}; diff --git a/docs/site/src/demos/badges/badges.md b/docs/site/src/demos/badges/badges.md new file mode 100644 index 00000000000000..068cbdb7ff6b02 --- /dev/null +++ b/docs/site/src/demos/badges/badges.md @@ -0,0 +1,10 @@ +# Badge + +Badge generates a small badge to the top-right of its child(ren). + +## Simple examples + +Two examples of badges containing text, using primary and secondary colors. The badge is applied to its children - an icon for the first example, and an Icon Button with tooltip for the second. + +{{demo='demos/badges/SimpleBadge.js'}} + diff --git a/src/Badge/Badge.js b/src/Badge/Badge.js new file mode 100644 index 00000000000000..b18d333269f72b --- /dev/null +++ b/src/Badge/Badge.js @@ -0,0 +1,113 @@ +// @flow weak + +import React, { PropTypes } from 'react'; +import classNames from 'classnames'; +import { createStyleSheet } from 'jss-theme-reactor'; +import customPropTypes from '../utils/customPropTypes'; + +const radius = 12; +const radius2x = 2 * radius; + +export const styleSheet = createStyleSheet('Badge', (theme) => { + const { typography, palette } = theme; + + return { + root: { + position: 'relative', + display: 'inline-block', + }, + badge: { + display: 'flex', + flexDirection: 'row', + flexWrap: 'wrap', + justifyContent: 'center', + alignContent: 'center', + alignItems: 'center', + position: 'absolute', + top: `-${radius}px`, + right: `-${radius}px`, + fontWeight: typography.fontWeight, + fontSize: radius, + width: radius2x, + height: radius2x, + borderRadius: '50%', + backgroundColor: palette.color, + color: palette.textColor, + }, + primary: { + backgroundColor: palette.primary[500], + color: palette.getContrastText(palette.primary[500]), + }, + accent: { + backgroundColor: palette.accent.A200, + color: palette.getContrastText(palette.accent.A200), + }, + }; +}); + +export default function Badge(props, context) { + const { + badgeClassName: badgeClassNameProp, + badgeContent, + className: classNameProp, + children, + primary, + accent, + ...other + } = props; + + const classes = context.styleManager.render(styleSheet); + const className = classNames({ + [classes.root]: true, + }, classNameProp); + const badgeClassName = classNames({ + [classes.badge]: true, + [classes.primary]: primary, + [classes.accent]: accent, + }, badgeClassNameProp); + + return ( +
+ {children} + + {badgeContent} + +
+ ); +} + +Badge.propTypes = { + /** + * If true, the badge will use the accent badge colors. + */ + accent: PropTypes.bool, + /** + * The css class name of the badge element. + */ + badgeClassName: PropTypes.string, + /** + * This is the content rendered within the badge. + */ + badgeContent: PropTypes.node.isRequired, + /** + * The badge will be added relativelty to this node. + */ + children: PropTypes.node.isRequired, + /** + * The css class name of the root element. + */ + className: PropTypes.string, + /** + * If true, the badge will use the primary badge colors. + */ + primary: PropTypes.bool, +}; + +Badge.defaultProps = { + primary: false, + accent: false, +}; + +Badge.contextTypes = { + styleManager: customPropTypes.muiRequired, +}; diff --git a/src/Badge/Badge.spec.js b/src/Badge/Badge.spec.js new file mode 100644 index 00000000000000..8583ad96423b7c --- /dev/null +++ b/src/Badge/Badge.spec.js @@ -0,0 +1,89 @@ +// @flow weak +/* eslint-env mocha */ +import React from 'react'; +import { createShallowWithContext } from 'test/utils'; +import { assert } from 'chai'; +import Badge, { styleSheet } from './Badge'; + +describe('', () => { + let shallow; + let classes; + + before(() => { + shallow = createShallowWithContext(); + classes = shallow.context.styleManager.render(styleSheet); + }); + + const testChildren =
Hello World
; + + it('renders children and badgeContent', () => { + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + assert.ok(wrapper.find('span').length, 'should contain the badgeContent'); + }); + + it('renders children and overwrite badge class', () => { + const badgeClassName = 'testBadgeClassName'; + + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + assert.strictEqual(wrapper.find('span').hasClass('testBadgeClassName'), true, + 'should contain the badgeClassName'); + }); + + it('renders children by default', () => { + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + }); + + it('renders children and className', () => { + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + assert.strictEqual(wrapper.is('.testClassName'), true, 'should contain the className'); + }); + + it('renders children and have primary styles', () => { + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + assert.strictEqual(wrapper.find('span').hasClass(classes.primary), true, + 'should have primary class'); + }); + + it('renders children and have accent styles', () => { + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + assert.strictEqual(wrapper.find('span').hasClass(classes.accent), true, + 'should have accent class'); + }); + + it('renders children and overwrite root styles', () => { + const style = { + backgroundColor: 'red', + }; + const wrapper = shallow( + {testChildren}, + ); + + assert.strictEqual(wrapper.contains(testChildren), true, 'should contain the children'); + assert.strictEqual(wrapper.node.props.style.backgroundColor, style.backgroundColor, + 'should overwrite badge backgroundColor'); + }); +}); diff --git a/src/Badge/index.js b/src/Badge/index.js new file mode 100644 index 00000000000000..40b8b2acdc3ba9 --- /dev/null +++ b/src/Badge/index.js @@ -0,0 +1,3 @@ +/* eslint-disable flowtype/require-valid-file-annotation */ + +export default from './Badge'; diff --git a/test/regressions/site/src/tests/Badge/Badge.js b/test/regressions/site/src/tests/Badge/Badge.js new file mode 100644 index 00000000000000..d680b36a7b2518 --- /dev/null +++ b/test/regressions/site/src/tests/Badge/Badge.js @@ -0,0 +1,13 @@ +// @flow weak + +import React from 'react'; +import Badge from 'material-ui/Badge'; +import Icon from 'material-ui/Icon'; + +export default function SimpleBadge() { + return ( + + mail + + ); +}