Repository URL to install this package:
|
Version:
8.1.0-rc.5 ▾
|
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import classnames from 'classnames';
import { Wrapper, Button, Menu as ReactMenu, MenuItem } from 'react-aria-menubutton';
import pickDataAttributes from '../../utils/pickDataAttributes';
import { buttonVariants, defaultButtonVariant } from '../Button/Button';
export const menuDimensions = ['compact', 'very-compact'];
export const defaultMenuDimension = null;
class Menu extends Component {
static propTypes = {
dimension: PropTypes.oneOf(menuDimensions),
children: PropTypes.any.isRequired,
items: PropTypes.arrayOf(
PropTypes.shape({
label: PropTypes.node.isRequired,
to: PropTypes.string,
action: PropTypes.func,
key: PropTypes.string,
target: PropTypes.string,
})
).isRequired,
className: PropTypes.string,
/** Determines if the menu will use the <nav> html tag. Use if the menu will contain ONLY links */
navigational: PropTypes.bool,
variant: PropTypes.oneOf(buttonVariants),
horizontalAlign: PropTypes.oneOf(['left', 'right']),
position: PropTypes.oneOf(['bottom', 'top']),
disabled: PropTypes.bool,
closeOnSelection: PropTypes.bool,
};
static defaultProps = {
dimension: defaultMenuDimension,
className: null,
navigational: false,
horizontalAlign: 'left',
position: 'bottom',
disabled: false,
variant: defaultButtonVariant,
closeOnSelection: true,
};
handleSelection = selectedValue => {
const itemSelected = this.props.items.find(item => {
if (typeof selectedValue === 'string') {
return item.label === selectedValue;
} else if (Array.isArray(selectedValue)) {
// multiple children, e.g. label and description
return item.label === selectedValue[0];
}
return null;
});
if (itemSelected && itemSelected.action) {
itemSelected.action();
}
};
render() {
const {
dimension,
children,
items,
className,
navigational,
variant,
horizontalAlign,
position,
disabled,
closeOnSelection,
} = this.props;
const componentClassName = classnames('Menu', className);
const menuButtonClassnames = classnames('Button', {
[`Button--${variant}`]: variant,
[`Button--compact`]: dimension === 'compact',
[`Button--very-compact`]: dimension === 'very-compact',
});
const menuListClassnames = classnames('Menu-list', {
[`Menu-list--position-${position}`]: position,
[`Menu-list--align-${horizontalAlign}`]: horizontalAlign,
});
return (
<Wrapper
tag={navigational ? 'nav' : 'div'}
className={componentClassName}
onSelection={this.handleSelection}
closeOnSelection={closeOnSelection}
>
<Button className={menuButtonClassnames} disabled={disabled || items.length === 0}>
{children}
</Button>
{items.length > 0 && (
<ReactMenu className={menuListClassnames} tag="ul">
{items.map(({ label, description, to, target, key, ...attributes }, index) => (
<li key={key || index}>
<MenuItem
className="Menu-item"
tag={to ? 'a' : 'span'}
href={to}
target={target}
{...pickDataAttributes(attributes)}
>
{label}
{description && <div className="body--soft">{description}</div>}
</MenuItem>
</li>
))}
</ReactMenu>
)}
</Wrapper>
);
}
}
export default Menu;