aefis-core-ui 2.2.1-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
  });
@@ -11122,6 +11132,7 @@ const BusinessObjectPicker = _ref => {
11122
11132
  pageSize,
11123
11133
  idTemplate,
11124
11134
  shouldResetOnParametersChange,
11135
+ // TODO: replace this implementation with getNextPageParam function prop
11125
11136
  queryParamNames,
11126
11137
  enableInfinteScroll,
11127
11138
  renderAddItemForm,
@@ -11369,7 +11380,12 @@ const BusinessObjectPicker = _ref => {
11369
11380
  loading: status === "loading",
11370
11381
  options: props.data || _flatData,
11371
11382
  onChange: handleChange,
11372
- 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
+ ,
11373
11389
  getOptionLabel: getOptionLabel || getLabel,
11374
11390
  size: props.size,
11375
11391
  value: value,
@@ -14280,9 +14296,20 @@ TitleAndDescription.propTypes = {
14280
14296
  gutterBottom: PropTypes.bool
14281
14297
  };
14282
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
+ */
14283
14310
  const useComponentWillMount = callback => {
14284
14311
  const willMount = useRef(true);
14285
- if (willMount.current) callback == null ? void 0 : callback();
14312
+ if (willMount.current) callback();
14286
14313
  willMount.current = false;
14287
14314
  };
14288
14315
 
@@ -15231,50 +15258,68 @@ RubricDistributionChart.propTypes = {
15231
15258
  titleComponent: PropTypes.oneOf(["h1", "h2", "h3", "h4", "div", "p"])
15232
15259
  };
15233
15260
 
15234
- const moreThan = ruleValue => fieldValue => {
15261
+ const moreThan = ruleValue => ({
15262
+ fieldValue
15263
+ }) => {
15235
15264
  const isValid = fieldValue > ruleValue;
15236
15265
  if (!isValid) return `should be more than ${ruleValue}`;
15237
15266
  };
15238
- const moreThanOrEqual = ruleValue => fieldValue => {
15267
+ const moreThanOrEqual = ruleValue => ({
15268
+ fieldValue
15269
+ }) => {
15239
15270
  const isValid = fieldValue >= ruleValue;
15240
15271
  if (!isValid) return `should be more than to ${ruleValue}`;
15241
15272
  };
15242
- const lessThan = ruleValue => fieldValue => {
15273
+ const lessThan = ruleValue => ({
15274
+ fieldValue
15275
+ }) => {
15243
15276
  const isValid = fieldValue < ruleValue;
15244
15277
  if (!isValid) return `should be less than ${ruleValue}`;
15245
15278
  };
15246
- const lessThanOrEqual = ruleValue => fieldValue => {
15279
+ const lessThanOrEqual = ruleValue => ({
15280
+ fieldValue
15281
+ }) => {
15247
15282
  const isValid = fieldValue <= ruleValue;
15248
15283
  if (!isValid) return `should be less than or equal to ${ruleValue}`;
15249
15284
  };
15250
- const notEqual = ruleValue => fieldValue => {
15285
+ const notEqual = ruleValue => ({
15286
+ fieldValue
15287
+ }) => {
15251
15288
  const isValid = ruleValue.toString() !== (fieldValue == null ? void 0 : fieldValue.toString == null ? void 0 : fieldValue.toString());
15252
15289
  if (!isValid) return `should NOT be ${ruleValue}`;
15253
15290
  };
15254
- const url = () => fieldValue => {
15291
+ const url = () => ({
15292
+ fieldValue
15293
+ }) => {
15255
15294
  const UrlRegEx = /^(?:http(s)?:\/\/)?[\w.-]+(?:\.[\w\.-]+)+[\w\-\._~:/?#[\]@!\$&'\(\)\*\+,;=.]+$/;
15256
15295
  const isValid = UrlRegEx.test(fieldValue);
15257
15296
  if (!isValid) return `is NOT a valid URL`;
15258
15297
  };
15259
- const email = () => fieldValue => {
15298
+ const email = () => ({
15299
+ fieldValue
15300
+ }) => {
15260
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,}))$/;
15261
15302
  const isValid = EmailRegEx.test(fieldValue);
15262
15303
  if (!isValid) return `is NOT a valid email address`;
15263
15304
  };
15264
- const isInvalidDate = () => fieldValue => {
15305
+ const isInvalidDate = () => ({
15306
+ fieldValue
15307
+ }) => {
15265
15308
  const isValid = fieldValue !== "Invalid Date";
15266
15309
  if (!isValid) return "is invalid date";
15267
15310
  };
15268
- const required = () => fieldValue => {
15311
+ const required = () => ({
15312
+ fieldValue,
15313
+ schema
15314
+ }) => {
15269
15315
  const message = "is required";
15270
- if (Array.isArray(fieldValue) && fieldValue.length === 0) {
15271
- return message;
15272
- }
15273
- if (fieldValue == undefined || fieldValue == "") {
15274
- return message;
15275
- }
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;
15276
15319
  };
15277
- const isNumber = () => fieldValue => {
15320
+ const isNumber = () => ({
15321
+ fieldValue
15322
+ }) => {
15278
15323
  const message = "should be number";
15279
15324
  const isValid = !isNaN(fieldValue) &&
15280
15325
  // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
@@ -15282,7 +15327,9 @@ const isNumber = () => fieldValue => {
15282
15327
 
15283
15328
  if (!isValid) return message;
15284
15329
  };
15285
- const isNotNegativeNumber = () => fieldValue => {
15330
+ const isNotNegativeNumber = () => ({
15331
+ fieldValue
15332
+ }) => {
15286
15333
  const isValid = !isNaN(fieldValue) &&
15287
15334
  // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
15288
15335
  !isNaN(parseFloat(fieldValue)); // ...and ensure strings of whitespace fail
@@ -15290,21 +15337,49 @@ const isNotNegativeNumber = () => fieldValue => {
15290
15337
  if (isValid && parseFloat(fieldValue) < 0) return "should be positive number";
15291
15338
  if (!isValid) return "should be number";
15292
15339
  };
15293
- const characterLimitLessThan = ruleValue => fieldValue => {
15294
- // INFO: fasly values ("", undefined, null) are assumed to be to be 0
15295
- if (!fieldValue) return;
15296
- const isValid = fieldValue.length < ruleValue;
15297
- 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;
15298
15359
  };
15299
- const characterLimitMoreThan = ruleValue => fieldValue => {
15300
- const message = `should be more than ${ruleValue} characters`;
15301
-
15302
- // INFO: fasly values ("", undefined, null) are assumed to be to be 0
15303
- if (!fieldValue) return message;
15304
- 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;
15305
15378
  if (!isValid) return message;
15306
15379
  };
15307
15380
  const Rules = {
15381
+ maxLength,
15382
+ minLength,
15308
15383
  moreThan,
15309
15384
  moreThanOrEqual,
15310
15385
  lessThan,
@@ -15334,6 +15409,14 @@ const {
15334
15409
  formData: {}
15335
15410
  });
15336
15411
 
15412
+ const useSubmitted = () => {
15413
+ const [submitted, setSubmitted] = useState(false);
15414
+ useSubmitListener(() => {
15415
+ setSubmitted(true);
15416
+ });
15417
+ return submitted;
15418
+ };
15419
+
15337
15420
  const useStyles$3 = makeStyles(theme => ({
15338
15421
  button: {
15339
15422
  margin: theme.spacing(1)
@@ -15349,10 +15432,10 @@ const FormButtons = ({
15349
15432
  showCancelButton: _showCancelButton = false,
15350
15433
  showResetButton: _showResetButton = false,
15351
15434
  showDeleteButton: _showDeleteButton = false,
15352
- saveLabel,
15353
- cancelLabel,
15354
- resetLabel,
15355
- deleteLabel,
15435
+ saveLabel: _saveLabel = "Save",
15436
+ cancelLabel: _cancelLabel = "Cancel",
15437
+ resetLabel: _resetLabel = "Reset",
15438
+ deleteLabel: _deleteLabel = "Delete",
15356
15439
  hidden,
15357
15440
  submitStatus,
15358
15441
  onCancel,
@@ -15361,13 +15444,15 @@ const FormButtons = ({
15361
15444
  }) => {
15362
15445
  const classes = useStyles$3();
15363
15446
  const setFormState = useSetFormState();
15447
+ const customErrorMapping = useSelectFormState(formState => formState.customErrorMapping);
15448
+ const submitted = useSubmitted();
15364
15449
  let renderSaveButton = () => /*#__PURE__*/jsx(Button, {
15365
15450
  variant: "contained",
15366
15451
  color: "primary",
15367
15452
  type: "submit",
15368
- name: saveLabel,
15453
+ name: _saveLabel,
15369
15454
  className: classes.button,
15370
- children: saveLabel
15455
+ children: _saveLabel
15371
15456
  });
15372
15457
  if (submitStatus === "loading") {
15373
15458
  renderSaveButton = () => {
@@ -15377,7 +15462,7 @@ const FormButtons = ({
15377
15462
  type: "submit",
15378
15463
  className: classes.button,
15379
15464
  disabled: true,
15380
- name: saveLabel,
15465
+ name: _saveLabel,
15381
15466
  endIcon: /*#__PURE__*/jsx(CircularProgress, {
15382
15467
  color: "grey",
15383
15468
  size: 15
@@ -15386,18 +15471,19 @@ const FormButtons = ({
15386
15471
  });
15387
15472
  };
15388
15473
  }
15389
- if (submitStatus === "error") {
15474
+ const submitBlockedByCustomError = Object.values(customErrorMapping).findIndex(Boolean) !== -1;
15475
+ if (submitted && (submitStatus === "error" || submitBlockedByCustomError)) {
15390
15476
  renderSaveButton = () => {
15391
15477
  return /*#__PURE__*/jsx(Button, {
15392
15478
  variant: "contained",
15393
15479
  color: "primary",
15394
15480
  type: "submit",
15395
- name: saveLabel,
15481
+ name: _saveLabel,
15396
15482
  className: classes.button,
15397
15483
  endIcon: /*#__PURE__*/jsx(Error$1, {
15398
15484
  size: 15
15399
15485
  }),
15400
- children: saveLabel
15486
+ children: _saveLabel
15401
15487
  });
15402
15488
  };
15403
15489
  }
@@ -15410,7 +15496,7 @@ const FormButtons = ({
15410
15496
  }, {
15411
15497
  children: [_showResetButton && /*#__PURE__*/jsx(Button, {
15412
15498
  className: classes.button,
15413
- name: resetLabel,
15499
+ name: _resetLabel,
15414
15500
  onClick: () => {
15415
15501
  onReset == null ? void 0 : onReset();
15416
15502
  setFormState(prevState => _extends({}, prevState, {
@@ -15418,26 +15504,20 @@ const FormButtons = ({
15418
15504
  key: +new Date()
15419
15505
  }));
15420
15506
  },
15421
- children: resetLabel
15507
+ children: _resetLabel
15422
15508
  }), _showCancelButton && /*#__PURE__*/jsx(Button, {
15423
- name: cancelLabel,
15509
+ name: _cancelLabel,
15424
15510
  onClick: onCancel,
15425
15511
  className: classes.button,
15426
- children: cancelLabel
15512
+ children: _cancelLabel
15427
15513
  }), _showDeleteButton && /*#__PURE__*/jsx(Button, {
15428
- name: deleteLabel,
15514
+ name: _deleteLabel,
15429
15515
  onClick: onDelete,
15430
15516
  className: classes.button,
15431
- children: deleteLabel
15517
+ children: _deleteLabel
15432
15518
  }), !disabled && renderSaveButton()]
15433
15519
  }));
15434
15520
  };
15435
- FormButtons.defaultProps = {
15436
- saveLabel: "Submit",
15437
- cancelLabel: "Cancel",
15438
- resetLabel: "Reset",
15439
- deleteLabel: "Delete"
15440
- };
15441
15521
  FormButtons.propTypes = {
15442
15522
  cancelLabel: PropTypes.string,
15443
15523
  disabled: PropTypes.any,
@@ -15509,51 +15589,6 @@ const withEmptyValue = Component => {
15509
15589
  });
15510
15590
  };
15511
15591
 
15512
- const windowKeys = Object.keys(window).filter(key => {
15513
- try {
15514
- Function.apply(null, [key, "return;"]);
15515
- return true;
15516
- } catch (e) {
15517
- return false;
15518
- }
15519
- });
15520
-
15521
- /**
15522
- * evaluates
15523
- * @param {string} code
15524
- * @param {object} context
15525
- * @param {object} options
15526
- * @param {function} options.falbback
15527
- *
15528
- * @returns
15529
- */
15530
- const safeEval = (code, context, options) => {
15531
- const keys = Object.keys(context);
15532
-
15533
- // TODO: optimize
15534
- const allParams = keys.concat(windowKeys, [`"use strict"; return ${code}`]);
15535
- try {
15536
- const fn = Function.apply(null, allParams);
15537
- const params = keys.map(key => context[key]);
15538
- const res = fn.apply(null, params);
15539
- return res;
15540
- } catch (e) {
15541
- (options == null ? void 0 : options.fallback == null ? void 0 : options.fallback(e)) || console.log("Eval Error : ", e, {
15542
- code,
15543
- context,
15544
- options
15545
- });
15546
- }
15547
- };
15548
- const lazyEval = (code, context) => {
15549
- return new Promise((resolve, reject) => {
15550
- const result = safeEval(code, context, {
15551
- fallback: reject
15552
- });
15553
- resolve(result);
15554
- });
15555
- };
15556
-
15557
15592
  const {
15558
15593
  useSelectState: useSelectFieldState,
15559
15594
  useSetState: useSetFieldState,
@@ -15672,14 +15707,113 @@ CustomFieldTemplate.propTypes = {
15672
15707
  };
15673
15708
  var CustomFieldTemplate$1 = /*#__PURE__*/React.memo(withFieldStore(CustomFieldTemplate));
15674
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
+
15675
15795
  const withValidate = Component => {
15676
15796
  const MemoizedComponent = /*#__PURE__*/React.memo(Component);
15677
15797
  return /*#__PURE__*/forwardRef((props, ref) => {
15678
- var _props$uiSchema;
15679
- const rules = ((_props$uiSchema = props.uiSchema) == null ? void 0 : _props$uiSchema["rules"]) || [];
15680
- const isWidget = !!props.id;
15681
- 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;
15682
15815
  const Rules = useSelectFormState(state => state.rules);
15816
+ const scopedEval = useScopedEval(_extends({}, Rules));
15683
15817
  const setFieldState = useSetFieldState();
15684
15818
  const setFormState = useSetFormState();
15685
15819
  const [submitted, setSubmitted] = useState(false);
@@ -15689,13 +15823,13 @@ const withValidate = Component => {
15689
15823
  if (!rules) return [];
15690
15824
  const evaluatedRules = rules.map(rule => {
15691
15825
  const isFunctionCall = rule.slice(-1) === ")";
15692
- const ruleFn = safeEval(rule, Rules);
15826
+ const ruleFn = scopedEval(rule, Rules);
15693
15827
  return isFunctionCall ? ruleFn : ruleFn();
15694
15828
  });
15695
15829
 
15696
15830
  // TODO: this is bad practise, implementation should be moved to
15697
15831
  // inside widget/field when withValidate replaced with custom hook
15698
- if (props.uiSchema["ui:widget"] === "DateWidget" || props.uiSchema["ui:field"] === "DateSelect") {
15832
+ if (uiSchema["ui:widget"] === "DateWidget" || uiSchema["ui:field"] === "DateSelect") {
15699
15833
  evaluatedRules.push(Rules.isInvalidDate());
15700
15834
  }
15701
15835
  return evaluatedRules;
@@ -15712,25 +15846,33 @@ const withValidate = Component => {
15712
15846
  if (!rules) return;
15713
15847
  const isEmpty = formItemValue == undefined || formItemValue === "";
15714
15848
  const skipValidationOnEmptyValue = isEmpty && !isRequired;
15715
- const message = !skipValidationOnEmptyValue && evalRuleArray(formItemValue)(ruleArray);
15849
+ const message = !skipValidationOnEmptyValue && evalRuleArray({
15850
+ fieldValue: formItemValue,
15851
+ formContext,
15852
+ formData,
15853
+ uiSchema,
15854
+ schema
15855
+ })(ruleArray);
15716
15856
  setFieldState(state => _extends({}, state, {
15717
15857
  errorMessage: message
15718
15858
  }));
15719
15859
 
15720
- // TODO: cleans the idPrefix if widget (not field). Custom idPrefix
15721
- // defination might effect here. It should be tested and updated
15722
- // accordingly
15723
- const fieldName = isWidget ? props.id.slice(5) : props.name;
15724
-
15725
15860
  // INFO: Adding item to array template does not work without
15726
15861
  // setFormState wrapped with setTimeout
15727
15862
  setTimeout(() => {
15728
- setFormState(state => _extends({}, state, {
15729
- customErrorMapping: _extends({}, state.customErrorMapping, {
15730
- [fieldName]: !!message
15731
- })
15732
- }));
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
+ });
15733
15874
  });
15875
+ // TODO: add other dependecies
15734
15876
  }, [formItemValue]);
15735
15877
  const handleOnchange = (...args) => {
15736
15878
  setTouched(true);
@@ -15743,13 +15885,31 @@ const withValidate = Component => {
15743
15885
  }));
15744
15886
  });
15745
15887
  };
15746
- const evalRuleArray = fieldValue => rules => {
15888
+ const evalRuleArray = ({
15889
+ fieldValue,
15890
+ schema,
15891
+ uiSchema,
15892
+ formContext,
15893
+ formData
15894
+ }) => rules => {
15747
15895
  for (let rule of rules) {
15748
- const message = rule(fieldValue);
15896
+ const message = rule({
15897
+ fieldValue,
15898
+ schema,
15899
+ uiSchema,
15900
+ formContext,
15901
+ formData
15902
+ });
15749
15903
  if (message != undefined) return message;
15750
15904
  }
15751
15905
  };
15752
15906
 
15907
+ /**
15908
+ * TODO:
15909
+ * - do two version of it seperately for widget and field eg. withValidate (for field) and withValidateWidget
15910
+ *
15911
+ */
15912
+
15753
15913
  const commonWidgetHOCs = [withValidate, withEmptyValue];
15754
15914
  const commonFieldHOCs = [withValidate, withEmptyValue];
15755
15915
 
@@ -16389,12 +16549,7 @@ const ReadOnlyView = ({
16389
16549
  sx: {
16390
16550
  fontStyle: "italic"
16391
16551
  },
16392
- description: /*#__PURE__*/jsx(Box$2, {
16393
- sx: {
16394
- paddingRight: 0.5
16395
- },
16396
- children: _emptyViewText
16397
- }),
16552
+ description: _emptyViewText,
16398
16553
  showIcon: false
16399
16554
  });
16400
16555
  }
@@ -16717,7 +16872,9 @@ const useReadOnly = uiSchema => {
16717
16872
  const selector = useCallback(state => {
16718
16873
  const defaultValue = state.readonly || state.schema.readonly;
16719
16874
  if (!code) return defaultValue;
16720
- const evaluatedReadyOnly = safeEval(code, state);
16875
+
16876
+ // TODO: change it with useScopedEval
16877
+ const evaluatedReadyOnly = scopedEval(code, state);
16721
16878
  return defaultValue || evaluatedReadyOnly;
16722
16879
  }, [code]);
16723
16880
  const evaluatedReadyOnly = useSelectFormState(selector);
@@ -16806,13 +16963,11 @@ const dateInputStyles = {
16806
16963
  const DateSelect = props => {
16807
16964
  var _useSelector, _useSelector2;
16808
16965
  const {
16809
- id,
16810
16966
  required,
16811
16967
  schema,
16812
16968
  formData,
16813
16969
  onChange,
16814
16970
  rawErrors,
16815
- options,
16816
16971
  disabled
16817
16972
  } = props;
16818
16973
  const [selectedDate, setSelectedDate] = useState(null);
@@ -16866,7 +17021,10 @@ const DateSelect = props => {
16866
17021
  const maxDateRaw = (_useSelector2 = useSelector(props.uiSchema["select::maxDate"])) == null ? void 0 : _useSelector2.date;
16867
17022
  const maxDate = maxDateRaw ? parse$1(maxDateRaw, "MM-dd-yyyy", new Date()) : undefined;
16868
17023
  const isReadOnly = useReadOnly(props.uiSchema);
16869
- if (isReadOnly) return /*#__PURE__*/jsx(DateSelectReadOnly$1, _extends({}, props));
17024
+ if (isReadOnly) return /*#__PURE__*/jsx(DateSelectReadOnly$1, {
17025
+ formData: formData,
17026
+ schema: schema
17027
+ });
16870
17028
  return /*#__PURE__*/jsxs(FormControl, {
16871
17029
  disabled: disabled || schema.disabled,
16872
17030
  required: required,
@@ -16924,7 +17082,6 @@ const DateSelect = props => {
16924
17082
  value: typeof selectedDate === "undefined" ? null : selectedDate,
16925
17083
  onChange: handleDateChange,
16926
17084
  disabled: disabled,
16927
- inputLabe: true,
16928
17085
  renderInput: params => /*#__PURE__*/jsx(TextField, _extends({}, params, {
16929
17086
  inputProps: _extends({}, params.inputProps, {
16930
17087
  type: "text"
@@ -17540,8 +17697,8 @@ const withEvalDisable = () => Component => {
17540
17697
  const code = (_props$uiSchema = props.uiSchema) == null ? void 0 : _props$uiSchema["ui:disabled"];
17541
17698
  if (!code) return props.disabled;
17542
17699
 
17543
- // TODO: use lazyEval
17544
- return safeEval(code, formState);
17700
+ // TODO: replace with useScopedEval
17701
+ return scopedEval(code, formState);
17545
17702
  }, [formState.formData, formState.formContext, props.disabled]);
17546
17703
  return /*#__PURE__*/jsx(MemoizedComponent, _extends({}, props, {
17547
17704
  disabled: isDisabled
@@ -17856,7 +18013,10 @@ var SelectField$1 = compose(HOCs$8)(SelectField);
17856
18013
  // check this topic to catch consistant view with autocmplete
17857
18014
  // https://stackoverflow.com/questions/63047684/material-ui-select-menu-with-end-adornment
17858
18015
 
18016
+ const useFormStateScopedEval = () => useScopedEval(formStateScopeMap);
18017
+
17859
18018
  const useProcessCondition = formState => {
18019
+ const safeEval = useFormStateScopedEval();
17860
18020
  const conditions = useMemo(() => {
17861
18021
  const {
17862
18022
  schema,
@@ -17882,47 +18042,48 @@ const useProcessCondition = formState => {
17882
18042
  const newFormState = useMemo(() => {
17883
18043
  const {
17884
18044
  schema,
17885
- formData
18045
+ formData,
18046
+ customErrorMapping
17886
18047
  } = formState;
17887
- let changed = false;
17888
- let newRequired = schema.required ? [...schema.required] : [];
18048
+ let newRequiredItemList = schema.required ? [...schema.required] : [];
17889
18049
  let newProperties = _extends({}, schema.properties);
18050
+ let newCustomErrorMapping = _extends({}, customErrorMapping);
17890
18051
  let newFormData = formData ? _extends({}, formData) : {};
17891
18052
  conditions.forEach(item => {
17892
- const nextOperation = safeEval(item.condition, formState) ? "added" : "deleted";
17893
- if (item.lastOperation !== nextOperation) {
17894
- changed = true;
17895
- }
17896
- if (nextOperation === "added") {
17897
- item.lastOperation = nextOperation;
18053
+ const nextOperation = safeEval(item.condition, formState) ? "add" : "delete";
18054
+ if (nextOperation === "add") {
17898
18055
  if (item.isRequired) {
17899
- newRequired.indexOf(item.key) === -1 && newRequired.push(item.key);
18056
+ newRequiredItemList.indexOf(item.key) === -1 && newRequired.push(item.key);
17900
18057
  }
17901
18058
  newProperties[item.key] = item.schema;
17902
- } else {
17903
- item.lastOperation = nextOperation;
18059
+ }
18060
+ if (nextOperation === "delete") {
17904
18061
  if (item.isRequired) {
17905
- newRequired = newRequired.filter(key => key !== item.key);
18062
+ newRequiredItemList = newRequiredItemList.filter(key => key !== item.key);
17906
18063
  }
17907
18064
  delete newProperties[item.key];
17908
18065
  delete newFormData[item.key];
18066
+ delete customErrorMapping[item.key];
17909
18067
  }
17910
18068
  });
17911
- if (changed) {
17912
- const newSchema = _extends({}, schema, {
17913
- properties: _extends({}, newProperties),
17914
- required: [...newRequired]
17915
- });
17916
- return _extends({}, formState, {
17917
- schema: newSchema,
17918
- formData: newFormData
17919
- });
17920
- }
17921
- return formState;
17922
- }, [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]);
17923
18079
  return newFormState;
17924
18080
  };
17925
18081
 
18082
+ /**
18083
+ * TODO:
18084
+ * remove required list field
18085
+ */
18086
+
17926
18087
  const useStyles$1 = makeStyles$1(theme => ({
17927
18088
  fab: {
17928
18089
  margin: theme.spacing(1)
@@ -19467,7 +19628,7 @@ TextWidgetBase.propTypes = {
19467
19628
  };
19468
19629
 
19469
19630
  const _excluded = ["onChange"];
19470
- const TextWidgetReadOnly$1 = props => {
19631
+ const TextWidgetReadOnly$1 = function TextWidgetReadOnly(props) {
19471
19632
  const {
19472
19633
  options: {
19473
19634
  prefix = "$",
@@ -19496,7 +19657,15 @@ const TextWidgetReadOnly$1 = props => {
19496
19657
  });
19497
19658
  };
19498
19659
  TextWidgetReadOnly$1.propTypes = {
19499
- 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,
19500
19669
  value: PropTypes.any
19501
19670
  };
19502
19671
  const CurrencyWidget = props => {
@@ -19697,7 +19866,6 @@ SelectWidget.propTypes = {
19697
19866
  id: PropTypes.any,
19698
19867
  onChange: PropTypes.func,
19699
19868
  options: PropTypes.any,
19700
- rawErrors: PropTypes.array,
19701
19869
  required: PropTypes.any,
19702
19870
  schema: PropTypes.shape({
19703
19871
  disabled: PropTypes.any,
@@ -19881,6 +20049,8 @@ ValidateWidget.propTypes = {
19881
20049
  };
19882
20050
  var ValidateWidget$1 = withReadyOnly(ValidateWidget);
19883
20051
 
20052
+ const humanReadableList = a => [a.slice(0, -1).join(", "), a.slice(-1)[0]].join(a.length < 2 ? "" : " and ");
20053
+
19884
20054
  const {
19885
20055
  useDispatcher: useSubmitDispatcher,
19886
20056
  useListener: useSubmitListener,
@@ -19921,27 +20091,43 @@ const defaultFields = {
19921
20091
  */
19922
20092
  };
19923
20093
 
20094
+ const useProcessedFormState = () => {
20095
+ const formState = useSelectFormState();
20096
+ return useProcessCondition(formState);
20097
+ };
19924
20098
  const defaultTemplates = {
19925
20099
  ArrayFieldTemplate: ArrayFieldTemplate$1
19926
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
+ };
19927
20113
  const DynamicForm = ({
19928
- schema,
19929
- uiSchema,
19930
- saveButtonText,
19931
- cancelButtonText,
19932
- resetButtonText,
19933
- deleteButtonText,
19934
- 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 = {},
19935
20121
  widgets: widgetsProp,
19936
20122
  fields: fieldsProp,
19937
20123
  templates: templatesProp,
19938
- onChange,
19939
- actionUrls,
20124
+ onChange: _onChange = fn,
20125
+ onError: _onError = fn,
20126
+ onSubmit: _onSubmit = fn,
19940
20127
  dataSources: _dataSources = [],
19941
20128
  formContext: formContextProp,
19942
20129
  initialFormContext,
19943
- onSubmit,
19944
- disableSubmit,
20130
+ disableSubmit: _disableSubmit = false,
19945
20131
  readonly,
19946
20132
  formDataStatus,
19947
20133
  submitStatus,
@@ -19958,33 +20144,40 @@ const DynamicForm = ({
19958
20144
  renderBottom
19959
20145
  }) => {
19960
20146
  const setFormState = useSetFormState();
20147
+ const {
20148
+ error
20149
+ } = useNotify();
19961
20150
  useComponentWillMount(() => {
19962
- setFormState(prev => _extends({}, prev, {
19963
- schema,
19964
- uiSchema,
20151
+ const initialState = {
20152
+ schema: _schema,
20153
+ uiSchema: _uiSchema,
19965
20154
  initialFormData: initialFormData,
19966
20155
  formData: initialFormData,
19967
- actionUrls,
19968
20156
  formContext: initialFormContext || formContextProp,
19969
20157
  readonly,
19970
20158
  dataSources: _dataSources,
19971
20159
  customErrorMapping: {},
19972
20160
  rules: _extends({}, _rules, Rules)
19973
- }));
20161
+ };
20162
+ setFormState(() => initialState);
19974
20163
  });
19975
- const formState = useSelectFormState();
20164
+ const formState = useProcessedFormState();
20165
+
20166
+ // useDependencyChange(() => {}, [processedState]);
20167
+
19976
20168
  const widgets = _extends({}, defaultWidgets, widgetsProp);
19977
20169
  const fields = _extends({}, defaultFields, fieldsProp);
19978
20170
  const templates = _extends({}, defaultTemplates, templatesProp);
19979
20171
  const dispatchSubmitEvent = useSubmitDispatcher();
19980
- const newFormState = useProcessCondition(formState);
19981
20172
  useComponentWillMount(() => {
19982
20173
  const configs = getConfigurationParameters();
19983
20174
  registerDataSources(_dataSources, configs);
19984
20175
  });
19985
- useEffect(() => {
19986
- setFormState(prev => _extends({}, prev, newFormState));
19987
- }, [newFormState]);
20176
+
20177
+ // useEffect(() => {
20178
+ // setFormState((prev) => ({ ...prev, ...newFormState }));
20179
+ // }, [newFormState]);
20180
+
19988
20181
  useEffect(() => {
19989
20182
  setFormState(prev => _extends({}, prev, {
19990
20183
  formContext: formContextProp
@@ -20001,19 +20194,35 @@ const DynamicForm = ({
20001
20194
  const [{
20002
20195
  formData
20003
20196
  }] = args;
20004
- setFormState(prevState => _extends({}, prevState, {
20005
- formData
20006
- }));
20007
- onChange == null ? void 0 : onChange(...args);
20197
+ setFormState(prevState => {
20198
+ return _extends({}, prevState, {
20199
+ formData
20200
+ });
20201
+ });
20202
+ _onChange == null ? void 0 : _onChange(...args);
20008
20203
  };
20009
20204
  const handleSubmit = (...args) => {
20010
- if (disableSubmit) {
20011
- return;
20012
- }
20205
+ if (_disableSubmit) return;
20013
20206
  dispatchSubmitEvent(...args);
20014
20207
  const submitBlockedByCustomError = Object.values(formState.customErrorMapping).findIndex(Boolean) !== -1;
20015
- if (submitBlockedByCustomError) return;
20016
- 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);
20017
20226
  };
20018
20227
  const handleError = (...args) => {
20019
20228
  dispatchSubmitEvent();
@@ -20043,27 +20252,21 @@ const DynamicForm = ({
20043
20252
  validate: validate,
20044
20253
  transformErrors: transformErrorsProps || transformErrors,
20045
20254
  children: [renderBottom == null ? void 0 : renderBottom(), /*#__PURE__*/jsx(FormButtons, {
20046
- hidden: readonly || schema.readonly,
20047
- saveLabel: saveButtonText,
20255
+ hidden: readonly || _schema.readonly,
20256
+ saveLabel: _saveButtonText,
20048
20257
  submitStatus: submitStatus,
20049
20258
  showResetButton: showResetButton,
20050
- resetLabel: resetButtonText,
20259
+ resetLabel: _resetButtonText,
20051
20260
  onReset: onReset,
20052
20261
  showCancelButton: showCancelButton,
20053
- cancelLabel: cancelButtonText,
20262
+ cancelLabel: _cancelButtonText,
20054
20263
  onCancel: onCancel,
20055
20264
  showDeleteButton: showDeleteButton,
20056
- deleteLabel: deleteButtonText,
20265
+ deleteLabel: _deleteButtonText,
20057
20266
  onDelete: onDelete
20058
20267
  })]
20059
20268
  }, formState.key);
20060
20269
  };
20061
- DynamicForm.defaultProps = {
20062
- saveButtonText: "Submit",
20063
- cancelButtonText: "Cancel",
20064
- resetButtonText: "Reset",
20065
- disableSubmitButton: false
20066
- };
20067
20270
  DynamicForm.propTypes = {
20068
20271
  /** JSON based schema definition for the form. */
20069
20272
  schema: PropTypes.object.isRequired,
@@ -20077,8 +20280,6 @@ DynamicForm.propTypes = {
20077
20280
  onSubmit: PropTypes.func,
20078
20281
  /** Error handler. */
20079
20282
  onError: PropTypes.func,
20080
- /** Urls to be used for templates of dataSource */
20081
- actionUrls: PropTypes.object,
20082
20283
  /** Additional data form custom fields can be passed as formContext */
20083
20284
  formContext: PropTypes.object,
20084
20285
  /** Shows reset button */