Skip to content

Commit

Permalink
feat(breadcrumb): adds breadcrumb, breadcrumbItem components (pattern…
Browse files Browse the repository at this point in the history
  • Loading branch information
rvsia authored and dlabaj committed Nov 27, 2018
1 parent 44aab83 commit bcd2954
Show file tree
Hide file tree
Showing 20 changed files with 897 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
import { SFC, HTMLProps, ReactNode } from 'react';

export interface BreadcrumbProps extends HTMLProps<HTMLElement> {
children?: ReactNode;
className?: string;
'aria-label'?: string;
}

declare const Breadcrumb: SFC<BreadcrumbProps>;

export default Breadcrumb;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Simple from './examples/SimpleBreadcrumbs';
import WithoutLinkBreadcrumbs from './examples/WithoutLinkBreadcrumbs';
import HeadingBreadcrumbs from './examples/HeadingBreadcrumbs';
import { Breadcrumb, BreadcrumbItem, BreadcrumbHeading } from '@patternfly/react-core';

export default {
title: 'Breadcrumb',
components: {
Breadcrumb,
BreadcrumbItem,
BreadcrumbHeading
},
examples: [
{
component: Simple,
title: 'Breadcrumb'
},
{
component: WithoutLinkBreadcrumbs,
title: 'Breadcrumb without Home Link'
},
{
component: HeadingBreadcrumbs,
title: 'Breadcrumb with Heading'
}
]
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import styles from '@patternfly/patternfly-next/components/Breadcrumb/breadcrumb.css';
import PropTypes from 'prop-types';
import { css } from '@patternfly/react-styles';

const propTypes = {
/** Children nodes be rendered to the BreadCrumb. Should be of type BreadCrumbItem. */
children: PropTypes.node,
/** Additional classes added to the breadcrumb nav. */
className: PropTypes.string,
/** Aria-label added to the breadcrumb nav. */
'aria-label': PropTypes.string
};

const defaultProps = {
children: null,
className: '',
'aria-label': 'breadcrumb'
};

const Breadcrumb = ({ className, children, ...props }) => (
<nav {...props} className={css(styles.breadcrumb, className)}>
<ol className={css(styles.breadcrumbList)}>{children}</ol>
</nav>
);

Breadcrumb.propTypes = propTypes;
Breadcrumb.defaultProps = defaultProps;

export default Breadcrumb;
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import Breadcrumb from './Breadcrumb';
import BreadcrumbItem from './BreadcrumbItem';
import { shallow } from 'enzyme';

describe('Breadcrumb component', () => {
test('should render default breadcrumb', () => {
const view = shallow(<Breadcrumb />);
expect(view).toMatchSnapshot();
});

test('should render breadcrumb with className', () => {
const view = shallow(<Breadcrumb className="className" />);
expect(view).toMatchSnapshot();
});

test('should render breadcrumb with aria-label', () => {
const view = shallow(<Breadcrumb aria-label="custom label" />);
expect(view).toMatchSnapshot();
});

test('should render breadcrumb with children', () => {
const view = shallow(
<Breadcrumb>
<BreadcrumbItem to="#">Item 1</BreadcrumbItem> <BreadcrumbItem to="#">Item 1</BreadcrumbItem>
</Breadcrumb>
);
expect(view).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { SFC, HTMLProps, ReactNode, ReactType } from 'react';

export interface BreadcrumbHeadingProps extends HTMLProps<HTMLLIElement> {
children?: ReactNode;
className?: string;
to?: string;
target?: string;
component?: ReactType<BreadcrumbHeadingProps>;
}

declare const BreeadcrumbHeading: SFC<BreadcrumbHeadingProps>;

export default BreeadcrumbHeading;
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import React from 'react';
import styles from '@patternfly/patternfly-next/components/Breadcrumb/breadcrumb.css';
import PropTypes from 'prop-types';
import { css } from '@patternfly/react-styles';
import { componentShape } from '../../internal/componentShape';

const propTypes = {
/** Content rendered inside the breadcrumb title. */
children: PropTypes.node,
/** Additional classes added to the breadcrumb item. */
className: PropTypes.string,
/** HREF for breadcrumb link. */
to: PropTypes.string,
/** Target for breadcrumb link. */
target: PropTypes.string,
/** Sets the base component to render. Defaults to <a> */
component: componentShape
};

const defaultProps = {
children: null,
className: '',
to: null,
target: null,
component: 'a'
};

const BreadcrumbHeading = ({ className, children, to, target, component: Component, ...props }) => (
<li {...props} className={css(styles.breadcrumbItem, className)}>
<h1 className={css(styles.breadcrumbHeading)}>
{to && (
<Component
href={to}
target={target}
className={css(styles.breadcrumbLink, styles.modifiers.current)}
aria-current="page"
>
{children}
</Component>
)}
{!to && <React.Fragment>{children}</React.Fragment>}
</h1>
</li>
);

BreadcrumbHeading.propTypes = propTypes;
BreadcrumbHeading.defaultProps = defaultProps;

export default BreadcrumbHeading;
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
import React from 'react';
import BreadcrumbHeading from './BreadcrumbHeading';
import { shallow } from 'enzyme';

describe('BreadcrumbHeading component', () => {
test('should render default breadcrumbHeading', () => {
const view = shallow(<BreadcrumbHeading>Item</BreadcrumbHeading>);
expect(view).toMatchSnapshot();
});

test('should pass classname', () => {
const view = shallow(<BreadcrumbHeading className="Class">Item</BreadcrumbHeading>);
expect(view).toMatchSnapshot();
});

test('should pass custom id', () => {
const view = shallow(<BreadcrumbHeading id="Id">Item</BreadcrumbHeading>);
expect(view).toMatchSnapshot();
});

test('should render link breadcrumbTItle', () => {
const view = shallow(<BreadcrumbHeading to="/somewhere">Item</BreadcrumbHeading>);
expect(view).toMatchSnapshot();
});

test('should render breadcrumbHeading with target', () => {
const view = shallow(
<BreadcrumbHeading to="#here" target="_blank">
Item
</BreadcrumbHeading>
);
expect(view).toMatchSnapshot();
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { SFC, HTMLProps, ReactNode, ReactType } from 'react';

export interface BreadcrumbItemProps extends HTMLProps<HTMLLIElement> {
children?: ReactNode;
className?: string;
to?: string;
isActive?: boolean;
target?: string;
component?: ReactType<BreadcrumbItemProps>;
}

declare const BreeadcrumbItem: SFC<BreadcrumbItemProps>;

export default BreeadcrumbItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from 'react';
import styles from '@patternfly/patternfly-next/components/Breadcrumb/breadcrumb.css';
import PropTypes from 'prop-types';
import { AngleRightIcon } from '@patternfly/react-icons';
import { css, getModifier } from '@patternfly/react-styles';
import { componentShape } from '../../internal/componentShape';

const propTypes = {
/** Content rendered inside the breadcrumb item. */
children: PropTypes.node,
/** Additional classes added to the breadcrumb item. */
className: PropTypes.string,
/** HREF for breadcrumb link. */
to: PropTypes.string,
/** Flag indicating whether the item is active. */
isActive: PropTypes.bool,
/** Target for breadcrumb link. */
target: PropTypes.string,
/** Sets the base component to render. Defaults to <a> */
component: componentShape
};

const defaultProps = {
children: null,
className: '',
to: null,
isActive: false,
target: null,
component: 'a'
};

const BreadcrumbItem = ({ className, children, to, isActive, target, component: Component, ...props }) => (
<li {...props} className={css(styles.breadcrumbItem, className)}>
{to && (
<Component
href={to}
target={target}
className={css(styles.breadcrumbLink, getModifier(styles, isActive && 'current'))}
aria-current={isActive ? 'page' : undefined}
>
{children}
</Component>
)}
{!to && <React.Fragment>{children}</React.Fragment>}
{!isActive && (
<span className={css(styles.breadcrumbItemDivider)}>
<AngleRightIcon />
</span>
)}
</li>
);

BreadcrumbItem.propTypes = propTypes;
BreadcrumbItem.defaultProps = defaultProps;

export default BreadcrumbItem;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import BreadcrumbItem from './BreadcrumbItem';
import { shallow } from 'enzyme';

describe('BreadcrumbItem component', () => {
test('should render default breadcrumbItem', () => {
const view = shallow(<BreadcrumbItem>Item</BreadcrumbItem>);
expect(view).toMatchSnapshot();
});

test('should render breadcrumbItem with className', () => {
const view = shallow(<BreadcrumbItem className="Class">Item</BreadcrumbItem>);
expect(view).toMatchSnapshot();
});

test('should render breadcrumbItem with id', () => {
const view = shallow(<BreadcrumbItem id="Item 1">Item</BreadcrumbItem>);
expect(view).toMatchSnapshot();
});

test('should render active breadcrumbItem', () => {
const view = shallow(<BreadcrumbItem isActive>Item</BreadcrumbItem>);
expect(view).toMatchSnapshot();
});

test('should render link breadcrumbItem', () => {
const view = shallow(<BreadcrumbItem to="/somewhere">Item</BreadcrumbItem>);
expect(view).toMatchSnapshot();
});

test('should render breadcrumbItem with target', () => {
const view = shallow(<BreadcrumbItem target="/somewhere">Item</BreadcrumbItem>);
expect(view).toMatchSnapshot();
});

test('should render breadcrumbItem with custom element', () => {
const view = shallow(
<BreadcrumbItem>
<h1>Header</h1>
</BreadcrumbItem>
);
expect(view).toMatchSnapshot();
});
});
Loading

0 comments on commit bcd2954

Please sign in to comment.