react-form-controlled
Version:
Intuitive react forms for building powerful applications
378 lines (307 loc) • 9.54 kB
JavaScript
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; };
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
import React, { createElement } from 'react';
import PropTypes from 'prop-types';
import get from 'lodash/get';
import isNumber from 'lodash/isNumber';
import Element from './Element';
import set from './utils/set';
import traverse from './utils/traverse';
import Input from './Input';
import Select from './Select';
import Textarea from './Textarea';
function isEmpty(value) {
return typeof value === 'undefined' || value === null || value === '';
}
export default class Fieldset extends Element {
constructor(...args) {
super(...args);
this.registeredChildren = [];
}
getTotals() {
const totals = [];
if (typeof this.props.total !== 'undefined') {
totals.push(this.props.total);
}
const parent = this.getParent();
if (!parent) {
return totals;
}
const parentTotals = parent.getTotals();
return [...totals, ...parentTotals];
}
getIndexes() {
const indexes = [];
if (typeof this.props.index !== 'undefined') {
indexes.push(this.props.index);
}
const parent = this.getParent();
if (!parent) {
return indexes;
}
const parentIndexes = parent.getIndexes();
return [...indexes, ...parentIndexes];
}
setValue(value, component, notifyChildren) {
super.setValue(value, component, notifyChildren);
if (notifyChildren) {
this.notifyChildren();
}
}
originalValueChanged() {
super.originalValueChanged();
this.notifyChildren();
}
notifyChildren() {
const { registeredChildren } = this;
registeredChildren.forEach(child => child.originalValueChanged());
}
registerChild(child, name) {
if (name && name[0] === '.') {
const parent = this.getParent();
parent.registerChild(child, name.substr(1));
return;
}
this.registeredChildren.push(child);
}
unregisterChild(child, name) {
if (name && name[0] === '.') {
const parent = this.getParent();
parent.unregisterChild(child, name.substr(1));
return;
}
const pos = this.registeredChildren.indexOf(child);
if (pos !== -1) {
this.registeredChildren.splice(pos, 1);
}
}
getChildContext() {
return {
fieldset: this
};
}
remove(index) {
var _this = this;
return _asyncToGenerator(function* () {
if (typeof index === 'undefined') {
const parent = _this.getParent();
return parent.remove(_this.getCurrentIndex());
}
const value = _this.getValue();
if (!Array.isArray(value) || index < 0 || value.length <= index) {
return undefined;
}
_this.setValue([...value.slice(0, index), ...value.slice(index + 1)]);
return index;
})();
}
up(index) {
var _this2 = this;
return _asyncToGenerator(function* () {
if (typeof index === 'undefined') {
const parent = _this2.getParent();
return parent.up(_this2.getCurrentIndex());
}
const value = _this2.getValue();
if (!Array.isArray(value) || index <= 0 || value.length <= index) {
return undefined;
}
_this2.setValue([...value.slice(0, index - 1), value[index], value[index - 1], ...value.slice(index + 1)]);
return index;
})();
}
getCurrentIndex() {
const { name } = this.props;
if (name === undefined) {
throw new Error('This is not an array');
}
const indexNumber = Number(name);
if (indexNumber.toString() !== name.toString() || !isNumber(indexNumber)) {
throw new Error(`Index ${indexNumber} is not a number`);
}
return indexNumber;
}
down(index) {
var _this3 = this;
return _asyncToGenerator(function* () {
if (typeof index === 'undefined') {
const parent = _this3.getParent();
return parent.down(_this3.getCurrentIndex());
}
const retVar = _this3.up(index + 1);
return typeof retVar === 'undefined' ? retVar : index;
})();
}
// return current or parent fieldset
resolveByPath(path, callback) {
if (path[0] === '.') {
const subPath = path.substr(1);
if (isEmpty(subPath)) {
return callback(null, this, subPath);
}
const parent = this.getParent();
return parent.resolveByPath(subPath, callback);
}
return callback(null, this, path);
}
getChildValue(path) {
if (isEmpty(path)) {
return this.getValue();
}
return this.resolveByPath(path, (err, current, subPath) => {
if (err) {
throw err;
}
const value = current.getValue();
if (isEmpty(subPath)) {
return value;
}
return get(value, subPath);
});
}
setChildValue(path, value, component) {
this.resolveByPath(path, (err, current, subPath) => {
if (err) {
throw err;
}
let newValue = value;
if (!isEmpty(subPath)) {
let currentValue = current.getValue();
// current value can be null or undefined
if (!currentValue) {
const firstChar = subPath[0];
const isCharNumber = Number(firstChar).toString() === firstChar;
currentValue = isCharNumber ? [] : {};
}
newValue = set(currentValue, subPath, value);
}
current.setValue(newValue, component);
const { onChange } = current.props;
if (onChange) {
onChange(newValue, component);
}
});
}
buildPath(path) {
return this.resolveByPath(path, (err, current, subPath) => {
if (err) {
throw err;
}
const currentPath = current.getPath();
if (isEmpty(subPath)) {
return currentPath;
}
return currentPath ? `${currentPath}.${subPath}` : subPath;
});
}
disableSmartUpdate(name) {
if (!name || name[0] !== '.' || name === '.') {
return;
}
this.smartUpdate = false;
const parent = this.getParent();
if (!parent) {
return;
}
parent.disableSmartUpdate(name.substr(1));
}
replaceChildren(children) {
const { skipReplace } = this.getForm().props;
if (skipReplace) {
return children;
}
return traverse(children, null, child => {
if (child.props && child.props.skipReplace) {
return undefined;
}
const childChildren = child.props && child.props.children || child.children;
if (child.type === 'input') {
return React.createElement(
Input,
child.props,
childChildren
);
} else if (child.type === 'select') {
return React.createElement(
Select,
child.props,
childChildren
);
} else if (child.type === 'textarea') {
return React.createElement(
Textarea,
child.props,
childChildren
);
} else if (child.type === 'fieldset' && child.props.name !== undefined) {
return React.createElement(
Fieldset,
child.props,
childChildren
);
} else if (child.type === 'tbody' && child.props.name !== undefined) {
return React.createElement(
Fieldset,
_extends({}, child.props, { tagName: 'tbody' }),
childChildren
);
}
return undefined;
});
}
processChildren(children) {
const value = this.getValue();
const { render } = this.props;
if (typeof render === 'function') {
return this.replaceChildren(render({ value }));
}
const path = this.getPath();
const { skipMap } = this.props;
if (Array.isArray(value) && !skipMap) {
const childrenOnly = this.props.tagName === 'tbody';
return value.map((item, index) => {
const uniqueKey = `${path}.${index}`;
return React.createElement(
Fieldset,
{
name: index,
key: uniqueKey,
total: value.length,
childrenOnly: childrenOnly
},
children
);
});
}
return this.replaceChildren(children);
}
render() {
const children = this.processChildren(this.props.children);
const { tagName = 'fieldset', className, style, childrenOnly } = this.props;
if (childrenOnly) {
return children;
}
return createElement(tagName, {
className,
style,
'data-path': this.getPath()
}, children);
}
}
Fieldset.propTypes = _extends({}, Element.propTypes, {
onChange: PropTypes.func,
index: PropTypes.number,
total: PropTypes.number,
children: PropTypes.node,
tagName: PropTypes.string,
childrenOnly: PropTypes.bool,
children: PropTypes.node,
sameChildren: PropTypes.bool
});
Fieldset.childContextTypes = {
fieldset: PropTypes.object.isRequired
};
Fieldset.contextTypes = {
fieldset: PropTypes.object
};
//# sourceMappingURL=Fieldset.js.map