'use strict';

var _extends = require('@babel/runtime/helpers/extends');
var _defineProperty = require('@babel/runtime/helpers/defineProperty');
var _slicedToArray = require('@babel/runtime/helpers/slicedToArray');
require('core-js/modules/es.symbol.js');
require('core-js/modules/es.array.concat.js');
require('core-js/modules/es.array.filter.js');
require('core-js/modules/es.array.map.js');
require('core-js/modules/es.object.assign.js');
require('core-js/modules/es.object.get-own-property-descriptor.js');
require('core-js/modules/es.object.get-own-property-descriptors.js');
require('core-js/modules/es.object.keys.js');
require('core-js/modules/es.object.to-string.js');
require('core-js/modules/web.dom-collections.for-each.js');
var React = require('react');
var PropTypes = require('prop-types');
var react = require('@carbon/react');
var classnames = require('classnames');
var useLangDirection = require('../../utils/useLangDirection.js');
var Settings = require('../../constants/Settings.js');
var deprecate = require('../../internal/deprecate.js');
var SplitMenuButton = require('./SplitMenuButton.js');
var SingleMenuButton = require('./SingleMenuButton.js');
var utils = require('./utils.js');
var iconsReact = require('@carbon/icons-react');

function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }

var _extends__default = /*#__PURE__*/_interopDefault(_extends);
var _defineProperty__default = /*#__PURE__*/_interopDefault(_defineProperty);
var _slicedToArray__default = /*#__PURE__*/_interopDefault(_slicedToArray);
var React__default = /*#__PURE__*/_interopDefault(React);
var PropTypes__default = /*#__PURE__*/_interopDefault(PropTypes);
var classnames__default = /*#__PURE__*/_interopDefault(classnames);

function ownKeys(e, r) { var t = Object.keys(e); if (Object.getOwnPropertySymbols) { var o = Object.getOwnPropertySymbols(e); r && (o = o.filter(function (r) { return Object.getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? ownKeys(Object(t), !0).forEach(function (r) { _defineProperty__default.default(e, r, t[r]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(e, Object.getOwnPropertyDescriptors(t)) : ownKeys(Object(t)).forEach(function (r) { Object.defineProperty(e, r, Object.getOwnPropertyDescriptor(t, r)); }); } return e; }
var iotPrefix = Settings.settings.iotPrefix;
var GHOST = 'ghost';
var propTypes = {
  // eslint-disable-next-line react/require-default-props
  testID: deprecate(PropTypes__default.default.string, "The 'testID' prop has been deprecated. Please use 'testId' instead."),
  testId: PropTypes__default.default.string,
  /**
   * Use by a split menu button to fire the event for clicking on the main button,
   * not the chevron to open the additional menu actions
   */
  onPrimaryActionClick: PropTypes__default.default.func,
  /**
   * The label on the primary button in a split button, or the whole button on a single menu button
   */
  label: PropTypes__default.default.string,
  /**
   * Optional prop to change the open icon on the button
   * Can be a React component class
   */
  renderOpenIcon: PropTypes__default.default.oneOfType([PropTypes__default.default.func, PropTypes__default.default.object]),
  /**
   * Optional prop to change the closed state icon on the button
   * Can be a React component class
   */
  renderCloseIcon: PropTypes__default.default.oneOfType([PropTypes__default.default.func, PropTypes__default.default.object]),
  /**
   * If specifying the `renderIcon` prop, provide a description for that icon that can
   * be read by screen readers
   */
  closeIconDescription: function closeIconDescription(props) {
    if (props.renderCloseIcon && !props.closeIconDescription) {
      return new Error('renderCloseIcon property specified without also providing an closeIconDescription property.');
    }
    return undefined;
  },
  /**
   * If specifying the `renderIcon` prop, provide a description for that icon that can
   * be read by screen readers
   */
  openIconDescription: function openIconDescription(props) {
    if (props.renderOpenIcon && !props.openIconDescription) {
      return new Error('renderOpenIcon property specified without also providing an openIconDescription property.');
    }
    return undefined;
  },
  children: PropTypes__default.default.oneOfType([PropTypes__default.default.arrayOf(PropTypes__default.default.node), PropTypes__default.default.node]).isRequired,
  /**
   * The size of the button and the dropdown items
   */
  size: PropTypes__default.default.oneOf(['sm', 'md', 'default']),
  /**
   * The kind of button.
   */
  kind: PropTypes__default.default.oneOf(['primary', 'secondary', 'tertiary', 'ghost'])
};
var defaultProps = {
  testId: 'menu-button',
  onPrimaryActionClick: null,
  label: null,
  openIconDescription: 'open menu button',
  closeIconDescription: 'close menu button',
  renderOpenIcon: iconsReact.ChevronDown,
  renderCloseIcon: iconsReact.ChevronUp,
  size: 'default',
  kind: 'primary'
};
var MenuButton = function MenuButton(_ref) {
  var testID = _ref.testID,
    testId = _ref.testId,
    onPrimaryActionClick = _ref.onPrimaryActionClick,
    label = _ref.label,
    openIconDescription = _ref.openIconDescription,
    closeIconDescription = _ref.closeIconDescription,
    renderOpenIcon = _ref.renderOpenIcon,
    renderCloseIcon = _ref.renderCloseIcon,
    children = _ref.children,
    buttonSize = _ref.size,
    kind = _ref.kind;
  var _useState = React.useState(false),
    _useState2 = _slicedToArray__default.default(_useState, 2),
    isMenuOpen = _useState2[0],
    setIsMenuOpen = _useState2[1];
  var _useState3 = React.useState({
      x: 0,
      y: 0
    }),
    _useState4 = _slicedToArray__default.default(_useState3, 2),
    position = _useState4[0],
    setPosition = _useState4[1];
  var _useState5 = React.useState({}),
    _useState6 = _slicedToArray__default.default(_useState5, 2),
    shadowBlockerConf = _useState6[0],
    setShadowBlockerConf = _useState6[1];
  var buttonRef = React.useRef(null);
  var langDir = useLangDirection.useLangDirection();
  var handleResize = React.useCallback(function () {
    /* istanbul ignore else */
    if (buttonRef.current) {
      var _getMenuPosition = utils.getMenuPosition({
          label: label,
          buttonRef: buttonRef,
          onPrimaryActionClick: onPrimaryActionClick,
          langDir: langDir
        }),
        x = _getMenuPosition.x,
        y = _getMenuPosition.y;
      setPosition({
        x: x,
        y: y
      });
      setShadowBlockerConf(utils.getShadowBlockerConfig(buttonRef));
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [label, langDir, onPrimaryActionClick, isMenuOpen, buttonSize]);

  /**
   * This is a hacky work-around, because the current Menu (7.42.1) won't allow us
   * to set classNames or a target for where the menu should be placed via the portal
   * So, to fix the autopositioning, I have to open it, hide it with a property, check
   * the positioning, reposition it, and then show it. ugh. They are adding these other
   * features. Hopefully they'll be released soon, and we can use the `target` prop to open
   * the menu in this container div where it used to be...
   */
  React.useEffect(function () {
    document.querySelector(':root').style.setProperty('--iot-menu-button-menu-opacity', isMenuOpen ? 0 : 1);
    setTimeout(function () {
      document.querySelector(':root').style.setProperty('--iot-menu-button-menu-opacity', 1);
    }, 0);
  }, [isMenuOpen]);
  React.useLayoutEffect(function () {
    window.addEventListener('resize', handleResize);
    return function () {
      return window.removeEventListener('resize', handleResize);
    };
  }, [handleResize]);
  React.useEffect(function () {
    window.addEventListener('scroll', handleResize);
    return function () {
      return window.removeEventListener('scroll', handleResize);
    };
  }, [handleResize]);
  React.useLayoutEffect(function () {
    handleResize();
  }, [handleResize]);
  var handlePrimaryClick = React.useCallback(function (e) {
    if (typeof onPrimaryActionClick === 'function') {
      onPrimaryActionClick(e);
    } else {
      setIsMenuOpen(function (prev) {
        handleResize();
        return !prev;
      });
    }
  }, [handleResize, onPrimaryActionClick]);
  var handleSecondaryClick = React.useCallback(function () {
    setIsMenuOpen(function (prev) {
      handleResize();
      return !prev;
    });
  }, [handleResize]);
  var handleChildClick = React.useCallback(function (onClick) {
    return function (e) {
      /* istanbul ignore else */
      if (typeof onClick === 'function') {
        setIsMenuOpen(function (prev) {
          handleResize();
          return !prev;
        });
        onClick(e);
      }
    };
  }, [handleResize]);

  /**
   * Wrap the children onClick handlers to also close the menu when an
   * action is triggered.
   */
  var contextMenuItems = React.useMemo(function () {
    return React__default.default.Children.map(children, function (child) {
      var _child$props;
      return /*#__PURE__*/React__default.default.cloneElement(child, Object.assign({}, child.props, {
        onClick: typeof ((_child$props = child.props) === null || _child$props === void 0 ? void 0 : _child$props.onClick) === 'function' ? handleChildClick(child.props.onClick) : undefined
      }));
    });
  }, [children, handleChildClick]);
  var menuSize = buttonSize === 'default' ? 'lg' : buttonSize;
  var buttonKind = !label ? GHOST : kind;

  /**
   * This shadow-blocker is needed to remove the menu shadow covering the button.
   * We can't use a pure CSS solution (like ::after) for this since the shadow-blocker styling
   * needs to get the position and dimensions of the menu and it is not possible to
   * pass that info as css attributes (vars) to the menu since the component internally use
   * the style attribute to set the x & y attributes.
   */
  var menuHeight = shadowBlockerConf.menuHeight,
    flippedX = shadowBlockerConf.flippedX,
    flippedY = shadowBlockerConf.flippedY,
    opensHorizontally = shadowBlockerConf.opensHorizontally;
  var shadowBlockerButtonClasses = _defineProperty__default.default(_defineProperty__default.default(_defineProperty__default.default({}, "".concat(iotPrefix, "--menu-button--flip-y"), flippedY), "".concat(iotPrefix, "--menu-button--flip-x"), flippedX), "".concat(iotPrefix, "--menu-button--opens-horizontally"), opensHorizontally);
  var showShadowBlocker = buttonKind === GHOST && isMenuOpen && !label;
  var shadowBlocker = showShadowBlocker ? /*#__PURE__*/React__default.default.createElement("div", {
    style: _defineProperty__default.default({}, "--menu-height", "".concat(menuHeight, "px")),
    className: classnames__default.default(_defineProperty__default.default(_defineProperty__default.default(_defineProperty__default.default({}, "".concat(iotPrefix, "--menu__shadow-blocker--flip-y"), flippedY), "".concat(iotPrefix, "--menu__shadow-blocker--flip-x"), flippedX), "".concat(iotPrefix, "--menu__shadow-blocker--opens-horizontally"), opensHorizontally), "".concat(iotPrefix, "--menu__shadow-blocker"), "".concat(iotPrefix, "--menu__shadow-blocker--").concat(menuSize))
  }) : null;
  var ButtonComponent = typeof onPrimaryActionClick === 'function' && label ? SplitMenuButton.SplitMenuButton : SingleMenuButton.SingleMenuButton;
  return /*#__PURE__*/React__default.default.createElement("div", {
    // TODO: remove deprecated 'testID' in v3.
    "data-testid": "".concat(testID || testId, "-wrapper"),
    className: classnames__default.default("".concat(iotPrefix, "--menu-button"), _objectSpread(_defineProperty__default.default({}, "".concat(iotPrefix, "--menu-button--open"), isMenuOpen), shadowBlockerButtonClasses))
  }, /*#__PURE__*/React__default.default.createElement(ButtonComponent, {
    ref: buttonRef,
    onPrimaryActionClick: handlePrimaryClick,
    onSecondaryActionClick: handleSecondaryClick,
    iconDescription: isMenuOpen ? closeIconDescription : openIconDescription,
    renderIcon: isMenuOpen ? renderCloseIcon : renderOpenIcon,
    label: label
    // TODO: remove deprecated 'testID' in v3.
    ,
    testId: testID || testId,
    size: buttonSize,
    kind: buttonKind
  }), /*#__PURE__*/React__default.default.createElement(react.Menu, _extends__default.default({
    className: classnames__default.default(_defineProperty__default.default({}, "".concat(iotPrefix, "--menu-button--icon-only"), buttonKind === GHOST), "".concat(iotPrefix, "--menu-button__menu")),
    size: menuSize,
    open: isMenuOpen
  }, position), contextMenuItems, shadowBlocker));
};
MenuButton.propTypes = propTypes;
MenuButton.defaultProps = defaultProps;
MenuButton.__docgenInfo = {
  "description": "",
  "methods": [],
  "displayName": "MenuButton",
  "props": {
    "testId": {
      "defaultValue": {
        "value": "'menu-button'",
        "computed": false
      },
      "description": "",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "onPrimaryActionClick": {
      "defaultValue": {
        "value": "null",
        "computed": false
      },
      "description": "Use by a split menu button to fire the event for clicking on the main button,\nnot the chevron to open the additional menu actions",
      "type": {
        "name": "func"
      },
      "required": false
    },
    "label": {
      "defaultValue": {
        "value": "null",
        "computed": false
      },
      "description": "The label on the primary button in a split button, or the whole button on a single menu button",
      "type": {
        "name": "string"
      },
      "required": false
    },
    "openIconDescription": {
      "defaultValue": {
        "value": "'open menu button'",
        "computed": false
      },
      "description": "If specifying the `renderIcon` prop, provide a description for that icon that can\nbe read by screen readers",
      "type": {
        "name": "custom",
        "raw": "(props) => {\n  if (props.renderOpenIcon && !props.openIconDescription) {\n    return new Error(\n      'renderOpenIcon property specified without also providing an openIconDescription property.'\n    );\n  }\n  return undefined;\n}"
      },
      "required": false
    },
    "closeIconDescription": {
      "defaultValue": {
        "value": "'close menu button'",
        "computed": false
      },
      "description": "If specifying the `renderIcon` prop, provide a description for that icon that can\nbe read by screen readers",
      "type": {
        "name": "custom",
        "raw": "(props) => {\n  if (props.renderCloseIcon && !props.closeIconDescription) {\n    return new Error(\n      'renderCloseIcon property specified without also providing an closeIconDescription property.'\n    );\n  }\n  return undefined;\n}"
      },
      "required": false
    },
    "renderOpenIcon": {
      "defaultValue": {
        "value": "ChevronDown",
        "computed": true
      },
      "description": "Optional prop to change the open icon on the button\nCan be a React component class",
      "type": {
        "name": "union",
        "value": [{
          "name": "func"
        }, {
          "name": "object"
        }]
      },
      "required": false
    },
    "renderCloseIcon": {
      "defaultValue": {
        "value": "ChevronUp",
        "computed": true
      },
      "description": "Optional prop to change the closed state icon on the button\nCan be a React component class",
      "type": {
        "name": "union",
        "value": [{
          "name": "func"
        }, {
          "name": "object"
        }]
      },
      "required": false
    },
    "size": {
      "defaultValue": {
        "value": "'default'",
        "computed": false
      },
      "description": "The size of the button and the dropdown items",
      "type": {
        "name": "enum",
        "value": [{
          "value": "'sm'",
          "computed": false
        }, {
          "value": "'md'",
          "computed": false
        }, {
          "value": "'default'",
          "computed": false
        }]
      },
      "required": false
    },
    "kind": {
      "defaultValue": {
        "value": "'primary'",
        "computed": false
      },
      "description": "The kind of button.",
      "type": {
        "name": "enum",
        "value": [{
          "value": "'primary'",
          "computed": false
        }, {
          "value": "'secondary'",
          "computed": false
        }, {
          "value": "'tertiary'",
          "computed": false
        }, {
          "value": "'ghost'",
          "computed": false
        }]
      },
      "required": false
    },
    "testID": {
      "description": "",
      "type": {
        "name": "custom",
        "raw": "deprecate(\n  PropTypes.string,\n  `The 'testID' prop has been deprecated. Please use 'testId' instead.`\n)"
      },
      "required": false
    },
    "children": {
      "description": "",
      "type": {
        "name": "union",
        "value": [{
          "name": "arrayOf",
          "value": {
            "name": "node"
          }
        }, {
          "name": "node"
        }]
      },
      "required": true
    }
  }
};
var MenuButton$1 = MenuButton;

module.exports = MenuButton$1;
