All files / components/dialogs ToastManager.tsx

77.27% Statements 17/22
100% Branches 2/2
70.58% Functions 12/17
72.22% Lines 13/18

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114                                              8x     4x 4x 4x         1x 1x       5x           6x   6x                     2x             8x   1x                 1x                                                                            
/**
 * ToastManager - Toast 全局管理器
 * 提供全局的 Toast 显示功能
 */
 
import React, { useEffect, useState } from 'react';
import { YStack } from 'tamagui';
import { Toast } from './Toast';
import type { ToastConfig } from './types';
import { create } from 'zustand';
 
interface ToastWithId extends ToastConfig {
  id: string;
}
 
interface ToastStore {
  toasts: ToastWithId[];
  addToast: (config: ToastConfig) => void;
  removeToast: (id: string) => void;
  clearAll: () => void;
}
 
// Zustand store for managing toasts
export const useToastStore = create<ToastStore>((set) => ({
  toasts: [],
  addToast: (config) => {
    const id = config.id || `toast-${Date.now()}-${Math.random()}`;
    const toast: ToastWithId = { ...config, id };
    set((state) => ({
      toasts: [...state.toasts, toast],
    }));
  },
  removeToast: (id) => {
    set((state) => ({
      toasts: state.toasts.filter((t) => t.id !== id),
    }));
  },
  clearAll: () => {
    set({ toasts: [] });
  },
}));
 
// Toast Manager Component
export function ToastManager() {
  const { toasts, removeToast } = useToastStore();
 
  return (
    <YStack
      position="absolute"
      top={0}
      left={0}
      right={0}
      bottom={0}
      pointerEvents="box-none"
      zIndex={9999}
    >
      {toasts.map((toast) => (
        <Toast key={toast.id} {...toast} onDismiss={() => removeToast(toast.id)} />
      ))}
    </YStack>
  );
}
 
// Helper functions for easy toast usage
export const toast = {
  success: (message: string, description?: string, config?: Partial<ToastConfig>) => {
    useToastStore.getState().addToast({
      type: 'success',
      message,
      description,
      ...config,
    });
  },
 
  error: (message: string, description?: string, config?: Partial<ToastConfig>) => {
    useToastStore.getState().addToast({
      type: 'error',
      message,
      description,
      ...config,
    });
  },
 
  warning: (message: string, description?: string, config?: Partial<ToastConfig>) => {
    useToastStore.getState().addToast({
      type: 'warning',
      message,
      description,
      ...config,
    });
  },
 
  info: (message: string, description?: string, config?: Partial<ToastConfig>) => {
    useToastStore.getState().addToast({
      type: 'info',
      message,
      description,
      ...config,
    });
  },
 
  custom: (config: ToastConfig) => {
    useToastStore.getState().addToast(config);
  },
 
  dismiss: (id: string) => {
    useToastStore.getState().removeToast(id);
  },
 
  dismissAll: () => {
    useToastStore.getState().clearAll();
  },
};