vuetify
Version:
Vue.js 2 Semantic Component Framework
160 lines (136 loc) • 3.74 kB
text/typescript
// Components
import VWindow from './VWindow'
// Mixins
import Bootable from '../../mixins/bootable'
import { factory as GroupableFactory } from '../../mixins/groupable'
// Directives
import Touch from '../../directives/touch'
// Utilities
import { convertToUnit } from '../../util/helpers'
import { ExtractVue } from './../../util/mixins'
import mixins from '../../util/mixins'
// Types
import Vue from 'vue'
import { VNode, VNodeDirective } from 'vue/types'
type VBaseWindow = InstanceType<typeof VWindow>
interface options extends Vue {
windowGroup: VBaseWindow
}
export default mixins<options & ExtractVue<[typeof Bootable]>>(
Bootable,
GroupableFactory('windowGroup', 'v-window-item', 'v-window')
/* @vue/component */
).extend({
name: 'v-window-item',
directives: {
Touch
},
props: {
reverseTransition: {
type: [Boolean, String],
default: undefined
},
transition: {
type: [Boolean, String],
default: undefined
},
value: {
required: false
}
},
data () {
return {
done: null as null | (() => void),
isActive: false,
wasCancelled: false
}
},
computed: {
computedTransition (): string | boolean {
if (!this.windowGroup.internalReverse) {
return typeof this.transition !== 'undefined'
? this.transition || ''
: this.windowGroup.computedTransition
}
return typeof this.reverseTransition !== 'undefined'
? this.reverseTransition || ''
: this.windowGroup.computedTransition
}
},
mounted () {
this.$el.addEventListener('transitionend', this.onTransitionEnd, false)
},
beforeDestroy () {
this.$el.removeEventListener('transitionend', this.onTransitionEnd, false)
},
methods: {
genDefaultSlot () {
return this.$slots.default
},
onAfterEnter () {
if (this.wasCancelled) {
this.wasCancelled = false
return
}
requestAnimationFrame(() => {
this.windowGroup.internalHeight = undefined
this.windowGroup.isActive = false
})
},
onBeforeEnter () {
this.windowGroup.isActive = true
},
onLeave (el: HTMLElement) {
this.windowGroup.internalHeight = convertToUnit(el.clientHeight)
},
onEnterCancelled () {
this.wasCancelled = true
},
onEnter (el: HTMLElement, done: () => void) {
const isBooted = this.windowGroup.isBooted
if (isBooted) this.done = done
requestAnimationFrame(() => {
if (!this.computedTransition) return done()
this.windowGroup.internalHeight = convertToUnit(el.clientHeight)
// On initial render, there is no transition
// Vue leaves a `enter` transition class
// if done is called too fast
!isBooted && setTimeout(done, 100)
})
},
onTransitionEnd (e: TransitionEvent) {
// This ensures we only call done
// when the element transform
// completes
if (
e.propertyName !== 'transform' ||
e.target !== this.$el ||
!this.done
) return
this.done()
this.done = null
}
},
render (h): VNode {
const div = h('div', {
staticClass: 'v-window-item',
directives: [{
name: 'show',
value: this.isActive
}] as VNodeDirective[],
on: this.$listeners
}, this.showLazyContent(this.genDefaultSlot()))
return h('transition', {
props: {
name: this.computedTransition
},
on: {
afterEnter: this.onAfterEnter,
beforeEnter: this.onBeforeEnter,
leave: this.onLeave,
enter: this.onEnter,
enterCancelled: this.onEnterCancelled
}
}, [div])
}
})