-
Notifications
You must be signed in to change notification settings - Fork 20
/
Input.tsx
119 lines (98 loc) · 3.22 KB
/
Input.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import * as React from 'react';
import * as PropTypes from 'prop-types';
import { FormWithConstraints, FormWithConstraintsChildContext } from './FormWithConstraints';
import Field from './Field';
export interface InputProps extends React.InputHTMLAttributes<HTMLInputElement> {
innerRef?: React.Ref<HTMLInputElement>;
classes: {
[index: string]: string | undefined;
isPending?: string;
hasErrors?: string;
hasWarnings?: string;
hasInfos?: string;
isValid?: string;
};
}
interface InputState {
field: undefined | 'pending' | Field;
}
export type InputContext = FormWithConstraintsChildContext;
export class Input extends React.Component<InputProps, InputState> {
static contextTypes: React.ValidationMap<InputContext> = {
form: PropTypes.instanceOf(FormWithConstraints).isRequired
};
context!: InputContext;
static defaultProps: InputProps = {
classes: {
isPending: 'is-pending',
hasErrors: 'has-errors',
hasWarnings: 'has-warnings',
hasInfos: 'has-infos',
isValid: 'is-valid'
}
};
state: InputState = {
field: undefined
};
/* eslint-disable react/destructuring-assignment */
componentDidMount() {
this.context.form.addFieldWillValidateEventListener(this.fieldWillValidate);
this.context.form.addFieldDidValidateEventListener(this.fieldDidValidate);
this.context.form.addFieldDidResetEventListener(this.fieldDidReset);
}
componentWillUnmount() {
this.context.form.removeFieldWillValidateEventListener(this.fieldWillValidate);
this.context.form.removeFieldDidValidateEventListener(this.fieldDidValidate);
this.context.form.removeFieldDidResetEventListener(this.fieldDidReset);
}
fieldWillValidate = (fieldName: string) => {
// Ignore the event if it's not for us
if (fieldName === this.props.name) {
this.setState({ field: 'pending' });
}
};
fieldDidValidate = (field: Field) => {
// Ignore the event if it's not for us
if (field.name === this.props.name) {
this.setState({ field });
}
};
fieldDidReset = (field: Field) => {
// Ignore the event if it's not for us
if (field.name === this.props.name) {
this.setState({ field: undefined });
}
};
/* eslint-enable react/destructuring-assignment */
fieldValidationStates() {
const { field } = this.state;
const states = [];
if (field !== undefined) {
if (field === 'pending') {
states.push('isPending');
} else {
if (field.hasErrors()) states.push('hasErrors');
if (field.hasWarnings()) states.push('hasWarnings');
if (field.hasInfos()) states.push('hasInfos');
if (field.isValid()) states.push('isValid');
}
}
return states;
}
render() {
const { innerRef, className, classes, ...inputProps } = this.props;
const validationStates = this.fieldValidationStates();
let classNames = className;
validationStates.forEach(validationState => {
const tmp = classes![validationState];
if (tmp !== undefined) {
if (classNames !== undefined) {
classNames += ` ${tmp}`;
} else {
classNames = tmp;
}
}
});
return <input ref={innerRef} {...inputProps} className={classNames} />;
}
}