{"_id":"@divanov/final-form-calculate","name":"@divanov/final-form-calculate","dist-tags":{"latest":"1.3.2"},"versions":{"1.3.2":{"name":"@divanov/final-form-calculate","version":"1.3.2","description":"Decorator for calculating field values based on other field values in 🏁 Final Form","main":"dist/final-form-calculate.cjs.js","jsnext:main":"dist/final-form-calculate.es.js","module":"dist/final-form-calculate.es.js","typings":"dist/index.d.ts","scripts":{"start":"nps","test":"nps test","precommit":"lint-staged && npm start validate"},"author":{"name":"Erik Rasmussen","email":"rasmussenerik@gmail.com","url":"http://github.com/erikras"},"license":"MIT","repository":{"type":"git","url":"git+https://github.com/final-form/final-form-calculate.git"},"bugs":{"url":"https://github.com/final-form/final-form-calculate/issues"},"homepage":"https://github.com/final-form/final-form-calculate#readme","devDependencies":{"@babel/core":"^7.2.2","@babel/plugin-external-helpers":"^7.0.0","@babel/plugin-proposal-class-properties":"^7.3.0","@babel/plugin-proposal-decorators":"^7.3.0","@babel/plugin-proposal-export-namespace-from":"^7.0.0","@babel/plugin-proposal-function-sent":"^7.0.0","@babel/plugin-proposal-json-strings":"^7.0.0","@babel/plugin-proposal-numeric-separator":"^7.0.0","@babel/plugin-proposal-throw-expressions":"^7.0.0","@babel/plugin-syntax-dynamic-import":"^7.0.0","@babel/plugin-syntax-import-meta":"^7.0.0","@babel/plugin-transform-flow-strip-types":"^7.2.3","@babel/plugin-transform-runtime":"^7.2.0","@babel/preset-env":"^7.3.1","@babel/preset-flow":"^7.0.0","babel-core":"^7.0.0-bridge.0","babel-eslint":"^10.0.1","babel-jest":"^26.3.0","bundlesize":"^0.18.0","doctoc":"^1.4.0","eslint":"^7.8.1","eslint-config-react-app":"^5.2.1","eslint-plugin-babel":"^5.3.0","eslint-plugin-flowtype":"^5.2.0","eslint-plugin-import":"^2.16.0","eslint-plugin-jsx-a11y":"^6.2.1","eslint-plugin-react":"^7.12.4","final-form":"^4.19.1","flow":"^0.2.3","flow-bin":"^0.132.0","glow":"^1.2.2","husky":"^4.2.5","jest":"^26.4.2","lint-staged":"^10.2.13","nps":"^5.9.3","nps-utils":"^1.7.0","prettier":"^2.1.1","prettier-eslint-cli":"^5.0.0","rollup":"^2.26.9","rollup-plugin-babel":"^4.3.2","rollup-plugin-commonjs":"^10.1.0","rollup-plugin-flow":"^1.1.1","rollup-plugin-node-resolve":"^5.2.0","rollup-plugin-replace":"^2.1.0","rollup-plugin-uglify":"^6.0.2","typescript":"^4.0.2"},"peerDependencies":{"final-form":">=1.3.0"},"lint-staged":{"*.{js,json,md,css}":["prettier --write","git add"]},"jest":{"testEnvironment":"node","testPathIgnorePatterns":[".*\\.ts"]},"bundlesize":[{"path":"dist/final-form-calculate.umd.min.js","threshold":"800B"},{"path":"dist/final-form-calculate.es.js","threshold":"1.2kB"},{"path":"dist/final-form-calculate.cjs.js","threshold":"1.2kB"}],"gitHead":"ec5777e6083f4b6211e67886bd43b6794405da59","_id":"@divanov/final-form-calculate@1.3.2","_nodeVersion":"14.19.1","_npmVersion":"6.14.16","dist":{"integrity":"sha512-2ycxofHrSWRl7RR3926X7Ju/JuxhGLL3BN0bYfD881JpsbIc3JozMlpaDk6FDiBV59PF0XPQxFQYuF0LPLYb4w==","shasum":"4964a294ed94b957ba9c6bba3486d808d0e64068","tarball":"https://registry.npmjs.org/@divanov/final-form-calculate/-/final-form-calculate-1.3.2.tgz","fileCount":14,"unpackedSize":28327,"signatures":[{"keyid":"SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA","sig":"MEYCIQC8JQC6HBVTZ4wD+oJlh8lVFqXbRfzKmgm9pxwGQSvaGAIhANBMe1TCVEfyptfRbVTfzHdA2Q0uRmhnYLUs66z4nfOg"}],"npm-signature":"-----BEGIN PGP SIGNATURE-----\r\nVersion: OpenPGP.js v4.10.10\r\nComment: https://openpgpjs.org\r\n\r\nwsFzBAEBCAAGBQJinOouACEJED1NWxICdlZqFiEECWMYAoorWMhJKdjhPU1b\r\nEgJ2Vmp8GQ//S8sXApbn0xVeesSjptlilv/AluoKH0yJabJq8m1YrD1gaTkL\r\neeTaPBLZd85IGG5Ym8Da7kGdLhsY+600oe39weHJ0u0/o9nxhKVSybbwyKJM\r\ne7340vODptthQVmlCs08AuXgAYcjYDM6zd8SZ3I3FNoVhktRPXvxcnH2YJQu\r\nO8Jquv8PBS5KZwCIk7JXqLtt1wJKEX8jgKw1/QJiZ0YjVtEIkZsQCYEgnZ5L\r\nVN6MXB4sg3WHrUpHkJOk4yqxTfZ4wYH24i3rfBEWEDbBU/O2mGZmVpSUJ7QI\r\ncKaHfpRY7UXsG8yPwq7Y94SfUwygJbOukyWJwObTEp4C4f3OBTY+eEpVbmyO\r\nIpQcQCymSJwjrcMzOXOOxBET1LDIIcBwiXsPoIolC7AnnU0Xq2c8RxM0ugbX\r\nRZTnRTZGo+nZs+HkIba9At4MSxSAUo3d4ZZpsKhqx92V46+JDcP424tpnB6F\r\nQalwreIUj7nhazvYna/JCxMYFKNzv+MZ5K3fYuHSAiSOwyzTOua2gkqNrpgb\r\n/6Z7xtZLzjCNGzUgEcQPUeqSubPvR8f2KMJDVfuHm7xRsj2AtIsPsRUU+vKH\r\nHBLcj6PEqE/7AFXiqYcaWZUyyDgmYZyAbQ6XtI32XnIuwC2reZ5vIkVPd+TA\r\nUoSy+pMpWWPXwzMKU4YIdcgpIdERq3+/1Do=\r\n=+W8R\r\n-----END PGP SIGNATURE-----\r\n"},"_npmUser":{"name":"divanov","email":"drago.ivanov@gmail.com"},"directories":{},"maintainers":[{"name":"divanov","email":"drago.ivanov@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages","tmp":"tmp/final-form-calculate_1.3.2_1654450734472_0.14153664451106063"},"_hasShrinkwrap":false}},"time":{"created":"2022-06-05T17:38:54.421Z","1.3.2":"2022-06-05T17:38:54.656Z","modified":"2022-06-05T17:38:54.803Z"},"maintainers":[{"name":"divanov","email":"drago.ivanov@gmail.com"}],"description":"Decorator for calculating field values based on other field values in 🏁 Final Form","homepage":"https://github.com/final-form/final-form-calculate#readme","repository":{"type":"git","url":"git+https://github.com/final-form/final-form-calculate.git"},"author":{"name":"Erik Rasmussen","email":"rasmussenerik@gmail.com","url":"http://github.com/erikras"},"bugs":{"url":"https://github.com/final-form/final-form-calculate/issues"},"license":"MIT","readme":"# 🏁 Final Form Calculate\n\n[![NPM Version](https://img.shields.io/npm/v/final-form-calculate.svg?style=flat)](https://www.npmjs.com/package/final-form-calculate)\n[![NPM Downloads](https://img.shields.io/npm/dm/final-form-calculate.svg?style=flat)](https://www.npmjs.com/package/final-form-calculate)\n[![Build Status](https://travis-ci.org/final-form/final-form-calculate.svg?branch=master)](https://travis-ci.org/final-form/final-form-calculate)\n[![codecov.io](https://codecov.io/gh/final-form/final-form-calculate/branch/master/graph/badge.svg)](https://codecov.io/gh/final-form/final-form-calculate)\n[![styled with prettier](https://img.shields.io/badge/styled_with-prettier-ff69b4.svg)](https://github.com/prettier/prettier)\n\nDecorator for [🏁 Final Form](https://github.com/final-form/final-form) that\nallows you to define calculations that happen between fields, i.e. \"When field X\nchanges, update field Y.\"\n\n---\n\n## Installation\n\n```bash\nnpm install --save final-form-calculate\n```\n\nor\n\n```bash\nyarn add final-form-calculate\n```\n\n## Usage\n\n```js\nimport { createForm, getIn } from 'final-form'\nimport createDecorator from 'final-form-calculate'\n\n// Create Form\nconst form = createForm({ onSubmit })\n\n// Create Decorator\nconst decorator = createDecorator(\n  // Calculations:\n  {\n    field: 'foo', // when the value of foo changes...\n    updates: {\n      // ...set field \"doubleFoo\" to twice the value of foo\n      doubleFoo: (fooValue, allValues) => fooValue * 2\n    }\n  },\n  {\n    field: 'bar', // when the value of bar changes...\n    updates: {\n      // ...set field \"foo\" to previous value of bar\n      foo: (fooValue, allValues, prevValues) => prevValues.bar\n    }\n  },\n  {\n    field: /items\\[\\d+\\]/, // when a field matching this pattern changes...\n    updates: {\n      // ...sets field \"total\" to the sum of all items\n      total: (itemValue, allValues) =>\n        (allValues.items || []).reduce((sum, value) => sum + value, 0)\n    }\n  },\n  {\n    field: 'foo', // when the value of foo changes...\n    updates: {\n      // ...asynchronously set field \"doubleFoo\" to twice the value using a promise\n      doubleFoo: (fooValue, allValues) =>\n        new Promise(resolve => {\n          setTimeout(() => resolve(fooValue * 2), 100)\n        })\n    }\n  },\n  {\n    field: /\\.timeFrom/, // when a deeper field matching this pattern changes...\n    updates: (value, name, allValues) => {\n      const toField = name.replace('timeFrom', 'timeTo')\n      const toValue = getIn(allValues, toField)\n      if (toValue && value > toValue) {\n        return {\n          [toField]: value\n        }\n      }\n\n      return {}\n    }\n  }\n)\n\n// Decorate form\nconst undecorate = decorator(form)\n\n// Use form as normal\n```\n\n## Table of Contents\n\n<!-- START doctoc generated TOC please keep comment here to allow auto update -->\n\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->\n\n- [Example](#example)\n  - [Calculated Fields Example](#calculated-fields-example)\n- [API](#api)\n  - [`createDecorator: (...calculations: Calculation[]) => Decorator`](#createdecorator-calculations-calculation--decorator)\n- [Types](#types)\n  - [`Calculation: { field: FieldPattern, updates: Updates }`](#calculation--field-fieldpattern-updates-updates-)\n  - [`FieldName: string`](#fieldname-string)\n  - [`FieldPattern: FieldName | RegExp`](#fieldpattern-fieldname--regexp)\n  - [`Updates: { [FieldName]: (value: any, allValues: Object, prevValues: Object, setHints: Hints) => any }`](#updates--fieldname-value-any-allvalues-object--any-)\n\n<!-- END doctoc generated TOC please keep comment here to allow auto update -->\n\n## Example\n\n### [Calculated Fields Example](https://codesandbox.io/s/oq52p6v96y)\n\nExample using\n[🏁 React Final Form](https://github.com/final-form/react-final-form#-react-final-form).\n\n## API\n\n### `createDecorator: (...calculations: Calculation[]) => Decorator`\n\nA function that takes a set of calculations and returns a 🏁 Final Form\n[`Decorator`](https://github.com/final-form/final-form#decorator-form-formapi--unsubscribe).\n\n## Types\n\n### `Calculation: { field: FieldPattern, isEqual?: (any, any) => boolean, updates: Updates }`\n\nA calculation to perform, with an optional `isEqual` predicate to determine if a value has really changed (defaults to `===`).\n\n### `FieldName: string`\n\n### `FieldPattern: FieldName | RegExp | (FieldName | RegExp)[]`\n\nA pattern to match a field with.\n\n### `Updates: UpdatesByName | UpdatesForAll`\n\nEither an object of updater functions or a function that generates updates for multiple fields.\n\n### `UpdatesByName: { [FieldName]: (value: any, allValues: Object, prevValues: Object) => Promise | any }`\n\nUpdater functions for each calculated field.\n\n### `UpdatesForAll: (value: any, field: string, allValues: Object, prevValues: Object, setHints: {skipNextUpdate: boolean}) => Promise | { [FieldName]: any }`\n\nTakes the value and name of the field that just changed, as well as all the values, and returns an object of fields and new values.\n\nWith `setHints`, you can instruct `final-form-calculate` to skip calling next `Updates` cycle.\nYou can do that with `skipHints({skipNextUpdate: true})` in your `updates` handler.\n\nThe reason behind this feature is, in certain scenarious you may have closed loops of fields dependency. E.g. field `foo` updates field `bar`, and field `bar` updates field `foo`. \nThis will result in infinite loop of updates. By calling this function selectively in the body of `updates`, `foo` will update `bar`, but updates on next update cycle will not be called, so `bar` will not update foo.\n\nWhen using this, make sure you `update` all fields that are dependant on the current field, even if they are recursive dependency.\n\nExample:\n```\n{\n  field: \"foo\",\n  updates: {\n    bar: \"foo updated me\",\n  }\n},{\n  field: \"bar\",\n  updates: {\n    baz: \"bar updated me\"\n  }\n}\n```\n\nUpdates on `foo` indirecly will update `baz` in 2 update cycles.\n\nWhen using:\n```\n{\n  field: \"foo\",\n  updates: (value, field, allValues, prevValues, setHints) => {\n    setHints({ skipNextUpdate: true })\n    return {\n      bar: \"foo updated me\",\n    }\n  }\n},{\n  field: \"bar\",\n  updates: {\n    baz: \"bar updated me\"\n  }\n}\n```\n\nUpdates on `foo` will not trigger update on `baz`. \n\nIn order to make such updates, make them directly from `foo`.\n```\n{\n  field: \"foo\",\n  updates: (value, field, allValues, prevValues, setHints) => {\n    setHints({ skipNextUpdate: true })\n    return {\n      bar: \"foo updated me\",\n      baz: \"foo updated me\",\n    }\n  }\n},{\n  field: \"bar\",\n  updates: {\n    baz: \"bar updated me\"\n  }\n}\n```","readmeFilename":"README.md"}