import { ref, computed, nextTick, watch, onBeforeUnmount, createVNode, mergeProps, Fragment, withDirectives, vShow } from "vue";
import "./styles/select.scss";
import { makeScrollbar, useScrollbar } from "../../composables/scrollbar/index.mjs";
import { useProxiedModel } from "../../composables/proxied-model/index.mjs";
import { Input } from "../input/input.mjs";
import { Icon } from "../icon/icon.mjs";
import { Progress } from "../progress/progress.mjs";
import { Menu } from "../menu/menu.mjs";
import { List } from "../list/list.mjs";
import { ListItem } from "../list/list-item.mjs";
import { ListItemAvatar } from "../list/list-item-avatar.mjs";
import { Checkbox } from "../checkbox/checkbox.mjs";
import { TagGroup } from "../tag-group/tag-group.mjs";
import { Tag } from "../tag/tag.mjs";
import { getUid, wrapInArray, pick, convertToUnit, debounce, keyValues } from "../../utils/dist/index.mjs";
import { genericComponent } from "../../utils/define-component.mjs";
function defaultFilter(value, query, _item) {
  if (value == null || query == null)
    return -1;
  return value.toString().toLocaleLowerCase().indexOf(query.toString().toLocaleLowerCase());
}
const Select = genericComponent()({
  name: "VeSelect",
  props: {
    appendInnerIcon: {
      type: String,
      default: "$dropdown"
    },
    deleteAfterUnmount: {
      type: Boolean,
      default: true
    },
    filterable: Boolean,
    id: String,
    items: Array,
    itemText: {
      type: String,
      default: "text"
    },
    itemValue: {
      type: String,
      default: "value"
    },
    loading: Boolean,
    modelValue: {
      type: null,
      default: () => []
    },
    multiple: Boolean,
    noDataText: {
      type: String,
      default: "\u6682\u65E0\u6570\u636E"
    },
    openOnClear: Boolean,
    placeholder: String,
    query: String,
    tags: Boolean,
    readonly: Boolean,
    returnObject: Boolean,
    ...makeScrollbar()
  },
  emits: {
    "click:clear": (_event) => true,
    "update:modelValue": (_modelValue) => true,
    "update:query": (_query) => true
  },
  setup(props, {
    emit,
    slots
  }) {
    const activator = ref();
    const pendingIndex = ref();
    const id = computed(() => props.id || `ve-select-${getUid()}`);
    const inputRef = ref();
    const isActiveMenu = ref(false);
    const listRef = ref();
    const menuRef = ref();
    const mirrorRef = ref();
    const tagInputRef = ref();
    const tagInputWidth = ref();
    const items = computed(() => {
      var _a, _b;
      return (_b = (_a = props.items) == null ? void 0 : _a.map(normalizeItem)) != null ? _b : [];
    });
    const {
      scrollbarClasses
    } = useScrollbar(props);
    const model = useProxiedModel(props, "modelValue");
    const arrayModel = computed({
      get: () => wrapInArray(model.value),
      set: (v) => model.value = props.multiple ? v : v[0]
    });
    const query = ref(props.query);
    const active = computed({
      get: () => arrayModel.value.map((v) => v && typeof v === "object" ? v[props.itemValue] : v),
      set: (val) => {
        arrayModel.value = props.returnObject ? val.map(getItem).filter((v) => v !== void 0) : val;
        if (!props.multiple)
          isActiveMenu.value = false;
      }
    });
    const selections = computed(() => {
      return active.value.map((v) => {
        return items.value.find((i) => i.value === v);
      }).filter((v) => v !== void 0);
    });
    const onUpdateQuery = debounce((v) => {
      if (props.loading)
        return;
      emit("update:query", v);
    }, 300);
    const inputValue = computed({
      get: () => {
        if (props.filterable && isActiveMenu.value)
          return query.value || void 0;
        if (props.tags)
          return void 0;
        return selections.value.map((item) => item.text).join(", ") || void 0;
      },
      set: (val) => {
        query.value = val;
        onUpdateQuery(val);
        if (isActiveMenu.value) {
          nextTick(() => {
            var _a, _b, _c;
            (_c = (_b = (_a = menuRef.value) == null ? void 0 : _a.overlayRef) == null ? void 0 : _b.updatePosition) == null ? void 0 : _c.call(_b);
          });
        }
      }
    });
    const placeholder = computed(() => {
      return props.tags && active.value.length > 0 ? void 0 : props.placeholder;
    });
    const filteredItems = computed(() => items.value.filter((v) => !v.filtered));
    function getItem(v) {
      var _a;
      return (_a = props.items) == null ? void 0 : _a.find((i) => {
        const i1 = typeof i === "object" ? i[props.itemValue] : i;
        const v1 = typeof v === "object" ? v[props.itemValue] : v;
        return i1 === v1;
      });
    }
    function normalizeItem(item) {
      var _a;
      let v;
      if (typeof item === "object") {
        const value = item[props.itemValue];
        const text = String((_a = item[props.itemText]) != null ? _a : value);
        v = {
          text,
          value
        };
      } else {
        v = {
          text: String(item),
          value: item
        };
      }
      if (props.filterable && query.value) {
        v.filtered = defaultFilter(v.text, query.value) === -1;
      }
      return v;
    }
    watch(() => inputRef.value, (val) => {
      activator.value = val.$el.querySelector(".ve-input-control");
    });
    watch(() => props.query, (val) => {
      query.value = val;
    });
    function onBlur() {
      isActiveMenu.value = false;
    }
    function onClear(e) {
      arrayModel.value = [];
      if (props.openOnClear) {
        isActiveMenu.value = true;
      } else {
        inputRef.value.blur();
      }
      emit("click:clear", e);
    }
    function onControl() {
      var _a;
      if (props.readonly)
        return;
      if (isActiveMenu.value) {
        (_a = inputRef.value) == null ? void 0 : _a.blur();
      } else {
        isActiveMenu.value = true;
      }
    }
    const onKeydownMove = debounce(({
      key
    }) => {
      var _a;
      const index = (_a = pendingIndex.value) != null ? _a : filteredItems.value.findIndex(({
        value
      }) => value === active.value[0]);
      const lastIndex = filteredItems.value.length - 1;
      if (key === keyValues.up) {
        pendingIndex.value = [-1, 0].includes(index) ? lastIndex : Math.max(0, index - 1);
      }
      if (key === keyValues.down) {
        pendingIndex.value = [-1, lastIndex].includes(index) ? 0 : Math.min(lastIndex, index + 1);
      }
      nextTick(() => {
        const el = listRef.value.$el;
        if (!el)
          return;
        const itemEl = el.querySelector(".ve-select__item--pendding");
        if (!itemEl)
          return;
        const itemTop = itemEl.offsetTop;
        if (itemTop <= el.scrollTop) {
          el.scrollTop -= el.scrollTop - itemTop;
        } else {
          const itemBottom = itemEl.offsetTop + itemEl.offsetHeight;
          const scrollBottom = el.scrollTop + el.offsetHeight;
          if (itemBottom >= scrollBottom) {
            el.scrollTop += itemBottom - scrollBottom;
          }
        }
      });
    }, 30);
    const onKeydownEnter = debounce(() => {
      if (!isActiveMenu.value) {
        isActiveMenu.value = true;
      } else if (filteredItems.value.length > 0) {
        const index = pendingIndex.value in filteredItems.value ? pendingIndex.value : 0;
        const value = filteredItems.value[index].value;
        if (props.multiple) {
          active.value = active.value.includes(value) ? active.value.filter((v) => v !== value) : active.value.concat([value]);
        } else {
          active.value = [value];
        }
      }
    }, 60);
    const onKeydownDelete = debounce(() => {
      active.value = active.value.filter((_, i) => i !== active.value.length - 1);
    }, 60);
    function onKeydown(e) {
      const {
        key
      } = e;
      if ([keyValues.up, keyValues.down].includes(key)) {
        e.preventDefault();
        onKeydownMove(e);
      }
      if ([keyValues.enter, keyValues.space, " "].includes(key)) {
        e.preventDefault();
        onKeydownEnter();
      }
      if (key === keyValues.backspace && isActiveMenu.value && props.multiple && props.filterable && props.tags && !query.value && active.value.length > 0) {
        onKeydownDelete();
      }
      if (key === keyValues.esc && isActiveMenu.value) {
        isActiveMenu.value = false;
      }
    }
    function resizeTagInput() {
      tagInputWidth.value = Math.max(0, mirrorRef.value.scrollWidth) + 1;
    }
    let observer;
    watch(mirrorRef, (val) => {
      if (val) {
        observer = new ResizeObserver(resizeTagInput);
        observer.observe(mirrorRef.value);
      } else {
        observer == null ? void 0 : observer.disconnect();
      }
    });
    onBeforeUnmount(() => {
      observer == null ? void 0 : observer.disconnect();
    });
    watch(isActiveMenu, (val) => {
      if (!val)
        pendingIndex.value = void 0;
    });
    return () => {
      const inputProps = props.multiple && !props.tags ? {
        autoResize: true,
        rows: 1,
        type: "textarea"
      } : {};
      const [listSlots, inputSlots] = pick(slots, ["item", "header", "title", "subtitle"]);
      return createVNode(Input, mergeProps(inputProps, {
        "class": ["ve-select", {
          "ve-select--active-menu": isActiveMenu.value
        }],
        "id": id.value,
        "inputAttach": tagInputRef.value,
        "controlValue": model.value,
        "modelValue": inputValue.value,
        "onUpdate:modelValue": ($event) => inputValue.value = $event,
        "onBlur": onBlur,
        "onClick:clear": onClear,
        "onClick:control": onControl,
        "onInput": (e) => {
          if (mirrorRef.value) {
            mirrorRef.value.textContent = e.target.value;
            resizeTagInput();
          }
        },
        "onKeydown": onKeydown,
        "onMousedown": (e) => e.preventDefault(),
        "placeholder": placeholder.value,
        "readonly": !props.filterable,
        "ref": inputRef
      }), {
        ...inputSlots,
        "append-inner": () => createVNode(Fragment, null, [!props.loading && createVNode(Icon, {
          "icon": props.appendInnerIcon
        }, null), props.loading && createVNode(Progress, {
          "size": "14",
          "variant": "circular",
          "stroke-width": "2",
          "indeterminate": true
        }, null)]),
        "default": () => createVNode(Fragment, null, [activator.value && createVNode(Menu, {
          "ref": menuRef,
          "contentClass": "ve-select__menu-wrapper",
          "id": `${id.value}-menu`,
          "modelValue": isActiveMenu.value,
          "onUpdate:modelValue": ($event) => isActiveMenu.value = $event,
          "activator": activator.value,
          "minWidth": void 0,
          "openOnClick": false,
          "eager": true
        }, {
          default: () => [createVNode(List, {
            "ref": listRef,
            "class": scrollbarClasses.value,
            "maxHeight": 250,
            "items": items.value,
            "active": active.value,
            "onUpdate:active": ($event) => active.value = $event,
            "activeStrategy": props.multiple ? "multiple" : "single",
            "deleteAfterUnmount": props.deleteAfterUnmount
          }, {
            ...listSlots,
            item: (itemSlot) => {
              const {
                item,
                index
              } = itemSlot;
              const itemSlotProps = {
                onMousedown: (e) => e.preventDefault(),
                class: {
                  "ve-select__item--pendding": pendingIndex.value === index
                }
              };
              if (slots.item) {
                return slots.item({
                  ...itemSlot,
                  props: itemSlotProps
                });
              }
              return withDirectives(createVNode(ListItem, mergeProps(itemSlotProps, item, {
                "link": true,
                "key": item.value
              }), {
                prepend: props.multiple ? () => createVNode(ListItemAvatar, {
                  "start": true,
                  "color": "inherit",
                  "variant": "text"
                }, {
                  default: () => [createVNode(Checkbox, {
                    "model-value": active.value.includes(item.value)
                  }, null)]
                }) : void 0
              }), [[vShow, !item.filtered]]);
            },
            append: () => {
              var _a, _b;
              return createVNode(Fragment, null, [filteredItems.value.length === 0 && ((_b = (_a = slots["no-data"]) == null ? void 0 : _a.call(slots)) != null ? _b : createVNode(ListItem, {
                "text": props.noDataText
              }, null))]);
            }
          })]
        }), props.tags && createVNode(TagGroup, {
          "class": "ve-select__selections",
          "size": "x-small"
        }, {
          default: () => [selections.value.map((item) => {
            var _a, _b;
            function close() {
              active.value = active.value.filter((v) => v !== item.value);
            }
            return (_b = (_a = slots.tag) == null ? void 0 : _a.call(slots, {
              item,
              close
            })) != null ? _b : createVNode(Tag, {
              "aria-hidden": "true",
              "tag": "div",
              "key": item.value,
              "closable": true,
              "text": item.text,
              "onClick:close": (e) => {
                e.stopPropagation();
                close();
              }
            }, null);
          }), createVNode("div", {
            "class": "ve-select__tag-input",
            "style": {
              width: convertToUnit(selections.value.length > 0 ? tagInputWidth.value : "100%")
            },
            "ref": tagInputRef
          }, [createVNode("span", {
            "class": "ve-select__tag-input-mirror",
            "ref": mirrorRef,
            "aria-hidden": "true"
          }, [query.value])])]
        })])
      });
    };
  }
});
export {
  Select
};
//# sourceMappingURL=select.mjs.map
