"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.default = void 0;
var _react = require("react");
var _classnames = _interopRequireDefault(require("classnames"));
var _utils = require("../utils");
var _constants = require("../../constants");
var _ComboBoxDropdown = _interopRequireWildcard(require("../ComboBoxDropdown"));
var _Translate = _interopRequireDefault(require("../Translate"));
var _SelectControl = _interopRequireDefault(require("./SelectControl"));
var _SelectOptionGroup = _interopRequireDefault(require("./SelectOptionGroup"));
var _SelectOption = _interopRequireDefault(require("./SelectOption"));
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.

// eslint-disable-next-line default-param-last
const collect = function (children) {
  let options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : [];
  let group = arguments.length > 2 ? arguments[2] : undefined;
  const groups = [];
  _react.Children.forEach(children, child => {
    if ( /*#__PURE__*/(0, _react.isValidElement)(child) && (child.type === _SelectOptionGroup.default || child.type === 'optgroup')) {
      const {
        label,
        children,
        ...props
      } = child.props;
      const group = {
        label: String(label),
        options: [],
        props
      };
      groups.push(group);
      collect(children, options, group);
    } else if ( /*#__PURE__*/(0, _react.isValidElement)(child) && (child.type === _SelectOption.default || child.type === 'option')) {
      // eslint-disable-next-line prefer-const
      let {
        value,
        label: propLabel,
        disabled,
        children,
        ...props
      } = child.props;
      if (typeof value !== 'string' && typeof value !== 'number') {
        if (typeof children === 'string' && children) {
          value = children;
        } else {
          throw new Error('The value can only be a number or a string.');
        }
      }
      let label;
      if (propLabel && typeof propLabel === 'string') {
        ({
          label
        } = child.props);
      } else if (typeof child.props.children === 'string') {
        label = child.props.children;
      }
      if (!label) {
        throw new Error('The label can only be a string.');
      }
      const option = {
        value,
        label,
        children,
        disabled: Boolean(disabled),
        group,
        props
      };
      options.push(option);
      if (group) {
        group.options.push(option);
      }
    }
  });
  if (groups.length === 0) {
    groups.push({
      options
    });
  }
  return {
    groups,
    options
  };
};
const getNextValue = (value, prevValue) => {
  if (Array.isArray(prevValue)) {
    return [...prevValue, value];
  }
  return value;
};
/**
 * `Select` component is used for making a choice among a set of related options.
 * @since 2.3.0
 */
const Select = _ref => {
  let {
    id,
    name,
    size,
    baseClassName = `${_constants.CLS_PREFIX}select`,
    className,
    children,
    defaultValue,
    value: propValue,
    onChange,
    disabled = false,
    searchable = false,
    clearable = false,
    multiple = false,
    placeholder,
    ...props
  } = _ref;
  const [opened, setOpened] = (0, _react.useState)(false);
  const controlRef = (0, _react.useRef)(null);
  const emitterRef = (0, _react.useRef)(new _utils.EventEmitter());
  let [value, setValue] = (0, _react.useState)(() => {
    if (typeof defaultValue === 'undefined') {
      return multiple ? [] : undefined;
    }
    return defaultValue;
  });
  if (typeof propValue !== 'undefined') {
    value = propValue;
    setValue = () => {};
  }
  const [filterValue, setFilterValue] = (0, _react.useState)('');
  const [highlightedIndex, setHighlightedIndex] = (0, _react.useState)(0);
  let {
    groups,
    options
  } = collect(children);
  let current;
  if (Array.isArray(value)) {
    const _current = [];
    value.forEach(v => {
      const option = options.find(o => o.value === v);
      if (option) {
        _current.push(option);
      }
    });
    current = _current;
  } else {
    const _current = options.find(o => o.value === value);
    current = _current;
  }
  const groupFns = [];
  const optionFns = [];
  // eslint-disable-next-line func-style
  function createInclude(fns) {
    return item => fns.every(fn => fn(item));
  }
  if (Array.isArray(value) && value.length > 0) {
    const v = value;
    groupFns.push(() => false);
    optionFns.push(option => v.indexOf(option.value) === -1);
  }
  if (filterValue) {
    const lowerFilterValue = filterValue.toLowerCase();
    groupFns.push(group => !!group.label && group.label.toLowerCase().includes(lowerFilterValue));
    optionFns.push(option => option.label.toLowerCase().includes(lowerFilterValue));
  }
  if (groupFns.length || optionFns.length) {
    const includeGroup = createInclude(groupFns);
    const includeOption = createInclude(optionFns);
    options = [];
    groups = groups.filter(group => {
      if (includeGroup(group)) {
        options = [...options, ...group.options];
        return true;
      }
      group.options = group.options.filter(option => {
        if (includeOption(option)) {
          options.push(option);
          return true;
        }
        return false;
      });
      return group.options.length > 0;
    });
  }
  if (highlightedIndex && highlightedIndex > options.length - 1) {
    setHighlightedIndex(0);
  }
  const handleFilterChange = nextFilterValue => {
    handleOpen();
    setFilterValue(nextFilterValue);
  };
  const focusHighlightedIndex = index => {
    emitterRef.current.emit('focus', index);
  };
  const handleHighlightChange = diff => {
    if (!opened) {
      handleOpen();
      return;
    }
    const nextIndex = (0, _ComboBoxDropdown.findNextSafeIndex)(highlightedIndex, diff, options);
    if (nextIndex !== -1) {
      setHighlightedIndex(nextIndex);
      focusHighlightedIndex(nextIndex);
    }
  };
  const handleHighlightConfirm = index => {
    if (!opened && index === undefined) {
      return;
    }
    const option = options[index === undefined ? highlightedIndex : index];
    if (!option) {
      return;
    }
    if (option.disabled) {
      return;
    }
    const nextValue = getNextValue(option.value, value);
    setValue(nextValue);
    setFilterValue('');
    if (!multiple) {
      handleClose();
    }
    (0, _utils.safeInvoke)(onChange, nextValue);
  };
  const handleHighlightSearch = query => {
    const lowerQuery = query.toLowerCase();
    const index = options.findIndex(o => !o.disabled && o.label.toLowerCase().includes(lowerQuery));
    if (index !== -1) {
      setHighlightedIndex(index);
      focusHighlightedIndex(index);
      if (!opened) {
        handleHighlightConfirm(index);
      }
    }
  };
  const handleOpen = () => {
    setOpened(true);
  };
  const handleClose = () => {
    setOpened(false);
    setHighlightedIndex(0);
  };
  const handleSelect = optionValue => {
    const nextValue = getNextValue(optionValue, value);
    setValue(nextValue);
    setFilterValue('');
    if (!multiple) {
      handleClose();
    }
    (0, _utils.safeInvoke)(onChange, nextValue);
  };
  const handleHighlightedIndexChange = index => {
    setHighlightedIndex(index);
  };
  const handleValueRemove = valueToRemove => {
    if (Array.isArray(value)) {
      let nextValue;
      if (valueToRemove === undefined) {
        nextValue = [...value];
        nextValue.pop();
      } else {
        nextValue = value.filter(v => v !== valueToRemove);
      }
      setValue(nextValue);
      (0, _utils.safeInvoke)(onChange, nextValue);
    } else {
      setValue(undefined);
      (0, _utils.safeInvoke)(onChange, undefined);
    }
  };
  const handleClear = () => {
    const nextValue = Array.isArray(value) ? [] : undefined;
    setFilterValue('');
    setValue(nextValue);
    (0, _utils.safeInvoke)(onChange, nextValue);
  };
  const control = /*#__PURE__*/(0, _jsxRuntime.jsx)(_SelectControl.default, {
    id: id,
    name: name,
    current: current,
    filterValue: filterValue,
    searchable: searchable,
    clearable: clearable,
    multiple: multiple,
    disabled: disabled,
    onFilterChange: handleFilterChange,
    onHighlightChange: handleHighlightChange,
    onHighlightConfirm: handleHighlightConfirm,
    onHighlightSearch: handleHighlightSearch,
    onOpen: handleOpen,
    onClose: handleClose,
    onClear: handleClear,
    onValueRemove: handleValueRemove,
    placeholder: placeholder,
    ref: controlRef
  });
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_ComboBoxDropdown.default, {
    className: (0, _classnames.default)(baseClassName, className, {
      [`${baseClassName}--size-${size}`]: size
    }),
    control: control,
    controlRef: controlRef,
    opened: opened && !disabled,
    disabled: disabled,
    groups: groups,
    options: options,
    onSelect: handleSelect,
    highlightedIndex: highlightedIndex,
    onHighlightedIndexChange: handleHighlightedIndexChange,
    onClose: handleClose,
    noOptions: /*#__PURE__*/(0, _jsxRuntime.jsx)(_Translate.default, {
      content: "Select.noOptions",
      fallback: "No options"
    }),
    emitter: emitterRef.current,
    value: value,
    ...props
  });
};
var _default = exports.default = Select;