45 lines
3.2 KiB
Vue
45 lines
3.2 KiB
Vue
<template>
|
|
<Label class="my-2 flex flex-1 items-center justify-between flex-col md:flex-row">
|
|
<span class="pb-1 md:p-0">{{ label }}</span>
|
|
<ComboboxRoot v-model:model-value="model" v-model:open="open" :multiple="multiple">
|
|
<ComboboxAnchor :disabled="disabled" class="mx-4 inline-flex min-w-[150px] items-center justify-between px-3 text-sm font-semibold leading-none h-8 gap-1
|
|
bg-light-20 dark:bg-dark-20 border border-light-35 dark:border-dark-35 outline-none data-[placeholder]:font-normal
|
|
data-[placeholder]:text-light-50 dark:data-[placeholder]:text-dark-50 focus:shadow-raw transition-[box-shadow] focus:shadow-light-40 dark:focus:shadow-dark-40
|
|
hover:border-light-50 dark:hover:border-dark-50">
|
|
<ComboboxTrigger class="flex flex-1 justify-between !cursor-pointer">
|
|
<span v-if="!multiple">{{ model !== undefined ? options.find(e => e[1] === model)![0] : "" }}</span>
|
|
<span class="flex gap-2" v-else><span v-if="model !== undefined">{{ options.find(e => e[1] === (model as T[])[0]) !== undefined ? options.find(e => e[1] === (model as T[])[0])![0] : undefined }}</span><span v-if="model !== undefined && (model as T[]).length > 1">{{((model as T[]).length > 1 ? `+${(model as T[]).length - 1}` : "") }}</span></span>
|
|
<Icon icon="radix-icons:caret-down" class="h-4 w-4" />
|
|
</ComboboxTrigger>
|
|
</ComboboxAnchor>
|
|
|
|
<ComboboxPortal :disabled="disabled">
|
|
<ComboboxContent :position="position" align="start" class="min-w-[150px] bg-light-20 dark:bg-dark-20 will-change-[opacity,transform] z-50">
|
|
<ComboboxViewport>
|
|
<ComboboxItem v-for="[label, value] of options" :value="value" :disabled="disabled" class="text-base py-2 leading-none text-light-60 dark:text-dark-60 flex items-center px-6 relative Combobox-none data-[disabled]:text-light-50 dark:data-[disabled]:text-dark-50 data-[disabled]:pointer-events-none data-[highlighted]:outline-none data-[highlighted]:bg-light-30 dark:data-[highlighted]:bg-dark-30 data-[highlighted]:text-light-100 dark:data-[highlighted]:text-dark-100">
|
|
<span class="">{{ label }}</span>
|
|
<ComboboxItemIndicator class="absolute left-1 w-4 inline-flex items-center justify-center">
|
|
<Icon icon="radix-icons:check" />
|
|
</ComboboxItemIndicator>
|
|
</ComboboxItem>
|
|
</ComboboxViewport>
|
|
</ComboboxContent>
|
|
</ComboboxPortal>
|
|
</ComboboxRoot>
|
|
</Label>
|
|
</template>
|
|
|
|
<script setup lang="ts" generic="T extends string | number | boolean | Record<string, any>">
|
|
import { ComboboxInput, ComboboxTrigger, ComboboxViewport, ComboboxContent, ComboboxPortal, ComboboxRoot } from 'radix-vue'
|
|
import { Icon } from '@iconify/vue';
|
|
const { disabled = false, position = 'popper', multiple = false } = defineProps<{
|
|
placeholder?: string
|
|
disabled?: boolean
|
|
position?: 'inline' | 'popper'
|
|
label?: string
|
|
multiple?: boolean
|
|
options: Array<[string, T]>
|
|
}>();
|
|
const open = ref(false);
|
|
const model = defineModel<T | T[]>();
|
|
</script> |