import { ObjectMap } from '@0xproject/types';
import * as _ from 'lodash';
import MenuItem from 'material-ui/MenuItem';
import * as React from 'react';
import { ALink, Styles } from '../types';
import { colors } from '../utils/colors';
import { utils } from '../utils/utils';
import { Link } from './link';
export interface NestedSidebarMenuProps {
sectionNameToLinks: ObjectMap<ALink[]>;
sidebarHeader?: React.ReactNode;
shouldDisplaySectionHeaders?: boolean;
shouldReformatMenuItemNames?: boolean;
parentName?: string;
}
export interface NestedSidebarMenuState {
scrolledToId: string;
}
const styles: Styles = {
menuItemWithHeaders: {
minHeight: 0,
},
menuItemWithoutHeaders: {
minHeight: 48,
},
menuItemInnerDivWithHeaders: {
color: colors.grey800,
fontSize: 14,
lineHeight: 2,
padding: 0,
whiteSpace: 'nowrap',
overflow: 'hidden',
textOverflow: 'ellipsis',
},
};
export class NestedSidebarMenu extends React.Component<NestedSidebarMenuProps, NestedSidebarMenuState> {
public static defaultProps: Partial<NestedSidebarMenuProps> = {
shouldDisplaySectionHeaders: true,
shouldReformatMenuItemNames: true,
parentName: 'default',
};
private _urlIntervalCheckId: number;
constructor(props: NestedSidebarMenuProps) {
super(props);
this.state = {
scrolledToId: '',
};
}
public componentDidMount(): void {
this._urlIntervalCheckId = window.setInterval(() => {
const scrollId = location.hash.slice(1);
if (scrollId !== this.state.scrolledToId) {
this.setState({
scrolledToId: scrollId,
});
}
}, 200);
}
public componentWillUnmount(): void {
window.clearInterval(this._urlIntervalCheckId);
}
public render(): React.ReactNode {
const navigation = _.map(this.props.sectionNameToLinks, (links: ALink[], sectionName: string) => {
const finalSectionName = utils.convertCamelCaseToSpaces(sectionName);
if (this.props.shouldDisplaySectionHeaders) {
// tslint:disable-next-line:no-unused-variable
return (
<div key={`section-${sectionName}`} className="py1" style={{ color: colors.greyTheme }}>
<div style={{ fontSize: 14, letterSpacing: 0.5 }} className="py1 pl1">
{finalSectionName.toUpperCase()}
</div>
{this._renderMenuItems(links)}
</div>
);
} else {
return <div key={`section-${sectionName}`}>{this._renderMenuItems(links)}</div>;
}
});
return (
<div>
{this.props.sidebarHeader}
<div>{navigation}</div>
</div>
);
}
private _renderMenuItems(links: ALink[]): React.ReactNode[] {
const scrolledToId = this.state.scrolledToId;
const menuItemStyles = this.props.shouldDisplaySectionHeaders
? styles.menuItemWithHeaders
: styles.menuItemWithoutHeaders;
const menuItemInnerDivStyles = this.props.shouldDisplaySectionHeaders ? styles.menuItemInnerDivWithHeaders : {};
const menuItems = _.map(links, link => {
const isScrolledTo = link.to === scrolledToId;
const finalMenuItemName = this.props.shouldReformatMenuItemNames
? utils.convertDashesToSpaces(link.title)
: link.title;
return (
<div key={`menuItem-${finalMenuItemName}`}>
<Link to={link.to} shouldOpenInNewTab={link.shouldOpenInNewTab}>
<MenuItem
style={{
...menuItemStyles,
paddingLeft: 8,
borderRadius: 6,
backgroundColor: isScrolledTo ? colors.lightLinkBlue : 'inherit',
}}
innerDivStyle={{
...menuItemInnerDivStyles,
color: isScrolledTo ? colors.white : 'inherit',
fontWeight: isScrolledTo ? 'bold' : 'inherit',
}}
>
<span
style={{
textTransform: this.props.shouldReformatMenuItemNames ? 'capitalize' : 'none',
}}
>
{finalMenuItemName}
</span>
</MenuItem>
</Link>
</div>
);
});
return menuItems;
}
}