UNPKG

flashmessage-js

Version:

A modern, lightweight, and fully customizable flash message library for React applications

183 lines (179 loc) 7.55 kB
"use client"; 'use strict'; var React = require('react'); // Default theme configuration const defaultTheme = { success: { bg: "#10b981", dark: "#059669", text: "#ffffff" }, error: { bg: "#ef4444", dark: "#dc2626", text: "#ffffff" }, info: { bg: "#3b82f6", dark: "#2563eb", text: "#ffffff" }, warning: { bg: "#f59e0b", dark: "#d97706", text: "#ffffff" } }; // Create Context const FlashMessageContext = React.createContext(undefined); // Individual Flash Message Item Component function FlashMessageItem({ message, onDismiss, theme }) { const [isExiting, setIsExiting] = React.useState(false); const [isPaused, setIsPaused] = React.useState(false); const [progress, setProgress] = React.useState(100); // Auto-dismiss timer with progress bar React.useEffect(() => { if (!message.duration || isPaused) return; const interval = 50; // Update every 50ms for smooth progress const decrement = (interval / message.duration) * 100; const timer = setInterval(() => { setProgress(prev => { const next = prev - decrement; if (next <= 0) { handleDismiss(); return 0; } return next; }); }, interval); return () => clearInterval(timer); }, [message.duration, isPaused]); // Handle dismiss with exit animation const handleDismiss = () => { setIsExiting(true); setTimeout(() => onDismiss(message.id), 300); }; // Get color scheme for message type const color = theme[message.type] || defaultTheme[message.type]; return (React.createElement("div", { role: "alert", "aria-live": "polite", "aria-atomic": "true", onMouseEnter: () => setIsPaused(true), onMouseLeave: () => setIsPaused(false), style: { backgroundColor: color.bg, color: color.text || "#ffffff", padding: "12px 16px", borderRadius: "8px", boxShadow: "0 4px 6px rgba(0, 0, 0, 0.1)", marginBottom: "10px", minWidth: "300px", maxWidth: "500px", cursor: "pointer", opacity: isExiting ? 0 : 1, transform: isExiting ? "translateY(-20px)" : "translateY(0)", transition: "all 0.3s ease-in-out", animation: "flashMessageSlideIn 0.3s ease-out", position: "relative", overflow: "hidden" }, onClick: handleDismiss }, React.createElement("div", { style: { display: "flex", justifyContent: "space-between", alignItems: "center" } }, React.createElement("span", { style: { flex: 1, marginRight: "12px" } }, message.message), React.createElement("button", { onClick: (e) => { e.stopPropagation(); handleDismiss(); }, "aria-label": "Close message", style: { background: "none", border: "none", color: color.text || "#ffffff", fontSize: "20px", cursor: "pointer", padding: "0", width: "24px", height: "24px", display: "flex", alignItems: "center", justifyContent: "center", opacity: 0.8 } }, "\u00D7")), message.duration && (React.createElement("div", { style: { position: "absolute", bottom: 0, left: 0, height: "3px", backgroundColor: color.dark, width: `${progress}%`, transition: "width 0.05s linear" } })))); } // Main Provider Component function FlashMessageProvider({ children, defaultPosition = "top", maxMessages = 5, defaultTheme: customDefaultTheme }) { const [messages, setMessages] = React.useState([]); const [position, setPosition] = React.useState(defaultPosition); const [theme, setTheme] = React.useState(Object.assign(Object.assign({}, defaultTheme), customDefaultTheme)); // Show a new flash message const showFlashMessage = React.useCallback((message, type, options = {}) => { var _a; const id = `flash-${Date.now()}-${Math.random()}`; const duration = (_a = options.duration) !== null && _a !== void 0 ? _a : 3000; setMessages(prev => { const newMessages = [...prev, { id, message, type, duration }]; return newMessages.slice(-maxMessages); }); return id; }, [maxMessages]); // Dismiss a specific message by ID const dismissFlashMessage = React.useCallback((id) => { setMessages(prev => prev.filter(msg => msg.id !== id)); }, []); // Clear all messages const clearAllMessages = React.useCallback(() => { setMessages([]); }, []); // Calculate position styles based on position prop const getPositionStyles = () => { const base = { position: "fixed", zIndex: 9999, display: "flex", flexDirection: "column", alignItems: "center" }; switch (position) { case "top": return Object.assign(Object.assign({}, base), { top: "20px", left: "50%", transform: "translateX(-50%)" }); case "bottom": return Object.assign(Object.assign({}, base), { bottom: "20px", left: "50%", transform: "translateX(-50%)" }); case "top-left": return Object.assign(Object.assign({}, base), { top: "20px", left: "20px" }); case "top-right": return Object.assign(Object.assign({}, base), { top: "20px", right: "20px" }); case "bottom-left": return Object.assign(Object.assign({}, base), { bottom: "20px", left: "20px" }); case "bottom-right": return Object.assign(Object.assign({}, base), { bottom: "20px", right: "20px" }); default: return Object.assign(Object.assign({}, base), { top: "20px", left: "50%", transform: "translateX(-50%)" }); } }; return (React.createElement(FlashMessageContext.Provider, { value: { messages, showFlashMessage, dismissFlashMessage, clearAllMessages, position, setPosition, theme, setTheme } }, children, React.createElement("style", null, ` @keyframes flashMessageSlideIn { from { opacity: 0; transform: translateY(-20px); } to { opacity: 1; transform: translateY(0); } } `), messages.length > 0 && (React.createElement("div", { style: getPositionStyles() }, messages.map(msg => (React.createElement(FlashMessageItem, { key: msg.id, message: msg, onDismiss: dismissFlashMessage, theme: theme }))))))); } // Custom Hook const useFlashMessage = () => { const context = React.useContext(FlashMessageContext); if (!context) { throw new Error("useFlashMessage must be used within a FlashMessageProvider"); } return context; }; exports.FlashMessageProvider = FlashMessageProvider; exports.defaultTheme = defaultTheme; exports.useFlashMessage = useFlashMessage; //# sourceMappingURL=index.cjs.js.map