@studiometa/js-toolkit
Version:
A set of useful little bits of JavaScript to boost your project! 🚀
114 lines (113 loc) • 3.5 kB
JavaScript
import { nextFrame } from "../nextFrame.js";
import * as classes from "./classes.js";
import * as styles from "./styles.js";
import { isArray, isString } from "../is.js";
import { hasWindow } from "../has.js";
import { eachElements } from "./utils.js";
const cache = /* @__PURE__ */ new WeakMap();
class Transition {
/**
* Is a transition currently running?
*/
isTransitioning = false;
/**
* A callback to execute when the transition ends.
*/
transitionEndHandler = null;
/**
* Instantiate and save the instance to the cache.
*/
constructor(element) {
cache.set(element, this);
}
/**
* Get the transition class attached to the given element.
*
* @param {HTMLElement} element The HTML element concerned by the transition.
* @return {Transition} The transition instance tied to the given element.
*/
static getInstance(element) {
let instance = cache.get(element);
if (!instance) {
instance = new this(element);
}
return instance;
}
}
function setClassesOrStyles(element, classesOrStyles, method = "add") {
if (isString(classesOrStyles) || isArray(classesOrStyles)) {
classes[method](element, classesOrStyles);
} else {
styles[method](element, classesOrStyles);
}
}
function testTransition(element) {
if (!hasWindow()) {
return false;
}
const { transitionDuration } = window.getComputedStyle(element);
return !!transitionDuration && transitionDuration !== "0s";
}
async function start(element, classesOrStyles) {
const trs = Transition.getInstance(element);
trs.isTransitioning = true;
setClassesOrStyles(element, classesOrStyles.from);
await nextFrame();
setClassesOrStyles(element, classesOrStyles.active);
}
async function next(element, classesOrStyles) {
const hasTransition = testTransition(element);
return new Promise(async (resolve) => {
if (hasTransition) {
const trs = Transition.getInstance(element);
trs.transitionEndHandler = () => resolve();
element.addEventListener("transitionend", trs.transitionEndHandler, false);
}
setClassesOrStyles(element, classesOrStyles.from, "remove");
setClassesOrStyles(element, classesOrStyles.to);
await nextFrame();
if (!hasTransition) {
resolve();
}
});
}
function end(element, classesOrStyles, mode = "remove") {
const trs = Transition.getInstance(element);
element.removeEventListener("transitionend", trs.transitionEndHandler, false);
if (mode === "remove") {
setClassesOrStyles(element, classesOrStyles.to, "remove");
}
setClassesOrStyles(element, classesOrStyles.active, "remove");
trs.isTransitioning = false;
trs.transitionEndHandler = null;
}
async function singleTransition(element, name, endMode = "remove") {
const classesOrStyles = isString(name) ? {
from: `${name}-from`,
active: `${name}-active`,
to: `${name}-to`
} : {
from: "",
active: "",
to: "",
...name
};
const trs = Transition.getInstance(element);
if (trs.isTransitioning) {
end(element, classesOrStyles);
}
await start(element, classesOrStyles);
await next(element, classesOrStyles);
end(element, classesOrStyles, endMode);
return Promise.resolve();
}
async function transition(elementOrElements, name, endMode = "remove") {
await Promise.all(
eachElements(elementOrElements, (element) => singleTransition(element, name, endMode))
);
}
export {
setClassesOrStyles,
transition
};
//# sourceMappingURL=transition.js.map