import { Ref } from "vue"; /** * Return the browser transiton end name. * * @returns {string} The browser transition end name. */ const transitionEndEventName = (): string => { const el = document.createElement("div"), transitions: Record = { transition: "transitionend", OTransition: "otransitionend", MozTransition: "transitionend", WebkitTransition: "webkitTransitionEnd", }; for (const i in transitions) { if ( Object.prototype.hasOwnProperty.call(transitions, i) && el.style[i] !== undefined ) { return transitions[i]; } } return ""; }; /** * Wait for the element to render as Promise * * @param elem The * @returns */ const waitForElementRender = (elem: Ref): Promise => { return new Promise((resolve) => { if (document.contains(elem.value)) { return resolve(elem.value as HTMLElement); } /* eslint-disable @typescript-eslint/no-explicit-any */ const MutationObserver = window.MutationObserver || (window as any).WebKitMutationObserver || (window as any).MozMutationObserver; /* eslint-enable @typescript-eslint/no-explicit-any */ const observer = new MutationObserver(() => { if (document.contains(elem.value)) { resolve(elem.value); observer.disconnect(); } }); observer.observe(document.body, { childList: true, subtree: true, }); }); }; /** * Run the enter transition on a element. * * @param {Ref} elem The element to run the enter transition. * @param {string} transition The transition name. * @returns {void} */ export const transitionEnter = (elem: Ref, transition: string): void => { waitForElementRender(elem) .then((e: HTMLElement) => { window.setTimeout(() => { e.classList.replace( transition + "-enter-from", transition + "-enter-active" ); const transitionName = transitionEndEventName(); e.addEventListener( transitionName, () => { e.classList.replace( transition + "-enter-active", transition + "-enter-to" ); }, false ); }, 1); }) .catch(() => { /* empty */ }); }; /** * Run the exit transition on a element then call a callback. * * @param {Ref} elem The element to run the enter transition. * @param {string} transition The transition name. * @param {TransitionLeaveCallback|null} callback The callback to run after the transition finishes. * @returns {void} */ type TransitionLeaveCallback = () => void; export const transitionLeave = ( elem: Ref, transition: string, callback: TransitionLeaveCallback | null = null ): void => { elem.value.classList.remove(transition + "-enter-to"); elem.value.classList.add(transition + "-leave-from"); window.setTimeout(() => { elem.value.classList.replace( transition + "-leave-from", transition + "-leave-active" ); const transitionName = transitionEndEventName(); elem.value.addEventListener( transitionName, () => { elem.value.classList.replace( transition + "-leave-active", transition + "-leave-to" ); if (callback) { callback(); } }, false ); }, 1); };