import { useTimeout, useUpdateEffect } from '@chakra-ui/hooks';
import { isFunction, __DEV__ } from '@chakra-ui/utils';
import ReachAlert from '@reach/alert';
import { motion, useIsPresent, Variants } from 'framer-motion';
import * as React from 'react';
import { ToastOptions } from './toast.types';
import { getToastStyle } from './toast.utils';
/**
* @todo After Gerrit refactors this implementation, allow users to change the toast transition
* direction from a `ToastProvider` component.
*
* Here's an API example:
*
* ```jsx
* ;
* ```
*/
const toastMotionVariants: Variants = {
initial: props => {
const { position } = props;
const dir = ['top', 'bottom'].includes(position) ? 'y' : 'x';
let factor = ['top-right', 'bottom-right'].includes(position) ? 1 : -1;
if (position === 'bottom') factor = 1;
return {
opacity: 0,
[dir]: factor * 24,
};
},
animate: {
opacity: 1,
y: 0,
x: 0,
scale: 1,
transition: {
duration: 0.4,
ease: [0.4, 0, 0.2, 1],
},
},
exit: {
opacity: 0,
scale: 0.85,
transition: {
duration: 0.2,
ease: [0.4, 0, 1, 1],
},
},
};
export interface ToastProps extends ToastOptions {}
export const Toast: React.FC = props => {
const {
id,
message,
onCloseComplete,
onRequestRemove,
requestClose = false,
position = 'bottom',
duration = 5000,
} = props;
const [delay, setDelay] = React.useState(duration);
const isPresent = useIsPresent();
useUpdateEffect(() => {
if (!isPresent) {
onCloseComplete?.();
}
}, [isPresent]);
useUpdateEffect(() => {
setDelay(duration);
}, [duration]);
const onMouseEnter = () => setDelay(null);
const onMouseLeave = () => setDelay(duration);
const close = () => {
if (isPresent) onRequestRemove();
};
React.useEffect(() => {
if (isPresent && requestClose) {
onRequestRemove();
}
}, [isPresent, requestClose, onRequestRemove]);
useTimeout(close, delay);
const style = React.useMemo(() => getToastStyle(position), [position]);
return (
{isFunction(message) ? message({ id, onClose: close }) : message}
);
};
if (__DEV__) {
Toast.displayName = 'Toast';
}