@pie-lib/config-ui 10.10.4-next.50 → 10.10.4-next.501

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.
Files changed (70) hide show
  1. package/CHANGELOG.md +346 -0
  2. package/lib/alert-dialog.js +44 -0
  3. package/lib/alert-dialog.js.map +1 -0
  4. package/lib/checkbox.js +4 -4
  5. package/lib/checkbox.js.map +1 -1
  6. package/lib/choice-configuration/feedback-menu.js +41 -53
  7. package/lib/choice-configuration/feedback-menu.js.map +1 -1
  8. package/lib/choice-configuration/index.js +88 -81
  9. package/lib/choice-configuration/index.js.map +1 -1
  10. package/lib/choice-utils.js +8 -8
  11. package/lib/choice-utils.js.map +1 -1
  12. package/lib/feedback-config/feedback-selector.js +38 -47
  13. package/lib/feedback-config/feedback-selector.js.map +1 -1
  14. package/lib/feedback-config/group.js +5 -5
  15. package/lib/feedback-config/group.js.map +1 -1
  16. package/lib/feedback-config/index.js +46 -52
  17. package/lib/feedback-config/index.js.map +1 -1
  18. package/lib/form-section.js +8 -6
  19. package/lib/form-section.js.map +1 -1
  20. package/lib/help.js +30 -37
  21. package/lib/help.js.map +1 -1
  22. package/lib/index.js +66 -45
  23. package/lib/index.js.map +1 -1
  24. package/lib/input.js +35 -40
  25. package/lib/input.js.map +1 -1
  26. package/lib/inputs.js +28 -17
  27. package/lib/inputs.js.map +1 -1
  28. package/lib/langs.js +37 -45
  29. package/lib/langs.js.map +1 -1
  30. package/lib/layout/config-layout.js +29 -37
  31. package/lib/layout/config-layout.js.map +1 -1
  32. package/lib/layout/index.js +2 -2
  33. package/lib/layout/index.js.map +1 -1
  34. package/lib/layout/layout-contents.js +28 -34
  35. package/lib/layout/layout-contents.js.map +1 -1
  36. package/lib/layout/settings-box.js +23 -31
  37. package/lib/layout/settings-box.js.map +1 -1
  38. package/lib/mui-box/index.js +3 -3
  39. package/lib/mui-box/index.js.map +1 -1
  40. package/lib/number-text-field-custom.js +364 -0
  41. package/lib/number-text-field-custom.js.map +1 -0
  42. package/lib/number-text-field.js +33 -42
  43. package/lib/number-text-field.js.map +1 -1
  44. package/lib/radio-with-label.js +4 -4
  45. package/lib/radio-with-label.js.map +1 -1
  46. package/lib/settings/display-size.js +10 -10
  47. package/lib/settings/display-size.js.map +1 -1
  48. package/lib/settings/index.js +11 -17
  49. package/lib/settings/index.js.map +1 -1
  50. package/lib/settings/panel.js +58 -68
  51. package/lib/settings/panel.js.map +1 -1
  52. package/lib/settings/settings-radio-label.js +4 -4
  53. package/lib/settings/settings-radio-label.js.map +1 -1
  54. package/lib/settings/toggle.js +5 -5
  55. package/lib/settings/toggle.js.map +1 -1
  56. package/lib/tabs/index.js +28 -35
  57. package/lib/tabs/index.js.map +1 -1
  58. package/lib/tags-input/index.js +32 -40
  59. package/lib/tags-input/index.js.map +1 -1
  60. package/lib/two-choice.js +38 -48
  61. package/lib/two-choice.js.map +1 -1
  62. package/lib/with-stateful-model.js +23 -30
  63. package/lib/with-stateful-model.js.map +1 -1
  64. package/package.json +4 -4
  65. package/src/alert-dialog.jsx +43 -0
  66. package/src/choice-configuration/index.jsx +30 -11
  67. package/src/form-section.jsx +2 -2
  68. package/src/index.js +4 -0
  69. package/src/inputs.jsx +13 -5
  70. package/src/number-text-field-custom.jsx +276 -0
@@ -1,64 +1,59 @@
1
1
  "use strict";
2
2
 
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
3
5
  Object.defineProperty(exports, "__esModule", {
4
6
  value: true
5
7
  });
6
8
  exports["default"] = void 0;
7
9
 
8
- var _react = _interopRequireDefault(require("react"));
9
-
10
- var _propTypes = _interopRequireDefault(require("prop-types"));
10
+ var _classCallCheck2 = _interopRequireDefault(require("@babel/runtime/helpers/classCallCheck"));
11
11
 
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
12
+ var _createClass2 = _interopRequireDefault(require("@babel/runtime/helpers/createClass"));
13
13
 
14
- function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
14
+ var _assertThisInitialized2 = _interopRequireDefault(require("@babel/runtime/helpers/assertThisInitialized"));
15
15
 
16
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
16
+ var _inherits2 = _interopRequireDefault(require("@babel/runtime/helpers/inherits"));
17
17
 
18
- 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); } }
18
+ var _possibleConstructorReturn2 = _interopRequireDefault(require("@babel/runtime/helpers/possibleConstructorReturn"));
19
19
 
20
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
20
+ var _getPrototypeOf2 = _interopRequireDefault(require("@babel/runtime/helpers/getPrototypeOf"));
21
21
 
22
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }
22
+ var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty"));
23
23
 
24
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
25
-
26
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
24
+ var _react = _interopRequireDefault(require("react"));
27
25
 
28
- function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
26
+ var _propTypes = _interopRequireDefault(require("prop-types"));
29
27
 
30
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
28
+ function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = (0, _getPrototypeOf2["default"])(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = (0, _getPrototypeOf2["default"])(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return (0, _possibleConstructorReturn2["default"])(this, result); }; }
31
29
 
32
- 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; }
30
+ function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
33
31
 
34
32
  var withStatefulModel = function withStatefulModel(Component) {
35
- var Stateful =
36
- /*#__PURE__*/
37
- function (_React$Component) {
38
- _inherits(Stateful, _React$Component);
33
+ var Stateful = /*#__PURE__*/function (_React$Component) {
34
+ (0, _inherits2["default"])(Stateful, _React$Component);
35
+
36
+ var _super = _createSuper(Stateful);
39
37
 
40
38
  function Stateful(props) {
41
39
  var _this;
42
40
 
43
- _classCallCheck(this, Stateful);
44
-
45
- _this = _possibleConstructorReturn(this, _getPrototypeOf(Stateful).call(this, props));
46
-
47
- _defineProperty(_assertThisInitialized(_this), "onChange", function (model) {
41
+ (0, _classCallCheck2["default"])(this, Stateful);
42
+ _this = _super.call(this, props);
43
+ (0, _defineProperty2["default"])((0, _assertThisInitialized2["default"])(_this), "onChange", function (model) {
48
44
  _this.setState({
49
45
  model: model
50
46
  }, function () {
51
47
  _this.props.onChange(_this.state.model);
52
48
  });
53
49
  });
54
-
55
50
  _this.state = {
56
51
  model: props.model
57
52
  };
58
53
  return _this;
59
54
  }
60
55
 
61
- _createClass(Stateful, [{
56
+ (0, _createClass2["default"])(Stateful, [{
62
57
  key: "componentWillReceiveProps",
63
58
  value: function componentWillReceiveProps(props) {
64
59
  this.setState({
@@ -68,21 +63,19 @@ var withStatefulModel = function withStatefulModel(Component) {
68
63
  }, {
69
64
  key: "render",
70
65
  value: function render() {
71
- return _react["default"].createElement(Component, {
66
+ return /*#__PURE__*/_react["default"].createElement(Component, {
72
67
  model: this.state.model,
73
68
  onChange: this.onChange
74
69
  });
75
70
  }
76
71
  }]);
77
-
78
72
  return Stateful;
79
73
  }(_react["default"].Component);
80
74
 
81
- _defineProperty(Stateful, "propTypes", {
75
+ (0, _defineProperty2["default"])(Stateful, "propTypes", {
82
76
  model: _propTypes["default"].object.isRequired,
83
77
  onChange: _propTypes["default"].func.isRequired
84
78
  });
85
-
86
79
  return Stateful;
87
80
  };
88
81
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/with-stateful-model.jsx"],"names":["withStatefulModel","Component","Stateful","props","model","setState","onChange","state","React","PropTypes","object","isRequired","func"],"mappings":";;;;;;;AAAA;;AACA;;;;;;;;;;;;;;;;;;;;;;;;AAEA,IAAMA,iBAAiB,GAAG,SAApBA,iBAAoB,CAAAC,SAAS,EAAI;AAAA,MAC/BC,QAD+B;AAAA;AAAA;AAAA;;AAOnC,sBAAYC,KAAZ,EAAmB;AAAA;;AAAA;;AACjB,oFAAMA,KAAN;;AADiB,iEAWR,UAAAC,KAAK,EAAI;AAClB,cAAKC,QAAL,CAAc;AAAED,UAAAA,KAAK,EAALA;AAAF,SAAd,EAAyB,YAAM;AAC7B,gBAAKD,KAAL,CAAWG,QAAX,CAAoB,MAAKC,KAAL,CAAWH,KAA/B;AACD,SAFD;AAGD,OAfkB;;AAEjB,YAAKG,KAAL,GAAa;AACXH,QAAAA,KAAK,EAAED,KAAK,CAACC;AADF,OAAb;AAFiB;AAKlB;;AAZkC;AAAA;AAAA,gDAcTD,KAdS,EAcF;AAC/B,aAAKE,QAAL,CAAc;AAAED,UAAAA,KAAK,EAAED,KAAK,CAACC;AAAf,SAAd;AACD;AAhBkC;AAAA;AAAA,+BAwB1B;AACP,eAAO,gCAAC,SAAD;AAAW,UAAA,KAAK,EAAE,KAAKG,KAAL,CAAWH,KAA7B;AAAoC,UAAA,QAAQ,EAAE,KAAKE;AAAnD,UAAP;AACD;AA1BkC;;AAAA;AAAA,IACdE,kBAAMP,SADQ;;AAAA,kBAC/BC,QAD+B,eAEhB;AACjBE,IAAAA,KAAK,EAAEK,sBAAUC,MAAV,CAAiBC,UADP;AAEjBL,IAAAA,QAAQ,EAAEG,sBAAUG,IAAV,CAAeD;AAFR,GAFgB;;AA6BrC,SAAOT,QAAP;AACD,CA9BD;;eAgCeF,iB","sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst withStatefulModel = Component => {\n class Stateful extends React.Component {\n static propTypes = {\n model: PropTypes.object.isRequired,\n onChange: PropTypes.func.isRequired\n };\n\n constructor(props) {\n super(props);\n this.state = {\n model: props.model\n };\n }\n\n componentWillReceiveProps(props) {\n this.setState({ model: props.model });\n }\n\n onChange = model => {\n this.setState({ model }, () => {\n this.props.onChange(this.state.model);\n });\n };\n\n render() {\n return <Component model={this.state.model} onChange={this.onChange} />;\n }\n }\n\n return Stateful;\n};\n\nexport default withStatefulModel;\n"],"file":"with-stateful-model.js"}
1
+ {"version":3,"file":"with-stateful-model.js","names":["withStatefulModel","Component","Stateful","props","model","setState","onChange","state","React","PropTypes","object","isRequired","func"],"sources":["../src/with-stateful-model.jsx"],"sourcesContent":["import React from 'react';\nimport PropTypes from 'prop-types';\n\nconst withStatefulModel = Component => {\n class Stateful extends React.Component {\n static propTypes = {\n model: PropTypes.object.isRequired,\n onChange: PropTypes.func.isRequired\n };\n\n constructor(props) {\n super(props);\n this.state = {\n model: props.model\n };\n }\n\n componentWillReceiveProps(props) {\n this.setState({ model: props.model });\n }\n\n onChange = model => {\n this.setState({ model }, () => {\n this.props.onChange(this.state.model);\n });\n };\n\n render() {\n return <Component model={this.state.model} onChange={this.onChange} />;\n }\n }\n\n return Stateful;\n};\n\nexport default withStatefulModel;\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;AAAA;;AACA;;;;;;AAEA,IAAMA,iBAAiB,GAAG,SAApBA,iBAAoB,CAAAC,SAAS,EAAI;EAAA,IAC/BC,QAD+B;IAAA;;IAAA;;IAOnC,kBAAYC,KAAZ,EAAmB;MAAA;;MAAA;MACjB,0BAAMA,KAAN;MADiB,6FAWR,UAAAC,KAAK,EAAI;QAClB,MAAKC,QAAL,CAAc;UAAED,KAAK,EAALA;QAAF,CAAd,EAAyB,YAAM;UAC7B,MAAKD,KAAL,CAAWG,QAAX,CAAoB,MAAKC,KAAL,CAAWH,KAA/B;QACD,CAFD;MAGD,CAfkB;MAEjB,MAAKG,KAAL,GAAa;QACXH,KAAK,EAAED,KAAK,CAACC;MADF,CAAb;MAFiB;IAKlB;;IAZkC;MAAA;MAAA,OAcnC,mCAA0BD,KAA1B,EAAiC;QAC/B,KAAKE,QAAL,CAAc;UAAED,KAAK,EAAED,KAAK,CAACC;QAAf,CAAd;MACD;IAhBkC;MAAA;MAAA,OAwBnC,kBAAS;QACP,oBAAO,gCAAC,SAAD;UAAW,KAAK,EAAE,KAAKG,KAAL,CAAWH,KAA7B;UAAoC,QAAQ,EAAE,KAAKE;QAAnD,EAAP;MACD;IA1BkC;IAAA;EAAA,EACdE,iBAAA,CAAMP,SADQ;;EAAA,iCAC/BC,QAD+B,eAEhB;IACjBE,KAAK,EAAEK,qBAAA,CAAUC,MAAV,CAAiBC,UADP;IAEjBL,QAAQ,EAAEG,qBAAA,CAAUG,IAAV,CAAeD;EAFR,CAFgB;EA6BrC,OAAOT,QAAP;AACD,CA9BD;;eAgCeF,iB"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pie-lib/config-ui",
3
- "version": "10.10.4-next.50+373febd7",
3
+ "version": "10.10.4-next.501+5dbb5690",
4
4
  "main": "lib/index.js",
5
5
  "module": "src/index.js",
6
6
  "publishConfig": {
@@ -10,9 +10,9 @@
10
10
  "dependencies": {
11
11
  "@material-ui/core": "^3.8.3",
12
12
  "@material-ui/icons": "^3.0.2",
13
- "@pie-lib/editable-html": "^7.17.4-next.50+373febd7",
13
+ "@pie-lib/editable-html": "^7.17.4-next.501+5dbb5690",
14
14
  "@pie-lib/icons": "^2.4.25",
15
- "@pie-lib/render-ui": "^4.12.0",
15
+ "@pie-lib/render-ui": "^4.13.1",
16
16
  "classnames": "^2.2.6",
17
17
  "debug": "^4.1.1",
18
18
  "lodash": "^4.17.11",
@@ -26,5 +26,5 @@
26
26
  "peerDependencies": {
27
27
  "react": "^16.8.1"
28
28
  },
29
- "gitHead": "373febd70834b3188f1f4c03819bb3112bd145df"
29
+ "gitHead": "5dbb56906290d5145ca6de59df2566a7e8b0e916"
30
30
  }
@@ -0,0 +1,43 @@
1
+ import React from 'react';
2
+ import PropTypes from 'prop-types';
3
+ import {
4
+ Button,
5
+ Dialog,
6
+ DialogActions,
7
+ DialogContent,
8
+ DialogContentText,
9
+ DialogTitle
10
+ } from '@material-ui/core';
11
+
12
+ const AlertDialog = ({ text, title, onClose, onConfirm, open }) => (
13
+ <Dialog open={open} onClose={onClose}>
14
+ {title && <DialogTitle>{title}</DialogTitle>}
15
+ {text && (
16
+ <DialogContent>
17
+ <DialogContentText>{text}</DialogContentText>
18
+ </DialogContent>
19
+ )}
20
+ <DialogActions>
21
+ {onClose && (
22
+ <Button onClick={onClose} color="primary">
23
+ CANCEL
24
+ </Button>
25
+ )}
26
+ {onConfirm && (
27
+ <Button autoFocus onClick={onConfirm} color="primary">
28
+ OK
29
+ </Button>
30
+ )}
31
+ </DialogActions>
32
+ </Dialog>
33
+ );
34
+
35
+ AlertDialog.propTypes = {
36
+ text: PropTypes.string,
37
+ title: PropTypes.string,
38
+ onClose: PropTypes.func,
39
+ onConfirm: PropTypes.func,
40
+ open: PropTypes.bool
41
+ };
42
+
43
+ export default AlertDialog;
@@ -18,16 +18,20 @@ const EditableHtmlContainer = withStyles(theme => ({
18
18
  }
19
19
  }))(
20
20
  ({
21
- label,
22
- classes,
23
- onChange,
24
- value,
25
- className,
26
- imageSupport,
27
- disabled,
28
- nonEmpty,
29
- toolbarOpts
30
- }) => {
21
+ label,
22
+ classes,
23
+ onChange,
24
+ value,
25
+ className,
26
+ imageSupport,
27
+ disabled,
28
+ spellCheck,
29
+ nonEmpty,
30
+ toolbarOpts,
31
+ error,
32
+ maxImageWidth,
33
+ maxImageHeight
34
+ }) => {
31
35
  const names = classNames(classes.labelContainer, className);
32
36
 
33
37
  return (
@@ -36,11 +40,15 @@ const EditableHtmlContainer = withStyles(theme => ({
36
40
  <EditableHtml
37
41
  markup={value || ''}
38
42
  disabled={disabled}
43
+ spellCheck={spellCheck}
39
44
  nonEmpty={nonEmpty}
40
45
  onChange={onChange}
41
46
  imageSupport={imageSupport}
42
47
  className={classes.editor}
43
48
  toolbarOpts={toolbarOpts}
49
+ error={error}
50
+ maxImageWidth={maxImageWidth}
51
+ maxImageHeight={maxImageHeight}
44
52
  />
45
53
  </div>
46
54
  </InputContainer>
@@ -183,10 +191,13 @@ export class ChoiceConfiguration extends React.Component {
183
191
  useLetterOrdering,
184
192
  imageSupport,
185
193
  disabled,
194
+ spellCheck,
186
195
  nonEmpty,
187
196
  allowFeedBack,
188
197
  allowDelete,
189
- toolbarOpts
198
+ toolbarOpts,
199
+ error,
200
+ noCorrectAnswerError
190
201
  } = this.props;
191
202
 
192
203
  const InputToggle = mode === 'checkbox' ? InputCheckbox : InputRadio;
@@ -204,6 +215,7 @@ export class ChoiceConfiguration extends React.Component {
204
215
  onChange={this.onCheckedChange}
205
216
  label={!noLabels ? 'Correct' : ''}
206
217
  checked={!!data.correct}
218
+ error={noCorrectAnswerError}
207
219
  />
208
220
  <div className={classes.middleColumn}>
209
221
  <EditableHtmlContainer
@@ -212,9 +224,12 @@ export class ChoiceConfiguration extends React.Component {
212
224
  onChange={this.onLabelChange}
213
225
  imageSupport={imageSupport}
214
226
  disabled={disabled}
227
+ spellCheck={spellCheck}
215
228
  nonEmpty={nonEmpty}
216
229
  toolbarOpts={toolbarOpts}
230
+ error={error}
217
231
  />
232
+ {error && <div className={classes.errorText}>{error}</div>}
218
233
 
219
234
  {allowFeedBack && (
220
235
  <Feedback
@@ -294,6 +309,10 @@ const styles = theme => ({
294
309
  display: 'flex',
295
310
  flex: 1,
296
311
  flexDirection: 'column'
312
+ },
313
+ errorText: {
314
+ fontSize: '12px',
315
+ color: 'red'
297
316
  }
298
317
  });
299
318
 
@@ -13,9 +13,9 @@ const styles = theme => ({
13
13
  }
14
14
  });
15
15
 
16
- export default withStyles(styles)(({ className, classes, label, children }) => (
16
+ export default withStyles(styles)(({ className, classes, label, children, labelExtraStyle }) => (
17
17
  <div className={classNames(classes.formSection, className)}>
18
- <Typography className={classes.label} type="subheading">
18
+ <Typography className={classes.label} type="subheading" style={labelExtraStyle}>
19
19
  {label}
20
20
  </Typography>
21
21
  {children}
package/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import AlertDialog from './alert-dialog';
1
2
  import FeedbackConfig, {
2
3
  FeedbackSelector,
3
4
  buildDefaults as feedbackConfigDefaults
@@ -11,6 +12,7 @@ import Help from './help';
11
12
  import Input from './input';
12
13
  import { InputContainer } from '@pie-lib/render-ui';
13
14
  import NumberTextField from './number-text-field';
15
+ import NumberTextFieldCustom from './number-text-field-custom';
14
16
  import TwoChoice, { NChoice } from './two-choice';
15
17
  import TagsInput from './tags-input';
16
18
  import MuiBox from './mui-box';
@@ -25,6 +27,7 @@ import DisplaySize from './settings/display-size';
25
27
  import * as settings from './settings';
26
28
 
27
29
  export {
30
+ AlertDialog,
28
31
  FeedbackConfig,
29
32
  FeedbackSelector,
30
33
  feedbackConfigDefaults,
@@ -40,6 +43,7 @@ export {
40
43
  Input,
41
44
  InputContainer,
42
45
  NumberTextField,
46
+ NumberTextFieldCustom,
43
47
  TwoChoice,
44
48
  NChoice,
45
49
  TagsInput,
package/src/inputs.jsx CHANGED
@@ -5,6 +5,7 @@ import PropTypes from 'prop-types';
5
5
  import React from 'react';
6
6
  import Switch from '@material-ui/core/Switch';
7
7
  import { withStyles } from '@material-ui/core/styles';
8
+ import classNames from 'classnames';
8
9
 
9
10
  const InputTypes = {
10
11
  classes: PropTypes.object.isRequired,
@@ -12,7 +13,8 @@ const InputTypes = {
12
13
  label: PropTypes.string,
13
14
  checked: PropTypes.bool,
14
15
  onChange: PropTypes.func,
15
- disabled: PropTypes.bool
16
+ disabled: PropTypes.bool,
17
+ error: PropTypes.string
16
18
  };
17
19
 
18
20
  const RawInputSwitch = ({ classes, className, label, checked, onChange }) => {
@@ -38,12 +40,12 @@ const InputSwitch = withStyles({
38
40
  })(RawInputSwitch);
39
41
 
40
42
  const RawInputCheckbox = props => {
41
- const { classes, className, label, checked, onChange, disabled } = props;
43
+ const { classes, className, label, checked, onChange, disabled, error } = props;
42
44
 
43
45
  return (
44
46
  <InputContainer className={className} label={label}>
45
47
  <Checkbox
46
- className={classes.checkboxRoot}
48
+ className={classNames(classes.checkboxRoot, error && classes.error)}
47
49
  disabled={disabled}
48
50
  checked={checked}
49
51
  onChange={onChange}
@@ -56,12 +58,12 @@ const RawInputCheckbox = props => {
56
58
  RawInputCheckbox.propTypes = { ...InputTypes };
57
59
 
58
60
  const RawInputRadio = props => {
59
- const { classes, className, label, checked, onChange, disabled } = props;
61
+ const { classes, className, label, checked, onChange, disabled, error } = props;
60
62
 
61
63
  return (
62
64
  <InputContainer className={className} label={label}>
63
65
  <Radio
64
- className={classes.radioRoot}
66
+ className={classNames(classes.radioRoot, error && classes.error)}
65
67
  disabled={disabled}
66
68
  checked={checked}
67
69
  onChange={onChange}
@@ -76,12 +78,18 @@ RawInputRadio.propTypes = { ...InputTypes };
76
78
  const InputCheckbox = withStyles({
77
79
  checkboxRoot: {
78
80
  transform: 'translate(-25%, 20%)'
81
+ },
82
+ error: {
83
+ color: 'red'
79
84
  }
80
85
  })(RawInputCheckbox);
81
86
 
82
87
  const InputRadio = withStyles(() => ({
83
88
  radioRoot: {
84
89
  transform: 'translate(-20%, 20%)'
90
+ },
91
+ error: {
92
+ color: 'red'
85
93
  }
86
94
  }))(RawInputRadio);
87
95
 
@@ -0,0 +1,276 @@
1
+ import PropTypes from 'prop-types';
2
+ import React from 'react';
3
+ import TextField from '@material-ui/core/TextField';
4
+ import classNames from 'classnames';
5
+ import { withStyles } from '@material-ui/core/styles';
6
+ import isFinite from 'lodash/isFinite';
7
+ import IconButton from '@material-ui/core/IconButton';
8
+ import InputAdornment from '@material-ui/core/InputAdornment';
9
+ import Remove from '@material-ui/icons/Remove';
10
+ import Add from '@material-ui/icons/Add';
11
+
12
+ const styles = theme => ({
13
+ input: {
14
+ '& input[type=number]': {
15
+ '-moz-appearance': 'textfield'
16
+ },
17
+ '& input[type=number]::-webkit-outer-spin-button': {
18
+ '-webkit-appearance': 'none',
19
+ margin: 0
20
+ },
21
+ '& input[type=number]::-webkit-inner-spin-button': {
22
+ '-webkit-appearance': 'none',
23
+ margin: 0
24
+ }
25
+ },
26
+ iconButton: {
27
+ padding: '2px'
28
+ }
29
+ });
30
+
31
+ const fallbackNumber = (min, max) => {
32
+ if (!isFinite(min) && !isFinite(max)) {
33
+ return 0;
34
+ }
35
+
36
+ if (!isFinite(min) && isFinite(max)) {
37
+ return max;
38
+ }
39
+
40
+ if (isFinite(min)) {
41
+ return min;
42
+ }
43
+ };
44
+
45
+ export class NumberTextFieldCustom extends React.Component {
46
+ static propTypes = {
47
+ classes: PropTypes.object.isRequired,
48
+ className: PropTypes.string,
49
+ customValues: PropTypes.array,
50
+ disabled: PropTypes.bool,
51
+ error: PropTypes.bool,
52
+ inputClassName: PropTypes.string,
53
+ onChange: PropTypes.func.isRequired,
54
+ onlyIntegersAllowed: PropTypes.bool,
55
+ value: PropTypes.number,
56
+ min: PropTypes.number,
57
+ max: PropTypes.number,
58
+ step: PropTypes.number,
59
+ label: PropTypes.string,
60
+ disableUnderline: PropTypes.bool,
61
+ variant: PropTypes.string
62
+ };
63
+
64
+ static defaultProps = {
65
+ step: 1,
66
+ customValues: [],
67
+ textAlign: 'center',
68
+ variant: 'standard',
69
+ onlyIntegersAllowed: false
70
+ };
71
+
72
+ constructor(props) {
73
+ super(props);
74
+
75
+ const { value, currentIndex } = this.normalizeValueAndIndex(props.customValues, props.value);
76
+
77
+ this.state = {
78
+ value,
79
+ currentIndex
80
+ };
81
+
82
+ if (value !== props.value) {
83
+ this.props.onChange({}, value);
84
+ }
85
+
86
+ this.onChange = this.onChange.bind(this);
87
+ }
88
+
89
+ UNSAFE_componentWillReceiveProps(props) {
90
+ const { value, currentIndex } = this.normalizeValueAndIndex(props.customValues, props.value);
91
+
92
+ this.setState({ value, currentIndex });
93
+ }
94
+
95
+ clamp(value) {
96
+ const { min, max, customValues } = this.props;
97
+
98
+ if ((customValues || []).length > 0) {
99
+ return value;
100
+ }
101
+
102
+ if (!isFinite(value)) {
103
+ return fallbackNumber(min, max);
104
+ }
105
+
106
+ if (isFinite(max)) {
107
+ value = Math.min(value, max);
108
+ }
109
+
110
+ if (isFinite(min)) {
111
+ value = Math.max(value, min);
112
+ }
113
+
114
+ return value;
115
+ }
116
+
117
+ normalizeValueAndIndex = (customValues, number) => {
118
+ const value = this.clamp(number);
119
+ const currentIndex = (customValues || []).findIndex(val => val === value);
120
+
121
+ if ((customValues || []).length > 0 && currentIndex === -1) {
122
+ const closestValue = this.getClosestValue(customValues, value);
123
+
124
+ return { value: closestValue.value, currentIndex: closestValue.index };
125
+ }
126
+
127
+ return { value, currentIndex };
128
+ };
129
+
130
+ getClosestValue = (customValues, number) =>
131
+ customValues.reduce(
132
+ (closest, value, index) =>
133
+ Math.abs(value - number) < Math.abs(closest.value - number) ? { value, index } : closest,
134
+ { value: customValues[0], index: 0 }
135
+ );
136
+
137
+ onBlur = event => {
138
+ const { customValues, onlyIntegersAllowed } = this.props;
139
+ const { value } = event.target;
140
+ const rawNumber = onlyIntegersAllowed ? parseInt(value) : parseFloat(value);
141
+
142
+ const { value: number, currentIndex } = this.normalizeValueAndIndex(customValues, rawNumber);
143
+
144
+ if (number !== this.state.value) {
145
+ this.setState(
146
+ {
147
+ value: number.toString(),
148
+ currentIndex
149
+ },
150
+ () => this.props.onChange(event, number)
151
+ );
152
+ }
153
+ };
154
+
155
+ onChange(event) {
156
+ const { value } = event.target;
157
+
158
+ this.setState({ value });
159
+ }
160
+
161
+ changeValue(event, sign = 1, shouldUpdate = false) {
162
+ event.preventDefault();
163
+
164
+ const { customValues, step, onlyIntegersAllowed, onChange } = this.props;
165
+ const { currentIndex, value } = this.state;
166
+ const updatedIndex = currentIndex + sign * 1;
167
+ let number;
168
+
169
+ if (customValues.length > 0) {
170
+ if (updatedIndex < 0 || updatedIndex >= customValues.length) {
171
+ return;
172
+ }
173
+
174
+ number = customValues[updatedIndex];
175
+ } else {
176
+ const rawNumber = onlyIntegersAllowed ? parseInt(value) : parseFloat(value);
177
+ const updatedValue = (rawNumber * 10000 + step * sign * 10000) / 10000;
178
+ number = this.clamp(updatedValue);
179
+ }
180
+
181
+ this.setState(
182
+ {
183
+ value: number.toString(),
184
+ currentIndex: updatedIndex
185
+ },
186
+ () => {
187
+ if (shouldUpdate) {
188
+ onChange(event, number);
189
+ }
190
+ }
191
+ );
192
+ }
193
+
194
+ render() {
195
+ const {
196
+ className,
197
+ classes,
198
+ label,
199
+ disabled,
200
+ error,
201
+ min,
202
+ max,
203
+ inputClassName,
204
+ disableUnderline,
205
+ helperText,
206
+ variant,
207
+ textAlign
208
+ } = this.props;
209
+ const { value } = this.state;
210
+ const names = classNames(className, classes.input);
211
+
212
+ return (
213
+ <TextField
214
+ variant={variant}
215
+ inputRef={ref => (this.inputRef = ref)}
216
+ disabled={disabled}
217
+ label={label}
218
+ value={value}
219
+ error={error}
220
+ helperText={helperText}
221
+ onChange={this.onChange}
222
+ onBlur={this.onBlur}
223
+ onKeyPress={e => {
224
+ // once the Enter key is pressed, we force input blur
225
+ if (e.key === 'Enter' && this.inputRef) {
226
+ this.inputRef.blur();
227
+ }
228
+ }}
229
+ onKeyDown={e => {
230
+ if (e.key === 'ArrowUp') {
231
+ this.changeValue(e);
232
+ }
233
+
234
+ if (e.key === 'ArrowDown') {
235
+ this.changeValue(e, -1);
236
+ }
237
+ }}
238
+ type="number"
239
+ className={names}
240
+ InputProps={{
241
+ className: inputClassName,
242
+ disableUnderline: disableUnderline,
243
+ startAdornment: (
244
+ <InputAdornment position="start">
245
+ <IconButton
246
+ className={classes.iconButton}
247
+ disabled={disabled}
248
+ onClick={e => this.changeValue(e, -1, true)}
249
+ >
250
+ <Remove fontSize="small" />
251
+ </IconButton>
252
+ </InputAdornment>
253
+ ),
254
+ endAdornment: (
255
+ <InputAdornment position="end">
256
+ <IconButton
257
+ className={classes.iconButton}
258
+ disabled={disabled}
259
+ onClick={e => this.changeValue(e, 1, true)}
260
+ >
261
+ <Add fontSize="small" />
262
+ </IconButton>
263
+ </InputAdornment>
264
+ )
265
+ }}
266
+ inputProps={{
267
+ style: { textAlign },
268
+ min,
269
+ max
270
+ }}
271
+ />
272
+ );
273
+ }
274
+ }
275
+
276
+ export default withStyles(styles)(NumberTextFieldCustom);