"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
var _utils = require("../../utils");
var _react = _interopRequireWildcard(require("react"));
var _propTypes = _interopRequireDefault(require("prop-types"));
var _classnames = _interopRequireDefault(require("classnames"));
var _constants = require("../../constants");
var _ButtonGroup = _interopRequireDefault(require("../ButtonGroup"));
var _Input = _interopRequireDefault(require("../Input"));
var _Button = _interopRequireDefault(require("../Button"));
var _Badge = _interopRequireDefault(require("../Badge"));
var _Menu = _interopRequireWildcard(require("../Menu"));
var _ResponsiveContext = _interopRequireDefault(require("../ResponsiveContext"));
var _DistractionFreeModeContext = _interopRequireDefault(require("../DistractionFreeModeContext"));
var _utils2 = require("../utils");
var _jsxRuntime = require("react/jsx-runtime");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
// Copyright 1999-2023. Plesk International GmbH. All rights reserved.

/**
 * `SearchBar` component is used for providing type-as-you-go search.
 * @since 0.0.58
 */
class SearchBar extends _react.Component {
  constructor() {
    super(...arguments);
    (0, _defineProperty2.default)(this, "state", {
      focused: false,
      overMenu: false,
      value: this.props.inputProps.value || '',
      highlightedValue: null
    });
    (0, _defineProperty2.default)(this, "isFocusScheduled", false);
    (0, _defineProperty2.default)(this, "keyboardNavigation", key => {
      const {
        onItemSelect,
        results
      } = this.props;
      const highlightedValue = this.getHighlightedValue();
      if (!results || !onItemSelect) {
        return;
      }
      const res = this.getResults();
      const currentIndex = res.indexOf(highlightedValue);
      let nextIndex;
      if (key === 'ArrowUp') {
        nextIndex = Math.max(currentIndex - 1, 0);
      } else if (key === 'ArrowDown') {
        nextIndex = Math.min(currentIndex + 1, res.length - 1);
      }
      this.setState({
        highlightedValue: currentIndex === -1 ? null : res[nextIndex]
      });
    });
    (0, _defineProperty2.default)(this, "handleFocus", () => {
      this.setState({
        focused: true
      });
      this.search && this.search.focus();
    });
    (0, _defineProperty2.default)(this, "handleBlur", () => {
      this.setState({
        focused: false
      });
      this.search && this.search.blur();
    });
    (0, _defineProperty2.default)(this, "handleMenuMouseOver", () => {
      this.setState({
        overMenu: true
      });
    });
    (0, _defineProperty2.default)(this, "handleMenuMouseOut", () => {
      this.setState({
        overMenu: false
      });
    });
    (0, _defineProperty2.default)(this, "handleKeyDown", e => {
      const {
        onTyping
      } = this.props;
      const {
        value
      } = e.target;
      if (['Enter', 'Escape', 'ArrowUp', 'ArrowDown'].indexOf(e.key) !== -1) {
        this.checkKeys(e.key);
        return;
      }
      this.setState({
        value
      });
      if (onTyping) {
        onTyping(value, () => this.clearInput());
      }
    });
    (0, _defineProperty2.default)(this, "handleSearch", () => {
      const {
        onSearch,
        onTyping
      } = this.props;
      const {
        value
      } = this.state;
      if (onSearch) {
        onSearch(value, () => this.clearInput());
      } else if (onTyping) {
        onTyping(value, () => this.clearInput());
      }
    });
    (0, _defineProperty2.default)(this, "handleReset", () => {
      this.clearInput();
      this.handleFocus();
    });
    (0, _defineProperty2.default)(this, "handleSelect", value => () => {
      const {
        onItemSelect
      } = this.props;
      this.setState({
        highlightedValue: null
      });
      this.handleBlur();
      if (onItemSelect) {
        onItemSelect(value, () => this.clearInput());
      } else {
        this.clearInput();
      }
    });
    (0, _defineProperty2.default)(this, "handleExpand", () => {
      const {
        onExpand,
        distractionFreeMode
      } = this.props;
      this.isFocusScheduled = true;
      (0, _utils2.safeInvoke)(onExpand);
      if (distractionFreeMode) {
        distractionFreeMode.toggle();
      }
    });
    (0, _defineProperty2.default)(this, "handleCollapse", () => {
      const {
        onCollapse,
        distractionFreeMode
      } = this.props;
      (0, _utils2.safeInvoke)(onCollapse);
      if (distractionFreeMode) {
        distractionFreeMode.toggle();
      }
    });
  }
  static getDerivedStateFromProps(props, state) {
    const {
      inputProps: {
        value: inputPropsValue
      } = {}
    } = props;
    const {
      prevInputProps: {
        value: prevInputPropsValue
      } = {}
    } = state;
    const nextState = {};
    if (inputPropsValue !== prevInputPropsValue) {
      nextState.value = inputPropsValue;
    }
    nextState.prevInputProps = props.inputProps;
    return nextState;
  }
  componentDidUpdate() {
    if (this.isFocusScheduled) {
      this.handleFocus();
      this.isFocusScheduled = false;
    }
  }
  isResponsive() {
    return this.props.responsive;
  }
  getResults() {
    let innerResults = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : false;
    const {
      results
    } = this.props;
    if (!results) {
      return [];
    }
    if (results.type === _Menu.default || innerResults) {
      let res = [];
      const children = innerResults || results.props.children;
      for (let i = 0; i < children.length; i++) {
        const child = children[i];
        if (!child) {
          continue;
        }
        if (child instanceof Array) {
          res = res.concat(this.getResults(child));
        } else if (child.type === _Menu.MenuItem || child.type === _Menu.MenuSelectableItem) {
          res.push(child.key);
        }
      }
      return res;
    }
    return results.map(item => item.value);
  }
  getHighlightedValue() {
    return this.state.highlightedValue || this.getResults()[0];
  }
  searchAction() {
    const {
      onItemSelect,
      results
    } = this.props;
    const highlightedValue = this.getHighlightedValue();
    if (onItemSelect && results) {
      const res = this.getResults();
      const currentIndex = res.indexOf(highlightedValue);
      if (currentIndex === -1) {
        this.handleSearch();
      } else {
        this.handleSelect(highlightedValue)();
      }
    } else {
      this.handleSearch();
    }
  }
  checkKeys(key) {
    if (key === 'Enter') {
      this.searchAction();
    } else if (key === 'Escape') {
      if (this.state.value) {
        this.handleReset();
      } else {
        this.handleBlur();
        this.handleMenuMouseOut();
      }
    } else if (key === 'ArrowUp' || key === 'ArrowDown') {
      this.keyboardNavigation(key);
    }
  }
  clearInput() {
    this.setState({
      value: ''
    }, this.handleSearch);
  }
  elementsIndexToKeyMapping(elements) {
    let result = [];
    for (let i = 0; i < elements.length; i++) {
      const element = elements[i];
      if (!element) {
        continue;
      }
      if (element instanceof Array) {
        result = result.concat(this.elementsIndexToKeyMapping(element));
      } else {
        result.push(element.key);
      }
    }
    return result;
  }
  renderResults() {
    const {
      baseClassName,
      results
    } = this.props;
    const {
      focused,
      overMenu
    } = this.state;
    const highlightedValue = this.getHighlightedValue();
    if (!results || results.length === 0) {
      return null;
    }
    return /*#__PURE__*/(0, _jsxRuntime.jsx)(_Menu.default, {
      className: (0, _classnames.default)(`${baseClassName}__results`, {
        [`${baseClassName}__results--hidden`]: !focused && !overMenu
      }),
      onMouseOver: this.handleMenuMouseOver,
      onMouseOut: this.handleMenuMouseOut,
      children: results.map(item => /*#__PURE__*/(0, _jsxRuntime.jsx)(_Menu.MenuItem, {
        active: item.value === highlightedValue,
        onClick: this.handleSelect(item.value),
        children: item.title
      }, item.value))
    });
  }
  renderResultsMenu() {
    const {
      baseClassName,
      results,
      onItemSelect
    } = this.props;
    const {
      focused,
      overMenu
    } = this.state;
    const highlightedValue = this.getHighlightedValue();
    if (!results) {
      return null;
    }
    return /*#__PURE__*/(0, _react.cloneElement)(results, {
      className: (0, _classnames.default)(`${baseClassName}__results`, {
        [`${baseClassName}__results--hidden`]: !focused && !overMenu
      }, results.className),
      onMouseOver: this.handleMenuMouseOver,
      onMouseOut: this.handleMenuMouseOut,
      onItemClick: (item, index) => {
        const indexMap = this.elementsIndexToKeyMapping(results.props.children);
        this.handleSelect(indexMap[index])();
      },
      children: _react.Children.map(results.props.children, child => {
        if (onItemSelect && child && (child.type === _Menu.MenuItem || child.type === _Menu.MenuSelectableItem)) {
          return /*#__PURE__*/(0, _react.cloneElement)(child, {
            active: child.key === highlightedValue
          });
        }
        return child;
      })
    });
  }
  render() {
    const {
      baseClassName,
      className,
      maxWidth,
      minWidth,
      loading,
      responsive,
      onSearch,
      onTyping,
      onItemSelect,
      collapsable,
      onCollapse,
      onExpand,
      results,
      inputProps,
      distractionFreeMode,
      ...props
    } = this.props;
    const {
      focused,
      value
    } = this.state;
    const isCollapsed = this.isResponsive();
    const distractionFreeModeEnabled = Boolean(distractionFreeMode && distractionFreeMode.enabled);
    return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
      className: (0, _classnames.default)(baseClassName, {
        [`${baseClassName}--focused`]: focused
      }, className),
      style: isCollapsed || distractionFreeModeEnabled ? null : {
        maxWidth,
        minWidth
      },
      ...props,
      children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_ButtonGroup.default, {
        className: `${baseClassName}__group`,
        children: isCollapsed && (collapsable || !distractionFreeModeEnabled) ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_Badge.default, {
          intent: "info",
          hidden: !value,
          children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
            icon: "search",
            onClick: this.handleExpand
          })
        }) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_Input.default, {
          innerRef: ref => this.search = ref,
          className: `${baseClassName}__input`,
          size: "fill",
          onChange: this.handleKeyDown,
          onFocus: this.handleFocus,
          onBlur: this.handleBlur,
          onKeyDown: this.handleKeyDown,
          ...inputProps,
          value: value,
          prefix: (collapsable && !isCollapsed || distractionFreeModeEnabled) && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
            icon: {
              name: 'chevron-right',
              flipHorizontal: (0, _utils.isRtl)()
            },
            ghost: true,
            onClick: this.handleCollapse
          }),
          suffix: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
            children: [value && /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
              icon: "remove",
              onClick: this.handleReset,
              ghost: true
            }), /*#__PURE__*/(0, _jsxRuntime.jsx)(_Button.default, {
              icon: "search",
              onClick: this.handleSearch,
              state: loading ? 'loading' : null,
              ghost: true
            })]
          })
        })
      }), results && results.type === _Menu.default ? this.renderResultsMenu() : this.renderResults()]
    });
  }
}
const propTypes = {
  /**
   * @ignore
   */
  className: _propTypes.default.string,
  /**
   * @ignore
   */
  baseClassName: _propTypes.default.string,
  /**
   * Maximum width of SearchBar
   * @since 0.1.0
   */
  maxWidth: _propTypes.default.number,
  /**
   * Minimum width of SearchBar
   * @since 0.1.0
   */
  minWidth: _propTypes.default.number,
  /**
   * Should disable input and show spinner or not.
   * @since 0.1.0
   */
  loading: _propTypes.default.bool,
  /**
   * Should collapse input or not. Used for control in independence of context.
   * @since 0.1.0
   */
  responsive: _propTypes.default.bool,
  /**
   * Callback for pressing 'Enter' key or 'Search' button.
   *
   * arguments:
   * * value - search value
   * * clearHandler - function that clears input value
   * @since 0.1.0
   */
  onSearch: _propTypes.default.func,
  /**
   * Callback for pressing any key in input. Used for a live search.
   *
   * arguments:
   * * value - search value
   * * clearHandler - function that clears input value
   * @since 0.1.0
   */
  onTyping: _propTypes.default.func,
  /**
   * Callback for selecting menu item with mouse click or key pressing.
   *
   * arguments:
   * * value - selected value
   * * clearHandler - function that clears input value
   * @since 0.1.0
   */
  onItemSelect: _propTypes.default.func,
  /**
   * Should render toggle button or not.
   * @since 2.2.0
   */
  collapsable: _propTypes.default.bool,
  /**
   * Callback for pressing toggle button (in normal mode).
   * @since 2.2.0
   */
  onCollapse: _propTypes.default.func,
  /**
   * Callback for pressing toggle button (in collapsed mode).
   * @since 2.2.0
   */
  onExpand: _propTypes.default.func,
  /**
   * Results to display.
   * Could be specified by array of objects with "value" and "title" properties or by Menu component.
   * If Menu component is used then key property of MenuItem will be treated as value.
   * @since 0.1.0
   */
  results: _propTypes.default.oneOfType([_propTypes.default.arrayOf(_propTypes.default.shape({
    value: _propTypes.default.string.isRequired,
    title: _propTypes.default.string.isRequired
  })), _propTypes.default.element]),
  /**
   * Props of underlying input element.
   * @since 0.4.1
   */
  inputProps: _propTypes.default.object
};
const defaultProps = {
  className: undefined,
  baseClassName: `${_constants.CLS_PREFIX}search-bar`,
  maxWidth: 500,
  minWidth: 270,
  loading: false,
  responsive: undefined,
  onSearch: undefined,
  onTyping: undefined,
  onItemSelect: undefined,
  collapsable: false,
  onCollapse: undefined,
  onExpand: undefined,
  results: undefined,
  inputProps: {}
};
SearchBar.propTypes = {
  ...propTypes,
  distractionFreeMode: _propTypes.default.shape({
    enabled: _propTypes.default.bool.isRequired,
    toggle: _propTypes.default.func.isRequired
  })
};
SearchBar.defaultProps = {
  distractionFreeMode: undefined
};
const SearchBarWrapper = props => {
  const distractionFreeMode = (0, _react.useContext)(_DistractionFreeModeContext.default);
  let responsive = (0, _react.useContext)(_ResponsiveContext.default);
  responsive = props.responsive === undefined ? responsive || false : Boolean(props.responsive);
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(SearchBar, {
    ...props,
    responsive: responsive,
    distractionFreeMode: distractionFreeMode
  });
};
SearchBarWrapper.displayName = 'SearchBar';
SearchBarWrapper.propTypes = propTypes;
SearchBarWrapper.defaultProps = defaultProps;
var _default = exports.default = SearchBarWrapper;