import React, { CSSProperties, HTMLAttributes, ReactNode, useEffect, useRef, useState } from 'react' import classnames from 'classnames' import { usePrefix } from '../ConfigProvider' import { concat } from '../utils' import { CheckCircleFilledIcon, InfoFilledIcon, TipFilledIcon, CloseCircleFilledIcon } from '../icons' import { WithRef } from '../utils/type' export { default as ToasterContainer } from './Container' export type { Props as ToasterContainerProps } from './Container' export type ToasterType = 'info' | 'error' | 'success' | 'warning' export type ToasterProps = { type?: ToasterType message: ReactNode className?: string style?: CSSProperties /** * 根元素的 html 属性 */ rootHtmlProps?: WithRef, HTMLDivElement> } export default function Toaster(props: ToasterProps) { const { className, message, type = 'info', rootHtmlProps, style } = props const prefix = usePrefix('toaster') const typePrefix = concat(prefix, type) const iconPrefix = concat(prefix, 'icon') const messagePrefix = concat(prefix, 'message') const innerIcon = getIconByType(type) const cls = classnames( className, prefix, typePrefix, rootHtmlProps?.className ) return (
{innerIcon}
{message}
) } function getIconByType(type: ToasterType) { switch (type) { case 'info': default: return case 'success': return case 'error': return case 'warning': return } } export type AnimatedToasterProps = Pick & { /** 显示/隐藏 Toaster。消失动画需要先把 visible 设置为 false,等动画完成后再移除元素 */ visible?: boolean /** 自定义样式名 */ className?: string /** 自定义样式。注意:不支持自定义高度,height 设置会被忽略 */ style?: CSSProperties } export function AnimatedToaster({ visible = true, className, style, ...props }: AnimatedToasterProps) { const prefix = usePrefix('toaster-animate-container') const childRef = useRef(null) const [height, setHeight] = useState(0) useEffect(() => { setHeight(visible && childRef.current ? childRef.current.offsetHeight : 0) }, [visible, props.message]) const targetClass = concat(prefix, height > 0 ? 'show' : 'hide') return (
) }