"use strict";
Object.defineProperties(exports, { __esModule: { value: true }, [Symbol.toStringTag]: { value: "Module" } });
const vue = require("vue");
const comp = require("../../ui/src/comp.js");
require("../../ui/index.js");
const dom = require("../../ui/src/dom.js");
const utils = require("../../ui/src/utils.js");
const util = require("../../tree/src/util.js");
const log = require("../../ui/src/log.js");
const XEUtils = require("xe-utils");
const input = require("../../input/src/input.js");
const button = require("../../button/src/button.js");
const config = require("../../../../@vxe-ui/core/es/src/config.js");
const i18n = require("../../../../@vxe-ui/core/es/src/i18n.js");
const useFns = require("../../../../@vxe-ui/core/es/src/useFns.js");
const event = require("../../../../@vxe-ui/core/es/src/event.js");
const icon = require("../../../../@vxe-ui/core/es/src/icon.js");
const index_esm = require("../../../../@vxe-ui/core/es/index.esm.js");
function getOptUniqueId() {
  return XEUtils.uniqueId("node_");
}
function createInternalData() {
  return {
    // hpTimeout: undefined,
    fullOptionList: [],
    fullNodeMaps: {}
  };
}
const VxeCascaderComponent = comp.defineVxeComponent({
  name: "VxeCascader",
  props: {
    modelValue: [String, Number, Array],
    clearable: Boolean,
    placeholder: {
      type: String,
      default: () => XEUtils.eqNull(config.getConfig().cascader.placeholder) ? i18n.getI18n("vxe.base.pleaseSelect") : config.getConfig().cascader.placeholder
    },
    readonly: {
      type: Boolean,
      default: null
    },
    loading: Boolean,
    disabled: {
      type: Boolean,
      default: null
    },
    filterable: Boolean,
    filterConfig: Object,
    multiple: Boolean,
    className: [String, Function],
    prefixIcon: String,
    placement: String,
    transform: Boolean,
    lazyOptions: Array,
    options: Array,
    optionProps: Object,
    zIndex: Number,
    size: {
      type: String,
      default: () => config.getConfig().cascader.size || config.getConfig().size
    },
    remote: Boolean,
    remoteConfig: Function,
    popupConfig: Object,
    autoClose: {
      type: Boolean,
      default: () => config.getConfig().cascader.autoClose
    },
    showTotalButoon: {
      type: Boolean,
      default: () => config.getConfig().cascader.showTotalButoon
    },
    showCheckedButoon: {
      type: Boolean,
      default: () => config.getConfig().cascader.showCheckedButoon
    },
    showClearButton: {
      type: Boolean,
      default: () => config.getConfig().cascader.showClearButton
    },
    transfer: {
      type: Boolean,
      default: null
    },
    /**
     * 已废弃，被 remote-config.queryMethod 替换
     * @deprecated
     */
    remoteMethod: Function
  },
  emits: [
    "update:modelValue",
    "change",
    "all-change",
    "clear",
    "blur",
    "focus",
    "click",
    "node-click"
  ],
  setup(props, context) {
    const { emit, slots } = context;
    const $xeModal = vue.inject("$xeModal", null);
    const $xeDrawer = vue.inject("$xeDrawer", null);
    const $xeTable = vue.inject("$xeTable", null);
    const $xeForm = vue.inject("$xeForm", null);
    const formItemInfo = vue.inject("xeFormItemInfo", null);
    const xID = XEUtils.uniqueId();
    const { computeSize } = useFns.useSize(props);
    const refElem = vue.ref();
    const refInput = vue.ref();
    const refInpSearch = vue.ref();
    const refTreeWrapper = vue.ref();
    const refOptionPanel = vue.ref();
    const refTree = vue.ref();
    const reactData = vue.reactive({
      initialized: false,
      searchValue: "",
      searchLoading: false,
      panelIndex: 0,
      panelStyle: {},
      panelPlacement: null,
      triggerFocusPanel: false,
      visiblePanel: false,
      isAniVisible: false,
      isActivated: false
    });
    const internalData = createInternalData();
    const refMaps = {
      refElem
    };
    const computeFormReadonly = vue.computed(() => {
      const { readonly } = props;
      if (readonly === null) {
        if ($xeForm) {
          return $xeForm.props.readonly;
        }
        return false;
      }
      return readonly;
    });
    const computeIsDisabled = vue.computed(() => {
      const { disabled } = props;
      if (disabled === null) {
        if ($xeForm) {
          return $xeForm.props.disabled;
        }
        return false;
      }
      return disabled;
    });
    const computeBtnTransfer = vue.computed(() => {
      const { transfer } = props;
      if (transfer === null) {
        const globalTransfer = config.getConfig().select.transfer;
        if (XEUtils.isBoolean(globalTransfer)) {
          return globalTransfer;
        }
        if ($xeTable || $xeModal || $xeDrawer || $xeForm) {
          return true;
        }
      }
      return transfer;
    });
    const computePopupOpts = vue.computed(() => {
      return Object.assign({}, config.getConfig().cascader.popupConfig, props.popupConfig);
    });
    const computePropsOpts = vue.computed(() => {
      return props.optionProps || {};
    });
    const computeNodeKeyField = vue.computed(() => {
      const valueField = computeValueField.value;
      return valueField;
    });
    const computeLabelField = vue.computed(() => {
      const propsOpts = computePropsOpts.value;
      return propsOpts.label || "label";
    });
    const computeValueField = vue.computed(() => {
      const propsOpts = computePropsOpts.value;
      return propsOpts.value || "value";
    });
    const computeChildrenField = vue.computed(() => {
      const propsOpts = computePropsOpts.value;
      return propsOpts.children || "children";
    });
    const computeRemoteOpts = vue.computed(() => {
      return Object.assign({}, config.getConfig().cascader.remoteConfig, props.remoteConfig);
    });
    const computeSelectLabel = vue.computed(() => {
      const { modelValue, lazyOptions } = props;
      const { fullNodeMaps } = internalData;
      const valueField = computeValueField.value;
      const labelField = computeLabelField.value;
      const selectVals = XEUtils.eqNull(modelValue) ? [] : XEUtils.isArray(modelValue) ? modelValue : [modelValue];
      return selectVals.map((val) => {
        const cacheItem = fullNodeMaps[val];
        if (cacheItem) {
          return cacheItem.item[labelField];
        }
        if (lazyOptions) {
          const lazyItem = lazyOptions.find((item) => item[valueField] === val);
          if (lazyItem) {
            return lazyItem[labelField];
          }
        }
        return val;
      }).join(", ");
    });
    const computePopupWrapperStyle = vue.computed(() => {
      const popupOpts = computePopupOpts.value;
      const { height, width } = popupOpts;
      const stys = {};
      if (width) {
        stys.width = dom.toCssUnit(width);
      }
      if (height) {
        stys.height = dom.toCssUnit(height);
        stys.maxHeight = dom.toCssUnit(height);
      }
      return stys;
    });
    const computeMaps = {};
    const $xeCascader = {
      xID,
      props,
      context,
      reactData,
      internalData,
      getRefMaps: () => refMaps,
      getComputeMaps: () => computeMaps
    };
    const dispatchEvent = (type, params, evnt) => {
      emit(type, event.createEvent(evnt, { $cascader: $xeCascader }, params));
    };
    const emitModel = (value) => {
      emit("update:modelValue", value);
    };
    const cascaderMethods = {
      dispatchEvent
    };
    const getNodeid = (option) => {
      const nodeKeyField = computeNodeKeyField.value;
      const nodeid = option[nodeKeyField];
      return nodeid ? encodeURIComponent(nodeid) : "";
    };
    const cacheDataMap = () => {
      const { transform, options } = props;
      const nodeKeyField = computeNodeKeyField.value;
      const childrenField = computeChildrenField.value;
      const valueField = computeValueField.value;
      const nodeMaps = {};
      const keyMaps = {};
      const handleOptNode = (item, index, items, path, parent, nodes) => {
        let nodeid = getNodeid(item);
        if (!nodeid) {
          nodeid = getOptUniqueId();
        }
        if (keyMaps[nodeid]) {
          log.errLog("vxe.error.repeatKey", [`[tree-select] ${nodeKeyField}`, nodeid]);
        }
        keyMaps[nodeid] = true;
        const value = item[valueField];
        if (nodeMaps[value]) {
          log.errLog("vxe.error.repeatKey", [`[tree-select] ${valueField}`, value]);
        }
        nodeMaps[value] = { item, index, items, parent, nodes };
      };
      if (options) {
        if (transform) {
          options.forEach((item, index, items) => {
            handleOptNode(item, index, items, [], null, []);
          });
        } else {
          XEUtils.eachTree(options, handleOptNode, { children: childrenField });
        }
      }
      internalData.fullOptionList = options || [];
      internalData.fullNodeMaps = nodeMaps;
    };
    const updateZindex = () => {
      const { zIndex } = props;
      if (zIndex) {
        reactData.panelIndex = zIndex;
      } else if (reactData.panelIndex < utils.getLastZIndex()) {
        reactData.panelIndex = utils.nextZIndex();
      }
    };
    const updatePlacement = () => {
      const { placement } = props;
      const { panelIndex } = reactData;
      const targetElem = refElem.value;
      const panelElem = refOptionPanel.value;
      const btnTransfer = computeBtnTransfer.value;
      const handleStyle = () => {
        const ppObj = dom.updatePanelPlacement(targetElem, panelElem, {
          placement,
          teleportTo: btnTransfer
        });
        const panelStyle = Object.assign(ppObj.style, {
          zIndex: panelIndex
        });
        reactData.panelStyle = panelStyle;
        reactData.panelPlacement = ppObj.placement;
      };
      handleStyle();
      return vue.nextTick().then(handleStyle);
    };
    const showOptionPanel = () => {
      const { loading, remote, filterable } = props;
      const { fullOptionList } = internalData;
      const isDisabled = computeIsDisabled.value;
      const remoteOpts = computeRemoteOpts.value;
      if (!loading && !isDisabled) {
        clearTimeout(internalData.hpTimeout);
        if (!reactData.initialized) {
          reactData.initialized = true;
        }
        reactData.isActivated = true;
        reactData.isAniVisible = true;
        if (filterable) {
          if (remote && remoteOpts.enabled && remoteOpts.autoLoad && !fullOptionList.length) {
            handleSearchEvent();
          }
        }
        setTimeout(() => {
          reactData.visiblePanel = true;
          handleFocusSearch();
        }, 10);
        updateZindex();
        updatePlacement();
      }
    };
    const hideOptionPanel = () => {
      reactData.visiblePanel = false;
      internalData.hpTimeout = setTimeout(() => {
        reactData.isAniVisible = false;
      }, 350);
    };
    const changeEvent = (evnt, selectValue, node) => {
      const value = XEUtils.isArray(selectValue) ? selectValue.map(util.deNodeValue) : util.deNodeValue(selectValue);
      emitModel(value);
      if (value !== props.modelValue) {
        dispatchEvent("change", { value, node, option: node }, evnt);
        if ($xeForm && formItemInfo) {
          $xeForm.triggerItemEvent(evnt, formItemInfo.itemConfig.field, value);
        }
      }
    };
    const clearValueEvent = (evnt, selectValue) => {
      changeEvent(evnt, selectValue, null);
      dispatchEvent("clear", { value: selectValue }, evnt);
    };
    const clearEvent = (params, evnt) => {
      clearValueEvent(evnt, null);
      hideOptionPanel();
    };
    const allCheckedPanelEvent = (params) => {
      const { $event } = params;
      const { multiple, autoClose } = props;
      const $tree = refTree.value;
      if (multiple) {
        if ($tree) {
          $tree.setAllCheckboxNode(true).then(({ checkNodeKeys, checkNodes }) => {
            changeEvent($event, checkNodeKeys, checkNodes[0]);
            dispatchEvent("all-change", { value: checkNodeKeys }, $event);
            if (autoClose) {
              hideOptionPanel();
            }
          });
        }
      }
    };
    const clearCheckedPanelEvent = (params) => {
      const { $event } = params;
      const { multiple, autoClose } = props;
      const $tree = refTree.value;
      if ($tree) {
        const value = multiple ? [] : null;
        $tree.clearCheckboxNode().then(() => {
          if (autoClose) {
            hideOptionPanel();
          }
        });
        changeEvent($event, value, null);
        dispatchEvent("clear", { value }, $event);
      }
    };
    const handleGlobalMousewheelEvent = (evnt) => {
      const { visiblePanel } = reactData;
      const isDisabled = computeIsDisabled.value;
      if (!isDisabled) {
        if (visiblePanel) {
          const panelElem = refOptionPanel.value;
          if (dom.getEventTargetNode(evnt, panelElem).flag) {
            updatePlacement();
          } else {
            hideOptionPanel();
          }
        }
      }
    };
    const handleGlobalMousedownEvent = (evnt) => {
      const { visiblePanel } = reactData;
      const isDisabled = computeIsDisabled.value;
      if (!isDisabled) {
        const el = refElem.value;
        const panelElem = refOptionPanel.value;
        reactData.isActivated = dom.getEventTargetNode(evnt, el).flag || dom.getEventTargetNode(evnt, panelElem).flag;
        if (visiblePanel && !reactData.isActivated) {
          hideOptionPanel();
        }
      }
    };
    const handleGlobalBlurEvent = () => {
      const { visiblePanel, isActivated } = reactData;
      if (visiblePanel) {
        hideOptionPanel();
      }
      if (isActivated) {
        reactData.isActivated = false;
      }
      if (visiblePanel || isActivated) {
        const $input = refInput.value;
        if ($input) {
          $input.blur();
        }
      }
    };
    const handleGlobalResizeEvent = () => {
      const { visiblePanel } = reactData;
      if (visiblePanel) {
        updatePlacement();
      }
    };
    const handleFocusSearch = () => {
      if (props.filterable) {
        vue.nextTick(() => {
          const inpSearch = refInpSearch.value;
          if (inpSearch) {
            inpSearch.focus();
          }
        });
      }
    };
    const focusEvent = (evnt) => {
      const isDisabled = computeIsDisabled.value;
      if (!isDisabled) {
        if (!reactData.visiblePanel) {
          reactData.triggerFocusPanel = true;
          showOptionPanel();
          setTimeout(() => {
            reactData.triggerFocusPanel = false;
          }, 150);
        }
      }
      dispatchEvent("focus", {}, evnt);
    };
    const clickEvent = (evnt) => {
      togglePanelEvent(evnt);
      dispatchEvent("click", {}, evnt);
    };
    const blurEvent = (evnt) => {
      reactData.isActivated = false;
      dispatchEvent("blur", {}, evnt);
    };
    const modelSearchEvent = (value) => {
      reactData.searchValue = value;
    };
    const handleSearchEvent = () => {
      const { modelValue, remote, remoteMethod } = props;
      const { searchValue } = reactData;
      const remoteOpts = computeRemoteOpts.value;
      const queryMethod = remoteOpts.queryMethod || remoteMethod;
      if (remote && queryMethod && remoteOpts.enabled) {
        reactData.searchLoading = true;
        Promise.resolve(queryMethod({ $cascader: $xeCascader, searchValue, value: modelValue })).then(() => vue.nextTick()).catch(() => vue.nextTick()).finally(() => {
          reactData.searchLoading = false;
        });
      }
    };
    const togglePanelEvent = (params) => {
      const { $event } = params;
      $event.preventDefault();
      if (reactData.triggerFocusPanel) {
        reactData.triggerFocusPanel = false;
      } else {
        if (reactData.visiblePanel) {
          hideOptionPanel();
        } else {
          showOptionPanel();
        }
      }
    };
    const cascaderPrivateMethods = {};
    Object.assign($xeCascader, cascaderMethods, cascaderPrivateMethods);
    const renderVN = () => {
      const { className, modelValue, multiple, loading, filterable, showTotalButoon, showCheckedButoon, showClearButton } = props;
      const { initialized, isActivated, isAniVisible, visiblePanel, searchValue } = reactData;
      const vSize = computeSize.value;
      const isDisabled = computeIsDisabled.value;
      const selectLabel = computeSelectLabel.value;
      const btnTransfer = computeBtnTransfer.value;
      const formReadonly = computeFormReadonly.value;
      const popupWrapperStyle = computePopupWrapperStyle.value;
      const headerSlot = slots.header;
      const footerSlot = slots.footer;
      const prefixSlot = slots.prefix;
      const popupOpts = computePopupOpts.value;
      const popupClassName = popupOpts.className;
      if (formReadonly) {
        return vue.h("div", {
          ref: refElem,
          class: ["vxe-cascader--readonly", className]
        }, [
          vue.h("span", {
            class: "vxe-cascader-label"
          }, selectLabel)
        ]);
      }
      const selectVals = XEUtils.eqNull(modelValue) ? [] : XEUtils.isArray(modelValue) ? modelValue : [modelValue];
      return vue.h("div", {
        ref: refElem,
        class: ["vxe-cascader", className ? XEUtils.isFunction(className) ? className({ $cascader: $xeCascader }) : className : "", {
          [`size--${vSize}`]: vSize,
          "is--filterable": filterable,
          "is--visible": visiblePanel,
          "is--disabled": isDisabled,
          "is--loading": loading,
          "is--active": isActivated
        }]
      }, [
        vue.h(input.default, {
          ref: refInput,
          clearable: props.clearable,
          placeholder: loading ? i18n.getI18n("vxe.select.loadingText") : props.placeholder,
          editable: false,
          disabled: isDisabled,
          type: "text",
          prefixIcon: props.prefixIcon,
          suffixIcon: loading ? icon.getIcon().TREE_SELECT_LOADED : visiblePanel ? icon.getIcon().TREE_SELECT_OPEN : icon.getIcon().TREE_SELECT_CLOSE,
          modelValue: loading ? "" : selectLabel,
          title: selectLabel,
          onClear: clearEvent,
          onClick: clickEvent,
          onFocus: focusEvent,
          onBlur: blurEvent,
          onSuffixClick: togglePanelEvent
        }, prefixSlot ? {
          prefix: () => prefixSlot({})
        } : {}),
        vue.h(vue.Teleport, {
          to: "body",
          disabled: btnTransfer ? !initialized : true
        }, [
          vue.h("div", {
            ref: refOptionPanel,
            class: ["vxe-table--ignore-clear vxe-cascader--panel", popupClassName ? XEUtils.isFunction(popupClassName) ? popupClassName({ $cascader: $xeCascader }) : popupClassName : "", {
              [`size--${vSize}`]: vSize,
              "is--transfer": btnTransfer,
              "ani--leave": !loading && isAniVisible,
              "ani--enter": !loading && visiblePanel
            }],
            placement: reactData.panelPlacement,
            style: reactData.panelStyle
          }, initialized ? [
            vue.h("div", {
              class: "vxe-cascader--panel-wrapper"
            }, [
              filterable ? vue.h("div", {
                class: "vxe-cascader--panel-search"
              }, [
                vue.h(input.default, {
                  ref: refInpSearch,
                  class: "vxe-cascader-search--input",
                  modelValue: searchValue,
                  clearable: true,
                  disabled: false,
                  readonly: false,
                  placeholder: i18n.getI18n("vxe.cascader.search"),
                  prefixIcon: icon.getIcon().INPUT_SEARCH,
                  "onUpdate:modelValue": modelSearchEvent
                })
              ]) : index_esm.renderEmptyElement(),
              showTotalButoon || showCheckedButoon && multiple || showClearButton || headerSlot ? vue.h("div", {
                class: "vxe-cascader--panel-header"
              }, headerSlot ? headerSlot({}) : [
                vue.h("div", {
                  class: "vxe-cascader--header-button"
                }, [
                  showTotalButoon ? vue.h("div", {
                    class: "vxe-cascader--header-total"
                  }, i18n.getI18n("vxe.cascader.total", [selectVals.length])) : index_esm.renderEmptyElement(),
                  vue.h("div", {
                    class: "vxe-cascader--header-btns"
                  }, [
                    showCheckedButoon && multiple ? vue.h(button.default, {
                      content: i18n.getI18n("vxe.cascader.allChecked"),
                      mode: "text",
                      onClick: allCheckedPanelEvent
                    }) : index_esm.renderEmptyElement(),
                    showClearButton ? vue.h(button.default, {
                      content: i18n.getI18n("vxe.cascader.clearChecked"),
                      mode: "text",
                      onClick: clearCheckedPanelEvent
                    }) : index_esm.renderEmptyElement()
                  ])
                ])
              ]) : index_esm.renderEmptyElement(),
              vue.h("div", {
                class: "vxe-cascader--panel-body"
              }, [
                vue.h("div", {
                  ref: refTreeWrapper,
                  class: "vxe-cascader-tree--wrapper",
                  style: popupWrapperStyle
                }, [])
              ]),
              footerSlot ? vue.h("div", {
                class: "vxe-cascader--panel-footer"
              }, footerSlot({})) : index_esm.renderEmptyElement()
            ])
          ] : [])
        ])
      ]);
    };
    vue.watch(() => props.options, () => {
      cacheDataMap();
    });
    cacheDataMap();
    vue.onMounted(() => {
      event.globalEvents.on($xeCascader, "mousewheel", handleGlobalMousewheelEvent);
      event.globalEvents.on($xeCascader, "mousedown", handleGlobalMousedownEvent);
      event.globalEvents.on($xeCascader, "blur", handleGlobalBlurEvent);
      event.globalEvents.on($xeCascader, "resize", handleGlobalResizeEvent);
    });
    vue.onUnmounted(() => {
      event.globalEvents.off($xeCascader, "mousewheel");
      event.globalEvents.off($xeCascader, "mousedown");
      event.globalEvents.off($xeCascader, "blur");
      event.globalEvents.off($xeCascader, "resize");
      XEUtils.assign(internalData, createInternalData());
    });
    vue.provide("$xeCascader", $xeCascader);
    $xeCascader.renderVN = renderVN;
    return $xeCascader;
  },
  render() {
    return this.renderVN();
  }
});
exports.default = VxeCascaderComponent;
