import * as React from 'react' ; import { Notification , NotificationContainer , Severity } from './components' ; import { AnimatePresence } from "framer-motion" ; import { v4 as uuid } from 'uuid' ; import lodash from 'lodash' ; export interface INotificationContext { addNotification : ( text : string , delay ? : number , severity ? : Severity ) => string ; removeNotification : ( id : string ) => void ; useNotification ( ) : [ ( text : string , delay ? : number , severity ? : Severity ) => void , ( ) => void ] ; } interface INotification { id : string ; text : string ; delay : number ; severity : Severity ; } const notificationContext = React . createContext < Partial < INotificationContext > > ( { } ) ; const { Provider } = notificationContext ; const NotificationProvider = ( { children } ) => { const [ notifications , setNotifications ] = React . useState < Array < INotification > > ( [ ] ) ; const removeNotification = React . useCallback ( ( id ) => { setNotifications ( notifications => { const index = notifications . findIndex ( ( notification ) => notification . id === id ) ; notifications . splice ( index , 1 ) ; return [ ... notifications ] ; } ) ; } , [ ] ) ; const addNotification = React . useCallback ( ( text , delay = 10000 , severity = Severity . info ) : string => { const id = uuid ( ) ; if ( lodash . some ( notifications , n => n . text === text && n . delay === delay && n . severity === severity ) ) return ; setNotifications ( [ { id , text , delay , severity } , ... notifications ] ) ; if ( delay > 0 ) { setTimeout ( ( ) => removeNotification ( id ) , delay ) ; } return id ; } , [ notifications , removeNotification ] ) ; const value = React . useMemo ( ( ) => ( { addNotification , removeNotification } ) , [ addNotification , removeNotification ] ) ; return ( < Provider value = { value } > < NotificationContainer > < AnimatePresence custom > { notifications . map ( ( { id , text , delay , severity } ) => ( < Notification id = { id } severity = { severity } key = { `notification-${ id }` } initial = { { opacity : 0 , y : - 50 } } animate = { { opacity : 1 , y : 0 } } exit = { { opacity : 0 , y : 50 } } > < div dangerouslySetInnerHTML = { { __html : text } } /> < /Notification>))} < /AnimatePresence> < /NotificationContainer> { children } < /Provider>); } ; export const useNotification = ( ) : [ ( text : string , delay ? : number , severity ? : Severity ) => void , ( ) => void ] => { const { addNotification , removeNotification } = React . useContext ( notificationContext ) ; const [ ids , setIds ] = React . useState ( [ ] ) ; const show = ( text , delay = 10000 , severity = Severity . info ) => { if ( ids . length > 0 && delay === 0 ) return ; setIds ( [ ... ids , addNotification ( text , delay , severity ) ] ) ; } ; const remove = ( ) => { if ( ids . length <= 0 ) return ; const [ id , ... rest ] = ids ; removeNotification ( id ) ; setIds ( rest ) ; } ; return [ show , remove ] ; } ; export const NotificationContext = { Provider : NotificationProvider , Context : notificationContext , useNotification } ; export * from './components' ;