"use strict";

var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard");

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");

exports.__esModule = true;
exports.default = void 0;

var _extends3 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));

var _objectWithoutPropertiesLoose2 = _interopRequireDefault(require("@babel/runtime/helpers/objectWithoutPropertiesLoose"));

var _react = _interopRequireWildcard(require("react"));

var _propTypes = _interopRequireDefault(require("prop-types"));

var _omit = _interopRequireDefault(require("lodash/omit"));

var _pick = _interopRequireDefault(require("lodash/pick"));

var _isNil = _interopRequireDefault(require("lodash/isNil"));

var _isFunction = _interopRequireDefault(require("lodash/isFunction"));

var _shallowEqual = _interopRequireDefault(require("../utils/shallowEqual"));

var _DropdownMenu = _interopRequireDefault(require("./DropdownMenu"));

var _treeUtils = require("../utils/treeUtils");

var _utils = require("./utils");

var _utils2 = require("../utils");

var _Picker = require("../Picker");

var defaultProps = {
  as: 'div',
  classPrefix: 'picker',
  cleanable: true,
  placement: 'bottomStart',
  appearance: 'default',
  data: [],
  disabledItemValues: [],
  childrenKey: 'children',
  valueKey: 'value',
  labelKey: 'label',
  searchable: true
};

var Cascader = /*#__PURE__*/_react.default.forwardRef(function (props, ref) {
  var Component = props.as,
      data = props.data,
      classPrefix = props.classPrefix,
      childrenKey = props.childrenKey,
      valueKey = props.valueKey,
      labelKey = props.labelKey,
      defaultValue = props.defaultValue,
      placeholder = props.placeholder,
      disabled = props.disabled,
      disabledItemValues = props.disabledItemValues,
      cleanable = props.cleanable,
      overrideLocale = props.locale,
      toggleAs = props.toggleAs,
      style = props.style,
      valueProp = props.value,
      inline = props.inline,
      menuClassName = props.menuClassName,
      menuStyle = props.menuStyle,
      menuWidth = props.menuWidth,
      menuHeight = props.menuHeight,
      searchable = props.searchable,
      parentSelectable = props.parentSelectable,
      placement = props.placement,
      id = props.id,
      renderMenuItem = props.renderMenuItem,
      renderValue = props.renderValue,
      renderMenu = props.renderMenu,
      renderExtraFooter = props.renderExtraFooter,
      onEnter = props.onEnter,
      onExited = props.onExited,
      onClean = props.onClean,
      onChange = props.onChange,
      onSelect = props.onSelect,
      onSearch = props.onSearch,
      onClose = props.onClose,
      onOpen = props.onOpen,
      getChildren = props.getChildren,
      rest = (0, _objectWithoutPropertiesLoose2.default)(props, ["as", "data", "classPrefix", "childrenKey", "valueKey", "labelKey", "defaultValue", "placeholder", "disabled", "disabledItemValues", "cleanable", "locale", "toggleAs", "style", "value", "inline", "menuClassName", "menuStyle", "menuWidth", "menuHeight", "searchable", "parentSelectable", "placement", "id", "renderMenuItem", "renderValue", "renderMenu", "renderExtraFooter", "onEnter", "onExited", "onClean", "onChange", "onSelect", "onSearch", "onClose", "onOpen", "getChildren"]); // Use component active state to support keyboard events.

  var _useState = (0, _react.useState)(false),
      active = _useState[0],
      setActive = _useState[1];

  var _useState2 = (0, _react.useState)((0, _treeUtils.flattenTree)(data)),
      flattenData = _useState2[0],
      setFlattenData = _useState2[1];

  var triggerRef = (0, _react.useRef)();
  var overlayRef = (0, _react.useRef)();
  var targetRef = (0, _react.useRef)();

  var _useControlled = (0, _utils2.useControlled)(valueProp, defaultValue),
      value = _useControlled[0],
      setValue = _useControlled[1];

  var _usePaths = (0, _utils.usePaths)({
    data: data,
    valueKey: valueKey,
    childrenKey: childrenKey,
    value: value
  }),
      selectedPaths = _usePaths.selectedPaths,
      valueToPaths = _usePaths.valueToPaths,
      columnData = _usePaths.columnData,
      addColumn = _usePaths.addColumn,
      setValueToPaths = _usePaths.setValueToPaths,
      setColumnData = _usePaths.setColumnData,
      setSelectedPaths = _usePaths.setSelectedPaths,
      enforceUpdate = _usePaths.enforceUpdate;

  (0, _react.useEffect)(function () {
    setFlattenData((0, _treeUtils.flattenTree)(data));
  }, [data]);
  (0, _Picker.usePublicMethods)(ref, {
    triggerRef: triggerRef,
    overlayRef: overlayRef,
    targetRef: targetRef
  });

  var _useCustom = (0, _utils2.useCustom)('Picker', overrideLocale),
      locale = _useCustom.locale,
      rtl = _useCustom.rtl;
  /**
   * 1.Have a value and the value is valid.
   * 2.Regardless of whether the value is valid, as long as renderValue is set, it is judged to have a value.
   */


  var hasValue = valueToPaths.length > 0 || !(0, _isNil.default)(value) && (0, _isFunction.default)(renderValue);

  var _useClassNames = (0, _utils2.useClassNames)(classPrefix),
      prefix = _useClassNames.prefix,
      merge = _useClassNames.merge;

  var _useState3 = (0, _react.useState)(''),
      searchKeyword = _useState3[0],
      setSearchKeyword = _useState3[1];

  var someKeyword = (0, _react.useCallback)(function (item, keyword) {
    if (item[labelKey].match(new RegExp((0, _utils2.getSafeRegExpString)(keyword || searchKeyword), 'i'))) {
      return true;
    }

    if (item.parent && someKeyword(item.parent)) {
      return true;
    }

    return false;
  }, [labelKey, searchKeyword]);
  var getSearchResult = (0, _react.useCallback)(function (keyword) {
    var items = [];
    var result = flattenData.filter(function (item) {
      if (item[childrenKey]) {
        return false;
      }

      return someKeyword(item, keyword);
    });

    for (var i = 0; i < result.length; i++) {
      items.push(result[i]); // A maximum of 100 search results are returned.

      if (i === 99) {
        return items;
      }
    }

    return items;
  }, [childrenKey, flattenData, someKeyword]); // Used to hover the focuse item  when trigger `onKeydown`

  var _useFocusItemValue = (0, _Picker.useFocusItemValue)(value, {
    rtl: rtl,
    data: flattenData,
    valueKey: valueKey,
    defaultLayer: (valueToPaths === null || valueToPaths === void 0 ? void 0 : valueToPaths.length) ? valueToPaths.length - 1 : 0,
    target: function target() {
      return overlayRef.current;
    },
    callback: (0, _react.useCallback)(function (value) {
      enforceUpdate(value, true);
    }, [enforceUpdate])
  }),
      focusItemValue = _useFocusItemValue.focusItemValue,
      setFocusItemValue = _useFocusItemValue.setFocusItemValue,
      setLayer = _useFocusItemValue.setLayer,
      setKeys = _useFocusItemValue.setKeys,
      onFocusItem = _useFocusItemValue.onKeyDown;

  var handleSearch = (0, _react.useCallback)(function (value, event) {
    var items = getSearchResult(value);
    setSearchKeyword(value);
    onSearch === null || onSearch === void 0 ? void 0 : onSearch(value, event);

    if (items === null || items === void 0 ? void 0 : items[0]) {
      setFocusItemValue(items === null || items === void 0 ? void 0 : items[0]);
      setLayer(0);
      setKeys([]);
    }
  }, [getSearchResult, onSearch, setFocusItemValue, setKeys, setLayer]);
  var handleEntered = (0, _react.useCallback)(function () {
    onOpen === null || onOpen === void 0 ? void 0 : onOpen();
    setActive(true);
  }, [onOpen]);
  var handleExited = (0, _react.useCallback)(function () {
    onClose === null || onClose === void 0 ? void 0 : onClose();
    setActive(false);
    setSearchKeyword('');
  }, [onClose]);
  var handleClose = (0, _react.useCallback)(function () {
    var _triggerRef$current;

    (_triggerRef$current = triggerRef.current) === null || _triggerRef$current === void 0 ? void 0 : _triggerRef$current.close();
  }, [triggerRef]);
  var handleClean = (0, _react.useCallback)(function (event) {
    if (disabled) {
      return;
    }

    setColumnData([data]);
    setValue(null);
    setSelectedPaths([]);
    setValueToPaths([]);
    onChange === null || onChange === void 0 ? void 0 : onChange(null, event);
  }, [data, disabled, onChange, setSelectedPaths, setColumnData, setValueToPaths, setValue]);
  var handleMenuPressEnter = (0, _react.useCallback)(function (event) {
    var focusItem = (0, _treeUtils.findNodeOfTree)(data, function (item) {
      return item[valueKey] === focusItemValue;
    });
    var isLeafNode = focusItem && !focusItem[childrenKey];

    if (isLeafNode) {
      setValue(focusItemValue);
      setValueToPaths(selectedPaths);

      if (selectedPaths.length) {
        setLayer(selectedPaths.length - 1);
      }

      if (!(0, _shallowEqual.default)(value, focusItemValue)) {
        onChange === null || onChange === void 0 ? void 0 : onChange(focusItemValue, event);
      }

      handleClose();
    }
  }, [childrenKey, data, focusItemValue, handleClose, onChange, selectedPaths, setLayer, setValue, setValueToPaths, value, valueKey]);
  var onPickerKeyDown = (0, _Picker.useToggleKeyDownEvent)((0, _extends3.default)({
    toggle: !focusItemValue || !active,
    triggerRef: triggerRef,
    targetRef: targetRef,
    overlayRef: overlayRef,
    active: active,
    onExit: handleClean,
    onMenuKeyDown: onFocusItem,
    onMenuPressEnter: handleMenuPressEnter
  }, rest));

  var handleSelect = function handleSelect(node, cascadeData, cascadePaths, isLeafNode, event) {
    var _node$children, _triggerRef$current2;

    var nextValue = node[valueKey];
    onSelect === null || onSelect === void 0 ? void 0 : onSelect(node, cascadePaths, event);
    setSelectedPaths(cascadePaths);
    setColumnData(cascadeData); // Lazy load node's children

    if (typeof getChildren === 'function' && ((_node$children = node.children) === null || _node$children === void 0 ? void 0 : _node$children.length) === 0) {
      node.loading = true;
      var children = getChildren(node);

      if (children instanceof Promise) {
        children.then(function (data) {
          node.loading = false;
          node[childrenKey] = data;
          addColumn(data, cascadePaths.length);
        });
      } else {
        node.loading = false;
        node[childrenKey] = children;
        addColumn(children, cascadePaths.length);
      }
    }

    if (isLeafNode) {
      // Determines whether the option is a leaf node, and if so, closes the picker.
      handleClose(); // Update the selected path to the value path.
      // That is, the selected path will be displayed on the button after clicking the child node.

      setValueToPaths(cascadePaths);
      setValue(nextValue);

      if (!(0, _shallowEqual.default)(value, nextValue)) {
        onChange === null || onChange === void 0 ? void 0 : onChange(nextValue, event);
      }

      return;
    }
    /** When the parent is optional, the value and the displayed path are updated. */


    if (parentSelectable && !(0, _shallowEqual.default)(value, nextValue)) {
      setValue(nextValue);
      onChange === null || onChange === void 0 ? void 0 : onChange(nextValue, event);
      setValueToPaths(cascadePaths);
    } // Update menu position


    (_triggerRef$current2 = triggerRef.current) === null || _triggerRef$current2 === void 0 ? void 0 : _triggerRef$current2.updatePosition();
  };
  /**
   * The search structure option is processed after being selected.
   */


  var handleSearchRowSelect = function handleSearchRowSelect(node, nodes, event) {
    var nextValue = node[valueKey];
    handleClose();
    setSearchKeyword('');
    setValue(nextValue);
    setValueToPaths(nodes);
    enforceUpdate(nextValue);
    onSelect === null || onSelect === void 0 ? void 0 : onSelect(node, null, event);
    onChange === null || onChange === void 0 ? void 0 : onChange(nextValue, event);
  };

  var renderSearchRow = function renderSearchRow(item, key) {
    var regx = new RegExp((0, _utils2.getSafeRegExpString)(searchKeyword), 'ig');
    var nodes = (0, _treeUtils.getNodeParents)(item);
    nodes.push(item);
    var formattedNodes = nodes.map(function (node) {
      var _extends2;

      var labelElements = [];
      var a = node[labelKey].split(regx);
      var b = node[labelKey].match(regx);

      for (var i = 0; i < a.length; i++) {
        labelElements.push(a[i]);

        if (b && b[i]) {
          labelElements.push( /*#__PURE__*/_react.default.createElement("strong", {
            key: i
          }, b[i]));
        }
      }

      return (0, _extends3.default)({}, node, (_extends2 = {}, _extends2[labelKey] = labelElements, _extends2));
    });
    var disabled = disabledItemValues.some(function (value) {
      return formattedNodes.some(function (node) {
        return node[valueKey] === value;
      });
    });
    var itemClasses = prefix('cascader-row', {
      'cascader-row-disabled': disabled,
      'cascader-row-focus': item[valueKey] === focusItemValue
    });
    return /*#__PURE__*/_react.default.createElement("div", {
      key: key,
      "aria-disabled": disabled,
      "data-key": item[valueKey],
      className: itemClasses,
      onClick: function onClick(event) {
        if (!disabled) {
          handleSearchRowSelect(item, nodes, event);
        }
      }
    }, formattedNodes.map(function (node, index) {
      return /*#__PURE__*/_react.default.createElement("span", {
        key: "col-" + index,
        className: prefix('cascader-col')
      }, node[labelKey]);
    }));
  };

  var renderSearchResultPanel = function renderSearchResultPanel() {
    if (searchKeyword === '') {
      return null;
    }

    var items = getSearchResult();
    return /*#__PURE__*/_react.default.createElement("div", {
      className: prefix('cascader-search-panel'),
      "data-layer": 0
    }, items.length ? items.map(renderSearchRow) : /*#__PURE__*/_react.default.createElement("div", {
      className: prefix('none')
    }, locale.noResultsText));
  };

  var renderDropdownMenu = function renderDropdownMenu(positionProps, speakerRef) {
    var _ref = positionProps || {},
        left = _ref.left,
        top = _ref.top,
        className = _ref.className;

    var styles = (0, _extends3.default)({}, menuStyle, {
      left: left,
      top: top
    });
    var classes = merge(className, menuClassName, prefix('cascader-menu', {
      inline: inline
    }));
    return /*#__PURE__*/_react.default.createElement(_Picker.PickerOverlay, {
      ref: (0, _utils2.mergeRefs)(overlayRef, speakerRef),
      className: classes,
      style: styles,
      target: triggerRef,
      onKeyDown: onPickerKeyDown
    }, searchable && /*#__PURE__*/_react.default.createElement(_Picker.SearchBar, {
      placeholder: locale === null || locale === void 0 ? void 0 : locale.searchPlaceholder,
      onChange: handleSearch,
      value: searchKeyword
    }), renderSearchResultPanel(), searchKeyword === '' && /*#__PURE__*/_react.default.createElement(_DropdownMenu.default, {
      id: id ? id + "-listbox" : undefined,
      menuWidth: menuWidth,
      menuHeight: menuHeight,
      disabledItemValues: disabledItemValues,
      valueKey: valueKey,
      labelKey: labelKey,
      childrenKey: childrenKey,
      classPrefix: 'picker-cascader-menu',
      cascadeData: columnData,
      cascadePaths: selectedPaths,
      activeItemValue: value,
      loadingText: locale === null || locale === void 0 ? void 0 : locale.loading,
      onSelect: handleSelect,
      renderMenu: renderMenu,
      renderMenuItem: renderMenuItem
    }), renderExtraFooter === null || renderExtraFooter === void 0 ? void 0 : renderExtraFooter());
  };

  var selectedElement = placeholder;

  if (valueToPaths.length > 0) {
    selectedElement = [];
    valueToPaths.forEach(function (item, index) {
      var key = item[valueKey] || item[labelKey];
      selectedElement.push( /*#__PURE__*/_react.default.createElement("span", {
        key: key
      }, item[labelKey]));

      if (index < valueToPaths.length - 1) {
        selectedElement.push( /*#__PURE__*/_react.default.createElement("span", {
          className: "separator",
          key: key + "-separator"
        }, ' / '));
      }
    });
  }

  if (!(0, _isNil.default)(value) && (0, _isFunction.default)(renderValue)) {
    selectedElement = renderValue(value, valueToPaths, selectedElement); // If renderValue returns null or undefined, hasValue is false.

    if ((0, _isNil.default)(selectedElement)) {
      hasValue = false;
    }
  }

  var _usePickerClassName = (0, _Picker.usePickerClassName)((0, _extends3.default)({}, props, {
    hasValue: hasValue,
    name: 'cascader'
  })),
      classes = _usePickerClassName[0],
      usedClassNamePropKeys = _usePickerClassName[1];

  if (inline) {
    return renderDropdownMenu();
  }

  return /*#__PURE__*/_react.default.createElement(_Picker.PickerToggleTrigger, {
    pickerProps: (0, _pick.default)(props, _Picker.pickTriggerPropKeys),
    ref: triggerRef,
    placement: placement,
    onEntered: (0, _utils2.createChainedFunction)(handleEntered, onEnter),
    onExited: (0, _utils2.createChainedFunction)(handleExited, onExited),
    speaker: renderDropdownMenu
  }, /*#__PURE__*/_react.default.createElement(Component, {
    className: classes,
    style: style
  }, /*#__PURE__*/_react.default.createElement(_Picker.PickerToggle, (0, _extends3.default)({}, (0, _omit.default)(rest, [].concat(_Picker.omitTriggerPropKeys, usedClassNamePropKeys)), {
    id: id,
    ref: targetRef,
    as: toggleAs,
    disabled: disabled,
    onClean: (0, _utils2.createChainedFunction)(handleClean, onClean),
    onKeyDown: onPickerKeyDown,
    cleanable: cleanable && !disabled,
    hasValue: hasValue,
    active: active,
    placement: placement,
    inputValue: value
  }), selectedElement || (locale === null || locale === void 0 ? void 0 : locale.placeholder))));
});

Cascader.displayName = 'Cascader';
Cascader.defaultProps = defaultProps;
Cascader.propTypes = (0, _extends3.default)({}, _Picker.listPickerPropTypes, {
  disabledItemValues: _propTypes.default.array,
  locale: _propTypes.default.any,
  appearance: _propTypes.default.oneOf(['default', 'subtle']),
  renderMenu: _propTypes.default.func,
  onSelect: _propTypes.default.func,
  onSearch: _propTypes.default.func,
  cleanable: _propTypes.default.bool,
  renderMenuItem: _propTypes.default.func,
  menuWidth: _propTypes.default.number,
  menuHeight: _propTypes.default.oneOfType([_propTypes.default.number, _propTypes.default.string]),
  searchable: _propTypes.default.bool,
  inline: _propTypes.default.bool,
  parentSelectable: _propTypes.default.bool
});
var _default = Cascader;
exports.default = _default;