react-form-with-constraints
Version:
Simple form validation for React
878 lines (853 loc) • 35.7 kB
JavaScript
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('react'), require('prop-types')) :
typeof define === 'function' && define.amd ? define(['exports', 'react', 'prop-types'], factory) :
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ReactFormWithConstraints = {}, global.React, global.PropTypes));
})(this, (function (exports, React, propTypes) { 'use strict';
function _interopNamespace(e) {
if (e && e.__esModule) return e;
var n = Object.create(null);
if (e) {
Object.keys(e).forEach(function (k) {
if (k !== 'default') {
var d = Object.getOwnPropertyDescriptor(e, k);
Object.defineProperty(n, k, d.get ? d : {
enumerable: true,
get: function () { return e[k]; }
});
}
});
}
n["default"] = e;
return Object.freeze(n);
}
var React__namespace = /*#__PURE__*/_interopNamespace(React);
function assert(_condition, _message) {}
class EventEmitter {
constructor() {
this.listeners = new Map();
}
emitSync(eventName, ...args) {
const listeners = this.getListeners(eventName);
const ret = new Array();
listeners.forEach(listener => ret.push(listener(...args)));
return ret;
}
async emitAsync(eventName, ...args) {
const listeners = this.getListeners(eventName);
const ret = new Array();
for (let i = 0; i < listeners.length; i++) {
ret.push(await listeners[i](...args));
}
return ret;
}
getListeners(eventName) {
const listeners = this.listeners.get(eventName);
if (listeners !== undefined) {
assert(listeners.length > 0, `No listener for event '${eventName}'`);
return listeners;
}
return [];
}
addListener(eventName, listener) {
if (!this.listeners.has(eventName))
this.listeners.set(eventName, []);
const listeners = this.listeners.get(eventName);
assert(!listeners.includes(listener), `Listener already added for event '${eventName}'`);
listeners.push(listener);
}
removeListener(eventName, listener) {
const listeners = this.listeners.get(eventName);
assert(listeners !== undefined, `Unknown event '${eventName}'`);
const index = listeners.lastIndexOf(listener);
assert(index > -1, `Listener not found for event '${eventName}'`);
listeners.splice(index, 1);
if (listeners.length === 0)
this.listeners.delete(eventName);
}
}
function clearArray(array) {
while (array.length > 0) {
array.pop();
}
}
exports.FieldFeedbackType = void 0;
(function (FieldFeedbackType) {
FieldFeedbackType["Error"] = "error";
FieldFeedbackType["Warning"] = "warning";
FieldFeedbackType["Info"] = "info";
FieldFeedbackType["WhenValid"] = "whenValid";
})(exports.FieldFeedbackType || (exports.FieldFeedbackType = {}));
class Field {
constructor(name) {
this.name = name;
this.validations = [];
}
addOrReplaceValidation(validation) {
const i = this.validations.findIndex(_validation => _validation.key === validation.key);
if (i > -1)
this.validations[i] = validation;
else
this.validations.push(validation);
}
clearValidations() {
clearArray(this.validations);
}
hasFeedbacksOfType(type, fieldFeedbacksKey) {
return this.validations.some(fieldFeedback => (fieldFeedbacksKey === undefined ||
fieldFeedback.key.startsWith(`${fieldFeedbacksKey}.`)) &&
fieldFeedback.type === type &&
fieldFeedback.show === true);
}
hasErrors(fieldFeedbacksKey) {
return this.hasFeedbacksOfType(exports.FieldFeedbackType.Error, fieldFeedbacksKey);
}
hasWarnings(fieldFeedbacksKey) {
return this.hasFeedbacksOfType(exports.FieldFeedbackType.Warning, fieldFeedbacksKey);
}
hasInfos(fieldFeedbacksKey) {
return this.hasFeedbacksOfType(exports.FieldFeedbackType.Info, fieldFeedbacksKey);
}
hasFeedbacks(fieldFeedbacksKey) {
return (this.hasErrors(fieldFeedbacksKey) ||
this.hasWarnings(fieldFeedbacksKey) ||
this.hasInfos(fieldFeedbacksKey));
}
isValid() {
return !this.hasErrors();
}
}
exports.FieldEvent = void 0;
(function (FieldEvent) {
FieldEvent["Added"] = "FIELD_ADDED";
FieldEvent["Removed"] = "FIELD_REMOVED";
})(exports.FieldEvent || (exports.FieldEvent = {}));
class FieldsStore extends EventEmitter {
constructor() {
super(...arguments);
this.fields = new Array();
}
getField(fieldName) {
const fields = this.fields.filter(_field => _field.name === fieldName);
return fields.length === 1 ? fields[0] : undefined;
}
addField(fieldName) {
const fields = this.fields.filter(_field => _field.name === fieldName);
assert(fields.length === 0 || fields.length === 1, `Cannot have more than 1 field matching '${fieldName}'`);
if (fields.length === 0) {
const newField = new Field(fieldName);
this.fields.push(newField);
this.emitSync(exports.FieldEvent.Added, newField);
}
}
removeField(fieldName) {
const fields = this.fields.filter(_field => _field.name === fieldName);
const index = this.fields.indexOf(fields[0]);
if (index > -1) {
this.fields.splice(index, 1);
this.emitSync(exports.FieldEvent.Removed, fieldName);
}
}
isValid() {
return this.fields.every(field => field.isValid());
}
hasFeedbacks() {
return this.fields.some(field => field.hasFeedbacks());
}
}
class IValidityState {
constructor(validity) {
this.badInput = validity.badInput;
this.customError = validity.customError;
this.patternMismatch = validity.patternMismatch;
this.rangeOverflow = validity.rangeOverflow;
this.rangeUnderflow = validity.rangeUnderflow;
this.stepMismatch = validity.stepMismatch;
this.tooLong = validity.tooLong;
this.tooShort = validity.tooShort;
this.typeMismatch = validity.typeMismatch;
this.valid = validity.valid;
this.valueMissing = validity.valueMissing;
}
}
function isHTMLInput(input) {
return input.props === undefined;
}
class InputElement {
constructor(input) {
if (isHTMLInput(input)) {
this.name = input.name;
this.type = input.type;
this.value = input.value;
this.validity = new IValidityState(input.validity);
this.validationMessage = input.validationMessage;
}
else {
this.name = input.props.name;
this.type = undefined;
this.value = input.props.value;
this.validity = undefined;
this.validationMessage = undefined;
}
}
}
function notUndefined(value) {
return value !== undefined;
}
const FieldDidResetEvent = 'FIELD_DID_RESET_EVENT';
function withFieldDidResetEventEmitter(Base) {
return class ResetFieldEvenEmitter extends Base {
constructor() {
super(...arguments);
this.fieldDidResetEventEmitter = new EventEmitter();
}
emitFieldDidResetEvent(field) {
return this.fieldDidResetEventEmitter.emitSync(FieldDidResetEvent, field);
}
addFieldDidResetEventListener(listener) {
this.fieldDidResetEventEmitter.addListener(FieldDidResetEvent, listener);
}
removeFieldDidResetEventListener(listener) {
this.fieldDidResetEventEmitter.removeListener(FieldDidResetEvent, listener);
}
};
}
const FieldDidValidateEvent = 'FIELD_DID_VALIDATE_EVENT';
function withFieldDidValidateEventEmitter(Base) {
return class FieldDidValidateEventEmitter extends Base {
constructor() {
super(...arguments);
this.fieldDidValidateEventEmitter = new EventEmitter();
}
emitFieldDidValidateEvent(field) {
return this.fieldDidValidateEventEmitter.emitSync(FieldDidValidateEvent, field);
}
addFieldDidValidateEventListener(listener) {
this.fieldDidValidateEventEmitter.addListener(FieldDidValidateEvent, listener);
}
removeFieldDidValidateEventListener(listener) {
this.fieldDidValidateEventEmitter.removeListener(FieldDidValidateEvent, listener);
}
};
}
const FieldWillValidateEvent = 'FIELD_WILL_VALIDATE_EVENT';
function withFieldWillValidateEventEmitter(Base) {
return class FieldWillValidateEventEmitter extends Base {
constructor() {
super(...arguments);
this.fieldWillValidateEventEmitter = new EventEmitter();
}
emitFieldWillValidateEvent(fieldName) {
return this.fieldWillValidateEventEmitter.emitSync(FieldWillValidateEvent, fieldName);
}
addFieldWillValidateEventListener(listener) {
this.fieldWillValidateEventEmitter.addListener(FieldWillValidateEvent, listener);
}
removeFieldWillValidateEventListener(listener) {
this.fieldWillValidateEventEmitter.removeListener(FieldWillValidateEvent, listener);
}
};
}
const ValidateFieldEvent = 'VALIDATE_FIELD_EVENT';
function withValidateFieldEventEmitter(Base) {
return class ValidateFieldEventEmitter extends Base {
constructor() {
super(...arguments);
this.validateFieldEventEmitter = new EventEmitter();
}
emitValidateFieldEvent(input) {
return this.validateFieldEventEmitter.emitAsync(ValidateFieldEvent, input);
}
addValidateFieldEventListener(listener) {
this.validateFieldEventEmitter.addListener(ValidateFieldEvent, listener);
}
removeValidateFieldEventListener(listener) {
this.validateFieldEventEmitter.removeListener(ValidateFieldEvent, listener);
}
};
}
class FormWithConstraintsComponent extends React__namespace.PureComponent {
}
class FormWithConstraints extends withFieldDidResetEventEmitter(withFieldWillValidateEventEmitter(withFieldDidValidateEventEmitter(withValidateFieldEventEmitter(FormWithConstraintsComponent)))) {
constructor() {
super(...arguments);
this.form = null;
this.fieldsStore = new FieldsStore();
this.fieldFeedbacksKeyCounter = 0;
}
getChildContext() {
return {
form: this
};
}
computeFieldFeedbacksKey() {
return `${this.fieldFeedbacksKeyCounter++}`;
}
validateFields(...inputsOrNames) {
return this._validateFields(true, ...inputsOrNames);
}
validateForm() {
return this.validateFieldsWithoutFeedback();
}
validateFieldsWithoutFeedback(...inputsOrNames) {
return this._validateFields(false, ...inputsOrNames);
}
async _validateFields(forceValidateFields, ...inputsOrNames) {
const fields = new Array();
const inputs = this.normalizeInputs(...inputsOrNames);
for (let i = 0; i < inputs.length; i++) {
const input = inputs[i];
const field = await this.validateField(forceValidateFields, new InputElement(input), input);
if (field !== undefined)
fields.push(field);
}
return fields;
}
async validateField(forceValidateFields, input, nativeInput) {
const fieldName = input.name;
const field = this.fieldsStore.getField(fieldName);
if (field === undefined) ;
else if (forceValidateFields || !field.hasFeedbacks()) {
field.element = nativeInput;
field.clearValidations();
this.emitFieldWillValidateEvent(fieldName);
const arrayOfArrays = await this.emitValidateFieldEvent(input);
assert(JSON.stringify(arrayOfArrays.flat(Number.POSITIVE_INFINITY).filter(fieldFeedback => notUndefined(fieldFeedback))) ===
JSON.stringify(field.validations), `FieldsStore does not match emitValidateFieldEvent() result, did the user changed the input rapidly?`);
this.emitFieldDidValidateEvent(field);
}
return field;
}
normalizeInputs(...inputsOrNames) {
let inputs;
if (inputsOrNames.length === 0) {
inputs = Array.from(this.form.querySelectorAll('[name]'));
inputs = inputs.filter(input => input.validity !== undefined);
inputs
.filter(input => input.type !== 'checkbox' && input.type !== 'radio')
.map(input => input.name)
.forEach((name, index, self) => {
if (self.indexOf(name) !== index) {
throw new Error(`Multiple elements matching '[name="${name}"]' inside the form`);
}
});
}
else {
inputs = inputsOrNames.map(input => {
if (typeof input === 'string') {
const query = `[name="${input}"]`;
const elements = Array.from(this.form.querySelectorAll(query));
if (elements.some(el => el.validity === undefined)) {
throw new Error(`'${query}' should match an <input>, <select> or <textarea>`);
}
if (elements.filter(el => el.type !== 'checkbox' && el.type !== 'radio').length > 1) {
throw new Error(`Multiple elements matching '${query}' inside the form`);
}
const element = elements[0];
if (element === undefined) {
throw new Error(`Could not find field '${query}' inside the form`);
}
return element;
}
return input;
});
}
return inputs;
}
isValid() {
return this.fieldsStore.isValid();
}
hasFeedbacks() {
return this.fieldsStore.hasFeedbacks();
}
reset() {
return this.resetFields();
}
resetFields(...inputsOrNames) {
const fields = new Array();
const inputs = this.normalizeInputs(...inputsOrNames);
inputs.forEach(input => {
const field = this.resetField(new InputElement(input));
if (field !== undefined)
fields.push(field);
});
return fields;
}
resetField(input) {
const fieldName = input.name;
const field = this.fieldsStore.getField(fieldName);
if (field === undefined) ;
else {
field.clearValidations();
this.emitFieldDidResetEvent(field);
}
return field;
}
render() {
return React__namespace.createElement("form", { ref: form => (this.form = form), ...this.props });
}
}
FormWithConstraints.childContextTypes = {
form: propTypes.instanceOf(FormWithConstraints).isRequired
};
class FieldFeedbacksComponent extends React__namespace.PureComponent {
}
class FieldFeedbacks extends withValidateFieldEventEmitter(FieldFeedbacksComponent) {
constructor(props, context) {
super(props, context);
this.fieldFeedbackKeyCounter = 0;
this.validate = async (input) => {
const { form, fieldFeedbacks: fieldFeedbacksParent } = this.context;
let validations;
if (input.name === this.fieldName) {
const field = form.fieldsStore.getField(this.fieldName);
if (fieldFeedbacksParent && (fieldFeedbacksParent.props.stop === 'first' && field.hasFeedbacks(fieldFeedbacksParent.key) ||
fieldFeedbacksParent.props.stop === 'first-error' && field.hasErrors(fieldFeedbacksParent.key) ||
fieldFeedbacksParent.props.stop === 'first-warning' && field.hasWarnings(fieldFeedbacksParent.key) ||
fieldFeedbacksParent.props.stop === 'first-info' && field.hasInfos(fieldFeedbacksParent.key))) ;
else {
validations = await this._validate(input);
}
}
return validations;
};
const { form, fieldFeedbacks: fieldFeedbacksParent } = context;
this.key = fieldFeedbacksParent
? fieldFeedbacksParent.computeFieldFeedbackKey()
: form.computeFieldFeedbacksKey();
if (fieldFeedbacksParent) {
this.fieldName = fieldFeedbacksParent.fieldName;
if (props.for !== undefined) {
throw new Error("FieldFeedbacks cannot have a parent and a 'for' prop");
}
}
else {
if (props.for === undefined) {
throw new Error("FieldFeedbacks cannot be without parent and without 'for' prop");
}
else {
this.fieldName = props.for;
}
}
}
getChildContext() {
return {
fieldFeedbacks: this
};
}
computeFieldFeedbackKey() {
return `${this.key}.${this.fieldFeedbackKeyCounter++}`;
}
addFieldFeedback() {
return this.computeFieldFeedbackKey();
}
componentDidMount() {
const { form, fieldFeedbacks: fieldFeedbacksParent } = this.context;
form.fieldsStore.addField(this.fieldName);
const parent = fieldFeedbacksParent !== null && fieldFeedbacksParent !== void 0 ? fieldFeedbacksParent : form;
parent.addValidateFieldEventListener(this.validate);
}
componentWillUnmount() {
const { form, fieldFeedbacks: fieldFeedbacksParent } = this.context;
form.fieldsStore.removeField(this.fieldName);
const parent = fieldFeedbacksParent !== null && fieldFeedbacksParent !== void 0 ? fieldFeedbacksParent : form;
parent.removeValidateFieldEventListener(this.validate);
}
async _validate(input) {
const arrayOfArrays = await this.emitValidateFieldEvent(input);
const validations = arrayOfArrays.flat(Number.POSITIVE_INFINITY);
return validations;
}
render() {
const { children } = this.props;
return children !== undefined ? children : null;
}
}
FieldFeedbacks.defaultProps = {
stop: 'first-error'
};
FieldFeedbacks.contextTypes = {
form: propTypes.instanceOf(FormWithConstraints).isRequired,
fieldFeedbacks: propTypes.instanceOf(FieldFeedbacks)
};
FieldFeedbacks.childContextTypes = {
fieldFeedbacks: propTypes.instanceOf(FieldFeedbacks).isRequired
};
exports.Status = void 0;
(function (Status) {
Status[Status["None"] = 0] = "None";
Status[Status["Pending"] = 1] = "Pending";
Status[Status["Rejected"] = 2] = "Rejected";
Status[Status["Resolved"] = 3] = "Resolved";
})(exports.Status || (exports.Status = {}));
class AsyncComponent extends React__namespace.PureComponent {
}
class Async extends withValidateFieldEventEmitter(AsyncComponent) {
constructor() {
super(...arguments);
this.state = {
status: exports.Status.None
};
this.validate = (input) => {
const { form, fieldFeedbacks } = this.context;
let validations;
const field = form.fieldsStore.getField(input.name);
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))) {
this.setState({ status: exports.Status.None });
}
else {
validations = this._validate(input);
}
return validations;
};
}
getChildContext() {
return {
async: this
};
}
componentDidMount() {
this.context.fieldFeedbacks.addValidateFieldEventListener(this.validate);
}
componentWillUnmount() {
this.context.fieldFeedbacks.removeValidateFieldEventListener(this.validate);
}
async setStateSync(state) {
return new Promise(resolve => {
this.setState(state, resolve);
});
}
async _validate(input) {
let state = {
status: exports.Status.Pending
};
this.setState(state);
try {
const value = await this.props.promise(input.value);
state = { status: exports.Status.Resolved, value };
}
catch (e) {
state = { status: exports.Status.Rejected, value: e };
}
await this.setStateSync(state);
return this.emitValidateFieldEvent(input);
}
render() {
const { props, state } = this;
let element = null;
switch (state.status) {
case exports.Status.None:
break;
case exports.Status.Pending:
if (props.pending)
element = props.pending;
break;
case exports.Status.Resolved:
if (props.then)
element = props.then(state.value);
break;
case exports.Status.Rejected:
if (props.catch)
element = props.catch(state.value);
break;
default:
assert(false, `Unknown status: '${state.status}'`);
}
return element;
}
}
Async.contextTypes = {
form: propTypes.instanceOf(FormWithConstraints).isRequired,
fieldFeedbacks: propTypes.instanceOf(FieldFeedbacks).isRequired
};
Async.childContextTypes = {
async: propTypes.instanceOf(Async).isRequired
};
function deepForEach(children, fn) {
React.Children.forEach(children, child => {
const element = child;
if (element.props && element.props.children && typeof element.props.children === 'object') {
deepForEach(element.props.children, fn);
}
fn(element);
});
}
class FieldFeedbackWhenValid extends React__namespace.Component {
constructor() {
super(...arguments);
this.state = {
fieldIsValid: undefined
};
this.fieldWillValidate = (fieldName) => {
if (fieldName === this.context.fieldFeedbacks.fieldName) {
this.setState({ fieldIsValid: undefined });
}
};
this.fieldDidValidate = (field) => {
if (field.name === this.context.fieldFeedbacks.fieldName) {
this.setState({ fieldIsValid: field.isValid() });
}
};
this.fieldDidReset = (field) => {
if (field.name === this.context.fieldFeedbacks.fieldName) {
this.setState({ fieldIsValid: undefined });
}
};
}
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);
}
render() {
const { style, ...otherProps } = this.props;
return this.state.fieldIsValid ? (React__namespace.createElement("span", { ...otherProps, style: { display: 'block', ...style } })) : null;
}
}
FieldFeedbackWhenValid.contextTypes = {
form: propTypes.instanceOf(FormWithConstraints).isRequired,
fieldFeedbacks: propTypes.instanceOf(FieldFeedbacks).isRequired
};
class FieldFeedback extends React__namespace.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 = exports.FieldFeedbackType.Error;
if (when === 'valid')
type = exports.FieldFeedbackType.WhenValid;
else if (warning)
type = exports.FieldFeedbackType.Warning;
else if (info)
type = exports.FieldFeedbackType.Info;
if (type === exports.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 === exports.FieldFeedbackType.WhenValid) {
return (React__namespace.createElement(FieldFeedbackWhenValid, { "data-feedback": this.key, style: style, className: classNames, ...otherProps }, children));
}
if (validation.show) {
const feedback = children !== undefined ? children : validationMessage;
return (React__namespace.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: propTypes.instanceOf(FormWithConstraints).isRequired,
fieldFeedbacks: propTypes.instanceOf(FieldFeedbacks).isRequired,
async: propTypes.instanceOf(Async)
};
class Input extends React__namespace.Component {
constructor() {
super(...arguments);
this.state = {
field: undefined
};
this.fieldWillValidate = (fieldName) => {
if (fieldName === this.props.name) {
this.setState({ field: 'pending' });
}
};
this.fieldDidValidate = (field) => {
if (field.name === this.props.name) {
this.setState({ field });
}
};
this.fieldDidReset = (field) => {
if (field.name === this.props.name) {
this.setState({ field: undefined });
}
};
}
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);
}
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 React__namespace.createElement("input", { ref: innerRef, ...inputProps, className: classNames });
}
}
Input.contextTypes = {
form: propTypes.instanceOf(FormWithConstraints).isRequired
};
Input.defaultProps = {
classes: {
isPending: 'is-pending',
hasErrors: 'has-errors',
hasWarnings: 'has-warnings',
hasInfos: 'has-infos',
isValid: 'is-valid'
}
};
exports.Async = Async;
exports.EventEmitter = EventEmitter;
exports.Field = Field;
exports.FieldDidResetEvent = FieldDidResetEvent;
exports.FieldDidValidateEvent = FieldDidValidateEvent;
exports.FieldFeedback = FieldFeedback;
exports.FieldFeedbackWhenValid = FieldFeedbackWhenValid;
exports.FieldFeedbacks = FieldFeedbacks;
exports.FieldWillValidateEvent = FieldWillValidateEvent;
exports.FieldsStore = FieldsStore;
exports.FormWithConstraints = FormWithConstraints;
exports.IValidityState = IValidityState;
exports.Input = Input;
exports.InputElement = InputElement;
exports.ValidateFieldEvent = ValidateFieldEvent;
exports.assert = assert;
exports.deepForEach = deepForEach;
exports.isHTMLInput = isHTMLInput;
exports.withFieldDidResetEventEmitter = withFieldDidResetEventEmitter;
exports.withFieldDidValidateEventEmitter = withFieldDidValidateEventEmitter;
exports.withFieldWillValidateEventEmitter = withFieldWillValidateEventEmitter;
exports.withValidateFieldEventEmitter = withValidateFieldEventEmitter;
Object.defineProperty(exports, '__esModule', { value: true });
}));