149 lines
4.8 KiB
Vue
Executable File
149 lines
4.8 KiB
Vue
Executable File
<template>
|
|
<div class="p-accordion p-component">
|
|
<div v-for="(tab,i) of tabs" :key="getKey(tab,i)" :class="getTabClass(i)">
|
|
<div :class="getTabHeaderClass(tab, i)">
|
|
<a role="tab" class="p-accordion-header-link" @click="onTabClick($event, tab, i)" @keydown="onTabKeydown($event, tab, i)" :tabindex="isTabDisabled(tab) ? null : '0'"
|
|
:aria-expanded="isTabActive(i)" :id="getTabAriaId(i) + '_header'" :aria-controls="getTabAriaId(i) + '_content'">
|
|
<span :class="getHeaderIcon(i)"></span>
|
|
<span class="p-accordion-header-text" v-if="tab.props?.header">{{tab.props?.header}}</span>
|
|
<component :is="tab.children.header" v-if="tab.children?.header"></component>
|
|
</a>
|
|
</div>
|
|
<transition name="p-toggleable-content">
|
|
<div class="p-toggleable-content" v-show="isTabActive(i)"
|
|
role="region" :id="getTabAriaId(i) + '_content'" :aria-labelledby="getTabAriaId(i) + '_header'">
|
|
<div class="p-accordion-content">
|
|
<component :is="tab"></component>
|
|
</div>
|
|
</div>
|
|
</transition>
|
|
</div>
|
|
</div>
|
|
</template>
|
|
|
|
<script>
|
|
import UniqueComponentId from '../utils/UniqueComponentId';
|
|
|
|
export default {
|
|
emits: ['tab-close', 'tab-open', 'update:activeIndex'],
|
|
props: {
|
|
multiple: Boolean,
|
|
activeIndex: [Number,Array]
|
|
},
|
|
data() {
|
|
return {
|
|
d_activeIndex: this.activeIndex
|
|
}
|
|
},
|
|
watch: {
|
|
activeIndex(newValue) {
|
|
this.d_activeIndex = newValue;
|
|
}
|
|
},
|
|
methods: {
|
|
onTabClick(event, tab, i) {
|
|
if (!this.isTabDisabled(tab)) {
|
|
const active = this.isTabActive(i);
|
|
const eventName = active ? 'tab-close' : 'tab-open';
|
|
|
|
if (this.multiple) {
|
|
if (active) {
|
|
this.d_activeIndex = this.d_activeIndex.filter(index => index !== i);
|
|
}
|
|
else {
|
|
if (this.d_activeIndex)
|
|
this.d_activeIndex.push(i);
|
|
else
|
|
this.d_activeIndex = [i];
|
|
}
|
|
}
|
|
else {
|
|
this.d_activeIndex = this.d_activeIndex === i ? null : i;
|
|
}
|
|
|
|
this.$emit('update:activeIndex', this.d_activeIndex);
|
|
|
|
this.$emit(eventName, {
|
|
originalEvent: event,
|
|
index: i
|
|
});
|
|
}
|
|
},
|
|
onTabKeydown(event, tab, i) {
|
|
if (event.which === 13) {
|
|
this.onTabClick(event, i);
|
|
}
|
|
},
|
|
isTabActive(index) {
|
|
if (this.multiple)
|
|
return this.d_activeIndex && this.d_activeIndex.includes(index);
|
|
else
|
|
return index === this.d_activeIndex;
|
|
},
|
|
getKey(tab, i) {
|
|
return tab.props?.header ? tab.props.header : i;
|
|
},
|
|
isTabDisabled(tab) {
|
|
return tab.props?.disabled;
|
|
},
|
|
getTabClass(i) {
|
|
return ['p-accordion-tab', {'p-accordion-tab-active': this.isTabActive(i)}];
|
|
},
|
|
getTabHeaderClass(tab, i) {
|
|
return ['p-accordion-header', {'p-highlight': this.isTabActive(i), 'p-disabled': this.isTabDisabled(tab)}];
|
|
},
|
|
getTabAriaId(i) {
|
|
return this.ariaId + + '_' + i;
|
|
},
|
|
getHeaderIcon(i) {
|
|
const active = this.isTabActive(i);
|
|
return ['p-accordion-toggle-icon pi', {'pi-chevron-right': !active, 'pi-chevron-down': active}];
|
|
},
|
|
isAccordionTab(child) {
|
|
return child.type.name === 'accordiontab'
|
|
}
|
|
},
|
|
computed: {
|
|
tabs() {
|
|
const tabs = []
|
|
this.$slots.default().forEach(child => {
|
|
if (this.isAccordionTab(child)) {
|
|
tabs.push(child);
|
|
}
|
|
else if (child.children.length > 0) {
|
|
child.children.forEach(nestedChild => {
|
|
if (this.isAccordionTab(nestedChild)) {
|
|
tabs.push(nestedChild)
|
|
}
|
|
});
|
|
}
|
|
}
|
|
)
|
|
return tabs;
|
|
},
|
|
ariaId() {
|
|
return UniqueComponentId();
|
|
}
|
|
}
|
|
}
|
|
</script>
|
|
|
|
<style>
|
|
.p-accordion-header-link {
|
|
cursor: pointer;
|
|
display: flex;
|
|
align-items: center;
|
|
user-select: none;
|
|
position: relative;
|
|
text-decoration: none;
|
|
}
|
|
|
|
.p-accordion-header-link:focus {
|
|
z-index: 1;
|
|
}
|
|
|
|
.p-accordion-header-text {
|
|
line-height: 1;
|
|
}
|
|
</style>
|