import { defineComponent, toRef, computed, watchEffect, shallowRef, ref, createVNode } from 'vue';
import '../../../utils/index.mjs';
import '../../../hooks/index.mjs';
import BaseSelect, { baseSelectPropsWithoutPrivate, isMultiple } from './BaseSelect.mjs';
import OptionList from './OptionList.mjs';
import useOptions from './hooks/useOptions.mjs';
import { useProvideSelectProps } from './SelectContext.mjs';
import useId from './hooks/useId.mjs';
import { fillFieldNames, flattenOptions, injectPropsWithOption } from './utils/valueUtil.mjs';
import warningProps from './utils/warningPropsUtil.mjs';
import { toArray } from './utils/commonUtil.mjs';
import useFilterOptions from './hooks/useFilterOptions.mjs';
import useCache from './hooks/useCache.mjs';
import PropTypes from '../../../utils/vue/vueTypes.mjs';
import { initDefaultProps } from '../../../utils/vue/initDefaultProps.mjs';
import { useMergedState } from '../../../hooks/use-merged-state/index.mjs';
import { useState } from '../../../hooks/use-state/index.mjs';
import { toReactive } from '../../../utils/vue/toReactive.mjs';
import { omit } from '../../../utils/lang/omit.mjs';

const OMIT_DOM_PROPS = ["inputValue"];
function selectProps() {
  return {
    ...baseSelectPropsWithoutPrivate(),
    prefixCls: String,
    id: String,
    backfill: {
      type: Boolean,
      default: void 0
    },
    // >>> Field Names
    fieldNames: Object,
    // >>> Search
    /** @deprecated Use `searchValue` instead */
    inputValue: String,
    searchValue: String,
    onSearch: Function,
    autoClearSearchValue: {
      type: Boolean,
      default: void 0
    },
    // >>> Select
    onSelect: Function,
    onDeselect: Function,
    // >>> Options
    /**
     * In Select, `false` means do nothing.
     * In TreeSelect, `false` will highlight match item.
     * It's by design.
     */
    filterOption: {
      type: [Boolean, Function],
      default: void 0
    },
    filterSort: Function,
    optionFilterProp: String,
    optionLabelProp: String,
    options: Array,
    defaultActiveFirstOption: {
      type: Boolean,
      default: void 0
    },
    virtual: {
      type: Boolean,
      default: void 0
    },
    listHeight: Number,
    listItemHeight: Number,
    // >>> Icon
    menuItemSelectedIcon: PropTypes.any,
    mode: String,
    labelInValue: {
      type: Boolean,
      default: void 0
    },
    value: PropTypes.any,
    defaultValue: PropTypes.any,
    onChange: Function,
    children: Array
  };
}
function isRawValue(value) {
  return !value || typeof value !== "object";
}
var VcSelect = /* @__PURE__ */ defineComponent({
  compatConfig: {
    MODE: 3
  },
  name: "VcSelect",
  inheritAttrs: false,
  props: initDefaultProps(selectProps(), {
    prefixCls: "vc-select",
    autoClearSearchValue: true,
    listHeight: 200,
    listItemHeight: 20,
    dropdownMatchSelectWidth: true
  }),
  setup(props, {
    expose,
    attrs,
    slots
  }) {
    const mergedId = useId(toRef(props, "id"));
    const multiple = computed(() => isMultiple(props.mode));
    const childrenAsData = computed(() => !!(!props.options && props.children));
    const mergedFilterOption = computed(() => {
      if (props.filterOption === void 0 && props.mode === "combobox")
        return false;
      return props.filterOption;
    });
    const mergedFieldNames = computed(() => fillFieldNames(props.fieldNames, childrenAsData.value));
    const [mergedSearchValue, setSearchValue] = useMergedState("", {
      value: computed(() => props.searchValue !== void 0 ? props.searchValue : props.inputValue),
      postState: (search) => search || ""
    });
    const parsedOptions = useOptions(toRef(props, "options"), toRef(props, "children"), mergedFieldNames);
    const {
      valueOptions,
      labelOptions,
      options: mergedOptions
    } = parsedOptions;
    const convert2LabelValues = (draftValues) => {
      const valueList = toArray(draftValues);
      return valueList.map((val) => {
        var _a, _b;
        let rawValue;
        let rawLabel;
        let rawKey;
        let rawDisabled;
        if (isRawValue(val)) {
          rawValue = val;
        } else {
          rawKey = val.key;
          rawLabel = val.label;
          rawValue = (_a = val.value) != null ? _a : rawKey;
        }
        const option = valueOptions.value.get(rawValue);
        if (option) {
          if (rawLabel === void 0)
            rawLabel = option == null ? void 0 : option[props.optionLabelProp || mergedFieldNames.value.label];
          if (rawKey === void 0)
            rawKey = (_b = option == null ? void 0 : option.key) != null ? _b : rawValue;
          rawDisabled = option == null ? void 0 : option.disabled;
        }
        return {
          label: rawLabel,
          value: rawValue,
          key: rawKey,
          disabled: rawDisabled,
          option
        };
      });
    };
    const [internalValue, setInternalValue] = useMergedState(props.defaultValue, {
      value: toRef(props, "value")
    });
    const rawLabeledValues = computed(() => {
      var _a;
      const values = convert2LabelValues(internalValue.value);
      if (props.mode === "combobox" && !((_a = values[0]) == null ? void 0 : _a.value))
        return [];
      return values;
    });
    const [mergedValues, getMixedOption] = useCache(rawLabeledValues, valueOptions);
    const displayValues = computed(() => {
      if (!props.mode && mergedValues.value.length === 1) {
        const firstValue = mergedValues.value[0];
        if (firstValue.value === null && (firstValue.label === null || firstValue.label === void 0))
          return [];
      }
      return mergedValues.value.map((item) => {
        var _a;
        return {
          ...item,
          label: (_a = typeof item.label === "function" ? item.label() : item.label) != null ? _a : item.value
        };
      });
    });
    const rawValues = computed(() => new Set(mergedValues.value.map((val) => val.value)));
    watchEffect(() => {
      var _a;
      if (props.mode === "combobox") {
        const strValue = (_a = mergedValues.value[0]) == null ? void 0 : _a.value;
        if (strValue !== void 0 && strValue !== null)
          setSearchValue(String(strValue));
      }
    }, {
      flush: "post"
    });
    const createTagOption = (val, label) => {
      const mergedLabel = label != null ? label : val;
      return {
        [mergedFieldNames.value.value]: val,
        [mergedFieldNames.value.label]: mergedLabel
      };
    };
    const filledTagOptions = shallowRef();
    watchEffect(() => {
      if (props.mode !== "tags") {
        filledTagOptions.value = mergedOptions.value;
        return;
      }
      const cloneOptions = mergedOptions.value.slice();
      const existOptions = (val) => valueOptions.value.has(val);
      [...mergedValues.value].sort((a, b) => a.value < b.value ? -1 : 1).forEach((item) => {
        const val = item.value;
        if (!existOptions(val))
          cloneOptions.push(createTagOption(val, item.label));
      });
      filledTagOptions.value = cloneOptions;
    });
    const filteredOptions = useFilterOptions(filledTagOptions, mergedFieldNames, mergedSearchValue, mergedFilterOption, toRef(props, "optionFilterProp"));
    const filledSearchOptions = computed(() => {
      if (props.mode !== "tags" || !mergedSearchValue.value || filteredOptions.value.some((item) => item[props.optionFilterProp || "value"] === mergedSearchValue.value))
        return filteredOptions.value;
      return [createTagOption(mergedSearchValue.value), ...filteredOptions.value];
    });
    const orderedFilteredOptions = computed(() => {
      if (!props.filterSort)
        return filledSearchOptions.value;
      return [...filledSearchOptions.value].sort((a, b) => props.filterSort(a, b));
    });
    const displayOptions = computed(() => flattenOptions(orderedFilteredOptions.value, {
      fieldNames: mergedFieldNames.value,
      childrenAsData: childrenAsData.value
    }));
    const triggerChange = (values) => {
      const labeledValues = convert2LabelValues(values);
      setInternalValue(labeledValues);
      if (props.onChange && (labeledValues.length !== mergedValues.value.length || labeledValues.some((newVal, index) => {
        var _a;
        return ((_a = mergedValues.value[index]) == null ? void 0 : _a.value) !== (newVal == null ? void 0 : newVal.value);
      }))) {
        const returnValues = props.labelInValue ? labeledValues.map((v) => {
          return {
            ...v,
            originLabel: v.label,
            label: typeof v.label === "function" ? v.label() : v.label
          };
        }) : labeledValues.map((v) => v.value);
        const returnOptions = labeledValues.map((v) => injectPropsWithOption(getMixedOption(v.value)));
        props.onChange(
          // Value
          multiple.value ? returnValues : returnValues[0],
          // Option
          multiple.value ? returnOptions : returnOptions[0]
        );
      }
    };
    const [activeValue, setActiveValue] = useState(null);
    const [accessibilityIndex, setAccessibilityIndex] = useState(0);
    const mergedDefaultActiveFirstOption = computed(() => props.defaultActiveFirstOption !== void 0 ? props.defaultActiveFirstOption : props.mode !== "combobox");
    const onActiveValue = (active, index, {
      source = "keyboard"
    } = {}) => {
      setAccessibilityIndex(index);
      if (props.backfill && props.mode === "combobox" && active !== null && source === "keyboard")
        setActiveValue(String(active));
    };
    const triggerSelect = (val, selected) => {
      const getSelectEnt = () => {
        var _a;
        const option = getMixedOption(val);
        const originLabel = option == null ? void 0 : option[mergedFieldNames.value.label];
        return [props.labelInValue ? {
          label: typeof originLabel === "function" ? originLabel() : originLabel,
          originLabel,
          value: val,
          key: (_a = option == null ? void 0 : option.key) != null ? _a : val
        } : val, injectPropsWithOption(option)];
      };
      if (selected && props.onSelect) {
        const [wrappedValue, option] = getSelectEnt();
        props.onSelect(wrappedValue, option);
      } else if (!selected && props.onDeselect) {
        const [wrappedValue, option] = getSelectEnt();
        props.onDeselect(wrappedValue, option);
      }
    };
    const onInternalSelect = (val, info) => {
      let cloneValues;
      const mergedSelect = multiple.value ? info.selected : true;
      if (mergedSelect)
        cloneValues = multiple.value ? [...mergedValues.value, val] : [val];
      else
        cloneValues = mergedValues.value.filter((v) => v.value !== val);
      triggerChange(cloneValues);
      triggerSelect(val, mergedSelect);
      if (props.mode === "combobox") {
        setActiveValue("");
      } else if (!multiple.value || props.autoClearSearchValue) {
        setSearchValue("");
        setActiveValue("");
      }
    };
    const onDisplayValuesChange = (nextValues, info) => {
      triggerChange(nextValues);
      if (info.type === "remove" || info.type === "clear") {
        info.values.forEach((item) => {
          triggerSelect(item.value, false);
        });
      }
    };
    const onInternalSearch = (searchText, info) => {
      var _a;
      setSearchValue(searchText);
      setActiveValue(null);
      if (info.source === "submit") {
        const formatted = (searchText || "").trim();
        if (formatted) {
          const newRawValues = Array.from(/* @__PURE__ */ new Set([...rawValues.value, formatted]));
          triggerChange(newRawValues);
          triggerSelect(formatted, true);
          setSearchValue("");
        }
        return;
      }
      if (info.source !== "blur") {
        if (props.mode === "combobox")
          triggerChange(searchText);
        (_a = props.onSearch) == null ? void 0 : _a.call(props, searchText);
      }
    };
    const onInternalSearchSplit = (words) => {
      let patchValues = words;
      if (props.mode !== "tags") {
        patchValues = words.map((word) => {
          const opt = labelOptions.value.get(word);
          return opt == null ? void 0 : opt.value;
        }).filter((val) => val !== void 0);
      }
      const newRawValues = Array.from(/* @__PURE__ */ new Set([...rawValues.value, ...patchValues]));
      triggerChange(newRawValues);
      newRawValues.forEach((newRawValue) => {
        triggerSelect(newRawValue, true);
      });
    };
    const realVirtual = computed(() => props.virtual !== false && props.dropdownMatchSelectWidth !== false);
    useProvideSelectProps(toReactive({
      ...parsedOptions,
      flattenOptions: displayOptions,
      onActiveValue,
      defaultActiveFirstOption: mergedDefaultActiveFirstOption,
      onSelect: onInternalSelect,
      menuItemSelectedIcon: toRef(props, "menuItemSelectedIcon"),
      rawValues,
      fieldNames: mergedFieldNames,
      virtual: realVirtual,
      listHeight: toRef(props, "listHeight"),
      listItemHeight: toRef(props, "listItemHeight"),
      childrenAsData
    }));
    if (process.env.NODE_ENV !== "production") {
      watchEffect(() => {
        warningProps(props);
      }, {
        flush: "post"
      });
    }
    const selectRef = ref();
    expose({
      focus() {
        var _a;
        (_a = selectRef.value) == null ? void 0 : _a.focus();
      },
      blur() {
        var _a;
        (_a = selectRef.value) == null ? void 0 : _a.blur();
      },
      scrollTo(arg) {
        var _a;
        (_a = selectRef.value) == null ? void 0 : _a.scrollTo(arg);
      }
    });
    const pickProps = computed(() => {
      return omit(props, [
        "id",
        "mode",
        "prefixCls",
        "backfill",
        "fieldNames",
        // Search
        "inputValue",
        "searchValue",
        "onSearch",
        "autoClearSearchValue",
        // Select
        "onSelect",
        "onDeselect",
        "dropdownMatchSelectWidth",
        // Options
        "filterOption",
        "filterSort",
        "optionFilterProp",
        "optionLabelProp",
        "options",
        "children",
        "defaultActiveFirstOption",
        "menuItemSelectedIcon",
        "virtual",
        "listHeight",
        "listItemHeight",
        // Value
        "value",
        "defaultValue",
        "labelInValue",
        "onChange"
      ]);
    });
    return () => {
      return createVNode(BaseSelect, {
        ...pickProps.value,
        ...attrs,
        "id": mergedId,
        "prefixCls": props.prefixCls,
        "ref": selectRef,
        "omitDomProps": OMIT_DOM_PROPS,
        "mode": props.mode,
        "displayValues": displayValues.value,
        "onDisplayValuesChange": onDisplayValuesChange,
        "searchValue": mergedSearchValue.value,
        "onSearch": onInternalSearch,
        "onSearchSplit": onInternalSearchSplit,
        "dropdownMatchSelectWidth": props.dropdownMatchSelectWidth,
        "OptionList": OptionList,
        "emptyOptions": !displayOptions.value.length,
        "activeValue": activeValue.value,
        "activeDescendantId": `${mergedId}_list_${accessibilityIndex.value}`
      }, slots);
    };
  }
});

export { VcSelect as default, selectProps };
//# sourceMappingURL=Select.mjs.map
