import { IconMASuccess1, IconMAFail1, IconMAWarning1, } from '../../icons'; import React, { useEffect, useState, useImperativeHandle, forwardRef, memo, ComponentType, isValidElement, } from 'react'; import { StyleSheet, Text, View, TouchableWithoutFeedback, StyleProp, ViewStyle, } from 'react-native'; import type { ToastProps, ToastType, ToastMethods } from './interface'; import { Popup, 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 Toast = forwardRef( ( { type = 'text', position = 'middle', message, numberOfLines = 2, overlay = false, forbidPress = false, closeOnPress = false, closeOnPressOverlay = false, duration = 2000, icon, onPressOverlay, ...reset }, ref ) => { const token = useTheme(); const styles = createStyle(token); const [show, setShow] = useState(false); const [msg, setMsg] = useState(message); // 修正数据 if (closeOnPress) { // 是否在点击后关闭 // 是否禁止背景点击 // 可以触发点击的地方正好被背景 View 挡住 forbidPress = false; } /** * 点击遮罩层 */ const onPopupPressOverlay = () => { // 是否在点击遮罩层后关闭 if (closeOnPressOverlay) { setShow(false); } // 点击遮罩回调方法 if (overlay) { onPressOverlay && onPressOverlay(); } }; /** * 点击内容 */ const onPressContent = () => { // 是否在点击后关闭 if (closeOnPress) { setShow(false); } }; const renderIcon = () => { const hasIcon = icon || ['success', 'fail', 'warn', 'loading'].includes(type || ''); if (hasIcon) { if (isValidElement(icon)) return icon; if (['success', 'fail', 'warn'].includes(type || '')) { return rnRenderIcon(type, { size: 44, fillColor: '#FFFFFF' }); } if (type === 'loading') { return ; } } return null; }; useEffect(() => { setShow(true); let timer: ReturnType; if (duration !== 0) { timer = setTimeout(() => { // 隐藏弹窗 setShow(false); }, duration); } return () => { clearTimeout(timer); }; }, [duration]); // 向外暴露方法 useImperativeHandle( ref, () => ({ show: () => { setShow(true); }, close: () => { setShow(false); }, setMessage: (s) => { setMsg(s); }, }), [] ); const posMap = { top: 'flex-start', bottom: 'flex-end', middle: 'center' }; return ( , ])} pointerEvents={forbidPress ? undefined : 'box-none'} collapsable={false} > {renderIcon()} {msg} ); } ); export default memo(Toast);