@itwin/itwinui-react
Version:
A react component library for iTwinUI
141 lines (140 loc) • 3.63 kB
JavaScript
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;
})();