/* @flow */

import React, {PropTypes} from 'react';
import FloatAnchor from 'react-float-anchor';
import MenuListInspector from './MenuListInspector';

type State = {
  opened: boolean;
};

export default class MenuButton extends React.Component {
  static propTypes = {
    className: PropTypes.string,
    style: PropTypes.object,
    disabled: PropTypes.bool,
    title: PropTypes.string,
    openedClassName: PropTypes.string,
    openedStyle: PropTypes.object,

    positionOptions: PropTypes.object,
    zIndex: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),

    children: PropTypes.node,
    menu: PropTypes.element,
    onWillOpen: PropTypes.func,
    onDidOpen: PropTypes.func,
    onWillClose: PropTypes.func
  };

  static defaultProps = {
    positionOptions: {position:'bottom', hAlign:'left'}
  };

  state: State = {
    opened: false
  };

  open() {
    if (this.state.opened) return;
    if (this.props.onWillOpen) this.props.onWillOpen();
    this.setState({opened: true}, this.props.onDidOpen);
  }

  close() {
    if (!this.state.opened) return;
    if (this.props.onWillClose) this.props.onWillClose();
    this.setState({opened: false});
  }

  toggle() {
    if (this.state.opened) {
      this.close();
    } else {
      this.open();
    }
  }

  _itemChosen() {
    this.close();
  }

  render() {
    const {
      children, menu,
      positionOptions, zIndex,
      disabled, title
    } = this.props;
    const {opened} = this.state;

    let style = this.props.style;
    let className = this.props.className;
    if (opened) {
      if (this.props.openedStyle) {
        style = {...style, ...this.props.openedStyle};
      }
      if (this.props.openedClassName) {
        className = `${className||''} ${this.props.openedClassName}`;
      }
    }

    return (
      <FloatAnchor
        options={positionOptions}
        zIndex={zIndex}
        anchor={
          <button
            type="button"
            className={className}
            style={style}
            onBlur={()=>this.close()}
            onMouseDown={()=>this.toggle()}
            onKeyDown={e=>{
              if (e.key === 'Enter' || e.key === ' ') {
                this.toggle();
              } else if (e.key === 'Escape' && opened) {
                this.close();
                e.preventDefault();
                e.stopPropagation();
              }
            }}
            aria-haspopup={true}
            aria-expanded={opened}
            disabled={disabled}
            title={title}
          >
            {children}
          </button>
        }
        float={
          !opened ? null :
            <MenuListInspector onItemChosen={() => this._itemChosen()}>
              {menu}
            </MenuListInspector>
        }
      />
    );
  }
}

@@ -863,16 +863,424 @@
 e%0A  %7D;%0A%0A
+  // Safari and Firefox on OS X don't focus the button on mousedown, so on%0A  // mousedown we do a quick setTimeout and focus a dummy child element if the%0A  // button wasn't focused.%0A  _focusFixerTimeout: any = null;%0A%0A  // Set to true after mousedown until the focus event happens. When it's true,%0A  // blur events on the dummy child element should not cause the menu to close.%0A  _focusing: boolean = false;%0A%0A
   open()
@@ -1728,16 +1728,91 @@
 );%0A  %7D%0A%0A
+  componentWillUnmount() %7B%0A    clearTimeout(this._focusFixerTimeout);%0A  %7D%0A%0A
   render
@@ -2426,16 +2426,41 @@
 button%22%0A
+            ref=%22button%22%0A
         
@@ -2529,74 +2529,683 @@
   on
-Blur=%7B()=%3Ethis.close()%7D%0A            onMouseDown=%7B()=%3Ethis.toggle()
+Focus=%7B()=%3E%7B%0A              this._focusing = false;%0A              clearTimeout(this._focusFixerTimeout);%0A            %7D%7D%0A            onBlur=%7B()=%3E%7B%0A              clearTimeout(this._focusFixerTimeout);%0A              this.close();%0A            %7D%7D%0A            onMouseDown=%7B()=%3E%7B%0A              clearTimeout(this._focusFixerTimeout);%0A              if (!opened) %7B%0A                this._focusing = true;%0A                this._focusFixerTimeout = setTimeout(() =%3E %7B%0A                  if (document.activeElement !== this.refs.button) %7B%0A                    this.refs.focusHolder.focus();%0A                  %7D%0A                %7D, 0);%0A              %7D%0A              this.toggle();%0A            %7D
 %7D%0A  
@@ -3219,20 +3219,21 @@
    onKey
-Down
+Press
 =%7Be=%3E%7B%0A 
@@ -3333,21 +3333,73 @@
        %7D
- else
+%0A            %7D%7D%0A            onKeyDown=%7Be=%3E%7B%0A             
  if (e.k
@@ -3699,16 +3699,479 @@
       %3E%0A
+            %3Cdiv%0A              ref=%22focusHolder%22%0A              tabIndex=%22-1%22%0A              aria-hidden=%7Btrue%7D%0A              style=%7B%7B%0A                opacity: '0',%0A                outline: 'none',%0A                width: '0px',%0A                height: '0px',%0A                overflow: 'hidden'%0A              %7D%7D%0A              onBlur=%7Be=%3E%7B%0A                if (this._focusing) %7B%0A                  e.stopPropagation();%0A                %7D%0A              %7D%7D%0A            /%3E%0A
         

Fix menuButton closing in Safari and Firefox on OS X.