diff options
-rw-r--r-- | package-lock.json | 2 | ||||
-rw-r--r-- | packages/forms/src/button/index.tsx | 73 | ||||
-rw-r--r-- | uidev/src/stories/button.stories.tsx | 25 |
3 files changed, 76 insertions, 24 deletions
diff --git a/package-lock.json b/package-lock.json index 6b10c8689..a432dda40 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": "file:packages/theme", | 2727 | "@meetfranz/theme": "^1.0.4", |
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 | }, |
diff --git a/packages/forms/src/button/index.tsx b/packages/forms/src/button/index.tsx index 784ead04c..92d69ae0e 100644 --- a/packages/forms/src/button/index.tsx +++ b/packages/forms/src/button/index.tsx | |||
@@ -8,16 +8,23 @@ 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 } from '../typings/generic'; | 11 | import { IFormField, IWithStyle, Omit } 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 | ||
15 | interface IProps extends React.InputHTMLAttributes<HTMLButtonElement>, IFormField, IWithStyle { | 15 | interface IProps extends IFormField, IWithStyle { |
16 | className?: string; | ||
17 | disabled?: boolean; | ||
18 | id?: string; | ||
19 | type?: string; | ||
20 | onClick: (event: React.MouseEvent<HTMLButtonElement> | React.MouseEvent<HTMLAnchorElement>) => void; | ||
16 | buttonType?: ButtonType; | 21 | buttonType?: ButtonType; |
17 | stretch?: boolean; | 22 | stretch?: boolean; |
18 | loaded?: boolean; | 23 | loaded?: boolean; |
19 | busy?: boolean; | 24 | busy?: boolean; |
20 | icon?: keyof typeof mdiIcons; | 25 | icon?: keyof typeof mdiIcons; |
26 | href?: string; | ||
27 | target?: string; | ||
21 | } | 28 | } |
22 | 29 | ||
23 | interface IState { | 30 | interface IState { |
@@ -28,7 +35,7 @@ const styles = (theme: Theme) => ({ | |||
28 | button: { | 35 | button: { |
29 | borderRadius: theme.borderRadiusSmall, | 36 | borderRadius: theme.borderRadiusSmall, |
30 | border: 'none', | 37 | border: 'none', |
31 | display: 'flex', | 38 | display: 'inline-flex', |
32 | position: 'relative' as CSS.PositionProperty, | 39 | position: 'relative' as CSS.PositionProperty, |
33 | transition: 'background .5s', | 40 | transition: 'background .5s', |
34 | textAlign: 'center' as CSS.TextAlignProperty, | 41 | textAlign: 'center' as CSS.TextAlignProperty, |
@@ -37,6 +44,7 @@ const styles = (theme: Theme) => ({ | |||
37 | padding: 0, | 44 | padding: 0, |
38 | width: (props: IProps) => (props.stretch ? '100%' : 'auto') as CSS.WidthProperty<string>, | 45 | width: (props: IProps) => (props.stretch ? '100%' : 'auto') as CSS.WidthProperty<string>, |
39 | fontSize: theme.uiFontSize, | 46 | fontSize: theme.uiFontSize, |
47 | textDecoration: 'none', | ||
40 | }, | 48 | }, |
41 | label: { | 49 | label: { |
42 | margin: '10px 20px', | 50 | margin: '10px 20px', |
@@ -127,6 +135,7 @@ class ButtonComponent extends Component<IProps> { | |||
127 | buttonType: 'primary' as ButtonType, | 135 | buttonType: 'primary' as ButtonType, |
128 | stretch: false, | 136 | stretch: false, |
129 | busy: false, | 137 | busy: false, |
138 | // target: '_self' | ||
130 | }; | 139 | }; |
131 | 140 | ||
132 | state = { | 141 | state = { |
@@ -163,6 +172,8 @@ class ButtonComponent extends Component<IProps> { | |||
163 | loaded, | 172 | loaded, |
164 | icon: iconName, | 173 | icon: iconName, |
165 | busy: busyProp, | 174 | busy: busyProp, |
175 | href, | ||
176 | target, | ||
166 | } = this.props; | 177 | } = this.props; |
167 | 178 | ||
168 | const { | 179 | const { |
@@ -185,19 +196,8 @@ class ButtonComponent extends Component<IProps> { | |||
185 | showLoader = busy; | 196 | showLoader = busy; |
186 | } | 197 | } |
187 | 198 | ||
188 | return ( | 199 | const content = ( |
189 | <button | 200 | <> |
190 | id={id} | ||
191 | type={type} | ||
192 | onClick={onClick} | ||
193 | className={classnames({ | ||
194 | [`${classes.button}`]: true, | ||
195 | [`${classes[buttonType as ButtonType]}`]: true, | ||
196 | [`${classes.disabled}`]: disabled, | ||
197 | [`${className}`]: className, | ||
198 | })} | ||
199 | disabled={disabled} | ||
200 | > | ||
201 | <div className={classes.loaderContainer}> | 201 | <div className={classes.loaderContainer}> |
202 | {showLoader && ( | 202 | {showLoader && ( |
203 | <Loader | 203 | <Loader |
@@ -219,8 +219,47 @@ class ButtonComponent extends Component<IProps> { | |||
219 | )} | 219 | )} |
220 | {label} | 220 | {label} |
221 | </div> | 221 | </div> |
222 | </button> | 222 | </> |
223 | ); | 223 | ); |
224 | |||
225 | let wrapperComponent = null; | ||
226 | |||
227 | if (!href) { | ||
228 | wrapperComponent = ( | ||
229 | <button | ||
230 | id={id} | ||
231 | type={type} | ||
232 | onClick={onClick} | ||
233 | className={classnames({ | ||
234 | [`${classes.button}`]: true, | ||
235 | [`${classes[buttonType as ButtonType]}`]: true, | ||
236 | [`${classes.disabled}`]: disabled, | ||
237 | [`${className}`]: className, | ||
238 | })} | ||
239 | disabled={disabled} | ||
240 | > | ||
241 | {content} | ||
242 | </button> | ||
243 | ); | ||
244 | } else { | ||
245 | wrapperComponent = ( | ||
246 | <a | ||
247 | href={href} | ||
248 | target={target} | ||
249 | onClick={onClick} | ||
250 | className={classnames({ | ||
251 | [`${classes.button}`]: true, | ||
252 | [`${classes[buttonType as ButtonType]}`]: true, | ||
253 | [`${className}`]: className, | ||
254 | })} | ||
255 | rel={target === '_blank' ? 'noopener' : ''} | ||
256 | > | ||
257 | {content} | ||
258 | </a> | ||
259 | ); | ||
260 | } | ||
261 | |||
262 | return wrapperComponent; | ||
224 | } | 263 | } |
225 | } | 264 | } |
226 | 265 | ||
diff --git a/uidev/src/stories/button.stories.tsx b/uidev/src/stories/button.stories.tsx index b5906211a..d81808530 100644 --- a/uidev/src/stories/button.stories.tsx +++ b/uidev/src/stories/button.stories.tsx | |||
@@ -10,7 +10,6 @@ const defaultProps = { | |||
10 | id: 'test1', | 10 | id: 'test1', |
11 | name: 'test1', | 11 | name: 'test1', |
12 | type: 'button', | 12 | type: 'button', |
13 | onClick: (e: React.MouseEvent<HTMLButtonElement>) => console.log('click event', e), | ||
14 | disabled: false, | 13 | disabled: false, |
15 | }; | 14 | }; |
16 | 15 | ||
@@ -22,13 +21,13 @@ const WithStoreButton = observer(({ store }: { store: any }) => ( | |||
22 | <> | 21 | <> |
23 | <Button | 22 | <Button |
24 | {...Object.assign({}, defaultProps, store)} | 23 | {...Object.assign({}, defaultProps, store)} |
25 | onClick={() => { | 24 | onClick={!store.onClick ? () => { |
26 | store.busy = !store.busy; | 25 | store.busy = !store.busy; |
27 | 26 | ||
28 | window.setTimeout(() => { | 27 | window.setTimeout(() => { |
29 | store.busy = !store.busy; | 28 | store.busy = !store.busy; |
30 | }, 1000); | 29 | }, 1000); |
31 | }} | 30 | } : store.onClick} |
32 | /> | 31 | /> |
33 | </> | 32 | </> |
34 | )); | 33 | )); |
@@ -77,8 +76,22 @@ storiesOf('Button') | |||
77 | busy: true, | 76 | busy: true, |
78 | })} /> | 77 | })} /> |
79 | )) | 78 | )) |
80 | .add('With icon', () => ( | 79 | .add('As link', () => ( |
81 | <WithStoreButton store={createStore({ | 80 | <WithStoreButton store={createStore({ |
82 | icon: 'mdiAccountCircle', | 81 | href: 'https://meetfranz.com', |
83 | })} /> | 82 | })} /> |
84 | )); | 83 | )) |
84 | .add('As link (target=_blank)', () => ( | ||
85 | <WithStoreButton store={createStore({ | ||
86 | href: 'https://meetfranz.com', | ||
87 | target: '_blank', | ||
88 | })} /> | ||
89 | )) | ||
90 | .add('As link (with onClick)', () => ( | ||
91 | <WithStoreButton store={createStore({ | ||
92 | href: 'https://meetfranz.com', | ||
93 | onClick: (e: React.MouseEvent<HTMLAnchorElement>) => { | ||
94 | e.preventDefault(); | ||
95 | alert('Click event'); | ||
96 | }, | ||
97 | })} />)); | ||