aefis-core-ui 2.2.0-rc1 → 2.2.1-rc2

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.
@@ -67,13 +67,13 @@ import 'lodash/camelCase';
67
67
  import debounce from 'lodash/debounce';
68
68
  import StepConnector, { stepConnectorClasses } from '@mui/material/StepConnector';
69
69
  import { MuiForm5 } from '@rjsf/material-ui';
70
+ import isEmpty from 'lodash/isEmpty';
70
71
  import compose from 'lodash/fp/compose';
71
72
  import Chip$2 from '@mui/material/Chip';
72
73
  import TextField$2 from '@mui/material/TextField';
73
74
  import { useFormControl } from '@mui/material/FormControl';
74
75
  import get$1 from 'lodash/get';
75
76
  import isPlainObject from 'lodash/isPlainObject';
76
- import isEmpty from 'lodash/isEmpty';
77
77
  import ToggleButton$1 from '@mui/material/ToggleButton';
78
78
  import { parse as parse$1, format as format$1, setDate, setMonth } from 'date-fns';
79
79
  import { MobileDatePicker as MobileDatePicker$1 } from '@mui/x-date-pickers/MobileDatePicker';
@@ -727,7 +727,7 @@ const DismissableAlert = props => {
727
727
  const [open, setOpen] = useState(true);
728
728
  const handleClick = () => {
729
729
  setOpen(false);
730
- props.onDismiss && props.onDismiss();
730
+ props.onDismiss == null ? void 0 : props.onDismiss();
731
731
  };
732
732
  return /*#__PURE__*/jsx(Collapse, {
733
733
  in: open,
@@ -747,7 +747,12 @@ const DismissableAlert = props => {
747
747
  }),
748
748
  children: [props.title && /*#__PURE__*/jsx(AlertTitle, {
749
749
  children: props.title
750
- }), props.description]
750
+ }), /*#__PURE__*/jsx(Box$1, {
751
+ sx: {
752
+ paddingRight: 0.5
753
+ },
754
+ children: props.description
755
+ })]
751
756
  }))
752
757
  });
753
758
  };
@@ -807,7 +812,12 @@ const Alert = /*#__PURE__*/forwardRef(function Alert(props, ref) {
807
812
  role: props.role,
808
813
  children: [props.title && /*#__PURE__*/jsx(AlertTitle, {
809
814
  children: props.title
810
- }), props.description]
815
+ }), /*#__PURE__*/jsx(Box$1, {
816
+ sx: {
817
+ paddingRight: 0.5
818
+ },
819
+ children: props.description
820
+ })]
811
821
  }))
812
822
  });
813
823
  });
@@ -6816,7 +6826,9 @@ DataTable.propTypes = {
6816
6826
  getRowId: PropTypes.func
6817
6827
  };
6818
6828
 
6819
- const options = {};
6829
+ const options = {
6830
+ arrayFormat: "index"
6831
+ };
6820
6832
  const setQueryStringWithoutPageReload = qsValue => {
6821
6833
  const {
6822
6834
  protocol,
@@ -11120,6 +11132,7 @@ const BusinessObjectPicker = _ref => {
11120
11132
  pageSize,
11121
11133
  idTemplate,
11122
11134
  shouldResetOnParametersChange,
11135
+ // TODO: replace this implementation with getNextPageParam function prop
11123
11136
  queryParamNames,
11124
11137
  enableInfinteScroll,
11125
11138
  renderAddItemForm,
@@ -11367,7 +11380,12 @@ const BusinessObjectPicker = _ref => {
11367
11380
  loading: status === "loading",
11368
11381
  options: props.data || _flatData,
11369
11382
  onChange: handleChange,
11370
- onInputChange: (event, value, reason) => reason === "reset" && setQ(""),
11383
+ onInputChange: (event, value, reason) => reason === "reset" && setQ("")
11384
+ // CAVEAT: changing this to getOptionLabel will create
11385
+ // problem when there are items with same label even though
11386
+ // they have different keys (ids).
11387
+ // getOptionLabel={getKey}
11388
+ ,
11371
11389
  getOptionLabel: getOptionLabel || getLabel,
11372
11390
  size: props.size,
11373
11391
  value: value,
@@ -14278,9 +14296,20 @@ TitleAndDescription.propTypes = {
14278
14296
  gutterBottom: PropTypes.bool
14279
14297
  };
14280
14298
 
14299
+ /**
14300
+ * Avoid using this hook as it mutates ref during render. using useState might
14301
+ * better option. https://beta.reactjs.org/learn/you-might-not-need-an-effect
14302
+ *
14303
+ * const useComponentWillMount = (callback) => { //
14304
+ * const [isMounted, setIsMounted] = useState(false); //
14305
+ * if (!isMounted) { callback(); setIsMounted(true); } //
14306
+ * };
14307
+ *
14308
+ * @param {function} callback
14309
+ */
14281
14310
  const useComponentWillMount = callback => {
14282
14311
  const willMount = useRef(true);
14283
- if (willMount.current) callback == null ? void 0 : callback();
14312
+ if (willMount.current) callback();
14284
14313
  willMount.current = false;
14285
14314
  };
14286
14315
 
@@ -15229,50 +15258,68 @@ RubricDistributionChart.propTypes = {
15229
15258
  titleComponent: PropTypes.oneOf(["h1", "h2", "h3", "h4", "div", "p"])
15230
15259
  };
15231
15260
 
15232
- const moreThan = ruleValue => fieldValue => {
15261
+ const moreThan = ruleValue => ({
15262
+ fieldValue
15263
+ }) => {
15233
15264
  const isValid = fieldValue > ruleValue;
15234
15265
  if (!isValid) return `should be more than ${ruleValue}`;
15235
15266
  };
15236
- const moreThanOrEqual = ruleValue => fieldValue => {
15267
+ const moreThanOrEqual = ruleValue => ({
15268
+ fieldValue
15269
+ }) => {
15237
15270
  const isValid = fieldValue >= ruleValue;
15238
15271
  if (!isValid) return `should be more than to ${ruleValue}`;
15239
15272
  };
15240
- const lessThan = ruleValue => fieldValue => {
15273
+ const lessThan = ruleValue => ({
15274
+ fieldValue
15275
+ }) => {
15241
15276
  const isValid = fieldValue < ruleValue;
15242
15277
  if (!isValid) return `should be less than ${ruleValue}`;
15243
15278
  };
15244
- const lessThanOrEqual = ruleValue => fieldValue => {
15279
+ const lessThanOrEqual = ruleValue => ({
15280
+ fieldValue
15281
+ }) => {
15245
15282
  const isValid = fieldValue <= ruleValue;
15246
15283
  if (!isValid) return `should be less than or equal to ${ruleValue}`;
15247
15284
  };
15248
- const notEqual = ruleValue => fieldValue => {
15285
+ const notEqual = ruleValue => ({
15286
+ fieldValue
15287
+ }) => {
15249
15288
  const isValid = ruleValue.toString() !== (fieldValue == null ? void 0 : fieldValue.toString == null ? void 0 : fieldValue.toString());
15250
15289
  if (!isValid) return `should NOT be ${ruleValue}`;
15251
15290
  };
15252
- const url = () => fieldValue => {
15291
+ const url = () => ({
15292
+ fieldValue
15293
+ }) => {
15253
15294
  const UrlRegEx = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/;
15254
15295
  const isValid = UrlRegEx.test(fieldValue);
15255
15296
  if (!isValid) return `is NOT a valid URL`;
15256
15297
  };
15257
- const email = () => fieldValue => {
15298
+ const email = () => ({
15299
+ fieldValue
15300
+ }) => {
15258
15301
  const EmailRegEx = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
15259
15302
  const isValid = EmailRegEx.test(fieldValue);
15260
15303
  if (!isValid) return `is NOT a valid email address`;
15261
15304
  };
15262
- const isInvalidDate = () => fieldValue => {
15305
+ const isInvalidDate = () => ({
15306
+ fieldValue
15307
+ }) => {
15263
15308
  const isValid = fieldValue !== "Invalid Date";
15264
15309
  if (!isValid) return "is invalid date";
15265
15310
  };
15266
- const required = () => fieldValue => {
15311
+ const required = () => ({
15312
+ fieldValue,
15313
+ schema
15314
+ }) => {
15267
15315
  const message = "is required";
15268
- if (Array.isArray(fieldValue) && fieldValue.length === 0) {
15269
- return message;
15270
- }
15271
- if (fieldValue == undefined || fieldValue == "") {
15272
- return message;
15273
- }
15316
+ if (schema.type.includes("array") && Array.isArray(fieldValue) && fieldValue.length === 0) return message;
15317
+ if (schema.type.includes("object") && isEmpty(fieldValue)) return message;
15318
+ if (fieldValue === null || fieldValue === undefined || fieldValue == "") return message;
15274
15319
  };
15275
- const isNumber = () => fieldValue => {
15320
+ const isNumber = () => ({
15321
+ fieldValue
15322
+ }) => {
15276
15323
  const message = "should be number";
15277
15324
  const isValid = !isNaN(fieldValue) &&
15278
15325
  // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
@@ -15280,7 +15327,9 @@ const isNumber = () => fieldValue => {
15280
15327
 
15281
15328
  if (!isValid) return message;
15282
15329
  };
15283
- const isNotNegativeNumber = () => fieldValue => {
15330
+ const isNotNegativeNumber = () => ({
15331
+ fieldValue
15332
+ }) => {
15284
15333
  const isValid = !isNaN(fieldValue) &&
15285
15334
  // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
15286
15335
  !isNaN(parseFloat(fieldValue)); // ...and ensure strings of whitespace fail
@@ -15288,21 +15337,49 @@ const isNotNegativeNumber = () => fieldValue => {
15288
15337
  if (isValid && parseFloat(fieldValue) < 0) return "should be positive number";
15289
15338
  if (!isValid) return "should be number";
15290
15339
  };
15291
- const characterLimitLessThan = ruleValue => fieldValue => {
15292
- // INFO: fasly values ("", undefined, null) are assumed to be to be 0
15293
- if (!fieldValue) return;
15294
- const isValid = fieldValue.length < ruleValue;
15295
- if (!isValid) return `should not exceed ${ruleValue - 1} characters`;
15340
+ const characterLimitLessThan = ruleValue => ({
15341
+ fieldValue
15342
+ }) => {
15343
+ // INFO: null and undefined are casted to empty string(""), number
15344
+ // values are casted to string
15345
+ const value = (fieldValue != null ? fieldValue : "").toString();
15346
+ const message = `should not exceed ${ruleValue - 1} characters`;
15347
+ const isValid = value.length < ruleValue;
15348
+ if (!isValid) return message;
15349
+ };
15350
+ const characterLimitMoreThan = ruleValue => ({
15351
+ fieldValue
15352
+ }) => {
15353
+ // INFO: null and undefined are casted to empty string(""), number
15354
+ // values are casted to string
15355
+ const value = (fieldValue != null ? fieldValue : "").toString();
15356
+ const message = `should not be less than ${ruleValue + 1} characters`;
15357
+ const isValid = value.length > ruleValue;
15358
+ if (!isValid) return message;
15296
15359
  };
15297
- const characterLimitMoreThan = ruleValue => fieldValue => {
15298
- const message = `should be more than ${ruleValue} characters`;
15299
-
15300
- // INFO: fasly values ("", undefined, null) are assumed to be to be 0
15301
- if (!fieldValue) return message;
15302
- const isValid = fieldValue.length > ruleValue;
15360
+ const maxLength = ruleValue => ({
15361
+ fieldValue
15362
+ }) => {
15363
+ // INFO: null and undefined are casted to empty string(""), number values
15364
+ // are casted to string
15365
+ const value = (fieldValue != null ? fieldValue : "").toString();
15366
+ const message = `should not exceed ${ruleValue} characters`;
15367
+ const isValid = value.length <= ruleValue;
15368
+ if (!isValid) return message;
15369
+ };
15370
+ const minLength = ruleValue => ({
15371
+ fieldValue
15372
+ }) => {
15373
+ // INFO: null and undefined are casted to empty string(""), number values
15374
+ // are casted to string
15375
+ const value = (fieldValue != null ? fieldValue : "").toString();
15376
+ const message = `should not be less than ${ruleValue} characters`;
15377
+ const isValid = value.length >= ruleValue;
15303
15378
  if (!isValid) return message;
15304
15379
  };
15305
15380
  const Rules = {
15381
+ maxLength,
15382
+ minLength,
15306
15383
  moreThan,
15307
15384
  moreThanOrEqual,
15308
15385
  lessThan,
@@ -15332,6 +15409,14 @@ const {
15332
15409
  formData: {}
15333
15410
  });
15334
15411
 
15412
+ const useSubmitted = () => {
15413
+ const [submitted, setSubmitted] = useState(false);
15414
+ useSubmitListener(() => {
15415
+ setSubmitted(true);
15416
+ });
15417
+ return submitted;
15418
+ };
15419
+
15335
15420
  const useStyles$3 = makeStyles(theme => ({
15336
15421
  button: {
15337
15422
  margin: theme.spacing(1)
@@ -15347,10 +15432,10 @@ const FormButtons = ({
15347
15432
  showCancelButton: _showCancelButton = false,
15348
15433
  showResetButton: _showResetButton = false,
15349
15434
  showDeleteButton: _showDeleteButton = false,
15350
- saveLabel,
15351
- cancelLabel,
15352
- resetLabel,
15353
- deleteLabel,
15435
+ saveLabel: _saveLabel = "Save",
15436
+ cancelLabel: _cancelLabel = "Cancel",
15437
+ resetLabel: _resetLabel = "Reset",
15438
+ deleteLabel: _deleteLabel = "Delete",
15354
15439
  hidden,
15355
15440
  submitStatus,
15356
15441
  onCancel,
@@ -15359,13 +15444,15 @@ const FormButtons = ({
15359
15444
  }) => {
15360
15445
  const classes = useStyles$3();
15361
15446
  const setFormState = useSetFormState();
15447
+ const customErrorMapping = useSelectFormState(formState => formState.customErrorMapping);
15448
+ const submitted = useSubmitted();
15362
15449
  let renderSaveButton = () => /*#__PURE__*/jsx(Button, {
15363
15450
  variant: "contained",
15364
15451
  color: "primary",
15365
15452
  type: "submit",
15366
- name: saveLabel,
15453
+ name: _saveLabel,
15367
15454
  className: classes.button,
15368
- children: saveLabel
15455
+ children: _saveLabel
15369
15456
  });
15370
15457
  if (submitStatus === "loading") {
15371
15458
  renderSaveButton = () => {
@@ -15375,7 +15462,7 @@ const FormButtons = ({
15375
15462
  type: "submit",
15376
15463
  className: classes.button,
15377
15464
  disabled: true,
15378
- name: saveLabel,
15465
+ name: _saveLabel,
15379
15466
  endIcon: /*#__PURE__*/jsx(CircularProgress, {
15380
15467
  color: "grey",
15381
15468
  size: 15
@@ -15384,18 +15471,19 @@ const FormButtons = ({
15384
15471
  });
15385
15472
  };
15386
15473
  }
15387
- if (submitStatus === "error") {
15474
+ const submitBlockedByCustomError = Object.values(customErrorMapping).findIndex(Boolean) !== -1;
15475
+ if (submitted && (submitStatus === "error" || submitBlockedByCustomError)) {
15388
15476
  renderSaveButton = () => {
15389
15477
  return /*#__PURE__*/jsx(Button, {
15390
15478
  variant: "contained",
15391
15479
  color: "primary",
15392
15480
  type: "submit",
15393
- name: saveLabel,
15481
+ name: _saveLabel,
15394
15482
  className: classes.button,
15395
15483
  endIcon: /*#__PURE__*/jsx(Error$1, {
15396
15484
  size: 15
15397
15485
  }),
15398
- children: saveLabel
15486
+ children: _saveLabel
15399
15487
  });
15400
15488
  };
15401
15489
  }
@@ -15408,7 +15496,7 @@ const FormButtons = ({
15408
15496
  }, {
15409
15497
  children: [_showResetButton && /*#__PURE__*/jsx(Button, {
15410
15498
  className: classes.button,
15411
- name: resetLabel,
15499
+ name: _resetLabel,
15412
15500
  onClick: () => {
15413
15501
  onReset == null ? void 0 : onReset();
15414
15502
  setFormState(prevState => _extends({}, prevState, {
@@ -15416,26 +15504,20 @@ const FormButtons = ({
15416
15504
  key: +new Date()
15417
15505
  }));
15418
15506
  },
15419
- children: resetLabel
15507
+ children: _resetLabel
15420
15508
  }), _showCancelButton && /*#__PURE__*/jsx(Button, {
15421
- name: cancelLabel,
15509
+ name: _cancelLabel,
15422
15510
  onClick: onCancel,
15423
15511
  className: classes.button,
15424
- children: cancelLabel
15512
+ children: _cancelLabel
15425
15513
  }), _showDeleteButton && /*#__PURE__*/jsx(Button, {
15426
- name: deleteLabel,
15514
+ name: _deleteLabel,
15427
15515
  onClick: onDelete,
15428
15516
  className: classes.button,
15429
- children: deleteLabel
15517
+ children: _deleteLabel
15430
15518
  }), !disabled && renderSaveButton()]
15431
15519
  }));
15432
15520
  };
15433
- FormButtons.defaultProps = {
15434
- saveLabel: "Submit",
15435
- cancelLabel: "Cancel",
15436
- resetLabel: "Reset",
15437
- deleteLabel: "Delete"
15438
- };
15439
15521
  FormButtons.propTypes = {
15440
15522
  cancelLabel: PropTypes.string,
15441
15523
  disabled: PropTypes.any,
@@ -15507,51 +15589,6 @@ const withEmptyValue = Component => {
15507
15589
  });
15508
15590
  };
15509
15591
 
15510
- const windowKeys = Object.keys(window).filter(key => {
15511
- try {
15512
- Function.apply(null, [key, "return;"]);
15513
- return true;
15514
- } catch (e) {
15515
- return false;
15516
- }
15517
- });
15518
-
15519
- /**
15520
- * evaluates
15521
- * @param {string} code
15522
- * @param {object} context
15523
- * @param {object} options
15524
- * @param {function} options.falbback
15525
- *
15526
- * @returns
15527
- */
15528
- const safeEval = (code, context, options) => {
15529
- const keys = Object.keys(context);
15530
-
15531
- // TODO: optimize
15532
- const allParams = keys.concat(windowKeys, [`"use strict"; return ${code}`]);
15533
- try {
15534
- const fn = Function.apply(null, allParams);
15535
- const params = keys.map(key => context[key]);
15536
- const res = fn.apply(null, params);
15537
- return res;
15538
- } catch (e) {
15539
- (options == null ? void 0 : options.fallback == null ? void 0 : options.fallback(e)) || console.log("Eval Error : ", e, {
15540
- code,
15541
- context,
15542
- options
15543
- });
15544
- }
15545
- };
15546
- const lazyEval = (code, context) => {
15547
- return new Promise((resolve, reject) => {
15548
- const result = safeEval(code, context, {
15549
- fallback: reject
15550
- });
15551
- resolve(result);
15552
- });
15553
- };
15554
-
15555
15592
  const {
15556
15593
  useSelectState: useSelectFieldState,
15557
15594
  useSetState: useSetFieldState,
@@ -15670,14 +15707,113 @@ CustomFieldTemplate.propTypes = {
15670
15707
  };
15671
15708
  var CustomFieldTemplate$1 = /*#__PURE__*/React.memo(withFieldStore(CustomFieldTemplate));
15672
15709
 
15710
+ /**
15711
+ * Simple memoize function. Check Stackoverflow topic for better implementation:
15712
+ * https://stackoverflow.com/questions/61402804/what-memoization-libraries-are-available-for-javascript
15713
+ *
15714
+ * @param {functionp} passedFunc
15715
+ * @returns function
15716
+ */
15717
+ const memoize = function memoize(passedFunc) {
15718
+ const cache = {};
15719
+ return function (x) {
15720
+ if (x in cache) return cache[x];
15721
+ cache[x] = passedFunc(x);
15722
+ return cache[x];
15723
+ };
15724
+ };
15725
+
15726
+ const windowKeys = Object.keys(window).filter(key => {
15727
+ try {
15728
+ Function.apply(null, [key, "return;"]);
15729
+ return true;
15730
+ } catch (e) {
15731
+ return false;
15732
+ }
15733
+ });
15734
+ const createScopedEval = (scopeMap, options) => {
15735
+ const keys = Object.keys(scopeMap);
15736
+ const createFunction = code => {
15737
+ const allParams = keys.concat(windowKeys, [`"use strict"; return ${code}`]);
15738
+ return Function.apply(null, allParams);
15739
+ };
15740
+ const memoizedCreateFunction = memoize(createFunction);
15741
+ const scopedEval = (code, scope) => {
15742
+ try {
15743
+ const fn = memoizedCreateFunction(code);
15744
+ const params = keys.map(key => scope[key]);
15745
+ const res = fn.apply(null, params);
15746
+ return res;
15747
+ } catch (e) {
15748
+ (options == null ? void 0 : options.fallback == null ? void 0 : options.fallback(e)) || console.log("Eval Error : ", e, {
15749
+ code,
15750
+ scope,
15751
+ options
15752
+ });
15753
+ }
15754
+ };
15755
+ return scopedEval;
15756
+ };
15757
+
15758
+ /**
15759
+ * evaluates
15760
+ * @param {string} code
15761
+ * @param {object} scope
15762
+ * @param {object} options
15763
+ * @param {function} options.falbback
15764
+ *
15765
+ * @returns
15766
+ */
15767
+ const scopedEval = (code, scope, options) => {
15768
+ const keys = Object.keys(scope);
15769
+
15770
+ // TODO: optimize
15771
+ const allParams = keys.concat(windowKeys, [`"use strict"; return ${code}`]);
15772
+ try {
15773
+ const fn = Function.apply(null, allParams);
15774
+ const params = keys.map(key => scope[key]);
15775
+ const res = fn.apply(null, params);
15776
+ return res;
15777
+ } catch (e) {
15778
+ (options == null ? void 0 : options.fallback == null ? void 0 : options.fallback(e)) || console.log("Eval Error : ", e, {
15779
+ code,
15780
+ scope,
15781
+ options
15782
+ });
15783
+ }
15784
+ };
15785
+ const lazyEval = (code, scope) => {
15786
+ return new Promise((resolve, reject) => {
15787
+ const result = safeEval(code, scope, {
15788
+ fallback: reject
15789
+ });
15790
+ resolve(result);
15791
+ });
15792
+ };
15793
+ const useScopedEval = scopeMap => useMemo(() => createScopedEval(scopeMap), []);
15794
+
15673
15795
  const withValidate = Component => {
15674
15796
  const MemoizedComponent = /*#__PURE__*/React.memo(Component);
15675
15797
  return /*#__PURE__*/forwardRef((props, ref) => {
15676
- var _props$uiSchema;
15677
- const rules = ((_props$uiSchema = props.uiSchema) == null ? void 0 : _props$uiSchema["rules"]) || [];
15678
- const isWidget = !!props.id;
15679
- const formItemValue = isWidget ? props.value : props.formData;
15798
+ const {
15799
+ id,
15800
+ name,
15801
+ value,
15802
+ formData,
15803
+ uiSchema,
15804
+ schema,
15805
+ formContext
15806
+ } = props;
15807
+ const rules = uiSchema["rules"] || [];
15808
+ const isWidget = !!id;
15809
+ const formItemValue = isWidget ? value : formData;
15810
+
15811
+ // CAVEAT: This cleans the idPrefix if widget (not field). Custom
15812
+ // idPrefix defination might effect here. It should be tested and
15813
+ // updated accordingly
15814
+ const fieldName = isWidget ? id.slice(5) : name;
15680
15815
  const Rules = useSelectFormState(state => state.rules);
15816
+ const scopedEval = useScopedEval(_extends({}, Rules));
15681
15817
  const setFieldState = useSetFieldState();
15682
15818
  const setFormState = useSetFormState();
15683
15819
  const [submitted, setSubmitted] = useState(false);
@@ -15687,13 +15823,13 @@ const withValidate = Component => {
15687
15823
  if (!rules) return [];
15688
15824
  const evaluatedRules = rules.map(rule => {
15689
15825
  const isFunctionCall = rule.slice(-1) === ")";
15690
- const ruleFn = safeEval(rule, Rules);
15826
+ const ruleFn = scopedEval(rule, Rules);
15691
15827
  return isFunctionCall ? ruleFn : ruleFn();
15692
15828
  });
15693
15829
 
15694
15830
  // TODO: this is bad practise, implementation should be moved to
15695
15831
  // inside widget/field when withValidate replaced with custom hook
15696
- if (props.uiSchema["ui:widget"] === "DateWidget" || props.uiSchema["ui:field"] === "DateSelect") {
15832
+ if (uiSchema["ui:widget"] === "DateWidget" || uiSchema["ui:field"] === "DateSelect") {
15697
15833
  evaluatedRules.push(Rules.isInvalidDate());
15698
15834
  }
15699
15835
  return evaluatedRules;
@@ -15710,25 +15846,33 @@ const withValidate = Component => {
15710
15846
  if (!rules) return;
15711
15847
  const isEmpty = formItemValue == undefined || formItemValue === "";
15712
15848
  const skipValidationOnEmptyValue = isEmpty && !isRequired;
15713
- const message = !skipValidationOnEmptyValue && evalRuleArray(formItemValue)(ruleArray);
15849
+ const message = !skipValidationOnEmptyValue && evalRuleArray({
15850
+ fieldValue: formItemValue,
15851
+ formContext,
15852
+ formData,
15853
+ uiSchema,
15854
+ schema
15855
+ })(ruleArray);
15714
15856
  setFieldState(state => _extends({}, state, {
15715
15857
  errorMessage: message
15716
15858
  }));
15717
15859
 
15718
- // TODO: cleans the idPrefix if widget (not field). Custom idPrefix
15719
- // defination might effect here. It should be tested and updated
15720
- // accordingly
15721
- const fieldName = isWidget ? props.id.slice(5) : props.name;
15722
-
15723
15860
  // INFO: Adding item to array template does not work without
15724
15861
  // setFormState wrapped with setTimeout
15725
15862
  setTimeout(() => {
15726
- setFormState(state => _extends({}, state, {
15727
- customErrorMapping: _extends({}, state.customErrorMapping, {
15728
- [fieldName]: !!message
15729
- })
15730
- }));
15863
+ // TODO: This setFormState create so much re-render on top
15864
+ // level. For now, leaving this optimization to React 18
15865
+ // debounced rendering. It can also be solved by creating
15866
+ // seperate state for customErrorMapping.
15867
+ setFormState(state => {
15868
+ return _extends({}, state, {
15869
+ customErrorMapping: _extends({}, state.customErrorMapping, {
15870
+ [fieldName]: message
15871
+ })
15872
+ });
15873
+ });
15731
15874
  });
15875
+ // TODO: add other dependecies
15732
15876
  }, [formItemValue]);
15733
15877
  const handleOnchange = (...args) => {
15734
15878
  setTouched(true);
@@ -15741,13 +15885,31 @@ const withValidate = Component => {
15741
15885
  }));
15742
15886
  });
15743
15887
  };
15744
- const evalRuleArray = fieldValue => rules => {
15888
+ const evalRuleArray = ({
15889
+ fieldValue,
15890
+ schema,
15891
+ uiSchema,
15892
+ formContext,
15893
+ formData
15894
+ }) => rules => {
15745
15895
  for (let rule of rules) {
15746
- const message = rule(fieldValue);
15896
+ const message = rule({
15897
+ fieldValue,
15898
+ schema,
15899
+ uiSchema,
15900
+ formContext,
15901
+ formData
15902
+ });
15747
15903
  if (message != undefined) return message;
15748
15904
  }
15749
15905
  };
15750
15906
 
15907
+ /**
15908
+ * TODO:
15909
+ * - do two version of it seperately for widget and field eg. withValidate (for field) and withValidateWidget
15910
+ *
15911
+ */
15912
+
15751
15913
  const commonWidgetHOCs = [withValidate, withEmptyValue];
15752
15914
  const commonFieldHOCs = [withValidate, withEmptyValue];
15753
15915
 
@@ -16387,12 +16549,7 @@ const ReadOnlyView = ({
16387
16549
  sx: {
16388
16550
  fontStyle: "italic"
16389
16551
  },
16390
- description: /*#__PURE__*/jsx(Box$2, {
16391
- sx: {
16392
- paddingRight: 0.5
16393
- },
16394
- children: _emptyViewText
16395
- }),
16552
+ description: _emptyViewText,
16396
16553
  showIcon: false
16397
16554
  });
16398
16555
  }
@@ -16715,7 +16872,9 @@ const useReadOnly = uiSchema => {
16715
16872
  const selector = useCallback(state => {
16716
16873
  const defaultValue = state.readonly || state.schema.readonly;
16717
16874
  if (!code) return defaultValue;
16718
- const evaluatedReadyOnly = safeEval(code, state);
16875
+
16876
+ // TODO: change it with useScopedEval
16877
+ const evaluatedReadyOnly = scopedEval(code, state);
16719
16878
  return defaultValue || evaluatedReadyOnly;
16720
16879
  }, [code]);
16721
16880
  const evaluatedReadyOnly = useSelectFormState(selector);
@@ -16804,13 +16963,11 @@ const dateInputStyles = {
16804
16963
  const DateSelect = props => {
16805
16964
  var _useSelector, _useSelector2;
16806
16965
  const {
16807
- id,
16808
16966
  required,
16809
16967
  schema,
16810
16968
  formData,
16811
16969
  onChange,
16812
16970
  rawErrors,
16813
- options,
16814
16971
  disabled
16815
16972
  } = props;
16816
16973
  const [selectedDate, setSelectedDate] = useState(null);
@@ -16864,7 +17021,10 @@ const DateSelect = props => {
16864
17021
  const maxDateRaw = (_useSelector2 = useSelector(props.uiSchema["select::maxDate"])) == null ? void 0 : _useSelector2.date;
16865
17022
  const maxDate = maxDateRaw ? parse$1(maxDateRaw, "MM-dd-yyyy", new Date()) : undefined;
16866
17023
  const isReadOnly = useReadOnly(props.uiSchema);
16867
- if (isReadOnly) return /*#__PURE__*/jsx(DateSelectReadOnly$1, _extends({}, props));
17024
+ if (isReadOnly) return /*#__PURE__*/jsx(DateSelectReadOnly$1, {
17025
+ formData: formData,
17026
+ schema: schema
17027
+ });
16868
17028
  return /*#__PURE__*/jsxs(FormControl, {
16869
17029
  disabled: disabled || schema.disabled,
16870
17030
  required: required,
@@ -16922,7 +17082,6 @@ const DateSelect = props => {
16922
17082
  value: typeof selectedDate === "undefined" ? null : selectedDate,
16923
17083
  onChange: handleDateChange,
16924
17084
  disabled: disabled,
16925
- inputLabe: true,
16926
17085
  renderInput: params => /*#__PURE__*/jsx(TextField, _extends({}, params, {
16927
17086
  inputProps: _extends({}, params.inputProps, {
16928
17087
  type: "text"
@@ -17538,8 +17697,8 @@ const withEvalDisable = () => Component => {
17538
17697
  const code = (_props$uiSchema = props.uiSchema) == null ? void 0 : _props$uiSchema["ui:disabled"];
17539
17698
  if (!code) return props.disabled;
17540
17699
 
17541
- // TODO: use lazyEval
17542
- return safeEval(code, formState);
17700
+ // TODO: replace with useScopedEval
17701
+ return scopedEval(code, formState);
17543
17702
  }, [formState.formData, formState.formContext, props.disabled]);
17544
17703
  return /*#__PURE__*/jsx(MemoizedComponent, _extends({}, props, {
17545
17704
  disabled: isDisabled
@@ -17854,7 +18013,10 @@ var SelectField$1 = compose(HOCs$8)(SelectField);
17854
18013
  // check this topic to catch consistant view with autocmplete
17855
18014
  // https://stackoverflow.com/questions/63047684/material-ui-select-menu-with-end-adornment
17856
18015
 
18016
+ const useFormStateScopedEval = () => useScopedEval(formStateScopeMap);
18017
+
17857
18018
  const useProcessCondition = formState => {
18019
+ const safeEval = useFormStateScopedEval();
17858
18020
  const conditions = useMemo(() => {
17859
18021
  const {
17860
18022
  schema,
@@ -17880,47 +18042,48 @@ const useProcessCondition = formState => {
17880
18042
  const newFormState = useMemo(() => {
17881
18043
  const {
17882
18044
  schema,
17883
- formData
18045
+ formData,
18046
+ customErrorMapping
17884
18047
  } = formState;
17885
- let changed = false;
17886
- let newRequired = schema.required ? [...schema.required] : [];
18048
+ let newRequiredItemList = schema.required ? [...schema.required] : [];
17887
18049
  let newProperties = _extends({}, schema.properties);
18050
+ let newCustomErrorMapping = _extends({}, customErrorMapping);
17888
18051
  let newFormData = formData ? _extends({}, formData) : {};
17889
18052
  conditions.forEach(item => {
17890
- const nextOperation = safeEval(item.condition, formState) ? "added" : "deleted";
17891
- if (item.lastOperation !== nextOperation) {
17892
- changed = true;
17893
- }
17894
- if (nextOperation === "added") {
17895
- item.lastOperation = nextOperation;
18053
+ const nextOperation = safeEval(item.condition, formState) ? "add" : "delete";
18054
+ if (nextOperation === "add") {
17896
18055
  if (item.isRequired) {
17897
- newRequired.indexOf(item.key) === -1 && newRequired.push(item.key);
18056
+ newRequiredItemList.indexOf(item.key) === -1 && newRequired.push(item.key);
17898
18057
  }
17899
18058
  newProperties[item.key] = item.schema;
17900
- } else {
17901
- item.lastOperation = nextOperation;
18059
+ }
18060
+ if (nextOperation === "delete") {
17902
18061
  if (item.isRequired) {
17903
- newRequired = newRequired.filter(key => key !== item.key);
18062
+ newRequiredItemList = newRequiredItemList.filter(key => key !== item.key);
17904
18063
  }
17905
18064
  delete newProperties[item.key];
17906
18065
  delete newFormData[item.key];
18066
+ delete customErrorMapping[item.key];
17907
18067
  }
17908
18068
  });
17909
- if (changed) {
17910
- const newSchema = _extends({}, schema, {
17911
- properties: _extends({}, newProperties),
17912
- required: [...newRequired]
17913
- });
17914
- return _extends({}, formState, {
17915
- schema: newSchema,
17916
- formData: newFormData
17917
- });
17918
- }
17919
- return formState;
17920
- }, [formState.formData]);
18069
+ const newSchema = _extends({}, schema, {
18070
+ properties: _extends({}, newProperties),
18071
+ required: [...newRequiredItemList]
18072
+ });
18073
+ return _extends({}, formState, {
18074
+ schema: newSchema,
18075
+ formData: newFormData,
18076
+ customErrorMapping: newCustomErrorMapping
18077
+ });
18078
+ }, [formState]);
17921
18079
  return newFormState;
17922
18080
  };
17923
18081
 
18082
+ /**
18083
+ * TODO:
18084
+ * remove required list field
18085
+ */
18086
+
17924
18087
  const useStyles$1 = makeStyles$1(theme => ({
17925
18088
  fab: {
17926
18089
  margin: theme.spacing(1)
@@ -19465,7 +19628,7 @@ TextWidgetBase.propTypes = {
19465
19628
  };
19466
19629
 
19467
19630
  const _excluded = ["onChange"];
19468
- const TextWidgetReadOnly$1 = props => {
19631
+ const TextWidgetReadOnly$1 = function TextWidgetReadOnly(props) {
19469
19632
  const {
19470
19633
  options: {
19471
19634
  prefix = "$",
@@ -19494,7 +19657,15 @@ const TextWidgetReadOnly$1 = props => {
19494
19657
  });
19495
19658
  };
19496
19659
  TextWidgetReadOnly$1.propTypes = {
19497
- schema: PropTypes.any,
19660
+ options: PropTypes.shape({
19661
+ prefix: PropTypes.string,
19662
+ decimalScale: PropTypes.number,
19663
+ fixedDecimalScale: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
19664
+ thousandSeparator: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
19665
+ decimalSeparator: PropTypes.string,
19666
+ allowNegative: PropTypes.bool
19667
+ }),
19668
+ schema: PropTypes.object,
19498
19669
  value: PropTypes.any
19499
19670
  };
19500
19671
  const CurrencyWidget = props => {
@@ -19695,7 +19866,6 @@ SelectWidget.propTypes = {
19695
19866
  id: PropTypes.any,
19696
19867
  onChange: PropTypes.func,
19697
19868
  options: PropTypes.any,
19698
- rawErrors: PropTypes.array,
19699
19869
  required: PropTypes.any,
19700
19870
  schema: PropTypes.shape({
19701
19871
  disabled: PropTypes.any,
@@ -19879,6 +20049,8 @@ ValidateWidget.propTypes = {
19879
20049
  };
19880
20050
  var ValidateWidget$1 = withReadyOnly(ValidateWidget);
19881
20051
 
20052
+ const humanReadableList = a => [a.slice(0, -1).join(", "), a.slice(-1)[0]].join(a.length < 2 ? "" : " and ");
20053
+
19882
20054
  const {
19883
20055
  useDispatcher: useSubmitDispatcher,
19884
20056
  useListener: useSubmitListener,
@@ -19919,27 +20091,43 @@ const defaultFields = {
19919
20091
  */
19920
20092
  };
19921
20093
 
20094
+ const useProcessedFormState = () => {
20095
+ const formState = useSelectFormState();
20096
+ return useProcessCondition(formState);
20097
+ };
19922
20098
  const defaultTemplates = {
19923
20099
  ArrayFieldTemplate: ArrayFieldTemplate$1
19924
20100
  };
20101
+ const fn = () => {};
20102
+ const formStateScopeMap = {
20103
+ schema: {},
20104
+ uiSchema: {},
20105
+ initialFormData: {},
20106
+ formData: {},
20107
+ formContext: {},
20108
+ readonly: false,
20109
+ dataSources: {},
20110
+ customErrorMapping: {},
20111
+ rules: {}
20112
+ };
19925
20113
  const DynamicForm = ({
19926
- schema,
19927
- uiSchema,
19928
- saveButtonText,
19929
- cancelButtonText,
19930
- resetButtonText,
19931
- deleteButtonText,
19932
- formData: initialFormData,
20114
+ schema: _schema = {},
20115
+ uiSchema: _uiSchema = {},
20116
+ saveButtonText: _saveButtonText = "Save",
20117
+ cancelButtonText: _cancelButtonText = "Cancel",
20118
+ resetButtonText: _resetButtonText = "Reset",
20119
+ deleteButtonText: _deleteButtonText = "Delete",
20120
+ formData: initialFormData = {},
19933
20121
  widgets: widgetsProp,
19934
20122
  fields: fieldsProp,
19935
20123
  templates: templatesProp,
19936
- onChange,
19937
- actionUrls,
20124
+ onChange: _onChange = fn,
20125
+ onError: _onError = fn,
20126
+ onSubmit: _onSubmit = fn,
19938
20127
  dataSources: _dataSources = [],
19939
20128
  formContext: formContextProp,
19940
20129
  initialFormContext,
19941
- onSubmit,
19942
- disableSubmit,
20130
+ disableSubmit: _disableSubmit = false,
19943
20131
  readonly,
19944
20132
  formDataStatus,
19945
20133
  submitStatus,
@@ -19956,33 +20144,40 @@ const DynamicForm = ({
19956
20144
  renderBottom
19957
20145
  }) => {
19958
20146
  const setFormState = useSetFormState();
20147
+ const {
20148
+ error
20149
+ } = useNotify();
19959
20150
  useComponentWillMount(() => {
19960
- setFormState(prev => _extends({}, prev, {
19961
- schema,
19962
- uiSchema,
20151
+ const initialState = {
20152
+ schema: _schema,
20153
+ uiSchema: _uiSchema,
19963
20154
  initialFormData: initialFormData,
19964
20155
  formData: initialFormData,
19965
- actionUrls,
19966
20156
  formContext: initialFormContext || formContextProp,
19967
20157
  readonly,
19968
20158
  dataSources: _dataSources,
19969
20159
  customErrorMapping: {},
19970
20160
  rules: _extends({}, _rules, Rules)
19971
- }));
20161
+ };
20162
+ setFormState(() => initialState);
19972
20163
  });
19973
- const formState = useSelectFormState();
20164
+ const formState = useProcessedFormState();
20165
+
20166
+ // useDependencyChange(() => {}, [processedState]);
20167
+
19974
20168
  const widgets = _extends({}, defaultWidgets, widgetsProp);
19975
20169
  const fields = _extends({}, defaultFields, fieldsProp);
19976
20170
  const templates = _extends({}, defaultTemplates, templatesProp);
19977
20171
  const dispatchSubmitEvent = useSubmitDispatcher();
19978
- const newFormState = useProcessCondition(formState);
19979
20172
  useComponentWillMount(() => {
19980
20173
  const configs = getConfigurationParameters();
19981
20174
  registerDataSources(_dataSources, configs);
19982
20175
  });
19983
- useEffect(() => {
19984
- setFormState(prev => _extends({}, prev, newFormState));
19985
- }, [newFormState]);
20176
+
20177
+ // useEffect(() => {
20178
+ // setFormState((prev) => ({ ...prev, ...newFormState }));
20179
+ // }, [newFormState]);
20180
+
19986
20181
  useEffect(() => {
19987
20182
  setFormState(prev => _extends({}, prev, {
19988
20183
  formContext: formContextProp
@@ -19999,19 +20194,35 @@ const DynamicForm = ({
19999
20194
  const [{
20000
20195
  formData
20001
20196
  }] = args;
20002
- setFormState(prevState => _extends({}, prevState, {
20003
- formData
20004
- }));
20005
- onChange == null ? void 0 : onChange(...args);
20197
+ setFormState(prevState => {
20198
+ return _extends({}, prevState, {
20199
+ formData
20200
+ });
20201
+ });
20202
+ _onChange == null ? void 0 : _onChange(...args);
20006
20203
  };
20007
20204
  const handleSubmit = (...args) => {
20008
- if (disableSubmit) {
20009
- return;
20010
- }
20205
+ if (_disableSubmit) return;
20011
20206
  dispatchSubmitEvent(...args);
20012
20207
  const submitBlockedByCustomError = Object.values(formState.customErrorMapping).findIndex(Boolean) !== -1;
20013
- if (submitBlockedByCustomError) return;
20014
- onSubmit(...args);
20208
+ if (submitBlockedByCustomError) {
20209
+ let errorFields = [];
20210
+ for (const [field, _message] of Object.entries(formState.customErrorMapping)) {
20211
+ if (!!_message) {
20212
+ errorFields.push(_schema.properties[field].title);
20213
+ }
20214
+ }
20215
+ const pluralSuffix = errorFields.length > 1 ? "s" : "";
20216
+ const fields = humanReadableList(errorFields);
20217
+ const message = `Please resolve issue${pluralSuffix} on following field${pluralSuffix}: ${fields}`;
20218
+ error(message);
20219
+ _onError({
20220
+ errors: formState.customErrorMapping,
20221
+ message
20222
+ });
20223
+ return;
20224
+ }
20225
+ _onSubmit(...args);
20015
20226
  };
20016
20227
  const handleError = (...args) => {
20017
20228
  dispatchSubmitEvent();
@@ -20041,27 +20252,21 @@ const DynamicForm = ({
20041
20252
  validate: validate,
20042
20253
  transformErrors: transformErrorsProps || transformErrors,
20043
20254
  children: [renderBottom == null ? void 0 : renderBottom(), /*#__PURE__*/jsx(FormButtons, {
20044
- hidden: readonly || schema.readonly,
20045
- saveLabel: saveButtonText,
20255
+ hidden: readonly || _schema.readonly,
20256
+ saveLabel: _saveButtonText,
20046
20257
  submitStatus: submitStatus,
20047
20258
  showResetButton: showResetButton,
20048
- resetLabel: resetButtonText,
20259
+ resetLabel: _resetButtonText,
20049
20260
  onReset: onReset,
20050
20261
  showCancelButton: showCancelButton,
20051
- cancelLabel: cancelButtonText,
20262
+ cancelLabel: _cancelButtonText,
20052
20263
  onCancel: onCancel,
20053
20264
  showDeleteButton: showDeleteButton,
20054
- deleteLabel: deleteButtonText,
20265
+ deleteLabel: _deleteButtonText,
20055
20266
  onDelete: onDelete
20056
20267
  })]
20057
20268
  }, formState.key);
20058
20269
  };
20059
- DynamicForm.defaultProps = {
20060
- saveButtonText: "Submit",
20061
- cancelButtonText: "Cancel",
20062
- resetButtonText: "Reset",
20063
- disableSubmitButton: false
20064
- };
20065
20270
  DynamicForm.propTypes = {
20066
20271
  /** JSON based schema definition for the form. */
20067
20272
  schema: PropTypes.object.isRequired,
@@ -20075,8 +20280,6 @@ DynamicForm.propTypes = {
20075
20280
  onSubmit: PropTypes.func,
20076
20281
  /** Error handler. */
20077
20282
  onError: PropTypes.func,
20078
- /** Urls to be used for templates of dataSource */
20079
- actionUrls: PropTypes.object,
20080
20283
  /** Additional data form custom fields can be passed as formContext */
20081
20284
  formContext: PropTypes.object,
20082
20285
  /** Shows reset button */