import React, { useState, useEffect } from 'react'; import { useTransition } from 'react-spring'; import { Container, Notification, Content, Life, ErrorIcon, Message, SuccessIcon, InfoIcon, Spinner, MessageContent, MessageLife, InfoIconNotification, SuccessIconNotification, ErrorIconNotification, Title, Desc, CloseIcon, } from './style'; export type IConfigObject = { timeout?: number; config?: { tension?: number; friction?: number; precision?: number } }; export type IMessageFn = (msg: string, messageConfig?: IConfigObject) => void; export type IItem = { msg: string; key: number }; let id = 0; const getMsgIcon = (type: 'info' | 'error' | 'success' | 'warning' | 'pending') => { switch (type) { case 'error': return ; case 'info': return ; case 'success': return ; case 'warning': return ; case 'pending': return ; } }; const getNotificationIcon = (type: 'info' | 'error' | 'success' | 'warning') => { switch (type) { case 'error': return ; case 'info': return ; case 'success': return ; case 'warning': return ; } }; function MessageHub({ children, type }: any) { const config = { tension: 125, friction: 20, precision: 0.1, clamp: true }; const [refMap] = useState(() => new WeakMap()); const [cancelMap] = useState(() => new WeakMap()); const [items, setItems]: any[] = useState([]); const [timeout, setTime] = useState(2000); const transitions = useTransition(items, (item: any) => item.key, { from: { opacity: 0, height: 0, life: '100%' }, enter: (item: any) => async (next: any) => await next({ opacity: 1, height: refMap.get(item).offsetHeight }), leave: (item: any) => async (next: any, cancel: any) => { cancelMap.set(item, cancel); await next({ life: '0%' }); await next({ opacity: 0, height: 0, margin: 0, display: 'none' }); //await next({ height: 0 }); }, onRest: (item: any) => setItems((state: IItem[]) => state.filter((i: IItem) => i.key !== item.key)), config: (item: IItem, springState: string) => springState === 'leave' ? [{ duration: timeout }, config, config] : config, } as any); useEffect( () => void children((msg: string, { timeout, ...rest }: any) => { const item = { key: id++, msg, ...rest }; setItems((state: IItem[]) => [...state, item]); setTime(s => timeout); return () => { cancelMap.get(item) && cancelMap.get(item)(); setTimeout(() => { cancelMap.get(item) && cancelMap.get(item)(); }, 1001); }; }), [] ); return ( {transitions.map(({ key, item, props: { life, ...style } }: any) => type === 'notification' ? ( ref && refMap.set(item, ref)} hasIcon={item.type} data-alter={item.alternativeStyle} > {item.title && {item.title}} {getNotificationIcon(item.type)} {item.msg} {item.showProgress && } { e.stopPropagation(); cancelMap.has(item) && cancelMap.get(item)(); }} /> ) : ( ref && refMap.set(item, ref)}> {getMsgIcon(item.type)} {item.msg} {item.showProgress && } ) )} ); } export default React.forwardRef(function({ type }: any, ref: any) { return (ref.current = add)} />; });