diff options
Diffstat (limited to 'packages/ui/src/infobox/index.tsx')
-rw-r--r-- | packages/ui/src/infobox/index.tsx | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/packages/ui/src/infobox/index.tsx b/packages/ui/src/infobox/index.tsx new file mode 100644 index 000000000..bf985ea9c --- /dev/null +++ b/packages/ui/src/infobox/index.tsx | |||
@@ -0,0 +1,194 @@ | |||
1 | import { Theme } from '@meetfranz/theme'; | ||
2 | import classnames from 'classnames'; | ||
3 | import { observer } from 'mobx-react'; | ||
4 | import React, { Component } from 'react'; | ||
5 | import injectStyle from 'react-jss'; | ||
6 | // import Loader from 'react-loader'; | ||
7 | |||
8 | import { Icon } from '../'; | ||
9 | import { IWithStyle } from '../typings/generic'; | ||
10 | |||
11 | interface IProps extends IWithStyle { | ||
12 | icon?: string; | ||
13 | type?: string; | ||
14 | dismissable?: boolean; | ||
15 | onDismiss?: () => void; | ||
16 | ctaOnClick?: () => void; | ||
17 | ctaLabel?: string; | ||
18 | ctaLoading?: boolean; | ||
19 | children: React.ReactNode; | ||
20 | } | ||
21 | |||
22 | interface IState { | ||
23 | isDismissing: boolean; | ||
24 | dismissed: boolean; | ||
25 | } | ||
26 | |||
27 | const buttonStyles = (theme: Theme) => { | ||
28 | const styles = {}; | ||
29 | Object.keys(theme.styleTypes).map((style) => { | ||
30 | Object.assign(styles, { | ||
31 | [style]: { | ||
32 | background: theme.styleTypes[style].accent, | ||
33 | color: theme.styleTypes[style].contrast, | ||
34 | border: theme.styleTypes[style].border, | ||
35 | |||
36 | '& svg': { | ||
37 | fill: theme.styleTypes[style].contrast, | ||
38 | }, | ||
39 | }, | ||
40 | }); | ||
41 | }); | ||
42 | |||
43 | return styles; | ||
44 | }; | ||
45 | |||
46 | const styles = (theme: Theme) => ({ | ||
47 | wrapper: { | ||
48 | position: 'relative', | ||
49 | overflow: 'hidden', | ||
50 | }, | ||
51 | infobox: { | ||
52 | alignItems: 'center', | ||
53 | borderRadius: theme.borderRadiusSmall, | ||
54 | display: 'flex', | ||
55 | height: 'auto', | ||
56 | marginBottom: 30, | ||
57 | padding: '15px 20px', | ||
58 | top: 0, | ||
59 | transition: 'all 0.5s', | ||
60 | opacity: 1, | ||
61 | }, | ||
62 | dismissing: { | ||
63 | // position: 'absolute', | ||
64 | marginTop: -100, | ||
65 | opacity: 0, | ||
66 | }, | ||
67 | content: { | ||
68 | flex: 1, | ||
69 | }, | ||
70 | icon: { | ||
71 | marginRight: 10, | ||
72 | }, | ||
73 | close: { | ||
74 | color: (props: IProps) => theme.styleTypes[props.type ? props.type : 'primary'].contrast, | ||
75 | marginRight: -5, | ||
76 | border: 0, | ||
77 | background: 'none', | ||
78 | }, | ||
79 | cta: { | ||
80 | borderColor: (props: IProps) => theme.styleTypes[props.type ? props.type : 'primary'].contrast, | ||
81 | borderRadius: theme.borderRadiusSmall, | ||
82 | borderStyle: 'solid', | ||
83 | borderWidth: 1, | ||
84 | background: 'none', | ||
85 | color: (props: IProps) => theme.styleTypes[props.type ? props.type : 'primary'].contrast, | ||
86 | marginLeft: 15, | ||
87 | padding: [4, 10], | ||
88 | fontSize: theme.uiFontSize, | ||
89 | transition: 'opacity 0.3s', | ||
90 | |||
91 | '&:hover': { | ||
92 | opacity: 0.6, | ||
93 | }, | ||
94 | }, | ||
95 | ...buttonStyles(theme), | ||
96 | }); | ||
97 | |||
98 | @observer | ||
99 | class InfoboxComponent extends Component<IProps, IState> { | ||
100 | public static defaultProps = { | ||
101 | type: 'primary', | ||
102 | dismissable: false, | ||
103 | ctaOnClick: () => {}, | ||
104 | onDismiss: () => {}, | ||
105 | ctaLabel: '', | ||
106 | ctaLoading: false, | ||
107 | }; | ||
108 | |||
109 | state = { | ||
110 | isDismissing: false, | ||
111 | dismissed: false, | ||
112 | }; | ||
113 | |||
114 | dismiss() { | ||
115 | const { | ||
116 | onDismiss, | ||
117 | } = this.props; | ||
118 | |||
119 | this.setState({ | ||
120 | isDismissing: true, | ||
121 | }); | ||
122 | |||
123 | if (onDismiss) { | ||
124 | onDismiss(); | ||
125 | } | ||
126 | |||
127 | setTimeout(() => { | ||
128 | this.setState({ | ||
129 | dismissed: true, | ||
130 | }); | ||
131 | }, 3000); | ||
132 | } | ||
133 | |||
134 | render() { | ||
135 | const { | ||
136 | classes, | ||
137 | children, | ||
138 | icon, | ||
139 | type, | ||
140 | ctaLabel, | ||
141 | ctaLoading, | ||
142 | ctaOnClick, | ||
143 | dismissable, | ||
144 | } = this.props; | ||
145 | |||
146 | const { | ||
147 | isDismissing, | ||
148 | dismissed, | ||
149 | } = this.state; | ||
150 | |||
151 | if (dismissed) { | ||
152 | return null; | ||
153 | } | ||
154 | |||
155 | return ( | ||
156 | <div className={classes.wrapper}> | ||
157 | <div | ||
158 | className={classnames({ | ||
159 | [classes.infobox]: true, | ||
160 | [classes[`${type}`]]: type, | ||
161 | [classes.dismissing]: isDismissing, | ||
162 | })} | ||
163 | > | ||
164 | {icon && ( | ||
165 | <Icon icon={icon} className={classes.icon} /> | ||
166 | )} | ||
167 | <div className={classes.content}> | ||
168 | {children} | ||
169 | </div> | ||
170 | {ctaLabel && ( | ||
171 | <button | ||
172 | className={classes.cta} | ||
173 | onClick={ctaOnClick} | ||
174 | type="button" | ||
175 | > | ||
176 | {ctaLabel} | ||
177 | </button> | ||
178 | )} | ||
179 | {dismissable && ( | ||
180 | <button | ||
181 | type="button" | ||
182 | onClick={this.dismiss.bind(this)} | ||
183 | className={classes.close} | ||
184 | > | ||
185 | <Icon icon="mdiClose" /> | ||
186 | </button> | ||
187 | )} | ||
188 | </div> | ||
189 | </div> | ||
190 | ); | ||
191 | } | ||
192 | } | ||
193 | |||
194 | export const Infobox = injectStyle(styles)(InfoboxComponent); | ||