forked from flexport/__latitude
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathBanner.jsx
202 lines (187 loc) · 4.86 KB
/
Banner.jsx
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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/**
* TEAM: frontend_infra
* @flow strict
*/
/* eslint-disable flexport/no-unused-aphrodite-styles */
import * as React from "react";
import {StyleSheet, css} from "aphrodite";
import Icon, {type IconNames} from "./Icon";
import invariant from "./tools/invariant";
import IconButton from "./button/IconButton";
import latitudeColors, {type Color} from "./colors";
import Text from "./Text";
type Intent = "default" | "default-light" | "warning" | "danger";
type Props = {|
/**
* defines the visual style which conveys the level of importance / urgency
* to the user
*/
+intent?: Intent,
/** the name of the icon to be displayed on the left of the banner */
+iconName?: IconNames,
/** the message that will appear at the center of the banner */
+message: string | React.Element<typeof Text>,
/** additional content to display in the banner below the message */
+additionalContent?: React.Node,
/**
* The call to action button that will appear below the banner message.
* This button should have intent "basic" and kind "blank"
*/
+ctaButton?: React.Node,
/**
* Called when the close button is pressed. If an onClose
* isn't provided, the close button will not appear
*/
+onClose?: () => void,
|};
/**
* @category Data Display
* @short Spans the entire width of its parent and displays a informing message
* @brandStatus V2
* @status Beta
*
* The banner component is used to provide feedback to the user such as when
* an app update has occured or when there are errors returned from the server.
* Banners can also be used to display passive messages such as when times are
* being displayed in a separate timezone or when the user is impersonating
* a client.
*/
export default function Banner({
intent = "default",
iconName,
message,
additionalContent,
ctaButton,
onClose,
}: Props) {
invariant(
!(intent === "danger" && ctaButton),
"Danger Banners cannot have a call to action button"
);
const messageContent = message === "string" ? <Text>message</Text> : message;
const iconColor = getIconColor(intent);
const ctaButtonContent =
ctaButton != null ? (
<div className={css(styles.ctaButtonWrapper)}>{ctaButton}</div>
) : null;
const additionalContentNode =
additionalContent != null ? (
<div className={css(styles.additionalContentWrapper)}>
{additionalContent}
</div>
) : null;
let closeNode = null;
if (onClose) {
closeNode = (
<div
className={css(
styles.closeWrapper,
intent === "danger" && styles.closeWrapperDanger
)}
>
<IconButton
iconName="cancel"
onClick={onClose}
kind="blank"
intent="none"
type="button"
size="l"
/>
</div>
);
}
return (
<div
className={css(
styles.container,
styles[intent],
additionalContent != null && styles.closeButtonWrapper
)}
>
<div className={css(styles.contentWrapper)}>
<div className={css(styles.iconWrapper)}>
{iconName && <Icon size="s" iconName={iconName} color={iconColor} />}
</div>
<div className={css(styles.content)}>
{messageContent}
{additionalContentNode}
{ctaButtonContent}
</div>
</div>
{closeNode}
</div>
);
}
const getIconColor = (intent: Intent): Color => {
if (intent === "danger") {
return "white";
} else if (intent === "warning") {
return "red40";
}
return "grey60";
};
const styles = StyleSheet.create({
container: {
display: "flex",
flexDirection: "row",
borderRadius: "0",
alignItems: "flex-start",
},
closeButtonWrapper: {
alignItems: "baseline",
},
contentWrapper: {
display: "flex",
flexDirection: "row",
flex: 1,
},
iconWrapper: {
marginRight: "20px",
},
closeWrapper: {
width: "20px",
height: "20px",
},
closeWrapperDanger: {
":nth-child(1n) > button > span > svg": {
fill: latitudeColors.white,
animationDuration: "0",
},
":nth-child(1n) > button > span > svg :hover": {
fill: latitudeColors.white,
},
},
content: {
display: "flex",
flexDirection: "column",
flex: "1",
marginRight: "20px",
lineHeight: "20px",
},
additionalContentWrapper: {
marginTop: "8px",
},
ctaButtonWrapper: {
paddingTop: "8px",
},
default: {
background: latitudeColors.grey10,
padding: "18px",
border: `2px solid ${latitudeColors.grey20}`,
},
"default-light": {
background: latitudeColors.white,
padding: "18px",
border: `2px solid ${latitudeColors.grey20}`,
},
warning: {
border: `2px solid ${latitudeColors.red40}`,
padding: "18px",
background: latitudeColors.white,
},
danger: {
background: latitudeColors.red40,
padding: "20px",
color: latitudeColors.white,
},
});