diff options
author | Stefan Malzner <stefan@adlk.io> | 2019-01-28 11:35:25 +0100 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2019-01-28 11:35:25 +0100 |
commit | 9a5b313ea12bdb9dc3e3873ca3a2639bd7483e46 (patch) | |
tree | 038dc5e0a209d06e1c15c1e3c4740d5bdda96f8a | |
parent | Add href and type to button component (diff) | |
download | ferdium-app-9a5b313ea12bdb9dc3e3873ca3a2639bd7483e46.tar.gz ferdium-app-9a5b313ea12bdb9dc3e3873ca3a2639bd7483e46.tar.zst ferdium-app-9a5b313ea12bdb9dc3e3873ca3a2639bd7483e46.zip |
Update packages
38 files changed, 1898 insertions, 29 deletions
@@ -1 +1 @@ | |||
10.13.0 \ No newline at end of file | 10.14.0 | ||
diff --git a/package-lock.json b/package-lock.json index a432dda40..435909e89 100644 --- a/package-lock.json +++ b/package-lock.json | |||
@@ -2724,7 +2724,7 @@ | |||
2724 | "requires": { | 2724 | "requires": { |
2725 | "@mdi/js": "^3.3.92", | 2725 | "@mdi/js": "^3.3.92", |
2726 | "@mdi/react": "^1.1.0", | 2726 | "@mdi/react": "^1.1.0", |
2727 | "@meetfranz/theme": "^1.0.4", | 2727 | "@meetfranz/theme": "file:packages/theme", |
2728 | "react-html-attributes": "^1.4.3", | 2728 | "react-html-attributes": "^1.4.3", |
2729 | "react-loader": "^2.4.5" | 2729 | "react-loader": "^2.4.5" |
2730 | }, | 2730 | }, |
@@ -2785,6 +2785,15 @@ | |||
2785 | "color": "^3.1.0" | 2785 | "color": "^3.1.0" |
2786 | } | 2786 | } |
2787 | }, | 2787 | }, |
2788 | "@meetfranz/ui": { | ||
2789 | "version": "file:packages/ui", | ||
2790 | "requires": { | ||
2791 | "@mdi/js": "^3.3.92", | ||
2792 | "@mdi/react": "^1.1.0", | ||
2793 | "@meetfranz/theme": "file:packages/theme", | ||
2794 | "react-loader": "^2.4.5" | ||
2795 | } | ||
2796 | }, | ||
2788 | "@mrmlnc/readdir-enhanced": { | 2797 | "@mrmlnc/readdir-enhanced": { |
2789 | "version": "2.2.1", | 2798 | "version": "2.2.1", |
2790 | "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", | 2799 | "resolved": "https://registry.npmjs.org/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz", |
diff --git a/package.json b/package.json index f9bf78f1d..1266eb117 100644 --- a/package.json +++ b/package.json | |||
@@ -35,6 +35,7 @@ | |||
35 | "@meetfranz/electron-notification-state": "^1.0.0", | 35 | "@meetfranz/electron-notification-state": "^1.0.0", |
36 | "@meetfranz/forms": "file:packages/forms", | 36 | "@meetfranz/forms": "file:packages/forms", |
37 | "@meetfranz/theme": "file:packages/theme", | 37 | "@meetfranz/theme": "file:packages/theme", |
38 | "@meetfranz/ui": "file:packages/ui", | ||
38 | "address-rfc2822": "^2.0.1", | 39 | "address-rfc2822": "^2.0.1", |
39 | "auto-launch": "https://github.com/meetfranz/node-auto-launch.git", | 40 | "auto-launch": "https://github.com/meetfranz/node-auto-launch.git", |
40 | "classnames": "2.2.6", | 41 | "classnames": "2.2.6", |
diff --git a/packages/forms/package-lock.json b/packages/forms/package-lock.json index cdfab23b5..834db8d33 100644 --- a/packages/forms/package-lock.json +++ b/packages/forms/package-lock.json | |||
@@ -1,6 +1,6 @@ | |||
1 | { | 1 | { |
2 | "name": "@meetfranz/forms", | 2 | "name": "@meetfranz/forms", |
3 | "version": "1.0.1", | 3 | "version": "1.0.4", |
4 | "lockfileVersion": 1, | 4 | "lockfileVersion": 1, |
5 | "requires": true, | 5 | "requires": true, |
6 | "dependencies": { | 6 | "dependencies": { |
diff --git a/packages/forms/package.json b/packages/forms/package.json index 8dc9920c8..32b81eed2 100644 --- a/packages/forms/package.json +++ b/packages/forms/package.json | |||
@@ -25,7 +25,7 @@ | |||
25 | "dependencies": { | 25 | "dependencies": { |
26 | "@mdi/js": "^3.3.92", | 26 | "@mdi/js": "^3.3.92", |
27 | "@mdi/react": "^1.1.0", | 27 | "@mdi/react": "^1.1.0", |
28 | "@meetfranz/theme": "^1.0.4", | 28 | "@meetfranz/theme": "file:../theme", |
29 | "react-html-attributes": "^1.4.3", | 29 | "react-html-attributes": "^1.4.3", |
30 | "react-loader": "^2.4.5" | 30 | "react-loader": "^2.4.5" |
31 | }, | 31 | }, |
diff --git a/packages/forms/src/button/index.tsx b/packages/forms/src/button/index.tsx index 92d69ae0e..b7cca7fa4 100644 --- a/packages/forms/src/button/index.tsx +++ b/packages/forms/src/button/index.tsx | |||
@@ -8,7 +8,7 @@ import React, { Component } from 'react'; | |||
8 | import injectStyle from 'react-jss'; | 8 | import injectStyle from 'react-jss'; |
9 | import Loader from 'react-loader'; | 9 | import Loader from 'react-loader'; |
10 | 10 | ||
11 | import { IFormField, IWithStyle, Omit } from '../typings/generic'; | 11 | import { IFormField, IWithStyle } from '../typings/generic'; |
12 | 12 | ||
13 | type ButtonType = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'inverted'; | 13 | type ButtonType = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'inverted'; |
14 | 14 | ||
diff --git a/packages/forms/src/error/index.tsx b/packages/forms/src/error/index.tsx index 3feaef7f6..9d26e086d 100644 --- a/packages/forms/src/error/index.tsx +++ b/packages/forms/src/error/index.tsx | |||
@@ -12,7 +12,7 @@ interface IProps { | |||
12 | } | 12 | } |
13 | 13 | ||
14 | @observer | 14 | @observer |
15 | class Error extends Component<IProps> { | 15 | class ErrorComponent extends Component<IProps> { |
16 | render() { | 16 | render() { |
17 | const { | 17 | const { |
18 | classes, | 18 | classes, |
@@ -29,4 +29,4 @@ class Error extends Component<IProps> { | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | export default injectSheet(styles)(Error); | 32 | export const Error = injectSheet(styles)(ErrorComponent); |
diff --git a/packages/forms/src/index.ts b/packages/forms/src/index.ts index fbeb7e3d3..ea47fe25e 100644 --- a/packages/forms/src/index.ts +++ b/packages/forms/src/index.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | export { Input } from './input'; | 1 | export { Input } from './input'; |
2 | export { Toggle } from './toggle'; | 2 | export { Toggle } from './toggle'; |
3 | export { Button } from './button'; | 3 | export { Button } from './button'; |
4 | export { Select } from './select'; | ||
diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx index 9fcf48010..cd6da3778 100644 --- a/packages/forms/src/input/index.tsx +++ b/packages/forms/src/input/index.tsx | |||
@@ -7,19 +7,25 @@ import injectSheet from 'react-jss'; | |||
7 | 7 | ||
8 | import { IFormField, IWithStyle } from '../typings/generic'; | 8 | import { IFormField, IWithStyle } from '../typings/generic'; |
9 | 9 | ||
10 | import Error from '../error'; | 10 | import { Error } from '../error'; |
11 | import Label from '../label'; | 11 | import { Label } from '../label'; |
12 | import Wrapper from '../wrapper'; | 12 | import { Wrapper } from '../wrapper'; |
13 | import scorePasswordFunc from './scorePassword'; | 13 | import { scorePasswordFunc } from './scorePassword'; |
14 | 14 | ||
15 | import styles from './styles'; | 15 | import styles from './styles'; |
16 | 16 | ||
17 | interface IData { | ||
18 | [index: string]: string; | ||
19 | } | ||
20 | |||
17 | interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField, IWithStyle { | 21 | interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField, IWithStyle { |
18 | focus?: boolean; | 22 | focus?: boolean; |
19 | prefix?: string; | 23 | prefix?: string; |
20 | suffix?: string; | 24 | suffix?: string; |
21 | scorePassword?: boolean; | 25 | scorePassword?: boolean; |
22 | showPasswordToggle?: boolean; | 26 | showPasswordToggle?: boolean; |
27 | data: IData; | ||
28 | inputClassName?: string; | ||
23 | } | 29 | } |
24 | 30 | ||
25 | interface IState { | 31 | interface IState { |
@@ -48,10 +54,16 @@ class InputComponent extends Component<IProps, IState> { | |||
48 | private inputRef = createRef<HTMLInputElement>(); | 54 | private inputRef = createRef<HTMLInputElement>(); |
49 | 55 | ||
50 | componentDidMount() { | 56 | componentDidMount() { |
51 | const { focus } = this.props; | 57 | const { focus, data } = this.props; |
58 | |||
59 | if (this.inputRef && this.inputRef.current) { | ||
60 | if (focus) { | ||
61 | this.inputRef.current.focus(); | ||
62 | } | ||
52 | 63 | ||
53 | if (focus && this.inputRef && this.inputRef.current) { | 64 | if (data) { |
54 | this.inputRef.current.focus(); | 65 | Object.keys(data).map(key => this.inputRef.current!.dataset[key] = data[key]); |
66 | } | ||
55 | } | 67 | } |
56 | } | 68 | } |
57 | 69 | ||
@@ -77,6 +89,7 @@ class InputComponent extends Component<IProps, IState> { | |||
77 | disabled, | 89 | disabled, |
78 | error, | 90 | error, |
79 | id, | 91 | id, |
92 | inputClassName, | ||
80 | label, | 93 | label, |
81 | prefix, | 94 | prefix, |
82 | scorePassword, | 95 | scorePassword, |
@@ -99,15 +112,17 @@ class InputComponent extends Component<IProps, IState> { | |||
99 | const inputType = type === 'password' && showPassword ? 'text' : type; | 112 | const inputType = type === 'password' && showPassword ? 'text' : type; |
100 | 113 | ||
101 | return ( | 114 | return ( |
102 | <Wrapper> | 115 | <Wrapper |
116 | className={className} | ||
117 | > | ||
103 | <Label | 118 | <Label |
104 | title={label} | 119 | title={label} |
105 | showLabel={showLabel} | 120 | showLabel={showLabel} |
106 | htmlFor={id} | 121 | htmlFor={id} |
107 | className={className} | ||
108 | > | 122 | > |
109 | <div | 123 | <div |
110 | className={classnames({ | 124 | className={classnames({ |
125 | [`${inputClassName}`]: inputClassName, | ||
111 | [`${classes.hasPasswordScore}`]: scorePassword, | 126 | [`${classes.hasPasswordScore}`]: scorePassword, |
112 | [`${classes.wrapper}`]: true, | 127 | [`${classes.wrapper}`]: true, |
113 | [`${classes.disabled}`]: disabled, | 128 | [`${classes.disabled}`]: disabled, |
@@ -122,13 +137,14 @@ class InputComponent extends Component<IProps, IState> { | |||
122 | id={id} | 137 | id={id} |
123 | type={inputType} | 138 | type={inputType} |
124 | name={name} | 139 | name={name} |
125 | value={value} | 140 | defaultValue={value as string} |
126 | placeholder={placeholder} | 141 | placeholder={placeholder} |
127 | spellCheck={spellCheck} | 142 | spellCheck={spellCheck} |
128 | className={classes.input} | 143 | className={classes.input} |
129 | ref={this.inputRef} | 144 | ref={this.inputRef} |
130 | onChange={this.onChange.bind(this)} | 145 | onChange={this.onChange.bind(this)} |
131 | onBlur={onBlur} | 146 | onBlur={onBlur} |
147 | disabled={disabled} | ||
132 | /> | 148 | /> |
133 | {suffix && ( | 149 | {suffix && ( |
134 | <span className={classes.suffix}> | 150 | <span className={classes.suffix}> |
diff --git a/packages/forms/src/input/scorePassword.ts b/packages/forms/src/input/scorePassword.ts index bdad7aa28..0b7719ec1 100644 --- a/packages/forms/src/input/scorePassword.ts +++ b/packages/forms/src/input/scorePassword.ts | |||
@@ -10,7 +10,7 @@ interface IVariations { | |||
10 | upper: boolean; | 10 | upper: boolean; |
11 | } | 11 | } |
12 | 12 | ||
13 | export default function scorePasswordFunc(password: string): number { | 13 | export function scorePasswordFunc(password: string): number { |
14 | let score: number = 0; | 14 | let score: number = 0; |
15 | if (!password) { | 15 | if (!password) { |
16 | return score; | 16 | return score; |
diff --git a/packages/forms/src/label/index.tsx b/packages/forms/src/label/index.tsx index 348b820c5..ee3268b16 100644 --- a/packages/forms/src/label/index.tsx +++ b/packages/forms/src/label/index.tsx | |||
@@ -13,7 +13,7 @@ interface ILabel extends IFormField, React.LabelHTMLAttributes<HTMLLabelElement> | |||
13 | } | 13 | } |
14 | 14 | ||
15 | @observer | 15 | @observer |
16 | class Label extends Component<ILabel> { | 16 | class LabelComponent extends Component<ILabel> { |
17 | static defaultProps = { | 17 | static defaultProps = { |
18 | showLabel: true, | 18 | showLabel: true, |
19 | }; | 19 | }; |
@@ -46,4 +46,4 @@ class Label extends Component<ILabel> { | |||
46 | } | 46 | } |
47 | } | 47 | } |
48 | 48 | ||
49 | export default injectSheet(styles)(Label); | 49 | export const Label = injectSheet(styles)(LabelComponent); |
diff --git a/packages/forms/src/select/index.tsx b/packages/forms/src/select/index.tsx new file mode 100644 index 000000000..58bb7317a --- /dev/null +++ b/packages/forms/src/select/index.tsx | |||
@@ -0,0 +1,422 @@ | |||
1 | import { mdiArrowRightDropCircleOutline, mdiCloseCircle, mdiMagnify } from '@mdi/js'; | ||
2 | import Icon from '@mdi/react'; | ||
3 | import { Theme } from '@meetfranz/theme'; | ||
4 | import classnames from 'classnames'; | ||
5 | import debounce from 'lodash/debounce'; | ||
6 | import { observer } from 'mobx-react'; | ||
7 | import React, { Component, createRef } from 'react'; | ||
8 | import injectStyle from 'react-jss'; | ||
9 | |||
10 | import { IFormField, IWithStyle } from '../typings/generic'; | ||
11 | |||
12 | import { NONAME } from 'dns'; | ||
13 | import { Error } from '../error'; | ||
14 | import { Label } from '../label'; | ||
15 | import { Wrapper } from '../wrapper'; | ||
16 | |||
17 | interface IOptions { | ||
18 | [index: string]: string; | ||
19 | } | ||
20 | |||
21 | interface IData { | ||
22 | [index: string]: string; | ||
23 | } | ||
24 | |||
25 | interface IProps extends IFormField, IWithStyle { | ||
26 | actionText: string; | ||
27 | className?: string; | ||
28 | inputClassName?: string; | ||
29 | defaultValue?: string; | ||
30 | disabled?: boolean; | ||
31 | id?: string; | ||
32 | name: string; | ||
33 | options: IOptions; | ||
34 | value: string; | ||
35 | onChange: (event: React.ChangeEvent<HTMLInputElement>) => void; | ||
36 | showSearch: boolean; | ||
37 | data: IData; | ||
38 | } | ||
39 | |||
40 | interface IState { | ||
41 | open: boolean; | ||
42 | value: string; | ||
43 | needle: string; | ||
44 | selected: number; | ||
45 | options: IOptions; | ||
46 | } | ||
47 | |||
48 | const styles = (theme: Theme) => ({ | ||
49 | select: { | ||
50 | background: theme.selectBackground, | ||
51 | border: theme.selectBorder, | ||
52 | borderRadius: theme.borderRadiusSmall, | ||
53 | height: theme.selectHeight, | ||
54 | fontSize: theme.uiFontSize, | ||
55 | width: '100%', | ||
56 | display: 'flex', | ||
57 | alignItems: 'center', | ||
58 | textAlign: 'left', | ||
59 | color: theme.selectColor, | ||
60 | }, | ||
61 | popup: { | ||
62 | opacity: 0, | ||
63 | height: 0, | ||
64 | overflowX: 'scroll', | ||
65 | border: theme.selectBorder, | ||
66 | borderTop: 0, | ||
67 | transition: 'all 0.3s', | ||
68 | }, | ||
69 | open: { | ||
70 | opacity: 1, | ||
71 | height: 350, | ||
72 | background: theme.selectPopupBackground, | ||
73 | }, | ||
74 | option: { | ||
75 | padding: 10, | ||
76 | borderBottom: theme.selectOptionBorder, | ||
77 | color: theme.selectOptionColor, | ||
78 | |||
79 | '&:hover': { | ||
80 | background: theme.selectOptionItemHover, | ||
81 | color: theme.selectOptionItemHoverColor, | ||
82 | }, | ||
83 | '&:active': { | ||
84 | background: theme.selectOptionItemActive, | ||
85 | color: theme.selectOptionItemActiveColor, | ||
86 | }, | ||
87 | }, | ||
88 | selected: { | ||
89 | fontWeight: 'bold', | ||
90 | }, | ||
91 | toggle: { | ||
92 | marginLeft: 'auto', | ||
93 | fill: theme.selectToggleColor, | ||
94 | transition: 'transform 0.3s', | ||
95 | }, | ||
96 | toggleOpened: { | ||
97 | transform: 'rotateZ(90deg)', | ||
98 | }, | ||
99 | searchContainer: { | ||
100 | display: 'flex', | ||
101 | background: theme.selectSearchBackground, | ||
102 | alignItems: 'center', | ||
103 | paddingLeft: 10, | ||
104 | color: theme.selectColor, | ||
105 | |||
106 | '& svg': { | ||
107 | fill: theme.selectSearchColor, | ||
108 | }, | ||
109 | }, | ||
110 | search: { | ||
111 | border: 0, | ||
112 | width: '100%', | ||
113 | fontSize: theme.uiFontSize, | ||
114 | background: 'none', | ||
115 | marginLeft: 10, | ||
116 | padding: [10, 0], | ||
117 | color: theme.selectSearchColor, | ||
118 | }, | ||
119 | clearNeedle: { | ||
120 | background: 'none', | ||
121 | border: 0, | ||
122 | }, | ||
123 | focused: { | ||
124 | fontWeight: 'bold', | ||
125 | background: theme.selectOptionItemHover, | ||
126 | color: theme.selectOptionItemHoverColor, | ||
127 | }, | ||
128 | hasError: { | ||
129 | borderColor: theme.brandDanger, | ||
130 | }, | ||
131 | disabled: { | ||
132 | opacity: theme.selectDisabledOpacity, | ||
133 | }, | ||
134 | }); | ||
135 | |||
136 | @observer | ||
137 | class SelectComponent extends Component<IProps> { | ||
138 | public static defaultProps = { | ||
139 | onChange: () => {}, | ||
140 | showLabel: true, | ||
141 | disabled: false, | ||
142 | error: '', | ||
143 | }; | ||
144 | |||
145 | state = { | ||
146 | open: false, | ||
147 | value: '', | ||
148 | needle: '', | ||
149 | selected: 0, | ||
150 | options: null, | ||
151 | }; | ||
152 | |||
153 | private componentRef = createRef<HTMLDivElement>(); | ||
154 | private inputRef = createRef<HTMLInputElement>(); | ||
155 | private searchInputRef = createRef<HTMLInputElement>(); | ||
156 | private scrollContainerRef = createRef<HTMLDivElement>(); | ||
157 | private activeOptionRef = createRef<HTMLDivElement>(); | ||
158 | |||
159 | private keyListener: any; | ||
160 | |||
161 | componentWillReceiveProps(nextProps: IProps) { | ||
162 | if (nextProps.value && nextProps.value !== this.props.value) { | ||
163 | this.setState({ | ||
164 | value: nextProps.value, | ||
165 | }); | ||
166 | } | ||
167 | } | ||
168 | |||
169 | componentDidUpdate() { | ||
170 | const { | ||
171 | open, | ||
172 | } = this.state; | ||
173 | |||
174 | if (this.searchInputRef && this.searchInputRef.current) { | ||
175 | if (open) { | ||
176 | this.searchInputRef.current.focus(); | ||
177 | } | ||
178 | } | ||
179 | } | ||
180 | |||
181 | componentDidMount() { | ||
182 | if (this.componentRef && this.componentRef.current) { | ||
183 | this.keyListener = this.componentRef.current.addEventListener('keydown', debounce((e) => { | ||
184 | const { | ||
185 | selected, | ||
186 | open, | ||
187 | options, | ||
188 | } = this.state; | ||
189 | |||
190 | if (!open) return; | ||
191 | |||
192 | if (e.keyCode === 38 && selected > 0) { | ||
193 | this.setState((state: IState) => ({ | ||
194 | selected: state.selected - 1, | ||
195 | })); | ||
196 | } else if (e.keyCode === 40 && selected < Object.keys(options!).length - 1) { | ||
197 | this.setState((state: IState) => ({ | ||
198 | selected: state.selected + 1, | ||
199 | })); | ||
200 | } else if (e.keyCode === 13) { | ||
201 | this.select(Object.keys(options!)[selected]); | ||
202 | } | ||
203 | |||
204 | if (this.activeOptionRef && this.activeOptionRef.current && this.scrollContainerRef && this.scrollContainerRef.current) { | ||
205 | const containerTopOffset = this.scrollContainerRef.current.offsetTop; | ||
206 | const optionTopOffset = this.activeOptionRef.current.offsetTop; | ||
207 | |||
208 | const topOffset = optionTopOffset - containerTopOffset; | ||
209 | |||
210 | this.scrollContainerRef.current.scrollTop = topOffset - 35; | ||
211 | } | ||
212 | }, 10, { | ||
213 | leading: true, | ||
214 | })); | ||
215 | } | ||
216 | |||
217 | if (this.inputRef && this.inputRef.current) { | ||
218 | const { | ||
219 | data, | ||
220 | } = this.props; | ||
221 | |||
222 | if (data) { | ||
223 | Object.keys(data).map(key => this.inputRef.current!.dataset[key] = data[key]); | ||
224 | } | ||
225 | } | ||
226 | } | ||
227 | |||
228 | componentWillMount() { | ||
229 | const { value } = this.props; | ||
230 | |||
231 | if (this.componentRef && this.componentRef.current) { | ||
232 | this.componentRef.current.removeEventListener('keydown', this.keyListener); | ||
233 | } | ||
234 | |||
235 | if (value) { | ||
236 | this.setState({ | ||
237 | value, | ||
238 | }); | ||
239 | } | ||
240 | |||
241 | this.setFilter(); | ||
242 | } | ||
243 | |||
244 | setFilter(needle: string = '') { | ||
245 | const { options } = this.props; | ||
246 | |||
247 | let filteredOptions = {}; | ||
248 | if (needle) { | ||
249 | Object.keys(options).map((key) => { | ||
250 | if (key.toLocaleLowerCase().startsWith(needle.toLocaleLowerCase()) || options[key].toLocaleLowerCase().startsWith(needle.toLocaleLowerCase())) { | ||
251 | Object.assign(filteredOptions, { | ||
252 | [`${key}`]: options[key], | ||
253 | }); | ||
254 | } | ||
255 | }); | ||
256 | } else { | ||
257 | filteredOptions = options; | ||
258 | } | ||
259 | |||
260 | this.setState({ | ||
261 | needle, | ||
262 | options: filteredOptions, | ||
263 | selected: 0, | ||
264 | }); | ||
265 | } | ||
266 | |||
267 | select(key: string) { | ||
268 | this.setState((state: IState) => ({ | ||
269 | value: key, | ||
270 | open: false, | ||
271 | })); | ||
272 | |||
273 | this.setFilter(); | ||
274 | |||
275 | if (this.props.onChange) { | ||
276 | this.props.onChange(key as any); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | render() { | ||
281 | const { | ||
282 | actionText, | ||
283 | classes, | ||
284 | className, | ||
285 | defaultValue, | ||
286 | disabled, | ||
287 | error, | ||
288 | id, | ||
289 | inputClassName, | ||
290 | name, | ||
291 | label, | ||
292 | showLabel, | ||
293 | showSearch, | ||
294 | onChange, | ||
295 | } = this.props; | ||
296 | |||
297 | const { | ||
298 | open, | ||
299 | needle, | ||
300 | value, | ||
301 | selected, | ||
302 | options, | ||
303 | } = this.state; | ||
304 | |||
305 | let selection = ''; | ||
306 | if (!value && defaultValue && options![defaultValue]) { | ||
307 | selection = options![defaultValue]; | ||
308 | } else if (value && options![value]) { | ||
309 | selection = options![value]; | ||
310 | } else { | ||
311 | selection = actionText; | ||
312 | } | ||
313 | |||
314 | return ( | ||
315 | <Wrapper | ||
316 | className={className} | ||
317 | > | ||
318 | <Label | ||
319 | title={label} | ||
320 | showLabel={showLabel} | ||
321 | htmlFor={id} | ||
322 | > | ||
323 | <div | ||
324 | className={classnames({ | ||
325 | [`${classes.hasError}`]: error, | ||
326 | [`${classes.disabled}`]: disabled, | ||
327 | })} | ||
328 | ref={this.componentRef} | ||
329 | > | ||
330 | <button | ||
331 | type="button" | ||
332 | className={classnames({ | ||
333 | [`${inputClassName}`]: inputClassName, | ||
334 | [`${classes.select}`]: true, | ||
335 | [`${classes.hasError}`]: error, | ||
336 | })} | ||
337 | onClick= {!disabled ? () => this.setState((state: IState) => ({ | ||
338 | open: !state.open, | ||
339 | })) : () => {}} | ||
340 | > | ||
341 | {selection} | ||
342 | <Icon | ||
343 | path={mdiArrowRightDropCircleOutline} | ||
344 | size={0.8} | ||
345 | className={classnames({ | ||
346 | [`${classes.toggle}`]: true, | ||
347 | [`${classes.toggleOpened}`]: open, | ||
348 | })} | ||
349 | /> | ||
350 | </button> | ||
351 | {showSearch && open && ( | ||
352 | <div className={classes.searchContainer}> | ||
353 | <Icon | ||
354 | path={mdiMagnify} | ||
355 | size={0.8} | ||
356 | /> | ||
357 | <input | ||
358 | type="text" | ||
359 | value={needle} | ||
360 | onChange={e => this.setFilter(e.currentTarget.value)} | ||
361 | placeholder="Search" | ||
362 | className={classes.search} | ||
363 | ref={this.searchInputRef} | ||
364 | /> | ||
365 | {needle && ( | ||
366 | <button | ||
367 | type="button" | ||
368 | className={classes.clearNeedle} | ||
369 | onClick={() => this.setState({ needle: '', selected: -1 })} | ||
370 | > | ||
371 | <Icon | ||
372 | path={mdiCloseCircle} | ||
373 | size={0.7} | ||
374 | /> | ||
375 | </button> | ||
376 | )} | ||
377 | </div> | ||
378 | )} | ||
379 | <div | ||
380 | className={classnames({ | ||
381 | [`${classes.popup}`]: true, | ||
382 | [`${classes.open}`]: open, | ||
383 | })} | ||
384 | ref={this.scrollContainerRef} | ||
385 | > | ||
386 | {Object.keys(options!).map(((key, i) => ( | ||
387 | <div | ||
388 | key={key} | ||
389 | onClick={() => this.select(key)} | ||
390 | className={classnames({ | ||
391 | [`${classes.option}`]: true, | ||
392 | [`${classes.selected}`]: options![key] === selection, | ||
393 | [`${classes.focused}`]: selected === i, | ||
394 | })} | ||
395 | onMouseOver={() => this.setState({ selected: i })} | ||
396 | ref={selected === i ? this.activeOptionRef : null} | ||
397 | > | ||
398 | {options![key]} | ||
399 | </div> | ||
400 | )))} | ||
401 | </div> | ||
402 | </div> | ||
403 | <input | ||
404 | className={classes.input} | ||
405 | id={id} | ||
406 | name={name} | ||
407 | type="hidden" | ||
408 | defaultValue={value} | ||
409 | onChange={onChange} | ||
410 | disabled={disabled} | ||
411 | ref={this.inputRef} | ||
412 | /> | ||
413 | </Label> | ||
414 | {error && ( | ||
415 | <Error message={error} /> | ||
416 | )} | ||
417 | </Wrapper> | ||
418 | ); | ||
419 | } | ||
420 | } | ||
421 | |||
422 | export const Select = injectStyle(styles)(SelectComponent); | ||
diff --git a/packages/forms/src/toggle/index.tsx b/packages/forms/src/toggle/index.tsx index a1cd7f1a4..4f446ab1a 100644 --- a/packages/forms/src/toggle/index.tsx +++ b/packages/forms/src/toggle/index.tsx | |||
@@ -7,11 +7,13 @@ import injectStyle from 'react-jss'; | |||
7 | 7 | ||
8 | import { IFormField, IWithStyle, Omit } from '../typings/generic'; | 8 | import { IFormField, IWithStyle, Omit } from '../typings/generic'; |
9 | 9 | ||
10 | import Error from '../error'; | 10 | import { Error } from '../error'; |
11 | import Label from '../label'; | 11 | import { Label } from '../label'; |
12 | import Wrapper from '../wrapper'; | 12 | import { Wrapper } from '../wrapper'; |
13 | 13 | ||
14 | interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField, IWithStyle {} | 14 | interface IProps extends React.InputHTMLAttributes<HTMLInputElement>, IFormField, IWithStyle { |
15 | className?: string; | ||
16 | } | ||
15 | 17 | ||
16 | const styles = (theme: Theme) => ({ | 18 | const styles = (theme: Theme) => ({ |
17 | toggle: { | 19 | toggle: { |
@@ -65,6 +67,7 @@ class ToggleComponent extends Component<IProps> { | |||
65 | render() { | 67 | render() { |
66 | const { | 68 | const { |
67 | classes, | 69 | classes, |
70 | className, | ||
68 | disabled, | 71 | disabled, |
69 | error, | 72 | error, |
70 | id, | 73 | id, |
@@ -76,7 +79,9 @@ class ToggleComponent extends Component<IProps> { | |||
76 | } = this.props; | 79 | } = this.props; |
77 | 80 | ||
78 | return ( | 81 | return ( |
79 | <Wrapper> | 82 | <Wrapper |
83 | className={className} | ||
84 | > | ||
80 | <Label | 85 | <Label |
81 | title={label} | 86 | title={label} |
82 | showLabel={showLabel} | 87 | showLabel={showLabel} |
diff --git a/packages/forms/src/wrapper/index.tsx b/packages/forms/src/wrapper/index.tsx index 633cc4c99..87e2c6513 100644 --- a/packages/forms/src/wrapper/index.tsx +++ b/packages/forms/src/wrapper/index.tsx | |||
@@ -1,3 +1,4 @@ | |||
1 | import classnames from 'classnames'; | ||
1 | import { observer } from 'mobx-react'; | 2 | import { observer } from 'mobx-react'; |
2 | import React, { Component } from 'react'; | 3 | import React, { Component } from 'react'; |
3 | import injectStyle from 'react-jss'; | 4 | import injectStyle from 'react-jss'; |
@@ -7,22 +8,27 @@ import styles from './styles'; | |||
7 | 8 | ||
8 | interface IProps extends IWithStyle { | 9 | interface IProps extends IWithStyle { |
9 | children: React.ReactNode; | 10 | children: React.ReactNode; |
11 | className?: string; | ||
10 | } | 12 | } |
11 | 13 | ||
12 | @observer | 14 | @observer |
13 | class Wrapper extends Component<IProps> { | 15 | class WrapperComponent extends Component<IProps> { |
14 | render() { | 16 | render() { |
15 | const { | 17 | const { |
16 | children, | 18 | children, |
17 | classes, | 19 | classes, |
20 | className, | ||
18 | } = this.props; | 21 | } = this.props; |
19 | 22 | ||
20 | return ( | 23 | return ( |
21 | <div className={classes.container}> | 24 | <div className={classnames({ |
25 | [`${classes.container}`]: true, | ||
26 | [`${className}`]: className, | ||
27 | })}> | ||
22 | {children} | 28 | {children} |
23 | </div> | 29 | </div> |
24 | ); | 30 | ); |
25 | } | 31 | } |
26 | } | 32 | } |
27 | 33 | ||
28 | export default injectStyle(styles)(Wrapper); | 34 | export const Wrapper = injectStyle(styles)(WrapperComponent); |
diff --git a/packages/misty.yml b/packages/misty.yml index 2750925c0..2d8cff014 100644 --- a/packages/misty.yml +++ b/packages/misty.yml | |||
@@ -5,3 +5,7 @@ theme: | |||
5 | forms: | 5 | forms: |
6 | cwd: ./forms | 6 | cwd: ./forms |
7 | cmd: npm run dev | 7 | cmd: npm run dev |
8 | |||
9 | ui: | ||
10 | cwd: ./ui | ||
11 | cmd: npm run dev | ||
diff --git a/packages/theme/package-lock.json b/packages/theme/package-lock.json index a1673ffe8..f74af2f24 100644 --- a/packages/theme/package-lock.json +++ b/packages/theme/package-lock.json | |||
@@ -1,6 +1,6 @@ | |||
1 | { | 1 | { |
2 | "name": "@meetfranz/theme", | 2 | "name": "@meetfranz/theme", |
3 | "version": "1.0.2", | 3 | "version": "1.0.4", |
4 | "lockfileVersion": 1, | 4 | "lockfileVersion": 1, |
5 | "requires": true, | 5 | "requires": true, |
6 | "dependencies": { | 6 | "dependencies": { |
diff --git a/packages/theme/src/themes/dark/index.ts b/packages/theme/src/themes/dark/index.ts index 58ef63217..9b6bf055c 100644 --- a/packages/theme/src/themes/dark/index.ts +++ b/packages/theme/src/themes/dark/index.ts | |||
@@ -48,3 +48,15 @@ export const buttonLoaderColor = { | |||
48 | danger: '#FFF', | 48 | danger: '#FFF', |
49 | inverted: defaultStyles.brandPrimary, | 49 | inverted: defaultStyles.brandPrimary, |
50 | }; | 50 | }; |
51 | |||
52 | // Select | ||
53 | export const selectBackground = inputBackground; | ||
54 | export const selectBorder = inputBorder; | ||
55 | export const selectColor = inputColor; | ||
56 | export const selectToggleColor = inputPrefixColor; | ||
57 | export const selectPopupBackground = legacyStyles.darkThemeGrayLight; | ||
58 | export const selectOptionColor = '#FFF'; | ||
59 | export const selectOptionBorder = `1px solid ${color(legacyStyles.darkThemeGrayLight).darken(0.2).hex()}`; | ||
60 | export const selectOptionItemHover = color(legacyStyles.darkThemeGrayLight).darken(0.2).hex(); | ||
61 | export const selectOptionItemHoverColor = selectColor; | ||
62 | export const selectSearchColor = inputBackground; | ||
diff --git a/packages/theme/src/themes/default/index.ts b/packages/theme/src/themes/default/index.ts index 0f78928c3..d36558ff0 100644 --- a/packages/theme/src/themes/default/index.ts +++ b/packages/theme/src/themes/default/index.ts | |||
@@ -2,6 +2,14 @@ import color from 'color'; | |||
2 | 2 | ||
3 | import * as legacyStyles from '../legacy'; | 3 | import * as legacyStyles from '../legacy'; |
4 | 4 | ||
5 | export interface IStyleTypes { | ||
6 | [index: string]: { | ||
7 | accent: string; | ||
8 | contrast: string; | ||
9 | border?: string; | ||
10 | }; | ||
11 | } | ||
12 | |||
5 | export const brandPrimary = '#3498db'; | 13 | export const brandPrimary = '#3498db'; |
6 | export const brandSuccess = '#5cb85c'; | 14 | export const brandSuccess = '#5cb85c'; |
7 | export const brandInfo = '#5bc0de'; | 15 | export const brandInfo = '#5bc0de'; |
@@ -51,6 +59,35 @@ export const toggleButtonActive = brandPrimary; | |||
51 | export const toggleWidth = 40; | 59 | export const toggleWidth = 40; |
52 | export const toggleHeight = 14; | 60 | export const toggleHeight = 14; |
53 | 61 | ||
62 | // Style Types | ||
63 | export const styleTypes: IStyleTypes = { | ||
64 | primary: { | ||
65 | accent: brandPrimary, | ||
66 | contrast: '#FFF', | ||
67 | }, | ||
68 | secondary: { | ||
69 | accent: legacyStyles.themeGrayLighter, | ||
70 | contrast: legacyStyles.themeGray, | ||
71 | }, | ||
72 | success: { | ||
73 | accent: brandSuccess, | ||
74 | contrast: '#FFF', | ||
75 | }, | ||
76 | warning: { | ||
77 | accent: brandWarning, | ||
78 | contrast: '#FFF', | ||
79 | }, | ||
80 | danger: { | ||
81 | accent: brandDanger, | ||
82 | contrast: '#FFF', | ||
83 | }, | ||
84 | inverted: { | ||
85 | accent: 'none', | ||
86 | contrast: brandPrimary, | ||
87 | border: `1px solid ${brandPrimary}`, | ||
88 | }, | ||
89 | }; | ||
90 | |||
54 | // Button | 91 | // Button |
55 | export const buttonPrimaryBackground = brandPrimary; | 92 | export const buttonPrimaryBackground = brandPrimary; |
56 | export const buttonPrimaryTextColor = '#FFF'; | 93 | export const buttonPrimaryTextColor = '#FFF'; |
@@ -79,3 +116,24 @@ export const buttonLoaderColor = { | |||
79 | danger: '#FFF', | 116 | danger: '#FFF', |
80 | inverted: brandPrimary, | 117 | inverted: brandPrimary, |
81 | }; | 118 | }; |
119 | |||
120 | // Select | ||
121 | export const selectBackground = inputBackground; | ||
122 | export const selectBorder = inputBorder; | ||
123 | export const selectHeight = inputHeight; | ||
124 | export const selectColor = inputColor; | ||
125 | export const selectToggleColor = inputPrefixColor; | ||
126 | export const selectPopupBackground = '#FFF'; | ||
127 | export const selectOptionColor = inputColor; | ||
128 | export const selectOptionBorder = `1px solid ${legacyStyles.themeGrayLightest}`; | ||
129 | export const selectOptionItemHover = legacyStyles.themeGrayLighter; | ||
130 | export const selectOptionItemHoverColor = selectColor; | ||
131 | export const selectOptionItemActive = brandPrimary; | ||
132 | export const selectOptionItemActiveColor = '#FFF'; | ||
133 | export const selectSearchBackground = legacyStyles.themeGrayLighter; | ||
134 | export const selectSearchColor = inputColor; | ||
135 | export const selectDisabledOpacity = inputDisabledOpacity; | ||
136 | |||
137 | // Badge | ||
138 | export const badgeFontSize = uiFontSize - 2; | ||
139 | export const badgeBorderRadius = 50; | ||
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 | }); | ||
diff --git a/uidev/src/app.tsx b/uidev/src/app.tsx index 0fd524e34..870911c2f 100644 --- a/uidev/src/app.tsx +++ b/uidev/src/app.tsx | |||
@@ -7,8 +7,14 @@ import injectSheet from 'react-jss'; | |||
7 | 7 | ||
8 | import { WithTheme } from './withTheme'; | 8 | import { WithTheme } from './withTheme'; |
9 | 9 | ||
10 | import './stories/badge.stories'; | ||
10 | import './stories/button.stories'; | 11 | import './stories/button.stories'; |
12 | import './stories/headline.stories'; | ||
13 | import './stories/icon.stories'; | ||
14 | import './stories/infobox.stories'; | ||
11 | import './stories/input.stories'; | 15 | import './stories/input.stories'; |
16 | import './stories/loader.stories'; | ||
17 | import './stories/select.stories'; | ||
12 | import './stories/toggle.stories'; | 18 | import './stories/toggle.stories'; |
13 | 19 | ||
14 | import { store } from './stores'; | 20 | import { store } from './stores'; |
@@ -31,6 +37,8 @@ const styles = { | |||
31 | position: 'fixed' as CSS.PositionProperty, | 37 | position: 'fixed' as CSS.PositionProperty, |
32 | listStyleType: 'none', | 38 | listStyleType: 'none', |
33 | fontSize: 14, | 39 | fontSize: 14, |
40 | overflow: 'scroll', | ||
41 | height: '100%', | ||
34 | }, | 42 | }, |
35 | storyList: { | 43 | storyList: { |
36 | paddingLeft: 18, | 44 | paddingLeft: 18, |
diff --git a/uidev/src/stories/badge.stories.tsx b/uidev/src/stories/badge.stories.tsx new file mode 100644 index 000000000..6de2034bf --- /dev/null +++ b/uidev/src/stories/badge.stories.tsx | |||
@@ -0,0 +1,21 @@ | |||
1 | import React from 'react'; | ||
2 | |||
3 | import { Badge } from '@meetfranz/ui'; | ||
4 | import { storiesOf } from '../stores/stories'; | ||
5 | |||
6 | storiesOf('Badge') | ||
7 | .add('Basic', () => ( | ||
8 | <> | ||
9 | <Badge>New</Badge> | ||
10 | </> | ||
11 | )) | ||
12 | .add('Styles', () => ( | ||
13 | <> | ||
14 | <Badge type="primary">Primary</Badge> | ||
15 | <Badge type="secondary">secondary</Badge> | ||
16 | <Badge type="success">success</Badge> | ||
17 | <Badge type="warning">warning</Badge> | ||
18 | <Badge type="danger">danger</Badge> | ||
19 | <Badge type="inverted">inverted</Badge> | ||
20 | </> | ||
21 | )); | ||
diff --git a/uidev/src/stories/headline.stories.tsx b/uidev/src/stories/headline.stories.tsx new file mode 100644 index 000000000..f42771cae --- /dev/null +++ b/uidev/src/stories/headline.stories.tsx | |||
@@ -0,0 +1,54 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import { observer } from 'mobx-react'; | ||
3 | import React from 'react'; | ||
4 | import uuid from 'uuid/v4'; | ||
5 | |||
6 | import { H1, H2, H3, H4 } from '@meetfranz/ui'; | ||
7 | import { storiesOf } from '../stores/stories'; | ||
8 | |||
9 | // interface IStoreArgs { | ||
10 | // value?: boolean; | ||
11 | // checked?: boolean; | ||
12 | // label?: string; | ||
13 | // id?: string; | ||
14 | // name?: string; | ||
15 | // disabled?: boolean; | ||
16 | // error?: string; | ||
17 | // } | ||
18 | |||
19 | // const createStore = (args?: IStoreArgs) => { | ||
20 | // return observable(Object.assign({ | ||
21 | // id: `element-${uuid()}`, | ||
22 | // name: 'toggle', | ||
23 | // label: 'Label', | ||
24 | // value: true, | ||
25 | // checked: false, | ||
26 | // disabled: false, | ||
27 | // error: '', | ||
28 | // }, args)); | ||
29 | // }; | ||
30 | |||
31 | // const WithStoreToggle = observer(({ store }: { store: any }) => ( | ||
32 | // <> | ||
33 | // <Toggle | ||
34 | // value={store.value} | ||
35 | // checked={store.checked} | ||
36 | // label={store.label} | ||
37 | // id={store.id} | ||
38 | // name={store.name} | ||
39 | // disabled={store.disabled} | ||
40 | // error={store.error} | ||
41 | // onChange={() => store.checked = !store.checked} | ||
42 | // /> | ||
43 | // </> | ||
44 | // )); | ||
45 | |||
46 | storiesOf('Typo') | ||
47 | .add('Headlines', () => ( | ||
48 | <> | ||
49 | <H1>Welcome to the world of tomorrow</H1> | ||
50 | <H2>Welcome to the world of tomorrow</H2> | ||
51 | <H3>Welcome to the world of tomorrow</H3> | ||
52 | <H4>Welcome to the world of tomorrow</H4> | ||
53 | </> | ||
54 | )); | ||
diff --git a/uidev/src/stories/icon.stories.tsx b/uidev/src/stories/icon.stories.tsx new file mode 100644 index 000000000..c8e7f8ced --- /dev/null +++ b/uidev/src/stories/icon.stories.tsx | |||
@@ -0,0 +1,53 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import { observer } from 'mobx-react'; | ||
3 | import React from 'react'; | ||
4 | import uuid from 'uuid/v4'; | ||
5 | |||
6 | import { Icon } from '@meetfranz/ui'; | ||
7 | import { storiesOf } from '../stores/stories'; | ||
8 | |||
9 | // interface IStoreArgs { | ||
10 | // value?: boolean; | ||
11 | // checked?: boolean; | ||
12 | // label?: string; | ||
13 | // id?: string; | ||
14 | // name?: string; | ||
15 | // disabled?: boolean; | ||
16 | // error?: string; | ||
17 | // } | ||
18 | |||
19 | // const createStore = (args?: IStoreArgs) => { | ||
20 | // return observable(Object.assign({ | ||
21 | // id: `element-${uuid()}`, | ||
22 | // name: 'toggle', | ||
23 | // label: 'Label', | ||
24 | // value: true, | ||
25 | // checked: false, | ||
26 | // disabled: false, | ||
27 | // error: '', | ||
28 | // }, args)); | ||
29 | // }; | ||
30 | |||
31 | // const WithStoreToggle = observer(({ store }: { store: any }) => ( | ||
32 | // <> | ||
33 | // <Toggle | ||
34 | // value={store.value} | ||
35 | // checked={store.checked} | ||
36 | // label={store.label} | ||
37 | // id={store.id} | ||
38 | // name={store.name} | ||
39 | // disabled={store.disabled} | ||
40 | // error={store.error} | ||
41 | // onChange={() => store.checked = !store.checked} | ||
42 | // /> | ||
43 | // </> | ||
44 | // )); | ||
45 | |||
46 | storiesOf('Icon') | ||
47 | .add('Basic', () => ( | ||
48 | <> | ||
49 | <Icon icon="mdiAccountCircle" /> | ||
50 | <Icon icon="mdiAccountCircle" size={2} /> | ||
51 | <Icon icon="mdiAccountCircle" size={3} /> | ||
52 | </> | ||
53 | )); | ||
diff --git a/uidev/src/stories/infobox.stories.tsx b/uidev/src/stories/infobox.stories.tsx new file mode 100644 index 000000000..2a5e8b0d5 --- /dev/null +++ b/uidev/src/stories/infobox.stories.tsx | |||
@@ -0,0 +1,126 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import { observer } from 'mobx-react'; | ||
3 | import React from 'react'; | ||
4 | |||
5 | import { Infobox } from '@meetfranz/ui'; | ||
6 | import { storiesOf } from '../stores/stories'; | ||
7 | |||
8 | interface IStoreArgs { | ||
9 | icon?: string; | ||
10 | ctaLabel?: string; | ||
11 | type?: string; | ||
12 | dismissable?: boolean; | ||
13 | } | ||
14 | |||
15 | const createStore = (args?: IStoreArgs) => { | ||
16 | return observable(Object.assign({ | ||
17 | type: 'primary', | ||
18 | ctaOnClick: () => { | ||
19 | alert('on click handler'); | ||
20 | }, | ||
21 | }, args)); | ||
22 | }; | ||
23 | |||
24 | const WithStoreInfobox = observer(({ store, children }: { store: any, children: string | React.ReactNode }) => ( | ||
25 | <> | ||
26 | <Infobox | ||
27 | icon={store.icon} | ||
28 | ctaLabel={store.ctaLabel} | ||
29 | type={store.type} | ||
30 | ctaOnClick={store.ctaOnClick} | ||
31 | dismissable={store.dismissable} | ||
32 | > | ||
33 | {children} | ||
34 | </Infobox> | ||
35 | </> | ||
36 | )); | ||
37 | |||
38 | storiesOf('Infobox') | ||
39 | .add('Basic', () => ( | ||
40 | <WithStoreInfobox store={createStore()}>Welcome to the world of tomorrow</WithStoreInfobox> | ||
41 | )) | ||
42 | .add('Icon + Dismissable', () => ( | ||
43 | <WithStoreInfobox | ||
44 | store={createStore({ | ||
45 | icon: 'mdiEarth', | ||
46 | dismissable: true, | ||
47 | })} | ||
48 | > | ||
49 | Welcome to the world of tomorrow | ||
50 | </WithStoreInfobox> | ||
51 | )) | ||
52 | .add('With CTA', () => ( | ||
53 | <WithStoreInfobox | ||
54 | store={createStore({ | ||
55 | icon: 'mdiEarth', | ||
56 | ctaLabel: 'Ok, hi!', | ||
57 | })} | ||
58 | > | ||
59 | Welcome to the world of tomorrow | ||
60 | </WithStoreInfobox> | ||
61 | )) | ||
62 | .add('With long text', () => ( | ||
63 | <WithStoreInfobox | ||
64 | store={createStore({ | ||
65 | icon: 'mdiEarth', | ||
66 | ctaLabel: 'Ok, hi!', | ||
67 | })} | ||
68 | > | ||
69 | Franz is your messaging app / former Emperor of Austria and combines chat & messaging services into one application. Franz currently supports Slack, WhatsApp, WeChat, HipChat, Facebook Messenger, Telegram, Google Hangouts,GroupMe, Skype and many more. | ||
70 | </WithStoreInfobox> | ||
71 | )) | ||
72 | .add('Secondary', () => ( | ||
73 | <WithStoreInfobox | ||
74 | store={createStore({ | ||
75 | icon: 'mdiEarth', | ||
76 | ctaLabel: 'Ok, hi!', | ||
77 | type: 'secondary', | ||
78 | })} | ||
79 | > | ||
80 | Welcome to the world of tomorrow | ||
81 | </WithStoreInfobox> | ||
82 | )) | ||
83 | .add('Success', () => ( | ||
84 | <WithStoreInfobox | ||
85 | store={createStore({ | ||
86 | icon: 'mdiEarth', | ||
87 | ctaLabel: 'Ok, hi!', | ||
88 | type: 'success', | ||
89 | })} | ||
90 | > | ||
91 | Welcome to the world of tomorrow | ||
92 | </WithStoreInfobox> | ||
93 | )) | ||
94 | .add('Warning', () => ( | ||
95 | <WithStoreInfobox | ||
96 | store={createStore({ | ||
97 | icon: 'mdiEarth', | ||
98 | ctaLabel: 'Ok, hi!', | ||
99 | type: 'warning', | ||
100 | })} | ||
101 | > | ||
102 | Welcome to the world of tomorrow | ||
103 | </WithStoreInfobox> | ||
104 | )) | ||
105 | .add('Danger', () => ( | ||
106 | <WithStoreInfobox | ||
107 | store={createStore({ | ||
108 | icon: 'mdiEarth', | ||
109 | ctaLabel: 'Ok, hi!', | ||
110 | type: 'danger', | ||
111 | })} | ||
112 | > | ||
113 | Welcome to the world of tomorrow | ||
114 | </WithStoreInfobox> | ||
115 | )) | ||
116 | .add('Inverted', () => ( | ||
117 | <WithStoreInfobox | ||
118 | store={createStore({ | ||
119 | icon: 'mdiEarth', | ||
120 | ctaLabel: 'Ok, hi!', | ||
121 | type: 'inverted', | ||
122 | })} | ||
123 | > | ||
124 | Welcome to the world of tomorrow | ||
125 | </WithStoreInfobox> | ||
126 | )); | ||
diff --git a/uidev/src/stories/loader.stories.tsx b/uidev/src/stories/loader.stories.tsx new file mode 100644 index 000000000..84e813c04 --- /dev/null +++ b/uidev/src/stories/loader.stories.tsx | |||
@@ -0,0 +1,14 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | import { observer } from 'mobx-react'; | ||
3 | import React from 'react'; | ||
4 | import uuid from 'uuid/v4'; | ||
5 | |||
6 | import { Loader } from '@meetfranz/ui'; | ||
7 | import { storiesOf } from '../stores/stories'; | ||
8 | |||
9 | storiesOf('Loader') | ||
10 | .add('Basic', () => ( | ||
11 | <> | ||
12 | <Loader /> | ||
13 | </> | ||
14 | )); | ||
diff --git a/uidev/src/stories/select.stories.tsx b/uidev/src/stories/select.stories.tsx new file mode 100644 index 000000000..81f7f08a6 --- /dev/null +++ b/uidev/src/stories/select.stories.tsx | |||
@@ -0,0 +1,320 @@ | |||
1 | import React from 'react'; | ||
2 | import uuid from 'uuid/v4'; | ||
3 | |||
4 | import { Select } from '@meetfranz/forms'; | ||
5 | import { storiesOf } from '../stores/stories'; | ||
6 | |||
7 | const defaultProps = () => { | ||
8 | const id = uuid(); | ||
9 | return { | ||
10 | label: 'Label', | ||
11 | id: `test-${id}`, | ||
12 | name: `test-${id}`, | ||
13 | options: { | ||
14 | AF: 'Afghanistan', | ||
15 | AL: 'Albania', | ||
16 | DZ: 'Algeria', | ||
17 | AS: 'American Samoa', | ||
18 | AD: 'Andorra', | ||
19 | AO: 'Angola', | ||
20 | AI: 'Anguilla', | ||
21 | AQ: 'Antarctica', | ||
22 | AG: 'Antigua and Barbuda', | ||
23 | AR: 'Argentina', | ||
24 | AM: 'Armenia', | ||
25 | AW: 'Aruba', | ||
26 | AC: 'Ascension Island', | ||
27 | AU: 'Australia', | ||
28 | AT: 'Austria', | ||
29 | AZ: 'Azerbaijan', | ||
30 | BS: 'Bahamas', | ||
31 | BH: 'Bahrain', | ||
32 | BD: 'Bangladesh', | ||
33 | BB: 'Barbados', | ||
34 | BY: 'Belarus', | ||
35 | BE: 'Belgium', | ||
36 | BZ: 'Belize', | ||
37 | BJ: 'Benin', | ||
38 | BM: 'Bermuda', | ||
39 | BT: 'Bhutan', | ||
40 | BO: 'Bolivia', | ||
41 | BA: 'Bosnia and Herzegovina', | ||
42 | BW: 'Botswana', | ||
43 | BV: 'Bouvet Island', | ||
44 | BR: 'Brazil', | ||
45 | BQ: 'British Antarctic Territory', | ||
46 | IO: 'British Indian Ocean Territory', | ||
47 | VG: 'British Virgin Islands', | ||
48 | BN: 'Brunei', | ||
49 | BG: 'Bulgaria', | ||
50 | BF: 'Burkina Faso', | ||
51 | BI: 'Burundi', | ||
52 | KH: 'Cambodia', | ||
53 | CM: 'Cameroon', | ||
54 | CA: 'Canada', | ||
55 | IC: 'Canary Islands', | ||
56 | CT: 'Canton and Enderbury Islands', | ||
57 | CV: 'Cape Verde', | ||
58 | KY: 'Cayman Islands', | ||
59 | CF: 'Central African Republic', | ||
60 | EA: 'Ceuta and Melilla', | ||
61 | TD: 'Chad', | ||
62 | CL: 'Chile', | ||
63 | CN: 'China', | ||
64 | CX: 'Christmas Island', | ||
65 | CP: 'Clipperton Island', | ||
66 | CC: 'Cocos [Keeling] Islands', | ||
67 | CO: 'Colombia', | ||
68 | KM: 'Comoros', | ||
69 | CD: 'Congo - Kinshasa', | ||
70 | CG: 'Congo [Republic]', | ||
71 | CK: 'Cook Islands', | ||
72 | CR: 'Costa Rica', | ||
73 | HR: 'Croatia', | ||
74 | CU: 'Cuba', | ||
75 | CY: 'Cyprus', | ||
76 | CZ: 'Czech Republic', | ||
77 | CI: 'Côte d’Ivoire', | ||
78 | DK: 'Denmark', | ||
79 | DG: 'Diego Garcia', | ||
80 | DJ: 'Djibouti', | ||
81 | DM: 'Dominica', | ||
82 | DO: 'Dominican Republic', | ||
83 | NQ: 'Dronning Maud Land', | ||
84 | TL: 'East Timor', | ||
85 | EC: 'Ecuador', | ||
86 | EG: 'Egypt', | ||
87 | SV: 'El Salvador', | ||
88 | GQ: 'Equatorial Guinea', | ||
89 | ER: 'Eritrea', | ||
90 | EE: 'Estonia', | ||
91 | ET: 'Ethiopia', | ||
92 | FK: 'Falkland Islands', | ||
93 | FO: 'Faroe Islands', | ||
94 | FJ: 'Fiji', | ||
95 | FI: 'Finland', | ||
96 | FR: 'France', | ||
97 | GF: 'French Guiana', | ||
98 | PF: 'French Polynesia', | ||
99 | TF: 'French Southern Territories', | ||
100 | FQ: 'French Southern and Antarctic Territories', | ||
101 | GA: 'Gabon', | ||
102 | GM: 'Gambia', | ||
103 | GE: 'Georgia', | ||
104 | DE: 'Germany', | ||
105 | GH: 'Ghana', | ||
106 | GI: 'Gibraltar', | ||
107 | GR: 'Greece', | ||
108 | GL: 'Greenland', | ||
109 | GD: 'Grenada', | ||
110 | GP: 'Guadeloupe', | ||
111 | GU: 'Guam', | ||
112 | GT: 'Guatemala', | ||
113 | GG: 'Guernsey', | ||
114 | GN: 'Guinea', | ||
115 | GW: 'Guinea-Bissau', | ||
116 | GY: 'Guyana', | ||
117 | HT: 'Haiti', | ||
118 | HM: 'Heard Island and McDonald Islands', | ||
119 | HN: 'Honduras', | ||
120 | HK: 'Hong Kong', | ||
121 | HU: 'Hungary', | ||
122 | IS: 'Iceland', | ||
123 | IN: 'India', | ||
124 | ID: 'Indonesia', | ||
125 | IR: 'Iran', | ||
126 | IQ: 'Iraq', | ||
127 | IE: 'Ireland', | ||
128 | IM: 'Isle of Man', | ||
129 | IL: 'Israel', | ||
130 | IT: 'Italy', | ||
131 | JM: 'Jamaica', | ||
132 | JP: 'Japan', | ||
133 | JE: 'Jersey', | ||
134 | JT: 'Johnston Island', | ||
135 | JO: 'Jordan', | ||
136 | KZ: 'Kazakhstan', | ||
137 | KE: 'Kenya', | ||
138 | KI: 'Kiribati', | ||
139 | XK: 'Kosovo', | ||
140 | KW: 'Kuwait', | ||
141 | KG: 'Kyrgyzstan', | ||
142 | LA: 'Laos', | ||
143 | LV: 'Latvia', | ||
144 | LB: 'Lebanon', | ||
145 | LS: 'Lesotho', | ||
146 | LR: 'Liberia', | ||
147 | LY: 'Libya', | ||
148 | LI: 'Liechtenstein', | ||
149 | LT: 'Lithuania', | ||
150 | LU: 'Luxembourg', | ||
151 | MO: 'Macau', | ||
152 | MK: 'Macedonia', | ||
153 | MG: 'Madagascar', | ||
154 | MW: 'Malawi', | ||
155 | MY: 'Malaysia', | ||
156 | MV: 'Maldives', | ||
157 | ML: 'Mali', | ||
158 | MT: 'Malta', | ||
159 | MH: 'Marshall Islands', | ||
160 | MQ: 'Martinique', | ||
161 | MR: 'Mauritania', | ||
162 | MU: 'Mauritius', | ||
163 | YT: 'Mayotte', | ||
164 | FX: 'Metropolitan France', | ||
165 | MX: 'Mexico', | ||
166 | FM: 'Micronesia', | ||
167 | MI: 'Midway Islands', | ||
168 | MD: 'Moldova', | ||
169 | MC: 'Monaco', | ||
170 | MN: 'Mongolia', | ||
171 | ME: 'Montenegro', | ||
172 | MS: 'Montserrat', | ||
173 | MA: 'Morocco', | ||
174 | MZ: 'Mozambique', | ||
175 | MM: 'Myanmar [Burma]', | ||
176 | NA: 'Namibia', | ||
177 | NR: 'Nauru', | ||
178 | NP: 'Nepal', | ||
179 | NL: 'Netherlands', | ||
180 | AN: 'Netherlands Antilles', | ||
181 | NC: 'New Caledonia', | ||
182 | NZ: 'New Zealand', | ||
183 | NI: 'Nicaragua', | ||
184 | NE: 'Niger', | ||
185 | NG: 'Nigeria', | ||
186 | NU: 'Niue', | ||
187 | NF: 'Norfolk Island', | ||
188 | KP: 'North Korea', | ||
189 | VD: 'North Vietnam', | ||
190 | MP: 'Northern Mariana Islands', | ||
191 | NO: 'Norway', | ||
192 | OM: 'Oman', | ||
193 | QO: 'Outlying Oceania', | ||
194 | PC: 'Pacific Islands Trust Territory', | ||
195 | PK: 'Pakistan', | ||
196 | PW: 'Palau', | ||
197 | PS: 'Palestinian Territories', | ||
198 | PA: 'Panama', | ||
199 | PZ: 'Panama Canal Zone', | ||
200 | PG: 'Papua New Guinea', | ||
201 | PY: 'Paraguay', | ||
202 | YD: 'Peoples Democratic Republic of Yemen', | ||
203 | PE: 'Peru', | ||
204 | PH: 'Philippines', | ||
205 | PN: 'Pitcairn Islands', | ||
206 | PL: 'Poland', | ||
207 | PT: 'Portugal', | ||
208 | PR: 'Puerto Rico', | ||
209 | QA: 'Qatar', | ||
210 | RO: 'Romania', | ||
211 | RU: 'Russia', | ||
212 | RW: 'Rwanda', | ||
213 | RE: 'Réunion', | ||
214 | BL: 'Saint Barthélemy', | ||
215 | SH: 'Saint Helena', | ||
216 | KN: 'Saint Kitts and Nevis', | ||
217 | LC: 'Saint Lucia', | ||
218 | MF: 'Saint Martin', | ||
219 | PM: 'Saint Pierre and Miquelon', | ||
220 | VC: 'Saint Vincent and the Grenadines', | ||
221 | WS: 'Samoa', | ||
222 | SM: 'San Marino', | ||
223 | SA: 'Saudi Arabia', | ||
224 | SN: 'Senegal', | ||
225 | RS: 'Serbia', | ||
226 | CS: 'Serbia and Montenegro', | ||
227 | SC: 'Seychelles', | ||
228 | SL: 'Sierra Leone', | ||
229 | SG: 'Singapore', | ||
230 | SK: 'Slovakia', | ||
231 | SI: 'Slovenia', | ||
232 | SB: 'Solomon Islands', | ||
233 | SO: 'Somalia', | ||
234 | ZA: 'South Africa', | ||
235 | GS: 'South Georgia and the South Sandwich Islands', | ||
236 | KR: 'South Korea', | ||
237 | ES: 'Spain', | ||
238 | LK: 'Sri Lanka', | ||
239 | SD: 'Sudan', | ||
240 | SR: 'Suriname', | ||
241 | SJ: 'Svalbard and Jan Mayen', | ||
242 | SZ: 'Swaziland', | ||
243 | SE: 'Sweden', | ||
244 | CH: 'Switzerland', | ||
245 | SY: 'Syria', | ||
246 | ST: 'São Tomé and Príncipe', | ||
247 | TW: 'Taiwan', | ||
248 | TJ: 'Tajikistan', | ||
249 | TZ: 'Tanzania', | ||
250 | TH: 'Thailand', | ||
251 | TG: 'Togo', | ||
252 | TK: 'Tokelau', | ||
253 | TO: 'Tonga', | ||
254 | TT: 'Trinidad and Tobago', | ||
255 | TA: 'Tristan da Cunha', | ||
256 | TN: 'Tunisia', | ||
257 | TR: 'Turkey', | ||
258 | TM: 'Turkmenistan', | ||
259 | TC: 'Turks and Caicos Islands', | ||
260 | TV: 'Tuvalu', | ||
261 | UM: 'U.S. Minor Outlying Islands', | ||
262 | PU: 'U.S. Miscellaneous Pacific Islands', | ||
263 | VI: 'U.S. Virgin Islands', | ||
264 | UG: 'Uganda', | ||
265 | UA: 'Ukraine', | ||
266 | AE: 'United Arab Emirates', | ||
267 | GB: 'United Kingdom', | ||
268 | US: 'United States', | ||
269 | UY: 'Uruguay', | ||
270 | UZ: 'Uzbekistan', | ||
271 | VU: 'Vanuatu', | ||
272 | VA: 'Vatican City', | ||
273 | VE: 'Venezuela', | ||
274 | VN: 'Vietnam', | ||
275 | WK: 'Wake Island', | ||
276 | WF: 'Wallis and Futuna', | ||
277 | EH: 'Western Sahara', | ||
278 | YE: 'Yemen', | ||
279 | ZM: 'Zambia', | ||
280 | ZW: 'Zimbabwe', | ||
281 | AX: 'Åland Islands', | ||
282 | }, | ||
283 | actionText: 'Select country', | ||
284 | // defaultValue: 'AT', | ||
285 | onChange: (e: React.ChangeEvent<HTMLInputElement>) => console.log('changed event', e), | ||
286 | }; | ||
287 | }; | ||
288 | |||
289 | storiesOf('Select') | ||
290 | .add('Basic', () => ( | ||
291 | <Select | ||
292 | {...defaultProps()} | ||
293 | /> | ||
294 | )) | ||
295 | .add('With preselection', () => ( | ||
296 | <Select | ||
297 | {...defaultProps()} | ||
298 | defaultValue="AT" | ||
299 | /> | ||
300 | )) | ||
301 | .add('With search', () => ( | ||
302 | <Select | ||
303 | {...defaultProps()} | ||
304 | showSearch | ||
305 | /> | ||
306 | )) | ||
307 | .add('Disabled', () => ( | ||
308 | <Select | ||
309 | {...defaultProps()} | ||
310 | showSearch | ||
311 | disabled | ||
312 | /> | ||
313 | )) | ||
314 | .add('With error', () => ( | ||
315 | <Select | ||
316 | {...defaultProps()} | ||
317 | showSearch | ||
318 | error="Your selection was a bit too funky for my taste" | ||
319 | /> | ||
320 | )); | ||