@bpmn-io/form-js-editor 0.5.0 → 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,4 +1,5 @@
1
- import { isArray, isFunction, isNumber, bind, assign, debounce, get, isUndefined, set, forEach, isObject, uniqueBy, isString } from 'min-dash';
1
+ import Ids from 'ids';
2
+ import { isArray, isFunction, isNumber, bind, assign, debounce, get, isUndefined, set, has, forEach, isObject, uniqueBy, isString } from 'min-dash';
2
3
  import { FormFieldRegistry as FormFieldRegistry$1, clone, Default, FormContext, FormRenderContext, FormComponent, FormFields, createFormContainer, createInjector, schemaVersion } from '@bpmn-io/form-js-viewer';
3
4
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
4
5
  import { createContext, render } from 'preact';
@@ -6,7 +7,7 @@ import { useContext, useRef, useEffect, useMemo, useState, useCallback } from 'p
6
7
  import React from 'preact/compat';
7
8
  import { jsxs, jsx, Fragment } from 'preact/jsx-runtime';
8
9
  import dragula from 'dragula';
9
- import { matches, event } from 'min-dom';
10
+ import { matches, closest, event } from 'min-dom';
10
11
  import { mutate } from 'array-move';
11
12
 
12
13
  var FN_REF = '__fn';
@@ -1006,7 +1007,7 @@ function CheckboxInput(props) {
1006
1007
  };
1007
1008
 
1008
1009
  return jsxs("div", {
1009
- class: "fjs-properties-panel-textfield",
1010
+ class: "fjs-properties-panel-checkbox",
1010
1011
  children: [jsx("label", {
1011
1012
  for: prefixId(id),
1012
1013
  class: "fjs-properties-panel-label",
@@ -1061,7 +1062,7 @@ function NumberInput(props) {
1061
1062
  }
1062
1063
  }, [_onInput]);
1063
1064
  return jsxs("div", {
1064
- class: "fjs-properties-panel-textfield",
1065
+ class: "fjs-properties-panel-number",
1065
1066
  children: [jsx("label", {
1066
1067
  for: prefixId(id),
1067
1068
  class: "fjs-properties-panel-label",
@@ -1094,7 +1095,7 @@ function Select(props) {
1094
1095
  };
1095
1096
 
1096
1097
  return jsxs("div", {
1097
- class: "fjs-properties-panel-textfield",
1098
+ class: "fjs-properties-panel-select",
1098
1099
  children: [jsx("label", {
1099
1100
  for: prefixId(id),
1100
1101
  class: "fjs-properties-panel-label",
@@ -1128,7 +1129,7 @@ function Textarea(props) {
1128
1129
  _onInput(value.length ? value : undefined);
1129
1130
  }, [_onInput]);
1130
1131
  return jsxs("div", {
1131
- class: "fjs-properties-panel-textfield",
1132
+ class: "fjs-properties-panel-textarea",
1132
1133
  children: [jsx("label", {
1133
1134
  for: prefixId(id),
1134
1135
  class: "fjs-properties-panel-label",
@@ -1155,7 +1156,7 @@ function TextInput(props) {
1155
1156
  const prevValue = usePrevious(value);
1156
1157
  const [cachedValue, setCachedValue] = useState(null);
1157
1158
  const [error, setError] = useState(null);
1158
- useEffect(() => setError(validate(value)), [value]);
1159
+ useEffect(() => setError(validate(value)), [validate, value]);
1159
1160
  const onInput = useDebounce(event => {
1160
1161
  const value = event.target.value;
1161
1162
  const error = validate(value);
@@ -1180,7 +1181,7 @@ function TextInput(props) {
1180
1181
  }
1181
1182
 
1182
1183
  return jsxs("div", {
1183
- class: "fjs-properties-panel-textfield",
1184
+ class: "fjs-properties-panel-text",
1184
1185
  children: [jsx("label", {
1185
1186
  for: prefixId(id),
1186
1187
  class: "fjs-properties-panel-label",
@@ -1262,6 +1263,41 @@ function NumberInputEntry(props) {
1262
1263
  });
1263
1264
  }
1264
1265
 
1266
+ function SelectEntry(props) {
1267
+ const {
1268
+ editField,
1269
+ field,
1270
+ id,
1271
+ description,
1272
+ label,
1273
+ options,
1274
+ path
1275
+ } = props;
1276
+
1277
+ const onChange = value => {
1278
+ if (editField && path) {
1279
+ editField(field, path, value);
1280
+ } else {
1281
+ props.onChange(value);
1282
+ }
1283
+ };
1284
+
1285
+ const value = path ? get(field, path, '') : props.value;
1286
+ return jsxs("div", {
1287
+ class: "fjs-properties-panel-entry",
1288
+ children: [jsx(Select, {
1289
+ id: id,
1290
+ label: label,
1291
+ onChange: onChange,
1292
+ options: options,
1293
+ value: value
1294
+ }), description && jsx("div", {
1295
+ class: "fjs-properties-panel-description",
1296
+ children: description
1297
+ })]
1298
+ });
1299
+ }
1300
+
1265
1301
  function TextareaEntry(props) {
1266
1302
  const {
1267
1303
  editField,
@@ -1472,12 +1508,6 @@ function ActionEntry(props) {
1472
1508
  editField,
1473
1509
  field
1474
1510
  } = props;
1475
-
1476
- const onChange = value => {
1477
- editField(field, 'action', value);
1478
- };
1479
-
1480
- const value = field.action;
1481
1511
  const options = [{
1482
1512
  label: 'Submit',
1483
1513
  value: 'submit'
@@ -1485,15 +1515,13 @@ function ActionEntry(props) {
1485
1515
  label: 'Reset',
1486
1516
  value: 'reset'
1487
1517
  }];
1488
- return jsx("div", {
1489
- class: "fjs-properties-panel-entry",
1490
- children: jsx(Select, {
1491
- id: "action",
1492
- label: "Action",
1493
- options: options,
1494
- onChange: onChange,
1495
- value: value
1496
- })
1518
+ return jsx(SelectEntry, {
1519
+ editField: editField,
1520
+ field: field,
1521
+ id: "action",
1522
+ label: "Action",
1523
+ options: options,
1524
+ path: ['action']
1497
1525
  });
1498
1526
  }
1499
1527
 
@@ -1547,6 +1575,94 @@ function DescriptionEntry(props) {
1547
1575
  });
1548
1576
  }
1549
1577
 
1578
+ function DefaultValueEntry(props) {
1579
+ const {
1580
+ editField,
1581
+ field
1582
+ } = props;
1583
+ const {
1584
+ defaultValue,
1585
+ type,
1586
+ values = []
1587
+ } = field;
1588
+
1589
+ if (type === 'checkbox') {
1590
+ const options = [{
1591
+ label: 'Checked',
1592
+ value: 'true'
1593
+ }, {
1594
+ label: 'Not checked',
1595
+ value: 'false'
1596
+ }];
1597
+
1598
+ const onChange = value => {
1599
+ editField(field, ['defaultValue'], parseStringToBoolean(value));
1600
+ };
1601
+
1602
+ return jsx(SelectEntry, {
1603
+ id: "defaultValue",
1604
+ label: "Default Value",
1605
+ onChange: onChange,
1606
+ options: options,
1607
+ value: parseBooleanToString(defaultValue)
1608
+ });
1609
+ }
1610
+
1611
+ if (type === 'number') {
1612
+ return jsx(NumberInputEntry, {
1613
+ editField: editField,
1614
+ field: field,
1615
+ id: "defaultValue",
1616
+ label: "Default Value",
1617
+ path: ['defaultValue']
1618
+ });
1619
+ }
1620
+
1621
+ if (type === 'radio' || type === 'select') {
1622
+ const options = [{
1623
+ label: '<none>'
1624
+ }, ...values];
1625
+
1626
+ const onChange = value => {
1627
+ editField(field, ['defaultValue'], value.length ? value : undefined);
1628
+ };
1629
+
1630
+ return jsx(SelectEntry, {
1631
+ id: "defaultValue",
1632
+ label: "Default Value",
1633
+ onChange: onChange,
1634
+ options: options,
1635
+ value: defaultValue
1636
+ });
1637
+ }
1638
+
1639
+ if (type === 'textfield') {
1640
+ return jsx(TextInputEntry, {
1641
+ editField: editField,
1642
+ field: field,
1643
+ id: "defaultValue",
1644
+ label: "Default Value",
1645
+ path: ['defaultValue']
1646
+ });
1647
+ }
1648
+ }
1649
+
1650
+ function parseStringToBoolean(value) {
1651
+ if (value === 'true') {
1652
+ return true;
1653
+ }
1654
+
1655
+ return false;
1656
+ }
1657
+
1658
+ function parseBooleanToString(value) {
1659
+ if (value === true) {
1660
+ return 'true';
1661
+ }
1662
+
1663
+ return 'false';
1664
+ }
1665
+
1550
1666
  function DisabledEntry(props) {
1551
1667
  const {
1552
1668
  editField,
@@ -1690,9 +1806,18 @@ function ValueEntry(props) {
1690
1806
  const {
1691
1807
  editField,
1692
1808
  field,
1693
- index
1809
+ index,
1810
+ validate
1694
1811
  } = props;
1695
1812
 
1813
+ const getLabel = () => {
1814
+ return get(field, ['values', index, 'label']);
1815
+ };
1816
+
1817
+ const getValue = () => {
1818
+ return get(field, ['values', index, 'value']);
1819
+ };
1820
+
1696
1821
  const onChange = key => {
1697
1822
  const values = get(field, ['values']);
1698
1823
  return value => {
@@ -1705,14 +1830,93 @@ function ValueEntry(props) {
1705
1830
  id: `value-label-${index}`,
1706
1831
  label: "Label",
1707
1832
  onChange: onChange('label'),
1708
- value: get(field, ['values', index, 'label'])
1833
+ value: getLabel()
1834
+ }), jsx(TextInputEntry, {
1835
+ id: `value-value-${index}`,
1836
+ label: "Value",
1837
+ onChange: onChange('value'),
1838
+ value: getValue(),
1839
+ validate: validate(getValue())
1840
+ })]
1841
+ });
1842
+ }
1843
+
1844
+ function CustomValueEntry(props) {
1845
+ const {
1846
+ editField,
1847
+ field,
1848
+ index,
1849
+ validate
1850
+ } = props;
1851
+
1852
+ const getKey = () => {
1853
+ return Object.keys(get(field, ['properties']))[index];
1854
+ };
1855
+
1856
+ const getValue = () => {
1857
+ return get(field, ['properties', getKey()]);
1858
+ };
1859
+
1860
+ const onChange = key => {
1861
+ const properties = get(field, ['properties']);
1862
+ return value => {
1863
+ if (key === 'value') {
1864
+ editField(field, 'properties', updateValue(properties, getKey(), value));
1865
+ } else if (key === 'key') {
1866
+ editField(field, 'properties', updateKey(properties, getKey(), value));
1867
+ }
1868
+ };
1869
+ };
1870
+
1871
+ return jsxs(Fragment, {
1872
+ children: [jsx(TextInputEntry, {
1873
+ id: `value-key-${index}`,
1874
+ label: "Key",
1875
+ onChange: onChange('key'),
1876
+ value: getKey(),
1877
+ validate: validate(getKey())
1709
1878
  }), jsx(TextInputEntry, {
1710
1879
  id: `value-value-${index}`,
1711
1880
  label: "Value",
1712
1881
  onChange: onChange('value'),
1713
- value: get(field, ['values', index, 'value'])
1882
+ value: getValue()
1714
1883
  })]
1715
1884
  });
1885
+ } // helpers //////////
1886
+
1887
+ /**
1888
+ * Returns copy of object with updated value.
1889
+ *
1890
+ * @param {Object} properties
1891
+ * @param {string} key
1892
+ * @param {string} value
1893
+ *
1894
+ * @returns {Object}
1895
+ */
1896
+
1897
+ function updateValue(properties, key, value) {
1898
+ return { ...properties,
1899
+ [key]: value
1900
+ };
1901
+ }
1902
+ /**
1903
+ * Returns copy of object with updated key.
1904
+ *
1905
+ * @param {Object} properties
1906
+ * @param {string} oldKey
1907
+ * @param {string} newKey
1908
+ *
1909
+ * @returns {Object}
1910
+ */
1911
+
1912
+
1913
+ function updateKey(properties, oldKey, newKey) {
1914
+ return Object.entries(properties).reduce((newProperties, entry) => {
1915
+ const [key, value] = entry;
1916
+ return { ...newProperties,
1917
+ [key === oldKey ? newKey : key]: value
1918
+ };
1919
+ }, {});
1716
1920
  }
1717
1921
 
1718
1922
  function GeneralGroup(field, editField) {
@@ -1749,6 +1953,13 @@ function GeneralGroup(field, editField) {
1749
1953
  }));
1750
1954
  }
1751
1955
 
1956
+ if (INPUTS.includes(type)) {
1957
+ entries.push(jsx(DefaultValueEntry, {
1958
+ editField: editField,
1959
+ field: field
1960
+ }));
1961
+ }
1962
+
1752
1963
  if (type === 'button') {
1753
1964
  entries.push(jsx(ActionEntry, {
1754
1965
  editField: editField,
@@ -1850,13 +2061,32 @@ function ValuesGroup(field, editField) {
1850
2061
  } = field;
1851
2062
 
1852
2063
  const addEntry = () => {
2064
+ const index = values.length + 1;
1853
2065
  const entry = {
1854
- label: 'Value',
1855
- value: 'value'
2066
+ label: `Value ${index}`,
2067
+ value: `value${index}`
1856
2068
  };
1857
2069
  editField(field, ['values'], arrayAdd$1(values, values.length, entry));
1858
2070
  };
1859
2071
 
2072
+ const validateFactory = key => {
2073
+ return value => {
2074
+ if (value === key) {
2075
+ return;
2076
+ }
2077
+
2078
+ if (isUndefined(value) || !value.length) {
2079
+ return 'Must not be empty.';
2080
+ }
2081
+
2082
+ const isValueAssigned = values.find(entry => entry.value === value);
2083
+
2084
+ if (isValueAssigned) {
2085
+ return 'Must be unique.';
2086
+ }
2087
+ };
2088
+ };
2089
+
1860
2090
  const hasEntries = values.length > 0;
1861
2091
  return jsx(Group, {
1862
2092
  label: "Values",
@@ -1877,11 +2107,90 @@ function ValuesGroup(field, editField) {
1877
2107
  children: jsx(ValueEntry, {
1878
2108
  editField: editField,
1879
2109
  field: field,
1880
- index: index
2110
+ index: index,
2111
+ validate: validateFactory
2112
+ })
2113
+ }, `${id}-${index}`);
2114
+ })
2115
+ });
2116
+ }
2117
+
2118
+ function CustomValuesGroup(field, editField) {
2119
+ const {
2120
+ id,
2121
+ properties = {}
2122
+ } = field;
2123
+
2124
+ const addEntry = () => {
2125
+ const index = Object.keys(properties).length + 1;
2126
+ const key = `key${index}`,
2127
+ value = 'value';
2128
+ editField(field, ['properties'], { ...properties,
2129
+ [key]: value
2130
+ });
2131
+ };
2132
+
2133
+ const validateFactory = key => {
2134
+ return value => {
2135
+ if (value === key) {
2136
+ return;
2137
+ }
2138
+
2139
+ if (isUndefined(value) || !value.length) {
2140
+ return 'Must not be empty.';
2141
+ }
2142
+
2143
+ if (has(properties, value)) {
2144
+ return 'Must be unique.';
2145
+ }
2146
+ };
2147
+ };
2148
+
2149
+ const hasEntries = Object.keys(properties).length > 0;
2150
+ return jsx(Group, {
2151
+ label: "Custom Properties",
2152
+ addEntry: addEntry,
2153
+ hasEntries: hasEntries,
2154
+ children: Object.keys(properties).map((key, index) => {
2155
+ const removeEntry = () => {
2156
+ editField(field, ['properties'], removeKey(properties, key));
2157
+ };
2158
+
2159
+ return jsx(CollapsibleEntry, {
2160
+ label: key,
2161
+ removeEntry: removeEntry,
2162
+ children: jsx(CustomValueEntry, {
2163
+ editField: editField,
2164
+ field: field,
2165
+ index: index,
2166
+ validate: validateFactory
1881
2167
  })
1882
- }, `${id}-${value.value}`);
2168
+ }, `${id}-${index}`);
1883
2169
  })
1884
2170
  });
2171
+ } // helpers //////////
2172
+
2173
+ /**
2174
+ * Returns copy of object without key.
2175
+ *
2176
+ * @param {Object} properties
2177
+ * @param {string} oldKey
2178
+ *
2179
+ * @returns {Object}
2180
+ */
2181
+
2182
+ function removeKey(properties, oldKey) {
2183
+ return Object.entries(properties).reduce((newProperties, entry) => {
2184
+ const [key, value] = entry;
2185
+
2186
+ if (key === oldKey) {
2187
+ return newProperties;
2188
+ }
2189
+
2190
+ return { ...newProperties,
2191
+ [key]: value
2192
+ };
2193
+ }, {});
1885
2194
  }
1886
2195
 
1887
2196
  const labelsByType = {
@@ -1910,6 +2219,10 @@ function getGroups(field, editField) {
1910
2219
  groups.push(ValidationGroup(field, editField));
1911
2220
  }
1912
2221
 
2222
+ if (type !== 'default') {
2223
+ groups.push(CustomValuesGroup(field, editField));
2224
+ }
2225
+
1913
2226
  return groups;
1914
2227
  }
1915
2228
 
@@ -2200,8 +2513,9 @@ function FormEditor$1(props) {
2200
2513
  }
2201
2514
 
2202
2515
  return injector.get(type, strict);
2203
- }
2516
+ },
2204
2517
 
2518
+ formId: formEditor._id
2205
2519
  };
2206
2520
  const onSubmit = useCallback(() => {}, []);
2207
2521
  const onReset = useCallback(() => {}, []);
@@ -2677,6 +2991,7 @@ function isShift(event) {
2677
2991
 
2678
2992
  var KEYDOWN_EVENT = 'keyboard.keydown',
2679
2993
  KEYUP_EVENT = 'keyboard.keyup';
2994
+ var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
2680
2995
  var DEFAULT_PRIORITY$1 = 1000;
2681
2996
  /**
2682
2997
  * A keyboard abstraction that may be activated and
@@ -2755,7 +3070,27 @@ Keyboard.prototype._keyHandler = function (event, type) {
2755
3070
  };
2756
3071
 
2757
3072
  Keyboard.prototype._isEventIgnored = function (event) {
2758
- return isInput(event.target) && !isCmd(event);
3073
+ return isInput(event.target) && this._isModifiedKeyIgnored(event);
3074
+ };
3075
+
3076
+ Keyboard.prototype._isModifiedKeyIgnored = function (event) {
3077
+ if (!isCmd(event)) {
3078
+ return true;
3079
+ }
3080
+
3081
+ var allowedModifiers = this._getAllowedModifiers(event.target);
3082
+
3083
+ return !allowedModifiers.includes(event.key);
3084
+ };
3085
+
3086
+ Keyboard.prototype._getAllowedModifiers = function (element) {
3087
+ var modifierContainer = closest(element, '[' + HANDLE_MODIFIER_ATTRIBUTE + ']', true);
3088
+
3089
+ if (!modifierContainer || this._node && !this._node.contains(modifierContainer)) {
3090
+ return [];
3091
+ }
3092
+
3093
+ return modifierContainer.getAttribute(HANDLE_MODIFIER_ATTRIBUTE).split(',');
2759
3094
  };
2760
3095
 
2761
3096
  Keyboard.prototype.bind = function (node) {
@@ -4308,6 +4643,7 @@ var SelectionModule = {
4308
4643
  selectionBehavior: ['type', SelectionBehavior]
4309
4644
  };
4310
4645
 
4646
+ const ids = new Ids([32, 36, 1]);
4311
4647
  /**
4312
4648
  * @typedef { import('./types').Injector } Injector
4313
4649
  * @typedef { import('./types').Module } Module
@@ -4332,11 +4668,20 @@ class FormEditor {
4332
4668
  * @param {FormEditorOptions} options
4333
4669
  */
4334
4670
  constructor(options = {}) {
4671
+ /**
4672
+ * @public
4673
+ * @type {String}
4674
+ */
4675
+ this._id = ids.next();
4335
4676
  /**
4336
4677
  * @private
4337
4678
  * @type {Element}
4338
4679
  */
4680
+
4339
4681
  this._container = createFormContainer();
4682
+
4683
+ this._container.setAttribute('input-handle-modified-keys', 'z,y');
4684
+
4340
4685
  const {
4341
4686
  container,
4342
4687
  exporter,
@@ -4595,10 +4940,9 @@ function exportSchema(schema, exporter, schemaVersion) {
4595
4940
 
4596
4941
  return value;
4597
4942
  });
4598
- return {
4599
- schemaVersion,
4943
+ return { ...cleanedSchema,
4600
4944
  ...exportDetails,
4601
- ...cleanedSchema
4945
+ schemaVersion
4602
4946
  };
4603
4947
  }
4604
4948