79 lines
1.9 KiB
Vue
79 lines
1.9 KiB
Vue
<script
|
|
setup
|
|
lang="ts"
|
|
>
|
|
defineProps({
|
|
show: { type: Boolean, required: true }
|
|
})
|
|
|
|
const beforeEnter = (element: Element) => {
|
|
const html_element = element as HTMLElement;
|
|
|
|
html_element.style.width = '0'
|
|
html_element.style.opacity = '0'
|
|
}
|
|
|
|
const enter = (element: Element) => {
|
|
const html_element = element as HTMLElement;
|
|
|
|
const w = html_element.scrollWidth
|
|
html_element.style.transition = 'width 0.25s ease, opacity 0.25s ease'
|
|
|
|
requestAnimationFrame(() => {
|
|
html_element.style.width = w + 'px'
|
|
html_element.style.opacity = '1'
|
|
})
|
|
}
|
|
|
|
const afterEnter = (element: Element) => {
|
|
const html_element = element as HTMLElement;
|
|
|
|
html_element.style.width = 'auto' // restore natural width
|
|
}
|
|
|
|
const beforeLeave = (element: Element) => {
|
|
const html_element = element as HTMLElement;
|
|
html_element.style.width = element.scrollWidth + 'px'
|
|
html_element.style.opacity = '1'
|
|
}
|
|
|
|
const leave = (element: Element) => {
|
|
const html_element = element as HTMLElement;
|
|
|
|
// force reflow
|
|
void html_element.offsetWidth
|
|
|
|
html_element.style.transition = 'width 0.25s ease, opacity 0.25s ease'
|
|
html_element.style.width = '0'
|
|
html_element.style.opacity = '0'
|
|
}
|
|
</script>
|
|
|
|
<template>
|
|
<transition
|
|
@before-enter="beforeEnter"
|
|
@enter="enter"
|
|
@after-enter="afterEnter"
|
|
@before-leave="beforeLeave"
|
|
@leave="leave"
|
|
>
|
|
<div
|
|
v-show="show"
|
|
class="h-slide"
|
|
>
|
|
<slot />
|
|
</div>
|
|
</transition>
|
|
</template>
|
|
|
|
|
|
|
|
<style scoped>
|
|
.h-slide {
|
|
overflow: hidden;
|
|
/* required for width transitions */
|
|
display: inline-block;
|
|
/* ensures width applies correctly */
|
|
}
|
|
</style>
|