@bpmn-io/form-js-viewer 1.7.1 → 1.7.3
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.cjs +112 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +113 -84
- package/dist/index.es.js.map +1 -1
- package/dist/types/render/components/index.d.ts +1 -1
- package/dist/types/render/components/util/optionsUtil.d.ts +24 -8
- package/dist/types/render/hooks/index.d.ts +1 -1
- package/dist/types/render/hooks/useDeepCompareMemoize.d.ts +8 -0
- package/package.json +2 -2
- package/dist/types/render/hooks/useDeepCompareState.d.ts +0 -8
package/dist/index.cjs
CHANGED
|
@@ -792,20 +792,59 @@ function useCondition(condition) {
|
|
|
792
792
|
}, [conditionChecker, condition, expressionContextInfo]);
|
|
793
793
|
}
|
|
794
794
|
|
|
795
|
-
|
|
796
|
-
|
|
795
|
+
/**
|
|
796
|
+
* Returns the options data for the provided if they can be simply determined, ignoring expression defined options.
|
|
797
|
+
*
|
|
798
|
+
* @param {object} formField
|
|
799
|
+
* @param {object} formData
|
|
800
|
+
*/
|
|
801
|
+
function getSimpleOptionsData(formField, formData) {
|
|
797
802
|
const {
|
|
803
|
+
valuesExpression: optionsExpression,
|
|
798
804
|
valuesKey: optionsKey,
|
|
799
805
|
values: staticOptions
|
|
800
806
|
} = formField;
|
|
807
|
+
if (optionsExpression) {
|
|
808
|
+
return null;
|
|
809
|
+
}
|
|
801
810
|
return optionsKey ? minDash.get(formData, [optionsKey]) : staticOptions;
|
|
802
811
|
}
|
|
803
812
|
|
|
804
|
-
|
|
813
|
+
/**
|
|
814
|
+
* Normalizes the provided options data to a format that can be used by the select components.
|
|
815
|
+
* If the options data is not valid, it is filtered out.
|
|
816
|
+
*
|
|
817
|
+
* @param {any[]} optionsData
|
|
818
|
+
*
|
|
819
|
+
* @returns {object[]}
|
|
820
|
+
*/
|
|
805
821
|
function normalizeOptionsData(optionsData) {
|
|
806
822
|
return optionsData.filter(_isAllowedValue).map(_normalizeOption).filter(o => !minDash.isNil(o));
|
|
807
823
|
}
|
|
808
824
|
|
|
825
|
+
/**
|
|
826
|
+
* Creates an options object with default values if no options are provided.
|
|
827
|
+
*
|
|
828
|
+
* @param {object} options
|
|
829
|
+
*
|
|
830
|
+
* @returns {object}
|
|
831
|
+
*/
|
|
832
|
+
function createEmptyOptions(options = {}) {
|
|
833
|
+
const defaults = {};
|
|
834
|
+
|
|
835
|
+
// provide default options if valuesKey and valuesExpression are not set
|
|
836
|
+
if (!options.valuesKey && !options.valuesExpression) {
|
|
837
|
+
defaults.values = [{
|
|
838
|
+
label: 'Value',
|
|
839
|
+
value: 'value'
|
|
840
|
+
}];
|
|
841
|
+
}
|
|
842
|
+
return {
|
|
843
|
+
...defaults,
|
|
844
|
+
...options
|
|
845
|
+
};
|
|
846
|
+
}
|
|
847
|
+
|
|
809
848
|
/**
|
|
810
849
|
* Converts the provided option to a normalized format.
|
|
811
850
|
* If the option is not valid, null is returned.
|
|
@@ -856,21 +895,6 @@ function _isAllowedValue(value) {
|
|
|
856
895
|
}
|
|
857
896
|
return _isAllowedPrimitive(value);
|
|
858
897
|
}
|
|
859
|
-
function createEmptyOptions(options = {}) {
|
|
860
|
-
const defaults = {};
|
|
861
|
-
|
|
862
|
-
// provide default options if valuesKey and valuesExpression are not set
|
|
863
|
-
if (!options.valuesKey && !options.valuesExpression) {
|
|
864
|
-
defaults.values = [{
|
|
865
|
-
label: 'Value',
|
|
866
|
-
value: 'value'
|
|
867
|
-
}];
|
|
868
|
-
}
|
|
869
|
-
return {
|
|
870
|
-
...defaults,
|
|
871
|
-
...options
|
|
872
|
-
};
|
|
873
|
-
}
|
|
874
898
|
|
|
875
899
|
/**
|
|
876
900
|
* Evaluate a string reactively based on the expressionLanguage and form data.
|
|
@@ -891,29 +915,19 @@ function useExpressionEvaluation(value) {
|
|
|
891
915
|
}, [expressionLanguage, expressionContextInfo, value]);
|
|
892
916
|
}
|
|
893
917
|
|
|
894
|
-
function usePrevious(value, defaultValue = null) {
|
|
895
|
-
const ref = hooks.useRef(defaultValue);
|
|
896
|
-
hooks.useEffect(() => ref.current = value, [value]);
|
|
897
|
-
return ref.current;
|
|
898
|
-
}
|
|
899
|
-
|
|
900
918
|
/**
|
|
901
919
|
* A custom hook to manage state changes with deep comparison.
|
|
902
920
|
*
|
|
903
|
-
* @
|
|
904
|
-
* @param {
|
|
905
|
-
* @returns {
|
|
921
|
+
* @template T
|
|
922
|
+
* @param {T} value - The current value to manage.
|
|
923
|
+
* @returns {T} - Returns the current state.
|
|
906
924
|
*/
|
|
907
|
-
function
|
|
908
|
-
const
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
setState(value);
|
|
914
|
-
}
|
|
915
|
-
}, [changed, value]);
|
|
916
|
-
return state;
|
|
925
|
+
function useDeepCompareMemoize(value) {
|
|
926
|
+
const ref = hooks.useRef();
|
|
927
|
+
if (!isEqual(value, ref.current)) {
|
|
928
|
+
ref.current = value;
|
|
929
|
+
}
|
|
930
|
+
return ref.current;
|
|
917
931
|
}
|
|
918
932
|
|
|
919
933
|
/**
|
|
@@ -943,15 +957,10 @@ function useOptionsAsync(field) {
|
|
|
943
957
|
valuesKey: optionsKey,
|
|
944
958
|
values: staticOptions
|
|
945
959
|
} = field;
|
|
946
|
-
const [optionsGetter, setOptionsGetter] = hooks.useState({
|
|
947
|
-
options: [],
|
|
948
|
-
error: undefined,
|
|
949
|
-
loadState: LOAD_STATES.LOADING
|
|
950
|
-
});
|
|
951
960
|
const initialData = useService('form')._getState().initialData;
|
|
952
961
|
const expressionEvaluation = useExpressionEvaluation(optionsExpression);
|
|
953
|
-
const evaluatedOptions =
|
|
954
|
-
hooks.
|
|
962
|
+
const evaluatedOptions = useDeepCompareMemoize(expressionEvaluation || []);
|
|
963
|
+
const optionsGetter = hooks.useMemo(() => {
|
|
955
964
|
let options = [];
|
|
956
965
|
|
|
957
966
|
// dynamic options
|
|
@@ -966,18 +975,16 @@ function useOptionsAsync(field) {
|
|
|
966
975
|
options = Array.isArray(staticOptions) ? staticOptions : [];
|
|
967
976
|
|
|
968
977
|
// expression
|
|
969
|
-
} else if (optionsExpression) {
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
978
|
+
} else if (optionsExpression && evaluatedOptions && Array.isArray(evaluatedOptions)) {
|
|
979
|
+
options = evaluatedOptions;
|
|
980
|
+
|
|
981
|
+
// error case
|
|
973
982
|
} else {
|
|
974
|
-
|
|
975
|
-
return;
|
|
983
|
+
return buildErrorState('No options source defined in the form definition');
|
|
976
984
|
}
|
|
977
985
|
|
|
978
986
|
// normalize data to support primitives and partially defined objects
|
|
979
|
-
|
|
980
|
-
setOptionsGetter(buildLoadedState(options));
|
|
987
|
+
return buildLoadedState(normalizeOptionsData(options));
|
|
981
988
|
}, [optionsKey, staticOptions, initialData, optionsExpression, evaluatedOptions]);
|
|
982
989
|
return optionsGetter;
|
|
983
990
|
}
|
|
@@ -1022,14 +1029,14 @@ const getDOMPurifyConfig = sanitizeStyleTags => {
|
|
|
1022
1029
|
};
|
|
1023
1030
|
};
|
|
1024
1031
|
|
|
1025
|
-
/**
|
|
1026
|
-
* A custom hook to build up security attributes from form configuration.
|
|
1027
|
-
*
|
|
1028
|
-
* @param {Object} security - The security configuration.
|
|
1029
|
-
* @returns {Array} - Returns a tuple with sandbox and allow attributes.
|
|
1032
|
+
/**
|
|
1033
|
+
* A custom hook to build up security attributes from form configuration.
|
|
1034
|
+
*
|
|
1035
|
+
* @param {Object} security - The security configuration.
|
|
1036
|
+
* @returns {Array} - Returns a tuple with sandbox and allow attributes.
|
|
1030
1037
|
*/
|
|
1031
1038
|
function useSecurityAttributesMap(security) {
|
|
1032
|
-
const securityMemoized =
|
|
1039
|
+
const securityMemoized = useDeepCompareMemoize(security);
|
|
1033
1040
|
const sandbox = hooks.useMemo(() => SECURITY_ATTRIBUTES_DEFINITIONS.filter(({
|
|
1034
1041
|
attribute
|
|
1035
1042
|
}) => attribute === SANDBOX_ATTRIBUTE).filter(({
|
|
@@ -1201,6 +1208,12 @@ function useReadonly(formField, properties = {}) {
|
|
|
1201
1208
|
return readonly || false;
|
|
1202
1209
|
}
|
|
1203
1210
|
|
|
1211
|
+
function usePrevious(value, defaultValue = null) {
|
|
1212
|
+
const ref = hooks.useRef(defaultValue);
|
|
1213
|
+
hooks.useEffect(() => ref.current = value, [value]);
|
|
1214
|
+
return ref.current;
|
|
1215
|
+
}
|
|
1216
|
+
|
|
1204
1217
|
function useFlushDebounce(func) {
|
|
1205
1218
|
const timeoutRef = hooks.useRef(null);
|
|
1206
1219
|
const lastArgsRef = hooks.useRef(null);
|
|
@@ -1465,8 +1478,16 @@ function sanitizeSingleSelectValue(options) {
|
|
|
1465
1478
|
data,
|
|
1466
1479
|
value
|
|
1467
1480
|
} = options;
|
|
1481
|
+
const {
|
|
1482
|
+
valuesExpression: optionsExpression
|
|
1483
|
+
} = formField;
|
|
1468
1484
|
try {
|
|
1469
|
-
|
|
1485
|
+
// if options are expression evaluated, we don't need to sanitize the value against the options
|
|
1486
|
+
// and defer to the field's internal validation
|
|
1487
|
+
if (optionsExpression) {
|
|
1488
|
+
return value;
|
|
1489
|
+
}
|
|
1490
|
+
const validValues = normalizeOptionsData(getSimpleOptionsData(formField, data)).map(v => v.value);
|
|
1470
1491
|
return hasEqualValue(value, validValues) ? value : null;
|
|
1471
1492
|
} catch (error) {
|
|
1472
1493
|
// use default value in case of formatting error
|
|
@@ -1480,8 +1501,16 @@ function sanitizeMultiSelectValue(options) {
|
|
|
1480
1501
|
data,
|
|
1481
1502
|
value
|
|
1482
1503
|
} = options;
|
|
1504
|
+
const {
|
|
1505
|
+
valuesExpression: optionsExpression
|
|
1506
|
+
} = formField;
|
|
1483
1507
|
try {
|
|
1484
|
-
|
|
1508
|
+
// if options are expression evaluated, we don't need to sanitize the values against the options
|
|
1509
|
+
// and defer to the field's internal validation
|
|
1510
|
+
if (optionsExpression) {
|
|
1511
|
+
return value;
|
|
1512
|
+
}
|
|
1513
|
+
const validValues = normalizeOptionsData(getSimpleOptionsData(formField, data)).map(v => v.value);
|
|
1485
1514
|
return value.filter(v => hasEqualValue(v, validValues));
|
|
1486
1515
|
} catch (error) {
|
|
1487
1516
|
// use default value in case of formatting error
|
|
@@ -1569,7 +1598,7 @@ function useCleanupMultiSelectValue(props) {
|
|
|
1569
1598
|
onChange,
|
|
1570
1599
|
values
|
|
1571
1600
|
} = props;
|
|
1572
|
-
const memoizedValues =
|
|
1601
|
+
const memoizedValues = useDeepCompareMemoize(values || []);
|
|
1573
1602
|
|
|
1574
1603
|
// ensures that the values are always a subset of the possible options
|
|
1575
1604
|
hooks.useEffect(() => {
|
|
@@ -2257,7 +2286,7 @@ function Datepicker(props) {
|
|
|
2257
2286
|
const [forceFocusCalendar, setForceFocusCalendar] = hooks.useState(false);
|
|
2258
2287
|
|
|
2259
2288
|
// ensures we render based on date value instead of reference
|
|
2260
|
-
const date =
|
|
2289
|
+
const date = useDeepCompareMemoize(dateObject);
|
|
2261
2290
|
|
|
2262
2291
|
// shorts the date value back to the source
|
|
2263
2292
|
hooks.useEffect(() => {
|
|
@@ -3693,8 +3722,8 @@ function Numberfield(props) {
|
|
|
3693
3722
|
'fjs-readonly': readonly
|
|
3694
3723
|
}),
|
|
3695
3724
|
children: [jsxRuntime.jsx("button", {
|
|
3696
|
-
class: "fjs-number-arrow-up",
|
|
3697
3725
|
type: "button",
|
|
3726
|
+
class: "fjs-number-arrow-up",
|
|
3698
3727
|
"aria-label": "Increment",
|
|
3699
3728
|
onClick: () => increment(),
|
|
3700
3729
|
tabIndex: -1,
|
|
@@ -3702,8 +3731,8 @@ function Numberfield(props) {
|
|
|
3702
3731
|
}), jsxRuntime.jsx("div", {
|
|
3703
3732
|
class: "fjs-number-arrow-separator"
|
|
3704
3733
|
}), jsxRuntime.jsx("button", {
|
|
3705
|
-
class: "fjs-number-arrow-down",
|
|
3706
3734
|
type: "button",
|
|
3735
|
+
class: "fjs-number-arrow-down",
|
|
3707
3736
|
"aria-label": "Decrement",
|
|
3708
3737
|
onClick: () => decrement(),
|
|
3709
3738
|
tabIndex: -1,
|
|
@@ -4374,7 +4403,7 @@ function Taglist(props) {
|
|
|
4374
4403
|
} = useOptionsAsync(field);
|
|
4375
4404
|
|
|
4376
4405
|
// ensures we render based on array content instead of reference
|
|
4377
|
-
const values =
|
|
4406
|
+
const values = useDeepCompareMemoize(value || []);
|
|
4378
4407
|
useCleanupMultiSelectValue({
|
|
4379
4408
|
field,
|
|
4380
4409
|
loadState,
|
|
@@ -6615,9 +6644,9 @@ class RepeatRenderManager {
|
|
|
6615
6644
|
};
|
|
6616
6645
|
const parentExpressionContextInfo = hooks.useContext(LocalExpressionContext);
|
|
6617
6646
|
return jsxRuntime.jsx(jsxRuntime.Fragment, {
|
|
6618
|
-
children: displayValues.map((
|
|
6619
|
-
|
|
6620
|
-
|
|
6647
|
+
children: displayValues.map((itemValue, itemIndex) => jsxRuntime.jsx(RepetitionScaffold, {
|
|
6648
|
+
itemIndex: itemIndex,
|
|
6649
|
+
itemValue: itemValue,
|
|
6621
6650
|
parentExpressionContextInfo: parentExpressionContextInfo,
|
|
6622
6651
|
repeaterField: repeaterField,
|
|
6623
6652
|
RowsRenderer: RowsRenderer,
|
|
@@ -6625,7 +6654,7 @@ class RepeatRenderManager {
|
|
|
6625
6654
|
onDeleteItem: onDeleteItem,
|
|
6626
6655
|
showRemove: showRemove,
|
|
6627
6656
|
...restProps
|
|
6628
|
-
},
|
|
6657
|
+
}, itemIndex))
|
|
6629
6658
|
});
|
|
6630
6659
|
}
|
|
6631
6660
|
RepeatFooter(props) {
|
|
@@ -6688,18 +6717,18 @@ class RepeatRenderManager {
|
|
|
6688
6717
|
'fjs-remove-allowed': repeaterField.allowAddRemove
|
|
6689
6718
|
}),
|
|
6690
6719
|
children: [showAdd ? jsxRuntime.jsx("button", {
|
|
6720
|
+
type: "button",
|
|
6691
6721
|
readOnly: readonly,
|
|
6692
6722
|
disabled: disabled || readonly,
|
|
6693
6723
|
class: "fjs-repeat-render-add",
|
|
6694
|
-
type: "button",
|
|
6695
6724
|
ref: addButtonRef,
|
|
6696
6725
|
onClick: onAddItem,
|
|
6697
6726
|
children: jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
6698
6727
|
children: [jsxRuntime.jsx(AddSvg, {}), " ", 'Add new']
|
|
6699
6728
|
})
|
|
6700
6729
|
}) : null, collapseEnabled ? jsxRuntime.jsx("button", {
|
|
6701
|
-
class: "fjs-repeat-render-collapse",
|
|
6702
6730
|
type: "button",
|
|
6731
|
+
class: "fjs-repeat-render-collapse",
|
|
6703
6732
|
onClick: toggle,
|
|
6704
6733
|
children: isCollapsed ? jsxRuntime.jsxs(jsxRuntime.Fragment, {
|
|
6705
6734
|
children: [jsxRuntime.jsx(ExpandSvg, {}), " ", `Expand all (${values.length})`]
|
|
@@ -6722,8 +6751,8 @@ class RepeatRenderManager {
|
|
|
6722
6751
|
* Individual repetition of a repeated field and context scaffolding.
|
|
6723
6752
|
*
|
|
6724
6753
|
* @param {Object} props
|
|
6725
|
-
* @param {number} props.
|
|
6726
|
-
* @param {Object} props.
|
|
6754
|
+
* @param {number} props.itemIndex
|
|
6755
|
+
* @param {Object} props.itemValue
|
|
6727
6756
|
* @param {Object} props.parentExpressionContextInfo
|
|
6728
6757
|
* @param {Object} props.repeaterField
|
|
6729
6758
|
* @param {Function} props.RowsRenderer
|
|
@@ -6734,8 +6763,8 @@ class RepeatRenderManager {
|
|
|
6734
6763
|
|
|
6735
6764
|
const RepetitionScaffold = props => {
|
|
6736
6765
|
const {
|
|
6737
|
-
|
|
6738
|
-
|
|
6766
|
+
itemIndex,
|
|
6767
|
+
itemValue,
|
|
6739
6768
|
parentExpressionContextInfo,
|
|
6740
6769
|
repeaterField,
|
|
6741
6770
|
RowsRenderer,
|
|
@@ -6748,15 +6777,15 @@ const RepetitionScaffold = props => {
|
|
|
6748
6777
|
...restProps,
|
|
6749
6778
|
indexes: {
|
|
6750
6779
|
...(indexes || {}),
|
|
6751
|
-
[repeaterField.id]:
|
|
6780
|
+
[repeaterField.id]: itemIndex
|
|
6752
6781
|
}
|
|
6753
|
-
}), [
|
|
6782
|
+
}), [itemIndex, indexes, repeaterField.id, restProps]);
|
|
6754
6783
|
const localExpressionContextInfo = hooks.useMemo(() => ({
|
|
6755
6784
|
data: parentExpressionContextInfo.data,
|
|
6756
|
-
this:
|
|
6785
|
+
this: itemValue,
|
|
6757
6786
|
parent: buildExpressionContext(parentExpressionContextInfo),
|
|
6758
|
-
i: [...parentExpressionContextInfo.i,
|
|
6759
|
-
}), [
|
|
6787
|
+
i: [...parentExpressionContextInfo.i, itemIndex + 1]
|
|
6788
|
+
}), [itemIndex, parentExpressionContextInfo, itemValue]);
|
|
6760
6789
|
return !showRemove ? jsxRuntime.jsx(LocalExpressionContext.Provider, {
|
|
6761
6790
|
value: localExpressionContextInfo,
|
|
6762
6791
|
children: jsxRuntime.jsx(RowsRenderer, {
|
|
@@ -6773,10 +6802,10 @@ const RepetitionScaffold = props => {
|
|
|
6773
6802
|
})
|
|
6774
6803
|
})
|
|
6775
6804
|
}), jsxRuntime.jsx("button", {
|
|
6776
|
-
class: "fjs-repeat-row-remove",
|
|
6777
6805
|
type: "button",
|
|
6778
|
-
"
|
|
6779
|
-
|
|
6806
|
+
class: "fjs-repeat-row-remove",
|
|
6807
|
+
"aria-label": `Remove list item ${itemIndex + 1}`,
|
|
6808
|
+
onClick: () => onDeleteItem(itemIndex),
|
|
6780
6809
|
children: jsxRuntime.jsx("div", {
|
|
6781
6810
|
class: "fjs-repeat-row-remove-icon-container",
|
|
6782
6811
|
children: jsxRuntime.jsx(DeleteSvg, {})
|