@bpmn-io/properties-panel 3.2.1 → 3.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -11,11 +11,32 @@ var classnames = require('classnames');
11
11
  var minDom = require('min-dom');
12
12
  var feelers = require('feelers');
13
13
  var FeelEditor = require('@bpmn-io/feel-editor');
14
+ var view = require('@codemirror/view');
15
+ var focusTrap = require('focus-trap');
14
16
 
15
17
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
16
18
 
19
+ function _interopNamespace(e) {
20
+ if (e && e.__esModule) return e;
21
+ var n = Object.create(null);
22
+ if (e) {
23
+ Object.keys(e).forEach(function (k) {
24
+ if (k !== 'default') {
25
+ var d = Object.getOwnPropertyDescriptor(e, k);
26
+ Object.defineProperty(n, k, d.get ? d : {
27
+ enumerable: true,
28
+ get: function () { return e[k]; }
29
+ });
30
+ }
31
+ });
32
+ }
33
+ n["default"] = e;
34
+ return Object.freeze(n);
35
+ }
36
+
17
37
  var classnames__default = /*#__PURE__*/_interopDefaultLegacy(classnames);
18
38
  var FeelEditor__default = /*#__PURE__*/_interopDefaultLegacy(FeelEditor);
39
+ var focusTrap__namespace = /*#__PURE__*/_interopNamespace(focusTrap);
19
40
 
20
41
  var ArrowIcon = function ArrowIcon(props) {
21
42
  return jsxRuntime.jsx("svg", {
@@ -59,6 +80,33 @@ DeleteIcon.defaultProps = {
59
80
  width: "16",
60
81
  height: "16"
61
82
  };
83
+ var DragIcon = function DragIcon(props) {
84
+ return jsxRuntime.jsxs("svg", {
85
+ ...props,
86
+ children: [jsxRuntime.jsx("path", {
87
+ fill: "#fff",
88
+ style: {
89
+ mixBlendMode: "multiply"
90
+ },
91
+ d: "M0 0h16v16H0z"
92
+ }), jsxRuntime.jsx("path", {
93
+ fill: "#fff",
94
+ style: {
95
+ mixBlendMode: "multiply"
96
+ },
97
+ d: "M0 0h16v16H0z"
98
+ }), jsxRuntime.jsx("path", {
99
+ d: "M7 3H5v2h2V3zm4 0H9v2h2V3zM7 7H5v2h2V7zm4 0H9v2h2V7zm-4 4H5v2h2v-2zm4 0H9v2h2v-2z",
100
+ fill: "#161616"
101
+ })]
102
+ });
103
+ };
104
+ DragIcon.defaultProps = {
105
+ width: "16",
106
+ height: "16",
107
+ fill: "none",
108
+ xmlns: "http://www.w3.org/2000/svg"
109
+ };
62
110
  var ExternalLinkIcon = function ExternalLinkIcon(props) {
63
111
  return jsxRuntime.jsx("svg", {
64
112
  ...props,
@@ -66,7 +114,7 @@ var ExternalLinkIcon = function ExternalLinkIcon(props) {
66
114
  fillRule: "evenodd",
67
115
  clipRule: "evenodd",
68
116
  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",
69
- fill: "#818798"
117
+ fill: "currentcolor"
70
118
  })
71
119
  });
72
120
  };
@@ -215,7 +263,7 @@ function TooltipWrapper(props) {
215
263
  return jsxRuntime.jsx(Tooltip, {
216
264
  ...props,
217
265
  value: value,
218
- forId: prefixId$8(forId)
266
+ forId: prefixId$9(forId)
219
267
  });
220
268
  }
221
269
  function Tooltip(props) {
@@ -333,7 +381,7 @@ function getTooltipPosition(refElement) {
333
381
  function isHovered(element) {
334
382
  return element.matches(':hover');
335
383
  }
336
- function prefixId$8(id) {
384
+ function prefixId$9(id) {
337
385
  return `bio-properties-panel-${id}`;
338
386
  }
339
387
 
@@ -743,713 +791,704 @@ function Placeholder(props) {
743
791
  });
744
792
  }
745
793
 
746
- const DEFAULT_LAYOUT = {};
747
- const DEFAULT_DESCRIPTION = {};
748
- const DEFAULT_TOOLTIP = {};
794
+ function Description(props) {
795
+ const {
796
+ element,
797
+ forId,
798
+ value
799
+ } = props;
800
+ const contextDescription = useDescriptionContext(forId, element);
801
+ const description = value || contextDescription;
802
+ if (description) {
803
+ return jsxRuntime.jsx("div", {
804
+ class: "bio-properties-panel-description",
805
+ children: description
806
+ });
807
+ }
808
+ }
749
809
 
750
- /**
751
- * @typedef { {
752
- * component: import('preact').Component,
753
- * id: String,
754
- * isEdited?: Function
755
- * } } EntryDefinition
756
- *
757
- * @typedef { {
758
- * autoFocusEntry: String,
759
- * autoOpen?: Boolean,
760
- * entries: Array<EntryDefinition>,
761
- * id: String,
762
- * label: String,
763
- * remove: (event: MouseEvent) => void
764
- * } } ListItemDefinition
765
- *
766
- * @typedef { {
767
- * add: (event: MouseEvent) => void,
768
- * component: import('preact').Component,
769
- * element: Object,
770
- * id: String,
771
- * items: Array<ListItemDefinition>,
772
- * label: String,
773
- * shouldSort?: Boolean,
774
- * shouldOpen?: Boolean
775
- * } } ListGroupDefinition
776
- *
777
- * @typedef { {
778
- * component?: import('preact').Component,
779
- * entries: Array<EntryDefinition>,
780
- * id: String,
781
- * label: String,
782
- * shouldOpen?: Boolean
783
- * } } GroupDefinition
784
- *
785
- * @typedef { {
786
- * [id: String]: GetDescriptionFunction
787
- * } } DescriptionConfig
788
- *
789
- * @typedef { {
790
- * [id: String]: GetTooltipFunction
791
- * } } TooltipConfig
792
- *
793
- * @callback { {
794
- * @param {string} id
795
- * @param {Object} element
796
- * @returns {string}
797
- * } } GetDescriptionFunction
798
- *
799
- * @callback { {
800
- * @param {string} id
801
- * @param {Object} element
802
- * @returns {string}
803
- * } } GetTooltipFunction
804
- *
805
- * @typedef { {
806
- * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
807
- * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
808
- * } } PlaceholderProvider
809
- *
810
- */
810
+ const noop$6 = () => {};
811
811
 
812
812
  /**
813
- * A basic properties panel component. Describes *how* content will be rendered, accepts
814
- * data from implementor to describe *what* will be rendered.
815
- *
816
- * @param {Object} props
817
- * @param {Object|Array} props.element
818
- * @param {import('./components/Header').HeaderProvider} props.headerProvider
819
- * @param {PlaceholderProvider} [props.placeholderProvider]
820
- * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
821
- * @param {Object} [props.layoutConfig]
822
- * @param {Function} [props.layoutChanged]
823
- * @param {DescriptionConfig} [props.descriptionConfig]
824
- * @param {Function} [props.descriptionLoaded]
825
- * @param {TooltipConfig} [props.tooltipConfig]
826
- * @param {Function} [props.tooltipLoaded]
827
- * @param {Object} [props.eventBus]
813
+ * Buffer `.focus()` calls while the editor is not initialized.
814
+ * Set Focus inside when the editor is ready.
828
815
  */
829
- function PropertiesPanel(props) {
816
+ const useBufferedFocus$1 = function (editor, ref) {
817
+ const [buffer, setBuffer] = hooks.useState(undefined);
818
+ ref.current = hooks.useMemo(() => ({
819
+ focus: offset => {
820
+ if (editor) {
821
+ editor.focus(offset);
822
+ } else {
823
+ if (typeof offset === 'undefined') {
824
+ offset = Infinity;
825
+ }
826
+ setBuffer(offset);
827
+ }
828
+ }
829
+ }), [editor]);
830
+ hooks.useEffect(() => {
831
+ if (typeof buffer !== 'undefined' && editor) {
832
+ editor.focus(buffer);
833
+ setBuffer(false);
834
+ }
835
+ }, [editor, buffer]);
836
+ };
837
+ const CodeEditor$1 = compat.forwardRef((props, ref) => {
830
838
  const {
831
- element,
832
- headerProvider,
833
- placeholderProvider,
834
- groups,
835
- layoutConfig,
836
- layoutChanged,
837
- descriptionConfig,
838
- descriptionLoaded,
839
- tooltipConfig,
840
- tooltipLoaded,
841
- eventBus
839
+ onInput,
840
+ disabled,
841
+ tooltipContainer,
842
+ enableGutters,
843
+ value,
844
+ onLint = noop$6,
845
+ onPopupOpen = noop$6,
846
+ popupOpen,
847
+ contentAttributes = {},
848
+ hostLanguage = null,
849
+ singleLine = false
842
850
  } = props;
843
-
844
- // set-up layout context
845
- const [layout, setLayout] = hooks.useState(createLayout(layoutConfig));
846
-
847
- // react to external changes in the layout config
848
- useUpdateLayoutEffect(() => {
849
- const newLayout = createLayout(layoutConfig);
850
- setLayout(newLayout);
851
- }, [layoutConfig]);
851
+ const inputRef = hooks.useRef();
852
+ const [editor, setEditor] = hooks.useState();
853
+ const [localValue, setLocalValue] = hooks.useState(value || '');
854
+ useBufferedFocus$1(editor, ref);
855
+ const handleInput = useStaticCallback(newValue => {
856
+ onInput(newValue);
857
+ setLocalValue(newValue);
858
+ });
852
859
  hooks.useEffect(() => {
853
- if (typeof layoutChanged === 'function') {
854
- layoutChanged(layout);
860
+ let editor;
861
+ editor = new feelers.FeelersEditor({
862
+ container: inputRef.current,
863
+ onChange: handleInput,
864
+ value: localValue,
865
+ onLint,
866
+ contentAttributes,
867
+ tooltipContainer,
868
+ enableGutters,
869
+ hostLanguage,
870
+ singleLine
871
+ });
872
+ setEditor(editor);
873
+ return () => {
874
+ onLint([]);
875
+ inputRef.current.innerHTML = '';
876
+ setEditor(null);
877
+ };
878
+ }, []);
879
+ hooks.useEffect(() => {
880
+ if (!editor) {
881
+ return;
855
882
  }
856
- }, [layout, layoutChanged]);
857
- const getLayoutForKey = (key, defaultValue) => {
858
- return minDash.get(layout, key, defaultValue);
859
- };
860
- const setLayoutForKey = (key, config) => {
861
- const newLayout = minDash.assign({}, layout);
862
- minDash.set(newLayout, key, config);
863
- setLayout(newLayout);
864
- };
865
- const layoutContext = {
866
- layout,
867
- setLayout,
868
- getLayoutForKey,
869
- setLayoutForKey
883
+ if (value === localValue) {
884
+ return;
885
+ }
886
+ editor.setValue(value);
887
+ setLocalValue(value);
888
+ }, [value]);
889
+ const handleClick = () => {
890
+ ref.current.focus();
870
891
  };
892
+ return jsxRuntime.jsxs("div", {
893
+ class: classnames__default["default"]('bio-properties-panel-feelers-editor-container', popupOpen ? 'popupOpen' : null),
894
+ children: [jsxRuntime.jsx("div", {
895
+ class: "bio-properties-panel-feelers-editor__open-popup-placeholder",
896
+ children: "Opened in editor"
897
+ }), jsxRuntime.jsx("div", {
898
+ name: props.name,
899
+ class: classnames__default["default"]('bio-properties-panel-feelers-editor bio-properties-panel-input', localValue ? 'edited' : null, disabled ? 'disabled' : null),
900
+ ref: inputRef,
901
+ onClick: handleClick
902
+ }), jsxRuntime.jsx("button", {
903
+ title: "Open pop-up editor",
904
+ class: "bio-properties-panel-open-feel-popup",
905
+ onClick: () => onPopupOpen('feelers'),
906
+ children: jsxRuntime.jsx(ExternalLinkIcon, {})
907
+ })]
908
+ });
909
+ });
871
910
 
872
- // set-up description context
873
- const description = hooks.useMemo(() => createDescriptionContext(descriptionConfig), [descriptionConfig]);
911
+ const noop$5 = () => {};
912
+
913
+ /**
914
+ * Buffer `.focus()` calls while the editor is not initialized.
915
+ * Set Focus inside when the editor is ready.
916
+ */
917
+ const useBufferedFocus = function (editor, ref) {
918
+ const [buffer, setBuffer] = hooks.useState(undefined);
919
+ ref.current = hooks.useMemo(() => ({
920
+ focus: offset => {
921
+ if (editor) {
922
+ editor.focus(offset);
923
+ } else {
924
+ if (typeof offset === 'undefined') {
925
+ offset = Infinity;
926
+ }
927
+ setBuffer(offset);
928
+ }
929
+ }
930
+ }), [editor]);
874
931
  hooks.useEffect(() => {
875
- if (typeof descriptionLoaded === 'function') {
876
- descriptionLoaded(description);
932
+ if (typeof buffer !== 'undefined' && editor) {
933
+ editor.focus(buffer);
934
+ setBuffer(false);
877
935
  }
878
- }, [description, descriptionLoaded]);
879
- const getDescriptionForId = (id, element) => {
880
- return description[id] && description[id](element);
881
- };
882
- const descriptionContext = {
883
- description,
884
- getDescriptionForId
885
- };
936
+ }, [editor, buffer]);
937
+ };
938
+ const CodeEditor = compat.forwardRef((props, ref) => {
939
+ const {
940
+ enableGutters,
941
+ value,
942
+ onInput,
943
+ onFeelToggle = noop$5,
944
+ onLint = noop$5,
945
+ onPopupOpen = noop$5,
946
+ popupOpen,
947
+ disabled,
948
+ tooltipContainer,
949
+ variables
950
+ } = props;
951
+ const inputRef = hooks.useRef();
952
+ const [editor, setEditor] = hooks.useState();
953
+ const [localValue, setLocalValue] = hooks.useState(value || '');
954
+ useBufferedFocus(editor, ref);
955
+ const handleInput = useStaticCallback(newValue => {
956
+ onInput(newValue);
957
+ setLocalValue(newValue);
958
+ });
959
+ hooks.useEffect(() => {
960
+ let editor;
886
961
 
887
- // set-up tooltip context
888
- const tooltip = hooks.useMemo(() => createTooltipContext(tooltipConfig), [tooltipConfig]);
962
+ /* Trigger FEEL toggle when
963
+ *
964
+ * - `backspace` is pressed
965
+ * - AND the cursor is at the beginning of the input
966
+ */
967
+ const onKeyDown = e => {
968
+ if (e.key !== 'Backspace' || !editor) {
969
+ return;
970
+ }
971
+ const selection = editor.getSelection();
972
+ const range = selection.ranges[selection.mainIndex];
973
+ if (range.from === 0 && range.to === 0) {
974
+ onFeelToggle();
975
+ }
976
+ };
977
+ editor = new FeelEditor__default["default"]({
978
+ container: inputRef.current,
979
+ onChange: handleInput,
980
+ onKeyDown: onKeyDown,
981
+ onLint: onLint,
982
+ tooltipContainer: tooltipContainer,
983
+ value: localValue,
984
+ variables: variables,
985
+ extensions: [...(enableGutters ? [view.lineNumbers()] : [])]
986
+ });
987
+ setEditor(editor);
988
+ return () => {
989
+ onLint([]);
990
+ inputRef.current.innerHTML = '';
991
+ setEditor(null);
992
+ };
993
+ }, []);
889
994
  hooks.useEffect(() => {
890
- if (typeof tooltipLoaded === 'function') {
891
- tooltipLoaded(tooltip);
995
+ if (!editor) {
996
+ return;
892
997
  }
893
- }, [tooltip, tooltipLoaded]);
894
- const getTooltipForId = (id, element) => {
895
- return tooltip[id] && tooltip[id](element);
896
- };
897
- const tooltipContext = {
898
- tooltip,
899
- getTooltipForId
900
- };
901
- const [errors, setErrors] = hooks.useState({});
902
- const onSetErrors = ({
903
- errors
904
- }) => setErrors(errors);
905
- useEvent('propertiesPanel.setErrors', onSetErrors, eventBus);
906
- const errorsContext = {
907
- errors
908
- };
909
- const eventContext = {
910
- eventBus
911
- };
912
- const propertiesPanelContext = {
913
- element
998
+ if (value === localValue) {
999
+ return;
1000
+ }
1001
+ editor.setValue(value);
1002
+ setLocalValue(value);
1003
+ }, [value]);
1004
+ hooks.useEffect(() => {
1005
+ if (!editor) {
1006
+ return;
1007
+ }
1008
+ editor.setVariables(variables);
1009
+ }, [variables]);
1010
+ const handleClick = () => {
1011
+ ref.current.focus();
914
1012
  };
1013
+ return jsxRuntime.jsxs("div", {
1014
+ class: classnames__default["default"]('bio-properties-panel-feel-editor-container', disabled ? 'disabled' : null, popupOpen ? 'popupOpen' : null),
1015
+ children: [jsxRuntime.jsx("div", {
1016
+ class: "bio-properties-panel-feel-editor__open-popup-placeholder",
1017
+ children: "Opened in editor"
1018
+ }), jsxRuntime.jsx("div", {
1019
+ name: props.name,
1020
+ class: classnames__default["default"]('bio-properties-panel-input', localValue ? 'edited' : null),
1021
+ ref: inputRef,
1022
+ onClick: handleClick
1023
+ }), jsxRuntime.jsx("button", {
1024
+ title: "Open pop-up editor",
1025
+ class: "bio-properties-panel-open-feel-popup",
1026
+ onClick: () => onPopupOpen(),
1027
+ children: jsxRuntime.jsx(ExternalLinkIcon, {})
1028
+ })]
1029
+ });
1030
+ });
915
1031
 
916
- // empty state
917
- if (placeholderProvider && !element) {
918
- return jsxRuntime.jsx(Placeholder, {
919
- ...placeholderProvider.getEmpty()
920
- });
921
- }
922
-
923
- // multiple state
924
- if (placeholderProvider && minDash.isArray(element)) {
925
- return jsxRuntime.jsx(Placeholder, {
926
- ...placeholderProvider.getMultiple()
927
- });
1032
+ function FeelIndicator(props) {
1033
+ const {
1034
+ active
1035
+ } = props;
1036
+ if (!active) {
1037
+ return null;
928
1038
  }
929
- return jsxRuntime.jsx(LayoutContext.Provider, {
930
- value: propertiesPanelContext,
931
- children: jsxRuntime.jsx(ErrorsContext.Provider, {
932
- value: errorsContext,
933
- children: jsxRuntime.jsx(DescriptionContext.Provider, {
934
- value: descriptionContext,
935
- children: jsxRuntime.jsx(TooltipContext.Provider, {
936
- value: tooltipContext,
937
- children: jsxRuntime.jsx(LayoutContext.Provider, {
938
- value: layoutContext,
939
- children: jsxRuntime.jsx(EventContext.Provider, {
940
- value: eventContext,
941
- children: jsxRuntime.jsxs("div", {
942
- class: "bio-properties-panel",
943
- children: [jsxRuntime.jsx(Header, {
944
- element: element,
945
- headerProvider: headerProvider
946
- }), jsxRuntime.jsx("div", {
947
- class: "bio-properties-panel-scroll-container",
948
- children: groups.map(group => {
949
- const {
950
- component: Component = Group,
951
- id
952
- } = group;
953
- return preact.createElement(Component, {
954
- ...group,
955
- key: id,
956
- element: element
957
- });
958
- })
959
- })]
960
- })
961
- })
962
- })
963
- })
964
- })
965
- })
1039
+ return jsxRuntime.jsx("span", {
1040
+ class: "bio-properties-panel-feel-indicator",
1041
+ children: "="
966
1042
  });
967
1043
  }
968
1044
 
969
- // helpers //////////////////
1045
+ const noop$4 = () => {};
970
1046
 
971
- function createLayout(overrides = {}, defaults = DEFAULT_LAYOUT) {
972
- return {
973
- ...defaults,
974
- ...overrides
975
- };
976
- }
977
- function createDescriptionContext(overrides = {}) {
978
- return {
979
- ...DEFAULT_DESCRIPTION,
980
- ...overrides
981
- };
982
- }
983
- function createTooltipContext(overrides = {}) {
984
- return {
985
- ...DEFAULT_TOOLTIP,
986
- ...overrides
1047
+ /**
1048
+ * @param {Object} props
1049
+ * @param {Object} props.label
1050
+ * @param {String} props.feel
1051
+ */
1052
+ function FeelIcon(props) {
1053
+ const {
1054
+ feel = false,
1055
+ active,
1056
+ disabled = false,
1057
+ onClick = noop$4
1058
+ } = props;
1059
+ const feelRequiredLabel = 'FEEL expression is mandatory';
1060
+ const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
1061
+ const handleClick = e => {
1062
+ onClick(e);
1063
+
1064
+ // when pointer event was created from keyboard, keep focus on button
1065
+ if (!e.pointerType) {
1066
+ e.stopPropagation();
1067
+ }
987
1068
  };
1069
+ return jsxRuntime.jsx("button", {
1070
+ class: classnames__default["default"]('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
1071
+ onClick: handleClick,
1072
+ disabled: feel === 'required' || disabled,
1073
+ title: feel === 'required' ? feelRequiredLabel : feelOptionalLabel,
1074
+ children: jsxRuntime.jsx(FeelIcon$1, {})
1075
+ });
988
1076
  }
989
1077
 
990
- // hooks //////////////////
1078
+ const FeelPopupContext = preact.createContext({
1079
+ open: () => {},
1080
+ close: () => {},
1081
+ source: null
1082
+ });
991
1083
 
992
1084
  /**
993
- * This hook behaves like useLayoutEffect, but does not trigger on the first render.
1085
+ * Add a dragger that calls back the passed function with
1086
+ * { event, delta } on drag.
994
1087
  *
995
- * @param {Function} effect
996
- * @param {Array} deps
1088
+ * @example
1089
+ *
1090
+ * function dragMove(event, delta) {
1091
+ * // we are dragging (!!)
1092
+ * }
1093
+ *
1094
+ * domElement.addEventListener('dragstart', dragger(dragMove));
1095
+ *
1096
+ * @param {Function} fn
1097
+ * @param {Element} [dragPreview]
1098
+ *
1099
+ * @return {Function} drag start callback function
997
1100
  */
998
- function useUpdateLayoutEffect(effect, deps) {
999
- const isMounted = hooks.useRef(false);
1000
- hooks.useLayoutEffect(() => {
1001
- if (isMounted.current) {
1002
- return effect();
1003
- } else {
1004
- isMounted.current = true;
1101
+ function createDragger(fn, dragPreview) {
1102
+ let self;
1103
+ let startX, startY;
1104
+
1105
+ /** drag start */
1106
+ function onDragStart(event) {
1107
+ self = this;
1108
+ startX = event.clientX;
1109
+ startY = event.clientY;
1110
+
1111
+ // (1) prevent preview image
1112
+ if (event.dataTransfer) {
1113
+ event.dataTransfer.setDragImage(dragPreview || emptyCanvas(), 0, 0);
1005
1114
  }
1006
- }, deps);
1115
+
1116
+ // (2) setup drag listeners
1117
+
1118
+ // attach drag + cleanup event
1119
+ document.addEventListener('dragover', onDrag);
1120
+ document.addEventListener('dragend', onEnd);
1121
+ document.addEventListener('drop', preventDefault);
1122
+ }
1123
+ function onDrag(event) {
1124
+ const delta = {
1125
+ x: event.clientX - startX,
1126
+ y: event.clientY - startY
1127
+ };
1128
+
1129
+ // call provided fn with event, delta
1130
+ return fn.call(self, event, delta);
1131
+ }
1132
+ function onEnd() {
1133
+ document.removeEventListener('dragover', onDrag);
1134
+ document.removeEventListener('dragend', onEnd);
1135
+ document.removeEventListener('drop', preventDefault);
1136
+ }
1137
+ return onDragStart;
1138
+ }
1139
+ function preventDefault(event) {
1140
+ event.preventDefault();
1141
+ event.stopPropagation();
1142
+ }
1143
+ function emptyCanvas() {
1144
+ return minDom.domify('<canvas width="0" height="0" />');
1007
1145
  }
1008
1146
 
1009
- function DropdownButton(props) {
1147
+ const noop$3 = () => {};
1148
+
1149
+ /**
1150
+ * A generic popup component.
1151
+ *
1152
+ * @param {Object} props
1153
+ * @param {HTMLElement} [props.container]
1154
+ * @param {string} [props.className]
1155
+ * @param {{x: number, y: number}} [props.position]
1156
+ * @param {number} [props.width]
1157
+ * @param {number} [props.height]
1158
+ * @param {Function} props.onClose
1159
+ * @param {Function} [props.onPostActivate]
1160
+ * @param {Function} [props.onPostDeactivate]
1161
+ * @param {boolean} [props.returnFocus]
1162
+ * @param {string} props.title
1163
+ */
1164
+ function Popup(props) {
1010
1165
  const {
1011
- class: className,
1012
- children,
1013
- menuItems = []
1166
+ container,
1167
+ className,
1168
+ position,
1169
+ width,
1170
+ height,
1171
+ onClose,
1172
+ onPostActivate = noop$3,
1173
+ onPostDeactivate = noop$3,
1174
+ returnFocus = true,
1175
+ title
1014
1176
  } = props;
1015
- const dropdownRef = hooks.useRef(null);
1016
- const menuRef = hooks.useRef(null);
1017
- const [open, setOpen] = hooks.useState(false);
1018
- const close = () => setOpen(false);
1019
- function onDropdownToggle(event) {
1020
- if (menuRef.current && menuRef.current.contains(event.target)) {
1021
- return;
1177
+ const focusTrapRef = hooks.useRef(null);
1178
+ const popupRef = hooks.useRef(null);
1179
+ const handleKeyPress = event => {
1180
+ if (event.key === 'Escape') {
1181
+ onClose();
1022
1182
  }
1023
- event.stopPropagation();
1024
- setOpen(open => !open);
1183
+ };
1184
+
1185
+ // re-activate focus trap on focus
1186
+ const handleFocus = () => {
1187
+ if (focusTrapRef.current) {
1188
+ focusTrapRef.current.activate();
1189
+ }
1190
+ };
1191
+ let style = {};
1192
+ if (position) {
1193
+ style = {
1194
+ ...style,
1195
+ top: position.top + 'px',
1196
+ left: position.left + 'px'
1197
+ };
1025
1198
  }
1026
- function onActionClick(event, action) {
1027
- event.stopPropagation();
1028
- close();
1029
- action();
1199
+ if (width) {
1200
+ style.width = width + 'px';
1030
1201
  }
1031
- useGlobalClick([dropdownRef.current], () => close());
1032
- return jsxRuntime.jsxs("div", {
1033
- class: classnames__default["default"]('bio-properties-panel-dropdown-button', {
1034
- open
1035
- }, className),
1036
- onClick: onDropdownToggle,
1037
- ref: dropdownRef,
1038
- children: [children, jsxRuntime.jsx("div", {
1039
- class: "bio-properties-panel-dropdown-button__menu",
1040
- ref: menuRef,
1041
- children: menuItems.map((item, index) => jsxRuntime.jsx(MenuItem, {
1042
- onClick: onActionClick,
1043
- item: item
1044
- }, index))
1045
- })]
1046
- });
1047
- }
1048
- function MenuItem({
1049
- item,
1050
- onClick
1051
- }) {
1052
- if (item.separator) {
1053
- return jsxRuntime.jsx("div", {
1054
- class: "bio-properties-panel-dropdown-button__menu-item bio-properties-panel-dropdown-button__menu-item--separator"
1055
- });
1056
- }
1057
- if (item.action) {
1058
- return jsxRuntime.jsx("button", {
1059
- class: "bio-properties-panel-dropdown-button__menu-item bio-properties-panel-dropdown-button__menu-item--actionable",
1060
- onClick: event => onClick(event, item.action),
1061
- children: item.entry
1062
- });
1202
+ if (height) {
1203
+ style.height = height + 'px';
1063
1204
  }
1064
- return jsxRuntime.jsx("div", {
1065
- class: "bio-properties-panel-dropdown-button__menu-item",
1066
- children: item.entry
1067
- });
1068
- }
1069
-
1070
- /**
1071
- *
1072
- * @param {Array<null | Element>} ignoredElements
1073
- * @param {Function} callback
1074
- */
1075
- function useGlobalClick(ignoredElements, callback) {
1076
1205
  hooks.useEffect(() => {
1077
- /**
1078
- * @param {MouseEvent} event
1079
- */
1080
- function listener(event) {
1081
- if (ignoredElements.some(element => element && element.contains(event.target))) {
1082
- return;
1083
- }
1084
- callback();
1206
+ if (popupRef.current) {
1207
+ popupRef.current.addEventListener('keydown', handleKeyPress);
1085
1208
  }
1086
- document.addEventListener('click', listener, {
1087
- capture: true
1088
- });
1089
- return () => document.removeEventListener('click', listener, {
1090
- capture: true
1091
- });
1092
- }, [...ignoredElements, callback]);
1209
+ return () => {
1210
+ popupRef.current.removeEventListener('keydown', handleKeyPress);
1211
+ };
1212
+ }, [popupRef]);
1213
+ hooks.useEffect(() => {
1214
+ if (popupRef.current) {
1215
+ popupRef.current.addEventListener('focusin', handleFocus);
1216
+ }
1217
+ return () => {
1218
+ popupRef.current.removeEventListener('focusin', handleFocus);
1219
+ };
1220
+ }, [popupRef]);
1221
+ hooks.useEffect(() => {
1222
+ if (popupRef.current) {
1223
+ focusTrapRef.current = focusTrap__namespace.createFocusTrap(popupRef.current, {
1224
+ clickOutsideDeactivates: true,
1225
+ fallbackFocus: popupRef.current,
1226
+ onPostActivate,
1227
+ onPostDeactivate,
1228
+ returnFocusOnDeactivate: returnFocus
1229
+ });
1230
+ focusTrapRef.current.activate();
1231
+ }
1232
+ return () => focusTrapRef.current && focusTrapRef.current.deactivate();
1233
+ }, [popupRef]);
1234
+ return compat.createPortal(jsxRuntime.jsx("div", {
1235
+ "aria-label": title,
1236
+ tabIndex: -1,
1237
+ ref: popupRef,
1238
+ role: "dialog",
1239
+ class: classnames__default["default"]('bio-properties-panel-popup', className),
1240
+ style: style,
1241
+ children: props.children
1242
+ }), container || document.body);
1093
1243
  }
1094
-
1095
- function HeaderButton(props) {
1244
+ Popup.Title = Title;
1245
+ Popup.Body = Body;
1246
+ Popup.Footer = Footer;
1247
+ function Title(props) {
1096
1248
  const {
1097
- children = null,
1098
- class: classname,
1099
- onClick = () => {},
1100
- ...otherProps
1249
+ children,
1250
+ className,
1251
+ draggable,
1252
+ title,
1253
+ ...rest
1101
1254
  } = props;
1102
- return jsxRuntime.jsx("button", {
1103
- ...otherProps,
1104
- onClick: onClick,
1105
- class: classnames__default["default"]('bio-properties-panel-group-header-button', classname),
1106
- children: children
1107
- });
1108
- }
1109
1255
 
1110
- function CollapsibleEntry(props) {
1111
- const {
1112
- element,
1113
- entries = [],
1114
- id,
1115
- label,
1116
- open: shouldOpen,
1117
- remove
1118
- } = props;
1119
- const [open, setOpen] = hooks.useState(shouldOpen);
1120
- const toggleOpen = () => setOpen(!open);
1121
- const {
1122
- onShow
1123
- } = hooks.useContext(LayoutContext);
1124
- const propertiesPanelContext = {
1125
- ...hooks.useContext(LayoutContext),
1126
- onShow: hooks.useCallback(() => {
1127
- setOpen(true);
1128
- if (minDash.isFunction(onShow)) {
1129
- onShow();
1130
- }
1131
- }, [onShow, setOpen])
1256
+ // we can't use state as we need to
1257
+ // manipulate this inside dragging events
1258
+ const context = hooks.useRef({
1259
+ startPosition: null,
1260
+ newPosition: null
1261
+ });
1262
+ const dragPreviewRef = hooks.useRef();
1263
+ const titleRef = hooks.useRef();
1264
+ const onMove = minDash.throttle((_, delta) => {
1265
+ const {
1266
+ x: dx,
1267
+ y: dy
1268
+ } = delta;
1269
+ const newPosition = {
1270
+ x: context.current.startPosition.x + dx,
1271
+ y: context.current.startPosition.y + dy
1272
+ };
1273
+ const popupParent = getPopupParent(titleRef.current);
1274
+ popupParent.style.top = newPosition.y + 'px';
1275
+ popupParent.style.left = newPosition.x + 'px';
1276
+ });
1277
+ const onMoveStart = event => {
1278
+ // initialize drag handler
1279
+ const onDragStart = createDragger(onMove, dragPreviewRef.current);
1280
+ onDragStart(event);
1281
+ const popupParent = getPopupParent(titleRef.current);
1282
+ const bounds = popupParent.getBoundingClientRect();
1283
+ context.current.startPosition = {
1284
+ x: bounds.left,
1285
+ y: bounds.top
1286
+ };
1287
+ };
1288
+ const onMoveEnd = () => {
1289
+ context.current.newPosition = null;
1132
1290
  };
1133
-
1134
- // todo(pinussilvestrus): translate once we have a translate mechanism for the core
1135
- const placeholderLabel = '<empty>';
1136
1291
  return jsxRuntime.jsxs("div", {
1137
- "data-entry-id": id,
1138
- class: classnames__default["default"]('bio-properties-panel-collapsible-entry', open ? 'open' : ''),
1139
- children: [jsxRuntime.jsxs("div", {
1140
- class: "bio-properties-panel-collapsible-entry-header",
1141
- onClick: toggleOpen,
1292
+ class: classnames__default["default"]('bio-properties-panel-popup__header', draggable && 'draggable', className),
1293
+ ref: titleRef,
1294
+ draggable: draggable,
1295
+ onDragStart: onMoveStart,
1296
+ onDragEnd: onMoveEnd,
1297
+ ...rest,
1298
+ children: [draggable && jsxRuntime.jsxs(jsxRuntime.Fragment, {
1142
1299
  children: [jsxRuntime.jsx("div", {
1143
- title: label || placeholderLabel,
1144
- class: classnames__default["default"]('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
1145
- children: label || placeholderLabel
1146
- }), jsxRuntime.jsx("button", {
1147
- title: "Toggle list item",
1148
- class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
1149
- children: jsxRuntime.jsx(ArrowIcon, {
1150
- class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1151
- })
1152
- }), remove ? jsxRuntime.jsx("button", {
1153
- title: "Delete item",
1154
- class: "bio-properties-panel-remove-entry",
1155
- onClick: remove,
1156
- children: jsxRuntime.jsx(DeleteIcon, {})
1157
- }) : null]
1300
+ ref: dragPreviewRef,
1301
+ class: "bio-properties-panel-popup__drag-preview"
1302
+ }), jsxRuntime.jsx("div", {
1303
+ class: "bio-properties-panel-popup__drag-handle",
1304
+ children: jsxRuntime.jsx(DragIcon, {})
1305
+ })]
1158
1306
  }), jsxRuntime.jsx("div", {
1159
- class: classnames__default["default"]('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
1160
- children: jsxRuntime.jsx(LayoutContext.Provider, {
1161
- value: propertiesPanelContext,
1162
- children: entries.map(entry => {
1163
- const {
1164
- component: Component,
1165
- id
1166
- } = entry;
1167
- return preact.createElement(Component, {
1168
- ...entry,
1169
- element: element,
1170
- key: id
1171
- });
1172
- })
1173
- })
1174
- })]
1307
+ class: "bio-properties-panel-popup__title",
1308
+ children: title
1309
+ }), children]
1175
1310
  });
1176
1311
  }
1177
-
1178
- function ListItem(props) {
1312
+ function Body(props) {
1179
1313
  const {
1180
- autoFocusEntry,
1181
- autoOpen
1314
+ children,
1315
+ className,
1316
+ ...rest
1182
1317
  } = props;
1183
-
1184
- // focus specified entry on auto open
1185
- hooks.useEffect(() => {
1186
- if (autoOpen && autoFocusEntry) {
1187
- const entry = minDom.query(`[data-entry-id="${autoFocusEntry}"]`);
1188
- const focusableInput = minDom.query('.bio-properties-panel-input', entry);
1189
- if (focusableInput) {
1190
- if (minDash.isFunction(focusableInput.select)) {
1191
- focusableInput.select();
1192
- } else if (minDash.isFunction(focusableInput.focus)) {
1193
- focusableInput.focus();
1194
- }
1195
- }
1196
- }
1197
- }, [autoOpen, autoFocusEntry]);
1198
1318
  return jsxRuntime.jsx("div", {
1199
- class: "bio-properties-panel-list-item",
1200
- children: jsxRuntime.jsx(CollapsibleEntry, {
1201
- ...props,
1202
- open: autoOpen
1203
- })
1319
+ class: classnames__default["default"]('bio-properties-panel-popup__body', className),
1320
+ ...rest,
1321
+ children: children
1322
+ });
1323
+ }
1324
+ function Footer(props) {
1325
+ const {
1326
+ children,
1327
+ className,
1328
+ ...rest
1329
+ } = props;
1330
+ return jsxRuntime.jsx("div", {
1331
+ class: classnames__default["default"]('bio-properties-panel-popup__footer', className),
1332
+ ...rest,
1333
+ children: props.children
1204
1334
  });
1205
1335
  }
1206
1336
 
1207
- const noop$3 = () => {};
1337
+ // helpers //////////////////////
1338
+
1339
+ function getPopupParent(node) {
1340
+ return node.closest('.bio-properties-panel-popup');
1341
+ }
1342
+
1343
+ const FEEL_POPUP_WIDTH = 700;
1344
+ const FEEL_POPUP_HEIGHT = 250;
1208
1345
 
1209
1346
  /**
1210
- * @param {import('../PropertiesPanel').ListGroupDefinition} props
1347
+ * FEEL popup component, built as a singleton.
1211
1348
  */
1212
- function ListGroup(props) {
1349
+ function FEELPopupRoot(props) {
1213
1350
  const {
1214
- add,
1215
- element,
1216
- id,
1217
- items,
1218
- label,
1219
- shouldOpen = true,
1220
- shouldSort = true
1351
+ element
1221
1352
  } = props;
1222
- const groupRef = hooks.useRef(null);
1223
- const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
1224
- const [sticky, setSticky] = hooks.useState(false);
1225
- const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
1226
- const [ordering, setOrdering] = hooks.useState([]);
1227
- const [newItemAdded, setNewItemAdded] = hooks.useState(false);
1228
-
1229
- // Flag to mark that add button was clicked in the last render cycle
1230
- const [addTriggered, setAddTriggered] = hooks.useState(false);
1231
- const prevItems = usePrevious(items);
1232
1353
  const prevElement = usePrevious(element);
1233
- const elementChanged = element !== prevElement;
1234
- const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
1235
-
1236
- // reset initial ordering when element changes (before first render)
1237
- if (elementChanged) {
1238
- setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
1239
- }
1240
-
1241
- // keep ordering in sync to items - and open changes
1354
+ const [popupConfig, setPopupConfig] = hooks.useState({});
1355
+ const [open, setOpen] = hooks.useState(false);
1356
+ const [source, setSource] = hooks.useState(null);
1357
+ const [sourceElement, setSourceElement] = hooks.useState(null);
1358
+ const handleOpen = (key, config, _sourceElement) => {
1359
+ setSource(key);
1360
+ setPopupConfig(config);
1361
+ setOpen(true);
1362
+ setSourceElement(_sourceElement);
1363
+ };
1364
+ const handleClose = () => {
1365
+ setOpen(false);
1366
+ setSource(null);
1367
+ };
1368
+ const feelPopupContext = {
1369
+ open: handleOpen,
1370
+ close: handleClose,
1371
+ source
1372
+ };
1242
1373
 
1243
- // (0) set initial ordering from given items
1374
+ // close popup on element change, cf. https://github.com/bpmn-io/properties-panel/issues/270
1244
1375
  hooks.useEffect(() => {
1245
- if (!prevItems || !shouldSort) {
1246
- setOrdering(createOrdering(items));
1376
+ if (element && element !== prevElement) {
1377
+ handleClose();
1247
1378
  }
1248
- }, [items, element]);
1249
-
1250
- // (1) items were added
1379
+ }, [element]);
1380
+ return jsxRuntime.jsxs(FeelPopupContext.Provider, {
1381
+ value: feelPopupContext,
1382
+ children: [open && jsxRuntime.jsx(FeelPopupComponent, {
1383
+ onClose: handleClose,
1384
+ sourceElement: sourceElement,
1385
+ ...popupConfig
1386
+ }), props.children]
1387
+ });
1388
+ }
1389
+ function FeelPopupComponent(props) {
1390
+ const {
1391
+ id,
1392
+ hostLanguage,
1393
+ onInput,
1394
+ onClose,
1395
+ position,
1396
+ singleLine,
1397
+ sourceElement,
1398
+ title,
1399
+ tooltipContainer,
1400
+ type,
1401
+ value,
1402
+ variables
1403
+ } = props;
1404
+ const editorRef = hooks.useRef();
1405
+ const handleSetReturnFocus = () => {
1406
+ sourceElement && sourceElement.focus();
1407
+ };
1251
1408
  hooks.useEffect(() => {
1252
- // reset addTriggered flag
1253
- setAddTriggered(false);
1254
- if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
1255
- let add = [];
1256
- items.forEach(item => {
1257
- if (!ordering.includes(item.id)) {
1258
- add.push(item.id);
1259
- }
1260
- });
1261
- let newOrdering = ordering;
1409
+ const editor = editorRef.current;
1410
+ if (editor) {
1411
+ editor.focus();
1412
+ }
1413
+ }, [editorRef, id]);
1414
+ return jsxRuntime.jsxs(Popup, {
1415
+ className: "bio-properties-panel-feel-popup",
1416
+ position: position,
1417
+ title: title,
1418
+ onClose: onClose
1419
+
1420
+ // handle focus manually on deactivate
1421
+ ,
1422
+ returnFocus: false,
1423
+ onPostDeactivate: handleSetReturnFocus,
1424
+ height: FEEL_POPUP_HEIGHT,
1425
+ width: FEEL_POPUP_WIDTH,
1426
+ children: [jsxRuntime.jsx(Popup.Title, {
1427
+ title: title,
1428
+ draggable: true
1429
+ }), jsxRuntime.jsx(Popup.Body, {
1430
+ children: jsxRuntime.jsxs("div", {
1431
+ class: "bio-properties-panel-feel-popup__body",
1432
+ children: [type === 'feel' && jsxRuntime.jsx(CodeEditor, {
1433
+ enableGutters: true,
1434
+ id: prefixId$8(id),
1435
+ name: id,
1436
+ onInput: onInput,
1437
+ value: value,
1438
+ variables: variables,
1439
+ ref: editorRef,
1440
+ tooltipContainer: tooltipContainer
1441
+ }), type === 'feelers' && jsxRuntime.jsx(CodeEditor$1, {
1442
+ id: prefixId$8(id),
1443
+ contentAttributes: {
1444
+ 'aria-label': title
1445
+ },
1446
+ enableGutters: true,
1447
+ hostLanguage: hostLanguage,
1448
+ name: id,
1449
+ onInput: onInput,
1450
+ value: value,
1451
+ ref: editorRef,
1452
+ singleLine: singleLine,
1453
+ tooltipContainer: tooltipContainer
1454
+ })]
1455
+ })
1456
+ }), jsxRuntime.jsx(Popup.Footer, {
1457
+ children: jsxRuntime.jsx("button", {
1458
+ onClick: onClose,
1459
+ title: "Close pop-up editor",
1460
+ class: "bio-properties-panel-feel-popup__close-btn",
1461
+ children: "Close"
1462
+ })
1463
+ })]
1464
+ });
1465
+ }
1262
1466
 
1263
- // open if not open, configured and triggered by add button
1264
- //
1265
- // TODO(marstamm): remove once we refactor layout handling for listGroups.
1266
- // Ideally, opening should be handled as part of the `add` callback and
1267
- // not be a concern for the ListGroup component.
1268
- if (addTriggered && !open && shouldOpen) {
1269
- toggleOpen();
1270
- }
1467
+ // helpers /////////////////
1271
1468
 
1272
- // filter when not open and configured
1273
- if (!open && shouldSort) {
1274
- newOrdering = createOrdering(sortItems(items));
1275
- }
1276
-
1277
- // add new items on top or bottom depending on sorting behavior
1278
- newOrdering = newOrdering.filter(item => !add.includes(item));
1279
- if (shouldSort) {
1280
- newOrdering.unshift(...add);
1281
- } else {
1282
- newOrdering.push(...add);
1283
- }
1284
- setOrdering(newOrdering);
1285
- setNewItemAdded(addTriggered);
1286
- } else {
1287
- setNewItemAdded(false);
1288
- }
1289
- }, [items, open, shouldHandleEffects, addTriggered]);
1290
-
1291
- // (2) sort items on open if shouldSort is set
1292
- hooks.useEffect(() => {
1293
- if (shouldSort && open && !newItemAdded) {
1294
- setOrdering(createOrdering(sortItems(items)));
1295
- }
1296
- }, [open, shouldSort]);
1297
-
1298
- // (3) items were deleted
1299
- hooks.useEffect(() => {
1300
- if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
1301
- let keep = [];
1302
- ordering.forEach(o => {
1303
- if (getItem(items, o)) {
1304
- keep.push(o);
1305
- }
1306
- });
1307
- setOrdering(keep);
1308
- }
1309
- }, [items, shouldHandleEffects]);
1310
-
1311
- // set css class when group is sticky to top
1312
- useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
1313
- const toggleOpen = () => setOpen(!open);
1314
- const hasItems = !!items.length;
1315
- const propertiesPanelContext = {
1316
- ...hooks.useContext(LayoutContext),
1317
- onShow
1318
- };
1319
- const handleAddClick = e => {
1320
- setAddTriggered(true);
1321
- add(e);
1322
- };
1323
- const allErrors = useErrors();
1324
- const hasError = items.some(item => {
1325
- if (allErrors[item.id]) {
1326
- return true;
1327
- }
1328
- if (!item.entries) {
1329
- return;
1330
- }
1331
-
1332
- // also check if the error is nested, e.g. for name-value entries
1333
- return item.entries.some(entry => allErrors[entry.id]);
1334
- });
1335
- return jsxRuntime.jsxs("div", {
1336
- class: "bio-properties-panel-group",
1337
- "data-group-id": 'group-' + id,
1338
- ref: groupRef,
1339
- children: [jsxRuntime.jsxs("div", {
1340
- class: classnames__default["default"]('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
1341
- onClick: hasItems ? toggleOpen : noop$3,
1342
- children: [jsxRuntime.jsx("div", {
1343
- title: label,
1344
- class: "bio-properties-panel-group-header-title",
1345
- children: jsxRuntime.jsx(TooltipWrapper, {
1346
- value: props.tooltip,
1347
- forId: 'group-' + id,
1348
- element: element,
1349
- parent: groupRef,
1350
- children: label
1351
- })
1352
- }), jsxRuntime.jsxs("div", {
1353
- class: "bio-properties-panel-group-header-buttons",
1354
- children: [add ? jsxRuntime.jsxs("button", {
1355
- title: "Create new list item",
1356
- class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
1357
- onClick: handleAddClick,
1358
- children: [jsxRuntime.jsx(CreateIcon, {}), !hasItems ? jsxRuntime.jsx("span", {
1359
- class: "bio-properties-panel-add-entry-label",
1360
- children: "Create"
1361
- }) : null]
1362
- }) : null, hasItems ? jsxRuntime.jsx("div", {
1363
- title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
1364
- class: classnames__default["default"]('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
1365
- children: items.length
1366
- }) : null, hasItems ? jsxRuntime.jsx("button", {
1367
- title: "Toggle section",
1368
- class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
1369
- children: jsxRuntime.jsx(ArrowIcon, {
1370
- class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
1371
- })
1372
- }) : null]
1373
- })]
1374
- }), jsxRuntime.jsx("div", {
1375
- class: classnames__default["default"]('bio-properties-panel-list', open && hasItems ? 'open' : ''),
1376
- children: jsxRuntime.jsx(LayoutContext.Provider, {
1377
- value: propertiesPanelContext,
1378
- children: ordering.map((o, index) => {
1379
- const item = getItem(items, o);
1380
- if (!item) {
1381
- return;
1382
- }
1383
- const {
1384
- id
1385
- } = item;
1386
-
1387
- // if item was added, open it
1388
- // Existing items will not be affected as autoOpen is only applied on first render
1389
- const autoOpen = newItemAdded;
1390
- return preact.createElement(ListItem, {
1391
- ...item,
1392
- autoOpen: autoOpen,
1393
- element: element,
1394
- index: index,
1395
- key: id
1396
- });
1397
- })
1398
- })
1399
- })]
1400
- });
1401
- }
1402
-
1403
- // helpers ////////////////////
1404
-
1405
- /**
1406
- * Sorts given items alphanumeric by label
1407
- */
1408
- function sortItems(items) {
1409
- return minDash.sortBy(items, i => i.label.toLowerCase());
1410
- }
1411
- function getItem(items, id) {
1412
- return minDash.find(items, i => i.id === id);
1413
- }
1414
- function createOrdering(items) {
1415
- return items.map(i => i.id);
1416
- }
1417
-
1418
- function Description(props) {
1419
- const {
1420
- element,
1421
- forId,
1422
- value
1423
- } = props;
1424
- const contextDescription = useDescriptionContext(forId, element);
1425
- const description = value || contextDescription;
1426
- if (description) {
1427
- return jsxRuntime.jsx("div", {
1428
- class: "bio-properties-panel-description",
1429
- children: description
1430
- });
1431
- }
1469
+ function prefixId$8(id) {
1470
+ return `bio-properties-panel-${id}`;
1432
1471
  }
1433
1472
 
1434
- function Checkbox(props) {
1473
+ function ToggleSwitch(props) {
1435
1474
  const {
1436
1475
  id,
1437
1476
  label,
1438
- onChange,
1439
- disabled,
1440
- value = false,
1477
+ onInput,
1478
+ value,
1479
+ switcherLabel,
1480
+ inline,
1441
1481
  onFocus,
1442
1482
  onBlur,
1483
+ inputRef,
1443
1484
  tooltip
1444
1485
  } = props;
1445
1486
  const [localValue, setLocalValue] = hooks.useState(value);
1446
- const handleChangeCallback = ({
1447
- target
1448
- }) => {
1449
- onChange(target.checked);
1487
+ const handleInputCallback = async () => {
1488
+ onInput(!value);
1450
1489
  };
1451
- const handleChange = e => {
1452
- handleChangeCallback(e);
1490
+ const handleInput = e => {
1491
+ handleInputCallback();
1453
1492
  setLocalValue(e.target.value);
1454
1493
  };
1455
1494
  hooks.useEffect(() => {
@@ -1458,29 +1497,40 @@ function Checkbox(props) {
1458
1497
  }
1459
1498
  setLocalValue(value);
1460
1499
  }, [value]);
1461
- const ref = useShowEntryEvent(id);
1462
1500
  return jsxRuntime.jsxs("div", {
1463
- class: "bio-properties-panel-checkbox",
1464
- children: [jsxRuntime.jsx("input", {
1465
- ref: ref,
1466
- id: prefixId$7(id),
1467
- name: id,
1468
- onFocus: onFocus,
1469
- onBlur: onBlur,
1470
- type: "checkbox",
1471
- class: "bio-properties-panel-input",
1472
- onChange: handleChange,
1473
- checked: localValue,
1474
- disabled: disabled
1475
- }), jsxRuntime.jsx("label", {
1476
- for: prefixId$7(id),
1501
+ class: classnames__default["default"]('bio-properties-panel-toggle-switch', {
1502
+ inline
1503
+ }),
1504
+ children: [jsxRuntime.jsx("label", {
1477
1505
  class: "bio-properties-panel-label",
1506
+ for: prefixId$7(id),
1478
1507
  children: jsxRuntime.jsx(TooltipWrapper, {
1479
1508
  value: tooltip,
1480
1509
  forId: id,
1481
1510
  element: props.element,
1482
1511
  children: label
1483
1512
  })
1513
+ }), jsxRuntime.jsxs("div", {
1514
+ class: "bio-properties-panel-field-wrapper",
1515
+ children: [jsxRuntime.jsxs("label", {
1516
+ class: "bio-properties-panel-toggle-switch__switcher",
1517
+ children: [jsxRuntime.jsx("input", {
1518
+ ref: inputRef,
1519
+ id: prefixId$7(id),
1520
+ class: "bio-properties-panel-input",
1521
+ type: "checkbox",
1522
+ onFocus: onFocus,
1523
+ onBlur: onBlur,
1524
+ name: id,
1525
+ onInput: handleInput,
1526
+ checked: !!localValue
1527
+ }), jsxRuntime.jsx("span", {
1528
+ class: "bio-properties-panel-toggle-switch__slider"
1529
+ })]
1530
+ }), switcherLabel && jsxRuntime.jsx("p", {
1531
+ class: "bio-properties-panel-toggle-switch__label",
1532
+ children: switcherLabel
1533
+ })]
1484
1534
  })]
1485
1535
  });
1486
1536
  }
@@ -1491,44 +1541,43 @@ function Checkbox(props) {
1491
1541
  * @param {String} props.id
1492
1542
  * @param {String} props.description
1493
1543
  * @param {String} props.label
1544
+ * @param {String} props.switcherLabel
1545
+ * @param {Boolean} props.inline
1494
1546
  * @param {Function} props.getValue
1495
1547
  * @param {Function} props.setValue
1496
1548
  * @param {Function} props.onFocus
1497
1549
  * @param {Function} props.onBlur
1498
1550
  * @param {string|import('preact').Component} props.tooltip
1499
- * @param {boolean} [props.disabled]
1500
1551
  */
1501
- function CheckboxEntry(props) {
1552
+ function ToggleSwitchEntry(props) {
1502
1553
  const {
1503
1554
  element,
1504
1555
  id,
1505
1556
  description,
1506
1557
  label,
1558
+ switcherLabel,
1559
+ inline,
1507
1560
  getValue,
1508
1561
  setValue,
1509
- disabled,
1510
1562
  onFocus,
1511
1563
  onBlur,
1512
1564
  tooltip
1513
1565
  } = props;
1514
1566
  const value = getValue(element);
1515
- const error = useError(id);
1516
1567
  return jsxRuntime.jsxs("div", {
1517
- class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
1568
+ class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
1518
1569
  "data-entry-id": id,
1519
- children: [jsxRuntime.jsx(Checkbox, {
1520
- disabled: disabled,
1570
+ children: [jsxRuntime.jsx(ToggleSwitch, {
1521
1571
  id: id,
1522
1572
  label: label,
1523
- onChange: setValue,
1573
+ value: value,
1574
+ onInput: setValue,
1524
1575
  onFocus: onFocus,
1525
1576
  onBlur: onBlur,
1526
- value: value,
1577
+ switcherLabel: switcherLabel,
1578
+ inline: inline,
1527
1579
  tooltip: tooltip,
1528
1580
  element: element
1529
- }, element), error && jsxRuntime.jsx("div", {
1530
- class: "bio-properties-panel-error",
1531
- children: error
1532
1581
  }), jsxRuntime.jsx(Description, {
1533
1582
  forId: id,
1534
1583
  element: element,
@@ -1546,450 +1595,94 @@ function prefixId$7(id) {
1546
1595
  return `bio-properties-panel-${id}`;
1547
1596
  }
1548
1597
 
1549
- const useBufferedFocus$1 = function (editor, ref) {
1550
- const [buffer, setBuffer] = hooks.useState(undefined);
1551
- ref.current = hooks.useMemo(() => ({
1552
- focus: offset => {
1553
- if (editor) {
1554
- editor.focus(offset);
1555
- } else {
1556
- if (typeof offset === 'undefined') {
1557
- offset = Infinity;
1558
- }
1559
- setBuffer(offset);
1560
- }
1561
- }
1562
- }), [editor]);
1563
- hooks.useEffect(() => {
1564
- if (typeof buffer !== 'undefined' && editor) {
1565
- editor.focus(buffer);
1566
- setBuffer(false);
1567
- }
1568
- }, [editor, buffer]);
1569
- };
1570
- const CodeEditor$1 = compat.forwardRef((props, ref) => {
1598
+ function NumberField(props) {
1571
1599
  const {
1572
- onInput,
1600
+ debounce,
1573
1601
  disabled,
1574
- tooltipContainer,
1575
- enableGutters,
1576
- value,
1577
- onLint = () => {},
1578
- contentAttributes = {},
1579
- hostLanguage = null,
1580
- singleLine = false
1581
- } = props;
1582
- const inputRef = hooks.useRef();
1583
- const [editor, setEditor] = hooks.useState();
1584
- const [localValue, setLocalValue] = hooks.useState(value || '');
1585
- useBufferedFocus$1(editor, ref);
1586
- const handleInput = useStaticCallback(newValue => {
1587
- onInput(newValue);
1588
- setLocalValue(newValue);
1589
- });
1590
- hooks.useEffect(() => {
1591
- let editor;
1592
- editor = new feelers.FeelersEditor({
1593
- container: inputRef.current,
1594
- onChange: handleInput,
1595
- value: localValue,
1596
- onLint,
1597
- contentAttributes,
1598
- tooltipContainer,
1599
- enableGutters,
1600
- hostLanguage,
1601
- singleLine
1602
- });
1603
- setEditor(editor);
1604
- return () => {
1605
- onLint([]);
1606
- inputRef.current.innerHTML = '';
1607
- setEditor(null);
1608
- };
1609
- }, []);
1610
- hooks.useEffect(() => {
1611
- if (!editor) {
1612
- return;
1613
- }
1614
- if (value === localValue) {
1615
- return;
1616
- }
1617
- editor.setValue(value);
1618
- setLocalValue(value);
1619
- }, [value]);
1620
- const handleClick = () => {
1621
- ref.current.focus();
1622
- };
1623
- return jsxRuntime.jsx("div", {
1624
- name: props.name,
1625
- class: classnames__default["default"]('bio-properties-panel-feelers-editor bio-properties-panel-input', localValue ? 'edited' : null, disabled ? 'disabled' : null),
1626
- ref: inputRef,
1627
- onClick: handleClick
1628
- });
1629
- });
1630
-
1631
- const useBufferedFocus = function (editor, ref) {
1632
- const [buffer, setBuffer] = hooks.useState(undefined);
1633
- ref.current = hooks.useMemo(() => ({
1634
- focus: offset => {
1635
- if (editor) {
1636
- editor.focus(offset);
1637
- } else {
1638
- if (typeof offset === 'undefined') {
1639
- offset = Infinity;
1640
- }
1641
- setBuffer(offset);
1642
- }
1643
- }
1644
- }), [editor]);
1645
- hooks.useEffect(() => {
1646
- if (typeof buffer !== 'undefined' && editor) {
1647
- editor.focus(buffer);
1648
- setBuffer(false);
1649
- }
1650
- }, [editor, buffer]);
1651
- };
1652
- const CodeEditor = compat.forwardRef((props, ref) => {
1653
- const {
1654
- value,
1602
+ displayLabel = true,
1603
+ id,
1604
+ inputRef,
1605
+ label,
1606
+ max,
1607
+ min,
1655
1608
  onInput,
1656
- onFeelToggle,
1657
- onLint = () => {},
1658
- disabled,
1659
- tooltipContainer,
1660
- variables
1609
+ step,
1610
+ value = '',
1611
+ onFocus,
1612
+ onBlur
1661
1613
  } = props;
1662
- const inputRef = hooks.useRef();
1663
- const [editor, setEditor] = hooks.useState();
1664
- const [localValue, setLocalValue] = hooks.useState(value || '');
1665
- useBufferedFocus(editor, ref);
1666
- const handleInput = useStaticCallback(newValue => {
1667
- onInput(newValue);
1668
- setLocalValue(newValue);
1669
- });
1670
- hooks.useEffect(() => {
1671
- let editor;
1672
-
1673
- /* Trigger FEEL toggle when
1674
- *
1675
- * - `backspace` is pressed
1676
- * - AND the cursor is at the beginning of the input
1677
- */
1678
- const onKeyDown = e => {
1679
- if (e.key !== 'Backspace' || !editor) {
1680
- return;
1681
- }
1682
- const selection = editor.getSelection();
1683
- const range = selection.ranges[selection.mainIndex];
1684
- if (range.from === 0 && range.to === 0) {
1685
- onFeelToggle();
1614
+ const [localValue, setLocalValue] = hooks.useState(value);
1615
+ const handleInputCallback = hooks.useMemo(() => {
1616
+ return debounce(event => {
1617
+ const {
1618
+ validity,
1619
+ value
1620
+ } = event.target;
1621
+ if (validity.valid) {
1622
+ onInput(value ? parseFloat(value) : undefined);
1686
1623
  }
1687
- };
1688
- editor = new FeelEditor__default["default"]({
1689
- container: inputRef.current,
1690
- onChange: handleInput,
1691
- onKeyDown: onKeyDown,
1692
- onLint: onLint,
1693
- tooltipContainer: tooltipContainer,
1694
- value: localValue,
1695
- variables: variables
1696
1624
  });
1697
- setEditor(editor);
1698
- return () => {
1699
- onLint([]);
1700
- inputRef.current.innerHTML = '';
1701
- setEditor(null);
1702
- };
1703
- }, []);
1625
+ }, [onInput, debounce]);
1626
+ const handleInput = e => {
1627
+ handleInputCallback(e);
1628
+ setLocalValue(e.target.value);
1629
+ };
1704
1630
  hooks.useEffect(() => {
1705
- if (!editor) {
1706
- return;
1707
- }
1708
1631
  if (value === localValue) {
1709
1632
  return;
1710
1633
  }
1711
- editor.setValue(value);
1712
1634
  setLocalValue(value);
1713
1635
  }, [value]);
1714
- hooks.useEffect(() => {
1715
- if (!editor) {
1716
- return;
1717
- }
1718
- editor.setVariables(variables);
1719
- }, [variables]);
1720
- const handleClick = () => {
1721
- ref.current.focus();
1722
- };
1723
- return jsxRuntime.jsx("div", {
1724
- class: classnames__default["default"]('bio-properties-panel-feel-editor-container', disabled ? 'disabled' : null),
1725
- children: jsxRuntime.jsx("div", {
1726
- name: props.name,
1727
- class: classnames__default["default"]('bio-properties-panel-input', localValue ? 'edited' : null),
1636
+ return jsxRuntime.jsxs("div", {
1637
+ class: "bio-properties-panel-numberfield",
1638
+ children: [displayLabel && jsxRuntime.jsx("label", {
1639
+ for: prefixId$6(id),
1640
+ class: "bio-properties-panel-label",
1641
+ children: label
1642
+ }), jsxRuntime.jsx("input", {
1643
+ id: prefixId$6(id),
1728
1644
  ref: inputRef,
1729
- onClick: handleClick
1730
- })
1731
- });
1732
- });
1733
-
1734
- function FeelIndicator(props) {
1735
- const {
1736
- active
1737
- } = props;
1738
- if (!active) {
1739
- return null;
1740
- }
1741
- return jsxRuntime.jsx("span", {
1742
- class: "bio-properties-panel-feel-indicator",
1743
- children: "="
1645
+ type: "number",
1646
+ name: id,
1647
+ spellCheck: "false",
1648
+ autoComplete: "off",
1649
+ disabled: disabled,
1650
+ class: "bio-properties-panel-input",
1651
+ max: max,
1652
+ min: min,
1653
+ onInput: handleInput,
1654
+ onFocus: onFocus,
1655
+ onBlur: onBlur,
1656
+ step: step,
1657
+ value: localValue
1658
+ })]
1744
1659
  });
1745
1660
  }
1746
1661
 
1747
- const noop$2 = () => {};
1748
-
1749
1662
  /**
1750
1663
  * @param {Object} props
1751
- * @param {Object} props.label
1752
- * @param {String} props.feel
1664
+ * @param {Boolean} props.debounce
1665
+ * @param {String} props.description
1666
+ * @param {Boolean} props.disabled
1667
+ * @param {Object} props.element
1668
+ * @param {Function} props.getValue
1669
+ * @param {String} props.id
1670
+ * @param {String} props.label
1671
+ * @param {String} props.max
1672
+ * @param {String} props.min
1673
+ * @param {Function} props.setValue
1674
+ * @param {Function} props.onFocus
1675
+ * @param {Function} props.onBlur
1676
+ * @param {String} props.step
1677
+ * @param {Function} props.validate
1753
1678
  */
1754
- function FeelIcon(props) {
1755
- const {
1756
- feel = false,
1757
- active,
1758
- disabled = false,
1759
- onClick = noop$2
1760
- } = props;
1761
- const feelRequiredLabel = 'FEEL expression is mandatory';
1762
- const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
1763
- const handleClick = e => {
1764
- onClick(e);
1765
-
1766
- // when pointer event was created from keyboard, keep focus on button
1767
- if (!e.pointerType) {
1768
- e.stopPropagation();
1769
- }
1770
- };
1771
- return jsxRuntime.jsx("button", {
1772
- class: classnames__default["default"]('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
1773
- onClick: handleClick,
1774
- disabled: feel === 'required' || disabled,
1775
- title: feel === 'required' ? feelRequiredLabel : feelOptionalLabel,
1776
- children: jsxRuntime.jsx(FeelIcon$1, {})
1777
- });
1778
- }
1779
-
1780
- function ToggleSwitch(props) {
1679
+ function NumberFieldEntry(props) {
1781
1680
  const {
1782
- id,
1783
- label,
1784
- onInput,
1785
- value,
1786
- switcherLabel,
1787
- inline,
1788
- onFocus,
1789
- onBlur,
1790
- inputRef,
1791
- tooltip
1792
- } = props;
1793
- const [localValue, setLocalValue] = hooks.useState(value);
1794
- const handleInputCallback = async () => {
1795
- onInput(!value);
1796
- };
1797
- const handleInput = e => {
1798
- handleInputCallback();
1799
- setLocalValue(e.target.value);
1800
- };
1801
- hooks.useEffect(() => {
1802
- if (value === localValue) {
1803
- return;
1804
- }
1805
- setLocalValue(value);
1806
- }, [value]);
1807
- return jsxRuntime.jsxs("div", {
1808
- class: classnames__default["default"]('bio-properties-panel-toggle-switch', {
1809
- inline
1810
- }),
1811
- children: [jsxRuntime.jsx("label", {
1812
- class: "bio-properties-panel-label",
1813
- for: prefixId$6(id),
1814
- children: jsxRuntime.jsx(TooltipWrapper, {
1815
- value: tooltip,
1816
- forId: id,
1817
- element: props.element,
1818
- children: label
1819
- })
1820
- }), jsxRuntime.jsxs("div", {
1821
- class: "bio-properties-panel-field-wrapper",
1822
- children: [jsxRuntime.jsxs("label", {
1823
- class: "bio-properties-panel-toggle-switch__switcher",
1824
- children: [jsxRuntime.jsx("input", {
1825
- ref: inputRef,
1826
- id: prefixId$6(id),
1827
- class: "bio-properties-panel-input",
1828
- type: "checkbox",
1829
- onFocus: onFocus,
1830
- onBlur: onBlur,
1831
- name: id,
1832
- onInput: handleInput,
1833
- checked: !!localValue
1834
- }), jsxRuntime.jsx("span", {
1835
- class: "bio-properties-panel-toggle-switch__slider"
1836
- })]
1837
- }), switcherLabel && jsxRuntime.jsx("p", {
1838
- class: "bio-properties-panel-toggle-switch__label",
1839
- children: switcherLabel
1840
- })]
1841
- })]
1842
- });
1843
- }
1844
-
1845
- /**
1846
- * @param {Object} props
1847
- * @param {Object} props.element
1848
- * @param {String} props.id
1849
- * @param {String} props.description
1850
- * @param {String} props.label
1851
- * @param {String} props.switcherLabel
1852
- * @param {Boolean} props.inline
1853
- * @param {Function} props.getValue
1854
- * @param {Function} props.setValue
1855
- * @param {Function} props.onFocus
1856
- * @param {Function} props.onBlur
1857
- * @param {string|import('preact').Component} props.tooltip
1858
- */
1859
- function ToggleSwitchEntry(props) {
1860
- const {
1861
- element,
1862
- id,
1863
- description,
1864
- label,
1865
- switcherLabel,
1866
- inline,
1867
- getValue,
1868
- setValue,
1869
- onFocus,
1870
- onBlur,
1871
- tooltip
1872
- } = props;
1873
- const value = getValue(element);
1874
- return jsxRuntime.jsxs("div", {
1875
- class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
1876
- "data-entry-id": id,
1877
- children: [jsxRuntime.jsx(ToggleSwitch, {
1878
- id: id,
1879
- label: label,
1880
- value: value,
1881
- onInput: setValue,
1882
- onFocus: onFocus,
1883
- onBlur: onBlur,
1884
- switcherLabel: switcherLabel,
1885
- inline: inline,
1886
- tooltip: tooltip,
1887
- element: element
1888
- }), jsxRuntime.jsx(Description, {
1889
- forId: id,
1890
- element: element,
1891
- value: description
1892
- })]
1893
- });
1894
- }
1895
- function isEdited$7(node) {
1896
- return node && !!node.checked;
1897
- }
1898
-
1899
- // helpers /////////////////
1900
-
1901
- function prefixId$6(id) {
1902
- return `bio-properties-panel-${id}`;
1903
- }
1904
-
1905
- function NumberField(props) {
1906
- const {
1907
- debounce,
1908
- disabled,
1909
- displayLabel = true,
1910
- id,
1911
- inputRef,
1912
- label,
1913
- max,
1914
- min,
1915
- onInput,
1916
- step,
1917
- value = '',
1918
- onFocus,
1919
- onBlur
1920
- } = props;
1921
- const [localValue, setLocalValue] = hooks.useState(value);
1922
- const handleInputCallback = hooks.useMemo(() => {
1923
- return debounce(event => {
1924
- const {
1925
- validity,
1926
- value
1927
- } = event.target;
1928
- if (validity.valid) {
1929
- onInput(value ? parseFloat(value) : undefined);
1930
- }
1931
- });
1932
- }, [onInput, debounce]);
1933
- const handleInput = e => {
1934
- handleInputCallback(e);
1935
- setLocalValue(e.target.value);
1936
- };
1937
- hooks.useEffect(() => {
1938
- if (value === localValue) {
1939
- return;
1940
- }
1941
- setLocalValue(value);
1942
- }, [value]);
1943
- return jsxRuntime.jsxs("div", {
1944
- class: "bio-properties-panel-numberfield",
1945
- children: [displayLabel && jsxRuntime.jsx("label", {
1946
- for: prefixId$5(id),
1947
- class: "bio-properties-panel-label",
1948
- children: label
1949
- }), jsxRuntime.jsx("input", {
1950
- id: prefixId$5(id),
1951
- ref: inputRef,
1952
- type: "number",
1953
- name: id,
1954
- spellCheck: "false",
1955
- autoComplete: "off",
1956
- disabled: disabled,
1957
- class: "bio-properties-panel-input",
1958
- max: max,
1959
- min: min,
1960
- onInput: handleInput,
1961
- onFocus: onFocus,
1962
- onBlur: onBlur,
1963
- step: step,
1964
- value: localValue
1965
- })]
1966
- });
1967
- }
1968
-
1969
- /**
1970
- * @param {Object} props
1971
- * @param {Boolean} props.debounce
1972
- * @param {String} props.description
1973
- * @param {Boolean} props.disabled
1974
- * @param {Object} props.element
1975
- * @param {Function} props.getValue
1976
- * @param {String} props.id
1977
- * @param {String} props.label
1978
- * @param {String} props.max
1979
- * @param {String} props.min
1980
- * @param {Function} props.setValue
1981
- * @param {Function} props.onFocus
1982
- * @param {Function} props.onBlur
1983
- * @param {String} props.step
1984
- * @param {Function} props.validate
1985
- */
1986
- function NumberFieldEntry(props) {
1987
- const {
1988
- debounce,
1989
- description,
1990
- disabled,
1991
- element,
1992
- getValue,
1681
+ debounce,
1682
+ description,
1683
+ disabled,
1684
+ element,
1685
+ getValue,
1993
1686
  id,
1994
1687
  label,
1995
1688
  max,
@@ -2043,28 +1736,31 @@ function NumberFieldEntry(props) {
2043
1736
  })]
2044
1737
  });
2045
1738
  }
2046
- function isEdited$6(node) {
1739
+ function isEdited$7(node) {
2047
1740
  return node && !!node.value;
2048
1741
  }
2049
1742
 
2050
1743
  // helpers /////////////////
2051
1744
 
2052
- function prefixId$5(id) {
1745
+ function prefixId$6(id) {
2053
1746
  return `bio-properties-panel-${id}`;
2054
1747
  }
2055
1748
 
2056
- const noop$1 = () => {};
1749
+ const noop$2 = () => {};
2057
1750
  function FeelTextfield(props) {
2058
1751
  const {
2059
1752
  debounce,
2060
1753
  id,
1754
+ element,
2061
1755
  label,
1756
+ hostLanguage,
2062
1757
  onInput,
2063
1758
  onError,
2064
1759
  feel,
2065
1760
  value = '',
2066
1761
  disabled = false,
2067
1762
  variables,
1763
+ singleLine,
2068
1764
  tooltipContainer,
2069
1765
  OptionalComponent = OptionalFeelInput,
2070
1766
  tooltip
@@ -2075,6 +1771,11 @@ function FeelTextfield(props) {
2075
1771
  const feelActive = minDash.isString(localValue) && localValue.startsWith('=') || feel === 'required';
2076
1772
  const feelOnlyValue = minDash.isString(localValue) && localValue.startsWith('=') ? localValue.substring(1) : localValue;
2077
1773
  const [focus, _setFocus] = hooks.useState(undefined);
1774
+ const {
1775
+ open: openPopup,
1776
+ source: popupSource
1777
+ } = hooks.useContext(FeelPopupContext);
1778
+ const popuOpen = popupSource === id;
2078
1779
  const setFocus = (offset = 0) => {
2079
1780
  const hasFocus = containerRef.current.contains(document.activeElement);
2080
1781
 
@@ -2127,6 +1828,21 @@ function FeelTextfield(props) {
2127
1828
  const message = `${error.source}: ${error.message}`;
2128
1829
  onError(message);
2129
1830
  });
1831
+ const handlePopupOpen = (type = 'feel') => {
1832
+ const popupOptions = {
1833
+ id,
1834
+ hostLanguage,
1835
+ onInput: handleLocalInput,
1836
+ position: calculatePopupPosition(containerRef.current),
1837
+ singleLine,
1838
+ title: getPopupTitle(element, label),
1839
+ tooltipContainer,
1840
+ type,
1841
+ value: feelOnlyValue,
1842
+ variables
1843
+ };
1844
+ openPopup(id, popupOptions, editorRef.current);
1845
+ };
2130
1846
  hooks.useEffect(() => {
2131
1847
  if (typeof focus !== 'undefined') {
2132
1848
  editorRef.current.focus(focus);
@@ -2155,7 +1871,7 @@ function FeelTextfield(props) {
2155
1871
  event.clipboardData.setData('application/FEEL', event.clipboardData.getData('text'));
2156
1872
  };
2157
1873
  const pasteHandler = event => {
2158
- if (feelActive) {
1874
+ if (feelActive || popuOpen) {
2159
1875
  return;
2160
1876
  }
2161
1877
  const data = event.clipboardData.getData('application/FEEL');
@@ -2180,7 +1896,7 @@ function FeelTextfield(props) {
2180
1896
  'feel-active': feelActive
2181
1897
  }),
2182
1898
  children: [jsxRuntime.jsxs("label", {
2183
- for: prefixId$4(id),
1899
+ for: prefixId$5(id),
2184
1900
  class: "bio-properties-panel-label",
2185
1901
  onClick: () => setFocus(),
2186
1902
  children: [jsxRuntime.jsx(TooltipWrapper, {
@@ -2202,28 +1918,33 @@ function FeelTextfield(props) {
2202
1918
  disabled: feel !== 'optional' || disabled,
2203
1919
  onClick: handleFeelToggle
2204
1920
  }), feelActive ? jsxRuntime.jsx(CodeEditor, {
2205
- id: prefixId$4(id),
1921
+ id: prefixId$5(id),
2206
1922
  name: id,
2207
1923
  onInput: handleLocalInput,
2208
1924
  disabled: disabled,
1925
+ popupOpen: popuOpen,
2209
1926
  onFeelToggle: () => {
2210
1927
  handleFeelToggle();
2211
1928
  setFocus(true);
2212
1929
  },
2213
1930
  onLint: handleLint,
1931
+ onPopupOpen: handlePopupOpen,
2214
1932
  value: feelOnlyValue,
2215
1933
  variables: variables,
2216
1934
  ref: editorRef,
2217
1935
  tooltipContainer: tooltipContainer
2218
1936
  }) : jsxRuntime.jsx(OptionalComponent, {
2219
1937
  ...props,
1938
+ popupOpen: popuOpen,
2220
1939
  onInput: handleLocalInput,
2221
1940
  contentAttributes: {
2222
- 'id': prefixId$4(id),
1941
+ 'id': prefixId$5(id),
2223
1942
  'aria-label': label
2224
1943
  },
2225
1944
  value: localValue,
2226
- ref: editorRef
1945
+ ref: editorRef,
1946
+ onPopupOpen: handlePopupOpen,
1947
+ containerRef: containerRef
2227
1948
  })]
2228
1949
  })]
2229
1950
  });
@@ -2257,7 +1978,7 @@ const OptionalFeelInput = compat.forwardRef((props, ref) => {
2257
1978
  }
2258
1979
  };
2259
1980
  return jsxRuntime.jsx("input", {
2260
- id: prefixId$4(id),
1981
+ id: prefixId$5(id),
2261
1982
  type: "text",
2262
1983
  ref: inputRef,
2263
1984
  name: id,
@@ -2342,7 +2063,7 @@ const OptionalFeelTextArea = compat.forwardRef((props, ref) => {
2342
2063
  }
2343
2064
  };
2344
2065
  return jsxRuntime.jsx("textarea", {
2345
- id: prefixId$4(id),
2066
+ id: prefixId$5(id),
2346
2067
  type: "text",
2347
2068
  ref: inputRef,
2348
2069
  name: id,
@@ -2418,7 +2139,7 @@ const OptionalFeelCheckbox = compat.forwardRef((props, ref) => {
2418
2139
  };
2419
2140
  return jsxRuntime.jsx("input", {
2420
2141
  ref: inputRef,
2421
- id: prefixId$4(id),
2142
+ id: prefixId$5(id),
2422
2143
  name: id,
2423
2144
  onFocus: onFocus,
2424
2145
  onBlur: onBlur,
@@ -2428,101 +2149,1056 @@ const OptionalFeelCheckbox = compat.forwardRef((props, ref) => {
2428
2149
  checked: value,
2429
2150
  disabled: disabled
2430
2151
  });
2431
- });
2152
+ });
2153
+
2154
+ /**
2155
+ * @param {Object} props
2156
+ * @param {Object} props.element
2157
+ * @param {String} props.id
2158
+ * @param {String} props.description
2159
+ * @param {Boolean} props.debounce
2160
+ * @param {Boolean} props.disabled
2161
+ * @param {Boolean} props.feel
2162
+ * @param {String} props.label
2163
+ * @param {Function} props.getValue
2164
+ * @param {Function} props.setValue
2165
+ * @param {Function} props.tooltipContainer
2166
+ * @param {Function} props.validate
2167
+ * @param {Function} props.show
2168
+ * @param {Function} props.example
2169
+ * @param {Function} props.variables
2170
+ * @param {Function} props.onFocus
2171
+ * @param {Function} props.onBlur
2172
+ * @param {string|import('preact').Component} props.tooltip
2173
+ */
2174
+ function FeelEntry(props) {
2175
+ const {
2176
+ element,
2177
+ id,
2178
+ description,
2179
+ debounce,
2180
+ disabled,
2181
+ feel,
2182
+ label,
2183
+ getValue,
2184
+ setValue,
2185
+ tooltipContainer,
2186
+ hostLanguage,
2187
+ singleLine,
2188
+ validate,
2189
+ show = noop$2,
2190
+ example,
2191
+ variables,
2192
+ onFocus,
2193
+ onBlur,
2194
+ tooltip
2195
+ } = props;
2196
+ const [validationError, setValidationError] = hooks.useState(null);
2197
+ const [localError, setLocalError] = hooks.useState(null);
2198
+ let value = getValue(element);
2199
+ hooks.useEffect(() => {
2200
+ if (minDash.isFunction(validate)) {
2201
+ const newValidationError = validate(value) || null;
2202
+ setValidationError(newValidationError);
2203
+ }
2204
+ }, [value]);
2205
+ const onInput = useStaticCallback(newValue => {
2206
+ let newValidationError = null;
2207
+ if (minDash.isFunction(validate)) {
2208
+ newValidationError = validate(newValue) || null;
2209
+ }
2210
+
2211
+ // don't create multiple commandStack entries for the same value
2212
+ if (newValue !== value) {
2213
+ setValue(newValue, newValidationError);
2214
+ }
2215
+ setValidationError(newValidationError);
2216
+ });
2217
+ const onError = hooks.useCallback(err => {
2218
+ setLocalError(err);
2219
+ }, []);
2220
+ const temporaryError = useError(id);
2221
+ const error = localError || temporaryError || validationError;
2222
+ return jsxRuntime.jsxs("div", {
2223
+ class: classnames__default["default"](props.class, 'bio-properties-panel-entry', error ? 'has-error' : ''),
2224
+ "data-entry-id": id,
2225
+ children: [preact.createElement(FeelTextfield, {
2226
+ ...props,
2227
+ debounce: debounce,
2228
+ disabled: disabled,
2229
+ feel: feel,
2230
+ id: id,
2231
+ key: element,
2232
+ label: label,
2233
+ onInput: onInput,
2234
+ onError: onError,
2235
+ onFocus: onFocus,
2236
+ onBlur: onBlur,
2237
+ example: example,
2238
+ hostLanguage: hostLanguage,
2239
+ singleLine: singleLine,
2240
+ show: show,
2241
+ value: value,
2242
+ variables: variables,
2243
+ tooltipContainer: tooltipContainer,
2244
+ OptionalComponent: props.OptionalComponent,
2245
+ tooltip: tooltip
2246
+ }), error && jsxRuntime.jsx("div", {
2247
+ class: "bio-properties-panel-error",
2248
+ children: error
2249
+ }), jsxRuntime.jsx(Description, {
2250
+ forId: id,
2251
+ element: element,
2252
+ value: description
2253
+ })]
2254
+ });
2255
+ }
2256
+
2257
+ /**
2258
+ * @param {Object} props
2259
+ * @param {Object} props.element
2260
+ * @param {String} props.id
2261
+ * @param {String} props.description
2262
+ * @param {Boolean} props.debounce
2263
+ * @param {Boolean} props.disabled
2264
+ * @param {String} props.max
2265
+ * @param {String} props.min
2266
+ * @param {String} props.step
2267
+ * @param {Boolean} props.feel
2268
+ * @param {String} props.label
2269
+ * @param {Function} props.getValue
2270
+ * @param {Function} props.setValue
2271
+ * @param {Function} props.tooltipContainer
2272
+ * @param {Function} props.validate
2273
+ * @param {Function} props.show
2274
+ * @param {Function} props.example
2275
+ * @param {Function} props.variables
2276
+ * @param {Function} props.onFocus
2277
+ * @param {Function} props.onBlur
2278
+ */
2279
+ function FeelNumberEntry(props) {
2280
+ return jsxRuntime.jsx(FeelEntry, {
2281
+ class: "bio-properties-panel-feel-number",
2282
+ OptionalComponent: OptionalFeelNumberField,
2283
+ ...props
2284
+ });
2285
+ }
2286
+
2287
+ /**
2288
+ * @param {Object} props
2289
+ * @param {Object} props.element
2290
+ * @param {String} props.id
2291
+ * @param {String} props.description
2292
+ * @param {Boolean} props.debounce
2293
+ * @param {Boolean} props.disabled
2294
+ * @param {Boolean} props.feel
2295
+ * @param {String} props.label
2296
+ * @param {Function} props.getValue
2297
+ * @param {Function} props.setValue
2298
+ * @param {Function} props.tooltipContainer
2299
+ * @param {Function} props.validate
2300
+ * @param {Function} props.show
2301
+ * @param {Function} props.example
2302
+ * @param {Function} props.variables
2303
+ * @param {Function} props.onFocus
2304
+ * @param {Function} props.onBlur
2305
+ */
2306
+ function FeelTextAreaEntry(props) {
2307
+ return jsxRuntime.jsx(FeelEntry, {
2308
+ class: "bio-properties-panel-feel-textarea",
2309
+ OptionalComponent: OptionalFeelTextArea,
2310
+ ...props
2311
+ });
2312
+ }
2313
+
2314
+ /**
2315
+ * @param {Object} props
2316
+ * @param {Object} props.element
2317
+ * @param {String} props.id
2318
+ * @param {String} props.description
2319
+ * @param {Boolean} props.debounce
2320
+ * @param {Boolean} props.disabled
2321
+ * @param {Boolean} props.feel
2322
+ * @param {String} props.label
2323
+ * @param {Function} props.getValue
2324
+ * @param {Function} props.setValue
2325
+ * @param {Function} props.tooltipContainer
2326
+ * @param {Function} props.validate
2327
+ * @param {Function} props.show
2328
+ * @param {Function} props.example
2329
+ * @param {Function} props.variables
2330
+ * @param {Function} props.onFocus
2331
+ * @param {Function} props.onBlur
2332
+ */
2333
+ function FeelToggleSwitchEntry(props) {
2334
+ return jsxRuntime.jsx(FeelEntry, {
2335
+ class: "bio-properties-panel-feel-toggle-switch",
2336
+ OptionalComponent: OptionalFeelToggleSwitch,
2337
+ ...props
2338
+ });
2339
+ }
2340
+
2341
+ /**
2342
+ * @param {Object} props
2343
+ * @param {Object} props.element
2344
+ * @param {String} props.id
2345
+ * @param {String} props.description
2346
+ * @param {Boolean} props.debounce
2347
+ * @param {Boolean} props.disabled
2348
+ * @param {Boolean} props.feel
2349
+ * @param {String} props.label
2350
+ * @param {Function} props.getValue
2351
+ * @param {Function} props.setValue
2352
+ * @param {Function} props.tooltipContainer
2353
+ * @param {Function} props.validate
2354
+ * @param {Function} props.show
2355
+ * @param {Function} props.example
2356
+ * @param {Function} props.variables
2357
+ * @param {Function} props.onFocus
2358
+ * @param {Function} props.onBlur
2359
+ */
2360
+ function FeelCheckboxEntry(props) {
2361
+ return jsxRuntime.jsx(FeelEntry, {
2362
+ class: "bio-properties-panel-feel-checkbox",
2363
+ OptionalComponent: OptionalFeelCheckbox,
2364
+ ...props
2365
+ });
2366
+ }
2367
+
2368
+ /**
2369
+ * @param {Object} props
2370
+ * @param {Object} props.element
2371
+ * @param {String} props.id
2372
+ * @param {String} props.description
2373
+ * @param {String} props.hostLanguage
2374
+ * @param {Boolean} props.singleLine
2375
+ * @param {Boolean} props.debounce
2376
+ * @param {Boolean} props.disabled
2377
+ * @param {Boolean} props.feel
2378
+ * @param {String} props.label
2379
+ * @param {Function} props.getValue
2380
+ * @param {Function} props.setValue
2381
+ * @param {Function} props.tooltipContainer
2382
+ * @param {Function} props.validate
2383
+ * @param {Function} props.show
2384
+ * @param {Function} props.example
2385
+ * @param {Function} props.variables
2386
+ * @param {Function} props.onFocus
2387
+ * @param {Function} props.onBlur
2388
+ */
2389
+ function FeelTemplatingEntry(props) {
2390
+ return jsxRuntime.jsx(FeelEntry, {
2391
+ class: "bio-properties-panel-feel-templating",
2392
+ OptionalComponent: CodeEditor$1,
2393
+ ...props
2394
+ });
2395
+ }
2396
+ function isEdited$6(node) {
2397
+ if (!node) {
2398
+ return false;
2399
+ }
2400
+ if (node.type === 'checkbox') {
2401
+ return !!node.checked || node.classList.contains('edited');
2402
+ }
2403
+ return !!node.value || node.classList.contains('edited');
2404
+ }
2405
+
2406
+ // helpers /////////////////
2407
+
2408
+ function prefixId$5(id) {
2409
+ return `bio-properties-panel-${id}`;
2410
+ }
2411
+ function calculatePopupPosition(element) {
2412
+ const {
2413
+ top,
2414
+ left
2415
+ } = element.getBoundingClientRect();
2416
+ return {
2417
+ left: left - FEEL_POPUP_WIDTH - 20,
2418
+ top: top
2419
+ };
2420
+ }
2421
+
2422
+ // todo(pinussilvestrus): make this configurable in the future
2423
+ function getPopupTitle(element, label) {
2424
+ let popupTitle;
2425
+ if (element && element.type) {
2426
+ popupTitle = `${element.type} / `;
2427
+ }
2428
+ return `${popupTitle}${label}`;
2429
+ }
2430
+
2431
+ const DEFAULT_LAYOUT = {};
2432
+ const DEFAULT_DESCRIPTION = {};
2433
+ const DEFAULT_TOOLTIP = {};
2434
+
2435
+ /**
2436
+ * @typedef { {
2437
+ * component: import('preact').Component,
2438
+ * id: String,
2439
+ * isEdited?: Function
2440
+ * } } EntryDefinition
2441
+ *
2442
+ * @typedef { {
2443
+ * autoFocusEntry: String,
2444
+ * autoOpen?: Boolean,
2445
+ * entries: Array<EntryDefinition>,
2446
+ * id: String,
2447
+ * label: String,
2448
+ * remove: (event: MouseEvent) => void
2449
+ * } } ListItemDefinition
2450
+ *
2451
+ * @typedef { {
2452
+ * add: (event: MouseEvent) => void,
2453
+ * component: import('preact').Component,
2454
+ * element: Object,
2455
+ * id: String,
2456
+ * items: Array<ListItemDefinition>,
2457
+ * label: String,
2458
+ * shouldSort?: Boolean,
2459
+ * shouldOpen?: Boolean
2460
+ * } } ListGroupDefinition
2461
+ *
2462
+ * @typedef { {
2463
+ * component?: import('preact').Component,
2464
+ * entries: Array<EntryDefinition>,
2465
+ * id: String,
2466
+ * label: String,
2467
+ * shouldOpen?: Boolean
2468
+ * } } GroupDefinition
2469
+ *
2470
+ * @typedef { {
2471
+ * [id: String]: GetDescriptionFunction
2472
+ * } } DescriptionConfig
2473
+ *
2474
+ * @typedef { {
2475
+ * [id: String]: GetTooltipFunction
2476
+ * } } TooltipConfig
2477
+ *
2478
+ * @callback { {
2479
+ * @param {string} id
2480
+ * @param {Object} element
2481
+ * @returns {string}
2482
+ * } } GetDescriptionFunction
2483
+ *
2484
+ * @callback { {
2485
+ * @param {string} id
2486
+ * @param {Object} element
2487
+ * @returns {string}
2488
+ * } } GetTooltipFunction
2489
+ *
2490
+ * @typedef { {
2491
+ * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
2492
+ * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
2493
+ * } } PlaceholderProvider
2494
+ *
2495
+ */
2496
+
2497
+ /**
2498
+ * A basic properties panel component. Describes *how* content will be rendered, accepts
2499
+ * data from implementor to describe *what* will be rendered.
2500
+ *
2501
+ * @param {Object} props
2502
+ * @param {Object|Array} props.element
2503
+ * @param {import('./components/Header').HeaderProvider} props.headerProvider
2504
+ * @param {PlaceholderProvider} [props.placeholderProvider]
2505
+ * @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
2506
+ * @param {Object} [props.layoutConfig]
2507
+ * @param {Function} [props.layoutChanged]
2508
+ * @param {DescriptionConfig} [props.descriptionConfig]
2509
+ * @param {Function} [props.descriptionLoaded]
2510
+ * @param {TooltipConfig} [props.tooltipConfig]
2511
+ * @param {Function} [props.tooltipLoaded]
2512
+ * @param {Object} [props.eventBus]
2513
+ */
2514
+ function PropertiesPanel(props) {
2515
+ const {
2516
+ element,
2517
+ headerProvider,
2518
+ placeholderProvider,
2519
+ groups,
2520
+ layoutConfig,
2521
+ layoutChanged,
2522
+ descriptionConfig,
2523
+ descriptionLoaded,
2524
+ tooltipConfig,
2525
+ tooltipLoaded,
2526
+ eventBus
2527
+ } = props;
2528
+
2529
+ // set-up layout context
2530
+ const [layout, setLayout] = hooks.useState(createLayout(layoutConfig));
2531
+
2532
+ // react to external changes in the layout config
2533
+ useUpdateLayoutEffect(() => {
2534
+ const newLayout = createLayout(layoutConfig);
2535
+ setLayout(newLayout);
2536
+ }, [layoutConfig]);
2537
+ hooks.useEffect(() => {
2538
+ if (typeof layoutChanged === 'function') {
2539
+ layoutChanged(layout);
2540
+ }
2541
+ }, [layout, layoutChanged]);
2542
+ const getLayoutForKey = (key, defaultValue) => {
2543
+ return minDash.get(layout, key, defaultValue);
2544
+ };
2545
+ const setLayoutForKey = (key, config) => {
2546
+ const newLayout = minDash.assign({}, layout);
2547
+ minDash.set(newLayout, key, config);
2548
+ setLayout(newLayout);
2549
+ };
2550
+ const layoutContext = {
2551
+ layout,
2552
+ setLayout,
2553
+ getLayoutForKey,
2554
+ setLayoutForKey
2555
+ };
2556
+
2557
+ // set-up description context
2558
+ const description = hooks.useMemo(() => createDescriptionContext(descriptionConfig), [descriptionConfig]);
2559
+ hooks.useEffect(() => {
2560
+ if (typeof descriptionLoaded === 'function') {
2561
+ descriptionLoaded(description);
2562
+ }
2563
+ }, [description, descriptionLoaded]);
2564
+ const getDescriptionForId = (id, element) => {
2565
+ return description[id] && description[id](element);
2566
+ };
2567
+ const descriptionContext = {
2568
+ description,
2569
+ getDescriptionForId
2570
+ };
2571
+
2572
+ // set-up tooltip context
2573
+ const tooltip = hooks.useMemo(() => createTooltipContext(tooltipConfig), [tooltipConfig]);
2574
+ hooks.useEffect(() => {
2575
+ if (typeof tooltipLoaded === 'function') {
2576
+ tooltipLoaded(tooltip);
2577
+ }
2578
+ }, [tooltip, tooltipLoaded]);
2579
+ const getTooltipForId = (id, element) => {
2580
+ return tooltip[id] && tooltip[id](element);
2581
+ };
2582
+ const tooltipContext = {
2583
+ tooltip,
2584
+ getTooltipForId
2585
+ };
2586
+ const [errors, setErrors] = hooks.useState({});
2587
+ const onSetErrors = ({
2588
+ errors
2589
+ }) => setErrors(errors);
2590
+ useEvent('propertiesPanel.setErrors', onSetErrors, eventBus);
2591
+ const errorsContext = {
2592
+ errors
2593
+ };
2594
+ const eventContext = {
2595
+ eventBus
2596
+ };
2597
+ const propertiesPanelContext = {
2598
+ element
2599
+ };
2600
+
2601
+ // empty state
2602
+ if (placeholderProvider && !element) {
2603
+ return jsxRuntime.jsx(Placeholder, {
2604
+ ...placeholderProvider.getEmpty()
2605
+ });
2606
+ }
2607
+
2608
+ // multiple state
2609
+ if (placeholderProvider && minDash.isArray(element)) {
2610
+ return jsxRuntime.jsx(Placeholder, {
2611
+ ...placeholderProvider.getMultiple()
2612
+ });
2613
+ }
2614
+ return jsxRuntime.jsx(LayoutContext.Provider, {
2615
+ value: propertiesPanelContext,
2616
+ children: jsxRuntime.jsx(ErrorsContext.Provider, {
2617
+ value: errorsContext,
2618
+ children: jsxRuntime.jsx(DescriptionContext.Provider, {
2619
+ value: descriptionContext,
2620
+ children: jsxRuntime.jsx(TooltipContext.Provider, {
2621
+ value: tooltipContext,
2622
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
2623
+ value: layoutContext,
2624
+ children: jsxRuntime.jsx(EventContext.Provider, {
2625
+ value: eventContext,
2626
+ children: jsxRuntime.jsx(FEELPopupRoot, {
2627
+ element: element,
2628
+ children: jsxRuntime.jsxs("div", {
2629
+ class: "bio-properties-panel",
2630
+ children: [jsxRuntime.jsx(Header, {
2631
+ element: element,
2632
+ headerProvider: headerProvider
2633
+ }), jsxRuntime.jsx("div", {
2634
+ class: "bio-properties-panel-scroll-container",
2635
+ children: groups.map(group => {
2636
+ const {
2637
+ component: Component = Group,
2638
+ id
2639
+ } = group;
2640
+ return preact.createElement(Component, {
2641
+ ...group,
2642
+ key: id,
2643
+ element: element
2644
+ });
2645
+ })
2646
+ })]
2647
+ })
2648
+ })
2649
+ })
2650
+ })
2651
+ })
2652
+ })
2653
+ })
2654
+ });
2655
+ }
2656
+
2657
+ // helpers //////////////////
2658
+
2659
+ function createLayout(overrides = {}, defaults = DEFAULT_LAYOUT) {
2660
+ return {
2661
+ ...defaults,
2662
+ ...overrides
2663
+ };
2664
+ }
2665
+ function createDescriptionContext(overrides = {}) {
2666
+ return {
2667
+ ...DEFAULT_DESCRIPTION,
2668
+ ...overrides
2669
+ };
2670
+ }
2671
+ function createTooltipContext(overrides = {}) {
2672
+ return {
2673
+ ...DEFAULT_TOOLTIP,
2674
+ ...overrides
2675
+ };
2676
+ }
2677
+
2678
+ // hooks //////////////////
2679
+
2680
+ /**
2681
+ * This hook behaves like useLayoutEffect, but does not trigger on the first render.
2682
+ *
2683
+ * @param {Function} effect
2684
+ * @param {Array} deps
2685
+ */
2686
+ function useUpdateLayoutEffect(effect, deps) {
2687
+ const isMounted = hooks.useRef(false);
2688
+ hooks.useLayoutEffect(() => {
2689
+ if (isMounted.current) {
2690
+ return effect();
2691
+ } else {
2692
+ isMounted.current = true;
2693
+ }
2694
+ }, deps);
2695
+ }
2696
+
2697
+ function DropdownButton(props) {
2698
+ const {
2699
+ class: className,
2700
+ children,
2701
+ menuItems = []
2702
+ } = props;
2703
+ const dropdownRef = hooks.useRef(null);
2704
+ const menuRef = hooks.useRef(null);
2705
+ const [open, setOpen] = hooks.useState(false);
2706
+ const close = () => setOpen(false);
2707
+ function onDropdownToggle(event) {
2708
+ if (menuRef.current && menuRef.current.contains(event.target)) {
2709
+ return;
2710
+ }
2711
+ event.stopPropagation();
2712
+ setOpen(open => !open);
2713
+ }
2714
+ function onActionClick(event, action) {
2715
+ event.stopPropagation();
2716
+ close();
2717
+ action();
2718
+ }
2719
+ useGlobalClick([dropdownRef.current], () => close());
2720
+ return jsxRuntime.jsxs("div", {
2721
+ class: classnames__default["default"]('bio-properties-panel-dropdown-button', {
2722
+ open
2723
+ }, className),
2724
+ onClick: onDropdownToggle,
2725
+ ref: dropdownRef,
2726
+ children: [children, jsxRuntime.jsx("div", {
2727
+ class: "bio-properties-panel-dropdown-button__menu",
2728
+ ref: menuRef,
2729
+ children: menuItems.map((item, index) => jsxRuntime.jsx(MenuItem, {
2730
+ onClick: onActionClick,
2731
+ item: item
2732
+ }, index))
2733
+ })]
2734
+ });
2735
+ }
2736
+ function MenuItem({
2737
+ item,
2738
+ onClick
2739
+ }) {
2740
+ if (item.separator) {
2741
+ return jsxRuntime.jsx("div", {
2742
+ class: "bio-properties-panel-dropdown-button__menu-item bio-properties-panel-dropdown-button__menu-item--separator"
2743
+ });
2744
+ }
2745
+ if (item.action) {
2746
+ return jsxRuntime.jsx("button", {
2747
+ class: "bio-properties-panel-dropdown-button__menu-item bio-properties-panel-dropdown-button__menu-item--actionable",
2748
+ onClick: event => onClick(event, item.action),
2749
+ children: item.entry
2750
+ });
2751
+ }
2752
+ return jsxRuntime.jsx("div", {
2753
+ class: "bio-properties-panel-dropdown-button__menu-item",
2754
+ children: item.entry
2755
+ });
2756
+ }
2757
+
2758
+ /**
2759
+ *
2760
+ * @param {Array<null | Element>} ignoredElements
2761
+ * @param {Function} callback
2762
+ */
2763
+ function useGlobalClick(ignoredElements, callback) {
2764
+ hooks.useEffect(() => {
2765
+ /**
2766
+ * @param {MouseEvent} event
2767
+ */
2768
+ function listener(event) {
2769
+ if (ignoredElements.some(element => element && element.contains(event.target))) {
2770
+ return;
2771
+ }
2772
+ callback();
2773
+ }
2774
+ document.addEventListener('click', listener, {
2775
+ capture: true
2776
+ });
2777
+ return () => document.removeEventListener('click', listener, {
2778
+ capture: true
2779
+ });
2780
+ }, [...ignoredElements, callback]);
2781
+ }
2782
+
2783
+ function HeaderButton(props) {
2784
+ const {
2785
+ children = null,
2786
+ class: classname,
2787
+ onClick = () => {},
2788
+ ...otherProps
2789
+ } = props;
2790
+ return jsxRuntime.jsx("button", {
2791
+ ...otherProps,
2792
+ onClick: onClick,
2793
+ class: classnames__default["default"]('bio-properties-panel-group-header-button', classname),
2794
+ children: children
2795
+ });
2796
+ }
2797
+
2798
+ function CollapsibleEntry(props) {
2799
+ const {
2800
+ element,
2801
+ entries = [],
2802
+ id,
2803
+ label,
2804
+ open: shouldOpen,
2805
+ remove
2806
+ } = props;
2807
+ const [open, setOpen] = hooks.useState(shouldOpen);
2808
+ const toggleOpen = () => setOpen(!open);
2809
+ const {
2810
+ onShow
2811
+ } = hooks.useContext(LayoutContext);
2812
+ const propertiesPanelContext = {
2813
+ ...hooks.useContext(LayoutContext),
2814
+ onShow: hooks.useCallback(() => {
2815
+ setOpen(true);
2816
+ if (minDash.isFunction(onShow)) {
2817
+ onShow();
2818
+ }
2819
+ }, [onShow, setOpen])
2820
+ };
2821
+
2822
+ // todo(pinussilvestrus): translate once we have a translate mechanism for the core
2823
+ const placeholderLabel = '<empty>';
2824
+ return jsxRuntime.jsxs("div", {
2825
+ "data-entry-id": id,
2826
+ class: classnames__default["default"]('bio-properties-panel-collapsible-entry', open ? 'open' : ''),
2827
+ children: [jsxRuntime.jsxs("div", {
2828
+ class: "bio-properties-panel-collapsible-entry-header",
2829
+ onClick: toggleOpen,
2830
+ children: [jsxRuntime.jsx("div", {
2831
+ title: label || placeholderLabel,
2832
+ class: classnames__default["default"]('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
2833
+ children: label || placeholderLabel
2834
+ }), jsxRuntime.jsx("button", {
2835
+ title: "Toggle list item",
2836
+ class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
2837
+ children: jsxRuntime.jsx(ArrowIcon, {
2838
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
2839
+ })
2840
+ }), remove ? jsxRuntime.jsx("button", {
2841
+ title: "Delete item",
2842
+ class: "bio-properties-panel-remove-entry",
2843
+ onClick: remove,
2844
+ children: jsxRuntime.jsx(DeleteIcon, {})
2845
+ }) : null]
2846
+ }), jsxRuntime.jsx("div", {
2847
+ class: classnames__default["default"]('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
2848
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
2849
+ value: propertiesPanelContext,
2850
+ children: entries.map(entry => {
2851
+ const {
2852
+ component: Component,
2853
+ id
2854
+ } = entry;
2855
+ return preact.createElement(Component, {
2856
+ ...entry,
2857
+ element: element,
2858
+ key: id
2859
+ });
2860
+ })
2861
+ })
2862
+ })]
2863
+ });
2864
+ }
2865
+
2866
+ function ListItem(props) {
2867
+ const {
2868
+ autoFocusEntry,
2869
+ autoOpen
2870
+ } = props;
2871
+
2872
+ // focus specified entry on auto open
2873
+ hooks.useEffect(() => {
2874
+ if (autoOpen && autoFocusEntry) {
2875
+ const entry = minDom.query(`[data-entry-id="${autoFocusEntry}"]`);
2876
+ const focusableInput = minDom.query('.bio-properties-panel-input', entry);
2877
+ if (focusableInput) {
2878
+ if (minDash.isFunction(focusableInput.select)) {
2879
+ focusableInput.select();
2880
+ } else if (minDash.isFunction(focusableInput.focus)) {
2881
+ focusableInput.focus();
2882
+ }
2883
+ }
2884
+ }
2885
+ }, [autoOpen, autoFocusEntry]);
2886
+ return jsxRuntime.jsx("div", {
2887
+ class: "bio-properties-panel-list-item",
2888
+ children: jsxRuntime.jsx(CollapsibleEntry, {
2889
+ ...props,
2890
+ open: autoOpen
2891
+ })
2892
+ });
2893
+ }
2894
+
2895
+ const noop$1 = () => {};
2896
+
2897
+ /**
2898
+ * @param {import('../PropertiesPanel').ListGroupDefinition} props
2899
+ */
2900
+ function ListGroup(props) {
2901
+ const {
2902
+ add,
2903
+ element,
2904
+ id,
2905
+ items,
2906
+ label,
2907
+ shouldOpen = true,
2908
+ shouldSort = true
2909
+ } = props;
2910
+ const groupRef = hooks.useRef(null);
2911
+ const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
2912
+ const [sticky, setSticky] = hooks.useState(false);
2913
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
2914
+ const [ordering, setOrdering] = hooks.useState([]);
2915
+ const [newItemAdded, setNewItemAdded] = hooks.useState(false);
2916
+
2917
+ // Flag to mark that add button was clicked in the last render cycle
2918
+ const [addTriggered, setAddTriggered] = hooks.useState(false);
2919
+ const prevItems = usePrevious(items);
2920
+ const prevElement = usePrevious(element);
2921
+ const elementChanged = element !== prevElement;
2922
+ const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
2923
+
2924
+ // reset initial ordering when element changes (before first render)
2925
+ if (elementChanged) {
2926
+ setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
2927
+ }
2928
+
2929
+ // keep ordering in sync to items - and open changes
2930
+
2931
+ // (0) set initial ordering from given items
2932
+ hooks.useEffect(() => {
2933
+ if (!prevItems || !shouldSort) {
2934
+ setOrdering(createOrdering(items));
2935
+ }
2936
+ }, [items, element]);
2937
+
2938
+ // (1) items were added
2939
+ hooks.useEffect(() => {
2940
+ // reset addTriggered flag
2941
+ setAddTriggered(false);
2942
+ if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
2943
+ let add = [];
2944
+ items.forEach(item => {
2945
+ if (!ordering.includes(item.id)) {
2946
+ add.push(item.id);
2947
+ }
2948
+ });
2949
+ let newOrdering = ordering;
2950
+
2951
+ // open if not open, configured and triggered by add button
2952
+ //
2953
+ // TODO(marstamm): remove once we refactor layout handling for listGroups.
2954
+ // Ideally, opening should be handled as part of the `add` callback and
2955
+ // not be a concern for the ListGroup component.
2956
+ if (addTriggered && !open && shouldOpen) {
2957
+ toggleOpen();
2958
+ }
2959
+
2960
+ // filter when not open and configured
2961
+ if (!open && shouldSort) {
2962
+ newOrdering = createOrdering(sortItems(items));
2963
+ }
2964
+
2965
+ // add new items on top or bottom depending on sorting behavior
2966
+ newOrdering = newOrdering.filter(item => !add.includes(item));
2967
+ if (shouldSort) {
2968
+ newOrdering.unshift(...add);
2969
+ } else {
2970
+ newOrdering.push(...add);
2971
+ }
2972
+ setOrdering(newOrdering);
2973
+ setNewItemAdded(addTriggered);
2974
+ } else {
2975
+ setNewItemAdded(false);
2976
+ }
2977
+ }, [items, open, shouldHandleEffects, addTriggered]);
2978
+
2979
+ // (2) sort items on open if shouldSort is set
2980
+ hooks.useEffect(() => {
2981
+ if (shouldSort && open && !newItemAdded) {
2982
+ setOrdering(createOrdering(sortItems(items)));
2983
+ }
2984
+ }, [open, shouldSort]);
2985
+
2986
+ // (3) items were deleted
2987
+ hooks.useEffect(() => {
2988
+ if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
2989
+ let keep = [];
2990
+ ordering.forEach(o => {
2991
+ if (getItem(items, o)) {
2992
+ keep.push(o);
2993
+ }
2994
+ });
2995
+ setOrdering(keep);
2996
+ }
2997
+ }, [items, shouldHandleEffects]);
2998
+
2999
+ // set css class when group is sticky to top
3000
+ useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
3001
+ const toggleOpen = () => setOpen(!open);
3002
+ const hasItems = !!items.length;
3003
+ const propertiesPanelContext = {
3004
+ ...hooks.useContext(LayoutContext),
3005
+ onShow
3006
+ };
3007
+ const handleAddClick = e => {
3008
+ setAddTriggered(true);
3009
+ add(e);
3010
+ };
3011
+ const allErrors = useErrors();
3012
+ const hasError = items.some(item => {
3013
+ if (allErrors[item.id]) {
3014
+ return true;
3015
+ }
3016
+ if (!item.entries) {
3017
+ return;
3018
+ }
3019
+
3020
+ // also check if the error is nested, e.g. for name-value entries
3021
+ return item.entries.some(entry => allErrors[entry.id]);
3022
+ });
3023
+ return jsxRuntime.jsxs("div", {
3024
+ class: "bio-properties-panel-group",
3025
+ "data-group-id": 'group-' + id,
3026
+ ref: groupRef,
3027
+ children: [jsxRuntime.jsxs("div", {
3028
+ class: classnames__default["default"]('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
3029
+ onClick: hasItems ? toggleOpen : noop$1,
3030
+ children: [jsxRuntime.jsx("div", {
3031
+ title: label,
3032
+ class: "bio-properties-panel-group-header-title",
3033
+ children: jsxRuntime.jsx(TooltipWrapper, {
3034
+ value: props.tooltip,
3035
+ forId: 'group-' + id,
3036
+ element: element,
3037
+ parent: groupRef,
3038
+ children: label
3039
+ })
3040
+ }), jsxRuntime.jsxs("div", {
3041
+ class: "bio-properties-panel-group-header-buttons",
3042
+ children: [add ? jsxRuntime.jsxs("button", {
3043
+ title: "Create new list item",
3044
+ class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
3045
+ onClick: handleAddClick,
3046
+ children: [jsxRuntime.jsx(CreateIcon, {}), !hasItems ? jsxRuntime.jsx("span", {
3047
+ class: "bio-properties-panel-add-entry-label",
3048
+ children: "Create"
3049
+ }) : null]
3050
+ }) : null, hasItems ? jsxRuntime.jsx("div", {
3051
+ title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
3052
+ class: classnames__default["default"]('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
3053
+ children: items.length
3054
+ }) : null, hasItems ? jsxRuntime.jsx("button", {
3055
+ title: "Toggle section",
3056
+ class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
3057
+ children: jsxRuntime.jsx(ArrowIcon, {
3058
+ class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
3059
+ })
3060
+ }) : null]
3061
+ })]
3062
+ }), jsxRuntime.jsx("div", {
3063
+ class: classnames__default["default"]('bio-properties-panel-list', open && hasItems ? 'open' : ''),
3064
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
3065
+ value: propertiesPanelContext,
3066
+ children: ordering.map((o, index) => {
3067
+ const item = getItem(items, o);
3068
+ if (!item) {
3069
+ return;
3070
+ }
3071
+ const {
3072
+ id
3073
+ } = item;
3074
+
3075
+ // if item was added, open it
3076
+ // Existing items will not be affected as autoOpen is only applied on first render
3077
+ const autoOpen = newItemAdded;
3078
+ return preact.createElement(ListItem, {
3079
+ ...item,
3080
+ autoOpen: autoOpen,
3081
+ element: element,
3082
+ index: index,
3083
+ key: id
3084
+ });
3085
+ })
3086
+ })
3087
+ })]
3088
+ });
3089
+ }
3090
+
3091
+ // helpers ////////////////////
3092
+
3093
+ /**
3094
+ * Sorts given items alphanumeric by label
3095
+ */
3096
+ function sortItems(items) {
3097
+ return minDash.sortBy(items, i => i.label.toLowerCase());
3098
+ }
3099
+ function getItem(items, id) {
3100
+ return minDash.find(items, i => i.id === id);
3101
+ }
3102
+ function createOrdering(items) {
3103
+ return items.map(i => i.id);
3104
+ }
3105
+
3106
+ function Checkbox(props) {
3107
+ const {
3108
+ id,
3109
+ label,
3110
+ onChange,
3111
+ disabled,
3112
+ value = false,
3113
+ onFocus,
3114
+ onBlur,
3115
+ tooltip
3116
+ } = props;
3117
+ const [localValue, setLocalValue] = hooks.useState(value);
3118
+ const handleChangeCallback = ({
3119
+ target
3120
+ }) => {
3121
+ onChange(target.checked);
3122
+ };
3123
+ const handleChange = e => {
3124
+ handleChangeCallback(e);
3125
+ setLocalValue(e.target.value);
3126
+ };
3127
+ hooks.useEffect(() => {
3128
+ if (value === localValue) {
3129
+ return;
3130
+ }
3131
+ setLocalValue(value);
3132
+ }, [value]);
3133
+ const ref = useShowEntryEvent(id);
3134
+ return jsxRuntime.jsxs("div", {
3135
+ class: "bio-properties-panel-checkbox",
3136
+ children: [jsxRuntime.jsx("input", {
3137
+ ref: ref,
3138
+ id: prefixId$4(id),
3139
+ name: id,
3140
+ onFocus: onFocus,
3141
+ onBlur: onBlur,
3142
+ type: "checkbox",
3143
+ class: "bio-properties-panel-input",
3144
+ onChange: handleChange,
3145
+ checked: localValue,
3146
+ disabled: disabled
3147
+ }), jsxRuntime.jsx("label", {
3148
+ for: prefixId$4(id),
3149
+ class: "bio-properties-panel-label",
3150
+ children: jsxRuntime.jsx(TooltipWrapper, {
3151
+ value: tooltip,
3152
+ forId: id,
3153
+ element: props.element,
3154
+ children: label
3155
+ })
3156
+ })]
3157
+ });
3158
+ }
2432
3159
 
2433
3160
  /**
2434
3161
  * @param {Object} props
2435
3162
  * @param {Object} props.element
2436
3163
  * @param {String} props.id
2437
3164
  * @param {String} props.description
2438
- * @param {Boolean} props.debounce
2439
- * @param {Boolean} props.disabled
2440
- * @param {Boolean} props.feel
2441
3165
  * @param {String} props.label
2442
3166
  * @param {Function} props.getValue
2443
3167
  * @param {Function} props.setValue
2444
- * @param {Function} props.tooltipContainer
2445
- * @param {Function} props.validate
2446
- * @param {Function} props.show
2447
- * @param {Function} props.example
2448
- * @param {Function} props.variables
2449
3168
  * @param {Function} props.onFocus
2450
3169
  * @param {Function} props.onBlur
2451
3170
  * @param {string|import('preact').Component} props.tooltip
3171
+ * @param {boolean} [props.disabled]
2452
3172
  */
2453
- function FeelEntry(props) {
3173
+ function CheckboxEntry(props) {
2454
3174
  const {
2455
3175
  element,
2456
3176
  id,
2457
3177
  description,
2458
- debounce,
2459
- disabled,
2460
- feel,
2461
3178
  label,
2462
3179
  getValue,
2463
3180
  setValue,
2464
- tooltipContainer,
2465
- hostLanguage,
2466
- singleLine,
2467
- validate,
2468
- show = noop$1,
2469
- example,
2470
- variables,
3181
+ disabled,
2471
3182
  onFocus,
2472
3183
  onBlur,
2473
3184
  tooltip
2474
3185
  } = props;
2475
- const [validationError, setValidationError] = hooks.useState(null);
2476
- const [localError, setLocalError] = hooks.useState(null);
2477
- let value = getValue(element);
2478
- hooks.useEffect(() => {
2479
- if (minDash.isFunction(validate)) {
2480
- const newValidationError = validate(value) || null;
2481
- setValidationError(newValidationError);
2482
- }
2483
- }, [value]);
2484
- const onInput = useStaticCallback(newValue => {
2485
- let newValidationError = null;
2486
- if (minDash.isFunction(validate)) {
2487
- newValidationError = validate(newValue) || null;
2488
- }
2489
-
2490
- // don't create multiple commandStack entries for the same value
2491
- if (newValue !== value) {
2492
- setValue(newValue, newValidationError);
2493
- }
2494
- setValidationError(newValidationError);
2495
- });
2496
- const onError = hooks.useCallback(err => {
2497
- setLocalError(err);
2498
- }, []);
2499
- const temporaryError = useError(id);
2500
- const error = localError || temporaryError || validationError;
3186
+ const value = getValue(element);
3187
+ const error = useError(id);
2501
3188
  return jsxRuntime.jsxs("div", {
2502
- class: classnames__default["default"](props.class, 'bio-properties-panel-entry', error ? 'has-error' : ''),
3189
+ class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
2503
3190
  "data-entry-id": id,
2504
- children: [preact.createElement(FeelTextfield, {
2505
- ...props,
2506
- debounce: debounce,
3191
+ children: [jsxRuntime.jsx(Checkbox, {
2507
3192
  disabled: disabled,
2508
- feel: feel,
2509
3193
  id: id,
2510
- key: element,
2511
3194
  label: label,
2512
- onInput: onInput,
2513
- onError: onError,
3195
+ onChange: setValue,
2514
3196
  onFocus: onFocus,
2515
3197
  onBlur: onBlur,
2516
- example: example,
2517
- hostLanguage: hostLanguage,
2518
- singleLine: singleLine,
2519
- show: show,
2520
3198
  value: value,
2521
- variables: variables,
2522
- tooltipContainer: tooltipContainer,
2523
- OptionalComponent: props.OptionalComponent,
2524
- tooltip: tooltip
2525
- }), error && jsxRuntime.jsx("div", {
3199
+ tooltip: tooltip,
3200
+ element: element
3201
+ }, element), error && jsxRuntime.jsx("div", {
2526
3202
  class: "bio-properties-panel-error",
2527
3203
  children: error
2528
3204
  }), jsxRuntime.jsx(Description, {
@@ -2532,154 +3208,8 @@ function FeelEntry(props) {
2532
3208
  })]
2533
3209
  });
2534
3210
  }
2535
-
2536
- /**
2537
- * @param {Object} props
2538
- * @param {Object} props.element
2539
- * @param {String} props.id
2540
- * @param {String} props.description
2541
- * @param {Boolean} props.debounce
2542
- * @param {Boolean} props.disabled
2543
- * @param {String} props.max
2544
- * @param {String} props.min
2545
- * @param {String} props.step
2546
- * @param {Boolean} props.feel
2547
- * @param {String} props.label
2548
- * @param {Function} props.getValue
2549
- * @param {Function} props.setValue
2550
- * @param {Function} props.tooltipContainer
2551
- * @param {Function} props.validate
2552
- * @param {Function} props.show
2553
- * @param {Function} props.example
2554
- * @param {Function} props.variables
2555
- * @param {Function} props.onFocus
2556
- * @param {Function} props.onBlur
2557
- */
2558
- function FeelNumberEntry(props) {
2559
- return jsxRuntime.jsx(FeelEntry, {
2560
- class: "bio-properties-panel-feel-number",
2561
- OptionalComponent: OptionalFeelNumberField,
2562
- ...props
2563
- });
2564
- }
2565
-
2566
- /**
2567
- * @param {Object} props
2568
- * @param {Object} props.element
2569
- * @param {String} props.id
2570
- * @param {String} props.description
2571
- * @param {Boolean} props.debounce
2572
- * @param {Boolean} props.disabled
2573
- * @param {Boolean} props.feel
2574
- * @param {String} props.label
2575
- * @param {Function} props.getValue
2576
- * @param {Function} props.setValue
2577
- * @param {Function} props.tooltipContainer
2578
- * @param {Function} props.validate
2579
- * @param {Function} props.show
2580
- * @param {Function} props.example
2581
- * @param {Function} props.variables
2582
- * @param {Function} props.onFocus
2583
- * @param {Function} props.onBlur
2584
- */
2585
- function FeelTextAreaEntry(props) {
2586
- return jsxRuntime.jsx(FeelEntry, {
2587
- class: "bio-properties-panel-feel-textarea",
2588
- OptionalComponent: OptionalFeelTextArea,
2589
- ...props
2590
- });
2591
- }
2592
-
2593
- /**
2594
- * @param {Object} props
2595
- * @param {Object} props.element
2596
- * @param {String} props.id
2597
- * @param {String} props.description
2598
- * @param {Boolean} props.debounce
2599
- * @param {Boolean} props.disabled
2600
- * @param {Boolean} props.feel
2601
- * @param {String} props.label
2602
- * @param {Function} props.getValue
2603
- * @param {Function} props.setValue
2604
- * @param {Function} props.tooltipContainer
2605
- * @param {Function} props.validate
2606
- * @param {Function} props.show
2607
- * @param {Function} props.example
2608
- * @param {Function} props.variables
2609
- * @param {Function} props.onFocus
2610
- * @param {Function} props.onBlur
2611
- */
2612
- function FeelToggleSwitchEntry(props) {
2613
- return jsxRuntime.jsx(FeelEntry, {
2614
- class: "bio-properties-panel-feel-toggle-switch",
2615
- OptionalComponent: OptionalFeelToggleSwitch,
2616
- ...props
2617
- });
2618
- }
2619
-
2620
- /**
2621
- * @param {Object} props
2622
- * @param {Object} props.element
2623
- * @param {String} props.id
2624
- * @param {String} props.description
2625
- * @param {Boolean} props.debounce
2626
- * @param {Boolean} props.disabled
2627
- * @param {Boolean} props.feel
2628
- * @param {String} props.label
2629
- * @param {Function} props.getValue
2630
- * @param {Function} props.setValue
2631
- * @param {Function} props.tooltipContainer
2632
- * @param {Function} props.validate
2633
- * @param {Function} props.show
2634
- * @param {Function} props.example
2635
- * @param {Function} props.variables
2636
- * @param {Function} props.onFocus
2637
- * @param {Function} props.onBlur
2638
- */
2639
- function FeelCheckboxEntry(props) {
2640
- return jsxRuntime.jsx(FeelEntry, {
2641
- class: "bio-properties-panel-feel-checkbox",
2642
- OptionalComponent: OptionalFeelCheckbox,
2643
- ...props
2644
- });
2645
- }
2646
-
2647
- /**
2648
- * @param {Object} props
2649
- * @param {Object} props.element
2650
- * @param {String} props.id
2651
- * @param {String} props.description
2652
- * @param {String} props.hostLanguage
2653
- * @param {Boolean} props.singleLine
2654
- * @param {Boolean} props.debounce
2655
- * @param {Boolean} props.disabled
2656
- * @param {Boolean} props.feel
2657
- * @param {String} props.label
2658
- * @param {Function} props.getValue
2659
- * @param {Function} props.setValue
2660
- * @param {Function} props.tooltipContainer
2661
- * @param {Function} props.validate
2662
- * @param {Function} props.show
2663
- * @param {Function} props.example
2664
- * @param {Function} props.variables
2665
- * @param {Function} props.onFocus
2666
- * @param {Function} props.onBlur
2667
- */
2668
- function FeelTemplatingEntry(props) {
2669
- return jsxRuntime.jsx(FeelEntry, {
2670
- class: "bio-properties-panel-feel-templating",
2671
- OptionalComponent: CodeEditor$1,
2672
- ...props
2673
- });
2674
- }
2675
3211
  function isEdited$5(node) {
2676
- if (!node) {
2677
- return false;
2678
- }
2679
- if (node.type === 'checkbox') {
2680
- return !!node.checked || node.classList.contains('edited');
2681
- }
2682
- return !!node.value || node.classList.contains('edited');
3212
+ return node && !!node.checked;
2683
3213
  }
2684
3214
 
2685
3215
  // helpers /////////////////
@@ -3570,6 +4100,7 @@ exports.DebounceInputModule = index;
3570
4100
  exports.DeleteIcon = DeleteIcon;
3571
4101
  exports.DescriptionContext = DescriptionContext;
3572
4102
  exports.DescriptionEntry = Description;
4103
+ exports.DragIcon = DragIcon;
3573
4104
  exports.DropdownButton = DropdownButton;
3574
4105
  exports.ErrorsContext = ErrorsContext;
3575
4106
  exports.EventContext = EventContext;
@@ -3590,6 +4121,7 @@ exports.ListGroup = ListGroup;
3590
4121
  exports.ListItem = ListItem;
3591
4122
  exports.NumberFieldEntry = NumberFieldEntry;
3592
4123
  exports.Placeholder = Placeholder;
4124
+ exports.Popup = Popup;
3593
4125
  exports.PropertiesPanel = PropertiesPanel;
3594
4126
  exports.PropertiesPanelContext = LayoutContext;
3595
4127
  exports.SelectEntry = SelectEntry;
@@ -3599,15 +4131,15 @@ exports.TextAreaEntry = TextAreaEntry;
3599
4131
  exports.TextFieldEntry = TextfieldEntry;
3600
4132
  exports.ToggleSwitchEntry = ToggleSwitchEntry;
3601
4133
  exports.TooltipContext = TooltipContext;
3602
- exports.isCheckboxEntryEdited = isEdited$8;
3603
- exports.isFeelEntryEdited = isEdited$5;
3604
- exports.isNumberFieldEntryEdited = isEdited$6;
4134
+ exports.isCheckboxEntryEdited = isEdited$5;
4135
+ exports.isFeelEntryEdited = isEdited$6;
4136
+ exports.isNumberFieldEntryEdited = isEdited$7;
3605
4137
  exports.isSelectEntryEdited = isEdited$3;
3606
4138
  exports.isSimpleEntryEdited = isEdited$2;
3607
4139
  exports.isTemplatingEntryEdited = isEdited$4;
3608
4140
  exports.isTextAreaEntryEdited = isEdited$1;
3609
4141
  exports.isTextFieldEntryEdited = isEdited;
3610
- exports.isToggleSwitchEntryEdited = isEdited$7;
4142
+ exports.isToggleSwitchEntryEdited = isEdited$8;
3611
4143
  exports.useDescriptionContext = useDescriptionContext;
3612
4144
  exports.useError = useError;
3613
4145
  exports.useErrors = useErrors;