@bpmn-io/form-js-editor 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.
Files changed (48) hide show
  1. package/README.md +1 -0
  2. package/dist/assets/form-js-editor.css +8 -202
  3. package/dist/assets/properties-panel.css +930 -0
  4. package/dist/index.cjs +2777 -844
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.es.js +2781 -849
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/types/render/components/palette/icons/index.d.ts +2 -0
  9. package/dist/types/render/components/properties-panel/PropertiesPanel.d.ts +1 -1
  10. package/dist/types/render/components/properties-panel/PropertiesPanelHeaderProvider.d.ts +5 -0
  11. package/dist/types/render/components/properties-panel/PropertiesPanelPlaceholderProvider.d.ts +8 -0
  12. package/dist/types/render/components/properties-panel/Util.d.ts +1 -0
  13. package/dist/types/render/components/properties-panel/entries/ActionEntry.d.ts +9 -1
  14. package/dist/types/render/components/properties-panel/entries/ColumnsEntry.d.ts +9 -1
  15. package/dist/types/render/components/properties-panel/entries/CustomValueEntry.d.ts +11 -1
  16. package/dist/types/render/components/properties-panel/entries/DefaultValueEntry.d.ts +1 -1
  17. package/dist/types/render/components/properties-panel/entries/DescriptionEntry.d.ts +9 -1
  18. package/dist/types/render/components/properties-panel/entries/DisabledEntry.d.ts +9 -1
  19. package/dist/types/render/components/properties-panel/entries/IdEntry.d.ts +9 -1
  20. package/dist/types/render/components/properties-panel/entries/InputKeyValuesSourceEntry.d.ts +11 -0
  21. package/dist/types/render/components/properties-panel/entries/KeyEntry.d.ts +9 -1
  22. package/dist/types/render/components/properties-panel/entries/LabelEntry.d.ts +9 -1
  23. package/dist/types/render/components/properties-panel/entries/StaticValuesSourceEntry.d.ts +4 -0
  24. package/dist/types/render/components/properties-panel/entries/TextEntry.d.ts +9 -1
  25. package/dist/types/render/components/properties-panel/entries/ValueEntry.d.ts +11 -1
  26. package/dist/types/render/components/properties-panel/entries/ValuesSourceSelectEntry.d.ts +9 -0
  27. package/dist/types/render/components/properties-panel/entries/ValuesSourceUtil.d.ts +15 -0
  28. package/dist/types/render/components/properties-panel/entries/index.d.ts +3 -0
  29. package/dist/types/render/components/properties-panel/groups/CustomValuesGroup.d.ts +22 -1
  30. package/dist/types/render/components/properties-panel/groups/GeneralGroup.d.ts +5 -1
  31. package/dist/types/render/components/properties-panel/groups/ValidationGroup.d.ts +14 -1
  32. package/dist/types/render/components/properties-panel/groups/ValuesGroups.d.ts +1 -0
  33. package/dist/types/render/components/properties-panel/groups/index.d.ts +1 -1
  34. package/package.json +5 -4
  35. package/dist/types/render/components/properties-panel/components/CheckboxInput.d.ts +0 -1
  36. package/dist/types/render/components/properties-panel/components/CheckboxInputEntry.d.ts +0 -1
  37. package/dist/types/render/components/properties-panel/components/CollapsibleEntry.d.ts +0 -1
  38. package/dist/types/render/components/properties-panel/components/Group.d.ts +0 -1
  39. package/dist/types/render/components/properties-panel/components/NumberInput.d.ts +0 -1
  40. package/dist/types/render/components/properties-panel/components/NumberInputEntry.d.ts +0 -1
  41. package/dist/types/render/components/properties-panel/components/Select.d.ts +0 -1
  42. package/dist/types/render/components/properties-panel/components/SelectEntry.d.ts +0 -1
  43. package/dist/types/render/components/properties-panel/components/TextInput.d.ts +0 -1
  44. package/dist/types/render/components/properties-panel/components/TextInputEntry.d.ts +0 -1
  45. package/dist/types/render/components/properties-panel/components/Textarea.d.ts +0 -1
  46. package/dist/types/render/components/properties-panel/components/TextareaEntry.d.ts +0 -1
  47. package/dist/types/render/components/properties-panel/components/index.d.ts +0 -12
  48. package/dist/types/render/components/properties-panel/groups/ValuesGroup.d.ts +0 -1
package/dist/index.es.js CHANGED
@@ -1,17 +1,18 @@
1
1
  import { FormFieldRegistry as FormFieldRegistry$1, clone, Default, FormContext, FormRenderContext, FormComponent, FormFields, createFormContainer, createInjector, schemaVersion } from '@bpmn-io/form-js-viewer';
2
2
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
3
3
  import Ids from 'ids';
4
- import { isArray, isFunction, isNumber, bind, assign, debounce, get, isUndefined, set, has, forEach, isObject, uniqueBy, isString } from 'min-dash';
5
- import { createContext, render } from 'preact';
6
- import { useContext, useRef, useEffect, useMemo, useState, useCallback } from 'preact/hooks';
4
+ import { isArray, isFunction, isNumber, bind, assign, debounce, sortBy, find, get, set, isUndefined, without, has, forEach, isObject, uniqueBy, isString } from 'min-dash';
5
+ import { createContext, createElement, render } from 'preact';
6
+ import { useContext, useState, useEffect, useRef, useCallback, useMemo } from 'preact/hooks';
7
7
  import React from 'preact/compat';
8
- import { jsxs, jsx, Fragment } from 'preact/jsx-runtime';
8
+ import { jsxs, jsx } from 'preact/jsx-runtime';
9
+ import classnames from 'classnames';
10
+ import { query, matches, closest, event } from 'min-dom';
9
11
  import dragula from 'dragula';
10
- import { matches, closest, event } from 'min-dom';
11
12
  import { mutate } from 'array-move';
12
13
 
13
14
  var FN_REF = '__fn';
14
- var DEFAULT_PRIORITY$2 = 1000;
15
+ var DEFAULT_PRIORITY$3 = 1000;
15
16
  var slice = Array.prototype.slice;
16
17
  /**
17
18
  * A general purpose event bus.
@@ -127,7 +128,7 @@ EventBus.prototype.on = function (events, priority, callback, that) {
127
128
  if (isFunction(priority)) {
128
129
  that = callback;
129
130
  callback = priority;
130
- priority = DEFAULT_PRIORITY$2;
131
+ priority = DEFAULT_PRIORITY$3;
131
132
  }
132
133
 
133
134
  if (!isNumber(priority)) {
@@ -169,7 +170,7 @@ EventBus.prototype.once = function (event, priority, callback, that) {
169
170
  if (isFunction(priority)) {
170
171
  that = callback;
171
172
  callback = priority;
172
- priority = DEFAULT_PRIORITY$2;
173
+ priority = DEFAULT_PRIORITY$3;
173
174
  }
174
175
 
175
176
  if (!isNumber(priority)) {
@@ -765,11 +766,11 @@ function useService (type, strict) {
765
766
  return getService(type, strict);
766
767
  }
767
768
 
768
- function _extends$c() { _extends$c = 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$c.apply(this, arguments); }
769
+ function _extends$b() { _extends$b = 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$b.apply(this, arguments); }
769
770
  var ButtonIcon = (({
770
771
  styles = {},
771
772
  ...props
772
- }) => /*#__PURE__*/React.createElement("svg", _extends$c({
773
+ }) => /*#__PURE__*/React.createElement("svg", _extends$b({
773
774
  xmlns: "http://www.w3.org/2000/svg",
774
775
  width: "54",
775
776
  height: "54"
@@ -778,11 +779,11 @@ var ButtonIcon = (({
778
779
  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"
779
780
  })));
780
781
 
781
- function _extends$b() { _extends$b = 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$b.apply(this, arguments); }
782
+ function _extends$a() { _extends$a = 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$a.apply(this, arguments); }
782
783
  var CheckboxIcon = (({
783
784
  styles = {},
784
785
  ...props
785
- }) => /*#__PURE__*/React.createElement("svg", _extends$b({
786
+ }) => /*#__PURE__*/React.createElement("svg", _extends$a({
786
787
  xmlns: "http://www.w3.org/2000/svg",
787
788
  width: "54",
788
789
  height: "54"
@@ -790,11 +791,49 @@ var CheckboxIcon = (({
790
791
  d: "M34 18H20a2 2 0 00-2 2v14a2 2 0 002 2h14a2 2 0 002-2V20a2 2 0 00-2-2zm-9 14l-5-5 1.41-1.41L25 29.17l7.59-7.59L34 23l-9 9z"
791
792
  })));
792
793
 
793
- function _extends$a() { _extends$a = 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$a.apply(this, arguments); }
794
+ function _extends$9() { _extends$9 = 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$9.apply(this, arguments); }
795
+ var ChecklistIcon = (({
796
+ styles = {},
797
+ ...props
798
+ }) => /*#__PURE__*/React.createElement("svg", _extends$9({
799
+ width: "54",
800
+ height: "54",
801
+ fill: "none",
802
+ xmlns: "http://www.w3.org/2000/svg"
803
+ }, props), /*#__PURE__*/React.createElement("path", {
804
+ fillRule: "evenodd",
805
+ clipRule: "evenodd",
806
+ d: "M19 24h-6v6h6v-6zm-6-2a2 2 0 00-2 2v6a2 2 0 002 2h6a2 2 0 002-2v-6a2 2 0 00-2-2h-6zm6 18h-6v6h6v-6zm-6-2a2 2 0 00-2 2v6a2 2 0 002 2h6a2 2 0 002-2v-6a2 2 0 00-2-2h-6zm6-30h-6v6h6V8zm-6-2a2 2 0 00-2 2v6a2 2 0 002 2h6a2 2 0 002-2V8a2 2 0 00-2-2h-6z",
807
+ fill: "#22242A"
808
+ }), /*#__PURE__*/React.createElement("path", {
809
+ d: "M26 26a1 1 0 011-1h15a1 1 0 011 1v2a1 1 0 01-1 1H27a1 1 0 01-1-1v-2zm0 16a1 1 0 011-1h15a1 1 0 011 1v2a1 1 0 01-1 1H27a1 1 0 01-1-1v-2zm0-32a1 1 0 011-1h15a1 1 0 011 1v2a1 1 0 01-1 1H27a1 1 0 01-1-1v-2z",
810
+ fill: "#22242A"
811
+ })));
812
+
813
+ function _extends$8() { _extends$8 = 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$8.apply(this, arguments); }
814
+ var TaglistIcon = (({
815
+ styles = {},
816
+ ...props
817
+ }) => /*#__PURE__*/React.createElement("svg", _extends$8({
818
+ width: "54",
819
+ height: "54",
820
+ fill: "none",
821
+ xmlns: "http://www.w3.org/2000/svg"
822
+ }, props), /*#__PURE__*/React.createElement("path", {
823
+ fillRule: "evenodd",
824
+ clipRule: "evenodd",
825
+ d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1z",
826
+ fill: "#000"
827
+ }), /*#__PURE__*/React.createElement("path", {
828
+ d: "M11 22a1 1 0 011-1h19a1 1 0 011 1v10a1 1 0 01-1 1H12a1 1 0 01-1-1V22z",
829
+ fill: "#505562"
830
+ })));
831
+
832
+ function _extends$7() { _extends$7 = 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$7.apply(this, arguments); }
794
833
  var FormIcon = (({
795
834
  styles = {},
796
835
  ...props
797
- }) => /*#__PURE__*/React.createElement("svg", _extends$a({
836
+ }) => /*#__PURE__*/React.createElement("svg", _extends$7({
798
837
  xmlns: "http://www.w3.org/2000/svg",
799
838
  width: "54",
800
839
  height: "54"
@@ -818,11 +857,11 @@ var FormIcon = (({
818
857
  rx: "1"
819
858
  })));
820
859
 
821
- function _extends$9() { _extends$9 = 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$9.apply(this, arguments); }
860
+ function _extends$6() { _extends$6 = 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$6.apply(this, arguments); }
822
861
  var ColumnsIcon = (({
823
862
  styles = {},
824
863
  ...props
825
- }) => /*#__PURE__*/React.createElement("svg", _extends$9({
864
+ }) => /*#__PURE__*/React.createElement("svg", _extends$6({
826
865
  xmlns: "http://www.w3.org/2000/svg",
827
866
  width: "54",
828
867
  height: "54"
@@ -831,11 +870,11 @@ var ColumnsIcon = (({
831
870
  d: "M8 33v5a1 1 0 001 1h4v2H9a3 3 0 01-3-3v-5h2zm18 6v2H15v-2h11zm13 0v2H28v-2h11zm9-6v5a3 3 0 01-3 3h-4v-2h4a1 1 0 00.993-.883L46 38v-5h2zM8 22v9H6v-9h2zm40 0v9h-2v-9h2zm-35-9v2H9a1 1 0 00-.993.883L8 16v4H6v-4a3 3 0 013-3h4zm32 0a3 3 0 013 3v4h-2v-4a1 1 0 00-.883-.993L45 15h-4v-2h4zm-6 0v2H28v-2h11zm-13 0v2H15v-2h11z"
832
871
  })));
833
872
 
834
- function _extends$8() { _extends$8 = 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$8.apply(this, arguments); }
873
+ function _extends$5() { _extends$5 = 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$5.apply(this, arguments); }
835
874
  var NumberIcon = (({
836
875
  styles = {},
837
876
  ...props
838
- }) => /*#__PURE__*/React.createElement("svg", _extends$8({
877
+ }) => /*#__PURE__*/React.createElement("svg", _extends$5({
839
878
  xmlns: "http://www.w3.org/2000/svg",
840
879
  width: "54",
841
880
  height: "54"
@@ -844,11 +883,11 @@ var NumberIcon = (({
844
883
  d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1zM35 28.444h7l-3.5 4-3.5-4zM35 26h7l-3.5-4-3.5 4z"
845
884
  })));
846
885
 
847
- function _extends$7() { _extends$7 = 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$7.apply(this, arguments); }
886
+ function _extends$4() { _extends$4 = 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$4.apply(this, arguments); }
848
887
  var RadioIcon = (({
849
888
  styles = {},
850
889
  ...props
851
- }) => /*#__PURE__*/React.createElement("svg", _extends$7({
890
+ }) => /*#__PURE__*/React.createElement("svg", _extends$4({
852
891
  xmlns: "http://www.w3.org/2000/svg",
853
892
  width: "54",
854
893
  height: "54"
@@ -856,11 +895,11 @@ var RadioIcon = (({
856
895
  d: "M27 22c-2.76 0-5 2.24-5 5s2.24 5 5 5 5-2.24 5-5-2.24-5-5-5zm0-5c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm0 18c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8z"
857
896
  })));
858
897
 
859
- function _extends$6() { _extends$6 = 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$6.apply(this, arguments); }
898
+ function _extends$3() { _extends$3 = 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$3.apply(this, arguments); }
860
899
  var SelectIcon = (({
861
900
  styles = {},
862
901
  ...props
863
- }) => /*#__PURE__*/React.createElement("svg", _extends$6({
902
+ }) => /*#__PURE__*/React.createElement("svg", _extends$3({
864
903
  xmlns: "http://www.w3.org/2000/svg",
865
904
  width: "54",
866
905
  height: "54"
@@ -869,11 +908,11 @@ var SelectIcon = (({
869
908
  d: "M45 16a3 3 0 013 3v16a3 3 0 01-3 3H9a3 3 0 01-3-3V19a3 3 0 013-3h36zm0 2H9a1 1 0 00-1 1v16a1 1 0 001 1h36a1 1 0 001-1V19a1 1 0 00-1-1zm-12 7h9l-4.5 6-4.5-6z"
870
909
  })));
871
910
 
872
- function _extends$5() { _extends$5 = 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$5.apply(this, arguments); }
911
+ function _extends$2() { _extends$2 = 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$2.apply(this, arguments); }
873
912
  var TextIcon = (({
874
913
  styles = {},
875
914
  ...props
876
- }) => /*#__PURE__*/React.createElement("svg", _extends$5({
915
+ }) => /*#__PURE__*/React.createElement("svg", _extends$2({
877
916
  xmlns: "http://www.w3.org/2000/svg",
878
917
  width: "54",
879
918
  height: "54"
@@ -881,11 +920,11 @@ var TextIcon = (({
881
920
  d: "M20.58 33.77h-3l-1.18-3.08H11l-1.1 3.08H7l5.27-13.54h2.89zm-5-5.36l-1.86-5-1.83 5zM22 20.23h5.41a15.47 15.47 0 012.4.14 3.42 3.42 0 011.41.55 3.47 3.47 0 011 1.14 3 3 0 01.42 1.58 3.26 3.26 0 01-1.91 2.94 3.63 3.63 0 011.91 1.22 3.28 3.28 0 01.66 2 4 4 0 01-.43 1.8 3.63 3.63 0 01-1.09 1.4 3.89 3.89 0 01-1.83.65q-.69.07-3.3.09H22zm2.73 2.25v3.13h3.8a1.79 1.79 0 001.1-.49 1.41 1.41 0 00.41-1 1.49 1.49 0 00-.35-1 1.54 1.54 0 00-1-.48c-.27 0-1.05-.05-2.34-.05zm0 5.39v3.62h2.57a11.52 11.52 0 001.88-.09 1.65 1.65 0 001-.54 1.6 1.6 0 00.38-1.14 1.75 1.75 0 00-.29-1 1.69 1.69 0 00-.86-.62 9.28 9.28 0 00-2.41-.23zM44.35 28.79l2.65.84a5.94 5.94 0 01-2 3.29A5.74 5.74 0 0141.38 34a5.87 5.87 0 01-4.44-1.84 7.09 7.09 0 01-1.73-5A7.43 7.43 0 0137 21.87 6 6 0 0141.54 20a5.64 5.64 0 014 1.47A5.33 5.33 0 0147 24l-2.7.65a2.8 2.8 0 00-2.86-2.27A3.09 3.09 0 0039 23.42a5.31 5.31 0 00-.93 3.5 5.62 5.62 0 00.93 3.65 3 3 0 002.4 1.09 2.72 2.72 0 001.82-.66 4 4 0 001.13-2.21z"
882
921
  })));
883
922
 
884
- function _extends$4() { _extends$4 = 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$4.apply(this, arguments); }
923
+ function _extends$1() { _extends$1 = 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$1.apply(this, arguments); }
885
924
  var TextfieldIcon = (({
886
925
  styles = {},
887
926
  ...props
888
- }) => /*#__PURE__*/React.createElement("svg", _extends$4({
927
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
889
928
  xmlns: "http://www.w3.org/2000/svg",
890
929
  width: "54",
891
930
  height: "54"
@@ -897,10 +936,12 @@ var TextfieldIcon = (({
897
936
  const iconsByType = {
898
937
  button: ButtonIcon,
899
938
  checkbox: CheckboxIcon,
939
+ checklist: ChecklistIcon,
900
940
  columns: ColumnsIcon,
901
941
  number: NumberIcon,
902
942
  radio: RadioIcon,
903
943
  select: SelectIcon,
944
+ taglist: TaglistIcon,
904
945
  text: TextIcon,
905
946
  textfield: TextfieldIcon,
906
947
  default: FormIcon
@@ -915,6 +956,12 @@ const types = [{
915
956
  }, {
916
957
  label: 'Checkbox',
917
958
  type: 'checkbox'
959
+ }, {
960
+ label: 'Checklist',
961
+ type: 'checklist'
962
+ }, {
963
+ label: 'Taglist',
964
+ type: 'taglist'
918
965
  }, {
919
966
  label: 'Radio',
920
967
  type: 'radio'
@@ -964,564 +1011,1763 @@ function Palette(props) {
964
1011
  });
965
1012
  }
966
1013
 
967
- function arrayAdd$1(array, index, item) {
968
- const copy = [...array];
969
- copy.splice(index, 0, item);
970
- return copy;
971
- }
972
- function arrayRemove$1(array, index) {
973
- const copy = [...array];
974
- copy.splice(index, 1);
975
- return copy;
976
- }
977
- function prefixId(id) {
978
- return `fjs-properties-panel-${id}`;
979
- }
980
- function stopPropagation(listener) {
981
- return event => {
982
- event.stopPropagation();
983
- listener(event);
984
- };
985
- }
986
- function textToLabel(text = '...') {
987
- if (text.length > 10) {
988
- return `${text.substring(0, 30)}...`;
989
- }
1014
+ var ArrowIcon = function ArrowIcon(props) {
1015
+ return jsx("svg", { ...props,
1016
+ children: jsx("path", {
1017
+ fillRule: "evenodd",
1018
+ d: "m11.657 8-4.95 4.95a1 1 0 0 1-1.414-1.414L8.828 8 5.293 4.464A1 1 0 1 1 6.707 3.05L11.657 8z"
1019
+ })
1020
+ });
1021
+ };
990
1022
 
991
- return text;
992
- }
993
- const INPUTS = ['checkbox', 'number', 'radio', 'select', 'textfield'];
1023
+ ArrowIcon.defaultProps = {
1024
+ xmlns: "http://www.w3.org/2000/svg",
1025
+ width: "16",
1026
+ height: "16"
1027
+ };
994
1028
 
995
- function CheckboxInput(props) {
996
- const {
997
- id,
998
- label,
999
- onChange,
1000
- value = false
1001
- } = props;
1029
+ var CreateIcon = function CreateIcon(props) {
1030
+ return jsx("svg", { ...props,
1031
+ children: jsx("path", {
1032
+ fillRule: "evenodd",
1033
+ d: "M9 13V9h4a1 1 0 0 0 0-2H9V3a1 1 0 1 0-2 0v4H3a1 1 0 1 0 0 2h4v4a1 1 0 0 0 2 0z"
1034
+ })
1035
+ });
1036
+ };
1002
1037
 
1003
- const handleChange = ({
1004
- target
1005
- }) => {
1006
- onChange(target.checked);
1007
- };
1038
+ CreateIcon.defaultProps = {
1039
+ xmlns: "http://www.w3.org/2000/svg",
1040
+ width: "16",
1041
+ height: "16"
1042
+ };
1008
1043
 
1009
- return jsxs("div", {
1010
- class: "fjs-properties-panel-checkbox",
1011
- children: [jsx("label", {
1012
- for: prefixId(id),
1013
- class: "fjs-properties-panel-label",
1014
- children: label
1015
- }), jsx("input", {
1016
- id: prefixId(id),
1017
- type: "checkbox",
1018
- class: "fjs-properties-panel-input",
1019
- onChange: handleChange,
1020
- checked: value
1021
- })]
1044
+ var DeleteIcon = function DeleteIcon(props) {
1045
+ return jsx("svg", { ...props,
1046
+ children: jsx("path", {
1047
+ fillRule: "evenodd",
1048
+ d: "M12 6v7c0 1.1-.4 1.55-1.5 1.55h-5C4.4 14.55 4 14.1 4 13V6h8zm-1.5 1.5h-5v4.3c0 .66.5 1.2 1.111 1.2H9.39c.611 0 1.111-.54 1.111-1.2V7.5zM13 3h-2l-1-1H6L5 3H3v1.5h10V3z"
1049
+ })
1022
1050
  });
1023
- }
1024
-
1025
- function usePrevious(value) {
1026
- const ref = useRef();
1027
- useEffect(() => ref.current = value);
1028
- return ref.current;
1029
- }
1051
+ };
1030
1052
 
1031
- function useDebounce(fn, dependencies = []) {
1032
- const debounce = useService('debounce');
1033
- const callback = useMemo(() => {
1034
- return debounce(fn);
1035
- }, dependencies); // cleanup async side-effect if callback #flush is provided.
1053
+ DeleteIcon.defaultProps = {
1054
+ xmlns: "http://www.w3.org/2000/svg",
1055
+ width: "16",
1056
+ height: "16"
1057
+ };
1036
1058
 
1037
- useEffect(() => {
1038
- return () => {
1039
- typeof callback.flush === 'function' && callback.flush();
1040
- };
1041
- }, [callback]);
1042
- return callback;
1043
- }
1059
+ var ExternalLinkIcon = function ExternalLinkIcon(props) {
1060
+ return jsx("svg", { ...props,
1061
+ children: jsx("path", {
1062
+ fillRule: "evenodd",
1063
+ clipRule: "evenodd",
1064
+ d: "M12.637 12.637v-4.72h1.362v4.721c0 .36-.137.676-.411.95-.275.275-.591.412-.95.412H3.362c-.38 0-.703-.132-.967-.396A1.315 1.315 0 0 1 2 12.638V3.362c0-.38.132-.703.396-.967S2.982 2 3.363 2h4.553v1.363H3.363v9.274h9.274zM14 2H9.28l-.001 1.362h2.408L5.065 9.984l.95.95 6.622-6.622v2.409H14V2z",
1065
+ fill: "#818798"
1066
+ })
1067
+ });
1068
+ };
1044
1069
 
1045
- function NumberInput(props) {
1046
- const {
1047
- id,
1048
- label,
1049
- max,
1050
- min,
1051
- value = '',
1052
- onInput: _onInput
1053
- } = props;
1054
- const onInput = useDebounce(event => {
1055
- const {
1056
- validity,
1057
- value
1058
- } = event.target;
1070
+ ExternalLinkIcon.defaultProps = {
1071
+ width: "16",
1072
+ height: "16",
1073
+ fill: "none",
1074
+ xmlns: "http://www.w3.org/2000/svg"
1075
+ };
1059
1076
 
1060
- if (validity.valid) {
1061
- _onInput(value ? parseInt(value, 10) : undefined);
1062
- }
1063
- }, [_onInput]);
1064
- return jsxs("div", {
1065
- class: "fjs-properties-panel-number",
1066
- children: [jsx("label", {
1067
- for: prefixId(id),
1068
- class: "fjs-properties-panel-label",
1069
- children: label
1070
- }), jsx("input", {
1071
- id: prefixId(id),
1072
- type: "number",
1073
- class: "fjs-properties-panel-input",
1074
- max: max,
1075
- min: min,
1076
- onInput: onInput,
1077
- value: value
1077
+ var FeelRequiredIcon = function FeelRequiredIcon(props) {
1078
+ return jsxs("svg", { ...props,
1079
+ children: [jsx("path", {
1080
+ d: "M5.8 7.06V5.95h4.307v1.11H5.8zm0 3.071v-1.11h4.307v1.11H5.8z",
1081
+ fill: "#505562"
1082
+ }), jsx("path", {
1083
+ fillRule: "evenodd",
1084
+ clipRule: "evenodd",
1085
+ d: "M8 3.268A4.732 4.732 0 1 0 12.732 8H14a6 6 0 1 1-6-6v1.268z",
1086
+ fill: "#505562"
1087
+ }), jsx("path", {
1088
+ d: "m11.28 6.072-.832-.56 1.016-1.224L10 3.848l.312-.912 1.392.584L11.632 2h1.032l-.072 1.52 1.392-.584.312.912-1.464.44 1.008 1.224-.832.552-.864-1.296-.864 1.304z",
1089
+ fill: "#505562"
1078
1090
  })]
1079
1091
  });
1080
- }
1081
-
1082
- function Select(props) {
1083
- const {
1084
- id,
1085
- label,
1086
- onChange,
1087
- options,
1088
- value
1089
- } = props;
1092
+ };
1090
1093
 
1091
- const handleChange = ({
1092
- target
1093
- }) => {
1094
- onChange(target.value);
1095
- };
1094
+ FeelRequiredIcon.defaultProps = {
1095
+ viewBox: "0 0 16 16",
1096
+ fill: "none",
1097
+ xmlns: "http://www.w3.org/2000/svg"
1098
+ };
1096
1099
 
1097
- return jsxs("div", {
1098
- class: "fjs-properties-panel-select",
1099
- children: [jsx("label", {
1100
- for: prefixId(id),
1101
- class: "fjs-properties-panel-label",
1102
- children: label
1103
- }), jsx("select", {
1104
- id: prefixId(id),
1105
- class: "fjs-properties-panel-input",
1106
- onInput: handleChange,
1107
- children: options.map(option => {
1108
- return jsx("option", {
1109
- value: option.value,
1110
- selected: option.value === value,
1111
- children: option.label
1112
- });
1113
- })
1100
+ var FeelOptionalIcon = function FeelOptionalIcon(props) {
1101
+ return jsxs("svg", { ...props,
1102
+ children: [jsx("path", {
1103
+ d: "M5.845 7.04V5.93h4.307v1.11H5.845zm0 3.07V9h4.307v1.11H5.845z",
1104
+ fill: "#505562"
1105
+ }), jsx("path", {
1106
+ fillRule: "evenodd",
1107
+ clipRule: "evenodd",
1108
+ d: "M3.286 8a4.714 4.714 0 1 0 9.428 0 4.714 4.714 0 0 0-9.428 0zM8 2a6 6 0 1 0 0 12A6 6 0 0 0 8 2z",
1109
+ fill: "#505562"
1114
1110
  })]
1115
1111
  });
1116
- }
1112
+ };
1117
1113
 
1118
- function Textarea(props) {
1114
+ FeelOptionalIcon.defaultProps = {
1115
+ viewBox: "0 0 16 16",
1116
+ fill: "none",
1117
+ xmlns: "http://www.w3.org/2000/svg"
1118
+ };
1119
+
1120
+ function Header(props) {
1119
1121
  const {
1120
- id,
1121
- label,
1122
- rows = 10,
1123
- value = '',
1124
- onInput: _onInput
1122
+ element,
1123
+ headerProvider
1125
1124
  } = props;
1126
- const onInput = useDebounce(event => {
1127
- const value = event.target.value;
1128
-
1129
- _onInput(value.length ? value : undefined);
1130
- }, [_onInput]);
1125
+ const {
1126
+ getElementIcon,
1127
+ getDocumentationRef,
1128
+ getElementLabel,
1129
+ getTypeLabel
1130
+ } = headerProvider;
1131
+ const label = getElementLabel(element);
1132
+ const type = getTypeLabel(element);
1133
+ const documentationRef = getDocumentationRef && getDocumentationRef(element);
1134
+ const ElementIcon = getElementIcon(element);
1131
1135
  return jsxs("div", {
1132
- class: "fjs-properties-panel-textarea",
1133
- children: [jsx("label", {
1134
- for: prefixId(id),
1135
- class: "fjs-properties-panel-label",
1136
- children: label
1137
- }), jsx("textarea", {
1138
- id: prefixId(id),
1139
- spellcheck: false,
1140
- class: "fjs-properties-panel-input",
1141
- onInput: onInput,
1142
- rows: rows,
1143
- value: value
1136
+ class: "bio-properties-panel-header",
1137
+ children: [jsx("div", {
1138
+ class: "bio-properties-panel-header-icon",
1139
+ children: ElementIcon && jsx(ElementIcon, {
1140
+ width: "32",
1141
+ height: "32",
1142
+ viewBox: "0 0 32 32"
1143
+ })
1144
+ }), jsxs("div", {
1145
+ class: "bio-properties-panel-header-labels",
1146
+ children: [jsx("div", {
1147
+ title: type,
1148
+ class: "bio-properties-panel-header-type",
1149
+ children: type
1150
+ }), label ? jsx("div", {
1151
+ title: label,
1152
+ class: "bio-properties-panel-header-label",
1153
+ children: label
1154
+ }) : null]
1155
+ }), jsx("div", {
1156
+ class: "bio-properties-panel-header-actions",
1157
+ children: documentationRef ? jsx("a", {
1158
+ rel: "noopener",
1159
+ class: "bio-properties-panel-header-link",
1160
+ href: documentationRef,
1161
+ title: "Open documentation",
1162
+ target: "_blank",
1163
+ children: jsx(ExternalLinkIcon, {})
1164
+ }) : null
1144
1165
  })]
1145
1166
  });
1146
1167
  }
1147
1168
 
1148
- function TextInput(props) {
1149
- let {
1150
- id,
1151
- label,
1152
- validate = () => null,
1153
- onInput: _onInput,
1154
- value = ''
1155
- } = props;
1156
- const prevValue = usePrevious(value);
1157
- const [cachedValue, setCachedValue] = useState(null);
1158
- const [error, setError] = useState(null);
1159
- useEffect(() => setError(validate(value)), [validate, value]);
1160
- const onInput = useDebounce(event => {
1161
- const value = event.target.value;
1162
- const error = validate(value);
1163
-
1164
- if (error) {
1165
- setCachedValue(value);
1166
- } else {
1167
- _onInput(value.length ? value : undefined);
1168
- }
1169
+ const DescriptionContext = createContext({
1170
+ description: {},
1171
+ getDescriptionForId: () => {}
1172
+ });
1173
+ /**
1174
+ * @typedef {Function} <propertiesPanel.showEntry> callback
1175
+ *
1176
+ * @example
1177
+ *
1178
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
1179
+ * // ...
1180
+ * });
1181
+ *
1182
+ * @param {Object} context
1183
+ * @param {boolean} [context.focus]
1184
+ *
1185
+ * @returns void
1186
+ */
1169
1187
 
1170
- setError(error);
1171
- }, [validate, setCachedValue, _onInput]);
1188
+ const EventContext = createContext({
1189
+ eventBus: null
1190
+ });
1191
+ const LayoutContext = createContext({
1192
+ layout: {},
1193
+ setLayout: () => {},
1194
+ getLayoutForKey: () => {},
1195
+ setLayoutForKey: () => {}
1196
+ });
1197
+ /**
1198
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
1199
+ *
1200
+ * @example
1201
+ * ```jsx
1202
+ * function TextField(props) {
1203
+ * const description = useDescriptionContext('input1', element);
1204
+ * }
1205
+ * ```
1206
+ *
1207
+ * @param {string} id
1208
+ * @param {object} element
1209
+ *
1210
+ * @returns {string}
1211
+ */
1172
1212
 
1173
- if (prevValue === value && error) {
1174
- value = cachedValue;
1175
- }
1213
+ function useDescriptionContext(id, element) {
1214
+ const {
1215
+ getDescriptionForId
1216
+ } = useContext(DescriptionContext);
1217
+ return getDescriptionForId(id, element);
1218
+ }
1176
1219
 
1177
- const classes = ['fjs-properties-panel-input'];
1220
+ const DEFAULT_PRIORITY$2 = 1000;
1221
+ /**
1222
+ * Subscribe to an event.
1223
+ *
1224
+ * @param {string} event
1225
+ * @param {Function} callback
1226
+ * @param {number} [priority]
1227
+ *
1228
+ * @returns {import('preact').Ref}
1229
+ */
1178
1230
 
1179
- if (error) {
1180
- classes.push('fjs-has-error');
1181
- }
1231
+ function useEvent(event, callback, priority = DEFAULT_PRIORITY$2) {
1232
+ const {
1233
+ eventBus
1234
+ } = useContext(EventContext);
1235
+ useEffect(() => {
1236
+ if (!eventBus) {
1237
+ return;
1238
+ }
1182
1239
 
1183
- return jsxs("div", {
1184
- class: "fjs-properties-panel-text",
1185
- children: [jsx("label", {
1186
- for: prefixId(id),
1187
- class: "fjs-properties-panel-label",
1188
- children: label
1189
- }), jsx("input", {
1190
- id: prefixId(id),
1191
- type: "text",
1192
- spellcheck: false,
1193
- class: classes.join(' '),
1194
- onInput: onInput,
1195
- value: value
1196
- }), error && jsx("div", {
1197
- class: "fjs-properties-panel-error",
1198
- children: error
1199
- })]
1200
- });
1240
+ eventBus.on(event, priority, callback);
1241
+ return () => eventBus.off(event, callback);
1242
+ }, [callback, event, eventBus, priority]);
1201
1243
  }
1202
1244
 
1203
- function CheckboxInputEntry(props) {
1204
- const {
1205
- editField,
1206
- field,
1207
- id,
1208
- label,
1209
- path
1210
- } = props;
1245
+ const HIGH_PRIORITY = 10000;
1246
+ /**
1247
+ * Buffer events and re-fire during passive effect phase.
1248
+ *
1249
+ * @param {string[]} bufferedEvents
1250
+ * @param {Object} [eventBus]
1251
+ */
1211
1252
 
1212
- const onChange = value => {
1213
- if (editField && path) {
1214
- editField(field, path, value);
1215
- } else {
1216
- props.onChange(value);
1253
+ function useEventBuffer(bufferedEvents, eventBus) {
1254
+ const buffer = useRef([]),
1255
+ buffering = useRef(true);
1256
+
1257
+ const createCallback = event => data => {
1258
+ if (buffering.current === true) {
1259
+ buffer.current.unshift([event, data]);
1217
1260
  }
1218
- };
1261
+ }; // (1) buffer events
1219
1262
 
1220
- const value = path ? get(field, path, false) : props.value;
1221
- return jsx("div", {
1222
- class: "fjs-properties-panel-entry",
1223
- children: jsx(CheckboxInput, {
1224
- id: id,
1225
- label: label,
1226
- onChange: onChange,
1227
- value: value
1228
- })
1229
- });
1230
- }
1231
1263
 
1232
- function NumberInputEntry(props) {
1233
- const {
1234
- editField,
1235
- field,
1236
- id,
1264
+ useEffect(() => {
1265
+ if (!eventBus) {
1266
+ return;
1267
+ }
1268
+
1269
+ const listeners = bufferedEvents.map(event => {
1270
+ return [event, createCallback(event)];
1271
+ });
1272
+ listeners.forEach(([event, callback]) => {
1273
+ eventBus.on(event, HIGH_PRIORITY, callback);
1274
+ });
1275
+ return () => {
1276
+ listeners.forEach(([event, callback]) => {
1277
+ eventBus.off(event, callback);
1278
+ });
1279
+ };
1280
+ }, [bufferedEvents, eventBus]); // (2) re-fire events
1281
+
1282
+ useEffect(() => {
1283
+ if (!eventBus) {
1284
+ return;
1285
+ }
1286
+
1287
+ buffering.current = false;
1288
+
1289
+ while (buffer.current.length) {
1290
+ const [event, data] = buffer.current.pop();
1291
+ eventBus.fire(event, data);
1292
+ }
1293
+
1294
+ buffering.current = true;
1295
+ });
1296
+ }
1297
+ /**
1298
+ * Creates a state that persists in the global LayoutContext.
1299
+ *
1300
+ * @example
1301
+ * ```jsx
1302
+ * function Group(props) {
1303
+ * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
1304
+ * }
1305
+ * ```
1306
+ *
1307
+ * @param {(string|number)[]} path
1308
+ * @param {any} [defaultValue]
1309
+ *
1310
+ * @returns {[ any, Function ]}
1311
+ */
1312
+
1313
+
1314
+ function useLayoutState(path, defaultValue) {
1315
+ const {
1316
+ getLayoutForKey,
1317
+ setLayoutForKey
1318
+ } = useContext(LayoutContext);
1319
+ const layoutForKey = getLayoutForKey(path, defaultValue);
1320
+ const [value, set] = useState(layoutForKey);
1321
+
1322
+ const setState = newValue => {
1323
+ // (1) set component state
1324
+ set(newValue); // (2) set context
1325
+
1326
+ setLayoutForKey(path, newValue);
1327
+ };
1328
+
1329
+ return [value, setState];
1330
+ }
1331
+ /**
1332
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
1333
+ * state on updates.
1334
+ *
1335
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
1336
+ */
1337
+
1338
+
1339
+ function usePrevious(value) {
1340
+ const ref = useRef();
1341
+ useEffect(() => {
1342
+ ref.current = value;
1343
+ });
1344
+ return ref.current;
1345
+ }
1346
+ /**
1347
+ * Subscribe to `propertiesPanel.showEntry`.
1348
+ *
1349
+ * @param {Function} show
1350
+ *
1351
+ * @returns {import('preact').Ref}
1352
+ */
1353
+
1354
+
1355
+ function useShowEntryEvent(show) {
1356
+ const {
1357
+ onShow
1358
+ } = useContext(LayoutContext);
1359
+ const ref = useRef();
1360
+ const [focus, setFocus] = useState(false);
1361
+ const onShowEntry = useCallback(event => {
1362
+ if (show(event)) {
1363
+ if (isFunction(onShow)) {
1364
+ onShow();
1365
+ }
1366
+
1367
+ if (event.focus && !focus) {
1368
+ setFocus(true);
1369
+ }
1370
+ }
1371
+ }, [show]);
1372
+ useEffect(() => {
1373
+ if (focus && ref.current) {
1374
+ if (isFunction(ref.current.focus)) {
1375
+ ref.current.focus();
1376
+ }
1377
+
1378
+ if (isFunction(ref.current.select)) {
1379
+ ref.current.select();
1380
+ }
1381
+
1382
+ setFocus(false);
1383
+ }
1384
+ }, [focus]);
1385
+ useEvent('propertiesPanel.showEntry', onShowEntry);
1386
+ return ref;
1387
+ }
1388
+ /**
1389
+ * Subscribe to `propertiesPanel.showError`. On `propertiesPanel.showError` set
1390
+ * temporary error. Fire `propertiesPanel.showEntry` for temporary error to be
1391
+ * visible. Unset error on `propertiesPanel.updated`.
1392
+ *
1393
+ * @param {Function} show
1394
+ *
1395
+ * @returns {import('preact').Ref}
1396
+ */
1397
+
1398
+
1399
+ function useShowErrorEvent(show) {
1400
+ const {
1401
+ eventBus
1402
+ } = useContext(EventContext);
1403
+ const [temporaryError, setTemporaryError] = useState(null);
1404
+ const onPropertiesPanelUpdated = useCallback(() => setTemporaryError(null), []);
1405
+ useEvent('propertiesPanel.updated', onPropertiesPanelUpdated);
1406
+ const onShowError = useCallback(event => {
1407
+ setTemporaryError(null);
1408
+
1409
+ if (show(event)) {
1410
+ if (eventBus) {
1411
+ eventBus.fire('propertiesPanel.showEntry', event);
1412
+ }
1413
+
1414
+ setTemporaryError(event.message);
1415
+ }
1416
+ }, [show]);
1417
+ useEvent('propertiesPanel.showError', onShowError);
1418
+ return temporaryError;
1419
+ }
1420
+ /**
1421
+ * @callback setSticky
1422
+ * @param {boolean} value
1423
+ */
1424
+
1425
+ /**
1426
+ * Use IntersectionObserver to identify when DOM element is in sticky mode.
1427
+ * If sticky is observered setSticky(true) will be called.
1428
+ * If sticky mode is left, setSticky(false) will be called.
1429
+ *
1430
+ *
1431
+ * @param {Object} ref
1432
+ * @param {string} scrollContainerSelector
1433
+ * @param {setSticky} setSticky
1434
+ */
1435
+
1436
+
1437
+ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
1438
+ useEffect(() => {
1439
+ // return early if IntersectionObserver is not available
1440
+ if (!IntersectionObserver) {
1441
+ return;
1442
+ }
1443
+
1444
+ let observer;
1445
+
1446
+ if (ref.current) {
1447
+ const scrollContainer = query(scrollContainerSelector);
1448
+ observer = new IntersectionObserver(entries => {
1449
+ if (entries[0].intersectionRatio < 1) {
1450
+ setSticky(true);
1451
+ } else if (entries[0].intersectionRatio === 1) {
1452
+ setSticky(false);
1453
+ }
1454
+ }, {
1455
+ root: scrollContainer,
1456
+ rootMargin: '0px 0px 999999% 0px',
1457
+ // Use bottom margin to avoid stickyness when scrolling out to bottom
1458
+ threshold: [1]
1459
+ });
1460
+ observer.observe(ref.current);
1461
+ } // Unobserve if unmounted
1462
+
1463
+
1464
+ return () => {
1465
+ if (ref.current && observer) {
1466
+ observer.unobserve(ref.current);
1467
+ }
1468
+ };
1469
+ }, [ref]);
1470
+ }
1471
+
1472
+ function Group(props) {
1473
+ const {
1474
+ element,
1475
+ entries = [],
1476
+ id,
1477
+ label,
1478
+ shouldOpen = false
1479
+ } = props;
1480
+ const groupRef = useRef(null);
1481
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
1482
+ const onShow = useCallback(() => setOpen(true), [setOpen]);
1483
+
1484
+ const toggleOpen = () => setOpen(!open);
1485
+
1486
+ const [edited, setEdited] = useState(false);
1487
+ const [sticky, setSticky] = useState(false); // set edited state depending on all entries
1488
+
1489
+ useEffect(() => {
1490
+ const hasOneEditedEntry = entries.find(entry => {
1491
+ const {
1492
+ id,
1493
+ isEdited
1494
+ } = entry;
1495
+ const entryNode = query(`[data-entry-id="${id}"]`);
1496
+
1497
+ if (!isFunction(isEdited) || !entryNode) {
1498
+ return false;
1499
+ }
1500
+
1501
+ const inputNode = query('.bio-properties-panel-input', entryNode);
1502
+ return isEdited(inputNode);
1503
+ });
1504
+ setEdited(hasOneEditedEntry);
1505
+ }, [entries]); // set css class when group is sticky to top
1506
+
1507
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
1508
+ const propertiesPanelContext = { ...useContext(LayoutContext),
1509
+ onShow
1510
+ };
1511
+ return jsxs("div", {
1512
+ class: "bio-properties-panel-group",
1513
+ "data-group-id": 'group-' + id,
1514
+ ref: groupRef,
1515
+ children: [jsxs("div", {
1516
+ class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
1517
+ onClick: toggleOpen,
1518
+ children: [jsx("div", {
1519
+ title: label,
1520
+ class: "bio-properties-panel-group-header-title",
1521
+ children: label
1522
+ }), jsxs("div", {
1523
+ class: "bio-properties-panel-group-header-buttons",
1524
+ children: [edited && jsx(DataMarker, {}), jsx("button", {
1525
+ title: "Toggle section",
1526
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
1527
+ children: jsx(ArrowIcon, {
1528
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1529
+ })
1530
+ })]
1531
+ })]
1532
+ }), jsx("div", {
1533
+ class: classnames('bio-properties-panel-group-entries', open ? 'open' : ''),
1534
+ children: jsx(LayoutContext.Provider, {
1535
+ value: propertiesPanelContext,
1536
+ children: entries.map(entry => {
1537
+ const {
1538
+ component: Component,
1539
+ id
1540
+ } = entry;
1541
+ return createElement(Component, { ...entry,
1542
+ element: element,
1543
+ key: id
1544
+ });
1545
+ })
1546
+ })
1547
+ })]
1548
+ });
1549
+ }
1550
+
1551
+ function DataMarker() {
1552
+ return jsx("div", {
1553
+ title: "Section contains data",
1554
+ class: "bio-properties-panel-dot"
1555
+ });
1556
+ }
1557
+ /**
1558
+ * @typedef { {
1559
+ * text: (element: object) => string,
1560
+ * icon?: (element: Object) => import('preact').Component
1561
+ * } } PlaceholderDefinition
1562
+ *
1563
+ * @param { PlaceholderDefinition } props
1564
+ */
1565
+
1566
+
1567
+ function Placeholder(props) {
1568
+ const {
1569
+ text,
1570
+ icon: Icon
1571
+ } = props;
1572
+ return jsx("div", {
1573
+ class: "bio-properties-panel open",
1574
+ children: jsxs("section", {
1575
+ class: "bio-properties-panel-placeholder",
1576
+ children: [Icon && jsx(Icon, {
1577
+ class: "bio-properties-panel-placeholder-icon"
1578
+ }), jsx("p", {
1579
+ class: "bio-properties-panel-placeholder-text",
1580
+ children: text
1581
+ })]
1582
+ })
1583
+ });
1584
+ }
1585
+
1586
+ const DEFAULT_LAYOUT = {
1587
+ open: true
1588
+ };
1589
+ const DEFAULT_DESCRIPTION = {};
1590
+ const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'];
1591
+ /**
1592
+ * @typedef { {
1593
+ * component: import('preact').Component,
1594
+ * id: String,
1595
+ * isEdited?: Function
1596
+ * } } EntryDefinition
1597
+ *
1598
+ * @typedef { {
1599
+ * autoFocusEntry: String,
1600
+ * autoOpen?: Boolean,
1601
+ * entries: Array<EntryDefinition>,
1602
+ * id: String,
1603
+ * label: String,
1604
+ * remove: (event: MouseEvent) => void
1605
+ * } } ListItemDefinition
1606
+ *
1607
+ * @typedef { {
1608
+ * add: (event: MouseEvent) => void,
1609
+ * component: import('preact').Component,
1610
+ * element: Object,
1611
+ * id: String,
1612
+ * items: Array<ListItemDefinition>,
1613
+ * label: String,
1614
+ * shouldSort?: Boolean,
1615
+ * shouldOpen?: Boolean
1616
+ * } } ListGroupDefinition
1617
+ *
1618
+ * @typedef { {
1619
+ * component?: import('preact').Component,
1620
+ * entries: Array<EntryDefinition>,
1621
+ * id: String,
1622
+ * label: String,
1623
+ * shouldOpen?: Boolean
1624
+ * } } GroupDefinition
1625
+ *
1626
+ * @typedef { {
1627
+ * [id: String]: GetDescriptionFunction
1628
+ * } } DescriptionConfig
1629
+ *
1630
+ * @callback { {
1631
+ * @param {string} id
1632
+ * @param {Object} element
1633
+ * @returns {string}
1634
+ * } } GetDescriptionFunction
1635
+ *
1636
+ * @typedef { {
1637
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
1638
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
1639
+ * } } PlaceholderProvider
1640
+ *
1641
+ */
1642
+
1643
+ /**
1644
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
1645
+ * data from implementor to describe *what* will be rendered.
1646
+ *
1647
+ * @param {Object} props
1648
+ * @param {Object|Array} props.element
1649
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
1650
+ * @param {PlaceholderProvider} [props.placeholderProvider]
1651
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
1652
+ * @param {Object} [props.layoutConfig]
1653
+ * @param {Function} [props.layoutChanged]
1654
+ * @param {DescriptionConfig} [props.descriptionConfig]
1655
+ * @param {Function} [props.descriptionLoaded]
1656
+ * @param {Object} [props.eventBus]
1657
+ */
1658
+
1659
+ function PropertiesPanel(props) {
1660
+ const {
1661
+ element,
1662
+ headerProvider,
1663
+ placeholderProvider,
1664
+ groups,
1665
+ layoutConfig = {},
1666
+ layoutChanged,
1667
+ descriptionConfig = {},
1668
+ descriptionLoaded,
1669
+ eventBus
1670
+ } = props; // set-up layout context
1671
+
1672
+ const [layout, setLayout] = useState(createLayout(layoutConfig));
1673
+ useEffect(() => {
1674
+ if (typeof layoutChanged === 'function') {
1675
+ layoutChanged(layout);
1676
+ }
1677
+ }, [layout, layoutChanged]);
1678
+
1679
+ const getLayoutForKey = (key, defaultValue) => {
1680
+ return get(layout, key, defaultValue);
1681
+ };
1682
+
1683
+ const setLayoutForKey = (key, config) => {
1684
+ const newLayout = assign({}, layout);
1685
+ set(newLayout, key, config);
1686
+ setLayout(newLayout);
1687
+ };
1688
+
1689
+ const layoutContext = {
1690
+ layout,
1691
+ setLayout,
1692
+ getLayoutForKey,
1693
+ setLayoutForKey
1694
+ }; // set-up description context
1695
+
1696
+ const description = createDescriptionContext(descriptionConfig);
1697
+
1698
+ if (typeof descriptionLoaded === 'function') {
1699
+ descriptionLoaded(description);
1700
+ }
1701
+
1702
+ const getDescriptionForId = (id, element) => {
1703
+ return description[id] && description[id](element);
1704
+ };
1705
+
1706
+ const descriptionContext = {
1707
+ description,
1708
+ getDescriptionForId
1709
+ };
1710
+ useEventBuffer(bufferedEvents, eventBus);
1711
+ const eventContext = {
1712
+ eventBus
1713
+ };
1714
+ const propertiesPanelContext = {
1715
+ element
1716
+ }; // empty state
1717
+
1718
+ if (placeholderProvider && !element) {
1719
+ return jsx(Placeholder, { ...placeholderProvider.getEmpty()
1720
+ });
1721
+ } // multiple state
1722
+
1723
+
1724
+ if (placeholderProvider && isArray(element)) {
1725
+ return jsx(Placeholder, { ...placeholderProvider.getMultiple()
1726
+ });
1727
+ }
1728
+
1729
+ return jsx(LayoutContext.Provider, {
1730
+ value: propertiesPanelContext,
1731
+ children: jsx(DescriptionContext.Provider, {
1732
+ value: descriptionContext,
1733
+ children: jsx(LayoutContext.Provider, {
1734
+ value: layoutContext,
1735
+ children: jsx(EventContext.Provider, {
1736
+ value: eventContext,
1737
+ children: jsxs("div", {
1738
+ class: classnames('bio-properties-panel', layout.open ? 'open' : ''),
1739
+ children: [jsx(Header, {
1740
+ element: element,
1741
+ headerProvider: headerProvider
1742
+ }), jsx("div", {
1743
+ class: "bio-properties-panel-scroll-container",
1744
+ children: groups.map(group => {
1745
+ const {
1746
+ component: Component = Group,
1747
+ id
1748
+ } = group;
1749
+ return createElement(Component, { ...group,
1750
+ key: id,
1751
+ element: element
1752
+ });
1753
+ })
1754
+ })]
1755
+ })
1756
+ })
1757
+ })
1758
+ })
1759
+ });
1760
+ } // helpers //////////////////
1761
+
1762
+
1763
+ function createLayout(overrides) {
1764
+ return { ...DEFAULT_LAYOUT,
1765
+ ...overrides
1766
+ };
1767
+ }
1768
+
1769
+ function createDescriptionContext(overrides) {
1770
+ return { ...DEFAULT_DESCRIPTION,
1771
+ ...overrides
1772
+ };
1773
+ }
1774
+
1775
+ function CollapsibleEntry(props) {
1776
+ const {
1777
+ element,
1778
+ entries = [],
1779
+ id,
1780
+ label,
1781
+ open: shouldOpen,
1782
+ remove
1783
+ } = props;
1784
+ const [open, setOpen] = useState(shouldOpen);
1785
+
1786
+ const toggleOpen = () => setOpen(!open);
1787
+
1788
+ const {
1789
+ onShow
1790
+ } = useContext(LayoutContext);
1791
+ const propertiesPanelContext = { ...useContext(LayoutContext),
1792
+ onShow: useCallback(() => {
1793
+ setOpen(true);
1794
+
1795
+ if (isFunction(onShow)) {
1796
+ onShow();
1797
+ }
1798
+ }, [onShow, setOpen])
1799
+ }; // todo(pinussilvestrus): translate once we have a translate mechanism for the core
1800
+
1801
+ const placeholderLabel = '<empty>';
1802
+ return jsxs("div", {
1803
+ "data-entry-id": id,
1804
+ class: classnames('bio-properties-panel-collapsible-entry', open ? 'open' : ''),
1805
+ children: [jsxs("div", {
1806
+ class: "bio-properties-panel-collapsible-entry-header",
1807
+ onClick: toggleOpen,
1808
+ children: [jsx("div", {
1809
+ title: label || placeholderLabel,
1810
+ class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
1811
+ children: label || placeholderLabel
1812
+ }), jsx("button", {
1813
+ title: "Toggle list item",
1814
+ class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
1815
+ children: jsx(ArrowIcon, {
1816
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1817
+ })
1818
+ }), remove ? jsx("button", {
1819
+ title: "Delete item",
1820
+ class: "bio-properties-panel-remove-entry",
1821
+ onClick: remove,
1822
+ children: jsx(DeleteIcon, {})
1823
+ }) : null]
1824
+ }), jsx("div", {
1825
+ class: classnames('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
1826
+ children: jsx(LayoutContext.Provider, {
1827
+ value: propertiesPanelContext,
1828
+ children: entries.map(entry => {
1829
+ const {
1830
+ component: Component,
1831
+ id
1832
+ } = entry;
1833
+ return createElement(Component, { ...entry,
1834
+ element: element,
1835
+ key: id
1836
+ });
1837
+ })
1838
+ })
1839
+ })]
1840
+ });
1841
+ }
1842
+
1843
+ function ListItem(props) {
1844
+ const {
1845
+ autoFocusEntry,
1846
+ autoOpen
1847
+ } = props; // focus specified entry on auto open
1848
+
1849
+ useEffect(() => {
1850
+ if (autoOpen && autoFocusEntry) {
1851
+ const entry = query(`[data-entry-id="${autoFocusEntry}"]`);
1852
+ const focusableInput = query('.bio-properties-panel-input', entry);
1853
+
1854
+ if (focusableInput) {
1855
+ if (isFunction(focusableInput.select)) {
1856
+ focusableInput.select();
1857
+ } else if (isFunction(focusableInput.focus)) {
1858
+ focusableInput.focus();
1859
+ }
1860
+ }
1861
+ }
1862
+ }, [autoOpen, autoFocusEntry]);
1863
+ return jsx("div", {
1864
+ class: "bio-properties-panel-list-item",
1865
+ children: jsx(CollapsibleEntry, { ...props,
1866
+ open: autoOpen
1867
+ })
1868
+ });
1869
+ }
1870
+
1871
+ const noop$3 = () => {};
1872
+ /**
1873
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
1874
+ */
1875
+
1876
+
1877
+ function ListGroup(props) {
1878
+ const {
1879
+ add,
1880
+ element,
1881
+ id,
1882
+ items,
1883
+ label,
1884
+ shouldOpen = true,
1885
+ shouldSort = true
1886
+ } = props;
1887
+ const groupRef = useRef(null);
1888
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
1889
+ const [sticky, setSticky] = useState(false);
1890
+ const onShow = useCallback(() => setOpen(true), [setOpen]);
1891
+ const [ordering, setOrdering] = useState([]);
1892
+ const [newItemAdded, setNewItemAdded] = useState(false);
1893
+ const prevItems = usePrevious(items);
1894
+ const prevElement = usePrevious(element);
1895
+ const elementChanged = element !== prevElement;
1896
+ const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen); // reset initial ordering when element changes (before first render)
1897
+
1898
+ if (elementChanged) {
1899
+ setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
1900
+ } // keep ordering in sync to items - and open changes
1901
+ // (0) set initial ordering from given items
1902
+
1903
+
1904
+ useEffect(() => {
1905
+ if (!prevItems || !shouldSort) {
1906
+ setOrdering(createOrdering(items));
1907
+ }
1908
+ }, [items, element]); // (1) items were added
1909
+
1910
+ useEffect(() => {
1911
+ if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
1912
+ let add = [];
1913
+ items.forEach(item => {
1914
+ if (!ordering.includes(item.id)) {
1915
+ add.push(item.id);
1916
+ }
1917
+ });
1918
+ let newOrdering = ordering; // open if not open and configured
1919
+
1920
+ if (!open && shouldOpen) {
1921
+ toggleOpen(); // if I opened and I should sort, then sort items
1922
+
1923
+ if (shouldSort) {
1924
+ newOrdering = createOrdering(sortItems(items));
1925
+ }
1926
+ } // add new items on top or bottom depending on sorting behavior
1927
+
1928
+
1929
+ newOrdering = newOrdering.filter(item => !add.includes(item));
1930
+
1931
+ if (shouldSort) {
1932
+ newOrdering.unshift(...add);
1933
+ } else {
1934
+ newOrdering.push(...add);
1935
+ }
1936
+
1937
+ setOrdering(newOrdering);
1938
+ setNewItemAdded(true);
1939
+ } else {
1940
+ setNewItemAdded(false);
1941
+ }
1942
+ }, [items, open, shouldHandleEffects]); // (2) sort items on open if shouldSort is set
1943
+
1944
+ useEffect(() => {
1945
+ if (shouldSort && open && !newItemAdded) {
1946
+ setOrdering(createOrdering(sortItems(items)));
1947
+ }
1948
+ }, [open, shouldSort]); // (3) items were deleted
1949
+
1950
+ useEffect(() => {
1951
+ if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
1952
+ let keep = [];
1953
+ ordering.forEach(o => {
1954
+ if (getItem(items, o)) {
1955
+ keep.push(o);
1956
+ }
1957
+ });
1958
+ setOrdering(keep);
1959
+ }
1960
+ }, [items, shouldHandleEffects]); // set css class when group is sticky to top
1961
+
1962
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
1963
+
1964
+ const toggleOpen = () => setOpen(!open);
1965
+
1966
+ const hasItems = !!items.length;
1967
+ const propertiesPanelContext = { ...useContext(LayoutContext),
1968
+ onShow
1969
+ };
1970
+ return jsxs("div", {
1971
+ class: "bio-properties-panel-group",
1972
+ "data-group-id": 'group-' + id,
1973
+ ref: groupRef,
1974
+ children: [jsxs("div", {
1975
+ class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
1976
+ onClick: hasItems ? toggleOpen : noop$3,
1977
+ children: [jsx("div", {
1978
+ title: label,
1979
+ class: "bio-properties-panel-group-header-title",
1980
+ children: label
1981
+ }), jsxs("div", {
1982
+ class: "bio-properties-panel-group-header-buttons",
1983
+ children: [add ? jsxs("button", {
1984
+ title: "Create new list item",
1985
+ class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
1986
+ onClick: add,
1987
+ children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
1988
+ class: "bio-properties-panel-add-entry-label",
1989
+ children: "Create"
1990
+ }) : null]
1991
+ }) : null, hasItems ? jsx("div", {
1992
+ title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
1993
+ class: "bio-properties-panel-list-badge",
1994
+ children: items.length
1995
+ }) : null, hasItems ? jsx("button", {
1996
+ title: "Toggle section",
1997
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
1998
+ children: jsx(ArrowIcon, {
1999
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
2000
+ })
2001
+ }) : null]
2002
+ })]
2003
+ }), jsx("div", {
2004
+ class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
2005
+ children: jsx(LayoutContext.Provider, {
2006
+ value: propertiesPanelContext,
2007
+ children: ordering.map((o, index) => {
2008
+ const item = getItem(items, o);
2009
+
2010
+ if (!item) {
2011
+ return;
2012
+ }
2013
+
2014
+ const {
2015
+ id
2016
+ } = item; // if item was added, open first or last item based on ordering
2017
+
2018
+ const autoOpen = newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1);
2019
+ return createElement(ListItem, { ...item,
2020
+ autoOpen: autoOpen,
2021
+ element: element,
2022
+ index: index,
2023
+ key: id
2024
+ });
2025
+ })
2026
+ })
2027
+ })]
2028
+ });
2029
+ } // helpers ////////////////////
2030
+
2031
+ /**
2032
+ * Sorts given items alphanumeric by label
2033
+ */
2034
+
2035
+
2036
+ function sortItems(items) {
2037
+ return sortBy(items, i => i.label.toLowerCase());
2038
+ }
2039
+
2040
+ function getItem(items, id) {
2041
+ return find(items, i => i.id === id);
2042
+ }
2043
+
2044
+ function createOrdering(items) {
2045
+ return items.map(i => i.id);
2046
+ }
2047
+
2048
+ function Description$1(props) {
2049
+ const {
2050
+ element,
2051
+ forId,
2052
+ value
2053
+ } = props;
2054
+ const contextDescription = useDescriptionContext(forId, element);
2055
+ const description = value || contextDescription;
2056
+
2057
+ if (description) {
2058
+ return jsx("div", {
2059
+ class: "bio-properties-panel-description",
2060
+ children: description
2061
+ });
2062
+ }
2063
+ }
2064
+
2065
+ const noop$2 = () => {};
2066
+
2067
+ function Checkbox(props) {
2068
+ const {
2069
+ id,
2070
+ label,
2071
+ onChange,
2072
+ disabled,
2073
+ value = false,
2074
+ show = noop$2
2075
+ } = props;
2076
+
2077
+ const handleChange = ({
2078
+ target
2079
+ }) => {
2080
+ onChange(target.checked);
2081
+ };
2082
+
2083
+ const ref = useShowEntryEvent(show);
2084
+ return jsxs("div", {
2085
+ class: "bio-properties-panel-checkbox",
2086
+ children: [jsx("input", {
2087
+ ref: ref,
2088
+ id: prefixId$6(id),
2089
+ name: id,
2090
+ type: "checkbox",
2091
+ class: "bio-properties-panel-input",
2092
+ onChange: handleChange,
2093
+ checked: value,
2094
+ disabled: disabled
2095
+ }), jsx("label", {
2096
+ for: prefixId$6(id),
2097
+ class: "bio-properties-panel-label",
2098
+ children: label
2099
+ })]
2100
+ });
2101
+ }
2102
+ /**
2103
+ * @param {Object} props
2104
+ * @param {Object} props.element
2105
+ * @param {String} props.id
2106
+ * @param {String} props.description
2107
+ * @param {String} props.label
2108
+ * @param {Function} props.getValue
2109
+ * @param {Function} props.setValue
2110
+ * @param {boolean} [props.disabled]
2111
+ */
2112
+
2113
+
2114
+ function CheckboxEntry(props) {
2115
+ const {
2116
+ element,
2117
+ id,
2118
+ description,
2119
+ label,
2120
+ getValue,
2121
+ setValue,
2122
+ disabled,
2123
+ show = noop$2
2124
+ } = props;
2125
+ const value = getValue(element);
2126
+ const error = useShowErrorEvent(show);
2127
+ return jsxs("div", {
2128
+ class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
2129
+ "data-entry-id": id,
2130
+ children: [jsx(Checkbox, {
2131
+ disabled: disabled,
2132
+ id: id,
2133
+ label: label,
2134
+ onChange: setValue,
2135
+ show: show,
2136
+ value: value
2137
+ }), error && jsx("div", {
2138
+ class: "bio-properties-panel-error",
2139
+ children: error
2140
+ }), jsx(Description$1, {
2141
+ forId: id,
2142
+ element: element,
2143
+ value: description
2144
+ })]
2145
+ });
2146
+ }
2147
+
2148
+ function isEdited$6(node) {
2149
+ return node && !!node.checked;
2150
+ } // helpers /////////////////
2151
+
2152
+
2153
+ function prefixId$6(id) {
2154
+ return `bio-properties-panel-${id}`;
2155
+ }
2156
+
2157
+ function NumberField(props) {
2158
+ const {
2159
+ debounce,
2160
+ disabled,
2161
+ id,
1237
2162
  label,
1238
2163
  max,
1239
2164
  min,
1240
- onChange,
1241
- path
2165
+ onInput,
2166
+ step,
2167
+ value = ''
1242
2168
  } = props;
2169
+ const handleInput = useMemo(() => {
2170
+ return debounce(event => {
2171
+ const {
2172
+ validity,
2173
+ value
2174
+ } = event.target;
1243
2175
 
1244
- const onInput = value => {
1245
- if (editField && path) {
1246
- editField(field, path, value);
1247
- } else {
1248
- onChange(value);
1249
- }
1250
- };
2176
+ if (validity.valid) {
2177
+ onInput(value ? parseFloat(value) : undefined);
2178
+ }
2179
+ });
2180
+ }, [onInput, debounce]);
2181
+ return jsxs("div", {
2182
+ class: "bio-properties-panel-numberfield",
2183
+ children: [jsx("label", {
2184
+ for: prefixId$5(id),
2185
+ class: "bio-properties-panel-label",
2186
+ children: label
2187
+ }), jsx("input", {
2188
+ id: prefixId$5(id),
2189
+ type: "number",
2190
+ name: id,
2191
+ spellCheck: "false",
2192
+ autoComplete: "off",
2193
+ disabled: disabled,
2194
+ class: "bio-properties-panel-input",
2195
+ max: max,
2196
+ min: min,
2197
+ onInput: handleInput,
2198
+ step: step,
2199
+ value: value
2200
+ })]
2201
+ });
2202
+ }
2203
+ /**
2204
+ * @param {Object} props
2205
+ * @param {Boolean} props.debounce
2206
+ * @param {String} props.description
2207
+ * @param {Boolean} props.disabled
2208
+ * @param {Object} props.element
2209
+ * @param {Function} props.getValue
2210
+ * @param {String} props.id
2211
+ * @param {String} props.label
2212
+ * @param {String} props.max
2213
+ * @param {String} props.min
2214
+ * @param {Function} props.setValue
2215
+ * @param {String} props.step
2216
+ */
1251
2217
 
1252
- const value = path ? get(field, path, '') : props.value;
1253
- return jsx("div", {
1254
- class: "fjs-properties-panel-entry",
1255
- children: jsx(NumberInput, {
2218
+
2219
+ function NumberFieldEntry(props) {
2220
+ const {
2221
+ debounce,
2222
+ description,
2223
+ disabled,
2224
+ element,
2225
+ getValue,
2226
+ id,
2227
+ label,
2228
+ max,
2229
+ min,
2230
+ setValue,
2231
+ step
2232
+ } = props;
2233
+ const value = getValue(element);
2234
+ return jsxs("div", {
2235
+ class: "bio-properties-panel-entry",
2236
+ "data-entry-id": id,
2237
+ children: [jsx(NumberField, {
2238
+ debounce: debounce,
2239
+ disabled: disabled,
1256
2240
  id: id,
1257
2241
  label: label,
2242
+ onInput: setValue,
1258
2243
  max: max,
1259
2244
  min: min,
1260
- onInput: onInput,
2245
+ step: step,
1261
2246
  value: value
1262
- })
2247
+ }), jsx(Description$1, {
2248
+ forId: id,
2249
+ element: element,
2250
+ value: description
2251
+ })]
1263
2252
  });
1264
2253
  }
1265
2254
 
1266
- function SelectEntry(props) {
2255
+ function isEdited$5(node) {
2256
+ return node && !!node.value;
2257
+ } // helpers /////////////////
2258
+
2259
+
2260
+ function prefixId$5(id) {
2261
+ return `bio-properties-panel-${id}`;
2262
+ }
2263
+
2264
+ const noop$1 = () => {};
2265
+ /**
2266
+ * @typedef { { value: string, label: string, disabled: boolean } } Option
2267
+ */
2268
+
2269
+ /**
2270
+ * Provides basic select input.
2271
+ *
2272
+ * @param {object} props
2273
+ * @param {string} props.id
2274
+ * @param {string[]} props.path
2275
+ * @param {string} props.label
2276
+ * @param {Function} props.onChange
2277
+ * @param {Array<Option>} [props.options]
2278
+ * @param {string} props.value
2279
+ * @param {boolean} [props.disabled]
2280
+ */
2281
+
2282
+
2283
+ function Select(props) {
1267
2284
  const {
1268
- editField,
1269
- field,
1270
2285
  id,
1271
- description,
1272
2286
  label,
1273
- options,
1274
- path
2287
+ onChange,
2288
+ options = [],
2289
+ value,
2290
+ disabled,
2291
+ show = noop$1
1275
2292
  } = props;
2293
+ const ref = useShowEntryEvent(show);
1276
2294
 
1277
- const onChange = value => {
1278
- if (editField && path) {
1279
- editField(field, path, value);
1280
- } else {
1281
- props.onChange(value);
1282
- }
2295
+ const handleChange = ({
2296
+ target
2297
+ }) => {
2298
+ onChange(target.value);
1283
2299
  };
1284
2300
 
1285
- const value = path ? get(field, path, '') : props.value;
1286
2301
  return jsxs("div", {
1287
- class: "fjs-properties-panel-entry",
2302
+ class: "bio-properties-panel-select",
2303
+ children: [jsx("label", {
2304
+ for: prefixId$4(id),
2305
+ class: "bio-properties-panel-label",
2306
+ children: label
2307
+ }), jsx("select", {
2308
+ ref: ref,
2309
+ id: prefixId$4(id),
2310
+ name: id,
2311
+ class: "bio-properties-panel-input",
2312
+ onInput: handleChange,
2313
+ value: value,
2314
+ disabled: disabled,
2315
+ children: options.map((option, idx) => {
2316
+ return jsx("option", {
2317
+ value: option.value,
2318
+ disabled: option.disabled,
2319
+ children: option.label
2320
+ }, idx);
2321
+ })
2322
+ })]
2323
+ });
2324
+ }
2325
+ /**
2326
+ * @param {object} props
2327
+ * @param {object} props.element
2328
+ * @param {string} props.id
2329
+ * @param {string} [props.description]
2330
+ * @param {string} props.label
2331
+ * @param {Function} props.getValue
2332
+ * @param {Function} props.setValue
2333
+ * @param {Function} props.getOptions
2334
+ * @param {boolean} [props.disabled]
2335
+ */
2336
+
2337
+
2338
+ function SelectEntry(props) {
2339
+ const {
2340
+ element,
2341
+ id,
2342
+ description,
2343
+ label,
2344
+ getValue,
2345
+ setValue,
2346
+ getOptions,
2347
+ disabled,
2348
+ show = noop$1
2349
+ } = props;
2350
+ const value = getValue(element);
2351
+ const options = getOptions(element);
2352
+ const error = useShowErrorEvent(show);
2353
+ return jsxs("div", {
2354
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
2355
+ "data-entry-id": id,
1288
2356
  children: [jsx(Select, {
1289
2357
  id: id,
1290
2358
  label: label,
1291
- onChange: onChange,
2359
+ value: value,
2360
+ onChange: setValue,
1292
2361
  options: options,
1293
- value: value
1294
- }), description && jsx("div", {
1295
- class: "fjs-properties-panel-description",
1296
- children: description
2362
+ disabled: disabled,
2363
+ show: show
2364
+ }), error && jsx("div", {
2365
+ class: "bio-properties-panel-error",
2366
+ children: error
2367
+ }), jsx(Description$1, {
2368
+ forId: id,
2369
+ element: element,
2370
+ value: description
1297
2371
  })]
1298
2372
  });
1299
2373
  }
1300
2374
 
1301
- function TextareaEntry(props) {
2375
+ function isEdited$4(node) {
2376
+ return node && !!node.value;
2377
+ } // helpers /////////////////
2378
+
2379
+
2380
+ function prefixId$4(id) {
2381
+ return `bio-properties-panel-${id}`;
2382
+ }
2383
+
2384
+ function FeelIcon(props) {
2385
+ const {
2386
+ label,
2387
+ feel = false
2388
+ } = props;
2389
+ const feelRequiredLabel = ' must be a FEEL expression';
2390
+ const feelOptionalLabel = ' can optionally be a FEEL expression';
2391
+ return jsx("i", {
2392
+ class: "bio-properties-panel-feel-icon",
2393
+ title: label + (feel === 'required' ? feelRequiredLabel : feelOptionalLabel),
2394
+ children: feel === 'required' ? jsx(FeelRequiredIcon, {}) : jsx(FeelOptionalIcon, {})
2395
+ });
2396
+ }
2397
+
2398
+ function TextArea(props) {
1302
2399
  const {
1303
- editField,
1304
- field,
1305
2400
  id,
1306
- description,
1307
2401
  label,
1308
- onChange,
1309
- path
2402
+ rows = 2,
2403
+ debounce,
2404
+ feel,
2405
+ onInput,
2406
+ value = '',
2407
+ disabled,
2408
+ monospace
1310
2409
  } = props;
2410
+ const handleInput = useMemo(() => {
2411
+ return debounce(({
2412
+ target
2413
+ }) => onInput(target.value.length ? target.value : undefined));
2414
+ }, [onInput, debounce]);
2415
+ return jsxs("div", {
2416
+ class: "bio-properties-panel-textarea",
2417
+ children: [jsxs("label", {
2418
+ for: prefixId$2(id),
2419
+ class: "bio-properties-panel-label",
2420
+ children: [label, feel && jsx(FeelIcon, {
2421
+ feel: feel,
2422
+ label: label
2423
+ })]
2424
+ }), jsx("textarea", {
2425
+ id: prefixId$2(id),
2426
+ name: id,
2427
+ spellCheck: "false",
2428
+ class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : ''),
2429
+ onInput: handleInput,
2430
+ onFocus: props.onFocus,
2431
+ onBlur: props.onBlur,
2432
+ rows: rows,
2433
+ value: value,
2434
+ disabled: disabled
2435
+ })]
2436
+ });
2437
+ }
2438
+ /**
2439
+ * @param {object} props
2440
+ * @param {object} props.element
2441
+ * @param {string} props.id
2442
+ * @param {string} props.description
2443
+ * @param {boolean} props.debounce
2444
+ * @param {string} props.label
2445
+ * @param {Function} props.getValue
2446
+ * @param {Function} props.setValue
2447
+ * @param {number} props.rows
2448
+ * @param {boolean} props.monospace
2449
+ * @param {boolean} [props.disabled]
2450
+ */
1311
2451
 
1312
- const onInput = value => {
1313
- if (editField && path) {
1314
- editField(field, path, value);
1315
- } else {
1316
- onChange(value);
1317
- }
1318
- };
1319
2452
 
1320
- const value = path ? get(field, path, '') : props.value;
2453
+ function TextAreaEntry(props) {
2454
+ const {
2455
+ element,
2456
+ id,
2457
+ description,
2458
+ debounce,
2459
+ feel,
2460
+ label,
2461
+ getValue,
2462
+ setValue,
2463
+ rows,
2464
+ monospace,
2465
+ disabled
2466
+ } = props;
2467
+ const value = getValue(element);
1321
2468
  return jsxs("div", {
1322
- class: "fjs-properties-panel-entry",
1323
- children: [jsx(Textarea, {
2469
+ class: "bio-properties-panel-entry",
2470
+ "data-entry-id": id,
2471
+ children: [jsx(TextArea, {
1324
2472
  id: id,
1325
2473
  label: label,
1326
- onInput: onInput,
1327
- value: value
1328
- }), description && jsx("div", {
1329
- class: "fjs-properties-panel-description",
1330
- children: description
2474
+ value: value,
2475
+ onInput: setValue,
2476
+ rows: rows,
2477
+ debounce: debounce,
2478
+ monospace: monospace,
2479
+ feel: feel,
2480
+ disabled: disabled
2481
+ }), jsx(Description$1, {
2482
+ forId: id,
2483
+ element: element,
2484
+ value: description
2485
+ })]
2486
+ });
2487
+ }
2488
+
2489
+ function isEdited$2(node) {
2490
+ return node && !!node.value;
2491
+ } // helpers /////////////////
2492
+
2493
+
2494
+ function prefixId$2(id) {
2495
+ return `bio-properties-panel-${id}`;
2496
+ }
2497
+
2498
+ const noop = () => {};
2499
+
2500
+ function Textfield(props) {
2501
+ const {
2502
+ debounce,
2503
+ disabled = false,
2504
+ id,
2505
+ label,
2506
+ onInput,
2507
+ feel = false,
2508
+ value = '',
2509
+ show = noop
2510
+ } = props;
2511
+ const ref = useShowEntryEvent(show);
2512
+ const handleInput = useMemo(() => {
2513
+ return debounce(({
2514
+ target
2515
+ }) => onInput(target.value.length ? target.value : undefined));
2516
+ }, [onInput, debounce]);
2517
+ return jsxs("div", {
2518
+ class: "bio-properties-panel-textfield",
2519
+ children: [jsxs("label", {
2520
+ for: prefixId$1(id),
2521
+ class: "bio-properties-panel-label",
2522
+ children: [label, feel && jsx(FeelIcon, {
2523
+ feel: feel,
2524
+ label: label
2525
+ })]
2526
+ }), jsx("input", {
2527
+ ref: ref,
2528
+ id: prefixId$1(id),
2529
+ type: "text",
2530
+ name: id,
2531
+ spellCheck: "false",
2532
+ autoComplete: "off",
2533
+ disabled: disabled,
2534
+ class: "bio-properties-panel-input",
2535
+ onInput: handleInput,
2536
+ onFocus: props.onFocus,
2537
+ onBlur: props.onBlur,
2538
+ value: value || ''
1331
2539
  })]
1332
2540
  });
1333
2541
  }
2542
+ /**
2543
+ * @param {Object} props
2544
+ * @param {Object} props.element
2545
+ * @param {String} props.id
2546
+ * @param {String} props.description
2547
+ * @param {Boolean} props.debounce
2548
+ * @param {Boolean} props.disabled
2549
+ * @param {String} props.label
2550
+ * @param {Function} props.getValue
2551
+ * @param {Function} props.setValue
2552
+ * @param {Function} props.validate
2553
+ */
2554
+
1334
2555
 
1335
- function TextInputEntry(props) {
2556
+ function TextfieldEntry(props) {
1336
2557
  const {
1337
- editField,
1338
- field,
2558
+ element,
1339
2559
  id,
1340
2560
  description,
2561
+ debounce,
2562
+ disabled,
2563
+ feel,
1341
2564
  label,
1342
- onChange,
1343
- path,
1344
- validate
2565
+ getValue,
2566
+ setValue,
2567
+ validate,
2568
+ show = noop
1345
2569
  } = props;
2570
+ const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
2571
+ const [validationError, setValidationError] = useState(null);
2572
+ let value = getValue(element);
2573
+ const previousValue = usePrevious(value);
2574
+ useEffect(() => {
2575
+ if (isFunction(validate)) {
2576
+ const newValidationError = validate(value) || null;
2577
+ setValidationError(newValidationError);
2578
+ }
2579
+ }, [value]);
2580
+
2581
+ const onInput = newValue => {
2582
+ let newValidationError = null;
2583
+
2584
+ if (isFunction(validate)) {
2585
+ newValidationError = validate(newValue) || null;
2586
+ }
1346
2587
 
1347
- const onInput = value => {
1348
- if (editField && path) {
1349
- editField(field, path, value);
2588
+ if (newValidationError) {
2589
+ setCachedInvalidValue(newValue);
1350
2590
  } else {
1351
- onChange(value);
2591
+ setValue(newValue);
1352
2592
  }
2593
+
2594
+ setValidationError(newValidationError);
1353
2595
  };
1354
2596
 
1355
- const value = path ? get(field, path, '') : props.value;
2597
+ if (previousValue === value && validationError) {
2598
+ value = cachedInvalidValue;
2599
+ }
2600
+
2601
+ const temporaryError = useShowErrorEvent(show);
2602
+ const error = temporaryError || validationError;
1356
2603
  return jsxs("div", {
1357
- class: "fjs-properties-panel-entry",
1358
- children: [jsx(TextInput, {
2604
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
2605
+ "data-entry-id": id,
2606
+ children: [jsx(Textfield, {
2607
+ debounce: debounce,
2608
+ disabled: disabled,
2609
+ feel: feel,
1359
2610
  id: id,
1360
2611
  label: label,
1361
2612
  onInput: onInput,
1362
- validate: validate,
2613
+ show: show,
1363
2614
  value: value
1364
- }), description && jsx("div", {
1365
- class: "fjs-properties-panel-description",
1366
- children: description
2615
+ }), error && jsx("div", {
2616
+ class: "bio-properties-panel-error",
2617
+ children: error
2618
+ }), jsx(Description$1, {
2619
+ forId: id,
2620
+ element: element,
2621
+ value: description
1367
2622
  })]
1368
2623
  });
1369
2624
  }
1370
2625
 
1371
- function _extends$3() { _extends$3 = 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$3.apply(this, arguments); }
1372
- var CreateIcon = (({
1373
- styles = {},
1374
- ...props
1375
- }) => /*#__PURE__*/React.createElement("svg", _extends$3({
1376
- xmlns: "http://www.w3.org/2000/svg",
1377
- width: "12",
1378
- height: "12"
1379
- }, props), /*#__PURE__*/React.createElement("path", {
1380
- fillRule: "evenodd",
1381
- d: "M7 0v5h5v2H7v5H5V7H0V5h5V0h2z"
1382
- })));
2626
+ function isEdited$1(node) {
2627
+ return node && !!node.value;
2628
+ } // helpers /////////////////
1383
2629
 
1384
- function _extends$2() { _extends$2 = 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$2.apply(this, arguments); }
1385
- var ListArrowIcon = (({
1386
- styles = {},
1387
- ...props
1388
- }) => /*#__PURE__*/React.createElement("svg", _extends$2({
1389
- xmlns: "http://www.w3.org/2000/svg",
1390
- width: "7",
1391
- height: "9"
1392
- }, props), /*#__PURE__*/React.createElement("path", {
1393
- fillRule: "evenodd",
1394
- d: "M6.25 4.421L4.836 5.835h-.001L2.007 8.663.593 7.249 3.421 4.42.593 1.593 2.007.178 6.25 4.421z"
1395
- })));
1396
2630
 
1397
- function _extends$1() { _extends$1 = 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$1.apply(this, arguments); }
1398
- var ListDeleteIcon = (({
1399
- styles = {},
1400
- ...props
1401
- }) => /*#__PURE__*/React.createElement("svg", _extends$1({
1402
- xmlns: "http://www.w3.org/2000/svg",
1403
- width: "11",
1404
- height: "14"
1405
- }, props), /*#__PURE__*/React.createElement("path", {
1406
- d: "M10 4v8c0 1.1-.9 2-2 2H3c-1.1 0-2-.9-2-2V4h9zM8 6H3v4.8c0 .66.5 1.2 1.111 1.2H6.89C7.5 12 8 11.46 8 10.8V6zm3-5H8.5l-1-1h-4l-1 1H0v1.5h11V1z"
1407
- })));
2631
+ function prefixId$1(id) {
2632
+ return `bio-properties-panel-${id}`;
2633
+ }
1408
2634
 
1409
- 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); }
1410
- var SectionArrowIcon = (({
1411
- styles = {},
1412
- ...props
1413
- }) => /*#__PURE__*/React.createElement("svg", _extends({
1414
- xmlns: "http://www.w3.org/2000/svg",
1415
- width: "8",
1416
- height: "12"
1417
- }, props), /*#__PURE__*/React.createElement("path", {
1418
- fillRule: "evenodd",
1419
- d: "M2.007 11.66L.593 10.248l4.242-4.243L.593 1.761 2.007.347l5.657 5.657-5.657 5.657z"
1420
- })));
2635
+ function arrayAdd$1(array, index, item) {
2636
+ const copy = [...array];
2637
+ copy.splice(index, 0, item);
2638
+ return copy;
2639
+ }
2640
+ function textToLabel(text = '...') {
2641
+ if (text.length > 10) {
2642
+ return `${text.substring(0, 30)}...`;
2643
+ }
1421
2644
 
1422
- function CollapsibleEntry(props) {
1423
- const {
1424
- children,
1425
- label,
1426
- removeEntry = () => {}
1427
- } = props;
1428
- const [collapsed, setCollapsed] = useState(false);
2645
+ return text;
2646
+ }
2647
+ const INPUTS = ['checkbox', 'checklist', 'number', 'radio', 'select', 'taglist', 'textfield'];
2648
+ const VALUES_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
2649
+
2650
+ const labelsByType = {
2651
+ button: 'BUTTON',
2652
+ checkbox: 'CHECKBOX',
2653
+ checklist: 'CHECKLIST',
2654
+ columns: 'COLUMNS',
2655
+ default: 'FORM',
2656
+ number: 'NUMBER',
2657
+ radio: 'RADIO',
2658
+ select: 'SELECT',
2659
+ taglist: 'TAGLIST',
2660
+ text: 'TEXT',
2661
+ textfield: 'TEXT FIELD'
2662
+ };
2663
+ const PropertiesPanelHeaderProvider = {
2664
+ getElementLabel: field => {
2665
+ const {
2666
+ type
2667
+ } = field;
1429
2668
 
1430
- const toggleCollapsed = () => setCollapsed(!collapsed);
2669
+ if (type === 'text') {
2670
+ return textToLabel(field.text);
2671
+ }
1431
2672
 
1432
- const classes = ['fjs-properties-panel-collapsible-entry'];
2673
+ if (type === 'default') {
2674
+ return field.id;
2675
+ }
1433
2676
 
1434
- if (collapsed) {
1435
- classes.push('fjs-properties-panel-collapsible-entry-collapsed');
2677
+ return field.label;
2678
+ },
2679
+ getElementIcon: field => {
2680
+ const {
2681
+ type
2682
+ } = field;
2683
+ const Icon = iconsByType[type];
2684
+
2685
+ if (Icon) {
2686
+ return () => jsx(Icon, {
2687
+ width: "36",
2688
+ height: "36",
2689
+ viewBox: "0 0 54 54"
2690
+ });
2691
+ }
2692
+ },
2693
+ getTypeLabel: field => {
2694
+ const {
2695
+ type
2696
+ } = field;
2697
+ return labelsByType[type];
1436
2698
  }
2699
+ };
1437
2700
 
1438
- return jsxs("div", {
1439
- class: classes.join(' '),
1440
- children: [jsxs("div", {
1441
- class: "fjs-properties-panel-collapsible-entry-header",
1442
- onClick: toggleCollapsed,
1443
- children: [jsxs("div", {
1444
- children: [jsx(ListArrowIcon, {
1445
- class: collapsed ? 'fjs-arrow-right' : 'fjs-arrow-down'
1446
- }), jsx("span", {
1447
- class: "fjs-properties-panel-collapsible-entry-header-label",
1448
- children: label
1449
- })]
1450
- }), jsx("button", {
1451
- class: "fjs-properties-panel-collapsible-entry-header-remove-entry",
1452
- onClick: stopPropagation(removeEntry),
1453
- children: jsx(ListDeleteIcon, {})
1454
- })]
1455
- }), collapsed ? null : jsx("div", {
1456
- class: "fjs-properties-panel-collapsible-entry-entries",
1457
- children: children
1458
- })]
1459
- });
1460
- }
2701
+ /**
2702
+ * Provide placeholders for empty and multiple state.
2703
+ */
2704
+ const PropertiesPanelPlaceholderProvider = {
2705
+ getEmpty: () => {
2706
+ return {
2707
+ text: 'Select a form field to edit its properties.'
2708
+ };
2709
+ },
2710
+ getMultiple: () => {
2711
+ return {
2712
+ text: 'Multiple form fields are selected. Select a single form field to edit its properties.'
2713
+ };
2714
+ }
2715
+ };
1461
2716
 
1462
- function Group(props) {
2717
+ function ActionEntry(props) {
1463
2718
  const {
1464
- children,
1465
- hasEntries = true,
1466
- label
2719
+ editField,
2720
+ field
1467
2721
  } = props;
1468
- const [open, setOpen] = useState(hasEntries);
1469
-
1470
- const toggleOpen = () => setOpen(!open);
2722
+ const {
2723
+ type
2724
+ } = field;
2725
+ const entries = [];
1471
2726
 
1472
- const addEntry = event => {
1473
- event.stopPropagation();
1474
- setOpen(true);
1475
- props.addEntry();
1476
- };
2727
+ if (type === 'button') {
2728
+ entries.push({
2729
+ id: 'action',
2730
+ component: Action,
2731
+ editField: editField,
2732
+ field: field,
2733
+ isEdited: isEdited$4
2734
+ });
2735
+ }
1477
2736
 
1478
- return jsxs("div", {
1479
- class: "fjs-properties-panel-group",
1480
- children: [jsxs("div", {
1481
- class: "fjs-properties-panel-group-header",
1482
- onClick: hasEntries ? toggleOpen : () => {},
1483
- children: [jsx("span", {
1484
- class: "fjs-properties-panel-group-header-label",
1485
- children: label
1486
- }), jsxs("div", {
1487
- class: "fjs-properties-panel-group-header-buttons",
1488
- children: [props.addEntry ? jsx("button", {
1489
- class: "fjs-properties-panel-group-header-button fjs-properties-panel-group-header-button-add-entry",
1490
- onClick: addEntry,
1491
- children: jsx(CreateIcon, {})
1492
- }) : null, jsx("button", {
1493
- class: "fjs-properties-panel-group-header-button fjs-properties-panel-group-header-button-toggle-open",
1494
- children: jsx(SectionArrowIcon, {
1495
- class: hasEntries && open ? 'fjs-arrow-down' : 'fjs-arrow-right'
1496
- })
1497
- })]
1498
- })]
1499
- }), hasEntries && open ? jsx("div", {
1500
- class: "fjs-properties-panel-group-entries",
1501
- children: children
1502
- }) : null]
1503
- });
2737
+ return entries;
1504
2738
  }
1505
2739
 
1506
- function ActionEntry(props) {
2740
+ function Action(props) {
1507
2741
  const {
1508
2742
  editField,
1509
- field
2743
+ field,
2744
+ id
1510
2745
  } = props;
1511
- const options = [{
2746
+ const path = ['action'];
2747
+
2748
+ const getValue = () => {
2749
+ return get(field, path, '');
2750
+ };
2751
+
2752
+ const setValue = value => {
2753
+ return editField(field, path, value);
2754
+ };
2755
+
2756
+ const getOptions = () => [{
1512
2757
  label: 'Submit',
1513
2758
  value: 'submit'
1514
2759
  }, {
1515
2760
  label: 'Reset',
1516
2761
  value: 'reset'
1517
2762
  }];
1518
- return jsx(SelectEntry, {
1519
- editField: editField,
1520
- field: field,
1521
- id: "action",
1522
- label: "Action",
1523
- options: options,
1524
- path: ['action']
2763
+
2764
+ return SelectEntry({
2765
+ element: field,
2766
+ getOptions,
2767
+ getValue,
2768
+ id,
2769
+ label: 'Action',
2770
+ setValue
1525
2771
  });
1526
2772
  }
1527
2773
 
@@ -1530,8 +2776,37 @@ function ColumnsEntry(props) {
1530
2776
  editField,
1531
2777
  field
1532
2778
  } = props;
2779
+ const {
2780
+ type
2781
+ } = field;
2782
+ const entries = [];
2783
+
2784
+ if (type === 'columns') {
2785
+ entries.push({
2786
+ id: 'columns',
2787
+ component: Columns,
2788
+ editField: editField,
2789
+ field: field,
2790
+ isEdited: isEdited$5
2791
+ });
2792
+ }
2793
+
2794
+ return entries;
2795
+ }
2796
+
2797
+ function Columns(props) {
2798
+ const {
2799
+ editField,
2800
+ field,
2801
+ id
2802
+ } = props;
2803
+ const debounce = useService('debounce');
2804
+
2805
+ const getValue = () => {
2806
+ return field.components.length;
2807
+ };
1533
2808
 
1534
- const onInput = value => {
2809
+ const setValue = value => {
1535
2810
  let components = field.components.slice();
1536
2811
 
1537
2812
  if (value > components.length) {
@@ -1547,17 +2822,13 @@ function ColumnsEntry(props) {
1547
2822
  editField(field, 'components', components);
1548
2823
  };
1549
2824
 
1550
- const value = field.components.length;
1551
- return jsx("div", {
1552
- class: "fjs-properties-panel-entry",
1553
- children: jsx(NumberInputEntry, {
1554
- id: "columns",
1555
- label: "Columns",
1556
- onInput: onInput,
1557
- value: value,
1558
- min: "1",
1559
- max: "3"
1560
- })
2825
+ return NumberFieldEntry({
2826
+ debounce,
2827
+ element: field,
2828
+ getValue,
2829
+ id,
2830
+ label: 'Columns',
2831
+ setValue
1561
2832
  });
1562
2833
  }
1563
2834
 
@@ -1566,87 +2837,238 @@ function DescriptionEntry(props) {
1566
2837
  editField,
1567
2838
  field
1568
2839
  } = props;
1569
- return jsx(TextInputEntry, {
1570
- editField: editField,
1571
- field: field,
1572
- id: "description",
1573
- label: "Field Description",
1574
- path: ['description']
2840
+ const {
2841
+ type
2842
+ } = field;
2843
+ const entries = [];
2844
+
2845
+ if (INPUTS.includes(type)) {
2846
+ entries.push({
2847
+ id: 'description',
2848
+ component: Description,
2849
+ editField: editField,
2850
+ field: field,
2851
+ isEdited: isEdited$1
2852
+ });
2853
+ }
2854
+
2855
+ return entries;
2856
+ }
2857
+
2858
+ function Description(props) {
2859
+ const {
2860
+ editField,
2861
+ field,
2862
+ id
2863
+ } = props;
2864
+ const debounce = useService('debounce');
2865
+ const path = ['description'];
2866
+
2867
+ const getValue = () => {
2868
+ return get(field, path, '');
2869
+ };
2870
+
2871
+ const setValue = value => {
2872
+ return editField(field, path, value);
2873
+ };
2874
+
2875
+ return TextfieldEntry({
2876
+ debounce,
2877
+ element: field,
2878
+ getValue,
2879
+ id,
2880
+ label: 'Field description',
2881
+ setValue
1575
2882
  });
1576
2883
  }
1577
2884
 
1578
- function DefaultValueEntry(props) {
2885
+ function DefaultOptionEntry(props) {
1579
2886
  const {
1580
2887
  editField,
1581
2888
  field
1582
2889
  } = props;
1583
2890
  const {
1584
- defaultValue,
1585
- type,
1586
- values = []
2891
+ type
1587
2892
  } = field;
2893
+ const entries = []; // Only make default values available when they are statically defined
2894
+
2895
+ if (!INPUTS.includes(type) || VALUES_INPUTS.includes(type) && !field.values) {
2896
+ return entries;
2897
+ }
2898
+
2899
+ const defaultOptions = {
2900
+ editField,
2901
+ field,
2902
+ id: 'defaultValue',
2903
+ label: 'Default value'
2904
+ };
1588
2905
 
1589
2906
  if (type === 'checkbox') {
1590
- const options = [{
2907
+ entries.push({ ...defaultOptions,
2908
+ component: DefaultValueCheckbox,
2909
+ isEdited: isEdited$4
2910
+ });
2911
+ }
2912
+
2913
+ if (type === 'number') {
2914
+ entries.push({ ...defaultOptions,
2915
+ component: DefaultValueNumber,
2916
+ isEdited: isEdited$5
2917
+ });
2918
+ }
2919
+
2920
+ if (type === 'radio' || type === 'select') {
2921
+ entries.push({ ...defaultOptions,
2922
+ component: DefaultValueSingleSelect,
2923
+ isEdited: isEdited$4
2924
+ });
2925
+ } // todo(Skaiir): implement a multiselect equivalent (cf. https://github.com/bpmn-io/form-js/issues/265)
2926
+
2927
+
2928
+ if (type === 'textfield') {
2929
+ entries.push({ ...defaultOptions,
2930
+ component: DefaultValueTextfield,
2931
+ isEdited: isEdited$1
2932
+ });
2933
+ }
2934
+
2935
+ return entries;
2936
+ }
2937
+
2938
+ function DefaultValueCheckbox(props) {
2939
+ const {
2940
+ editField,
2941
+ field,
2942
+ id,
2943
+ label
2944
+ } = props;
2945
+ const {
2946
+ defaultValue
2947
+ } = field;
2948
+ const path = ['defaultValue'];
2949
+
2950
+ const getOptions = () => {
2951
+ return [{
1591
2952
  label: 'Checked',
1592
2953
  value: 'true'
1593
2954
  }, {
1594
2955
  label: 'Not checked',
1595
2956
  value: 'false'
1596
2957
  }];
2958
+ };
1597
2959
 
1598
- const onChange = value => {
1599
- editField(field, ['defaultValue'], parseStringToBoolean(value));
1600
- };
2960
+ const setValue = value => {
2961
+ return editField(field, path, parseStringToBoolean(value));
2962
+ };
1601
2963
 
1602
- return jsx(SelectEntry, {
1603
- id: "defaultValue",
1604
- label: "Default Value",
1605
- onChange: onChange,
1606
- options: options,
1607
- value: parseBooleanToString(defaultValue)
1608
- });
1609
- }
2964
+ const getValue = () => {
2965
+ return parseBooleanToString(defaultValue);
2966
+ };
1610
2967
 
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
- }
2968
+ return SelectEntry({
2969
+ element: field,
2970
+ getOptions,
2971
+ getValue,
2972
+ id,
2973
+ label,
2974
+ setValue
2975
+ });
2976
+ }
1620
2977
 
1621
- if (type === 'radio' || type === 'select') {
1622
- const options = [{
2978
+ function DefaultValueNumber(props) {
2979
+ const {
2980
+ editField,
2981
+ field,
2982
+ id,
2983
+ label
2984
+ } = props;
2985
+ const debounce = useService('debounce');
2986
+ const path = ['defaultValue'];
2987
+
2988
+ const getValue = () => {
2989
+ return get(field, path, '');
2990
+ };
2991
+
2992
+ const setValue = value => {
2993
+ return editField(field, path, value);
2994
+ };
2995
+
2996
+ return NumberFieldEntry({
2997
+ debounce,
2998
+ element: field,
2999
+ getValue,
3000
+ id,
3001
+ label,
3002
+ setValue
3003
+ });
3004
+ }
3005
+
3006
+ function DefaultValueSingleSelect(props) {
3007
+ const {
3008
+ editField,
3009
+ field,
3010
+ id,
3011
+ label
3012
+ } = props;
3013
+ const {
3014
+ defaultValue,
3015
+ values = []
3016
+ } = field;
3017
+ const path = ['defaultValue'];
3018
+
3019
+ const getOptions = () => {
3020
+ return [{
1623
3021
  label: '<none>'
1624
3022
  }, ...values];
3023
+ };
1625
3024
 
1626
- const onChange = value => {
1627
- editField(field, ['defaultValue'], value.length ? value : undefined);
1628
- };
3025
+ const setValue = value => {
3026
+ return editField(field, path, value.length ? value : undefined);
3027
+ };
1629
3028
 
1630
- return jsx(SelectEntry, {
1631
- id: "defaultValue",
1632
- label: "Default Value",
1633
- onChange: onChange,
1634
- options: options,
1635
- value: defaultValue
1636
- });
1637
- }
3029
+ const getValue = () => {
3030
+ return defaultValue;
3031
+ };
1638
3032
 
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
- }
3033
+ return SelectEntry({
3034
+ element: field,
3035
+ getOptions,
3036
+ getValue,
3037
+ id,
3038
+ label,
3039
+ setValue
3040
+ });
1648
3041
  }
1649
3042
 
3043
+ function DefaultValueTextfield(props) {
3044
+ const {
3045
+ editField,
3046
+ field,
3047
+ id,
3048
+ label
3049
+ } = props;
3050
+ const debounce = useService('debounce');
3051
+ const path = ['defaultValue'];
3052
+
3053
+ const getValue = () => {
3054
+ return get(field, path, '');
3055
+ };
3056
+
3057
+ const setValue = value => {
3058
+ return editField(field, path, value);
3059
+ };
3060
+
3061
+ return TextfieldEntry({
3062
+ debounce,
3063
+ element: field,
3064
+ getValue,
3065
+ id,
3066
+ label,
3067
+ setValue
3068
+ });
3069
+ } // helpers /////////////////
3070
+
3071
+
1650
3072
  function parseStringToBoolean(value) {
1651
3073
  if (value === 'true') {
1652
3074
  return true;
@@ -1660,25 +3082,54 @@ function parseBooleanToString(value) {
1660
3082
  return 'true';
1661
3083
  }
1662
3084
 
1663
- return 'false';
3085
+ return 'false';
3086
+ }
3087
+
3088
+ function DisabledEntry(props) {
3089
+ const {
3090
+ editField,
3091
+ field
3092
+ } = props;
3093
+ const {
3094
+ type
3095
+ } = field;
3096
+ const entries = [];
3097
+
3098
+ if (INPUTS.includes(type)) {
3099
+ entries.push({
3100
+ id: 'disabled',
3101
+ component: Disabled,
3102
+ editField: editField,
3103
+ field: field,
3104
+ isEdited: isEdited$6
3105
+ });
3106
+ }
3107
+
3108
+ return entries;
1664
3109
  }
1665
3110
 
1666
- function DisabledEntry(props) {
3111
+ function Disabled(props) {
1667
3112
  const {
1668
3113
  editField,
1669
- field
3114
+ field,
3115
+ id
1670
3116
  } = props;
3117
+ const path = ['disabled'];
3118
+
3119
+ const getValue = () => {
3120
+ return get(field, path, '');
3121
+ };
1671
3122
 
1672
- const onChange = value => {
1673
- editField(field, ['disabled'], value);
3123
+ const setValue = value => {
3124
+ return editField(field, path, value);
1674
3125
  };
1675
3126
 
1676
- return jsx(CheckboxInputEntry, {
1677
- id: "disabled",
1678
- field: field,
1679
- label: "Disabled",
1680
- path: ['disabled'],
1681
- onChange: onChange
3127
+ return CheckboxEntry({
3128
+ element: field,
3129
+ getValue,
3130
+ id,
3131
+ label: 'Disabled',
3132
+ setValue
1682
3133
  });
1683
3134
  }
1684
3135
 
@@ -1687,7 +3138,38 @@ function IdEntry(props) {
1687
3138
  editField,
1688
3139
  field
1689
3140
  } = props;
3141
+ const entries = [];
3142
+
3143
+ if (field.type === 'default') {
3144
+ entries.push({
3145
+ id: 'id',
3146
+ component: Id,
3147
+ editField: editField,
3148
+ field: field,
3149
+ isEdited: isEdited$1
3150
+ });
3151
+ }
3152
+
3153
+ return entries;
3154
+ }
3155
+
3156
+ function Id(props) {
3157
+ const {
3158
+ editField,
3159
+ field,
3160
+ id
3161
+ } = props;
1690
3162
  const formFieldRegistry = useService('formFieldRegistry');
3163
+ const debounce = useService('debounce');
3164
+ const path = ['id'];
3165
+
3166
+ const getValue = () => {
3167
+ return get(field, path, '');
3168
+ };
3169
+
3170
+ const setValue = value => {
3171
+ return editField(field, path, value);
3172
+ };
1691
3173
 
1692
3174
  const validate = value => {
1693
3175
  if (isUndefined(value) || !value.length) {
@@ -1703,16 +3185,18 @@ function IdEntry(props) {
1703
3185
  return validateId(value) || null;
1704
3186
  };
1705
3187
 
1706
- return jsx(TextInputEntry, {
1707
- editField: editField,
1708
- field: field,
1709
- id: "id",
1710
- label: "Id",
1711
- path: ['id'],
1712
- validate: validate
3188
+ return TextfieldEntry({
3189
+ debounce,
3190
+ element: field,
3191
+ getValue,
3192
+ id,
3193
+ label: 'ID',
3194
+ setValue,
3195
+ validate
1713
3196
  });
1714
3197
  } // id structural validation /////////////
1715
3198
 
3199
+
1716
3200
  const SPACE_REGEX = /\s/; // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
1717
3201
 
1718
3202
  const QNAME_REGEX = /^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i; // for ID validation as per BPMN Schema (QName - Namespace)
@@ -1742,7 +3226,41 @@ function KeyEntry(props) {
1742
3226
  editField,
1743
3227
  field
1744
3228
  } = props;
3229
+ const {
3230
+ type
3231
+ } = field;
3232
+ const entries = [];
3233
+
3234
+ if (INPUTS.includes(type)) {
3235
+ entries.push({
3236
+ id: 'key',
3237
+ component: Key$1,
3238
+ editField: editField,
3239
+ field: field,
3240
+ isEdited: isEdited$1
3241
+ });
3242
+ }
3243
+
3244
+ return entries;
3245
+ }
3246
+
3247
+ function Key$1(props) {
3248
+ const {
3249
+ editField,
3250
+ field,
3251
+ id
3252
+ } = props;
1745
3253
  const formFieldRegistry = useService('formFieldRegistry');
3254
+ const debounce = useService('debounce');
3255
+ const path = ['key'];
3256
+
3257
+ const getValue = () => {
3258
+ return get(field, path, '');
3259
+ };
3260
+
3261
+ const setValue = value => {
3262
+ return editField(field, path, value);
3263
+ };
1746
3264
 
1747
3265
  const validate = value => {
1748
3266
  if (isUndefined(value) || !value.length) {
@@ -1762,14 +3280,15 @@ function KeyEntry(props) {
1762
3280
  return null;
1763
3281
  };
1764
3282
 
1765
- return jsx(TextInputEntry, {
1766
- editField: editField,
1767
- field: field,
1768
- id: "key",
1769
- label: "Key",
1770
- description: "Maps to a process variable.",
1771
- path: ['key'],
1772
- validate: validate
3283
+ return TextfieldEntry({
3284
+ debounce,
3285
+ description: 'Maps to a process variable',
3286
+ element: field,
3287
+ getValue,
3288
+ id,
3289
+ label: 'Key',
3290
+ setValue,
3291
+ validate
1773
3292
  });
1774
3293
  }
1775
3294
 
@@ -1778,12 +3297,48 @@ function LabelEntry(props) {
1778
3297
  editField,
1779
3298
  field
1780
3299
  } = props;
1781
- return jsx(TextInputEntry, {
1782
- editField: editField,
1783
- field: field,
1784
- id: "label",
1785
- label: "Field Label",
1786
- path: ['label']
3300
+ const {
3301
+ type
3302
+ } = field;
3303
+ const entries = [];
3304
+
3305
+ if (INPUTS.includes(type) || type === 'button') {
3306
+ entries.push({
3307
+ id: 'label',
3308
+ component: Label$1,
3309
+ editField: editField,
3310
+ field: field,
3311
+ isEdited: isEdited$1
3312
+ });
3313
+ }
3314
+
3315
+ return entries;
3316
+ }
3317
+
3318
+ function Label$1(props) {
3319
+ const {
3320
+ editField,
3321
+ field,
3322
+ id
3323
+ } = props;
3324
+ const debounce = useService('debounce');
3325
+ const path = ['label'];
3326
+
3327
+ const getValue = () => {
3328
+ return get(field, path, '');
3329
+ };
3330
+
3331
+ const setValue = value => {
3332
+ return editField(field, path, value);
3333
+ };
3334
+
3335
+ return TextfieldEntry({
3336
+ debounce,
3337
+ element: field,
3338
+ getValue,
3339
+ id,
3340
+ label: 'Field label',
3341
+ setValue
1787
3342
  });
1788
3343
  }
1789
3344
 
@@ -1792,13 +3347,50 @@ function TextEntry(props) {
1792
3347
  editField,
1793
3348
  field
1794
3349
  } = props;
1795
- return jsx(TextareaEntry, {
1796
- editField: editField,
1797
- field: field,
1798
- id: "text",
1799
- label: "Text",
1800
- path: ['text'],
1801
- description: "Use Markdown or basic HTML to format."
3350
+ const {
3351
+ type
3352
+ } = field;
3353
+ const entries = [];
3354
+
3355
+ if (type === 'text') {
3356
+ entries.push({
3357
+ id: 'text',
3358
+ component: Text,
3359
+ editField: editField,
3360
+ field: field,
3361
+ isEdited: isEdited$2
3362
+ });
3363
+ }
3364
+
3365
+ return entries;
3366
+ }
3367
+
3368
+ function Text(props) {
3369
+ const {
3370
+ editField,
3371
+ field,
3372
+ id
3373
+ } = props;
3374
+ const debounce = useService('debounce');
3375
+ const path = ['text'];
3376
+
3377
+ const getValue = () => {
3378
+ return get(field, path, '');
3379
+ };
3380
+
3381
+ const setValue = value => {
3382
+ return editField(field, path, value);
3383
+ };
3384
+
3385
+ return TextAreaEntry({
3386
+ debounce,
3387
+ description: 'Use Markdown or basic HTML to format.',
3388
+ element: field,
3389
+ getValue,
3390
+ id,
3391
+ label: 'Text',
3392
+ rows: 10,
3393
+ setValue
1802
3394
  });
1803
3395
  }
1804
3396
 
@@ -1806,38 +3398,87 @@ function ValueEntry(props) {
1806
3398
  const {
1807
3399
  editField,
1808
3400
  field,
3401
+ idPrefix,
1809
3402
  index,
1810
- validate
3403
+ validateFactory
1811
3404
  } = props;
3405
+ const entries = [{
3406
+ component: Label,
3407
+ editField,
3408
+ field,
3409
+ id: idPrefix + '-label',
3410
+ idPrefix,
3411
+ index,
3412
+ validateFactory
3413
+ }, {
3414
+ component: Value$1,
3415
+ editField,
3416
+ field,
3417
+ id: idPrefix + '-value',
3418
+ idPrefix,
3419
+ index,
3420
+ validateFactory
3421
+ }];
3422
+ return entries;
3423
+ }
1812
3424
 
1813
- const getLabel = () => {
1814
- return get(field, ['values', index, 'label']);
3425
+ function Label(props) {
3426
+ const {
3427
+ editField,
3428
+ field,
3429
+ id,
3430
+ index,
3431
+ validateFactory
3432
+ } = props;
3433
+ const debounce = useService('debounce');
3434
+
3435
+ const setValue = value => {
3436
+ const values = get(field, ['values']);
3437
+ return editField(field, 'values', set(values, [index, 'label'], value));
1815
3438
  };
1816
3439
 
1817
3440
  const getValue = () => {
1818
- return get(field, ['values', index, 'value']);
3441
+ return get(field, ['values', index, 'label']);
1819
3442
  };
1820
3443
 
1821
- const onChange = key => {
3444
+ return TextfieldEntry({
3445
+ debounce,
3446
+ element: field,
3447
+ getValue,
3448
+ id,
3449
+ label: 'Label',
3450
+ setValue,
3451
+ validate: validateFactory(getValue())
3452
+ });
3453
+ }
3454
+
3455
+ function Value$1(props) {
3456
+ const {
3457
+ editField,
3458
+ field,
3459
+ id,
3460
+ index,
3461
+ validateFactory
3462
+ } = props;
3463
+ const debounce = useService('debounce');
3464
+
3465
+ const setValue = value => {
1822
3466
  const values = get(field, ['values']);
1823
- return value => {
1824
- editField(field, 'values', set(values, [index, key], value));
1825
- };
3467
+ return editField(field, 'values', set(values, [index, 'value'], value));
1826
3468
  };
1827
3469
 
1828
- return jsxs(Fragment, {
1829
- children: [jsx(TextInputEntry, {
1830
- id: `value-label-${index}`,
1831
- label: "Label",
1832
- onChange: onChange('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
- })]
3470
+ const getValue = () => {
3471
+ return get(field, ['values', index, 'value']);
3472
+ };
3473
+
3474
+ return TextfieldEntry({
3475
+ debounce,
3476
+ element: field,
3477
+ getValue,
3478
+ id,
3479
+ label: 'Value',
3480
+ setValue,
3481
+ validate: validateFactory(getValue())
1841
3482
  });
1842
3483
  }
1843
3484
 
@@ -1845,42 +3486,91 @@ function CustomValueEntry(props) {
1845
3486
  const {
1846
3487
  editField,
1847
3488
  field,
3489
+ idPrefix,
1848
3490
  index,
1849
- validate
3491
+ validateFactory
3492
+ } = props;
3493
+ const entries = [{
3494
+ component: Key,
3495
+ editField,
3496
+ field,
3497
+ id: idPrefix + '-key',
3498
+ idPrefix,
3499
+ index,
3500
+ validateFactory
3501
+ }, {
3502
+ component: Value,
3503
+ editField,
3504
+ field,
3505
+ id: idPrefix + '-value',
3506
+ idPrefix,
3507
+ index,
3508
+ validateFactory
3509
+ }];
3510
+ return entries;
3511
+ }
3512
+
3513
+ function Key(props) {
3514
+ const {
3515
+ editField,
3516
+ field,
3517
+ id,
3518
+ index,
3519
+ validateFactory
1850
3520
  } = props;
3521
+ const debounce = useService('debounce');
1851
3522
 
1852
- const getKey = () => {
1853
- return Object.keys(get(field, ['properties']))[index];
3523
+ const setValue = value => {
3524
+ const properties = get(field, ['properties']);
3525
+ const key = Object.keys(properties)[index];
3526
+ return editField(field, 'properties', updateKey(properties, key, value));
1854
3527
  };
1855
3528
 
1856
3529
  const getValue = () => {
1857
- return get(field, ['properties', getKey()]);
3530
+ return Object.keys(get(field, ['properties']))[index];
1858
3531
  };
1859
3532
 
1860
- const onChange = key => {
3533
+ return TextfieldEntry({
3534
+ debounce,
3535
+ element: field,
3536
+ getValue,
3537
+ id,
3538
+ label: 'Key',
3539
+ setValue,
3540
+ validate: validateFactory(getValue())
3541
+ });
3542
+ }
3543
+
3544
+ function Value(props) {
3545
+ const {
3546
+ editField,
3547
+ field,
3548
+ id,
3549
+ index,
3550
+ validateFactory
3551
+ } = props;
3552
+ const debounce = useService('debounce');
3553
+
3554
+ const setValue = value => {
1861
3555
  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
- };
3556
+ const key = Object.keys(properties)[index];
3557
+ editField(field, 'properties', updateValue(properties, key, value));
1869
3558
  };
1870
3559
 
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())
1878
- }), jsx(TextInputEntry, {
1879
- id: `value-value-${index}`,
1880
- label: "Value",
1881
- onChange: onChange('value'),
1882
- value: getValue()
1883
- })]
3560
+ const getValue = () => {
3561
+ const properties = get(field, ['properties']);
3562
+ const key = Object.keys(properties)[index];
3563
+ return get(field, ['properties', key]);
3564
+ };
3565
+
3566
+ return TextfieldEntry({
3567
+ debounce,
3568
+ element: field,
3569
+ getValue,
3570
+ id,
3571
+ label: 'Value',
3572
+ setValue,
3573
+ validate: validateFactory(getValue())
1884
3574
  });
1885
3575
  } // helpers //////////
1886
3576
 
@@ -1894,6 +3584,7 @@ function CustomValueEntry(props) {
1894
3584
  * @returns {Object}
1895
3585
  */
1896
3586
 
3587
+
1897
3588
  function updateValue(properties, key, value) {
1898
3589
  return { ...properties,
1899
3590
  [key]: value
@@ -1919,154 +3610,149 @@ function updateKey(properties, oldKey, newKey) {
1919
3610
  }, {});
1920
3611
  }
1921
3612
 
1922
- function GeneralGroup(field, editField) {
1923
- const {
1924
- type
1925
- } = field;
1926
- const entries = [];
1927
-
1928
- if (type === 'default') {
1929
- entries.push(jsx(IdEntry, {
1930
- editField: editField,
1931
- field: field
1932
- }));
1933
- }
1934
-
1935
- if (INPUTS.includes(type) || type === 'button') {
1936
- entries.push(jsx(LabelEntry, {
1937
- editField: editField,
1938
- field: field
1939
- }));
1940
- }
1941
-
1942
- if (INPUTS.includes(type)) {
1943
- entries.push(jsx(DescriptionEntry, {
1944
- editField: editField,
1945
- field: field
1946
- }));
1947
- }
1948
-
1949
- if (INPUTS.includes(type)) {
1950
- entries.push(jsx(KeyEntry, {
1951
- editField: editField,
1952
- field: field
1953
- }));
1954
- }
1955
-
1956
- if (INPUTS.includes(type)) {
1957
- entries.push(jsx(DefaultValueEntry, {
1958
- editField: editField,
1959
- field: field
1960
- }));
3613
+ const VALUES_SOURCES = {
3614
+ STATIC: 'static',
3615
+ INPUT: 'input'
3616
+ };
3617
+ const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
3618
+ const VALUES_SOURCES_LABELS = {
3619
+ [VALUES_SOURCES.STATIC]: 'Static',
3620
+ [VALUES_SOURCES.INPUT]: 'Input data'
3621
+ };
3622
+ const VALUES_SOURCES_PATHS = {
3623
+ [VALUES_SOURCES.STATIC]: ['values'],
3624
+ [VALUES_SOURCES.INPUT]: ['valuesKey']
3625
+ };
3626
+ const VALUES_SOURCES_DEFAULTS = {
3627
+ [VALUES_SOURCES.STATIC]: [],
3628
+ [VALUES_SOURCES.INPUT]: ''
3629
+ }; // helpers ///////////////////
3630
+
3631
+ function getValuesSource(field) {
3632
+ for (const source of Object.values(VALUES_SOURCES)) {
3633
+ if (get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
3634
+ return source;
3635
+ }
1961
3636
  }
1962
3637
 
1963
- if (type === 'button') {
1964
- entries.push(jsx(ActionEntry, {
1965
- editField: editField,
1966
- field: field
1967
- }));
1968
- }
3638
+ return VALUES_SOURCE_DEFAULT;
3639
+ }
1969
3640
 
1970
- if (type === 'columns') {
1971
- entries.push(jsx(ColumnsEntry, {
1972
- editField: editField,
1973
- field: field
1974
- }));
1975
- }
3641
+ function ValuesSourceSelectEntry(props) {
3642
+ const {
3643
+ editField,
3644
+ field,
3645
+ id
3646
+ } = props;
3647
+ return [{
3648
+ id: id + '-select',
3649
+ component: ValuesSourceSelect,
3650
+ isEdited: isEdited$4,
3651
+ editField,
3652
+ field
3653
+ }];
3654
+ }
1976
3655
 
1977
- if (type === 'text') {
1978
- entries.push(jsx(TextEntry, {
1979
- editField: editField,
1980
- field: field
1981
- }));
1982
- }
3656
+ function ValuesSourceSelect(props) {
3657
+ const {
3658
+ editField,
3659
+ field,
3660
+ id
3661
+ } = props;
3662
+ const getValue = getValuesSource;
3663
+
3664
+ const setValue = value => {
3665
+ let newField = field;
3666
+ Object.values(VALUES_SOURCES).forEach(source => {
3667
+ // Clear all values source definitions and default the newly selected one
3668
+ const newValue = value === source ? VALUES_SOURCES_DEFAULTS[source] : undefined;
3669
+ newField = editField(field, VALUES_SOURCES_PATHS[source], newValue);
3670
+ });
3671
+ return newField;
3672
+ };
1983
3673
 
1984
- if (INPUTS.includes(type)) {
1985
- entries.push(jsx(DisabledEntry, {
1986
- editField: editField,
1987
- field: field
3674
+ const getValuesSourceOptions = () => {
3675
+ return Object.values(VALUES_SOURCES).map(valueSource => ({
3676
+ label: VALUES_SOURCES_LABELS[valueSource],
3677
+ value: valueSource
1988
3678
  }));
1989
- }
3679
+ };
1990
3680
 
1991
- return jsx(Group, {
1992
- label: "General",
1993
- children: entries.length ? entries : null
3681
+ return SelectEntry({
3682
+ label: 'Type',
3683
+ element: field,
3684
+ getOptions: getValuesSourceOptions,
3685
+ getValue,
3686
+ id,
3687
+ setValue
1994
3688
  });
1995
3689
  }
1996
3690
 
1997
- function ValidationGroup(field, editField) {
3691
+ function InputKeyValuesSourceEntry(props) {
1998
3692
  const {
1999
- type
2000
- } = field;
2001
-
2002
- const onChange = key => {
2003
- return value => {
2004
- const validate = get(field, ['validate'], {});
2005
- editField(field, ['validate'], set(validate, [key], value));
2006
- };
2007
- };
3693
+ editField,
3694
+ field,
3695
+ id
3696
+ } = props;
3697
+ return [{
3698
+ id: id + '-key',
3699
+ component: InputValuesKey,
3700
+ label: 'Input values key',
3701
+ description: 'Define which input property to populate the values from',
3702
+ isEdited: isEdited$1,
3703
+ editField,
3704
+ field
3705
+ }];
3706
+ }
2008
3707
 
2009
- const entries = [jsx(CheckboxInputEntry, {
2010
- id: "required",
2011
- label: "Required",
2012
- onChange: onChange('required'),
2013
- value: get(field, ['validate', 'required'])
2014
- })];
3708
+ function InputValuesKey(props) {
3709
+ const {
3710
+ editField,
3711
+ field,
3712
+ id,
3713
+ label,
3714
+ description
3715
+ } = props;
3716
+ const debounce = useService('debounce');
3717
+ const path = VALUES_SOURCES_PATHS[VALUES_SOURCES.INPUT];
2015
3718
 
2016
- if (type === 'textfield') {
2017
- entries.push(jsx(NumberInputEntry, {
2018
- id: "minLength",
2019
- label: "Minimum Length",
2020
- min: "0",
2021
- onChange: onChange('minLength'),
2022
- value: get(field, ['validate', 'minLength'])
2023
- }), jsx(NumberInputEntry, {
2024
- id: "maxLength",
2025
- label: "Maximum Length",
2026
- min: "0",
2027
- onChange: onChange('maxLength'),
2028
- value: get(field, ['validate', 'maxLength'])
2029
- }), jsx(TextInputEntry, {
2030
- id: "pattern",
2031
- label: "Regular Expression Pattern",
2032
- onChange: onChange('pattern'),
2033
- value: get(field, ['validate', 'pattern'])
2034
- }));
2035
- }
3719
+ const getValue = () => get(field, path, '');
2036
3720
 
2037
- if (type === 'number') {
2038
- entries.push(jsx(NumberInputEntry, {
2039
- id: "min",
2040
- label: "Minimum",
2041
- onChange: onChange('min'),
2042
- value: get(field, ['validate', 'min'])
2043
- }), jsx(NumberInputEntry, {
2044
- id: "max",
2045
- label: "Maximum",
2046
- onChange: onChange('max'),
2047
- value: get(field, ['validate', 'max'])
2048
- }));
2049
- }
3721
+ const setValue = value => editField(field, path, value || '');
2050
3722
 
2051
- return jsx(Group, {
2052
- label: "Validation",
2053
- children: entries.length ? entries : null
3723
+ return TextfieldEntry({
3724
+ debounce,
3725
+ description,
3726
+ element: field,
3727
+ getValue,
3728
+ id,
3729
+ label,
3730
+ setValue
2054
3731
  });
2055
3732
  }
2056
3733
 
2057
- function ValuesGroup(field, editField) {
3734
+ function StaticValuesSourceEntry(props) {
2058
3735
  const {
2059
- id,
2060
- values = []
3736
+ editField,
3737
+ field,
3738
+ id: idPrefix
3739
+ } = props;
3740
+ const {
3741
+ values
2061
3742
  } = field;
2062
3743
 
2063
- const addEntry = () => {
3744
+ const addEntry = e => {
3745
+ e.stopPropagation();
2064
3746
  const index = values.length + 1;
2065
3747
  const entry = {
2066
3748
  label: `Value ${index}`,
2067
3749
  value: `value${index}`
2068
3750
  };
2069
- editField(field, ['values'], arrayAdd$1(values, values.length, entry));
3751
+ editField(field, VALUES_SOURCES_PATHS[VALUES_SOURCES.STATIC], arrayAdd$1(values, values.length, entry));
3752
+ };
3753
+
3754
+ const removeEntry = entry => {
3755
+ editField(field, VALUES_SOURCES_PATHS[VALUES_SOURCES.STATIC], without(values, entry));
2070
3756
  };
2071
3757
 
2072
3758
  const validateFactory = key => {
@@ -2087,41 +3773,321 @@ function ValuesGroup(field, editField) {
2087
3773
  };
2088
3774
  };
2089
3775
 
2090
- const hasEntries = values.length > 0;
2091
- return jsx(Group, {
2092
- label: "Values",
2093
- addEntry: addEntry,
2094
- hasEntries: hasEntries,
2095
- children: values.map((value, index) => {
2096
- const {
2097
- label
2098
- } = value;
3776
+ const items = values.map((entry, index) => {
3777
+ const id = idPrefix + '-' + index;
3778
+ return {
3779
+ id,
3780
+ label: entry.label,
3781
+ entries: ValueEntry({
3782
+ editField,
3783
+ field,
3784
+ idPrefix: id,
3785
+ index,
3786
+ validateFactory
3787
+ }),
3788
+ autoFocusEntry: id + '-label',
3789
+ remove: () => removeEntry(entry)
3790
+ };
3791
+ });
3792
+ return {
3793
+ items,
3794
+ add: addEntry
3795
+ };
3796
+ }
2099
3797
 
2100
- const removeEntry = () => {
2101
- editField(field, ['values'], arrayRemove$1(values, index));
2102
- };
3798
+ function GeneralGroup(field, editField) {
3799
+ const entries = [...IdEntry({
3800
+ field,
3801
+ editField
3802
+ }), ...LabelEntry({
3803
+ field,
3804
+ editField
3805
+ }), ...DescriptionEntry({
3806
+ field,
3807
+ editField
3808
+ }), ...KeyEntry({
3809
+ field,
3810
+ editField
3811
+ }), ...DefaultOptionEntry({
3812
+ field,
3813
+ editField
3814
+ }), ...ActionEntry({
3815
+ field,
3816
+ editField
3817
+ }), ...ColumnsEntry({
3818
+ field,
3819
+ editField
3820
+ }), ...TextEntry({
3821
+ field,
3822
+ editField
3823
+ }), ...DisabledEntry({
3824
+ field,
3825
+ editField
3826
+ })];
3827
+ return {
3828
+ id: 'general',
3829
+ label: 'General',
3830
+ entries
3831
+ };
3832
+ }
2103
3833
 
2104
- return jsx(CollapsibleEntry, {
2105
- label: label,
2106
- removeEntry: removeEntry,
2107
- children: jsx(ValueEntry, {
2108
- editField: editField,
2109
- field: field,
2110
- index: index,
2111
- validate: validateFactory
2112
- })
2113
- }, `${id}-${index}`);
2114
- })
3834
+ function ValidationGroup(field, editField) {
3835
+ const {
3836
+ type
3837
+ } = field;
3838
+
3839
+ if (!(INPUTS.includes(type) && type !== 'checkbox' && type !== 'checklist' && type !== 'taglist')) {
3840
+ return null;
3841
+ }
3842
+
3843
+ const onChange = key => {
3844
+ return value => {
3845
+ const validate = get(field, ['validate'], {});
3846
+ editField(field, ['validate'], set(validate, [key], value));
3847
+ };
3848
+ };
3849
+
3850
+ const getValue = key => {
3851
+ return () => {
3852
+ return get(field, ['validate', key]);
3853
+ };
3854
+ };
3855
+
3856
+ let entries = [{
3857
+ id: 'required',
3858
+ component: Required,
3859
+ getValue,
3860
+ field,
3861
+ isEdited: isEdited$6,
3862
+ onChange
3863
+ }];
3864
+
3865
+ if (type === 'textfield') {
3866
+ entries.push({
3867
+ id: 'minLength',
3868
+ component: MinLength,
3869
+ getValue,
3870
+ field,
3871
+ isEdited: isEdited$5,
3872
+ onChange
3873
+ }, {
3874
+ id: 'maxLength',
3875
+ component: MaxLength,
3876
+ getValue,
3877
+ field,
3878
+ isEdited: isEdited$5,
3879
+ onChange
3880
+ }, {
3881
+ id: 'pattern',
3882
+ component: Pattern,
3883
+ getValue,
3884
+ field,
3885
+ isEdited: isEdited$1,
3886
+ onChange
3887
+ });
3888
+ }
3889
+
3890
+ if (type === 'number') {
3891
+ entries.push({
3892
+ id: 'min',
3893
+ component: Min,
3894
+ getValue,
3895
+ field,
3896
+ isEdited: isEdited$5,
3897
+ onChange
3898
+ }, {
3899
+ id: 'max',
3900
+ component: Max,
3901
+ getValue,
3902
+ field,
3903
+ isEdited: isEdited$5,
3904
+ onChange
3905
+ });
3906
+ }
3907
+
3908
+ return {
3909
+ id: 'validation',
3910
+ label: 'Validation',
3911
+ entries
3912
+ };
3913
+ }
3914
+
3915
+ function Required(props) {
3916
+ const {
3917
+ field,
3918
+ getValue,
3919
+ id,
3920
+ onChange
3921
+ } = props;
3922
+ return CheckboxEntry({
3923
+ element: field,
3924
+ getValue: getValue('required'),
3925
+ id,
3926
+ label: 'Required',
3927
+ setValue: onChange('required')
2115
3928
  });
2116
3929
  }
2117
3930
 
2118
- function CustomValuesGroup(field, editField) {
3931
+ function MinLength(props) {
3932
+ const {
3933
+ field,
3934
+ getValue,
3935
+ id,
3936
+ onChange
3937
+ } = props;
3938
+ const debounce = useService('debounce');
3939
+ return NumberFieldEntry({
3940
+ debounce,
3941
+ element: field,
3942
+ getValue: getValue('minLength'),
3943
+ id,
3944
+ label: 'Minimum length',
3945
+ min: 0,
3946
+ setValue: onChange('minLength')
3947
+ });
3948
+ }
3949
+
3950
+ function MaxLength(props) {
3951
+ const {
3952
+ field,
3953
+ getValue,
3954
+ id,
3955
+ onChange
3956
+ } = props;
3957
+ const debounce = useService('debounce');
3958
+ return NumberFieldEntry({
3959
+ debounce,
3960
+ element: field,
3961
+ getValue: getValue('maxLength'),
3962
+ id,
3963
+ label: 'Maximum length',
3964
+ min: 0,
3965
+ setValue: onChange('maxLength')
3966
+ });
3967
+ }
3968
+
3969
+ function Pattern(props) {
3970
+ const {
3971
+ field,
3972
+ getValue,
3973
+ id,
3974
+ onChange
3975
+ } = props;
3976
+ const debounce = useService('debounce');
3977
+ return TextfieldEntry({
3978
+ debounce,
3979
+ element: field,
3980
+ getValue: getValue('pattern'),
3981
+ id,
3982
+ label: 'Regular expression pattern',
3983
+ setValue: onChange('pattern')
3984
+ });
3985
+ }
3986
+
3987
+ function Min(props) {
2119
3988
  const {
3989
+ field,
3990
+ getValue,
3991
+ id,
3992
+ onChange
3993
+ } = props;
3994
+ const debounce = useService('debounce');
3995
+ return NumberFieldEntry({
3996
+ debounce,
3997
+ element: field,
3998
+ getValue: getValue('min'),
3999
+ id,
4000
+ label: 'Minimum',
4001
+ min: 0,
4002
+ setValue: onChange('min')
4003
+ });
4004
+ }
4005
+
4006
+ function Max(props) {
4007
+ const {
4008
+ field,
4009
+ getValue,
4010
+ id,
4011
+ onChange
4012
+ } = props;
4013
+ const debounce = useService('debounce');
4014
+ return NumberFieldEntry({
4015
+ debounce,
4016
+ element: field,
4017
+ getValue: getValue('max'),
2120
4018
  id,
2121
- properties = {}
4019
+ label: 'Maximum',
4020
+ min: 0,
4021
+ setValue: onChange('max')
4022
+ });
4023
+ }
4024
+
4025
+ function ValuesGroups(field, editField) {
4026
+ const {
4027
+ type,
4028
+ id: fieldId
4029
+ } = field;
4030
+
4031
+ if (!VALUES_INPUTS.includes(type)) {
4032
+ return [];
4033
+ }
4034
+
4035
+ const context = {
4036
+ editField,
4037
+ field
4038
+ };
4039
+ const valuesSourceId = `${fieldId}-valuesSource`;
4040
+ /**
4041
+ * @type {Array<Group|ListGroup>}
4042
+ */
4043
+
4044
+ const groups = [{
4045
+ id: valuesSourceId,
4046
+ label: 'Values source',
4047
+ component: Group,
4048
+ entries: ValuesSourceSelectEntry({ ...context,
4049
+ id: valuesSourceId
4050
+ })
4051
+ }];
4052
+ const valuesSource = getValuesSource(field);
4053
+
4054
+ if (valuesSource === VALUES_SOURCES.INPUT) {
4055
+ const dynamicValuesId = `${fieldId}-dynamicValues`;
4056
+ groups.push({
4057
+ id: dynamicValuesId,
4058
+ label: 'Dynamic values',
4059
+ component: Group,
4060
+ entries: InputKeyValuesSourceEntry({ ...context,
4061
+ id: dynamicValuesId
4062
+ })
4063
+ });
4064
+ } else if (valuesSource === VALUES_SOURCES.STATIC) {
4065
+ const staticValuesId = `${fieldId}-staticValues`;
4066
+ groups.push({
4067
+ id: staticValuesId,
4068
+ label: 'Static values',
4069
+ component: ListGroup,
4070
+ ...StaticValuesSourceEntry({ ...context,
4071
+ id: staticValuesId
4072
+ })
4073
+ });
4074
+ }
4075
+
4076
+ return groups;
4077
+ }
4078
+
4079
+ function CustomValuesGroup(field, editField) {
4080
+ const {
4081
+ properties = {},
4082
+ type
2122
4083
  } = field;
2123
4084
 
2124
- const addEntry = () => {
4085
+ if (type === 'default') {
4086
+ return null;
4087
+ }
4088
+
4089
+ const addEntry = event => {
4090
+ event.stopPropagation();
2125
4091
  const index = Object.keys(properties).length + 1;
2126
4092
  const key = `key${index}`,
2127
4093
  value = 'value';
@@ -2146,28 +4112,35 @@ function CustomValuesGroup(field, editField) {
2146
4112
  };
2147
4113
  };
2148
4114
 
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
- };
4115
+ const items = Object.keys(properties).map((key, index) => {
4116
+ const removeEntry = event => {
4117
+ event.stopPropagation();
4118
+ return editField(field, ['properties'], removeKey(properties, key));
4119
+ };
2158
4120
 
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
2167
- })
2168
- }, `${id}-${index}`);
2169
- })
4121
+ const id = `${field.id}-property-${index}`;
4122
+ return {
4123
+ autoFocusEntry: id + '-key',
4124
+ entries: CustomValueEntry({
4125
+ editField,
4126
+ field,
4127
+ idPrefix: id,
4128
+ index,
4129
+ validateFactory
4130
+ }),
4131
+ id,
4132
+ label: key || '',
4133
+ remove: removeEntry
4134
+ };
2170
4135
  });
4136
+ return {
4137
+ add: addEntry,
4138
+ component: ListGroup,
4139
+ id: 'custom-values',
4140
+ items,
4141
+ label: 'Custom properties',
4142
+ shouldSort: false
4143
+ };
2171
4144
  } // helpers //////////
2172
4145
 
2173
4146
  /**
@@ -2193,95 +4166,54 @@ function removeKey(properties, oldKey) {
2193
4166
  }, {});
2194
4167
  }
2195
4168
 
2196
- const labelsByType = {
2197
- button: 'BUTTON',
2198
- checkbox: 'CHECKBOX',
2199
- columns: 'COLUMNS',
2200
- default: 'FORM',
2201
- number: 'NUMBER',
2202
- radio: 'RADIO',
2203
- select: 'SELECT',
2204
- text: 'TEXT',
2205
- textfield: 'TEXT FIELD'
2206
- };
2207
-
2208
4169
  function getGroups(field, editField) {
2209
- const {
2210
- type
2211
- } = field;
2212
- const groups = [GeneralGroup(field, editField)];
2213
-
2214
- if (type === 'radio' || type === 'select') {
2215
- groups.push(ValuesGroup(field, editField));
2216
- }
2217
-
2218
- if (INPUTS.includes(type) && type !== 'checkbox') {
2219
- groups.push(ValidationGroup(field, editField));
4170
+ if (!field) {
4171
+ return [];
2220
4172
  }
2221
4173
 
2222
- if (type !== 'default') {
2223
- groups.push(CustomValuesGroup(field, editField));
2224
- }
4174
+ const groups = [GeneralGroup(field, editField), ...ValuesGroups(field, editField), ValidationGroup(field, editField), CustomValuesGroup(field, editField)]; // contract: if a group returns null, it should not be displayed at all
2225
4175
 
2226
- return groups;
4176
+ return groups.filter(group => group !== null);
2227
4177
  }
2228
4178
 
2229
- function PropertiesPanel(props) {
4179
+ function FormPropertiesPanel(props) {
2230
4180
  const {
2231
4181
  editField,
2232
4182
  field
2233
4183
  } = props;
2234
4184
  const eventBus = useService('eventBus');
2235
4185
 
2236
- if (!field) {
2237
- return jsx("div", {
2238
- class: "fjs-properties-panel-placeholder",
2239
- children: "Select a form field to edit its properties."
2240
- });
2241
- }
2242
-
2243
4186
  const onFocus = () => eventBus.fire('propertiesPanel.focusin');
2244
4187
 
2245
4188
  const onBlur = () => eventBus.fire('propertiesPanel.focusout');
2246
4189
 
2247
- const {
2248
- type
2249
- } = field;
2250
- const Icon = iconsByType[type];
2251
- const label = labelsByType[type];
2252
- return jsxs("div", {
4190
+ return jsx("div", {
2253
4191
  class: "fjs-properties-panel",
2254
- "data-field": field.id,
4192
+ "data-field": field && field.id,
2255
4193
  onFocusCapture: onFocus,
2256
4194
  onBlurCapture: onBlur,
2257
- children: [jsxs("div", {
2258
- class: "fjs-properties-panel-header",
2259
- children: [jsx("div", {
2260
- class: "fjs-properties-panel-header-icon",
2261
- children: jsx(Icon, {
2262
- width: "36",
2263
- height: "36",
2264
- viewBox: "0 0 54 54"
2265
- })
2266
- }), jsxs("div", {
2267
- children: [jsx("span", {
2268
- class: "fjs-properties-panel-header-type",
2269
- children: label
2270
- }), type === 'text' ? jsx("div", {
2271
- class: "fjs-properties-panel-header-label",
2272
- children: textToLabel(field.text)
2273
- }) : type === 'default' ? jsx("div", {
2274
- class: "fjs-properties-panel-header-label",
2275
- children: field.id
2276
- }) : jsx("div", {
2277
- class: "fjs-properties-panel-header-label",
2278
- children: field.label
2279
- })]
2280
- })]
2281
- }), getGroups(field, editField)]
4195
+ children: jsx(PropertiesPanel, {
4196
+ element: field,
4197
+ eventBus: eventBus,
4198
+ groups: getGroups(field, editField),
4199
+ headerProvider: PropertiesPanelHeaderProvider,
4200
+ placeholderProvider: PropertiesPanelPlaceholderProvider
4201
+ })
2282
4202
  });
2283
4203
  }
2284
4204
 
4205
+ 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); }
4206
+ var ListDeleteIcon = (({
4207
+ styles = {},
4208
+ ...props
4209
+ }) => /*#__PURE__*/React.createElement("svg", _extends({
4210
+ xmlns: "http://www.w3.org/2000/svg",
4211
+ width: "11",
4212
+ height: "14"
4213
+ }, props), /*#__PURE__*/React.createElement("path", {
4214
+ d: "M10 4v8c0 1.1-.9 2-2 2H3c-1.1 0-2-.9-2-2V4h9zM8 6H3v4.8c0 .66.5 1.2 1.111 1.2H6.89C7.5 12 8 11.46 8 10.8V6zm3-5H8.5l-1-1h-4l-1 1H0v1.5h11V1z"
4215
+ })));
4216
+
2285
4217
  function ContextPad(props) {
2286
4218
  if (!props.children) {
2287
4219
  return null;
@@ -2542,7 +4474,7 @@ function FormEditor$1(props) {
2542
4474
  }), jsx(CreatePreview, {})]
2543
4475
  }), jsx("div", {
2544
4476
  class: "fjs-properties-container",
2545
- children: jsx(PropertiesPanel, {
4477
+ children: jsx(FormPropertiesPanel, {
2546
4478
  field: selectedFormField,
2547
4479
  editField: editField
2548
4480
  })