import * as React from 'react'; import * as PropTypes from 'prop-types'; import { Container } from 'reakit'; import { ActionMap, EffectMap } from 'constate/dist/ts/src'; // @ts-ignore import _uniqueId from 'lodash/uniqueId'; import { Placement, placementPropType } from '../types'; import { LocalToastProps } from './Toast'; type Toast = LocalToastProps & { key?: string; message: string | React.ReactElement; }; type Actions = { remove: ({ key }: { key: Toast['key'] }) => void; }; type Effects = { add: (toast: Toast) => void; info: (toast: Toast) => void; success: (toast: Toast) => void; danger: (toast: Toast) => void; warning: (toast: Toast) => void; }; type State = { toasts: Array; props: {}; }; export type ToastContainerProps = { children: (props: Actions & Effects & { toasts: Array }) => React.ReactNode; placement?: Placement; }; const initialState = { autoDismissTimeout: 5000, toasts: [] }; const add = (toast: Toast) => ({ setState, state }: any) => { const { placement } = state.props; const key = _uniqueId('toast-'); const autoDismissTimeout = typeof toast.autoDismissTimeout === 'number' ? toast.autoDismissTimeout : state.autoDismissTimeout; setState((state: State) => ({ toasts: [ ...(placement.includes('bottom') ? state.toasts : []), { key, autoDismissTimeout, ...toast }, ...(!placement.includes('bottom') ? state.toasts : []) ] })); if (autoDismissTimeout > 0) { setTimeout( () => setState((state: State) => ({ toasts: state.toasts.filter(toast => toast.key !== key) })), toast.autoDismissTimeout || state.autoDismissTimeout ); } }; const effects: EffectMap = { add, info: (toast: Toast) => add({ ...toast, type: 'info' }), success: (toast: Toast) => add({ ...toast, type: 'success' }), danger: (toast: Toast) => add({ ...toast, type: 'danger' }), warning: (toast: Toast) => add({ ...toast, type: 'warning' }) }; const actions: ActionMap = { remove: ({ key }) => state => ({ toasts: state.toasts.filter(toast => toast.key !== key) }) }; export const ToastContainer: React.FunctionComponent = ({ children, ...props }) => ( {children} ); export const toastContainerPropTypes = { children: PropTypes.func.isRequired, placement: placementPropType }; ToastContainer.propTypes = toastContainerPropTypes; export const toastContainerDefaultProps: Partial = { placement: 'top-end' }; ToastContainer.defaultProps = toastContainerDefaultProps; export default ToastContainer; export const withToasts = (C: React.ComponentType) => (props: any) => ( {toast => } );