From fec12d7dccc573c016ee2d8e1fa2b67f134c2786 Mon Sep 17 00:00:00 2001 From: Kael Date: Wed, 11 May 2022 11:56:57 +1000 Subject: [PATCH] fix(runtime-core): transition hooks can be arrays of functions (#5177) --- .../src/components/BaseTransition.ts | 57 +++++++++++-------- 1 file changed, 33 insertions(+), 24 deletions(-) diff --git a/packages/runtime-core/src/components/BaseTransition.ts b/packages/runtime-core/src/components/BaseTransition.ts index 64249f8c..53c3e853 100644 --- a/packages/runtime-core/src/components/BaseTransition.ts +++ b/packages/runtime-core/src/components/BaseTransition.ts @@ -16,10 +16,12 @@ import { warn } from '../warning' import { isKeepAlive } from './KeepAlive' import { toRaw } from '@vue/reactivity' import { callWithAsyncErrorHandling, ErrorCodes } from '../errorHandling' -import { ShapeFlags, PatchFlags } from '@vue/shared' +import { ShapeFlags, PatchFlags, isArray } from '@vue/shared' import { onBeforeUnmount, onMounted } from '../apiLifecycle' import { RendererElement } from '../renderer' +type Hook void> = T | T[] + export interface BaseTransitionProps { mode?: 'in-out' | 'out-in' | 'default' appear?: boolean @@ -34,20 +36,20 @@ export interface BaseTransitionProps { // Hooks. Using camel case for easier usage in render functions & JSX. // In templates these can be written as @before-enter="xxx" as prop names // are camelized. - onBeforeEnter?: (el: HostElement) => void - onEnter?: (el: HostElement, done: () => void) => void - onAfterEnter?: (el: HostElement) => void - onEnterCancelled?: (el: HostElement) => void + onBeforeEnter?: Hook<(el: HostElement) => void> + onEnter?: Hook<(el: HostElement, done: () => void) => void> + onAfterEnter?: Hook<(el: HostElement) => void> + onEnterCancelled?: Hook<(el: HostElement) => void> // leave - onBeforeLeave?: (el: HostElement) => void - onLeave?: (el: HostElement, done: () => void) => void - onAfterLeave?: (el: HostElement) => void - onLeaveCancelled?: (el: HostElement) => void // only fired in persisted mode + onBeforeLeave?: Hook<(el: HostElement) => void> + onLeave?: Hook<(el: HostElement, done: () => void) => void> + onAfterLeave?: Hook<(el: HostElement) => void> + onLeaveCancelled?: Hook<(el: HostElement) => void> // only fired in persisted mode // appear - onBeforeAppear?: (el: HostElement) => void - onAppear?: (el: HostElement, done: () => void) => void - onAfterAppear?: (el: HostElement) => void - onAppearCancelled?: (el: HostElement) => void + onBeforeAppear?: Hook<(el: HostElement) => void> + onAppear?: Hook<(el: HostElement, done: () => void) => void> + onAfterAppear?: Hook<(el: HostElement) => void> + onAppearCancelled?: Hook<(el: HostElement) => void> } export interface TransitionHooks< @@ -69,9 +71,9 @@ export interface TransitionHooks< delayedLeave?(): void } -export type TransitionHookCaller = ( - hook: ((el: any) => void) | Array<(el: any) => void> | undefined, - args?: any[] +export type TransitionHookCaller = ( + hook: Hook<(...args: T) => void> | undefined, + args?: T ) => void export type PendingCallback = (cancelled?: boolean) => void @@ -331,6 +333,19 @@ export function resolveTransitionHooks( ) } + const callAsyncHook = ( + hook: Hook<(el: any, done: () => void) => void>, + args: [TransitionElement, () => void] + ) => { + const done = args[1] + callHook(hook, args) + if (isArray(hook)) { + if (hook.every(hook => hook.length <= 1)) done() + } else if (hook.length <= 1) { + done() + } + } + const hooks: TransitionHooks = { mode, persisted, @@ -388,10 +403,7 @@ export function resolveTransitionHooks( el._enterCb = undefined }) if (hook) { - hook(el, done) - if (hook.length <= 1) { - done() - } + callAsyncHook(hook, [el, done]) } else { done() } @@ -423,10 +435,7 @@ export function resolveTransitionHooks( }) leavingVNodesCache[key] = vnode if (onLeave) { - onLeave(el, done) - if (onLeave.length <= 1) { - done() - } + callAsyncHook(onLeave, [el, done]) } else { done() }