react-jsonschema-form-extras 0.9.67 → 0.9.71

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,402 @@
1
+ import React, { Component } from "react";
2
+ import {
3
+ deepEquals,
4
+ getDefaultFormState
5
+ } from "react-jsonschema-form/lib/utils";
6
+ import PropTypes from "prop-types";
7
+
8
+ import { getFieldName } from "./utils";
9
+
10
+ class CollapseMenuAction extends Component {
11
+ render() {
12
+ let { action, allActions = {} } = this.props;
13
+ if (!action) {
14
+ return null;
15
+ }
16
+ if (typeof action === "string") {
17
+ return <div>{action}</div>;
18
+ } else if (typeof action === "object") {
19
+ const Component = allActions[action.component];
20
+ if (!Component) {
21
+ console.error(
22
+ `Can't find ${action.component} in formContext.allActions`
23
+ );
24
+ return (
25
+ <h2 className="warning bg-error" style={{ color: "red" }}>
26
+ Can't find <b>{action.component}</b> in <b>formContext</b>.<b>allActions</b>
27
+ </h2>
28
+ );
29
+ }
30
+ return <Component {...action.props} />;
31
+ }
32
+ }
33
+ }
34
+
35
+ function CollapseMenu(props) {
36
+ let {
37
+ headerElementsSchemas,
38
+ uiSchema,
39
+ formContext = {},
40
+ formData = {},
41
+ onChange,
42
+ onAdd,
43
+ title,
44
+ name,
45
+ collapsed,
46
+ fields,
47
+ propsOnChange
48
+ } = props;
49
+
50
+ const {
51
+ collapse: {
52
+ collapsibleHeaderElements = {},
53
+ icon: {
54
+ enabled = "glyphicon glyphicon-chevron-down",
55
+ disabled = "glyphicon glyphicon-chevron-right",
56
+ add = "glyphicon glyphicon-plus-sign"
57
+ } = {},
58
+ separate = true,
59
+ addTo,
60
+ wrapClassName = "lead",
61
+ actions = [],
62
+ classNames = "collapsibleHeading",
63
+ collapseDivStyles: {
64
+ textColor = "white",
65
+ background = "linear-gradient(to right, #0472B6, white)",
66
+ collapseGlyphColor = "white",
67
+ addGlyphColor = "white",
68
+ padding = "14px",
69
+ margin = "",
70
+ marginLeft = "-5px",
71
+ marginBottom = "5px",
72
+ zIndex = -1,
73
+ divCursor = "pointer",
74
+ addCursor = "copy"
75
+ } = {}
76
+ }
77
+ } = uiSchema;
78
+
79
+ const handleAdd = event => {
80
+ event.stopPropagation();
81
+ onAdd(event);
82
+ };
83
+
84
+ let headerElements = [];
85
+ let {
86
+ className: headerElementsWrapperClass = "header-element-wrapper"
87
+ } = collapsibleHeaderElements;
88
+
89
+ Object.keys(headerElementsSchemas).map(key => {
90
+ const fieldSchema = headerElementsSchemas[key];
91
+ const fieldName = getFieldName(fieldSchema.type);
92
+
93
+ if (fieldName) {
94
+ let FieldElement = fields[fieldName];
95
+ const fieldId = `${key}`;
96
+ const fieldUiSchema = uiSchema[key];
97
+ const fieldFormData = formData[key];
98
+
99
+ const elementOnChange = (value, options) => {
100
+ formData[key] = value;
101
+ propsOnChange(formData, options);
102
+ };
103
+
104
+ headerElements.push(
105
+ <FieldElement
106
+ formContext={formContext}
107
+ formData={fieldFormData}
108
+ idSchema={{ $id: fieldId }}
109
+ key={key}
110
+ onChange={elementOnChange}
111
+ schema={fieldSchema}
112
+ uiSchema={fieldUiSchema}
113
+ />
114
+ );
115
+ }
116
+ });
117
+
118
+ return (
119
+ <div className={`${wrapClassName}`}>
120
+ <div
121
+ className={classNames}
122
+ onClick={onChange}
123
+ style={{
124
+ padding,
125
+ margin,
126
+ marginLeft,
127
+ marginBottom,
128
+ zIndex,
129
+ cursor: divCursor,
130
+ background
131
+ }}
132
+ >
133
+ <span style={{ color: textColor }}>{title || name}</span>&nbsp;
134
+ {addTo && (
135
+ <a
136
+ onClick={handleAdd}
137
+ style={{ color: addGlyphColor, cursor: addCursor }}
138
+ >
139
+ <i style={{ cursor: addCursor }} className={add} />
140
+ </a>
141
+ )}
142
+ <a>
143
+ <i
144
+ style={{ color: collapseGlyphColor }}
145
+ className={collapsed ? disabled : enabled}
146
+ />
147
+ </a>
148
+ {!!headerElements.length && (
149
+ <div
150
+ className={headerElementsWrapperClass}
151
+ onClick={event => event.stopPropagation()}
152
+ >
153
+ {headerElements}
154
+ </div>
155
+ )}
156
+ {actions.map((action, i) => (
157
+ <CollapseMenuAction
158
+ key={i}
159
+ action={action}
160
+ allActions={formContext.allActions}
161
+ />
162
+ ))}
163
+ </div>
164
+ {separate && <hr />}
165
+ </div>
166
+ );
167
+ }
168
+
169
+ class CollapseLegend extends Component {
170
+ render() {
171
+ let {
172
+ uiSchema: { collapse: { legend } },
173
+ formContext: { legends = {} } = {}
174
+ } = this.props;
175
+ if (!legend) {
176
+ return null;
177
+ }
178
+ if (typeof legend === "string") {
179
+ return <div>{legend}</div>;
180
+ } else if (typeof legend === "object") {
181
+ const Component = legends[legend.component];
182
+ if (!Component) {
183
+ console.error(`Can't find ${legend.components} in formContext.legends`);
184
+ return (
185
+ <h2 className="warning bg-error" style={{ color: "red" }}>
186
+ Can't find <b>{legend.component}</b> in <b>formContext</b>.<b>legends</b>
187
+ </h2>
188
+ );
189
+ }
190
+ return <Component {...legend.props} />;
191
+ }
192
+ return <div>I'm a legend</div>;
193
+ }
194
+ }
195
+
196
+ class CollapsibleField extends Component {
197
+ constructor(props) {
198
+ super(props);
199
+
200
+ let { uiSchema: { collapse: { collapsed = true } = {} } } = props;
201
+
202
+ this.state = { collapsed };
203
+ }
204
+
205
+ appendToArray = (formData = [], newVal) => {
206
+ let { uiSchema: { collapse: { addToBottom = true } = {} } } = this.props;
207
+ if (formData.some(v => deepEquals(v, newVal))) {
208
+ return formData;
209
+ } else {
210
+ // newVal can be either array or a single element, concat flattens value
211
+ if (addToBottom) {
212
+ return formData.concat(newVal);
213
+ } else {
214
+ return [newVal].concat(formData);
215
+ }
216
+ }
217
+ };
218
+
219
+ doAdd = (field, formData, newVal) => {
220
+ if (field === "self") {
221
+ this.props.onChange(this.appendToArray(formData, newVal));
222
+ } else {
223
+ let fieldVal = this.appendToArray(formData[field], newVal);
224
+ let change = Object.assign({}, formData, { [field]: fieldVal });
225
+ this.props.onChange(change);
226
+ }
227
+ };
228
+
229
+ handleAdd = () => {
230
+ this.setState({ collapsed: false });
231
+ this.forceUpdate(() => {
232
+ let {
233
+ schema,
234
+ uiSchema,
235
+ formData,
236
+ registry: { fields },
237
+ formContext
238
+ } = this.props;
239
+ let { collapse: { addTo, addElement } } = uiSchema;
240
+
241
+ let fieldSchema =
242
+ addTo === "self"
243
+ ? schema.items
244
+ : schema.properties
245
+ ? schema.properties[addTo] ? schema.properties[addTo].items : null
246
+ : null;
247
+ if (!fieldSchema) {
248
+ return false;
249
+ }
250
+ let fieldUiSchema = addTo === "self" ? uiSchema : uiSchema[addTo];
251
+ let fieldFormData = addTo === "self" ? formData : formData[addTo];
252
+
253
+ if (addElement) {
254
+ if (typeof addElement === "function") {
255
+ let onSubmit = newVal => {
256
+ this.setState({ AddElement: undefined });
257
+ this.doAdd(addTo, formData, newVal);
258
+ };
259
+ let AddElement = addElement(fieldSchema, fieldUiSchema, onSubmit);
260
+ this.setState({ AddElement });
261
+ } else {
262
+ let FieldElement = fields[addElement];
263
+ let onBlur = newVal => {
264
+ this.setState({ AddElement: undefined });
265
+ this.doAdd(addTo, formData, newVal);
266
+ };
267
+ let AddElement = () => (
268
+ <FieldElement
269
+ schema={fieldSchema}
270
+ uiSchema={fieldUiSchema}
271
+ onChange={formData => {
272
+ onBlur(formData);
273
+ }}
274
+ formContext={formContext}
275
+ formData={fieldFormData}
276
+ />
277
+ );
278
+ this.setState({ AddElement });
279
+ }
280
+ } else {
281
+ let newVal = getDefaultFormState(fieldSchema, {});
282
+ this.doAdd(addTo, formData, newVal);
283
+ }
284
+ });
285
+ };
286
+
287
+ handleCollapsed = () => {
288
+ this.setState(function(state) {
289
+ return { collapsed: !state.collapsed };
290
+ });
291
+ };
292
+
293
+ componentDidCatch(error, errorInfo) {
294
+ // You can also log the error to an error reporting service
295
+ console.log({ error, errorInfo });
296
+ }
297
+
298
+ render() {
299
+ let {
300
+ schema: { title, properties = {} },
301
+ uiSchema,
302
+ registry: { fields },
303
+ idSchema: { $id } = {},
304
+ name,
305
+ formContext,
306
+ formData,
307
+ onChange: propsOnChange
308
+ } = this.props;
309
+ let { collapsed, AddElement } = this.state;
310
+ let { collapse: { collapsibleHeaderElements = {}, field } } = uiSchema;
311
+ let CollapseElement = fields[field];
312
+ <<<<<<< HEAD
313
+
314
+ // uischema retains the value for the state
315
+ =======
316
+ let { elements = [] } = collapsibleHeaderElements;
317
+ // uischema retains the value form the state
318
+ >>>>>>> origin/master
319
+ uiSchema.collapse.collapsed = this.state.collapsed;
320
+
321
+ title = uiSchema["ui:title"] ? uiSchema["ui:title"] : title ? title : name;
322
+ let customizedId = collapsed ? $id : undefined;
323
+
324
+ //remove header elements from the schema
325
+ let headerElementsSchemas = {};
326
+ let propertiesNoHeader = { ...properties };
327
+ let orderNoHeader = uiSchema["ui:order"]
328
+ ? uiSchema["ui:order"].filter(x => elements.indexOf(x) < 0)
329
+ : uiSchema["ui:order"];
330
+
331
+ elements.forEach(key => {
332
+ if (propertiesNoHeader[key]) {
333
+ headerElementsSchemas[key] = propertiesNoHeader[key];
334
+ delete propertiesNoHeader[key];
335
+ }
336
+ });
337
+
338
+ const collapseElementProps = {
339
+ ...this.props,
340
+ schema: { ...this.props.schema, properties: propertiesNoHeader },
341
+ uiSchema: { ...this.props.uiSchema, "ui:order": orderNoHeader }
342
+ };
343
+
344
+ return (
345
+ <div id={customizedId}>
346
+ <CollapseMenu
347
+ headerElementsSchemas={headerElementsSchemas}
348
+ collapsibleFieldId={$id}
349
+ title={title}
350
+ uiSchema={uiSchema}
351
+ collapsed={collapsed}
352
+ formContext={formContext}
353
+ formData={formData}
354
+ fields={fields}
355
+ onAdd={this.handleAdd}
356
+ onChange={this.handleCollapsed}
357
+ propsOnChange={propsOnChange}
358
+ />
359
+ <div className="form-group">
360
+ {AddElement && <AddElement />}
361
+ {!collapsed && <CollapseLegend {...this.props} />}
362
+ {!collapsed && <CollapseElement {...collapseElementProps} />}
363
+ </div>
364
+ </div>
365
+ );
366
+ }
367
+ }
368
+
369
+ CollapsibleField.propTypes = {
370
+ uiSchema: PropTypes.shape({
371
+ collapse: PropTypes.shape({
372
+ field: PropTypes.string.isRequired,
373
+ icon: PropTypes.shape({
374
+ enabled: PropTypes.string,
375
+ disabled: PropTypes.string,
376
+ add: PropTypes.string
377
+ }),
378
+ separate: PropTypes.boolean,
379
+ addTo: PropTypes.string,
380
+ addElement: PropTypes.oneOfType([PropTypes.string, PropTypes.string]),
381
+ legend: PropTypes.oneOfType([
382
+ PropTypes.string,
383
+ PropTypes.shape({
384
+ component: PropTypes.string.isRequired,
385
+ props: PropTypes.object
386
+ })
387
+ ]),
388
+ actions: PropTypes.arrayOf(
389
+ PropTypes.shape({
390
+ component: PropTypes.string.isRequired,
391
+ props: PropTypes.object
392
+ })
393
+ ),
394
+ wrapClassName: PropTypes.string
395
+ }).isRequired
396
+ }).isRequired,
397
+ registry: PropTypes.shape({
398
+ fields: PropTypes.object.isRequired
399
+ }).isRequired
400
+ };
401
+
402
+ export default CollapsibleField;
package/lib/DraftRte.js CHANGED
@@ -74,15 +74,15 @@ function mapFromObject(data, mapping, defVal) {
74
74
  return agg;
75
75
  }, defVal);
76
76
  }
77
- /**
78
- *
79
- * @param {*} data
80
- * @param {*} mapping
81
- * Mapped object is converted to the object mapping takes
77
+ /**
78
+ *
79
+ * @param {*} data
80
+ * @param {*} mapping
81
+ * Mapped object is converted to the object mapping takes
82
82
  */
83
83
  function mapFromSchema(data, mapping) {
84
- /* if (isEmpty(data)) {
85
- return;
84
+ /* if (isEmpty(data)) {
85
+ return;
86
86
  } */
87
87
  if (!mapping || mapping === null) {
88
88
  return data;
@@ -95,11 +95,11 @@ function mapFromSchema(data, mapping) {
95
95
  }
96
96
  }
97
97
 
98
- /**
99
- *
100
- * @param {*} data
101
- * @param {*} mapping
102
- * prepare the String to display
98
+ /**
99
+ *
100
+ * @param {*} data
101
+ * @param {*} mapping
102
+ * prepare the String to display
103
103
  */
104
104
  function optionToString(fields, separator) {
105
105
  return function (option) {
@@ -119,11 +119,11 @@ function optionToString(fields, separator) {
119
119
  }, "");
120
120
  };
121
121
  }
122
- /**
123
- *
124
- * @param {*} data
125
- * @param {*} mapping
126
- * maping the label
122
+ /**
123
+ *
124
+ * @param {*} data
125
+ * @param {*} mapping
126
+ * maping the label
127
127
  */
128
128
  function mapLabelKey(labelKey) {
129
129
  if (Array.isArray(labelKey)) {
@@ -140,10 +140,10 @@ function mapLabelKey(labelKey) {
140
140
  var DraftRTE = function (_Component) {
141
141
  _inherits(DraftRTE, _Component);
142
142
 
143
- /**
144
- *
145
- * @param {*} props
146
- * Currently only supports HTML
143
+ /**
144
+ *
145
+ * @param {*} props
146
+ * Currently only supports HTML
147
147
  */
148
148
  function DraftRTE(props) {
149
149
  _classCallCheck(this, DraftRTE);
@@ -183,24 +183,24 @@ var DraftRTE = function (_Component) {
183
183
  };
184
184
  return _this;
185
185
  }
186
- /**
187
- * updates formData by calling parent's onChange function with current html content
186
+ /**
187
+ * updates formData by calling parent's onChange function with current html content
188
188
  */
189
189
 
190
190
 
191
- /**
192
- * handles editor's onChange
193
- * handles logic to update form data based on props supplied to the component
191
+ /**
192
+ * handles editor's onChange
193
+ * handles logic to update form data based on props supplied to the component
194
194
  */
195
195
  //will only be executed if debounce is present
196
196
 
197
- /**
198
- * handles the logic to update formData on blur
197
+ /**
198
+ * handles the logic to update formData on blur
199
199
  */
200
200
 
201
201
 
202
- /**
203
- * handles the logic to load the suggestions on the time of focus
202
+ /**
203
+ * handles the logic to load the suggestions on the time of focus
204
204
  */
205
205
 
206
206
 
@@ -208,8 +208,8 @@ var DraftRTE = function (_Component) {
208
208
  key: "render",
209
209
 
210
210
 
211
- /**
212
- * react render function
211
+ /**
212
+ * react render function
213
213
  */
214
214
  value: function render() {
215
215
  var _this2 = this;
@@ -154,11 +154,11 @@ function mapFromObject(data, mapping, defVal) {
154
154
  return agg;
155
155
  }, defVal);
156
156
  }
157
- /**
158
- *
159
- * @param {*} data
160
- * @param {*} mapping
161
- * Mapped object is converted to the object mapping takes
157
+ /**
158
+ *
159
+ * @param {*} data
160
+ * @param {*} mapping
161
+ * Mapped object is converted to the object mapping takes
162
162
  */
163
163
  function mapFromSchema(data, mapping) {
164
164
  if (isEmpty(data)) {
@@ -223,9 +223,9 @@ function isFunction(functionToCheck) {
223
223
  return functionToCheck instanceof Function;
224
224
  }
225
225
 
226
- /*
227
- this is done to prevent an edge case with a typeahead wrapped inside a table that has an item selected & uses a function as a labelKey
228
- TODO: Need to find a better solution for this
226
+ /*
227
+ this is done to prevent an edge case with a typeahead wrapped inside a table that has an item selected & uses a function as a labelKey
228
+ TODO: Need to find a better solution for this
229
229
  */
230
230
  function transformLabelKey(labelKey, schema, selected) {
231
231
  if (isFunction(labelKey) && selected && selected.length > 0 && schema.type === "string" && selected.every(function (x) {
@@ -0,0 +1,10 @@
1
+ /*Collapsible header items*/
2
+ .header-elements-wrapper {
3
+ align-items: center;
4
+ color: #fff;
5
+ display: inline-flex;
6
+ flex-direction: row;
7
+ justify-content: flex-start;
8
+ padding-left: 20px;
9
+ white-space: nowrap;
10
+ }
@@ -92,32 +92,6 @@ function getFieldValue(cellValue, type, format, dataFormat) {
92
92
  }
93
93
  return cellValue;
94
94
  }
95
- function isEquivalentObject(a, b) {
96
- // Create arrays of property names
97
- var aProps = Object.getOwnPropertyNames(a);
98
- var bProps = Object.getOwnPropertyNames(b);
99
-
100
- // If number of properties is different,
101
- // objects are not equivalent
102
- if (aProps.length != bProps.length) {
103
- return false;
104
- }
105
-
106
- for (var i = 0; i < aProps.length; i++) {
107
- var propName = aProps[i];
108
-
109
- // If values of same property are not equal,
110
- // objects are not equivalent
111
- if (a[propName] !== b[propName]) {
112
- return false;
113
- }
114
- }
115
-
116
- // If we made it this far, objects
117
- // are considered equivalent
118
-
119
- return true;
120
- }
121
95
 
122
96
  var TableField = function (_Component) {
123
97
  _inherits(TableField, _Component);
@@ -255,31 +229,35 @@ var TableField = function (_Component) {
255
229
  }, {
256
230
  key: "handleRowSelect",
257
231
  value: function handleRowSelect(row, isSelected, e) {
232
+ var onChange = this.props.onChange;
258
233
  var _tableConf3 = this.tableConf,
259
- data = _tableConf3.data,
234
+ _tableConf3$data = _tableConf3.data,
235
+ data = _tableConf3$data === undefined ? [] : _tableConf3$data,
260
236
  _tableConf3$selectRow = _tableConf3.selectRow.onSelectRow.fieldToUpdate,
261
237
  fieldToUpdate = _tableConf3$selectRow === undefined ? "picked" : _tableConf3$selectRow;
262
238
 
263
- var filteredRows = (data || []).map(function (item) {
264
- if (!isSelected && item[fieldToUpdate] !== undefined) {
265
- if (isEquivalentObject(item, row)) {
266
- delete item[fieldToUpdate];
267
- }
268
- } else if (isEquivalentObject(item, row)) {
269
- item[fieldToUpdate] = isSelected;
270
- }
271
- return item;
272
- });
273
- this.props.onChange(filteredRows);
239
+
240
+ row.isRowSelected = isSelected;
241
+
242
+ if (!isSelected) {
243
+ delete row[fieldToUpdate];
244
+ } else {
245
+ row[fieldToUpdate] = isSelected;
246
+ }
247
+
248
+ onChange(data);
274
249
  }
275
250
  }, {
276
251
  key: "handleAllRowSelect",
277
252
  value: function handleAllRowSelect(isSelected, rows, e) {
278
- var _tableConf$selectRow$ = this.tableConf.selectRow.onSelectAllRow.fieldToUpdate,
279
- fieldToUpdate = _tableConf$selectRow$ === undefined ? "picked" : _tableConf$selectRow$;
253
+ var _tableConf4 = this.tableConf,
254
+ data = _tableConf4.data,
255
+ _tableConf4$selectRow = _tableConf4.selectRow.onSelectAllRow.fieldToUpdate,
256
+ fieldToUpdate = _tableConf4$selectRow === undefined ? "picked" : _tableConf4$selectRow;
280
257
 
281
258
 
282
- var filteredRows = (rows || []).map(function (item) {
259
+ var filteredRows = data.map(function (item) {
260
+ item.isRowSelected = isSelected;
283
261
  if (!isSelected && item[fieldToUpdate] !== undefined) {
284
262
  delete item[fieldToUpdate];
285
263
  } else {
@@ -487,12 +465,14 @@ var TableField = function (_Component) {
487
465
  _props2$idSchema = _props2.idSchema;
488
466
  _props2$idSchema = _props2$idSchema === undefined ? {} : _props2$idSchema;
489
467
  var $id = _props2$idSchema.$id,
490
- onChange = _props2.onChange;
468
+ onChange = _props2.onChange,
469
+ selectedItems = _props2.selectedItems;
491
470
 
492
471
 
493
472
  var forceReRenderTable = this.forceReRenderTable;
494
473
 
495
- this.tableConf = (0, _tableConfFactory2.default)(uiSchema, formData, this.handleCellSave, this.handleRowsDelete, this.handleDeletedRow, this.handleRowSelect, this.handleAllRowSelect, this.myRowExpand, this.isRowExpandable, this.expandColumnComponent);
474
+ this.tableConf = (0, _tableConfFactory2.default)(uiSchema, formData, this.handleCellSave, this.handleRowsDelete, this.handleDeletedRow, this.handleRowSelect, this.handleAllRowSelect, this.myRowExpand, this.isRowExpandable, this.expandColumnComponent, selectedItems);
475
+
496
476
  var expandableTableOptions = this.getExpandableTableOptions();
497
477
  this.tableConf.options.insertModal = this.createCustomModal;
498
478
  var boostrapTableOptions = _extends({
@@ -508,7 +488,10 @@ var TableField = function (_Component) {
508
488
  { id: $id },
509
489
  _react2.default.createElement(
510
490
  _reactBootstrapTable.BootstrapTable,
511
- _extends({}, this.tableConf, { trClassName: this.handleRowColorChange, ref: "table" }),
491
+ _extends({}, this.tableConf, {
492
+ trClassName: this.handleRowColorChange,
493
+ ref: "table"
494
+ }),
512
495
  columns.map(function (column, i) {
513
496
  return _react2.default.createElement(
514
497
  _reactBootstrapTable.TableHeaderColumn,