Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(tabs): Better handling of active tab and transitions #903

Merged
merged 14 commits into from
Aug 21, 2017
131 changes: 67 additions & 64 deletions docs/components/tabs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,71 +4,74 @@

```html
<template>
<div>
<!-- Tabs with card integration -->
<b-card no-body>
<b-tabs small card ref="tabs" v-model="tabIndex">
<b-tab title="General">
I'm the first fading tab
</b-tab>
<b-tab title="Edit profile">
I'm the second tab
<b-card>I'm the card in tab</b-card>
</b-tab>
<b-tab title="Premium Plan" disabled>
Sibzamini!
</b-tab>
</b-tabs>

</b-card>
<div>
<!-- Tabs with card integration -->
<b-card no-body>
<b-tabs small card ref="tabs" v-model="tabIndex">
<b-tab title="General">
I'm the first fading tab
</b-tab>
<b-tab title="Edit profile">
I'm the second tab
<b-card>I'm the card in tab</b-card>
</b-tab>
<b-tab title="Premium Plan" disabled>
Sibzamini!
</b-tab>
<b-tab title="Info">
I'm the last tab
</b-tab>
</b-tabs>

</b-card>

<!-- Control buttons-->
<div class="text-center">
<b-button-group class="mt-2">
<b-btn @click="tabIndex--">Previous</b-btn>
<b-btn @click="tabIndex++">Next</b-btn>
</b-button-group>
<br>
<span class="text-muted">Current Tab: {{tabIndex}}</span>
</div>

<br><br>

<b-card no-body>
<b-tabs card>
<!-- Render Tabs -->
<b-tab :title="`Tab ${i}`" v-for="i in tabs" :key="i">
Tab Contents {{i}}
<b-btn size="sm" variant="danger" class="float-right" @click="()=>closeTab(i)">
Close tab
</b-btn>
</b-tab>

<!-- Control buttons-->
<div class="text-center">
<b-button-group class="mt-2">
<b-btn @click="$refs.tabs.previousTab()">Previous</b-btn>
<b-btn @click="$refs.tabs.nextTab()">Next</b-btn>
</b-button-group>
<br>
<span class="text-muted">Current Tab: {{tabIndex}}</span>
</div>
<!-- Newtab Button (Using tabs slot) -->
<b-nav-item slot="tabs" @click.prevent="newTab" href="#">
+
</b-nav-item>

<br>
<br>

<b-card no-body>
<b-tabs card>
<!-- Render Tabs -->
<b-tab :title="`Tab ${i}`" v-for="i in tabs" :key="i">
Tab Contents {{i}}
<b-btn size="sm" variant="danger" class="float-right" @click="()=>closeTab(i)">Close tab
</b-btn>
</b-tab>

<!-- Newtab Button (Using tabs slot) -->
<b-nav-item slot="tabs" @click.prevent="newTab" href="#">
+
</b-nav-item>

<!-- Render this if no tabs -->
<div slot="empty" class="text-center text-muted">
There are no open tabs
<br> Open a new tab using + button.
</div>
</b-tabs>
</b-card>
<!-- Render this if no tabs -->
<div slot="empty" class="text-center text-muted">
There are no open tabs
<br> Open a new tab using + button.
</div>
</b-tabs>
</b-card>

</div>
</div>
</template>

<script>
export default {
data: {
tabIndex: null,
tabs: [],
tabCounter: 0
},
methods: {
closeTab(x) {
export default {
data: {
tabIndex: 0,
tabs: [],
tabCounter: 0
},
methods: {
closeTab(x) {
for (let i = 0; i < this.tabs.length; i++) {
if (this.tabs[i] === x) {
this.tabs.splice(i, 1);
Expand All @@ -78,11 +81,11 @@ export default {
newTab() {
this.tabs.push(this.tabCounter++);
}
}
}
}
</script>

<!-- tabs.vue -->
<!-- tabs-1.vue -->
```

### Basic usage
Expand All @@ -103,13 +106,13 @@ export default {

### Cards Integration

Tabs support integrating with bootstrap cards. Just add `card` property. Note
Tabs support integrating with bootstrap cards. Just add the `card` property. Note
that you should add `no-body` prop on `<b-card>` element in order to decorate header
and remove the extra badding
and remove the extra padding.

```html
<b-card no-body>
<b-tabs ref="tabs" v-model="tabIndex" card>
<b-tabs ref="tabs" card>
<b-tab title="Tab 1" active>
Tab Contents
</b-tab>
Expand Down
56 changes: 38 additions & 18 deletions lib/components/tab.vue
Original file line number Diff line number Diff line change
@@ -1,48 +1,72 @@
<template>
<transition @enter="enter" @before-leave="beforeLeave" mode="out-in">
<transition @before-enter="beforeEnter" @after-enter="afterEnter" @after-leave="afterLeave" mode="out-in">
<component :is="tag"
:id="id || null"
:id="safeId()"
role="tabpanel"
:class="['tab-pane', {show, fade, disabled, active: localActive}]"
:class="tabClasses"
:aria-hidden="localActive ? 'false' : 'true'"
:aria-expanded="localActive ? 'true' : 'false'"
:aria-lablelledby="controlledBy || null"
v-if="localActive || !lazy"
v-show="localActive || lazy"
v-if="localActive || !computedLazy"
v-show="localActive"
ref="panel"
:css="false"
>
<slot></slot>
</component>
</transition>
</template>

<script>
import { idMixin } from '../mixins';

export default {
mixins: [idMixin],
methods: {
enter() {
beforeEnter() {
this.show = false;
},
afterEnter() {
this.show = true;
},
beforeLeave() {
afterLeave() {
this.show = false;
}
},
data() {
return {
fade: false,
localActive: this.active,
lazy: true,
localActive: this.active && !this.disabled,
show: false
};
},
computed: {
tabClasses() {
return [
'tab-pane',
this.show ? 'show' : '',
this.computedFade ? 'fade' : '',
this.disabled ? 'disabled' : '',
this.localActive ? 'active' : ''
];
},
controlledBy() {
return this.buttonId || (this.id ? (this.id + '__BV_tab_button__') : null);
return this.buttonId || this.safeId('__BV_tab_button__');
},
computedFade() {
return this.$parent.fade;
},
computedLazy() {
return this.$parent.lazy;
},
_isTab() {
// For parent sniffing of child
return true;
}
},
props: {
id: {
type: String,
default: ''
active: {
type: Boolean,
default: false
},
tag: {
type: String,
Expand All @@ -64,10 +88,6 @@
type: Boolean,
default: false
},
active: {
type: Boolean,
default: false
},
href: {
type: String,
default: '#'
Expand Down
Loading