Why Gemfury? Push, build, and install  RubyGems npm packages Python packages Maven artifacts PHP packages Go Modules Debian packages RPM packages NuGet packages

Repository URL to install this package:

Details    
Size: Mime:
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;