diff --git a/dist/components/Field.js b/dist/components/Field.js
index c940da7..a67b8f0 100644
--- a/dist/components/Field.js
+++ b/dist/components/Field.js
@@ -18,6 +18,8 @@ var _utilities = require('../helpers/utilities');
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 _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
function _possibleConstructorReturn(self, call) { if (!self) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return call && (typeof call === "object" || typeof call === "function") ? call : self; }
@@ -118,6 +120,8 @@ var Field = function (_React$Component) {
}, {
key: 'render',
value: function render() {
+ var _this2 = this;
+
var childCount = _react2.default.Children.count(this.props.children);
var inputProps = {
name: this.props.name,
@@ -143,8 +147,16 @@ var Field = function (_React$Component) {
'div',
null,
_react2.default.Children.map(this.props.children, function (child) {
- return (0, _utilities.mapPropsToChild)(child, 'input', function () {
- return inputProps;
+ return (0, _utilities.mapPropsToChild)(child, {
+ input: function input() {
+ return inputProps;
+ },
+ valid: function valid() {
+ return (0, _utilities.makePropsForStatus)('valid', _defineProperty({}, _this2.props.name, { valid: _this2.state.valid }));
+ },
+ pristine: function pristine() {
+ return (0, _utilities.makePropsForStatus)('pristine', _defineProperty({}, _this2.props.name, { pristine: _this2.state.pristine }));
+ }
});
})
);
diff --git a/dist/components/Form.js b/dist/components/Form.js
index e7656ed..bec9c82 100644
--- a/dist/components/Form.js
+++ b/dist/components/Form.js
@@ -79,8 +79,15 @@ var Form = function (_React$Component) {
'form',
{ onSubmit: this.onSubmit },
_react2.default.Children.map(this.props.children, function (child) {
- return (0, _utilities.mapPropsToChild)(child, 'Field', function (grandChild) {
- return (0, _utilities.makeFieldProps)(grandChild, _this3.onFieldChange, _this3.state);
+ return (0, _utilities.mapPropsToChild)(child, { Field: function Field(grandChild) {
+ return (0, _utilities.makeFieldProps)(grandChild, _this3.onFieldChange, _this3.state);
+ },
+ pristine: function pristine() {
+ return (0, _utilities.makePropsForStatus)('pristine', _this3.state);
+ },
+ valid: function valid() {
+ return (0, _utilities.makePropsForStatus)('valid', _this3.state);
+ }
});
})
);
diff --git a/dist/helpers/utilities.js b/dist/helpers/utilities.js
index d8e6cea..d254bda 100644
--- a/dist/helpers/utilities.js
+++ b/dist/helpers/utilities.js
@@ -3,13 +3,17 @@
Object.defineProperty(exports, "__esModule", {
value: true
});
+
+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; };
+
exports.assembleValidators = assembleValidators;
exports.updateValidators = updateValidators;
exports.isValid = isValid;
+exports.getValuesOf = getValuesOf;
exports.buildStateForField = buildStateForField;
exports.addFieldsToState = addFieldsToState;
-exports.getValuesOf = getValuesOf;
exports.makeFieldProps = makeFieldProps;
+exports.makePropsForStatus = makePropsForStatus;
exports.mapPropsToChild = mapPropsToChild;
var _react = require('react');
@@ -77,16 +81,24 @@ function isValid(value, validators) {
}, true);
}
+function getValuesOf() {
+ var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
+
+ return Object.keys(obj).map(function (key) {
+ return obj[key];
+ });
+}
+
function buildStateForField(fieldProps) {
- var value = fieldProps.value,
- valid = fieldProps.valid,
- pristine = fieldProps.pristine;
+ var value = fieldProps.value;
- var newState = { value: '', valid: false, pristine: true };
+ var newState = {
+ value: '',
+ valid: isValid(value, getValuesOf(assembleValidators(fieldProps))),
+ pristine: true
+ };
if (value !== undefined) Object.assign(newState, { value: value });
- if (valid !== undefined) Object.assign(newState, { valid: valid });
- if (pristine !== undefined) Object.assign(newState, { pristine: pristine });
return newState;
}
@@ -108,14 +120,6 @@ function addFieldsToState(component, child) {
}
}
-function getValuesOf() {
- var obj = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {};
-
- return Object.keys(obj).map(function (key) {
- return obj[key];
- });
-}
-
function makeFieldProps(child, onChange, state) {
if (typeof child.type === 'function' && child.type.name === 'Field') {
var name = child.props.name;
@@ -128,15 +132,40 @@ function makeFieldProps(child, onChange, state) {
return null;
}
-function mapPropsToChild(child, type, propFunction) {
- if (child.type === type || typeof child.type === 'function' && child.type.name === type) {
- return _react2.default.cloneElement(child, propFunction(child));
+function makePropsForStatus(status, state) {
+ return Object.keys(state).reduce(function (props, field) {
+ if (Object.prototype.hasOwnProperty.call(state[field], status)) {
+ return _extends({}, props, _defineProperty({}, field + '_' + status, state[field][status]));
+ }
+ return props;
+ }, {});
+}
+
+function mapPropsToChild(child, childPropsMap) {
+ var type = typeof child.type === 'function' ? child.type.name : child.type;
+ var childProps = {};
+ var newChildren = void 0;
+
+ if (child.props) {
+ if (childPropsMap.valid && child.props.valid) {
+ Object.assign(childProps, childPropsMap.valid());
+ }
+ if (childPropsMap.pristine && child.props.pristine) {
+ Object.assign(childProps, childPropsMap.pristine());
+ }
+ if (child.props.children) {
+ newChildren = _react2.default.Children.map(child.props.children, function (nestedChild) {
+ return mapPropsToChild(nestedChild, childPropsMap);
+ });
+ }
}
- if (child.props && child.props.children) {
- var newChildren = _react2.default.Children.map(child.props.children, function (nestedChild) {
- return mapPropsToChild(nestedChild, type, propFunction);
- });
- return _react2.default.cloneElement(child, null, newChildren);
+
+ if (childPropsMap.Field && type === 'Field') {
+ return _react2.default.cloneElement(child, _extends({}, childPropsMap.Field(child), childProps), newChildren);
}
- return child;
+ if (childPropsMap.input && type === 'input') {
+ return _react2.default.cloneElement(child, _extends({}, childPropsMap.input(child), childProps), newChildren);
+ }
+
+ return Object.keys(childProps).length || newChildren ? _react2.default.cloneElement(child, childProps, newChildren) : child;
}
\ No newline at end of file
diff --git a/readme.md b/readme.md
index 2ca58cd..620fe1e 100644
--- a/readme.md
+++ b/readme.md
@@ -28,6 +28,7 @@ React-formulize can be used to both quickly compose forms or add validation to e
2. A `Field` component can wrap (nested JSX) an `input` element (or a fragment containing an `input`) and control its underlying state automatically.
3. Pass validator props to the `Field` components. A `Field` component will keep track of its own validity.
4. Pass an `onSubmit` handler to `Form` in order to interact with the submission event. The callback will be passed a clone of the `Form`'s state.
+ 5. Pass `valid` and `pristine` props to any nested child components in either a `Form` or `Field` component. These components will receive information about the `Form`'s status in the format of `${fieldName}_${statusType}` (e.g. name_valid & email_pristine).
#### Example: Composing A New Form With Custom Input Component(s)
```javascript
@@ -112,8 +113,10 @@ The `Form` component is a stateful higher-order-component which wraps presentati
The `Form` component will behave as follows with respect to its children:
1. Any `Field` tag will be passed the state associated with the `Field`'s name (`Form.state[child.props.name]`).
- 2. Any other component or element will be rendered with the props it would otherwise be passed.
- 3. Upon submission, `Form` will pass its `onSubmit` callback a clone of its current state.
+ 2. Any component with a `valid` prop will be passed props stating the validity for all `Field`s in the `Form` (e.g. name_valid).
+ 3. Any component with a `pristine` prop will be passed a props stating the pristine state for all `Field`s in the `Form` (e.g. email_pristine).
+ 4. Any other component or element will be rendered with the props it would otherwise be passed.
+ 5. Upon submission, `Form` will pass its `onSubmit` callback a clone of its current state.
*Note:* The `Form` component should be passed an `onSubmit` handler if you want to interact with the submission event!
@@ -184,7 +187,9 @@ The `Field` component will behave as follows with respect to its children:
2. Any `input` tag will be passed `name`, `type`, `value`, and `onChange` props.
3. If only a single direct child is passed to `Field`, it will be passed all of the relevant input props.
4. If multiple `input` tags are nested in a single `Field`, they would all share a single state (not recommended).
-
+ 5. Any component with a `valid` prop will be passed a prop stating the `Field`'s validity (e.g. name_valid).
+ 6. Any component with a `pristine` prop will be passed a prop stating the `Field`'s pristine state (e.g. email_pristine).
+
*Note:* Only one input element should be nested inside of a `Field` tag (see #4 above).
### Props
diff --git a/src/components/Field.jsx b/src/components/Field.jsx
index 2f44b22..da34e41 100644
--- a/src/components/Field.jsx
+++ b/src/components/Field.jsx
@@ -6,6 +6,7 @@ import {
updateValidators,
getValuesOf,
mapPropsToChild,
+ makePropsForStatus,
} from '../helpers/utilities';
const Field = class extends React.Component {
@@ -112,7 +113,13 @@ const Field = class extends React.Component {
return (