@bpmn-io/form-js-viewer 0.5.1 → 0.7.1

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
1
  import Ids from 'ids';
2
- import { isArray, isFunction, isNumber, bind, assign, get, set, isString } from 'min-dash';
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';
@@ -8,109 +8,6 @@ import Markup from 'preact-markup';
8
8
  import { createPortal } from 'preact/compat';
9
9
  import { Injector } from 'didi';
10
10
 
11
- function createInjector(bootstrapModules) {
12
- const modules = [],
13
- components = [];
14
-
15
- function hasModule(module) {
16
- return modules.includes(module);
17
- }
18
-
19
- function addModule(module) {
20
- modules.push(module);
21
- }
22
-
23
- function visit(module) {
24
- if (hasModule(module)) {
25
- return;
26
- }
27
-
28
- (module.__depends__ || []).forEach(visit);
29
-
30
- if (hasModule(module)) {
31
- return;
32
- }
33
-
34
- addModule(module);
35
- (module.__init__ || []).forEach(function (component) {
36
- components.push(component);
37
- });
38
- }
39
-
40
- bootstrapModules.forEach(visit);
41
- const injector = new Injector(modules);
42
- components.forEach(function (component) {
43
- try {
44
- injector[typeof component === 'string' ? 'get' : 'invoke'](component);
45
- } catch (err) {
46
- console.error('Failed to instantiate component');
47
- console.error(err.stack);
48
- throw err;
49
- }
50
- });
51
- return injector;
52
- }
53
-
54
- /**
55
- * @param {string?} prefix
56
- *
57
- * @returns Element
58
- */
59
- function createFormContainer(prefix = 'fjs') {
60
- const container = document.createElement('div');
61
- container.classList.add(`${prefix}-container`);
62
- return container;
63
- }
64
-
65
- function findErrors(errors, path) {
66
- return errors[pathStringify(path)];
67
- }
68
- function isRequired(field) {
69
- return field.required;
70
- }
71
- function pathParse(path) {
72
- if (!path) {
73
- return [];
74
- }
75
-
76
- return path.split('.').map(key => {
77
- return isNaN(parseInt(key)) ? key : parseInt(key);
78
- });
79
- }
80
- function pathsEqual(a, b) {
81
- return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
82
- }
83
- function pathStringify(path) {
84
- if (!path) {
85
- return '';
86
- }
87
-
88
- return path.join('.');
89
- }
90
- const indices = {};
91
- function generateIndexForType(type) {
92
- if (type in indices) {
93
- indices[type]++;
94
- } else {
95
- indices[type] = 1;
96
- }
97
-
98
- return indices[type];
99
- }
100
- function generateIdForType(type) {
101
- return `${type}${generateIndexForType(type)}`;
102
- }
103
- /**
104
- * @template T
105
- * @param {T} data
106
- * @param {(this: any, key: string, value: any) => any} [replacer]
107
- * @return {T}
108
- */
109
-
110
- function clone(data, replacer) {
111
- return JSON.parse(JSON.stringify(data, replacer));
112
- }
113
-
114
11
  var FN_REF = '__fn';
115
12
  var DEFAULT_PRIORITY = 1000;
116
13
  var slice = Array.prototype.slice;
@@ -600,7 +497,7 @@ class Validator {
600
497
  errors = [...errors, `Field must match pattern ${validate.pattern}.`];
601
498
  }
602
499
 
603
- if (validate.required && (typeof value === 'undefined' || value === '')) {
500
+ if (validate.required && (isNil(value) || value === '')) {
604
501
  errors = [...errors, 'Field is required.'];
605
502
  }
606
503
 
@@ -624,6 +521,7 @@ class Validator {
624
521
  }
625
522
 
626
523
  }
524
+ Validator.$inject = [];
627
525
 
628
526
  class FormFieldRegistry {
629
527
  constructor(eventBus) {
@@ -689,6 +587,109 @@ class FormFieldRegistry {
689
587
  }
690
588
  FormFieldRegistry.$inject = ['eventBus'];
691
589
 
590
+ function createInjector(bootstrapModules) {
591
+ const modules = [],
592
+ components = [];
593
+
594
+ function hasModule(module) {
595
+ return modules.includes(module);
596
+ }
597
+
598
+ function addModule(module) {
599
+ modules.push(module);
600
+ }
601
+
602
+ function visit(module) {
603
+ if (hasModule(module)) {
604
+ return;
605
+ }
606
+
607
+ (module.__depends__ || []).forEach(visit);
608
+
609
+ if (hasModule(module)) {
610
+ return;
611
+ }
612
+
613
+ addModule(module);
614
+ (module.__init__ || []).forEach(function (component) {
615
+ components.push(component);
616
+ });
617
+ }
618
+
619
+ bootstrapModules.forEach(visit);
620
+ const injector = new Injector(modules);
621
+ components.forEach(function (component) {
622
+ try {
623
+ injector[typeof component === 'string' ? 'get' : 'invoke'](component);
624
+ } catch (err) {
625
+ console.error('Failed to instantiate component');
626
+ console.error(err.stack);
627
+ throw err;
628
+ }
629
+ });
630
+ return injector;
631
+ }
632
+
633
+ /**
634
+ * @param {string?} prefix
635
+ *
636
+ * @returns Element
637
+ */
638
+ function createFormContainer(prefix = 'fjs') {
639
+ const container = document.createElement('div');
640
+ container.classList.add(`${prefix}-container`);
641
+ return container;
642
+ }
643
+
644
+ function findErrors(errors, path) {
645
+ return errors[pathStringify(path)];
646
+ }
647
+ function isRequired(field) {
648
+ return field.required;
649
+ }
650
+ function pathParse(path) {
651
+ if (!path) {
652
+ return [];
653
+ }
654
+
655
+ return path.split('.').map(key => {
656
+ return isNaN(parseInt(key)) ? key : parseInt(key);
657
+ });
658
+ }
659
+ function pathsEqual(a, b) {
660
+ return a && b && a.length === b.length && a.every((value, index) => value === b[index]);
661
+ }
662
+ function pathStringify(path) {
663
+ if (!path) {
664
+ return '';
665
+ }
666
+
667
+ return path.join('.');
668
+ }
669
+ const indices = {};
670
+ function generateIndexForType(type) {
671
+ if (type in indices) {
672
+ indices[type]++;
673
+ } else {
674
+ indices[type] = 1;
675
+ }
676
+
677
+ return indices[type];
678
+ }
679
+ function generateIdForType(type) {
680
+ return `${type}${generateIndexForType(type)}`;
681
+ }
682
+ /**
683
+ * @template T
684
+ * @param {T} data
685
+ * @param {(this: any, key: string, value: any) => any} [replacer]
686
+ * @return {T}
687
+ */
688
+
689
+ function clone(data, replacer) {
690
+ return JSON.parse(JSON.stringify(data, replacer));
691
+ }
692
+
692
693
  class Importer {
693
694
  /**
694
695
  * @constructor
@@ -716,8 +717,8 @@ class Importer {
716
717
  const warnings = [];
717
718
 
718
719
  try {
719
- const importedData = clone(data);
720
- const importedSchema = this.importFormField(clone(schema), importedData);
720
+ const importedSchema = this.importFormField(clone(schema)),
721
+ importedData = this.importData(clone(data));
721
722
  return {
722
723
  warnings,
723
724
  schema: importedSchema,
@@ -730,14 +731,13 @@ class Importer {
730
731
  }
731
732
  /**
732
733
  * @param {any} formField
733
- * @param {Object} [data]
734
734
  * @param {string} [parentId]
735
735
  *
736
- * @return {any} field
736
+ * @return {any} importedField
737
737
  */
738
738
 
739
739
 
740
- importFormField(formField, data = {}, parentId) {
740
+ importFormField(formField, parentId) {
741
741
  const {
742
742
  components,
743
743
  key,
@@ -760,10 +760,13 @@ class Importer {
760
760
  throw new Error(`form field with key <${key}> already exists`);
761
761
  }
762
762
 
763
- this._formFieldRegistry._keys.claim(key, formField); // set form field path
763
+ this._formFieldRegistry._keys.claim(key, formField); // TODO: buttons should not have key
764
764
 
765
765
 
766
- formField._path = [key];
766
+ if (type !== 'button') {
767
+ // set form field path
768
+ formField._path = [key];
769
+ }
767
770
  }
768
771
 
769
772
  if (id) {
@@ -781,17 +784,44 @@ class Importer {
781
784
  this._formFieldRegistry.add(formField);
782
785
 
783
786
  if (components) {
784
- this.importFormFields(components, data, id);
787
+ this.importFormFields(components, id);
785
788
  }
786
789
 
787
790
  return formField;
788
791
  }
789
792
 
790
- importFormFields(components, data = {}, parentId) {
793
+ importFormFields(components, parentId) {
791
794
  components.forEach(component => {
792
- this.importFormField(component, data, parentId);
795
+ this.importFormField(component, parentId);
793
796
  });
794
797
  }
798
+ /**
799
+ * @param {Object} data
800
+ *
801
+ * @return {Object} importedData
802
+ */
803
+
804
+
805
+ importData(data) {
806
+ return this._formFieldRegistry.getAll().reduce((importedData, formField) => {
807
+ const {
808
+ defaultValue,
809
+ _path,
810
+ type
811
+ } = formField;
812
+
813
+ if (!_path) {
814
+ return importedData;
815
+ } // (1) try to get value from data
816
+ // (2) try to get default value from form field
817
+ // (3) get empty value from form field
818
+
819
+
820
+ return { ...importedData,
821
+ [_path[0]]: get(data, _path, isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
822
+ };
823
+ }, {});
824
+ }
795
825
 
796
826
  }
797
827
  Importer.$inject = ['formFieldRegistry', 'formFields'];
@@ -1115,6 +1145,7 @@ Checkbox.create = function (options = {}) {
1115
1145
  Checkbox.type = type$5;
1116
1146
  Checkbox.label = 'Checkbox';
1117
1147
  Checkbox.keyed = true;
1148
+ Checkbox.emptyValue = false;
1118
1149
 
1119
1150
  function useService (type, strict) {
1120
1151
  const {
@@ -1355,7 +1386,7 @@ function Number(props) {
1355
1386
  const parsedValue = parseInt(target.value, 10);
1356
1387
  props.onChange({
1357
1388
  field,
1358
- value: isNaN(parsedValue) ? undefined : parsedValue
1389
+ value: isNaN(parsedValue) ? null : parsedValue
1359
1390
  });
1360
1391
  };
1361
1392
 
@@ -1391,6 +1422,7 @@ Number.create = function (options = {}) {
1391
1422
  Number.type = type$4;
1392
1423
  Number.keyed = true;
1393
1424
  Number.label = 'Number';
1425
+ Number.emptyValue = null;
1394
1426
 
1395
1427
  const type$3 = 'radio';
1396
1428
  function Radio(props) {
@@ -1439,7 +1471,7 @@ function Radio(props) {
1439
1471
  type: "radio",
1440
1472
  onClick: () => onChange(v.value)
1441
1473
  })
1442
- }, v.value);
1474
+ }, `${id}-${index}`);
1443
1475
  }), jsx(Description, {
1444
1476
  description: description
1445
1477
  }), jsx(Errors, {
@@ -1461,6 +1493,7 @@ Radio.create = function (options = {}) {
1461
1493
  Radio.type = type$3;
1462
1494
  Radio.label = 'Radio';
1463
1495
  Radio.keyed = true;
1496
+ Radio.emptyValue = null;
1464
1497
 
1465
1498
  const type$2 = 'select';
1466
1499
  function Select(props) {
@@ -1486,7 +1519,7 @@ function Select(props) {
1486
1519
  }) => {
1487
1520
  props.onChange({
1488
1521
  field,
1489
- value: target.value === '' ? undefined : target.value
1522
+ value: target.value === '' ? null : target.value
1490
1523
  });
1491
1524
  };
1492
1525
 
@@ -1507,11 +1540,11 @@ function Select(props) {
1507
1540
  value: value || '',
1508
1541
  children: [jsx("option", {
1509
1542
  value: ""
1510
- }), values.map(v => {
1543
+ }), values.map((v, index) => {
1511
1544
  return jsx("option", {
1512
1545
  value: v.value,
1513
1546
  children: v.label
1514
- }, v.value);
1547
+ }, `${id}-${index}`);
1515
1548
  })]
1516
1549
  }), jsx(Description, {
1517
1550
  description: description
@@ -1534,6 +1567,7 @@ Select.create = function (options = {}) {
1534
1567
  Select.type = type$2;
1535
1568
  Select.label = 'Select';
1536
1569
  Select.keyed = true;
1570
+ Select.emptyValue = null;
1537
1571
 
1538
1572
  const type$1 = 'text';
1539
1573
  function Text(props) {
@@ -1621,6 +1655,7 @@ Textfield.create = function (options = {}) {
1621
1655
  Textfield.type = type;
1622
1656
  Textfield.label = 'Text Field';
1623
1657
  Textfield.keyed = true;
1658
+ Textfield.emptyValue = '';
1624
1659
 
1625
1660
  const formFields = [Button, Checkbox, Default, Number, Radio, Select, Text, Textfield];
1626
1661
 
@@ -1731,6 +1766,10 @@ var core = {
1731
1766
  * properties: FormProperties,
1732
1767
  * schema: Schema
1733
1768
  * } } State
1769
+ *
1770
+ * @typedef { (type:FormEvent, priority:number, handler:Function) => void } OnEventWithPriority
1771
+ * @typedef { (type:FormEvent, handler:Function) => void } OnEventWithOutPriority
1772
+ * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
1734
1773
  */
1735
1774
 
1736
1775
  const ids = new Ids([32, 36, 1]);
@@ -1744,10 +1783,16 @@ class Form {
1744
1783
  * @param {FormOptions} options
1745
1784
  */
1746
1785
  constructor(options = {}) {
1786
+ /**
1787
+ * @public
1788
+ * @type {OnEventType}
1789
+ */
1790
+ this.on = this._onEvent;
1747
1791
  /**
1748
1792
  * @public
1749
1793
  * @type {String}
1750
1794
  */
1795
+
1751
1796
  this._id = ids.next();
1752
1797
  /**
1753
1798
  * @private
@@ -1862,21 +1907,22 @@ class Form {
1862
1907
  throw new Error('form is read-only');
1863
1908
  }
1864
1909
 
1865
- const formFieldRegistry = this.get('formFieldRegistry'); // do not submit disabled form fields
1866
-
1910
+ const formFieldRegistry = this.get('formFieldRegistry');
1867
1911
  const data = formFieldRegistry.getAll().reduce((data, field) => {
1868
1912
  const {
1869
1913
  disabled,
1870
1914
  _path
1871
- } = field;
1915
+ } = field; // do not submit disabled form fields
1872
1916
 
1873
- if (disabled) {
1874
- // strip disabled field value
1875
- set(data, _path, undefined);
1917
+ if (disabled || !_path) {
1918
+ return data;
1876
1919
  }
1877
1920
 
1878
- return data;
1879
- }, clone(this._getState().data));
1921
+ const value = get(this._getState().data, _path);
1922
+ return { ...data,
1923
+ [_path[0]]: value
1924
+ };
1925
+ }, {});
1880
1926
  const errors = this.validate();
1881
1927
 
1882
1928
  this._emit('submit', {
@@ -1993,16 +2039,6 @@ class Form {
1993
2039
  properties
1994
2040
  });
1995
2041
  }
1996
- /**
1997
- * @param {FormEvent} type
1998
- * @param {number} priority
1999
- * @param {Function} handler
2000
- */
2001
-
2002
-
2003
- on(type, priority, handler) {
2004
- this.get('eventBus').on(type, priority, handler);
2005
- }
2006
2042
  /**
2007
2043
  * @param {FormEvent} type
2008
2044
  * @param {Function} handler
@@ -2097,10 +2133,18 @@ class Form {
2097
2133
 
2098
2134
  this._emit('changed', this._getState());
2099
2135
  }
2136
+ /**
2137
+ * @internal
2138
+ */
2139
+
2140
+
2141
+ _onEvent(type, priority, handler) {
2142
+ this.get('eventBus').on(type, priority, handler);
2143
+ }
2100
2144
 
2101
2145
  }
2102
2146
 
2103
- const schemaVersion = 2;
2147
+ const schemaVersion = 4;
2104
2148
  /**
2105
2149
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
2106
2150
  */