@bpmn-io/form-js-editor 1.0.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs CHANGED
@@ -8,7 +8,7 @@ var jsxRuntime = require('preact/jsx-runtime');
8
8
  var hooks = require('preact/hooks');
9
9
  var preact = require('preact');
10
10
  var React = require('preact/compat');
11
- var dragula = require('dragula');
11
+ var dragula = require('@bpmn-io/draggle');
12
12
  var minDom = require('min-dom');
13
13
  var arrayMove = require('array-move');
14
14
  var feelers = require('feelers');
@@ -534,10 +534,10 @@ function invokeFunction(fn, args) {
534
534
  return fn.apply(null, args);
535
535
  }
536
536
 
537
- /**
538
- * A factory to create a configurable debouncer.
539
- *
540
- * @param {number|boolean} [config=true]
537
+ /**
538
+ * A factory to create a configurable debouncer.
539
+ *
540
+ * @param {number|boolean} [config=true]
541
541
  */
542
542
  function DebounceFactory(config = true) {
543
543
  const timeout = typeof config === 'number' ? config : config ? 300 : 0;
@@ -550,11 +550,11 @@ function DebounceFactory(config = true) {
550
550
  DebounceFactory.$inject = ['config.debounce'];
551
551
 
552
552
  class FieldFactory {
553
- /**
554
- * @constructor
555
- *
556
- * @param { import('./FormFieldRegistry').default } formFieldRegistry
557
- * @param { import('@bpmn-io/form-js-viewer').FormFields } formFields
553
+ /**
554
+ * @constructor
555
+ *
556
+ * @param { import('./FormFieldRegistry').default } formFieldRegistry
557
+ * @param { import('@bpmn-io/form-js-viewer').FormFields } formFields
558
558
  */
559
559
  constructor(formFieldRegistry, formFields) {
560
560
  this._formFieldRegistry = formFieldRegistry;
@@ -617,11 +617,11 @@ class FieldFactory {
617
617
  FieldFactory.$inject = ['formFieldRegistry', 'formFields'];
618
618
 
619
619
  class FormFieldRegistry extends formJsViewer.FormFieldRegistry {
620
- /**
621
- * Updates a form fields id.
622
- *
623
- * @param {Object} formField
624
- * @param {string} newId
620
+ /**
621
+ * Updates a form fields id.
622
+ *
623
+ * @param {Object} formField
624
+ * @param {string} newId
625
625
  */
626
626
  updateId(formField, newId) {
627
627
  this._validateId(newId);
@@ -642,13 +642,13 @@ class FormFieldRegistry extends formJsViewer.FormFieldRegistry {
642
642
  }
643
643
  }
644
644
 
645
- /**
646
- * Validate the suitability of the given id and signals a problem
647
- * with an exception.
648
- *
649
- * @param {string} id
650
- *
651
- * @throws {Error} if id is empty or already assigned
645
+ /**
646
+ * Validate the suitability of the given id and signals a problem
647
+ * with an exception.
648
+ *
649
+ * @param {string} id
650
+ *
651
+ * @throws {Error} if id is empty or already assigned
652
652
  */
653
653
  _validateId(id) {
654
654
  if (!id) {
@@ -665,11 +665,11 @@ const MAX_COLUMNS = 16;
665
665
  const MIN_COLUMNS = 2;
666
666
  const MAX_FIELDS_PER_ROW = 4;
667
667
  class FormLayoutValidator {
668
- /**
669
- * @constructor
670
- *
671
- * @param { import('./FormLayouter').default } formLayouter
672
- * @param { import('./FormFieldRegistry').default } formFieldRegistry
668
+ /**
669
+ * @constructor
670
+ *
671
+ * @param { import('./FormLayouter').default } formLayouter
672
+ * @param { import('./FormFieldRegistry').default } formFieldRegistry
673
673
  */
674
674
  constructor(formLayouter, formFieldRegistry) {
675
675
  this._formLayouter = formLayouter;
@@ -729,11 +729,11 @@ function calculateMaxColumnsWithAuto(autoCols) {
729
729
  }
730
730
 
731
731
  class Importer {
732
- /**
733
- * @constructor
734
- * @param { import('../core/FormFieldRegistry').default } formFieldRegistry
735
- * @param { import('../core/FieldFactory').default } fieldFactory
736
- * @param { import('../core/FormLayouter').default } formLayouter
732
+ /**
733
+ * @constructor
734
+ * @param { import('../core/FormFieldRegistry').default } formFieldRegistry
735
+ * @param { import('../core/FieldFactory').default } fieldFactory
736
+ * @param { import('../core/FormLayouter').default } formLayouter
737
737
  */
738
738
  constructor(formFieldRegistry, fieldFactory, formLayouter) {
739
739
  this._formFieldRegistry = formFieldRegistry;
@@ -741,21 +741,21 @@ class Importer {
741
741
  this._formLayouter = formLayouter;
742
742
  }
743
743
 
744
- /**
745
- * Import schema creating rows, fields, attaching additional
746
- * information to each field and adding fields to the
747
- * field registry.
748
- *
749
- * Additional information attached:
750
- *
751
- * * `id` (unless present)
752
- * * `_parent`
753
- * * `_path`
754
- *
755
- * @param {any} schema
756
- *
757
- * @typedef {{ warnings: Error[], schema: any }} ImportResult
758
- * @returns {ImportResult}
744
+ /**
745
+ * Import schema creating rows, fields, attaching additional
746
+ * information to each field and adding fields to the
747
+ * field registry.
748
+ *
749
+ * Additional information attached:
750
+ *
751
+ * * `id` (unless present)
752
+ * * `_parent`
753
+ * * `_path`
754
+ *
755
+ * @param {any} schema
756
+ *
757
+ * @typedef {{ warnings: Error[], schema: any }} ImportResult
758
+ * @returns {ImportResult}
759
759
  */
760
760
  importSchema(schema) {
761
761
  // TODO: Add warnings
@@ -773,12 +773,12 @@ class Importer {
773
773
  }
774
774
  }
775
775
 
776
- /**
777
- * @param {{[x: string]: any}} fieldAttrs
778
- * @param {String} [parentId]
779
- * @param {number} [index]
780
- *
781
- * @return {any} field
776
+ /**
777
+ * @param {{[x: string]: any}} fieldAttrs
778
+ * @param {String} [parentId]
779
+ * @param {number} [index]
780
+ *
781
+ * @return {any} field
782
782
  */
783
783
  importFormField(fieldAttrs, parentId, index) {
784
784
  const {
@@ -815,11 +815,11 @@ class Importer {
815
815
  return field;
816
816
  }
817
817
 
818
- /**
819
- * @param {Array<any>} components
820
- * @param {string} parentId
821
- *
822
- * @return {Array<any>} imported components
818
+ /**
819
+ * @param {Array<any>} components
820
+ * @param {string} parentId
821
+ *
822
+ * @return {Array<any>} imported components
823
823
  */
824
824
  importFormFields(components, parentId) {
825
825
  return components.map((component, index) => {
@@ -844,22 +844,22 @@ function editorFormFieldClasses(type, {
844
844
  });
845
845
  }
846
846
 
847
- /**
848
- * Add a dragger that calls back the passed function with
849
- * { event, delta } on drag.
850
- *
851
- * @example
852
- *
853
- * function dragMove(event, delta) {
854
- * // we are dragging (!!)
855
- * }
856
- *
857
- * domElement.addEventListener('dragstart', dragger(dragMove));
858
- *
859
- * @param {Function} fn
860
- * @param {Element} dragPreview
861
- *
862
- * @return {Function} drag start callback function
847
+ /**
848
+ * Add a dragger that calls back the passed function with
849
+ * { event, delta } on drag.
850
+ *
851
+ * @example
852
+ *
853
+ * function dragMove(event, delta) {
854
+ * // we are dragging (!!)
855
+ * }
856
+ *
857
+ * domElement.addEventListener('dragstart', dragger(dragMove));
858
+ *
859
+ * @param {Function} fn
860
+ * @param {Element} dragPreview
861
+ *
862
+ * @return {Function} drag start callback function
863
863
  */
864
864
  function createDragger(fn, dragPreview) {
865
865
  let self;
@@ -900,12 +900,12 @@ function createDragger(fn, dragPreview) {
900
900
  return onDragStart;
901
901
  }
902
902
 
903
- /**
904
- * Throttle function call according UI update cycle.
905
- *
906
- * @param {Function} fn
907
- *
908
- * @return {Function} throttled fn
903
+ /**
904
+ * Throttle function call according UI update cycle.
905
+ *
906
+ * @param {Function} fn
907
+ *
908
+ * @return {Function} throttled fn
909
909
  */
910
910
  function throttle(fn) {
911
911
  let active = false;
@@ -934,11 +934,11 @@ const DragAndDropContext = preact.createContext({
934
934
  });
935
935
  var DragAndDropContext$1 = DragAndDropContext;
936
936
 
937
- /**
938
- * @param {string} type
939
- * @param {boolean} [strict]
940
- *
941
- * @returns {any}
937
+ /**
938
+ * @param {string} type
939
+ * @param {boolean} [strict]
940
+ *
941
+ * @returns {any}
942
942
  */
943
943
  function getService$1(type, strict) {}
944
944
  const FormEditorContext = preact.createContext({
@@ -953,15 +953,15 @@ function useService$1 (type, strict) {
953
953
  return getService(type, strict);
954
954
  }
955
955
 
956
- var _path$3;
957
- function _extends$3() { _extends$3 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$3.apply(this, arguments); }
956
+ var _path$4;
957
+ function _extends$4() { _extends$4 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$4.apply(this, arguments); }
958
958
  var SvgClose = function SvgClose(props) {
959
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$3({
959
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$4({
960
960
  xmlns: "http://www.w3.org/2000/svg",
961
961
  width: 16,
962
962
  height: 16,
963
963
  fill: "currentColor"
964
- }, props), _path$3 || (_path$3 = /*#__PURE__*/React__namespace.createElement("path", {
964
+ }, props), _path$4 || (_path$4 = /*#__PURE__*/React__namespace.createElement("path", {
965
965
  fillRule: "evenodd",
966
966
  d: "m12 4.7-.7-.7L8 7.3 4.7 4l-.7.7L7.3 8 4 11.3l.7.7L8 8.7l3.3 3.3.7-.7L8.7 8 12 4.7Z",
967
967
  clipRule: "evenodd"
@@ -969,10 +969,10 @@ var SvgClose = function SvgClose(props) {
969
969
  };
970
970
  var CloseIcon = SvgClose;
971
971
 
972
- var _path$2, _path2;
973
- function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); }
972
+ var _path$3, _path2$1;
973
+ function _extends$3() { _extends$3 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$3.apply(this, arguments); }
974
974
  var SvgDelete = function SvgDelete(props) {
975
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$2({
975
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$3({
976
976
  xmlns: "http://www.w3.org/2000/svg",
977
977
  width: 16,
978
978
  height: 16,
@@ -993,27 +993,27 @@ var SvgDelete = function SvgDelete(props) {
993
993
  mixBlendMode: "multiply"
994
994
  },
995
995
  transform: "translate(.536)"
996
- }), _path$2 || (_path$2 = /*#__PURE__*/React__namespace.createElement("path", {
996
+ }), _path$3 || (_path$3 = /*#__PURE__*/React__namespace.createElement("path", {
997
997
  fill: "currentcolor",
998
998
  d: "M7.536 6h-1v6h1V6Zm3 0h-1v6h1V6Z"
999
- })), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", {
999
+ })), _path2$1 || (_path2$1 = /*#__PURE__*/React__namespace.createElement("path", {
1000
1000
  fill: "currentcolor",
1001
1001
  d: "M2.536 3v1h1v10a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4h1V3h-12Zm2 11V4h8v10h-8Zm6-13h-4v1h4V1Z"
1002
1002
  })));
1003
1003
  };
1004
1004
  var DeleteIcon$1 = SvgDelete;
1005
1005
 
1006
- var _path$1;
1007
- function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
1006
+ var _path$2;
1007
+ function _extends$2() { _extends$2 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$2.apply(this, arguments); }
1008
1008
  var SvgDraggable = function SvgDraggable(props) {
1009
- return /*#__PURE__*/React__namespace.createElement("svg", _extends$1({
1009
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$2({
1010
1010
  xmlns: "http://www.w3.org/2000/svg",
1011
1011
  xmlSpace: "preserve",
1012
1012
  width: 16,
1013
1013
  height: 16,
1014
1014
  fill: "currentcolor",
1015
1015
  viewBox: "0 0 32 32"
1016
- }, props), _path$1 || (_path$1 = /*#__PURE__*/React__namespace.createElement("path", {
1016
+ }, props), _path$2 || (_path$2 = /*#__PURE__*/React__namespace.createElement("path", {
1017
1017
  d: "M10 6h4v4h-4zm8 0h4v4h-4zm-8 8h4v4h-4zm8 0h4v4h-4zm-8 8h4v4h-4zm8 0h4v4h-4z"
1018
1018
  })), /*#__PURE__*/React__namespace.createElement("path", {
1019
1019
  d: "M0 0h32v32H0z",
@@ -1024,21 +1024,76 @@ var SvgDraggable = function SvgDraggable(props) {
1024
1024
  };
1025
1025
  var DraggableIcon = SvgDraggable;
1026
1026
 
1027
- var _path;
1028
- function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
1027
+ var _path$1;
1028
+ function _extends$1() { _extends$1 = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends$1.apply(this, arguments); }
1029
1029
  var SvgSearch = function SvgSearch(props) {
1030
- return /*#__PURE__*/React__namespace.createElement("svg", _extends({
1030
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends$1({
1031
1031
  xmlns: "http://www.w3.org/2000/svg",
1032
1032
  width: 15,
1033
1033
  height: 15,
1034
1034
  fill: "none"
1035
- }, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", {
1035
+ }, props), _path$1 || (_path$1 = /*#__PURE__*/React__namespace.createElement("path", {
1036
1036
  fill: "currentColor",
1037
1037
  d: "m14.5 13.793-3.776-3.776a5.508 5.508 0 1 0-.707.707l3.776 3.776.707-.707ZM2 6.5a4.5 4.5 0 1 1 9 0 4.5 4.5 0 0 1-9 0Z"
1038
1038
  })));
1039
1039
  };
1040
1040
  var SearchIcon = SvgSearch;
1041
1041
 
1042
+ var _path, _rect, _mask, _path2, _path3, _path4, _path5, _path6;
1043
+ function _extends() { _extends = Object.assign ? Object.assign.bind() : function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }
1044
+ var SvgEmptyForm = function SvgEmptyForm(props) {
1045
+ return /*#__PURE__*/React__namespace.createElement("svg", _extends({
1046
+ xmlns: "http://www.w3.org/2000/svg",
1047
+ width: 126,
1048
+ height: 96,
1049
+ fill: "none"
1050
+ }, props), _path || (_path = /*#__PURE__*/React__namespace.createElement("path", {
1051
+ fill: "#FF832B",
1052
+ fillRule: "evenodd",
1053
+ d: "M70 78v8a3 3 0 0 1-3 3h-8v-5h6v-6h5Zm0-16h-5V46h5v16Zm0-32h-5v-6h-6v-5h8a3 3 0 0 1 3 3v8ZM43 19v5H27v-5h16Zm-32 0v5H5v6H0v-8a3 3 0 0 1 3-3h8ZM0 46h5v16H0V46Zm0 32h5v6h6v5H3a3 3 0 0 1-3-3v-8Zm27 11v-5h16v5H27Z",
1054
+ clipRule: "evenodd"
1055
+ })), _rect || (_rect = /*#__PURE__*/React__namespace.createElement("rect", {
1056
+ width: 70,
1057
+ height: 70,
1058
+ fill: "#E5E5E5",
1059
+ rx: 3,
1060
+ transform: "matrix(-1 0 0 1 94 0)"
1061
+ })), _mask || (_mask = /*#__PURE__*/React__namespace.createElement("mask", {
1062
+ id: "EmptyForm_svg__a",
1063
+ fill: "#fff"
1064
+ }, /*#__PURE__*/React__namespace.createElement("path", {
1065
+ fillRule: "evenodd",
1066
+ d: "M87.085 88.684 75.43 45.185l43.499 11.656-11.044 8.072 8.557 8.556-12.728 12.728-8.557-8.556-8.072 11.043Z",
1067
+ clipRule: "evenodd"
1068
+ }))), _path2 || (_path2 = /*#__PURE__*/React__namespace.createElement("path", {
1069
+ fill: "#393939",
1070
+ fillRule: "evenodd",
1071
+ d: "M87.085 88.684 75.43 45.185l43.499 11.656-11.044 8.072 8.557 8.556-12.728 12.728-8.557-8.556-8.072 11.043Z",
1072
+ clipRule: "evenodd"
1073
+ })), _path3 || (_path3 = /*#__PURE__*/React__namespace.createElement("path", {
1074
+ fill: "#393939",
1075
+ d: "M75.43 45.185 70.6 46.48l-2.241-8.365 8.365 2.242-1.294 4.83Zm11.655 43.499 4.037 2.95-6.163 8.432-2.704-10.088 4.83-1.294Zm31.844-31.843 1.294-4.83 10.088 2.703-8.432 6.163-2.95-4.036Zm-11.044 8.072-3.535 3.535-4.128-4.127 4.713-3.445 2.95 4.037Zm8.557 8.556 3.535-3.535 3.536 3.535-3.536 3.536-3.535-3.536Zm-12.728 12.728 3.536 3.536-3.536 3.535-3.536-3.535 3.536-3.536Zm-8.557-8.556-4.036-2.951 3.444-4.713 4.128 4.128-3.536 3.535ZM80.26 43.89 91.915 87.39l-9.66 2.588L70.6 46.48l9.66-2.588Zm37.375 17.78L74.136 50.014l2.588-9.66 43.499 11.656-2.589 9.66Zm-12.699-.795 11.043-8.072 5.901 8.073-11.043 8.072-5.901-8.073Zm7.971 16.129-8.556-8.557 7.071-7.07 8.556 8.556-7.071 7.07Zm-12.728 5.657 12.728-12.728 7.071 7.07-12.727 12.729-7.072-7.071Zm-1.485-8.557 8.557 8.557-7.072 7.07-8.556-8.556 7.07-7.071ZM83.049 85.733 91.12 74.69l8.073 5.901-8.072 11.044-8.073-5.902Z",
1076
+ mask: "url(#EmptyForm_svg__a)"
1077
+ })), _path4 || (_path4 = /*#__PURE__*/React__namespace.createElement("path", {
1078
+ stroke: "#000",
1079
+ strokeLinecap: "round",
1080
+ strokeWidth: 3,
1081
+ d: "m69.431 39.163-9.192-9.192"
1082
+ })), _path5 || (_path5 = /*#__PURE__*/React__namespace.createElement("path", {
1083
+ stroke: "#000",
1084
+ strokeLinecap: "round",
1085
+ strokeWidth: 3,
1086
+ d: "M1.5-1.5h8",
1087
+ transform: "matrix(-1 0 0 1 68.213 50.123)"
1088
+ })), _path6 || (_path6 = /*#__PURE__*/React__namespace.createElement("path", {
1089
+ stroke: "#000",
1090
+ strokeLinecap: "round",
1091
+ strokeWidth: 3,
1092
+ d: "M78.969 36.367v-8"
1093
+ })));
1094
+ };
1095
+ var EmptyFormIcon = SvgEmptyForm;
1096
+
1042
1097
  function EditorText(props) {
1043
1098
  const {
1044
1099
  type,
@@ -1047,7 +1102,7 @@ function EditorText(props) {
1047
1102
  const Icon = formJsViewer.iconsByType('text');
1048
1103
  const templating = useService$1('templating');
1049
1104
  const expressionLanguage = useService$1('expressionLanguage');
1050
- if (!text) {
1105
+ if (!text || !text.trim()) {
1051
1106
  return jsxRuntime.jsx("div", {
1052
1107
  class: editorFormFieldClasses(type),
1053
1108
  children: jsxRuntime.jsxs("div", {
@@ -1233,23 +1288,23 @@ var Slot = (props => {
1233
1288
  return fillsAndSeparators;
1234
1289
  });
1235
1290
 
1236
- /**
1237
- * Creates a Fragment for a fill.
1238
- *
1239
- * @param {Object} fill Fill to be rendered
1240
- * @returns {Object} Preact Fragment containing fill's children
1291
+ /**
1292
+ * Creates a Fragment for a fill.
1293
+ *
1294
+ * @param {Object} fill Fill to be rendered
1295
+ * @returns {Object} Preact Fragment containing fill's children
1241
1296
  */
1242
1297
  const FillFragment = fill => jsxRuntime.jsx(preact.Fragment, {
1243
1298
  children: fill.children
1244
1299
  }, fill.id);
1245
1300
 
1246
- /**
1247
- * Creates an array of fills, with separators inserted between groups.
1248
- *
1249
- * @param {Array} groups Groups of fills
1250
- * @param {Function} fillRenderer Function to create a fill
1251
- * @param {Function} separatorRenderer Function to create a separator
1252
- * @returns {Array} Array of fills and separators
1301
+ /**
1302
+ * Creates an array of fills, with separators inserted between groups.
1303
+ *
1304
+ * @param {Array} groups Groups of fills
1305
+ * @param {Function} fillRenderer Function to create a fill
1306
+ * @param {Function} separatorRenderer Function to create a separator
1307
+ * @returns {Array} Array of fills and separators
1253
1308
  */
1254
1309
  const buildFills = (groups, fillRenderer, separatorRenderer) => {
1255
1310
  const result = [];
@@ -1267,8 +1322,8 @@ const buildFills = (groups, fillRenderer, separatorRenderer) => {
1267
1322
  return result;
1268
1323
  };
1269
1324
 
1270
- /**
1271
- * Groups fills by group name property.
1325
+ /**
1326
+ * Groups fills by group name property.
1272
1327
  */
1273
1328
  const _groupByGroupName = fills => {
1274
1329
  const groups = [];
@@ -1288,8 +1343,8 @@ const _groupByGroupName = fills => {
1288
1343
  return Object.keys(groupsById).sort().map(id => groupsById[id]);
1289
1344
  };
1290
1345
 
1291
- /**
1292
- * Compares fills by priority.
1346
+ /**
1347
+ * Compares fills by priority.
1293
1348
  */
1294
1349
  const _comparePriority = (a, b) => {
1295
1350
  return (b.priority || 0) - (a.priority || 0);
@@ -1517,19 +1572,19 @@ const DRAG_NO_DROP_CLS = 'fjs-no-drop';
1517
1572
  const DRAG_NO_MOVE_CLS = 'fjs-no-move';
1518
1573
  const ERROR_DROP_CLS = 'fjs-error-drop';
1519
1574
 
1520
- /**
1521
- * @typedef { { id: String, components: Array<any> } } FormRow
1575
+ /**
1576
+ * @typedef { { id: String, components: Array<any> } } FormRow
1522
1577
  */
1523
1578
 
1524
1579
  class Dragging {
1525
- /**
1526
- * @constructor
1527
- *
1528
- * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1529
- * @param { import('../../core/FormLayouter').default } formLayouter
1530
- * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1531
- * @param { import('../../core/EventBus').default } eventBus
1532
- * @param { import('../modeling/Modeling').default } modeling
1580
+ /**
1581
+ * @constructor
1582
+ *
1583
+ * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1584
+ * @param { import('../../core/FormLayouter').default } formLayouter
1585
+ * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1586
+ * @param { import('../../core/EventBus').default } eventBus
1587
+ * @param { import('../modeling/Modeling').default } modeling
1533
1588
  */
1534
1589
  constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling) {
1535
1590
  this._formFieldRegistry = formFieldRegistry;
@@ -1539,13 +1594,13 @@ class Dragging {
1539
1594
  this._modeling = modeling;
1540
1595
  }
1541
1596
 
1542
- /**
1543
- * Calculcates position in form schema given the dropped place.
1544
- *
1545
- * @param { FormRow } targetRow
1546
- * @param { any } targetFormField
1547
- * @param { HTMLElement } sibling
1548
- * @returns { number }
1597
+ /**
1598
+ * Calculcates position in form schema given the dropped place.
1599
+ *
1600
+ * @param { FormRow } targetRow
1601
+ * @param { any } targetFormField
1602
+ * @param { HTMLElement } sibling
1603
+ * @returns { number }
1549
1604
  */
1550
1605
  getTargetIndex(targetRow, targetFormField, sibling) {
1551
1606
  /** @type HTMLElement */
@@ -1647,17 +1702,21 @@ class Dragging {
1647
1702
  }
1648
1703
  }
1649
1704
 
1650
- /**
1651
- * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1705
+ /**
1706
+ * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1652
1707
  */
1653
1708
  createDragulaInstance(options) {
1654
1709
  const {
1655
1710
  container,
1656
- direction,
1657
1711
  mirrorContainer
1658
1712
  } = options || {};
1659
- const dragulaInstance = dragula({
1660
- direction,
1713
+ let dragulaOptions = {
1714
+ direction: function (el, target) {
1715
+ if (isRow(target)) {
1716
+ return 'horizontal';
1717
+ }
1718
+ return 'vertical';
1719
+ },
1661
1720
  mirrorContainer,
1662
1721
  isContainer(el) {
1663
1722
  return container.some(cls => el.classList.contains(cls));
@@ -1688,7 +1747,8 @@ class Dragging {
1688
1747
  },
1689
1748
  slideFactorX: 10,
1690
1749
  slideFactorY: 5
1691
- });
1750
+ };
1751
+ const dragulaInstance = dragula(dragulaOptions);
1692
1752
 
1693
1753
  // bind life cycle events
1694
1754
  dragulaInstance.on('drag', (element, source) => {
@@ -1948,7 +2008,19 @@ function ContextPad(props) {
1948
2008
  });
1949
2009
  }
1950
2010
  function Empty(props) {
1951
- return null;
2011
+ return jsxRuntime.jsx("div", {
2012
+ class: "fjs-empty-editor",
2013
+ children: jsxRuntime.jsxs("div", {
2014
+ class: "fjs-empty-editor-card",
2015
+ children: [jsxRuntime.jsx(EmptyFormIcon, {}), jsxRuntime.jsx("h2", {
2016
+ children: "Build your form"
2017
+ }), jsxRuntime.jsx("span", {
2018
+ children: "Drag and drop components here to start designing."
2019
+ }), jsxRuntime.jsx("span", {
2020
+ children: "Use the preview window to test your form."
2021
+ })]
2022
+ })
2023
+ });
1952
2024
  }
1953
2025
  function Element$1(props) {
1954
2026
  const eventBus = useService$1('eventBus'),
@@ -2045,7 +2117,7 @@ function DebugColumns(props) {
2045
2117
  return null;
2046
2118
  }
2047
2119
  return jsxRuntime.jsx("div", {
2048
- style: "width: fit-content; padding: 2px 6px; height: 16px; background: var(--color-blue-205-100-95); display: flex; justify-content: center; align-items: center; position: absolute; bottom: -2px; z-index: 2; font-size: 10px; right: 3px;",
2120
+ style: "width: fit-content;\r padding: 2px 6px;\r height: 16px;\r background: var(--color-blue-205-100-95);\r display: flex;\r justify-content: center;\r align-items: center;\r position: absolute;\r bottom: -2px;\r z-index: 2;\r font-size: 10px;\r right: 3px;",
2049
2121
  class: "fjs-debug-columns",
2050
2122
  children: (field.layout || {}).columns || 'auto'
2051
2123
  });
@@ -2142,7 +2214,6 @@ function FormEditor$1(props) {
2142
2214
  hooks.useEffect(() => {
2143
2215
  let dragulaInstance = dragging.createDragulaInstance({
2144
2216
  container: [DRAG_CONTAINER_CLS, DROP_CONTAINER_VERTICAL_CLS, DROP_CONTAINER_HORIZONTAL_CLS],
2145
- direction: 'vertical',
2146
2217
  mirrorContainer: formContainerRef.current
2147
2218
  });
2148
2219
  setDrake(dragulaInstance);
@@ -2156,7 +2227,6 @@ function FormEditor$1(props) {
2156
2227
  onDetach();
2157
2228
  dragulaInstance = dragging.createDragulaInstance({
2158
2229
  container: [DRAG_CONTAINER_CLS, DROP_CONTAINER_VERTICAL_CLS, DROP_CONTAINER_HORIZONTAL_CLS],
2159
- direction: 'vertical',
2160
2230
  mirrorContainer: formContainerRef.current
2161
2231
  });
2162
2232
  setDrake(dragulaInstance);
@@ -3104,10 +3174,10 @@ function updateRow(formField, rowId) {
3104
3174
  }
3105
3175
 
3106
3176
  class AddFormFieldHandler {
3107
- /**
3108
- * @constructor
3109
- * @param { import('../../../FormEditor').default } formEditor
3110
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3177
+ /**
3178
+ * @constructor
3179
+ * @param { import('../../../FormEditor').default } formEditor
3180
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3111
3181
  */
3112
3182
  constructor(formEditor, formFieldRegistry) {
3113
3183
  this._formEditor = formEditor;
@@ -3168,10 +3238,10 @@ class AddFormFieldHandler {
3168
3238
  AddFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3169
3239
 
3170
3240
  class EditFormFieldHandler {
3171
- /**
3172
- * @constructor
3173
- * @param { import('../../../FormEditor').default } formEditor
3174
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3241
+ /**
3242
+ * @constructor
3243
+ * @param { import('../../../FormEditor').default } formEditor
3244
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3175
3245
  */
3176
3246
  constructor(formEditor, formFieldRegistry) {
3177
3247
  this._formEditor = formEditor;
@@ -3234,10 +3304,10 @@ class EditFormFieldHandler {
3234
3304
  EditFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3235
3305
 
3236
3306
  class MoveFormFieldHandler {
3237
- /**
3238
- * @constructor
3239
- * @param { import('../../../FormEditor').default } formEditor
3240
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3307
+ /**
3308
+ * @constructor
3309
+ * @param { import('../../../FormEditor').default } formEditor
3310
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3241
3311
  */
3242
3312
  constructor(formEditor, formFieldRegistry) {
3243
3313
  this._formEditor = formEditor;
@@ -3326,10 +3396,10 @@ class MoveFormFieldHandler {
3326
3396
  MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3327
3397
 
3328
3398
  class RemoveFormFieldHandler {
3329
- /**
3330
- * @constructor
3331
- * @param { import('../../../FormEditor').default } formEditor
3332
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3399
+ /**
3400
+ * @constructor
3401
+ * @param { import('../../../FormEditor').default } formEditor
3402
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3333
3403
  */
3334
3404
  constructor(formEditor, formFieldRegistry) {
3335
3405
  this._formEditor = formEditor;
@@ -3389,9 +3459,9 @@ class RemoveFormFieldHandler {
3389
3459
  RemoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
3390
3460
 
3391
3461
  class UpdateIdClaimHandler {
3392
- /**
3393
- * @constructor
3394
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3462
+ /**
3463
+ * @constructor
3464
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3395
3465
  */
3396
3466
  constructor(formFieldRegistry) {
3397
3467
  this._formFieldRegistry = formFieldRegistry;
@@ -3424,9 +3494,9 @@ class UpdateIdClaimHandler {
3424
3494
  UpdateIdClaimHandler.$inject = ['formFieldRegistry'];
3425
3495
 
3426
3496
  class UpdateKeyClaimHandler {
3427
- /**
3428
- * @constructor
3429
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3497
+ /**
3498
+ * @constructor
3499
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3430
3500
  */
3431
3501
  constructor(formFieldRegistry) {
3432
3502
  this._formFieldRegistry = formFieldRegistry;
@@ -3892,8 +3962,8 @@ class ValidateBehavior extends CommandInterceptor {
3892
3962
  constructor(eventBus) {
3893
3963
  super(eventBus);
3894
3964
 
3895
- /**
3896
- * Remove custom validation if <validationType> is about to be added.
3965
+ /**
3966
+ * Remove custom validation if <validationType> is about to be added.
3897
3967
  */
3898
3968
  // @ts-ignore-next-line
3899
3969
  this.preExecute('formField.edit', function (context) {
@@ -4473,22 +4543,22 @@ var SelectionModule = {
4473
4543
  selectionBehavior: ['type', SelectionBehavior]
4474
4544
  };
4475
4545
 
4476
- /**
4477
- * Base class for sectionable UI modules.
4478
- *
4479
- * @property {EventBus} _eventBus - EventBus instance used for event handling.
4480
- * @property {string} managerType - Type of the render manager. Used to form event names.
4481
- *
4482
- * @class SectionModuleBase
4546
+ /**
4547
+ * Base class for sectionable UI modules.
4548
+ *
4549
+ * @property {EventBus} _eventBus - EventBus instance used for event handling.
4550
+ * @property {string} managerType - Type of the render manager. Used to form event names.
4551
+ *
4552
+ * @class SectionModuleBase
4483
4553
  */
4484
4554
  class SectionModuleBase {
4485
- /**
4486
- * Create a SectionModuleBase instance.
4487
- *
4488
- * @param {any} eventBus - The EventBus instance used for event handling.
4489
- * @param {string} sectionKey - The type of render manager. Used to form event names.
4490
- *
4491
- * @constructor
4555
+ /**
4556
+ * Create a SectionModuleBase instance.
4557
+ *
4558
+ * @param {any} eventBus - The EventBus instance used for event handling.
4559
+ * @param {string} sectionKey - The type of render manager. Used to form event names.
4560
+ *
4561
+ * @constructor
4492
4562
  */
4493
4563
  constructor(eventBus, sectionKey) {
4494
4564
  this._eventBus = eventBus;
@@ -4501,10 +4571,10 @@ class SectionModuleBase {
4501
4571
  });
4502
4572
  }
4503
4573
 
4504
- /**
4505
- * Attach the managed section to a parent node.
4506
- *
4507
- * @param {HTMLElement} container - The parent node to attach to.
4574
+ /**
4575
+ * Attach the managed section to a parent node.
4576
+ *
4577
+ * @param {HTMLElement} container - The parent node to attach to.
4508
4578
  */
4509
4579
  attachTo(container) {
4510
4580
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.attach`, {
@@ -4512,22 +4582,22 @@ class SectionModuleBase {
4512
4582
  }));
4513
4583
  }
4514
4584
 
4515
- /**
4516
- * Detach the managed section from its parent node.
4585
+ /**
4586
+ * Detach the managed section from its parent node.
4517
4587
  */
4518
4588
  detach() {
4519
4589
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.detach`));
4520
4590
  }
4521
4591
 
4522
- /**
4523
- * Reset the managed section to its initial state.
4592
+ /**
4593
+ * Reset the managed section to its initial state.
4524
4594
  */
4525
4595
  reset() {
4526
4596
  this._onceSectionRendered(() => this._eventBus.fire(`${this._sectionKey}.reset`));
4527
4597
  }
4528
4598
 
4529
- /**
4530
- * Circumvents timing issues.
4599
+ /**
4600
+ * Circumvents timing issues.
4531
4601
  */
4532
4602
  _onceSectionRendered(callback) {
4533
4603
  if (this.isSectionRendered) {
@@ -4702,6 +4772,166 @@ const LayoutContext = preact.createContext({
4702
4772
  getLayoutForKey: () => {},
4703
4773
  setLayoutForKey: () => {}
4704
4774
  });
4775
+ const TooltipContext = preact.createContext({
4776
+ tooltip: {},
4777
+ getTooltipForId: () => {}
4778
+ });
4779
+
4780
+ /**
4781
+ * Accesses the global TooltipContext and returns a tooltip for a given id and element.
4782
+ *
4783
+ * @example
4784
+ * ```jsx
4785
+ * function TextField(props) {
4786
+ * const tooltip = useTooltipContext('input1', element);
4787
+ * }
4788
+ * ```
4789
+ *
4790
+ * @param {string} id
4791
+ * @param {object} element
4792
+ *
4793
+ * @returns {string}
4794
+ */
4795
+ function useTooltipContext(id, element) {
4796
+ const {
4797
+ getTooltipForId
4798
+ } = hooks.useContext(TooltipContext);
4799
+ return getTooltipForId(id, element);
4800
+ }
4801
+ function TooltipWrapper(props) {
4802
+ const {
4803
+ forId,
4804
+ element
4805
+ } = props;
4806
+ const contextDescription = useTooltipContext(forId, element);
4807
+ const value = props.value || contextDescription;
4808
+ if (!value) {
4809
+ return props.children;
4810
+ }
4811
+ return jsxRuntime.jsx(Tooltip, {
4812
+ ...props,
4813
+ value: value,
4814
+ forId: prefixId$8(forId)
4815
+ });
4816
+ }
4817
+ function Tooltip(props) {
4818
+ const {
4819
+ forId,
4820
+ value,
4821
+ parent
4822
+ } = props;
4823
+ const [visible, setShow] = hooks.useState(false);
4824
+ let timeout = null;
4825
+ const wrapperRef = hooks.useRef(null);
4826
+ const tooltipRef = hooks.useRef(null);
4827
+ const showTooltip = async event => {
4828
+ const show = () => !visible && setShow(true);
4829
+ if (event instanceof MouseEvent) {
4830
+ timeout = setTimeout(show, 200);
4831
+ } else {
4832
+ show();
4833
+ }
4834
+ };
4835
+ const hideTooltip = () => setShow(false);
4836
+ const hideTooltipViaEscape = e => {
4837
+ e.code === 'Escape' && hideTooltip();
4838
+ };
4839
+ const isTooltipHovered = ({
4840
+ x,
4841
+ y
4842
+ }) => {
4843
+ const tooltip = tooltipRef.current;
4844
+ const wrapper = wrapperRef.current;
4845
+ return tooltip && (inBounds(x, y, wrapper.getBoundingClientRect()) || inBounds(x, y, tooltip.getBoundingClientRect()));
4846
+ };
4847
+ hooks.useEffect(() => {
4848
+ const {
4849
+ current
4850
+ } = wrapperRef;
4851
+ if (!current) {
4852
+ return;
4853
+ }
4854
+ const hideHoveredTooltip = e => {
4855
+ const isFocused = document.activeElement === wrapperRef.current || document.activeElement.closest('.bio-properties-panel-tooltip');
4856
+ if (visible && !isTooltipHovered({
4857
+ x: e.x,
4858
+ y: e.y
4859
+ }) && !isFocused) {
4860
+ hideTooltip();
4861
+ }
4862
+ };
4863
+ const hideFocusedTooltip = e => {
4864
+ const {
4865
+ relatedTarget
4866
+ } = e;
4867
+ const isTooltipChild = el => el && !!el.closest('.bio-properties-panel-tooltip');
4868
+ if (visible && !isHovered(wrapperRef.current) && !isTooltipChild(relatedTarget)) {
4869
+ hideTooltip();
4870
+ }
4871
+ };
4872
+ document.addEventListener('wheel', hideHoveredTooltip);
4873
+ document.addEventListener('focusout', hideFocusedTooltip);
4874
+ document.addEventListener('mousemove', hideHoveredTooltip);
4875
+ return () => {
4876
+ document.removeEventListener('wheel', hideHoveredTooltip);
4877
+ document.removeEventListener('mousemove', hideHoveredTooltip);
4878
+ document.removeEventListener('focusout', hideFocusedTooltip);
4879
+ };
4880
+ }, [wrapperRef.current, visible]);
4881
+ const renderTooltip = () => {
4882
+ return jsxRuntime.jsxs("div", {
4883
+ class: "bio-properties-panel-tooltip",
4884
+ role: "tooltip",
4885
+ id: "bio-properties-panel-tooltip",
4886
+ "aria-labelledby": forId,
4887
+ style: getTooltipPosition(wrapperRef.current),
4888
+ ref: tooltipRef,
4889
+ onClick: e => e.stopPropagation(),
4890
+ children: [jsxRuntime.jsx("div", {
4891
+ class: "bio-properties-panel-tooltip-content",
4892
+ children: value
4893
+ }), jsxRuntime.jsx("div", {
4894
+ class: "bio-properties-panel-tooltip-arrow"
4895
+ })]
4896
+ });
4897
+ };
4898
+ return jsxRuntime.jsxs("div", {
4899
+ class: "bio-properties-panel-tooltip-wrapper",
4900
+ tabIndex: "0",
4901
+ ref: wrapperRef,
4902
+ onMouseEnter: showTooltip,
4903
+ onMouseLeave: () => clearTimeout(timeout),
4904
+ onFocus: showTooltip,
4905
+ onKeyDown: hideTooltipViaEscape,
4906
+ onMouseDown: e => {
4907
+ e.preventDefault();
4908
+ },
4909
+ children: [props.children, visible ? parent ? React.createPortal(renderTooltip(), parent.current) : renderTooltip() : null]
4910
+ });
4911
+ }
4912
+
4913
+ // helper
4914
+ function inBounds(x, y, bounds) {
4915
+ const {
4916
+ top,
4917
+ right,
4918
+ bottom,
4919
+ left
4920
+ } = bounds;
4921
+ return x >= left && x <= right && y >= top && y <= bottom;
4922
+ }
4923
+ function getTooltipPosition(refElement) {
4924
+ const refPosition = refElement.getBoundingClientRect();
4925
+ const right = `calc(100% - ${refPosition.x}px)`;
4926
+ const top = `${refPosition.top - 10}px`;
4927
+ return `right: ${right}; top: ${top};`;
4928
+ }
4929
+ function isHovered(element) {
4930
+ return element.matches(':hover');
4931
+ }
4932
+ function prefixId$8(id) {
4933
+ return `bio-properties-panel-${id}`;
4934
+ }
4705
4935
 
4706
4936
  /**
4707
4937
  * Accesses the global DescriptionContext and returns a description for a given id and element.
@@ -4730,6 +4960,12 @@ function useError(id) {
4730
4960
  } = hooks.useContext(ErrorsContext);
4731
4961
  return errors[id];
4732
4962
  }
4963
+ function useErrors() {
4964
+ const {
4965
+ errors
4966
+ } = hooks.useContext(ErrorsContext);
4967
+ return errors;
4968
+ }
4733
4969
 
4734
4970
  /**
4735
4971
  * Subscribe to an event immediately. Update subscription after inputs changed.
@@ -4961,6 +5197,10 @@ function Group(props) {
4961
5197
  setEdited(hasOneEditedEntry);
4962
5198
  }, [entries]);
4963
5199
 
5200
+ // set error state depending on all entries
5201
+ const allErrors = useErrors();
5202
+ const hasErrors = entries.some(entry => allErrors[entry.id]);
5203
+
4964
5204
  // set css class when group is sticky to top
4965
5205
  useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
4966
5206
  const propertiesPanelContext = {
@@ -4977,10 +5217,19 @@ function Group(props) {
4977
5217
  children: [jsxRuntime.jsx("div", {
4978
5218
  title: label,
4979
5219
  class: "bio-properties-panel-group-header-title",
4980
- children: label
5220
+ children: jsxRuntime.jsx(TooltipWrapper, {
5221
+ value: props.tooltip,
5222
+ forId: 'group-' + id,
5223
+ element: element,
5224
+ parent: groupRef,
5225
+ children: label
5226
+ })
4981
5227
  }), jsxRuntime.jsxs("div", {
4982
5228
  class: "bio-properties-panel-group-header-buttons",
4983
- children: [edited && jsxRuntime.jsx(DataMarker, {}), jsxRuntime.jsx("button", {
5229
+ children: [jsxRuntime.jsx(DataMarker, {
5230
+ edited: edited,
5231
+ hasErrors: hasErrors
5232
+ }), jsxRuntime.jsx("button", {
4984
5233
  title: "Toggle section",
4985
5234
  class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
4986
5235
  children: jsxRuntime.jsx(ArrowIcon, {
@@ -5007,11 +5256,24 @@ function Group(props) {
5007
5256
  })]
5008
5257
  });
5009
5258
  }
5010
- function DataMarker() {
5011
- return jsxRuntime.jsx("div", {
5012
- title: "Section contains data",
5013
- class: "bio-properties-panel-dot"
5014
- });
5259
+ function DataMarker(props) {
5260
+ const {
5261
+ edited,
5262
+ hasErrors
5263
+ } = props;
5264
+ if (hasErrors) {
5265
+ return jsxRuntime.jsx("div", {
5266
+ title: "Section contains an error",
5267
+ class: "bio-properties-panel-dot bio-properties-panel-dot--error"
5268
+ });
5269
+ }
5270
+ if (edited) {
5271
+ return jsxRuntime.jsx("div", {
5272
+ title: "Section contains data",
5273
+ class: "bio-properties-panel-dot"
5274
+ });
5275
+ }
5276
+ return null;
5015
5277
  }
5016
5278
 
5017
5279
  /**
@@ -5042,6 +5304,7 @@ function Placeholder(props) {
5042
5304
  }
5043
5305
  const DEFAULT_LAYOUT = {};
5044
5306
  const DEFAULT_DESCRIPTION = {};
5307
+ const DEFAULT_TOOLTIP = {};
5045
5308
 
5046
5309
  /**
5047
5310
  * @typedef { {
@@ -5082,12 +5345,22 @@ const DEFAULT_DESCRIPTION = {};
5082
5345
  * [id: String]: GetDescriptionFunction
5083
5346
  * } } DescriptionConfig
5084
5347
  *
5348
+ * @typedef { {
5349
+ * [id: String]: GetTooltipFunction
5350
+ * } } TooltipConfig
5351
+ *
5085
5352
  * @callback { {
5086
5353
  * @param {string} id
5087
5354
  * @param {Object} element
5088
5355
  * @returns {string}
5089
5356
  * } } GetDescriptionFunction
5090
5357
  *
5358
+ * @callback { {
5359
+ * @param {string} id
5360
+ * @param {Object} element
5361
+ * @returns {string}
5362
+ * } } GetTooltipFunction
5363
+ *
5091
5364
  * @typedef { {
5092
5365
  * getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
5093
5366
  * getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
@@ -5108,6 +5381,8 @@ const DEFAULT_DESCRIPTION = {};
5108
5381
  * @param {Function} [props.layoutChanged]
5109
5382
  * @param {DescriptionConfig} [props.descriptionConfig]
5110
5383
  * @param {Function} [props.descriptionLoaded]
5384
+ * @param {TooltipConfig} [props.tooltipConfig]
5385
+ * @param {Function} [props.tooltipLoaded]
5111
5386
  * @param {Object} [props.eventBus]
5112
5387
  */
5113
5388
  function PropertiesPanel(props) {
@@ -5120,6 +5395,8 @@ function PropertiesPanel(props) {
5120
5395
  layoutChanged,
5121
5396
  descriptionConfig,
5122
5397
  descriptionLoaded,
5398
+ tooltipConfig,
5399
+ tooltipLoaded,
5123
5400
  eventBus
5124
5401
  } = props;
5125
5402
 
@@ -5165,6 +5442,21 @@ function PropertiesPanel(props) {
5165
5442
  description,
5166
5443
  getDescriptionForId
5167
5444
  };
5445
+
5446
+ // set-up tooltip context
5447
+ const tooltip = hooks.useMemo(() => createTooltipContext(tooltipConfig), [tooltipConfig]);
5448
+ hooks.useEffect(() => {
5449
+ if (typeof tooltipLoaded === 'function') {
5450
+ tooltipLoaded(tooltip);
5451
+ }
5452
+ }, [tooltip, tooltipLoaded]);
5453
+ const getTooltipForId = (id, element) => {
5454
+ return tooltip[id] && tooltip[id](element);
5455
+ };
5456
+ const tooltipContext = {
5457
+ tooltip,
5458
+ getTooltipForId
5459
+ };
5168
5460
  const [errors, setErrors] = hooks.useState({});
5169
5461
  const onSetErrors = ({
5170
5462
  errors
@@ -5199,29 +5491,32 @@ function PropertiesPanel(props) {
5199
5491
  value: errorsContext,
5200
5492
  children: jsxRuntime.jsx(DescriptionContext.Provider, {
5201
5493
  value: descriptionContext,
5202
- children: jsxRuntime.jsx(LayoutContext.Provider, {
5203
- value: layoutContext,
5204
- children: jsxRuntime.jsx(EventContext.Provider, {
5205
- value: eventContext,
5206
- children: jsxRuntime.jsxs("div", {
5207
- class: "bio-properties-panel",
5208
- children: [jsxRuntime.jsx(Header, {
5209
- element: element,
5210
- headerProvider: headerProvider
5211
- }), jsxRuntime.jsx("div", {
5212
- class: "bio-properties-panel-scroll-container",
5213
- children: groups.map(group => {
5214
- const {
5215
- component: Component = Group,
5216
- id
5217
- } = group;
5218
- return preact.createElement(Component, {
5219
- ...group,
5220
- key: id,
5221
- element: element
5222
- });
5223
- })
5224
- })]
5494
+ children: jsxRuntime.jsx(TooltipContext.Provider, {
5495
+ value: tooltipContext,
5496
+ children: jsxRuntime.jsx(LayoutContext.Provider, {
5497
+ value: layoutContext,
5498
+ children: jsxRuntime.jsx(EventContext.Provider, {
5499
+ value: eventContext,
5500
+ children: jsxRuntime.jsxs("div", {
5501
+ class: "bio-properties-panel",
5502
+ children: [jsxRuntime.jsx(Header, {
5503
+ element: element,
5504
+ headerProvider: headerProvider
5505
+ }), jsxRuntime.jsx("div", {
5506
+ class: "bio-properties-panel-scroll-container",
5507
+ children: groups.map(group => {
5508
+ const {
5509
+ component: Component = Group,
5510
+ id
5511
+ } = group;
5512
+ return preact.createElement(Component, {
5513
+ ...group,
5514
+ key: id,
5515
+ element: element
5516
+ });
5517
+ })
5518
+ })]
5519
+ })
5225
5520
  })
5226
5521
  })
5227
5522
  })
@@ -5244,6 +5539,12 @@ function createDescriptionContext(overrides = {}) {
5244
5539
  ...overrides
5245
5540
  };
5246
5541
  }
5542
+ function createTooltipContext(overrides = {}) {
5543
+ return {
5544
+ ...DEFAULT_TOOLTIP,
5545
+ ...overrides
5546
+ };
5547
+ }
5247
5548
 
5248
5549
  // hooks //////////////////
5249
5550
 
@@ -5474,6 +5775,18 @@ function ListGroup(props) {
5474
5775
  setAddTriggered(true);
5475
5776
  add(e);
5476
5777
  };
5778
+ const allErrors = useErrors();
5779
+ const hasError = items.some(item => {
5780
+ if (allErrors[item.id]) {
5781
+ return true;
5782
+ }
5783
+ if (!item.entries) {
5784
+ return;
5785
+ }
5786
+
5787
+ // also check if the error is nested, e.g. for name-value entries
5788
+ return item.entries.some(entry => allErrors[entry.id]);
5789
+ });
5477
5790
  return jsxRuntime.jsxs("div", {
5478
5791
  class: "bio-properties-panel-group",
5479
5792
  "data-group-id": 'group-' + id,
@@ -5484,7 +5797,13 @@ function ListGroup(props) {
5484
5797
  children: [jsxRuntime.jsx("div", {
5485
5798
  title: label,
5486
5799
  class: "bio-properties-panel-group-header-title",
5487
- children: label
5800
+ children: jsxRuntime.jsx(TooltipWrapper, {
5801
+ value: props.tooltip,
5802
+ forId: 'group-' + id,
5803
+ element: element,
5804
+ parent: groupRef,
5805
+ children: label
5806
+ })
5488
5807
  }), jsxRuntime.jsxs("div", {
5489
5808
  class: "bio-properties-panel-group-header-buttons",
5490
5809
  children: [add ? jsxRuntime.jsxs("button", {
@@ -5497,7 +5816,7 @@ function ListGroup(props) {
5497
5816
  }) : null]
5498
5817
  }) : null, hasItems ? jsxRuntime.jsx("div", {
5499
5818
  title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
5500
- class: "bio-properties-panel-list-badge",
5819
+ class: classnames('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
5501
5820
  children: items.length
5502
5821
  }) : null, hasItems ? jsxRuntime.jsx("button", {
5503
5822
  title: "Toggle section",
@@ -5573,7 +5892,8 @@ function Checkbox(props) {
5573
5892
  disabled,
5574
5893
  value = false,
5575
5894
  onFocus,
5576
- onBlur
5895
+ onBlur,
5896
+ tooltip
5577
5897
  } = props;
5578
5898
  const [localValue, setLocalValue] = hooks.useState(value);
5579
5899
  const handleChangeCallback = ({
@@ -5608,7 +5928,12 @@ function Checkbox(props) {
5608
5928
  }), jsxRuntime.jsx("label", {
5609
5929
  for: prefixId$7(id),
5610
5930
  class: "bio-properties-panel-label",
5611
- children: label
5931
+ children: jsxRuntime.jsx(TooltipWrapper, {
5932
+ value: tooltip,
5933
+ forId: id,
5934
+ element: props.element,
5935
+ children: label
5936
+ })
5612
5937
  })]
5613
5938
  });
5614
5939
  }
@@ -5623,6 +5948,7 @@ function Checkbox(props) {
5623
5948
  * @param {Function} props.setValue
5624
5949
  * @param {Function} props.onFocus
5625
5950
  * @param {Function} props.onBlur
5951
+ * @param {string|import('preact').Component} props.tooltip
5626
5952
  * @param {boolean} [props.disabled]
5627
5953
  */
5628
5954
  function CheckboxEntry(props) {
@@ -5635,7 +5961,8 @@ function CheckboxEntry(props) {
5635
5961
  setValue,
5636
5962
  disabled,
5637
5963
  onFocus,
5638
- onBlur
5964
+ onBlur,
5965
+ tooltip
5639
5966
  } = props;
5640
5967
  const value = getValue(element);
5641
5968
  const error = useError(id);
@@ -5649,7 +5976,9 @@ function CheckboxEntry(props) {
5649
5976
  onChange: setValue,
5650
5977
  onFocus: onFocus,
5651
5978
  onBlur: onBlur,
5652
- value: value
5979
+ value: value,
5980
+ tooltip: tooltip,
5981
+ element: element
5653
5982
  }, element), error && jsxRuntime.jsx("div", {
5654
5983
  class: "bio-properties-panel-error",
5655
5984
  children: error
@@ -5906,7 +6235,8 @@ function ToggleSwitch(props) {
5906
6235
  inline,
5907
6236
  onFocus,
5908
6237
  onBlur,
5909
- inputRef
6238
+ inputRef,
6239
+ tooltip
5910
6240
  } = props;
5911
6241
  const [localValue, setLocalValue] = hooks.useState(value);
5912
6242
  const handleInputCallback = async () => {
@@ -5929,7 +6259,12 @@ function ToggleSwitch(props) {
5929
6259
  children: [jsxRuntime.jsx("label", {
5930
6260
  class: "bio-properties-panel-label",
5931
6261
  for: prefixId$6(id),
5932
- children: label
6262
+ children: jsxRuntime.jsx(TooltipWrapper, {
6263
+ value: tooltip,
6264
+ forId: id,
6265
+ element: props.element,
6266
+ children: label
6267
+ })
5933
6268
  }), jsxRuntime.jsxs("div", {
5934
6269
  class: "bio-properties-panel-field-wrapper",
5935
6270
  children: [jsxRuntime.jsxs("label", {
@@ -5967,6 +6302,7 @@ function ToggleSwitch(props) {
5967
6302
  * @param {Function} props.setValue
5968
6303
  * @param {Function} props.onFocus
5969
6304
  * @param {Function} props.onBlur
6305
+ * @param {string|import('preact').Component} props.tooltip
5970
6306
  */
5971
6307
  function ToggleSwitchEntry(props) {
5972
6308
  const {
@@ -5979,7 +6315,8 @@ function ToggleSwitchEntry(props) {
5979
6315
  getValue,
5980
6316
  setValue,
5981
6317
  onFocus,
5982
- onBlur
6318
+ onBlur,
6319
+ tooltip
5983
6320
  } = props;
5984
6321
  const value = getValue(element);
5985
6322
  return jsxRuntime.jsxs("div", {
@@ -5993,7 +6330,9 @@ function ToggleSwitchEntry(props) {
5993
6330
  onFocus: onFocus,
5994
6331
  onBlur: onBlur,
5995
6332
  switcherLabel: switcherLabel,
5996
- inline: inline
6333
+ inline: inline,
6334
+ tooltip: tooltip,
6335
+ element: element
5997
6336
  }), jsxRuntime.jsx(Description$1, {
5998
6337
  forId: id,
5999
6338
  element: element,
@@ -6108,11 +6447,9 @@ function NumberFieldEntry(props) {
6108
6447
  onBlur,
6109
6448
  validate
6110
6449
  } = props;
6111
- const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
6112
6450
  const globalError = useError(id);
6113
6451
  const [localError, setLocalError] = hooks.useState(null);
6114
6452
  let value = getValue(element);
6115
- const previousValue = usePrevious(value);
6116
6453
  hooks.useEffect(() => {
6117
6454
  if (minDash.isFunction(validate)) {
6118
6455
  const newValidationError = validate(value) || null;
@@ -6124,16 +6461,9 @@ function NumberFieldEntry(props) {
6124
6461
  if (minDash.isFunction(validate)) {
6125
6462
  newValidationError = validate(newValue) || null;
6126
6463
  }
6127
- if (newValidationError) {
6128
- setCachedInvalidValue(newValue);
6129
- } else {
6130
- setValue(newValue);
6131
- }
6464
+ setValue(newValue, newValidationError);
6132
6465
  setLocalError(newValidationError);
6133
6466
  };
6134
- if (previousValue === value && localError) {
6135
- value = cachedInvalidValue;
6136
- }
6137
6467
  const error = globalError || localError;
6138
6468
  return jsxRuntime.jsxs("div", {
6139
6469
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
@@ -6182,7 +6512,8 @@ function FeelTextfield(props) {
6182
6512
  disabled = false,
6183
6513
  variables,
6184
6514
  tooltipContainer,
6185
- OptionalComponent = OptionalFeelInput
6515
+ OptionalComponent = OptionalFeelInput,
6516
+ tooltip
6186
6517
  } = props;
6187
6518
  const [localValue, _setLocalValue] = hooks.useState(value);
6188
6519
  const editorRef = useShowEntryEvent(id);
@@ -6298,7 +6629,12 @@ function FeelTextfield(props) {
6298
6629
  for: prefixId$4(id),
6299
6630
  class: "bio-properties-panel-label",
6300
6631
  onClick: () => setFocus(),
6301
- children: [label, jsxRuntime.jsx(FeelIcon, {
6632
+ children: [jsxRuntime.jsx(TooltipWrapper, {
6633
+ value: tooltip,
6634
+ forId: id,
6635
+ element: props.element,
6636
+ children: label
6637
+ }), jsxRuntime.jsx(FeelIcon, {
6302
6638
  label: label,
6303
6639
  feel: feel,
6304
6640
  onClick: handleFeelToggle,
@@ -6558,6 +6894,7 @@ React.forwardRef((props, ref) => {
6558
6894
  * @param {Function} props.variables
6559
6895
  * @param {Function} props.onFocus
6560
6896
  * @param {Function} props.onBlur
6897
+ * @param {string|import('preact').Component} props.tooltip
6561
6898
  */
6562
6899
  function FeelEntry(props) {
6563
6900
  const {
@@ -6578,13 +6915,12 @@ function FeelEntry(props) {
6578
6915
  example,
6579
6916
  variables,
6580
6917
  onFocus,
6581
- onBlur
6918
+ onBlur,
6919
+ tooltip
6582
6920
  } = props;
6583
- const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
6584
6921
  const [validationError, setValidationError] = hooks.useState(null);
6585
6922
  const [localError, setLocalError] = hooks.useState(null);
6586
6923
  let value = getValue(element);
6587
- const previousValue = usePrevious(value);
6588
6924
  hooks.useEffect(() => {
6589
6925
  if (minDash.isFunction(validate)) {
6590
6926
  const newValidationError = validate(value) || null;
@@ -6596,22 +6932,16 @@ function FeelEntry(props) {
6596
6932
  if (minDash.isFunction(validate)) {
6597
6933
  newValidationError = validate(newValue) || null;
6598
6934
  }
6599
- if (newValidationError) {
6600
- setCachedInvalidValue(newValue);
6601
- } else {
6602
- // don't create multiple commandStack entries for the same value
6603
- if (newValue !== value) {
6604
- setValue(newValue);
6605
- }
6935
+
6936
+ // don't create multiple commandStack entries for the same value
6937
+ if (newValue !== value) {
6938
+ setValue(newValue, newValidationError);
6606
6939
  }
6607
6940
  setValidationError(newValidationError);
6608
6941
  });
6609
6942
  const onError = hooks.useCallback(err => {
6610
6943
  setLocalError(err);
6611
6944
  }, []);
6612
- if (previousValue === value && validationError) {
6613
- value = cachedInvalidValue;
6614
- }
6615
6945
  const temporaryError = useError(id);
6616
6946
  const error = localError || temporaryError || validationError;
6617
6947
  return jsxRuntime.jsxs("div", {
@@ -6636,7 +6966,8 @@ function FeelEntry(props) {
6636
6966
  value: value,
6637
6967
  variables: variables,
6638
6968
  tooltipContainer: tooltipContainer,
6639
- OptionalComponent: props.OptionalComponent
6969
+ OptionalComponent: props.OptionalComponent,
6970
+ tooltip: tooltip
6640
6971
  }), error && jsxRuntime.jsx("div", {
6641
6972
  class: "bio-properties-panel-error",
6642
6973
  children: error
@@ -6757,7 +7088,8 @@ function Select(props) {
6757
7088
  value = '',
6758
7089
  disabled,
6759
7090
  onFocus,
6760
- onBlur
7091
+ onBlur,
7092
+ tooltip
6761
7093
  } = props;
6762
7094
  const ref = useShowEntryEvent(id);
6763
7095
  const [localValue, setLocalValue] = hooks.useState(value);
@@ -6781,7 +7113,12 @@ function Select(props) {
6781
7113
  children: [jsxRuntime.jsx("label", {
6782
7114
  for: prefixId$3(id),
6783
7115
  class: "bio-properties-panel-label",
6784
- children: label
7116
+ children: jsxRuntime.jsx(TooltipWrapper, {
7117
+ value: tooltip,
7118
+ forId: id,
7119
+ element: props.element,
7120
+ children: label
7121
+ })
6785
7122
  }), jsxRuntime.jsx("select", {
6786
7123
  ref: ref,
6787
7124
  id: prefixId$3(id),
@@ -6826,6 +7163,7 @@ function Select(props) {
6826
7163
  * @param {Function} props.getOptions
6827
7164
  * @param {boolean} [props.disabled]
6828
7165
  * @param {Function} [props.validate]
7166
+ * @param {string|import('preact').Component} props.tooltip
6829
7167
  */
6830
7168
  function SelectEntry(props) {
6831
7169
  const {
@@ -6839,14 +7177,13 @@ function SelectEntry(props) {
6839
7177
  disabled,
6840
7178
  onFocus,
6841
7179
  onBlur,
6842
- validate
7180
+ validate,
7181
+ tooltip
6843
7182
  } = props;
6844
7183
  const options = getOptions(element);
6845
- const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
6846
7184
  const globalError = useError(id);
6847
7185
  const [localError, setLocalError] = hooks.useState(null);
6848
7186
  let value = getValue(element);
6849
- const previousValue = usePrevious(value);
6850
7187
  hooks.useEffect(() => {
6851
7188
  if (minDash.isFunction(validate)) {
6852
7189
  const newValidationError = validate(value) || null;
@@ -6858,16 +7195,9 @@ function SelectEntry(props) {
6858
7195
  if (minDash.isFunction(validate)) {
6859
7196
  newValidationError = validate(newValue) || null;
6860
7197
  }
6861
- if (newValidationError) {
6862
- setCachedInvalidValue(newValue);
6863
- } else {
6864
- setValue(newValue);
6865
- }
7198
+ setValue(newValue, newValidationError);
6866
7199
  setLocalError(newValidationError);
6867
7200
  };
6868
- if (previousValue === value && localError) {
6869
- value = cachedInvalidValue;
6870
- }
6871
7201
  const error = globalError || localError;
6872
7202
  return jsxRuntime.jsxs("div", {
6873
7203
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
@@ -6880,7 +7210,9 @@ function SelectEntry(props) {
6880
7210
  onFocus: onFocus,
6881
7211
  onBlur: onBlur,
6882
7212
  options: options,
6883
- disabled: disabled
7213
+ disabled: disabled,
7214
+ tooltip: tooltip,
7215
+ element: element
6884
7216
  }, element), error && jsxRuntime.jsx("div", {
6885
7217
  class: "bio-properties-panel-error",
6886
7218
  children: error
@@ -6919,7 +7251,8 @@ function TextArea(props) {
6919
7251
  onFocus,
6920
7252
  onBlur,
6921
7253
  autoResize,
6922
- rows = autoResize ? 1 : 2
7254
+ rows = autoResize ? 1 : 2,
7255
+ tooltip
6923
7256
  } = props;
6924
7257
  const [localValue, setLocalValue] = hooks.useState(value);
6925
7258
  const ref = useShowEntryEvent(id);
@@ -6947,7 +7280,12 @@ function TextArea(props) {
6947
7280
  children: [jsxRuntime.jsx("label", {
6948
7281
  for: prefixId$1(id),
6949
7282
  class: "bio-properties-panel-label",
6950
- children: label
7283
+ children: jsxRuntime.jsx(TooltipWrapper, {
7284
+ value: tooltip,
7285
+ forId: id,
7286
+ element: props.element,
7287
+ children: label
7288
+ })
6951
7289
  }), jsxRuntime.jsx("textarea", {
6952
7290
  ref: ref,
6953
7291
  id: prefixId$1(id),
@@ -6996,13 +7334,12 @@ function TextAreaEntry(props) {
6996
7334
  validate,
6997
7335
  onFocus,
6998
7336
  onBlur,
6999
- autoResize
7337
+ autoResize,
7338
+ tooltip
7000
7339
  } = props;
7001
- const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
7002
7340
  const globalError = useError(id);
7003
7341
  const [localError, setLocalError] = hooks.useState(null);
7004
7342
  let value = getValue(element);
7005
- const previousValue = usePrevious(value);
7006
7343
  hooks.useEffect(() => {
7007
7344
  if (minDash.isFunction(validate)) {
7008
7345
  const newValidationError = validate(value) || null;
@@ -7014,16 +7351,9 @@ function TextAreaEntry(props) {
7014
7351
  if (minDash.isFunction(validate)) {
7015
7352
  newValidationError = validate(newValue) || null;
7016
7353
  }
7017
- if (newValidationError) {
7018
- setCachedInvalidValue(newValue);
7019
- } else {
7020
- setValue(newValue);
7021
- }
7354
+ setValue(newValue, newValidationError);
7022
7355
  setLocalError(newValidationError);
7023
7356
  };
7024
- if (previousValue === value && localError) {
7025
- value = cachedInvalidValue;
7026
- }
7027
7357
  const error = globalError || localError;
7028
7358
  return jsxRuntime.jsxs("div", {
7029
7359
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
@@ -7039,7 +7369,9 @@ function TextAreaEntry(props) {
7039
7369
  debounce: debounce,
7040
7370
  monospace: monospace,
7041
7371
  disabled: disabled,
7042
- autoResize: autoResize
7372
+ autoResize: autoResize,
7373
+ tooltip: tooltip,
7374
+ element: element
7043
7375
  }, element), error && jsxRuntime.jsx("div", {
7044
7376
  class: "bio-properties-panel-error",
7045
7377
  children: error
@@ -7068,7 +7400,8 @@ function Textfield(props) {
7068
7400
  onInput,
7069
7401
  onFocus,
7070
7402
  onBlur,
7071
- value = ''
7403
+ value = '',
7404
+ tooltip
7072
7405
  } = props;
7073
7406
  const [localValue, setLocalValue] = hooks.useState(value || '');
7074
7407
  const ref = useShowEntryEvent(id);
@@ -7092,7 +7425,12 @@ function Textfield(props) {
7092
7425
  children: [jsxRuntime.jsx("label", {
7093
7426
  for: prefixId(id),
7094
7427
  class: "bio-properties-panel-label",
7095
- children: label
7428
+ children: jsxRuntime.jsx(TooltipWrapper, {
7429
+ value: tooltip,
7430
+ forId: id,
7431
+ element: props.element,
7432
+ children: label
7433
+ })
7096
7434
  }), jsxRuntime.jsx("input", {
7097
7435
  ref: ref,
7098
7436
  id: prefixId(id),
@@ -7122,6 +7460,7 @@ function Textfield(props) {
7122
7460
  * @param {Function} props.setValue
7123
7461
  * @param {Function} props.onFocus
7124
7462
  * @param {Function} props.onBlur
7463
+ * @param {string|import('preact').Component} props.tooltip
7125
7464
  * @param {Function} props.validate
7126
7465
  */
7127
7466
  function TextfieldEntry(props) {
@@ -7136,13 +7475,12 @@ function TextfieldEntry(props) {
7136
7475
  setValue,
7137
7476
  validate,
7138
7477
  onFocus,
7139
- onBlur
7478
+ onBlur,
7479
+ tooltip
7140
7480
  } = props;
7141
- const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
7142
7481
  const globalError = useError(id);
7143
7482
  const [localError, setLocalError] = hooks.useState(null);
7144
7483
  let value = getValue(element);
7145
- const previousValue = usePrevious(value);
7146
7484
  hooks.useEffect(() => {
7147
7485
  if (minDash.isFunction(validate)) {
7148
7486
  const newValidationError = validate(value) || null;
@@ -7154,16 +7492,9 @@ function TextfieldEntry(props) {
7154
7492
  if (minDash.isFunction(validate)) {
7155
7493
  newValidationError = validate(newValue) || null;
7156
7494
  }
7157
- if (newValidationError) {
7158
- setCachedInvalidValue(newValue);
7159
- } else {
7160
- setValue(newValue);
7161
- }
7495
+ setValue(newValue, newValidationError);
7162
7496
  setLocalError(newValidationError);
7163
7497
  };
7164
- if (previousValue === value && localError) {
7165
- value = cachedInvalidValue;
7166
- }
7167
7498
  const error = globalError || localError;
7168
7499
  return jsxRuntime.jsxs("div", {
7169
7500
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
@@ -7176,7 +7507,9 @@ function TextfieldEntry(props) {
7176
7507
  onInput: onInput,
7177
7508
  onFocus: onFocus,
7178
7509
  onBlur: onBlur,
7179
- value: value
7510
+ value: value,
7511
+ tooltip: tooltip,
7512
+ element: element
7180
7513
  }, element), error && jsxRuntime.jsx("div", {
7181
7514
  class: "bio-properties-panel-error",
7182
7515
  children: error
@@ -7197,11 +7530,11 @@ function prefixId(id) {
7197
7530
  return `bio-properties-panel-${id}`;
7198
7531
  }
7199
7532
 
7200
- /**
7201
- * @param {string} type
7202
- * @param {boolean} [strict]
7203
- *
7204
- * @returns {any}
7533
+ /**
7534
+ * @param {string} type
7535
+ * @param {boolean} [strict]
7536
+ *
7537
+ * @returns {any}
7205
7538
  */
7206
7539
  function getService(type, strict) {}
7207
7540
  const PropertiesPanelContext = preact.createContext({
@@ -7248,6 +7581,7 @@ const labelsByType = {
7248
7581
  number: 'NUMBER',
7249
7582
  radio: 'RADIO',
7250
7583
  select: 'SELECT',
7584
+ spacer: 'SPACER',
7251
7585
  taglist: 'TAGLIST',
7252
7586
  text: 'TEXT VIEW',
7253
7587
  textfield: 'TEXT FIELD',
@@ -7290,8 +7624,8 @@ const PropertiesPanelHeaderProvider = {
7290
7624
  }
7291
7625
  };
7292
7626
 
7293
- /**
7294
- * Provide placeholders for empty and multiple state.
7627
+ /**
7628
+ * Provide placeholders for empty and multiple state.
7295
7629
  */
7296
7630
  const PropertiesPanelPlaceholderProvider = {
7297
7631
  getEmpty: () => {
@@ -7363,10 +7697,10 @@ function useService (type, strict) {
7363
7697
  return getService(type, strict);
7364
7698
  }
7365
7699
 
7366
- /**
7367
- * Retrieve list of variables from the form schema.
7368
- *
7369
- * @returns { string[] } list of variables used in form schema
7700
+ /**
7701
+ * Retrieve list of variables from the form schema.
7702
+ *
7703
+ * @returns { string[] } list of variables used in form schema
7370
7704
  */
7371
7705
  function useVariables() {
7372
7706
  const form = useService('formEditor');
@@ -7418,6 +7752,7 @@ function AltText(props) {
7418
7752
  getValue,
7419
7753
  id,
7420
7754
  label: 'Alternative text',
7755
+ tooltip: 'Descriptive text for screen reader accessibility.',
7421
7756
  setValue,
7422
7757
  singleLine: true,
7423
7758
  variables
@@ -7450,7 +7785,10 @@ function Columns(props) {
7450
7785
  const validate = value => {
7451
7786
  return formLayoutValidator.validateField(field, value ? parseInt(value) : null);
7452
7787
  };
7453
- const setValue = value => {
7788
+ const setValue = (value, error) => {
7789
+ if (error) {
7790
+ return;
7791
+ }
7454
7792
  const layout = minDash.get(field, ['layout'], {});
7455
7793
  const newValue = value ? parseInt(value) : null;
7456
7794
  editField(field, ['layout'], minDash.set(layout, ['columns'], newValue));
@@ -7658,7 +7996,10 @@ function DefaultValueNumber(props) {
7658
7996
  // Enforces decimal notation so that we do not submit defaults in exponent form
7659
7997
  return serializeToString ? Big(value).toFixed() : value;
7660
7998
  };
7661
- const setValue = value => {
7999
+ const setValue = (value, error) => {
8000
+ if (error) {
8001
+ return;
8002
+ }
7662
8003
  let newValue;
7663
8004
  if (isValidNumber(value)) {
7664
8005
  newValue = serializeToString ? value : Number(value);
@@ -7815,6 +8156,7 @@ function Disabled(props) {
7815
8156
  getValue,
7816
8157
  id,
7817
8158
  label: 'Disabled',
8159
+ tooltip: 'Field cannot be edited by the end-user, and the data is not submitted.',
7818
8160
  inline: true,
7819
8161
  setValue
7820
8162
  });
@@ -7849,7 +8191,10 @@ function Id(props) {
7849
8191
  const getValue = () => {
7850
8192
  return minDash.get(field, path, '');
7851
8193
  };
7852
- const setValue = value => {
8194
+ const setValue = (value, error) => {
8195
+ if (error) {
8196
+ return;
8197
+ }
7853
8198
  return editField(field, path, value);
7854
8199
  };
7855
8200
  const validate = value => {
@@ -7929,7 +8274,10 @@ function Key$1(props) {
7929
8274
  const getValue = () => {
7930
8275
  return minDash.get(field, path, '');
7931
8276
  };
7932
- const setValue = value => {
8277
+ const setValue = (value, error) => {
8278
+ if (error) {
8279
+ return;
8280
+ }
7933
8281
  return editField(field, path, value);
7934
8282
  };
7935
8283
  const validate = value => {
@@ -7952,6 +8300,7 @@ function Key$1(props) {
7952
8300
  getValue,
7953
8301
  id,
7954
8302
  label: 'Key',
8303
+ tooltip: 'Use a unique "key" to link the form element and the related input/output data. When dealing with nested data, break it down in the user task\'s input mapping before using it.',
7955
8304
  setValue,
7956
8305
  validate
7957
8306
  });
@@ -8012,7 +8361,7 @@ function Label$1(props) {
8012
8361
  return minDash.get(field, path, '');
8013
8362
  };
8014
8363
  const setValue = value => {
8015
- return editField(field, path, value);
8364
+ return editField(field, path, value || '');
8016
8365
  };
8017
8366
  return FeelTemplatingEntry({
8018
8367
  debounce,
@@ -8040,7 +8389,7 @@ function DateLabel(props) {
8040
8389
  return minDash.get(field, path, '');
8041
8390
  };
8042
8391
  const setValue = value => {
8043
- return editField(field, path, value);
8392
+ return editField(field, path, value || '');
8044
8393
  };
8045
8394
  return FeelTemplatingEntry({
8046
8395
  debounce,
@@ -8068,7 +8417,7 @@ function TimeLabel(props) {
8068
8417
  return minDash.get(field, path, '');
8069
8418
  };
8070
8419
  const setValue = value => {
8071
- return editField(field, path, value);
8420
+ return editField(field, path, value || '');
8072
8421
  };
8073
8422
  return FeelTemplatingEntry({
8074
8423
  debounce,
@@ -8127,6 +8476,7 @@ function Source(props) {
8127
8476
  getValue,
8128
8477
  id,
8129
8478
  label: 'Image source',
8479
+ tooltip: 'Link referring to a hosted image, or use a data URI directly to embed image data into the form.',
8130
8480
  setValue,
8131
8481
  singleLine: true,
8132
8482
  variables
@@ -8184,7 +8534,7 @@ function Text(props) {
8184
8534
  return minDash.get(field, path, '');
8185
8535
  };
8186
8536
  const setValue = value => {
8187
- return editField(field, path, value);
8537
+ return editField(field, path, value || '');
8188
8538
  };
8189
8539
  const description = hooks.useMemo(() => jsxRuntime.jsxs(jsxRuntime.Fragment, {
8190
8540
  children: ["Supports markdown and templating. ", jsxRuntime.jsx("a", {
@@ -8206,6 +8556,57 @@ function Text(props) {
8206
8556
  });
8207
8557
  }
8208
8558
 
8559
+ function SpacerEntry(props) {
8560
+ const {
8561
+ editField,
8562
+ field,
8563
+ id
8564
+ } = props;
8565
+ const {
8566
+ type
8567
+ } = field;
8568
+ if (type !== 'spacer') {
8569
+ return [];
8570
+ }
8571
+ const entries = [];
8572
+ entries.push({
8573
+ id: id + '-height',
8574
+ component: SpacerHeight,
8575
+ isEdited: isEdited$6,
8576
+ editField,
8577
+ field
8578
+ });
8579
+ return entries;
8580
+ }
8581
+ function SpacerHeight(props) {
8582
+ const {
8583
+ editField,
8584
+ field,
8585
+ id
8586
+ } = props;
8587
+ const debounce = useService('debounce');
8588
+ const getValue = e => minDash.get(field, ['height']);
8589
+ const setValue = (value, error) => {
8590
+ if (error) {
8591
+ return;
8592
+ }
8593
+ editField(field, ['height'], value);
8594
+ };
8595
+ return NumberFieldEntry({
8596
+ debounce,
8597
+ label: 'Height',
8598
+ element: field,
8599
+ id,
8600
+ getValue,
8601
+ setValue,
8602
+ validate: value => {
8603
+ if (value === undefined || value === null) return;
8604
+ if (value < 1) return 'Should be greater than zero.';
8605
+ if (!Number.isInteger(value)) return 'Should be an integer.';
8606
+ }
8607
+ });
8608
+ }
8609
+
8209
8610
  function NumberEntries(props) {
8210
8611
  const {
8211
8612
  editField,
@@ -8243,7 +8644,12 @@ function NumberDecimalDigits(props) {
8243
8644
  } = props;
8244
8645
  const debounce = useService('debounce');
8245
8646
  const getValue = e => minDash.get(field, ['decimalDigits']);
8246
- const setValue = value => editField(field, ['decimalDigits'], value);
8647
+ const setValue = (value, error) => {
8648
+ if (error) {
8649
+ return;
8650
+ }
8651
+ editField(field, ['decimalDigits'], value);
8652
+ };
8247
8653
  return NumberFieldEntry({
8248
8654
  debounce,
8249
8655
  label: 'Decimal digits',
@@ -8279,7 +8685,12 @@ function NumberArrowStep(props) {
8279
8685
  const trimmed = value.replace(/^0+/g, '');
8280
8686
  return (trimmed.startsWith('.') ? '0' : '') + trimmed;
8281
8687
  };
8282
- const setValue = value => editField(field, ['increment'], clearLeadingZeroes(value));
8688
+ const setValue = (value, error) => {
8689
+ if (error) {
8690
+ return;
8691
+ }
8692
+ editField(field, ['increment'], clearLeadingZeroes(value));
8693
+ };
8283
8694
  const decimalDigitsSet = decimalDigits || decimalDigits === 0;
8284
8695
  return TextfieldEntry({
8285
8696
  debounce,
@@ -8688,7 +9099,10 @@ function Label(props) {
8688
9099
  validateFactory
8689
9100
  } = props;
8690
9101
  const debounce = useService('debounce');
8691
- const setValue = value => {
9102
+ const setValue = (value, error) => {
9103
+ if (error) {
9104
+ return;
9105
+ }
8692
9106
  const values = minDash.get(field, ['values']);
8693
9107
  return editField(field, 'values', minDash.set(values, [index, 'label'], value));
8694
9108
  };
@@ -8714,7 +9128,10 @@ function Value$1(props) {
8714
9128
  validateFactory
8715
9129
  } = props;
8716
9130
  const debounce = useService('debounce');
8717
- const setValue = value => {
9131
+ const setValue = (value, error) => {
9132
+ if (error) {
9133
+ return;
9134
+ }
8718
9135
  const values = minDash.get(field, ['values']);
8719
9136
  return editField(field, 'values', minDash.set(values, [index, 'value'], value));
8720
9137
  };
@@ -8768,7 +9185,10 @@ function Key(props) {
8768
9185
  validateFactory
8769
9186
  } = props;
8770
9187
  const debounce = useService('debounce');
8771
- const setValue = value => {
9188
+ const setValue = (value, error) => {
9189
+ if (error) {
9190
+ return;
9191
+ }
8772
9192
  const properties = minDash.get(field, ['properties']);
8773
9193
  const key = Object.keys(properties)[index];
8774
9194
  return editField(field, 'properties', updateKey(properties, key, value));
@@ -8818,14 +9238,14 @@ function Value(props) {
8818
9238
 
8819
9239
  // helpers //////////
8820
9240
 
8821
- /**
8822
- * Returns copy of object with updated value.
8823
- *
8824
- * @param {Object} properties
8825
- * @param {string} key
8826
- * @param {string} value
8827
- *
8828
- * @returns {Object}
9241
+ /**
9242
+ * Returns copy of object with updated value.
9243
+ *
9244
+ * @param {Object} properties
9245
+ * @param {string} key
9246
+ * @param {string} value
9247
+ *
9248
+ * @returns {Object}
8829
9249
  */
8830
9250
  function updateValue(properties, key, value) {
8831
9251
  return {
@@ -8834,14 +9254,14 @@ function updateValue(properties, key, value) {
8834
9254
  };
8835
9255
  }
8836
9256
 
8837
- /**
8838
- * Returns copy of object with updated key.
8839
- *
8840
- * @param {Object} properties
8841
- * @param {string} oldKey
8842
- * @param {string} newKey
8843
- *
8844
- * @returns {Object}
9257
+ /**
9258
+ * Returns copy of object with updated key.
9259
+ *
9260
+ * @param {Object} properties
9261
+ * @param {string} oldKey
9262
+ * @param {string} newKey
9263
+ *
9264
+ * @returns {Object}
8845
9265
  */
8846
9266
  function updateKey(properties, oldKey, newKey) {
8847
9267
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -8979,7 +9399,12 @@ function InputValuesKey(props) {
8979
9399
  const debounce = useService('debounce');
8980
9400
  const path = formJsViewer.VALUES_SOURCES_PATHS[formJsViewer.VALUES_SOURCES.INPUT];
8981
9401
  const getValue = () => minDash.get(field, path, '');
8982
- const setValue = value => editField(field, path, value || '');
9402
+ const setValue = (value, error) => {
9403
+ if (error) {
9404
+ return;
9405
+ }
9406
+ editField(field, path, value || '');
9407
+ };
8983
9408
  const validate = value => {
8984
9409
  if (minDash.isUndefined(value) || !value.length) {
8985
9410
  return 'Must not be empty.';
@@ -9208,6 +9633,7 @@ function Readonly(props) {
9208
9633
  getValue,
9209
9634
  id,
9210
9635
  label: 'Read only',
9636
+ tooltip: 'Field cannot be edited by the end-user, but the data will still be submitted.',
9211
9637
  setValue,
9212
9638
  variables
9213
9639
  });
@@ -9336,6 +9762,9 @@ function GeneralGroup(field, editField, getService) {
9336
9762
  field,
9337
9763
  editField,
9338
9764
  getService
9765
+ }), ...SpacerEntry({
9766
+ field,
9767
+ editField
9339
9768
  }), ...NumberEntries({
9340
9769
  field,
9341
9770
  editField
@@ -9658,12 +10087,13 @@ function ValuesGroups(field, editField) {
9658
10087
  };
9659
10088
  const valuesSourceId = `${fieldId}-valuesSource`;
9660
10089
 
9661
- /**
9662
- * @type {Array<Group|ListGroup>}
10090
+ /**
10091
+ * @type {Array<Group|ListGroup>}
9663
10092
  */
9664
10093
  const groups = [{
9665
10094
  id: valuesSourceId,
9666
10095
  label: 'Options source',
10096
+ tooltip: '"Static" defines a constant, predefined set of form options.\n"Dynamic" defines options that are populated dynamically, adjusting based on variable data for flexible responses to different conditions or inputs.',
9667
10097
  component: Group,
9668
10098
  entries: ValuesSourceSelectEntry({
9669
10099
  ...context,
@@ -9708,7 +10138,7 @@ function ValuesGroups(field, editField) {
9708
10138
  return groups;
9709
10139
  }
9710
10140
 
9711
- function CustomValuesGroup(field, editField) {
10141
+ function CustomPropertiesGroup(field, editField) {
9712
10142
  const {
9713
10143
  properties = {},
9714
10144
  type
@@ -9766,19 +10196,20 @@ function CustomValuesGroup(field, editField) {
9766
10196
  id: 'custom-values',
9767
10197
  items,
9768
10198
  label: 'Custom properties',
10199
+ tooltip: 'Add properties directly to the form schema, useful to configure functionality in custom-built task applications and form renderers.',
9769
10200
  shouldSort: false
9770
10201
  };
9771
10202
  }
9772
10203
 
9773
10204
  // helpers //////////
9774
10205
 
9775
- /**
9776
- * Returns copy of object without key.
9777
- *
9778
- * @param {Object} properties
9779
- * @param {string} oldKey
9780
- *
9781
- * @returns {Object}
10206
+ /**
10207
+ * Returns copy of object without key.
10208
+ *
10209
+ * @param {Object} properties
10210
+ * @param {string} oldKey
10211
+ *
10212
+ * @returns {Object}
9782
10213
  */
9783
10214
  function removeKey(properties, oldKey) {
9784
10215
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -9851,7 +10282,7 @@ function getGroups(field, editField, getService) {
9851
10282
  if (!field) {
9852
10283
  return [];
9853
10284
  }
9854
- const groups = [GeneralGroup(field, editField, getService), ConditionGroup(field, editField), LayoutGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ...ValuesGroups(field, editField), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomValuesGroup(field, editField)];
10285
+ const groups = [GeneralGroup(field, editField, getService), ConditionGroup(field, editField), LayoutGroup(field, editField), AppearanceGroup(field, editField), SerializationGroup(field, editField), ...ValuesGroups(field, editField), ConstraintsGroup(field, editField), ValidationGroup(field, editField), CustomPropertiesGroup(field, editField)];
9855
10286
 
9856
10287
  // contract: if a group returns null, it should not be displayed at all
9857
10288
  return groups.filter(group => group !== null);
@@ -9881,9 +10312,9 @@ function FormPropertiesPanel(props) {
9881
10312
  });
9882
10313
  }, [eventBus, formEditor, selectionModule]);
9883
10314
  hooks.useLayoutEffect(() => {
9884
- /**
9885
- * TODO(pinussilvestrus): update with actual updated element,
9886
- * once we have a proper updater/change support
10315
+ /**
10316
+ * TODO(pinussilvestrus): update with actual updated element,
10317
+ * once we have a proper updater/change support
9887
10318
  */
9888
10319
  eventBus.on('changed', refresh);
9889
10320
  eventBus.on('import.done', refresh);
@@ -9935,10 +10366,10 @@ class PropertiesPanelRenderer {
9935
10366
  });
9936
10367
  }
9937
10368
 
9938
- /**
9939
- * Attach the properties panel to a parent node.
9940
- *
9941
- * @param {HTMLElement} container
10369
+ /**
10370
+ * Attach the properties panel to a parent node.
10371
+ *
10372
+ * @param {HTMLElement} container
9942
10373
  */
9943
10374
  attachTo(container) {
9944
10375
  if (!container) {
@@ -9958,8 +10389,8 @@ class PropertiesPanelRenderer {
9958
10389
  this._eventBus.fire('propertiesPanel.attach');
9959
10390
  }
9960
10391
 
9961
- /**
9962
- * Detach the properties panel from its parent node.
10392
+ /**
10393
+ * Detach the properties panel from its parent node.
9963
10394
  */
9964
10395
  detach() {
9965
10396
  const parentNode = this._container.parentNode;
@@ -9989,10 +10420,10 @@ var PropertiesPanelModule = {
9989
10420
  propertiesPanel: ['type', PropertiesPanelRenderer]
9990
10421
  };
9991
10422
 
9992
- /**
9993
- * Manages the rendering of visual plugins.
9994
- * @constructor
9995
- * @param {Object} eventBus - Event bus for the application.
10423
+ /**
10424
+ * Manages the rendering of visual plugins.
10425
+ * @constructor
10426
+ * @param {Object} eventBus - Event bus for the application.
9996
10427
  */
9997
10428
  class RenderInjector extends SectionModuleBase {
9998
10429
  constructor(eventBus) {
@@ -10001,10 +10432,10 @@ class RenderInjector extends SectionModuleBase {
10001
10432
  this.registeredRenderers = [];
10002
10433
  }
10003
10434
 
10004
- /**
10005
- * Inject a new renderer into the injector.
10006
- * @param {string} identifier - Identifier for the renderer.
10007
- * @param {Function} Renderer - The renderer function.
10435
+ /**
10436
+ * Inject a new renderer into the injector.
10437
+ * @param {string} identifier - Identifier for the renderer.
10438
+ * @param {Function} Renderer - The renderer function.
10008
10439
  */
10009
10440
  attachRenderer(identifier, Renderer) {
10010
10441
  this.registeredRenderers = [...this.registeredRenderers, {
@@ -10013,17 +10444,17 @@ class RenderInjector extends SectionModuleBase {
10013
10444
  }];
10014
10445
  }
10015
10446
 
10016
- /**
10017
- * Detach a renderer from the by key injector.
10018
- * @param {string} identifier - Identifier for the renderer.
10447
+ /**
10448
+ * Detach a renderer from the by key injector.
10449
+ * @param {string} identifier - Identifier for the renderer.
10019
10450
  */
10020
10451
  detachRenderer(identifier) {
10021
10452
  this.registeredRenderers = this.registeredRenderers.filter(r => r.identifier !== identifier);
10022
10453
  }
10023
10454
 
10024
- /**
10025
- * Returns the registered renderers.
10026
- * @returns {Array} Array of registered renderers.
10455
+ /**
10456
+ * Returns the registered renderers.
10457
+ * @returns {Array} Array of registered renderers.
10027
10458
  */
10028
10459
  fetchRenderers() {
10029
10460
  return this.registeredRenderers;
@@ -10057,48 +10488,48 @@ var ExpressionLanguageModule = {
10057
10488
 
10058
10489
  const ids = new Ids([32, 36, 1]);
10059
10490
 
10060
- /**
10061
- * @typedef { import('./types').Injector } Injector
10062
- * @typedef { import('./types').Module } Module
10063
- * @typedef { import('./types').Schema } Schema
10064
- *
10065
- * @typedef { import('./types').FormEditorOptions } FormEditorOptions
10066
- * @typedef { import('./types').FormEditorProperties } FormEditorProperties
10067
- *
10068
- * @typedef { {
10069
- * properties: FormEditorProperties,
10070
- * schema: Schema
10071
- * } } State
10072
- *
10073
- * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
10074
- * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
10075
- * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
10491
+ /**
10492
+ * @typedef { import('./types').Injector } Injector
10493
+ * @typedef { import('./types').Module } Module
10494
+ * @typedef { import('./types').Schema } Schema
10495
+ *
10496
+ * @typedef { import('./types').FormEditorOptions } FormEditorOptions
10497
+ * @typedef { import('./types').FormEditorProperties } FormEditorProperties
10498
+ *
10499
+ * @typedef { {
10500
+ * properties: FormEditorProperties,
10501
+ * schema: Schema
10502
+ * } } State
10503
+ *
10504
+ * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
10505
+ * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
10506
+ * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
10076
10507
  */
10077
10508
 
10078
- /**
10079
- * The form editor.
10509
+ /**
10510
+ * The form editor.
10080
10511
  */
10081
10512
  class FormEditor {
10082
- /**
10083
- * @constructor
10084
- * @param {FormEditorOptions} options
10513
+ /**
10514
+ * @constructor
10515
+ * @param {FormEditorOptions} options
10085
10516
  */
10086
10517
  constructor(options = {}) {
10087
- /**
10088
- * @public
10089
- * @type {OnEventType}
10518
+ /**
10519
+ * @public
10520
+ * @type {OnEventType}
10090
10521
  */
10091
10522
  this.on = this._onEvent;
10092
10523
 
10093
- /**
10094
- * @public
10095
- * @type {String}
10524
+ /**
10525
+ * @public
10526
+ * @type {String}
10096
10527
  */
10097
10528
  this._id = ids.next();
10098
10529
 
10099
- /**
10100
- * @private
10101
- * @type {Element}
10530
+ /**
10531
+ * @private
10532
+ * @type {Element}
10102
10533
  */
10103
10534
  this._container = formJsViewer.createFormContainer();
10104
10535
  this._container.setAttribute('input-handle-modified-keys', 'z,y');
@@ -10109,15 +10540,15 @@ class FormEditor {
10109
10540
  properties = {}
10110
10541
  } = options;
10111
10542
 
10112
- /**
10113
- * @private
10114
- * @type {any}
10543
+ /**
10544
+ * @private
10545
+ * @type {any}
10115
10546
  */
10116
10547
  this.exporter = exporter;
10117
10548
 
10118
- /**
10119
- * @private
10120
- * @type {State}
10549
+ /**
10550
+ * @private
10551
+ * @type {State}
10121
10552
  */
10122
10553
  this._state = {
10123
10554
  properties,
@@ -10146,10 +10577,10 @@ class FormEditor {
10146
10577
  this._detach(false);
10147
10578
  }
10148
10579
 
10149
- /**
10150
- * @param {Schema} schema
10151
- *
10152
- * @return {Promise<{ warnings: Array<any> }>}
10580
+ /**
10581
+ * @param {Schema} schema
10582
+ *
10583
+ * @return {Promise<{ warnings: Array<any> }>}
10153
10584
  */
10154
10585
  importSchema(schema) {
10155
10586
  return new Promise((resolve, reject) => {
@@ -10178,15 +10609,15 @@ class FormEditor {
10178
10609
  });
10179
10610
  }
10180
10611
 
10181
- /**
10182
- * @returns {Schema}
10612
+ /**
10613
+ * @returns {Schema}
10183
10614
  */
10184
10615
  saveSchema() {
10185
10616
  return this.getSchema();
10186
10617
  }
10187
10618
 
10188
- /**
10189
- * @returns {Schema}
10619
+ /**
10620
+ * @returns {Schema}
10190
10621
  */
10191
10622
  getSchema() {
10192
10623
  const {
@@ -10195,8 +10626,8 @@ class FormEditor {
10195
10626
  return exportSchema(schema, this.exporter, formJsViewer.schemaVersion);
10196
10627
  }
10197
10628
 
10198
- /**
10199
- * @param {Element|string} parentNode
10629
+ /**
10630
+ * @param {Element|string} parentNode
10200
10631
  */
10201
10632
  attachTo(parentNode) {
10202
10633
  if (!parentNode) {
@@ -10214,10 +10645,10 @@ class FormEditor {
10214
10645
  this._detach();
10215
10646
  }
10216
10647
 
10217
- /**
10218
- * @internal
10219
- *
10220
- * @param {boolean} [emit]
10648
+ /**
10649
+ * @internal
10650
+ *
10651
+ * @param {boolean} [emit]
10221
10652
  */
10222
10653
  _detach(emit = true) {
10223
10654
  const container = this._container,
@@ -10231,9 +10662,9 @@ class FormEditor {
10231
10662
  parentNode.removeChild(container);
10232
10663
  }
10233
10664
 
10234
- /**
10235
- * @param {any} property
10236
- * @param {any} value
10665
+ /**
10666
+ * @param {any} property
10667
+ * @param {any} value
10237
10668
  */
10238
10669
  setProperty(property, value) {
10239
10670
  const properties = minDash.set(this._getState().properties, [property], value);
@@ -10242,21 +10673,21 @@ class FormEditor {
10242
10673
  });
10243
10674
  }
10244
10675
 
10245
- /**
10246
- * @param {string} type
10247
- * @param {Function} handler
10676
+ /**
10677
+ * @param {string} type
10678
+ * @param {Function} handler
10248
10679
  */
10249
10680
  off(type, handler) {
10250
10681
  this.get('eventBus').off(type, handler);
10251
10682
  }
10252
10683
 
10253
- /**
10254
- * @internal
10255
- *
10256
- * @param {FormEditorOptions} options
10257
- * @param {Element} container
10258
- *
10259
- * @returns {Injector}
10684
+ /**
10685
+ * @internal
10686
+ *
10687
+ * @param {FormEditorOptions} options
10688
+ * @param {Element} container
10689
+ *
10690
+ * @returns {Injector}
10260
10691
  */
10261
10692
  _createInjector(options, container) {
10262
10693
  const {
@@ -10278,22 +10709,22 @@ class FormEditor {
10278
10709
  }, core, ...modules, ...additionalModules]);
10279
10710
  }
10280
10711
 
10281
- /**
10282
- * @internal
10712
+ /**
10713
+ * @internal
10283
10714
  */
10284
10715
  _emit(type, data) {
10285
10716
  this.get('eventBus').fire(type, data);
10286
10717
  }
10287
10718
 
10288
- /**
10289
- * @internal
10719
+ /**
10720
+ * @internal
10290
10721
  */
10291
10722
  _getState() {
10292
10723
  return this._state;
10293
10724
  }
10294
10725
 
10295
- /**
10296
- * @internal
10726
+ /**
10727
+ * @internal
10297
10728
  */
10298
10729
  _setState(state) {
10299
10730
  this._state = {
@@ -10303,15 +10734,15 @@ class FormEditor {
10303
10734
  this._emit('changed', this._getState());
10304
10735
  }
10305
10736
 
10306
- /**
10307
- * @internal
10737
+ /**
10738
+ * @internal
10308
10739
  */
10309
10740
  _getModules() {
10310
10741
  return [ModelingModule, EditorActionsModule, DraggingModule, KeyboardModule, SelectionModule, PaletteModule, ExpressionLanguageModule, formJsViewer.MarkdownModule, PropertiesPanelModule, RenderInjectionModule];
10311
10742
  }
10312
10743
 
10313
- /**
10314
- * @internal
10744
+ /**
10745
+ * @internal
10315
10746
  */
10316
10747
  _onEvent(type, priority, handler) {
10317
10748
  this.get('eventBus').on(type, priority, handler);