Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Using transition @leave #83

Open
plexus77 opened this issue Sep 21, 2022 · 3 comments
Open

Using transition @leave #83

plexus77 opened this issue Sep 21, 2022 · 3 comments

Comments

@plexus77
Copy link

I am trying to implement a leave transition using the transition element like in your demo so that I can show and hide an element with nice transitions

I'm using Nuxt 3.0.0-rc.10 and @vueuse/motion 2.0.0-beta.22

Here is a simple example below.

<template>
  <div class="p-8">
    <div class="flex">
      <button class="px-2 py-4 mr-4 bg-blue-500 text-white" @click="toggle=true">
        Show
      </button>
      <button class="px-2 py-4 bg-blue-500 text-white" @click="toggle=false">
        Hide
      </button>
      <div>{{ toggle }}</div>
    </div>

    <transition
        :css="false"
        @leave="(_, done) => motions.transition.leave(done)"
    >
      <div
          v-if="toggle"

          v-motion="'transition'"
          :initial="{ opacity: 0, y: -200 }"
          :enter="{ opacity: 1, y: 0 }"
          :leave="{ opacity: 0, y: -200 }"

          style="width: 200px; height: 200px"
          class="m-6 bg-green-900"
      >
      </div>
    </transition>
  </div>
</template>
<script setup>
import { useMotions } from '@vueuse/motion'

const toggle = useState('toggle', () => false)

definePageMeta({
  layout: 'empty'
});

const motions = useMotions()
</script>

If I remove the element then it works as expected with the div animating in when I click show and then disappearing instantly by clicking hide.

I can't see what I am doing wrong here, if there is a bug or perhaps incompatability with the version I am using.

@plexus77
Copy link
Author

So I found a better way to achieve the animation without using the transition component.

<template>
  <div class="p-8">
    <div class="flex">
      <button class="px-2 py-4 mr-4 bg-blue-500 text-white" @click="toggle">
        Toggle
      </button>
      <div>{{ show }}</div>
    </div>
    <div
        v-if="show"

        v-motion="'transition'"
        :initial="{ opacity: 0, y: -200 }"
        :enter="{ opacity: 1, y: 0, transition: { duration: 500 } }"
        :leave="{ opacity: 0, y: -200, transition: { duration: 500 } }"

        style="width: 200px; height: 200px"
        class="m-6 bg-green-900"
    >
    </div>
  </div>
</template>
<script setup>
import { useMotions } from '@vueuse/motion'

definePageMeta({
  layout: 'empty'
});

const motions = useMotions()
const show = useState('show', () => false)
const toggle = () => {
  if (show.value) {
    motions.transition.leave(() => { show.value=false })
  } else {
    show.value=true
  }
}
</script>

@plexus77 plexus77 reopened this Sep 22, 2022
@SkyleLai
Copy link

SkyleLai commented Sep 23, 2022

I had same problem that motions.transition.leave doesn't work onLeave at transition component.

I create a component "Motionable" as a workaround based on your comment:

Motionable.vue

<template>
  <component :is="is" v-if="show || !leaved" v-motion="name">
    <slot />
  </component>
</template>

<script setup>
import { useMotions } from '@vueuse/motion'
const props = defineProps({
  is: { type: [String, Object], default: 'div' },
  name: { type: String, required: true },
  show: { type: Boolean, default: true },
})
const motions = useMotions()
const leaved = ref(!props.show)
watch(
  () => props.show,
  async (newShow) => {
    const motion = motions[props.name]
    if (motion && motion.isAnimating.value) {
      motion.stop('leave')
      if (newShow) {
        motion.apply('enter')
      }
    }
    if (!newShow) {
      leaved.value = false
      motion.leave(() => {
        leaved.value = true
      })
    }
  }
)
</script>

usage

<Motionable
  is="div"
  name="transition1"
  :show="show"
  :initial="{
    y: 300,
    opacity: 0,
  }"
  :enter="{
    y: 0,
    opacity: 1,
  }"
  :leave="{
    y: 300,
    opacity: 0,
  }"
>
  hello, world
</Motionable>

@productdevbook
Copy link

productdevbook commented Oct 8, 2022

yes same problem, nuxt 3

<script setup lang="ts">
import { useMotions } from '@vueuse/motion'
import { Teleport, toRefs } from 'vue'
const props = defineProps({
  visible: { type: Boolean, default: false },
})
const emit = defineEmits(['update:visible', 'close'])
const { visible } = toRefs(props)

const leaveTransition = async () => {
  const { windowTransition, overlayTransition } = useMotions()
  await Promise.all([
    overlayTransition.apply('leave'),
    windowTransition.apply('leave'),
  ])
}
const close = async () => {
  await leaveTransition()
  emit('close')
  emit('update:visible', false)
}
</script>

<template>
  <Teleport to="#dialog-outlet">
    <div v-if="visible" class="fixed z-[99999] h-screen w-screen">
      <div
        v-motion="'overlayTransition'"
        :initial="{
          opacity: 0,
        }"
        :enter="{
          opacity: 1,
        }"
        :leave="{ opacity: 0 }"
        class="fixed inset-0 bg-gray-500 bg-opacity-10 backdrop-blur-[3px] transition-opacity"
      />

      <div class="fixed inset-0 z-10 overflow-y-auto">
        <div
          class="flex min-h-full items-end justify-center p-4 text-center sm:items-center sm:p-0"
        >
          <div
            v-motion="'windowTransition'"
            :initial="{
              opacity: 0,
              scale: 0,
            }"
            :enter="{
              opacity: 1,
              scale: 1,
              transition: {
                type: 'keyframes',
                duration: 50,
              },
            }"
            :leave="{
              scale: 0.5,
              opacity: 0,
              transition: {
                duration: 100,
                type: 'keyframes',
                ease: 'easeInOut',
              },
            }"
            :delay="100"
            class="relative w-full transform overflow-hidden rounded-lg bg-white dark:bg-dark-400 px-4 pt-5 pb-4 text-left shadow-xl transition-all sm:my-8 sm:w-full sm:max-w-sm sm:p-6"
          >
            <div>
              <div class="text-left">
                <h3 id="modal-title" class="text-lg font-medium leading-6">
                  Change Color Site
                </h3>
                <slot />
              </div>
            </div>
            <div class="mt-5 sm:mt-6">
              <button
                type="button"
                class="inline-flex w-full justify-center rounded-md border border-transparent bg-red-600 px-4 py-2 text-base font-medium text-white shadow-sm hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-red-500 focus:ring-offset-2 sm:text-sm"
                @click="close"
              >
                Go back to
              </button>
            </div>
          </div>
        </div>
      </div>
    </div>
  </Teleport>
</template>

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants