UNPKG

@backpackapp-io/react-native-toast

Version:

A toasting library for React Native. Built in features such as swipe to dismiss, multiple toasts, & no context power this library.

158 lines (156 loc) 4.32 kB
"use strict"; import { useEffect, useState } from 'react'; const TOAST_LIMIT = 20; export let ActionType = /*#__PURE__*/function (ActionType) { ActionType[ActionType["ADD_TOAST"] = 0] = "ADD_TOAST"; ActionType[ActionType["UPDATE_TOAST"] = 1] = "UPDATE_TOAST"; ActionType[ActionType["UPSERT_TOAST"] = 2] = "UPSERT_TOAST"; ActionType[ActionType["DISMISS_TOAST"] = 3] = "DISMISS_TOAST"; ActionType[ActionType["REMOVE_TOAST"] = 4] = "REMOVE_TOAST"; ActionType[ActionType["START_PAUSE"] = 5] = "START_PAUSE"; ActionType[ActionType["END_PAUSE"] = 6] = "END_PAUSE"; return ActionType; }({}); const toastTimeouts = new Map(); const addToRemoveQueue = (toastId, reason) => { if (toastTimeouts.has(toastId)) { return; } const timeout = setTimeout(() => { toastTimeouts.delete(toastId); dispatch({ type: ActionType.REMOVE_TOAST, toastId: toastId, reason }); }, 1000); toastTimeouts.set(toastId, timeout); }; const clearFromRemoveQueue = toastId => { const timeout = toastTimeouts.get(toastId); if (timeout) { clearTimeout(timeout); } }; export const reducer = (state, action) => { switch (action.type) { case ActionType.ADD_TOAST: return { ...state, toasts: [action.toast, ...state.toasts].slice(0, TOAST_LIMIT) }; case ActionType.UPDATE_TOAST: // ! Side effects ! if (action.toast.id) { clearFromRemoveQueue(action.toast.id); } return { ...state, toasts: state.toasts.map(t => t.id === action.toast.id ? { ...t, ...action.toast } : t) }; case ActionType.UPSERT_TOAST: const { toast } = action; return state.toasts.find(t => t.id === toast.id) ? reducer(state, { type: ActionType.UPDATE_TOAST, toast }) : reducer(state, { type: ActionType.ADD_TOAST, toast }); case ActionType.DISMISS_TOAST: const { toastId, reason } = action; // ! Side effects ! - This could be execrated into a dismissToast() action, but I'll keep it here for simplicity if (toastId) { addToRemoveQueue(toastId, reason); } else { state.toasts.forEach(toast => { addToRemoveQueue(toast.id, reason); }); } return { ...state, toasts: state.toasts.map(t => t.id === toastId || toastId === undefined ? { ...t, visible: false, dismissReason: reason } : t) }; case ActionType.REMOVE_TOAST: if (action.toastId === undefined) { return { ...state, toasts: [] }; } return { ...state, toasts: state.toasts.filter(t => t.id !== action.toastId) }; case ActionType.START_PAUSE: return { ...state, pausedAt: action.time }; case ActionType.END_PAUSE: const diff = action.time - (state.pausedAt || 0); return { ...state, pausedAt: undefined, toasts: state.toasts.map(t => ({ ...t, pauseDuration: t.pauseDuration + diff })) }; } }; const listeners = []; let memoryState = { toasts: [], pausedAt: undefined }; export const dispatch = action => { memoryState = reducer(memoryState, action); listeners.forEach(listener => { listener(memoryState); }); }; const defaultTimeouts = { blank: 4000, error: 4000, success: 2000, loading: Infinity }; export const useStore = (toastOptions = {}) => { const [state, setState] = useState(memoryState); useEffect(() => { listeners.push(setState); return () => { const index = listeners.indexOf(setState); if (index > -1) { listeners.splice(index, 1); } }; }, [state]); const mergedToasts = state.toasts.filter(t => toastOptions?.providerKey === undefined || t.providerKey === toastOptions?.providerKey || t.providerKey === 'PERSISTS').map(t => ({ ...toastOptions, ...toastOptions[t.type], ...t, duration: t.duration || toastOptions[t.type]?.duration || toastOptions?.duration || defaultTimeouts[t.type], styles: { ...(t?.styles ?? {}) } })); return { ...state, toasts: mergedToasts }; }; //# sourceMappingURL=store.js.map