@bpmn-io/form-js-editor 1.2.0 → 1.3.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.
- package/dist/assets/form-js-editor-base.css +50 -11
- package/dist/assets/form-js-editor.css +289 -10
- package/dist/assets/properties-panel.css +245 -1
- package/dist/index.cjs +2320 -1640
- package/dist/index.cjs.map +1 -1
- package/dist/index.es.js +2320 -1641
- package/dist/index.es.js.map +1 -1
- package/dist/types/FormEditor.d.ts +1 -0
- package/dist/types/core/index.d.ts +7 -5
- package/dist/types/features/dragging/Dragging.d.ts +3 -1
- package/dist/types/features/modeling/Modeling.d.ts +4 -0
- package/dist/types/features/modeling/behavior/KeyBehavior.d.ts +1 -1
- package/dist/types/features/modeling/behavior/PathBehavior.d.ts +8 -0
- package/dist/types/features/modeling/behavior/index.d.ts +2 -0
- package/dist/types/features/modeling/cmd/MoveFormFieldHandler.d.ts +3 -1
- package/dist/types/features/modeling/cmd/UpdateKeyClaimHandler.d.ts +3 -3
- package/dist/types/features/modeling/cmd/UpdatePathClaimHandler.d.ts +14 -0
- package/dist/types/features/modeling/cmd/Util.d.ts +1 -0
- package/dist/types/features/modeling/index.d.ts +1 -0
- package/dist/types/features/properties-panel/Util.d.ts +1 -0
- package/dist/types/features/properties-panel/entries/GroupEntries.d.ts +10 -0
- package/dist/types/features/properties-panel/entries/PathEntry.d.ts +9 -0
- package/dist/types/features/properties-panel/entries/index.d.ts +2 -0
- package/dist/types/render/components/Util.d.ts +1 -2
- package/package.json +4 -4
- package/dist/types/core/FieldFactory.d.ts +0 -18
- package/dist/types/import/Importer.d.ts +0 -53
- package/dist/types/import/index.d.ts +0 -5
package/dist/index.es.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { FormFieldRegistry as FormFieldRegistry$1,
|
|
1
|
+
import { FormFieldRegistry as FormFieldRegistry$1, iconsByType, Text as Text$1, FormFields, formFields, FormContext, FormRenderContext, FormComponent, Importer, PathRegistry, FormLayouter, FieldFactory, runRecursively, clone, 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, 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, isString, isUndefined, without, has } from 'min-dash';
|
|
4
|
+
import { isArray, isFunction, isNumber, bind, assign, debounce, forEach, get, isObject, uniqueBy, sortBy, find, throttle as throttle$1, set as set$1, isString, isUndefined, without, has } from 'min-dash';
|
|
5
5
|
import classnames from 'classnames';
|
|
6
6
|
import { jsx, jsxs, Fragment as Fragment$1 } from 'preact/jsx-runtime';
|
|
7
7
|
import { useContext, useState, useMemo, useEffect, useCallback, useRef as useRef$1, useLayoutEffect } from 'preact/hooks';
|
|
@@ -13,6 +13,8 @@ import { classes, query, closest, event, matches, domify } from 'min-dom';
|
|
|
13
13
|
import { mutate } from 'array-move';
|
|
14
14
|
import { FeelersEditor } from 'feelers';
|
|
15
15
|
import FeelEditor from '@bpmn-io/feel-editor';
|
|
16
|
+
import { lineNumbers } from '@codemirror/view';
|
|
17
|
+
import * as focusTrap from 'focus-trap';
|
|
16
18
|
import Big from 'big.js';
|
|
17
19
|
|
|
18
20
|
var FN_REF = '__fn';
|
|
@@ -530,73 +532,6 @@ function DebounceFactory(config = true) {
|
|
|
530
532
|
}
|
|
531
533
|
DebounceFactory.$inject = ['config.debounce'];
|
|
532
534
|
|
|
533
|
-
class FieldFactory {
|
|
534
|
-
/**
|
|
535
|
-
* @constructor
|
|
536
|
-
*
|
|
537
|
-
* @param { import('./FormFieldRegistry').default } formFieldRegistry
|
|
538
|
-
* @param { import('@bpmn-io/form-js-viewer').FormFields } formFields
|
|
539
|
-
*/
|
|
540
|
-
constructor(formFieldRegistry, formFields) {
|
|
541
|
-
this._formFieldRegistry = formFieldRegistry;
|
|
542
|
-
this._formFields = formFields;
|
|
543
|
-
}
|
|
544
|
-
create(attrs, applyDefaults = true) {
|
|
545
|
-
const {
|
|
546
|
-
id,
|
|
547
|
-
key,
|
|
548
|
-
type
|
|
549
|
-
} = attrs;
|
|
550
|
-
const fieldDefinition = this._formFields.get(type);
|
|
551
|
-
if (!fieldDefinition) {
|
|
552
|
-
throw new Error(`form field of type <${type}> not supported`);
|
|
553
|
-
}
|
|
554
|
-
const {
|
|
555
|
-
config
|
|
556
|
-
} = fieldDefinition;
|
|
557
|
-
if (id && this._formFieldRegistry._ids.assigned(id)) {
|
|
558
|
-
throw new Error(`ID <${id}> already assigned`);
|
|
559
|
-
}
|
|
560
|
-
if (key && this._formFieldRegistry._keys.assigned(key)) {
|
|
561
|
-
throw new Error(`key <${key}> already assigned`);
|
|
562
|
-
}
|
|
563
|
-
const labelAttrs = applyDefaults && config.label ? {
|
|
564
|
-
label: config.label
|
|
565
|
-
} : {};
|
|
566
|
-
const field = config.create({
|
|
567
|
-
...labelAttrs,
|
|
568
|
-
...attrs
|
|
569
|
-
});
|
|
570
|
-
this._ensureId(field);
|
|
571
|
-
if (config.keyed) {
|
|
572
|
-
this._ensureKey(field, applyDefaults);
|
|
573
|
-
}
|
|
574
|
-
return field;
|
|
575
|
-
}
|
|
576
|
-
_ensureId(field) {
|
|
577
|
-
if (field.id) {
|
|
578
|
-
this._formFieldRegistry._ids.claim(field.id, field);
|
|
579
|
-
return;
|
|
580
|
-
}
|
|
581
|
-
let prefix = 'Field';
|
|
582
|
-
if (field.type === 'default') {
|
|
583
|
-
prefix = 'Form';
|
|
584
|
-
}
|
|
585
|
-
field.id = this._formFieldRegistry._ids.nextPrefixed(`${prefix}_`, field);
|
|
586
|
-
}
|
|
587
|
-
_ensureKey(field, applyDefaults) {
|
|
588
|
-
if (field.key) {
|
|
589
|
-
this._formFieldRegistry._keys.claim(field.key, field);
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
if (applyDefaults) {
|
|
593
|
-
let prefix = 'field';
|
|
594
|
-
field.key = this._formFieldRegistry._keys.nextPrefixed(`${prefix}_`, field);
|
|
595
|
-
}
|
|
596
|
-
}
|
|
597
|
-
}
|
|
598
|
-
FieldFactory.$inject = ['formFieldRegistry', 'formFields'];
|
|
599
|
-
|
|
600
535
|
class FormFieldRegistry extends FormFieldRegistry$1 {
|
|
601
536
|
/**
|
|
602
537
|
* Updates a form fields id.
|
|
@@ -709,111 +644,7 @@ function calculateMaxColumnsWithAuto(autoCols) {
|
|
|
709
644
|
return MAX_COLUMNS_PER_ROW - autoCols * 2;
|
|
710
645
|
}
|
|
711
646
|
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* @constructor
|
|
715
|
-
* @param { import('../core/FormFieldRegistry').default } formFieldRegistry
|
|
716
|
-
* @param { import('../core/FieldFactory').default } fieldFactory
|
|
717
|
-
* @param { import('../core/FormLayouter').default } formLayouter
|
|
718
|
-
*/
|
|
719
|
-
constructor(formFieldRegistry, fieldFactory, formLayouter) {
|
|
720
|
-
this._formFieldRegistry = formFieldRegistry;
|
|
721
|
-
this._fieldFactory = fieldFactory;
|
|
722
|
-
this._formLayouter = formLayouter;
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
/**
|
|
726
|
-
* Import schema creating rows, fields, attaching additional
|
|
727
|
-
* information to each field and adding fields to the
|
|
728
|
-
* field registry.
|
|
729
|
-
*
|
|
730
|
-
* Additional information attached:
|
|
731
|
-
*
|
|
732
|
-
* * `id` (unless present)
|
|
733
|
-
* * `_parent`
|
|
734
|
-
* * `_path`
|
|
735
|
-
*
|
|
736
|
-
* @param {any} schema
|
|
737
|
-
*
|
|
738
|
-
* @typedef {{ warnings: Error[], schema: any }} ImportResult
|
|
739
|
-
* @returns {ImportResult}
|
|
740
|
-
*/
|
|
741
|
-
importSchema(schema) {
|
|
742
|
-
// TODO: Add warnings
|
|
743
|
-
const warnings = [];
|
|
744
|
-
try {
|
|
745
|
-
const importedSchema = this.importFormField(clone(schema));
|
|
746
|
-
this._formLayouter.calculateLayout(clone(importedSchema));
|
|
747
|
-
return {
|
|
748
|
-
schema: importedSchema,
|
|
749
|
-
warnings
|
|
750
|
-
};
|
|
751
|
-
} catch (err) {
|
|
752
|
-
err.warnings = warnings;
|
|
753
|
-
throw err;
|
|
754
|
-
}
|
|
755
|
-
}
|
|
756
|
-
|
|
757
|
-
/**
|
|
758
|
-
* @param {{[x: string]: any}} fieldAttrs
|
|
759
|
-
* @param {String} [parentId]
|
|
760
|
-
* @param {number} [index]
|
|
761
|
-
*
|
|
762
|
-
* @return {any} field
|
|
763
|
-
*/
|
|
764
|
-
importFormField(fieldAttrs, parentId, index) {
|
|
765
|
-
const {
|
|
766
|
-
components,
|
|
767
|
-
id,
|
|
768
|
-
key
|
|
769
|
-
} = fieldAttrs;
|
|
770
|
-
let parent, path;
|
|
771
|
-
if (parentId) {
|
|
772
|
-
parent = this._formFieldRegistry.get(parentId);
|
|
773
|
-
}
|
|
774
|
-
|
|
775
|
-
// validate <id> uniqueness
|
|
776
|
-
if (id && this._formFieldRegistry._ids.assigned(id)) {
|
|
777
|
-
throw new Error(`form field with id <${id}> already exists`);
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
// validate <key> uniqueness
|
|
781
|
-
if (key && this._formFieldRegistry._keys.assigned(key)) {
|
|
782
|
-
throw new Error(`form field with key <${key}> already exists`);
|
|
783
|
-
}
|
|
784
|
-
|
|
785
|
-
// set form field path
|
|
786
|
-
path = parent ? [...parent._path, 'components', index] : [];
|
|
787
|
-
const field = this._fieldFactory.create({
|
|
788
|
-
...fieldAttrs,
|
|
789
|
-
_path: path,
|
|
790
|
-
_parent: parent && parent.id
|
|
791
|
-
}, false);
|
|
792
|
-
this._formFieldRegistry.add(field);
|
|
793
|
-
if (components) {
|
|
794
|
-
field.components = this.importFormFields(components, field.id);
|
|
795
|
-
}
|
|
796
|
-
return field;
|
|
797
|
-
}
|
|
798
|
-
|
|
799
|
-
/**
|
|
800
|
-
* @param {Array<any>} components
|
|
801
|
-
* @param {string} parentId
|
|
802
|
-
*
|
|
803
|
-
* @return {Array<any>} imported components
|
|
804
|
-
*/
|
|
805
|
-
importFormFields(components, parentId) {
|
|
806
|
-
return components.map((component, index) => {
|
|
807
|
-
return this.importFormField(component, parentId, index);
|
|
808
|
-
});
|
|
809
|
-
}
|
|
810
|
-
}
|
|
811
|
-
Importer.$inject = ['formFieldRegistry', 'fieldFactory', 'formLayouter'];
|
|
812
|
-
|
|
813
|
-
var importModule = {
|
|
814
|
-
importer: ['type', Importer]
|
|
815
|
-
};
|
|
816
|
-
|
|
647
|
+
const emptyImage = createEmptyImage();
|
|
817
648
|
function editorFormFieldClasses(type, {
|
|
818
649
|
disabled = false
|
|
819
650
|
} = {}) {
|
|
@@ -838,11 +669,10 @@ function editorFormFieldClasses(type, {
|
|
|
838
669
|
* domElement.addEventListener('dragstart', dragger(dragMove));
|
|
839
670
|
*
|
|
840
671
|
* @param {Function} fn
|
|
841
|
-
* @param {Element} dragPreview
|
|
842
672
|
*
|
|
843
673
|
* @return {Function} drag start callback function
|
|
844
674
|
*/
|
|
845
|
-
function createDragger(fn
|
|
675
|
+
function createDragger$1(fn) {
|
|
846
676
|
let self;
|
|
847
677
|
let startX, startY;
|
|
848
678
|
|
|
@@ -852,9 +682,9 @@ function createDragger(fn, dragPreview) {
|
|
|
852
682
|
startX = event.clientX;
|
|
853
683
|
startY = event.clientY;
|
|
854
684
|
|
|
855
|
-
// (1)
|
|
685
|
+
// (1) hide drag preview image
|
|
856
686
|
if (event.dataTransfer) {
|
|
857
|
-
event.dataTransfer.setDragImage(
|
|
687
|
+
event.dataTransfer.setDragImage(emptyImage, 0, 0);
|
|
858
688
|
}
|
|
859
689
|
|
|
860
690
|
// (2) setup drag listeners
|
|
@@ -862,7 +692,7 @@ function createDragger(fn, dragPreview) {
|
|
|
862
692
|
// attach drag + cleanup event
|
|
863
693
|
document.addEventListener('dragover', onDrag);
|
|
864
694
|
document.addEventListener('dragend', onEnd);
|
|
865
|
-
document.addEventListener('drop', preventDefault);
|
|
695
|
+
document.addEventListener('drop', preventDefault$1);
|
|
866
696
|
}
|
|
867
697
|
function onDrag(event) {
|
|
868
698
|
const delta = {
|
|
@@ -876,7 +706,7 @@ function createDragger(fn, dragPreview) {
|
|
|
876
706
|
function onEnd() {
|
|
877
707
|
document.removeEventListener('dragover', onDrag);
|
|
878
708
|
document.removeEventListener('dragend', onEnd);
|
|
879
|
-
document.removeEventListener('drop', preventDefault);
|
|
709
|
+
document.removeEventListener('drop', preventDefault$1);
|
|
880
710
|
}
|
|
881
711
|
return onDragStart;
|
|
882
712
|
}
|
|
@@ -905,10 +735,15 @@ function throttle(fn) {
|
|
|
905
735
|
});
|
|
906
736
|
};
|
|
907
737
|
}
|
|
908
|
-
function preventDefault(event) {
|
|
738
|
+
function preventDefault$1(event) {
|
|
909
739
|
event.preventDefault();
|
|
910
740
|
event.stopPropagation();
|
|
911
741
|
}
|
|
742
|
+
function createEmptyImage() {
|
|
743
|
+
const img = new Image();
|
|
744
|
+
img.src = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7';
|
|
745
|
+
return img;
|
|
746
|
+
}
|
|
912
747
|
|
|
913
748
|
const DragAndDropContext = createContext({
|
|
914
749
|
drake: null
|
|
@@ -1566,13 +1401,15 @@ class Dragging {
|
|
|
1566
1401
|
* @param { import('../../core/FormLayoutValidator').default } formLayoutValidator
|
|
1567
1402
|
* @param { import('../../core/EventBus').default } eventBus
|
|
1568
1403
|
* @param { import('../modeling/Modeling').default } modeling
|
|
1404
|
+
* @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
|
|
1569
1405
|
*/
|
|
1570
|
-
constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling) {
|
|
1406
|
+
constructor(formFieldRegistry, formLayouter, formLayoutValidator, eventBus, modeling, pathRegistry) {
|
|
1571
1407
|
this._formFieldRegistry = formFieldRegistry;
|
|
1572
1408
|
this._formLayouter = formLayouter;
|
|
1573
1409
|
this._formLayoutValidator = formLayoutValidator;
|
|
1574
1410
|
this._eventBus = eventBus;
|
|
1575
1411
|
this._modeling = modeling;
|
|
1412
|
+
this._pathRegistry = pathRegistry;
|
|
1576
1413
|
}
|
|
1577
1414
|
|
|
1578
1415
|
/**
|
|
@@ -1606,11 +1443,50 @@ class Dragging {
|
|
|
1606
1443
|
const targetRow = this._formLayouter.getRow(target.dataset.rowId);
|
|
1607
1444
|
let columns;
|
|
1608
1445
|
let formField;
|
|
1446
|
+
let targetParentId;
|
|
1609
1447
|
if (formFieldNode) {
|
|
1610
1448
|
formField = this._formFieldRegistry.get(formFieldNode.dataset.id);
|
|
1611
1449
|
columns = (formField.layout || {}).columns;
|
|
1450
|
+
|
|
1451
|
+
// (1) check for row constraints
|
|
1452
|
+
if (isRow(target)) {
|
|
1453
|
+
targetParentId = getFormParent(target).dataset.id;
|
|
1454
|
+
const rowError = this._formLayoutValidator.validateField(formField, columns, targetRow);
|
|
1455
|
+
if (rowError) {
|
|
1456
|
+
return rowError;
|
|
1457
|
+
}
|
|
1458
|
+
} else {
|
|
1459
|
+
targetParentId = target.dataset.id;
|
|
1460
|
+
}
|
|
1461
|
+
|
|
1462
|
+
// (2) check target is a valid parent
|
|
1463
|
+
if (!targetParentId) {
|
|
1464
|
+
return 'Drop is not a valid target';
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
// (3) check for path collisions
|
|
1468
|
+
const targetParentFormField = this._formFieldRegistry.get(targetParentId);
|
|
1469
|
+
const currentParentFormField = this._formFieldRegistry.get(formField._parent);
|
|
1470
|
+
if (targetParentFormField !== currentParentFormField) {
|
|
1471
|
+
const targetParentPath = this._pathRegistry.getValuePath(targetParentFormField);
|
|
1472
|
+
const currentParentPath = this._pathRegistry.getValuePath(currentParentFormField);
|
|
1473
|
+
if (targetParentPath.join('.') !== currentParentPath.join('.')) {
|
|
1474
|
+
const isDropAllowedByPathRegistry = this._pathRegistry.executeRecursivelyOnFields(formField, ({
|
|
1475
|
+
field,
|
|
1476
|
+
isClosed
|
|
1477
|
+
}) => {
|
|
1478
|
+
const options = {
|
|
1479
|
+
cutoffNode: currentParentFormField.id
|
|
1480
|
+
};
|
|
1481
|
+
const fieldPath = this._pathRegistry.getValuePath(field, options);
|
|
1482
|
+
return this._pathRegistry.canClaimPath([...targetParentPath, ...fieldPath], isClosed);
|
|
1483
|
+
});
|
|
1484
|
+
if (!isDropAllowedByPathRegistry) {
|
|
1485
|
+
return 'Drop not allowed by path registry';
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
}
|
|
1612
1489
|
}
|
|
1613
|
-
return this._formLayoutValidator.validateField(formField, columns, targetRow);
|
|
1614
1490
|
}
|
|
1615
1491
|
moveField(element, source, targetRow, targetFormField, targetIndex) {
|
|
1616
1492
|
const formFieldNode = element.querySelector('.fjs-element');
|
|
@@ -1628,6 +1504,7 @@ class Dragging {
|
|
|
1628
1504
|
};
|
|
1629
1505
|
attrs = {
|
|
1630
1506
|
...attrs,
|
|
1507
|
+
_parent: targetFormField.id,
|
|
1631
1508
|
layout: {
|
|
1632
1509
|
row: targetRow ? targetRow.id : this._formLayouter.nextRowId(),
|
|
1633
1510
|
// enable auto columns
|
|
@@ -1661,14 +1538,13 @@ class Dragging {
|
|
|
1661
1538
|
|
|
1662
1539
|
// (2.1) dropped in existing row
|
|
1663
1540
|
if (isRow(target)) {
|
|
1664
|
-
unsetDropNotAllowed(target);
|
|
1665
1541
|
targetRow = this._formLayouter.getRow(target.dataset.rowId);
|
|
1542
|
+
}
|
|
1666
1543
|
|
|
1667
|
-
|
|
1668
|
-
|
|
1669
|
-
|
|
1670
|
-
|
|
1671
|
-
}
|
|
1544
|
+
// (2.2) validate whether drop is allowed
|
|
1545
|
+
const validationError = this.validateDrop(el, target);
|
|
1546
|
+
if (validationError) {
|
|
1547
|
+
return drake.cancel(true);
|
|
1672
1548
|
}
|
|
1673
1549
|
drake.remove();
|
|
1674
1550
|
|
|
@@ -1716,13 +1592,11 @@ class Dragging {
|
|
|
1716
1592
|
return !target.classList.contains(DROP_CONTAINER_HORIZONTAL_CLS);
|
|
1717
1593
|
}
|
|
1718
1594
|
|
|
1719
|
-
// validate field drop
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
setDropNotAllowed(target);
|
|
1725
|
-
}
|
|
1595
|
+
// validate field drop
|
|
1596
|
+
const validationError = this.validateDrop(el, target);
|
|
1597
|
+
if (validationError) {
|
|
1598
|
+
// set error feedback to row
|
|
1599
|
+
setDropNotAllowed(target);
|
|
1726
1600
|
}
|
|
1727
1601
|
return !target.classList.contains(DRAG_NO_DROP_CLS);
|
|
1728
1602
|
},
|
|
@@ -1793,7 +1667,7 @@ class Dragging {
|
|
|
1793
1667
|
this._eventBus.fire(event, context);
|
|
1794
1668
|
}
|
|
1795
1669
|
}
|
|
1796
|
-
Dragging.$inject = ['formFieldRegistry', 'formLayouter', 'formLayoutValidator', 'eventBus', 'modeling'];
|
|
1670
|
+
Dragging.$inject = ['formFieldRegistry', 'formLayouter', 'formLayoutValidator', 'eventBus', 'modeling', 'pathRegistry'];
|
|
1797
1671
|
|
|
1798
1672
|
// helper //////////
|
|
1799
1673
|
|
|
@@ -1851,7 +1725,6 @@ function FieldDragPreview(props) {
|
|
|
1851
1725
|
|
|
1852
1726
|
const COLUMNS_REGEX = /^cds--col(-lg)?/;
|
|
1853
1727
|
const ELEMENT_RESIZING_CLS = 'fjs-element-resizing';
|
|
1854
|
-
const RESIZE_DRAG_PREVIEW_CLS = 'fjs-resize-drag-preview';
|
|
1855
1728
|
const GRID_OFFSET_PX = 16;
|
|
1856
1729
|
function FieldResizer(props) {
|
|
1857
1730
|
const {
|
|
@@ -1890,17 +1763,8 @@ function FieldResizer(props) {
|
|
|
1890
1763
|
const target = getElementNode(field);
|
|
1891
1764
|
const parent = getParent(target);
|
|
1892
1765
|
|
|
1893
|
-
// create a blank element to use as drag preview
|
|
1894
|
-
// ensure it was only created once
|
|
1895
|
-
let blankPreview = getDragPreviewImage(parent);
|
|
1896
|
-
if (!blankPreview) {
|
|
1897
|
-
blankPreview = document.createElement('div');
|
|
1898
|
-
blankPreview.classList.add(RESIZE_DRAG_PREVIEW_CLS);
|
|
1899
|
-
parent.appendChild(blankPreview);
|
|
1900
|
-
}
|
|
1901
|
-
|
|
1902
1766
|
// initialize drag handler
|
|
1903
|
-
const onDragStart = createDragger(onResize
|
|
1767
|
+
const onDragStart = createDragger$1(onResize);
|
|
1904
1768
|
onDragStart(event);
|
|
1905
1769
|
|
|
1906
1770
|
// mitigate auto columns on the grid that
|
|
@@ -1923,10 +1787,6 @@ function FieldResizer(props) {
|
|
|
1923
1787
|
const target = getElementNode(field);
|
|
1924
1788
|
unsetResizing(target, position);
|
|
1925
1789
|
context.current.newColumns = null;
|
|
1926
|
-
|
|
1927
|
-
// remove blank preview
|
|
1928
|
-
const blankPreview = getDragPreviewImage(getParent(target));
|
|
1929
|
-
blankPreview.remove();
|
|
1930
1790
|
};
|
|
1931
1791
|
if (field.type === 'default') {
|
|
1932
1792
|
return null;
|
|
@@ -1969,9 +1829,6 @@ function getColumnNode(node) {
|
|
|
1969
1829
|
function getElementNode(field) {
|
|
1970
1830
|
return query('.fjs-element[data-id="' + field.id + '"]');
|
|
1971
1831
|
}
|
|
1972
|
-
function getDragPreviewImage(node) {
|
|
1973
|
-
return query('.fjs-resize-drag-preview', node);
|
|
1974
|
-
}
|
|
1975
1832
|
function setResizing(node, position) {
|
|
1976
1833
|
classes(node).add(ELEMENT_RESIZING_CLS + '-' + position);
|
|
1977
1834
|
}
|
|
@@ -1988,7 +1845,10 @@ function ContextPad(props) {
|
|
|
1988
1845
|
children: props.children
|
|
1989
1846
|
});
|
|
1990
1847
|
}
|
|
1991
|
-
function Empty(
|
|
1848
|
+
function Empty() {
|
|
1849
|
+
return null;
|
|
1850
|
+
}
|
|
1851
|
+
function EmptyRoot(props) {
|
|
1992
1852
|
return jsx("div", {
|
|
1993
1853
|
class: "fjs-empty-editor",
|
|
1994
1854
|
children: jsxs("div", {
|
|
@@ -2009,12 +1869,17 @@ function Element$1(props) {
|
|
|
2009
1869
|
formFieldRegistry = useService$1('formFieldRegistry'),
|
|
2010
1870
|
modeling = useService$1('modeling'),
|
|
2011
1871
|
selection = useService$1('selection');
|
|
1872
|
+
const {
|
|
1873
|
+
hoveredId,
|
|
1874
|
+
setHoveredId
|
|
1875
|
+
} = useContext(FormRenderContext);
|
|
2012
1876
|
const {
|
|
2013
1877
|
field
|
|
2014
1878
|
} = props;
|
|
2015
1879
|
const {
|
|
2016
1880
|
id,
|
|
2017
|
-
type
|
|
1881
|
+
type,
|
|
1882
|
+
showOutline
|
|
2018
1883
|
} = field;
|
|
2019
1884
|
const ref = useRef$1();
|
|
2020
1885
|
function scrollIntoView({
|
|
@@ -2052,6 +1917,12 @@ function Element$1(props) {
|
|
|
2052
1917
|
if (selection.isSelected(field)) {
|
|
2053
1918
|
classes.push('fjs-editor-selected');
|
|
2054
1919
|
}
|
|
1920
|
+
if (showOutline) {
|
|
1921
|
+
classes.push('fjs-outlined');
|
|
1922
|
+
}
|
|
1923
|
+
if (hoveredId === field.id) {
|
|
1924
|
+
classes.push('fjs-editor-hovered');
|
|
1925
|
+
}
|
|
2055
1926
|
const onRemove = event => {
|
|
2056
1927
|
event.stopPropagation();
|
|
2057
1928
|
const parentField = formFieldRegistry.get(field._parent);
|
|
@@ -2071,6 +1942,11 @@ function Element$1(props) {
|
|
|
2071
1942
|
tabIndex: type === 'default' ? -1 : 0,
|
|
2072
1943
|
onClick: onClick,
|
|
2073
1944
|
onKeyPress: onKeyPress,
|
|
1945
|
+
onMouseOver: e => {
|
|
1946
|
+
// @ts-ignore
|
|
1947
|
+
setHoveredId(field.id);
|
|
1948
|
+
e.stopPropagation();
|
|
1949
|
+
},
|
|
2074
1950
|
ref: ref,
|
|
2075
1951
|
children: [jsx(DebugColumns, {
|
|
2076
1952
|
field: field
|
|
@@ -2240,14 +2116,18 @@ function FormEditor$1(props) {
|
|
|
2240
2116
|
useEffect(() => {
|
|
2241
2117
|
eventBus.fire('formEditor.rendered');
|
|
2242
2118
|
}, []);
|
|
2243
|
-
const
|
|
2119
|
+
const [hoveredId, setHoveredId] = useState(null);
|
|
2120
|
+
const formRenderContext = useMemo(() => ({
|
|
2244
2121
|
Children,
|
|
2245
2122
|
Column,
|
|
2246
2123
|
Element: Element$1,
|
|
2247
2124
|
Empty,
|
|
2248
|
-
|
|
2249
|
-
|
|
2250
|
-
|
|
2125
|
+
EmptyRoot,
|
|
2126
|
+
Row,
|
|
2127
|
+
hoveredId,
|
|
2128
|
+
setHoveredId
|
|
2129
|
+
}), [hoveredId]);
|
|
2130
|
+
const formContext = useMemo(() => ({
|
|
2251
2131
|
getService(type, strict = true) {
|
|
2252
2132
|
// TODO(philippfromme): clean up
|
|
2253
2133
|
if (type === 'form') {
|
|
@@ -2268,7 +2148,7 @@ function FormEditor$1(props) {
|
|
|
2268
2148
|
return injector.get(type, strict);
|
|
2269
2149
|
},
|
|
2270
2150
|
formId: formEditor._id
|
|
2271
|
-
};
|
|
2151
|
+
}), [ariaLabel, formEditor, injector, schema]);
|
|
2272
2152
|
const onSubmit = useCallback(() => {}, []);
|
|
2273
2153
|
const onReset = useCallback(() => {}, []);
|
|
2274
2154
|
|
|
@@ -2294,6 +2174,7 @@ function FormEditor$1(props) {
|
|
|
2294
2174
|
children: jsx(FormContext.Provider, {
|
|
2295
2175
|
value: formContext,
|
|
2296
2176
|
children: jsx(FormRenderContext.Provider, {
|
|
2177
|
+
// @ts-ignore
|
|
2297
2178
|
value: formRenderContext,
|
|
2298
2179
|
children: jsx(FormComponent, {
|
|
2299
2180
|
onSubmit: onSubmit,
|
|
@@ -2431,10 +2312,12 @@ var renderModule = {
|
|
|
2431
2312
|
};
|
|
2432
2313
|
|
|
2433
2314
|
var core = {
|
|
2434
|
-
__depends__: [
|
|
2315
|
+
__depends__: [renderModule],
|
|
2435
2316
|
debounce: ['factory', DebounceFactory],
|
|
2436
2317
|
eventBus: ['type', EventBus],
|
|
2318
|
+
importer: ['type', Importer],
|
|
2437
2319
|
formFieldRegistry: ['type', FormFieldRegistry],
|
|
2320
|
+
pathRegistry: ['type', PathRegistry],
|
|
2438
2321
|
formLayouter: ['type', FormLayouter],
|
|
2439
2322
|
formLayoutValidator: ['type', FormLayoutValidator],
|
|
2440
2323
|
fieldFactory: ['type', FieldFactory]
|
|
@@ -3143,9 +3026,16 @@ function arrayRemove(array, index) {
|
|
|
3143
3026
|
}
|
|
3144
3027
|
function updatePath(formFieldRegistry, formField, index) {
|
|
3145
3028
|
const parent = formFieldRegistry.get(formField._parent);
|
|
3146
|
-
formField
|
|
3029
|
+
refreshPathsRecursively(formField, [...parent._path, 'components', index]);
|
|
3147
3030
|
return formField;
|
|
3148
3031
|
}
|
|
3032
|
+
function refreshPathsRecursively(formField, path) {
|
|
3033
|
+
formField._path = path;
|
|
3034
|
+
const components = formField.components || [];
|
|
3035
|
+
components.forEach((component, index) => {
|
|
3036
|
+
refreshPathsRecursively(component, [...path, 'components', index]);
|
|
3037
|
+
});
|
|
3038
|
+
}
|
|
3149
3039
|
function updateRow(formField, rowId) {
|
|
3150
3040
|
formField.layout = {
|
|
3151
3041
|
...(formField.layout || {}),
|
|
@@ -3179,7 +3069,7 @@ class AddFormFieldHandler {
|
|
|
3179
3069
|
// (1) Add new form field
|
|
3180
3070
|
arrayAdd$1(get(schema, targetPath), targetIndex, formField);
|
|
3181
3071
|
|
|
3182
|
-
// (2) Update paths of new form field and its siblings
|
|
3072
|
+
// (2) Update internal paths of new form field and its siblings (and their children)
|
|
3183
3073
|
get(schema, targetPath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3184
3074
|
|
|
3185
3075
|
// (3) Add new form field to form field registry
|
|
@@ -3204,7 +3094,7 @@ class AddFormFieldHandler {
|
|
|
3204
3094
|
// (1) Remove new form field
|
|
3205
3095
|
arrayRemove(get(schema, targetPath), targetIndex);
|
|
3206
3096
|
|
|
3207
|
-
// (2) Update paths of new form field and its siblings
|
|
3097
|
+
// (2) Update internal paths of new form field and its siblings (and their children)
|
|
3208
3098
|
get(schema, targetPath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3209
3099
|
|
|
3210
3100
|
// (3) Remove new form field from form field registry
|
|
@@ -3289,10 +3179,12 @@ class MoveFormFieldHandler {
|
|
|
3289
3179
|
* @constructor
|
|
3290
3180
|
* @param { import('../../../FormEditor').default } formEditor
|
|
3291
3181
|
* @param { import('../../../core/FormFieldRegistry').default } formFieldRegistry
|
|
3182
|
+
* @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
|
|
3292
3183
|
*/
|
|
3293
|
-
constructor(formEditor, formFieldRegistry) {
|
|
3184
|
+
constructor(formEditor, formFieldRegistry, pathRegistry) {
|
|
3294
3185
|
this._formEditor = formEditor;
|
|
3295
3186
|
this._formFieldRegistry = formFieldRegistry;
|
|
3187
|
+
this._pathRegistry = pathRegistry;
|
|
3296
3188
|
}
|
|
3297
3189
|
execute(context) {
|
|
3298
3190
|
this.moveFormField(context);
|
|
@@ -3345,27 +3237,42 @@ class MoveFormFieldHandler {
|
|
|
3345
3237
|
// (2) Move form field
|
|
3346
3238
|
mutate(get(schema, sourcePath), sourceIndex, targetIndex);
|
|
3347
3239
|
|
|
3348
|
-
// (3) Update paths of new form field and its siblings
|
|
3240
|
+
// (3) Update internal paths of new form field and its siblings (and their children)
|
|
3349
3241
|
get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3350
3242
|
} else {
|
|
3351
3243
|
const formField = get(schema, [...sourcePath, sourceIndex]);
|
|
3244
|
+
|
|
3245
|
+
// (1) Deregister form field (and children) from path registry
|
|
3246
|
+
this._pathRegistry.executeRecursivelyOnFields(formField, ({
|
|
3247
|
+
field
|
|
3248
|
+
}) => {
|
|
3249
|
+
this._pathRegistry.unclaimPath(this._pathRegistry.getValuePath(field));
|
|
3250
|
+
});
|
|
3352
3251
|
formField._parent = targetFormField.id;
|
|
3353
3252
|
|
|
3354
|
-
// (
|
|
3253
|
+
// (2) Remove form field
|
|
3355
3254
|
arrayRemove(get(schema, sourcePath), sourceIndex);
|
|
3356
3255
|
|
|
3357
|
-
// (
|
|
3256
|
+
// (3) Update internal paths of siblings (and their children)
|
|
3358
3257
|
get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3359
3258
|
const targetPath = [...targetFormField._path, 'components'];
|
|
3360
3259
|
|
|
3361
|
-
// (
|
|
3260
|
+
// (4) Add to row
|
|
3362
3261
|
updateRow(formField, targetRow ? targetRow.id : null);
|
|
3363
3262
|
|
|
3364
|
-
// (
|
|
3263
|
+
// (5) Add form field
|
|
3365
3264
|
arrayAdd$1(get(schema, targetPath), targetIndex, formField);
|
|
3366
3265
|
|
|
3367
|
-
// (
|
|
3266
|
+
// (6) Update internal paths of siblings (and their children)
|
|
3368
3267
|
get(schema, targetPath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3268
|
+
|
|
3269
|
+
// (7) Reregister form field (and children) from path registry
|
|
3270
|
+
this._pathRegistry.executeRecursivelyOnFields(formField, ({
|
|
3271
|
+
field,
|
|
3272
|
+
isClosed
|
|
3273
|
+
}) => {
|
|
3274
|
+
this._pathRegistry.claimPath(this._pathRegistry.getValuePath(field), isClosed);
|
|
3275
|
+
});
|
|
3369
3276
|
}
|
|
3370
3277
|
|
|
3371
3278
|
// TODO: Create updater/change support that automatically updates paths and schema on command execution
|
|
@@ -3374,7 +3281,7 @@ class MoveFormFieldHandler {
|
|
|
3374
3281
|
});
|
|
3375
3282
|
}
|
|
3376
3283
|
}
|
|
3377
|
-
MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry'];
|
|
3284
|
+
MoveFormFieldHandler.$inject = ['formEditor', 'formFieldRegistry', 'pathRegistry'];
|
|
3378
3285
|
|
|
3379
3286
|
class RemoveFormFieldHandler {
|
|
3380
3287
|
/**
|
|
@@ -3400,11 +3307,11 @@ class RemoveFormFieldHandler {
|
|
|
3400
3307
|
// (1) Remove form field
|
|
3401
3308
|
arrayRemove(get(schema, sourcePath), sourceIndex);
|
|
3402
3309
|
|
|
3403
|
-
// (2) Update paths of its siblings
|
|
3310
|
+
// (2) Update internal paths of its siblings (and their children)
|
|
3404
3311
|
get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3405
3312
|
|
|
3406
|
-
// (3) Remove form field from form field registry
|
|
3407
|
-
this._formFieldRegistry.remove(formField);
|
|
3313
|
+
// (3) Remove form field and children from form field registry
|
|
3314
|
+
runRecursively(formField, formField => this._formFieldRegistry.remove(formField));
|
|
3408
3315
|
|
|
3409
3316
|
// TODO: Create updater/change support that automatically updates paths and schema on command execution
|
|
3410
3317
|
this._formEditor._setState({
|
|
@@ -3425,11 +3332,11 @@ class RemoveFormFieldHandler {
|
|
|
3425
3332
|
// (1) Add form field
|
|
3426
3333
|
arrayAdd$1(get(schema, sourcePath), sourceIndex, formField);
|
|
3427
3334
|
|
|
3428
|
-
// (2) Update paths of its siblings
|
|
3335
|
+
// (2) Update internal paths of its siblings (and their children)
|
|
3429
3336
|
get(schema, sourcePath).forEach((formField, index) => updatePath(this._formFieldRegistry, formField, index));
|
|
3430
3337
|
|
|
3431
|
-
// (3) Add form field to form field registry
|
|
3432
|
-
this._formFieldRegistry.add(formField);
|
|
3338
|
+
// (3) Add form field and children to form field registry
|
|
3339
|
+
runRecursively(formField, formField => this._formFieldRegistry.add(formField));
|
|
3433
3340
|
|
|
3434
3341
|
// TODO: Create updater/change support that automatically updates paths and schema on command execution
|
|
3435
3342
|
this._formEditor._setState({
|
|
@@ -3477,10 +3384,10 @@ UpdateIdClaimHandler.$inject = ['formFieldRegistry'];
|
|
|
3477
3384
|
class UpdateKeyClaimHandler {
|
|
3478
3385
|
/**
|
|
3479
3386
|
* @constructor
|
|
3480
|
-
* @param { import('
|
|
3387
|
+
* @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
|
|
3481
3388
|
*/
|
|
3482
|
-
constructor(
|
|
3483
|
-
this.
|
|
3389
|
+
constructor(pathRegistry) {
|
|
3390
|
+
this._pathRegistry = pathRegistry;
|
|
3484
3391
|
}
|
|
3485
3392
|
execute(context) {
|
|
3486
3393
|
const {
|
|
@@ -3488,26 +3395,106 @@ class UpdateKeyClaimHandler {
|
|
|
3488
3395
|
formField,
|
|
3489
3396
|
key
|
|
3490
3397
|
} = context;
|
|
3398
|
+
const options = {
|
|
3399
|
+
replacements: {
|
|
3400
|
+
[formField.id]: key
|
|
3401
|
+
}
|
|
3402
|
+
};
|
|
3403
|
+
const valuePath = this._pathRegistry.getValuePath(formField, options);
|
|
3491
3404
|
if (claiming) {
|
|
3492
|
-
this.
|
|
3405
|
+
this._pathRegistry.claimPath(valuePath, true);
|
|
3493
3406
|
} else {
|
|
3494
|
-
this.
|
|
3407
|
+
this._pathRegistry.unclaimPath(valuePath);
|
|
3495
3408
|
}
|
|
3409
|
+
|
|
3410
|
+
// cache path for revert
|
|
3411
|
+
context.valuePath = valuePath;
|
|
3496
3412
|
}
|
|
3497
3413
|
revert(context) {
|
|
3414
|
+
const {
|
|
3415
|
+
claiming,
|
|
3416
|
+
valuePath
|
|
3417
|
+
} = context;
|
|
3418
|
+
if (claiming) {
|
|
3419
|
+
this._pathRegistry.unclaimPath(valuePath);
|
|
3420
|
+
} else {
|
|
3421
|
+
this._pathRegistry.claimPath(valuePath, true);
|
|
3422
|
+
}
|
|
3423
|
+
}
|
|
3424
|
+
}
|
|
3425
|
+
UpdateKeyClaimHandler.$inject = ['pathRegistry'];
|
|
3426
|
+
|
|
3427
|
+
class UpdatePathClaimHandler {
|
|
3428
|
+
/**
|
|
3429
|
+
* @constructor
|
|
3430
|
+
* @param { import('@bpmn-io/form-js-viewer').PathRegistry } pathRegistry
|
|
3431
|
+
*/
|
|
3432
|
+
constructor(pathRegistry) {
|
|
3433
|
+
this._pathRegistry = pathRegistry;
|
|
3434
|
+
}
|
|
3435
|
+
execute(context) {
|
|
3498
3436
|
const {
|
|
3499
3437
|
claiming,
|
|
3500
3438
|
formField,
|
|
3501
|
-
|
|
3439
|
+
path
|
|
3440
|
+
} = context;
|
|
3441
|
+
const options = {
|
|
3442
|
+
replacements: {
|
|
3443
|
+
[formField.id]: path
|
|
3444
|
+
}
|
|
3445
|
+
};
|
|
3446
|
+
const valuePaths = [];
|
|
3447
|
+
if (claiming) {
|
|
3448
|
+
this._pathRegistry.executeRecursivelyOnFields(formField, ({
|
|
3449
|
+
field,
|
|
3450
|
+
isClosed
|
|
3451
|
+
}) => {
|
|
3452
|
+
const valuePath = this._pathRegistry.getValuePath(field, options);
|
|
3453
|
+
valuePaths.push({
|
|
3454
|
+
valuePath,
|
|
3455
|
+
isClosed
|
|
3456
|
+
});
|
|
3457
|
+
this._pathRegistry.claimPath(valuePath, isClosed);
|
|
3458
|
+
});
|
|
3459
|
+
} else {
|
|
3460
|
+
this._pathRegistry.executeRecursivelyOnFields(formField, ({
|
|
3461
|
+
field,
|
|
3462
|
+
isClosed
|
|
3463
|
+
}) => {
|
|
3464
|
+
const valuePath = this._pathRegistry.getValuePath(field, options);
|
|
3465
|
+
valuePaths.push({
|
|
3466
|
+
valuePath,
|
|
3467
|
+
isClosed
|
|
3468
|
+
});
|
|
3469
|
+
this._pathRegistry.unclaimPath(valuePath);
|
|
3470
|
+
});
|
|
3471
|
+
}
|
|
3472
|
+
|
|
3473
|
+
// cache path info for revert
|
|
3474
|
+
context.valuePaths = valuePaths;
|
|
3475
|
+
}
|
|
3476
|
+
revert(context) {
|
|
3477
|
+
const {
|
|
3478
|
+
claiming,
|
|
3479
|
+
valuePaths
|
|
3502
3480
|
} = context;
|
|
3503
3481
|
if (claiming) {
|
|
3504
|
-
|
|
3482
|
+
valuePaths.forEach(({
|
|
3483
|
+
valuePath
|
|
3484
|
+
}) => {
|
|
3485
|
+
this._pathRegistry.unclaimPath(valuePath);
|
|
3486
|
+
});
|
|
3505
3487
|
} else {
|
|
3506
|
-
|
|
3488
|
+
valuePaths.forEach(({
|
|
3489
|
+
valuePath,
|
|
3490
|
+
isClosed
|
|
3491
|
+
}) => {
|
|
3492
|
+
this._pathRegistry.claimPath(valuePath, isClosed);
|
|
3493
|
+
});
|
|
3507
3494
|
}
|
|
3508
3495
|
}
|
|
3509
3496
|
}
|
|
3510
|
-
|
|
3497
|
+
UpdatePathClaimHandler.$inject = ['pathRegistry'];
|
|
3511
3498
|
|
|
3512
3499
|
class Modeling {
|
|
3513
3500
|
constructor(commandStack, eventBus, formEditor, formFieldRegistry, fieldFactory) {
|
|
@@ -3531,7 +3518,8 @@ class Modeling {
|
|
|
3531
3518
|
'formField.move': MoveFormFieldHandler,
|
|
3532
3519
|
'formField.remove': RemoveFormFieldHandler,
|
|
3533
3520
|
'id.updateClaim': UpdateIdClaimHandler,
|
|
3534
|
-
'key.updateClaim': UpdateKeyClaimHandler
|
|
3521
|
+
'key.updateClaim': UpdateKeyClaimHandler,
|
|
3522
|
+
'path.updateClaim': UpdatePathClaimHandler
|
|
3535
3523
|
};
|
|
3536
3524
|
}
|
|
3537
3525
|
addFormField(attrs, targetFormField, targetIndex) {
|
|
@@ -3608,6 +3596,22 @@ class Modeling {
|
|
|
3608
3596
|
};
|
|
3609
3597
|
this._commandStack.execute('key.updateClaim', context);
|
|
3610
3598
|
}
|
|
3599
|
+
claimPath(formField, path) {
|
|
3600
|
+
const context = {
|
|
3601
|
+
formField,
|
|
3602
|
+
path,
|
|
3603
|
+
claiming: true
|
|
3604
|
+
};
|
|
3605
|
+
this._commandStack.execute('path.updateClaim', context);
|
|
3606
|
+
}
|
|
3607
|
+
unclaimPath(formField, path) {
|
|
3608
|
+
const context = {
|
|
3609
|
+
formField,
|
|
3610
|
+
path,
|
|
3611
|
+
claiming: false
|
|
3612
|
+
};
|
|
3613
|
+
this._commandStack.execute('path.updateClaim', context);
|
|
3614
|
+
}
|
|
3611
3615
|
}
|
|
3612
3616
|
Modeling.$inject = ['commandStack', 'eventBus', 'formEditor', 'formFieldRegistry', 'fieldFactory'];
|
|
3613
3617
|
|
|
@@ -3880,8 +3884,6 @@ FormLayoutUpdater.$inject = ['eventBus', 'formLayouter', 'modeling', 'formEditor
|
|
|
3880
3884
|
class IdBehavior extends CommandInterceptor {
|
|
3881
3885
|
constructor(eventBus, modeling) {
|
|
3882
3886
|
super(eventBus);
|
|
3883
|
-
|
|
3884
|
-
// @ts-ignore-next-line
|
|
3885
3887
|
this.preExecute('formField.remove', function (context) {
|
|
3886
3888
|
const {
|
|
3887
3889
|
formField
|
|
@@ -3891,8 +3893,6 @@ class IdBehavior extends CommandInterceptor {
|
|
|
3891
3893
|
} = formField;
|
|
3892
3894
|
modeling.unclaimId(formField, id);
|
|
3893
3895
|
}, true);
|
|
3894
|
-
|
|
3895
|
-
// @ts-ignore-next-line
|
|
3896
3896
|
this.preExecute('formField.edit', function (context) {
|
|
3897
3897
|
const {
|
|
3898
3898
|
formField,
|
|
@@ -3908,36 +3908,82 @@ class IdBehavior extends CommandInterceptor {
|
|
|
3908
3908
|
IdBehavior.$inject = ['eventBus', 'modeling'];
|
|
3909
3909
|
|
|
3910
3910
|
class KeyBehavior extends CommandInterceptor {
|
|
3911
|
-
constructor(eventBus, modeling) {
|
|
3911
|
+
constructor(eventBus, modeling, formFields) {
|
|
3912
3912
|
super(eventBus);
|
|
3913
|
-
|
|
3914
|
-
// @ts-ignore-next-line
|
|
3915
3913
|
this.preExecute('formField.remove', function (context) {
|
|
3916
3914
|
const {
|
|
3917
3915
|
formField
|
|
3918
3916
|
} = context;
|
|
3919
3917
|
const {
|
|
3920
|
-
key
|
|
3918
|
+
key,
|
|
3919
|
+
type
|
|
3921
3920
|
} = formField;
|
|
3922
|
-
|
|
3921
|
+
const {
|
|
3922
|
+
config
|
|
3923
|
+
} = formFields.get(type);
|
|
3924
|
+
if (config.keyed) {
|
|
3923
3925
|
modeling.unclaimKey(formField, key);
|
|
3924
3926
|
}
|
|
3925
3927
|
}, true);
|
|
3926
|
-
|
|
3927
|
-
// @ts-ignore-next-line
|
|
3928
3928
|
this.preExecute('formField.edit', function (context) {
|
|
3929
3929
|
const {
|
|
3930
3930
|
formField,
|
|
3931
3931
|
properties
|
|
3932
3932
|
} = context;
|
|
3933
|
-
|
|
3934
|
-
|
|
3933
|
+
const {
|
|
3934
|
+
key,
|
|
3935
|
+
type
|
|
3936
|
+
} = formField;
|
|
3937
|
+
const {
|
|
3938
|
+
config
|
|
3939
|
+
} = formFields.get(type);
|
|
3940
|
+
if (config.keyed && 'key' in properties) {
|
|
3941
|
+
modeling.unclaimKey(formField, key);
|
|
3935
3942
|
modeling.claimKey(formField, properties.key);
|
|
3936
3943
|
}
|
|
3937
3944
|
}, true);
|
|
3938
3945
|
}
|
|
3939
3946
|
}
|
|
3940
|
-
KeyBehavior.$inject = ['eventBus', 'modeling'];
|
|
3947
|
+
KeyBehavior.$inject = ['eventBus', 'modeling', 'formFields'];
|
|
3948
|
+
|
|
3949
|
+
class PathBehavior extends CommandInterceptor {
|
|
3950
|
+
constructor(eventBus, modeling, formFields) {
|
|
3951
|
+
super(eventBus);
|
|
3952
|
+
this.preExecute('formField.remove', function (context) {
|
|
3953
|
+
const {
|
|
3954
|
+
formField
|
|
3955
|
+
} = context;
|
|
3956
|
+
const {
|
|
3957
|
+
path,
|
|
3958
|
+
type
|
|
3959
|
+
} = formField;
|
|
3960
|
+
const {
|
|
3961
|
+
config
|
|
3962
|
+
} = formFields.get(type);
|
|
3963
|
+
if (config.pathed) {
|
|
3964
|
+
modeling.unclaimPath(formField, path);
|
|
3965
|
+
}
|
|
3966
|
+
}, true);
|
|
3967
|
+
this.preExecute('formField.edit', function (context) {
|
|
3968
|
+
const {
|
|
3969
|
+
formField,
|
|
3970
|
+
properties
|
|
3971
|
+
} = context;
|
|
3972
|
+
const {
|
|
3973
|
+
path,
|
|
3974
|
+
type
|
|
3975
|
+
} = formField;
|
|
3976
|
+
const {
|
|
3977
|
+
config
|
|
3978
|
+
} = formFields.get(type);
|
|
3979
|
+
if (config.pathed && 'path' in properties) {
|
|
3980
|
+
modeling.unclaimPath(formField, path);
|
|
3981
|
+
modeling.claimPath(formField, properties.path);
|
|
3982
|
+
}
|
|
3983
|
+
}, true);
|
|
3984
|
+
}
|
|
3985
|
+
}
|
|
3986
|
+
PathBehavior.$inject = ['eventBus', 'modeling', 'formFields'];
|
|
3941
3987
|
|
|
3942
3988
|
class ValidateBehavior extends CommandInterceptor {
|
|
3943
3989
|
constructor(eventBus) {
|
|
@@ -3946,7 +3992,6 @@ class ValidateBehavior extends CommandInterceptor {
|
|
|
3946
3992
|
/**
|
|
3947
3993
|
* Remove custom validation if <validationType> is about to be added.
|
|
3948
3994
|
*/
|
|
3949
|
-
// @ts-ignore-next-line
|
|
3950
3995
|
this.preExecute('formField.edit', function (context) {
|
|
3951
3996
|
const {
|
|
3952
3997
|
properties
|
|
@@ -3969,9 +4014,10 @@ class ValidateBehavior extends CommandInterceptor {
|
|
|
3969
4014
|
ValidateBehavior.$inject = ['eventBus'];
|
|
3970
4015
|
|
|
3971
4016
|
var behaviorModule = {
|
|
3972
|
-
__init__: ['idBehavior', 'keyBehavior', 'validateBehavior'],
|
|
4017
|
+
__init__: ['idBehavior', 'keyBehavior', 'pathBehavior', 'validateBehavior'],
|
|
3973
4018
|
idBehavior: ['type', IdBehavior],
|
|
3974
4019
|
keyBehavior: ['type', KeyBehavior],
|
|
4020
|
+
pathBehavior: ['type', PathBehavior],
|
|
3975
4021
|
validateBehavior: ['type', ValidateBehavior]
|
|
3976
4022
|
};
|
|
3977
4023
|
|
|
@@ -4642,6 +4688,33 @@ DeleteIcon.defaultProps = {
|
|
|
4642
4688
|
width: "16",
|
|
4643
4689
|
height: "16"
|
|
4644
4690
|
};
|
|
4691
|
+
var DragIcon = function DragIcon(props) {
|
|
4692
|
+
return jsxs("svg", {
|
|
4693
|
+
...props,
|
|
4694
|
+
children: [jsx("path", {
|
|
4695
|
+
fill: "#fff",
|
|
4696
|
+
style: {
|
|
4697
|
+
mixBlendMode: "multiply"
|
|
4698
|
+
},
|
|
4699
|
+
d: "M0 0h16v16H0z"
|
|
4700
|
+
}), jsx("path", {
|
|
4701
|
+
fill: "#fff",
|
|
4702
|
+
style: {
|
|
4703
|
+
mixBlendMode: "multiply"
|
|
4704
|
+
},
|
|
4705
|
+
d: "M0 0h16v16H0z"
|
|
4706
|
+
}), jsx("path", {
|
|
4707
|
+
d: "M7 3H5v2h2V3zm4 0H9v2h2V3zM7 7H5v2h2V7zm4 0H9v2h2V7zm-4 4H5v2h2v-2zm4 0H9v2h2v-2z",
|
|
4708
|
+
fill: "#161616"
|
|
4709
|
+
})]
|
|
4710
|
+
});
|
|
4711
|
+
};
|
|
4712
|
+
DragIcon.defaultProps = {
|
|
4713
|
+
width: "16",
|
|
4714
|
+
height: "16",
|
|
4715
|
+
fill: "none",
|
|
4716
|
+
xmlns: "http://www.w3.org/2000/svg"
|
|
4717
|
+
};
|
|
4645
4718
|
var ExternalLinkIcon = function ExternalLinkIcon(props) {
|
|
4646
4719
|
return jsx("svg", {
|
|
4647
4720
|
...props,
|
|
@@ -4649,7 +4722,7 @@ var ExternalLinkIcon = function ExternalLinkIcon(props) {
|
|
|
4649
4722
|
fillRule: "evenodd",
|
|
4650
4723
|
clipRule: "evenodd",
|
|
4651
4724
|
d: "M12.637 12.637v-4.72h1.362v4.721c0 .36-.137.676-.411.95-.275.275-.591.412-.95.412H3.362c-.38 0-.703-.132-.967-.396A1.315 1.315 0 0 1 2 12.638V3.362c0-.38.132-.703.396-.967S2.982 2 3.363 2h4.553v1.363H3.363v9.274h9.274ZM14 2H9.28l-.001 1.362h2.408L5.065 9.984l.95.95 6.622-6.622v2.409H14V2Z",
|
|
4652
|
-
fill: "
|
|
4725
|
+
fill: "currentcolor"
|
|
4653
4726
|
})
|
|
4654
4727
|
});
|
|
4655
4728
|
};
|
|
@@ -4792,7 +4865,7 @@ function TooltipWrapper(props) {
|
|
|
4792
4865
|
return jsx(Tooltip, {
|
|
4793
4866
|
...props,
|
|
4794
4867
|
value: value,
|
|
4795
|
-
forId: prefixId$
|
|
4868
|
+
forId: prefixId$9(forId)
|
|
4796
4869
|
});
|
|
4797
4870
|
}
|
|
4798
4871
|
function Tooltip(props) {
|
|
@@ -4910,7 +4983,7 @@ function getTooltipPosition(refElement) {
|
|
|
4910
4983
|
function isHovered(element) {
|
|
4911
4984
|
return element.matches(':hover');
|
|
4912
4985
|
}
|
|
4913
|
-
function prefixId$
|
|
4986
|
+
function prefixId$9(id) {
|
|
4914
4987
|
return `bio-properties-panel-${id}`;
|
|
4915
4988
|
}
|
|
4916
4989
|
|
|
@@ -5283,638 +5356,739 @@ function Placeholder(props) {
|
|
|
5283
5356
|
})
|
|
5284
5357
|
});
|
|
5285
5358
|
}
|
|
5286
|
-
|
|
5287
|
-
const
|
|
5288
|
-
|
|
5359
|
+
function Description$1(props) {
|
|
5360
|
+
const {
|
|
5361
|
+
element,
|
|
5362
|
+
forId,
|
|
5363
|
+
value
|
|
5364
|
+
} = props;
|
|
5365
|
+
const contextDescription = useDescriptionContext(forId, element);
|
|
5366
|
+
const description = value || contextDescription;
|
|
5367
|
+
if (description) {
|
|
5368
|
+
return jsx("div", {
|
|
5369
|
+
class: "bio-properties-panel-description",
|
|
5370
|
+
children: description
|
|
5371
|
+
});
|
|
5372
|
+
}
|
|
5373
|
+
}
|
|
5374
|
+
const noop$6 = () => {};
|
|
5289
5375
|
|
|
5290
5376
|
/**
|
|
5291
|
-
*
|
|
5292
|
-
*
|
|
5293
|
-
* id: String,
|
|
5294
|
-
* isEdited?: Function
|
|
5295
|
-
* } } EntryDefinition
|
|
5296
|
-
*
|
|
5297
|
-
* @typedef { {
|
|
5298
|
-
* autoFocusEntry: String,
|
|
5299
|
-
* autoOpen?: Boolean,
|
|
5300
|
-
* entries: Array<EntryDefinition>,
|
|
5301
|
-
* id: String,
|
|
5302
|
-
* label: String,
|
|
5303
|
-
* remove: (event: MouseEvent) => void
|
|
5304
|
-
* } } ListItemDefinition
|
|
5305
|
-
*
|
|
5306
|
-
* @typedef { {
|
|
5307
|
-
* add: (event: MouseEvent) => void,
|
|
5308
|
-
* component: import('preact').Component,
|
|
5309
|
-
* element: Object,
|
|
5310
|
-
* id: String,
|
|
5311
|
-
* items: Array<ListItemDefinition>,
|
|
5312
|
-
* label: String,
|
|
5313
|
-
* shouldSort?: Boolean,
|
|
5314
|
-
* shouldOpen?: Boolean
|
|
5315
|
-
* } } ListGroupDefinition
|
|
5316
|
-
*
|
|
5317
|
-
* @typedef { {
|
|
5318
|
-
* component?: import('preact').Component,
|
|
5319
|
-
* entries: Array<EntryDefinition>,
|
|
5320
|
-
* id: String,
|
|
5321
|
-
* label: String,
|
|
5322
|
-
* shouldOpen?: Boolean
|
|
5323
|
-
* } } GroupDefinition
|
|
5324
|
-
*
|
|
5325
|
-
* @typedef { {
|
|
5326
|
-
* [id: String]: GetDescriptionFunction
|
|
5327
|
-
* } } DescriptionConfig
|
|
5328
|
-
*
|
|
5329
|
-
* @typedef { {
|
|
5330
|
-
* [id: String]: GetTooltipFunction
|
|
5331
|
-
* } } TooltipConfig
|
|
5332
|
-
*
|
|
5333
|
-
* @callback { {
|
|
5334
|
-
* @param {string} id
|
|
5335
|
-
* @param {Object} element
|
|
5336
|
-
* @returns {string}
|
|
5337
|
-
* } } GetDescriptionFunction
|
|
5338
|
-
*
|
|
5339
|
-
* @callback { {
|
|
5340
|
-
* @param {string} id
|
|
5341
|
-
* @param {Object} element
|
|
5342
|
-
* @returns {string}
|
|
5343
|
-
* } } GetTooltipFunction
|
|
5344
|
-
*
|
|
5345
|
-
* @typedef { {
|
|
5346
|
-
* getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
|
|
5347
|
-
* getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
|
|
5348
|
-
* } } PlaceholderProvider
|
|
5349
|
-
*
|
|
5350
|
-
*/
|
|
5351
|
-
|
|
5352
|
-
/**
|
|
5353
|
-
* A basic properties panel component. Describes *how* content will be rendered, accepts
|
|
5354
|
-
* data from implementor to describe *what* will be rendered.
|
|
5355
|
-
*
|
|
5356
|
-
* @param {Object} props
|
|
5357
|
-
* @param {Object|Array} props.element
|
|
5358
|
-
* @param {import('./components/Header').HeaderProvider} props.headerProvider
|
|
5359
|
-
* @param {PlaceholderProvider} [props.placeholderProvider]
|
|
5360
|
-
* @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
|
|
5361
|
-
* @param {Object} [props.layoutConfig]
|
|
5362
|
-
* @param {Function} [props.layoutChanged]
|
|
5363
|
-
* @param {DescriptionConfig} [props.descriptionConfig]
|
|
5364
|
-
* @param {Function} [props.descriptionLoaded]
|
|
5365
|
-
* @param {TooltipConfig} [props.tooltipConfig]
|
|
5366
|
-
* @param {Function} [props.tooltipLoaded]
|
|
5367
|
-
* @param {Object} [props.eventBus]
|
|
5377
|
+
* Buffer `.focus()` calls while the editor is not initialized.
|
|
5378
|
+
* Set Focus inside when the editor is ready.
|
|
5368
5379
|
*/
|
|
5369
|
-
function
|
|
5380
|
+
const useBufferedFocus$1 = function (editor, ref) {
|
|
5381
|
+
const [buffer, setBuffer] = useState(undefined);
|
|
5382
|
+
ref.current = useMemo(() => ({
|
|
5383
|
+
focus: offset => {
|
|
5384
|
+
if (editor) {
|
|
5385
|
+
editor.focus(offset);
|
|
5386
|
+
} else {
|
|
5387
|
+
if (typeof offset === 'undefined') {
|
|
5388
|
+
offset = Infinity;
|
|
5389
|
+
}
|
|
5390
|
+
setBuffer(offset);
|
|
5391
|
+
}
|
|
5392
|
+
}
|
|
5393
|
+
}), [editor]);
|
|
5394
|
+
useEffect(() => {
|
|
5395
|
+
if (typeof buffer !== 'undefined' && editor) {
|
|
5396
|
+
editor.focus(buffer);
|
|
5397
|
+
setBuffer(false);
|
|
5398
|
+
}
|
|
5399
|
+
}, [editor, buffer]);
|
|
5400
|
+
};
|
|
5401
|
+
const CodeEditor$1 = forwardRef((props, ref) => {
|
|
5370
5402
|
const {
|
|
5371
|
-
|
|
5372
|
-
|
|
5373
|
-
|
|
5374
|
-
|
|
5375
|
-
|
|
5376
|
-
|
|
5377
|
-
|
|
5378
|
-
|
|
5379
|
-
|
|
5380
|
-
|
|
5381
|
-
|
|
5403
|
+
onInput,
|
|
5404
|
+
disabled,
|
|
5405
|
+
tooltipContainer,
|
|
5406
|
+
enableGutters,
|
|
5407
|
+
value,
|
|
5408
|
+
onLint = noop$6,
|
|
5409
|
+
onPopupOpen = noop$6,
|
|
5410
|
+
popupOpen,
|
|
5411
|
+
contentAttributes = {},
|
|
5412
|
+
hostLanguage = null,
|
|
5413
|
+
singleLine = false
|
|
5382
5414
|
} = props;
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
const [
|
|
5386
|
-
|
|
5387
|
-
|
|
5388
|
-
|
|
5389
|
-
|
|
5390
|
-
|
|
5391
|
-
}, [layoutConfig]);
|
|
5415
|
+
const inputRef = useRef$1();
|
|
5416
|
+
const [editor, setEditor] = useState();
|
|
5417
|
+
const [localValue, setLocalValue] = useState(value || '');
|
|
5418
|
+
useBufferedFocus$1(editor, ref);
|
|
5419
|
+
const handleInput = useStaticCallback(newValue => {
|
|
5420
|
+
onInput(newValue);
|
|
5421
|
+
setLocalValue(newValue);
|
|
5422
|
+
});
|
|
5392
5423
|
useEffect(() => {
|
|
5393
|
-
|
|
5394
|
-
|
|
5424
|
+
let editor;
|
|
5425
|
+
editor = new FeelersEditor({
|
|
5426
|
+
container: inputRef.current,
|
|
5427
|
+
onChange: handleInput,
|
|
5428
|
+
value: localValue,
|
|
5429
|
+
onLint,
|
|
5430
|
+
contentAttributes,
|
|
5431
|
+
tooltipContainer,
|
|
5432
|
+
enableGutters,
|
|
5433
|
+
hostLanguage,
|
|
5434
|
+
singleLine
|
|
5435
|
+
});
|
|
5436
|
+
setEditor(editor);
|
|
5437
|
+
return () => {
|
|
5438
|
+
onLint([]);
|
|
5439
|
+
inputRef.current.innerHTML = '';
|
|
5440
|
+
setEditor(null);
|
|
5441
|
+
};
|
|
5442
|
+
}, []);
|
|
5443
|
+
useEffect(() => {
|
|
5444
|
+
if (!editor) {
|
|
5445
|
+
return;
|
|
5395
5446
|
}
|
|
5396
|
-
|
|
5397
|
-
|
|
5398
|
-
|
|
5399
|
-
|
|
5400
|
-
|
|
5401
|
-
|
|
5402
|
-
|
|
5403
|
-
|
|
5404
|
-
};
|
|
5405
|
-
const layoutContext = {
|
|
5406
|
-
layout,
|
|
5407
|
-
setLayout,
|
|
5408
|
-
getLayoutForKey,
|
|
5409
|
-
setLayoutForKey
|
|
5447
|
+
if (value === localValue) {
|
|
5448
|
+
return;
|
|
5449
|
+
}
|
|
5450
|
+
editor.setValue(value);
|
|
5451
|
+
setLocalValue(value);
|
|
5452
|
+
}, [value]);
|
|
5453
|
+
const handleClick = () => {
|
|
5454
|
+
ref.current.focus();
|
|
5410
5455
|
};
|
|
5456
|
+
return jsxs("div", {
|
|
5457
|
+
class: classnames('bio-properties-panel-feelers-editor-container', popupOpen ? 'popupOpen' : null),
|
|
5458
|
+
children: [jsx("div", {
|
|
5459
|
+
class: "bio-properties-panel-feelers-editor__open-popup-placeholder",
|
|
5460
|
+
children: "Opened in editor"
|
|
5461
|
+
}), jsx("div", {
|
|
5462
|
+
name: props.name,
|
|
5463
|
+
class: classnames('bio-properties-panel-feelers-editor bio-properties-panel-input', localValue ? 'edited' : null, disabled ? 'disabled' : null),
|
|
5464
|
+
ref: inputRef,
|
|
5465
|
+
onClick: handleClick
|
|
5466
|
+
}), jsx("button", {
|
|
5467
|
+
title: "Open pop-up editor",
|
|
5468
|
+
class: "bio-properties-panel-open-feel-popup",
|
|
5469
|
+
onClick: () => onPopupOpen('feelers'),
|
|
5470
|
+
children: jsx(ExternalLinkIcon, {})
|
|
5471
|
+
})]
|
|
5472
|
+
});
|
|
5473
|
+
});
|
|
5474
|
+
const noop$5 = () => {};
|
|
5411
5475
|
|
|
5412
|
-
|
|
5413
|
-
|
|
5476
|
+
/**
|
|
5477
|
+
* Buffer `.focus()` calls while the editor is not initialized.
|
|
5478
|
+
* Set Focus inside when the editor is ready.
|
|
5479
|
+
*/
|
|
5480
|
+
const useBufferedFocus = function (editor, ref) {
|
|
5481
|
+
const [buffer, setBuffer] = useState(undefined);
|
|
5482
|
+
ref.current = useMemo(() => ({
|
|
5483
|
+
focus: offset => {
|
|
5484
|
+
if (editor) {
|
|
5485
|
+
editor.focus(offset);
|
|
5486
|
+
} else {
|
|
5487
|
+
if (typeof offset === 'undefined') {
|
|
5488
|
+
offset = Infinity;
|
|
5489
|
+
}
|
|
5490
|
+
setBuffer(offset);
|
|
5491
|
+
}
|
|
5492
|
+
}
|
|
5493
|
+
}), [editor]);
|
|
5414
5494
|
useEffect(() => {
|
|
5415
|
-
if (typeof
|
|
5416
|
-
|
|
5495
|
+
if (typeof buffer !== 'undefined' && editor) {
|
|
5496
|
+
editor.focus(buffer);
|
|
5497
|
+
setBuffer(false);
|
|
5417
5498
|
}
|
|
5418
|
-
}, [
|
|
5419
|
-
|
|
5420
|
-
|
|
5421
|
-
|
|
5422
|
-
|
|
5423
|
-
|
|
5424
|
-
|
|
5425
|
-
|
|
5499
|
+
}, [editor, buffer]);
|
|
5500
|
+
};
|
|
5501
|
+
const CodeEditor = forwardRef((props, ref) => {
|
|
5502
|
+
const {
|
|
5503
|
+
enableGutters,
|
|
5504
|
+
value,
|
|
5505
|
+
onInput,
|
|
5506
|
+
onFeelToggle = noop$5,
|
|
5507
|
+
onLint = noop$5,
|
|
5508
|
+
onPopupOpen = noop$5,
|
|
5509
|
+
popupOpen,
|
|
5510
|
+
disabled,
|
|
5511
|
+
tooltipContainer,
|
|
5512
|
+
variables
|
|
5513
|
+
} = props;
|
|
5514
|
+
const inputRef = useRef$1();
|
|
5515
|
+
const [editor, setEditor] = useState();
|
|
5516
|
+
const [localValue, setLocalValue] = useState(value || '');
|
|
5517
|
+
useBufferedFocus(editor, ref);
|
|
5518
|
+
const handleInput = useStaticCallback(newValue => {
|
|
5519
|
+
onInput(newValue);
|
|
5520
|
+
setLocalValue(newValue);
|
|
5521
|
+
});
|
|
5522
|
+
useEffect(() => {
|
|
5523
|
+
let editor;
|
|
5426
5524
|
|
|
5427
|
-
|
|
5428
|
-
|
|
5525
|
+
/* Trigger FEEL toggle when
|
|
5526
|
+
*
|
|
5527
|
+
* - `backspace` is pressed
|
|
5528
|
+
* - AND the cursor is at the beginning of the input
|
|
5529
|
+
*/
|
|
5530
|
+
const onKeyDown = e => {
|
|
5531
|
+
if (e.key !== 'Backspace' || !editor) {
|
|
5532
|
+
return;
|
|
5533
|
+
}
|
|
5534
|
+
const selection = editor.getSelection();
|
|
5535
|
+
const range = selection.ranges[selection.mainIndex];
|
|
5536
|
+
if (range.from === 0 && range.to === 0) {
|
|
5537
|
+
onFeelToggle();
|
|
5538
|
+
}
|
|
5539
|
+
};
|
|
5540
|
+
editor = new FeelEditor({
|
|
5541
|
+
container: inputRef.current,
|
|
5542
|
+
onChange: handleInput,
|
|
5543
|
+
onKeyDown: onKeyDown,
|
|
5544
|
+
onLint: onLint,
|
|
5545
|
+
tooltipContainer: tooltipContainer,
|
|
5546
|
+
value: localValue,
|
|
5547
|
+
variables: variables,
|
|
5548
|
+
extensions: [...(enableGutters ? [lineNumbers()] : [])]
|
|
5549
|
+
});
|
|
5550
|
+
setEditor(editor);
|
|
5551
|
+
return () => {
|
|
5552
|
+
onLint([]);
|
|
5553
|
+
inputRef.current.innerHTML = '';
|
|
5554
|
+
setEditor(null);
|
|
5555
|
+
};
|
|
5556
|
+
}, []);
|
|
5429
5557
|
useEffect(() => {
|
|
5430
|
-
if (
|
|
5431
|
-
|
|
5558
|
+
if (!editor) {
|
|
5559
|
+
return;
|
|
5432
5560
|
}
|
|
5433
|
-
|
|
5434
|
-
|
|
5435
|
-
|
|
5436
|
-
|
|
5437
|
-
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
|
|
5441
|
-
|
|
5442
|
-
|
|
5443
|
-
|
|
5444
|
-
}
|
|
5445
|
-
|
|
5446
|
-
|
|
5447
|
-
errors
|
|
5448
|
-
};
|
|
5449
|
-
const eventContext = {
|
|
5450
|
-
eventBus
|
|
5451
|
-
};
|
|
5452
|
-
const propertiesPanelContext = {
|
|
5453
|
-
element
|
|
5561
|
+
if (value === localValue) {
|
|
5562
|
+
return;
|
|
5563
|
+
}
|
|
5564
|
+
editor.setValue(value);
|
|
5565
|
+
setLocalValue(value);
|
|
5566
|
+
}, [value]);
|
|
5567
|
+
useEffect(() => {
|
|
5568
|
+
if (!editor) {
|
|
5569
|
+
return;
|
|
5570
|
+
}
|
|
5571
|
+
editor.setVariables(variables);
|
|
5572
|
+
}, [variables]);
|
|
5573
|
+
const handleClick = () => {
|
|
5574
|
+
ref.current.focus();
|
|
5454
5575
|
};
|
|
5455
|
-
|
|
5456
|
-
|
|
5457
|
-
|
|
5458
|
-
|
|
5459
|
-
|
|
5460
|
-
})
|
|
5461
|
-
|
|
5462
|
-
|
|
5463
|
-
|
|
5464
|
-
|
|
5465
|
-
|
|
5466
|
-
|
|
5467
|
-
|
|
5576
|
+
return jsxs("div", {
|
|
5577
|
+
class: classnames('bio-properties-panel-feel-editor-container', disabled ? 'disabled' : null, popupOpen ? 'popupOpen' : null),
|
|
5578
|
+
children: [jsx("div", {
|
|
5579
|
+
class: "bio-properties-panel-feel-editor__open-popup-placeholder",
|
|
5580
|
+
children: "Opened in editor"
|
|
5581
|
+
}), jsx("div", {
|
|
5582
|
+
name: props.name,
|
|
5583
|
+
class: classnames('bio-properties-panel-input', localValue ? 'edited' : null),
|
|
5584
|
+
ref: inputRef,
|
|
5585
|
+
onClick: handleClick
|
|
5586
|
+
}), jsx("button", {
|
|
5587
|
+
title: "Open pop-up editor",
|
|
5588
|
+
class: "bio-properties-panel-open-feel-popup",
|
|
5589
|
+
onClick: () => onPopupOpen(),
|
|
5590
|
+
children: jsx(ExternalLinkIcon, {})
|
|
5591
|
+
})]
|
|
5592
|
+
});
|
|
5593
|
+
});
|
|
5594
|
+
function FeelIndicator(props) {
|
|
5595
|
+
const {
|
|
5596
|
+
active
|
|
5597
|
+
} = props;
|
|
5598
|
+
if (!active) {
|
|
5599
|
+
return null;
|
|
5468
5600
|
}
|
|
5469
|
-
return jsx(
|
|
5470
|
-
|
|
5471
|
-
children:
|
|
5472
|
-
value: errorsContext,
|
|
5473
|
-
children: jsx(DescriptionContext.Provider, {
|
|
5474
|
-
value: descriptionContext,
|
|
5475
|
-
children: jsx(TooltipContext.Provider, {
|
|
5476
|
-
value: tooltipContext,
|
|
5477
|
-
children: jsx(LayoutContext.Provider, {
|
|
5478
|
-
value: layoutContext,
|
|
5479
|
-
children: jsx(EventContext.Provider, {
|
|
5480
|
-
value: eventContext,
|
|
5481
|
-
children: jsxs("div", {
|
|
5482
|
-
class: "bio-properties-panel",
|
|
5483
|
-
children: [jsx(Header, {
|
|
5484
|
-
element: element,
|
|
5485
|
-
headerProvider: headerProvider
|
|
5486
|
-
}), jsx("div", {
|
|
5487
|
-
class: "bio-properties-panel-scroll-container",
|
|
5488
|
-
children: groups.map(group => {
|
|
5489
|
-
const {
|
|
5490
|
-
component: Component = Group,
|
|
5491
|
-
id
|
|
5492
|
-
} = group;
|
|
5493
|
-
return createElement(Component, {
|
|
5494
|
-
...group,
|
|
5495
|
-
key: id,
|
|
5496
|
-
element: element
|
|
5497
|
-
});
|
|
5498
|
-
})
|
|
5499
|
-
})]
|
|
5500
|
-
})
|
|
5501
|
-
})
|
|
5502
|
-
})
|
|
5503
|
-
})
|
|
5504
|
-
})
|
|
5505
|
-
})
|
|
5601
|
+
return jsx("span", {
|
|
5602
|
+
class: "bio-properties-panel-feel-indicator",
|
|
5603
|
+
children: "="
|
|
5506
5604
|
});
|
|
5507
5605
|
}
|
|
5606
|
+
const noop$4 = () => {};
|
|
5508
5607
|
|
|
5509
|
-
|
|
5608
|
+
/**
|
|
5609
|
+
* @param {Object} props
|
|
5610
|
+
* @param {Object} props.label
|
|
5611
|
+
* @param {String} props.feel
|
|
5612
|
+
*/
|
|
5613
|
+
function FeelIcon(props) {
|
|
5614
|
+
const {
|
|
5615
|
+
feel = false,
|
|
5616
|
+
active,
|
|
5617
|
+
disabled = false,
|
|
5618
|
+
onClick = noop$4
|
|
5619
|
+
} = props;
|
|
5620
|
+
const feelRequiredLabel = 'FEEL expression is mandatory';
|
|
5621
|
+
const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
|
|
5622
|
+
const handleClick = e => {
|
|
5623
|
+
onClick(e);
|
|
5510
5624
|
|
|
5511
|
-
|
|
5512
|
-
|
|
5513
|
-
|
|
5514
|
-
|
|
5625
|
+
// when pointer event was created from keyboard, keep focus on button
|
|
5626
|
+
if (!e.pointerType) {
|
|
5627
|
+
e.stopPropagation();
|
|
5628
|
+
}
|
|
5515
5629
|
};
|
|
5630
|
+
return jsx("button", {
|
|
5631
|
+
class: classnames('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
|
|
5632
|
+
onClick: handleClick,
|
|
5633
|
+
disabled: feel === 'required' || disabled,
|
|
5634
|
+
title: feel === 'required' ? feelRequiredLabel : feelOptionalLabel,
|
|
5635
|
+
children: jsx(FeelIcon$1, {})
|
|
5636
|
+
});
|
|
5516
5637
|
}
|
|
5517
|
-
|
|
5518
|
-
|
|
5519
|
-
|
|
5520
|
-
|
|
5521
|
-
|
|
5638
|
+
const FeelPopupContext = createContext({
|
|
5639
|
+
open: () => {},
|
|
5640
|
+
close: () => {},
|
|
5641
|
+
source: null
|
|
5642
|
+
});
|
|
5643
|
+
|
|
5644
|
+
/**
|
|
5645
|
+
* Add a dragger that calls back the passed function with
|
|
5646
|
+
* { event, delta } on drag.
|
|
5647
|
+
*
|
|
5648
|
+
* @example
|
|
5649
|
+
*
|
|
5650
|
+
* function dragMove(event, delta) {
|
|
5651
|
+
* // we are dragging (!!)
|
|
5652
|
+
* }
|
|
5653
|
+
*
|
|
5654
|
+
* domElement.addEventListener('dragstart', dragger(dragMove));
|
|
5655
|
+
*
|
|
5656
|
+
* @param {Function} fn
|
|
5657
|
+
* @param {Element} [dragPreview]
|
|
5658
|
+
*
|
|
5659
|
+
* @return {Function} drag start callback function
|
|
5660
|
+
*/
|
|
5661
|
+
function createDragger(fn, dragPreview) {
|
|
5662
|
+
let self;
|
|
5663
|
+
let startX, startY;
|
|
5664
|
+
|
|
5665
|
+
/** drag start */
|
|
5666
|
+
function onDragStart(event) {
|
|
5667
|
+
self = this;
|
|
5668
|
+
startX = event.clientX;
|
|
5669
|
+
startY = event.clientY;
|
|
5670
|
+
|
|
5671
|
+
// (1) prevent preview image
|
|
5672
|
+
if (event.dataTransfer) {
|
|
5673
|
+
event.dataTransfer.setDragImage(dragPreview || emptyCanvas(), 0, 0);
|
|
5674
|
+
}
|
|
5675
|
+
|
|
5676
|
+
// (2) setup drag listeners
|
|
5677
|
+
|
|
5678
|
+
// attach drag + cleanup event
|
|
5679
|
+
document.addEventListener('dragover', onDrag);
|
|
5680
|
+
document.addEventListener('dragend', onEnd);
|
|
5681
|
+
document.addEventListener('drop', preventDefault);
|
|
5682
|
+
}
|
|
5683
|
+
function onDrag(event) {
|
|
5684
|
+
const delta = {
|
|
5685
|
+
x: event.clientX - startX,
|
|
5686
|
+
y: event.clientY - startY
|
|
5687
|
+
};
|
|
5688
|
+
|
|
5689
|
+
// call provided fn with event, delta
|
|
5690
|
+
return fn.call(self, event, delta);
|
|
5691
|
+
}
|
|
5692
|
+
function onEnd() {
|
|
5693
|
+
document.removeEventListener('dragover', onDrag);
|
|
5694
|
+
document.removeEventListener('dragend', onEnd);
|
|
5695
|
+
document.removeEventListener('drop', preventDefault);
|
|
5696
|
+
}
|
|
5697
|
+
return onDragStart;
|
|
5522
5698
|
}
|
|
5523
|
-
function
|
|
5524
|
-
|
|
5525
|
-
|
|
5526
|
-
...overrides
|
|
5527
|
-
};
|
|
5699
|
+
function preventDefault(event) {
|
|
5700
|
+
event.preventDefault();
|
|
5701
|
+
event.stopPropagation();
|
|
5528
5702
|
}
|
|
5529
|
-
|
|
5530
|
-
|
|
5703
|
+
function emptyCanvas() {
|
|
5704
|
+
return domify('<canvas width="0" height="0" />');
|
|
5705
|
+
}
|
|
5706
|
+
const noop$3 = () => {};
|
|
5531
5707
|
|
|
5532
5708
|
/**
|
|
5533
|
-
*
|
|
5709
|
+
* A generic popup component.
|
|
5534
5710
|
*
|
|
5535
|
-
* @param {
|
|
5536
|
-
* @param {
|
|
5711
|
+
* @param {Object} props
|
|
5712
|
+
* @param {HTMLElement} [props.container]
|
|
5713
|
+
* @param {string} [props.className]
|
|
5714
|
+
* @param {{x: number, y: number}} [props.position]
|
|
5715
|
+
* @param {number} [props.width]
|
|
5716
|
+
* @param {number} [props.height]
|
|
5717
|
+
* @param {Function} props.onClose
|
|
5718
|
+
* @param {Function} [props.onPostActivate]
|
|
5719
|
+
* @param {Function} [props.onPostDeactivate]
|
|
5720
|
+
* @param {boolean} [props.returnFocus]
|
|
5721
|
+
* @param {string} props.title
|
|
5537
5722
|
*/
|
|
5538
|
-
function
|
|
5539
|
-
const
|
|
5540
|
-
|
|
5541
|
-
|
|
5542
|
-
|
|
5543
|
-
|
|
5544
|
-
|
|
5723
|
+
function Popup(props) {
|
|
5724
|
+
const {
|
|
5725
|
+
container,
|
|
5726
|
+
className,
|
|
5727
|
+
position,
|
|
5728
|
+
width,
|
|
5729
|
+
height,
|
|
5730
|
+
onClose,
|
|
5731
|
+
onPostActivate = noop$3,
|
|
5732
|
+
onPostDeactivate = noop$3,
|
|
5733
|
+
returnFocus = true,
|
|
5734
|
+
title
|
|
5735
|
+
} = props;
|
|
5736
|
+
const focusTrapRef = useRef$1(null);
|
|
5737
|
+
const popupRef = useRef$1(null);
|
|
5738
|
+
const handleKeyPress = event => {
|
|
5739
|
+
if (event.key === 'Escape') {
|
|
5740
|
+
onClose();
|
|
5545
5741
|
}
|
|
5546
|
-
}
|
|
5742
|
+
};
|
|
5743
|
+
|
|
5744
|
+
// re-activate focus trap on focus
|
|
5745
|
+
const handleFocus = () => {
|
|
5746
|
+
if (focusTrapRef.current) {
|
|
5747
|
+
focusTrapRef.current.activate();
|
|
5748
|
+
}
|
|
5749
|
+
};
|
|
5750
|
+
let style = {};
|
|
5751
|
+
if (position) {
|
|
5752
|
+
style = {
|
|
5753
|
+
...style,
|
|
5754
|
+
top: position.top + 'px',
|
|
5755
|
+
left: position.left + 'px'
|
|
5756
|
+
};
|
|
5757
|
+
}
|
|
5758
|
+
if (width) {
|
|
5759
|
+
style.width = width + 'px';
|
|
5760
|
+
}
|
|
5761
|
+
if (height) {
|
|
5762
|
+
style.height = height + 'px';
|
|
5763
|
+
}
|
|
5764
|
+
useEffect(() => {
|
|
5765
|
+
if (popupRef.current) {
|
|
5766
|
+
popupRef.current.addEventListener('keydown', handleKeyPress);
|
|
5767
|
+
}
|
|
5768
|
+
return () => {
|
|
5769
|
+
popupRef.current.removeEventListener('keydown', handleKeyPress);
|
|
5770
|
+
};
|
|
5771
|
+
}, [popupRef]);
|
|
5772
|
+
useEffect(() => {
|
|
5773
|
+
if (popupRef.current) {
|
|
5774
|
+
popupRef.current.addEventListener('focusin', handleFocus);
|
|
5775
|
+
}
|
|
5776
|
+
return () => {
|
|
5777
|
+
popupRef.current.removeEventListener('focusin', handleFocus);
|
|
5778
|
+
};
|
|
5779
|
+
}, [popupRef]);
|
|
5780
|
+
useEffect(() => {
|
|
5781
|
+
if (popupRef.current) {
|
|
5782
|
+
focusTrapRef.current = focusTrap.createFocusTrap(popupRef.current, {
|
|
5783
|
+
clickOutsideDeactivates: true,
|
|
5784
|
+
fallbackFocus: popupRef.current,
|
|
5785
|
+
onPostActivate,
|
|
5786
|
+
onPostDeactivate,
|
|
5787
|
+
returnFocusOnDeactivate: returnFocus
|
|
5788
|
+
});
|
|
5789
|
+
focusTrapRef.current.activate();
|
|
5790
|
+
}
|
|
5791
|
+
return () => focusTrapRef.current && focusTrapRef.current.deactivate();
|
|
5792
|
+
}, [popupRef]);
|
|
5793
|
+
return createPortal(jsx("div", {
|
|
5794
|
+
"aria-label": title,
|
|
5795
|
+
tabIndex: -1,
|
|
5796
|
+
ref: popupRef,
|
|
5797
|
+
role: "dialog",
|
|
5798
|
+
class: classnames('bio-properties-panel-popup', className),
|
|
5799
|
+
style: style,
|
|
5800
|
+
children: props.children
|
|
5801
|
+
}), container || document.body);
|
|
5547
5802
|
}
|
|
5548
|
-
|
|
5803
|
+
Popup.Title = Title;
|
|
5804
|
+
Popup.Body = Body;
|
|
5805
|
+
Popup.Footer = Footer;
|
|
5806
|
+
function Title(props) {
|
|
5549
5807
|
const {
|
|
5550
|
-
|
|
5551
|
-
|
|
5552
|
-
|
|
5553
|
-
|
|
5554
|
-
|
|
5555
|
-
remove
|
|
5808
|
+
children,
|
|
5809
|
+
className,
|
|
5810
|
+
draggable,
|
|
5811
|
+
title,
|
|
5812
|
+
...rest
|
|
5556
5813
|
} = props;
|
|
5557
|
-
const [open, setOpen] = useState(shouldOpen);
|
|
5558
|
-
const toggleOpen = () => setOpen(!open);
|
|
5559
|
-
const {
|
|
5560
|
-
onShow
|
|
5561
|
-
} = useContext(LayoutContext);
|
|
5562
|
-
const propertiesPanelContext = {
|
|
5563
|
-
...useContext(LayoutContext),
|
|
5564
|
-
onShow: useCallback(() => {
|
|
5565
|
-
setOpen(true);
|
|
5566
|
-
if (isFunction(onShow)) {
|
|
5567
|
-
onShow();
|
|
5568
|
-
}
|
|
5569
|
-
}, [onShow, setOpen])
|
|
5570
|
-
};
|
|
5571
5814
|
|
|
5572
|
-
//
|
|
5573
|
-
|
|
5815
|
+
// we can't use state as we need to
|
|
5816
|
+
// manipulate this inside dragging events
|
|
5817
|
+
const context = useRef$1({
|
|
5818
|
+
startPosition: null,
|
|
5819
|
+
newPosition: null
|
|
5820
|
+
});
|
|
5821
|
+
const dragPreviewRef = useRef$1();
|
|
5822
|
+
const titleRef = useRef$1();
|
|
5823
|
+
const onMove = throttle$1((_, delta) => {
|
|
5824
|
+
const {
|
|
5825
|
+
x: dx,
|
|
5826
|
+
y: dy
|
|
5827
|
+
} = delta;
|
|
5828
|
+
const newPosition = {
|
|
5829
|
+
x: context.current.startPosition.x + dx,
|
|
5830
|
+
y: context.current.startPosition.y + dy
|
|
5831
|
+
};
|
|
5832
|
+
const popupParent = getPopupParent(titleRef.current);
|
|
5833
|
+
popupParent.style.top = newPosition.y + 'px';
|
|
5834
|
+
popupParent.style.left = newPosition.x + 'px';
|
|
5835
|
+
});
|
|
5836
|
+
const onMoveStart = event => {
|
|
5837
|
+
// initialize drag handler
|
|
5838
|
+
const onDragStart = createDragger(onMove, dragPreviewRef.current);
|
|
5839
|
+
onDragStart(event);
|
|
5840
|
+
const popupParent = getPopupParent(titleRef.current);
|
|
5841
|
+
const bounds = popupParent.getBoundingClientRect();
|
|
5842
|
+
context.current.startPosition = {
|
|
5843
|
+
x: bounds.left,
|
|
5844
|
+
y: bounds.top
|
|
5845
|
+
};
|
|
5846
|
+
};
|
|
5847
|
+
const onMoveEnd = () => {
|
|
5848
|
+
context.current.newPosition = null;
|
|
5849
|
+
};
|
|
5574
5850
|
return jsxs("div", {
|
|
5575
|
-
|
|
5576
|
-
|
|
5577
|
-
|
|
5578
|
-
|
|
5579
|
-
|
|
5851
|
+
class: classnames('bio-properties-panel-popup__header', draggable && 'draggable', className),
|
|
5852
|
+
ref: titleRef,
|
|
5853
|
+
draggable: draggable,
|
|
5854
|
+
onDragStart: onMoveStart,
|
|
5855
|
+
onDragEnd: onMoveEnd,
|
|
5856
|
+
...rest,
|
|
5857
|
+
children: [draggable && jsxs(Fragment$1, {
|
|
5580
5858
|
children: [jsx("div", {
|
|
5581
|
-
|
|
5582
|
-
class:
|
|
5583
|
-
|
|
5584
|
-
|
|
5585
|
-
|
|
5586
|
-
|
|
5587
|
-
children: jsx(ArrowIcon, {
|
|
5588
|
-
class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
|
|
5589
|
-
})
|
|
5590
|
-
}), remove ? jsx("button", {
|
|
5591
|
-
title: "Delete item",
|
|
5592
|
-
class: "bio-properties-panel-remove-entry",
|
|
5593
|
-
onClick: remove,
|
|
5594
|
-
children: jsx(DeleteIcon, {})
|
|
5595
|
-
}) : null]
|
|
5859
|
+
ref: dragPreviewRef,
|
|
5860
|
+
class: "bio-properties-panel-popup__drag-preview"
|
|
5861
|
+
}), jsx("div", {
|
|
5862
|
+
class: "bio-properties-panel-popup__drag-handle",
|
|
5863
|
+
children: jsx(DragIcon, {})
|
|
5864
|
+
})]
|
|
5596
5865
|
}), jsx("div", {
|
|
5597
|
-
class:
|
|
5598
|
-
children:
|
|
5599
|
-
|
|
5600
|
-
children: entries.map(entry => {
|
|
5601
|
-
const {
|
|
5602
|
-
component: Component,
|
|
5603
|
-
id
|
|
5604
|
-
} = entry;
|
|
5605
|
-
return createElement(Component, {
|
|
5606
|
-
...entry,
|
|
5607
|
-
element: element,
|
|
5608
|
-
key: id
|
|
5609
|
-
});
|
|
5610
|
-
})
|
|
5611
|
-
})
|
|
5612
|
-
})]
|
|
5866
|
+
class: "bio-properties-panel-popup__title",
|
|
5867
|
+
children: title
|
|
5868
|
+
}), children]
|
|
5613
5869
|
});
|
|
5614
5870
|
}
|
|
5615
|
-
function
|
|
5871
|
+
function Body(props) {
|
|
5616
5872
|
const {
|
|
5617
|
-
|
|
5618
|
-
|
|
5873
|
+
children,
|
|
5874
|
+
className,
|
|
5875
|
+
...rest
|
|
5619
5876
|
} = props;
|
|
5620
|
-
|
|
5621
|
-
// focus specified entry on auto open
|
|
5622
|
-
useEffect(() => {
|
|
5623
|
-
if (autoOpen && autoFocusEntry) {
|
|
5624
|
-
const entry = query(`[data-entry-id="${autoFocusEntry}"]`);
|
|
5625
|
-
const focusableInput = query('.bio-properties-panel-input', entry);
|
|
5626
|
-
if (focusableInput) {
|
|
5627
|
-
if (isFunction(focusableInput.select)) {
|
|
5628
|
-
focusableInput.select();
|
|
5629
|
-
} else if (isFunction(focusableInput.focus)) {
|
|
5630
|
-
focusableInput.focus();
|
|
5631
|
-
}
|
|
5632
|
-
}
|
|
5633
|
-
}
|
|
5634
|
-
}, [autoOpen, autoFocusEntry]);
|
|
5635
5877
|
return jsx("div", {
|
|
5636
|
-
class:
|
|
5637
|
-
|
|
5638
|
-
|
|
5639
|
-
open: autoOpen
|
|
5640
|
-
})
|
|
5878
|
+
class: classnames('bio-properties-panel-popup__body', className),
|
|
5879
|
+
...rest,
|
|
5880
|
+
children: children
|
|
5641
5881
|
});
|
|
5642
5882
|
}
|
|
5643
|
-
|
|
5883
|
+
function Footer(props) {
|
|
5884
|
+
const {
|
|
5885
|
+
children,
|
|
5886
|
+
className,
|
|
5887
|
+
...rest
|
|
5888
|
+
} = props;
|
|
5889
|
+
return jsx("div", {
|
|
5890
|
+
class: classnames('bio-properties-panel-popup__footer', className),
|
|
5891
|
+
...rest,
|
|
5892
|
+
children: props.children
|
|
5893
|
+
});
|
|
5894
|
+
}
|
|
5895
|
+
|
|
5896
|
+
// helpers //////////////////////
|
|
5897
|
+
|
|
5898
|
+
function getPopupParent(node) {
|
|
5899
|
+
return node.closest('.bio-properties-panel-popup');
|
|
5900
|
+
}
|
|
5901
|
+
const FEEL_POPUP_WIDTH = 700;
|
|
5902
|
+
const FEEL_POPUP_HEIGHT = 250;
|
|
5644
5903
|
|
|
5645
5904
|
/**
|
|
5646
|
-
*
|
|
5905
|
+
* FEEL popup component, built as a singleton.
|
|
5647
5906
|
*/
|
|
5648
|
-
function
|
|
5907
|
+
function FEELPopupRoot(props) {
|
|
5649
5908
|
const {
|
|
5650
|
-
|
|
5651
|
-
element,
|
|
5652
|
-
id,
|
|
5653
|
-
items,
|
|
5654
|
-
label,
|
|
5655
|
-
shouldOpen = true,
|
|
5656
|
-
shouldSort = true
|
|
5909
|
+
element
|
|
5657
5910
|
} = props;
|
|
5658
|
-
const groupRef = useRef$1(null);
|
|
5659
|
-
const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
|
|
5660
|
-
const [sticky, setSticky] = useState(false);
|
|
5661
|
-
const onShow = useCallback(() => setOpen(true), [setOpen]);
|
|
5662
|
-
const [ordering, setOrdering] = useState([]);
|
|
5663
|
-
const [newItemAdded, setNewItemAdded] = useState(false);
|
|
5664
|
-
|
|
5665
|
-
// Flag to mark that add button was clicked in the last render cycle
|
|
5666
|
-
const [addTriggered, setAddTriggered] = useState(false);
|
|
5667
|
-
const prevItems = usePrevious(items);
|
|
5668
5911
|
const prevElement = usePrevious(element);
|
|
5669
|
-
const
|
|
5670
|
-
const
|
|
5671
|
-
|
|
5672
|
-
|
|
5673
|
-
|
|
5674
|
-
|
|
5675
|
-
|
|
5676
|
-
|
|
5677
|
-
|
|
5678
|
-
|
|
5679
|
-
|
|
5680
|
-
|
|
5681
|
-
|
|
5682
|
-
|
|
5683
|
-
|
|
5684
|
-
|
|
5685
|
-
|
|
5686
|
-
|
|
5912
|
+
const [popupConfig, setPopupConfig] = useState({});
|
|
5913
|
+
const [open, setOpen] = useState(false);
|
|
5914
|
+
const [source, setSource] = useState(null);
|
|
5915
|
+
const [sourceElement, setSourceElement] = useState(null);
|
|
5916
|
+
const handleOpen = (key, config, _sourceElement) => {
|
|
5917
|
+
setSource(key);
|
|
5918
|
+
setPopupConfig(config);
|
|
5919
|
+
setOpen(true);
|
|
5920
|
+
setSourceElement(_sourceElement);
|
|
5921
|
+
};
|
|
5922
|
+
const handleClose = () => {
|
|
5923
|
+
setOpen(false);
|
|
5924
|
+
setSource(null);
|
|
5925
|
+
};
|
|
5926
|
+
const feelPopupContext = {
|
|
5927
|
+
open: handleOpen,
|
|
5928
|
+
close: handleClose,
|
|
5929
|
+
source
|
|
5930
|
+
};
|
|
5931
|
+
|
|
5932
|
+
// close popup on element change, cf. https://github.com/bpmn-io/properties-panel/issues/270
|
|
5687
5933
|
useEffect(() => {
|
|
5688
|
-
|
|
5689
|
-
|
|
5690
|
-
if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
|
|
5691
|
-
let add = [];
|
|
5692
|
-
items.forEach(item => {
|
|
5693
|
-
if (!ordering.includes(item.id)) {
|
|
5694
|
-
add.push(item.id);
|
|
5695
|
-
}
|
|
5696
|
-
});
|
|
5697
|
-
let newOrdering = ordering;
|
|
5698
|
-
|
|
5699
|
-
// open if not open, configured and triggered by add button
|
|
5700
|
-
//
|
|
5701
|
-
// TODO(marstamm): remove once we refactor layout handling for listGroups.
|
|
5702
|
-
// Ideally, opening should be handled as part of the `add` callback and
|
|
5703
|
-
// not be a concern for the ListGroup component.
|
|
5704
|
-
if (addTriggered && !open && shouldOpen) {
|
|
5705
|
-
toggleOpen();
|
|
5706
|
-
}
|
|
5707
|
-
|
|
5708
|
-
// filter when not open and configured
|
|
5709
|
-
if (!open && shouldSort) {
|
|
5710
|
-
newOrdering = createOrdering(sortItems(items));
|
|
5711
|
-
}
|
|
5712
|
-
|
|
5713
|
-
// add new items on top or bottom depending on sorting behavior
|
|
5714
|
-
newOrdering = newOrdering.filter(item => !add.includes(item));
|
|
5715
|
-
if (shouldSort) {
|
|
5716
|
-
newOrdering.unshift(...add);
|
|
5717
|
-
} else {
|
|
5718
|
-
newOrdering.push(...add);
|
|
5719
|
-
}
|
|
5720
|
-
setOrdering(newOrdering);
|
|
5721
|
-
setNewItemAdded(addTriggered);
|
|
5722
|
-
} else {
|
|
5723
|
-
setNewItemAdded(false);
|
|
5934
|
+
if (element && element !== prevElement) {
|
|
5935
|
+
handleClose();
|
|
5724
5936
|
}
|
|
5725
|
-
}, [
|
|
5726
|
-
|
|
5727
|
-
|
|
5937
|
+
}, [element]);
|
|
5938
|
+
return jsxs(FeelPopupContext.Provider, {
|
|
5939
|
+
value: feelPopupContext,
|
|
5940
|
+
children: [open && jsx(FeelPopupComponent, {
|
|
5941
|
+
onClose: handleClose,
|
|
5942
|
+
sourceElement: sourceElement,
|
|
5943
|
+
...popupConfig
|
|
5944
|
+
}), props.children]
|
|
5945
|
+
});
|
|
5946
|
+
}
|
|
5947
|
+
function FeelPopupComponent(props) {
|
|
5948
|
+
const {
|
|
5949
|
+
id,
|
|
5950
|
+
hostLanguage,
|
|
5951
|
+
onInput,
|
|
5952
|
+
onClose,
|
|
5953
|
+
position,
|
|
5954
|
+
singleLine,
|
|
5955
|
+
sourceElement,
|
|
5956
|
+
title,
|
|
5957
|
+
tooltipContainer,
|
|
5958
|
+
type,
|
|
5959
|
+
value,
|
|
5960
|
+
variables
|
|
5961
|
+
} = props;
|
|
5962
|
+
const editorRef = useRef$1();
|
|
5963
|
+
const handleSetReturnFocus = () => {
|
|
5964
|
+
sourceElement && sourceElement.focus();
|
|
5965
|
+
};
|
|
5728
5966
|
useEffect(() => {
|
|
5729
|
-
|
|
5730
|
-
|
|
5731
|
-
|
|
5732
|
-
|
|
5967
|
+
const editor = editorRef.current;
|
|
5968
|
+
if (editor) {
|
|
5969
|
+
editor.focus();
|
|
5970
|
+
}
|
|
5971
|
+
}, [editorRef, id]);
|
|
5972
|
+
return jsxs(Popup, {
|
|
5973
|
+
className: "bio-properties-panel-feel-popup",
|
|
5974
|
+
position: position,
|
|
5975
|
+
title: title,
|
|
5976
|
+
onClose: onClose
|
|
5977
|
+
|
|
5978
|
+
// handle focus manually on deactivate
|
|
5979
|
+
,
|
|
5980
|
+
|
|
5981
|
+
returnFocus: false,
|
|
5982
|
+
onPostDeactivate: handleSetReturnFocus,
|
|
5983
|
+
height: FEEL_POPUP_HEIGHT,
|
|
5984
|
+
width: FEEL_POPUP_WIDTH,
|
|
5985
|
+
children: [jsx(Popup.Title, {
|
|
5986
|
+
title: title,
|
|
5987
|
+
draggable: true
|
|
5988
|
+
}), jsx(Popup.Body, {
|
|
5989
|
+
children: jsxs("div", {
|
|
5990
|
+
class: "bio-properties-panel-feel-popup__body",
|
|
5991
|
+
children: [type === 'feel' && jsx(CodeEditor, {
|
|
5992
|
+
enableGutters: true,
|
|
5993
|
+
id: prefixId$8(id),
|
|
5994
|
+
name: id,
|
|
5995
|
+
onInput: onInput,
|
|
5996
|
+
value: value,
|
|
5997
|
+
variables: variables,
|
|
5998
|
+
ref: editorRef,
|
|
5999
|
+
tooltipContainer: tooltipContainer
|
|
6000
|
+
}), type === 'feelers' && jsx(CodeEditor$1, {
|
|
6001
|
+
id: prefixId$8(id),
|
|
6002
|
+
contentAttributes: {
|
|
6003
|
+
'aria-label': title
|
|
6004
|
+
},
|
|
6005
|
+
enableGutters: true,
|
|
6006
|
+
hostLanguage: hostLanguage,
|
|
6007
|
+
name: id,
|
|
6008
|
+
onInput: onInput,
|
|
6009
|
+
value: value,
|
|
6010
|
+
ref: editorRef,
|
|
6011
|
+
singleLine: singleLine,
|
|
6012
|
+
tooltipContainer: tooltipContainer
|
|
6013
|
+
})]
|
|
6014
|
+
})
|
|
6015
|
+
}), jsx(Popup.Footer, {
|
|
6016
|
+
children: jsx("button", {
|
|
6017
|
+
onClick: onClose,
|
|
6018
|
+
title: "Close pop-up editor",
|
|
6019
|
+
class: "bio-properties-panel-feel-popup__close-btn",
|
|
6020
|
+
children: "Close"
|
|
6021
|
+
})
|
|
6022
|
+
})]
|
|
6023
|
+
});
|
|
6024
|
+
}
|
|
5733
6025
|
|
|
5734
|
-
|
|
5735
|
-
useEffect(() => {
|
|
5736
|
-
if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
|
|
5737
|
-
let keep = [];
|
|
5738
|
-
ordering.forEach(o => {
|
|
5739
|
-
if (getItem(items, o)) {
|
|
5740
|
-
keep.push(o);
|
|
5741
|
-
}
|
|
5742
|
-
});
|
|
5743
|
-
setOrdering(keep);
|
|
5744
|
-
}
|
|
5745
|
-
}, [items, shouldHandleEffects]);
|
|
6026
|
+
// helpers /////////////////
|
|
5746
6027
|
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
5751
|
-
const
|
|
5752
|
-
|
|
5753
|
-
|
|
6028
|
+
function prefixId$8(id) {
|
|
6029
|
+
return `bio-properties-panel-${id}`;
|
|
6030
|
+
}
|
|
6031
|
+
function ToggleSwitch(props) {
|
|
6032
|
+
const {
|
|
6033
|
+
id,
|
|
6034
|
+
label,
|
|
6035
|
+
onInput,
|
|
6036
|
+
value,
|
|
6037
|
+
switcherLabel,
|
|
6038
|
+
inline,
|
|
6039
|
+
onFocus,
|
|
6040
|
+
onBlur,
|
|
6041
|
+
inputRef,
|
|
6042
|
+
tooltip
|
|
6043
|
+
} = props;
|
|
6044
|
+
const [localValue, setLocalValue] = useState(value);
|
|
6045
|
+
const handleInputCallback = async () => {
|
|
6046
|
+
onInput(!value);
|
|
5754
6047
|
};
|
|
5755
|
-
const
|
|
5756
|
-
|
|
5757
|
-
|
|
6048
|
+
const handleInput = e => {
|
|
6049
|
+
handleInputCallback();
|
|
6050
|
+
setLocalValue(e.target.value);
|
|
5758
6051
|
};
|
|
5759
|
-
|
|
5760
|
-
|
|
5761
|
-
if (allErrors[item.id]) {
|
|
5762
|
-
return true;
|
|
5763
|
-
}
|
|
5764
|
-
if (!item.entries) {
|
|
6052
|
+
useEffect(() => {
|
|
6053
|
+
if (value === localValue) {
|
|
5765
6054
|
return;
|
|
5766
6055
|
}
|
|
5767
|
-
|
|
5768
|
-
|
|
5769
|
-
return item.entries.some(entry => allErrors[entry.id]);
|
|
5770
|
-
});
|
|
6056
|
+
setLocalValue(value);
|
|
6057
|
+
}, [value]);
|
|
5771
6058
|
return jsxs("div", {
|
|
5772
|
-
class:
|
|
5773
|
-
|
|
5774
|
-
|
|
5775
|
-
children: [
|
|
5776
|
-
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
5777
|
-
onClick: hasItems ? toggleOpen : noop$3,
|
|
5778
|
-
children: [jsx("div", {
|
|
5779
|
-
title: label,
|
|
5780
|
-
class: "bio-properties-panel-group-header-title",
|
|
5781
|
-
children: jsx(TooltipWrapper, {
|
|
5782
|
-
value: props.tooltip,
|
|
5783
|
-
forId: 'group-' + id,
|
|
5784
|
-
element: element,
|
|
5785
|
-
parent: groupRef,
|
|
5786
|
-
children: label
|
|
5787
|
-
})
|
|
5788
|
-
}), jsxs("div", {
|
|
5789
|
-
class: "bio-properties-panel-group-header-buttons",
|
|
5790
|
-
children: [add ? jsxs("button", {
|
|
5791
|
-
title: "Create new list item",
|
|
5792
|
-
class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
|
|
5793
|
-
onClick: handleAddClick,
|
|
5794
|
-
children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
|
|
5795
|
-
class: "bio-properties-panel-add-entry-label",
|
|
5796
|
-
children: "Create"
|
|
5797
|
-
}) : null]
|
|
5798
|
-
}) : null, hasItems ? jsx("div", {
|
|
5799
|
-
title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
|
|
5800
|
-
class: classnames('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
|
|
5801
|
-
children: items.length
|
|
5802
|
-
}) : null, hasItems ? jsx("button", {
|
|
5803
|
-
title: "Toggle section",
|
|
5804
|
-
class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
|
|
5805
|
-
children: jsx(ArrowIcon, {
|
|
5806
|
-
class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
|
|
5807
|
-
})
|
|
5808
|
-
}) : null]
|
|
5809
|
-
})]
|
|
5810
|
-
}), jsx("div", {
|
|
5811
|
-
class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
|
|
5812
|
-
children: jsx(LayoutContext.Provider, {
|
|
5813
|
-
value: propertiesPanelContext,
|
|
5814
|
-
children: ordering.map((o, index) => {
|
|
5815
|
-
const item = getItem(items, o);
|
|
5816
|
-
if (!item) {
|
|
5817
|
-
return;
|
|
5818
|
-
}
|
|
5819
|
-
const {
|
|
5820
|
-
id
|
|
5821
|
-
} = item;
|
|
5822
|
-
|
|
5823
|
-
// if item was added, open it
|
|
5824
|
-
// Existing items will not be affected as autoOpen is only applied on first render
|
|
5825
|
-
const autoOpen = newItemAdded;
|
|
5826
|
-
return createElement(ListItem, {
|
|
5827
|
-
...item,
|
|
5828
|
-
autoOpen: autoOpen,
|
|
5829
|
-
element: element,
|
|
5830
|
-
index: index,
|
|
5831
|
-
key: id
|
|
5832
|
-
});
|
|
5833
|
-
})
|
|
5834
|
-
})
|
|
5835
|
-
})]
|
|
5836
|
-
});
|
|
5837
|
-
}
|
|
5838
|
-
|
|
5839
|
-
// helpers ////////////////////
|
|
5840
|
-
|
|
5841
|
-
/**
|
|
5842
|
-
* Sorts given items alphanumeric by label
|
|
5843
|
-
*/
|
|
5844
|
-
function sortItems(items) {
|
|
5845
|
-
return sortBy(items, i => i.label.toLowerCase());
|
|
5846
|
-
}
|
|
5847
|
-
function getItem(items, id) {
|
|
5848
|
-
return find(items, i => i.id === id);
|
|
5849
|
-
}
|
|
5850
|
-
function createOrdering(items) {
|
|
5851
|
-
return items.map(i => i.id);
|
|
5852
|
-
}
|
|
5853
|
-
function Description$1(props) {
|
|
5854
|
-
const {
|
|
5855
|
-
element,
|
|
5856
|
-
forId,
|
|
5857
|
-
value
|
|
5858
|
-
} = props;
|
|
5859
|
-
const contextDescription = useDescriptionContext(forId, element);
|
|
5860
|
-
const description = value || contextDescription;
|
|
5861
|
-
if (description) {
|
|
5862
|
-
return jsx("div", {
|
|
5863
|
-
class: "bio-properties-panel-description",
|
|
5864
|
-
children: description
|
|
5865
|
-
});
|
|
5866
|
-
}
|
|
5867
|
-
}
|
|
5868
|
-
function Checkbox(props) {
|
|
5869
|
-
const {
|
|
5870
|
-
id,
|
|
5871
|
-
label,
|
|
5872
|
-
onChange,
|
|
5873
|
-
disabled,
|
|
5874
|
-
value = false,
|
|
5875
|
-
onFocus,
|
|
5876
|
-
onBlur,
|
|
5877
|
-
tooltip
|
|
5878
|
-
} = props;
|
|
5879
|
-
const [localValue, setLocalValue] = useState(value);
|
|
5880
|
-
const handleChangeCallback = ({
|
|
5881
|
-
target
|
|
5882
|
-
}) => {
|
|
5883
|
-
onChange(target.checked);
|
|
5884
|
-
};
|
|
5885
|
-
const handleChange = e => {
|
|
5886
|
-
handleChangeCallback(e);
|
|
5887
|
-
setLocalValue(e.target.value);
|
|
5888
|
-
};
|
|
5889
|
-
useEffect(() => {
|
|
5890
|
-
if (value === localValue) {
|
|
5891
|
-
return;
|
|
5892
|
-
}
|
|
5893
|
-
setLocalValue(value);
|
|
5894
|
-
}, [value]);
|
|
5895
|
-
const ref = useShowEntryEvent(id);
|
|
5896
|
-
return jsxs("div", {
|
|
5897
|
-
class: "bio-properties-panel-checkbox",
|
|
5898
|
-
children: [jsx("input", {
|
|
5899
|
-
ref: ref,
|
|
5900
|
-
id: prefixId$7(id),
|
|
5901
|
-
name: id,
|
|
5902
|
-
onFocus: onFocus,
|
|
5903
|
-
onBlur: onBlur,
|
|
5904
|
-
type: "checkbox",
|
|
5905
|
-
class: "bio-properties-panel-input",
|
|
5906
|
-
onChange: handleChange,
|
|
5907
|
-
checked: localValue,
|
|
5908
|
-
disabled: disabled
|
|
5909
|
-
}), jsx("label", {
|
|
5910
|
-
for: prefixId$7(id),
|
|
6059
|
+
class: classnames('bio-properties-panel-toggle-switch', {
|
|
6060
|
+
inline
|
|
6061
|
+
}),
|
|
6062
|
+
children: [jsx("label", {
|
|
5911
6063
|
class: "bio-properties-panel-label",
|
|
6064
|
+
for: prefixId$7(id),
|
|
5912
6065
|
children: jsx(TooltipWrapper, {
|
|
5913
6066
|
value: tooltip,
|
|
5914
6067
|
forId: id,
|
|
5915
6068
|
element: props.element,
|
|
5916
6069
|
children: label
|
|
5917
6070
|
})
|
|
6071
|
+
}), jsxs("div", {
|
|
6072
|
+
class: "bio-properties-panel-field-wrapper",
|
|
6073
|
+
children: [jsxs("label", {
|
|
6074
|
+
class: "bio-properties-panel-toggle-switch__switcher",
|
|
6075
|
+
children: [jsx("input", {
|
|
6076
|
+
ref: inputRef,
|
|
6077
|
+
id: prefixId$7(id),
|
|
6078
|
+
class: "bio-properties-panel-input",
|
|
6079
|
+
type: "checkbox",
|
|
6080
|
+
onFocus: onFocus,
|
|
6081
|
+
onBlur: onBlur,
|
|
6082
|
+
name: id,
|
|
6083
|
+
onInput: handleInput,
|
|
6084
|
+
checked: !!localValue
|
|
6085
|
+
}), jsx("span", {
|
|
6086
|
+
class: "bio-properties-panel-toggle-switch__slider"
|
|
6087
|
+
})]
|
|
6088
|
+
}), switcherLabel && jsx("p", {
|
|
6089
|
+
class: "bio-properties-panel-toggle-switch__label",
|
|
6090
|
+
children: switcherLabel
|
|
6091
|
+
})]
|
|
5918
6092
|
})]
|
|
5919
6093
|
});
|
|
5920
6094
|
}
|
|
@@ -5925,44 +6099,43 @@ function Checkbox(props) {
|
|
|
5925
6099
|
* @param {String} props.id
|
|
5926
6100
|
* @param {String} props.description
|
|
5927
6101
|
* @param {String} props.label
|
|
6102
|
+
* @param {String} props.switcherLabel
|
|
6103
|
+
* @param {Boolean} props.inline
|
|
5928
6104
|
* @param {Function} props.getValue
|
|
5929
6105
|
* @param {Function} props.setValue
|
|
5930
6106
|
* @param {Function} props.onFocus
|
|
5931
6107
|
* @param {Function} props.onBlur
|
|
5932
6108
|
* @param {string|import('preact').Component} props.tooltip
|
|
5933
|
-
* @param {boolean} [props.disabled]
|
|
5934
6109
|
*/
|
|
5935
|
-
function
|
|
6110
|
+
function ToggleSwitchEntry(props) {
|
|
5936
6111
|
const {
|
|
5937
6112
|
element,
|
|
5938
6113
|
id,
|
|
5939
6114
|
description,
|
|
5940
6115
|
label,
|
|
6116
|
+
switcherLabel,
|
|
6117
|
+
inline,
|
|
5941
6118
|
getValue,
|
|
5942
6119
|
setValue,
|
|
5943
|
-
disabled,
|
|
5944
6120
|
onFocus,
|
|
5945
6121
|
onBlur,
|
|
5946
6122
|
tooltip
|
|
5947
6123
|
} = props;
|
|
5948
6124
|
const value = getValue(element);
|
|
5949
|
-
const error = useError(id);
|
|
5950
6125
|
return jsxs("div", {
|
|
5951
|
-
class: "bio-properties-panel-entry bio-properties-panel-
|
|
6126
|
+
class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
|
|
5952
6127
|
"data-entry-id": id,
|
|
5953
|
-
children: [jsx(
|
|
5954
|
-
disabled: disabled,
|
|
6128
|
+
children: [jsx(ToggleSwitch, {
|
|
5955
6129
|
id: id,
|
|
5956
6130
|
label: label,
|
|
5957
|
-
|
|
6131
|
+
value: value,
|
|
6132
|
+
onInput: setValue,
|
|
5958
6133
|
onFocus: onFocus,
|
|
5959
6134
|
onBlur: onBlur,
|
|
5960
|
-
|
|
6135
|
+
switcherLabel: switcherLabel,
|
|
6136
|
+
inline: inline,
|
|
5961
6137
|
tooltip: tooltip,
|
|
5962
6138
|
element: element
|
|
5963
|
-
}, element), error && jsx("div", {
|
|
5964
|
-
class: "bio-properties-panel-error",
|
|
5965
|
-
children: error
|
|
5966
6139
|
}), jsx(Description$1, {
|
|
5967
6140
|
forId: id,
|
|
5968
6141
|
element: element,
|
|
@@ -5979,254 +6152,38 @@ function isEdited$8(node) {
|
|
|
5979
6152
|
function prefixId$7(id) {
|
|
5980
6153
|
return `bio-properties-panel-${id}`;
|
|
5981
6154
|
}
|
|
5982
|
-
|
|
5983
|
-
const [buffer, setBuffer] = useState(undefined);
|
|
5984
|
-
ref.current = useMemo(() => ({
|
|
5985
|
-
focus: offset => {
|
|
5986
|
-
if (editor) {
|
|
5987
|
-
editor.focus(offset);
|
|
5988
|
-
} else {
|
|
5989
|
-
if (typeof offset === 'undefined') {
|
|
5990
|
-
offset = Infinity;
|
|
5991
|
-
}
|
|
5992
|
-
setBuffer(offset);
|
|
5993
|
-
}
|
|
5994
|
-
}
|
|
5995
|
-
}), [editor]);
|
|
5996
|
-
useEffect(() => {
|
|
5997
|
-
if (typeof buffer !== 'undefined' && editor) {
|
|
5998
|
-
editor.focus(buffer);
|
|
5999
|
-
setBuffer(false);
|
|
6000
|
-
}
|
|
6001
|
-
}, [editor, buffer]);
|
|
6002
|
-
};
|
|
6003
|
-
const CodeEditor$1 = forwardRef((props, ref) => {
|
|
6155
|
+
function NumberField(props) {
|
|
6004
6156
|
const {
|
|
6005
|
-
|
|
6157
|
+
debounce,
|
|
6006
6158
|
disabled,
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6159
|
+
displayLabel = true,
|
|
6160
|
+
id,
|
|
6161
|
+
inputRef,
|
|
6162
|
+
label,
|
|
6163
|
+
max,
|
|
6164
|
+
min,
|
|
6165
|
+
onInput,
|
|
6166
|
+
step,
|
|
6167
|
+
value = '',
|
|
6168
|
+
onFocus,
|
|
6169
|
+
onBlur
|
|
6014
6170
|
} = props;
|
|
6015
|
-
const
|
|
6016
|
-
const
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
editor = new FeelersEditor({
|
|
6026
|
-
container: inputRef.current,
|
|
6027
|
-
onChange: handleInput,
|
|
6028
|
-
value: localValue,
|
|
6029
|
-
onLint,
|
|
6030
|
-
contentAttributes,
|
|
6031
|
-
tooltipContainer,
|
|
6032
|
-
enableGutters,
|
|
6033
|
-
hostLanguage,
|
|
6034
|
-
singleLine
|
|
6171
|
+
const [localValue, setLocalValue] = useState(value);
|
|
6172
|
+
const handleInputCallback = useMemo(() => {
|
|
6173
|
+
return debounce(event => {
|
|
6174
|
+
const {
|
|
6175
|
+
validity,
|
|
6176
|
+
value
|
|
6177
|
+
} = event.target;
|
|
6178
|
+
if (validity.valid) {
|
|
6179
|
+
onInput(value ? parseFloat(value) : undefined);
|
|
6180
|
+
}
|
|
6035
6181
|
});
|
|
6036
|
-
|
|
6037
|
-
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
};
|
|
6042
|
-
}, []);
|
|
6043
|
-
useEffect(() => {
|
|
6044
|
-
if (!editor) {
|
|
6045
|
-
return;
|
|
6046
|
-
}
|
|
6047
|
-
if (value === localValue) {
|
|
6048
|
-
return;
|
|
6049
|
-
}
|
|
6050
|
-
editor.setValue(value);
|
|
6051
|
-
setLocalValue(value);
|
|
6052
|
-
}, [value]);
|
|
6053
|
-
const handleClick = () => {
|
|
6054
|
-
ref.current.focus();
|
|
6055
|
-
};
|
|
6056
|
-
return jsx("div", {
|
|
6057
|
-
name: props.name,
|
|
6058
|
-
class: classnames('bio-properties-panel-feelers-editor bio-properties-panel-input', localValue ? 'edited' : null, disabled ? 'disabled' : null),
|
|
6059
|
-
ref: inputRef,
|
|
6060
|
-
onClick: handleClick
|
|
6061
|
-
});
|
|
6062
|
-
});
|
|
6063
|
-
const useBufferedFocus = function (editor, ref) {
|
|
6064
|
-
const [buffer, setBuffer] = useState(undefined);
|
|
6065
|
-
ref.current = useMemo(() => ({
|
|
6066
|
-
focus: offset => {
|
|
6067
|
-
if (editor) {
|
|
6068
|
-
editor.focus(offset);
|
|
6069
|
-
} else {
|
|
6070
|
-
if (typeof offset === 'undefined') {
|
|
6071
|
-
offset = Infinity;
|
|
6072
|
-
}
|
|
6073
|
-
setBuffer(offset);
|
|
6074
|
-
}
|
|
6075
|
-
}
|
|
6076
|
-
}), [editor]);
|
|
6077
|
-
useEffect(() => {
|
|
6078
|
-
if (typeof buffer !== 'undefined' && editor) {
|
|
6079
|
-
editor.focus(buffer);
|
|
6080
|
-
setBuffer(false);
|
|
6081
|
-
}
|
|
6082
|
-
}, [editor, buffer]);
|
|
6083
|
-
};
|
|
6084
|
-
const CodeEditor = forwardRef((props, ref) => {
|
|
6085
|
-
const {
|
|
6086
|
-
value,
|
|
6087
|
-
onInput,
|
|
6088
|
-
onFeelToggle,
|
|
6089
|
-
onLint = () => {},
|
|
6090
|
-
disabled,
|
|
6091
|
-
tooltipContainer,
|
|
6092
|
-
variables
|
|
6093
|
-
} = props;
|
|
6094
|
-
const inputRef = useRef$1();
|
|
6095
|
-
const [editor, setEditor] = useState();
|
|
6096
|
-
const [localValue, setLocalValue] = useState(value || '');
|
|
6097
|
-
useBufferedFocus(editor, ref);
|
|
6098
|
-
const handleInput = useStaticCallback(newValue => {
|
|
6099
|
-
onInput(newValue);
|
|
6100
|
-
setLocalValue(newValue);
|
|
6101
|
-
});
|
|
6102
|
-
useEffect(() => {
|
|
6103
|
-
let editor;
|
|
6104
|
-
|
|
6105
|
-
/* Trigger FEEL toggle when
|
|
6106
|
-
*
|
|
6107
|
-
* - `backspace` is pressed
|
|
6108
|
-
* - AND the cursor is at the beginning of the input
|
|
6109
|
-
*/
|
|
6110
|
-
const onKeyDown = e => {
|
|
6111
|
-
if (e.key !== 'Backspace' || !editor) {
|
|
6112
|
-
return;
|
|
6113
|
-
}
|
|
6114
|
-
const selection = editor.getSelection();
|
|
6115
|
-
const range = selection.ranges[selection.mainIndex];
|
|
6116
|
-
if (range.from === 0 && range.to === 0) {
|
|
6117
|
-
onFeelToggle();
|
|
6118
|
-
}
|
|
6119
|
-
};
|
|
6120
|
-
editor = new FeelEditor({
|
|
6121
|
-
container: inputRef.current,
|
|
6122
|
-
onChange: handleInput,
|
|
6123
|
-
onKeyDown: onKeyDown,
|
|
6124
|
-
onLint: onLint,
|
|
6125
|
-
tooltipContainer: tooltipContainer,
|
|
6126
|
-
value: localValue,
|
|
6127
|
-
variables: variables
|
|
6128
|
-
});
|
|
6129
|
-
setEditor(editor);
|
|
6130
|
-
return () => {
|
|
6131
|
-
onLint([]);
|
|
6132
|
-
inputRef.current.innerHTML = '';
|
|
6133
|
-
setEditor(null);
|
|
6134
|
-
};
|
|
6135
|
-
}, []);
|
|
6136
|
-
useEffect(() => {
|
|
6137
|
-
if (!editor) {
|
|
6138
|
-
return;
|
|
6139
|
-
}
|
|
6140
|
-
if (value === localValue) {
|
|
6141
|
-
return;
|
|
6142
|
-
}
|
|
6143
|
-
editor.setValue(value);
|
|
6144
|
-
setLocalValue(value);
|
|
6145
|
-
}, [value]);
|
|
6146
|
-
useEffect(() => {
|
|
6147
|
-
if (!editor) {
|
|
6148
|
-
return;
|
|
6149
|
-
}
|
|
6150
|
-
editor.setVariables(variables);
|
|
6151
|
-
}, [variables]);
|
|
6152
|
-
const handleClick = () => {
|
|
6153
|
-
ref.current.focus();
|
|
6154
|
-
};
|
|
6155
|
-
return jsx("div", {
|
|
6156
|
-
class: classnames('bio-properties-panel-feel-editor-container', disabled ? 'disabled' : null),
|
|
6157
|
-
children: jsx("div", {
|
|
6158
|
-
name: props.name,
|
|
6159
|
-
class: classnames('bio-properties-panel-input', localValue ? 'edited' : null),
|
|
6160
|
-
ref: inputRef,
|
|
6161
|
-
onClick: handleClick
|
|
6162
|
-
})
|
|
6163
|
-
});
|
|
6164
|
-
});
|
|
6165
|
-
function FeelIndicator(props) {
|
|
6166
|
-
const {
|
|
6167
|
-
active
|
|
6168
|
-
} = props;
|
|
6169
|
-
if (!active) {
|
|
6170
|
-
return null;
|
|
6171
|
-
}
|
|
6172
|
-
return jsx("span", {
|
|
6173
|
-
class: "bio-properties-panel-feel-indicator",
|
|
6174
|
-
children: "="
|
|
6175
|
-
});
|
|
6176
|
-
}
|
|
6177
|
-
const noop$2 = () => {};
|
|
6178
|
-
|
|
6179
|
-
/**
|
|
6180
|
-
* @param {Object} props
|
|
6181
|
-
* @param {Object} props.label
|
|
6182
|
-
* @param {String} props.feel
|
|
6183
|
-
*/
|
|
6184
|
-
function FeelIcon(props) {
|
|
6185
|
-
const {
|
|
6186
|
-
feel = false,
|
|
6187
|
-
active,
|
|
6188
|
-
disabled = false,
|
|
6189
|
-
onClick = noop$2
|
|
6190
|
-
} = props;
|
|
6191
|
-
const feelRequiredLabel = 'FEEL expression is mandatory';
|
|
6192
|
-
const feelOptionalLabel = `Click to ${active ? 'remove' : 'set a'} dynamic value with FEEL expression`;
|
|
6193
|
-
const handleClick = e => {
|
|
6194
|
-
onClick(e);
|
|
6195
|
-
|
|
6196
|
-
// when pointer event was created from keyboard, keep focus on button
|
|
6197
|
-
if (!e.pointerType) {
|
|
6198
|
-
e.stopPropagation();
|
|
6199
|
-
}
|
|
6200
|
-
};
|
|
6201
|
-
return jsx("button", {
|
|
6202
|
-
class: classnames('bio-properties-panel-feel-icon', active ? 'active' : null, feel === 'required' ? 'required' : 'optional'),
|
|
6203
|
-
onClick: handleClick,
|
|
6204
|
-
disabled: feel === 'required' || disabled,
|
|
6205
|
-
title: feel === 'required' ? feelRequiredLabel : feelOptionalLabel,
|
|
6206
|
-
children: jsx(FeelIcon$1, {})
|
|
6207
|
-
});
|
|
6208
|
-
}
|
|
6209
|
-
function ToggleSwitch(props) {
|
|
6210
|
-
const {
|
|
6211
|
-
id,
|
|
6212
|
-
label,
|
|
6213
|
-
onInput,
|
|
6214
|
-
value,
|
|
6215
|
-
switcherLabel,
|
|
6216
|
-
inline,
|
|
6217
|
-
onFocus,
|
|
6218
|
-
onBlur,
|
|
6219
|
-
inputRef,
|
|
6220
|
-
tooltip
|
|
6221
|
-
} = props;
|
|
6222
|
-
const [localValue, setLocalValue] = useState(value);
|
|
6223
|
-
const handleInputCallback = async () => {
|
|
6224
|
-
onInput(!value);
|
|
6225
|
-
};
|
|
6226
|
-
const handleInput = e => {
|
|
6227
|
-
handleInputCallback();
|
|
6228
|
-
setLocalValue(e.target.value);
|
|
6229
|
-
};
|
|
6182
|
+
}, [onInput, debounce]);
|
|
6183
|
+
const handleInput = e => {
|
|
6184
|
+
handleInputCallback(e);
|
|
6185
|
+
setLocalValue(e.target.value);
|
|
6186
|
+
};
|
|
6230
6187
|
useEffect(() => {
|
|
6231
6188
|
if (value === localValue) {
|
|
6232
6189
|
return;
|
|
@@ -6234,199 +6191,64 @@ function ToggleSwitch(props) {
|
|
|
6234
6191
|
setLocalValue(value);
|
|
6235
6192
|
}, [value]);
|
|
6236
6193
|
return jsxs("div", {
|
|
6237
|
-
class:
|
|
6238
|
-
|
|
6239
|
-
}),
|
|
6240
|
-
children: [jsx("label", {
|
|
6241
|
-
class: "bio-properties-panel-label",
|
|
6194
|
+
class: "bio-properties-panel-numberfield",
|
|
6195
|
+
children: [displayLabel && jsx("label", {
|
|
6242
6196
|
for: prefixId$6(id),
|
|
6243
|
-
|
|
6244
|
-
|
|
6245
|
-
|
|
6246
|
-
|
|
6247
|
-
|
|
6248
|
-
|
|
6249
|
-
|
|
6250
|
-
|
|
6251
|
-
|
|
6252
|
-
|
|
6253
|
-
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
|
|
6257
|
-
|
|
6258
|
-
|
|
6259
|
-
|
|
6260
|
-
|
|
6261
|
-
onInput: handleInput,
|
|
6262
|
-
checked: !!localValue
|
|
6263
|
-
}), jsx("span", {
|
|
6264
|
-
class: "bio-properties-panel-toggle-switch__slider"
|
|
6265
|
-
})]
|
|
6266
|
-
}), switcherLabel && jsx("p", {
|
|
6267
|
-
class: "bio-properties-panel-toggle-switch__label",
|
|
6268
|
-
children: switcherLabel
|
|
6269
|
-
})]
|
|
6197
|
+
class: "bio-properties-panel-label",
|
|
6198
|
+
children: label
|
|
6199
|
+
}), jsx("input", {
|
|
6200
|
+
id: prefixId$6(id),
|
|
6201
|
+
ref: inputRef,
|
|
6202
|
+
type: "number",
|
|
6203
|
+
name: id,
|
|
6204
|
+
spellCheck: "false",
|
|
6205
|
+
autoComplete: "off",
|
|
6206
|
+
disabled: disabled,
|
|
6207
|
+
class: "bio-properties-panel-input",
|
|
6208
|
+
max: max,
|
|
6209
|
+
min: min,
|
|
6210
|
+
onInput: handleInput,
|
|
6211
|
+
onFocus: onFocus,
|
|
6212
|
+
onBlur: onBlur,
|
|
6213
|
+
step: step,
|
|
6214
|
+
value: localValue
|
|
6270
6215
|
})]
|
|
6271
6216
|
});
|
|
6272
6217
|
}
|
|
6273
6218
|
|
|
6274
6219
|
/**
|
|
6275
6220
|
* @param {Object} props
|
|
6221
|
+
* @param {Boolean} props.debounce
|
|
6222
|
+
* @param {String} props.description
|
|
6223
|
+
* @param {Boolean} props.disabled
|
|
6276
6224
|
* @param {Object} props.element
|
|
6225
|
+
* @param {Function} props.getValue
|
|
6277
6226
|
* @param {String} props.id
|
|
6278
|
-
* @param {String} props.description
|
|
6279
6227
|
* @param {String} props.label
|
|
6280
|
-
* @param {String} props.
|
|
6281
|
-
* @param {
|
|
6282
|
-
* @param {Function} props.getValue
|
|
6228
|
+
* @param {String} props.max
|
|
6229
|
+
* @param {String} props.min
|
|
6283
6230
|
* @param {Function} props.setValue
|
|
6284
6231
|
* @param {Function} props.onFocus
|
|
6285
6232
|
* @param {Function} props.onBlur
|
|
6286
|
-
* @param {
|
|
6233
|
+
* @param {String} props.step
|
|
6234
|
+
* @param {Function} props.validate
|
|
6287
6235
|
*/
|
|
6288
|
-
function
|
|
6236
|
+
function NumberFieldEntry(props) {
|
|
6289
6237
|
const {
|
|
6238
|
+
debounce,
|
|
6239
|
+
description,
|
|
6240
|
+
disabled,
|
|
6290
6241
|
element,
|
|
6242
|
+
getValue,
|
|
6291
6243
|
id,
|
|
6292
|
-
description,
|
|
6293
6244
|
label,
|
|
6294
|
-
|
|
6295
|
-
|
|
6296
|
-
getValue,
|
|
6245
|
+
max,
|
|
6246
|
+
min,
|
|
6297
6247
|
setValue,
|
|
6248
|
+
step,
|
|
6298
6249
|
onFocus,
|
|
6299
6250
|
onBlur,
|
|
6300
|
-
|
|
6301
|
-
} = props;
|
|
6302
|
-
const value = getValue(element);
|
|
6303
|
-
return jsxs("div", {
|
|
6304
|
-
class: "bio-properties-panel-entry bio-properties-panel-toggle-switch-entry",
|
|
6305
|
-
"data-entry-id": id,
|
|
6306
|
-
children: [jsx(ToggleSwitch, {
|
|
6307
|
-
id: id,
|
|
6308
|
-
label: label,
|
|
6309
|
-
value: value,
|
|
6310
|
-
onInput: setValue,
|
|
6311
|
-
onFocus: onFocus,
|
|
6312
|
-
onBlur: onBlur,
|
|
6313
|
-
switcherLabel: switcherLabel,
|
|
6314
|
-
inline: inline,
|
|
6315
|
-
tooltip: tooltip,
|
|
6316
|
-
element: element
|
|
6317
|
-
}), jsx(Description$1, {
|
|
6318
|
-
forId: id,
|
|
6319
|
-
element: element,
|
|
6320
|
-
value: description
|
|
6321
|
-
})]
|
|
6322
|
-
});
|
|
6323
|
-
}
|
|
6324
|
-
function isEdited$7(node) {
|
|
6325
|
-
return node && !!node.checked;
|
|
6326
|
-
}
|
|
6327
|
-
|
|
6328
|
-
// helpers /////////////////
|
|
6329
|
-
|
|
6330
|
-
function prefixId$6(id) {
|
|
6331
|
-
return `bio-properties-panel-${id}`;
|
|
6332
|
-
}
|
|
6333
|
-
function NumberField(props) {
|
|
6334
|
-
const {
|
|
6335
|
-
debounce,
|
|
6336
|
-
disabled,
|
|
6337
|
-
displayLabel = true,
|
|
6338
|
-
id,
|
|
6339
|
-
inputRef,
|
|
6340
|
-
label,
|
|
6341
|
-
max,
|
|
6342
|
-
min,
|
|
6343
|
-
onInput,
|
|
6344
|
-
step,
|
|
6345
|
-
value = '',
|
|
6346
|
-
onFocus,
|
|
6347
|
-
onBlur
|
|
6348
|
-
} = props;
|
|
6349
|
-
const [localValue, setLocalValue] = useState(value);
|
|
6350
|
-
const handleInputCallback = useMemo(() => {
|
|
6351
|
-
return debounce(event => {
|
|
6352
|
-
const {
|
|
6353
|
-
validity,
|
|
6354
|
-
value
|
|
6355
|
-
} = event.target;
|
|
6356
|
-
if (validity.valid) {
|
|
6357
|
-
onInput(value ? parseFloat(value) : undefined);
|
|
6358
|
-
}
|
|
6359
|
-
});
|
|
6360
|
-
}, [onInput, debounce]);
|
|
6361
|
-
const handleInput = e => {
|
|
6362
|
-
handleInputCallback(e);
|
|
6363
|
-
setLocalValue(e.target.value);
|
|
6364
|
-
};
|
|
6365
|
-
useEffect(() => {
|
|
6366
|
-
if (value === localValue) {
|
|
6367
|
-
return;
|
|
6368
|
-
}
|
|
6369
|
-
setLocalValue(value);
|
|
6370
|
-
}, [value]);
|
|
6371
|
-
return jsxs("div", {
|
|
6372
|
-
class: "bio-properties-panel-numberfield",
|
|
6373
|
-
children: [displayLabel && jsx("label", {
|
|
6374
|
-
for: prefixId$5(id),
|
|
6375
|
-
class: "bio-properties-panel-label",
|
|
6376
|
-
children: label
|
|
6377
|
-
}), jsx("input", {
|
|
6378
|
-
id: prefixId$5(id),
|
|
6379
|
-
ref: inputRef,
|
|
6380
|
-
type: "number",
|
|
6381
|
-
name: id,
|
|
6382
|
-
spellCheck: "false",
|
|
6383
|
-
autoComplete: "off",
|
|
6384
|
-
disabled: disabled,
|
|
6385
|
-
class: "bio-properties-panel-input",
|
|
6386
|
-
max: max,
|
|
6387
|
-
min: min,
|
|
6388
|
-
onInput: handleInput,
|
|
6389
|
-
onFocus: onFocus,
|
|
6390
|
-
onBlur: onBlur,
|
|
6391
|
-
step: step,
|
|
6392
|
-
value: localValue
|
|
6393
|
-
})]
|
|
6394
|
-
});
|
|
6395
|
-
}
|
|
6396
|
-
|
|
6397
|
-
/**
|
|
6398
|
-
* @param {Object} props
|
|
6399
|
-
* @param {Boolean} props.debounce
|
|
6400
|
-
* @param {String} props.description
|
|
6401
|
-
* @param {Boolean} props.disabled
|
|
6402
|
-
* @param {Object} props.element
|
|
6403
|
-
* @param {Function} props.getValue
|
|
6404
|
-
* @param {String} props.id
|
|
6405
|
-
* @param {String} props.label
|
|
6406
|
-
* @param {String} props.max
|
|
6407
|
-
* @param {String} props.min
|
|
6408
|
-
* @param {Function} props.setValue
|
|
6409
|
-
* @param {Function} props.onFocus
|
|
6410
|
-
* @param {Function} props.onBlur
|
|
6411
|
-
* @param {String} props.step
|
|
6412
|
-
* @param {Function} props.validate
|
|
6413
|
-
*/
|
|
6414
|
-
function NumberFieldEntry(props) {
|
|
6415
|
-
const {
|
|
6416
|
-
debounce,
|
|
6417
|
-
description,
|
|
6418
|
-
disabled,
|
|
6419
|
-
element,
|
|
6420
|
-
getValue,
|
|
6421
|
-
id,
|
|
6422
|
-
label,
|
|
6423
|
-
max,
|
|
6424
|
-
min,
|
|
6425
|
-
setValue,
|
|
6426
|
-
step,
|
|
6427
|
-
onFocus,
|
|
6428
|
-
onBlur,
|
|
6429
|
-
validate
|
|
6251
|
+
validate
|
|
6430
6252
|
} = props;
|
|
6431
6253
|
const globalError = useError(id);
|
|
6432
6254
|
const [localError, setLocalError] = useState(null);
|
|
@@ -6471,27 +6293,30 @@ function NumberFieldEntry(props) {
|
|
|
6471
6293
|
})]
|
|
6472
6294
|
});
|
|
6473
6295
|
}
|
|
6474
|
-
function isEdited$
|
|
6296
|
+
function isEdited$7(node) {
|
|
6475
6297
|
return node && !!node.value;
|
|
6476
6298
|
}
|
|
6477
6299
|
|
|
6478
6300
|
// helpers /////////////////
|
|
6479
6301
|
|
|
6480
|
-
function prefixId$
|
|
6302
|
+
function prefixId$6(id) {
|
|
6481
6303
|
return `bio-properties-panel-${id}`;
|
|
6482
6304
|
}
|
|
6483
|
-
const noop$
|
|
6305
|
+
const noop$2 = () => {};
|
|
6484
6306
|
function FeelTextfield(props) {
|
|
6485
6307
|
const {
|
|
6486
6308
|
debounce,
|
|
6487
6309
|
id,
|
|
6310
|
+
element,
|
|
6488
6311
|
label,
|
|
6312
|
+
hostLanguage,
|
|
6489
6313
|
onInput,
|
|
6490
6314
|
onError,
|
|
6491
6315
|
feel,
|
|
6492
6316
|
value = '',
|
|
6493
6317
|
disabled = false,
|
|
6494
6318
|
variables,
|
|
6319
|
+
singleLine,
|
|
6495
6320
|
tooltipContainer,
|
|
6496
6321
|
OptionalComponent = OptionalFeelInput,
|
|
6497
6322
|
tooltip
|
|
@@ -6502,6 +6327,11 @@ function FeelTextfield(props) {
|
|
|
6502
6327
|
const feelActive = isString(localValue) && localValue.startsWith('=') || feel === 'required';
|
|
6503
6328
|
const feelOnlyValue = isString(localValue) && localValue.startsWith('=') ? localValue.substring(1) : localValue;
|
|
6504
6329
|
const [focus, _setFocus] = useState(undefined);
|
|
6330
|
+
const {
|
|
6331
|
+
open: openPopup,
|
|
6332
|
+
source: popupSource
|
|
6333
|
+
} = useContext(FeelPopupContext);
|
|
6334
|
+
const popuOpen = popupSource === id;
|
|
6505
6335
|
const setFocus = (offset = 0) => {
|
|
6506
6336
|
const hasFocus = containerRef.current.contains(document.activeElement);
|
|
6507
6337
|
|
|
@@ -6554,6 +6384,21 @@ function FeelTextfield(props) {
|
|
|
6554
6384
|
const message = `${error.source}: ${error.message}`;
|
|
6555
6385
|
onError(message);
|
|
6556
6386
|
});
|
|
6387
|
+
const handlePopupOpen = (type = 'feel') => {
|
|
6388
|
+
const popupOptions = {
|
|
6389
|
+
id,
|
|
6390
|
+
hostLanguage,
|
|
6391
|
+
onInput: handleLocalInput,
|
|
6392
|
+
position: calculatePopupPosition(containerRef.current),
|
|
6393
|
+
singleLine,
|
|
6394
|
+
title: getPopupTitle(element, label),
|
|
6395
|
+
tooltipContainer,
|
|
6396
|
+
type,
|
|
6397
|
+
value: feelOnlyValue,
|
|
6398
|
+
variables
|
|
6399
|
+
};
|
|
6400
|
+
openPopup(id, popupOptions, editorRef.current);
|
|
6401
|
+
};
|
|
6557
6402
|
useEffect(() => {
|
|
6558
6403
|
if (typeof focus !== 'undefined') {
|
|
6559
6404
|
editorRef.current.focus(focus);
|
|
@@ -6582,7 +6427,7 @@ function FeelTextfield(props) {
|
|
|
6582
6427
|
event.clipboardData.setData('application/FEEL', event.clipboardData.getData('text'));
|
|
6583
6428
|
};
|
|
6584
6429
|
const pasteHandler = event => {
|
|
6585
|
-
if (feelActive) {
|
|
6430
|
+
if (feelActive || popuOpen) {
|
|
6586
6431
|
return;
|
|
6587
6432
|
}
|
|
6588
6433
|
const data = event.clipboardData.getData('application/FEEL');
|
|
@@ -6607,7 +6452,7 @@ function FeelTextfield(props) {
|
|
|
6607
6452
|
'feel-active': feelActive
|
|
6608
6453
|
}),
|
|
6609
6454
|
children: [jsxs("label", {
|
|
6610
|
-
for: prefixId$
|
|
6455
|
+
for: prefixId$5(id),
|
|
6611
6456
|
class: "bio-properties-panel-label",
|
|
6612
6457
|
onClick: () => setFocus(),
|
|
6613
6458
|
children: [jsx(TooltipWrapper, {
|
|
@@ -6629,28 +6474,33 @@ function FeelTextfield(props) {
|
|
|
6629
6474
|
disabled: feel !== 'optional' || disabled,
|
|
6630
6475
|
onClick: handleFeelToggle
|
|
6631
6476
|
}), feelActive ? jsx(CodeEditor, {
|
|
6632
|
-
id: prefixId$
|
|
6477
|
+
id: prefixId$5(id),
|
|
6633
6478
|
name: id,
|
|
6634
6479
|
onInput: handleLocalInput,
|
|
6635
6480
|
disabled: disabled,
|
|
6481
|
+
popupOpen: popuOpen,
|
|
6636
6482
|
onFeelToggle: () => {
|
|
6637
6483
|
handleFeelToggle();
|
|
6638
6484
|
setFocus(true);
|
|
6639
6485
|
},
|
|
6640
6486
|
onLint: handleLint,
|
|
6487
|
+
onPopupOpen: handlePopupOpen,
|
|
6641
6488
|
value: feelOnlyValue,
|
|
6642
6489
|
variables: variables,
|
|
6643
6490
|
ref: editorRef,
|
|
6644
6491
|
tooltipContainer: tooltipContainer
|
|
6645
6492
|
}) : jsx(OptionalComponent, {
|
|
6646
6493
|
...props,
|
|
6494
|
+
popupOpen: popuOpen,
|
|
6647
6495
|
onInput: handleLocalInput,
|
|
6648
6496
|
contentAttributes: {
|
|
6649
|
-
'id': prefixId$
|
|
6497
|
+
'id': prefixId$5(id),
|
|
6650
6498
|
'aria-label': label
|
|
6651
6499
|
},
|
|
6652
6500
|
value: localValue,
|
|
6653
|
-
ref: editorRef
|
|
6501
|
+
ref: editorRef,
|
|
6502
|
+
onPopupOpen: handlePopupOpen,
|
|
6503
|
+
containerRef: containerRef
|
|
6654
6504
|
})]
|
|
6655
6505
|
})]
|
|
6656
6506
|
});
|
|
@@ -6684,7 +6534,7 @@ const OptionalFeelInput = forwardRef((props, ref) => {
|
|
|
6684
6534
|
}
|
|
6685
6535
|
};
|
|
6686
6536
|
return jsx("input", {
|
|
6687
|
-
id: prefixId$
|
|
6537
|
+
id: prefixId$5(id),
|
|
6688
6538
|
type: "text",
|
|
6689
6539
|
ref: inputRef,
|
|
6690
6540
|
name: id,
|
|
@@ -6711,309 +6561,995 @@ const OptionalFeelNumberField = forwardRef((props, ref) => {
|
|
|
6711
6561
|
onFocus,
|
|
6712
6562
|
onBlur
|
|
6713
6563
|
} = props;
|
|
6714
|
-
const inputRef = useRef$1();
|
|
6564
|
+
const inputRef = useRef$1();
|
|
6565
|
+
|
|
6566
|
+
// To be consistent with the FEEL editor, set focus at start of input
|
|
6567
|
+
// this ensures clean editing experience when switching with the keyboard
|
|
6568
|
+
ref.current = {
|
|
6569
|
+
focus: position => {
|
|
6570
|
+
const input = inputRef.current;
|
|
6571
|
+
if (!input) {
|
|
6572
|
+
return;
|
|
6573
|
+
}
|
|
6574
|
+
input.focus();
|
|
6575
|
+
if (typeof position === 'number' && position !== Infinity) {
|
|
6576
|
+
if (position > value.length) {
|
|
6577
|
+
position = value.length;
|
|
6578
|
+
}
|
|
6579
|
+
input.setSelectionRange(position, position);
|
|
6580
|
+
}
|
|
6581
|
+
}
|
|
6582
|
+
};
|
|
6583
|
+
return jsx(NumberField, {
|
|
6584
|
+
id: id,
|
|
6585
|
+
debounce: debounce,
|
|
6586
|
+
disabled: disabled,
|
|
6587
|
+
displayLabel: false,
|
|
6588
|
+
inputRef: inputRef,
|
|
6589
|
+
max: max,
|
|
6590
|
+
min: min,
|
|
6591
|
+
onInput: onInput,
|
|
6592
|
+
step: step,
|
|
6593
|
+
value: value,
|
|
6594
|
+
onFocus: onFocus,
|
|
6595
|
+
onBlur: onBlur
|
|
6596
|
+
});
|
|
6597
|
+
});
|
|
6598
|
+
forwardRef((props, ref) => {
|
|
6599
|
+
const {
|
|
6600
|
+
id,
|
|
6601
|
+
disabled,
|
|
6602
|
+
onInput,
|
|
6603
|
+
value,
|
|
6604
|
+
onFocus,
|
|
6605
|
+
onBlur
|
|
6606
|
+
} = props;
|
|
6607
|
+
const inputRef = useRef$1();
|
|
6608
|
+
|
|
6609
|
+
// To be consistent with the FEEL editor, set focus at start of input
|
|
6610
|
+
// this ensures clean editing experience when switching with the keyboard
|
|
6611
|
+
ref.current = {
|
|
6612
|
+
focus: () => {
|
|
6613
|
+
const input = inputRef.current;
|
|
6614
|
+
if (!input) {
|
|
6615
|
+
return;
|
|
6616
|
+
}
|
|
6617
|
+
input.focus();
|
|
6618
|
+
input.setSelectionRange(0, 0);
|
|
6619
|
+
}
|
|
6620
|
+
};
|
|
6621
|
+
return jsx("textarea", {
|
|
6622
|
+
id: prefixId$5(id),
|
|
6623
|
+
type: "text",
|
|
6624
|
+
ref: inputRef,
|
|
6625
|
+
name: id,
|
|
6626
|
+
spellCheck: "false",
|
|
6627
|
+
autoComplete: "off",
|
|
6628
|
+
disabled: disabled,
|
|
6629
|
+
class: "bio-properties-panel-input",
|
|
6630
|
+
onInput: e => onInput(e.target.value),
|
|
6631
|
+
onFocus: onFocus,
|
|
6632
|
+
onBlur: onBlur,
|
|
6633
|
+
value: value || '',
|
|
6634
|
+
"data-gramm": "false"
|
|
6635
|
+
});
|
|
6636
|
+
});
|
|
6637
|
+
const OptionalFeelToggleSwitch = forwardRef((props, ref) => {
|
|
6638
|
+
const {
|
|
6639
|
+
id,
|
|
6640
|
+
onInput,
|
|
6641
|
+
value,
|
|
6642
|
+
onFocus,
|
|
6643
|
+
onBlur,
|
|
6644
|
+
switcherLabel
|
|
6645
|
+
} = props;
|
|
6646
|
+
const inputRef = useRef$1();
|
|
6647
|
+
|
|
6648
|
+
// To be consistent with the FEEL editor, set focus at start of input
|
|
6649
|
+
// this ensures clean editing experience when switching with the keyboard
|
|
6650
|
+
ref.current = {
|
|
6651
|
+
focus: () => {
|
|
6652
|
+
const input = inputRef.current;
|
|
6653
|
+
if (!input) {
|
|
6654
|
+
return;
|
|
6655
|
+
}
|
|
6656
|
+
input.focus();
|
|
6657
|
+
}
|
|
6658
|
+
};
|
|
6659
|
+
return jsx(ToggleSwitch, {
|
|
6660
|
+
id: id,
|
|
6661
|
+
value: value,
|
|
6662
|
+
inputRef: inputRef,
|
|
6663
|
+
onInput: onInput,
|
|
6664
|
+
onFocus: onFocus,
|
|
6665
|
+
onBlur: onBlur,
|
|
6666
|
+
switcherLabel: switcherLabel
|
|
6667
|
+
});
|
|
6668
|
+
});
|
|
6669
|
+
forwardRef((props, ref) => {
|
|
6670
|
+
const {
|
|
6671
|
+
id,
|
|
6672
|
+
disabled,
|
|
6673
|
+
onInput,
|
|
6674
|
+
value,
|
|
6675
|
+
onFocus,
|
|
6676
|
+
onBlur
|
|
6677
|
+
} = props;
|
|
6678
|
+
const inputRef = useRef$1();
|
|
6679
|
+
const handleChange = ({
|
|
6680
|
+
target
|
|
6681
|
+
}) => {
|
|
6682
|
+
onInput(target.checked);
|
|
6683
|
+
};
|
|
6684
|
+
|
|
6685
|
+
// To be consistent with the FEEL editor, set focus at start of input
|
|
6686
|
+
// this ensures clean editing experience when switching with the keyboard
|
|
6687
|
+
ref.current = {
|
|
6688
|
+
focus: () => {
|
|
6689
|
+
const input = inputRef.current;
|
|
6690
|
+
if (!input) {
|
|
6691
|
+
return;
|
|
6692
|
+
}
|
|
6693
|
+
input.focus();
|
|
6694
|
+
}
|
|
6695
|
+
};
|
|
6696
|
+
return jsx("input", {
|
|
6697
|
+
ref: inputRef,
|
|
6698
|
+
id: prefixId$5(id),
|
|
6699
|
+
name: id,
|
|
6700
|
+
onFocus: onFocus,
|
|
6701
|
+
onBlur: onBlur,
|
|
6702
|
+
type: "checkbox",
|
|
6703
|
+
class: "bio-properties-panel-input",
|
|
6704
|
+
onChange: handleChange,
|
|
6705
|
+
checked: value,
|
|
6706
|
+
disabled: disabled
|
|
6707
|
+
});
|
|
6708
|
+
});
|
|
6709
|
+
|
|
6710
|
+
/**
|
|
6711
|
+
* @param {Object} props
|
|
6712
|
+
* @param {Object} props.element
|
|
6713
|
+
* @param {String} props.id
|
|
6714
|
+
* @param {String} props.description
|
|
6715
|
+
* @param {Boolean} props.debounce
|
|
6716
|
+
* @param {Boolean} props.disabled
|
|
6717
|
+
* @param {Boolean} props.feel
|
|
6718
|
+
* @param {String} props.label
|
|
6719
|
+
* @param {Function} props.getValue
|
|
6720
|
+
* @param {Function} props.setValue
|
|
6721
|
+
* @param {Function} props.tooltipContainer
|
|
6722
|
+
* @param {Function} props.validate
|
|
6723
|
+
* @param {Function} props.show
|
|
6724
|
+
* @param {Function} props.example
|
|
6725
|
+
* @param {Function} props.variables
|
|
6726
|
+
* @param {Function} props.onFocus
|
|
6727
|
+
* @param {Function} props.onBlur
|
|
6728
|
+
* @param {string|import('preact').Component} props.tooltip
|
|
6729
|
+
*/
|
|
6730
|
+
function FeelEntry(props) {
|
|
6731
|
+
const {
|
|
6732
|
+
element,
|
|
6733
|
+
id,
|
|
6734
|
+
description,
|
|
6735
|
+
debounce,
|
|
6736
|
+
disabled,
|
|
6737
|
+
feel,
|
|
6738
|
+
label,
|
|
6739
|
+
getValue,
|
|
6740
|
+
setValue,
|
|
6741
|
+
tooltipContainer,
|
|
6742
|
+
hostLanguage,
|
|
6743
|
+
singleLine,
|
|
6744
|
+
validate,
|
|
6745
|
+
show = noop$2,
|
|
6746
|
+
example,
|
|
6747
|
+
variables,
|
|
6748
|
+
onFocus,
|
|
6749
|
+
onBlur,
|
|
6750
|
+
tooltip
|
|
6751
|
+
} = props;
|
|
6752
|
+
const [validationError, setValidationError] = useState(null);
|
|
6753
|
+
const [localError, setLocalError] = useState(null);
|
|
6754
|
+
let value = getValue(element);
|
|
6755
|
+
useEffect(() => {
|
|
6756
|
+
if (isFunction(validate)) {
|
|
6757
|
+
const newValidationError = validate(value) || null;
|
|
6758
|
+
setValidationError(newValidationError);
|
|
6759
|
+
}
|
|
6760
|
+
}, [value]);
|
|
6761
|
+
const onInput = useStaticCallback(newValue => {
|
|
6762
|
+
let newValidationError = null;
|
|
6763
|
+
if (isFunction(validate)) {
|
|
6764
|
+
newValidationError = validate(newValue) || null;
|
|
6765
|
+
}
|
|
6766
|
+
|
|
6767
|
+
// don't create multiple commandStack entries for the same value
|
|
6768
|
+
if (newValue !== value) {
|
|
6769
|
+
setValue(newValue, newValidationError);
|
|
6770
|
+
}
|
|
6771
|
+
setValidationError(newValidationError);
|
|
6772
|
+
});
|
|
6773
|
+
const onError = useCallback(err => {
|
|
6774
|
+
setLocalError(err);
|
|
6775
|
+
}, []);
|
|
6776
|
+
const temporaryError = useError(id);
|
|
6777
|
+
const error = localError || temporaryError || validationError;
|
|
6778
|
+
return jsxs("div", {
|
|
6779
|
+
class: classnames(props.class, 'bio-properties-panel-entry', error ? 'has-error' : ''),
|
|
6780
|
+
"data-entry-id": id,
|
|
6781
|
+
children: [createElement(FeelTextfield, {
|
|
6782
|
+
...props,
|
|
6783
|
+
debounce: debounce,
|
|
6784
|
+
disabled: disabled,
|
|
6785
|
+
feel: feel,
|
|
6786
|
+
id: id,
|
|
6787
|
+
key: element,
|
|
6788
|
+
label: label,
|
|
6789
|
+
onInput: onInput,
|
|
6790
|
+
onError: onError,
|
|
6791
|
+
onFocus: onFocus,
|
|
6792
|
+
onBlur: onBlur,
|
|
6793
|
+
example: example,
|
|
6794
|
+
hostLanguage: hostLanguage,
|
|
6795
|
+
singleLine: singleLine,
|
|
6796
|
+
show: show,
|
|
6797
|
+
value: value,
|
|
6798
|
+
variables: variables,
|
|
6799
|
+
tooltipContainer: tooltipContainer,
|
|
6800
|
+
OptionalComponent: props.OptionalComponent,
|
|
6801
|
+
tooltip: tooltip
|
|
6802
|
+
}), error && jsx("div", {
|
|
6803
|
+
class: "bio-properties-panel-error",
|
|
6804
|
+
children: error
|
|
6805
|
+
}), jsx(Description$1, {
|
|
6806
|
+
forId: id,
|
|
6807
|
+
element: element,
|
|
6808
|
+
value: description
|
|
6809
|
+
})]
|
|
6810
|
+
});
|
|
6811
|
+
}
|
|
6812
|
+
|
|
6813
|
+
/**
|
|
6814
|
+
* @param {Object} props
|
|
6815
|
+
* @param {Object} props.element
|
|
6816
|
+
* @param {String} props.id
|
|
6817
|
+
* @param {String} props.description
|
|
6818
|
+
* @param {Boolean} props.debounce
|
|
6819
|
+
* @param {Boolean} props.disabled
|
|
6820
|
+
* @param {String} props.max
|
|
6821
|
+
* @param {String} props.min
|
|
6822
|
+
* @param {String} props.step
|
|
6823
|
+
* @param {Boolean} props.feel
|
|
6824
|
+
* @param {String} props.label
|
|
6825
|
+
* @param {Function} props.getValue
|
|
6826
|
+
* @param {Function} props.setValue
|
|
6827
|
+
* @param {Function} props.tooltipContainer
|
|
6828
|
+
* @param {Function} props.validate
|
|
6829
|
+
* @param {Function} props.show
|
|
6830
|
+
* @param {Function} props.example
|
|
6831
|
+
* @param {Function} props.variables
|
|
6832
|
+
* @param {Function} props.onFocus
|
|
6833
|
+
* @param {Function} props.onBlur
|
|
6834
|
+
*/
|
|
6835
|
+
function FeelNumberEntry(props) {
|
|
6836
|
+
return jsx(FeelEntry, {
|
|
6837
|
+
class: "bio-properties-panel-feel-number",
|
|
6838
|
+
OptionalComponent: OptionalFeelNumberField,
|
|
6839
|
+
...props
|
|
6840
|
+
});
|
|
6841
|
+
}
|
|
6842
|
+
|
|
6843
|
+
/**
|
|
6844
|
+
* @param {Object} props
|
|
6845
|
+
* @param {Object} props.element
|
|
6846
|
+
* @param {String} props.id
|
|
6847
|
+
* @param {String} props.description
|
|
6848
|
+
* @param {Boolean} props.debounce
|
|
6849
|
+
* @param {Boolean} props.disabled
|
|
6850
|
+
* @param {Boolean} props.feel
|
|
6851
|
+
* @param {String} props.label
|
|
6852
|
+
* @param {Function} props.getValue
|
|
6853
|
+
* @param {Function} props.setValue
|
|
6854
|
+
* @param {Function} props.tooltipContainer
|
|
6855
|
+
* @param {Function} props.validate
|
|
6856
|
+
* @param {Function} props.show
|
|
6857
|
+
* @param {Function} props.example
|
|
6858
|
+
* @param {Function} props.variables
|
|
6859
|
+
* @param {Function} props.onFocus
|
|
6860
|
+
* @param {Function} props.onBlur
|
|
6861
|
+
*/
|
|
6862
|
+
function FeelToggleSwitchEntry(props) {
|
|
6863
|
+
return jsx(FeelEntry, {
|
|
6864
|
+
class: "bio-properties-panel-feel-toggle-switch",
|
|
6865
|
+
OptionalComponent: OptionalFeelToggleSwitch,
|
|
6866
|
+
...props
|
|
6867
|
+
});
|
|
6868
|
+
}
|
|
6869
|
+
|
|
6870
|
+
/**
|
|
6871
|
+
* @param {Object} props
|
|
6872
|
+
* @param {Object} props.element
|
|
6873
|
+
* @param {String} props.id
|
|
6874
|
+
* @param {String} props.description
|
|
6875
|
+
* @param {String} props.hostLanguage
|
|
6876
|
+
* @param {Boolean} props.singleLine
|
|
6877
|
+
* @param {Boolean} props.debounce
|
|
6878
|
+
* @param {Boolean} props.disabled
|
|
6879
|
+
* @param {Boolean} props.feel
|
|
6880
|
+
* @param {String} props.label
|
|
6881
|
+
* @param {Function} props.getValue
|
|
6882
|
+
* @param {Function} props.setValue
|
|
6883
|
+
* @param {Function} props.tooltipContainer
|
|
6884
|
+
* @param {Function} props.validate
|
|
6885
|
+
* @param {Function} props.show
|
|
6886
|
+
* @param {Function} props.example
|
|
6887
|
+
* @param {Function} props.variables
|
|
6888
|
+
* @param {Function} props.onFocus
|
|
6889
|
+
* @param {Function} props.onBlur
|
|
6890
|
+
*/
|
|
6891
|
+
function FeelTemplatingEntry(props) {
|
|
6892
|
+
return jsx(FeelEntry, {
|
|
6893
|
+
class: "bio-properties-panel-feel-templating",
|
|
6894
|
+
OptionalComponent: CodeEditor$1,
|
|
6895
|
+
...props
|
|
6896
|
+
});
|
|
6897
|
+
}
|
|
6898
|
+
function isEdited$6(node) {
|
|
6899
|
+
if (!node) {
|
|
6900
|
+
return false;
|
|
6901
|
+
}
|
|
6902
|
+
if (node.type === 'checkbox') {
|
|
6903
|
+
return !!node.checked || node.classList.contains('edited');
|
|
6904
|
+
}
|
|
6905
|
+
return !!node.value || node.classList.contains('edited');
|
|
6906
|
+
}
|
|
6907
|
+
|
|
6908
|
+
// helpers /////////////////
|
|
6909
|
+
|
|
6910
|
+
function prefixId$5(id) {
|
|
6911
|
+
return `bio-properties-panel-${id}`;
|
|
6912
|
+
}
|
|
6913
|
+
function calculatePopupPosition(element) {
|
|
6914
|
+
const {
|
|
6915
|
+
top,
|
|
6916
|
+
left
|
|
6917
|
+
} = element.getBoundingClientRect();
|
|
6918
|
+
return {
|
|
6919
|
+
left: left - FEEL_POPUP_WIDTH - 20,
|
|
6920
|
+
top: top
|
|
6921
|
+
};
|
|
6922
|
+
}
|
|
6923
|
+
|
|
6924
|
+
// todo(pinussilvestrus): make this configurable in the future
|
|
6925
|
+
function getPopupTitle(element, label) {
|
|
6926
|
+
let popupTitle;
|
|
6927
|
+
if (element && element.type) {
|
|
6928
|
+
popupTitle = `${element.type} / `;
|
|
6929
|
+
}
|
|
6930
|
+
return `${popupTitle}${label}`;
|
|
6931
|
+
}
|
|
6932
|
+
const DEFAULT_LAYOUT = {};
|
|
6933
|
+
const DEFAULT_DESCRIPTION = {};
|
|
6934
|
+
const DEFAULT_TOOLTIP = {};
|
|
6935
|
+
|
|
6936
|
+
/**
|
|
6937
|
+
* @typedef { {
|
|
6938
|
+
* component: import('preact').Component,
|
|
6939
|
+
* id: String,
|
|
6940
|
+
* isEdited?: Function
|
|
6941
|
+
* } } EntryDefinition
|
|
6942
|
+
*
|
|
6943
|
+
* @typedef { {
|
|
6944
|
+
* autoFocusEntry: String,
|
|
6945
|
+
* autoOpen?: Boolean,
|
|
6946
|
+
* entries: Array<EntryDefinition>,
|
|
6947
|
+
* id: String,
|
|
6948
|
+
* label: String,
|
|
6949
|
+
* remove: (event: MouseEvent) => void
|
|
6950
|
+
* } } ListItemDefinition
|
|
6951
|
+
*
|
|
6952
|
+
* @typedef { {
|
|
6953
|
+
* add: (event: MouseEvent) => void,
|
|
6954
|
+
* component: import('preact').Component,
|
|
6955
|
+
* element: Object,
|
|
6956
|
+
* id: String,
|
|
6957
|
+
* items: Array<ListItemDefinition>,
|
|
6958
|
+
* label: String,
|
|
6959
|
+
* shouldSort?: Boolean,
|
|
6960
|
+
* shouldOpen?: Boolean
|
|
6961
|
+
* } } ListGroupDefinition
|
|
6962
|
+
*
|
|
6963
|
+
* @typedef { {
|
|
6964
|
+
* component?: import('preact').Component,
|
|
6965
|
+
* entries: Array<EntryDefinition>,
|
|
6966
|
+
* id: String,
|
|
6967
|
+
* label: String,
|
|
6968
|
+
* shouldOpen?: Boolean
|
|
6969
|
+
* } } GroupDefinition
|
|
6970
|
+
*
|
|
6971
|
+
* @typedef { {
|
|
6972
|
+
* [id: String]: GetDescriptionFunction
|
|
6973
|
+
* } } DescriptionConfig
|
|
6974
|
+
*
|
|
6975
|
+
* @typedef { {
|
|
6976
|
+
* [id: String]: GetTooltipFunction
|
|
6977
|
+
* } } TooltipConfig
|
|
6978
|
+
*
|
|
6979
|
+
* @callback { {
|
|
6980
|
+
* @param {string} id
|
|
6981
|
+
* @param {Object} element
|
|
6982
|
+
* @returns {string}
|
|
6983
|
+
* } } GetDescriptionFunction
|
|
6984
|
+
*
|
|
6985
|
+
* @callback { {
|
|
6986
|
+
* @param {string} id
|
|
6987
|
+
* @param {Object} element
|
|
6988
|
+
* @returns {string}
|
|
6989
|
+
* } } GetTooltipFunction
|
|
6990
|
+
*
|
|
6991
|
+
* @typedef { {
|
|
6992
|
+
* getEmpty: (element: object) => import('./components/Placeholder').PlaceholderDefinition,
|
|
6993
|
+
* getMultiple: (element: Object) => import('./components/Placeholder').PlaceholderDefinition
|
|
6994
|
+
* } } PlaceholderProvider
|
|
6995
|
+
*
|
|
6996
|
+
*/
|
|
6997
|
+
|
|
6998
|
+
/**
|
|
6999
|
+
* A basic properties panel component. Describes *how* content will be rendered, accepts
|
|
7000
|
+
* data from implementor to describe *what* will be rendered.
|
|
7001
|
+
*
|
|
7002
|
+
* @param {Object} props
|
|
7003
|
+
* @param {Object|Array} props.element
|
|
7004
|
+
* @param {import('./components/Header').HeaderProvider} props.headerProvider
|
|
7005
|
+
* @param {PlaceholderProvider} [props.placeholderProvider]
|
|
7006
|
+
* @param {Array<GroupDefinition|ListGroupDefinition>} props.groups
|
|
7007
|
+
* @param {Object} [props.layoutConfig]
|
|
7008
|
+
* @param {Function} [props.layoutChanged]
|
|
7009
|
+
* @param {DescriptionConfig} [props.descriptionConfig]
|
|
7010
|
+
* @param {Function} [props.descriptionLoaded]
|
|
7011
|
+
* @param {TooltipConfig} [props.tooltipConfig]
|
|
7012
|
+
* @param {Function} [props.tooltipLoaded]
|
|
7013
|
+
* @param {Object} [props.eventBus]
|
|
7014
|
+
*/
|
|
7015
|
+
function PropertiesPanel(props) {
|
|
7016
|
+
const {
|
|
7017
|
+
element,
|
|
7018
|
+
headerProvider,
|
|
7019
|
+
placeholderProvider,
|
|
7020
|
+
groups,
|
|
7021
|
+
layoutConfig,
|
|
7022
|
+
layoutChanged,
|
|
7023
|
+
descriptionConfig,
|
|
7024
|
+
descriptionLoaded,
|
|
7025
|
+
tooltipConfig,
|
|
7026
|
+
tooltipLoaded,
|
|
7027
|
+
eventBus
|
|
7028
|
+
} = props;
|
|
7029
|
+
|
|
7030
|
+
// set-up layout context
|
|
7031
|
+
const [layout, setLayout] = useState(createLayout(layoutConfig));
|
|
7032
|
+
|
|
7033
|
+
// react to external changes in the layout config
|
|
7034
|
+
useUpdateLayoutEffect(() => {
|
|
7035
|
+
const newLayout = createLayout(layoutConfig);
|
|
7036
|
+
setLayout(newLayout);
|
|
7037
|
+
}, [layoutConfig]);
|
|
7038
|
+
useEffect(() => {
|
|
7039
|
+
if (typeof layoutChanged === 'function') {
|
|
7040
|
+
layoutChanged(layout);
|
|
7041
|
+
}
|
|
7042
|
+
}, [layout, layoutChanged]);
|
|
7043
|
+
const getLayoutForKey = (key, defaultValue) => {
|
|
7044
|
+
return get(layout, key, defaultValue);
|
|
7045
|
+
};
|
|
7046
|
+
const setLayoutForKey = (key, config) => {
|
|
7047
|
+
const newLayout = assign({}, layout);
|
|
7048
|
+
set$1(newLayout, key, config);
|
|
7049
|
+
setLayout(newLayout);
|
|
7050
|
+
};
|
|
7051
|
+
const layoutContext = {
|
|
7052
|
+
layout,
|
|
7053
|
+
setLayout,
|
|
7054
|
+
getLayoutForKey,
|
|
7055
|
+
setLayoutForKey
|
|
7056
|
+
};
|
|
7057
|
+
|
|
7058
|
+
// set-up description context
|
|
7059
|
+
const description = useMemo(() => createDescriptionContext(descriptionConfig), [descriptionConfig]);
|
|
7060
|
+
useEffect(() => {
|
|
7061
|
+
if (typeof descriptionLoaded === 'function') {
|
|
7062
|
+
descriptionLoaded(description);
|
|
7063
|
+
}
|
|
7064
|
+
}, [description, descriptionLoaded]);
|
|
7065
|
+
const getDescriptionForId = (id, element) => {
|
|
7066
|
+
return description[id] && description[id](element);
|
|
7067
|
+
};
|
|
7068
|
+
const descriptionContext = {
|
|
7069
|
+
description,
|
|
7070
|
+
getDescriptionForId
|
|
7071
|
+
};
|
|
7072
|
+
|
|
7073
|
+
// set-up tooltip context
|
|
7074
|
+
const tooltip = useMemo(() => createTooltipContext(tooltipConfig), [tooltipConfig]);
|
|
7075
|
+
useEffect(() => {
|
|
7076
|
+
if (typeof tooltipLoaded === 'function') {
|
|
7077
|
+
tooltipLoaded(tooltip);
|
|
7078
|
+
}
|
|
7079
|
+
}, [tooltip, tooltipLoaded]);
|
|
7080
|
+
const getTooltipForId = (id, element) => {
|
|
7081
|
+
return tooltip[id] && tooltip[id](element);
|
|
7082
|
+
};
|
|
7083
|
+
const tooltipContext = {
|
|
7084
|
+
tooltip,
|
|
7085
|
+
getTooltipForId
|
|
7086
|
+
};
|
|
7087
|
+
const [errors, setErrors] = useState({});
|
|
7088
|
+
const onSetErrors = ({
|
|
7089
|
+
errors
|
|
7090
|
+
}) => setErrors(errors);
|
|
7091
|
+
useEvent('propertiesPanel.setErrors', onSetErrors, eventBus);
|
|
7092
|
+
const errorsContext = {
|
|
7093
|
+
errors
|
|
7094
|
+
};
|
|
7095
|
+
const eventContext = {
|
|
7096
|
+
eventBus
|
|
7097
|
+
};
|
|
7098
|
+
const propertiesPanelContext = {
|
|
7099
|
+
element
|
|
7100
|
+
};
|
|
7101
|
+
|
|
7102
|
+
// empty state
|
|
7103
|
+
if (placeholderProvider && !element) {
|
|
7104
|
+
return jsx(Placeholder, {
|
|
7105
|
+
...placeholderProvider.getEmpty()
|
|
7106
|
+
});
|
|
7107
|
+
}
|
|
7108
|
+
|
|
7109
|
+
// multiple state
|
|
7110
|
+
if (placeholderProvider && isArray(element)) {
|
|
7111
|
+
return jsx(Placeholder, {
|
|
7112
|
+
...placeholderProvider.getMultiple()
|
|
7113
|
+
});
|
|
7114
|
+
}
|
|
7115
|
+
return jsx(LayoutContext.Provider, {
|
|
7116
|
+
value: propertiesPanelContext,
|
|
7117
|
+
children: jsx(ErrorsContext.Provider, {
|
|
7118
|
+
value: errorsContext,
|
|
7119
|
+
children: jsx(DescriptionContext.Provider, {
|
|
7120
|
+
value: descriptionContext,
|
|
7121
|
+
children: jsx(TooltipContext.Provider, {
|
|
7122
|
+
value: tooltipContext,
|
|
7123
|
+
children: jsx(LayoutContext.Provider, {
|
|
7124
|
+
value: layoutContext,
|
|
7125
|
+
children: jsx(EventContext.Provider, {
|
|
7126
|
+
value: eventContext,
|
|
7127
|
+
children: jsx(FEELPopupRoot, {
|
|
7128
|
+
element: element,
|
|
7129
|
+
children: jsxs("div", {
|
|
7130
|
+
class: "bio-properties-panel",
|
|
7131
|
+
children: [jsx(Header, {
|
|
7132
|
+
element: element,
|
|
7133
|
+
headerProvider: headerProvider
|
|
7134
|
+
}), jsx("div", {
|
|
7135
|
+
class: "bio-properties-panel-scroll-container",
|
|
7136
|
+
children: groups.map(group => {
|
|
7137
|
+
const {
|
|
7138
|
+
component: Component = Group,
|
|
7139
|
+
id
|
|
7140
|
+
} = group;
|
|
7141
|
+
return createElement(Component, {
|
|
7142
|
+
...group,
|
|
7143
|
+
key: id,
|
|
7144
|
+
element: element
|
|
7145
|
+
});
|
|
7146
|
+
})
|
|
7147
|
+
})]
|
|
7148
|
+
})
|
|
7149
|
+
})
|
|
7150
|
+
})
|
|
7151
|
+
})
|
|
7152
|
+
})
|
|
7153
|
+
})
|
|
7154
|
+
})
|
|
7155
|
+
});
|
|
7156
|
+
}
|
|
7157
|
+
|
|
7158
|
+
// helpers //////////////////
|
|
7159
|
+
|
|
7160
|
+
function createLayout(overrides = {}, defaults = DEFAULT_LAYOUT) {
|
|
7161
|
+
return {
|
|
7162
|
+
...defaults,
|
|
7163
|
+
...overrides
|
|
7164
|
+
};
|
|
7165
|
+
}
|
|
7166
|
+
function createDescriptionContext(overrides = {}) {
|
|
7167
|
+
return {
|
|
7168
|
+
...DEFAULT_DESCRIPTION,
|
|
7169
|
+
...overrides
|
|
7170
|
+
};
|
|
7171
|
+
}
|
|
7172
|
+
function createTooltipContext(overrides = {}) {
|
|
7173
|
+
return {
|
|
7174
|
+
...DEFAULT_TOOLTIP,
|
|
7175
|
+
...overrides
|
|
7176
|
+
};
|
|
7177
|
+
}
|
|
7178
|
+
|
|
7179
|
+
// hooks //////////////////
|
|
7180
|
+
|
|
7181
|
+
/**
|
|
7182
|
+
* This hook behaves like useLayoutEffect, but does not trigger on the first render.
|
|
7183
|
+
*
|
|
7184
|
+
* @param {Function} effect
|
|
7185
|
+
* @param {Array} deps
|
|
7186
|
+
*/
|
|
7187
|
+
function useUpdateLayoutEffect(effect, deps) {
|
|
7188
|
+
const isMounted = useRef$1(false);
|
|
7189
|
+
useLayoutEffect(() => {
|
|
7190
|
+
if (isMounted.current) {
|
|
7191
|
+
return effect();
|
|
7192
|
+
} else {
|
|
7193
|
+
isMounted.current = true;
|
|
7194
|
+
}
|
|
7195
|
+
}, deps);
|
|
7196
|
+
}
|
|
7197
|
+
function CollapsibleEntry(props) {
|
|
7198
|
+
const {
|
|
7199
|
+
element,
|
|
7200
|
+
entries = [],
|
|
7201
|
+
id,
|
|
7202
|
+
label,
|
|
7203
|
+
open: shouldOpen,
|
|
7204
|
+
remove
|
|
7205
|
+
} = props;
|
|
7206
|
+
const [open, setOpen] = useState(shouldOpen);
|
|
7207
|
+
const toggleOpen = () => setOpen(!open);
|
|
7208
|
+
const {
|
|
7209
|
+
onShow
|
|
7210
|
+
} = useContext(LayoutContext);
|
|
7211
|
+
const propertiesPanelContext = {
|
|
7212
|
+
...useContext(LayoutContext),
|
|
7213
|
+
onShow: useCallback(() => {
|
|
7214
|
+
setOpen(true);
|
|
7215
|
+
if (isFunction(onShow)) {
|
|
7216
|
+
onShow();
|
|
7217
|
+
}
|
|
7218
|
+
}, [onShow, setOpen])
|
|
7219
|
+
};
|
|
7220
|
+
|
|
7221
|
+
// todo(pinussilvestrus): translate once we have a translate mechanism for the core
|
|
7222
|
+
const placeholderLabel = '<empty>';
|
|
7223
|
+
return jsxs("div", {
|
|
7224
|
+
"data-entry-id": id,
|
|
7225
|
+
class: classnames('bio-properties-panel-collapsible-entry', open ? 'open' : ''),
|
|
7226
|
+
children: [jsxs("div", {
|
|
7227
|
+
class: "bio-properties-panel-collapsible-entry-header",
|
|
7228
|
+
onClick: toggleOpen,
|
|
7229
|
+
children: [jsx("div", {
|
|
7230
|
+
title: label || placeholderLabel,
|
|
7231
|
+
class: classnames('bio-properties-panel-collapsible-entry-header-title', !label && 'empty'),
|
|
7232
|
+
children: label || placeholderLabel
|
|
7233
|
+
}), jsx("button", {
|
|
7234
|
+
title: "Toggle list item",
|
|
7235
|
+
class: "bio-properties-panel-arrow bio-properties-panel-collapsible-entry-arrow",
|
|
7236
|
+
children: jsx(ArrowIcon, {
|
|
7237
|
+
class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
|
|
7238
|
+
})
|
|
7239
|
+
}), remove ? jsx("button", {
|
|
7240
|
+
title: "Delete item",
|
|
7241
|
+
class: "bio-properties-panel-remove-entry",
|
|
7242
|
+
onClick: remove,
|
|
7243
|
+
children: jsx(DeleteIcon, {})
|
|
7244
|
+
}) : null]
|
|
7245
|
+
}), jsx("div", {
|
|
7246
|
+
class: classnames('bio-properties-panel-collapsible-entry-entries', open ? 'open' : ''),
|
|
7247
|
+
children: jsx(LayoutContext.Provider, {
|
|
7248
|
+
value: propertiesPanelContext,
|
|
7249
|
+
children: entries.map(entry => {
|
|
7250
|
+
const {
|
|
7251
|
+
component: Component,
|
|
7252
|
+
id
|
|
7253
|
+
} = entry;
|
|
7254
|
+
return createElement(Component, {
|
|
7255
|
+
...entry,
|
|
7256
|
+
element: element,
|
|
7257
|
+
key: id
|
|
7258
|
+
});
|
|
7259
|
+
})
|
|
7260
|
+
})
|
|
7261
|
+
})]
|
|
7262
|
+
});
|
|
7263
|
+
}
|
|
7264
|
+
function ListItem(props) {
|
|
7265
|
+
const {
|
|
7266
|
+
autoFocusEntry,
|
|
7267
|
+
autoOpen
|
|
7268
|
+
} = props;
|
|
6715
7269
|
|
|
6716
|
-
//
|
|
6717
|
-
|
|
6718
|
-
|
|
6719
|
-
|
|
6720
|
-
const
|
|
6721
|
-
if (
|
|
6722
|
-
|
|
6723
|
-
|
|
6724
|
-
|
|
6725
|
-
|
|
6726
|
-
if (position > value.length) {
|
|
6727
|
-
position = value.length;
|
|
7270
|
+
// focus specified entry on auto open
|
|
7271
|
+
useEffect(() => {
|
|
7272
|
+
if (autoOpen && autoFocusEntry) {
|
|
7273
|
+
const entry = query(`[data-entry-id="${autoFocusEntry}"]`);
|
|
7274
|
+
const focusableInput = query('.bio-properties-panel-input', entry);
|
|
7275
|
+
if (focusableInput) {
|
|
7276
|
+
if (isFunction(focusableInput.select)) {
|
|
7277
|
+
focusableInput.select();
|
|
7278
|
+
} else if (isFunction(focusableInput.focus)) {
|
|
7279
|
+
focusableInput.focus();
|
|
6728
7280
|
}
|
|
6729
|
-
input.setSelectionRange(position, position);
|
|
6730
7281
|
}
|
|
6731
7282
|
}
|
|
6732
|
-
};
|
|
6733
|
-
return jsx(
|
|
6734
|
-
|
|
6735
|
-
|
|
6736
|
-
|
|
6737
|
-
|
|
6738
|
-
|
|
6739
|
-
max: max,
|
|
6740
|
-
min: min,
|
|
6741
|
-
onInput: onInput,
|
|
6742
|
-
step: step,
|
|
6743
|
-
value: value,
|
|
6744
|
-
onFocus: onFocus,
|
|
6745
|
-
onBlur: onBlur
|
|
7283
|
+
}, [autoOpen, autoFocusEntry]);
|
|
7284
|
+
return jsx("div", {
|
|
7285
|
+
class: "bio-properties-panel-list-item",
|
|
7286
|
+
children: jsx(CollapsibleEntry, {
|
|
7287
|
+
...props,
|
|
7288
|
+
open: autoOpen
|
|
7289
|
+
})
|
|
6746
7290
|
});
|
|
6747
|
-
}
|
|
6748
|
-
|
|
7291
|
+
}
|
|
7292
|
+
const noop$1 = () => {};
|
|
7293
|
+
|
|
7294
|
+
/**
|
|
7295
|
+
* @param {import('../PropertiesPanel').ListGroupDefinition} props
|
|
7296
|
+
*/
|
|
7297
|
+
function ListGroup(props) {
|
|
6749
7298
|
const {
|
|
7299
|
+
add,
|
|
7300
|
+
element,
|
|
6750
7301
|
id,
|
|
6751
|
-
|
|
6752
|
-
|
|
6753
|
-
|
|
6754
|
-
|
|
6755
|
-
onBlur
|
|
7302
|
+
items,
|
|
7303
|
+
label,
|
|
7304
|
+
shouldOpen = true,
|
|
7305
|
+
shouldSort = true
|
|
6756
7306
|
} = props;
|
|
6757
|
-
const
|
|
7307
|
+
const groupRef = useRef$1(null);
|
|
7308
|
+
const [open, setOpen] = useLayoutState(['groups', id, 'open'], false);
|
|
7309
|
+
const [sticky, setSticky] = useState(false);
|
|
7310
|
+
const onShow = useCallback(() => setOpen(true), [setOpen]);
|
|
7311
|
+
const [ordering, setOrdering] = useState([]);
|
|
7312
|
+
const [newItemAdded, setNewItemAdded] = useState(false);
|
|
6758
7313
|
|
|
6759
|
-
//
|
|
6760
|
-
|
|
6761
|
-
|
|
6762
|
-
|
|
6763
|
-
|
|
6764
|
-
|
|
6765
|
-
|
|
7314
|
+
// Flag to mark that add button was clicked in the last render cycle
|
|
7315
|
+
const [addTriggered, setAddTriggered] = useState(false);
|
|
7316
|
+
const prevItems = usePrevious(items);
|
|
7317
|
+
const prevElement = usePrevious(element);
|
|
7318
|
+
const elementChanged = element !== prevElement;
|
|
7319
|
+
const shouldHandleEffects = !elementChanged && (shouldSort || shouldOpen);
|
|
7320
|
+
|
|
7321
|
+
// reset initial ordering when element changes (before first render)
|
|
7322
|
+
if (elementChanged) {
|
|
7323
|
+
setOrdering(createOrdering(shouldSort ? sortItems(items) : items));
|
|
7324
|
+
}
|
|
7325
|
+
|
|
7326
|
+
// keep ordering in sync to items - and open changes
|
|
7327
|
+
|
|
7328
|
+
// (0) set initial ordering from given items
|
|
7329
|
+
useEffect(() => {
|
|
7330
|
+
if (!prevItems || !shouldSort) {
|
|
7331
|
+
setOrdering(createOrdering(items));
|
|
7332
|
+
}
|
|
7333
|
+
}, [items, element]);
|
|
7334
|
+
|
|
7335
|
+
// (1) items were added
|
|
7336
|
+
useEffect(() => {
|
|
7337
|
+
// reset addTriggered flag
|
|
7338
|
+
setAddTriggered(false);
|
|
7339
|
+
if (shouldHandleEffects && prevItems && items.length > prevItems.length) {
|
|
7340
|
+
let add = [];
|
|
7341
|
+
items.forEach(item => {
|
|
7342
|
+
if (!ordering.includes(item.id)) {
|
|
7343
|
+
add.push(item.id);
|
|
7344
|
+
}
|
|
7345
|
+
});
|
|
7346
|
+
let newOrdering = ordering;
|
|
7347
|
+
|
|
7348
|
+
// open if not open, configured and triggered by add button
|
|
7349
|
+
//
|
|
7350
|
+
// TODO(marstamm): remove once we refactor layout handling for listGroups.
|
|
7351
|
+
// Ideally, opening should be handled as part of the `add` callback and
|
|
7352
|
+
// not be a concern for the ListGroup component.
|
|
7353
|
+
if (addTriggered && !open && shouldOpen) {
|
|
7354
|
+
toggleOpen();
|
|
6766
7355
|
}
|
|
6767
|
-
|
|
6768
|
-
|
|
7356
|
+
|
|
7357
|
+
// filter when not open and configured
|
|
7358
|
+
if (!open && shouldSort) {
|
|
7359
|
+
newOrdering = createOrdering(sortItems(items));
|
|
7360
|
+
}
|
|
7361
|
+
|
|
7362
|
+
// add new items on top or bottom depending on sorting behavior
|
|
7363
|
+
newOrdering = newOrdering.filter(item => !add.includes(item));
|
|
7364
|
+
if (shouldSort) {
|
|
7365
|
+
newOrdering.unshift(...add);
|
|
7366
|
+
} else {
|
|
7367
|
+
newOrdering.push(...add);
|
|
7368
|
+
}
|
|
7369
|
+
setOrdering(newOrdering);
|
|
7370
|
+
setNewItemAdded(addTriggered);
|
|
7371
|
+
} else {
|
|
7372
|
+
setNewItemAdded(false);
|
|
7373
|
+
}
|
|
7374
|
+
}, [items, open, shouldHandleEffects, addTriggered]);
|
|
7375
|
+
|
|
7376
|
+
// (2) sort items on open if shouldSort is set
|
|
7377
|
+
useEffect(() => {
|
|
7378
|
+
if (shouldSort && open && !newItemAdded) {
|
|
7379
|
+
setOrdering(createOrdering(sortItems(items)));
|
|
7380
|
+
}
|
|
7381
|
+
}, [open, shouldSort]);
|
|
7382
|
+
|
|
7383
|
+
// (3) items were deleted
|
|
7384
|
+
useEffect(() => {
|
|
7385
|
+
if (shouldHandleEffects && prevItems && items.length < prevItems.length) {
|
|
7386
|
+
let keep = [];
|
|
7387
|
+
ordering.forEach(o => {
|
|
7388
|
+
if (getItem(items, o)) {
|
|
7389
|
+
keep.push(o);
|
|
7390
|
+
}
|
|
7391
|
+
});
|
|
7392
|
+
setOrdering(keep);
|
|
6769
7393
|
}
|
|
7394
|
+
}, [items, shouldHandleEffects]);
|
|
7395
|
+
|
|
7396
|
+
// set css class when group is sticky to top
|
|
7397
|
+
useStickyIntersectionObserver(groupRef, 'div.bio-properties-panel-scroll-container', setSticky);
|
|
7398
|
+
const toggleOpen = () => setOpen(!open);
|
|
7399
|
+
const hasItems = !!items.length;
|
|
7400
|
+
const propertiesPanelContext = {
|
|
7401
|
+
...useContext(LayoutContext),
|
|
7402
|
+
onShow
|
|
6770
7403
|
};
|
|
6771
|
-
|
|
6772
|
-
|
|
6773
|
-
|
|
6774
|
-
|
|
6775
|
-
|
|
6776
|
-
|
|
6777
|
-
|
|
6778
|
-
|
|
6779
|
-
|
|
6780
|
-
|
|
6781
|
-
|
|
6782
|
-
|
|
6783
|
-
|
|
6784
|
-
|
|
7404
|
+
const handleAddClick = e => {
|
|
7405
|
+
setAddTriggered(true);
|
|
7406
|
+
add(e);
|
|
7407
|
+
};
|
|
7408
|
+
const allErrors = useErrors();
|
|
7409
|
+
const hasError = items.some(item => {
|
|
7410
|
+
if (allErrors[item.id]) {
|
|
7411
|
+
return true;
|
|
7412
|
+
}
|
|
7413
|
+
if (!item.entries) {
|
|
7414
|
+
return;
|
|
7415
|
+
}
|
|
7416
|
+
|
|
7417
|
+
// also check if the error is nested, e.g. for name-value entries
|
|
7418
|
+
return item.entries.some(entry => allErrors[entry.id]);
|
|
6785
7419
|
});
|
|
6786
|
-
|
|
6787
|
-
|
|
6788
|
-
|
|
6789
|
-
|
|
6790
|
-
|
|
6791
|
-
|
|
6792
|
-
|
|
6793
|
-
|
|
6794
|
-
|
|
6795
|
-
|
|
6796
|
-
|
|
7420
|
+
return jsxs("div", {
|
|
7421
|
+
class: "bio-properties-panel-group",
|
|
7422
|
+
"data-group-id": 'group-' + id,
|
|
7423
|
+
ref: groupRef,
|
|
7424
|
+
children: [jsxs("div", {
|
|
7425
|
+
class: classnames('bio-properties-panel-group-header', hasItems ? '' : 'empty', hasItems && open ? 'open' : '', sticky && open ? 'sticky' : ''),
|
|
7426
|
+
onClick: hasItems ? toggleOpen : noop$1,
|
|
7427
|
+
children: [jsx("div", {
|
|
7428
|
+
title: label,
|
|
7429
|
+
class: "bio-properties-panel-group-header-title",
|
|
7430
|
+
children: jsx(TooltipWrapper, {
|
|
7431
|
+
value: props.tooltip,
|
|
7432
|
+
forId: 'group-' + id,
|
|
7433
|
+
element: element,
|
|
7434
|
+
parent: groupRef,
|
|
7435
|
+
children: label
|
|
7436
|
+
})
|
|
7437
|
+
}), jsxs("div", {
|
|
7438
|
+
class: "bio-properties-panel-group-header-buttons",
|
|
7439
|
+
children: [add ? jsxs("button", {
|
|
7440
|
+
title: "Create new list item",
|
|
7441
|
+
class: "bio-properties-panel-group-header-button bio-properties-panel-add-entry",
|
|
7442
|
+
onClick: handleAddClick,
|
|
7443
|
+
children: [jsx(CreateIcon, {}), !hasItems ? jsx("span", {
|
|
7444
|
+
class: "bio-properties-panel-add-entry-label",
|
|
7445
|
+
children: "Create"
|
|
7446
|
+
}) : null]
|
|
7447
|
+
}) : null, hasItems ? jsx("div", {
|
|
7448
|
+
title: `List contains ${items.length} item${items.length != 1 ? 's' : ''}`,
|
|
7449
|
+
class: classnames('bio-properties-panel-list-badge', hasError ? 'bio-properties-panel-list-badge--error' : ''),
|
|
7450
|
+
children: items.length
|
|
7451
|
+
}) : null, hasItems ? jsx("button", {
|
|
7452
|
+
title: "Toggle section",
|
|
7453
|
+
class: "bio-properties-panel-group-header-button bio-properties-panel-arrow",
|
|
7454
|
+
children: jsx(ArrowIcon, {
|
|
7455
|
+
class: open ? 'bio-properties-panel-arrow-down' : 'bio-properties-panel-arrow-right'
|
|
7456
|
+
})
|
|
7457
|
+
}) : null]
|
|
7458
|
+
})]
|
|
7459
|
+
}), jsx("div", {
|
|
7460
|
+
class: classnames('bio-properties-panel-list', open && hasItems ? 'open' : ''),
|
|
7461
|
+
children: jsx(LayoutContext.Provider, {
|
|
7462
|
+
value: propertiesPanelContext,
|
|
7463
|
+
children: ordering.map((o, index) => {
|
|
7464
|
+
const item = getItem(items, o);
|
|
7465
|
+
if (!item) {
|
|
7466
|
+
return;
|
|
7467
|
+
}
|
|
7468
|
+
const {
|
|
7469
|
+
id
|
|
7470
|
+
} = item;
|
|
6797
7471
|
|
|
6798
|
-
|
|
6799
|
-
|
|
6800
|
-
|
|
6801
|
-
|
|
6802
|
-
|
|
6803
|
-
|
|
6804
|
-
|
|
6805
|
-
|
|
6806
|
-
|
|
6807
|
-
|
|
6808
|
-
|
|
6809
|
-
|
|
6810
|
-
|
|
6811
|
-
value: value,
|
|
6812
|
-
inputRef: inputRef,
|
|
6813
|
-
onInput: onInput,
|
|
6814
|
-
onFocus: onFocus,
|
|
6815
|
-
onBlur: onBlur,
|
|
6816
|
-
switcherLabel: switcherLabel
|
|
7472
|
+
// if item was added, open it
|
|
7473
|
+
// Existing items will not be affected as autoOpen is only applied on first render
|
|
7474
|
+
const autoOpen = newItemAdded;
|
|
7475
|
+
return createElement(ListItem, {
|
|
7476
|
+
...item,
|
|
7477
|
+
autoOpen: autoOpen,
|
|
7478
|
+
element: element,
|
|
7479
|
+
index: index,
|
|
7480
|
+
key: id
|
|
7481
|
+
});
|
|
7482
|
+
})
|
|
7483
|
+
})
|
|
7484
|
+
})]
|
|
6817
7485
|
});
|
|
6818
|
-
}
|
|
6819
|
-
forwardRef((props, ref) => {
|
|
6820
|
-
const {
|
|
6821
|
-
id,
|
|
6822
|
-
disabled,
|
|
6823
|
-
onInput,
|
|
6824
|
-
value,
|
|
6825
|
-
onFocus,
|
|
6826
|
-
onBlur
|
|
6827
|
-
} = props;
|
|
6828
|
-
const inputRef = useRef$1();
|
|
6829
|
-
const handleChange = ({
|
|
6830
|
-
target
|
|
6831
|
-
}) => {
|
|
6832
|
-
onInput(target.checked);
|
|
6833
|
-
};
|
|
7486
|
+
}
|
|
6834
7487
|
|
|
6835
|
-
|
|
6836
|
-
// this ensures clean editing experience when switching with the keyboard
|
|
6837
|
-
ref.current = {
|
|
6838
|
-
focus: () => {
|
|
6839
|
-
const input = inputRef.current;
|
|
6840
|
-
if (!input) {
|
|
6841
|
-
return;
|
|
6842
|
-
}
|
|
6843
|
-
input.focus();
|
|
6844
|
-
}
|
|
6845
|
-
};
|
|
6846
|
-
return jsx("input", {
|
|
6847
|
-
ref: inputRef,
|
|
6848
|
-
id: prefixId$4(id),
|
|
6849
|
-
name: id,
|
|
6850
|
-
onFocus: onFocus,
|
|
6851
|
-
onBlur: onBlur,
|
|
6852
|
-
type: "checkbox",
|
|
6853
|
-
class: "bio-properties-panel-input",
|
|
6854
|
-
onChange: handleChange,
|
|
6855
|
-
checked: value,
|
|
6856
|
-
disabled: disabled
|
|
6857
|
-
});
|
|
6858
|
-
});
|
|
7488
|
+
// helpers ////////////////////
|
|
6859
7489
|
|
|
6860
7490
|
/**
|
|
6861
|
-
*
|
|
6862
|
-
* @param {Object} props.element
|
|
6863
|
-
* @param {String} props.id
|
|
6864
|
-
* @param {String} props.description
|
|
6865
|
-
* @param {Boolean} props.debounce
|
|
6866
|
-
* @param {Boolean} props.disabled
|
|
6867
|
-
* @param {Boolean} props.feel
|
|
6868
|
-
* @param {String} props.label
|
|
6869
|
-
* @param {Function} props.getValue
|
|
6870
|
-
* @param {Function} props.setValue
|
|
6871
|
-
* @param {Function} props.tooltipContainer
|
|
6872
|
-
* @param {Function} props.validate
|
|
6873
|
-
* @param {Function} props.show
|
|
6874
|
-
* @param {Function} props.example
|
|
6875
|
-
* @param {Function} props.variables
|
|
6876
|
-
* @param {Function} props.onFocus
|
|
6877
|
-
* @param {Function} props.onBlur
|
|
6878
|
-
* @param {string|import('preact').Component} props.tooltip
|
|
7491
|
+
* Sorts given items alphanumeric by label
|
|
6879
7492
|
*/
|
|
6880
|
-
function
|
|
7493
|
+
function sortItems(items) {
|
|
7494
|
+
return sortBy(items, i => i.label.toLowerCase());
|
|
7495
|
+
}
|
|
7496
|
+
function getItem(items, id) {
|
|
7497
|
+
return find(items, i => i.id === id);
|
|
7498
|
+
}
|
|
7499
|
+
function createOrdering(items) {
|
|
7500
|
+
return items.map(i => i.id);
|
|
7501
|
+
}
|
|
7502
|
+
function Checkbox(props) {
|
|
6881
7503
|
const {
|
|
6882
|
-
element,
|
|
6883
7504
|
id,
|
|
6884
|
-
description,
|
|
6885
|
-
debounce,
|
|
6886
|
-
disabled,
|
|
6887
|
-
feel,
|
|
6888
7505
|
label,
|
|
6889
|
-
|
|
6890
|
-
|
|
6891
|
-
|
|
6892
|
-
hostLanguage,
|
|
6893
|
-
singleLine,
|
|
6894
|
-
validate,
|
|
6895
|
-
show = noop$1,
|
|
6896
|
-
example,
|
|
6897
|
-
variables,
|
|
7506
|
+
onChange,
|
|
7507
|
+
disabled,
|
|
7508
|
+
value = false,
|
|
6898
7509
|
onFocus,
|
|
6899
7510
|
onBlur,
|
|
6900
7511
|
tooltip
|
|
6901
7512
|
} = props;
|
|
6902
|
-
const [
|
|
6903
|
-
const
|
|
6904
|
-
|
|
7513
|
+
const [localValue, setLocalValue] = useState(value);
|
|
7514
|
+
const handleChangeCallback = ({
|
|
7515
|
+
target
|
|
7516
|
+
}) => {
|
|
7517
|
+
onChange(target.checked);
|
|
7518
|
+
};
|
|
7519
|
+
const handleChange = e => {
|
|
7520
|
+
handleChangeCallback(e);
|
|
7521
|
+
setLocalValue(e.target.value);
|
|
7522
|
+
};
|
|
6905
7523
|
useEffect(() => {
|
|
6906
|
-
if (
|
|
6907
|
-
|
|
6908
|
-
setValidationError(newValidationError);
|
|
7524
|
+
if (value === localValue) {
|
|
7525
|
+
return;
|
|
6909
7526
|
}
|
|
7527
|
+
setLocalValue(value);
|
|
6910
7528
|
}, [value]);
|
|
6911
|
-
const
|
|
6912
|
-
let newValidationError = null;
|
|
6913
|
-
if (isFunction(validate)) {
|
|
6914
|
-
newValidationError = validate(newValue) || null;
|
|
6915
|
-
}
|
|
6916
|
-
|
|
6917
|
-
// don't create multiple commandStack entries for the same value
|
|
6918
|
-
if (newValue !== value) {
|
|
6919
|
-
setValue(newValue, newValidationError);
|
|
6920
|
-
}
|
|
6921
|
-
setValidationError(newValidationError);
|
|
6922
|
-
});
|
|
6923
|
-
const onError = useCallback(err => {
|
|
6924
|
-
setLocalError(err);
|
|
6925
|
-
}, []);
|
|
6926
|
-
const temporaryError = useError(id);
|
|
6927
|
-
const error = localError || temporaryError || validationError;
|
|
7529
|
+
const ref = useShowEntryEvent(id);
|
|
6928
7530
|
return jsxs("div", {
|
|
6929
|
-
class:
|
|
6930
|
-
"
|
|
6931
|
-
|
|
6932
|
-
|
|
6933
|
-
|
|
6934
|
-
disabled: disabled,
|
|
6935
|
-
feel: feel,
|
|
6936
|
-
id: id,
|
|
6937
|
-
key: element,
|
|
6938
|
-
label: label,
|
|
6939
|
-
onInput: onInput,
|
|
6940
|
-
onError: onError,
|
|
7531
|
+
class: "bio-properties-panel-checkbox",
|
|
7532
|
+
children: [jsx("input", {
|
|
7533
|
+
ref: ref,
|
|
7534
|
+
id: prefixId$4(id),
|
|
7535
|
+
name: id,
|
|
6941
7536
|
onFocus: onFocus,
|
|
6942
7537
|
onBlur: onBlur,
|
|
6943
|
-
|
|
6944
|
-
|
|
6945
|
-
|
|
6946
|
-
|
|
6947
|
-
|
|
6948
|
-
|
|
6949
|
-
|
|
6950
|
-
|
|
6951
|
-
|
|
6952
|
-
|
|
6953
|
-
|
|
6954
|
-
|
|
6955
|
-
|
|
6956
|
-
|
|
6957
|
-
|
|
6958
|
-
value: description
|
|
6959
|
-
})]
|
|
6960
|
-
});
|
|
6961
|
-
}
|
|
6962
|
-
|
|
6963
|
-
/**
|
|
6964
|
-
* @param {Object} props
|
|
6965
|
-
* @param {Object} props.element
|
|
6966
|
-
* @param {String} props.id
|
|
6967
|
-
* @param {String} props.description
|
|
6968
|
-
* @param {Boolean} props.debounce
|
|
6969
|
-
* @param {Boolean} props.disabled
|
|
6970
|
-
* @param {String} props.max
|
|
6971
|
-
* @param {String} props.min
|
|
6972
|
-
* @param {String} props.step
|
|
6973
|
-
* @param {Boolean} props.feel
|
|
6974
|
-
* @param {String} props.label
|
|
6975
|
-
* @param {Function} props.getValue
|
|
6976
|
-
* @param {Function} props.setValue
|
|
6977
|
-
* @param {Function} props.tooltipContainer
|
|
6978
|
-
* @param {Function} props.validate
|
|
6979
|
-
* @param {Function} props.show
|
|
6980
|
-
* @param {Function} props.example
|
|
6981
|
-
* @param {Function} props.variables
|
|
6982
|
-
* @param {Function} props.onFocus
|
|
6983
|
-
* @param {Function} props.onBlur
|
|
6984
|
-
*/
|
|
6985
|
-
function FeelNumberEntry(props) {
|
|
6986
|
-
return jsx(FeelEntry, {
|
|
6987
|
-
class: "bio-properties-panel-feel-number",
|
|
6988
|
-
OptionalComponent: OptionalFeelNumberField,
|
|
6989
|
-
...props
|
|
6990
|
-
});
|
|
6991
|
-
}
|
|
6992
|
-
|
|
6993
|
-
/**
|
|
6994
|
-
* @param {Object} props
|
|
6995
|
-
* @param {Object} props.element
|
|
6996
|
-
* @param {String} props.id
|
|
6997
|
-
* @param {String} props.description
|
|
6998
|
-
* @param {Boolean} props.debounce
|
|
6999
|
-
* @param {Boolean} props.disabled
|
|
7000
|
-
* @param {Boolean} props.feel
|
|
7001
|
-
* @param {String} props.label
|
|
7002
|
-
* @param {Function} props.getValue
|
|
7003
|
-
* @param {Function} props.setValue
|
|
7004
|
-
* @param {Function} props.tooltipContainer
|
|
7005
|
-
* @param {Function} props.validate
|
|
7006
|
-
* @param {Function} props.show
|
|
7007
|
-
* @param {Function} props.example
|
|
7008
|
-
* @param {Function} props.variables
|
|
7009
|
-
* @param {Function} props.onFocus
|
|
7010
|
-
* @param {Function} props.onBlur
|
|
7011
|
-
*/
|
|
7012
|
-
function FeelToggleSwitchEntry(props) {
|
|
7013
|
-
return jsx(FeelEntry, {
|
|
7014
|
-
class: "bio-properties-panel-feel-toggle-switch",
|
|
7015
|
-
OptionalComponent: OptionalFeelToggleSwitch,
|
|
7016
|
-
...props
|
|
7538
|
+
type: "checkbox",
|
|
7539
|
+
class: "bio-properties-panel-input",
|
|
7540
|
+
onChange: handleChange,
|
|
7541
|
+
checked: localValue,
|
|
7542
|
+
disabled: disabled
|
|
7543
|
+
}), jsx("label", {
|
|
7544
|
+
for: prefixId$4(id),
|
|
7545
|
+
class: "bio-properties-panel-label",
|
|
7546
|
+
children: jsx(TooltipWrapper, {
|
|
7547
|
+
value: tooltip,
|
|
7548
|
+
forId: id,
|
|
7549
|
+
element: props.element,
|
|
7550
|
+
children: label
|
|
7551
|
+
})
|
|
7552
|
+
})]
|
|
7017
7553
|
});
|
|
7018
7554
|
}
|
|
7019
7555
|
|
|
@@ -7022,37 +7558,54 @@ function FeelToggleSwitchEntry(props) {
|
|
|
7022
7558
|
* @param {Object} props.element
|
|
7023
7559
|
* @param {String} props.id
|
|
7024
7560
|
* @param {String} props.description
|
|
7025
|
-
* @param {String} props.hostLanguage
|
|
7026
|
-
* @param {Boolean} props.singleLine
|
|
7027
|
-
* @param {Boolean} props.debounce
|
|
7028
|
-
* @param {Boolean} props.disabled
|
|
7029
|
-
* @param {Boolean} props.feel
|
|
7030
7561
|
* @param {String} props.label
|
|
7031
7562
|
* @param {Function} props.getValue
|
|
7032
7563
|
* @param {Function} props.setValue
|
|
7033
|
-
* @param {Function} props.tooltipContainer
|
|
7034
|
-
* @param {Function} props.validate
|
|
7035
|
-
* @param {Function} props.show
|
|
7036
|
-
* @param {Function} props.example
|
|
7037
|
-
* @param {Function} props.variables
|
|
7038
7564
|
* @param {Function} props.onFocus
|
|
7039
7565
|
* @param {Function} props.onBlur
|
|
7566
|
+
* @param {string|import('preact').Component} props.tooltip
|
|
7567
|
+
* @param {boolean} [props.disabled]
|
|
7040
7568
|
*/
|
|
7041
|
-
function
|
|
7042
|
-
|
|
7043
|
-
|
|
7044
|
-
|
|
7045
|
-
|
|
7569
|
+
function CheckboxEntry(props) {
|
|
7570
|
+
const {
|
|
7571
|
+
element,
|
|
7572
|
+
id,
|
|
7573
|
+
description,
|
|
7574
|
+
label,
|
|
7575
|
+
getValue,
|
|
7576
|
+
setValue,
|
|
7577
|
+
disabled,
|
|
7578
|
+
onFocus,
|
|
7579
|
+
onBlur,
|
|
7580
|
+
tooltip
|
|
7581
|
+
} = props;
|
|
7582
|
+
const value = getValue(element);
|
|
7583
|
+
const error = useError(id);
|
|
7584
|
+
return jsxs("div", {
|
|
7585
|
+
class: "bio-properties-panel-entry bio-properties-panel-checkbox-entry",
|
|
7586
|
+
"data-entry-id": id,
|
|
7587
|
+
children: [jsx(Checkbox, {
|
|
7588
|
+
disabled: disabled,
|
|
7589
|
+
id: id,
|
|
7590
|
+
label: label,
|
|
7591
|
+
onChange: setValue,
|
|
7592
|
+
onFocus: onFocus,
|
|
7593
|
+
onBlur: onBlur,
|
|
7594
|
+
value: value,
|
|
7595
|
+
tooltip: tooltip,
|
|
7596
|
+
element: element
|
|
7597
|
+
}, element), error && jsx("div", {
|
|
7598
|
+
class: "bio-properties-panel-error",
|
|
7599
|
+
children: error
|
|
7600
|
+
}), jsx(Description$1, {
|
|
7601
|
+
forId: id,
|
|
7602
|
+
element: element,
|
|
7603
|
+
value: description
|
|
7604
|
+
})]
|
|
7046
7605
|
});
|
|
7047
7606
|
}
|
|
7048
7607
|
function isEdited$5(node) {
|
|
7049
|
-
|
|
7050
|
-
return false;
|
|
7051
|
-
}
|
|
7052
|
-
if (node.type === 'checkbox') {
|
|
7053
|
-
return !!node.checked || node.classList.contains('edited');
|
|
7054
|
-
}
|
|
7055
|
-
return !!node.value || node.classList.contains('edited');
|
|
7608
|
+
return node && !!node.checked;
|
|
7056
7609
|
}
|
|
7057
7610
|
|
|
7058
7611
|
// helpers /////////////////
|
|
@@ -7548,6 +8101,9 @@ function textToLabel(text) {
|
|
|
7548
8101
|
}
|
|
7549
8102
|
return null;
|
|
7550
8103
|
}
|
|
8104
|
+
function isValidDotPath(path) {
|
|
8105
|
+
return /^\w+(\.\w+)*$/.test(path);
|
|
8106
|
+
}
|
|
7551
8107
|
const INPUTS = ['checkbox', 'checklist', 'datetime', 'number', 'radio', 'select', 'taglist', 'textfield', 'textarea'];
|
|
7552
8108
|
const VALUES_INPUTS = ['checklist', 'radio', 'select', 'taglist'];
|
|
7553
8109
|
|
|
@@ -7558,6 +8114,7 @@ const labelsByType = {
|
|
|
7558
8114
|
columns: 'COLUMNS',
|
|
7559
8115
|
default: 'FORM',
|
|
7560
8116
|
datetime: 'DATETIME',
|
|
8117
|
+
group: 'GROUP',
|
|
7561
8118
|
image: 'IMAGE VIEW',
|
|
7562
8119
|
number: 'NUMBER',
|
|
7563
8120
|
radio: 'RADIO',
|
|
@@ -7573,6 +8130,9 @@ const PropertiesPanelHeaderProvider = {
|
|
|
7573
8130
|
const {
|
|
7574
8131
|
type
|
|
7575
8132
|
} = field;
|
|
8133
|
+
if (type === 'spacer') {
|
|
8134
|
+
return '';
|
|
8135
|
+
}
|
|
7576
8136
|
if (type === 'text') {
|
|
7577
8137
|
return textToLabel(field.text);
|
|
7578
8138
|
}
|
|
@@ -7704,7 +8264,7 @@ function AltTextEntry(props) {
|
|
|
7704
8264
|
component: AltText,
|
|
7705
8265
|
editField: editField,
|
|
7706
8266
|
field: field,
|
|
7707
|
-
isEdited: isEdited$
|
|
8267
|
+
isEdited: isEdited$6
|
|
7708
8268
|
});
|
|
7709
8269
|
}
|
|
7710
8270
|
return entries;
|
|
@@ -7827,7 +8387,7 @@ function DescriptionEntry(props) {
|
|
|
7827
8387
|
component: Description,
|
|
7828
8388
|
editField: editField,
|
|
7829
8389
|
field: field,
|
|
7830
|
-
isEdited: isEdited$
|
|
8390
|
+
isEdited: isEdited$6
|
|
7831
8391
|
});
|
|
7832
8392
|
}
|
|
7833
8393
|
return entries;
|
|
@@ -8114,7 +8674,7 @@ function DisabledEntry(props) {
|
|
|
8114
8674
|
component: Disabled,
|
|
8115
8675
|
editField: editField,
|
|
8116
8676
|
field: field,
|
|
8117
|
-
isEdited: isEdited$
|
|
8677
|
+
isEdited: isEdited$8
|
|
8118
8678
|
});
|
|
8119
8679
|
}
|
|
8120
8680
|
return entries;
|
|
@@ -8249,7 +8809,7 @@ function Key$1(props) {
|
|
|
8249
8809
|
field,
|
|
8250
8810
|
id
|
|
8251
8811
|
} = props;
|
|
8252
|
-
const
|
|
8812
|
+
const pathRegistry = useService('pathRegistry');
|
|
8253
8813
|
const debounce = useService('debounce');
|
|
8254
8814
|
const path = ['key'];
|
|
8255
8815
|
const getValue = () => {
|
|
@@ -8262,17 +8822,32 @@ function Key$1(props) {
|
|
|
8262
8822
|
return editField(field, path, value);
|
|
8263
8823
|
};
|
|
8264
8824
|
const validate = value => {
|
|
8825
|
+
if (value === field.key) {
|
|
8826
|
+
return null;
|
|
8827
|
+
}
|
|
8265
8828
|
if (isUndefined(value) || !value.length) {
|
|
8266
8829
|
return 'Must not be empty.';
|
|
8267
8830
|
}
|
|
8268
|
-
if (
|
|
8269
|
-
return 'Must
|
|
8831
|
+
if (value && !isValidDotPath(value)) {
|
|
8832
|
+
return 'Must be a variable or a dot separated path.';
|
|
8270
8833
|
}
|
|
8271
|
-
const
|
|
8272
|
-
if (
|
|
8273
|
-
return 'Must
|
|
8834
|
+
const hasIntegerPathSegment = value.split('.').some(segment => /^\d+$/.test(segment));
|
|
8835
|
+
if (hasIntegerPathSegment) {
|
|
8836
|
+
return 'Must not contain numerical path segments.';
|
|
8274
8837
|
}
|
|
8275
|
-
|
|
8838
|
+
const replacements = {
|
|
8839
|
+
[field.id]: value.split('.')
|
|
8840
|
+
};
|
|
8841
|
+
const oldPath = pathRegistry.getValuePath(field);
|
|
8842
|
+
const newPath = pathRegistry.getValuePath(field, {
|
|
8843
|
+
replacements
|
|
8844
|
+
});
|
|
8845
|
+
|
|
8846
|
+
// unclaim temporarily to avoid self-conflicts
|
|
8847
|
+
pathRegistry.unclaimPath(oldPath);
|
|
8848
|
+
const canClaim = pathRegistry.canClaimPath(newPath, true);
|
|
8849
|
+
pathRegistry.claimPath(oldPath, true);
|
|
8850
|
+
return canClaim ? null : 'Must not conflict with other key/path assignments.';
|
|
8276
8851
|
};
|
|
8277
8852
|
return TextfieldEntry({
|
|
8278
8853
|
debounce,
|
|
@@ -8287,6 +8862,147 @@ function Key$1(props) {
|
|
|
8287
8862
|
});
|
|
8288
8863
|
}
|
|
8289
8864
|
|
|
8865
|
+
function PathEntry(props) {
|
|
8866
|
+
const {
|
|
8867
|
+
editField,
|
|
8868
|
+
field
|
|
8869
|
+
} = props;
|
|
8870
|
+
const {
|
|
8871
|
+
type
|
|
8872
|
+
} = field;
|
|
8873
|
+
const entries = [];
|
|
8874
|
+
if (type === 'group') {
|
|
8875
|
+
entries.push({
|
|
8876
|
+
id: 'path',
|
|
8877
|
+
component: Path,
|
|
8878
|
+
editField: editField,
|
|
8879
|
+
field: field,
|
|
8880
|
+
isEdited: isEdited
|
|
8881
|
+
});
|
|
8882
|
+
}
|
|
8883
|
+
return entries;
|
|
8884
|
+
}
|
|
8885
|
+
function Path(props) {
|
|
8886
|
+
const {
|
|
8887
|
+
editField,
|
|
8888
|
+
field,
|
|
8889
|
+
id
|
|
8890
|
+
} = props;
|
|
8891
|
+
const debounce = useService('debounce');
|
|
8892
|
+
const pathRegistry = useService('pathRegistry');
|
|
8893
|
+
const path = ['path'];
|
|
8894
|
+
const getValue = () => {
|
|
8895
|
+
return get(field, path, '');
|
|
8896
|
+
};
|
|
8897
|
+
const setValue = (value, error) => {
|
|
8898
|
+
if (error) {
|
|
8899
|
+
return;
|
|
8900
|
+
}
|
|
8901
|
+
return editField(field, path, value);
|
|
8902
|
+
};
|
|
8903
|
+
const validate = value => {
|
|
8904
|
+
if (!value || value === field.path) {
|
|
8905
|
+
return null;
|
|
8906
|
+
}
|
|
8907
|
+
if (value && !isValidDotPath(value)) {
|
|
8908
|
+
return 'Must be empty, a variable or a dot separated path';
|
|
8909
|
+
}
|
|
8910
|
+
const hasIntegerPathSegment = value && value.split('.').some(segment => /^\d+$/.test(segment));
|
|
8911
|
+
if (hasIntegerPathSegment) {
|
|
8912
|
+
return 'Must not contain numerical path segments.';
|
|
8913
|
+
}
|
|
8914
|
+
const options = value && {
|
|
8915
|
+
replacements: {
|
|
8916
|
+
[field.id]: [value]
|
|
8917
|
+
}
|
|
8918
|
+
} || {};
|
|
8919
|
+
const canClaim = pathRegistry.executeRecursivelyOnFields(field, ({
|
|
8920
|
+
field,
|
|
8921
|
+
isClosed
|
|
8922
|
+
}) => {
|
|
8923
|
+
const path = pathRegistry.getValuePath(field, options);
|
|
8924
|
+
return pathRegistry.canClaimPath(path, isClosed);
|
|
8925
|
+
});
|
|
8926
|
+
if (!canClaim) {
|
|
8927
|
+
return 'Must not cause two binding paths to colide';
|
|
8928
|
+
}
|
|
8929
|
+
};
|
|
8930
|
+
return TextfieldEntry({
|
|
8931
|
+
debounce,
|
|
8932
|
+
description: 'Where the child variables of this component are pathed to.',
|
|
8933
|
+
element: field,
|
|
8934
|
+
getValue,
|
|
8935
|
+
id,
|
|
8936
|
+
label: 'Path',
|
|
8937
|
+
tooltip: 'Routes the children of this component into a form variable, may be left empty to route at the root level.',
|
|
8938
|
+
setValue,
|
|
8939
|
+
validate
|
|
8940
|
+
});
|
|
8941
|
+
}
|
|
8942
|
+
|
|
8943
|
+
function simpleBoolEntryFactory(options) {
|
|
8944
|
+
const {
|
|
8945
|
+
id,
|
|
8946
|
+
label,
|
|
8947
|
+
description,
|
|
8948
|
+
path,
|
|
8949
|
+
props
|
|
8950
|
+
} = options;
|
|
8951
|
+
const {
|
|
8952
|
+
editField,
|
|
8953
|
+
field
|
|
8954
|
+
} = props;
|
|
8955
|
+
return {
|
|
8956
|
+
id,
|
|
8957
|
+
label,
|
|
8958
|
+
path,
|
|
8959
|
+
field,
|
|
8960
|
+
editField,
|
|
8961
|
+
description,
|
|
8962
|
+
component: SimpleBoolComponent,
|
|
8963
|
+
isEdited: isEdited$5
|
|
8964
|
+
};
|
|
8965
|
+
}
|
|
8966
|
+
const SimpleBoolComponent = props => {
|
|
8967
|
+
const {
|
|
8968
|
+
id,
|
|
8969
|
+
label,
|
|
8970
|
+
path,
|
|
8971
|
+
field,
|
|
8972
|
+
editField,
|
|
8973
|
+
description
|
|
8974
|
+
} = props;
|
|
8975
|
+
const getValue = () => get(field, path, '');
|
|
8976
|
+
const setValue = value => editField(field, path, value || false);
|
|
8977
|
+
return CheckboxEntry({
|
|
8978
|
+
element: field,
|
|
8979
|
+
getValue,
|
|
8980
|
+
id,
|
|
8981
|
+
label,
|
|
8982
|
+
setValue,
|
|
8983
|
+
description
|
|
8984
|
+
});
|
|
8985
|
+
};
|
|
8986
|
+
|
|
8987
|
+
function GroupEntries(props) {
|
|
8988
|
+
const {
|
|
8989
|
+
field
|
|
8990
|
+
} = props;
|
|
8991
|
+
const {
|
|
8992
|
+
type
|
|
8993
|
+
} = field;
|
|
8994
|
+
if (type !== 'group') {
|
|
8995
|
+
return [];
|
|
8996
|
+
}
|
|
8997
|
+
const entries = [simpleBoolEntryFactory({
|
|
8998
|
+
id: 'showOutline',
|
|
8999
|
+
path: ['showOutline'],
|
|
9000
|
+
label: 'Show outline',
|
|
9001
|
+
props
|
|
9002
|
+
})];
|
|
9003
|
+
return entries;
|
|
9004
|
+
}
|
|
9005
|
+
|
|
8290
9006
|
function LabelEntry(props) {
|
|
8291
9007
|
const {
|
|
8292
9008
|
field,
|
|
@@ -8304,7 +9020,7 @@ function LabelEntry(props) {
|
|
|
8304
9020
|
component: DateLabel,
|
|
8305
9021
|
editField,
|
|
8306
9022
|
field,
|
|
8307
|
-
isEdited: isEdited$
|
|
9023
|
+
isEdited: isEdited$6
|
|
8308
9024
|
});
|
|
8309
9025
|
}
|
|
8310
9026
|
if (subtype === DATETIME_SUBTYPES.TIME || subtype === DATETIME_SUBTYPES.DATETIME) {
|
|
@@ -8313,16 +9029,16 @@ function LabelEntry(props) {
|
|
|
8313
9029
|
component: TimeLabel,
|
|
8314
9030
|
editField,
|
|
8315
9031
|
field,
|
|
8316
|
-
isEdited: isEdited$
|
|
9032
|
+
isEdited: isEdited$6
|
|
8317
9033
|
});
|
|
8318
9034
|
}
|
|
8319
|
-
} else if (INPUTS.includes(type) || type === 'button') {
|
|
9035
|
+
} else if (INPUTS.includes(type) || type === 'button' || type === 'group') {
|
|
8320
9036
|
entries.push({
|
|
8321
9037
|
id: 'label',
|
|
8322
9038
|
component: Label$1,
|
|
8323
9039
|
editField,
|
|
8324
9040
|
field,
|
|
8325
|
-
isEdited: isEdited$
|
|
9041
|
+
isEdited: isEdited$6
|
|
8326
9042
|
});
|
|
8327
9043
|
}
|
|
8328
9044
|
return entries;
|
|
@@ -8344,12 +9060,13 @@ function Label$1(props) {
|
|
|
8344
9060
|
const setValue = value => {
|
|
8345
9061
|
return editField(field, path, value || '');
|
|
8346
9062
|
};
|
|
9063
|
+
const label = field.type === 'group' ? 'Group label' : 'Field label';
|
|
8347
9064
|
return FeelTemplatingEntry({
|
|
8348
9065
|
debounce,
|
|
8349
9066
|
element: field,
|
|
8350
9067
|
getValue,
|
|
8351
9068
|
id,
|
|
8352
|
-
label
|
|
9069
|
+
label,
|
|
8353
9070
|
singleLine: true,
|
|
8354
9071
|
setValue,
|
|
8355
9072
|
variables
|
|
@@ -8427,7 +9144,7 @@ function SourceEntry(props) {
|
|
|
8427
9144
|
component: Source,
|
|
8428
9145
|
editField: editField,
|
|
8429
9146
|
field: field,
|
|
8430
|
-
isEdited: isEdited$
|
|
9147
|
+
isEdited: isEdited$6
|
|
8431
9148
|
});
|
|
8432
9149
|
}
|
|
8433
9150
|
return entries;
|
|
@@ -8484,7 +9201,7 @@ function TextEntry(props) {
|
|
|
8484
9201
|
component: Text,
|
|
8485
9202
|
editField: editField,
|
|
8486
9203
|
field: field,
|
|
8487
|
-
isEdited: isEdited$
|
|
9204
|
+
isEdited: isEdited$6
|
|
8488
9205
|
}];
|
|
8489
9206
|
|
|
8490
9207
|
// todo: skipped to make the release without too much risk
|
|
@@ -8553,7 +9270,7 @@ function SpacerEntry(props) {
|
|
|
8553
9270
|
entries.push({
|
|
8554
9271
|
id: id + '-height',
|
|
8555
9272
|
component: SpacerHeight,
|
|
8556
|
-
isEdited: isEdited$
|
|
9273
|
+
isEdited: isEdited$7,
|
|
8557
9274
|
editField,
|
|
8558
9275
|
field
|
|
8559
9276
|
});
|
|
@@ -8604,7 +9321,7 @@ function NumberEntries(props) {
|
|
|
8604
9321
|
entries.push({
|
|
8605
9322
|
id: id + '-decimalDigits',
|
|
8606
9323
|
component: NumberDecimalDigits,
|
|
8607
|
-
isEdited: isEdited$
|
|
9324
|
+
isEdited: isEdited$7,
|
|
8608
9325
|
editField,
|
|
8609
9326
|
field
|
|
8610
9327
|
});
|
|
@@ -8708,7 +9425,7 @@ function NumberSerializationEntry(props) {
|
|
|
8708
9425
|
entries.push({
|
|
8709
9426
|
id: 'serialize-to-string',
|
|
8710
9427
|
component: SerializeToString,
|
|
8711
|
-
isEdited: isEdited$
|
|
9428
|
+
isEdited: isEdited$5,
|
|
8712
9429
|
editField,
|
|
8713
9430
|
field
|
|
8714
9431
|
});
|
|
@@ -8767,7 +9484,7 @@ function DateTimeEntry(props) {
|
|
|
8767
9484
|
entries.push({
|
|
8768
9485
|
id: 'use24h',
|
|
8769
9486
|
component: Use24h,
|
|
8770
|
-
isEdited: isEdited$
|
|
9487
|
+
isEdited: isEdited$5,
|
|
8771
9488
|
editField,
|
|
8772
9489
|
field
|
|
8773
9490
|
});
|
|
@@ -8880,7 +9597,7 @@ function DateTimeConstraintsEntry(props) {
|
|
|
8880
9597
|
entries.push({
|
|
8881
9598
|
id: id + '-disallowPassedDates',
|
|
8882
9599
|
component: DisallowPassedDates,
|
|
8883
|
-
isEdited: isEdited$
|
|
9600
|
+
isEdited: isEdited$5,
|
|
8884
9601
|
editField,
|
|
8885
9602
|
field
|
|
8886
9603
|
});
|
|
@@ -8981,50 +9698,6 @@ function TimeFormatSelect(props) {
|
|
|
8981
9698
|
});
|
|
8982
9699
|
}
|
|
8983
9700
|
|
|
8984
|
-
function simpleBoolEntryFactory(options) {
|
|
8985
|
-
const {
|
|
8986
|
-
id,
|
|
8987
|
-
label,
|
|
8988
|
-
description,
|
|
8989
|
-
path,
|
|
8990
|
-
props
|
|
8991
|
-
} = options;
|
|
8992
|
-
const {
|
|
8993
|
-
editField,
|
|
8994
|
-
field
|
|
8995
|
-
} = props;
|
|
8996
|
-
return {
|
|
8997
|
-
id,
|
|
8998
|
-
label,
|
|
8999
|
-
path,
|
|
9000
|
-
field,
|
|
9001
|
-
editField,
|
|
9002
|
-
description,
|
|
9003
|
-
component: SimpleBoolComponent,
|
|
9004
|
-
isEdited: isEdited$8
|
|
9005
|
-
};
|
|
9006
|
-
}
|
|
9007
|
-
const SimpleBoolComponent = props => {
|
|
9008
|
-
const {
|
|
9009
|
-
id,
|
|
9010
|
-
label,
|
|
9011
|
-
path,
|
|
9012
|
-
field,
|
|
9013
|
-
editField,
|
|
9014
|
-
description
|
|
9015
|
-
} = props;
|
|
9016
|
-
const getValue = () => get(field, path, '');
|
|
9017
|
-
const setValue = value => editField(field, path, value);
|
|
9018
|
-
return CheckboxEntry({
|
|
9019
|
-
element: field,
|
|
9020
|
-
getValue,
|
|
9021
|
-
id,
|
|
9022
|
-
label,
|
|
9023
|
-
setValue,
|
|
9024
|
-
description
|
|
9025
|
-
});
|
|
9026
|
-
};
|
|
9027
|
-
|
|
9028
9701
|
function SelectEntries(props) {
|
|
9029
9702
|
const {
|
|
9030
9703
|
field
|
|
@@ -9506,7 +10179,7 @@ function AdornerEntry(props) {
|
|
|
9506
10179
|
entries.push({
|
|
9507
10180
|
id: 'prefix-adorner',
|
|
9508
10181
|
component: PrefixAdorner,
|
|
9509
|
-
isEdited: isEdited$
|
|
10182
|
+
isEdited: isEdited$6,
|
|
9510
10183
|
editField,
|
|
9511
10184
|
field,
|
|
9512
10185
|
onChange,
|
|
@@ -9515,7 +10188,7 @@ function AdornerEntry(props) {
|
|
|
9515
10188
|
entries.push({
|
|
9516
10189
|
id: 'suffix-adorner',
|
|
9517
10190
|
component: SuffixAdorner,
|
|
9518
|
-
isEdited: isEdited$
|
|
10191
|
+
isEdited: isEdited$6,
|
|
9519
10192
|
editField,
|
|
9520
10193
|
field,
|
|
9521
10194
|
onChange,
|
|
@@ -9585,7 +10258,7 @@ function ReadonlyEntry(props) {
|
|
|
9585
10258
|
component: Readonly,
|
|
9586
10259
|
editField: editField,
|
|
9587
10260
|
field: field,
|
|
9588
|
-
isEdited: isEdited$
|
|
10261
|
+
isEdited: isEdited$6
|
|
9589
10262
|
});
|
|
9590
10263
|
}
|
|
9591
10264
|
return entries;
|
|
@@ -9630,7 +10303,7 @@ function ConditionEntry(props) {
|
|
|
9630
10303
|
component: Condition,
|
|
9631
10304
|
editField: editField,
|
|
9632
10305
|
field: field,
|
|
9633
|
-
isEdited: isEdited$
|
|
10306
|
+
isEdited: isEdited$6
|
|
9634
10307
|
}];
|
|
9635
10308
|
}
|
|
9636
10309
|
function Condition(props) {
|
|
@@ -9678,7 +10351,7 @@ function ValuesExpressionEntry(props) {
|
|
|
9678
10351
|
id: id + '-expression',
|
|
9679
10352
|
component: ValuesExpression,
|
|
9680
10353
|
label: 'Values expression',
|
|
9681
|
-
isEdited: isEdited$
|
|
10354
|
+
isEdited: isEdited$6,
|
|
9682
10355
|
editField,
|
|
9683
10356
|
field
|
|
9684
10357
|
}];
|
|
@@ -9730,6 +10403,12 @@ function GeneralGroup(field, editField, getService) {
|
|
|
9730
10403
|
}), ...KeyEntry({
|
|
9731
10404
|
field,
|
|
9732
10405
|
editField
|
|
10406
|
+
}), ...PathEntry({
|
|
10407
|
+
field,
|
|
10408
|
+
editField
|
|
10409
|
+
}), ...GroupEntries({
|
|
10410
|
+
field,
|
|
10411
|
+
editField
|
|
9733
10412
|
}), ...DefaultOptionEntry({
|
|
9734
10413
|
field,
|
|
9735
10414
|
editField
|
|
@@ -9844,7 +10523,7 @@ function ValidationGroup(field, editField) {
|
|
|
9844
10523
|
component: Required,
|
|
9845
10524
|
getValue,
|
|
9846
10525
|
field,
|
|
9847
|
-
isEdited: isEdited$
|
|
10526
|
+
isEdited: isEdited$5,
|
|
9848
10527
|
onChange
|
|
9849
10528
|
}];
|
|
9850
10529
|
if (type === 'textfield') {
|
|
@@ -9864,14 +10543,14 @@ function ValidationGroup(field, editField) {
|
|
|
9864
10543
|
component: MinLength,
|
|
9865
10544
|
getValue,
|
|
9866
10545
|
field,
|
|
9867
|
-
isEdited: isEdited$
|
|
10546
|
+
isEdited: isEdited$6,
|
|
9868
10547
|
onChange
|
|
9869
10548
|
}, {
|
|
9870
10549
|
id: 'maxLength',
|
|
9871
10550
|
component: MaxLength,
|
|
9872
10551
|
getValue,
|
|
9873
10552
|
field,
|
|
9874
|
-
isEdited: isEdited$
|
|
10553
|
+
isEdited: isEdited$6,
|
|
9875
10554
|
onChange
|
|
9876
10555
|
});
|
|
9877
10556
|
}
|
|
@@ -9891,14 +10570,14 @@ function ValidationGroup(field, editField) {
|
|
|
9891
10570
|
component: Min,
|
|
9892
10571
|
getValue,
|
|
9893
10572
|
field,
|
|
9894
|
-
isEdited: isEdited$
|
|
10573
|
+
isEdited: isEdited$6,
|
|
9895
10574
|
onChange
|
|
9896
10575
|
}, {
|
|
9897
10576
|
id: 'max',
|
|
9898
10577
|
component: Max,
|
|
9899
10578
|
getValue,
|
|
9900
10579
|
field,
|
|
9901
|
-
isEdited: isEdited$
|
|
10580
|
+
isEdited: isEdited$6,
|
|
9902
10581
|
onChange
|
|
9903
10582
|
});
|
|
9904
10583
|
}
|