@bpmn-io/form-js-editor 0.7.1 → 0.8.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. package/README.md +1 -0
  2. package/dist/assets/form-js-editor.css +26 -214
  3. package/dist/assets/properties-panel.css +930 -0
  4. package/dist/index.cjs +3099 -1072
  5. package/dist/index.cjs.map +1 -1
  6. package/dist/index.es.js +3036 -1010
  7. package/dist/index.es.js.map +1 -1
  8. package/dist/types/FormEditor.d.ts +6 -4
  9. package/dist/types/features/palette/PaletteRenderer.d.ts +33 -0
  10. package/dist/types/{render/components/palette → features/palette/components}/Palette.d.ts +0 -0
  11. package/dist/types/features/palette/index.d.ts +5 -0
  12. package/dist/types/render/Renderer.d.ts +1 -1
  13. package/dist/types/render/components/{palette/icons → icons}/index.d.ts +2 -0
  14. package/dist/types/render/components/properties-panel/PropertiesPanel.d.ts +1 -1
  15. package/dist/types/render/components/properties-panel/PropertiesPanelHeaderProvider.d.ts +5 -0
  16. package/dist/types/render/components/properties-panel/PropertiesPanelPlaceholderProvider.d.ts +8 -0
  17. package/dist/types/render/components/properties-panel/Util.d.ts +1 -0
  18. package/dist/types/render/components/properties-panel/entries/ActionEntry.d.ts +9 -1
  19. package/dist/types/render/components/properties-panel/entries/ColumnsEntry.d.ts +9 -1
  20. package/dist/types/render/components/properties-panel/entries/CustomValueEntry.d.ts +11 -1
  21. package/dist/types/render/components/properties-panel/entries/DefaultValueEntry.d.ts +1 -1
  22. package/dist/types/render/components/properties-panel/entries/DescriptionEntry.d.ts +9 -1
  23. package/dist/types/render/components/properties-panel/entries/DisabledEntry.d.ts +9 -1
  24. package/dist/types/render/components/properties-panel/entries/IdEntry.d.ts +9 -1
  25. package/dist/types/render/components/properties-panel/entries/InputKeyValuesSourceEntry.d.ts +11 -0
  26. package/dist/types/render/components/properties-panel/entries/KeyEntry.d.ts +9 -1
  27. package/dist/types/render/components/properties-panel/entries/LabelEntry.d.ts +9 -1
  28. package/dist/types/render/components/properties-panel/entries/StaticValuesSourceEntry.d.ts +4 -0
  29. package/dist/types/render/components/properties-panel/entries/TextEntry.d.ts +9 -1
  30. package/dist/types/render/components/properties-panel/entries/ValueEntry.d.ts +11 -1
  31. package/dist/types/render/components/properties-panel/entries/ValuesSourceSelectEntry.d.ts +9 -0
  32. package/dist/types/render/components/properties-panel/entries/ValuesSourceUtil.d.ts +15 -0
  33. package/dist/types/render/components/properties-panel/entries/index.d.ts +3 -0
  34. package/dist/types/render/components/properties-panel/groups/CustomValuesGroup.d.ts +22 -1
  35. package/dist/types/render/components/properties-panel/groups/GeneralGroup.d.ts +5 -1
  36. package/dist/types/render/components/properties-panel/groups/ValidationGroup.d.ts +14 -1
  37. package/dist/types/render/components/properties-panel/groups/ValuesGroups.d.ts +1 -0
  38. package/dist/types/render/components/properties-panel/groups/index.d.ts +1 -1
  39. package/package.json +5 -4
  40. package/dist/types/render/components/properties-panel/components/CheckboxInput.d.ts +0 -1
  41. package/dist/types/render/components/properties-panel/components/CheckboxInputEntry.d.ts +0 -1
  42. package/dist/types/render/components/properties-panel/components/CollapsibleEntry.d.ts +0 -1
  43. package/dist/types/render/components/properties-panel/components/Group.d.ts +0 -1
  44. package/dist/types/render/components/properties-panel/components/NumberInput.d.ts +0 -1
  45. package/dist/types/render/components/properties-panel/components/NumberInputEntry.d.ts +0 -1
  46. package/dist/types/render/components/properties-panel/components/Select.d.ts +0 -1
  47. package/dist/types/render/components/properties-panel/components/SelectEntry.d.ts +0 -1
  48. package/dist/types/render/components/properties-panel/components/TextInput.d.ts +0 -1
  49. package/dist/types/render/components/properties-panel/components/TextInputEntry.d.ts +0 -1
  50. package/dist/types/render/components/properties-panel/components/Textarea.d.ts +0 -1
  51. package/dist/types/render/components/properties-panel/components/TextareaEntry.d.ts +0 -1
  52. package/dist/types/render/components/properties-panel/components/index.d.ts +0 -12
  53. 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
+ import classnames from 'classnames';
7
8
  import React from 'preact/compat';
8
- import { jsxs, jsx, Fragment } from 'preact/jsx-runtime';
9
+ import { jsx, jsxs } from 'preact/jsx-runtime';
10
+ import { query, matches, closest, event, domify } 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,36 +766,1710 @@ 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
+ var ArrowIcon = function ArrowIcon(props) {
770
+ return jsx("svg", { ...props,
771
+ children: jsx("path", {
772
+ fillRule: "evenodd",
773
+ 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"
774
+ })
775
+ });
776
+ };
777
+
778
+ ArrowIcon.defaultProps = {
779
+ xmlns: "http://www.w3.org/2000/svg",
780
+ width: "16",
781
+ height: "16"
782
+ };
783
+
784
+ var CreateIcon = function CreateIcon(props) {
785
+ return jsx("svg", { ...props,
786
+ children: jsx("path", {
787
+ fillRule: "evenodd",
788
+ 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"
789
+ })
790
+ });
791
+ };
792
+
793
+ CreateIcon.defaultProps = {
794
+ xmlns: "http://www.w3.org/2000/svg",
795
+ width: "16",
796
+ height: "16"
797
+ };
798
+
799
+ var DeleteIcon = function DeleteIcon(props) {
800
+ return jsx("svg", { ...props,
801
+ children: jsx("path", {
802
+ fillRule: "evenodd",
803
+ 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"
804
+ })
805
+ });
806
+ };
807
+
808
+ DeleteIcon.defaultProps = {
809
+ xmlns: "http://www.w3.org/2000/svg",
810
+ width: "16",
811
+ height: "16"
812
+ };
813
+
814
+ var ExternalLinkIcon = function ExternalLinkIcon(props) {
815
+ return jsx("svg", { ...props,
816
+ children: jsx("path", {
817
+ fillRule: "evenodd",
818
+ clipRule: "evenodd",
819
+ 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",
820
+ fill: "#818798"
821
+ })
822
+ });
823
+ };
824
+
825
+ ExternalLinkIcon.defaultProps = {
826
+ width: "16",
827
+ height: "16",
828
+ fill: "none",
829
+ xmlns: "http://www.w3.org/2000/svg"
830
+ };
831
+
832
+ var FeelRequiredIcon = function FeelRequiredIcon(props) {
833
+ return jsxs("svg", { ...props,
834
+ children: [jsx("path", {
835
+ d: "M5.8 7.06V5.95h4.307v1.11H5.8zm0 3.071v-1.11h4.307v1.11H5.8z",
836
+ fill: "#505562"
837
+ }), jsx("path", {
838
+ fillRule: "evenodd",
839
+ clipRule: "evenodd",
840
+ d: "M8 3.268A4.732 4.732 0 1 0 12.732 8H14a6 6 0 1 1-6-6v1.268z",
841
+ fill: "#505562"
842
+ }), jsx("path", {
843
+ 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",
844
+ fill: "#505562"
845
+ })]
846
+ });
847
+ };
848
+
849
+ FeelRequiredIcon.defaultProps = {
850
+ viewBox: "0 0 16 16",
851
+ fill: "none",
852
+ xmlns: "http://www.w3.org/2000/svg"
853
+ };
854
+
855
+ var FeelOptionalIcon = function FeelOptionalIcon(props) {
856
+ return jsxs("svg", { ...props,
857
+ children: [jsx("path", {
858
+ d: "M5.845 7.04V5.93h4.307v1.11H5.845zm0 3.07V9h4.307v1.11H5.845z",
859
+ fill: "#505562"
860
+ }), jsx("path", {
861
+ fillRule: "evenodd",
862
+ clipRule: "evenodd",
863
+ 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",
864
+ fill: "#505562"
865
+ })]
866
+ });
867
+ };
868
+
869
+ FeelOptionalIcon.defaultProps = {
870
+ viewBox: "0 0 16 16",
871
+ fill: "none",
872
+ xmlns: "http://www.w3.org/2000/svg"
873
+ };
874
+
875
+ function Header(props) {
876
+ const {
877
+ element,
878
+ headerProvider
879
+ } = props;
880
+ const {
881
+ getElementIcon,
882
+ getDocumentationRef,
883
+ getElementLabel,
884
+ getTypeLabel
885
+ } = headerProvider;
886
+ const label = getElementLabel(element);
887
+ const type = getTypeLabel(element);
888
+ const documentationRef = getDocumentationRef && getDocumentationRef(element);
889
+ const ElementIcon = getElementIcon(element);
890
+ return jsxs("div", {
891
+ class: "bio-properties-panel-header",
892
+ children: [jsx("div", {
893
+ class: "bio-properties-panel-header-icon",
894
+ children: ElementIcon && jsx(ElementIcon, {
895
+ width: "32",
896
+ height: "32",
897
+ viewBox: "0 0 32 32"
898
+ })
899
+ }), jsxs("div", {
900
+ class: "bio-properties-panel-header-labels",
901
+ children: [jsx("div", {
902
+ title: type,
903
+ class: "bio-properties-panel-header-type",
904
+ children: type
905
+ }), label ? jsx("div", {
906
+ title: label,
907
+ class: "bio-properties-panel-header-label",
908
+ children: label
909
+ }) : null]
910
+ }), jsx("div", {
911
+ class: "bio-properties-panel-header-actions",
912
+ children: documentationRef ? jsx("a", {
913
+ rel: "noopener",
914
+ class: "bio-properties-panel-header-link",
915
+ href: documentationRef,
916
+ title: "Open documentation",
917
+ target: "_blank",
918
+ children: jsx(ExternalLinkIcon, {})
919
+ }) : null
920
+ })]
921
+ });
922
+ }
923
+
924
+ const DescriptionContext = createContext({
925
+ description: {},
926
+ getDescriptionForId: () => {}
927
+ });
928
+ /**
929
+ * @typedef {Function} <propertiesPanel.showEntry> callback
930
+ *
931
+ * @example
932
+ *
933
+ * useEvent('propertiesPanel.showEntry', ({ focus = false, ...rest }) => {
934
+ * // ...
935
+ * });
936
+ *
937
+ * @param {Object} context
938
+ * @param {boolean} [context.focus]
939
+ *
940
+ * @returns void
941
+ */
942
+
943
+ const EventContext = createContext({
944
+ eventBus: null
945
+ });
946
+ const LayoutContext = createContext({
947
+ layout: {},
948
+ setLayout: () => {},
949
+ getLayoutForKey: () => {},
950
+ setLayoutForKey: () => {}
951
+ });
952
+ /**
953
+ * Accesses the global DescriptionContext and returns a description for a given id and element.
954
+ *
955
+ * @example
956
+ * ```jsx
957
+ * function TextField(props) {
958
+ * const description = useDescriptionContext('input1', element);
959
+ * }
960
+ * ```
961
+ *
962
+ * @param {string} id
963
+ * @param {object} element
964
+ *
965
+ * @returns {string}
966
+ */
967
+
968
+ function useDescriptionContext(id, element) {
969
+ const {
970
+ getDescriptionForId
971
+ } = useContext(DescriptionContext);
972
+ return getDescriptionForId(id, element);
973
+ }
974
+
975
+ const DEFAULT_PRIORITY$2 = 1000;
976
+ /**
977
+ * Subscribe to an event.
978
+ *
979
+ * @param {string} event
980
+ * @param {Function} callback
981
+ * @param {number} [priority]
982
+ *
983
+ * @returns {import('preact').Ref}
984
+ */
985
+
986
+ function useEvent(event, callback, priority = DEFAULT_PRIORITY$2) {
987
+ const {
988
+ eventBus
989
+ } = useContext(EventContext);
990
+ useEffect(() => {
991
+ if (!eventBus) {
992
+ return;
993
+ }
994
+
995
+ eventBus.on(event, priority, callback);
996
+ return () => eventBus.off(event, callback);
997
+ }, [callback, event, eventBus, priority]);
998
+ }
999
+
1000
+ const HIGH_PRIORITY = 10000;
1001
+ /**
1002
+ * Buffer events and re-fire during passive effect phase.
1003
+ *
1004
+ * @param {string[]} bufferedEvents
1005
+ * @param {Object} [eventBus]
1006
+ */
1007
+
1008
+ function useEventBuffer(bufferedEvents, eventBus) {
1009
+ const buffer = useRef([]),
1010
+ buffering = useRef(true);
1011
+
1012
+ const createCallback = event => data => {
1013
+ if (buffering.current === true) {
1014
+ buffer.current.unshift([event, data]);
1015
+ }
1016
+ }; // (1) buffer events
1017
+
1018
+
1019
+ useEffect(() => {
1020
+ if (!eventBus) {
1021
+ return;
1022
+ }
1023
+
1024
+ const listeners = bufferedEvents.map(event => {
1025
+ return [event, createCallback(event)];
1026
+ });
1027
+ listeners.forEach(([event, callback]) => {
1028
+ eventBus.on(event, HIGH_PRIORITY, callback);
1029
+ });
1030
+ return () => {
1031
+ listeners.forEach(([event, callback]) => {
1032
+ eventBus.off(event, callback);
1033
+ });
1034
+ };
1035
+ }, [bufferedEvents, eventBus]); // (2) re-fire events
1036
+
1037
+ useEffect(() => {
1038
+ if (!eventBus) {
1039
+ return;
1040
+ }
1041
+
1042
+ buffering.current = false;
1043
+
1044
+ while (buffer.current.length) {
1045
+ const [event, data] = buffer.current.pop();
1046
+ eventBus.fire(event, data);
1047
+ }
1048
+
1049
+ buffering.current = true;
1050
+ });
1051
+ }
1052
+ /**
1053
+ * Creates a state that persists in the global LayoutContext.
1054
+ *
1055
+ * @example
1056
+ * ```jsx
1057
+ * function Group(props) {
1058
+ * const [ open, setOpen ] = useLayoutState([ 'groups', 'foo', 'open' ], false);
1059
+ * }
1060
+ * ```
1061
+ *
1062
+ * @param {(string|number)[]} path
1063
+ * @param {any} [defaultValue]
1064
+ *
1065
+ * @returns {[ any, Function ]}
1066
+ */
1067
+
1068
+
1069
+ function useLayoutState(path, defaultValue) {
1070
+ const {
1071
+ getLayoutForKey,
1072
+ setLayoutForKey
1073
+ } = useContext(LayoutContext);
1074
+ const layoutForKey = getLayoutForKey(path, defaultValue);
1075
+ const [value, set] = useState(layoutForKey);
1076
+
1077
+ const setState = newValue => {
1078
+ // (1) set component state
1079
+ set(newValue); // (2) set context
1080
+
1081
+ setLayoutForKey(path, newValue);
1082
+ };
1083
+
1084
+ return [value, setState];
1085
+ }
1086
+ /**
1087
+ * @pinussilvestrus: we need to introduce our own hook to persist the previous
1088
+ * state on updates.
1089
+ *
1090
+ * cf. https://reactjs.org/docs/hooks-faq.html#how-to-get-the-previous-props-or-state
1091
+ */
1092
+
1093
+
1094
+ function usePrevious(value) {
1095
+ const ref = useRef();
1096
+ useEffect(() => {
1097
+ ref.current = value;
1098
+ });
1099
+ return ref.current;
1100
+ }
1101
+ /**
1102
+ * Subscribe to `propertiesPanel.showEntry`.
1103
+ *
1104
+ * @param {Function} show
1105
+ *
1106
+ * @returns {import('preact').Ref}
1107
+ */
1108
+
1109
+
1110
+ function useShowEntryEvent(show) {
1111
+ const {
1112
+ onShow
1113
+ } = useContext(LayoutContext);
1114
+ const ref = useRef();
1115
+ const [focus, setFocus] = useState(false);
1116
+ const onShowEntry = useCallback(event => {
1117
+ if (show(event)) {
1118
+ if (isFunction(onShow)) {
1119
+ onShow();
1120
+ }
1121
+
1122
+ if (event.focus && !focus) {
1123
+ setFocus(true);
1124
+ }
1125
+ }
1126
+ }, [show]);
1127
+ useEffect(() => {
1128
+ if (focus && ref.current) {
1129
+ if (isFunction(ref.current.focus)) {
1130
+ ref.current.focus();
1131
+ }
1132
+
1133
+ if (isFunction(ref.current.select)) {
1134
+ ref.current.select();
1135
+ }
1136
+
1137
+ setFocus(false);
1138
+ }
1139
+ }, [focus]);
1140
+ useEvent('propertiesPanel.showEntry', onShowEntry);
1141
+ return ref;
1142
+ }
1143
+ /**
1144
+ * Subscribe to `propertiesPanel.showError`. On `propertiesPanel.showError` set
1145
+ * temporary error. Fire `propertiesPanel.showEntry` for temporary error to be
1146
+ * visible. Unset error on `propertiesPanel.updated`.
1147
+ *
1148
+ * @param {Function} show
1149
+ *
1150
+ * @returns {import('preact').Ref}
1151
+ */
1152
+
1153
+
1154
+ function useShowErrorEvent(show) {
1155
+ const {
1156
+ eventBus
1157
+ } = useContext(EventContext);
1158
+ const [temporaryError, setTemporaryError] = useState(null);
1159
+ const onPropertiesPanelUpdated = useCallback(() => setTemporaryError(null), []);
1160
+ useEvent('propertiesPanel.updated', onPropertiesPanelUpdated);
1161
+ const onShowError = useCallback(event => {
1162
+ setTemporaryError(null);
1163
+
1164
+ if (show(event)) {
1165
+ if (eventBus) {
1166
+ eventBus.fire('propertiesPanel.showEntry', event);
1167
+ }
1168
+
1169
+ setTemporaryError(event.message);
1170
+ }
1171
+ }, [show]);
1172
+ useEvent('propertiesPanel.showError', onShowError);
1173
+ return temporaryError;
1174
+ }
1175
+ /**
1176
+ * @callback setSticky
1177
+ * @param {boolean} value
1178
+ */
1179
+
1180
+ /**
1181
+ * Use IntersectionObserver to identify when DOM element is in sticky mode.
1182
+ * If sticky is observered setSticky(true) will be called.
1183
+ * If sticky mode is left, setSticky(false) will be called.
1184
+ *
1185
+ *
1186
+ * @param {Object} ref
1187
+ * @param {string} scrollContainerSelector
1188
+ * @param {setSticky} setSticky
1189
+ */
1190
+
1191
+
1192
+ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
1193
+ useEffect(() => {
1194
+ // return early if IntersectionObserver is not available
1195
+ if (!IntersectionObserver) {
1196
+ return;
1197
+ }
1198
+
1199
+ let observer;
1200
+
1201
+ if (ref.current) {
1202
+ const scrollContainer = query(scrollContainerSelector);
1203
+ observer = new IntersectionObserver(entries => {
1204
+ if (entries[0].intersectionRatio < 1) {
1205
+ setSticky(true);
1206
+ } else if (entries[0].intersectionRatio === 1) {
1207
+ setSticky(false);
1208
+ }
1209
+ }, {
1210
+ root: scrollContainer,
1211
+ rootMargin: '0px 0px 999999% 0px',
1212
+ // Use bottom margin to avoid stickyness when scrolling out to bottom
1213
+ threshold: [1]
1214
+ });
1215
+ observer.observe(ref.current);
1216
+ } // Unobserve if unmounted
1217
+
1218
+
1219
+ return () => {
1220
+ if (ref.current && observer) {
1221
+ observer.unobserve(ref.current);
1222
+ }
1223
+ };
1224
+ }, [ref]);
1225
+ }
1226
+
1227
+ function Group(props) {
1228
+ const {
1229
+ element,
1230
+ entries = [],
1231
+ id,
1232
+ label,
1233
+ shouldOpen = false
1234
+ } = props;
1235
+ const groupRef = useRef(null);
1236
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
1237
+ const onShow = useCallback(() => setOpen(true), [setOpen]);
1238
+
1239
+ const toggleOpen = () => setOpen(!open);
1240
+
1241
+ const [edited, setEdited] = useState(false);
1242
+ const [sticky, setSticky] = useState(false); // set edited state depending on all entries
1243
+
1244
+ useEffect(() => {
1245
+ const hasOneEditedEntry = entries.find(entry => {
1246
+ const {
1247
+ id,
1248
+ isEdited
1249
+ } = entry;
1250
+ const entryNode = query(`[data-entry-id="${id}"]`);
1251
+
1252
+ if (!isFunction(isEdited) || !entryNode) {
1253
+ return false;
1254
+ }
1255
+
1256
+ const inputNode = query('.bio-properties-panel-input', entryNode);
1257
+ return isEdited(inputNode);
1258
+ });
1259
+ setEdited(hasOneEditedEntry);
1260
+ }, [entries]); // set css class when group is sticky to top
1261
+
1262
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
1263
+ const propertiesPanelContext = { ...useContext(LayoutContext),
1264
+ onShow
1265
+ };
1266
+ return jsxs("div", {
1267
+ class: "bio-properties-panel-group",
1268
+ "data-group-id": 'group-' + id,
1269
+ ref: groupRef,
1270
+ children: [jsxs("div", {
1271
+ class: classnames('bio-properties-panel-group-header', edited ? '' : 'empty', open ? 'open' : '', sticky && open ? 'sticky' : ''),
1272
+ onClick: toggleOpen,
1273
+ children: [jsx("div", {
1274
+ title: label,
1275
+ class: "bio-properties-panel-group-header-title",
1276
+ children: label
1277
+ }), jsxs("div", {
1278
+ class: "bio-properties-panel-group-header-buttons",
1279
+ children: [edited && jsx(DataMarker, {}), jsx("button", {
1280
+ title: "Toggle section",
1281
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
1282
+ children: jsx(ArrowIcon, {
1283
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1284
+ })
1285
+ })]
1286
+ })]
1287
+ }), jsx("div", {
1288
+ class: classnames('bio-properties-panel-group-entries', open ? 'open' : ''),
1289
+ children: jsx(LayoutContext.Provider, {
1290
+ value: propertiesPanelContext,
1291
+ children: entries.map(entry => {
1292
+ const {
1293
+ component: Component,
1294
+ id
1295
+ } = entry;
1296
+ return createElement(Component, { ...entry,
1297
+ element: element,
1298
+ key: id
1299
+ });
1300
+ })
1301
+ })
1302
+ })]
1303
+ });
1304
+ }
1305
+
1306
+ function DataMarker() {
1307
+ return jsx("div", {
1308
+ title: "Section contains data",
1309
+ class: "bio-properties-panel-dot"
1310
+ });
1311
+ }
1312
+ /**
1313
+ * @typedef { {
1314
+ * text: (element: object) => string,
1315
+ * icon?: (element: Object) => import('preact').Component
1316
+ * } } PlaceholderDefinition
1317
+ *
1318
+ * @param { PlaceholderDefinition } props
1319
+ */
1320
+
1321
+
1322
+ function Placeholder(props) {
1323
+ const {
1324
+ text,
1325
+ icon: Icon
1326
+ } = props;
1327
+ return jsx("div", {
1328
+ class: "bio-properties-panel open",
1329
+ children: jsxs("section", {
1330
+ class: "bio-properties-panel-placeholder",
1331
+ children: [Icon && jsx(Icon, {
1332
+ class: "bio-properties-panel-placeholder-icon"
1333
+ }), jsx("p", {
1334
+ class: "bio-properties-panel-placeholder-text",
1335
+ children: text
1336
+ })]
1337
+ })
1338
+ });
1339
+ }
1340
+
1341
+ const DEFAULT_LAYOUT = {
1342
+ open: true
1343
+ };
1344
+ const DEFAULT_DESCRIPTION = {};
1345
+ const bufferedEvents = ['propertiesPanel.showEntry', 'propertiesPanel.showError'];
1346
+ /**
1347
+ * @typedef { {
1348
+ * component: import('preact').Component,
1349
+ * id: String,
1350
+ * isEdited?: Function
1351
+ * } } EntryDefinition
1352
+ *
1353
+ * @typedef { {
1354
+ * autoFocusEntry: String,
1355
+ * autoOpen?: Boolean,
1356
+ * entries: Array<EntryDefinition>,
1357
+ * id: String,
1358
+ * label: String,
1359
+ * remove: (event: MouseEvent) => void
1360
+ * } } ListItemDefinition
1361
+ *
1362
+ * @typedef { {
1363
+ * add: (event: MouseEvent) => void,
1364
+ * component: import('preact').Component,
1365
+ * element: Object,
1366
+ * id: String,
1367
+ * items: Array<ListItemDefinition>,
1368
+ * label: String,
1369
+ * shouldSort?: Boolean,
1370
+ * shouldOpen?: Boolean
1371
+ * } } ListGroupDefinition
1372
+ *
1373
+ * @typedef { {
1374
+ * component?: import('preact').Component,
1375
+ * entries: Array<EntryDefinition>,
1376
+ * id: String,
1377
+ * label: String,
1378
+ * shouldOpen?: Boolean
1379
+ * } } GroupDefinition
1380
+ *
1381
+ * @typedef { {
1382
+ * [id: String]: GetDescriptionFunction
1383
+ * } } DescriptionConfig
1384
+ *
1385
+ * @callback { {
1386
+ * @param {string} id
1387
+ * @param {Object} element
1388
+ * @returns {string}
1389
+ * } } GetDescriptionFunction
1390
+ *
1391
+ * @typedef { {
1392
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
1393
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
1394
+ * } } PlaceholderProvider
1395
+ *
1396
+ */
1397
+
1398
+ /**
1399
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
1400
+ * data from implementor to describe *what* will be rendered.
1401
+ *
1402
+ * @param {Object} props
1403
+ * @param {Object|Array} props.element
1404
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
1405
+ * @param {PlaceholderProvider} [props.placeholderProvider]
1406
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
1407
+ * @param {Object} [props.layoutConfig]
1408
+ * @param {Function} [props.layoutChanged]
1409
+ * @param {DescriptionConfig} [props.descriptionConfig]
1410
+ * @param {Function} [props.descriptionLoaded]
1411
+ * @param {Object} [props.eventBus]
1412
+ */
1413
+
1414
+ function PropertiesPanel(props) {
1415
+ const {
1416
+ element,
1417
+ headerProvider,
1418
+ placeholderProvider,
1419
+ groups,
1420
+ layoutConfig = {},
1421
+ layoutChanged,
1422
+ descriptionConfig = {},
1423
+ descriptionLoaded,
1424
+ eventBus
1425
+ } = props; // set-up layout context
1426
+
1427
+ const [layout, setLayout] = useState(createLayout(layoutConfig));
1428
+ useEffect(() => {
1429
+ if (typeof layoutChanged === 'function') {
1430
+ layoutChanged(layout);
1431
+ }
1432
+ }, [layout, layoutChanged]);
1433
+
1434
+ const getLayoutForKey = (key, defaultValue) => {
1435
+ return get(layout, key, defaultValue);
1436
+ };
1437
+
1438
+ const setLayoutForKey = (key, config) => {
1439
+ const newLayout = assign({}, layout);
1440
+ set(newLayout, key, config);
1441
+ setLayout(newLayout);
1442
+ };
1443
+
1444
+ const layoutContext = {
1445
+ layout,
1446
+ setLayout,
1447
+ getLayoutForKey,
1448
+ setLayoutForKey
1449
+ }; // set-up description context
1450
+
1451
+ const description = createDescriptionContext(descriptionConfig);
1452
+
1453
+ if (typeof descriptionLoaded === 'function') {
1454
+ descriptionLoaded(description);
1455
+ }
1456
+
1457
+ const getDescriptionForId = (id, element) => {
1458
+ return description[id] && description[id](element);
1459
+ };
1460
+
1461
+ const descriptionContext = {
1462
+ description,
1463
+ getDescriptionForId
1464
+ };
1465
+ useEventBuffer(bufferedEvents, eventBus);
1466
+ const eventContext = {
1467
+ eventBus
1468
+ };
1469
+ const propertiesPanelContext = {
1470
+ element
1471
+ }; // empty state
1472
+
1473
+ if (placeholderProvider && !element) {
1474
+ return jsx(Placeholder, { ...placeholderProvider.getEmpty()
1475
+ });
1476
+ } // multiple state
1477
+
1478
+
1479
+ if (placeholderProvider && isArray(element)) {
1480
+ return jsx(Placeholder, { ...placeholderProvider.getMultiple()
1481
+ });
1482
+ }
1483
+
1484
+ return jsx(LayoutContext.Provider, {
1485
+ value: propertiesPanelContext,
1486
+ children: jsx(DescriptionContext.Provider, {
1487
+ value: descriptionContext,
1488
+ children: jsx(LayoutContext.Provider, {
1489
+ value: layoutContext,
1490
+ children: jsx(EventContext.Provider, {
1491
+ value: eventContext,
1492
+ children: jsxs("div", {
1493
+ class: classnames('bio-properties-panel', layout.open ? 'open' : ''),
1494
+ children: [jsx(Header, {
1495
+ element: element,
1496
+ headerProvider: headerProvider
1497
+ }), jsx("div", {
1498
+ class: "bio-properties-panel-scroll-container",
1499
+ children: groups.map(group => {
1500
+ const {
1501
+ component: Component = Group,
1502
+ id
1503
+ } = group;
1504
+ return createElement(Component, { ...group,
1505
+ key: id,
1506
+ element: element
1507
+ });
1508
+ })
1509
+ })]
1510
+ })
1511
+ })
1512
+ })
1513
+ })
1514
+ });
1515
+ } // helpers //////////////////
1516
+
1517
+
1518
+ function createLayout(overrides) {
1519
+ return { ...DEFAULT_LAYOUT,
1520
+ ...overrides
1521
+ };
1522
+ }
1523
+
1524
+ function createDescriptionContext(overrides) {
1525
+ return { ...DEFAULT_DESCRIPTION,
1526
+ ...overrides
1527
+ };
1528
+ }
1529
+
1530
+ function CollapsibleEntry(props) {
1531
+ const {
1532
+ element,
1533
+ entries = [],
1534
+ id,
1535
+ label,
1536
+ open: shouldOpen,
1537
+ remove
1538
+ } = props;
1539
+ const [open, setOpen] = useState(shouldOpen);
1540
+
1541
+ const toggleOpen = () => setOpen(!open);
1542
+
1543
+ const {
1544
+ onShow
1545
+ } = useContext(LayoutContext);
1546
+ const propertiesPanelContext = { ...useContext(LayoutContext),
1547
+ onShow: useCallback(() => {
1548
+ setOpen(true);
1549
+
1550
+ if (isFunction(onShow)) {
1551
+ onShow();
1552
+ }
1553
+ }, [onShow, setOpen])
1554
+ }; // todo(pinussilvestrus): translate once we have a translate mechanism for the core
1555
+
1556
+ const placeholderLabel = '<empty>';
1557
+ return jsxs("div", {
1558
+ "data-entry-id": id,
1559
+ class: classnames('bio-properties-panel-collapsible-entry', open ? 'open' : ''),
1560
+ children: [jsxs("div", {
1561
+ class: "bio-properties-panel-collapsible-entry-header",
1562
+ onClick: toggleOpen,
1563
+ children: [jsx("div", {
1564
+ title: label || placeholderLabel,
1565
+ class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
1566
+ children: label || placeholderLabel
1567
+ }), jsx("button", {
1568
+ title: "Toggle list item",
1569
+ class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
1570
+ children: jsx(ArrowIcon, {
1571
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1572
+ })
1573
+ }), remove ? jsx("button", {
1574
+ title: "Delete item",
1575
+ class: "bio-properties-panel-remove-entry",
1576
+ onClick: remove,
1577
+ children: jsx(DeleteIcon, {})
1578
+ }) : null]
1579
+ }), jsx("div", {
1580
+ class: classnames('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
1581
+ children: jsx(LayoutContext.Provider, {
1582
+ value: propertiesPanelContext,
1583
+ children: entries.map(entry => {
1584
+ const {
1585
+ component: Component,
1586
+ id
1587
+ } = entry;
1588
+ return createElement(Component, { ...entry,
1589
+ element: element,
1590
+ key: id
1591
+ });
1592
+ })
1593
+ })
1594
+ })]
1595
+ });
1596
+ }
1597
+
1598
+ function ListItem(props) {
1599
+ const {
1600
+ autoFocusEntry,
1601
+ autoOpen
1602
+ } = props; // focus specified entry on auto open
1603
+
1604
+ useEffect(() => {
1605
+ if (autoOpen && autoFocusEntry) {
1606
+ const entry = query(`[data-entry-id="${autoFocusEntry}"]`);
1607
+ const focusableInput = query('.bio-properties-panel-input', entry);
1608
+
1609
+ if (focusableInput) {
1610
+ if (isFunction(focusableInput.select)) {
1611
+ focusableInput.select();
1612
+ } else if (isFunction(focusableInput.focus)) {
1613
+ focusableInput.focus();
1614
+ }
1615
+ }
1616
+ }
1617
+ }, [autoOpen, autoFocusEntry]);
1618
+ return jsx("div", {
1619
+ class: "bio-properties-panel-list-item",
1620
+ children: jsx(CollapsibleEntry, { ...props,
1621
+ open: autoOpen
1622
+ })
1623
+ });
1624
+ }
1625
+
1626
+ const noop$3 = () => {};
1627
+ /**
1628
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
1629
+ */
1630
+
1631
+
1632
+ function ListGroup(props) {
1633
+ const {
1634
+ add,
1635
+ element,
1636
+ id,
1637
+ items,
1638
+ label,
1639
+ shouldOpen = true,
1640
+ shouldSort = true
1641
+ } = props;
1642
+ const groupRef = useRef(null);
1643
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
1644
+ const [sticky, setSticky] = useState(false);
1645
+ const onShow = useCallback(() => setOpen(true), [setOpen]);
1646
+ const [ordering, setOrdering] = useState([]);
1647
+ const [newItemAdded, setNewItemAdded] = useState(false);
1648
+ const prevItems = usePrevious(items);
1649
+ const prevElement = usePrevious(element);
1650
+ const elementChanged = element !== prevElement;
1651
+ const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen); // reset initial ordering when element changes (before first render)
1652
+
1653
+ if (elementChanged) {
1654
+ setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
1655
+ } // keep ordering in sync to items - and open changes
1656
+ // (0) set initial ordering from given items
1657
+
1658
+
1659
+ useEffect(() => {
1660
+ if (!prevItems || !shouldSort) {
1661
+ setOrdering(createOrdering(items));
1662
+ }
1663
+ }, [items, element]); // (1) items were added
1664
+
1665
+ useEffect(() => {
1666
+ if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
1667
+ let add = [];
1668
+ items.forEach(item => {
1669
+ if (!ordering.includes(item.id)) {
1670
+ add.push(item.id);
1671
+ }
1672
+ });
1673
+ let newOrdering = ordering; // open if not open and configured
1674
+
1675
+ if (!open && shouldOpen) {
1676
+ toggleOpen(); // if I opened and I should sort, then sort items
1677
+
1678
+ if (shouldSort) {
1679
+ newOrdering = createOrdering(sortItems(items));
1680
+ }
1681
+ } // add new items on top or bottom depending on sorting behavior
1682
+
1683
+
1684
+ newOrdering = newOrdering.filter(item => !add.includes(item));
1685
+
1686
+ if (shouldSort) {
1687
+ newOrdering.unshift(...add);
1688
+ } else {
1689
+ newOrdering.push(...add);
1690
+ }
1691
+
1692
+ setOrdering(newOrdering);
1693
+ setNewItemAdded(true);
1694
+ } else {
1695
+ setNewItemAdded(false);
1696
+ }
1697
+ }, [items, open, shouldHandleEffects]); // (2) sort items on open if shouldSort is set
1698
+
1699
+ useEffect(() => {
1700
+ if (shouldSort && open && !newItemAdded) {
1701
+ setOrdering(createOrdering(sortItems(items)));
1702
+ }
1703
+ }, [open, shouldSort]); // (3) items were deleted
1704
+
1705
+ useEffect(() => {
1706
+ if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
1707
+ let keep = [];
1708
+ ordering.forEach(o => {
1709
+ if (getItem(items, o)) {
1710
+ keep.push(o);
1711
+ }
1712
+ });
1713
+ setOrdering(keep);
1714
+ }
1715
+ }, [items, shouldHandleEffects]); // set css class when group is sticky to top
1716
+
1717
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
1718
+
1719
+ const toggleOpen = () => setOpen(!open);
1720
+
1721
+ const hasItems = !!items.length;
1722
+ const propertiesPanelContext = { ...useContext(LayoutContext),
1723
+ onShow
1724
+ };
1725
+ return jsxs("div", {
1726
+ class: "bio-properties-panel-group",
1727
+ "data-group-id": 'group-' + id,
1728
+ ref: groupRef,
1729
+ children: [jsxs("div", {
1730
+ class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
1731
+ onClick: hasItems ? toggleOpen : noop$3,
1732
+ children: [jsx("div", {
1733
+ title: label,
1734
+ class: "bio-properties-panel-group-header-title",
1735
+ children: label
1736
+ }), jsxs("div", {
1737
+ class: "bio-properties-panel-group-header-buttons",
1738
+ children: [add ? jsxs("button", {
1739
+ title: "Create new list item",
1740
+ class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
1741
+ onClick: add,
1742
+ children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
1743
+ class: "bio-properties-panel-add-entry-label",
1744
+ children: "Create"
1745
+ }) : null]
1746
+ }) : null, hasItems ? jsx("div", {
1747
+ title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
1748
+ class: "bio-properties-panel-list-badge",
1749
+ children: items.length
1750
+ }) : null, hasItems ? jsx("button", {
1751
+ title: "Toggle section",
1752
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
1753
+ children: jsx(ArrowIcon, {
1754
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1755
+ })
1756
+ }) : null]
1757
+ })]
1758
+ }), jsx("div", {
1759
+ class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
1760
+ children: jsx(LayoutContext.Provider, {
1761
+ value: propertiesPanelContext,
1762
+ children: ordering.map((o, index) => {
1763
+ const item = getItem(items, o);
1764
+
1765
+ if (!item) {
1766
+ return;
1767
+ }
1768
+
1769
+ const {
1770
+ id
1771
+ } = item; // if item was added, open first or last item based on ordering
1772
+
1773
+ const autoOpen = newItemAdded && (shouldSort ? index === 0 : index === ordering.length - 1);
1774
+ return createElement(ListItem, { ...item,
1775
+ autoOpen: autoOpen,
1776
+ element: element,
1777
+ index: index,
1778
+ key: id
1779
+ });
1780
+ })
1781
+ })
1782
+ })]
1783
+ });
1784
+ } // helpers ////////////////////
1785
+
1786
+ /**
1787
+ * Sorts given items alphanumeric by label
1788
+ */
1789
+
1790
+
1791
+ function sortItems(items) {
1792
+ return sortBy(items, i => i.label.toLowerCase());
1793
+ }
1794
+
1795
+ function getItem(items, id) {
1796
+ return find(items, i => i.id === id);
1797
+ }
1798
+
1799
+ function createOrdering(items) {
1800
+ return items.map(i => i.id);
1801
+ }
1802
+
1803
+ function Description$1(props) {
1804
+ const {
1805
+ element,
1806
+ forId,
1807
+ value
1808
+ } = props;
1809
+ const contextDescription = useDescriptionContext(forId, element);
1810
+ const description = value || contextDescription;
1811
+
1812
+ if (description) {
1813
+ return jsx("div", {
1814
+ class: "bio-properties-panel-description",
1815
+ children: description
1816
+ });
1817
+ }
1818
+ }
1819
+
1820
+ const noop$2 = () => {};
1821
+
1822
+ function Checkbox(props) {
1823
+ const {
1824
+ id,
1825
+ label,
1826
+ onChange,
1827
+ disabled,
1828
+ value = false,
1829
+ show = noop$2
1830
+ } = props;
1831
+
1832
+ const handleChange = ({
1833
+ target
1834
+ }) => {
1835
+ onChange(target.checked);
1836
+ };
1837
+
1838
+ const ref = useShowEntryEvent(show);
1839
+ return jsxs("div", {
1840
+ class: "bio-properties-panel-checkbox",
1841
+ children: [jsx("input", {
1842
+ ref: ref,
1843
+ id: prefixId$6(id),
1844
+ name: id,
1845
+ type: "checkbox",
1846
+ class: "bio-properties-panel-input",
1847
+ onChange: handleChange,
1848
+ checked: value,
1849
+ disabled: disabled
1850
+ }), jsx("label", {
1851
+ for: prefixId$6(id),
1852
+ class: "bio-properties-panel-label",
1853
+ children: label
1854
+ })]
1855
+ });
1856
+ }
1857
+ /**
1858
+ * @param {Object} props
1859
+ * @param {Object} props.element
1860
+ * @param {String} props.id
1861
+ * @param {String} props.description
1862
+ * @param {String} props.label
1863
+ * @param {Function} props.getValue
1864
+ * @param {Function} props.setValue
1865
+ * @param {boolean} [props.disabled]
1866
+ */
1867
+
1868
+
1869
+ function CheckboxEntry(props) {
1870
+ const {
1871
+ element,
1872
+ id,
1873
+ description,
1874
+ label,
1875
+ getValue,
1876
+ setValue,
1877
+ disabled,
1878
+ show = noop$2
1879
+ } = props;
1880
+ const value = getValue(element);
1881
+ const error = useShowErrorEvent(show);
1882
+ return jsxs("div", {
1883
+ class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
1884
+ "data-entry-id": id,
1885
+ children: [jsx(Checkbox, {
1886
+ disabled: disabled,
1887
+ id: id,
1888
+ label: label,
1889
+ onChange: setValue,
1890
+ show: show,
1891
+ value: value
1892
+ }), error && jsx("div", {
1893
+ class: "bio-properties-panel-error",
1894
+ children: error
1895
+ }), jsx(Description$1, {
1896
+ forId: id,
1897
+ element: element,
1898
+ value: description
1899
+ })]
1900
+ });
1901
+ }
1902
+
1903
+ function isEdited$6(node) {
1904
+ return node && !!node.checked;
1905
+ } // helpers /////////////////
1906
+
1907
+
1908
+ function prefixId$6(id) {
1909
+ return `bio-properties-panel-${id}`;
1910
+ }
1911
+
1912
+ function NumberField(props) {
1913
+ const {
1914
+ debounce,
1915
+ disabled,
1916
+ id,
1917
+ label,
1918
+ max,
1919
+ min,
1920
+ onInput,
1921
+ step,
1922
+ value = ''
1923
+ } = props;
1924
+ const handleInput = useMemo(() => {
1925
+ return debounce(event => {
1926
+ const {
1927
+ validity,
1928
+ value
1929
+ } = event.target;
1930
+
1931
+ if (validity.valid) {
1932
+ onInput(value ? parseFloat(value) : undefined);
1933
+ }
1934
+ });
1935
+ }, [onInput, debounce]);
1936
+ return jsxs("div", {
1937
+ class: "bio-properties-panel-numberfield",
1938
+ children: [jsx("label", {
1939
+ for: prefixId$5(id),
1940
+ class: "bio-properties-panel-label",
1941
+ children: label
1942
+ }), jsx("input", {
1943
+ id: prefixId$5(id),
1944
+ type: "number",
1945
+ name: id,
1946
+ spellCheck: "false",
1947
+ autoComplete: "off",
1948
+ disabled: disabled,
1949
+ class: "bio-properties-panel-input",
1950
+ max: max,
1951
+ min: min,
1952
+ onInput: handleInput,
1953
+ step: step,
1954
+ value: value
1955
+ })]
1956
+ });
1957
+ }
1958
+ /**
1959
+ * @param {Object} props
1960
+ * @param {Boolean} props.debounce
1961
+ * @param {String} props.description
1962
+ * @param {Boolean} props.disabled
1963
+ * @param {Object} props.element
1964
+ * @param {Function} props.getValue
1965
+ * @param {String} props.id
1966
+ * @param {String} props.label
1967
+ * @param {String} props.max
1968
+ * @param {String} props.min
1969
+ * @param {Function} props.setValue
1970
+ * @param {String} props.step
1971
+ */
1972
+
1973
+
1974
+ function NumberFieldEntry(props) {
1975
+ const {
1976
+ debounce,
1977
+ description,
1978
+ disabled,
1979
+ element,
1980
+ getValue,
1981
+ id,
1982
+ label,
1983
+ max,
1984
+ min,
1985
+ setValue,
1986
+ step
1987
+ } = props;
1988
+ const value = getValue(element);
1989
+ return jsxs("div", {
1990
+ class: "bio-properties-panel-entry",
1991
+ "data-entry-id": id,
1992
+ children: [jsx(NumberField, {
1993
+ debounce: debounce,
1994
+ disabled: disabled,
1995
+ id: id,
1996
+ label: label,
1997
+ onInput: setValue,
1998
+ max: max,
1999
+ min: min,
2000
+ step: step,
2001
+ value: value
2002
+ }), jsx(Description$1, {
2003
+ forId: id,
2004
+ element: element,
2005
+ value: description
2006
+ })]
2007
+ });
2008
+ }
2009
+
2010
+ function isEdited$5(node) {
2011
+ return node && !!node.value;
2012
+ } // helpers /////////////////
2013
+
2014
+
2015
+ function prefixId$5(id) {
2016
+ return `bio-properties-panel-${id}`;
2017
+ }
2018
+
2019
+ const noop$1 = () => {};
2020
+ /**
2021
+ * @typedef { { value: string, label: string, disabled: boolean } } Option
2022
+ */
2023
+
2024
+ /**
2025
+ * Provides basic select input.
2026
+ *
2027
+ * @param {object} props
2028
+ * @param {string} props.id
2029
+ * @param {string[]} props.path
2030
+ * @param {string} props.label
2031
+ * @param {Function} props.onChange
2032
+ * @param {Array<Option>} [props.options]
2033
+ * @param {string} props.value
2034
+ * @param {boolean} [props.disabled]
2035
+ */
2036
+
2037
+
2038
+ function Select(props) {
2039
+ const {
2040
+ id,
2041
+ label,
2042
+ onChange,
2043
+ options = [],
2044
+ value,
2045
+ disabled,
2046
+ show = noop$1
2047
+ } = props;
2048
+ const ref = useShowEntryEvent(show);
2049
+
2050
+ const handleChange = ({
2051
+ target
2052
+ }) => {
2053
+ onChange(target.value);
2054
+ };
2055
+
2056
+ return jsxs("div", {
2057
+ class: "bio-properties-panel-select",
2058
+ children: [jsx("label", {
2059
+ for: prefixId$4(id),
2060
+ class: "bio-properties-panel-label",
2061
+ children: label
2062
+ }), jsx("select", {
2063
+ ref: ref,
2064
+ id: prefixId$4(id),
2065
+ name: id,
2066
+ class: "bio-properties-panel-input",
2067
+ onInput: handleChange,
2068
+ value: value,
2069
+ disabled: disabled,
2070
+ children: options.map((option, idx) => {
2071
+ return jsx("option", {
2072
+ value: option.value,
2073
+ disabled: option.disabled,
2074
+ children: option.label
2075
+ }, idx);
2076
+ })
2077
+ })]
2078
+ });
2079
+ }
2080
+ /**
2081
+ * @param {object} props
2082
+ * @param {object} props.element
2083
+ * @param {string} props.id
2084
+ * @param {string} [props.description]
2085
+ * @param {string} props.label
2086
+ * @param {Function} props.getValue
2087
+ * @param {Function} props.setValue
2088
+ * @param {Function} props.getOptions
2089
+ * @param {boolean} [props.disabled]
2090
+ */
2091
+
2092
+
2093
+ function SelectEntry(props) {
2094
+ const {
2095
+ element,
2096
+ id,
2097
+ description,
2098
+ label,
2099
+ getValue,
2100
+ setValue,
2101
+ getOptions,
2102
+ disabled,
2103
+ show = noop$1
2104
+ } = props;
2105
+ const value = getValue(element);
2106
+ const options = getOptions(element);
2107
+ const error = useShowErrorEvent(show);
2108
+ return jsxs("div", {
2109
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
2110
+ "data-entry-id": id,
2111
+ children: [jsx(Select, {
2112
+ id: id,
2113
+ label: label,
2114
+ value: value,
2115
+ onChange: setValue,
2116
+ options: options,
2117
+ disabled: disabled,
2118
+ show: show
2119
+ }), error && jsx("div", {
2120
+ class: "bio-properties-panel-error",
2121
+ children: error
2122
+ }), jsx(Description$1, {
2123
+ forId: id,
2124
+ element: element,
2125
+ value: description
2126
+ })]
2127
+ });
2128
+ }
2129
+
2130
+ function isEdited$4(node) {
2131
+ return node && !!node.value;
2132
+ } // helpers /////////////////
2133
+
2134
+
2135
+ function prefixId$4(id) {
2136
+ return `bio-properties-panel-${id}`;
2137
+ }
2138
+
2139
+ function FeelIcon(props) {
2140
+ const {
2141
+ label,
2142
+ feel = false
2143
+ } = props;
2144
+ const feelRequiredLabel = ' must be a FEEL expression';
2145
+ const feelOptionalLabel = ' can optionally be a FEEL expression';
2146
+ return jsx("i", {
2147
+ class: "bio-properties-panel-feel-icon",
2148
+ title: label + (feel === 'required' ? feelRequiredLabel : feelOptionalLabel),
2149
+ children: feel === 'required' ? jsx(FeelRequiredIcon, {}) : jsx(FeelOptionalIcon, {})
2150
+ });
2151
+ }
2152
+
2153
+ function TextArea(props) {
2154
+ const {
2155
+ id,
2156
+ label,
2157
+ rows = 2,
2158
+ debounce,
2159
+ feel,
2160
+ onInput,
2161
+ value = '',
2162
+ disabled,
2163
+ monospace
2164
+ } = props;
2165
+ const handleInput = useMemo(() => {
2166
+ return debounce(({
2167
+ target
2168
+ }) => onInput(target.value.length ? target.value : undefined));
2169
+ }, [onInput, debounce]);
2170
+ return jsxs("div", {
2171
+ class: "bio-properties-panel-textarea",
2172
+ children: [jsxs("label", {
2173
+ for: prefixId$2(id),
2174
+ class: "bio-properties-panel-label",
2175
+ children: [label, feel && jsx(FeelIcon, {
2176
+ feel: feel,
2177
+ label: label
2178
+ })]
2179
+ }), jsx("textarea", {
2180
+ id: prefixId$2(id),
2181
+ name: id,
2182
+ spellCheck: "false",
2183
+ class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : ''),
2184
+ onInput: handleInput,
2185
+ onFocus: props.onFocus,
2186
+ onBlur: props.onBlur,
2187
+ rows: rows,
2188
+ value: value,
2189
+ disabled: disabled
2190
+ })]
2191
+ });
2192
+ }
2193
+ /**
2194
+ * @param {object} props
2195
+ * @param {object} props.element
2196
+ * @param {string} props.id
2197
+ * @param {string} props.description
2198
+ * @param {boolean} props.debounce
2199
+ * @param {string} props.label
2200
+ * @param {Function} props.getValue
2201
+ * @param {Function} props.setValue
2202
+ * @param {number} props.rows
2203
+ * @param {boolean} props.monospace
2204
+ * @param {boolean} [props.disabled]
2205
+ */
2206
+
2207
+
2208
+ function TextAreaEntry(props) {
2209
+ const {
2210
+ element,
2211
+ id,
2212
+ description,
2213
+ debounce,
2214
+ feel,
2215
+ label,
2216
+ getValue,
2217
+ setValue,
2218
+ rows,
2219
+ monospace,
2220
+ disabled
2221
+ } = props;
2222
+ const value = getValue(element);
2223
+ return jsxs("div", {
2224
+ class: "bio-properties-panel-entry",
2225
+ "data-entry-id": id,
2226
+ children: [jsx(TextArea, {
2227
+ id: id,
2228
+ label: label,
2229
+ value: value,
2230
+ onInput: setValue,
2231
+ rows: rows,
2232
+ debounce: debounce,
2233
+ monospace: monospace,
2234
+ feel: feel,
2235
+ disabled: disabled
2236
+ }), jsx(Description$1, {
2237
+ forId: id,
2238
+ element: element,
2239
+ value: description
2240
+ })]
2241
+ });
2242
+ }
2243
+
2244
+ function isEdited$2(node) {
2245
+ return node && !!node.value;
2246
+ } // helpers /////////////////
2247
+
2248
+
2249
+ function prefixId$2(id) {
2250
+ return `bio-properties-panel-${id}`;
2251
+ }
2252
+
2253
+ const noop = () => {};
2254
+
2255
+ function Textfield(props) {
2256
+ const {
2257
+ debounce,
2258
+ disabled = false,
2259
+ id,
2260
+ label,
2261
+ onInput,
2262
+ feel = false,
2263
+ value = '',
2264
+ show = noop
2265
+ } = props;
2266
+ const ref = useShowEntryEvent(show);
2267
+ const handleInput = useMemo(() => {
2268
+ return debounce(({
2269
+ target
2270
+ }) => onInput(target.value.length ? target.value : undefined));
2271
+ }, [onInput, debounce]);
2272
+ return jsxs("div", {
2273
+ class: "bio-properties-panel-textfield",
2274
+ children: [jsxs("label", {
2275
+ for: prefixId$1(id),
2276
+ class: "bio-properties-panel-label",
2277
+ children: [label, feel && jsx(FeelIcon, {
2278
+ feel: feel,
2279
+ label: label
2280
+ })]
2281
+ }), jsx("input", {
2282
+ ref: ref,
2283
+ id: prefixId$1(id),
2284
+ type: "text",
2285
+ name: id,
2286
+ spellCheck: "false",
2287
+ autoComplete: "off",
2288
+ disabled: disabled,
2289
+ class: "bio-properties-panel-input",
2290
+ onInput: handleInput,
2291
+ onFocus: props.onFocus,
2292
+ onBlur: props.onBlur,
2293
+ value: value || ''
2294
+ })]
2295
+ });
2296
+ }
2297
+ /**
2298
+ * @param {Object} props
2299
+ * @param {Object} props.element
2300
+ * @param {String} props.id
2301
+ * @param {String} props.description
2302
+ * @param {Boolean} props.debounce
2303
+ * @param {Boolean} props.disabled
2304
+ * @param {String} props.label
2305
+ * @param {Function} props.getValue
2306
+ * @param {Function} props.setValue
2307
+ * @param {Function} props.validate
2308
+ */
2309
+
2310
+
2311
+ function TextfieldEntry(props) {
2312
+ const {
2313
+ element,
2314
+ id,
2315
+ description,
2316
+ debounce,
2317
+ disabled,
2318
+ feel,
2319
+ label,
2320
+ getValue,
2321
+ setValue,
2322
+ validate,
2323
+ show = noop
2324
+ } = props;
2325
+ const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
2326
+ const [validationError, setValidationError] = useState(null);
2327
+ let value = getValue(element);
2328
+ const previousValue = usePrevious(value);
2329
+ useEffect(() => {
2330
+ if (isFunction(validate)) {
2331
+ const newValidationError = validate(value) || null;
2332
+ setValidationError(newValidationError);
2333
+ }
2334
+ }, [value]);
2335
+
2336
+ const onInput = newValue => {
2337
+ let newValidationError = null;
2338
+
2339
+ if (isFunction(validate)) {
2340
+ newValidationError = validate(newValue) || null;
2341
+ }
2342
+
2343
+ if (newValidationError) {
2344
+ setCachedInvalidValue(newValue);
2345
+ } else {
2346
+ setValue(newValue);
2347
+ }
2348
+
2349
+ setValidationError(newValidationError);
2350
+ };
2351
+
2352
+ if (previousValue === value && validationError) {
2353
+ value = cachedInvalidValue;
2354
+ }
2355
+
2356
+ const temporaryError = useShowErrorEvent(show);
2357
+ const error = temporaryError || validationError;
2358
+ return jsxs("div", {
2359
+ class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
2360
+ "data-entry-id": id,
2361
+ children: [jsx(Textfield, {
2362
+ debounce: debounce,
2363
+ disabled: disabled,
2364
+ feel: feel,
2365
+ id: id,
2366
+ label: label,
2367
+ onInput: onInput,
2368
+ show: show,
2369
+ value: value
2370
+ }), error && jsx("div", {
2371
+ class: "bio-properties-panel-error",
2372
+ children: error
2373
+ }), jsx(Description$1, {
2374
+ forId: id,
2375
+ element: element,
2376
+ value: description
2377
+ })]
2378
+ });
2379
+ }
2380
+
2381
+ function isEdited$1(node) {
2382
+ return node && !!node.value;
2383
+ } // helpers /////////////////
2384
+
2385
+
2386
+ function prefixId$1(id) {
2387
+ return `bio-properties-panel-${id}`;
2388
+ }
2389
+
2390
+ function arrayAdd$1(array, index, item) {
2391
+ const copy = [...array];
2392
+ copy.splice(index, 0, item);
2393
+ return copy;
2394
+ }
2395
+ function textToLabel(text = '...') {
2396
+ if (text.length > 10) {
2397
+ return `${text.substring(0, 30)}...`;
2398
+ }
2399
+
2400
+ return text;
2401
+ }
2402
+ const INPUTS = ['checkbox', 'checklist', 'number', 'radio', 'select', 'taglist', 'textfield'];
2403
+ const VALUES_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
2404
+
2405
+ 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
2406
  var ButtonIcon = (({
770
2407
  styles = {},
771
2408
  ...props
772
- }) => /*#__PURE__*/React.createElement("svg", _extends$c({
773
- xmlns: "http://www.w3.org/2000/svg",
2409
+ }) => /*#__PURE__*/React.createElement("svg", _extends$b({
2410
+ xmlns: "http://www.w3.org/2000/svg",
2411
+ width: "54",
2412
+ height: "54"
2413
+ }, props), /*#__PURE__*/React.createElement("path", {
2414
+ fillRule: "evenodd",
2415
+ 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"
2416
+ })));
2417
+
2418
+ 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); }
2419
+ var CheckboxIcon = (({
2420
+ styles = {},
2421
+ ...props
2422
+ }) => /*#__PURE__*/React.createElement("svg", _extends$a({
2423
+ xmlns: "http://www.w3.org/2000/svg",
2424
+ width: "54",
2425
+ height: "54"
2426
+ }, props), /*#__PURE__*/React.createElement("path", {
2427
+ 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"
2428
+ })));
2429
+
2430
+ 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); }
2431
+ var ChecklistIcon = (({
2432
+ styles = {},
2433
+ ...props
2434
+ }) => /*#__PURE__*/React.createElement("svg", _extends$9({
774
2435
  width: "54",
775
- height: "54"
2436
+ height: "54",
2437
+ fill: "none",
2438
+ xmlns: "http://www.w3.org/2000/svg"
776
2439
  }, props), /*#__PURE__*/React.createElement("path", {
777
2440
  fillRule: "evenodd",
778
- 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"
2441
+ clipRule: "evenodd",
2442
+ 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",
2443
+ fill: "#22242A"
2444
+ }), /*#__PURE__*/React.createElement("path", {
2445
+ 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",
2446
+ fill: "#22242A"
779
2447
  })));
780
2448
 
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
- var CheckboxIcon = (({
2449
+ 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); }
2450
+ var TaglistIcon = (({
783
2451
  styles = {},
784
2452
  ...props
785
- }) => /*#__PURE__*/React.createElement("svg", _extends$b({
786
- xmlns: "http://www.w3.org/2000/svg",
2453
+ }) => /*#__PURE__*/React.createElement("svg", _extends$8({
787
2454
  width: "54",
788
- height: "54"
2455
+ height: "54",
2456
+ fill: "none",
2457
+ xmlns: "http://www.w3.org/2000/svg"
789
2458
  }, props), /*#__PURE__*/React.createElement("path", {
790
- 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"
2459
+ fillRule: "evenodd",
2460
+ clipRule: "evenodd",
2461
+ 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",
2462
+ fill: "#000"
2463
+ }), /*#__PURE__*/React.createElement("path", {
2464
+ d: "M11 22a1 1 0 011-1h19a1 1 0 011 1v10a1 1 0 01-1 1H12a1 1 0 01-1-1V22z",
2465
+ fill: "#505562"
791
2466
  })));
792
2467
 
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); }
2468
+ 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
2469
  var FormIcon = (({
795
2470
  styles = {},
796
2471
  ...props
797
- }) => /*#__PURE__*/React.createElement("svg", _extends$a({
2472
+ }) => /*#__PURE__*/React.createElement("svg", _extends$7({
798
2473
  xmlns: "http://www.w3.org/2000/svg",
799
2474
  width: "54",
800
2475
  height: "54"
@@ -818,11 +2493,11 @@ var FormIcon = (({
818
2493
  rx: "1"
819
2494
  })));
820
2495
 
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); }
2496
+ 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
2497
  var ColumnsIcon = (({
823
2498
  styles = {},
824
2499
  ...props
825
- }) => /*#__PURE__*/React.createElement("svg", _extends$9({
2500
+ }) => /*#__PURE__*/React.createElement("svg", _extends$6({
826
2501
  xmlns: "http://www.w3.org/2000/svg",
827
2502
  width: "54",
828
2503
  height: "54"
@@ -831,11 +2506,11 @@ var ColumnsIcon = (({
831
2506
  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
2507
  })));
833
2508
 
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); }
2509
+ 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
2510
  var NumberIcon = (({
836
2511
  styles = {},
837
2512
  ...props
838
- }) => /*#__PURE__*/React.createElement("svg", _extends$8({
2513
+ }) => /*#__PURE__*/React.createElement("svg", _extends$5({
839
2514
  xmlns: "http://www.w3.org/2000/svg",
840
2515
  width: "54",
841
2516
  height: "54"
@@ -844,11 +2519,11 @@ var NumberIcon = (({
844
2519
  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
2520
  })));
846
2521
 
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); }
2522
+ 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
2523
  var RadioIcon = (({
849
2524
  styles = {},
850
2525
  ...props
851
- }) => /*#__PURE__*/React.createElement("svg", _extends$7({
2526
+ }) => /*#__PURE__*/React.createElement("svg", _extends$4({
852
2527
  xmlns: "http://www.w3.org/2000/svg",
853
2528
  width: "54",
854
2529
  height: "54"
@@ -856,11 +2531,11 @@ var RadioIcon = (({
856
2531
  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
2532
  })));
858
2533
 
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); }
2534
+ 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
2535
  var SelectIcon = (({
861
2536
  styles = {},
862
2537
  ...props
863
- }) => /*#__PURE__*/React.createElement("svg", _extends$6({
2538
+ }) => /*#__PURE__*/React.createElement("svg", _extends$3({
864
2539
  xmlns: "http://www.w3.org/2000/svg",
865
2540
  width: "54",
866
2541
  height: "54"
@@ -869,11 +2544,11 @@ var SelectIcon = (({
869
2544
  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
2545
  })));
871
2546
 
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); }
2547
+ 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
2548
  var TextIcon = (({
874
2549
  styles = {},
875
2550
  ...props
876
- }) => /*#__PURE__*/React.createElement("svg", _extends$5({
2551
+ }) => /*#__PURE__*/React.createElement("svg", _extends$2({
877
2552
  xmlns: "http://www.w3.org/2000/svg",
878
2553
  width: "54",
879
2554
  height: "54"
@@ -881,11 +2556,11 @@ var TextIcon = (({
881
2556
  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
2557
  })));
883
2558
 
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); }
2559
+ 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
2560
  var TextfieldIcon = (({
886
2561
  styles = {},
887
2562
  ...props
888
- }) => /*#__PURE__*/React.createElement("svg", _extends$4({
2563
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
889
2564
  xmlns: "http://www.w3.org/2000/svg",
890
2565
  width: "54",
891
2566
  height: "54"
@@ -897,755 +2572,438 @@ var TextfieldIcon = (({
897
2572
  const iconsByType = {
898
2573
  button: ButtonIcon,
899
2574
  checkbox: CheckboxIcon,
2575
+ checklist: ChecklistIcon,
900
2576
  columns: ColumnsIcon,
901
2577
  number: NumberIcon,
902
2578
  radio: RadioIcon,
903
2579
  select: SelectIcon,
2580
+ taglist: TaglistIcon,
904
2581
  text: TextIcon,
905
2582
  textfield: TextfieldIcon,
906
2583
  default: FormIcon
907
2584
  };
908
2585
 
909
- const types = [{
910
- label: 'Text Field',
911
- type: 'textfield'
912
- }, {
913
- label: 'Number',
914
- type: 'number'
915
- }, {
916
- label: 'Checkbox',
917
- type: 'checkbox'
918
- }, {
919
- label: 'Radio',
920
- type: 'radio'
921
- }, {
922
- label: 'Select',
923
- type: 'select'
924
- }, {
925
- label: 'Text',
926
- type: 'text'
927
- }, {
928
- label: 'Button',
929
- type: 'button'
930
- }];
931
- function Palette(props) {
932
- return jsxs("div", {
933
- class: "fjs-palette",
934
- children: [jsxs("div", {
935
- class: "fjs-palette-header",
936
- title: "Form elements library",
937
- children: [jsx("span", {
938
- class: "fjs-hide-compact",
939
- children: "FORM ELEMENTS "
940
- }), "LIBRARY"]
941
- }), jsx("div", {
942
- class: "fjs-palette-fields fjs-drag-container fjs-no-drop",
943
- children: types.map(({
944
- label,
945
- type
946
- }) => {
947
- const Icon = iconsByType[type];
948
- return jsxs("div", {
949
- class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
950
- "data-field-type": type,
951
- title: `Create a ${label} element`,
952
- children: [Icon ? jsx(Icon, {
953
- class: "fjs-palette-field-icon",
954
- width: "36",
955
- height: "36",
956
- viewBox: "0 0 54 54"
957
- }) : null, jsx("span", {
958
- class: "fjs-palette-field-text fjs-hide-compact",
959
- children: label
960
- })]
961
- });
962
- })
963
- })]
964
- });
965
- }
966
-
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
- }
990
-
991
- return text;
992
- }
993
- const INPUTS = ['checkbox', 'number', 'radio', 'select', 'textfield'];
994
-
995
- function CheckboxInput(props) {
996
- const {
997
- id,
998
- label,
999
- onChange,
1000
- value = false
1001
- } = props;
1002
-
1003
- const handleChange = ({
1004
- target
1005
- }) => {
1006
- onChange(target.checked);
1007
- };
1008
-
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
- })]
1022
- });
1023
- }
1024
-
1025
- function usePrevious(value) {
1026
- const ref = useRef();
1027
- useEffect(() => ref.current = value);
1028
- return ref.current;
1029
- }
1030
-
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.
1036
-
1037
- useEffect(() => {
1038
- return () => {
1039
- typeof callback.flush === 'function' && callback.flush();
1040
- };
1041
- }, [callback]);
1042
- return callback;
1043
- }
1044
-
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 => {
2586
+ const labelsByType = {
2587
+ button: 'BUTTON',
2588
+ checkbox: 'CHECKBOX',
2589
+ checklist: 'CHECKLIST',
2590
+ columns: 'COLUMNS',
2591
+ default: 'FORM',
2592
+ number: 'NUMBER',
2593
+ radio: 'RADIO',
2594
+ select: 'SELECT',
2595
+ taglist: 'TAGLIST',
2596
+ text: 'TEXT',
2597
+ textfield: 'TEXT FIELD'
2598
+ };
2599
+ const PropertiesPanelHeaderProvider = {
2600
+ getElementLabel: field => {
1055
2601
  const {
1056
- validity,
1057
- value
1058
- } = event.target;
2602
+ type
2603
+ } = field;
1059
2604
 
1060
- if (validity.valid) {
1061
- _onInput(value ? parseInt(value, 10) : undefined);
2605
+ if (type === 'text') {
2606
+ return textToLabel(field.text);
1062
2607
  }
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
1078
- })]
1079
- });
1080
- }
1081
-
1082
- function Select(props) {
1083
- const {
1084
- id,
1085
- label,
1086
- onChange,
1087
- options,
1088
- value
1089
- } = props;
1090
-
1091
- const handleChange = ({
1092
- target
1093
- }) => {
1094
- onChange(target.value);
1095
- };
1096
-
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
- })
1114
- })]
1115
- });
1116
- }
1117
-
1118
- function Textarea(props) {
1119
- const {
1120
- id,
1121
- label,
1122
- rows = 10,
1123
- value = '',
1124
- onInput: _onInput
1125
- } = props;
1126
- const onInput = useDebounce(event => {
1127
- const value = event.target.value;
1128
-
1129
- _onInput(value.length ? value : undefined);
1130
- }, [_onInput]);
1131
- 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
1144
- })]
1145
- });
1146
- }
1147
2608
 
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);
2609
+ if (type === 'default') {
2610
+ return field.id;
1168
2611
  }
1169
2612
 
1170
- setError(error);
1171
- }, [validate, setCachedValue, _onInput]);
2613
+ return field.label;
2614
+ },
2615
+ getElementIcon: field => {
2616
+ const {
2617
+ type
2618
+ } = field;
2619
+ const Icon = iconsByType[type];
2620
+
2621
+ if (Icon) {
2622
+ return () => jsx(Icon, {
2623
+ width: "36",
2624
+ height: "36",
2625
+ viewBox: "0 0 54 54"
2626
+ });
2627
+ }
2628
+ },
2629
+ getTypeLabel: field => {
2630
+ const {
2631
+ type
2632
+ } = field;
2633
+ return labelsByType[type];
2634
+ }
2635
+ };
1172
2636
 
1173
- if (prevValue === value && error) {
1174
- value = cachedValue;
2637
+ /**
2638
+ * Provide placeholders for empty and multiple state.
2639
+ */
2640
+ const PropertiesPanelPlaceholderProvider = {
2641
+ getEmpty: () => {
2642
+ return {
2643
+ text: 'Select a form field to edit its properties.'
2644
+ };
2645
+ },
2646
+ getMultiple: () => {
2647
+ return {
2648
+ text: 'Multiple form fields are selected. Select a single form field to edit its properties.'
2649
+ };
1175
2650
  }
2651
+ };
1176
2652
 
1177
- const classes = ['fjs-properties-panel-input'];
2653
+ function ActionEntry(props) {
2654
+ const {
2655
+ editField,
2656
+ field
2657
+ } = props;
2658
+ const {
2659
+ type
2660
+ } = field;
2661
+ const entries = [];
1178
2662
 
1179
- if (error) {
1180
- classes.push('fjs-has-error');
2663
+ if (type === 'button') {
2664
+ entries.push({
2665
+ id: 'action',
2666
+ component: Action,
2667
+ editField: editField,
2668
+ field: field,
2669
+ isEdited: isEdited$4
2670
+ });
1181
2671
  }
1182
2672
 
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
- });
2673
+ return entries;
1201
2674
  }
1202
2675
 
1203
- function CheckboxInputEntry(props) {
2676
+ function Action(props) {
1204
2677
  const {
1205
2678
  editField,
1206
2679
  field,
1207
- id,
1208
- label,
1209
- path
2680
+ id
1210
2681
  } = props;
2682
+ const path = ['action'];
1211
2683
 
1212
- const onChange = value => {
1213
- if (editField && path) {
1214
- editField(field, path, value);
1215
- } else {
1216
- props.onChange(value);
1217
- }
2684
+ const getValue = () => {
2685
+ return get(field, path, '');
1218
2686
  };
1219
2687
 
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
- })
2688
+ const setValue = value => {
2689
+ return editField(field, path, value);
2690
+ };
2691
+
2692
+ const getOptions = () => [{
2693
+ label: 'Submit',
2694
+ value: 'submit'
2695
+ }, {
2696
+ label: 'Reset',
2697
+ value: 'reset'
2698
+ }];
2699
+
2700
+ return SelectEntry({
2701
+ element: field,
2702
+ getOptions,
2703
+ getValue,
2704
+ id,
2705
+ label: 'Action',
2706
+ setValue
1229
2707
  });
1230
2708
  }
1231
2709
 
1232
- function NumberInputEntry(props) {
2710
+ function ColumnsEntry(props) {
1233
2711
  const {
1234
2712
  editField,
1235
- field,
1236
- id,
1237
- label,
1238
- max,
1239
- min,
1240
- onChange,
1241
- path
2713
+ field
1242
2714
  } = props;
2715
+ const {
2716
+ type
2717
+ } = field;
2718
+ const entries = [];
1243
2719
 
1244
- const onInput = value => {
1245
- if (editField && path) {
1246
- editField(field, path, value);
1247
- } else {
1248
- onChange(value);
1249
- }
1250
- };
2720
+ if (type === 'columns') {
2721
+ entries.push({
2722
+ id: 'columns',
2723
+ component: Columns,
2724
+ editField: editField,
2725
+ field: field,
2726
+ isEdited: isEdited$5
2727
+ });
2728
+ }
1251
2729
 
1252
- const value = path ? get(field, path, '') : props.value;
1253
- return jsx("div", {
1254
- class: "fjs-properties-panel-entry",
1255
- children: jsx(NumberInput, {
1256
- id: id,
1257
- label: label,
1258
- max: max,
1259
- min: min,
1260
- onInput: onInput,
1261
- value: value
1262
- })
1263
- });
2730
+ return entries;
1264
2731
  }
1265
2732
 
1266
- function SelectEntry(props) {
2733
+ function Columns(props) {
1267
2734
  const {
1268
2735
  editField,
1269
2736
  field,
1270
- id,
1271
- description,
1272
- label,
1273
- options,
1274
- path
2737
+ id
1275
2738
  } = props;
2739
+ const debounce = useService('debounce');
2740
+
2741
+ const getValue = () => {
2742
+ return field.components.length;
2743
+ };
2744
+
2745
+ const setValue = value => {
2746
+ let components = field.components.slice();
1276
2747
 
1277
- const onChange = value => {
1278
- if (editField && path) {
1279
- editField(field, path, value);
2748
+ if (value > components.length) {
2749
+ while (value > components.length) {
2750
+ components.push(Default.create({
2751
+ _parent: field.id
2752
+ }));
2753
+ }
1280
2754
  } else {
1281
- props.onChange(value);
2755
+ components = components.slice(0, value);
1282
2756
  }
2757
+
2758
+ editField(field, 'components', components);
1283
2759
  };
1284
2760
 
1285
- const value = path ? get(field, path, '') : props.value;
1286
- return jsxs("div", {
1287
- class: "fjs-properties-panel-entry",
1288
- children: [jsx(Select, {
1289
- id: id,
1290
- label: label,
1291
- onChange: onChange,
1292
- options: options,
1293
- value: value
1294
- }), description && jsx("div", {
1295
- class: "fjs-properties-panel-description",
1296
- children: description
1297
- })]
2761
+ return NumberFieldEntry({
2762
+ debounce,
2763
+ element: field,
2764
+ getValue,
2765
+ id,
2766
+ label: 'Columns',
2767
+ setValue
1298
2768
  });
1299
2769
  }
1300
2770
 
1301
- function TextareaEntry(props) {
2771
+ function DescriptionEntry(props) {
1302
2772
  const {
1303
2773
  editField,
1304
- field,
1305
- id,
1306
- description,
1307
- label,
1308
- onChange,
1309
- path
2774
+ field
1310
2775
  } = props;
2776
+ const {
2777
+ type
2778
+ } = field;
2779
+ const entries = [];
1311
2780
 
1312
- const onInput = value => {
1313
- if (editField && path) {
1314
- editField(field, path, value);
1315
- } else {
1316
- onChange(value);
1317
- }
1318
- };
2781
+ if (INPUTS.includes(type)) {
2782
+ entries.push({
2783
+ id: 'description',
2784
+ component: Description,
2785
+ editField: editField,
2786
+ field: field,
2787
+ isEdited: isEdited$1
2788
+ });
2789
+ }
1319
2790
 
1320
- const value = path ? get(field, path, '') : props.value;
1321
- return jsxs("div", {
1322
- class: "fjs-properties-panel-entry",
1323
- children: [jsx(Textarea, {
1324
- id: id,
1325
- label: label,
1326
- onInput: onInput,
1327
- value: value
1328
- }), description && jsx("div", {
1329
- class: "fjs-properties-panel-description",
1330
- children: description
1331
- })]
1332
- });
2791
+ return entries;
1333
2792
  }
1334
2793
 
1335
- function TextInputEntry(props) {
2794
+ function Description(props) {
1336
2795
  const {
1337
2796
  editField,
1338
2797
  field,
1339
- id,
1340
- description,
1341
- label,
1342
- onChange,
1343
- path,
1344
- validate
2798
+ id
1345
2799
  } = props;
2800
+ const debounce = useService('debounce');
2801
+ const path = ['description'];
1346
2802
 
1347
- const onInput = value => {
1348
- if (editField && path) {
1349
- editField(field, path, value);
1350
- } else {
1351
- onChange(value);
1352
- }
2803
+ const getValue = () => {
2804
+ return get(field, path, '');
1353
2805
  };
1354
2806
 
1355
- const value = path ? get(field, path, '') : props.value;
1356
- return jsxs("div", {
1357
- class: "fjs-properties-panel-entry",
1358
- children: [jsx(TextInput, {
1359
- id: id,
1360
- label: label,
1361
- onInput: onInput,
1362
- validate: validate,
1363
- value: value
1364
- }), description && jsx("div", {
1365
- class: "fjs-properties-panel-description",
1366
- children: description
1367
- })]
2807
+ const setValue = value => {
2808
+ return editField(field, path, value);
2809
+ };
2810
+
2811
+ return TextfieldEntry({
2812
+ debounce,
2813
+ element: field,
2814
+ getValue,
2815
+ id,
2816
+ label: 'Field description',
2817
+ setValue
1368
2818
  });
1369
2819
  }
1370
2820
 
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
- })));
1383
-
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
-
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
- })));
1408
-
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
- })));
1421
-
1422
- function CollapsibleEntry(props) {
2821
+ function DefaultOptionEntry(props) {
1423
2822
  const {
1424
- children,
1425
- label,
1426
- removeEntry = () => {}
2823
+ editField,
2824
+ field
1427
2825
  } = props;
1428
- const [collapsed, setCollapsed] = useState(false);
2826
+ const {
2827
+ type
2828
+ } = field;
2829
+ const entries = []; // Only make default values available when they are statically defined
1429
2830
 
1430
- const toggleCollapsed = () => setCollapsed(!collapsed);
2831
+ if (!INPUTS.includes(type) || VALUES_INPUTS.includes(type) && !field.values) {
2832
+ return entries;
2833
+ }
1431
2834
 
1432
- const classes = ['fjs-properties-panel-collapsible-entry'];
2835
+ const defaultOptions = {
2836
+ editField,
2837
+ field,
2838
+ id: 'defaultValue',
2839
+ label: 'Default value'
2840
+ };
1433
2841
 
1434
- if (collapsed) {
1435
- classes.push('fjs-properties-panel-collapsible-entry-collapsed');
2842
+ if (type === 'checkbox') {
2843
+ entries.push({ ...defaultOptions,
2844
+ component: DefaultValueCheckbox,
2845
+ isEdited: isEdited$4
2846
+ });
1436
2847
  }
1437
2848
 
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
- }
2849
+ if (type === 'number') {
2850
+ entries.push({ ...defaultOptions,
2851
+ component: DefaultValueNumber,
2852
+ isEdited: isEdited$5
2853
+ });
2854
+ }
1461
2855
 
1462
- function Group(props) {
1463
- const {
1464
- children,
1465
- hasEntries = true,
1466
- label
1467
- } = props;
1468
- const [open, setOpen] = useState(hasEntries);
2856
+ if (type === 'radio' || type === 'select') {
2857
+ entries.push({ ...defaultOptions,
2858
+ component: DefaultValueSingleSelect,
2859
+ isEdited: isEdited$4
2860
+ });
2861
+ } // todo(Skaiir): implement a multiselect equivalent (cf. https://github.com/bpmn-io/form-js/issues/265)
1469
2862
 
1470
- const toggleOpen = () => setOpen(!open);
1471
2863
 
1472
- const addEntry = event => {
1473
- event.stopPropagation();
1474
- setOpen(true);
1475
- props.addEntry();
1476
- };
2864
+ if (type === 'textfield') {
2865
+ entries.push({ ...defaultOptions,
2866
+ component: DefaultValueTextfield,
2867
+ isEdited: isEdited$1
2868
+ });
2869
+ }
1477
2870
 
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
- });
2871
+ return entries;
1504
2872
  }
1505
2873
 
1506
- function ActionEntry(props) {
2874
+ function DefaultValueCheckbox(props) {
1507
2875
  const {
1508
2876
  editField,
1509
- field
2877
+ field,
2878
+ id,
2879
+ label
1510
2880
  } = props;
1511
- const options = [{
1512
- label: 'Submit',
1513
- value: 'submit'
1514
- }, {
1515
- label: 'Reset',
1516
- value: 'reset'
1517
- }];
1518
- return jsx(SelectEntry, {
1519
- editField: editField,
1520
- field: field,
1521
- id: "action",
1522
- label: "Action",
1523
- options: options,
1524
- path: ['action']
1525
- });
1526
- }
1527
-
1528
- function ColumnsEntry(props) {
1529
2881
  const {
1530
- editField,
1531
- field
1532
- } = props;
2882
+ defaultValue
2883
+ } = field;
2884
+ const path = ['defaultValue'];
1533
2885
 
1534
- const onInput = value => {
1535
- let components = field.components.slice();
2886
+ const getOptions = () => {
2887
+ return [{
2888
+ label: 'Checked',
2889
+ value: 'true'
2890
+ }, {
2891
+ label: 'Not checked',
2892
+ value: 'false'
2893
+ }];
2894
+ };
1536
2895
 
1537
- if (value > components.length) {
1538
- while (value > components.length) {
1539
- components.push(Default.create({
1540
- _parent: field.id
1541
- }));
1542
- }
1543
- } else {
1544
- components = components.slice(0, value);
1545
- }
2896
+ const setValue = value => {
2897
+ return editField(field, path, parseStringToBoolean(value));
2898
+ };
1546
2899
 
1547
- editField(field, 'components', components);
2900
+ const getValue = () => {
2901
+ return parseBooleanToString(defaultValue);
1548
2902
  };
1549
2903
 
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
- })
2904
+ return SelectEntry({
2905
+ element: field,
2906
+ getOptions,
2907
+ getValue,
2908
+ id,
2909
+ label,
2910
+ setValue
1561
2911
  });
1562
2912
  }
1563
2913
 
1564
- function DescriptionEntry(props) {
2914
+ function DefaultValueNumber(props) {
1565
2915
  const {
1566
2916
  editField,
1567
- field
2917
+ field,
2918
+ id,
2919
+ label
1568
2920
  } = props;
1569
- return jsx(TextInputEntry, {
1570
- editField: editField,
1571
- field: field,
1572
- id: "description",
1573
- label: "Field Description",
1574
- path: ['description']
2921
+ const debounce = useService('debounce');
2922
+ const path = ['defaultValue'];
2923
+
2924
+ const getValue = () => {
2925
+ return get(field, path, '');
2926
+ };
2927
+
2928
+ const setValue = value => {
2929
+ return editField(field, path, value);
2930
+ };
2931
+
2932
+ return NumberFieldEntry({
2933
+ debounce,
2934
+ element: field,
2935
+ getValue,
2936
+ id,
2937
+ label,
2938
+ setValue
1575
2939
  });
1576
2940
  }
1577
2941
 
1578
- function DefaultValueEntry(props) {
2942
+ function DefaultValueSingleSelect(props) {
1579
2943
  const {
1580
2944
  editField,
1581
- field
2945
+ field,
2946
+ id,
2947
+ label
1582
2948
  } = props;
1583
2949
  const {
1584
2950
  defaultValue,
1585
- type,
1586
2951
  values = []
1587
2952
  } = field;
2953
+ const path = ['defaultValue'];
1588
2954
 
1589
- if (type === 'checkbox') {
1590
- const options = [{
1591
- label: 'Checked',
1592
- value: 'true'
1593
- }, {
1594
- label: 'Not checked',
1595
- value: 'false'
1596
- }];
2955
+ const getOptions = () => {
2956
+ return [{
2957
+ label: '<none>'
2958
+ }, ...values];
2959
+ };
1597
2960
 
1598
- const onChange = value => {
1599
- editField(field, ['defaultValue'], parseStringToBoolean(value));
1600
- };
2961
+ const setValue = value => {
2962
+ return editField(field, path, value.length ? value : undefined);
2963
+ };
1601
2964
 
1602
- return jsx(SelectEntry, {
1603
- id: "defaultValue",
1604
- label: "Default Value",
1605
- onChange: onChange,
1606
- options: options,
1607
- value: parseBooleanToString(defaultValue)
1608
- });
1609
- }
2965
+ const getValue = () => {
2966
+ return defaultValue;
2967
+ };
1610
2968
 
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
- }
2969
+ return SelectEntry({
2970
+ element: field,
2971
+ getOptions,
2972
+ getValue,
2973
+ id,
2974
+ label,
2975
+ setValue
2976
+ });
2977
+ }
1620
2978
 
1621
- if (type === 'radio' || type === 'select') {
1622
- const options = [{
1623
- label: '<none>'
1624
- }, ...values];
2979
+ function DefaultValueTextfield(props) {
2980
+ const {
2981
+ editField,
2982
+ field,
2983
+ id,
2984
+ label
2985
+ } = props;
2986
+ const debounce = useService('debounce');
2987
+ const path = ['defaultValue'];
1625
2988
 
1626
- const onChange = value => {
1627
- editField(field, ['defaultValue'], value.length ? value : undefined);
1628
- };
2989
+ const getValue = () => {
2990
+ return get(field, path, '');
2991
+ };
1629
2992
 
1630
- return jsx(SelectEntry, {
1631
- id: "defaultValue",
1632
- label: "Default Value",
1633
- onChange: onChange,
1634
- options: options,
1635
- value: defaultValue
1636
- });
1637
- }
2993
+ const setValue = value => {
2994
+ return editField(field, path, value);
2995
+ };
2996
+
2997
+ return TextfieldEntry({
2998
+ debounce,
2999
+ element: field,
3000
+ getValue,
3001
+ id,
3002
+ label,
3003
+ setValue
3004
+ });
3005
+ } // helpers /////////////////
1638
3006
 
1639
- if (type === 'textfield') {
1640
- return jsx(TextInputEntry, {
1641
- editField: editField,
1642
- field: field,
1643
- id: "defaultValue",
1644
- label: "Default Value",
1645
- path: ['defaultValue']
1646
- });
1647
- }
1648
- }
1649
3007
 
1650
3008
  function parseStringToBoolean(value) {
1651
3009
  if (value === 'true') {
@@ -1668,17 +3026,46 @@ function DisabledEntry(props) {
1668
3026
  editField,
1669
3027
  field
1670
3028
  } = props;
3029
+ const {
3030
+ type
3031
+ } = field;
3032
+ const entries = [];
3033
+
3034
+ if (INPUTS.includes(type)) {
3035
+ entries.push({
3036
+ id: 'disabled',
3037
+ component: Disabled,
3038
+ editField: editField,
3039
+ field: field,
3040
+ isEdited: isEdited$6
3041
+ });
3042
+ }
3043
+
3044
+ return entries;
3045
+ }
3046
+
3047
+ function Disabled(props) {
3048
+ const {
3049
+ editField,
3050
+ field,
3051
+ id
3052
+ } = props;
3053
+ const path = ['disabled'];
3054
+
3055
+ const getValue = () => {
3056
+ return get(field, path, '');
3057
+ };
1671
3058
 
1672
- const onChange = value => {
1673
- editField(field, 'disabled', value);
3059
+ const setValue = value => {
3060
+ return editField(field, path, value);
1674
3061
  };
1675
3062
 
1676
- return jsx(CheckboxInputEntry, {
1677
- id: "disabled",
1678
- field: field,
1679
- label: "Disabled",
1680
- path: ['disabled'],
1681
- onChange: onChange
3063
+ return CheckboxEntry({
3064
+ element: field,
3065
+ getValue,
3066
+ id,
3067
+ label: 'Disabled',
3068
+ setValue
1682
3069
  });
1683
3070
  }
1684
3071
 
@@ -1687,7 +3074,38 @@ function IdEntry(props) {
1687
3074
  editField,
1688
3075
  field
1689
3076
  } = props;
3077
+ const entries = [];
3078
+
3079
+ if (field.type === 'default') {
3080
+ entries.push({
3081
+ id: 'id',
3082
+ component: Id,
3083
+ editField: editField,
3084
+ field: field,
3085
+ isEdited: isEdited$1
3086
+ });
3087
+ }
3088
+
3089
+ return entries;
3090
+ }
3091
+
3092
+ function Id(props) {
3093
+ const {
3094
+ editField,
3095
+ field,
3096
+ id
3097
+ } = props;
1690
3098
  const formFieldRegistry = useService('formFieldRegistry');
3099
+ const debounce = useService('debounce');
3100
+ const path = ['id'];
3101
+
3102
+ const getValue = () => {
3103
+ return get(field, path, '');
3104
+ };
3105
+
3106
+ const setValue = value => {
3107
+ return editField(field, path, value);
3108
+ };
1691
3109
 
1692
3110
  const validate = value => {
1693
3111
  if (isUndefined(value) || !value.length) {
@@ -1703,16 +3121,18 @@ function IdEntry(props) {
1703
3121
  return validateId(value) || null;
1704
3122
  };
1705
3123
 
1706
- return jsx(TextInputEntry, {
1707
- editField: editField,
1708
- field: field,
1709
- id: "id",
1710
- label: "Id",
1711
- path: ['id'],
1712
- validate: validate
3124
+ return TextfieldEntry({
3125
+ debounce,
3126
+ element: field,
3127
+ getValue,
3128
+ id,
3129
+ label: 'ID',
3130
+ setValue,
3131
+ validate
1713
3132
  });
1714
3133
  } // id structural validation /////////////
1715
3134
 
3135
+
1716
3136
  const SPACE_REGEX = /\s/; // for QName validation as per http://www.w3.org/TR/REC-xml/#NT-NameChar
1717
3137
 
1718
3138
  const QNAME_REGEX = /^([a-z][\w-.]*:)?[a-z_][\w-.]*$/i; // for ID validation as per BPMN Schema (QName - Namespace)
@@ -1742,7 +3162,41 @@ function KeyEntry(props) {
1742
3162
  editField,
1743
3163
  field
1744
3164
  } = props;
3165
+ const {
3166
+ type
3167
+ } = field;
3168
+ const entries = [];
3169
+
3170
+ if (INPUTS.includes(type)) {
3171
+ entries.push({
3172
+ id: 'key',
3173
+ component: Key$1,
3174
+ editField: editField,
3175
+ field: field,
3176
+ isEdited: isEdited$1
3177
+ });
3178
+ }
3179
+
3180
+ return entries;
3181
+ }
3182
+
3183
+ function Key$1(props) {
3184
+ const {
3185
+ editField,
3186
+ field,
3187
+ id
3188
+ } = props;
1745
3189
  const formFieldRegistry = useService('formFieldRegistry');
3190
+ const debounce = useService('debounce');
3191
+ const path = ['key'];
3192
+
3193
+ const getValue = () => {
3194
+ return get(field, path, '');
3195
+ };
3196
+
3197
+ const setValue = value => {
3198
+ return editField(field, path, value);
3199
+ };
1746
3200
 
1747
3201
  const validate = value => {
1748
3202
  if (isUndefined(value) || !value.length) {
@@ -1753,134 +3207,306 @@ function KeyEntry(props) {
1753
3207
  return 'Must not contain spaces.';
1754
3208
  }
1755
3209
 
1756
- const assigned = formFieldRegistry._keys.assigned(value);
3210
+ const assigned = formFieldRegistry._keys.assigned(value);
3211
+
3212
+ if (assigned && assigned !== field) {
3213
+ return 'Must be unique.';
3214
+ }
3215
+
3216
+ return null;
3217
+ };
3218
+
3219
+ return TextfieldEntry({
3220
+ debounce,
3221
+ description: 'Binds to a form variable',
3222
+ element: field,
3223
+ getValue,
3224
+ id,
3225
+ label: 'Key',
3226
+ setValue,
3227
+ validate
3228
+ });
3229
+ }
3230
+
3231
+ function LabelEntry(props) {
3232
+ const {
3233
+ editField,
3234
+ field
3235
+ } = props;
3236
+ const {
3237
+ type
3238
+ } = field;
3239
+ const entries = [];
3240
+
3241
+ if (INPUTS.includes(type) || type === 'button') {
3242
+ entries.push({
3243
+ id: 'label',
3244
+ component: Label$1,
3245
+ editField: editField,
3246
+ field: field,
3247
+ isEdited: isEdited$1
3248
+ });
3249
+ }
3250
+
3251
+ return entries;
3252
+ }
3253
+
3254
+ function Label$1(props) {
3255
+ const {
3256
+ editField,
3257
+ field,
3258
+ id
3259
+ } = props;
3260
+ const debounce = useService('debounce');
3261
+ const path = ['label'];
3262
+
3263
+ const getValue = () => {
3264
+ return get(field, path, '');
3265
+ };
3266
+
3267
+ const setValue = value => {
3268
+ return editField(field, path, value);
3269
+ };
3270
+
3271
+ return TextfieldEntry({
3272
+ debounce,
3273
+ element: field,
3274
+ getValue,
3275
+ id,
3276
+ label: 'Field label',
3277
+ setValue
3278
+ });
3279
+ }
3280
+
3281
+ function TextEntry(props) {
3282
+ const {
3283
+ editField,
3284
+ field
3285
+ } = props;
3286
+ const {
3287
+ type
3288
+ } = field;
3289
+ const entries = [];
3290
+
3291
+ if (type === 'text') {
3292
+ entries.push({
3293
+ id: 'text',
3294
+ component: Text,
3295
+ editField: editField,
3296
+ field: field,
3297
+ isEdited: isEdited$2
3298
+ });
3299
+ }
3300
+
3301
+ return entries;
3302
+ }
3303
+
3304
+ function Text(props) {
3305
+ const {
3306
+ editField,
3307
+ field,
3308
+ id
3309
+ } = props;
3310
+ const debounce = useService('debounce');
3311
+ const path = ['text'];
3312
+
3313
+ const getValue = () => {
3314
+ return get(field, path, '');
3315
+ };
3316
+
3317
+ const setValue = value => {
3318
+ return editField(field, path, value);
3319
+ };
3320
+
3321
+ return TextAreaEntry({
3322
+ debounce,
3323
+ description: 'Use Markdown or basic HTML to format.',
3324
+ element: field,
3325
+ getValue,
3326
+ id,
3327
+ label: 'Text',
3328
+ rows: 10,
3329
+ setValue
3330
+ });
3331
+ }
3332
+
3333
+ function ValueEntry(props) {
3334
+ const {
3335
+ editField,
3336
+ field,
3337
+ idPrefix,
3338
+ index,
3339
+ validateFactory
3340
+ } = props;
3341
+ const entries = [{
3342
+ component: Label,
3343
+ editField,
3344
+ field,
3345
+ id: idPrefix + '-label',
3346
+ idPrefix,
3347
+ index,
3348
+ validateFactory
3349
+ }, {
3350
+ component: Value$1,
3351
+ editField,
3352
+ field,
3353
+ id: idPrefix + '-value',
3354
+ idPrefix,
3355
+ index,
3356
+ validateFactory
3357
+ }];
3358
+ return entries;
3359
+ }
3360
+
3361
+ function Label(props) {
3362
+ const {
3363
+ editField,
3364
+ field,
3365
+ id,
3366
+ index,
3367
+ validateFactory
3368
+ } = props;
3369
+ const debounce = useService('debounce');
1757
3370
 
1758
- if (assigned && assigned !== field) {
1759
- return 'Must be unique.';
1760
- }
3371
+ const setValue = value => {
3372
+ const values = get(field, ['values']);
3373
+ return editField(field, 'values', set(values, [index, 'label'], value));
3374
+ };
1761
3375
 
1762
- return null;
3376
+ const getValue = () => {
3377
+ return get(field, ['values', index, 'label']);
1763
3378
  };
1764
3379
 
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
3380
+ return TextfieldEntry({
3381
+ debounce,
3382
+ element: field,
3383
+ getValue,
3384
+ id,
3385
+ label: 'Label',
3386
+ setValue,
3387
+ validate: validateFactory(getValue())
1773
3388
  });
1774
3389
  }
1775
3390
 
1776
- function LabelEntry(props) {
3391
+ function Value$1(props) {
1777
3392
  const {
1778
3393
  editField,
1779
- field
3394
+ field,
3395
+ id,
3396
+ index,
3397
+ validateFactory
1780
3398
  } = props;
1781
- return jsx(TextInputEntry, {
1782
- editField: editField,
1783
- field: field,
1784
- id: "label",
1785
- label: "Field Label",
1786
- path: ['label']
3399
+ const debounce = useService('debounce');
3400
+
3401
+ const setValue = value => {
3402
+ const values = get(field, ['values']);
3403
+ return editField(field, 'values', set(values, [index, 'value'], value));
3404
+ };
3405
+
3406
+ const getValue = () => {
3407
+ return get(field, ['values', index, 'value']);
3408
+ };
3409
+
3410
+ return TextfieldEntry({
3411
+ debounce,
3412
+ element: field,
3413
+ getValue,
3414
+ id,
3415
+ label: 'Value',
3416
+ setValue,
3417
+ validate: validateFactory(getValue())
1787
3418
  });
1788
3419
  }
1789
3420
 
1790
- function TextEntry(props) {
3421
+ function CustomValueEntry(props) {
1791
3422
  const {
1792
3423
  editField,
1793
- field
3424
+ field,
3425
+ idPrefix,
3426
+ index,
3427
+ validateFactory
1794
3428
  } = 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."
1802
- });
3429
+ const entries = [{
3430
+ component: Key,
3431
+ editField,
3432
+ field,
3433
+ id: idPrefix + '-key',
3434
+ idPrefix,
3435
+ index,
3436
+ validateFactory
3437
+ }, {
3438
+ component: Value,
3439
+ editField,
3440
+ field,
3441
+ id: idPrefix + '-value',
3442
+ idPrefix,
3443
+ index,
3444
+ validateFactory
3445
+ }];
3446
+ return entries;
1803
3447
  }
1804
3448
 
1805
- function ValueEntry(props) {
3449
+ function Key(props) {
1806
3450
  const {
1807
3451
  editField,
1808
3452
  field,
3453
+ id,
1809
3454
  index,
1810
- validate
3455
+ validateFactory
1811
3456
  } = props;
3457
+ const debounce = useService('debounce');
1812
3458
 
1813
- const getLabel = () => {
1814
- return get(field, ['values', index, 'label']);
3459
+ const setValue = value => {
3460
+ const properties = get(field, ['properties']);
3461
+ const key = Object.keys(properties)[index];
3462
+ return editField(field, 'properties', updateKey(properties, key, value));
1815
3463
  };
1816
3464
 
1817
3465
  const getValue = () => {
1818
- return get(field, ['values', index, 'value']);
1819
- };
1820
-
1821
- const onChange = key => {
1822
- const values = get(field, ['values']);
1823
- return value => {
1824
- editField(field, 'values', set(values, [index, key], value));
1825
- };
3466
+ return Object.keys(get(field, ['properties']))[index];
1826
3467
  };
1827
3468
 
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
- })]
3469
+ return TextfieldEntry({
3470
+ debounce,
3471
+ element: field,
3472
+ getValue,
3473
+ id,
3474
+ label: 'Key',
3475
+ setValue,
3476
+ validate: validateFactory(getValue())
1841
3477
  });
1842
3478
  }
1843
3479
 
1844
- function CustomValueEntry(props) {
3480
+ function Value(props) {
1845
3481
  const {
1846
3482
  editField,
1847
3483
  field,
3484
+ id,
1848
3485
  index,
1849
- validate
3486
+ validateFactory
1850
3487
  } = props;
3488
+ const debounce = useService('debounce');
1851
3489
 
1852
- const getKey = () => {
1853
- return Object.keys(get(field, ['properties']))[index];
3490
+ const setValue = value => {
3491
+ const properties = get(field, ['properties']);
3492
+ const key = Object.keys(properties)[index];
3493
+ editField(field, 'properties', updateValue(properties, key, value));
1854
3494
  };
1855
3495
 
1856
3496
  const getValue = () => {
1857
- return get(field, ['properties', getKey()]);
1858
- };
1859
-
1860
- const onChange = key => {
1861
3497
  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
- };
3498
+ const key = Object.keys(properties)[index];
3499
+ return get(field, ['properties', key]);
1869
3500
  };
1870
3501
 
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
- })]
3502
+ return TextfieldEntry({
3503
+ debounce,
3504
+ element: field,
3505
+ getValue,
3506
+ id,
3507
+ label: 'Value',
3508
+ setValue,
3509
+ validate: validateFactory(getValue())
1884
3510
  });
1885
3511
  } // helpers //////////
1886
3512
 
@@ -1894,6 +3520,7 @@ function CustomValueEntry(props) {
1894
3520
  * @returns {Object}
1895
3521
  */
1896
3522
 
3523
+
1897
3524
  function updateValue(properties, key, value) {
1898
3525
  return { ...properties,
1899
3526
  [key]: value
@@ -1919,79 +3546,225 @@ function updateKey(properties, oldKey, newKey) {
1919
3546
  }, {});
1920
3547
  }
1921
3548
 
1922
- function GeneralGroup(field, editField) {
3549
+ const VALUES_SOURCES = {
3550
+ STATIC: 'static',
3551
+ INPUT: 'input'
3552
+ };
3553
+ const VALUES_SOURCE_DEFAULT = VALUES_SOURCES.STATIC;
3554
+ const VALUES_SOURCES_LABELS = {
3555
+ [VALUES_SOURCES.STATIC]: 'Static',
3556
+ [VALUES_SOURCES.INPUT]: 'Input data'
3557
+ };
3558
+ const VALUES_SOURCES_PATHS = {
3559
+ [VALUES_SOURCES.STATIC]: ['values'],
3560
+ [VALUES_SOURCES.INPUT]: ['valuesKey']
3561
+ };
3562
+ const VALUES_SOURCES_DEFAULTS = {
3563
+ [VALUES_SOURCES.STATIC]: [],
3564
+ [VALUES_SOURCES.INPUT]: ''
3565
+ }; // helpers ///////////////////
3566
+
3567
+ function getValuesSource(field) {
3568
+ for (const source of Object.values(VALUES_SOURCES)) {
3569
+ if (get(field, VALUES_SOURCES_PATHS[source]) !== undefined) {
3570
+ return source;
3571
+ }
3572
+ }
3573
+
3574
+ return VALUES_SOURCE_DEFAULT;
3575
+ }
3576
+
3577
+ function ValuesSourceSelectEntry(props) {
1923
3578
  const {
1924
- type
1925
- } = field;
1926
- const entries = [];
3579
+ editField,
3580
+ field,
3581
+ id
3582
+ } = props;
3583
+ return [{
3584
+ id: id + '-select',
3585
+ component: ValuesSourceSelect,
3586
+ isEdited: isEdited$4,
3587
+ editField,
3588
+ field
3589
+ }];
3590
+ }
1927
3591
 
1928
- if (type === 'default') {
1929
- entries.push(jsx(IdEntry, {
1930
- editField: editField,
1931
- field: field
1932
- }));
1933
- }
3592
+ function ValuesSourceSelect(props) {
3593
+ const {
3594
+ editField,
3595
+ field,
3596
+ id
3597
+ } = props;
3598
+ const getValue = getValuesSource;
3599
+
3600
+ const setValue = value => {
3601
+ let newField = field;
3602
+ Object.values(VALUES_SOURCES).forEach(source => {
3603
+ // Clear all values source definitions and default the newly selected one
3604
+ const newValue = value === source ? VALUES_SOURCES_DEFAULTS[source] : undefined;
3605
+ newField = editField(field, VALUES_SOURCES_PATHS[source], newValue);
3606
+ });
3607
+ return newField;
3608
+ };
1934
3609
 
1935
- if (INPUTS.includes(type) || type === 'button') {
1936
- entries.push(jsx(LabelEntry, {
1937
- editField: editField,
1938
- field: field
3610
+ const getValuesSourceOptions = () => {
3611
+ return Object.values(VALUES_SOURCES).map(valueSource => ({
3612
+ label: VALUES_SOURCES_LABELS[valueSource],
3613
+ value: valueSource
1939
3614
  }));
1940
- }
3615
+ };
1941
3616
 
1942
- if (INPUTS.includes(type)) {
1943
- entries.push(jsx(DescriptionEntry, {
1944
- editField: editField,
1945
- field: field
1946
- }));
1947
- }
3617
+ return SelectEntry({
3618
+ label: 'Type',
3619
+ element: field,
3620
+ getOptions: getValuesSourceOptions,
3621
+ getValue,
3622
+ id,
3623
+ setValue
3624
+ });
3625
+ }
1948
3626
 
1949
- if (INPUTS.includes(type)) {
1950
- entries.push(jsx(KeyEntry, {
1951
- editField: editField,
1952
- field: field
1953
- }));
1954
- }
3627
+ function InputKeyValuesSourceEntry(props) {
3628
+ const {
3629
+ editField,
3630
+ field,
3631
+ id
3632
+ } = props;
3633
+ return [{
3634
+ id: id + '-key',
3635
+ component: InputValuesKey,
3636
+ label: 'Input values key',
3637
+ description: 'Define which input property to populate the values from',
3638
+ isEdited: isEdited$1,
3639
+ editField,
3640
+ field
3641
+ }];
3642
+ }
1955
3643
 
1956
- if (INPUTS.includes(type)) {
1957
- entries.push(jsx(DefaultValueEntry, {
1958
- editField: editField,
1959
- field: field
1960
- }));
1961
- }
3644
+ function InputValuesKey(props) {
3645
+ const {
3646
+ editField,
3647
+ field,
3648
+ id,
3649
+ label,
3650
+ description
3651
+ } = props;
3652
+ const debounce = useService('debounce');
3653
+ const path = VALUES_SOURCES_PATHS[VALUES_SOURCES.INPUT];
1962
3654
 
1963
- if (type === 'button') {
1964
- entries.push(jsx(ActionEntry, {
1965
- editField: editField,
1966
- field: field
1967
- }));
1968
- }
3655
+ const getValue = () => get(field, path, '');
1969
3656
 
1970
- if (type === 'columns') {
1971
- entries.push(jsx(ColumnsEntry, {
1972
- editField: editField,
1973
- field: field
1974
- }));
1975
- }
3657
+ const setValue = value => editField(field, path, value || '');
1976
3658
 
1977
- if (type === 'text') {
1978
- entries.push(jsx(TextEntry, {
1979
- editField: editField,
1980
- field: field
1981
- }));
1982
- }
3659
+ return TextfieldEntry({
3660
+ debounce,
3661
+ description,
3662
+ element: field,
3663
+ getValue,
3664
+ id,
3665
+ label,
3666
+ setValue
3667
+ });
3668
+ }
1983
3669
 
1984
- if (INPUTS.includes(type)) {
1985
- entries.push(jsx(DisabledEntry, {
1986
- editField: editField,
1987
- field: field
1988
- }));
1989
- }
3670
+ function StaticValuesSourceEntry(props) {
3671
+ const {
3672
+ editField,
3673
+ field,
3674
+ id: idPrefix
3675
+ } = props;
3676
+ const {
3677
+ values
3678
+ } = field;
3679
+
3680
+ const addEntry = e => {
3681
+ e.stopPropagation();
3682
+ const index = values.length + 1;
3683
+ const entry = {
3684
+ label: `Value ${index}`,
3685
+ value: `value${index}`
3686
+ };
3687
+ editField(field, VALUES_SOURCES_PATHS[VALUES_SOURCES.STATIC], arrayAdd$1(values, values.length, entry));
3688
+ };
3689
+
3690
+ const removeEntry = entry => {
3691
+ editField(field, VALUES_SOURCES_PATHS[VALUES_SOURCES.STATIC], without(values, entry));
3692
+ };
3693
+
3694
+ const validateFactory = key => {
3695
+ return value => {
3696
+ if (value === key) {
3697
+ return;
3698
+ }
1990
3699
 
1991
- return jsx(Group, {
1992
- label: "General",
1993
- children: entries.length ? entries : null
3700
+ if (isUndefined(value) || !value.length) {
3701
+ return 'Must not be empty.';
3702
+ }
3703
+
3704
+ const isValueAssigned = values.find(entry => entry.value === value);
3705
+
3706
+ if (isValueAssigned) {
3707
+ return 'Must be unique.';
3708
+ }
3709
+ };
3710
+ };
3711
+
3712
+ const items = values.map((entry, index) => {
3713
+ const id = idPrefix + '-' + index;
3714
+ return {
3715
+ id,
3716
+ label: entry.label,
3717
+ entries: ValueEntry({
3718
+ editField,
3719
+ field,
3720
+ idPrefix: id,
3721
+ index,
3722
+ validateFactory
3723
+ }),
3724
+ autoFocusEntry: id + '-label',
3725
+ remove: () => removeEntry(entry)
3726
+ };
1994
3727
  });
3728
+ return {
3729
+ items,
3730
+ add: addEntry
3731
+ };
3732
+ }
3733
+
3734
+ function GeneralGroup(field, editField) {
3735
+ const entries = [...IdEntry({
3736
+ field,
3737
+ editField
3738
+ }), ...LabelEntry({
3739
+ field,
3740
+ editField
3741
+ }), ...DescriptionEntry({
3742
+ field,
3743
+ editField
3744
+ }), ...KeyEntry({
3745
+ field,
3746
+ editField
3747
+ }), ...DefaultOptionEntry({
3748
+ field,
3749
+ editField
3750
+ }), ...ActionEntry({
3751
+ field,
3752
+ editField
3753
+ }), ...ColumnsEntry({
3754
+ field,
3755
+ editField
3756
+ }), ...TextEntry({
3757
+ field,
3758
+ editField
3759
+ }), ...DisabledEntry({
3760
+ field,
3761
+ editField
3762
+ })];
3763
+ return {
3764
+ id: 'general',
3765
+ label: 'General',
3766
+ entries
3767
+ };
1995
3768
  }
1996
3769
 
1997
3770
  function ValidationGroup(field, editField) {
@@ -1999,6 +3772,10 @@ function ValidationGroup(field, editField) {
1999
3772
  type
2000
3773
  } = field;
2001
3774
 
3775
+ if (!(INPUTS.includes(type) && type !== 'checkbox' && type !== 'checklist' && type !== 'taglist')) {
3776
+ return null;
3777
+ }
3778
+
2002
3779
  const onChange = key => {
2003
3780
  return value => {
2004
3781
  const validate = get(field, ['validate'], {});
@@ -2006,122 +3783,247 @@ function ValidationGroup(field, editField) {
2006
3783
  };
2007
3784
  };
2008
3785
 
2009
- const entries = [jsx(CheckboxInputEntry, {
2010
- id: "required",
2011
- label: "Required",
2012
- onChange: onChange('required'),
2013
- value: get(field, ['validate', 'required'])
2014
- })];
3786
+ const getValue = key => {
3787
+ return () => {
3788
+ return get(field, ['validate', key]);
3789
+ };
3790
+ };
3791
+
3792
+ let entries = [{
3793
+ id: 'required',
3794
+ component: Required,
3795
+ getValue,
3796
+ field,
3797
+ isEdited: isEdited$6,
3798
+ onChange
3799
+ }];
2015
3800
 
2016
3801
  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: "regularExpressionPattern",
2031
- label: "Regular Expression Pattern",
2032
- onChange: onChange('regularExpressionPattern'),
2033
- value: get(field, ['validate', 'regularExpressionPattern'])
2034
- }));
3802
+ entries.push({
3803
+ id: 'minLength',
3804
+ component: MinLength,
3805
+ getValue,
3806
+ field,
3807
+ isEdited: isEdited$5,
3808
+ onChange
3809
+ }, {
3810
+ id: 'maxLength',
3811
+ component: MaxLength,
3812
+ getValue,
3813
+ field,
3814
+ isEdited: isEdited$5,
3815
+ onChange
3816
+ }, {
3817
+ id: 'pattern',
3818
+ component: Pattern,
3819
+ getValue,
3820
+ field,
3821
+ isEdited: isEdited$1,
3822
+ onChange
3823
+ });
2035
3824
  }
2036
3825
 
2037
3826
  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
- }));
3827
+ entries.push({
3828
+ id: 'min',
3829
+ component: Min,
3830
+ getValue,
3831
+ field,
3832
+ isEdited: isEdited$5,
3833
+ onChange
3834
+ }, {
3835
+ id: 'max',
3836
+ component: Max,
3837
+ getValue,
3838
+ field,
3839
+ isEdited: isEdited$5,
3840
+ onChange
3841
+ });
2049
3842
  }
2050
3843
 
2051
- return jsx(Group, {
2052
- label: "Validation",
2053
- children: entries.length ? entries : null
3844
+ return {
3845
+ id: 'validation',
3846
+ label: 'Validation',
3847
+ entries
3848
+ };
3849
+ }
3850
+
3851
+ function Required(props) {
3852
+ const {
3853
+ field,
3854
+ getValue,
3855
+ id,
3856
+ onChange
3857
+ } = props;
3858
+ return CheckboxEntry({
3859
+ element: field,
3860
+ getValue: getValue('required'),
3861
+ id,
3862
+ label: 'Required',
3863
+ setValue: onChange('required')
3864
+ });
3865
+ }
3866
+
3867
+ function MinLength(props) {
3868
+ const {
3869
+ field,
3870
+ getValue,
3871
+ id,
3872
+ onChange
3873
+ } = props;
3874
+ const debounce = useService('debounce');
3875
+ return NumberFieldEntry({
3876
+ debounce,
3877
+ element: field,
3878
+ getValue: getValue('minLength'),
3879
+ id,
3880
+ label: 'Minimum length',
3881
+ min: 0,
3882
+ setValue: onChange('minLength')
3883
+ });
3884
+ }
3885
+
3886
+ function MaxLength(props) {
3887
+ const {
3888
+ field,
3889
+ getValue,
3890
+ id,
3891
+ onChange
3892
+ } = props;
3893
+ const debounce = useService('debounce');
3894
+ return NumberFieldEntry({
3895
+ debounce,
3896
+ element: field,
3897
+ getValue: getValue('maxLength'),
3898
+ id,
3899
+ label: 'Maximum length',
3900
+ min: 0,
3901
+ setValue: onChange('maxLength')
2054
3902
  });
2055
3903
  }
2056
3904
 
2057
- function ValuesGroup(field, editField) {
3905
+ function Pattern(props) {
2058
3906
  const {
3907
+ field,
3908
+ getValue,
2059
3909
  id,
2060
- values = []
2061
- } = field;
3910
+ onChange
3911
+ } = props;
3912
+ const debounce = useService('debounce');
3913
+ return TextfieldEntry({
3914
+ debounce,
3915
+ element: field,
3916
+ getValue: getValue('pattern'),
3917
+ id,
3918
+ label: 'Regular expression pattern',
3919
+ setValue: onChange('pattern')
3920
+ });
3921
+ }
2062
3922
 
2063
- const addEntry = () => {
2064
- const index = values.length + 1;
2065
- const entry = {
2066
- label: `Value ${index}`,
2067
- value: `value${index}`
2068
- };
2069
- editField(field, ['values'], arrayAdd$1(values, values.length, entry));
2070
- };
3923
+ function Min(props) {
3924
+ const {
3925
+ field,
3926
+ getValue,
3927
+ id,
3928
+ onChange
3929
+ } = props;
3930
+ const debounce = useService('debounce');
3931
+ return NumberFieldEntry({
3932
+ debounce,
3933
+ element: field,
3934
+ getValue: getValue('min'),
3935
+ id,
3936
+ label: 'Minimum',
3937
+ min: 0,
3938
+ setValue: onChange('min')
3939
+ });
3940
+ }
2071
3941
 
2072
- const validateFactory = key => {
2073
- return value => {
2074
- if (value === key) {
2075
- return;
2076
- }
3942
+ function Max(props) {
3943
+ const {
3944
+ field,
3945
+ getValue,
3946
+ id,
3947
+ onChange
3948
+ } = props;
3949
+ const debounce = useService('debounce');
3950
+ return NumberFieldEntry({
3951
+ debounce,
3952
+ element: field,
3953
+ getValue: getValue('max'),
3954
+ id,
3955
+ label: 'Maximum',
3956
+ min: 0,
3957
+ setValue: onChange('max')
3958
+ });
3959
+ }
2077
3960
 
2078
- if (isUndefined(value) || !value.length) {
2079
- return 'Must not be empty.';
2080
- }
3961
+ function ValuesGroups(field, editField) {
3962
+ const {
3963
+ type,
3964
+ id: fieldId
3965
+ } = field;
2081
3966
 
2082
- const isValueAssigned = values.find(entry => entry.value === value);
3967
+ if (!VALUES_INPUTS.includes(type)) {
3968
+ return [];
3969
+ }
2083
3970
 
2084
- if (isValueAssigned) {
2085
- return 'Must be unique.';
2086
- }
2087
- };
3971
+ const context = {
3972
+ editField,
3973
+ field
2088
3974
  };
3975
+ const valuesSourceId = `${fieldId}-valuesSource`;
3976
+ /**
3977
+ * @type {Array<Group|ListGroup>}
3978
+ */
2089
3979
 
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;
2099
-
2100
- const removeEntry = () => {
2101
- editField(field, ['values'], arrayRemove$1(values, index));
2102
- };
2103
-
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}`);
3980
+ const groups = [{
3981
+ id: valuesSourceId,
3982
+ label: 'Options source',
3983
+ component: Group,
3984
+ entries: ValuesSourceSelectEntry({ ...context,
3985
+ id: valuesSourceId
2114
3986
  })
2115
- });
3987
+ }];
3988
+ const valuesSource = getValuesSource(field);
3989
+
3990
+ if (valuesSource === VALUES_SOURCES.INPUT) {
3991
+ const dynamicValuesId = `${fieldId}-dynamicValues`;
3992
+ groups.push({
3993
+ id: dynamicValuesId,
3994
+ label: 'Dynamic options',
3995
+ component: Group,
3996
+ entries: InputKeyValuesSourceEntry({ ...context,
3997
+ id: dynamicValuesId
3998
+ })
3999
+ });
4000
+ } else if (valuesSource === VALUES_SOURCES.STATIC) {
4001
+ const staticValuesId = `${fieldId}-staticValues`;
4002
+ groups.push({
4003
+ id: staticValuesId,
4004
+ label: 'Static options',
4005
+ component: ListGroup,
4006
+ ...StaticValuesSourceEntry({ ...context,
4007
+ id: staticValuesId
4008
+ })
4009
+ });
4010
+ }
4011
+
4012
+ return groups;
2116
4013
  }
2117
4014
 
2118
4015
  function CustomValuesGroup(field, editField) {
2119
4016
  const {
2120
- id,
2121
- properties = {}
4017
+ properties = {},
4018
+ type
2122
4019
  } = field;
2123
4020
 
2124
- const addEntry = () => {
4021
+ if (type === 'default') {
4022
+ return null;
4023
+ }
4024
+
4025
+ const addEntry = event => {
4026
+ event.stopPropagation();
2125
4027
  const index = Object.keys(properties).length + 1;
2126
4028
  const key = `key${index}`,
2127
4029
  value = 'value';
@@ -2146,28 +4048,35 @@ function CustomValuesGroup(field, editField) {
2146
4048
  };
2147
4049
  };
2148
4050
 
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
- };
4051
+ const items = Object.keys(properties).map((key, index) => {
4052
+ const removeEntry = event => {
4053
+ event.stopPropagation();
4054
+ return editField(field, ['properties'], removeKey(properties, key));
4055
+ };
2158
4056
 
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
- })
4057
+ const id = `${field.id}-property-${index}`;
4058
+ return {
4059
+ autoFocusEntry: id + '-key',
4060
+ entries: CustomValueEntry({
4061
+ editField,
4062
+ field,
4063
+ idPrefix: id,
4064
+ index,
4065
+ validateFactory
4066
+ }),
4067
+ id,
4068
+ label: key || '',
4069
+ remove: removeEntry
4070
+ };
2170
4071
  });
4072
+ return {
4073
+ add: addEntry,
4074
+ component: ListGroup,
4075
+ id: 'custom-values',
4076
+ items,
4077
+ label: 'Custom properties',
4078
+ shouldSort: false
4079
+ };
2171
4080
  } // helpers //////////
2172
4081
 
2173
4082
  /**
@@ -2193,95 +4102,54 @@ function removeKey(properties, oldKey) {
2193
4102
  }, {});
2194
4103
  }
2195
4104
 
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
4105
  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));
4106
+ if (!field) {
4107
+ return [];
2220
4108
  }
2221
4109
 
2222
- if (type !== 'default') {
2223
- groups.push(CustomValuesGroup(field, editField));
2224
- }
4110
+ 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
4111
 
2226
- return groups;
4112
+ return groups.filter(group => group !== null);
2227
4113
  }
2228
4114
 
2229
- function PropertiesPanel(props) {
4115
+ function FormPropertiesPanel(props) {
2230
4116
  const {
2231
4117
  editField,
2232
4118
  field
2233
4119
  } = props;
2234
4120
  const eventBus = useService('eventBus');
2235
4121
 
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
4122
  const onFocus = () => eventBus.fire('propertiesPanel.focusin');
2244
4123
 
2245
4124
  const onBlur = () => eventBus.fire('propertiesPanel.focusout');
2246
4125
 
2247
- const {
2248
- type
2249
- } = field;
2250
- const Icon = iconsByType[type];
2251
- const label = labelsByType[type];
2252
- return jsxs("div", {
4126
+ return jsx("div", {
2253
4127
  class: "fjs-properties-panel",
2254
- "data-field": field.id,
4128
+ "data-field": field && field.id,
2255
4129
  onFocusCapture: onFocus,
2256
4130
  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)]
4131
+ children: jsx(PropertiesPanel, {
4132
+ element: field,
4133
+ eventBus: eventBus,
4134
+ groups: getGroups(field, editField),
4135
+ headerProvider: PropertiesPanelHeaderProvider,
4136
+ placeholderProvider: PropertiesPanelPlaceholderProvider
4137
+ })
2282
4138
  });
2283
4139
  }
2284
4140
 
4141
+ 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); }
4142
+ var ListDeleteIcon = (({
4143
+ styles = {},
4144
+ ...props
4145
+ }) => /*#__PURE__*/React.createElement("svg", _extends({
4146
+ xmlns: "http://www.w3.org/2000/svg",
4147
+ width: "11",
4148
+ height: "14"
4149
+ }, props), /*#__PURE__*/React.createElement("path", {
4150
+ 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"
4151
+ })));
4152
+
2285
4153
  function ContextPad(props) {
2286
4154
  if (!props.children) {
2287
4155
  return null;
@@ -2396,12 +4264,15 @@ function FormEditor$1(props) {
2396
4264
  formFieldRegistry = useService('formFieldRegistry'),
2397
4265
  injector = useService('injector'),
2398
4266
  modeling = useService('modeling'),
2399
- selection = useService('selection');
4267
+ selection = useService('selection'),
4268
+ palette = useService('palette'),
4269
+ paletteConfig = useService('config.palette');
2400
4270
 
2401
4271
  const {
2402
4272
  schema
2403
4273
  } = formEditor._getState();
2404
4274
 
4275
+ const paletteRef = useRef(null);
2405
4276
  const [selectedFormField, setSelection] = useState(schema);
2406
4277
  useEffect(() => {
2407
4278
  function handleSelectionChanged(event) {
@@ -2485,6 +4356,10 @@ function FormEditor$1(props) {
2485
4356
  eventBus.off('attach', onAttach);
2486
4357
  eventBus.off('detach', onDetach);
2487
4358
  };
4359
+ }, []); // fire event after first render to notify interested parties
4360
+
4361
+ useEffect(() => {
4362
+ eventBus.fire('formEditor.rendered');
2488
4363
  }, []);
2489
4364
  const formRenderContext = {
2490
4365
  Children,
@@ -2519,14 +4394,21 @@ function FormEditor$1(props) {
2519
4394
  };
2520
4395
  const onSubmit = useCallback(() => {}, []);
2521
4396
  const onReset = useCallback(() => {}, []);
2522
- const editField = useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
4397
+ const editField = useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]); // attach default palette
4398
+
4399
+ const hasDefaultPalette = defaultPalette(paletteConfig);
4400
+ useEffect(() => {
4401
+ if (hasDefaultPalette) {
4402
+ palette.attachTo(paletteRef.current);
4403
+ }
4404
+ }, [palette, paletteRef, hasDefaultPalette]);
2523
4405
  return jsxs("div", {
2524
4406
  class: "fjs-form-editor",
2525
4407
  children: [jsxs(DragAndDropContext.Provider, {
2526
4408
  value: dragAndDropContext,
2527
- children: [jsx("div", {
2528
- class: "fjs-palette-container",
2529
- children: jsx(Palette, {})
4409
+ children: [hasDefaultPalette && jsx("div", {
4410
+ class: "fjs-editor-palette-container",
4411
+ ref: paletteRef
2530
4412
  }), jsx("div", {
2531
4413
  class: "fjs-form-container",
2532
4414
  children: jsx(FormContext.Provider, {
@@ -2542,7 +4424,7 @@ function FormEditor$1(props) {
2542
4424
  }), jsx(CreatePreview, {})]
2543
4425
  }), jsx("div", {
2544
4426
  class: "fjs-properties-container",
2545
- children: jsx(PropertiesPanel, {
4427
+ children: jsx(FormPropertiesPanel, {
2546
4428
  field: selectedFormField,
2547
4429
  editField: editField
2548
4430
  })
@@ -2587,6 +4469,11 @@ function CreatePreview(props) {
2587
4469
  return () => drake.off('cloned', handleCloned);
2588
4470
  }, [drake]);
2589
4471
  return null;
4472
+ } // helper //////
4473
+
4474
+
4475
+ function defaultPalette(paletteConfig) {
4476
+ return !(paletteConfig && paletteConfig.parent);
2590
4477
  }
2591
4478
 
2592
4479
  class Renderer {
@@ -4643,6 +6530,145 @@ var SelectionModule = {
4643
6530
  selectionBehavior: ['type', SelectionBehavior]
4644
6531
  };
4645
6532
 
6533
+ const types = [{
6534
+ label: 'Text Field',
6535
+ type: 'textfield'
6536
+ }, {
6537
+ label: 'Number',
6538
+ type: 'number'
6539
+ }, {
6540
+ label: 'Checkbox',
6541
+ type: 'checkbox'
6542
+ }, {
6543
+ label: 'Checklist',
6544
+ type: 'checklist'
6545
+ }, {
6546
+ label: 'Taglist',
6547
+ type: 'taglist'
6548
+ }, {
6549
+ label: 'Radio',
6550
+ type: 'radio'
6551
+ }, {
6552
+ label: 'Select',
6553
+ type: 'select'
6554
+ }, {
6555
+ label: 'Text',
6556
+ type: 'text'
6557
+ }, {
6558
+ label: 'Button',
6559
+ type: 'button'
6560
+ }];
6561
+ function Palette(props) {
6562
+ return jsxs("div", {
6563
+ class: "fjs-palette",
6564
+ children: [jsxs("div", {
6565
+ class: "fjs-palette-header",
6566
+ title: "Form elements library",
6567
+ children: [jsx("span", {
6568
+ class: "fjs-hide-compact",
6569
+ children: "FORM ELEMENTS "
6570
+ }), "LIBRARY"]
6571
+ }), jsx("div", {
6572
+ class: "fjs-palette-fields fjs-drag-container fjs-no-drop",
6573
+ children: types.map(({
6574
+ label,
6575
+ type
6576
+ }) => {
6577
+ const Icon = iconsByType[type];
6578
+ return jsxs("div", {
6579
+ class: "fjs-palette-field fjs-drag-copy fjs-no-drop",
6580
+ "data-field-type": type,
6581
+ title: `Create a ${label} element`,
6582
+ children: [Icon ? jsx(Icon, {
6583
+ class: "fjs-palette-field-icon",
6584
+ width: "36",
6585
+ height: "36",
6586
+ viewBox: "0 0 54 54"
6587
+ }) : null, jsx("span", {
6588
+ class: "fjs-palette-field-text fjs-hide-compact",
6589
+ children: label
6590
+ })]
6591
+ });
6592
+ })
6593
+ })]
6594
+ });
6595
+ }
6596
+
6597
+ class PaletteRenderer {
6598
+ constructor(paletteConfig, eventBus) {
6599
+ const {
6600
+ parent
6601
+ } = paletteConfig || {};
6602
+ this._eventBus = eventBus;
6603
+ this._container = domify('<div class="fjs-palette-container"></div>');
6604
+
6605
+ if (parent) {
6606
+ this.attachTo(parent);
6607
+ }
6608
+
6609
+ this._eventBus.once('formEditor.rendered', 500, () => {
6610
+ this._render();
6611
+ });
6612
+ }
6613
+ /**
6614
+ * Attach the palette to a parent node.
6615
+ *
6616
+ * @param {HTMLElement} container
6617
+ */
6618
+
6619
+
6620
+ attachTo(container) {
6621
+ if (!container) {
6622
+ throw new Error('container required');
6623
+ }
6624
+
6625
+ if (typeof container === 'string') {
6626
+ container = query(container);
6627
+ } // (1) detach from old parent
6628
+
6629
+
6630
+ this.detach(); // (2) append to parent container
6631
+
6632
+ container.appendChild(this._container); // (3) notify interested parties
6633
+
6634
+ this._eventBus.fire('palette.attach');
6635
+ }
6636
+ /**
6637
+ * Detach the palette from its parent node.
6638
+ */
6639
+
6640
+
6641
+ detach() {
6642
+ const parentNode = this._container.parentNode;
6643
+
6644
+ if (parentNode) {
6645
+ parentNode.removeChild(this._container);
6646
+
6647
+ this._eventBus.fire('palette.detach');
6648
+ }
6649
+ }
6650
+
6651
+ _render() {
6652
+ render(jsx(Palette, {}), this._container);
6653
+
6654
+ this._eventBus.fire('palette.rendered');
6655
+ }
6656
+
6657
+ _destroy() {
6658
+ if (this._container) {
6659
+ render(null, this._container);
6660
+
6661
+ this._eventBus.fire('palette.destroyed');
6662
+ }
6663
+ }
6664
+
6665
+ }
6666
+ PaletteRenderer.$inject = ['config.palette', 'eventBus'];
6667
+
6668
+ var PaletteModule = {
6669
+ palette: ['type', PaletteRenderer]
6670
+ };
6671
+
4646
6672
  const ids = new Ids([32, 36, 1]);
4647
6673
  /**
4648
6674
  * @typedef { import('./types').Injector } Injector
@@ -4924,7 +6950,7 @@ class FormEditor {
4924
6950
 
4925
6951
 
4926
6952
  _getModules() {
4927
- return [ModelingModule, EditorActionsModule, KeyboardModule, SelectionModule];
6953
+ return [ModelingModule, EditorActionsModule, KeyboardModule, SelectionModule, PaletteModule];
4928
6954
  }
4929
6955
  /**
4930
6956
  * @internal