1- import React , { useEffect , useState , useRef } from 'react' ;
2- import classNames from 'classnames' ;
31import { useTimeout } from 'ahooks' ;
2+ import classNames from 'classnames' ;
43import { isObject } from 'lodash-es' ;
4+ import React , { useEffect , useRef , useState } from 'react' ;
55import { CSSTransition } from 'react-transition-group' ;
66import { CheckCircleFilledIcon , CloseIcon , ErrorCircleFilledIcon , InfoCircleFilledIcon } from 'tdesign-icons-react' ;
7-
8- import type { TdMessageProps , MessageMarquee } from './type' ;
9- import useMessageCssTransition from './hooks/useMessageCssTransition' ;
10- import useDefaultProps from '../hooks/useDefaultProps' ;
11- import { usePrefixClass } from '../hooks/useClass' ;
12-
13- import type { StyledProps , TNode } from '../common' ;
14- import parseTNode from '../_util/parseTNode' ;
157import { convertUnit } from '../_util/convertUnit' ;
16- import { messageDefaultProps } from './defaultProps' ;
17-
8+ import parseTNode from '../_util/parseTNode' ;
9+ import type { StyledProps , TNode } from '../common' ;
10+ import { usePrefixClass } from '../hooks/useClass' ;
11+ import useDefaultProps from '../hooks/useDefaultProps' ;
1812import Link from '../link' ;
13+ import { messageDefaultProps } from './defaultProps' ;
14+ import useMarqueeAnimation from './hooks/useMarqueeAnimation' ;
15+ import useMessageCssTransition from './hooks/useMessageCssTransition' ;
16+ import type { TdMessageProps } from './type' ;
1917
2018export interface MessageProps extends TdMessageProps , StyledProps {
2119 container ?: Element ;
2220 children ?: React . ReactNode ;
2321}
2422
25- interface IInnerState {
26- duration : number ;
27- offset : number ;
28- listWidth : number ;
29- itemWidth : number ;
30- scroll : {
31- marquee : boolean ;
32- speed : number ;
33- loop : number ;
34- delay : number ;
35- } ;
36- }
37-
3823const iconDefault = {
3924 info : < InfoCircleFilledIcon size = { 22 } /> ,
4025 success : < CheckCircleFilledIcon size = { 22 } /> ,
@@ -79,27 +64,10 @@ const Message: React.FC<MessageProps> = (originProps) => {
7964
8065 const name = usePrefixClass ( 'message' ) ;
8166
82- /**
83- * 获取visibleChange函数引用
84- */
85- const scrollingHandler = useRef < null | ( ( ) => void ) > ( null ) ;
86-
8767 /**
8868 * duration为0时,取消倒计时
8969 */
9070 const [ messageDuration ] = useState < number | null > ( duration || null ) ;
91- const [ state , setState ] = useState < IInnerState > ( {
92- duration : 0 ,
93- offset : 0 ,
94- listWidth : 0 ,
95- itemWidth : 0 ,
96- scroll : {
97- marquee : false ,
98- speed : 50 ,
99- loop : - 1 , // 值为 -1 表示循环播放,值为 0 表示不循环播放
100- delay : 300 ,
101- } ,
102- } ) ;
10371
10472 const [ messageVisible , setVisible ] = useState < boolean > ( visible ?? defaultVisible ) ;
10573
@@ -125,139 +93,38 @@ const Message: React.FC<MessageProps> = (originProps) => {
12593 onDurationEnd ?.( ) ;
12694 } , messageDuration ) ;
12795
128- const handleScrolling = ( ) => {
129- if ( ! marquee || ( isObject ( marquee ) && ( marquee as MessageMarquee ) ) ?. loop === 0 ) {
130- return ;
131- }
132-
133- const { loop, speed, delay } = state . scroll ;
134-
135- const scroll = {
136- marquee : true ,
137- // 负数统一当作循环播放
138- loop : Math . max (
139- props . marquee === true || ( props . marquee as MessageMarquee ) ?. loop == null
140- ? loop
141- : ( props . marquee as MessageMarquee ) ?. loop ,
142- - 1 ,
143- ) ,
144- // 速度必须为正数
145- speed : Math . max (
146- props . marquee === true || ( props . marquee as MessageMarquee ) ?. speed == null
147- ? speed
148- : ( props . marquee as MessageMarquee ) ?. speed ,
149- 1 ,
150- ) ,
151- // 延迟不可为负数
152- delay : Math . max (
153- props . marquee === true || ( props . marquee as MessageMarquee ) ?. delay == null
154- ? delay
155- : ( props . marquee as MessageMarquee ) ?. delay ,
156- 0 ,
157- ) ,
158- } ;
159- setState ( {
160- ...state ,
161- scroll,
162- offset : 0 ,
163- } ) ;
164-
165- // 设置动画
166- setTimeout ( ( ) => {
167- const textWrapDOMWidth = textWrapRef . current ?. getBoundingClientRect ( ) . width ;
168- const textDOMWidth = textRef . current ?. getBoundingClientRect ( ) . width ;
169-
170- setState ( {
171- ...state ,
172- scroll,
173- offset : - textDOMWidth ,
174- duration : textDOMWidth / state . scroll . speed ,
175- listWidth : textWrapDOMWidth ,
176- itemWidth : textDOMWidth ,
177- } ) ;
178- } , state . scroll . delay ) ;
179- } ;
180-
181- scrollingHandler . current = handleScrolling ;
182-
183- useEffect ( ( ) => {
184- scrollingHandler . current ( ) ;
185- } , [ ] ) ;
186-
187- const animateStyle = {
188- transform : state . offset ? `translateX(${ state . offset } px)` : '' ,
189- transitionDuration : `${ state . duration } s` ,
190- transitionTimingFunction : 'linear' ,
191- } ;
192-
193- const resetTransition = ( ) => {
194- setState ( {
195- ...state ,
196- duration : 0 ,
197- offset : state . listWidth ,
198- } ) ;
199-
200- setTimeout ( ( ) => {
201- setState ( {
202- ...state ,
203- offset : - state . itemWidth ,
204- duration : ( state . itemWidth + state . listWidth ) / state . scroll . speed ,
205- } ) ;
206- } , 0 ) ;
207- } ;
208-
209- // 动画结束后,初始化动画
210- const handleTransitionend = ( ) => {
211- resetTransition ( ) ;
212-
213- if ( state . scroll . loop === - 1 ) {
214- return ;
215- }
216-
217- const newState = {
218- ...state ,
219- scroll : {
220- ...state . scroll ,
221- loop : - ( - state . scroll . loop ) ,
222- } ,
223- } ;
224-
225- if ( state . scroll . loop === 0 ) {
226- newState . scroll . marquee = false ;
227- }
228-
229- setState ( newState ) ;
230- } ;
231-
23296 const onLinkClick = ( e ) => {
23397 props . onLinkClick ?.( e ) ;
23498 } ;
99+
235100 const leftIcon = parseTNode ( icon , null , iconDefault [ theme ] || iconDefault . info ) ;
236101
237102 const getLinkContent = ( ) => {
238103 if ( typeof link === 'string' ) {
239104 return < Link theme = "primary" content = { link } /> ;
240105 }
241- if ( isObject ( link ) ) {
106+
107+ // React element is also an object,need to add extra judgement
108+ if ( isObject ( link ) && ! React . isValidElement ( link ) && typeof link !== 'function' ) {
242109 return < Link theme = "primary" { ...link } /> ;
243110 }
244- return parseTNode ( link ) ;
111+
112+ return parseTNode ( link as TNode ) ;
245113 } ;
246114
247115 const clickCloseButton = ( e ) => {
248116 setVisible ( false ) ;
249- onCloseBtnClick ?.( e ) ;
117+ onCloseBtnClick ?.( { e } ) ;
250118 } ;
251119
252- const renderCloseBtn = ( ) => {
253- if ( ! closeBtn ) return ;
254-
255- return closeBtn === true ? (
256- < CloseIcon className = { `${ name } --close-btn` } size = { 22 } onClick = { clickCloseButton } />
120+ const renderCloseBtn = ( ) =>
121+ closeBtn === true ? (
122+ < CloseIcon className = { `${ name } --close-btn` } size = { 22 } />
257123 ) : (
258124 parseTNode ( closeBtn as string | TNode )
259125 ) ;
260- } ;
126+
127+ useMarqueeAnimation ( marquee , textWrapRef , textRef ) ;
261128
262129 return (
263130 < CSSTransition in = { messageVisible } appear { ...cssTransitionState . props } unmountOnExit >
@@ -268,21 +135,20 @@ const Message: React.FC<MessageProps> = (originProps) => {
268135 >
269136 < div className = { `${ name } __icon--left` } > { leftIcon } </ div >
270137 < div ref = { textWrapRef } className = { classNames ( `${ name } __text-wrap` , { [ `${ name } __text-nowrap` ] : marquee } ) } >
271- < div
272- ref = { textRef }
273- className = { `${ name } __text` }
274- style = { state . scroll . marquee ? animateStyle : { } }
275- onTransitionEnd = { handleTransitionend }
276- >
138+ < div ref = { textRef } className = { `${ name } __text` } >
277139 { parseTNode ( content ) || parseTNode ( children ) }
278140 </ div >
279141 </ div >
280142 { link && (
281- < div className = { `${ name } __link` } onClick = { onLinkClick } >
143+ < div className = { `${ name } __link` } onClick = { ( e ) => onLinkClick ( { e } ) } >
282144 { getLinkContent ( ) }
283145 </ div >
284146 ) }
285- { renderCloseBtn ( ) }
147+ { closeBtn && (
148+ < div className = { `${ name } __close-wrap ${ name } __icon--right` } onClick = { clickCloseButton } >
149+ { renderCloseBtn ( ) }
150+ </ div >
151+ ) }
286152 </ div >
287153 </ CSSTransition >
288154 ) ;
0 commit comments