@bpmn-io/form-js-editor 0.14.0 → 0.15.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 (37) hide show
  1. package/LICENSE +22 -22
  2. package/README.md +116 -116
  3. package/dist/assets/form-js-editor-base.css +704 -489
  4. package/dist/assets/form-js-editor.css +229 -35
  5. package/dist/index.cjs +1049 -523
  6. package/dist/index.cjs.map +1 -1
  7. package/dist/index.es.js +920 -394
  8. package/dist/index.es.js.map +1 -1
  9. package/dist/types/FormEditor.d.ts +9 -4
  10. package/dist/types/core/EventBus.d.ts +1 -1
  11. package/dist/types/core/FormLayoutValidator.d.ts +5 -1
  12. package/dist/types/core/index.d.ts +2 -1
  13. package/dist/types/features/dragging/Dragging.d.ts +3 -3
  14. package/dist/types/features/editor-actions/FormEditorActions.d.ts +2 -1
  15. package/dist/types/features/editor-actions/index.d.ts +1 -1
  16. package/dist/types/features/keyboard/index.d.ts +1 -1
  17. package/dist/types/features/modeling/FormLayoutUpdater.d.ts +2 -1
  18. package/dist/types/features/modeling/behavior/IdBehavior.d.ts +2 -1
  19. package/dist/types/features/modeling/behavior/KeyBehavior.d.ts +2 -1
  20. package/dist/types/features/modeling/behavior/ValidateBehavior.d.ts +2 -1
  21. package/dist/types/features/modeling/index.d.ts +6 -1
  22. package/dist/types/features/palette/PaletteRenderer.d.ts +1 -1
  23. package/dist/types/features/palette/components/Palette.d.ts +1 -1
  24. package/dist/types/features/properties-panel/PropertiesPanel.d.ts +1 -1
  25. package/dist/types/features/properties-panel/PropertiesPanelHeaderProvider.d.ts +1 -1
  26. package/dist/types/features/properties-panel/PropertiesPanelRenderer.d.ts +1 -1
  27. package/dist/types/features/properties-panel/entries/InputKeyValuesSourceEntry.d.ts +1 -1
  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/dist/types/types.d.ts +28 -28
  36. package/package.json +4 -3
  37. package/dist/types/features/properties-panel/icons/index.d.ts +0 -1
package/dist/index.es.js CHANGED
@@ -4,11 +4,11 @@ import Ids from 'ids';
4
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';
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, useMemo, useLayoutEffect } 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.
189
+ *
190
+ * @template T
160
191
  *
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
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,18 +506,18 @@ 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);
448
515
  }
449
516
 
450
- /**
451
- * A factory to create a configurable debouncer.
452
- *
453
- * @param {number|boolean} [config=true]
517
+ /**
518
+ * A factory to create a configurable debouncer.
519
+ *
520
+ * @param {number|boolean} [config=true]
454
521
  */
455
522
  function DebounceFactory(config = true) {
456
523
  const timeout = typeof config === 'number' ? config : config ? 300 : 0;
@@ -463,11 +530,11 @@ function DebounceFactory(config = true) {
463
530
  DebounceFactory.$inject = ['config.debounce'];
464
531
 
465
532
  class FieldFactory {
466
- /**
467
- * @constructor
468
- *
469
- * @param { import('./FormFieldRegistry').default } formFieldRegistry
470
- * @param { import('@bpmn-io/form-js-viewer').FormFields } formFields
533
+ /**
534
+ * @constructor
535
+ *
536
+ * @param { import('./FormFieldRegistry').default } formFieldRegistry
537
+ * @param { import('@bpmn-io/form-js-viewer').FormFields } formFields
471
538
  */
472
539
  constructor(formFieldRegistry, formFields) {
473
540
  this._formFieldRegistry = formFieldRegistry;
@@ -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;
@@ -527,11 +597,11 @@ class FieldFactory {
527
597
  FieldFactory.$inject = ['formFieldRegistry', 'formFields'];
528
598
 
529
599
  class FormFieldRegistry extends FormFieldRegistry$1 {
530
- /**
531
- * Updates a form fields id.
532
- *
533
- * @param {Object} formField
534
- * @param {string} newId
600
+ /**
601
+ * Updates a form fields id.
602
+ *
603
+ * @param {Object} formField
604
+ * @param {string} newId
535
605
  */
536
606
  updateId(formField, newId) {
537
607
  this._validateId(newId);
@@ -552,13 +622,13 @@ class FormFieldRegistry extends FormFieldRegistry$1 {
552
622
  }
553
623
  }
554
624
 
555
- /**
556
- * Validate the suitability of the given id and signals a problem
557
- * with an exception.
558
- *
559
- * @param {string} id
560
- *
561
- * @throws {Error} if id is empty or already assigned
625
+ /**
626
+ * Validate the suitability of the given id and signals a problem
627
+ * with an exception.
628
+ *
629
+ * @param {string} id
630
+ *
631
+ * @throws {Error} if id is empty or already assigned
562
632
  */
563
633
  _validateId(id) {
564
634
  if (!id) {
@@ -570,12 +640,16 @@ 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
- /**
575
- * @constructor
576
- *
577
- * @param { import('./FormLayouter').default } formLayouter
578
- * @param { import('./FormFieldRegistry').default } formFieldRegistry
648
+ /**
649
+ * @constructor
650
+ *
651
+ * @param { import('./FormLayouter').default } formLayouter
652
+ * @param { import('./FormFieldRegistry').default } formFieldRegistry
579
653
  */
580
654
  constructor(formLayouter, formFieldRegistry) {
581
655
  this._formLayouter = formLayouter;
@@ -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,23 +690,30 @@ 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
- /**
632
- * @constructor
633
- * @param { import('../core/FormFieldRegistry').default } formFieldRegistry
634
- * @param { import('../core/FieldFactory').default } fieldFactory
635
- * @param { import('../core/FormLayouter').default } formLayouter
712
+ /**
713
+ * @constructor
714
+ * @param { import('../core/FormFieldRegistry').default } formFieldRegistry
715
+ * @param { import('../core/FieldFactory').default } fieldFactory
716
+ * @param { import('../core/FormLayouter').default } formLayouter
636
717
  */
637
718
  constructor(formFieldRegistry, fieldFactory, formLayouter) {
638
719
  this._formFieldRegistry = formFieldRegistry;
@@ -640,21 +721,21 @@ class Importer {
640
721
  this._formLayouter = formLayouter;
641
722
  }
642
723
 
643
- /**
644
- * Import schema creating rows, fields, attaching additional
645
- * information to each field and adding fields to the
646
- * field registry.
647
- *
648
- * Additional information attached:
649
- *
650
- * * `id` (unless present)
651
- * * `_parent`
652
- * * `_path`
653
- *
654
- * @param {any} schema
655
- *
656
- * @typedef {{ warnings: Error[], schema: any }} ImportResult
657
- * @returns {ImportResult}
724
+ /**
725
+ * Import schema creating rows, fields, attaching additional
726
+ * information to each field and adding fields to the
727
+ * field registry.
728
+ *
729
+ * Additional information attached:
730
+ *
731
+ * * `id` (unless present)
732
+ * * `_parent`
733
+ * * `_path`
734
+ *
735
+ * @param {any} schema
736
+ *
737
+ * @typedef {{ warnings: Error[], schema: any }} ImportResult
738
+ * @returns {ImportResult}
658
739
  */
659
740
  importSchema(schema) {
660
741
  // TODO: Add warnings
@@ -672,12 +753,12 @@ class Importer {
672
753
  }
673
754
  }
674
755
 
675
- /**
676
- * @param {{[x: string]: any}} fieldAttrs
677
- * @param {String} [parentId]
678
- * @param {number} [index]
679
- *
680
- * @return {any} field
756
+ /**
757
+ * @param {{[x: string]: any}} fieldAttrs
758
+ * @param {String} [parentId]
759
+ * @param {number} [index]
760
+ *
761
+ * @return {any} field
681
762
  */
682
763
  importFormField(fieldAttrs, parentId, index) {
683
764
  const {
@@ -714,11 +795,11 @@ class Importer {
714
795
  return field;
715
796
  }
716
797
 
717
- /**
718
- * @param {Array<any>} components
719
- * @param {string} parentId
720
- *
721
- * @return {Array<any>} imported components
798
+ /**
799
+ * @param {Array<any>} components
800
+ * @param {string} parentId
801
+ *
802
+ * @return {Array<any>} imported components
722
803
  */
723
804
  importFormFields(components, parentId) {
724
805
  return components.map((component, index) => {
@@ -743,16 +824,101 @@ 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
  });
749
915
  var DragAndDropContext$1 = DragAndDropContext;
750
916
 
751
- /**
752
- * @param {string} type
753
- * @param {boolean} [strict]
754
- *
755
- * @returns {any}
917
+ /**
918
+ * @param {string} type
919
+ * @param {boolean} [strict]
920
+ *
921
+ * @returns {any}
756
922
  */
757
923
  function getService$1(type, strict) {}
758
924
  const FormEditorContext = createContext({
@@ -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]);
@@ -1045,19 +1238,19 @@ const DRAG_NO_DROP_CLS = 'fjs-no-drop';
1045
1238
  const DRAG_NO_MOVE_CLS = 'fjs-no-move';
1046
1239
  const ERROR_DROP_CLS = 'fjs-error-drop';
1047
1240
 
1048
- /**
1049
- * @typedef { { id: String, components: Array<any> } } FormRow
1241
+ /**
1242
+ * @typedef { { id: String, components: Array<any> } } FormRow
1050
1243
  */
1051
1244
 
1052
1245
  class Dragging {
1053
- /**
1054
- * @constructor
1055
- *
1056
- * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1057
- * @param { import('../../core/FormLayouter').default } formLayouter
1058
- * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1059
- * @param { import('../../core/EventBus').default } eventBus
1060
- * @param { import('../modeling/Modeling').default } modeling
1246
+ /**
1247
+ * @constructor
1248
+ *
1249
+ * @param { import('../../core/FormFieldRegistry').default } formFieldRegistry
1250
+ * @param { import('../../core/FormLayouter').default } formLayouter
1251
+ * @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
1252
+ * @param { import('../../core/EventBus').default } eventBus
1253
+ * @param { import('../modeling/Modeling').default } modeling
1061
1254
  */
1062
1255
  constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling) {
1063
1256
  this._formFieldRegistry = formFieldRegistry;
@@ -1067,13 +1260,13 @@ class Dragging {
1067
1260
  this._modeling = modeling;
1068
1261
  }
1069
1262
 
1070
- /**
1071
- * Calculcates position in form schema given the dropped place.
1072
- *
1073
- * @param { FormRow } targetRow
1074
- * @param { any } targetFormField
1075
- * @param { HTMLElement } sibling
1076
- * @returns { number }
1263
+ /**
1264
+ * Calculcates position in form schema given the dropped place.
1265
+ *
1266
+ * @param { FormRow } targetRow
1267
+ * @param { any } targetFormField
1268
+ * @param { HTMLElement } sibling
1269
+ * @returns { number }
1077
1270
  */
1078
1271
  getTargetIndex(targetRow, targetFormField, sibling) {
1079
1272
  /** @type HTMLElement */
@@ -1175,8 +1368,8 @@ class Dragging {
1175
1368
  }
1176
1369
  }
1177
1370
 
1178
- /**
1179
- * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1371
+ /**
1372
+ * @param { { container: Array<string>, direction: string, mirrorContainer: string } } options
1180
1373
  */
1181
1374
  createDragulaInstance(options) {
1182
1375
  const {
@@ -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;
@@ -1407,9 +1730,15 @@ function Element(props) {
1407
1730
  children: selection.isSelected(field) && field.type !== 'default' ? jsx("button", {
1408
1731
  class: "fjs-context-pad-item",
1409
1732
  onClick: onRemove,
1410
- children: jsx(ListDeleteIcon, {})
1733
+ children: jsx(DeleteIcon$1, {})
1411
1734
  }) : null
1412
- }), props.children]
1735
+ }), props.children, jsx(FieldResizer, {
1736
+ position: "left",
1737
+ field: field
1738
+ }), jsx(FieldResizer, {
1739
+ position: "right",
1740
+ field: field
1741
+ })]
1413
1742
  });
1414
1743
  }
1415
1744
  function DebugColumns(props) {
@@ -1421,7 +1750,7 @@ function DebugColumns(props) {
1421
1750
  return null;
1422
1751
  }
1423
1752
  return jsx("div", {
1424
- style: "width: fit-content;\r padding: 2px 6px;\r height: 16px;\r background: var(--color-blue-205-100-95);\r display: flex;\r justify-content: center;\r align-items: center;\r position: absolute;\r bottom: -2px;\r z-index: 2;\r font-size: 10px;\r right: 3px;",
1753
+ style: "width: fit-content; padding: 2px 6px; height: 16px; background: var(--color-blue-205-100-95); display: flex; justify-content: center; align-items: center; position: absolute; bottom: -2px; z-index: 2; font-size: 10px; right: 3px;",
1425
1754
  class: "fjs-debug-columns",
1426
1755
  children: (field.layout || {}).columns || 'auto'
1427
1756
  });
@@ -1494,8 +1823,12 @@ function FormEditor$1(props) {
1494
1823
  propertiesPanel = useService$1('propertiesPanel'),
1495
1824
  propertiesPanelConfig = useService$1('config.propertiesPanel');
1496
1825
  const {
1497
- schema
1826
+ schema,
1827
+ properties
1498
1828
  } = formEditor._getState();
1829
+ const {
1830
+ ariaLabel
1831
+ } = properties;
1499
1832
  const formContainerRef = useRef(null);
1500
1833
  const paletteRef = useRef(null);
1501
1834
  const propertiesPanelRef = useRef(null);
@@ -1581,6 +1914,7 @@ function FormEditor$1(props) {
1581
1914
  data: {},
1582
1915
  errors: {},
1583
1916
  properties: {
1917
+ ariaLabel,
1584
1918
  readOnly: true
1585
1919
  },
1586
1920
  schema
@@ -1767,6 +2101,12 @@ var core = {
1767
2101
  fieldFactory: ['type', FieldFactory]
1768
2102
  };
1769
2103
 
2104
+ /**
2105
+ * @typedef {import('didi').Injector} Injector
2106
+ *
2107
+ * @typedef {import('../../core/EventBus').default} EventBus
2108
+ */
2109
+
1770
2110
  var NOT_REGISTERED_ERROR = 'is not a registered action',
1771
2111
  IS_REGISTERED_ERROR = 'is already registered';
1772
2112
 
@@ -1896,10 +2236,10 @@ EditorActions.prototype._registerDefaultActions = function (injector) {
1896
2236
  /**
1897
2237
  * Triggers a registered action
1898
2238
  *
1899
- * @param {string} action
1900
- * @param {Object} opts
2239
+ * @param {string} action
2240
+ * @param {Object} opts
1901
2241
  *
1902
- * @return {Unknown} Returns what the registered listener returns
2242
+ * @return {unknown} Returns what the registered listener returns
1903
2243
  */
1904
2244
  EditorActions.prototype.trigger = function (action, opts) {
1905
2245
  if (!this._actions[action]) {
@@ -1928,7 +2268,7 @@ EditorActions.prototype.trigger = function (action, opts) {
1928
2268
  * editorActions.isRegistered('spaceTool'); // true
1929
2269
  * ´´´
1930
2270
  *
1931
- * @param {Object} actions
2271
+ * @param {Object} actions
1932
2272
  */
1933
2273
  EditorActions.prototype.register = function (actions, listener) {
1934
2274
  var self = this;
@@ -1943,8 +2283,8 @@ EditorActions.prototype.register = function (actions, listener) {
1943
2283
  /**
1944
2284
  * Registers a listener to an action key
1945
2285
  *
1946
- * @param {string} action
1947
- * @param {Function} listener
2286
+ * @param {string} action
2287
+ * @param {Function} listener
1948
2288
  */
1949
2289
  EditorActions.prototype._registerAction = function (action, listener) {
1950
2290
  if (this.isRegistered(action)) {
@@ -1988,6 +2328,9 @@ function error(action, message) {
1988
2328
  return new Error(action + ' ' + message);
1989
2329
  }
1990
2330
 
2331
+ /**
2332
+ * @type { import('didi').ModuleDeclaration }
2333
+ */
1991
2334
  var EditorActionsModule$1 = {
1992
2335
  __init__: ['editorActions'],
1993
2336
  editorActions: ['type', EditorActions]
@@ -2047,10 +2390,10 @@ var DraggingModule = {
2047
2390
  dragging: ['type', Dragging]
2048
2391
  };
2049
2392
 
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'];
2393
+ var KEYS_COPY = ['c', 'C'];
2394
+ var KEYS_PASTE = ['v', 'V'];
2395
+ var KEYS_REDO = ['y', 'Y'];
2396
+ var KEYS_UNDO = ['z', 'Z'];
2054
2397
 
2055
2398
  /**
2056
2399
  * Returns true if event was triggered with any modifier
@@ -2075,7 +2418,7 @@ function isCmd(event) {
2075
2418
  /**
2076
2419
  * Checks if key pressed is one of provided keys.
2077
2420
  *
2078
- * @param {string|Array<string>} keys
2421
+ * @param {string|string[]} keys
2079
2422
  * @param {KeyboardEvent} event
2080
2423
  */
2081
2424
  function isKey(keys, event) {
@@ -2096,12 +2439,16 @@ function isPaste(event) {
2096
2439
  return isCmd(event) && isKey(KEYS_PASTE, event);
2097
2440
  }
2098
2441
  function isUndo(event) {
2099
- return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO$1, event);
2442
+ return isCmd(event) && !isShift(event) && isKey(KEYS_UNDO, event);
2100
2443
  }
2101
2444
  function isRedo(event) {
2102
- return isCmd(event) && (isKey(KEYS_REDO$1, event) || isKey(KEYS_UNDO$1, event) && isShift(event));
2445
+ return isCmd(event) && (isKey(KEYS_REDO, event) || isKey(KEYS_UNDO, event) && isShift(event));
2103
2446
  }
2104
2447
 
2448
+ /**
2449
+ * @typedef {import('../../core/EventBus').default} EventBus
2450
+ */
2451
+
2105
2452
  var KEYDOWN_EVENT = 'keyboard.keydown',
2106
2453
  KEYUP_EVENT = 'keyboard.keyup';
2107
2454
  var HANDLE_MODIFIER_ATTRIBUTE = 'input-handle-modified-keys';
@@ -2128,7 +2475,7 @@ var DEFAULT_PRIORITY$1 = 1000;
2128
2475
  * A default binding for the keyboard may be specified via the
2129
2476
  * `keyboard.bindTo` configuration option.
2130
2477
  *
2131
- * @param {Config} config
2478
+ * @param {Object} config
2132
2479
  * @param {EventBus} eventBus
2133
2480
  */
2134
2481
  function Keyboard(config, eventBus) {
@@ -2257,8 +2604,6 @@ function isInput(target) {
2257
2604
  }
2258
2605
 
2259
2606
  var LOW_PRIORITY$1 = 500;
2260
- var KEYS_REDO = ['y', 'Y', 'KeyY'];
2261
- var KEYS_UNDO = ['z', 'Z', 'KeyZ'];
2262
2607
 
2263
2608
  /**
2264
2609
  * Adds default keyboard bindings.
@@ -2389,6 +2734,9 @@ KeyboardBindings.prototype.registerBindings = function (keyboard, editorActions)
2389
2734
  });
2390
2735
  };
2391
2736
 
2737
+ /**
2738
+ * @type { import('didi').ModuleDeclaration }
2739
+ */
2392
2740
  var KeyboardModule$1 = {
2393
2741
  __init__: ['keyboard', 'keyboardBindings'],
2394
2742
  keyboard: ['type', Keyboard],
@@ -2468,10 +2816,10 @@ function updateRow(formField, rowId) {
2468
2816
  }
2469
2817
 
2470
2818
  class AddFormFieldHandler {
2471
- /**
2472
- * @constructor
2473
- * @param { import('../../../FormEditor').default } formEditor
2474
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2819
+ /**
2820
+ * @constructor
2821
+ * @param { import('../../../FormEditor').default } formEditor
2822
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2475
2823
  */
2476
2824
  constructor(formEditor, formFieldRegistry) {
2477
2825
  this._formEditor = formEditor;
@@ -2532,10 +2880,10 @@ class AddFormFieldHandler {
2532
2880
  AddFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
2533
2881
 
2534
2882
  class EditFormFieldHandler {
2535
- /**
2536
- * @constructor
2537
- * @param { import('../../../FormEditor').default } formEditor
2538
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2883
+ /**
2884
+ * @constructor
2885
+ * @param { import('../../../FormEditor').default } formEditor
2886
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2539
2887
  */
2540
2888
  constructor(formEditor, formFieldRegistry) {
2541
2889
  this._formEditor = formEditor;
@@ -2598,10 +2946,10 @@ class EditFormFieldHandler {
2598
2946
  EditFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
2599
2947
 
2600
2948
  class MoveFormFieldHandler {
2601
- /**
2602
- * @constructor
2603
- * @param { import('../../../FormEditor').default } formEditor
2604
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2949
+ /**
2950
+ * @constructor
2951
+ * @param { import('../../../FormEditor').default } formEditor
2952
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2605
2953
  */
2606
2954
  constructor(formEditor, formFieldRegistry) {
2607
2955
  this._formEditor = formEditor;
@@ -2690,10 +3038,10 @@ class MoveFormFieldHandler {
2690
3038
  MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
2691
3039
 
2692
3040
  class RemoveFormFieldHandler {
2693
- /**
2694
- * @constructor
2695
- * @param { import('../../../FormEditor').default } formEditor
2696
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3041
+ /**
3042
+ * @constructor
3043
+ * @param { import('../../../FormEditor').default } formEditor
3044
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2697
3045
  */
2698
3046
  constructor(formEditor, formFieldRegistry) {
2699
3047
  this._formEditor = formEditor;
@@ -2753,9 +3101,9 @@ class RemoveFormFieldHandler {
2753
3101
  RemoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
2754
3102
 
2755
3103
  class UpdateIdClaimHandler {
2756
- /**
2757
- * @constructor
2758
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3104
+ /**
3105
+ * @constructor
3106
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2759
3107
  */
2760
3108
  constructor(formFieldRegistry) {
2761
3109
  this._formFieldRegistry = formFieldRegistry;
@@ -2788,9 +3136,9 @@ class UpdateIdClaimHandler {
2788
3136
  UpdateIdClaimHandler.$inject = ['formFieldRegistry'];
2789
3137
 
2790
3138
  class UpdateKeyClaimHandler {
2791
- /**
2792
- * @constructor
2793
- * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
3139
+ /**
3140
+ * @constructor
3141
+ * @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
2794
3142
  */
2795
3143
  constructor(formFieldRegistry) {
2796
3144
  this._formFieldRegistry = formFieldRegistry;
@@ -2924,32 +3272,46 @@ class Modeling {
2924
3272
  }
2925
3273
  Modeling.$inject = ['commandStack', 'eventBus', 'formEditor', 'formFieldRegistry', 'fieldFactory'];
2926
3274
 
3275
+ /**
3276
+ * @typedef {import('../core/Types').ElementLike} ElementLike
3277
+ * @typedef {import('../core/EventBus').default} EventBus
3278
+ * @typedef {import('./CommandStack').CommandContext} CommandContext
3279
+ *
3280
+ * @typedef {string|string[]} Events
3281
+ * @typedef { (context: CommandContext) => ElementLike[] | void } HandlerFunction
3282
+ * @typedef { (context: CommandContext) => void } ComposeHandlerFunction
3283
+ */
3284
+
2927
3285
  var DEFAULT_PRIORITY = 1000;
2928
3286
 
2929
3287
  /**
2930
- * A utility that can be used to plug-in into the command execution for
3288
+ * A utility that can be used to plug into the command execution for
2931
3289
  * extension and/or validation.
2932
3290
  *
2933
- * @param {EventBus} eventBus
3291
+ * @class
3292
+ * @constructor
2934
3293
  *
2935
3294
  * @example
2936
3295
  *
2937
- * import inherits from 'inherits-browser';
2938
- *
3296
+ * ```javascript
2939
3297
  * import CommandInterceptor from 'diagram-js/lib/command/CommandInterceptor';
2940
3298
  *
2941
- * function CommandLogger(eventBus) {
2942
- * CommandInterceptor.call(this, eventBus);
3299
+ * class CommandLogger extends CommandInterceptor {
3300
+ * constructor(eventBus) {
3301
+ * super(eventBus);
2943
3302
  *
2944
- * this.preExecute(function(event) {
2945
- * console.log('command pre-execute', event);
3303
+ * this.preExecute('shape.create', (event) => {
3304
+ * console.log('commandStack.shape-create.preExecute', event);
2946
3305
  * });
2947
3306
  * }
3307
+ * ```
2948
3308
  *
2949
- * inherits(CommandLogger, CommandInterceptor);
2950
- *
3309
+ * @param {EventBus} eventBus
2951
3310
  */
2952
3311
  function CommandInterceptor(eventBus) {
3312
+ /**
3313
+ * @type {EventBus}
3314
+ */
2953
3315
  this._eventBus = eventBus;
2954
3316
  }
2955
3317
  CommandInterceptor.$inject = ['eventBus'];
@@ -2960,15 +3322,14 @@ function unwrapEvent(fn, that) {
2960
3322
  }
2961
3323
 
2962
3324
  /**
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
3325
+ * Intercept a command during one of the phases.
3326
+ *
3327
+ * @param {Events} [events] command(s) to intercept
3328
+ * @param {string} [hook] phase to intercept
3329
+ * @param {number} [priority]
3330
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3331
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3332
+ * @param {any} [that]
2972
3333
  */
2973
3334
  CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, unwrap, that) {
2974
3335
  if (isFunction(hook) || isNumber(hook)) {
@@ -3003,28 +3364,130 @@ CommandInterceptor.prototype.on = function (events, hook, priority, handlerFn, u
3003
3364
  eventBus.on(fullEvent, priority, unwrap ? unwrapEvent(handlerFn, that) : handlerFn, that);
3004
3365
  });
3005
3366
  };
3006
- var hooks = ['canExecute', 'preExecute', 'preExecuted', 'execute', 'executed', 'postExecute', 'postExecuted', 'revert', 'reverted'];
3367
+
3368
+ /**
3369
+ * Add a <canExecute> phase of command interceptor.
3370
+ *
3371
+ * @param {Events} [events] command(s) to intercept
3372
+ * @param {number} [priority]
3373
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3374
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3375
+ * @param {any} [that]
3376
+ */
3377
+ CommandInterceptor.prototype.canExecute = createHook('canExecute');
3378
+
3379
+ /**
3380
+ * Add a <preExecute> phase of command interceptor.
3381
+ *
3382
+ * @param {Events} [events] command(s) to intercept
3383
+ * @param {number} [priority]
3384
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3385
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3386
+ * @param {any} [that]
3387
+ */
3388
+ CommandInterceptor.prototype.preExecute = createHook('preExecute');
3389
+
3390
+ /**
3391
+ * Add a <preExecuted> phase of command interceptor.
3392
+ *
3393
+ * @param {Events} [events] command(s) to intercept
3394
+ * @param {number} [priority]
3395
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3396
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3397
+ * @param {any} [that]
3398
+ */
3399
+ CommandInterceptor.prototype.preExecuted = createHook('preExecuted');
3400
+
3401
+ /**
3402
+ * Add a <execute> phase of command interceptor.
3403
+ *
3404
+ * @param {Events} [events] command(s) to intercept
3405
+ * @param {number} [priority]
3406
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3407
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3408
+ * @param {any} [that]
3409
+ */
3410
+ CommandInterceptor.prototype.execute = createHook('execute');
3411
+
3412
+ /**
3413
+ * Add a <executed> phase of command interceptor.
3414
+ *
3415
+ * @param {Events} [events] command(s) to intercept
3416
+ * @param {number} [priority]
3417
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3418
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3419
+ * @param {any} [that]
3420
+ */
3421
+ CommandInterceptor.prototype.executed = createHook('executed');
3422
+
3423
+ /**
3424
+ * Add a <postExecute> phase of command interceptor.
3425
+ *
3426
+ * @param {Events} [events] command(s) to intercept
3427
+ * @param {number} [priority]
3428
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3429
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3430
+ * @param {any} [that]
3431
+ */
3432
+ CommandInterceptor.prototype.postExecute = createHook('postExecute');
3433
+
3434
+ /**
3435
+ * Add a <postExecuted> phase of command interceptor.
3436
+ *
3437
+ * @param {Events} [events] command(s) to intercept
3438
+ * @param {number} [priority]
3439
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3440
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3441
+ * @param {any} [that]
3442
+ */
3443
+ CommandInterceptor.prototype.postExecuted = createHook('postExecuted');
3444
+
3445
+ /**
3446
+ * Add a <revert> phase of command interceptor.
3447
+ *
3448
+ * @param {Events} [events] command(s) to intercept
3449
+ * @param {number} [priority]
3450
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3451
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3452
+ * @param {any} [that]
3453
+ */
3454
+ CommandInterceptor.prototype.revert = createHook('revert');
3455
+
3456
+ /**
3457
+ * Add a <reverted> phase of command interceptor.
3458
+ *
3459
+ * @param {Events} [events] command(s) to intercept
3460
+ * @param {number} [priority]
3461
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3462
+ * @param {boolean} [unwrap] whether the event should be unwrapped
3463
+ * @param {any} [that]
3464
+ */
3465
+ CommandInterceptor.prototype.reverted = createHook('reverted');
3007
3466
 
3008
3467
  /*
3009
- * Install hook shortcuts
3468
+ * Add prototype methods for each phase of command execution (e.g. execute,
3469
+ * revert).
3010
3470
  *
3011
- * This will generate the CommandInterceptor#(preExecute|...|reverted) methods
3012
- * which will in term forward to CommandInterceptor#on.
3471
+ * @param {string} hook
3472
+ *
3473
+ * @return { (
3474
+ * events?: Events,
3475
+ * priority?: number,
3476
+ * handlerFn: ComposeHandlerFunction|HandlerFunction,
3477
+ * unwrap?: boolean
3478
+ * ) => any }
3013
3479
  */
3014
- forEach(hooks, function (hook) {
3480
+ function createHook(hook) {
3015
3481
  /**
3016
- * {canExecute|preExecute|preExecuted|execute|executed|postExecute|postExecuted|revert|reverted}
3017
- *
3018
- * A named hook for plugging into the command execution
3482
+ * @this {CommandInterceptor}
3019
3483
  *
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
3484
+ * @param {Events} [events]
3485
+ * @param {number} [priority]
3486
+ * @param {ComposeHandlerFunction|HandlerFunction} handlerFn
3487
+ * @param {boolean} [unwrap]
3488
+ * @param {any} [that]
3026
3489
  */
3027
- CommandInterceptor.prototype[hook] = function (events, priority, handlerFn, unwrap, that) {
3490
+ const hookFn = function (events, priority, handlerFn, unwrap, that) {
3028
3491
  if (isFunction(events) || isNumber(events)) {
3029
3492
  that = unwrap;
3030
3493
  unwrap = handlerFn;
@@ -3034,7 +3497,8 @@ forEach(hooks, function (hook) {
3034
3497
  }
3035
3498
  this.on(events, hook, priority, handlerFn, unwrap, that);
3036
3499
  };
3037
- });
3500
+ return hookFn;
3501
+ }
3038
3502
 
3039
3503
  class FormLayoutUpdater extends CommandInterceptor {
3040
3504
  constructor(eventBus, formLayouter, modeling, formEditor) {
@@ -3140,8 +3604,8 @@ class ValidateBehavior extends CommandInterceptor {
3140
3604
  constructor(eventBus) {
3141
3605
  super(eventBus);
3142
3606
 
3143
- /**
3144
- * Remove custom validation if <validationType> is about to be added.
3607
+ /**
3608
+ * Remove custom validation if <validationType> is about to be added.
3145
3609
  */
3146
3610
  // @ts-ignore-next-line
3147
3611
  this.preExecute('formField.edit', function (context) {
@@ -3172,6 +3636,34 @@ var behaviorModule = {
3172
3636
  validateBehavior: ['type', ValidateBehavior]
3173
3637
  };
3174
3638
 
3639
+ /**
3640
+ * @typedef {import('didi').Injector} Injector
3641
+ *
3642
+ * @typedef {import('../core/Types').ElementLike} ElementLike
3643
+ *
3644
+ * @typedef {import('../core/EventBus').default} EventBus
3645
+ * @typedef {import('./CommandHandler').default} CommandHandler
3646
+ *
3647
+ * @typedef { any } CommandContext
3648
+ * @typedef { {
3649
+ * new (...args: any[]) : CommandHandler
3650
+ * } } CommandHandlerConstructor
3651
+ * @typedef { {
3652
+ * [key: string]: CommandHandler;
3653
+ * } } CommandHandlerMap
3654
+ * @typedef { {
3655
+ * command: string;
3656
+ * context: any;
3657
+ * id?: any;
3658
+ * } } CommandStackAction
3659
+ * @typedef { {
3660
+ * actions: CommandStackAction[];
3661
+ * dirty: ElementLike[];
3662
+ * trigger: 'execute' | 'undo' | 'redo' | 'clear' | null;
3663
+ * atomic?: boolean;
3664
+ * } } CurrentExecution
3665
+ */
3666
+
3175
3667
  /**
3176
3668
  * A service that offers un- and redoable execution of commands.
3177
3669
  *
@@ -3222,7 +3714,7 @@ var behaviorModule = {
3222
3714
  * got changed during the `execute` and `revert` operations.
3223
3715
  *
3224
3716
  * Command handlers may execute other modeling operations (and thus
3225
- * commands) in their `preExecute` and `postExecute` phases. The command
3717
+ * commands) in their `preExecute(d)` and `postExecute(d)` phases. The command
3226
3718
  * stack will properly group all commands together into a logical unit
3227
3719
  * that may be re- and undone atomically.
3228
3720
  *
@@ -3252,14 +3744,14 @@ function CommandStack(eventBus, injector) {
3252
3744
  /**
3253
3745
  * A map of all registered command handlers.
3254
3746
  *
3255
- * @type {Object}
3747
+ * @type {CommandHandlerMap}
3256
3748
  */
3257
3749
  this._handlerMap = {};
3258
3750
 
3259
3751
  /**
3260
3752
  * A stack containing all re/undoable actions on the diagram
3261
3753
  *
3262
- * @type {Array<Object>}
3754
+ * @type {CommandStackAction[]}
3263
3755
  */
3264
3756
  this._stack = [];
3265
3757
 
@@ -3273,18 +3765,27 @@ function CommandStack(eventBus, injector) {
3273
3765
  /**
3274
3766
  * Current active commandStack execution
3275
3767
  *
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
3768
+ * @type {CurrentExecution}
3280
3769
  */
3281
3770
  this._currentExecution = {
3282
3771
  actions: [],
3283
3772
  dirty: [],
3284
3773
  trigger: null
3285
3774
  };
3775
+
3776
+ /**
3777
+ * @type {Injector}
3778
+ */
3286
3779
  this._injector = injector;
3780
+
3781
+ /**
3782
+ * @type EventBus
3783
+ */
3287
3784
  this._eventBus = eventBus;
3785
+
3786
+ /**
3787
+ * @type { number }
3788
+ */
3288
3789
  this._uid = 1;
3289
3790
  eventBus.on(['diagram.destroy', 'diagram.clear'], function () {
3290
3791
  this.clear(false);
@@ -3293,10 +3794,10 @@ function CommandStack(eventBus, injector) {
3293
3794
  CommandStack.$inject = ['eventBus', 'injector'];
3294
3795
 
3295
3796
  /**
3296
- * Execute a command
3797
+ * Execute a command.
3297
3798
  *
3298
- * @param {string} command the command to execute
3299
- * @param {Object} context the environment to execute the command in
3799
+ * @param {string} command The command to execute.
3800
+ * @param {CommandContext} context The context with which to execute the command.
3300
3801
  */
3301
3802
  CommandStack.prototype.execute = function (command, context) {
3302
3803
  if (!command) {
@@ -3309,11 +3810,11 @@ CommandStack.prototype.execute = function (command, context) {
3309
3810
  };
3310
3811
  this._pushAction(action);
3311
3812
  this._internalExecute(action);
3312
- this._popAction(action);
3813
+ this._popAction();
3313
3814
  };
3314
3815
 
3315
3816
  /**
3316
- * Ask whether a given command can be executed.
3817
+ * Check whether a command can be executed.
3317
3818
  *
3318
3819
  * Implementors may hook into the mechanism on two ways:
3319
3820
  *
@@ -3327,10 +3828,10 @@ CommandStack.prototype.execute = function (command, context) {
3327
3828
  * If the method {@link CommandHandler#canExecute} is implemented in a handler
3328
3829
  * it will be called to figure out whether the execution is allowed.
3329
3830
  *
3330
- * @param {string} command the command to execute
3331
- * @param {Object} context the environment to execute the command in
3831
+ * @param {string} command The command to execute.
3832
+ * @param {CommandContext} context The context with which to execute the command.
3332
3833
  *
3333
- * @return {boolean} true if the command can be executed
3834
+ * @return {boolean} Whether the command can be executed with the given context.
3334
3835
  */
3335
3836
  CommandStack.prototype.canExecute = function (command, context) {
3336
3837
  const action = {
@@ -3354,7 +3855,9 @@ CommandStack.prototype.canExecute = function (command, context) {
3354
3855
  };
3355
3856
 
3356
3857
  /**
3357
- * Clear the command stack, erasing all undo / redo history
3858
+ * Clear the command stack, erasing all undo / redo history.
3859
+ *
3860
+ * @param {boolean} [emit=true] Whether to fire an event. Defaults to `true`.
3358
3861
  */
3359
3862
  CommandStack.prototype.clear = function (emit) {
3360
3863
  this._stack.length = 0;
@@ -3409,21 +3912,21 @@ CommandStack.prototype.redo = function () {
3409
3912
  };
3410
3913
 
3411
3914
  /**
3412
- * Register a handler instance with the command stack
3915
+ * Register a handler instance with the command stack.
3413
3916
  *
3414
- * @param {string} command
3415
- * @param {CommandHandler} handler
3917
+ * @param {string} command Command to be executed.
3918
+ * @param {CommandHandler} handler Handler to execute the command.
3416
3919
  */
3417
3920
  CommandStack.prototype.register = function (command, handler) {
3418
3921
  this._setHandler(command, handler);
3419
3922
  };
3420
3923
 
3421
3924
  /**
3422
- * Register a handler type with the command stack
3423
- * by instantiating it and injecting its dependencies.
3925
+ * Register a handler type with the command stack by instantiating it and
3926
+ * injecting its dependencies.
3424
3927
  *
3425
- * @param {string} command
3426
- * @param {Function} a constructor for a {@link CommandHandler}
3928
+ * @param {string} command Command to be executed.
3929
+ * @param {CommandHandlerConstructor} handlerCls Constructor to instantiate a {@link CommandHandler}.
3427
3930
  */
3428
3931
  CommandStack.prototype.registerHandler = function (command, handlerCls) {
3429
3932
  if (!command || !handlerCls) {
@@ -3432,9 +3935,17 @@ CommandStack.prototype.registerHandler = function (command, handlerCls) {
3432
3935
  const handler = this._injector.instantiate(handlerCls);
3433
3936
  this.register(command, handler);
3434
3937
  };
3938
+
3939
+ /**
3940
+ * @return {boolean}
3941
+ */
3435
3942
  CommandStack.prototype.canUndo = function () {
3436
3943
  return !!this._getUndoAction();
3437
3944
  };
3945
+
3946
+ /**
3947
+ * @return {boolean}
3948
+ */
3438
3949
  CommandStack.prototype.canRedo = function () {
3439
3950
  return !!this._getRedoAction();
3440
3951
  };
@@ -3528,7 +4039,7 @@ CommandStack.prototype._internalExecute = function (action, redo) {
3528
4039
  }
3529
4040
  this._fire(command, 'postExecuted', action);
3530
4041
  }
3531
- this._popAction(action);
4042
+ this._popAction();
3532
4043
  };
3533
4044
  CommandStack.prototype._pushAction = function (action) {
3534
4045
  const execution = this._currentExecution,
@@ -3589,6 +4100,9 @@ CommandStack.prototype._setHandler = function (command, handler) {
3589
4100
  this._handlerMap[command] = handler;
3590
4101
  };
3591
4102
 
4103
+ /**
4104
+ * @type { import('didi').ModuleDeclaration }
4105
+ */
3592
4106
  var commandModule = {
3593
4107
  commandStack: ['type', CommandStack]
3594
4108
  };
@@ -3686,10 +4200,10 @@ class PaletteRenderer {
3686
4200
  });
3687
4201
  }
3688
4202
 
3689
- /**
3690
- * Attach the palette to a parent node.
3691
- *
3692
- * @param {HTMLElement} container
4203
+ /**
4204
+ * Attach the palette to a parent node.
4205
+ *
4206
+ * @param {HTMLElement} container
3693
4207
  */
3694
4208
  attachTo(container) {
3695
4209
  if (!container) {
@@ -3709,8 +4223,8 @@ class PaletteRenderer {
3709
4223
  this._eventBus.fire('palette.attach');
3710
4224
  }
3711
4225
 
3712
- /**
3713
- * Detach the palette from its parent node.
4226
+ /**
4227
+ * Detach the palette from its parent node.
3714
4228
  */
3715
4229
  detach() {
3716
4230
  const parentNode = this._container.parentNode;
@@ -6067,11 +6581,11 @@ function prefixId$1(id) {
6067
6581
  return `bio-properties-panel-${id}`;
6068
6582
  }
6069
6583
 
6070
- /**
6071
- * @param {string} type
6072
- * @param {boolean} [strict]
6073
- *
6074
- * @returns {any}
6584
+ /**
6585
+ * @param {string} type
6586
+ * @param {boolean} [strict]
6587
+ *
6588
+ * @returns {any}
6075
6589
  */
6076
6590
  function getService(type, strict) {}
6077
6591
  const PropertiesPanelContext = createContext({
@@ -6160,8 +6674,8 @@ const PropertiesPanelHeaderProvider = {
6160
6674
  }
6161
6675
  };
6162
6676
 
6163
- /**
6164
- * Provide placeholders for empty and multiple state.
6677
+ /**
6678
+ * Provide placeholders for empty and multiple state.
6165
6679
  */
6166
6680
  const PropertiesPanelPlaceholderProvider = {
6167
6681
  getEmpty: () => {
@@ -6233,10 +6747,10 @@ function useService (type, strict) {
6233
6747
  return getService(type, strict);
6234
6748
  }
6235
6749
 
6236
- /**
6237
- * Retrieve list of variables from the form schema.
6238
- *
6239
- * @returns { string[] } list of variables used in form schema
6750
+ /**
6751
+ * Retrieve list of variables from the form schema.
6752
+ *
6753
+ * @returns { string[] } list of variables used in form schema
6240
6754
  */
6241
6755
  function useVariables() {
6242
6756
  const form = useService('formEditor');
@@ -6334,7 +6848,7 @@ function Columns(props) {
6334
6848
  },
6335
6849
  // todo(pinussilvestrus): make options dependant on field type
6336
6850
  // cf. https://github.com/bpmn-io/form-js/issues/575
6337
- ...[2, 4, 6, 8, 10, 12, 14, 16].map(asOption)];
6851
+ ...asArray(16).filter(i => i >= MIN_COLUMNS).map(asOption)];
6338
6852
  };
6339
6853
  return SelectEntry({
6340
6854
  debounce,
@@ -6356,6 +6870,11 @@ function asOption(number) {
6356
6870
  label: number.toString()
6357
6871
  };
6358
6872
  }
6873
+ function asArray(length) {
6874
+ return Array.from({
6875
+ length
6876
+ }).map((_, i) => i + 1);
6877
+ }
6359
6878
 
6360
6879
  function DescriptionEntry(props) {
6361
6880
  const {
@@ -7513,7 +8032,7 @@ function Label(props) {
7513
8032
  id,
7514
8033
  label: 'Label',
7515
8034
  setValue,
7516
- validate: validateFactory(getValue())
8035
+ validate: validateFactory(getValue(), entry => entry.label)
7517
8036
  });
7518
8037
  }
7519
8038
  function Value$1(props) {
@@ -7539,7 +8058,7 @@ function Value$1(props) {
7539
8058
  id,
7540
8059
  label: 'Value',
7541
8060
  setValue,
7542
- validate: validateFactory(getValue())
8061
+ validate: validateFactory(getValue(), entry => entry.value)
7543
8062
  });
7544
8063
  }
7545
8064
 
@@ -7629,14 +8148,14 @@ function Value(props) {
7629
8148
 
7630
8149
  // helpers //////////
7631
8150
 
7632
- /**
7633
- * Returns copy of object with updated value.
7634
- *
7635
- * @param {Object} properties
7636
- * @param {string} key
7637
- * @param {string} value
7638
- *
7639
- * @returns {Object}
8151
+ /**
8152
+ * Returns copy of object with updated value.
8153
+ *
8154
+ * @param {Object} properties
8155
+ * @param {string} key
8156
+ * @param {string} value
8157
+ *
8158
+ * @returns {Object}
7640
8159
  */
7641
8160
  function updateValue(properties, key, value) {
7642
8161
  return {
@@ -7645,14 +8164,14 @@ function updateValue(properties, key, value) {
7645
8164
  };
7646
8165
  }
7647
8166
 
7648
- /**
7649
- * Returns copy of object with updated key.
7650
- *
7651
- * @param {Object} properties
7652
- * @param {string} oldKey
7653
- * @param {string} newKey
7654
- *
7655
- * @returns {Object}
8167
+ /**
8168
+ * Returns copy of object with updated key.
8169
+ *
8170
+ * @param {Object} properties
8171
+ * @param {string} oldKey
8172
+ * @param {string} newKey
8173
+ *
8174
+ * @returns {Object}
7656
8175
  */
7657
8176
  function updateKey(properties, oldKey, newKey) {
7658
8177
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -7781,13 +8300,13 @@ function StaticValuesSourceEntry(props) {
7781
8300
  const addEntry = e => {
7782
8301
  e.stopPropagation();
7783
8302
  const index = values.length + 1;
7784
- const entry = getIndexedEntry(index);
8303
+ const entry = getIndexedEntry(index, values);
7785
8304
  editField(field, VALUES_SOURCES_PATHS[VALUES_SOURCES.STATIC], arrayAdd(values, values.length, entry));
7786
8305
  };
7787
8306
  const removeEntry = entry => {
7788
8307
  editField(field, VALUES_SOURCES_PATHS[VALUES_SOURCES.STATIC], without(values, entry));
7789
8308
  };
7790
- const validateFactory = key => {
8309
+ const validateFactory = (key, getValue) => {
7791
8310
  return value => {
7792
8311
  if (value === key) {
7793
8312
  return;
@@ -7795,7 +8314,7 @@ function StaticValuesSourceEntry(props) {
7795
8314
  if (isUndefined(value) || !value.length) {
7796
8315
  return 'Must not be empty.';
7797
8316
  }
7798
- const isValueAssigned = values.find(entry => entry.value === value);
8317
+ const isValueAssigned = values.find(entry => getValue(entry) === value);
7799
8318
  if (isValueAssigned) {
7800
8319
  return 'Must be unique.';
7801
8320
  }
@@ -7826,17 +8345,23 @@ function StaticValuesSourceEntry(props) {
7826
8345
 
7827
8346
  // helper
7828
8347
 
7829
- function getIndexedEntry(index) {
8348
+ function getIndexedEntry(index, values) {
7830
8349
  const entry = {
7831
8350
  label: 'Value',
7832
8351
  value: 'value'
7833
8352
  };
8353
+ while (labelOrValueIsAlreadyAssignedForIndex(index, values)) {
8354
+ index++;
8355
+ }
7834
8356
  if (index > 1) {
7835
8357
  entry.label += ` ${index}`;
7836
8358
  entry.value += `${index}`;
7837
8359
  }
7838
8360
  return entry;
7839
8361
  }
8362
+ function labelOrValueIsAlreadyAssignedForIndex(index, values) {
8363
+ return values.some(existingEntry => existingEntry.label === `Value ${index}` || existingEntry.value === `value${index}`);
8364
+ }
7840
8365
 
7841
8366
  function AdornerEntry(props) {
7842
8367
  const {
@@ -8288,8 +8813,8 @@ function ValuesGroups(field, editField) {
8288
8813
  };
8289
8814
  const valuesSourceId = `${fieldId}-valuesSource`;
8290
8815
 
8291
- /**
8292
- * @type {Array<Group|ListGroup>}
8816
+ /**
8817
+ * @type {Array<Group|ListGroup>}
8293
8818
  */
8294
8819
  const groups = [{
8295
8820
  id: valuesSourceId,
@@ -8337,12 +8862,13 @@ function CustomValuesGroup(field, editField) {
8337
8862
  }
8338
8863
  const addEntry = event => {
8339
8864
  event.stopPropagation();
8340
- const index = Object.keys(properties).length + 1;
8341
- const key = `key${index}`,
8342
- value = 'value';
8865
+ let index = Object.keys(properties).length + 1;
8866
+ while (`key${index}` in properties) {
8867
+ index++;
8868
+ }
8343
8869
  editField(field, ['properties'], {
8344
8870
  ...properties,
8345
- [key]: value
8871
+ [`key${index}`]: 'value'
8346
8872
  });
8347
8873
  };
8348
8874
  const validateFactory = key => {
@@ -8390,13 +8916,13 @@ function CustomValuesGroup(field, editField) {
8390
8916
 
8391
8917
  // helpers //////////
8392
8918
 
8393
- /**
8394
- * Returns copy of object without key.
8395
- *
8396
- * @param {Object} properties
8397
- * @param {string} oldKey
8398
- *
8399
- * @returns {Object}
8919
+ /**
8920
+ * Returns copy of object without key.
8921
+ *
8922
+ * @param {Object} properties
8923
+ * @param {string} oldKey
8924
+ *
8925
+ * @returns {Object}
8400
8926
  */
8401
8927
  function removeKey(properties, oldKey) {
8402
8928
  return Object.entries(properties).reduce((newProperties, entry) => {
@@ -8510,9 +9036,9 @@ function FormPropertiesPanel(props) {
8510
9036
  }, []);
8511
9037
  useLayoutEffect(() => {
8512
9038
  const onFieldChanged = () => {
8513
- /**
8514
- * TODO(pinussilvestrus): update with actual updated element,
8515
- * once we have a proper updater/change support
9039
+ /**
9040
+ * TODO(pinussilvestrus): update with actual updated element,
9041
+ * once we have a proper updater/change support
8516
9042
  */
8517
9043
  _update(selection.get() || schema);
8518
9044
  };
@@ -8563,10 +9089,10 @@ class PropertiesPanelRenderer {
8563
9089
  });
8564
9090
  }
8565
9091
 
8566
- /**
8567
- * Attach the properties panel to a parent node.
8568
- *
8569
- * @param {HTMLElement} container
9092
+ /**
9093
+ * Attach the properties panel to a parent node.
9094
+ *
9095
+ * @param {HTMLElement} container
8570
9096
  */
8571
9097
  attachTo(container) {
8572
9098
  if (!container) {
@@ -8586,8 +9112,8 @@ class PropertiesPanelRenderer {
8586
9112
  this._eventBus.fire('propertiesPanel.attach');
8587
9113
  }
8588
9114
 
8589
- /**
8590
- * Detach the properties panel from its parent node.
9115
+ /**
9116
+ * Detach the properties panel from its parent node.
8591
9117
  */
8592
9118
  detach() {
8593
9119
  const parentNode = this._container.parentNode;
@@ -8625,48 +9151,48 @@ var ExpressionLanguageModule = {
8625
9151
 
8626
9152
  const ids = new Ids([32, 36, 1]);
8627
9153
 
8628
- /**
8629
- * @typedef { import('./types').Injector } Injector
8630
- * @typedef { import('./types').Module } Module
8631
- * @typedef { import('./types').Schema } Schema
8632
- *
8633
- * @typedef { import('./types').FormEditorOptions } FormEditorOptions
8634
- * @typedef { import('./types').FormEditorProperties } FormEditorProperties
8635
- *
8636
- * @typedef { {
8637
- * properties: FormEditorProperties,
8638
- * schema: Schema
8639
- * } } State
8640
- *
8641
- * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
8642
- * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
8643
- * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
9154
+ /**
9155
+ * @typedef { import('./types').Injector } Injector
9156
+ * @typedef { import('./types').Module } Module
9157
+ * @typedef { import('./types').Schema } Schema
9158
+ *
9159
+ * @typedef { import('./types').FormEditorOptions } FormEditorOptions
9160
+ * @typedef { import('./types').FormEditorProperties } FormEditorProperties
9161
+ *
9162
+ * @typedef { {
9163
+ * properties: FormEditorProperties,
9164
+ * schema: Schema
9165
+ * } } State
9166
+ *
9167
+ * @typedef { (type:string, priority:number, handler:Function) => void } OnEventWithPriority
9168
+ * @typedef { (type:string, handler:Function) => void } OnEventWithOutPriority
9169
+ * @typedef { OnEventWithPriority & OnEventWithOutPriority } OnEventType
8644
9170
  */
8645
9171
 
8646
- /**
8647
- * The form editor.
9172
+ /**
9173
+ * The form editor.
8648
9174
  */
8649
9175
  class FormEditor {
8650
- /**
8651
- * @constructor
8652
- * @param {FormEditorOptions} options
9176
+ /**
9177
+ * @constructor
9178
+ * @param {FormEditorOptions} options
8653
9179
  */
8654
9180
  constructor(options = {}) {
8655
- /**
8656
- * @public
8657
- * @type {OnEventType}
9181
+ /**
9182
+ * @public
9183
+ * @type {OnEventType}
8658
9184
  */
8659
9185
  this.on = this._onEvent;
8660
9186
 
8661
- /**
8662
- * @public
8663
- * @type {String}
9187
+ /**
9188
+ * @public
9189
+ * @type {String}
8664
9190
  */
8665
9191
  this._id = ids.next();
8666
9192
 
8667
- /**
8668
- * @private
8669
- * @type {Element}
9193
+ /**
9194
+ * @private
9195
+ * @type {Element}
8670
9196
  */
8671
9197
  this._container = createFormContainer();
8672
9198
  this._container.setAttribute('input-handle-modified-keys', 'z,y');
@@ -8677,15 +9203,15 @@ class FormEditor {
8677
9203
  properties = {}
8678
9204
  } = options;
8679
9205
 
8680
- /**
8681
- * @private
8682
- * @type {any}
9206
+ /**
9207
+ * @private
9208
+ * @type {any}
8683
9209
  */
8684
9210
  this.exporter = exporter;
8685
9211
 
8686
- /**
8687
- * @private
8688
- * @type {State}
9212
+ /**
9213
+ * @private
9214
+ * @type {State}
8689
9215
  */
8690
9216
  this._state = {
8691
9217
  properties,
@@ -8714,10 +9240,10 @@ class FormEditor {
8714
9240
  this._detach(false);
8715
9241
  }
8716
9242
 
8717
- /**
8718
- * @param {Schema} schema
8719
- *
8720
- * @return {Promise<{ warnings: Array<any> }>}
9243
+ /**
9244
+ * @param {Schema} schema
9245
+ *
9246
+ * @return {Promise<{ warnings: Array<any> }>}
8721
9247
  */
8722
9248
  importSchema(schema) {
8723
9249
  return new Promise((resolve, reject) => {
@@ -8746,15 +9272,15 @@ class FormEditor {
8746
9272
  });
8747
9273
  }
8748
9274
 
8749
- /**
8750
- * @returns {Schema}
9275
+ /**
9276
+ * @returns {Schema}
8751
9277
  */
8752
9278
  saveSchema() {
8753
9279
  return this.getSchema();
8754
9280
  }
8755
9281
 
8756
- /**
8757
- * @returns {Schema}
9282
+ /**
9283
+ * @returns {Schema}
8758
9284
  */
8759
9285
  getSchema() {
8760
9286
  const {
@@ -8763,8 +9289,8 @@ class FormEditor {
8763
9289
  return exportSchema(schema, this.exporter, schemaVersion);
8764
9290
  }
8765
9291
 
8766
- /**
8767
- * @param {Element|string} parentNode
9292
+ /**
9293
+ * @param {Element|string} parentNode
8768
9294
  */
8769
9295
  attachTo(parentNode) {
8770
9296
  if (!parentNode) {
@@ -8782,10 +9308,10 @@ class FormEditor {
8782
9308
  this._detach();
8783
9309
  }
8784
9310
 
8785
- /**
8786
- * @internal
8787
- *
8788
- * @param {boolean} [emit]
9311
+ /**
9312
+ * @internal
9313
+ *
9314
+ * @param {boolean} [emit]
8789
9315
  */
8790
9316
  _detach(emit = true) {
8791
9317
  const container = this._container,
@@ -8799,9 +9325,9 @@ class FormEditor {
8799
9325
  parentNode.removeChild(container);
8800
9326
  }
8801
9327
 
8802
- /**
8803
- * @param {any} property
8804
- * @param {any} value
9328
+ /**
9329
+ * @param {any} property
9330
+ * @param {any} value
8805
9331
  */
8806
9332
  setProperty(property, value) {
8807
9333
  const properties = set$1(this._getState().properties, [property], value);
@@ -8810,21 +9336,21 @@ class FormEditor {
8810
9336
  });
8811
9337
  }
8812
9338
 
8813
- /**
8814
- * @param {string} type
8815
- * @param {Function} handler
9339
+ /**
9340
+ * @param {string} type
9341
+ * @param {Function} handler
8816
9342
  */
8817
9343
  off(type, handler) {
8818
9344
  this.get('eventBus').off(type, handler);
8819
9345
  }
8820
9346
 
8821
- /**
8822
- * @internal
8823
- *
8824
- * @param {FormEditorOptions} options
8825
- * @param {Element} container
8826
- *
8827
- * @returns {Injector}
9347
+ /**
9348
+ * @internal
9349
+ *
9350
+ * @param {FormEditorOptions} options
9351
+ * @param {Element} container
9352
+ *
9353
+ * @returns {Injector}
8828
9354
  */
8829
9355
  _createInjector(options, container) {
8830
9356
  const {
@@ -8846,22 +9372,22 @@ class FormEditor {
8846
9372
  }, core, ...modules, ...additionalModules]);
8847
9373
  }
8848
9374
 
8849
- /**
8850
- * @internal
9375
+ /**
9376
+ * @internal
8851
9377
  */
8852
9378
  _emit(type, data) {
8853
9379
  this.get('eventBus').fire(type, data);
8854
9380
  }
8855
9381
 
8856
- /**
8857
- * @internal
9382
+ /**
9383
+ * @internal
8858
9384
  */
8859
9385
  _getState() {
8860
9386
  return this._state;
8861
9387
  }
8862
9388
 
8863
- /**
8864
- * @internal
9389
+ /**
9390
+ * @internal
8865
9391
  */
8866
9392
  _setState(state) {
8867
9393
  this._state = {
@@ -8871,15 +9397,15 @@ class FormEditor {
8871
9397
  this._emit('changed', this._getState());
8872
9398
  }
8873
9399
 
8874
- /**
8875
- * @internal
9400
+ /**
9401
+ * @internal
8876
9402
  */
8877
9403
  _getModules() {
8878
9404
  return [ModelingModule, EditorActionsModule, DraggingModule, KeyboardModule, SelectionModule, PaletteModule, ExpressionLanguageModule, MarkdownModule, PropertiesPanelModule];
8879
9405
  }
8880
9406
 
8881
- /**
8882
- * @internal
9407
+ /**
9408
+ * @internal
8883
9409
  */
8884
9410
  _onEvent(type, priority, handler) {
8885
9411
  this.get('eventBus').on(type, priority, handler);