98 lines
3.1 KiB
Vue
98 lines
3.1 KiB
Vue
<script setup lang="ts">
|
|
interface Props {
|
|
options: Array<any>
|
|
labelName: string | number
|
|
modelValue?: object
|
|
placeholder?: string
|
|
defaultLabel?: string
|
|
placement?: string | 'top' | 'bottom'
|
|
className?: string
|
|
selectedColor?: string
|
|
}
|
|
|
|
const props = withDefaults(defineProps<Props>(), {
|
|
modelValue: null,
|
|
placeholder: null,
|
|
defaultLabel: null,
|
|
placement: 'bottom',
|
|
className: '',
|
|
selectedColor: '#333333',
|
|
})
|
|
|
|
const emits = defineEmits(['update:modelValue'])
|
|
|
|
const isActive = ref(false)
|
|
const isSelected = ref(props.defaultLabel !== null)
|
|
const selectedOption = ref<string>(props.placeholder || props.defaultLabel)
|
|
|
|
const onToggleOpen = () => {
|
|
isActive.value = !isActive.value
|
|
}
|
|
|
|
const onSelectOption = (option: { [key: string | number]: any }): void => {
|
|
isActive.value = false
|
|
isSelected.value = true
|
|
selectedOption.value = option[props.labelName]
|
|
emits('update:modelValue', option)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<div class="relative w-full max-w-[432px]">
|
|
<button
|
|
type="button"
|
|
class="relative flex items-center justify-between gap-[12px] w-full py-[12px] px-[16px] bg-white border-solid border-[1px] border-[#D9D9D9] rounded-[8px]"
|
|
@click="onToggleOpen"
|
|
>
|
|
<span
|
|
class="inline-flex items-center justify-left text-left text-[14px] font-[400] leading-[20px] tracking-[-0.42px]"
|
|
:class="isSelected ? 'text-[#333333]' : 'text-[#999999]'"
|
|
>
|
|
{{ selectedOption }}
|
|
</span>
|
|
<i class="inline-flex items-center justify-center shrink-0">
|
|
<AtomsIconsArrowDownFill
|
|
:size="14"
|
|
color="#333333"
|
|
:class="isActive ? 'rotate-180' : ''"
|
|
/>
|
|
</i>
|
|
</button>
|
|
<div
|
|
v-if="isActive"
|
|
:data-placement="props.placement"
|
|
class="absolute z-[10] top-full left-0 translate-y-[4px] w-full py-[8px] border-[1px] border-solid border-[rgba(0,0,0,0.3)] rounded-[8px] bg-white shadow-[0_4px_10px_0_rgba(0,0,0,0.10)]"
|
|
>
|
|
<ul class="relative flex flex-col items-center justify-start w-full">
|
|
<li
|
|
v-for="option in props.options"
|
|
:key="String(option[props.labelName])"
|
|
class="relative flex items-center justify-left w-full"
|
|
>
|
|
<button
|
|
type="button"
|
|
class="relative flex items-center justify-left w-full py-[8px] pl-[40px] pr-[16px] bg-white text-left text-[14px] font-[400] leading-[24px] tracking-[-0.42px] hover:bg-[rgba(0,0,0,0.04)]"
|
|
:class="
|
|
selectedColor ? `text-[${selectedColor}]` : 'text-[#333333]'
|
|
"
|
|
@click="onSelectOption(option)"
|
|
>
|
|
<template v-if="option[props.labelName] === selectedOption">
|
|
<i
|
|
class="absolute top-1/2 left-[12px] translate-y-[-50%] flex items-center justify-center w-[20px] h-[20px]"
|
|
>
|
|
<AtomsIconsCheckLine :size="16" :color="selectedColor" />
|
|
</i>
|
|
</template>
|
|
<span>
|
|
{{ option[props.labelName] }}
|
|
</span>
|
|
</button>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<style scoped></style>
|