Skip to content
Open
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: 10 additions & 0 deletions src/Nav/Nav.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,16 @@
height: auto;
}

.horizontal {
display: flex;
flex-direction: row;
}

.nav a {
text-decoration: none;
}

.horizontal.nav .nav li:not(:first-child) {
position: absolute;
z-index: 9998;
}
182 changes: 145 additions & 37 deletions src/Nav/Nav.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,11 @@ export class Nav extends React.Component {
super(props);
this.state = {
"activeIndex": props.activeIndex, // The index of selected menu item.
"collapsed": props.collapsed // Whether or not sub-nav menu collapsed.
"collapsed": props.collapsed, // Whether or not sub-nav menu collapsed.
"subNavItemHeight": 0, // the NavItem's height in subNav
"subNavItemMaxWidth": 0
};
this.subNavItemRef = React.createRef();
}

UNSAFE_componentWillReceiveProps(nextProps) {
Expand All @@ -34,50 +37,130 @@ export class Nav extends React.Component {
}
};

_buildNavByData = () => {
const { className, data, ignoreActive, onClick, style } = this.props;
_setDimension = (height, width) => {
console.log("height", height);
console.log("width", width);
if (width > 0 && width > this.state.subNavItemMaxWidth) {
this.setState({
"subNavItemHeight": height,
"subNavItemMaxWidth": width
});
} else {
this.setState({
"subNavItemHeight": height
});
}
};

// use this ternary helper to avoid nested ternary in JSX
// not working for _buidNavByData
widthStyleTernaryHelper = (cond1, cond2, child, index, data) => {
let tempIndex = index;
if (cond1 && cond2) {
if (data) {
tempIndex += 2;
}
return {
"transform": `translateY(${(tempIndex - 1) *
this.state.subNavItemHeight}px)`,
"width": `${this.state.subNavItemMaxWidth}px`,
...child.style
};
} else if (cond1 && !cond2) {
if (data) {
tempIndex += 2;
}
return {
"transform": `translateY(${(tempIndex - 1) *
this.state.subNavItemHeight}px)`,
...child.style
};
} else {
return child.style;
}
};

_buildNavByData = data => {
const {
className,
ignoreActive,
onClick,
style,
subNav,
horizontal
} = this.props;
return (
<Nav
styleName={cx("nav")}
styleName={
horizontal && typeof subNav === "undefined"
? cx("nav", "horizontal")
: cx("nav")
}
className={className}
style={style}
activeIndex={this.state.activeIndex}
onClick={onClick}
ignoreActive={ignoreActive}
horizontal={horizontal}
>
{data.map(nav => {
const { title, collapsed, ...others } = nav;
if (!nav.subNav) {
if (nav.subNavArray) {
return (
// If NavItem has a subNav, wrap it in a new Nav
<Nav
key={"nav_" + nav.navKey}
styleName={
horizontal && typeof subNav === "undefined"
? cx("nav", "horizontal")
: cx("nav")
}
collapsed={collapsed}
onClick={onClick}
horizontal={horizontal}
>
{/* The following NavItem component is the parent for a collapsible group. */}
<NavItem
key={"navItem_" + nav.navKey}
horizontal={horizontal}
{...others}
>
{title}
</NavItem>
{nav.subNavArray.map((subNavbar, index) => {
const { ...otherArgs } = subNavbar;
return (
<NavItem
key={"navItem_" + subNavbar.navKey}
horizontal={horizontal}
ref={horizontal && subNav ? this.subNavItemRef : null}
style={this.widthStyleTernaryHelper(
true,
true,
subNavbar,
index,
true
)}
{...otherArgs}
>
{subNavbar.title}
</NavItem>
);
})}
</Nav>
);
} else {
return (
// NavItems with no subNav
<NavItem key={"navItem_" + nav.navKey} {...others}>
<NavItem
key={"navItem_" + nav.navKey}
horizontal={horizontal}
{...others}
>
{title}
</NavItem>
);
}

return (
// If NavItem has a subNav, wrap it in a new Nav
<Nav
key={"nav_" + nav.navKey}
styleName={cx("nav")}
collapsed={collapsed}
onClick={onClick}
>
{/* The following NavItem component is the parent for a collapsible group. */}
<NavItem key={"navItem_" + nav.navKey} {...others}>
{title}
</NavItem>
{nav.subNav.map(subNav => {
const { ...otherArgs } = subNav;
return (
<NavItem key={"navItem_" + subNav.navKey} {...otherArgs}>
{subNav.title}
</NavItem>
);
})}
</Nav>
);
})}
</Nav>
);
Expand All @@ -90,15 +173,21 @@ export class Nav extends React.Component {
data,
ignoreActive,
style,
subNav
subNav,
horizontal
} = this.props;
let styleName;
if (data) {
return this._buildNavByData();
return this._buildNavByData(data);
}
// Avoid to append styleName to ul if rendering from json data.
styleName =
className.indexOf("ra_Nav__nav") === -1 ? { "styleName": cx("nav") } : {};
className.indexOf("ra_Nav__nav") === -1
? horizontal && typeof subNav === "undefined"
? { "styleName": cx("nav", "horizontal") }
: { "styleName": cx("nav") }
: {};

return (
<ul {...styleName} className={className} style={style}>
{React.Children.map(children, (child, index) => {
Expand All @@ -116,7 +205,8 @@ export class Nav extends React.Component {
"activeIndex": this.state.activeIndex,
"subNav": true,
"onClick": this._handleClick,
"ignoreActive": ignoreActive
"ignoreActive": ignoreActive,
horizontal
});
}
let isParent = subNav && index === 0;
Expand All @@ -126,7 +216,20 @@ export class Nav extends React.Component {
"parent": isParent,
"collapsed": this.state.collapsed,
active,
"onClick": isParent ? this._handleCollapse : this._handleClick
"onClick": isParent ? this._handleCollapse : this._handleClick,
horizontal,
"ref": horizontal && !isParent && subNav ? this.subNavItemRef : null,
"dimension": this._setDimension,
"style": this.widthStyleTernaryHelper(
horizontal && !isParent && subNav,
horizontal &&
!isParent &&
subNav &&
this.state.subNavItemMaxWidth > 0,
child.props,
index,
false
)
});
})}
</ul>
Expand All @@ -151,21 +254,26 @@ Nav.propTypes = {
"data": PropTypes.array,
/** Set to true if you intend to set an active style externally. */
"ignoreActive": PropTypes.bool,
/** Function that will be executed when onClick event occurs. */
/** Function that will be executed when onClick event occurs.
* @ignore
* */
"onClick": PropTypes.func,
/** Pass inline styling here. */
"style": PropTypes.object,
/** Set true If is a sub-Nav container, not a public prop.
* @ignore
*/
"subNav": PropTypes.bool
"subNav": PropTypes.bool,
/** Define whether the Nav is vertical or horizontal, Nav is vertical by default */
"horizontal": PropTypes.bool
};

Nav.defaultProps = {
"className": "",
"collapsed": false,
"data": null,
"ignoreActive": false
"ignoreActive": false,
"horizontal": false
};

export default CSSModules(Nav, styles, { "allowMultiple": true });
34 changes: 29 additions & 5 deletions src/Nav/README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,36 @@
Basic Nav component:
Basic Vertical Nav component:
<Nav activeIndex={0}>
<NavItem navKey={0}>Home</NavItem>
<NavItem navKey={1}>Catalog</NavItem>
<NavItem navKey={2}>Customer Service</NavItem>
<NavItem navKey={3}>Administration</NavItem>
<NavItem navKey={4}>Support</NavItem>
</Nav>


Basic Horizontal Nav component:
<Nav activeIndex={0} horizontal>
<NavItem navKey={0}>Home</NavItem>
<NavItem navKey={1}>Catalog</NavItem>
<NavItem navKey={2}>Customer Service</NavItem>
<NavItem navKey={3}>Administration</NavItem>
<NavItem navKey={4}>Support</NavItem>
</Nav>

Horizontal Nav with sub-NavItems:
<Nav activeIndex={0} horizontal>
<NavItem navKey={0}>Home</NavItem>
<NavItem navKey={1}>Catalog</NavItem>
<NavItem navKey={2}>Customer Service</NavItem>
<Nav collapsed>
<NavItem navKey={3}>Reports</NavItem>
<NavItem navKey={3.1}>Create a Report</NavItem>
<NavItem navKey={3.2}>Edit a Report</NavItem>
<NavItem navKey={3.3}>Delete a Report</NavItem>
</Nav>
<NavItem navKey={4}>Administration</NavItem>
<NavItem navKey={5}>Support</NavItem>
</Nav>

Nav with sub-NavItems:
<Nav activeIndex={0}>
<NavItem navKey={0}>Home</NavItem>
Expand Down Expand Up @@ -102,7 +126,7 @@ Build Nav Menu via data attribute:
"navKey": 3,
"title": "Reports",
"collapsed": true,
"subNav": [
"subNavArray": [
{
"navKey": 3.1,
"title": "Create a Report"
Expand All @@ -120,7 +144,7 @@ Build Nav Menu via data attribute:
];

_handleClick = (selectedIndex) => console.log('Item ' + selectedIndex + ' has been selected.');
<Nav activeIndex={1} data={data} onClick={_handleClick} />
<Nav horizontal activeIndex={1} data={data} onClick={_handleClick} />

Nav component with a routing library. Use the `as` property to define the component name (e.g. `Link` from react-router) and pass any router specific props to your NavItem component:

Expand All @@ -146,7 +170,7 @@ Nav component with React-Router using data instead of children:
"navKey": 0,
"title": "Form Components",
"collapsed": true,
"subNav": [
"subNavArray": [
{
"navKey": 0.1,
"to": "button",
Expand Down
Loading