UNPKG

redux-form

Version:

A higher order component decorator for forms using Redux and React

458 lines (406 loc) 17.9 kB
'use strict'; Object.defineProperty(exports, "__esModule", { value: true }); var _actionTypes = require('./actionTypes'); require('array-findindex-polyfill'); var _deleteInWithCleanUp = require('./deleteInWithCleanUp'); var _deleteInWithCleanUp2 = _interopRequireDefault(_deleteInWithCleanUp); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } 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; } var createReducer = function createReducer(structure) { var _behaviors; var deepEqual = structure.deepEqual; var empty = structure.empty; var getIn = structure.getIn; var setIn = structure.setIn; var deleteIn = structure.deleteIn; var fromJS = structure.fromJS; var size = structure.size; var some = structure.some; var splice = structure.splice; var deleteInWithCleanUp = (0, _deleteInWithCleanUp2.default)(structure); var doSplice = function doSplice(state, key, field, index, removeNum, value, force) { var existing = getIn(state, key + '.' + field); return existing || force ? setIn(state, key + '.' + field, splice(existing, index, removeNum, value)) : state; }; var rootKeys = ['values', 'fields', 'submitErrors', 'asyncErrors']; var arraySplice = function arraySplice(state, field, index, removeNum, value) { var result = state; var nonValuesValue = value != null ? empty : undefined; result = doSplice(result, 'values', field, index, removeNum, value, true); result = doSplice(result, 'fields', field, index, removeNum, nonValuesValue); result = doSplice(result, 'submitErrors', field, index, removeNum, nonValuesValue); result = doSplice(result, 'asyncErrors', field, index, removeNum, nonValuesValue); return result; }; var behaviors = (_behaviors = {}, _defineProperty(_behaviors, _actionTypes.ARRAY_INSERT, function (state, _ref) { var _ref$meta = _ref.meta; var field = _ref$meta.field; var index = _ref$meta.index; var payload = _ref.payload; return arraySplice(state, field, index, 0, payload); }), _defineProperty(_behaviors, _actionTypes.ARRAY_MOVE, function (state, _ref2) { var _ref2$meta = _ref2.meta; var field = _ref2$meta.field; var from = _ref2$meta.from; var to = _ref2$meta.to; var array = getIn(state, 'values.' + field); var length = array ? size(array) : 0; var result = state; if (length) { rootKeys.forEach(function (key) { var path = key + '.' + field; if (getIn(result, path)) { var value = getIn(result, path + '[' + from + ']'); result = setIn(result, path, splice(getIn(result, path), from, 1)); // remove result = setIn(result, path, splice(getIn(result, path), to, 0, value)); // insert } }); } return result; }), _defineProperty(_behaviors, _actionTypes.ARRAY_POP, function (state, _ref3) { var field = _ref3.meta.field; var array = getIn(state, 'values.' + field); var length = array ? size(array) : 0; return length ? arraySplice(state, field, length - 1, 1) : state; }), _defineProperty(_behaviors, _actionTypes.ARRAY_PUSH, function (state, _ref4) { var field = _ref4.meta.field; var payload = _ref4.payload; var array = getIn(state, 'values.' + field); var length = array ? size(array) : 0; return arraySplice(state, field, length, 0, payload); }), _defineProperty(_behaviors, _actionTypes.ARRAY_REMOVE, function (state, _ref5) { var _ref5$meta = _ref5.meta; var field = _ref5$meta.field; var index = _ref5$meta.index; return arraySplice(state, field, index, 1); }), _defineProperty(_behaviors, _actionTypes.ARRAY_REMOVE_ALL, function (state, _ref6) { var field = _ref6.meta.field; var array = getIn(state, 'values.' + field); var length = array ? size(array) : 0; return length ? arraySplice(state, field, 0, length) : state; }), _defineProperty(_behaviors, _actionTypes.ARRAY_SHIFT, function (state, _ref7) { var field = _ref7.meta.field; return arraySplice(state, field, 0, 1); }), _defineProperty(_behaviors, _actionTypes.ARRAY_SPLICE, function (state, _ref8) { var _ref8$meta = _ref8.meta; var field = _ref8$meta.field; var index = _ref8$meta.index; var removeNum = _ref8$meta.removeNum; var payload = _ref8.payload; return arraySplice(state, field, index, removeNum, payload); }), _defineProperty(_behaviors, _actionTypes.ARRAY_SWAP, function (state, _ref9) { var _ref9$meta = _ref9.meta; var field = _ref9$meta.field; var indexA = _ref9$meta.indexA; var indexB = _ref9$meta.indexB; var result = state; rootKeys.forEach(function (key) { var valueA = getIn(result, key + '.' + field + '[' + indexA + ']'); var valueB = getIn(result, key + '.' + field + '[' + indexB + ']'); if (valueA !== undefined || valueB !== undefined) { result = setIn(result, key + '.' + field + '[' + indexA + ']', valueB); result = setIn(result, key + '.' + field + '[' + indexB + ']', valueA); } }); return result; }), _defineProperty(_behaviors, _actionTypes.ARRAY_UNSHIFT, function (state, _ref10) { var field = _ref10.meta.field; var payload = _ref10.payload; return arraySplice(state, field, 0, 0, payload); }), _defineProperty(_behaviors, _actionTypes.AUTOFILL, function (state, _ref11) { var field = _ref11.meta.field; var payload = _ref11.payload; var result = state; result = deleteInWithCleanUp(result, 'asyncErrors.' + field); result = deleteInWithCleanUp(result, 'submitErrors.' + field); result = setIn(result, 'fields.' + field + '.autofilled', true); result = setIn(result, 'values.' + field, payload); return result; }), _defineProperty(_behaviors, _actionTypes.BLUR, function (state, _ref12) { var _ref12$meta = _ref12.meta; var field = _ref12$meta.field; var touch = _ref12$meta.touch; var payload = _ref12.payload; var result = state; var initial = getIn(result, 'initial.' + field); if (initial === undefined && payload === '') { result = deleteInWithCleanUp(result, 'values.' + field); } else if (payload !== undefined) { result = setIn(result, 'values.' + field, payload); } if (field === getIn(result, 'active')) { result = deleteIn(result, 'active'); } result = deleteIn(result, 'fields.' + field + '.active'); if (touch) { result = setIn(result, 'fields.' + field + '.touched', true); result = setIn(result, 'anyTouched', true); } return result; }), _defineProperty(_behaviors, _actionTypes.CHANGE, function (state, _ref13) { var _ref13$meta = _ref13.meta; var field = _ref13$meta.field; var touch = _ref13$meta.touch; var persistentSubmitErrors = _ref13$meta.persistentSubmitErrors; var payload = _ref13.payload; var result = state; var initial = getIn(result, 'initial.' + field); if (initial === undefined && payload === '') { result = deleteInWithCleanUp(result, 'values.' + field); } else if (payload !== undefined) { result = setIn(result, 'values.' + field, payload); } result = deleteInWithCleanUp(result, 'asyncErrors.' + field); if (!persistentSubmitErrors) { result = deleteInWithCleanUp(result, 'submitErrors.' + field); } result = deleteInWithCleanUp(result, 'fields.' + field + '.autofilled'); if (!persistentSubmitErrors) { result = deleteInWithCleanUp(result, 'error'); } if (touch) { result = setIn(result, 'fields.' + field + '.touched', true); result = setIn(result, 'anyTouched', true); } return result; }), _defineProperty(_behaviors, _actionTypes.FOCUS, function (state, _ref14) { var field = _ref14.meta.field; var result = state; var previouslyActive = getIn(state, 'active'); result = deleteIn(result, 'fields.' + previouslyActive + '.active'); result = setIn(result, 'fields.' + field + '.visited', true); result = setIn(result, 'fields.' + field + '.active', true); result = setIn(result, 'active', field); return result; }), _defineProperty(_behaviors, _actionTypes.INITIALIZE, function (state, _ref15) { var payload = _ref15.payload; var keepDirty = _ref15.meta.keepDirty; var mapData = fromJS(payload); var result = empty; // clean all field state var registeredFields = getIn(state, 'registeredFields'); if (registeredFields) { result = setIn(result, 'registeredFields', registeredFields); } var newValues = mapData; if (keepDirty && registeredFields) { (function () { // // Keep the value of dirty fields while updating the value of // pristine fields. This way, apps can reinitialize forms while // avoiding stomping on user edits. // // Note 1: The initialize action replaces all initial values // regardless of keepDirty. // // Note 2: When a field is dirty, keepDirty is enabled, and the field // value is the same as the new initial value for the field, the // initialize action causes the field to become pristine. That effect // is what we want. // var previousValues = getIn(state, 'values'); var previousInitialValues = getIn(state, 'initial'); registeredFields.forEach(function (field) { var name = field.name; var previousInitialValue = getIn(previousInitialValues, name); var previousValue = getIn(previousValues, name); if (!deepEqual(previousValue, previousInitialValue)) { // This field was dirty. Restore the dirty value. newValues = setIn(newValues, name, previousValue); } }); })(); } result = setIn(result, 'values', newValues); result = setIn(result, 'initial', mapData); return result; }), _defineProperty(_behaviors, _actionTypes.REGISTER_FIELD, function (state, _ref16) { var _ref16$payload = _ref16.payload; var name = _ref16$payload.name; var type = _ref16$payload.type; var result = state; var registeredFields = getIn(result, 'registeredFields'); if (some(registeredFields, function (field) { return getIn(field, 'name') === name; })) { return state; } var mapData = fromJS({ name: name, type: type }); result = setIn(state, 'registeredFields', splice(registeredFields, size(registeredFields), 0, mapData)); return result; }), _defineProperty(_behaviors, _actionTypes.RESET, function (state) { var result = empty; var registeredFields = getIn(state, 'registeredFields'); if (registeredFields) { result = setIn(result, 'registeredFields', registeredFields); } var values = getIn(state, 'initial'); if (values) { result = setIn(result, 'values', values); result = setIn(result, 'initial', values); } return result; }), _defineProperty(_behaviors, _actionTypes.START_ASYNC_VALIDATION, function (state, _ref17) { var field = _ref17.meta.field; return setIn(state, 'asyncValidating', field || true); }), _defineProperty(_behaviors, _actionTypes.START_SUBMIT, function (state) { return setIn(state, 'submitting', true); }), _defineProperty(_behaviors, _actionTypes.STOP_ASYNC_VALIDATION, function (state, _ref18) { var payload = _ref18.payload; var result = state; result = deleteIn(result, 'asyncValidating'); if (payload && Object.keys(payload).length) { var _error = payload._error; var fieldErrors = _objectWithoutProperties(payload, ['_error']); if (_error) { result = setIn(result, 'error', _error); } if (Object.keys(fieldErrors).length) { result = setIn(result, 'asyncErrors', fromJS(fieldErrors)); } else { result = deleteIn(result, 'asyncErrors'); } } else { result = deleteIn(result, 'error'); result = deleteIn(result, 'asyncErrors'); } return result; }), _defineProperty(_behaviors, _actionTypes.STOP_SUBMIT, function (state, _ref19) { var payload = _ref19.payload; var result = state; result = deleteIn(result, 'submitting'); result = deleteIn(result, 'submitFailed'); result = deleteIn(result, 'submitSucceeded'); if (payload && Object.keys(payload).length) { var _error = payload._error; var fieldErrors = _objectWithoutProperties(payload, ['_error']); if (_error) { result = setIn(result, 'error', _error); } else { result = deleteIn(result, 'error'); } if (Object.keys(fieldErrors).length) { result = setIn(result, 'submitErrors', fromJS(fieldErrors)); } else { result = deleteIn(result, 'submitErrors'); } result = setIn(result, 'submitFailed', true); } else { result = setIn(result, 'submitSucceeded', true); result = deleteIn(result, 'error'); result = deleteIn(result, 'submitErrors'); } return result; }), _defineProperty(_behaviors, _actionTypes.SET_SUBMIT_FAILED, function (state, _ref20) { var fields = _ref20.meta.fields; var result = state; result = setIn(result, 'submitFailed', true); result = deleteIn(result, 'submitSucceeded'); result = deleteIn(result, 'submitting'); fields.forEach(function (field) { return result = setIn(result, 'fields.' + field + '.touched', true); }); if (fields.length) { result = setIn(result, 'anyTouched', true); } return result; }), _defineProperty(_behaviors, _actionTypes.SET_SUBMIT_SUCCEEDED, function (state) { var result = state; result = deleteIn(result, 'submitFailed'); result = setIn(result, 'submitSucceeded', true); return result; }), _defineProperty(_behaviors, _actionTypes.TOUCH, function (state, _ref21) { var fields = _ref21.meta.fields; var result = state; fields.forEach(function (field) { return result = setIn(result, 'fields.' + field + '.touched', true); }); result = setIn(result, 'anyTouched', true); return result; }), _defineProperty(_behaviors, _actionTypes.UNREGISTER_FIELD, function (state, _ref22) { var name = _ref22.payload.name; var registeredFields = getIn(state, 'registeredFields'); // in case the form was destroyed and registeredFields no longer exists if (!registeredFields) { return state; } var fieldIndex = registeredFields.findIndex(function (value) { return getIn(value, 'name') === name; }); if (size(registeredFields) <= 1 && fieldIndex >= 0) { return deleteInWithCleanUp(state, 'registeredFields'); } if (fieldIndex < 0) { return state; } return setIn(state, 'registeredFields', splice(registeredFields, fieldIndex, 1)); }), _defineProperty(_behaviors, _actionTypes.UNTOUCH, function (state, _ref23) { var fields = _ref23.meta.fields; var result = state; fields.forEach(function (field) { return result = deleteIn(result, 'fields.' + field + '.touched'); }); return result; }), _defineProperty(_behaviors, _actionTypes.UPDATE_SYNC_ERRORS, function (state, _ref24) { var _ref24$payload = _ref24.payload; var syncErrors = _ref24$payload.syncErrors; var error = _ref24$payload.error; var result = state; if (error) { result = setIn(result, 'error', error); } else { result = deleteIn(result, 'error'); } if (Object.keys(syncErrors).length) { result = setIn(result, 'syncErrors', syncErrors); } else { result = deleteIn(result, 'syncErrors'); } return result; }), _behaviors); var reducer = function reducer() { var state = arguments.length <= 0 || arguments[0] === undefined ? empty : arguments[0]; var action = arguments[1]; var behavior = behaviors[action.type]; return behavior ? behavior(state, action) : state; }; var byForm = function byForm(reducer) { return function () { var state = arguments.length <= 0 || arguments[0] === undefined ? empty : arguments[0]; var action = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; var form = action && action.meta && action.meta.form; if (!form) { return state; } if (action.type === _actionTypes.DESTROY) { return deleteInWithCleanUp(state, action.meta.form); } var formState = getIn(state, form); var result = reducer(formState, action); return result === formState ? state : setIn(state, form, result); }; }; /** * Adds additional functionality to the reducer */ function decorate(target) { target.plugin = function plugin(reducers) { var _this = this; // use 'function' keyword to enable 'this' return decorate(function () { var state = arguments.length <= 0 || arguments[0] === undefined ? empty : arguments[0]; var action = arguments.length <= 1 || arguments[1] === undefined ? {} : arguments[1]; return Object.keys(reducers).reduce(function (accumulator, key) { var previousState = getIn(accumulator, key); var nextState = reducers[key](previousState, action); return nextState === previousState ? accumulator : setIn(accumulator, key, nextState); }, _this(state, action)); }); }; return target; } return decorate(byForm(reducer)); }; exports.default = createReducer;