| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | /* eslint-disable max-len */import React, { CSSProperties } from 'react';import cls from 'classnames';import PropTypes from 'prop-types';import ConfigContext, { ContextValue } from '../configProvider/context';import ToastFoundation, { ToastAdapter, ToastState, ToastProps } from '@douyinfe/semi-foundation/toast/toastFoundation';import { numbers, cssClasses, strings } from '@douyinfe/semi-foundation/toast/constants';import BaseComponent from '../_base/baseComponent';import Button from '../iconButton/index';import { IconClose, IconAlertTriangle, IconInfoCircle, IconTickCircle, IconAlertCircle } from '@douyinfe/semi-icons';import { noop } from 'lodash';import { isSemiIcon } from '../_utils';const prefixCls = cssClasses.PREFIX;export interface ToastReactProps extends ToastProps {    style?: CSSProperties;    icon?: React.ReactNode;    content: React.ReactNode;}class Toast extends BaseComponent<ToastReactProps, ToastState> {    static contextType = ConfigContext;    static propTypes = {        onClose: PropTypes.func,        content: PropTypes.node,        close: PropTypes.func,        duration: PropTypes.number,        theme: PropTypes.oneOf(strings.themes),        type: PropTypes.oneOf(strings.types),        textMaxWidth: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),        style: PropTypes.object,        className: PropTypes.string,        showClose: PropTypes.bool,        icon: PropTypes.oneOfType([PropTypes.string, PropTypes.node]),        direction: PropTypes.oneOf(strings.directions),    };    static defaultProps = {        onClose: noop,        content: '',        close: noop,        duration: numbers.duration,        textMaxWidth: 450,        showClose: true,        theme: 'normal'    };    constructor(props: ToastReactProps) {        super(props);        this.state = {};        this.foundation = new ToastFoundation(this.adapter);    }    context: ContextValue;    get adapter(): ToastAdapter {        return {            ...super.adapter,            notifyWrapperToRemove: (id: string) => {                this.props.close(id);            },            notifyClose: () => {                this.props.onClose();            },        };    }    componentDidMount() {        this.foundation.init();    }    componentWillUnmount() {        this.foundation.destroy();    }    close(e: React.MouseEvent) {        this.foundation.close(e);    }    clearCloseTimer = () => {        this.foundation.clearCloseTimer_();    };    startCloseTimer = () => {        this.foundation.startCloseTimer_();    };    renderIcon() {        const { type, icon } = this.props;        const iconMap = {            warning: <IconAlertTriangle />,            success: <IconTickCircle />,            info: <IconInfoCircle />,            error: <IconAlertCircle />        };        const iconType = iconMap[type];        const iconSize = 'large';        const iconCls = cls(`${prefixCls}-icon`, `${prefixCls}-icon-${type}`);        if (icon) {            return isSemiIcon(icon) ? React.cloneElement((icon as React.ReactElement), { size: iconSize, className: `${prefixCls}-icon` }) : icon;        }        if (type && iconType) {            return React.cloneElement(iconType, { size: iconSize, className: iconCls });        }        return null;    }    render() {        const { content, type, theme, showClose, textMaxWidth, className, style } = this.props;        const direction = this.props.direction || this.context.direction;        const toastCls = cls(prefixCls, className, {            [`${prefixCls}-${type}`]: true,            [`${prefixCls}-${theme}`]: theme === 'light',            [`${prefixCls}-rtl`]: direction === 'rtl',        });        const textStyle: CSSProperties = {};        textStyle.maxWidth = textMaxWidth;        const btnTheme = 'borderless';        const btnSize = 'small';        return (            <div                role="alert"                aria-label={`${type ? type : 'default'} type`}                className={toastCls}                style={style}                onMouseEnter={this.clearCloseTimer}                onMouseLeave={this.startCloseTimer}            >                <div className={`${prefixCls}-content`}>                    {this.renderIcon()}                    <span className={`${prefixCls}-content-text`} style={textStyle} x-semi-prop="content">                        {content}                    </span>                    {showClose && (                        <div className={`${prefixCls}-close-button`}>                            <Button                                onClick={e => this.close(e)}                                type="tertiary"                                icon={<IconClose x-semi-prop="icon" />}                                theme={btnTheme}                                size={btnSize}                            />                        </div>                    )}                </div>            </div>        );    }}export default Toast;
 |