diff --git a/docs/components/Layout/index.jsx b/docs/components/Layout/index.jsx index 614263461..5be3f98bb 100644 --- a/docs/components/Layout/index.jsx +++ b/docs/components/Layout/index.jsx @@ -29,6 +29,7 @@ import FlexibleSpacerExample from '../../examples/FlexibleSpacerExample'; import PageTitleExample from '../../examples/PageTitleExample'; import SliceyExample from '../../examples/SliceyExample'; import StatisticExample from '../../examples/StatisticExample'; +import StatusPillExample from '../../examples/StatusPillExample'; import TagExample from '../../examples/TagExample'; import TotalsExample from '../../examples/TotalsExample'; import AvatarExample from '../../examples/AvatarExample'; @@ -90,7 +91,7 @@ const componentsBySection = { 'stats-and-data': ['count-badge', 'statistic', 'totals', 'slicey'], 'icons-and-graphics': ['svg-symbol', 'svg-symbol-circle'], navigation: ['breadcrumb', 'tab', 'hover-dropdown-menu', 'navigation-tabs'], - 'feedback-and-states': ['alert', 'empty', 'spinner', 'pretty-diff'], + 'feedback-and-states': ['alert', 'empty', 'spinner', 'pretty-diff', 'status-pill'], dialogue: ['popover', 'help-icon-popover', 'avatar'], modals: ['confirm-modal'], search: ['search', 'search-bar', 'tag'], @@ -210,6 +211,7 @@ class PageLayout extends React.Component { + diff --git a/docs/examples/StatusPillExample.jsx b/docs/examples/StatusPillExample.jsx new file mode 100644 index 000000000..d743d1ce4 --- /dev/null +++ b/docs/examples/StatusPillExample.jsx @@ -0,0 +1,84 @@ +import React from 'react'; +import Example from '../components/Example'; +import { StatusPill } from '../../src'; + +class StatusPillExample extends React.PureComponent { + render() { + return ( + <> + +
+ + + + + +
+
+ +
+ + + + + +
+ + ); + } +} + +const exampleProps = { + componentName: 'Status Pill', + notes: '', + exampleCodeSnippet: ` + + + + + + + + + + + + + + + `, + propTypeSectionArray: [ + { + propTypes: [ + { + propType: 'status', + type: 'string', + note: 'Text inside status pill', + }, + { + propType: 'displayStyle', + type: 'string', + note: 'one of ["primary", "success", "warning", "error", "light"]', + defaultValue: 'primary', + }, + { + propType: 'inverse', + type: 'boolean', + note: 'Status pill with inverse style', + defaultValue: 'false', + }, + { + propType: 'dts', + type: 'string', + note: 'Generate "data-test-selector" on the status pill', + }, + ], + }, + ], +}; + +export default () => ( + + + +); diff --git a/docs/examples/styles.scss b/docs/examples/styles.scss index 72e0cf642..1d3efe79a 100644 --- a/docs/examples/styles.scss +++ b/docs/examples/styles.scss @@ -82,6 +82,12 @@ width: 200px; } } + + &.status-pill-example { + .aui--status-pill + .aui--status-pill { + margin-left: 20px; + } + } } .full-width { diff --git a/src/components/adslot-ui/StatusPill/index.jsx b/src/components/adslot-ui/StatusPill/index.jsx new file mode 100644 index 000000000..6ae0e9029 --- /dev/null +++ b/src/components/adslot-ui/StatusPill/index.jsx @@ -0,0 +1,35 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import classnames from 'classnames'; +import { expandDts } from 'lib/utils'; + +import './styles.scss'; + +const styles = ['primary', 'success', 'warning', 'error', 'light']; + +const StatusPill = ({ displayStyle, status, inverse, dts }) => ( +
+ {status} +
+); + +StatusPill.defaultProps = { + displayStyle: styles[0], + inverse: false, +}; + +StatusPill.propTypes = { + status: PropTypes.string.isRequired, + displayStyle: PropTypes.oneOf(styles), + inverse: PropTypes.bool, + dts: PropTypes.string, +}; + +export default StatusPill; diff --git a/src/components/adslot-ui/StatusPill/index.spec.jsx b/src/components/adslot-ui/StatusPill/index.spec.jsx new file mode 100644 index 000000000..b5af7ef4e --- /dev/null +++ b/src/components/adslot-ui/StatusPill/index.spec.jsx @@ -0,0 +1,25 @@ +import React from 'react'; +import { shallow } from 'enzyme'; +import StatusPill from '.'; + +describe('', () => { + it('should have default style', () => { + const wrapper = shallow(); + expect(wrapper.props().className).to.equal('aui--status-pill aui--status-pill-primary'); + }); + + it('should allow style prop', () => { + const wrapper = shallow(); + expect(wrapper.props().className).to.equal('aui--status-pill aui--status-pill-success'); + }); + + it('should allow inverse prop', () => { + const wrapper = shallow(); + expect(wrapper.props().className).to.equal('aui--status-pill aui--status-pill-success aui--status-pill-inverse'); + }); + + it('should support custom dts', () => { + const wrapper = shallow(); + expect(wrapper.props()['data-test-selector']).to.equal('test-dts'); + }); +}); diff --git a/src/components/adslot-ui/StatusPill/styles.scss b/src/components/adslot-ui/StatusPill/styles.scss new file mode 100644 index 000000000..589648bdd --- /dev/null +++ b/src/components/adslot-ui/StatusPill/styles.scss @@ -0,0 +1,76 @@ +@import '~styles/variable'; + +$color-primary: $color-status-blue; +$color-primary-background: rgba($color-primary, .35); +$color-success: $color-status-green; +$color-success-background: rgba($color-success, .35); +$color-warning: $color-status-orange; +$color-warning-background: rgba($color-warning, .35); +$color-error: $color-status-red; +$color-error-background: rgba($color-error, .35); +$color-light: $color-status-light; +$color-inverse-border: $color-status-light; + +.aui--status-pill { + font-size: $font-size-base; + display: inline-block; + align-items: center; + justify-content: center; + height: 24px; + padding: 5px 12px; + border: 1px solid transparent; + border-radius: 12px; + user-select: none; + font-weight: $font-weight-bold; + line-height: 1; + color: $color-gray-darker; + + &.aui--status-pill-primary { + background-color: $color-primary-background; + + &.aui--status-pill-inverse { + background-color: $color-background; + border-color: $color-inverse-border; + color: $color-primary; + } + } + + &.aui--status-pill-success { + background-color: $color-success-background; + + &.aui--status-pill-inverse { + background-color: $color-background; + border-color: $color-inverse-border; + color: $color-success; + } + } + + &.aui--status-pill-warning { + background-color: $color-warning-background; + + &.aui--status-pill-inverse { + background-color: $color-background; + border-color: $color-inverse-border; + color: $color-warning; + } + } + + &.aui--status-pill-error { + background-color: $color-error-background; + + &.aui--status-pill-inverse { + background-color: $color-background; + border-color: $color-inverse-border; + color: $color-error; + } + } + + &.aui--status-pill-light { + background-color: $color-light; + + &.aui--status-pill-inverse { + background-color: $color-background; + border-color: $color-inverse-border; + } + } +} diff --git a/src/components/adslot-ui/index.js b/src/components/adslot-ui/index.js index 5865be8d0..1944d101f 100644 --- a/src/components/adslot-ui/index.js +++ b/src/components/adslot-ui/index.js @@ -17,6 +17,7 @@ import RadioGroup from 'adslot-ui/RadioGroup'; import Search from 'adslot-ui/Search'; import SearchBar from 'adslot-ui/SearchBar'; import SplitPane from 'adslot-ui/SplitPane'; +import StatusPill from 'adslot-ui/StatusPill'; import Tab from 'adslot-ui/Tab'; import Tabs from 'adslot-ui/Tabs'; import Textarea from 'adslot-ui/Textarea'; @@ -53,6 +54,7 @@ export { Search, SearchBar, SplitPane, + StatusPill, Tab, Tabs, Textarea, diff --git a/src/index.js b/src/index.js index 3338a0ee0..c805e4062 100644 --- a/src/index.js +++ b/src/index.js @@ -64,6 +64,7 @@ import { Search, SearchBar, SplitPane, + StatusPill, Tab, Tabs, Textarea, @@ -125,6 +126,7 @@ export { Spinner, SplitPane, Statistic, + StatusPill, SvgSymbol, SvgSymbolCircle, Tab, diff --git a/src/styles/color.scss b/src/styles/color.scss index 0fba7f42f..fbc57efe4 100644 --- a/src/styles/color.scss +++ b/src/styles/color.scss @@ -31,6 +31,12 @@ $color-gray-darkest: #333; $color-black: #000; +// Status Colors +$color-status-blue: #00adee; +$color-status-green: #95c83d; +$color-status-red: $color-red; +$color-status-orange: #f93; +$color-status-light: $color-gray-lighter; // Usage: Use these values, not the colours directly