himanshu-react-jsonschema-form
Version:
A simple React component capable of building HTML forms out of a JSON schema.
566 lines (503 loc) • 21.7 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
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 _utils = require("../../utils");
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: 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; }
function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function, not " + typeof superClass); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }
function _objectWithoutProperties(obj, keys) { var target = {}; for (var i in obj) { if (keys.indexOf(i) >= 0) continue; if (!Object.prototype.hasOwnProperty.call(obj, i)) continue; target[i] = obj[i]; } return target; }
function ArrayFieldTitle(_ref) {
var TitleField = _ref.TitleField,
idSchema = _ref.idSchema,
title = _ref.title,
required = _ref.required;
if (!title) {
// See #312: Ensure compatibility with old versions of React.
return _react2.default.createElement("div", null);
}
var id = idSchema.$id + "__title";
return _react2.default.createElement(TitleField, { id: id, title: title, required: required });
}
function ArrayFieldDescription(_ref2) {
var DescriptionField = _ref2.DescriptionField,
idSchema = _ref2.idSchema,
description = _ref2.description;
if (!description) {
// See #312: Ensure compatibility with old versions of React.
return _react2.default.createElement("div", null);
}
var id = idSchema.$id + "__description";
return _react2.default.createElement(DescriptionField, { id: id, description: description });
}
function IconBtn(props) {
var _props$type = props.type,
type = _props$type === undefined ? "default" : _props$type,
icon = props.icon,
className = props.className,
otherProps = _objectWithoutProperties(props, ["type", "icon", "className"]);
return _react2.default.createElement(
"button",
_extends({ type: "button", className: "btn btn-" + type + " " + className }, otherProps),
_react2.default.createElement("i", { className: "glyphicon glyphicon-" + icon })
);
}
var ArrayField = function (_Component) {
_inherits(ArrayField, _Component);
function ArrayField(props) {
_classCallCheck(this, ArrayField);
var _this = _possibleConstructorReturn(this, (ArrayField.__proto__ || Object.getPrototypeOf(ArrayField)).call(this, props));
_this.onAddClick = function (event) {
event.preventDefault();
var items = _this.state.items;
var _this$props = _this.props,
schema = _this$props.schema,
registry = _this$props.registry;
var definitions = registry.definitions;
var itemSchema = schema.items;
if ((0, _utils.isFixedItems)(schema) && (0, _utils.allowAdditionalItems)(schema)) {
itemSchema = schema.additionalItems;
}
_this.asyncSetState({
items: items.concat([(0, _utils.getDefaultFormState)(itemSchema, undefined, definitions)])
});
};
_this.onDropIndexClick = function (index) {
return function (event) {
event.preventDefault();
_this.asyncSetState({
items: _this.state.items.filter(function (_, i) {
return i !== index;
})
}, { validate: true }); // refs #195
};
};
_this.onReorderClick = function (index, newIndex) {
return function (event) {
event.preventDefault();
event.target.blur();
var items = _this.state.items;
_this.asyncSetState({
items: items.map(function (item, i) {
if (i === newIndex) {
return items[index];
} else if (i === index) {
return items[newIndex];
} else {
return item;
}
})
}, { validate: true });
};
};
_this.onChangeForIndex = function (index) {
return function (value) {
_this.asyncSetState({
items: _this.state.items.map(function (item, i) {
return index === i ? value : item;
})
});
};
};
_this.onSelectChange = function (value) {
_this.asyncSetState({ items: value });
};
_this.state = _this.getStateFromProps(props);
return _this;
}
_createClass(ArrayField, [{
key: "componentWillReceiveProps",
value: function componentWillReceiveProps(nextProps) {
this.setState(this.getStateFromProps(nextProps));
}
}, {
key: "getStateFromProps",
value: function getStateFromProps(props) {
var formData = Array.isArray(props.formData) ? props.formData : null;
var definitions = this.props.registry.definitions;
return {
items: (0, _utils.getDefaultFormState)(props.schema, formData, definitions) || []
};
}
}, {
key: "shouldComponentUpdate",
value: function shouldComponentUpdate(nextProps, nextState) {
return (0, _utils.shouldRender)(this, nextProps, nextState);
}
}, {
key: "isItemRequired",
value: function isItemRequired(itemsSchema) {
return itemsSchema.type === "string" && itemsSchema.minLength > 0;
}
}, {
key: "asyncSetState",
value: function asyncSetState(state) {
var _this2 = this;
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { validate: false };
(0, _utils.setState)(this, state, function () {
_this2.props.onChange(_this2.state.items, options);
});
}
}, {
key: "render",
value: function render() {
var _props = this.props,
schema = _props.schema,
uiSchema = _props.uiSchema;
if ((0, _utils.isFilesArray)(schema, uiSchema)) {
return this.renderFiles();
}
if ((0, _utils.isFixedItems)(schema)) {
return this.renderFixedArray();
}
if ((0, _utils.isMultiSelect)(schema)) {
return this.renderMultiSelect();
}
return this.renderNormalArray();
}
}, {
key: "renderNormalArray",
value: function renderNormalArray() {
var _this3 = this;
var _props2 = this.props,
schema = _props2.schema,
uiSchema = _props2.uiSchema,
errorSchema = _props2.errorSchema,
idSchema = _props2.idSchema,
name = _props2.name,
required = _props2.required,
disabled = _props2.disabled,
readonly = _props2.readonly,
autofocus = _props2.autofocus;
var title = schema.title === undefined ? name : schema.title;
var items = this.state.items;
var _props$registry = this.props.registry,
definitions = _props$registry.definitions,
fields = _props$registry.fields;
var TitleField = fields.TitleField,
DescriptionField = fields.DescriptionField;
var itemsSchema = (0, _utils.retrieveSchema)(schema.items, definitions);
var _getUiOptions = (0, _utils.getUiOptions)(uiSchema),
_getUiOptions$addable = _getUiOptions.addable,
addable = _getUiOptions$addable === undefined ? true : _getUiOptions$addable;
return _react2.default.createElement(
"fieldset",
{
className: "field field-array field-array-of-" + itemsSchema.type },
_react2.default.createElement(ArrayFieldTitle, {
TitleField: TitleField,
idSchema: idSchema,
title: title,
required: required }),
schema.description ? _react2.default.createElement(ArrayFieldDescription, {
DescriptionField: DescriptionField,
idSchema: idSchema,
description: schema.description }) : null,
_react2.default.createElement(
"div",
{ className: "row array-item-list" },
items.map(function (item, index) {
var itemErrorSchema = errorSchema ? errorSchema[index] : undefined;
var itemIdPrefix = idSchema.$id + "_" + index;
var itemIdSchema = (0, _utils.toIdSchema)(itemsSchema, itemIdPrefix, definitions);
return _this3.renderArrayFieldItem({
index: index,
canMoveUp: index > 0,
canMoveDown: index < items.length - 1,
itemSchema: itemsSchema,
itemIdSchema: itemIdSchema,
itemErrorSchema: itemErrorSchema,
itemData: items[index],
itemUiSchema: uiSchema.items,
autofocus: autofocus && index === 0
});
})
),
addable ? _react2.default.createElement(AddButton, {
onClick: this.onAddClick,
disabled: disabled || readonly }) : null
);
}
}, {
key: "renderMultiSelect",
value: function renderMultiSelect() {
var _props3 = this.props,
schema = _props3.schema,
idSchema = _props3.idSchema,
uiSchema = _props3.uiSchema,
disabled = _props3.disabled,
readonly = _props3.readonly,
autofocus = _props3.autofocus;
var items = this.state.items;
var _props$registry2 = this.props.registry,
widgets = _props$registry2.widgets,
definitions = _props$registry2.definitions;
var itemsSchema = (0, _utils.retrieveSchema)(schema.items, definitions);
var enumOptions = (0, _utils.optionsList)(itemsSchema);
var _getUiOptions$enumOpt = _extends({}, (0, _utils.getUiOptions)(uiSchema), { enumOptions: enumOptions }),
_getUiOptions$enumOpt2 = _getUiOptions$enumOpt.widget,
widget = _getUiOptions$enumOpt2 === undefined ? "select" : _getUiOptions$enumOpt2,
options = _objectWithoutProperties(_getUiOptions$enumOpt, ["widget"]);
var Widget = (0, _utils.getWidget)(schema, widget, widgets);
return _react2.default.createElement(Widget, {
id: idSchema && idSchema.$id,
multiple: true,
onChange: this.onSelectChange,
options: options,
schema: schema,
value: items,
disabled: disabled,
readonly: readonly,
autofocus: autofocus });
}
}, {
key: "renderFiles",
value: function renderFiles() {
var _props4 = this.props,
schema = _props4.schema,
uiSchema = _props4.uiSchema,
idSchema = _props4.idSchema,
name = _props4.name,
disabled = _props4.disabled,
readonly = _props4.readonly,
autofocus = _props4.autofocus;
var title = schema.title || name;
var items = this.state.items;
var widgets = this.props.registry.widgets;
var _getUiOptions2 = (0, _utils.getUiOptions)(uiSchema),
_getUiOptions2$widget = _getUiOptions2.widget,
widget = _getUiOptions2$widget === undefined ? "files" : _getUiOptions2$widget,
options = _objectWithoutProperties(_getUiOptions2, ["widget"]);
var Widget = (0, _utils.getWidget)(schema, widget, widgets);
return _react2.default.createElement(Widget, {
options: options,
id: idSchema && idSchema.$id,
multiple: true,
onChange: this.onSelectChange,
schema: schema,
title: title,
value: items,
disabled: disabled,
readonly: readonly,
autofocus: autofocus });
}
}, {
key: "renderFixedArray",
value: function renderFixedArray() {
var _this4 = this;
var _props5 = this.props,
schema = _props5.schema,
uiSchema = _props5.uiSchema,
errorSchema = _props5.errorSchema,
idSchema = _props5.idSchema,
name = _props5.name,
required = _props5.required,
disabled = _props5.disabled,
readonly = _props5.readonly,
autofocus = _props5.autofocus;
var title = schema.title || name;
var items = this.state.items;
var _props$registry3 = this.props.registry,
definitions = _props$registry3.definitions,
fields = _props$registry3.fields;
var TitleField = fields.TitleField;
var itemSchemas = schema.items.map(function (item) {
return (0, _utils.retrieveSchema)(item, definitions);
});
var additionalSchema = (0, _utils.allowAdditionalItems)(schema) ? (0, _utils.retrieveSchema)(schema.additionalItems, definitions) : null;
var _getUiOptions3 = (0, _utils.getUiOptions)(uiSchema),
_getUiOptions3$addabl = _getUiOptions3.addable,
addable = _getUiOptions3$addabl === undefined ? true : _getUiOptions3$addabl;
var canAdd = addable && additionalSchema;
if (!items || items.length < itemSchemas.length) {
// to make sure at least all fixed items are generated
items = items || [];
items = items.concat(new Array(itemSchemas.length - items.length));
}
return _react2.default.createElement(
"fieldset",
{ className: "field field-array field-array-fixed-items" },
_react2.default.createElement(ArrayFieldTitle, {
TitleField: TitleField,
idSchema: idSchema,
title: title,
required: required }),
schema.description ? _react2.default.createElement(
"div",
{ className: "field-description" },
schema.description
) : null,
_react2.default.createElement(
"div",
{ className: "row array-item-list" },
items.map(function (item, index) {
var additional = index >= itemSchemas.length;
var itemSchema = additional ? additionalSchema : itemSchemas[index];
var itemIdPrefix = idSchema.$id + "_" + index;
var itemIdSchema = (0, _utils.toIdSchema)(itemSchema, itemIdPrefix, definitions);
var itemUiSchema = additional ? uiSchema.additionalItems || {} : Array.isArray(uiSchema.items) ? uiSchema.items[index] : uiSchema.items || {};
var itemErrorSchema = errorSchema ? errorSchema[index] : undefined;
return _this4.renderArrayFieldItem({
index: index,
canRemove: additional,
canMoveUp: index >= itemSchemas.length + 1,
canMoveDown: additional && index < items.length - 1,
itemSchema: itemSchema,
itemData: item,
itemUiSchema: itemUiSchema,
itemIdSchema: itemIdSchema,
itemErrorSchema: itemErrorSchema,
autofocus: autofocus && index === 0
});
})
),
canAdd ? _react2.default.createElement(AddButton, {
onClick: this.onAddClick,
disabled: disabled || readonly }) : null
);
}
}, {
key: "renderArrayFieldItem",
value: function renderArrayFieldItem(_ref3) {
var index = _ref3.index,
_ref3$canRemove = _ref3.canRemove,
canRemove = _ref3$canRemove === undefined ? true : _ref3$canRemove,
_ref3$canMoveUp = _ref3.canMoveUp,
canMoveUp = _ref3$canMoveUp === undefined ? true : _ref3$canMoveUp,
_ref3$canMoveDown = _ref3.canMoveDown,
canMoveDown = _ref3$canMoveDown === undefined ? true : _ref3$canMoveDown,
itemSchema = _ref3.itemSchema,
itemData = _ref3.itemData,
itemUiSchema = _ref3.itemUiSchema,
itemIdSchema = _ref3.itemIdSchema,
itemErrorSchema = _ref3.itemErrorSchema,
autofocus = _ref3.autofocus;
var SchemaField = this.props.registry.fields.SchemaField;
var _props6 = this.props,
disabled = _props6.disabled,
readonly = _props6.readonly,
uiSchema = _props6.uiSchema;
var _orderable$removable$ = _extends({
orderable: true,
removable: true
}, uiSchema["ui:options"]),
orderable = _orderable$removable$.orderable,
removable = _orderable$removable$.removable;
var has = {
moveUp: orderable && canMoveUp,
moveDown: orderable && canMoveDown,
remove: removable && canRemove
};
has.toolbar = Object.keys(has).some(function (key) {
return has[key];
});
var btnStyle = { flex: 1, paddingLeft: 6, paddingRight: 6, fontWeight: "bold" };
return _react2.default.createElement(
"div",
{ key: index, className: "array-item" },
_react2.default.createElement(
"div",
{ className: has.toolbar ? "col-xs-9" : "col-xs-12" },
_react2.default.createElement(SchemaField, {
schema: itemSchema,
uiSchema: itemUiSchema,
formData: itemData,
errorSchema: itemErrorSchema,
idSchema: itemIdSchema,
required: this.isItemRequired(itemSchema),
onChange: this.onChangeForIndex(index),
registry: this.props.registry,
disabled: this.props.disabled,
readonly: this.props.readonly,
autofocus: autofocus })
),
has.toolbar ? _react2.default.createElement(
"div",
{ className: "col-xs-3 array-item-toolbox" },
_react2.default.createElement(
"div",
{ className: "btn-group", style: { display: "flex", justifyContent: "space-around" } },
has.moveUp || has.moveDown ? _react2.default.createElement(IconBtn, { icon: "arrow-up", className: "array-item-move-up",
tabIndex: "-1",
style: btnStyle,
disabled: disabled || readonly || !has.moveUp,
onClick: this.onReorderClick(index, index - 1) }) : null,
has.moveUp || has.moveDown ? _react2.default.createElement(IconBtn, { icon: "arrow-down", className: "array-item-move-down",
tabIndex: "-1",
style: btnStyle,
disabled: disabled || readonly || !has.moveDown,
onClick: this.onReorderClick(index, index + 1) }) : null,
has.remove ? _react2.default.createElement(IconBtn, { type: "danger", icon: "remove", className: "array-item-remove",
tabIndex: "-1",
style: btnStyle,
disabled: disabled || readonly,
onClick: this.onDropIndexClick(index) }) : null
)
) : null
);
}
}, {
key: "itemTitle",
get: function get() {
var schema = this.props.schema;
return schema.items.title || schema.items.description || "Item";
}
}]);
return ArrayField;
}(_react.Component);
ArrayField.defaultProps = {
uiSchema: {},
idSchema: {},
registry: (0, _utils.getDefaultRegistry)(),
required: false,
disabled: false,
readonly: false,
autofocus: false
};
function AddButton(_ref4) {
var onClick = _ref4.onClick,
disabled = _ref4.disabled;
return _react2.default.createElement(
"div",
{ className: "row" },
_react2.default.createElement(
"p",
{ className: "col-xs-3 col-xs-offset-9 array-item-add text-right" },
_react2.default.createElement(IconBtn, { type: "info", icon: "plus", className: "btn-add col-xs-12",
tabIndex: "0", onClick: onClick,
disabled: disabled })
)
);
}
if (process.env.NODE_ENV !== "production") {
ArrayField.propTypes = {
schema: _react.PropTypes.object.isRequired,
uiSchema: _react.PropTypes.shape({
"ui:options": _react.PropTypes.shape({
addable: _react.PropTypes.bool,
orderable: _react.PropTypes.bool,
removable: _react.PropTypes.bool
})
}),
idSchema: _react.PropTypes.object,
errorSchema: _react.PropTypes.object,
onChange: _react.PropTypes.func.isRequired,
formData: _react.PropTypes.array,
required: _react.PropTypes.bool,
disabled: _react.PropTypes.bool,
readonly: _react.PropTypes.bool,
autofocus: _react.PropTypes.bool,
registry: _react.PropTypes.shape({
widgets: _react.PropTypes.objectOf(_react.PropTypes.oneOfType([_react.PropTypes.func, _react.PropTypes.object])).isRequired,
fields: _react.PropTypes.objectOf(_react.PropTypes.func).isRequired,
definitions: _react.PropTypes.object.isRequired,
formContext: _react.PropTypes.object.isRequired
})
};
}
exports.default = ArrayField;