<template>
  <div class="cpTransitionCounter">
    <transition :duration="resolvedDuration" mode="out-in" :name="formattedTransitionName">
      <span :key="counterNumber">
        <slot />
      </span>
    </transition>
  </div>
</template>

<script setup lang="ts">
import { computed, ref, watch } from 'vue'

import { useReducedMotion } from '@/composables/useReducedMotion'

interface Props {
  counterNumber?: number
  duration?: number
}

const props = withDefaults(defineProps<Props>(), {
  counterNumber: 0,
  duration: 300,
})

enum Directions {
  UP = 'up',
  DOWN = 'down',
}

const direction = ref<Directions>(Directions.UP)

const formattedTransitionName = computed(() => `counter-${direction.value}`)

const prefersReducedMotion = useReducedMotion()
const resolvedDuration = computed(() => (prefersReducedMotion.value ? 0 : props.duration))

watch(
  () => props.counterNumber,
  (newValue: number, oldValue: number) => {
    direction.value = newValue < oldValue ? Directions.DOWN : Directions.UP
  },
)
</script>

<style lang="scss">
.cpTransitionCounter {
  display: inline-flex;
  overflow: hidden;

  .counter-up-enter-from {
    transform: translate3d(0, 100%, 0);
  }

  .counter-down-enter-from {
    transform: translate3d(0, -100%, 0);
  }

  .counter-up-leave-to,
  .counter-down-leave-to {
    filter: blur(1px);
    opacity: 0;
  }

  .counter-up-leave-to {
    transform: translate3d(0, -100%, 0) skewY(-30deg);
  }

  .counter-down-leave-to {
    transform: translate3d(0, 100%, 0) skewY(30deg);
  }

  .counter-up-enter-active,
  .counter-down-enter-active,
  .counter-up-leave-active,
  .counter-down-leave-active {
    transition:
      transform 200ms ease,
      opacity 200ms ease;
  }
}
</style>
