diff options
Diffstat (limited to 'src/view/com/util/Toast.web.tsx')
-rw-r--r-- | src/view/com/util/Toast.web.tsx | 118 |
1 files changed, 97 insertions, 21 deletions
diff --git a/src/view/com/util/Toast.web.tsx b/src/view/com/util/Toast.web.tsx index d3b7bda33..6b99b30bf 100644 --- a/src/view/com/util/Toast.web.tsx +++ b/src/view/com/util/Toast.web.tsx @@ -4,17 +4,23 @@ import {useEffect, useState} from 'react' import {Pressable, StyleSheet, Text, View} from 'react-native' + import { - FontAwesomeIcon, - type FontAwesomeIconStyle, - type Props as FontAwesomeProps, -} from '@fortawesome/react-native-fontawesome' + convertLegacyToastType, + getToastTypeStyles, + getToastWebAnimationStyles, + type LegacyToastType, + TOAST_TYPE_TO_ICON, + TOAST_WEB_KEYFRAMES, + type ToastType, +} from '#/view/com/util/Toast.style' +import {atoms as a, useTheme} from '#/alf' const DURATION = 3500 interface ActiveToast { text: string - icon: FontAwesomeProps['icon'] + type: ToastType } type GlobalSetActiveToast = (_activeToast: ActiveToast | undefined) => void @@ -28,21 +34,82 @@ let toastTimeout: NodeJS.Timeout | undefined type ToastContainerProps = {} export const ToastContainer: React.FC<ToastContainerProps> = ({}) => { const [activeToast, setActiveToast] = useState<ActiveToast | undefined>() + const [isExiting, setIsExiting] = useState(false) + useEffect(() => { globalSetActiveToast = (t: ActiveToast | undefined) => { - setActiveToast(t) + if (!t && activeToast) { + setIsExiting(true) + setTimeout(() => { + setActiveToast(t) + setIsExiting(false) + }, 200) + } else { + setActiveToast(t) + setIsExiting(false) + } + } + }, [activeToast]) + + useEffect(() => { + const styleId = 'toast-animations' + if (!document.getElementById(styleId)) { + const style = document.createElement('style') + style.id = styleId + style.textContent = TOAST_WEB_KEYFRAMES + document.head.appendChild(style) } - }) + }, []) + + const t = useTheme() + + const toastTypeStyles = getToastTypeStyles(t) + const toastStyles = activeToast + ? toastTypeStyles[activeToast.type] + : toastTypeStyles.default + + const IconComponent = activeToast + ? TOAST_TYPE_TO_ICON[activeToast.type] + : TOAST_TYPE_TO_ICON.default + + const animationStyles = getToastWebAnimationStyles() + return ( <> {activeToast && ( - <View style={styles.container}> - <FontAwesomeIcon - icon={activeToast.icon} - size={20} - style={styles.icon as FontAwesomeIconStyle} - /> - <Text style={styles.text}>{activeToast.text}</Text> + <View + style={[ + styles.container, + { + backgroundColor: toastStyles.backgroundColor, + borderColor: toastStyles.borderColor, + ...(isExiting + ? animationStyles.exiting + : animationStyles.entering), + }, + ]}> + <View + style={[ + styles.iconContainer, + { + backgroundColor: 'transparent', + }, + ]}> + <IconComponent + fill={toastStyles.iconColor} + size="sm" + style={styles.icon} + /> + </View> + <Text + style={[ + styles.text, + a.text_sm, + a.font_bold, + {color: toastStyles.textColor}, + ]}> + {activeToast.text} + </Text> <Pressable style={styles.dismissBackdrop} accessibilityLabel="Dismiss" @@ -60,11 +127,15 @@ export const ToastContainer: React.FC<ToastContainerProps> = ({}) => { // methods // = -export function show(text: string, icon: FontAwesomeProps['icon'] = 'check') { +export function show( + text: string, + type: ToastType | LegacyToastType = 'default', +) { if (toastTimeout) { clearTimeout(toastTimeout) } - globalSetActiveToast?.({text, icon}) + + globalSetActiveToast?.({text, type: convertLegacyToastType(type)}) toastTimeout = setTimeout(() => { globalSetActiveToast?.(undefined) }, DURATION) @@ -78,12 +149,12 @@ const styles = StyleSheet.create({ bottom: 20, // @ts-ignore web only width: 'calc(100% - 40px)', - maxWidth: 350, + maxWidth: 380, padding: 20, flexDirection: 'row', alignItems: 'center', - backgroundColor: '#000c', borderRadius: 10, + borderWidth: 1, }, dismissBackdrop: { position: 'absolute', @@ -92,13 +163,18 @@ const styles = StyleSheet.create({ bottom: 0, right: 0, }, + iconContainer: { + width: 32, + height: 32, + borderRadius: 16, + alignItems: 'center', + justifyContent: 'center', + flexShrink: 0, + }, icon: { - color: '#fff', flexShrink: 0, }, text: { - color: '#fff', - fontSize: 18, marginLeft: 10, }, }) |