@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.es.js CHANGED
@@ -1,14 +1,14 @@
1
1
  import { FormFieldRegistry as FormFieldRegistry$1, clone, iconsByType, Text as Text$1, FormFields, formFields, FormContext, FormRenderContext, FormComponent, FormLayouter, getSchemaVariables, DATETIME_SUBTYPES, DATE_LABEL_PATH, TIME_LABEL_PATH, DATETIME_SUBTYPE_PATH, DATETIME_SUBTYPES_LABELS, TIME_SERIALISING_FORMAT_PATH, TIME_SERIALISING_FORMATS, TIME_INTERVAL_PATH, TIME_USE24H_PATH, DATE_DISALLOW_PAST_PATH, TIME_SERIALISINGFORMAT_LABELS, getValuesSource, VALUES_SOURCES, VALUES_SOURCES_DEFAULTS, VALUES_SOURCES_PATHS, VALUES_SOURCES_LABELS, FeelExpressionLanguage, FeelersTemplating, createFormContainer, createInjector, MarkdownModule, schemaVersion } from '@bpmn-io/form-js-viewer';
2
2
  export { schemaVersion } from '@bpmn-io/form-js-viewer';
3
3
  import Ids from 'ids';
4
- import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, set as set$1, isUndefined, without, has, isString } from 'min-dash';
4
+ import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, set as set$1, isString, isUndefined, without, has } from 'min-dash';
5
5
  import classnames from 'classnames';
6
6
  import { jsx, jsxs, Fragment } from 'preact/jsx-runtime';
7
- import { useContext, useState, useRef, useEffect, useCallback, useMemo, useLayoutEffect } from 'preact/hooks';
7
+ import { useContext, useState, useRef, useCallback, useEffect, useLayoutEffect, useMemo } from 'preact/hooks';
8
8
  import { createContext, render, createElement } from 'preact';
9
9
  import React, { forwardRef } from 'preact/compat';
10
10
  import dragula from 'dragula';
11
- import { classes, closest, event, matches, domify, query } from 'min-dom';
11
+ import { classes, query, closest, event, matches, domify } from 'min-dom';
12
12
  import { mutate } from 'array-move';
13
13
  import { FeelersEditor } from 'feelers';
14
14
  import FeelEditor from '@bpmn-io/feel-editor';
@@ -18,6 +18,30 @@ var FN_REF = '__fn';
18
18
  var DEFAULT_PRIORITY$2 = 1000;
19
19
  var slice = Array.prototype.slice;
20
20
 
21
+ /**
22
+ * @typedef { {
23
+ * stopPropagation(): void;
24
+ * preventDefault(): void;
25
+ * cancelBubble: boolean;
26
+ * defaultPrevented: boolean;
27
+ * returnValue: any;
28
+ * } } Event
29
+ */
30
+
31
+ /**
32
+ * @template E
33
+ *
34
+ * @typedef { (event: E & Event, ...any) => any } EventBusEventCallback
35
+ */
36
+
37
+ /**
38
+ * @typedef { {
39
+ * priority: number;
40
+ * next: EventBusListener | null;
41
+ * callback: EventBusEventCallback<any>;
42
+ * } } EventBusListener
43
+ */
44
+
21
45
  /**
22
46
  * A general purpose event bus.
23
47
  *
@@ -102,6 +126,9 @@ var slice = Array.prototype.slice;
102
126
  * ```
103
127
  */
104
128
  function EventBus() {
129
+ /**
130
+ * @type { Record<string, EventBusListener> }
131
+ */
105
132
  this._listeners = {};
106
133
 
107
134
  // cleanup on destroy on lowest priority to allow
@@ -121,10 +148,12 @@ function EventBus() {
121
148
  *
122
149
  * Returning anything but `undefined` from a listener will stop the listener propagation.
123
150
  *
124
- * @param {string|Array<string>} events
125
- * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
126
- * @param {Function} callback
127
- * @param {Object} [that] Pass context (`this`) to the callback
151
+ * @template T
152
+ *
153
+ * @param {string|string[]} events to subscribe to
154
+ * @param {number} [priority=1000] listen priority
155
+ * @param {EventBusEventCallback<T>} callback
156
+ * @param {any} [that] callback context
128
157
  */
129
158
  EventBus.prototype.on = function (events, priority, callback, that) {
130
159
  events = isArray(events) ? events : [events];
@@ -156,14 +185,16 @@ EventBus.prototype.on = function (events, priority, callback, that) {
156
185
  };
157
186
 
158
187
  /**
159
- * Register an event listener that is executed only once.
188
+ * Register an event listener that is called only once.
160
189
  *
161
- * @param {string} event the event name to register for
162
- * @param {number} [priority=1000] the priority in which this listener is called, larger is higher
163
- * @param {Function} callback the callback to execute
164
- * @param {Object} [that] Pass context (`this`) to the callback
190
+ * @template T
191
+ *
192
+ * @param {string|string[]} events to subscribe to
193
+ * @param {number} [priority=1000] the listen priority
194
+ * @param {EventBusEventCallback<T>} callback
195
+ * @param {any} [that] callback context
165
196
  */
166
- EventBus.prototype.once = function (event, priority, callback, that) {
197
+ EventBus.prototype.once = function (events, priority, callback, that) {
167
198
  var self = this;
168
199
  if (isFunction(priority)) {
169
200
  that = callback;
@@ -176,7 +207,7 @@ EventBus.prototype.once = function (event, priority, callback, that) {
176
207
  function wrappedCallback() {
177
208
  wrappedCallback.__isTomb = true;
178
209
  var result = callback.apply(that, arguments);
179
- self.off(event, wrappedCallback);
210
+ self.off(events, wrappedCallback);
180
211
  return result;
181
212
  }
182
213
 
@@ -184,7 +215,7 @@ EventBus.prototype.once = function (event, priority, callback, that) {
184
215
  // bound callbacks via {@link #off} using the original
185
216
  // callback
186
217
  wrappedCallback[FN_REF] = callback;
187
- this.on(event, priority, wrappedCallback);
218
+ this.on(events, priority, wrappedCallback);
188
219
  };
189
220
 
190
221
  /**
@@ -192,8 +223,8 @@ EventBus.prototype.once = function (event, priority, callback, that) {
192
223
  *
193
224
  * If no callback is given, all listeners for a given event name are being removed.
194
225
  *
195
- * @param {string|Array<string>} events
196
- * @param {Function} [callback]
226
+ * @param {string|string[]} events
227
+ * @param {EventBusEventCallback} [callback]
197
228
  */
198
229
  EventBus.prototype.off = function (events, callback) {
199
230
  events = isArray(events) ? events : [events];
@@ -204,11 +235,11 @@ EventBus.prototype.off = function (events, callback) {
204
235
  };
205
236
 
206
237
  /**
207
- * Create an EventBus event.
238
+ * Create an event recognized be the event bus.
208
239
  *
209
- * @param {Object} data
240
+ * @param {Object} data Event data.
210
241
  *
211
- * @return {Object} event, recognized by the eventBus
242
+ * @return {Event} An event that will be recognized by the event bus.
212
243
  */
213
244
  EventBus.prototype.createEvent = function (data) {
214
245
  var event = new InternalEvent();
@@ -217,10 +248,11 @@ EventBus.prototype.createEvent = function (data) {
217
248
  };
218
249
 
219
250
  /**
220
- * Fires a named event.
251
+ * Fires an event.
221
252
  *
222
253
  * @example
223
254
  *
255
+ * ```javascript
224
256
  * // fire event by name
225
257
  * events.fire('foo');
226
258
  *
@@ -238,13 +270,13 @@ EventBus.prototype.createEvent = function (data) {
238
270
  * });
239
271
  *
240
272
  * events.fire({ type: 'foo' }, 'I am bar!');
273
+ * ```
241
274
  *
242
- * @param {string} [name] the optional event name
243
- * @param {Object} [event] the event object
244
- * @param {...Object} additional arguments to be passed to the callback functions
275
+ * @param {string} [type] event type
276
+ * @param {Object} [data] event or event data
277
+ * @param {...any} [args] additional arguments the callback will be called with.
245
278
  *
246
- * @return {boolean} the events return value, if specified or false if the
247
- * default action was prevented by listeners
279
+ * @return {any} The return value. Will be set to `false` if the default was prevented.
248
280
  */
249
281
  EventBus.prototype.fire = function (type, data) {
250
282
  var event, firstListener, returnValue, args;
@@ -296,6 +328,14 @@ EventBus.prototype.fire = function (type, data) {
296
328
  }
297
329
  return returnValue;
298
330
  };
331
+
332
+ /**
333
+ * Handle an error by firing an event.
334
+ *
335
+ * @param {Error} error The error to be handled.
336
+ *
337
+ * @return {boolean} Whether the error was handled.
338
+ */
299
339
  EventBus.prototype.handleError = function (error) {
300
340
  return this.fire('error', {
301
341
  error: error
@@ -304,6 +344,14 @@ EventBus.prototype.handleError = function (error) {
304
344
  EventBus.prototype._destroy = function () {
305
345
  this._listeners = {};
306
346
  };
347
+
348
+ /**
349
+ * @param {Event} event
350
+ * @param {any[]} args
351
+ * @param {EventBusListener} listener
352
+ *
353
+ * @return {any}
354
+ */
307
355
  EventBus.prototype._invokeListeners = function (event, args, listener) {
308
356
  var returnValue;
309
357
  while (listener) {
@@ -316,6 +364,14 @@ EventBus.prototype._invokeListeners = function (event, args, listener) {
316
364
  }
317
365
  return returnValue;
318
366
  };
367
+
368
+ /**
369
+ * @param {Event} event
370
+ * @param {any[]} args
371
+ * @param {EventBusListener} listener
372
+ *
373
+ * @return {any}
374
+ */
319
375
  EventBus.prototype._invokeListener = function (event, args, listener) {
320
376
  var returnValue;
321
377
  if (listener.callback.__isTomb) {
@@ -344,7 +400,7 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
344
400
  return returnValue;
345
401
  };
346
402
 
347
- /*
403
+ /**
348
404
  * Add new listener with a certain priority to the list
349
405
  * of listeners (for the given event).
350
406
  *
@@ -358,7 +414,7 @@ EventBus.prototype._invokeListener = function (event, args, listener) {
358
414
  * * after: [ 1500, 1500, (new=1300), 1000, 1000, (new=1000) ]
359
415
  *
360
416
  * @param {string} event
361
- * @param {Object} listener { priority, callback }
417
+ * @param {EventBusListener} listener
362
418
  */
363
419
  EventBus.prototype._addListener = function (event, newListener) {
364
420
  var listener = this._getListeners(event),
@@ -389,9 +445,20 @@ EventBus.prototype._addListener = function (event, newListener) {
389
445
  // add new listener to back
390
446
  previousListener.next = newListener;
391
447
  };
448
+
449
+ /**
450
+ * @param {string} name
451
+ *
452
+ * @return {EventBusListener}
453
+ */
392
454
  EventBus.prototype._getListeners = function (name) {
393
455
  return this._listeners[name];
394
456
  };
457
+
458
+ /**
459
+ * @param {string} name
460
+ * @param {EventBusListener} listener
461
+ */
395
462
  EventBus.prototype._setListeners = function (name, listener) {
396
463
  this._listeners[name] = listener;
397
464
  };
@@ -439,9 +506,9 @@ InternalEvent.prototype.init = function (data) {
439
506
  * Invoke function. Be fast...
440
507
  *
441
508
  * @param {Function} fn
442
- * @param {Array<Object>} args
509
+ * @param {any[]} args
443
510
  *
444
- * @return {Any}
511
+ * @return {any}
445
512
  */
446
513
  function invokeFunction(fn, args) {
447
514
  return fn.apply(null, args);
@@ -483,21 +550,24 @@ class FieldFactory {
483
550
  if (!fieldDefinition) {
484
551
  throw new Error(`form field of type <${type}> not supported`);
485
552
  }
553
+ const {
554
+ config
555
+ } = fieldDefinition;
486
556
  if (id && this._formFieldRegistry._ids.assigned(id)) {
487
557
  throw new Error(`ID <${id}> already assigned`);
488
558
  }
489
559
  if (key && this._formFieldRegistry._keys.assigned(key)) {
490
560
  throw new Error(`key <${key}> already assigned`);
491
561
  }
492
- const labelAttrs = applyDefaults && fieldDefinition.label ? {
493
- label: fieldDefinition.label
562
+ const labelAttrs = applyDefaults && config.label ? {
563
+ label: config.label
494
564
  } : {};
495
- const field = fieldDefinition.create({
565
+ const field = config.create({
496
566
  ...labelAttrs,
497
567
  ...attrs
498
568
  });
499
569
  this._ensureId(field);
500
- if (fieldDefinition.keyed) {
570
+ if (config.keyed) {
501
571
  this._ensureKey(field, applyDefaults);
502
572
  }
503
573
  return field;
@@ -570,6 +640,10 @@ class FormFieldRegistry extends FormFieldRegistry$1 {
570
640
  }
571
641
  }
572
642
 
643
+ const MAX_COLUMNS_PER_ROW = 16;
644
+ const MAX_COLUMNS = 16;
645
+ const MIN_COLUMNS = 2;
646
+ const MAX_FIELDS_PER_ROW = 4;
573
647
  class FormLayoutValidator {
574
648
  /**
575
649
  * @constructor
@@ -583,15 +657,15 @@ class FormLayoutValidator {
583
657
  }
584
658
  validateField(field = {}, columns, row) {
585
659
  // allow empty (auto columns)
586
- if (columns) {
587
- // allow minimum 2 cols
588
- if (columns < 2) {
589
- return 'Minimum 2 columns are allowed';
660
+ if (Number.isInteger(columns)) {
661
+ // allow minimum cols
662
+ if (columns < MIN_COLUMNS) {
663
+ return `Minimum ${MIN_COLUMNS} columns are allowed`;
590
664
  }
591
665
 
592
- // allow maximum 16 cols
593
- if (columns > 16) {
594
- return 'Maximum 16 columns are allowed';
666
+ // allow maximum cols
667
+ if (columns > MAX_COLUMNS) {
668
+ return `Maximum ${MAX_COLUMNS} columns are allowed`;
595
669
  }
596
670
  }
597
671
  if (!row) {
@@ -616,17 +690,24 @@ class FormLayoutValidator {
616
690
  });
617
691
 
618
692
  // do not allow overflows
619
- if (sumColumns > 16 || sumColumns === 16 && sumAutoCols > 0 || columns === 16 && sumFields > 1) {
620
- return 'New value exceeds the maximum of 16 columns per row';
693
+ if (sumColumns > MAX_COLUMNS_PER_ROW || sumAutoCols > 0 && sumColumns > calculateMaxColumnsWithAuto(sumAutoCols) || columns === MAX_COLUMNS_PER_ROW && sumFields > 1) {
694
+ return `New value exceeds the maximum of ${MAX_COLUMNS_PER_ROW} columns per row`;
621
695
  }
622
- if (sumFields > 4) {
623
- return 'Maximum 4 fields per row are allowed';
696
+ if (sumFields > MAX_FIELDS_PER_ROW) {
697
+ return `Maximum ${MAX_FIELDS_PER_ROW} fields per row are allowed`;
624
698
  }
625
699
  return null;
626
700
  }
627
701
  }
628
702
  FormLayoutValidator.$inject = ['formLayouter', 'formFieldRegistry'];
629
703
 
704
+ // helper //////////////////////
705
+
706
+ // on normal screen sizes, auto columns take minimum 2 columns
707
+ function calculateMaxColumnsWithAuto(autoCols) {
708
+ return MAX_COLUMNS_PER_ROW - autoCols * 2;
709
+ }
710
+
630
711
  class Importer {
631
712
  /**
632
713
  * @constructor
@@ -743,6 +824,91 @@ function editorFormFieldClasses(type, {
743
824
  });
744
825
  }
745
826
 
827
+ /**
828
+ * Add a dragger that calls back the passed function with
829
+ * { event, delta } on drag.
830
+ *
831
+ * @example
832
+ *
833
+ * function dragMove(event, delta) {
834
+ * // we are dragging (!!)
835
+ * }
836
+ *
837
+ * domElement.addEventListener('dragstart', dragger(dragMove));
838
+ *
839
+ * @param {Function} fn
840
+ * @param {Element} dragPreview
841
+ *
842
+ * @return {Function} drag start callback function
843
+ */
844
+ function createDragger(fn, dragPreview) {
845
+ let self;
846
+ let startX, startY;
847
+
848
+ /** drag start */
849
+ function onDragStart(event) {
850
+ self = this;
851
+ startX = event.clientX;
852
+ startY = event.clientY;
853
+
854
+ // (1) prevent preview image
855
+ if (event.dataTransfer) {
856
+ event.dataTransfer.setDragImage(dragPreview, 0, 0);
857
+ }
858
+
859
+ // (2) setup drag listeners
860
+
861
+ // attach drag + cleanup event
862
+ document.addEventListener('dragover', onDrag);
863
+ document.addEventListener('dragend', onEnd);
864
+ document.addEventListener('drop', preventDefault);
865
+ }
866
+ function onDrag(event) {
867
+ const delta = {
868
+ x: event.clientX - startX,
869
+ y: event.clientY - startY
870
+ };
871
+
872
+ // call provided fn with event, delta
873
+ return fn.call(self, event, delta);
874
+ }
875
+ function onEnd() {
876
+ document.removeEventListener('dragover', onDrag);
877
+ document.removeEventListener('dragend', onEnd);
878
+ document.removeEventListener('drop', preventDefault);
879
+ }
880
+ return onDragStart;
881
+ }
882
+
883
+ /**
884
+ * Throttle function call according UI update cycle.
885
+ *
886
+ * @param {Function} fn
887
+ *
888
+ * @return {Function} throttled fn
889
+ */
890
+ function throttle(fn) {
891
+ let active = false;
892
+ let lastArgs = [];
893
+ let lastThis = undefined;
894
+ return function (...args) {
895
+ lastArgs = args;
896
+ lastThis = this;
897
+ if (active) {
898
+ return;
899
+ }
900
+ active = true;
901
+ fn.apply(lastThis, lastArgs);
902
+ window.requestAnimationFrame(function () {
903
+ lastArgs = lastThis = active = undefined;
904
+ });
905
+ };
906
+ }
907
+ function preventDefault(event) {
908
+ event.preventDefault();
909
+ event.stopPropagation();
910
+ }
911
+
746
912
  const DragAndDropContext = createContext({
747
913
  drake: null
748
914
  });
@@ -783,10 +949,42 @@ var CloseIcon = (({
783
949
  })));
784
950
 
785
951
  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); }
786
- var DraggableIcon = (({
952
+ var DeleteIcon$1 = (({
787
953
  styles = {},
788
954
  ...props
789
955
  }) => /*#__PURE__*/React.createElement("svg", _extends$2({
956
+ xmlns: "http://www.w3.org/2000/svg",
957
+ width: "16",
958
+ height: "16",
959
+ fill: "none"
960
+ }, props), /*#__PURE__*/React.createElement("rect", {
961
+ width: "16",
962
+ height: "16",
963
+ x: ".536",
964
+ fill: "#fff",
965
+ rx: "3",
966
+ style: {
967
+ mixBlendMode: "multiply"
968
+ }
969
+ }), /*#__PURE__*/React.createElement("path", {
970
+ fill: "#fff",
971
+ d: "M.536 0h16v16h-16z",
972
+ style: {
973
+ mixBlendMode: "multiply"
974
+ }
975
+ }), /*#__PURE__*/React.createElement("path", {
976
+ fill: "currentcolor",
977
+ d: "M7.536 6h-1v6h1V6zm3 0h-1v6h1V6z"
978
+ }), /*#__PURE__*/React.createElement("path", {
979
+ fill: "currentcolor",
980
+ d: "M2.536 3v1h1v10a1 1 0 001 1h8a1 1 0 001-1V4h1V3h-12zm2 11V4h8v10h-8zm6-13h-4v1h4V1z"
981
+ })));
982
+
983
+ 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); }
984
+ var DraggableIcon = (({
985
+ styles = {},
986
+ ...props
987
+ }) => /*#__PURE__*/React.createElement("svg", _extends$1({
790
988
  xmlns: "http://www.w3.org/2000/svg",
791
989
  width: "16",
792
990
  height: "16",
@@ -799,11 +997,11 @@ var DraggableIcon = (({
799
997
  fill: "none"
800
998
  })));
801
999
 
802
- 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); }
1000
+ 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); }
803
1001
  var SearchIcon = (({
804
1002
  styles = {},
805
1003
  ...props
806
- }) => /*#__PURE__*/React.createElement("svg", _extends$1({
1004
+ }) => /*#__PURE__*/React.createElement("svg", _extends({
807
1005
  width: "15",
808
1006
  height: "15",
809
1007
  fill: "none",
@@ -859,9 +1057,7 @@ function EditorText(props) {
859
1057
  disableLinks: true
860
1058
  });
861
1059
  }
862
- EditorText.create = Text$1.create;
863
- EditorText.type = Text$1.type;
864
- EditorText.keyed = Text$1.keyed;
1060
+ EditorText.config = Text$1.config;
865
1061
 
866
1062
  const editorFormFields = [EditorText];
867
1063
 
@@ -869,28 +1065,20 @@ class EditorFormFields extends FormFields {
869
1065
  constructor() {
870
1066
  super();
871
1067
  editorFormFields.forEach(formField => {
872
- this.register(formField.type, formField);
1068
+ this.register(formField.config.type, formField);
873
1069
  });
874
1070
  }
875
1071
  }
876
1072
 
877
- 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); }
878
- var ListDeleteIcon = (({
879
- styles = {},
880
- ...props
881
- }) => /*#__PURE__*/React.createElement("svg", _extends({
882
- xmlns: "http://www.w3.org/2000/svg",
883
- width: "11",
884
- height: "14"
885
- }, props), /*#__PURE__*/React.createElement("path", {
886
- 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"
887
- })));
888
-
889
- const PALETTE_ENTRIES = formFields.filter(f => f.type !== 'default').map(f => {
1073
+ const PALETTE_ENTRIES = formFields.filter(({
1074
+ config: fieldConfig
1075
+ }) => fieldConfig.type !== 'default').map(({
1076
+ config: fieldConfig
1077
+ }) => {
890
1078
  return {
891
- label: f.label,
892
- type: f.type,
893
- group: f.group
1079
+ label: fieldConfig.label,
1080
+ type: fieldConfig.type,
1081
+ group: fieldConfig.group
894
1082
  };
895
1083
  });
896
1084
  const PALETTE_GROUPS = [{
@@ -911,19 +1099,24 @@ function Palette(props) {
911
1099
  const [searchTerm, setSearchTerm] = useState('');
912
1100
  const inputRef = useRef();
913
1101
  const groups = groupEntries(entries);
1102
+ const simplifyString = useCallback(str => {
1103
+ return str.toLowerCase().replace(/\s+/g, '');
1104
+ }, []);
1105
+ const filter = useCallback(entry => {
1106
+ const simplifiedSearchTerm = simplifyString(searchTerm);
1107
+ if (!simplifiedSearchTerm) {
1108
+ return true;
1109
+ }
1110
+ const simplifiedEntryLabel = simplifyString(entry.label);
1111
+ const simplifiedEntryType = simplifyString(entry.type);
1112
+ return simplifiedEntryLabel.includes(simplifiedSearchTerm) || simplifiedEntryType.includes(simplifiedSearchTerm);
1113
+ }, [searchTerm, simplifyString]);
914
1114
 
915
1115
  // filter entries on search change
916
1116
  useEffect(() => {
917
- const filter = entry => {
918
- if (!searchTerm) {
919
- return true;
920
- }
921
- const search = entry.label.toLowerCase();
922
- return searchTerm.toLowerCase().split(/\s/g).every(term => search.includes(term));
923
- };
924
1117
  const entries = PALETTE_ENTRIES.filter(filter);
925
1118
  setEntries(entries);
926
- }, [searchTerm]);
1119
+ }, [filter, searchTerm]);
927
1120
  const handleInput = useCallback(event => {
928
1121
  setSearchTerm(() => event.target.value);
929
1122
  }, [setSearchTerm]);
@@ -1336,6 +1529,136 @@ function FieldDragPreview(props) {
1336
1529
  });
1337
1530
  }
1338
1531
 
1532
+ const COLUMNS_REGEX = /^cds--col(-lg)?/;
1533
+ const ELEMENT_RESIZING_CLS = 'fjs-element-resizing';
1534
+ const RESIZE_DRAG_PREVIEW_CLS = 'fjs-resize-drag-preview';
1535
+ const GRID_OFFSET_PX = 16;
1536
+ function FieldResizer(props) {
1537
+ const {
1538
+ field,
1539
+ position
1540
+ } = props;
1541
+ const ref = useRef(null);
1542
+ const formLayoutValidator = useService$1('formLayoutValidator');
1543
+ const modeling = useService$1('modeling');
1544
+
1545
+ // we can't use state as we need to
1546
+ // manipulate this inside dragging events
1547
+ const context = useRef({
1548
+ startColumns: 0,
1549
+ newColumns: 0
1550
+ });
1551
+ const onResize = throttle((_, delta) => {
1552
+ const {
1553
+ x: dx
1554
+ } = delta;
1555
+ const {
1556
+ layout = {}
1557
+ } = field;
1558
+ const newColumns = calculateNewColumns(ref.current, layout.columns || context.current.startColumns, dx, position);
1559
+ const errorMessage = formLayoutValidator.validateField(field, newColumns);
1560
+ if (!errorMessage) {
1561
+ context.current.newColumns = newColumns;
1562
+
1563
+ // make visual updates to preview change
1564
+ const columnNode = ref.current.closest('.fjs-layout-column');
1565
+ removeMatching(columnNode, COLUMNS_REGEX);
1566
+ columnNode.classList.add(`cds--col-lg-${newColumns}`);
1567
+ }
1568
+ });
1569
+ const onResizeStart = event => {
1570
+ const target = getElementNode(field);
1571
+ const parent = getParent(target);
1572
+
1573
+ // create a blank element to use as drag preview
1574
+ // ensure it was only created once
1575
+ let blankPreview = getDragPreviewImage(parent);
1576
+ if (!blankPreview) {
1577
+ blankPreview = document.createElement('div');
1578
+ blankPreview.classList.add(RESIZE_DRAG_PREVIEW_CLS);
1579
+ parent.appendChild(blankPreview);
1580
+ }
1581
+
1582
+ // initialize drag handler
1583
+ const onDragStart = createDragger(onResize, blankPreview);
1584
+ onDragStart(event);
1585
+
1586
+ // mitigate auto columns on the grid that
1587
+ // has a offset of 16px (1rem) to both side
1588
+ const columnNode = getColumnNode(target);
1589
+ const startWidth = columnNode.getBoundingClientRect().width + GRID_OFFSET_PX;
1590
+ context.current.startColumns = asColumns(startWidth, parent);
1591
+ setResizing(target, position);
1592
+ };
1593
+ const onResizeEnd = () => {
1594
+ const {
1595
+ layout = {}
1596
+ } = field;
1597
+ if (context.current.newColumns) {
1598
+ modeling.editFormField(field, 'layout', {
1599
+ ...layout,
1600
+ columns: context.current.newColumns
1601
+ });
1602
+ }
1603
+ const target = getElementNode(field);
1604
+ unsetResizing(target, position);
1605
+ context.current.newColumns = null;
1606
+
1607
+ // remove blank preview
1608
+ const blankPreview = getDragPreviewImage(getParent(target));
1609
+ blankPreview.remove();
1610
+ };
1611
+ if (field.type === 'default') {
1612
+ return null;
1613
+ }
1614
+ return jsx("div", {
1615
+ ref: ref,
1616
+ class: classnames('fjs-field-resize-handle', 'fjs-field-resize-handle-' + position, DRAG_NO_MOVE_CLS),
1617
+ draggable: true,
1618
+ onDragStart: onResizeStart,
1619
+ onDragEnd: onResizeEnd
1620
+ });
1621
+ }
1622
+
1623
+ // helper //////
1624
+
1625
+ function asColumns(width, parent) {
1626
+ const totalWidth = parent.getBoundingClientRect().width;
1627
+ const oneColumn = 1 / 16 * totalWidth;
1628
+ return Math.round(width / oneColumn);
1629
+ }
1630
+ function calculateNewColumns(node, currentColumns, deltaX, position) {
1631
+ const parent = getParent(node);
1632
+
1633
+ // invert delta if we are resizing from the left
1634
+ if (position === 'left') {
1635
+ deltaX = deltaX * -1;
1636
+ }
1637
+ const deltaColumns = asColumns(deltaX, parent);
1638
+ return currentColumns + deltaColumns;
1639
+ }
1640
+ function getParent(node) {
1641
+ return node.closest('.fjs-layout-row');
1642
+ }
1643
+ function removeMatching(node, regex) {
1644
+ return classes(node).removeMatching(regex);
1645
+ }
1646
+ function getColumnNode(node) {
1647
+ return node.closest('.fjs-layout-column');
1648
+ }
1649
+ function getElementNode(field) {
1650
+ return query('.fjs-element[data-id="' + field.id + '"]');
1651
+ }
1652
+ function getDragPreviewImage(node) {
1653
+ return query('.fjs-resize-drag-preview', node);
1654
+ }
1655
+ function setResizing(node, position) {
1656
+ classes(node).add(ELEMENT_RESIZING_CLS + '-' + position);
1657
+ }
1658
+ function unsetResizing(node, position) {
1659
+ classes(node).remove(ELEMENT_RESIZING_CLS + '-' + position);
1660
+ }
1661
+
1339
1662
  function ContextPad(props) {
1340
1663
  if (!props.children) {
1341
1664
  return null;
@@ -1378,9 +1701,17 @@ function Element(props) {
1378
1701
  eventBus.on('selection.changed', scrollIntoView);
1379
1702
  return () => eventBus.off('selection.changed', scrollIntoView);
1380
1703
  }, [id]);
1704
+ useLayoutEffect(() => {
1705
+ if (selection.isSelected(field)) {
1706
+ ref.current.focus();
1707
+ }
1708
+ }, [selection, field]);
1381
1709
  function onClick(event) {
1382
1710
  event.stopPropagation();
1383
1711
  selection.toggle(field);
1712
+
1713
+ // properly focus on field
1714
+ ref.current.focus();
1384
1715
  }
1385
1716
  const classes = [];
1386
1717
  if (props.class) {
@@ -1395,11 +1726,19 @@ function Element(props) {
1395
1726
  const index = getFormFieldIndex(parentField, field);
1396
1727
  modeling.removeFormField(field, parentField, index);
1397
1728
  };
1729
+ const onKeyPress = event => {
1730
+ if (event.key === 'Enter') {
1731
+ event.stopPropagation();
1732
+ selection.toggle(field);
1733
+ }
1734
+ };
1398
1735
  return jsxs("div", {
1399
1736
  class: classes.join(' '),
1400
1737
  "data-id": id,
1401
1738
  "data-field-type": type,
1739
+ tabIndex: type === 'default' ? -1 : 0,
1402
1740
  onClick: onClick,
1741
+ onKeyPress: onKeyPress,
1403
1742
  ref: ref,
1404
1743
  children: [jsx(DebugColumns, {
1405
1744
  field: field
@@ -1407,9 +1746,15 @@ function Element(props) {
1407
1746
  children: selection.isSelected(field) && field.type !== 'default' ? jsx("button", {
1408
1747
  class: "fjs-context-pad-item",
1409
1748
  onClick: onRemove,
1410
- children: jsx(ListDeleteIcon, {})
1749
+ children: jsx(DeleteIcon$1, {})
1411
1750
  }) : null
1412
- }), props.children]
1751
+ }), props.children, jsx(FieldResizer, {
1752
+ position: "left",
1753
+ field: field
1754
+ }), jsx(FieldResizer, {
1755
+ position: "right",
1756
+ field: field
1757
+ })]
1413
1758
  });
1414
1759
  }
1415
1760
  function DebugColumns(props) {
@@ -1494,8 +1839,12 @@ function FormEditor$1(props) {
1494
1839
  propertiesPanel = useService$1('propertiesPanel'),
1495
1840
  propertiesPanelConfig = useService$1('config.propertiesPanel');
1496
1841
  const {
1497
- schema
1842
+ schema,
1843
+ properties
1498
1844
  } = formEditor._getState();
1845
+ const {
1846
+ ariaLabel
1847
+ } = properties;
1499
1848
  const formContainerRef = useRef(null);
1500
1849
  const paletteRef = useRef(null);
1501
1850
  const propertiesPanelRef = useRef(null);
@@ -1581,7 +1930,8 @@ function FormEditor$1(props) {
1581
1930
  data: {},
1582
1931
  errors: {},
1583
1932
  properties: {
1584
- readOnly: true
1933
+ ariaLabel,
1934
+ disabled: true
1585
1935
  },
1586
1936
  schema
1587
1937
  };
@@ -1767,6 +2117,12 @@ var core = {
1767
2117
  fieldFactory: ['type', FieldFactory]
1768
2118
  };
1769
2119
 
2120
+ /**
2121
+ * @typedef {import('didi').Injector} Injector
2122
+ *
2123
+ * @typedef {import('../../core/EventBus').default} EventBus
2124
+ */
2125
+
1770
2126
  var NOT_REGISTERED_ERROR = 'is not a registered action',
1771
2127
  IS_REGISTERED_ERROR = 'is already registered';
1772
2128
 
@@ -1896,10 +2252,10 @@ EditorActions.prototype._registerDefaultActions = function (injector) {
1896
2252
  /**
1897
2253
  * Triggers a registered action
1898
2254
  *
1899
- * @param {string} action
1900
- * @param {Object} opts
2255
+ * @param {string} action
2256
+ * @param {Object} opts
1901
2257
  *
1902
- * @return {Unknown} Returns what the registered listener returns
2258
+ * @return {unknown} Returns what the registered listener returns
1903
2259
  */
1904
2260
  EditorActions.prototype.trigger = function (action, opts) {
1905
2261
  if (!this._actions[action]) {
@@ -1928,7 +2284,7 @@ EditorActions.prototype.trigger = function (action, opts) {
1928
2284
  * editorActions.isRegistered('spaceTool'); // true
1929
2285
  * ´´´
1930
2286
  *
1931
- * @param {Object} actions
2287
+ * @param {Object} actions
1932
2288
  */
1933
2289
  EditorActions.prototype.register = function (actions, listener) {
1934
2290
  var self = this;
@@ -1943,8 +2299,8 @@ EditorActions.prototype.register = function (actions, listener) {
1943
2299
  /**
1944
2300
  * Registers a listener to an action key
1945
2301
  *
1946
- * @param {string} action
1947
- * @param {Function} listener
2302
+ * @param {string} action
2303
+ * @param {Function} listener
1948
2304
  */
1949
2305
  EditorActions.prototype._registerAction = function (action, listener) {
1950
2306
  if (this.isRegistered(action)) {
@@ -1988,6 +2344,9 @@ function error(action, message) {
1988
2344
  return new Error(action + ' ' + message);
1989
2345
  }
1990
2346
 
2347
+ /**
2348
+ * @type { import('didi').ModuleDeclaration }
2349
+ */
1991
2350
  var EditorActionsModule$1 = {
1992
2351
  __init__: ['editorActions'],
1993
2352
  editorActions: ['type', EditorActions]
@@ -2047,10 +2406,10 @@ var DraggingModule = {
2047
2406
  dragging: ['type', Dragging]
2048
2407
  };
2049
2408
 
2050
- var KEYS_COPY = ['c', 'C', 'KeyC'];
2051
- var KEYS_PASTE = ['v', 'V', 'KeyV'];
2052
- var KEYS_REDO$1 = ['y', 'Y', 'KeyY'];
2053
- var KEYS_UNDO$1 = ['z', 'Z', 'KeyZ'];
2409
+ var KEYS_COPY = ['c', 'C'];
2410
+ var KEYS_PASTE = ['v', 'V'];
2411
+ var KEYS_REDO = ['y', 'Y'];
2412
+ var KEYS_UNDO = ['z', 'Z'];
2054
2413
 
2055
2414
  /**
2056
2415
  * Returns true if event was triggered with any modifier
@@ -2075,7 +2434,7 @@ function isCmd(event) {
2075
2434
  /**
2076
2435
  * Checks if key pressed is one of provided keys.
2077
2436
  *
2078
- * @param {string|Array<string>} keys
2437
+ * @param {string|string[]} keys
2079
2438
  * @param {KeyboardEvent} event
2080
2439
  */
2081
2440
  function isKey(keys, event) {
@@ -2096,12 +2455,16 @@ function isPaste(event) {
2096
2455
  return isCmd(event) && isKey(KEYS_PASTE, event);
2097
2456
  }
2098
2457
  function isUndo(event) {
2099
- return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO$1, event);
2458
+ return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
2100
2459
  }
2101
2460
  function isRedo(event) {
2102
- return isCmd(event) && (isKey(KEYS_REDO$1, event) || isKey(KEYS_UNDO$1, event) && isShift(event));
2461
+ return isCmd(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
2103
2462
  }
2104
2463
 
2464
+ /**
2465
+ * @typedef {import('../../core/EventBus').default} EventBus
2466
+ */
2467
+
2105
2468
  var KEYDOWN_EVENT = 'keyboard.keydown',
2106
2469
  KEYUP_EVENT = 'keyboard.keyup';
2107
2470
  var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
@@ -2128,7 +2491,7 @@ var DEFAULT_PRIORITY$1 = 1000;
2128
2491
  * A default binding for the keyboard may be specified via the
2129
2492
  * `keyboard.bindTo` configuration option.
2130
2493
  *
2131
- * @param {Config} config
2494
+ * @param {Object} config
2132
2495
  * @param {EventBus} eventBus
2133
2496
  */
2134
2497
  function Keyboard(config, eventBus) {
@@ -2257,8 +2620,6 @@ function isInput(target) {
2257
2620
  }
2258
2621
 
2259
2622
  var LOW_PRIORITY$1 = 500;
2260
- var KEYS_REDO = ['y', 'Y', 'KeyY'];
2261
- var KEYS_UNDO = ['z', 'Z', 'KeyZ'];
2262
2623
 
2263
2624
  /**
2264
2625
  * Adds default keyboard bindings.
@@ -2389,6 +2750,9 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
2389
2750
  });
2390
2751
  };
2391
2752
 
2753
+ /**
2754
+ * @type { import('didi').ModuleDeclaration }
2755
+ */
2392
2756
  var KeyboardModule$1 = {
2393
2757
  __init__: ['keyboard', 'keyboardBindings'],
2394
2758
  keyboard: ['type', Keyboard],
@@ -2924,32 +3288,46 @@ class Modeling {
2924
3288
  }
2925
3289
  Modeling.$inject = ['commandStack', 'eventBus', 'formEditor', 'formFieldRegistry', 'fieldFactory'];
2926
3290
 
3291
+ /**
3292
+ * @typedef {import('../core/Types').ElementLike} ElementLike
3293
+ * @typedef {import('../core/EventBus').default} EventBus
3294
+ * @typedef {import('./CommandStack').CommandContext} CommandContext
3295
+ *
3296
+ * @typedef {string|string[]} Events
3297
+ * @typedef { (context: CommandContext) => ElementLike[] | void } HandlerFunction
3298
+ * @typedef { (context: CommandContext) => void } ComposeHandlerFunction
3299
+ */
3300
+
2927
3301
  var DEFAULT_PRIORITY = 1000;
2928
3302
 
2929
3303
  /**
2930
- * A utility that can be used to plug-in into the command execution for
3304
+ * A utility that can be used to plug into the command execution for
2931
3305
  * extension and/or validation.
2932
3306
  *
2933
- * @param {EventBus} eventBus
3307
+ * @class
3308
+ * @constructor
2934
3309
  *
2935
3310
  * @example
2936
3311
  *
2937
- * import inherits from 'inherits-browser';
2938
- *
3312
+ * ```javascript
2939
3313
  * import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
2940
3314
  *
2941
- * function CommandLogger(eventBus) {
2942
- * CommandInterceptor.call(this, eventBus);
3315
+ * class CommandLogger extends CommandInterceptor {
3316
+ * constructor(eventBus) {
3317
+ * super(eventBus);
2943
3318
  *
2944
- * this.preExecute(function(event) {
2945
- * console.log('command pre-execute', event);
3319
+ * this.preExecute('shape.create', (event) => {
3320
+ * console.log('commandStack.shape-create.preExecute', event);
2946
3321
  * });
2947
3322
  * }
3323
+ * ```
2948
3324
  *
2949
- * inherits(CommandLogger, CommandInterceptor);
2950
- *
3325
+ * @param {EventBus} eventBus
2951
3326
  */
2952
3327
  function CommandInterceptor(eventBus) {
3328
+ /**
3329
+ * @type {EventBus}
3330
+ */
2953
3331
  this._eventBus = eventBus;
2954
3332
  }
2955
3333
  CommandInterceptor.$inject = ['eventBus'];
@@ -2960,15 +3338,14 @@ function unwrapEvent(fn, that) {
2960
3338
  }
2961
3339
 
2962
3340
  /**
2963
- * Register an interceptor for a command execution
2964
- *
2965
- * @param {string|Array<string>} [events] list of commands to register on
2966
- * @param {string} [hook] command hook, i.e. preExecute, executed to listen on
2967
- * @param {number} [priority] the priority on which to hook into the execution
2968
- * @param {Function} handlerFn interceptor to be invoked with (event)
2969
- * @param {boolean} unwrap if true, unwrap the event and pass (context, command, event) to the
2970
- * listener instead
2971
- * @param {Object} [that] Pass context (`this`) to the handler function
3341
+ * Intercept a command during one of the phases.
3342
+ *
3343
+ * @param {Events} [events] command(s) to intercept
3344
+ * @param {string} [hook] phase to intercept
3345
+ * @param {number} [priority]
3346
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3347
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3348
+ * @param {any} [that]
2972
3349
  */
2973
3350
  CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, unwrap, that) {
2974
3351
  if (isFunction(hook) || isNumber(hook)) {
@@ -3003,28 +3380,130 @@ CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, u
3003
3380
  eventBus.on(fullEvent, priority, unwrap ? unwrapEvent(handlerFn, that) : handlerFn, that);
3004
3381
  });
3005
3382
  };
3006
- var hooks = ['canExecute', 'preExecute', 'preExecuted', 'execute', 'executed', 'postExecute', 'postExecuted', 'revert', 'reverted'];
3383
+
3384
+ /**
3385
+ * Add a <canExecute> phase of command interceptor.
3386
+ *
3387
+ * @param {Events} [events] command(s) to intercept
3388
+ * @param {number} [priority]
3389
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3390
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3391
+ * @param {any} [that]
3392
+ */
3393
+ CommandInterceptor.prototype.canExecute = createHook('canExecute');
3394
+
3395
+ /**
3396
+ * Add a <preExecute> phase of command interceptor.
3397
+ *
3398
+ * @param {Events} [events] command(s) to intercept
3399
+ * @param {number} [priority]
3400
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3401
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3402
+ * @param {any} [that]
3403
+ */
3404
+ CommandInterceptor.prototype.preExecute = createHook('preExecute');
3405
+
3406
+ /**
3407
+ * Add a <preExecuted> phase of command interceptor.
3408
+ *
3409
+ * @param {Events} [events] command(s) to intercept
3410
+ * @param {number} [priority]
3411
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3412
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3413
+ * @param {any} [that]
3414
+ */
3415
+ CommandInterceptor.prototype.preExecuted = createHook('preExecuted');
3416
+
3417
+ /**
3418
+ * Add a <execute> phase of command interceptor.
3419
+ *
3420
+ * @param {Events} [events] command(s) to intercept
3421
+ * @param {number} [priority]
3422
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3423
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3424
+ * @param {any} [that]
3425
+ */
3426
+ CommandInterceptor.prototype.execute = createHook('execute');
3427
+
3428
+ /**
3429
+ * Add a <executed> phase of command interceptor.
3430
+ *
3431
+ * @param {Events} [events] command(s) to intercept
3432
+ * @param {number} [priority]
3433
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3434
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3435
+ * @param {any} [that]
3436
+ */
3437
+ CommandInterceptor.prototype.executed = createHook('executed');
3438
+
3439
+ /**
3440
+ * Add a <postExecute> phase of command interceptor.
3441
+ *
3442
+ * @param {Events} [events] command(s) to intercept
3443
+ * @param {number} [priority]
3444
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3445
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3446
+ * @param {any} [that]
3447
+ */
3448
+ CommandInterceptor.prototype.postExecute = createHook('postExecute');
3449
+
3450
+ /**
3451
+ * Add a <postExecuted> phase of command interceptor.
3452
+ *
3453
+ * @param {Events} [events] command(s) to intercept
3454
+ * @param {number} [priority]
3455
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3456
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3457
+ * @param {any} [that]
3458
+ */
3459
+ CommandInterceptor.prototype.postExecuted = createHook('postExecuted');
3460
+
3461
+ /**
3462
+ * Add a <revert> phase of command interceptor.
3463
+ *
3464
+ * @param {Events} [events] command(s) to intercept
3465
+ * @param {number} [priority]
3466
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3467
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3468
+ * @param {any} [that]
3469
+ */
3470
+ CommandInterceptor.prototype.revert = createHook('revert');
3471
+
3472
+ /**
3473
+ * Add a <reverted> phase of command interceptor.
3474
+ *
3475
+ * @param {Events} [events] command(s) to intercept
3476
+ * @param {number} [priority]
3477
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3478
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3479
+ * @param {any} [that]
3480
+ */
3481
+ CommandInterceptor.prototype.reverted = createHook('reverted');
3007
3482
 
3008
3483
  /*
3009
- * Install hook shortcuts
3484
+ * Add prototype methods for each phase of command execution (e.g. execute,
3485
+ * revert).
3486
+ *
3487
+ * @param {string} hook
3010
3488
  *
3011
- * This will generate the CommandInterceptor#(preExecute|...|reverted) methods
3012
- * which will in term forward to CommandInterceptor#on.
3489
+ * @return { (
3490
+ * events?: Events,
3491
+ * priority?: number,
3492
+ * handlerFn: ComposeHandlerFunction|HandlerFunction,
3493
+ * unwrap?: boolean
3494
+ * ) => any }
3013
3495
  */
3014
- forEach(hooks, function (hook) {
3496
+ function createHook(hook) {
3015
3497
  /**
3016
- * {canExecute|preExecute|preExecuted|execute|executed|postExecute|postExecuted|revert|reverted}
3498
+ * @this {CommandInterceptor}
3017
3499
  *
3018
- * A named hook for plugging into the command execution
3019
- *
3020
- * @param {string|Array<string>} [events] list of commands to register on
3021
- * @param {number} [priority] the priority on which to hook into the execution
3022
- * @param {Function} handlerFn interceptor to be invoked with (event)
3023
- * @param {boolean} [unwrap=false] if true, unwrap the event and pass (context, command, event) to the
3024
- * listener instead
3025
- * @param {Object} [that] Pass context (`this`) to the handler function
3500
+ * @param {Events} [events]
3501
+ * @param {number} [priority]
3502
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3503
+ * @param {boolean} [unwrap]
3504
+ * @param {any} [that]
3026
3505
  */
3027
- CommandInterceptor.prototype[hook] = function (events, priority, handlerFn, unwrap, that) {
3506
+ const hookFn = function (events, priority, handlerFn, unwrap, that) {
3028
3507
  if (isFunction(events) || isNumber(events)) {
3029
3508
  that = unwrap;
3030
3509
  unwrap = handlerFn;
@@ -3034,7 +3513,8 @@ forEach(hooks, function (hook) {
3034
3513
  }
3035
3514
  this.on(events, hook, priority, handlerFn, unwrap, that);
3036
3515
  };
3037
- });
3516
+ return hookFn;
3517
+ }
3038
3518
 
3039
3519
  class FormLayoutUpdater extends CommandInterceptor {
3040
3520
  constructor(eventBus, formLayouter, modeling, formEditor) {
@@ -3172,6 +3652,34 @@ var behaviorModule = {
3172
3652
  validateBehavior: ['type', ValidateBehavior]
3173
3653
  };
3174
3654
 
3655
+ /**
3656
+ * @typedef {import('didi').Injector} Injector
3657
+ *
3658
+ * @typedef {import('../core/Types').ElementLike} ElementLike
3659
+ *
3660
+ * @typedef {import('../core/EventBus').default} EventBus
3661
+ * @typedef {import('./CommandHandler').default} CommandHandler
3662
+ *
3663
+ * @typedef { any } CommandContext
3664
+ * @typedef { {
3665
+ * new (...args: any[]) : CommandHandler
3666
+ * } } CommandHandlerConstructor
3667
+ * @typedef { {
3668
+ * [key: string]: CommandHandler;
3669
+ * } } CommandHandlerMap
3670
+ * @typedef { {
3671
+ * command: string;
3672
+ * context: any;
3673
+ * id?: any;
3674
+ * } } CommandStackAction
3675
+ * @typedef { {
3676
+ * actions: CommandStackAction[];
3677
+ * dirty: ElementLike[];
3678
+ * trigger: 'execute' | 'undo' | 'redo' | 'clear' | null;
3679
+ * atomic?: boolean;
3680
+ * } } CurrentExecution
3681
+ */
3682
+
3175
3683
  /**
3176
3684
  * A service that offers un- and redoable execution of commands.
3177
3685
  *
@@ -3222,7 +3730,7 @@ var behaviorModule = {
3222
3730
  * got changed during the `execute` and `revert` operations.
3223
3731
  *
3224
3732
  * Command handlers may execute other modeling operations (and thus
3225
- * commands) in their `preExecute` and `postExecute` phases. The command
3733
+ * commands) in their `preExecute(d)` and `postExecute(d)` phases. The command
3226
3734
  * stack will properly group all commands together into a logical unit
3227
3735
  * that may be re- and undone atomically.
3228
3736
  *
@@ -3252,14 +3760,14 @@ function CommandStack(eventBus, injector) {
3252
3760
  /**
3253
3761
  * A map of all registered command handlers.
3254
3762
  *
3255
- * @type {Object}
3763
+ * @type {CommandHandlerMap}
3256
3764
  */
3257
3765
  this._handlerMap = {};
3258
3766
 
3259
3767
  /**
3260
3768
  * A stack containing all re/undoable actions on the diagram
3261
3769
  *
3262
- * @type {Array<Object>}
3770
+ * @type {CommandStackAction[]}
3263
3771
  */
3264
3772
  this._stack = [];
3265
3773
 
@@ -3273,18 +3781,27 @@ function CommandStack(eventBus, injector) {
3273
3781
  /**
3274
3782
  * Current active commandStack execution
3275
3783
  *
3276
- * @type {Object}
3277
- * @property {Object[]} actions
3278
- * @property {Object[]} dirty
3279
- * @property { 'undo' | 'redo' | 'clear' | 'execute' | null } trigger the cause of the current excecution
3784
+ * @type {CurrentExecution}
3280
3785
  */
3281
3786
  this._currentExecution = {
3282
3787
  actions: [],
3283
3788
  dirty: [],
3284
3789
  trigger: null
3285
3790
  };
3286
- this._injector = injector;
3791
+
3792
+ /**
3793
+ * @type {Injector}
3794
+ */
3795
+ this._injector = injector;
3796
+
3797
+ /**
3798
+ * @type EventBus
3799
+ */
3287
3800
  this._eventBus = eventBus;
3801
+
3802
+ /**
3803
+ * @type { number }
3804
+ */
3288
3805
  this._uid = 1;
3289
3806
  eventBus.on(['diagram.destroy', 'diagram.clear'], function () {
3290
3807
  this.clear(false);
@@ -3293,10 +3810,10 @@ function CommandStack(eventBus, injector) {
3293
3810
  CommandStack.$inject = ['eventBus', 'injector'];
3294
3811
 
3295
3812
  /**
3296
- * Execute a command
3813
+ * Execute a command.
3297
3814
  *
3298
- * @param {string} command the command to execute
3299
- * @param {Object} context the environment to execute the command in
3815
+ * @param {string} command The command to execute.
3816
+ * @param {CommandContext} context The context with which to execute the command.
3300
3817
  */
3301
3818
  CommandStack.prototype.execute = function (command, context) {
3302
3819
  if (!command) {
@@ -3309,11 +3826,11 @@ CommandStack.prototype.execute = function (command, context) {
3309
3826
  };
3310
3827
  this._pushAction(action);
3311
3828
  this._internalExecute(action);
3312
- this._popAction(action);
3829
+ this._popAction();
3313
3830
  };
3314
3831
 
3315
3832
  /**
3316
- * Ask whether a given command can be executed.
3833
+ * Check whether a command can be executed.
3317
3834
  *
3318
3835
  * Implementors may hook into the mechanism on two ways:
3319
3836
  *
@@ -3327,10 +3844,10 @@ CommandStack.prototype.execute = function (command, context) {
3327
3844
  * If the method {@link CommandHandler#canExecute} is implemented in a handler
3328
3845
  * it will be called to figure out whether the execution is allowed.
3329
3846
  *
3330
- * @param {string} command the command to execute
3331
- * @param {Object} context the environment to execute the command in
3847
+ * @param {string} command The command to execute.
3848
+ * @param {CommandContext} context The context with which to execute the command.
3332
3849
  *
3333
- * @return {boolean} true if the command can be executed
3850
+ * @return {boolean} Whether the command can be executed with the given context.
3334
3851
  */
3335
3852
  CommandStack.prototype.canExecute = function (command, context) {
3336
3853
  const action = {
@@ -3354,7 +3871,9 @@ CommandStack.prototype.canExecute = function (command, context) {
3354
3871
  };
3355
3872
 
3356
3873
  /**
3357
- * Clear the command stack, erasing all undo / redo history
3874
+ * Clear the command stack, erasing all undo / redo history.
3875
+ *
3876
+ * @param {boolean} [emit=true] Whether to fire an event. Defaults to `true`.
3358
3877
  */
3359
3878
  CommandStack.prototype.clear = function (emit) {
3360
3879
  this._stack.length = 0;
@@ -3409,21 +3928,21 @@ CommandStack.prototype.redo = function () {
3409
3928
  };
3410
3929
 
3411
3930
  /**
3412
- * Register a handler instance with the command stack
3931
+ * Register a handler instance with the command stack.
3413
3932
  *
3414
- * @param {string} command
3415
- * @param {CommandHandler} handler
3933
+ * @param {string} command Command to be executed.
3934
+ * @param {CommandHandler} handler Handler to execute the command.
3416
3935
  */
3417
3936
  CommandStack.prototype.register = function (command, handler) {
3418
3937
  this._setHandler(command, handler);
3419
3938
  };
3420
3939
 
3421
3940
  /**
3422
- * Register a handler type with the command stack
3423
- * by instantiating it and injecting its dependencies.
3941
+ * Register a handler type with the command stack by instantiating it and
3942
+ * injecting its dependencies.
3424
3943
  *
3425
- * @param {string} command
3426
- * @param {Function} a constructor for a {@link CommandHandler}
3944
+ * @param {string} command Command to be executed.
3945
+ * @param {CommandHandlerConstructor} handlerCls Constructor to instantiate a {@link CommandHandler}.
3427
3946
  */
3428
3947
  CommandStack.prototype.registerHandler = function (command, handlerCls) {
3429
3948
  if (!command || !handlerCls) {
@@ -3432,9 +3951,17 @@ CommandStack.prototype.registerHandler = function (command, handlerCls) {
3432
3951
  const handler = this._injector.instantiate(handlerCls);
3433
3952
  this.register(command, handler);
3434
3953
  };
3954
+
3955
+ /**
3956
+ * @return {boolean}
3957
+ */
3435
3958
  CommandStack.prototype.canUndo = function () {
3436
3959
  return !!this._getUndoAction();
3437
3960
  };
3961
+
3962
+ /**
3963
+ * @return {boolean}
3964
+ */
3438
3965
  CommandStack.prototype.canRedo = function () {
3439
3966
  return !!this._getRedoAction();
3440
3967
  };
@@ -3528,7 +4055,7 @@ CommandStack.prototype._internalExecute = function (action, redo) {
3528
4055
  }
3529
4056
  this._fire(command, 'postExecuted', action);
3530
4057
  }
3531
- this._popAction(action);
4058
+ this._popAction();
3532
4059
  };
3533
4060
  CommandStack.prototype._pushAction = function (action) {
3534
4061
  const execution = this._currentExecution,
@@ -3589,6 +4116,9 @@ CommandStack.prototype._setHandler = function (command, handler) {
3589
4116
  this._handlerMap[command] = handler;
3590
4117
  };
3591
4118
 
4119
+ /**
4120
+ * @type { import('didi').ModuleDeclaration }
4121
+ */
3592
4122
  var commandModule = {
3593
4123
  commandStack: ['type', CommandStack]
3594
4124
  };
@@ -3795,44 +4325,18 @@ ExternalLinkIcon.defaultProps = {
3795
4325
  fill: "none",
3796
4326
  xmlns: "http://www.w3.org/2000/svg"
3797
4327
  };
3798
- var FeelRequiredIcon = function FeelRequiredIcon(props) {
3799
- return jsxs("svg", {
3800
- ...props,
3801
- children: [jsx("path", {
3802
- d: "M5.8 7.06V5.95h4.307v1.11H5.8Zm0 3.071v-1.11h4.307v1.11H5.8Z",
3803
- fill: "currentColor"
3804
- }), jsx("path", {
3805
- fillRule: "evenodd",
3806
- clipRule: "evenodd",
3807
- d: "M8 3.268A4.732 4.732 0 1 0 12.732 8H14a6 6 0 1 1-6-6v1.268Z",
3808
- fill: "currentColor"
3809
- }), jsx("path", {
3810
- 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",
3811
- fill: "currentColor"
3812
- })]
3813
- });
3814
- };
3815
- FeelRequiredIcon.defaultProps = {
3816
- viewBox: "0 0 16 16",
3817
- fill: "none",
3818
- xmlns: "http://www.w3.org/2000/svg"
3819
- };
3820
- var FeelOptionalIcon = function FeelOptionalIcon(props) {
3821
- return jsxs("svg", {
4328
+ var FeelIcon$1 = function FeelIcon(props) {
4329
+ return jsx("svg", {
3822
4330
  ...props,
3823
- children: [jsx("path", {
3824
- d: "M5.845 7.04V5.93h4.307v1.11H5.845Zm0 3.07V9h4.307v1.11H5.845Z",
3825
- fill: "currentColor"
3826
- }), jsx("path", {
3827
- fillRule: "evenodd",
3828
- clipRule: "evenodd",
3829
- 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",
3830
- fill: "currentColor"
3831
- })]
4331
+ children: jsx("path", {
4332
+ 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",
4333
+ fill: "currentcolor"
4334
+ })
3832
4335
  });
3833
4336
  };
3834
- FeelOptionalIcon.defaultProps = {
3835
- viewBox: "0 0 16 16",
4337
+ FeelIcon$1.defaultProps = {
4338
+ width: "14",
4339
+ height: "14",
3836
4340
  fill: "none",
3837
4341
  xmlns: "http://www.w3.org/2000/svg"
3838
4342
  };
@@ -4072,6 +4576,18 @@ function useShowEntryEvent(id) {
4072
4576
  * @param {setSticky} setSticky
4073
4577
  */
4074
4578
  function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky) {
4579
+ const [scrollContainer, setScrollContainer] = useState(query(scrollContainerSelector));
4580
+ const updateScrollContainer = useCallback(() => {
4581
+ const newScrollContainer = query(scrollContainerSelector);
4582
+ if (newScrollContainer !== scrollContainer) {
4583
+ setScrollContainer(newScrollContainer);
4584
+ }
4585
+ }, [scrollContainerSelector, scrollContainer]);
4586
+ useEffect(() => {
4587
+ updateScrollContainer();
4588
+ }, [updateScrollContainer]);
4589
+ useEvent('propertiesPanel.attach', updateScrollContainer);
4590
+ useEvent('propertiesPanel.detach', updateScrollContainer);
4075
4591
  useEffect(() => {
4076
4592
  const Observer = IntersectionObserver;
4077
4593
 
@@ -4079,33 +4595,36 @@ function useStickyIntersectionObserver(ref, scrollContainerSelector, setSticky)
4079
4595
  if (!Observer) {
4080
4596
  return;
4081
4597
  }
4082
- let observer;
4083
- if (ref.current) {
4084
- const scrollContainer = query(scrollContainerSelector);
4085
- observer = new Observer(entries => {
4086
- entries.forEach(entry => {
4087
- if (entry.intersectionRatio < 1) {
4088
- setSticky(true);
4089
- } else if (entry.intersectionRatio === 1) {
4090
- setSticky(false);
4091
- }
4092
- });
4093
- }, {
4094
- root: scrollContainer,
4095
- rootMargin: '0px 0px 999999% 0px',
4096
- // Use bottom margin to avoid stickyness when scrolling out to bottom
4097
- threshold: [1]
4098
- });
4099
- observer.observe(ref.current);
4598
+
4599
+ // TODO(@barmac): test this
4600
+ if (!ref.current || !scrollContainer) {
4601
+ return;
4100
4602
  }
4603
+ const observer = new Observer(entries => {
4604
+ // scroll container is unmounted, do not update sticky state
4605
+ if (scrollContainer.scrollHeight === 0) {
4606
+ return;
4607
+ }
4608
+ entries.forEach(entry => {
4609
+ if (entry.intersectionRatio < 1) {
4610
+ setSticky(true);
4611
+ } else if (entry.intersectionRatio === 1) {
4612
+ setSticky(false);
4613
+ }
4614
+ });
4615
+ }, {
4616
+ root: scrollContainer,
4617
+ rootMargin: '0px 0px 999999% 0px',
4618
+ // Use bottom margin to avoid stickyness when scrolling out to bottom
4619
+ threshold: [1]
4620
+ });
4621
+ observer.observe(ref.current);
4101
4622
 
4102
4623
  // Unobserve if unmounted
4103
4624
  return () => {
4104
- if (ref.current && observer) {
4105
- observer.unobserve(ref.current);
4106
- }
4625
+ observer.unobserve(ref.current);
4107
4626
  };
4108
- }, [ref, scrollContainerSelector, setSticky]);
4627
+ }, [ref.current, scrollContainer, setSticky]);
4109
4628
  }
4110
4629
 
4111
4630
  /**
@@ -4238,9 +4757,7 @@ function Placeholder(props) {
4238
4757
  })
4239
4758
  });
4240
4759
  }
4241
- const DEFAULT_LAYOUT = {
4242
- open: true
4243
- };
4760
+ const DEFAULT_LAYOUT = {};
4244
4761
  const DEFAULT_DESCRIPTION = {};
4245
4762
 
4246
4763
  /**
@@ -4327,7 +4844,7 @@ function PropertiesPanel(props) {
4327
4844
  const [layout, setLayout] = useState(createLayout(layoutConfig));
4328
4845
 
4329
4846
  // react to external changes in the layout config
4330
- useUpdateEffect(() => {
4847
+ useUpdateLayoutEffect(() => {
4331
4848
  const newLayout = createLayout(layoutConfig);
4332
4849
  setLayout(newLayout);
4333
4850
  }, [layoutConfig]);
@@ -4404,7 +4921,7 @@ function PropertiesPanel(props) {
4404
4921
  children: jsx(EventContext.Provider, {
4405
4922
  value: eventContext,
4406
4923
  children: jsxs("div", {
4407
- class: classnames('bio-properties-panel', layout.open ? 'open' : ''),
4924
+ class: "bio-properties-panel",
4408
4925
  children: [jsx(Header, {
4409
4926
  element: element,
4410
4927
  headerProvider: headerProvider
@@ -4448,14 +4965,14 @@ function createDescriptionContext(overrides = {}) {
4448
4965
  // hooks //////////////////
4449
4966
 
4450
4967
  /**
4451
- * This hook behaves like useEffect, but does not trigger on the first render.
4968
+ * This hook behaves like useLayoutEffect, but does not trigger on the first render.
4452
4969
  *
4453
4970
  * @param {Function} effect
4454
4971
  * @param {Array} deps
4455
4972
  */
4456
- function useUpdateEffect(effect, deps) {
4973
+ function useUpdateLayoutEffect(effect, deps) {
4457
4974
  const isMounted = useRef(false);
4458
- useEffect(() => {
4975
+ useLayoutEffect(() => {
4459
4976
  if (isMounted.current) {
4460
4977
  return effect();
4461
4978
  } else {
@@ -5073,14 +5590,13 @@ const noop$2 = () => {};
5073
5590
  */
5074
5591
  function FeelIcon(props) {
5075
5592
  const {
5076
- label,
5077
5593
  feel = false,
5078
5594
  active,
5079
5595
  disabled = false,
5080
5596
  onClick = noop$2
5081
5597
  } = props;
5082
- const feelRequiredLabel = ' must be a FEEL expression';
5083
- const feelOptionalLabel = ' can optionally be a FEEL expression';
5598
+ const feelRequiredLabel = 'FEEL expression is mandatory';
5599
+ const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
5084
5600
  const handleClick = e => {
5085
5601
  onClick(e);
5086
5602
 
@@ -5093,10 +5609,124 @@ function FeelIcon(props) {
5093
5609
  class: classnames('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
5094
5610
  onClick: handleClick,
5095
5611
  disabled: feel === 'required' || disabled,
5096
- title: label + (feel === 'required' ? feelRequiredLabel : feelOptionalLabel),
5097
- children: feel === 'required' ? jsx(FeelRequiredIcon, {}) : jsx(FeelOptionalIcon, {})
5612
+ title: feel === 'required' ? feelRequiredLabel : feelOptionalLabel,
5613
+ children: jsx(FeelIcon$1, {})
5614
+ });
5615
+ }
5616
+ function ToggleSwitch(props) {
5617
+ const {
5618
+ id,
5619
+ label,
5620
+ onInput,
5621
+ value,
5622
+ switcherLabel,
5623
+ inline,
5624
+ onFocus,
5625
+ onBlur,
5626
+ inputRef
5627
+ } = props;
5628
+ const [localValue, setLocalValue] = useState(value);
5629
+ const handleInputCallback = async () => {
5630
+ onInput(!value);
5631
+ };
5632
+ const handleInput = e => {
5633
+ handleInputCallback();
5634
+ setLocalValue(e.target.value);
5635
+ };
5636
+ useEffect(() => {
5637
+ if (value === localValue) {
5638
+ return;
5639
+ }
5640
+ setLocalValue(value);
5641
+ }, [value]);
5642
+ return jsxs("div", {
5643
+ class: classnames('bio-properties-panel-toggle-switch', {
5644
+ inline
5645
+ }),
5646
+ children: [jsx("label", {
5647
+ class: "bio-properties-panel-label",
5648
+ for: prefixId$6(id),
5649
+ children: label
5650
+ }), jsxs("div", {
5651
+ class: "bio-properties-panel-field-wrapper",
5652
+ children: [jsxs("label", {
5653
+ class: "bio-properties-panel-toggle-switch__switcher",
5654
+ children: [jsx("input", {
5655
+ ref: inputRef,
5656
+ id: prefixId$6(id),
5657
+ class: "bio-properties-panel-input",
5658
+ type: "checkbox",
5659
+ onFocus: onFocus,
5660
+ onBlur: onBlur,
5661
+ name: id,
5662
+ onInput: handleInput,
5663
+ checked: !!localValue
5664
+ }), jsx("span", {
5665
+ class: "bio-properties-panel-toggle-switch__slider"
5666
+ })]
5667
+ }), switcherLabel && jsx("p", {
5668
+ class: "bio-properties-panel-toggle-switch__label",
5669
+ children: switcherLabel
5670
+ })]
5671
+ })]
5098
5672
  });
5099
5673
  }
5674
+
5675
+ /**
5676
+ * @param {Object} props
5677
+ * @param {Object} props.element
5678
+ * @param {String} props.id
5679
+ * @param {String} props.description
5680
+ * @param {String} props.label
5681
+ * @param {String} props.switcherLabel
5682
+ * @param {Boolean} props.inline
5683
+ * @param {Function} props.getValue
5684
+ * @param {Function} props.setValue
5685
+ * @param {Function} props.onFocus
5686
+ * @param {Function} props.onBlur
5687
+ */
5688
+ function ToggleSwitchEntry(props) {
5689
+ const {
5690
+ element,
5691
+ id,
5692
+ description,
5693
+ label,
5694
+ switcherLabel,
5695
+ inline,
5696
+ getValue,
5697
+ setValue,
5698
+ onFocus,
5699
+ onBlur
5700
+ } = props;
5701
+ const value = getValue(element);
5702
+ return jsxs("div", {
5703
+ class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
5704
+ "data-entry-id": id,
5705
+ children: [jsx(ToggleSwitch, {
5706
+ id: id,
5707
+ label: label,
5708
+ value: value,
5709
+ onInput: setValue,
5710
+ onFocus: onFocus,
5711
+ onBlur: onBlur,
5712
+ switcherLabel: switcherLabel,
5713
+ inline: inline
5714
+ }), jsx(Description$1, {
5715
+ forId: id,
5716
+ element: element,
5717
+ value: description
5718
+ })]
5719
+ });
5720
+ }
5721
+ function isEdited$7(node) {
5722
+ return node && !!node.checked;
5723
+ }
5724
+
5725
+ // helpers /////////////////
5726
+
5727
+ function prefixId$6(id) {
5728
+ return `bio-properties-panel-${id}`;
5729
+ }
5100
5730
  const noop$1 = () => {};
5101
5731
  function FeelTextfield(props) {
5102
5732
  const {
@@ -5115,8 +5745,8 @@ function FeelTextfield(props) {
5115
5745
  const [localValue, _setLocalValue] = useState(value);
5116
5746
  const editorRef = useShowEntryEvent(id);
5117
5747
  const containerRef = useRef();
5118
- const feelActive = localValue.startsWith('=') || feel === 'required';
5119
- const feelOnlyValue = localValue.startsWith('=') ? localValue.substring(1) : localValue;
5748
+ const feelActive = isString(localValue) && localValue.startsWith('=') || feel === 'required';
5749
+ const feelOnlyValue = isString(localValue) && localValue.startsWith('=') ? localValue.substring(1) : localValue;
5120
5750
  const [focus, _setFocus] = useState(undefined);
5121
5751
  const setFocus = (offset = 0) => {
5122
5752
  const hasFocus = containerRef.current.contains(document.activeElement);
@@ -5156,7 +5786,7 @@ function FeelTextfield(props) {
5156
5786
  return;
5157
5787
  }
5158
5788
  setLocalValue(newValue);
5159
- if (!feelActive && newValue.startsWith('=')) {
5789
+ if (!feelActive && isString(newValue) && newValue.startsWith('=')) {
5160
5790
  // focus is behind `=` sign that will be removed
5161
5791
  setFocus(-1);
5162
5792
  }
@@ -5219,9 +5849,11 @@ function FeelTextfield(props) {
5219
5849
  };
5220
5850
  }, [containerRef, feelActive, handleFeelToggle, setFocus]);
5221
5851
  return jsxs("div", {
5222
- class: "bio-properties-panel-feel-entry",
5852
+ class: classnames('bio-properties-panel-feel-entry', {
5853
+ 'feel-active': feelActive
5854
+ }),
5223
5855
  children: [jsxs("label", {
5224
- for: prefixId$6(id),
5856
+ for: prefixId$5(id),
5225
5857
  class: "bio-properties-panel-label",
5226
5858
  onClick: () => setFocus(),
5227
5859
  children: [label, jsx(FeelIcon, {
@@ -5238,7 +5870,7 @@ function FeelTextfield(props) {
5238
5870
  disabled: feel !== 'optional' || disabled,
5239
5871
  onClick: handleFeelToggle
5240
5872
  }), feelActive ? jsx(CodeEditor, {
5241
- id: prefixId$6(id),
5873
+ id: prefixId$5(id),
5242
5874
  name: id,
5243
5875
  onInput: handleLocalInput,
5244
5876
  disabled: disabled,
@@ -5255,7 +5887,8 @@ function FeelTextfield(props) {
5255
5887
  ...props,
5256
5888
  onInput: handleLocalInput,
5257
5889
  contentAttributes: {
5258
- 'id': prefixId$6(id)
5890
+ 'id': prefixId$5(id),
5891
+ 'aria-label': label
5259
5892
  },
5260
5893
  value: localValue,
5261
5894
  ref: editorRef
@@ -5292,7 +5925,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
5292
5925
  }
5293
5926
  };
5294
5927
  return jsx("input", {
5295
- id: prefixId$6(id),
5928
+ id: prefixId$5(id),
5296
5929
  type: "text",
5297
5930
  ref: inputRef,
5298
5931
  name: id,
@@ -5330,7 +5963,7 @@ forwardRef((props, ref) => {
5330
5963
  }
5331
5964
  };
5332
5965
  return jsx("textarea", {
5333
- id: prefixId$6(id),
5966
+ id: prefixId$5(id),
5334
5967
  type: "text",
5335
5968
  ref: inputRef,
5336
5969
  name: id,
@@ -5345,6 +5978,78 @@ forwardRef((props, ref) => {
5345
5978
  "data-gramm": "false"
5346
5979
  });
5347
5980
  });
5981
+ const OptionalFeelToggleSwitch = forwardRef((props, ref) => {
5982
+ const {
5983
+ id,
5984
+ onInput,
5985
+ value,
5986
+ onFocus,
5987
+ onBlur,
5988
+ switcherLabel
5989
+ } = props;
5990
+ const inputRef = useRef();
5991
+
5992
+ // To be consistent with the FEEL editor, set focus at start of input
5993
+ // this ensures clean editing experience when switching with the keyboard
5994
+ ref.current = {
5995
+ focus: () => {
5996
+ const input = inputRef.current;
5997
+ if (!input) {
5998
+ return;
5999
+ }
6000
+ input.focus();
6001
+ }
6002
+ };
6003
+ return jsx(ToggleSwitch, {
6004
+ id: id,
6005
+ value: value,
6006
+ inputRef: inputRef,
6007
+ onInput: onInput,
6008
+ onFocus: onFocus,
6009
+ onBlur: onBlur,
6010
+ switcherLabel: switcherLabel
6011
+ });
6012
+ });
6013
+ forwardRef((props, ref) => {
6014
+ const {
6015
+ id,
6016
+ disabled,
6017
+ onInput,
6018
+ value,
6019
+ onFocus,
6020
+ onBlur
6021
+ } = props;
6022
+ const inputRef = useRef();
6023
+ const handleChange = ({
6024
+ target
6025
+ }) => {
6026
+ onInput(target.checked);
6027
+ };
6028
+
6029
+ // To be consistent with the FEEL editor, set focus at start of input
6030
+ // this ensures clean editing experience when switching with the keyboard
6031
+ ref.current = {
6032
+ focus: () => {
6033
+ const input = inputRef.current;
6034
+ if (!input) {
6035
+ return;
6036
+ }
6037
+ input.focus();
6038
+ }
6039
+ };
6040
+ return jsx("input", {
6041
+ ref: inputRef,
6042
+ id: prefixId$5(id),
6043
+ name: id,
6044
+ onFocus: onFocus,
6045
+ onBlur: onBlur,
6046
+ type: "checkbox",
6047
+ class: "bio-properties-panel-input",
6048
+ onChange: handleChange,
6049
+ checked: value,
6050
+ disabled: disabled
6051
+ });
6052
+ });
5348
6053
 
5349
6054
  /**
5350
6055
  * @param {Object} props
@@ -5452,6 +6157,33 @@ function FeelEntry(props) {
5452
6157
  });
5453
6158
  }
5454
6159
 
6160
+ /**
6161
+ * @param {Object} props
6162
+ * @param {Object} props.element
6163
+ * @param {String} props.id
6164
+ * @param {String} props.description
6165
+ * @param {Boolean} props.debounce
6166
+ * @param {Boolean} props.disabled
6167
+ * @param {Boolean} props.feel
6168
+ * @param {String} props.label
6169
+ * @param {Function} props.getValue
6170
+ * @param {Function} props.setValue
6171
+ * @param {Function} props.tooltipContainer
6172
+ * @param {Function} props.validate
6173
+ * @param {Function} props.show
6174
+ * @param {Function} props.example
6175
+ * @param {Function} props.variables
6176
+ * @param {Function} props.onFocus
6177
+ * @param {Function} props.onBlur
6178
+ */
6179
+ function FeelToggleSwitchEntry(props) {
6180
+ return jsx(FeelEntry, {
6181
+ class: "bio-properties-panel-feel-toggle-switch",
6182
+ OptionalComponent: OptionalFeelToggleSwitch,
6183
+ ...props
6184
+ });
6185
+ }
6186
+
5455
6187
  /**
5456
6188
  * @param {Object} props
5457
6189
  * @param {Object} props.element
@@ -5480,13 +6212,19 @@ function FeelTemplatingEntry(props) {
5480
6212
  ...props
5481
6213
  });
5482
6214
  }
5483
- function isEdited$7(node) {
5484
- return node && (!!node.value || node.classList.contains('edited'));
6215
+ function isEdited$6(node) {
6216
+ if (!node) {
6217
+ return false;
6218
+ }
6219
+ if (node.type === 'checkbox') {
6220
+ return !!node.checked || node.classList.contains('edited');
6221
+ }
6222
+ return !!node.value || node.classList.contains('edited');
5485
6223
  }
5486
6224
 
5487
6225
  // helpers /////////////////
5488
6226
 
5489
- function prefixId$6(id) {
6227
+ function prefixId$5(id) {
5490
6228
  return `bio-properties-panel-${id}`;
5491
6229
  }
5492
6230
  function NumberField(props) {
@@ -5528,11 +6266,11 @@ function NumberField(props) {
5528
6266
  return jsxs("div", {
5529
6267
  class: "bio-properties-panel-numberfield",
5530
6268
  children: [jsx("label", {
5531
- for: prefixId$5(id),
6269
+ for: prefixId$4(id),
5532
6270
  class: "bio-properties-panel-label",
5533
6271
  children: label
5534
6272
  }), jsx("input", {
5535
- id: prefixId$5(id),
6273
+ id: prefixId$4(id),
5536
6274
  type: "number",
5537
6275
  name: id,
5538
6276
  spellCheck: "false",
@@ -5636,13 +6374,13 @@ function NumberFieldEntry(props) {
5636
6374
  })]
5637
6375
  });
5638
6376
  }
5639
- function isEdited$5(node) {
6377
+ function isEdited$4(node) {
5640
6378
  return node && !!node.value;
5641
6379
  }
5642
6380
 
5643
6381
  // helpers /////////////////
5644
6382
 
5645
- function prefixId$5(id) {
6383
+ function prefixId$4(id) {
5646
6384
  return `bio-properties-panel-${id}`;
5647
6385
  }
5648
6386
  function Select(props) {
@@ -5676,12 +6414,12 @@ function Select(props) {
5676
6414
  return jsxs("div", {
5677
6415
  class: "bio-properties-panel-select",
5678
6416
  children: [jsx("label", {
5679
- for: prefixId$4(id),
6417
+ for: prefixId$3(id),
5680
6418
  class: "bio-properties-panel-label",
5681
6419
  children: label
5682
6420
  }), jsx("select", {
5683
6421
  ref: ref,
5684
- id: prefixId$4(id),
6422
+ id: prefixId$3(id),
5685
6423
  name: id,
5686
6424
  class: "bio-properties-panel-input",
5687
6425
  onInput: handleChange,
@@ -5788,13 +6526,13 @@ function SelectEntry(props) {
5788
6526
  })]
5789
6527
  });
5790
6528
  }
5791
- function isEdited$4(node) {
6529
+ function isEdited$3(node) {
5792
6530
  return node && !!node.value;
5793
6531
  }
5794
6532
 
5795
6533
  // helpers /////////////////
5796
6534
 
5797
- function prefixId$4(id) {
6535
+ function prefixId$3(id) {
5798
6536
  return `bio-properties-panel-${id}`;
5799
6537
  }
5800
6538
  function resizeToContents(element) {
@@ -5842,12 +6580,12 @@ function TextArea(props) {
5842
6580
  return jsxs("div", {
5843
6581
  class: "bio-properties-panel-textarea",
5844
6582
  children: [jsx("label", {
5845
- for: prefixId$2(id),
6583
+ for: prefixId$1(id),
5846
6584
  class: "bio-properties-panel-label",
5847
6585
  children: label
5848
6586
  }), jsx("textarea", {
5849
6587
  ref: ref,
5850
- id: prefixId$2(id),
6588
+ id: prefixId$1(id),
5851
6589
  name: id,
5852
6590
  spellCheck: "false",
5853
6591
  class: classnames('bio-properties-panel-input', monospace ? 'bio-properties-panel-input-monospace' : '', autoResize ? 'auto-resize' : ''),
@@ -5875,6 +6613,7 @@ function TextArea(props) {
5875
6613
  * @param {Function} props.onBlur
5876
6614
  * @param {number} props.rows
5877
6615
  * @param {boolean} props.monospace
6616
+ * @param {Function} [props.validate]
5878
6617
  * @param {boolean} [props.disabled]
5879
6618
  */
5880
6619
  function TextAreaEntry(props) {
@@ -5889,12 +6628,38 @@ function TextAreaEntry(props) {
5889
6628
  rows,
5890
6629
  monospace,
5891
6630
  disabled,
6631
+ validate,
5892
6632
  onFocus,
5893
6633
  onBlur,
5894
6634
  autoResize
5895
6635
  } = props;
5896
- const value = getValue(element);
5897
- const error = useError(id);
6636
+ const [cachedInvalidValue, setCachedInvalidValue] = useState(null);
6637
+ const globalError = useError(id);
6638
+ const [localError, setLocalError] = useState(null);
6639
+ let value = getValue(element);
6640
+ const previousValue = usePrevious(value);
6641
+ useEffect(() => {
6642
+ if (isFunction(validate)) {
6643
+ const newValidationError = validate(value) || null;
6644
+ setLocalError(newValidationError);
6645
+ }
6646
+ }, [value]);
6647
+ const onInput = newValue => {
6648
+ let newValidationError = null;
6649
+ if (isFunction(validate)) {
6650
+ newValidationError = validate(newValue) || null;
6651
+ }
6652
+ if (newValidationError) {
6653
+ setCachedInvalidValue(newValue);
6654
+ } else {
6655
+ setValue(newValue);
6656
+ }
6657
+ setLocalError(newValidationError);
6658
+ };
6659
+ if (previousValue === value && localError) {
6660
+ value = cachedInvalidValue;
6661
+ }
6662
+ const error = globalError || localError;
5898
6663
  return jsxs("div", {
5899
6664
  class: classnames('bio-properties-panel-entry', error ? 'has-error' : ''),
5900
6665
  "data-entry-id": id,
@@ -5902,7 +6667,7 @@ function TextAreaEntry(props) {
5902
6667
  id: id,
5903
6668
  label: label,
5904
6669
  value: value,
5905
- onInput: setValue,
6670
+ onInput: onInput,
5906
6671
  onFocus: onFocus,
5907
6672
  onBlur: onBlur,
5908
6673
  rows: rows,
@@ -5920,13 +6685,13 @@ function TextAreaEntry(props) {
5920
6685
  })]
5921
6686
  });
5922
6687
  }
5923
- function isEdited$2(node) {
6688
+ function isEdited$1(node) {
5924
6689
  return node && !!node.value;
5925
6690
  }
5926
6691
 
5927
6692
  // helpers /////////////////
5928
6693
 
5929
- function prefixId$2(id) {
6694
+ function prefixId$1(id) {
5930
6695
  return `bio-properties-panel-${id}`;
5931
6696
  }
5932
6697
  function Textfield(props) {
@@ -5960,12 +6725,12 @@ function Textfield(props) {
5960
6725
  return jsxs("div", {
5961
6726
  class: "bio-properties-panel-textfield",
5962
6727
  children: [jsx("label", {
5963
- for: prefixId$1(id),
6728
+ for: prefixId(id),
5964
6729
  class: "bio-properties-panel-label",
5965
6730
  children: label
5966
6731
  }), jsx("input", {
5967
6732
  ref: ref,
5968
- id: prefixId$1(id),
6733
+ id: prefixId(id),
5969
6734
  type: "text",
5970
6735
  name: id,
5971
6736
  spellCheck: "false",
@@ -6057,13 +6822,13 @@ function TextfieldEntry(props) {
6057
6822
  })]
6058
6823
  });
6059
6824
  }
6060
- function isEdited$1(node) {
6825
+ function isEdited(node) {
6061
6826
  return node && !!node.value;
6062
6827
  }
6063
6828
 
6064
6829
  // helpers /////////////////
6065
6830
 
6066
- function prefixId$1(id) {
6831
+ function prefixId(id) {
6067
6832
  return `bio-properties-panel-${id}`;
6068
6833
  }
6069
6834
 
@@ -6191,7 +6956,7 @@ function ActionEntry(props) {
6191
6956
  component: Action,
6192
6957
  editField: editField,
6193
6958
  field: field,
6194
- isEdited: isEdited$4
6959
+ isEdited: isEdited$3
6195
6960
  });
6196
6961
  }
6197
6962
  return entries;
@@ -6259,7 +7024,7 @@ function AltTextEntry(props) {
6259
7024
  component: AltText,
6260
7025
  editField: editField,
6261
7026
  field: field,
6262
- isEdited: isEdited$7
7027
+ isEdited: isEdited$6
6263
7028
  });
6264
7029
  }
6265
7030
  return entries;
@@ -6304,7 +7069,7 @@ function ColumnsEntry(props) {
6304
7069
  component: Columns,
6305
7070
  field,
6306
7071
  editField,
6307
- isEdited: isEdited$4
7072
+ isEdited: isEdited$3
6308
7073
  }];
6309
7074
  return entries;
6310
7075
  }
@@ -6334,7 +7099,7 @@ function Columns(props) {
6334
7099
  },
6335
7100
  // todo(pinussilvestrus): make options dependant on field type
6336
7101
  // cf. https://github.com/bpmn-io/form-js/issues/575
6337
- ...[2, 4, 6, 8, 10, 12, 14, 16].map(asOption)];
7102
+ ...asArray(16).filter(i => i >= MIN_COLUMNS).map(asOption)];
6338
7103
  };
6339
7104
  return SelectEntry({
6340
7105
  debounce,
@@ -6356,6 +7121,11 @@ function asOption(number) {
6356
7121
  label: number.toString()
6357
7122
  };
6358
7123
  }
7124
+ function asArray(length) {
7125
+ return Array.from({
7126
+ length
7127
+ }).map((_, i) => i + 1);
7128
+ }
6359
7129
 
6360
7130
  function DescriptionEntry(props) {
6361
7131
  const {
@@ -6372,7 +7142,7 @@ function DescriptionEntry(props) {
6372
7142
  component: Description,
6373
7143
  editField: editField,
6374
7144
  field: field,
6375
- isEdited: isEdited$1
7145
+ isEdited: isEdited
6376
7146
  });
6377
7147
  }
6378
7148
  return entries;
@@ -6426,21 +7196,21 @@ function DefaultOptionEntry(props) {
6426
7196
  entries.push({
6427
7197
  ...defaultOptions,
6428
7198
  component: DefaultValueCheckbox,
6429
- isEdited: isEdited$4
7199
+ isEdited: isEdited$3
6430
7200
  });
6431
7201
  }
6432
7202
  if (type === 'number') {
6433
7203
  entries.push({
6434
7204
  ...defaultOptions,
6435
7205
  component: DefaultValueNumber,
6436
- isEdited: isEdited$1
7206
+ isEdited: isEdited
6437
7207
  });
6438
7208
  }
6439
7209
  if (type === 'radio' || type === 'select') {
6440
7210
  entries.push({
6441
7211
  ...defaultOptions,
6442
7212
  component: DefaultValueSingleSelect,
6443
- isEdited: isEdited$4
7213
+ isEdited: isEdited$3
6444
7214
  });
6445
7215
  }
6446
7216
 
@@ -6450,14 +7220,14 @@ function DefaultOptionEntry(props) {
6450
7220
  entries.push({
6451
7221
  ...defaultOptions,
6452
7222
  component: DefaultValueTextfield,
6453
- isEdited: isEdited$1
7223
+ isEdited: isEdited
6454
7224
  });
6455
7225
  }
6456
7226
  if (type === 'textarea') {
6457
7227
  entries.push({
6458
7228
  ...defaultOptions,
6459
7229
  component: DefaultValueTextarea,
6460
- isEdited: isEdited$2
7230
+ isEdited: isEdited$1
6461
7231
  });
6462
7232
  }
6463
7233
  return entries;
@@ -6651,7 +7421,7 @@ function DisabledEntry(props) {
6651
7421
  component: Disabled,
6652
7422
  editField: editField,
6653
7423
  field: field,
6654
- isEdited: isEdited$8
7424
+ isEdited: isEdited$7
6655
7425
  });
6656
7426
  }
6657
7427
  return entries;
@@ -6669,11 +7439,12 @@ function Disabled(props) {
6669
7439
  const setValue = value => {
6670
7440
  return editField(field, path, value);
6671
7441
  };
6672
- return CheckboxEntry({
7442
+ return ToggleSwitchEntry({
6673
7443
  element: field,
6674
7444
  getValue,
6675
7445
  id,
6676
7446
  label: 'Disabled',
7447
+ inline: true,
6677
7448
  setValue
6678
7449
  });
6679
7450
  }
@@ -6690,7 +7461,7 @@ function IdEntry(props) {
6690
7461
  component: Id,
6691
7462
  editField: editField,
6692
7463
  field: field,
6693
- isEdited: isEdited$1
7464
+ isEdited: isEdited
6694
7465
  });
6695
7466
  }
6696
7467
  return entries;
@@ -6770,7 +7541,7 @@ function KeyEntry(props) {
6770
7541
  component: Key$1,
6771
7542
  editField: editField,
6772
7543
  field: field,
6773
- isEdited: isEdited$1
7544
+ isEdited: isEdited
6774
7545
  });
6775
7546
  }
6776
7547
  return entries;
@@ -6833,7 +7604,7 @@ function simpleStringEntryFactory(options) {
6833
7604
  field,
6834
7605
  editField,
6835
7606
  component: SimpleStringComponent,
6836
- isEdited: isEdited$1
7607
+ isEdited: isEdited
6837
7608
  };
6838
7609
  }
6839
7610
  const SimpleStringComponent = props => {
@@ -6953,7 +7724,7 @@ function SourceEntry(props) {
6953
7724
  component: Source,
6954
7725
  editField: editField,
6955
7726
  field: field,
6956
- isEdited: isEdited$7
7727
+ isEdited: isEdited$6
6957
7728
  });
6958
7729
  }
6959
7730
  return entries;
@@ -7008,7 +7779,7 @@ function TextEntry(props) {
7008
7779
  component: Text,
7009
7780
  editField: editField,
7010
7781
  field: field,
7011
- isEdited: isEdited$7
7782
+ isEdited: isEdited$6
7012
7783
  }];
7013
7784
 
7014
7785
  // todo: skipped to make the release without too much risk
@@ -7077,14 +7848,14 @@ function NumberEntries(props) {
7077
7848
  entries.push({
7078
7849
  id: id + '-decimalDigits',
7079
7850
  component: NumberDecimalDigits,
7080
- isEdited: isEdited$5,
7851
+ isEdited: isEdited$4,
7081
7852
  editField,
7082
7853
  field
7083
7854
  });
7084
7855
  entries.push({
7085
7856
  id: id + '-step',
7086
7857
  component: NumberArrowStep,
7087
- isEdited: isEdited$1,
7858
+ isEdited: isEdited,
7088
7859
  editField,
7089
7860
  field
7090
7861
  });
@@ -7222,7 +7993,7 @@ function DateTimeEntry(props) {
7222
7993
  const entries = [{
7223
7994
  id: 'subtype',
7224
7995
  component: DateTimeSubtypeSelect,
7225
- isEdited: isEdited$4,
7996
+ isEdited: isEdited$3,
7226
7997
  editField,
7227
7998
  field
7228
7999
  }];
@@ -7334,7 +8105,7 @@ function DateTimeConstraintsEntry(props) {
7334
8105
  entries.push({
7335
8106
  id: id + '-timeInterval',
7336
8107
  component: TimeIntervalSelect,
7337
- isEdited: isEdited$4,
8108
+ isEdited: isEdited$3,
7338
8109
  editField,
7339
8110
  field
7340
8111
  });
@@ -7413,7 +8184,7 @@ function DateTimeFormatEntry(props) {
7413
8184
  entries.push({
7414
8185
  id: 'time-format',
7415
8186
  component: TimeFormatSelect,
7416
- isEdited: isEdited$4,
8187
+ isEdited: isEdited$3,
7417
8188
  editField,
7418
8189
  field
7419
8190
  });
@@ -7673,7 +8444,7 @@ function ValuesSourceSelectEntry(props) {
7673
8444
  return [{
7674
8445
  id: id + '-select',
7675
8446
  component: ValuesSourceSelect,
7676
- isEdited: isEdited$4,
8447
+ isEdited: isEdited$3,
7677
8448
  editField,
7678
8449
  field
7679
8450
  }];
@@ -7731,7 +8502,7 @@ function InputKeyValuesSourceEntry(props) {
7731
8502
  component: InputValuesKey,
7732
8503
  label: 'Input values key',
7733
8504
  description,
7734
- isEdited: isEdited$1,
8505
+ isEdited: isEdited,
7735
8506
  editField,
7736
8507
  field
7737
8508
  }];
@@ -7868,7 +8639,7 @@ function AdornerEntry(props) {
7868
8639
  entries.push({
7869
8640
  id: 'prefix-adorner',
7870
8641
  component: PrefixAdorner,
7871
- isEdited: isEdited$1,
8642
+ isEdited: isEdited,
7872
8643
  editField,
7873
8644
  field,
7874
8645
  onChange,
@@ -7877,7 +8648,7 @@ function AdornerEntry(props) {
7877
8648
  entries.push({
7878
8649
  id: 'suffix-adorner',
7879
8650
  component: SuffixAdorner,
7880
- isEdited: isEdited$1,
8651
+ isEdited: isEdited,
7881
8652
  editField,
7882
8653
  field,
7883
8654
  onChange,
@@ -7921,6 +8692,55 @@ function SuffixAdorner(props) {
7921
8692
  });
7922
8693
  }
7923
8694
 
8695
+ function ReadonlyEntry(props) {
8696
+ const {
8697
+ editField,
8698
+ field
8699
+ } = props;
8700
+ const {
8701
+ type
8702
+ } = field;
8703
+ const entries = [];
8704
+ if (INPUTS.includes(type)) {
8705
+ entries.push({
8706
+ id: 'readonly',
8707
+ component: Readonly,
8708
+ editField: editField,
8709
+ field: field,
8710
+ isEdited: isEdited$6
8711
+ });
8712
+ }
8713
+ return entries;
8714
+ }
8715
+ function Readonly(props) {
8716
+ const {
8717
+ editField,
8718
+ field,
8719
+ id
8720
+ } = props;
8721
+ const debounce = useService('debounce');
8722
+ const variables = useVariables().map(name => ({
8723
+ name
8724
+ }));
8725
+ const path = ['readonly'];
8726
+ const getValue = () => {
8727
+ return get(field, path, '');
8728
+ };
8729
+ const setValue = value => {
8730
+ return editField(field, path, value || false);
8731
+ };
8732
+ return FeelToggleSwitchEntry({
8733
+ debounce,
8734
+ element: field,
8735
+ feel: 'optional',
8736
+ getValue,
8737
+ id,
8738
+ label: 'Read only',
8739
+ setValue,
8740
+ variables
8741
+ });
8742
+ }
8743
+
7924
8744
  function ConditionEntry(props) {
7925
8745
  const {
7926
8746
  editField,
@@ -7931,7 +8751,7 @@ function ConditionEntry(props) {
7931
8751
  component: Condition,
7932
8752
  editField: editField,
7933
8753
  field: field,
7934
- isEdited: isEdited$7
8754
+ isEdited: isEdited$6
7935
8755
  }];
7936
8756
  }
7937
8757
  function Condition(props) {
@@ -8010,6 +8830,9 @@ function GeneralGroup(field, editField, getService) {
8010
8830
  }), ...DisabledEntry({
8011
8831
  field,
8012
8832
  editField
8833
+ }), ...ReadonlyEntry({
8834
+ field,
8835
+ editField
8013
8836
  })];
8014
8837
  return {
8015
8838
  id: 'general',
@@ -8100,7 +8923,7 @@ function ValidationGroup(field, editField) {
8100
8923
  getValue,
8101
8924
  field,
8102
8925
  editField,
8103
- isEdited: isEdited$1,
8926
+ isEdited: isEdited,
8104
8927
  onChange
8105
8928
  });
8106
8929
  }
@@ -8110,14 +8933,14 @@ function ValidationGroup(field, editField) {
8110
8933
  component: MinLength,
8111
8934
  getValue,
8112
8935
  field,
8113
- isEdited: isEdited$5,
8936
+ isEdited: isEdited$4,
8114
8937
  onChange
8115
8938
  }, {
8116
8939
  id: 'maxLength',
8117
8940
  component: MaxLength,
8118
8941
  getValue,
8119
8942
  field,
8120
- isEdited: isEdited$5,
8943
+ isEdited: isEdited$4,
8121
8944
  onChange
8122
8945
  });
8123
8946
  }
@@ -8127,7 +8950,7 @@ function ValidationGroup(field, editField) {
8127
8950
  component: Pattern,
8128
8951
  getValue,
8129
8952
  field,
8130
- isEdited: isEdited$1,
8953
+ isEdited: isEdited,
8131
8954
  onChange
8132
8955
  });
8133
8956
  }
@@ -8137,14 +8960,14 @@ function ValidationGroup(field, editField) {
8137
8960
  component: Min,
8138
8961
  getValue,
8139
8962
  field,
8140
- isEdited: isEdited$5,
8963
+ isEdited: isEdited$4,
8141
8964
  onChange
8142
8965
  }, {
8143
8966
  id: 'max',
8144
8967
  component: Max,
8145
8968
  getValue,
8146
8969
  field,
8147
- isEdited: isEdited$5,
8970
+ isEdited: isEdited$4,
8148
8971
  onChange
8149
8972
  });
8150
8973
  }