2022-05-08 09:44:52 +02:00
|
|
|
<template>
|
|
|
|
<div
|
|
|
|
ref="el"
|
|
|
|
class="select"
|
2022-05-13 18:20:47 +02:00
|
|
|
:class="{'select--open': isOpen, 'select--disabled': disabled}"
|
2022-05-08 09:44:52 +02:00
|
|
|
role="combobox"
|
2022-05-10 10:29:38 +02:00
|
|
|
:tabindex="searchable || disabled ? -1 : tabindex"
|
2022-05-08 09:44:52 +02:00
|
|
|
@focus="activate()"
|
2022-05-09 11:29:25 +02:00
|
|
|
@blur="searchable ? false : handleBlurEvent()"
|
2022-05-08 09:44:52 +02:00
|
|
|
@keyup.esc="deactivate()"
|
|
|
|
@keydown.self.down.prevent="moveDown()"
|
|
|
|
@keydown.self.up.prevent="moveUp"
|
|
|
|
>
|
|
|
|
<div class="select__item-text">
|
|
|
|
<input
|
|
|
|
v-if="searchable"
|
|
|
|
ref="searchInput"
|
|
|
|
class="select__search-input"
|
|
|
|
:style="searchInputStyle"
|
|
|
|
type="text"
|
|
|
|
autocomplete="off"
|
|
|
|
spellcheck="false"
|
|
|
|
:tabindex="tabindex"
|
|
|
|
:value="searchText"
|
|
|
|
@input="searchText = $event.target.value"
|
2022-05-09 11:29:25 +02:00
|
|
|
@focus.prevent="!isOpen ? activate() : false"
|
|
|
|
@blur.prevent="handleBlurEvent()"
|
2022-05-08 09:44:52 +02:00
|
|
|
@keyup.esc="deactivate()"
|
2022-05-08 18:59:00 +02:00
|
|
|
@keydown.down.prevent="keyArrows('down')"
|
|
|
|
@keydown.up.prevent="keyArrows('up')"
|
2022-05-08 09:44:52 +02:00
|
|
|
@keypress.enter.prevent.stop.self="select(filteredOptions[hightlightedIndex])"
|
|
|
|
>
|
|
|
|
<span v-if="searchable && !isOpen || !searchable">{{ currentOptionLabel }}</span>
|
|
|
|
</div>
|
2022-05-22 15:45:16 +02:00
|
|
|
<Transition :name="animation">
|
2022-05-09 11:29:25 +02:00
|
|
|
<div
|
2022-05-22 15:45:16 +02:00
|
|
|
v-if="isOpen"
|
2022-05-09 11:29:25 +02:00
|
|
|
ref="optionList"
|
|
|
|
:class="`select__list-wrapper ${dropdownClass ? dropdownClass : '' }`"
|
2022-05-29 16:42:41 +02:00
|
|
|
@mousedown="isMouseDown = true"
|
|
|
|
@mouseup="handleMouseUpEvent()"
|
2022-05-09 11:29:25 +02:00
|
|
|
>
|
|
|
|
<ul class="select__list" @mousedown.prevent>
|
|
|
|
<li
|
|
|
|
v-for="(opt, index) of filteredOptions"
|
2022-05-09 17:31:58 +02:00
|
|
|
:key="opt.id"
|
2022-05-09 11:29:25 +02:00
|
|
|
:ref="(el) => optionRefs[index] = el"
|
|
|
|
:class="{
|
2022-05-13 18:35:02 +02:00
|
|
|
'select__item': true,
|
2022-05-09 17:31:58 +02:00
|
|
|
'select__group': opt.$type === 'group',
|
2022-05-11 22:57:13 +02:00
|
|
|
'select__option--highlight': opt.$type === 'option' && !opt.disabled && index === hightlightedIndex,
|
|
|
|
'select__option--selected': opt.$type === 'option' && isSelected(opt),
|
|
|
|
'select__option--disabled': opt.disabled
|
2022-05-09 11:29:25 +02:00
|
|
|
}"
|
|
|
|
@click.stop="select(opt)"
|
2022-05-13 18:35:02 +02:00
|
|
|
@mousemove.self="hightlightedIndex = index"
|
2022-05-08 09:44:52 +02:00
|
|
|
>
|
2022-05-09 11:29:25 +02:00
|
|
|
<slot
|
|
|
|
name="option"
|
|
|
|
:option="opt"
|
|
|
|
:index="index"
|
|
|
|
>
|
2022-05-09 17:31:58 +02:00
|
|
|
{{ opt.label }}
|
2022-05-09 11:29:25 +02:00
|
|
|
</slot>
|
|
|
|
</li>
|
|
|
|
</ul>
|
|
|
|
</div>
|
2022-05-22 15:45:16 +02:00
|
|
|
</Transition>
|
2022-05-08 09:44:52 +02:00
|
|
|
</div>
|
|
|
|
</template>
|
|
|
|
|
|
|
|
<script>
|
2023-08-18 15:57:31 +02:00
|
|
|
import { computed, defineComponent, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
export default defineComponent({
|
|
|
|
name: 'BaseSelect',
|
|
|
|
props: {
|
|
|
|
modelValue: {
|
2022-05-13 18:20:47 +02:00
|
|
|
type: [String, Number, Object, Boolean]
|
2022-05-08 09:44:52 +02:00
|
|
|
},
|
2022-05-09 11:29:25 +02:00
|
|
|
value: {
|
2022-05-13 18:20:47 +02:00
|
|
|
type: [String, Number, Object, Boolean]
|
2022-05-09 11:29:25 +02:00
|
|
|
},
|
2022-05-08 09:44:52 +02:00
|
|
|
searchable: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true
|
|
|
|
},
|
|
|
|
preserveSearch: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
|
|
|
},
|
|
|
|
tabindex: {
|
|
|
|
type: Number,
|
|
|
|
default: 0
|
|
|
|
},
|
|
|
|
options: {
|
|
|
|
type: Array,
|
|
|
|
default: () => []
|
|
|
|
},
|
|
|
|
optionTrackBy: {
|
|
|
|
type: [String, Function],
|
2022-05-10 10:29:38 +02:00
|
|
|
default: 'value'
|
2022-05-08 09:44:52 +02:00
|
|
|
},
|
|
|
|
optionLabel: {
|
|
|
|
type: [String, Function],
|
2022-05-10 10:29:38 +02:00
|
|
|
default: 'label'
|
2022-05-08 09:44:52 +02:00
|
|
|
},
|
2022-05-11 22:57:13 +02:00
|
|
|
optionDisabled: {
|
|
|
|
type: Function
|
|
|
|
},
|
2022-05-09 17:31:58 +02:00
|
|
|
groupLabel: {
|
|
|
|
type: String
|
|
|
|
},
|
|
|
|
groupValues: {
|
|
|
|
type: String
|
|
|
|
},
|
2022-05-08 09:44:52 +02:00
|
|
|
closeOnSelect: {
|
|
|
|
type: Boolean,
|
|
|
|
default: true
|
2022-05-09 11:29:25 +02:00
|
|
|
},
|
2022-05-22 15:45:16 +02:00
|
|
|
animation: {
|
2022-05-09 11:29:25 +02:00
|
|
|
type: String,
|
2022-05-22 15:45:16 +02:00
|
|
|
default: 'fade-slide-down'
|
2022-05-09 11:29:25 +02:00
|
|
|
},
|
|
|
|
dropdownOffsets: {
|
|
|
|
type: Object,
|
|
|
|
default: () => ({ top: 10, left: 0 })
|
|
|
|
},
|
|
|
|
dropdownClass: {
|
|
|
|
type: String
|
2022-05-10 10:29:38 +02:00
|
|
|
},
|
|
|
|
disabled: {
|
|
|
|
type: Boolean,
|
|
|
|
default: false
|
2022-06-19 16:58:52 +02:00
|
|
|
},
|
|
|
|
maxVisibleOptions: {
|
|
|
|
type: Number,
|
|
|
|
default: 100
|
2022-05-08 09:44:52 +02:00
|
|
|
}
|
|
|
|
},
|
2022-05-09 11:29:25 +02:00
|
|
|
emits: ['select', 'open', 'close', 'update:modelValue', 'change', 'blur'],
|
2022-05-08 09:44:52 +02:00
|
|
|
setup (props, { emit }) {
|
|
|
|
const hightlightedIndex = ref(0);
|
|
|
|
const isOpen = ref(false);
|
2022-05-29 16:42:41 +02:00
|
|
|
const isMouseDown = ref(false);
|
2022-06-14 20:02:17 +02:00
|
|
|
const internalValue = ref(props.modelValue !== false ? props.modelValue : props.value);
|
2022-05-08 09:44:52 +02:00
|
|
|
const el = ref(null);
|
|
|
|
const searchInput = ref(null);
|
2022-05-08 18:59:00 +02:00
|
|
|
const optionList = ref(null);
|
|
|
|
const optionRefs = [];
|
2022-05-08 09:44:52 +02:00
|
|
|
const searchText = ref('');
|
2022-05-09 17:31:58 +02:00
|
|
|
|
|
|
|
const getOptionValue = (opt) => _guess('optionTrackBy', opt);
|
2022-06-19 16:58:52 +02:00
|
|
|
const getOptionLabel = (opt) => _guess('optionLabel', opt) + '';
|
2022-05-11 22:57:13 +02:00
|
|
|
const getOptionDisabled = (opt) => _guess('optionDisabled', opt);
|
2022-05-09 17:31:58 +02:00
|
|
|
const _guess = (name, item) => {
|
|
|
|
const prop = props[name];
|
2022-05-10 10:29:38 +02:00
|
|
|
if (typeof prop === 'function')
|
|
|
|
return prop(item);
|
|
|
|
|
2022-06-02 09:46:49 +02:00
|
|
|
return item[prop] !== undefined ? item[prop] : item;
|
2022-05-09 17:31:58 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const flattenOptions = computed(() => {
|
|
|
|
return [...props.options].reduce((prev, curr) => {
|
|
|
|
if (curr[props.groupValues] && curr[props.groupValues].length) {
|
|
|
|
prev.push({
|
|
|
|
$type: 'group',
|
|
|
|
label: curr[props.groupLabel],
|
|
|
|
id: `group-${curr[props.groupLabel]}`,
|
|
|
|
count: curr[props.groupLabel].length
|
|
|
|
});
|
|
|
|
|
|
|
|
return prev.concat(curr[props.groupValues].map(el => {
|
|
|
|
const value = getOptionValue(el);
|
|
|
|
return {
|
|
|
|
$type: 'option',
|
|
|
|
label: getOptionLabel(el),
|
|
|
|
id: `option-${value}`,
|
2022-05-11 22:57:13 +02:00
|
|
|
disabled: getOptionDisabled(el) === true,
|
2022-05-09 17:31:58 +02:00
|
|
|
value,
|
|
|
|
$data: {
|
|
|
|
...el
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
const value = getOptionValue(curr);
|
|
|
|
prev.push({
|
|
|
|
$type: 'option',
|
|
|
|
label: getOptionLabel(curr),
|
|
|
|
id: `option-${value}`,
|
2022-05-11 22:57:13 +02:00
|
|
|
disabled: getOptionDisabled(curr) === true,
|
2022-05-09 17:31:58 +02:00
|
|
|
value,
|
|
|
|
$data: {
|
|
|
|
...curr
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
return prev;
|
|
|
|
}, []);
|
|
|
|
});
|
|
|
|
|
2022-05-08 09:44:52 +02:00
|
|
|
const filteredOptions = computed(() => {
|
2022-06-19 16:58:52 +02:00
|
|
|
const searchTerms = (searchText.value || '').toLowerCase().trim();
|
2022-05-08 09:44:52 +02:00
|
|
|
|
2022-06-19 16:58:52 +02:00
|
|
|
let options = searchTerms
|
|
|
|
? flattenOptions.value.filter(opt => opt.$type === 'group' || opt.label.trim().toLowerCase().indexOf(searchTerms) !== -1)
|
2022-05-09 17:31:58 +02:00
|
|
|
: flattenOptions.value;
|
2022-06-19 16:58:52 +02:00
|
|
|
|
|
|
|
if (options.length > props.maxVisibleOptions) {
|
|
|
|
let sliceStart = 0;
|
|
|
|
let sliceEnd = sliceStart + props.maxVisibleOptions;
|
|
|
|
|
|
|
|
// if no search active try to open the dropdown showing options around the selected one
|
|
|
|
if (searchTerms === '') {
|
|
|
|
const index = internalValue.value ? flattenOptions.value.findIndex(el => el.value === internalValue.value) : -1;
|
|
|
|
|
|
|
|
if (index < options.length -1) {
|
|
|
|
sliceStart = Math.max(0, index - Math.floor(props.maxVisibleOptions / 2));
|
|
|
|
sliceEnd = Math.min(sliceStart + sliceEnd, options.length -1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
options = options.slice(sliceStart, sliceEnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
return options;
|
2022-05-08 09:44:52 +02:00
|
|
|
});
|
|
|
|
|
|
|
|
const searchInputStyle = computed(() => {
|
|
|
|
if (props.searchable)
|
|
|
|
// just hide the input and give the ability to receive focus
|
|
|
|
return isOpen.value ? { with: '100%' } : { width: 0, position: 'absolute', padding: 0, margin: 0 };
|
|
|
|
|
|
|
|
return '';
|
|
|
|
});
|
|
|
|
|
|
|
|
watch(filteredOptions, (options) => {
|
|
|
|
if (hightlightedIndex.value >= options.length -1)
|
|
|
|
hightlightedIndex.value = options.length ? options.length -1 : 0;
|
|
|
|
else
|
|
|
|
hightlightedIndex.value = 0;
|
|
|
|
});
|
|
|
|
|
2022-06-10 20:02:26 +02:00
|
|
|
watch(() => props.modelValue, (val) => {
|
|
|
|
internalValue.value = val;
|
|
|
|
});
|
|
|
|
|
|
|
|
watch(() => props.value, (val) => {
|
|
|
|
internalValue.value = val;
|
|
|
|
});
|
|
|
|
|
2022-05-09 17:31:58 +02:00
|
|
|
const currentOptionLabel = computed(() =>
|
2022-06-10 20:02:26 +02:00
|
|
|
flattenOptions.value.find(d => d.value === internalValue.value)?.label
|
2022-05-09 17:31:58 +02:00
|
|
|
);
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
const select = (opt) => {
|
2022-05-11 22:57:13 +02:00
|
|
|
if (opt.$type === 'group' || opt.disabled) return;
|
2022-05-09 17:31:58 +02:00
|
|
|
|
|
|
|
internalValue.value = opt.value;
|
2022-05-08 09:44:52 +02:00
|
|
|
emit('select', opt);
|
2022-05-09 17:31:58 +02:00
|
|
|
emit('update:modelValue', opt.value);
|
2022-05-09 11:29:25 +02:00
|
|
|
emit('change', opt);
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
if (props.closeOnSelect)
|
|
|
|
deactivate();
|
|
|
|
};
|
|
|
|
|
|
|
|
const isSelected = (opt) => {
|
2022-05-09 17:31:58 +02:00
|
|
|
return internalValue.value === opt.value;
|
2022-05-08 09:44:52 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
const activate = () => {
|
2022-05-10 10:29:38 +02:00
|
|
|
if (isOpen.value || props.disabled) return;
|
2022-05-09 11:29:25 +02:00
|
|
|
isOpen.value = true;
|
2022-06-19 16:58:52 +02:00
|
|
|
hightlightedIndex.value = filteredOptions.value.findIndex(el => el.value === internalValue.value) || 0;
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
if (props.searchable)
|
|
|
|
searchInput.value.focus();
|
|
|
|
else
|
|
|
|
el.value.focus();
|
|
|
|
|
2022-05-09 17:31:58 +02:00
|
|
|
nextTick(() => {
|
|
|
|
adjustListPosition();
|
|
|
|
scrollTo(optionRefs[hightlightedIndex.value]);
|
|
|
|
});
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
emit('open');
|
|
|
|
};
|
|
|
|
|
|
|
|
const deactivate = () => {
|
|
|
|
if (!isOpen.value) return;
|
|
|
|
isOpen.value = false;
|
|
|
|
|
|
|
|
if (props.searchable)
|
2022-05-11 22:57:13 +02:00
|
|
|
searchInput.value?.blur();
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
else
|
2022-05-11 22:57:13 +02:00
|
|
|
el.value?.blur();
|
2022-05-08 09:44:52 +02:00
|
|
|
|
|
|
|
if (!props.preserveSearch) searchText.value = '';
|
|
|
|
|
|
|
|
emit('close');
|
|
|
|
};
|
|
|
|
|
2022-05-09 11:29:25 +02:00
|
|
|
const adjustListPosition = () => {
|
2022-06-26 10:21:17 +02:00
|
|
|
if (!optionList.value) return;
|
|
|
|
|
2022-05-22 15:45:16 +02:00
|
|
|
const element = el.value;
|
|
|
|
let { left, top } = element.getBoundingClientRect();
|
|
|
|
const { left: offsetLeft = 0, top: offsetTop = 0 } = props.dropdownOffsets;
|
|
|
|
top = top + element.clientHeight + offsetTop;
|
|
|
|
const openBottom = top >= 0 && top + optionList.value.clientHeight <= window.innerHeight;
|
|
|
|
|
|
|
|
if (!openBottom) {
|
|
|
|
top -= (offsetTop * 2 + element.clientHeight);
|
|
|
|
optionList.value.style.transform = 'translate(0, -100%)';
|
|
|
|
}
|
|
|
|
|
|
|
|
optionList.value.style.left = `${left + offsetLeft}px`;
|
|
|
|
optionList.value.style.top = `${top}px`;
|
|
|
|
optionList.value.style.minWidth = `${element.clientWidth}px`;
|
2022-05-09 11:29:25 +02:00
|
|
|
};
|
|
|
|
|
2022-05-08 18:59:00 +02:00
|
|
|
const keyArrows = (direction) => {
|
|
|
|
const sum = direction === 'down' ? +1 : -1;
|
2022-05-09 17:31:58 +02:00
|
|
|
let index = hightlightedIndex.value + sum;
|
|
|
|
index = Math.max(0, index > filteredOptions.value.length - 1 ? filteredOptions.value.length - 1 : index);
|
|
|
|
if (filteredOptions.value[index].$type === 'group')
|
|
|
|
index=Math.max(1, index+sum);
|
|
|
|
|
|
|
|
hightlightedIndex.value = index;
|
2022-05-08 18:59:00 +02:00
|
|
|
|
|
|
|
const optEl = optionRefs[hightlightedIndex.value];
|
2022-05-09 17:31:58 +02:00
|
|
|
if (!optEl)
|
|
|
|
return;
|
2022-05-08 18:59:00 +02:00
|
|
|
|
2022-05-09 17:31:58 +02:00
|
|
|
scrollTo(optEl);
|
|
|
|
};
|
|
|
|
|
|
|
|
const scrollTo = (optEl) => {
|
|
|
|
if (!optEl) return;
|
2022-05-08 18:59:00 +02:00
|
|
|
const visMin = optionList.value.scrollTop;
|
|
|
|
const visMax = optionList.value.scrollTop + optionList.value.clientHeight - optEl.clientHeight;
|
|
|
|
|
|
|
|
if (optEl.offsetTop < visMin)
|
|
|
|
optionList.value.scrollTop = optEl.offsetTop;
|
|
|
|
|
|
|
|
else if (optEl.offsetTop >= visMax)
|
|
|
|
optionList.value.scrollTop = optEl.offsetTop - optionList.value.clientHeight + optEl.clientHeight;
|
2022-05-08 09:44:52 +02:00
|
|
|
};
|
|
|
|
|
2022-05-09 11:29:25 +02:00
|
|
|
const handleBlurEvent = () => {
|
2022-05-29 16:42:41 +02:00
|
|
|
if (isMouseDown.value) return;
|
2022-05-09 11:29:25 +02:00
|
|
|
deactivate();
|
|
|
|
emit('blur');
|
|
|
|
};
|
|
|
|
|
2022-05-29 16:42:41 +02:00
|
|
|
const handleMouseUpEvent = () => {
|
|
|
|
isMouseDown.value = false;
|
|
|
|
searchInput.value.focus();
|
|
|
|
};
|
|
|
|
|
|
|
|
const handleWheelEvent = (e) => {
|
|
|
|
if (!e.target.className.includes('select__')) deactivate();
|
|
|
|
};
|
|
|
|
|
2022-05-09 11:29:25 +02:00
|
|
|
onMounted(() => {
|
|
|
|
window.addEventListener('resize', adjustListPosition);
|
2022-05-29 16:42:41 +02:00
|
|
|
window.addEventListener('wheel', handleWheelEvent);
|
|
|
|
|
2022-05-22 15:45:16 +02:00
|
|
|
nextTick(() => {
|
|
|
|
// fix position when the component is created and opened at the same time
|
|
|
|
if (isOpen.value) {
|
|
|
|
setTimeout(() => {
|
|
|
|
adjustListPosition();
|
|
|
|
}, 50);
|
|
|
|
}
|
|
|
|
});
|
2022-05-09 11:29:25 +02:00
|
|
|
});
|
|
|
|
onUnmounted(() => {
|
|
|
|
window.removeEventListener('resize', adjustListPosition);
|
2022-05-29 16:42:41 +02:00
|
|
|
window.removeEventListener('wheel', handleWheelEvent);
|
2022-05-09 11:29:25 +02:00
|
|
|
});
|
|
|
|
|
2022-05-08 09:44:52 +02:00
|
|
|
return {
|
|
|
|
el,
|
|
|
|
searchInput,
|
|
|
|
searchText,
|
|
|
|
searchInputStyle,
|
|
|
|
filteredOptions,
|
|
|
|
currentOptionLabel,
|
|
|
|
activate,
|
|
|
|
deactivate,
|
|
|
|
select,
|
|
|
|
isSelected,
|
2022-05-08 18:59:00 +02:00
|
|
|
keyArrows,
|
2022-05-08 09:44:52 +02:00
|
|
|
isOpen,
|
2022-05-29 16:42:41 +02:00
|
|
|
isMouseDown,
|
2022-05-08 18:59:00 +02:00
|
|
|
hightlightedIndex,
|
|
|
|
optionList,
|
2022-05-09 11:29:25 +02:00
|
|
|
optionRefs,
|
2022-05-29 16:42:41 +02:00
|
|
|
handleBlurEvent,
|
2022-06-14 20:02:17 +02:00
|
|
|
handleMouseUpEvent,
|
|
|
|
internalValue
|
2022-05-08 09:44:52 +02:00
|
|
|
};
|
|
|
|
}
|
|
|
|
});
|
|
|
|
</script>
|
|
|
|
|
|
|
|
<style lang="scss" scoped>
|
|
|
|
.select {
|
2022-06-10 20:02:26 +02:00
|
|
|
display: block;
|
|
|
|
|
|
|
|
&:focus,
|
|
|
|
&--open {
|
|
|
|
z-index: 10;
|
|
|
|
}
|
|
|
|
|
|
|
|
&__search-input {
|
|
|
|
appearance: none;
|
|
|
|
border: none;
|
|
|
|
background: transparent;
|
|
|
|
outline: none;
|
|
|
|
color: currentColor;
|
|
|
|
max-width: 100%;
|
|
|
|
width: 100%;
|
|
|
|
}
|
|
|
|
|
2022-08-05 17:03:16 +02:00
|
|
|
&__item-text {
|
|
|
|
overflow: hidden;
|
|
|
|
white-space: nowrap;
|
|
|
|
text-overflow: ellipsis;
|
|
|
|
}
|
|
|
|
|
2022-06-10 20:02:26 +02:00
|
|
|
&__list-wrapper {
|
|
|
|
cursor: pointer;
|
|
|
|
position: fixed;
|
|
|
|
display: block;
|
|
|
|
z-index: 5;
|
|
|
|
-webkit-overflow-scrolling: touch;
|
|
|
|
max-height: 240px;
|
|
|
|
overflow: auto;
|
|
|
|
left: 0;
|
|
|
|
top: 40px;
|
|
|
|
}
|
|
|
|
|
|
|
|
&__list {
|
|
|
|
list-style: none;
|
|
|
|
}
|
|
|
|
|
|
|
|
&__option {
|
|
|
|
&--disabled {
|
2022-05-10 10:29:38 +02:00
|
|
|
opacity: 0.6;
|
|
|
|
cursor: not-allowed;
|
2022-06-10 20:02:26 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
&--disabled {
|
|
|
|
opacity: 0.6;
|
|
|
|
cursor: not-allowed;
|
|
|
|
}
|
2022-05-08 09:44:52 +02:00
|
|
|
}
|
|
|
|
</style>
|