Skip to content

Commit

Permalink
Add pill component (#5)
Browse files Browse the repository at this point in the history
Adding a Pill component to use for concise inline status messages.
  • Loading branch information
TimeBones authored Feb 11, 2022
1 parent 0201c74 commit 81647e6
Show file tree
Hide file tree
Showing 8 changed files with 368 additions and 0 deletions.
100 changes: 100 additions & 0 deletions src/components/pill/Pill.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
.stx-pill {
display: inline-flex;
vertical-align: middle;
align-items: center;
margin: 0px 0.3em;
border: 1px solid #5C6670;
background-color: #ECEEF0;
color: #394046;
font-size: 0.8125rem;
font-weight: 500;
padding: 0.0625rem 0.375rem;
line-height: 1rem;
border-radius: 0.625rem;
}

.stx-pill--with-info {
border-color: #3B63FF;
background-color: #E8ECFF;
color: #264BD9;
}

.stx-pill--with-warning {
border-color: #E16D00;
background-color: #F0DAFF;
color: #B25600;
}

.stx-pill--with-success {
border-color: #008757;
background-color: #DEF6EE;
color: #00633F;
}

.stx-pill--with-alert {
border-color: #E41244;
background-color: #FFEBF0;
color: #B4002B;
}

.stx-pill--is-clickable {
cursor: pointer;
}

.stx-pill--is-minimized {
padding: 0;
width: 0.5rem;
height: 0.5rem;
border-radius: 0.5rem;
}

.stx-pill--is-minimized > .bv-pill__icon,
.stx-pill--is-minimized > .bv-pill__label,
.stx-pill--is-minimized > .bv-pill__dismiss-button {
display: none;
}

.stx-pill--is-filled {
background-color: #5C6670;
border-color: rgba(0,0,0,0.1);
color: #fff;
}

.stx-pill--is-filled.bv-pill--with-info {
background-color: #3B63FF;
color: #fff;
}

.stx-pill--is-filled.bv-pill--with-warning {
background-color: #B25600;
color: #fff;
}

.stx-pill--is-filled.bv-pill--with-success {
background-color: #008757;
color: #fff;
}

.stx-pill--is-filled.bv-pill--with-alert {
background-color: #E41244;
color: #fff;
}

.stx-pill__label {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
display: inline-block;
}

.stx-pill__icon {
margin-left: -0.125rem;
margin-right: 0.125rem;
}

.stx-pill__dismiss-button {
margin-left: 0.125rem;
margin-right: -0.125rem;
width: 1rem;
height: 1rem;
}
75 changes: 75 additions & 0 deletions src/components/pill/Pill.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
import React from 'react';
import cn from 'classnames';
import PropTypes from 'prop-types';
import times from './timesIcon';

import './Pill.css';

function Pill(props) {
const {
label, status, dismissible, minimized, filled, onClick, onDismiss, dismissType, dismissText, className, ...otherProps
} = props;
const classNames = cn([
'stx-pill',
{ 'stx-pill--with-info': status === 'info' },
{ 'stx-pill--with-warning': status === 'warning' },
{ 'stx-pill--with-success': status === 'success' },
{ 'stx-pill--with-alert': status === 'alert' },
{ 'stx-pill--is-filled': filled },
{ 'stx-pill--is-minimized': minimized },
{ 'stx-pill--is-clickable': onClick },
className,
]);

const timesIcon = <span className='stx-pill__icon'>
<svg
className='stx-pill-icon__icon'
viewBox='0 0 24 24'
>
<path className='stx-pill-icon__path' fill='#6B6B6B' d={times} />
</svg>
</span>;

return (
<span
{...otherProps}
className={classNames}
onClick={onClick}
>
<span className="stx-pill__label">
{ label }
</span>
{ dismissible && <button
className='stx-pill__dismiss-button'
aria-label={dismissText}
onClick={onDismiss}>
{dismissType === 'icon' ? timesIcon : dismissText}
</button> }
</span>
);
}

Pill.propTypes = {
/** Label for the pill */
label: PropTypes.string,
/** Status modifier to change the color */
status: PropTypes.oneOf(['alert', 'warning', 'success', 'info', '']),
/** Show the dismiss button */
dismissible: PropTypes.bool,
/** Show the pill as a minimized indicator */
minimized: PropTypes.bool,
/** Show the pill as a solid colour instead of an outline */
filled: PropTypes.bool,
/** Event that fires when you click on the pill */
onClick: PropTypes.func,
/** Event that fires when you click on the dismiss button */
onDismiss: PropTypes.func,
/** Dismiss button type */
dismissType: PropTypes.oneOf(['string', 'icon']),
/** Dismiss text for dismissType of string and aria label of dismiss button */
dismissText: PropTypes.string,
/** Additional classname(s) */
className: PropTypes.string,
};

export default Pill;
104 changes: 104 additions & 0 deletions src/components/pill/Pill.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
import React from 'react';
import { shallow } from 'enzyme';
import toJson from 'enzyme-to-json';
import Pill from './Pill';

describe('Pill', () => {
test('Pill renders with basic props', () => {
const component = shallow(<Pill
className="class-name"
label="label"
/>);

expect(toJson(component)).toMatchSnapshot();
});

test('Pill renders with a11y props', () => {
const component = shallow(<Pill
aria-label="aria-label"
/>);

const span = component.find('span.stx-pill');
expect(span).toHaveLength(1);
expect(span.prop('aria-label')).toEqual('aria-label');
expect(toJson(component)).toMatchSnapshot();
});

test('Pill renders with dismiss button', () => {
const onDismissSpy = jest.fn();
const component = shallow(<Pill
dismissible
dismissText='dismiss'
onDismiss={onDismissSpy}
/>);

const dismissButton = component.find('button.stx-pill__dismiss-button');
expect(dismissButton.exists()).toBe(true);
expect(dismissButton.prop('onClick')).toBe(onDismissSpy);
});

test('Pill renders with alert status', () => {
const component = shallow(<Pill
status="alert"
/>);

const span = component.find('span.stx-pill--with-alert');
expect(span.exists()).toBe(true);
});

test('Pill renders with warning status', () => {
const component = shallow(<Pill
status="warning"
/>);

const span = component.find('span.stx-pill--with-warning');
expect(span.exists()).toBe(true);
});

test('Pill renders with success status', () => {
const component = shallow(<Pill
status="success"
/>);

const span = component.find('span.stx-pill--with-success');
expect(span.exists()).toBe(true);
});

test('Pill renders with info status', () => {
const component = shallow(<Pill
status="info"
/>);

const span = component.find('span.stx-pill--with-info');
expect(span.exists()).toBe(true);
});

test('Pill renders as minimized', () => {
const component = shallow(<Pill
minimized
/>);

const span = component.find('span.stx-pill--is-minimized');
expect(span.exists()).toBe(true);
});

test('Pill renders as filled', () => {
const component = shallow(<Pill
filled
/>);

const span = component.find('span.stx-pill--is-filled');
expect(span.exists()).toBe(true);
});

test('Pill renders as clickable', () => {
const onClickSpy = jest.fn();
const component = shallow(<Pill
onClick={onClickSpy}
/>);

const span = component.find('span.stx-pill--is-clickable');
expect(span.exists()).toBe(true);
expect(span.prop('onClick')).toBe(onClickSpy);
});
});
61 changes: 61 additions & 0 deletions src/components/pill/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
### Purpose
Give the user a brief (1 - 2 word) status message that can sit inline with other text or elements.

### Examples
#### Standard
```jsx
<React.Fragment>
<Pill label="Alert" status="alert" />
<Pill label="Warning" status="warning" />
<Pill label="Success" status="success" />
<Pill label="Info" status="info" />
<Pill label="Default" />
</React.Fragment>
```
#### Filled
```jsx
<React.Fragment>
<Pill filled label="Alert" status="alert" />
<Pill filled label="Warning" status="warning" />
<Pill filled label="Success" status="success" />
<Pill filled label="Info" status="info" />
<Pill filled label="Default" />
</React.Fragment>
```

#### Dismissibles
##### Default dismissType
```jsx
<React.Fragment>
<Pill
dismissible
dismissText='dismiss'
onDismiss={ e => myFunction() }
label="Info"
status="info"
/>

<Pill filled dismissible label="Default" />
</React.Fragment>
```

##### Icon dismissType
```jsx
<React.Fragment>
<Pill
dismissible
dismissText='dismiss'
dismissType='icon'
onDismiss={ e => myFunction() }
label="Warning"
status="warning"
/>

<Pill filled dismissible label="Default" />
</React.Fragment>
```

#### Pills as status for something
These 5 status types can carry different meanings. If Pill is being used to show status, several different labels can be used with the same status type. For example, `warning` can refer to "In Progress" and "Incomplete" at the same time; basically anything that is proceeding with caution.

`success` should be reserved for status that is both complete and positive, and `alert` should be reserve for status that is both complete and negative.
24 changes: 24 additions & 0 deletions src/components/pill/__snapshots__/Pill.test.js.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Pill Pill renders with a11y props 1`] = `
<span
aria-label="aria-label"
className="stx-pill"
>
<span
className="stx-pill__label"
/>
</span>
`;

exports[`Pill Pill renders with basic props 1`] = `
<span
className="stx-pill class-name"
>
<span
className="stx-pill__label"
>
label
</span>
</span>
`;
2 changes: 2 additions & 0 deletions src/components/pill/timesIcon.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ export { default as CheckboxField } from './components/checkboxfield/CheckboxFie
export { default as LoadingSpinner } from './components/loadingspinner/LoadingSpinner';
export { default as ProgressBar } from './components/progressbar/ProgressBar';
export { default as Message } from './components/message/Message';
export { default as Pill } from './components/pill/Pill';

// Product
export { default as Details } from './components/details/Details';
Expand Down
1 change: 1 addition & 0 deletions styleguide.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ module.exports = {
'src/components/loadingspinner/LoadingSpinner.js',
'src/components/progressbar/ProgressBar.js',
'src/components/message/Message.js',
'sec/components/pill/Pill.js',
],
},

Expand Down

0 comments on commit 81647e6

Please sign in to comment.