<template>
  <transition
      name="expand"
      @enter="enter"
      @leave="leave"
      @enter-cancel="cancel"
      @leave-cancel="cancel">
    <slot></slot>
  </transition>
</template>

<script>

  import TWEEN from '@tweenjs/tween.js';
  import { useGlobalTweenGroup } from "../lib/useGlobalTweenGroup";

  export default {
    props: {
      expandTime: {
        type: Number,
        default: 250
      }
    },

    data() {
      return {
        animation: null
      }
    },

    methods: {
      cancel () {
        if (this.animation) {
          this.animation.stop();
          this.animation = null;
        }
      },

      enter(element, done) {
        const width = parseInt(getComputedStyle(element).width);
        const paddingTop = parseInt(getComputedStyle(element).paddingTop);
        const paddingBottom = parseInt(getComputedStyle(element).paddingBottom);

        element.style.width = width;
        element.style.position = 'absolute';
        element.style.visibility = 'hidden';
        element.style.height = 'auto';

        const height = parseInt(getComputedStyle(element).height);

        element.style.width = null;
        element.style.position = null;
        element.style.visibility = null;
        element.style.overflow = 'hidden';
        element.style.height = 0;

        this.animation = new TWEEN.Tween({height: 0, paddingTop: 0, paddingBottom: 0})
          .to({height: height, paddingTop: paddingTop, paddingBottom: paddingBottom}, this.expandTime)
          .onUpdate(obj => {
            element.style.height = obj.height + "px";
            element.style.paddingBottom = obj.paddingBottom + "px";
            element.style.paddingTop = obj.paddingTop + "px";
          })
          .onComplete(() => {
            this.animation = null;
            element.removeAttribute('style');
            element.style.opacity = 0.99;
            setTimeout(() => {
              // Fixes odd drawing bug in Chrome
              element.style.opacity = 1.0;
            }, 1000);
            done();
          })
          .group(useGlobalTweenGroup())
          .start();
      },

      leave(element, done) {
        const height = parseInt(getComputedStyle(element).height);
        const paddingTop = parseInt(getComputedStyle(element).paddingTop);
        const paddingBottom = parseInt(getComputedStyle(element).paddingBottom);

        element.style.overflow = 'hidden';

        this.animation = new TWEEN.Tween({height: height, paddingTop: paddingTop, paddingBottom: paddingBottom})
          .to({height: 0, paddingTop: 0, paddingBottom: 0}, this.expandTime)
          .onUpdate(obj => {
            element.style.height = obj.height + "px";
            element.style.paddingBottom = obj.paddingBottom + "px";
            element.style.paddingTop = obj.paddingTop + "px";
          })
          .onComplete(() => {
            this.animation = null;
            element.removeAttribute('style');
            done();
          })
          .group(useGlobalTweenGroup())
          .start();
      }
    }
  }

</script>

<style scoped>
  * {
    will-change: height;
    transform: translateZ(0);
    backface-visibility: hidden;
    perspective: 1000px;
  }
</style>