aboutsummaryrefslogtreecommitdiffstats
path: root/src/components/ui/input/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'src/components/ui/input/index.tsx')
-rw-r--r--src/components/ui/input/index.tsx208
1 files changed, 208 insertions, 0 deletions
diff --git a/src/components/ui/input/index.tsx b/src/components/ui/input/index.tsx
new file mode 100644
index 000000000..0b16fe688
--- /dev/null
+++ b/src/components/ui/input/index.tsx
@@ -0,0 +1,208 @@
1import { mdiEye, mdiEyeOff } from '@mdi/js';
2import Icon from '@mdi/react';
3import classnames from 'classnames';
4import { Component, createRef, InputHTMLAttributes } from 'react';
5import injectSheet from 'react-jss';
6
7import { IFormField, IWithStyle } from '../typings/generic';
8
9import { Error } from '../error';
10import { Label } from '../label';
11import { Wrapper } from '../wrapper';
12import { scorePasswordFunc } from './scorePassword';
13
14import styles from './styles';
15
16interface IData {
17 [index: string]: string;
18}
19
20interface IProps
21 extends InputHTMLAttributes<HTMLInputElement>,
22 IFormField,
23 IWithStyle {
24 focus?: boolean;
25 prefix?: string;
26 suffix?: string;
27 scorePassword?: boolean;
28 showPasswordToggle?: boolean;
29 data: IData;
30 inputClassName?: string;
31 onEnterKey?: Function;
32}
33
34interface IState {
35 showPassword: boolean;
36 passwordScore: number;
37}
38
39class InputComponent extends Component<IProps, IState> {
40 static defaultProps = {
41 focus: false,
42 onChange: () => {},
43 onBlur: () => {},
44 onFocus: () => {},
45 scorePassword: false,
46 showLabel: true,
47 showPasswordToggle: false,
48 type: 'text',
49 disabled: false,
50 };
51
52 state = {
53 passwordScore: 0,
54 showPassword: false,
55 };
56
57 private inputRef = createRef<HTMLInputElement>();
58
59 componentDidMount() {
60 const { focus, data } = this.props;
61
62 if (this.inputRef && this.inputRef.current) {
63 if (focus) {
64 this.inputRef.current.focus();
65 }
66
67 if (data) {
68 Object.keys(data).map(
69 key => (this.inputRef.current!.dataset[key] = data[key]),
70 );
71 }
72 }
73 }
74
75 onChange(e: React.ChangeEvent<HTMLInputElement>) {
76 const { scorePassword, onChange } = this.props;
77
78 if (onChange) {
79 onChange(e);
80 }
81
82 if (this.inputRef && this.inputRef.current && scorePassword) {
83 this.setState({
84 passwordScore: scorePasswordFunc(this.inputRef.current.value),
85 });
86 }
87 }
88
89 onInputKeyPress(e: React.KeyboardEvent) {
90 if (e.key === 'Enter') {
91 const { onEnterKey } = this.props;
92 onEnterKey && onEnterKey();
93 }
94 }
95
96 render() {
97 const {
98 classes,
99 className,
100 disabled,
101 error,
102 id,
103 inputClassName,
104 label,
105 prefix,
106 scorePassword,
107 suffix,
108 showLabel,
109 showPasswordToggle,
110 type,
111 value,
112 name,
113 placeholder,
114 spellCheck,
115 onBlur,
116 onFocus,
117 min,
118 max,
119 step,
120 required,
121 noMargin,
122 } = this.props;
123
124 const { showPassword, passwordScore } = this.state;
125
126 const inputType = type === 'password' && showPassword ? 'text' : type;
127
128 return (
129 <Wrapper
130 className={className}
131 identifier="franz-input"
132 noMargin={noMargin}
133 >
134 <Label
135 title={label}
136 showLabel={showLabel}
137 htmlFor={id}
138 className={classes.label}
139 isRequired={required}
140 >
141 <div
142 className={classnames({
143 [`${inputClassName}`]: inputClassName,
144 [`${classes.hasPasswordScore}`]: scorePassword,
145 [`${classes.wrapper}`]: true,
146 [`${classes.disabled}`]: disabled,
147 [`${classes.hasError}`]: error,
148 })}
149 >
150 {prefix && <span className={classes.prefix}>{prefix}</span>}
151 <input
152 id={id}
153 type={inputType}
154 name={name}
155 value={value as string}
156 placeholder={placeholder}
157 spellCheck={spellCheck}
158 className={classes.input}
159 ref={this.inputRef}
160 onChange={this.onChange.bind(this)}
161 onFocus={onFocus}
162 onBlur={onBlur}
163 disabled={disabled}
164 onKeyPress={this.onInputKeyPress.bind(this)}
165 min={min}
166 max={max}
167 step={step}
168 />
169 {suffix && <span className={classes.suffix}>{suffix}</span>}
170 {showPasswordToggle && (
171 <button
172 type="button"
173 className={classes.formModifier}
174 onClick={() =>
175 this.setState(prevState => ({
176 showPassword: !prevState.showPassword,
177 }))
178 }
179 tabIndex={-1}
180 >
181 <Icon path={!showPassword ? mdiEye : mdiEyeOff} size={1} />
182 </button>
183 )}
184 </div>
185 {scorePassword && (
186 <div
187 className={classnames({
188 [`${classes.passwordScore}`]: true,
189 [`${classes.hasError}`]: error,
190 })}
191 >
192 <meter
193 value={passwordScore < 5 ? 5 : passwordScore}
194 low={30}
195 high={75}
196 optimum={100}
197 max={100}
198 />
199 </div>
200 )}
201 </Label>
202 {error && <Error message={error} />}
203 </Wrapper>
204 );
205 }
206}
207
208export const Input = injectSheet(styles)(InputComponent);