@shopify/react-form-state
Advanced tools
Comparing version
@@ -9,2 +9,3 @@ import * as React from 'react'; | ||
export default class List<Fields> extends React.Component<Props<Fields>, never> { | ||
private changeHandlers; | ||
shouldComponentUpdate(nextProps: any): boolean; | ||
@@ -11,0 +12,0 @@ render(): JSX.Element[]; |
@@ -5,4 +5,2 @@ "use strict"; | ||
var React = tslib_1.__importStar(require("react")); | ||
var get_1 = tslib_1.__importDefault(require("lodash/get")); | ||
var lodash_decorators_1 = require("lodash-decorators"); | ||
var utilities_1 = require("../utilities"); | ||
@@ -12,3 +10,25 @@ var List = /** @class */ (function (_super) { | ||
function List() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
var _this = _super !== null && _super.apply(this, arguments) || this; | ||
_this.changeHandlers = new Map(); | ||
_this.handleChange = function (_a) { | ||
var index = _a.index, key = _a.key; | ||
var hashKey = index + ":" + key; | ||
if (_this.changeHandlers.has(hashKey)) { | ||
return _this.changeHandlers.get(hashKey); | ||
} | ||
var handler = function (newValue) { | ||
var onChange = _this.props.field.onChange; | ||
onChange(function (value) { | ||
var _a; | ||
var existingItem = value[index]; | ||
var newItem = tslib_1.__assign({}, existingItem, (_a = {}, _a[key] = typeof newValue === 'function' | ||
? newValue(value[index][key]) | ||
: newValue, _a)); | ||
return utilities_1.replace(value, index, newItem); | ||
}); | ||
}; | ||
_this.changeHandlers.set(hashKey, handler); | ||
return handler; | ||
}; | ||
return _this; | ||
} | ||
@@ -27,3 +47,3 @@ List.prototype.shouldComponentUpdate = function (nextProps) { | ||
var innerFields = utilities_1.mapObject(fieldValues, function (value, fieldPath) { | ||
var initialFieldValue = get_1.default(initialValue, [index, fieldPath]); | ||
var initialFieldValue = initialValue[index][fieldPath]; | ||
return { | ||
@@ -35,3 +55,3 @@ value: value, | ||
dirty: value !== initialFieldValue, | ||
error: get_1.default(error, [index, fieldPath]), | ||
error: error && error[index] && error[index][fieldPath], | ||
onChange: _this.handleChange({ index: index, key: fieldPath }), | ||
@@ -46,23 +66,4 @@ }; | ||
}; | ||
List.prototype.handleChange = function (_a) { | ||
var _this = this; | ||
var index = _a.index, key = _a.key; | ||
return function (newValue) { | ||
var onChange = _this.props.field.onChange; | ||
onChange(function (value) { | ||
var _a; | ||
var existingItem = value[index]; | ||
var newItem = tslib_1.__assign({}, existingItem, (_a = {}, _a[key] = typeof newValue === 'function' | ||
? newValue(value[index][key]) | ||
: newValue, _a)); | ||
return utilities_1.replace(value, index, newItem); | ||
}); | ||
}; | ||
}; | ||
tslib_1.__decorate([ | ||
lodash_decorators_1.memoize(), | ||
lodash_decorators_1.bind() | ||
], List.prototype, "handleChange", null); | ||
return List; | ||
}(React.Component)); | ||
exports.default = List; |
@@ -8,2 +8,3 @@ import * as React from 'react'; | ||
export default class Nested<Fields> extends React.Component<Props<Fields>, never> { | ||
private changeHandlers; | ||
shouldComponentUpdate(nextProps: any): boolean; | ||
@@ -10,0 +11,0 @@ render(): React.ReactNode; |
@@ -5,4 +5,2 @@ "use strict"; | ||
var React = tslib_1.__importStar(require("react")); | ||
var get_1 = tslib_1.__importDefault(require("lodash/get")); | ||
var lodash_decorators_1 = require("lodash-decorators"); | ||
var utilities_1 = require("../utilities"); | ||
@@ -12,3 +10,21 @@ var Nested = /** @class */ (function (_super) { | ||
function Nested() { | ||
return _super !== null && _super.apply(this, arguments) || this; | ||
var _this = _super !== null && _super.apply(this, arguments) || this; | ||
_this.changeHandlers = new Map(); | ||
_this.handleChange = function (key) { | ||
if (_this.changeHandlers.has(key)) { | ||
return _this.changeHandlers.get(key); | ||
} | ||
var handler = function (newValue) { | ||
var onChange = _this.props.field.onChange; | ||
onChange(function (value) { | ||
var _a; | ||
return tslib_1.__assign({}, value, (_a = {}, _a[key] = typeof newValue === 'function' | ||
? newValue(value[key]) | ||
: newValue, _a)); | ||
}); | ||
}; | ||
_this.changeHandlers.set(key, handler); | ||
return handler; | ||
}; | ||
return _this; | ||
} | ||
@@ -33,3 +49,3 @@ Nested.prototype.shouldComponentUpdate = function (nextProps) { | ||
dirty: value !== initialFieldValue, | ||
error: get_1.default(error, fieldPath), | ||
error: error && error[fieldPath], | ||
onChange: _this.handleChange(fieldPath), | ||
@@ -40,20 +56,4 @@ }; | ||
}; | ||
Nested.prototype.handleChange = function (key) { | ||
var _this = this; | ||
return function (newValue) { | ||
var onChange = _this.props.field.onChange; | ||
onChange(function (value) { | ||
var _a; | ||
return tslib_1.__assign({}, value, (_a = {}, _a[key] = typeof newValue === 'function' | ||
? newValue(value[key]) | ||
: newValue, _a)); | ||
}); | ||
}; | ||
}; | ||
tslib_1.__decorate([ | ||
lodash_decorators_1.memoize(), | ||
lodash_decorators_1.bind() | ||
], Nested.prototype, "handleChange", null); | ||
return Nested; | ||
}(React.Component)); | ||
exports.default = Nested; |
@@ -48,2 +48,3 @@ import * as React from 'react'; | ||
private mounted; | ||
private fieldsWithHandlers; | ||
componentDidMount(): void; | ||
@@ -54,3 +55,3 @@ componentWillUnmount(): void; | ||
validateForm(): Promise<{}>; | ||
reset(): Promise<{}>; | ||
reset: () => Promise<{}>; | ||
private readonly dirty; | ||
@@ -57,0 +58,0 @@ private readonly valid; |
@@ -6,6 +6,2 @@ "use strict"; | ||
var React = tslib_1.__importStar(require("react")); | ||
var isEqual_1 = tslib_1.__importDefault(require("lodash/isEqual")); | ||
var isArray_1 = tslib_1.__importDefault(require("lodash/isArray")); | ||
var set_1 = tslib_1.__importDefault(require("lodash/set")); | ||
var lodash_decorators_1 = require("lodash-decorators"); | ||
var utilities_1 = require("./utilities"); | ||
@@ -19,2 +15,60 @@ var components_1 = require("./components"); | ||
_this.mounted = false; | ||
_this.fieldsWithHandlers = new WeakMap(); | ||
_this.reset = function () { | ||
return new Promise(function (resolve) { | ||
_this.setState(function (_state, props) { return createFormState(props.initialValues); }, function () { return resolve(); }); | ||
}); | ||
}; | ||
_this.submit = function (event) { return tslib_1.__awaiter(_this, void 0, void 0, function () { | ||
var _a, onSubmit, validateOnSubmit, formData, errors; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_a = this.props, onSubmit = _a.onSubmit, validateOnSubmit = _a.validateOnSubmit; | ||
formData = this.formData; | ||
if (!this.mounted) { | ||
return [2 /*return*/]; | ||
} | ||
if (event && event.preventDefault && !event.defaultPrevented) { | ||
event.preventDefault(); | ||
} | ||
if (onSubmit == null) { | ||
return [2 /*return*/]; | ||
} | ||
this.setState({ submitting: true }); | ||
if (!validateOnSubmit) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.validateForm()]; | ||
case 1: | ||
_b.sent(); | ||
if (this.hasClientErrors) { | ||
this.setState({ submitting: false }); | ||
return [2 /*return*/]; | ||
} | ||
_b.label = 2; | ||
case 2: return [4 /*yield*/, onSubmit(formData)]; | ||
case 3: | ||
errors = (_b.sent()) || []; | ||
if (!this.mounted) { | ||
return [2 /*return*/]; | ||
} | ||
if (errors.length > 0) { | ||
this.updateRemoteErrors(errors); | ||
this.setState({ submitting: false }); | ||
} | ||
else { | ||
this.setState({ submitting: false, errors: errors }); | ||
} | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); }; | ||
_this.fieldWithHandlers = function (field, fieldPath) { | ||
if (_this.fieldsWithHandlers.has(field)) { | ||
// eslint-disable-next-line typescript/no-non-null-assertion | ||
return _this.fieldsWithHandlers.get(field); | ||
} | ||
var result = tslib_1.__assign({}, field, { name: String(fieldPath), onChange: _this.updateField.bind(_this, fieldPath), onBlur: _this.blurField.bind(_this, fieldPath) }); | ||
_this.fieldsWithHandlers.set(field, result); | ||
return result; | ||
}; | ||
return _this; | ||
@@ -32,3 +86,3 @@ } | ||
var oldInitialValues = initialValuesFromFields(oldState.fields); | ||
var valuesMatch = isEqual_1.default(oldInitialValues, initialValues); | ||
var valuesMatch = utilities_1.isEqual(oldInitialValues, initialValues); | ||
if (valuesMatch) { | ||
@@ -74,8 +128,2 @@ return null; | ||
}; | ||
FormState.prototype.reset = function () { | ||
var _this = this; | ||
return new Promise(function (resolve) { | ||
_this.setState(function (_state, props) { return createFormState(props.initialValues); }, function () { return resolve(); }); | ||
}); | ||
}; | ||
Object.defineProperty(FormState.prototype, "dirty", { | ||
@@ -116,50 +164,2 @@ get: function () { | ||
}); | ||
FormState.prototype.submit = function (event) { | ||
return tslib_1.__awaiter(this, void 0, void 0, function () { | ||
var _a, onSubmit, validateOnSubmit, formData, errors; | ||
return tslib_1.__generator(this, function (_b) { | ||
switch (_b.label) { | ||
case 0: | ||
_a = this.props, onSubmit = _a.onSubmit, validateOnSubmit = _a.validateOnSubmit; | ||
formData = this.formData; | ||
if (!this.mounted) { | ||
return [2 /*return*/]; | ||
} | ||
if (event && event.preventDefault && !event.defaultPrevented) { | ||
event.preventDefault(); | ||
} | ||
if (onSubmit == null) { | ||
return [2 /*return*/]; | ||
} | ||
this.setState({ submitting: true }); | ||
if (!validateOnSubmit) return [3 /*break*/, 2]; | ||
return [4 /*yield*/, this.validateForm()]; | ||
case 1: | ||
_b.sent(); | ||
if (this.hasClientErrors) { | ||
this.setState({ submitting: false }); | ||
return [2 /*return*/]; | ||
} | ||
_b.label = 2; | ||
case 2: return [4 /*yield*/, onSubmit(formData)]; | ||
case 3: | ||
errors = (_b.sent()) || []; | ||
if (!this.mounted) { | ||
return [2 /*return*/]; | ||
} | ||
if (errors.length > 0) { | ||
this.updateRemoteErrors(errors); | ||
this.setState({ submitting: false }); | ||
} | ||
else { | ||
this.setState({ submitting: false, errors: errors }); | ||
} | ||
return [2 /*return*/]; | ||
} | ||
}); | ||
}); | ||
}; | ||
FormState.prototype.fieldWithHandlers = function (field, fieldPath) { | ||
return tslib_1.__assign({}, field, { name: fieldPath, onChange: this.updateField.bind(this, fieldPath), onBlur: this.blurField.bind(this, fieldPath) }); | ||
}; | ||
FormState.prototype.updateField = function (fieldPath, value) { | ||
@@ -174,3 +174,3 @@ var _this = this; | ||
: value; | ||
var dirty = !isEqual_1.default(newValue, field.initialValue); | ||
var dirty = !utilities_1.isEqual(newValue, field.initialValue); | ||
var updatedField = _this.getUpdatedField({ | ||
@@ -255,3 +255,3 @@ fieldPath: fieldPath, | ||
} | ||
return set_1.default(accumulator, field, message); | ||
return utilities_1.set(accumulator, field, message); | ||
}, {}); | ||
@@ -268,12 +268,2 @@ return { | ||
FormState.Nested = components_1.Nested; | ||
tslib_1.__decorate([ | ||
lodash_decorators_1.bind() | ||
], FormState.prototype, "reset", null); | ||
tslib_1.__decorate([ | ||
lodash_decorators_1.bind() | ||
], FormState.prototype, "submit", null); | ||
tslib_1.__decorate([ | ||
lodash_decorators_1.memoize(), | ||
lodash_decorators_1.bind() | ||
], FormState.prototype, "fieldWithHandlers", null); | ||
return FormState; | ||
@@ -287,3 +277,3 @@ }(React.PureComponent)); | ||
var oldField = oldFields[key]; | ||
if (isEqual_1.default(value, oldField.initialValue)) { | ||
if (utilities_1.isEqual(value, oldField.initialValue)) { | ||
return oldField; | ||
@@ -327,3 +317,3 @@ } | ||
} | ||
if (!isArray_1.default(validate)) { | ||
if (!Array.isArray(validate)) { | ||
// eslint-disable-next-line consistent-return | ||
@@ -330,0 +320,0 @@ return; |
@@ -5,1 +5,3 @@ export declare function mapObject<Input, Output>(input: Input, mapper: (value: any, key: keyof Input) => any): Output; | ||
export declare function replace<T>(array: T[], targetIndex: number, newValue: T): T[]; | ||
export declare function set<InputType extends Object>(rootObject: InputType, path: string[], value: any): any; | ||
export declare function isEqual(value: any, baseline: any): boolean; |
@@ -5,5 +5,3 @@ "use strict"; | ||
function mapObject(input, mapper) { | ||
return Object.keys(input) | ||
.map(function (key) { return [key, input[key]]; }) | ||
.reduce(function (accumulator, _a) { | ||
return Object.entries(input).reduce(function (accumulator, _a) { | ||
var _b = tslib_1.__read(_a, 2), key = _b[0], value = _b[1]; | ||
@@ -36,1 +34,69 @@ accumulator[key] = mapper(value, key); | ||
exports.replace = replace; | ||
function set(rootObject, path, value) { | ||
var _a, _b; | ||
if (path.length === 0) { | ||
return rootObject; | ||
} | ||
else if (path.length === 1) { | ||
return tslib_1.__assign({}, rootObject, (_a = {}, _a[path[0]] = value, _a)); | ||
} | ||
else { | ||
var _c = tslib_1.__read(path), current = _c[0], rest = _c.slice(1); | ||
return tslib_1.__assign({}, rootObject, (_b = {}, _b[current] = set(rootObject[current], rest, value), _b)); | ||
} | ||
} | ||
exports.set = set; | ||
function isEqual(value, baseline) { | ||
var e_1, _a; | ||
if (value === baseline) { | ||
return true; | ||
} | ||
if (typeof value !== typeof baseline) { | ||
return false; | ||
} | ||
if (Array.isArray(value)) { | ||
if (!Array.isArray(baseline)) { | ||
return false; | ||
} | ||
if (value.length !== baseline.length) { | ||
return false; | ||
} | ||
for (var iter = 0; iter < value.length; iter++) { | ||
if (!isEqual(value[iter], baseline[iter])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
if (typeof value === 'object') { | ||
if (value === null) { | ||
return baseline === null; | ||
} | ||
if (baseline === null) { | ||
return false; | ||
} | ||
var keysInValue = Object.keys(value); | ||
var keysInBaseline = Object.keys(baseline); | ||
if (!isEqual(keysInValue, keysInBaseline)) { | ||
return false; | ||
} | ||
try { | ||
for (var keysInValue_1 = tslib_1.__values(keysInValue), keysInValue_1_1 = keysInValue_1.next(); !keysInValue_1_1.done; keysInValue_1_1 = keysInValue_1.next()) { | ||
var key = keysInValue_1_1.value; | ||
if (!isEqual(value[key], baseline[key])) { | ||
return false; | ||
} | ||
} | ||
} | ||
catch (e_1_1) { e_1 = { error: e_1_1 }; } | ||
finally { | ||
try { | ||
if (keysInValue_1_1 && !keysInValue_1_1.done && (_a = keysInValue_1.return)) _a.call(keysInValue_1); | ||
} | ||
finally { if (e_1) throw e_1.error; } | ||
} | ||
return true; | ||
} | ||
return false; | ||
} | ||
exports.isEqual = isEqual; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
var tslib_1 = require("tslib"); | ||
var toString_1 = tslib_1.__importDefault(require("lodash/toString")); | ||
var isArray_1 = tslib_1.__importDefault(require("lodash/isArray")); | ||
var utilities_1 = require("./utilities"); | ||
@@ -49,3 +47,3 @@ function lengthMoreThan(length) { | ||
} | ||
if (!isArray_1.default(validate)) { | ||
if (!Array.isArray(validate)) { | ||
// eslint-disable-next-line consistent-return | ||
@@ -98,3 +96,3 @@ return; | ||
// eslint-disable-next-line consistent-return | ||
return errorContent(toString_1.default(input)); | ||
return errorContent(toString(input)); | ||
} | ||
@@ -114,3 +112,3 @@ // eslint-disable-next-line consistent-return | ||
// eslint-disable-next-line consistent-return | ||
return errorContent(toString_1.default(input)); | ||
return errorContent(toString(input)); | ||
} | ||
@@ -142,2 +140,8 @@ // eslint-disable-next-line consistent-return | ||
}; | ||
function toString(obj) { | ||
if (obj == null) { | ||
return ''; | ||
} | ||
return obj.toString(); | ||
} | ||
exports.default = validators; |
{ | ||
"name": "@shopify/react-form-state", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"license": "MIT", | ||
@@ -26,4 +26,2 @@ "description": "Manage react forms tersely and type-safe with no magic.", | ||
"dependencies": { | ||
"lodash": "^4.17.10", | ||
"lodash-decorators": "^6.0.0", | ||
"tslib": "^1.9.3" | ||
@@ -30,0 +28,0 @@ }, |
/* eslint-disable no-case-declarations */ | ||
import * as React from 'react'; | ||
import isEqual from 'lodash/isEqual'; | ||
import isArray from 'lodash/isArray'; | ||
import set from 'lodash/set'; | ||
import {memoize, bind} from 'lodash-decorators'; | ||
import {mapObject} from './utilities'; | ||
import {mapObject, set, isEqual} from './utilities'; | ||
import { | ||
@@ -96,2 +92,3 @@ FieldDescriptors, | ||
private mounted = false; | ||
private fieldsWithHandlers = new WeakMap(); | ||
@@ -137,4 +134,3 @@ componentDidMount() { | ||
@bind() | ||
public reset() { | ||
public reset = () => { | ||
return new Promise(resolve => { | ||
@@ -146,3 +142,3 @@ this.setState( | ||
}); | ||
} | ||
}; | ||
@@ -178,4 +174,3 @@ private get dirty() { | ||
@bind() | ||
private async submit(event?: Event) { | ||
private submit = async (event?: Event) => { | ||
const {onSubmit, validateOnSubmit} = this.props; | ||
@@ -219,17 +214,22 @@ const {formData} = this; | ||
} | ||
} | ||
}; | ||
@memoize() | ||
@bind() | ||
private fieldWithHandlers<Key extends keyof Fields>( | ||
private fieldWithHandlers = <Key extends keyof Fields>( | ||
field: FieldStates<Fields>[Key], | ||
fieldPath: Key, | ||
) { | ||
return { | ||
) => { | ||
if (this.fieldsWithHandlers.has(field)) { | ||
// eslint-disable-next-line typescript/no-non-null-assertion | ||
return this.fieldsWithHandlers.get(field)!; | ||
} | ||
const result = { | ||
...(field as FieldState<Fields[Key]>), | ||
name: fieldPath, | ||
name: String(fieldPath), | ||
onChange: this.updateField.bind(this, fieldPath), | ||
onBlur: this.blurField.bind(this, fieldPath), | ||
}; | ||
} | ||
this.fieldsWithHandlers.set(field, result); | ||
return result; | ||
}; | ||
@@ -454,3 +454,3 @@ private updateField<Key extends keyof Fields>( | ||
if (!isArray(validate)) { | ||
if (!Array.isArray(validate)) { | ||
// eslint-disable-next-line consistent-return | ||
@@ -457,0 +457,0 @@ return; |
@@ -5,8 +5,6 @@ export function mapObject<Input, Output>( | ||
) { | ||
return Object.keys(input) | ||
.map(key => [key, input[key]]) | ||
.reduce((accumulator: any, [key, value]) => { | ||
accumulator[key] = mapper(value, key as keyof Input); | ||
return accumulator; | ||
}, {}) as Output; | ||
return Object.entries(input).reduce((accumulator: any, [key, value]) => { | ||
accumulator[key] = mapper(value, key as keyof Input); | ||
return accumulator; | ||
}, {}) as Output; | ||
} | ||
@@ -31,1 +29,65 @@ | ||
} | ||
export function set<InputType extends Object>( | ||
rootObject: InputType, | ||
path: string[], | ||
value: any, | ||
) { | ||
if (path.length === 0) { | ||
return rootObject; | ||
} else if (path.length === 1) { | ||
return { | ||
...(rootObject as any), | ||
[path[0]]: value, | ||
}; | ||
} else { | ||
const [current, ...rest] = path; | ||
return { | ||
...(rootObject as any), | ||
[current]: set(rootObject[current], rest, value), | ||
} as InputType; | ||
} | ||
} | ||
export function isEqual(value: any, baseline: any) { | ||
if (value === baseline) { | ||
return true; | ||
} | ||
if (typeof value !== typeof baseline) { | ||
return false; | ||
} | ||
if (Array.isArray(value)) { | ||
if (!Array.isArray(baseline)) { | ||
return false; | ||
} | ||
if (value.length !== baseline.length) { | ||
return false; | ||
} | ||
for (let iter = 0; iter < value.length; iter++) { | ||
if (!isEqual(value[iter], baseline[iter])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
if (typeof value === 'object') { | ||
if (value === null) { | ||
return baseline === null; | ||
} | ||
if (baseline === null) { | ||
return false; | ||
} | ||
const keysInValue = Object.keys(value); | ||
const keysInBaseline = Object.keys(baseline); | ||
if (!isEqual(keysInValue, keysInBaseline)) { | ||
return false; | ||
} | ||
for (const key of keysInValue) { | ||
if (!isEqual(value[key], baseline[key])) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
return false; | ||
} |
@@ -1,3 +0,1 @@ | ||
import toString from 'lodash/toString'; | ||
import isArray from 'lodash/isArray'; | ||
import {mapObject} from './utilities'; | ||
@@ -56,3 +54,3 @@ | ||
if (!isArray(validate)) { | ||
if (!Array.isArray(validate)) { | ||
// eslint-disable-next-line consistent-return | ||
@@ -183,2 +181,9 @@ return; | ||
function toString(obj) { | ||
if (obj == null) { | ||
return ''; | ||
} | ||
return obj.toString(); | ||
} | ||
export default validators; |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
174845
2.28%2
-50%3819
3.64%- Removed
- Removed
- Removed
- Removed