diff options
Diffstat (limited to 'packages/ui')
-rw-r--r-- | packages/ui/.gitignore | 2 | ||||
-rw-r--r-- | packages/ui/package-lock.json | 207 | ||||
-rw-r--r-- | packages/ui/package.json | 41 | ||||
-rw-r--r-- | packages/ui/src/badge/index.tsx | 75 | ||||
-rw-r--r-- | packages/ui/src/headline/index.tsx | 71 | ||||
-rw-r--r-- | packages/ui/src/icon/index.tsx | 55 | ||||
-rw-r--r-- | packages/ui/src/index.ts | 5 | ||||
-rw-r--r-- | packages/ui/src/infobox/index.tsx | 194 | ||||
-rw-r--r-- | packages/ui/src/loader/index.tsx | 45 | ||||
-rw-r--r-- | packages/ui/src/typings/generic.ts | 10 | ||||
-rw-r--r-- | packages/ui/tsconfig.json | 12 | ||||
-rw-r--r-- | packages/ui/tslint.json | 3 | ||||
-rw-r--r-- | packages/ui/webpack.config.js | 19 |
13 files changed, 739 insertions, 0 deletions
diff --git a/packages/ui/.gitignore b/packages/ui/.gitignore new file mode 100644 index 000000000..d01826a6b --- /dev/null +++ b/packages/ui/.gitignore | |||
@@ -0,0 +1,2 @@ | |||
1 | node_modules/ | ||
2 | lib | ||
diff --git a/packages/ui/package-lock.json b/packages/ui/package-lock.json new file mode 100644 index 000000000..8fa68a29b --- /dev/null +++ b/packages/ui/package-lock.json | |||
@@ -0,0 +1,207 @@ | |||
1 | { | ||
2 | "name": "@meetfranz/ui", | ||
3 | "version": "0.0.0", | ||
4 | "lockfileVersion": 1, | ||
5 | "requires": true, | ||
6 | "dependencies": { | ||
7 | "@mdi/js": { | ||
8 | "version": "3.3.92", | ||
9 | "resolved": "https://registry.npmjs.org/@mdi/js/-/js-3.3.92.tgz", | ||
10 | "integrity": "sha512-l+12IwTycHlijWMiRWBAssm0RSgkQiwMthIy/EcBAdSqtnsHnFjHq+aI2MBZ8/AYX0QBxNUv4+EN0SXZgNkWDg==" | ||
11 | }, | ||
12 | "@mdi/react": { | ||
13 | "version": "1.1.0", | ||
14 | "resolved": "https://registry.npmjs.org/@mdi/react/-/react-1.1.0.tgz", | ||
15 | "integrity": "sha512-c0+avMYEZ6i7Pg1ULLFs+p7k8bDPiie9rrgGYs8VWQhw2tUUYz7r0lIPVzD3bzMghWfyhfkArj88K5Of0WTMNw==" | ||
16 | }, | ||
17 | "@meetfranz/theme": { | ||
18 | "version": "file:../theme", | ||
19 | "requires": { | ||
20 | "color": "^3.1.0" | ||
21 | }, | ||
22 | "dependencies": { | ||
23 | "color": { | ||
24 | "version": "3.1.0", | ||
25 | "bundled": true, | ||
26 | "requires": { | ||
27 | "color-convert": "^1.9.1", | ||
28 | "color-string": "^1.5.2" | ||
29 | } | ||
30 | }, | ||
31 | "color-convert": { | ||
32 | "version": "1.9.3", | ||
33 | "bundled": true, | ||
34 | "requires": { | ||
35 | "color-name": "1.1.3" | ||
36 | } | ||
37 | }, | ||
38 | "color-name": { | ||
39 | "version": "1.1.3", | ||
40 | "bundled": true | ||
41 | }, | ||
42 | "color-string": { | ||
43 | "version": "1.5.3", | ||
44 | "bundled": true, | ||
45 | "requires": { | ||
46 | "color-name": "^1.0.0", | ||
47 | "simple-swizzle": "^0.2.2" | ||
48 | } | ||
49 | }, | ||
50 | "is-arrayish": { | ||
51 | "version": "0.3.2", | ||
52 | "bundled": true | ||
53 | }, | ||
54 | "simple-swizzle": { | ||
55 | "version": "0.2.2", | ||
56 | "bundled": true, | ||
57 | "requires": { | ||
58 | "is-arrayish": "^0.3.1" | ||
59 | } | ||
60 | } | ||
61 | } | ||
62 | }, | ||
63 | "asap": { | ||
64 | "version": "2.0.6", | ||
65 | "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", | ||
66 | "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY=" | ||
67 | }, | ||
68 | "core-js": { | ||
69 | "version": "1.2.7", | ||
70 | "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz", | ||
71 | "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY=" | ||
72 | }, | ||
73 | "create-react-class": { | ||
74 | "version": "15.6.3", | ||
75 | "resolved": "https://registry.npmjs.org/create-react-class/-/create-react-class-15.6.3.tgz", | ||
76 | "integrity": "sha512-M+/3Q6E6DLO6Yx3OwrWjwHBnvfXXYA7W+dFjt/ZDBemHO1DDZhsalX/NUtnTYclN6GfnBDRh4qRHjcDHmlJBJg==", | ||
77 | "requires": { | ||
78 | "fbjs": "^0.8.9", | ||
79 | "loose-envify": "^1.3.1", | ||
80 | "object-assign": "^4.1.1" | ||
81 | } | ||
82 | }, | ||
83 | "encoding": { | ||
84 | "version": "0.1.12", | ||
85 | "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.12.tgz", | ||
86 | "integrity": "sha1-U4tm8+5izRq1HsMjgp0flIDHS+s=", | ||
87 | "requires": { | ||
88 | "iconv-lite": "~0.4.13" | ||
89 | } | ||
90 | }, | ||
91 | "fbjs": { | ||
92 | "version": "0.8.17", | ||
93 | "resolved": "https://registry.npmjs.org/fbjs/-/fbjs-0.8.17.tgz", | ||
94 | "integrity": "sha1-xNWY6taUkRJlPWWIsBpc3Nn5D90=", | ||
95 | "requires": { | ||
96 | "core-js": "^1.0.0", | ||
97 | "isomorphic-fetch": "^2.1.1", | ||
98 | "loose-envify": "^1.0.0", | ||
99 | "object-assign": "^4.1.0", | ||
100 | "promise": "^7.1.1", | ||
101 | "setimmediate": "^1.0.5", | ||
102 | "ua-parser-js": "^0.7.18" | ||
103 | } | ||
104 | }, | ||
105 | "iconv-lite": { | ||
106 | "version": "0.4.24", | ||
107 | "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", | ||
108 | "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", | ||
109 | "requires": { | ||
110 | "safer-buffer": ">= 2.1.2 < 3" | ||
111 | } | ||
112 | }, | ||
113 | "is-stream": { | ||
114 | "version": "1.1.0", | ||
115 | "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", | ||
116 | "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ=" | ||
117 | }, | ||
118 | "isomorphic-fetch": { | ||
119 | "version": "2.2.1", | ||
120 | "resolved": "https://registry.npmjs.org/isomorphic-fetch/-/isomorphic-fetch-2.2.1.tgz", | ||
121 | "integrity": "sha1-YRrhrPFPXoH3KVB0coGf6XM1WKk=", | ||
122 | "requires": { | ||
123 | "node-fetch": "^1.0.1", | ||
124 | "whatwg-fetch": ">=0.10.0" | ||
125 | } | ||
126 | }, | ||
127 | "js-tokens": { | ||
128 | "version": "4.0.0", | ||
129 | "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", | ||
130 | "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" | ||
131 | }, | ||
132 | "loose-envify": { | ||
133 | "version": "1.4.0", | ||
134 | "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", | ||
135 | "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", | ||
136 | "requires": { | ||
137 | "js-tokens": "^3.0.0 || ^4.0.0" | ||
138 | } | ||
139 | }, | ||
140 | "node-fetch": { | ||
141 | "version": "1.7.3", | ||
142 | "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-1.7.3.tgz", | ||
143 | "integrity": "sha512-NhZ4CsKx7cYm2vSrBAr2PvFOe6sWDf0UYLRqA6svUYg7+/TSfVAu49jYC4BvQ4Sms9SZgdqGBgroqfDhJdTyKQ==", | ||
144 | "requires": { | ||
145 | "encoding": "^0.1.11", | ||
146 | "is-stream": "^1.0.1" | ||
147 | } | ||
148 | }, | ||
149 | "object-assign": { | ||
150 | "version": "4.1.1", | ||
151 | "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", | ||
152 | "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" | ||
153 | }, | ||
154 | "promise": { | ||
155 | "version": "7.3.1", | ||
156 | "resolved": "https://registry.npmjs.org/promise/-/promise-7.3.1.tgz", | ||
157 | "integrity": "sha512-nolQXZ/4L+bP/UGlkfaIujX9BKxGwmQ9OT4mOt5yvy8iK1h3wqTEJCijzGANTCCl9nWjY41juyAn2K3Q1hLLTg==", | ||
158 | "requires": { | ||
159 | "asap": "~2.0.3" | ||
160 | } | ||
161 | }, | ||
162 | "prop-types": { | ||
163 | "version": "15.6.2", | ||
164 | "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.6.2.tgz", | ||
165 | "integrity": "sha512-3pboPvLiWD7dkI3qf3KbUe6hKFKa52w+AE0VCqECtf+QHAKgOL37tTaNCnuX1nAAQ4ZhyP+kYVKf8rLmJ/feDQ==", | ||
166 | "requires": { | ||
167 | "loose-envify": "^1.3.1", | ||
168 | "object-assign": "^4.1.1" | ||
169 | } | ||
170 | }, | ||
171 | "react-loader": { | ||
172 | "version": "2.4.5", | ||
173 | "resolved": "https://registry.npmjs.org/react-loader/-/react-loader-2.4.5.tgz", | ||
174 | "integrity": "sha1-zT5VHGzQc4wcDxPwc2VPk4KL5ak=", | ||
175 | "requires": { | ||
176 | "create-react-class": "^15.5.2", | ||
177 | "prop-types": "^15.5.8", | ||
178 | "spin.js": "2.x" | ||
179 | } | ||
180 | }, | ||
181 | "safer-buffer": { | ||
182 | "version": "2.1.2", | ||
183 | "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", | ||
184 | "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" | ||
185 | }, | ||
186 | "setimmediate": { | ||
187 | "version": "1.0.5", | ||
188 | "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", | ||
189 | "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=" | ||
190 | }, | ||
191 | "spin.js": { | ||
192 | "version": "2.3.2", | ||
193 | "resolved": "https://registry.npmjs.org/spin.js/-/spin.js-2.3.2.tgz", | ||
194 | "integrity": "sha1-bKpW1SBnNFD9XPvGlx5tB3LDeho=" | ||
195 | }, | ||
196 | "ua-parser-js": { | ||
197 | "version": "0.7.19", | ||
198 | "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.19.tgz", | ||
199 | "integrity": "sha512-T3PVJ6uz8i0HzPxOF9SWzWAlfN/DavlpQqepn22xgve/5QecC+XMCAtmUNnY7C9StehaV6exjUCI801lOI7QlQ==" | ||
200 | }, | ||
201 | "whatwg-fetch": { | ||
202 | "version": "3.0.0", | ||
203 | "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.0.0.tgz", | ||
204 | "integrity": "sha512-9GSJUgz1D4MfyKU7KRqwOjXCXTqWdFNvEr7eUBYchQiVc744mqK/MzXPNR2WsPkmkOa4ywfg8C2n8h+13Bey1Q==" | ||
205 | } | ||
206 | } | ||
207 | } | ||
diff --git a/packages/ui/package.json b/packages/ui/package.json new file mode 100644 index 000000000..cd7252850 --- /dev/null +++ b/packages/ui/package.json | |||
@@ -0,0 +1,41 @@ | |||
1 | { | ||
2 | "name": "@meetfranz/ui", | ||
3 | "version": "0.0.0", | ||
4 | "description": "React UI components for Franz", | ||
5 | "main": "lib/index.js", | ||
6 | "scripts": { | ||
7 | "dev": "NODE_ENV=development ../../node_modules/.bin/webpack -w", | ||
8 | "prepare": "../../node_modules/.bin/webpack" | ||
9 | }, | ||
10 | "publishConfig": { | ||
11 | "access": "public" | ||
12 | }, | ||
13 | "repository": { | ||
14 | "type": "git", | ||
15 | "url": "git+https://github.com/meetfranz/franz.git" | ||
16 | }, | ||
17 | "keywords": [ | ||
18 | "Franz", | ||
19 | "Forms", | ||
20 | "React", | ||
21 | "UI" | ||
22 | ], | ||
23 | "author": "Stefan Malzner <stefan@adlk.io>", | ||
24 | "license": "Apache-2.0", | ||
25 | "dependencies": { | ||
26 | "@mdi/js": "^3.3.92", | ||
27 | "@mdi/react": "^1.1.0", | ||
28 | "@meetfranz/theme": "file:../theme", | ||
29 | "react-loader": "^2.4.5" | ||
30 | }, | ||
31 | "peerDependencies": { | ||
32 | "classnames": "^2.2.6", | ||
33 | "lodash": "^4.17.11", | ||
34 | "mobx": "^5.8.0", | ||
35 | "mobx-react": "^5.4.3", | ||
36 | "react": "^16.7.0", | ||
37 | "react-dom": "16.7.0", | ||
38 | "react-jss": "^8.6.1" | ||
39 | }, | ||
40 | "gitHead": "e31248830eb63c8bff3d9add3baa4ca8916b74e1" | ||
41 | } | ||
diff --git a/packages/ui/src/badge/index.tsx b/packages/ui/src/badge/index.tsx new file mode 100644 index 000000000..241e778e7 --- /dev/null +++ b/packages/ui/src/badge/index.tsx | |||
@@ -0,0 +1,75 @@ | |||
1 | import { Theme } from '@meetfranz/theme'; | ||
2 | import classnames from 'classnames'; | ||
3 | import React, { Component } from 'react'; | ||
4 | import injectStyle from 'react-jss'; | ||
5 | |||
6 | import { IWithStyle } from '../typings/generic'; | ||
7 | |||
8 | interface IProps extends IWithStyle { | ||
9 | type: string; | ||
10 | className?: string; | ||
11 | children: React.ReactNode; | ||
12 | } | ||
13 | |||
14 | const badgeStyles = (theme: Theme) => { | ||
15 | const styles = {}; | ||
16 | Object.keys(theme.styleTypes).map((style) => { | ||
17 | Object.assign(styles, { | ||
18 | [style]: { | ||
19 | background: theme.styleTypes[style].accent, | ||
20 | color: theme.styleTypes[style].contrast, | ||
21 | border: theme.styleTypes[style].border, | ||
22 | }, | ||
23 | }); | ||
24 | }); | ||
25 | |||
26 | return styles; | ||
27 | }; | ||
28 | |||
29 | const styles = (theme: Theme) => ({ | ||
30 | badge: { | ||
31 | display: 'inline-block', | ||
32 | padding: [3, 8, 4], | ||
33 | fontSize: theme.badgeFontSize, | ||
34 | borderRadius: theme.badgeBorderRadius, | ||
35 | margin: [0, 4], | ||
36 | |||
37 | '&:first-child': { | ||
38 | marginLeft: 0, | ||
39 | }, | ||
40 | |||
41 | '&:last-child': { | ||
42 | marginRight: 0, | ||
43 | }, | ||
44 | }, | ||
45 | ...badgeStyles(theme), | ||
46 | }); | ||
47 | |||
48 | class BadgeComponent extends Component<IProps> { | ||
49 | public static defaultProps = { | ||
50 | type: 'primary', | ||
51 | }; | ||
52 | |||
53 | render() { | ||
54 | const { | ||
55 | classes, | ||
56 | children, | ||
57 | type, | ||
58 | className, | ||
59 | } = this.props; | ||
60 | |||
61 | return ( | ||
62 | <div | ||
63 | className={classnames({ | ||
64 | [classes.badge]: true, | ||
65 | [classes[type]]: true, | ||
66 | [`${className}`]: className, | ||
67 | })} | ||
68 | > | ||
69 | {children} | ||
70 | </div> | ||
71 | ); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | export const Badge = injectStyle(styles)(BadgeComponent); | ||
diff --git a/packages/ui/src/headline/index.tsx b/packages/ui/src/headline/index.tsx new file mode 100644 index 000000000..3458a40ad --- /dev/null +++ b/packages/ui/src/headline/index.tsx | |||
@@ -0,0 +1,71 @@ | |||
1 | import { Theme } from '@meetfranz/theme'; | ||
2 | import classnames from 'classnames'; | ||
3 | import React, { Component } from 'react'; | ||
4 | import injectStyle from 'react-jss'; | ||
5 | |||
6 | import { uiFontSize } from '@meetfranz/theme/lib/themes/default'; | ||
7 | import { IWithStyle, Omit } from '../typings/generic'; | ||
8 | |||
9 | interface IProps extends IWithStyle { | ||
10 | level?: number; | ||
11 | className?: string; | ||
12 | children: string | React.ReactNode; | ||
13 | id?: string; | ||
14 | } | ||
15 | |||
16 | const styles = (theme: Theme) => ({ | ||
17 | headline: { | ||
18 | fontWeight: 'lighter', | ||
19 | color: theme.colorText, | ||
20 | marginTop: 0, | ||
21 | marginBottom: 10, | ||
22 | textAlign: 'left', | ||
23 | }, | ||
24 | h1: { | ||
25 | fontSize: 30, | ||
26 | marginTop: 0, | ||
27 | }, | ||
28 | h2: { | ||
29 | fontSize: 20, | ||
30 | }, | ||
31 | h3: { | ||
32 | fontSize: 18, | ||
33 | }, | ||
34 | h4: { | ||
35 | fontSize: theme.uiFontSize, | ||
36 | }, | ||
37 | }); | ||
38 | |||
39 | class HeadlineComponent extends Component<IProps> { | ||
40 | render() { | ||
41 | const { | ||
42 | classes, | ||
43 | level, | ||
44 | className, | ||
45 | children, | ||
46 | id, | ||
47 | } = this.props; | ||
48 | |||
49 | return React.createElement( | ||
50 | `h${level}`, | ||
51 | { | ||
52 | id, | ||
53 | className: classnames({ | ||
54 | [classes.headline]: true, | ||
55 | [classes[level ? `h${level}` : 'h1']]: true, | ||
56 | [`${className}`]: className, | ||
57 | }), | ||
58 | }, | ||
59 | children, | ||
60 | ); | ||
61 | } | ||
62 | } | ||
63 | |||
64 | const Headline = injectStyle(styles)(HeadlineComponent); | ||
65 | |||
66 | const createH = (level: number) => (props: Omit<IProps, 'classes' | 'theme'>) => <Headline level={level} {...props}>{props.children}</Headline>; | ||
67 | |||
68 | export const H1 = createH(1); | ||
69 | export const H2 = createH(2); | ||
70 | export const H3 = createH(3); | ||
71 | export const H4 = createH(4); | ||
diff --git a/packages/ui/src/icon/index.tsx b/packages/ui/src/icon/index.tsx new file mode 100644 index 000000000..e30d3396d --- /dev/null +++ b/packages/ui/src/icon/index.tsx | |||
@@ -0,0 +1,55 @@ | |||
1 | import * as mdiIcons from '@mdi/js'; | ||
2 | import MdiIcon from '@mdi/react'; | ||
3 | import { Theme } from '@meetfranz/theme'; | ||
4 | import classnames from 'classnames'; | ||
5 | import React, { Component } from 'react'; | ||
6 | import injectStyle from 'react-jss'; | ||
7 | |||
8 | import { IWithStyle } from '../typings/generic'; | ||
9 | |||
10 | interface IProps extends IWithStyle { | ||
11 | icon: keyof typeof mdiIcons; | ||
12 | size?: number; | ||
13 | className?: string; | ||
14 | } | ||
15 | |||
16 | const styles = (theme: Theme) => ({ | ||
17 | icon: { | ||
18 | fill: theme.colorText, | ||
19 | }, | ||
20 | }); | ||
21 | |||
22 | class IconComponent extends Component<IProps> { | ||
23 | public static defaultProps = { | ||
24 | size: 1, | ||
25 | }; | ||
26 | |||
27 | render() { | ||
28 | const { | ||
29 | classes, | ||
30 | icon: iconName, | ||
31 | size, | ||
32 | className, | ||
33 | } = this.props; | ||
34 | |||
35 | let icon = ''; | ||
36 | if (iconName && mdiIcons[iconName]) { | ||
37 | icon = mdiIcons[iconName]; | ||
38 | } else if (iconName && !mdiIcons[iconName]) { | ||
39 | console.warn(`Icon '${iconName}' was not found`); | ||
40 | } | ||
41 | |||
42 | return ( | ||
43 | <MdiIcon | ||
44 | path={icon} | ||
45 | size={size} | ||
46 | className={classnames({ | ||
47 | [classes.icon]: true, | ||
48 | [`${className}`]: className, | ||
49 | })} | ||
50 | /> | ||
51 | ); | ||
52 | } | ||
53 | } | ||
54 | |||
55 | export const Icon = injectStyle(styles)(IconComponent); | ||
diff --git a/packages/ui/src/index.ts b/packages/ui/src/index.ts new file mode 100644 index 000000000..1eeec5144 --- /dev/null +++ b/packages/ui/src/index.ts | |||
@@ -0,0 +1,5 @@ | |||
1 | export { Icon } from './icon'; | ||
2 | export { Infobox } from './infobox'; | ||
3 | export * from './headline'; | ||
4 | export { Loader } from './loader'; | ||
5 | export { Badge } from './badge'; | ||
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); | ||
diff --git a/packages/ui/src/loader/index.tsx b/packages/ui/src/loader/index.tsx new file mode 100644 index 000000000..799caf195 --- /dev/null +++ b/packages/ui/src/loader/index.tsx | |||
@@ -0,0 +1,45 @@ | |||
1 | import { Theme } from '@meetfranz/theme'; | ||
2 | import classnames from 'classnames'; | ||
3 | import React, { Component } from 'react'; | ||
4 | import injectStyle from 'react-jss'; | ||
5 | import ReactLoader from 'react-loader'; | ||
6 | |||
7 | import { IWithStyle } from '../typings/generic'; | ||
8 | |||
9 | interface IProps extends IWithStyle { | ||
10 | className?: string; | ||
11 | } | ||
12 | |||
13 | const styles = (theme: Theme) => ({ | ||
14 | container: { | ||
15 | position: 'relative', | ||
16 | height: 60, | ||
17 | }, | ||
18 | }); | ||
19 | |||
20 | class LoaderComponent extends Component<IProps> { | ||
21 | render() { | ||
22 | const { | ||
23 | classes, | ||
24 | className, | ||
25 | theme, | ||
26 | } = this.props; | ||
27 | |||
28 | return ( | ||
29 | <div className={classnames({ | ||
30 | [classes.container]: true, | ||
31 | [`${className}`]: className, | ||
32 | })}> | ||
33 | <ReactLoader | ||
34 | loaded={false} | ||
35 | width={4} | ||
36 | scale={0.75} | ||
37 | color={theme.colorText} | ||
38 | parentClassName={classes.loader} | ||
39 | /> | ||
40 | </div> | ||
41 | ); | ||
42 | } | ||
43 | } | ||
44 | |||
45 | export const Loader = injectStyle(styles)(LoaderComponent); | ||
diff --git a/packages/ui/src/typings/generic.ts b/packages/ui/src/typings/generic.ts new file mode 100644 index 000000000..d5f953b9f --- /dev/null +++ b/packages/ui/src/typings/generic.ts | |||
@@ -0,0 +1,10 @@ | |||
1 | import { Theme } from '@meetfranz/theme/lib'; | ||
2 | import { Classes } from 'jss'; | ||
3 | |||
4 | export interface IWithStyle { | ||
5 | classes: Classes; | ||
6 | theme: Theme; | ||
7 | } | ||
8 | |||
9 | export type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N; | ||
10 | export type Omit<T, K extends keyof T> = Pick<T, Exclude<keyof T, K>>; | ||
diff --git a/packages/ui/tsconfig.json b/packages/ui/tsconfig.json new file mode 100644 index 000000000..8b9507eac --- /dev/null +++ b/packages/ui/tsconfig.json | |||
@@ -0,0 +1,12 @@ | |||
1 | { | ||
2 | "extends": "../../tsconfig.settings.json", | ||
3 | "compilerOptions": { | ||
4 | "outDir": "lib", | ||
5 | "rootDir": "src" | ||
6 | }, | ||
7 | "references": [ | ||
8 | { | ||
9 | "path": "../theme" | ||
10 | } | ||
11 | ] | ||
12 | } | ||
diff --git a/packages/ui/tslint.json b/packages/ui/tslint.json new file mode 100644 index 000000000..0946f2096 --- /dev/null +++ b/packages/ui/tslint.json | |||
@@ -0,0 +1,3 @@ | |||
1 | { | ||
2 | "extends": "../../tslint.json" | ||
3 | } | ||
diff --git a/packages/ui/webpack.config.js b/packages/ui/webpack.config.js new file mode 100644 index 000000000..cc3370359 --- /dev/null +++ b/packages/ui/webpack.config.js | |||
@@ -0,0 +1,19 @@ | |||
1 | const path = require('path'); | ||
2 | const baseConfig = require('../../webpack.config.base')(__dirname); | ||
3 | |||
4 | module.exports = Object.assign({}, baseConfig, { | ||
5 | output: { | ||
6 | filename: 'index.js', | ||
7 | path: path.join(__dirname, 'lib'), | ||
8 | libraryTarget: 'commonjs2', | ||
9 | }, | ||
10 | externals: { | ||
11 | react: 'react', | ||
12 | reactDom: 'react-dom', | ||
13 | classnames: 'classnames', | ||
14 | lodash: 'lodash', | ||
15 | mobx: 'mobx', | ||
16 | mobxReact: 'mobx-react', | ||
17 | reactJss: 'react-jss', | ||
18 | }, | ||
19 | }); | ||