@bpmn-io/form-js-viewer 1.8.1 → 1.8.4

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.
package/dist/index.es.js CHANGED
@@ -8,8 +8,9 @@ import { createContext, createElement, Fragment as Fragment$1, render } from 'pr
8
8
  import isEqual from 'lodash/isEqual';
9
9
  import flatpickr from 'flatpickr';
10
10
  import * as React from 'preact/compat';
11
- import { useEffect as useEffect$1, createPortal } from 'preact/compat';
11
+ import { createPortal } from 'preact/compat';
12
12
  import DOMPurify from 'dompurify';
13
+ import { isEqual as isEqual$1 } from 'lodash';
13
14
  import { Injector } from 'didi';
14
15
  import { parseExpression, parseUnaryTests, evaluate, unaryTest } from 'feelin';
15
16
  import { evaluate as evaluate$1, parser, buildSimpleTree } from 'feelers';
@@ -352,10 +353,10 @@ class FeelersTemplating {
352
353
  }
353
354
 
354
355
  /**
355
- * @typedef {Object} ExpressionWithDepth
356
- * @property {number} depth - The depth of the expression in the syntax tree.
357
- * @property {string} expression - The extracted expression
358
- */
356
+ * @typedef {Object} ExpressionWithDepth
357
+ * @property {number} depth - The depth of the expression in the syntax tree.
358
+ * @property {string} expression - The extracted expression
359
+ */
359
360
 
360
361
  /**
361
362
  * Extracts all feel expressions in the template along with their depth in the syntax tree.
@@ -1009,11 +1010,11 @@ const getDOMPurifyConfig = sanitizeStyleTags => {
1009
1010
  };
1010
1011
  };
1011
1012
 
1012
- /**
1013
- * A custom hook to build up security attributes from form configuration.
1014
- *
1015
- * @param {Object} security - The security configuration.
1016
- * @returns {Array} - Returns a tuple with sandbox and allow attributes.
1013
+ /**
1014
+ * A custom hook to build up security attributes from form configuration.
1015
+ *
1016
+ * @param {Object} security - The security configuration.
1017
+ * @returns {Array} - Returns a tuple with sandbox and allow attributes.
1017
1018
  */
1018
1019
  function useSecurityAttributesMap(security) {
1019
1020
  const securityMemoized = useDeepCompareMemoize(security);
@@ -1300,17 +1301,6 @@ function useFlushDebounce(func) {
1300
1301
  return [debounceFunc, flushFunc];
1301
1302
  }
1302
1303
 
1303
- function useEffectOnChange(value, callback, dependencies = []) {
1304
- const previousValue = usePrevious(value);
1305
- useEffect$1(() => {
1306
- if (value !== previousValue) {
1307
- callback();
1308
- }
1309
-
1310
- // eslint-disable-next-line react-hooks/exhaustive-deps
1311
- }, [value, ...dependencies]);
1312
- }
1313
-
1314
1304
  /**
1315
1305
  * Template a string reactively based on form data. If the string is not a template, it is returned as is.
1316
1306
  * Memoised to minimize re-renders
@@ -1501,6 +1491,18 @@ function formatTimezoneOffset(minutes) {
1501
1491
  function isInvalidDateString(value) {
1502
1492
  return isNaN(new Date(Date.parse(value)).getTime());
1503
1493
  }
1494
+ function getNullDateTime() {
1495
+ return {
1496
+ date: new Date(Date.parse(null)),
1497
+ time: null
1498
+ };
1499
+ }
1500
+ function isValidDate(date) {
1501
+ return date && !isNaN(date.getTime());
1502
+ }
1503
+ function isValidTime(time) {
1504
+ return !isNaN(parseInt(time));
1505
+ }
1504
1506
  function _getSignedPaddedHours(minutes) {
1505
1507
  if (minutes > 0) {
1506
1508
  return '-' + _getZeroPaddedString(Math.floor(minutes / 60));
@@ -1939,6 +1941,7 @@ function FormField(props) {
1939
1941
  } = props;
1940
1942
  const formFields = useService('formFields'),
1941
1943
  viewerCommands = useService('viewerCommands', false),
1944
+ formFieldInstanceRegistry = useService('formFieldInstanceRegistry', false),
1942
1945
  pathRegistry = useService('pathRegistry'),
1943
1946
  eventBus = useService('eventBus'),
1944
1947
  form = useService('form');
@@ -1965,6 +1968,7 @@ function FormField(props) {
1965
1968
  throw new Error(`cannot render field <${field.type}>`);
1966
1969
  }
1967
1970
  const fieldConfig = FormFieldComponent.config;
1971
+ const localExpressionContext = useContext(LocalExpressionContext);
1968
1972
  const valuePath = useMemo(() => pathRegistry.getValuePath(field, {
1969
1973
  indexes
1970
1974
  }), [field, indexes, pathRegistry]);
@@ -1974,6 +1978,22 @@ function FormField(props) {
1974
1978
 
1975
1979
  // add precedence: global readonly > form field disabled
1976
1980
  const disabled = !properties.readOnly && (properties.disabled || field.disabled || false);
1981
+ const hidden = useCondition(field.conditional && field.conditional.hide || null);
1982
+
1983
+ // register form field instance
1984
+ useEffect(() => {
1985
+ if (formFieldInstanceRegistry && !hidden) {
1986
+ const instanceId = formFieldInstanceRegistry.add({
1987
+ id: field.id,
1988
+ expressionContextInfo: localExpressionContext,
1989
+ valuePath,
1990
+ indexes
1991
+ });
1992
+ return () => {
1993
+ formFieldInstanceRegistry.remove(instanceId);
1994
+ };
1995
+ }
1996
+ }, [formFieldInstanceRegistry, field.id, localExpressionContext, valuePath, indexes, hidden]);
1977
1997
 
1978
1998
  // ensures the initial validation behavior can be re-triggered upon form reset
1979
1999
  useEffect(() => {
@@ -1991,7 +2011,8 @@ function FormField(props) {
1991
2011
  };
1992
2012
  }, [eventBus, viewerCommands]);
1993
2013
  useEffect(() => {
1994
- if (initialValidationTrigger && initialValue) {
2014
+ const hasInitialValue = initialValue && !isEqual(initialValue, []);
2015
+ if (initialValidationTrigger && hasInitialValue) {
1995
2016
  setInitialValidationTrigger(false);
1996
2017
  viewerCommands.updateFieldValidation(field, initialValue, indexes);
1997
2018
  }
@@ -2011,7 +2032,6 @@ function FormField(props) {
2011
2032
  formField: field
2012
2033
  });
2013
2034
  }, [eventBus, field]);
2014
- const hidden = useCondition(field.conditional && field.conditional.hide || null);
2015
2035
  const onChangeIndexed = useCallback(update => {
2016
2036
  // any data change will trigger validation
2017
2037
  setInitialValidationTrigger(false);
@@ -2156,7 +2176,7 @@ function RowsRenderer(props) {
2156
2176
  Row
2157
2177
  } = useContext(FormRenderContext);
2158
2178
  return jsxs(Fragment, {
2159
- children: [" ", rows.map(row => {
2179
+ children: [' ', rows.map(row => {
2160
2180
  const {
2161
2181
  components = []
2162
2182
  } = row;
@@ -2182,7 +2202,7 @@ function RowsRenderer(props) {
2182
2202
  });
2183
2203
  })
2184
2204
  });
2185
- }), " "]
2205
+ }), ' ']
2186
2206
  });
2187
2207
  }
2188
2208
 
@@ -2312,23 +2332,23 @@ function InputAdorner(props) {
2312
2332
  'fjs-disabled': disabled,
2313
2333
  'fjs-readonly': readonly
2314
2334
  }, {
2315
- 'hasErrors': hasErrors
2335
+ hasErrors: hasErrors
2316
2336
  }),
2317
2337
  ref: rootRef,
2318
2338
  children: [pre && jsxs("span", {
2319
2339
  class: "fjs-input-adornment border-right border-radius-left",
2320
2340
  onClick: onAdornmentClick,
2321
- children: [" ", isString(pre) ? jsx("span", {
2341
+ children: [' ', isString(pre) ? jsx("span", {
2322
2342
  class: "fjs-input-adornment-text",
2323
2343
  children: pre
2324
- }) : pre, " "]
2344
+ }) : pre, ' ']
2325
2345
  }), children, post && jsxs("span", {
2326
2346
  class: "fjs-input-adornment border-left border-radius-right",
2327
2347
  onClick: onAdornmentClick,
2328
- children: [" ", isString(post) ? jsx("span", {
2348
+ children: [' ', isString(post) ? jsx("span", {
2329
2349
  class: "fjs-input-adornment-text",
2330
2350
  children: post
2331
- }) : post, " "]
2351
+ }) : post, ' ']
2332
2352
  })]
2333
2353
  });
2334
2354
  }
@@ -2377,7 +2397,9 @@ function Datepicker(props) {
2377
2397
  clickOpens: false,
2378
2398
  // TODO: support dates prior to 1900 (https://github.com/bpmn-io/form-js/issues/533)
2379
2399
  minDate: disallowPassedDates ? 'today' : '01/01/1900',
2380
- errorHandler: () => {/* do nothing, we expect the values to sometimes be erronous and we don't want warnings polluting the console */}
2400
+ errorHandler: () => {
2401
+ /* do nothing, we expect the values to sometimes be erronous and we don't want warnings polluting the console */
2402
+ }
2381
2403
  };
2382
2404
  const instance = flatpickr(dateInputRef.current, config);
2383
2405
  setFlatpickrInstance(instance);
@@ -2482,7 +2504,7 @@ function Datepicker(props) {
2482
2504
  });
2483
2505
  }
2484
2506
 
2485
- var _path$v, _path2$5;
2507
+ var _path$v, _path2$4;
2486
2508
  function _extends$w() { _extends$w = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$w.apply(this, arguments); }
2487
2509
  var SvgClock = function SvgClock(props) {
2488
2510
  return /*#__PURE__*/React.createElement("svg", _extends$w({
@@ -2494,7 +2516,7 @@ var SvgClock = function SvgClock(props) {
2494
2516
  }, props), _path$v || (_path$v = /*#__PURE__*/React.createElement("path", {
2495
2517
  fill: "currentColor",
2496
2518
  d: "M13 14.41 18.59 20 20 18.59l-5-5.01V5h-2v9.41Z"
2497
- })), _path2$5 || (_path2$5 = /*#__PURE__*/React.createElement("path", {
2519
+ })), _path2$4 || (_path2$4 = /*#__PURE__*/React.createElement("path", {
2498
2520
  fill: "currentColor",
2499
2521
  fillRule: "evenodd",
2500
2522
  d: "M6.222 25.64A14 14 0 1 0 21.778 2.36 14 14 0 0 0 6.222 25.64ZM7.333 4.023a12 12 0 1 1 13.334 19.955A12 12 0 0 1 7.333 4.022Z",
@@ -2585,7 +2607,7 @@ function DropdownList(props) {
2585
2607
  children: [values.length > 0 && values.map((v, i) => {
2586
2608
  return jsx("div", {
2587
2609
  class: classNames('fjs-dropdownlist-item', {
2588
- 'focused': focusedValueIndex === i
2610
+ focused: focusedValueIndex === i
2589
2611
  }),
2590
2612
  onMouseMove: mouseControl ? undefined : e => onMouseMovedInKeyboardMode(e, i),
2591
2613
  onMouseEnter: mouseControl ? () => setFocusedValueIndex(i) : undefined,
@@ -2737,11 +2759,9 @@ function Timepicker(props) {
2737
2759
  disabled: disabled,
2738
2760
  readOnly: readonly,
2739
2761
  placeholder: use24h ? 'hh:mm' : 'hh:mm ?m',
2740
- autoComplete: "off"
2741
-
2742
- // @ts-ignore
2743
- ,
2762
+ autoComplete: "off",
2744
2763
  onInput: e => {
2764
+ // @ts-expect-error
2745
2765
  setRawValue(e.target.value);
2746
2766
  useDropdown && setDropdownIsOpen(false);
2747
2767
  },
@@ -2795,14 +2815,8 @@ function Datetime(props) {
2795
2815
  formId
2796
2816
  } = useContext(FormContext);
2797
2817
  const dateTimeGroupRef = useRef();
2798
- const getNullDateTime = () => ({
2799
- date: new Date(Date.parse(null)),
2800
- time: null
2801
- });
2802
2818
  const [dateTime, setDateTime] = useState(getNullDateTime());
2803
2819
  const [dateTimeUpdateRequest, setDateTimeUpdateRequest] = useState(null);
2804
- const isValidDate = date => date && !isNaN(date.getTime());
2805
- const isValidTime = time => !isNaN(parseInt(time));
2806
2820
  const useDatePicker = useMemo(() => subtype === DATETIME_SUBTYPES.DATE || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
2807
2821
  const useTimePicker = useMemo(() => subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME, [subtype]);
2808
2822
  const onDateTimeBlur = useCallback(e => {
@@ -2857,11 +2871,14 @@ function Datetime(props) {
2857
2871
  } else if (subtype === DATETIME_SUBTYPES.DATETIME && isValidDate(date) && isValidTime(time)) {
2858
2872
  newDateTimeValue = serializeDateTime(date, time, timeSerializingFormat);
2859
2873
  }
2874
+ if (value === newDateTimeValue) {
2875
+ return;
2876
+ }
2860
2877
  onChange({
2861
2878
  value: newDateTimeValue,
2862
2879
  field
2863
2880
  });
2864
- }, [field, onChange, subtype, timeSerializingFormat]);
2881
+ }, [value, field, onChange, subtype, timeSerializingFormat]);
2865
2882
  useEffect(() => {
2866
2883
  if (dateTimeUpdateRequest) {
2867
2884
  if (dateTimeUpdateRequest.refreshOnly) {
@@ -3143,7 +3160,7 @@ var SvgChecklist = function SvgChecklist(props) {
3143
3160
  };
3144
3161
  var ChecklistIcon = SvgChecklist;
3145
3162
 
3146
- var _path$r, _path2$4, _path3;
3163
+ var _path$r, _path2$3, _path3;
3147
3164
  function _extends$s() { _extends$s = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$s.apply(this, arguments); }
3148
3165
  var SvgDatetime = function SvgDatetime(props) {
3149
3166
  return /*#__PURE__*/React.createElement("svg", _extends$s({
@@ -3154,7 +3171,7 @@ var SvgDatetime = function SvgDatetime(props) {
3154
3171
  }, props), _path$r || (_path$r = /*#__PURE__*/React.createElement("path", {
3155
3172
  fillRule: "evenodd",
3156
3173
  d: "M37.908 13.418h-5.004v-2.354h-1.766v2.354H21.13v-2.354h-1.766v2.354H14.36a2.07 2.07 0 0 0-2.06 2.06v23.549a2.07 2.07 0 0 0 2.06 2.06h6.77v-1.766h-6.358a.707.707 0 0 1-.706-.706V15.89c0-.39.316-.707.706-.707h4.592v2.355h1.766v-2.355h10.008v2.355h1.766v-2.355h4.592a.71.71 0 0 1 .707.707v6.358h1.765v-6.77c0-1.133-.927-2.06-2.06-2.06z"
3157
- })), _path2$4 || (_path2$4 = /*#__PURE__*/React.createElement("path", {
3174
+ })), _path2$3 || (_path2$3 = /*#__PURE__*/React.createElement("path", {
3158
3175
  d: "m35.13 37.603 1.237-1.237-3.468-3.475v-5.926h-1.754v6.654l3.984 3.984Z"
3159
3176
  })), _path3 || (_path3 = /*#__PURE__*/React.createElement("path", {
3160
3177
  fillRule: "evenodd",
@@ -3163,7 +3180,7 @@ var SvgDatetime = function SvgDatetime(props) {
3163
3180
  };
3164
3181
  var DatetimeIcon = SvgDatetime;
3165
3182
 
3166
- var _path$q, _path2$3;
3183
+ var _path$q, _path2$2;
3167
3184
  function _extends$r() { _extends$r = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$r.apply(this, arguments); }
3168
3185
  var SvgTaglist = function SvgTaglist(props) {
3169
3186
  return /*#__PURE__*/React.createElement("svg", _extends$r({
@@ -3174,7 +3191,7 @@ var SvgTaglist = function SvgTaglist(props) {
3174
3191
  }, props), _path$q || (_path$q = /*#__PURE__*/React.createElement("path", {
3175
3192
  fillRule: "evenodd",
3176
3193
  d: "M45 16a3 3 0 0 1 3 3v16a3 3 0 0 1-3 3H9a3 3 0 0 1-3-3V19a3 3 0 0 1 3-3h36Zm0 2H9a1 1 0 0 0-1 1v16a1 1 0 0 0 1 1h36a1 1 0 0 0 1-1V19a1 1 0 0 0-1-1Z"
3177
- })), _path2$3 || (_path2$3 = /*#__PURE__*/React.createElement("path", {
3194
+ })), _path2$2 || (_path2$2 = /*#__PURE__*/React.createElement("path", {
3178
3195
  d: "M11 22a1 1 0 0 1 1-1h19a1 1 0 0 1 1 1v10a1 1 0 0 1-1 1H12a1 1 0 0 1-1-1V22Z"
3179
3196
  })));
3180
3197
  };
@@ -3216,10 +3233,12 @@ var SvgGroup = function SvgGroup(props) {
3216
3233
  xmlns: "http://www.w3.org/2000/svg",
3217
3234
  width: 54,
3218
3235
  height: 54,
3219
- fill: "currentcolor"
3236
+ fill: "none"
3220
3237
  }, props), _path$p || (_path$p = /*#__PURE__*/React.createElement("path", {
3238
+ fill: "#000",
3221
3239
  fillRule: "evenodd",
3222
- d: "M8 33v5a1 1 0 0 0 1 1h4v2H9a3 3 0 0 1-3-3v-5h2Zm18 6v2H15v-2h11Zm13 0v2H28v-2h11Zm9-6v5a3 3 0 0 1-3 3h-4v-2h4a1 1 0 0 0 .993-.883L46 38v-5h2ZM8 22v9H6v-9h2Zm40 0v9h-2v-9h2Zm-35-9v2H9a1 1 0 0 0-.993.883L8 16v4H6v-4a3 3 0 0 1 3-3h4Zm32 0a3 3 0 0 1 3 3v4h-2v-4a1 1 0 0 0-.883-.993L45 15h-4v-2h4Zm-6 0v2H28v-2h11Zm-13 0v2H15v-2h11Z"
3240
+ d: "M4.05 42.132v1.164c0 .693.604 1.254 1.35 1.254h1.35v-2.507h-2.7v.09Zm0-2.328h2.7v-2.328h-2.7v2.328Zm0-4.656h2.7V32.82h-2.7v2.328Zm0-4.656h2.7v-2.328h-2.7v2.328Zm0-4.656h2.7v-2.328h-2.7v2.328Zm0-4.656h2.7v-2.328h-2.7v2.328Zm0-4.656h2.7v-2.328h-2.7v2.328Zm0-4.656v.09h2.7V9.45H5.4c-.746 0-1.35.561-1.35 1.254v1.164Zm5.4-2.418v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7V9.45h-2.7Zm5.4 0v2.507h2.7v-1.253c0-.693-.604-1.254-1.35-1.254h-1.35Zm2.7 4.746h-2.7v2.328h2.7v-2.328Zm0 4.656h-2.7v2.328h2.7v-2.328Zm0 4.656h-2.7v2.328h2.7v-2.328Zm0 4.656h-2.7v2.328h2.7v-2.328Zm0 4.656h-2.7v2.328h2.7V32.82Zm0 4.656h-2.7v2.328h2.7v-2.328Zm0 4.656v-.09h-2.7v2.508h1.35c.746 0 1.35-.561 1.35-1.254v-1.164Zm-5.4 2.418v-2.507h-2.7v2.507h2.7Zm-5.4 0v-2.507h-2.7v2.507h2.7Zm-5.4 0v-2.507h-2.7v2.507h2.7Zm-5.4 0v-2.507h-2.7v2.507h2.7Zm-5.4 0v-2.507h-2.7v2.507h2.7Zm-5.4 0v-2.507h-2.7v2.507h2.7Zm-5.4 0v-2.507h-2.7v2.507h2.7Z",
3241
+ clipRule: "evenodd"
3223
3242
  })));
3224
3243
  };
3225
3244
  var GroupIcon = SvgGroup;
@@ -3309,7 +3328,7 @@ var SvgDynamicList = function SvgDynamicList(props) {
3309
3328
  }, props), _path$j || (_path$j = /*#__PURE__*/React.createElement("path", {
3310
3329
  fill: "currentColor",
3311
3330
  fillRule: "evenodd",
3312
- d: "M2.7 43.296v1.254c0 .746.604 1.35 1.35 1.35h1.275v-1.795c.049.14.075.29.075.445v-1.254h-.075V43.2H4.05c.177 0 .347.034.502.096H2.7Zm2.7-2.507v-2.507H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.015V23.24H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.014V13.21H2.7v2.507h2.7Zm-2.7-5.014h1.852a1.346 1.346 0 0 1-.502.096h1.275v-.096H5.4V9.45c0 .156-.026.306-.075.445V8.1H4.05A1.35 1.35 0 0 0 2.7 9.45v1.254Zm5.175.096h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1-2.7v1.795a1.348 1.348 0 0 1-.075-.445v1.254h.075v.096h1.275c-.177 0-.347-.034-.502-.096H51.3V9.45a1.35 1.35 0 0 0-1.35-1.35h-1.275Zm-.075 5.11v2.508h2.7V13.21h-2.7Zm0 5.015v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7V23.24h-2.7Zm0 5.015v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7v-2.507h-2.7Zm2.7 5.014h-1.852c.155-.062.325-.096.502-.096h-1.275v.096H48.6v1.254c0-.156.026-.305.075-.445V45.9h1.275a1.35 1.35 0 0 0 1.35-1.35v-1.254Zm-5.175-.096h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7ZM16.2 17.55a4.05 4.05 0 0 1 4.05 4.05v1.35A4.05 4.05 0 0 1 16.2 27h-1.35a4.05 4.05 0 0 1-4.05-4.05V21.6a4.05 4.05 0 0 1 4.05-4.05h1.35Zm0 2.7h-1.35a1.35 1.35 0 0 0-1.35 1.35v1.35c0 .746.604 1.35 1.35 1.35h1.35a1.35 1.35 0 0 0 1.35-1.35V21.6a1.35 1.35 0 0 0-1.35-1.35Zm27 1.35a4.05 4.05 0 0 0-4.05-4.05H29.7a4.05 4.05 0 0 0-4.05 4.05v1.35A4.05 4.05 0 0 0 29.7 27h9.45a4.05 4.05 0 0 0 4.05-4.05V21.6Zm-13.5-1.35h9.45c.746 0 1.35.604 1.35 1.35v1.35a1.35 1.35 0 0 1-1.35 1.35H29.7a1.35 1.35 0 0 1-1.35-1.35V21.6c0-.746.604-1.35 1.35-1.35ZM43.2 37.8a4.05 4.05 0 0 0-4.05-4.05H29.7a4.05 4.05 0 0 0-4.05 4.05v1.35h2.7V37.8c0-.746.604-1.35 1.35-1.35h9.45c.746 0 1.35.604 1.35 1.35v1.35h2.7V37.8Zm-27-4.05a4.05 4.05 0 0 1 4.05 4.05v1.35h-2.7V37.8a1.35 1.35 0 0 0-1.35-1.35h-1.35a1.35 1.35 0 0 0-1.35 1.35v1.35h-2.7V37.8a4.05 4.05 0 0 1 4.05-4.05h1.35Z",
3331
+ d: "M2.7 43.296v1.254c0 .746.604 1.35 1.35 1.35h1.275v-1.795c.049.14.075.29.075.445v-1.254h-.075V43.2H4.05c.177 0 .347.034.502.096H2.7Zm2.7-2.507v-2.507H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.015V23.24H2.7v2.507h2.7Zm0-5.014v-2.507H2.7v2.507h2.7Zm0-5.014V13.21H2.7v2.507h2.7Zm-2.7-5.014h1.852a1.346 1.346 0 0 1-.502.096h1.275v-.096H5.4V9.45c0 .156-.026.306-.075.445V8.1H4.05A1.35 1.35 0 0 0 2.7 9.45v1.254Zm5.175.096h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1 0h2.55V8.1h-2.55v2.7Zm5.1-2.7v1.795a1.348 1.348 0 0 1-.075-.445v1.254h.075v.096h1.275a1.35 1.35 0 0 1-.502-.096H51.3V9.45a1.35 1.35 0 0 0-1.35-1.35h-1.275Zm-.075 5.11v2.508h2.7V13.21h-2.7Zm0 5.015v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7V23.24h-2.7Zm0 5.015v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7v-2.507h-2.7Zm0 5.014v2.507h2.7v-2.507h-2.7Zm2.7 5.014h-1.852a1.35 1.35 0 0 1 .502-.096h-1.275v.096H48.6v1.254c0-.156.026-.305.075-.445V45.9h1.275a1.35 1.35 0 0 0 1.35-1.35v-1.254Zm-5.175-.096h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7Zm-5.1 0h-2.55v2.7h2.55v-2.7ZM16.2 17.55a4.05 4.05 0 0 1 4.05 4.05v1.35A4.05 4.05 0 0 1 16.2 27h-1.35a4.05 4.05 0 0 1-4.05-4.05V21.6a4.05 4.05 0 0 1 4.05-4.05h1.35Zm0 2.7h-1.35a1.35 1.35 0 0 0-1.35 1.35v1.35c0 .746.604 1.35 1.35 1.35h1.35a1.35 1.35 0 0 0 1.35-1.35V21.6a1.35 1.35 0 0 0-1.35-1.35Zm27 1.35a4.05 4.05 0 0 0-4.05-4.05H29.7a4.05 4.05 0 0 0-4.05 4.05v1.35A4.05 4.05 0 0 0 29.7 27h9.45a4.05 4.05 0 0 0 4.05-4.05V21.6Zm-13.5-1.35h9.45c.746 0 1.35.604 1.35 1.35v1.35a1.35 1.35 0 0 1-1.35 1.35H29.7a1.35 1.35 0 0 1-1.35-1.35V21.6c0-.746.604-1.35 1.35-1.35ZM43.2 37.8a4.05 4.05 0 0 0-4.05-4.05H29.7a4.05 4.05 0 0 0-4.05 4.05v1.35h2.7V37.8c0-.746.604-1.35 1.35-1.35h9.45c.746 0 1.35.604 1.35 1.35v1.35h2.7V37.8Zm-27-4.05a4.05 4.05 0 0 1 4.05 4.05v1.35h-2.7V37.8a1.35 1.35 0 0 0-1.35-1.35h-1.35a1.35 1.35 0 0 0-1.35 1.35v1.35h-2.7V37.8a4.05 4.05 0 0 1 4.05-4.05h1.35Z",
3313
3332
  clipRule: "evenodd"
3314
3333
  })));
3315
3334
  };
@@ -3393,7 +3412,7 @@ var SvgTextarea = function SvgTextarea(props) {
3393
3412
  };
3394
3413
  var TextareaIcon = SvgTextarea;
3395
3414
 
3396
- var _path$d, _path2$2;
3415
+ var _path$d;
3397
3416
  function _extends$d() { _extends$d = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$d.apply(this, arguments); }
3398
3417
  var SvgIFrame = function SvgIFrame(props) {
3399
3418
  return /*#__PURE__*/React.createElement("svg", _extends$d({
@@ -3402,12 +3421,9 @@ var SvgIFrame = function SvgIFrame(props) {
3402
3421
  height: 54,
3403
3422
  fill: "none"
3404
3423
  }, props), _path$d || (_path$d = /*#__PURE__*/React.createElement("path", {
3405
- fill: "currentcolor",
3406
- d: "M34.467 37.3 41 31l-6.533-6.3-1.32 1.273L38.36 31l-5.213 5.027 1.32 1.273ZM19.533 24.7 13 31l6.533 6.3 1.32-1.273L15.64 31l5.214-5.027-1.32-1.273Zm4.127 14.832 1.805.468 4.875-17.532L28.535 22 23.66 39.532Z"
3407
- })), _path2$2 || (_path2$2 = /*#__PURE__*/React.createElement("path", {
3408
- fill: "currentcolor",
3424
+ fill: "currentColor",
3409
3425
  fillRule: "evenodd",
3410
- d: "M46 9a3 3 0 0 1 3 3v30a3 3 0 0 1-3 3H8a3 3 0 0 1-3-3V12a3 3 0 0 1 3-3h38Zm0 2H8a1 1 0 0 0-1 1v4h40v-4a1 1 0 0 0-1-1ZM7 42V18h40v24a1 1 0 0 1-1 1H8a1 1 0 0 1-1-1Z",
3426
+ d: "M45.658 9.45c1.625 0 2.942 1.36 2.942 3.039V22.95h-1.961v-4.383H7.36V41.51c0 .56.44 1.013.98 1.013H27v2.026H8.342c-1.625 0-2.942-1.36-2.942-3.039V12.489c0-1.678 1.317-3.039 2.942-3.039h37.316Zm0 2.026H8.342c-.542 0-.98.454-.98 1.013v4.052h39.277v-4.052c0-.56-.44-1.013-.98-1.013ZM31.05 35.775A8.768 8.768 0 0 1 39.825 27a8.768 8.768 0 0 1 8.775 8.775 8.768 8.768 0 0 1-8.775 8.775 8.768 8.768 0 0 1-8.775-8.775Zm12.388-.516h3.097c-.206-2.581-1.858-4.646-4.026-5.678.62 1.548.93 3.613.93 5.678Zm-5.162 2.065c.207 3.303 1.136 4.955 1.549 5.161.413-.206 1.239-1.858 1.445-5.161h-2.994Zm1.446-8.26c-.31.207-1.342 2.272-1.446 6.195h2.994c-.103-3.923-1.135-5.988-1.548-6.194Zm-3.51 6.195c.103-2.065.31-4.13.929-5.678-2.168 1.032-3.82 3.097-4.026 5.678h3.097Zm0 2.065h-2.89c.515 2.064 1.96 3.82 3.819 4.645-.516-1.342-.826-2.994-.93-4.645Zm7.226 0c-.103 1.755-.413 3.303-.929 4.645 1.858-.826 3.304-2.58 3.923-4.645h-2.994Z",
3411
3427
  clipRule: "evenodd"
3412
3428
  })));
3413
3429
  };
@@ -3778,7 +3794,7 @@ function Numberfield(props) {
3778
3794
  'fjs-disabled': disabled,
3779
3795
  'fjs-readonly': readonly
3780
3796
  }, {
3781
- 'hasErrors': errors.length
3797
+ hasErrors: errors.length
3782
3798
  }),
3783
3799
  children: [jsx("input", {
3784
3800
  ref: inputRef,
@@ -3790,7 +3806,6 @@ function Numberfield(props) {
3790
3806
  onKeyPress: onKeyPress,
3791
3807
  onBlur: onInputBlur,
3792
3808
  onFocus: onInputFocus
3793
-
3794
3809
  // @ts-ignore
3795
3810
  ,
3796
3811
  onInput: e => setValue(e.target.value, true),
@@ -4099,10 +4114,10 @@ function SearchableSelect(props) {
4099
4114
  return jsxs(Fragment, {
4100
4115
  children: [jsxs("div", {
4101
4116
  class: classNames('fjs-input-group', {
4102
- 'disabled': disabled,
4103
- 'readonly': readonly
4117
+ disabled: disabled,
4118
+ readonly: readonly
4104
4119
  }, {
4105
- 'hasErrors': errors.length
4120
+ hasErrors: errors.length
4106
4121
  }),
4107
4122
  children: [jsx("input", {
4108
4123
  disabled: disabled,
@@ -4126,7 +4141,7 @@ function SearchableSelect(props) {
4126
4141
  setValue(null);
4127
4142
  e.preventDefault();
4128
4143
  },
4129
- children: [jsx(XMarkIcon, {}), " "]
4144
+ children: [jsx(XMarkIcon, {}), ' ']
4130
4145
  }), jsx("span", {
4131
4146
  class: "fjs-select-arrow",
4132
4147
  onMouseDown: e => onAngelMouseDown(e),
@@ -4220,7 +4235,7 @@ function SimpleSelect(props) {
4220
4235
  disabled,
4221
4236
  readonly
4222
4237
  }, {
4223
- 'hasErrors': errors.length
4238
+ hasErrors: errors.length
4224
4239
  }),
4225
4240
  onFocus: onInputFocus,
4226
4241
  onBlur: onInputBlur,
@@ -4928,7 +4943,7 @@ function Html(props) {
4928
4943
  Html.config = {
4929
4944
  type: type$4,
4930
4945
  keyed: false,
4931
- label: 'HTML',
4946
+ label: 'HTML view',
4932
4947
  group: 'presentation',
4933
4948
  create: (options = {}) => ({
4934
4949
  content: '',
@@ -4940,7 +4955,8 @@ const type$3 = 'expression';
4940
4955
  function ExpressionField(props) {
4941
4956
  const {
4942
4957
  field,
4943
- onChange
4958
+ onChange,
4959
+ value
4944
4960
  } = props;
4945
4961
  const {
4946
4962
  computeOn,
@@ -4949,18 +4965,20 @@ function ExpressionField(props) {
4949
4965
  const evaluation = useExpressionEvaluation(expression);
4950
4966
  const evaluationMemo = useDeepCompareMemoize(evaluation);
4951
4967
  const eventBus = useService('eventBus');
4968
+ const expressionLoopPreventer = useService('expressionLoopPreventer');
4952
4969
  const sendValue = useCallback(() => {
4953
4970
  onChange && onChange({
4954
4971
  field,
4955
- value: evaluationMemo
4972
+ value: evaluationMemo,
4973
+ shouldNotRecompute: true
4956
4974
  });
4957
4975
  }, [field, evaluationMemo, onChange]);
4958
- useEffectOnChange(evaluationMemo, () => {
4959
- if (computeOn !== 'change') {
4976
+ useEffect(() => {
4977
+ if (computeOn !== 'change' || isEqual$1(evaluationMemo, value) || !expressionLoopPreventer.registerExpressionExecution(this)) {
4960
4978
  return;
4961
4979
  }
4962
4980
  sendValue();
4963
- }, [computeOn, sendValue]);
4981
+ });
4964
4982
  useEffect(() => {
4965
4983
  if (computeOn === 'presubmit') {
4966
4984
  eventBus.on('presubmit', sendValue);
@@ -4974,6 +4992,7 @@ ExpressionField.config = {
4974
4992
  label: 'Expression',
4975
4993
  group: 'basic-input',
4976
4994
  keyed: true,
4995
+ emptyValue: null,
4977
4996
  escapeGridRender: true,
4978
4997
  create: (options = {}) => ({
4979
4998
  computeOn: 'change',
@@ -5624,7 +5643,7 @@ function Lightbox(props) {
5624
5643
  style: "margin: 15px 20px 15px 10px; align-self: center; color: var(--cds-icon-primary, #404040)",
5625
5644
  children: jsx(Logo, {})
5626
5645
  }), jsxs("span", {
5627
- children: ["Web-based tooling for BPMN, DMN, and forms powered by ", jsx("a", {
5646
+ children: ["Web-based tooling for BPMN, DMN, and forms powered by", ' ', jsx("a", {
5628
5647
  href: "https://bpmn.io",
5629
5648
  target: "_blank",
5630
5649
  rel: "noopener",
@@ -5714,7 +5733,12 @@ function FormComponent(props) {
5714
5733
  });
5715
5734
  }
5716
5735
 
5717
- const formFields = [Button, Checkbox, Checklist, Default, DynamicList, Numberfield, Datetime, Radio, Select, Taglist, Textfield, Textarea, ExpressionField, Text, Image, Table, Html, Spacer, Separator, Group, DynamicList, IFrame];
5736
+ const formFields = [/* Input */
5737
+ Textfield, Textarea, Numberfield, Datetime, ExpressionField, /* Selection */
5738
+ Checkbox, Checklist, Radio, Select, Taglist, /* Presentation */
5739
+ Text, Image, Table, Html, Spacer, Separator, /* Containers */
5740
+ Group, DynamicList, IFrame, /* Other */
5741
+ Button, Default];
5718
5742
 
5719
5743
  class FormFields {
5720
5744
  constructor() {
@@ -5884,8 +5908,7 @@ class ConditionChecker {
5884
5908
  const {
5885
5909
  getFilterPath = (field, indexes) => this._pathRegistry.getValuePath(field, {
5886
5910
  indexes
5887
- }),
5888
- leafNodeDeletionOnly = false
5911
+ })
5889
5912
  } = options;
5890
5913
  const _applyConditionsWithinScope = (rootField, scopeContext, startHidden = false) => {
5891
5914
  const {
@@ -5916,7 +5939,7 @@ class ConditionChecker {
5916
5939
  context.isHidden = startHidden || context.isHidden || conditional && this._checkHideCondition(conditional, localExpressionContext);
5917
5940
 
5918
5941
  // if a field is repeatable and visible, we need to implement custom recursion on its children
5919
- if (isRepeatable && (!context.isHidden || leafNodeDeletionOnly)) {
5942
+ if (isRepeatable && !context.isHidden) {
5920
5943
  // prevent the regular recursion behavior of executeRecursivelyOnFields
5921
5944
  context.preventRecursion = true;
5922
5945
  const repeaterValuePath = this._pathRegistry.getValuePath(field, {
@@ -5948,7 +5971,7 @@ class ConditionChecker {
5948
5971
  }
5949
5972
 
5950
5973
  // if we have a hidden repeatable field, and the data structure allows, we clear it directly at the root and stop recursion
5951
- if (context.isHidden && !leafNodeDeletionOnly && isRepeatable) {
5974
+ if (context.isHidden && isRepeatable) {
5952
5975
  context.preventRecursion = true;
5953
5976
  this._cleanlyClearDataAtPath(getFilterPath(field, indexes), workingData);
5954
5977
  }
@@ -6038,6 +6061,49 @@ const ExpressionLanguageModule = {
6038
6061
  conditionChecker: ['type', ConditionChecker]
6039
6062
  };
6040
6063
 
6064
+ class ExpressionLoopPreventer {
6065
+ constructor(eventBus) {
6066
+ this._computedExpressions = [];
6067
+ eventBus.on('field.updated', ({
6068
+ shouldNotRecompute
6069
+ }) => {
6070
+ if (shouldNotRecompute) {
6071
+ return;
6072
+ }
6073
+ this.reset();
6074
+ });
6075
+ eventBus.on('import.done', this.reset.bind(this));
6076
+ eventBus.on('reset', this.reset.bind(this));
6077
+ }
6078
+
6079
+ /**
6080
+ * Checks if the expression field has already been computed, and registers it if not.
6081
+ *
6082
+ * @param {any} expressionField
6083
+ * @returns {boolean} - whether the expression field has already been computed within the current cycle
6084
+ */
6085
+ registerExpressionExecution(expressionField) {
6086
+ if (this._computedExpressions.includes(expressionField)) {
6087
+ return false;
6088
+ }
6089
+ this._computedExpressions.push(expressionField);
6090
+ return true;
6091
+ }
6092
+
6093
+ /**
6094
+ * Resets the list of computed expressions.
6095
+ */
6096
+ reset() {
6097
+ this._computedExpressions = [];
6098
+ }
6099
+ }
6100
+ ExpressionLoopPreventer.$inject = ['eventBus'];
6101
+
6102
+ const ExpressionFieldModule = {
6103
+ __init__: ['expressionLoopPreventer'],
6104
+ expressionLoopPreventer: ['type', ExpressionLoopPreventer]
6105
+ };
6106
+
6041
6107
  class MarkdownRenderer {
6042
6108
  /**
6043
6109
  * Render markdown to HTML.
@@ -8212,6 +8278,62 @@ class FormFieldRegistry {
8212
8278
  }
8213
8279
  FormFieldRegistry.$inject = ['eventBus'];
8214
8280
 
8281
+ class FormFieldInstanceRegistry {
8282
+ constructor(eventBus, formFieldRegistry, formFields) {
8283
+ this._eventBus = eventBus;
8284
+ this._formFieldRegistry = formFieldRegistry;
8285
+ this._formFields = formFields;
8286
+ this._formFieldInstances = {};
8287
+ eventBus.on('form.clear', () => this.clear());
8288
+ }
8289
+ add(instance) {
8290
+ const {
8291
+ id,
8292
+ expressionContextInfo,
8293
+ valuePath,
8294
+ indexes
8295
+ } = instance;
8296
+ const instanceId = [id, ...Object.values(indexes || {})].join('_');
8297
+ if (this._formFieldInstances[instanceId]) {
8298
+ throw new Error('this form field instance is already registered');
8299
+ }
8300
+ this._formFieldInstances[instanceId] = {
8301
+ id,
8302
+ instanceId,
8303
+ expressionContextInfo,
8304
+ valuePath,
8305
+ indexes
8306
+ };
8307
+ return instanceId;
8308
+ }
8309
+ remove(instanceId) {
8310
+ if (!this._formFieldInstances[instanceId]) {
8311
+ return;
8312
+ }
8313
+ delete this._formFieldInstances[instanceId];
8314
+ }
8315
+ getAll() {
8316
+ return Object.values(this._formFieldInstances);
8317
+ }
8318
+ getAllKeyed() {
8319
+ return this.getAll().filter(({
8320
+ id
8321
+ }) => {
8322
+ const {
8323
+ type
8324
+ } = this._formFieldRegistry.get(id);
8325
+ const {
8326
+ config
8327
+ } = this._formFields.get(type);
8328
+ return config.keyed;
8329
+ });
8330
+ }
8331
+ clear() {
8332
+ this._formFieldInstances = {};
8333
+ }
8334
+ }
8335
+ FormFieldInstanceRegistry.$inject = ['eventBus', 'formFieldRegistry', 'formFields'];
8336
+
8215
8337
  function Renderer(config, eventBus, form, injector) {
8216
8338
  const App = () => {
8217
8339
  const [state, setState] = useState(form._getState());
@@ -8276,6 +8398,7 @@ const CoreModule = {
8276
8398
  importer: ['type', Importer],
8277
8399
  fieldFactory: ['type', FieldFactory],
8278
8400
  formFieldRegistry: ['type', FormFieldRegistry],
8401
+ formFieldInstanceRegistry: ['type', FormFieldInstanceRegistry],
8279
8402
  pathRegistry: ['type', PathRegistry],
8280
8403
  formLayouter: ['type', FormLayouter],
8281
8404
  validator: ['type', Validator]
@@ -8450,73 +8573,39 @@ class Form {
8450
8573
  * @returns {Errors}
8451
8574
  */
8452
8575
  validate() {
8453
- const formFields = this.get('formFields'),
8454
- formFieldRegistry = this.get('formFieldRegistry'),
8455
- pathRegistry = this.get('pathRegistry'),
8576
+ const formFieldRegistry = this.get('formFieldRegistry'),
8577
+ formFieldInstanceRegistry = this.get('formFieldInstanceRegistry'),
8456
8578
  validator = this.get('validator');
8457
8579
  const {
8458
8580
  data
8459
8581
  } = this._getState();
8460
- const getErrorPath = (field, indexes) => [field.id, ...Object.values(indexes || {})];
8461
- function validateFieldRecursively(errors, field, indexes) {
8462
- const {
8463
- disabled,
8464
- type,
8465
- isRepeating
8466
- } = field;
8467
- const {
8468
- config: fieldConfig
8469
- } = formFields.get(type);
8582
+ const errors = {};
8583
+ const getErrorPath = (id, indexes) => [id, ...Object.values(indexes || {})];
8584
+ formFieldInstanceRegistry.getAllKeyed().forEach(({
8585
+ id,
8586
+ valuePath,
8587
+ indexes
8588
+ }) => {
8589
+ const field = formFieldRegistry.get(id);
8470
8590
 
8471
8591
  // (1) Skip disabled fields
8472
- if (disabled) {
8592
+ if (field.disabled) {
8473
8593
  return;
8474
8594
  }
8475
8595
 
8476
8596
  // (2) Validate the field
8477
- const valuePath = pathRegistry.getValuePath(field, {
8478
- indexes
8479
- });
8480
- const valueData = get(data, valuePath);
8481
- const fieldErrors = validator.validateField(field, valueData);
8597
+ const value = get(data, valuePath);
8598
+ const fieldErrors = validator.validateField(field, value);
8482
8599
  if (fieldErrors.length) {
8483
- set(errors, getErrorPath(field, indexes), fieldErrors);
8484
- }
8485
-
8486
- // (3) Process parents
8487
- if (!Array.isArray(field.components)) {
8488
- return;
8489
- }
8490
-
8491
- // (4a) Recurse repeatable parents both across the indexes of repetition and the children
8492
- if (fieldConfig.repeatable && isRepeating) {
8493
- if (!Array.isArray(valueData)) {
8494
- return;
8495
- }
8496
- valueData.forEach((_, index) => {
8497
- field.components.forEach(component => {
8498
- validateFieldRecursively(errors, component, {
8499
- ...indexes,
8500
- [field.id]: index
8501
- });
8502
- });
8503
- });
8504
- return;
8600
+ set(errors, getErrorPath(field.id, indexes), fieldErrors);
8505
8601
  }
8506
-
8507
- // (4b) Recurse non-repeatable parents only across the children
8508
- field.components.forEach(component => validateFieldRecursively(errors, component, indexes));
8509
- }
8510
- const workingErrors = {};
8511
- validateFieldRecursively(workingErrors, formFieldRegistry.getForm());
8512
- const filteredErrors = this._applyConditions(workingErrors, data, {
8513
- getFilterPath: getErrorPath,
8514
- leafNodeDeletionOnly: true
8515
8602
  });
8516
8603
  this._setState({
8517
- errors: filteredErrors
8604
+ errors
8518
8605
  });
8519
- return filteredErrors;
8606
+
8607
+ // @ts-ignore
8608
+ return errors;
8520
8609
  }
8521
8610
 
8522
8611
  /**
@@ -8611,7 +8700,7 @@ class Form {
8611
8700
  /**
8612
8701
  * @internal
8613
8702
  *
8614
- * @param { { add?: boolean, field: any, indexes: object, remove?: number, value?: any } } update
8703
+ * @param { { field: any, indexes: object, value: any } } update
8615
8704
  */
8616
8705
  _update(update) {
8617
8706
  const {
@@ -8631,6 +8720,7 @@ class Form {
8631
8720
  });
8632
8721
  set(data, valuePath, value);
8633
8722
  set(errors, [field.id, ...Object.values(indexes || {})], fieldErrors.length ? fieldErrors : undefined);
8723
+ this._emit('field.updated', update);
8634
8724
  this._setState({
8635
8725
  data: clone(data),
8636
8726
  errors: clone(errors)
@@ -8656,10 +8746,10 @@ class Form {
8656
8746
  }
8657
8747
 
8658
8748
  /**
8659
- * @internal
8660
- */
8749
+ * @internal
8750
+ */
8661
8751
  _getModules() {
8662
- return [ExpressionLanguageModule, MarkdownRendererModule, ViewerCommandsModule, RepeatRenderModule];
8752
+ return [ExpressionLanguageModule, ExpressionFieldModule, MarkdownRendererModule, ViewerCommandsModule, RepeatRenderModule];
8663
8753
  }
8664
8754
 
8665
8755
  /**
@@ -8674,65 +8764,24 @@ class Form {
8674
8764
  */
8675
8765
  _getSubmitData() {
8676
8766
  const formFieldRegistry = this.get('formFieldRegistry');
8677
- const formFields = this.get('formFields');
8678
- const pathRegistry = this.get('pathRegistry');
8767
+ const formFieldInstanceRegistry = this.get('formFieldInstanceRegistry');
8679
8768
  const formData = this._getState().data;
8680
- function collectSubmitDataRecursively(submitData, formField, indexes) {
8769
+ const submitData = {};
8770
+ formFieldInstanceRegistry.getAllKeyed().forEach(formFieldInstance => {
8681
8771
  const {
8682
- disabled,
8683
- type
8684
- } = formField;
8772
+ id,
8773
+ valuePath
8774
+ } = formFieldInstance;
8685
8775
  const {
8686
- config: fieldConfig
8687
- } = formFields.get(type);
8688
-
8689
- // (1) Process keyed fields
8690
- if (!disabled && fieldConfig.keyed) {
8691
- const valuePath = pathRegistry.getValuePath(formField, {
8692
- indexes
8693
- });
8694
- const value = get(formData, valuePath);
8695
- set(submitData, valuePath, value);
8696
- }
8697
-
8698
- // (2) Process parents
8699
- if (!Array.isArray(formField.components)) {
8700
- return;
8701
- }
8702
-
8703
- // (3a) Recurse repeatable parents both across the indexes of repetition and the children
8704
- if (fieldConfig.repeatable && formField.isRepeating) {
8705
- const valueData = get(formData, pathRegistry.getValuePath(formField, {
8706
- indexes
8707
- }));
8708
- if (!Array.isArray(valueData)) {
8709
- return;
8710
- }
8711
- valueData.forEach((_, index) => {
8712
- formField.components.forEach(component => {
8713
- collectSubmitDataRecursively(submitData, component, {
8714
- ...indexes,
8715
- [formField.id]: index
8716
- });
8717
- });
8718
- });
8776
+ disabled
8777
+ } = formFieldRegistry.get(id);
8778
+ if (disabled) {
8719
8779
  return;
8720
8780
  }
8721
-
8722
- // (3b) Recurse non-repeatable parents only across the children
8723
- formField.components.forEach(component => collectSubmitDataRecursively(submitData, component, indexes));
8724
- }
8725
- const workingSubmitData = {};
8726
- collectSubmitDataRecursively(workingSubmitData, formFieldRegistry.getForm(), {});
8727
- return this._applyConditions(workingSubmitData, formData);
8728
- }
8729
-
8730
- /**
8731
- * @internal
8732
- */
8733
- _applyConditions(toFilter, data, options = {}) {
8734
- const conditionChecker = this.get('conditionChecker');
8735
- return conditionChecker.applyConditions(toFilter, data, options);
8781
+ const value = get(formData, valuePath);
8782
+ set(submitData, valuePath, value);
8783
+ });
8784
+ return submitData;
8736
8785
  }
8737
8786
 
8738
8787
  /**
@@ -8827,16 +8876,16 @@ class Form {
8827
8876
 
8828
8877
  const schemaVersion = 16;
8829
8878
 
8830
- /**
8831
- * @typedef { import('./types').CreateFormOptions } CreateFormOptions
8879
+ /**
8880
+ * @typedef { import('./types').CreateFormOptions } CreateFormOptions
8832
8881
  */
8833
8882
 
8834
- /**
8835
- * Create a form.
8836
- *
8837
- * @param {CreateFormOptions} options
8838
- *
8839
- * @return {Promise<Form>}
8883
+ /**
8884
+ * Create a form.
8885
+ *
8886
+ * @param {CreateFormOptions} options
8887
+ *
8888
+ * @return {Promise<Form>}
8840
8889
  */
8841
8890
  function createForm(options) {
8842
8891
  const {
@@ -8850,5 +8899,5 @@ function createForm(options) {
8850
8899
  });
8851
8900
  }
8852
8901
 
8853
- export { ALLOW_ATTRIBUTE, Button, Checkbox, Checklist, ConditionChecker, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, Default, Description, DynamicList, Errors, ExpressionField, ExpressionLanguageModule, FeelExpressionLanguage, FeelersTemplating, FieldFactory, Form, FormComponent, FormContext, FormField, FormFieldRegistry, FormFields, FormLayouter, FormRenderContext, Group, Html, IFrame, Image, Importer, Label, LocalExpressionContext, MINUTES_IN_DAY, MarkdownRenderer, MarkdownRendererModule, Numberfield, OPTIONS_SOURCES, OPTIONS_SOURCES_DEFAULTS, OPTIONS_SOURCES_LABELS, OPTIONS_SOURCES_PATHS, OPTIONS_SOURCE_DEFAULT, PathRegistry, Radio, RenderModule, RepeatRenderManager, RepeatRenderModule, SANDBOX_ATTRIBUTE, SECURITY_ATTRIBUTES_DEFINITIONS, Select, Separator, Spacer, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Table, Taglist, Text, Textarea, Textfield, ViewerCommands, ViewerCommandsModule, buildExpressionContext, clone, createForm, createFormContainer, createInjector, escapeHTML, formFields, generateIdForType, generateIndexForType, getAncestryList, getOptionsSource, getSchemaVariables, getScrollContainer, hasEqualValue, iconsByType, isRequired, pathParse, pathsEqual, runRecursively, sanitizeDateTimePickerValue, sanitizeHTML, sanitizeIFrameSource, sanitizeImageSource, sanitizeMultiSelectValue, sanitizeSingleSelectValue, schemaVersion, useExpressionEvaluation, useSingleLineTemplateEvaluation, useTemplateEvaluation, wrapCSSStyles };
8902
+ export { ALLOW_ATTRIBUTE, Button, Checkbox, Checklist, ConditionChecker, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, Default, Description, DynamicList, Errors, ExpressionField, ExpressionFieldModule, ExpressionLanguageModule, ExpressionLoopPreventer, FeelExpressionLanguage, FeelersTemplating, FieldFactory, Form, FormComponent, FormContext, FormField, FormFieldRegistry, FormFields, FormLayouter, FormRenderContext, Group, Html, IFrame, Image, Importer, Label, LocalExpressionContext, MINUTES_IN_DAY, MarkdownRenderer, MarkdownRendererModule, Numberfield, OPTIONS_SOURCES, OPTIONS_SOURCES_DEFAULTS, OPTIONS_SOURCES_LABELS, OPTIONS_SOURCES_PATHS, OPTIONS_SOURCE_DEFAULT, PathRegistry, Radio, RenderModule, RepeatRenderManager, RepeatRenderModule, SANDBOX_ATTRIBUTE, SECURITY_ATTRIBUTES_DEFINITIONS, Select, Separator, Spacer, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Table, Taglist, Text, Textarea, Textfield, ViewerCommands, ViewerCommandsModule, buildExpressionContext, clone, createForm, createFormContainer, createInjector, escapeHTML, formFields, generateIdForType, generateIndexForType, getAncestryList, getOptionsSource, getSchemaVariables, getScrollContainer, hasEqualValue, iconsByType, isRequired, pathParse, pathsEqual, runRecursively, sanitizeDateTimePickerValue, sanitizeHTML, sanitizeIFrameSource, sanitizeImageSource, sanitizeMultiSelectValue, sanitizeSingleSelectValue, schemaVersion, useExpressionEvaluation, useSingleLineTemplateEvaluation, useTemplateEvaluation, wrapCSSStyles };
8854
8903
  //# sourceMappingURL=index.es.js.map