UNPKG

@studiometa/js-toolkit

Version:

A set of useful little bits of JavaScript to boost your project! 🚀

114 lines (113 loc) • 3.5 kB
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. * @returns {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