aboutsummaryrefslogtreecommitdiffstats
path: root/packages/forms/src/input
diff options
context:
space:
mode:
authorLibravatar Vijay Aravamudhan <vraravam@users.noreply.github.com>2021-10-15 16:22:25 +0530
committerLibravatar GitHub <noreply@github.com>2021-10-15 16:22:25 +0530
commitec15f83b947fb2daf4ca1a72e3af527dc89512a3 (patch)
treeea049cee5184a58b5bc09505e723cd19a736c4bd /packages/forms/src/input
parentchore: move 'packages/ui' into 'src' (no longer an injected package) (#2077) (diff)
downloadferdium-app-ec15f83b947fb2daf4ca1a72e3af527dc89512a3.tar.gz
ferdium-app-ec15f83b947fb2daf4ca1a72e3af527dc89512a3.tar.zst
ferdium-app-ec15f83b947fb2daf4ca1a72e3af527dc89512a3.zip
chore: move 'packages/forms' into 'src' (no longer an injected package) (#2079)
Diffstat (limited to 'packages/forms/src/input')
-rw-r--r--packages/forms/src/input/index.tsx208
-rw-r--r--packages/forms/src/input/scorePassword.ts42
-rw-r--r--packages/forms/src/input/styles.ts102
3 files changed, 0 insertions, 352 deletions
diff --git a/packages/forms/src/input/index.tsx b/packages/forms/src/input/index.tsx
deleted file mode 100644
index 0b16fe688..000000000
--- a/packages/forms/src/input/index.tsx
+++ /dev/null
@@ -1,208 +0,0 @@
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);
diff --git a/packages/forms/src/input/scorePassword.ts b/packages/forms/src/input/scorePassword.ts
deleted file mode 100644
index 59502e2b0..000000000
--- a/packages/forms/src/input/scorePassword.ts
+++ /dev/null
@@ -1,42 +0,0 @@
1interface ILetters {
2 [key: string]: number;
3}
4
5interface IVariations {
6 [index: string]: boolean;
7 digits: boolean;
8 lower: boolean;
9 nonWords: boolean;
10 upper: boolean;
11}
12
13export function scorePasswordFunc(password: string): number {
14 let score = 0;
15 if (!password) {
16 return score;
17 }
18
19 // award every unique letter until 5 repetitions
20 const letters: ILetters = {};
21 for (const element of password) {
22 letters[element] = (letters[element] || 0) + 1;
23 score += 5 / letters[element];
24 }
25
26 // bonus points for mixing it up
27 const variations: IVariations = {
28 digits: /\d/.test(password),
29 lower: /[a-z]/.test(password),
30 nonWords: /\W/.test(password),
31 upper: /[A-Z]/.test(password),
32 };
33
34 let variationCount = 0;
35 for (const key of Object.keys(variations)) {
36 variationCount += variations[key] === true ? 1 : 0;
37 }
38
39 score += (variationCount - 1) * 10;
40
41 return Math.round(score);
42}
diff --git a/packages/forms/src/input/styles.ts b/packages/forms/src/input/styles.ts
deleted file mode 100644
index 6d56e93b3..000000000
--- a/packages/forms/src/input/styles.ts
+++ /dev/null
@@ -1,102 +0,0 @@
1import { Property } from 'csstype';
2
3import { Theme } from '../../../theme';
4
5const prefixStyles = (theme: Theme) => ({
6 background: theme.inputPrefixBackground,
7 color: theme.inputPrefixColor,
8 lineHeight: `${theme.inputHeight}px`,
9 padding: '0 10px',
10 fontSize: theme.uiFontSize,
11});
12
13export default (theme: Theme) => ({
14 label: {
15 '& > div': {
16 marginTop: 5,
17 },
18 },
19 disabled: {
20 opacity: theme.inputDisabledOpacity,
21 },
22 formModifier: {
23 background: 'none',
24 border: 0,
25 borderLeft: theme.inputBorder,
26 padding: '4px 20px 0',
27 outline: 'none',
28
29 '&:active': {
30 opacity: 0.5,
31 },
32
33 '& svg': {
34 fill: theme.inputModifierColor,
35 },
36 },
37 input: {
38 background: 'none',
39 border: 0,
40 fontSize: theme.uiFontSize,
41 outline: 'none',
42 padding: 8,
43 width: '100%',
44 color: theme.inputColor,
45
46 '&::placeholder': {
47 color: theme.inputPlaceholderColor,
48 },
49 },
50 passwordScore: {
51 background: theme.inputScorePasswordBackground,
52 border: theme.inputBorder,
53 borderTopWidth: 0,
54 borderBottomLeftRadius: theme.borderRadiusSmall,
55 borderBottomRightRadius: theme.borderRadiusSmall,
56 display: 'block',
57 flexBasis: '100%',
58 height: 5,
59 overflow: 'hidden',
60
61 '& meter': {
62 display: 'block',
63 height: '100%',
64 width: '100%',
65
66 '&::-webkit-meter-bar': {
67 background: 'none',
68 },
69
70 '&::-webkit-meter-even-less-good-value': {
71 background: theme.brandDanger,
72 },
73
74 '&::-webkit-meter-suboptimum-value': {
75 background: theme.brandWarning,
76 },
77
78 '&::-webkit-meter-optimum-value': {
79 background: theme.brandSuccess,
80 },
81 },
82 },
83 prefix: prefixStyles(theme),
84 suffix: prefixStyles(theme),
85 wrapper: {
86 background: theme.inputBackground,
87 border: theme.inputBorder,
88 borderRadius: theme.borderRadiusSmall,
89 boxSizing: 'border-box' as Property.BoxSizing,
90 display: 'flex',
91 height: theme.inputHeight,
92 order: 1,
93 width: '100%',
94 },
95 hasPasswordScore: {
96 borderBottomLeftRadius: 0,
97 borderBottomRightRadius: 0,
98 },
99 hasError: {
100 borderColor: theme.brandDanger,
101 },
102});