138 lines
5.5 KiB
JavaScript
138 lines
5.5 KiB
JavaScript
Vue.component('tt-icon-select', {
|
|
props: {
|
|
options: {type: Array, required: true},
|
|
label: {type: String, default: null},
|
|
value: {type: [String, Array, Number, null], default: null},
|
|
multiple: {type: Boolean, default: false},
|
|
sm: {type: Boolean, default: false} // Added sm prop
|
|
},
|
|
data() {
|
|
return {
|
|
isOpen: false,
|
|
};
|
|
},
|
|
computed: {
|
|
internalValue: {
|
|
get() {
|
|
return this.multiple ? (Array.isArray(this.value) ? this.value : []) : this.value;
|
|
},
|
|
set(newValue) {
|
|
if (JSON.stringify(newValue) !== JSON.stringify(this.value)) {
|
|
this.$emit('input', newValue);
|
|
}
|
|
}
|
|
},
|
|
triggerDisplay() {
|
|
if (this.multiple) {
|
|
const count = this.internalValue.length;
|
|
if (count === 0) return { text: 'Auswählen...', isPlaceholder: true };
|
|
if (count === 1) {
|
|
const opt = this.options.find(o => o.value?.toString() === this.internalValue[0]?.toString());
|
|
return opt ? { icon: opt.icon, text: opt.text, isPlaceholder: false } : { text: '1 ausgewählt', isPlaceholder: false };
|
|
}
|
|
return { text: `${count} ausgewählt`, isPlaceholder: false };
|
|
} else {
|
|
const opt = this.options.find(o => o.value?.toString() === this.internalValue?.toString());
|
|
return opt ? { icon: opt.icon, text: opt.text, isPlaceholder: false } : { text: 'Auswählen...', isPlaceholder: true };
|
|
}
|
|
}
|
|
},
|
|
mounted() {
|
|
document.addEventListener('click', this.onClickOutside);
|
|
document.addEventListener('tt-select-open', this.handleGlobalOpen);
|
|
},
|
|
beforeDestroy() {
|
|
document.removeEventListener('click', this.onClickOutside);
|
|
document.removeEventListener('tt-select-open', this.handleGlobalOpen);
|
|
},
|
|
methods: {
|
|
toggleDropdown() {
|
|
if (!this.isOpen) {
|
|
// Dispatch event that this select is opening
|
|
document.dispatchEvent(new CustomEvent('tt-select-open', { detail: { id: this._uid } }));
|
|
}
|
|
this.isOpen = !this.isOpen;
|
|
},
|
|
onClickOutside(e) {
|
|
if (this.$el && !this.$el.contains(e.target)) {
|
|
this.isOpen = false;
|
|
}
|
|
},
|
|
handleGlobalOpen(event) {
|
|
if (event.detail.id !== this._uid) {
|
|
this.isOpen = false;
|
|
}
|
|
},
|
|
selectOption(option) {
|
|
const selectedVal = option ? option.value : null;
|
|
if (this.multiple) {
|
|
let currentValues = [...this.internalValue];
|
|
if (selectedVal === null) {
|
|
currentValues = [];
|
|
} else {
|
|
const index = currentValues.findIndex(v => v?.toString() === selectedVal?.toString());
|
|
if (index > -1) {
|
|
currentValues.splice(index, 1);
|
|
} else {
|
|
currentValues.push(selectedVal);
|
|
}
|
|
}
|
|
this.internalValue = currentValues;
|
|
} else {
|
|
this.internalValue = selectedVal;
|
|
this.isOpen = false;
|
|
}
|
|
},
|
|
isSelected(option) {
|
|
const checkVal = option ? option.value : null;
|
|
if (this.multiple) {
|
|
if (checkVal === null) return this.internalValue.length === 0;
|
|
return this.internalValue.some(v => v?.toString() === checkVal?.toString());
|
|
} else {
|
|
return this.internalValue?.toString() === checkVal?.toString();
|
|
}
|
|
}
|
|
},
|
|
template: `
|
|
<div class="tt-icon-select-modern">
|
|
<button type="button" class="tt-select-trigger"
|
|
:class="{ 'open': isOpen, 'sm': sm }"
|
|
@click.stop="toggleDropdown">
|
|
<span class="trigger-text" :class="{'placeholder': triggerDisplay.isPlaceholder}">
|
|
<i v-if="triggerDisplay.icon" :class="triggerDisplay.icon"></i>
|
|
<span>{{ triggerDisplay.text }}</span>
|
|
</span>
|
|
<i class="fas fa-chevron-down trigger-arrow"></i>
|
|
</button>
|
|
|
|
<div class="tt-select-dropdown" :class="{ show: isOpen }" @click.stop>
|
|
<div class="dropdown-header">
|
|
<span>{{ label || 'Auswählen' }}</span>
|
|
<button type="button" class="close-btn" @click="toggleDropdown">×</button>
|
|
</div>
|
|
|
|
<ul class="options-list">
|
|
<li class="option-item"
|
|
:class="{ 'selected': isSelected(null) }"
|
|
@click="selectOption(null)">
|
|
<div class="option-label">
|
|
<i class="fas fa-ban"></i> <span>{{ multiple ? 'Alle abwählen' : 'Alle' }}</span>
|
|
</div>
|
|
<i v-if="isSelected(null)" class="fas fa-check option-checkmark"></i>
|
|
</li>
|
|
|
|
<li v-for="opt in options" :key="opt.value"
|
|
class="option-item"
|
|
:class="{ 'selected': isSelected(opt) }"
|
|
@click="selectOption(opt)">
|
|
<div class="option-label">
|
|
<i :class="opt.icon"></i>
|
|
<span>{{ opt.text }}</span>
|
|
</div>
|
|
<i v-if="isSelected(opt)" class="fas fa-check option-checkmark"></i>
|
|
</li>
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
`
|
|
}); |