@bpmn-io/form-js-viewer 1.7.0 → 1.7.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/LICENSE +22 -22
- package/README.md +189 -189
- package/dist/index.cjs +270 -163
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +271 -164
- package/dist/index.es.js.map +1 -1
- package/dist/types/render/components/Label.d.ts +4 -2
- 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/dist/types/types.d.ts +35 -35
- package/package.json +2 -2
- package/dist/types/render/hooks/useDeepCompareState.d.ts +0 -8
package/dist/index.es.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isString, get, isNil, isObject, some, isNumber, set, findIndex, isArray
|
|
|
3
3
|
import Big from 'big.js';
|
|
4
4
|
import classNames from 'classnames';
|
|
5
5
|
import { jsx, jsxs, Fragment } from 'preact/jsx-runtime';
|
|
6
|
-
import { useContext, useMemo, useRef, useEffect, useState,
|
|
6
|
+
import { useContext, useMemo, useRef, useCallback, useEffect, useState, useLayoutEffect } from 'preact/hooks';
|
|
7
7
|
import { createContext, createElement, Fragment as Fragment$1, render } from 'preact';
|
|
8
8
|
import isEqual from 'lodash/isEqual';
|
|
9
9
|
import flatpickr from 'flatpickr';
|
|
@@ -772,20 +772,59 @@ function useCondition(condition) {
|
|
|
772
772
|
}, [conditionChecker, condition, expressionContextInfo]);
|
|
773
773
|
}
|
|
774
774
|
|
|
775
|
-
|
|
776
|
-
|
|
775
|
+
/**
|
|
776
|
+
* Returns the options data for the provided if they can be simply determined, ignoring expression defined options.
|
|
777
|
+
*
|
|
778
|
+
* @param {object} formField
|
|
779
|
+
* @param {object} formData
|
|
780
|
+
*/
|
|
781
|
+
function getSimpleOptionsData(formField, formData) {
|
|
777
782
|
const {
|
|
783
|
+
valuesExpression: optionsExpression,
|
|
778
784
|
valuesKey: optionsKey,
|
|
779
785
|
values: staticOptions
|
|
780
786
|
} = formField;
|
|
787
|
+
if (optionsExpression) {
|
|
788
|
+
return null;
|
|
789
|
+
}
|
|
781
790
|
return optionsKey ? get(formData, [optionsKey]) : staticOptions;
|
|
782
791
|
}
|
|
783
792
|
|
|
784
|
-
|
|
793
|
+
/**
|
|
794
|
+
* Normalizes the provided options data to a format that can be used by the select components.
|
|
795
|
+
* If the options data is not valid, it is filtered out.
|
|
796
|
+
*
|
|
797
|
+
* @param {any[]} optionsData
|
|
798
|
+
*
|
|
799
|
+
* @returns {object[]}
|
|
800
|
+
*/
|
|
785
801
|
function normalizeOptionsData(optionsData) {
|
|
786
802
|
return optionsData.filter(_isAllowedValue).map(_normalizeOption).filter(o => !isNil(o));
|
|
787
803
|
}
|
|
788
804
|
|
|
805
|
+
/**
|
|
806
|
+
* Creates an options object with default values if no options are provided.
|
|
807
|
+
*
|
|
808
|
+
* @param {object} options
|
|
809
|
+
*
|
|
810
|
+
* @returns {object}
|
|
811
|
+
*/
|
|
812
|
+
function createEmptyOptions(options = {}) {
|
|
813
|
+
const defaults = {};
|
|
814
|
+
|
|
815
|
+
// provide default options if valuesKey and valuesExpression are not set
|
|
816
|
+
if (!options.valuesKey && !options.valuesExpression) {
|
|
817
|
+
defaults.values = [{
|
|
818
|
+
label: 'Value',
|
|
819
|
+
value: 'value'
|
|
820
|
+
}];
|
|
821
|
+
}
|
|
822
|
+
return {
|
|
823
|
+
...defaults,
|
|
824
|
+
...options
|
|
825
|
+
};
|
|
826
|
+
}
|
|
827
|
+
|
|
789
828
|
/**
|
|
790
829
|
* Converts the provided option to a normalized format.
|
|
791
830
|
* If the option is not valid, null is returned.
|
|
@@ -836,21 +875,6 @@ function _isAllowedValue(value) {
|
|
|
836
875
|
}
|
|
837
876
|
return _isAllowedPrimitive(value);
|
|
838
877
|
}
|
|
839
|
-
function createEmptyOptions(options = {}) {
|
|
840
|
-
const defaults = {};
|
|
841
|
-
|
|
842
|
-
// provide default options if valuesKey and valuesExpression are not set
|
|
843
|
-
if (!options.valuesKey && !options.valuesExpression) {
|
|
844
|
-
defaults.values = [{
|
|
845
|
-
label: 'Value',
|
|
846
|
-
value: 'value'
|
|
847
|
-
}];
|
|
848
|
-
}
|
|
849
|
-
return {
|
|
850
|
-
...defaults,
|
|
851
|
-
...options
|
|
852
|
-
};
|
|
853
|
-
}
|
|
854
878
|
|
|
855
879
|
/**
|
|
856
880
|
* Evaluate a string reactively based on the expressionLanguage and form data.
|
|
@@ -871,29 +895,19 @@ function useExpressionEvaluation(value) {
|
|
|
871
895
|
}, [expressionLanguage, expressionContextInfo, value]);
|
|
872
896
|
}
|
|
873
897
|
|
|
874
|
-
function usePrevious(value, defaultValue = null) {
|
|
875
|
-
const ref = useRef(defaultValue);
|
|
876
|
-
useEffect(() => ref.current = value, [value]);
|
|
877
|
-
return ref.current;
|
|
878
|
-
}
|
|
879
|
-
|
|
880
898
|
/**
|
|
881
899
|
* A custom hook to manage state changes with deep comparison.
|
|
882
900
|
*
|
|
883
|
-
* @
|
|
884
|
-
* @param {
|
|
885
|
-
* @returns {
|
|
901
|
+
* @template T
|
|
902
|
+
* @param {T} value - The current value to manage.
|
|
903
|
+
* @returns {T} - Returns the current state.
|
|
886
904
|
*/
|
|
887
|
-
function
|
|
888
|
-
const
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
setState(value);
|
|
894
|
-
}
|
|
895
|
-
}, [changed, value]);
|
|
896
|
-
return state;
|
|
905
|
+
function useDeepCompareMemoize(value) {
|
|
906
|
+
const ref = useRef();
|
|
907
|
+
if (!isEqual(value, ref.current)) {
|
|
908
|
+
ref.current = value;
|
|
909
|
+
}
|
|
910
|
+
return ref.current;
|
|
897
911
|
}
|
|
898
912
|
|
|
899
913
|
/**
|
|
@@ -923,15 +937,10 @@ function useOptionsAsync(field) {
|
|
|
923
937
|
valuesKey: optionsKey,
|
|
924
938
|
values: staticOptions
|
|
925
939
|
} = field;
|
|
926
|
-
const [optionsGetter, setOptionsGetter] = useState({
|
|
927
|
-
options: [],
|
|
928
|
-
error: undefined,
|
|
929
|
-
loadState: LOAD_STATES.LOADING
|
|
930
|
-
});
|
|
931
940
|
const initialData = useService('form')._getState().initialData;
|
|
932
941
|
const expressionEvaluation = useExpressionEvaluation(optionsExpression);
|
|
933
|
-
const evaluatedOptions =
|
|
934
|
-
|
|
942
|
+
const evaluatedOptions = useDeepCompareMemoize(expressionEvaluation || []);
|
|
943
|
+
const optionsGetter = useMemo(() => {
|
|
935
944
|
let options = [];
|
|
936
945
|
|
|
937
946
|
// dynamic options
|
|
@@ -946,18 +955,16 @@ function useOptionsAsync(field) {
|
|
|
946
955
|
options = Array.isArray(staticOptions) ? staticOptions : [];
|
|
947
956
|
|
|
948
957
|
// expression
|
|
949
|
-
} else if (optionsExpression) {
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
958
|
+
} else if (optionsExpression && evaluatedOptions && Array.isArray(evaluatedOptions)) {
|
|
959
|
+
options = evaluatedOptions;
|
|
960
|
+
|
|
961
|
+
// error case
|
|
953
962
|
} else {
|
|
954
|
-
|
|
955
|
-
return;
|
|
963
|
+
return buildErrorState('No options source defined in the form definition');
|
|
956
964
|
}
|
|
957
965
|
|
|
958
966
|
// normalize data to support primitives and partially defined objects
|
|
959
|
-
|
|
960
|
-
setOptionsGetter(buildLoadedState(options));
|
|
967
|
+
return buildLoadedState(normalizeOptionsData(options));
|
|
961
968
|
}, [optionsKey, staticOptions, initialData, optionsExpression, evaluatedOptions]);
|
|
962
969
|
return optionsGetter;
|
|
963
970
|
}
|
|
@@ -1002,14 +1009,14 @@ const getDOMPurifyConfig = sanitizeStyleTags => {
|
|
|
1002
1009
|
};
|
|
1003
1010
|
};
|
|
1004
1011
|
|
|
1005
|
-
/**
|
|
1006
|
-
* A custom hook to build up security attributes from form configuration.
|
|
1007
|
-
*
|
|
1008
|
-
* @param {Object} security - The security configuration.
|
|
1009
|
-
* @returns {Array} - Returns a tuple with sandbox and allow attributes.
|
|
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.
|
|
1010
1017
|
*/
|
|
1011
1018
|
function useSecurityAttributesMap(security) {
|
|
1012
|
-
const securityMemoized =
|
|
1019
|
+
const securityMemoized = useDeepCompareMemoize(security);
|
|
1013
1020
|
const sandbox = useMemo(() => SECURITY_ATTRIBUTES_DEFINITIONS.filter(({
|
|
1014
1021
|
attribute
|
|
1015
1022
|
}) => attribute === SANDBOX_ATTRIBUTE).filter(({
|
|
@@ -1181,6 +1188,12 @@ function useReadonly(formField, properties = {}) {
|
|
|
1181
1188
|
return readonly || false;
|
|
1182
1189
|
}
|
|
1183
1190
|
|
|
1191
|
+
function usePrevious(value, defaultValue = null) {
|
|
1192
|
+
const ref = useRef(defaultValue);
|
|
1193
|
+
useEffect(() => ref.current = value, [value]);
|
|
1194
|
+
return ref.current;
|
|
1195
|
+
}
|
|
1196
|
+
|
|
1184
1197
|
function useFlushDebounce(func) {
|
|
1185
1198
|
const timeoutRef = useRef(null);
|
|
1186
1199
|
const lastArgsRef = useRef(null);
|
|
@@ -1445,8 +1458,16 @@ function sanitizeSingleSelectValue(options) {
|
|
|
1445
1458
|
data,
|
|
1446
1459
|
value
|
|
1447
1460
|
} = options;
|
|
1461
|
+
const {
|
|
1462
|
+
valuesExpression: optionsExpression
|
|
1463
|
+
} = formField;
|
|
1448
1464
|
try {
|
|
1449
|
-
|
|
1465
|
+
// if options are expression evaluated, we don't need to sanitize the value against the options
|
|
1466
|
+
// and defer to the field's internal validation
|
|
1467
|
+
if (optionsExpression) {
|
|
1468
|
+
return value;
|
|
1469
|
+
}
|
|
1470
|
+
const validValues = normalizeOptionsData(getSimpleOptionsData(formField, data)).map(v => v.value);
|
|
1450
1471
|
return hasEqualValue(value, validValues) ? value : null;
|
|
1451
1472
|
} catch (error) {
|
|
1452
1473
|
// use default value in case of formatting error
|
|
@@ -1460,8 +1481,16 @@ function sanitizeMultiSelectValue(options) {
|
|
|
1460
1481
|
data,
|
|
1461
1482
|
value
|
|
1462
1483
|
} = options;
|
|
1484
|
+
const {
|
|
1485
|
+
valuesExpression: optionsExpression
|
|
1486
|
+
} = formField;
|
|
1463
1487
|
try {
|
|
1464
|
-
|
|
1488
|
+
// if options are expression evaluated, we don't need to sanitize the values against the options
|
|
1489
|
+
// and defer to the field's internal validation
|
|
1490
|
+
if (optionsExpression) {
|
|
1491
|
+
return value;
|
|
1492
|
+
}
|
|
1493
|
+
const validValues = normalizeOptionsData(getSimpleOptionsData(formField, data)).map(v => v.value);
|
|
1465
1494
|
return value.filter(v => hasEqualValue(v, validValues));
|
|
1466
1495
|
} catch (error) {
|
|
1467
1496
|
// use default value in case of formatting error
|
|
@@ -1549,7 +1578,7 @@ function useCleanupMultiSelectValue(props) {
|
|
|
1549
1578
|
onChange,
|
|
1550
1579
|
values
|
|
1551
1580
|
} = props;
|
|
1552
|
-
const memoizedValues =
|
|
1581
|
+
const memoizedValues = useDeepCompareMemoize(values || []);
|
|
1553
1582
|
|
|
1554
1583
|
// ensures that the values are always a subset of the possible options
|
|
1555
1584
|
useEffect(() => {
|
|
@@ -1569,7 +1598,8 @@ function useCleanupMultiSelectValue(props) {
|
|
|
1569
1598
|
|
|
1570
1599
|
function Description(props) {
|
|
1571
1600
|
const {
|
|
1572
|
-
description
|
|
1601
|
+
description,
|
|
1602
|
+
id
|
|
1573
1603
|
} = props;
|
|
1574
1604
|
const evaluatedDescription = useSingleLineTemplateEvaluation(description || '', {
|
|
1575
1605
|
debug: true
|
|
@@ -1578,6 +1608,7 @@ function Description(props) {
|
|
|
1578
1608
|
return null;
|
|
1579
1609
|
}
|
|
1580
1610
|
return jsx("div", {
|
|
1611
|
+
id: id,
|
|
1581
1612
|
class: "fjs-form-field-description",
|
|
1582
1613
|
children: evaluatedDescription
|
|
1583
1614
|
});
|
|
@@ -1608,6 +1639,7 @@ function Errors(props) {
|
|
|
1608
1639
|
function Label(props) {
|
|
1609
1640
|
const {
|
|
1610
1641
|
id,
|
|
1642
|
+
htmlFor,
|
|
1611
1643
|
label,
|
|
1612
1644
|
collapseOnEmpty = true,
|
|
1613
1645
|
required = false
|
|
@@ -1616,12 +1648,14 @@ function Label(props) {
|
|
|
1616
1648
|
debug: true
|
|
1617
1649
|
});
|
|
1618
1650
|
return jsxs("label", {
|
|
1619
|
-
|
|
1651
|
+
id: id,
|
|
1652
|
+
for: htmlFor,
|
|
1620
1653
|
class: classNames('fjs-form-field-label', {
|
|
1621
1654
|
'fjs-incollapsible-label': !collapseOnEmpty
|
|
1622
1655
|
}, props['class']),
|
|
1623
1656
|
children: [props.children, evaluatedLabel, required && jsx("span", {
|
|
1624
1657
|
class: "fjs-asterix",
|
|
1658
|
+
"aria-hidden": true,
|
|
1625
1659
|
children: "*"
|
|
1626
1660
|
})]
|
|
1627
1661
|
});
|
|
@@ -1632,7 +1666,6 @@ function Checkbox(props) {
|
|
|
1632
1666
|
const {
|
|
1633
1667
|
disabled,
|
|
1634
1668
|
errors = [],
|
|
1635
|
-
errorMessageId,
|
|
1636
1669
|
domId,
|
|
1637
1670
|
onBlur,
|
|
1638
1671
|
onFocus,
|
|
@@ -1656,6 +1689,8 @@ function Checkbox(props) {
|
|
|
1656
1689
|
value: target.checked
|
|
1657
1690
|
});
|
|
1658
1691
|
};
|
|
1692
|
+
const descriptionId = `${domId}-description`;
|
|
1693
|
+
const errorMessageId = `${domId}-error-message`;
|
|
1659
1694
|
return jsxs("div", {
|
|
1660
1695
|
class: classNames(formFieldClasses(type$f, {
|
|
1661
1696
|
errors,
|
|
@@ -1665,7 +1700,7 @@ function Checkbox(props) {
|
|
|
1665
1700
|
'fjs-checked': value
|
|
1666
1701
|
}),
|
|
1667
1702
|
children: [jsx(Label, {
|
|
1668
|
-
|
|
1703
|
+
htmlFor: domId,
|
|
1669
1704
|
label: label,
|
|
1670
1705
|
required: required,
|
|
1671
1706
|
children: jsx("input", {
|
|
@@ -1678,13 +1713,16 @@ function Checkbox(props) {
|
|
|
1678
1713
|
onChange: onChange,
|
|
1679
1714
|
onBlur: () => onBlur && onBlur(),
|
|
1680
1715
|
onFocus: () => onFocus && onFocus(),
|
|
1681
|
-
|
|
1716
|
+
required: required,
|
|
1717
|
+
"aria-invalid": errors.length > 0,
|
|
1718
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' ')
|
|
1682
1719
|
})
|
|
1683
1720
|
}), jsx(Description, {
|
|
1721
|
+
id: descriptionId,
|
|
1684
1722
|
description: description
|
|
1685
1723
|
}), jsx(Errors, {
|
|
1686
|
-
|
|
1687
|
-
|
|
1724
|
+
id: errorMessageId,
|
|
1725
|
+
errors: errors
|
|
1688
1726
|
})]
|
|
1689
1727
|
});
|
|
1690
1728
|
}
|
|
@@ -1707,7 +1745,6 @@ function Checklist(props) {
|
|
|
1707
1745
|
const {
|
|
1708
1746
|
disabled,
|
|
1709
1747
|
errors = [],
|
|
1710
|
-
errorMessageId,
|
|
1711
1748
|
domId,
|
|
1712
1749
|
onBlur,
|
|
1713
1750
|
onFocus,
|
|
@@ -1754,6 +1791,8 @@ function Checklist(props) {
|
|
|
1754
1791
|
values,
|
|
1755
1792
|
onChange: props.onChange
|
|
1756
1793
|
});
|
|
1794
|
+
const descriptionId = `${domId}-description`;
|
|
1795
|
+
const errorMessageId = `${domId}-error-message`;
|
|
1757
1796
|
return jsxs("div", {
|
|
1758
1797
|
class: classNames(formFieldClasses(type$e, {
|
|
1759
1798
|
errors,
|
|
@@ -1768,7 +1807,7 @@ function Checklist(props) {
|
|
|
1768
1807
|
const itemDomId = `${domId}-${index}`;
|
|
1769
1808
|
const isChecked = hasEqualValue(o.value, values);
|
|
1770
1809
|
return jsx(Label, {
|
|
1771
|
-
|
|
1810
|
+
htmlFor: itemDomId,
|
|
1772
1811
|
label: o.label,
|
|
1773
1812
|
class: classNames({
|
|
1774
1813
|
'fjs-checked': isChecked
|
|
@@ -1784,14 +1823,17 @@ function Checklist(props) {
|
|
|
1784
1823
|
onClick: () => toggleCheckbox(o.value),
|
|
1785
1824
|
onBlur: onCheckboxBlur,
|
|
1786
1825
|
onFocus: onCheckboxFocus,
|
|
1787
|
-
|
|
1826
|
+
required: required,
|
|
1827
|
+
"aria-invalid": errors.length > 0,
|
|
1828
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' ')
|
|
1788
1829
|
})
|
|
1789
1830
|
});
|
|
1790
1831
|
}), jsx(Description, {
|
|
1832
|
+
id: descriptionId,
|
|
1791
1833
|
description: description
|
|
1792
1834
|
}), jsx(Errors, {
|
|
1793
|
-
|
|
1794
|
-
|
|
1835
|
+
id: errorMessageId,
|
|
1836
|
+
errors: errors
|
|
1795
1837
|
})]
|
|
1796
1838
|
});
|
|
1797
1839
|
}
|
|
@@ -1871,6 +1913,7 @@ function FormField(props) {
|
|
|
1871
1913
|
}
|
|
1872
1914
|
}, [viewerCommands, field, initialValue, initialValidationTrigger, indexes]);
|
|
1873
1915
|
const onBlur = useCallback(() => {
|
|
1916
|
+
const value = get(data, valuePath);
|
|
1874
1917
|
if (initialValidationTrigger) {
|
|
1875
1918
|
setInitialValidationTrigger(false);
|
|
1876
1919
|
viewerCommands.updateFieldValidation(field, value, indexes);
|
|
@@ -1878,7 +1921,7 @@ function FormField(props) {
|
|
|
1878
1921
|
eventBus.fire('formField.blur', {
|
|
1879
1922
|
formField: field
|
|
1880
1923
|
});
|
|
1881
|
-
}, [eventBus, field, indexes,
|
|
1924
|
+
}, [eventBus, field, indexes, viewerCommands, initialValidationTrigger, data, valuePath]);
|
|
1882
1925
|
const onFocus = useCallback(() => {
|
|
1883
1926
|
eventBus.fire('formField.focus', {
|
|
1884
1927
|
formField: field
|
|
@@ -1902,7 +1945,6 @@ function FormField(props) {
|
|
|
1902
1945
|
}
|
|
1903
1946
|
const domId = `${prefixId(field.id, formId, indexes)}`;
|
|
1904
1947
|
const fieldErrors = get(errors, [field.id, ...Object.values(indexes || {})]) || [];
|
|
1905
|
-
const errorMessageId = errors.length === 0 ? undefined : `${domId}-error-message`;
|
|
1906
1948
|
return jsx(Column, {
|
|
1907
1949
|
field: field,
|
|
1908
1950
|
class: gridColumnClasses(field),
|
|
@@ -1913,7 +1955,6 @@ function FormField(props) {
|
|
|
1913
1955
|
...props,
|
|
1914
1956
|
disabled: disabled,
|
|
1915
1957
|
errors: fieldErrors,
|
|
1916
|
-
errorMessageId: errorMessageId,
|
|
1917
1958
|
domId: domId,
|
|
1918
1959
|
onChange: disabled || readonly ? noop$1 : onChangeIndexed,
|
|
1919
1960
|
onBlur: disabled || readonly ? noop$1 : onBlur,
|
|
@@ -2225,7 +2266,7 @@ function Datepicker(props) {
|
|
|
2225
2266
|
const [forceFocusCalendar, setForceFocusCalendar] = useState(false);
|
|
2226
2267
|
|
|
2227
2268
|
// ensures we render based on date value instead of reference
|
|
2228
|
-
const date =
|
|
2269
|
+
const date = useDeepCompareMemoize(dateObject);
|
|
2229
2270
|
|
|
2230
2271
|
// shorts the date value back to the source
|
|
2231
2272
|
useEffect(() => {
|
|
@@ -2316,7 +2357,7 @@ function Datepicker(props) {
|
|
|
2316
2357
|
return jsxs("div", {
|
|
2317
2358
|
class: "fjs-datetime-subsection",
|
|
2318
2359
|
children: [jsx(Label, {
|
|
2319
|
-
|
|
2360
|
+
htmlFor: domId,
|
|
2320
2361
|
label: label,
|
|
2321
2362
|
collapseOnEmpty: collapseLabelOnEmpty,
|
|
2322
2363
|
required: required
|
|
@@ -2588,7 +2629,7 @@ function Timepicker(props) {
|
|
|
2588
2629
|
return jsxs("div", {
|
|
2589
2630
|
class: "fjs-datetime-subsection",
|
|
2590
2631
|
children: [jsx(Label, {
|
|
2591
|
-
|
|
2632
|
+
htmlFor: domId,
|
|
2592
2633
|
label: label,
|
|
2593
2634
|
collapseOnEmpty: collapseLabelOnEmpty,
|
|
2594
2635
|
required: required
|
|
@@ -2775,6 +2816,7 @@ function Datetime(props) {
|
|
|
2775
2816
|
});
|
|
2776
2817
|
}, []);
|
|
2777
2818
|
const errorMessageId = allErrors.length === 0 ? undefined : `${prefixId(id, formId)}-error-message`;
|
|
2819
|
+
const descriptionId = `${prefixId(id, formId)}-description`;
|
|
2778
2820
|
const datePickerProps = {
|
|
2779
2821
|
label: dateLabel,
|
|
2780
2822
|
collapseLabelOnEmpty: !timeLabel,
|
|
@@ -2787,7 +2829,7 @@ function Datetime(props) {
|
|
|
2787
2829
|
date: dateTime.date,
|
|
2788
2830
|
readonly,
|
|
2789
2831
|
setDate,
|
|
2790
|
-
'aria-describedby': errorMessageId
|
|
2832
|
+
'aria-describedby': [descriptionId, errorMessageId].join(' ')
|
|
2791
2833
|
};
|
|
2792
2834
|
const timePickerProps = {
|
|
2793
2835
|
label: timeLabel,
|
|
@@ -2802,7 +2844,7 @@ function Datetime(props) {
|
|
|
2802
2844
|
timeInterval,
|
|
2803
2845
|
time: dateTime.time,
|
|
2804
2846
|
setTime,
|
|
2805
|
-
'aria-describedby': errorMessageId
|
|
2847
|
+
'aria-describedby': [descriptionId, errorMessageId].join(' ')
|
|
2806
2848
|
};
|
|
2807
2849
|
return jsxs("div", {
|
|
2808
2850
|
class: formFieldClasses(type$d, {
|
|
@@ -2821,6 +2863,7 @@ function Datetime(props) {
|
|
|
2821
2863
|
...timePickerProps
|
|
2822
2864
|
})]
|
|
2823
2865
|
}), jsx(Description, {
|
|
2866
|
+
id: descriptionId,
|
|
2824
2867
|
description: description
|
|
2825
2868
|
}), jsx(Errors, {
|
|
2826
2869
|
errors: allErrors,
|
|
@@ -2924,7 +2967,7 @@ function IFrame(props) {
|
|
|
2924
2967
|
readonly
|
|
2925
2968
|
}),
|
|
2926
2969
|
children: [jsx(Label, {
|
|
2927
|
-
|
|
2970
|
+
htmlFor: domId,
|
|
2928
2971
|
label: evaluatedLabel
|
|
2929
2972
|
}), !evaluatedUrl && jsx(IFramePlaceholder, {
|
|
2930
2973
|
text: "No content to show."
|
|
@@ -3470,7 +3513,6 @@ function Numberfield(props) {
|
|
|
3470
3513
|
const {
|
|
3471
3514
|
disabled,
|
|
3472
3515
|
errors = [],
|
|
3473
|
-
errorMessageId,
|
|
3474
3516
|
domId,
|
|
3475
3517
|
onBlur,
|
|
3476
3518
|
onFocus,
|
|
@@ -3608,6 +3650,8 @@ function Numberfield(props) {
|
|
|
3608
3650
|
e.preventDefault();
|
|
3609
3651
|
}
|
|
3610
3652
|
};
|
|
3653
|
+
const descriptionId = `${domId}-description`;
|
|
3654
|
+
const errorMessageId = `${domId}-error-message`;
|
|
3611
3655
|
return jsxs("div", {
|
|
3612
3656
|
class: formFieldClasses(type$a, {
|
|
3613
3657
|
errors,
|
|
@@ -3615,7 +3659,7 @@ function Numberfield(props) {
|
|
|
3615
3659
|
readonly
|
|
3616
3660
|
}),
|
|
3617
3661
|
children: [jsx(Label, {
|
|
3618
|
-
|
|
3662
|
+
htmlFor: domId,
|
|
3619
3663
|
label: label,
|
|
3620
3664
|
required: required
|
|
3621
3665
|
}), jsx(TemplatedInputAdorner, {
|
|
@@ -3649,15 +3693,17 @@ function Numberfield(props) {
|
|
|
3649
3693
|
autoComplete: "off",
|
|
3650
3694
|
step: incrementAmount,
|
|
3651
3695
|
value: displayValue,
|
|
3652
|
-
"aria-describedby": errorMessageId
|
|
3696
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' '),
|
|
3697
|
+
required: required,
|
|
3698
|
+
"aria-invalid": errors.length > 0
|
|
3653
3699
|
}), jsxs("div", {
|
|
3654
3700
|
class: classNames('fjs-number-arrow-container', {
|
|
3655
3701
|
'fjs-disabled': disabled,
|
|
3656
3702
|
'fjs-readonly': readonly
|
|
3657
3703
|
}),
|
|
3658
3704
|
children: [jsx("button", {
|
|
3659
|
-
class: "fjs-number-arrow-up",
|
|
3660
3705
|
type: "button",
|
|
3706
|
+
class: "fjs-number-arrow-up",
|
|
3661
3707
|
"aria-label": "Increment",
|
|
3662
3708
|
onClick: () => increment(),
|
|
3663
3709
|
tabIndex: -1,
|
|
@@ -3665,8 +3711,8 @@ function Numberfield(props) {
|
|
|
3665
3711
|
}), jsx("div", {
|
|
3666
3712
|
class: "fjs-number-arrow-separator"
|
|
3667
3713
|
}), jsx("button", {
|
|
3668
|
-
class: "fjs-number-arrow-down",
|
|
3669
3714
|
type: "button",
|
|
3715
|
+
class: "fjs-number-arrow-down",
|
|
3670
3716
|
"aria-label": "Decrement",
|
|
3671
3717
|
onClick: () => decrement(),
|
|
3672
3718
|
tabIndex: -1,
|
|
@@ -3675,10 +3721,11 @@ function Numberfield(props) {
|
|
|
3675
3721
|
})]
|
|
3676
3722
|
})
|
|
3677
3723
|
}), jsx(Description, {
|
|
3724
|
+
id: descriptionId,
|
|
3678
3725
|
description: description
|
|
3679
3726
|
}), jsx(Errors, {
|
|
3680
|
-
|
|
3681
|
-
|
|
3727
|
+
id: errorMessageId,
|
|
3728
|
+
errors: errors
|
|
3682
3729
|
})]
|
|
3683
3730
|
});
|
|
3684
3731
|
}
|
|
@@ -3708,7 +3755,6 @@ function Radio(props) {
|
|
|
3708
3755
|
const {
|
|
3709
3756
|
disabled,
|
|
3710
3757
|
errors = [],
|
|
3711
|
-
errorMessageId,
|
|
3712
3758
|
domId,
|
|
3713
3759
|
onBlur,
|
|
3714
3760
|
onFocus,
|
|
@@ -3754,6 +3800,8 @@ function Radio(props) {
|
|
|
3754
3800
|
value,
|
|
3755
3801
|
onChange: props.onChange
|
|
3756
3802
|
});
|
|
3803
|
+
const descriptionId = `${domId}-description`;
|
|
3804
|
+
const errorMessageId = `${domId}-error-message`;
|
|
3757
3805
|
return jsxs("div", {
|
|
3758
3806
|
class: formFieldClasses(type$9, {
|
|
3759
3807
|
errors,
|
|
@@ -3768,7 +3816,7 @@ function Radio(props) {
|
|
|
3768
3816
|
const itemDomId = `${domId}-${index}`;
|
|
3769
3817
|
const isChecked = isEqual(option.value, value);
|
|
3770
3818
|
return jsx(Label, {
|
|
3771
|
-
|
|
3819
|
+
htmlFor: itemDomId,
|
|
3772
3820
|
label: option.label,
|
|
3773
3821
|
class: classNames({
|
|
3774
3822
|
'fjs-checked': isChecked
|
|
@@ -3784,14 +3832,17 @@ function Radio(props) {
|
|
|
3784
3832
|
onClick: () => onChange(option.value),
|
|
3785
3833
|
onBlur: onRadioBlur,
|
|
3786
3834
|
onFocus: onRadioFocus,
|
|
3787
|
-
"aria-describedby": errorMessageId
|
|
3835
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' '),
|
|
3836
|
+
required: required,
|
|
3837
|
+
"aria-invalid": errors.length > 0
|
|
3788
3838
|
})
|
|
3789
3839
|
}, index);
|
|
3790
3840
|
}), jsx(Description, {
|
|
3841
|
+
id: descriptionId,
|
|
3791
3842
|
description: description
|
|
3792
3843
|
}), jsx(Errors, {
|
|
3793
|
-
|
|
3794
|
-
|
|
3844
|
+
id: errorMessageId,
|
|
3845
|
+
errors: errors
|
|
3795
3846
|
})]
|
|
3796
3847
|
});
|
|
3797
3848
|
}
|
|
@@ -3856,7 +3907,7 @@ function SearchableSelect(props) {
|
|
|
3856
3907
|
|
|
3857
3908
|
// whenever we change the underlying value, set the label to it
|
|
3858
3909
|
useEffect(() => {
|
|
3859
|
-
setFilter(label);
|
|
3910
|
+
setFilter(label || '');
|
|
3860
3911
|
}, [label]);
|
|
3861
3912
|
const filteredOptions = useMemo(() => {
|
|
3862
3913
|
if (loadState !== LOAD_STATES.LOADED) {
|
|
@@ -3936,7 +3987,7 @@ function SearchableSelect(props) {
|
|
|
3936
3987
|
}, [onFocus]);
|
|
3937
3988
|
const onInputBlur = useCallback(() => {
|
|
3938
3989
|
setIsDropdownExpanded(false);
|
|
3939
|
-
setFilter(label);
|
|
3990
|
+
setFilter(label || '');
|
|
3940
3991
|
onBlur && onBlur();
|
|
3941
3992
|
}, [onBlur, label]);
|
|
3942
3993
|
return jsxs(Fragment, {
|
|
@@ -4032,6 +4083,9 @@ function SimpleSelect(props) {
|
|
|
4032
4083
|
}, [disabled, isDropdownExpanded, loadState, readonly, value]);
|
|
4033
4084
|
const onMouseDown = useCallback(e => {
|
|
4034
4085
|
const input = inputRef.current;
|
|
4086
|
+
if (disabled || !input) {
|
|
4087
|
+
return;
|
|
4088
|
+
}
|
|
4035
4089
|
setIsDropdownExpanded(!isDropdownExpanded);
|
|
4036
4090
|
if (isDropdownExpanded) {
|
|
4037
4091
|
input.blur();
|
|
@@ -4039,7 +4093,7 @@ function SimpleSelect(props) {
|
|
|
4039
4093
|
input.focus();
|
|
4040
4094
|
}
|
|
4041
4095
|
e.preventDefault();
|
|
4042
|
-
}, [isDropdownExpanded]);
|
|
4096
|
+
}, [disabled, isDropdownExpanded]);
|
|
4043
4097
|
const initialFocusIndex = useMemo(() => value && findIndex(options, o => o.value === value) || 0, [options, value]);
|
|
4044
4098
|
const onInputFocus = useCallback(() => {
|
|
4045
4099
|
if (!readonly) {
|
|
@@ -4111,7 +4165,6 @@ function Select(props) {
|
|
|
4111
4165
|
const {
|
|
4112
4166
|
disabled,
|
|
4113
4167
|
errors = [],
|
|
4114
|
-
errorMessageId,
|
|
4115
4168
|
domId,
|
|
4116
4169
|
onBlur,
|
|
4117
4170
|
onFocus,
|
|
@@ -4129,6 +4182,8 @@ function Select(props) {
|
|
|
4129
4182
|
const {
|
|
4130
4183
|
required
|
|
4131
4184
|
} = validate;
|
|
4185
|
+
const descriptionId = `${domId}-description`;
|
|
4186
|
+
const errorMessageId = `${domId}-error-message`;
|
|
4132
4187
|
const selectProps = {
|
|
4133
4188
|
domId,
|
|
4134
4189
|
disabled,
|
|
@@ -4139,7 +4194,9 @@ function Select(props) {
|
|
|
4139
4194
|
value,
|
|
4140
4195
|
onChange,
|
|
4141
4196
|
readonly,
|
|
4142
|
-
|
|
4197
|
+
required,
|
|
4198
|
+
'aria-invalid': errors.length > 0,
|
|
4199
|
+
'aria-describedby': [descriptionId, errorMessageId].join(' ')
|
|
4143
4200
|
};
|
|
4144
4201
|
return jsxs("div", {
|
|
4145
4202
|
class: formFieldClasses(type$8, {
|
|
@@ -4154,7 +4211,7 @@ function Select(props) {
|
|
|
4154
4211
|
}
|
|
4155
4212
|
},
|
|
4156
4213
|
children: [jsx(Label, {
|
|
4157
|
-
|
|
4214
|
+
htmlFor: domId,
|
|
4158
4215
|
label: label,
|
|
4159
4216
|
required: required
|
|
4160
4217
|
}), searchable ? jsx(SearchableSelect, {
|
|
@@ -4162,10 +4219,11 @@ function Select(props) {
|
|
|
4162
4219
|
}) : jsx(SimpleSelect, {
|
|
4163
4220
|
...selectProps
|
|
4164
4221
|
}), jsx(Description, {
|
|
4222
|
+
id: descriptionId,
|
|
4165
4223
|
description: description
|
|
4166
4224
|
}), jsx(Errors, {
|
|
4167
|
-
|
|
4168
|
-
|
|
4225
|
+
id: errorMessageId,
|
|
4226
|
+
errors: errors
|
|
4169
4227
|
})]
|
|
4170
4228
|
});
|
|
4171
4229
|
}
|
|
@@ -4298,7 +4356,6 @@ function Taglist(props) {
|
|
|
4298
4356
|
const {
|
|
4299
4357
|
disabled,
|
|
4300
4358
|
errors = [],
|
|
4301
|
-
errorMessageId,
|
|
4302
4359
|
onFocus,
|
|
4303
4360
|
domId,
|
|
4304
4361
|
onBlur,
|
|
@@ -4326,7 +4383,7 @@ function Taglist(props) {
|
|
|
4326
4383
|
} = useOptionsAsync(field);
|
|
4327
4384
|
|
|
4328
4385
|
// ensures we render based on array content instead of reference
|
|
4329
|
-
const values =
|
|
4386
|
+
const values = useDeepCompareMemoize(value || []);
|
|
4330
4387
|
useCleanupMultiSelectValue({
|
|
4331
4388
|
field,
|
|
4332
4389
|
loadState,
|
|
@@ -4434,6 +4491,8 @@ function Taglist(props) {
|
|
|
4434
4491
|
inputRef.current.focus();
|
|
4435
4492
|
};
|
|
4436
4493
|
const shouldDisplayDropdown = useMemo(() => !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed, [disabled, isDropdownExpanded, isEscapeClosed, loadState]);
|
|
4494
|
+
const descriptionId = `${domId}-description`;
|
|
4495
|
+
const errorMessageId = `${domId}-error-message`;
|
|
4437
4496
|
return jsxs("div", {
|
|
4438
4497
|
ref: focusScopeRef,
|
|
4439
4498
|
class: formFieldClasses(type$5, {
|
|
@@ -4450,7 +4509,7 @@ function Taglist(props) {
|
|
|
4450
4509
|
children: [jsx(Label, {
|
|
4451
4510
|
label: label,
|
|
4452
4511
|
required: required,
|
|
4453
|
-
|
|
4512
|
+
htmlFor: domId
|
|
4454
4513
|
}), !disabled && !readonly && !!values.length && jsx(SkipLink, {
|
|
4455
4514
|
className: "fjs-taglist-skip-link",
|
|
4456
4515
|
label: "Skip to search",
|
|
@@ -4498,7 +4557,9 @@ function Taglist(props) {
|
|
|
4498
4557
|
onMouseDown: () => setIsEscapeClose(false),
|
|
4499
4558
|
onFocus: onInputFocus,
|
|
4500
4559
|
onBlur: onInputBlur,
|
|
4501
|
-
"aria-describedby": errorMessageId
|
|
4560
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' '),
|
|
4561
|
+
required: required,
|
|
4562
|
+
"aria-invalid": errors.length > 0
|
|
4502
4563
|
})]
|
|
4503
4564
|
}), jsx("div", {
|
|
4504
4565
|
class: "fjs-taglist-anchor",
|
|
@@ -4510,10 +4571,11 @@ function Taglist(props) {
|
|
|
4510
4571
|
listenerElement: inputRef.current
|
|
4511
4572
|
})
|
|
4512
4573
|
}), jsx(Description, {
|
|
4574
|
+
id: descriptionId,
|
|
4513
4575
|
description: description
|
|
4514
4576
|
}), jsx(Errors, {
|
|
4515
|
-
|
|
4516
|
-
|
|
4577
|
+
id: errorMessageId,
|
|
4578
|
+
errors: errors
|
|
4517
4579
|
})]
|
|
4518
4580
|
});
|
|
4519
4581
|
}
|
|
@@ -4830,7 +4892,6 @@ function Textfield(props) {
|
|
|
4830
4892
|
const {
|
|
4831
4893
|
disabled,
|
|
4832
4894
|
errors = [],
|
|
4833
|
-
errorMessageId,
|
|
4834
4895
|
domId,
|
|
4835
4896
|
onBlur,
|
|
4836
4897
|
onFocus,
|
|
@@ -4866,6 +4927,8 @@ function Textfield(props) {
|
|
|
4866
4927
|
const onInputFocus = () => {
|
|
4867
4928
|
onFocus && onFocus();
|
|
4868
4929
|
};
|
|
4930
|
+
const descriptionId = `${domId}-description`;
|
|
4931
|
+
const errorMessageId = `${domId}-error-message`;
|
|
4869
4932
|
return jsxs("div", {
|
|
4870
4933
|
class: formFieldClasses(type$2, {
|
|
4871
4934
|
errors,
|
|
@@ -4873,7 +4936,7 @@ function Textfield(props) {
|
|
|
4873
4936
|
readonly
|
|
4874
4937
|
}),
|
|
4875
4938
|
children: [jsx(Label, {
|
|
4876
|
-
|
|
4939
|
+
htmlFor: domId,
|
|
4877
4940
|
label: label,
|
|
4878
4941
|
required: required
|
|
4879
4942
|
}), jsx(TemplatedInputAdorner, {
|
|
@@ -4891,13 +4954,16 @@ function Textfield(props) {
|
|
|
4891
4954
|
onFocus: onInputFocus,
|
|
4892
4955
|
type: "text",
|
|
4893
4956
|
value: value,
|
|
4894
|
-
"aria-describedby": errorMessageId
|
|
4957
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' '),
|
|
4958
|
+
required: required,
|
|
4959
|
+
"aria-invalid": errors.length > 0
|
|
4895
4960
|
})
|
|
4896
4961
|
}), jsx(Description, {
|
|
4962
|
+
id: descriptionId,
|
|
4897
4963
|
description: description
|
|
4898
4964
|
}), jsx(Errors, {
|
|
4899
|
-
|
|
4900
|
-
|
|
4965
|
+
id: errorMessageId,
|
|
4966
|
+
errors: errors
|
|
4901
4967
|
})]
|
|
4902
4968
|
});
|
|
4903
4969
|
}
|
|
@@ -4930,7 +4996,6 @@ function Textarea(props) {
|
|
|
4930
4996
|
const {
|
|
4931
4997
|
disabled,
|
|
4932
4998
|
errors = [],
|
|
4933
|
-
errorMessageId,
|
|
4934
4999
|
domId,
|
|
4935
5000
|
onBlur,
|
|
4936
5001
|
onFocus,
|
|
@@ -4974,6 +5039,8 @@ function Textarea(props) {
|
|
|
4974
5039
|
useEffect(() => {
|
|
4975
5040
|
autoSizeTextarea(textareaRef.current);
|
|
4976
5041
|
}, []);
|
|
5042
|
+
const descriptionId = `${domId}-description`;
|
|
5043
|
+
const errorMessageId = `${domId}-error-message`;
|
|
4977
5044
|
return jsxs("div", {
|
|
4978
5045
|
class: formFieldClasses(type$1, {
|
|
4979
5046
|
errors,
|
|
@@ -4981,7 +5048,7 @@ function Textarea(props) {
|
|
|
4981
5048
|
readonly
|
|
4982
5049
|
}),
|
|
4983
5050
|
children: [jsx(Label, {
|
|
4984
|
-
|
|
5051
|
+
htmlFor: domId,
|
|
4985
5052
|
label: label,
|
|
4986
5053
|
required: required
|
|
4987
5054
|
}), jsx("textarea", {
|
|
@@ -4994,12 +5061,15 @@ function Textarea(props) {
|
|
|
4994
5061
|
onFocus: onInputFocus,
|
|
4995
5062
|
value: value,
|
|
4996
5063
|
ref: textareaRef,
|
|
4997
|
-
"aria-describedby": errorMessageId
|
|
5064
|
+
"aria-describedby": [descriptionId, errorMessageId].join(' '),
|
|
5065
|
+
required: required,
|
|
5066
|
+
"aria-invalid": errors.length > 0
|
|
4998
5067
|
}), jsx(Description, {
|
|
5068
|
+
id: descriptionId,
|
|
4999
5069
|
description: description
|
|
5000
5070
|
}), jsx(Errors, {
|
|
5001
|
-
|
|
5002
|
-
|
|
5071
|
+
id: errorMessageId,
|
|
5072
|
+
errors: errors
|
|
5003
5073
|
})]
|
|
5004
5074
|
});
|
|
5005
5075
|
}
|
|
@@ -5168,7 +5238,7 @@ function Table(props) {
|
|
|
5168
5238
|
return jsxs("div", {
|
|
5169
5239
|
class: formFieldClasses(type),
|
|
5170
5240
|
children: [jsx(Label, {
|
|
5171
|
-
|
|
5241
|
+
htmlFor: prefixId(id),
|
|
5172
5242
|
label: label
|
|
5173
5243
|
}), jsxs("div", {
|
|
5174
5244
|
class: classNames('fjs-table-middle-container', {
|
|
@@ -5568,7 +5638,7 @@ class FormFields {
|
|
|
5568
5638
|
}
|
|
5569
5639
|
|
|
5570
5640
|
const EXPRESSION_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'conditional.hide', 'description', 'label', 'source', 'readonly', 'text', 'validate.min', 'validate.max', 'validate.minLength', 'validate.maxLength', 'valuesExpression', 'url', 'dataSource', 'columnsExpression'];
|
|
5571
|
-
const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text', 'url'];
|
|
5641
|
+
const TEMPLATE_PROPERTIES = ['alt', 'appearance.prefixAdorner', 'appearance.suffixAdorner', 'description', 'label', 'source', 'text', 'content', 'url'];
|
|
5572
5642
|
|
|
5573
5643
|
/**
|
|
5574
5644
|
* @typedef { import('../types').Schema } Schema
|
|
@@ -6554,47 +6624,17 @@ class RepeatRenderManager {
|
|
|
6554
6624
|
};
|
|
6555
6625
|
const parentExpressionContextInfo = useContext(LocalExpressionContext);
|
|
6556
6626
|
return jsx(Fragment, {
|
|
6557
|
-
children: displayValues.map((value, index) => {
|
|
6558
|
-
|
|
6559
|
-
|
|
6560
|
-
|
|
6561
|
-
|
|
6562
|
-
|
|
6563
|
-
|
|
6564
|
-
|
|
6565
|
-
|
|
6566
|
-
|
|
6567
|
-
|
|
6568
|
-
parent: buildExpressionContext(parentExpressionContextInfo),
|
|
6569
|
-
i: [...parentExpressionContextInfo.i, index + 1]
|
|
6570
|
-
}), [index, value]);
|
|
6571
|
-
return !showRemove ? jsx(LocalExpressionContext.Provider, {
|
|
6572
|
-
value: localExpressionContextInfo,
|
|
6573
|
-
children: jsx(RowsRenderer, {
|
|
6574
|
-
...elementProps
|
|
6575
|
-
})
|
|
6576
|
-
}) : jsxs("div", {
|
|
6577
|
-
class: "fjs-repeat-row-container",
|
|
6578
|
-
children: [jsx("div", {
|
|
6579
|
-
class: "fjs-repeat-row-rows",
|
|
6580
|
-
children: jsx(LocalExpressionContext.Provider, {
|
|
6581
|
-
value: localExpressionContextInfo,
|
|
6582
|
-
children: jsx(RowsRenderer, {
|
|
6583
|
-
...elementProps
|
|
6584
|
-
})
|
|
6585
|
-
})
|
|
6586
|
-
}), jsx("button", {
|
|
6587
|
-
class: "fjs-repeat-row-remove",
|
|
6588
|
-
type: "button",
|
|
6589
|
-
"aria-label": `Remove list item ${index + 1}`,
|
|
6590
|
-
onClick: () => onDeleteItem(index),
|
|
6591
|
-
children: jsx("div", {
|
|
6592
|
-
class: "fjs-repeat-row-remove-icon-container",
|
|
6593
|
-
children: jsx(DeleteSvg, {})
|
|
6594
|
-
})
|
|
6595
|
-
})]
|
|
6596
|
-
});
|
|
6597
|
-
})
|
|
6627
|
+
children: displayValues.map((value, index) => jsx(RepetitionScaffold, {
|
|
6628
|
+
index: index,
|
|
6629
|
+
value: value,
|
|
6630
|
+
parentExpressionContextInfo: parentExpressionContextInfo,
|
|
6631
|
+
repeaterField: repeaterField,
|
|
6632
|
+
RowsRenderer: RowsRenderer,
|
|
6633
|
+
indexes: indexes,
|
|
6634
|
+
onDeleteItem: onDeleteItem,
|
|
6635
|
+
showRemove: showRemove,
|
|
6636
|
+
...restProps
|
|
6637
|
+
}, index))
|
|
6598
6638
|
});
|
|
6599
6639
|
}
|
|
6600
6640
|
RepeatFooter(props) {
|
|
@@ -6657,18 +6697,18 @@ class RepeatRenderManager {
|
|
|
6657
6697
|
'fjs-remove-allowed': repeaterField.allowAddRemove
|
|
6658
6698
|
}),
|
|
6659
6699
|
children: [showAdd ? jsx("button", {
|
|
6700
|
+
type: "button",
|
|
6660
6701
|
readOnly: readonly,
|
|
6661
6702
|
disabled: disabled || readonly,
|
|
6662
6703
|
class: "fjs-repeat-render-add",
|
|
6663
|
-
type: "button",
|
|
6664
6704
|
ref: addButtonRef,
|
|
6665
6705
|
onClick: onAddItem,
|
|
6666
6706
|
children: jsxs(Fragment, {
|
|
6667
6707
|
children: [jsx(AddSvg, {}), " ", 'Add new']
|
|
6668
6708
|
})
|
|
6669
6709
|
}) : null, collapseEnabled ? jsx("button", {
|
|
6670
|
-
class: "fjs-repeat-render-collapse",
|
|
6671
6710
|
type: "button",
|
|
6711
|
+
class: "fjs-repeat-render-collapse",
|
|
6672
6712
|
onClick: toggle,
|
|
6673
6713
|
children: isCollapsed ? jsxs(Fragment, {
|
|
6674
6714
|
children: [jsx(ExpandSvg, {}), " ", `Expand all (${values.length})`]
|
|
@@ -6686,6 +6726,73 @@ class RepeatRenderManager {
|
|
|
6686
6726
|
return nonCollapsedItems ? nonCollapsedItems : DEFAULT_NON_COLLAPSED_ITEMS;
|
|
6687
6727
|
}
|
|
6688
6728
|
}
|
|
6729
|
+
|
|
6730
|
+
/**
|
|
6731
|
+
* Individual repetition of a repeated field and context scaffolding.
|
|
6732
|
+
*
|
|
6733
|
+
* @param {Object} props
|
|
6734
|
+
* @param {number} props.index
|
|
6735
|
+
* @param {Object} props.value
|
|
6736
|
+
* @param {Object} props.parentExpressionContextInfo
|
|
6737
|
+
* @param {Object} props.repeaterField
|
|
6738
|
+
* @param {Function} props.RowsRenderer
|
|
6739
|
+
* @param {Object} props.indexes
|
|
6740
|
+
* @param {Function} props.onDeleteItem
|
|
6741
|
+
* @param {boolean} props.showRemove
|
|
6742
|
+
*/
|
|
6743
|
+
|
|
6744
|
+
const RepetitionScaffold = props => {
|
|
6745
|
+
const {
|
|
6746
|
+
index,
|
|
6747
|
+
value,
|
|
6748
|
+
parentExpressionContextInfo,
|
|
6749
|
+
repeaterField,
|
|
6750
|
+
RowsRenderer,
|
|
6751
|
+
indexes,
|
|
6752
|
+
onDeleteItem,
|
|
6753
|
+
showRemove,
|
|
6754
|
+
...restProps
|
|
6755
|
+
} = props;
|
|
6756
|
+
const elementProps = useMemo(() => ({
|
|
6757
|
+
...restProps,
|
|
6758
|
+
indexes: {
|
|
6759
|
+
...(indexes || {}),
|
|
6760
|
+
[repeaterField.id]: index
|
|
6761
|
+
}
|
|
6762
|
+
}), [index, indexes, repeaterField.id, restProps]);
|
|
6763
|
+
const localExpressionContextInfo = useMemo(() => ({
|
|
6764
|
+
data: parentExpressionContextInfo.data,
|
|
6765
|
+
this: value,
|
|
6766
|
+
parent: buildExpressionContext(parentExpressionContextInfo),
|
|
6767
|
+
i: [...parentExpressionContextInfo.i, index + 1]
|
|
6768
|
+
}), [index, parentExpressionContextInfo, value]);
|
|
6769
|
+
return !showRemove ? jsx(LocalExpressionContext.Provider, {
|
|
6770
|
+
value: localExpressionContextInfo,
|
|
6771
|
+
children: jsx(RowsRenderer, {
|
|
6772
|
+
...elementProps
|
|
6773
|
+
})
|
|
6774
|
+
}) : jsxs("div", {
|
|
6775
|
+
class: "fjs-repeat-row-container",
|
|
6776
|
+
children: [jsx("div", {
|
|
6777
|
+
class: "fjs-repeat-row-rows",
|
|
6778
|
+
children: jsx(LocalExpressionContext.Provider, {
|
|
6779
|
+
value: localExpressionContextInfo,
|
|
6780
|
+
children: jsx(RowsRenderer, {
|
|
6781
|
+
...elementProps
|
|
6782
|
+
})
|
|
6783
|
+
})
|
|
6784
|
+
}), jsx("button", {
|
|
6785
|
+
type: "button",
|
|
6786
|
+
class: "fjs-repeat-row-remove",
|
|
6787
|
+
"aria-label": `Remove list item ${index + 1}`,
|
|
6788
|
+
onClick: () => onDeleteItem(index),
|
|
6789
|
+
children: jsx("div", {
|
|
6790
|
+
class: "fjs-repeat-row-remove-icon-container",
|
|
6791
|
+
children: jsx(DeleteSvg, {})
|
|
6792
|
+
})
|
|
6793
|
+
})]
|
|
6794
|
+
});
|
|
6795
|
+
};
|
|
6689
6796
|
RepeatRenderManager.$inject = ['form', 'formFields', 'formFieldRegistry', 'pathRegistry'];
|
|
6690
6797
|
|
|
6691
6798
|
const RepeatRenderModule = {
|