diff --git a/packages/radix-vue/src/Dialog/DialogContentImpl.vue b/packages/radix-vue/src/Dialog/DialogContentImpl.vue index ccd1246f7..e472f8071 100644 --- a/packages/radix-vue/src/Dialog/DialogContentImpl.vue +++ b/packages/radix-vue/src/Dialog/DialogContentImpl.vue @@ -15,7 +15,7 @@ export type DialogContentImplEmits = DismissableLayerEmits & { * Event handler called when auto-focusing on close. * Can be prevented. */ - 'closeAutoFocus': [ event: Event] + 'closeAutoFocus': [event: Event] } export interface DialogContentImplProps extends DismissableLayerProps { diff --git a/packages/radix-vue/src/Presence/usePresence.ts b/packages/radix-vue/src/Presence/usePresence.ts index b421bfc2c..af9fc8c69 100644 --- a/packages/radix-vue/src/Presence/usePresence.ts +++ b/packages/radix-vue/src/Presence/usePresence.ts @@ -23,6 +23,11 @@ export function usePresence( }, }) + const dispatchCustomEvent = (name: 'enter' | 'after-enter' | 'leave' | 'after-leave') => { + const customEvent = new CustomEvent(name, { bubbles: false, cancelable: false }) + node.value?.dispatchEvent(customEvent) + } + watch( present, async (currentPresent, prevPresent) => { @@ -34,6 +39,9 @@ export function usePresence( if (currentPresent) { dispatch('MOUNT') + dispatchCustomEvent('enter') + if (currentAnimationName === 'none') + dispatchCustomEvent('after-enter') } else if ( currentAnimationName === 'none' @@ -42,6 +50,8 @@ export function usePresence( // If there is no exit animation or the element is hidden, animations won't run // so we unmount instantly rv dispatch('UNMOUNT') + dispatchCustomEvent('leave') + dispatchCustomEvent('after-leave') } else { /** @@ -51,9 +61,14 @@ export function usePresence( * fires after `animation-delay` has expired which would be too late. */ const isAnimating = prevAnimationName !== currentAnimationName - if (prevPresent && isAnimating) + if (prevPresent && isAnimating) { dispatch('ANIMATION_OUT') - else dispatch('UNMOUNT') + dispatchCustomEvent('leave') + } + else { + dispatch('UNMOUNT') + dispatchCustomEvent('after-leave') + } } } }, @@ -70,8 +85,11 @@ export function usePresence( const isCurrentAnimation = currentAnimationName.includes( event.animationName, ) - if (event.target === node.value && isCurrentAnimation) + const directionName = state.value === 'mounted' ? 'enter' : 'leave' + if (event.target === node.value && isCurrentAnimation) { + dispatchCustomEvent(`after-${directionName}`) dispatch('ANIMATION_END') + } // if no animation, immediately trigger 'ANIMATION_END' if (event.target === node.value && currentAnimationName === 'none') dispatch('ANIMATION_END')