{"version":3,"file":"index.mjs","sources":["../../../../../../packages/components/autocomplete/src/index.vue"],"sourcesContent":["<template>\r\n  <sg-tooltip\r\n    ref=\"popper\"\r\n    :show-arrow = \"false\"\r\n    v-model:visible=\"suggestionVisible\"\r\n    :placement=\"placement\"\r\n    :fallback-placements=\"['bottom-start', 'top-start']\"\r\n    :gpu-acceleration=\"false\"\r\n    :drop-class-name=\"`${ns.e('popper')}`\"\r\n    :transfer=\"transfer\"\r\n    pure\r\n    manual-mode\r\n    theme=\"light\"\r\n    trigger=\"click\"\r\n    :transition=\"`${ns.namespace.value}-zoom-in-top`\"\r\n    persistent\r\n    @before-show=\"onSuggestionShow\"\r\n    @show=\"onShow\"\r\n    @hide=\"onHide\"\r\n  >\r\n    <div\r\n      v-clickoutside=\"close\"\r\n      :class=\"[ns.b(), $attrs.class]\"\r\n      :style=\"$attrs.style as any || undefined\"\r\n      role=\"combobox\"\r\n      aria-haspopup=\"listbox\"\r\n      :aria-expanded=\"suggestionVisible\"\r\n      :aria-owns=\"id\"\r\n    >\r\n      <sg-input\r\n        ref=\"inputRef\"\r\n        v-bind=\"attrs\"\r\n        type=\"text\"\r\n        :size=\"size\"\r\n        :model-value=\"modelValue\"\r\n        @on-input=\"handleInput\"\r\n        @on-change=\"handleChange\"\r\n        @on-focus=\"handleFocus\"\r\n        @on-blur=\"handleBlur\"\r\n        @on-clear=\"handleClear\"\r\n        @keydown.up.prevent=\"highlight(highlightedIndex - 1)\"\r\n        @keydown.down.prevent=\"highlight(highlightedIndex + 1)\"\r\n        @keydown.enter=\"handleKeyEnter\"\r\n        @keydown.tab=\"close\"\r\n        @keydown.esc=\"handleKeyEscape\"\r\n      >\r\n        <template v-if=\"$slots.prepend\" #prepend>\r\n          <slot name=\"prepend\"></slot>\r\n        </template>\r\n        <template v-if=\"$slots.append\" #append>\r\n          <slot name=\"append\"></slot>\r\n        </template>\r\n      </sg-input>\r\n    </div>\r\n    <template #content>\r\n      <div\r\n        ref=\"regionRef\"\r\n        :class=\"[ns.b('suggestion'), ns.is('loading', suggestionLoading)]\"\r\n        :style=\"{ minWidth: scrollwidth ? '' : dropdownWidth, outline: 'none', width: scrollwidth }\"\r\n        role=\"region\"\r\n      >\r\n        <sg-scrollbar\r\n          :id=\"id\"\r\n          tag=\"ul\"\r\n          :wrap-class=\"ns.be('suggestion', 'wrap')\"\r\n          :view-class=\"ns.be('suggestion', 'list')\"\r\n          :wrap-style=\"{ maxHeight: scrollheight }\"\r\n          role=\"listbox\"\r\n        >\r\n          <li v-if=\"suggestionLoading\">\r\n            <sg-icon class=\"is-loading\"><Loading /></sg-icon>\r\n          </li>\r\n          <template v-else>\r\n            <li\r\n              v-for=\"(item, index) in suggestions\"\r\n              :id=\"`${id}-item-${index}`\"\r\n              :key=\"index\"\r\n              :class=\"{ highlighted: highlightedIndex === index }\"\r\n              role=\"option\"\r\n              :aria-selected=\"highlightedIndex === index\"\r\n              @click=\"select(item)\"\r\n            >\r\n              <slot :item=\"item\">{{ item[valueKey] }}</slot>\r\n            </li>\r\n          </template>\r\n        </sg-scrollbar>\r\n      </div>\r\n    </template>\r\n  </sg-tooltip>\r\n</template>\r\n\r\n<script lang=\"ts\">\r\nimport { defineComponent, ref, computed, onMounted, nextTick } from 'vue'\r\nimport debounce from 'lodash/debounce'\r\nimport { useAttrs, useNamespace } from '@sgui-plus/hooks'\r\nimport { ClickOutside } from '@sgui-plus/directives'\r\nimport { generateId, isArray } from '@sgui-plus/utils/util'\r\nimport { UPDATE_MODEL_EVENT } from '@sgui-plus/utils/constants'\r\nimport { throwError } from '@sgui-plus/utils/error'\r\nimport SgInput from '@sgui-plus/components/input'\r\nimport SgScrollbar from '@sgui-plus/components/scrollbar'\r\nimport SgTooltip from '@sgui-plus/components/tooltip'\r\nimport SgIcon from '@sgui-plus/components/icon'\r\nimport { Loading } from '@sgui-plus/icons-vue'\r\nimport { autocompleteProps, autocompleteEmits } from './autocomplete'\r\nimport type { AutocompleteData } from './autocomplete'\r\n\r\nexport default defineComponent({\r\n  name: 'SgAutocomplete',\r\n  components: {\r\n    SgTooltip,\r\n    SgInput,\r\n    SgScrollbar,\r\n    SgIcon,\r\n    Loading,\r\n  },\r\n  directives: {\r\n    clickoutside: ClickOutside,\r\n  },\r\n  inheritAttrs: false,\r\n  props: autocompleteProps,\r\n  emits: autocompleteEmits,\r\n  setup(props, ctx) {\r\n    const ns = useNamespace('autocomplete')\r\n    const attrs = useAttrs()\r\n    const suggestions = ref<any[]>([])\r\n    const highlightedIndex = ref(-1)\r\n    const dropdownWidth = ref('')\r\n    const activated = ref(false)\r\n    const suggestionDisabled = ref(false)\r\n    const loading = ref(false)\r\n    let isClear = false\r\n    let ignoreFocusEvent = false\r\n    const inputRef = ref<{\r\n      inputOrTextarea: HTMLInputElement | HTMLTextAreaElement\r\n      focus: () => void\r\n      $el: HTMLElement\r\n    } | null>(null)\r\n    const regionRef = ref<HTMLElement | null>(null)\r\n    const popper = ref(null)\r\n\r\n    const id = computed(() => {\r\n      return ns.b(String(generateId()))\r\n    })\r\n    const suggestionVisible = computed(() => {\r\n      const isValidData =\r\n        isArray(suggestions.value) && suggestions.value.length > 0\r\n      return (isValidData || loading.value) && activated.value\r\n    })\r\n    const suggestionLoading = computed(() => {\r\n      return !props.hideLoading && loading.value\r\n    })\r\n\r\n    const onSuggestionShow = async () => {\r\n      await nextTick()\r\n      if (suggestionVisible.value) {\r\n        dropdownWidth.value = `${inputRef.value!.$el.offsetWidth}px`\r\n      }\r\n    }\r\n\r\n    const onShow = () => {\r\n      ignoreFocusEvent = true\r\n    }\r\n\r\n    const onHide = () => {\r\n      ignoreFocusEvent = false\r\n      highlightedIndex.value = -1\r\n    }\r\n\r\n    onMounted(() => {\r\n      inputRef.value!.inputOrTextarea.setAttribute('role', 'textbox')\r\n      inputRef.value!.inputOrTextarea.setAttribute('aria-autocomplete', 'list')\r\n      inputRef.value!.inputOrTextarea.setAttribute('aria-controls', 'id')\r\n      inputRef.value!.inputOrTextarea.setAttribute(\r\n        'aria-activedescendant',\r\n        `${id.value}-item-${highlightedIndex.value}`\r\n      )\r\n    })\r\n\r\n    const getData = async (queryString: string) => {\r\n      if (suggestionDisabled.value) {\r\n        return\r\n      }\r\n\r\n      const cb = (suggestionList: AutocompleteData) => {\r\n        loading.value = false\r\n        if (suggestionDisabled.value) return\r\n\r\n        if (isArray(suggestionList)) {\r\n          suggestions.value = suggestionList\r\n          highlightedIndex.value = props.highlightFirstItem ? 0 : -1\r\n        } else {\r\n          throwError('SgAutocomplete', 'autocomplete suggestions must be an array')\r\n        }\r\n      }\r\n      loading.value = true\r\n      if (isArray(props.fetchSuggestions)) {\r\n        cb(props.fetchSuggestions)\r\n      } else {\r\n        const result = await props.fetchSuggestions(queryString, cb)\r\n        if (isArray(result)) cb(result)\r\n      }\r\n    }\r\n\r\n    const debouncedGetData = debounce(getData, props.debounce)\r\n\r\n    const handleInput = (value: string) => {\r\n      const valuePresented = !!value\r\n      ctx.emit(UPDATE_MODEL_EVENT, value)\r\n\r\n      suggestionDisabled.value = false\r\n      activated.value ||= isClear && valuePresented\r\n\r\n      if (!props.triggerOnFocus && !value) {\r\n        suggestionDisabled.value = true\r\n        suggestions.value = []\r\n        return\r\n      }\r\n      if (isClear && valuePresented) {\r\n        isClear = false\r\n      }\r\n\r\n      debouncedGetData(value)\r\n    }\r\n\r\n    const handleChange = (value: string) => {\r\n      ctx.emit('onChange', value)\r\n    }\r\n\r\n    const handleFocus = (e: FocusEvent) => {\r\n      if (ignoreFocusEvent) return\r\n\r\n      activated.value = true\r\n      ctx.emit('onFocus', e)\r\n      if (props.triggerOnFocus) {\r\n        debouncedGetData(String(props.modelValue))\r\n      }\r\n    }\r\n\r\n    const handleBlur = (e: FocusEvent) => {\r\n      if (ignoreFocusEvent) return\r\n      ctx.emit('onBlur', e)\r\n    }\r\n\r\n    const handleClear = () => {\r\n      activated.value = false\r\n      isClear = true\r\n      ctx.emit(UPDATE_MODEL_EVENT, '')\r\n      ctx.emit('onClear')\r\n    }\r\n\r\n    const handleKeyEnter = () => {\r\n      if (\r\n        suggestionVisible.value &&\r\n        highlightedIndex.value >= 0 &&\r\n        highlightedIndex.value < suggestions.value.length\r\n      ) {\r\n        select(suggestions.value[highlightedIndex.value])\r\n      } else if (props.selectWhenUnmatched) {\r\n        ctx.emit('onSelect', { value: props.modelValue })\r\n        nextTick(() => {\r\n          suggestions.value = []\r\n          highlightedIndex.value = -1\r\n        })\r\n      }\r\n    }\r\n\r\n    const handleKeyEscape = (evt: Event) => {\r\n      if (suggestionVisible.value) {\r\n        evt.preventDefault()\r\n        evt.stopPropagation()\r\n        close()\r\n      }\r\n    }\r\n\r\n    const close = () => {\r\n      activated.value = false\r\n    }\r\n\r\n    const focus = () => {\r\n      inputRef.value?.focus()\r\n    }\r\n\r\n    const select = (item: any) => {\r\n      ctx.emit('onInput', item[props.valueKey])\r\n      ctx.emit(UPDATE_MODEL_EVENT, item[props.valueKey])\r\n      ctx.emit('onSelect', item)\r\n      nextTick(() => {\r\n        suggestions.value = []\r\n        highlightedIndex.value = -1\r\n      })\r\n    }\r\n    const highlight = (index: number) => {\r\n      if (!suggestionVisible.value || loading.value) {\r\n        return\r\n      }\r\n      if (index < 0) {\r\n        highlightedIndex.value = -1\r\n        return\r\n      }\r\n      if (index >= suggestions.value.length) {\r\n        index = suggestions.value.length - 1\r\n      }\r\n      const suggestion = regionRef.value!.querySelector(\r\n        `.${ns.be('suggestion', 'wrap')}`\r\n      )!\r\n      const suggestionList = suggestion.querySelectorAll(\r\n        `.${ns.be('suggestion', 'list')} li`\r\n      )!\r\n      const highlightItem = suggestionList[index]\r\n      const scrollTop = suggestion.scrollTop\r\n      const { offsetTop, scrollHeight } = highlightItem as HTMLElement\r\n\r\n      if (offsetTop + scrollHeight > scrollTop + suggestion.clientHeight) {\r\n        suggestion.scrollTop += scrollHeight\r\n      }\r\n      if (offsetTop < scrollTop) {\r\n        suggestion.scrollTop -= scrollHeight\r\n      }\r\n      highlightedIndex.value = index\r\n      inputRef.value!.inputOrTextarea.setAttribute(\r\n        'aria-activedescendant',\r\n        `${id.value}-item-${highlightedIndex.value}`\r\n      )\r\n    }\r\n\r\n    return {\r\n      attrs,\r\n      suggestions,\r\n      highlightedIndex,\r\n      dropdownWidth,\r\n      activated,\r\n      suggestionDisabled,\r\n      loading,\r\n      inputRef,\r\n      regionRef,\r\n      popper,\r\n\r\n      id,\r\n      suggestionVisible,\r\n      suggestionLoading,\r\n\r\n      getData,\r\n      handleInput,\r\n      handleChange,\r\n      handleFocus,\r\n      handleBlur,\r\n      handleClear,\r\n      handleKeyEnter,\r\n      handleKeyEscape,\r\n      close,\r\n      focus,\r\n      select,\r\n      highlight,\r\n      onSuggestionShow,\r\n      onShow,\r\n      onHide,\r\n      ns,\r\n    }\r\n  },\r\n})\r\n</script>\r\n"],"names":["_resolveDirective","_openBlock","_createBlock","_withCtx","_createElementVNode","_normalizeClass","_normalizeStyle","_createVNode","_createElementBlock","_Fragment","_renderList","_withDirectives","_mergeProps","_withKeys","_withModifiers"],"mappings":"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"}