@bpmn-io/form-js-viewer 0.4.4 → 0.7.0
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/assets/form-js.css +36 -38
- package/dist/index.cjs +126 -63
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +126 -63
- package/dist/index.es.js.map +1 -1
- package/dist/types/Form.d.ts +5 -18
- package/dist/types/import/Importer.d.ts +9 -4
- package/dist/types/index.d.ts +1 -1
- package/dist/types/render/components/Util.d.ts +1 -1
- package/dist/types/render/components/form-fields/Checkbox.d.ts +1 -0
- package/dist/types/render/components/form-fields/Number.d.ts +1 -0
- package/dist/types/render/components/form-fields/Radio.d.ts +1 -0
- package/dist/types/render/components/form-fields/Select.d.ts +1 -0
- package/dist/types/render/components/form-fields/Textfield.d.ts +1 -0
- package/dist/types/render/components/index.d.ts +1 -1
- package/dist/types/render/context/FormContext.d.ts +1 -0
- package/package.json +3 -2
package/dist/index.es.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isArray, isFunction, isNumber, bind, assign, get, set, isString } from 'min-dash';
|
|
2
1
|
import Ids from 'ids';
|
|
2
|
+
import { isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, set, isString } from 'min-dash';
|
|
3
3
|
import snarkdown from '@bpmn-io/snarkdown';
|
|
4
4
|
import { jsx, jsxs } from 'preact/jsx-runtime';
|
|
5
5
|
import { useContext, useState, useCallback } from 'preact/hooks';
|
|
@@ -600,7 +600,7 @@ class Validator {
|
|
|
600
600
|
errors = [...errors, `Field must match pattern ${validate.pattern}.`];
|
|
601
601
|
}
|
|
602
602
|
|
|
603
|
-
if (validate.required && (
|
|
603
|
+
if (validate.required && (isNil(value) || value === '')) {
|
|
604
604
|
errors = [...errors, 'Field is required.'];
|
|
605
605
|
}
|
|
606
606
|
|
|
@@ -716,8 +716,8 @@ class Importer {
|
|
|
716
716
|
const warnings = [];
|
|
717
717
|
|
|
718
718
|
try {
|
|
719
|
-
const
|
|
720
|
-
|
|
719
|
+
const importedSchema = this.importFormField(clone(schema)),
|
|
720
|
+
importedData = this.importData(clone(data));
|
|
721
721
|
return {
|
|
722
722
|
warnings,
|
|
723
723
|
schema: importedSchema,
|
|
@@ -730,14 +730,13 @@ class Importer {
|
|
|
730
730
|
}
|
|
731
731
|
/**
|
|
732
732
|
* @param {any} formField
|
|
733
|
-
* @param {Object} [data]
|
|
734
733
|
* @param {string} [parentId]
|
|
735
734
|
*
|
|
736
|
-
* @return {any}
|
|
735
|
+
* @return {any} importedField
|
|
737
736
|
*/
|
|
738
737
|
|
|
739
738
|
|
|
740
|
-
importFormField(formField,
|
|
739
|
+
importFormField(formField, parentId) {
|
|
741
740
|
const {
|
|
742
741
|
components,
|
|
743
742
|
key,
|
|
@@ -760,10 +759,13 @@ class Importer {
|
|
|
760
759
|
throw new Error(`form field with key <${key}> already exists`);
|
|
761
760
|
}
|
|
762
761
|
|
|
763
|
-
this._formFieldRegistry._keys.claim(key, formField); //
|
|
762
|
+
this._formFieldRegistry._keys.claim(key, formField); // TODO: buttons should not have key
|
|
764
763
|
|
|
765
764
|
|
|
766
|
-
|
|
765
|
+
if (type !== 'button') {
|
|
766
|
+
// set form field path
|
|
767
|
+
formField._path = [key];
|
|
768
|
+
}
|
|
767
769
|
}
|
|
768
770
|
|
|
769
771
|
if (id) {
|
|
@@ -781,17 +783,44 @@ class Importer {
|
|
|
781
783
|
this._formFieldRegistry.add(formField);
|
|
782
784
|
|
|
783
785
|
if (components) {
|
|
784
|
-
this.importFormFields(components,
|
|
786
|
+
this.importFormFields(components, id);
|
|
785
787
|
}
|
|
786
788
|
|
|
787
789
|
return formField;
|
|
788
790
|
}
|
|
789
791
|
|
|
790
|
-
importFormFields(components,
|
|
792
|
+
importFormFields(components, parentId) {
|
|
791
793
|
components.forEach(component => {
|
|
792
|
-
this.importFormField(component,
|
|
794
|
+
this.importFormField(component, parentId);
|
|
793
795
|
});
|
|
794
796
|
}
|
|
797
|
+
/**
|
|
798
|
+
* @param {Object} data
|
|
799
|
+
*
|
|
800
|
+
* @return {Object} importedData
|
|
801
|
+
*/
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
importData(data) {
|
|
805
|
+
return this._formFieldRegistry.getAll().reduce((importedData, formField) => {
|
|
806
|
+
const {
|
|
807
|
+
defaultValue,
|
|
808
|
+
_path,
|
|
809
|
+
type
|
|
810
|
+
} = formField;
|
|
811
|
+
|
|
812
|
+
if (!_path) {
|
|
813
|
+
return importedData;
|
|
814
|
+
} // (1) try to get value from data
|
|
815
|
+
// (2) try to get default value from form field
|
|
816
|
+
// (3) get empty value from form field
|
|
817
|
+
|
|
818
|
+
|
|
819
|
+
return { ...importedData,
|
|
820
|
+
[_path[0]]: get(data, _path, isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
|
|
821
|
+
};
|
|
822
|
+
}, {});
|
|
823
|
+
}
|
|
795
824
|
|
|
796
825
|
}
|
|
797
826
|
Importer.$inject = ['formFieldRegistry', 'formFields'];
|
|
@@ -933,7 +962,11 @@ function formFieldClasses(type, errors = []) {
|
|
|
933
962
|
|
|
934
963
|
return classes.join(' ');
|
|
935
964
|
}
|
|
936
|
-
function prefixId(id) {
|
|
965
|
+
function prefixId(id, formId) {
|
|
966
|
+
if (formId) {
|
|
967
|
+
return `fjs-form-${formId}-${id}`;
|
|
968
|
+
}
|
|
969
|
+
|
|
937
970
|
return `fjs-form-${id}`;
|
|
938
971
|
}
|
|
939
972
|
function markdownToHTML(markdown) {
|
|
@@ -977,6 +1010,32 @@ Button.type = type$6;
|
|
|
977
1010
|
Button.label = 'Button';
|
|
978
1011
|
Button.keyed = true;
|
|
979
1012
|
|
|
1013
|
+
const FormRenderContext = createContext({
|
|
1014
|
+
Empty: props => {
|
|
1015
|
+
return null;
|
|
1016
|
+
},
|
|
1017
|
+
Children: props => {
|
|
1018
|
+
return props.children;
|
|
1019
|
+
},
|
|
1020
|
+
Element: props => {
|
|
1021
|
+
return props.children;
|
|
1022
|
+
}
|
|
1023
|
+
});
|
|
1024
|
+
|
|
1025
|
+
/**
|
|
1026
|
+
* @param {string} type
|
|
1027
|
+
* @param {boolean} [strict]
|
|
1028
|
+
*
|
|
1029
|
+
* @returns {any}
|
|
1030
|
+
*/
|
|
1031
|
+
|
|
1032
|
+
function getService(type, strict) {}
|
|
1033
|
+
|
|
1034
|
+
const FormContext = createContext({
|
|
1035
|
+
getService,
|
|
1036
|
+
formId: null
|
|
1037
|
+
});
|
|
1038
|
+
|
|
980
1039
|
function Description(props) {
|
|
981
1040
|
const {
|
|
982
1041
|
description
|
|
@@ -1052,17 +1111,20 @@ function Checkbox(props) {
|
|
|
1052
1111
|
});
|
|
1053
1112
|
};
|
|
1054
1113
|
|
|
1114
|
+
const {
|
|
1115
|
+
formId
|
|
1116
|
+
} = useContext(FormContext);
|
|
1055
1117
|
return jsxs("div", {
|
|
1056
1118
|
class: formFieldClasses(type$5, errors),
|
|
1057
1119
|
children: [jsx(Label, {
|
|
1058
|
-
id: prefixId(id),
|
|
1120
|
+
id: prefixId(id, formId),
|
|
1059
1121
|
label: label,
|
|
1060
1122
|
required: false,
|
|
1061
1123
|
children: jsx("input", {
|
|
1062
1124
|
checked: value,
|
|
1063
1125
|
class: "fjs-input",
|
|
1064
1126
|
disabled: disabled,
|
|
1065
|
-
id: prefixId(id),
|
|
1127
|
+
id: prefixId(id, formId),
|
|
1066
1128
|
type: "checkbox",
|
|
1067
1129
|
onChange: onChange
|
|
1068
1130
|
})
|
|
@@ -1082,31 +1144,7 @@ Checkbox.create = function (options = {}) {
|
|
|
1082
1144
|
Checkbox.type = type$5;
|
|
1083
1145
|
Checkbox.label = 'Checkbox';
|
|
1084
1146
|
Checkbox.keyed = true;
|
|
1085
|
-
|
|
1086
|
-
const FormRenderContext = createContext({
|
|
1087
|
-
Empty: props => {
|
|
1088
|
-
return null;
|
|
1089
|
-
},
|
|
1090
|
-
Children: props => {
|
|
1091
|
-
return props.children;
|
|
1092
|
-
},
|
|
1093
|
-
Element: props => {
|
|
1094
|
-
return props.children;
|
|
1095
|
-
}
|
|
1096
|
-
});
|
|
1097
|
-
|
|
1098
|
-
/**
|
|
1099
|
-
* @param {string} type
|
|
1100
|
-
* @param {boolean} [strict]
|
|
1101
|
-
*
|
|
1102
|
-
* @returns {any}
|
|
1103
|
-
*/
|
|
1104
|
-
|
|
1105
|
-
function getService(type, strict) {}
|
|
1106
|
-
|
|
1107
|
-
const FormContext = createContext({
|
|
1108
|
-
getService
|
|
1109
|
-
});
|
|
1147
|
+
Checkbox.emptyValue = false;
|
|
1110
1148
|
|
|
1111
1149
|
function useService (type, strict) {
|
|
1112
1150
|
const {
|
|
@@ -1347,20 +1385,23 @@ function Number(props) {
|
|
|
1347
1385
|
const parsedValue = parseInt(target.value, 10);
|
|
1348
1386
|
props.onChange({
|
|
1349
1387
|
field,
|
|
1350
|
-
value: isNaN(parsedValue) ?
|
|
1388
|
+
value: isNaN(parsedValue) ? null : parsedValue
|
|
1351
1389
|
});
|
|
1352
1390
|
};
|
|
1353
1391
|
|
|
1392
|
+
const {
|
|
1393
|
+
formId
|
|
1394
|
+
} = useContext(FormContext);
|
|
1354
1395
|
return jsxs("div", {
|
|
1355
1396
|
class: formFieldClasses(type$4, errors),
|
|
1356
1397
|
children: [jsx(Label, {
|
|
1357
|
-
id: prefixId(id),
|
|
1398
|
+
id: prefixId(id, formId),
|
|
1358
1399
|
label: label,
|
|
1359
1400
|
required: required
|
|
1360
1401
|
}), jsx("input", {
|
|
1361
1402
|
class: "fjs-input",
|
|
1362
1403
|
disabled: disabled,
|
|
1363
|
-
id: prefixId(id),
|
|
1404
|
+
id: prefixId(id, formId),
|
|
1364
1405
|
onInput: onChange,
|
|
1365
1406
|
type: "number",
|
|
1366
1407
|
value: value || ''
|
|
@@ -1380,6 +1421,7 @@ Number.create = function (options = {}) {
|
|
|
1380
1421
|
Number.type = type$4;
|
|
1381
1422
|
Number.keyed = true;
|
|
1382
1423
|
Number.label = 'Number';
|
|
1424
|
+
Number.emptyValue = null;
|
|
1383
1425
|
|
|
1384
1426
|
const type$3 = 'radio';
|
|
1385
1427
|
function Radio(props) {
|
|
@@ -1407,6 +1449,9 @@ function Radio(props) {
|
|
|
1407
1449
|
});
|
|
1408
1450
|
};
|
|
1409
1451
|
|
|
1452
|
+
const {
|
|
1453
|
+
formId
|
|
1454
|
+
} = useContext(FormContext);
|
|
1410
1455
|
return jsxs("div", {
|
|
1411
1456
|
class: formFieldClasses(type$3, errors),
|
|
1412
1457
|
children: [jsx(Label, {
|
|
@@ -1414,18 +1459,18 @@ function Radio(props) {
|
|
|
1414
1459
|
required: required
|
|
1415
1460
|
}), values.map((v, index) => {
|
|
1416
1461
|
return jsx(Label, {
|
|
1417
|
-
id: prefixId(`${id}-${index}
|
|
1462
|
+
id: prefixId(`${id}-${index}`, formId),
|
|
1418
1463
|
label: v.label,
|
|
1419
1464
|
required: false,
|
|
1420
1465
|
children: jsx("input", {
|
|
1421
1466
|
checked: v.value === value,
|
|
1422
1467
|
class: "fjs-input",
|
|
1423
1468
|
disabled: disabled,
|
|
1424
|
-
id: prefixId(`${id}-${index}
|
|
1469
|
+
id: prefixId(`${id}-${index}`, formId),
|
|
1425
1470
|
type: "radio",
|
|
1426
1471
|
onClick: () => onChange(v.value)
|
|
1427
1472
|
})
|
|
1428
|
-
},
|
|
1473
|
+
}, `${id}-${index}`);
|
|
1429
1474
|
}), jsx(Description, {
|
|
1430
1475
|
description: description
|
|
1431
1476
|
}), jsx(Errors, {
|
|
@@ -1447,6 +1492,7 @@ Radio.create = function (options = {}) {
|
|
|
1447
1492
|
Radio.type = type$3;
|
|
1448
1493
|
Radio.label = 'Radio';
|
|
1449
1494
|
Radio.keyed = true;
|
|
1495
|
+
Radio.emptyValue = null;
|
|
1450
1496
|
|
|
1451
1497
|
const type$2 = 'select';
|
|
1452
1498
|
function Select(props) {
|
|
@@ -1472,29 +1518,32 @@ function Select(props) {
|
|
|
1472
1518
|
}) => {
|
|
1473
1519
|
props.onChange({
|
|
1474
1520
|
field,
|
|
1475
|
-
value: target.value === '' ?
|
|
1521
|
+
value: target.value === '' ? null : target.value
|
|
1476
1522
|
});
|
|
1477
1523
|
};
|
|
1478
1524
|
|
|
1525
|
+
const {
|
|
1526
|
+
formId
|
|
1527
|
+
} = useContext(FormContext);
|
|
1479
1528
|
return jsxs("div", {
|
|
1480
1529
|
class: formFieldClasses(type$2, errors),
|
|
1481
1530
|
children: [jsx(Label, {
|
|
1482
|
-
id: prefixId(id),
|
|
1531
|
+
id: prefixId(id, formId),
|
|
1483
1532
|
label: label,
|
|
1484
1533
|
required: required
|
|
1485
1534
|
}), jsxs("select", {
|
|
1486
1535
|
class: "fjs-select",
|
|
1487
1536
|
disabled: disabled,
|
|
1488
|
-
id: prefixId(id),
|
|
1537
|
+
id: prefixId(id, formId),
|
|
1489
1538
|
onChange: onChange,
|
|
1490
1539
|
value: value || '',
|
|
1491
1540
|
children: [jsx("option", {
|
|
1492
1541
|
value: ""
|
|
1493
|
-
}), values.map(v => {
|
|
1542
|
+
}), values.map((v, index) => {
|
|
1494
1543
|
return jsx("option", {
|
|
1495
1544
|
value: v.value,
|
|
1496
1545
|
children: v.label
|
|
1497
|
-
},
|
|
1546
|
+
}, `${id}-${index}`);
|
|
1498
1547
|
})]
|
|
1499
1548
|
}), jsx(Description, {
|
|
1500
1549
|
description: description
|
|
@@ -1517,6 +1566,7 @@ Select.create = function (options = {}) {
|
|
|
1517
1566
|
Select.type = type$2;
|
|
1518
1567
|
Select.label = 'Select';
|
|
1519
1568
|
Select.keyed = true;
|
|
1569
|
+
Select.emptyValue = null;
|
|
1520
1570
|
|
|
1521
1571
|
const type$1 = 'text';
|
|
1522
1572
|
function Text(props) {
|
|
@@ -1572,16 +1622,19 @@ function Textfield(props) {
|
|
|
1572
1622
|
});
|
|
1573
1623
|
};
|
|
1574
1624
|
|
|
1625
|
+
const {
|
|
1626
|
+
formId
|
|
1627
|
+
} = useContext(FormContext);
|
|
1575
1628
|
return jsxs("div", {
|
|
1576
1629
|
class: formFieldClasses(type, errors),
|
|
1577
1630
|
children: [jsx(Label, {
|
|
1578
|
-
id: prefixId(id),
|
|
1631
|
+
id: prefixId(id, formId),
|
|
1579
1632
|
label: label,
|
|
1580
1633
|
required: required
|
|
1581
1634
|
}), jsx("input", {
|
|
1582
1635
|
class: "fjs-input",
|
|
1583
1636
|
disabled: disabled,
|
|
1584
|
-
id: prefixId(id),
|
|
1637
|
+
id: prefixId(id, formId),
|
|
1585
1638
|
onInput: onChange,
|
|
1586
1639
|
type: "text",
|
|
1587
1640
|
value: value
|
|
@@ -1601,6 +1654,7 @@ Textfield.create = function (options = {}) {
|
|
|
1601
1654
|
Textfield.type = type;
|
|
1602
1655
|
Textfield.label = 'Text Field';
|
|
1603
1656
|
Textfield.keyed = true;
|
|
1657
|
+
Textfield.emptyValue = '';
|
|
1604
1658
|
|
|
1605
1659
|
const formFields = [Button, Checkbox, Default, Number, Radio, Select, Text, Textfield];
|
|
1606
1660
|
|
|
@@ -1631,8 +1685,9 @@ function Renderer(config, eventBus, form, injector) {
|
|
|
1631
1685
|
const formContext = {
|
|
1632
1686
|
getService(type, strict = true) {
|
|
1633
1687
|
return injector.get(type, strict);
|
|
1634
|
-
}
|
|
1688
|
+
},
|
|
1635
1689
|
|
|
1690
|
+
formId: form._id
|
|
1636
1691
|
};
|
|
1637
1692
|
eventBus.on('changed', newState => {
|
|
1638
1693
|
setState(newState);
|
|
@@ -1712,6 +1767,7 @@ var core = {
|
|
|
1712
1767
|
* } } State
|
|
1713
1768
|
*/
|
|
1714
1769
|
|
|
1770
|
+
const ids = new Ids([32, 36, 1]);
|
|
1715
1771
|
/**
|
|
1716
1772
|
* The form.
|
|
1717
1773
|
*/
|
|
@@ -1722,10 +1778,16 @@ class Form {
|
|
|
1722
1778
|
* @param {FormOptions} options
|
|
1723
1779
|
*/
|
|
1724
1780
|
constructor(options = {}) {
|
|
1781
|
+
/**
|
|
1782
|
+
* @public
|
|
1783
|
+
* @type {String}
|
|
1784
|
+
*/
|
|
1785
|
+
this._id = ids.next();
|
|
1725
1786
|
/**
|
|
1726
1787
|
* @private
|
|
1727
1788
|
* @type {Element}
|
|
1728
1789
|
*/
|
|
1790
|
+
|
|
1729
1791
|
this._container = createFormContainer();
|
|
1730
1792
|
const {
|
|
1731
1793
|
container,
|
|
@@ -1834,21 +1896,22 @@ class Form {
|
|
|
1834
1896
|
throw new Error('form is read-only');
|
|
1835
1897
|
}
|
|
1836
1898
|
|
|
1837
|
-
const formFieldRegistry = this.get('formFieldRegistry');
|
|
1838
|
-
|
|
1899
|
+
const formFieldRegistry = this.get('formFieldRegistry');
|
|
1839
1900
|
const data = formFieldRegistry.getAll().reduce((data, field) => {
|
|
1840
1901
|
const {
|
|
1841
1902
|
disabled,
|
|
1842
1903
|
_path
|
|
1843
|
-
} = field;
|
|
1904
|
+
} = field; // do not submit disabled form fields
|
|
1844
1905
|
|
|
1845
|
-
if (disabled) {
|
|
1846
|
-
|
|
1847
|
-
set(data, _path, undefined);
|
|
1906
|
+
if (disabled || !_path) {
|
|
1907
|
+
return data;
|
|
1848
1908
|
}
|
|
1849
1909
|
|
|
1850
|
-
|
|
1851
|
-
|
|
1910
|
+
const value = get(this._getState().data, _path);
|
|
1911
|
+
return { ...data,
|
|
1912
|
+
[_path[0]]: value
|
|
1913
|
+
};
|
|
1914
|
+
}, {});
|
|
1852
1915
|
const errors = this.validate();
|
|
1853
1916
|
|
|
1854
1917
|
this._emit('submit', {
|
|
@@ -2072,7 +2135,7 @@ class Form {
|
|
|
2072
2135
|
|
|
2073
2136
|
}
|
|
2074
2137
|
|
|
2075
|
-
const schemaVersion =
|
|
2138
|
+
const schemaVersion = 4;
|
|
2076
2139
|
/**
|
|
2077
2140
|
* @typedef { import('./types').CreateFormOptions } CreateFormOptions
|
|
2078
2141
|
*/
|