UNPKG

@cran/vue.core

Version:

Cranberry Vue Core Utilities

124 lines (123 loc) 5.11 kB
/* eslint-disable max-lines */ /* eslint-disable max-lines-per-function */ import { BaseTransition, h } from "@vue/runtime-dom"; import { addClasses, callHook, deferred, forceReflow, hasCallback, nextFrame, removeClasses, whenAnimationEnds } from "../utility"; const VTB = Symbol("vue.transition.began"); const VTC = Symbol("vue.transition.children"); const tnProps = { ...BaseTransition.props, name: String, css: Boolean, duration: [String, Number, Object,], enterFromClass: String, enterActiveClass: String, enterToClass: String, appearFromClass: String, appearActiveClass: String, appearToClass: String, leaveFromClass: String, leaveActiveClass: String, leaveToClass: String, }; export const tn = Object.assign(function TransitionComponent(props, { slots, }) { return h(BaseTransition, resolveTransitionProps(props), slots); }, { displayName: "Tn", props: tnProps, }); function resolveTransitionProps({ name = "v", css = true, duration, enterFromClass = `${name}-enter-from`, enterActiveClass = `${name}-enter-active`, enterToClass = `${name}-enter-to`, appearFromClass = enterFromClass, appearActiveClass = enterActiveClass, appearToClass = enterToClass, leaveFromClass = `${name}-leave-from`, leaveActiveClass = `${name}-leave-active`, leaveToClass = `${name}-leave-to`, ...baseProps }) { if (!css) { return baseProps; } const { enter: enterDuration, leave: leaveDuration, } = "object" === typeof duration ? duration : { enter: duration, leave: duration, }; const { onBeforeEnter, onEnter, onEnterCancelled, onLeave, onLeaveCancelled, onBeforeAppear = onBeforeEnter, onAppear = onEnter, onAppearCancelled = onEnterCancelled, } = baseProps; function finishEnter(el, appear, done) { removeClasses(el, appear ? appearToClass : enterToClass); removeClasses(el, appear ? appearActiveClass : enterActiveClass); done?.(); } function finishLeave(el, done) { removeClasses(el, leaveToClass); removeClasses(el, leaveActiveClass); done?.(); } function makeBeforeEnterHook(appear) { return function beforeEnterHook(el) { callHook(appear ? onBeforeAppear : onBeforeEnter, [el,]); addClasses(el, appear ? appearToClass : enterFromClass); addClasses(el, appear ? appearActiveClass : enterActiveClass); el[VTB] = deferred(); el[VTC] = []; }; } function makeEnterHook(appear) { return function enterHook(el, done) { const hook = appear ? onAppear : onEnter; void el[VTB].then(function onThen() { finishEnter(el, appear, done); }); callHook(hook, [el, el[VTB].resolve,]); nextFrame(async function onNextFrame() { let parent = el.parentElement; while (parent && !(VTB in parent)) { parent = parent.parentElement; } if (parent) { await parent[VTB]; parent[VTC].push(el); } removeClasses(el, appear ? appearFromClass : enterFromClass); addClasses(el, appear ? appearToClass : enterToClass); if (!hasCallback(hook)) { whenAnimationEnds(el, enterDuration, el[VTB].resolve); } }); }; } return { ...baseProps, onBeforeEnter: makeBeforeEnterHook(false), onBeforeAppear: makeBeforeEnterHook(true), onEnter: makeEnterHook(false), onAppear: makeEnterHook(true), onLeave(el, done, internal = false) { function resolve() { if (!internal) { finishLeave(el, done); } else { done(); } } addClasses(el, leaveFromClass); forceReflow(); addClasses(el, leaveActiveClass); nextFrame(async function onNextFrame() { await Promise.all(el[VTC].map(function mapChild(child) { const promise = deferred(); // eslint-disable-next-line @typescript-eslint/no-explicit-any child.__vueParentComponent.ctx.onLeave(child, promise.resolve, true); return promise; })); removeClasses(el, leaveFromClass); addClasses(el, leaveToClass); if (!hasCallback(onLeave)) { whenAnimationEnds(el, leaveDuration, resolve); } }); callHook(onLeave, [el, resolve,]); }, onEnterCancelled(el) { finishEnter(el, false); callHook(onEnterCancelled, [el,]); }, onAppearCancelled(el) { finishEnter(el, true); callHook(onAppearCancelled, [el,]); }, onLeaveCancelled(el) { finishLeave(el); callHook(onLeaveCancelled, [el,]); }, }; }