]> git.ipfire.org Git - thirdparty/vuejs/core.git/commitdiff
fix(runtime-core): transition hooks can be arrays of functions (#5177)
authorKael <kaelwd@gmail.com>
Wed, 11 May 2022 01:56:57 +0000 (11:56 +1000)
committerGitHub <noreply@github.com>
Wed, 11 May 2022 01:56:57 +0000 (21:56 -0400)
packages/runtime-core/src/components/BaseTransition.ts

index 64249f8c4efffb98c02905d6e7031a93697140e8..53c3e85390a146497a14403a5e2c5747bb9740b9 100644 (file)
@@ -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<T = () => void> = T | T[]
+
 export interface BaseTransitionProps<HostElement = RendererElement> {
   mode?: 'in-out' | 'out-in' | 'default'
   appear?: boolean
@@ -34,20 +36,20 @@ export interface BaseTransitionProps<HostElement = RendererElement> {
   // 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 = <T extends any[] = [el: any]>(
+  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<TransitionElement> = {
     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()
       }