Skip to content

Commit 4741e67

Browse files
committed
fix: refactor CToast components:
- CToast: delete 'header', 'headerSlot', 'custom', 'transition' props fix animation, allow for cancelling autohide when it starts hidding, correct animation times, add 'onStateChange' prop - CToastHeader - add default closing button - delete tag prop from components, clean comopnents
1 parent abfb1d1 commit 4741e67

File tree

5 files changed

+139
-176
lines changed

5 files changed

+139
-176
lines changed

src/CToast.js

+83-108
Original file line numberDiff line numberDiff line change
@@ -1,150 +1,125 @@
1-
import React, {useState} from 'react';
2-
import PropTypes from 'prop-types';
3-
import classNames from 'classnames';
4-
import {tagPropType, mapToCssModules} from './Shared/helper.js';
5-
import Slot from './Shared/Slot';
6-
import CToastHeader from './CToastHeader';
7-
import CToastBody from './CToastBody';
8-
import CButtonClose from './CButtonClose';
9-
import CFade from './CFade';
10-
import style from './CToast.module.css';
1+
import React, { useState, useEffect } from 'react'
2+
import PropTypes from 'prop-types'
3+
import classNames from 'classnames'
4+
import { mapToCssModules } from './Shared/helper.js'
5+
import CFade from './CFade'
6+
import style from './CToast.module.css'
117

12-
//component - CoreUI / CToast
8+
export const Context = React.createContext({})
139

14-
const CToast = props=>{
10+
//component - CoreUI / CToast
11+
const CToast = props => {
1512

1613
const {
17-
tag: Tag,
1814
className,
1915
cssModule,
20-
custom,
16+
children,
2117
//
2218
innerRef,
2319
show,
24-
header,
25-
headerSlot,
2620
autohide,
27-
closeButton,
2821
fade,
29-
transition,
22+
onStateChange,
3023
...attributes
31-
} = props;
32-
33-
const [shown, setShown] = useState(show);
34-
35-
const transitionPar = {
36-
...CFade.defaultProps,
37-
...transition,
38-
baseClass: fade ? transition.baseClass : '',
39-
timeout: fade ? transition.timeout : 0,
40-
};
41-
42-
let timeout;
43-
44-
const setAutohide = ()=>{
45-
timeout = setTimeout(()=>{
46-
setShown(false);
47-
}, autohide);
24+
} = props
25+
26+
const [state, setState] = useState(show)
27+
const [timer, setTimer] = useState()
28+
29+
useEffect(() => {
30+
setState(show)
31+
}, [show])
32+
33+
useEffect(() => {
34+
if (state === true && autohide) {
35+
setAutohide()
36+
}
37+
onStateChange && onStateChange(state)
38+
return () => clearTimeout(timer)
39+
}, [state])
40+
41+
const setAutohide = () => {
42+
clearTimeout(timer)
43+
setTimer(setTimeout(() => {
44+
startAutohide()
45+
}, autohide))
4846
}
4947

50-
const onMouseOver = ()=>{
51-
clearTimeout(timeout);
48+
const onMouseOver = () => {
49+
if (state !== 'closing') {
50+
state !== true && setState(true)
51+
clearTimeout(timer)
52+
}
5253
}
53-
const onMouseOut = ()=>{
54-
if (autohide)
55-
setAutohide();
54+
55+
const onMouseOut = () => {
56+
if (autohide && state !== 'closing') {
57+
setAutohide()
58+
}
5659
}
57-
const onClick = ()=>{
58-
setShown(false);
60+
61+
const startAutohide = () => {
62+
setState('hiding')
63+
clearTimeout(timer)
64+
setTimer(setTimeout(() => {
65+
setState(false)
66+
}, 2000))
5967
}
6068

61-
if (autohide){
62-
setAutohide();
69+
const close = () => {
70+
setState(fade ? 'closing' : false)
71+
clearTimeout(timer)
72+
fade && setTimer(setTimeout(() => {
73+
setState(false)
74+
}, 500))
6375
}
6476

6577
// render
66-
6778
const classes = mapToCssModules(classNames(
68-
className,
69-
'toast',
70-
'mytoast',
71-
), Object.assign(style, cssModule));
72-
73-
if (!shown)
74-
return null;
75-
76-
if (!custom)
77-
return (
78-
<CFade
79-
{...attributes}
80-
{...transitionPar}
81-
tag={Tag}
82-
className={classes}
83-
in={true}
84-
role="alert"
85-
innerRef={innerRef}
86-
>
87-
<Tag
88-
{...attributes}
79+
'toast', className
80+
), cssModule)
81+
82+
const fadeClasses = classNames(
83+
fade && style[`${state === 'hiding' ? 'slowfade' : 'fade' }`]
84+
)
85+
86+
return (
87+
<Context.Provider value={{ close }}>
88+
{
89+
state && <CFade
90+
tag={'div'}
91+
className={classes}
92+
role="alert"
8993
aria-live="assertive"
9094
aria-atomic="true"
95+
{...attributes}
96+
in={state === true}
9197
onMouseOver={onMouseOver}
9298
onMouseOut={onMouseOut}
93-
className={classes}
99+
baseClass={fadeClasses}
100+
innerRef={innerRef}
94101
>
95-
<CToastHeader>
96-
{
97-
headerSlot || header?
98-
<Slot content={headerSlot}>
99-
<strong className="mr-auto">{header}</strong>
100-
</Slot>:''
101-
}
102-
{
103-
closeButton?
104-
<CButtonClose className='ml-2 mb-1' onClick={onClick}/>:''
105-
}
106-
</CToastHeader>
107-
<CToastBody>
108-
{attributes.children}
109-
</CToastBody>
110-
</Tag>
111-
</CFade>
112-
);
113-
114-
return (
115-
<Tag {...attributes} onMouseOver={onMouseOver} onMouseOut={onMouseOut} className={classes} ref={innerRef} />
116-
);
117-
102+
{children}
103+
</CFade>
104+
}
105+
</Context.Provider>
106+
)
118107
}
119108

120109
CToast.propTypes = {
121-
tag: tagPropType,
122110
className: PropTypes.string,
123111
cssModule: PropTypes.object,
124-
custom: PropTypes.bool,
112+
children: PropTypes.node,
125113
//
126-
headerSlot: PropTypes.node,
127114
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.object]),
128115
show: PropTypes.bool,
129-
header: PropTypes.string,
130116
autohide: PropTypes.oneOfType([PropTypes.number, PropTypes.bool]),
131-
closeButton: PropTypes.bool,
132117
fade: PropTypes.bool,
133-
transition: PropTypes.shape(CFade.propTypes),
134-
role: PropTypes.string
118+
onStateChange: PropTypes.func
135119
};
136120

137121
CToast.defaultProps = {
138-
custom: true,
139-
tag: 'div',
140-
autohide: 1500,
141-
closeButton: true,
142-
fade: true,
143-
transition: {
144-
...CFade.defaultProps,
145-
unmountOnExit: true,
146-
},
147-
role: 'alert',
122+
fade: true
148123
};
149124

150-
export default CToast;
125+
export default CToast

src/CToast.module.css

+2-8
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,6 @@
1-
.mytoast {
2-
opacity: inherit;
3-
}
4-
.fade-enter-active {
1+
.fade {
52
transition: opacity .5s;
63
}
7-
.fade-leave-active {
4+
.slowfade {
85
transition: opacity 2s;
96
}
10-
.fade-enter, .fade-leave-to {
11-
opacity: 0;
12-
}

src/CToastBody.js

+11-20
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,35 @@
1-
import React from 'react';
2-
import PropTypes from 'prop-types';
3-
import classNames from 'classnames';
4-
import {tagPropType, mapToCssModules} from './Shared/helper.js';
1+
import React from 'react'
2+
import PropTypes from 'prop-types'
3+
import classNames from 'classnames'
4+
import { mapToCssModules } from './Shared/helper.js'
55

66
//component - CoreUI / CToastBody
77

8-
const CToastBody = props=>{
8+
const CToastBody = props => {
99

1010
const {
11-
tag: Tag,
1211
className,
1312
cssModule,
1413
//
1514
innerRef,
1615
...attributes
17-
} = props;
16+
} = props
1817

1918
//render
20-
2119
const classes = mapToCssModules(classNames(
22-
className,
23-
'toast-body'
24-
), cssModule);
20+
'toast-body', className
21+
), cssModule)
2522

2623
return (
27-
<Tag {...attributes} className={classes} ref={innerRef} />
28-
);
29-
24+
<div className={classes} {...attributes} ref={innerRef}/>
25+
)
3026
}
3127

3228
CToastBody.propTypes = {
33-
tag: tagPropType,
3429
className: PropTypes.string,
3530
cssModule: PropTypes.object,
3631
//
3732
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.object])
3833
};
3934

40-
CToastBody.defaultProps = {
41-
tag: 'div'
42-
};
43-
44-
export default CToastBody;
35+
export default CToastBody

src/CToastHeader.js

+26-19
Original file line numberDiff line numberDiff line change
@@ -1,44 +1,51 @@
1-
import React from 'react';
2-
import PropTypes from 'prop-types';
3-
import classNames from 'classnames';
4-
import {tagPropType, mapToCssModules} from './Shared/helper.js';
1+
import React, { useContext } from 'react'
2+
import PropTypes from 'prop-types'
3+
import classNames from 'classnames'
4+
import { mapToCssModules } from './Shared/helper.js'
5+
import CButtonClose from './CButtonClose'
56

6-
//component - CoreUI / CToastHeader
7+
import { Context } from './CToast'
78

8-
const CToastHeader = props=>{
9+
//component - CoreUI / CToastHeader
10+
const CToastHeader = props => {
911

1012
const {
11-
tag: Tag,
1213
className,
1314
cssModule,
15+
children,
1416
//
1517
innerRef,
18+
closeButton,
1619
...attributes
17-
} = props;
20+
} = props
1821

22+
const { close } = useContext(Context)
23+
1924
//render
20-
2125
const classes = mapToCssModules(classNames(
22-
className,
23-
'toast-header'
24-
), cssModule);
26+
'toast-header', className
27+
), cssModule)
2528

2629
return (
27-
<Tag {...attributes} className={classes} ref={innerRef} />
28-
);
29-
30+
<div className={classes} {...attributes} ref={innerRef}>
31+
{ children }
32+
{ closeButton &&
33+
<CButtonClose className="ml-auto" onClick={close}/>}
34+
</div>
35+
)
3036
}
3137

3238
CToastHeader.propTypes = {
33-
tag: tagPropType,
3439
className: PropTypes.string,
3540
cssModule: PropTypes.object,
41+
children: PropTypes.node,
3642
//
37-
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.object])
43+
innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.string, PropTypes.object]),
44+
closeButton: PropTypes.bool
3845
};
3946

4047
CToastHeader.defaultProps = {
41-
tag: 'div'
48+
closeButton: true
4249
};
4350

44-
export default CToastHeader;
51+
export default CToastHeader

0 commit comments

Comments
 (0)