Remove Toast With Panning (Using mouse & touch events)
by Konstantin Rouda
HTML
<main class="c-main">
<div id="toastsContainer" class="c-toasts-container c-toasts-container--left c-toasts-container--from-bottom">
<div class="c-toast c-toast--visible" role="alert" id="toast" aria-live="assertive" aria-atomic="true">
<h4 class="c-toast__title">Toast Title</h4>
<div class="c-toast__content">User has been successfully created</div>
</div>
</div>
</main>
CSS
HTML {
/*using system font-stack*/
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
font-size: calc(16px + (20 - 16) * (100vw - 300px) / (1100 - 300));
line-height: 1.5;
box-sizing: border-box;
}
BODY {
height: 720px;
margin: 0;
padding-bottom: 2rem;
color: rgb(58, 61, 64);
background-color: rgb(254, 254, 254);
}
*,
*::before,
*::after {
box-sizing: inherit;
color: inherit;
}
/*Actual Style*/
.c-main {
display: flex;
height: 100vh;
}
.panning {
user-select: none;
transition: none !important;
opacity: 1;
}
.panning * {
pointer-events: none;
}
/**TOAST STYLE**/
/*===================================
TOASTS CONTAINER
===================================*/
.c-toasts-container {
position: fixed;
top: 0;
bottom: 0;
min-width: 250px;
width: 100%;
max-width: 100%;
min-height: 100px;
pointer-events: none;
box-sizing: border-box;
z-index: 9999;
}
.c-toasts-container *,
.c-toasts-container *::before,
.c-toasts-container *::after {
box-sizing: inherit;
}
@media screen and (min-width: 600px) {
.c-toasts-container {
max-width: 50%;
}
/* POSITIONS
-------------------*/
.c-toasts-container--left {
left: 0.5em;
}
.c-toasts-container--right {
right: 0.5em;
}
}
/*===================================
TOAST
===================================*/
.c-toast {
opacity: 0;
position: absolute;
display: flex;
flex-direction: column;
max-width: 100%;
min-height: 50px;
margin-bottom: 1em;
border-radius: 0.3em;
background: rgba(42, 44, 46, 0.98);
color: rgba(248, 248, 248, 1);
line-height: 1.5;
box-shadow: 0 2px 8px -2px rgba(0, 0, 0, 0.3);
pointer-events: all;
transition: transform 0.7s, opacity 0.6s 0.2s;
}
/*align toast to the right*/
.c-toasts-container--right .c-toast {
right: 0;
}
/*--> FROM TOP <--*/
.c-toasts-container--from-top .c-toast {
top: 0;
transform:...
JavaScript
;(function () {
"use strict";
const toast = document.getElementById("toast");
toast.addEventListener("mousedown", onDragStart);
document.addEventListener("mousemove", onDrag);
document.addEventListener("mouseup", onDragEnd);
toast.addEventListener("mouseleave", onDragEnd);
document.addEventListener("touchstart", onDragStart);
document.addEventListener("touchmove", onDrag);
document.addEventListener("touchend", onDragEnd);
function onDragStart (e) {
const toast = e.currentTarget;
//debugger;
toast.classList.add("panning");
const translateYVal = getComputedStyle(toast).transform.match(/(-?\d\.?\d*)\)$/)[1];
let intialTranslateY = null;
if(translateYVal) {
intialTranslateY = Math.round((translateYVal / toast.offsetHeight) * 100);
}
if(intialTranslateY) {
toast.intialTranslateY = intialTranslateY;
}
toast.dragStartTime = performance.now();
if(e.type === "touchstart") {
toast.initX = e.touches[0].clientX;
} else {
toast.initX = e.clientX;
}
}
function onDrag (e) {
const toast = e.target;
if(!toast.classList.contains("panning")) return;
e.preventDefault();
let clientX = e.clientX;
if(e.type === "touchmove") {
clientX = e.touches[0].clientX;
}
let x = clientX - toast.initX;
toast.dragEndTime = performance.now();
//debugger;
translateX(toast, x);
}
function onDragEnd (e) {
const toast = e.target;
if(!toast.classList.contains("panning")) return;
e.preventDefault();
toast.classList.remove("panning");
translateX(toast, 0);
}
// UTILITIES
function translateX(elem, newPos) {
let pos = 0;
let opacity = 1;
let moveTime = 0;
if(newPos !== 0) {
pos = newPos;/* - (elem.offsetWidth / 2);*/
// mouse speed (https://stackoverflow.com/questions/6417036/track-mouse-speed-with-js)
moveTime = Math.abs(Math.round(pos...