UNPKG

react-form-tools

Version:

Form components with validation for React + Baobab

317 lines (264 loc) 9.77 kB
'use strict'; 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; }; var _react = require('react'); var _react2 = _interopRequireDefault(_react); var _lodash = require('lodash'); var _lodash2 = _interopRequireDefault(_lodash); var _yupValidationStrategy = require('yup-validation-strategy'); var _yupValidationStrategy2 = _interopRequireDefault(_yupValidationStrategy); var _baobabPropTypes = require('baobab-prop-types'); var _baobabPropTypes2 = _interopRequireDefault(_baobabPropTypes); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } exports.default = _react2.default.createClass({ displayName: 'form', propTypes: { onSubmit: _react2.default.PropTypes.func, onInvalidSubmit: _react2.default.PropTypes.func, cursor: _baobabPropTypes2.default.cursor.isRequired, // TODO: concretize type validationSchema: _react2.default.PropTypes.any.isRequired, strategy: _react2.default.PropTypes.object.isRequired, formStateCursor: _baobabPropTypes2.default.cursor, validateOnFly: _react2.default.PropTypes.bool, useHtmlForm: _react2.default.PropTypes.bool, className: _react2.default.PropTypes.string, style: _react2.default.PropTypes.object }, childContextTypes: { form: _react2.default.PropTypes.object }, contextTypes: { form: _react2.default.PropTypes.object }, subscribers: [], _isHtmlForm: null, getDefaultProps: function getDefaultProps() { return { validateOnFly: true, strategy: (0, _yupValidationStrategy2.default)(), onSubmit: _lodash2.default.identity, onInvalidSubmit: _lodash2.default.identity, useHtmlForm: true }; }, getChildContext: function getChildContext() { return { form: { parentForm: this.context.form, isHtmlForm: this.isHtmlForm, cursor: this.props.cursor, isValid: this.isValid, isDirty: this.isDirty, getValidationErrors: this.getValidationErrors, setDirtyState: this.setDirtyState, setPristineState: this.setPristineState, submit: this.submit, validate: this.validate, subscribe: this.subscribe, unsubscribe: this.unsubscribe } }; }, getInitialState: function getInitialState() { if (this.props.formStateCursor) { return {}; } return { errors: {}, dirtyStates: {}, isFormDirty: false }; }, componentDidMount: function componentDidMount() { if (this.props.validateOnFly) { this.props.cursor.on('update', this.onUpdate); } this.validate(); }, componentWillUnmount: function componentWillUnmount() { if (this.props.validateOnFly) { this.props.cursor.off('update', this.onUpdate); } }, render: function render() { var props = _lodash2.default.pick(this.props, ['className', 'style']); if (this.isHtmlForm()) { return _react2.default.createElement( 'form', _extends({ noValidate: true }, props, { onSubmit: this.onFormSubmit }), this.props.children ); } return _react2.default.createElement( 'div', props, this.props.children ); }, hasParentHtmlForm: function hasParentHtmlForm() { var parentForm = this.context.form; while (parentForm) { if (parentForm.isHtmlForm()) { return true; } parentForm = parentForm.parentForm; } }, isHtmlForm: function isHtmlForm() { if (this._isHtmlForm === null) { this._isHtmlForm = this.props.useHtmlForm && !this.hasParentHtmlForm(); } return this._isHtmlForm; }, publish: function publish() { for (var _len = arguments.length, args = Array(_len), _key = 0; _key < _len; _key++) { args[_key] = arguments[_key]; } _lodash2.default.each(this.subscribers, function (subscriber) { return subscriber.apply(undefined, args); }); }, subscribe: function subscribe(subscriber) { this.subscribers = _lodash2.default.concat(this.subscribers, subscriber); // Notify new subscriber about initial form state subscriber(this.getFormState(), null); }, unsubscribe: function unsubscribe(subscriber) { this.subscribers = _lodash2.default.without(this.subscribers, subscriber); }, onFormStateUpdate: function onFormStateUpdate(data, previousData) { // Notify subscribers about changed data only if (_lodash2.default.isEqual(data, previousData)) { return; } this.publish(data, previousData); }, setFormState: function setFormState(nextState) { var _this = this; // It is necessary because validation strategy is asynchronous and validation's // callback might be called after component unmount if (!this.isMounted()) { return; } var prevState = this.getFormState(); if (this.props.formStateCursor) { this.props.formStateCursor.once('update', function (_ref) { var data = _ref.data; return _this.onFormStateUpdate(data.currentData, prevState); }); this.props.formStateCursor.merge(nextState); } else { this.setState(nextState, function () { return _this.onFormStateUpdate(_this.state, prevState); }); } }, getFormState: function getFormState() { if (this.props.formStateCursor) { return this.props.formStateCursor.get(); } return this.state; }, onFormSubmit: function onFormSubmit(event) { event.preventDefault(); event.stopPropagation(); return this.submit(); }, onUpdate: function onUpdate() { this.validate(); }, submit: function submit() { return this.validate(this.props.onSubmit, this.props.onInvalidSubmit); }, getFormData: function getFormData() { return this.props.cursor.get(); }, validate: function validate(successCallback, errorCallback) { var _this2 = this; var data = this.getFormData(); var schema = _lodash2.default.isFunction(this.props.validationSchema) ? this.props.validationSchema(data) : this.props.validationSchema; this.props.strategy.validate(data, schema, {}, function (errors) { _this2.setFormState({ errors: errors }); if (_lodash2.default.isEmpty(errors)) { if (successCallback) { return successCallback(data); } } else { if (errorCallback) { return errorCallback(errors); } } }); }, getValidationErrors: function getValidationErrors(fieldPath) { var formState = this.getFormState(); if (fieldPath) { return _lodash2.default.get(formState.errors, fieldPath); } return formState.errors; }, isValid: function isValid(fieldPath) { var formState = this.getFormState(); if (fieldPath) { return !_lodash2.default.get(formState.errors, fieldPath); } return _lodash2.default.isEmpty(formState.errors); }, isDirty: function isDirty(fieldPath) { var formState = this.getFormState(); var isFormDirty = formState.isFormDirty; if (isFormDirty) { return true; } if (!fieldPath) { return !_lodash2.default.isEmpty(formState.dirtyStates); } return !!_lodash2.default.get(formState.dirtyStates, fieldPath); }, resetValidationErrors: function resetValidationErrors() { this.setValidationErrors({}); }, setValidationErrors: function setValidationErrors(errors) { this.setFormState({ errors: errors }); }, setDirtyState: function setDirtyState(fieldPath) { if (!fieldPath) { this.setFormState({ dirtyStates: {}, isFormDirty: true }); return; } this.updateDirtyState(fieldPath, true); }, setPristineState: function setPristineState(fieldPath) { if (!fieldPath) { this.setFormState({ dirtyStates: {}, isFormDirty: false }); return; } this.updateDirtyState(fieldPath, false); }, updateDirtyState: function updateDirtyState(fieldPath, dirtyState) { if (this.isDirty(fieldPath) === dirtyState) { return; } var _getFormState = this.getFormState(); var dirtyStates = _getFormState.dirtyStates; dirtyStates = _lodash2.default.cloneDeep(dirtyStates || {}); _lodash2.default.set(dirtyStates, fieldPath, dirtyState); this.setFormState({ dirtyStates: dirtyStates }); } });