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;
|