Skip to content

Commit 9347e61

Browse files
committed
Enable transition animation
1 parent 45b7667 commit 9347e61

File tree

1 file changed

+31
-21
lines changed

1 file changed

+31
-21
lines changed

lib/components/popover.vue

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
<div>
33
<span ref="trigger"><slot></slot></span>
44

5-
<div tabindex="-1" :class="['popover',popoverAlignment]" ref="popover" @focus="$emit('focus')"
5+
<div tabindex="-1" class="popover fade" :class="[classState ? 'show' : '', popoverAlignment]" ref="popover" @focus="$emit('focus')"
66
@blur="$emit('blur')" :style="popoverStyle">
77
<div class="popover-arrow"></div>
88
<h3 class="popover-title" v-if="title" v-html="title"></h3>
@@ -20,13 +20,13 @@
2020
import Tether from 'tether';
2121
2222
// Controls which events are mapped for each named trigger, and the expected popover behavior for each.
23-
const triggerListeners = {
23+
const TRIGGER_LISTENERS = {
2424
click: {click: 'toggle'},
2525
hover: {mouseenter: 'show', mouseleave: 'hide'},
2626
focus: {focus: 'show', blur: 'hide'}
2727
};
2828
29-
const placementParams = {
29+
const PLACEMENT_PARAMS = {
3030
top: {
3131
attachment: 'bottom center',
3232
targetAttachment: 'top center'
@@ -46,6 +46,8 @@
4646
}
4747
};
4848
49+
const TRANSITION_DURATION = 150;
50+
4951
export default {
5052
props: {
5153
constraints: {
@@ -92,7 +94,7 @@
9294
type: String,
9395
default: 'top',
9496
validator(value) {
95-
return ['top', 'bottom', 'left', 'right'].indexOf(value) !== -1;
97+
return Object.keys(PLACEMENT_PARAMS).indexOf(value) !== -1;
9698
}
9799
},
98100
popoverStyle: {
@@ -115,9 +117,9 @@
115117
if (value === false || value === '') {
116118
return true;
117119
} else if (typeof value === 'string') {
118-
return Object.keys(triggerListeners).indexOf(value) !== -1;
120+
return Object.keys(TRIGGER_LISTENERS).indexOf(value) !== -1;
119121
} else if (Array.isArray(value)) {
120-
const keys = Object.keys(triggerListeners);
122+
const keys = Object.keys(TRIGGER_LISTENERS);
121123
value.forEach(item => {
122124
if (keys.indexOf(item) === -1) {
123125
return false;
@@ -133,6 +135,7 @@
133135
data() {
134136
return {
135137
triggerState: this.show,
138+
classState: this.show,
136139
lastEvent: null
137140
};
138141
},
@@ -226,7 +229,7 @@
226229
*/
227230
addListener(trigger) {
228231
// eslint-disable-next-line guard-for-in
229-
for (const item in triggerListeners[trigger]) {
232+
for (const item in TRIGGER_LISTENERS[trigger]) {
230233
this._trigger.addEventListener(item, e => this.eventHandler(e));
231234
}
232235
},
@@ -235,7 +238,7 @@
235238
* Tidy removal of Tether object from the DOM
236239
*/
237240
destroyTether() {
238-
if (this._tether) {
241+
if (this._tether && !this.showState) {
239242
this._tether.destroy();
240243
this._tether = null;
241244
}
@@ -253,10 +256,10 @@
253256
254257
// Look up the expected popover action for the event
255258
// eslint-disable-next-line guard-for-in
256-
for (const trigger in triggerListeners) {
257-
for (const event in triggerListeners[trigger]) {
259+
for (const trigger in TRIGGER_LISTENERS) {
260+
for (const event in TRIGGER_LISTENERS[trigger]) {
258261
if (event === e.type) {
259-
const action = triggerListeners[trigger][event];
262+
const action = TRIGGER_LISTENERS[trigger][event];
260263
261264
// If the expected event action is the opposite of the current state, allow it
262265
if (action === 'toggle' || (this.triggerState && action === 'hide') || (!this.triggerState && action === 'show')) {
@@ -293,17 +296,21 @@
293296
target: this._trigger,
294297
offset: this.offset,
295298
constraints: this.constraints,
296-
attachment: placementParams[this.placement].attachment,
297-
targetAttachment: placementParams[this.placement].targetAttachment
299+
attachment: PLACEMENT_PARAMS[this.placement].attachment,
300+
targetAttachment: PLACEMENT_PARAMS[this.placement].targetAttachment
298301
};
299302
},
300303
301304
/**
302305
* Hide popover and fire event
303306
*/
304307
hidePopover() {
305-
this._popover.style.display = 'none';
306-
this.destroyTether();
308+
this.classState = false;
309+
clearTimeout(this._timeout);
310+
this._timeout = setTimeout(() => {
311+
this._popover.style.display = 'none';
312+
this.destroyTether();
313+
}, TRANSITION_DURATION);
307314
},
308315
309316
/**
@@ -323,7 +330,7 @@
323330
*/
324331
removeListener(trigger) {
325332
// eslint-disable-next-line guard-for-in
326-
for (const item in triggerListeners[trigger]) {
333+
for (const item in TRIGGER_LISTENERS[trigger]) {
327334
this._trigger.removeEventListener(item, e => this.eventHandler(e));
328335
}
329336
},
@@ -341,15 +348,19 @@
341348
* Display popover and fire event
342349
*/
343350
showPopover() {
344-
// Just in case
345-
this.destroyTether();
351+
clearTimeout(this._timeout);
346352
347-
// Let tether do the magic, after element is shown
353+
if (!this._tether) {
354+
this._tether = new Tether(this.getTetherOptions());
355+
}
348356
this._popover.style.display = 'block';
349-
this._tether = new Tether(this.getTetherOptions());
350357
351358
// Make sure the popup is rendered in the correct location
352359
this.refreshPosition();
360+
361+
this.$nextTick(() => {
362+
this.classState = true;
363+
});
353364
},
354365
355366
/**
@@ -405,7 +416,6 @@
405416
// Configure tether
406417
this._trigger = this.$refs.trigger.children[0];
407418
this._popover = this.$refs.popover;
408-
this._popover.style.display = 'none';
409419
this._timeout = 0;
410420
411421
// Add listeners for specified triggers and complementary click event

0 commit comments

Comments
 (0)