text: "use strict";
  Object.defineProperty(exports, "__esModule", { value: true });
  var tslib_1 = require("tslib");
  var React = require("react");
  var Utilities_1 = require("../../Utilities");
  var Icon_1 = require("../../Icon");
  var ContextualMenu_1 = require("../../ContextualMenu");
  var BaseButton_classNames_1 = require("./BaseButton.classNames");
  var SplitButton_classNames_1 = require("./SplitButton/SplitButton.classNames");
  var KeytipData_1 = require("../../KeytipData");
  var TouchIdleDelay = 500; /* ms */
  var BaseButton = /** @class */ (function (_super) {
      tslib_1.__extends(BaseButton, _super);
      function BaseButton(props, rootClassName) {
          var _this = _super.call(this, props) || this;
          _this._buttonElement = Utilities_1.createRef();
          _this._splitButtonContainer = Utilities_1.createRef();
          _this._onRenderIcon = function (buttonProps, defaultRender) {
              var iconProps = _this.props.iconProps;
              if (iconProps) {
                  return (React.createElement(Icon_1.Icon, tslib_1.__assign({}, iconProps, { className: _this._classNames.icon })));
              }
              return null;
          };
          _this._onRenderTextContents = function () {
              var _a = _this.props, text = _a.text, children = _a.children, _b = _a.secondaryText, secondaryText = _b === void 0 ? _this.props.description : _b, _c = _a.onRenderText, onRenderText = _c === void 0 ? _this._onRenderText : _c, _d = _a.onRenderDescription, onRenderDescription = _d === void 0 ? _this._onRenderDescription : _d;
              if (text || typeof (children) === 'string' || secondaryText) {
                  return (React.createElement("div", { className: _this._classNames.textContainer },
                      onRenderText(_this.props, _this._onRenderText),
                      onRenderDescription(_this.props, _this._onRenderDescription)));
              }
              return ([
                  onRenderText(_this.props, _this._onRenderText),
                  onRenderDescription(_this.props, _this._onRenderDescription)
              ]);
          };
          _this._onRenderText = function () {
              var text = _this.props.text;
              var children = _this.props.children;
              // For backwards compat, we should continue to take in the text content from children.
              if (text === undefined && typeof (children) === 'string') {
                  text = children;
              }
              if (_this._hasText()) {
                  return (React.createElement("div", { key: _this._labelId, className: _this._classNames.label, id: _this._labelId }, text));
              }
              return null;
          };
          _this._onRenderChildren = function () {
              var children = _this.props.children;
              // If children is just a string, either it or the text will be rendered via onRenderLabel
              // If children is another component, it will be rendered after text
              if (typeof (children) === 'string') {
                  return null;
              }
              return children;
          };
          _this._onRenderDescription = function (props) {
              var _a = props.secondaryText, secondaryText = _a === void 0 ? _this.props.description : _a;
              // ms-Button-description is only shown when the button type is compound.
              // In other cases it will not be displayed.
              return (secondaryText) ? (React.createElement("div", { key: _this._descriptionId, className: _this._classNames.description, id: _this._descriptionId }, secondaryText)) : (null);
          };
          _this._onRenderAriaDescription = function () {
              var ariaDescription = _this.props.ariaDescription;
              // If ariaDescription is given, descriptionId will be assigned to ariaDescriptionSpan,
              // otherwise it will be assigned to descriptionSpan.
              return ariaDescription ? (React.createElement("span", { className: _this._classNames.screenReaderText, id: _this._ariaDescriptionId }, ariaDescription)) : (null);
          };
          _this._onRenderMenuIcon = function (props) {
              var menuIconProps = _this.props.menuIconProps;
              return (React.createElement(Icon_1.Icon, tslib_1.__assign({ iconName: 'ChevronDown' }, menuIconProps, { className: _this._classNames.menuIcon })));
          };
          _this._onRenderMenu = function (menuProps) {
              var _a = menuProps.onDismiss, onDismiss = _a === void 0 ? _this._dismissMenu : _a;
              // the accessible menu label (accessible name) has a relationship to the button.
              // If the menu props do not specify an explicit value for aria-label or aria-labelledBy,
              // AND the button has text, we'll set the menu aria-labelledBy to the text element id.
              if (!menuProps.ariaLabel && !menuProps.labelElementId && _this._hasText()) {
                  menuProps = tslib_1.__assign({}, menuProps, { labelElementId: _this._labelId });
              }
              return (React.createElement(ContextualMenu_1.ContextualMenu, tslib_1.__assign({ id: _this._labelId + '-menu', directionalHint: 4 /* bottomLeftEdge */ }, menuProps, { shouldFocusOnContainer: _this.state.menuProps ? _this.state.menuProps.shouldFocusOnContainer : undefined, className: Utilities_1.css('ms-BaseButton-menuhost', menuProps.className), target: _this._isSplitButton ? _this._splitButtonContainer.current : _this._buttonElement.current, onDismiss: onDismiss })));
          };
          _this._dismissMenu = function () {
              var menuProps = null;
              if (_this.props.persistMenu && _this.state.menuProps) {
                  menuProps = _this.state.menuProps;
                  menuProps.hidden = true;
              }
              _this.setState({ menuProps: menuProps });
          };
          _this._openMenu = function (shouldFocusOnContainer) {
              if (_this.props.menuProps) {
                  var menuProps = tslib_1.__assign({}, _this.props.menuProps, { shouldFocusOnContainer: shouldFocusOnContainer });
                  if (_this.props.persistMenu) {
                      menuProps.hidden = false;
                  }
                  _this.setState({ menuProps: menuProps });
              }
          };
          _this._onToggleMenu = function (shouldFocusOnContainer) {
              if (_this._splitButtonContainer.current) {
                  _this._splitButtonContainer.current.focus();
              }
              var currentMenuProps = _this.state.menuProps;
              if (_this.props.persistMenu) {
                  currentMenuProps && currentMenuProps.hidden ? _this._openMenu(shouldFocusOnContainer) : _this._dismissMenu();
              }
              else {
                  currentMenuProps ? _this._dismissMenu() : _this._openMenu(shouldFocusOnContainer);
              }
          };
          _this._onSplitButtonPrimaryClick = function (ev) {
              if (_this._isExpanded) {
                  _this._dismissMenu();
              }
              if (!_this._processingTouch && _this.props.onClick) {
                  _this.props.onClick(ev);
              }
              else if (_this._processingTouch) {
                  _this._onMenuClick(ev);
              }
          };
          _this._onMouseDown = function (ev) {
              if (_this.props.onMouseDown) {
                  _this.props.onMouseDown(ev);
              }
              ev.preventDefault();
          };
          _this._onSplitButtonContainerKeyDown = function (ev) {
              if (ev.which === 13 /* enter */) {
                  if (_this._buttonElement.current) {
                      _this._buttonElement.current.click();
                      ev.preventDefault();
                      ev.stopPropagation();
                  }
              }
              else {
                  _this._onMenuKeyDown(ev);
              }
          };
          _this._onMenuKeyDown = function (ev) {
              if (_this.props.disabled) {
                  return;
              }
              if (_this.props.onKeyDown) {
                  _this.props.onKeyDown(ev);
              }
              if (!ev.defaultPrevented && _this._isValidMenuOpenKey(ev)) {
                  var onMenuClick = _this.props.onMenuClick;
                  if (onMenuClick) {
                      onMenuClick(ev, _this);
                  }
                  _this._onToggleMenu(false);
                  ev.preventDefault();
                  ev.stopPropagation();
              }
          };
          _this._onTouchStart = function () {
              if (_this._isSplitButton && _this._splitButtonContainer.value && !('onpointerdown' in _this._splitButtonContainer.value)) {
                  _this._handleTouchAndPointerEvent();
              }
          };
          _this._onMenuClick = function (ev) {
              var onMenuClick = _this.props.onMenuClick;
              if (onMenuClick) {
                  onMenuClick(ev, _this);
              }
              if (!ev.defaultPrevented) {
                  // When Edge + Narrator are used together (regardless of if the button is in a form or not), pressing
                  // "Enter" fires this method and not _onMenuKeyDown. Checking ev.nativeEvent.detail differentiates
                  // between a real click event and a keypress event.
                  var shouldFocusOnContainer = ev.nativeEvent.detail !== 0;
                  _this._onToggleMenu(shouldFocusOnContainer);
                  ev.preventDefault();
                  ev.stopPropagation();
              }
          };
          _this._warnConditionallyRequiredProps(['menuProps', 'onClick'], 'split', _this.props.split);
          _this._warnDeprecations({
              rootProps: undefined,
              'description': 'secondaryText'
          });
          _this._labelId = Utilities_1.getId();
          _this._descriptionId = Utilities_1.getId();
          _this._ariaDescriptionId = Utilities_1.getId();
          var menuProps = null;
          if (props.persistMenu && props.menuProps) {
              menuProps = props.menuProps;
              menuProps.hidden = true;
          }
          _this.state = {
              menuProps: menuProps
          };
          return _this;
      }
      Object.defineProperty(BaseButton.prototype, "_isSplitButton", {
          get: function () {
              return (!!this.props.menuProps && !!this.props.onClick) && this.props.split === true;
          },
          enumerable: true,
          configurable: true
      });
      Object.defineProperty(BaseButton.prototype, "_isExpanded", {
          get: function () {
              if (this.props.persistMenu) {
                  return !this.state.menuProps.hidden;
              }
              return !!this.state.menuProps;
          },
          enumerable: true,
          configurable: true
      });
      BaseButton.prototype.render = function () {
          var _a = this.props, ariaDescription = _a.ariaDescription, ariaLabel = _a.ariaLabel, ariaHidden = _a.ariaHidden, className = _a.className, disabled = _a.disabled, primaryDisabled = _a.primaryDisabled, _b = _a.secondaryText, secondaryText = _b === void 0 ? this.props.description : _b, href = _a.href, iconProps = _a.iconProps, menuIconProps = _a.menuIconProps, styles = _a.styles, text = _a.text, checked = _a.checked, variantClassName = _a.variantClassName, theme = _a.theme, getClassNames = _a.getClassNames;
          var menuProps = this.state.menuProps;
          // Button is disabled if the whole button (in case of splitbutton is disabled) or if the primary action is disabled
          var isPrimaryButtonDisabled = (disabled || primaryDisabled);
          this._classNames = getClassNames ? getClassNames(theme, className, variantClassName, iconProps && iconProps.className, menuIconProps && menuIconProps.className, isPrimaryButtonDisabled, checked, !!menuProps, this.props.split) : BaseButton_classNames_1.getBaseButtonClassNames(styles, className, variantClassName, iconProps && iconProps.className, menuIconProps && menuIconProps.className, isPrimaryButtonDisabled, checked, !!menuProps, this.props.split);
          var _c = this, _ariaDescriptionId = _c._ariaDescriptionId, _labelId = _c._labelId, _descriptionId = _c._descriptionId;
          // Anchor tag cannot be disabled hence in disabled state rendering
          // anchor button as normal button
          var renderAsAnchor = !isPrimaryButtonDisabled && !!href;
          var tag = renderAsAnchor ? 'a' : 'button';
          var nativeProps = Utilities_1.getNativeProps(Utilities_1.assign(renderAsAnchor ? {} : { type: 'button' }, this.props.rootProps, this.props), renderAsAnchor ? Utilities_1.anchorProperties : Utilities_1.buttonProperties, [
              'disabled' // let disabled buttons be focused and styled as disabled.
          ]);
          // Check for ariaDescription, secondaryText or aria-describedby in the native props to determine source of aria-describedby
          // otherwise default to null.
          var ariaDescribedBy;
          if (ariaDescription) {
              ariaDescribedBy = _ariaDescriptionId;
          }
          else if (secondaryText) {
              ariaDescribedBy = _descriptionId;
          }
          else if (nativeProps['aria-describedby']) {
              ariaDescribedBy = nativeProps['aria-describedby'];
          }
          else {
              ariaDescribedBy = null;
          }
          // If an explicit ariaLabel is given, use that as the label and we're done.
          // If an explicit aria-labelledby is given, use that and we're done.
          // If any kind of description is given (which will end up as an aria-describedby attribute),
          // set the labelledby element. Otherwise, the button is labeled implicitly by the descendent
          // text on the button (if it exists). Never set both aria-label and aria-labelledby.
          var ariaLabelledBy = null;
          if (!ariaLabel) {
              if (nativeProps['aria-labelledby']) {
                  ariaLabelledBy = nativeProps['aria-labelledby'];
              }
              else if (ariaDescribedBy) {
                  ariaLabelledBy = text ? _labelId : null;
              }
          }
          var buttonProps = Utilities_1.assign(nativeProps, {
              className: this._classNames.root,
              ref: this._buttonElement,
              'disabled': isPrimaryButtonDisabled,
              'aria-label': ariaLabel,
              'aria-labelledby': ariaLabelledBy,
              'aria-describedby': ariaDescribedBy,
              'data-is-focusable': (this.props['data-is-focusable'] === false || disabled || this._isSplitButton) ? false : true,
              'aria-pressed': checked
          });
          if (ariaHidden) {
              buttonProps['aria-hidden'] = true;
          }
          if (this._isSplitButton) {
              return (this._onRenderSplitButtonContent(tag, buttonProps));
          }
          else if (this.props.menuProps) {
              Utilities_1.assign(buttonProps, {
                  'onKeyDown': this._onMenuKeyDown,
                  'onClick': this._onMenuClick,
                  'aria-expanded': this._isExpanded,
                  'aria-owns': this.state.menuProps ? this._labelId + '-menu' : null,
                  'aria-haspopup': true
              });
          }
          return this._onRenderContent(tag, buttonProps);
      };
      BaseButton.prototype.componentDidMount = function () {
          // For split buttons, touching anywhere in the button should drop the dropdown, which should contain the primary action.
          // This gives more hit target space for touch environments. We're setting the onpointerdown here, because React
          // does not support Pointer events yet.
          if (this._isSplitButton && this._splitButtonContainer.value && 'onpointerdown' in this._splitButtonContainer.value) {
              this._events.on(this._splitButtonContainer.value, 'pointerdown', this._onPointerDown, true);
          }
      };
      BaseButton.prototype.componentDidUpdate = function (prevProps, prevState) {
          // If Button's menu was closed, run onAfterMenuDismiss
          if (this.props.onAfterMenuDismiss && prevState.menuProps && !this.state.menuProps) {
              this.props.onAfterMenuDismiss();
          }
      };
      BaseButton.prototype.focus = function () {
          if (this._isSplitButton && this._splitButtonContainer.current) {
              this._splitButtonContainer.current.focus();
          }
          else if (this._buttonElement.current) {
              this._buttonElement.current.focus();
          }
      };
      BaseButton.prototype.dismissMenu = function () {
          this._dismissMenu();
      };
      BaseButton.prototype.openMenu = function () {
          this._openMenu();
      };
      BaseButton.prototype._onRenderContent = function (tag, buttonProps) {
          var _this = this;
          var props = this.props;
          var Tag = tag;
          var menuIconProps = props.menuIconProps, menuProps = props.menuProps, _a = props.onRenderIcon, onRenderIcon = _a === void 0 ? this._onRenderIcon : _a, _b = props.onRenderAriaDescription, onRenderAriaDescription = _b === void 0 ? this._onRenderAriaDescription : _b, _c = props.onRenderChildren, onRenderChildren = _c === void 0 ? this._onRenderChildren : _c, _d = props.onRenderMenu, onRenderMenu = _d === void 0 ? this._onRenderMenu : _d, _e = props.onRenderMenuIcon, onRenderMenuIcon = _e === void 0 ? this._onRenderMenuIcon : _e, disabled = props.disabled;
          var keytipProps = props.keytipProps;
          if (keytipProps && menuProps) {
              keytipProps = tslib_1.__assign({}, keytipProps, { hasMenu: true });
          }
          var Content = (
          // If we're making a split button, we won't put the keytip here
          React.createElement(KeytipData_1.KeytipData, { keytipProps: !this._isSplitButton ? keytipProps : undefined, ariaDescribedBy: buttonProps['aria-describedby'], disabled: disabled }, function (keytipAttributes) { return (React.createElement(Tag, tslib_1.__assign({}, buttonProps, keytipAttributes),
              React.createElement("div", { className: _this._classNames.flexContainer },
                  onRenderIcon(props, _this._onRenderIcon),
                  _this._onRenderTextContents(),
                  onRenderAriaDescription(props, _this._onRenderAriaDescription),
                  onRenderChildren(props, _this._onRenderChildren),
                  !_this._isSplitButton && (menuProps || menuIconProps || _this.props.onRenderMenuIcon) && onRenderMenuIcon(_this.props, _this._onRenderMenuIcon),
                  _this.state.menuProps && !_this.state.menuProps.doNotLayer && onRenderMenu(menuProps, _this._onRenderMenu)))); }));
          if (menuProps && menuProps.doNotLayer) {
              return (React.createElement("div", { style: { display: 'inline-block' } },
                  Content,
                  this.state.menuProps && onRenderMenu(menuProps, this._onRenderMenu)));
          }
          return Content;
      };
      BaseButton.prototype._hasText = function () {
          // _onRenderTextContents and _onRenderText do not perform the same checks. Below is parity with what _onRenderText used to have
          // before the refactor that introduced this function. _onRenderTextContents does not require props.text to be undefined in order
          // for props.children to be used as a fallback. Purely a code maintainability/reuse issue, but logged as Issue #4979
          return this.props.text !== null && (this.props.text !== undefined || typeof (this.props.children) === 'string');
      };
      BaseButton.prototype._onRenderSplitButtonContent = function (tag, buttonProps) {
          var _this = this;
          var _a = this.props, _b = _a.styles, styles = _b === void 0 ? {} : _b, disabled = _a.disabled, checked = _a.checked, getSplitButtonClassNames = _a.getSplitButtonClassNames, primaryDisabled = _a.primaryDisabled, menuProps = _a.menuProps;
          var keytipProps = this.props.keytipProps;
          var classNames = getSplitButtonClassNames ? getSplitButtonClassNames(!!disabled, !!this.state.menuProps, !!checked) : styles && SplitButton_classNames_1.getClassNames(styles, !!disabled, !!this.state.menuProps, !!checked);
          Utilities_1.assign(buttonProps, {
              onClick: undefined,
              tabIndex: -1,
              'data-is-focusable': false
          });
          var ariaDescribedBy = buttonProps.ariaDescription || '';
          if (keytipProps && menuProps) {
              keytipProps = tslib_1.__assign({}, keytipProps, { hasMenu: true });
          }
          return (React.createElement(KeytipData_1.KeytipData, { keytipProps: keytipProps, disabled: disabled }, function (keytipAttributes) { return (React.createElement("div", { "data-ktp-target": keytipAttributes['data-ktp-target'], role: 'button', "aria-labelledby": buttonProps.ariaLabel, "aria-disabled": disabled, "aria-haspopup": true, "aria-expanded": _this._isExpanded, "aria-pressed": _this.props.checked, "aria-describedby": ariaDescribedBy + (keytipAttributes['aria-describedby'] || ''), className: classNames && classNames.splitButtonContainer, onKeyDown: _this._onSplitButtonContainerKeyDown, onTouchStart: _this._onTouchStart, ref: _this._splitButtonContainer, "data-is-focusable": true, onClick: !disabled && !primaryDisabled ? _this._onSplitButtonPrimaryClick : undefined, tabIndex: !disabled ? 0 : undefined },
              React.createElement("span", { style: { 'display': 'flex' } },
                  _this._onRenderContent(tag, buttonProps),
                  _this._onRenderSplitButtonMenuButton(classNames, keytipAttributes),
                  _this._onRenderSplitButtonDivider(classNames)))); }));
      };
      BaseButton.prototype._onRenderSplitButtonDivider = function (classNames) {
          if (classNames && classNames.divider) {
              return React.createElement("span", { className: classNames.divider });
          }
          return null;
      };
      BaseButton.prototype._onRenderSplitButtonMenuButton = function (classNames, keytipAttributes) {
          var menuIconProps = this.props.menuIconProps;
          var splitButtonAriaLabel = this.props.splitButtonAriaLabel;
          if (menuIconProps === undefined) {
              menuIconProps = {
                  iconName: 'ChevronDown'
              };
          }
          var splitButtonProps = {
              'styles': classNames,
              'checked': this.props.checked,
              'disabled': this.props.disabled,
              'onClick': this._onMenuClick,
              'menuProps': undefined,
              'iconProps': menuIconProps,
              'ariaLabel': splitButtonAriaLabel,
              'aria-haspopup': true,
              'aria-expanded': this._isExpanded,
              'data-is-focusable': false
          };
          // Add data-ktp-execute-target to the split button if the keytip is defined
          return (React.createElement(BaseButton, tslib_1.__assign({}, splitButtonProps, { "data-ktp-execute-target": keytipAttributes['data-ktp-execute-target'], onMouseDown: this._onMouseDown, tabIndex: -1 })));
      };
      BaseButton.prototype._onPointerDown = function (ev) {
          if (ev.pointerType === 'touch') {
              this._handleTouchAndPointerEvent();
              ev.preventDefault();
              ev.stopImmediatePropagation();
          }
      };
      BaseButton.prototype._handleTouchAndPointerEvent = function () {
          var _this = this;
          // If we already have an existing timeeout from a previous touch and pointer event
          // cancel that timeout so we can set a nwe one.
          if (this._lastTouchTimeoutId !== undefined) {
              this._async.clearTimeout(this._lastTouchTimeoutId);
              this._lastTouchTimeoutId = undefined;
          }
          this._processingTouch = true;
          this._lastTouchTimeoutId = this._async.setTimeout(function () {
              _this._processingTouch = false;
              _this._lastTouchTimeoutId = undefined;
          }, TouchIdleDelay);
      };
      /**
       * Returns if the user hits a valid keyboard key to open the menu
       * @param ev - the keyboard event
       * @returns True if user clicks on custom trigger key if enabled or alt + down arrow if not. False otherwise.
       */
      BaseButton.prototype._isValidMenuOpenKey = function (ev) {
          if (this.props.menuTriggerKeyCode) {
              return ev.which === this.props.menuTriggerKeyCode;
          }
          else if (this.props.menuProps) {
              return ev.which === 40 /* down */ && (ev.altKey || ev.metaKey);
          }
          // Note: When enter is pressed, we will let the event continue to propagate
          // to trigger the onClick event on the button
          return false;
      };
      BaseButton.defaultProps = {
          baseClassName: 'ms-Button',
          styles: {},
          split: false,
      };
      return BaseButton;
  }(Utilities_1.BaseComponent));
  exports.BaseButton = BaseButton;
  //# sourceMappingURL=BaseButton.js.map