121 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			121 lines
		
	
	
		
			3.6 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <script setup lang="ts">
 | |
|   interface DataItem {
 | |
|     id: number;
 | |
|     value: string;
 | |
|   }
 | |
| 
 | |
|   import { ref, computed } from 'vue'
 | |
|   import {
 | |
|     Combobox,
 | |
|     ComboboxInput,
 | |
|     ComboboxButton,
 | |
|     ComboboxOptions,
 | |
|     ComboboxOption,
 | |
|     TransitionRoot
 | |
|   } from '@headlessui/vue'
 | |
|   import { CheckIcon, ChevronUpDownIcon } from '@heroicons/vue/20/solid'
 | |
| 
 | |
|   const props = defineProps({
 | |
|     placeholder: {
 | |
|       type: String,
 | |
|       default: ''
 | |
|     },
 | |
|     data: {
 | |
|       type: Array as () => DataItem[],
 | |
|       default: []
 | |
|     }
 | |
|   })
 | |
| 
 | |
|   const data: DataItem[] = [
 | |
|     {id: 0, value: props.placeholder},
 | |
|     ...props.data
 | |
|   ]
 | |
| 
 | |
|   let selected = ref(data[0])
 | |
|   let query = ref('')
 | |
| 
 | |
|   let filteredData = computed(() =>
 | |
|     query.value === ''
 | |
|       ? data
 | |
|       : data.filter((item: DataItem) =>
 | |
|           item.value
 | |
|             .toLowerCase()
 | |
|             .replace(/\s+/g, '')
 | |
|             .includes(query.value.toLowerCase().replace(/\s+/g, ''))
 | |
|         )
 | |
|   )
 | |
| 
 | |
|   const show = ref(false)
 | |
| </script>
 | |
| 
 | |
| <template>
 | |
|   <Combobox v-model="selected" v-slot="{ open }">
 | |
|     <div class="relative mt-1">
 | |
|       <div
 | |
|         class="relative w-full cursor-default overflow-hidden rounded-lg bg-gray-200 text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-teal-300 sm:text-sm"
 | |
|       >
 | |
|         <ComboboxInput
 | |
|           class="w-full border-none py-2 pl-3 pr-10 bg-gray-200 text-sm leading-5 text-gray-900 focus:ring-0"
 | |
|           :displayValue="(item: any) => (show || open ? '' : item.value)"
 | |
|           @change="query = $event.target.value"
 | |
|           @click="show = true"
 | |
|           @blur="show = false"
 | |
|           defaultValue="sasa"
 | |
|         />
 | |
| 
 | |
|         <ComboboxButton id="Test" class="absolute inset-y-0 right-0 flex items-center pr-2">
 | |
|           <ChevronUpDownIcon class="h-5 w-5 text-gray-400" aria-hidden="true" />
 | |
|         </ComboboxButton>
 | |
|       </div>
 | |
|       <TransitionRoot
 | |
|         :show="show || open"
 | |
|         leave="transition ease-in duration-100"
 | |
|         leaveFrom="opacity-100"
 | |
|         leaveTo="opacity-0"
 | |
|         @after-leave="query = ''"
 | |
|       >
 | |
|         <ComboboxOptions
 | |
|           class="absolute mt-1 z-10 max-h-60 w-full overflow-auto rounded-md bg-gray-200 py-1 text-base shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm"
 | |
|         >
 | |
|           <div
 | |
|             v-if="filteredData.length === 0 && query !== ''"
 | |
|             class="relative cursor-default select-none py-2 px-4 text-gray-700"
 | |
|           >
 | |
|             Nothing found.
 | |
|           </div>
 | |
| 
 | |
|           <ComboboxOption
 | |
|             v-for="item in filteredData"
 | |
|             as="template"
 | |
|             :key="item.id"
 | |
|             :value="item"
 | |
|             v-slot="{ selected, active }"
 | |
|           >
 | |
|             <li
 | |
|               class="relative cursor-default select-none py-2 pl-10 pr-4"
 | |
|               :class="{
 | |
|                 'bg-teal-600 text-white': active,
 | |
|                 'text-gray-900': !active
 | |
|               }"
 | |
|             >
 | |
|               <span
 | |
|                 class="block truncate"
 | |
|                 :class="{ 'font-medium': selected, 'font-normal': !selected }"
 | |
|               >
 | |
|                 {{ item.value }}
 | |
|               </span>
 | |
|               <span
 | |
|                 v-if="selected"
 | |
|                 class="absolute inset-y-0 left-0 flex items-center pl-3"
 | |
|                 :class="{ 'text-white': active, 'text-teal-600': !active }"
 | |
|               >
 | |
|                 <CheckIcon class="h-5 w-5" aria-hidden="true" />
 | |
|               </span>
 | |
|             </li>
 | |
|           </ComboboxOption>
 | |
|         </ComboboxOptions>
 | |
|       </TransitionRoot>
 | |
|     </div>
 | |
|   </Combobox>
 | |
| </template>
 |