@bpmn-io/form-js-viewer 0.11.0 → 0.12.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.
Files changed (28) hide show
  1. package/dist/assets/form-js.css +146 -50
  2. package/dist/index.cjs +757 -484
  3. package/dist/index.cjs.map +1 -1
  4. package/dist/index.es.js +678 -396
  5. package/dist/index.es.js.map +1 -1
  6. package/dist/types/Form.d.ts +2 -2
  7. package/dist/types/index.d.ts +1 -1
  8. package/dist/types/render/components/form-fields/Button.d.ts +1 -0
  9. package/dist/types/render/components/form-fields/Checkbox.d.ts +1 -0
  10. package/dist/types/render/components/form-fields/Checklist.d.ts +7 -1
  11. package/dist/types/render/components/form-fields/Datetime.d.ts +2 -0
  12. package/dist/types/render/components/form-fields/Default.d.ts +2 -0
  13. package/dist/types/render/components/form-fields/Image.d.ts +2 -0
  14. package/dist/types/render/components/form-fields/Number.d.ts +1 -0
  15. package/dist/types/render/components/form-fields/Radio.d.ts +7 -1
  16. package/dist/types/render/components/form-fields/Select.d.ts +7 -1
  17. package/dist/types/render/components/form-fields/Taglist.d.ts +7 -1
  18. package/dist/types/render/components/form-fields/Text.d.ts +2 -0
  19. package/dist/types/render/components/form-fields/Textarea.d.ts +1 -0
  20. package/dist/types/render/components/form-fields/Textfield.d.ts +1 -0
  21. package/dist/types/render/components/form-fields/parts/SearchableSelect.d.ts +1 -0
  22. package/dist/types/render/components/form-fields/parts/SimpleSelect.d.ts +1 -0
  23. package/dist/types/render/components/icons/index.d.ts +1 -16
  24. package/dist/types/render/components/index.d.ts +1 -1
  25. package/dist/types/{src/types.d.ts → types.d.ts} +0 -0
  26. package/dist/types/util/constants/ValuesSourceConstants.d.ts +4 -1
  27. package/dist/types/util/index.d.ts +1 -0
  28. package/package.json +5 -5
package/dist/index.es.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import Ids from 'ids';
2
- import { isString, isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, set, isObject } from 'min-dash';
2
+ import { isString, isArray, isFunction, isNumber, bind, assign, isNil, get, isUndefined, set, findIndex, isObject } from 'min-dash';
3
3
  import { unaryTest, evaluate, parseUnaryTests, parseExpressions } from 'feelin';
4
4
  import Big from 'big.js';
5
5
  import snarkdown from '@bpmn-io/snarkdown';
6
6
  import classNames from 'classnames';
7
- import { jsx, jsxs } from 'preact/jsx-runtime';
7
+ import { jsx, jsxs, Fragment as Fragment$1 } from 'preact/jsx-runtime';
8
8
  import { useContext, useState, useEffect, useRef, useCallback, useMemo } from 'preact/hooks';
9
9
  import { createContext, createElement, Fragment, render } from 'preact';
10
10
  import React, { createPortal } from 'preact/compat';
@@ -740,7 +740,7 @@ function getExpressionVariableNames(expression) {
740
740
  } while (cursor.next());
741
741
  return Array.from(variables);
742
742
  }
743
- function isExpression$2(value) {
743
+ function isExpression$1(value) {
744
744
  return isString(value) && value.startsWith('=');
745
745
  }
746
746
 
@@ -791,7 +791,10 @@ const VALUES_SOURCES_PATHS = {
791
791
  [VALUES_SOURCES.INPUT]: ['valuesKey']
792
792
  };
793
793
  const VALUES_SOURCES_DEFAULTS = {
794
- [VALUES_SOURCES.STATIC]: [],
794
+ [VALUES_SOURCES.STATIC]: [{
795
+ label: 'Value',
796
+ value: 'value'
797
+ }],
795
798
  [VALUES_SOURCES.INPUT]: ''
796
799
  };
797
800
 
@@ -917,12 +920,6 @@ function getSchemaVariables(schema) {
917
920
  return Array.from(new Set(variables));
918
921
  }
919
922
 
920
- // helper ///////////////
921
-
922
- function isExpression$1(value) {
923
- return isString(value) && value.startsWith('=');
924
- }
925
-
926
923
  class Importer {
927
924
  /**
928
925
  * @constructor
@@ -1235,15 +1232,14 @@ function Button(props) {
1235
1232
  })
1236
1233
  });
1237
1234
  }
1238
- Button.create = function (options = {}) {
1239
- return {
1240
- action: 'submit',
1241
- ...options
1242
- };
1243
- };
1235
+ Button.create = (options = {}) => ({
1236
+ action: 'submit',
1237
+ ...options
1238
+ });
1244
1239
  Button.type = type$b;
1245
1240
  Button.label = 'Button';
1246
1241
  Button.keyed = true;
1242
+ Button.group = 'action';
1247
1243
 
1248
1244
  const FormRenderContext = createContext({
1249
1245
  Empty: props => {
@@ -1256,6 +1252,7 @@ const FormRenderContext = createContext({
1256
1252
  return props.children;
1257
1253
  }
1258
1254
  });
1255
+ var FormRenderContext$1 = FormRenderContext;
1259
1256
 
1260
1257
  /**
1261
1258
  * @param {string} type
@@ -1268,6 +1265,7 @@ const FormContext = createContext({
1268
1265
  getService,
1269
1266
  formId: null
1270
1267
  });
1268
+ var FormContext$1 = FormContext;
1271
1269
 
1272
1270
  function Description(props) {
1273
1271
  const {
@@ -1343,7 +1341,7 @@ function Checkbox(props) {
1343
1341
  };
1344
1342
  const {
1345
1343
  formId
1346
- } = useContext(FormContext);
1344
+ } = useContext(FormContext$1);
1347
1345
  return jsxs("div", {
1348
1346
  class: classNames(formFieldClasses(type$a, {
1349
1347
  errors,
@@ -1370,11 +1368,9 @@ function Checkbox(props) {
1370
1368
  })]
1371
1369
  });
1372
1370
  }
1373
- Checkbox.create = function (options = {}) {
1374
- return {
1375
- ...options
1376
- };
1377
- };
1371
+ Checkbox.create = (options = {}) => ({
1372
+ ...options
1373
+ });
1378
1374
  Checkbox.type = type$a;
1379
1375
  Checkbox.label = 'Checkbox';
1380
1376
  Checkbox.keyed = true;
@@ -1382,11 +1378,12 @@ Checkbox.emptyValue = false;
1382
1378
  Checkbox.sanitizeValue = ({
1383
1379
  value
1384
1380
  }) => value === true;
1381
+ Checkbox.group = 'selection';
1385
1382
 
1386
1383
  function useService (type, strict) {
1387
1384
  const {
1388
1385
  getService
1389
- } = useContext(FormContext);
1386
+ } = useContext(FormContext$1);
1390
1387
  return getService(type, strict);
1391
1388
  }
1392
1389
 
@@ -1483,8 +1480,8 @@ function parseInputTime(stringTime) {
1483
1480
  if (is12h) {
1484
1481
  const isPM = workingString.includes('pm');
1485
1482
  const digits = workingString.match(/\d+/g);
1486
- const displayHour = parseInt(digits?.[0]);
1487
- const minute = parseInt(digits?.[1]) || 0;
1483
+ const displayHour = parseInt(digits && digits[0]);
1484
+ const minute = parseInt(digits && digits[1]) || 0;
1488
1485
  const isValidDisplayHour = isNumber(displayHour) && displayHour >= 1 && displayHour <= 12;
1489
1486
  const isValidMinute = minute >= 0 && minute <= 59;
1490
1487
  if (!isValidDisplayHour || !isValidMinute) return null;
@@ -1492,8 +1489,8 @@ function parseInputTime(stringTime) {
1492
1489
  return hour * 60 + minute;
1493
1490
  } else {
1494
1491
  const digits = workingString.match(/\d+/g);
1495
- const hour = parseInt(digits?.[0]);
1496
- const minute = parseInt(digits?.[1]);
1492
+ const hour = parseInt(digits && digits[0]);
1493
+ const minute = parseInt(digits && digits[1]);
1497
1494
  const isValidHour = isNumber(hour) && hour >= 0 && hour <= 23;
1498
1495
  const isValidMinute = isNumber(minute) && minute >= 0 && minute <= 59;
1499
1496
  if (!isValidHour || !isValidMinute) return null;
@@ -1696,7 +1693,7 @@ function Checklist(props) {
1696
1693
  } = useValuesAsync(field);
1697
1694
  const {
1698
1695
  formId
1699
- } = useContext(FormContext);
1696
+ } = useContext(FormContext$1);
1700
1697
  return jsxs("div", {
1701
1698
  class: classNames(formFieldClasses(type$9, {
1702
1699
  errors,
@@ -1728,13 +1725,18 @@ function Checklist(props) {
1728
1725
  })]
1729
1726
  });
1730
1727
  }
1731
- Checklist.create = function (options = {}) {
1732
- if (options.valuesKey) return options;
1733
- return {
1734
- values: [{
1728
+ Checklist.create = (options = {}) => {
1729
+ const defaults = {};
1730
+
1731
+ // provide default values if valuesKey isn't set
1732
+ if (!options.valuesKey) {
1733
+ defaults.values = [{
1735
1734
  label: 'Value',
1736
1735
  value: 'value'
1737
- }],
1736
+ }];
1737
+ }
1738
+ return {
1739
+ ...defaults,
1738
1740
  ...options
1739
1741
  };
1740
1742
  };
@@ -1743,6 +1745,7 @@ Checklist.label = 'Checklist';
1743
1745
  Checklist.keyed = true;
1744
1746
  Checklist.emptyValue = [];
1745
1747
  Checklist.sanitizeValue = sanitizeMultiSelectValue;
1748
+ Checklist.group = 'selection';
1746
1749
 
1747
1750
  /**
1748
1751
  * Check if condition is met with given variables.
@@ -1786,7 +1789,7 @@ function FormField(props) {
1786
1789
  const {
1787
1790
  Element,
1788
1791
  Empty
1789
- } = useContext(FormRenderContext);
1792
+ } = useContext(FormRenderContext$1);
1790
1793
  const FormFieldComponent = formFields.get(field.type);
1791
1794
  if (!FormFieldComponent) {
1792
1795
  throw new Error(`cannot render field <${field.type}>`);
@@ -1818,7 +1821,7 @@ function Default(props) {
1818
1821
  const {
1819
1822
  Children,
1820
1823
  Empty
1821
- } = useContext(FormRenderContext);
1824
+ } = useContext(FormRenderContext$1);
1822
1825
  const {
1823
1826
  field
1824
1827
  } = props;
@@ -1837,20 +1840,20 @@ function Default(props) {
1837
1840
  }), components.length ? null : jsx(Empty, {})]
1838
1841
  });
1839
1842
  }
1840
- Default.create = function (options = {}) {
1841
- return {
1842
- components: [],
1843
- ...options
1844
- };
1845
- };
1843
+ Default.create = (options = {}) => ({
1844
+ components: [],
1845
+ ...options
1846
+ });
1846
1847
  Default.type = 'default';
1847
1848
  Default.keyed = false;
1849
+ Default.label = null;
1850
+ Default.group = null;
1848
1851
 
1849
- function _extends$h() { _extends$h = Object.assign ? Object.assign.bind() : 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$h.apply(this, arguments); }
1852
+ function _extends$j() { _extends$j = Object.assign ? Object.assign.bind() : 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$j.apply(this, arguments); }
1850
1853
  var CalendarIcon = (({
1851
1854
  styles = {},
1852
1855
  ...props
1853
- }) => /*#__PURE__*/React.createElement("svg", _extends$h({
1856
+ }) => /*#__PURE__*/React.createElement("svg", _extends$j({
1854
1857
  width: "14",
1855
1858
  height: "15",
1856
1859
  viewBox: "0 0 28 30",
@@ -1859,8 +1862,8 @@ var CalendarIcon = (({
1859
1862
  }, props), /*#__PURE__*/React.createElement("path", {
1860
1863
  fillRule: "evenodd",
1861
1864
  clipRule: "evenodd",
1862
- d: "M19 2H9V0H7v2H2a2 2 0 00-2 2v24a2 2 0 002 2h24a2 2 0 002-2V4a2 2 0 00-2-2h-5V0h-2v2zM7 7V4H2v5h24V4h-5v3h-2V4H9v3H7zm-5 4v17h24V11H2z",
1863
- fill: "currentColor"
1865
+ fill: "currentColor",
1866
+ d: "M19 2H9V0H7v2H2a2 2 0 00-2 2v24a2 2 0 002 2h24a2 2 0 002-2V4a2 2 0 00-2-2h-5V0h-2v2zM7 7V4H2v5h24V4h-5v3h-2V4H9v3H7zm-5 4v17h24V11H2z"
1864
1867
  })));
1865
1868
 
1866
1869
  function InputAdorner(props) {
@@ -1873,10 +1876,10 @@ function InputAdorner(props) {
1873
1876
  disabled,
1874
1877
  hasErrors
1875
1878
  } = props;
1876
- const onAdornmentClick = () => inputRef?.current?.focus();
1879
+ const onAdornmentClick = () => inputRef && inputRef.current && inputRef.current.focus();
1877
1880
  return jsxs("div", {
1878
1881
  class: classNames('fjs-input-group', {
1879
- 'disabled': disabled
1882
+ 'fjs-disabled': disabled
1880
1883
  }, {
1881
1884
  'hasErrors': hasErrors
1882
1885
  }),
@@ -1884,11 +1887,17 @@ function InputAdorner(props) {
1884
1887
  children: [pre !== null && jsxs("span", {
1885
1888
  class: "fjs-input-adornment border-right border-radius-left",
1886
1889
  onClick: onAdornmentClick,
1887
- children: [" ", pre, " "]
1890
+ children: [" ", isString(pre) ? jsx("span", {
1891
+ class: "fjs-input-adornment-text",
1892
+ children: pre
1893
+ }) : pre, " "]
1888
1894
  }), children, post !== null && jsxs("span", {
1889
1895
  class: "fjs-input-adornment border-left border-radius-right",
1890
1896
  onClick: onAdornmentClick,
1891
- children: [" ", post, " "]
1897
+ children: [" ", isString(post) ? jsx("span", {
1898
+ class: "fjs-input-adornment-text",
1899
+ children: post
1900
+ }) : post, " "]
1892
1901
  })]
1893
1902
  });
1894
1903
  }
@@ -1930,14 +1939,10 @@ function Datepicker(props) {
1930
1939
  dateFormat: 'm/d/Y',
1931
1940
  static: true,
1932
1941
  clickOpens: false,
1942
+ // TODO: support dates prior to 1900 (https://github.com/bpmn-io/form-js/issues/533)
1943
+ minDate: disallowPassedDates ? 'today' : '01/01/1900',
1933
1944
  errorHandler: () => {/* do nothing, we expect the values to sometimes be erronous and we don't want warnings polluting the console */}
1934
1945
  };
1935
- if (disallowPassedDates) {
1936
- config = {
1937
- ...config,
1938
- minDate: 'today'
1939
- };
1940
- }
1941
1946
  const instance = flatpickr(dateInputRef.current, config);
1942
1947
  setFlatpickrInstance(instance);
1943
1948
  const onCalendarFocusOut = e => {
@@ -2021,7 +2026,7 @@ function Datepicker(props) {
2021
2026
  class: 'fjs-input',
2022
2027
  disabled: disabled,
2023
2028
  placeholder: "mm/dd/yyyy",
2024
- autoComplete: "false",
2029
+ autoComplete: "off",
2025
2030
  onFocus: onInputFocus,
2026
2031
  onKeyDown: onInputKeyDown,
2027
2032
  onMouseDown: e => !flatpickrInstance.isOpen && flatpickrInstance.open(),
@@ -2034,24 +2039,24 @@ function Datepicker(props) {
2034
2039
  });
2035
2040
  }
2036
2041
 
2037
- function _extends$g() { _extends$g = Object.assign ? Object.assign.bind() : 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$g.apply(this, arguments); }
2042
+ function _extends$i() { _extends$i = Object.assign ? Object.assign.bind() : 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$i.apply(this, arguments); }
2038
2043
  var ClockIcon = (({
2039
2044
  styles = {},
2040
2045
  ...props
2041
- }) => /*#__PURE__*/React.createElement("svg", _extends$g({
2046
+ }) => /*#__PURE__*/React.createElement("svg", _extends$i({
2042
2047
  width: "16",
2043
2048
  height: "16",
2044
2049
  viewBox: "0 0 28 29",
2045
2050
  fill: "none",
2046
2051
  xmlns: "http://www.w3.org/2000/svg"
2047
2052
  }, props), /*#__PURE__*/React.createElement("path", {
2048
- d: "M13 14.41L18.59 20 20 18.59l-5-5.01V5h-2v9.41z",
2049
- fill: "currentColor"
2053
+ fill: "currentColor",
2054
+ d: "M13 14.41L18.59 20 20 18.59l-5-5.01V5h-2v9.41z"
2050
2055
  }), /*#__PURE__*/React.createElement("path", {
2051
2056
  fillRule: "evenodd",
2052
2057
  clipRule: "evenodd",
2053
- d: "M6.222 25.64A14 14 0 1021.778 2.36 14 14 0 006.222 25.64zM7.333 4.023a12 12 0 1113.334 19.955A12 12 0 017.333 4.022z",
2054
- fill: "currentColor"
2058
+ fill: "currentColor",
2059
+ d: "M6.222 25.64A14 14 0 1021.778 2.36 14 14 0 006.222 25.64zM7.333 4.023a12 12 0 1113.334 19.955A12 12 0 017.333 4.022z"
2055
2060
  })));
2056
2061
 
2057
2062
  function useKeyDownAction(targetKey, action, listenerElement = window) {
@@ -2074,7 +2079,7 @@ const DEFAULT_LABEL_GETTER = value => value;
2074
2079
  const NOOP = () => {};
2075
2080
  function DropdownList(props) {
2076
2081
  const {
2077
- keyEventsListener = window,
2082
+ listenerElement = window,
2078
2083
  values = [],
2079
2084
  getLabel = DEFAULT_LABEL_GETTER,
2080
2085
  onValueSelected = NOOP,
@@ -2104,18 +2109,18 @@ function DropdownList(props) {
2104
2109
  changeFocusedValueIndex(-1);
2105
2110
  setMouseControl(false);
2106
2111
  }
2107
- }, keyEventsListener);
2112
+ }, listenerElement);
2108
2113
  useKeyDownAction('ArrowDown', () => {
2109
2114
  if (values.length) {
2110
2115
  changeFocusedValueIndex(1);
2111
2116
  setMouseControl(false);
2112
2117
  }
2113
- }, keyEventsListener);
2118
+ }, listenerElement);
2114
2119
  useKeyDownAction('Enter', () => {
2115
2120
  if (focusedItem) {
2116
2121
  onValueSelected(focusedItem);
2117
2122
  }
2118
- }, keyEventsListener);
2123
+ }, listenerElement);
2119
2124
  useEffect(() => {
2120
2125
  const individualEntries = dropdownContainer.current.children;
2121
2126
  if (individualEntries.length && !mouseControl) {
@@ -2288,7 +2293,7 @@ function Timepicker(props) {
2288
2293
  value: rawValue,
2289
2294
  disabled: disabled,
2290
2295
  placeholder: use24h ? 'hh:mm' : 'hh:mm ?m',
2291
- autoComplete: "false",
2296
+ autoComplete: "off",
2292
2297
  onFocus: () => useDropdown && setDropdownIsOpen(true),
2293
2298
  onClick: () => useDropdown && setDropdownIsOpen(true)
2294
2299
 
@@ -2339,7 +2344,7 @@ function Datetime(props) {
2339
2344
  } = validate;
2340
2345
  const {
2341
2346
  formId
2342
- } = useContext(FormContext);
2347
+ } = useContext(FormContext$1);
2343
2348
  const getNullDateTime = () => ({
2344
2349
  date: new Date(Date.parse(null)),
2345
2350
  time: null
@@ -2480,12 +2485,12 @@ function Datetime(props) {
2480
2485
  })]
2481
2486
  });
2482
2487
  }
2483
- Datetime.create = function (options = {}) {
2484
- const newOptions = {};
2485
- set(newOptions, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES.DATE);
2486
- set(newOptions, DATE_LABEL_PATH, 'Date');
2488
+ Datetime.create = (options = {}) => {
2489
+ const defaults = {};
2490
+ set(defaults, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES.DATE);
2491
+ set(defaults, DATE_LABEL_PATH, 'Date');
2487
2492
  return {
2488
- ...newOptions,
2493
+ ...defaults,
2489
2494
  ...options
2490
2495
  };
2491
2496
  };
@@ -2493,6 +2498,8 @@ Datetime.type = type$8;
2493
2498
  Datetime.keyed = true;
2494
2499
  Datetime.emptyValue = null;
2495
2500
  Datetime.sanitizeValue = sanitizeDateTimePickerValue;
2501
+ Datetime.label = 'Date time';
2502
+ Datetime.group = 'basic-input';
2496
2503
 
2497
2504
  /**
2498
2505
  * This file must not be changed or exchanged.
@@ -2656,11 +2663,11 @@ function isExpression(value) {
2656
2663
  return isString(value) && value.startsWith('=');
2657
2664
  }
2658
2665
 
2659
- function _extends$f() { _extends$f = Object.assign ? Object.assign.bind() : 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$f.apply(this, arguments); }
2666
+ function _extends$h() { _extends$h = Object.assign ? Object.assign.bind() : 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$h.apply(this, arguments); }
2660
2667
  var ImagePlaceholder = (({
2661
2668
  styles = {},
2662
2669
  ...props
2663
- }) => /*#__PURE__*/React.createElement("svg", _extends$f({
2670
+ }) => /*#__PURE__*/React.createElement("svg", _extends$h({
2664
2671
  width: "64",
2665
2672
  height: "64",
2666
2673
  viewBox: "0 0 1280 1280",
@@ -2700,7 +2707,7 @@ function Image(props) {
2700
2707
  const altText = useExpressionValue(alt);
2701
2708
  const {
2702
2709
  formId
2703
- } = useContext(FormContext);
2710
+ } = useContext(FormContext$1);
2704
2711
  return jsx("div", {
2705
2712
  class: formFieldClasses(type$7),
2706
2713
  children: jsxs("div", {
@@ -2719,13 +2726,47 @@ function Image(props) {
2719
2726
  })
2720
2727
  });
2721
2728
  }
2722
- Image.create = function (options = {}) {
2723
- return {
2724
- ...options
2725
- };
2726
- };
2729
+ Image.create = (options = {}) => ({
2730
+ ...options
2731
+ });
2727
2732
  Image.type = type$7;
2728
2733
  Image.keyed = false;
2734
+ Image.label = 'Image view';
2735
+ Image.group = 'presentation';
2736
+
2737
+ function _extends$g() { _extends$g = Object.assign ? Object.assign.bind() : 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$g.apply(this, arguments); }
2738
+ var AngelDownIcon = (({
2739
+ styles = {},
2740
+ ...props
2741
+ }) => /*#__PURE__*/React.createElement("svg", _extends$g({
2742
+ xmlns: "http://www.w3.org/2000/svg",
2743
+ width: "8",
2744
+ height: "8"
2745
+ }, props), /*#__PURE__*/React.createElement("path", {
2746
+ fillRule: "evenodd",
2747
+ clipRule: "evenodd",
2748
+ fill: "currentColor",
2749
+ stroke: "currentColor",
2750
+ strokeWidth: ".5",
2751
+ d: "M7.75 1.336L4 6.125.258 1.335 0 1.54l4 5.125L8 1.54zm0 0"
2752
+ })));
2753
+
2754
+ function _extends$f() { _extends$f = Object.assign ? Object.assign.bind() : 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$f.apply(this, arguments); }
2755
+ var AngelUpIcon = (({
2756
+ styles = {},
2757
+ ...props
2758
+ }) => /*#__PURE__*/React.createElement("svg", _extends$f({
2759
+ xmlns: "http://www.w3.org/2000/svg",
2760
+ width: "8",
2761
+ height: "8"
2762
+ }, props), /*#__PURE__*/React.createElement("path", {
2763
+ fillRule: "evenodd",
2764
+ clipRule: "evenodd",
2765
+ fill: "currentColor",
2766
+ stroke: "currentColor",
2767
+ strokeWidth: ".5",
2768
+ d: "M7.75 6.664L4 1.875.258 6.665 0 6.46l4-5.125L8 6.46zm0 0"
2769
+ })));
2729
2770
 
2730
2771
  const type$6 = 'number';
2731
2772
  function Numberfield(props) {
@@ -2854,7 +2895,7 @@ function Numberfield(props) {
2854
2895
  };
2855
2896
  const {
2856
2897
  formId
2857
- } = useContext(FormContext);
2898
+ } = useContext(FormContext$1);
2858
2899
  return jsxs("div", {
2859
2900
  class: formFieldClasses(type$6, {
2860
2901
  errors,
@@ -2870,7 +2911,7 @@ function Numberfield(props) {
2870
2911
  post: suffixAdorner,
2871
2912
  children: jsxs("div", {
2872
2913
  class: classNames('fjs-vertical-group', {
2873
- 'disabled': disabled
2914
+ 'fjs-disabled': disabled
2874
2915
  }, {
2875
2916
  'hasErrors': errors.length
2876
2917
  }),
@@ -2891,22 +2932,24 @@ function Numberfield(props) {
2891
2932
  value: displayValue
2892
2933
  }), jsxs("div", {
2893
2934
  class: classNames('fjs-number-arrow-container', {
2894
- 'disabled': disabled
2935
+ 'fjs-disabled': disabled
2895
2936
  }),
2896
2937
  children: [jsx("button", {
2897
2938
  class: "fjs-number-arrow-up",
2898
2939
  type: "button",
2940
+ "aria-label": "Increment",
2899
2941
  onClick: () => increment(),
2900
2942
  tabIndex: -1,
2901
- children: "\u02C4"
2943
+ children: jsx(AngelUpIcon, {})
2902
2944
  }), jsx("div", {
2903
2945
  class: "fjs-number-arrow-separator"
2904
2946
  }), jsx("button", {
2905
2947
  class: "fjs-number-arrow-down",
2906
2948
  type: "button",
2949
+ "aria-label": "Decrement",
2907
2950
  onClick: () => decrement(),
2908
2951
  tabIndex: -1,
2909
- children: "\u02C5"
2952
+ children: jsx(AngelDownIcon, {})
2910
2953
  })]
2911
2954
  })]
2912
2955
  })
@@ -2917,7 +2960,9 @@ function Numberfield(props) {
2917
2960
  })]
2918
2961
  });
2919
2962
  }
2920
- Numberfield.create = (options = {}) => options;
2963
+ Numberfield.create = (options = {}) => ({
2964
+ ...options
2965
+ });
2921
2966
  Numberfield.sanitizeValue = ({
2922
2967
  value,
2923
2968
  formField
@@ -2935,6 +2980,7 @@ Numberfield.type = type$6;
2935
2980
  Numberfield.keyed = true;
2936
2981
  Numberfield.label = 'Number';
2937
2982
  Numberfield.emptyValue = null;
2983
+ Numberfield.group = 'basic-input';
2938
2984
 
2939
2985
  const type$5 = 'radio';
2940
2986
  function Radio(props) {
@@ -2965,7 +3011,7 @@ function Radio(props) {
2965
3011
  } = useValuesAsync(field);
2966
3012
  const {
2967
3013
  formId
2968
- } = useContext(FormContext);
3014
+ } = useContext(FormContext$1);
2969
3015
  return jsxs("div", {
2970
3016
  class: formFieldClasses(type$5, {
2971
3017
  errors,
@@ -2999,12 +3045,17 @@ function Radio(props) {
2999
3045
  });
3000
3046
  }
3001
3047
  Radio.create = function (options = {}) {
3002
- if (options.valuesKey) return options;
3003
- return {
3004
- values: [{
3048
+ const defaults = {};
3049
+
3050
+ // provide default values if valuesKey isn't set
3051
+ if (!options.valuesKey) {
3052
+ defaults.values = [{
3005
3053
  label: 'Value',
3006
3054
  value: 'value'
3007
- }],
3055
+ }];
3056
+ }
3057
+ return {
3058
+ ...defaults,
3008
3059
  ...options
3009
3060
  };
3010
3061
  };
@@ -3013,6 +3064,266 @@ Radio.label = 'Radio';
3013
3064
  Radio.keyed = true;
3014
3065
  Radio.emptyValue = null;
3015
3066
  Radio.sanitizeValue = sanitizeSingleSelectValue;
3067
+ Radio.group = 'selection';
3068
+
3069
+ function _extends$e() { _extends$e = Object.assign ? Object.assign.bind() : 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$e.apply(this, arguments); }
3070
+ var XMarkIcon = (({
3071
+ styles = {},
3072
+ ...props
3073
+ }) => /*#__PURE__*/React.createElement("svg", _extends$e({
3074
+ xmlns: "http://www.w3.org/2000/svg",
3075
+ width: "8",
3076
+ height: "8"
3077
+ }, props), /*#__PURE__*/React.createElement("path", {
3078
+ fillRule: "evenodd",
3079
+ clipRule: "evenodd",
3080
+ fill: "currentColor",
3081
+ stroke: "currentColor",
3082
+ strokeWidth: ".5",
3083
+ d: "M4 3.766L7.43.336l.234.234L4.234 4l3.43 3.43-.234.234L4 4.234.57 7.664.336 7.43 3.766 4 .336.57.57.336zm0 0"
3084
+ })));
3085
+
3086
+ function SearchableSelect(props) {
3087
+ const {
3088
+ id,
3089
+ disabled,
3090
+ errors,
3091
+ field,
3092
+ value
3093
+ } = props;
3094
+ const {
3095
+ formId
3096
+ } = useContext(FormContext$1);
3097
+ const [filter, setFilter] = useState('');
3098
+ const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
3099
+ const [shouldApplyFilter, setShouldApplyFilter] = useState(true);
3100
+ const [isEscapeClosed, setIsEscapeClose] = useState(false);
3101
+ const searchbarRef = useRef();
3102
+ const {
3103
+ state: loadState,
3104
+ values: options
3105
+ } = useValuesAsync(field);
3106
+
3107
+ // We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
3108
+ const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({
3109
+ [o.value]: options[x]
3110
+ }))), [options]);
3111
+ const valueLabel = useMemo(() => value && valueToOptionMap[value] && valueToOptionMap[value].label || '', [value, valueToOptionMap]);
3112
+
3113
+ // whenever we change the underlying value, set the label to it
3114
+ useEffect(() => {
3115
+ setFilter(valueLabel);
3116
+ }, [valueLabel]);
3117
+ const filteredOptions = useMemo(() => {
3118
+ if (loadState === LOAD_STATES.LOADED) {
3119
+ return shouldApplyFilter ? options.filter(o => o.label && o.value && o.label.toLowerCase().includes(filter.toLowerCase())) : options;
3120
+ }
3121
+ return [];
3122
+ }, [filter, loadState, options, shouldApplyFilter]);
3123
+ const onChange = ({
3124
+ target
3125
+ }) => {
3126
+ setIsEscapeClose(false);
3127
+ setIsDropdownExpanded(true);
3128
+ setShouldApplyFilter(true);
3129
+ setFilter(target.value || '');
3130
+ };
3131
+ const setValue = useCallback(option => {
3132
+ setFilter(option && option.label || '');
3133
+ props.onChange({
3134
+ value: option && option.value || null,
3135
+ field
3136
+ });
3137
+ }, [field, props]);
3138
+ const onInputKeyDown = useCallback(keyDownEvent => {
3139
+ switch (keyDownEvent.key) {
3140
+ case 'ArrowUp':
3141
+ keyDownEvent.preventDefault();
3142
+ break;
3143
+ case 'ArrowDown':
3144
+ {
3145
+ if (!isDropdownExpanded) {
3146
+ setIsDropdownExpanded(true);
3147
+ setShouldApplyFilter(false);
3148
+ }
3149
+ keyDownEvent.preventDefault();
3150
+ break;
3151
+ }
3152
+ case 'Escape':
3153
+ setIsEscapeClose(true);
3154
+ break;
3155
+ case 'Enter':
3156
+ if (isEscapeClosed) {
3157
+ setIsEscapeClose(false);
3158
+ }
3159
+ break;
3160
+ }
3161
+ }, [isDropdownExpanded, isEscapeClosed]);
3162
+ const displayState = useMemo(() => {
3163
+ const ds = {};
3164
+ ds.componentReady = !disabled && loadState === LOAD_STATES.LOADED;
3165
+ ds.displayCross = ds.componentReady && value !== null && value !== undefined;
3166
+ ds.displayDropdown = !disabled && isDropdownExpanded && !isEscapeClosed;
3167
+ return ds;
3168
+ }, [disabled, isDropdownExpanded, isEscapeClosed, loadState, value]);
3169
+ const onAngelMouseDown = useCallback(e => {
3170
+ setIsEscapeClose(false);
3171
+ setIsDropdownExpanded(!isDropdownExpanded);
3172
+ const searchbar = searchbarRef.current;
3173
+ isDropdownExpanded ? searchbar.blur() : searchbar.focus();
3174
+ e.preventDefault();
3175
+ }, [isDropdownExpanded]);
3176
+ return jsxs(Fragment$1, {
3177
+ children: [jsxs("div", {
3178
+ id: prefixId(`${id}`, formId),
3179
+ class: classNames('fjs-input-group', {
3180
+ 'disabled': disabled
3181
+ }, {
3182
+ 'hasErrors': errors.length
3183
+ }),
3184
+ children: [jsx("input", {
3185
+ disabled: disabled,
3186
+ class: "fjs-input",
3187
+ ref: searchbarRef,
3188
+ id: prefixId(`${id}-search`, formId),
3189
+ onChange: onChange,
3190
+ type: "text",
3191
+ value: filter,
3192
+ placeholder: 'Search',
3193
+ autoComplete: "off",
3194
+ onKeyDown: e => onInputKeyDown(e),
3195
+ onMouseDown: () => {
3196
+ setIsEscapeClose(false);
3197
+ setIsDropdownExpanded(true);
3198
+ setShouldApplyFilter(false);
3199
+ },
3200
+ onFocus: () => {
3201
+ setIsDropdownExpanded(true);
3202
+ setShouldApplyFilter(false);
3203
+ },
3204
+ onBlur: () => {
3205
+ setIsDropdownExpanded(false);
3206
+ setFilter(valueLabel);
3207
+ }
3208
+ }), displayState.displayCross && jsxs("span", {
3209
+ class: "fjs-select-cross",
3210
+ onMouseDown: e => {
3211
+ setValue(null);
3212
+ e.preventDefault();
3213
+ },
3214
+ children: [jsx(XMarkIcon, {}), " "]
3215
+ }), jsx("span", {
3216
+ class: "fjs-select-arrow",
3217
+ onMouseDown: e => onAngelMouseDown(e),
3218
+ children: displayState.displayDropdown ? jsx(AngelUpIcon, {}) : jsx(AngelDownIcon, {})
3219
+ })]
3220
+ }), jsx("div", {
3221
+ class: "fjs-select-anchor",
3222
+ children: displayState.displayDropdown && jsx(DropdownList, {
3223
+ values: filteredOptions,
3224
+ getLabel: o => o.label,
3225
+ onValueSelected: o => {
3226
+ setValue(o);
3227
+ setIsDropdownExpanded(false);
3228
+ },
3229
+ listenerElement: searchbarRef.current
3230
+ })
3231
+ })]
3232
+ });
3233
+ }
3234
+
3235
+ function SimpleSelect(props) {
3236
+ const {
3237
+ id,
3238
+ disabled,
3239
+ errors,
3240
+ field,
3241
+ value
3242
+ } = props;
3243
+ const {
3244
+ formId
3245
+ } = useContext(FormContext$1);
3246
+ const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
3247
+ const selectRef = useRef();
3248
+ const {
3249
+ state: loadState,
3250
+ values: options
3251
+ } = useValuesAsync(field);
3252
+
3253
+ // We cache a map of option values to their index so that we don't need to search the whole options array every time to correlate the label
3254
+ const valueToOptionMap = useMemo(() => Object.assign({}, ...options.map((o, x) => ({
3255
+ [o.value]: options[x]
3256
+ }))), [options]);
3257
+ const valueLabel = useMemo(() => value && valueToOptionMap[value] && valueToOptionMap[value].label || '', [value, valueToOptionMap]);
3258
+ const setValue = useCallback(option => {
3259
+ props.onChange({
3260
+ value: option && option.value || null,
3261
+ field
3262
+ });
3263
+ }, [field, props]);
3264
+ const displayState = useMemo(() => {
3265
+ const ds = {};
3266
+ ds.componentReady = !disabled && loadState === LOAD_STATES.LOADED;
3267
+ ds.displayCross = ds.componentReady && value !== null && value !== undefined;
3268
+ ds.displayDropdown = !disabled && isDropdownExpanded;
3269
+ return ds;
3270
+ }, [disabled, isDropdownExpanded, loadState, value]);
3271
+ const onMouseDown = useCallback(e => {
3272
+ const select = selectRef.current;
3273
+ setIsDropdownExpanded(!isDropdownExpanded);
3274
+ if (isDropdownExpanded) {
3275
+ select.blur();
3276
+ } else {
3277
+ select.focus();
3278
+ }
3279
+ e.preventDefault();
3280
+ }, [isDropdownExpanded]);
3281
+ const initialFocusIndex = useMemo(() => value && findIndex(options, o => o.value === value) || 0, [options, value]);
3282
+ return jsxs(Fragment$1, {
3283
+ children: [jsxs("div", {
3284
+ ref: selectRef,
3285
+ id: prefixId(`${id}`, formId),
3286
+ class: classNames('fjs-input-group', {
3287
+ 'disabled': disabled
3288
+ }, {
3289
+ 'hasErrors': errors.length
3290
+ }),
3291
+ onFocus: () => setIsDropdownExpanded(true),
3292
+ onBlur: () => setIsDropdownExpanded(false),
3293
+ onMouseDown: e => onMouseDown(e),
3294
+ tabIndex: disabled ? undefined : 0,
3295
+ children: [jsx("div", {
3296
+ class: classNames('fjs-select-display', {
3297
+ 'fjs-select-placeholder': !value
3298
+ }),
3299
+ id: prefixId(`${id}-display`, formId),
3300
+ children: valueLabel || 'Select'
3301
+ }), displayState.displayCross && jsx("span", {
3302
+ class: "fjs-select-cross",
3303
+ onMouseDown: e => {
3304
+ setValue(null);
3305
+ e.stopPropagation();
3306
+ },
3307
+ children: jsx(XMarkIcon, {})
3308
+ }), jsx("span", {
3309
+ class: "fjs-select-arrow",
3310
+ children: displayState.displayDropdown ? jsx(AngelUpIcon, {}) : jsx(AngelDownIcon, {})
3311
+ })]
3312
+ }), jsx("div", {
3313
+ class: "fjs-select-anchor",
3314
+ children: displayState.displayDropdown && jsx(DropdownList, {
3315
+ values: options,
3316
+ getLabel: o => o.label,
3317
+ initialFocusIndex: initialFocusIndex,
3318
+ onValueSelected: o => {
3319
+ setValue(o);
3320
+ setIsDropdownExpanded(false);
3321
+ },
3322
+ listenerElement: selectRef.current
3323
+ })
3324
+ })]
3325
+ });
3326
+ }
3016
3327
 
3017
3328
  const type$4 = 'select';
3018
3329
  function Select(props) {
@@ -3020,32 +3331,30 @@ function Select(props) {
3020
3331
  disabled,
3021
3332
  errors = [],
3022
3333
  field,
3334
+ onChange,
3023
3335
  value
3024
3336
  } = props;
3025
3337
  const {
3026
3338
  description,
3027
3339
  id,
3028
3340
  label,
3341
+ searchable = false,
3029
3342
  validate = {}
3030
3343
  } = field;
3031
3344
  const {
3032
3345
  required
3033
3346
  } = validate;
3034
- const onChange = ({
3035
- target
3036
- }) => {
3037
- props.onChange({
3038
- field,
3039
- value: target.value === '' ? null : target.value
3040
- });
3041
- };
3042
- const {
3043
- state: loadState,
3044
- values: options
3045
- } = useValuesAsync(field);
3046
3347
  const {
3047
3348
  formId
3048
- } = useContext(FormContext);
3349
+ } = useContext(FormContext$1);
3350
+ const selectProps = useMemo(() => ({
3351
+ id,
3352
+ disabled,
3353
+ errors,
3354
+ field,
3355
+ value,
3356
+ onChange
3357
+ }), [disabled, errors, field, id, value, onChange]);
3049
3358
  return jsxs("div", {
3050
3359
  class: formFieldClasses(type$4, {
3051
3360
  errors,
@@ -3055,20 +3364,10 @@ function Select(props) {
3055
3364
  id: prefixId(id, formId),
3056
3365
  label: label,
3057
3366
  required: required
3058
- }), jsxs("select", {
3059
- class: "fjs-select",
3060
- disabled: disabled,
3061
- id: prefixId(id, formId),
3062
- onChange: onChange,
3063
- value: value || '',
3064
- children: [jsx("option", {
3065
- value: ""
3066
- }), loadState == LOAD_STATES.LOADED && options.map((option, index) => {
3067
- return jsx("option", {
3068
- value: option.value,
3069
- children: option.label
3070
- }, `${id}-${index}`);
3071
- })]
3367
+ }), searchable ? jsx(SearchableSelect, {
3368
+ ...selectProps
3369
+ }) : jsx(SimpleSelect, {
3370
+ ...selectProps
3072
3371
  }), jsx(Description, {
3073
3372
  description: description
3074
3373
  }), jsx(Errors, {
@@ -3076,13 +3375,18 @@ function Select(props) {
3076
3375
  })]
3077
3376
  });
3078
3377
  }
3079
- Select.create = function (options = {}) {
3080
- if (options.valuesKey) return options;
3081
- return {
3082
- values: [{
3378
+ Select.create = (options = {}) => {
3379
+ const defaults = {};
3380
+
3381
+ // provide default values if valuesKey isn't set
3382
+ if (!options.valuesKey) {
3383
+ defaults.values = [{
3083
3384
  label: 'Value',
3084
3385
  value: 'value'
3085
- }],
3386
+ }];
3387
+ }
3388
+ return {
3389
+ ...defaults,
3086
3390
  ...options
3087
3391
  };
3088
3392
  };
@@ -3091,22 +3395,7 @@ Select.label = 'Select';
3091
3395
  Select.keyed = true;
3092
3396
  Select.emptyValue = null;
3093
3397
  Select.sanitizeValue = sanitizeSingleSelectValue;
3094
-
3095
- function _extends$e() { _extends$e = Object.assign ? Object.assign.bind() : 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$e.apply(this, arguments); }
3096
- var CloseIcon = (({
3097
- styles = {},
3098
- ...props
3099
- }) => /*#__PURE__*/React.createElement("svg", _extends$e({
3100
- width: "16",
3101
- height: "16",
3102
- fill: "none",
3103
- xmlns: "http://www.w3.org/2000/svg"
3104
- }, props), /*#__PURE__*/React.createElement("path", {
3105
- fillRule: "evenodd",
3106
- clipRule: "evenodd",
3107
- 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",
3108
- fill: "currentColor"
3109
- })));
3398
+ Select.group = 'selection';
3110
3399
 
3111
3400
  const type$3 = 'taglist';
3112
3401
  function Taglist(props) {
@@ -3123,7 +3412,7 @@ function Taglist(props) {
3123
3412
  } = field;
3124
3413
  const {
3125
3414
  formId
3126
- } = useContext(FormContext);
3415
+ } = useContext(FormContext$1);
3127
3416
  const [filter, setFilter] = useState('');
3128
3417
  const [filteredOptions, setFilteredOptions] = useState([]);
3129
3418
  const [isDropdownExpanded, setIsDropdownExpanded] = useState(false);
@@ -3211,6 +3500,7 @@ function Taglist(props) {
3211
3500
  searchbarRef.current.focus();
3212
3501
  }
3213
3502
  };
3503
+ const shouldDisplayDropdown = useMemo(() => !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed, [disabled, isDropdownExpanded, isEscapeClosed, loadState]);
3214
3504
  return jsxs("div", {
3215
3505
  class: formFieldClasses(type$3, {
3216
3506
  errors,
@@ -3221,23 +3511,25 @@ function Taglist(props) {
3221
3511
  id: prefixId(`${id}-search`, formId)
3222
3512
  }), jsxs("div", {
3223
3513
  class: classNames('fjs-taglist', {
3224
- 'disabled': disabled
3514
+ 'fjs-disabled': disabled
3225
3515
  }),
3226
- children: [!disabled && loadState === LOAD_STATES.LOADED && jsx("div", {
3516
+ children: [loadState === LOAD_STATES.LOADED && jsx("div", {
3227
3517
  class: "fjs-taglist-tags",
3228
3518
  children: values.map(v => {
3229
3519
  return jsxs("div", {
3230
- class: "fjs-taglist-tag",
3520
+ class: classNames('fjs-taglist-tag', {
3521
+ 'fjs-disabled': disabled
3522
+ }),
3231
3523
  onMouseDown: e => e.preventDefault(),
3232
3524
  children: [jsx("span", {
3233
3525
  class: "fjs-taglist-tag-label",
3234
3526
  children: valueToOptionMap[v] ? valueToOptionMap[v].label : `unexpected value{${v}}`
3235
- }), jsx("button", {
3527
+ }), !disabled && jsx("button", {
3236
3528
  type: "button",
3237
3529
  title: "Remove tag",
3238
3530
  class: "fjs-taglist-tag-remove",
3239
3531
  onClick: event => onTagRemoveClick(event, v),
3240
- children: jsx(CloseIcon, {})
3532
+ children: jsx(XMarkIcon, {})
3241
3533
  })]
3242
3534
  });
3243
3535
  })
@@ -3249,7 +3541,7 @@ function Taglist(props) {
3249
3541
  onChange: onFilterChange,
3250
3542
  type: "text",
3251
3543
  value: filter,
3252
- placeholder: 'Search',
3544
+ placeholder: disabled ? '' : 'Search',
3253
3545
  autoComplete: "off",
3254
3546
  onKeyDown: e => onInputKeyDown(e),
3255
3547
  onMouseDown: () => setIsEscapeClose(false),
@@ -3261,7 +3553,7 @@ function Taglist(props) {
3261
3553
  })]
3262
3554
  }), jsx("div", {
3263
3555
  class: "fjs-taglist-anchor",
3264
- children: !disabled && loadState === LOAD_STATES.LOADED && isDropdownExpanded && !isEscapeClosed && jsx(DropdownList, {
3556
+ children: shouldDisplayDropdown && jsx(DropdownList, {
3265
3557
  values: filteredOptions,
3266
3558
  getLabel: o => o.label,
3267
3559
  onValueSelected: o => selectValue(o.value),
@@ -3275,33 +3567,234 @@ function Taglist(props) {
3275
3567
  })]
3276
3568
  });
3277
3569
  }
3278
- Taglist.create = function (options = {}) {
3279
- if (options.valuesKey) return options;
3280
- return {
3281
- values: [{
3570
+ Taglist.create = (options = {}) => {
3571
+ const defaults = {};
3572
+
3573
+ // provide default values if valuesKey isn't set
3574
+ if (!options.valuesKey) {
3575
+ defaults.values = [{
3282
3576
  label: 'Value',
3283
3577
  value: 'value'
3284
- }],
3578
+ }];
3579
+ }
3580
+ return {
3581
+ ...defaults,
3285
3582
  ...options
3286
3583
  };
3287
3584
  };
3288
3585
  Taglist.type = type$3;
3289
- Taglist.label = 'Taglist';
3586
+ Taglist.label = 'Tag list';
3290
3587
  Taglist.keyed = true;
3291
3588
  Taglist.emptyValue = [];
3292
3589
  Taglist.sanitizeValue = sanitizeMultiSelectValue;
3590
+ Taglist.group = 'selection';
3293
3591
 
3294
- function _extends$d() { _extends$d = Object.assign ? Object.assign.bind() : 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$d.apply(this, arguments); }
3295
- var ButtonIcon = (({
3296
- styles = {},
3297
- ...props
3298
- }) => /*#__PURE__*/React.createElement("svg", _extends$d({
3299
- xmlns: "http://www.w3.org/2000/svg",
3300
- width: "54",
3301
- height: "54"
3302
- }, props), /*#__PURE__*/React.createElement("path", {
3303
- fillRule: "evenodd",
3304
- d: "M45 17a3 3 0 013 3v14a3 3 0 01-3 3H9a3 3 0 01-3-3V20a3 3 0 013-3h36zm-9 8.889H18v2.222h18V25.89z"
3592
+ const type$2 = 'text';
3593
+ function Text(props) {
3594
+ const {
3595
+ field,
3596
+ disableLinks
3597
+ } = props;
3598
+ const {
3599
+ text = ''
3600
+ } = field;
3601
+ const textValue = useExpressionValue(text) || '';
3602
+ const componentOverrides = disableLinks ? {
3603
+ 'a': DisabledLink
3604
+ } : {};
3605
+ return jsx("div", {
3606
+ class: formFieldClasses(type$2),
3607
+ children: jsx(Markup, {
3608
+ markup: safeMarkdown(textValue),
3609
+ components: componentOverrides,
3610
+ trim: false
3611
+ })
3612
+ });
3613
+ }
3614
+ Text.create = (options = {}) => ({
3615
+ text: '# Text',
3616
+ ...options
3617
+ });
3618
+ Text.type = type$2;
3619
+ Text.keyed = false;
3620
+ Text.group = 'presentation';
3621
+ Text.label = 'Text view';
3622
+ function DisabledLink({
3623
+ href,
3624
+ children
3625
+ }) {
3626
+ return jsx("a", {
3627
+ class: "fjs-disabled-link",
3628
+ href: href,
3629
+ tabIndex: -1,
3630
+ children: children
3631
+ });
3632
+ }
3633
+
3634
+ const type$1 = 'textfield';
3635
+ function Textfield(props) {
3636
+ const {
3637
+ disabled,
3638
+ errors = [],
3639
+ field,
3640
+ value = ''
3641
+ } = props;
3642
+ const {
3643
+ description,
3644
+ id,
3645
+ label,
3646
+ appearance = {},
3647
+ validate = {}
3648
+ } = field;
3649
+ const {
3650
+ prefixAdorner,
3651
+ suffixAdorner
3652
+ } = appearance;
3653
+ const {
3654
+ required
3655
+ } = validate;
3656
+ const onChange = ({
3657
+ target
3658
+ }) => {
3659
+ props.onChange({
3660
+ field,
3661
+ value: target.value
3662
+ });
3663
+ };
3664
+ const {
3665
+ formId
3666
+ } = useContext(FormContext$1);
3667
+ return jsxs("div", {
3668
+ class: formFieldClasses(type$1, {
3669
+ errors,
3670
+ disabled
3671
+ }),
3672
+ children: [jsx(Label, {
3673
+ id: prefixId(id, formId),
3674
+ label: label,
3675
+ required: required
3676
+ }), jsx(InputAdorner, {
3677
+ disabled: disabled,
3678
+ pre: prefixAdorner,
3679
+ post: suffixAdorner,
3680
+ children: jsx("input", {
3681
+ class: "fjs-input",
3682
+ disabled: disabled,
3683
+ id: prefixId(id, formId),
3684
+ onInput: onChange,
3685
+ type: "text",
3686
+ value: value
3687
+ })
3688
+ }), jsx(Description, {
3689
+ description: description
3690
+ }), jsx(Errors, {
3691
+ errors: errors
3692
+ })]
3693
+ });
3694
+ }
3695
+ Textfield.create = (options = {}) => ({
3696
+ ...options
3697
+ });
3698
+ Textfield.type = type$1;
3699
+ Textfield.label = 'Text field';
3700
+ Textfield.keyed = true;
3701
+ Textfield.emptyValue = '';
3702
+ Textfield.sanitizeValue = ({
3703
+ value
3704
+ }) => isArray(value) || isObject(value) ? '' : String(value);
3705
+ Textfield.group = 'basic-input';
3706
+
3707
+ const type = 'textarea';
3708
+ function Textarea(props) {
3709
+ const {
3710
+ disabled,
3711
+ errors = [],
3712
+ field,
3713
+ value = ''
3714
+ } = props;
3715
+ const {
3716
+ description,
3717
+ id,
3718
+ label,
3719
+ validate = {}
3720
+ } = field;
3721
+ const {
3722
+ required
3723
+ } = validate;
3724
+ const textareaRef = useRef();
3725
+ const onInput = ({
3726
+ target
3727
+ }) => {
3728
+ props.onChange({
3729
+ field,
3730
+ value: target.value
3731
+ });
3732
+ };
3733
+ const autoSizeTextarea = useCallback(textarea => {
3734
+ // Ensures the textarea shrinks back, and improves resizing behavior consistency
3735
+ textarea.style.height = '0px';
3736
+ const computed = window.getComputedStyle(textarea);
3737
+ const calculatedHeight = parseInt(computed.getPropertyValue('border-top-width')) + parseInt(computed.getPropertyValue('padding-top')) + textarea.scrollHeight + parseInt(computed.getPropertyValue('padding-bottom')) + parseInt(computed.getPropertyValue('border-bottom-width'));
3738
+ const minHeight = 75;
3739
+ const maxHeight = 350;
3740
+ const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
3741
+ textarea.style.height = `${displayHeight}px`;
3742
+
3743
+ // Overflow is hidden by default to hide scrollbar flickering
3744
+ textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
3745
+ }, []);
3746
+ useEffect(() => {
3747
+ autoSizeTextarea(textareaRef.current);
3748
+ }, [autoSizeTextarea, value]);
3749
+ const {
3750
+ formId
3751
+ } = useContext(FormContext$1);
3752
+ return jsxs("div", {
3753
+ class: formFieldClasses(type, {
3754
+ errors,
3755
+ disabled
3756
+ }),
3757
+ children: [jsx(Label, {
3758
+ id: prefixId(id, formId),
3759
+ label: label,
3760
+ required: required
3761
+ }), jsx("textarea", {
3762
+ class: "fjs-textarea",
3763
+ disabled: disabled,
3764
+ id: prefixId(id, formId),
3765
+ onInput: onInput,
3766
+ value: value,
3767
+ ref: textareaRef
3768
+ }), jsx(Description, {
3769
+ description: description
3770
+ }), jsx(Errors, {
3771
+ errors: errors
3772
+ })]
3773
+ });
3774
+ }
3775
+ Textarea.create = (options = {}) => ({
3776
+ ...options
3777
+ });
3778
+ Textarea.type = type;
3779
+ Textarea.label = 'Text area';
3780
+ Textarea.keyed = true;
3781
+ Textarea.emptyValue = '';
3782
+ Textarea.sanitizeValue = ({
3783
+ value
3784
+ }) => isArray(value) || isObject(value) ? '' : String(value);
3785
+ Textarea.group = 'basic-input';
3786
+
3787
+ function _extends$d() { _extends$d = Object.assign ? Object.assign.bind() : 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$d.apply(this, arguments); }
3788
+ var ButtonIcon = (({
3789
+ styles = {},
3790
+ ...props
3791
+ }) => /*#__PURE__*/React.createElement("svg", _extends$d({
3792
+ xmlns: "http://www.w3.org/2000/svg",
3793
+ width: "54",
3794
+ height: "54"
3795
+ }, props), /*#__PURE__*/React.createElement("path", {
3796
+ fillRule: "evenodd",
3797
+ d: "M45 17a3 3 0 013 3v14a3 3 0 01-3 3H9a3 3 0 01-3-3V20a3 3 0 013-3h36zm-9 8.889H18v2.222h18V25.89z"
3305
3798
  })));
3306
3799
 
3307
3800
  function _extends$c() { _extends$c = Object.assign ? Object.assign.bind() : 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$c.apply(this, arguments); }
@@ -3516,232 +4009,24 @@ var ImageIcon = (({
3516
4009
  fill: "#000"
3517
4010
  })));
3518
4011
 
3519
- const iconsByType = {
3520
- button: ButtonIcon,
3521
- checkbox: CheckboxIcon,
3522
- checklist: ChecklistIcon,
3523
- columns: ColumnsIcon,
3524
- datetime: DatetimeIcon,
3525
- image: ImageIcon,
3526
- number: NumberIcon,
3527
- radio: RadioIcon,
3528
- select: SelectIcon,
3529
- taglist: TaglistIcon,
3530
- text: TextIcon,
3531
- textfield: TextfieldIcon,
3532
- textarea: TextareaIcon,
3533
- default: FormIcon
3534
- };
3535
-
3536
- const type$2 = 'text';
3537
- function Text(props) {
3538
- const {
3539
- field,
3540
- disabled
3541
- } = props;
3542
- const {
3543
- text = ''
3544
- } = field;
3545
- const textValue = useExpressionValue(text) || '';
3546
- return jsx("div", {
3547
- class: formFieldClasses(type$2),
3548
- children: renderText(field, textValue, disabled)
3549
- });
3550
- }
3551
- Text.create = function (options = {}) {
3552
- return {
3553
- text: '# Text',
3554
- ...options
3555
- };
3556
- };
3557
- Text.type = type$2;
3558
- Text.keyed = false;
3559
-
3560
- // helper //////////////
3561
-
3562
- function renderText(field, content, disabled) {
3563
- const {
3564
- text
3565
- } = field;
3566
- const Icon = iconsByType['text'];
3567
- if (disabled) {
3568
- if (!text) {
3569
- return jsxs("div", {
3570
- class: "fjs-form-field-placeholder",
3571
- children: [jsx(Icon, {
3572
- viewBox: "0 0 54 54"
3573
- }), "Text view is empty"]
3574
- });
3575
- }
3576
- if (isExpression$2(text)) {
3577
- return jsxs("div", {
3578
- class: "fjs-form-field-placeholder",
3579
- children: [jsx(Icon, {
3580
- viewBox: "0 0 54 54"
3581
- }), "Text view is populated by an expression"]
3582
- });
3583
- }
3584
- }
3585
- return jsx(Markup, {
3586
- markup: safeMarkdown(content),
3587
- trim: false
3588
- });
3589
- }
3590
-
3591
- const type$1 = 'textfield';
3592
- function Textfield(props) {
3593
- const {
3594
- disabled,
3595
- errors = [],
3596
- field,
3597
- value = ''
3598
- } = props;
3599
- const {
3600
- description,
3601
- id,
3602
- label,
3603
- appearance = {},
3604
- validate = {}
3605
- } = field;
3606
- const {
3607
- prefixAdorner,
3608
- suffixAdorner
3609
- } = appearance;
3610
- const {
3611
- required
3612
- } = validate;
3613
- const onChange = ({
3614
- target
3615
- }) => {
3616
- props.onChange({
3617
- field,
3618
- value: target.value
3619
- });
3620
- };
3621
- const {
3622
- formId
3623
- } = useContext(FormContext);
3624
- return jsxs("div", {
3625
- class: formFieldClasses(type$1, {
3626
- errors,
3627
- disabled
3628
- }),
3629
- children: [jsx(Label, {
3630
- id: prefixId(id, formId),
3631
- label: label,
3632
- required: required
3633
- }), jsx(InputAdorner, {
3634
- disabled: disabled,
3635
- pre: prefixAdorner,
3636
- post: suffixAdorner,
3637
- children: jsx("input", {
3638
- class: "fjs-input",
3639
- disabled: disabled,
3640
- id: prefixId(id, formId),
3641
- onInput: onChange,
3642
- type: "text",
3643
- value: value
3644
- })
3645
- }), jsx(Description, {
3646
- description: description
3647
- }), jsx(Errors, {
3648
- errors: errors
3649
- })]
3650
- });
3651
- }
3652
- Textfield.create = function (options = {}) {
3653
- return {
3654
- ...options
3655
- };
3656
- };
3657
- Textfield.type = type$1;
3658
- Textfield.label = 'Text field';
3659
- Textfield.keyed = true;
3660
- Textfield.emptyValue = '';
3661
- Textfield.sanitizeValue = ({
3662
- value
3663
- }) => isArray(value) || isObject(value) ? '' : String(value);
3664
-
3665
- const type = 'textarea';
3666
- function Textarea(props) {
3667
- const {
3668
- disabled,
3669
- errors = [],
3670
- field,
3671
- value = ''
3672
- } = props;
3673
- const {
3674
- description,
3675
- id,
3676
- label,
3677
- validate = {}
3678
- } = field;
3679
- const {
3680
- required
3681
- } = validate;
3682
- const textareaRef = useRef();
3683
- const onInput = ({
3684
- target
3685
- }) => {
3686
- props.onChange({
3687
- field,
3688
- value: target.value
3689
- });
3690
- };
3691
- const autoSizeTextarea = useCallback(textarea => {
3692
- // Ensures the textarea shrinks back, and improves resizing behavior consistency
3693
- textarea.style.height = '0px';
3694
- const computed = window.getComputedStyle(textarea);
3695
- const calculatedHeight = parseInt(computed.getPropertyValue('border-top-width')) + parseInt(computed.getPropertyValue('padding-top')) + textarea.scrollHeight + parseInt(computed.getPropertyValue('padding-bottom')) + parseInt(computed.getPropertyValue('border-bottom-width'));
3696
- const minHeight = 75;
3697
- const maxHeight = 350;
3698
- const displayHeight = Math.max(Math.min(calculatedHeight, maxHeight), minHeight);
3699
- textarea.style.height = `${displayHeight}px`;
3700
-
3701
- // Overflow is hidden by default to hide scrollbar flickering
3702
- textarea.style.overflow = calculatedHeight > maxHeight ? 'visible' : 'hidden';
3703
- }, []);
3704
- useEffect(() => {
3705
- autoSizeTextarea(textareaRef.current);
3706
- }, [autoSizeTextarea, value]);
3707
- const {
3708
- formId
3709
- } = useContext(FormContext);
3710
- return jsxs("div", {
3711
- class: formFieldClasses(type, {
3712
- errors,
3713
- disabled
3714
- }),
3715
- children: [jsx(Label, {
3716
- id: prefixId(id, formId),
3717
- label: label,
3718
- required: required
3719
- }), jsx("textarea", {
3720
- class: "fjs-textarea",
3721
- disabled: disabled,
3722
- id: prefixId(id, formId),
3723
- onInput: onInput,
3724
- value: value,
3725
- ref: textareaRef
3726
- }), jsx(Description, {
3727
- description: description
3728
- }), jsx(Errors, {
3729
- errors: errors
3730
- })]
3731
- });
3732
- }
3733
- Textarea.create = function (options = {}) {
4012
+ const iconsByType = type => {
3734
4013
  return {
3735
- ...options
3736
- };
4014
+ button: ButtonIcon,
4015
+ checkbox: CheckboxIcon,
4016
+ checklist: ChecklistIcon,
4017
+ columns: ColumnsIcon,
4018
+ datetime: DatetimeIcon,
4019
+ image: ImageIcon,
4020
+ number: NumberIcon,
4021
+ radio: RadioIcon,
4022
+ select: SelectIcon,
4023
+ taglist: TaglistIcon,
4024
+ text: TextIcon,
4025
+ textfield: TextfieldIcon,
4026
+ textarea: TextareaIcon,
4027
+ default: FormIcon
4028
+ }[type];
3737
4029
  };
3738
- Textarea.type = type;
3739
- Textarea.label = 'Text area';
3740
- Textarea.keyed = true;
3741
- Textarea.emptyValue = '';
3742
- Textarea.sanitizeValue = ({
3743
- value
3744
- }) => isArray(value) || isObject(value) ? '' : String(value);
3745
4030
 
3746
4031
  const formFields = [Button, Checkbox, Checklist, Default, Image, Numberfield, Datetime, Radio, Select, Taglist, Text, Textfield, Textarea];
3747
4032
 
@@ -3749,10 +4034,7 @@ class FormFields {
3749
4034
  constructor() {
3750
4035
  this._formFields = {};
3751
4036
  formFields.forEach(formField => {
3752
- const {
3753
- type
3754
- } = formField;
3755
- this.register(type, formField);
4037
+ this.register(formField.type, formField);
3756
4038
  });
3757
4039
  }
3758
4040
  register(type, formField) {
@@ -3794,7 +4076,7 @@ function Renderer(config, eventBus, form, injector) {
3794
4076
  if (!schema) {
3795
4077
  return null;
3796
4078
  }
3797
- return jsx(FormContext.Provider, {
4079
+ return jsx(FormContext$1.Provider, {
3798
4080
  value: formContext,
3799
4081
  children: jsx(FormComponent, {
3800
4082
  onChange: onChange,
@@ -4195,7 +4477,7 @@ class Form {
4195
4477
  }
4196
4478
  }
4197
4479
 
4198
- const schemaVersion = 6;
4480
+ const schemaVersion = 7;
4199
4481
 
4200
4482
  /**
4201
4483
  * @typedef { import('./types').CreateFormOptions } CreateFormOptions
@@ -4220,5 +4502,5 @@ function createForm(options) {
4220
4502
  });
4221
4503
  }
4222
4504
 
4223
- export { Button, Checkbox, Checklist, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, Default, Form, FormComponent, FormContext, FormFieldRegistry, FormFields, FormRenderContext, Image, MINUTES_IN_DAY, Numberfield, Radio, Select, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Taglist, Text, Textarea, Textfield, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, VALUES_SOURCES_PATHS, VALUES_SOURCE_DEFAULT, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getSchemaVariables, getValuesSource, iconsByType, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
4505
+ export { Button, Checkbox, Checklist, DATETIME_SUBTYPES, DATETIME_SUBTYPES_LABELS, DATETIME_SUBTYPE_PATH, DATE_DISALLOW_PAST_PATH, DATE_LABEL_PATH, Datetime, Default, Form, FormComponent, FormContext$1 as FormContext, FormFieldRegistry, FormFields, FormRenderContext$1 as FormRenderContext, Image, MINUTES_IN_DAY, Numberfield, Radio, Select, TIME_INTERVAL_PATH, TIME_LABEL_PATH, TIME_SERIALISINGFORMAT_LABELS, TIME_SERIALISING_FORMATS, TIME_SERIALISING_FORMAT_PATH, TIME_USE24H_PATH, Taglist, Text, Textarea, Textfield, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_LABELS, VALUES_SOURCES_PATHS, VALUES_SOURCE_DEFAULT, clone, createForm, createFormContainer, createInjector, findErrors, formFields, generateIdForType, generateIndexForType, getExpressionVariableNames, getSchemaVariables, getValuesSource, getVariableNames, iconsByType, isExpression$1 as isExpression, isRequired, pathParse, pathStringify, pathsEqual, schemaVersion };
4224
4506
  //# sourceMappingURL=index.es.js.map