aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui
diff options
context:
space:
mode:
authorLibravatar muhamedsalih-tw <104364298+muhamedsalih-tw@users.noreply.github.com>2022-11-02 06:31:36 +0530
committerLibravatar GitHub <noreply@github.com>2022-11-02 01:01:36 +0000
commit302d595f7c289387e53a0ef7df4d574ed4e25d70 (patch)
tree2385e59eaca9c78921d9b0b3681cfba1b3eef168 /src/components/ui
parentRe-enable editing of the address bar to manually access a different url withi... (diff)
downloadferdium-app-302d595f7c289387e53a0ef7df4d574ed4e25d70.tar.gz
ferdium-app-302d595f7c289387e53a0ef7df4d574ed4e25d70.tar.zst
ferdium-app-302d595f7c289387e53a0ef7df4d574ed4e25d70.zip
Transform to TS and refactored components w.r.t deletion if duplicated Input component (#729)
Diffstat (limited to 'src/components/ui')
-rw-r--r--src/components/ui/ColorPickerInput.tsx18
-rw-r--r--src/components/ui/Input.tsx170
-rw-r--r--src/components/ui/input/index.tsx187
-rw-r--r--src/components/ui/input/styles.ts1
4 files changed, 119 insertions, 257 deletions
diff --git a/src/components/ui/ColorPickerInput.tsx b/src/components/ui/ColorPickerInput.tsx
index 7e3965331..da1fffb71 100644
--- a/src/components/ui/ColorPickerInput.tsx
+++ b/src/components/ui/ColorPickerInput.tsx
@@ -1,15 +1,25 @@
1import { ChangeEvent, Component, createRef, RefObject } from 'react'; 1import {
2 ChangeEvent,
3 ChangeEventHandler,
4 Component,
5 createRef,
6 RefObject,
7} from 'react';
2import { observer } from 'mobx-react'; 8import { observer } from 'mobx-react';
3import classnames from 'classnames'; 9import classnames from 'classnames';
4import { SliderPicker } from 'react-color'; 10import { SliderPicker } from 'react-color';
11import { noop } from 'lodash';
5import { Field } from '../../@types/mobx-form.types'; 12import { Field } from '../../@types/mobx-form.types';
6 13
7interface IProps { 14interface IProps {
8 field: Field; 15 field: Field;
9 className?: string; 16 className?: string;
10 focus?: boolean; 17 focus?: boolean;
18 onChange: ChangeEventHandler<HTMLInputElement>;
11} 19}
12 20
21// TODO - [TS DEBT] check if field can be spread instead of having it single field attribute in interface
22@observer
13class ColorPickerInput extends Component<IProps> { 23class ColorPickerInput extends Component<IProps> {
14 private inputElement: RefObject<HTMLInputElement> = 24 private inputElement: RefObject<HTMLInputElement> =
15 createRef<HTMLInputElement>(); 25 createRef<HTMLInputElement>();
@@ -22,7 +32,9 @@ class ColorPickerInput extends Component<IProps> {
22 } 32 }
23 33
24 onChange(e: ChangeEvent<HTMLInputElement>) { 34 onChange(e: ChangeEvent<HTMLInputElement>) {
25 const { field } = this.props; 35 const { field, onChange = noop } = this.props;
36
37 onChange(e);
26 if (field.onChange) { 38 if (field.onChange) {
27 field.onChange(e); 39 field.onChange(e);
28 } 40 }
@@ -87,4 +99,4 @@ class ColorPickerInput extends Component<IProps> {
87 } 99 }
88} 100}
89 101
90export default observer(ColorPickerInput); 102export default ColorPickerInput;
diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx
deleted file mode 100644
index c22dc5838..000000000
--- a/src/components/ui/Input.tsx
+++ /dev/null
@@ -1,170 +0,0 @@
1import {
2 ChangeEvent,
3 ChangeEventHandler,
4 Component,
5 createRef,
6 ReactElement,
7 RefObject,
8} from 'react';
9import { observer } from 'mobx-react';
10import classnames from 'classnames';
11import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
12import { mdiEye, mdiEyeOff } from '@mdi/js';
13import { noop } from 'lodash';
14import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers';
15import Icon from './icon';
16import { Field } from '../../@types/mobx-form.types';
17
18const messages = defineMessages({
19 passwordToggle: {
20 id: 'settings.app.form.passwordToggle',
21 defaultMessage: 'Password toggle',
22 },
23});
24
25interface IProps extends WrappedComponentProps {
26 field: Field;
27 className?: string;
28 focus?: boolean;
29 showPasswordToggle?: boolean;
30 showLabel?: boolean;
31 scorePassword?: boolean;
32 prefix?: string;
33 suffix?: string;
34 placeholder?: string;
35 onChange?: ChangeEventHandler<HTMLInputElement>;
36}
37
38interface IState {
39 showPassword: boolean;
40 passwordScore: number;
41}
42
43// Can this file be merged into the './input/index.tsx' file?
44@observer
45class Input extends Component<IProps, IState> {
46 private inputElement: RefObject<HTMLInputElement> =
47 createRef<HTMLInputElement>();
48
49 constructor(props: IProps) {
50 super(props);
51
52 this.state = {
53 showPassword: false,
54 passwordScore: 0,
55 };
56 }
57
58 componentDidMount(): void {
59 const { focus = false } = this.props;
60 if (focus) {
61 this.focus();
62 }
63 }
64
65 onChange(e: ChangeEvent<HTMLInputElement>): void {
66 const { field, scorePassword, onChange = noop } = this.props;
67
68 if (field.onChange) {
69 onChange(e);
70 field.onChange(e);
71 }
72
73 if (scorePassword) {
74 this.setState({
75 passwordScore: scorePasswordFunc(field.value as string),
76 });
77 }
78 }
79
80 focus() {
81 if (this.inputElement && this.inputElement.current) {
82 this.inputElement.current!.focus();
83 }
84 }
85
86 render(): ReactElement {
87 const {
88 field,
89 className = null,
90 showPasswordToggle = false,
91 showLabel = true,
92 scorePassword = false,
93 prefix = '',
94 suffix = '',
95 intl,
96 } = this.props;
97
98 const { passwordScore } = this.state;
99
100 let { type } = field;
101 if (type === 'password' && this.state.showPassword) {
102 type = 'text';
103 }
104
105 return (
106 <div
107 className={classnames({
108 'franz-form__field': true,
109 'has-error': field.error,
110 [`${className}`]: className,
111 })}
112 >
113 <div className="franz-form__input-wrapper">
114 {prefix && <span className="franz-form__input-prefix">{prefix}</span>}
115 <input
116 id={field.id}
117 type={type}
118 className="franz-form__input"
119 name={field.name}
120 value={field.value}
121 placeholder={field.placeholder}
122 onChange={e => this.onChange(e)}
123 onBlur={field.onBlur}
124 onFocus={field.onFocus}
125 ref={this.inputElement}
126 disabled={field.disabled}
127 />
128 {suffix && <span className="franz-form__input-suffix">{suffix}</span>}
129 {showPasswordToggle && (
130 <button
131 type="button"
132 className={classnames({
133 'franz-form__input-modifier': true,
134 })}
135 onClick={() =>
136 this.setState(prevState => ({
137 showPassword: !prevState.showPassword,
138 }))
139 }
140 tabIndex={-1}
141 aria-label={intl.formatMessage(messages.passwordToggle)}
142 >
143 <Icon icon={this.state.showPassword ? mdiEye : mdiEyeOff} />
144 </button>
145 )}
146 {scorePassword && (
147 <div className="franz-form__password-score">
148 {/* <progress value={this.state.passwordScore} max="100" /> */}
149 <meter
150 value={passwordScore < 5 ? 5 : passwordScore}
151 low={30}
152 high={75}
153 optimum={100}
154 max={100}
155 />
156 </div>
157 )}
158 </div>
159 {field.label && showLabel && (
160 <label className="franz-form__label" htmlFor={field.name}>
161 {field.label}
162 </label>
163 )}
164 {field.error && <div className="franz-form__error">{field.error}</div>}
165 </div>
166 );
167 }
168}
169
170export default injectIntl(Input);
diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx
index 2a36d7aa9..cb26c0ea4 100644
--- a/src/components/ui/input/index.tsx
+++ b/src/components/ui/input/index.tsx
@@ -1,5 +1,4 @@
1import { mdiEye, mdiEyeOff } from '@mdi/js'; 1import { mdiEye, mdiEyeOff } from '@mdi/js';
2import Icon from '@mdi/react';
3import classnames from 'classnames'; 2import classnames from 'classnames';
4import { 3import {
5 Component, 4 Component,
@@ -7,9 +6,13 @@ import {
7 InputHTMLAttributes, 6 InputHTMLAttributes,
8 ReactElement, 7 ReactElement,
9 RefObject, 8 RefObject,
9 KeyboardEvent,
10} from 'react'; 10} from 'react';
11import injectSheet, { WithStylesProps } from 'react-jss'; 11import withStyles, { WithStylesProps } from 'react-jss';
12import { noop } from 'lodash'; 12import { noop } from 'lodash';
13import { observer } from 'mobx-react';
14import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
15import Icon from '../icon';
13import { IFormField } from '../typings/generic'; 16import { IFormField } from '../typings/generic';
14import Error from '../error'; 17import Error from '../error';
15import Label from '../label'; 18import Label from '../label';
@@ -17,6 +20,12 @@ import Wrapper from '../wrapper';
17import { scorePasswordFunc } from './scorePassword'; 20import { scorePasswordFunc } from './scorePassword';
18import styles from './styles'; 21import styles from './styles';
19 22
23const messages = defineMessages({
24 passwordToggle: {
25 id: 'settings.app.form.passwordToggle',
26 defaultMessage: 'Password toggle',
27 },
28});
20interface IData { 29interface IData {
21 [index: string]: string; 30 [index: string]: string;
22} 31}
@@ -24,7 +33,8 @@ interface IData {
24interface IProps 33interface IProps
25 extends InputHTMLAttributes<HTMLInputElement>, 34 extends InputHTMLAttributes<HTMLInputElement>,
26 IFormField, 35 IFormField,
27 WithStylesProps<typeof styles> { 36 WithStylesProps<typeof styles>,
37 WrappedComponentProps {
28 focus?: boolean; 38 focus?: boolean;
29 prefix?: string; 39 prefix?: string;
30 suffix?: string; 40 suffix?: string;
@@ -40,8 +50,10 @@ interface IState {
40 passwordScore: number; 50 passwordScore: number;
41} 51}
42 52
43class InputComponent extends Component<IProps, IState> { 53@observer
44 private inputRef: RefObject<HTMLInputElement> = createRef<HTMLInputElement>(); 54class Input extends Component<IProps, IState> {
55 private inputElement: RefObject<HTMLInputElement> =
56 createRef<HTMLInputElement>();
45 57
46 constructor(props: IProps) { 58 constructor(props: IProps) {
47 super(props); 59 super(props);
@@ -53,36 +65,40 @@ class InputComponent extends Component<IProps, IState> {
53 } 65 }
54 66
55 componentDidMount(): void { 67 componentDidMount(): void {
56 const { focus, data = {} } = this.props; 68 const { focus = false, data = {} } = this.props;
57 69
58 if (this.inputRef && this.inputRef.current) { 70 if (this.inputElement && this.inputElement.current) {
59 if (focus) { 71 if (focus) {
60 this.inputRef.current.focus(); 72 this.inputElement.current.focus();
61 } 73 }
62 74
63 for (const key of Object.keys(data)) 75 for (const key of Object.keys(data)) {
64 this.inputRef.current!.dataset[key] = data[key]; 76 this.inputElement.current.dataset[key] = data[key];
77 }
65 } 78 }
66 } 79 }
67 80
68 onChange(e: React.ChangeEvent<HTMLInputElement>): void { 81 onChange(e: React.ChangeEvent<HTMLInputElement>): void {
69 const { scorePassword, onChange } = this.props; 82 const { scorePassword, onChange = noop } = this.props;
70 83
71 if (onChange) { 84 onChange(e);
72 onChange(e);
73 }
74 85
75 if (this.inputRef && this.inputRef.current && scorePassword) { 86 if (scorePassword) {
87 console.log(
88 '--->',
89 e.target.value,
90 scorePasswordFunc(e.target.value as string),
91 );
76 this.setState({ 92 this.setState({
77 passwordScore: scorePasswordFunc(this.inputRef.current.value), 93 passwordScore: scorePasswordFunc(e.target.value),
78 }); 94 });
79 } 95 }
80 } 96 }
81 97
82 onInputKeyPress(e: React.KeyboardEvent): void { 98 onInputKeyPress(e: KeyboardEvent<HTMLInputElement>): void {
83 if (e.key === 'Enter') { 99 if (e.key === 'Enter') {
84 const { onEnterKey } = this.props; 100 const { onEnterKey = noop } = this.props;
85 onEnterKey && onEnterKey(); 101 onEnterKey();
86 } 102 }
87 } 103 }
88 104
@@ -113,10 +129,9 @@ class InputComponent extends Component<IProps, IState> {
113 type = 'text', 129 type = 'text',
114 disabled = false, 130 disabled = false,
115 readOnly, 131 readOnly,
132 intl,
116 } = this.props; 133 } = this.props;
117
118 const { showPassword, passwordScore } = this.state; 134 const { showPassword, passwordScore } = this.state;
119
120 const inputType = type === 'password' && showPassword ? 'text' : type; 135 const inputType = type === 'password' && showPassword ? 'text' : type;
121 136
122 return ( 137 return (
@@ -125,79 +140,85 @@ class InputComponent extends Component<IProps, IState> {
125 identifier="franz-input" 140 identifier="franz-input"
126 noMargin={noMargin} 141 noMargin={noMargin}
127 > 142 >
128 <Label 143 {label && showLabel && (
129 title={label} 144 <Label
130 showLabel={showLabel} 145 title={label}
131 htmlFor={id} 146 showLabel={showLabel}
132 className={classes.label} 147 htmlFor={id}
133 isRequired={required} 148 className={classes.label}
149 isRequired={required}
150 />
151 )}
152 <div
153 className={classnames({
154 [`${inputClassName}`]: inputClassName,
155 // [`${classes.hasPasswordScore}`]: scorePassword,
156 [`${classes.wrapper}`]: true,
157 [`${classes.disabled}`]: disabled,
158 [`${classes.hasError}`]: error,
159 })}
134 > 160 >
161 {prefix && <span className={classes.prefix}>{prefix}</span>}
162 <input
163 id={id}
164 type={inputType}
165 name={name}
166 value={value as string}
167 placeholder={placeholder}
168 spellCheck={spellCheck}
169 className={classes.input}
170 ref={this.inputElement}
171 onChange={this.onChange.bind(this)}
172 onFocus={onFocus}
173 onBlur={onBlur}
174 disabled={disabled}
175 onKeyPress={this.onInputKeyPress.bind(this)}
176 min={min}
177 max={max}
178 step={step}
179 readOnly={readOnly}
180 />
181
182 {suffix && <span className={classes.suffix}>{suffix}</span>}
183
184 {showPasswordToggle && (
185 <button
186 type="button"
187 className={classnames({
188 'franz-form__input-modifier': true,
189 })}
190 onClick={() =>
191 this.setState(prevState => ({
192 showPassword: !prevState.showPassword,
193 }))
194 }
195 tabIndex={-1}
196 aria-label={intl.formatMessage(messages.passwordToggle)}
197 >
198 <Icon icon={this.state.showPassword ? mdiEye : mdiEyeOff} />
199 </button>
200 )}
201 </div>
202 {scorePassword && (
135 <div 203 <div
136 className={classnames({ 204 className={classnames({
137 [`${inputClassName}`]: inputClassName, 205 [`${classes.passwordScore}`]: true,
138 [`${classes.hasPasswordScore}`]: scorePassword,
139 [`${classes.wrapper}`]: true,
140 [`${classes.disabled}`]: disabled,
141 [`${classes.hasError}`]: error, 206 [`${classes.hasError}`]: error,
142 })} 207 })}
143 > 208 >
144 {prefix && <span className={classes.prefix}>{prefix}</span>} 209 <meter
145 <input 210 value={passwordScore < 5 ? 5 : passwordScore}
146 id={id} 211 low={30}
147 type={inputType} 212 high={75}
148 name={name} 213 optimum={100}
149 value={value as string} 214 max={100}
150 placeholder={placeholder}
151 spellCheck={spellCheck}
152 className={classes.input}
153 ref={this.inputRef}
154 onChange={this.onChange.bind(this)}
155 onFocus={onFocus}
156 onBlur={onBlur}
157 disabled={disabled}
158 onKeyPress={this.onInputKeyPress.bind(this)}
159 min={min}
160 max={max}
161 step={step}
162 readOnly={readOnly}
163 /> 215 />
164 {suffix && <span className={classes.suffix}>{suffix}</span>}
165 {showPasswordToggle && (
166 <button
167 type="button"
168 className={classes.formModifier}
169 onClick={() =>
170 this.setState(prevState => ({
171 showPassword: !prevState.showPassword,
172 }))
173 }
174 tabIndex={-1}
175 >
176 <Icon path={!showPassword ? mdiEye : mdiEyeOff} />
177 </button>
178 )}
179 </div> 216 </div>
180 {scorePassword && ( 217 )}
181 <div
182 className={classnames({
183 [`${classes.passwordScore}`]: true,
184 [`${classes.hasError}`]: error,
185 })}
186 >
187 <meter
188 value={passwordScore < 5 ? 5 : passwordScore}
189 low={30}
190 high={75}
191 optimum={100}
192 max={100}
193 />
194 </div>
195 )}
196 </Label>
197 {error && <Error message={error} />} 218 {error && <Error message={error} />}
198 </Wrapper> 219 </Wrapper>
199 ); 220 );
200 } 221 }
201} 222}
202 223
203export default injectSheet(styles, { injectTheme: true })(InputComponent); 224export default injectIntl(withStyles(styles, { injectTheme: true })(Input));
diff --git a/src/components/ui/input/styles.ts b/src/components/ui/input/styles.ts
index 04c1b3991..ebae0e40d 100644
--- a/src/components/ui/input/styles.ts
+++ b/src/components/ui/input/styles.ts
@@ -49,7 +49,6 @@ export default (theme: Theme) => ({
49 }, 49 },
50 passwordScore: { 50 passwordScore: {
51 background: theme.inputScorePasswordBackground, 51 background: theme.inputScorePasswordBackground,
52 border: theme.inputBorder,
53 borderTopWidth: 0, 52 borderTopWidth: 0,
54 borderBottomLeftRadius: theme.borderRadiusSmall, 53 borderBottomLeftRadius: theme.borderRadiusSmall,
55 borderBottomRightRadius: theme.borderRadiusSmall, 54 borderBottomRightRadius: theme.borderRadiusSmall,