import {
defineComponent, type Ref, type PropType, ref, computed,
} from 'vue'
import useClickOutside from '../../composables/use-click-outside'
import defineTemplate from './template'
import type { SelectSlotParams } from './types'
import './styles.scss'
export interface DefaultSelectExposed {
isActive: boolean
}
/**
* Пользовательский компонент для отображения селекта, соответствующий дизайну.
*
* Дизайн
*
*/
export const defineDefaultSelect = () => defineComponent({
name: 'DefaultSelect',
props: {
/**
* Опция копирования значения
*/
isWithCopy: {
type: Boolean,
default: false,
},
/**
* Вариант отображения селекта (filter, form)
*/
appearance: {
type: String as PropType<'filter'|'form'>,
default: 'filter',
},
/**
* Пользовательская установка значения **подсветки** \
*/
customHighlightSearch: {
type: Function as PropType<(value: string) => string>,
default: undefined,
},
/**
* Скрытие поиска
*/
hideSearch: {
type: Boolean,
default: true,
},
/**
* Значение селекта
*/
modelValue: {
type: Object as PropType,
default: undefined,
},
/**
* Название селекта. Располагается над селектом
*/
title: {
type: String,
},
/**
* Текстовая подсказка в окне селекта при значении undefined в modelValue
*/
placeholder: {
type: String,
},
/**
* Описание селекта. Располагается под селектом
*/
description: {
type: String,
default: '',
},
/**
* Функция смены значения
*/
onValueChange: {
type: Function as PropType<(value: T|undefined) => void>,
required: true,
},
/**
* Массив объектов для выпадающего списка
* Пример: const items = [ { id: '1', name: 'Вариант 1' }, { id: '2', name: 'Вариант 2' } ]
*/
items: {
type: Array as PropType,
required: true,
},
/**
* Функция со слотом кастомных элементов списка
*/
itemSlot: {
type: Function as PropType<(item: T, params: SelectSlotParams) => JSX.Element>,
},
/**
* Вкл/Выкл возможность очищать выбранное значение
*/
resetable: {
type: Boolean,
default: true,
},
/**
* Размер селекта
*/
size: {
type: String as PropType<'M'|'S'>,
},
/**
* Флаг, указывающий, отключен ли селект
*/
disabled: {
type: Boolean,
default: false,
},
/**
* Массив ошибок
*/
errors: {
type: [Array, String] as PropType,
default: () => [],
},
/**
* Число отображаемых элементов в раскрытом списке
*/
showItemsCount: {
type: Number,
default: 6,
},
/**
* Отметить как обязательный
*/
isRequired: {
type: Boolean,
default: false,
},
/**
* Флаг, в значении true отображает id каждого элемента
*/
showDescriptionId: {
type: Boolean,
default: false,
},
},
setup(props, app) {
const isOpened = ref(false)
const search = ref('')
const root = ref(null) as unknown as Ref
const select = ref(null) as unknown as Ref
const triggerDown = ref(null) as unknown as Ref
const triggerUp = ref(null) as unknown as Ref
const value = computed(() => props.modelValue as T)
const items = computed(() => {
let result = props.items
if (search.value) {
result = props.items.filter(({ name }) => name.toLowerCase().includes(search.value.toLowerCase()))
}
return result
})
useClickOutside(select, () => {
isOpened.value = false
})
const clear = () => {
if (props.onValueChange) props.onValueChange(undefined)
}
app.expose({ isOpened })
const toggleOpened = () => {
isOpened.value = !isOpened.value
}
const toggleItem = (item: T) => {
if (value.value?.id !== item.id && props.onValueChange) {
props.onValueChange(item)
}
toggleOpened()
}
const isSelected = (item: T) => value.value?.id === item.id
const SelectTemplate = defineTemplate()
const templateProps = computed(() => ({
clear,
close: () => { isOpened.value = false },
isWithCopy: props.isWithCopy,
disabled: props.disabled,
errors: props.errors,
isLoadingNext: false,
isLoadingPrev: false,
isOpened: isOpened.value,
isSelected,
items: items.value,
itemSlot: props.itemSlot,
modelValue: value.value ? [value.value] : [],
placeholder: props.placeholder,
description: props.description,
isRequired: props.isRequired,
resetable: props.resetable,
root,
select,
title: props.title,
toggleItem,
toggleOpened,
topItems: [],
triggerUp,
triggerDown,
tableIconType: 'arrow',
isSingle: true,
appearance: props.appearance,
size: props.size,
showItemsCount: props.showItemsCount,
showDescriptionId: props.showDescriptionId,
hideSearch: props.hideSearch,
search: search.value,
setSearch: (s: string) => { search.value = s },
customHighlightSearch: props.customHighlightSearch?.(search.value),
}))
return (): JSX.Element =>
},
})
export default defineDefaultSelect<{id: string, name: string}>()