aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui/Input.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/ui/Input.tsx')
-rw-r--r--src/components/ui/Input.tsx157
1 files changed, 157 insertions, 0 deletions
diff --git a/src/components/ui/Input.tsx b/src/components/ui/Input.tsx
new file mode 100644
index 000000000..78b3a9200
--- /dev/null
+++ b/src/components/ui/Input.tsx
@@ -0,0 +1,157 @@
1import { ChangeEvent, Component, createRef, RefObject } from 'react';
2import { observer } from 'mobx-react';
3import classnames from 'classnames';
4import { defineMessages, injectIntl, WrappedComponentProps } from 'react-intl';
5import { mdiEye, mdiEyeOff } from '@mdi/js';
6import { scorePassword as scorePasswordFunc } from '../../helpers/password-helpers';
7import Icon from './icon';
8import { Field } from '../../@types/mobx-form.types';
9
10const messages = defineMessages({
11 passwordToggle: {
12 id: 'settings.app.form.passwordToggle',
13 defaultMessage: 'Password toggle',
14 },
15});
16
17interface IProps extends WrappedComponentProps {
18 field: Field;
19 className?: string;
20 focus?: boolean;
21 showPasswordToggle?: boolean;
22 showLabel?: boolean;
23 scorePassword?: boolean;
24 prefix?: string;
25 suffix?: string;
26}
27
28interface IState {
29 showPassword: boolean;
30 passwordScore: number;
31}
32
33// Can this file be merged into the './input/index.tsx' file?
34@observer
35class Input extends Component<IProps, IState> {
36 private inputElement: RefObject<HTMLInputElement> =
37 createRef<HTMLInputElement>();
38
39 constructor(props: IProps) {
40 super(props);
41
42 this.state = {
43 showPassword: false,
44 passwordScore: 0,
45 };
46 }
47
48 componentDidMount(): void {
49 const { focus = false } = this.props;
50 if (focus) {
51 this.focus();
52 }
53 }
54
55 onChange(e: ChangeEvent<HTMLInputElement>): void {
56 const { field, scorePassword } = this.props;
57
58 if (field.onChange) {
59 field.onChange(e);
60 }
61
62 if (scorePassword) {
63 this.setState({ passwordScore: scorePasswordFunc(field.value) });
64 }
65 }
66
67 focus() {
68 if (this.inputElement && this.inputElement.current) {
69 this.inputElement.current!.focus();
70 }
71 }
72
73 render() {
74 const {
75 field,
76 className = null,
77 showPasswordToggle = false,
78 showLabel = true,
79 scorePassword = false,
80 prefix = '',
81 suffix = '',
82 intl,
83 } = this.props;
84
85 const { passwordScore } = this.state;
86
87 let { type } = field;
88 if (type === 'password' && this.state.showPassword) {
89 type = 'text';
90 }
91
92 return (
93 <div
94 className={classnames({
95 'franz-form__field': true,
96 'has-error': field.error,
97 [`${className}`]: className,
98 })}
99 >
100 <div className="franz-form__input-wrapper">
101 {prefix && <span className="franz-form__input-prefix">{prefix}</span>}
102 <input
103 id={field.id}
104 type={type}
105 className="franz-form__input"
106 name={field.name}
107 value={field.value}
108 placeholder={field.placeholder}
109 onChange={e => this.onChange(e)}
110 onBlur={field.onBlur}
111 onFocus={field.onFocus}
112 ref={this.inputElement}
113 disabled={field.disabled}
114 />
115 {suffix && <span className="franz-form__input-suffix">{suffix}</span>}
116 {showPasswordToggle && (
117 <button
118 type="button"
119 className={classnames({
120 'franz-form__input-modifier': true,
121 })}
122 onClick={() =>
123 this.setState(prevState => ({
124 showPassword: !prevState.showPassword,
125 }))
126 }
127 tabIndex={-1}
128 aria-label={intl.formatMessage(messages.passwordToggle)}
129 >
130 <Icon icon={this.state.showPassword ? mdiEye : mdiEyeOff} />
131 </button>
132 )}
133 {scorePassword && (
134 <div className="franz-form__password-score">
135 {/* <progress value={this.state.passwordScore} max="100" /> */}
136 <meter
137 value={passwordScore < 5 ? 5 : passwordScore}
138 low={30}
139 high={75}
140 optimum={100}
141 max={100}
142 />
143 </div>
144 )}
145 </div>
146 {field.label && showLabel && (
147 <label className="franz-form__label" htmlFor={field.name}>
148 {field.label}
149 </label>
150 )}
151 {field.error && <div className="franz-form__error">{field.error}</div>}
152 </div>
153 );
154 }
155}
156
157export default injectIntl(Input);