@bpmn-io/form-js-viewer 1.3.0-alpha.0 → 1.3.2

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
@@ -5,7 +5,7 @@ import { parseExpression, parseUnaryTests, evaluate, unaryTest } from 'feelin';
5
5
  import { evaluate as evaluate$1, parser, buildSimpleTree } from 'feelers';
6
6
  import classNames from 'classnames';
7
7
  import { jsx, jsxs, Fragment as Fragment$1 } from 'preact/jsx-runtime';
8
- import { useContext, useMemo, useEffect, useState, useRef, useCallback, useLayoutEffect } from 'preact/hooks';
8
+ import { useContext, useMemo, useEffect, useRef, useState, useCallback, useLayoutEffect } from 'preact/hooks';
9
9
  import { createContext, createElement, Fragment, render } from 'preact';
10
10
  import * as React from 'preact/compat';
11
11
  import { createPortal } from 'preact/compat';
@@ -619,9 +619,14 @@ class ConditionChecker {
619
619
  *
620
620
  * @param {Object<string, any>} properties
621
621
  * @param {Object<string, any>} data
622
+ * @param {Object} [options]
623
+ * @param {Function} [options.getFilterPath]
622
624
  */
623
- applyConditions(properties, data = {}) {
625
+ applyConditions(properties, data = {}, options = {}) {
624
626
  const newProperties = clone(properties);
627
+ const {
628
+ getFilterPath = field => this._pathRegistry.getValuePath(field)
629
+ } = options;
625
630
  const form = this._formFieldRegistry.getAll().find(field => field.type === 'default');
626
631
  if (!form) {
627
632
  throw new Error('form field registry has no form');
@@ -638,8 +643,7 @@ class ConditionChecker {
638
643
 
639
644
  // only clear the leaf nodes, as groups may both point to the same path
640
645
  if (context.isHidden && isClosed) {
641
- const valuePath = this._pathRegistry.getValuePath(field);
642
- this._clearObjectValueRecursively(valuePath, newProperties);
646
+ this._clearObjectValueRecursively(getFilterPath(field), newProperties);
643
647
  }
644
648
  });
645
649
  return newProperties;
@@ -2704,6 +2708,37 @@ function useReadonly(formField, properties = {}) {
2704
2708
  return readonly || false;
2705
2709
  }
2706
2710
 
2711
+ function usePrevious(value, defaultValue, dependencies) {
2712
+ const ref = useRef(defaultValue);
2713
+ useEffect(() => ref.current = value, dependencies);
2714
+ return ref.current;
2715
+ }
2716
+
2717
+ /**
2718
+ * A custom hook to manage state changes with deep comparison.
2719
+ *
2720
+ * @param {any} value - The current value to manage.
2721
+ * @param {any} defaultValue - The initial default value for the state.
2722
+ * @returns {any} - Returns the current state.
2723
+ */
2724
+ function useDeepCompareState(value, defaultValue) {
2725
+ const [state, setState] = useState(defaultValue);
2726
+ const previous = usePrevious(value, defaultValue, [value]);
2727
+ const changed = !compare(previous, value);
2728
+ useEffect(() => {
2729
+ if (changed) {
2730
+ setState(value);
2731
+ }
2732
+ }, [changed, value]);
2733
+ return state;
2734
+ }
2735
+
2736
+ // helpers //////////////////////////
2737
+
2738
+ function compare(a, b) {
2739
+ return JSON.stringify(a) === JSON.stringify(b);
2740
+ }
2741
+
2707
2742
  /**
2708
2743
  * Template a string reactively based on form data. If the string is not a template, it is returned as is.
2709
2744
  * Memoised to minimize re-renders
@@ -2973,11 +3008,8 @@ function useValuesAsync (field) {
2973
3008
  state: LOAD_STATES.LOADING
2974
3009
  });
2975
3010
  const initialData = useService('form')._getState().initialData;
2976
- const evaluatedValues = useMemo(() => {
2977
- if (valuesExpression) {
2978
- return useExpressionEvaluation(valuesExpression);
2979
- }
2980
- }, [valuesExpression]);
3011
+ const expressionEvaluation = useExpressionEvaluation(valuesExpression);
3012
+ const evaluatedValues = useDeepCompareState(expressionEvaluation || [], []);
2981
3013
  useEffect(() => {
2982
3014
  let values = [];
2983
3015
 
@@ -2993,8 +3025,10 @@ function useValuesAsync (field) {
2993
3025
  values = Array.isArray(staticValues) ? staticValues : [];
2994
3026
 
2995
3027
  // expression
2996
- } else if (evaluatedValues && Array.isArray(evaluatedValues)) {
2997
- values = evaluatedValues;
3028
+ } else if (valuesExpression) {
3029
+ if (evaluatedValues && Array.isArray(evaluatedValues)) {
3030
+ values = evaluatedValues;
3031
+ }
2998
3032
  } else {
2999
3033
  setValuesGetter(buildErrorState('No values source defined in the form definition'));
3000
3034
  return;
@@ -3003,7 +3037,7 @@ function useValuesAsync (field) {
3003
3037
  // normalize data to support primitives and partially defined objects
3004
3038
  values = normalizeValuesData(values);
3005
3039
  setValuesGetter(buildLoadedState(values));
3006
- }, [valuesKey, staticValues, initialData]);
3040
+ }, [valuesKey, staticValues, initialData, valuesExpression, evaluatedValues]);
3007
3041
  return valuesGetter;
3008
3042
  }
3009
3043
  const buildErrorState = error => ({
@@ -3022,7 +3056,6 @@ const ENTER_KEYDOWN_EVENT = new KeyboardEvent('keydown', {
3022
3056
  key: 'Enter',
3023
3057
  charCode: 13,
3024
3058
  keyCode: 13,
3025
- view: window,
3026
3059
  bubbles: true
3027
3060
  });
3028
3061
  function focusRelevantFlatpickerDay(flatpickrInstance) {
@@ -3788,7 +3821,8 @@ function DropdownList(props) {
3788
3821
  useEffect(() => {
3789
3822
  const individualEntries = dropdownContainer.current.children;
3790
3823
  if (individualEntries.length && !mouseControl) {
3791
- individualEntries[focusedValueIndex].scrollIntoView({
3824
+ const focusedEntry = individualEntries[focusedValueIndex];
3825
+ focusedEntry && focusedEntry.scrollIntoView({
3792
3826
  block: 'nearest',
3793
3827
  inline: 'nearest'
3794
3828
  });
@@ -6351,10 +6385,9 @@ class Form {
6351
6385
  }
6352
6386
  const data = this._getSubmitData();
6353
6387
  const errors = this.validate();
6354
- const filteredErrors = this._applyConditions(errors, data);
6355
6388
  const result = {
6356
6389
  data,
6357
- errors: filteredErrors
6390
+ errors
6358
6391
  };
6359
6392
  this._emit('submit', result);
6360
6393
  return result;
@@ -6377,6 +6410,7 @@ class Form {
6377
6410
  const {
6378
6411
  data
6379
6412
  } = this._getState();
6413
+ const getErrorPath = field => [field.id];
6380
6414
  const errors = formFieldRegistry.getAll().reduce((errors, field) => {
6381
6415
  const {
6382
6416
  disabled
@@ -6386,12 +6420,15 @@ class Form {
6386
6420
  }
6387
6421
  const value = get(data, pathRegistry.getValuePath(field));
6388
6422
  const fieldErrors = validator.validateField(field, value);
6389
- return set(errors, [field.id], fieldErrors.length ? fieldErrors : undefined);
6423
+ return set(errors, getErrorPath(field), fieldErrors.length ? fieldErrors : undefined);
6390
6424
  }, /** @type {Errors} */{});
6425
+ const filteredErrors = this._applyConditions(errors, data, {
6426
+ getFilterPath: getErrorPath
6427
+ });
6391
6428
  this._setState({
6392
- errors
6429
+ errors: filteredErrors
6393
6430
  });
6394
- return errors;
6431
+ return filteredErrors;
6395
6432
  }
6396
6433
 
6397
6434
  /**
@@ -6570,9 +6607,9 @@ class Form {
6570
6607
  /**
6571
6608
  * @internal
6572
6609
  */
6573
- _applyConditions(toFilter, data) {
6610
+ _applyConditions(toFilter, data, options = {}) {
6574
6611
  const conditionChecker = this.get('conditionChecker');
6575
- return conditionChecker.applyConditions(toFilter, data);
6612
+ return conditionChecker.applyConditions(toFilter, data, options);
6576
6613
  }
6577
6614
 
6578
6615
  /**
@@ -6638,5 +6675,5 @@ function createForm(options) {
6638
6675
  });
6639
6676
  }
6640
6677
 
6641
- export { Button, Checkbox, Checklist, ConditionChecker, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, FormComponent$1 as Default, ExpressionLanguageModule, FeelExpressionLanguage, FeelersTemplating, FieldFactory, Form, FormComponent, FormContext$1 as FormContext, FormFieldRegistry, FormFields, FormLayouter, FormRenderContext$1 as FormRenderContext, Group, Image, Importer, MINUTES_IN_DAY, MarkdownModule, MarkdownRenderer, Numberfield, PathRegistry, Radio, Select, Spacer, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Taglist, Text, Textarea, Textfield, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, VALUES_SOURCES_PATHS, VALUES_SOURCE_DEFAULT, ViewerCommands, ViewerCommandsModule, clone, createForm, createFormContainer, createInjector, formFields, generateIdForType, generateIndexForType, getSchemaVariables, getValuesSource, iconsByType, isRequired, pathParse, pathsEqual, runRecursively, schemaVersion };
6678
+ export { Button, Checkbox, Checklist, ConditionChecker, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, FormComponent$1 as Default, ExpressionLanguageModule, FeelExpressionLanguage, FeelersTemplating, FieldFactory, Form, FormComponent, FormContext$1 as FormContext, FormField, FormFieldRegistry, FormFields, FormLayouter, FormRenderContext$1 as FormRenderContext, Group, Image, Importer, MINUTES_IN_DAY, MarkdownModule, MarkdownRenderer, Numberfield, PathRegistry, Radio, Select, Spacer, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Taglist, Text, Textarea, Textfield, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, VALUES_SOURCES_PATHS, VALUES_SOURCE_DEFAULT, ViewerCommands, ViewerCommandsModule, clone, createForm, createFormContainer, createInjector, formFields, generateIdForType, generateIndexForType, getSchemaVariables, getValuesSource, iconsByType, isRequired, pathParse, pathsEqual, runRecursively, schemaVersion };
6642
6679
  //# sourceMappingURL=index.es.js.map