diff --git a/src-docs/src/views/breadcrumbs/breadcrumbs_example.js b/src-docs/src/views/breadcrumbs/breadcrumbs_example.js
index 93be4bc44343..3a4fe3b65ff3 100644
--- a/src-docs/src/views/breadcrumbs/breadcrumbs_example.js
+++ b/src-docs/src/views/breadcrumbs/breadcrumbs_example.js
@@ -23,6 +23,10 @@ import Truncate from './truncate';
const truncateSource = require('!!raw-loader!./truncate');
const truncateHtml = renderToHtml(Truncate);
+import Max from './max';
+const maxSource = require('!!raw-loader!./max');
+const maxHtml = renderToHtml(Max);
+
export const BreadcrumbsExample = {
title: 'Breadcrumbs',
sections: [{
@@ -59,7 +63,7 @@ export const BreadcrumbsExample = {
props: { EuiBreadcrumbs },
demo: ,
}, {
- title: 'Truncate',
+ title: 'Truncate each breadcrumb',
source: [{
type: GuideSectionTypes.JS,
code: truncateSource,
@@ -74,5 +78,21 @@ export const BreadcrumbsExample = {
),
props: { EuiBreadcrumbs },
demo: ,
+ }, {
+ title: 'Limit the number of breadcrumbs',
+ source: [{
+ type: GuideSectionTypes.JS,
+ code: maxSource,
+ }, {
+ type: GuideSectionTypes.HTML,
+ code: maxHtml,
+ }],
+ text: (
+
+ Use the max prop to cull breadcrumbs beyond a certain number.
+
+ ),
+ props: { EuiBreadcrumbs },
+ demo: ,
}],
};
diff --git a/src-docs/src/views/breadcrumbs/max.js b/src-docs/src/views/breadcrumbs/max.js
new file mode 100644
index 000000000000..ae9529458c29
--- /dev/null
+++ b/src-docs/src/views/breadcrumbs/max.js
@@ -0,0 +1,34 @@
+import React from 'react';
+
+import {
+ EuiBreadcrumbs,
+} from '../../../../src/components';
+
+export default () => {
+ const breadcrumbs = [{
+ text: 'Animals',
+ href: '#',
+ }, {
+ text: 'Metazoans',
+ href: '#',
+ }, {
+ text: 'Chordates',
+ href: '#',
+ }, {
+ text: 'Vertebrates',
+ href: '#',
+ }, {
+ text: 'Tetrapods',
+ href: '#',
+ }, {
+ text: 'Reptiles',
+ href: '#',
+ }, {
+ text: 'Boa constrictor',
+ href: '#',
+ }, {
+ text: 'Nebulosa subspecies',
+ }];
+
+ return ;
+};
diff --git a/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap b/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap
index 12c6598184ad..d33aaeebfb98 100644
--- a/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap
+++ b/src/components/breadcrumbs/__snapshots__/breadcrumbs.test.js.snap
@@ -42,6 +42,132 @@ exports[`EuiBreadcrumbs is rendered 1`] = `
`;
+exports[`EuiBreadcrumbs props max doesn't break when max exceeds the number of breadcrumbs 1`] = `
+
+
+
+
+
+
+
+
+ Edit
+
+
+`;
+
+exports[`EuiBreadcrumbs props max renders 1 item 1`] = `
+
+`;
+
+exports[`EuiBreadcrumbs props max renders 2 items 1`] = `
+
+
+
+
+ …
+
+
+
+ Edit
+
+
+`;
+
+exports[`EuiBreadcrumbs props max renders 3 items 1`] = `
+
+
+
+
+ …
+
+
+
+
+
+ Edit
+
+
+`;
+
exports[`EuiBreadcrumbs props responsive is rendered 1`] = `
+
+
+
+
@@ -76,6 +220,24 @@ exports[`EuiBreadcrumbs props truncate is rendered 1`] = `
+
+
+
+
diff --git a/src/components/breadcrumbs/_breadcrumbs.scss b/src/components/breadcrumbs/_breadcrumbs.scss
index 40143f132a3f..f345f8c5d471 100644
--- a/src/components/breadcrumbs/_breadcrumbs.scss
+++ b/src/components/breadcrumbs/_breadcrumbs.scss
@@ -4,7 +4,6 @@
.euiBreadcrumb {
display: inline-block;
- position: relative;
&:not(.euiBreadcrumb--last) {
margin-right: $euiBreadcrumbSpacing;
@@ -15,13 +14,17 @@
font-weight: 500;
}
+.euiBreadcrumb--collapsed {
+ color: $euiColorLightShade;
+}
+
.euiBreadcrumbSeparator {
pointer-events: none;
display: inline-block;
margin-right: $euiBreadcrumbSpacing;
width: 1px;
height: $euiSize;
- transform: rotate(15deg) translateY(0.2em);
+ transform: translateY(0.2em) rotate(15deg);
background: $euiColorLightShade;
}
diff --git a/src/components/breadcrumbs/breadcrumbs.js b/src/components/breadcrumbs/breadcrumbs.js
index 93bd64fe40d2..b74f08463bde 100644
--- a/src/components/breadcrumbs/breadcrumbs.js
+++ b/src/components/breadcrumbs/breadcrumbs.js
@@ -4,11 +4,55 @@ import classNames from 'classnames';
import { EuiLink } from '../link';
+const limitBreadcrumbs = (breadcrumbs, max) => {
+ const breadcrumbsAtStart = [];
+ const breadcrumbsAtEnd = [];
+ const limit = Math.min(max, breadcrumbs.length);
+
+ for (let i = 0; i < limit; i++) {
+ // We'll alternate with displaying breadcrumbs at the end and at the start, but be biased
+ // towards breadcrumbs the end so that if max is an odd number, we'll have one more
+ // breadcrumb visible at the end than at the beginning.
+ const isEven = i % 2 === 0;
+
+ // We're picking breadcrumbs from the front AND the back, so we treat each iteration as a
+ // half-iteration.
+ const normalizedIndex = Math.floor(i * 0.5);
+ const indexOfBreadcrumb = isEven ? breadcrumbs.length - 1 - normalizedIndex : normalizedIndex;
+ const breadcrumb = breadcrumbs[indexOfBreadcrumb];
+
+ if (isEven) {
+ breadcrumbsAtEnd.unshift(breadcrumb);
+ } else {
+ breadcrumbsAtStart.push(breadcrumb);
+ }
+ }
+
+ if (max < breadcrumbs.length) {
+ breadcrumbsAtStart.push();
+ }
+
+ return [
+ ...breadcrumbsAtStart,
+ ...breadcrumbsAtEnd,
+ ];
+}
+
+const EuiBreadcrumbCollapsed = () => (
+
+ …
+
+
+);
+
+const EuiBreadcrumbSeparator = () => ;
+
export const EuiBreadcrumbs = ({
breadcrumbs,
className,
responsive,
truncate,
+ max,
...rest,
}) => {
const breadcrumbElements = breadcrumbs.map((breadcrumb, index) => {
@@ -51,7 +95,7 @@ export const EuiBreadcrumbs = ({
let separator;
if (!isLastBreadcrumb) {
- separator = ;
+ separator = ;
}
return (
@@ -62,6 +106,8 @@ export const EuiBreadcrumbs = ({
);
})
+ const limitedBreadcrumbs = max ? limitBreadcrumbs(breadcrumbElements, max) : breadcrumbElements;
+
const classes = classNames('euiBreadcrumbs', className, {
'euiBreadcrumbs--truncate': truncate,
'euiBreadcrumbs--responsive': responsive,
@@ -69,7 +115,7 @@ export const EuiBreadcrumbs = ({
return (
- {breadcrumbElements}
+ {limitedBreadcrumbs}
);
};
@@ -78,6 +124,7 @@ EuiBreadcrumbs.propTypes = {
className: PropTypes.string,
responsive: PropTypes.bool,
truncate: PropTypes.bool,
+ max: PropTypes.number,
breadcrumbs: PropTypes.arrayOf(PropTypes.shape({
text: PropTypes.node.isRequired,
href: PropTypes.string,
diff --git a/src/components/breadcrumbs/breadcrumbs.test.js b/src/components/breadcrumbs/breadcrumbs.test.js
index 0a1999175c04..6f7030817779 100644
--- a/src/components/breadcrumbs/breadcrumbs.test.js
+++ b/src/components/breadcrumbs/breadcrumbs.test.js
@@ -32,6 +32,10 @@ describe('EuiBreadcrumbs', () => {
describe('props', () => {
const breadcrumbs = [{
text: 'Animals',
+ }, {
+ text: 'Reptiles',
+ }, {
+ text: 'Boa constrictor',
}, {
text: 'Edit',
}];
@@ -49,5 +53,27 @@ describe('EuiBreadcrumbs', () => {
expect(component).toMatchSnapshot();
});
});
+
+ describe('max', () => {
+ test('renders 1 item', () => {
+ const component = render();
+ expect(component).toMatchSnapshot();
+ });
+
+ test('renders 2 items', () => {
+ const component = render();
+ expect(component).toMatchSnapshot();
+ });
+
+ test('renders 3 items', () => {
+ const component = render();
+ expect(component).toMatchSnapshot();
+ });
+
+ test(`doesn't break when max exceeds the number of breadcrumbs`, () => {
+ const component = render();
+ expect(component).toMatchSnapshot();
+ });
+ });
});
});
diff --git a/src/components/breadcrumbs/max.js b/src/components/breadcrumbs/max.js
new file mode 100644
index 000000000000..e69de29bb2d1