import { IconMASuccess1, IconMAFail1, IconMAWarning1, } from '../../icons'; import React, { useState, useImperativeHandle, forwardRef, memo, ComponentType, isValidElement, useRef, useMemo, } from 'react'; import { StyleSheet, Text, View, TouchableWithoutFeedback } from 'react-native'; import type { ToastProps, ToastType, ToastMethods } from './interface'; import { Loading, useTheme, ShouldRender } from '@xrnjs/ui'; import createStyle from './styles/toast.style'; interface IconProps { color?: string; size?: string | number; fillColor?: string; } type Icon = ComponentType; const IconUrlMap: { [key: string]: Icon } = { success: IconMASuccess1, fail: IconMAFail1, warn: IconMAWarning1, }; const rnRenderIcon = (status?: ToastType, iconProps?: IconProps) => { if (!status) return null; const IconComponent = IconUrlMap[status]; if (!IconComponent) return null; return ; }; const InitToastProps = { type: 'text' as ToastProps['type'], position: 'middle' as ToastProps['position'], overlay: false, forbidPress: false, closeOnPress: false, duration: 2000, }; const ToastRoot = forwardRef((props, ref) => { const token = useTheme(); const [toastProps, setToastProps] = useState({ ...InitToastProps, ...props, }); const styles = createStyle(token); const [show, setShow] = useState(false); /** * 点击内容 */ const onPressContent = () => { // 是否在点击后关闭 if (toastProps.closeOnPressOverlay) { setShow(false); timerRef.current && clearTimeout(timerRef.current); } toastProps.onPressOverlay?.(); }; const onPressInnerContent = () => { // 是否在点击后关闭 if (toastProps.closeOnPress) { setShow(false); timerRef.current && clearTimeout(timerRef.current); } }; const renderIcon = () => { const hasIcon = toastProps.icon || ['success', 'fail', 'warn', 'loading'].includes(toastProps.type || ''); if (hasIcon) { if (isValidElement(toastProps.icon)) return toastProps.icon; if (['success', 'fail', 'warn'].includes(toastProps.type || '')) { return rnRenderIcon(toastProps.type, { size: 44, fillColor: '#FFFFFF', }); } if (toastProps.type === 'loading') { return ; } } return null; }; const timerRef = useRef>(); const handleShow = (showProps: ToastProps) => { setToastProps(showProps || {}); timerRef.current && clearTimeout(timerRef.current); setShow(true); if (showProps?.duration !== 0) { timerRef.current = setTimeout(() => { // 隐藏弹窗 setShow(false); }, showProps?.duration); } }; // 向外暴露方法 useImperativeHandle( ref, () => ({ close: () => { timerRef.current && clearTimeout(timerRef.current); setShow(false); }, show: (params: ToastProps | string) => { if (typeof params === 'string') { handleShow({ ...InitToastProps, message: params, }); return; } handleShow({ ...InitToastProps, ...params, }); }, setMessage: (s) => { handleShow({ ...toastProps, message: s, }); }, }), [] ); const getAlign = useMemo(() => { if (toastProps.position === 'bottom') return 'flex-end'; if (toastProps.position === 'top') return 'flex-start'; return 'center'; }, [toastProps.position]); return show ? ( {renderIcon()} {toastProps.message} ) : null; }); export default memo(ToastRoot);