diff options
author | Stefan Malzner <stefan@adlk.io> | 2019-01-14 22:26:06 +0100 |
---|---|---|
committer | Stefan Malzner <stefan@adlk.io> | 2019-01-14 22:26:06 +0100 |
commit | 8b4231e3109d4b29e4d90f4553f718a1d7867bc5 (patch) | |
tree | b7c89bd60d01cca3692a3e6df580669fd08a4b27 /packages/forms/src | |
parent | Update package.json (diff) | |
download | ferdium-app-8b4231e3109d4b29e4d90f4553f718a1d7867bc5.tar.gz ferdium-app-8b4231e3109d4b29e4d90f4553f718a1d7867bc5.tar.zst ferdium-app-8b4231e3109d4b29e4d90f4553f718a1d7867bc5.zip |
Add buttons
Diffstat (limited to 'packages/forms/src')
-rw-r--r-- | packages/forms/src/button/index.tsx | 172 | ||||
-rw-r--r-- | packages/forms/src/error/styles.ts | 1 | ||||
-rw-r--r-- | packages/forms/src/index.ts | 1 | ||||
-rw-r--r-- | packages/forms/src/input/index.tsx | 34 | ||||
-rw-r--r-- | packages/forms/src/input/styles.ts | 6 | ||||
-rw-r--r-- | packages/forms/src/label/styles.ts | 1 | ||||
-rw-r--r-- | packages/forms/src/toggle/index.tsx | 8 | ||||
-rw-r--r-- | packages/forms/src/typings/generic.ts | 2 | ||||
-rw-r--r-- | packages/forms/src/wrapper/index.tsx | 2 |
9 files changed, 201 insertions, 26 deletions
diff --git a/packages/forms/src/button/index.tsx b/packages/forms/src/button/index.tsx new file mode 100644 index 000000000..c4a138b16 --- /dev/null +++ b/packages/forms/src/button/index.tsx | |||
@@ -0,0 +1,172 @@ | |||
1 | import { Theme } from '@meetfranz/theme'; | ||
2 | import classnames from 'classnames'; | ||
3 | import CSS from 'csstype'; | ||
4 | import { observer } from 'mobx-react'; | ||
5 | import React, { Component } from 'react'; | ||
6 | import injectStyle from 'react-jss'; | ||
7 | import Loader from 'react-loader'; | ||
8 | |||
9 | import { IFormField, IWithStyle } from '../typings/generic'; | ||
10 | |||
11 | type ButtonType = 'primary' | 'secondary' | 'danger' | 'warning' | 'inverted'; | ||
12 | |||
13 | interface IProps extends React.InputHTMLAttributes<HTMLButtonElement>, IFormField, IWithStyle { | ||
14 | buttonType?: ButtonType; | ||
15 | stretch?: boolean; | ||
16 | loaded?: boolean; | ||
17 | busy?: boolean; | ||
18 | } | ||
19 | |||
20 | interface IState { | ||
21 | busy: boolean; | ||
22 | } | ||
23 | |||
24 | const styles = (theme: Theme) => ({ | ||
25 | button: { | ||
26 | borderRadius: theme.borderRadiusSmall, | ||
27 | border: 'none', | ||
28 | display: 'flex', | ||
29 | position: 'relative' as CSS.PositionProperty, | ||
30 | transition: 'background .5s', | ||
31 | textAlign: 'center' as CSS.TextAlignProperty, | ||
32 | outline: 'none', | ||
33 | alignItems: 'center', | ||
34 | padding: 0, | ||
35 | width: (props: IProps) => (props.stretch ? '100%' : 'auto') as CSS.WidthProperty<string>, | ||
36 | fontSize: theme.uiFontSize, | ||
37 | }, | ||
38 | label: { | ||
39 | margin: '10px 20px', | ||
40 | width: '100%', | ||
41 | }, | ||
42 | primary: { | ||
43 | background: theme.buttonPrimaryBackground, | ||
44 | color: theme.buttonPrimaryTextColor, | ||
45 | }, | ||
46 | secondary: { | ||
47 | background: theme.buttonSecondaryBackground, | ||
48 | color: theme.buttonSecondaryTextColor, | ||
49 | }, | ||
50 | danger: { | ||
51 | background: theme.buttonDangerBackground, | ||
52 | color: theme.buttonDangerTextColor, | ||
53 | }, | ||
54 | warning: { | ||
55 | background: theme.buttonWarningBackground, | ||
56 | color: theme.buttonWarningTextColor, | ||
57 | }, | ||
58 | inverted: { | ||
59 | background: theme.buttonInvertedBackground, | ||
60 | color: theme.buttonInvertedTextColor, | ||
61 | border: theme.buttonInvertedBorder, | ||
62 | }, | ||
63 | disabled: { | ||
64 | opacity: theme.inputDisabledOpacity, | ||
65 | }, | ||
66 | loader: { | ||
67 | position: 'relative' as CSS.PositionProperty, | ||
68 | width: 20, | ||
69 | height: 18, | ||
70 | zIndex: 9999, | ||
71 | }, | ||
72 | loaderContainer: { | ||
73 | width: (props: IProps): string => (!props.busy ? '0' : '40px'), | ||
74 | height: 20, | ||
75 | overflow: 'hidden', | ||
76 | transition: 'all 0.3s', | ||
77 | marginLeft: (props: IProps): number => !props.busy ? 10 : 20, | ||
78 | marginRight: (props: IProps): number => !props.busy ? -10 : -20, | ||
79 | position: (props: IProps): CSS.PositionProperty => props.stretch ? 'absolute' : 'inherit', | ||
80 | }, | ||
81 | }); | ||
82 | |||
83 | @observer | ||
84 | class ButtonComponent extends Component<IProps> { | ||
85 | public static defaultProps = { | ||
86 | type: 'button', | ||
87 | disabled: false, | ||
88 | onClick: () => null, | ||
89 | buttonType: 'primary' as ButtonType, | ||
90 | stretch: false, | ||
91 | busy: false, | ||
92 | }; | ||
93 | |||
94 | state = { | ||
95 | busy: false, | ||
96 | }; | ||
97 | |||
98 | componentWillMount() { | ||
99 | this.setState({ busy: this.props.busy }); | ||
100 | } | ||
101 | |||
102 | componentWillReceiveProps(nextProps: IProps) { | ||
103 | if (nextProps.busy !== this.props.busy) { | ||
104 | if (this.props.busy) { | ||
105 | setTimeout(() => { | ||
106 | this.setState({ busy: nextProps.busy }); | ||
107 | }, 300); | ||
108 | } else { | ||
109 | this.setState({ busy: nextProps.busy }); | ||
110 | } | ||
111 | } | ||
112 | } | ||
113 | |||
114 | render() { | ||
115 | const { | ||
116 | classes, | ||
117 | theme, | ||
118 | disabled, | ||
119 | id, | ||
120 | label, | ||
121 | type, | ||
122 | onClick, | ||
123 | buttonType, | ||
124 | loaded, | ||
125 | busy: busyProp, | ||
126 | } = this.props; | ||
127 | |||
128 | const { | ||
129 | busy, | ||
130 | } = this.state; | ||
131 | |||
132 | let showLoader = false; | ||
133 | if (loaded) { | ||
134 | showLoader = !loaded; | ||
135 | console.warn('Franz Button prop `loaded` will be deprecated in the future. Please use `busy` instead'); | ||
136 | } | ||
137 | if (busy) { | ||
138 | showLoader = busy; | ||
139 | } | ||
140 | |||
141 | return ( | ||
142 | <button | ||
143 | id={id} | ||
144 | type={type} | ||
145 | onClick={onClick} | ||
146 | className={classnames({ | ||
147 | [`${classes.button}`]: true, | ||
148 | [`${classes[buttonType as ButtonType]}`]: true, | ||
149 | [`${classes.disabled}`]: disabled, | ||
150 | })} | ||
151 | disabled={disabled} | ||
152 | > | ||
153 | <div className={classes.loaderContainer}> | ||
154 | {showLoader && ( | ||
155 | <Loader | ||
156 | loaded={false} | ||
157 | width={4} | ||
158 | scale={0.45} | ||
159 | color={theme.buttonLoaderColor[buttonType!]} | ||
160 | parentClassName={classes.loader} | ||
161 | /> | ||
162 | )} | ||
163 | </div> | ||
164 | <div className={classes.label}> | ||
165 | {label} | ||
166 | </div> | ||
167 | </button> | ||
168 | ); | ||
169 | } | ||
170 | } | ||
171 | |||
172 | export const Button = injectStyle(styles)(ButtonComponent); | ||
diff --git a/packages/forms/src/error/styles.ts b/packages/forms/src/error/styles.ts index 36a2b24e7..5104838a5 100644 --- a/packages/forms/src/error/styles.ts +++ b/packages/forms/src/error/styles.ts | |||
@@ -4,5 +4,6 @@ export default (theme: Theme) => ({ | |||
4 | message: { | 4 | message: { |
5 | color: theme.brandDanger, | 5 | color: theme.brandDanger, |
6 | margin: '5px 0 0', | 6 | margin: '5px 0 0', |
7 | fontSize: theme.uiFontSize, | ||
7 | }, | 8 | }, |
8 | }); | 9 | }); |
diff --git a/packages/forms/src/index.ts b/packages/forms/src/index.ts index a506de111..fbeb7e3d3 100644 --- a/packages/forms/src/index.ts +++ b/packages/forms/src/index.ts | |||
@@ -1,2 +1,3 @@ | |||
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'; | ||
diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx index d82ee5fe3..8f17ba2f9 100644 --- a/packages/forms/src/input/index.tsx +++ b/packages/forms/src/input/index.tsx | |||
@@ -34,6 +34,7 @@ class InputComponent extends Component<IProps, IState> { | |||
34 | public static defaultProps = { | 34 | public static defaultProps = { |
35 | focus: false, | 35 | focus: false, |
36 | onChange: () => {}, | 36 | onChange: () => {}, |
37 | onBlur: () => {}, | ||
37 | scorePassword: false, | 38 | scorePassword: false, |
38 | showLabel: true, | 39 | showLabel: true, |
39 | showPasswordToggle: false, | 40 | showPasswordToggle: false, |
@@ -74,6 +75,7 @@ class InputComponent extends Component<IProps, IState> { | |||
74 | render() { | 75 | render() { |
75 | const { | 76 | const { |
76 | classes, | 77 | classes, |
78 | className, | ||
77 | disabled, | 79 | disabled, |
78 | error, | 80 | error, |
79 | id, | 81 | id, |
@@ -84,6 +86,11 @@ class InputComponent extends Component<IProps, IState> { | |||
84 | showLabel, | 86 | showLabel, |
85 | showPasswordToggle, | 87 | showPasswordToggle, |
86 | type, | 88 | type, |
89 | value, | ||
90 | name, | ||
91 | placeholder, | ||
92 | spellCheck, | ||
93 | onBlur, | ||
87 | } = this.props; | 94 | } = this.props; |
88 | 95 | ||
89 | const { | 96 | const { |
@@ -91,18 +98,7 @@ class InputComponent extends Component<IProps, IState> { | |||
91 | passwordScore, | 98 | passwordScore, |
92 | } = this.state; | 99 | } = this.state; |
93 | 100 | ||
94 | const inputProps = pick(this.props, htmlElementAttributes['input']); | 101 | const inputType = type === 'password' && showPassword ? 'text' : type; |
95 | |||
96 | if (type === 'password' && showPassword) { | ||
97 | inputProps.type = 'text'; | ||
98 | } | ||
99 | |||
100 | inputProps.onChange = this.onChange.bind(this); | ||
101 | |||
102 | const cssClasses = classnames({ | ||
103 | [`${inputProps.className}`]: inputProps.className, | ||
104 | [`${classes.input}`]: true, | ||
105 | }); | ||
106 | 102 | ||
107 | return ( | 103 | return ( |
108 | <Wrapper> | 104 | <Wrapper> |
@@ -110,10 +106,11 @@ class InputComponent extends Component<IProps, IState> { | |||
110 | title={label} | 106 | title={label} |
111 | showLabel={showLabel} | 107 | showLabel={showLabel} |
112 | htmlFor={id} | 108 | htmlFor={id} |
109 | className={className} | ||
113 | > | 110 | > |
114 | <div | 111 | <div |
115 | className={classnames({ | 112 | className={classnames({ |
116 | [`${classes.hasPasswordScore}`]: showPasswordToggle, | 113 | [`${classes.hasPasswordScore}`]: scorePassword, |
117 | [`${classes.wrapper}`]: true, | 114 | [`${classes.wrapper}`]: true, |
118 | [`${classes.disabled}`]: disabled, | 115 | [`${classes.disabled}`]: disabled, |
119 | [`${classes.hasError}`]: error, | 116 | [`${classes.hasError}`]: error, |
@@ -124,9 +121,16 @@ class InputComponent extends Component<IProps, IState> { | |||
124 | </span> | 121 | </span> |
125 | )} | 122 | )} |
126 | <input | 123 | <input |
127 | {...inputProps} | 124 | id={id} |
128 | className={cssClasses} | 125 | type={inputType} |
126 | name={name} | ||
127 | value={value} | ||
128 | placeholder={placeholder} | ||
129 | spellCheck={spellCheck} | ||
130 | className={classes.input} | ||
129 | ref={this.inputRef} | 131 | ref={this.inputRef} |
132 | onChange={this.onChange.bind(this)} | ||
133 | onBlur={onBlur} | ||
130 | /> | 134 | /> |
131 | {suffix && ( | 135 | {suffix && ( |
132 | <span className={classes.suffix}> | 136 | <span className={classes.suffix}> |
diff --git a/packages/forms/src/input/styles.ts b/packages/forms/src/input/styles.ts index 2b34e92c3..a64d2c340 100644 --- a/packages/forms/src/input/styles.ts +++ b/packages/forms/src/input/styles.ts | |||
@@ -6,12 +6,10 @@ const prefixStyles = (theme: Theme) => ({ | |||
6 | color: theme.inputPrefixColor, | 6 | color: theme.inputPrefixColor, |
7 | lineHeight: theme.inputHeight, | 7 | lineHeight: theme.inputHeight, |
8 | padding: '0 10px', | 8 | padding: '0 10px', |
9 | fontSize: theme.uiFontSize, | ||
9 | }); | 10 | }); |
10 | 11 | ||
11 | export default (theme: Theme) => ({ | 12 | export default (theme: Theme) => ({ |
12 | container: { | ||
13 | // display: 'flex', | ||
14 | }, | ||
15 | disabled: { | 13 | disabled: { |
16 | opacity: theme.inputDisabledOpacity, | 14 | opacity: theme.inputDisabledOpacity, |
17 | }, | 15 | }, |
@@ -33,7 +31,7 @@ export default (theme: Theme) => ({ | |||
33 | input: { | 31 | input: { |
34 | background: 'none', | 32 | background: 'none', |
35 | border: 0, | 33 | border: 0, |
36 | fontSize: theme.inputFontSize, | 34 | fontSize: theme.uiFontSize, |
37 | outline: 'none', | 35 | outline: 'none', |
38 | padding: 8, | 36 | padding: 8, |
39 | width: '100%', | 37 | width: '100%', |
diff --git a/packages/forms/src/label/styles.ts b/packages/forms/src/label/styles.ts index 64011a93d..f3998de04 100644 --- a/packages/forms/src/label/styles.ts +++ b/packages/forms/src/label/styles.ts | |||
@@ -6,6 +6,7 @@ export default (theme: Theme) => ({ | |||
6 | }, | 6 | }, |
7 | label: { | 7 | label: { |
8 | color: theme.labelColor, | 8 | color: theme.labelColor, |
9 | fontSize: theme.uiFontSize, | ||
9 | }, | 10 | }, |
10 | hasError: { | 11 | hasError: { |
11 | color: theme.brandDanger, | 12 | color: theme.brandDanger, |
diff --git a/packages/forms/src/toggle/index.tsx b/packages/forms/src/toggle/index.tsx index 759694dc8..a1cd7f1a4 100644 --- a/packages/forms/src/toggle/index.tsx +++ b/packages/forms/src/toggle/index.tsx | |||
@@ -11,9 +11,7 @@ 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 | // field: any; | ||
16 | } | ||
17 | 15 | ||
18 | const styles = (theme: Theme) => ({ | 16 | const styles = (theme: Theme) => ({ |
19 | toggle: { | 17 | toggle: { |
@@ -42,7 +40,7 @@ const styles = (theme: Theme) => ({ | |||
42 | visibility: 'hidden' as any, | 40 | visibility: 'hidden' as any, |
43 | }, | 41 | }, |
44 | disabled: { | 42 | disabled: { |
45 | opacity: 0.5, | 43 | opacity: theme.inputDisabledOpacity, |
46 | }, | 44 | }, |
47 | toggleLabel: { | 45 | toggleLabel: { |
48 | display: 'flex', | 46 | display: 'flex', |
@@ -77,8 +75,6 @@ class ToggleComponent extends Component<IProps> { | |||
77 | onChange, | 75 | onChange, |
78 | } = this.props; | 76 | } = this.props; |
79 | 77 | ||
80 | console.log('props', this.props); | ||
81 | |||
82 | return ( | 78 | return ( |
83 | <Wrapper> | 79 | <Wrapper> |
84 | <Label | 80 | <Label |
diff --git a/packages/forms/src/typings/generic.ts b/packages/forms/src/typings/generic.ts index bd3ea364b..b7f2fc452 100644 --- a/packages/forms/src/typings/generic.ts +++ b/packages/forms/src/typings/generic.ts | |||
@@ -1,3 +1,4 @@ | |||
1 | import { Theme } from '@meetfranz/theme/lib'; | ||
1 | import { Classes } from 'jss'; | 2 | import { Classes } from 'jss'; |
2 | 3 | ||
3 | export interface IFormField { | 4 | export interface IFormField { |
@@ -8,6 +9,7 @@ export interface IFormField { | |||
8 | 9 | ||
9 | export interface IWithStyle { | 10 | export interface IWithStyle { |
10 | classes: Classes; | 11 | classes: Classes; |
12 | theme: Theme; | ||
11 | } | 13 | } |
12 | 14 | ||
13 | export type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N; | 15 | export type Merge<M, N> = Omit<M, Extract<keyof M, keyof N>> & N; |
diff --git a/packages/forms/src/wrapper/index.tsx b/packages/forms/src/wrapper/index.tsx index b3e92da66..633cc4c99 100644 --- a/packages/forms/src/wrapper/index.tsx +++ b/packages/forms/src/wrapper/index.tsx | |||
@@ -18,7 +18,7 @@ class Wrapper extends Component<IProps> { | |||
18 | } = this.props; | 18 | } = this.props; |
19 | 19 | ||
20 | return ( | 20 | return ( |
21 | <div className={classes.container}> | 21 | <div className={classes.container}> |
22 | {children} | 22 | {children} |
23 | </div> | 23 | </div> |
24 | ); | 24 | ); |