@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/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 && (typeof value === 'undefined' || value === '')) {
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 importedData = clone(data);
720
- const importedSchema = this.importFormField(clone(schema), importedData);
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} field
735
+ * @return {any} importedField
737
736
  */
738
737
 
739
738
 
740
- importFormField(formField, data = {}, parentId) {
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); // set form field path
762
+ this._formFieldRegistry._keys.claim(key, formField); // TODO: buttons should not have key
764
763
 
765
764
 
766
- formField._path = [key];
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, data, id);
786
+ this.importFormFields(components, id);
785
787
  }
786
788
 
787
789
  return formField;
788
790
  }
789
791
 
790
- importFormFields(components, data = {}, parentId) {
792
+ importFormFields(components, parentId) {
791
793
  components.forEach(component => {
792
- this.importFormField(component, data, parentId);
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) ? undefined : 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
- }, v.value);
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 === '' ? undefined : 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
- }, v.value);
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'); // do not submit disabled form fields
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
- // strip disabled field value
1847
- set(data, _path, undefined);
1906
+ if (disabled || !_path) {
1907
+ return data;
1848
1908
  }
1849
1909
 
1850
- return data;
1851
- }, clone(this._getState().data));
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 = 2;
2138
+ const schemaVersion = 4;
2076
2139
  /**
2077
2140
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
2078
2141
  */