text: /**
   * @Copyright (c) Microsoft Corporation.  All rights reserved.
   *
   * @file Root component of the inbuilt webpart property configuration user experience.
   *
   */
  import { __assign, __extends } from "tslib";
  import * as React from 'react';
  import * as ReactDOM from 'react-dom';
  import { debounce } from '@microsoft/sp-lodash-subset';
  import Compare from '../utils/Compare';
  import PropertyPanePage from '../propertyPanePage/PropertyPanePage';
  import { PropertyPaneTitleBar } from '../propertyPaneTitleBar/PropertyPaneTitleBar';
  import PropertyPaneFooter from '../propertyPaneFooter/PropertyPaneFooter';
  import * as strings from '../loc/Strings.resx';
  import propertyPaneStyles from './PropertyPane.module.scss';
  import propertyPanePageStyles from '../propertyPanePage/PropertyPanePage.module.scss';
  // VSO: Bug 227235 Remove this dependency on Canvas11y
  import { css, Fabric, FocusTrapZone, KeyCodes, Overlay, Spinner, SpinnerType } from '@microsoft/office-ui-fabric-react-bundle';
  import { getFocusableChildren, getFirstFocusableChild, isKey, KeyCodes as ExtendedKeyCodes } from '../utils/CanvasA11y';
  /**
   * Page direction.
   */
  export var PageDirection;
  (function (PageDirection) {
      PageDirection[PageDirection["back"] = -1] = "back";
      PageDirection[PageDirection["next"] = 1] = "next";
  })(PageDirection || (PageDirection = {}));
  /**
   * A constant value to delay the clearing of save confirmation message.
   */
  var CLEAR_DELAY = 100;
  /**
   * A constant value to set when there is no web part to configure.
   */
  var NO_WEBPART_ID = 'No_Web_Part_ID';
  var DELAY_RAISE_EVENT_IN_MILLISECONDS = 500;
  /**
   * Propertypane component.
   *
   * @internal
   */
  var PropertyPane = /** @class */ (function (_super) {
      __extends(PropertyPane, _super);
      /**
       * Constructor to instantiate the propertypane component.
       */
      function PropertyPane(props) {
          var _this = _super.call(this, props) || this;
          _this._propertyPane = React.createRef();
          _this._setEntryState = function (targetProperty, isValidEntry) {
              // maintain the list of invalid entries
              if (isValidEntry) {
                  if (_this._invalidEntries.hasOwnProperty(targetProperty)) {
                      delete _this._invalidEntries[targetProperty];
                  }
              }
              else {
                  _this._invalidEntries[targetProperty] = !isValidEntry;
              }
          };
          /* tslint:disable-next-line:no-any */
          _this._onChange = function (targetProperty, value, fieldType) {
              _this._properties[targetProperty] = value;
              // enable the save button in Reactive mode if there are no invalid entries
              if (!_this.props.data.isReactive) {
                  _this._enableSaveButton(Object.keys(_this._invalidEntries).length === 0);
              }
              if (!_this._invalidEntries.hasOwnProperty(targetProperty)) {
                  _this._raiseEvent(targetProperty, value, fieldType);
              }
          };
          _this.state = {
              isSaveButtonEnabled: false,
              saveConfirmationMessage: '',
              currentPage: 1
          };
          _this._currentlyConfiguredWebPartId = props.data.webPartId;
          // method bindings.
          _this._onChange = _this._onChange.bind(_this);
          _this._onPropertyPaneKeyDown = _this._onPropertyPaneKeyDown.bind(_this);
          _this._flipPage = _this._flipPage.bind(_this);
          _this._handleSaveClick = _this._handleSaveClick.bind(_this);
          _this._handleCloseClick = _this._handleCloseClick.bind(_this);
          _this._propertyPaneShouldLooseFocus = _this._propertyPaneShouldLooseFocus.bind(_this);
          _this._setContainerDiv = _this._setContainerDiv.bind(_this);
          _this._propertyPaneGroupStateChanged = _this._propertyPaneGroupStateChanged.bind(_this);
          _this._raiseEventImpl = _this._raiseEventImpl.bind(_this);
          _this._debounceCallbacks = new Map();
          var _a = _this.props.data.configuration.debounceProperties, debounceProperties = _a === void 0 ? [] : _a;
          for (var _i = 0, debounceProperties_1 = debounceProperties; _i < debounceProperties_1.length; _i++) {
              var p = debounceProperties_1[_i];
              var propertyName = p.propertyName, _b = p.debouncePeriod, debouncePeriod = _b === void 0 ? DELAY_RAISE_EVENT_IN_MILLISECONDS : _b;
              _this._debounceCallbacks.set(propertyName, debounce(_this._raiseEventImpl, debouncePeriod, { leading: true, trailing: true }));
          }
          _this._invalidEntries = {};
          _this._propertyPanePagesStateMap = {};
          return _this;
      }
      /**
       * React component lifecycle event.
       * @param props - new props for the component.
       */
      PropertyPane.prototype.UNSAFE_componentWillReceiveProps = function (props) {
          if (props.data.shouldResetState) {
              // resetting the map data.
              this._propertyPanePagesStateMap = {};
          }
          if (this._currentlyConfiguredWebPartId !== props.data.webPartId || props.data.shouldResetState) {
              var webPartId = props.data.webPartId ? props.data.webPartId : NO_WEBPART_ID;
              this._resetState(webPartId);
          }
          else {
              this.setState({
                  saveConfirmationMessage: ''
              });
          }
      };
      PropertyPane.prototype.componentDidMount = function () {
          // @todo: for some god forsaken reason the z-index in the class does not apply. Hence this hack
          // Some react thing that I don't have time to dig into right now. Perhaps later.
          var domNode = ReactDOM.findDOMNode(this);
          domNode.style.zIndex = '999';
          if (this.props.data.onRendered) {
              this.props.data.onRendered();
          }
          // This is the hack to workaround a react bug that doesn't set the focus in componentDidMount properly
          // VSO:Bug 215692 Remove the hack and implement focus methods in fabric react
          this._setTimeOutForFocus();
      };
      PropertyPane.prototype.componentDidUpdate = function (props) {
          if (this._isPropertyPaneReplaced) {
              this._updateTabIndexes(0, true);
              this._isPropertyPaneReplaced = false;
          }
          /**
           * From framework standpoint, we do not want to allow this event handler to be passed in, and trigger it.
           *
           * This api should be deprecated and then removed as part of refactoring.
           */
          if (this.props.data.onRendered) {
              this.props.data.onRendered();
          }
      };
      /**
       * React component lifecycle method.
       * Added this method to avoid, unnecessary renders.
       */
      PropertyPane.prototype.shouldComponentUpdate = function (nextProps, nextState) {
          return (!Compare.shallowCompare(this.props, nextProps) ||
              !Compare.shallowCompare(this.state, nextState) ||
              // Need the !! to ensure undefined is properly converted
              !!(nextProps.data.configuration && nextProps.data.configuration.showLoadingIndicator));
      };
      PropertyPane.prototype.render = function () {
          this._properties = this.props.data.properties;
          var showOverlaySpinner = this.props.data.configuration && this.props.data.configuration.showLoadingIndicator;
          return (React.createElement(Fabric, { "data-sp-feature-tag": 'Property Pane', "data-sp-feature-instance-id": '_Property Pane' },
              React.createElement("div", { role: 'alert', "aria-live": 'polite', className: propertyPaneStyles.propertyPaneScreenReaderOnly },
                  React.createElement("span", null, this.state.saveConfirmationMessage)),
              React.createElement(FocusTrapZone, { isClickableOutsideFocusTrap: true, forceFocusInsideTrap: false, disabled: this.props.data.configuration.disableFocusTrap },
                  React.createElement("div", { className: this.props.renderNarrow
                          ? propertyPaneStyles.propertyPaneNarrow
                          : propertyPaneStyles.propertyPane, role: 'region', "aria-label": strings.PropertyPaneAriaLabel, "aria-describedby": this._descriptionId, ref: this._propertyPane, onKeyDown: this._onPropertyPaneKeyDown, key: this.props.data.webPartId },
                      showOverlaySpinner && (React.createElement(Overlay, { className: propertyPaneStyles.overlay },
                          React.createElement(Spinner, { className: propertyPaneStyles.spinner, type: SpinnerType.large, label: strings.PropertyPaneFetchingSettingsDataLabel }))),
                      React.createElement(PropertyPaneTitleBar, { title: this.props.data.title, onClose: this._handleCloseClick }),
                      React.createElement("div", null, this._shouldRenderEmptyPage ? this._renderNoConfigurationState() : this._renderPage())))));
      };
      /**
       * Renders the description for no configuration scenario.
       */
      PropertyPane.prototype._renderNoConfigurationState = function () {
          return (React.createElement("div", null,
              React.createElement("div", null, this.props.children),
              React.createElement("div", { role: 'alert', "aria-live": 'polite', className: propertyPaneStyles.propertyPaneDescription, "data-automation-id": 'noConfigurationPropertyPane' }, strings.PropertyPaneEmptyStateDescription)));
      };
      Object.defineProperty(PropertyPane.prototype, "_descriptionId", {
          get: function () {
              var page = undefined;
              if (this.props.data.configuration && this.props.data.configuration.pages) {
                  var pages = this.props.data.configuration.pages;
                  page = pages[this.state.currentPage - 1];
              }
              return page && page.header && page.header.description ? 'propertyPaneDescriptionId' : undefined;
          },
          enumerable: false,
          configurable: true
      });
      /**
       * Renders page on the property pane.
       */
      PropertyPane.prototype._renderPage = function () {
          var pages = this.props.data.configuration.pages;
          var page = pages[this.state.currentPage - 1];
          var classForPropertyPanePageContentBottom = this._getCssBottomValueForPageContentElement();
          return (React.createElement("div", null,
              React.createElement("div", { className: css(classForPropertyPanePageContentBottom, propertyPanePageStyles.propertyPanePageContent), "data-automation-id": 'propertyPanePageContent' },
                  React.createElement("div", null, this.props.children),
                  React.createElement(PropertyPanePage, __assign({}, this.props.data, { pageNumber: this.state.currentPage, pageDescription: page.header ? page.header.description : '', displayGroupsAsAccordion: page.displayGroupsAsAccordion || false, onChange: this._onChange, propertyGroups: page.groups, properties: this._properties, setEntryState: this._setEntryState, setContainerDiv: this._setContainerDiv, propertyPaneGroupStateChanged: this._propertyPaneGroupStateChanged, propertyPanePagesStateMap: this._propertyPanePagesStateMap, dynamicConfiguration: this.props.data.dynamicConfiguration }))),
              React.createElement(PropertyPaneFooter, { isReactive: this.props.data.isReactive || false, isSaveButtonEnabled: this.state.isSaveButtonEnabled, numberOfPages: this.props.data.configuration &&
                      this.props.data.configuration.pages &&
                      this.props.data.configuration.pages.length
                      ? this.props.data.configuration.pages.length
                      : 0, currentPage: this.state.currentPage, onSaveClick: this._handleSaveClick, onFlipPage: this._flipPage })));
      };
      PropertyPane.prototype._setContainerDiv = function (containerDiv) {
          this._propertyPaneContent = containerDiv;
      };
      /**
       * Private method which gets called when user manually collapses or opens the propertyPane group,
       * when the Propertypane page's displayGroupsAsAccordion prop is true.
       *
       * @param pageNumber - page on which the group's state changed.
       * @param groupName - name of the group.
       * @param isCollapsed - indicates whether the group is collapsed or not.
       */
      PropertyPane.prototype._propertyPaneGroupStateChanged = function (pageNumber, groupName, isCollapsed) {
          if (!this._propertyPanePagesStateMap[pageNumber]) {
              this._propertyPanePagesStateMap[pageNumber] = {};
          }
          this._propertyPanePagesStateMap[pageNumber][groupName] = isCollapsed;
      };
      Object.defineProperty(PropertyPane.prototype, "_shouldRenderEmptyPage", {
          /**
           * Returns if the empty page should be rendered in property pane.
           */
          get: function () {
              return (!this.props.data.configuration ||
                  !this.props.data.configuration.pages ||
                  this.props.data.configuration.pages.length === 0 ||
                  !this.props.data.configuration.pages[this.state.currentPage - 1].groups ||
                  this.props.data.configuration.pages[this.state.currentPage - 1].groups.length === 0);
          },
          enumerable: false,
          configurable: true
      });
      /**
       * Flips the page based on the direction.
       * @param direction - direction of the page flip. Positive value is forward direction, negative is backwards.
       */
      PropertyPane.prototype._flipPage = function (direction) {
          var page = this.state.currentPage + direction;
          this.setState({
              currentPage: page
          });
          // trigger rendering the page
          if (this.props.data.render) {
              this.props.data.render();
          }
          this._setTimeOutForFocus();
      };
      PropertyPane.prototype._enableSaveButton = function (enabled) {
          this.setState({
              isSaveButtonEnabled: enabled
          });
      };
      PropertyPane.prototype._handleSaveClick = function () {
          var _this = this;
          this.setState({
              saveConfirmationMessage: strings.SaveConfirmation
          });
          this._enableSaveButton(false);
          setTimeout(function () {
              _this.setState({
                  saveConfirmationMessage: ''
              });
          }, CLEAR_DELAY);
          this.props.data.onConfigurationEvent('ApplyClicked');
      };
      PropertyPane.prototype._handleCloseClick = function () {
          this._resetState(NO_WEBPART_ID);
          this._updateTabIndexes(-1, false);
          this.props.data.onConfigurationEvent('Closed');
      };
      /* tslint:disable-next-line:no-any */
      PropertyPane.prototype._raiseEventImpl = function (targetProperty, value, fieldType) {
          this.props.data.onPropertyPaneFieldChanged(targetProperty, value, fieldType);
      };
      /* tslint:disable-next-line:no-any */
      PropertyPane.prototype._raiseEvent = function (targetProperty, value, fieldType) {
          var fn = this._debounceCallbacks.get(targetProperty) || this._raiseEventImpl;
          fn(targetProperty, value, fieldType);
      };
      PropertyPane.prototype._onPropertyPaneKeyDown = function (ev) {
          if (isKey(KeyCodes.escape, ev) && !ev.defaultPrevented) {
              ev.preventDefault();
              this._handleCloseClick();
          }
          else if (isKey(ExtendedKeyCodes.P, ev, true)) {
              ev.preventDefault();
              this._propertyPaneShouldLooseFocus();
          }
      };
      /**
       * Handles the case when the user presses 'Alt + P'(it's the key combination to toggle the PropertyPane focus)
       * while the Propertypane is in focus.
       *
       * @private
       */
      PropertyPane.prototype._propertyPaneShouldLooseFocus = function () {
          this._resetState(NO_WEBPART_ID);
          this._updateTabIndexes(-1, false);
          this.props.data.onConfigurationEvent('LostFocus');
      };
      PropertyPane.prototype._setTimeOutForFocus = function () {
          var _this = this;
          if (!this._isManagingFocusBySettings) {
              setTimeout(function () {
                  var propertyPane = _this._shouldRenderEmptyPage
                      ? _this._propertyPane.current
                      : _this._propertyPaneContent;
                  _this._focusOnFirstActionableElement(propertyPane);
              }, 0);
          }
      };
      Object.defineProperty(PropertyPane.prototype, "_isManagingFocusBySettings", {
          get: function () {
              return (this.props.data.configuration &&
                  this.props.data.configuration.pages &&
                  this.props.data.configuration.pages.some(function (page) {
                      return page.groups.some(function (group) {
                          // Checking if the group is PropertyPaneConditionalGroup, if yes then extracting
                          // the required group from it.
                          if ('primaryGroup' in group) {
                              var _a = group, primaryGroup = _a.primaryGroup, secondaryGroup = _a.secondaryGroup, showSecondaryGroup = _a.showSecondaryGroup;
                              group = showSecondaryGroup ? secondaryGroup : primaryGroup;
                          }
                          group = group;
                          return (group.groupFields
                              // tslint:disable-next-line:no-any
                              .some(function (groupField) { return groupField.shouldFocus || false; }));
                      });
                  }));
          },
          enumerable: false,
          configurable: true
      });
      PropertyPane.prototype._focusOnFirstActionableElement = function (propertyPane) {
          if (propertyPane) {
              var firstElement = getFirstFocusableChild(propertyPane);
              if (firstElement) {
                  firstElement.focus();
              }
          }
      };
      /**
       * Method to update the tab indexes of all the elements in the root to the given value.
       * @param tabIndex
       */
      PropertyPane.prototype._updateTabIndexes = function (tabIndex, ignoreTabIndexes) {
          var rootElement = this._propertyPane.current;
          var elements = getFocusableChildren(rootElement, ignoreTabIndexes);
          for (var _i = 0, elements_1 = elements; _i < elements_1.length; _i++) {
              var el = elements_1[_i];
              el.tabIndex = tabIndex;
          }
      };
      /**
       * Resetting the PropertyPane state.
       * @param webPartId - web part id to be configured with.
       */
      PropertyPane.prototype._resetState = function (webPartId) {
          this._isPropertyPaneReplaced = true;
          this._currentlyConfiguredWebPartId = webPartId;
          this.setState({
              isSaveButtonEnabled: false,
              saveConfirmationMessage: '',
              currentPage: 1
          });
      };
      PropertyPane.prototype._getCssBottomValueForPageContentElement = function () {
          var pageContentBottom = undefined;
          // non-reactive property pane case.
          if (!this.props.data.isReactive) {
              pageContentBottom = propertyPaneStyles.oneRowFooter;
          }
          if (this.props.data.configuration &&
              this.props.data.configuration.pages &&
              this.props.data.configuration.pages.length &&
              this.props.data.configuration.pages.length > 1) {
              if (!pageContentBottom) {
                  pageContentBottom = propertyPaneStyles.oneRowFooter;
              }
              else {
                  pageContentBottom = propertyPaneStyles.twoRowFooter;
              }
          }
          return pageContentBottom;
      };
      return PropertyPane;
  }(React.Component));
  export default PropertyPane;
  //# sourceMappingURL=PropertyPane.js.map