a-plus-forms
Advanced tools
Comparing version 0.5.4 to 0.6.0
@@ -61,5 +61,21 @@ 'use strict'; | ||
// default form layout | ||
var FormLayout = function FormLayout(_ref2) { | ||
var error = _ref2.error, | ||
input = _ref2.input; | ||
return _react2.default.cloneElement(input, { | ||
error: error && _react2.default.createElement( | ||
'small', | ||
{ className: 'error' }, | ||
error | ||
) | ||
}); | ||
}; | ||
exports.default = { | ||
DefaultValidator: DefaultValidator, | ||
formLayout: FormLayout, | ||
defaultLayout: DefaultLayout | ||
}; |
@@ -15,5 +15,30 @@ 'use strict'; | ||
var ValidationError = function (_Error) { | ||
_inherits(ValidationError, _Error); | ||
function _extendableBuiltin(cls) { | ||
function ExtendableBuiltin() { | ||
var instance = Reflect.construct(cls, Array.from(arguments)); | ||
Object.setPrototypeOf(instance, Object.getPrototypeOf(this)); | ||
return instance; | ||
} | ||
ExtendableBuiltin.prototype = Object.create(cls.prototype, { | ||
constructor: { | ||
value: cls, | ||
enumerable: false, | ||
writable: true, | ||
configurable: true | ||
} | ||
}); | ||
if (Object.setPrototypeOf) { | ||
Object.setPrototypeOf(ExtendableBuiltin, cls); | ||
} else { | ||
ExtendableBuiltin.__proto__ = cls; | ||
} | ||
return ExtendableBuiltin; | ||
} | ||
var ValidationError = function (_extendableBuiltin2) { | ||
_inherits(ValidationError, _extendableBuiltin2); | ||
function ValidationError(errors) { | ||
@@ -29,3 +54,3 @@ _classCallCheck(this, ValidationError); | ||
return ValidationError; | ||
}(Error); | ||
}(_extendableBuiltin(Error)); | ||
@@ -40,6 +65,6 @@ exports.default = ValidationError; | ||
var error = propsError || APFError[name]; | ||
var error = propsError == null ? APFError[name] : propsError; // eslint-disable-line | ||
if (error && typeof error !== 'string') { | ||
// nested errors | ||
if (error != null && typeof error !== 'string') { | ||
// eslint-disable-line | ||
var nestedErrors = error; | ||
@@ -51,10 +76,6 @@ | ||
// filter out the existing nested fields | ||
var names = Object.keys(field.stateManager.getValue() || {}); | ||
var _field$stateManager$s = field.stateManager.strategy.fields, | ||
_fields = _field$stateManager$s === undefined ? [] : _field$stateManager$s; | ||
for (var i = 0; i < _fields.length; i++) { | ||
var _name = _fields[i].name; | ||
if (_name) delete nestedErrors[_name]; | ||
for (var i = 0; i < names.length; i++) { | ||
delete nestedErrors[names[i]]; | ||
} | ||
@@ -61,0 +82,0 @@ } |
@@ -7,4 +7,2 @@ 'use strict'; | ||
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 _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; | ||
@@ -36,4 +34,2 @@ | ||
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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } | ||
@@ -62,3 +58,3 @@ | ||
_this.stateManager = new _state2.default(_this, { nested: options.nested }); | ||
_this.stateManager = new _state2.default(_this); | ||
return _this; | ||
@@ -80,11 +76,7 @@ } | ||
value: function componentWillMount() { | ||
this.checkForNewValueIn(this.props, true); | ||
if (this.context.APFState) { | ||
this.context.APFState.register(this); | ||
} | ||
if ('value' in this.props) { | ||
this.stateManager.value = this.props.value; | ||
} else if ('defaultValue' in this.props) { | ||
this.stateManager.value = this.props.defaultValue; | ||
} | ||
} | ||
@@ -94,4 +86,2 @@ }, { | ||
value: function componentWillUnmount() { | ||
this.isUnmounted = true; | ||
if (this.context.APFState) { | ||
@@ -104,7 +94,14 @@ this.context.APFState.unregister(this); | ||
value: function componentWillReceiveProps(props) { | ||
this.checkForNewValueIn(props, false); | ||
} | ||
}, { | ||
key: 'checkForNewValueIn', | ||
value: function checkForNewValueIn(props, isInitialCall) { | ||
if ('value' in props) { | ||
this.value = props.value; | ||
this.stateManager.setValue(props.value); | ||
} else if ('defaultValue' in props) { | ||
if (JSON.stringify(props.defaultValue) !== JSON.stringify(this.props.defaultValue)) { | ||
this.stateManager.value = props.defaultValue; | ||
// something was changed or an initial call | ||
if (isInitialCall || this.props.defaultValue !== props.defaultValue) { | ||
var triggerOnChange = !isInitialCall; | ||
this.stateManager.setValue(props.defaultValue, triggerOnChange); | ||
} | ||
@@ -114,28 +111,9 @@ } | ||
}, { | ||
key: 'propagateChange', | ||
value: function propagateChange(value) { | ||
var APFState = this.context.APFState; | ||
var _props = this.props, | ||
name = _props.name, | ||
onChange = _props.onChange; | ||
onChange(value); | ||
if (APFState && name) { | ||
var parentField = APFState.strategy.component; | ||
var parentValue = parentField.value; | ||
parentField.propagateChange(_extends({}, parentValue, _defineProperty({}, name, value))); | ||
} | ||
} | ||
}, { | ||
key: 'render', | ||
value: function render() { | ||
var _props2 = this.props, | ||
defaultValue = _props2.defaultValue, | ||
error = _props2.error, | ||
dirty = _props2.dirty, | ||
props = _objectWithoutProperties(_props2, ['defaultValue', 'error', 'dirty']); // eslint-disable-line | ||
var _props = this.props, | ||
defaultValue = _props.defaultValue, | ||
error = _props.error, | ||
dirty = _props.dirty, | ||
props = _objectWithoutProperties(_props, ['defaultValue', 'error', 'dirty']); // eslint-disable-line | ||
@@ -160,9 +138,6 @@ Object.assign(props, { value: this.value, onChange: this.onChange }); | ||
get: function get() { | ||
return this.stateManager.value; | ||
return this.stateManager.getValue(); | ||
}, | ||
set: function set(value) { | ||
if (this.stateManager.value !== value) { | ||
this.stateManager.value = value; | ||
this.propagateChange(value); | ||
} | ||
this.stateManager.setValue(value); | ||
} | ||
@@ -169,0 +144,0 @@ }, { |
@@ -42,4 +42,13 @@ 'use strict'; | ||
var StateContainer = (0, _field2.default)({ layout: null, nested: true })(function (_ref) { | ||
var children = _ref.children; | ||
return children; | ||
var children = _ref.children, | ||
error = _ref.error; | ||
var output = _react2.default.Children.toArray(children); | ||
if (error != null) { | ||
// eslint-disable-line | ||
output.unshift(_react2.default.cloneElement(error, { key: 'errors' })); | ||
} | ||
return output; | ||
}); | ||
@@ -154,3 +163,4 @@ var isPromisish = function isPromisish(smth) { | ||
children = _props.children, | ||
defaultValue = _props.defaultValue; | ||
defaultValue = _props.defaultValue, | ||
className = _props.className; | ||
var _state = this.state, | ||
@@ -163,13 +173,14 @@ errors = _state.errors, | ||
return _react2.default.createElement( | ||
StateContainer, | ||
{ | ||
dirty: dirty, | ||
error: errors, | ||
defaultValue: defaultValue, | ||
onChange: this.onChange, | ||
ref: this.setStateRef | ||
}, | ||
'form', | ||
{ onSubmit: this.onSubmit, className: className, noValidate: true, disabled: disabled }, | ||
_react2.default.createElement( | ||
'form', | ||
{ onSubmit: this.onSubmit, noValidate: true, disabled: disabled }, | ||
StateContainer, | ||
{ | ||
dirty: dirty, | ||
error: errors, | ||
defaultValue: defaultValue, | ||
onChange: this.onChange, | ||
layout: _config2.default.formLayout, | ||
ref: this.setStateRef | ||
}, | ||
children | ||
@@ -176,0 +187,0 @@ ) |
@@ -15,98 +15,59 @@ 'use strict'; | ||
/* eslint no-use-before-define: off */ | ||
var StateManager = function () { | ||
function StateManager(component, _ref) { | ||
var nested = _ref.nested; | ||
function StateManager(element) { | ||
_classCallCheck(this, StateManager); | ||
this.strategy = new (nested ? NestedStateStrategy : ReactStateStrategy)(component); | ||
this.element = element; | ||
} | ||
_createClass(StateManager, [{ | ||
key: 'register', | ||
value: function register(field) { | ||
if (this.strategy instanceof NestedStateStrategy) { | ||
this.strategy.register(field); | ||
} | ||
} | ||
}, { | ||
key: 'unregister', | ||
value: function unregister(field) { | ||
if (this.strategy instanceof NestedStateStrategy) { | ||
this.strategy.unregister(field); | ||
} | ||
} | ||
}, { | ||
key: 'value', | ||
get: function get() { | ||
return this.strategy.value; | ||
}, | ||
set: function set(value) { | ||
this.strategy.value = value; | ||
} | ||
}]); | ||
// actual set value that allows to swtich off onChange data propagation | ||
return StateManager; | ||
}(); | ||
// a generic input field state strategy | ||
_createClass(StateManager, [{ | ||
key: 'setValue', | ||
value: function setValue(value) { | ||
var propagate = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; | ||
var _element$props = this.element.props, | ||
name = _element$props.name, | ||
onChange = _element$props.onChange; | ||
var parent = this.element.context.APFState; | ||
/* eslint no-use-before-define: off */ | ||
exports.default = StateManager; | ||
var ReactStateStrategy = function () { | ||
function ReactStateStrategy(component) { | ||
_classCallCheck(this, ReactStateStrategy); | ||
this.component = component; | ||
this.component.state = { value: undefined }; | ||
} | ||
_createClass(ReactStateStrategy, [{ | ||
key: 'value', | ||
get: function get() { | ||
return this.component.state.value; | ||
}, | ||
set: function set(value) { | ||
if (!this.component.isUnmounted) { | ||
this.component.setState({ value: value }); | ||
if (parent !== undefined && name !== undefined) { | ||
var parentValue = parent.getValue() || {}; | ||
if (parentValue[name] !== value) { | ||
var newValue = Object.freeze(_extends({}, parentValue, _defineProperty({}, name, value))); | ||
if (propagate) onChange(newValue); | ||
parent.setValue(newValue, propagate); | ||
} | ||
} else if (this.currentValue !== value) { | ||
this.currentValue = value; | ||
if (propagate) onChange(value); | ||
this.element.forceUpdate(); // re-render with the new value | ||
} | ||
} | ||
}]); | ||
}, { | ||
key: 'getValue', | ||
value: function getValue() { | ||
var name = this.element.props.name; | ||
var parent = this.element.context.APFState; | ||
return ReactStateStrategy; | ||
}(); | ||
// a compount input state strategy | ||
// NOTE: a nested field can receive initial values _before_ sub-fields | ||
// start to register. which, will create a un-sync situation | ||
// to solve the problem, nested field strategy saves any incoming values | ||
// in the `seedValues` property and then pipes them into fields as they | ||
// register | ||
if (parent !== undefined && name !== undefined) { | ||
var parentValue = parent.getValue() || {}; | ||
return parentValue[name]; | ||
} | ||
var NestedStateStrategy = function () { | ||
function NestedStateStrategy(component) { | ||
_classCallCheck(this, NestedStateStrategy); | ||
this.fields = []; | ||
this.seedValues = {}; | ||
this.component = component; | ||
} | ||
_createClass(NestedStateStrategy, [{ | ||
return this.currentValue; | ||
} | ||
}, { | ||
key: 'register', | ||
value: function register(field) { | ||
this.fields.push(field); | ||
var name = field.props.name; | ||
if (!this.component.isUnmounted) { | ||
this.component.forceUpdate(); // re-render in case of errors were re-picked up | ||
} | ||
var currentValue = this.getValue() || {}; | ||
if (field.name && field.name in this.seedValues) { | ||
field.stateManager.value = this.seedValues[field.name]; | ||
delete this.seedValues[field.name]; | ||
if (!(name in currentValue)) { | ||
this.setValue(_extends({}, currentValue, _defineProperty({}, name, undefined)), false); | ||
} | ||
@@ -117,28 +78,16 @@ } | ||
value: function unregister(field) { | ||
this.fields.splice(this.fields.indexOf(field), 1); | ||
} | ||
}, { | ||
key: 'value', | ||
get: function get() { | ||
return this.fields.reduce(function (data, field) { | ||
return Object.assign(data, field.name ? _defineProperty({}, field.name, field.value) : {}); | ||
}, {}); | ||
}, | ||
set: function set(data) { | ||
var _this = this; | ||
var name = field.props.name; | ||
if (this.fields.length === 0) { | ||
this.seedValues = _extends({}, data); // stashing the initial value | ||
if (name !== undefined) { | ||
var newValue = _extends({}, this.getValue()); | ||
delete newValue[name]; | ||
this.setValue(Object.freeze(newValue)); | ||
} | ||
Object.keys(data || {}).forEach(function (name) { | ||
var field = _this.fields.find(function (field) { | ||
return field.name === name; | ||
}); | ||
if (field) field.value = data[name]; | ||
}); | ||
} | ||
}]); | ||
return NestedStateStrategy; | ||
}(); | ||
return StateManager; | ||
}(); | ||
exports.default = StateManager; |
{ | ||
"name": "a-plus-forms", | ||
"version": "0.5.4", | ||
"version": "0.6.0", | ||
"description": "A+ forms. Would use again", | ||
@@ -41,2 +41,3 @@ "files": [ | ||
"babel-eslint": "8.0.1", | ||
"babel-plugin-transform-builtin-extend": "^1.1.2", | ||
"babel-plugin-transform-decorators-legacy": "^1.3.4", | ||
@@ -43,0 +44,0 @@ "babel-preset-env": "^1.6.0", |
98560
28
1526