UNPKG

final-form-calculate

Version:

Decorator for calculating field values based on other field values in 🏁 Final Form

178 lines (170 loc) 6.68 kB
(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : typeof define === 'function' && define.amd ? define(['exports'], factory) : (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global["final-form-calculate"] = {})); })(this, (function (exports) { 'use strict'; var charCodeOfDot = ".".charCodeAt(0); var reEscapeChar = /\\(\\)?/g; var rePropName = RegExp( // Match anything that isn't a dot or bracket. "[^.[\\]]+" + "|" + // Or match property names within brackets. "\\[(?:" + // Match a non-string expression. "([^\"'][^[]*)" + "|" + // Or match strings (supports escaping characters). "([\"'])((?:(?!\\2)[^\\\\]|\\\\.)*?)\\2" + ")\\]" + "|" + // Or match "" as the space between consecutive dots or empty brackets. "(?=(?:\\.|\\[\\])(?:\\.|\\[\\]|$))", "g"); /** * Converts `string` to a property path array. * * @private * @param {string} string The string to convert. * @returns {Array} Returns the property path array. */ var stringToPath = function stringToPath(string) { var result = []; if (string.charCodeAt(0) === charCodeOfDot) { result.push(""); } string.replace(rePropName, function (match, expression, quote, subString) { var key = match; if (quote) { key = subString.replace(reEscapeChar, "$1"); } else if (expression) { key = expression.trim(); } result.push(key); return ""; }); return result; }; var keysCache = {}; var keysRegex = /[.[\]]+/; var toPath = function toPath(key) { if (key === null || key === undefined || !key.length) { return []; } if (typeof key !== "string") { throw new Error("toPath() expects a string"); } if (keysCache[key] == null) { /** * The following patch fixes issue 456, introduced since v4.20.3: * * Before v4.20.3, i.e. in v4.20.2, a `key` like 'choices[]' would map to ['choices'] * (e.g. an array of choices used where 'choices[]' is name attribute of an input of type checkbox). * * Since v4.20.3, a `key` like 'choices[]' would map to ['choices', ''] which is wrong and breaks * this kind of inputs e.g. in React. * * v4.20.3 introduced an unwanted breaking change, this patch fixes it, see the issue at the link below. * * @see https://github.com/final-form/final-form/issues/456 */ if (key.endsWith("[]")) { // v4.20.2 (a `key` like 'choices[]' should map to ['choices'], which is fine). keysCache[key] = key.split(keysRegex).filter(Boolean); } else { // v4.20.3 (a `key` like 'choices[]' maps to ['choices', ''], which breaks applications relying on inputs like `<input type="checkbox" name="choices[]" />`). keysCache[key] = stringToPath(key); } } return keysCache[key]; }; var getIn = function getIn(state, complexKey) { // Intentionally using iteration rather than recursion var path = toPath(complexKey); var current = state; for (var i = 0; i < path.length; i++) { var key = path[i]; if (current === undefined || current === null || typeof current !== "object" || Array.isArray(current) && isNaN(Number(key))) { return undefined; } current = current[key]; } return current; }; function isPromise(obj) { return !!obj && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'; } var tripleEquals = function tripleEquals(a, b) { return a === b; }; var createDecorator = function createDecorator() { for (var _len = arguments.length, calculations = new Array(_len), _key = 0; _key < _len; _key++) { calculations[_key] = arguments[_key]; } return function (form) { var previousValues; var unsubscribe = form.subscribe(function (_ref) { var values = _ref.values; form.batch(function () { var runUpdates = function runUpdates(field, isEqual, updates) { var next = values && getIn(values, field); var previous = previousValues && getIn(previousValues, field); if (!isEqual(next, previous)) { if (typeof updates === 'function') { var results = updates(next, field, values, previousValues); if (isPromise(results)) { results.then(function (resolved) { Object.keys(resolved).forEach(function (destField) { form.change(destField, resolved[destField]); }); }); } else { Object.keys(results).forEach(function (destField) { form.change(destField, results[destField]); }); } } else { Object.keys(updates).forEach(function (destField) { var update = updates[destField]; var result = update(next, values, previousValues); if (isPromise(result)) { result.then(function (resolved) { form.change(destField, resolved); }); } else { form.change(destField, result); } }); } } }; var fields = form.getRegisteredFields(); calculations.forEach(function (_ref2) { var field = _ref2.field, isEqual = _ref2.isEqual, updates = _ref2.updates; if (typeof field === 'string') { runUpdates(field, isEqual || tripleEquals, updates); } else { // field is a either array or regex var matches = Array.isArray(field) ? function (name) { return ~field.indexOf(name) || field.findIndex(function (f) { return f instanceof RegExp && f.test(name); }) !== -1; } : function (name) { return field.test(name); }; fields.forEach(function (fieldName) { if (matches(fieldName)) { runUpdates(fieldName, isEqual || tripleEquals, updates); } }); } }); previousValues = values; }); }, { values: true }); return unsubscribe; }; }; exports.default = createDecorator; Object.defineProperty(exports, '__esModule', { value: true }); })); //# sourceMappingURL=final-form-calculate.umd.js.map