Skip to content

Commit

Permalink
feat(Chip): Add the Chip component to PF4 (patternfly#1180)
Browse files Browse the repository at this point in the history
  • Loading branch information
ibolton336 authored and jschuler committed Jan 15, 2019
1 parent 822fc29 commit 752adae
Show file tree
Hide file tree
Showing 11 changed files with 298 additions and 0 deletions.
15 changes: 15 additions & 0 deletions packages/patternfly-4/react-core/src/components/Chip/Chip.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { SFC, HTMLProps } from 'react';
import { Omit, OneOf } from '../../typeUtils';
import { TooltipPosition } from '../Tooltip';

export interface ChipProps extends HTMLProps<HTMLDivElement> {
children: string;
closeBtnAriaLabel: string;
isOverflowChip: boolean;
tooltipPosition: OneOf<typeof TooltipPosition, keyof typeof TooltipPosition>;
}

declare const Chip: SFC<ChipProps>;

export default Chip;

15 changes: 15 additions & 0 deletions packages/patternfly-4/react-core/src/components/Chip/Chip.docs.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { Chip } from '@patternfly/react-core';
import SimpleExample from './examples/SimpleChip';

export default {
title: 'Chip',
components: {
Chip,
},
examples: [
{
component: SimpleExample,
title: 'Simple Example'
}
]
};
100 changes: 100 additions & 0 deletions packages/patternfly-4/react-core/src/components/Chip/Chip.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import ChipButton from './ChipButton';
import { Tooltip, TooltipPosition } from '../Tooltip';
import { TimesCircleIcon } from '@patternfly/react-icons';
import styles from '@patternfly/patternfly-next/components/Chip/chip.css';
import GenerateId from '../../internal/GenerateId/GenerateId';
class Chip extends React.Component {

renderOverflowChip = () => {
const { children, className, onClick } = this.props;
return (
<div className={css(styles.chip, styles.modifiers.overflow, className)}>
<ChipButton onClick={onClick}>
<span className={css(styles.chipText)}>{children}</span>
</ChipButton>
</div>
);
}

renderChip = (randomId) => {
const {
children,
closeBtnAriaLabel,
tooltipPosition,
className,
onClick,
} = this.props;
const isTooltipVisible = children.length > 16;
if (isTooltipVisible) {
return (
<Tooltip position={tooltipPosition} content={children}>
<div className={css(styles.chip, className)}>
<span className={css(styles.chipText)} id={randomId}>
{children}
</span>
<ChipButton onClick={onClick} ariaLabel={closeBtnAriaLabel} id={`remove_${randomId}`} aria-labelledby={`remove_${randomId} ${randomId}`}>
<TimesCircleIcon aria-hidden="true" />
</ChipButton>
</div>
</Tooltip>
)
} else {
return (
<div className={css(styles.chip, className)}>
<span className={css(styles.chipText)} id={randomId}>
{children}
</span>
<ChipButton onClick={onClick} ariaLabel={closeBtnAriaLabel} id={`remove_${randomId}`} aria-labelledby={`remove_${randomId} ${randomId}`}>
<TimesCircleIcon aria-hidden="true" />
</ChipButton>
</div>
)
}
}

render() {
const {
isOverflowChip,
} = this.props;
return (
<GenerateId>
{(randomId) =>
(
<React.Fragment>
{isOverflowChip ? this.renderOverflowChip() : this.renderChip(randomId)}
</React.Fragment>
)
}
</GenerateId>
)
}
}
Chip.propTypes = {
/** Content rendered inside the chip text */
children: PropTypes.string.isRequired,
/** Aria Label for close button */
closeBtnAriaLabel: PropTypes.string,
/** ID of the chip */
id: PropTypes.string,
/** Additional classes added to the chip item */
className: PropTypes.string,
/** Flag indicating if the chip has overflow*/
isOverflowChip: PropTypes.bool,
/** Position of the tooltip which is displayed if text is longer */
tooltipPosition: PropTypes.oneOf(Object.values(TooltipPosition)),
/** Function that is called when clicking on the chip button */
onClick: PropTypes.func,
};

Chip.defaultProps = {
id: undefined,
closeBtnAriaLabel: 'close',
className: '',
tooltipPosition: 'top',
isOverflowChip: false,
};

export default Chip;
43 changes: 43 additions & 0 deletions packages/patternfly-4/react-core/src/components/Chip/Chip.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { shallow } from 'enzyme';
import ChipButton from './ChipButton';
import Chip from './Chip';

test('ChipButton', () => {
const view = shallow(
<ChipButton id="my-chip-button" className="chip-bttn-cls">
<b>Close</b>
</ChipButton>
);
expect(view).toMatchSnapshot();
});

describe('Chip', () => {
test('overflow', () => {
const view = shallow(
<Chip className="my-chp-cls" isOverflowChip={true}>
4 more
</Chip>
);
expect(view).toMatchSnapshot();
});

test('closable', () => {
const view = shallow(
<Chip className="my-chp-cls" id="chip_one">
Chip
</Chip>
);
expect(view).toMatchSnapshot();
});


test('closable with tooltip', () => {
const view = shallow(
<Chip className="my-chp-cls" id="chip_one">
12345678901234567891
</Chip>
);
expect(view).toMatchSnapshot();
});
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SFC, HTMLProps } from 'react';

export interface ChipButtonProps extends HTMLProps<HTMLButtonElement> {}

declare const ChipButton: SFC<ChipButtonProps>;

export default ChipButton;
33 changes: 33 additions & 0 deletions packages/patternfly-4/react-core/src/components/Chip/ChipButton.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { css } from '@patternfly/react-styles';
import PropTypes from 'prop-types';
import styles from '@patternfly/patternfly-next/components/Chip/chip.css';
import { Button } from '../Button';

const ChipButton = ({ ariaLabel, children, className, onClick, ...props }) => {
return (
<Button variant="plain" aria-label={ariaLabel} onClick={onClick} className={className} {...props}>
{children}
</Button>
);
};

ChipButton.propTypes = {
/** Aria label for chip button */
ariaLabel: PropTypes.string,
/** Content rendered inside the chip item */
children: PropTypes.node,
/** Additional classes added to the chip item */
className: PropTypes.string,
/** Function that is called when clicking on the chip button */
onClick: PropTypes.func,
};

ChipButton.defaultProps = {
ariaLabel: 'close',
children: null,
className: '',
onClick: () => { }
};

export default ChipButton;
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Chip closable 1`] = `
<GenerateId
prefix="pf-random-id-"
/>
`;

exports[`Chip closable with tooltip 1`] = `
<GenerateId
prefix="pf-random-id-"
/>
`;

exports[`Chip overflow 1`] = `
<GenerateId
prefix="pf-random-id-"
/>
`;

exports[`ChipButton 1`] = `
<Button
aria-label="close"
className="chip-bttn-cls"
component="button"
id="my-chip-button"
isActive={false}
isBlock={false}
isDisabled={false}
isFocus={false}
isHover={false}
onClick={[Function]}
type="button"
variant="plain"
>
<b>
Close
</b>
</Button>
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import React from 'react';
import { Chip } from '@patternfly/react-core';

class SimpleChip extends React.Component {
state = {
show: ['chip_one', 'chip_two']
};
deleteItem = id => {
const { show } = this.state;
const ix = show.indexOf(id);
if (ix < 0) {
return;
}
this.setState(() => ({
show: [...show.slice(0, ix), ...show.slice(ix + 1, show.length)]
}));
};
render() {
const { show } = this.state
return (
<React.Fragment>
{show.includes('chip_one') && (
<Chip id="chip_one" onClick={() => this.deleteItem('chip_one')}>
Chip
</Chip>
)}
<br />
<br />
{show.includes('chip_two') && (
<Chip id="chip_two" onClick={() => this.deleteItem('chip_two')}>
Really long Chip that goes on and on
</Chip>
)}
<br />
<br />
<Chip isOverflowChip={true}>4 more</Chip>
</React.Fragment>
);
}
}

export default SimpleChip;
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Chip } from './Chip';
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as Chip } from './Chip';
1 change: 1 addition & 0 deletions packages/patternfly-4/react-core/src/components/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export * from './Breadcrumb';
export * from './Button';
export * from './Card';
export * from './Checkbox';
export * from './Chip';
export * from './DataList';
export * from './Dropdown';
export * from './EmptyState';
Expand Down

0 comments on commit 752adae

Please sign in to comment.