Skip to content

Commit 0c92b2f

Browse files
author
Constance
authored
[EuiBreadcrumbs] Fix the last breadcrumb in the array not respecting truncate overrides (#6280)
* [REVERT ME] Local reproduction of last breadcrumb issue - not respecting `truncate: true` on child breadcrumb when it should * Fix last EuiBreadcrumb in array to respect `truncate: true` or `false` over parent `truncate` + minor opinioted change: don't allow `breadcrumb` objs coming in from consumers to override internal props coming in from EuiBreadcrumbs parent * write a bunch of unit tests * changelog * Revert "[REVERT ME] Local reproduction of last breadcrumb issue" This reverts commit 233ae6a.
1 parent 092a8c0 commit 0c92b2f

File tree

5 files changed

+112
-75
lines changed

5 files changed

+112
-75
lines changed

src/components/breadcrumbs/__snapshots__/breadcrumbs.test.tsx.snap

Lines changed: 3 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -629,88 +629,31 @@ exports[`EuiBreadcrumbs props responsive is rendered with custom breakpoints 1`]
629629
</nav>
630630
`;
631631

632-
exports[`EuiBreadcrumbs props truncate as false is rendered 1`] = `
632+
exports[`EuiBreadcrumbs truncation setting truncate on breadcrumbs parents cascades down to all children 1`] = `
633633
<nav
634634
aria-label="Breadcrumbs"
635635
class="euiBreadcrumbs"
636636
>
637637
<ol
638638
class="euiBreadcrumbs__list emotion-euiBreadcrumbs__list"
639639
>
640-
<li
641-
class="euiBreadcrumb emotion-euiBreadcrumb-page"
642-
>
643-
<a
644-
class="euiLink euiBreadcrumb__content customClass emotion-euiLink-primary-euiBreadcrumb__content-page"
645-
data-test-subj="breadcrumbsAnimals"
646-
href="#"
647-
rel="noreferrer"
648-
>
649-
Animals
650-
</a>
651-
</li>
652640
<li
653641
class="euiBreadcrumb emotion-euiBreadcrumb-page"
654642
>
655643
<span
656644
class="euiBreadcrumb__content emotion-euiBreadcrumb__content-page-euiTextColor-subdued"
657645
>
658-
Metazoans
646+
A
659647
</span>
660648
</li>
661-
<li
662-
class="euiBreadcrumb emotion-euiBreadcrumb-page-isCollapsed"
663-
>
664-
<div
665-
class="euiPopover emotion-euiPopover"
666-
>
667-
<div
668-
class="euiPopover__anchor css-16vtueo-render"
669-
>
670-
<button
671-
aria-label="See collapsed breadcrumbs"
672-
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content-page"
673-
title="See collapsed breadcrumbs"
674-
type="button"
675-
>
676-
677-
<span
678-
data-euiicon-type="arrowDown"
679-
/>
680-
</button>
681-
</div>
682-
</div>
683-
</li>
684-
<li
685-
class="euiBreadcrumb emotion-euiBreadcrumb-page"
686-
>
687-
<button
688-
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content-page"
689-
type="button"
690-
>
691-
Reptiles
692-
</button>
693-
</li>
694-
<li
695-
class="euiBreadcrumb emotion-euiBreadcrumb-page"
696-
>
697-
<a
698-
class="euiLink euiBreadcrumb__content emotion-euiLink-subdued-euiBreadcrumb__content-page-isTruncated"
699-
href="#"
700-
rel="noreferrer"
701-
title="Boa constrictor has an error"
702-
>
703-
Boa constrictor
704-
</a>
705-
</li>
706649
<li
707650
class="euiBreadcrumb emotion-euiBreadcrumb-page"
708651
>
709652
<span
710653
aria-current="page"
711654
class="euiBreadcrumb__content emotion-euiBreadcrumb__content-page-euiTextColor-default"
712655
>
713-
Edit
656+
B
714657
</span>
715658
</li>
716659
</ol>

src/components/breadcrumbs/breadcrumb.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ type _EuiBreadcrumbProps = {
6363
isLastBreadcrumb?: boolean;
6464
isOnlyBreadcrumb?: boolean;
6565
highlightLastBreadcrumb?: boolean;
66+
truncateLastBreadcrumb?: boolean;
6667
} & Pick<EuiBreadcrumbProps, 'truncate'>;
6768

6869
export const EuiBreadcrumb: FunctionComponent<
@@ -100,6 +101,7 @@ export const EuiBreadcrumbContent: FunctionComponent<
100101
isLastBreadcrumb,
101102
isOnlyBreadcrumb,
102103
highlightLastBreadcrumb,
104+
truncateLastBreadcrumb,
103105
...rest
104106
}) => {
105107
const classes = classNames('euiBreadcrumb__content', className);
@@ -109,8 +111,8 @@ export const EuiBreadcrumbContent: FunctionComponent<
109111
const cssStyles = [
110112
styles.euiBreadcrumb__content,
111113
styles[type],
112-
truncate &&
113-
(isLastBreadcrumb ? styles.isTruncatedLast : styles.isTruncated),
114+
truncate && !truncateLastBreadcrumb && styles.isTruncated,
115+
truncateLastBreadcrumb && styles.isTruncatedLast,
114116
];
115117
if (type === 'application') {
116118
if (isOnlyBreadcrumb) {

src/components/breadcrumbs/breadcrumbs.test.tsx

Lines changed: 96 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
import React from 'react';
1010
import { render } from 'enzyme';
11-
import { requiredProps } from '../../test';
11+
import { requiredProps, replaceEmotionPrefix } from '../../test';
1212

1313
import { EuiBreadcrumbs, EuiBreadcrumb } from './';
1414

@@ -74,6 +74,101 @@ describe('EuiBreadcrumbs', () => {
7474
expect(component).toMatchSnapshot();
7575
});
7676

77+
describe('truncation', () => {
78+
test('setting truncate on breadcrumbs parents cascades down to all children', () => {
79+
const component = render(
80+
<EuiBreadcrumbs
81+
breadcrumbs={[{ text: 'A' }, { text: 'B' }]}
82+
truncate={false}
83+
/>
84+
);
85+
expect(component).toMatchSnapshot();
86+
});
87+
88+
const getBreadcrumbClass = (component: Cheerio, dataTestSubj: string) =>
89+
replaceEmotionPrefix(
90+
component.find(`[data-test-subj=${dataTestSubj}]`).attr('class')
91+
);
92+
93+
test('child breadcrumbs can override truncate set on parent breadcrumbs', () => {
94+
const component = render(
95+
<>
96+
<EuiBreadcrumbs
97+
breadcrumbs={[
98+
{ text: 'A', 'data-test-subj': 'A', truncate: false },
99+
{ text: 'B', 'data-test-subj': 'B' },
100+
]}
101+
truncate
102+
/>
103+
<EuiBreadcrumbs
104+
breadcrumbs={[
105+
{ text: 'C', 'data-test-subj': 'C', truncate: true },
106+
{ text: 'D', 'data-test-subj': 'D' },
107+
]}
108+
truncate={false}
109+
/>
110+
</>
111+
);
112+
expect(getBreadcrumbClass(component, 'A')).toEqual(
113+
'emotion-euiBreadcrumb__content-page-euiTextColor-subdued'
114+
);
115+
expect(getBreadcrumbClass(component, 'C')).toEqual(
116+
'emotion-euiBreadcrumb__content-page-isTruncated-euiTextColor-subdued'
117+
);
118+
});
119+
120+
describe('last breadcrumb', () => {
121+
describe('if the parent truncate is true and the last breadcrumb does not have its own truncate property', () => {
122+
it('sets a isTruncatedLast style that allows the last breadcrumb to occupy the remaining width of the breadcrumbs line', () => {
123+
const component = render(
124+
<EuiBreadcrumbs
125+
breadcrumbs={[
126+
{ text: 'A' },
127+
{ text: 'B', 'data-test-subj': 'last' },
128+
]}
129+
truncate
130+
/>
131+
);
132+
expect(getBreadcrumbClass(component, 'last')).toEqual(
133+
'emotion-euiBreadcrumb__content-page-isTruncatedLast-euiTextColor-default'
134+
);
135+
});
136+
});
137+
138+
describe('if the last breadcrumb has its own truncate property', () => {
139+
it('uses the normal isTruncated if truncate is true', () => {
140+
const component = render(
141+
<EuiBreadcrumbs
142+
breadcrumbs={[
143+
{ text: 'A' },
144+
{ text: 'B', 'data-test-subj': 'last', truncate: true },
145+
]}
146+
truncate
147+
/>
148+
);
149+
expect(getBreadcrumbClass(component, 'last')).toEqual(
150+
'emotion-euiBreadcrumb__content-page-isTruncated-euiTextColor-default'
151+
);
152+
});
153+
154+
it('does not set any truncation classes if truncate is false', () => {
155+
const component = render(
156+
<EuiBreadcrumbs
157+
breadcrumbs={[
158+
{ text: 'A' },
159+
{ text: 'B', 'data-test-subj': 'last', truncate: false },
160+
]}
161+
truncate
162+
/>
163+
);
164+
expect(getBreadcrumbClass(component, 'last')).toEqual(
165+
'emotion-euiBreadcrumb__content-page-euiTextColor-default'
166+
);
167+
});
168+
});
169+
});
170+
});
171+
77172
describe('props', () => {
78173
describe('responsive', () => {
79174
test('is rendered', () => {
@@ -101,15 +196,6 @@ describe('EuiBreadcrumbs', () => {
101196
});
102197
});
103198

104-
describe('truncate as false', () => {
105-
test('is rendered', () => {
106-
const component = render(
107-
<EuiBreadcrumbs breadcrumbs={breadcrumbs} truncate={false} />
108-
);
109-
expect(component).toMatchSnapshot();
110-
});
111-
});
112-
113199
describe('max', () => {
114200
test('renders 1 item', () => {
115201
const component = render(

src/components/breadcrumbs/breadcrumbs.tsx

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ export const EuiBreadcrumbs: FunctionComponent<EuiBreadcrumbsProps> = ({
120120
const isLastBreadcrumb = index === visibleBreadcrumbs.length - 1;
121121
const isOnlyBreadcrumb = visibleBreadcrumbs.length === 1;
122122

123-
const sharedProps = { type, truncate };
123+
const sharedProps = { type, truncate: breadcrumb.truncate ?? truncate };
124124

125125
return breadcrumb.isCollapsedButton ? (
126126
<EuiBreadcrumbCollapsed
@@ -139,14 +139,17 @@ export const EuiBreadcrumbs: FunctionComponent<EuiBreadcrumbsProps> = ({
139139
) : (
140140
<EuiBreadcrumb key={index} {...sharedProps}>
141141
<EuiBreadcrumbContent
142+
{...breadcrumb}
143+
{...sharedProps}
142144
isFirstBreadcrumb={isFirstBreadcrumb}
143145
isLastBreadcrumb={isLastBreadcrumb}
144146
isOnlyBreadcrumb={isOnlyBreadcrumb}
145147
highlightLastBreadcrumb={
146148
isLastBreadcrumb && lastBreadcrumbIsCurrentPage
147149
}
148-
{...sharedProps}
149-
{...breadcrumb}
150+
truncateLastBreadcrumb={
151+
isLastBreadcrumb && truncate && breadcrumb.truncate == null
152+
}
150153
/>
151154
</EuiBreadcrumb>
152155
);

upcoming_changelogs/6280.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
**Bug fixes**
2+
3+
- Fixed the last breadcrumb in `EuiBreadcrumbs`'s `breadcrumbs` array not respecting `truncate` overrides

0 commit comments

Comments
 (0)