diff options
Diffstat (limited to 'src/components/ui')
-rw-r--r-- | src/components/ui/Link.js | 86 | ||||
-rw-r--r-- | src/components/ui/Link.tsx | 73 | ||||
-rw-r--r-- | src/components/ui/button/index.tsx | 76 | ||||
-rw-r--r-- | src/components/ui/input/index.tsx | 2 |
4 files changed, 105 insertions, 132 deletions
diff --git a/src/components/ui/Link.js b/src/components/ui/Link.js deleted file mode 100644 index 714fc5a68..000000000 --- a/src/components/ui/Link.js +++ /dev/null | |||
@@ -1,86 +0,0 @@ | |||
1 | import { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { inject, observer } from 'mobx-react'; | ||
4 | import { RouterStore } from '@superwf/mobx-react-router'; | ||
5 | import classnames from 'classnames'; | ||
6 | |||
7 | import { oneOrManyChildElements } from '../../prop-types'; | ||
8 | import matchRoute from '../../helpers/routing-helpers'; | ||
9 | import { openExternalUrl } from '../../helpers/url-helpers'; | ||
10 | |||
11 | // Should this file be converted into the coding style similar to './toggle/index.tsx'? | ||
12 | // TODO: create container component for this component | ||
13 | class Link extends Component { | ||
14 | onClick(e) { | ||
15 | if (this.props.disabled) { | ||
16 | e.preventDefault(); | ||
17 | } else if (this.props.target === '_blank') { | ||
18 | e.preventDefault(); | ||
19 | openExternalUrl(this.props.to, true); | ||
20 | } | ||
21 | // Note: if neither of the above, then let the other onClick handlers process it | ||
22 | } | ||
23 | |||
24 | render() { | ||
25 | const { | ||
26 | children, | ||
27 | stores, | ||
28 | to, | ||
29 | className, | ||
30 | activeClassName, | ||
31 | strictFilter, | ||
32 | style, | ||
33 | } = this.props; | ||
34 | const { router } = stores; | ||
35 | |||
36 | let filter = `${to}(*action)`; | ||
37 | if (strictFilter) { | ||
38 | filter = `${to}`; | ||
39 | } | ||
40 | |||
41 | const match = matchRoute(filter, router.location.pathname); | ||
42 | |||
43 | const linkClasses = classnames({ | ||
44 | [`${className}`]: true, | ||
45 | [`${activeClassName}`]: match, | ||
46 | 'is-disabled': this.props.disabled, | ||
47 | }); | ||
48 | |||
49 | return ( | ||
50 | <a | ||
51 | href={router.history.createHref(to)} | ||
52 | className={linkClasses} | ||
53 | style={style} | ||
54 | onClick={e => this.onClick(e)} | ||
55 | > | ||
56 | {children} | ||
57 | </a> | ||
58 | ); | ||
59 | } | ||
60 | } | ||
61 | |||
62 | Link.propTypes = { | ||
63 | stores: PropTypes.shape({ | ||
64 | router: PropTypes.instanceOf(RouterStore).isRequired, | ||
65 | }).isRequired, | ||
66 | children: PropTypes.oneOfType([oneOrManyChildElements, PropTypes.string]) | ||
67 | .isRequired, | ||
68 | to: PropTypes.string.isRequired, | ||
69 | className: PropTypes.string, | ||
70 | activeClassName: PropTypes.string, | ||
71 | strictFilter: PropTypes.bool, | ||
72 | target: PropTypes.string, | ||
73 | style: PropTypes.object, | ||
74 | disabled: PropTypes.bool, | ||
75 | }; | ||
76 | |||
77 | Link.defaultProps = { | ||
78 | className: '', | ||
79 | activeClassName: '', | ||
80 | strictFilter: false, | ||
81 | disabled: false, | ||
82 | target: '', | ||
83 | style: {}, | ||
84 | }; | ||
85 | |||
86 | export default inject('stores')(observer(Link)); | ||
diff --git a/src/components/ui/Link.tsx b/src/components/ui/Link.tsx new file mode 100644 index 000000000..b5890ebd1 --- /dev/null +++ b/src/components/ui/Link.tsx | |||
@@ -0,0 +1,73 @@ | |||
1 | import { Component, CSSProperties, ReactNode, MouseEvent } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | import classnames from 'classnames'; | ||
4 | import matchRoute from '../../helpers/routing-helpers'; | ||
5 | import { openExternalUrl } from '../../helpers/url-helpers'; | ||
6 | import { StoresProps } from '../../@types/ferdium-components.types'; | ||
7 | |||
8 | interface IProps extends Partial<StoresProps> { | ||
9 | children: ReactNode; | ||
10 | to: string; | ||
11 | className?: string; | ||
12 | activeClassName?: string; | ||
13 | strictFilter?: boolean; | ||
14 | target?: string; | ||
15 | style?: CSSProperties; | ||
16 | disabled?: boolean; | ||
17 | } | ||
18 | |||
19 | // TODO: create container component for this component | ||
20 | @inject('stores') | ||
21 | @observer | ||
22 | class Link extends Component<IProps> { | ||
23 | constructor(props: IProps) { | ||
24 | super(props); | ||
25 | } | ||
26 | |||
27 | onClick(e: MouseEvent<HTMLAnchorElement>): void { | ||
28 | const { disabled = false, target = '', to } = this.props; | ||
29 | if (disabled) { | ||
30 | e.preventDefault(); | ||
31 | } else if (target === '_blank') { | ||
32 | e.preventDefault(); | ||
33 | openExternalUrl(to, true); | ||
34 | } | ||
35 | // Note: if neither of the above, then let the other onClick handlers process it | ||
36 | } | ||
37 | |||
38 | render() { | ||
39 | const { | ||
40 | children, | ||
41 | stores, | ||
42 | to, | ||
43 | className = '', | ||
44 | activeClassName = '', | ||
45 | strictFilter = false, | ||
46 | disabled = false, | ||
47 | style = {}, | ||
48 | } = this.props; | ||
49 | const { router } = stores!; | ||
50 | |||
51 | const filter = strictFilter ? `${to}` : `${to}(*action)`; | ||
52 | const match = matchRoute(filter, router.location.pathname); | ||
53 | |||
54 | const linkClasses = classnames({ | ||
55 | [`${className}`]: true, | ||
56 | [`${activeClassName}`]: match, | ||
57 | 'is-disabled': disabled, | ||
58 | }); | ||
59 | |||
60 | return ( | ||
61 | <a | ||
62 | href={router.history.createHref(to)} | ||
63 | className={linkClasses} | ||
64 | style={style} | ||
65 | onClick={e => this.onClick(e)} | ||
66 | > | ||
67 | {children} | ||
68 | </a> | ||
69 | ); | ||
70 | } | ||
71 | } | ||
72 | |||
73 | export default Link; | ||
diff --git a/src/components/ui/button/index.tsx b/src/components/ui/button/index.tsx index a8bbfe730..c1e647bc0 100644 --- a/src/components/ui/button/index.tsx +++ b/src/components/ui/button/index.tsx | |||
@@ -1,10 +1,10 @@ | |||
1 | import Icon from '@mdi/react'; | 1 | import Icon from '@mdi/react'; |
2 | import classnames from 'classnames'; | 2 | import classnames from 'classnames'; |
3 | import { Property } from 'csstype'; | 3 | import { Property } from 'csstype'; |
4 | import { noop } from 'lodash'; | ||
4 | import { Component, MouseEvent } from 'react'; | 5 | import { Component, MouseEvent } from 'react'; |
5 | import withStyles, { WithStylesProps } from 'react-jss'; | 6 | import withStyles, { WithStylesProps } from 'react-jss'; |
6 | import Loader from 'react-loader'; | 7 | import Loader from 'react-loader'; |
7 | |||
8 | import { Theme } from '../../../themes'; | 8 | import { Theme } from '../../../themes'; |
9 | import { IFormField } from '../typings/generic'; | 9 | import { IFormField } from '../typings/generic'; |
10 | 10 | ||
@@ -16,24 +16,6 @@ type ButtonType = | |||
16 | | 'warning' | 16 | | 'warning' |
17 | | 'inverted'; | 17 | | 'inverted'; |
18 | 18 | ||
19 | interface IProps extends IFormField, WithStylesProps<typeof styles> { | ||
20 | className?: string; | ||
21 | label?: string; | ||
22 | disabled?: boolean; | ||
23 | id?: string; | ||
24 | type?: 'button' | 'reset' | 'submit' | undefined; | ||
25 | onClick: ( | ||
26 | event: MouseEvent<HTMLButtonElement> | MouseEvent<HTMLAnchorElement>, | ||
27 | ) => void; | ||
28 | buttonType?: ButtonType; | ||
29 | loaded?: boolean; | ||
30 | busy?: boolean; | ||
31 | icon?: string; | ||
32 | href?: string; | ||
33 | target?: string; | ||
34 | htmlForm?: string; | ||
35 | } | ||
36 | |||
37 | let buttonTransition: string = 'none'; | 19 | let buttonTransition: string = 'none'; |
38 | let loaderContainerTransition: string = 'none'; | 20 | let loaderContainerTransition: string = 'none'; |
39 | 21 | ||
@@ -148,38 +130,38 @@ const styles = (theme: Theme) => ({ | |||
148 | }, | 130 | }, |
149 | }); | 131 | }); |
150 | 132 | ||
151 | class ButtonComponent extends Component<IProps> { | 133 | interface IProps extends IFormField, WithStylesProps<typeof styles> { |
152 | customDefaultProps: { | 134 | className?: string; |
153 | disabled: boolean; | 135 | label?: string; |
154 | type: 'button' | 'reset' | 'submit' | undefined; | 136 | disabled?: boolean; |
155 | onClick: ( | 137 | id?: string; |
156 | event: MouseEvent<HTMLButtonElement> | MouseEvent<HTMLAnchorElement>, | 138 | type?: 'button' | 'reset' | 'submit' | undefined; |
157 | ) => void; | 139 | onClick: (event: MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void; |
158 | buttonType: ButtonType; | 140 | buttonType?: ButtonType; |
159 | busy: boolean; | 141 | loaded?: boolean; |
160 | } = { | 142 | busy?: boolean; |
161 | type: 'button', | 143 | icon?: string; |
162 | disabled: false, | 144 | href?: string; |
163 | onClick: () => null, | 145 | target?: string; |
164 | buttonType: 'primary' as ButtonType, | 146 | htmlForm?: string; |
165 | busy: false, | 147 | } |
166 | }; | ||
167 | 148 | ||
168 | state = { | 149 | interface IState { |
169 | busy: false, | 150 | busy: boolean; |
170 | }; | 151 | } |
171 | 152 | ||
153 | class ButtonComponent extends Component<IProps, IState> { | ||
172 | constructor(props: IProps) { | 154 | constructor(props: IProps) { |
173 | super(props); | 155 | super(props); |
174 | 156 | ||
175 | this.state = { | 157 | this.state = { |
176 | busy: props.busy || false, | 158 | busy: this.props.busy || false, |
177 | }; | 159 | }; |
178 | } | 160 | } |
179 | 161 | ||
180 | static getDerivedStateFromProps(nextProps: IProps) { | 162 | static getDerivedStateFromProps(nextProps: IProps): IState { |
181 | return { | 163 | return { |
182 | busy: nextProps.busy, | 164 | busy: nextProps.busy || false, |
183 | }; | 165 | }; |
184 | } | 166 | } |
185 | 167 | ||
@@ -188,27 +170,29 @@ class ButtonComponent extends Component<IProps> { | |||
188 | classes, | 170 | classes, |
189 | className, | 171 | className, |
190 | // theme, | 172 | // theme, |
191 | disabled, | ||
192 | id, | 173 | id, |
193 | label, | 174 | label, |
194 | type, | ||
195 | onClick, | ||
196 | buttonType, | ||
197 | loaded, | 175 | loaded, |
198 | icon, | 176 | icon, |
199 | href, | 177 | href, |
200 | target, | 178 | target, |
201 | htmlForm, | 179 | htmlForm, |
202 | } = { ...this.customDefaultProps, ...this.props }; | 180 | type = 'button', |
181 | disabled = false, | ||
182 | onClick = noop, | ||
183 | buttonType = 'primary' as ButtonType, | ||
184 | } = this.props; | ||
203 | 185 | ||
204 | const { busy } = this.state; | 186 | const { busy } = this.state; |
205 | let showLoader = false; | 187 | let showLoader = false; |
188 | |||
206 | if (loaded) { | 189 | if (loaded) { |
207 | showLoader = !loaded; | 190 | showLoader = !loaded; |
208 | console.warn( | 191 | console.warn( |
209 | 'Ferdium Button prop `loaded` will be deprecated in the future. Please use `busy` instead', | 192 | 'Ferdium Button prop `loaded` will be deprecated in the future. Please use `busy` instead', |
210 | ); | 193 | ); |
211 | } | 194 | } |
195 | |||
212 | if (busy) { | 196 | if (busy) { |
213 | showLoader = busy; | 197 | showLoader = busy; |
214 | } | 198 | } |
diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx index b19bb4bc9..3bafc93e7 100644 --- a/src/components/ui/input/index.tsx +++ b/src/components/ui/input/index.tsx | |||
@@ -106,6 +106,7 @@ class InputComponent extends Component<IProps, IState> { | |||
106 | showPasswordToggle = false, | 106 | showPasswordToggle = false, |
107 | type = 'text', | 107 | type = 'text', |
108 | disabled = false, | 108 | disabled = false, |
109 | readOnly, | ||
109 | } = this.props; | 110 | } = this.props; |
110 | 111 | ||
111 | const { showPassword, passwordScore } = this.state; | 112 | const { showPassword, passwordScore } = this.state; |
@@ -152,6 +153,7 @@ class InputComponent extends Component<IProps, IState> { | |||
152 | min={min} | 153 | min={min} |
153 | max={max} | 154 | max={max} |
154 | step={step} | 155 | step={step} |
156 | readOnly={readOnly} | ||
155 | /> | 157 | /> |
156 | {suffix && <span className={classes.suffix}>{suffix}</span>} | 158 | {suffix && <span className={classes.suffix}>{suffix}</span>} |
157 | {showPasswordToggle && ( | 159 | {showPasswordToggle && ( |