import {
getCurrentInstance,
- ComponentInternalInstance,
SetupContext,
ComponentOptions
} from '../component'
onLeaveCancelled?: (el: any) => void
}
+type TransitionHookCaller = (
+ hook: ((el: any) => void) | undefined,
+ args?: any[]
+) => void
+
+interface PendingCallbacks {
+ enter?: (cancelled?: boolean) => void
+ leave?: (cancelled?: boolean) => void
+}
+
const TransitionImpl = {
name: `BaseTransition`,
setup(props: TransitionProps, { slots }: SetupContext) {
const instance = getCurrentInstance()!
let isLeaving = false
let isMounted = false
+ const pendingCallbacks: PendingCallbacks = {}
onMounted(() => {
isMounted = true
})
+ const callTransitionHook: TransitionHookCaller = (hook, args) => {
+ hook &&
+ callWithAsyncErrorHandling(
+ hook,
+ instance,
+ ErrorCodes.TRANSITION_HOOK,
+ args
+ )
+ }
+
return () => {
const children = slots.default && slots.default()
if (!children || !children.length) {
let delayedLeave: (() => void) | undefined
const performDelayedLeave = () => delayedLeave && delayedLeave()
- const transitionData = (child.transition = resolveTransitionData(
- instance,
+ const transitionHooks = (child.transition = resolveTransitionHooks(
rawProps,
+ callTransitionHook,
isMounted,
+ pendingCallbacks,
performDelayedLeave
))
) {
// update old tree's hooks in case of dynamic transition
// need to do this recursively in case of HOCs
- updateHOCTransitionData(oldChild, transitionData)
+ updateHOCTransitionData(oldChild, transitionHooks)
// switching between different views
if (mode === 'out-in') {
isLeaving = true
// return placeholder node and queue update when leave finishes
- transitionData.afterLeave = () => {
+ transitionHooks.afterLeave = () => {
isLeaving = false
instance.update()
}
return placeholder(child)
} else if (mode === 'in-out') {
- transitionData.delayLeave = performLeave => {
+ transitionHooks.delayLeave = performLeave => {
delayedLeave = performLeave
}
}
}
}
-export interface TransitionData {
+export interface TransitionHooks {
beforeEnter(el: object): void
enter(el: object): void
leave(el: object, remove: () => void): void
delayLeave?(performLeave: () => void): void
}
-function resolveTransitionData(
- instance: ComponentInternalInstance,
+function resolveTransitionHooks(
{
appear,
onBeforeEnter,
onAfterLeave,
onLeaveCancelled
}: TransitionProps,
+ callHook: TransitionHookCaller,
isMounted: boolean,
+ pendingCallbacks: PendingCallbacks,
performDelayedLeave: () => void
-): TransitionData {
- // TODO handle cancel hooks
+): TransitionHooks {
return {
beforeEnter(el) {
if (!isMounted && !appear) {
return
}
- onBeforeEnter &&
- callWithAsyncErrorHandling(
- onBeforeEnter,
- instance,
- ErrorCodes.TRANSITION_HOOK,
- [el]
- )
+ if (pendingCallbacks.leave) {
+ pendingCallbacks.leave(true /* cancelled */)
+ }
+ callHook(onBeforeEnter, [el])
},
+
enter(el) {
if (!isMounted && !appear) {
return
}
- const done = () => {
- onAfterEnter &&
- callWithAsyncErrorHandling(
- onAfterEnter,
- instance,
- ErrorCodes.TRANSITION_HOOK,
- [el]
- )
- performDelayedLeave()
- }
+ const afterEnter = (pendingCallbacks.enter = (cancelled?) => {
+ if (cancelled) {
+ callHook(onEnterCancelled, [el])
+ } else {
+ callHook(onAfterEnter, [el])
+ performDelayedLeave()
+ }
+ pendingCallbacks.enter = undefined
+ })
if (onEnter) {
- onEnter(el, done)
+ onEnter(el, afterEnter)
} else {
- done()
+ afterEnter()
}
},
+
leave(el, remove) {
- onBeforeLeave &&
- callWithAsyncErrorHandling(
- onBeforeLeave,
- instance,
- ErrorCodes.TRANSITION_HOOK,
- [el]
- )
- const afterLeave = () =>
- onAfterLeave &&
- callWithAsyncErrorHandling(
- onAfterLeave,
- instance,
- ErrorCodes.TRANSITION_HOOK,
- [el]
- )
+ if (pendingCallbacks.enter) {
+ pendingCallbacks.enter(true /* cancelled */)
+ }
+ callHook(onBeforeLeave, [el])
+ const afterLeave = (pendingCallbacks.leave = (cancelled?) => {
+ remove()
+ if (cancelled) {
+ callHook(onLeaveCancelled, [el])
+ } else {
+ callHook(onAfterLeave, [el])
+ }
+ pendingCallbacks.leave = undefined
+ })
if (onLeave) {
- onLeave(el, () => {
- remove()
- afterLeave()
- })
+ onLeave(el, afterLeave)
} else {
- remove()
afterLeave()
}
}
}
}
-function updateHOCTransitionData(vnode: VNode, data: TransitionData) {
+function updateHOCTransitionData(vnode: VNode, data: TransitionHooks) {
if (vnode.shapeFlag & ShapeFlags.COMPONENT) {
updateHOCTransitionData(vnode.component!.subTree, data)
} else {