react-form-with-constraints
Version:
Simple form validation for React
138 lines (137 loc) • 6.26 kB
JavaScript
import * as React from 'react';
import { instanceOf } from 'prop-types';
import { Async } from './Async';
import { FieldFeedbacks } from './FieldFeedbacks';
import { FieldFeedbackType } from './FieldFeedbackType';
import { FieldFeedbackWhenValid } from './FieldFeedbackWhenValid';
import { FormWithConstraints } from './FormWithConstraints';
export class FieldFeedback extends React.Component {
constructor(props, context) {
var _a;
super(props, context);
this.validate = (input) => {
const { when } = this.props;
const { form, fieldFeedbacks } = this.context;
const field = form.fieldsStore.getField(input.name);
const validation = { ...this.state.validation };
if ((fieldFeedbacks.props.stop === 'first' && field.hasFeedbacks(fieldFeedbacks.key)) ||
(fieldFeedbacks.props.stop === 'first-error' && field.hasErrors(fieldFeedbacks.key)) ||
(fieldFeedbacks.props.stop === 'first-warning' && field.hasWarnings(fieldFeedbacks.key)) ||
(fieldFeedbacks.props.stop === 'first-info' && field.hasInfos(fieldFeedbacks.key))) {
validation.show = undefined;
}
else {
validation.show = false;
if (typeof when === 'function') {
validation.show = when(input.value);
}
else if (typeof when === 'string') {
if (when === 'valid') {
validation.show = undefined;
}
else {
const { validity } = input;
if (!validity.valid) {
if (when === '*') {
validation.show = true;
}
else if ((validity.badInput && when === 'badInput') ||
(validity.patternMismatch && when === 'patternMismatch') ||
(validity.rangeOverflow && when === 'rangeOverflow') ||
(validity.rangeUnderflow && when === 'rangeUnderflow') ||
(validity.stepMismatch && when === 'stepMismatch') ||
(validity.tooLong && when === 'tooLong') ||
(validity.tooShort && when === 'tooShort') ||
(validity.typeMismatch && when === 'typeMismatch') ||
(validity.valueMissing && when === 'valueMissing')) {
validation.show = true;
}
}
}
}
else {
throw new TypeError(`Invalid FieldFeedback 'when' type: ${typeof when}`);
}
}
field.addOrReplaceValidation(validation);
this.setState({
validation,
validationMessage: input.validationMessage
});
return validation;
};
this.fieldDidReset = (field) => {
if (field.name === this.context.fieldFeedbacks.fieldName) {
this.setState(prevState => ({
validation: { ...prevState.validation, show: undefined },
validationMessage: ''
}));
}
};
this.key = context.fieldFeedbacks.addFieldFeedback();
const { error, warning, info, when } = props;
let type = FieldFeedbackType.Error;
if (when === 'valid')
type = FieldFeedbackType.WhenValid;
else if (warning)
type = FieldFeedbackType.Warning;
else if (info)
type = FieldFeedbackType.Info;
if (type === FieldFeedbackType.WhenValid && ((_a = error !== null && error !== void 0 ? error : warning) !== null && _a !== void 0 ? _a : info)) {
throw new Error('Cannot have an attribute (error, warning...) with FieldFeedback when="valid"');
}
this.state = {
validation: {
key: this.key,
type,
show: undefined
},
validationMessage: ''
};
}
componentDidMount() {
const { form, fieldFeedbacks, async } = this.context;
if (async)
async.addValidateFieldEventListener(this.validate);
else
fieldFeedbacks.addValidateFieldEventListener(this.validate);
form.addFieldDidResetEventListener(this.fieldDidReset);
}
componentWillUnmount() {
const { form, fieldFeedbacks, async } = this.context;
if (async)
async.removeValidateFieldEventListener(this.validate);
else
fieldFeedbacks.removeValidateFieldEventListener(this.validate);
form.removeFieldDidResetEventListener(this.fieldDidReset);
}
render() {
const { when, error, warning, info, className, classes, style, children, ...otherProps } = this
.props;
const { validation, validationMessage } = this.state;
const fieldFeedbackClassName = classes[validation.type];
const classNames = className !== undefined ? `${className} ${fieldFeedbackClassName}` : fieldFeedbackClassName;
if (validation.type === FieldFeedbackType.WhenValid) {
return (React.createElement(FieldFeedbackWhenValid, { "data-feedback": this.key, style: style, className: classNames, ...otherProps }, children));
}
if (validation.show) {
const feedback = children !== undefined ? children : validationMessage;
return (React.createElement("span", { "data-feedback": this.key, className: classNames, style: { display: 'block', ...style }, ...otherProps }, feedback));
}
return null;
}
}
FieldFeedback.defaultProps = {
when: () => true,
classes: {
error: 'error',
warning: 'warning',
info: 'info',
whenValid: 'when-valid'
}
};
FieldFeedback.contextTypes = {
form: instanceOf(FormWithConstraints).isRequired,
fieldFeedbacks: instanceOf(FieldFeedbacks).isRequired,
async: instanceOf(Async)
};