react-toast-kit
Version:
A modern, accessible toast notification system for React applications with automatic CSS injection
284 lines (277 loc) • 10.8 kB
TypeScript
import * as zustand from 'zustand';
import * as React$1 from 'react';
import { JSX } from 'react';
type ToastPosition = 'top-right' | 'top-center' | 'top-left' | 'bottom-right' | 'bottom-center' | 'bottom-left';
type ToastVariant = 'success' | 'error' | 'info' | 'warning' | 'default' | 'custom' | 'loading';
type ToastTheme = 'light' | 'dark' | 'system';
type ToastAnimation = 'slide' | 'fade' | 'bounce' | 'flip' | 'zoom' | 'none' | 'elastic';
type ToastStyle = 'solid' | 'gradient' | 'glass' | 'shimmer' | 'pill' | 'neon' | 'retro' | 'confetti' | 'minimal' | 'outlined';
interface ToastAction {
label: string;
onClick: (id: string) => void;
variant?: 'primary' | 'secondary' | 'danger';
closeOnClick?: boolean;
}
type ProgressBarStyle = 'default' | 'fancy' | 'gradient-wave' | 'pulse' | 'particles' | 'liquid' | 'three-d' | 'dashed' | 'glow' | 'rainbow' | 'data-flow' | 'step-progress';
interface CustomAnimation {
initial: Record<string, unknown>;
animate: Record<string, unknown>;
exit: Record<string, unknown>;
transition?: Record<string, unknown>;
}
interface ToastPlugin {
name: string;
description?: string;
beforeCreate?: (options: ToastOptions) => ToastOptions;
afterCreate?: (toast: Toast) => void;
beforeRemove?: (toast: Toast) => boolean;
afterRemove?: (toast: Toast) => void;
}
interface ToastOptions {
id?: string;
title?: string;
description?: string;
variant?: ToastVariant;
duration?: number;
position?: ToastPosition;
dismissible?: boolean;
pauseOnHover?: boolean;
dismissOnClick?: boolean;
theme?: ToastTheme;
icon?: JSX.Element;
component?: JSX.Element;
onDismiss?: (id: string) => void;
className?: string;
style?: React.CSSProperties;
animation?: ToastAnimation;
customAnimation?: CustomAnimation;
visualStyle?: ToastStyle;
progressBarStyle?: ProgressBarStyle;
progressBarColor?: string;
progressBarPosition?: 'top' | 'bottom' | 'left' | 'right';
progressBarThickness?: number;
floating?: boolean;
emoji?: string;
rippleEffect?: boolean;
stagger?: number;
swipeToDismiss?: boolean;
priority?: 'low' | 'normal' | 'high';
progressAnimation?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
actions?: ToastAction[];
}
interface StrictToastOptions extends Omit<ToastOptions, 'variant' | 'position'> {
variant: ToastVariant;
position: ToastPosition;
}
interface Toast extends Required<Pick<ToastOptions, 'id' | 'variant' | 'position' | 'duration' | 'pauseOnHover' | 'dismissible' | 'dismissOnClick' | 'theme'>> {
title?: string;
description?: string;
icon?: JSX.Element;
component?: JSX.Element;
createdAt: number;
onDismiss?: (id: string) => void;
className?: string;
style?: React.CSSProperties;
animation?: ToastAnimation;
customAnimation?: CustomAnimation;
visualStyle?: ToastStyle;
progressBarStyle?: ProgressBarStyle;
progressBarColor?: string;
progressBarPosition?: 'top' | 'bottom' | 'left' | 'right';
progressBarThickness?: number;
floating?: boolean;
emoji?: string;
rippleEffect?: boolean;
stagger?: number;
swipeToDismiss?: boolean;
priority?: 'low' | 'normal' | 'high';
progressAnimation?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
actions?: ToastAction[];
iconString?: string;
updating?: boolean;
}
interface ToastStoreConfig {
defaultDuration: number;
defaultDismissible: boolean;
defaultPauseOnHover: boolean;
defaultDismissOnClick: boolean;
defaultAnimation: ToastAnimation;
defaultStyle: ToastStyle;
defaultProgressBarStyle?: ProgressBarStyle;
defaultProgressBarColor?: string;
defaultProgressBarPosition: 'top' | 'bottom' | 'left' | 'right';
defaultProgressBarThickness: number;
defaultProgressAnimation: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
defaultFloating: boolean;
defaultRippleEffect: boolean;
defaultSwipeToDismiss: boolean;
defaultPriority: 'low' | 'normal' | 'high';
defaultStagger: number;
globalClassName?: string;
globalStyle?: React.CSSProperties;
}
interface ToastState {
toasts: Toast[];
maxToasts: number;
theme: ToastTheme;
effectiveTheme: 'light' | 'dark';
pausedToasts: Set<string>;
activeTimers: Map<string, number>;
timerStartedAt: Map<string, number>;
remainingTime: Map<string, number>;
plugins: ToastPlugin[];
config: ToastStoreConfig;
addToast: (toast: Toast) => string;
removeToast: (id: string) => void;
updateToast: (id: string, toast: Partial<Toast>) => void;
pauseToast: (id: string) => void;
resumeToast: (id: string) => void;
clearAllToasts: () => void;
setTheme: (theme: ToastTheme) => void;
setMaxToasts: (max: number) => void;
updateEffectiveTheme: () => void;
setConfig: (config: Partial<ToastStoreConfig>) => void;
cleanup: () => void;
registerPlugin: (plugin: ToastPlugin) => void;
unregisterPlugin: (name: string) => void;
}
declare const useToastStore: zustand.UseBoundStore<zustand.StoreApi<ToastState>>;
type ToastHandler = {
(message: string): string;
(options: ToastOptions): string;
success: (options: ToastOptions | string) => string;
error: (options: ToastOptions | string) => string;
warning: (options: ToastOptions | string) => string;
info: (options: ToastOptions | string) => string;
loading: (options: ToastOptions | string) => string;
custom: (component: JSX.Element, options?: Omit<ToastOptions, 'component'>) => string;
promise: <T>(promise: Promise<T>, options: {
loading: ToastOptions | string;
success: ((data: T) => ToastOptions | string) | ToastOptions | string;
error: ((error: unknown) => ToastOptions | string) | ToastOptions | string;
}) => Promise<T>;
update: (id: string, options: Partial<ToastOptions>) => void;
dismiss: (id?: string) => void;
clearAll: () => void;
};
declare const toast: ToastHandler;
declare const registerPlugin: (plugin: ToastPlugin) => void;
declare const unregisterPlugin: (name: string) => void;
declare const cleanup: () => void;
declare global {
interface Window {
__TOAST_DEV_MODE__?: boolean;
}
}
interface ToastProviderProps {
children: React$1.ReactNode;
theme?: ToastTheme;
position?: ToastPosition;
maxToasts?: number;
defaultAnimation?: ToastAnimation;
defaultStyle?: ToastStyle;
defaultDuration?: number;
defaultDismissible?: boolean;
defaultPauseOnHover?: boolean;
defaultDismissOnClick?: boolean;
defaultProgressBarStyle?: ProgressBarStyle;
defaultProgressBarColor?: string;
defaultProgressBarPosition?: 'top' | 'bottom' | 'left' | 'right';
defaultProgressBarThickness?: number;
defaultProgressAnimation?: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
defaultFloating?: boolean;
defaultRippleEffect?: boolean;
defaultSwipeToDismiss?: boolean;
defaultPriority?: 'low' | 'normal' | 'high';
defaultStagger?: number;
containerClassName?: string;
topOffset?: number;
bottomOffset?: number;
leftOffset?: number;
rightOffset?: number;
enableAccessibleAnnouncements?: boolean;
enableDevMode?: boolean;
enableDevTools?: boolean;
suppressHydrationWarning?: boolean;
globalClassName?: string;
globalStyle?: React$1.CSSProperties;
}
interface ToastProviderContext {
theme: ToastTheme;
effectiveTheme: 'light' | 'dark';
position: ToastPosition;
maxToasts: number;
defaultAnimation: ToastAnimation;
defaultStyle: ToastStyle;
defaultDuration: number;
defaultDismissible: boolean;
defaultPauseOnHover: boolean;
defaultDismissOnClick: boolean;
defaultProgressBarStyle?: ProgressBarStyle;
defaultProgressBarColor?: string;
defaultProgressBarPosition: 'top' | 'bottom' | 'left' | 'right';
defaultProgressBarThickness: number;
defaultProgressAnimation: 'linear' | 'ease' | 'ease-in' | 'ease-out' | 'ease-in-out' | 'spring';
defaultFloating: boolean;
defaultRippleEffect: boolean;
defaultSwipeToDismiss: boolean;
defaultPriority: 'low' | 'normal' | 'high';
defaultStagger: number;
globalClassName?: string;
globalStyle?: React$1.CSSProperties;
}
declare const ToastProviderContext: React$1.Context<ToastProviderContext | null>;
declare const ToastProvider: React$1.FC<ToastProviderProps>;
declare const useToastProvider: () => ToastProviderContext;
/**
* Primary hook — exposes toast state and actions for component use.
* Uses a shallow selector so consumers only re-render when user-facing
* state changes (toasts list, theme, maxToasts, plugins). Internal timer
* bookkeeping (activeTimers, timerStartedAt, remainingTime, pausedToasts)
* does NOT cause re-renders here.
*/
declare const useToast: () => {
toasts: Toast[];
theme: ToastTheme;
effectiveTheme: "light" | "dark";
maxToasts: number;
plugins: ToastPlugin[];
addToast: (toast: Toast) => string;
removeToast: (id: string) => void;
updateToast: (id: string, toast: Partial<Toast>) => void;
clearAllToasts: () => void;
pauseToast: (id: string) => void;
resumeToast: (id: string) => void;
setTheme: (theme: ToastTheme) => void;
setMaxToasts: (max: number) => void;
registerPlugin: (plugin: ToastPlugin) => void;
unregisterPlugin: (name: string) => void;
getToastById: (id: string) => Toast | undefined;
hasToasts: () => boolean;
stats: {
total: number;
byVariant: Record<string, number>;
byPosition: Record<ToastPosition, number>;
};
};
/**
* Lightweight hook for reading/setting theme and maxToasts only.
*/
declare const useToastConfig: () => {
theme: ToastTheme;
effectiveTheme: "light" | "dark";
setTheme: (theme: ToastTheme) => void;
maxToasts: number;
setMaxToasts: (max: number) => void;
};
/**
* Derived statistics hook — useful for analytics or custom UI.
*/
declare const useToastStats: () => {
total: number;
byVariant: Record<string, number>;
byPosition: Record<ToastPosition, number>;
byTheme: Record<ToastTheme, number>;
};
declare const injectCSS: () => void;
export { type CustomAnimation, type ProgressBarStyle, type StrictToastOptions, type Toast, type ToastAction, type ToastAnimation, type ToastOptions, type ToastPlugin, type ToastPosition, ToastProvider, type ToastStoreConfig, type ToastStyle, type ToastTheme, type ToastVariant, cleanup, injectCSS, registerPlugin, toast, unregisterPlugin, useToast, useToastConfig, useToastProvider, useToastStats, useToastStore };