react-proforma
Version:
React Proforma helps you build simple to complex web forms with ease in React. -- Simplicity where you want it. Flexibility where you need it.
284 lines (283 loc) • 15.4 kB
JavaScript
;
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 __());
};
})();
var __assign = (this && this.__assign) || function () {
__assign = Object.assign || function(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
var react_1 = __importDefault(require("react"));
var helpers_1 = require("./helpers");
var ProformaContext_1 = require("./ProformaContext");
/**
* The core component of the React Proforma library. It takes in a config object and a handleSubmit
* function as props, expects a function (that renders your form) as a child, and then executes that
* function while providing it all of the methods and properties that make up the
* ProformaBundle (see docs for complete contents of the bundle). You can either hook up
* your form elements yourself using the appropriate pieces of the ProformaBundle, or you can rely
* on the custom form elements offered by the React Proforma library that come pre-hooked-up to the
* Proforma internal functionality (see docs for complete list of custom form elements).
*
* @param {Object} config - Core configuration object for React Proforma. See docs for complete config options.
* @param {Object} config.initialValues - an object containing the initial values for your form data. The name for each piece of form data MUST exist on this object, or it will not be included in any of the internal processing.
* @param {Object=} [config.validationObject] - an object containing any validation you wish to have performed on any (or all) form data. See docs for more information.
* @param {Object=} [config.customOnChangeObject] - an object containing the names of any field that you wish to have a custom onChange operation performed. If present for a given name, the provided onChange function will be executed instead of the internal React Proforma change handler. See docs for more information.
* @param {Object=} [config.onValidateCallbacksObject] - an object containing the names of any field that you wish to have a custom callback function called after each validation cycle. If present for a given name, the provided callback function will be executed upon the completion of each validation cycle. See docs for more information.
* @param {boolean=} [config.resetTouchedOnFocus=false] - boolean flag that, if set to true, causes the "touched" status for fields to reset whenever the field has focus. Defaults to false.
* @param {boolean=} [config.validateOnChange=true] - boolean flat that, if set to false, will not run validation for fields on change. Defaults to true.
* @param {Function} handleSubmit - The function to be executed when your form is submitted. The function will be executed with the following two arguments:
* <br/>(1) values - an object containing the current form values.
* <br/>(2) HandleSubmitBundle - an object containing useful methods and properties for your form submission:
* <br/>(i) setSubmitting - a function that enables you to change the submission status of your form, with signature: (setTo: boolean) => void
* <br/>(ii) setComplete - a function that enables you to change the completion status of your form, with signature: (setTo: boolean) => void
* <br/>(iii) setValues - a function that enables you to set the values of any of your form fields, with signature: (setToObject: object) => void
* <br/>(iv) resetFields - a function that resets all of your form fields back to the initial values, with signature: () => void
* <br/>(v) submitCount - a property that represents the number of times this form has been submitted.
* <br/>(vi) event - the original form submission React event.
* @returns {JSX.Element | null} - JSX.Element or null (null if no children are provided)
*/
var Proforma = /** @class */ (function (_super) {
__extends(Proforma, _super);
function Proforma(props) {
var _this = _super.call(this, props) || this;
// Check incoming props
if (!_this.props.config)
throw new Error('You must provide a "config" prop to the Proforma component.');
if (!_this.props.config.initialValues)
throw new Error('You must provide an initialValues object to the config prop.');
if (!_this.props.handleSubmit)
console.warn('You have not provided a handleSubmit function prop to the Proforma component. React Proforma will still work. However, when your form is submitted, nothing will happen.');
// Generate state
_this.state = helpers_1.generateStateObject(_this.props.config.initialValues);
// Forced to use bind approach because class property syntax brings
// class property methods to top of constructor before prop error checking
// can be run and state object is generated.
_this.validateField = _this.validateField.bind(_this);
_this.handleChange = _this.handleChange.bind(_this);
_this.handleFocus = _this.handleFocus.bind(_this);
_this.handleBlur = _this.handleBlur.bind(_this);
_this.setValues = _this.setValues.bind(_this);
_this.setSubmitting = _this.setSubmitting.bind(_this);
_this.setComplete = _this.setComplete.bind(_this);
_this.handleSubmit = _this.handleSubmit.bind(_this);
_this.handleReset = _this.handleReset.bind(_this);
_this.resetFields = _this.resetFields.bind(_this);
_this.computeProformaBundle = _this.computeProformaBundle.bind(_this);
_this.proformaBundle = {
values: __assign({}, _this.state.values),
touched: __assign({}, _this.state.touched),
errors: __assign({}, _this.state.errors),
isSubmitting: _this.state.isSubmitting,
isComplete: _this.state.isComplete,
handleChange: _this.handleChange,
handleFocus: _this.handleFocus,
handleBlur: _this.handleBlur,
handleSubmit: _this.handleSubmit,
handleReset: _this.handleReset,
setSubmitting: _this.setSubmitting,
setValues: _this.setValues,
setComplete: _this.setComplete,
submitCount: _this.state.submitCount
};
return _this;
}
// state: ProformaStateType<V> = generateStateObject<V>(
// this.props.config.initialValues
// );
Proforma.prototype.validateField = function (name) {
var _this = this;
var validationObject = this.props.config.validationObject;
if (validationObject && validationObject[name]) {
this.setState(function (prevState) {
var _a;
return ({
errors: __assign(__assign({}, prevState.errors), (_a = {}, _a[name] = helpers_1.validator(name, prevState.values, validationObject), _a))
});
}, function () {
var onValidateCallbacksObject = _this.props.config.onValidateCallbacksObject;
if (onValidateCallbacksObject && onValidateCallbacksObject[name]) {
onValidateCallbacksObject[name]();
}
});
}
};
Proforma.prototype.handleChange = function (event) {
var _this = this;
var target = event.target;
var value = target.type === 'checkbox' ? target.checked : target.value;
var name = target.name;
// Check for customOnChangeObject from user
var customOnChangeObject = this.props.config.customOnChangeObject;
if (customOnChangeObject && customOnChangeObject[name]) {
// execute user's onChange function
customOnChangeObject[name](event, this.setValues);
return;
}
this.setState(function (prevState) {
var _a;
return ({
values: __assign(__assign({}, prevState.values), (_a = {}, _a[name] = value, _a))
});
}, function () {
if (_this.props.config.validateOnChange === undefined ||
_this.props.config.validateOnChange === true) {
_this.validateField(name);
}
});
};
Proforma.prototype.handleFocus = function (event) {
if (this.props.config.resetTouchedOnFocus) {
var target = event.target;
var name_1 = target.name;
if (name_1) {
this.setState(function (prevState) {
var _a;
return ({
touched: __assign(__assign({}, prevState.touched), (_a = {}, _a[name_1] = false, _a))
});
});
}
}
};
Proforma.prototype.handleBlur = function (event) {
var _this = this;
var target = event.target;
var name = target.name;
if (name) {
this.setState(function (prevState) {
var _a;
return ({
touched: __assign(__assign({}, prevState.touched), (_a = {}, _a[name] = true, _a))
});
}, function () {
_this.validateField(name);
});
}
};
Proforma.prototype.setValues = function (setToObj) {
var _this = this;
if (typeof setToObj !== 'object')
return;
var keys = Object.keys(setToObj);
var tmpObj = {};
for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
var key = keys_1[_i];
if (key in this.state.values) {
tmpObj[key] = setToObj[key];
}
}
if (Object.keys(tmpObj).length > 0) {
this.setState(function (prevState) { return ({
values: __assign(__assign({}, prevState.values), tmpObj)
}); }, function () {
if (_this.props.config.validateOnChange === undefined ||
_this.props.config.validateOnChange === true) {
if (_this.props.config.validationObject) {
var validationObject = _this.props.config.validationObject;
// Create errors object to insert into state.errors
var errorsToInsert_1 = {};
var errors = void 0;
for (var _i = 0, keys_2 = keys; _i < keys_2.length; _i++) {
var key = keys_2[_i];
if (validationObject[key]) {
errors = helpers_1.validator(key, _this.state.values, validationObject);
if (errors !== undefined) {
errorsToInsert_1[key] = errors;
}
}
}
// If errorsToInsert is not empty, update state.errors
if (Object.keys(errorsToInsert_1).length > 0) {
_this.setState(function (prevState) { return ({
errors: __assign(__assign({}, prevState.errors), errorsToInsert_1)
}); });
}
}
}
});
}
};
Proforma.prototype.setSubmitting = function (setTo) {
this.setState({ isSubmitting: setTo });
};
Proforma.prototype.setComplete = function (setTo) {
this.setState({ isComplete: setTo });
};
Proforma.prototype.handleSubmit = function (event) {
var _this = this;
event.preventDefault();
if (this.state.isSubmitting === false) {
this.setState(function (prevState) { return ({
isSubmitting: true,
submitCount: prevState.submitCount + 1
}); }, function () {
if (_this.props.handleSubmit) {
_this.props.handleSubmit(_this.state.values, {
setSubmitting: _this.setSubmitting,
setComplete: _this.setComplete,
setValues: _this.setValues,
resetFields: _this.resetFields,
submitCount: _this.state.submitCount,
event: event
});
}
});
}
};
Proforma.prototype.handleReset = function (event) {
// if (event.target === event.currentTarget) {
event.preventDefault();
event.stopPropagation();
this.setState(__assign({}, helpers_1.generateStateObject(this.props.config.initialValues)));
// }
};
Proforma.prototype.resetFields = function () {
this.setState(__assign({}, helpers_1.generateStateObject(this.props.config.initialValues)));
};
Proforma.prototype.computeProformaBundle = function () {
var _a = this.state, values = _a.values, touched = _a.touched, errors = _a.errors, isSubmitting = _a.isSubmitting, isComplete = _a.isComplete, submitCount = _a.submitCount;
this.proformaBundle.values = __assign({}, values);
this.proformaBundle.touched = __assign({}, touched);
this.proformaBundle.errors = __assign({}, errors);
this.proformaBundle.isSubmitting = isSubmitting;
this.proformaBundle.isComplete = isComplete;
this.proformaBundle.submitCount = submitCount;
};
Proforma.prototype.render = function () {
this.computeProformaBundle();
var children = this.props.children;
if (!children)
return null;
if (typeof children === 'function') {
// children exists and is a function. Execute it, passing in the ProformaBundle.
return (react_1.default.createElement(ProformaContext_1.ProformaContextProvider, { value: this.proformaBundle }, children(this.proformaBundle)));
}
else {
// Same, but children is not a function (will still work if user uses React Proforma custom form elements
return (react_1.default.createElement(ProformaContext_1.ProformaContextProvider, { value: this.proformaBundle }, children));
}
};
return Proforma;
}(react_1.default.PureComponent));
exports.Proforma = Proforma;