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

Simplify flyout children logic by adding EuiNavDrawerGroup #4

Merged
merged 1 commit into from
Mar 11, 2019
Merged
Show file tree
Hide file tree
Changes from all 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
10 changes: 5 additions & 5 deletions src-docs/src/views/nav_drawer/nav_drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ import {
EuiHeaderLogo,
EuiIcon,
EuiTitle,
EuiNavDrawerGroup,
EuiNavDrawer,
EuiListGroup,
EuiHorizontalRule,
EuiShowFor,
EuiFocusTrap,
Expand Down Expand Up @@ -493,13 +493,13 @@ export default class extends Component {
</EuiHeaderSection>
</EuiHeader>
<EuiNavDrawer ref={this.setNavDrawerRef}>
<EuiListGroup listItems={this.topLinks} />
<EuiNavDrawerGroup listItems={this.topLinks} />
<EuiHorizontalRule margin="none" />
<EuiListGroup listItems={this.exploreLinks} />
<EuiNavDrawerGroup listItems={this.exploreLinks} />
<EuiHorizontalRule margin="none" />
<EuiListGroup listItems={this.solutionsLinks} />
<EuiNavDrawerGroup listItems={this.solutionsLinks} />
<EuiHorizontalRule margin="none" />
<EuiListGroup listItems={this.adminLinks} />
<EuiNavDrawerGroup listItems={this.adminLinks}/>
</EuiNavDrawer>
<EuiPage className="euiNavDrawerPage">
<EuiPageBody className="euiNavDrawerPage__pageBody">
Expand Down
1 change: 1 addition & 0 deletions src/components/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,7 @@ export {

export {
EuiNavDrawer,
EuiNavDrawerGroup,
EuiNavDrawerFlyout,
} from './nav_drawer';

Expand Down
4 changes: 4 additions & 0 deletions src/components/nav_drawer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@ export {
EuiNavDrawer,
} from './nav_drawer';

export {
EuiNavDrawerGroup,
} from './nav_drawer_group';

export {
EuiNavDrawerFlyout,
} from './nav_drawer_flyout';
95 changes: 8 additions & 87 deletions src/components/nav_drawer/nav_drawer.js
Original file line number Diff line number Diff line change
Expand Up @@ -180,93 +180,14 @@ export class EuiNavDrawer extends Component {
let modifiedChildren = children;

// 1. Loop through the EuiNavDrawer children (EuiListGroup, EuiHorizontalRules, etc)
modifiedChildren = React.Children.map(this.props.children, (child, childIndex) => {

// 2a. Check if child is an EuiListGroup (i.e. not an EuiHorizontalRule)
if (child.type.name === 'EuiListGroup') {

// 3a. Loop through list items passed as an array on EuiListGroup
if (typeof child.props.listItems !== 'undefined') {
const listItemArray = child.props.listItems;
const modifiedListItems = listItemArray.map((item) => {
// 4. If there is a flyoutMenu prop, then add an onClick prop
if (item.flyoutMenu) {
const { flyoutMenu, ...itemProps } = item;
return {
onClick: () => this.expandFlyout(flyoutMenu.listItems, flyoutMenu.title),
...itemProps
};
}
return item;
});
child = ({ ...child, ...{
props: ({ ...child.props, ...{ listItems: modifiedListItems } })
} });
}

// 3b. Loop through list itmes passed as separate EuiListGroupItem components
if (typeof child.props.children !== 'undefined') {
const listGroupItems = child.props.children;

// 4. If there is a flyoutMenu prop, then add an onClick prop
// If only one child, then there is no index; props is top level
if (listGroupItems.props) {
const item = React.cloneElement(listGroupItems, {
onClick: listGroupItems.props.flyoutMenu ?
() => this.expandFlyout(
listGroupItems.props.flyoutMenu.listItems,
listGroupItems.props.flyoutMenu.title
)
: null,
});

// Remove `flyoutMenu` so it doesn't get passed to the DOM
const {
flyoutMenu, // eslint-disable-line no-unused-vars
...itemProps
} = item.props;

child = React.cloneElement(child, {
key: childIndex,
children: ({ ...item, ...{ props: { ...itemProps } } })
});
// If more than one child, then there is an index
} else {
child = React.cloneElement(child, {
key: childIndex,
children: Object.keys(listGroupItems).map((key, itemIndex) => {
const item = React.cloneElement(listGroupItems[key], {
key: itemIndex,
onClick: listGroupItems[itemIndex].props.flyoutMenu ?
() => this.expandFlyout(
listGroupItems[itemIndex].props.flyoutMenu.listItems,
listGroupItems[itemIndex].props.flyoutMenu.title
)
: null,
});

// Remove `flyoutMenu` so it doesn't get passed to the DOM
const {
flyoutMenu, // eslint-disable-line no-unused-vars
...itemProps
} = item.props;

return ({ ...item, ...{ props: { ...itemProps } } });
})
});
}
}

// 5. If showToolTips passed and currently enabled, add showToolTips prop to EuiListGroup
if (this.state.toolTipsEnabled && showToolTips) {
return React.cloneElement(child, {
showToolTips: true
});
} else {
return child;
}

// 2b. Child is not an EuiListGroup, so just return it as-is
modifiedChildren = React.Children.map(this.props.children, child => {
// 2. Check if child is an EuiNavDrawerGroup and if it does have a flyout, add the expand function
if (child.type.name === 'EuiNavDrawerGroup') {
const item = React.cloneElement(child, {
flyoutMenuButtonClick: this.expandFlyout,
showToolTips: this.state.toolTipsEnabled && showToolTips,
});
return item;
} else {
return child;
}
Expand Down
48 changes: 48 additions & 0 deletions src/components/nav_drawer/nav_drawer_group.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import React from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';

import { EuiListGroup } from '../list_group/list_group';

export const EuiNavDrawerGroup = ({ className, listItems, flyoutMenuButtonClick, ...rest }) => {
const classes = classNames(
'euiNavDrawerGroup',
className
);

// Create handlers if flyoutMenu exists
const newListItems = listItems.map((item) => {
// If the flyout menu exists, pass back the list of times and the title with the onClick handler of the item
if (item.flyoutMenu && flyoutMenuButtonClick) {
const items = [...item.flyoutMenu.listItems];
const title = `${item.flyoutMenu.title}`;
item.onClick = () => flyoutMenuButtonClick(items, title);
}

// Then remove the flyoutMenu key
delete item.flyoutMenu;

// And return the item
return item;
});


return (
<EuiListGroup className={classes} listItems={newListItems} {...rest} />
);
};

EuiNavDrawerGroup.propTypes = {
listItems: PropTypes.arrayOf(PropTypes.shape({
...EuiListGroup.propTypes.listItems[0],
flyoutMenu: PropTypes.shape({
title: PropTypes.string.isRequired,
listItems: EuiListGroup.propTypes.listItems.isRequired,
}),
})).isRequired,
/**
* While not normally required, it is required to pass a function for handling
* of the flyout menu button click
*/
flyoutMenuButtonClick: PropTypes.func,
};