Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow custom components to be rendered in EuiSideNav #310

Merged
merged 4 commits into from
Jan 19, 2018
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# [`master`](https://github.com/elastic/eui/tree/master)

No public interface changes since `0.0.13`.
- In `EuiSideNav`, allow a callback to be passed that renders the individual items in the navigation. This makes interoperability with e.g. `react-router` easier. [#310](https://github.com/elastic/eui/pull/310)

# [`0.0.13`](https://github.com/elastic/eui/tree/v0.0.13)

Expand Down
85 changes: 84 additions & 1 deletion src/components/side_nav/__snapshots__/side_nav.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,90 @@ exports[`EuiSideNav items is rendered 1`] = `
</nav>
`;

exports[`EuiSideNav items renders items with are links 1`] = `
exports[`EuiSideNav items renders items using a specified callback 1`] = `
<nav
class="euiSideNav"
>
<button
class="euiSideNav__mobileToggle euiLink"
type="button"
>
<span
class="euiSideNav__mobileWrap"
>
<span
class="euiSideNav__mobileTitle"
/>
<svg
aria-hidden="true"
class="euiIcon euiSideNav__mobileIcon euiIcon--medium"
height="16"
viewBox="0 0 16 16"
width="16"
xlink="http://www.w3.org/1999/xlink"
xmlns="http://www.w3.org/2000/svg"
>
<defs>
<path
d="M2 4V2h2v2H2zm5 0V2h2v2H7zm5 0V2h2v2h-2zM2 9V7h2v2H2zm5 0V7h2v2H7zm5 0V7h2v2h-2zM2 14v-2h2v2H2zm5 0v-2h2v2H7zm5 0v-2h2v2h-2z"
id="apps-a"
/>
</defs>
<use
href="#apps-a"
/>
</svg>
</span>
</button>
<div
class="euiSideNav__content"
>
<div
class="euiSideNavItem euiSideNavItem--root"
>
<a
class="euiSideNavItemButton"
data-test-id="my-custom-element"
href="http://www.elastic.co"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label"
>
A
</span>
</span>
</a>
<div
class="euiSideNavItem__items"
>
<div
class="euiSideNavItem euiSideNavItem--trunk"
>
<a
class="euiSideNavItemButton"
data-test-id="my-custom-element"
>
<span
class="euiSideNavItemButton__content"
>
<span
class="euiSideNavItemButton__label"
>
B
</span>
</span>
</a>
</div>
</div>
</div>
</div>
</nav>
`;

exports[`EuiSideNav items renders items which are links 1`] = `
<nav
class="euiSideNav"
>
Expand Down
8 changes: 8 additions & 0 deletions src/components/side_nav/side_nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export class EuiSideNav extends Component {
};

renderTree = (items, depth = 0) => {
const { renderItem } = this.props;

return items.map((item) => {
const {
id,
Expand All @@ -35,6 +37,7 @@ export class EuiSideNav extends Component {
icon,
onClick,
href,
...rest
} = item;

// Root items are always open.
Expand All @@ -57,6 +60,8 @@ export class EuiSideNav extends Component {
items={renderedItems}
key={id}
depth={depth}
renderItem={renderItem}
{...rest}
>
{name}
</EuiSideNavItem>
Expand All @@ -71,6 +76,8 @@ export class EuiSideNav extends Component {
toggleOpenOnMobile,
isOpenOnMobile,
mobileTitle,
// Extract this one out so it isn't passed to <nav>
renderItem, // eslint-disable-line no-unused-vars
...rest
} = this.props;

Expand Down Expand Up @@ -125,6 +132,7 @@ EuiSideNav.propTypes = {
isOpenOnMobile: PropTypes.bool,
mobileTitle: PropTypes.node,
items: PropTypes.array,
renderItem: PropTypes.func,
};

EuiSideNav.defaultProps = {
Expand Down
26 changes: 25 additions & 1 deletion src/components/side_nav/side_nav.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ describe('EuiSideNav', () => {
.toMatchSnapshot();
});

test('renders items with are links', () => {
test('renders items which are links', () => {
const sideNav = [{
name: 'A',
id: 0,
Expand Down Expand Up @@ -92,6 +92,30 @@ describe('EuiSideNav', () => {
.toMatchSnapshot();
});

test('renders items using a specified callback', () => {
const sideNav = [{
name: 'A',
id: 0,
href: 'http://www.elastic.co',
items: [{
name: 'B',
id: 1,
}],
}];

const renderItem = ({ href, className, children }) => (
<a data-test-id="my-custom-element" href={href} className={className}>
{children}
</a>);

const component = render(
<EuiSideNav items={sideNav} renderItem={renderItem} />
);

expect(component)
.toMatchSnapshot();
});

test('renders selected item and automatically opens parent items', () => {
const sideNav = [{
name: 'A',
Expand Down
56 changes: 29 additions & 27 deletions src/components/side_nav/side_nav_item.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,30 @@ import {
EuiIcon,
} from '../icon';

const defaultRenderItem = ({ href, onClick, className, children, ...rest }) => {
if (href) {
return (
<a
className={className}
href={href}
{...rest}
>
{children}
</a>
);
}

return (
<button
className={className}
onClick={onClick}
{...rest}
>
{children}
</button>
);
};

export const EuiSideNavItem = ({
isOpen,
isSelected,
Expand All @@ -18,6 +42,7 @@ export const EuiSideNavItem = ({
items,
children,
depth,
renderItem = defaultRenderItem,
...rest,
}) => {
let childItems;
Expand Down Expand Up @@ -60,41 +85,17 @@ export const EuiSideNavItem = ({
<span className="euiSideNavItemButton__content">
{buttonIcon}

<span
className="euiSideNavItemButton__label"
>
<span className="euiSideNavItemButton__label">
{children}
</span>

{caret}
</span>
);

let button;

if (href) {
button = (
<a
className={buttonClasses}
href={href}
>
{buttonContent}
</a>
);
} else {
button = (
<button
className={buttonClasses}
onClick={onClick}
>
{buttonContent}
</button>
);
}

return (
<div className={classes} {...rest}>
{button}
<div className={classes}>
{renderItem({ href, onClick, className: buttonClasses, children: buttonContent, ...rest })}
{childItems}
</div>
);
Expand All @@ -110,4 +111,5 @@ EuiSideNavItem.propTypes = {
items: PropTypes.node,
children: PropTypes.node,
depth: PropTypes.number,
renderItem: PropTypes.func,
};