UNPKG

react-redux-formal

Version:

Form state management and building library for react and redux

288 lines (218 loc) 9.31 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }(); var _propTypes = require('prop-types'); var _propTypes2 = _interopRequireDefault(_propTypes); var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _reactRedux = require('react-redux'); var _shallowEquals = require('shallow-equals'); var _shallowEquals2 = _interopRequireDefault(_shallowEquals); var _formActions = require('./formActions'); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _toArray(arr) { return Array.isArray(arr) ? arr : Array.from(arr); } function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; } function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; } exports.default = function (setup) { return function (WrappedComponent) { var ReactReduxForm = function (_React$Component) { _inherits(ReactReduxForm, _React$Component); /** * Initialise the form. */ function ReactReduxForm() { _classCallCheck(this, ReactReduxForm); var _this = _possibleConstructorReturn(this, (ReactReduxForm.__proto__ || Object.getPrototypeOf(ReactReduxForm)).call(this)); _this.inputCache = {}; _this.formValidate = _this.formValidate.bind(_this); return _this; } /** * Ensure the form is present in redux upon mounting */ _createClass(ReactReduxForm, [{ key: 'componentWillMount', value: function componentWillMount() { var _props = this.props, dispatch = _props.dispatch, options = _props.options; dispatch((0, _formActions.formInit)(options.name, Object.keys(options.fields), options.values || {})); } /** * Invalidate generated inputs if they're not valid anymore * Additionally, create initial state for any fields that were added */ }, { key: 'componentWillReceiveProps', value: function componentWillReceiveProps(_ref) { var _this2 = this; var _ref$options = _ref.options, nextFields = _ref$options.fields, nextValues = _ref$options.values; var _props$options = this.props.options, fields = _props$options.fields, name = _props$options.name; Object.keys(fields).forEach(function (fieldName) { if (!nextFields[fieldName]) { delete _this2.inputCache[fieldName]; } if (!(0, _shallowEquals2.default)(fields[fieldName], nextFields[fieldName])) { delete _this2.inputCache[fieldName]; } }); Object.keys(nextFields).forEach(function (fieldName) { if (fields[fieldName]) return; _this2.props.dispatch((0, _formActions.formAddField)(name, fieldName, nextValues[fieldName])); }); } /** * Create a change handler for the given field * * @param {String} fieldName */ }, { key: 'createChangeHandler', value: function createChangeHandler(fieldName) { var _props2 = this.props, dispatch = _props2.dispatch, options = _props2.options; return function (value) { dispatch((0, _formActions.fieldUpdate)(options.name, fieldName, value)); }; } /** * Create a validation handler for the given field * * @param {String} fieldName * @param {Array} validators */ }, { key: 'createValidateHandler', value: function createValidateHandler(fieldName, validators) { var _this3 = this; return function (value) { _this3.fieldValidate(fieldName, validators, value); }; } /** * Create field components for each desired field */ }, { key: 'createFields', value: function createFields() { var _this4 = this; var _props$options2 = this.props.options, fields = _props$options2.fields, inputTypes = _props$options2.inputTypes, name = _props$options2.name; var fieldComponents = {}; Object.keys(fields).forEach(function (fieldName) { if (_this4.inputCache[fieldName]) { fieldComponents[fieldName] = _this4.inputCache[fieldName]; return; } var _fields$fieldName = fields[fieldName], validators = _fields$fieldName.validators, field = _objectWithoutProperties(_fields$fieldName, ['validators']); var InputType = inputTypes[field.type]; var ConnectedInput = (0, _reactRedux.connect)(function (state) { return { error: state.form[name].fields[fieldName].error, value: state.form[name].values[fieldName] }; }, function () { return {}; })(InputType); _this4.inputCache[fieldName] = fieldComponents[fieldName] = function (fieldProps) { return _react2.default.createElement(ConnectedInput, _extends({}, field, fieldProps, { name: fieldName, change: _this4.createChangeHandler(fieldName), validate: _this4.createValidateHandler(fieldName, validators) })); }; }); return fieldComponents; } /** * Validate given field * * @param {String} fieldName * @param {Function[]} validators * @param {Mixed} value */ }, { key: 'fieldValidate', value: function fieldValidate(fieldName, validators, value) { if (!validators || !validators.length) return Promise.resolve(value); var _props3 = this.props, dispatch = _props3.dispatch, formName = _props3.options.name; var _validators = _toArray(validators), fv = _validators[0], v = _validators.slice(1); return v.reduce(function (a, b) { return a.then(b); }, fv(value || '')).then(function (finalValue) { dispatch((0, _formActions.fieldValidateSuccess)(formName, fieldName)); return Promise.resolve(finalValue); }).catch(function (err) { dispatch((0, _formActions.fieldValidateFailure)(formName, fieldName, err)); return Promise.reject(err); }); } /** * Validate all fields in the form */ }, { key: 'formValidate', value: function formValidate() { var _this5 = this; var _props4 = this.props, fields = _props4.options.fields, values = _props4.values; return Promise.all(Object.keys(fields).map(function (fieldName) { return _this5.fieldValidate(fieldName, fields[fieldName].validators, values[fieldName]); })).then(function () { return Promise.resolve(values); }); } /** * Render the form */ }, { key: 'render', value: function render() { var props = _objectWithoutProperties(this.props, []); delete props.dispatch; delete props.options; return _react2.default.createElement(WrappedComponent, _extends({}, props, { fields: this.createFields(), formValidate: this.formValidate })); } }]); return ReactReduxForm; }(_react2.default.Component); ReactReduxForm.propTypes = { dispatch: _propTypes2.default.func.isRequired, options: _propTypes2.default.shape({ fields: _propTypes2.default.object.isRequired, name: _propTypes2.default.string.isRequired }).isRequired, // eslint-disable-next-line react/forbid-prop-types values: _propTypes2.default.object.isRequired }; return (0, _reactRedux.connect)(function (state, props) { var options = setup(state, props); return { options: options, values: (state.form[options.name] || { values: {} }).values }; })(ReactReduxForm); }; };