@bpmn-io/form-js-editor 0.14.1 → 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (36) hide show
  1. package/dist/assets/form-js-editor-base.css +266 -37
  2. package/dist/assets/form-js-editor.css +318 -53
  3. package/dist/index.cjs +1241 -418
  4. package/dist/index.cjs.map +1 -1
  5. package/dist/index.es.js +1113 -290
  6. package/dist/index.es.js.map +1 -1
  7. package/dist/types/FormEditor.d.ts +9 -4
  8. package/dist/types/core/EventBus.d.ts +1 -1
  9. package/dist/types/core/FormLayoutValidator.d.ts +5 -1
  10. package/dist/types/core/index.d.ts +2 -1
  11. package/dist/types/features/dragging/Dragging.d.ts +3 -3
  12. package/dist/types/features/editor-actions/FormEditorActions.d.ts +2 -1
  13. package/dist/types/features/editor-actions/index.d.ts +1 -1
  14. package/dist/types/features/keyboard/index.d.ts +1 -1
  15. package/dist/types/features/modeling/FormLayoutUpdater.d.ts +2 -1
  16. package/dist/types/features/modeling/behavior/IdBehavior.d.ts +2 -1
  17. package/dist/types/features/modeling/behavior/KeyBehavior.d.ts +2 -1
  18. package/dist/types/features/modeling/behavior/ValidateBehavior.d.ts +2 -1
  19. package/dist/types/features/modeling/index.d.ts +6 -1
  20. package/dist/types/features/palette/PaletteRenderer.d.ts +1 -1
  21. package/dist/types/features/palette/components/Palette.d.ts +1 -1
  22. package/dist/types/features/properties-panel/PropertiesPanel.d.ts +1 -1
  23. package/dist/types/features/properties-panel/PropertiesPanelHeaderProvider.d.ts +1 -1
  24. package/dist/types/features/properties-panel/PropertiesPanelRenderer.d.ts +1 -1
  25. package/dist/types/features/properties-panel/entries/InputKeyValuesSourceEntry.d.ts +1 -1
  26. package/dist/types/features/properties-panel/entries/ReadonlyEntry.d.ts +9 -0
  27. package/dist/types/features/properties-panel/entries/index.d.ts +1 -0
  28. package/dist/types/render/Renderer.d.ts +1 -1
  29. package/dist/types/render/components/FieldDragPreview.d.ts +1 -1
  30. package/dist/types/render/components/FieldResizer.d.ts +1 -0
  31. package/dist/types/render/components/FormEditor.d.ts +1 -1
  32. package/dist/types/render/components/Util.d.ts +27 -1
  33. package/dist/types/render/components/editor-form-fields/EditorText.d.ts +2 -4
  34. package/dist/types/render/components/icons/index.d.ts +1 -1
  35. package/package.json +4 -4
  36. package/dist/types/features/properties-panel/icons/index.d.ts +0 -1
package/dist/index.cjs CHANGED
@@ -5,7 +5,7 @@ var Ids = require('ids');
5
5
  var minDash = require('min-dash');
6
6
  var classnames = require('classnames');
7
7
  var jsxRuntime = require('preact/jsx-runtime');
8
- var hooks$1 = require('preact/hooks');
8
+ var hooks = require('preact/hooks');
9
9
  var preact = require('preact');
10
10
  var React = require('preact/compat');
11
11
  var dragula = require('dragula');
@@ -19,6 +19,30 @@ var FN_REF = '__fn';
19
19
  var DEFAULT_PRIORITY$2 = 1000;
20
20
  var slice = Array.prototype.slice;
21
21
 
22
+ /**
23
+ * @typedef { {
24
+ * stopPropagation(): void;
25
+ * preventDefault(): void;
26
+ * cancelBubble: boolean;
27
+ * defaultPrevented: boolean;
28
+ * returnValue: any;
29
+ * } } Event
30
+ */
31
+
32
+ /**
33
+ * @template E
34
+ *
35
+ * @typedef { (event: E & Event, ...any) => any } EventBusEventCallback
36
+ */
37
+
38
+ /**
39
+ * @typedef { {
40
+ * priority: number;
41
+ * next: EventBusListener | null;
42
+ * callback: EventBusEventCallback<any>;
43
+ * } } EventBusListener
44
+ */
45
+
22
46
  /**
23
47
  * A general purpose event bus.
24
48
  *
@@ -103,6 +127,9 @@ var slice = Array.prototype.slice;
103
127
  * ```
104
128
  */
105
129
  function EventBus() {
130
+ /**
131
+ * @type { Record<string, EventBusListener> }
132
+ */
106
133
  this._listeners = {};
107
134
 
108
135
  // cleanup on destroy on lowest priority to allow
@@ -122,10 +149,12 @@ function EventBus() {
122
149
  *
123
150
  * Returning anything but `undefined` from a listener will stop the listener propagation.
124
151
  *
125
- * @param {string|Array<string>} events
126
- * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
127
- * @param {Function} callback
128
- * @param {Object} [that] Pass context (`this`) to the callback
152
+ * @template T
153
+ *
154
+ * @param {string|string[]} events to subscribe to
155
+ * @param {number} [priority=1000] listen priority
156
+ * @param {EventBusEventCallback<T>} callback
157
+ * @param {any} [that] callback context
129
158
  */
130
159
  EventBus.prototype.on = function (events, priority, callback, that) {
131
160
  events = minDash.isArray(events) ? events : [events];
@@ -157,14 +186,16 @@ EventBus.prototype.on = function (events, priority, callback, that) {
157
186
  };
158
187
 
159
188
  /**
160
- * Register an event listener that is executed only once.
189
+ * Register an event listener that is called only once.
161
190
  *
162
- * @param {string} event the event name to register for
163
- * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
164
- * @param {Function} callback the callback to execute
165
- * @param {Object} [that] Pass context (`this`) to the callback
191
+ * @template T
192
+ *
193
+ * @param {string|string[]} events to subscribe to
194
+ * @param {number} [priority=1000] the listen priority
195
+ * @param {EventBusEventCallback<T>} callback
196
+ * @param {any} [that] callback context
166
197
  */
167
- EventBus.prototype.once = function (event, priority, callback, that) {
198
+ EventBus.prototype.once = function (events, priority, callback, that) {
168
199
  var self = this;
169
200
  if (minDash.isFunction(priority)) {
170
201
  that = callback;
@@ -177,7 +208,7 @@ EventBus.prototype.once = function (event, priority, callback, that) {
177
208
  function wrappedCallback() {
178
209
  wrappedCallback.__isTomb = true;
179
210
  var result = callback.apply(that, arguments);
180
- self.off(event, wrappedCallback);
211
+ self.off(events, wrappedCallback);
181
212
  return result;
182
213
  }
183
214
 
@@ -185,7 +216,7 @@ EventBus.prototype.once = function (event, priority, callback, that) {
185
216
  // bound callbacks via {@link #off} using the original
186
217
  // callback
187
218
  wrappedCallback[FN_REF] = callback;
188
- this.on(event, priority, wrappedCallback);
219
+ this.on(events, priority, wrappedCallback);
189
220
  };
190
221
 
191
222
  /**
@@ -193,8 +224,8 @@ EventBus.prototype.once = function (event, priority, callback, that) {
193
224
  *
194
225
  * If no callback is given, all listeners for a given event name are being removed.
195
226
  *
196
- * @param {string|Array<string>} events
197
- * @param {Function} [callback]
227
+ * @param {string|string[]} events
228
+ * @param {EventBusEventCallback} [callback]
198
229
  */
199
230
  EventBus.prototype.off = function (events, callback) {
200
231
  events = minDash.isArray(events) ? events : [events];
@@ -205,11 +236,11 @@ EventBus.prototype.off = function (events, callback) {
205
236
  };
206
237
 
207
238
  /**
208
- * Create an EventBus event.
239
+ * Create an event recognized be the event bus.
209
240
  *
210
- * @param {Object} data
241
+ * @param {Object} data Event data.
211
242
  *
212
- * @return {Object} event, recognized by the eventBus
243
+ * @return {Event} An event that will be recognized by the event bus.
213
244
  */
214
245
  EventBus.prototype.createEvent = function (data) {
215
246
  var event = new InternalEvent();
@@ -218,10 +249,11 @@ EventBus.prototype.createEvent = function (data) {
218
249
  };
219
250
 
220
251
  /**
221
- * Fires a named event.
252
+ * Fires an event.
222
253
  *
223
254
  * @example
224
255
  *
256
+ * ```javascript
225
257
  * // fire event by name
226
258
  * events.fire('foo');
227
259
  *
@@ -239,13 +271,13 @@ EventBus.prototype.createEvent = function (data) {
239
271
  * });
240
272
  *
241
273
  * events.fire({ type: 'foo' }, 'I am bar!');
274
+ * ```
242
275
  *
243
- * @param {string} [name] the optional event name
244
- * @param {Object} [event] the event object
245
- * @param {...Object} additional arguments to be passed to the callback functions
276
+ * @param {string} [type] event type
277
+ * @param {Object} [data] event or event data
278
+ * @param {...any} [args] additional arguments the callback will be called with.
246
279
  *
247
- * @return {boolean} the events return value, if specified or false if the
248
- * default action was prevented by listeners
280
+ * @return {any} The return value. Will be set to `false` if the default was prevented.
249
281
  */
250
282
  EventBus.prototype.fire = function (type, data) {
251
283
  var event, firstListener, returnValue, args;
@@ -297,6 +329,14 @@ EventBus.prototype.fire = function (type, data) {
297
329
  }
298
330
  return returnValue;
299
331
  };
332
+
333
+ /**
334
+ * Handle an error by firing an event.
335
+ *
336
+ * @param {Error} error The error to be handled.
337
+ *
338
+ * @return {boolean} Whether the error was handled.
339
+ */
300
340
  EventBus.prototype.handleError = function (error) {
301
341
  return this.fire('error', {
302
342
  error: error
@@ -305,6 +345,14 @@ EventBus.prototype.handleError = function (error) {
305
345
  EventBus.prototype._destroy = function () {
306
346
  this._listeners = {};
307
347
  };
348
+
349
+ /**
350
+ * @param {Event} event
351
+ * @param {any[]} args
352
+ * @param {EventBusListener} listener
353
+ *
354
+ * @return {any}
355
+ */
308
356
  EventBus.prototype._invokeListeners = function (event, args, listener) {
309
357
  var returnValue;
310
358
  while (listener) {
@@ -317,6 +365,14 @@ EventBus.prototype._invokeListeners = function (event, args, listener) {
317
365
  }
318
366
  return returnValue;
319
367
  };
368
+
369
+ /**
370
+ * @param {Event} event
371
+ * @param {any[]} args
372
+ * @param {EventBusListener} listener
373
+ *
374
+ * @return {any}
375
+ */
320
376
  EventBus.prototype._invokeListener = function (event, args, listener) {
321
377
  var returnValue;
322
378
  if (listener.callback.__isTomb) {
@@ -345,7 +401,7 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
345
401
  return returnValue;
346
402
  };
347
403
 
348
- /*
404
+ /**
349
405
  * Add new listener with a certain priority to the list
350
406
  * of listeners (for the given event).
351
407
  *
@@ -359,7 +415,7 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
359
415
  * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
360
416
  *
361
417
  * @param {string} event
362
- * @param {Object} listener { priority, callback }
418
+ * @param {EventBusListener} listener
363
419
  */
364
420
  EventBus.prototype._addListener = function (event, newListener) {
365
421
  var listener = this._getListeners(event),
@@ -390,9 +446,20 @@ EventBus.prototype._addListener = function (event, newListener) {
390
446
  // add new listener to back
391
447
  previousListener.next = newListener;
392
448
  };
449
+
450
+ /**
451
+ * @param {string} name
452
+ *
453
+ * @return {EventBusListener}
454
+ */
393
455
  EventBus.prototype._getListeners = function (name) {
394
456
  return this._listeners[name];
395
457
  };
458
+
459
+ /**
460
+ * @param {string} name
461
+ * @param {EventBusListener} listener
462
+ */
396
463
  EventBus.prototype._setListeners = function (name, listener) {
397
464
  this._listeners[name] = listener;
398
465
  };
@@ -440,9 +507,9 @@ InternalEvent.prototype.init = function (data) {
440
507
  * Invoke function. Be fast...
441
508
  *
442
509
  * @param {Function} fn
443
- * @param {Array<Object>} args
510
+ * @param {any[]} args
444
511
  *
445
- * @return {Any}
512
+ * @return {any}
446
513
  */
447
514
  function invokeFunction(fn, args) {
448
515
  return fn.apply(null, args);
@@ -484,21 +551,24 @@ class FieldFactory {
484
551
  if (!fieldDefinition) {
485
552
  throw new Error(`form field of type <${type}> not supported`);
486
553
  }
554
+ const {
555
+ config
556
+ } = fieldDefinition;
487
557
  if (id && this._formFieldRegistry._ids.assigned(id)) {
488
558
  throw new Error(`ID <${id}> already assigned`);
489
559
  }
490
560
  if (key && this._formFieldRegistry._keys.assigned(key)) {
491
561
  throw new Error(`key <${key}> already assigned`);
492
562
  }
493
- const labelAttrs = applyDefaults && fieldDefinition.label ? {
494
- label: fieldDefinition.label
563
+ const labelAttrs = applyDefaults && config.label ? {
564
+ label: config.label
495
565
  } : {};
496
- const field = fieldDefinition.create({
566
+ const field = config.create({
497
567
  ...labelAttrs,
498
568
  ...attrs
499
569
  });
500
570
  this._ensureId(field);
501
- if (fieldDefinition.keyed) {
571
+ if (config.keyed) {
502
572
  this._ensureKey(field, applyDefaults);
503
573
  }
504
574
  return field;
@@ -571,6 +641,10 @@ class FormFieldRegistry extends formJsViewer.FormFieldRegistry {
571
641
  }
572
642
  }
573
643
 
644
+ const MAX_COLUMNS_PER_ROW = 16;
645
+ const MAX_COLUMNS = 16;
646
+ const MIN_COLUMNS = 2;
647
+ const MAX_FIELDS_PER_ROW = 4;
574
648
  class FormLayoutValidator {
575
649
  /**
576
650
  * @constructor
@@ -584,15 +658,15 @@ class FormLayoutValidator {
584
658
  }
585
659
  validateField(field = {}, columns, row) {
586
660
  // allow empty (auto columns)
587
- if (columns) {
588
- // allow minimum 2 cols
589
- if (columns < 2) {
590
- return 'Minimum 2 columns are allowed';
661
+ if (Number.isInteger(columns)) {
662
+ // allow minimum cols
663
+ if (columns < MIN_COLUMNS) {
664
+ return `Minimum ${MIN_COLUMNS} columns are allowed`;
591
665
  }
592
666
 
593
- // allow maximum 16 cols
594
- if (columns > 16) {
595
- return 'Maximum 16 columns are allowed';
667
+ // allow maximum cols
668
+ if (columns > MAX_COLUMNS) {
669
+ return `Maximum ${MAX_COLUMNS} columns are allowed`;
596
670
  }
597
671
  }
598
672
  if (!row) {
@@ -617,17 +691,24 @@ class FormLayoutValidator {
617
691
  });
618
692
 
619
693
  // do not allow overflows
620
- if (sumColumns > 16 || sumColumns === 16 && sumAutoCols > 0 || columns === 16 && sumFields > 1) {
621
- return 'New value exceeds the maximum of 16 columns per row';
694
+ if (sumColumns > MAX_COLUMNS_PER_ROW || sumAutoCols > 0 && sumColumns > calculateMaxColumnsWithAuto(sumAutoCols) || columns === MAX_COLUMNS_PER_ROW && sumFields > 1) {
695
+ return `New value exceeds the maximum of ${MAX_COLUMNS_PER_ROW} columns per row`;
622
696
  }
623
- if (sumFields > 4) {
624
- return 'Maximum 4 fields per row are allowed';
697
+ if (sumFields > MAX_FIELDS_PER_ROW) {
698
+ return `Maximum ${MAX_FIELDS_PER_ROW} fields per row are allowed`;
625
699
  }
626
700
  return null;
627
701
  }
628
702
  }
629
703
  FormLayoutValidator.$inject = ['formLayouter', 'formFieldRegistry'];
630
704
 
705
+ // helper //////////////////////
706
+
707
+ // on normal screen sizes, auto columns take minimum 2 columns
708
+ function calculateMaxColumnsWithAuto(autoCols) {
709
+ return MAX_COLUMNS_PER_ROW - autoCols * 2;
710
+ }
711
+
631
712
  class Importer {
632
713
  /**
633
714
  * @constructor
@@ -744,6 +825,91 @@ function editorFormFieldClasses(type, {
744
825
  });
745
826
  }
746
827
 
828
+ /**
829
+ * Add a dragger that calls back the passed function with
830
+ * { event, delta } on drag.
831
+ *
832
+ * @example
833
+ *
834
+ * function dragMove(event, delta) {
835
+ * // we are dragging (!!)
836
+ * }
837
+ *
838
+ * domElement.addEventListener('dragstart', dragger(dragMove));
839
+ *
840
+ * @param {Function} fn
841
+ * @param {Element} dragPreview
842
+ *
843
+ * @return {Function} drag start callback function
844
+ */
845
+ function createDragger(fn, dragPreview) {
846
+ let self;
847
+ let startX, startY;
848
+
849
+ /** drag start */
850
+ function onDragStart(event) {
851
+ self = this;
852
+ startX = event.clientX;
853
+ startY = event.clientY;
854
+
855
+ // (1) prevent preview image
856
+ if (event.dataTransfer) {
857
+ event.dataTransfer.setDragImage(dragPreview, 0, 0);
858
+ }
859
+
860
+ // (2) setup drag listeners
861
+
862
+ // attach drag + cleanup event
863
+ document.addEventListener('dragover', onDrag);
864
+ document.addEventListener('dragend', onEnd);
865
+ document.addEventListener('drop', preventDefault);
866
+ }
867
+ function onDrag(event) {
868
+ const delta = {
869
+ x: event.clientX - startX,
870
+ y: event.clientY - startY
871
+ };
872
+
873
+ // call provided fn with event, delta
874
+ return fn.call(self, event, delta);
875
+ }
876
+ function onEnd() {
877
+ document.removeEventListener('dragover', onDrag);
878
+ document.removeEventListener('dragend', onEnd);
879
+ document.removeEventListener('drop', preventDefault);
880
+ }
881
+ return onDragStart;
882
+ }
883
+
884
+ /**
885
+ * Throttle function call according UI update cycle.
886
+ *
887
+ * @param {Function} fn
888
+ *
889
+ * @return {Function} throttled fn
890
+ */
891
+ function throttle(fn) {
892
+ let active = false;
893
+ let lastArgs = [];
894
+ let lastThis = undefined;
895
+ return function (...args) {
896
+ lastArgs = args;
897
+ lastThis = this;
898
+ if (active) {
899
+ return;
900
+ }
901
+ active = true;
902
+ fn.apply(lastThis, lastArgs);
903
+ window.requestAnimationFrame(function () {
904
+ lastArgs = lastThis = active = undefined;
905
+ });
906
+ };
907
+ }
908
+ function preventDefault(event) {
909
+ event.preventDefault();
910
+ event.stopPropagation();
911
+ }
912
+
747
913
  const DragAndDropContext = preact.createContext({
748
914
  drake: null
749
915
  });
@@ -764,7 +930,7 @@ var FormEditorContext$1 = FormEditorContext;
764
930
  function useService$1 (type, strict) {
765
931
  const {
766
932
  getService
767
- } = hooks$1.useContext(FormEditorContext$1);
933
+ } = hooks.useContext(FormEditorContext$1);
768
934
  return getService(type, strict);
769
935
  }
770
936
 
@@ -784,10 +950,42 @@ var CloseIcon = (({
784
950
  })));
785
951
 
786
952
  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); }
787
- var DraggableIcon = (({
953
+ var DeleteIcon$1 = (({
788
954
  styles = {},
789
955
  ...props
790
956
  }) => /*#__PURE__*/React.createElement("svg", _extends$2({
957
+ xmlns: "http://www.w3.org/2000/svg",
958
+ width: "16",
959
+ height: "16",
960
+ fill: "none"
961
+ }, props), /*#__PURE__*/React.createElement("rect", {
962
+ width: "16",
963
+ height: "16",
964
+ x: ".536",
965
+ fill: "#fff",
966
+ rx: "3",
967
+ style: {
968
+ mixBlendMode: "multiply"
969
+ }
970
+ }), /*#__PURE__*/React.createElement("path", {
971
+ fill: "#fff",
972
+ d: "M.536 0h16v16h-16z",
973
+ style: {
974
+ mixBlendMode: "multiply"
975
+ }
976
+ }), /*#__PURE__*/React.createElement("path", {
977
+ fill: "currentcolor",
978
+ d: "M7.536 6h-1v6h1V6zm3 0h-1v6h1V6z"
979
+ }), /*#__PURE__*/React.createElement("path", {
980
+ fill: "currentcolor",
981
+ d: "M2.536 3v1h1v10a1 1 0 001 1h8a1 1 0 001-1V4h1V3h-12zm2 11V4h8v10h-8zm6-13h-4v1h4V1z"
982
+ })));
983
+
984
+ 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); }
985
+ var DraggableIcon = (({
986
+ styles = {},
987
+ ...props
988
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
791
989
  xmlns: "http://www.w3.org/2000/svg",
792
990
  width: "16",
793
991
  height: "16",
@@ -800,11 +998,11 @@ var DraggableIcon = (({
800
998
  fill: "none"
801
999
  })));
802
1000
 
803
- 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); }
1001
+ 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); }
804
1002
  var SearchIcon = (({
805
1003
  styles = {},
806
1004
  ...props
807
- }) => /*#__PURE__*/React.createElement("svg", _extends$1({
1005
+ }) => /*#__PURE__*/React.createElement("svg", _extends({
808
1006
  width: "15",
809
1007
  height: "15",
810
1008
  fill: "none",
@@ -860,9 +1058,7 @@ function EditorText(props) {
860
1058
  disableLinks: true
861
1059
  });
862
1060
  }
863
- EditorText.create = formJsViewer.Text.create;
864
- EditorText.type = formJsViewer.Text.type;
865
- EditorText.keyed = formJsViewer.Text.keyed;
1061
+ EditorText.config = formJsViewer.Text.config;
866
1062
 
867
1063
  const editorFormFields = [EditorText];
868
1064
 
@@ -870,28 +1066,20 @@ class EditorFormFields extends formJsViewer.FormFields {
870
1066
  constructor() {
871
1067
  super();
872
1068
  editorFormFields.forEach(formField => {
873
- this.register(formField.type, formField);
1069
+ this.register(formField.config.type, formField);
874
1070
  });
875
1071
  }
876
1072
  }
877
1073
 
878
- 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); }
879
- var ListDeleteIcon = (({
880
- styles = {},
881
- ...props
882
- }) => /*#__PURE__*/React.createElement("svg", _extends({
883
- xmlns: "http://www.w3.org/2000/svg",
884
- width: "11",
885
- height: "14"
886
- }, props), /*#__PURE__*/React.createElement("path", {
887
- d: "M10 4v8c0 1.1-.9 2-2 2H3c-1.1 0-2-.9-2-2V4h9zM8 6H3v4.8c0 .66.5 1.2 1.111 1.2H6.89C7.5 12 8 11.46 8 10.8V6zm3-5H8.5l-1-1h-4l-1 1H0v1.5h11V1z"
888
- })));
889
-
890
- const PALETTE_ENTRIES = formJsViewer.formFields.filter(f => f.type !== 'default').map(f => {
1074
+ const PALETTE_ENTRIES = formJsViewer.formFields.filter(({
1075
+ config: fieldConfig
1076
+ }) => fieldConfig.type !== 'default').map(({
1077
+ config: fieldConfig
1078
+ }) => {
891
1079
  return {
892
- label: f.label,
893
- type: f.type,
894
- group: f.group
1080
+ label: fieldConfig.label,
1081
+ type: fieldConfig.type,
1082
+ group: fieldConfig.group
895
1083
  };
896
1084
  });
897
1085
  const PALETTE_GROUPS = [{
@@ -908,27 +1096,32 @@ const PALETTE_GROUPS = [{
908
1096
  id: 'action'
909
1097
  }];
910
1098
  function Palette(props) {
911
- const [entries, setEntries] = hooks$1.useState(PALETTE_ENTRIES);
912
- const [searchTerm, setSearchTerm] = hooks$1.useState('');
913
- const inputRef = hooks$1.useRef();
1099
+ const [entries, setEntries] = hooks.useState(PALETTE_ENTRIES);
1100
+ const [searchTerm, setSearchTerm] = hooks.useState('');
1101
+ const inputRef = hooks.useRef();
914
1102
  const groups = groupEntries(entries);
1103
+ const simplifyString = hooks.useCallback(str => {
1104
+ return str.toLowerCase().replace(/\s+/g, '');
1105
+ }, []);
1106
+ const filter = hooks.useCallback(entry => {
1107
+ const simplifiedSearchTerm = simplifyString(searchTerm);
1108
+ if (!simplifiedSearchTerm) {
1109
+ return true;
1110
+ }
1111
+ const simplifiedEntryLabel = simplifyString(entry.label);
1112
+ const simplifiedEntryType = simplifyString(entry.type);
1113
+ return simplifiedEntryLabel.includes(simplifiedSearchTerm) || simplifiedEntryType.includes(simplifiedSearchTerm);
1114
+ }, [searchTerm, simplifyString]);
915
1115
 
916
1116
  // filter entries on search change
917
- hooks$1.useEffect(() => {
918
- const filter = entry => {
919
- if (!searchTerm) {
920
- return true;
921
- }
922
- const search = entry.label.toLowerCase();
923
- return searchTerm.toLowerCase().split(/\s/g).every(term => search.includes(term));
924
- };
1117
+ hooks.useEffect(() => {
925
1118
  const entries = PALETTE_ENTRIES.filter(filter);
926
1119
  setEntries(entries);
927
- }, [searchTerm]);
928
- const handleInput = hooks$1.useCallback(event => {
1120
+ }, [filter, searchTerm]);
1121
+ const handleInput = hooks.useCallback(event => {
929
1122
  setSearchTerm(() => event.target.value);
930
1123
  }, [setSearchTerm]);
931
- const handleClear = hooks$1.useCallback(event => {
1124
+ const handleClear = hooks.useCallback(event => {
932
1125
  setSearchTerm('');
933
1126
  inputRef.current.focus();
934
1127
  }, [inputRef, setSearchTerm]);
@@ -1337,6 +1530,136 @@ function FieldDragPreview(props) {
1337
1530
  });
1338
1531
  }
1339
1532
 
1533
+ const COLUMNS_REGEX = /^cds--col(-lg)?/;
1534
+ const ELEMENT_RESIZING_CLS = 'fjs-element-resizing';
1535
+ const RESIZE_DRAG_PREVIEW_CLS = 'fjs-resize-drag-preview';
1536
+ const GRID_OFFSET_PX = 16;
1537
+ function FieldResizer(props) {
1538
+ const {
1539
+ field,
1540
+ position
1541
+ } = props;
1542
+ const ref = hooks.useRef(null);
1543
+ const formLayoutValidator = useService$1('formLayoutValidator');
1544
+ const modeling = useService$1('modeling');
1545
+
1546
+ // we can't use state as we need to
1547
+ // manipulate this inside dragging events
1548
+ const context = hooks.useRef({
1549
+ startColumns: 0,
1550
+ newColumns: 0
1551
+ });
1552
+ const onResize = throttle((_, delta) => {
1553
+ const {
1554
+ x: dx
1555
+ } = delta;
1556
+ const {
1557
+ layout = {}
1558
+ } = field;
1559
+ const newColumns = calculateNewColumns(ref.current, layout.columns || context.current.startColumns, dx, position);
1560
+ const errorMessage = formLayoutValidator.validateField(field, newColumns);
1561
+ if (!errorMessage) {
1562
+ context.current.newColumns = newColumns;
1563
+
1564
+ // make visual updates to preview change
1565
+ const columnNode = ref.current.closest('.fjs-layout-column');
1566
+ removeMatching(columnNode, COLUMNS_REGEX);
1567
+ columnNode.classList.add(`cds--col-lg-${newColumns}`);
1568
+ }
1569
+ });
1570
+ const onResizeStart = event => {
1571
+ const target = getElementNode(field);
1572
+ const parent = getParent(target);
1573
+
1574
+ // create a blank element to use as drag preview
1575
+ // ensure it was only created once
1576
+ let blankPreview = getDragPreviewImage(parent);
1577
+ if (!blankPreview) {
1578
+ blankPreview = document.createElement('div');
1579
+ blankPreview.classList.add(RESIZE_DRAG_PREVIEW_CLS);
1580
+ parent.appendChild(blankPreview);
1581
+ }
1582
+
1583
+ // initialize drag handler
1584
+ const onDragStart = createDragger(onResize, blankPreview);
1585
+ onDragStart(event);
1586
+
1587
+ // mitigate auto columns on the grid that
1588
+ // has a offset of 16px (1rem) to both side
1589
+ const columnNode = getColumnNode(target);
1590
+ const startWidth = columnNode.getBoundingClientRect().width + GRID_OFFSET_PX;
1591
+ context.current.startColumns = asColumns(startWidth, parent);
1592
+ setResizing(target, position);
1593
+ };
1594
+ const onResizeEnd = () => {
1595
+ const {
1596
+ layout = {}
1597
+ } = field;
1598
+ if (context.current.newColumns) {
1599
+ modeling.editFormField(field, 'layout', {
1600
+ ...layout,
1601
+ columns: context.current.newColumns
1602
+ });
1603
+ }
1604
+ const target = getElementNode(field);
1605
+ unsetResizing(target, position);
1606
+ context.current.newColumns = null;
1607
+
1608
+ // remove blank preview
1609
+ const blankPreview = getDragPreviewImage(getParent(target));
1610
+ blankPreview.remove();
1611
+ };
1612
+ if (field.type === 'default') {
1613
+ return null;
1614
+ }
1615
+ return jsxRuntime.jsx("div", {
1616
+ ref: ref,
1617
+ class: classnames('fjs-field-resize-handle', 'fjs-field-resize-handle-' + position, DRAG_NO_MOVE_CLS),
1618
+ draggable: true,
1619
+ onDragStart: onResizeStart,
1620
+ onDragEnd: onResizeEnd
1621
+ });
1622
+ }
1623
+
1624
+ // helper //////
1625
+
1626
+ function asColumns(width, parent) {
1627
+ const totalWidth = parent.getBoundingClientRect().width;
1628
+ const oneColumn = 1 / 16 * totalWidth;
1629
+ return Math.round(width / oneColumn);
1630
+ }
1631
+ function calculateNewColumns(node, currentColumns, deltaX, position) {
1632
+ const parent = getParent(node);
1633
+
1634
+ // invert delta if we are resizing from the left
1635
+ if (position === 'left') {
1636
+ deltaX = deltaX * -1;
1637
+ }
1638
+ const deltaColumns = asColumns(deltaX, parent);
1639
+ return currentColumns + deltaColumns;
1640
+ }
1641
+ function getParent(node) {
1642
+ return node.closest('.fjs-layout-row');
1643
+ }
1644
+ function removeMatching(node, regex) {
1645
+ return minDom.classes(node).removeMatching(regex);
1646
+ }
1647
+ function getColumnNode(node) {
1648
+ return node.closest('.fjs-layout-column');
1649
+ }
1650
+ function getElementNode(field) {
1651
+ return minDom.query('.fjs-element[data-id="' + field.id + '"]');
1652
+ }
1653
+ function getDragPreviewImage(node) {
1654
+ return minDom.query('.fjs-resize-drag-preview', node);
1655
+ }
1656
+ function setResizing(node, position) {
1657
+ minDom.classes(node).add(ELEMENT_RESIZING_CLS + '-' + position);
1658
+ }
1659
+ function unsetResizing(node, position) {
1660
+ minDom.classes(node).remove(ELEMENT_RESIZING_CLS + '-' + position);
1661
+ }
1662
+
1340
1663
  function ContextPad(props) {
1341
1664
  if (!props.children) {
1342
1665
  return null;
@@ -1362,7 +1685,7 @@ function Element(props) {
1362
1685
  id,
1363
1686
  type
1364
1687
  } = field;
1365
- const ref = hooks$1.useRef();
1688
+ const ref = hooks.useRef();
1366
1689
  function scrollIntoView({
1367
1690
  selection
1368
1691
  }) {
@@ -1375,13 +1698,21 @@ function Element(props) {
1375
1698
  ref.current.scrollIntoView();
1376
1699
  }
1377
1700
  }
1378
- hooks$1.useEffect(() => {
1701
+ hooks.useEffect(() => {
1379
1702
  eventBus.on('selection.changed', scrollIntoView);
1380
1703
  return () => eventBus.off('selection.changed', scrollIntoView);
1381
1704
  }, [id]);
1705
+ hooks.useLayoutEffect(() => {
1706
+ if (selection.isSelected(field)) {
1707
+ ref.current.focus();
1708
+ }
1709
+ }, [selection, field]);
1382
1710
  function onClick(event) {
1383
1711
  event.stopPropagation();
1384
1712
  selection.toggle(field);
1713
+
1714
+ // properly focus on field
1715
+ ref.current.focus();
1385
1716
  }
1386
1717
  const classes = [];
1387
1718
  if (props.class) {
@@ -1396,11 +1727,19 @@ function Element(props) {
1396
1727
  const index = getFormFieldIndex(parentField, field);
1397
1728
  modeling.removeFormField(field, parentField, index);
1398
1729
  };
1730
+ const onKeyPress = event => {
1731
+ if (event.key === 'Enter') {
1732
+ event.stopPropagation();
1733
+ selection.toggle(field);
1734
+ }
1735
+ };
1399
1736
  return jsxRuntime.jsxs("div", {
1400
1737
  class: classes.join(' '),
1401
1738
  "data-id": id,
1402
1739
  "data-field-type": type,
1740
+ tabIndex: type === 'default' ? -1 : 0,
1403
1741
  onClick: onClick,
1742
+ onKeyPress: onKeyPress,
1404
1743
  ref: ref,
1405
1744
  children: [jsxRuntime.jsx(DebugColumns, {
1406
1745
  field: field
@@ -1408,9 +1747,15 @@ function Element(props) {
1408
1747
  children: selection.isSelected(field) && field.type !== 'default' ? jsxRuntime.jsx("button", {
1409
1748
  class: "fjs-context-pad-item",
1410
1749
  onClick: onRemove,
1411
- children: jsxRuntime.jsx(ListDeleteIcon, {})
1750
+ children: jsxRuntime.jsx(DeleteIcon$1, {})
1412
1751
  }) : null
1413
- }), props.children]
1752
+ }), props.children, jsxRuntime.jsx(FieldResizer, {
1753
+ position: "left",
1754
+ field: field
1755
+ }), jsxRuntime.jsx(FieldResizer, {
1756
+ position: "right",
1757
+ field: field
1758
+ })]
1414
1759
  });
1415
1760
  }
1416
1761
  function DebugColumns(props) {
@@ -1495,13 +1840,17 @@ function FormEditor$1(props) {
1495
1840
  propertiesPanel = useService$1('propertiesPanel'),
1496
1841
  propertiesPanelConfig = useService$1('config.propertiesPanel');
1497
1842
  const {
1498
- schema
1843
+ schema,
1844
+ properties
1499
1845
  } = formEditor._getState();
1500
- const formContainerRef = hooks$1.useRef(null);
1501
- const paletteRef = hooks$1.useRef(null);
1502
- const propertiesPanelRef = hooks$1.useRef(null);
1503
- const [, setSelection] = hooks$1.useState(schema);
1504
- hooks$1.useEffect(() => {
1846
+ const {
1847
+ ariaLabel
1848
+ } = properties;
1849
+ const formContainerRef = hooks.useRef(null);
1850
+ const paletteRef = hooks.useRef(null);
1851
+ const propertiesPanelRef = hooks.useRef(null);
1852
+ const [, setSelection] = hooks.useState(schema);
1853
+ hooks.useEffect(() => {
1505
1854
  function handleSelectionChanged(event) {
1506
1855
  setSelection(event.selection || schema);
1507
1856
  }
@@ -1511,11 +1860,11 @@ function FormEditor$1(props) {
1511
1860
  eventBus.off('selection.changed', handleSelectionChanged);
1512
1861
  };
1513
1862
  }, [schema, selection]);
1514
- const [drake, setDrake] = hooks$1.useState(null);
1863
+ const [drake, setDrake] = hooks.useState(null);
1515
1864
  const dragAndDropContext = {
1516
1865
  drake
1517
1866
  };
1518
- hooks$1.useEffect(() => {
1867
+ hooks.useEffect(() => {
1519
1868
  let dragulaInstance = dragging.createDragulaInstance({
1520
1869
  container: [DRAG_CONTAINER_CLS, DROP_CONTAINER_VERTICAL_CLS, DROP_CONTAINER_HORIZONTAL_CLS],
1521
1870
  direction: 'vertical',
@@ -1562,7 +1911,7 @@ function FormEditor$1(props) {
1562
1911
  }, []);
1563
1912
 
1564
1913
  // fire event after render to notify interested parties
1565
- hooks$1.useEffect(() => {
1914
+ hooks.useEffect(() => {
1566
1915
  eventBus.fire('formEditor.rendered');
1567
1916
  }, []);
1568
1917
  const formRenderContext = {
@@ -1582,7 +1931,8 @@ function FormEditor$1(props) {
1582
1931
  data: {},
1583
1932
  errors: {},
1584
1933
  properties: {
1585
- readOnly: true
1934
+ ariaLabel,
1935
+ disabled: true
1586
1936
  },
1587
1937
  schema
1588
1938
  };
@@ -1593,12 +1943,12 @@ function FormEditor$1(props) {
1593
1943
  },
1594
1944
  formId: formEditor._id
1595
1945
  };
1596
- const onSubmit = hooks$1.useCallback(() => {}, []);
1597
- const onReset = hooks$1.useCallback(() => {}, []);
1946
+ const onSubmit = hooks.useCallback(() => {}, []);
1947
+ const onReset = hooks.useCallback(() => {}, []);
1598
1948
 
1599
1949
  // attach default palette
1600
1950
  const hasDefaultPalette = defaultPalette(paletteConfig);
1601
- hooks$1.useEffect(() => {
1951
+ hooks.useEffect(() => {
1602
1952
  if (hasDefaultPalette) {
1603
1953
  palette.attachTo(paletteRef.current);
1604
1954
  }
@@ -1606,7 +1956,7 @@ function FormEditor$1(props) {
1606
1956
 
1607
1957
  // attach default properties panel
1608
1958
  const hasDefaultPropertiesPanel = defaultPropertiesPanel(propertiesPanelConfig);
1609
- hooks$1.useEffect(() => {
1959
+ hooks.useEffect(() => {
1610
1960
  if (hasDefaultPropertiesPanel) {
1611
1961
  propertiesPanel.attachTo(propertiesPanelRef.current);
1612
1962
  }
@@ -1652,7 +2002,7 @@ function getFormFieldIndex(parent, formField) {
1652
2002
  function CreatePreview(props) {
1653
2003
  const {
1654
2004
  drake
1655
- } = hooks$1.useContext(DragAndDropContext$1);
2005
+ } = hooks.useContext(DragAndDropContext$1);
1656
2006
  function handleCloned(clone, original, type) {
1657
2007
  const fieldType = clone.dataset.fieldType;
1658
2008
 
@@ -1690,7 +2040,7 @@ function CreatePreview(props) {
1690
2040
  clone.classList.add('cds--grid--condensed');
1691
2041
  }
1692
2042
  }
1693
- hooks$1.useEffect(() => {
2043
+ hooks.useEffect(() => {
1694
2044
  if (!drake) {
1695
2045
  return;
1696
2046
  }
@@ -1719,7 +2069,7 @@ class Renderer {
1719
2069
  compact = false
1720
2070
  } = renderConfig;
1721
2071
  const App = () => {
1722
- const [state, setState] = hooks$1.useState(formEditor._getState());
2072
+ const [state, setState] = hooks.useState(formEditor._getState());
1723
2073
  const formEditorContext = {
1724
2074
  getService(type, strict = true) {
1725
2075
  return injector.get(type, strict);
@@ -1768,6 +2118,12 @@ var core = {
1768
2118
  fieldFactory: ['type', FieldFactory]
1769
2119
  };
1770
2120
 
2121
+ /**
2122
+ * @typedef {import('didi').Injector} Injector
2123
+ *
2124
+ * @typedef {import('../../core/EventBus').default} EventBus
2125
+ */
2126
+
1771
2127
  var NOT_REGISTERED_ERROR = 'is not a registered action',
1772
2128
  IS_REGISTERED_ERROR = 'is already registered';
1773
2129
 
@@ -1897,10 +2253,10 @@ EditorActions.prototype._registerDefaultActions = function (injector) {
1897
2253
  /**
1898
2254
  * Triggers a registered action
1899
2255
  *
1900
- * @param {string} action
1901
- * @param {Object} opts
2256
+ * @param {string} action
2257
+ * @param {Object} opts
1902
2258
  *
1903
- * @return {Unknown} Returns what the registered listener returns
2259
+ * @return {unknown} Returns what the registered listener returns
1904
2260
  */
1905
2261
  EditorActions.prototype.trigger = function (action, opts) {
1906
2262
  if (!this._actions[action]) {
@@ -1929,7 +2285,7 @@ EditorActions.prototype.trigger = function (action, opts) {
1929
2285
  * editorActions.isRegistered('spaceTool'); // true
1930
2286
  * ´´´
1931
2287
  *
1932
- * @param {Object} actions
2288
+ * @param {Object} actions
1933
2289
  */
1934
2290
  EditorActions.prototype.register = function (actions, listener) {
1935
2291
  var self = this;
@@ -1944,8 +2300,8 @@ EditorActions.prototype.register = function (actions, listener) {
1944
2300
  /**
1945
2301
  * Registers a listener to an action key
1946
2302
  *
1947
- * @param {string} action
1948
- * @param {Function} listener
2303
+ * @param {string} action
2304
+ * @param {Function} listener
1949
2305
  */
1950
2306
  EditorActions.prototype._registerAction = function (action, listener) {
1951
2307
  if (this.isRegistered(action)) {
@@ -1989,6 +2345,9 @@ function error(action, message) {
1989
2345
  return new Error(action + ' ' + message);
1990
2346
  }
1991
2347
 
2348
+ /**
2349
+ * @type { import('didi').ModuleDeclaration }
2350
+ */
1992
2351
  var EditorActionsModule$1 = {
1993
2352
  __init__: ['editorActions'],
1994
2353
  editorActions: ['type', EditorActions]
@@ -2048,10 +2407,10 @@ var DraggingModule = {
2048
2407
  dragging: ['type', Dragging]
2049
2408
  };
2050
2409
 
2051
- var KEYS_COPY = ['c', 'C', 'KeyC'];
2052
- var KEYS_PASTE = ['v', 'V', 'KeyV'];
2053
- var KEYS_REDO$1 = ['y', 'Y', 'KeyY'];
2054
- var KEYS_UNDO$1 = ['z', 'Z', 'KeyZ'];
2410
+ var KEYS_COPY = ['c', 'C'];
2411
+ var KEYS_PASTE = ['v', 'V'];
2412
+ var KEYS_REDO = ['y', 'Y'];
2413
+ var KEYS_UNDO = ['z', 'Z'];
2055
2414
 
2056
2415
  /**
2057
2416
  * Returns true if event was triggered with any modifier
@@ -2076,7 +2435,7 @@ function isCmd(event) {
2076
2435
  /**
2077
2436
  * Checks if key pressed is one of provided keys.
2078
2437
  *
2079
- * @param {string|Array<string>} keys
2438
+ * @param {string|string[]} keys
2080
2439
  * @param {KeyboardEvent} event
2081
2440
  */
2082
2441
  function isKey(keys, event) {
@@ -2097,12 +2456,16 @@ function isPaste(event) {
2097
2456
  return isCmd(event) && isKey(KEYS_PASTE, event);
2098
2457
  }
2099
2458
  function isUndo(event) {
2100
- return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO$1, event);
2459
+ return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
2101
2460
  }
2102
2461
  function isRedo(event) {
2103
- return isCmd(event) && (isKey(KEYS_REDO$1, event) || isKey(KEYS_UNDO$1, event) && isShift(event));
2462
+ return isCmd(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
2104
2463
  }
2105
2464
 
2465
+ /**
2466
+ * @typedef {import('../../core/EventBus').default} EventBus
2467
+ */
2468
+
2106
2469
  var KEYDOWN_EVENT = 'keyboard.keydown',
2107
2470
  KEYUP_EVENT = 'keyboard.keyup';
2108
2471
  var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
@@ -2129,7 +2492,7 @@ var DEFAULT_PRIORITY$1 = 1000;
2129
2492
  * A default binding for the keyboard may be specified via the
2130
2493
  * `keyboard.bindTo` configuration option.
2131
2494
  *
2132
- * @param {Config} config
2495
+ * @param {Object} config
2133
2496
  * @param {EventBus} eventBus
2134
2497
  */
2135
2498
  function Keyboard(config, eventBus) {
@@ -2258,8 +2621,6 @@ function isInput(target) {
2258
2621
  }
2259
2622
 
2260
2623
  var LOW_PRIORITY$1 = 500;
2261
- var KEYS_REDO = ['y', 'Y', 'KeyY'];
2262
- var KEYS_UNDO = ['z', 'Z', 'KeyZ'];
2263
2624
 
2264
2625
  /**
2265
2626
  * Adds default keyboard bindings.
@@ -2390,6 +2751,9 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
2390
2751
  });
2391
2752
  };
2392
2753
 
2754
+ /**
2755
+ * @type { import('didi').ModuleDeclaration }
2756
+ */
2393
2757
  var KeyboardModule$1 = {
2394
2758
  __init__: ['keyboard', 'keyboardBindings'],
2395
2759
  keyboard: ['type', Keyboard],
@@ -2925,32 +3289,46 @@ class Modeling {
2925
3289
  }
2926
3290
  Modeling.$inject = ['commandStack', 'eventBus', 'formEditor', 'formFieldRegistry', 'fieldFactory'];
2927
3291
 
3292
+ /**
3293
+ * @typedef {import('../core/Types').ElementLike} ElementLike
3294
+ * @typedef {import('../core/EventBus').default} EventBus
3295
+ * @typedef {import('./CommandStack').CommandContext} CommandContext
3296
+ *
3297
+ * @typedef {string|string[]} Events
3298
+ * @typedef { (context: CommandContext) => ElementLike[] | void } HandlerFunction
3299
+ * @typedef { (context: CommandContext) => void } ComposeHandlerFunction
3300
+ */
3301
+
2928
3302
  var DEFAULT_PRIORITY = 1000;
2929
3303
 
2930
3304
  /**
2931
- * A utility that can be used to plug-in into the command execution for
3305
+ * A utility that can be used to plug into the command execution for
2932
3306
  * extension and/or validation.
2933
3307
  *
2934
- * @param {EventBus} eventBus
3308
+ * @class
3309
+ * @constructor
2935
3310
  *
2936
3311
  * @example
2937
3312
  *
2938
- * import inherits from 'inherits-browser';
2939
- *
3313
+ * ```javascript
2940
3314
  * import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
2941
3315
  *
2942
- * function CommandLogger(eventBus) {
2943
- * CommandInterceptor.call(this, eventBus);
3316
+ * class CommandLogger extends CommandInterceptor {
3317
+ * constructor(eventBus) {
3318
+ * super(eventBus);
2944
3319
  *
2945
- * this.preExecute(function(event) {
2946
- * console.log('command pre-execute', event);
3320
+ * this.preExecute('shape.create', (event) => {
3321
+ * console.log('commandStack.shape-create.preExecute', event);
2947
3322
  * });
2948
3323
  * }
3324
+ * ```
2949
3325
  *
2950
- * inherits(CommandLogger, CommandInterceptor);
2951
- *
3326
+ * @param {EventBus} eventBus
2952
3327
  */
2953
3328
  function CommandInterceptor(eventBus) {
3329
+ /**
3330
+ * @type {EventBus}
3331
+ */
2954
3332
  this._eventBus = eventBus;
2955
3333
  }
2956
3334
  CommandInterceptor.$inject = ['eventBus'];
@@ -2961,15 +3339,14 @@ function unwrapEvent(fn, that) {
2961
3339
  }
2962
3340
 
2963
3341
  /**
2964
- * Register an interceptor for a command execution
2965
- *
2966
- * @param {string|Array<string>} [events] list of commands to register on
2967
- * @param {string} [hook] command hook, i.e. preExecute, executed to listen on
2968
- * @param {number} [priority] the priority on which to hook into the execution
2969
- * @param {Function} handlerFn interceptor to be invoked with (event)
2970
- * @param {boolean} unwrap if true, unwrap the event and pass (context, command, event) to the
2971
- * listener instead
2972
- * @param {Object} [that] Pass context (`this`) to the handler function
3342
+ * Intercept a command during one of the phases.
3343
+ *
3344
+ * @param {Events} [events] command(s) to intercept
3345
+ * @param {string} [hook] phase to intercept
3346
+ * @param {number} [priority]
3347
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3348
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3349
+ * @param {any} [that]
2973
3350
  */
2974
3351
  CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, unwrap, that) {
2975
3352
  if (minDash.isFunction(hook) || minDash.isNumber(hook)) {
@@ -3004,28 +3381,130 @@ CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, u
3004
3381
  eventBus.on(fullEvent, priority, unwrap ? unwrapEvent(handlerFn, that) : handlerFn, that);
3005
3382
  });
3006
3383
  };
3007
- var hooks = ['canExecute', 'preExecute', 'preExecuted', 'execute', 'executed', 'postExecute', 'postExecuted', 'revert', 'reverted'];
3384
+
3385
+ /**
3386
+ * Add a <canExecute> phase of command interceptor.
3387
+ *
3388
+ * @param {Events} [events] command(s) to intercept
3389
+ * @param {number} [priority]
3390
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3391
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3392
+ * @param {any} [that]
3393
+ */
3394
+ CommandInterceptor.prototype.canExecute = createHook('canExecute');
3395
+
3396
+ /**
3397
+ * Add a <preExecute> phase of command interceptor.
3398
+ *
3399
+ * @param {Events} [events] command(s) to intercept
3400
+ * @param {number} [priority]
3401
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3402
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3403
+ * @param {any} [that]
3404
+ */
3405
+ CommandInterceptor.prototype.preExecute = createHook('preExecute');
3406
+
3407
+ /**
3408
+ * Add a <preExecuted> phase of command interceptor.
3409
+ *
3410
+ * @param {Events} [events] command(s) to intercept
3411
+ * @param {number} [priority]
3412
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3413
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3414
+ * @param {any} [that]
3415
+ */
3416
+ CommandInterceptor.prototype.preExecuted = createHook('preExecuted');
3417
+
3418
+ /**
3419
+ * Add a <execute> phase of command interceptor.
3420
+ *
3421
+ * @param {Events} [events] command(s) to intercept
3422
+ * @param {number} [priority]
3423
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3424
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3425
+ * @param {any} [that]
3426
+ */
3427
+ CommandInterceptor.prototype.execute = createHook('execute');
3428
+
3429
+ /**
3430
+ * Add a <executed> phase of command interceptor.
3431
+ *
3432
+ * @param {Events} [events] command(s) to intercept
3433
+ * @param {number} [priority]
3434
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3435
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3436
+ * @param {any} [that]
3437
+ */
3438
+ CommandInterceptor.prototype.executed = createHook('executed');
3439
+
3440
+ /**
3441
+ * Add a <postExecute> phase of command interceptor.
3442
+ *
3443
+ * @param {Events} [events] command(s) to intercept
3444
+ * @param {number} [priority]
3445
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3446
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3447
+ * @param {any} [that]
3448
+ */
3449
+ CommandInterceptor.prototype.postExecute = createHook('postExecute');
3450
+
3451
+ /**
3452
+ * Add a <postExecuted> phase of command interceptor.
3453
+ *
3454
+ * @param {Events} [events] command(s) to intercept
3455
+ * @param {number} [priority]
3456
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3457
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3458
+ * @param {any} [that]
3459
+ */
3460
+ CommandInterceptor.prototype.postExecuted = createHook('postExecuted');
3461
+
3462
+ /**
3463
+ * Add a <revert> phase of command interceptor.
3464
+ *
3465
+ * @param {Events} [events] command(s) to intercept
3466
+ * @param {number} [priority]
3467
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3468
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3469
+ * @param {any} [that]
3470
+ */
3471
+ CommandInterceptor.prototype.revert = createHook('revert');
3472
+
3473
+ /**
3474
+ * Add a <reverted> phase of command interceptor.
3475
+ *
3476
+ * @param {Events} [events] command(s) to intercept
3477
+ * @param {number} [priority]
3478
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3479
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3480
+ * @param {any} [that]
3481
+ */
3482
+ CommandInterceptor.prototype.reverted = createHook('reverted');
3008
3483
 
3009
3484
  /*
3010
- * Install hook shortcuts
3485
+ * Add prototype methods for each phase of command execution (e.g. execute,
3486
+ * revert).
3011
3487
  *
3012
- * This will generate the CommandInterceptor#(preExecute|...|reverted) methods
3013
- * which will in term forward to CommandInterceptor#on.
3488
+ * @param {string} hook
3489
+ *
3490
+ * @return { (
3491
+ * events?: Events,
3492
+ * priority?: number,
3493
+ * handlerFn: ComposeHandlerFunction|HandlerFunction,
3494
+ * unwrap?: boolean
3495
+ * ) => any }
3014
3496
  */
3015
- minDash.forEach(hooks, function (hook) {
3497
+ function createHook(hook) {
3016
3498
  /**
3017
- * {canExecute|preExecute|preExecuted|execute|executed|postExecute|postExecuted|revert|reverted}
3018
- *
3019
- * A named hook for plugging into the command execution
3499
+ * @this {CommandInterceptor}
3020
3500
  *
3021
- * @param {string|Array<string>} [events] list of commands to register on
3022
- * @param {number} [priority] the priority on which to hook into the execution
3023
- * @param {Function} handlerFn interceptor to be invoked with (event)
3024
- * @param {boolean} [unwrap=false] if true, unwrap the event and pass (context, command, event) to the
3025
- * listener instead
3026
- * @param {Object} [that] Pass context (`this`) to the handler function
3501
+ * @param {Events} [events]
3502
+ * @param {number} [priority]
3503
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3504
+ * @param {boolean} [unwrap]
3505
+ * @param {any} [that]
3027
3506
  */
3028
- CommandInterceptor.prototype[hook] = function (events, priority, handlerFn, unwrap, that) {
3507
+ const hookFn = function (events, priority, handlerFn, unwrap, that) {
3029
3508
  if (minDash.isFunction(events) || minDash.isNumber(events)) {
3030
3509
  that = unwrap;
3031
3510
  unwrap = handlerFn;
@@ -3035,7 +3514,8 @@ minDash.forEach(hooks, function (hook) {
3035
3514
  }
3036
3515
  this.on(events, hook, priority, handlerFn, unwrap, that);
3037
3516
  };
3038
- });
3517
+ return hookFn;
3518
+ }
3039
3519
 
3040
3520
  class FormLayoutUpdater extends CommandInterceptor {
3041
3521
  constructor(eventBus, formLayouter, modeling, formEditor) {
@@ -3173,6 +3653,34 @@ var behaviorModule = {
3173
3653
  validateBehavior: ['type', ValidateBehavior]
3174
3654
  };
3175
3655
 
3656
+ /**
3657
+ * @typedef {import('didi').Injector} Injector
3658
+ *
3659
+ * @typedef {import('../core/Types').ElementLike} ElementLike
3660
+ *
3661
+ * @typedef {import('../core/EventBus').default} EventBus
3662
+ * @typedef {import('./CommandHandler').default} CommandHandler
3663
+ *
3664
+ * @typedef { any } CommandContext
3665
+ * @typedef { {
3666
+ * new (...args: any[]) : CommandHandler
3667
+ * } } CommandHandlerConstructor
3668
+ * @typedef { {
3669
+ * [key: string]: CommandHandler;
3670
+ * } } CommandHandlerMap
3671
+ * @typedef { {
3672
+ * command: string;
3673
+ * context: any;
3674
+ * id?: any;
3675
+ * } } CommandStackAction
3676
+ * @typedef { {
3677
+ * actions: CommandStackAction[];
3678
+ * dirty: ElementLike[];
3679
+ * trigger: 'execute' | 'undo' | 'redo' | 'clear' | null;
3680
+ * atomic?: boolean;
3681
+ * } } CurrentExecution
3682
+ */
3683
+
3176
3684
  /**
3177
3685
  * A service that offers un- and redoable execution of commands.
3178
3686
  *
@@ -3223,7 +3731,7 @@ var behaviorModule = {
3223
3731
  * got changed during the `execute` and `revert` operations.
3224
3732
  *
3225
3733
  * Command handlers may execute other modeling operations (and thus
3226
- * commands) in their `preExecute` and `postExecute` phases. The command
3734
+ * commands) in their `preExecute(d)` and `postExecute(d)` phases. The command
3227
3735
  * stack will properly group all commands together into a logical unit
3228
3736
  * that may be re- and undone atomically.
3229
3737
  *
@@ -3253,14 +3761,14 @@ function CommandStack(eventBus, injector) {
3253
3761
  /**
3254
3762
  * A map of all registered command handlers.
3255
3763
  *
3256
- * @type {Object}
3764
+ * @type {CommandHandlerMap}
3257
3765
  */
3258
3766
  this._handlerMap = {};
3259
3767
 
3260
3768
  /**
3261
3769
  * A stack containing all re/undoable actions on the diagram
3262
3770
  *
3263
- * @type {Array<Object>}
3771
+ * @type {CommandStackAction[]}
3264
3772
  */
3265
3773
  this._stack = [];
3266
3774
 
@@ -3274,18 +3782,27 @@ function CommandStack(eventBus, injector) {
3274
3782
  /**
3275
3783
  * Current active commandStack execution
3276
3784
  *
3277
- * @type {Object}
3278
- * @property {Object[]} actions
3279
- * @property {Object[]} dirty
3280
- * @property { 'undo' | 'redo' | 'clear' | 'execute' | null } trigger the cause of the current excecution
3785
+ * @type {CurrentExecution}
3281
3786
  */
3282
3787
  this._currentExecution = {
3283
3788
  actions: [],
3284
3789
  dirty: [],
3285
3790
  trigger: null
3286
3791
  };
3287
- this._injector = injector;
3288
- this._eventBus = eventBus;
3792
+
3793
+ /**
3794
+ * @type {Injector}
3795
+ */
3796
+ this._injector = injector;
3797
+
3798
+ /**
3799
+ * @type EventBus
3800
+ */
3801
+ this._eventBus = eventBus;
3802
+
3803
+ /**
3804
+ * @type { number }
3805
+ */
3289
3806
  this._uid = 1;
3290
3807
  eventBus.on(['diagram.destroy', 'diagram.clear'], function () {
3291
3808
  this.clear(false);
@@ -3294,10 +3811,10 @@ function CommandStack(eventBus, injector) {
3294
3811
  CommandStack.$inject = ['eventBus', 'injector'];
3295
3812
 
3296
3813
  /**
3297
- * Execute a command
3814
+ * Execute a command.
3298
3815
  *
3299
- * @param {string} command the command to execute
3300
- * @param {Object} context the environment to execute the command in
3816
+ * @param {string} command The command to execute.
3817
+ * @param {CommandContext} context The context with which to execute the command.
3301
3818
  */
3302
3819
  CommandStack.prototype.execute = function (command, context) {
3303
3820
  if (!command) {
@@ -3310,11 +3827,11 @@ CommandStack.prototype.execute = function (command, context) {
3310
3827
  };
3311
3828
  this._pushAction(action);
3312
3829
  this._internalExecute(action);
3313
- this._popAction(action);
3830
+ this._popAction();
3314
3831
  };
3315
3832
 
3316
3833
  /**
3317
- * Ask whether a given command can be executed.
3834
+ * Check whether a command can be executed.
3318
3835
  *
3319
3836
  * Implementors may hook into the mechanism on two ways:
3320
3837
  *
@@ -3328,10 +3845,10 @@ CommandStack.prototype.execute = function (command, context) {
3328
3845
  * If the method {@link CommandHandler#canExecute} is implemented in a handler
3329
3846
  * it will be called to figure out whether the execution is allowed.
3330
3847
  *
3331
- * @param {string} command the command to execute
3332
- * @param {Object} context the environment to execute the command in
3848
+ * @param {string} command The command to execute.
3849
+ * @param {CommandContext} context The context with which to execute the command.
3333
3850
  *
3334
- * @return {boolean} true if the command can be executed
3851
+ * @return {boolean} Whether the command can be executed with the given context.
3335
3852
  */
3336
3853
  CommandStack.prototype.canExecute = function (command, context) {
3337
3854
  const action = {
@@ -3355,7 +3872,9 @@ CommandStack.prototype.canExecute = function (command, context) {
3355
3872
  };
3356
3873
 
3357
3874
  /**
3358
- * Clear the command stack, erasing all undo / redo history
3875
+ * Clear the command stack, erasing all undo / redo history.
3876
+ *
3877
+ * @param {boolean} [emit=true] Whether to fire an event. Defaults to `true`.
3359
3878
  */
3360
3879
  CommandStack.prototype.clear = function (emit) {
3361
3880
  this._stack.length = 0;
@@ -3410,21 +3929,21 @@ CommandStack.prototype.redo = function () {
3410
3929
  };
3411
3930
 
3412
3931
  /**
3413
- * Register a handler instance with the command stack
3932
+ * Register a handler instance with the command stack.
3414
3933
  *
3415
- * @param {string} command
3416
- * @param {CommandHandler} handler
3934
+ * @param {string} command Command to be executed.
3935
+ * @param {CommandHandler} handler Handler to execute the command.
3417
3936
  */
3418
3937
  CommandStack.prototype.register = function (command, handler) {
3419
3938
  this._setHandler(command, handler);
3420
3939
  };
3421
3940
 
3422
3941
  /**
3423
- * Register a handler type with the command stack
3424
- * by instantiating it and injecting its dependencies.
3942
+ * Register a handler type with the command stack by instantiating it and
3943
+ * injecting its dependencies.
3425
3944
  *
3426
- * @param {string} command
3427
- * @param {Function} a constructor for a {@link CommandHandler}
3945
+ * @param {string} command Command to be executed.
3946
+ * @param {CommandHandlerConstructor} handlerCls Constructor to instantiate a {@link CommandHandler}.
3428
3947
  */
3429
3948
  CommandStack.prototype.registerHandler = function (command, handlerCls) {
3430
3949
  if (!command || !handlerCls) {
@@ -3433,9 +3952,17 @@ CommandStack.prototype.registerHandler = function (command, handlerCls) {
3433
3952
  const handler = this._injector.instantiate(handlerCls);
3434
3953
  this.register(command, handler);
3435
3954
  };
3955
+
3956
+ /**
3957
+ * @return {boolean}
3958
+ */
3436
3959
  CommandStack.prototype.canUndo = function () {
3437
3960
  return !!this._getUndoAction();
3438
3961
  };
3962
+
3963
+ /**
3964
+ * @return {boolean}
3965
+ */
3439
3966
  CommandStack.prototype.canRedo = function () {
3440
3967
  return !!this._getRedoAction();
3441
3968
  };
@@ -3529,7 +4056,7 @@ CommandStack.prototype._internalExecute = function (action, redo) {
3529
4056
  }
3530
4057
  this._fire(command, 'postExecuted', action);
3531
4058
  }
3532
- this._popAction(action);
4059
+ this._popAction();
3533
4060
  };
3534
4061
  CommandStack.prototype._pushAction = function (action) {
3535
4062
  const execution = this._currentExecution,
@@ -3590,6 +4117,9 @@ CommandStack.prototype._setHandler = function (command, handler) {
3590
4117
  this._handlerMap[command] = handler;
3591
4118
  };
3592
4119
 
4120
+ /**
4121
+ * @type { import('didi').ModuleDeclaration }
4122
+ */
3593
4123
  var commandModule = {
3594
4124
  commandStack: ['type', CommandStack]
3595
4125
  };
@@ -3796,44 +4326,18 @@ ExternalLinkIcon.defaultProps = {
3796
4326
  fill: "none",
3797
4327
  xmlns: "http://www.w3.org/2000/svg"
3798
4328
  };
3799
- var FeelRequiredIcon = function FeelRequiredIcon(props) {
3800
- return jsxRuntime.jsxs("svg", {
3801
- ...props,
3802
- children: [jsxRuntime.jsx("path", {
3803
- d: "M5.8 7.06V5.95h4.307v1.11H5.8Zm0 3.071v-1.11h4.307v1.11H5.8Z",
3804
- fill: "currentColor"
3805
- }), jsxRuntime.jsx("path", {
3806
- fillRule: "evenodd",
3807
- clipRule: "evenodd",
3808
- d: "M8 3.268A4.732 4.732 0 1 0 12.732 8H14a6 6 0 1 1-6-6v1.268Z",
3809
- fill: "currentColor"
3810
- }), jsxRuntime.jsx("path", {
3811
- d: "m11.28 6.072-.832-.56 1.016-1.224L10 3.848l.312-.912 1.392.584L11.632 2h1.032l-.072 1.52 1.392-.584.312.912-1.464.44 1.008 1.224-.832.552-.864-1.296-.864 1.304Z",
3812
- fill: "currentColor"
3813
- })]
3814
- });
3815
- };
3816
- FeelRequiredIcon.defaultProps = {
3817
- viewBox: "0 0 16 16",
3818
- fill: "none",
3819
- xmlns: "http://www.w3.org/2000/svg"
3820
- };
3821
- var FeelOptionalIcon = function FeelOptionalIcon(props) {
3822
- return jsxRuntime.jsxs("svg", {
4329
+ var FeelIcon$1 = function FeelIcon(props) {
4330
+ return jsxRuntime.jsx("svg", {
3823
4331
  ...props,
3824
- children: [jsxRuntime.jsx("path", {
3825
- d: "M5.845 7.04V5.93h4.307v1.11H5.845Zm0 3.07V9h4.307v1.11H5.845Z",
3826
- fill: "currentColor"
3827
- }), jsxRuntime.jsx("path", {
3828
- fillRule: "evenodd",
3829
- clipRule: "evenodd",
3830
- d: "M3.286 8a4.714 4.714 0 1 0 9.428 0 4.714 4.714 0 0 0-9.428 0ZM8 2a6 6 0 1 0 0 12A6 6 0 0 0 8 2Z",
3831
- fill: "currentColor"
3832
- })]
4332
+ children: jsxRuntime.jsx("path", {
4333
+ d: "M3.617 11.99c-.137.684-.392 1.19-.765 1.518-.362.328-.882.492-1.558.492H0l.309-1.579h1.264l1.515-7.64h-.912l.309-1.579h.911l.236-1.191c.137-.685.387-1.192.75-1.52C4.753.164 5.277 0 5.953 0h1.294L6.94 1.579H5.675l-.323 1.623h1.264l-.309 1.579H5.043l-1.426 7.208ZM5.605 11.021l3.029-4.155L7.28 3.202h2.073l.706 2.547h.176l1.691-2.547H14l-3.014 4.051 1.338 3.768H10.25l-.706-2.606H9.37L7.678 11.02H5.605Z",
4334
+ fill: "currentcolor"
4335
+ })
3833
4336
  });
3834
4337
  };
3835
- FeelOptionalIcon.defaultProps = {
3836
- viewBox: "0 0 16 16",
4338
+ FeelIcon$1.defaultProps = {
4339
+ width: "14",
4340
+ height: "14",
3837
4341
  fill: "none",
3838
4342
  xmlns: "http://www.w3.org/2000/svg"
3839
4343
  };
@@ -3935,13 +4439,13 @@ const LayoutContext = preact.createContext({
3935
4439
  function useDescriptionContext(id, element) {
3936
4440
  const {
3937
4441
  getDescriptionForId
3938
- } = hooks$1.useContext(DescriptionContext);
4442
+ } = hooks.useContext(DescriptionContext);
3939
4443
  return getDescriptionForId(id, element);
3940
4444
  }
3941
4445
  function useError(id) {
3942
4446
  const {
3943
4447
  errors
3944
- } = hooks$1.useContext(ErrorsContext);
4448
+ } = hooks.useContext(ErrorsContext);
3945
4449
  return errors[id];
3946
4450
  }
3947
4451
 
@@ -3952,13 +4456,13 @@ function useError(id) {
3952
4456
  * @param {Function} callback
3953
4457
  */
3954
4458
  function useEvent(event, callback, eventBus) {
3955
- const eventContext = hooks$1.useContext(EventContext);
4459
+ const eventContext = hooks.useContext(EventContext);
3956
4460
  if (!eventBus) {
3957
4461
  ({
3958
4462
  eventBus
3959
4463
  } = eventContext);
3960
4464
  }
3961
- const didMount = hooks$1.useRef(false);
4465
+ const didMount = hooks.useRef(false);
3962
4466
 
3963
4467
  // (1) subscribe immediately
3964
4468
  if (eventBus && !didMount.current) {
@@ -3966,7 +4470,7 @@ function useEvent(event, callback, eventBus) {
3966
4470
  }
3967
4471
 
3968
4472
  // (2) update subscription after inputs changed
3969
- hooks$1.useEffect(() => {
4473
+ hooks.useEffect(() => {
3970
4474
  if (eventBus && didMount.current) {
3971
4475
  eventBus.on(event, callback);
3972
4476
  }
@@ -3998,9 +4502,9 @@ function useLayoutState(path, defaultValue) {
3998
4502
  const {
3999
4503
  getLayoutForKey,
4000
4504
  setLayoutForKey
4001
- } = hooks$1.useContext(LayoutContext);
4505
+ } = hooks.useContext(LayoutContext);
4002
4506
  const layoutForKey = getLayoutForKey(path, defaultValue);
4003
- const setState = hooks$1.useCallback(newValue => {
4507
+ const setState = hooks.useCallback(newValue => {
4004
4508
  setLayoutForKey(path, newValue);
4005
4509
  }, [setLayoutForKey]);
4006
4510
  return [layoutForKey, setState];
@@ -4014,8 +4518,8 @@ function useLayoutState(path, defaultValue) {
4014
4518
  */
4015
4519
 
4016
4520
  function usePrevious(value) {
4017
- const ref = hooks$1.useRef();
4018
- hooks$1.useEffect(() => {
4521
+ const ref = hooks.useRef();
4522
+ hooks.useEffect(() => {
4019
4523
  ref.current = value;
4020
4524
  });
4021
4525
  return ref.current;
@@ -4031,10 +4535,10 @@ function usePrevious(value) {
4031
4535
  function useShowEntryEvent(id) {
4032
4536
  const {
4033
4537
  onShow
4034
- } = hooks$1.useContext(LayoutContext);
4035
- const ref = hooks$1.useRef();
4036
- const focus = hooks$1.useRef(false);
4037
- const onShowEntry = hooks$1.useCallback(event => {
4538
+ } = hooks.useContext(LayoutContext);
4539
+ const ref = hooks.useRef();
4540
+ const focus = hooks.useRef(false);
4541
+ const onShowEntry = hooks.useCallback(event => {
4038
4542
  if (event.id === id) {
4039
4543
  onShow();
4040
4544
  if (!focus.current) {
@@ -4042,7 +4546,7 @@ function useShowEntryEvent(id) {
4042
4546
  }
4043
4547
  }
4044
4548
  }, [id]);
4045
- hooks$1.useEffect(() => {
4549
+ hooks.useEffect(() => {
4046
4550
  if (focus.current && ref.current) {
4047
4551
  if (minDash.isFunction(ref.current.focus)) {
4048
4552
  ref.current.focus();
@@ -4073,40 +4577,55 @@ function useShowEntryEvent(id) {
4073
4577
  * @param {setSticky} setSticky
4074
4578
  */
4075
4579
  function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
4076
- hooks$1.useEffect(() => {
4580
+ const [scrollContainer, setScrollContainer] = hooks.useState(minDom.query(scrollContainerSelector));
4581
+ const updateScrollContainer = hooks.useCallback(() => {
4582
+ const newScrollContainer = minDom.query(scrollContainerSelector);
4583
+ if (newScrollContainer !== scrollContainer) {
4584
+ setScrollContainer(newScrollContainer);
4585
+ }
4586
+ }, [scrollContainerSelector, scrollContainer]);
4587
+ hooks.useEffect(() => {
4588
+ updateScrollContainer();
4589
+ }, [updateScrollContainer]);
4590
+ useEvent('propertiesPanel.attach', updateScrollContainer);
4591
+ useEvent('propertiesPanel.detach', updateScrollContainer);
4592
+ hooks.useEffect(() => {
4077
4593
  const Observer = IntersectionObserver;
4078
4594
 
4079
4595
  // return early if IntersectionObserver is not available
4080
4596
  if (!Observer) {
4081
4597
  return;
4082
4598
  }
4083
- let observer;
4084
- if (ref.current) {
4085
- const scrollContainer = minDom.query(scrollContainerSelector);
4086
- observer = new Observer(entries => {
4087
- entries.forEach(entry => {
4088
- if (entry.intersectionRatio < 1) {
4089
- setSticky(true);
4090
- } else if (entry.intersectionRatio === 1) {
4091
- setSticky(false);
4092
- }
4093
- });
4094
- }, {
4095
- root: scrollContainer,
4096
- rootMargin: '0px 0px 999999% 0px',
4097
- // Use bottom margin to avoid stickyness when scrolling out to bottom
4098
- threshold: [1]
4099
- });
4100
- observer.observe(ref.current);
4599
+
4600
+ // TODO(@barmac): test this
4601
+ if (!ref.current || !scrollContainer) {
4602
+ return;
4101
4603
  }
4604
+ const observer = new Observer(entries => {
4605
+ // scroll container is unmounted, do not update sticky state
4606
+ if (scrollContainer.scrollHeight === 0) {
4607
+ return;
4608
+ }
4609
+ entries.forEach(entry => {
4610
+ if (entry.intersectionRatio < 1) {
4611
+ setSticky(true);
4612
+ } else if (entry.intersectionRatio === 1) {
4613
+ setSticky(false);
4614
+ }
4615
+ });
4616
+ }, {
4617
+ root: scrollContainer,
4618
+ rootMargin: '0px 0px 999999% 0px',
4619
+ // Use bottom margin to avoid stickyness when scrolling out to bottom
4620
+ threshold: [1]
4621
+ });
4622
+ observer.observe(ref.current);
4102
4623
 
4103
4624
  // Unobserve if unmounted
4104
4625
  return () => {
4105
- if (ref.current && observer) {
4106
- observer.unobserve(ref.current);
4107
- }
4626
+ observer.unobserve(ref.current);
4108
4627
  };
4109
- }, [ref, scrollContainerSelector, setSticky]);
4628
+ }, [ref.current, scrollContainer, setSticky]);
4110
4629
  }
4111
4630
 
4112
4631
  /**
@@ -4124,9 +4643,9 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
4124
4643
  * @returns {Function} static function reference
4125
4644
  */
4126
4645
  function useStaticCallback(callback) {
4127
- const callbackRef = hooks$1.useRef(callback);
4646
+ const callbackRef = hooks.useRef(callback);
4128
4647
  callbackRef.current = callback;
4129
- return hooks$1.useCallback((...args) => callbackRef.current(...args), []);
4648
+ return hooks.useCallback((...args) => callbackRef.current(...args), []);
4130
4649
  }
4131
4650
  function Group(props) {
4132
4651
  const {
@@ -4136,15 +4655,15 @@ function Group(props) {
4136
4655
  label,
4137
4656
  shouldOpen = false
4138
4657
  } = props;
4139
- const groupRef = hooks$1.useRef(null);
4658
+ const groupRef = hooks.useRef(null);
4140
4659
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], shouldOpen);
4141
- const onShow = hooks$1.useCallback(() => setOpen(true), [setOpen]);
4660
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
4142
4661
  const toggleOpen = () => setOpen(!open);
4143
- const [edited, setEdited] = hooks$1.useState(false);
4144
- const [sticky, setSticky] = hooks$1.useState(false);
4662
+ const [edited, setEdited] = hooks.useState(false);
4663
+ const [sticky, setSticky] = hooks.useState(false);
4145
4664
 
4146
4665
  // set edited state depending on all entries
4147
- hooks$1.useEffect(() => {
4666
+ hooks.useEffect(() => {
4148
4667
  const hasOneEditedEntry = entries.find(entry => {
4149
4668
  const {
4150
4669
  id,
@@ -4163,7 +4682,7 @@ function Group(props) {
4163
4682
  // set css class when group is sticky to top
4164
4683
  useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
4165
4684
  const propertiesPanelContext = {
4166
- ...hooks$1.useContext(LayoutContext),
4685
+ ...hooks.useContext(LayoutContext),
4167
4686
  onShow
4168
4687
  };
4169
4688
  return jsxRuntime.jsxs("div", {
@@ -4239,9 +4758,7 @@ function Placeholder(props) {
4239
4758
  })
4240
4759
  });
4241
4760
  }
4242
- const DEFAULT_LAYOUT = {
4243
- open: true
4244
- };
4761
+ const DEFAULT_LAYOUT = {};
4245
4762
  const DEFAULT_DESCRIPTION = {};
4246
4763
 
4247
4764
  /**
@@ -4325,14 +4842,14 @@ function PropertiesPanel(props) {
4325
4842
  } = props;
4326
4843
 
4327
4844
  // set-up layout context
4328
- const [layout, setLayout] = hooks$1.useState(createLayout(layoutConfig));
4845
+ const [layout, setLayout] = hooks.useState(createLayout(layoutConfig));
4329
4846
 
4330
4847
  // react to external changes in the layout config
4331
- useUpdateEffect(() => {
4848
+ useUpdateLayoutEffect(() => {
4332
4849
  const newLayout = createLayout(layoutConfig);
4333
4850
  setLayout(newLayout);
4334
4851
  }, [layoutConfig]);
4335
- hooks$1.useEffect(() => {
4852
+ hooks.useEffect(() => {
4336
4853
  if (typeof layoutChanged === 'function') {
4337
4854
  layoutChanged(layout);
4338
4855
  }
@@ -4353,8 +4870,8 @@ function PropertiesPanel(props) {
4353
4870
  };
4354
4871
 
4355
4872
  // set-up description context
4356
- const description = hooks$1.useMemo(() => createDescriptionContext(descriptionConfig), [descriptionConfig]);
4357
- hooks$1.useEffect(() => {
4873
+ const description = hooks.useMemo(() => createDescriptionContext(descriptionConfig), [descriptionConfig]);
4874
+ hooks.useEffect(() => {
4358
4875
  if (typeof descriptionLoaded === 'function') {
4359
4876
  descriptionLoaded(description);
4360
4877
  }
@@ -4366,7 +4883,7 @@ function PropertiesPanel(props) {
4366
4883
  description,
4367
4884
  getDescriptionForId
4368
4885
  };
4369
- const [errors, setErrors] = hooks$1.useState({});
4886
+ const [errors, setErrors] = hooks.useState({});
4370
4887
  const onSetErrors = ({
4371
4888
  errors
4372
4889
  }) => setErrors(errors);
@@ -4405,7 +4922,7 @@ function PropertiesPanel(props) {
4405
4922
  children: jsxRuntime.jsx(EventContext.Provider, {
4406
4923
  value: eventContext,
4407
4924
  children: jsxRuntime.jsxs("div", {
4408
- class: classnames('bio-properties-panel', layout.open ? 'open' : ''),
4925
+ class: "bio-properties-panel",
4409
4926
  children: [jsxRuntime.jsx(Header, {
4410
4927
  element: element,
4411
4928
  headerProvider: headerProvider
@@ -4449,14 +4966,14 @@ function createDescriptionContext(overrides = {}) {
4449
4966
  // hooks //////////////////
4450
4967
 
4451
4968
  /**
4452
- * This hook behaves like useEffect, but does not trigger on the first render.
4969
+ * This hook behaves like useLayoutEffect, but does not trigger on the first render.
4453
4970
  *
4454
4971
  * @param {Function} effect
4455
4972
  * @param {Array} deps
4456
4973
  */
4457
- function useUpdateEffect(effect, deps) {
4458
- const isMounted = hooks$1.useRef(false);
4459
- hooks$1.useEffect(() => {
4974
+ function useUpdateLayoutEffect(effect, deps) {
4975
+ const isMounted = hooks.useRef(false);
4976
+ hooks.useLayoutEffect(() => {
4460
4977
  if (isMounted.current) {
4461
4978
  return effect();
4462
4979
  } else {
@@ -4473,14 +4990,14 @@ function CollapsibleEntry(props) {
4473
4990
  open: shouldOpen,
4474
4991
  remove
4475
4992
  } = props;
4476
- const [open, setOpen] = hooks$1.useState(shouldOpen);
4993
+ const [open, setOpen] = hooks.useState(shouldOpen);
4477
4994
  const toggleOpen = () => setOpen(!open);
4478
4995
  const {
4479
4996
  onShow
4480
- } = hooks$1.useContext(LayoutContext);
4997
+ } = hooks.useContext(LayoutContext);
4481
4998
  const propertiesPanelContext = {
4482
- ...hooks$1.useContext(LayoutContext),
4483
- onShow: hooks$1.useCallback(() => {
4999
+ ...hooks.useContext(LayoutContext),
5000
+ onShow: hooks.useCallback(() => {
4484
5001
  setOpen(true);
4485
5002
  if (minDash.isFunction(onShow)) {
4486
5003
  onShow();
@@ -4538,7 +5055,7 @@ function ListItem(props) {
4538
5055
  } = props;
4539
5056
 
4540
5057
  // focus specified entry on auto open
4541
- hooks$1.useEffect(() => {
5058
+ hooks.useEffect(() => {
4542
5059
  if (autoOpen && autoFocusEntry) {
4543
5060
  const entry = minDom.query(`[data-entry-id="${autoFocusEntry}"]`);
4544
5061
  const focusableInput = minDom.query('.bio-properties-panel-input', entry);
@@ -4574,15 +5091,15 @@ function ListGroup(props) {
4574
5091
  shouldOpen = true,
4575
5092
  shouldSort = true
4576
5093
  } = props;
4577
- const groupRef = hooks$1.useRef(null);
5094
+ const groupRef = hooks.useRef(null);
4578
5095
  const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
4579
- const [sticky, setSticky] = hooks$1.useState(false);
4580
- const onShow = hooks$1.useCallback(() => setOpen(true), [setOpen]);
4581
- const [ordering, setOrdering] = hooks$1.useState([]);
4582
- const [newItemAdded, setNewItemAdded] = hooks$1.useState(false);
5096
+ const [sticky, setSticky] = hooks.useState(false);
5097
+ const onShow = hooks.useCallback(() => setOpen(true), [setOpen]);
5098
+ const [ordering, setOrdering] = hooks.useState([]);
5099
+ const [newItemAdded, setNewItemAdded] = hooks.useState(false);
4583
5100
 
4584
5101
  // Flag to mark that add button was clicked in the last render cycle
4585
- const [addTriggered, setAddTriggered] = hooks$1.useState(false);
5102
+ const [addTriggered, setAddTriggered] = hooks.useState(false);
4586
5103
  const prevItems = usePrevious(items);
4587
5104
  const prevElement = usePrevious(element);
4588
5105
  const elementChanged = element !== prevElement;
@@ -4596,14 +5113,14 @@ function ListGroup(props) {
4596
5113
  // keep ordering in sync to items - and open changes
4597
5114
 
4598
5115
  // (0) set initial ordering from given items
4599
- hooks$1.useEffect(() => {
5116
+ hooks.useEffect(() => {
4600
5117
  if (!prevItems || !shouldSort) {
4601
5118
  setOrdering(createOrdering(items));
4602
5119
  }
4603
5120
  }, [items, element]);
4604
5121
 
4605
5122
  // (1) items were added
4606
- hooks$1.useEffect(() => {
5123
+ hooks.useEffect(() => {
4607
5124
  // reset addTriggered flag
4608
5125
  setAddTriggered(false);
4609
5126
  if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
@@ -4644,14 +5161,14 @@ function ListGroup(props) {
4644
5161
  }, [items, open, shouldHandleEffects, addTriggered]);
4645
5162
 
4646
5163
  // (2) sort items on open if shouldSort is set
4647
- hooks$1.useEffect(() => {
5164
+ hooks.useEffect(() => {
4648
5165
  if (shouldSort && open && !newItemAdded) {
4649
5166
  setOrdering(createOrdering(sortItems(items)));
4650
5167
  }
4651
5168
  }, [open, shouldSort]);
4652
5169
 
4653
5170
  // (3) items were deleted
4654
- hooks$1.useEffect(() => {
5171
+ hooks.useEffect(() => {
4655
5172
  if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
4656
5173
  let keep = [];
4657
5174
  ordering.forEach(o => {
@@ -4668,7 +5185,7 @@ function ListGroup(props) {
4668
5185
  const toggleOpen = () => setOpen(!open);
4669
5186
  const hasItems = !!items.length;
4670
5187
  const propertiesPanelContext = {
4671
- ...hooks$1.useContext(LayoutContext),
5188
+ ...hooks.useContext(LayoutContext),
4672
5189
  onShow
4673
5190
  };
4674
5191
  const handleAddClick = e => {
@@ -4776,7 +5293,7 @@ function Checkbox(props) {
4776
5293
  onFocus,
4777
5294
  onBlur
4778
5295
  } = props;
4779
- const [localValue, setLocalValue] = hooks$1.useState(value);
5296
+ const [localValue, setLocalValue] = hooks.useState(value);
4780
5297
  const handleChangeCallback = ({
4781
5298
  target
4782
5299
  }) => {
@@ -4786,7 +5303,7 @@ function Checkbox(props) {
4786
5303
  handleChangeCallback(e);
4787
5304
  setLocalValue(e.target.value);
4788
5305
  };
4789
- hooks$1.useEffect(() => {
5306
+ hooks.useEffect(() => {
4790
5307
  if (value === localValue) {
4791
5308
  return;
4792
5309
  }
@@ -4871,8 +5388,8 @@ function prefixId$7(id) {
4871
5388
  return `bio-properties-panel-${id}`;
4872
5389
  }
4873
5390
  const useBufferedFocus$1 = function (editor, ref) {
4874
- const [buffer, setBuffer] = hooks$1.useState(undefined);
4875
- ref.current = hooks$1.useMemo(() => ({
5391
+ const [buffer, setBuffer] = hooks.useState(undefined);
5392
+ ref.current = hooks.useMemo(() => ({
4876
5393
  focus: offset => {
4877
5394
  if (editor) {
4878
5395
  editor.focus(offset);
@@ -4884,7 +5401,7 @@ const useBufferedFocus$1 = function (editor, ref) {
4884
5401
  }
4885
5402
  }
4886
5403
  }), [editor]);
4887
- hooks$1.useEffect(() => {
5404
+ hooks.useEffect(() => {
4888
5405
  if (typeof buffer !== 'undefined' && editor) {
4889
5406
  editor.focus(buffer);
4890
5407
  setBuffer(false);
@@ -4903,15 +5420,15 @@ const CodeEditor$1 = React.forwardRef((props, ref) => {
4903
5420
  hostLanguage = null,
4904
5421
  singleLine = false
4905
5422
  } = props;
4906
- const inputRef = hooks$1.useRef();
4907
- const [editor, setEditor] = hooks$1.useState();
4908
- const [localValue, setLocalValue] = hooks$1.useState(value || '');
5423
+ const inputRef = hooks.useRef();
5424
+ const [editor, setEditor] = hooks.useState();
5425
+ const [localValue, setLocalValue] = hooks.useState(value || '');
4909
5426
  useBufferedFocus$1(editor, ref);
4910
5427
  const handleInput = useStaticCallback(newValue => {
4911
5428
  onInput(newValue);
4912
5429
  setLocalValue(newValue);
4913
5430
  });
4914
- hooks$1.useEffect(() => {
5431
+ hooks.useEffect(() => {
4915
5432
  let editor;
4916
5433
  editor = new feelers.FeelersEditor({
4917
5434
  container: inputRef.current,
@@ -4931,7 +5448,7 @@ const CodeEditor$1 = React.forwardRef((props, ref) => {
4931
5448
  setEditor(null);
4932
5449
  };
4933
5450
  }, []);
4934
- hooks$1.useEffect(() => {
5451
+ hooks.useEffect(() => {
4935
5452
  if (!editor) {
4936
5453
  return;
4937
5454
  }
@@ -4952,8 +5469,8 @@ const CodeEditor$1 = React.forwardRef((props, ref) => {
4952
5469
  });
4953
5470
  });
4954
5471
  const useBufferedFocus = function (editor, ref) {
4955
- const [buffer, setBuffer] = hooks$1.useState(undefined);
4956
- ref.current = hooks$1.useMemo(() => ({
5472
+ const [buffer, setBuffer] = hooks.useState(undefined);
5473
+ ref.current = hooks.useMemo(() => ({
4957
5474
  focus: offset => {
4958
5475
  if (editor) {
4959
5476
  editor.focus(offset);
@@ -4965,7 +5482,7 @@ const useBufferedFocus = function (editor, ref) {
4965
5482
  }
4966
5483
  }
4967
5484
  }), [editor]);
4968
- hooks$1.useEffect(() => {
5485
+ hooks.useEffect(() => {
4969
5486
  if (typeof buffer !== 'undefined' && editor) {
4970
5487
  editor.focus(buffer);
4971
5488
  setBuffer(false);
@@ -4982,15 +5499,15 @@ const CodeEditor = React.forwardRef((props, ref) => {
4982
5499
  tooltipContainer,
4983
5500
  variables
4984
5501
  } = props;
4985
- const inputRef = hooks$1.useRef();
4986
- const [editor, setEditor] = hooks$1.useState();
4987
- const [localValue, setLocalValue] = hooks$1.useState(value || '');
5502
+ const inputRef = hooks.useRef();
5503
+ const [editor, setEditor] = hooks.useState();
5504
+ const [localValue, setLocalValue] = hooks.useState(value || '');
4988
5505
  useBufferedFocus(editor, ref);
4989
5506
  const handleInput = useStaticCallback(newValue => {
4990
5507
  onInput(newValue);
4991
5508
  setLocalValue(newValue);
4992
5509
  });
4993
- hooks$1.useEffect(() => {
5510
+ hooks.useEffect(() => {
4994
5511
  let editor;
4995
5512
 
4996
5513
  /* Trigger FEEL toggle when
@@ -5024,7 +5541,7 @@ const CodeEditor = React.forwardRef((props, ref) => {
5024
5541
  setEditor(null);
5025
5542
  };
5026
5543
  }, []);
5027
- hooks$1.useEffect(() => {
5544
+ hooks.useEffect(() => {
5028
5545
  if (!editor) {
5029
5546
  return;
5030
5547
  }
@@ -5034,7 +5551,7 @@ const CodeEditor = React.forwardRef((props, ref) => {
5034
5551
  editor.setValue(value);
5035
5552
  setLocalValue(value);
5036
5553
  }, [value]);
5037
- hooks$1.useEffect(() => {
5554
+ hooks.useEffect(() => {
5038
5555
  if (!editor) {
5039
5556
  return;
5040
5557
  }
@@ -5074,14 +5591,13 @@ const noop$2 = () => {};
5074
5591
  */
5075
5592
  function FeelIcon(props) {
5076
5593
  const {
5077
- label,
5078
5594
  feel = false,
5079
5595
  active,
5080
5596
  disabled = false,
5081
5597
  onClick = noop$2
5082
5598
  } = props;
5083
- const feelRequiredLabel = ' must be a FEEL expression';
5084
- const feelOptionalLabel = ' can optionally be a FEEL expression';
5599
+ const feelRequiredLabel = 'FEEL expression is mandatory';
5600
+ const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
5085
5601
  const handleClick = e => {
5086
5602
  onClick(e);
5087
5603
 
@@ -5094,10 +5610,124 @@ function FeelIcon(props) {
5094
5610
  class: classnames('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
5095
5611
  onClick: handleClick,
5096
5612
  disabled: feel === 'required' || disabled,
5097
- title: label + (feel === 'required' ? feelRequiredLabel : feelOptionalLabel),
5098
- children: feel === 'required' ? jsxRuntime.jsx(FeelRequiredIcon, {}) : jsxRuntime.jsx(FeelOptionalIcon, {})
5613
+ title: feel === 'required' ? feelRequiredLabel : feelOptionalLabel,
5614
+ children: jsxRuntime.jsx(FeelIcon$1, {})
5615
+ });
5616
+ }
5617
+ function ToggleSwitch(props) {
5618
+ const {
5619
+ id,
5620
+ label,
5621
+ onInput,
5622
+ value,
5623
+ switcherLabel,
5624
+ inline,
5625
+ onFocus,
5626
+ onBlur,
5627
+ inputRef
5628
+ } = props;
5629
+ const [localValue, setLocalValue] = hooks.useState(value);
5630
+ const handleInputCallback = async () => {
5631
+ onInput(!value);
5632
+ };
5633
+ const handleInput = e => {
5634
+ handleInputCallback();
5635
+ setLocalValue(e.target.value);
5636
+ };
5637
+ hooks.useEffect(() => {
5638
+ if (value === localValue) {
5639
+ return;
5640
+ }
5641
+ setLocalValue(value);
5642
+ }, [value]);
5643
+ return jsxRuntime.jsxs("div", {
5644
+ class: classnames('bio-properties-panel-toggle-switch', {
5645
+ inline
5646
+ }),
5647
+ children: [jsxRuntime.jsx("label", {
5648
+ class: "bio-properties-panel-label",
5649
+ for: prefixId$6(id),
5650
+ children: label
5651
+ }), jsxRuntime.jsxs("div", {
5652
+ class: "bio-properties-panel-field-wrapper",
5653
+ children: [jsxRuntime.jsxs("label", {
5654
+ class: "bio-properties-panel-toggle-switch__switcher",
5655
+ children: [jsxRuntime.jsx("input", {
5656
+ ref: inputRef,
5657
+ id: prefixId$6(id),
5658
+ class: "bio-properties-panel-input",
5659
+ type: "checkbox",
5660
+ onFocus: onFocus,
5661
+ onBlur: onBlur,
5662
+ name: id,
5663
+ onInput: handleInput,
5664
+ checked: !!localValue
5665
+ }), jsxRuntime.jsx("span", {
5666
+ class: "bio-properties-panel-toggle-switch__slider"
5667
+ })]
5668
+ }), switcherLabel && jsxRuntime.jsx("p", {
5669
+ class: "bio-properties-panel-toggle-switch__label",
5670
+ children: switcherLabel
5671
+ })]
5672
+ })]
5673
+ });
5674
+ }
5675
+
5676
+ /**
5677
+ * @param {Object} props
5678
+ * @param {Object} props.element
5679
+ * @param {String} props.id
5680
+ * @param {String} props.description
5681
+ * @param {String} props.label
5682
+ * @param {String} props.switcherLabel
5683
+ * @param {Boolean} props.inline
5684
+ * @param {Function} props.getValue
5685
+ * @param {Function} props.setValue
5686
+ * @param {Function} props.onFocus
5687
+ * @param {Function} props.onBlur
5688
+ */
5689
+ function ToggleSwitchEntry(props) {
5690
+ const {
5691
+ element,
5692
+ id,
5693
+ description,
5694
+ label,
5695
+ switcherLabel,
5696
+ inline,
5697
+ getValue,
5698
+ setValue,
5699
+ onFocus,
5700
+ onBlur
5701
+ } = props;
5702
+ const value = getValue(element);
5703
+ return jsxRuntime.jsxs("div", {
5704
+ class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
5705
+ "data-entry-id": id,
5706
+ children: [jsxRuntime.jsx(ToggleSwitch, {
5707
+ id: id,
5708
+ label: label,
5709
+ value: value,
5710
+ onInput: setValue,
5711
+ onFocus: onFocus,
5712
+ onBlur: onBlur,
5713
+ switcherLabel: switcherLabel,
5714
+ inline: inline
5715
+ }), jsxRuntime.jsx(Description$1, {
5716
+ forId: id,
5717
+ element: element,
5718
+ value: description
5719
+ })]
5099
5720
  });
5100
5721
  }
5722
+ function isEdited$7(node) {
5723
+ return node && !!node.checked;
5724
+ }
5725
+
5726
+ // helpers /////////////////
5727
+
5728
+ function prefixId$6(id) {
5729
+ return `bio-properties-panel-${id}`;
5730
+ }
5101
5731
  const noop$1 = () => {};
5102
5732
  function FeelTextfield(props) {
5103
5733
  const {
@@ -5113,12 +5743,12 @@ function FeelTextfield(props) {
5113
5743
  tooltipContainer,
5114
5744
  OptionalComponent = OptionalFeelInput
5115
5745
  } = props;
5116
- const [localValue, _setLocalValue] = hooks$1.useState(value);
5746
+ const [localValue, _setLocalValue] = hooks.useState(value);
5117
5747
  const editorRef = useShowEntryEvent(id);
5118
- const containerRef = hooks$1.useRef();
5119
- const feelActive = localValue.startsWith('=') || feel === 'required';
5120
- const feelOnlyValue = localValue.startsWith('=') ? localValue.substring(1) : localValue;
5121
- const [focus, _setFocus] = hooks$1.useState(undefined);
5748
+ const containerRef = hooks.useRef();
5749
+ const feelActive = minDash.isString(localValue) && localValue.startsWith('=') || feel === 'required';
5750
+ const feelOnlyValue = minDash.isString(localValue) && localValue.startsWith('=') ? localValue.substring(1) : localValue;
5751
+ const [focus, _setFocus] = hooks.useState(undefined);
5122
5752
  const setFocus = (offset = 0) => {
5123
5753
  const hasFocus = containerRef.current.contains(document.activeElement);
5124
5754
 
@@ -5126,7 +5756,7 @@ function FeelTextfield(props) {
5126
5756
  const position = hasFocus ? document.activeElement.selectionStart : Infinity;
5127
5757
  _setFocus(position + offset);
5128
5758
  };
5129
- const handleInputCallback = hooks$1.useMemo(() => {
5759
+ const handleInputCallback = hooks.useMemo(() => {
5130
5760
  return debounce(newValue => {
5131
5761
  onInput(newValue);
5132
5762
  });
@@ -5157,7 +5787,7 @@ function FeelTextfield(props) {
5157
5787
  return;
5158
5788
  }
5159
5789
  setLocalValue(newValue);
5160
- if (!feelActive && newValue.startsWith('=')) {
5790
+ if (!feelActive && minDash.isString(newValue) && newValue.startsWith('=')) {
5161
5791
  // focus is behind `=` sign that will be removed
5162
5792
  setFocus(-1);
5163
5793
  }
@@ -5171,13 +5801,13 @@ function FeelTextfield(props) {
5171
5801
  const message = `${error.source}: ${error.message}`;
5172
5802
  onError(message);
5173
5803
  });
5174
- hooks$1.useEffect(() => {
5804
+ hooks.useEffect(() => {
5175
5805
  if (typeof focus !== 'undefined') {
5176
5806
  editorRef.current.focus(focus);
5177
5807
  _setFocus(undefined);
5178
5808
  }
5179
5809
  }, [focus]);
5180
- hooks$1.useEffect(() => {
5810
+ hooks.useEffect(() => {
5181
5811
  if (value === localValue) {
5182
5812
  return;
5183
5813
  }
@@ -5191,7 +5821,7 @@ function FeelTextfield(props) {
5191
5821
  }, [value]);
5192
5822
 
5193
5823
  // copy-paste integration
5194
- hooks$1.useEffect(() => {
5824
+ hooks.useEffect(() => {
5195
5825
  const copyHandler = event => {
5196
5826
  if (!feelActive) {
5197
5827
  return;
@@ -5220,9 +5850,11 @@ function FeelTextfield(props) {
5220
5850
  };
5221
5851
  }, [containerRef, feelActive, handleFeelToggle, setFocus]);
5222
5852
  return jsxRuntime.jsxs("div", {
5223
- class: "bio-properties-panel-feel-entry",
5853
+ class: classnames('bio-properties-panel-feel-entry', {
5854
+ 'feel-active': feelActive
5855
+ }),
5224
5856
  children: [jsxRuntime.jsxs("label", {
5225
- for: prefixId$6(id),
5857
+ for: prefixId$5(id),
5226
5858
  class: "bio-properties-panel-label",
5227
5859
  onClick: () => setFocus(),
5228
5860
  children: [label, jsxRuntime.jsx(FeelIcon, {
@@ -5239,7 +5871,7 @@ function FeelTextfield(props) {
5239
5871
  disabled: feel !== 'optional' || disabled,
5240
5872
  onClick: handleFeelToggle
5241
5873
  }), feelActive ? jsxRuntime.jsx(CodeEditor, {
5242
- id: prefixId$6(id),
5874
+ id: prefixId$5(id),
5243
5875
  name: id,
5244
5876
  onInput: handleLocalInput,
5245
5877
  disabled: disabled,
@@ -5256,7 +5888,8 @@ function FeelTextfield(props) {
5256
5888
  ...props,
5257
5889
  onInput: handleLocalInput,
5258
5890
  contentAttributes: {
5259
- 'id': prefixId$6(id)
5891
+ 'id': prefixId$5(id),
5892
+ 'aria-label': label
5260
5893
  },
5261
5894
  value: localValue,
5262
5895
  ref: editorRef
@@ -5273,7 +5906,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
5273
5906
  onFocus,
5274
5907
  onBlur
5275
5908
  } = props;
5276
- const inputRef = hooks$1.useRef();
5909
+ const inputRef = hooks.useRef();
5277
5910
 
5278
5911
  // To be consistent with the FEEL editor, set focus at start of input
5279
5912
  // this ensures clean editing experience when switching with the keyboard
@@ -5293,7 +5926,7 @@ const OptionalFeelInput = React.forwardRef((props, ref) => {
5293
5926
  }
5294
5927
  };
5295
5928
  return jsxRuntime.jsx("input", {
5296
- id: prefixId$6(id),
5929
+ id: prefixId$5(id),
5297
5930
  type: "text",
5298
5931
  ref: inputRef,
5299
5932
  name: id,
@@ -5316,7 +5949,7 @@ React.forwardRef((props, ref) => {
5316
5949
  onFocus,
5317
5950
  onBlur
5318
5951
  } = props;
5319
- const inputRef = hooks$1.useRef();
5952
+ const inputRef = hooks.useRef();
5320
5953
 
5321
5954
  // To be consistent with the FEEL editor, set focus at start of input
5322
5955
  // this ensures clean editing experience when switching with the keyboard
@@ -5331,7 +5964,7 @@ React.forwardRef((props, ref) => {
5331
5964
  }
5332
5965
  };
5333
5966
  return jsxRuntime.jsx("textarea", {
5334
- id: prefixId$6(id),
5967
+ id: prefixId$5(id),
5335
5968
  type: "text",
5336
5969
  ref: inputRef,
5337
5970
  name: id,
@@ -5346,6 +5979,78 @@ React.forwardRef((props, ref) => {
5346
5979
  "data-gramm": "false"
5347
5980
  });
5348
5981
  });
5982
+ const OptionalFeelToggleSwitch = React.forwardRef((props, ref) => {
5983
+ const {
5984
+ id,
5985
+ onInput,
5986
+ value,
5987
+ onFocus,
5988
+ onBlur,
5989
+ switcherLabel
5990
+ } = props;
5991
+ const inputRef = hooks.useRef();
5992
+
5993
+ // To be consistent with the FEEL editor, set focus at start of input
5994
+ // this ensures clean editing experience when switching with the keyboard
5995
+ ref.current = {
5996
+ focus: () => {
5997
+ const input = inputRef.current;
5998
+ if (!input) {
5999
+ return;
6000
+ }
6001
+ input.focus();
6002
+ }
6003
+ };
6004
+ return jsxRuntime.jsx(ToggleSwitch, {
6005
+ id: id,
6006
+ value: value,
6007
+ inputRef: inputRef,
6008
+ onInput: onInput,
6009
+ onFocus: onFocus,
6010
+ onBlur: onBlur,
6011
+ switcherLabel: switcherLabel
6012
+ });
6013
+ });
6014
+ React.forwardRef((props, ref) => {
6015
+ const {
6016
+ id,
6017
+ disabled,
6018
+ onInput,
6019
+ value,
6020
+ onFocus,
6021
+ onBlur
6022
+ } = props;
6023
+ const inputRef = hooks.useRef();
6024
+ const handleChange = ({
6025
+ target
6026
+ }) => {
6027
+ onInput(target.checked);
6028
+ };
6029
+
6030
+ // To be consistent with the FEEL editor, set focus at start of input
6031
+ // this ensures clean editing experience when switching with the keyboard
6032
+ ref.current = {
6033
+ focus: () => {
6034
+ const input = inputRef.current;
6035
+ if (!input) {
6036
+ return;
6037
+ }
6038
+ input.focus();
6039
+ }
6040
+ };
6041
+ return jsxRuntime.jsx("input", {
6042
+ ref: inputRef,
6043
+ id: prefixId$5(id),
6044
+ name: id,
6045
+ onFocus: onFocus,
6046
+ onBlur: onBlur,
6047
+ type: "checkbox",
6048
+ class: "bio-properties-panel-input",
6049
+ onChange: handleChange,
6050
+ checked: value,
6051
+ disabled: disabled
6052
+ });
6053
+ });
5349
6054
 
5350
6055
  /**
5351
6056
  * @param {Object} props
@@ -5387,12 +6092,12 @@ function FeelEntry(props) {
5387
6092
  onFocus,
5388
6093
  onBlur
5389
6094
  } = props;
5390
- const [cachedInvalidValue, setCachedInvalidValue] = hooks$1.useState(null);
5391
- const [validationError, setValidationError] = hooks$1.useState(null);
5392
- const [localError, setLocalError] = hooks$1.useState(null);
6095
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
6096
+ const [validationError, setValidationError] = hooks.useState(null);
6097
+ const [localError, setLocalError] = hooks.useState(null);
5393
6098
  let value = getValue(element);
5394
6099
  const previousValue = usePrevious(value);
5395
- hooks$1.useEffect(() => {
6100
+ hooks.useEffect(() => {
5396
6101
  if (minDash.isFunction(validate)) {
5397
6102
  const newValidationError = validate(value) || null;
5398
6103
  setValidationError(newValidationError);
@@ -5413,7 +6118,7 @@ function FeelEntry(props) {
5413
6118
  }
5414
6119
  setValidationError(newValidationError);
5415
6120
  });
5416
- const onError = hooks$1.useCallback(err => {
6121
+ const onError = hooks.useCallback(err => {
5417
6122
  setLocalError(err);
5418
6123
  }, []);
5419
6124
  if (previousValue === value && validationError) {
@@ -5453,6 +6158,33 @@ function FeelEntry(props) {
5453
6158
  });
5454
6159
  }
5455
6160
 
6161
+ /**
6162
+ * @param {Object} props
6163
+ * @param {Object} props.element
6164
+ * @param {String} props.id
6165
+ * @param {String} props.description
6166
+ * @param {Boolean} props.debounce
6167
+ * @param {Boolean} props.disabled
6168
+ * @param {Boolean} props.feel
6169
+ * @param {String} props.label
6170
+ * @param {Function} props.getValue
6171
+ * @param {Function} props.setValue
6172
+ * @param {Function} props.tooltipContainer
6173
+ * @param {Function} props.validate
6174
+ * @param {Function} props.show
6175
+ * @param {Function} props.example
6176
+ * @param {Function} props.variables
6177
+ * @param {Function} props.onFocus
6178
+ * @param {Function} props.onBlur
6179
+ */
6180
+ function FeelToggleSwitchEntry(props) {
6181
+ return jsxRuntime.jsx(FeelEntry, {
6182
+ class: "bio-properties-panel-feel-toggle-switch",
6183
+ OptionalComponent: OptionalFeelToggleSwitch,
6184
+ ...props
6185
+ });
6186
+ }
6187
+
5456
6188
  /**
5457
6189
  * @param {Object} props
5458
6190
  * @param {Object} props.element
@@ -5481,13 +6213,19 @@ function FeelTemplatingEntry(props) {
5481
6213
  ...props
5482
6214
  });
5483
6215
  }
5484
- function isEdited$7(node) {
5485
- return node && (!!node.value || node.classList.contains('edited'));
6216
+ function isEdited$6(node) {
6217
+ if (!node) {
6218
+ return false;
6219
+ }
6220
+ if (node.type === 'checkbox') {
6221
+ return !!node.checked || node.classList.contains('edited');
6222
+ }
6223
+ return !!node.value || node.classList.contains('edited');
5486
6224
  }
5487
6225
 
5488
6226
  // helpers /////////////////
5489
6227
 
5490
- function prefixId$6(id) {
6228
+ function prefixId$5(id) {
5491
6229
  return `bio-properties-panel-${id}`;
5492
6230
  }
5493
6231
  function NumberField(props) {
@@ -5504,8 +6242,8 @@ function NumberField(props) {
5504
6242
  onFocus,
5505
6243
  onBlur
5506
6244
  } = props;
5507
- const [localValue, setLocalValue] = hooks$1.useState(value);
5508
- const handleInputCallback = hooks$1.useMemo(() => {
6245
+ const [localValue, setLocalValue] = hooks.useState(value);
6246
+ const handleInputCallback = hooks.useMemo(() => {
5509
6247
  return debounce(event => {
5510
6248
  const {
5511
6249
  validity,
@@ -5520,7 +6258,7 @@ function NumberField(props) {
5520
6258
  handleInputCallback(e);
5521
6259
  setLocalValue(e.target.value);
5522
6260
  };
5523
- hooks$1.useEffect(() => {
6261
+ hooks.useEffect(() => {
5524
6262
  if (value === localValue) {
5525
6263
  return;
5526
6264
  }
@@ -5529,11 +6267,11 @@ function NumberField(props) {
5529
6267
  return jsxRuntime.jsxs("div", {
5530
6268
  class: "bio-properties-panel-numberfield",
5531
6269
  children: [jsxRuntime.jsx("label", {
5532
- for: prefixId$5(id),
6270
+ for: prefixId$4(id),
5533
6271
  class: "bio-properties-panel-label",
5534
6272
  children: label
5535
6273
  }), jsxRuntime.jsx("input", {
5536
- id: prefixId$5(id),
6274
+ id: prefixId$4(id),
5537
6275
  type: "number",
5538
6276
  name: id,
5539
6277
  spellCheck: "false",
@@ -5585,12 +6323,12 @@ function NumberFieldEntry(props) {
5585
6323
  onBlur,
5586
6324
  validate
5587
6325
  } = props;
5588
- const [cachedInvalidValue, setCachedInvalidValue] = hooks$1.useState(null);
6326
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
5589
6327
  const globalError = useError(id);
5590
- const [localError, setLocalError] = hooks$1.useState(null);
6328
+ const [localError, setLocalError] = hooks.useState(null);
5591
6329
  let value = getValue(element);
5592
6330
  const previousValue = usePrevious(value);
5593
- hooks$1.useEffect(() => {
6331
+ hooks.useEffect(() => {
5594
6332
  if (minDash.isFunction(validate)) {
5595
6333
  const newValidationError = validate(value) || null;
5596
6334
  setLocalError(newValidationError);
@@ -5637,13 +6375,13 @@ function NumberFieldEntry(props) {
5637
6375
  })]
5638
6376
  });
5639
6377
  }
5640
- function isEdited$5(node) {
6378
+ function isEdited$4(node) {
5641
6379
  return node && !!node.value;
5642
6380
  }
5643
6381
 
5644
6382
  // helpers /////////////////
5645
6383
 
5646
- function prefixId$5(id) {
6384
+ function prefixId$4(id) {
5647
6385
  return `bio-properties-panel-${id}`;
5648
6386
  }
5649
6387
  function Select(props) {
@@ -5658,7 +6396,7 @@ function Select(props) {
5658
6396
  onBlur
5659
6397
  } = props;
5660
6398
  const ref = useShowEntryEvent(id);
5661
- const [localValue, setLocalValue] = hooks$1.useState(value);
6399
+ const [localValue, setLocalValue] = hooks.useState(value);
5662
6400
  const handleChangeCallback = ({
5663
6401
  target
5664
6402
  }) => {
@@ -5668,7 +6406,7 @@ function Select(props) {
5668
6406
  handleChangeCallback(e);
5669
6407
  setLocalValue(e.target.value);
5670
6408
  };
5671
- hooks$1.useEffect(() => {
6409
+ hooks.useEffect(() => {
5672
6410
  if (value === localValue) {
5673
6411
  return;
5674
6412
  }
@@ -5677,12 +6415,12 @@ function Select(props) {
5677
6415
  return jsxRuntime.jsxs("div", {
5678
6416
  class: "bio-properties-panel-select",
5679
6417
  children: [jsxRuntime.jsx("label", {
5680
- for: prefixId$4(id),
6418
+ for: prefixId$3(id),
5681
6419
  class: "bio-properties-panel-label",
5682
6420
  children: label
5683
6421
  }), jsxRuntime.jsx("select", {
5684
6422
  ref: ref,
5685
- id: prefixId$4(id),
6423
+ id: prefixId$3(id),
5686
6424
  name: id,
5687
6425
  class: "bio-properties-panel-input",
5688
6426
  onInput: handleChange,
@@ -5740,12 +6478,12 @@ function SelectEntry(props) {
5740
6478
  validate
5741
6479
  } = props;
5742
6480
  const options = getOptions(element);
5743
- const [cachedInvalidValue, setCachedInvalidValue] = hooks$1.useState(null);
6481
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
5744
6482
  const globalError = useError(id);
5745
- const [localError, setLocalError] = hooks$1.useState(null);
6483
+ const [localError, setLocalError] = hooks.useState(null);
5746
6484
  let value = getValue(element);
5747
6485
  const previousValue = usePrevious(value);
5748
- hooks$1.useEffect(() => {
6486
+ hooks.useEffect(() => {
5749
6487
  if (minDash.isFunction(validate)) {
5750
6488
  const newValidationError = validate(value) || null;
5751
6489
  setLocalError(newValidationError);
@@ -5789,13 +6527,13 @@ function SelectEntry(props) {
5789
6527
  })]
5790
6528
  });
5791
6529
  }
5792
- function isEdited$4(node) {
6530
+ function isEdited$3(node) {
5793
6531
  return node && !!node.value;
5794
6532
  }
5795
6533
 
5796
6534
  // helpers /////////////////
5797
6535
 
5798
- function prefixId$4(id) {
6536
+ function prefixId$3(id) {
5799
6537
  return `bio-properties-panel-${id}`;
5800
6538
  }
5801
6539
  function resizeToContents(element) {
@@ -5819,9 +6557,9 @@ function TextArea(props) {
5819
6557
  autoResize,
5820
6558
  rows = autoResize ? 1 : 2
5821
6559
  } = props;
5822
- const [localValue, setLocalValue] = hooks$1.useState(value);
6560
+ const [localValue, setLocalValue] = hooks.useState(value);
5823
6561
  const ref = useShowEntryEvent(id);
5824
- const handleInputCallback = hooks$1.useMemo(() => {
6562
+ const handleInputCallback = hooks.useMemo(() => {
5825
6563
  return debounce(({
5826
6564
  target
5827
6565
  }) => onInput(target.value.length ? target.value : undefined));
@@ -5831,10 +6569,10 @@ function TextArea(props) {
5831
6569
  autoResize && resizeToContents(e.target);
5832
6570
  setLocalValue(e.target.value);
5833
6571
  };
5834
- hooks$1.useLayoutEffect(() => {
6572
+ hooks.useLayoutEffect(() => {
5835
6573
  autoResize && resizeToContents(ref.current);
5836
6574
  }, []);
5837
- hooks$1.useEffect(() => {
6575
+ hooks.useEffect(() => {
5838
6576
  if (value === localValue) {
5839
6577
  return;
5840
6578
  }
@@ -5843,12 +6581,12 @@ function TextArea(props) {
5843
6581
  return jsxRuntime.jsxs("div", {
5844
6582
  class: "bio-properties-panel-textarea",
5845
6583
  children: [jsxRuntime.jsx("label", {
5846
- for: prefixId$2(id),
6584
+ for: prefixId$1(id),
5847
6585
  class: "bio-properties-panel-label",
5848
6586
  children: label
5849
6587
  }), jsxRuntime.jsx("textarea", {
5850
6588
  ref: ref,
5851
- id: prefixId$2(id),
6589
+ id: prefixId$1(id),
5852
6590
  name: id,
5853
6591
  spellCheck: "false",
5854
6592
  class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
@@ -5876,6 +6614,7 @@ function TextArea(props) {
5876
6614
  * @param {Function} props.onBlur
5877
6615
  * @param {number} props.rows
5878
6616
  * @param {boolean} props.monospace
6617
+ * @param {Function} [props.validate]
5879
6618
  * @param {boolean} [props.disabled]
5880
6619
  */
5881
6620
  function TextAreaEntry(props) {
@@ -5890,12 +6629,38 @@ function TextAreaEntry(props) {
5890
6629
  rows,
5891
6630
  monospace,
5892
6631
  disabled,
6632
+ validate,
5893
6633
  onFocus,
5894
6634
  onBlur,
5895
6635
  autoResize
5896
6636
  } = props;
5897
- const value = getValue(element);
5898
- const error = useError(id);
6637
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
6638
+ const globalError = useError(id);
6639
+ const [localError, setLocalError] = hooks.useState(null);
6640
+ let value = getValue(element);
6641
+ const previousValue = usePrevious(value);
6642
+ hooks.useEffect(() => {
6643
+ if (minDash.isFunction(validate)) {
6644
+ const newValidationError = validate(value) || null;
6645
+ setLocalError(newValidationError);
6646
+ }
6647
+ }, [value]);
6648
+ const onInput = newValue => {
6649
+ let newValidationError = null;
6650
+ if (minDash.isFunction(validate)) {
6651
+ newValidationError = validate(newValue) || null;
6652
+ }
6653
+ if (newValidationError) {
6654
+ setCachedInvalidValue(newValue);
6655
+ } else {
6656
+ setValue(newValue);
6657
+ }
6658
+ setLocalError(newValidationError);
6659
+ };
6660
+ if (previousValue === value && localError) {
6661
+ value = cachedInvalidValue;
6662
+ }
6663
+ const error = globalError || localError;
5899
6664
  return jsxRuntime.jsxs("div", {
5900
6665
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
5901
6666
  "data-entry-id": id,
@@ -5903,7 +6668,7 @@ function TextAreaEntry(props) {
5903
6668
  id: id,
5904
6669
  label: label,
5905
6670
  value: value,
5906
- onInput: setValue,
6671
+ onInput: onInput,
5907
6672
  onFocus: onFocus,
5908
6673
  onBlur: onBlur,
5909
6674
  rows: rows,
@@ -5921,13 +6686,13 @@ function TextAreaEntry(props) {
5921
6686
  })]
5922
6687
  });
5923
6688
  }
5924
- function isEdited$2(node) {
6689
+ function isEdited$1(node) {
5925
6690
  return node && !!node.value;
5926
6691
  }
5927
6692
 
5928
6693
  // helpers /////////////////
5929
6694
 
5930
- function prefixId$2(id) {
6695
+ function prefixId$1(id) {
5931
6696
  return `bio-properties-panel-${id}`;
5932
6697
  }
5933
6698
  function Textfield(props) {
@@ -5941,9 +6706,9 @@ function Textfield(props) {
5941
6706
  onBlur,
5942
6707
  value = ''
5943
6708
  } = props;
5944
- const [localValue, setLocalValue] = hooks$1.useState(value || '');
6709
+ const [localValue, setLocalValue] = hooks.useState(value || '');
5945
6710
  const ref = useShowEntryEvent(id);
5946
- const handleInputCallback = hooks$1.useMemo(() => {
6711
+ const handleInputCallback = hooks.useMemo(() => {
5947
6712
  return debounce(({
5948
6713
  target
5949
6714
  }) => onInput(target.value.length ? target.value : undefined));
@@ -5952,7 +6717,7 @@ function Textfield(props) {
5952
6717
  handleInputCallback(e);
5953
6718
  setLocalValue(e.target.value);
5954
6719
  };
5955
- hooks$1.useEffect(() => {
6720
+ hooks.useEffect(() => {
5956
6721
  if (value === localValue) {
5957
6722
  return;
5958
6723
  }
@@ -5961,12 +6726,12 @@ function Textfield(props) {
5961
6726
  return jsxRuntime.jsxs("div", {
5962
6727
  class: "bio-properties-panel-textfield",
5963
6728
  children: [jsxRuntime.jsx("label", {
5964
- for: prefixId$1(id),
6729
+ for: prefixId(id),
5965
6730
  class: "bio-properties-panel-label",
5966
6731
  children: label
5967
6732
  }), jsxRuntime.jsx("input", {
5968
6733
  ref: ref,
5969
- id: prefixId$1(id),
6734
+ id: prefixId(id),
5970
6735
  type: "text",
5971
6736
  name: id,
5972
6737
  spellCheck: "false",
@@ -6009,12 +6774,12 @@ function TextfieldEntry(props) {
6009
6774
  onFocus,
6010
6775
  onBlur
6011
6776
  } = props;
6012
- const [cachedInvalidValue, setCachedInvalidValue] = hooks$1.useState(null);
6777
+ const [cachedInvalidValue, setCachedInvalidValue] = hooks.useState(null);
6013
6778
  const globalError = useError(id);
6014
- const [localError, setLocalError] = hooks$1.useState(null);
6779
+ const [localError, setLocalError] = hooks.useState(null);
6015
6780
  let value = getValue(element);
6016
6781
  const previousValue = usePrevious(value);
6017
- hooks$1.useEffect(() => {
6782
+ hooks.useEffect(() => {
6018
6783
  if (minDash.isFunction(validate)) {
6019
6784
  const newValidationError = validate(value) || null;
6020
6785
  setLocalError(newValidationError);
@@ -6058,13 +6823,13 @@ function TextfieldEntry(props) {
6058
6823
  })]
6059
6824
  });
6060
6825
  }
6061
- function isEdited$1(node) {
6826
+ function isEdited(node) {
6062
6827
  return node && !!node.value;
6063
6828
  }
6064
6829
 
6065
6830
  // helpers /////////////////
6066
6831
 
6067
- function prefixId$1(id) {
6832
+ function prefixId(id) {
6068
6833
  return `bio-properties-panel-${id}`;
6069
6834
  }
6070
6835
 
@@ -6192,7 +6957,7 @@ function ActionEntry(props) {
6192
6957
  component: Action,
6193
6958
  editField: editField,
6194
6959
  field: field,
6195
- isEdited: isEdited$4
6960
+ isEdited: isEdited$3
6196
6961
  });
6197
6962
  }
6198
6963
  return entries;
@@ -6230,7 +6995,7 @@ function Action(props) {
6230
6995
  function useService (type, strict) {
6231
6996
  const {
6232
6997
  getService
6233
- } = hooks$1.useContext(FormPropertiesPanelContext);
6998
+ } = hooks.useContext(FormPropertiesPanelContext);
6234
6999
  return getService(type, strict);
6235
7000
  }
6236
7001
 
@@ -6260,7 +7025,7 @@ function AltTextEntry(props) {
6260
7025
  component: AltText,
6261
7026
  editField: editField,
6262
7027
  field: field,
6263
- isEdited: isEdited$7
7028
+ isEdited: isEdited$6
6264
7029
  });
6265
7030
  }
6266
7031
  return entries;
@@ -6305,7 +7070,7 @@ function ColumnsEntry(props) {
6305
7070
  component: Columns,
6306
7071
  field,
6307
7072
  editField,
6308
- isEdited: isEdited$4
7073
+ isEdited: isEdited$3
6309
7074
  }];
6310
7075
  return entries;
6311
7076
  }
@@ -6335,7 +7100,7 @@ function Columns(props) {
6335
7100
  },
6336
7101
  // todo(pinussilvestrus): make options dependant on field type
6337
7102
  // cf. https://github.com/bpmn-io/form-js/issues/575
6338
- ...[2, 4, 6, 8, 10, 12, 14, 16].map(asOption)];
7103
+ ...asArray(16).filter(i => i >= MIN_COLUMNS).map(asOption)];
6339
7104
  };
6340
7105
  return SelectEntry({
6341
7106
  debounce,
@@ -6357,6 +7122,11 @@ function asOption(number) {
6357
7122
  label: number.toString()
6358
7123
  };
6359
7124
  }
7125
+ function asArray(length) {
7126
+ return Array.from({
7127
+ length
7128
+ }).map((_, i) => i + 1);
7129
+ }
6360
7130
 
6361
7131
  function DescriptionEntry(props) {
6362
7132
  const {
@@ -6373,7 +7143,7 @@ function DescriptionEntry(props) {
6373
7143
  component: Description,
6374
7144
  editField: editField,
6375
7145
  field: field,
6376
- isEdited: isEdited$1
7146
+ isEdited: isEdited
6377
7147
  });
6378
7148
  }
6379
7149
  return entries;
@@ -6427,21 +7197,21 @@ function DefaultOptionEntry(props) {
6427
7197
  entries.push({
6428
7198
  ...defaultOptions,
6429
7199
  component: DefaultValueCheckbox,
6430
- isEdited: isEdited$4
7200
+ isEdited: isEdited$3
6431
7201
  });
6432
7202
  }
6433
7203
  if (type === 'number') {
6434
7204
  entries.push({
6435
7205
  ...defaultOptions,
6436
7206
  component: DefaultValueNumber,
6437
- isEdited: isEdited$1
7207
+ isEdited: isEdited
6438
7208
  });
6439
7209
  }
6440
7210
  if (type === 'radio' || type === 'select') {
6441
7211
  entries.push({
6442
7212
  ...defaultOptions,
6443
7213
  component: DefaultValueSingleSelect,
6444
- isEdited: isEdited$4
7214
+ isEdited: isEdited$3
6445
7215
  });
6446
7216
  }
6447
7217
 
@@ -6451,14 +7221,14 @@ function DefaultOptionEntry(props) {
6451
7221
  entries.push({
6452
7222
  ...defaultOptions,
6453
7223
  component: DefaultValueTextfield,
6454
- isEdited: isEdited$1
7224
+ isEdited: isEdited
6455
7225
  });
6456
7226
  }
6457
7227
  if (type === 'textarea') {
6458
7228
  entries.push({
6459
7229
  ...defaultOptions,
6460
7230
  component: DefaultValueTextarea,
6461
- isEdited: isEdited$2
7231
+ isEdited: isEdited$1
6462
7232
  });
6463
7233
  }
6464
7234
  return entries;
@@ -6652,7 +7422,7 @@ function DisabledEntry(props) {
6652
7422
  component: Disabled,
6653
7423
  editField: editField,
6654
7424
  field: field,
6655
- isEdited: isEdited$8
7425
+ isEdited: isEdited$7
6656
7426
  });
6657
7427
  }
6658
7428
  return entries;
@@ -6670,11 +7440,12 @@ function Disabled(props) {
6670
7440
  const setValue = value => {
6671
7441
  return editField(field, path, value);
6672
7442
  };
6673
- return CheckboxEntry({
7443
+ return ToggleSwitchEntry({
6674
7444
  element: field,
6675
7445
  getValue,
6676
7446
  id,
6677
7447
  label: 'Disabled',
7448
+ inline: true,
6678
7449
  setValue
6679
7450
  });
6680
7451
  }
@@ -6691,7 +7462,7 @@ function IdEntry(props) {
6691
7462
  component: Id,
6692
7463
  editField: editField,
6693
7464
  field: field,
6694
- isEdited: isEdited$1
7465
+ isEdited: isEdited
6695
7466
  });
6696
7467
  }
6697
7468
  return entries;
@@ -6771,7 +7542,7 @@ function KeyEntry(props) {
6771
7542
  component: Key$1,
6772
7543
  editField: editField,
6773
7544
  field: field,
6774
- isEdited: isEdited$1
7545
+ isEdited: isEdited
6775
7546
  });
6776
7547
  }
6777
7548
  return entries;
@@ -6834,7 +7605,7 @@ function simpleStringEntryFactory(options) {
6834
7605
  field,
6835
7606
  editField,
6836
7607
  component: SimpleStringComponent,
6837
- isEdited: isEdited$1
7608
+ isEdited: isEdited
6838
7609
  };
6839
7610
  }
6840
7611
  const SimpleStringComponent = props => {
@@ -6954,7 +7725,7 @@ function SourceEntry(props) {
6954
7725
  component: Source,
6955
7726
  editField: editField,
6956
7727
  field: field,
6957
- isEdited: isEdited$7
7728
+ isEdited: isEdited$6
6958
7729
  });
6959
7730
  }
6960
7731
  return entries;
@@ -7009,7 +7780,7 @@ function TextEntry(props) {
7009
7780
  component: Text,
7010
7781
  editField: editField,
7011
7782
  field: field,
7012
- isEdited: isEdited$7
7783
+ isEdited: isEdited$6
7013
7784
  }];
7014
7785
 
7015
7786
  // todo: skipped to make the release without too much risk
@@ -7042,7 +7813,7 @@ function Text(props) {
7042
7813
  const setValue = value => {
7043
7814
  return editField(field, path, value);
7044
7815
  };
7045
- const description = hooks$1.useMemo(() => jsxRuntime.jsxs(jsxRuntime.Fragment, {
7816
+ const description = hooks.useMemo(() => jsxRuntime.jsxs(jsxRuntime.Fragment, {
7046
7817
  children: ["Supports markdown and templating. ", jsxRuntime.jsx("a", {
7047
7818
  href: "https://docs.camunda.io/docs/components/modeler/forms/form-element-library/forms-element-library-text/",
7048
7819
  target: "_blank",
@@ -7078,14 +7849,14 @@ function NumberEntries(props) {
7078
7849
  entries.push({
7079
7850
  id: id + '-decimalDigits',
7080
7851
  component: NumberDecimalDigits,
7081
- isEdited: isEdited$5,
7852
+ isEdited: isEdited$4,
7082
7853
  editField,
7083
7854
  field
7084
7855
  });
7085
7856
  entries.push({
7086
7857
  id: id + '-step',
7087
7858
  component: NumberArrowStep,
7088
- isEdited: isEdited$1,
7859
+ isEdited: isEdited,
7089
7860
  editField,
7090
7861
  field
7091
7862
  });
@@ -7223,7 +7994,7 @@ function DateTimeEntry(props) {
7223
7994
  const entries = [{
7224
7995
  id: 'subtype',
7225
7996
  component: DateTimeSubtypeSelect,
7226
- isEdited: isEdited$4,
7997
+ isEdited: isEdited$3,
7227
7998
  editField,
7228
7999
  field
7229
8000
  }];
@@ -7335,7 +8106,7 @@ function DateTimeConstraintsEntry(props) {
7335
8106
  entries.push({
7336
8107
  id: id + '-timeInterval',
7337
8108
  component: TimeIntervalSelect,
7338
- isEdited: isEdited$4,
8109
+ isEdited: isEdited$3,
7339
8110
  editField,
7340
8111
  field
7341
8112
  });
@@ -7414,7 +8185,7 @@ function DateTimeFormatEntry(props) {
7414
8185
  entries.push({
7415
8186
  id: 'time-format',
7416
8187
  component: TimeFormatSelect,
7417
- isEdited: isEdited$4,
8188
+ isEdited: isEdited$3,
7418
8189
  editField,
7419
8190
  field
7420
8191
  });
@@ -7674,7 +8445,7 @@ function ValuesSourceSelectEntry(props) {
7674
8445
  return [{
7675
8446
  id: id + '-select',
7676
8447
  component: ValuesSourceSelect,
7677
- isEdited: isEdited$4,
8448
+ isEdited: isEdited$3,
7678
8449
  editField,
7679
8450
  field
7680
8451
  }];
@@ -7732,7 +8503,7 @@ function InputKeyValuesSourceEntry(props) {
7732
8503
  component: InputValuesKey,
7733
8504
  label: 'Input values key',
7734
8505
  description,
7735
- isEdited: isEdited$1,
8506
+ isEdited: isEdited,
7736
8507
  editField,
7737
8508
  field
7738
8509
  }];
@@ -7869,7 +8640,7 @@ function AdornerEntry(props) {
7869
8640
  entries.push({
7870
8641
  id: 'prefix-adorner',
7871
8642
  component: PrefixAdorner,
7872
- isEdited: isEdited$1,
8643
+ isEdited: isEdited,
7873
8644
  editField,
7874
8645
  field,
7875
8646
  onChange,
@@ -7878,7 +8649,7 @@ function AdornerEntry(props) {
7878
8649
  entries.push({
7879
8650
  id: 'suffix-adorner',
7880
8651
  component: SuffixAdorner,
7881
- isEdited: isEdited$1,
8652
+ isEdited: isEdited,
7882
8653
  editField,
7883
8654
  field,
7884
8655
  onChange,
@@ -7922,6 +8693,55 @@ function SuffixAdorner(props) {
7922
8693
  });
7923
8694
  }
7924
8695
 
8696
+ function ReadonlyEntry(props) {
8697
+ const {
8698
+ editField,
8699
+ field
8700
+ } = props;
8701
+ const {
8702
+ type
8703
+ } = field;
8704
+ const entries = [];
8705
+ if (INPUTS.includes(type)) {
8706
+ entries.push({
8707
+ id: 'readonly',
8708
+ component: Readonly,
8709
+ editField: editField,
8710
+ field: field,
8711
+ isEdited: isEdited$6
8712
+ });
8713
+ }
8714
+ return entries;
8715
+ }
8716
+ function Readonly(props) {
8717
+ const {
8718
+ editField,
8719
+ field,
8720
+ id
8721
+ } = props;
8722
+ const debounce = useService('debounce');
8723
+ const variables = useVariables().map(name => ({
8724
+ name
8725
+ }));
8726
+ const path = ['readonly'];
8727
+ const getValue = () => {
8728
+ return minDash.get(field, path, '');
8729
+ };
8730
+ const setValue = value => {
8731
+ return editField(field, path, value || false);
8732
+ };
8733
+ return FeelToggleSwitchEntry({
8734
+ debounce,
8735
+ element: field,
8736
+ feel: 'optional',
8737
+ getValue,
8738
+ id,
8739
+ label: 'Read only',
8740
+ setValue,
8741
+ variables
8742
+ });
8743
+ }
8744
+
7925
8745
  function ConditionEntry(props) {
7926
8746
  const {
7927
8747
  editField,
@@ -7932,7 +8752,7 @@ function ConditionEntry(props) {
7932
8752
  component: Condition,
7933
8753
  editField: editField,
7934
8754
  field: field,
7935
- isEdited: isEdited$7
8755
+ isEdited: isEdited$6
7936
8756
  }];
7937
8757
  }
7938
8758
  function Condition(props) {
@@ -8011,6 +8831,9 @@ function GeneralGroup(field, editField, getService) {
8011
8831
  }), ...DisabledEntry({
8012
8832
  field,
8013
8833
  editField
8834
+ }), ...ReadonlyEntry({
8835
+ field,
8836
+ editField
8014
8837
  })];
8015
8838
  return {
8016
8839
  id: 'general',
@@ -8101,7 +8924,7 @@ function ValidationGroup(field, editField) {
8101
8924
  getValue,
8102
8925
  field,
8103
8926
  editField,
8104
- isEdited: isEdited$1,
8927
+ isEdited: isEdited,
8105
8928
  onChange
8106
8929
  });
8107
8930
  }
@@ -8111,14 +8934,14 @@ function ValidationGroup(field, editField) {
8111
8934
  component: MinLength,
8112
8935
  getValue,
8113
8936
  field,
8114
- isEdited: isEdited$5,
8937
+ isEdited: isEdited$4,
8115
8938
  onChange
8116
8939
  }, {
8117
8940
  id: 'maxLength',
8118
8941
  component: MaxLength,
8119
8942
  getValue,
8120
8943
  field,
8121
- isEdited: isEdited$5,
8944
+ isEdited: isEdited$4,
8122
8945
  onChange
8123
8946
  });
8124
8947
  }
@@ -8128,7 +8951,7 @@ function ValidationGroup(field, editField) {
8128
8951
  component: Pattern,
8129
8952
  getValue,
8130
8953
  field,
8131
- isEdited: isEdited$1,
8954
+ isEdited: isEdited,
8132
8955
  onChange
8133
8956
  });
8134
8957
  }
@@ -8138,14 +8961,14 @@ function ValidationGroup(field, editField) {
8138
8961
  component: Min,
8139
8962
  getValue,
8140
8963
  field,
8141
- isEdited: isEdited$5,
8964
+ isEdited: isEdited$4,
8142
8965
  onChange
8143
8966
  }, {
8144
8967
  id: 'max',
8145
8968
  component: Max,
8146
8969
  getValue,
8147
8970
  field,
8148
- isEdited: isEdited$5,
8971
+ isEdited: isEdited$4,
8149
8972
  onChange
8150
8973
  });
8151
8974
  }
@@ -8493,7 +9316,7 @@ function FormPropertiesPanel(props) {
8493
9316
  const {
8494
9317
  schema
8495
9318
  } = formEditor._getState();
8496
- const [state, setState] = hooks$1.useState({
9319
+ const [state, setState] = hooks.useState({
8497
9320
  selectedFormField: selection.get() || schema
8498
9321
  });
8499
9322
  const _update = field => {
@@ -8507,7 +9330,7 @@ function FormPropertiesPanel(props) {
8507
9330
  formField: field
8508
9331
  });
8509
9332
  };
8510
- hooks$1.useLayoutEffect(() => {
9333
+ hooks.useLayoutEffect(() => {
8511
9334
  function onSelectionChange(event) {
8512
9335
  _update(event.selection || schema);
8513
9336
  }
@@ -8516,7 +9339,7 @@ function FormPropertiesPanel(props) {
8516
9339
  eventBus.off('selection.changed', onSelectionChange);
8517
9340
  };
8518
9341
  }, []);
8519
- hooks$1.useLayoutEffect(() => {
9342
+ hooks.useLayoutEffect(() => {
8520
9343
  const onFieldChanged = () => {
8521
9344
  /**
8522
9345
  * TODO(pinussilvestrus): update with actual updated element,
@@ -8536,7 +9359,7 @@ function FormPropertiesPanel(props) {
8536
9359
  };
8537
9360
  const onFocus = () => eventBus.fire('propertiesPanel.focusin');
8538
9361
  const onBlur = () => eventBus.fire('propertiesPanel.focusout');
8539
- const editField = hooks$1.useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
9362
+ const editField = hooks.useCallback((formField, key, value) => modeling.editFormField(formField, key, value), [modeling]);
8540
9363
  return jsxRuntime.jsx("div", {
8541
9364
  class: "fjs-properties-panel",
8542
9365
  "data-field": selectedFormField && selectedFormField.id,