Skip to content

Commit aab8e8c

Browse files
committed
feat(ui-breadcrumb): add icon support
This is a follow-up commit to https://gerrit.instructure.com/164847, which only works with links, not buttons (this was an oversight). This commit passes the icon through to the underlying Link component for display. Refs INSTUI-1543 Test plan: check that all Breadcrumb examples look good Change-Id: Idb9fc3a54977d58a19b613a31e800cc9fb5ff3ef Reviewed-on: https://gerrit.instructure.com/164975 Tested-by: Jenkins Reviewed-by: Omar Khan <okhan@instructure.com> Reviewed-by: Ken Meleta <kmeleta@instructure.com> Product-Review: Ken Meleta <kmeleta@instructure.com> QA-Review: Dan Sasaki <dsasaki@instructure.com>
1 parent 04c6fa7 commit aab8e8c

File tree

9 files changed

+88
-101
lines changed

9 files changed

+88
-101
lines changed

packages/ui-breadcrumb/src/components/Breadcrumb/BreadcrumbLink/__tests__/BreadcrumbLink.test.js

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,18 +23,15 @@
2323
*/
2424

2525
import React from 'react'
26-
import Link from '@instructure/ui-elements/lib/components/Link'
2726

2827
import BreadcrumbLink from '../index'
2928

30-
import styles from '../styles.css'
31-
3229
describe('<BreadcrumbLink />', () => {
3330
const testbed = new Testbed(<BreadcrumbLink>Content</BreadcrumbLink>)
3431

35-
it('should render a Link component when given an href prop', () => {
32+
it('should render a link when given an href prop', () => {
3633
const subject = testbed.render({href: '#'})
37-
expect(subject.find(Link)).to.be.present()
34+
expect(subject.find('a')).to.be.present()
3835
})
3936

4037
it('should render as a button and respond to onClick event', () => {
@@ -44,9 +41,14 @@ describe('<BreadcrumbLink />', () => {
4441
expect(onClick).to.have.been.called()
4542
})
4643

47-
it('should not render a Link component when not given an href prop', () => {
44+
it('should not render a link when not given an href prop', () => {
45+
const subject = testbed.render()
46+
expect(subject.find('a')).not.to.be.present()
47+
})
48+
49+
it('should not render a button when not given an onClick prop', () => {
4850
const subject = testbed.render()
49-
expect(subject.find(`.${styles.text}`)).to.be.present()
51+
expect(subject.find('button')).not.to.be.present()
5052
})
5153

5254
it('should meet a11y standards', (done) => {

packages/ui-breadcrumb/src/components/Breadcrumb/BreadcrumbLink/index.js

Lines changed: 28 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -25,18 +25,13 @@
2525
import React, { Component } from 'react'
2626
import PropTypes from 'prop-types'
2727
import Link from '@instructure/ui-elements/lib/components/Link'
28-
import themeable from '@instructure/ui-themeable'
2928
import { omitProps } from '@instructure/ui-utils/lib/react/passthroughProps'
3029

31-
import styles from './styles.css'
32-
import theme from './theme'
33-
3430
/**
3531
---
3632
parent: Breadcrumb
3733
---
3834
**/
39-
@themeable(theme, styles)
4035
export default class BreadcrumbLink extends Component {
4136
static propTypes = {
4237
/**
@@ -54,35 +49,44 @@ export default class BreadcrumbLink extends Component {
5449
/**
5550
* Sets the font-size of the breadcrumb text
5651
*/
57-
size: PropTypes.oneOf(['small', 'medium', 'large'])
52+
size: PropTypes.oneOf(['small', 'medium', 'large']),
53+
/**
54+
* Add an icon to the BreadcrumbLink
55+
*/
56+
icon: PropTypes.oneOfType([PropTypes.func, PropTypes.element]),
57+
/**
58+
* Place the icon before or after the text in the BreadcrumbLink
59+
*/
60+
iconPlacement: PropTypes.oneOf(['start', 'end'])
5861
}
5962

6063
render () {
6164
const {
6265
children,
6366
href,
67+
icon,
68+
iconPlacement,
6469
onClick
6570
} = this.props
6671

6772
const props = omitProps(this.props, BreadcrumbLink.propTypes)
6873

69-
if (href || onClick) {
70-
return (
71-
<Link
72-
{...props}
73-
ellipsis
74-
href={href}
75-
onClick={onClick}
76-
>
77-
{children}
78-
</Link>
79-
)
80-
} else {
81-
return (
82-
<span className={styles.text}>
83-
<span className={styles.ellipsis}>{children}</span>
84-
</span>
85-
)
86-
}
74+
// Link will display a button by default, even if there is no action.
75+
// Force a span in this case.
76+
const as = href || onClick ? void 0 : 'span'
77+
78+
return (
79+
<Link
80+
as={as}
81+
{...props}
82+
ellipsis
83+
href={href}
84+
icon={icon}
85+
iconPlacement={iconPlacement}
86+
onClick={onClick}
87+
>
88+
{children}
89+
</Link>
90+
)
8791
}
8892
}

packages/ui-breadcrumb/src/components/Breadcrumb/BreadcrumbLink/styles.css

Lines changed: 0 additions & 14 deletions
This file was deleted.

packages/ui-breadcrumb/src/components/Breadcrumb/BreadcrumbLink/theme.js

Lines changed: 0 additions & 36 deletions
This file was deleted.

packages/ui-breadcrumb/src/components/Breadcrumb/README.md

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -68,18 +68,16 @@ example: true
6868
</Breadcrumb>
6969
```
7070

71-
You can include icons inside `BreadcrumbLink`:
71+
You can include icons in `BreadcrumbLink`:
7272

7373
```js
7474
---
7575
example: true
7676
---
77-
<Breadcrumb label="You are here:">
78-
<BreadcrumbLink href="https://instructure.github.io/instructure-ui/">
79-
<IconBank.Line size="small" /> Item Bank
80-
</BreadcrumbLink>
81-
<BreadcrumbLink href="https://instructure.github.io/instructure-ui/">History</BreadcrumbLink>
82-
<BreadcrumbLink>Question</BreadcrumbLink>
77+
<Breadcrumb label="Breadcrumb with icons">
78+
<BreadcrumbLink icon={<IconBank.Line size="small" />} href="#Breadcrumb">Item Bank</BreadcrumbLink>
79+
<BreadcrumbLink icon={<IconClock.Line size="small" />} onClick={() => {}}>History</BreadcrumbLink>
80+
<BreadcrumbLink icon={IconPlus.Line} iconPlacement="end">New Question</BreadcrumbLink>
8381
</Breadcrumb>
8482
```
8583

@@ -100,4 +98,3 @@ guidelines: true
10098
</Figure>
10199
</Guidelines>
102100
```
103-

packages/ui-breadcrumb/src/components/Breadcrumb/index.js

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import IconArrowOpenEnd from '@instructure/ui-icons/lib/Solid/IconArrowOpenEnd'
3131
import themeable from '@instructure/ui-themeable'
3232
import ThemeablePropTypes from '@instructure/ui-themeable/lib/utils/ThemeablePropTypes'
3333
import CustomPropTypes from '@instructure/ui-utils/lib/react/CustomPropTypes'
34+
import Browser from '@instructure/ui-utils/lib/Browser'
3435

3536
import BreadcrumbLink from './BreadcrumbLink'
3637

@@ -88,10 +89,16 @@ export default class Breadcrumb extends Component {
8889
}
8990

9091
render () {
92+
// FF and EDGE calculate flex baseline alignment differently, and do better with `center`
93+
// in this case: http://kizu.ru/en/blog/flex-baseline/#another-way
94+
const preferAlignCenter = Browser.firefox || Browser.msedge
95+
9196
const classes = {
9297
[styles.root]: true,
98+
[styles.preferAlignCenter]: preferAlignCenter,
9399
[styles[this.props.size]]: true
94100
}
101+
95102
return (
96103
<View
97104
role="navigation"

packages/ui-breadcrumb/src/components/Breadcrumb/styles.css

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,49 +1,71 @@
11
/* stylelint-disable selector-max-class */
22

33
.root {
4-
display: flex;
5-
flex-direction: row;
6-
align-items: baseline;
4+
font-family: var(--fontFamily);
75
margin: 0;
86
padding: 0;
97
list-style-type: none;
108
overflow: visible;
9+
display: flex;
10+
align-items: baseline;
11+
}
12+
13+
.root.preferAlignCenter {
14+
align-items: center;
1115
}
1216

1317
.crumb {
14-
display: flex;
15-
flex-direction: row;
16-
align-items: baseline;
18+
box-sizing: border-box;
19+
position: relative;
20+
}
21+
22+
.crumb:last-child {
23+
padding-inline-end: 0;
1724
}
1825

1926
.separator {
27+
box-sizing: border-box;
28+
position: absolute;
29+
top: 50%;
2030
color: var(--separatorColor);
2131
}
2232

2333
.small .crumb {
2434
font-size: var(--smallFontSize);
35+
padding-inline-end: calc(var(--smallSeparatorFontSize) * 2);
36+
padding-inline-start: 0;
2537

2638
.separator {
2739
font-size: var(--smallSeparatorFontSize);
28-
margin: 0 calc(var(--smallSeparatorFontSize) / 2);
40+
offset-inline-end: calc(var(--smallSeparatorFontSize) / 2);
41+
offset-inline-start: auto;
42+
margin-top: calc(-1 * (var(--smallSeparatorFontSize) / 2));
2943
}
3044
}
3145

3246
.medium .crumb {
3347
font-size: var(--mediumFontSize);
48+
padding-inline-end: calc(var(--mediumSeparatorFontSize) * 2);
49+
padding-inline-start: 0;
3450

3551
.separator {
3652
font-size: var(--mediumSeparatorFontSize);
37-
margin: 0 calc(var(--mediumSeparatorFontSize) / 2);
53+
offset-inline-end: calc(var(--mediumSeparatorFontSize) / 2);
54+
offset-inline-start: auto;
55+
margin-top: calc(-1 * (var(--mediumSeparatorFontSize) / 2));
3856
}
3957
}
4058

4159
.large .crumb {
4260
font-size: var(--largeFontSize);
61+
padding-inline-end: calc(var(--largeSeparatorFontSize) * 2);
62+
padding-inline-start: 0;
4363

4464
.separator {
4565
font-size: var(--largeSeparatorFontSize);
46-
margin: 0 calc(var(--largeSeparatorFontSize) / 2);
66+
offset-inline-end: calc(var(--largeSeparatorFontSize) / 2);
67+
offset-inline-start: auto;
68+
margin-top: calc(-1 * (var(--largeSeparatorFontSize) / 2));
4769
}
4870
}
4971

packages/ui-breadcrumb/src/components/Breadcrumb/theme.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424

2525
export default function generator ({ colors, typography }) {
2626
return {
27+
fontFamily: typography.fontFamily,
2728
separatorColor: colors.borderDark,
2829

2930
smallSeparatorFontSize: '0.5rem',

packages/ui-elements/src/components/Link/styles.css

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@
4747
}
4848
}
4949

50+
.root .inverse,
5051
.root a.inverse:link,
5152
.root a.inverse:visited,
5253
.root button.inverse {
@@ -79,18 +80,21 @@
7980
font-size: 1em;
8081
margin: 0;
8182
padding: 0;
82-
display: inline-flex;
83-
align-content: flex-start;
84-
text-align: inherit;
8583
}
8684

8785
.ellipsis {
86+
box-sizing: border-box;
8887
display: block;
8988
overflow: hidden;
9089
white-space: nowrap;
9190
text-overflow: ellipsis;
9291
}
9392

93+
button.ellipsis {
94+
width: 100%;
95+
text-align: start;
96+
}
97+
9498
.icon {
9599
font-size: 1.125em; /* make icon slightly larger than inherited font-size */
96100
}

0 commit comments

Comments
 (0)