class ToastClass{ constructor(){ const node = document.createElement('section'); node.classList.add('gui-toast-group'); document.firstElementChild.insertBefore(node, document.body); this.Toaster=node; } createToast = text => { const node = document.createElement('output') node.innerText = text node.classList.add('gui-toast') node.setAttribute('role', 'status') return node } addToast = toast => { const { matches:motionOK } = window.matchMedia( '(prefers-reduced-motion: no-preference)' ) this.Toaster.children.length && motionOK ? this.flipToast(toast) : this.Toaster.appendChild(toast) } flipToast = toast => { // FIRST const first = this.Toaster.offsetHeight // add new child to change container size this.Toaster.appendChild(toast) // LAST const last = this.Toaster.offsetHeight // INVERT const invert = last - first // PLAY const animation = this.Toaster.animate([ { transform: `translateY(${invert}px)` }, { transform: 'translateY(0)' } ], { duration: 150, easing: 'ease-out', }) } Toast = text => { let toast = this.createToast(text) this.addToast(toast) return new Promise(async (resolve, reject) => { await Promise.allSettled( toast.getAnimations().map(animation => animation.finished ) ) this.Toaster.removeChild(toast) resolve() }) } }