<template> <component v-if="!asChild" :is="as" v-ripple :class="cx('root')" @click="onClick" v-bind="attrs"> <slot></slot> </component> <slot v-else :class="cx('root')" :active="active" :a11yAttrs="a11yAttrs" :onClick="onClick"></slot> </template> <script> import Ripple from 'primevue/ripple'; import { DomHandler, ObjectUtils } from 'primevue/utils'; import { mergeProps } from 'vue'; import BaseTab from './BaseTab.vue'; export default { name: 'Tab', extends: BaseTab, inheritAttrs: false, inject: ['$pcTabs', '$pcTabList'], methods: { onFocus() { this.$pcTabs.selectOnFocus && this.changeActiveValue(); }, onClick() { this.changeActiveValue(); }, onKeydown(event) { switch (event.code) { case 'ArrowRight': this.onArrowRightKey(event); break; case 'ArrowLeft': this.onArrowLeftKey(event); break; case 'Home': this.onHomeKey(event); break; case 'End': this.onEndKey(event); break; case 'PageDown': this.onPageDownKey(event); break; case 'PageUp': this.onPageUpKey(event); break; case 'Enter': case 'NumpadEnter': case 'Space': this.onEnterKey(event); break; default: break; } }, onArrowRightKey(event) { const nextTab = this.findNextTab(event.currentTarget); nextTab ? this.changeFocusedTab(event, nextTab) : this.onHomeKey(event); event.preventDefault(); }, onArrowLeftKey(event) { const prevTab = this.findPrevTab(event.currentTarget); prevTab ? this.changeFocusedTab(event, prevTab) : this.onEndKey(event); event.preventDefault(); }, onHomeKey(event) { const firstTab = this.findFirstTab(); this.changeFocusedTab(event, firstTab); event.preventDefault(); }, onEndKey(event) { const lastTab = this.findLastTab(); this.changeFocusedTab(event, lastTab); event.preventDefault(); }, onPageDownKey(event) { this.scrollInView(this.findLastTab()); event.preventDefault(); }, onPageUpKey(event) { this.scrollInView(this.findFirstTab()); event.preventDefault(); }, onEnterKey(event) { this.changeActiveValue(); event.preventDefault(); }, findNextTab(tabElement, selfCheck = false) { const element = selfCheck ? tabElement : tabElement.nextElementSibling; return element ? (DomHandler.getAttribute(element, 'data-p-disabled') || DomHandler.getAttribute(element, 'data-pc-section') === 'inkbar' ? this.findNextTab(element) : DomHandler.findSingle(element, '[data-pc-name="tab"]')) : null; }, findPrevTab(tabElement, selfCheck = false) { const element = selfCheck ? tabElement : tabElement.previousElementSibling; return element ? (DomHandler.getAttribute(element, 'data-p-disabled') || DomHandler.getAttribute(element, 'data-pc-section') === 'inkbar' ? this.findPrevTab(element) : DomHandler.findSingle(element, '[data-pc-name="tab"]')) : null; }, findFirstTab() { return this.findNextTab(this.$pcTabList.$refs.content.firstElementChild, true); }, findLastTab() { return this.findPrevTab(this.$pcTabList.$refs.content.lastElementChild, true); }, changeActiveValue() { this.$pcTabs.updateValue(this.value); }, changeFocusedTab(event, element) { DomHandler.focus(element); this.scrollInView(element); }, scrollInView(element) { element?.scrollIntoView?.({ block: 'nearest' }); } }, computed: { active() { return ObjectUtils.equals(this.$pcTabs?.d_value, this.value); }, id() { return `${this.$pcTabs?.id}_tab_${this.value}`; }, ariaControls() { return `${this.$pcTabs?.id}_tabpanel_${this.value}`; }, attrs() { return mergeProps(this.asAttrs, this.a11yAttrs, this.ptmi('root', this.ptParams)); }, asAttrs() { return this.as === 'BUTTON' ? { type: 'button', disabled: this.disabled } : undefined; }, a11yAttrs() { return { id: this.id, tabindex: this.active ? this.$pcTabs.tabindex : -1, role: 'tab', 'aria-selected': this.active, 'aria-controls': this.ariaControls, 'data-pc-name': 'tab', 'data-p-disabled': this.disabled, 'data-p-active': this.active, onFocus: this.onFocus, onKeydown: this.onKeydown }; }, ptParams() { return { context: { active: this.active } }; } }, directives: { ripple: Ripple } }; </script>