aboutsummaryrefslogtreecommitdiffstats
path: root/packages/forms/src/input/index.tsx
diff options
context:
space:
mode:
Diffstat (limited to 'packages/forms/src/input/index.tsx')
-rw-r--r--packages/forms/src/input/index.tsx175
1 files changed, 175 insertions, 0 deletions
diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx
new file mode 100644
index 000000000..107335573
--- /dev/null
+++ b/packages/forms/src/input/index.tsx
@@ -0,0 +1,175 @@
1import { mdiEye, mdiEyeOff } from '@mdi/js';
2import Icon from '@mdi/react';
3import classnames from 'classnames';
4import pick from 'lodash/pick';
5import { observer } from 'mobx-react';
6import React, { Component } from 'react';
7import htmlElementAttributes from 'react-html-attributes';
8import injectSheet from 'react-jss';
9
10import { IFormField, IWithStyle } from '../typings/generic';
11
12import Error from '../error';
13import Label from '../label';
14import Wrapper from '../wrapper';
15import scorePasswordFunc from './scorePassword';
16
17import styles from './styles';
18
19interface IProps extends IFormField, React.InputHTMLAttributes<HTMLInputElement>, IWithStyle {
20 label: string;
21 focus?: boolean;
22 prefix?: string;
23 suffix?: string;
24 scorePassword?: boolean;
25 showPasswordToggle?: boolean;
26 error?: string;
27}
28
29interface IState {
30 showPassword: boolean;
31 passwordScore: number;
32}
33
34@observer
35class Input extends Component<IProps, IState> {
36 public static defaultProps = {
37 classes: {},
38 focus: false,
39 onChange: () => {},
40 scorePassword: false,
41 showLabel: true,
42 showPasswordToggle: false,
43 type: 'text',
44 };
45
46 state = {
47 passwordScore: 0,
48 showPassword: false,
49 };
50
51 private inputRef = React.createRef<HTMLInputElement>();
52
53 componentDidMount() {
54 const { focus } = this.props;
55
56 if (focus && this.inputRef && this.inputRef.current) {
57 this.inputRef.current.focus();
58 }
59 }
60
61 onChange(e: React.ChangeEvent<HTMLInputElement>) {
62 const {
63 scorePassword,
64 onChange,
65 } = this.props;
66
67 if (onChange) {
68 onChange(e);
69 }
70
71 if (this.inputRef && this.inputRef.current && scorePassword) {
72 this.setState({ passwordScore: scorePasswordFunc(this.inputRef.current.value) });
73 }
74 }
75
76 render() {
77 const {
78 classes,
79 disabled,
80 error,
81 id,
82 label,
83 prefix,
84 scorePassword,
85 suffix,
86 showLabel,
87 showPasswordToggle,
88 type,
89 } = this.props;
90
91 const {
92 showPassword,
93 passwordScore,
94 } = this.state;
95
96 const inputProps = pick(this.props, htmlElementAttributes['input']);
97
98 if (type === 'password' && showPassword) {
99 inputProps.type = 'text';
100 }
101
102 inputProps.onChange = this.onChange.bind(this);
103
104 const cssClasses = classnames({
105 [`${inputProps.className}`]: inputProps.className,
106 [`${classes.input}`]: true,
107 });
108
109 return (
110 <Wrapper>
111 <Label
112 title={label}
113 showLabel={showLabel}
114 htmlFor={id}
115 >
116 <div
117 className={classnames({
118 [`${classes.hasPasswordScore}`]: showPasswordToggle,
119 [`${classes.wrapper}`]: true,
120 [`${classes.disabled}`]: disabled,
121 [`${classes.hasError}`]: error,
122 })}>
123 {prefix && (
124 <span className={classes.prefix}>
125 {prefix}
126 </span>
127 )}
128 <input
129 {...inputProps}
130 className={cssClasses}
131 ref={this.inputRef}
132 />
133 {suffix && (
134 <span className={classes.suffix}>
135 {suffix}
136 </span>
137 )}
138 {showPasswordToggle && (
139 <button
140 type="button"
141 className={classes.formModifier}
142 onClick={() => this.setState(prevState => ({ showPassword: !prevState.showPassword }))}
143 tabIndex={-1}
144 >
145 <Icon
146 path={!showPassword ? mdiEye : mdiEyeOff}
147 size={1}
148 />
149 </button>
150 )}
151 </div>
152 {scorePassword && (
153 <div className={classnames({
154 [`${classes.passwordScore}`]: true,
155 [`${classes.hasError}`]: error,
156 })}>
157 <meter
158 value={passwordScore < 5 ? 5 : passwordScore}
159 low={30}
160 high={75}
161 optimum={100}
162 max={100}
163 />
164 </div>
165 )}
166 </Label>
167 {error && (
168 <Error message={error} />
169 )}
170 </Wrapper>
171 );
172 }
173}
174
175export default injectSheet(styles)(Input);