revenge-react-components
Version:
react-components for revenge https://github.com/buildo/revenge
129 lines (111 loc) • 3.13 kB
JavaScript
import React from 'react';
import { pure, props, t, skinnable } from 'revenge';
import Menu, { optionType } from './Menu';
import { FlexView } from 'buildo-react-components';
import Icon from '../Icon/Icon';
import cx from 'classnames';
import './dropdownMenu.scss';
export const Props = {
children: t.maybe(t.ReactNode),
options: t.list(optionType),
iconClassName: t.maybe(t.Str), // if children is passed, this is ignored
initiallyOpen: t.maybe(t.Bool),
dismissOnClickOut: t.maybe(t.Bool),
size: t.maybe(t.enums.of(['small', 'medium', 'large']), ''),
maxHeight: t.maybe(t.Num),
className: t.maybe(t.Str)
};
()
(Props)
export default class DropdownMenu extends React.Component {
constructor(props) {
super(props);
this.state = {
isOpen: props.initiallyOpen
};
}
static defaultProps = {
initiallyOpen: false,
dismissOnClickOut: true
}
toggleMenu = () => {
this.setState({ isOpen: !this.state.isOpen });
}
onMenuClick = () => {
this.toggleMenu();
}
getHeightFromSize = size => {
switch (size) {
case 'small': return 250;
case 'medium': return 400;
case 'large': return 600;
default: return null;
}
}
getLocals() {
const {
toggleMenu,
onMenuClick,
props: {
iconClassName,
children,
options,
dismissOnClickOut,
maxHeight,
className,
size
},
state: {
isOpen
}
} = this;
const height = maxHeight || this.getHeightFromSize(size);
return {
toggleMenu,
iconClassName,
children,
options,
isOpen,
dismissOnClickOut,
onMenuClick,
className,
height
};
}
templateToggler = ({ children, iconClassName, toggleMenu, isOpen }) => {
return (
children || this.templateIconButton({ iconClassName, toggleMenu, isOpen })
);
}
templateIconButton = ({ iconClassName, toggleMenu, isOpen }) => {
return (
<FlexView vAlignContent="center" className={cx('dropdown-menu-icon-container', { isOpen })}>
<Icon icon={iconClassName} className='dropdown-menu-icon' />
</FlexView>
);
}
templateMenu = ({ isOpen, options, height, onMenuClick }) => {
return (
isOpen ?
<Menu {...{ options }} maxHeight={height} onClick={onMenuClick} />
: null
);
}
templateOverlay = ({ isOpen, toggleMenu, dismissOnClickOut }) => {
return (
dismissOnClickOut && isOpen ?
<div className='dropdown-menu-overlay' onClick={toggleMenu} />
: null
);
}
template({ iconClassName, toggleMenu, children, options, isOpen, dismissOnClickOut, className, onMenuClick, height }) {
return (
<FlexView vAlignContent="center" className={cx('dropdown-menu', className)} onClick={toggleMenu}>
{this.templateOverlay({ isOpen, toggleMenu, dismissOnClickOut })}
{this.templateToggler({ children, iconClassName, toggleMenu, isOpen })}
{this.templateMenu({ isOpen, options, height, toggleMenu, onMenuClick })}
</FlexView>
);
}
}