import y from "./combobox-loading-list.js";
import I from "./combobox-empty-list.js";
import { getUniqueString as L, hasSlotContent as b } from "../../common/utils/index.js";
import { resolveComponent as h, openBlock as d, createElementBlock as a, withKeys as l, withModifiers as o, createElementVNode as c, renderSlot as r, createBlock as g, normalizeProps as x, mergeProps as m, withCtx as v, createCommentVNode as E } from "vue";
import { _ as O } from "../../_plugin-vue_export-helper-CHgC5LLL.js";
import S from "../../common/mixins/keyboard-list-navigation.js";
import { COMBOBOX_LABEL_SIZES as H } from "./combobox-constants.js";
const K = {
  compatConfig: { MODE: 3 },
  name: "DtCombobox",
  components: {
    ComboboxLoadingList: y,
    ComboboxEmptyList: I
  },
  mixins: [
    S({
      indexKey: "highlightIndex",
      idKey: "highlightId",
      listElementKey: "getListElement",
      afterHighlightMethod: "afterHighlight",
      beginningOfListMethod: "beginningOfListMethod",
      endOfListMethod: "endOfListMethod",
      activeItemKey: "activeItemEl"
    })
  ],
  props: {
    /**
     * String to use for the input label.
     */
    label: {
      type: String,
      required: !0
    },
    /**
     * Determines visibility of input label.
     * @values true, false
     */
    labelVisible: {
      type: Boolean,
      default: !0
    },
    /**
     * Size of the input, one of `xs`, `sm`, `md`, `lg`, `xl`
     * @values null, xs, sm, md, lg, xl
     */
    size: {
      type: String,
      default: null,
      validator: (e) => Object.values(H).includes(e)
    },
    /**
     * Description for the input
     */
    description: {
      type: String,
      default: ""
    },
    /**
     * Sets an ID on the list element of the component. Used by several aria attributes
     * as well as when deriving the IDs for each item.
     */
    listId: {
      type: String,
      default() {
        return L();
      }
    },
    /**
     * A method that will be called when the selection goes past the beginning of the list.
     */
    onBeginningOfList: {
      type: Function,
      default: null
    },
    /**
     * A method that will be called when the selection goes past the end of the list.
     */
    onEndOfList: {
      type: Function,
      default: null
    },
    /**
     * Determines when to show the list element and also controls the aria-expanded attribute.
     * @values true, false
     */
    showList: {
      type: Boolean,
      default: !1
    },
    /**
     * If the list is rendered outside the component, like when using popover as the list wrapper.
     * @values true, false
     */
    listRenderedOutside: {
      type: Boolean,
      default: !1
    },
    /**
     * Determines when to show the skeletons and also controls aria-busy attribute.
     * @values true, false
     */
    loading: {
      type: Boolean,
      default: !1
    },
    /**
     * Sets the list to an empty state, and displays the message from prop `emptyStateMessage`.
     * @values true, false
     */
    emptyList: {
      type: Boolean,
      default: !1
    },
    /**
     * Message to show when the list is empty
     */
    emptyStateMessage: {
      type: String,
      default: ""
    },
    /**
     * Additional class name for the empty list element.
     * Can accept all of String, Object, and Array, i.e. has the
     * same api as Vue's built-in handling of the class attribute.
     */
    emptyStateClass: {
      type: [String, Object, Array],
      default: ""
    },
    /**
     * Programmatically click on the active list item element when a selection
     * comes from keyboard navigation, i.e. pressing the "Enter" key.
     * @values true, false
     */
    clickOnSelect: {
      type: Boolean,
      default: !1
    }
  },
  emits: [
    /**
     * Event fired when item selected
     *
     * @event select
     * @type {Number}
     */
    "select",
    /**
     * Event fired when pressing escape
     *
     * @event escape
     */
    "escape",
    /**
     * Event fired when the highlight changes
     *
     * @event highlight
     * @type {Number}
     */
    "highlight",
    /**
     * Event fired when list is shown or hidden
     *
     * @event opened
     * @type {Boolean}
     */
    "opened"
  ],
  data() {
    return {
      // If the list is rendered at the root, rather than as a child
      // of this component, this is the ref to that dom element. Set
      // by the onOpen method.
      outsideRenderedListRef: null,
      hasSlotContent: b
    };
  },
  computed: {
    inputProps() {
      return {
        label: this.label,
        labelVisible: this.labelVisible,
        size: this.size,
        description: this.description,
        role: "combobox",
        "aria-label": this.label,
        "aria-expanded": this.showList.toString(),
        "aria-owns": this.listId,
        "aria-haspopup": "listbox",
        "aria-activedescendant": this.activeItemId,
        "aria-controls": this.listId
      };
    },
    listProps() {
      return {
        role: "listbox",
        id: this.listId,
        // The list has to be positioned relatively so that the auto-scroll can
        // calculate the correct offset for the list items.
        class: "d-ps-relative",
        "aria-label": this.label
      };
    },
    beginningOfListMethod() {
      return this.onBeginningOfList || this.jumpToEnd;
    },
    endOfListMethod() {
      return this.onEndOfList || this.jumpToBeginning;
    },
    activeItemId() {
      if (!(!this.showList || this.highlightIndex < 0 || this.loading))
        return this.highlightId;
    },
    activeItemEl() {
      return this.highlightId ? this.getListElement().querySelector("#" + this.highlightId) : "";
    }
  },
  watch: {
    showList(e) {
      this.listRenderedOutside || (this.setInitialHighlightIndex(), this.$emit("opened", e)), !e && this.outsideRenderedListRef && (this.outsideRenderedListRef.removeEventListener("mousemove", this.onMouseHighlight), this.outsideRenderedListRef = null);
    },
    loading(e) {
      this.$nextTick(() => {
        this.setInitialHighlightIndex();
      });
    },
    $props: {
      deep: !0,
      immediate: !0,
      handler() {
        this.validateEmptyListProps();
      }
    }
  },
  created() {
    this.validateEmptyListProps();
  },
  methods: {
    onMouseHighlight(e) {
      if (this.loading) return;
      const t = e.target.closest("li");
      t && this.highlightId !== t.id && this.setHighlightId(t.id);
    },
    getListElement() {
      var e;
      return this.outsideRenderedListRef ?? ((e = this.$refs.listWrapper) == null ? void 0 : e.querySelector(`#${this.listId}`));
    },
    clearHighlightIndex() {
      this.showList && this.setHighlightIndex(-1);
    },
    afterHighlight() {
      this.loading || this.$emit("highlight", this.highlightIndex);
    },
    onEnterKey() {
      var e;
      this.loading || this.emptyList || this.highlightIndex >= 0 && (this.$emit("select", this.highlightIndex), this.clickOnSelect && ((e = this.activeItemEl) == null || e.click()));
    },
    onEscapeKey() {
      this.$emit("escape");
    },
    onOpen(e, t) {
      var n;
      this.outsideRenderedListRef = t, (n = this.outsideRenderedListRef) == null || n.addEventListener("mousemove", this.onMouseHighlight), this.$emit("opened", e), e && this.setInitialHighlightIndex();
    },
    onKeyValidation(e, t) {
      !this.showList || !this.getListElement() || this[t](e);
    },
    setInitialHighlightIndex() {
      this.showList && this.$nextTick(() => {
        this.setHighlightIndex(this.loading ? -1 : 0);
      });
    },
    validateEmptyListProps() {
      this.$slots.emptyListItem || this.emptyList && !this.emptyStateMessage && console.error(`Invalid props: you must pass both props emptyList and emptyStateMessage to show the
      empty message.`);
    }
  }
}, M = { "data-qa": "dt-combobox-input-wrapper" };
function w(e, t, n, R, p, i) {
  const u = h("combobox-loading-list"), f = h("combobox-empty-list");
  return d(), a("div", {
    onKeydown: [
      t[3] || (t[3] = l(o((s) => i.onKeyValidation(s, "onEscapeKey"), ["stop"]), ["esc"])),
      t[4] || (t[4] = l(o((s) => i.onKeyValidation(s, "onEnterKey"), ["exact"]), ["enter"])),
      t[5] || (t[5] = l(o((s) => i.onKeyValidation(s, "onUpKey"), ["stop", "prevent"]), ["up"])),
      t[6] || (t[6] = l(o((s) => i.onKeyValidation(s, "onDownKey"), ["stop", "prevent"]), ["down"])),
      t[7] || (t[7] = l(o((s) => i.onKeyValidation(s, "onHomeKey"), ["stop", "prevent"]), ["home"])),
      t[8] || (t[8] = l(o((s) => i.onKeyValidation(s, "onEndKey"), ["stop", "prevent"]), ["end"]))
    ]
  }, [
    c("div", M, [
      r(e.$slots, "input", { inputProps: i.inputProps })
    ]),
    n.showList ? (d(), a("div", {
      key: 0,
      ref: "listWrapper",
      "data-qa": "dt-combobox-list-wrapper",
      onMouseleave: t[0] || (t[0] = (...s) => i.clearHighlightIndex && i.clearHighlightIndex(...s)),
      onFocusout: t[1] || (t[1] = (...s) => i.clearHighlightIndex && i.clearHighlightIndex(...s)),
      onMousemoveCapture: t[2] || (t[2] = (...s) => i.onMouseHighlight && i.onMouseHighlight(...s))
    }, [
      n.loading && !n.listRenderedOutside ? (d(), g(u, x(m({ key: 0 }, i.listProps)), null, 16)) : n.emptyList && (n.emptyStateMessage || p.hasSlotContent(e.$slots.emptyListItem)) && !n.listRenderedOutside ? (d(), g(f, m({ key: 1 }, i.listProps, {
        message: n.emptyStateMessage,
        "item-class": n.emptyStateClass
      }), {
        default: v(() => [
          r(e.$slots, "emptyListItem")
        ]),
        _: 3
      }, 16, ["message", "item-class"])) : r(e.$slots, "list", {
        key: 2,
        listProps: i.listProps,
        opened: i.onOpen,
        clearHighlightIndex: i.clearHighlightIndex
      })
    ], 544)) : E("", !0)
  ], 32);
}
const z = /* @__PURE__ */ O(K, [["render", w]]);
export {
  z as default
};
//# sourceMappingURL=combobox.js.map
