Skip to content

Commit

Permalink
feat(collapse): apply bootstrap classes during transition stages (issue
Browse files Browse the repository at this point in the history
#565) (#707)

* Update collapse.vue

* Update toggle.js

* Update collapse.spec.js

* [collapse] document show, shown, hide, hidden events

* Update meta.json
  • Loading branch information
tmorehouse committed Jul 19, 2017
1 parent 721292c commit 947d253
Show file tree
Hide file tree
Showing 4 changed files with 112 additions and 65 deletions.
38 changes: 25 additions & 13 deletions __tests__/components/collapse.spec.js
@@ -1,4 +1,4 @@
import {loadFixture, testVM, setData, nextTick} from '../helpers'; import {loadFixture, testVM, setData, nextTick, sleep} from '../helpers';


describe('collapse', async() => { describe('collapse', async() => {
beforeEach(loadFixture('collapse')); beforeEach(loadFixture('collapse'));
Expand Down Expand Up @@ -139,32 +139,44 @@ describe('collapse', async() => {
const btn3 = $refs.accordion_3_btn const btn3 = $refs.accordion_3_btn
const col3 = $refs.accordion_3 const col3 = $refs.accordion_3


expect(col1.$el.classList.contains('show')).toBe(true)
expect(btn1.$el.getAttribute('aria-expanded')).toBe('true') expect(btn1.$el.getAttribute('aria-expanded')).toBe('true')
expect(col2.$el.classList.contains('show')).toBe(false)
expect(btn2.$el.getAttribute('aria-expanded')).toBe('false') expect(btn2.$el.getAttribute('aria-expanded')).toBe('false')
expect(col3.$el.classList.contains('show')).toBe(false)
expect(btn3.$el.getAttribute('aria-expanded')).toBe('false') expect(btn3.$el.getAttribute('aria-expanded')).toBe('false')


btn2.$el.click(); expect(col1.show).toBe(true)
expect(col2.show).toBe(false)
expect(col3.show).toBe(false)

// Open pane 2 and close others
btn2.$el.click()
await nextTick() await nextTick()


expect(col1.$el.classList.contains('show')).toBe(false)
expect(btn1.$el.getAttribute('aria-expanded')).toBe('false') expect(btn1.$el.getAttribute('aria-expanded')).toBe('false')
expect(col2.$el.classList.contains('show')).toBe(true)
expect(btn2.$el.getAttribute('aria-expanded')).toBe('true') expect(btn2.$el.getAttribute('aria-expanded')).toBe('true')
expect(col3.$el.classList.contains('show')).toBe(false)
expect(btn3.$el.getAttribute('aria-expanded')).toBe('false') expect(btn3.$el.getAttribute('aria-expanded')).toBe('false')


btn2.$el.click(); await nextTick()

expect(col1.show).toBe(false)
expect(col2.show).toBe(true)
expect(col3.show).toBe(false)

await nextTick()

// Close all accordion panes
btn2.$el.click()
await nextTick() await nextTick()


expect(col1.$el.classList.contains('show')).toBe(false)
expect(btn1.$el.getAttribute('aria-expanded')).toBe('false') expect(btn1.$el.getAttribute('aria-expanded')).toBe('false')
expect(col2.$el.classList.contains('show')).toBe(false)
expect(btn2.$el.getAttribute('aria-expanded')).toBe('false') expect(btn2.$el.getAttribute('aria-expanded')).toBe('false')
expect(col3.$el.classList.contains('show')).toBe(false)
expect(btn3.$el.getAttribute('aria-expanded')).toBe('false') expect(btn3.$el.getAttribute('aria-expanded')).toBe('false')

await nextTick()

expect(col1.show).toBe(false)
expect(col2.show).toBe(false)
expect(col3.show).toBe(false)

}) })


}); });
16 changes: 16 additions & 0 deletions docs/components/collapse/meta.json
Expand Up @@ -2,6 +2,22 @@
"title": "Collapse", "title": "Collapse",
"component": "bCollapse", "component": "bCollapse",
"events": [ "events": [
{
"event": "show",
"description": "emitted when collaspe has started to open"
},
{
"event": "shown",
"description": "emitted when collaspe has finised opening"
},
{
"event": "hide",
"description": "emitted when collaspe has started to close"
},
{
"event": "hidden",
"description": "emitted when collaspe has finished closing"
},
{ {
"event": "collapse::toggle", "event": "collapse::toggle",
"description": "toggles visible state of collaspe when this event emits on $root", "description": "toggles visible state of collaspe when this event emits on $root",
Expand Down
116 changes: 64 additions & 52 deletions lib/components/collapse.vue
@@ -1,63 +1,46 @@
<template> <template>
<transition <transition
@enter="enter" enter-class=""
@after-enter="clearHeight" enter-active-class="collapsing"
@leave="leave" enter-to-class=""
@after-leave="clearHeight" leave-class=""
name="collapse" leave-active-class="collapsing"
leave-to-class=""
@enter="onEnter"
@after-enter="onAfterEnter"
@leave="onLeave"
@after-leave="onAfterLeave"
> >
<div :id="id || null" :class="classObject" v-show="show"> <div :id="id || null" :class="classObject" v-show="show">
<slot></slot> <slot></slot>
</div> </div>
</transition> </transition>
</template> </template>


<style scoped>
.collapse-enter-active, .collapse-leave-active {
transition: all .35s ease;
overflow: hidden;
}
</style>

<script> <script>
import { listenOnRootMixin } from '../mixins'; import { listenOnRootMixin } from '../mixins';
export default { export default {
mixins: [listenOnRootMixin], mixins: [listenOnRootMixin],
data() { data() {
return { return {
show: this.visible show: this.visible,
transitioning: false
}; };
}, },
computed: {
classObject() {
return {
'navbar-collapse': this.isNav,
show: this.show
};
}
},
model: { model: {
prop: 'visible', prop: 'visible',
event: 'input' event: 'input'
}, },
watch: {
visible(newVal) {
if (newVal !== this.show) {
this.show = newVal;
this.emitState();
}
},
},
props: { props: {
isNav: {
type: Boolean,
default: false
},
id: { id: {
type: String, type: String,
required: true required: true
}, },
isNav: {
type: Boolean,
default: false
},
accordion: { accordion: {
type: String, type: String,
default: null default: null
Expand All @@ -67,33 +50,60 @@
default: false default: false
} }
}, },
watch: {
visible(newVal) {
if (newVal !== this.show) {
this.show = newVal;
}
},
show(newVal, oldVal) {
if (newVal !== oldVal) {
this.emitState();
}
}
},
computed: {
classObject() {
return {
'navbar-collapse': this.isNav,
'collapse': !this.transitioning,
'show': this.show && !this.transitioning
};
}
},
methods: { methods: {
toggle() { toggle() {
this.show = !this.show; this.show = !this.show;
this.emitState();
}, },
enter(el) { onEnter(el) {
el.style.height = 'auto'; el.style.height = 0;
const realHeight = getComputedStyle(el).height; this.reflow(el);
el.style.height = '0px'; el.style.height = el.scrollHeight + 'px';
this.transitioning = true;
/* eslint-disable no-unused-expressions */ this.$emit('show');
el.offsetHeight; // Force repaint
el.style.height = realHeight;
}, },
leave(el) { onAfterEnter(el) {
el.style.height = null;
this.transitioning = false;
this.$emit('shown');
},
onLeave(el) {
el.style.height = 'auto'; el.style.height = 'auto';
const realHeight = getComputedStyle(el).height; el.style.display = 'block';
el.style.height = realHeight; el.style.height = el.getBoundingClientRect().height + 'px';
this.reflow(el);
/* eslint-disable no-unused-expressions */ this.transitioning = true;
el.offsetHeight; // Force repaint el.style.height = 0;
this.$emit('hide');
el.style.height = '0px';
}, },
clearHeight(el) { onAfterLeave(el) {
el.style.height = null; el.style.height = null;
this.transitioning = false;
this.$emit('hidden');
},
reflow(el) {
/* eslint-disable no-unused-expressions */
el.offsetHeight; // Force repaint
}, },
emitState() { emitState() {
this.$emit('input', this.show); this.$emit('input', this.show);
Expand All @@ -114,10 +124,12 @@
return; return;
} }
if (openedId === this.id) { if (openedId === this.id) {
// Open this collapse if not shown
if (!this.show) { if (!this.show) {
this.toggle(); this.toggle();
} }
} else { } else {
// Close this collapse if shown
if (this.show) { if (this.show) {
this.toggle(); this.toggle();
} }
Expand Down
7 changes: 7 additions & 0 deletions lib/directives/toggle.js
Expand Up @@ -28,7 +28,14 @@ export default {
// Toggle state hadnler, stored on element // Toggle state hadnler, stored on element
el[BVT] = function toggleDirectiveHandler(id, state) { el[BVT] = function toggleDirectiveHandler(id, state) {
if (targets.indexOf(id) !== -1) { if (targets.indexOf(id) !== -1) {
// Set aria-expanded state
el.setAttribute('aria-expanded', state ? 'true' : 'false'); el.setAttribute('aria-expanded', state ? 'true' : 'false');
// Set 'collapsed' class state
if (state) {
el.classList.remove('collapsed');
} else {
el.classList.add('collapsed');
}
} }
}; };


Expand Down

0 comments on commit 947d253

Please sign in to comment.