react-hooks-dynamic-form
Version:
Dynamic form with react hooks
238 lines (237 loc) • 8.34 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
/**
* [TYPE] Available value for field "type"
*/
var FieldTypeEnum;
(function (FieldTypeEnum) {
/**
* HTML Text input
*/
FieldTypeEnum["TEXT"] = "text";
/**
* HTML Number input
*/
FieldTypeEnum["NUMBER"] = "number";
/**
* Text input with default email format validation
*/
FieldTypeEnum["EMAIL"] = "email";
/**
* Text input with general phone format validation
*/
FieldTypeEnum["PHONE"] = "phone";
/**
* HTML password input
*/
FieldTypeEnum["PASSWORD"] = "password";
/**
* HTML hidden input
*/
FieldTypeEnum["HIDDEN"] = "hidden";
/**
* HTML textarea
*/
FieldTypeEnum["TEXTAREA"] = "textarea";
/**
* Generated checkbox
* (only applicable to Form Component)
*/
FieldTypeEnum["CHECKBOX"] = "checkbox";
/**
* Generated radio button
* (only applicable to Form Component)
*/
FieldTypeEnum["RADIO"] = "radio";
/**
* User's custom rendered field
* (only applicable to Form Component)
*/
FieldTypeEnum["CUSTOM"] = "custom";
})(FieldTypeEnum = exports.FieldTypeEnum || (exports.FieldTypeEnum = {}));
var DEFAULT_ERROR_MESSAGES = {
isRequired: "This field is required",
email: "Invalid email",
phone: "Invalid phone number",
default: "Invalid field value",
};
/**
* [TYPE] Field settings
*/
var FieldSettings = /** @class */ (function () {
function FieldSettings() {
//#region --- Common settings for Form API and Form Component
/**
* Field type that will be use for adding default validation rule and render method when using Form component
*/
this.type = "text";
/**
* If true, the field is required for validation. Can be a predicate with formData as parameter in case of conditional validation based on other field
*/
this.isRequired = false;
/**
* Custom validation rules
*/
this.customValidators = [];
/**
* If true, validate field on change, otherwise validate on blur by default
*/
this.validateOnChange = false;
/**
* If true, disable built-in validator, applicable to type with default validator (email, phone)
*/
this.disableBuiltInValidator = false;
//#endregion --- Settings only applicable to Form Component
}
return FieldSettings;
}());
exports.FieldSettings = FieldSettings;
var Field = /** @class */ (function (_super) {
__extends(Field, _super);
//#endregion --- Private State
function Field(init) {
var _this = _super.call(this) || this;
//#region --- Private State
_this._error = null;
_this._isPristine = true; // Not sure yet for a use case
/**
* Return error message if field is error after validation
*/
_this.getInputError = function () { return _this._error; };
Object.assign(_this, init, {
_error: null,
_isPristine: true,
});
// Default type text
if (!_this.type || Object.keys(FieldTypeEnum).includes(_this.type)) {
_this.type = "text";
}
// Default value
if (typeof _this.value === "undefined") {
_this.setDefaultValue();
}
// Default validations
_this.setDefaultValidations();
return _this;
}
/**
* Get error message
* @param key error key
*/
Field.prototype.getErrorMessage = function (key) {
return (this.errorMessages && this.errorMessages[key]) || DEFAULT_ERROR_MESSAGES[key] || "";
};
/**
* PRIVATE: set default value
*/
Field.prototype.setDefaultValue = function () {
switch (this.type) {
case FieldTypeEnum.CHECKBOX:
case FieldTypeEnum.RADIO:
this.value = false;
break;
case FieldTypeEnum.CUSTOM:
this.value = null;
break;
default:
this.value = "";
break;
}
};
/**
* PRIVATE: set default validations
*/
Field.prototype.setDefaultValidations = function () {
var _this = this;
// [Optimization]: avoid unnecessary trigger
if (this.validateOnChange && this.validateOnBlur) {
this.validateOnBlur = false;
}
// Init customValidators with empty array
if (!Array.isArray(this.customValidators)) {
this.customValidators = [];
}
switch (this.type) {
case FieldTypeEnum.EMAIL:
if (!this.disableBuiltInValidator) {
// --- Auto add a default email validation
// Keep HTML email type for some browser default validation
// this.type = "text";
this.customValidators.push({
validate: function (value) {
var regex = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return ((!_this.isRequired && !value) || (!!value && regex.test(value.trim())));
},
errorMessage: this.getErrorMessage("email"),
});
}
break;
case FieldTypeEnum.PHONE:
if (!this.disableBuiltInValidator) {
// --- Auto add a default phone validation
this.type = "text";
this.customValidators.push({
validate: function (value) {
var regex = /^(\+)?(\d)(?:[ _.-]?(\d))+$/;
return ((!_this.isRequired && !value) || (!!value && regex.test(value.trim())));
},
errorMessage: this.getErrorMessage("phone"),
});
}
break;
default:
break;
}
};
/**
* Set value from user input
* @param newValue input value
*/
Field.prototype.setInputValue = function (newValue) {
// Temporarily reset error till next validation
this._error = null;
this.value = newValue;
this._isPristine = false;
};
/**
* Validate field
* @param formData current form data object
*/
Field.prototype.validate = function (formData) {
var _this = this;
// Reset error
this._error = null;
// 0 is a valid value :P
var hasValue = !(typeof this.value === "undefined" ||
this.value === null ||
this.value === "" ||
this.value === false);
if (this.isRequired) {
var _isRequired = typeof this.isRequired === "function" ? this.isRequired(formData) : this.isRequired;
this._error = _isRequired && !hasValue ? this.getErrorMessage("isRequired") : null;
}
// isRequired passed, check next rules if field has a value
if (!this._error && hasValue && Array.isArray(this.customValidators)) {
var validationFailed = this.customValidators.find(function (validation) { return !validation.validate(_this.value, formData); });
this._error = validationFailed
? validationFailed.errorMessage || this.getErrorMessage("default")
: null;
}
return !this._error;
};
return Field;
}(FieldSettings));
exports.Field = Field;