UNPKG

@itwin/itwinui-react

Version:

A react component library for iTwinUI

141 lines (140 loc) 3.63 kB
import * as React from 'react'; import cx from 'classnames'; import { Box, useSafeContext } from '../../utils/index.js'; import { Toast } from './Toast.js'; export const useToaster = () => { let dispatch = useSafeContext(ToasterDispatchContext); return React.useMemo(() => { let showToast = (category) => (content, options) => { let id = nextId(); dispatch({ type: 'add', toast: { ...options, id, content, category, }, }); return { close: () => dispatch({ type: 'remove', id, }), }; }; return { positive: showToast('positive'), informational: showToast('informational'), negative: showToast('negative'), warning: showToast('warning'), closeAll: () => { dispatch({ type: 'close-all', }); }, setSettings: (settings) => { dispatch({ type: 'settings', settings, }); }, }; }, [dispatch]); }; export const Toaster = () => { let { toasts, settings } = useSafeContext(ToasterStateContext); return React.createElement( Box, { className: cx('iui-toast-wrapper', `iui-placement-${settings.placement}`), }, toasts.map((toastProps) => React.createElement(Toast, { key: toastProps.id, ...toastProps, }), ), ); }; export const ToastProvider = ({ children, inherit = false }) => { let [toasterState, dispatch] = React.useReducer(toastReducer, { toasts: [], settings: { order: 'auto', placement: 'top', }, }); let toasterDispatchContext = React.useContext(ToasterDispatchContext); let toasterStateContext = React.useContext(ToasterStateContext); let shouldReuse = toasterStateContext && inherit; let toasterDispatchContextValue = shouldReuse ? toasterDispatchContext : dispatch; let toasterStateContextValue = shouldReuse ? toasterStateContext : toasterState; return React.createElement( ToasterDispatchContext.Provider, { value: toasterDispatchContextValue, }, React.createElement( ToasterStateContext.Provider, { value: toasterStateContextValue, }, children, ), ); }; let toastReducer = (state, action) => { if ('add' === action.type) { let order = state.settings.order; if ('auto' === order) order = state.settings.placement.startsWith('top') ? 'descending' : 'ascending'; return { ...state, toasts: [ ...('ascending' === order ? state.toasts : []), action.toast, ...('descending' === order ? state.toasts : []), ], }; } if ('remove' === action.type) return { ...state, toasts: state.toasts.filter((toast) => toast.id !== action.id), }; if ('close-all' === action.type) return { ...state, toasts: state.toasts.map((toast) => ({ ...toast, isVisible: false, })), }; if ('settings' === action.type) return { ...state, settings: { ...state.settings, ...action.settings, }, }; return state; }; export const ToasterStateContext = React.createContext(void 0); if ('development' === process.env.NODE_ENV) ToasterStateContext.displayName = 'ToasterStateContext'; let ToasterDispatchContext = React.createContext(void 0); if ('development' === process.env.NODE_ENV) ToasterDispatchContext.displayName = 'ToasterDispatchContext'; let nextId = (() => { let count = 0; return () => ++count; })();