@mariojgt/wind-notify
Version:
toast notification for tailwindcss and daisyui
167 lines (150 loc) • 5.58 kB
JavaScript
import { info, error, success, warning } from "./toasts/messages";
export const startWindToast = async (title, message, alertType, duration = 10, position = 'right', zIndex = 10000) => {
// Check if we're in a browser environment
if (typeof window === 'undefined') return;
// Get the body element
const body = document.querySelector("body");
const containerId = "wind-notify-" + position;
// Find an element with the id 'wind-notify'
let toastyContainer = document.getElementById(containerId);
if (!toastyContainer) {
// Create the toastyContainer element after the body
toastyContainer = document.createElement("div");
// Add the div id to the toastyContainer element
toastyContainer.id = containerId;
// append the toastyContainer element to the body
body.appendChild(toastyContainer);
}
// Add the style to the main toastyContainer element so we can use it
toastDefaultStyle(toastyContainer, position, zIndex);
const toastyMessage = document.createElement("div");
// Add padding class to the toasty message
toastyMessage.className = "p-3 block transform transition-all duration-150 ease-out scale-0";
toastyContainer.appendChild(toastyMessage);
// Start the toasty animation
toastsAnimation(toastyMessage);
// Add the html to the toasty element
switch (alertType) {
case 'info':
toastyMessage.innerHTML = info(title, message);
break;
case 'error':
toastyMessage.innerHTML = error(title, message);
break;
case 'success':
toastyMessage.innerHTML = success(title, message);
break;
default:
toastyMessage.innerHTML = warning(title, message);
break;
}
// Move the progress bar once reached the end of the toasty, remove the toasty
moveProgressBar(toastyMessage, duration);
};
/**
* Add the default style to the main toasty element
*
* @param mixed element
*
* @return [type]
*/
function toastDefaultStyle(toastyContainer, position, zIndex = 10000) {
// Set the fixed positioning and other styles
toastyContainer.style.position = 'fixed';
toastyContainer.style.zIndex = zIndex;
toastyContainer.style.width = '300px'; // Set a default width
switch(position) {
case 'left':
toastyContainer.style.top = '50%';
toastyContainer.style.transform = 'translateY(-50%)';
toastyContainer.style.left = '1rem';
break;
case 'right':
toastyContainer.style.top = '50%';
toastyContainer.style.transform = 'translateY(-50%)';
toastyContainer.style.right = '1rem';
break;
case 'top':
toastyContainer.style.top = '1rem';
toastyContainer.style.left = '50%';
toastyContainer.style.transform = 'translateX(-50%)';
break;
case 'bottom':
toastyContainer.style.bottom = '1rem';
toastyContainer.style.left = '50%';
toastyContainer.style.transform = 'translateX(-50%)';
break;
case 'middle':
toastyContainer.style.top = '50%';
toastyContainer.style.left = '50%';
toastyContainer.style.transform = 'translate(-50%, -50%)';
break;
default:
toastyContainer.style.bottom = '1rem';
toastyContainer.style.right = '1rem';
break;
}
toastyContainer.style.maxHeight = 'calc(100vh - 2rem)';
toastyContainer.style.overflowY = 'auto'; // Allow scrolling if there are too many toasts
}
/**
* Animate the toasty message using tailwindcss animation classes
*
* @param mixed element
*
* @return [type]
*/
function toastsAnimation(element) {
setTimeout(() => {
// Remove class 'hidden' from the toasty element
element.classList.remove("scale-0");
// Add class 'animate' to the toasty element
element.classList.add("scale-100");
}, 200);
}
/**
* Move the progress bar with a smoother ease-out progression.
* Once the progress bar reaches the end, remove the toast notification.
*
* @param {HTMLElement} element - The toast container element.
* @param {number} duration - Duration in seconds for the toast to last.
*/
function moveProgressBar(element, duration) {
const progressBar = element.querySelector(".progress");
if (!progressBar) return;
const totalFrames = duration * 60; // Assuming 60 frames per second
let frameCount = 0;
const increment = () => {
// Use ease-out progression
const progress = Math.min((frameCount / totalFrames) ** 0.5 * 100, 100);
progressBar.value = progress;
if (frameCount >= totalFrames) {
element.classList.add("scale-0");
setTimeout(() => {
element.remove();
}, 200);
} else {
frameCount++;
requestAnimationFrame(increment);
}
};
increment();
}
/**
* Used in the button when the user clicks the button to remove the toasty
*
* @param mixed element
*
*/
function removeWindToast(element) {
const target = element.target;
// Get target parent element
const parent =
target.parentElement.parentElement.parentElement.parentElement
.parentElement;
parent.remove();
}
// Only add to window if we're in a browser environment
if (typeof window !== 'undefined') {
window.removeWindToast = removeWindToast;
}