mirror of
https://github.com/nocodb/nocodb.git
synced 2026-05-01 10:56:36 +00:00
158 lines
3.6 KiB
Vue
158 lines
3.6 KiB
Vue
<script lang="ts" setup>
|
|
import type { iconMap } from '#imports'
|
|
|
|
const props = withDefaults(
|
|
defineProps<{
|
|
value?: string | string[]
|
|
placeholder?: string
|
|
mode?: 'multiple' | 'tags'
|
|
size?: 'small' | 'middle' | 'large'
|
|
dropdownClassName?: string
|
|
showSearch?: boolean
|
|
// filterOptions is a function
|
|
filterOption?: (input: string, option: any) => boolean
|
|
dropdownMatchSelectWidth?: boolean
|
|
allowClear?: boolean
|
|
loading?: boolean
|
|
suffixIcon?: keyof typeof iconMap
|
|
maxTagCount?: number
|
|
}>(),
|
|
{
|
|
suffixIcon: 'arrowDown',
|
|
},
|
|
)
|
|
|
|
const emits = defineEmits(['update:value', 'change', 'search'])
|
|
|
|
const placeholder = computed(() => props.placeholder)
|
|
|
|
const dropdownClassName = computed(() => {
|
|
let className = 'nc-select-dropdown'
|
|
if (props.dropdownClassName) {
|
|
className += ` ${props.dropdownClassName}`
|
|
}
|
|
return className
|
|
})
|
|
|
|
const { showSearch, filterOption, dropdownMatchSelectWidth, loading, mode } = toRefs(props)
|
|
|
|
const vModel = useVModel(props, 'value', emits)
|
|
|
|
const onChange = (value: string) => {
|
|
emits('change', value)
|
|
}
|
|
|
|
const onSearch = (value: string) => {
|
|
emits('search', value)
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<a-select
|
|
v-model:value="vModel"
|
|
:size="size"
|
|
:allow-clear="allowClear"
|
|
:disabled="loading"
|
|
:dropdown-class-name="dropdownClassName"
|
|
:dropdown-match-select-width="dropdownMatchSelectWidth"
|
|
:filter-option="filterOption"
|
|
:loading="loading"
|
|
:mode="mode"
|
|
:placeholder="placeholder"
|
|
:show-search="showSearch"
|
|
:max-tag-count="maxTagCount"
|
|
class="nc-select nc-select-shadow"
|
|
@change="onChange as any"
|
|
@search="onSearch"
|
|
>
|
|
<template #suffixIcon>
|
|
<GeneralLoader v-if="loading" />
|
|
<GeneralIcon v-else class="text-nc-content-gray nc-select-expand-btn" :icon="suffixIcon" />
|
|
</template>
|
|
|
|
<template v-if="$slots.dropdownRender" #dropdownRender="{ menuNode }">
|
|
<slot name="dropdownRender" :menu-node="menuNode" />
|
|
</template>
|
|
<slot />
|
|
</a-select>
|
|
</template>
|
|
|
|
<style lang="scss">
|
|
.ant-select-item {
|
|
@apply !xs:h-13 !min-h-[2.375rem] !p-2;
|
|
}
|
|
|
|
.ant-select-item-option-state {
|
|
@apply !xs:mt-1.75;
|
|
}
|
|
.ant-select-item-option {
|
|
@apply !rounded-md;
|
|
}
|
|
|
|
.nc-select.ant-select {
|
|
height: fit-content;
|
|
.ant-select-selector {
|
|
box-shadow: 0px 5px 3px -2px rgba(0, 0, 0, 0.02), 0px 3px 1px -2px rgba(0, 0, 0, 0.06);
|
|
@apply border-1 border-nc-border-gray-medium rounded-lg shadow-default;
|
|
}
|
|
|
|
.ant-select-selection-item {
|
|
@apply font-medium pr-3 rounded-md flex items-center;
|
|
}
|
|
|
|
.ant-select-selection-placeholder {
|
|
@apply text-nc-content-gray-subtle2;
|
|
}
|
|
.ant-select-selection-item-remove {
|
|
@apply text-nc-content-gray !pb-1;
|
|
}
|
|
|
|
.ant-select-clear {
|
|
@apply flex;
|
|
|
|
svg {
|
|
@apply flex-none;
|
|
}
|
|
}
|
|
}
|
|
.nc-select.ant-select-focused:not(.ant-select-disabled).ant-select:not(.ant-select-customize-input) .ant-select-selector {
|
|
@apply border-nc-border-brand;
|
|
}
|
|
|
|
.nc-select.ant-select.ant-select-disabled .nc-select-expand-btn {
|
|
@apply text-nc-content-brand-hover;
|
|
}
|
|
|
|
.nc-select-dropdown {
|
|
@apply !rounded-lg py-1.5;
|
|
|
|
.rc-virtual-list-holder {
|
|
overflow-y: auto;
|
|
overflow-x: hidden;
|
|
font-weight: 500;
|
|
|
|
.ant-select-item-option-content {
|
|
font-weight: 500;
|
|
}
|
|
|
|
&::-webkit-scrollbar {
|
|
width: 4px;
|
|
height: 4px;
|
|
}
|
|
&::-webkit-scrollbar-track-piece {
|
|
width: 0px;
|
|
}
|
|
&::-webkit-scrollbar {
|
|
@apply bg-transparent;
|
|
}
|
|
&::-webkit-scrollbar-thumb {
|
|
width: 4px;
|
|
@apply bg-nc-bg-gray-dark rounded-md;
|
|
}
|
|
&::-webkit-scrollbar-thumb:hover {
|
|
@apply bg-nc-bg-gray-extra-dark;
|
|
}
|
|
}
|
|
}
|
|
</style>
|