bootstrap-vue
Version:
With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens
199 lines (196 loc) • 5.14 kB
JavaScript
import Vue from '../../vue'
import { NAME_TAB } from '../../constants/components'
import { SLOT_NAME_TITLE } from '../../constants/slot-names'
import idMixin from '../../mixins/id'
import normalizeSlotMixin from '../../mixins/normalize-slot'
import BVTransition from '../../utils/bv-transition'
// @vue/component
export const BTab = /*#__PURE__*/ Vue.extend({
name: NAME_TAB,
mixins: [idMixin, normalizeSlotMixin],
inject: {
bvTabs: {
default: () => ({})
}
},
props: {
active: {
type: Boolean,
default: false
},
tag: {
type: String,
default: 'div'
},
buttonId: {
type: String
// default: ''
},
title: {
type: String,
default: ''
},
titleItemClass: {
// Sniffed by `<b-tabs>` and added to nav `li.nav-item`
type: [String, Array, Object]
// default: null
},
titleLinkClass: {
// Sniffed by `<b-tabs>` and added to nav `a.nav-link`
type: [String, Array, Object]
// default: null
},
titleLinkAttributes: {
type: Object
// default: null
},
disabled: {
type: Boolean,
default: false
},
noBody: {
type: Boolean,
default: false
},
lazy: {
type: Boolean,
default: false
}
},
data() {
return {
localActive: this.active && !this.disabled,
show: false
}
},
computed: {
tabClasses() {
return [
{
active: this.localActive,
disabled: this.disabled,
'card-body': this.bvTabs.card && !this.noBody
},
// Apply <b-tabs> `activeTabClass` styles when this tab is active
this.localActive ? this.bvTabs.activeTabClass : null
]
},
controlledBy() {
return this.buttonId || this.safeId('__BV_tab_button__')
},
computedNoFade() {
return !(this.bvTabs.fade || false)
},
computedLazy() {
return this.bvTabs.lazy || this.lazy
},
// For parent sniffing of child
_isTab() {
return true
}
},
watch: {
localActive(newValue) {
// Make `active` prop work with `.sync` modifier
this.$emit('update:active', newValue)
},
active(newValue, oldValue) {
if (newValue !== oldValue) {
if (newValue) {
// If activated post mount
this.activate()
} else {
/* istanbul ignore next */
if (!this.deactivate()) {
// Tab couldn't be deactivated, so we reset the synced active prop
// Deactivation will fail if no other tabs to activate
this.$emit('update:active', this.localActive)
}
}
}
},
disabled(newValue, oldValue) {
if (newValue !== oldValue) {
const { firstTab } = this.bvTabs
if (newValue && this.localActive && firstTab) {
this.localActive = false
firstTab()
}
}
}
},
mounted() {
// Inform b-tabs of our presence
this.registerTab()
// Initially show on mount if active and not disabled
this.show = this.localActive
},
updated() {
// Force the tab button content to update (since slots are not reactive)
// Only done if we have a title slot, as the title prop is reactive
const { updateButton } = this.bvTabs
if (updateButton && this.hasNormalizedSlot(SLOT_NAME_TITLE)) {
updateButton(this)
}
},
destroyed() {
// inform b-tabs of our departure
this.unregisterTab()
},
methods: {
// Private methods
registerTab() {
// Inform `<b-tabs>` of our presence
const { registerTab } = this.bvTabs
if (registerTab) {
registerTab(this)
}
},
unregisterTab() {
// Inform `<b-tabs>` of our departure
const { unregisterTab } = this.bvTabs
if (unregisterTab) {
unregisterTab(this)
}
},
// Public methods
activate() {
// Not inside a `<b-tabs>` component or tab is disabled
const { activateTab } = this.bvTabs
return activateTab && !this.disabled ? activateTab(this) : false
},
deactivate() {
// Not inside a `<b-tabs>` component or not active to begin with
const { deactivateTab } = this.bvTabs
return deactivateTab && this.localActive ? deactivateTab(this) : false
}
},
render(h) {
const { localActive } = this
const $content = h(
this.tag,
{
ref: 'panel',
staticClass: 'tab-pane',
class: this.tabClasses,
directives: [
{
name: 'show',
rawName: 'v-show',
value: localActive,
expression: 'localActive'
}
],
attrs: {
role: 'tabpanel',
id: this.safeId(),
'aria-hidden': localActive ? 'false' : 'true',
'aria-labelledby': this.controlledBy || null
}
},
// Render content lazily if requested
[localActive || !this.computedLazy ? this.normalizeSlot() : h()]
)
return h(BVTransition, { props: { mode: 'out-in', noFade: this.computedNoFade } }, [$content])
}
})