Skip to content

Commit

Permalink
refactor toast (#494)
Browse files Browse the repository at this point in the history
* refactor(toast): update api

* chore(toast): update snapshot

* refactor(toast): use parseTNode

* fix: fix cr

---------

Co-authored-by: anlyyao <[email protected]>
  • Loading branch information
novlan1 and anlyyao authored Sep 19, 2024
1 parent 55cb32d commit 9521869
Show file tree
Hide file tree
Showing 26 changed files with 820 additions and 378 deletions.
2 changes: 1 addition & 1 deletion site/mobile/mobile.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ export default {
{
title: 'Toast 轻提示',
name: 'toast',
component: () => import('tdesign-mobile-react/toast/_example/index.jsx'),
component: () => import('tdesign-mobile-react/toast/_example/index.tsx'),
},
{
title: 'Drawer 抽屉',
Expand Down
100 changes: 76 additions & 24 deletions src/toast/Toast.tsx
Original file line number Diff line number Diff line change
@@ -1,38 +1,83 @@
import React, { FC, useRef, useState, useEffect } from 'react';
import { Icon } from 'tdesign-icons-react';
import { LoadingIcon, CheckCircleIcon, CloseCircleIcon } from 'tdesign-icons-react';
import { CSSTransition } from 'react-transition-group';
import classNames from 'classnames';
import Overlay from '../overlay';
import useMessageCssTransition from './hooks/useMessageCssTransition';
import useConfig from '../_util/useConfig';
import { TdToastProps } from './type';
import { IconType } from './constant';
import { StyledProps } from '../common';
import { toastDefaultProps } from './defaultProps';
import { usePrefixClass } from '../hooks/useClass';
import { useLockScroll } from '../hooks/useLockScroll';
import useDefaultProps from '../hooks/useDefaultProps';
import parseTNode from '../_util/parseTNode';

interface ToastProps extends TdToastProps {
interface ToastProps extends TdToastProps, StyledProps {
children?: React.ReactNode;
el: React.ReactNode;
}

const Toast: FC<TdToastProps> = (props: ToastProps) => {
const themeIconMap = {
loading: <LoadingIcon />,
success: <CheckCircleIcon />,
error: <CloseCircleIcon />,
};

const Toast: FC<ToastProps> = (originProps) => {
const props = useDefaultProps<ToastProps>(originProps, toastDefaultProps);
const {
direction = 'row',
placement = 'middle',
className,
style,
direction,
placement,
icon,
message,
// children,
duration,
theme,
preventScrollThrough,
showOverlay,
overlayProps,
el,
onClose,
} = props;

const { classPrefix } = useConfig();
const cls = `${classPrefix}-overflow-hidden`;
const TIcon = icon || (theme && <Icon className={`${classPrefix}-icon`} name={IconType[theme]} />);
const containerClass = [
`${classPrefix}-toast--${direction || 'row'}`,
`${classPrefix}-toast--${placement}`,
icon && !message && `${classPrefix}-toast--icononly`,
];
const toastClass = usePrefixClass('toast');
const iconClasses = classNames([
{
[`${toastClass}__icon--${direction}`]: direction,
},
]);

const renderIconNode = () => {
if (icon) return parseTNode(icon);
return themeIconMap[theme];
};

const containerClass = classNames([
`${toastClass}`,
`${toastClass}__content`,
`${toastClass}__icon`,
{
[`${toastClass}--${direction}`]: direction,
[`${toastClass}__content--${direction}`]: direction,
[`${toastClass}--loading`]: theme === 'loading',
},
className,
]);
const topOptions = {
top: '25%',
bottom: '75%',
};
const computedStyle = { ...style, top: topOptions[placement] ?? '45%' };

const textClasses = classNames([
`${toastClass}__text`,
{
[`${toastClass}__text--${direction}`]: direction,
},
]);

const contentRef = useRef<HTMLDivElement>(null);

Expand All @@ -44,32 +89,39 @@ const Toast: FC<TdToastProps> = (props: ToastProps) => {

const [toastVisible, setToastVisible] = useState<boolean>(true);

useLockScroll(contentRef, toastVisible && preventScrollThrough, toastClass);

useEffect(() => {
let timer = null;
if (duration) {
timer = setTimeout(() => {
setToastVisible(false);
onClose?.();
}, duration);
}
return () => {
clearTimeout(timer);
};
}, [duration]);
}, [duration, onClose]);

useEffect(() => {
preventScrollThrough && document.body.classList.add(cls);
return () => {
preventScrollThrough && document.body.classList.remove(cls);
const getCustomOverlayProps = () => {
const toastOverlayProps = {
preventScrollThrough,
visible: showOverlay,
};
return {
...overlayProps,
...toastOverlayProps,
};
}, [preventScrollThrough, cls]);
};

return (
<>
{preventScrollThrough && <Overlay />}
{showOverlay && <Overlay {...getCustomOverlayProps()} />}
<CSSTransition in={toastVisible} appear {...cssTransitionState.props} unmountOnExit>
<div className={classNames(`${classPrefix}-toast`, [...containerClass])} ref={contentRef}>
{TIcon && TIcon}
{message && <div className={classNames(`${classPrefix}-toast__text`)}>{message}</div>}
<div className={containerClass} ref={contentRef} style={computedStyle}>
<div className={iconClasses}>{renderIconNode()}</div>
{message && <div className={textClasses}>{parseTNode(message)}</div>}
</div>
</CSSTransition>
</>
Expand Down
50 changes: 0 additions & 50 deletions src/toast/_example/base.jsx

This file was deleted.

50 changes: 50 additions & 0 deletions src/toast/_example/base.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import React from 'react';
import { Toast, Button } from 'tdesign-mobile-react';

export default function () {
const onlyText = () => {
Toast('轻提示文字内容');
};

const textMaxHeight = () => {
Toast({
message: '最多一行展示十个汉字宽度限制最多不超过三行文字行文字行文字',
});
};

const iconHori = () => {
Toast({ message: '轻提示文字内容', theme: 'success' });
};

const iconColumn = () => {
Toast({ message: '轻提示文字内容', theme: 'success', direction: 'column' });
};

const iconLoading = () => {
Toast({ message: '轻提示文字内容', theme: 'loading' });
};

return (
<div className="toast-demo">
<Button block theme="primary" variant="outline" size="large" onClick={onlyText}>
纯文本
</Button>

<Button block theme="primary" variant="outline" size="large" onClick={textMaxHeight}>
多行文字
</Button>

<Button block theme="primary" variant="outline" size="large" onClick={iconHori}>
带横向图标
</Button>

<Button block theme="primary" variant="outline" size="large" onClick={iconColumn}>
带竖向图标
</Button>

<Button block theme="primary" variant="outline" size="large" onClick={iconLoading}>
加载状态
</Button>
</div>
);
}
32 changes: 32 additions & 0 deletions src/toast/_example/close.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import React from 'react';
import { Toast, Button } from 'tdesign-mobile-react';

export default function () {
const showToast = () => {
Toast({
message: '轻提示文字内容',
onClose: () => {
console.log('onClose');
},
onDestroy: () => {
console.log('onDestroy');
},
});
};

const hideToast = () => {
Toast.clear();
};

return (
<div className="toast-demo">
<Button block theme="primary" variant="outline" size="large" onClick={showToast}>
显示提示
</Button>

<Button block theme="primary" variant="outline" size="large" onClick={hideToast}>
关闭提示
</Button>
</div>
);
}
24 changes: 24 additions & 0 deletions src/toast/_example/cover.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import React from 'react';
import { Toast, Button } from 'tdesign-mobile-react';
import { PoweroffIcon } from 'tdesign-icons-react';

export default function () {
const showMssk = () => {
Toast({
message: '禁止滑动和点击',
direction: 'column',
placement: 'bottom',
duration: 5000,
preventScrollThrough: true,
showOverlay: true,
icon: <PoweroffIcon />,
});
};
return (
<div className="toast-demo">
<Button block theme="primary" variant="outline" size="large" onClick={showMssk}>
禁止滑动和点击
</Button>
</div>
);
}
32 changes: 0 additions & 32 deletions src/toast/_example/icon.jsx

This file was deleted.

49 changes: 0 additions & 49 deletions src/toast/_example/iconText.jsx

This file was deleted.

Loading

0 comments on commit 9521869

Please sign in to comment.