UNPKG

react-toastly-jsx

Version:

A beautiful React toast notification library with animations, gradients, sounds, and premium features for free.

123 lines (109 loc) 3.76 kB
import React, { createContext, useContext, useState, useCallback } from "react"; const ToastlyContext = createContext(); const soundMap = { success: "/sounds/success.mp3", error: "/sounds/error.mp3", warning: "/sounds/warning.mp3", info: "/sounds/info.mp3", }; export function ToastlyProvider({ children }) { const [toasts, setToasts] = useState([]); const playSound = (type) => { const soundPath = soundMap[type]; if (soundPath) { const audio = new Audio(soundPath); audio.play().catch((e) => console.warn("Sound play failed:", e)); } }; const addToast = useCallback(({ type, message, content, duration = 3000 }) => { const id = Date.now() + Math.random(); setToasts((prev) => [...prev, { id, type, message, content }]); playSound(type); setTimeout(() => { setToasts((prev) => prev.filter((t) => t.id !== id)); }, duration); }, []); const success = (msg, opts = {}) => addToast({ type: "success", message: msg, ...opts }); const error = (msg, opts = {}) => addToast({ type: "error", message: msg, ...opts }); const warning = (msg, opts = {}) => addToast({ type: "warning", message: msg, ...opts }); const info = (msg, opts = {}) => addToast({ type: "info", message: msg, ...opts }); const custom = (content, opts = {}) => addToast({ type: "custom", content, ...opts }); // Promise-based toast helper const promise = (promise, { loading, success: successMsg, error: errorMsg }) => { const id = Date.now() + Math.random(); setToasts((prev) => [...prev, { id, type: "info", message: loading }]); playSound("info"); return promise .then((res) => { setToasts((prev) => prev.filter((t) => t.id !== id)); addToast({ type: "success", message: successMsg }); return res; }) .catch((err) => { setToasts((prev) => prev.filter((t) => t.id !== id)); addToast({ type: "error", message: errorMsg }); throw err; }); }; return ( <ToastlyContext.Provider value={{ success, error, warning, info, custom, promise }}> {children} <div style={{ position: "fixed", top: 10, right: 10, display: "flex", flexDirection: "column", gap: 10, zIndex: 9999, maxWidth: 320, }} > {toasts.map(({ id, type, message, content }) => ( <div key={id} style={{ padding: "12px 20px", borderRadius: 8, color: "white", fontWeight: "bold", backgroundColor: type === "success" ? "#4caf50" : type === "error" ? "#f44336" : type === "warning" ? "#ff9800" : type === "info" ? "#2196f3" : "#555", boxShadow: "0 2px 6px rgba(0,0,0,0.3)", opacity: 0.9, animation: "slideIn 0.3s ease forwards", }} > {content || message} </div> ))} </div> <style>{` @keyframes slideIn { from { opacity: 0; transform: translateX(100%); } to { opacity: 0.9; transform: translateX(0); } } `}</style> </ToastlyContext.Provider> ); } export function useToastly() { const context = useContext(ToastlyContext); if (!context) throw new Error("useToastly must be used within ToastlyProvider"); return context; }