-
-
Notifications
You must be signed in to change notification settings - Fork 4.6k
Expand file tree
/
Copy pathtoastIndicator.tsx
More file actions
125 lines (110 loc) · 2.94 KB
/
toastIndicator.tsx
File metadata and controls
125 lines (110 loc) · 2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
import * as React from 'react';
import styled from '@emotion/styled';
import classNames from 'classnames';
import {motion} from 'framer-motion';
import {Indicator} from 'app/actionCreators/indicator';
import LoadingIndicator from 'app/components/loadingIndicator';
import {IconCheckmark, IconClose} from 'app/icons';
import {t} from 'app/locale';
import space from 'app/styles/space';
import testableTransition from 'app/utils/testableTransition';
type Props = {
indicator: Indicator;
onDismiss: (indicator: Indicator, event: React.MouseEvent) => void;
className?: string;
};
function ToastIndicator({indicator, onDismiss, className, ...props}: Props) {
let icon: React.ReactNode;
const {options, message, type} = indicator;
const {undo, disableDismiss} = options || {};
const showUndo = typeof undo === 'function';
const handleClick = (e: React.MouseEvent) => {
if (disableDismiss) {
return;
}
if (typeof onDismiss === 'function') {
onDismiss(indicator, e);
}
};
if (type === 'success') {
icon = <IconCheckmark size="lg" isCircled />;
} else if (type === 'error') {
icon = <IconClose size="lg" isCircled />;
}
// TODO(billy): Remove ref- className after removing usage from getsentry
return (
<Toast
onClick={handleClick}
data-test-id={type ? `toast-${type}` : 'toast'}
className={classNames(className, 'ref-toast', `ref-${type}`)}
{...props}
>
{type === 'loading' ? (
<StyledLoadingIndicator mini />
) : (
<Icon type={type}>{icon}</Icon>
)}
<Message>{message}</Message>
{showUndo && <Undo onClick={undo}>{t('Undo')}</Undo>}
</Toast>
);
}
const Toast = styled(motion.div)`
display: flex;
align-items: center;
height: 40px;
padding: 0 15px 0 10px;
margin-top: 15px;
background: ${p => p.theme.gray500};
color: #fff;
border-radius: 44px 7px 7px 44px;
box-shadow: 0 4px 12px 0 rgba(47, 40, 55, 0.16);
position: relative;
`;
Toast.defaultProps = {
initial: {
opacity: 0,
y: 70,
},
animate: {
opacity: 1,
y: 0,
},
exit: {
opacity: 0,
y: 70,
},
transition: testableTransition({
type: 'spring',
stiffness: 450,
damping: 25,
}),
};
const Icon = styled('div', {shouldForwardProp: p => p !== 'type'})<{type: string}>`
margin-right: ${space(0.75)};
svg {
display: block;
}
color: ${p => (p.type === 'success' ? p.theme.green300 : p.theme.red300)};
`;
const Message = styled('div')`
flex: 1;
`;
const Undo = styled('div')`
display: inline-block;
color: ${p => p.theme.gray300};
padding-left: ${space(2)};
margin-left: ${space(2)};
border-left: 1px solid ${p => p.theme.gray200};
cursor: pointer;
&:hover {
color: ${p => p.theme.gray200};
}
`;
const StyledLoadingIndicator = styled(LoadingIndicator)`
.loading-indicator {
border-color: ${p => p.theme.gray500};
border-left-color: ${p => p.theme.purple300};
}
`;
export default ToastIndicator;