@momentum-ui/react
Version:
Cisco Momentum UI framework for ReactJs applications
221 lines (198 loc) • 5.53 kB
JavaScript
/** @component sidebar */
import React from 'react';
import PropTypes from 'prop-types';
import omit from 'lodash/omit';
import { Icon, ListItem, ListItemSection } from '@momentum-ui/react';
import SidebarContext from '../SidebarContext';
import SidebarNavContext from '../SidebarNavContext';
import mapContextToProps from '@restart/context/mapContextToProps';
import { UIDConsumer, UIDFork } from 'react-uid';
class SidebarNavItem extends React.Component {
state = {
expanded: this.props.expanded
};
componentDidMount() {
this.setParentContext();
}
componentDidUpdate(prevProps) {
this.props.expanded !== prevProps.expanded
&& this.state.expanded !== this.props.expanded
&& this.setExpanded();
}
handleNavToggle = () => {
this.setState({
expanded: !this.state.expanded
});
}
setExpanded = () => {
this.setState({ expanded: this.props.expanded });
}
getHeaderLevel = () => {
const { level } = this.props;
if (!level) {
return 'primary';
} else if (level === 'primary') {
return 'secondary';
} else if (level === 'secondary') {
return 'tertiary';
}
}
setParentContext = () => {
const { children, setContext } = this.props;
const nextLevel = children && this.getHeaderLevel() || 'primary';
nextLevel
&& setContext
&& setContext(nextLevel);
}
render() {
const {
children,
className,
level,
icon,
keyboardKey,
title,
titleNode,
...props
} = this.props;
const { expanded } = this.state;
const otherProps = omit({...props}, [
'expanded',
'primary',
'secondary',
'setContext',
'tertiary',
]);
const getIcon = () => {
const { secondary } = this.props;
if(typeof icon === 'string') {
return (
<Icon
name={icon}
sizeOverride
size={secondary ? 20 : 16}
/>
);
} else return icon;
};
const getSection = id => (
!titleNode
? (
<ListItem
className={className}
id={id}
keyboardKey={keyboardKey || title}
onClick={() => {children ? this.handleNavToggle() : false;}}
{...otherProps}
>
{
icon &&
<ListItemSection position='left'>
{getIcon()}
</ListItemSection>
}
<ListItemSection position='center'>
{title}
</ListItemSection>
{
children &&
<ListItemSection position='right'>
{
expanded
? <Icon name='arrow-up_12' />
: <Icon name='arrow-down_12' />
}
</ListItemSection>
}
</ListItem>
)
: React.cloneElement(titleNode, {
id,
onClick : () => {children ? this.handleNavToggle() : false;}
})
);
const getHeaderLevel = () => {
if (!level) {
return 'primary';
} else if (level === 'primary') {
return 'secondary';
} else if (level === 'secondary') {
return 'tertiary';
}
};
const headerLevel = getHeaderLevel();
return (
<UIDConsumer name={id => `md-sidebar__nav-item-${id}`}>
{id => {
return (
<React.Fragment>
{getSection(id)}
{
children &&
<UIDFork>
<div className={
'md-sidebar-nav__group' +
` md-sidebar-nav__group--${headerLevel}` +
` md-sidebar-nav__group--${(!children || expanded) ? 'expanded' : 'collapsed'}`
}>
<SidebarNavContext.Provider value={{ level: headerLevel }}>
{children}
</SidebarNavContext.Provider>
</div>
</UIDFork>
}
</React.Fragment>
);
}}
</UIDConsumer>
);
}
}
SidebarNavItem.propTypes = {
/** @prop Children nodes to Render inside side navigation | null */
children: PropTypes.node,
/** @prop Optional CSS class string | '' */
className: PropTypes.string,
/** @prop Set navigation expanded or collapsed | false */
expanded: PropTypes.bool,
/** @prop Icon string or node for the title | null */
icon: PropTypes.node,
/** @prop Unique string used for keyboard navigation | '' */
keyboardKey: PropTypes.string,
// Internal Context Use Only
level: PropTypes.string,
// Internal Context Use Only
primary: PropTypes.bool,
// Internal Context Use Only
secondary: PropTypes.bool,
// Internal Context Use Only
setContext: PropTypes.func,
// Internal Context Use Only
tertiary: PropTypes.bool,
/** @prop Node to replace title | null */
titleNode: PropTypes.node,
/** @prop Title for the side navigation | '' */
title: PropTypes.string,
};
SidebarNavItem.defaultProps = {
children: null,
expanded: false,
icon: null,
keyboardKey: '',
level: null,
primary: false,
secondary: false,
tertiary: false,
titleNode: null,
title: '',
setContext: null,
};
SidebarNavItem.displayName = 'SidebarNavItem';
export default mapContextToProps(
[SidebarContext, SidebarNavContext],
(sidebarContext, sidebarNavContext) => ({
...sidebarContext,
...sidebarNavContext
}),
SidebarNavItem
);