@bpmn-io/form-js-viewer 0.7.2 → 0.8.0-alpha.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.cjs CHANGED
@@ -8,14 +8,17 @@ var snarkdown = require('@bpmn-io/snarkdown');
8
8
  var jsxRuntime = require('preact/jsx-runtime');
9
9
  var hooks = require('preact/hooks');
10
10
  var preact = require('preact');
11
+ var React = require('preact/compat');
12
+ var classNames = require('classnames');
11
13
  var Markup = require('preact-markup');
12
- var compat = require('preact/compat');
13
14
  var didi = require('didi');
14
15
 
15
16
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
16
17
 
17
18
  var Ids__default = /*#__PURE__*/_interopDefaultLegacy(Ids);
18
19
  var snarkdown__default = /*#__PURE__*/_interopDefaultLegacy(snarkdown);
20
+ var React__default = /*#__PURE__*/_interopDefaultLegacy(React);
21
+ var classNames__default = /*#__PURE__*/_interopDefaultLegacy(classNames);
19
22
  var Markup__default = /*#__PURE__*/_interopDefaultLegacy(Markup);
20
23
 
21
24
  var FN_REF = '__fn';
@@ -817,19 +820,26 @@ class Importer {
817
820
  const {
818
821
  defaultValue,
819
822
  _path,
820
- type
821
- } = formField;
822
-
823
- if (!_path) {
824
- return importedData;
825
- } // (1) try to get value from data
826
- // (2) try to get default value from form field
827
- // (3) get empty value from form field
828
-
823
+ type,
824
+ valuesKey
825
+ } = formField; // get values defined via valuesKey
826
+
827
+ if (valuesKey) {
828
+ importedData = { ...importedData,
829
+ [valuesKey]: minDash.get(data, [valuesKey])
830
+ };
831
+ } // try to get value from data
832
+ // if unavailable - try to get default value from form field
833
+ // if unavailable - get empty value from form field
834
+
835
+
836
+ if (_path) {
837
+ importedData = { ...importedData,
838
+ [_path[0]]: minDash.get(data, _path, minDash.isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
839
+ };
840
+ }
829
841
 
830
- return { ...importedData,
831
- [_path[0]]: minDash.get(data, _path, minDash.isUndefined(defaultValue) ? this._formFields.get(type).emptyValue : defaultValue)
832
- };
842
+ return importedData;
833
843
  }, {});
834
844
  }
835
845
 
@@ -990,7 +1000,7 @@ function safeMarkdown(markdown) {
990
1000
  return sanitizeHTML(html);
991
1001
  }
992
1002
 
993
- const type$6 = 'button';
1003
+ const type$8 = 'button';
994
1004
  function Button(props) {
995
1005
  const {
996
1006
  disabled,
@@ -1000,7 +1010,7 @@ function Button(props) {
1000
1010
  action = 'submit'
1001
1011
  } = field;
1002
1012
  return jsxRuntime.jsx("div", {
1003
- class: formFieldClasses(type$6),
1013
+ class: formFieldClasses(type$8),
1004
1014
  children: jsxRuntime.jsx("button", {
1005
1015
  class: "fjs-button",
1006
1016
  type: action,
@@ -1017,7 +1027,7 @@ Button.create = function (options = {}) {
1017
1027
  };
1018
1028
  };
1019
1029
 
1020
- Button.type = type$6;
1030
+ Button.type = type$8;
1021
1031
  Button.label = 'Button';
1022
1032
  Button.keyed = true;
1023
1033
 
@@ -1099,7 +1109,7 @@ function Label(props) {
1099
1109
  });
1100
1110
  }
1101
1111
 
1102
- const type$5 = 'checkbox';
1112
+ const type$7 = 'checkbox';
1103
1113
  function Checkbox(props) {
1104
1114
  const {
1105
1115
  disabled,
@@ -1126,7 +1136,7 @@ function Checkbox(props) {
1126
1136
  formId
1127
1137
  } = hooks.useContext(FormContext);
1128
1138
  return jsxRuntime.jsxs("div", {
1129
- class: formFieldClasses(type$5, errors),
1139
+ class: formFieldClasses(type$7, errors),
1130
1140
  children: [jsxRuntime.jsx(Label, {
1131
1141
  id: prefixId(id, formId),
1132
1142
  label: label,
@@ -1152,7 +1162,7 @@ Checkbox.create = function (options = {}) {
1152
1162
  };
1153
1163
  };
1154
1164
 
1155
- Checkbox.type = type$5;
1165
+ Checkbox.type = type$7;
1156
1166
  Checkbox.label = 'Checkbox';
1157
1167
  Checkbox.keyed = true;
1158
1168
  Checkbox.emptyValue = false;
@@ -1164,6 +1174,152 @@ function useService (type, strict) {
1164
1174
  return getService(type, strict);
1165
1175
  }
1166
1176
 
1177
+ /**
1178
+ * @enum { String }
1179
+ */
1180
+
1181
+ const LOAD_STATES = {
1182
+ LOADING: 'loading',
1183
+ LOADED: 'loaded',
1184
+ ERROR: 'error'
1185
+ };
1186
+ /**
1187
+ * @typedef {Object} ValuesGetter
1188
+ * @property {Object[]} values - The values data
1189
+ * @property {(LOAD_STATES)} state - The values data's loading state, to use for conditional rendering
1190
+ */
1191
+
1192
+ /**
1193
+ * A hook to load values for single and multiselect components.
1194
+ *
1195
+ * @param {Object} field - The form field to handle values for
1196
+ * @return {ValuesGetter} valuesGetter - A values getter object providing loading state and values
1197
+ */
1198
+
1199
+ function useValuesAsync (field) {
1200
+ const {
1201
+ valuesKey,
1202
+ values: staticValues
1203
+ } = field;
1204
+ const [valuesGetter, setValuesGetter] = hooks.useState({
1205
+ values: [],
1206
+ error: undefined,
1207
+ state: LOAD_STATES.LOADING
1208
+ });
1209
+
1210
+ const initialData = useService('form')._getState().initialData;
1211
+
1212
+ hooks.useEffect(() => {
1213
+ let values = [];
1214
+
1215
+ if (valuesKey !== undefined) {
1216
+ const keyedValues = (initialData || {})[valuesKey];
1217
+
1218
+ if (keyedValues && Array.isArray(keyedValues)) {
1219
+ values = keyedValues;
1220
+ }
1221
+ } else if (staticValues !== undefined) {
1222
+ values = Array.isArray(staticValues) ? staticValues : [];
1223
+ } else {
1224
+ setValuesGetter(getErrorState('No values source defined in the form definition'));
1225
+ return;
1226
+ }
1227
+
1228
+ setValuesGetter(buildLoadedState(values));
1229
+ }, [valuesKey, staticValues, initialData]);
1230
+ return valuesGetter;
1231
+ }
1232
+
1233
+ const getErrorState = error => ({
1234
+ values: [],
1235
+ error,
1236
+ state: LOAD_STATES.ERROR
1237
+ });
1238
+
1239
+ const buildLoadedState = values => ({
1240
+ values,
1241
+ error: undefined,
1242
+ state: LOAD_STATES.LOADED
1243
+ });
1244
+
1245
+ const type$6 = 'checklist';
1246
+ function Checklist(props) {
1247
+ const {
1248
+ disabled,
1249
+ errors = [],
1250
+ field,
1251
+ value = []
1252
+ } = props;
1253
+ const {
1254
+ description,
1255
+ id,
1256
+ label
1257
+ } = field;
1258
+
1259
+ const toggleCheckbox = v => {
1260
+ let newValue = [...value];
1261
+
1262
+ if (!newValue.includes(v)) {
1263
+ newValue.push(v);
1264
+ } else {
1265
+ newValue = newValue.filter(x => x != v);
1266
+ }
1267
+
1268
+ props.onChange({
1269
+ field,
1270
+ value: newValue
1271
+ });
1272
+ };
1273
+
1274
+ const {
1275
+ state: loadState,
1276
+ values: options
1277
+ } = useValuesAsync(field);
1278
+ const {
1279
+ formId
1280
+ } = hooks.useContext(FormContext);
1281
+ return jsxRuntime.jsxs("div", {
1282
+ class: formFieldClasses(type$6, errors),
1283
+ children: [jsxRuntime.jsx(Label, {
1284
+ label: label
1285
+ }), loadState == LOAD_STATES.LOADED && options.map((v, index) => {
1286
+ return jsxRuntime.jsx(Label, {
1287
+ id: prefixId(`${id}-${index}`, formId),
1288
+ label: v.label,
1289
+ required: false,
1290
+ children: jsxRuntime.jsx("input", {
1291
+ checked: value.includes(v.value),
1292
+ class: "fjs-input",
1293
+ disabled: disabled,
1294
+ id: prefixId(`${id}-${index}`, formId),
1295
+ type: "checkbox",
1296
+ onClick: () => toggleCheckbox(v.value)
1297
+ })
1298
+ }, `${id}-${index}`);
1299
+ }), jsxRuntime.jsx(Description, {
1300
+ description: description
1301
+ }), jsxRuntime.jsx(Errors, {
1302
+ errors: errors
1303
+ })]
1304
+ });
1305
+ }
1306
+
1307
+ Checklist.create = function (options = {}) {
1308
+ if (options.valuesKey) return options;
1309
+ return {
1310
+ values: [{
1311
+ label: 'Value',
1312
+ value: 'value'
1313
+ }],
1314
+ ...options
1315
+ };
1316
+ };
1317
+
1318
+ Checklist.type = type$6;
1319
+ Checklist.label = 'Checklist';
1320
+ Checklist.keyed = true;
1321
+ Checklist.emptyValue = [];
1322
+
1167
1323
  const noop$1 = () => false;
1168
1324
 
1169
1325
  function FormField(props) {
@@ -1327,7 +1483,7 @@ function PoweredBy(props) {
1327
1483
  }
1328
1484
 
1329
1485
  return jsxRuntime.jsxs(preact.Fragment, {
1330
- children: [compat.createPortal(jsxRuntime.jsx(Lightbox, {
1486
+ children: [React.createPortal(jsxRuntime.jsx(Lightbox, {
1331
1487
  open: open,
1332
1488
  onBackdropClick: toggleOpen(false)
1333
1489
  }), document.body), jsxRuntime.jsx(Link, {
@@ -1372,7 +1528,7 @@ function FormComponent(props) {
1372
1528
  });
1373
1529
  }
1374
1530
 
1375
- const type$4 = 'number';
1531
+ const type$5 = 'number';
1376
1532
  function Number(props) {
1377
1533
  const {
1378
1534
  disabled,
@@ -1404,7 +1560,7 @@ function Number(props) {
1404
1560
  formId
1405
1561
  } = hooks.useContext(FormContext);
1406
1562
  return jsxRuntime.jsxs("div", {
1407
- class: formFieldClasses(type$4, errors),
1563
+ class: formFieldClasses(type$5, errors),
1408
1564
  children: [jsxRuntime.jsx(Label, {
1409
1565
  id: prefixId(id, formId),
1410
1566
  label: label,
@@ -1429,12 +1585,12 @@ Number.create = function (options = {}) {
1429
1585
  };
1430
1586
  };
1431
1587
 
1432
- Number.type = type$4;
1588
+ Number.type = type$5;
1433
1589
  Number.keyed = true;
1434
1590
  Number.label = 'Number';
1435
1591
  Number.emptyValue = null;
1436
1592
 
1437
- const type$3 = 'radio';
1593
+ const type$4 = 'radio';
1438
1594
  function Radio(props) {
1439
1595
  const {
1440
1596
  disabled,
@@ -1446,8 +1602,7 @@ function Radio(props) {
1446
1602
  description,
1447
1603
  id,
1448
1604
  label,
1449
- validate = {},
1450
- values
1605
+ validate = {}
1451
1606
  } = field;
1452
1607
  const {
1453
1608
  required
@@ -1460,26 +1615,30 @@ function Radio(props) {
1460
1615
  });
1461
1616
  };
1462
1617
 
1618
+ const {
1619
+ state: loadState,
1620
+ values: options
1621
+ } = useValuesAsync(field);
1463
1622
  const {
1464
1623
  formId
1465
1624
  } = hooks.useContext(FormContext);
1466
1625
  return jsxRuntime.jsxs("div", {
1467
- class: formFieldClasses(type$3, errors),
1626
+ class: formFieldClasses(type$4, errors),
1468
1627
  children: [jsxRuntime.jsx(Label, {
1469
1628
  label: label,
1470
1629
  required: required
1471
- }), values.map((v, index) => {
1630
+ }), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
1472
1631
  return jsxRuntime.jsx(Label, {
1473
1632
  id: prefixId(`${id}-${index}`, formId),
1474
- label: v.label,
1633
+ label: option.label,
1475
1634
  required: false,
1476
1635
  children: jsxRuntime.jsx("input", {
1477
- checked: v.value === value,
1636
+ checked: option.value === value,
1478
1637
  class: "fjs-input",
1479
1638
  disabled: disabled,
1480
1639
  id: prefixId(`${id}-${index}`, formId),
1481
1640
  type: "radio",
1482
- onClick: () => onChange(v.value)
1641
+ onClick: () => onChange(option.value)
1483
1642
  })
1484
1643
  }, `${id}-${index}`);
1485
1644
  }), jsxRuntime.jsx(Description, {
@@ -1491,6 +1650,7 @@ function Radio(props) {
1491
1650
  }
1492
1651
 
1493
1652
  Radio.create = function (options = {}) {
1653
+ if (options.valuesKey) return options;
1494
1654
  return {
1495
1655
  values: [{
1496
1656
  label: 'Value',
@@ -1500,12 +1660,12 @@ Radio.create = function (options = {}) {
1500
1660
  };
1501
1661
  };
1502
1662
 
1503
- Radio.type = type$3;
1663
+ Radio.type = type$4;
1504
1664
  Radio.label = 'Radio';
1505
1665
  Radio.keyed = true;
1506
1666
  Radio.emptyValue = null;
1507
1667
 
1508
- const type$2 = 'select';
1668
+ const type$3 = 'select';
1509
1669
  function Select(props) {
1510
1670
  const {
1511
1671
  disabled,
@@ -1517,8 +1677,7 @@ function Select(props) {
1517
1677
  description,
1518
1678
  id,
1519
1679
  label,
1520
- validate = {},
1521
- values
1680
+ validate = {}
1522
1681
  } = field;
1523
1682
  const {
1524
1683
  required
@@ -1533,11 +1692,15 @@ function Select(props) {
1533
1692
  });
1534
1693
  };
1535
1694
 
1695
+ const {
1696
+ state: loadState,
1697
+ values: options
1698
+ } = useValuesAsync(field);
1536
1699
  const {
1537
1700
  formId
1538
1701
  } = hooks.useContext(FormContext);
1539
1702
  return jsxRuntime.jsxs("div", {
1540
- class: formFieldClasses(type$2, errors),
1703
+ class: formFieldClasses(type$3, errors),
1541
1704
  children: [jsxRuntime.jsx(Label, {
1542
1705
  id: prefixId(id, formId),
1543
1706
  label: label,
@@ -1550,10 +1713,10 @@ function Select(props) {
1550
1713
  value: value || '',
1551
1714
  children: [jsxRuntime.jsx("option", {
1552
1715
  value: ""
1553
- }), values.map((v, index) => {
1716
+ }), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
1554
1717
  return jsxRuntime.jsx("option", {
1555
- value: v.value,
1556
- children: v.label
1718
+ value: option.value,
1719
+ children: option.label
1557
1720
  }, `${id}-${index}`);
1558
1721
  })]
1559
1722
  }), jsxRuntime.jsx(Description, {
@@ -1565,6 +1728,7 @@ function Select(props) {
1565
1728
  }
1566
1729
 
1567
1730
  Select.create = function (options = {}) {
1731
+ if (options.valuesKey) return options;
1568
1732
  return {
1569
1733
  values: [{
1570
1734
  label: 'Value',
@@ -1574,11 +1738,313 @@ Select.create = function (options = {}) {
1574
1738
  };
1575
1739
  };
1576
1740
 
1577
- Select.type = type$2;
1741
+ Select.type = type$3;
1578
1742
  Select.label = 'Select';
1579
1743
  Select.keyed = true;
1580
1744
  Select.emptyValue = null;
1581
1745
 
1746
+ function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
1747
+ var CloseIcon = (({
1748
+ styles = {},
1749
+ ...props
1750
+ }) => /*#__PURE__*/React__default['default'].createElement("svg", _extends({
1751
+ width: "16",
1752
+ height: "16",
1753
+ fill: "none",
1754
+ xmlns: "http://www.w3.org/2000/svg"
1755
+ }, props), /*#__PURE__*/React__default['default'].createElement("path", {
1756
+ fillRule: "evenodd",
1757
+ clipRule: "evenodd",
1758
+ d: "M12 4.7l-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7z",
1759
+ fill: "#000"
1760
+ })));
1761
+
1762
+ function useKeyDownAction(targetKey, action, listenerElement = window) {
1763
+ function downHandler({
1764
+ key
1765
+ }) {
1766
+ if (key === targetKey) {
1767
+ action();
1768
+ }
1769
+ }
1770
+
1771
+ hooks.useEffect(() => {
1772
+ listenerElement.addEventListener('keydown', downHandler);
1773
+ return () => {
1774
+ listenerElement.removeEventListener('keydown', downHandler);
1775
+ };
1776
+ });
1777
+ }
1778
+
1779
+ const DEFAULT_LABEL_GETTER = value => value;
1780
+
1781
+ const NOOP = () => {};
1782
+
1783
+ function DropdownList(props) {
1784
+ const {
1785
+ keyEventsListener = window,
1786
+ values = [],
1787
+ getLabel = DEFAULT_LABEL_GETTER,
1788
+ onValueSelected = NOOP,
1789
+ height = 235,
1790
+ emptyListMessage = 'No results'
1791
+ } = props;
1792
+ const [mouseControl, setMouseControl] = hooks.useState(true);
1793
+ const [focusedValueIndex, setFocusedValueIndex] = hooks.useState(0);
1794
+ const dropdownContainer = hooks.useRef();
1795
+ const mouseScreenPos = hooks.useRef();
1796
+ const focusedItem = hooks.useMemo(() => values.length ? values[focusedValueIndex] : null, [focusedValueIndex, values]);
1797
+ const changeFocusedValueIndex = hooks.useCallback(delta => {
1798
+ setFocusedValueIndex(x => Math.min(Math.max(0, x + delta), values.length - 1));
1799
+ }, [values.length]);
1800
+ hooks.useEffect(() => {
1801
+ if (focusedValueIndex === 0) return;
1802
+
1803
+ if (!focusedValueIndex || !values.length) {
1804
+ setFocusedValueIndex(0);
1805
+ } else if (focusedValueIndex >= values.length) {
1806
+ setFocusedValueIndex(values.length - 1);
1807
+ }
1808
+ }, [focusedValueIndex, values.length]);
1809
+ useKeyDownAction('ArrowUp', () => {
1810
+ if (values.length) {
1811
+ changeFocusedValueIndex(-1);
1812
+ setMouseControl(false);
1813
+ }
1814
+ }, keyEventsListener);
1815
+ useKeyDownAction('ArrowDown', () => {
1816
+ if (values.length) {
1817
+ changeFocusedValueIndex(1);
1818
+ setMouseControl(false);
1819
+ }
1820
+ }, keyEventsListener);
1821
+ useKeyDownAction('Enter', () => {
1822
+ if (focusedItem) {
1823
+ onValueSelected(focusedItem);
1824
+ }
1825
+ }, keyEventsListener);
1826
+ hooks.useEffect(() => {
1827
+ const individualEntries = dropdownContainer.current.children;
1828
+
1829
+ if (individualEntries.length && !mouseControl) {
1830
+ individualEntries[focusedValueIndex].scrollIntoView({
1831
+ block: 'nearest',
1832
+ inline: 'nearest'
1833
+ });
1834
+ }
1835
+ }, [focusedValueIndex, mouseControl]);
1836
+
1837
+ const mouseMove = (e, i) => {
1838
+ const userMoved = !mouseScreenPos.current || mouseScreenPos.current.x !== e.screenX && mouseScreenPos.current.y !== e.screenY;
1839
+
1840
+ if (userMoved) {
1841
+ mouseScreenPos.current = {
1842
+ x: e.screenX,
1843
+ y: e.screenY
1844
+ };
1845
+
1846
+ if (!mouseControl) {
1847
+ setMouseControl(true);
1848
+ setFocusedValueIndex(i);
1849
+ }
1850
+ }
1851
+ };
1852
+
1853
+ return jsxRuntime.jsxs("div", {
1854
+ ref: dropdownContainer,
1855
+ tabIndex: -1,
1856
+ class: "fjs-dropdownlist",
1857
+ style: {
1858
+ maxHeight: height
1859
+ },
1860
+ children: [!!values.length && values.map((v, i) => {
1861
+ return jsxRuntime.jsx("div", {
1862
+ class: 'fjs-dropdownlist-item' + (focusedValueIndex === i ? ' focused' : ''),
1863
+ onMouseMove: e => mouseMove(e, i),
1864
+ onMouseEnter: mouseControl ? () => setFocusedValueIndex(i) : undefined,
1865
+ onMouseDown: e => {
1866
+ e.preventDefault();
1867
+ onValueSelected(v);
1868
+ },
1869
+ children: getLabel(v)
1870
+ });
1871
+ }), !values.length && jsxRuntime.jsx("div", {
1872
+ class: "fjs-dropdownlist-empty",
1873
+ children: emptyListMessage
1874
+ })]
1875
+ });
1876
+ }
1877
+
1878
+ const type$2 = 'taglist';
1879
+ function Taglist(props) {
1880
+ const {
1881
+ disabled,
1882
+ errors = [],
1883
+ field,
1884
+ value: values = []
1885
+ } = props;
1886
+ const {
1887
+ description,
1888
+ id,
1889
+ label
1890
+ } = field;
1891
+ const {
1892
+ formId
1893
+ } = hooks.useContext(FormContext);
1894
+ const [filter, setFilter] = hooks.useState('');
1895
+ const [selectedValues, setSelectedValues] = hooks.useState([]);
1896
+ const [filteredValues, setFilteredValues] = hooks.useState([]);
1897
+ const [isDropdownExpanded, setIsDropdownExpanded] = hooks.useState(false);
1898
+ const [hasValuesLeft, setHasValuesLeft] = hooks.useState(true);
1899
+ const [isEscapeClosed, setIsEscapeClose] = hooks.useState(false);
1900
+ const searchbarRef = hooks.useRef();
1901
+ const {
1902
+ state: loadState,
1903
+ values: options
1904
+ } = useValuesAsync(field); // Usage of stringify is necessary here because we want this effect to only trigger when there is a value change to the array
1905
+
1906
+ hooks.useEffect(() => {
1907
+ if (loadState === LOAD_STATES.LOADED) {
1908
+ const selectedValues = values.map(v => options.find(o => o.value === v)).filter(v => v !== undefined);
1909
+ setSelectedValues(selectedValues);
1910
+ } else {
1911
+ setSelectedValues([]);
1912
+ }
1913
+ }, [JSON.stringify(values), options, loadState]);
1914
+ hooks.useEffect(() => {
1915
+ if (loadState === LOAD_STATES.LOADED) {
1916
+ setFilteredValues(options.filter(o => o.label && o.label.toLowerCase().includes(filter.toLowerCase()) && !values.includes(o.value)));
1917
+ } else {
1918
+ setFilteredValues([]);
1919
+ }
1920
+ }, [filter, JSON.stringify(values), options]);
1921
+ hooks.useEffect(() => {
1922
+ setHasValuesLeft(selectedValues.length < options.length);
1923
+ }, [selectedValues.length, options.length]);
1924
+
1925
+ const onFilterChange = ({
1926
+ target
1927
+ }) => {
1928
+ setIsEscapeClose(false);
1929
+ setFilter(target.value);
1930
+ };
1931
+
1932
+ const selectValue = option => {
1933
+ setFilter('');
1934
+ props.onChange({
1935
+ value: [...values, option.value],
1936
+ field
1937
+ });
1938
+ };
1939
+
1940
+ const deselectValue = option => {
1941
+ props.onChange({
1942
+ value: values.filter(v => v != option.value),
1943
+ field
1944
+ });
1945
+ };
1946
+
1947
+ const onInputKeyDown = e => {
1948
+ switch (e.key) {
1949
+ case 'ArrowUp':
1950
+ case 'ArrowDown':
1951
+ // We do not want the cursor to seek in the search field when we press up and down
1952
+ e.preventDefault();
1953
+ break;
1954
+
1955
+ case 'Backspace':
1956
+ if (!filter && selectedValues.length) {
1957
+ deselectValue(selectedValues[selectedValues.length - 1]);
1958
+ }
1959
+
1960
+ break;
1961
+
1962
+ case 'Escape':
1963
+ setIsEscapeClose(true);
1964
+ break;
1965
+
1966
+ case 'Enter':
1967
+ if (isEscapeClosed) {
1968
+ setIsEscapeClose(false);
1969
+ }
1970
+
1971
+ break;
1972
+ }
1973
+ };
1974
+
1975
+ return jsxRuntime.jsxs("div", {
1976
+ class: formFieldClasses(type$2, errors),
1977
+ children: [jsxRuntime.jsx(Label, {
1978
+ label: label,
1979
+ id: prefixId(id, formId)
1980
+ }), jsxRuntime.jsxs("div", {
1981
+ class: classNames__default['default']('fjs-taglist', {
1982
+ 'disabled': disabled
1983
+ }),
1984
+ children: [!disabled && loadState === LOAD_STATES.LOADED && selectedValues.map(sv => {
1985
+ return jsxRuntime.jsxs("div", {
1986
+ class: "fjs-taglist-tag",
1987
+ onMouseDown: e => e.preventDefault(),
1988
+ children: [jsxRuntime.jsx("span", {
1989
+ class: "fjs-taglist-tag-label",
1990
+ children: sv.label
1991
+ }), jsxRuntime.jsx("span", {
1992
+ class: "fjs-taglist-tag-remove",
1993
+ onMouseDown: () => deselectValue(sv),
1994
+ children: jsxRuntime.jsx(CloseIcon, {})
1995
+ })]
1996
+ });
1997
+ }), jsxRuntime.jsx("input", {
1998
+ disabled: disabled,
1999
+ class: "fjs-taglist-input",
2000
+ ref: searchbarRef,
2001
+ id: prefixId(`${id}-search`, formId),
2002
+ onChange: onFilterChange,
2003
+ type: "text",
2004
+ value: filter,
2005
+ placeholder: 'Search',
2006
+ autoComplete: "off",
2007
+ onKeyDown: e => onInputKeyDown(e),
2008
+ onMouseDown: () => setIsEscapeClose(false),
2009
+ onFocus: () => setIsDropdownExpanded(true),
2010
+ onBlur: () => {
2011
+ setIsDropdownExpanded(false);
2012
+ setFilter('');
2013
+ }
2014
+ })]
2015
+ }), jsxRuntime.jsx("div", {
2016
+ class: "fjs-taglist-anchor",
2017
+ children: !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed && jsxRuntime.jsx(DropdownList, {
2018
+ values: filteredValues,
2019
+ getLabel: v => v.label,
2020
+ onValueSelected: v => selectValue(v),
2021
+ emptyListMessage: hasValuesLeft ? 'No results' : 'All values selected',
2022
+ listenerElement: searchbarRef.current
2023
+ })
2024
+ }), jsxRuntime.jsx(Description, {
2025
+ description: description
2026
+ }), jsxRuntime.jsx(Errors, {
2027
+ errors: errors
2028
+ })]
2029
+ });
2030
+ }
2031
+
2032
+ Taglist.create = function (options = {}) {
2033
+ if (options.valuesKey) return options;
2034
+ return {
2035
+ values: [{
2036
+ label: 'Value',
2037
+ value: 'value'
2038
+ }],
2039
+ ...options
2040
+ };
2041
+ };
2042
+
2043
+ Taglist.type = type$2;
2044
+ Taglist.label = 'Taglist';
2045
+ Taglist.keyed = true;
2046
+ Taglist.emptyValue = [];
2047
+
1582
2048
  const type$1 = 'text';
1583
2049
  function Text(props) {
1584
2050
  const {
@@ -1667,7 +2133,7 @@ Textfield.label = 'Text Field';
1667
2133
  Textfield.keyed = true;
1668
2134
  Textfield.emptyValue = '';
1669
2135
 
1670
- const formFields = [Button, Checkbox, Default, Number, Radio, Select, Text, Textfield];
2136
+ const formFields = [Button, Checkbox, Checklist, Default, Number, Radio, Select, Taglist, Text, Textfield];
1671
2137
 
1672
2138
  class FormFields {
1673
2139
  constructor() {
@@ -2154,7 +2620,7 @@ class Form {
2154
2620
 
2155
2621
  }
2156
2622
 
2157
- const schemaVersion = 4;
2623
+ const schemaVersion = 5;
2158
2624
  /**
2159
2625
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
2160
2626
  */
@@ -2181,6 +2647,7 @@ function createForm(options) {
2181
2647
 
2182
2648
  exports.Button = Button;
2183
2649
  exports.Checkbox = Checkbox;
2650
+ exports.Checklist = Checklist;
2184
2651
  exports.Default = Default;
2185
2652
  exports.Form = Form;
2186
2653
  exports.FormComponent = FormComponent;
@@ -2191,6 +2658,7 @@ exports.FormRenderContext = FormRenderContext;
2191
2658
  exports.Number = Number;
2192
2659
  exports.Radio = Radio;
2193
2660
  exports.Select = Select;
2661
+ exports.Taglist = Taglist;
2194
2662
  exports.Text = Text;
2195
2663
  exports.Textfield = Textfield;
2196
2664
  exports.clone = clone;