mirror of
				https://github.com/crater-invoice/crater.git
				synced 2025-11-03 22:13:18 -05:00 
			
		
		
		
	
		
			
				
	
	
		
			646 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
			
		
		
	
	
			646 lines
		
	
	
		
			18 KiB
		
	
	
	
		
			Vue
		
	
	
		
			Executable File
		
	
	
	
	
<template>
 | 
						|
  <BaseContentPlaceholders v-if="contentLoading">
 | 
						|
    <BaseContentPlaceholdersBox
 | 
						|
      :rounded="true"
 | 
						|
      class="w-full"
 | 
						|
      style="height: 40px"
 | 
						|
    />
 | 
						|
  </BaseContentPlaceholders>
 | 
						|
  <div
 | 
						|
    v-else
 | 
						|
    :id="id"
 | 
						|
    ref="multiselect"
 | 
						|
    :tabindex="tabindex"
 | 
						|
    :class="classList.container"
 | 
						|
    @focusin="activate"
 | 
						|
    @focusout="deactivate"
 | 
						|
    @keydown="handleKeydown"
 | 
						|
    @focus="handleFocus"
 | 
						|
  >
 | 
						|
    <!-- Search -->
 | 
						|
    <template v-if="mode !== 'tags' && searchable && !disabled">
 | 
						|
      <input
 | 
						|
        ref="input"
 | 
						|
        :type="inputType"
 | 
						|
        :modelValue="search"
 | 
						|
        :value="search"
 | 
						|
        :class="classList.search"
 | 
						|
        :autocomplete="autocomplete"
 | 
						|
        @input="handleSearchInput"
 | 
						|
        @paste.stop="handlePaste"
 | 
						|
      />
 | 
						|
    </template>
 | 
						|
 | 
						|
    <!-- Tags (with search) -->
 | 
						|
    <template v-if="mode == 'tags'">
 | 
						|
      <div :class="classList.tags">
 | 
						|
        <slot
 | 
						|
          v-for="(option, i, key) in iv"
 | 
						|
          name="tag"
 | 
						|
          :option="option"
 | 
						|
          :handleTagRemove="handleTagRemove"
 | 
						|
          :disabled="disabled"
 | 
						|
        >
 | 
						|
          <span :key="key" :class="classList.tag">
 | 
						|
            {{ option[label] }}
 | 
						|
            <span
 | 
						|
              v-if="!disabled"
 | 
						|
              :class="classList.tagRemove"
 | 
						|
              @mousedown.stop="handleTagRemove(option, $event)"
 | 
						|
            >
 | 
						|
              <span :class="classList.tagRemoveIcon"></span>
 | 
						|
            </span>
 | 
						|
          </span>
 | 
						|
        </slot>
 | 
						|
 | 
						|
        <div :class="classList.tagsSearchWrapper">
 | 
						|
          <!-- Used for measuring search width -->
 | 
						|
          <span :class="classList.tagsSearchCopy">{{ search }}</span>
 | 
						|
 | 
						|
          <!-- Actual search input -->
 | 
						|
          <input
 | 
						|
            v-if="searchable && !disabled"
 | 
						|
            ref="input"
 | 
						|
            :type="inputType"
 | 
						|
            :modelValue="search"
 | 
						|
            :value="search"
 | 
						|
            :class="classList.tagsSearch"
 | 
						|
            :autocomplete="autocomplete"
 | 
						|
            style="box-shadow: none !important"
 | 
						|
            @input="handleSearchInput"
 | 
						|
            @paste.stop="handlePaste"
 | 
						|
          />
 | 
						|
        </div>
 | 
						|
      </div>
 | 
						|
    </template>
 | 
						|
 | 
						|
    <!-- Single label -->
 | 
						|
    <template v-if="mode == 'single' && hasSelected && !search && iv">
 | 
						|
      <slot name="singlelabel" :value="iv">
 | 
						|
        <div :class="classList.singleLabel">
 | 
						|
          {{ iv[label] }}
 | 
						|
        </div>
 | 
						|
      </slot>
 | 
						|
    </template>
 | 
						|
 | 
						|
    <!-- Multiple label -->
 | 
						|
    <template v-if="mode == 'multiple' && hasSelected && !search">
 | 
						|
      <slot name="multiplelabel" :values="iv">
 | 
						|
        <div :class="classList.multipleLabel">
 | 
						|
          {{ multipleLabelText }}
 | 
						|
        </div>
 | 
						|
      </slot>
 | 
						|
    </template>
 | 
						|
 | 
						|
    <!-- Placeholder -->
 | 
						|
    <template v-if="placeholder && !hasSelected && !search">
 | 
						|
      <slot name="placeholder">
 | 
						|
        <div :class="classList.placeholder">
 | 
						|
          {{ placeholder }}
 | 
						|
        </div>
 | 
						|
      </slot>
 | 
						|
    </template>
 | 
						|
 | 
						|
    <!-- Spinner -->
 | 
						|
    <slot v-if="busy" name="spinner">
 | 
						|
      <span :class="classList.spinner"></span>
 | 
						|
    </slot>
 | 
						|
 | 
						|
    <!-- Clear -->
 | 
						|
    <slot
 | 
						|
      v-if="hasSelected && !disabled && canClear && !busy"
 | 
						|
      name="clear"
 | 
						|
      :clear="clear"
 | 
						|
    >
 | 
						|
      <span :class="classList.clear" @mousedown="clear"
 | 
						|
        ><span :class="classList.clearIcon"></span
 | 
						|
      ></span>
 | 
						|
    </slot>
 | 
						|
 | 
						|
    <!-- Caret -->
 | 
						|
    <slot v-if="caret" name="caret">
 | 
						|
      <span
 | 
						|
        :class="classList.caret"
 | 
						|
        @mousedown.prevent.stop="handleCaretClick"
 | 
						|
      ></span>
 | 
						|
    </slot>
 | 
						|
 | 
						|
    <!-- Options -->
 | 
						|
    <div :class="classList.dropdown" tabindex="-1">
 | 
						|
      <div class="w-full overflow-y-auto">
 | 
						|
        <slot name="beforelist" :options="fo"></slot>
 | 
						|
 | 
						|
        <ul :class="classList.options">
 | 
						|
          <template v-if="groups">
 | 
						|
            <li
 | 
						|
              v-for="(group, i, key) in fg"
 | 
						|
              :key="key"
 | 
						|
              :class="classList.group"
 | 
						|
            >
 | 
						|
              <div
 | 
						|
                :class="classList.groupLabel(group)"
 | 
						|
                :data-pointed="isPointed(group)"
 | 
						|
                @mouseenter="setPointer(group)"
 | 
						|
                @click="handleGroupClick(group)"
 | 
						|
              >
 | 
						|
                <slot name="grouplabel" :group="group">
 | 
						|
                  <span>{{ group[groupLabel] }}</span>
 | 
						|
                </slot>
 | 
						|
              </div>
 | 
						|
 | 
						|
              <ul :class="classList.groupOptions">
 | 
						|
                <li
 | 
						|
                  v-for="(option, i, key) in group.__VISIBLE__"
 | 
						|
                  :key="key"
 | 
						|
                  :class="classList.option(option, group)"
 | 
						|
                  :data-pointed="isPointed(option)"
 | 
						|
                  @mouseenter="setPointer(option)"
 | 
						|
                  @click="handleOptionClick(option)"
 | 
						|
                >
 | 
						|
                  <slot name="option" :option="option" :search="search">
 | 
						|
                    <span>{{ option[label] }}</span>
 | 
						|
                  </slot>
 | 
						|
                </li>
 | 
						|
              </ul>
 | 
						|
            </li>
 | 
						|
          </template>
 | 
						|
          <template v-else>
 | 
						|
            <li
 | 
						|
              v-for="(option, i, key) in fo"
 | 
						|
              :key="key"
 | 
						|
              :class="classList.option(option)"
 | 
						|
              :data-pointed="isPointed(option)"
 | 
						|
              @mouseenter="setPointer(option)"
 | 
						|
              @click="handleOptionClick(option)"
 | 
						|
            >
 | 
						|
              <slot name="option" :option="option" :search="search">
 | 
						|
                <span>{{ option[label] }}</span>
 | 
						|
              </slot>
 | 
						|
            </li>
 | 
						|
          </template>
 | 
						|
        </ul>
 | 
						|
 | 
						|
        <slot v-if="noOptions" name="nooptions">
 | 
						|
          <div :class="classList.noOptions" v-html="noOptionsText"></div>
 | 
						|
        </slot>
 | 
						|
 | 
						|
        <slot v-if="noResults" name="noresults">
 | 
						|
          <div :class="classList.noResults" v-html="noResultsText"></div>
 | 
						|
        </slot>
 | 
						|
 | 
						|
        <slot name="afterlist" :options="fo"> </slot>
 | 
						|
      </div>
 | 
						|
      <slot name="action"></slot>
 | 
						|
    </div>
 | 
						|
 | 
						|
    <!-- Hacky input element to show HTML5 required warning -->
 | 
						|
    <input
 | 
						|
      v-if="required"
 | 
						|
      :class="classList.fakeInput"
 | 
						|
      tabindex="-1"
 | 
						|
      :value="textValue"
 | 
						|
      required
 | 
						|
    />
 | 
						|
 | 
						|
    <!-- Native input support -->
 | 
						|
    <template v-if="nativeSupport">
 | 
						|
      <input
 | 
						|
        v-if="mode == 'single'"
 | 
						|
        type="hidden"
 | 
						|
        :name="name"
 | 
						|
        :value="plainValue !== undefined ? plainValue : ''"
 | 
						|
      />
 | 
						|
      <template v-else>
 | 
						|
        <input
 | 
						|
          v-for="(v, i) in plainValue"
 | 
						|
          :key="i"
 | 
						|
          type="hidden"
 | 
						|
          :name="`${name}[]`"
 | 
						|
          :value="v"
 | 
						|
        />
 | 
						|
      </template>
 | 
						|
    </template>
 | 
						|
 | 
						|
    <!-- Create height for empty input -->
 | 
						|
    <div :class="classList.spacer"></div>
 | 
						|
  </div>
 | 
						|
</template>
 | 
						|
 | 
						|
<script>
 | 
						|
import useData from './composables/useData'
 | 
						|
import useValue from './composables/useValue'
 | 
						|
import useSearch from './composables/useSearch'
 | 
						|
import usePointer from './composables/usePointer'
 | 
						|
import useOptions from './composables/useOptions'
 | 
						|
import usePointerAction from './composables/usePointerAction'
 | 
						|
import useDropdown from './composables/useDropdown'
 | 
						|
import useMultiselect from './composables/useMultiselect'
 | 
						|
import useKeyboard from './composables/useKeyboard'
 | 
						|
import useClasses from './composables/useClasses'
 | 
						|
 | 
						|
export default {
 | 
						|
  name: 'BaseMultiselect',
 | 
						|
  props: {
 | 
						|
    preserveSearch: {
 | 
						|
      type: Boolean,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    initialSearch: {
 | 
						|
      type: String,
 | 
						|
      default: null,
 | 
						|
    },
 | 
						|
    contentLoading: {
 | 
						|
      type: Boolean,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    value: {
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    modelValue: {
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    options: {
 | 
						|
      type: [Array, Object, Function],
 | 
						|
      required: false,
 | 
						|
      default: () => [],
 | 
						|
    },
 | 
						|
    id: {
 | 
						|
      type: [String, Number],
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    name: {
 | 
						|
      type: [String, Number],
 | 
						|
      required: false,
 | 
						|
      default: 'multiselect',
 | 
						|
    },
 | 
						|
    disabled: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    label: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'label',
 | 
						|
    },
 | 
						|
    trackBy: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'label',
 | 
						|
    },
 | 
						|
    valueProp: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'value',
 | 
						|
    },
 | 
						|
    placeholder: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: null,
 | 
						|
    },
 | 
						|
    mode: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'single', // single|multiple|tags
 | 
						|
    },
 | 
						|
    searchable: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    limit: {
 | 
						|
      type: Number,
 | 
						|
      required: false,
 | 
						|
      default: -1,
 | 
						|
    },
 | 
						|
    hideSelected: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    createTag: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    appendNewTag: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    caret: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    loading: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    noOptionsText: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'The list is empty',
 | 
						|
    },
 | 
						|
    noResultsText: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'No results found',
 | 
						|
    },
 | 
						|
    multipleLabel: {
 | 
						|
      type: Function,
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    object: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    delay: {
 | 
						|
      type: Number,
 | 
						|
      required: false,
 | 
						|
      default: -1,
 | 
						|
    },
 | 
						|
    minChars: {
 | 
						|
      type: Number,
 | 
						|
      required: false,
 | 
						|
      default: 0,
 | 
						|
    },
 | 
						|
    resolveOnLoad: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    filterResults: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    clearOnSearch: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    clearOnSelect: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    canDeselect: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    canClear: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    max: {
 | 
						|
      type: Number,
 | 
						|
      required: false,
 | 
						|
      default: -1,
 | 
						|
    },
 | 
						|
    showOptions: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    addTagOn: {
 | 
						|
      type: Array,
 | 
						|
      required: false,
 | 
						|
      default: () => ['enter'],
 | 
						|
    },
 | 
						|
    required: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    openDirection: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'bottom',
 | 
						|
    },
 | 
						|
    nativeSupport: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    invalid: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    classes: {
 | 
						|
      type: Object,
 | 
						|
      required: false,
 | 
						|
      default: () => ({
 | 
						|
        container:
 | 
						|
          'p-0 relative mx-auto w-full flex items-center justify-end box-border cursor-pointer border border-gray-200 rounded-md bg-white text-sm leading-snug outline-none max-h-10',
 | 
						|
        containerDisabled:
 | 
						|
          'cursor-default bg-gray-200 bg-opacity-50 !text-gray-400',
 | 
						|
        containerOpen: '',
 | 
						|
        containerOpenTop: '',
 | 
						|
        containerActive: 'ring-1 ring-primary-400 border-primary-400',
 | 
						|
        containerInvalid:
 | 
						|
          'border-red-400 ring-red-400 focus:ring-red-400 focus:border-red-400',
 | 
						|
        containerInvalidActive: 'ring-1 border-red-400 ring-red-400',
 | 
						|
        singleLabel:
 | 
						|
          'flex items-center h-full absolute left-0 top-0 pointer-events-none bg-transparent leading-snug pl-3.5',
 | 
						|
        multipleLabel:
 | 
						|
          'flex items-center h-full absolute left-0 top-0 pointer-events-none bg-transparent leading-snug pl-3.5',
 | 
						|
        search:
 | 
						|
          'w-full absolute inset-0 outline-none appearance-none box-border border-0 text-sm font-sans bg-white rounded-md pl-3.5',
 | 
						|
        tags: 'grow shrink flex flex-wrap mt-1 pl-2',
 | 
						|
        tag: 'bg-primary-500 text-white text-sm font-semibold py-0.5 pl-2 rounded mr-1 mb-1 flex items-center whitespace-nowrap',
 | 
						|
        tagDisabled: 'pr-2 !bg-gray-400 text-white',
 | 
						|
        tagRemove:
 | 
						|
          'flex items-center justify-center p-1 mx-0.5 rounded-sm hover:bg-black hover:bg-opacity-10 group',
 | 
						|
        tagRemoveIcon:
 | 
						|
          'bg-multiselect-remove text-white bg-center bg-no-repeat opacity-30 inline-block w-3 h-3 group-hover:opacity-60',
 | 
						|
        tagsSearchWrapper: 'inline-block relative mx-1 mb-1 grow shrink h-full',
 | 
						|
        tagsSearch:
 | 
						|
          'absolute inset-0 border-0 focus:outline-none !shadow-none !focus:shadow-none appearance-none p-0 text-sm font-sans box-border w-full',
 | 
						|
        tagsSearchCopy: 'invisible whitespace-pre-wrap inline-block h-px',
 | 
						|
        placeholder:
 | 
						|
          'flex items-center h-full absolute left-0 top-0 pointer-events-none bg-transparent leading-snug pl-3.5 text-gray-400 text-sm',
 | 
						|
        caret:
 | 
						|
          'bg-multiselect-caret bg-center bg-no-repeat w-5 h-5 py-px box-content z-5 relative mr-1 opacity-40 shrink-0 grow-0 transition-transform',
 | 
						|
        caretOpen: 'rotate-180 pointer-events-auto',
 | 
						|
        clear:
 | 
						|
          'pr-3.5 relative z-10 opacity-40 transition duration-300 shrink-0 grow-0 flex hover:opacity-80',
 | 
						|
        clearIcon:
 | 
						|
          'bg-multiselect-remove bg-center bg-no-repeat w-2.5 h-4 py-px box-content inline-block',
 | 
						|
        spinner:
 | 
						|
          'bg-multiselect-spinner bg-center bg-no-repeat w-4 h-4 z-10 mr-3.5 animate-spin shrink-0 grow-0',
 | 
						|
        dropdown:
 | 
						|
          'max-h-60 shadow-lg absolute -left-px -right-px -bottom-1 translate-y-full border border-gray-300 mt-1 overflow-y-auto z-50 bg-white flex flex-col rounded-md',
 | 
						|
        dropdownTop:
 | 
						|
          '-translate-y-full -top-2 bottom-auto flex-col-reverse rounded-md',
 | 
						|
        dropdownHidden: 'hidden',
 | 
						|
        options: 'flex flex-col p-0 m-0 list-none',
 | 
						|
        optionsTop: 'flex-col-reverse',
 | 
						|
        group: 'p-0 m-0',
 | 
						|
        groupLabel:
 | 
						|
          'flex text-sm box-border items-center justify-start text-left py-1 px-3 font-semibold bg-gray-200 cursor-default leading-normal',
 | 
						|
        groupLabelPointable: 'cursor-pointer',
 | 
						|
        groupLabelPointed: 'bg-gray-300 text-gray-700',
 | 
						|
        groupLabelSelected: 'bg-primary-600 text-white',
 | 
						|
        groupLabelDisabled: 'bg-gray-100 text-gray-300 cursor-not-allowed',
 | 
						|
        groupLabelSelectedPointed: 'bg-primary-600 text-white opacity-90',
 | 
						|
        groupLabelSelectedDisabled:
 | 
						|
          'text-primary-100 bg-primary-600 bg-opacity-50 cursor-not-allowed',
 | 
						|
        groupOptions: 'p-0 m-0',
 | 
						|
        option:
 | 
						|
          'flex items-center justify-start box-border text-left cursor-pointer text-sm leading-snug py-2 px-3',
 | 
						|
        optionPointed: 'text-gray-800 bg-gray-100',
 | 
						|
        optionSelected: 'text-white bg-primary-500',
 | 
						|
        optionDisabled: 'text-gray-300 cursor-not-allowed',
 | 
						|
        optionSelectedPointed: 'text-white bg-primary-500 opacity-90',
 | 
						|
        optionSelectedDisabled:
 | 
						|
          'text-primary-100 bg-primary-500 bg-opacity-50 cursor-not-allowed',
 | 
						|
        noOptions: 'py-2 px-3 text-gray-600 bg-white',
 | 
						|
        noResults: 'py-2 px-3 text-gray-600 bg-white',
 | 
						|
        fakeInput:
 | 
						|
          'bg-transparent absolute left-0 right-0 -bottom-px w-full h-px border-0 p-0 appearance-none outline-none text-transparent',
 | 
						|
        spacer: 'h-9 py-px box-content',
 | 
						|
      }),
 | 
						|
    },
 | 
						|
    strict: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    closeOnSelect: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    autocomplete: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
    },
 | 
						|
    groups: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    groupLabel: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'label',
 | 
						|
    },
 | 
						|
    groupOptions: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'options',
 | 
						|
    },
 | 
						|
    groupHideEmpty: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: false,
 | 
						|
    },
 | 
						|
    groupSelect: {
 | 
						|
      type: Boolean,
 | 
						|
      required: false,
 | 
						|
      default: true,
 | 
						|
    },
 | 
						|
    inputType: {
 | 
						|
      type: String,
 | 
						|
      required: false,
 | 
						|
      default: 'text',
 | 
						|
    },
 | 
						|
  },
 | 
						|
  emits: [
 | 
						|
    'open',
 | 
						|
    'close',
 | 
						|
    'select',
 | 
						|
    'deselect',
 | 
						|
    'input',
 | 
						|
    'search-change',
 | 
						|
    'tag',
 | 
						|
    'update:modelValue',
 | 
						|
    'change',
 | 
						|
    'clear',
 | 
						|
  ],
 | 
						|
  setup(props, context) {
 | 
						|
    const value = useValue(props, context)
 | 
						|
    const pointer = usePointer(props, context)
 | 
						|
    const dropdown = useDropdown(props, context)
 | 
						|
    const search = useSearch(props, context)
 | 
						|
 | 
						|
    const data = useData(props, context, {
 | 
						|
      iv: value.iv,
 | 
						|
    })
 | 
						|
 | 
						|
    const multiselect = useMultiselect(props, context, {
 | 
						|
      input: search.input,
 | 
						|
      open: dropdown.open,
 | 
						|
      close: dropdown.close,
 | 
						|
      clearSearch: search.clearSearch,
 | 
						|
    })
 | 
						|
 | 
						|
    const options = useOptions(props, context, {
 | 
						|
      ev: value.ev,
 | 
						|
      iv: value.iv,
 | 
						|
      search: search.search,
 | 
						|
      clearSearch: search.clearSearch,
 | 
						|
      update: data.update,
 | 
						|
      pointer: pointer.pointer,
 | 
						|
      clearPointer: pointer.clearPointer,
 | 
						|
      blur: multiselect.blur,
 | 
						|
      deactivate: multiselect.deactivate,
 | 
						|
    })
 | 
						|
 | 
						|
    const pointerAction = usePointerAction(props, context, {
 | 
						|
      fo: options.fo,
 | 
						|
      fg: options.fg,
 | 
						|
      handleOptionClick: options.handleOptionClick,
 | 
						|
      handleGroupClick: options.handleGroupClick,
 | 
						|
      search: search.search,
 | 
						|
      pointer: pointer.pointer,
 | 
						|
      setPointer: pointer.setPointer,
 | 
						|
      clearPointer: pointer.clearPointer,
 | 
						|
      multiselect: multiselect.multiselect,
 | 
						|
    })
 | 
						|
 | 
						|
    const keyboard = useKeyboard(props, context, {
 | 
						|
      iv: value.iv,
 | 
						|
      update: data.update,
 | 
						|
      search: search.search,
 | 
						|
      setPointer: pointer.setPointer,
 | 
						|
      selectPointer: pointerAction.selectPointer,
 | 
						|
      backwardPointer: pointerAction.backwardPointer,
 | 
						|
      forwardPointer: pointerAction.forwardPointer,
 | 
						|
      blur: multiselect.blur,
 | 
						|
      fo: options.fo,
 | 
						|
    })
 | 
						|
 | 
						|
    const classes = useClasses(props, context, {
 | 
						|
      isOpen: dropdown.isOpen,
 | 
						|
      isPointed: pointerAction.isPointed,
 | 
						|
      canPointGroups: pointerAction.canPointGroups,
 | 
						|
      isSelected: options.isSelected,
 | 
						|
      isDisabled: options.isDisabled,
 | 
						|
      isActive: multiselect.isActive,
 | 
						|
      resolving: options.resolving,
 | 
						|
      fo: options.fo,
 | 
						|
    })
 | 
						|
 | 
						|
    return {
 | 
						|
      ...value,
 | 
						|
      ...dropdown,
 | 
						|
      ...multiselect,
 | 
						|
      ...pointer,
 | 
						|
      ...data,
 | 
						|
      ...search,
 | 
						|
      ...options,
 | 
						|
      ...pointerAction,
 | 
						|
      ...keyboard,
 | 
						|
      ...classes,
 | 
						|
    }
 | 
						|
  },
 | 
						|
}
 | 
						|
</script>
 |