From 72acfcec644e448b8f1a4b1751f729db1fe84a99 Mon Sep 17 00:00:00 2001 From: Daniel Karlsson Date: Tue, 18 Oct 2022 11:57:08 +0200 Subject: [PATCH] feat(toast): use toasts from context Enables use of different ToastAnchors throughout the application sharing the toasts. --- packages/core/src/Toast/ToastsProvider.tsx | 46 +++++++++++----------- packages/core/src/Toast/context.ts | 10 +++-- packages/core/src/Toast/index.ts | 1 + packages/core/src/Toast/toastReducer.ts | 9 +---- packages/core/src/Toast/useToasts.ts | 18 ++++----- 5 files changed, 41 insertions(+), 43 deletions(-) diff --git a/packages/core/src/Toast/ToastsProvider.tsx b/packages/core/src/Toast/ToastsProvider.tsx index 52ea4787..355f3374 100644 --- a/packages/core/src/Toast/ToastsProvider.tsx +++ b/packages/core/src/Toast/ToastsProvider.tsx @@ -3,7 +3,6 @@ import { useContext, useRef, FC, - Dispatch, isValidElement, cloneElement, ReactNode, @@ -18,7 +17,7 @@ import { BaseToast } from './Toast' import { toastReducer } from './toastReducer' import { useToastCallbacks, SimpleToastsDurations } from './useToasts' -import { ToastAction, NI, ToastsContext } from './context' +import { ToastsContext } from './context' export interface ToastsPlacement { readonly justify: 'center' | 'right' @@ -65,12 +64,12 @@ export const ToastsProvider: FC = ({ children, ...toastsOptions }) => { - const __dispatchRef = useRef>(NI) + const [toasts, dispatch] = useReducer(toastReducer, new Map()) - const callbacks = useToastCallbacks(__dispatchRef, toastsOptions) + const callbacks = useToastCallbacks(dispatch, toastsOptions) return ( - + {children} ) @@ -109,25 +108,28 @@ export interface ToastsAnchorProps { } export const ToastsAnchor: FC = ({ placement }) => { - const [toasts, dispatch] = useReducer(toastReducer, new Map()) - const { hideToast, __dispatchRef } = useContext(ToastsContext) - __dispatchRef.current = dispatch - return ( - - {[...toasts.entries()].map(([id, props], index) => ( - - - - ))} - + ) } + +export const ToastContent = () => { + const { hideToast, toasts } = useContext(ToastsContext) + return ( + + {[...toasts.entries()].map(([id, props], index) => ( + + + + ))} + + ) +} diff --git a/packages/core/src/Toast/context.ts b/packages/core/src/Toast/context.ts index 7e320253..b814602a 100644 --- a/packages/core/src/Toast/context.ts +++ b/packages/core/src/Toast/context.ts @@ -1,4 +1,4 @@ -import { createContext, ReactNode, MutableRefObject, Dispatch } from 'react' +import { createContext, ReactNode, Dispatch } from 'react' import { IconType } from '../Icon' import { ALinkProps, ButtonLinkProps } from '../Link' @@ -25,6 +25,8 @@ export interface ProgressToast extends SimpleToast { } } +export type ToastsMap = ReadonlyMap + export type ShowToastHandler = (toast: BaseToastValue, id?: ToastId) => ToastId export type HideToastHandler = (id: ToastId) => void export type SimpleToastCreator = (toast: SimpleToast, id?: ToastId) => ToastId @@ -88,7 +90,8 @@ export const NI = () => { throw new Error(`Not implemented: no ToastContext set`) } export interface ToastContextType extends ToastCallbacks { - readonly __dispatchRef: MutableRefObject> + readonly dispatch: Dispatch + readonly toasts: ToastsMap } export const ToastsContext = createContext({ @@ -102,5 +105,6 @@ export const ToastsContext = createContext({ showLoadingToast: NI, showProgressToast: NI, showActionToast: NI, - __dispatchRef: { current: NI }, + dispatch: NI, + toasts: new Map(), }) diff --git a/packages/core/src/Toast/index.ts b/packages/core/src/Toast/index.ts index 472f7211..c2447b2b 100644 --- a/packages/core/src/Toast/index.ts +++ b/packages/core/src/Toast/index.ts @@ -7,3 +7,4 @@ export { ToastIconWrapper, ToastIconType, } from './toastCreators' +export { ToastContent } from './ToastsProvider' diff --git a/packages/core/src/Toast/toastReducer.ts b/packages/core/src/Toast/toastReducer.ts index 42816bd7..3c684e65 100644 --- a/packages/core/src/Toast/toastReducer.ts +++ b/packages/core/src/Toast/toastReducer.ts @@ -1,11 +1,4 @@ -import { - BaseToastValue, - ToastAction, - ToastActionType, - ToastId, -} from './context' - -export type ToastsMap = ReadonlyMap +import { ToastAction, ToastActionType, ToastsMap } from './context' /** * Given the current state (toast map) and an action, diff --git a/packages/core/src/Toast/useToasts.ts b/packages/core/src/Toast/useToasts.ts index 845f24f2..5b560d23 100644 --- a/packages/core/src/Toast/useToasts.ts +++ b/packages/core/src/Toast/useToasts.ts @@ -1,4 +1,4 @@ -import { MutableRefObject, Dispatch, useContext, useCallback } from 'react' +import { Dispatch, useContext, useCallback } from 'react' import { createToast, removeToast, removeAllToasts } from './toastActions' import { @@ -30,29 +30,27 @@ export interface SimpleToastsDurations { } export const useToastCallbacks = ( - dispatchRef: MutableRefObject>, + dispatch: Dispatch, { success, error, warning, info }: SimpleToastsDurations = {} ): ToastCallbacks => { const showToast: ShowToastHandler = useCallback( (toast, id) => { const toastAction = createToast(toast, id) - dispatchRef.current(toastAction) + dispatch(toastAction) return toastAction.id }, - [dispatchRef] + [dispatch] ) const hideToast: HideToastHandler = useCallback( id => { const toastAction = removeToast(id) - dispatchRef.current(toastAction) + dispatch(toastAction) }, - [dispatchRef] + [dispatch] ) - const clearToasts = useCallback(() => { - dispatchRef.current(removeAllToasts) - }, [dispatchRef]) + const clearToasts = useCallback(() => dispatch(removeAllToasts), [dispatch]) const showSuccessToast: SimpleToastCreator = useCallback( (toast, id) => @@ -111,7 +109,7 @@ export const useToastCallbacks = ( } export const useToasts = () => { - const { __dispatchRef, ...callbacks } = useContext(ToastsContext) + const { dispatch, toasts, ...callbacks } = useContext(ToastsContext) return callbacks }