@cran/vue.core
Version:
Cranberry Vue Core Utilities
124 lines (123 loc) • 5.11 kB
JavaScript
/* 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,]);
},
};
}